Merge branch release-2021 into merge-2021-into-master
authorPaul Bauer <paul.bauer.q@gmail.com>
Thu, 6 May 2021 14:22:09 +0000 (16:22 +0200)
committerPaul Bauer <paul.bauer.q@gmail.com>
Fri, 7 May 2021 08:21:46 +0000 (10:21 +0200)
Resolved Conflicts:
cmake/gmxCFlags.cmake
cmake/gmxManageFFTLibraries.cmake
cmake/gmxVersionInfo.cmake
docs/CMakeLists.txt
src/gromacs/applied_forces/awh/bias.cpp
src/gromacs/applied_forces/awh/biasstate.cpp
src/gromacs/applied_forces/awh/biasstate.h
src/gromacs/applied_forces/awh/read_params.cpp
src/gromacs/applied_forces/awh/tests/bias_fep_lambda_state.cpp
src/gromacs/fileio/vmdio.cpp
src/gromacs/gmxpreprocess/readir.cpp
src/gromacs/mdlib/constr.cpp
src/gromacs/mdlib/enerdata_utils.cpp
src/gromacs/mdlib/mdatoms.cpp
src/gromacs/mdrun/mimic.cpp
src/gromacs/mdrun/runner.cpp
src/gromacs/modularsimulator/modularsimulator.cpp
src/gromacs/utility/mdmodulesnotifiers.h

1668 files changed:
.clang-format
.gitlab-ci.yml
CMakeLists.txt
admin/ci-scripts/build-and-test-py-gmxapi-0.3.sh [new file with mode: 0644]
admin/clang-format.sh
admin/clang-tidy.sh
admin/containers/buildall.sh [changed mode: 0644->0755]
admin/containers/scripted_gmx_docker_builds.py
admin/containers/utility.py
admin/git-pre-commit
admin/gitlab-ci/archive.gitlab-ci.yml
admin/gitlab-ci/documentation.gitlab-ci.yml
admin/gitlab-ci/global.gitlab-ci.yml
admin/gitlab-ci/gromacs.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.clang-11-cuda-11.2.gitlab-ci.yml [new file with mode: 0644]
admin/gitlab-ci/gromacs.matrix/gromacs.clang-8-cuda-10.0.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.clang-8-cuda-10.1-release.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.clang-8.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.clang-9-mpi.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.clang-9-release.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.clang-ASAN.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.clang-TSAN.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.clang-UBSAN.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.clang-static-analyzer.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.gcc-10-coverage.gitlab-ci.yml [new file with mode: 0644]
admin/gitlab-ci/gromacs.matrix/gromacs.gcc-10.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.gcc-7-cuda-10.2.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.gcc-8-cuda-11.0-release.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.gcc-8-cuda-11.0.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.gcc-9-release.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.hipsycl-dev.gitlab-ci.yml [new file with mode: 0644]
admin/gitlab-ci/gromacs.matrix/gromacs.icc-2021.1.gitlab-ci.yml [deleted file]
admin/gitlab-ci/gromacs.matrix/gromacs.oneapi-2021.1.1-opencl-release.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.oneapi-2021.1.1-opencl.gitlab-ci.yml
admin/gitlab-ci/gromacs.matrix/gromacs.oneapi-2021.1.1-sycl.gitlab-ci.yml
admin/gitlab-ci/lint.gitlab-ci.yml
admin/gitlab-ci/python-gmxapi01.gitlab-ci.yml [moved from admin/gitlab-ci/python-gmxapi.gitlab-ci.yml with 97% similarity]
admin/gitlab-ci/python-gmxapi02.gitlab-ci.yml [new file with mode: 0644]
admin/gitlab-ci/python-gmxapi03.gitlab-ci.yml [new file with mode: 0644]
admin/gitlab-ci/rules.gitlab-ci.yml
admin/gitlab-ci/sample_restraint-regression.gitlab-ci.yml
admin/gitlab-ci/sample_restraint.gitlab-ci.yml
admin/lsan-suppressions.txt
api/CMakeLists.txt
api/gmxapi/CMakeLists.txt
api/gmxapi/cpp/CMakeLists.txt
api/gmxapi/cpp/cmake/gmxapi-config.cmake.in
api/gmxapi/cpp/context.cpp
api/gmxapi/cpp/mdsignals.cpp
api/gmxapi/cpp/session.cpp
api/gmxapi/cpp/tpr.cpp
api/legacy/CMakeLists.txt [moved from cmake/Platform/Toolchain-Fujitsu-Sparc64.cmake with 53% similarity]
api/legacy/include/gromacs/fileio/confio.h [moved from src/gromacs/fileio/confio.h with 98% similarity]
api/legacy/include/gromacs/fileio/filetypes.h [moved from src/gromacs/fileio/filetypes.h with 100% similarity]
api/legacy/include/gromacs/fileio/oenv.h [moved from src/gromacs/fileio/oenv.h with 100% similarity]
api/legacy/include/gromacs/fileio/pdbio.h [moved from src/gromacs/fileio/pdbio.h with 87% similarity]
api/legacy/include/gromacs/fileio/tpxio.h [moved from src/gromacs/fileio/tpxio.h with 99% similarity]
api/legacy/include/gromacs/fileio/trxio.h [moved from src/gromacs/fileio/trxio.h with 98% similarity]
api/legacy/include/gromacs/math/do_fit.h [moved from src/gromacs/math/do_fit.h with 100% similarity]
api/legacy/include/gromacs/math/functions.h [moved from src/gromacs/math/functions.h with 95% similarity]
api/legacy/include/gromacs/math/units.h [new file with mode: 0644]
api/legacy/include/gromacs/math/utilities.h [moved from src/gromacs/math/utilities.h with 84% similarity]
api/legacy/include/gromacs/math/vec.h [moved from src/gromacs/math/vec.h with 100% similarity]
api/legacy/include/gromacs/math/vectypes.h [moved from src/gromacs/math/vectypes.h with 96% similarity]
api/legacy/include/gromacs/restraint/restraintpotential.h [moved from src/gromacs/restraint/restraintpotential.h with 99% similarity]
api/legacy/include/gromacs/utility/arrayref.h [moved from src/gromacs/utility/arrayref.h with 100% similarity]
api/legacy/include/gromacs/utility/basedefinitions.h [moved from src/gromacs/utility/basedefinitions.h with 89% similarity]
api/legacy/include/gromacs/utility/current_function.h [moved from src/gromacs/utility/current_function.h with 94% similarity]
api/legacy/include/gromacs/utility/exceptions.h [moved from src/gromacs/utility/exceptions.h with 100% similarity]
api/legacy/include/gromacs/utility/gmxassert.h [moved from src/gromacs/utility/gmxassert.h with 92% similarity]
api/legacy/include/gromacs/utility/listoflists.h [moved from src/gromacs/utility/listoflists.h with 96% similarity]
api/legacy/include/gromacs/utility/real.h [moved from src/gromacs/utility/real.h with 100% similarity]
api/legacy/version.h.cmakein [new file with mode: 0644]
api/nblib/CMakeLists.txt
api/nblib/gmxcalculator.cpp
api/nblib/gmxsetup.cpp
api/nblib/interactions.cpp
api/nblib/listed_forces/tests/bondtypes.cpp
api/nblib/listed_forces/tests/calculator.cpp
api/nblib/listed_forces/tests/helpers.cpp
api/nblib/listed_forces/transformations.cpp
api/nblib/molecules.cpp
api/nblib/particlesequencer.cpp
api/nblib/samples/argon-forces-integration.cpp
api/nblib/samples/methane-water-integration.cpp
api/nblib/simulationstate.cpp
api/nblib/tests/CMakeLists.txt
api/nblib/tests/integrator.cpp
api/nblib/tests/interactions.cpp
api/nblib/tests/nbkernelsystem.cpp
api/nblib/tests/testsystems.cpp
api/nblib/tests/topology.cpp
api/nblib/topology.cpp
api/nblib/topologyhelpers.cpp
api/nblib/util/setup.cpp
cmake/FindLibStdCpp.cmake
cmake/FindLmfit.cmake
cmake/FindclFFT.cmake
cmake/TestFujitsuSparc64.cpp [deleted file]
cmake/TestMIC.cpp [deleted file]
cmake/ThreadMPI.cmake
cmake/gmxCFlags.cmake
cmake/gmxDetectSimd.cmake
cmake/gmxDetectTargetArchitecture.cmake
cmake/gmxGenerateVersionInfoWithoutGit.cmake
cmake/gmxManageClangCudaConfig.cmake
cmake/gmxManageCudaAwareMPI.cmake [moved from cmake/gmxTestMPI_IN_PLACE.cmake with 57% similarity]
cmake/gmxManageFFTLibraries.cmake
cmake/gmxManageLinearAlgebraLibraries.cmake
cmake/gmxManageMPI.cmake
cmake/gmxManageOpenCL.cmake
cmake/gmxManageSYCL.cmake
cmake/gmxManageSharedLibraries.cmake
cmake/gmxManageSimd.cmake
cmake/gmxManageSuffixes.cmake
cmake/gmxPythonDiscovery.cmake
cmake/gmxSimdFlags.cmake
cmake/gmxTestCompilerProblems.cmake
cmake/gmxTestMMMalloc.cmake
cmake/gmxVersionInfo.cmake
docs/CMakeLists.txt
docs/dev-manual/build-system.rst
docs/dev-manual/change-management.rst
docs/dev-manual/containers.rst
docs/dev-manual/documentation-generation.rst
docs/dev-manual/error-handling.rst
docs/dev-manual/gitlab-ci.rst [moved from docs/dev-manual/gitlab.rst with 99% similarity]
docs/dev-manual/gmxtree.rst
docs/dev-manual/includestyle.rst
docs/dev-manual/infrastructure.rst
docs/dev-manual/naming.rst
docs/dev-manual/overview.rst
docs/dev-manual/tools.rst
docs/doxygen/CMakeLists.txt
docs/doxygen/Doxyfile-common.cmakein
docs/doxygen/check-source.py
docs/doxygen/cycle-suppressions.txt [deleted file]
docs/doxygen/lib/mdmodules.md
docs/doxygen/lib/modularsimulator.md
docs/doxygen/lib/simd.md
docs/doxygen/suppressions.txt
docs/gmxapi/userguide/usage.rst
docs/install-guide/index.rst
docs/reference-manual/algorithms/group-concept.rst
docs/reference-manual/functions/interaction-methods.rst
docs/release-notes/2021/major/deprecated-functionality.rst
docs/release-notes/2022/major/api.rst [new file with mode: 0644]
docs/release-notes/2022/major/bugs-fixed.rst [new file with mode: 0644]
docs/release-notes/2022/major/deprecated-functionality.rst [new file with mode: 0644]
docs/release-notes/2022/major/features.rst [new file with mode: 0644]
docs/release-notes/2022/major/highlights.rst [new file with mode: 0644]
docs/release-notes/2022/major/miscellaneous.rst [new file with mode: 0644]
docs/release-notes/2022/major/performance.rst [new file with mode: 0644]
docs/release-notes/2022/major/portability.rst [new file with mode: 0644]
docs/release-notes/2022/major/removed-functionality.rst [new file with mode: 0644]
docs/release-notes/2022/major/tools.rst [new file with mode: 0644]
docs/release-notes/index.rst
docs/user-guide/cmdline.rst
docs/user-guide/environment-variables.rst
docs/user-guide/faq.rst
docs/user-guide/getting-started.rst
docs/user-guide/mdp-options.rst
docs/user-guide/mdrun-features.rst
docs/user-guide/mdrun-performance.rst
python_packaging/requirements-test.txt
python_packaging/sample_restraint/CMakeLists.txt
python_packaging/sample_restraint/src/cpp/CMakeLists.txt
python_packaging/sample_restraint/tests/CMakeLists.txt
python_packaging/sample_restraint/tests/conftest.py
python_packaging/src/CMakeLists.txt
python_packaging/src/gmxapi/commandline.py
python_packaging/src/gmxapi/export_context.cpp
python_packaging/src/gmxapi/export_exceptions.cpp
python_packaging/src/gmxapi/export_system.cpp
python_packaging/src/gmxapi/export_tprfile.cpp
python_packaging/src/gmxapi/module.cpp
python_packaging/src/gmxapi/version.py
python_packaging/src/setup.py
python_packaging/src/test/conftest.py
python_packaging/src/test/test_commandline.py
share/template/CMakeLists.txt
share/template/CMakeLists.txt.template
share/template/template.cpp
src/.clang-tidy
src/.clang-tidy.new.code
src/CMakeLists.txt
src/api/CMakeLists.txt
src/api/cpp/tests/.clang-tidy [new file with mode: 0644]
src/api/cpp/tests/restraint.cpp
src/api/cpp/tests/runner.cpp
src/api/cpp/tests/testingconfiguration.h
src/api/cpp/workflow/tests/.clang-tidy [new file with mode: 0644]
src/config.h.cmakein
src/external/.clang-tidy
src/external/thread_mpi/include/thread_mpi/atomic/gcc_x86.h
src/external/thread_mpi/include/thread_mpi/mutex.h [deleted file]
src/external/thread_mpi/include/thread_mpi/system_error.h [deleted file]
src/external/thread_mpi/src/system_error.cpp [deleted file]
src/external/thread_mpi/src/tmpi_init.cpp
src/gromacs/CMakeLists.txt
src/gromacs/analysisdata/CMakeLists.txt
src/gromacs/analysisdata/abstractdata.h
src/gromacs/analysisdata/analysisdata.h
src/gromacs/analysisdata/arraydata.cpp
src/gromacs/analysisdata/dataframe.h
src/gromacs/analysisdata/datamodulemanager.cpp
src/gromacs/analysisdata/datamodulemanager.h
src/gromacs/analysisdata/datastorage.cpp
src/gromacs/analysisdata/datastorage.h
src/gromacs/analysisdata/modules/average.h
src/gromacs/analysisdata/modules/displacement.cpp
src/gromacs/analysisdata/modules/displacement.h
src/gromacs/analysisdata/modules/frameaverager.h
src/gromacs/analysisdata/modules/histogram.cpp
src/gromacs/analysisdata/modules/histogram.h
src/gromacs/analysisdata/modules/lifetime.cpp
src/gromacs/analysisdata/modules/lifetime.h
src/gromacs/analysisdata/modules/plot.cpp
src/gromacs/analysisdata/modules/plot.h
src/gromacs/analysisdata/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/analysisdata/tests/CMakeLists.txt
src/gromacs/analysisdata/tests/datatest.cpp
src/gromacs/analysisdata/tests/mock_datamodule.cpp
src/gromacs/analysisdata/tests/mock_datamodule.h
src/gromacs/applied_forces/CMakeLists.txt
src/gromacs/applied_forces/awh/awh.cpp
src/gromacs/applied_forces/awh/awh.h
src/gromacs/applied_forces/awh/bias.cpp
src/gromacs/applied_forces/awh/bias.h
src/gromacs/applied_forces/awh/biasgrid.cpp
src/gromacs/applied_forces/awh/biasgrid.h
src/gromacs/applied_forces/awh/biasparams.cpp
src/gromacs/applied_forces/awh/biasparams.h
src/gromacs/applied_forces/awh/biassharing.cpp
src/gromacs/applied_forces/awh/biassharing.h
src/gromacs/applied_forces/awh/biasstate.cpp
src/gromacs/applied_forces/awh/biasstate.h
src/gromacs/applied_forces/awh/biaswriter.cpp
src/gromacs/applied_forces/awh/biaswriter.h
src/gromacs/applied_forces/awh/coordstate.cpp
src/gromacs/applied_forces/awh/coordstate.h
src/gromacs/applied_forces/awh/correlationgrid.cpp
src/gromacs/applied_forces/awh/correlationgrid.h
src/gromacs/applied_forces/awh/correlationhistory.cpp
src/gromacs/applied_forces/awh/dimparams.h
src/gromacs/applied_forces/awh/histogramsize.cpp
src/gromacs/applied_forces/awh/histogramsize.h
src/gromacs/applied_forces/awh/pointstate.h
src/gromacs/applied_forces/awh/read_params.cpp
src/gromacs/applied_forces/awh/read_params.h
src/gromacs/applied_forces/awh/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/applied_forces/awh/tests/CMakeLists.txt
src/gromacs/applied_forces/awh/tests/awh_setup.cpp [new file with mode: 0644]
src/gromacs/applied_forces/awh/tests/awh_setup.h [new file with mode: 0644]
src/gromacs/applied_forces/awh/tests/bias.cpp
src/gromacs/applied_forces/awh/tests/bias_fep_lambda_state.cpp
src/gromacs/applied_forces/awh/tests/biasgrid.cpp
src/gromacs/applied_forces/awh/tests/biasstate.cpp
src/gromacs/applied_forces/densityfitting/densityfitting.cpp
src/gromacs/applied_forces/densityfitting/densityfittingamplitudelookup.cpp
src/gromacs/applied_forces/densityfitting/densityfittingamplitudelookup.h
src/gromacs/applied_forces/densityfitting/densityfittingforceprovider.cpp
src/gromacs/applied_forces/densityfitting/densityfittingforceprovider.h
src/gromacs/applied_forces/densityfitting/densityfittingoptions.cpp
src/gromacs/applied_forces/densityfitting/densityfittingparameters.h
src/gromacs/applied_forces/densityfitting/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/applied_forces/densityfitting/tests/densityfitting.cpp
src/gromacs/applied_forces/densityfitting/tests/densityfittingamplitudelookup.cpp
src/gromacs/applied_forces/densityfitting/tests/densityfittingoptions.cpp
src/gromacs/applied_forces/electricfield.cpp
src/gromacs/applied_forces/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/applied_forces/tests/electricfield.cpp
src/gromacs/commandline/CMakeLists.txt
src/gromacs/commandline/cmdlinehelpcontext.cpp
src/gromacs/commandline/cmdlinehelpcontext.h
src/gromacs/commandline/cmdlinehelpmodule.cpp
src/gromacs/commandline/cmdlinehelpmodule.h
src/gromacs/commandline/cmdlinehelpwriter.cpp
src/gromacs/commandline/cmdlinehelpwriter.h
src/gromacs/commandline/cmdlineinit.cpp
src/gromacs/commandline/cmdlinemodule.h
src/gromacs/commandline/cmdlinemodulemanager.cpp
src/gromacs/commandline/cmdlinemodulemanager.h
src/gromacs/commandline/cmdlineparser.h
src/gromacs/commandline/cmdlineprogramcontext.cpp
src/gromacs/commandline/cmdlineprogramcontext.h
src/gromacs/commandline/filenm.h
src/gromacs/commandline/pargs.cpp
src/gromacs/commandline/pargs.h
src/gromacs/commandline/shellcompletions.h
src/gromacs/commandline/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/commandline/tests/cmdlinehelpwriter.cpp
src/gromacs/commandline/tests/cmdlinemodulemanagertest.cpp
src/gromacs/commandline/tests/cmdlinemodulemanagertest.h
src/gromacs/commandline/tests/pargs.cpp
src/gromacs/commandline/viewit.cpp
src/gromacs/compat/CMakeLists.txt
src/gromacs/compat/pointers.h
src/gromacs/compat/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/compat/tests/pointers.cpp
src/gromacs/coordinateio/CMakeLists.txt
src/gromacs/coordinateio/coordinatefile.cpp
src/gromacs/coordinateio/outputadaptercontainer.cpp
src/gromacs/coordinateio/outputadaptercontainer.h
src/gromacs/coordinateio/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/coordinateio/tests/coordinate_test.h
src/gromacs/coordinateio/tests/outputadapters.h
src/gromacs/correlationfunctions/CMakeLists.txt
src/gromacs/correlationfunctions/autocorr.cpp
src/gromacs/correlationfunctions/expfit.cpp
src/gromacs/correlationfunctions/expfit.h
src/gromacs/correlationfunctions/gmx_lmcurve.cpp
src/gromacs/correlationfunctions/gmx_lmcurve.h
src/gromacs/correlationfunctions/manyautocorrelation.cpp
src/gromacs/correlationfunctions/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/correlationfunctions/tests/autocorr.cpp
src/gromacs/correlationfunctions/tests/correlationdataset.h
src/gromacs/correlationfunctions/tests/expfit.cpp
src/gromacs/domdec/CMakeLists.txt
src/gromacs/domdec/box.cpp
src/gromacs/domdec/builder.h
src/gromacs/domdec/cellsizes.cpp
src/gromacs/domdec/cellsizes.h
src/gromacs/domdec/collect.cpp
src/gromacs/domdec/distribute.cpp
src/gromacs/domdec/dlbtiming.cpp
src/gromacs/domdec/domdec.cpp
src/gromacs/domdec/domdec.h
src/gromacs/domdec/domdec_constraints.cpp
src/gromacs/domdec/domdec_constraints.h
src/gromacs/domdec/domdec_internal.h
src/gromacs/domdec/domdec_network.cpp
src/gromacs/domdec/domdec_setup.cpp
src/gromacs/domdec/domdec_specatomcomm.cpp
src/gromacs/domdec/domdec_struct.h
src/gromacs/domdec/domdec_topology.cpp
src/gromacs/domdec/domdec_vsite.cpp
src/gromacs/domdec/dump.cpp
src/gromacs/domdec/dump.h
src/gromacs/domdec/gpuhaloexchange.h
src/gromacs/domdec/gpuhaloexchange_impl.cu
src/gromacs/domdec/gpuhaloexchange_impl.cuh
src/gromacs/domdec/localatomsetmanager.h
src/gromacs/domdec/mdsetup.cpp
src/gromacs/domdec/mdsetup.h
src/gromacs/domdec/nsgrid.cpp [new file with mode: 0644]
src/gromacs/domdec/nsgrid.h [new file with mode: 0644]
src/gromacs/domdec/options.h
src/gromacs/domdec/partition.cpp
src/gromacs/domdec/partition.h
src/gromacs/domdec/redistribute.cpp
src/gromacs/domdec/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/domdec/tests/haloexchange_mpi.cpp
src/gromacs/energyanalysis/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/essentialdynamics/CMakeLists.txt
src/gromacs/essentialdynamics/edsam.cpp
src/gromacs/essentialdynamics/edsam.h
src/gromacs/ewald/CMakeLists.txt
src/gromacs/ewald/calculate_spline_moduli.cpp
src/gromacs/ewald/ewald.cpp
src/gromacs/ewald/ewald.h
src/gromacs/ewald/ewald_utils.h
src/gromacs/ewald/long_range_correction.cpp
src/gromacs/ewald/long_range_correction.h
src/gromacs/ewald/pme.cpp
src/gromacs/ewald/pme.h
src/gromacs/ewald/pme_coordinate_receiver_gpu.h
src/gromacs/ewald/pme_coordinate_receiver_gpu_impl.cpp
src/gromacs/ewald/pme_coordinate_receiver_gpu_impl.cu
src/gromacs/ewald/pme_coordinate_receiver_gpu_impl.h
src/gromacs/ewald/pme_force_sender_gpu.h
src/gromacs/ewald/pme_force_sender_gpu_impl.cpp
src/gromacs/ewald/pme_force_sender_gpu_impl.cu
src/gromacs/ewald/pme_force_sender_gpu_impl.h
src/gromacs/ewald/pme_gather.clh
src/gromacs/ewald/pme_gather.cu
src/gromacs/ewald/pme_gpu.cpp
src/gromacs/ewald/pme_gpu_3dfft.cu
src/gromacs/ewald/pme_gpu_3dfft.h
src/gromacs/ewald/pme_gpu_3dfft_ocl.cpp
src/gromacs/ewald/pme_gpu_calculate_splines.cuh
src/gromacs/ewald/pme_gpu_internal.cpp
src/gromacs/ewald/pme_gpu_internal.h
src/gromacs/ewald/pme_gpu_program_impl.cpp
src/gromacs/ewald/pme_gpu_program_impl.cu
src/gromacs/ewald/pme_gpu_program_impl.h
src/gromacs/ewald/pme_gpu_program_impl_ocl.cpp
src/gromacs/ewald/pme_gpu_sycl_stubs.cpp [moved from src/gromacs/gmxlib/nonbonded/nb_kernel.h with 56% similarity]
src/gromacs/ewald/pme_gpu_timings.cpp
src/gromacs/ewald/pme_gpu_timings.h
src/gromacs/ewald/pme_gpu_types.h
src/gromacs/ewald/pme_gpu_types_host.h
src/gromacs/ewald/pme_gpu_types_host_impl.h
src/gromacs/ewald/pme_grid.cpp
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_only.h
src/gromacs/ewald/pme_pp.cpp
src/gromacs/ewald/pme_pp.h
src/gromacs/ewald/pme_pp_comm_gpu.h
src/gromacs/ewald/pme_pp_comm_gpu_impl.cpp
src/gromacs/ewald/pme_pp_comm_gpu_impl.cu
src/gromacs/ewald/pme_pp_comm_gpu_impl.h
src/gromacs/ewald/pme_pp_communication.h
src/gromacs/ewald/pme_redistribute.cpp
src/gromacs/ewald/pme_redistribute.h
src/gromacs/ewald/pme_solve.cpp
src/gromacs/ewald/pme_spread.clh
src/gromacs/ewald/pme_spread.cpp
src/gromacs/ewald/pme_spread.cu
src/gromacs/ewald/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/ewald/tests/CMakeLists.txt
src/gromacs/ewald/tests/pme.cpp [new file with mode: 0644]
src/gromacs/ewald/tests/pmebsplinetest.cpp
src/gromacs/ewald/tests/pmegathertest.cpp
src/gromacs/ewald/tests/pmesolvetest.cpp
src/gromacs/ewald/tests/pmesplinespreadtest.cpp
src/gromacs/ewald/tests/pmetestcommon.cpp
src/gromacs/fft/CMakeLists.txt
src/gromacs/fft/calcgrid.cpp
src/gromacs/fft/fft5d.cpp
src/gromacs/fft/fft5d.h
src/gromacs/fft/fft_fftw3.cpp
src/gromacs/fft/parallel_3dfft.cpp
src/gromacs/fft/parallel_3dfft.h
src/gromacs/fft/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/fft/tests/fft.cpp
src/gromacs/fileio/CMakeLists.txt
src/gromacs/fileio/checkpoint.cpp
src/gromacs/fileio/checkpoint.h
src/gromacs/fileio/confio.cpp
src/gromacs/fileio/enxio.cpp
src/gromacs/fileio/enxio.h
src/gromacs/fileio/espio.cpp
src/gromacs/fileio/filetypes.cpp
src/gromacs/fileio/g96io.cpp
src/gromacs/fileio/gmxfio.cpp
src/gromacs/fileio/gmxfio_xdr.cpp
src/gromacs/fileio/groio.cpp
src/gromacs/fileio/groio.h
src/gromacs/fileio/libxdrf.cpp
src/gromacs/fileio/matio.cpp
src/gromacs/fileio/mrcdensitymap.cpp
src/gromacs/fileio/mrcdensitymap.h
src/gromacs/fileio/mrcdensitymapheader.cpp
src/gromacs/fileio/mtxio.cpp
src/gromacs/fileio/oenv.cpp
src/gromacs/fileio/pdbio.cpp
src/gromacs/fileio/readinp.cpp
src/gromacs/fileio/readinp.h
src/gromacs/fileio/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/fileio/tests/CMakeLists.txt
src/gromacs/fileio/tests/confio.cpp
src/gromacs/fileio/tests/filemd5.cpp
src/gromacs/fileio/tests/mrcdensitymap.cpp
src/gromacs/fileio/tests/xvgio.cpp
src/gromacs/fileio/timecontrol.cpp
src/gromacs/fileio/timecontrol.h
src/gromacs/fileio/tngio.cpp
src/gromacs/fileio/tpxio.cpp
src/gromacs/fileio/trrio.cpp
src/gromacs/fileio/trxio.cpp
src/gromacs/fileio/vmdio.cpp
src/gromacs/fileio/warninp.cpp
src/gromacs/fileio/warninp.h
src/gromacs/fileio/writeps.cpp
src/gromacs/fileio/writeps.h
src/gromacs/fileio/xdr_datatype.h
src/gromacs/fileio/xtcio.cpp
src/gromacs/fileio/xvgr.cpp
src/gromacs/gmxana/CMakeLists.txt
src/gromacs/gmxana/anadih.cpp
src/gromacs/gmxana/angle_correction.h
src/gromacs/gmxana/binsearch.h
src/gromacs/gmxana/cluster_methods.cpp [new file with mode: 0644]
src/gromacs/gmxana/cluster_methods.h [new file with mode: 0644]
src/gromacs/gmxana/cmat.h
src/gromacs/gmxana/dens_filter.h
src/gromacs/gmxana/dlist.cpp
src/gromacs/gmxana/eigio.cpp
src/gromacs/gmxana/eigio.h
src/gromacs/gmxana/fitahx.cpp
src/gromacs/gmxana/fitahx.h
src/gromacs/gmxana/gmx_ana.h
src/gromacs/gmxana/gmx_anaeig.cpp
src/gromacs/gmxana/gmx_analyze.cpp
src/gromacs/gmxana/gmx_angle.cpp
src/gromacs/gmxana/gmx_awh.cpp
src/gromacs/gmxana/gmx_bar.cpp
src/gromacs/gmxana/gmx_bundle.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_covar.cpp
src/gromacs/gmxana/gmx_current.cpp
src/gromacs/gmxana/gmx_density.cpp
src/gromacs/gmxana/gmx_densmap.cpp
src/gromacs/gmxana/gmx_densorder.cpp
src/gromacs/gmxana/gmx_dielectric.cpp
src/gromacs/gmxana/gmx_dipoles.cpp
src/gromacs/gmxana/gmx_disre.cpp
src/gromacs/gmxana/gmx_do_dssp.cpp
src/gromacs/gmxana/gmx_dos.cpp
src/gromacs/gmxana/gmx_dyecoupl.cpp
src/gromacs/gmxana/gmx_enemat.cpp
src/gromacs/gmxana/gmx_energy.cpp
src/gromacs/gmxana/gmx_filter.cpp
src/gromacs/gmxana/gmx_gyrate.cpp
src/gromacs/gmxana/gmx_h2order.cpp
src/gromacs/gmxana/gmx_hbond.cpp
src/gromacs/gmxana/gmx_helix.cpp
src/gromacs/gmxana/gmx_helixorient.cpp
src/gromacs/gmxana/gmx_hydorder.cpp
src/gromacs/gmxana/gmx_lie.cpp
src/gromacs/gmxana/gmx_make_edi.cpp
src/gromacs/gmxana/gmx_mdmat.cpp
src/gromacs/gmxana/gmx_mindist.cpp
src/gromacs/gmxana/gmx_msd.cpp [deleted file]
src/gromacs/gmxana/gmx_nmeig.cpp
src/gromacs/gmxana/gmx_nmens.cpp
src/gromacs/gmxana/gmx_nmr.cpp
src/gromacs/gmxana/gmx_nmtraj.cpp
src/gromacs/gmxana/gmx_order.cpp
src/gromacs/gmxana/gmx_polystat.cpp
src/gromacs/gmxana/gmx_potential.cpp
src/gromacs/gmxana/gmx_principal.cpp
src/gromacs/gmxana/gmx_rama.cpp
src/gromacs/gmxana/gmx_rms.cpp
src/gromacs/gmxana/gmx_rmsdist.cpp
src/gromacs/gmxana/gmx_rmsf.cpp
src/gromacs/gmxana/gmx_rotacf.cpp
src/gromacs/gmxana/gmx_rotmat.cpp
src/gromacs/gmxana/gmx_saltbr.cpp
src/gromacs/gmxana/gmx_sans.cpp
src/gromacs/gmxana/gmx_saxs.cpp
src/gromacs/gmxana/gmx_sham.cpp
src/gromacs/gmxana/gmx_sigeps.cpp
src/gromacs/gmxana/gmx_sorient.cpp
src/gromacs/gmxana/gmx_spatial.cpp
src/gromacs/gmxana/gmx_spol.cpp
src/gromacs/gmxana/gmx_tcaf.cpp
src/gromacs/gmxana/gmx_traj.cpp
src/gromacs/gmxana/gmx_trjorder.cpp
src/gromacs/gmxana/gmx_vanhove.cpp
src/gromacs/gmxana/gmx_velacc.cpp
src/gromacs/gmxana/gmx_wham.cpp
src/gromacs/gmxana/gmx_wheel.cpp
src/gromacs/gmxana/gmx_xpm2ps.cpp
src/gromacs/gmxana/hxprops.cpp
src/gromacs/gmxana/hxprops.h
src/gromacs/gmxana/interf.h
src/gromacs/gmxana/nrama.cpp
src/gromacs/gmxana/nsfactor.cpp
src/gromacs/gmxana/powerspect.h
src/gromacs/gmxana/pp2shift.cpp
src/gromacs/gmxana/princ.cpp
src/gromacs/gmxana/sfactor.cpp
src/gromacs/gmxana/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/gmxana/tests/CMakeLists.txt
src/gromacs/gmxana/tests/gmx_msd.cpp [deleted file]
src/gromacs/gmxana/tests/refdata/MsdMolTest_diffMolMassWeighted.xml [deleted file]
src/gromacs/gmxana/tests/refdata/MsdMolTest_diffMolNonMassWeighted.xml [deleted file]
src/gromacs/gmxana/tests/refdata/MsdMolTest_diffMolSelected.xml [deleted file]
src/gromacs/gmxana/thermochemistry.cpp
src/gromacs/gmxlib/CMakeLists.txt
src/gromacs/gmxlib/network.cpp
src/gromacs/gmxlib/nonbonded/nb_free_energy.cpp
src/gromacs/gmxlib/nonbonded/nb_free_energy.h
src/gromacs/gmxlib/nonbonded/tests/CMakeLists.txt [moved from cmake/gmxManageFujitsuSparc64.cmake with 72% similarity]
src/gromacs/gmxlib/nonbonded/tests/nb_free_energy.cpp [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_0.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_1.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_10.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_11.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_12.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_13.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_14.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_15.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_16.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_17.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_18.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_19.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_2.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_20.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_21.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_22.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_23.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_24.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_25.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_26.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_27.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_28.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_29.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_3.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_30.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_31.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_32.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_33.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_34.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_35.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_4.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_5.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_6.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_7.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_8.xml [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_9.xml [new file with mode: 0644]
src/gromacs/gmxlib/nrnb.cpp
src/gromacs/gmxlib/nrnb.h
src/gromacs/gmxpreprocess/CMakeLists.txt
src/gromacs/gmxpreprocess/add_par.cpp
src/gromacs/gmxpreprocess/calch.cpp
src/gromacs/gmxpreprocess/convparm.cpp
src/gromacs/gmxpreprocess/convparm.h
src/gromacs/gmxpreprocess/editconf.cpp
src/gromacs/gmxpreprocess/fflibutil.cpp
src/gromacs/gmxpreprocess/gen_ad.cpp
src/gromacs/gmxpreprocess/gen_maxwell_velocities.cpp
src/gromacs/gmxpreprocess/gen_vsite.cpp
src/gromacs/gmxpreprocess/genconf.cpp
src/gromacs/gmxpreprocess/genhydro.cpp
src/gromacs/gmxpreprocess/genion.cpp
src/gromacs/gmxpreprocess/genrestr.cpp
src/gromacs/gmxpreprocess/gmxcpp.cpp
src/gromacs/gmxpreprocess/gpp_atomtype.cpp
src/gromacs/gmxpreprocess/gpp_atomtype.h
src/gromacs/gmxpreprocess/gpp_bond_atomtype.cpp
src/gromacs/gmxpreprocess/gpp_bond_atomtype.h
src/gromacs/gmxpreprocess/grompp.cpp
src/gromacs/gmxpreprocess/h_db.cpp
src/gromacs/gmxpreprocess/hackblock.cpp
src/gromacs/gmxpreprocess/hackblock.h
src/gromacs/gmxpreprocess/hizzie.cpp
src/gromacs/gmxpreprocess/insert_molecules.cpp
src/gromacs/gmxpreprocess/makeexclusiondistances.cpp
src/gromacs/gmxpreprocess/nm2type.cpp
src/gromacs/gmxpreprocess/pdb2gmx.cpp
src/gromacs/gmxpreprocess/pdb2top.cpp
src/gromacs/gmxpreprocess/pdb2top.h
src/gromacs/gmxpreprocess/pgutil.cpp
src/gromacs/gmxpreprocess/readir.cpp
src/gromacs/gmxpreprocess/readir.h
src/gromacs/gmxpreprocess/readpull.cpp
src/gromacs/gmxpreprocess/readrot.cpp
src/gromacs/gmxpreprocess/resall.cpp
src/gromacs/gmxpreprocess/solvate.cpp
src/gromacs/gmxpreprocess/specbond.cpp
src/gromacs/gmxpreprocess/ter_db.cpp
src/gromacs/gmxpreprocess/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/gmxpreprocess/tests/cyclic-dna.pdb [deleted file]
src/gromacs/gmxpreprocess/tests/editconf.cpp
src/gromacs/gmxpreprocess/tests/gpp_atomtype.cpp
src/gromacs/gmxpreprocess/tests/gpp_bond_atomtype.cpp
src/gromacs/gmxpreprocess/tests/insert_molecules.cpp
src/gromacs/gmxpreprocess/tests/readir.cpp
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsDefineParametersWithValuesIncludingAssignment.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsElectricField.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsElectricFieldOscillating.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsElectricFieldPulsed.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsEmptyLines.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsImplicitSolventNo.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsKeyWithoutValue.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_AcceptsMimic.xml
src/gromacs/gmxpreprocess/tests/refdata/GetIrTest_HandlesDifferentKindsOfMdpLines.xml
src/gromacs/gmxpreprocess/tests/topdirs.cpp
src/gromacs/gmxpreprocess/tomorse.cpp
src/gromacs/gmxpreprocess/topdirs.cpp
src/gromacs/gmxpreprocess/topdirs.h
src/gromacs/gmxpreprocess/topio.cpp
src/gromacs/gmxpreprocess/topio.h
src/gromacs/gmxpreprocess/toppush.cpp
src/gromacs/gmxpreprocess/toppush.h
src/gromacs/gmxpreprocess/topshake.cpp
src/gromacs/gmxpreprocess/toputil.cpp
src/gromacs/gmxpreprocess/vsite_parm.cpp
src/gromacs/gmxpreprocess/x2top.cpp
src/gromacs/gmxpreprocess/xlate.cpp
src/gromacs/gpu_utils/CMakeLists.txt
src/gromacs/gpu_utils/clfftinitializer.cpp
src/gromacs/gpu_utils/cudautils.cuh
src/gromacs/gpu_utils/device_context.h
src/gromacs/gpu_utils/device_context_ocl.cpp
src/gromacs/gpu_utils/device_stream.h
src/gromacs/gpu_utils/device_stream_manager.h
src/gromacs/gpu_utils/device_stream_ocl.cpp
src/gromacs/gpu_utils/device_stream_sycl.cpp
src/gromacs/gpu_utils/devicebuffer.cuh
src/gromacs/gpu_utils/devicebuffer.h
src/gromacs/gpu_utils/devicebuffer_ocl.h
src/gromacs/gpu_utils/devicebuffer_sycl.h
src/gromacs/gpu_utils/gmxsycl.h
src/gromacs/gpu_utils/gpu_macros.h
src/gromacs/gpu_utils/gpu_utils.cpp
src/gromacs/gpu_utils/gpu_utils.cu
src/gromacs/gpu_utils/gpu_utils.h
src/gromacs/gpu_utils/gpueventsynchronizer.cuh
src/gromacs/gpu_utils/gpueventsynchronizer_ocl.h
src/gromacs/gpu_utils/gpueventsynchronizer_sycl.h
src/gromacs/gpu_utils/gpuregiontimer_ocl.h
src/gromacs/gpu_utils/gputraits.cuh
src/gromacs/gpu_utils/gputraits.h
src/gromacs/gpu_utils/gputraits_ocl.h
src/gromacs/gpu_utils/gputraits_sycl.h
src/gromacs/gpu_utils/ocl_caching.cpp
src/gromacs/gpu_utils/ocl_compiler.cpp
src/gromacs/gpu_utils/oclutils.cpp
src/gromacs/gpu_utils/oclutils.h
src/gromacs/gpu_utils/pmalloc.cu [moved from src/gromacs/gpu_utils/pmalloc_cuda.cu with 78% similarity]
src/gromacs/gpu_utils/pmalloc.h [moved from src/gromacs/gpu_utils/pmalloc_cuda.h with 85% similarity]
src/gromacs/gpu_utils/pmalloc_ocl.cpp [new file with mode: 0644]
src/gromacs/gpu_utils/pmalloc_sycl.cpp [new file with mode: 0644]
src/gromacs/gpu_utils/sycl_kernel_utils.h [new file with mode: 0644]
src/gromacs/gpu_utils/syclutils.h [new file with mode: 0644]
src/gromacs/gpu_utils/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/gpu_utils/tests/device_buffer.cpp
src/gromacs/gpu_utils/tests/device_stream_manager.cpp
src/gromacs/gpu_utils/tests/devicetransfers_ocl.cpp
src/gromacs/gpu_utils/tests/pinnedmemorychecker.cpp
src/gromacs/gpu_utils/tests/typecasts_runner.cu
src/gromacs/gpu_utils/typecasts.cuh
src/gromacs/hardware/CMakeLists.txt
src/gromacs/hardware/cpuinfo.cpp
src/gromacs/hardware/cpuinfo.h
src/gromacs/hardware/detecthardware.cpp
src/gromacs/hardware/device_information.h
src/gromacs/hardware/device_management.cu
src/gromacs/hardware/device_management.h
src/gromacs/hardware/device_management_common.cpp
src/gromacs/hardware/device_management_ocl.cpp
src/gromacs/hardware/device_management_sycl.cpp
src/gromacs/hardware/hardwaretopology.cpp
src/gromacs/hardware/hardwaretopology.h
src/gromacs/hardware/hw_info.h
src/gromacs/hardware/identifyavx512fmaunits.cpp
src/gromacs/hardware/prepare_detection.cpp
src/gromacs/hardware/printhardware.cpp
src/gromacs/hardware/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/hardware/tests/cpuinfo.cpp
src/gromacs/hardware/tests/hardwaretopology.cpp
src/gromacs/imd/CMakeLists.txt
src/gromacs/imd/imd.cpp
src/gromacs/imd/imd.h
src/gromacs/linearalgebra/CMakeLists.txt
src/gromacs/linearalgebra/eigensolver.cpp
src/gromacs/linearalgebra/gmx_arpack.cpp
src/gromacs/linearalgebra/nrjac.cpp
src/gromacs/linearalgebra/nrjac.h
src/gromacs/listed_forces/CMakeLists.txt
src/gromacs/listed_forces/bonded.cpp
src/gromacs/listed_forces/bonded.h
src/gromacs/listed_forces/disre.cpp
src/gromacs/listed_forces/disre.h
src/gromacs/listed_forces/gpubonded.h
src/gromacs/listed_forces/gpubonded_impl.cpp
src/gromacs/listed_forces/gpubonded_impl.cu
src/gromacs/listed_forces/gpubondedkernels.cu
src/gromacs/listed_forces/listed_forces.cpp
src/gromacs/listed_forces/listed_forces.h
src/gromacs/listed_forces/listed_internal.h
src/gromacs/listed_forces/manage_threading.cpp
src/gromacs/listed_forces/orires.cpp
src/gromacs/listed_forces/orires.h
src/gromacs/listed_forces/pairs.cpp
src/gromacs/listed_forces/pairs.h
src/gromacs/listed_forces/position_restraints.cpp
src/gromacs/listed_forces/position_restraints.h
src/gromacs/listed_forces/restcbt.cpp
src/gromacs/listed_forces/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/listed_forces/tests/CMakeLists.txt
src/gromacs/listed_forces/tests/bonded.cpp
src/gromacs/listed_forces/tests/pairs.cpp [new file with mode: 0644]
src/gromacs/listed_forces/tests/position_restraints.cpp [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_0.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_1.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_10.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_11.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_2.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_3.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_4.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_5.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_6.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_7.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_8.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_9.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_0.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_1.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_2.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_3.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_4.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_5.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_6.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_7.xml [new file with mode: 0644]
src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_8.xml [new file with mode: 0644]
src/gromacs/math/CMakeLists.txt
src/gromacs/math/coordinatetransformation.h
src/gromacs/math/densityfit.cpp
src/gromacs/math/densityfit.h
src/gromacs/math/densityfittingforce.cpp
src/gromacs/math/densityfittingforce.h
src/gromacs/math/do_fit.cpp
src/gromacs/math/functions.cpp
src/gromacs/math/gausstransform.cpp
src/gromacs/math/gausstransform.h
src/gromacs/math/gmxcomplex.h
src/gromacs/math/matrix.cpp
src/gromacs/math/neldermead.cpp
src/gromacs/math/optimization.cpp
src/gromacs/math/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/math/tests/CMakeLists.txt
src/gromacs/math/tests/arrayrefwithpadding.cpp
src/gromacs/math/tests/coordinatetransformation.cpp
src/gromacs/math/tests/densityfit.cpp
src/gromacs/math/tests/densityfittingforce.cpp
src/gromacs/math/tests/dofit.cpp
src/gromacs/math/tests/functions.cpp
src/gromacs/math/tests/gausstransform.cpp
src/gromacs/math/tests/multidimarray.cpp
src/gromacs/math/tests/vectypes.cpp
src/gromacs/math/units.cpp [deleted file]
src/gromacs/math/units.h [deleted file]
src/gromacs/math/utilities.cpp
src/gromacs/math/veccompare.cpp
src/gromacs/math/vecdump.cpp
src/gromacs/mdlib/CMakeLists.txt
src/gromacs/mdlib/broadcaststructs.cpp
src/gromacs/mdlib/calc_verletbuf.cpp
src/gromacs/mdlib/calcmu.cpp
src/gromacs/mdlib/calcmu.h
src/gromacs/mdlib/calcvir.cpp
src/gromacs/mdlib/compute_io.cpp
src/gromacs/mdlib/constr.cpp
src/gromacs/mdlib/constr.h
src/gromacs/mdlib/constraintrange.cpp
src/gromacs/mdlib/coupling.cpp
src/gromacs/mdlib/coupling.h
src/gromacs/mdlib/dispersioncorrection.cpp
src/gromacs/mdlib/dispersioncorrection.h
src/gromacs/mdlib/ebin.cpp
src/gromacs/mdlib/enerdata_utils.cpp
src/gromacs/mdlib/energydrifttracker.cpp
src/gromacs/mdlib/energyoutput.cpp
src/gromacs/mdlib/energyoutput.h
src/gromacs/mdlib/expanded.cpp
src/gromacs/mdlib/expanded.h
src/gromacs/mdlib/expanded_internal.cpp
src/gromacs/mdlib/expanded_internal.h
src/gromacs/mdlib/force.cpp
src/gromacs/mdlib/force.h
src/gromacs/mdlib/forcerec.cpp
src/gromacs/mdlib/forcerec.h
src/gromacs/mdlib/forcerec_threading.h
src/gromacs/mdlib/freeenergyparameters.cpp
src/gromacs/mdlib/freeenergyparameters.h
src/gromacs/mdlib/gmx_omp_nthreads.cpp
src/gromacs/mdlib/gmx_omp_nthreads.h
src/gromacs/mdlib/gpuforcereduction.h
src/gromacs/mdlib/gpuforcereduction_impl.cpp
src/gromacs/mdlib/gpuforcereduction_impl.cu [deleted file]
src/gromacs/mdlib/gpuforcereduction_impl.h [moved from src/gromacs/mdlib/gpuforcereduction_impl.cuh with 88% similarity]
src/gromacs/mdlib/gpuforcereduction_impl_internal.cu [new file with mode: 0644]
src/gromacs/mdlib/gpuforcereduction_impl_internal.h [new file with mode: 0644]
src/gromacs/mdlib/gpuforcereduction_impl_stubs.cpp [new file with mode: 0644]
src/gromacs/mdlib/leapfrog_gpu.cu
src/gromacs/mdlib/leapfrog_gpu.h
src/gromacs/mdlib/leapfrog_gpu_sycl.cpp
src/gromacs/mdlib/lincs.cpp
src/gromacs/mdlib/lincs.h
src/gromacs/mdlib/lincs_gpu.cpp [moved from src/gromacs/mdlib/lincs_gpu.cu with 55% similarity]
src/gromacs/mdlib/lincs_gpu.h [moved from src/gromacs/mdlib/lincs_gpu.cuh with 87% similarity]
src/gromacs/mdlib/lincs_gpu_internal.cu [new file with mode: 0644]
src/gromacs/mdlib/lincs_gpu_internal.h [new file with mode: 0644]
src/gromacs/mdlib/lincs_gpu_internal_sycl.cpp [new file with mode: 0644]
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_bar.cpp
src/gromacs/mdlib/mdebin_bar.h
src/gromacs/mdlib/mdoutf.cpp
src/gromacs/mdlib/mdoutf.h
src/gromacs/mdlib/membed.cpp
src/gromacs/mdlib/membed.h
src/gromacs/mdlib/nsgrid.cpp [deleted file]
src/gromacs/mdlib/nsgrid.h [deleted file]
src/gromacs/mdlib/perf_est.cpp
src/gromacs/mdlib/rbin.cpp
src/gromacs/mdlib/rbin.h
src/gromacs/mdlib/resethandler.cpp
src/gromacs/mdlib/resethandler.h
src/gromacs/mdlib/rf_util.cpp
src/gromacs/mdlib/settle.cpp
src/gromacs/mdlib/settle.h
src/gromacs/mdlib/settle_gpu.cpp [new file with mode: 0644]
src/gromacs/mdlib/settle_gpu.h [moved from src/gromacs/mdlib/settle_gpu.cuh with 82% similarity]
src/gromacs/mdlib/settle_gpu_internal.cu [moved from src/gromacs/mdlib/settle_gpu.cu with 62% similarity]
src/gromacs/mdlib/settle_gpu_internal.h [new file with mode: 0644]
src/gromacs/mdlib/settle_gpu_internal_sycl.cpp [new file with mode: 0644]
src/gromacs/mdlib/shake.cpp
src/gromacs/mdlib/shake.h
src/gromacs/mdlib/sighandler.cpp
src/gromacs/mdlib/sighandler.h
src/gromacs/mdlib/sim_util.cpp
src/gromacs/mdlib/simulationsignal.cpp
src/gromacs/mdlib/splitter.cpp
src/gromacs/mdlib/stat.cpp
src/gromacs/mdlib/stat.h
src/gromacs/mdlib/stophandler.cpp
src/gromacs/mdlib/stophandler.h
src/gromacs/mdlib/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/mdlib/tests/CMakeLists.txt
src/gromacs/mdlib/tests/calcvir.cpp [new file with mode: 0644]
src/gromacs/mdlib/tests/constr.cpp
src/gromacs/mdlib/tests/constrtestdata.cpp
src/gromacs/mdlib/tests/constrtestrunners.cpp
src/gromacs/mdlib/tests/constrtestrunners.cu
src/gromacs/mdlib/tests/energyoutput.cpp
src/gromacs/mdlib/tests/expanded.cpp
src/gromacs/mdlib/tests/freeenergyparameters.cpp
src/gromacs/mdlib/tests/leapfrog.cpp
src/gromacs/mdlib/tests/leapfrogtestdata.cpp
src/gromacs/mdlib/tests/leapfrogtestrunners.cpp
src/gromacs/mdlib/tests/leapfrogtestrunners.h
src/gromacs/mdlib/tests/leapfrogtestrunners_gpu.cpp
src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAllAtomsInBox.xml [new file with mode: 0644]
src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAllAtomsInBoxScrew.xml [new file with mode: 0644]
src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAtomsOutOfBoxScrewX.xml [new file with mode: 0644]
src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAtomsOutOfBoxScrewXYZ.xml [new file with mode: 0644]
src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAtomsOutOfBoxScrewY.xml [new file with mode: 0644]
src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAtomsOutOfBoxScrewZ.xml [new file with mode: 0644]
src/gromacs/mdlib/tests/refdata/WithParameters_EnergyOutputTest_CheckOutput_0.xml
src/gromacs/mdlib/tests/refdata/WithParameters_EnergyOutputTest_CheckOutput_1.xml
src/gromacs/mdlib/tests/refdata/WithParameters_EnergyOutputTest_CheckOutput_10.xml
src/gromacs/mdlib/tests/refdata/WithParameters_EnergyOutputTest_CheckOutput_2.xml
src/gromacs/mdlib/tests/refdata/WithParameters_EnergyOutputTest_CheckOutput_3.xml
src/gromacs/mdlib/tests/refdata/WithParameters_EnergyOutputTest_CheckOutput_4.xml
src/gromacs/mdlib/tests/refdata/WithParameters_EnergyOutputTest_CheckOutput_5.xml
src/gromacs/mdlib/tests/refdata/WithParameters_EnergyOutputTest_CheckOutput_6.xml
src/gromacs/mdlib/tests/refdata/WithParameters_EnergyOutputTest_CheckOutput_7.xml
src/gromacs/mdlib/tests/refdata/WithParameters_EnergyOutputTest_CheckOutput_8.xml
src/gromacs/mdlib/tests/refdata/WithParameters_EnergyOutputTest_CheckOutput_9.xml
src/gromacs/mdlib/tests/settle.cpp
src/gromacs/mdlib/tests/settletestrunners.cpp
src/gromacs/mdlib/tests/settletestrunners.cu
src/gromacs/mdlib/tests/shake.cpp
src/gromacs/mdlib/tests/updategroups.cpp
src/gromacs/mdlib/tests/updategroupscog.cpp
src/gromacs/mdlib/tgroup.cpp
src/gromacs/mdlib/tgroup.h
src/gromacs/mdlib/trajectory_writing.cpp
src/gromacs/mdlib/trajectory_writing.h
src/gromacs/mdlib/update.cpp
src/gromacs/mdlib/update.h
src/gromacs/mdlib/update_constrain_gpu.h
src/gromacs/mdlib/update_constrain_gpu_impl.cpp
src/gromacs/mdlib/update_constrain_gpu_impl.cu
src/gromacs/mdlib/update_constrain_gpu_impl.h
src/gromacs/mdlib/update_vv.cpp [new file with mode: 0644]
src/gromacs/mdlib/update_vv.h [new file with mode: 0644]
src/gromacs/mdlib/updategroups.cpp
src/gromacs/mdlib/updategroups.h
src/gromacs/mdlib/updategroupscog.cpp
src/gromacs/mdlib/updategroupscog.h
src/gromacs/mdlib/vcm.cpp
src/gromacs/mdlib/vcm.h
src/gromacs/mdlib/vsite.cpp
src/gromacs/mdlib/vsite.h
src/gromacs/mdlib/wall.cpp
src/gromacs/mdlib/wall.h
src/gromacs/mdrun/CMakeLists.txt
src/gromacs/mdrun/isimulator.h
src/gromacs/mdrun/legacymdrunoptions.cpp
src/gromacs/mdrun/legacymdrunoptions.h
src/gromacs/mdrun/legacysimulator.cpp
src/gromacs/mdrun/md.cpp
src/gromacs/mdrun/mdmodules.cpp
src/gromacs/mdrun/mdmodules.h
src/gromacs/mdrun/mimic.cpp
src/gromacs/mdrun/minimize.cpp
src/gromacs/mdrun/replicaexchange.cpp
src/gromacs/mdrun/rerun.cpp
src/gromacs/mdrun/runner.cpp
src/gromacs/mdrun/shellfc.cpp
src/gromacs/mdrun/shellfc.h
src/gromacs/mdrun/simulationinput.cpp
src/gromacs/mdrun/simulationinput.h
src/gromacs/mdrun/simulatorbuilder.cpp
src/gromacs/mdrun/simulatorbuilder.h
src/gromacs/mdrun/tpi.cpp
src/gromacs/mdrunutility/CMakeLists.txt
src/gromacs/mdrunutility/handlerestart.cpp
src/gromacs/mdrunutility/multisim.cpp
src/gromacs/mdrunutility/multisim.h
src/gromacs/mdrunutility/printtime.cpp
src/gromacs/mdrunutility/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/mdrunutility/tests/CMakeLists.txt
src/gromacs/mdrunutility/tests/threadaffinitytest.h
src/gromacs/mdrunutility/threadaffinity.cpp
src/gromacs/mdspan/CMakeLists.txt
src/gromacs/mdspan/extensions.h
src/gromacs/mdspan/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/mdspan/tests/CMakeLists.txt
src/gromacs/mdspan/tests/mdspan.cpp
src/gromacs/mdtypes/CMakeLists.txt
src/gromacs/mdtypes/awh_history.h
src/gromacs/mdtypes/awh_params.h
src/gromacs/mdtypes/checkpointdata.h
src/gromacs/mdtypes/commrec.h
src/gromacs/mdtypes/enerdata.h
src/gromacs/mdtypes/energyhistory.h
src/gromacs/mdtypes/fcdata.h
src/gromacs/mdtypes/forcebuffers.cpp
src/gromacs/mdtypes/forcebuffers.h
src/gromacs/mdtypes/forceoutput.h
src/gromacs/mdtypes/forcerec.h
src/gromacs/mdtypes/group.cpp
src/gromacs/mdtypes/group.h
src/gromacs/mdtypes/iforceprovider.cpp
src/gromacs/mdtypes/iforceprovider.h
src/gromacs/mdtypes/imdmodule.h
src/gromacs/mdtypes/inputrec.cpp
src/gromacs/mdtypes/inputrec.h
src/gromacs/mdtypes/interaction_const.cpp
src/gromacs/mdtypes/interaction_const.h
src/gromacs/mdtypes/locality.h
src/gromacs/mdtypes/md_enums.cpp
src/gromacs/mdtypes/md_enums.h
src/gromacs/mdtypes/mdatom.h
src/gromacs/mdtypes/multipletimestepping.cpp
src/gromacs/mdtypes/multipletimestepping.h
src/gromacs/mdtypes/nblist.h
src/gromacs/mdtypes/pull_params.h
src/gromacs/mdtypes/state.cpp
src/gromacs/mdtypes/state.h
src/gromacs/mdtypes/state_propagator_data_gpu.h
src/gromacs/mdtypes/state_propagator_data_gpu_impl.cpp
src/gromacs/mdtypes/state_propagator_data_gpu_impl.h
src/gromacs/mdtypes/state_propagator_data_gpu_impl_gpu.cpp
src/gromacs/mdtypes/swaphistory.h
src/gromacs/mdtypes/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/mdtypes/tests/CMakeLists.txt
src/gromacs/mdtypes/tests/multipletimestepping.cpp [new file with mode: 0644]
src/gromacs/mimic/CMakeLists.txt
src/gromacs/mimic/communicator.cpp
src/gromacs/modularsimulator/CMakeLists.txt
src/gromacs/modularsimulator/checkpointhelper.cpp
src/gromacs/modularsimulator/checkpointhelper.h
src/gromacs/modularsimulator/computeglobalselement.cpp
src/gromacs/modularsimulator/computeglobalselement.h
src/gromacs/modularsimulator/constraintelement.cpp
src/gromacs/modularsimulator/domdechelper.cpp
src/gromacs/modularsimulator/domdechelper.h
src/gromacs/modularsimulator/energydata.cpp
src/gromacs/modularsimulator/energydata.h
src/gromacs/modularsimulator/forceelement.cpp
src/gromacs/modularsimulator/forceelement.h
src/gromacs/modularsimulator/freeenergyperturbationdata.cpp
src/gromacs/modularsimulator/freeenergyperturbationdata.h
src/gromacs/modularsimulator/modularsimulator.cpp
src/gromacs/modularsimulator/modularsimulatorinterfaces.h
src/gromacs/modularsimulator/parrinellorahmanbarostat.cpp
src/gromacs/modularsimulator/parrinellorahmanbarostat.h
src/gromacs/modularsimulator/pmeloadbalancehelper.cpp
src/gromacs/modularsimulator/propagator.cpp
src/gromacs/modularsimulator/propagator.h
src/gromacs/modularsimulator/signallers.cpp
src/gromacs/modularsimulator/signallers.h
src/gromacs/modularsimulator/simulatoralgorithm.cpp
src/gromacs/modularsimulator/simulatoralgorithm.h
src/gromacs/modularsimulator/statepropagatordata.cpp
src/gromacs/modularsimulator/statepropagatordata.h
src/gromacs/modularsimulator/topologyholder.cpp
src/gromacs/modularsimulator/trajectoryelement.cpp
src/gromacs/modularsimulator/trajectoryelement.h
src/gromacs/modularsimulator/velocityscalingtemperaturecoupling.cpp
src/gromacs/modularsimulator/velocityscalingtemperaturecoupling.h
src/gromacs/nbnxm/CMakeLists.txt
src/gromacs/nbnxm/atomdata.cpp
src/gromacs/nbnxm/atomdata.h
src/gromacs/nbnxm/benchmark/bench_setup.cpp
src/gromacs/nbnxm/benchmark/bench_system.cpp
src/gromacs/nbnxm/clusterdistancekerneltype.h
src/gromacs/nbnxm/cuda/nbnxm_buffer_ops_kernels.cuh
src/gromacs/nbnxm/cuda/nbnxm_cuda.cu
src/gromacs/nbnxm/cuda/nbnxm_cuda_data_mgmt.cu
src/gromacs/nbnxm/cuda/nbnxm_cuda_kernel.cuh
src/gromacs/nbnxm/cuda/nbnxm_cuda_kernel_pruneonly.cu
src/gromacs/nbnxm/cuda/nbnxm_cuda_kernel_pruneonly.cuh
src/gromacs/nbnxm/cuda/nbnxm_cuda_kernel_utils.cuh
src/gromacs/nbnxm/cuda/nbnxm_cuda_types.h
src/gromacs/nbnxm/gpu_common.h
src/gromacs/nbnxm/gpu_common_utils.h
src/gromacs/nbnxm/gpu_data_mgmt.h
src/gromacs/nbnxm/gpu_types_common.h
src/gromacs/nbnxm/grid.cpp
src/gromacs/nbnxm/grid.h
src/gromacs/nbnxm/gridset.cpp
src/gromacs/nbnxm/gridset.h
src/gromacs/nbnxm/kernel_common.cpp
src/gromacs/nbnxm/kerneldispatch.cpp
src/gromacs/nbnxm/kernels_reference/kernel_gpu_ref.cpp
src/gromacs/nbnxm/kernels_reference/kernel_gpu_ref.h
src/gromacs/nbnxm/kernels_reference/kernel_ref.h
src/gromacs/nbnxm/kernels_reference/kernel_ref_inner.h
src/gromacs/nbnxm/kernels_reference/kernel_ref_outer.h
src/gromacs/nbnxm/kernels_reference/kernel_ref_prune.cpp
src/gromacs/nbnxm/kernels_reference/kernel_ref_prune.h
src/gromacs/nbnxm/kernels_simd_2xmm/kernel_common.h
src/gromacs/nbnxm/kernels_simd_2xmm/kernel_inner.h
src/gromacs/nbnxm/kernels_simd_2xmm/kernel_outer.h
src/gromacs/nbnxm/kernels_simd_2xmm/kernel_prune.cpp
src/gromacs/nbnxm/kernels_simd_2xmm/kernel_prune.h
src/gromacs/nbnxm/kernels_simd_2xmm/kernels.h
src/gromacs/nbnxm/kernels_simd_4xm/kernel_common.h
src/gromacs/nbnxm/kernels_simd_4xm/kernel_inner.h
src/gromacs/nbnxm/kernels_simd_4xm/kernel_outer.h
src/gromacs/nbnxm/kernels_simd_4xm/kernel_prune.cpp
src/gromacs/nbnxm/kernels_simd_4xm/kernel_prune.h
src/gromacs/nbnxm/kernels_simd_4xm/kernels.h
src/gromacs/nbnxm/nbnxm.cpp
src/gromacs/nbnxm/nbnxm.h
src/gromacs/nbnxm/nbnxm_geometry.h
src/gromacs/nbnxm/nbnxm_gpu.h
src/gromacs/nbnxm/nbnxm_gpu_data_mgmt.cpp
src/gromacs/nbnxm/nbnxm_gpu_data_mgmt.h
src/gromacs/nbnxm/nbnxm_setup.cpp
src/gromacs/nbnxm/nbnxm_simd.h
src/gromacs/nbnxm/opencl/CMakeLists.txt
src/gromacs/nbnxm/opencl/nbnxm_ocl.cpp
src/gromacs/nbnxm/opencl/nbnxm_ocl_consts.h
src/gromacs/nbnxm/opencl/nbnxm_ocl_data_mgmt.cpp
src/gromacs/nbnxm/opencl/nbnxm_ocl_jit_support.cpp
src/gromacs/nbnxm/opencl/nbnxm_ocl_kernel.clh
src/gromacs/nbnxm/opencl/nbnxm_ocl_kernel_pruneonly.clh
src/gromacs/nbnxm/opencl/nbnxm_ocl_kernel_utils.clh
src/gromacs/nbnxm/opencl/nbnxm_ocl_kernels.cl
src/gromacs/nbnxm/opencl/nbnxm_ocl_types.h
src/gromacs/nbnxm/pairlist.cpp
src/gromacs/nbnxm/pairlist.h
src/gromacs/nbnxm/pairlist_simd_2xmm.h
src/gromacs/nbnxm/pairlist_simd_4xm.h
src/gromacs/nbnxm/pairlist_tuning.cpp
src/gromacs/nbnxm/pairlist_tuning.h
src/gromacs/nbnxm/pairlistparams.h
src/gromacs/nbnxm/pairlistset.h
src/gromacs/nbnxm/pairlistsets.h
src/gromacs/nbnxm/pairlistwork.h
src/gromacs/nbnxm/pairsearch.cpp
src/gromacs/nbnxm/pairsearch.h
src/gromacs/nbnxm/prunekerneldispatch.cpp
src/gromacs/nbnxm/sycl/CMakeLists.txt [moved from cmake/Platform/XeonPhi.cmake with 83% similarity]
src/gromacs/nbnxm/sycl/nbnxm_sycl.cpp [new file with mode: 0644]
src/gromacs/nbnxm/sycl/nbnxm_sycl_data_mgmt.cpp [new file with mode: 0644]
src/gromacs/nbnxm/sycl/nbnxm_sycl_kernel.cpp [new file with mode: 0644]
src/gromacs/nbnxm/sycl/nbnxm_sycl_kernel.h [moved from src/gromacs/utility/mutex.h with 74% similarity]
src/gromacs/nbnxm/sycl/nbnxm_sycl_kernel_pruneonly.cpp [new file with mode: 0644]
src/gromacs/nbnxm/sycl/nbnxm_sycl_kernel_pruneonly.h [moved from src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_general.h with 67% similarity]
src/gromacs/nbnxm/sycl/nbnxm_sycl_kernel_utils.h [new file with mode: 0644]
src/gromacs/nbnxm/sycl/nbnxm_sycl_types.h [new file with mode: 0644]
src/gromacs/onlinehelp/CMakeLists.txt
src/gromacs/onlinehelp/helpformat.cpp
src/gromacs/onlinehelp/helpformat.h
src/gromacs/onlinehelp/helpmanager.cpp
src/gromacs/onlinehelp/helpmanager.h
src/gromacs/onlinehelp/helptopic.h
src/gromacs/onlinehelp/helpwritercontext.cpp
src/gromacs/onlinehelp/helpwritercontext.h
src/gromacs/onlinehelp/rstparser.h
src/gromacs/onlinehelp/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/onlinehelp/tests/CMakeLists.txt
src/gromacs/options/CMakeLists.txt
src/gromacs/options/abstractoption.h
src/gromacs/options/abstractoptionstorage.h
src/gromacs/options/abstractsection.h
src/gromacs/options/basicoptions.h
src/gromacs/options/filenameoption.cpp
src/gromacs/options/filenameoption.h
src/gromacs/options/filenameoptionmanager.cpp
src/gromacs/options/filenameoptionmanager.h
src/gromacs/options/optionfiletype.h
src/gromacs/options/optionmanagercontainer.h
src/gromacs/options/options.h
src/gromacs/options/options_impl.h
src/gromacs/options/optionsassigner.h
src/gromacs/options/optionsection.h
src/gromacs/options/optionsvisitor.h
src/gromacs/options/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/options/tests/filenameoption.cpp
src/gromacs/options/tests/filenameoptionmanager.cpp
src/gromacs/options/timeunitmanager.cpp
src/gromacs/options/timeunitmanager.h
src/gromacs/options/treesupport.cpp
src/gromacs/pbcutil/CMakeLists.txt
src/gromacs/pbcutil/com.h
src/gromacs/pbcutil/ishift.h
src/gromacs/pbcutil/mshift.cpp
src/gromacs/pbcutil/pbc.cpp
src/gromacs/pbcutil/pbc.h
src/gromacs/pbcutil/pbc_aiuc_cuda.cuh
src/gromacs/pbcutil/pbcenums.cpp
src/gromacs/pbcutil/pbcmethods.cpp
src/gromacs/pbcutil/rmpbc.cpp
src/gromacs/pbcutil/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/pbcutil/tests/com.cpp
src/gromacs/pbcutil/tests/pbc.cpp
src/gromacs/pulling/CMakeLists.txt
src/gromacs/pulling/output.cpp
src/gromacs/pulling/pull.cpp
src/gromacs/pulling/pull.h
src/gromacs/pulling/pull_internal.h
src/gromacs/pulling/pull_rotation.cpp
src/gromacs/pulling/pull_rotation.h
src/gromacs/pulling/pullutil.cpp
src/gromacs/pulling/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/pulling/tests/pull.cpp
src/gromacs/random/CMakeLists.txt
src/gromacs/random/exponentialdistribution.h
src/gromacs/random/gammadistribution.h
src/gromacs/random/normaldistribution.h
src/gromacs/random/tabulatednormaldistribution.h
src/gromacs/random/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/random/tests/threefry.cpp
src/gromacs/random/threefry.h
src/gromacs/random/uniformintdistribution.h
src/gromacs/random/uniformrealdistribution.h
src/gromacs/restraint/CMakeLists.txt
src/gromacs/restraint/manager.cpp
src/gromacs/restraint/restraintmdmodule.cpp
src/gromacs/restraint/restraintmdmodule.h
src/gromacs/restraint/restraintmdmodule_impl.h
src/gromacs/restraint/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/selection/.clang-tidy [new file with mode: 0644]
src/gromacs/selection/CMakeLists.txt
src/gromacs/selection/centerofmass.cpp
src/gromacs/selection/compiler.cpp
src/gromacs/selection/evaluate.cpp
src/gromacs/selection/indexutil.cpp
src/gromacs/selection/nbsearch.cpp
src/gromacs/selection/nbsearch.h
src/gromacs/selection/params.cpp
src/gromacs/selection/parsetree.cpp
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.cpp
src/gromacs/selection/selectioncollection.h
src/gromacs/selection/selectionoptionbehavior.cpp
src/gromacs/selection/selectionoptionbehavior.h
src/gromacs/selection/selectionoptionmanager.cpp
src/gromacs/selection/selectionoptionmanager.h
src/gromacs/selection/selelem.cpp
src/gromacs/selection/selhelp.cpp
src/gromacs/selection/selmethod.cpp
src/gromacs/selection/sm_insolidangle.cpp
src/gromacs/selection/sm_merge.cpp
src/gromacs/selection/sm_permute.cpp
src/gromacs/selection/sm_simple.cpp
src/gromacs/selection/symrec.cpp
src/gromacs/selection/symrec.h
src/gromacs/selection/tests/indexutil.cpp
src/gromacs/selection/tests/nbsearch.cpp
src/gromacs/selection/tests/poscalc.cpp
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_CopiedSelectionWithIndexPostCompilation.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_CopiedSelectionWorksPostCompilation.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_CopiedSelectionWorksPreCompilation.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_CopiedSelectionsAreIndependent.xml [new file with mode: 0644]
src/gromacs/selection/tests/selectioncollection.cpp
src/gromacs/selection/tests/toputils.cpp
src/gromacs/simd/CMakeLists.txt
src/gromacs/simd/impl_arm_neon/impl_arm_neon.h [deleted file]
src/gromacs/simd/impl_arm_neon/impl_arm_neon_definitions.h [deleted file]
src/gromacs/simd/impl_arm_neon/impl_arm_neon_simd4_float.h [deleted file]
src/gromacs/simd/impl_arm_neon/impl_arm_neon_simd_float.h [deleted file]
src/gromacs/simd/impl_arm_neon/impl_arm_neon_util_float.h [deleted file]
src/gromacs/simd/impl_arm_neon_asimd/impl_arm_neon_asimd_general.h
src/gromacs/simd/impl_arm_neon_asimd/impl_arm_neon_asimd_simd4_float.h
src/gromacs/simd/impl_arm_neon_asimd/impl_arm_neon_asimd_simd_float.h
src/gromacs/simd/impl_arm_neon_asimd/impl_arm_neon_asimd_util_float.h
src/gromacs/simd/impl_arm_sve/impl_arm_sve_simd4_double.h
src/gromacs/simd/impl_arm_sve/impl_arm_sve_simd_double.h
src/gromacs/simd/impl_arm_sve/impl_arm_sve_simd_float.h
src/gromacs/simd/impl_arm_sve/impl_arm_sve_util_double.h
src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx.h [deleted file]
src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_definitions.h [deleted file]
src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_simd4_float.h [deleted file]
src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_simd_float.h [deleted file]
src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_util_float.h [deleted file]
src/gromacs/simd/impl_ibm_vsx/impl_ibm_vsx_simd_double.h
src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace.h [deleted file]
src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace_common.h [deleted file]
src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace_simd_double.h [deleted file]
src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace_simd_float.h [deleted file]
src/gromacs/simd/impl_x86_avx_256/impl_x86_avx_256_simd_double.h
src/gromacs/simd/impl_x86_avx_256/impl_x86_avx_256_util_float.h
src/gromacs/simd/impl_x86_avx_512/impl_x86_avx_512_simd4_double.h
src/gromacs/simd/impl_x86_avx_512/impl_x86_avx_512_simd4_float.h
src/gromacs/simd/impl_x86_avx_512/impl_x86_avx_512_simd_double.h
src/gromacs/simd/impl_x86_avx_512/impl_x86_avx_512_simd_float.h
src/gromacs/simd/impl_x86_avx_512/impl_x86_avx_512_util_double.h
src/gromacs/simd/impl_x86_avx_512/impl_x86_avx_512_util_float.h
src/gromacs/simd/impl_x86_mic/impl_x86_mic.h [deleted file]
src/gromacs/simd/impl_x86_mic/impl_x86_mic_definitions.h [deleted file]
src/gromacs/simd/impl_x86_mic/impl_x86_mic_simd4_double.h [deleted file]
src/gromacs/simd/impl_x86_mic/impl_x86_mic_simd4_float.h [deleted file]
src/gromacs/simd/impl_x86_mic/impl_x86_mic_simd_double.h [deleted file]
src/gromacs/simd/impl_x86_mic/impl_x86_mic_simd_float.h [deleted file]
src/gromacs/simd/impl_x86_mic/impl_x86_mic_util_double.h [deleted file]
src/gromacs/simd/impl_x86_mic/impl_x86_mic_util_float.h [deleted file]
src/gromacs/simd/scalar/scalar.h
src/gromacs/simd/scalar/scalar_math.h
src/gromacs/simd/simd.h
src/gromacs/simd/simd_math.h
src/gromacs/simd/simd_memory.h
src/gromacs/simd/support.cpp
src/gromacs/simd/support.h
src/gromacs/simd/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/simd/tests/base.cpp
src/gromacs/simd/tests/base.h
src/gromacs/simd/tests/scalar_math.cpp
src/gromacs/simd/tests/simd4_floatingpoint.cpp
src/gromacs/simd/tests/simd4_math.cpp
src/gromacs/simd/tests/simd4_vector_operations.cpp
src/gromacs/simd/tests/simd_floatingpoint.cpp
src/gromacs/simd/tests/simd_floatingpoint_util.cpp
src/gromacs/simd/tests/simd_math.cpp
src/gromacs/simd/tests/simd_vector_operations.cpp
src/gromacs/statistics/CMakeLists.txt
src/gromacs/statistics/statistics.cpp
src/gromacs/statistics/statistics.h
src/gromacs/swap/CMakeLists.txt
src/gromacs/swap/swapcoords.cpp
src/gromacs/swap/swapcoords.h
src/gromacs/tables/CMakeLists.txt
src/gromacs/tables/cubicsplinetable.cpp
src/gromacs/tables/cubicsplinetable.h
src/gromacs/tables/forcetable.cpp
src/gromacs/tables/forcetable.h
src/gromacs/tables/quadraticsplinetable.cpp
src/gromacs/tables/quadraticsplinetable.h
src/gromacs/tables/splineutil.cpp
src/gromacs/tables/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/tables/tests/splinetable.cpp
src/gromacs/taskassignment/CMakeLists.txt
src/gromacs/taskassignment/decidegpuusage.cpp
src/gromacs/taskassignment/decidegpuusage.h
src/gromacs/taskassignment/findallgputasks.cpp
src/gromacs/taskassignment/reportgpuusage.cpp
src/gromacs/taskassignment/resourcedivision.cpp
src/gromacs/taskassignment/resourcedivision.h
src/gromacs/taskassignment/taskassignment.cpp
src/gromacs/taskassignment/taskassignment.h
src/gromacs/taskassignment/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/taskassignment/usergpuids.cpp
src/gromacs/taskassignment/usergpuids.h
src/gromacs/timing/CMakeLists.txt
src/gromacs/timing/gpu_timing.h
src/gromacs/timing/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/timing/tests/CMakeLists.txt [moved from cmake/Platform/Toolchain-Fujitsu-Sparc64-mpi.cmake with 67% similarity]
src/gromacs/timing/tests/timing.cpp [new file with mode: 0644]
src/gromacs/timing/wallcycle.cpp
src/gromacs/timing/wallcycle.h
src/gromacs/timing/wallcyclereporting.h
src/gromacs/tools/CMakeLists.txt
src/gromacs/tools/check.cpp
src/gromacs/tools/convert_tpr.cpp
src/gromacs/tools/dump.cpp
src/gromacs/tools/eneconv.cpp
src/gromacs/tools/make_ndx.cpp
src/gromacs/tools/mk_angndx.cpp
src/gromacs/tools/pme_error.cpp
src/gromacs/tools/report_methods.cpp
src/gromacs/tools/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/tools/tests/dump.cpp
src/gromacs/tools/tests/report_methods.cpp
src/gromacs/tools/trjcat.cpp
src/gromacs/tools/trjconv.cpp
src/gromacs/tools/tune_pme.cpp
src/gromacs/topology/CMakeLists.txt
src/gromacs/topology/atomprop.cpp
src/gromacs/topology/atomprop.h
src/gromacs/topology/atoms.cpp
src/gromacs/topology/atoms.h
src/gromacs/topology/atomsbuilder.h
src/gromacs/topology/block.cpp
src/gromacs/topology/block.h
src/gromacs/topology/forcefieldparameters.cpp
src/gromacs/topology/idef.cpp
src/gromacs/topology/idef.h
src/gromacs/topology/ifunc.cpp
src/gromacs/topology/index.cpp
src/gromacs/topology/invblock.cpp
src/gromacs/topology/mtop_lookup.h
src/gromacs/topology/mtop_util.cpp
src/gromacs/topology/mtop_util.h
src/gromacs/topology/residuetypes.cpp
src/gromacs/topology/residuetypes.h
src/gromacs/topology/symtab.cpp
src/gromacs/topology/symtab.h
src/gromacs/topology/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/topology/tests/symtab.cpp
src/gromacs/topology/topology.cpp
src/gromacs/topology/topology.h
src/gromacs/topology/topsort.cpp
src/gromacs/trajectory/CMakeLists.txt
src/gromacs/trajectory/energyframe.cpp
src/gromacs/trajectory/energyframe.h
src/gromacs/trajectoryanalysis/CMakeLists.txt
src/gromacs/trajectoryanalysis/analysismodule.cpp
src/gromacs/trajectoryanalysis/analysismodule.h
src/gromacs/trajectoryanalysis/analysissettings.h
src/gromacs/trajectoryanalysis/modules.cpp
src/gromacs/trajectoryanalysis/modules/angle.cpp
src/gromacs/trajectoryanalysis/modules/convert_trj.cpp
src/gromacs/trajectoryanalysis/modules/distance.cpp
src/gromacs/trajectoryanalysis/modules/extract_cluster.cpp
src/gromacs/trajectoryanalysis/modules/freevolume.cpp
src/gromacs/trajectoryanalysis/modules/msd.cpp [new file with mode: 0644]
src/gromacs/trajectoryanalysis/modules/msd.h [moved from src/gromacs/simd/impl_x86_mic/impl_x86_mic_general.h with 69% similarity]
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/surfacearea.cpp
src/gromacs/trajectoryanalysis/modules/surfacearea.h
src/gromacs/trajectoryanalysis/modules/trajectory.cpp
src/gromacs/trajectoryanalysis/runnercommon.cpp
src/gromacs/trajectoryanalysis/runnercommon.h
src/gromacs/trajectoryanalysis/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/CMakeLists.txt
src/gromacs/trajectoryanalysis/tests/convert_trj.cpp
src/gromacs/trajectoryanalysis/tests/extract_cluster.cpp
src/gromacs/trajectoryanalysis/tests/moduletest.cpp
src/gromacs/trajectoryanalysis/tests/moduletest.h
src/gromacs/trajectoryanalysis/tests/msd.cpp [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/rdf.cpp
src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_beginFit.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_endFit.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_molTest.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_multipleGroupsWork.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_notEnoughPointsForFitErrorEstimate.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_oneDimensionalDiffusion.xml [moved from src/gromacs/gmxana/tests/refdata/MsdTest_oneDimensionalDiffusion.xml with 67% similarity]
src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_threeDimensionalDiffusion.xml [moved from src/gromacs/gmxana/tests/refdata/MsdTest_twoDimensionalDiffusion.xml with 67% similarity]
src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_trestartGreaterThanDt.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_trestartLessThanDt.xml [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_twoDimensionalDiffusion.xml [moved from src/gromacs/gmxana/tests/refdata/MsdTest_threeDimensionalDiffusion.xml with 67% similarity]
src/gromacs/trajectoryanalysis/tests/select.cpp
src/gromacs/trajectoryanalysis/tests/surfacearea.cpp
src/gromacs/trajectoryanalysis/tests/test_selection.cpp
src/gromacs/trajectoryanalysis/tests/topologyinformation.cpp
src/gromacs/trajectoryanalysis/topologyinformation.cpp
src/gromacs/utility.h
src/gromacs/utility/CMakeLists.txt
src/gromacs/utility/alignedallocator.cpp
src/gromacs/utility/alignedallocator.h
src/gromacs/utility/any.h
src/gromacs/utility/basenetwork.cpp
src/gromacs/utility/baseversion-gen.cpp.cmakein
src/gromacs/utility/baseversion.cpp
src/gromacs/utility/baseversion_gen.h
src/gromacs/utility/binaryinformation.cpp
src/gromacs/utility/bitmask.h
src/gromacs/utility/classhelpers.h
src/gromacs/utility/compare.h
src/gromacs/utility/coolstuff.cpp
src/gromacs/utility/cstringutil.cpp
src/gromacs/utility/datafilefinder.cpp
src/gromacs/utility/datafilefinder.h
src/gromacs/utility/directoryenumerator.cpp
src/gromacs/utility/directoryenumerator.h
src/gromacs/utility/enumerationhelpers.h
src/gromacs/utility/exceptions.cpp
src/gromacs/utility/fatalerror.cpp
src/gromacs/utility/fatalerror.h
src/gromacs/utility/filestream.cpp
src/gromacs/utility/filestream.h
src/gromacs/utility/fixedcapacityvector.h
src/gromacs/utility/futil.cpp
src/gromacs/utility/gmxassert.cpp
src/gromacs/utility/gmxomp.cpp
src/gromacs/utility/gmxomp.h
src/gromacs/utility/inmemoryserializer.cpp
src/gromacs/utility/inmemoryserializer.h
src/gromacs/utility/int64_to_int.cpp
src/gromacs/utility/iserializer.h
src/gromacs/utility/keyvaluetree.cpp
src/gromacs/utility/keyvaluetreeserializer.cpp
src/gromacs/utility/keyvaluetreetransform.cpp
src/gromacs/utility/keyvaluetreetransform.h
src/gromacs/utility/loggerbuilder.h
src/gromacs/utility/mdmodulenotification-impl.h [deleted file]
src/gromacs/utility/mdmodulesnotifier.h [new file with mode: 0644]
src/gromacs/utility/mdmodulesnotifiers.h [moved from src/gromacs/utility/mdmodulenotification.h with 51% similarity]
src/gromacs/utility/messagestringcollector.h
src/gromacs/utility/mpiinfo.cpp [new file with mode: 0644]
src/gromacs/utility/mpiinfo.h [moved from src/gromacs/simd/impl_arm_neon/impl_arm_neon_general.h with 65% similarity]
src/gromacs/utility/niceheader.cpp
src/gromacs/utility/path.cpp
src/gromacs/utility/physicalnodecommunicator.cpp
src/gromacs/utility/pleasecite.cpp
src/gromacs/utility/programcontext.cpp
src/gromacs/utility/range.h
src/gromacs/utility/smalloc.cpp
src/gromacs/utility/smalloc.h
src/gromacs/utility/strconvert.cpp
src/gromacs/utility/strconvert.h
src/gromacs/utility/strdb.cpp
src/gromacs/utility/stringtoenumvalueconverter.h [new file with mode: 0644]
src/gromacs/utility/stringutil.cpp
src/gromacs/utility/template_mp.h
src/gromacs/utility/tests/.clang-tidy [new file with mode: 0644]
src/gromacs/utility/tests/CMakeLists.txt
src/gromacs/utility/tests/bitmask.h
src/gromacs/utility/tests/enumerationhelpers.cpp
src/gromacs/utility/tests/inmemoryserializer.cpp
src/gromacs/utility/tests/keyvaluetreetransform.cpp
src/gromacs/utility/tests/mdmodulesnotifier.cpp [moved from src/gromacs/utility/tests/mdmodulenotification-impl.cpp with 64% similarity]
src/gromacs/utility/tests/mutex.cpp [deleted file]
src/gromacs/utility/tests/path.cpp
src/gromacs/utility/tests/stringtoenumvalueconverter.cpp [new file with mode: 0644]
src/gromacs/utility/tests/stringutil.cpp
src/gromacs/utility/tests/template_mp.cpp
src/gromacs/utility/textreader.h
src/gromacs/utility/textwriter.h
src/gromacs/utility/txtdump.cpp
src/include/gmxpre.h [moved from src/gmxpre.h with 80% similarity]
src/programs/CMakeLists.txt
src/programs/legacymodules.cpp
src/programs/mdrun/mdrun.cpp
src/programs/mdrun/nonbonded_bench.cpp
src/programs/mdrun/tests/.clang-tidy [new file with mode: 0644]
src/programs/mdrun/tests/CMakeLists.txt
src/programs/mdrun/tests/checkpoint.cpp
src/programs/mdrun/tests/energycomparison.cpp
src/programs/mdrun/tests/energyreader.cpp
src/programs/mdrun/tests/ewaldsurfaceterm.cpp
src/programs/mdrun/tests/exactcontinuation.cpp
src/programs/mdrun/tests/freeenergy.cpp
src/programs/mdrun/tests/freezegroups.cpp [new file with mode: 0644]
src/programs/mdrun/tests/initialconstraints.cpp
src/programs/mdrun/tests/minimize.cpp
src/programs/mdrun/tests/moduletest.cpp
src/programs/mdrun/tests/moduletest.h
src/programs/mdrun/tests/multiple_time_stepping.cpp
src/programs/mdrun/tests/multisim.cpp
src/programs/mdrun/tests/multisimtest.cpp
src/programs/mdrun/tests/multisimtest.h
src/programs/mdrun/tests/nonbonded_bench.cpp
src/programs/mdrun/tests/normalmodes.cpp
src/programs/mdrun/tests/outputfiles.cpp
src/programs/mdrun/tests/periodicactions.cpp
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_Crescale_4Ranks_1RanksPerSimulation_d.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_Crescale_4Ranks_1RanksPerSimulation_s.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_Crescale_4Ranks_2RanksPerSimulation_d.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_Crescale_4Ranks_2RanksPerSimulation_s.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_ParrinelloRahman_4Ranks_1RanksPerSimulation_d.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_ParrinelloRahman_4Ranks_1RanksPerSimulation_s.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_ParrinelloRahman_4Ranks_2RanksPerSimulation_d.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_ParrinelloRahman_4Ranks_2RanksPerSimulation_s.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_Crescale_4Ranks_1RanksPerSimulation_d.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_Crescale_4Ranks_1RanksPerSimulation_s.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_Crescale_4Ranks_2RanksPerSimulation_d.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_Crescale_4Ranks_2RanksPerSimulation_s.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_ParrinelloRahman_4Ranks_1RanksPerSimulation_d.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_ParrinelloRahman_4Ranks_1RanksPerSimulation_s.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_ParrinelloRahman_4Ranks_2RanksPerSimulation_d.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_ParrinelloRahman_4Ranks_2RanksPerSimulation_s.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceVelocityVerlet_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_mdvv_NoseHoover_No_4Ranks_1RanksPerSimulation_d.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceVelocityVerlet_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_mdvv_NoseHoover_No_4Ranks_1RanksPerSimulation_s.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceVelocityVerlet_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_mdvv_NoseHoover_No_4Ranks_2RanksPerSimulation_d.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceVelocityVerlet_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_mdvv_NoseHoover_No_4Ranks_2RanksPerSimulation_s.xml [new file with mode: 0644]
src/programs/mdrun/tests/replicaexchange.cpp
src/programs/mdrun/tests/rerun.cpp
src/programs/mdrun/tests/simple_mdrun.cpp
src/programs/mdrun/tests/simulator.cpp
src/programs/mdrun/tests/termination.cpp
src/programs/mdrun/tests/tpitest.cpp
src/programs/mdrun/tests/trajectorycomparison.cpp
src/programs/mdrun/tests/trajectoryreader.cpp
src/programs/mdrun/tests/virtualsites.cpp [new file with mode: 0644]
src/programs/mdrun_main.cpp
src/programs/view/buttons.cpp
src/programs/view/dialogs.cpp
src/programs/view/fgrid.cpp
src/programs/view/filter.cpp
src/programs/view/logo.cpp
src/programs/view/manager.cpp
src/programs/view/molps.cpp
src/programs/view/nmol.cpp
src/programs/view/popup.cpp
src/programs/view/pulldown.cpp
src/programs/view/view.cpp
src/programs/view/x11.cpp
src/programs/view/xdlg.cpp
src/programs/view/xdlghi.cpp
src/programs/view/xdlgitem.cpp
src/programs/view/xmb.cpp
src/programs/view/xutil.cpp
src/testutils/.clang-tidy [new file with mode: 0644]
src/testutils/CMakeLists.txt
src/testutils/TestMacros.cmake
src/testutils/cmdlinetest.cpp
src/testutils/conftest.cpp
src/testutils/filematchers.cpp
src/testutils/include/testutils/cmdlinetest.h [moved from src/testutils/cmdlinetest.h with 98% similarity]
src/testutils/include/testutils/conftest.h [moved from src/testutils/conftest.h with 97% similarity]
src/testutils/include/testutils/filematchers.h [moved from src/testutils/filematchers.h with 98% similarity]
src/testutils/include/testutils/interactivetest.h [moved from src/testutils/interactivetest.h with 96% similarity]
src/testutils/include/testutils/loggertest.h [moved from src/testutils/loggertest.h with 88% similarity]
src/testutils/include/testutils/mpitest.h [moved from src/testutils/mpitest.h with 91% similarity]
src/testutils/include/testutils/refdata.h [moved from src/testutils/refdata.h with 99% similarity]
src/testutils/include/testutils/setenv.h [moved from src/testutils/setenv.h with 97% similarity]
src/testutils/include/testutils/simulationdatabase.h [moved from src/testutils/simulationdatabase.h with 96% similarity]
src/testutils/include/testutils/stdiohelper.h [moved from src/testutils/stdiohelper.h with 96% similarity]
src/testutils/include/testutils/stringtest.h [moved from src/testutils/stringtest.h with 94% similarity]
src/testutils/include/testutils/test_device.h [moved from src/testutils/test_device.h with 95% similarity]
src/testutils/include/testutils/test_hardware_environment.h [moved from src/testutils/test_hardware_environment.h with 100% similarity]
src/testutils/include/testutils/testasserts.h [moved from src/testutils/testasserts.h with 99% similarity]
src/testutils/include/testutils/testexceptions.h [moved from src/testutils/testexceptions.h with 97% similarity]
src/testutils/include/testutils/testfilemanager.h [moved from src/testutils/testfilemanager.h with 98% similarity]
src/testutils/include/testutils/testfileredirector.h [moved from src/testutils/testfileredirector.h with 96% similarity]
src/testutils/include/testutils/testinit.h [moved from src/testutils/testinit.h with 100% similarity]
src/testutils/include/testutils/testmatchers.h [moved from src/testutils/testmatchers.h with 100% similarity]
src/testutils/include/testutils/testoptions.h [moved from src/testutils/testoptions.h with 98% similarity]
src/testutils/include/testutils/textblockmatchers.h [moved from src/testutils/textblockmatchers.h with 98% similarity]
src/testutils/include/testutils/tprfilegenerator.h [moved from src/testutils/tprfilegenerator.h with 97% similarity]
src/testutils/include/testutils/xvgtest.h [moved from src/testutils/xvgtest.h with 98% similarity]
src/testutils/interactivetest.cpp
src/testutils/loggertest.cpp
src/testutils/mpitest.cpp
src/testutils/refdata.cpp
src/testutils/refdata_checkers.h
src/testutils/refdata_xml.cpp
src/testutils/refdata_xml.h
src/testutils/simulationdatabase.cpp
src/testutils/simulationdatabase/alanine_vacuo.gro [new file with mode: 0644]
src/testutils/simulationdatabase/alanine_vacuo.ndx [new file with mode: 0644]
src/testutils/simulationdatabase/alanine_vacuo.top [new file with mode: 0644]
src/testutils/simulationdatabase/alanine_vsite_solvated.ndx
src/testutils/simulationdatabase/alanine_vsite_solvated.xtc [new file with mode: 0644]
src/testutils/simulationdatabase/msd.ndx [new file with mode: 0644]
src/testutils/simulationdatabase/msd_coords.gro [new file with mode: 0644]
src/testutils/simulationdatabase/msd_traj.xtc [new file with mode: 0644]
src/testutils/simulationdatabase/vsite_test.gro [new file with mode: 0644]
src/testutils/simulationdatabase/vsite_test.ndx [new file with mode: 0644]
src/testutils/simulationdatabase/vsite_test.top [new file with mode: 0644]
src/testutils/stdiohelper.cpp
src/testutils/stringtest.cpp
src/testutils/test_device.cpp
src/testutils/test_hardware_environment.cpp
src/testutils/testasserts.cpp
src/testutils/testfilemanager.cpp
src/testutils/testfileredirector.cpp
src/testutils/testinit.cpp
src/testutils/testmatchers.cpp
src/testutils/testoptions.cpp
src/testutils/tests/CMakeLists.txt
src/testutils/tests/xvgtest_tests.cpp
src/testutils/textblockmatchers.cpp
src/testutils/tprfilegenerator.cpp
src/testutils/unittest_main.cpp
src/testutils/xvgtest.cpp
tests/CMakeLists.txt

index 600e45a53206ca793f299f4de7d3c2710ca61528..b189deb7e2110a17bfdfe0b07106e523c7063710 100644 (file)
@@ -17,7 +17,7 @@ AlwaysBreakAfterDefinitionReturnType: None
 AlwaysBreakAfterReturnType: None
 AlwaysBreakBeforeMultilineStrings: true
 AlwaysBreakTemplateDeclarations: true
-BinPackArguments: true
+BinPackArguments: false
 BinPackParameters: false
 BraceWrapping:
   AfterClass:      true
index 033b5eef4509306cc3d9dda19c6d5789bf80ea6e..5512be09efb9eef388bb9dc0815e6b1e313d7eb0 100644 (file)
@@ -24,14 +24,14 @@ stages:
   - nightly-deploy
   # Release work for packaging code
   - release-package
-  # Release checksum verification
-  - release-verify
   # Configure code for release builds
   - release-configure
   # Release work for packaging code
   - release-build
   # Tests for release code
   - release-tests
+  # Release checksum verification
+  - release-verify
   # Prepare for deploying artifacts
   - release-prepare-deploy
   # Deploy stage for release builds
@@ -42,7 +42,9 @@ include:
   - local: '/admin/gitlab-ci/global.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/rules.gitlab-ci.yml'
   # gmxapi Python package.
-  - local: '/admin/gitlab-ci/python-gmxapi.gitlab-ci.yml'
+  - local: '/admin/gitlab-ci/python-gmxapi01.gitlab-ci.yml'
+  - local: '/admin/gitlab-ci/python-gmxapi02.gitlab-ci.yml'
+  - local: '/admin/gitlab-ci/python-gmxapi03.gitlab-ci.yml'
   # Further API validation and usability of sample gmxapi extension package.
   - local: '/admin/gitlab-ci/sample_restraint.gitlab-ci.yml'
   # API regression testing using sample gmxapi extension package.
index 32a6621dfd30c2cb92a320d64c8cbf3d36569405..344ac3428f109764d869afed37804f7aa4663d74 100644 (file)
@@ -34,7 +34,7 @@
 # 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 3.13)
+cmake_minimum_required(VERSION 3.16.3)
 cmake_policy(SET CMP0074 NEW) # From CMake 3.12
 cmake_policy(SET CMP0068 NEW) # From CMake-3.9
 
@@ -174,20 +174,10 @@ include(gmxOptionUtilities)
 
 set(CMAKE_PREFIX_PATH "" CACHE STRING "Extra locations to search for external libraries and tools (give directory without lib, bin, or include)")
 
-# Fujitsu only has SIMD in double precision, so this will be faster
-gmx_set_boolean(GMX_DOUBLE_DEFAULT GMX_TARGET_FUJITSU_SPARC64)
-option(GMX_DOUBLE "Use double precision (much slower, use only if you really need it)" ${GMX_DOUBLE_DEFAULT})
-option(GMX_RELAXED_DOUBLE_PRECISION "Accept single precision 1/sqrt(x) when using Fujitsu HPC-ACE SIMD" OFF)
-mark_as_advanced(GMX_RELAXED_DOUBLE_PRECISION)
+option(GMX_DOUBLE "Use double precision (much slower, use only if you really need it)" OFF)
 
 option(GMX_MPI    "Build a parallel (message-passing) version of GROMACS" OFF)
 option(GMX_THREAD_MPI  "Build a thread-MPI-based multithreaded version of GROMACS (not compatible with MPI)" ON)
-gmx_dependent_option(
-    GMX_MPI_IN_PLACE
-    "Enable MPI_IN_PLACE for MPIs that have it defined"
-    ON
-    GMX_MPI)
-mark_as_advanced(GMX_MPI_IN_PLACE)
 
 option(GMX_MIMIC "Enable MiMiC QM/MM interface (CPMD is required)" OFF)
 
@@ -210,13 +200,9 @@ gmx_option_multichoice(
     GMX_SIMD
     "SIMD instruction set for CPU kernels and compiler optimization"
     "AUTO"
-    AUTO None SSE2 SSE4.1 AVX_128_FMA AVX_256 AVX2_256 AVX2_128 AVX_512 AVX_512_KNL MIC ARM_NEON ARM_NEON_ASIMD ARM_SVE IBM_VMX IBM_VSX Sparc64_HPC_ACE Reference)
+    AUTO None SSE2 SSE4.1 AVX_128_FMA AVX_256 AVX2_256 AVX2_128 AVX_512 AVX_512_KNL ARM_NEON_ASIMD ARM_SVE IBM_VSX Reference)
 
-if(GMX_TARGET_MIC)
-    set(GMX_FFT_LIBRARY_DEFAULT "mkl")
-else()
-    set(GMX_FFT_LIBRARY_DEFAULT "fftw3")
-endif()
+set(GMX_FFT_LIBRARY_DEFAULT "fftw3")
 
 gmx_option_multichoice(
     GMX_FFT_LIBRARY
@@ -248,8 +234,6 @@ option(GMX_OPENMP "Enable OpenMP-based multithreading" ON)
 
 option(GMX_USE_TNG "Use the TNG library for trajectory I/O" ON)
 
-option(GMX_BUILD_MDRUN_ONLY "Build and install only the mdrun binary" OFF)
-
 option(GMX_CYCLE_SUBCOUNTERS "Enable cycle subcounters to get a more detailed cycle timings" OFF)
 mark_as_advanced(GMX_CYCLE_SUBCOUNTERS)
 
@@ -323,9 +307,6 @@ gmx_test_compiler_problems()
 # want such variables to always have a definition, because #if is more
 # robust than #ifdef. So, we put this value on the compiler command
 # line in all cases.
-#
-# GMX_RELAXED_DOUBLE_PRECISION does not need to be handled here,
-# because no installed header needs it
 if(GMX_DOUBLE)
     set(GMX_DOUBLE_VALUE 1)
 else()
@@ -402,17 +383,6 @@ test_big_endian(GMX_INTEGER_BIG_ENDIAN)
 
 gmx_set_boolean(GMX_USE_NICE "HAVE_UNISTD_H AND HAVE_NICE")
 
-# Management of GROMACS options for specific toolchains should go
-# here. Because the initial settings for some of the main options have
-# already happened, but things like library detection and MPI compiler
-# feature detection have not, the docstrings for any over-rides of
-# GROMACS defaults or user settings will make sense. Also, any
-# toolchain-related reasons for choosing whether to detect various
-# things can be sorted out now, before the detection takes place.
-if(GMX_TARGET_FUJITSU_SPARC64)
-    include(gmxManageFujitsuSparc64)
-endif()
-
 ########################################################################
 #Process MPI settings
 ########################################################################
@@ -561,7 +531,6 @@ tmpi_enable_core("${CMAKE_SOURCE_DIR}/src/external/thread_mpi/include")
 if(GMX_THREAD_MPI)
     # enable MPI functions
     tmpi_enable()
-    set(MPI_IN_PLACE_EXISTS 1)
 endif()
 # If atomics are manually disabled a define is needed because atomics.h doesn't depend on config.h
 if (TMPI_ATOMICS_DISABLED)
@@ -589,6 +558,43 @@ if(GMX_GPU)
         message(WARNING "To use GPU acceleration efficiently, mdrun requires OpenMP multi-threading, which is currently not enabled.")
     endif()
 
+    if (GMX_OPENCL_NB_CLUSTER_SIZE)
+        message(WARNING "GMX_OPENCL_NB_CLUSTER_SIZE is deprecated, use GMX_GPU_NB_CLUSTER_SIZE instead")
+    endif()
+    if (GMX_OPENCL_NB_CLUSTER_SIZE AND GMX_GPU_NB_CLUSTER_SIZE)
+        if (NOT ${GMX_OPENCL_NB_CLUSTER_SIZE} EQUAL ${GMX_GPU_NB_CLUSTER_SIZE})
+            message(FATAL_ERROR "Mismatching values passed to GMX_OPENCL_NB_CLUSTER_SIZE and GMX_GPU_NB_CLUSTER_SIZE; the former is deprecated, use only the latter!")
+        endif()
+    endif()
+    # Only OpenCL and SYCL support changing the default cluster size
+    if (${_gmx_gpu_uppercase} STREQUAL "CUDA")
+        if (GMX_GPU_NB_CLUSTER_SIZE AND NOT "${GMX_GPU_NB_CLUSTER_SIZE}" EQUAL 8)
+            message(FATAL_ERROR "Setting GMX_GPU_NB_CLUSTER_SIZE is not supported in CUDA (the default GMX_GPU_NB_CLUSTER_SIZE=8 is used)")
+        endif()
+    else()
+        # use the legacy GMX_OPENCL_NB_CLUSTER_SIZE variable if set, otherwise set the defaults
+        if (GMX_OPENCL_NB_CLUSTER_SIZE)
+            set(_gmx_gpu_nb_cluster_size_value ${GMX_OPENCL_NB_CLUSTER_SIZE})
+        else()
+            # default cluster size is 8 with OpenCL and 4 with SYCL for now
+            if(${_gmx_gpu_uppercase} STREQUAL "OPENCL")
+                set(_gmx_gpu_nb_cluster_size_value 8)
+            else()
+                set(_gmx_gpu_nb_cluster_size_value 4)
+            endif()
+        endif()
+        set(GMX_GPU_NB_CLUSTER_SIZE ${_gmx_gpu_nb_cluster_size_value} CACHE STRING "Cluster size used by the nonbonded kernel. Set to 4 for Intel GPUs.")
+        mark_as_advanced(GMX_GPU_NB_CLUSTER_SIZE)
+    endif()
+
+endif()
+
+# For build with CUDA and Lib-MPI, check if underlying MPI implementation is CUDA-aware
+# CUDA-aware MPI allows direct GPU communication without staging data through host
+if(GMX_GPU_CUDA AND GMX_LIB_MPI)
+    include(gmxManageCudaAwareMPI)
+else()
+    set(HAVE_CUDA_AWARE_MPI 0)
 endif()
 
 if(CYGWIN)
@@ -610,10 +616,7 @@ gmx_add_cache_dependency(GMX_BUILD_UNITTESTS BOOL BUILD_TESTING OFF)
 # Our own GROMACS tests
 ########################################################################
 
-include_directories(BEFORE ${CMAKE_SOURCE_DIR}/src)
 include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/src/external)
-# Required for config.h, maybe should only be set in src/CMakeLists.txt
-include_directories(BEFORE ${CMAKE_BINARY_DIR}/src)
 
 include(gmxTestInlineASM)
 gmx_test_inline_asm_gcc_x86(GMX_X86_GCC_INLINE_ASM)
@@ -720,6 +723,12 @@ if (GMX_BUILD_HELP AND SOURCE_IS_SOURCE_DISTRIBUTION AND BUILD_IS_INSOURCE)
         "Set GMX_BUILD_HELP=OFF or do an out-of-source build to proceed.")
 endif()
 
+if (GMX_BUILD_FOR_COVERAGE)
+    # Set flags for coverage build here instead having to do so manually
+    set(CMAKE_C_FLAGS "-g --coverage")
+    set(CMAKE_CXX_FLAGS "-g --coverage")
+endif()
+
 # # # # # # # # # # NO MORE TESTS AFTER THIS LINE! # # # # # # # # # # #
 # these are set after everything else
 if (NOT GMX_SKIP_DEFAULT_CFLAGS)
@@ -774,15 +783,6 @@ endif()
 #Simpler to always install.
 install(FILES COPYING DESTINATION ${GMX_INSTALL_GMXDATADIR} COMPONENT data)
 
-if (GMX_BUILD_FOR_COVERAGE)
-    # Code heavy with asserts makes conditional coverage close to useless metric,
-    # as by design most of the false branches are impossible to trigger in
-    # correctly functioning code.  And the benefit of testing those that could
-    # be triggered by using an API against its specification isn't usually
-    # worth the effort.
-    add_definitions(-DNDEBUG -DGMX_DISABLE_ASSERTS)
-endif()
-
 if (BUILD_TESTING)
     include(tests/CheckTarget.cmake)
 endif()
@@ -792,15 +792,13 @@ endif()
 option(GMX_PYTHON_PACKAGE "Configure gmxapi Python package" OFF)
 mark_as_advanced(GMX_PYTHON_PACKAGE)
 
-if (NOT GMX_BUILD_MDRUN_ONLY)
-    find_package(ImageMagick QUIET COMPONENTS convert)
-    include(gmxTestImageMagick)
-    GMX_TEST_IMAGEMAGICK(IMAGE_CONVERT_POSSIBLE)
-    # TODO: Resolve circular dependency between docs, gromacs, and python_packaging
-    add_subdirectory(docs)
-    add_subdirectory(share)
-    add_subdirectory(scripts)
-endif()
+find_package(ImageMagick QUIET COMPONENTS convert)
+include(gmxTestImageMagick)
+GMX_TEST_IMAGEMAGICK(IMAGE_CONVERT_POSSIBLE)
+# TODO: Resolve circular dependency between docs, gromacs, and python_packaging
+add_subdirectory(docs)
+add_subdirectory(share)
+add_subdirectory(scripts)
 add_subdirectory(api)
 add_subdirectory(src)
 
@@ -808,7 +806,7 @@ if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
 
-if(GMX_PYTHON_PACKAGE AND NOT GMX_BUILD_MDRUN_ONLY)
+if(GMX_PYTHON_PACKAGE)
     add_subdirectory(python_packaging)
 endif()
 
diff --git a/admin/ci-scripts/build-and-test-py-gmxapi-0.3.sh b/admin/ci-scripts/build-and-test-py-gmxapi-0.3.sh
new file mode 100644 (file)
index 0000000..e33fb3f
--- /dev/null
@@ -0,0 +1,83 @@
+#!/usr/bin/env bash
+#
+# Build, install, and test the gmxapi 0.2 Python package developed with
+# GROMACS 2021.
+#
+# This script assumes an activated Python venv with the
+# gmxapi dependencies already installed, with `python` resolvable by the shell
+# to the appropriate Python interpreter.
+#
+# This script is intended to support automated GROMACS testing infrastructure,
+# and may be removed without notice.
+#
+# WARNING: This script assumes OpenMPI mpiexec. Syntax for launch wrappers from
+# other implementations will need different syntax, and we should get a
+# MPIRUNNER from the environment, or something.
+
+# Make sure the script errors if any commands error.
+set -e
+
+# Create "sdist" source distribution archive.
+pushd python_packaging/src
+  # TODO: Remove extraneous environment variable with resolution of #3273
+  # Ref: https://redmine.gromacs.org/issues/3273
+  GMXTOOLCHAINDIR=$INSTALL_DIR/share/cmake/gromacs \
+      python setup.py sdist
+  # TODO: Identify SDIST
+
+  # Build and install from sdist.
+  # Note that tool chain may be provided differently in GROMACS 2020 and 2021.
+  GMXTOOLCHAINDIR=$INSTALL_DIR/share/cmake/gromacs \
+      python -m pip install \
+          --no-cache-dir \
+          --no-deps \
+          --no-index \
+          --no-build-isolation \
+          dist/gmxapi*
+  # TODO: Build and install from $SDIST instead of wildcard.
+
+popd
+
+# Run Python unit tests.
+python -m pytest python_packaging/src/test --junitxml=$PY_UNIT_TEST_XML --threads=2
+
+# Note: Multiple pytest processes getting --junitxml output file argument
+# may cause problems, so we set the option on only one of the launched processes.
+# See also Multiple Instruction Multiple Data Model for OpenMPI mpirun:
+# https://www.open-mpi.org/doc/v3.0/man1/mpiexec.1.php
+PROGRAM=(`which python` -m mpi4py -m pytest \
+        -p no:cacheprovider \
+        $PWD/python_packaging/src/test \
+        --threads=1)
+# shellcheck disable=SC2068
+if [ -x `which mpiexec` ]; then
+    PYTHONDONTWRITEBYTECODE=1 \
+    mpiexec --allow-run-as-root \
+      -x OMP_NUM_THREADS=1 \
+      --mca opal_warn_on_missing_libcuda 0 \
+      --mca orte_base_help_aggregate 0 \
+      -n 1 ${PROGRAM[@]} --junitxml=$PLUGIN_MPI_TEST_XML : \
+      -n 1 ${PROGRAM[@]}
+fi
+
+# Run Python acceptance tests.
+python -m pytest python_packaging/test --junitxml=$PY_ACCEPTANCE_TEST_XML --threads=2
+
+# Note: Multiple pytest processes getting --junitxml output file argument
+# may cause problems, so we set the option on only one of the launched processes.
+# See also Multiple Instruction Multiple Data Model for OpenMPI mpirun:
+# https://www.open-mpi.org/doc/v3.0/man1/mpiexec.1.php
+PROGRAM=(`which python` -m mpi4py -m pytest \
+        -p no:cacheprovider \
+        $PWD/python_packaging/test \
+        --threads=1)
+# shellcheck disable=SC2068
+if [ -x `which mpiexec` ]; then
+    PYTHONDONTWRITEBYTECODE=1 \
+    mpiexec --allow-run-as-root \
+      -x OMP_NUM_THREADS=1 \
+      --mca opal_warn_on_missing_libcuda 0 \
+      --mca orte_base_help_aggregate 0 \
+      -n 1 ${PROGRAM[@]} --junitxml=$PLUGIN_MPI_TEST_XML : \
+      -n 1 ${PROGRAM[@]}
+fi
index 36fc12d9e315dd5ecc9edba0ceb4743b0d22b484..4a2fc713276a59062937f5e6b70d840665b7c85c 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -98,15 +98,15 @@ then
     if [ -z "$CLANG_FORMAT" ]
     then
         echo "Please set the path to clang-format using the git hook"
-        echo "git config hooks.clangformatpath /path/to/clang-format"
+        echo "git config hooks.clangformatpath /path/to/clang-format-11"
         echo "or by setting an environment variable, e.g."
-        echo "CLANG_FORMAT=/path/to/clang-format"
+        echo "CLANG_FORMAT=/path/to/clang-format-11"
         echo "See docs/dev-manual/code-formatting.rst for how to get clang-format."
         exit 2
     fi
     if ! which "$CLANG_FORMAT" 1>/dev/null
     then
-        echo "clang-format not found: $CLANG_FORMAT"
+        echo "clang-format-11 not found: $CLANG_FORMAT"
         exit 2
     fi
 fi
index 9668b506e8a0f52e59b4c3d40bb2c3fcded7400e..b7f770d87ec097ffe04ccdebd2ca1a6eb98f79f7 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2020, by the GROMACS development team, led by
+# Copyright (c) 2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,12 +107,12 @@ then
         echo "Please set the path to run-clang-tidy using the git hook"
         echo "git config hooks.runclangtidypath /path/to/run-clang-tidy-9.py"
         echo "or by setting an environment variable, e.g."
-        echo "RUN_CLANG_TIDY=/path/to/run-clang-tidy-9.py"
+        echo "RUN_CLANG_TIDY=/path/to/run-clang-tidy-11.py"
         exit 2
     fi
     if ! which "$RUN_CLANG_TIDY" 1>/dev/null
     then
-        echo "run-clang-tidy-9.py not found: $RUN_CLANG_TIDY"
+        echo "run-clang-tidy-11.py not found: $RUN_CLANG_TIDY"
         exit 2
     fi
 fi
old mode 100644 (file)
new mode 100755 (executable)
index 1dd359d..fe02f4e
@@ -14,12 +14,14 @@ args[${#args[@]}]="--gcc 9 --clfft --mpi openmpi"
 args[${#args[@]}]="--gcc 8 --cuda 11.0 --clfft --mpi openmpi"
 args[${#args[@]}]="--gcc 7 --cuda 10.2 --clfft --mpi openmpi --ubuntu 18.04"
 args[${#args[@]}]="--llvm 8 --tsan"
+args[${#args[@]}]="--llvm 11 --tsan"
 args[${#args[@]}]="--llvm 8 --cuda 10.0 --clfft --mpi openmpi"
 args[${#args[@]}]="--llvm 8 --cuda 10.1 --clfft --mpi openmpi"
 args[${#args[@]}]="--llvm 8 --cuda 11.0 --clfft --mpi openmpi"
 args[${#args[@]}]="--llvm 9 --clfft --mpi openmpi --ubuntu 18.04"
 args[${#args[@]}]="--oneapi 2021.1.1"
-args[${#args[@]}]="--llvm --doxygen"
+args[${#args[@]}]="--llvm --doxygen --mpi openmpi --venvs 3.7.7"
+args[${#args[@]}]="--llvm 11 --cuda 11.2.1 --hipsycl 2bc21b677a --ubuntu 20.04"
 
 echo "Building the following images."
 for arg_string in "${args[@]}"; do
@@ -30,7 +32,7 @@ echo
 
 for arg_string in "${args[@]}"; do
   # shellcheck disable=SC2086
-  tag=$(python3 -m utility $arg_string):release-2021
+  tag=$(python3 -m utility $arg_string)
   tags[${#tags[@]}]=$tag
   # shellcheck disable=SC2086
   python3 $SCRIPT $arg_string | docker build -t $tag -
index c3f3e770888a3f244a570620b056cdfaa40155f8..7425cb29b7ff32ca8bdfaaa577f181ad7f204e38 100755 (executable)
@@ -192,10 +192,15 @@ def base_image_tag(args) -> str:
 def get_llvm_packages(args) -> typing.Iterable[str]:
     # If we use the package version of LLVM, we need to install extra packages for it.
     if (args.llvm is not None) and (args.tsan is None):
-        return ['libomp-dev',
-                'libomp5',
-                'clang-format-' + str(args.llvm),
-                'clang-tidy-' + str(args.llvm)]
+        packages = [f'libomp-{args.llvm}-dev',
+                    f'libomp5-{args.llvm}',
+                    'clang-format-' + str(args.llvm),
+                    'clang-tidy-' + str(args.llvm)]
+        if args.hipsycl is not None:
+            packages += [f'llvm-{args.llvm}-dev',
+                         f'libclang-{args.llvm}-dev',
+                         f'lld-{args.llvm}']
+        return packages
     else:
         return []
 
@@ -207,9 +212,6 @@ def get_opencl_packages(args) -> typing.Iterable[str]:
 
 def get_compiler(args, compiler_build_stage: hpccm.Stage = None) -> bb_base:
     # Compiler
-    if args.icc is not None:
-        raise RuntimeError('Intel compiler toolchain recipe not implemented yet')
-
     if args.llvm is not None:
         # Build our own version instead to get TSAN + OMP
         if args.tsan is not None:
@@ -226,8 +228,8 @@ def get_compiler(args, compiler_build_stage: hpccm.Stage = None) -> bb_base:
             compiler = compiler_build_stage.runtime(_from='oneapi')
             # Prepare the toolchain (needed only for builds done within the Dockerfile, e.g.
             # OpenMPI builds, which don't currently work for other reasons)
-            oneapi_toolchain = hpccm.toolchain(CC='/opt/intel/oneapi/compiler/latest/linux/bin/intel64/icc',
-                                               CXX='/opt/intel/oneapi/compiler/latest/linux/bin/intel64/icpc')
+            oneapi_toolchain = hpccm.toolchain(CC=f'/opt/intel/oneapi/compiler/{args.oneapi}/linux/bin/intel64/icx',
+                                               CXX=f'/opt/intel/oneapi/compiler/{args.oneapi}/linux/bin/intel64/icpx')
             setattr(compiler, 'toolchain', oneapi_toolchain)
 
         else:
@@ -279,6 +281,38 @@ def get_clfft(args):
     else:
         return None
 
+def get_hipsycl(args):
+    if args.hipsycl is None:
+        return None
+    if args.llvm is None:
+        raise RuntimeError('Can not build hipSYCL without llvm')
+
+    cmake_opts = [f'-DLLVM_DIR=/usr/lib/llvm-{args.llvm}/cmake',
+                  f'-DCLANG_EXECUTABLE_PATH=/usr/bin/clang++-{args.llvm}',
+                  '-DCMAKE_PREFIX_PATH=/opt/rocm/lib/cmake',
+                  '-DWITH_ROCM_BACKEND=ON']
+    if args.cuda is not None:
+        cmake_opts += [f'-DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda',
+                       '-DWITH_CUDA_BACKEND=ON']
+
+    postinstall = [
+            # https://github.com/illuhad/hipSYCL/issues/361#issuecomment-718943645
+            'for f in /opt/rocm/amdgcn/bitcode/*.bc; do ln -s "$f" "/opt/rocm/lib/$(basename $f .bc).amdgcn.bc"; done'
+            ]
+    if args.cuda is not None:
+        postinstall += [
+            # https://github.com/illuhad/hipSYCL/issues/410#issuecomment-743301929
+            f'sed s/_OPENMP/__OPENMP_NVPTX__/ -i /usr/lib/llvm-{args.llvm}/lib/clang/*/include/__clang_cuda_complex_builtins.h',
+            # Not needed unless we're building with CUDA 11.x, but no harm in doing always
+            f'ln -s /usr/local/cuda/compat/* /usr/local/cuda/lib64/'
+            ]
+
+    return hpccm.building_blocks.generic_cmake(
+        repository='https://github.com/illuhad/hipSYCL.git',
+        directory='/var/tmp/hipSYCL',
+        prefix='/usr/local', recursive=True, commit=args.hipsycl,
+        cmake_opts=['-DCMAKE_BUILD_TYPE=Release', *cmake_opts],
+        postinstall=postinstall)
 
 def add_tsan_compiler_build_stage(input_args, output_stages: typing.Mapping[str, hpccm.Stage]):
     """Isolate the expensive TSAN preparation stage.
@@ -326,9 +360,6 @@ def add_oneapi_compiler_build_stage(input_args, output_stages: typing.Mapping[st
     This stage is isolated so that its installed components are minimized in the
     final image (chiefly /opt/intel) and its environment setup script can be
     sourced. This also helps with rebuild time and final image size.
-
-    Note that the ICC compiler inside oneAPI on linux also needs
-    gcc to build other components and provide libstdc++.
     """
     if not isinstance(output_stages, collections.abc.MutableMapping):
         raise RuntimeError('Need output_stages container.')
@@ -343,14 +374,16 @@ def add_oneapi_compiler_build_stage(input_args, output_stages: typing.Mapping[st
         apt_keys=['https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB'],
         apt_repositories=['deb https://apt.repos.intel.com/oneapi all main'],
         # Add minimal packages (not the whole HPC toolkit!)
-        ospackages=['intel-oneapi-dpcpp-cpp-{}'.format(version),
-            'intel-oneapi-openmp-{}'.format(version),
-            'intel-oneapi-mkl-{}'.format(version),
-            'intel-oneapi-mkl-devel-{}'.format(version)]
+        ospackages=[f'intel-oneapi-dpcpp-cpp-{version}',
+            f'intel-oneapi-openmp-{version}',
+            f'intel-oneapi-mkl-{version}',
+            f'intel-oneapi-mkl-devel-{version}']
     )
     # Ensure that all bash shells on the final container will have access to oneAPI
     oneapi_stage += hpccm.primitives.shell(
-            commands=['echo "source /opt/intel/oneapi/setvars.sh" >> /etc/bash.bashrc']
+            commands=['echo "source /opt/intel/oneapi/setvars.sh" >> /etc/bash.bashrc',
+                      'unlink /opt/intel/oneapi/compiler/latest',
+                     f'ln -sf /opt/intel/oneapi/compiler/{version} /opt/intel/oneapi/compiler/latest']
             )
     setattr(oneapi_stage, 'runtime', oneapi_runtime)
 
@@ -363,35 +396,33 @@ def prepare_venv(version: StrictVersion) -> typing.Sequence[str]:
 
     pyenv = '$HOME/.pyenv/bin/pyenv'
 
-    py_ver = '{}.{}'.format(major, minor)
-    venv_path = '$HOME/venv/py{}'.format(py_ver)
-    commands = ['$({pyenv} prefix `{pyenv} whence python{py_ver}`)/bin/python -m venv {path}'.format(
-        pyenv=pyenv,
-        py_ver=py_ver,
-        path=venv_path
-    )]
-
-    commands.append('{path}/bin/python -m pip install --upgrade pip setuptools'.format(
-        path=venv_path
-    ))
+    py_ver = f'{major}.{minor}'
+    venv_path = f'$HOME/venv/py{py_ver}'
+    commands = [f'$({pyenv} prefix `{pyenv} whence python{py_ver}`)/bin/python -m venv {venv_path}']
+
+    commands.append(f'{venv_path}/bin/python -m pip install --upgrade pip setuptools')
     # Install dependencies for building and testing gmxapi Python package.
     # WARNING: Please keep this list synchronized with python_packaging/requirements-test.txt
     # TODO: Get requirements.txt from an input argument.
-    commands.append("""{path}/bin/python -m pip install --upgrade \
-            'cmake>=3.13' \
+    commands.append(f"""{venv_path}/bin/python -m pip install --upgrade \
+            'cmake>=3.16.3' \
             'flake8>=3.7.7' \
+            'gcovr>=4.2' \
             'mpi4py>=3.0.3' \
             'networkx>=2.0' \
             'numpy>=1' \
             'pip>=10.1' \
+            'Pygments>=2.2.0' \
             'pytest>=3.9' \
             'setuptools>=42' \
-            'scikit-build>=0.10'""".format(path=venv_path))
+            'scikit-build>=0.10' \
+            'Sphinx>=1.6.3' \
+            'sphinxcontrib-plantuml>=0.14'""")
 
     # TODO: Remove 'importlib_resources' dependency when Python >=3.7 is required.
     if minor == 6:
-        commands.append("""{path}/bin/python -m pip install --upgrade \
-                'importlib_resources'""".format(path=venv_path))
+        commands.append(f"""{venv_path}/bin/python -m pip install --upgrade \
+                'importlib_resources'""")
 
     return commands
 
@@ -438,9 +469,7 @@ def add_python_stages(building_blocks: typing.Mapping[str, bb_base],
             """echo 'eval "$(pyenv init -)"' >> $HOME/.bashrc""",
             """echo 'eval "$(pyenv virtualenv-init -)"' >> $HOME/.bashrc"""])
         pyenv = '$HOME/.pyenv/bin/pyenv'
-        commands = ['PYTHON_CONFIGURE_OPTS="--enable-shared" {pyenv} install -s {version}'.format(
-            pyenv=pyenv,
-            version=str(version))]
+        commands = [f'PYTHON_CONFIGURE_OPTS="--enable-shared" {pyenv} install -s {version}']
         stage += hpccm.primitives.shell(commands=commands)
 
         commands = prepare_venv(version)
@@ -473,7 +502,6 @@ def add_documentation_dependencies(input_args,
         return
     output_stages['main'] += hpccm.primitives.shell(
         commands=['sed -i \'/\"XPS\"/d;/\"PDF\"/d;/\"PS\"/d;/\"EPS\"/d;/disable ghostscript format types/d\' /etc/ImageMagick-6/policy.xml'])
-    output_stages['main'] += hpccm.building_blocks.pip(pip='pip3', packages=['sphinx==1.6.1', 'gcovr'])
     if input_args.doxygen == '1.8.5':
         doxygen_commit = 'ed4ed873ab0e7f15116e2052119a6729d4589f7a'
         output_stages['main'] += hpccm.building_blocks.generic_autotools(
@@ -491,17 +519,14 @@ def add_documentation_dependencies(input_args,
                 '--static'])
     else:
         version = input_args.doxygen
-        archive_name = 'doxygen-{}.linux.bin.tar.gz'.format(version)
-        archive_url = 'https://sourceforge.net/projects/doxygen/files/rel-{}/{}'.format(
-            version,
-            archive_name
-        )
-        binary_path = 'doxygen-{}/bin/doxygen'.format(version)
+        archive_name = f'doxygen-{version}.linux.bin.tar.gz'
+        archive_url = f'https://sourceforge.net/projects/doxygen/files/rel-{version}/{archive_name}'
+        binary_path = f'doxygen-{version}/bin/doxygen'
         commands = [
             'mkdir doxygen && cd doxygen',
-            'wget {}'.format(archive_url),
-            'tar xf {} {}'.format(archive_name, binary_path),
-            'cp {} /usr/local/bin/'.format(binary_path),
+            f'wget {archive_url}',
+            f'tar xf {archive_name} {binary_path}',
+            f'cp {binary_path} /usr/local/bin/',
             'cd .. && rm -rf doxygen'
         ]
         output_stages['main'] += hpccm.primitives.shell(commands=commands)
@@ -539,7 +564,7 @@ def build_stages(args) -> typing.Iterable[hpccm.Stage]:
     for i, cmake in enumerate(args.cmake):
         building_blocks['cmake' + str(i)] = hpccm.building_blocks.cmake(
             eula=True,
-            prefix='/usr/local/cmake-{}'.format(cmake),
+            prefix=f'/usr/local/cmake-{cmake}',
             version=cmake)
 
     # Install additional packages early in the build to optimize Docker build layer cache.
@@ -548,6 +573,8 @@ def build_stages(args) -> typing.Iterable[hpccm.Stage]:
         os_packages += _docs_extra_packages
     if args.oneapi is not None:
         os_packages += ['lsb-release']
+    if args.hipsycl is not None:
+        os_packages += ['libboost-fiber-dev']
     building_blocks['extra_packages'] = hpccm.building_blocks.packages(
         ospackages=os_packages,
         apt_ppas=['ppa:intel-opencl/intel-opencl'],
@@ -555,8 +582,24 @@ def build_stages(args) -> typing.Iterable[hpccm.Stage]:
         apt_repositories=['deb [arch=amd64] http://repo.radeon.com/rocm/apt/debian/ xenial main']
     )
 
+    if args.cuda is not None and args.llvm is not None:
+        # Hack to tell clang what version of CUDA we're using
+        # based on https://github.com/llvm/llvm-project/blob/1fdec59bffc11ae37eb51a1b9869f0696bfd5312/clang/lib/Driver/ToolChains/Cuda.cpp#L43
+        cuda_version_split = args.cuda.split('.')
+        # LLVM requires having the version in x.y.z format, while args.cuda be be either x.y or x.y.z
+        cuda_version_str = '{}.{}.{}'.format(
+            cuda_version_split[0],
+            cuda_version_split[1],
+            cuda_version_split[2] if len(cuda_version_split) > 2 else 0
+        )
+        building_blocks['cuda-clang-workaround'] = hpccm.primitives.shell(commands=[
+            f'echo "CUDA Version {cuda_version_str}" > /usr/local/cuda/version.txt'
+            ])
+
     building_blocks['clfft'] = get_clfft(args)
 
+    building_blocks['hipSYCL'] = get_hipsycl(args)
+
     # Add Python environments to MPI images, only, so we don't have to worry
     # about whether to install mpi4py.
     if args.mpi is not None and len(args.venvs) > 0:
@@ -571,9 +614,7 @@ def build_stages(args) -> typing.Iterable[hpccm.Stage]:
             stages['main'] += bb
 
     # We always add Python3 and Pip
-    stages['main'] += hpccm.building_blocks.python(python3=True, python2=False, devel=True)
-    stages['main'] += hpccm.building_blocks.pip(upgrade=True, pip='pip3',
-                                                packages=['pytest', 'networkx', 'numpy'])
+    stages['main'] += hpccm.building_blocks.python(python3=True, python2=False)
 
     # Add documentation requirements (doxygen and sphinx + misc).
     if args.doxygen is not None:
index 47e943e0526090040f307b5603a8bdd4347e5392..c374f88480f065a38483218ec360140542f081d3 100644 (file)
@@ -86,7 +86,7 @@ parsers for tools.
     Instead, inherit from it with the *parents* argument to :py:class:`argparse.ArgumentParser`
 """
 
-parser.add_argument('--cmake', nargs='*', type=str, default=['3.13.0', '3.15.7', '3.17.2'],
+parser.add_argument('--cmake', nargs='*', type=str, default=['3.16.3', '3.17.2', '3.18.4'], # new minimum required versions
                     help='Selection of CMake version to provide to base image')
 
 compiler_group = parser.add_mutually_exclusive_group()
@@ -96,9 +96,6 @@ compiler_group.add_argument('--gcc', type=int, nargs='?', const=7, default=7,
 compiler_group.add_argument('--llvm', type=str, nargs='?', const='7', default=None,
                             help='Select LLVM compiler tool chain. '
                                  'Some checking is implemented to avoid incompatible combinations')
-compiler_group.add_argument('--icc', type=int, nargs='?', const=19, default=None,
-                            help='Select Intel compiler tool chain. '
-                                 'Some checking is implemented to avoid incompatible combinations')
 # TODO currently the installation merely gets the latest beta version of oneAPI,
 # not a specific version. GROMACS probably doesn't need to address that until
 # oneAPI makes an official release. Also, the resulting container is a mix
@@ -123,6 +120,9 @@ parser.add_argument('--mpi', type=str, nargs='?', const='openmpi', default=None,
 parser.add_argument('--tsan', type=str, nargs='?', const='llvm', default=None,
                     help='Build special compiler versions with TSAN OpenMP support')
 
+parser.add_argument('--hipsycl', type=str, nargs='?', default=None,
+                    help='Select hipSYCL repository tag/commit/branch.')
+
 parser.add_argument('--clfft', type=str, nargs='?', const='master', default=None,
                     help='Add external clFFT libraries to the build image')
 
@@ -155,12 +155,12 @@ def image_name(configuration: argparse.Namespace) -> str:
         if version is not None:
             elements.append(distro + '-' + version)
             break
-    for compiler in ('icc', 'llvm', 'gcc'):
+    for compiler in ('llvm', 'gcc'):
         version = getattr(configuration, compiler, None)
         if version is not None:
             elements.append(compiler + '-' + str(version).split('.')[0])
             break
-    for gpusdk in ('cuda',):
+    for gpusdk in ('cuda', 'hipsycl'):
         version = getattr(configuration, gpusdk, None)
         if version is not None:
             elements.append(gpusdk + '-' + version)
index e6506adaa1532ea5dc6df65320ea042c4d32a396..f20e930d7d82ca43203e5ec746fc745da4fb42f7 100755 (executable)
@@ -88,7 +88,7 @@ then
     if [ -z "$runclangtidy_path" ]
     then
         echo "Please set the path to run-clang-tidy using 'git config hooks.runclangtidypath'."
-        echo "Note that you need at least clang-tidy-9."
+        echo "Note that you should use clang-tidy-11 to get the same checking as in CI."
         exit 1
     fi
     export RUN_CLANG_TIDY="$runclangtidy_path"
index 8a582e5cb2608907675a1954035c0154e4855af0..e6f86417d7b7149331d364ee065165561d53d7a8 100644 (file)
@@ -5,7 +5,7 @@ prepare-release-version:
     - .variables:default
     - .rules:nightly-only-for-release
   cache: {}
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs
   stage: configure-build
   variables:
     KUBERNETES_CPU_LIMIT: 1
@@ -25,15 +25,15 @@ regressiontests:prepare:
     - .variables:default
     - .rules:merge-and-post-merge-acceptance
   cache: {}
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs
   stage: configure-build
   variables:
     KUBERNETES_CPU_LIMIT: 1
     KUBERNETES_CPU_REQUEST: 1
     KUBERNETES_MEMORY_REQUEST: 2Gi
-  # Always clone the default version for this branch, 2021 in this case
+  # Always clone the default version for this branch, master in this case
   script:
-    - export REGTESTBRANCH=release-2021
+    - export REGTESTBRANCH=master
     - if [[ ! -z $REGRESSIONTESTBRANCH ]] ; then
       export REGTESTBRANCH=$REGRESSIONTESTBRANCH ;
       echo "Using $REGTESTBRANCH instead of default" ;
@@ -69,7 +69,7 @@ regressiontests:package:
   cache: {}
   # Docker image uploaded to dockerhub by user eriklindahl
   # TODO: Get DockerFile for admin/dockerfiles
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs
   stage: release-package
   variables:
     KUBERNETES_CPU_LIMIT: 1
@@ -84,7 +84,7 @@ regressiontests:package:
     - if [[ $GROMACS_RELEASE != "true" ]] ; then
       REGTESTNAME=$REGTESTNAME-dev ;
       fi
-    - export REGTESTBRANCH=release-2021
+    - export REGTESTBRANCH=master
     - if [[ $CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME == "release-20"[1-2][0-9] ]] ; then
       export REGTESTBRANCH=$CI_COMMIT_REF_NAME ;
       fi
@@ -143,7 +143,7 @@ archive:configure:release:
     - .use-ccache
     - .before_script:default
     - .docs:build
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs
   variables:
     KUBERNETES_CPU_LIMIT: 4
     KUBERNETES_CPU_REQUEST: 2
@@ -182,7 +182,9 @@ archive:configure:release:
     when: always
     expire_in: 1 week
     paths:
-      - $BUILD_DIR/*log
+      - $BUILD_DIR/*logs
+      - $BUILD_DIR/bin
+      - $BUILD_DIR/lib
       - gromacs*tar.gz
 
 archive:build:
@@ -205,8 +207,8 @@ archive:package:
   variables:
     BUILD_DIR: build-package
 
-release-verify:
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs:release-2021
+checksum-verify:
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs
   stage: release-verify
   extends:
     - .variables:default
@@ -217,25 +219,30 @@ release-verify:
     KUBERNETES_CPU_LIMIT: 1
     KUBERNETES_CPU_REQUEST: 1
     KUBERNETES_MEMORY_REQUEST: 2Gi
+    BUILD_DIR: build-package
   script:
+    - VALID_BUILD=true
     - VERSION=`cat version.json |
       python3 -c "import json,sys; print(json.load(sys.stdin)['version'])"`
-    - if [[ $GROMACS_RELEASE != "true" ]] ; then
-      VERSION=$VERSION-dev ;
+    - if [[ "$GROMACS_RELEASE" != "true" ]] ; then
+      VERSION="$VERSION"-dev ;
       fi
     - REGTEST_COMPARE=`cat version.json |
       python3 -c "import json,sys; print(json.load(sys.stdin)['regressiontest-md5sum'])"`
-    - SOURCENAME=gromacs-$VERSION
-    - SOURCETARBALL=$SOURCENAME.tar.gz
-    - SOURCE_MD5SUM=`md5sum $SOURCETARBALL | awk '{print $1}'`
-    - REGTESTNAME=regressiontests-$VERSION
-    - REGTESTTARBALL=$REGTESTNAME.tar.gz
-    - REGTEST_MD5SUM=`md5sum $REGTESTTARBALL | awk '{print $1}'`
+    - SOURCENAME=gromacs-"$VERSION"
+    - SOURCETARBALL="$SOURCENAME".tar.gz
+    - SOURCE_MD5SUM=`md5sum "$SOURCETARBALL" | awk '{print $1}'`
+    - REGTESTNAME=regressiontests-"$VERSION"
+    - REGTESTTARBALL="$REGTESTNAME".tar.gz
+    - REGTEST_MD5SUM=`md5sum "$REGTESTTARBALL" | awk '{print $1}'`
     - echo "$SOURCETARBALL md5sum = $SOURCE_MD5SUM"
     - echo "$REGTESTTARBALL md5sum = $REGTEST_MD5SUM"
     - echo "$REGTESTTARBALL reference md5sum = $REGTEST_COMPARE"
-    - if [[ $REGTEST_COMPARE != $REGTEST_MD5SUM && $GROMACS_RELEASE == "true" ]] ; then
+    - if [[ "$REGTEST_COMPARE" != "$REGTEST_MD5SUM" && "$GROMACS_RELEASE" == "true" ]] ; then
       echo "Mismatch in regressiontest md5sums";
+      VALID_BUILD=false;
+      fi
+    - if [[ "$VALID_BUILD" != "true" ]] ; then
       exit 1;
       fi
   dependencies:
@@ -243,6 +250,40 @@ release-verify:
     - regressiontests:package
     - prepare-release-version
 
+version-verify:
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs
+  stage: release-verify
+  extends:
+    - .variables:default
+    - .rules:nightly-only-for-release
+  cache: {}
+
+  variables:
+    KUBERNETES_CPU_LIMIT: 1
+    KUBERNETES_CPU_REQUEST: 1
+    KUBERNETES_MEMORY_REQUEST: 2Gi
+    BUILD_DIR: release-doc-builds
+  script:
+    - VALID_BUILD=true
+    - VERSION=`cat version.json |
+      python3 -c "import json,sys; print(json.load(sys.stdin)['version'])"`
+    - if [[ "$GROMACS_RELEASE" != "true" ]] ; then
+      VERSION="$VERSION"-dev ;
+      fi
+    - VERSION_FROM_BINARY=`"${BUILD_DIR}"/bin/gmx --version | grep "GROMACS version" | awk '{print $3}'`
+    - echo "Version name from CMake = $VERSION"
+    - echo "Version name from binary = $VERSION_FROM_BINARY"
+    - if [[ "$VERSION" != "$VERSION_FROM_BINARY" && "$GROMACS_RELEASE" == "true" ]] ; then
+      echo "Version names don't match";
+      VALID_BUILD=false;
+      fi
+    - if [[ "$VALID_BUILD" != "true" ]] ; then
+      exit 1;
+      fi
+  dependencies:
+    - webpage:dependencies
+    - prepare-release-version
+
 archive:nightly-webpage:
   extends:
     - .webpage:build
@@ -254,8 +295,16 @@ archive:nightly-webpage:
     - job: webpage:build
   variables:
     BUILD_DIR: build-docs
+  before_script:
+    - eval $(ssh-agent -s)
+    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
+    - mkdir -p ~/.ssh
+    - chmod 700 ~/.ssh
+    - ssh-keyscan manual.gromacs.org > ~/.ssh/known_hosts # Force overwrite the known hosts so we only have that one key in it.
+    - chmod 644 ~/.ssh/known_hosts
   script:
     - tar czf webpage.tar.gz $BUILD_DIR/docs/html/
+    - rsync --chmod=u+rwX,g+rwX,o+rX -av $BUILD_DIR/docs/html/* $BUILD_DIR/docs/html/.[a-z]* pbauer@manual.gromacs.org:/var/www/manual/nightly/
 
   artifacts:
     when: always
index 785dee9df73010c0959c1a11e1cd3d0f331787b7..b15f6c7e807dc346d216e33f3cb6da7d5edf59ef 100644 (file)
@@ -6,7 +6,7 @@
     - .gromacs:base:configure
     - .before_script:default
   # TODO (#3480) this should be organized more like the current documentation.py script
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs
   stage: configure-build
   cache: {}
   variables:
       mkdir $BUILD_DIR ;
       fi
     - cd $BUILD_DIR
+    # Running CMake with the venv activated should not be strictly necessary,
+    # but helps to find and cache self-consistent Python and Sphinx details
+    # without additional hinting. Once CMakeCache.txt exists, the later stages
+    # should work fine without reactivating the venv.
+    - source /root/venv/py3.7/bin/activate
     - cmake ..
       -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
       $CMAKE_COMPILER_SCRIPT
@@ -72,7 +77,7 @@
     - .before_script:default
     - .rules:nightly-only-for-release
   # TODO (#3480) this should be organized more like the current documentation.py script
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs
   stage: release-configure
   cache: {}
   variables:
       mkdir $RELEASE_BUILD_DIR ;
       fi
     - cd $RELEASE_BUILD_DIR
+    - source /root/venv/py3.7/bin/activate
     - cmake ../$RELEASE_SOURCE/
       -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
       $CMAKE_COMPILER_SCRIPT
@@ -182,7 +188,7 @@ docs:configure:
 
 .docs:build:
   # TODO (#3480) this should be organized more like the current documentation.py script
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs
   script:
     - cd $BUILD_DIR
     - cmake --build . --target gmx -- -j8
@@ -222,7 +228,7 @@ docs:build:
     - .gromacs:base:build
     - .before_script:default
   # TODO (#3480) this should be organized more like the current documentation.py script
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs
   cache: {}
   variables:
     KUBERNETES_CPU_LIMIT: 4
index c90d795014dac27abf99bbd1d9a8f540d034508b..96dcd9ae14bcd205a774679a37f886d5887927ab 100644 (file)
@@ -15,7 +15,7 @@
     KUBERNETES_MEMORY_LIMIT: 8Gi
     KUBERNETES_EXTENDED_RESOURCE_NAME: ""
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 0
-    CACHE_FALLBACK_KEY: "$CI_JOB_NAME-$CI_JOB_STAGE-release-2021"
+    CACHE_FALLBACK_KEY: "$CI_JOB_NAME-$CI_JOB_STAGE-master"
     BUILD_DIR: build
     INSTALL_DIR: install
     CMAKE_GMXAPI_OPTIONS: ""
@@ -79,7 +79,7 @@
 # Base definition for using oneAPI.
 .use-oneapi:base:
   variables:
-    # Use the HPC variants of icc and icpc so that OpenMP is active
+    # Use the HPC clang-based compiler variants so that OpenMP is active
     CMAKE_COMPILER_SCRIPT: -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DCMAKE_INCLUDE_PATH=/opt/intel/oneapi/compiler/latest/linux/include/sycl -DCMAKE_PREFIX_PATH=/opt/intel/oneapi/compiler/latest/linux
     CMAKE_EXTRA_OPTIONS: -DGMX_FFT_LIBRARY=mkl
   before_script:
     - mkdir -p ccache
     - export CCACHE_BASEDIR=${PWD}
     - export CCACHE_DIR=${PWD}/ccache
-
-# Base definition for using the classic Intel compiler
-.use-icc-oneapi:base:
-  variables:
-    CMAKE_COMPILER_SCRIPT: -DCMAKE_C_COMPILER=icc -DCMAKE_CXX_COMPILER=icpc #-DCMAKE_PREFIX_PATH=/opt/intel/oneapi/compiler/latest/linux
-    CMAKE_EXTRA_OPTIONS: -DGMX_FFT_LIBRARY=mkl
-  before_script:
-    # Necessary to override gitlab default 'set -e' which breaks Intel's
-    # setvar.sh script
-    - set +e
-    - source /opt/intel/oneapi/setvars.sh
-    - set -e
-    - mkdir -p ccache
-#    - export CCACHE_BASEDIR=${PWD}
-#    - export CCACHE_DIR=${PWD}/ccache
index f7572028771b96809a71264e1a69a1dcb0ba7a47..55b0e1cd17dfc83e5b7da110979b097bf50b1bff 100644 (file)
@@ -3,6 +3,7 @@
 #   OS: Ubuntu oldest supported
 #   Compiler: Clang
 #   Build type: Debug
+#   CMake: oldest supported
 #   GPU: no
 #   SIMD: no
 #   Scope: configure, build, unit tests
@@ -20,9 +21,9 @@ simple-build:
     - .use-clang:base
     - .rules:basic-push
   stage: pre-build
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     KUBERNETES_CPU_LIMIT: 8
     KUBERNETES_CPU_REQUEST: 4
     KUBERNETES_MEMORY_REQUEST: 8Gi
index e073c5f02b88b0644f5951cd98238a0dabe6954f..f67cfc5a6e0cfddadf91429f16433a1dbd326512 100644 (file)
@@ -260,16 +260,18 @@ include:
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.clang-8.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.clang-9-mpi.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.clang-9-release.gitlab-ci.yml'
+  - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.clang-11-cuda-11.2.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.clang-ASAN.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.clang-static-analyzer.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.clang-TSAN.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.clang-UBSAN.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.gcc-10.gitlab-ci.yml'
+  - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.gcc-10-coverage.gitlab-ci.yml'  
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.gcc-7-cuda-10.2.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.gcc-8-cuda-11.0.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.gcc-8-cuda-11.0-release.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.gcc-9-release.gitlab-ci.yml'
-  - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.icc-2021.1.gitlab-ci.yml'
+  - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.hipsycl-dev.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.oneapi-2021.1.1-opencl.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.oneapi-2021.1.1-opencl-release.gitlab-ci.yml'
   - local: '/admin/gitlab-ci/gromacs.matrix/gromacs.oneapi-2021.1.1-sycl.gitlab-ci.yml'
diff --git a/admin/gitlab-ci/gromacs.matrix/gromacs.clang-11-cuda-11.2.gitlab-ci.yml b/admin/gitlab-ci/gromacs.matrix/gromacs.clang-11-cuda-11.2.gitlab-ci.yml
new file mode 100644 (file)
index 0000000..e8a6dc0
--- /dev/null
@@ -0,0 +1,75 @@
+# Test goal: Clang-CUDA build
+# Test intents (should change rarely and conservatively):
+#   OS: Ubuntu newest supported
+#   GPU: Clang CUDA
+#   HW: NVIDIA GPU
+#   Scope: configure, build, unit tests, regression tests
+# Test implementation choices (free to change as needed):
+#   OS: Ubuntu 20.04
+#   Build type: RelWithDebInfo
+#   Compiler: Clang 11
+#   MPI: thread_MPI
+#   GPU: Clang CUDA 11.2, CUDA 11.2
+#   SIMD: AVX2_256, no kernels
+#   FFT: FFTW3
+#   Parallelism nt/ntomp: 4/2 (unit tests)
+#   Parallelism nt/ntomp: 2/1 (regression tests)
+
+gromacs:clang-11-cuda-11.2:configure:
+  extends:
+    - .gromacs:base:configure
+    - .use-clang:base
+    - .use-cuda
+    - .rules:post-merge-acceptance
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-llvm-11-cuda-11.2.1-hipsycl-2bc21b677a
+  variables:
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
+    CMAKE_SIMD_OPTIONS: "-DGMX_USE_SIMD_KERNELS=off"
+    CMAKE_EXTRA_OPTIONS: "-DGMX_CLANG_CUDA=ON"
+    CMAKE_BUILD_TYPE_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
+    COMPILER_MAJOR_VERSION: 11
+
+gromacs:clang-11-cuda-11.2:build:
+  extends:
+    - .variables:default
+    - .gromacs:base:build
+    - .use-clang:base
+    - .use-ccache
+    - .rules:post-merge-acceptance
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-llvm-11-cuda-11.2.1-hipsycl-2bc21b677a
+  variables:
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
+  needs:
+    - job: gromacs:clang-11-cuda-11.2:configure
+
+gromacs:clang-11-cuda-11.2:test:
+  extends:
+    - .gromacs:base:test
+    - .rules:post-merge-acceptance
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-llvm-11-cuda-11.2.1-hipsycl-2bc21b677a
+  variables:
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
+    KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
+    KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
+  tags:
+    - k8s-scilifelab
+  needs:
+    - job: gromacs:clang-11-cuda-11.2:build
+
+gromacs:clang-11-cuda-11.2:regressiontest:
+  extends:
+    - .gromacs:base:regressiontest
+    - .rules:post-merge-acceptance
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-llvm-11-cuda-11.2.1-hipsycl-2bc21b677a
+  variables:
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
+    KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
+    KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
+    REGRESSIONTEST_PME_RANK_NUMBER: 0
+    REGRESSIONTEST_TOTAL_RANK_NUMBER: 2
+    REGRESSIONTEST_OMP_RANK_NUMBER: 1
+  tags:
+    - k8s-scilifelab
+  needs:
+    - job: gromacs:clang-11-cuda-11.2:build
+    - job: regressiontests:prepare
\ No newline at end of file
index 3b93ad701227b8bbc7f2a85b8562a94fe1700e75..5c1f0443ed2055cccaef647a160834f2177af67b 100644 (file)
@@ -21,9 +21,9 @@ gromacs:clang-8-cuda-10.0:configure:
     - .use-clang:base
     - .use-cuda
     - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
     CMAKE_SIMD_OPTIONS: "-DGMX_USE_SIMD_KERNELS=off"
     CMAKE_EXTRA_OPTIONS: "-DGMX_CLANG_CUDA=ON"
     CMAKE_BUILD_TYPE_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
@@ -36,9 +36,9 @@ gromacs:clang-8-cuda-10.0:build:
     - .use-clang:base
     - .use-ccache
     - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
   needs:
     - job: gromacs:clang-8-cuda-10.0:configure
 
@@ -46,9 +46,9 @@ gromacs:clang-8-cuda-10.0:test:
   extends:
     - .gromacs:base:test
     - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
     KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
   tags:
@@ -60,9 +60,9 @@ gromacs:clang-8-cuda-10.0:regressiontest:
   extends:
     - .gromacs:base:regressiontest
     - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
     KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
     REGRESSIONTEST_PME_RANK_NUMBER: 0
index cf86e4c04f24b080cb921c58045b34aa8f860b19..e6ea8183bf77c66db0394ad8dfd880fc56ff05cd 100644 (file)
@@ -21,7 +21,7 @@ gromacs:clang-8-cuda-10.1:release:configure:
     - .use-clang:base
     - .use-cuda
     - .rules:nightly-only-for-release
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.1
   variables:
     COMPILER_MAJOR_VERSION: 8
     RELEASE_BUILD_DIR: release-builds-clang
@@ -37,7 +37,7 @@ gromacs:clang-8-cuda-10.1:release:build:
   stage: release-build
   variables:
     BUILD_DIR: release-builds-clang
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.1
   needs:
     - job: gromacs:clang-8-cuda-10.1:release:configure
 
@@ -46,7 +46,7 @@ gromacs:clang-8-cuda-10.1:release:test:
     - .gromacs:base:test
     - .rules:nightly-only-for-release
   stage: release-tests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.1
   variables:
     KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
@@ -62,7 +62,7 @@ gromacs:clang-8-cuda-10.1:release:regressiontest:
     - .gromacs:base:regressiontest
     - .rules:nightly-only-for-release
   stage: release-tests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.1
   variables:
     BUILD_DIR: release-builds-clang
     KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
index 47def43229e22d6be825cd90c71e29f1753e449f..5a590b9701173f1d28cade5202fdd23079d86956 100644 (file)
@@ -18,7 +18,7 @@ gromacs:clang-8:configure:
     - .gromacs:base:configure
     - .use-clang:base
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0
   variables:
     COMPILER_MAJOR_VERSION: 8
 
@@ -29,7 +29,7 @@ gromacs:clang-8:build:
     - .before_script:default
     - .use-ccache
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0
   needs:
     - job: gromacs:clang-8:configure
 
@@ -37,7 +37,7 @@ gromacs:clang-8:test:
   extends:
     - .gromacs:base:test
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0
   needs:
     - job: gromacs:clang-8:build
 
@@ -45,7 +45,7 @@ gromacs:clang-8:regressiontest:
   extends:
     - .gromacs:base:regressiontest
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-cuda-10.0
   tags:
     - k8s-scilifelab
   needs:
index d7c2682283a5e200a90162fea2c66f42e0f0d607..803828a7b1e4fbb7437aec18a2483a3bccf49aa7 100644 (file)
@@ -14,6 +14,7 @@
 #   SIMD: AVX2_256
 #   FFT: FFTW3
 #   Parallelism np/ntomp: 4/2
+#   Subcyclecounting: Active
 
 gromacs:clang-9-mpi:configure:
   extends:
@@ -21,11 +22,12 @@ gromacs:clang-9-mpi:configure:
    - .use-clang:base
    - .use-mpi
    - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
     COMPILER_MAJOR_VERSION: 9
     CMAKE_PRECISION_OPTIONS: -DGMX_DOUBLE=ON
+    CMAKE_EXTRA_OPTIONS: -DGMX_CYCLE_SUBCOUNTERS=ON
 
 gromacs:clang-9-mpi:build:
   # Test using configuration: gromacs:clang-9-mpi:configure
@@ -36,9 +38,9 @@ gromacs:clang-9-mpi:build:
     - .before_script:default
     - .use-ccache
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
   needs:
     - job: gromacs:clang-9-mpi:configure
 
@@ -46,9 +48,9 @@ gromacs:clang-9-mpi:test:
   extends:
     - .gromacs:base:test
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
   tags:
     - k8s-scilifelab
   needs:
@@ -58,9 +60,9 @@ gromacs:clang-9:regressiontest:
   extends:
     - .gromacs:base:regressiontest
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
     REGRESSIONTEST_DOUBLE: "-double"
     REGRESSIONTEST_PARALLEL: "-np"
   tags:
index 943ad08d40831b366a36198470528ed39e7142c0..f2d59a277b41118847fab943ad6ae6e5b9bdf636 100644 (file)
@@ -21,9 +21,9 @@ gromacs:clang-9:release:configure:
     - .use-clang:base
     - .use-mpi
     - .rules:nightly-only-for-release
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     COMPILER_MAJOR_VERSION: 9
     RELEASE_BUILD_DIR: release-builds-clang
     CMAKE_PRECISION_OPTIONS: "-DGMX_DOUBLE=ON"
@@ -42,9 +42,9 @@ gromacs:clang-9:release:build:
     - .rules:nightly-only-for-release
   stage: release-build
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     BUILD_DIR: release-builds-clang
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9
   needs:
     - job: gromacs:clang-9:release:configure
 
@@ -53,9 +53,9 @@ gromacs:clang-9:release:test:
     - .gromacs:base:test
     - .rules:nightly-only-for-release
   stage: release-tests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     BUILD_DIR: release-builds-clang
   needs:
     - job: gromacs:clang-9:release:configure
@@ -66,9 +66,9 @@ gromacs:clang-9:release:regressiontest:
     - .gromacs:base:regressiontest
     - .rules:nightly-only-for-release
   stage: release-tests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     BUILD_DIR: release-builds-clang
     REGRESSIONTEST_DOUBLE: "-double"
     REGRESSIONTEST_PARALLEL: "-np"
index b9a3c7f21b09398c37a2a48a1abe6e865f0ba42a..78d0dcec3c1dc34f9cdd0152851436315867ac98 100644 (file)
@@ -7,7 +7,7 @@
 #   Scope: configure, build, unit tests, regression tests
 # Test implementation choices (free to change as needed):
 #   OS: Ubuntu 18.04
-#   Compiler: Clang 8
+#   Compiler: Clang 11
 #   MPI: thread_MPI
 #   SIMD: AVX2_256
 #   FFT: FFTW3
@@ -18,10 +18,10 @@ gromacs:clang-ASAN:configure:
     - .gromacs:base:configure
     - .use-clang:base
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-tsan:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
-    COMPILER_MAJOR_VERSION: 8
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
+    COMPILER_MAJOR_VERSION: 11
     CMAKE_BUILD_TYPE_OPTIONS: "-DCMAKE_BUILD_TYPE=ASAN"
 
 gromacs:clang-ASAN:build:
@@ -31,9 +31,9 @@ gromacs:clang-ASAN:build:
     - .use-clang:base
     - .use-ccache
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-tsan:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
   tags:
     - k8s-scilifelab
   needs:
@@ -44,9 +44,9 @@ gromacs:clang-ASAN:test:
     - .gromacs:base:test
     - .use-clang:base
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-tsan:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
     CTEST_RUN_MODE: "ExperimentalMemCheck"
   tags:
     - k8s-scilifelab
@@ -58,9 +58,9 @@ gromacs:clang-ASAN:regressiontest:
     - .gromacs:base:regressiontest
     - .use-clang:base
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-tsan:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
   tags:
     - k8s-scilifelab
   needs:
index 53073f81717fa614b0596602ca8f5c7fff5bbcd5..0ea46d802feba4ce6ed5cc454d0cfb4f87d36828 100644 (file)
@@ -7,7 +7,7 @@
 #   Scope: configure, build, unit tests, regression tests
 # Test implementation choices (free to change as needed):
 #   OS: Ubuntu 18.04
-#   Compiler: Clang 8
+#   Compiler: Clang 11
 #   MPI: thread_MPI
 #   SIMD: AVX2_256
 #   FFT: FFTW3
@@ -18,10 +18,10 @@ gromacs:clang-TSAN:configure:
     - .gromacs:base:configure
     - .use-clang:base
     - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-tsan:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
-    COMPILER_MAJOR_VERSION: 8
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
+    COMPILER_MAJOR_VERSION: 11
     CMAKE_BUILD_TYPE_OPTIONS: "-DCMAKE_BUILD_TYPE=TSAN"
 
 gromacs:clang-TSAN:build:
@@ -31,9 +31,9 @@ gromacs:clang-TSAN:build:
     - .use-clang:base
     - .use-ccache
     - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-tsan:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
   needs:
     - job: gromacs:clang-TSAN:configure
 
@@ -41,9 +41,9 @@ gromacs:clang-TSAN:test:
   extends:
     - .gromacs:base:test
     - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-tsan:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
   needs:
     - job: gromacs:clang-TSAN:build
 
@@ -51,9 +51,9 @@ gromacs:clang-TSAN:regressiontest:
   extends:
     - .gromacs:base:regressiontest
     - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-tsan:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
   tags:
     - k8s-scilifelab
   needs:
index e0588ca2b756ef5550253ef386e89485b8bdd777..75bbd7a00da50a01a5f7849844665e636ef32219 100644 (file)
@@ -7,7 +7,7 @@
 #   Scope: configure, build, unit tests
 # Test implementation choices (free to change as needed):
 #   OS: Ubuntu 18.04
-#   Compiler: Clang 8
+#   Compiler: Clang 11
 #   MPI: thread_MPI
 #   SIMD: AVX2_256
 #   FFT: FFTW3
@@ -18,10 +18,10 @@ gromacs:clang-UBSAN:configure:
     - .gromacs:base:configure
     - .use-clang:base
     - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-tsan:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
-    COMPILER_MAJOR_VERSION: 8
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
+    COMPILER_MAJOR_VERSION: 11
     CMAKE_BUILD_TYPE_OPTIONS: "-DCMAKE_BUILD_TYPE=UBSAN"
 
 gromacs:clang-UBSAN:build:
@@ -31,9 +31,9 @@ gromacs:clang-UBSAN:build:
     - .use-clang:base
     - .use-ccache
     - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-tsan:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
   tags:
     - k8s-scilifelab
   needs:
@@ -44,9 +44,9 @@ gromacs:clang-UBSAN:test:
     - .gromacs:base:test
     - .use-clang:base
     - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-tsan:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
   tags:
     - k8s-scilifelab
   needs:
index 7168a6a34840ac8101f9c33478f805a9edea757e..61ea460f0fb0a0182a5141d24481c9a40404fa28 100644 (file)
@@ -17,9 +17,9 @@ gromacs:clang-static-analyzer:configure:
     - .gromacs:base:configure
     - .use-clang:base
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-tsan:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     CMAKE_COMPILER_SCRIPT: "-DCMAKE_CXX_COMPILER=/usr/local/libexec/c++-analyzer -DCMAKE_C_COMPILER=gcc"
     CMAKE_EXTRA_OPTIONS: "-DGMX_CLANG_ANALYZER=ON -DGMX_OPENMP=OFF -DGMX_USE_RDTSCP=OFF -DGMX_FFT_LIBRARY=fftpack -DGMX_DEVELOPER_BUILD=ON"
     CMAKE_SIMD_OPTIONS: "-DGMX_SIMD=None"
@@ -31,9 +31,9 @@ gromacs:clang-static-analyzer:build:
     - .use-clang:base
     - .use-ccache
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-8-tsan:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
   tags:
     - k8s-scilifelab
   needs:
diff --git a/admin/gitlab-ci/gromacs.matrix/gromacs.gcc-10-coverage.gitlab-ci.yml b/admin/gitlab-ci/gromacs.matrix/gromacs.gcc-10-coverage.gitlab-ci.yml
new file mode 100644 (file)
index 0000000..b8e2190
--- /dev/null
@@ -0,0 +1,90 @@
+# Test goal: code coverage with newest GCC
+# Test intents (should change rarely and conservatively):
+#   OS: Ubuntu newest supported
+#   Compiler: GCC newest supported
+#   GPU: no
+#   Scope: configure, build, unit tests, coverage
+# Test implementation choices (free to change as needed):
+#   OS: Ubuntu 20.04
+#   Build type: Debug
+#   Compiler: GCC 10
+#   MPI: thread_MPI
+#   SIMD: AVX2_256
+#   Parallelism nt/ntomp: 4/2 (unit tests)
+
+gromacs:gcc-10:coverage:configure:
+  extends:
+    - .gromacs:base:configure
+    - .use-gcc:base
+    - .rules:post-merge-acceptance
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10
+  variables:
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
+    CMAKE_SIMD_OPTIONS: "-DGMX_SIMD=AVX2_256"
+    CMAKE_EXTRA_OPTIONS: "-DGMX_BUILD_FOR_COVERAGE=ON"
+    COMPILER_MAJOR_VERSION: 10
+
+gromacs:gcc-10:coverage:build:
+  extends:
+    - .variables:default
+    - .gromacs:base:build
+    - .before_script:default
+    - .use-ccache
+    - .rules:post-merge-acceptance
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10
+  variables:
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
+  needs:
+    - job: gromacs:gcc-10:coverage:configure
+
+gromacs:gcc-10:coverage:test:
+  extends:
+    - .gromacs:base:test
+    - .rules:post-merge-acceptance
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10
+  variables:
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
+  tags:
+    - k8s-scilifelab
+  needs:
+    - job: gromacs:gcc-10:coverage:build
+  artifacts:
+    paths:
+      - $BUILD_DIR
+
+gromacs:coverage:analyse:
+  variables:
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
+    VENVPATH: "/root/venv/py3.7"
+    GCOVR_GENERAL_OPTIONS: "-r ../ /. --gcov-executable=gcov-10 --exclude-unreachable-branches --exclude-throw-branches -j$KUBERNETES_CPU_LIMIT"
+    GCOVR_EXCLUDE_OPTIONS: "--exclude-directories '^src/external/.*' --exclude-directories '^src/gromacs/selection/.*' --exclude-directories '.*tests.*" 
+  extends:
+    - .variables:default
+    - .rules:post-merge-acceptance
+  stage: post-test
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10
+  needs:
+    - job: gromacs:gcc-10:coverage:build
+    - job: gromacs:gcc-10:coverage:test
+
+  tags:
+    - k8s-scilifelab
+  script:
+    - echo ${GCOVR_GENERAL_OPTIONS}
+    - echo ${GCOVR_EXCLUDE_OPTIONS}
+    - source $VENVPATH/bin/activate
+    - mkdir public
+    - outputdir=`pwd`/public
+    - cd $BUILD_DIR
+    # run gcovr to write to stdout for GitLab pipeline grep.
+    - gcovr ${GCOVR_GENERAL_OPTIONS} ${GCOVR_EXCLUDE_OPTIONS}
+    # run gcovr to generate xml output. keep the generated files to produce the html output later.
+    # the invocations need to be separate due to a crash in gcovr where files can not be found.
+    - gcovr ${GCOVR_GENERAL_OPTIONS} ${GCOVR_EXCLUDE_OPTIONS} --xml $outputdir/cobertura-coverage.xml --xml-pretty --keep
+    # final gcovr run, using the generated files to produce nice looking html output
+    - gcovr ${GCOVR_GENERAL_OPTIONS} ${GCOVR_EXCLUDE_OPTIONS} --html $outputdir/coverage.html --use-gcov-files
+  artifacts:
+    paths:
+      - public/
+    reports:
+      cobertura: public/cobertura-coverage.xml
index 725b57a2dfde662a0f125b4ef5f621ea3dd52dbd..64cb95d1b51865f6dc6cdc53f93c9512744b1c73 100644 (file)
@@ -21,9 +21,9 @@ gromacs:gcc-10:configure:
     - .use-gcc:base
     - .use-opencl
     - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     CMAKE_SIMD_OPTIONS: "-DGMX_SIMD=AVX2_256"
     CMAKE_EXTRA_OPTIONS: "-DGMX_EXTERNAL_CLFFT=ON"
     COMPILER_MAJOR_VERSION: 10
@@ -35,9 +35,9 @@ gromacs:gcc-10:build:
     - .before_script:default
     - .use-ccache
     - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
   needs:
     - job: gromacs:gcc-10:configure
 
@@ -45,9 +45,9 @@ gromacs:gcc-10:test:
   extends:
     - .gromacs:base:test
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     KUBERNETES_EXTENDED_RESOURCE_NAME: "amd.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
     LD_LIBRARY_PATH: "/opt/rocm-3.5.0/opencl/lib"
@@ -60,9 +60,9 @@ gromacs:gcc-10:regressiontest:
   extends:
     - .gromacs:base:regressiontest
     - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     KUBERNETES_EXTENDED_RESOURCE_NAME: "amd.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
     REGRESSIONTEST_PME_RANK_NUMBER: 0
index b898aacb79dda18692d848e201db47b80a2b9fb6..e3e5817d02be394e0b59b35566c3baae597542cf 100644 (file)
@@ -26,9 +26,9 @@ gromacs:gcc-7-cuda-10.2:configure:
     - .use-gcc:base
     - .use-cuda
     - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
     CMAKE_SIMD_OPTIONS: "-DGMX_SIMD=SSE4.1"
     COMPILER_MAJOR_VERSION: 7
 
@@ -39,9 +39,9 @@ gromacs:gcc-7-cuda-10.2:build:
     - .before_script:default
     - .use-ccache
     - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
   needs:
     - job: gromacs:gcc-7-cuda-10.2:configure
 
@@ -49,9 +49,9 @@ gromacs:gcc-7-cuda-10.2:test:
   extends:
     - .gromacs:base:test
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
     KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
   tags:
@@ -63,9 +63,9 @@ gromacs:gcc-7-cuda-10.2:test-gpucommupd:
   extends:
     - .gromacs:base:test
     - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
     KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
     GMX_GPU_DD_COMMS: 1
@@ -80,9 +80,9 @@ gromacs:gcc-7-cuda-10.2:regressiontest:
   extends:
     - .gromacs:base:regressiontest
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
     KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
     REGRESSIONTEST_PME_RANK_NUMBER: 0
@@ -98,9 +98,9 @@ gromacs:gcc-7-cuda-10.2:regressiontest-gpucommupd-tMPI:
   extends:
     - .gromacs:base:regressiontest
     - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
     KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 2
     REGRESSIONTEST_PME_RANK_NUMBER: 0
@@ -124,7 +124,7 @@ gromacs:gcc-7-cuda-10.2:regressiontest-upd-tMPI:
   extends:
     - .gromacs:base:regressiontest
     - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-cuda-10.2
   variables:
     KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 2
index 9b91166100b6b6e460f79b21c5e99162c61eb6f7..ca45745dc433fdc2eb016ba4506a687ddaf78fd5 100644 (file)
@@ -1,9 +1,9 @@
-# Test goal: GCC with newest CUDA; Mdrun-only build
+# Test goal: GCC with newest CUDA
 # Test intents (should change rarely and conservatively):
 #   OS: Ubuntu oldest supported
 #   GPU: CUDA newest supported
 #   HW: NVIDIA GPU
-#   Features: Mdrun-only build
+#   CMake: oldest supported
 #   Scope: configure, build, unit tests
 # Test implementation choices (free to change as needed):
 #   OS: Ubuntu 18.04
@@ -22,12 +22,11 @@ gromacs:gcc-8-cuda-11.0:release:configure:
     - .use-mpi
     - .use-cuda
     - .rules:nightly-only-for-release
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     COMPILER_MAJOR_VERSION: 8
     RELEASE_BUILD_DIR: release-builds-gcc
-    CMAKE_EXTRA_OPTIONS: "-DGMX_BUILD_MDRUN_ONLY=ON"
     CMAKE_BUILD_TYPE_OPTIONS : "-DCMAKE_BUILD_TYPE=RelWithAssert"
     CMAKE_REGRESSIONTEST_OPTIONS: ""
   dependencies:
@@ -44,9 +43,9 @@ gromacs:gcc-8-cuda-11.0:release:build:
     - .rules:nightly-only-for-release
   stage: release-build
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     BUILD_DIR: release-builds-gcc
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0
   needs:
     - job: gromacs:gcc-8-cuda-11.0:release:configure
 
@@ -55,9 +54,9 @@ gromacs:gcc-8-cuda-11.0:release:test:
     - .gromacs:base:test
     - .rules:nightly-only-for-release
   stage: release-tests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
     BUILD_DIR: release-builds-gcc
index 5daeb613794ace627fdc92a8e121cc8e6c68e218..37704f40404df23fe8c93503484b3b59e82c188e 100644 (file)
@@ -22,9 +22,9 @@ gromacs:gcc-8-cuda-11.0:configureMPI:
     - .use-cuda
     - .use-mpi
     - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
     CMAKE_SIMD_OPTIONS: "-DGMX_SIMD=SSE4.1"
     COMPILER_MAJOR_VERSION: 8
 
@@ -35,9 +35,9 @@ gromacs:gcc-8-cuda-11.0:buildMPI:
     - .before_script:default
     - .use-ccache
     - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
   needs:
     - job: gromacs:gcc-8-cuda-11.0:configureMPI
 
@@ -47,9 +47,9 @@ gromacs:gcc-8-cuda-11.0:regressiontest-gpucommupd-MPI:
   extends:
     - .gromacs:base:regressiontest
     - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-8-cuda-11.0
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
     KUBERNETES_EXTENDED_RESOURCE_NAME: "nvidia.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 2
     REGRESSIONTEST_PME_RANK_NUMBER: 0
index 7ee3fe6d41b1e903c6640cbd458794d8a439d938..4de9ff7a5c482689ea55e60a8fed31c181aff23e 100644 (file)
@@ -12,7 +12,8 @@
 #   MPI: thread_MPI
 #   SIMD: AVX2_256
 #   FFT: FFTW3
-#   Parallelism nt/ntomp: 4/2
+#   Parallelism nt/ntomp: 4/2 (unit tests)
+#   Parallelism nt/ntomp: 2/1 (regression tests)
 
 gromacs:gcc-9:release:configure:
   extends:
@@ -20,9 +21,9 @@ gromacs:gcc-9:release:configure:
     - .use-gcc:base
     - .use-opencl
     - .rules:nightly-only-for-release
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-9
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     COMPILER_MAJOR_VERSION: 9
     RELEASE_BUILD_DIR: release-builds-gcc
     CMAKE_BUILD_TYPE_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithAssert"
@@ -42,9 +43,9 @@ gromacs:gcc-9:release:build:
     - .rules:nightly-only-for-release
   stage: release-build
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     BUILD_DIR: release-builds-gcc
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-9
   needs:
     - job: gromacs:gcc-9:release:configure
 
@@ -53,9 +54,9 @@ gromacs:gcc-9:release:test:
     - .gromacs:base:test
     - .rules:nightly-only-for-release
   stage: release-tests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-9
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     BUILD_DIR: release-builds-gcc
     KUBERNETES_EXTENDED_RESOURCE_NAME: "amd.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
@@ -71,12 +72,15 @@ gromacs:gcc-9:release:regressiontest:
     - .gromacs:base:regressiontest
     - .rules:nightly-only-for-release
   stage: release-tests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-9
   variables:
-    CMAKE: /usr/local/cmake-3.13.0/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     BUILD_DIR: release-builds-gcc
     KUBERNETES_EXTENDED_RESOURCE_NAME: "amd.com/gpu"
     KUBERNETES_EXTENDED_RESOURCE_LIMIT: 1
+    REGRESSIONTEST_PME_RANK_NUMBER: 0
+    REGRESSIONTEST_TOTAL_RANK_NUMBER: 2
+    REGRESSIONTEST_OMP_RANK_NUMBER: 1
     LD_LIBRARY_PATH: "/opt/rocm-3.5.0/opencl/lib"
   tags:
     - k8s-scilifelab
diff --git a/admin/gitlab-ci/gromacs.matrix/gromacs.hipsycl-dev.gitlab-ci.yml b/admin/gitlab-ci/gromacs.matrix/gromacs.hipsycl-dev.gitlab-ci.yml
new file mode 100644 (file)
index 0000000..ba7c33c
--- /dev/null
@@ -0,0 +1,44 @@
+# Test goal: build with hipSYCL (both CUDA and ROCm backends) to check SYCL code compatibility
+# Test intents (should change rarely and conservatively):
+#   OS: Ubuntu newest supported
+#   Compiler: Clang newest supported
+#   GPU: hipSYCL
+#   Scope: configure, build
+# Test implementation choices (free to change as needed):
+#   OS: Ubuntu 20.04
+#   Build type: RelWithAssert
+#   Compiler: Clang 11
+#   MPI: thread_MPI
+#   SIMD: AVX2_256
+
+gromacs:hipsycl-dev:configure:
+  extends:
+    - .gromacs:base:configure
+    - .use-clang:base
+    - .use-sycl
+    - .rules:merge-and-post-merge-acceptance
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-llvm-11-cuda-11.2.1-hipsycl-2bc21b677a
+  variables:
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
+    CMAKE_SIMD_OPTIONS: "-DGMX_SIMD=AVX2_256"
+    CMAKE_BUILD_TYPE_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithAssert"
+    CMAKE_GPU_OPTIONS: "-DGMX_GPU=SYCL -DGMX_SYCL_HIPSYCL=ON -DHIPSYCL_TARGETS='cuda:sm_60,sm_61,sm_70,sm_75;hip:gfx900'"
+    # Unset COMPILER_LAUNCHER (previously set to ccache) because it conflicts with hipSYCL's syclcc-launcher
+    CMAKE_EXTRA_OPTIONS: "-DCMAKE_C_COMPILER_LAUNCHER= -DCMAKE_CXX_COMPILER_LAUNCHER="
+    COMPILER_MAJOR_VERSION: 11
+
+gromacs:hipsycl-dev:build:
+  extends:
+    - .variables:default
+    - .gromacs:base:build
+    - .before_script:default
+    # Not using ccache because it plays poorly with syclcc-launcher
+    - .rules:merge-and-post-merge-acceptance
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-llvm-11-cuda-11.2.1-hipsycl-2bc21b677a
+  variables:
+    CMAKE: /usr/local/cmake-3.18.4/bin/cmake
+  tags:
+    - k8s-scilifelab
+  needs:
+    - job: gromacs:hipsycl-dev:configure
+
diff --git a/admin/gitlab-ci/gromacs.matrix/gromacs.icc-2021.1.gitlab-ci.yml b/admin/gitlab-ci/gromacs.matrix/gromacs.icc-2021.1.gitlab-ci.yml
deleted file mode 100644 (file)
index fe3fd83..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-# Test goal: Newest ICC CPU-only build
-# Test intents (should change rarely and conservatively):
-#   OS: Ubuntu oldest supported
-#   Compiler: ICC newest supported
-#   FFT: MKL
-#   GPU: no
-#   Scope: configure, build, unit tests, regression tests
-# Test implementation choices (free to change as needed):
-#   OS: Ubuntu 18.04
-#   Build type: Debug
-#   Compiler: ICC 2021.1
-#   MPI: thread_MPI
-#   SIMD: AVX2_256
-#   Parallelism nt/ntomp: 4/2
-
-gromacs:icc-2021.1:configure:
-  # Test SIMD: AVX2_256
-  # Test FFT: MKL
-  # Test scope: configure
-  extends:
-   - .gromacs:base:configure
-   - .use-icc-oneapi:base
-   - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
-  variables:
-    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
-    COMPILER_MAJOR_VERSION: 2021
-
-gromacs:icc-2021.1:build:
-  extends:
-    - .variables:default
-    - .gromacs:base:build
-    - .use-icc-oneapi:base
-    - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
-  variables:
-    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
-  needs:
-    - job: gromacs:icc-2021.1:configure
-
-gromacs:icc-2021.1:test:
-  extends:
-    - .gromacs:base:test
-    - .use-icc-oneapi:base
-    - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
-  variables:
-    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
-  needs:
-    - job: gromacs:icc-2021.1:build
-
-gromacs:icc-2021.1:regressiontest:
-  extends:
-    - .gromacs:base:regressiontest
-    - .use-icc-oneapi:base
-    - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
-  variables:
-    CMAKE: /usr/local/cmake-3.17.2/bin/cmake
-  needs:
-    - job: gromacs:icc-2021.1:build
-    - job: regressiontests:prepare
-
index 13d5646a2c18af691f8a0ec648bd38199fdea88a..db672a5f23b9a872e001481f75aa15c97e171ca7 100644 (file)
@@ -20,7 +20,7 @@ gromacs:oneapi-2021.1.1-opencl:release:configure:
    - .use-oneapi:base
    - .use-opencl
    - .rules:nightly-only-for-release
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1
   variables:
     CMAKE: /usr/local/cmake-3.17.2/bin/cmake
     COMPILER_MAJOR_VERSION: 2021
@@ -39,7 +39,7 @@ gromacs:oneapi-2021.1.1-opencl:release:build:
     CMAKE: /usr/local/cmake-3.17.2/bin/cmake
     BUILD_DIR: release-builds-oneapi
     COMPILER_MAJOR_VERSION: 2021
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1
   needs:
     - job: gromacs:oneapi-2021.1.1-opencl:release:configure
 
@@ -49,7 +49,7 @@ gromacs:oneapi-2021.1.1-opencl:release:test:
     - .use-oneapi:base
     - .rules:nightly-only-for-release
   stage: release-tests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1
   variables:
     CMAKE: /usr/local/cmake-3.17.2/bin/cmake
     BUILD_DIR: release-builds-oneapi
@@ -63,7 +63,7 @@ gromacs:oneapi-2021.1.1-opencl:release:regressiontest:
     - .use-oneapi:base
     - .rules:nightly-only-for-release
   stage: release-tests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1
   variables:
     CMAKE: /usr/local/cmake-3.17.2/bin/cmake
     BUILD_DIR: release-builds-oneapi
index de2009819f942eae381b6f3a461701bd7d927899..4f304b83728be60feb55826852ea94238005f7f7 100644 (file)
@@ -19,7 +19,7 @@ gromacs:oneapi-2021.1.1-opencl:configure:
    - .use-oneapi:base
    - .use-opencl
    - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1
   variables:
     CMAKE: /usr/local/cmake-3.17.2/bin/cmake
     COMPILER_MAJOR_VERSION: 2021
@@ -31,7 +31,7 @@ gromacs:oneapi-2021.1.1-opencl:build:
     - .use-ccache
     - .use-oneapi:base
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1
   variables:
     CMAKE: /usr/local/cmake-3.17.2/bin/cmake
   needs:
@@ -42,7 +42,7 @@ gromacs:oneapi-2021.1.1-opencl:test:
     - .gromacs:base:test
     - .use-oneapi:base
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1
   variables:
     CMAKE: /usr/local/cmake-3.17.2/bin/cmake
   needs:
@@ -53,7 +53,7 @@ gromacs:oneapi-2021.1.1-opencl:regressiontest:
     - .gromacs:base:regressiontest
     - .use-oneapi:base
     - .rules:merge-requests
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1
   variables:
     CMAKE: /usr/local/cmake-3.17.2/bin/cmake
   needs:
index 9c923031e42642c7d16c4cbd8894768e681bcd92..5f01e0d579bab95f3e29e04ee0f0b21e78a7ee65 100644 (file)
@@ -19,7 +19,7 @@ gromacs:oneapi-2021.1.1-sycl:configure:
    - .use-oneapi:base
    - .use-sycl
    - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1
   variables:
     CMAKE: /usr/local/cmake-3.17.2/bin/cmake
     COMPILER_MAJOR_VERSION: 2021
@@ -31,7 +31,7 @@ gromacs:oneapi-2021.1.1-sycl:build:
     - .use-ccache
     - .use-oneapi:base
     - .rules:merge-and-post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1
   variables:
     CMAKE: /usr/local/cmake-3.17.2/bin/cmake
   needs:
@@ -42,7 +42,7 @@ gromacs:oneapi-2021.1.1-sycl:test:
     - .gromacs:base:test
     - .use-oneapi:base
     - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1
   variables:
     CMAKE: /usr/local/cmake-3.17.2/bin/cmake
   needs:
@@ -53,7 +53,7 @@ gromacs:oneapi-2021.1.1-sycl:regressiontest:
     - .gromacs:base:regressiontest
     - .use-oneapi:base
     - .rules:post-merge-acceptance
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-gcc-7-oneapi-2021.1.1
   variables:
     CMAKE: /usr/local/cmake-3.17.2/bin/cmake
   needs:
index 23eb084a17a8dc16e6daf3d3b4e27d9f149c7be7..51813fee1a848a58e0762a436e1caa6b7c005322 100644 (file)
@@ -5,10 +5,10 @@ clang-tidy:configure-push:
     - .gromacs:base:configure
     - .use-clang:base
     - .rules:basic-push
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
-    COMPILER_MAJOR_VERSION: 9
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
+    COMPILER_MAJOR_VERSION: 11
     BUILD_DIR: build-clang-tidy
     CMAKE_EXTRA_OPTIONS: -DCLANG_TIDY=clang-tidy-$COMPILER_MAJOR_VERSION -DGMX_CLANG_TIDY=ON -DGMX_COMPILER_WARNINGS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
 
@@ -17,10 +17,10 @@ clang-tidy:configure-schedule:
     - .gromacs:base:configure
     - .use-clang:base
     - .rules:nightly-not-for-release
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
-    COMPILER_MAJOR_VERSION: 9
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
+    COMPILER_MAJOR_VERSION: 11
     BUILD_DIR: build-clang-tidy
     CMAKE_EXTRA_OPTIONS: -DCLANG_TIDY=clang-tidy-$COMPILER_MAJOR_VERSION -DGMX_CLANG_TIDY=ON -DGMX_COMPILER_WARNINGS=ON
 
@@ -31,11 +31,11 @@ clang-tidy:build:
     - .variables:default
     - .rules:nightly-not-for-release
   stage: source-check
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   needs:
     - job: clang-tidy:configure-schedule
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
     BUILD_DIR: build-clang-tidy
 
 clang-tidy:test:
@@ -44,12 +44,12 @@ clang-tidy:test:
     - .variables:default
     - .rules:basic-push
   stage: source-check
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-9:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   needs:
     - job: clang-tidy:configure-push
   variables:
-    CMAKE: /usr/local/cmake-3.15.7/bin/cmake
-    COMPILER_MAJOR_VERSION: 9
+    CMAKE: /usr/local/cmake-3.16.3/bin/cmake
+    COMPILER_MAJOR_VERSION: 11
     BUILD_DIR: build-clang-tidy
     EXTRA_INSTALLS: clang-tidy-$COMPILER_MAJOR_VERSION
     KUBERNETES_CPU_LIMIT: 4
@@ -59,7 +59,7 @@ clang-tidy:test:
     # Make sure that a Python interpreter can be found for `/bin/env python`
     - test -x /usr/bin/python || update-alternatives --install /usr/bin/python python /usr/bin/python3 1
     # TODO (issue #3272) `master` is not appropriate for use on release-xxxx branches, how should we handle that?
-    - REV=$(git fetch -q https://gitlab.com/gromacs/gromacs.git release-2021 && git show -s --pretty=format:"%h" `git merge-base FETCH_HEAD HEAD`)
+    - REV=$(git fetch -q https://gitlab.com/gromacs/gromacs.git master && git show -s --pretty=format:"%h" `git merge-base FETCH_HEAD HEAD`)
     - HEAD_REV=$(git show -s --pretty=format:"%h" HEAD)
     - if [[ "$REV" == "$HEAD_REV" ]] ; then
         REV="HEAD~1" ;
@@ -81,15 +81,16 @@ clang-format:
     - .rules:basic-push
   cache: {}
   stage: pre-build
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
-    COMPILER_MAJOR_VERSION: 7
+    COMPILER_MAJOR_VERSION: 11
     KUBERNETES_CPU_LIMIT: 1
     KUBERNETES_CPU_REQUEST: 1
     KUBERNETES_MEMORY_REQUEST: 2Gi
     EXTRA_INSTALLS: clang-format-$COMPILER_MAJOR_VERSION
   script:
-    - REV=$(git fetch -q https://gitlab.com/gromacs/gromacs.git release-2021 && git show -s --pretty=format:"%h" `git merge-base FETCH_HEAD HEAD`)
+    # TODO (issue #3272) `master` is not appropriate for use on release-xxxx branches, how should we handle that?
+    - REV=$(git fetch -q https://gitlab.com/gromacs/gromacs.git master && git show -s --pretty=format:"%h" `git merge-base FETCH_HEAD HEAD`)
     - HEAD_REV=$(git show -s --pretty=format:"%h" HEAD)
     - if [[ "$REV" == "$HEAD_REV" ]] ; then
         REV="HEAD~1" ;
@@ -111,13 +112,13 @@ copyright-check:
     - .rules:basic-push
   cache: {}
   stage: pre-build
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-7-docs:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-18.04-llvm-11-tsan
   variables:
     KUBERNETES_CPU_LIMIT: 1
     KUBERNETES_CPU_REQUEST: 1
     KUBERNETES_MEMORY_REQUEST: 2Gi
   script:
-    - REV=$(git fetch -q https://gitlab.com/gromacs/gromacs.git release-2021 && git show -s --pretty=format:"%h" `git merge-base FETCH_HEAD HEAD`)
+    - REV=$(git fetch -q https://gitlab.com/gromacs/gromacs.git master && git show -s --pretty=format:"%h" `git merge-base FETCH_HEAD HEAD`)
     - HEAD_REV=$(git show -s --pretty=format:"%h" HEAD)
     - if [[ "$REV" == "$HEAD_REV" ]] ; then
         REV="HEAD~1" ;
similarity index 97%
rename from admin/gitlab-ci/python-gmxapi.gitlab-ci.yml
rename to admin/gitlab-ci/python-gmxapi01.gitlab-ci.yml
index f4082386414897f0f096ced41126d429fd8a5de9..32de191be57460f81a52de89e0a5c1a710c76f04 100644 (file)
@@ -8,7 +8,7 @@
     - .variables:default
     - .use-clang:base
   stage: test
-  image: ${CI_REGISTRY}/gromacs/gromacs/cmake-3.15.7-llvm-8-intelopencl-openmpi:2020:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/cmake-3.15.7-llvm-8-intelopencl-openmpi:2020
   variables:
     KUBERNETES_CPU_LIMIT: 2
     KUBERNETES_CPU_REQUEST: 2
@@ -78,7 +78,7 @@ gmxapi-0.1:clang-8:py-3.8.2:
   extends:
     - .variables:default
     - .use-clang:base
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10
   stage: test
   variables:
     KUBERNETES_CPU_LIMIT: 2
diff --git a/admin/gitlab-ci/python-gmxapi02.gitlab-ci.yml b/admin/gitlab-ci/python-gmxapi02.gitlab-ci.yml
new file mode 100644 (file)
index 0000000..fc267ec
--- /dev/null
@@ -0,0 +1,61 @@
+#
+# Jobs to test gmxapi client (Python) packages
+#
+
+.gmxapi-0.2:gcc-10:gmx2021:
+  extends:
+    - .variables:default
+    - .use-clang:base
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10
+  stage: test
+  variables:
+    KUBERNETES_CPU_LIMIT: 2
+    KUBERNETES_CPU_REQUEST: 2
+    KUBERNETES_MEMORY_LIMIT: 2Gi
+    KUBERNETES_MEMORY_REQUEST: 2Gi
+    PY_UNIT_TEST_XML: $CI_PROJECT_DIR/py-JUnitTestResults.xml
+    PY_MPI_UNIT_TEST_XML: $CI_PROJECT_DIR/py-mpi-JUnitTestResults.xml
+    PY_ACCEPTANCE_TEST_XML: $CI_PROJECT_DIR/gmxapi-acceptance-JUnitTestResults.xml
+    PY_MPI_ACCEPTANCE_TEST_XML: $CI_PROJECT_DIR/gmxapi-acceptance-mpi-JUnitTestResults.xml
+  script:
+    - source $INSTALL_DIR/bin/GMXRC
+    - source $VENVPATH/bin/activate && INSTALL_DIR=$PWD/$INSTALL_DIR OMP_NUM_THREADS=1 bash admin/ci-scripts/build-and-test-py-gmxapi-0.2.sh
+  artifacts:
+    reports:
+      junit:
+        - $PY_UNIT_TEST_XML
+        - $PY_MPI_UNIT_TEST_XML
+        - $PY_ACCEPTANCE_TEST_XML
+        - $PY_MPI_ACCEPTANCE_TEST_XML
+    when: always
+    expire_in: 1 week
+  tags:
+    - k8s-scilifelab
+  # The dependency means we need to use the same tag restriction as upstream.
+  needs:
+    - job: gromacs:gcc-10:build
+      artifacts: true
+
+gmxapi-0.2:gcc-10:gmx2021:py-3.6.10:
+  extends:
+    - .gmxapi-0.2:gcc-10:gmx2021
+    - .rules:merge-requests:release-2021
+  variables:
+    VENVPATH: "/root/venv/py3.6"
+    PY_VER: "3.6.10"
+
+gmxapi-0.2:gcc-10:gmx2021:py-3.7.7:
+  extends:
+    - .gmxapi-0.2:gcc-10:gmx2021
+    - .rules:merge-requests:release-2021
+  variables:
+    VENVPATH: "/root/venv/py3.7"
+    PY_VER: "3.7.7"
+
+gmxapi-0.2:gcc-10:gmx2021:py-3.8.2:
+  extends:
+    - .gmxapi-0.2:gcc-10:gmx2021
+    - .rules:merge-requests:release-2021
+  variables:
+    VENVPATH: "/root/venv/py3.8"
+    PY_VER: "3.8.2"
diff --git a/admin/gitlab-ci/python-gmxapi03.gitlab-ci.yml b/admin/gitlab-ci/python-gmxapi03.gitlab-ci.yml
new file mode 100644 (file)
index 0000000..53a8605
--- /dev/null
@@ -0,0 +1,53 @@
+#
+# Jobs to test gmxapi client (Python) packages
+#
+
+.gmxapi-0.3:gcc-10:gmx2022:
+  extends:
+    - .variables:default
+    - .use-clang:base
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10
+  stage: test
+  variables:
+    KUBERNETES_CPU_LIMIT: 2
+    KUBERNETES_CPU_REQUEST: 2
+    KUBERNETES_MEMORY_LIMIT: 2Gi
+    KUBERNETES_MEMORY_REQUEST: 2Gi
+    PY_UNIT_TEST_XML: $CI_PROJECT_DIR/py-JUnitTestResults.xml
+    PY_MPI_UNIT_TEST_XML: $CI_PROJECT_DIR/py-mpi-JUnitTestResults.xml
+    PY_ACCEPTANCE_TEST_XML: $CI_PROJECT_DIR/gmxapi-acceptance-JUnitTestResults.xml
+    PY_MPI_ACCEPTANCE_TEST_XML: $CI_PROJECT_DIR/gmxapi-acceptance-mpi-JUnitTestResults.xml
+  script:
+    - source $INSTALL_DIR/bin/GMXRC
+    - source $VENVPATH/bin/activate && INSTALL_DIR=$PWD/$INSTALL_DIR OMP_NUM_THREADS=1 bash admin/ci-scripts/build-and-test-py-gmxapi-0.3.sh
+  artifacts:
+    reports:
+      junit:
+        - $PY_UNIT_TEST_XML
+        - $PY_MPI_UNIT_TEST_XML
+        - $PY_ACCEPTANCE_TEST_XML
+        - $PY_MPI_ACCEPTANCE_TEST_XML
+    when: always
+    expire_in: 1 week
+  tags:
+    - k8s-scilifelab
+  # The dependency means we need to use the same tag restriction as upstream.
+  needs:
+    - job: gromacs:gcc-10:build
+      artifacts: true
+
+gmxapi-0.3:gcc-10:gmx2022:py-3.7.7:
+  extends:
+    - .gmxapi-0.3:gcc-10:gmx2022
+    - .rules:merge-requests:master
+  variables:
+    VENVPATH: "/root/venv/py3.7"
+    PY_VER: "3.7.7"
+
+gmxapi-0.3:gcc-10:gmx2022:py-3.8.2:
+  extends:
+    - .gmxapi-0.3:gcc-10:gmx2022
+    - .rules:merge-requests:master
+  variables:
+    VENVPATH: "/root/venv/py3.8"
+    PY_VER: "3.8.2"
index c53451100649921494646057d2fb0d12d021778c..a872fecc42e01d9d6c0ef8522e5b667f3c8b3bfb 100644 (file)
 .rules-element:if-post-merge-acceptance-or-mr-then-always: &if-post-merge-acceptance-or-mr-then-always
   if: '$CI_PIPELINE_SOURCE == "merge_request_event" ||
        ($CI_PIPELINE_SOURCE == "push" &&
-        $CI_COMMIT_REF_NAME == "release-2021")'
+        $CI_COMMIT_REF_NAME == "master")'
   when: always
 
 # Include job only for post submit push
 .rules-element:if-post-merge-acceptance-then-always: &if-post-merge-acceptance-then-always
   if: '$CI_PIPELINE_SOURCE == "push" &&
-       $CI_COMMIT_REF_NAME == "release-2021"'
+       $CI_COMMIT_REF_NAME == "master"'
   when: always
 
 # When composing a rule set, note that the first matching rule is applied.
     - *if-schedule-then-always
     - *if-mr-then-always
 
-# Jobs that run for merge requests and schedules for branch `release-2020`,
+# Jobs that run for merge requests and schedules for branch `release-2021`,
 # but not when GROMACS_RELEASE is set.
 # Excludes non-gromacs projects.
-.rules:merge-requests:release-2020:
+.rules:merge-requests:release-2021:
   rules:
     - *if-not-gromacs-then-never
     - *if-release-then-never
     - *if-post-merge-acceptance-then-never
-    # This next rule catches "push" and other events in branches other than `release-2020`
-    # but allows merge_request_events for merge requests targeting `release-2020`.
+    # This next rule catches "push" and other events in branches other than `release-2021`
+    # but allows merge_request_events for merge requests targeting `release-2021`.
     # This rule is before "web" so the web interface won't include jobs that can't succeed
     # (and would not ordinarily be run). Such jobs are hard to identify in a way that is
     # sufficiently general for a global rules definition.
     # If extra coverage is needed through a web-triggered job in merge request branches,
     # we could provide an additional short-circuiting rule based on an environment variable
     # to be provided through the web interface.
-    - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME != "release-2020" && $CI_COMMIT_REF_NAME != "release-2020"'
+    - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME != "release-2021" && $CI_COMMIT_REF_NAME != "release-2021"'
       when: never
     - *if-web-then-always
     - *if-schedule-then-always
     - *if-mr-then-always
 
-# Jobs that run for merge requests and schedules for branch `release-2021`,
+# Jobs that run for merge requests and schedules for branch `release-2020`,
 # but not when GROMACS_RELEASE is set.
 # Excludes non-gromacs projects.
-.rules:merge-requests:release-2021:
+.rules:merge-requests:release-2020:
   rules:
     - *if-not-gromacs-then-never
     - *if-release-then-never
     - *if-post-merge-acceptance-then-never
-    # This next rule catches "push" and other events in branches other than `release-2021`
-    # but allows merge_request_events for merge requests targeting `release-2021`.
+    # This next rule catches "push" and other events in branches other than `release-2020`
+    # but allows merge_request_events for merge requests targeting `release-2020`.
     # This rule is before "web" so the web interface won't include jobs that can't succeed
     # (and would not ordinarily be run). Such jobs are hard to identify in a way that is
     # sufficiently general for a global rules definition.
     # If extra coverage is needed through a web-triggered job in merge request branches,
     # we could provide an additional short-circuiting rule based on an environment variable
     # to be provided through the web interface.
-    - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME != "release-2021" && $CI_COMMIT_REF_NAME != "release-2021"'
+    - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME != "release-2020" && $CI_COMMIT_REF_NAME != "release-2020"'
       when: never
     - *if-web-then-always
     - *if-schedule-then-always
index be00e42f7c6540bfd0b70ad9e0c4d6226820a014..e5d9b0a412efc73e5a2498bd21946582337d08d4 100644 (file)
@@ -5,7 +5,7 @@
   extends:
     - .variables:default
     - .use-clang:base
-  image: ${CI_REGISTRY}/gromacs/gromacs/cmake-3.15.7-llvm-8-intelopencl-openmpi:2020:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/cmake-3.15.7-llvm-8-intelopencl-openmpi:2020
   stage: test
   variables:
     KUBERNETES_CPU_LIMIT: 2
index 13c255b0bcc3d755230eedcf8bdcf0d3defa6c2e..629efb245dead094929003ec113c1c5edeb76041 100644 (file)
@@ -3,7 +3,7 @@
   extends:
     - .variables:default
     - .use-clang:base
-  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10:release-2021
+  image: ${CI_REGISTRY}/gromacs/gromacs/ci-ubuntu-20.04-gcc-10
   stage: test
   variables:
     KUBERNETES_CPU_LIMIT: 2
index f04a688a8f68fac9a0ca4eef3bd40b4f05458865..ce8a33ee2b886b0d6f90e511c5b9e0eb58aebbe4 100644 (file)
@@ -4,8 +4,8 @@ leak:add_to_list
 leak:atoms_to_constraints
 leak:atoms_to_settles
 leak:balance_fep_lists
-leak:cpp_opts
-leak:dd_init_bondeds
+leak:dd_make_reverse_top
+leak:makeBondedLinks
 leak:dd_make_local_constraints
 leak:dd_move_f
 leak:dd_partition_system
@@ -14,39 +14,29 @@ leak:do_cpte_matrices
 leak:do_edsam
 leak:do_inputrec
 leak:do_single_flood
-leak:get_ir
-leak:get_zone_pulse_cgs
+leak:get_zone_pulse_groups
 leak:gmx::DomainDecompositionBuilder::Impl::build
 leak:gmx_check
 leak:gmx_make_edi
-leak:gmx_mtop_ilistloop_init
-leak:gmx_pme_init
 leak:gmx_pme_receive_f
-leak:init_buffer_flags
-leak:init_disres
 leak:init_dfhist_state
 leak:init_df_history
+leak:init_disres
 leak:init_edsam
 leak:init_ekinstate
-leak:init_interaction_const
-leak:init_orires
 leak:init_rot
 leak:init_swapcoords
 leak:make_bondeds_zone
 leak:make_dd_indices
 leak:make_exclusions_zone
 leak:make_fep_list
-leak:make_ljpme_c6grid
 leak:make_pull_groups
-leak:make_reverse_top
 leak:make_rotation_groups
-leak:make_swap_groups
 leak:make_tables
 leak:mdoutf_write_to_trajectory_files
 # Stack trace does not report a function beyond gmx_srenew_impl, so the file is suppressed instead.
 leak:pairlist.cpp
 leak:read_rotparams
-leak:set_ddgrid_parameters
 leak:set_reference_positions
 leak:set_state_entries
 leak:visitOption
index cc6f2849f4b9db99b8159e76e55b30585c844c71..5773bbf265b33edb3aa49d78ff5f83392866b45c 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# The legacy public API headers may still be installed,
+# but may be removed or changed without warning.
+add_subdirectory(legacy)
 
 # Activate targets for new C++ API components and docs.
-if(GMX_NATIVE_WINDOWS OR GMX_BUILD_MDRUN_ONLY)
+if(GMX_NATIVE_WINDOWS)
     # GMXAPI has not been tested in Microsoft environments.
-    # GMXAPI relies on libgromacs and is incompatible with an `mdrun`-only build.
     # GMXAPI requires position-independent code
     set(_GMXAPI_DEFAULT OFF)
 else()
@@ -48,11 +50,9 @@ if (GMXAPI)
 endif()
 
 # Activate targets NBLIB
-if(GMX_NATIVE_WINDOWS OR GMX_BUILD_MDRUN_ONLY OR NOT BUILD_SHARED_LIBS OR CMAKE_CXX_COMPILER_ID MATCHES "Intel")
+if(GMX_NATIVE_WINDOWS OR NOT BUILD_SHARED_LIBS)
     # NBLIB has not been tested in Microsoft environments.
-    # NBLIB relies on libgromacs and is incompatible with an `mdrun`-only build.
     # NBLIB requires position-independent code
-    # NBLIB causes an ICE in icc 19.1.2.20200623
     set(_NBLIB_DEFAULT OFF)
 else()
     set(_NBLIB_DEFAULT ON)
index 7a5710a7a80ea508c9c6843e86fcc4ebe849d9d5..865abe29253db45832529ed5c4e5378f7b7255a2 100644 (file)
@@ -50,7 +50,7 @@
 # be tagged. Official GROMACS releases should be mappable to a distinct gmxapi
 # release string. For roadmap details, see https://gitlab.com/gromacs/gromacs/-/issues/2585
 set(GMXAPI_MAJOR 0)
-set(GMXAPI_MINOR 2)
+set(GMXAPI_MINOR 3)
 set(GMXAPI_PATCH 0)
 set(GMXAPI_RELEASE ${GMXAPI_MAJOR}.${GMXAPI_MINOR}.${GMXAPI_PATCH})
 
@@ -69,7 +69,7 @@ if (GMX_LIB_MPI)
     # Do not target_link_options(gmxapi PRIVATE ${MPI_LINKER_FLAGS})
     # because the root CMakeLists.txt sets CMAKE_SHARED_LINKER_FLAGS.
     target_compile_options(gmxapi PUBLIC ${MPI_COMPILE_FLAGS})
-    target_link_libraries(gmxapi PUBLIC ${MPI_C_LIBRARIES})
+    target_link_libraries(gmxapi PUBLIC ${MPI_CXX_LIBRARIES})
 elseif(GMX_THREAD_MPI)
     # GROMACS is built with its internal thread-MPI implementation.
     set(_gmx_mpi_type "tmpi")
index 52d88c54dce11188c1ce70191028b440be493085..1e07928a83f3b2fb18977bccf75060539a3a7e93 100644 (file)
@@ -84,6 +84,9 @@ set_target_properties(gmxapi PROPERTIES
                       )
 
 target_link_libraries(gmxapi PRIVATE libgromacs)
+target_link_libraries(gmxapi PRIVATE common)
+# TODO: Explicitly link specific modules: mdlib, mdtypes, utility, commandline
+target_link_libraries(gmxapi PRIVATE legacy_modules)
 
 
 ################################################
index fcb7de77e103d4ca06183f2ba758d71aae34fd70..829e802bc639e4b689a6af3ae30aa6b4b34a4ac1 100644 (file)
@@ -2,6 +2,8 @@ set(gmxapi_VERSION @GMXAPI_RELEASE@)
 @PACKAGE_INIT@
 # Refer to CMake docs for information on more elaborate use of this stub file:
 # https://cmake.org/cmake/help/v3.4/module/CMakePackageConfigHelpers.html#command:configure_package_config_file
+include(CMakeFindDependencyMacro)
+@_gmxapi_find_dependencies@
 include("${CMAKE_CURRENT_LIST_DIR}/gmxapi.cmake")
 check_required_components(gmxapi)
 set_property(TARGET Gromacs::gmxapi PROPERTY MPI "@_mpi@")
index 6d11120eae6c55e520374f3ba4a21636f41f7db0..a46f78238ab56002b4071ea599646acd5cac6065 100644 (file)
@@ -347,13 +347,16 @@ std::shared_ptr<Session> ContextImpl::launch(const Workflow& work)
         SimulationContext simulationContext(communicator, multiSimDirectoryNames);
 
 
-        StartingBehavior startingBehavior        = StartingBehavior::NewSimulation;
-        LogFilePtr       logFileGuard            = nullptr;
-        gmx_multisim_t*  ms                      = simulationContext.multiSimulation_.get();
-        std::tie(startingBehavior, logFileGuard) = handleRestart(
-                findIsSimulationMasterRank(ms, simulationContext.simulationCommunicator_),
-                simulationContext.simulationCommunicator_, ms, options.mdrunOptions.appendingBehavior,
-                ssize(options.filenames), options.filenames.data());
+        StartingBehavior startingBehavior = StartingBehavior::NewSimulation;
+        LogFilePtr       logFileGuard     = nullptr;
+        gmx_multisim_t*  ms               = simulationContext.multiSimulation_.get();
+        std::tie(startingBehavior, logFileGuard) =
+                handleRestart(findIsSimulationMasterRank(ms, simulationContext.simulationCommunicator_),
+                              simulationContext.simulationCommunicator_,
+                              ms,
+                              options.mdrunOptions.appendingBehavior,
+                              ssize(options.filenames),
+                              options.filenames.data());
 
         auto builder = MdrunnerBuilder(std::move(mdModules),
                                        compat::not_null<SimulationContext*>(&simulationContext));
@@ -384,8 +387,8 @@ std::shared_ptr<Session> ContextImpl::launch(const Workflow& work)
         builder.addLogFile(logFileGuard.get());
 
         // Note, creation is not mature enough to be exposed in the external API yet.
-        launchedSession = createSession(shared_from_this(), std::move(builder),
-                                        std::move(simulationContext), std::move(logFileGuard));
+        launchedSession = createSession(
+                shared_from_this(), std::move(builder), std::move(simulationContext), std::move(logFileGuard));
 
         // Clean up argv once builder is no longer in use
         // TODO: Remove long-lived references to argv so this is no longer necessary.
index 6cf8f6158a9ee6f29def2e89707dc5319618c70b..e54615a0c9602a6d8967703e006f9a0810bb3ccd 100644 (file)
@@ -129,8 +129,9 @@ public:
         auto& callCounter = manager_->called_.at(name_);
         callCounter.store(true);
         using pairType = typename decltype(manager_->called_)::value_type;
-        if (std::all_of(manager_->called_.cbegin(), manager_->called_.cend(),
-                        [](const pairType& p) { return p.second.load(); }))
+        if (std::all_of(manager_->called_.cbegin(), manager_->called_.cend(), [](const pairType& p) {
+                return p.second.load();
+            }))
         {
             *manager_->state_ = gmx::StopSignal::stopAtNextNSStep;
         }
index 2b909663b094a2d9b579957fb6bccbffe6a333cd..0bccfacf8d6bb2f5ef06d91e715b850ff07e27c8 100644 (file)
@@ -122,8 +122,10 @@ std::unique_ptr<SessionImpl> SessionImpl::create(std::shared_ptr<ContextImpl> co
 {
     // We should be able to get a communicator (or subcommunicator) through the
     // Context.
-    return std::make_unique<SessionImpl>(std::move(context), std::move(runnerBuilder),
-                                         std::move(simulationContext), std::move(logFilehandle));
+    return std::make_unique<SessionImpl>(std::move(context),
+                                         std::move(runnerBuilder),
+                                         std::move(simulationContext),
+                                         std::move(logFilehandle));
 }
 
 SessionImpl::SessionImpl(std::shared_ptr<ContextImpl> context,
@@ -156,8 +158,10 @@ std::shared_ptr<Session> createSession(std::shared_ptr<ContextImpl> context,
                                        gmx::SimulationContext&&     simulationContext,
                                        gmx::LogFilePtr              logFilehandle)
 {
-    auto newSession      = SessionImpl::create(std::move(context), std::move(runnerBuilder),
-                                          std::move(simulationContext), std::move(logFilehandle));
+    auto newSession      = SessionImpl::create(std::move(context),
+                                          std::move(runnerBuilder),
+                                          std::move(simulationContext),
+                                          std::move(logFilehandle));
     auto launchedSession = std::make_shared<Session>(std::move(newSession));
     return launchedSession;
 }
index 2d498079f87a400a8053c5ac105233cba6c1f4b0..b59f7f971e8d405250dc202371ea485beaf7edfe 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -706,7 +706,7 @@ void writeTprFile(const std::string&     filename,
     const auto& inputRecord   = tprFile->inputRecord();
     const auto& writeState    = tprFile->state();
     const auto& writeTopology = tprFile->molecularTopology();
-    write_tpx_state(filename.c_str(), &inputRecord, &writeState, &writeTopology);
+    write_tpx_state(filename.c_str(), &inputRecord, &writeState, writeTopology);
 }
 
 TprReadHandle::TprReadHandle(TprContents&& tprFile) :
@@ -745,9 +745,11 @@ bool copy_tprfile(const gmxapicompat::TprReadHandle& input, const std::string& o
     {
         return false;
     }
-    gmxapicompat::writeTprFile(
-            outFile, *gmxapicompat::getMdParams(input), *gmxapicompat::getStructureSource(input),
-            *gmxapicompat::getSimulationState(input), *gmxapicompat::getTopologySource(input));
+    gmxapicompat::writeTprFile(outFile,
+                               *gmxapicompat::getMdParams(input),
+                               *gmxapicompat::getStructureSource(input),
+                               *gmxapicompat::getSimulationState(input),
+                               *gmxapicompat::getTopologySource(input));
     return true;
 }
 
@@ -772,7 +774,7 @@ bool rewrite_tprfile(const std::string& inFile, const std::string& outFile, doub
 
     irInstance.nsteps = lround((endTime - run_t) / irInstance.delta_t);
 
-    write_tpx_state(outFile.c_str(), &irInstance, &state, &mtop);
+    write_tpx_state(outFile.c_str(), &irInstance, &state, mtop);
 
     success = true;
     return success;
similarity index 53%
rename from cmake/Platform/Toolchain-Fujitsu-Sparc64.cmake
rename to api/legacy/CMakeLists.txt
index be5f13898ad466c3c2f694e3179aa10137c1b678..116bf49ada48322e59bb59ae47e03e0c1b2f3603 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) 2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
-# the name of the target operating system
-set(CMAKE_SYSTEM_NAME Linux CACHE STRING "Cross-compiling for Fujitsu Sparc64")
-# Set the identification to the same value we would get on the nodes (uname -m)
-set(CMAKE_SYSTEM_PROCESSOR "s64fx")
+# The legacy installed API consists of headers that are not considered
+# to be maintainable in terms of a stable API specification. These headers
+# will no longer be available to install in a future release.
 
-set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+# Note: Any usage requirements that should be transitive should be added to
+# this INTERFACE target. Compiler and linker options (that do not need to
+# be propagated when linking to the `common` target) can be added directly
+# to the `common` target.
+add_library(legacy_api INTERFACE)
+target_include_directories(legacy_api INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
+                           $<INSTALL_INTERFACE:include>)
 
-# set the compiler
-set(CMAKE_C_COMPILER fccpx)
-set(CMAKE_CXX_COMPILER FCCpx)
+configure_file(version.h.cmakein include/gromacs/version.h)
 
-# Prevent CMake from adding GNU-specific linker flags (-rdynamic)
-# A patch has been submitted to make CMake itself handle this in the future
-set(CMAKE_C_COMPILER_ID "Fujitsu" CACHE STRING "Fujitsu C cross-compiler" FORCE)
-set(CMAKE_CXX_COMPILER_ID "Fujitsu" CACHE STRING "Fujitsu C++ cross-compiler" FORCE)
+# Allow an export target for legacy_api since it is a dependency of the
+# installable libgromacs target.
+install(TARGETS legacy_api
+        EXPORT libgromacs
+        INCLUDES DESTINATION include)
 
-# FindOpenMP.cmake does not try -Kopenmp,but the package will try specific
-# flags based on the compier ID.
-set(OMP_FLAG_Fujitsu "-Kopenmp")
+if(GMX_INSTALL_LEGACY_API)
+    # Install public header directories.
+    install(DIRECTORY include/gromacs
+            DESTINATION include)
+
+    # Install "configured" files from the build tree.
+    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/gromacs/version.h
+            DESTINATION include/gromacs)
+endif()
similarity index 98%
rename from src/gromacs/fileio/confio.h
rename to api/legacy/include/gromacs/fileio/confio.h
index 08af69c205ef465e727c040d8a9b9fa2e8bcaa8c..bd69125d2efc884dc358ae3920cb252e5b05d630 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -73,7 +73,7 @@ void write_sto_conf(const char*    outfile,
 
 void write_sto_conf_mtop(const char*       outfile,
                          const char*       title,
-                         const gmx_mtop_t* mtop,
+                         const gmx_mtop_t& mtop,
                          const rvec        x[],
                          const rvec*       v,
                          PbcType           pbcType,
similarity index 87%
rename from src/gromacs/fileio/pdbio.h
rename to api/legacy/include/gromacs/fileio/pdbio.h
index fee2ab1373b2d457b2d915120449164257b8a3af..c34562e095dd86d4fb0b72a812bd668e0cabf6fd 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,7 @@ struct t_atoms;
 struct t_symtab;
 struct t_topology;
 enum class PbcType : int;
+enum class PdbRecordType : int;
 
 typedef struct gmx_conect_t* gmx_conect;
 
@@ -58,21 +59,21 @@ typedef struct gmx_conect_t* gmx_conect;
  *
  * Returns the number of characters printed.
  */
-int gmx_fprintf_pdb_atomline(FILE*           fp,
-                             enum PDB_record record,
-                             int             atom_seq_number,
-                             const char*     atom_name,
-                             char            alternate_location,
-                             const char*     res_name,
-                             char            chain_id,
-                             int             res_seq_number,
-                             char            res_insertion_code,
-                             real            x,
-                             real            y,
-                             real            z,
-                             real            occupancy,
-                             real            b_factor,
-                             const char*     element);
+int gmx_fprintf_pdb_atomline(FILE*         fp,
+                             PdbRecordType record,
+                             int           atom_seq_number,
+                             const char*   atom_name,
+                             char          alternate_location,
+                             const char*   res_name,
+                             char          chain_id,
+                             int           res_seq_number,
+                             char          res_insertion_code,
+                             real          x,
+                             real          y,
+                             real          z,
+                             real          occupancy,
+                             real          b_factor,
+                             const char*   element);
 
 /* Enumerated value for indexing an uij entry (anisotropic temperature factors) */
 enum
similarity index 99%
rename from src/gromacs/fileio/tpxio.h
rename to api/legacy/include/gromacs/fileio/tpxio.h
index 08229c62a4bcb7866b3c3d91352a41267850330b..96ff4f6ca532bcdf004ee6b85583b3cd3c34ccce 100644 (file)
@@ -144,7 +144,7 @@ struct PartialDeserializedTprFile
  */
 TpxFileHeader readTpxHeader(const char* fileName, bool canReadTopologyOnly);
 
-void write_tpx_state(const char* fn, const t_inputrec* ir, const t_state* state, const gmx_mtop_t* mtop);
+void write_tpx_state(const char* fn, const t_inputrec* ir, const t_state* state, const gmx_mtop_t& mtop);
 /* Write a file, and close it again.
  */
 
similarity index 98%
rename from src/gromacs/fileio/trxio.h
rename to api/legacy/include/gromacs/fileio/trxio.h
index ae1660c99ac33d13a573fa019f278b227183fba3..9e9bedf421750bf06218830f929759a0f0a88f64 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -138,7 +138,7 @@ t_trxstatus* trjtools_gmx_prepare_tng_writing(const char*              filename,
                                               t_trxstatus*             in,
                                               const char*              infile,
                                               int                      natoms,
-                                              const struct gmx_mtop_t* mtop,
+                                              const gmx_mtop_t*        mtop,
                                               gmx::ArrayRef<const int> index,
                                               const char*              index_group_name);
 
similarity index 95%
rename from src/gromacs/math/functions.h
rename to api/legacy/include/gromacs/math/functions.h
index 35150b3ddd7c2da8a66ddbd92d9515b744b545b8..af557fb6adde0cd37262f2b659a1ca92de888c82 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2018,2019,2020 by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -472,6 +473,19 @@ static inline int64_t roundToInt64(double x)
     return static_cast<int>(rint(x));
 }
 
+//! \brief Check whether \p v is an integer power of 2.
+template<typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
+#if defined(__NVCC__) && !defined(__CUDACC_RELAXED_CONSTEXPR__)
+/* In CUDA 11, a constexpr function cannot be called from a function with incompatible execution
+ * space, unless --expt-relaxed-constexpr flag is set */
+__host__ __device__
+#endif
+        static inline constexpr bool
+        isPowerOfTwo(const T v)
+{
+    return (v > 0) && ((v & (v - 1)) == 0);
+}
+
 } // namespace gmx
 
 
diff --git a/api/legacy/include/gromacs/math/units.h b/api/legacy/include/gromacs/math/units.h
new file mode 100644 (file)
index 0000000..c0cde6f
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * 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,2018,2019, The GROMACS development team.
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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_MATH_UNITS_H
+#define GMX_MATH_UNITS_H
+
+#include <cmath>
+
+/*
+ * Physical constants to be used in Gromacs.
+ * No constants (apart from 0, 1 or 2) should
+ * be anywhere else in the code.
+ */
+
+#ifndef M_PI
+#    define M_PI 3.14159265358979323846
+#endif
+
+#ifndef M_PI_2
+#    define M_PI_2 1.57079632679489661923
+#endif
+
+#ifndef M_2PI
+#    define M_2PI 6.28318530717958647692
+#endif
+
+#ifndef M_SQRT2
+#    define M_SQRT2 sqrt(2.0)
+#endif
+
+#ifndef M_1_PI
+#    define M_1_PI 0.31830988618379067154
+#endif
+
+#ifndef M_FLOAT_1_SQRTPI /* used in GPU kernels */
+/* 1.0 / sqrt(M_PI) */
+#    define M_FLOAT_1_SQRTPI 0.564189583547756f
+#endif
+
+#ifndef M_1_SQRTPI
+/* 1.0 / sqrt(M_PI) */
+#    define M_1_SQRTPI 0.564189583547756
+#endif
+
+#ifndef M_2_SQRTPI
+/* 2.0 / sqrt(M_PI) */
+#    define M_2_SQRTPI 1.128379167095513
+#endif
+
+namespace gmx
+{
+
+constexpr double c_angstrom       = 1e-10;
+constexpr double c_kilo           = 1e3;
+constexpr double c_nano           = 1e-9;
+constexpr double c_pico           = 1e-12;
+constexpr double c_nm2A           = c_nano / c_angstrom;
+constexpr double c_cal2Joule      = 4.184;           /* Exact definition of the calorie */
+constexpr double c_electronCharge = 1.602176634e-19; /* Exact definition, Coulomb NIST 2018 CODATA */
+
+constexpr double c_amu       = 1.66053906660e-27; /* kg, NIST 2018 CODATA  */
+constexpr double c_boltzmann = 1.380649e-23;      /* (J/K, Exact definition, NIST 2018 CODATA */
+constexpr double c_avogadro  = 6.02214076e23;     /* 1/mol, Exact definition, NIST 2018 CODATA */
+constexpr double c_universalGasConstant = c_boltzmann * c_avogadro;        /* (J/(mol K))  */
+constexpr double c_boltz                = c_universalGasConstant / c_kilo; /* (kJ/(mol K)) */
+constexpr double c_faraday              = c_electronCharge * c_avogadro;   /* (C/mol)      */
+constexpr double c_planck1 = 6.62607015e-34; /* J/Hz, Exact definition, NIST 2018 CODATA */
+constexpr double c_planck  = (c_planck1 * c_avogadro / (c_pico * c_kilo)); /* (kJ/mol) ps */
+
+constexpr double c_epsilon0Si = 8.8541878128e-12; /* F/m,  NIST 2018 CODATA */
+/* Epsilon in our MD units: (e^2 / Na (kJ nm)) == (e^2 mol/(kJ nm)) */
+constexpr double c_epsilon0 =
+        ((c_epsilon0Si * c_nano * c_kilo) / (c_electronCharge * c_electronCharge * c_avogadro));
+
+constexpr double c_speedOfLight =
+        2.99792458e05; /* units of nm/ps, Exact definition, NIST 2018 CODATA */
+
+constexpr double c_rydberg = 1.0973731568160e-02; /* nm^-1, NIST 2018 CODATA */
+
+constexpr double c_one4PiEps0 = (1.0 / (4.0 * M_PI * c_epsilon0));
+
+/* Pressure in MD units is:
+ * 1 bar = 1e5 Pa = 1e5 kg m^-1 s^-2 = 1e-28 kg nm^-1 ps^-2 = 1e-28 / amu amu nm^1 ps ^2
+ */
+constexpr double c_barMdunits = (1e5 * c_nano * c_pico * c_pico / c_amu);
+constexpr double c_presfac    = 1.0 / c_barMdunits;
+
+/* c_debye2Enm should be (1e-21*c_pico)/(c_speedOfLight*c_electronCharge*c_nano*c_nano),
+ * but we need to factor out some of the exponents to avoid single-precision overflows.
+ */
+constexpr double c_debye2Enm = (1e-15 / (c_speedOfLight * c_electronCharge));
+constexpr double c_enm2Debye = 1.0 / c_debye2Enm;
+
+/* to convert from a acceleration in (e V)/(amu nm) */
+/* c_fieldfac is also Faraday's constant and c_electronCharge/(1e6 amu) */
+constexpr double c_fieldfac = c_faraday / c_kilo;
+
+/* to convert AU to MD units: */
+constexpr double c_hartree2Kj     = ((2.0 * c_rydberg * c_planck * c_speedOfLight) / c_avogadro);
+constexpr double c_bohr2Nm        = 0.0529177210903; /* nm^-1, NIST 2018 CODATA */
+constexpr double c_hartreeBohr2Md = (c_hartree2Kj * c_avogadro / c_bohr2Nm);
+
+constexpr double c_rad2Deg = 180.0 / M_PI;
+constexpr double c_deg2Rad = M_PI / 180.0;
+} // namespace gmx
+
+/* The four basic units */
+#define unit_length "nm"
+#define unit_time "ps"
+#define unit_mass "u"
+#define unit_energy "kJ/mol"
+
+/* Temperature unit, T in this unit times c_boltz give energy in unit_energy */
+#define unit_temp_K "K"
+
+/* Charge unit, electron charge, involves c_one4PiEps0 */
+#define unit_charge_e "e"
+
+/* Pressure unit, pressure in basic units times c_presfac gives this unit */
+#define unit_pres_bar "bar"
+
+/* Dipole unit, debye, conversion from the unit_charge_e involves c_enm2Debye */
+#define unit_dipole_D "D"
+
+/* Derived units from basic units only */
+#define unit_vel unit_length "/" unit_time
+#define unit_volume unit_length "^3"
+#define unit_invtime "1/" unit_time
+
+/* Other derived units */
+#define unit_surft_bar unit_pres_bar " " unit_length
+
+/* SI units, conversion from basic units involves c_nano, c_pico and amu */
+#define unit_length_SI "m"
+#define unit_time_SI "s"
+#define unit_mass_SI "kg"
+
+#define unit_density_SI unit_mass_SI "/" unit_length_SI "^3"
+#define unit_invvisc_SI unit_length_SI " " unit_time_SI "/" unit_mass_SI
+
+#endif
similarity index 84%
rename from src/gromacs/math/utilities.h
rename to api/legacy/include/gromacs/math/utilities.h
index 5ff601d97cdfff969b386ae520fca04ec89be1fe..a4c40e949677662777514c9324390953645e9ed3 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_MATH_UTILITIES_H
 
 #include <limits.h>
+#include <stdint.h>
 
 #include <cmath>
 
-#include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/real.h"
-
-#ifndef M_PI
-#    define M_PI 3.14159265358979323846
-#endif
-
-#ifndef M_PI_2
-#    define M_PI_2 1.57079632679489661923
-#endif
-
-#ifndef M_2PI
-#    define M_2PI 6.28318530717958647692
-#endif
-
-#ifndef M_SQRT2
-#    define M_SQRT2 sqrt(2.0)
-#endif
-
-#ifndef M_1_PI
-#    define M_1_PI 0.31830988618379067154
-#endif
-
-#ifndef M_FLOAT_1_SQRTPI /* used in GPU kernels */
-/* 1.0 / sqrt(M_PI) */
-#    define M_FLOAT_1_SQRTPI 0.564189583547756f
-#endif
-
-#ifndef M_1_SQRTPI
-/* 1.0 / sqrt(M_PI) */
-#    define M_1_SQRTPI 0.564189583547756
-#endif
-
-#ifndef M_2_SQRTPI
-/* 2.0 / sqrt(M_PI) */
-#    define M_2_SQRTPI 1.128379167095513
-#endif
-
 /*! \brief Enum to select safe or highly unsafe (faster) math functions.
  *
  *  Normally all the Gromacs math functions should apply reasonable care with
@@ -139,7 +102,7 @@ bool gmx_numzero(double a);
  *
  * \return False iff overflow occurred
  */
-gmx_bool check_int_multiply_for_overflow(int64_t a, int64_t b, int64_t* result);
+bool check_int_multiply_for_overflow(int64_t a, int64_t b, int64_t* result);
 
 /*! \brief Enable floating-point exceptions if supported on OS
  *
@@ -157,4 +120,19 @@ int gmx_feenableexcept();
  */
 int gmx_fedisableexcept();
 
+/*! \brief Return true if the current build should enable floating-point exceptions by default.
+ *
+ * Currently, it returns true unless any of the following conditions are met:
+ * - release build,
+ * - SYCL build (Intel IGC, at least 1.0.5964, raises FP exceptions in JIT compilation),
+ * - - See https://github.com/intel/intel-graphics-compiler/issues/164
+ * - compilers with known buggy FP exception support (clang with any optimization)
+ *   or suspected buggy FP exception support (gcc 7.* with optimization).
+ *
+ * Note that this function does not check whether the build/OS supports FP exceptions.
+ *
+ * \returns true if we should enable FP exceptions by default.
+ */
+bool gmxShouldEnableFPExceptions();
+
 #endif
similarity index 96%
rename from src/gromacs/math/vectypes.h
rename to api/legacy/include/gromacs/math/vectypes.h
index d4d5211d11040df051f044d22918d33a4caf5588..55f28e2a4de3961446838ab56fc8d861bb97c687 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +123,16 @@ public:
     ValueType& operator[](int i) { return x_[i]; }
     //! Indexing operator to make the class work as the raw array.
     ValueType operator[](int i) const { return x_[i]; }
+    //! Return whether all elements compare equal
+    bool operator==(const BasicVector<ValueType>& right)
+    {
+        return x_[0] == right[0] && x_[1] == right[1] && x_[2] == right[2];
+    }
+    //! Return whether any elements compare unequal
+    bool operator!=(const BasicVector<ValueType>& right)
+    {
+        return x_[0] != right[0] || x_[1] != right[1] || x_[2] != right[2];
+    }
     //! Allow inplace addition for BasicVector
     BasicVector<ValueType>& operator+=(const BasicVector<ValueType>& right)
     {
similarity index 99%
rename from src/gromacs/restraint/restraintpotential.h
rename to api/legacy/include/gromacs/restraint/restraintpotential.h
index 72bf0dbe712d25ed80262202b4096d0bd5a71ca4..872d0690160688484e7fe606f13f6ca3f44693fc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
similarity index 89%
rename from src/gromacs/utility/basedefinitions.h
rename to api/legacy/include/gromacs/utility/basedefinitions.h
index bfb155651abac78b7e354662b12245f91064b67b..79dbbbc736467ae246d8af2344127ea32e8a45e2 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,10 +104,7 @@ index ssize(const T& t)
  */
 #ifndef gmx_unused
 #    ifdef __GNUC__
-/* GCC, clang, and some ICC pretending to be GCC */
-#        define gmx_unused __attribute__((unused))
-#    elif (defined(__INTEL_COMPILER) || defined(__ECC)) && !defined(_MSC_VER)
-/* ICC on *nix */
+/* GCC, clang, and any pretending to be or based on them */
 #        define gmx_unused __attribute__((unused))
 #    elif defined(__PGI)
 /* Portland group compilers */
@@ -148,6 +145,18 @@ index ssize(const T& t)
  */
 #define GMX_UNUSED_VALUE(value) (void)value
 
+#if defined(__GNUC__) && !defined(__clang__)
+#    define DO_PRAGMA(x) _Pragma(#    x)
+#    define GCC_DIAGNOSTIC_IGNORE(warning) \
+        _Pragma("GCC diagnostic push") DO_PRAGMA(GCC diagnostic ignored #warning)
+#    define GCC_DIAGNOSTIC_RESET _Pragma("GCC diagnostic pop")
+#else
+//! Ignore specified clang warning until GCC_DIAGNOSTIC_RESET
+#    define GCC_DIAGNOSTIC_IGNORE(warning)
+//! Reset all diagnostics to default
+#    define GCC_DIAGNOSTIC_RESET
+#endif
+
 #ifdef __clang__
 #    define DO_PRAGMA(x) _Pragma(#    x)
 #    define CLANG_DIAGNOSTIC_IGNORE(warning) \
@@ -170,18 +179,6 @@ index ssize(const T& t)
 #    define MSVC_DIAGNOSTIC_RESET
 #endif
 
-#ifdef __INTEL_COMPILER
-//! Ignore unused loop variable warning - it was used until the compiler removes the use!
-#    define DO_PRAGMA(x) _Pragma(#    x)
-#    define INTEL_DIAGNOSTIC_IGNORE(id) DO_PRAGMA(warning push) DO_PRAGMA(warning(disable : id))
-#    define INTEL_DIAGNOSTIC_RESET DO_PRAGMA(warning pop)
-#else
-//! Ignore specified diagnostic message from Intel compiler.
-#    define INTEL_DIAGNOSTIC_IGNORE(id)
-//! Reset the diagnostic message setting.
-#    define INTEL_DIAGNOSTIC_RESET
-#endif
-
 namespace gmx
 {
 namespace internal
similarity index 94%
rename from src/gromacs/utility/current_function.h
rename to api/legacy/include/gromacs/utility/current_function.h
index 1f18cab6ffce9d542ae887075677ca3556e24bfc..2d5aef4f60737f14214763bb2cd7521e46cb9ab2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +85,7 @@ inline void current_function_helper()
 
 #    define GMX_CURRENT_FUNCTION __FUNCSIG__
 
-#elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)) \
-        || (defined(__IBMCPP__) && (__IBMCPP__ >= 500))
+#elif (defined(__IBMCPP__) && (__IBMCPP__ >= 500))
 
 #    define GMX_CURRENT_FUNCTION __FUNCTION__
 
similarity index 92%
rename from src/gromacs/utility/gmxassert.h
rename to api/legacy/include/gromacs/utility/gmxassert.h
index c278f2c2fc3c702d473c718a47a60793c0a1345b..dea2e5eb0d62db5e317ade4c8581ec35d3b0fd74 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2011-2018, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +44,6 @@
 #ifndef GMX_UTILITY_GMXASSERT_H
 #define GMX_UTILITY_GMXASSERT_H
 
-#include "gromacs/utility/basedefinitions.h"
-
 #include "current_function.h"
 
 //! \addtogroup module_utility
 #    define GMX_RELEASE_ASSERT(condition, msg)
 #else
 #    ifdef _MSC_VER
-#        define GMX_RELEASE_ASSERT(condition, msg)                                                      \
-            ((void)((condition) ? (void)0                                                               \
-                                : ::gmx::internal::assertHandler(#condition, msg, GMX_CURRENT_FUNCTION, \
-                                                                 __FILE__, __LINE__)))
+#        define GMX_RELEASE_ASSERT(condition, msg)                \
+            ((void)((condition) ? (void)0                         \
+                                : ::gmx::internal::assertHandler( \
+                                          #condition, msg, GMX_CURRENT_FUNCTION, __FILE__, __LINE__)))
 #    else
 // Use an "immediately invoked function expression" to allow being
 // used in constexpr context with older GCC versions
similarity index 96%
rename from src/gromacs/utility/listoflists.h
rename to api/legacy/include/gromacs/utility/listoflists.h
index 8d707a0957b3d8d87bd6d0e05b621b09afa89de8..13c14149a5f562e64f5650532acdcf6eda77f89f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -162,8 +162,8 @@ public:
     ArrayRef<T> front()
     {
         GMX_ASSERT(size() > 0, "Must contain a list if front() is called");
-        auto beginPtr = elements_.data();
-        auto endPtr   = beginPtr + listRanges_[1];
+        auto* beginPtr = elements_.data();
+        auto* endPtr   = beginPtr + listRanges_[1];
         return { beginPtr, endPtr };
     }
     /*! \brief Returns a reference to the final list
@@ -188,8 +188,8 @@ public:
     //! Appends a ListOfLists at the end and increments the appended elements by \p offset
     void appendListOfLists(const ListOfLists& listOfLists, const T offset = 0)
     {
-        listRanges_.insert(listRanges_.end(), listOfLists.listRanges_.begin() + 1,
-                           listOfLists.listRanges_.end());
+        listRanges_.insert(
+                listRanges_.end(), listOfLists.listRanges_.begin() + 1, listOfLists.listRanges_.end());
         const int oldNumElements = elements_.size();
         for (std::size_t i = listRanges_.size() - listOfLists.size(); i < listRanges_.size(); i++)
         {
diff --git a/api/legacy/version.h.cmakein b/api/legacy/version.h.cmakein
new file mode 100644 (file)
index 0000000..ffe1a25
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2012,2014,2020, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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
+ * Version information for software that links to \Gromacs.
+ *
+ * \if libapi
+ * This include file will be configured by CMake and contains version
+ * information.  It is not used by \Gromacs, but intended for software that
+ * links to \Gromacs.
+ * The values come from the main CMakeLists.txt.
+ * \endif
+ *
+ * This file exists from 4.6 onward, and can be included as
+ * `<gromacs/version.h>`.  In 4.6, it is also included by
+ * `<gromacs/typedefs.h>, but that header has already moved in 5.0.
+ *
+ * This header defines two values, the \Gromacs version, and the API version.
+ * The versions are in numerical form, where, for example, version
+ * 4.6.1 would be 40601.
+ *
+ * The API version is defined in ::GMX_API_VERSION, and denotes the
+ * version of the programmer interface, i.e. the installed header files
+ * and compatible library.
+ *
+ * Programs written against the \Gromacs library can use this file
+ * to provide some backward compatibility even though parts of the API
+ * change.  For example:
+ * \code
+   #include <gromacs/version.h>
+   #if (GMX_API_VERSION < 50000)
+       .... <do pre-5.0 stuff>
+   #else
+       .... <do post-5.0 stuff>
+   #endif
+   \endcode
+ * where version.h is included directly. For code that must be compatible
+ * between 4.5 and 4.6, an interim solution is to include typedefs.h, which
+ * includes this file:
+ * \code
+   #include <gromacs/typedefs.h>
+   #if !defined(GMX_API_VERSION) || (GMX_API_VERSION < 40600)
+       ....  <do 4.5 specific stuff>
+   #elif (GMX_API_VERSION < 40700)
+       ....  <do 4.6 specific stuff>
+   #endif
+   \endcode
+ *
+ * \inpublicapi
+ */
+#ifndef GMX_VERSION_H
+#define GMX_VERSION_H
+
+/*! \brief
+ * API version of this set of \Gromacs headers.
+ *
+ * If there are multiple versions of \Gromacs that work with the same set of
+ * headers, then this version is not updated between the versions, even though
+ * ::GMX_VERSION is.
+ * For 4.6 and 5.0 (and likely for some time in the future as well), this
+ * tracks the exact \Gromacs version.
+ */
+#define GMX_API_VERSION @GMX_API_VERSION@
+
+/*! \brief
+ * Exact \Gromacs version of this set of headers.
+ *
+ * This specifies the version number of the actual \Gromacs library that
+ * installed these headers.
+ */
+#define GMX_VERSION @GMX_VERSION_NUMERIC@
+
+#endif
index a2ce06596e0417cee6e42789c2fc10e5705b3663..90038702a7bc079afaa5662f2c8fda5f84b033f4 100644 (file)
@@ -120,6 +120,11 @@ gmx_target_compile_options(nblib)
 target_link_libraries(nblib PRIVATE libgromacs)
 target_include_directories(nblib PRIVATE ${PROJECT_SOURCE_DIR}/api)
 include_directories(BEFORE ${CMAKE_SOURCE_DIR}/api)
+target_link_libraries(nblib PRIVATE common)
+# There are transitive dependencies on the legacy GROMACS headers.
+target_link_libraries(nblib PUBLIC legacy_api)
+# TODO: Explicitly link specific modules.
+target_link_libraries(nblib PRIVATE legacy_modules)
 
 install(TARGETS nblib
         EXPORT nblib
index d49b1d1cb56cb692381338695dfbcdaa24e1ea22..751ed51518d63043fb7b3b06b145b306bd9bf4ca 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,10 +71,18 @@ void GmxForceCalculator::compute(gmx::ArrayRef<const gmx::RVec> coordinateInput,
                                  gmx::ArrayRef<gmx::RVec>       forceOutput)
 {
     // update the coordinates in the backend
-    nbv_->convertCoordinates(gmx::AtomLocality::Local, false, coordinateInput);
+    nbv_->convertCoordinates(gmx::AtomLocality::Local, coordinateInput);
 
-    nbv_->dispatchNonbondedKernel(gmx::InteractionLocality::Local, *interactionConst_, *stepWork_,
-                                  enbvClearFYes, *forcerec_, enerd_.get(), nrnb_.get());
+    nbv_->dispatchNonbondedKernel(
+            gmx::InteractionLocality::Local,
+            *interactionConst_,
+            *stepWork_,
+            enbvClearFYes,
+            forcerec_->shift_vec,
+            enerd_->grpp.energyGroupPairTerms[forcerec_->haveBuckingham ? NonBondedEnergyTerms::BuckinghamSR
+                                                                        : NonBondedEnergyTerms::LJSR],
+            enerd_->grpp.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR],
+            nrnb_.get());
 
     nbv_->atomdata_add_nbat_f_to_f(gmx::AtomLocality::All, forceOutput);
 }
@@ -94,9 +102,18 @@ void GmxForceCalculator::setParticlesOnGrid(gmx::ArrayRef<const int>       parti
 
     const real particleDensity = coordinates.size() / det(legacyBox);
 
-    nbnxn_put_on_grid(nbv_.get(), legacyBox, 0, lowerCorner, upperCorner, nullptr,
-                      { 0, int(coordinates.size()) }, particleDensity, particleInfoAllVdw,
-                      coordinates, 0, nullptr);
+    nbnxn_put_on_grid(nbv_.get(),
+                      legacyBox,
+                      0,
+                      lowerCorner,
+                      upperCorner,
+                      nullptr,
+                      { 0, int(coordinates.size()) },
+                      particleDensity,
+                      particleInfoAllVdw,
+                      coordinates,
+                      0,
+                      nullptr);
 }
 
 } // namespace nblib
index eb95e2fc15d6cfbffe602ad7a02f3f3a4a468820..3baa358e98d0fbe5393606240f53b8f6ec031bf5 100644 (file)
@@ -103,8 +103,8 @@ NbvSetupUtil::NbvSetupUtil() : gmxForceCalculator_(std::make_unique<GmxForceCalc
 void NbvSetupUtil::setExecutionContext(const NBKernelOptions& options)
 {
     // Todo: find a more general way to initialize hardware
-    gmx_omp_nthreads_set(emntPairsearch, options.numOpenMPThreads);
-    gmx_omp_nthreads_set(emntNonbonded, options.numOpenMPThreads);
+    gmx_omp_nthreads_set(ModuleMultiThread::Pairsearch, options.numOpenMPThreads);
+    gmx_omp_nthreads_set(ModuleMultiThread::Nonbonded, options.numOpenMPThreads);
 }
 
 Nbnxm::KernelSetup NbvSetupUtil::getKernelSetup(const NBKernelOptions& options)
@@ -186,23 +186,24 @@ void NbvSetupUtil::setupNbnxmInstance(const size_t numParticleTypes, const NBKer
     Nbnxm::KernelSetup kernelSetup = getKernelSetup(options);
 
     PairlistParams pairlistParams(kernelSetup.kernelType, false, options.pairlistCutoff, false);
-    Nbnxm::GridSet gridSet(PbcType::Xyz, false, nullptr, nullptr, pairlistParams.pairlistType,
-                           false, numThreads, pinPolicy);
-    auto           pairlistSets = std::make_unique<PairlistSets>(pairlistParams, false, 0);
-    auto           pairSearch =
-            std::make_unique<PairSearch>(PbcType::Xyz, false, nullptr, nullptr,
-                                         pairlistParams.pairlistType, false, numThreads, pinPolicy);
-
-    auto atomData = std::make_unique<nbnxn_atomdata_t>(pinPolicy);
-
-    // Needs to be called with the number of unique ParticleTypes
-    nbnxn_atomdata_init(gmx::MDLogger(), atomData.get(), kernelSetup.kernelType, combinationRule,
-                        numParticleTypes, nonbondedParameters_, 1, numThreads);
+    Nbnxm::GridSet gridSet(
+            PbcType::Xyz, false, nullptr, nullptr, pairlistParams.pairlistType, false, numThreads, pinPolicy);
+    auto pairlistSets = std::make_unique<PairlistSets>(pairlistParams, false, 0);
+    auto pairSearch   = std::make_unique<PairSearch>(
+            PbcType::Xyz, false, nullptr, nullptr, pairlistParams.pairlistType, false, numThreads, pinPolicy);
+
+    auto atomData = std::make_unique<nbnxn_atomdata_t>(pinPolicy,
+                                                       gmx::MDLogger(),
+                                                       kernelSetup.kernelType,
+                                                       combinationRule,
+                                                       numParticleTypes,
+                                                       nonbondedParameters_,
+                                                       1,
+                                                       numThreads);
 
     // Put everything together
-    auto nbv = std::make_unique<nonbonded_verlet_t>(std::move(pairlistSets), std::move(pairSearch),
-                                                    std::move(atomData), kernelSetup, nullptr,
-                                                    nullWallcycle);
+    auto nbv = std::make_unique<nonbonded_verlet_t>(
+            std::move(pairlistSets), std::move(pairSearch), std::move(atomData), kernelSetup, nullptr, nullptr);
 
     gmxForceCalculator_->nbv_ = std::move(nbv);
 }
@@ -227,22 +228,26 @@ void NbvSetupUtil::setupStepWorkload(const NBKernelOptions& options)
 
 void NbvSetupUtil::setupInteractionConst(const NBKernelOptions& options)
 {
-    gmxForceCalculator_->interactionConst_->vdwtype      = evdwCUT;
-    gmxForceCalculator_->interactionConst_->vdw_modifier = eintmodPOTSHIFT;
+    gmxForceCalculator_->interactionConst_->vdwtype      = VanDerWaalsType::Cut;
+    gmxForceCalculator_->interactionConst_->vdw_modifier = InteractionModifiers::PotShift;
     gmxForceCalculator_->interactionConst_->rvdw         = options.pairlistCutoff;
 
     switch (options.coulombType)
     {
-        case CoulombType::Pme: gmxForceCalculator_->interactionConst_->eeltype = eelPME; break;
-        case CoulombType::Cutoff: gmxForceCalculator_->interactionConst_->eeltype = eelCUT; break;
+        case CoulombType::Pme:
+            gmxForceCalculator_->interactionConst_->eeltype = CoulombInteractionType::Pme;
+            break;
+        case CoulombType::Cutoff:
+            gmxForceCalculator_->interactionConst_->eeltype = CoulombInteractionType::Cut;
+            break;
         case CoulombType::ReactionField:
-            gmxForceCalculator_->interactionConst_->eeltype = eelRF;
+            gmxForceCalculator_->interactionConst_->eeltype = CoulombInteractionType::RF;
             break;
         case CoulombType::Count: throw InputException("Unsupported electrostatic interaction");
     }
-    gmxForceCalculator_->interactionConst_->coulomb_modifier = eintmodPOTSHIFT;
+    gmxForceCalculator_->interactionConst_->coulomb_modifier = InteractionModifiers::PotShift;
     gmxForceCalculator_->interactionConst_->rcoulomb         = options.pairlistCutoff;
-    // Note: values correspond to ic->coulomb_modifier = eintmodPOTSHIFT
+    // Note: values correspond to ic->coulomb_modifier = InteractionModifiers::PotShift
     gmxForceCalculator_->interactionConst_->dispersion_shift.cpot =
             -1.0 / gmx::power6(gmxForceCalculator_->interactionConst_->rvdw);
     gmxForceCalculator_->interactionConst_->repulsion_shift.cpot =
@@ -250,8 +255,8 @@ void NbvSetupUtil::setupInteractionConst(const NBKernelOptions& options)
 
     // These are the initialized values but we leave them here so that later
     // these can become options.
-    gmxForceCalculator_->interactionConst_->epsilon_r  = 1.0;
-    gmxForceCalculator_->interactionConst_->epsilon_rf = 1.0;
+    gmxForceCalculator_->interactionConst_->epsilon_r                = 1.0;
+    gmxForceCalculator_->interactionConst_->reactionFieldPermitivity = 1.0;
 
     /* Set the Coulomb energy conversion factor */
     if (gmxForceCalculator_->interactionConst_->epsilon_r != 0)
@@ -265,11 +270,12 @@ void NbvSetupUtil::setupInteractionConst(const NBKernelOptions& options)
         gmxForceCalculator_->interactionConst_->epsfac = 0;
     }
 
-    calc_rffac(nullptr, gmxForceCalculator_->interactionConst_->epsilon_r,
-               gmxForceCalculator_->interactionConst_->epsilon_rf,
+    calc_rffac(nullptr,
+               gmxForceCalculator_->interactionConst_->epsilon_r,
+               gmxForceCalculator_->interactionConst_->reactionFieldPermitivity,
                gmxForceCalculator_->interactionConst_->rcoulomb,
-               &gmxForceCalculator_->interactionConst_->k_rf,
-               &gmxForceCalculator_->interactionConst_->c_rf);
+               &gmxForceCalculator_->interactionConst_->reactionFieldCoefficient,
+               &gmxForceCalculator_->interactionConst_->reactionFieldShift);
 
     if (EEL_PME_EWALD(gmxForceCalculator_->interactionConst_->eeltype))
     {
@@ -289,7 +295,7 @@ void NbvSetupUtil::setupForceRec(const matrix& box)
 {
     assert((gmxForceCalculator_->forcerec_ && "Forcerec not initialized"));
     gmxForceCalculator_->forcerec_->nbfp = nonbondedParameters_;
-    snew(gmxForceCalculator_->forcerec_->shift_vec, numShiftVectors);
+    gmxForceCalculator_->forcerec_->shift_vec.resize(numShiftVectors);
     calc_shifts(box, gmxForceCalculator_->forcerec_->shift_vec);
 }
 
@@ -302,8 +308,8 @@ void NbvSetupUtil::constructPairList(ExclusionLists<int> exclusionLists)
 {
     gmx::ListOfLists<int> exclusions(std::move(exclusionLists.ListRanges),
                                      std::move(exclusionLists.ListElements));
-    gmxForceCalculator_->nbv_->constructPairlist(gmx::InteractionLocality::Local, exclusions, 0,
-                                                 gmxForceCalculator_->nrnb_.get());
+    gmxForceCalculator_->nbv_->constructPairlist(
+            gmx::InteractionLocality::Local, exclusions, 0, gmxForceCalculator_->nrnb_.get());
 }
 
 
index f97b01702e55c20d1e1ec886d9708374ac1dba19..461e26ff68dfe276014995d8c22a626bead5d950 100644 (file)
@@ -137,7 +137,8 @@ ParticleTypesInteractions& ParticleTypesInteractions::add(const ParticleTypeName
             std::string message = formatString(
                     "Attempting to add nonbonded interaction parameters between the particle types "
                     "{} {} twice",
-                    particleTypeName1.value(), particleTypeName2.value());
+                    particleTypeName1.value(),
+                    particleTypeName2.value());
             throw InputException(message);
         }
     }
@@ -162,8 +163,8 @@ NonBondedInteractionMap ParticleTypesInteractions::generateTable() const
             C6  c6_combo{ combineNonbondedParameters(c6_1, c6_2, combinationRule_) };
             C12 c12_combo{ combineNonbondedParameters(c12_1, c12_2, combinationRule_) };
 
-            nonbondedParameters_.setInteractions(particleType1.first, particleType2.first, c6_combo,
-                                                 c12_combo);
+            nonbondedParameters_.setInteractions(
+                    particleType1.first, particleType2.first, c6_combo, c12_combo);
         }
     }
 
@@ -194,7 +195,8 @@ NonBondedInteractionMap ParticleTypesInteractions::generateTable() const
             if (nonbondedParameters_.count(interactionKey) == 0)
             {
                 std::string message = formatString("Missing interaction between {} {}",
-                                                   particleTypeName1.value(), particleTypeName2.value());
+                                                   particleTypeName1.value(),
+                                                   particleTypeName2.value());
                 throw InputException(message);
             }
         }
@@ -216,7 +218,9 @@ void ParticleTypesInteractions::merge(const ParticleTypesInteractions& other)
 
     for (const auto& keyval : other.twoParticlesInteractionsMap_)
     {
-        add(std::get<0>(keyval.first), std::get<1>(keyval.first), std::get<0>(keyval.second),
+        add(std::get<0>(keyval.first),
+            std::get<1>(keyval.first),
+            std::get<0>(keyval.second),
             std::get<1>(keyval.second));
     }
 }
index 22250f0f323c6d6b285f30044931d6424b373b3a..c26fb10acb05c4f436858e8f650a1155bcf9b006 100644 (file)
@@ -114,8 +114,8 @@ void testThreeParameterBondLessThan([[maybe_unused]] const B& deduceType)
 
 TEST(NBlibTest, BondTypesOperatorEqualWorks)
 {
-    auto bondList3 = std::make_tuple(HarmonicBondType(), G96BondType(), FENEBondType(),
-                                     HalfAttractiveQuarticBondType());
+    auto bondList3 = std::make_tuple(
+            HarmonicBondType(), G96BondType(), FENEBondType(), HalfAttractiveQuarticBondType());
     for_each_tuple([](const auto& b) { test_detail::testTwoParameterBondEquality(b); }, bondList3);
 
     auto bondList4 = std::make_tuple(CubicBondType(), MorseBondType());
@@ -124,8 +124,8 @@ TEST(NBlibTest, BondTypesOperatorEqualWorks)
 
 TEST(NBlibTest, BondTypesLessThanWorks)
 {
-    auto bondList3 = std::make_tuple(HarmonicBondType(), G96BondType(), FENEBondType(),
-                                     HalfAttractiveQuarticBondType());
+    auto bondList3 = std::make_tuple(
+            HarmonicBondType(), G96BondType(), FENEBondType(), HalfAttractiveQuarticBondType());
     for_each_tuple([](const auto& b) { test_detail::testTwoParameterBondLessThan(b); }, bondList3);
 
     auto bondList4 = std::make_tuple(CubicBondType(), MorseBondType());
index 247f926208f1a9353dda0b289377b35aa3923f8f..fe0c107cd5ff3b372ad6aef7ce783df312f13487 100644 (file)
@@ -83,7 +83,9 @@ void compareVectors(const TestSeq&                    forces,
         for (int m = 0; m < dimSize; ++m)
         {
             EXPECT_FLOAT_DOUBLE_EQ_TOL(
-                    forces[i][m], refForcesFloat[i][m], refForcesDouble[i][m],
+                    forces[i][m],
+                    refForcesFloat[i][m],
+                    refForcesDouble[i][m],
                     // Todo: why does the tolerance need to be so low?
                     gmx::test::relativeToleranceAsFloatingPoint(refForcesDouble[i][m], 5e-5));
         }
@@ -182,7 +184,8 @@ void compareArray(const ListedForceCalculator::EnergyType& energies,
 {
     for (size_t i = 0; i < energies.size(); ++i)
     {
-        EXPECT_REAL_EQ_TOL(energies[i], refEnergies[i],
+        EXPECT_REAL_EQ_TOL(energies[i],
+                           refEnergies[i],
                            gmx::test::relativeToleranceAsFloatingPoint(refEnergies[i], 1e-5));
     }
 }
index 917d84be5984023a220985a3e3f75237cdcea286..87f16ff9f04e1848067021646d36dc8263e53e42 100644 (file)
@@ -131,8 +131,8 @@ TEST(NBlibTest, ListedForceBuffer)
     {
         for (size_t m = 0; m < dimSize; ++m)
         {
-            EXPECT_REAL_EQ_TOL(refMasterBuffer[i][m], masterBuffer[i][m],
-                               gmx::test::defaultRealTolerance());
+            EXPECT_REAL_EQ_TOL(
+                    refMasterBuffer[i][m], masterBuffer[i][m], gmx::test::defaultRealTolerance());
         }
     }
 
index f16970ada2590f2af8153b9f9adc858f5999ca30..f6e92ac86864b7fb1b149e01c0601d24c2cda6ca 100644 (file)
@@ -57,7 +57,8 @@ void sortInteractions(ListedInteractionData& interactions)
         using InteractionContainerType = std::decay_t<decltype(interactionElement)>;
         using InteractionType          = typename InteractionContainerType::type;
 
-        std::sort(begin(interactionElement.indices), end(interactionElement.indices),
+        std::sort(begin(interactionElement.indices),
+                  end(interactionElement.indices),
                   interactionSortKey<InteractionType>);
     };
 
index db3772039a35d67137c4a3959b806e369d3faa93..9b243bf6cdae5430f6a29b5b01a85e19a50ffbe5 100644 (file)
@@ -145,8 +145,11 @@ void Molecule::addInteraction(const ParticleIdentifier&   particleI,
                              + name_.value());
     }
 
-    addInteractionImpl(interaction, particleI.particleName(), residueName(particleI),
-                       particleJ.particleName(), residueName(particleJ));
+    addInteractionImpl(interaction,
+                       particleI.particleName(),
+                       residueName(particleI),
+                       particleJ.particleName(),
+                       residueName(particleJ));
 }
 
 void Molecule::addInteraction(const ParticleIdentifier&     particleI,
@@ -161,8 +164,12 @@ void Molecule::addInteraction(const ParticleIdentifier&     particleI,
                              + name_.value());
     }
 
-    addInteractionImpl(interaction, particleI.particleName(), residueName(particleI),
-                       particleJ.particleName(), residueName(particleJ), particleK.particleName(),
+    addInteractionImpl(interaction,
+                       particleI.particleName(),
+                       residueName(particleI),
+                       particleJ.particleName(),
+                       residueName(particleJ),
+                       particleK.particleName(),
                        residueName(particleK));
 }
 
@@ -179,9 +186,15 @@ void Molecule::addInteraction(const ParticleIdentifier&    particleI,
                              + name_.value());
     }
 
-    addInteractionImpl(interaction, particleI.particleName(), residueName(particleI),
-                       particleJ.particleName(), residueName(particleJ), particleK.particleName(),
-                       residueName(particleK), particleL.particleName(), residueName(particleL));
+    addInteractionImpl(interaction,
+                       particleI.particleName(),
+                       residueName(particleI),
+                       particleJ.particleName(),
+                       residueName(particleJ),
+                       particleK.particleName(),
+                       residueName(particleK),
+                       particleL.particleName(),
+                       residueName(particleL));
 }
 
 void Molecule::addInteraction(const ParticleIdentifier&    particleI,
@@ -198,10 +211,17 @@ void Molecule::addInteraction(const ParticleIdentifier&    particleI,
                              + name_.value());
     }
 
-    addInteractionImpl(interaction, particleI.particleName(), residueName(particleI),
-                       particleJ.particleName(), residueName(particleJ), particleK.particleName(),
-                       residueName(particleK), particleL.particleName(), residueName(particleL),
-                       particleM.particleName(), residueName(particleM));
+    addInteractionImpl(interaction,
+                       particleI.particleName(),
+                       residueName(particleI),
+                       particleJ.particleName(),
+                       residueName(particleJ),
+                       particleK.particleName(),
+                       residueName(particleK),
+                       particleL.particleName(),
+                       residueName(particleL),
+                       particleM.particleName(),
+                       residueName(particleM));
 }
 
 
@@ -218,7 +238,8 @@ void Molecule::addExclusion(const ParticleIdentifier& particle, const ParticleId
     }
 
     // duplication for the swapped pair happens in getExclusions()
-    exclusionsByName_.emplace_back(std::make_tuple(particle.particleName(), residueName(particle),
+    exclusionsByName_.emplace_back(std::make_tuple(particle.particleName(),
+                                                   residueName(particle),
                                                    particleToExclude.particleName(),
                                                    residueName(particleToExclude)));
 }
@@ -280,8 +301,10 @@ std::vector<std::tuple<int, int>> Molecule::getExclusions() const
         const std::string& residueName2  = std::get<3>(tup);
 
         // look up first index (binary search)
-        auto it1 = std::lower_bound(std::begin(indexKey), std::end(indexKey),
-                                    std::make_tuple(particleName1, residueName2, 0), sortKey);
+        auto it1 = std::lower_bound(std::begin(indexKey),
+                                    std::end(indexKey),
+                                    std::make_tuple(particleName1, residueName2, 0),
+                                    sortKey);
 
         // make sure we have the (particleName,residueName) combo
         if (it1 == std::end(indexKey) or std::get<0>(*it1) != particleName1 or std::get<1>(*it1) != residueName1)
@@ -294,8 +317,10 @@ std::vector<std::tuple<int, int>> Molecule::getExclusions() const
         int firstIndex = std::get<2>(*it1);
 
         // look up second index (binary search)
-        auto it2 = std::lower_bound(std::begin(indexKey), std::end(indexKey),
-                                    std::make_tuple(particleName2, residueName2, 0), sortKey);
+        auto it2 = std::lower_bound(std::begin(indexKey),
+                                    std::end(indexKey),
+                                    std::make_tuple(particleName2, residueName2, 0),
+                                    sortKey);
 
         // make sure we have the (particleName,residueName) combo
         if (it2 == std::end(indexKey) or std::get<0>(*it2) != particleName2 or std::get<1>(*it2) != residueName2)
index fb97ac298e2245bdfb1ad191bd20cf19a6f88d59..7bb98bed165eaf963b75cd4cdf9ffa7eb4e628c7 100644 (file)
@@ -65,12 +65,15 @@ int ParticleSequencer::operator()(const MoleculeName& moleculeName,
         // TODO: use string format function once we have it
         if (moleculeName.value() == residueName.value())
         {
-            printf("No particle %s in residue %s in molecule %s found\n", particleName.value().c_str(),
-                   residueName.value().c_str(), moleculeName.value().c_str());
+            printf("No particle %s in residue %s in molecule %s found\n",
+                   particleName.value().c_str(),
+                   residueName.value().c_str(),
+                   moleculeName.value().c_str());
         }
         else
         {
-            printf("No particle %s in molecule %s found\n", particleName.value().c_str(),
+            printf("No particle %s in molecule %s found\n",
+                   particleName.value().c_str(),
                    moleculeName.value().c_str());
         }
 
index b54996d6af04f5138c8203653601e9d3c62cabc6..75416ea5df2a53a71950168cace5b1952346077d 100644 (file)
@@ -119,17 +119,23 @@ int main()
     gmx::ArrayRef<nblib::Vec3> userForces(simState.forces());
     forceCalculator.compute(simState.coordinates(), userForces);
     // Print some diagnostic info
-    printf("  final forces on particle 0: x %4f y %4f z %4f\n", userForces[0][0], userForces[0][1],
+    printf("  final forces on particle 0: x %4f y %4f z %4f\n",
+           userForces[0][0],
+           userForces[0][1],
            userForces[0][2]);
     // User may modify forces stored in simState.forces() if needed
     // Print some diagnostic info
-    printf("initial position of particle 0: x %4f y %4f z %4f\n", simState.coordinates()[0][0],
-           simState.coordinates()[0][1], simState.coordinates()[0][2]);
+    printf("initial position of particle 0: x %4f y %4f z %4f\n",
+           simState.coordinates()[0][0],
+           simState.coordinates()[0][1],
+           simState.coordinates()[0][2]);
     // Integrate with a time step of 1 fs
     integrator.integrate(1.0, simState.coordinates(), simState.velocities(), simState.forces());
     // Print some diagnostic info
 
-    printf("  final position of particle 0: x %4f y %4f z %4f\n", simState.coordinates()[0][0],
-           simState.coordinates()[0][1], simState.coordinates()[0][2]);
+    printf("  final position of particle 0: x %4f y %4f z %4f\n",
+           simState.coordinates()[0][0],
+           simState.coordinates()[0][1],
+           simState.coordinates()[0][2]);
     return 0;
 }
index a54839cd4c670814e05873d0ae8514ee5724f2f6..e574fea72e516a2c3c57a99a92f99f22bbae4c08 100644 (file)
@@ -180,16 +180,18 @@ int main()
     ForceCalculator forceCalculator(simulationState, options);
 
     // The listed force calculator is also initialized with the required arguments
-    ListedForceCalculator listedForceCalculator(topology.getInteractionData(),
-                                                topology.numParticles(), 4, box);
+    ListedForceCalculator listedForceCalculator(
+            topology.getInteractionData(), topology.numParticles(), 4, box);
 
     // Integrator is initialized with an array of inverse masses (constructed from topology) and
     // the bounding box
     LeapFrog integrator(topology, box);
 
     // Print some diagnostic info
-    printf("initial position of particle 0: x %4f y %4f z %4f\n", simulationState.coordinates()[0][0],
-           simulationState.coordinates()[0][1], simulationState.coordinates()[0][2]);
+    printf("initial position of particle 0: x %4f y %4f z %4f\n",
+           simulationState.coordinates()[0][0],
+           simulationState.coordinates()[0][1],
+           simulationState.coordinates()[0][2]);
 
     // MD Loop
     int numSteps = 2;
@@ -203,12 +205,14 @@ int main()
         listedForceCalculator.compute(simulationState.coordinates(), simulationState.forces());
 
         // Integrate with a time step of 1 fs, positions, velocities and forces
-        integrator.integrate(1.0, simulationState.coordinates(), simulationState.velocities(),
-                             simulationState.forces());
+        integrator.integrate(
+                1.0, simulationState.coordinates(), simulationState.velocities(), simulationState.forces());
     }
 
-    printf("  final position of particle 9: x %4f y %4f z %4f\n", simulationState.coordinates()[9][0],
-           simulationState.coordinates()[9][1], simulationState.coordinates()[9][2]);
+    printf("  final position of particle 9: x %4f y %4f z %4f\n",
+           simulationState.coordinates()[9][0],
+           simulationState.coordinates()[9][1],
+           simulationState.coordinates()[9][2]);
 
     return 0;
 } // main
index e474d015089c0d57c62b1002a07c70210fc20da4..bd5d2d8595da97e1bbaf65c2ad7a9935c1ba9c76 100644 (file)
@@ -46,6 +46,7 @@
 #include <vector>
 
 #include "gromacs/pbcutil/pbc.h"
+#include "gromacs/utility/arrayref.h"
 #include "nblib/exception.h"
 #include "nblib/simulationstate.h"
 #include "nblib/simulationstateimpl.h"
index 23b9efc0531d8258fdf6cf3932a5e6b1372d837d..33d34e58c7b65a87539f2bc5f79c607ddd35c4a2 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2020, by the GROMACS development team, led by
+# Copyright (c) 2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,9 @@ gmx_add_unit_test_library(nblib_test_infrastructure
     )
 target_include_directories(nblib_test_infrastructure PRIVATE ${PROJECT_SOURCE_DIR}/api)
 target_include_directories(nblib_test_infrastructure SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/src/external)
+target_link_libraries(nblib_test_infrastructure PRIVATE legacy_api)
+# TODO: Explicitly link specific modules: math,
+target_link_libraries(nblib_test_infrastructure PRIVATE legacy_modules)
 
 set(testname "NbLibSetupTests")
 set(exename "nblib-setup-test")
index 52ba075b1382e21a1427df73834798fc7d4ba49b..fb484557d3200d4b49daf3fff24640a95fbde3da 100644 (file)
@@ -44,6 +44,7 @@
  */
 #include "nblib/integrator.h"
 #include "gromacs/pbcutil/pbc.h"
+#include "gromacs/utility/arrayref.h"
 #include "nblib/molecules.h"
 #include "nblib/particletype.h"
 #include "nblib/simulationstate.h"
@@ -113,15 +114,21 @@ TEST(NBlibTest, IntegratorWorks)
                         << formatString(
                                    "Coordinate {} of atom {} is different from analytical solution "
                                    "at step {}.",
-                                   d, i, step);
+                                   d,
+                                   i,
+                                   step);
 
                 EXPECT_REAL_EQ_TOL(vAnalytical[d], simulationState.velocities()[i][d], tolerance)
                         << formatString(
                                    "Velocity component {} of atom {} is different from analytical "
                                    "solution at step {}.",
-                                   d, i, step);
+                                   d,
+                                   i,
+                                   step);
             }
-            integrator.integrate(dt, simulationState.coordinates(), simulationState.velocities(),
+            integrator.integrate(dt,
+                                 simulationState.coordinates(),
+                                 simulationState.velocities(),
                                  simulationState.forces());
         }
     }
index bb93f5dfd3d7f5493e134ace3de65dfd2b2dcd6a..ca6a950d039fc88abab32b0a191fbe8dbad915d4 100644 (file)
@@ -87,18 +87,22 @@ TEST(NBlibTest, NonBondedForceParamsCorrect)
     EXPECT_REAL_EQ_TOL(c12_1, nbfp.getC12(atom1.name(), atom1.name()), gmx::test::defaultRealTolerance());
 
     //! geometric comb rule for c6
-    EXPECT_REAL_EQ_TOL(std::sqrt(c6_1 * c6_2), nbfp.getC6(atom1.name(), atom2.name()),
+    EXPECT_REAL_EQ_TOL(std::sqrt(c6_1 * c6_2),
+                       nbfp.getC6(atom1.name(), atom2.name()),
                        gmx::test::defaultRealTolerance());
     //! + symmetric pair
-    EXPECT_REAL_EQ_TOL(std::sqrt(c6_1 * c6_2), nbfp.getC6(atom2.name(), atom1.name()),
+    EXPECT_REAL_EQ_TOL(std::sqrt(c6_1 * c6_2),
+                       nbfp.getC6(atom2.name(), atom1.name()),
                        gmx::test::defaultRealTolerance());
 
     //! geometric comb rule for c12
-    EXPECT_REAL_EQ_TOL(std::sqrt(c12_1 * c12_2), nbfp.getC12(atom1.name(), atom2.name()),
+    EXPECT_REAL_EQ_TOL(std::sqrt(c12_1 * c12_2),
+                       nbfp.getC12(atom1.name(), atom2.name()),
                        gmx::test::defaultRealTolerance());
 
     //! + symmetric par
-    EXPECT_REAL_EQ_TOL(std::sqrt(c12_1 * c12_2), nbfp.getC12(atom2.name(), atom1.name()),
+    EXPECT_REAL_EQ_TOL(std::sqrt(c12_1 * c12_2),
+                       nbfp.getC12(atom2.name(), atom1.name()),
                        gmx::test::defaultRealTolerance());
 
     //! explicit pairwise interaction c6
@@ -106,10 +110,10 @@ TEST(NBlibTest, NonBondedForceParamsCorrect)
     EXPECT_REAL_EQ_TOL(c6comb, nbfp.getC6(atom3.name(), atom2.name()), gmx::test::defaultRealTolerance());
 
     //! explicit pairwise interaction c12
-    EXPECT_REAL_EQ_TOL(c12comb, nbfp.getC12(atom2.name(), atom3.name()),
-                       gmx::test::defaultRealTolerance());
-    EXPECT_REAL_EQ_TOL(c12comb, nbfp.getC12(atom3.name(), atom2.name()),
-                       gmx::test::defaultRealTolerance());
+    EXPECT_REAL_EQ_TOL(
+            c12comb, nbfp.getC12(atom2.name(), atom3.name()), gmx::test::defaultRealTolerance());
+    EXPECT_REAL_EQ_TOL(
+            c12comb, nbfp.getC12(atom3.name(), atom2.name()), gmx::test::defaultRealTolerance());
 
     ParticleType atom4(ParticleTypeName("a4"), Mass(1));
     interactions.add(atom3.name(), atom4.name(), C6(1), C12(2));
@@ -160,14 +164,16 @@ TEST(NBlibTest, CanMergeInteractions)
 
     auto nbfp = interactions.generateTable();
 
-    EXPECT_REAL_EQ_TOL(std::sqrt(c6_3 * c6_4), nbfp.getC6(atom3.name(), atom4.name()),
-                       gmx::test::defaultRealTolerance());
-    EXPECT_REAL_EQ_TOL(std::sqrt(c12_3 * c12_4), nbfp.getC12(atom3.name(), atom4.name()),
-                       gmx::test::defaultRealTolerance());
-    EXPECT_REAL_EQ_TOL(c6_override, nbfp.getC6(atom4.name(), atom5.name()),
+    EXPECT_REAL_EQ_TOL(std::sqrt(c6_3 * c6_4),
+                       nbfp.getC6(atom3.name(), atom4.name()),
                        gmx::test::defaultRealTolerance());
-    EXPECT_REAL_EQ_TOL(c12_override, nbfp.getC12(atom4.name(), atom5.name()),
+    EXPECT_REAL_EQ_TOL(std::sqrt(c12_3 * c12_4),
+                       nbfp.getC12(atom3.name(), atom4.name()),
                        gmx::test::defaultRealTolerance());
+    EXPECT_REAL_EQ_TOL(
+            c6_override, nbfp.getC6(atom4.name(), atom5.name()), gmx::test::defaultRealTolerance());
+    EXPECT_REAL_EQ_TOL(
+            c12_override, nbfp.getC12(atom4.name(), atom5.name()), gmx::test::defaultRealTolerance());
 }
 
 } // namespace
index c3ec7d9b0263a23e1168855bd20afa1967aebbf0..ca1524675ec330d8454a8a95ac6fcea4b2a8d345 100644 (file)
@@ -117,8 +117,8 @@ TEST(NBlibTest, CanIntegrateSystem)
     {
         gmx::ArrayRef<Vec3> forces(simState.forces());
         forceCalculator.compute(simState.coordinates(), simState.forces());
-        EXPECT_NO_THROW(integrator.integrate(1.0, simState.coordinates(), simState.velocities(),
-                                             simState.forces()));
+        EXPECT_NO_THROW(integrator.integrate(
+                1.0, simState.coordinates(), simState.velocities(), simState.forces()));
     }
 }
 
index 1d1d0a78a638b240d4f53a76e8ddf37acb352278..2bedef8887ecc158f0d914c1d4c023be3c06be21 100644 (file)
@@ -180,8 +180,8 @@ Topology WaterTopologyBuilder::buildTopology(int numMolecules)
     std::vector<std::string>  typeNames = { "Ow", "H" };
     for (const auto& name : typeNames)
     {
-        interactions.add(ParticleTypeName(name), library.c6(ParticleName(name)),
-                         library.c12(ParticleName(name)));
+        interactions.add(
+                ParticleTypeName(name), library.c6(ParticleName(name)), library.c12(ParticleName(name)));
     }
 
     // Add some molecules to the topology
@@ -208,8 +208,8 @@ Topology SpcMethanolTopologyBuilder::buildTopology(int numWater, int numMethanol
     std::vector<std::string>  typeNames = { "Ow", "H", "OMet", "CMet" };
     for (const auto& name : typeNames)
     {
-        interactions.add(ParticleTypeName(name), library.c6(ParticleName(name)),
-                         library.c12(ParticleName(name)));
+        interactions.add(
+                ParticleTypeName(name), library.c6(ParticleName(name)), library.c12(ParticleName(name)));
     }
 
     // Add some molecules to the topology
@@ -239,8 +239,8 @@ ArgonTopologyBuilder::ArgonTopologyBuilder(const int& numParticles)
     ParticleLibrary library;
 
     ParticleTypesInteractions nbinteractions;
-    nbinteractions.add(ParticleTypeName("Ar"), library.c6(ParticleName("Ar")),
-                       library.c12(ParticleName("Ar")));
+    nbinteractions.add(
+            ParticleTypeName("Ar"), library.c6(ParticleName("Ar")), library.c12(ParticleName("Ar")));
 
     Molecule argonMolecule(MoleculeName("AR"));
     argonMolecule.addParticle(ParticleName("AR"), library.type("Ar"));
index 1d1d9ab6e25eafbe2bb41a520b433b65c9640dcd..ff4d0336d929edc9eaa0e3c2af468a7d70628dfa 100644 (file)
@@ -188,12 +188,10 @@ TEST(NBlibTest, TopologyHasSequencing)
     WaterTopologyBuilder waters;
     Topology             watersTopology = waters.buildTopology(2);
 
-    EXPECT_EQ(0, watersTopology.sequenceID(MoleculeName("SOL"), 0, ResidueName("SOL"),
-                                           ParticleName("Oxygen")));
+    EXPECT_EQ(0, watersTopology.sequenceID(MoleculeName("SOL"), 0, ResidueName("SOL"), ParticleName("Oxygen")));
     EXPECT_EQ(1, watersTopology.sequenceID(MoleculeName("SOL"), 0, ResidueName("SOL"), ParticleName("H1")));
     EXPECT_EQ(2, watersTopology.sequenceID(MoleculeName("SOL"), 0, ResidueName("SOL"), ParticleName("H2")));
-    EXPECT_EQ(3, watersTopology.sequenceID(MoleculeName("SOL"), 1, ResidueName("SOL"),
-                                           ParticleName("Oxygen")));
+    EXPECT_EQ(3, watersTopology.sequenceID(MoleculeName("SOL"), 1, ResidueName("SOL"), ParticleName("Oxygen")));
     EXPECT_EQ(4, watersTopology.sequenceID(MoleculeName("SOL"), 1, ResidueName("SOL"), ParticleName("H1")));
     EXPECT_EQ(5, watersTopology.sequenceID(MoleculeName("SOL"), 1, ResidueName("SOL"), ParticleName("H2")));
 }
@@ -211,7 +209,9 @@ TEST(NBlibTest, TopologyCanAggregateBonds)
 
     std::vector<HarmonicBondType> bondsTest;
     // use the expansionArray (bondsExpansion) to expand to the full list if bonds
-    std::transform(begin(bondsExpansion), end(bondsExpansion), std::back_inserter(bondsTest),
+    std::transform(begin(bondsExpansion),
+                   end(bondsExpansion),
+                   std::back_inserter(bondsTest),
                    [&bonds](size_t i) { return bonds[i]; });
 
     std::vector<HarmonicBondType> waterBonds =
@@ -355,8 +355,8 @@ TEST(NBlibTest, TopologyListedInteractions)
 #undef SORT
     /// \endcond
 
-    EXPECT_TRUE(std::equal(begin(interactions_reference), end(interactions_reference),
-                           begin(interactions_test)));
+    EXPECT_TRUE(std::equal(
+            begin(interactions_reference), end(interactions_reference), begin(interactions_test)));
 }
 
 TEST(NBlibTest, TopologyListedInteractionsMultipleTypes)
@@ -407,8 +407,9 @@ TEST(NBlibTest, TopologyListedInteractionsMultipleTypes)
     int MeH1 = topology.sequenceID(MoleculeName("MeOH"), 0, ResidueName("MeOH"), ParticleName("H3"));
 
     std::vector<CubicBondType>                   cubicBondsReference{ testBond };
-    std::vector<InteractionIndex<CubicBondType>> cubicIndicesReference{ { std::min(H1, H2),
-                                                                          std::max(H1, H2), 0 } };
+    std::vector<InteractionIndex<CubicBondType>> cubicIndicesReference{
+        { std::min(H1, H2), std::max(H1, H2), 0 }
+    };
     EXPECT_EQ(cubicBondsReference, cubicBonds.parameters);
     EXPECT_EQ(cubicIndicesReference, cubicBonds.indices);
 
index b55eaa03710388ca2048d37eb68703c17e3cfe01..acaea4999f2a25cce5fc775f78aa112c10122f55 100644 (file)
@@ -86,7 +86,8 @@ ExclusionLists<int> TopologyBuilder::createExclusionsLists() const
         {
             auto offsetExclusions = offsetGmxBlock(exclusionBlockPerMolecule, particleNumberOffset);
 
-            std::copy(std::begin(offsetExclusions), std::end(offsetExclusions),
+            std::copy(std::begin(offsetExclusions),
+                      std::end(offsetExclusions),
                       std::back_inserter(exclusionBlockGlobal));
 
             particleNumberOffset += molecule.numParticlesInMolecule();
@@ -134,7 +135,9 @@ ListedInteractionData TopologyBuilder::createInteractionData(const ParticleSeque
 
         // combine stage 1 + 2 expansion arrays
         std::vector<size_t> expansionArray(expansionArrayStage1.size());
-        std::transform(begin(expansionArrayStage1), end(expansionArrayStage1), begin(expansionArray),
+        std::transform(begin(expansionArrayStage1),
+                       end(expansionArrayStage1),
+                       begin(expansionArray),
                        [& S2 = expansionArrayStage2](size_t S1Element) { return S2[S1Element]; });
 
         // add data about InteractionType instances
@@ -144,7 +147,9 @@ ListedInteractionData TopologyBuilder::createInteractionData(const ParticleSeque
         // coordinateIndices contains the particle sequence IDs of all interaction coordinates of type <BondType>
         auto coordinateIndices = detail::sequenceIDs<InteractionType>(this->molecules_, particleSequencer);
         // zip coordinateIndices(i,j,...) + expansionArray(k) -> interactionDataElement.indices(i,j,...,k)
-        std::transform(begin(coordinateIndices), end(coordinateIndices), begin(expansionArray),
+        std::transform(begin(coordinateIndices),
+                       end(coordinateIndices),
+                       begin(expansionArray),
                        begin(interactionDataElement.indices),
                        [](auto coordinateIndex, auto interactionIndex) {
                            std::array<int, coordinateIndex.size() + 1> ret{ 0 };
@@ -236,7 +241,8 @@ Topology TopologyBuilder::buildTopology()
             {
                 std::string message =
                         formatString("Missing nonbonded interaction parameters for pair {} {}",
-                                     particleType1.first, particleType2.first);
+                                     particleType1.first,
+                                     particleType2.first);
                 throw InputException(message);
             }
         }
index 1cad0bbcca40ce4d5596657599b16165e9a7b86a..0bb283b171ef1f0f9564d9bdaed892efcf0e968d 100644 (file)
@@ -96,8 +96,10 @@ std::vector<gmx::ExclusionBlock> offsetGmxBlock(std::vector<gmx::ExclusionBlock>
     // shift particle numbers by offset
     for (auto& localBlock : inBlock)
     {
-        std::transform(std::begin(localBlock.atomNumber), std::end(localBlock.atomNumber),
-                       std::begin(localBlock.atomNumber), [offset](auto i) { return i + offset; });
+        std::transform(std::begin(localBlock.atomNumber),
+                       std::end(localBlock.atomNumber),
+                       std::begin(localBlock.atomNumber),
+                       [offset](auto i) { return i + offset; });
     }
 
     return inBlock;
index 9aa85bc3b484379a5128b5cae985078d3d4808f0..a6521e9cccec601832120ff2d5691ad8aa0808f8 100644 (file)
@@ -99,7 +99,8 @@ static std::vector<Vec3> low_mspeed(real tempi, std::vector<real> const& masses,
         fprintf(debug,
                 "Velocities were taken from a Maxwell distribution\n"
                 "Initial generated temperature: %12.5e (scaled to: %12.5e)\n",
-                temp, tempi);
+                temp,
+                tempi);
     }
 
     return velocities;
index 25c1038a6a330c0ef1af8680f63f45015d0c3a8e..f1f8684c93388729075d057093ab98bd25710750 100644 (file)
@@ -128,10 +128,6 @@ if(NEED_TO_FIND_GPLUSPLUS)
             message(FATAL_ERROR "${GMX_GPLUSPLUS_PATH}/include/c++ doesn't exist even though it should. "
                 "Please report to developers.")
         endif()
-    else() #Intel
-        if (${GMX_GPLUSPLUS_VERSION} VERSION_GREATER_EQUAL 7 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19)
-            message(FATAL_ERROR "ICC versions below 19 don't support GCC versions above 6.")
-        endif ()
     endif()
 
     # Set up to use the libstdc++ from that g++. Note that we checked
@@ -139,8 +135,6 @@ if(NEED_TO_FIND_GPLUSPLUS)
     # we will not override any user settings here.
     if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "IntelLLVM")
         set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --gcc-toolchain=${GMX_GPLUSPLUS_PATH}")
-    else() #Intel
-        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -gcc-name=${GMX_GPLUSPLUS_PATH}")
     endif()
 endif()
 
index 4f9b3ecee87013040fe45298070b18fbbcfa1ab6..61370821af76e9034076a389ac8419584c18881b 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2016,2018, by the GROMACS development team, led by
+# Copyright (c) 2016,2018,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -97,10 +97,8 @@ mark_as_advanced(LMFIT_INCLUDE_DIR LMFIT_LIBRARY)
 # library built in the main project.
 if (LMFIT_FOUND)
     add_library(lmfit INTERFACE IMPORTED)
-    set_target_properties(lmfit PROPERTIES
-        INTERFACE_INCLUDE_DIRECTORIES "${LMFIT_INCLUDE_DIR}"
-        INTERFACE_LINK_LIBRARIES "${LMFIT_LIBRARY}"
-        )
+    target_link_libraries(lmfit INTERFACE "${LMFIT_LIBRARY}")
+    target_include_directories(lmfit SYSTEM BEFORE INTERFACE "${LMFIT_INCLUDE_DIR}")
 endif()
 
 cmake_pop_check_state()
index a13470d8bf94a2b00a84518a23260214d2f2cbf3..ea66f2b50a806decc771177bf32fa115f2978515 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2018, by the GROMACS development team, led by
+# Copyright (c) 2018,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,12 +88,7 @@ mark_as_advanced(clFFT_ROOT_DIR clFFT_LIBRARY clFFT_INCLUDE_DIR)
 # that was found was actually built in this project.
 if(clFFT_FOUND)
     add_library(clFFT INTERFACE IMPORTED)
-    # When we depend on cmake 3.11, this work-around (specific to
-    # imported targets) can be done more simply by using the normal
-    # target_include_directories() and target_link_libraries()
-    set_target_properties(clFFT PROPERTIES
-        INTERFACE_INCLUDE_DIRECTORIES "${clFFT_INCLUDE_DIR}"
-        INTERFACE_LINK_LIBRARIES "${clFFT_LIBRARY};${CMAKE_DL_LIBS}"
-        )
+    target_link_libraries(clFFT INTERFACE "${clFFT_LIBRARY}" "${CMAKE_DL_LIBS}")
+    target_include_directories(clFFT SYSTEM BEFORE INTERFACE "${clFFT_INCLUDE_DIR}")
 endif()
 
diff --git a/cmake/TestFujitsuSparc64.cpp b/cmake/TestFujitsuSparc64.cpp
deleted file mode 100644 (file)
index 0740688..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-int main()
-{
-#if defined (__FUJITSU) && ( defined(__sparc) || defined(__sparcv9) ) && ( defined(__LP64__) || defined(__arch64) )
-    return 0;
-#else
-#error This compiler is not targetting Fujitsu Sparc64
-#endif
-}
diff --git a/cmake/TestMIC.cpp b/cmake/TestMIC.cpp
deleted file mode 100644 (file)
index c03a61b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-int main()
-{
-#ifdef __MIC__
-    return 0;
-#else
-#error This compiler is not targetting MIC
-#endif
-}
index c0847c429e7f7eabd9e8c5b5cf3daac4f55fcac7..a013fb164a1dee50eb2fe629e13111084485d4d4 100644 (file)
@@ -220,10 +220,6 @@ MACRO(TMPI_GET_SOURCE_LIST SRC_VARIABLE SRC_ROOT)
         list(APPEND ${SRC_VARIABLE} ${SRC_ROOT}/winthreads.cpp)
     endif ()
 
-    if (TMPI_CXX_LIB)
-        list(APPEND ${SRC_VARIABLE} ${SRC_ROOT}/system_error.cpp)
-    endif ()
-
     if (TMPI_ENABLED)
         list(APPEND ${SRC_VARIABLE}
              ${SRC_ROOT}/alltoall.cpp      ${SRC_ROOT}/p2p_protocol.cpp
index dbbc4f1ca78758b26e73071cd87ed73ccf6786b3..831dbcac400a1816c2c918ab92645c4e0c4e38c2 100644 (file)
@@ -256,88 +256,6 @@ macro (gmx_c_flags)
         GMX_TEST_CXXFLAG(CXXFLAGS_NOINLINE "-fno-inline" GMXC_CXXFLAGS_DEBUG)
     endif()
 
-    # icc
-    if (CMAKE_C_COMPILER_ID STREQUAL "Intel")
-        if (NOT WIN32)
-            if(NOT GMX_OPENMP)
-# 3180: unrecognized OpenMP #pragma
-                GMX_TEST_CFLAG(CFLAGS_PRAGMA "-wd3180" GMXC_CFLAGS)
-            endif()
-            if (GMX_COMPILER_WARNINGS)
-# -w3 enables a lot of useful diagnostics but we don't care about all. -wd disables some selectively.
-# 177: function/variable ".." was declared but never referenced
-# 280: selector expression is constant
-# 411: class defines no constructor to initialize the following (incorrect for struct, initializer list works)
-# 593: variable ".." was set but never used
-# 981: operands are evaluated in unspecified order
-#1418: external function definition with no prior declaration
-#1419: external declaration in primary source file
-#1572: floating-point equality and inequality comparisons are unreliable
-#1599: declaration hides variable ".."
-#2259: non-pointer conversion from ".." to ".." may lose significant bits
-#2415: variable ".." of static storage duration was declared but never referenced
-#2547: ".." was specified as both a system and non-system include directory
-#2557: comparison between signed and unsigned operands
-#3280: declaration hides member ".."
-#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;-wd280;-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;-no-prec-div;-fimf-domain-exclusion=14;-qoverride-limits" GMXC_CFLAGS_RELEASE)
-            GMX_TEST_CFLAG(CFLAGS_DEBUG "-O0" GMXC_CFLAGS_DEBUG) #icc defaults to -O2 even with -g
-            # The "except" fp-model requires something other than the
-            # default "fast" model, so we test and use it with
-            # "precise".
-            GMX_TEST_CFLAG(CFLAGS_FP_MODEL_RELASSERT "-fp-model=except;-fp-model=precise" GMXC_CFLAGS_RELWITHASSERT)
-        else()
-            if(NOT GMX_OPENMP)
-                GMX_TEST_CFLAG(CFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
-            endif()
-            if (GMX_COMPILER_WARNINGS)
-#only on Windows
-#161: unrecognized pragma
-#1786 function was declared deprecated (is issued for stdlib function such as strncpy which have a _s version)
-GMX_TEST_CFLAG(CFLAGS_WARN "/W3;/wd161;/wd177;/wd411;/wd593;/wd981;/wd1418;/wd1419;/wd1572;/wd1599;/wd1786;/wd2259;/wd2415;/wd2547;/wd2557;/wd3280" GMXC_CFLAGS)
-            endif()
-            GMX_TEST_CFLAG(CFLAGS_OPT "/Qip" GMXC_CFLAGS_RELEASE)
-        endif()
-    endif()
-
-    if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
-        if (NOT WIN32) 
-            if(NOT GMX_OPENMP)
-                GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "-wd3180" GMXC_CXXFLAGS)
-            endif()
-            if (GMX_COMPILER_WARNINGS)
-#All but the following warnings are identical for the C-compiler (see above)
-# 304: access control not specified
-# 383: value copied to temporary, reference to temporary used
-# 444: destructor for base class ".." is not virtual
-# 869: was never referenced (false positives)
-#2282: unrecognized GCC pragma
-#2621: attribute "unused" does not apply here
-                GMX_TEST_CXXFLAG(CXXFLAGS_WARN "-w3;-wd177;-wd280;-wd304;-wd383;-wd411;-wd444;-wd869;-wd981;-wd1418;-wd1572;-wd1599;-wd2259;-wd2547;-wd2621;-wd3280;-wd11074;-wd11076;-wd2282" GMXC_CXXFLAGS)
-            endif()
-            GMX_TEST_CXXFLAG(CXXFLAGS_OPT "-ip;-funroll-all-loops;-alias-const;-ansi-alias;-no-prec-div;-fimf-domain-exclusion=14;-qoverride-limits" GMXC_CXXFLAGS_RELEASE)
-            GMX_TEST_CXXFLAG(CXXFLAGS_DEBUG "-O0" GMXC_CXXFLAGS_DEBUG)
-            # The "except" fp-model requires something other than the
-            # default "fast" model, so we test and use it with
-            # "precise".
-            GMX_TEST_CXXFLAG(CXXFLAGS_FP_MODEL_RELASSERT "-fp-model=except;-fp-model=precise" GMXC_CXXFLAGS_RELWITHASSERT)
-        else()
-            if(NOT GMX_OPENMP)
-                GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
-            endif()
-            if (GMX_COMPILER_WARNINGS)
-#161: unrecognized pragma
-#809: exception specification for virtual function X is incompatible with that of overridden function
-                GMX_TEST_CXXFLAG(CXXFLAGS_WARN "/W3;/wd161;/wd177;/wd280;/wd304;/wd383;/wd411;/wd444;/wd809;/wd869;/wd981;/wd1418;/wd1572;/wd1599;/wd1786;/wd2259;/wd2547;/wd3280;/wd11074;/wd11076;/wd2282" GMXC_CXXFLAGS)
-            endif()
-            GMX_TEST_CXXFLAG(CXXFLAGS_OPT "/Qip" GMXC_CXXFLAGS_RELEASE)
-        endif()
-    endif()
-
     # PGI
     # Inter-procedural analysis causes pgcc/pgc++ to crash when linking the library with PGI release 15.7.
     if (CMAKE_C_COMPILER_ID MATCHES "PGI")
@@ -488,17 +406,4 @@ GMX_TEST_CFLAG(CFLAGS_WARN "/W3;/wd161;/wd177;/wd411;/wd593;/wd981;/wd1418;/wd14
         endif()
     endif()
 
-    # Fujitsu compilers on PrimeHPC/Sparc64
-    if(${CMAKE_C_COMPILER_ID} MATCHES Fujitsu OR
-       (${CMAKE_C_COMPILER_ID} MATCHES unknown AND ${CMAKE_C_COMPILER} MATCHES ^fcc))
-        GMX_TEST_CFLAG(CFLAG_GNUCOMPAT "-Xg;-w" GMXC_CFLAGS)
-        GMX_TEST_CFLAG(CFLAG_OPT "-Kfast,reduction,swp,simd=2,uxsimd,fsimple;-x100" GMXC_CFLAGS)
-    endif()
-
-    if(${CMAKE_CXX_COMPILER_ID} MATCHES Fujitsu OR
-       (${CMAKE_CXX_COMPILER_ID} MATCHES unknown AND ${CMAKE_CXX_COMPILER} MATCHES ^FCC))
-        GMX_TEST_CXXFLAG(CXXFLAG_GNUCOMPAT "-Xg;-w" GMXC_CXXFLAGS)
-        GMX_TEST_CXXFLAG(CXXFLAG_OPT "-Kfast,reduction,swp,simd=2,uxsimd,fsimple;-x100" GMXC_CXXFLAGS)
-    endif()
-
 endmacro()
index 781e9a2e5619d76303a26b4848893af5eaf83057..098918eea929b9ebc9d2a85c480154582d7c427e 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
-# Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,14 +126,10 @@ function(gmx_suggest_simd _suggested_simd)
         else()
             if(CPU_DETECTION_FEATURES MATCHES " vsx ")
                 set(OUTPUT_SIMD "IBM_VSX")
-            elseif(CPU_DETECTION_FEATURES MATCHES " vmx ")
-                set(OUTPUT_SIMD "IBM_VMX")
             elseif(CPU_DETECTION_FEATURES MATCHES " sve ")
                 set(OUTPUT_SIMD "ARM_SVE")
             elseif(CPU_DETECTION_FEATURES MATCHES " neon_asimd ")
                 set(OUTPUT_SIMD "ARM_NEON_ASIMD")
-            elseif(CPU_DETECTION_FEATURES MATCHES " neon " AND NOT GMX_DOUBLE)
-                set(OUTPUT_SIMD "ARM_NEON")
             endif()
         endif()
         if (NOT SUGGEST_SIMD_QUIETLY)
@@ -151,15 +147,7 @@ endfunction()
 
 function(gmx_detect_simd _suggested_simd)
     if(GMX_SIMD STREQUAL "AUTO")
-        if(GMX_TARGET_FUJITSU_SPARC64)
-            # HPC-ACE is always present. In the future we
-            # should add detection for HPC-ACE2 here.
-            set(${_suggested_simd} "Sparc64_HPC_ACE")
-        elseif(GMX_TARGET_MIC)
-            set(${_suggested_simd} "MIC")
-        else()
-            gmx_suggest_simd(${_suggested_simd})
-        endif()
+        gmx_suggest_simd(${_suggested_simd})
 
         string(TOUPPER "${${_suggested_simd}}" ${_suggested_simd})
         set(${_suggested_simd} ${${_suggested_simd}} PARENT_SCOPE)
index ad5734db7a6f211e1124f0112e3380e4b0da208a..2c89c28f7debd85d820737e3c1034f917b99b760 100644 (file)
@@ -1,7 +1,8 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2013,2014,2016,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2013,2014,2016,2018,2019,2020, by the GROMACS development team.
+# Copyright (c) 2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,18 +45,4 @@ function(gmx_detect_target_architecture)
         try_compile(GMX_TARGET_X86 ${CMAKE_BINARY_DIR}
             "${CMAKE_SOURCE_DIR}/cmake/TestX86.cpp")
     endif()
-    if (NOT DEFINED GMX_TARGET_MIC)
-        try_compile(GMX_TARGET_MIC ${CMAKE_BINARY_DIR}
-            "${CMAKE_SOURCE_DIR}/cmake/TestMIC.cpp")
-    endif()
-    if (GMX_TARGET_MIC)
-        message(STATUS "The Intel MIC KNC target is deprecated")
-    endif()
-    if (NOT DEFINED GMX_TARGET_FUJITSU_SPARC64)
-        try_compile(GMX_TARGET_FUJITSU_SPARC64 ${CMAKE_BINARY_DIR}
-            "${CMAKE_SOURCE_DIR}/cmake/TestFujitsuSparc64.cpp")
-    endif()
-    if (GMX_TARGET_FUJITSU_SPARC64)
-        message(STATUS "The Fujitsu Sparc64 target is deprecated")
-    endif()
 endfunction()
index 72b85bcc66842d020e6e3982d7d75b4c30a3d5fa..e099cc28d78310493b14326a30b9498345dc12f2 100644 (file)
@@ -118,7 +118,17 @@ if (SOURCE_IS_SOURCE_DISTRIBUTION)
     # version of GROMACS is in use.
     set(RELEASE_CHECKSUM_FILE "${PROJECT_SOURCE_DIR}/src/reference_checksum")
     if(NOT VERSION_STRING_OF_FORK OR "${VERSION_STRING_OF_FORK}" STREQUAL "")
-        if(EXISTS ${RELEASE_CHECKSUM_FILE} AND PYTHON_EXECUTABLE)
+        if(NOT EXISTS ${RELEASE_CHECKSUM_FILE})
+            set(GMX_VERSION_STRING_FULL "${GMX_VERSION_STRING_FULL}-UNCHECKED")
+            set(GMX_RELEASE_SOURCE_FILE_CHECKSUM "NoChecksumFile")
+            set(GMX_CURRENT_SOURCE_FILE_CHECKSUM "NoChecksumFile")
+            message(WARNING "Could not valdiate the GROMACS source due to missing reference checksum file.")
+        elseif(NOT PYTHON_EXECUTABLE)
+            set(GMX_VERSION_STRING_FULL "${GMX_VERSION_STRING_FULL}-UNCHECKED")
+            set(GMX_RELEASE_SOURCE_FILE_CHECKSUM "NoPythonAvailable")
+            set(GMX_CURRENT_SOURCE_FILE_CHECKSUM "NoPythonAvailable")
+            message(STATUS "Could not calculate checksum of source files without Python")
+        else()
             file(READ ${RELEASE_CHECKSUM_FILE} GMX_RELEASE_SOURCE_FILE_CHECKSUM)
             string(STRIP ${GMX_RELEASE_SOURCE_FILE_CHECKSUM} GMX_RELEASE_SOURCE_FILE_CHECKSUM)
             set(CHECKSUM_RESULT_FILE "${CMAKE_CURRENT_BINARY_DIR}/computed_checksum")
@@ -134,16 +144,6 @@ if (SOURCE_IS_SOURCE_DISTRIBUTION)
                 set(GMX_VERSION_STRING_FULL "${GMX_VERSION_STRING_FULL}-MODIFIED")
                 message(STATUS "The source code for this GROMACS installation is different from the officially released version.")
             endif()
-        elseif(PYTHON_EXECUTABLE)
-            set(GMX_VERSION_STRING_FULL "${GMX_VERSION_STRING_FULL}-UNCHECKED")
-            set(GMX_RELEASE_SOURCE_FILE_CHECKSUM "NoChecksumFile")
-            set(GMX_CURRENT_SOURCE_FILE_CHECKSUM "NoChecksumFile")
-            message(WARNING "Could not valdiate the GROMACS source due to missing reference checksum file.")
-        else()
-            set(GMX_VERSION_STRING_FULL "${GMX_VERSION_STRING_FULL}-UNCHECKED")
-            set(GMX_RELEASE_SOURCE_FILE_CHECKSUM "NoPythonAvailable")
-            set(GMX_CURRENT_SOURCE_FILE_CHECKSUM "NoPythonAvailable")
-            message(STATUS "Could not calculate checksum of source files without Python")
         endif()
     endif()
 else()
index c68dce68534aee8fff3660ed3eafd0681444a45c..2f25ceddb1d18856096ea1a6eb01ef22b7647838 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,27 @@ if (GMX_CUDA_TARGET_COMPUTE)
     message(WARNING "Values passed in GMX_CUDA_TARGET_COMPUTE will be ignored; clang will by default include PTX in the binary.")
 endif()
 
+if (CUDA_VERSION VERSION_GREATER 10.1)
+    # At the time of writing, the latest versions are Clang 11 and CUDA 11.2.
+    if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 11.0)
+        # We don't know about the future Clang versions, but so far Clang 12 docs state that only CUDA versions 7.0-10.1 are supported.
+        set(_support_status "likely incompatible")
+    else()
+        if (CUDA_VERSION VERSION_GREATER 11.2)
+            # No idea about future CUDA versions.
+            set(_support_status "officially incompatible")
+        else()
+            # Our experience and multiple reports on the internet indicate that it works just fine.
+            set(_support_status "officially incompatible (but generally working)")
+        endif()
+    endif()
+    message(NOTICE "Using ${_support_status} version of CUDA with Clang.")
+    message(NOTICE "If Clang fails to recognize CUDA version, consider creating doing "
+      "`echo \"CUDA Version ${CUDA_VERSION}\" | sudo tee \"${CUDA_TOOLKIT_ROOT_DIR}/version.txt\"`")
+    list(APPEND _CUDA_CLANG_FLAGS "-Wno-unknown-cuda-version")
+
+endif()
+
 if (GMX_CUDA_TARGET_SM)
     set(_CUDA_CLANG_GENCODE_FLAGS)
     set(_target_sm_list ${GMX_CUDA_TARGET_SM})
@@ -58,7 +79,9 @@ if (GMX_CUDA_TARGET_SM)
         list(APPEND _CUDA_CLANG_GENCODE_FLAGS "--cuda-gpu-arch=sm_${_target}")
     endforeach()
 else()
-    list(APPEND _CUDA_CLANG_GENCODE_FLAGS "--cuda-gpu-arch=sm_30")
+    if (CUDA_VERSION VERSION_LESS 11.0)
+        list(APPEND _CUDA_CLANG_GENCODE_FLAGS "--cuda-gpu-arch=sm_30")
+    endif()
     list(APPEND _CUDA_CLANG_GENCODE_FLAGS "--cuda-gpu-arch=sm_35")
     # clang 6.0 + CUDA 9.0 seems to have issues generating code for sm_37
     if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6.0.999)
@@ -69,9 +92,16 @@ else()
     list(APPEND _CUDA_CLANG_GENCODE_FLAGS "--cuda-gpu-arch=sm_60")
     list(APPEND _CUDA_CLANG_GENCODE_FLAGS "--cuda-gpu-arch=sm_61")
     list(APPEND _CUDA_CLANG_GENCODE_FLAGS "--cuda-gpu-arch=sm_70")
-    # Enable this when clang (8.0 ?) introduces sm_75 support
-    #if (NOT CUDA_VERSION VERSION_LESS 10.0)
-    #    list(APPEND _CUDA_CLANG_GENCODE_FLAGS "--cuda-gpu-arch=sm_75")
+    if (NOT CUDA_VERSION VERSION_LESS 10.0)
+        list(APPEND _CUDA_CLANG_GENCODE_FLAGS "--cuda-gpu-arch=sm_75")
+    endif()
+    # Enable this when clang (12.0 ?) properly recognizes CUDA 11.0
+    #if(NOT CUDA_VERSION VERSION_LESS 11.0)
+    #    list(APPEND _CUDA_CLANG_GENCODE_FLAGS "--cuda-gpu-arch=sm_80")
+    #endif()
+    # Enable this when clang (12.0 ?) introduces sm_86 support
+    #if(NOT CUDA_VERSION VERSION_LESS 11.1)
+    #    list(APPEND _CUDA_CLANG_GENCODE_FLAGS "--cuda-gpu-arch=sm_86")
     #endif()
 endif()
 if (GMX_CUDA_TARGET_SM)
similarity index 57%
rename from cmake/gmxTestMPI_IN_PLACE.cmake
rename to cmake/gmxManageCudaAwareMPI.cmake
index 54cdb1046ddf90d31dcace41b9592f42c84e41ec..3b23840f70ca531d690394ee9d39ea892b5b4888 100644 (file)
@@ -1,8 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2009,2011,2012,2014,2015 by the GROMACS development team.
-# Copyright (c) 2016,2020, by the GROMACS development team, led by
+# Copyright (c) 2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
-# - Define macro to check if MPI_IN_PLACE exists
+# - Define function to check if underlying MPI is CUDA-aware
 #
-#  GMX_TEST_MPI_IN_PLACE(VARIABLE)
+#  GMX_TEST_CUDA_AWARE_MPI()
 #
-#  VARIABLE will be set to true if MPI_IN_PLACE exists
+#  GMX_TEST_CUDA_AWARE_MPI puts HAVE_CUDA_AWARE_MPI variable in cache
 #
-
-include(CheckCSourceCompiles)
-MACRO(GMX_TEST_MPI_IN_PLACE VARIABLE)
-  if(NOT DEFINED MPI_IN_PLACE_COMPILE_OK)
-    MESSAGE(STATUS "Checking for MPI_IN_PLACE")
-
-    if(CMAKE_VERSION VERSION_LESS 3.12)
-      foreach(_FLAG ${MPI_COMPILE_FLAGS})
-        set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${_FLAG}")
-      endforeach()
-    else()
-      list(JOIN MPI_COMPILE_FLAGS " " CMAKE_REQUIRED_FLAGS)
-    endif()
+include(CheckCXXSourceCompiles)
+function(GMX_TEST_CUDA_AWARE_MPI)
+  if (NOT DEFINED HAVE_CUDA_AWARE_MPI)
+    MESSAGE(STATUS "Checking for CUDA_AWARE_MPI")
+    list(JOIN MPI_COMPILE_FLAGS " " CMAKE_REQUIRED_FLAGS)
     set(CMAKE_REQUIRED_INCLUDES ${MPI_INCLUDE_PATH})
     set(CMAKE_REQUIRED_LIBRARIES ${MPI_LIBRARIES})
+    # cannot use check_include_file here as mpi.h needs to be included
+    # before mpi-ext.h for compilation, check_include_file doesn't support 
+    # this use-case
     check_cxx_source_compiles(
       "#include <mpi.h>
-int main(void) {
-  void* buf;
-  MPI_Allreduce(MPI_IN_PLACE, buf, 10, MPI_FLOAT, MPI_SUM, MPI_COMM_WORLD);
-}" MPI_IN_PLACE_COMPILE_OK)
+      #include <mpi-ext.h>
+      int main(void) 
+      {
+      #if defined(MPIX_CUDA_AWARE_SUPPORT) && (MPIX_CUDA_AWARE_SUPPORT==1)
+        return 0;
+      #else
+      #error MPI implementation isn't CUDA-aware
+      #endif
+      }" HAVE_CUDA_AWARE_MPI)
 
-    if(MPI_IN_PLACE_COMPILE_OK)
-        MESSAGE(STATUS "Checking for MPI_IN_PLACE - yes")
+    if(HAVE_CUDA_AWARE_MPI)
+      MESSAGE(STATUS "Checking for CUDA_AWARE_MPI - yes")
     else()
-        MESSAGE(STATUS "Checking for MPI_IN_PLACE - no")
+      MESSAGE(STATUS "Checking for CUDA_AWARE_MPI - no")
+      MESSAGE(WARNING "GROMACS cannot determine if underlying MPI is CUDA-aware, " 
+      "for better multi-GPU performance consider using a more recent CUDA-aware MPI.")
     endif()
-    set(MPI_IN_PLACE_COMPILE_OK "${MPI_IN_PLACE_COMPILE_OK}" CACHE INTERNAL "Result of mpi_in_place check")
-    set(CMAKE_REQUIRED_FLAGS)
-    set(CMAKE_REQUIRED_INCLUDES)
-    set(CMAKE_REQUIRED_LIBRARIES)
   endif()
-  if (MPI_IN_PLACE_COMPILE_OK)
-    set(${VARIABLE} ${MPI_IN_PLACE_COMPILE_OK}
-      "Result of test for MPI_IN_PLACE")
-  endif()
-ENDMACRO(GMX_TEST_MPI_IN_PLACE VARIABLE)
+endfunction()
+
+# Test if CUDA-aware MPI is supported
+gmx_test_cuda_aware_mpi()
+
 
 
 
index bc310470b1523572c0f09057800813d4d0167d5e..e412641fcec82b742f79991a9282151f65bd7083 100644 (file)
@@ -40,9 +40,7 @@ set(PKG_FFT_LIBS "")
 # all their stuff. It's not easy if you only want some of their
 # stuff...
 set(MKL_MANUALLY FALSE)
-if (GMX_FFT_LIBRARY STREQUAL "MKL" AND
-    NOT ((CMAKE_C_COMPILER_ID MATCHES "Intel" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "11")
-         OR GMX_INTEL_LLVM))
+if (GMX_FFT_LIBRARY STREQUAL "MKL" AND NOT GMX_INTEL_LLVM)
     # The user will have to provide the set of magic libraries in
     # MKL_LIBRARIES (see below), which we cache (non-advanced), so that they
     # don't have to keep specifying it, and can easily see that
@@ -126,7 +124,7 @@ if(${GMX_FFT_LIBRARY} STREQUAL "FFTW3")
 
     set(FFT_LIBRARIES ${${FFTW}_LIBRARIES})
 elseif(${GMX_FFT_LIBRARY} STREQUAL "MKL")
-    # Intel 11 and up makes life somewhat easy if you just want to use
+    # Intel compilers make life somewhat easy if you just want to use
     # all their stuff. It's not easy if you only want some of their
     # stuff...
     if (NOT MKL_MANUALLY)
index bb5a5e61655e5ff2bd9227cb92f633914353f5fc..56ea29e1e82f207ca8833f14a7a15d62f37795a8 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2013,2014,2016,2020, by the GROMACS development team, led by
+# Copyright (c) 2013,2014,2016,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -153,7 +153,7 @@ endmacro()
 # these. If the libraries are not in a standard location, the user can
 # indicate a search path with CMAKE_PREFIX_PATH.
 #
-# However, if we are using icc+mkl (so a build command that includes
+# However, if we are using icpx+mkl (so a build command that includes
 # -mkl), then it is probably painful to try to link some other BLAS or
 # LAPACK. In that case, we use the BLAS & LAPACK provided by MKL. In
 # principle, we could offer a more configurable behaviour if/when
index 82737aaed8c31c4a29876299c65afbe665ca7beb..5a0273d28ee2c5546a59c1f08743657f0981c646 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
-# Copyright (c) 2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,15 +50,18 @@ if(GMX_MPI)
   # If CMAKE_C_COMPILER is not a MPI wrapper. Try to find MPI using cmake module as fall-back.
   if(NOT MPI_FOUND)
       find_package(MPI)
-      if(MPI_C_FOUND)
-          set(MPI_COMPILE_FLAGS ${MPI_C_COMPILE_FLAGS})
+      if (MPI_CXX_VERSION VERSION_LESS 2.0)
+          message(FATAL_ERROR "MPI version 2.0 or higher is required. Please update your MPI library.")
+      endif()
+      if(MPI_CXX_FOUND)
+          set(MPI_COMPILE_FLAGS ${MPI_CXX_COMPILE_FLAGS})
           separate_arguments(MPI_COMPILE_FLAGS)
-          set(MPI_LINKER_FLAGS ${MPI_C_LINK_FLAGS})
-          separate_arguments(MPI_C_LINK_FLAGS)
-          include_directories(SYSTEM ${MPI_C_INCLUDE_PATH})
-          list(APPEND GMX_COMMON_LIBRARIES ${MPI_C_LIBRARIES})
+          set(MPI_LINKER_FLAGS ${MPI_CXX_LINK_FLAGS})
+          separate_arguments(MPI_CXX_LINK_FLAGS)
+          include_directories(SYSTEM ${MPI_CXX_INCLUDE_PATH})
+          list(APPEND GMX_COMMON_LIBRARIES ${MPI_CXX_LIBRARIES})
       endif()
-      set(MPI_FOUND ${MPI_C_FOUND})
+      set(MPI_FOUND ${MPI_CXX_FOUND})
   else()
       # The following defaults are based on FindMPI.cmake in cmake
       # 3.1.2. (That package does not actually do any detection of the
@@ -85,14 +88,9 @@ if(GMX_MPI)
   endif()
 
   if(MPI_FOUND)
-    include(gmxTestMPI_IN_PLACE)
-    if (GMX_MPI_IN_PLACE)
-      gmx_test_mpi_in_place(MPI_IN_PLACE_EXISTS)
-    endif()
-
     # Find path of the mpi compilers
-    if (${MPI_C_FOUND})
-        get_filename_component(_mpi_c_compiler_path "${MPI_C_COMPILER}" PATH)
+    if (${MPI_CXX_FOUND})
+        get_filename_component(_mpi_c_compiler_path "${MPI_CXX_COMPILER}" PATH)
         get_filename_component(_mpiexec_path "${MPIEXEC}" PATH)
     else()
         get_filename_component(_cmake_c_compiler_path "${CMAKE_C_COMPILER}" PATH)
@@ -172,7 +170,7 @@ if(GMX_MPI)
       message(FATAL_ERROR
         "MPI support requested, but no MPI compiler found. Either set the "
         "C-compiler (CMAKE_C_COMPILER) to the MPI compiler (often called mpicc), "
-        "or set the variables reported missing for MPI_C above.")
+        "or set the variables reported missing for MPI_CXX above.")
   endif()
 
   set(GMX_LIB_MPI 1)
index 3f849e9e2893d2fb63ac116ee316a7e7a210631f..f95395fef2d3e982ceeb055e7e106b2e459f7a61 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2012,2013,2014,2015,2018 by the GROMACS development team.
-# Copyright (c) 2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -79,7 +79,4 @@ if (NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
     message(FATAL_ERROR "The OpenCL implementation is only supported on 64-bit platforms.")
 endif()
 
-set(GMX_OPENCL_NB_CLUSTER_SIZE 8 CACHE STRING "Cluster size used by nonbonded OpenCL kernel. Set to 4 for Intel GPUs.")
-mark_as_advanced(GMX_OPENCL_NB_CLUSTER_SIZE)
-
 set(GMX_INSTALL_OCLDIR       ${GMX_INSTALL_GMXDATADIR}/opencl)
index 57c1338d5cd7a73e57ad21e8fd3bee728b7b53be..cf5117453655637dc57b61e6abb156950ef57b7a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2020, by the GROMACS development team, led by
+# Copyright (c) 2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -39,76 +39,99 @@ set(REQUIRED_SYCL_MIN_VERSION ${REQUIRED_SYCL_MIN_VERSION_MAJOR}.${REQUIRED_SYCL
 
 set(GMX_GPU_SYCL ON)
 
+# CMake issue tracking the efforts to make a universal upstream module:
+# https://gitlab.kitware.com/cmake/cmake/-/issues/21711
+
+option(GMX_SYCL_HIPSYCL "Use hipSYCL instead of Intel/Clang for SYCL compilation" OFF)
+
 if(GMX_DOUBLE)
     message(FATAL_ERROR "SYCL acceleration is not available in double precision")
 endif()
 
 include(gmxFindFlagsForSource)
 
-if(CMAKE_CXX_COMPILER MATCHES "dpcpp")
-    # At least Intel dpcpp defaults to having SYCL enabled for all code. This leads to two problems:
-    #
-    # 1. Compiles take ~3x longer, since every file has to be compiled for multiple targets.
-    # 2. We get a ton of warnings for the device-specific pass when the compiler sees our SIMD code.
-    #
-    # To avoid this, we attempt to find a flag to disable SYCL for non-SYCL files. Unfortunately,
-    # when using gmx_find_flag_for_source() that includes calling check_cxx_compiler_flag(),  
-    # this in turn exposes a bug in dpcpp, where an object file compiles with -fno-sycl leads to
-    # a failed link stage (when the same flag is not used). Since none of this is critical, we handle
-    # it by merely checking if it works to compile a source fils with this flag, and choking if SYCL
-    # is still enabled.
-
-    if(NOT CHECK_DISABLE_SYCL_CXX_FLAGS_QUIETLY)
-        message(STATUS "Checking for flags to disable SYCL")
-    endif()
-
-    gmx_check_source_compiles_with_flags(
-        "int main() { return 0; }"
-        "-fno-sycl"
-        "CXX"
-        DISABLE_SYCL_CXX_FLAGS_RESULT)
-
-    if(DISABLE_SYCL_CXX_FLAGS_RESULT)
-        set(DISABLE_SYCL_CXX_FLAGS "-fno-sycl")
+if(GMX_SYCL_HIPSYCL)
+    if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+        message(FATAL_ERROR "hipSYCL can only be built with Clang++ compiler")
     endif()
-    if(NOT CHECK_DISABLE_SYCL_CXX_FLAGS_QUIETLY)
+    set(HIPSYCL_CLANG "${CMAKE_CXX_COMPILER}")
+    # -Wno-unknown-cuda-version because Clang-11 complains about CUDA 11.0-11.2, despite working fine with them.
+    # -Wno-unknown-attributes because hipSYCL does not support reqd_sub_group_size (because it can only do some sub group sizes).
+    # --hipsycl-explicit-multipass is needed when building for both CUDA and HIP.
+    set(HIPSYCL_SYCLCC_EXTRA_ARGS "-Wno-unknown-cuda-version -Wno-unknown-attributes --hipsycl-explicit-multipass")
+    find_package(hipsycl REQUIRED)
+else()
+    if(CMAKE_CXX_COMPILER MATCHES "dpcpp")
+        # At least Intel dpcpp defaults to having SYCL enabled for all code. This leads to two problems:
+        #
+        # 1. Compiles take ~3x longer, since every file has to be compiled for multiple targets.
+        # 2. We get a ton of warnings for the device-specific pass when the compiler sees our SIMD code.
+        #
+        # To avoid this, we attempt to find a flag to disable SYCL for non-SYCL files. Unfortunately,
+        # when using gmx_find_flag_for_source() that includes calling check_cxx_compiler_flag(),
+        # this in turn exposes a bug in dpcpp, where an object file compiles with -fno-sycl leads to
+        # a failed link stage (when the same flag is not used). Since none of this is critical, we handle
+        # it by merely checking if it works to compile a source fils with this flag, and choking if SYCL
+        # is still enabled.
+    
+        if(NOT CHECK_DISABLE_SYCL_CXX_FLAGS_QUIETLY)
+            message(STATUS "Checking for flags to disable SYCL")
+        endif()
+    
+        gmx_check_source_compiles_with_flags(
+            "int main() { return 0; }"
+            "-fno-sycl"
+            "CXX"
+            DISABLE_SYCL_CXX_FLAGS_RESULT)
+    
         if(DISABLE_SYCL_CXX_FLAGS_RESULT)
-            message(STATUS "Checking for flags to disable SYCL - -fno-sycl")
-        else()
-            message(WARNING "Cannot find flags to disable SYCL for non-SYCL hardware-specific C++ code. Expect many warnings, but they are likely benign.")
+            set(DISABLE_SYCL_CXX_FLAGS "-fno-sycl")
+        endif()
+        if(NOT CHECK_DISABLE_SYCL_CXX_FLAGS_QUIETLY)
+            if(DISABLE_SYCL_CXX_FLAGS_RESULT)
+                message(STATUS "Checking for flags to disable SYCL - -fno-sycl")
+            else()
+                message(WARNING "Cannot find flags to disable SYCL for non-SYCL hardware-specific C++ code. Expect many warnings, but they are likely benign.")
+            endif()
+            set(CHECK_DISABLE_SYCL_CXX_FLAGS_QUIETLY 1 CACHE INTERNAL "Keep quiet on future calls to detect no-SYCL flags" FORCE)
         endif()
-        set(CHECK_DISABLE_SYCL_CXX_FLAGS_QUIETLY 1 CACHE INTERNAL "Keep quiet on future calls to detect no-SYCL flags" FORCE)
     endif()
-endif()
-
-# Find the flags to enable (or re-enable) SYCL with Intel extensions. In case we turned it off above,
-# it's important that we check the combination of both flags, to make sure the second one re-enables SYCL.
-if(NOT CHECK_SYCL_CXX_FLAGS_QUIETLY)
-    message(STATUS "Checking for flags to enable SYCL")
-endif()
-gmx_find_flag_for_source(SYCL_CXX_FLAGS_RESULT
-    "#include <CL/sycl.hpp>
-     namespace sycl = cl::sycl;
-     int main(){
-         constexpr int length = 1000;
-         sycl::queue q(sycl::default_selector{});
-         // Check USM extension
-         sycl::usm_allocator<int, sycl::usm::alloc::shared> q_alloc{q};
-         std::vector<int, sycl::usm_allocator<int, sycl::usm::alloc::shared>> v(q_alloc);
-         v.reserve(length);
-         for(int i = 0; i < length ; i++) { v.push_back(i); }
-         q.parallel_for<class whatever>(sycl::range<1>{length}, [=, ptr = v.data()] (sycl::id<1> i){ ptr[i] *= 2; }).wait();
-         return 0;
-     }
-     " "CXX" DISABLE_SYCL_CXX_FLAGS SYCL_CXX_FLAGS "-fsycl")
-
-if(NOT CHECK_SYCL_CXX_FLAGS_QUIETLY)
-    if(SYCL_CXX_FLAGS_RESULT)
-        message(STATUS "Checking for flags to enable SYCL - ${SYCL_CXX_FLAGS}")
+    
+    # Find the flags to enable (or re-enable) SYCL with Intel extensions. In case we turned it off above,
+    # it's important that we check the combination of both flags, to make sure the second one re-enables SYCL.
+    if(NOT CHECK_SYCL_CXX_FLAGS_QUIETLY)
+        message(STATUS "Checking for flags to enable SYCL")
+    endif()
+    gmx_find_flag_for_source(SYCL_CXX_FLAGS_RESULT
+        "#include <CL/sycl.hpp>
+         namespace sycl = cl::sycl;
+         int main(){
+             sycl::queue q(sycl::default_selector{});
+             return 0;
+         }
+         " "CXX" DISABLE_SYCL_CXX_FLAGS SYCL_CXX_FLAGS "-fsycl -fsycl-device-code-split=per_kernel")
+    
+    if(NOT CHECK_SYCL_CXX_FLAGS_QUIETLY)
+        if(SYCL_CXX_FLAGS_RESULT)
+            message(STATUS "Checking for flags to enable SYCL - ${SYCL_CXX_FLAGS}")
+        endif()
+        set(CHECK_SYCL_CXX_FLAGS_QUIETLY 1 CACHE INTERNAL "Keep quiet on future calls to detect SYCL flags" FORCE)
+    endif()
+    
+    if(NOT SYCL_CXX_FLAGS_RESULT)
+        message(FATAL_ERROR "Cannot compile with SYCL Intel compiler. Try a different compiler or disable SYCL.")
     endif()
-    set(CHECK_SYCL_CXX_FLAGS_QUIETLY 1 CACHE INTERNAL "Keep quiet on future calls to detect SYCL flags" FORCE)
-endif()
 
-if(NOT SYCL_CXX_FLAGS_RESULT)
-    message(ERROR "Cannot compile SYCL with Intel extensions. Try a different compiler or disable SYCL.")
+    # Add function wrapper similar to the one used by ComputeCPP and hipSYCL
+    function(add_sycl_to_target)
+        cmake_parse_arguments(
+            PARSE_ARGV 0 # No positional arguments
+            ARGS # Prefix for the resulting variables
+            "" # No options
+            "TARGET" # One-value keyword
+            "SOURCES" # Multi-value keyword
+        )
+        set_source_files_properties(${ARGS_SOURCES} PROPERTIES COMPILE_FLAGS "${SYCL_CXX_FLAGS}")
+        target_link_libraries(${ARGS_TARGET} PRIVATE ${SYCL_CXX_FLAGS})
+    endfunction(add_sycl_to_target)
 endif()
index 8b3f3a92350a2c0ad926ceccf0e179120e81a3b8..0511529c058d36289fd6ebdc4f868116af92b13e 100644 (file)
@@ -39,7 +39,7 @@
 ########################################################################
 # Determine the defaults (this block has no effect if the variables have
 # already been set)
-if((APPLE OR CYGWIN OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux|.*BSD|GNU") AND NOT GMX_BUILD_MDRUN_ONLY)
+if((APPLE OR CYGWIN OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux|.*BSD|GNU"))
     # Maybe Solaris should be here? Patch this if you know!
     SET(SHARED_LIBS_DEFAULT ON)
 elseif(WIN32)
@@ -74,10 +74,6 @@ if (WIN32 AND NOT BUILD_SHARED_LIBS)
     set(GMX_PREFER_STATIC_LIBS_DEFAULT ON)
 endif()
 
-if(BUILD_SHARED_LIBS AND GMX_BUILD_MDRUN_ONLY)
-    message(WARNING "Both BUILD_SHARED_LIBS and GMX_BUILD_MDRUN_ONLY are set. Generally, an mdrun-only build should prefer to use static libraries, which is the default if you make a fresh build tree. You may be re-using an old build tree, and so may wish to set BUILD_SHARED_LIBS=off yourself.")
-endif()
-
 if (UNIX)
     set(GMX_PREFER_STATIC_LIBS_DESCRIPTION
         "When finding libraries prefer static archives (it will only work if static versions of external dependencies are available and found)")
index af870d4fbaaffea8d0458be57d211b2c80833a47..89e1469cdbc838fa518e28b7cda138d9b510c808 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
-# Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -177,11 +177,6 @@ elseif(GMX_SIMD_ACTIVE MATCHES "AVX2_")
         set(SIMD_STATUS_MESSAGE "Enabling 256-bit AVX2 SIMD instructions using CXX flags: ${SIMD_AVX2_CXX_FLAGS}")
     endif()
 
-elseif(GMX_SIMD_ACTIVE STREQUAL "MIC")
-    # No flags needed. Not testing.
-    set(GMX_SIMD_X86_MIC 1)
-    set(SIMD_STATUS_MESSAGE "Enabling MIC (Xeon Phi) SIMD instructions without special flags. This SIMD support is deprecated.")
-
 elseif(GMX_SIMD_ACTIVE STREQUAL "AVX_512")
 
     gmx_find_simd_avx_512_flags(SIMD_AVX_512_C_SUPPORTED SIMD_AVX_512_CXX_SUPPORTED
@@ -212,25 +207,6 @@ elseif(GMX_SIMD_ACTIVE STREQUAL "AVX_512_KNL")
     set(GMX_SIMD_X86_${GMX_SIMD_ACTIVE} 1)
     set(SIMD_STATUS_MESSAGE "Enabling 512-bit AVX-512-KNL SIMD instructions using CXX flags: ${SIMD_AVX_512_KNL_CXX_FLAGS}")
 
-elseif(GMX_SIMD_ACTIVE STREQUAL "ARM_NEON")
-
-    if (GMX_DOUBLE)
-        message(FATAL_ERROR "ARM_NEON SIMD support is not available for a double precision build because the architecture lacks double-precision support")
-    endif()
-
-    gmx_find_simd_arm_neon_flags(SIMD_ARM_NEON_C_SUPPORTED SIMD_ARM_NEON_CXX_SUPPORTED
-                                 SIMD_ARM_NEON_C_FLAGS SIMD_ARM_NEON_CXX_FLAGS)
-
-    if(NOT SIMD_ARM_NEON_C_SUPPORTED OR NOT SIMD_ARM_NEON_CXX_SUPPORTED)
-        gmx_give_fatal_error_when_simd_support_not_found("ARM NEON" "disable SIMD support (slower)" "${SUGGEST_BINUTILS_UPDATE}")
-    endif()
-
-    # If multiple flags are neeed, make them into a list
-    string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_ARM_NEON_C_FLAGS})
-    string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_ARM_NEON_CXX_FLAGS})
-    set(GMX_SIMD_${GMX_SIMD_ACTIVE} 1)
-    set(SIMD_STATUS_MESSAGE "Enabling 32-bit ARM NEON SIMD instructions using CXX flags: ${SIMD_ARM_NEON_CXX_FLAGS}. This SIMD support is deprecated.")
-
 elseif(GMX_SIMD_ACTIVE STREQUAL "ARM_NEON_ASIMD")
 
     gmx_find_simd_arm_neon_asimd_flags(SIMD_ARM_NEON_ASIMD_C_SUPPORTED SIMD_ARM_NEON_ASIMD_CXX_SUPPORTED
@@ -248,7 +224,6 @@ elseif(GMX_SIMD_ACTIVE STREQUAL "ARM_NEON_ASIMD")
 
 elseif(GMX_SIMD_ACTIVE STREQUAL "ARM_SVE")
 
-    # Note that GMX_RELAXED_DOUBLE_PRECISION is enabled by default in the top-level CMakeLists.txt
     gmx_option_multichoice(
         GMX_SIMD_ARM_SVE_LENGTH
        "SVE vector length in bits"
@@ -285,21 +260,6 @@ elseif(GMX_SIMD_ACTIVE STREQUAL "ARM_SVE")
     set(GMX_SIMD_${GMX_SIMD_ACTIVE} 1)
     set(SIMD_STATUS_MESSAGE "Enabling ARM (AArch64) SVE Advanced SIMD instructions using CXX flags: ${SIMD_ARM_SVE_CXX_FLAGS}")
 
-elseif(GMX_SIMD_ACTIVE STREQUAL "IBM_VMX")
-
-    gmx_find_simd_ibm_vmx_flags(SIMD_IBM_VMX_C_SUPPORTED SIMD_IBM_VMX_CXX_SUPPORTED
-                                SIMD_IBM_VMX_C_FLAGS SIMD_IBM_VMX_CXX_FLAGS)
-
-    if(NOT SIMD_IBM_VMX_C_SUPPORTED OR NOT SIMD_IBM_VMX_CXX_SUPPORTED)
-        gmx_give_fatal_error_when_simd_support_not_found("IBM VMX" "disable SIMD support (slower)" "${SUGGEST_BINUTILS_UPDATE}")
-    endif()
-
-    # If multiple flags are neeed, make them into a list
-    string(REPLACE " " ";" SIMD_C_FLAGS ${SIMD_IBM_VMX_C_FLAGS})
-    string(REPLACE " " ";" SIMD_CXX_FLAGS ${SIMD_IBM_VMX_CXX_FLAGS})
-    set(GMX_SIMD_${GMX_SIMD_ACTIVE} 1)
-    set(SIMD_STATUS_MESSAGE "Enabling IBM VMX SIMD instructions using CXX flags: ${SIMD_IBM_VMX_CXX_FLAGS}. This SIMD support is deprecated.")
-
 elseif(GMX_SIMD_ACTIVE STREQUAL "IBM_VSX")
 
     # IBM_VSX and gcc > 9 do not work together, so we need to prevent people from
@@ -327,13 +287,6 @@ elseif(GMX_SIMD_ACTIVE STREQUAL "IBM_VSX")
     set(GMX_SIMD_${GMX_SIMD_ACTIVE} 1)
     set(SIMD_STATUS_MESSAGE "Enabling IBM VSX SIMD instructions using CXX flags: ${SIMD_IBM_VSX_CXX_FLAGS}")
 
-elseif(GMX_SIMD_ACTIVE STREQUAL "SPARC64_HPC_ACE")
-
-    # Note that GMX_RELAXED_DOUBLE_PRECISION is enabled by default in the top-level CMakeLists.txt
-
-    set(GMX_SIMD_${GMX_SIMD_ACTIVE} 1)
-    set(SIMD_STATUS_MESSAGE "Enabling Sparc64 HPC-ACE SIMD instructions without special flags. This SIMD support is deprecated.")
-
 elseif(GMX_SIMD_ACTIVE STREQUAL "REFERENCE")
 
     # NB: This file handles settings for the SIMD module, so in the interest 
@@ -403,8 +356,8 @@ endif()
 
 # By default, 32-bit windows cannot pass SIMD (SSE/AVX) arguments in registers,
 # and even on 64-bit (all platforms) it is only used for a handful of arguments.
-# The __vectorcall (MSVC, from MSVC2013) or __regcall (ICC) calling conventions
-# enable this, which is critical to enable 32-bit SIMD and improves performance
+# The __vectorcall (MSVC, from MSVC2013) calling convention
+# enables this, which is critical to enable 32-bit SIMD and improves performance
 # for 64-bit SIMD.
 # Check if the compiler supports one of these, and in that case set gmx_simdcall
 # to that string. If we do not have any such calling convention modifier, set it
index 1783f7f20d980b08188121653c282084351ed1e5..0c33a7c3f4b6a16552803e33b0a40cdf78d195d5 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,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -79,7 +79,3 @@ else()
     endif()
 endif()
 unset(SUFFIXES_CHANGED)
-
-if (GMX_BUILD_MDRUN_ONLY)
-    set(GMX_LIBS_SUFFIX "_mdrun${GMX_LIBS_SUFFIX}")
-endif()
index b778c39beaf14bf9bdf94ef67dd18980cd593f71..c55a7f0575264cd9429d3ef95d5308f2c76fcb8e 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2020, by the GROMACS development team, led by
+# Copyright (c) 2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,28 +42,17 @@ if(FIND_PACKAGE_MESSAGE_DETAILS_Python3)
     set(Python3_FIND_QUIETLY ON)
     set(PythonInterp_FIND_QUIETLY ON)
 endif()
-if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.15)
-    if (NOT Python3_FIND_STRATEGY)
-        # If the user provides a hint for the Python installation with Python3_ROOT_DIR,
-        # prevent FindPython3 from overriding the choice with a newer Python version
-        # when CMP0094 is set to OLD.
-        set(Python3_FIND_STRATEGY LOCATION)
-    endif ()
-    if(NOT Python3_FIND_VIRTUALENV)
-        # We advocate using Python venvs to manage package availability, so by default
-        # we want to preferentially discover user-space software.
-        set(Python3_FIND_VIRTUALENV FIRST)
-    endif()
-else()
-    if(NOT Python3_FIND_REGISTRY)
-        # We advocate using Python venvs to manage package availability, so by default
-        # we want to preferentially discover user-space software.
-        set(Python3_FIND_REGISTRY LAST)
-    endif()
-    # Make package discovery consistent with Unix behavior and our documented
-    # suggestions for installing dependencies.
-    set(CMAKE_FIND_FRAMEWORK LAST)
+if (NOT Python3_FIND_STRATEGY)
+    # If the user provides a hint for the Python installation with Python3_ROOT_DIR,
+    # prevent FindPython3 from overriding the choice with a newer Python version
+    # when CMP0094 is set to OLD.
+    set(Python3_FIND_STRATEGY LOCATION)
 endif ()
+if(NOT Python3_FIND_VIRTUALENV)
+    # We advocate using Python venvs to manage package availability, so by default
+    # we want to preferentially discover user-space software.
+    set(Python3_FIND_VIRTUALENV FIRST)
+endif()
 if(GMX_PYTHON_PACKAGE)
     find_package(Python3 3.6 COMPONENTS Interpreter Development)
     if (NOT Python3_FOUND OR NOT Python3_Development_FOUND)
index 1b09d525213c860ebe11b7cab48b53f57731a828..607b8523dff6bced69573b7920f3e4da4c1f496e 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -219,27 +219,12 @@ endfunction()
 # AVX2
 function(gmx_find_simd_avx2_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
     find_x86_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
-    # For our "AVX2_256" support we would ideally want to enable the instructions
-    # we want to use, '-mavx2 -mfma'. icc (v16-18) does not allow doing that and
-    # instead, it requires the '-march=core-avx2' flag to be used. Annoyingly, it does
-    # however accept the former flags but it is not silent about it issuing warnings
-    # that can't be disabled.
-    # At the same time Intel's -march=core-avx2 flag is not rejected by gcc/clang either
-    # (though they're at least silent). However, -march=core-avx2 is an undocumented
-    # flag with unclear behavior in gcc/clang (and might enable some arch-specific optimizations).
-    # For this reason, and because we can't distinguish compilers just based on checking flag
-    # compatibility, we need to treat the Intel and gcc/clang separately.
-    if (CMAKE_C_COMPILER_ID MATCHES "Intel")
-        set(TOOLCHAIN_FLAG_FOR_AVX2 "-march=core-avx2")
-    else()
-        set(TOOLCHAIN_FLAG_FOR_AVX2 "-mavx2 -mfma")
-    endif()
     gmx_find_flags(SIMD_AVX2_C_FLAGS_RESULT SIMD_AVX2_CXX_FLAGS_RESULT
         "#include<immintrin.h>
 int main(){__m256i x=_mm256_set1_epi32(5);x=_mm256_add_epi32(x,x);return _mm256_movemask_epi8(x);}"
         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
         SIMD_AVX2_C_FLAGS SIMD_AVX2_CXX_FLAGS
-        "${TOOLCHAIN_FLAG_FOR_AVX2}" "-mavx2" "/arch:AVX2" "-hgnu") 
+        "-mavx2 -mfma" "-mavx2" "/arch:AVX2" "-hgnu")
 
     if(${SIMD_AVX2_C_FLAGS_RESULT})
         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX2_C_FLAGS}" CACHE INTERNAL "C flags required for AVX2 instructions")
@@ -266,7 +251,7 @@ function(gmx_find_simd_avx_512_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VAR
           return idata[0]*(int)(_mm512_cmp_ps_mask(x,y,_CMP_LT_OS));}"
         TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
         SIMD_AVX_512_C_FLAGS SIMD_AVX_512_CXX_FLAGS
-        "-xCORE-AVX512 -qopt-zmm-usage=high" "-xCORE-AVX512" "-mavx512f -mfma" "-mavx512f" "/arch:AVX512" "-hgnu") #ICC should use ZMM if code anyhow uses ZMM
+        "-xCORE-AVX512 -qopt-zmm-usage=high" "-xCORE-AVX512" "-mavx512f -mfma" "-mavx512f" "/arch:AVX512" "-hgnu")
 
     if(${SIMD_AVX_512_C_FLAGS_RESULT})
         set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_AVX_512_C_FLAGS}" CACHE INTERNAL "C flags required for AVX-512 instructions")
@@ -301,26 +286,6 @@ function(gmx_find_simd_avx_512_knl_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS
 endfunction()
 
 
-# Arm Neon (32-bit ARM)
-function(gmx_find_simd_arm_neon_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
-
-    gmx_find_flags(SIMD_ARM_NEON_C_FLAGS_RESULT SIMD_ARM_NEON_CXX_FLAGS_RESULT
-        "#include<arm_neon.h>
-         int main(){float32x4_t x=vdupq_n_f32(0.5);x=vmlaq_f32(x,x,x);return vgetq_lane_f32(x,0)>0;}"
-        TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
-        SIMD_ARM_NEON_C_FLAGS SIMD_ARM_NEON_CXX_FLAGS
-        "-mfpu=neon-vfpv4" "-mfpu=neon" "")
-
-    if(${SIMD_ARM_NEON_C_FLAGS_RESULT})
-        set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_ARM_NEON_C_FLAGS}" CACHE INTERNAL "C flags required for Arm Neon instructions")
-    endif()
-    if(${SIMD_ARM_NEON_CXX_FLAGS_RESULT})
-        set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_ARM_NEON_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for Arm Neon instructions")
-    endif()
-    set(${C_FLAGS_RESULT} ${SIMD_ARM_NEON_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for Arm Neon C flags" FORCE)
-    set(${CXX_FLAGS_RESULT} ${SIMD_ARM_NEON_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for Arm Neon C++ flags" FORCE)
-endfunction()
-
 # Arm Neon Asimd (64-bit ARM)
 function(gmx_find_simd_arm_neon_asimd_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
 
@@ -363,26 +328,6 @@ function(gmx_find_simd_arm_sve_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VAR
     set(${CXX_FLAGS_RESULT} ${SIMD_ARM_SVE_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for Arm SVE C++ flags" FORCE)
 endfunction()
 
-# IBM VMX (power6)
-function(gmx_find_simd_ibm_vmx_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
-
-    gmx_find_flags(SIMD_IBM_VMX_C_FLAGS_RESULT SIMD_IBM_VMX_CXX_FLAGS_RESULT
-        "#include<altivec.h>
-         int main(){vector float x,y=vec_ctf(vec_splat_s32(1),0);x=vec_madd(y,y,y);return vec_all_ge(y,x);}"
-        TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS
-        SIMD_IBM_VMX_C_FLAGS SIMD_IBM_VMX_CXX_FLAGS
-        "-maltivec -mabi=altivec" "-qarch=auto -qaltivec")
-
-    if(${SIMD_IBM_VMX_C_FLAGS_RESULT})
-        set(${C_FLAGS_VARIABLE} "${TOOLCHAIN_C_FLAGS} ${SIMD_IBM_VMX_C_FLAGS}" CACHE INTERNAL "C flags required for IBM VMX instructions")
-    endif()
-    if(${SIMD_IBM_VMX_CXX_FLAGS_RESULT})
-        set(${CXX_FLAGS_VARIABLE} "${TOOLCHAIN_CXX_FLAGS} ${SIMD_IBM_VMX_CXX_FLAGS}" CACHE INTERNAL "C++ flags required for IBM VMX instructions")
-    endif()
-    set(${C_FLAGS_RESULT} ${SIMD_IBM_VMX_C_FLAGS_RESULT} CACHE INTERNAL "Result of test for IBM VMX C flags" FORCE)
-    set(${CXX_FLAGS_RESULT} ${SIMD_IBM_VMX_CXX_FLAGS_RESULT} CACHE INTERNAL "Result of test for IBM VMX C++ flags" FORCE)
-endfunction()
-
 # IBM VSX (power7 and later)
 function(gmx_find_simd_ibm_vsx_flags C_FLAGS_RESULT CXX_FLAGS_RESULT C_FLAGS_VARIABLE CXX_FLAGS_VARIABLE)
     find_power_vsx_toolchain_flags(TOOLCHAIN_C_FLAGS TOOLCHAIN_CXX_FLAGS)
index 9dc093e3930c8a2c6726be89197cae699cdab631..620f1767eda7c32b832e6a60faaa169539923fba 100644 (file)
@@ -62,10 +62,6 @@ macro(gmx_test_compiler_problems)
         if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5)
             set(cxx_required_version "Clang 5")
         endif()
-    elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
-        if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.1)
-            set(cxx_required_version "Intel Compiler 2017")
-        endif()
     else()
         message(WARNING "You are using an unsupported compiler. Please make sure it fully supports C++17.")
     endif()
@@ -74,6 +70,10 @@ macro(gmx_test_compiler_problems)
                             "Earlier versions don't have full C++17 support.")
     endif()
 
+    if (CMAKE_CXX_COMPILER_ID MATCHES "Intel")
+        message(WARNING "The Intel classic compiler is no longer supported. It may pass the tests, but is not tested by the GROMACS developers. Use the clang-based compiler from oneAPI, or gcc")
+    endif()
+
     if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "XL")
         check_cxx_source_compiles(
 "// Test in-class array initalizers used with constructor initializer lists
@@ -90,7 +90,7 @@ TestStruct::TestStruct() : b(0) {}
         endif()
     endif()
     if("${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.")
+        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 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 5fbde1e86be6ca053a7053b04f6bebbeaf71a561..37307f8f3d08f0f3373b65bd67fbb9fd91973033 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2009,2010,2012,2013,2014 by the GROMACS development team.
-# Copyright (c) 2015,2020, by the GROMACS development team, led by
+# Copyright (c) 2015,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
index 5b96f803350aee4eed9a4e650eec56c91c780180..3fc0d840bb96cae98f89e71f9da8c53bca2bf82d 100644 (file)
@@ -60,6 +60,7 @@
 #         GROMACS     2019   4
 #         GROMACS     2020   5
 #         GROMACS     2021   6
+#         GROMACS     2022   7
 #   LIBRARY_SOVERSION_MINOR so minor version for the built libraries.
 #       Should be increased for each release that changes only the implementation.
 #       In GROMACS, the typical policy is to increase it for each patch version
 
 # 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 2021)
-set(GMX_VERSION_PATCH 3)
+set(GMX_VERSION_MAJOR 2022)
+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
@@ -214,7 +215,7 @@ 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 6)
+set(LIBRARY_SOVERSION_MAJOR 7)
 set(LIBRARY_SOVERSION_MINOR 0)
 set(LIBRARY_VERSION ${LIBRARY_SOVERSION_MAJOR}.${LIBRARY_SOVERSION_MINOR}.0)
 
@@ -256,7 +257,7 @@ if (NOT SOURCE_IS_SOURCE_DISTRIBUTION AND
 endif()
 
 set(REGRESSIONTEST_VERSION "${GMX_VERSION_STRING}")
-set(REGRESSIONTEST_BRANCH "release-2021") 
+set(REGRESSIONTEST_BRANCH "master")
 # Run the regressiontests packaging job with the correct pakage
 # version string, and the release box checked, in order to have it
 # build the regressiontests tarball with all the right naming. The
index 11d7c710ea77354ae638e6347bd7778b85d4d7f8..468c8ed31a43d6c7bcc1a145c76d69f5a9b37591 100644 (file)
@@ -338,7 +338,7 @@ if (SPHINX_FOUND)
         dev-manual/doxygen.rst
         dev-manual/error-handling.rst
         dev-manual/formatting.rst
-        dev-manual/gitlab.rst
+        dev-manual/gitlab-ci.rst
         dev-manual/gmxtree.rst
         dev-manual/includestyle.rst
         dev-manual/index.rst
@@ -364,6 +364,16 @@ if (SPHINX_FOUND)
         how-to/visualize.rst
         install-guide/index.rst
         release-notes/index.rst
+        release-notes/2022/major/highlights.rst
+        release-notes/2022/major/features.rst
+        release-notes/2022/major/performance.rst
+        release-notes/2022/major/tools.rst
+        release-notes/2022/major/bugs-fixed.rst
+        release-notes/2022/major/removed-functionality.rst
+        release-notes/2022/major/deprecated-functionality.rst
+        release-notes/2022/major/portability.rst
+        release-notes/2022/major/miscellaneous.rst
+        release-notes/2022/major/api.rst
         release-notes/2021/2021.3.rst
         release-notes/2021/2021.2.rst
         release-notes/2021/2021.1.rst
index a35b57f78427902aba124c80fa84cdb690a8038e..9c848a342e15db96b9cf368e469685478dcaaa3c 100644 (file)
@@ -176,20 +176,6 @@ Variables affecting compilation/linking
 
    .. todo:: This could likely be replaced by a (yet another) build type.
 
-.. cmake:: GMX_BUILD_MDRUN_ONLY
-
-   If set ``ON``, the build system is configured to only build and install a
-   single :file:`mdrun` executable.  To be fully functional, the installed
-   :file:`mdrun` requires a standard |Gromacs| installation (with
-   ``GMX_BUILD_MDRUN_ONLY=OFF``) in the same installation prefix, as the
-   mdrun-only build does not install any data files or scripts, only the
-   binary.  This is intended for cases where one wants to/needs to compile one
-   or more instances of :file:`mdrun` with different build options (e.g., MPI
-   or SIMD) than the full installation with the other utilities.
-   Defaults to ``OFF``, in which case a single :file:`gmx` executable is built
-   and installed, together with all the supporting files.  :command:`mdrun` can
-   be executed as :command:`gmx mdrun`.
-
 .. cmake:: GMX_BUILD_OWN_FFTW
 
 .. cmake:: GMX_BUILD_SHARED_EXE
@@ -241,18 +227,6 @@ Variables affecting compilation/linking
    unaffected by this setting. See reference manual for further
    information.
 
-.. cmake:: GMX_RELAXED_DOUBLE_PRECISION
-
-   Permit a double-precision configuration to compute some quantities
-   to single-precision accuracy. Particularly on architectures where
-   only double-precision SIMD is available (e.g. Sparc machines such
-   as the K computer), it is faster to default to ``GMX_DOUBLE=ON``
-   and use SIMD than to use ``GMX_DOUBLE=OFF`` and use no
-   SIMD. However, if the user does not need full double precision,
-   then some optimizations can achieve the equivalent of
-   single-precision results (e.g. fewer Newton-Raphson iterations for
-   a reciprocal square root computation).
-
 .. cmake:: GMX_EXTRAE
 
 .. cmake:: GMX_EXTERNAL_BLAS
@@ -566,7 +540,9 @@ The build system uses a few different mechanisms to influence the compilation:
     headers fall in this category.  See Doxygen documentation for
     :file:`gmxpre.h`.
 
-  All the above files get generated in :file:`src/`.
+  The above files are available through the INTERFACE_INCLUDE_DIR of
+  the ``common`` CMake target. I.e. to ``#include "config.h"``, be sure to
+  ``target_link_libraries(mymodule PRIVATE common)``
 
   Additionally, the following file is generated by the build system:
 
index a5cf8d824fa9c3217b0cd4fc57b4acef1689662c..e0fcd620b68f662c7d6df886c3d6d264119fe8af 100644 (file)
@@ -84,6 +84,26 @@ Naming branches
 Good names: documentation_UpdateDevelopersDocsTOGitLab, nbnxm_MakeNbnxmGPUIntoClass, pme_FEPPMEGPU. 
 Bad names: branch1234, mybranch, test, etc
 
+Labels
+======
+
+Labels <https://docs.gitlab.com/ee/user/project/labels.html>`__ help developers by allowing additional filtering of issues and merge requests.
+
+The GROMACS project `defines many labels <https://gitlab.com/gromacs/gromacs/-/labels>`__.
+
+.. Note: labeling guidelines TBD. See https://gitlab.com/gromacs/gromacs/-/issues/3949 and open new issues as appropriate.
+
+In general:
+
+* Ongoing categorizations to help specify the GROMACS component or development area use the ``#7F8C8D`` color.
+* Specific features or subproject areas targeting an upcoming release use the ``#8E44AD`` background color.
+
+When creating a new label, please provide a short description
+so that people can understand what the label is intended to convey,
+and when they should apply it to their own issues or merge requests.
+
+.. Best practices and labeling policies can be proposed as changes to this document. See https://gitlab.com/gromacs/gromacs/-/issues/3949
+
 Code Review
 ===========
 
@@ -92,7 +112,7 @@ Reviewing someone else's uploaded code
 
 The reviewing workflow is the following:
 
-#. https://gitlab.com/gromacs/gromacs/-/issues shows all open changes
+#. https://gitlab.com/gromacs/gromacs/-/merge_requests shows all open changes
 #. A change needs two approvals to go in, of which one approval has to come from
    a member of either GMX Core or GMX Developers.
 #. Usually a patch goes through several cycles of voting, commenting and
index 0ca634440c88d964655d7b962b4770f948a0daea..eed17ec2ab742b91b4f8ca8140a1c5a35a6298ff 100644 (file)
@@ -23,15 +23,15 @@ to the container registry.
 
 Steps:
 
-1. Create a `personal access token <https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html>`__
-   with ``write_registry`` scope. Save the hash!
-2. Authenticate from the command line with ``docker login registry.gitlab.com -u <token name> -p <hash>``
+1. Create a `personal access token <https://gitlab.com/-/profile/personal_access_tokens>`__ (`docs <https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html>`__)
+   with ``write_registry`` and ``read_registry`` scopes. Save the hash!
+2. Authenticate from the command line with ``docker login registry.gitlab.com -u <user name> -p <hash>``
 3. ``docker push registry.gitlab.com/gromacs/gromacs/<imagename>``
 
 Refer to :file:`buildall.sh` in the ``master`` branch for the set of images
 currently built.
 
-Within :doc:`pipeline jobs <gitlab>`, jobs specify a Docker image with the *image* property.
+Within :doc:`pipeline jobs <gitlab-ci>`, jobs specify a Docker image with the *image* property.
 For image naming convention, see :py:func:`utility.image_name`.
 Images from the GitLab registry
 are easily accessible with the same identifier as above.
index e3b4663d8201a9a53a93b96a0430b1124f53cc66..11aa14b5bff0caab8224a2f2d9a13eafb01d8b33 100644 (file)
@@ -31,8 +31,7 @@ You need to enable at least some of the following CMake options:
   to build the ``man`` target manually before installing). See
   :cmake:`GMX_BUILD_HELP`.
 
-Some documentation cannot be built if the CMake option
-``GMX_BUILD_MDRUN_ONLY`` is enabled, or when cross-compiling, as it
+Some documentation cannot be built when cross-compiling, as it
 requires executing the ``gmx`` binary.
 
 The following make targets are the most useful:
index b56bb27ca2530196e5b846345e4b86381940c4ce..4cfa632c787c1c843e9dec1f0b5a4bc411353fad 100644 (file)
 Error handling
 ==============
 
-To make |Gromacs| behave like a proper library, we need to change the
-way errors etc. are handled. Basically, the library should not print
-out anything to stdio/stderr unless it is part of the API
-specification, and even then, there should be a way for the user to
-suppress the output. Also, the library should normally not terminate
-the program without the user having control over this. There are
-different types of errors, which also affects the handling. Different
-cases are discussed separately below, split by the way they are
-handled. These guidelines are starting to take their final form,
-although details may still change.
-
-* For programming errors, i.e., errors that should never occur if the
-  program is correctly written, it's acceptable to assert and
-  terminate the program. This applies to both errors in the library
-  and errors in user code or user input that calls the library.
-  Older code tends to still use ``assert()`` calls, but new
-  code should prefer more expressive functionality such as
-  ``GMX_RELEASE_ASSERT()``. This version of the macro will result
-  in asserts that are still present when the build type is Release,
-  which is what we want by default. In performance-sensitive parts
-  of the code, it is acceptable to rather use ``GMX_ASSERT()`` to
-  avoid the performance penalty of a branch when the code is compiled
-  for production use. By default, Jenkins builds the RelWithAssert
-  build type.
-* For some errors it might be feasible to recover gracefully and
-  continue execution. In this case, your APIs should be defined
-  so that the API-user/programmer does not have to check separately
-  whether the problem was due to a programming error, but it's
-  better to e.g. use exceptions for recoverable errors and
-  asserts for programming errors.
-* Exceptions should only be used for unexpected errors, e.g., out of
+To make |Gromacs| behave like a proper library, we need to handle
+errors in a consistent and predictable way. In this section, "user"
+refers to the end user of |Gromacs| whether via some command-line
+tool, or a workflow, or a call to a public API. There are different
+types of errors, and the handling reflects this. This section is a work
+in progress, particularly as the broader C++ community is a long way
+from consensus in these areas.
+
+Brief summary on which method to use
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+More detailed rules and rationale are written below, but in short, when a reason
+exists that code is unable to do its job:
+
+* If the reason can be checked at compile-time, then use ``static_assert``.
+* If the reason is normal in context, then express that in the types used
+  (e.g. return ``std::optional``) and document that this is normal.
+* If the reason is that an internal invariant or pre-condition is violated (e.g.
+  unexpected null pointer passed) on a hot code path, then use ``GMX_ASSERT``.
+* Otherwise, if the reason is that an internal invariant or pre-condition is violated
+  then use ``GMX_RELEASE_ASSERT``.
+* Otherwise, (typically an error returned from system call or GPU SDK, bad user
+  input), then use ``GMX_THROW``.
+
+Guiding principles
+^^^^^^^^^^^^^^^^^^
+
+* |Gromacs| should adopt approaches that have achieved consensus
+  elsewhere, e.g. in the `C++ Core Guidelines
+  <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines>`_. In
+  particular, be guided by `its section on error handling
+  <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-errors>`_
+* The library should not print out anything to stdio/stderr unless it
+  is part of the API specification, and even then, there should be a
+  way for the user to suppress or redirect the output.
+* The library should normally not terminate the program without
+  the user having control over this.
+* Design interfaces of functions, classes, modules, and libraries so
+  that values passed at run time are valid. Pass const references or
+  ``not_null`` pointers rather than raw pointers. Return objects where
+  possible. Use e.g. class enums for the type of passed
+  values. Consider such enums as template parameters, rather than
+  passing run-time values. Refactor existing interfaces to improve
+  such aspects when starting new work in an area.
+* Check user input at API boundaries and establish invariants as soon
+  as possible, e.g. by expressing the user's choice in the type
+  system. These form the pre-conditions that error handling will rely
+  on.
+* Use assertions to validate invariants and pre-conditions. There is value in
+  using a different technique for checking such violations in order to make 
+  the reason for the check clear to the maintainer.
+
+Specific rules
+^^^^^^^^^^^^^^
+
+* Use ``static_assert`` wherever possible to detect errors at compile
+  time.
+* Throw *exceptions* to indicate that a function can't do its assigned
+  task, per the `C++ Core Guidelines E.2
+  <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Re-throw>`_.
+  In particular, constructors should throw when they cannot construct
+  a valid object, per `C++ Core Guidelines C.42
+  <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Re-invariant>`_.
+  However, recognize that in some cases the underlying reason is that
+  some other component has not set up the correct pre-condition, and
+  such cases should be handled with assertions (see below).
+* At API boundaries, the assigned task of some code will be to
+  validate the input, and that code should express failure to validate
+  by throwing.
+* Many programming errors violate pre-conditions of other
+  functions. Until there is language support for contracts, the best
+  that can be done is to check these with *assertions*. Note that only
+  one component should have the responsibility for validating any
+  particular input from the user, and other components should rely
+  upon that validation in their pre-conditions.
+* When asserting, use ``GMX_RELEASE_ASSERT`` by default. This macro
+  will run its check in all build configurations, including
+  ``Release``.
+* When asserting in cases where the code is called in an inner loop of
+  e.g. the MD step, ``GMX_ASSERT`` can be used. This macro will run
+  its check only when ``NDEBUG`` is not defined, including the
+  ``RelWithAssert`` build configuration (which is the default build
+  type used in CI).
+* It can be appropriate to provide both checked and unchecked
+  interfaces, as ``std::vector`` does with ``at()`` and
+  ``operator[]``, respectively. Note that even the latter is checked
+  if you build e.g. ``libstdc++`` in the right configuration!
+* When calling low-level APIs (including C and C++ standard
+  libraries, GPU SDKs) always check for success/failure. Generally the
+  correct thing to do upon failure will be to throw, perhaps including
+  a descriptive string obtained from an error code with another API
+  call.
+* Do catch exceptions from lower-level components
   memory or file system IO errors. As a general guideline, incorrect
   user input should not produce an untrapped exception resulting
   in execution termination telling the user an exception occured.
   Instead, you should catch exceptions in an earlier stack frame,
   make a suitable decision about diagnostic messages, and then
-  decide how execution should be terminated.
+  decide whether execution should be terminated (if that is in the
+  scope of the code making the decision) and, if so, how to terminate.
 * There is a global list of possible exceptions in
-  ``src/gromacs/utility/exceptions.h``, and the library should throw
-  one of these when it fails, possibly providing a more detailed
-  description of the reason for the failure. The types of exceptions
-  can be extended, and currently include:
+  ``api/legacy/include/gromacs/utility/exceptions.h``, and the library
+  should throw one of these when it fails, possibly providing a more
+  detailed description of the reason for the failure. The types of
+  exceptions can be extended, and currently include:
 
   - Out of memory (e.g. ``std::bad_alloc``)
 
@@ -63,11 +126,16 @@ although details may still change.
     avoid propagating them to caller code.
 
 * Avoid using exceptions to propagate errors across regions that start
-  or join threads with OpenMP, since OpenMP cannot make guarantees about
-  whether exceptions are caught or if the program will crash.
-  Currently we catch all exceptions before we leave an OpenMP threaded region.
-  If you throw an exception, make sure that it is caught and handled appropriately
-  in the same thread/OpenMP section.
+  or join threads with OpenMP, since OpenMP cannot make guarantees
+  about whether exceptions are caught or if the program will crash.
+  Currently we catch all exceptions before we leave an OpenMP threaded
+  region.  If you throw an exception, make sure that it is caught and
+  handled appropriately in the same thread/OpenMP section.
+* Avoid using exceptions to propagate errors within regions where
+  non-blocking API calls (e.g. to MPI or GPU SDKs) have been made,
+  because the possible advantage of catching at a higher level and
+  continuing execution is absent when the partner in the API call
+  may be left blocked.
 * There are also cases where a library routine wants to report a
   warning or a non-fatal error, but is still able to continue
   processing. In this case you should try to collect all issues and
@@ -80,5 +148,17 @@ although details may still change.
   accessing data should typically also be callable when no such data is
   available, but still return through normal means. If the failure is not
   normal, it is OK to rather throw an exception.
+* Error handling with ``gmx_fatal``, ``gmx_warning``, ``gmx_incons``,
+  ``gmx_comm`` etc.  is deprecated and should generally be refactored
+  to throw or assert according to the above guidelines.
+* There is currently no attempt made to check for error states on
+  other MPI ranks during the simulation and provide a coordinated
+  recovery. However setup code should do such checks routinely.
+* We use ``GMX_RELEASE_ASSERT`` and ``GMX_ASSERT`` rather
+  than ``assert`` to ensure that non-immediate strings can be
+  used to describe the problem when the error is reported.
+  This is particularly useful when troubleshooting issues where
+  missing test coverage leads users to uncover such errors.
 
+  
 For coding guidelines to make this all work, see :ref:`implementing exceptions`.
similarity index 99%
rename from docs/dev-manual/gitlab.rst
rename to docs/dev-manual/gitlab-ci.rst
index 3c5dda31de7c3e62440304fa019da8f8c61eac44..6f12994ed669e556a70bf8306d67912363adfffa 100644 (file)
@@ -59,7 +59,7 @@ GitLab CI job parameters, but note the following GROMACS-specific conventions.
         Avoid using *before-script* directly, and be cautious
         about nested *extends* overriding multiple *before_script* definitions.
 
-    cache
+    job cache
         There is no global default, but jobs that build software will likely
         set *cache*. To explicitly unset *cache* directives, specify a job
         parameter of ``cache: {}``.
index 565c62325bbb6d4206079ec7ea9b7606546f87cf..44bf4b9c3e965d7f6f64c0468d6e7d40b2f49f52 100644 (file)
@@ -153,18 +153,6 @@ issue does not have a file name (or a pseudo-file) associated, a leading ``:``
 must be added.  To cover many similar issues, parts of the line can then be
 replaced with wildcards.
 
-A separate suppression mechanism is in place for cyclic dependencies: to
-suppress a cycle between moduleA and moduleB, add a line with format ::
-
-    moduleA -> moduleB
-
-into ``doxygen/cycle-suppressions.txt``.  This suppresses all cycles that contain
-the mentioned edge.  Since a cycle contains multiple edges, the suppression
-should be made for the edge that is determined to be an incorrect dependency.
-This also affects the layout of the include dependency graphs (see below): the
-suppressed edge is not considered when determining the dependency order, and is
-shown as invalid in the graph.
-
 .. _dev-include-sorter:
 
 Include order sorting
index 5c2b890297d97e3d2e2b92f81b2e89d319aa38b8..ece8fbaf1ac9b363fee6e885c2722600cc0c6294 100644 (file)
@@ -7,8 +7,8 @@ between each group, and headers within each group sorted alphabetically.
 1. Each *source* file should include ``gmxpre.h`` first.
 2. If a *source* file has a corresponding header, it should be included next.
    If the header is in the same directory as the source, then it is included
-   without any path (i.e., relative to the source), otherwise relative to
-   ``src/`` (the latter case should be rare).
+   without any path (i.e., relative to the source). Otherwise, the canonical
+   include path of ``libraryname/modulename/header.h`` is used.
 3. If the file depends on defines from ``config.h``, that comes next.
 4. This is followed by standard C/C++ headers, grouped as follows:
 
@@ -23,15 +23,11 @@ between each group, and headers within each group sorted alphabetically.
    ``<gtest/gtest.h>``.
 6. |Gromacs|-specific libraries from ``src/external/``, such as
    ``"thread_mpi/threads.h"``.
-7. |Gromacs|-specific headers that are not internal to the including module,
-   included with a path relative to ``src/``.
-8. In *test* files, headers not internal to the module, but specific to
-   testing code, are in a separate block at this point, paths relative to
-   ``src/``.
-9. Finally, |Gromacs| headers that are internal to the including module are
-   included using a relative path (but never with a path starting with ``../``;
-   such headers go into group 7 instead).  For test files, this group contains
-   headers that are internal to tests for that module.
+7. |Gromacs| headers that are not part of the including module.
+8. Public |Gromacs| headers that are part of the including module.
+9. Finally, |Gromacs| headers that are internal to the including module,
+   executable, or test target
+   (typically at the same path as the source file).
 
 All |Gromacs| headers are included with quotes (``"gromacs/utility/path.h"``),
 other headers with angle brackets (``<stdio.h>``).  Headers under ``src/external/``
@@ -48,20 +44,11 @@ is up to the author of the code to put the headers in proper order in such
 cases.  Trailing comments on the same line as #include statements are
 preserved and do not affect the checker/sorter.
 
-The includestyle used to differentiate between header files that were declared
-to be part of the module and not used outside the module, and those that were
-either not part of a module, used in other modules, or installed.
-As the possibility of installation has been removed (for now), changes to the
-previous organization might occur where such installed files were implicitly
-marked as being used outside of a module even though they were not used within
-|Gromacs| outside their module.
-
 As part of the effort to build a proper API, a new scheme of separating between
 public, library and module functionality in header files is planned.
-
-The guidelines are enforced by an automatic checker script that can also
-sort/reformat include statements to follow the guidelines.
-See :doc:`gmxtree` for details.
+See also :doc:`gmxtree` and
+`API restructuring issues <https://gitlab.com/gromacs/gromacs/-/issues?label_name%5B%5D=API+restructuring>`__
+for details.
 
 Enforcing a consistent order and style has a few advantages:
 
@@ -73,7 +60,7 @@ Enforcing a consistent order and style has a few advantages:
   first.  With this order, the person working on the header is most likely to
   see these problems instead of someone else seeing them later when
   refactoring unrelated code.
-* Consistent usage of paths in #include directives makes it easy to use
+* Consistent usage of paths in ``#include`` directives makes it easy to use
   ``grep`` to find all uses of a header, as well as all include dependencies
   between two modules.
 * An automatic script can be used to re-establish clean code after
index 535a6888ae3d040e8c005a184fabea3c0a1a62bc..fd8c25e58c24a464c41b33ad667a9672cc30213b 100644 (file)
@@ -10,6 +10,6 @@ performed by a Jenkins installation. With the resolution of :issue:`3272`,
     :maxdepth: 2
 
     jenkins
-    gitlab
+    gitlab-ci
     containers
 
index e0fb2d6deca5152730de3abe9d6b0f8b6c1b0ed3..89985e7db2aeb87d736d383c2bb87e3d9c3f21d4 100644 (file)
@@ -89,8 +89,9 @@ C++ code
 * Member variables are named with a trailing underscore.
 * Accessors for a variable ``foo_`` are named ``foo()`` and ``setFoo()``.
 * Global variables are named with a ``g_`` prefix.
-* Static class variables are named with a ``s_`` prefix.
-* Static ``constexpr`` class members are named with a ``sc_`` prefix.
+* Global and file-static variables are named with a ``g_`` prefix.
+* Static class and function variables are named with an ``s_`` prefix.
+* Static ``constexpr`` file, class, or function members are named with a ``sc_`` prefix.
 * Global constants are often named with a ``c_`` prefix.
 * If the main responsibility of a file is to implement a particular class,
   then the name of the file should match that class, except for possible
@@ -105,6 +106,7 @@ C++ code
   typically including a verb for boolean variables, like ``foundAtom``.
 * Prefer class enums over regular ones, so that unexpected conversions to
   int do not happen.
+* Name functions to convert class enum values to strings as ``enumValueToString``.
 * When using a non-class enum, prefer to include the name of the enumeration type
   as a base in the name of enum values, e.g., ``HelpOutputFormat_Console``,
   in particular for settings exposed to other modules.
index e9bf4c8baa7d5a67cd370c51718ec9191ca3953a..fcb10ded11245bc2172c28d006f925faca97f5e1 100644 (file)
@@ -44,11 +44,10 @@ Source code organization
 
 The following figure shows a high-level view of components of what gets built
 from the source code under :file:`src/` and how the code is organized.
+Arrows indicate the direction of dependencies.
 The build system is described in detail in :doc:`build-system`.
 With default options, the green and white components are built as part of the
-default target.  If ``GMX_BUILD_MDRUN_ONLY`` is ``ON``, then the blue and white
-components are built instead; :file:`libgromacs_mdrun` is built from a subset
-of the code used for :file:`libgromacs`.
+default target.
 The gray parts are for testing, and are by default only built as part of the
 ``tests`` target, but if ``GMX_DEVELOPER_BUILD`` is ``ON``, then these are
 included in the default build target.
@@ -65,7 +64,7 @@ See :doc:`testutils` for details of the testing side.
        label="externals\nsrc/external/", group=common, style=rounded
      ]
      gtest [
-       label="Google Test & Mock\nsrc/external/gmock-1.7.0/", group=test
+       label="Google Test & Mock\nsrc/external/googletest/", group=test
        style="rounded,filled", fillcolor="0 0 0.9"
      ]
    }
@@ -74,25 +73,16 @@ See :doc:`testutils` for details of the testing side.
      libgromacs [
        label="libgromacs\nsrc/gromacs/", group=gmx, fillcolor="0.33 0.3 1"
      ]
-     libgromacs_mdrun [
-       label="libgromacs_mdrun\nsrc/gromacs/", group=mdrun, fillcolor="0.66 0.3 1"
-     ]
    }
    testutils [
      label="testutils\nsrc/testutils/", group=test
      style="rounded,filled", fillcolor="0 0 0.9"
    ]
-   mdrun_objlib [
-     label="mdrun object lib.\nsrc/programs/mdrun/", group=common, style=rouded
-   ]
    subgraph {
      rank = same
      gmx [
        label="gmx\nsrc/programs/", group=gmx, fillcolor="0.33 0.3 1"
      ]
-     mdrun [
-       label="mdrun\nsrc/programs/", group=mdrun, fillcolor="0.66 0.3 1"
-     ]
      tests [
        label="test binaries\nsrc/.../tests/", group=test
        style="rounded,filled", fillcolor="0 0 0.9"
@@ -103,28 +93,18 @@ See :doc:`testutils` for details of the testing side.
      ]
 
      gmx -> template [ style=invis, constraint=no ]
-     template -> mdrun [ style=invis, constraint=no ]
    }
 
    libgromacs -> externals
-   libgromacs_mdrun -> externals
-   mdrun_objlib -> libgromacs
    gmx -> libgromacs
-   gmx -> mdrun_objlib
-   mdrun -> libgromacs_mdrun
-   mdrun -> mdrun_objlib
    testutils -> externals
    testutils -> gtest
    testutils -> libgromacs
    tests -> gtest
    tests -> libgromacs
-   tests -> mdrun_objlib
    tests -> testutils
    template -> libgromacs
 
-   template -> mdrun_objlib [ style=invis ]
-   mdrun_objlib -> externals [ style=invis ]
-
 All the source code (except for the analysis template) is under the
 :file:`src/` directory.  Only a few files related to the build system are
 included at the root level.  All actual code is in subdirectories:
@@ -135,9 +115,10 @@ included at the root level.  All actual code is in subdirectories:
   This is the main part of the code, and is organized into further subdirectories
   as *modules*.  See below for details.
 :file:`src/programs/`
-  |Gromacs| executables are built from code under this directory.
-  Although some build options can change this, there is typically only a single
-  binary, :file:`gmx`, built.
+  The |Gromacs| executable ``gmx`` is built from code under this directory.
+  Also found here is some of the driver code for the ``mdrun`` module called
+  by ``gmx``, the whole of the ``gmx view`` visualization module, and numerous
+  end-to-end tests of ``gmx mdrun``.
 
 :file:`src/{...}/tests/`
   Various subdirectories under :file:`src/` contain a subdirectory named
@@ -201,8 +182,6 @@ source files, include only headers from other modules that are
 necessary for that file. You can use the public API header if you
 really require everything declared in it.
 
-intra-module/intra-file.
-
 See :doc:`naming` for some common naming patterns for files that can help
 locating declarations.
 
index c6f7d6f3c58a00f734453ab0dc8fb536a0d0c2c0..1c4d7efdaa6c33a961ae8806a0e6531e62286218 100644 (file)
@@ -77,6 +77,20 @@ coverage
 
 regression tests
 
+floating-point exceptions
+  In debug builds, floating-point exceptions (FPEs) are generated whenever one of the
+  following operations is encountered: division by zero, floating-point overflow,
+  invalid operation (e.g., taking sqrt of a negative number).
+  Such checks are *not* performed in the following configurations:
+
+  - release build,
+  - any build by GCC 7.x or Clang with optimizations,
+  - build with SYCL support.
+
+  In these configurations, FPEs can be enabled by adding ``-fpexcept`` flag to ``gmx``
+  invocation. However, FPEs are not supported on Windows and non-x86 Apple hardware.
+  See ``api/legacy/include/gromacs/math/utilities.h`` for more details.
+
 .. _dev-formatting-tools:
 
 Code formatting and style
index 99ab6d665c61ccfb2dad7b3e35502006df5ee3fb..232adc044b70e9dd631fe1a3b545f4b7aee5a7e0 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
-# Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,13 +168,11 @@ if (DOXYGEN_FOUND)
             COMMAND ${Python3_EXECUTABLE}
                 ${CMAKE_CURRENT_SOURCE_DIR}/graphbuilder.py
                 -S ${CMAKE_SOURCE_DIR} -B ${CMAKE_BINARY_DIR}
-                --ignore-cycles ${CMAKE_CURRENT_SOURCE_DIR}/cycle-suppressions.txt
                 -o ${DEPGRAPH_DIR}
             DEPENDS doxygen-xml ${INSTALLED_HEADER_FILE}
                 ${CMAKE_CURRENT_SOURCE_DIR}/doxygenxml.py
                 ${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"
             USES_TERMINAL)
 
@@ -215,8 +213,7 @@ if (DOXYGEN_FOUND)
             ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/check-source.py
             -S ${CMAKE_SOURCE_DIR} -B ${CMAKE_BINARY_DIR}
             -l ${CMAKE_CURRENT_BINARY_DIR}/check-source.log
-            --ignore ${CMAKE_CURRENT_SOURCE_DIR}/suppressions.txt
-            --ignore-cycles ${CMAKE_CURRENT_SOURCE_DIR}/cycle-suppressions.txt)
+            --ignore ${CMAKE_CURRENT_SOURCE_DIR}/suppressions.txt)
         add_custom_target(check-source      COMMAND ${check_source_command}
             COMMENT "Checking source code for various issues" VERBATIM USES_TERMINAL)
         add_custom_target(check-source-fast COMMAND ${check_source_command}
index d713ea9b564995041de8233d033bf44b584f67fd..e9cc7b858ce89759830c8a50c75edbbf48e17480 100644 (file)
@@ -3,6 +3,7 @@ PROJECT_NAME           = @CMAKE_PROJECT_NAME@
 LAYOUT_FILE            = @CMAKE_CURRENT_SOURCE_DIR@/DoxygenLayout.xml
 INPUT                  = @CMAKE_CURRENT_SOURCE_DIR@ \
                          @CMAKE_SOURCE_DIR@/src \
+                         @CMAKE_SOURCE_DIR@/api/legacy/include \
                          @CMAKE_SOURCE_DIR@/share/template
 FILE_PATTERNS          = *.c *.cpp *.h *.md
 # CUDA files could be included like this, but currently produce a lot of
@@ -29,7 +30,10 @@ EXCLUDE_SYMBOLS       += TEST TEST_F TEST_P TYPED_TEST_CASE TYPED_TEST INSTANTIA
 EXCLUDE_SYMBOLS       += MOCK_METHOD* MOCK_CONST_METHOD*
 FULL_PATH_NAMES        = YES
 STRIP_FROM_PATH        = @CMAKE_SOURCE_DIR@
-STRIP_FROM_INC_PATH    = @CMAKE_SOURCE_DIR@/src
+STRIP_FROM_INC_PATH    = @CMAKE_SOURCE_DIR@/src \
+                         @CMAKE_SOURCE_DIR@/src/include \
+                         @CMAKE_SOURCE_DIR@/src/gromacs/*/include \
+                         @CMAKE_SOURCE_DIR@/api/legacy/include
 INCLUDE_PATH           = @CMAKE_SOURCE_DIR@/src
 HAVE_DOT               = @DOXYGEN_DOT_FOUND@
 DOT_PATH               = @DOXYGEN_DOT_PATH@
index 8790eb6a1780d01893a2ea9155232f71981193f5..e2a11cfe1cd9140744342707562c9866b3be100f 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2014,2015,2018,2019, by the GROMACS development team, led by
+# Copyright (c) 2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,166 +193,24 @@ def check_member(member, reporter, check_ignored):
         if member.has_inbody_description():
             reporter.doc_note(member, "has in-body comments, which are ignored")
 
-def check_cycles(graph, reporter):
-    """Check cyclic dependencies in a dependency graph.
-
-    The graph parameter provides the graph to check.  It should be an object
-    that has three methods:
-      iternodes():
-        Return the list of nodes in the graph.
-      iteredges(node):
-        Return the list of edges from a given node.
-        The list should contain (node, edge) pairs, where node is an object
-        returned by iternodes() and edge is any object.
-      report_cycle(cycle, reporter):
-        Process a found cycle. cycle contains a list of (node, edge) pairs
-        that describe the cycle.  edge is the edge object that leads _to_
-        the node in the cycle.
-
-    This is implemented using an extended DFS-based strongly connected
-    component (SCC) search, written using a stack instead of recursion.
-    The base algorithm is Tarjan's SCC search:
-      http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm
-
-    Each back edge that is encountered during the search is reported as a
-    cycle.  Additionally, if a cross edge is encountered that is within the
-    current SCC, the target node and all its children in the current SCC will
-    be visited again to find all cycles.  All steps except cycle detection are
-    omitted for such re-traversal.
-
-    To avoid duplicates from cycles that do not include all nodes in an SCC,
-    a cycle is only reported if the target of the back edge is still active
-    in the search, i.e., all edges from it have not yet been traversed.
-    """
-    # The DFS stack; next node is always popped from the end.
-    # Stores (node, edge) pairs.
-    # edge is None for start nodes and for post-order processing.
-    dfsstack = []
-    for node in graph.iternodes():
-        dfsstack.append((node, None))
-    # Stack of visited nodes that have not yet been assigned to a strongly
-    # connected component.
-    visitstack = []
-    # List of nodes in the DFS recursion stack.
-    currlist = []
-    # Set of nodes in currlist for more efficient searching.
-    currset = set()
-    # Counter for initializing preorder.
-    visit_count = 0
-    # DFS pre-order for nodes: initialized when a node is first encountered
-    # in the search.
-    preorder = dict()
-    # Lowest pre-order index reachable from this node.
-    # Initialized to pre-order, and updated during post-order processing.
-    linkorder = dict()
-    # Set to True for a node when first encountered, and set to False when
-    # a strongly connected component has been processed.
-    in_progress = dict()
-    # The DFS search
-    while dfsstack:
-        currnode, curredge = dfsstack.pop()
-        # curredge is None if this is a start node or post-order traversal.
-        # currlist is empty if this is a start node.
-        if curredge is None and currlist:
-            # All children visited: post-order processing.
-            done = currlist.pop()[0]
-            assert done == currnode
-            currset.remove(currnode)
-            # If this is the first time this node is encountered, fill
-            # linkorder and check for strongly connected components.
-            if linkorder[currnode] == preorder[currnode]:
-                children = [x for x, dummy in graph.iteredges(currnode) if in_progress[x]]
-                if children:
-                    linkorder[currnode] = min([linkorder[x] for x in children])
-                if preorder[currnode] <= linkorder[currnode]:
-                    # This is a root of a strongly connected component.
-                    while visitstack:
-                        node = visitstack.pop()
-                        in_progress[node] = False
-                        if node == currnode:
-                            break
-                    else:
-                        assert False
-            continue
-        if currnode not in preorder:
-            # First encounter of this node: pre-order processing.
-            preorder[currnode] = visit_count
-            linkorder[currnode] = visit_count
-            visitstack.append(currnode)
-            visit_count += 1
-            in_progress[currnode] = True
-        elif not in_progress[currnode]:
-            # Do not enter processed components again.
-            continue
-        currlist.append((currnode, curredge))
-        currset.add(currnode)
-        # add entry for post-order traversal
-        dfsstack.append((currnode, None))
-        for nextnode, edge in graph.iteredges(currnode):
-            if nextnode not in preorder:
-                # Not seen previously: push
-                dfsstack.append((nextnode, edge))
-            else:
-                # If an already visited node is in the same component, it is
-                # either part of a cycle, or we need to traverse it again to
-                # find all cycles.
-                if in_progress[nextnode]:
-                    if nextnode not in currset:
-                        dfsstack.append((nextnode, edge))
-                    # Only report cycles to nodes that haven't been processed
-                    # yet to avoid duplicates.
-                    elif linkorder[nextnode] == preorder[nextnode]:
-                        for index, node in enumerate(currlist):
-                            if node[0] == nextnode:
-                                cycle = [(nextnode, edge)]
-                                cycle.extend(currlist[index+1:])
-                                graph.report_cycle(cycle, reporter)
-                                break
-                        else:
-                            assert False
-
-class ModuleDependencyGraph(object):
-
-    """Module dependency graph representation for check_cycles().
-
-    In the reported graph, the nodes are gmxtree.Module objects and the edges
-    are gmxtree.ModuleDependency objects.
-    """
-
-    def __init__(self, tree):
-        self._tree = tree
-
-    def iternodes(self):
-        return self._tree.get_modules()
-
-    def iteredges(self, module):
-        for dependency in module.get_dependencies():
-            if not dependency.is_test_only_dependency():
-                yield (dependency.get_other_module(), dependency)
-
-    def report_cycle(self, cycle, reporter):
-        if any([x[1].is_cycle_suppressed() for x in cycle]):
-            # TODO: Report unused suppressions.
-            return
-        modulelist = ' -> '.join([x[0].get_name()[7:] for x in cycle])
-        summary = 'module-level cyclic dependency: ' + modulelist
-        reporter.cyclic_issue(summary)
-
 def check_all(tree, reporter, check_ignored):
     """Do all checks for the GROMACS tree."""
-    includesorter = IncludeSorter()
-    for fileobj in tree.get_files():
-        if isinstance(fileobj, gmxtree.GeneratorSourceFile):
-            continue
-        check_file(fileobj, tree, reporter)
-        for includedfile in fileobj.get_includes():
-            check_include(fileobj, includedfile, reporter)
-        if fileobj.should_includes_be_sorted():
-            is_sorted, details = includesorter.check_sorted(fileobj)
-            if not is_sorted:
-                details.append("You can use includesorter.py to do the sorting automatically; see docs/dev-manual/gmxtree.rst")
-                reporter.code_issue(fileobj,
-                        "include style/order is not consistent; see docs/dev-manual/includestyle.rst", details)
+    # Include sorting is disabled pending resolution of
+    # https://gitlab.com/gromacs/gromacs/-/issues/3288 and
+    # https://gitlab.com/gromacs/gromacs/-/issues/3659
+    # includesorter = IncludeSorter()
+    # for fileobj in tree.get_files():
+    #     if isinstance(fileobj, gmxtree.GeneratorSourceFile):
+    #         continue
+    #     check_file(fileobj, tree, reporter)
+    #     for includedfile in fileobj.get_includes():
+    #         check_include(fileobj, includedfile, reporter)
+    #     if fileobj.should_includes_be_sorted():
+    #         is_sorted, details = includesorter.check_sorted(fileobj)
+    #         if not is_sorted:
+    #             details.append("You can use includesorter.py to do the sorting automatically; see docs/dev-manual/gmxtree.rst")
+    #             reporter.code_issue(fileobj,
+    #                     "include style/order is not consistent; see docs/dev-manual/includestyle.rst", details)
 
     for classobj in tree.get_classes():
         check_class(classobj, reporter)
@@ -360,9 +218,6 @@ def check_all(tree, reporter, check_ignored):
     for memberobj in tree.get_members():
         check_member(memberobj, reporter, check_ignored)
 
-    check_cycles(ModuleDependencyGraph(tree), reporter)
-    tree.report_unused_cycle_suppressions(reporter)
-
 def main():
     """Run the checking script."""
     parser = OptionParser()
@@ -374,8 +229,6 @@ def main():
                       help='Write issues into a given log file in addition to stderr')
     parser.add_option('--ignore',
                       help='Set file with patterns for messages to ignore')
-    parser.add_option('--ignore-cycles',
-                      help='Set file with module dependencies to ignore in cycles')
     parser.add_option('--check-ignored', action='store_true',
                       help='Issue notes for comments ignored by Doxygen')
     parser.add_option('-q', '--quiet', action='store_true',
@@ -399,8 +252,6 @@ def main():
     if not options.quiet:
         sys.stderr.write('Finding config.h and other preprocessor macro uses...\n')
     tree.find_define_file_uses()
-    if options.ignore_cycles:
-        tree.load_cycle_suppression_list(options.ignore_cycles)
     if not options.quiet:
         sys.stderr.write('Reading Doxygen XML files...\n')
     tree.load_xml()
diff --git a/docs/doxygen/cycle-suppressions.txt b/docs/doxygen/cycle-suppressions.txt
deleted file mode 100644 (file)
index ad53e6c..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-# Order (or more generally, edge selection) is significant (see gmxtree.md);
-# "moduleA -> moduleB" means that moduleA should not depend on moduleB, and is
-# a problem to be addressed at some point.
-
-domdec -> imd
-domdec -> ewald
-domdec -> mdlib
-domdec -> pulling
-fileio -> gmxlib
-mdlib -> essentialdynamics
-mdlib -> imd
-mdlib -> ewald
-mdlib -> pulling
-nbnxm -> domdec
-nbnxm -> mdlib
-simd -> hardware
-gpu_utils -> hardware
-listed_forces -> mdlib
-utility -> math
-
-# modular simulator uses shellfc from mdrun, but is later included in mdrun by simulator builder
-modularsimulator -> mdrun
-
-# Cycle counters in timing use comrec for the set up, which is in the mdtypes. This introduces
-# cyclic dependencies if the cycle counting is used anywhere in mdtypes.
-timing -> mdtypes
-
-# awh has dependencies in mdlib and pulling that need resolving.
-mdlib -> applied_forces
index 9d6ea6bf9c54bc48a390687c3365f46c11dac6b8..f3c7be022c3647922828a5e3adb4f9e16b217ed0 100644 (file)
@@ -162,17 +162,17 @@ and local atom sets by subscribing to callback functions.
 To include a notification for your module
 
 * Add the function signature for the callback function to the
-  `MdModulesNotifier` in `mdmodulenotification.h`,
+  `MDModulesNotifiers` in `mdmodulesnotifiers.h`,
 
   ```C++
-    registerMdModulesNotification<...,
+    BuildMDModulesNotifier<...,
                       YourCallbackSignature,
                       ...,
   ```
 
   (keep alphabetical order for ease of git merge)
 
-* Hand the notifier_ member of the MdModules Implementation class to your
+* Hand the notifier_ member of the MDModules Implementation class to your
   builder createYourModule(&notifier_)
 
 * Add the function you want to subscribe with in the builder,
index c5f73730fa03dc6a74ae37feff3e7456e3cff5cb..52d7e98d0fb5df597577563389d9b80200c1cd58 100644 (file)
@@ -200,13 +200,14 @@ the simulator algorithm.
             builder->add<ForceElement>();
              // We have a full state here (positions(t), velocities(t-dt/2), forces(t)
             builder->add<StatePropagatorData::Element>();
-            if (legacySimulatorData_->inputrec->etc == etcVRESCALE)
+            if (legacySimulatorData_->inputrec->etc == TemperatureCoupling::VRescale)
             {
-                builder->add<VRescaleThermostat>(-1, VRescaleThermostatUseFullStepKE::No);
+                builder->add<VRescaleThermostat>(-1,
+                                                 VRescaleThermostatUseFullStepKE::No,
+                                                 PropagatorTag("LeapFrogPropagator"));
             }
-            builder->add<Propagator<IntegrationStep::LeapFrog>>(legacySimulatorData_->inputrec->delta_t,
-                                                                RegisterWithThermostat::True,
-                                                                RegisterWithBarostat::True);
+            builder->add<Propagator<IntegrationStage::LeapFrog>>(PropagatorTag("LeapFrogPropagator"),
+                                                                legacySimulatorData_->inputrec->delta_t);
             if (legacySimulatorData_->constr)
             {
                 builder->add<ConstraintsElement<ConstraintVariable::Positions>>();
@@ -214,9 +215,9 @@ the simulator algorithm.
             builder->add<ComputeGlobalsElement<ComputeGlobalsAlgorithm::LeapFrog>>();
             // We have the energies at time t here
             builder->add<EnergyData::Element>();
-            if (legacySimulatorData_->inputrec->epc == epcPARRINELLORAHMAN)
+            if (legacySimulatorData_->inputrec->epc == PressureCoupling::ParrinelloRahman)
             {
-                builder->add<ParrinelloRahmanBarostat>(-1);
+                builder->add<ParrinelloRahmanBarostat>(-1, PropagatorTag("LeapFrogPropagator"));
             }
         }
     }
@@ -545,7 +546,15 @@ Currently, the (templated) implementation covers four cases:
     time step of PositionsOnly.
 
 The propagators also allow to implement temperature and pressure coupling
-schemes by offering (templated) scaling of the velocities.
+schemes by offering (templated) scaling of the velocities. In order to
+link temperature / pressure coupling objects to the propagators, the
+propagator objects have a tag (of strong type `PropagatorTag`). The
+temperature and pressure coupling objects can then connect to the
+matching propagator by comparing their target tag to the different
+propagators. Giving the propagators their tags and informing the
+temperature and pressure coupling algorithms which propagator they are
+connecting to is in the responsibility of the simulation algorithm
+builder.
 
 #### `CompositeSimulatorElement`
 The composite simulator element takes a list of elements and implements
@@ -716,7 +725,7 @@ with the XDR library. The alternative would be to write an entirely new data
 structure, changing the function signature of all checkpoint-related functions,
 and write a corresponding low-level routine interacting with the XDR library.
 
-**The MdModule approach:** To allow for modules to write checkpoints, the legacy
+**The MDModule approach:** To allow for modules to write checkpoints, the legacy
 checkpoint was extended by a KVTree. When writing to checkpoint, this tree gets
 filled (via callbacks) by the single modules, and then serialized. When reading,
 the KVTree gets deserialized, and then distributed to the modules which can read
@@ -724,7 +733,7 @@ back the data previously stored.
 
 ##### Modular simulator design
 
-The MdModule checks off almost all requirements to a modularized checkpointing format.
+The MDModule checks off almost all requirements to a modularized checkpointing format.
 The proposed design is therefore an evolved form of this approach. Notably, two
 improvements include
 * Hide the implementation details of the data structure holding the data (currently,
@@ -784,13 +793,13 @@ if clients write self-consistent read and write code, this should never be neede
 Checking for key existence seems rather to be a lazy way to circumvent versioning,
 and is therefore discouraged.
 
-**Callback method:** The modular simulator and MdModules don't use the exact same
+**Callback method:** The modular simulator and MDModules don't use the exact same
 way of communicating with clients. The two methods could be unified if needed.
 The only _fundamental_ difference is that modular simulator clients need to identify
-with a unique key to receive their dedicated sub-data, while MdModules all read from
-and write to the same KV-tree. MdModules could be adapted to that by either requiring
+with a unique key to receive their dedicated sub-data, while MDModules all read from
+and write to the same KV-tree. MDModules could be adapted to that by either requiring
 a unique key from the modules, or by using the same `CheckpointData` for all modules
-and using a single unique key (something like "MdModules") to register that object
+and using a single unique key (something like "MDModules") to register that object
 with the global checkpoint.
 
 **Performance:** One of the major differences between the new approach and the legacy
index 1363f3728f5443f56adf4af1a94c87cf2effa3b6..a1a6d53e121fac817df33482b3541de176218b88 100644 (file)
@@ -52,7 +52,7 @@ and for this reason they are part of the SIMD implementation.
 Finally, for some architectures with large or very large SIMD width (e.g. AVX
 with 8 elements in single precision, or AVX-512 with 16), the nonbonded
 kernels can become inefficient. Since all such architectures presently known
-(AVX, AVX2, MIC, AVX512) also provide extensive support for accessing
+(AVX, AVX2, AVX512) also provide extensive support for accessing
 parts of the register, we optionally define a handful of routines to
 perform load, store, and reduce operations based on half-SIMD-width data,
 which can improve performance. It is only useful for wide implementations,
index a6538a629f163f194e75486586a409382fbb6cd7..c32d4efeeadcedf9f2ac8aca5ea8427286a1b889 100644 (file)
@@ -1,63 +1,71 @@
-# The script is currently a bit too eager
-share/template/template.cpp: error: source file documentation appears outside full documentation
-# The parser in the script is not clever enough
-src/gromacs/version.h: warning: includes local file as <gromacs/version.h>
-
-# These are OK
-src/gromacs/linearalgebra/eigensolver.cpp: warning: should include "config.h"
-src/gromacs/linearalgebra/gmx_arpack.cpp: warning: should include "config.h"
-src/gromacs/linearalgebra/gmx_blas/*: warning: does not include "gmxpre.h" first
-src/gromacs/linearalgebra/gmx_blas/*: warning: should include "config.h"
-src/gromacs/linearalgebra/gmx_lapack/*: warning: does not include "gmxpre.h" first
-src/gromacs/linearalgebra/gmx_lapack/*: warning: should include "config.h"
-src/gromacs/utility/baseversion-gen.cpp: warning: does not include "gmxpre.h" first
-
-# Exclude header files that are used for inlining code; the responsibility for
-# making the right #includes should be on the source file that uses these.
-# TODO: # Stop using the preprocessor for meta-programming!
-src/gromacs/ewald/pme_simd4.h: warning: should include "pme_simd.h"
-src/gromacs/ewald/pme_spline_work.cpp: warning: includes "simd.h" unnecessarily
-src/gromacs/ewald/pme_spline_work.h: warning: includes "simd.h" unnecessarily
-src/gromacs/ewald/pme_spread.cpp: warning: includes "simd.h" unnecessarily
-src/gromacs/nbnxm/boundingboxes.h: warning: includes "simd.h" unnecessarily
-src/gromacs/nbnxm/kernels_simd_2xmm/kernel_inner.h: warning: should include "simd.h"
-src/gromacs/nbnxm/kernels_simd_2xmm/kernel_outer.h: warning: should include "simd.h"
-src/gromacs/nbnxm/kernels_simd_4xm/kernel_inner.h: warning: should include "simd.h"
-src/gromacs/nbnxm/kernels_simd_4xm/kernel_outer.h: warning: should include "simd.h"
-src/gromacs/nbnxm/pairlist_simd_2xmm.h: warning: should include "simd.h"
-src/gromacs/nbnxm/pairlist_simd_4xm.h: warning: should include "simd.h"
-
-# This module name doesn't really fall into any currently used pattern; needs some thought
-: error: no matching directory for module: module_mdrun_integration_tests
-
-# These would be nice to fix, but can wait for later / deletion / rewrites
-src/gromacs/nbnxm/kernels_simd_2xmm/kernel_common.h: warning: should include "nbnxm_simd.h"
-src/gromacs/nbnxm/kernels_simd_4xm/kernel_common.h: warning: should include "nbnxm_simd.h"
-
 # This seems to be a false positive
 src/gromacs/nbnxm/cuda/nbnxm_cuda_types.h: error: NbnxmGpu: is in internal file(s), but appears in public documentation
 
+# doxygen has problems with the template construct in this file
+src/gromacs/modularsimulator/signallers.h: error: build: is documented, but does not have brief description
+
 # False positive caused by forward-declaration of BasicVector in src/testutils/refdata.h
-src/gromacs/math/vectypes.h: error: gmx::BasicVector: is in library file(s), but appears in public documentation
+src/testutils/refdata.h: error: gmx::BasicVector: is in library file(s), but appears in public documentation
 
-# Temporary while we change the SIMD implementation
-src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace_common.h: warning: should include "simd.h"
+#
+# All following suppressions are disabled while the include checker
+# is temporarily disabled pending resolution of
+# https://gitlab.com/gromacs/gromacs/-/issues/3288 and
+# https://gitlab.com/gromacs/gromacs/-/issues/3659
+#
 
-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
+# # The script is currently a bit too eager
+# share/template/template.cpp: error: source file documentation appears outside full documentation
+# # The parser in the script is not clever enough
+# src/gromacs/version.h: warning: includes local file as <gromacs/version.h>
 
-# These are specific to Folding@Home, and easiest to suppress here
-src/gmxpre.h: warning: includes non-local file as "swindirect.h"
+# # These are OK
+# src/gromacs/linearalgebra/eigensolver.cpp: warning: should include "config.h"
+# src/gromacs/linearalgebra/gmx_arpack.cpp: warning: should include "config.h"
+# src/gromacs/linearalgebra/gmx_blas/*: warning: does not include "gmxpre.h" first
+# src/gromacs/linearalgebra/gmx_blas/*: warning: should include "config.h"
+# src/gromacs/linearalgebra/gmx_lapack/*: warning: does not include "gmxpre.h" first
+# src/gromacs/linearalgebra/gmx_lapack/*: warning: should include "config.h"
+# src/gromacs/utility/baseversion-gen.cpp: warning: does not include "gmxpre.h" first
 
-# New external API (see https://gitlab.com/gromacs/gromacs/-/issues/2586) has some unresolved
-# conflicts with previous definitions of public API, installed API, and other things
-# described or implemented in check-source.py, gmxtree.py, gmxtree.rst, and others
-# TODO: resolve definitions, update testing heuristics, and activate policy checks
-# for src/api/cpp files.
-src/api/cpp/*: *
+# # Exclude header files that are used for inlining code; the responsibility for
+# # making the right #includes should be on the source file that uses these.
+# # TODO: # Stop using the preprocessor for meta-programming!
+# src/gromacs/ewald/pme_simd4.h: warning: should include "pme_simd.h"
+# src/gromacs/ewald/pme_spline_work.cpp: warning: includes "simd.h" unnecessarily
+# src/gromacs/ewald/pme_spline_work.h: warning: includes "simd.h" unnecessarily
+# src/gromacs/ewald/pme_spread.cpp: warning: includes "simd.h" unnecessarily
+# src/gromacs/nbnxm/boundingboxes.h: warning: includes "simd.h" unnecessarily
+# src/gromacs/nbnxm/kernels_simd_2xmm/kernel_inner.h: warning: should include "simd.h"
+# src/gromacs/nbnxm/kernels_simd_2xmm/kernel_outer.h: warning: should include "simd.h"
+# src/gromacs/nbnxm/kernels_simd_4xm/kernel_inner.h: warning: should include "simd.h"
+# src/gromacs/nbnxm/kernels_simd_4xm/kernel_outer.h: warning: should include "simd.h"
+# src/gromacs/nbnxm/pairlist_simd_2xmm.h: warning: should include "simd.h"
+# src/gromacs/nbnxm/pairlist_simd_4xm.h: warning: should include "simd.h"
 
-# doxygen has problems with the template construct in this file
-src/gromacs/modularsimulator/signallers.h: error: build: is documented, but does not have brief description
+# # This module name doesn't really fall into any currently used pattern; needs some thought
+# : error: no matching directory for module: module_mdrun_integration_tests
+
+# # These would be nice to fix, but can wait for later / deletion / rewrites
+# src/gromacs/nbnxm/kernels_simd_2xmm/kernel_common.h: warning: should include "nbnxm_simd.h"
+# src/gromacs/nbnxm/kernels_simd_4xm/kernel_common.h: warning: should include "nbnxm_simd.h"
+
+
+# # Temporary while we change the SIMD implementation
+# src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace_common.h: warning: should include "simd.h"
+
+# 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
+# src/gmxpre.h: warning: includes non-local file as "swindirect.h"
+
+# # New external API (see https://gitlab.com/gromacs/gromacs/-/issues/2586) has some unresolved
+# # conflicts with previous definitions of public API, installed API, and other things
+# # described or implemented in check-source.py, gmxtree.py, gmxtree.rst, and others
+# # TODO: resolve definitions, update testing heuristics, and activate policy checks
+# # for src/api/cpp files.
+# src/api/cpp/*: *
index cc9afd0cc5acd1b0f9dc323ec2bb8a3c7a9256d4..7cd08a764b748875803e90f5c5c99d8ddf41dfb0 100644 (file)
@@ -145,7 +145,7 @@ For example, you might create a :command:`gmx solvate` operation as::
                                                       }
 
 To check the status or error output of a command line operation, refer to the
-``returncode`` and ``erroroutput`` outputs.
+``returncode`` and ``stderr`` outputs.
 To access the results from the output file arguments, use the command line flags
 as keys in the ``file`` dictionary output.
 
index 24911f03ee82e2a4d91ecc86a0ecbd23f56d3d35..27859f51f7d955ce66740c64a07ec2a7db4acd2d 100644 (file)
@@ -55,10 +55,9 @@ Quick and dirty cluster installation
 
 On a cluster where users are expected to be running across multiple
 nodes using MPI, make one installation similar to the above, and
-another using ``-DGMX_MPI=on`` and which is `building only
-mdrun`_, because that is the only component of |Gromacs| that uses
-MPI. The latter will install a single simulation engine binary,
-i.e. ``mdrun_mpi`` when the default suffix is used. Hence it is safe
+another using ``-DGMX_MPI=on``.
+The latter will install binaries and libraries named using
+a default suffix of ``_mpi`` ie ``gmx_mpi``. Hence it is safe
 and common practice to install this into the same location where
 the non-MPI build is installed.
 
@@ -71,11 +70,10 @@ appropriate value instead of ``xxx`` :
 
 * ``-DCMAKE_C_COMPILER=xxx`` equal to the name of the C99 `Compiler`_ you wish to use (or the environment variable ``CC``)
 * ``-DCMAKE_CXX_COMPILER=xxx`` equal to the name of the C++17 `compiler`_ you wish to use (or the environment variable ``CXX``)
-* ``-DGMX_MPI=on`` to build using `MPI support`_ (generally good to combine with `building only mdrun`_)
+* ``-DGMX_MPI=on`` to build using `MPI support`_
 * ``-DGMX_GPU=CUDA`` to build with NVIDIA CUDA support enabled.
 * ``-DGMX_GPU=OpenCL`` to build with OpenCL_ support enabled.
 * ``-DGMX_SIMD=xxx`` to specify the level of `SIMD support`_ of the node on which |Gromacs| will run
-* ``-DGMX_BUILD_MDRUN_ONLY=on`` for `building only mdrun`_, e.g. for compute cluster back-end nodes
 * ``-DGMX_DOUBLE=on`` to build |Gromacs| in double precision (slower, and not normally useful)
 * ``-DCMAKE_PREFIX_PATH=xxx`` to add a non-standard location for CMake to `search for libraries, headers or programs`_
 * ``-DCMAKE_INSTALL_PREFIX=xxx`` to install |Gromacs| to a `non-standard location`_ (default ``/usr/local/gromacs``)
@@ -115,7 +113,6 @@ compiler. Since we require full C++17 support the minimum supported
 compiler versions are
 
 * GNU (gcc/libstdc++) 7
-* Intel (icc) 19.1
 * LLVM (clang/libc++) 5
 * Microsoft (MSVC) 2017 15.7
 
@@ -123,6 +120,10 @@ Other compilers may work (Cray, Pathscale, older clang) but do
 not offer competitive performance. We recommend against PGI because
 the performance with C++ is very bad.
 
+The Intel classic compiler (icc/icpc) is no longer supported in
+|Gromacs|. Use Intel's newer clang-based compiler from oneAPI, or
+gcc.
+
 The xlc compiler is not supported and version 16.1 does not compile on
 POWER architectures for |Gromacs|\ -\ |version|. We recommend to use
 the gcc compiler instead, as it is being extensively tested.
@@ -137,23 +138,18 @@ libraries and require no further configuration. If your vendor's
 compiler also manages the standard library library via compiler flags,
 these will be honored. For configuration of other compilers, read on.
 
-On Linux, both the Intel and clang compiler use the libstdc++ which
+On Linux, the clang compilers use the libstdc++ which
 comes with gcc as the default C++ library. For |Gromacs|, we require
 the compiler to support libstc++ version 7.1 or higher. To select a
 particular libstdc++ library, provide the path to g++ with
 ``-DGMX_GPLUSPLUS_PATH=/path/to/g++``.
 
-On Windows with the Intel compiler, the MSVC standard library is used,
-and at least MSVC 2017 15.7 is required. Load the environment variables with
-vcvarsall.bat.
-
 To build with clang and llvm's libcxx standard library, use
 ``-DCMAKE_CXX_FLAGS=-stdlib=libc++``.
 
-If you are running on Mac OS X, the best option is the Intel
-compiler. Both clang and gcc will work, but they produce lower
-performance and each have some shortcomings. clang 3.8 now offers
-support for OpenMP, and so may provide decent performance.
+If you are running on Mac OS X, the best option is gcc. The Apple
+clang compiler provided by MacPorts will work, but does not support
+OpenMP, so will probably not provide best performance.
 
 For all non-x86 platforms, your best option is typically to use gcc or
 the vendor's default or recommended compiler, and check for
@@ -217,28 +213,41 @@ workstation using its built-in thread-MPI. No user action is required
 in order to enable this.
 
 If you wish to run in parallel on multiple machines across a network,
-you will need to have
-
-* an MPI library installed that supports the MPI 1.3
-  standard, and
-* wrapper compilers that will compile code using that library.
+you will need to have an MPI library installed that supports the MPI
+2.0 standard. That's true for any MPI library version released since
+about 2009, but the |Gromacs| team recommends the latest version (for
+best performance) of either your vendor's library, OpenMPI_ or MPICH_.
 
 To compile with MPI set your compiler to the normal (non-MPI) compiler
 and add ``-DGMX_MPI=on`` to the cmake options. It is possible to set
 the compiler to the MPI compiler wrapper but it is neither necessary
 nor recommended.
 
-The |Gromacs| team recommends OpenMPI_ version
-1.6 (or higher), MPICH_ version 1.4.1 (or
-higher), or your hardware vendor's MPI installation. The most recent
-version of either of these is likely to be the best. More specialized
-networks might depend on accelerations only available in the vendor's
-library. LAM-MPI_ might work, but since it has
-been deprecated for years, it is not supported.
-
-For example, depending on your actual MPI library, use ``cmake
--DMPI_C_COMPILER=mpicc -DGMX_MPI=on``.
+CUDA-Aware MPI support
+~~~~~~~~~~~~~~~~~~~~~~
 
+In simulations using multiple NVIDIA GPUs, an MPI implementation with CUDA support
+(also called "CUDA-aware") allows communication to be performed directly between the
+distinct GPU memory spaces without staging through CPU memory, often
+resulting in higher bandwidth and lower latency communication.  For
+more details, see `Introduction to CUDA-aware MPI
+<https://developer.nvidia.com/blog/introduction-cuda-aware-mpi/>`_.
+
+To use CUDA-aware MPI for direct GPU communication we recommend
+using the latest OpenMPI version (>=4.1.0) with the latest UCX version
+(>=1.10), since most GROMACS internal testing on CUDA-aware support has 
+been performed using these versions. OpenMPI with CUDA-aware support can 
+be built following the procedure in `these OpenMPI build instructions
+<https://www.open-mpi.org/faq/?category=buildcuda>`_.
+
+With ``GPU_MPI=ON``, GROMACS attempts to automatically detect CUDA support
+in the underlying MPI library at compile time, and enables direct GPU 
+communication when this is detected.  However, there are some cases when
+GROMACS may fail to detect existing CUDA-aware support, in which case
+it can be manually enabled by setting environment variable ``GMX_FORCE_CUDA_AWARE_MPI=1``
+at runtime (although such cases still lack substantial
+testing, so we urge the user to carefully check correctness of results
+against those using default build options, and report any issues).
 
 CMake
 ^^^^^
@@ -570,12 +579,9 @@ lead to performance loss, e.g. on Intel Skylake-X/SP and AMD Zen.
    Additionally, with GPU accelerated runs ``AVX2_256`` can also be
    faster on high-end Skylake CPUs with both 512-bit FMA units enabled.
 9. ``AVX_512_KNL`` Knights Landing Xeon Phi processors
-10. ``Sparc64_HPC_ACE`` Fujitsu machines like the K computer have this.
-11. ``IBM_VMX`` Power6 and similar Altivec processors have this.
-12. ``IBM_VSX`` Power7, Power8, Power9 and later have this.
-13. ``ARM_NEON`` 32-bit ARMv7 with NEON support.
-14. ``ARM_NEON_ASIMD`` 64-bit ARMv8 and later.
-15. ``ARM_SVE`` 64-bit ARMv8 and later with the Scalable Vector Extensions (SVE).
+10. ``IBM_VSX`` Power7, Power8, Power9 and later have this.
+11. ``ARM_NEON_ASIMD`` 64-bit ARMv8 and later.
+12. ``ARM_SVE`` 64-bit ARMv8 and later with the Scalable Vector Extensions (SVE).
     The SVE vector length is fixed at CMake configure time. The default vector
     length is automatically detected, and this can be changed via the
     ``GMX_SIMD_ARM_SVE_LENGTH`` CMake variable.
@@ -732,7 +738,7 @@ To trigger an OpenCL_ build the following CMake flags must be set
     cmake .. -DGMX_GPU=OpenCL
 
 To build with support for Intel integrated GPUs, it is required
-to add ``-DGMX_OPENCL_NB_CLUSTER_SIZE=4`` to the cmake command line,
+to add ``-DGMX_GPU_NB_CLUSTER_SIZE=4`` to the cmake command line,
 so that the GPU kernels match the characteristics of the hardware.
 The `Neo driver <https://github.com/intel/compute-runtime/releases>`_
 is recommended.
@@ -818,18 +824,16 @@ earlier hardware, because this will lead to programs (especially
 mdrun) that run slowly on the new hardware. Building two full
 installations and locally managing how to call the correct one
 (e.g. using a module system) is the recommended
-approach. Alternatively, as at the moment the |Gromacs| tools do not
-make strong use of SIMD acceleration, it can be convenient to create
-an installation with tools portable across different x86 machines, but
-with separate mdrun binaries for each architecture. To achieve this,
+approach. Alternatively, one can use different suffixes to install 
+several versions of |Gromacs| in the same location. To achieve this,
 one can first build a full installation with the
 least-common-denominator SIMD instruction set, e.g. ``-DGMX_SIMD=SSE2``,
-then build separate mdrun binaries for each architecture present in
+in order for simple commands like ``gmx grompp`` to work on all machines,
+then build specialized ``gmx`` binaries for each architecture present in
 the heterogeneous environment. By using custom binary and library
-suffixes for the mdrun-only builds, these can be installed to the
-same location as the "generic" tools installation.
-`Building just the mdrun binary`_ is possible by setting the
-``-DGMX_BUILD_MDRUN_ONLY=ON`` option.
+suffixes (with CMake variables ``-DGMX_BINARY_SUFFIX=xxx`` and
+``-DGMX_LIBS_SUFFIX=xxx``), these can be installed to the same
+location.
 
 Linear algebra libraries
 ~~~~~~~~~~~~~~~~~~~~~~~~
@@ -964,17 +968,6 @@ supported by ``cmake`` (e.g. ``ninja``) also work well.
 
 .. _building just the mdrun binary:
 
-Building only mdrun
-~~~~~~~~~~~~~~~~~~~
-
-This is now deprecated, but still supported with the ``cmake`` option
-``-DGMX_BUILD_MDRUN_ONLY=ON``, which will build a different version of
-``libgromacs`` and the ``mdrun`` program.  Naturally, now ``make
-install`` installs only those products. By default, mdrun-only builds
-will default to static linking against |Gromacs| libraries, because
-this is generally a good idea for the targets for which an mdrun-only
-build is desirable.
-
 Installing |Gromacs|
 ^^^^^^^^^^^^^^^^^^^^
 
@@ -1060,42 +1053,11 @@ but then you should include a detailed description of
 your hardware, and the output of ``gmx mdrun -version`` (which contains
 valuable diagnostic information in the header).
 
-Testing for MDRUN_ONLY executables
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A build with ``-DGMX_BUILD_MDRUN_ONLY`` cannot be tested with
-``make check`` from the build tree, because most of the tests
-require a full build to run things like ``grompp``. To test such an
-mdrun fully requires installing it to the same location as a normal
-build of |Gromacs|, downloading the regression tests tarball manually
-as described above, sourcing the correct ``GMXRC`` and running the
-perl script manually. For example, from your |Gromacs| source
-directory:
-
-::
-
-    mkdir build-normal
-    cd build-normal
-    # First, build and install normally to allow full testing of the standalone simulator.
-    cmake .. -DGMX_MPI=ON -DCMAKE_INSTALL_PREFIX=/your/installation/prefix/here
-    make -j 4
-    make install
-    cd ..
-    mkdir build-mdrun-only
-    cd build-mdrun-only
-    # Next, build and install the GMX_BUILD_MDRUN_ONLY version (optional).
-    cmake .. -DGMX_MPI=ON -DGMX_BUILD_MDRUN_ONLY=ON -DCMAKE_INSTALL_PREFIX=/your/installation/prefix/here
-    make -j 4
-    make install
-    cd /to/your/unpacked/regressiontests
-    source /your/installation/prefix/here/bin/GMXRC
-    ./gmxtest.pl all -np 2
-
 Non-standard suffix
 ~~~~~~~~~~~~~~~~~~~
 
-If your mdrun program has been suffixed in a non-standard way, then
-the ``./gmxtest.pl -mdrun`` option will let you specify that name to the
+If your ``gmx`` program has been suffixed in a non-standard way, then
+the ``./gmxtest.pl -suffix`` option will let you specify that suffix to the
 test machinery. You can use ``./gmxtest.pl -double`` to test the
 double-precision version. You can use ``./gmxtest.pl -crosscompiling``
 to stop the test harness attempting to check that the programs can
@@ -1244,49 +1206,10 @@ Oracle Developer Studio is not a currently supported compiler (and
 does not currently compile |Gromacs| correctly, perhaps because the
 thread-MPI atomics are incorrectly implemented in |Gromacs|).
 
-Fujitsu PRIMEHPC
-^^^^^^^^^^^^^^^^
-
-This is the architecture of the K computer, which uses Fujitsu
-Sparc64VIIIfx chips. On this platform, |Gromacs| has
-accelerated group kernels using the HPC-ACE instructions, no
-accelerated Verlet kernels, and a custom build toolchain. Since this
-particular chip only does double precision SIMD, the default setup
-is to build |Gromacs| in double. Since most users only need single, we have added
-an option GMX_RELAXED_DOUBLE_PRECISION to accept single precision square root
-accuracy in the group kernels; unless you know that you really need 15 digits
-of accuracy in each individual force, we strongly recommend you use this. Note
-that all summation and other operations are still done in double.
-
-The recommended configuration is to use
-
-::
-
-    cmake .. -DCMAKE_TOOLCHAIN_FILE=Toolchain-Fujitsu-Sparc64-mpi.cmake \
-             -DCMAKE_PREFIX_PATH=/your/fftw/installation/prefix \
-             -DCMAKE_INSTALL_PREFIX=/where/gromacs/should/be/installed \
-             -DGMX_MPI=ON \
-             -DGMX_BUILD_MDRUN_ONLY=ON \
-             -DGMX_RELAXED_DOUBLE_PRECISION=ON
-    make
-    make install
-
 Intel Xeon Phi
 ^^^^^^^^^^^^^^
 
 Xeon Phi processors, hosted or self-hosted, are supported.
-Only symmetric (aka native) mode is supported on Knights Corner. The
-performance depends among other factors on the system size, and for
-now the performance might not be faster than CPUs. When building for it,
-the recommended configuration is
-
-::
-
-    cmake .. -DCMAKE_TOOLCHAIN_FILE=Platform/XeonPhi
-    make
-    make install
-
-
 The Knights Landing-based Xeon Phi processors behave like standard x86 nodes,
 but support a special SIMD instruction set. When cross-compiling for such nodes,
 use the ``AVX_512_KNL`` SIMD flavor.
@@ -1314,7 +1237,7 @@ is currently tested with a range of configuration options on x86 with
 gcc versions 7 and 8,
 clang versions 8 and 9,
 and
-a beta version of oneAPI containing Intel's compiler.
+a version of oneAPI containing Intel's clang-based compiler.
 For this testing, we use Ubuntu 18.04 or 20.04 operating system.
 Other compiler, library, and OS versions are tested less frequently.
 For details, you can have a look at the
index 2df2655a2ee764314bccf5a35f5a1849f14461e3..1c97ea602c6df8e894a90ec7360674e96dd9bca0 100644 (file)
@@ -40,15 +40,6 @@ freeze group
     simulation, and afterward use position restraints in conjunction
     with constant pressure.
 
-accelerate group
-
-    On each atom in an “accelerate group” an acceleration
-    :math:`\mathbf{a}^g` is imposed. This is equivalent to
-    an external force. This feature makes it possible to drive the
-    system into a non-equilibrium state and enables the performance of
-    non-equilibrium MD and hence to obtain transport properties.
-    (Deprecated)
-
 energy-monitor group
 
     Mutual interactions between all energy-monitor groups are compiled
index 4d88abfb0722eaaa8827f6e5ea96c9f5a8f01104..524c19f78aa61d07171ed734f68dc85a1cb44bb9 100644 (file)
@@ -195,11 +195,16 @@ The force is then redistributed using the same weights:
 The types of virtual sites supported in |Gromacs| are given in the list
 below. Constructing atoms in virtual sites can be virtual sites
 themselves, but only if they are higher in the list, i.e. virtual sites
-can be constructed from “particles” that are simpler virtual sites.
+can be constructed from “particles” that are simpler virtual sites. The
+virtual site velocities are reported, but not used in the integration
+of the virtual site positions.
 
--  On top of an atom. This allows giving an atom multiple atom types and
+On top of an atom
+~~~~~~~~~~~~~~~~~
+
+-  This allows giving an atom multiple atom types and
    with that also assigned multiple, different bonded interactions. This
-   can espically be of use in free-energy calculations.
+   can especially be of use in free-energy calculations.
 
 -  The coordinates of the virtual site equal that of the constructing atom:
 
@@ -211,8 +216,15 @@ can be constructed from “particles” that are simpler virtual sites.
    .. math:: \mathbf{F}_i ~=~ \mathbf{F}_{s}
              :label: eqnvsite1force
 
--  As a linear combination of two atoms
-   (:numref:`Fig. %s <fig-vsites>` 2):
+-  The velocity of the virtual site equals that of the constructing atom:
+
+   .. math:: \mathbf{v}_s ~=~ \mathbf{v}_i
+             :label: eqnvsite1vel
+
+As a linear combination of two atoms (:numref:`Fig. %s <fig-vsites>` 2)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+-  The weights are calculated as
 
    .. math:: w_i = 1 - a ~,~~ w_j = a
              :label: eqnvsitelin2atom
@@ -220,8 +232,13 @@ can be constructed from “particles” that are simpler virtual sites.
 -  In this case the virtual site is on the line through atoms :math:`i`
    and :math:`j`.
 
--  On the line through two atoms, with a fixed distance
-   (:numref:`Fig. %s <fig-vsites>` 2fd):
+-  The velocity of the virtual site is a linear combination of the
+   velocities of the constructing atoms
+
+On the line through two atoms, with a fixed distance (:numref:`Fig. %s <fig-vsites>` 2fd)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+-  The position is calculated as:
 
    .. math:: \mathbf{r}_s ~=~ \mathbf{r}_i + a \frac{ \mathbf{r}_{ij} }
                                                   { | \mathbf{r}_{ij} | }
@@ -244,8 +261,18 @@ can be constructed from “particles” that are simpler virtual sites.
              \end{array}
              :label: eqnvsite2fdforce
 
--  As a linear combination of three atoms
-   (:numref:`Fig. %s <fig-vsites>` 3):
+-  The velocity is calculated as:
+
+   .. math:: \mathbf{v}_{s} = \mathbf{v}_{i} + \frac{a}{|\mathbf{r}_{ij}|}
+                                 \left(\mathbf{v}_{ij} - \mathbf{r}_{ij}
+                                    \frac{\mathbf{v}_{ij}\cdot\mathbf{r}_{ij}}
+                                         {|\mathbf{r}_{ij}|^2}\right)
+             :label: eqnvsite2fdatomvel
+
+As a linear combination of three atoms (:numref:`Fig. %s <fig-vsites>` 3)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+-  The weights are calculated as:
 
    .. math:: w_i = 1 - a - b ~,~~ w_j = a ~,~~ w_k = b
              :label: eqnvsitelin3atom
@@ -253,11 +280,14 @@ can be constructed from “particles” that are simpler virtual sites.
 -  In this case the virtual site is in the plane of the other three
    particles.
 
--  In the plane of three atoms, with a fixed distance
-   (:numref:`Fig. %s <fig-vsites>` 3fd):
+In the plane of three atoms, with a fixed distance (:numref:`Fig. %s <fig-vsites>` 3fd)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-   .. math:: \mathbf{r}_s ~=~ \mathbf{r}_i + b \frac{  (1 - a) \mathbf{r}_{ij} + a \mathbf{r}_{jk}  }
-                                                  { | (1 - a) \mathbf{r}_{ij} + a \mathbf{r}_{jk} | }
+-  The position is calculated as:
+
+   .. math:: \mathbf{r}_s ~=~ \mathbf{r}_i + b \frac{ \mathbf{r}_{ijk} } { | \mathbf{r}_{ijk} | }
+             ~\mbox{ where }~
+             \mathbf{r}_{ijk} ~=~ (1 - a) \mathbf{r}_{ij} + a \mathbf{r}_{jk}
              :label: eqnvsiteplane3atom
 
 -  In this case the virtual site is in the plane of the other three
@@ -278,8 +308,19 @@ can be constructed from “particles” that are simpler virtual sites.
              \end{array}
              :label: eqnvsiteplane3atomforce
 
--  In the plane of three atoms, with a fixed angle and
-   distance (:numref:`Fig. %s <fig-vsites>` 3fad):
+-  The velocity is calculated as:
+
+   .. math:: \mathbf{v}_{s} ~=~ \mathbf{v}_{i} +
+                                \frac{b}{|\mathbf{r}_{ijk}|}
+                                \left(\dot{\mathbf{r}}_{ijk} -
+                                \mathbf{r}_{ijk}\frac{\dot{\mathbf{r}}_{ijk}\cdot\mathbf{r}_{ijk}}
+                                                     {|\mathbf{r}_{ijk}|^2}\right)
+             :label: eqnvsiteplane3atomvel
+
+In the plane of three atoms, with a fixed angle and distance (:numref:`Fig. %s <fig-vsites>` 3fad)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+-  The position is calculated as:
 
    .. math:: \mathbf{r}_s ~=~ \mathbf{r}_i +
              d \cos \theta \frac{\mathbf{r}_{ij}}{ | \mathbf{r}_{ij} | } +
@@ -334,8 +375,27 @@ can be constructed from “particles” that are simpler virtual sites.
              \end{array}
              :label: eqnvsite2fadFforce
 
--  As a non-linear combination of three atoms, out of
-   plane (:numref:`Fig. %s <fig-vsites>` 3out):
+-  The velocity is calculated as:
+
+   .. math:: \mathbf{v}_{s} &= \mathbf{v}_{i} + d\cos\theta\ \frac{\delta}{\delta t}\frac{\mathbf{r}_{ij}}{|\mathbf{r}_{ij}|} +
+                               d\sin\theta\ \frac{\delta}{\delta t}\frac{\mathbf{r}_{\perp}}{|\mathbf{r}_{\perp}|} \\
+             ~\mbox{where}~&\\
+             \frac{\delta}{\delta t}\frac{\mathbf{r}_{ij}}{|\mathbf{r}_{ij}|} &=
+                 \frac{1}{|\mathbf{r}_{ij}|}\left(\mathbf{v}_{ij} - \mathbf{r}_{ij}
+                 \frac{\mathbf{v}_{ij}\cdot\mathbf{r}_{ij}}{|\mathbf{r}_{ij}|^2}\right)\\
+             \frac{\delta}{\delta t}\frac{\mathbf{r}_{\perp}}{|\mathbf{r}_{\perp}|} &=
+                 \frac{1}{|\mathbf{r}_{\perp}|}
+                 \left(\dot{\mathbf{r}}_{\perp} - \mathbf{r}_{\perp}\frac{\dot{\mathbf{r}}_{\perp}\cdot\mathbf{r}_{\perp}}{|\mathbf{r}_{\perp}|^2}\right)\\
+             \dot{\mathbf{r}}_\perp &= \mathbf{v}_{jk} - \mathbf{r}_{ij}
+                 \frac{|\mathbf{r}_{ij}|^2(\mathbf{v}_{ij}\cdot\mathbf{r}_{jk} + \mathbf{r}_{ij}\cdot\mathbf{v}_{jk}) -
+                 (\mathbf{r}_{ij}\cdot\mathbf{r}_{jk})(2\mathbf{r}_{ij}\cdot\mathbf{v}_{ij})} {|\mathbf{r}_{ij}|^4} -
+                 \frac{\mathbf{r}_{ij}\cdot\mathbf{r}_{jk}}{|\mathbf{r}_{ij}|^2}\ \mathbf{v}_{ij}
+             :label: eqnvsite2fadvel
+
+As a non-linear combination of three atoms, out of plane (:numref:`Fig. %s <fig-vsites>` 3out)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+-  The position is calculated as:
 
    .. math:: \mathbf{r}_s ~=~ \mathbf{r}_i + a \mathbf{r}_{ij} + b \mathbf{r}_{ik} +
                               c (\mathbf{r}_{ij} \times \mathbf{r}_{ik})
@@ -360,8 +420,15 @@ can be constructed from “particles” that are simpler virtual sites.
              \end{array}
              :label: eqnvsitenonlin3atomforce
 
--  From four atoms, with a fixed distance, see
-   separate :numref:`Fig. %s <fig-vsite4fdn>`. This construction is a bit complex,
+-  The velocity is calculated as:
+
+   .. math:: \mathbf{v}_{s} ~=~ \mathbf{v}_{i} + \frac{c}{|\mathbf{r}_{m}|}\left(\dot{\mathbf{r}}_{m} -
+                 \mathbf{r}_{m} \frac{\dot{\mathbf{r}}_{m}\cdot\mathbf{r}_{m}}{|\mathbf{r}_{m}|^2}\right)
+             :label: eqnvsitenonlin3atomvel
+
+From four atoms, with a fixed distance, see separate :numref:`Fig. %s <fig-vsite4fdn>`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-  This construction is a bit complex,
    in particular since the previous type (4fd) could be unstable which
    forced us to introduce a more elaborate construction:
 
@@ -373,15 +440,23 @@ can be constructed from “particles” that are simpler virtual sites.
       The new 4fdn virtual site construction, which is stable even when
       all constructing atoms are in the same plane.
 
--
+-  The position is calculated as
+
       .. math::   \begin{aligned}
                   \mathbf{r}_{ja} &=& a\, \mathbf{r}_{ik} - \mathbf{r}_{ij} = a\, (\mathbf{x}_k - \mathbf{x}_i) - (\mathbf{x}_j - \mathbf{x}_i) \nonumber \\
                   \mathbf{r}_{jb} &=& b\, \mathbf{r}_{il} - \mathbf{r}_{ij} = b\, (\mathbf{x}_l - \mathbf{x}_i) - (\mathbf{x}_j - \mathbf{x}_i) \nonumber \\
                   \mathbf{r}_m &=& \mathbf{r}_{ja} \times \mathbf{r}_{jb} \nonumber \\
-                  \mathbf{x}_s &=& \mathbf{x}_i + c \frac{\mathbf{r}_m}{ | \mathbf{r}_m | }
+                  \mathbf{r}_s &=& \mathbf{r}_i + c \frac{\mathbf{r}_m}{ | \mathbf{r}_m | }
                   \end{aligned}
                   :label: eqnvsite
 
+-   The velocity is calculated as:
+
+   .. math:: \mathbf{v}_{s} = \mathbf{v}_{i} + \frac{c}{|\mathbf{r}_{m}|}\left(\dot{\mathbf{r}}_{m} - \mathbf{r}_{m} \frac{\dot{\mathbf{r}}_{m}\cdot\mathbf{r}_{m}}{|\mathbf{r}_{m}|^2}\right)\\
+             ~\mbox{where}~&\\
+             \dot{\mathbf{r}}_{m} &= \dot{\mathbf{r}}_{ja} \times \mathbf{r}_{jb} + \mathbf{r}_{ja} \times \dot{\mathbf{r}}_{jb}
+             :label: eqnvsitevel
+
 -  In this case the virtual site is at a distance of :math:`|c|` from
    :math:`i`, while :math:`a` and :math:`b` are parameters. **Note**
    that the vectors :math:`\mathbf{r}_{ik}` and :math:`\mathbf{r}_{ij}`
@@ -400,8 +475,10 @@ can be constructed from “particles” that are simpler virtual sites.
    value 1), but it should not be used for new simulations. All current
    |Gromacs| tools will automatically generate type 4fdn instead.
 
--  A linear combination of :math:`N` atoms with relative
-   weights :math:`a_i`. The weight for atom :math:`i` is:
+A linear combination of :math:`N` atoms with relative weights :math:`a_i`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+-  The weight for atom :math:`i` is:
 
    .. math:: w_i = a_i \left(\sum_{j=1}^N a_j \right)^{-1}
              :label: eqnvsiterelweight
index 195827bc559f29fa9fa757a0c8c58c262658c48b..6c43588883fa4b662edd589068fd2c116dafb5b7 100644 (file)
@@ -1,5 +1,3 @@
-.. _anticipated-changes:
-
 .. Note to developers!
    Please use """"""" to underline the individual entries for fixed issues in the subfolders,
    otherwise the formatting on the webpage is messed up.
diff --git a/docs/release-notes/2022/major/api.rst b/docs/release-notes/2022/major/api.rst
new file mode 100644 (file)
index 0000000..12744a9
--- /dev/null
@@ -0,0 +1,16 @@
+Changes to the API
+^^^^^^^^^^^^^^^^^^
+
+.. Note to developers!
+   Please use """"""" to underline the individual entries for fixed issues in the subfolders,
+   otherwise the formatting on the webpage is messed up.
+   Also, please use the syntax :issue:`number` to reference issues on GitLab, without the
+   a space between the colon and number!
+
+Remove physical constant conversion functions
+"""""""""""""""""""""""""""""""""""""""""""""
+
+Legacy conversion functions for physical constants from and to the |Gromacs|
+representation have been removed as they didn't see any use in the library.
+
+
diff --git a/docs/release-notes/2022/major/bugs-fixed.rst b/docs/release-notes/2022/major/bugs-fixed.rst
new file mode 100644 (file)
index 0000000..6a68e96
--- /dev/null
@@ -0,0 +1,21 @@
+Bugs fixed
+^^^^^^^^^^
+
+Fixed slight inaccuracies when using virtual sites with pressure coupling
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+Virtual sites were reconstructed after the system was propagated, but before
+scaling due to pressure coupling. For virtual site types which are not a linear
+combination of other atoms, this is not completely correct. Since the scaling
+due to pressure coupling is very small in healthy simulations, the resulting
+inaccuracies are expected to have been extremely minor, and in most cases
+undetectable.
+
+:issue:`3866`
+
+.. Note to developers!
+   Please use """"""" to underline the individual entries for fixed issues in the subfolders,
+   otherwise the formatting on the webpage is messed up.
+   Also, please use the syntax :issue:`number` to reference issues on GitLab, without the
+   a space between the colon and number!
+
diff --git a/docs/release-notes/2022/major/deprecated-functionality.rst b/docs/release-notes/2022/major/deprecated-functionality.rst
new file mode 100644 (file)
index 0000000..8dfd7f8
--- /dev/null
@@ -0,0 +1,18 @@
+.. _anticipated-changes:
+
+.. Note to developers!
+   Please use """"""" to underline the individual entries for fixed issues in the subfolders,
+   otherwise the formatting on the webpage is messed up.
+   Also, please use the syntax :issue:`number` to reference issues on GitLab, without the
+   a space between the colon and number!
+
+Changes anticipated to |Gromacs| 2022 functionality
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Functionality deprecated in |Gromacs| 2022
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+GMX_OPENCL_NB_CLUSTER_SIZE CMake variable deprecated in favor of GMX_GPU_NB_CLUSTER_SIZE
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Both OpenCL and SYCL support different cluster sizes, so GMX_GPU_NB_CLUSTER_SIZE should
+be used going forward.
diff --git a/docs/release-notes/2022/major/features.rst b/docs/release-notes/2022/major/features.rst
new file mode 100644 (file)
index 0000000..5626dc8
--- /dev/null
@@ -0,0 +1,9 @@
+New and improved features
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. Note to developers!
+   Please use """"""" to underline the individual entries for fixed issues in the subfolders,
+   otherwise the formatting on the webpage is messed up.
+   Also, please use the syntax :issue:`number` to reference issues on GitLab, without the
+   a space between the colon and number!
+
diff --git a/docs/release-notes/2022/major/highlights.rst b/docs/release-notes/2022/major/highlights.rst
new file mode 100644 (file)
index 0000000..bf79671
--- /dev/null
@@ -0,0 +1,22 @@
+Highlights
+^^^^^^^^^^
+
+|Gromacs| 2022 was released on INSERT DATE HERE. Patch releases may
+have been made since then, please use the updated versions!  Here are
+some highlights of what you can expect, along with more detail in the
+links below!
+
+As always, we've got several useful performance improvements, with or
+without GPUs, all enabled and automated by default. In addition,
+several new features are available for running simulations. We are extremely
+interested in your feedback on how well the new release works on your
+simulations and hardware. The new features are:
+
+* Cool quotes music play list
+
+
+.. Note to developers!
+   Please use """"""" to underline the individual entries for fixed issues in the subfolders,
+   otherwise the formatting on the webpage is messed up.
+   Also, please use the syntax :issue:`number` to reference issues on GitLab, without the
+   a space between the colon and number!
diff --git a/docs/release-notes/2022/major/miscellaneous.rst b/docs/release-notes/2022/major/miscellaneous.rst
new file mode 100644 (file)
index 0000000..1a242e3
--- /dev/null
@@ -0,0 +1,9 @@
+Miscellaneous
+^^^^^^^^^^^^^
+
+.. Note to developers!
+   Please use """"""" to underline the individual entries for fixed issues in the subfolders,
+   otherwise the formatting on the webpage is messed up.
+   Also, please use the syntax :issue:`number` to reference issues on GitLab, without the
+   a space between the colon and number!
+
diff --git a/docs/release-notes/2022/major/performance.rst b/docs/release-notes/2022/major/performance.rst
new file mode 100644 (file)
index 0000000..4e1f6ba
--- /dev/null
@@ -0,0 +1,15 @@
+Performance improvements
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. Note to developers!
+   Please use """"""" to underline the individual entries for fixed issues in the subfolders,
+   otherwise the formatting on the webpage is messed up.
+   Also, please use the syntax :issue:`number` to reference issues on GitLab, without the
+   a space between the colon and number!
+
+Dynamic pairlist generation for energy minimization
+"""""""""""""""""""""""""""""""""""""""""""""""""""
+
+With energy minimization, the pairlist, and domain decomposition when running
+in parallel, is now performed when at least one atom has moved more than the
+half the pairlist buffer size. The pairlist used to be constructed every step.
diff --git a/docs/release-notes/2022/major/portability.rst b/docs/release-notes/2022/major/portability.rst
new file mode 100644 (file)
index 0000000..75c4b48
--- /dev/null
@@ -0,0 +1,10 @@
+Portability
+^^^^^^^^^^^
+
+Intel classic compiler (icc/icpc) no longer supported
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+We now support the Intel clang-based compiler from oneAPI (icx/icpx)
+instead. Please use it, or gcc.
+
+:issue:`3893`
diff --git a/docs/release-notes/2022/major/removed-functionality.rst b/docs/release-notes/2022/major/removed-functionality.rst
new file mode 100644 (file)
index 0000000..440bb64
--- /dev/null
@@ -0,0 +1,53 @@
+Removed functionality
+^^^^^^^^^^^^^^^^^^^^^
+
+Removed constant-acceleration groups support
+""""""""""""""""""""""""""""""""""""""""""""
+This code has been broken since before GROMACS 4.6, so it has been
+removed.
+
+:issue:`1354`
+
+.. Note to developers!
+   Please use """"""" to underline the individual entries for fixed issues in the subfolders,
+   otherwise the formatting on the webpage is messed up.
+   Also, please use the syntax :issue:`number` to reference issues on GitLab, without the
+   a space between the colon and number!
+
+Removed mdrun-only build configuration
+""""""""""""""""""""""""""""""""""""""
+
+The need for the mdrun-only build of |Gromacs| has expired, as it has
+the same set of dependencies as regular |Gromacs|. It was deprecated
+in GROMACS 2021. Removing it will simplify maintenance, testing,
+documentation, installation, and teaching new users.
+
+:issue:`3808`
+
+Removed support for x86 MIC, ARMv7, Sparc64 HPC-ACE, and IBM VMX SIMD
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+These platforms are dead in HPC and so are no longer supported. The
+KNL platform is unaffected by this change.
+
+:issue:`3891`
+
+Removed deprecated environment variables
+""""""""""""""""""""""""""""""""""""""""
+
+The following environment variables were removed after being deprecated
+in favor of better-named alternatives:
+
+* ``GMX_CUDA_NB_ANA_EWALD`` and ``GMX_OCL_NB_ANA_EWALD`` (use ``GMX_GPU_NB_ANA_EWALD``)
+* ``GMX_CUDA_NB_TAB_EWALD`` and ``GMX_OCL_NB_TAB_EWALD`` (use ``GMX_GPU_NB_TAB_EWALD``)
+* ``GMX_CUDA_NB_EWALD_TWINCUT`` and ``GMX_OCL_NB_EWALD_TWINCUT`` (use ``GMX_GPU_NB_EWALD_TWINCUT``)
+
+:issue:`3803`
+
+Removed the ability for gmx wham to read .pdo files
+"""""""""""""""""""""""""""""""""""""""""""""""""""
+
+Files in .pdo format were written by |Gromacs| versions prior to 4.0.
+That is so long ago that being able to read them is no longer
+relevant, so this capability was deprecated in version 2021. If you do
+need to read such files, please use an older version of |Gromacs|.
diff --git a/docs/release-notes/2022/major/tools.rst b/docs/release-notes/2022/major/tools.rst
new file mode 100644 (file)
index 0000000..fdc5086
--- /dev/null
@@ -0,0 +1,26 @@
+Improvements to |Gromacs| tools
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. Note to developers!
+   Please use """"""" to underline the individual entries for fixed issues in the subfolders,
+   otherwise the formatting on the webpage is messed up.
+   Also, please use the syntax :issue:`number` to reference issues on GitLab, without the
+   a space between the colon and number!
+
+gmx msd has been migrated to the trajectoryanalysis framework
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+The tool now uses the |Gromacs| selection syntax. Rather than piping selections via stdin,
+selections are now made using the "-sel" option.
+
+This migration comes with about a 20% speedup in execution time.
+
+TODO: Modify/Delete this segment as features are added back in.
+Some rarely used features have yet to be migrated, including:
+
+- Mass weighting of MSDs cannot currently be turned on or off. It is set to on when -mol is set, otherwise off.
+- The -tensor option is not yet implemented.
+- System COM removal with -rmcomm has not yet been implemented.
+- B-factor writing using the -pdb option is not yet supported.
+
+:issue:`2368`
\ No newline at end of file
index e90bc26370897914e82d934fb949bbd0c9f33cd9..0702e8693404a67b8392a99a84ca667a50957771 100644 (file)
@@ -8,19 +8,19 @@ releases of |Gromacs|. Major releases contain changes to the
 functionality supported, whereas patch releases contain only fixes for
 issues identified in the corresponding major releases.
 
-Two versions of |Gromacs| are under active maintenance, the 2021
-series and the 2020 series. In the latter, only highly conservative
+Two versions of |Gromacs| are under active maintenance, the 2022
+series and the 2021 series. In the latter, only highly conservative
 fixes will be made, and only to address issues that affect scientific
 correctness. Naturally, some of those releases will be made after the
-year 2020 ends, but we keep 2019 in the name so users understand how
+year 2021 ends, but we keep 2021 in the name so users understand how
 up to date their version is. Such fixes will also be incorporated into
-the 2021 release series, as appropriate. Around the time the 2022
-release is made, the 2020 series will no longer be maintained.
+the 2022 release series, as appropriate. Around the time the 2023
+release is made, the 2021 series will no longer be maintained.
 
 Where issue numbers are reported in these release notes, more details
 can be found on the `issue tracker`_ at that issue number.
 
-|Gromacs| 2021 series
+|Gromacs| 2022 series
 ---------------------
 
 .. todolist::
@@ -36,6 +36,27 @@ Patch releases
    2021/2021.1
 
 
+Major release
+^^^^^^^^^^^^^
+
+.. toctree::
+   :maxdepth: 1
+
+   2022/major/highlights
+   2022/major/features
+   2022/major/performance
+   2022/major/api
+   2022/major/tools
+   2022/major/bugs-fixed
+   2022/major/deprecated-functionality
+   2022/major/removed-functionality
+   2022/major/portability
+   2022/major/miscellaneous
+
+
+|Gromacs| 2021 series
+---------------------
+
 Major release
 ^^^^^^^^^^^^^
 
@@ -52,6 +73,10 @@ Major release
    2021/major/portability
    2021/major/miscellaneous
 
+
+Older (unmaintained) |Gromacs| series
+-------------------------------------------------------
+
 |Gromacs| 2020 series
 ---------------------
 
@@ -117,9 +142,6 @@ Major release
    2019/major/portability
    2019/major/miscellaneous
 
-Older (unmaintained) |Gromacs| series
--------------------------------------------------------
-
 |Gromacs| 2018 series
 ---------------------
 
index fed58b407a18a1b58cb85eb913a43bfcd3f0ead5..671dd2a9fc26be7dd2cc81f04a8ff5cc6cc9bc36 100644 (file)
@@ -13,9 +13,7 @@ Command-line reference
 |Gromacs| includes many tools for preparing, running and analyzing
 molecular dynamics simulations. These are all structured as part of a single
 :command:`gmx` wrapper binary, and invoked with commands like :command:`gmx grompp`.
-:ref:`mdrun <gmx mdrun>` is the only other binary that
-:ref:`can be built <building just the mdrun binary>`; in the normal
-build it can be run with :command:`gmx mdrun`. Documentation for these can
+or :command:`gmx mdrun`. Documentation for these can
 be found at the respective sections below, as well as on man pages (e.g.,
 :manpage:`gmx-grompp(1)`) and with :samp:`gmx help {command}` or
 :samp:`gmx {command} -h`.
index 8d288eed43bda79949bcc8e2ed8e42662884a4f7..ecd06e671e8c4296836a168b57254cd83795d6e5 100644 (file)
@@ -170,6 +170,10 @@ Performance and Run Control
         (for coordinate and force buffers) directly on GPU memory spaces, without the staging of data through CPU
         memory, where possible. 
 
+``GMX_GPU_SYCL_NO_SYNCHRONIZE``
+        disable synchronizations between different GPU streams in SYCL build, instead relying on SYCL runtime to
+        do scheduling based on data dependencies. Experimental.
+
 ``GMX_CYCLE_ALL``
         times all code during runs.  Incompatible with threads.
 
@@ -396,10 +400,6 @@ Performance and Run Control
         by mdrun. Values should be between the pruning frequency value
         (1 for CPU and 2 for GPU) and :mdp:`nstlist` ``- 1``.
 
-``GMX_USE_TREEREDUCE``
-        use tree reduction for nbnxn force reduction. Potentially faster for large number of
-        OpenMP threads (if memory locality is important).
-
 .. _opencl-management:
 
 OpenCL management
@@ -502,9 +502,6 @@ Analysis and Core Functions
         terminal residues (NXXX and CXXX) as :ref:`rtp` entries that are normally renamed. Setting
         this environment variable disables this renaming.
 
-``GMX_PATH_GZIP``
-        ``gunzip`` executable, used by :ref:`gmx wham`.
-
 ``GMX_FONT``
         name of X11 font used by :ref:`gmx view`.
 
index 2c45196c27e0495bc95bb988acaa547a86e5bf4b..8b0bf3ed2bf51202435dbf73e8830178be9a4f03 100644 (file)
@@ -14,11 +14,14 @@ Questions regarding |Gromacs| installation
 
 #. Do I need to compile all utilities with MPI?
 
-   With one rarely-used exception (:ref:`pme_error <gmx pme_error>`), only the
-   :ref:`mdrun <gmx mdrun>` binary is able to use the :ref:`MPI <mpi-support>`
+   With one rarely-used exception (:ref:`pme_error <gmx pme_error>`), only
+   :ref:`mdrun <gmx mdrun>` is able to use the :ref:`MPI <mpi-support>`
    parallelism. So you only need to use the ``-DGMX_MPI=on`` flag
    when :ref:`configuring <configure-cmake>` for a build intended to run
-   the main simulation engine :ref:`mdrun <gmx mdrun>`.
+   the main simulation engine :ref:`mdrun <gmx mdrun>`. Generally that
+   is desirable when running on a multi-node cluster, and necessary
+   when using multi-simulation algorithms. Usually also installing a
+   build of GROMACS configured without MPI is convenient for users.
 
 
 #. Should my version be compiled using double precision?
index 02214fba67dbb2d160c064b533e811bdc17a40f0..6fa77469a24a13bbb3c6eb42a98952bb29f1191d 100644 (file)
@@ -147,8 +147,8 @@ Trajectory file (``.trr``, ``.tng``, or ``.xtc``)
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Once the run input file is available, we can start the simulation. The
-program which starts the simulation is called :ref:`gmx mdrun` (or
-sometimes just mdrun, or mdrun_mpi). The only input file of :ref:`gmx mdrun`
+program which starts the simulation is called :ref:`gmx mdrun`.
+The only input file of :ref:`gmx mdrun`
 that you usually need in order to start a run is the run input
 file (:ref:`tpr` file). The typical output files of :ref:`gmx mdrun` are the
 trajectory file (:ref:`trr` file), a logfile (:ref:`log` file), and perhaps a
index a11ace67a42fd6023fb2c3177f39aef56d0e4042..667576a73d0575387c849c0e80df5256ffd73b75 100644 (file)
@@ -492,7 +492,9 @@ Neighbor searching
       a minimum value and :ref:`gmx mdrun` might increase it, unless
       it is set to 1. With parallel simulations and/or non-bonded
       force calculation on the GPU, a value of 20 or 40 often gives
-      the best performance.
+      the best performance. With energy minimization this parameter
+      is not used as the pair list is updated when at least one atom
+      has moved by more than half the pair list buffer size.
 
    .. mdp-value:: 0
 
@@ -2953,20 +2955,6 @@ Expanded Ensemble calculations
 Non-equilibrium MD
 ^^^^^^^^^^^^^^^^^^
 
-.. mdp:: acc-grps
-
-   groups for constant acceleration (*e.g.* ``Protein Sol``) all atoms
-   in groups Protein and Sol will experience constant acceleration as
-   specified in the :mdp:`accelerate` line. (Deprecated)
-
-.. mdp:: accelerate
-
-   (0) [nm ps\ :sup:`-2`]
-   acceleration for :mdp:`acc-grps`; x, y and z for each group
-   (*e.g.* ``0.1 0.0 0.0 -0.1 0.0 0.0`` means that first group has
-   constant acceleration of 0.1 nm ps\ :sup:`-2` in X direction, second group
-   the opposite). (Deprecated)
-
 .. mdp:: freezegrps
 
    Groups that are to be frozen (*i.e.* their X, Y, and/or Z position
index 08ea83f6d8164657fd1ec945f71862589ffad036..1620a9fe18c175a2835833957a52b1275a329dc9 100644 (file)
@@ -75,7 +75,7 @@ This feature requires
 :ref:`configuring |Gromacs| with an external MPI library <mpi-support>`
 so that the set of
 simulations can communicate. The ``n`` simulations within the set can
-use internal MPI parallelism also, so that ``mpirun -np x mdrun_mpi``
+use internal MPI parallelism also, so that ``mpirun -np x gmx_mpi mdrun``
 for ``x`` a multiple of ``n`` will use ``x/n`` ranks per simulation.
 
 There are two ways of organizing files when running such
index 1989c670c1061cbb9658335aa0dd849f343e5188..e97494a76c63447f15d2b6e096ca86556ae81c59 100644 (file)
@@ -759,7 +759,7 @@ Running :ref:`mdrun <gmx mdrun>` on more than one node
 
 This requires configuring |Gromacs| to build with an external MPI
 library. By default, this :ref:`mdrun <gmx mdrun>` executable is run with
-:ref:`mdrun_mpi`. All of the considerations for running single-node
+``gmx_mpi mdrun``. All of the considerations for running single-node
 :ref:`mdrun <gmx mdrun>` still apply, except that ``-ntmpi`` and ``-nt`` cause a fatal
 error, and instead the number of ranks is controlled by the
 MPI environment.
@@ -830,7 +830,7 @@ to choose the number of MPI ranks.
 
     mpirun -np 16 gmx_mpi mdrun
 
-Starts :ref:`mdrun_mpi` with 16 ranks, which are mapped to
+Starts :ref:`gmx mdrun` with 16 ranks, which are mapped to
 the hardware by the MPI library, e.g. as specified
 in an MPI hostfile. The available cores will be
 automatically split among ranks using OpenMP threads,
@@ -841,7 +841,7 @@ such as ``OMP_NUM_THREADS``.
 
     mpirun -np 16 gmx_mpi mdrun -npme 5
 
-Starts :ref:`mdrun_mpi` with 16 ranks, as above, and
+Starts :ref:`gmx mdrun` with 16 ranks, as above, and
 require that 5 of them are dedicated to the PME
 component.
 
@@ -849,7 +849,7 @@ component.
 
     mpirun -np 11 gmx_mpi mdrun -ntomp 2 -npme 6 -ntomp_pme 1
 
-Starts :ref:`mdrun_mpi` with 11 ranks, as above, and
+Starts :ref:`gmx mdrun` with 11 ranks, as above, and
 require that six of them are dedicated to the PME
 component with one OpenMP thread each. The remaining
 five do the PP component, with two OpenMP threads
@@ -859,7 +859,7 @@ each.
 
     mpirun -np 4 gmx_mpi mdrun -ntomp 6 -nb gpu -gputasks 00
 
-Starts :ref:`mdrun_mpi` on a machine with two nodes, using
+Starts :ref:`gmx mdrun` on a machine with two nodes, using
 four total ranks, each rank with six OpenMP threads,
 and both ranks on a node sharing GPU with ID 0.
 
@@ -868,7 +868,7 @@ and both ranks on a node sharing GPU with ID 0.
     mpirun -np 8 gmx_mpi mdrun -ntomp 3 -gputasks 0000
 
 Using a same/similar hardware as above,
-starts :ref:`mdrun_mpi` on a machine with two nodes, using
+starts :ref:`gmx mdrun` on a machine with two nodes, using
 eight total ranks, each rank with three OpenMP threads,
 and all four ranks on a node sharing GPU with ID 0.
 This may or may not be faster than the previous setup
@@ -878,7 +878,7 @@ on the same hardware.
 
     mpirun -np 20 gmx_mpi mdrun -ntomp 4 -gputasks 00
 
-Starts :ref:`mdrun_mpi` with 20 ranks, and assigns the CPU cores evenly
+Starts :ref:`gmx mdrun` with 20 ranks, and assigns the CPU cores evenly
 across ranks each to one OpenMP thread. This setup is likely to be
 suitable when there are ten nodes, each with one GPU, and each node
 has two sockets each of four cores.
@@ -887,7 +887,7 @@ has two sockets each of four cores.
 
     mpirun -np 10 gmx_mpi mdrun -gpu_id 1
 
-Starts :ref:`mdrun_mpi` with 20 ranks, and assigns the CPU cores evenly
+Starts :ref:`gmx mdrun` with 20 ranks, and assigns the CPU cores evenly
 across ranks each to one OpenMP thread. This setup is likely to be
 suitable when there are ten nodes, each with two GPUs, but another
 job on each node is using GPU 0. The job scheduler should set the
@@ -898,7 +898,7 @@ performance of :ref:`mdrun <gmx mdrun>` will suffer greatly.
 
     mpirun -np 20 gmx_mpi mdrun -gpu_id 01
 
-Starts :ref:`mdrun_mpi` with 20 ranks. This setup is likely
+Starts :ref:`gmx mdrun` with 20 ranks. This setup is likely
 to be suitable when there are ten nodes, each with two
 GPUs, but there is no need to specify ``-gpu_id`` for the
 normal case where all the GPUs on the node are available
@@ -1362,7 +1362,7 @@ of 2. So it can be useful go through the checklist.
 * Don't use double precision unless you're absolute sure you need it.
 * Compile the FFTW library (yourself) with the correct flags on x86 (in most
   cases, the correct flags are automatically configured).
-* On x86, use gcc or icc as the compiler (not pgi or the Cray compiler).
+* On x86, use gcc as the compiler (not icc, pgi or the Cray compiler).
 * On POWER, use gcc instead of IBM's xlc.
 * Use a new compiler version, especially for gcc (e.g. from version 5 to 6
   the performance of the compiled code improved a lot).
index ef4c6ae0a9f3fd174e4a6c76d64131604018c20e..b40cd610656a1a8e77e6b59671ff518bfbe136dc 100644 (file)
@@ -1,6 +1,6 @@
 # Python package requirements for complete build, installation, and testing of
 # gmxapi functionality.
-cmake>=3.13
+cmake>=3.16.3
 flake8>=3.7.7
 networkx>=2.0
 numpy>=1
index fee19bfcd2edfb9c2c8e299446d30f53185bbf2c..352bb16c0a768d1523c5560475ffd8dc36011faf 100644 (file)
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.13.0)
+cmake_minimum_required(VERSION 3.16.3)
 # If you are using this repository as a template, you should probably change the
 # project name and adopt your own versioning scheme.
 project(sample_restraint VERSION 0.0.8)
index 9fac443fd75ae37d22d40b062cb347e9410130e1..6e70fb46df5217e761c03ec0c2655b5f5a86d519 100644 (file)
@@ -20,4 +20,4 @@ set_target_properties(gmxapi_extension_ensemblepotential PROPERTIES SKIP_BUILD_R
 # If building with setuptools, CMake will not be performing the install
 set_target_properties(gmxapi_extension_ensemblepotential PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
 
-target_link_libraries(gmxapi_extension_ensemblepotential PRIVATE Gromacs::gmxapi)
+target_link_libraries(gmxapi_extension_ensemblepotential PUBLIC Gromacs::libgromacs Gromacs::gmxapi)
index 3cc6a2dbad0e3835225fe998aca8c9001fbb56fd..0952396d334cb0c46e940e691be9f8066f661337 100644 (file)
@@ -97,7 +97,7 @@ configure_file(testingconfiguration.in.h testingconfiguration.h)
 add_executable(gmxapi_extension_library-test test_binding.cpp)
 add_dependencies(gmxapi_extension_library-test gmxapi_extension_spc2_water_box)
 target_include_directories(gmxapi_extension_library-test PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
-target_link_libraries(gmxapi_extension_library-test Gromacs::gmxapi GTest::Main)
+target_link_libraries(gmxapi_extension_library-test Gromacs::libgromacs Gromacs::gmxapi GTest::Main)
 gtest_add_tests(TARGET gmxapi_extension_library-test
                 TEST_LIST BasicPlugin)
 
index 37ef0767824a937fcd2a92c7ce5d3ff8526e0a8b..e439b3366ec92f2cc49a51ff09915f105703d67a 100644 (file)
@@ -96,7 +96,7 @@ def spc_water_box(gmxcli, remove_tempdir):
         assert os.path.exists(topfile)
 
         if solvate.output.returncode.result() != 0:
-            logging.debug(solvate.output.erroroutput.result())
+            logging.debug(solvate.output.stderr.result())
             raise RuntimeError('solvate failed in spc_water_box testing fixture.')
 
         # Choose an exactly representable dt of 2^-9 ps (approximately 0.002)
@@ -132,7 +132,7 @@ def spc_water_box(gmxcli, remove_tempdir):
                                            output_files={'-o': tprfile})
         tprfilename = grompp.output.file['-o'].result()
         if grompp.output.returncode.result() != 0:
-            logging.debug(grompp.output.erroroutput.result())
+            logging.debug(grompp.output.stderr.result())
             raise RuntimeError('grompp failed in spc_water_box testing fixture.')
 
         # TODO: more inspection of grompp errors...
index c75549fc8213ba825f08154b882a04fb168982ff..e9da713490cb02650013f72296da0a94a99a29a8 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +38,7 @@
 # configure and run CMake. CMake could be invoked directly by the user or a
 # parent package, but the Python distribution would not be packaged automatically.
 # Reference https://gitlab.com/gromacs/gromacs/-/issues/2896 for additional discussion.
-cmake_minimum_required(VERSION 3.13.0)
+cmake_minimum_required(VERSION 3.16.3)
 
 # This needs to be set before project() in order to pick up toolchain files
 #list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../cmake)
@@ -55,7 +55,7 @@ set(CMAKE_OSX_ARCHITECTURES x86_64 CACHE STRING
 # Note that this is the gmxapi._gmxapi Python bindings package version,
 # not the C++ API version. It is not essential that it match the pure Python
 # package version, but is likely to do so.
-project(gmxapi VERSION 0.2.0)
+project(gmxapi VERSION 0.3.0)
 
 # Check if Python package is being built directly or via add_subdirectory
 set(GMXAPI_MASTER_PROJECT OFF)
index 0166dcebe13d56e1413aefabea6a3158c377f076..04269854925ccc7f6e5fa2f982975f64f416b432 100644 (file)
@@ -60,7 +60,8 @@ logger.info('Importing {}'.format(__name__))
 #    * provides `output` publishing proxy to the inner function and
 #    * produce a result with attributes for
 #       * file: mapping of output flags to output filenames
-#       * erroroutput: text results in case of error
+#       * stdout: process STDOUT
+#       * stderr: porcess STDERR
 #       * returncode: integer return code of wrapped command
 #
 # Note that the existence of the 'file' output map is expressed here, but
@@ -70,7 +71,9 @@ logger.info('Importing {}'.format(__name__))
 #
 # TODO: Operation returns the output object when called with the shorter signature.
 #
-@gmx.function_wrapper(output={'erroroutput': str, 'returncode': int})
+@gmx.function_wrapper(output={'stdout': str,
+                              'stderr': str,
+                              'returncode': int})
 def cli(command: NDArray, shell: bool, output: OutputCollectionDescription, stdin: str = ''):
     """Execute a command line program in a subprocess.
 
@@ -117,23 +120,21 @@ def cli(command: NDArray, shell: bool, output: OutputCollectionDescription, stdi
             >>> my_filename = "somefilename"
             >>> result = cli(('exe', '--origin', 1.0, 2.0, 3.0, '-f', my_filename), shell=False)
             >>> assert hasattr(result, 'file')
-            >>> assert hasattr(result, 'erroroutput')
+            >>> assert hasattr(result, 'stdout')
+            >>> assert hasattr(result, 'stderr')
             >>> assert hasattr(result, 'returncode')
 
     Returns:
-        A data structure with attributes for each of the results `file`, `erroroutput`, and `returncode`
+        A data structure with attributes for each of the results `file`, `stdout`, `stderr`, and `returncode`
 
     Result object attributes:
         * `file`: the mapping of CLI flags to filename strings resulting from the `output` kwarg
-        * `erroroutput`: A string of error output (if any) if the process failed.
+        * `stdout`: A string mapping from process STDOUT.
+        * `stderr`: A string mapping from process STDERR; it will be the
+                    error output (if any) if the process failed.
         * `returncode`: return code of the subprocess.
 
     """
-    # Note: we could make provisions for stdio filehandles in a future version. E.g.
-    # * STDOUT is available if a consuming operation is bound to `output.stdout`.
-    # * STDERR is available if a consuming operation is bound to `output.stderr`.
-    # * Otherwise, STDOUT and/or STDERR is(are) closed when command is called.
-
     # In the operation implementation, we expect the `shell` parameter to be intercepted by the
     # wrapper and set to False.
     if shell:
@@ -154,7 +155,8 @@ def cli(command: NDArray, shell: bool, output: OutputCollectionDescription, stdi
     # TODO: (FR9) Can OS input/output filehandles be a responsibility of
     #  the code providing 'resources'?
 
-    erroroutput = ''
+    stdout = ''
+    stderr = ''
     logger.debug('executing subprocess')
     try:
         completed_process = subprocess.run(command,
@@ -162,20 +164,38 @@ def cli(command: NDArray, shell: bool, output: OutputCollectionDescription, stdi
                                            input=stdin,
                                            check=True,
                                            stdout=subprocess.PIPE,
-                                           stderr=subprocess.STDOUT,
+                                           stderr=subprocess.PIPE,
                                            encoding='utf-8',
                                            universal_newlines=True
                                            )
         returncode = completed_process.returncode
         # TODO: Resource management code should manage a safe data object for `output`.
-        for line in completed_process.stdout.split('\n'):
-            logger.debug(line)
+        logger.debug('STDOUT:')
+        if completed_process.stderr is not None:
+            for line in completed_process.stdout.split('\n'):
+                logger.debug(line)
+        else:
+            logger.debug('STDOUT is empty')
+        logger.debug('STDERR:')
+        if completed_process.stderr is not None:
+            for line in completed_process.stderr.split('\n'):
+                logger.debug(line)
+        else:
+            logger.debug('STDERR is empty')
+
+        stdout = completed_process.stdout
+        stderr = completed_process.stderr
+
     except subprocess.CalledProcessError as e:
-        logger.info("commandline operation had non-zero return status when calling {}".format(e.cmd))
-        erroroutput = e.output
+        logger.info("commandline operation had non-zero return status"
+                    "when calling {}".format(e.cmd))
+        stdout = e.stdout
+        stderr = e.stderr
         returncode = e.returncode
+
     # Publish outputs.
-    output.erroroutput = erroroutput
+    output.stdout = stdout
+    output.stderr = stderr
     output.returncode = returncode
 
 
@@ -253,7 +273,9 @@ def commandline_operation(executable=None,
         The output node of the resulting operation handle contains
 
         * ``file``: the mapping of CLI flags to filename strings resulting from the ``output_files`` kwarg
-        * ``erroroutput``: A string of error output (if any) if the process failed.
+        * ``stdout``: A string mapping from process STDOUT.
+        * ``stderr``: A string mapping from process STDERR; it will be the
+                      error output (if any) if the process failed.
         * ``returncode``: return code of the subprocess.
 
     """
@@ -284,15 +306,23 @@ def commandline_operation(executable=None,
     #
     # TODO: (FR4+) Characterize the `file` dictionary key type:
     #  explicitly sequences rather than maybe-string/maybe-sequence-of-strings
-    @gmx.function_wrapper(output={'erroroutput': str, 'returncode': int, 'file': dict})
-    def merged_ops(erroroutput: str = None, returncode: int = None, file: dict = None,
+    @gmx.function_wrapper(output={'stdout': str,
+                                  'stderr': str,
+                                  'returncode': int,
+                                  'file': dict})
+    def merged_ops(stdout: str = None,
+                   stderr: str = None,
+                   returncode: int = None,
+                   file: dict = None,
                    output: OutputCollectionDescription = None):
-        assert erroroutput is not None
+        assert stdout is not None
+        assert stderr is not None
         assert returncode is not None
         assert file is not None
         assert output is not None
         output.returncode = returncode
-        output.erroroutput = erroroutput
+        output.stdout = stdout
+        output.stderr = stderr
         if returncode == 0:
             output.file = file
         else:
@@ -328,7 +358,8 @@ def commandline_operation(executable=None,
     # TODO: ``label`` kwarg
     # TODO: input fingerprinting
     cli_result = cli(**cli_args)
-    merged_result = merged_ops(erroroutput=cli_result.output.erroroutput,
+    merged_result = merged_ops(stdout=cli_result.output.stdout,
+                               stderr=cli_result.output.stderr,
                                returncode=cli_result.output.returncode,
                                file=output_files,
                                **kwargs)
index f618f052b7892a6de044ab9025401ac85069d658..4b8d15adb80a154759cc5cd43ecc61e51448a115 100644 (file)
@@ -158,7 +158,8 @@ void export_context(py::module& m)
     // Add argument type before it is used for more sensible automatic bindings behavior.
     py::class_<MDArgs, std::unique_ptr<MDArgs>> mdargs(m, "MDArgs");
     mdargs.def(py::init(), "Create an empty MDArgs object.");
-    mdargs.def("set", [](MDArgs* self, const py::dict& params) { setMDArgs(self, params); },
+    mdargs.def("set",
+               [](MDArgs* self, const py::dict& params) { setMDArgs(self, params); },
                "Assign parameters in MDArgs from Python dict.");
 
     // Export execution context class
index fd864f5ada12adb19b29a33b640c8b4d7cdfe665..a8012618a8ec52753cc77daeb26d3b13466f498f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +87,8 @@ void export_exceptions(pybind11::module& m)
     struct UnknownExceptionPlaceHolder
     {
     };
-    static py::exception<UnknownExceptionPlaceHolder> unknownException(m, "UnknownException",
-                                                                       baseException.ptr());
+    static py::exception<UnknownExceptionPlaceHolder> unknownException(
+            m, "UnknownException", baseException.ptr());
     unknownException.doc() =
             "GROMACS library produced an exception that is "
             "not mapped in gmxapi or which should have been "
index 91463edcff05023a8b1ff335eaed5ff85a58e432..bbb68ed0f834a25eea3619fc1e8daea21a47472f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -75,7 +75,8 @@ void export_system(py::module& m)
     // required to maintain and to pass to the API.
     py::class_<::gmxapi::Session, std::shared_ptr<::gmxapi::Session>> session(m, "MDSession");
     session.def("run", &::gmxapi::Session::run, "Run the simulation workflow");
-    session.def("close", &::gmxapi::Session::close,
+    session.def("close",
+                &::gmxapi::Session::close,
                 "Shut down the execution environment and close the session.");
 
     // Export system container class
@@ -88,7 +89,8 @@ void export_system(py::module& m)
                "Launch the configured workflow in the provided context.");
 
     // Module-level function
-    m.def("from_tpr", &gmxpy::from_tpr,
+    m.def("from_tpr",
+          &gmxpy::from_tpr,
           "Return a system container initialized from the given input record.");
 }
 
index 9a80297e459928f0db126b11b671282e37c6fd65..4f7301e2dfa0bc359d921bbd558d5e5077e63df4 100644 (file)
@@ -112,19 +112,22 @@ void detail::export_tprfile(pybind11::module& module)
                  [](GmxMdParams* self, const std::string& key, int64_t value) {
                      gmxapicompat::setParam(self, key, value);
                  },
-                 py::arg("key").none(false), py::arg("value").none(false),
+                 py::arg("key").none(false),
+                 py::arg("value").none(false),
                  "Use a dictionary to update simulation parameters.");
     mdparams.def("set",
                  [](GmxMdParams* self, const std::string& key, double value) {
                      gmxapicompat::setParam(self, key, value);
                  },
-                 py::arg("key").none(false), py::arg("value").none(false),
+                 py::arg("key").none(false),
+                 py::arg("value").none(false),
                  "Use a dictionary to update simulation parameters.");
     mdparams.def("set",
                  [](GmxMdParams* self, const std::string& key, py::none) {
                      // unsetParam(self, key);
                  },
-                 py::arg("key").none(false), py::arg("value"),
+                 py::arg("key").none(false),
+                 py::arg("value"),
                  "Use a dictionary to update simulation parameters.");
 
 
@@ -134,7 +137,9 @@ void detail::export_tprfile(pybind11::module& module)
         return params;
     });
 
-    module.def("read_tprfile", &readTprFile, py::arg("filename"),
+    module.def("read_tprfile",
+               &readTprFile,
+               py::arg("filename"),
                "Get a handle to a TPR file resource for a given file name.");
 
     module.def("write_tprfile",
@@ -146,21 +151,25 @@ void detail::export_tprfile(pybind11::module& module)
                    auto topology      = gmxapicompat::getTopologySource(tprReadHandle);
                    gmxapicompat::writeTprFile(filename, *params, *structure, *state, *topology);
                },
-               py::arg("filename").none(false), py::arg("parameters"),
+               py::arg("filename").none(false),
+               py::arg("parameters"),
                "Write a new TPR file with the provided data.");
 
     module.def("copy_tprfile",
                [](const gmxapicompat::TprReadHandle& input, std::string outFile) {
                    return gmxapicompat::copy_tprfile(input, outFile);
                },
-               py::arg("source"), py::arg("destination"),
+               py::arg("source"),
+               py::arg("destination"),
                "Copy a TPR file from ``source`` to ``destination``.");
 
     module.def("rewrite_tprfile",
                [](std::string input, std::string output, double end_time) {
                    return gmxapicompat::rewrite_tprfile(input, output, end_time);
                },
-               py::arg("source"), py::arg("destination"), py::arg("end_time"),
+               py::arg("source"),
+               py::arg("destination"),
+               py::arg("end_time"),
                "Copy a TPR file from ``source`` to ``destination``, replacing `nsteps` with "
                "``end_time``.");
 }
index 0496dc2b8a49b8e2960729e328133abd234e0ab4..1601cbae142441d23d9309a38018f7d91c1b130f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@ PYBIND11_MODULE(_gmxapi, m)
     export_exceptions(m);
 
     // Export core bindings
-    m.def("has_feature", &gmxapi::Version::hasFeature,
+    m.def("has_feature",
+          &gmxapi::Version::hasFeature,
           "Check the gmxapi library for a named feature.");
 
     py::class_<::gmxapi::Status> gmx_status(m, "Status", "Holds status for API operations.");
index 94a37af107702f5e11b749515d1db5eec03c50d5..ae443a53772e88a12eebf707e8b2aeca0c313c90 100644 (file)
@@ -70,7 +70,7 @@ from .exceptions import FeatureNotAvailableError
 
 # TODO: Version management policy and procedures.
 _major = 0
-_minor = 2
+_minor = 3
 _micro = 0
 _suffix = ''
 
index c8ae4732193e327ecac5477458d663e9ee56d1e9..7ec8697061048710ad4ffc682a6fc0d11123f61d 100644 (file)
@@ -161,7 +161,7 @@ setup(
     name='gmxapi',
 
     # TODO: single-source version information (currently repeated in gmxapi/version.py and CMakeLists.txt)
-    version='0.2.0',
+    version='0.3.0a1',
     python_requires='>=3.6',
     install_requires=['networkx>=2.0',
                       'numpy>=1'],
index aa9d69a2b0ecfd277c288873b86fd667f735447f..b80c21d4392ecc6044903236b1997e44a91f458f 100644 (file)
@@ -94,7 +94,7 @@ def spc_water_box(gmxcli, remove_tempdir):
         assert os.path.exists(topfile)
 
         if solvate.output.returncode.result() != 0:
-            logging.debug(solvate.output.erroroutput.result())
+            logging.debug(solvate.output.stderr.result())
             raise RuntimeError('solvate failed in spc_water_box testing fixture.')
 
         # Choose an exactly representable dt of 2^-9 ps (approximately 0.002)
@@ -130,7 +130,7 @@ def spc_water_box(gmxcli, remove_tempdir):
                                            output_files={'-o': tprfile})
         tprfilename = grompp.output.file['-o'].result()
         if grompp.output.returncode.result() != 0:
-            logging.debug(grompp.output.erroroutput.result())
+            logging.debug(grompp.output.stderr.result())
             raise RuntimeError('grompp failed in spc_water_box testing fixture.')
 
         # TODO: more inspection of grompp errors...
index 9aa5dbd4b4eb8d08d318596f18092c7262597892..b5dd1838fe056390d9715f37a712e9c6b2a1aa59 100644 (file)
@@ -60,15 +60,12 @@ class SimpleCliTestCase(unittest.TestCase):
         command = shutil.which('true')
         operation = commandline.cli(command=[command], shell=False)
 
-        # Note: 'stdout' and 'stderr' not mapped.
         # Note: getitem not implemented.
-        # assert not 'stdout' in operation.output
-        # assert not 'stderr' in operation.output
-        assert not hasattr(operation.output, 'stdout')
-        assert not hasattr(operation.output, 'stderr')
-
-        # Check for the attributes that we _do_ expect.
-        assert hasattr(operation.output, 'erroroutput')
+        # assert 'stdout' in operation.output
+        # assert 'stderr' in operation.output
+        assert hasattr(operation.output, 'stdout')
+        assert hasattr(operation.output, 'stderr')
+        assert not hasattr(operation.output, 'erroroutput')
         assert hasattr(operation.output, 'returncode')
 
         operation.run()
@@ -118,14 +115,13 @@ class CommandLineOperationSimpleTestCase(unittest.TestCase):
 
     def test_true(self):
         operation = commandline.commandline_operation(executable='true')
-        # Note: 'stdout' and 'stderr' not mapped.
         # Note: getitem not implemented.
-        # assert not 'stdout' in operation.output
-        # assert not 'stderr' in operation.output
-        assert not hasattr(operation.output, 'stdout')
-        assert not hasattr(operation.output, 'stderr')
+        # assert 'stdout' in operation.output
+        # assert 'stderr' in operation.output
+        assert not hasattr(operation.output, 'erroroutput')
         assert hasattr(operation.output, 'file')
-        assert hasattr(operation.output, 'erroroutput')
+        assert hasattr(operation.output, 'stdout')
+        assert hasattr(operation.output, 'stderr')
         assert hasattr(operation.output, 'returncode')
         assert operation.output.returncode.result() == 0
 
@@ -134,7 +130,7 @@ class CommandLineOperationSimpleTestCase(unittest.TestCase):
         assert operation.output.returncode.result() == 1
 
     def test_echo(self):
-        # TODO: (FR5+) do we want to pipeline or checkpoint stdout somehow?
+        # TODO: (#3549) Check stdout, stderr.
         operation = commandline.commandline_operation(executable='echo',
                                                       arguments=['hi there'])
         assert operation.output.returncode.result() == 0
index 47b14d0ef62d6e2187695b6b7f01a4a563803390..00828e711cdf8d63a1116c7e1c11a15ef5ac0e3a 100644 (file)
@@ -41,7 +41,7 @@ endif()
 # This should be removable once object libraries can directly use target_link_libraries
 # with CMake 3.12, #3290
 target_include_directories(template SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/src/external)
-target_link_libraries(template libgromacs ${GMX_EXE_LINKER_FLAGS})
+target_link_libraries(template libgromacs legacy_modules ${GMX_EXE_LINKER_FLAGS})
 
 set(DOCUMENTATION_HTTP_URL_BASE
     http://jenkins.gromacs.org/job/Documentation_Nightly_master/javadoc)
index a7ddcdd67b2faa1abe56cbaf2858568ecba2407c..9299e06272fc45506c6f675647a4683809deec3c 100644 (file)
@@ -1,8 +1,8 @@
-cmake_minimum_required(VERSION 3.9.6)
+cmake_minimum_required(VERSION 3.16.3)
 
 project(template CXX)
 
-set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 set(CMAKE_CXX_EXTENSIONS OFF)
 
index f1dadb766db241a994e6980e874b12c11f2c6dc0..dbdd12a1f585b1996069b78c6b030f7978aad06b 100644 (file)
@@ -104,7 +104,7 @@ AnalysisTemplate::initOptions(IOptionsContainer          *options,
     settings->setHelpText(desc);
 
     options->addOption(FileNameOption("o")
-                           .filetype(eftPlot).outputFile()
+                           .filetype(OptionFileType::Plot).outputFile()
                            .store(&fnDist_).defaultBasename("avedist")
                            .description("Average distances from reference group"));
 
index 6a7556b89ebe66054b1ed70087d62439792c00b6..4cfa2bddc8c112f12e021a16ff413faa9a193481 100644 (file)
@@ -33,6 +33,8 @@
 # We need to use underscores for readability for our legacy types
 # and command-line parameter names
 #
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
 Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
          bugprone-*,misc-*,readability-*,performance-*,mpi-*,
          -readability-inconsistent-declaration-parameter-name,
@@ -56,7 +58,9 @@ Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureA
          -cppcoreguidelines-macro-usage,
          -cppcoreguidelines-narrowing-conversions,
          -bugprone-narrowing-conversions,
-         -google-readability-avoid-underscore-in-googletest-name
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion
 HeaderFilterRegex: .*
 CheckOptions:
   - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
index 98c36ee119803b616b24a6288c586f1d77864b8b..bdf63b27cc949d18b677f8a4b7ed601b27ae7aab 100644 (file)
@@ -24,7 +24,9 @@ Checks:  clang-diagnostic-*,-clang-analyzer-*,
          -readability-magic-numbers,
          -cppcoreguidelines-macro-usage,
          -cppcoreguidelines-narrowing-conversions,
-         -bugprone-narrowing-conversions
+         -cppcoreguidelines-init-variables,
+         -bugprone-narrowing-conversions,
+         -misc-no-recursion
 HeaderFilterRegex: .*
 CheckOptions:
   - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
index b987bdb5e56b62b382ae91e729601ca99a94bdd8..aac191361c61439090c18ebf3fea22b638972b5b 100644 (file)
@@ -53,7 +53,7 @@ endif()
 # CMAKE_BUILD_TYPE is #included into buildinfo.h and populates the
 # fields e.g. printed to the log file.
 file(GENERATE
-    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/compilerflaginfo-$<CONFIG>-$<COMPILE_LANGUAGE>.h
+    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/include/compilerflaginfo-$<CONFIG>-$<COMPILE_LANGUAGE>.h
     INPUT ${CMAKE_CURRENT_SOURCE_DIR}/compilerflaginfo.h.cmakein
     CONDITION $<CONFIG:${CMAKE_BUILD_TYPE}>
     )
@@ -114,6 +114,19 @@ if (GMX_CLANG_TIDY)
    mark_as_advanced(CLANG_TIDY_EXE)
 endif()
 
+# Create a basic target for the `src` section of the build tree to capture
+# the library-level shared details through CMake infrastructure. It is not
+# installed or exported, so it must only be used as a PRIVATE dependency by
+# installed targets.
+# Initially, this is just an INTERFACE target to provide include directory.
+# It should also absorb global variables and compiler/linker details to be
+# provided as transitive usage requirements.
+# It could expand to aggregate the module targets in the future.
+add_library(common INTERFACE)
+target_include_directories(common INTERFACE
+                           ${CMAKE_CURRENT_SOURCE_DIR}/include
+                           ${CMAKE_CURRENT_BINARY_DIR}/include)
+
 add_subdirectory(external)
 
 if (BUILD_TESTING)
@@ -139,9 +152,9 @@ add_subdirectory(api)
 # header file in both of the make stages. That's slow, and is useless
 # busy work for ccache, too.
 string(TOUPPER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_UPPER)
-configure_file(config.h.cmakein config.h)
-configure_file(gmxpre-config.h.cmakein gmxpre-config.h)
+configure_file(config.h.cmakein include/config.h)
+configure_file(gmxpre-config.h.cmakein include/gmxpre-config.h)
 
 set(CMAKE_BUILD_CONFIGURATION_C_FLAGS   ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPER}})
 set(CMAKE_BUILD_CONFIGURATION_CXX_FLAGS ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}})
-configure_file(buildinfo.h.cmakein buildinfo.h ESCAPE_QUOTES)
+configure_file(buildinfo.h.cmakein include/buildinfo.h ESCAPE_QUOTES)
index 0f62185f143abe8b94d62b9ffe298bf215408c49..0206ba1b3d0855236a03ae3a89f85c23c78de3b4 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +34,6 @@
 
 # Activate targets for new C++ API components and docs.
 if (GMXAPI)
-    if (GMX_BUILD_MDRUN_ONLY)
-        message(FATAL_ERROR "GMXAPI relies on libgromacs and is incompatible with GMX_BUILD_MDRUN_ONLY.")
-    endif()
     if(NOT ${BUILD_SHARED_LIBS})
         # Note: this conditional should check for the existence of a libgromacs target supporting PIC
         # using the POSITION_INDEPENDENT_CODE property, but for now the only facility we have is the global
diff --git a/src/api/cpp/tests/.clang-tidy b/src/api/cpp/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 11d001db648d6bcf36769e8b4bf9adecbaaacbeb..08ce92c084c77f2f3f50418343aa7043c2f829da 100644 (file)
@@ -45,7 +45,6 @@
 #include "gromacs/math/vectypes.h"
 #include "gromacs/restraint/restraintpotential.h"
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmxapi
 {
index d96760836ee2d1906f67d89bc365d8201213f4e7..cfe49d757a8da5ec80fc311e2b7a4dabd3718b05 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018, by the GROMACS development team, led by
+ * Copyright (c) 2018,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -93,13 +93,14 @@ TEST_F(GmxApiTest, RunnerReinitialize)
         auto session = system.launch(context);
 
         // Try to simulate an interrupt signal to catch.
-        gmx_set_stop_condition(gmx_stop_cond_next_ns);
+        gmx_set_stop_condition(StopCondition::NextNS);
 
-        session->run();
+        auto status = session->run();
+        EXPECT_FALSE(status.success());
 
         // If this assertion fails, it is not an error, but it indicates expected behavior has
         // changed and we need to consider the impact of whatever changes caused this.
-        EXPECT_NE(gmx_get_stop_condition(), gmx_stop_cond_none);
+        EXPECT_NE(gmx_get_stop_condition(), StopCondition::None);
 
         session->close();
     } // allow system and session to be destroyed.
@@ -112,17 +113,18 @@ TEST_F(GmxApiTest, RunnerReinitialize)
         // changed and we need to consider the impact of whatever changes caused this.
         // We are expecting that the libgromacs state has retained the stop condition from the
         // previously issued SIGINT
-        EXPECT_NE(gmx_get_stop_condition(), gmx_stop_cond_none);
+        EXPECT_NE(gmx_get_stop_condition(), StopCondition::None);
 
         auto session = system.launch(context);
 
         // Launching a session should clear the stop condition.
-        EXPECT_EQ(gmx_get_stop_condition(), gmx_stop_cond_none);
+        EXPECT_EQ(gmx_get_stop_condition(), StopCondition::None);
 
-        session->run();
+        auto status = session->run();
+        EXPECT_TRUE(status.success());
 
         // Stop condition should still be clear.
-        EXPECT_EQ(gmx_get_stop_condition(), gmx_stop_cond_none);
+        EXPECT_EQ(gmx_get_stop_condition(), StopCondition::None);
 
         session->close();
     }
index e7180f8984b17b08518a092a7755d7d49375eda7..1becf040882c7cd929905c9b84a557349fc16453 100644 (file)
@@ -112,7 +112,8 @@ public:
                                   "tau-t = 1\n"
                                   "ref-t = 298\n"
                                   "compressed-x-grps = Sol\n",
-                                  steps, getTestStepSize()));
+                                  steps,
+                                  getTestStepSize()));
 
         EXPECT_EQ(0, runner_.callGromppOnThisRank());
     }
diff --git a/src/api/cpp/workflow/tests/.clang-tidy b/src/api/cpp/workflow/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..365b9bc
--- /dev/null
@@ -0,0 +1,86 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# Test code relies on exported and globally accessible variables.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 5991b0c71124912cf9a68553ee7e90b44ca9d6a6..1554d4aa853469d605cdc399025eef5f550248c4 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2009,2010,2011,2012,2013 by the GROMACS development team.
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 /* AVX2 128-bit SIMD instruction set level was selected */
 #cmakedefine01 GMX_SIMD_X86_AVX2_128
 
-/* MIC (Xeon Phi) SIMD instruction set level was selected */
-#cmakedefine01 GMX_SIMD_X86_MIC
-
 /* AVX-512F foundation level instruction SIMD */
 #cmakedefine01 GMX_SIMD_X86_AVX_512
 
 /* AVX-512ER foundation level instruction SIMD */
 #cmakedefine01 GMX_SIMD_X86_AVX_512_KNL
 
-/* 32-bit ARM NEON SIMD instruction set level was selected */
-#cmakedefine01 GMX_SIMD_ARM_NEON
-
 /* ARM (AArch64) NEON Advanced SIMD instruction set level was selected */
 #cmakedefine01 GMX_SIMD_ARM_NEON_ASIMD
 
 /* SVE vector length */
 #define GMX_SIMD_ARM_SVE_LENGTH_VALUE @GMX_SIMD_ARM_SVE_LENGTH_VALUE@
 
-/* IBM VMX was selected as SIMD instructions (Power 6 and later) */
-#cmakedefine01 GMX_SIMD_IBM_VMX
-
 /* IBM VSX was selected as SIMD instructions (Power 7 and later) */
 #cmakedefine01 GMX_SIMD_IBM_VSX
 
-/* Fujitsu Sparc64 HPC-ACE SIMD acceleration */
-#cmakedefine01 GMX_SIMD_SPARC64_HPC_ACE
-
 /* Reference SIMD implementation for testing */
 #cmakedefine01 GMX_SIMD_REFERENCE
 
 /* Whether NBNXM and other SIMD kernels should be compiled */
 #cmakedefine01 GMX_USE_SIMD_KERNELS
 
-/* Whether a double-precision configuration may target accuracy equivalent to single precision */
-#cmakedefine01 GMX_RELAXED_DOUBLE_PRECISION
-
 /* Integer byte order is big endian. */
 #cmakedefine01 GMX_INTEGER_BIG_ENDIAN
 
    (MPI or thread_mpi) */
 #define GMX_MPI (GMX_LIB_MPI || GMX_THREAD_MPI)
 
-/* MPI_IN_PLACE exists for collective operations */
-#cmakedefine01 MPI_IN_PLACE_EXISTS
-
 /* Use OpenMP multithreading */
 #cmakedefine01 GMX_OPENMP
 
 /* Define if SYCL GPU acceleration is compiled */
 #cmakedefine01 GMX_GPU_SYCL
 
+/* Define if hipSYCL is used for SYCL support (otherwise DPCPP is assumed) */
+#cmakedefine01 GMX_SYCL_HIPSYCL
+
+/* Define if Intel's DPCPP is used (default unless hipSYCL is chosen) */
+#define GMX_SYCL_DPCPP (!GMX_SYCL_HIPSYCL)
+
 /* Use a single compilation unit when compiling the CUDA (non-bonded) kernels.  */
 #cmakedefine01 GMX_CUDA_NB_SINGLE_COMPILATION_UNIT
 
-/* Cluster size used by nonbonded OpenCL kernel. Should be 8 for NVIDIA/AMD and 4 for Intel */
-#define GMX_OPENCL_NB_CLUSTER_SIZE @GMX_OPENCL_NB_CLUSTER_SIZE@
+/* Use CUDA-aware MPI.  */
+#cmakedefine01 HAVE_CUDA_AWARE_MPI
+
+/* Cluster size used by nonbonded kernel. Should be 8 for NVIDIA/AMD and 4 for Intel */
+#define GMX_GPU_NB_CLUSTER_SIZE @GMX_GPU_NB_CLUSTER_SIZE@
 
 /* Define constants for build types (starting at 1 to make sure undefined values don't match) */
 #define CMAKE_BUILD_TYPE_DEBUG 1
 #cmakedefine01 HAVE_FSEEKO
 
 /* Define to 1 if _fseeki64 (and presumably _fseeki64) exists and is declared. */
+//NOLINTNEXTLINE(bugprone-reserved-identifier)
 #cmakedefine01 HAVE__FSEEKI64
 
 /* Have io.h (windows)*/
 #cmakedefine01 HAVE_MEMALIGN
 
 /* Define to 1 if you have the MSVC _aligned_malloc() function. */
+//NOLINTNEXTLINE(bugprone-reserved-identifier)
 #cmakedefine01 HAVE__ALIGNED_MALLOC
 
 /* Define to 1 if you have the clock_gettime() function. */
 #cmakedefine01 HAVE_FSYNC
 
 /* Define to 1 if you have the Windows _commit() function. */
+//NOLINTNEXTLINE(bugprone-reserved-identifier)
 #cmakedefine01 HAVE__COMMIT
 
 /* Define to 1 if you have the fileno() function. */
 #cmakedefine01 HAVE_FILENO
 
 /* Define to 1 if you have the _fileno() function. */
+//NOLINTNEXTLINE(bugprone-reserved-identifier)
 #cmakedefine01 HAVE__FILENO
 
 /* Define to 1 if you have the sigaction() function. */
  * malloc.h or xmmintrin.h, and 0 otherwise. Note that you need to
  * conditionally include the three headers too before using _mm_malloc().
  */
+//NOLINTNEXTLINE(bugprone-reserved-identifier)
 #cmakedefine01 HAVE__MM_MALLOC
 
 /* Define if SIGUSR1 is present */
index 10766f156640b5494d61c2c8de6464e64b010629..af6e5d46b6a7c79b9c8f674e90fb7e8ed4152b41 100644 (file)
@@ -1,4 +1,4 @@
 # We don't want any checks at all for external code, but that leads to
 # clang-tidy complaining that it is being run with no checks. So we
 # let it use a single check that is irrelevant for GROMACS.
-Checks: -clang-analyzer*,zircon-temporary-objects
+Checks: -clang-analyzer*,zircon-temporary-objects, -cppcoreguidelines*
index 1dc5d995d87dc0b2173e3e0c7d6cc69a29af0b24..a2d72afb81d58944eda879bdf3c7c0f5c71c504d 100644 (file)
@@ -109,12 +109,7 @@ typedef struct tMPI_Spinlock
 #else
 /* older versions of gcc don't support atomic intrinsics */
 
-#ifndef __MIC__
 #define tMPI_Atomic_memory_barrier() __asm__ __volatile__("sfence;" : : : "memory")
-#else
-/* MIC is in-order and does not need nor support sfense */
-#define tMPI_Atomic_memory_barrier() __asm__ __volatile__("" ::: "memory")
-#endif
 
 #define TMPI_ATOMIC_HAVE_NATIVE_FETCH_ADD
 static inline int tMPI_Atomic_fetch_add(tMPI_Atomic_t *a, int i)
diff --git a/src/external/thread_mpi/include/thread_mpi/mutex.h b/src/external/thread_mpi/include/thread_mpi/mutex.h
deleted file mode 100644 (file)
index fc5381a..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
-   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.
-   All rights reserved.
-
-   Redistribution and use in source and binary forms, with or without
-   modification, are permitted provided that the following conditions are met:
-   1) Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-   2) Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-   3) Neither the name of the copyright holders nor the
-   names of its contributors may be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-   THIS SOFTWARE IS PROVIDED BY US ''AS IS'' AND ANY
-   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-   DISCLAIMED. IN NO EVENT SHALL WE BE LIABLE FOR ANY
-   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-   If you want to redistribute modifications, please consider that
-   scientific software is very special. Version control is crucial -
-   bugs must be traceable. We will be happy to consider code for
-   inclusion in the official distribution, but derived work should not
-   be called official thread_mpi. Details are found in the README & COPYING
-   files.
- */
-
-/** \file
- *
- * \brief mutex objects with C++11 API compatibility.
- *
- * This header contains classes mutex and lock_guard, used in C++ mutex
- * implementations safe for exceptions.
- */
-
-#ifndef TMPI_MUTEX_H_
-#define TMPI_MUTEX_H_
-
-#include "visibility.h"
-#include "system_error.h"
-#include "threads.h"
-
-namespace tMPI
-{
-/*! \brief A lock guard class that allows for the simple management of
-           mutexes. C++11 compatible.
-
-    In C++, mutexes would normally have to be unlocked with explicit
-    exception handlers and unlock statements. This class automates that
-    by handling the mutex unlock in a destructor. The constructor locks
-    the mutex.
-
-    Usage example:
-    tMPI::mutex mtx;
-    void do_count()
-    {
-        tMPI::lock_guard<tMPI::mutex> lock(mtx);
-        count += 1;
-    }
- */
-template <class Mutex> class TMPI_EXPORT lock_guard
-{
-    public:
-        //! Lockable type that this lock operates on.
-        typedef Mutex mutex_type;
-        /*! \brief The constructor, which locks the mutex.
-
-            \param m The exisiting (globally accessible) mutex to lock. */
-        explicit lock_guard(mutex_type &m) : m_(m)
-        {
-            m_.lock();
-        }
-        //lock_guard(mutex_type &m, adopt_lock_t t);
-
-        /*! \brief The destructor, which unlocks the mutex */
-        ~lock_guard()
-        {
-            m_.unlock();
-        }
-    private:
-        // forbid copy constructor & assignment
-        lock_guard(const lock_guard &l);
-        lock_guard &operator=(const lock_guard &l);
-
-        mutex_type &m_;
-};
-
-/*! \brief A basic mutex class with C++11 compatibility.  */
-class TMPI_EXPORT mutex
-{
-    public:
-        //! Type of the native mutex handle.
-        typedef tMPI_Thread_mutex_t* native_handle_type;
-
-        /*! \brief The constructor.
-
-           Throws a tMPI::system_error exception upon failure. */
-        mutex()
-        {
-            int ret = tMPI_Thread_mutex_init(&handle_);
-            if (ret)
-            {
-                throw system_error(ret);
-            }
-        }
-
-        /*! \brief The destructor.*/
-        ~mutex()
-        {
-            tMPI_Thread_mutex_destroy(&handle_);
-        }
-
-        /*! \brief The lock function.
-
-           Throws a tMPI::system_error exception upon failure. */
-        void lock()
-        {
-            int ret = tMPI_Thread_mutex_lock(&handle_);
-            if (ret)
-            {
-                throw system_error(ret);
-            }
-        }
-
-        /*! \brief The try_lock function.
-
-           \return true if the lock was locked successfully, false if
-           another thread owned it, and implementation-specific if
-           already held by this thread. Do not rely on the return code
-           if the calling thread could already hold this lock. */
-        bool try_lock()
-        {
-            if (tMPI_Thread_mutex_trylock(&handle_))
-            {
-                return false;
-            }
-            return true;
-        }
-
-        /*! \brief The unlock function.
-
-           Throws a tMPI::system_error exception upon failure. */
-        void unlock()
-        {
-            int ret = tMPI_Thread_mutex_unlock(&handle_);
-            if (ret)
-            {
-                throw system_error(ret);
-            }
-        }
-
-        //! Returns the native handle for this mutex.
-        native_handle_type native_handle() { return &handle_; }
-    private:
-        // forbid copy constructor & assignment
-        mutex(const mutex &m);
-        mutex &operator=(const mutex &m);
-
-        tMPI_Thread_mutex_t handle_;
-};
-}
-
-#endif /* TMPI_MUTEX_H_ */
diff --git a/src/external/thread_mpi/include/thread_mpi/system_error.h b/src/external/thread_mpi/include/thread_mpi/system_error.h
deleted file mode 100644 (file)
index f425f7c..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-   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.
-   All rights reserved.
-
-   Redistribution and use in source and binary forms, with or without
-   modification, are permitted provided that the following conditions are met:
-   1) Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-   2) Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-   3) Neither the name of the copyright holders nor the
-   names of its contributors may be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-   THIS SOFTWARE IS PROVIDED BY US ''AS IS'' AND ANY
-   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-   DISCLAIMED. IN NO EVENT SHALL WE BE LIABLE FOR ANY
-   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-   If you want to redistribute modifications, please consider that
-   scientific software is very special. Version control is crucial -
-   bugs must be traceable. We will be happy to consider code for
-   inclusion in the official distribution, but derived work should not
-   be called official thread_mpi. Details are found in the README & COPYING
-   files.
- */
-
-/** \file
- * \brief A C++11 compatible system_error class for reporting exceptions
- *
- * This header contains class definitions for system_error.
- */
-
-#ifndef TMPI_SYSTEM_ERROR_H_
-#define TMPI_SYSTEM_ERROR_H_
-
-#include <stdexcept>
-
-#include "visibility.h"
-
-namespace tMPI
-{
-/*! \brief Subset of the C++11 system_error class
-
-   Only contains the errno-based constructor. */
-class system_error : public std::runtime_error
-{
-    public:
-        //! Type to represent error codes within this class.
-        typedef int error_code;
-
-        //system_error(error_code ec, const std::string& what_arg);
-        //system_error(error_code ec, const char* what_arg);
-        /*! \brief Constuctor that takes an system error number */
-        explicit system_error(error_code ec);
-
-        /*! \brief Returns the error code */
-        const error_code &code() const
-        {
-            return ec_;
-        }
-    private:
-        error_code ec_;
-};
-}
-
-#endif /* TMPI_SYSTEM_ERROR_H_ */
diff --git a/src/external/thread_mpi/src/system_error.cpp b/src/external/thread_mpi/src/system_error.cpp
deleted file mode 100644 (file)
index 46d116c..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-   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.
-   All rights reserved.
-
-   Redistribution and use in source and binary forms, with or without
-   modification, are permitted provided that the following conditions are met:
-   1) Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-   2) Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-   3) Neither the name of the copyright holders nor the
-   names of its contributors may be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-   THIS SOFTWARE IS PROVIDED BY US ''AS IS'' AND ANY
-   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-   DISCLAIMED. IN NO EVENT SHALL WE BE LIABLE FOR ANY
-   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-   If you want to redistribute modifications, please consider that
-   scientific software is very special. Version control is crucial -
-   bugs must be traceable. We will be happy to consider code for
-   inclusion in the official distribution, but derived work should not
-   be called official thread_mpi. Details are found in the README & COPYING
-   files.
- */
-
-#include <cerrno>
-#include <cstring>
-#include <cstdlib>
-#include <stdexcept>
-#include <string>
-#include "thread_mpi/system_error.h"
-
-tMPI::system_error::system_error(error_code ec)
-    : runtime_error(std::string(std::strerror(ec))), ec_(ec)
-{
-}
index e2576ef0bb3dca9ad4aad370e7bf5aac22eab8ef..812d5131e30677b454594f7e6728bc62fa1bbcd0 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,2018, Sander Pronk, Erik Lindahl.
+   Copyright (c) 2009,2018,2021, Sander Pronk, Erik Lindahl.
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or without
@@ -369,6 +369,12 @@ static void tMPI_Global_destroy(struct tmpi_global *g)
     tMPI_Thread_barrier_destroy(&(g->barrier));
     tMPI_Thread_mutex_destroy(&(g->timer_mutex));
     tMPI_Thread_mutex_destroy(&(g->comm_link_lock));
+    for (int i = 0; i < g->N_usertypes; i++)
+    {
+        tMPI_Free(g->usertypes[i]->comps);
+        tMPI_Free(g->usertypes[i]);
+    }
+    tMPI_Free(g->usertypes);
 }
 
 
index a4430e9dd6b356d01de7f3b301ddda8994f4630d..889289d019a6e6ebfe186a069ed6dcf204cc05dd 100644 (file)
@@ -2,7 +2,8 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
-# Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2015,2016,2017,2018,2019 by the GROMACS development team.
+# Copyright (c) 2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,17 +109,15 @@ add_subdirectory(imd)
 add_subdirectory(compat)
 add_subdirectory(mimic)
 add_subdirectory(modularsimulator)
-if (NOT GMX_BUILD_MDRUN_ONLY)
-    add_subdirectory(gmxana)
-    add_subdirectory(gmxpreprocess)
-    add_subdirectory(correlationfunctions)
-    add_subdirectory(statistics)
-    add_subdirectory(analysisdata)
-    add_subdirectory(coordinateio)
-    add_subdirectory(trajectoryanalysis)
-    add_subdirectory(energyanalysis)
-    add_subdirectory(tools)
-endif()
+add_subdirectory(gmxana)
+add_subdirectory(gmxpreprocess)
+add_subdirectory(correlationfunctions)
+add_subdirectory(statistics)
+add_subdirectory(analysisdata)
+add_subdirectory(coordinateio)
+add_subdirectory(trajectoryanalysis)
+add_subdirectory(energyanalysis)
+add_subdirectory(tools)
 
 get_property(PROPERTY_SOURCES GLOBAL PROPERTY GMX_LIBGROMACS_SOURCES)
 list(APPEND LIBGROMACS_SOURCES ${GMXLIB_SOURCES} ${MDLIB_SOURCES} ${PROPERTY_SOURCES})
@@ -142,10 +141,8 @@ if (WIN32)
 endif()
 list(APPEND libgromacs_object_library_dependencies thread_mpi)
 
-configure_file(version.h.cmakein version.h)
 if(GMX_INSTALL_LEGACY_API)
   install(FILES
-          ${CMAKE_CURRENT_BINARY_DIR}/version.h
          analysisdata.h
          options.h
          selection.h
@@ -188,6 +185,13 @@ if (GMX_GPU_CUDA)
 else()
     add_library(libgromacs ${LIBGROMACS_SOURCES})
 endif()
+target_link_libraries(libgromacs PRIVATE $<BUILD_INTERFACE:common>)
+# As long as the libgromacs target has source files that reference headers from
+# modules that don't provide CMake targets, libgromacs needs to use `src/`
+# amongst its include directories (to support `#include "gromacs/module/header.h"`).
+add_library(legacy_modules INTERFACE)
+target_include_directories(legacy_modules INTERFACE $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src>)
+target_link_libraries(libgromacs PRIVATE $<BUILD_INTERFACE:legacy_modules>)
 
 # Add these contents first because linking their tests can take a lot
 # of time, so we want lots of parallel work still available after
@@ -206,6 +210,7 @@ foreach(object_library ${libgromacs_object_library_dependencies})
         set_target_properties(${object_library} PROPERTIES POSITION_INDEPENDENT_CODE true)
     endif()
     target_include_directories(${object_library} SYSTEM BEFORE PRIVATE ${PROJECT_SOURCE_DIR}/src/external/thread_mpi/include)
+    target_link_libraries(${object_library} PRIVATE common)
 
     # Add the sources from the object libraries to the main library.
     target_sources(libgromacs PRIVATE $<TARGET_OBJECTS:${object_library}>)
@@ -299,7 +304,7 @@ endif()
 # Only add the -fsycl flag to sources that really need it
 if (GMX_GPU_SYCL)
     get_property(SYCL_SOURCES GLOBAL PROPERTY SYCL_SOURCES)
-    set_source_files_properties(${SYCL_SOURCES} PROPERTIES COMPILE_FLAGS "${SYCL_CXX_FLAGS}")
+    add_sycl_to_target(TARGET libgromacs SOURCES ${SYCL_SOURCES})
 endif()
 
 gmx_setup_tng_for_libgromacs()
@@ -321,6 +326,60 @@ target_link_libraries(libgromacs
                       PUBLIC
                       ${GMX_PUBLIC_LIBRARIES}
                       )
+target_link_libraries(libgromacs PUBLIC legacy_api)
+# Dependencies from libgromacs to the modules are set up here, but
+# once the add_subdirectory() commands are re-ordered then
+# responsibility for setting this up will move to the respective
+# modules.
+target_link_libraries(libgromacs PRIVATE
+                      $<BUILD_INTERFACE:analysisdata>
+                      $<BUILD_INTERFACE:applied_forces>
+                      $<BUILD_INTERFACE:commandline>
+                      $<BUILD_INTERFACE:compat>
+                      $<BUILD_INTERFACE:coordinateio>
+                      $<BUILD_INTERFACE:correlationfunctions>
+                      $<BUILD_INTERFACE:domdec>
+#                      $<BUILD_INTERFACE:energyanalysis>
+                      $<BUILD_INTERFACE:essentialdynamics>
+                      $<BUILD_INTERFACE:ewald>
+                      $<BUILD_INTERFACE:fft>
+                      $<BUILD_INTERFACE:fileio>
+                      $<BUILD_INTERFACE:gmxana>
+                      $<BUILD_INTERFACE:gmxlib>
+                      $<BUILD_INTERFACE:gmxpreprocess>
+                      $<BUILD_INTERFACE:gpu_utils>
+                      $<BUILD_INTERFACE:hardware>
+                      $<BUILD_INTERFACE:imd>
+                      $<BUILD_INTERFACE:linearalgebra>
+                      $<BUILD_INTERFACE:listed_forces>
+                      $<BUILD_INTERFACE:math>
+                      $<BUILD_INTERFACE:mdlib>
+                      $<BUILD_INTERFACE:mdrun>
+                      $<BUILD_INTERFACE:mdrunutility>
+                      $<BUILD_INTERFACE:mdspan>
+                      $<BUILD_INTERFACE:mdtypes>
+                      $<BUILD_INTERFACE:mimic>
+                      $<BUILD_INTERFACE:modularsimulator>
+                      $<BUILD_INTERFACE:nbnxm>
+                      $<BUILD_INTERFACE:onlinehelp>
+                      $<BUILD_INTERFACE:options>
+                      $<BUILD_INTERFACE:pbcutil>
+                      $<BUILD_INTERFACE:pulling>
+                      $<BUILD_INTERFACE:random>
+                      $<BUILD_INTERFACE:restraint>
+                      $<BUILD_INTERFACE:selection>
+                      $<BUILD_INTERFACE:simd>
+                      $<BUILD_INTERFACE:statistics>
+                      $<BUILD_INTERFACE:swap>
+                      $<BUILD_INTERFACE:tables>
+                      $<BUILD_INTERFACE:taskassignment>
+                      $<BUILD_INTERFACE:timing>
+                      $<BUILD_INTERFACE:tools>
+                      $<BUILD_INTERFACE:topology>
+                      $<BUILD_INTERFACE:trajectory>
+                      $<BUILD_INTERFACE:trajectoryanalysis>
+                      $<BUILD_INTERFACE:utility>
+    )
 if (GMX_OPENMP)
     target_link_libraries(libgromacs PUBLIC OpenMP::OpenMP_CXX)
 endif()
@@ -378,9 +437,8 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION MATCHES
     target_compile_options(libgromacs PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-w>)
 endif()
 
-# Only install the library in mdrun-only mode if it is actually necessary
-# for the binary
-if (NOT GMX_BUILD_MDRUN_ONLY OR BUILD_SHARED_LIBS)
+# TODO: Stop installing libgromacs. Possibly allow installation during deprecation period with GMX_INSTALL_LEGACY_API.
+if (BUILD_SHARED_LIBS)
     install(TARGETS libgromacs
             EXPORT libgromacs
             LIBRARY
@@ -398,12 +456,10 @@ if (NOT GMX_BUILD_MDRUN_ONLY OR BUILD_SHARED_LIBS)
     if(GMX_INSTALL_LEGACY_API)
         target_compile_features(libgromacs INTERFACE cxx_std_${CMAKE_CXX_STANDARD})
     endif()
-    add_library(Gromacs::libgromacs ALIAS libgromacs)
 endif()
+add_library(Gromacs::libgromacs ALIAS libgromacs)
 
-if (NOT GMX_BUILD_MDRUN_ONLY)
-    include(InstallLibInfo.cmake)
-endif()
+include(InstallLibInfo.cmake)
 
 # Technically, the user could want to do this for an OpenCL build
 # using the CUDA runtime, but currently there's no reason to want to
index 43b71d60ec8419f9b124bdf42e7f9211c16de451..c0541c80af83932d0eee74bed0790e2099598b56 100644 (file)
@@ -33,6 +33,7 @@
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
+add_library(analysisdata INTERFACE)
 file(GLOB ANALYSISDATA_SOURCES *.cpp modules/*.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${ANALYSISDATA_SOURCES} PARENT_SCOPE)
 
@@ -46,6 +47,37 @@ if(GMX_INSTALL_LEGACY_API)
             DESTINATION include/gromacs/analysisdata)
 endif()
 
+# Source files have the following private module dependencies.
+target_link_libraries(analysisdata PRIVATE
+#                      gmxlib
+#                      math
+#                      mdtypes
+#                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(analysisdata PUBLIC
+target_include_directories(analysisdata INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(analysisdata PUBLIC
+target_link_libraries(analysisdata INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when analysisdata is an OBJECT target
+#target_link_libraries(analysisdata PUBLIC legacy_api)
+#target_link_libraries(analysisdata PRIVATE common)
+
+# Module dependencies
+# analysisdata interfaces convey transitive dependence on these modules.
+#target_link_libraries(analysisdata PUBLIC
+target_link_libraries(analysisdata INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(analysisdata PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(analysisdata PRIVATE legacy_modules)
 
 add_subdirectory(modules)
 
index ca83202be56efe06ea5581d11099b88379b03cef..c8ed78454bd3dde1c08999bba1fad952112eeab9 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2015,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +46,6 @@
 
 #include <memory>
 
-#include "gromacs/utility/classhelpers.h"
-
 namespace gmx
 {
 
@@ -437,7 +435,7 @@ protected:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 0c74baf712fb51a19c6ab98025aaadb56480977a..5b4d12a761d7b706d4b60e21e3828ab9a3024d91 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -200,7 +200,7 @@ private:
 
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     friend class AnalysisDataHandle;
 };
index 8dfa05a5722630b2b99eeba5b9ced9b47d90528e..de6436e46c7f241a886678a1cb08d5f04433956e 100644 (file)
@@ -171,8 +171,7 @@ void AbstractAnalysisArrayData::valuesReady()
         AnalysisDataFrameHeader header(i, xvalue(i), 0);
         modules.notifyFrameStart(header);
         modules.notifyPointsAdd(AnalysisDataPointSetRef(
-                header, pointSetInfo_,
-                makeConstArrayRef(value_).subArray(i * columnCount(), columnCount())));
+                header, pointSetInfo_, makeConstArrayRef(value_).subArray(i * columnCount(), columnCount())));
         modules.notifyFrameFinish(header);
     }
     modules.notifyDataFinish();
index c034fd8ed27a030d85e12cc7e7afe5c74f13f566..07d66ea3562734ecb3b4742a31279329422eef7b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <vector>
 
 #include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/flags.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/real.h"
index bd51891b02bc4aa9d2285bc43255f7c2bec169ff..c5e982f579703b980b75eadf4d65317782183ed8 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -134,7 +134,7 @@ public:
      * calls the notification functions in \p module as if the module had
      * been registered to the data object when the data was added.
      */
-    void presentData(AbstractAnalysisData* data, IAnalysisDataModule* module);
+    void presentData(AbstractAnalysisData* data, IAnalysisDataModule* module) const;
 
     //! List of modules added to the data.
     ModuleList modules_;
@@ -216,7 +216,7 @@ void AnalysisDataModuleManager::Impl::checkModuleProperties(const IAnalysisDataM
     }
 }
 
-void AnalysisDataModuleManager::Impl::presentData(AbstractAnalysisData* data, IAnalysisDataModule* module)
+void AnalysisDataModuleManager::Impl::presentData(AbstractAnalysisData* data, IAnalysisDataModule* module) const
 {
     if (state_ == eNotStarted)
     {
index 55f15ac8579ebaf5c8827cfe28077e1838e62183..44c844b4b0d57c9d9cd5b5404eeca3b573b47506 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2015,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +44,9 @@
 #ifndef GMX_ANALYSISDATA_DATAMODULEMANAGER_H
 #define GMX_ANALYSISDATA_DATAMODULEMANAGER_H
 
+#include <memory>
+
 #include "gromacs/analysisdata/abstractdata.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
@@ -272,7 +273,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 78f379e8693e753006591fdc3b43c703d8f16fe8..2e701f2ecf46adbbb35b4a5a5b94bf838f3a1ae4 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/analysisdata/dataframe.h"
 #include "gromacs/analysisdata/datamodulemanager.h"
 #include "gromacs/analysisdata/paralleloptions.h"
+#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
 
@@ -674,8 +675,7 @@ void AnalysisDataStorageFrame::selectDataSet(int index)
 {
     GMX_RELEASE_ASSERT(data_ != nullptr, "Invalid frame accessed");
     const AbstractAnalysisData& baseData = data_->baseData();
-    GMX_RELEASE_ASSERT(index >= 0 && index < baseData.dataSetCount(),
-                       "Out of range data set index");
+    GMX_RELEASE_ASSERT(index >= 0 && index < baseData.dataSetCount(), "Out of range data set index");
     GMX_RELEASE_ASSERT(!baseData.isMultipoint() || !bPointSetInProgress_,
                        "Point sets in multipoint data cannot span data sets");
     currentDataSet_ = index;
@@ -712,8 +712,8 @@ void AnalysisDataStorageFrame::finishPointSet()
         {
             firstColumn = 0;
         }
-        data_->addPointSet(currentDataSet_, firstColumn,
-                           makeConstArrayRef(values_).subArray(begin, end - begin));
+        data_->addPointSet(
+                currentDataSet_, firstColumn, makeConstArrayRef(values_).subArray(begin, end - begin));
     }
     clearValues();
 }
@@ -810,7 +810,7 @@ void AnalysisDataStorage::startParallelDataStorage(AbstractAnalysisData*
 AnalysisDataStorageFrame& AnalysisDataStorage::startFrame(const AnalysisDataFrameHeader& header)
 {
     GMX_ASSERT(header.isValid(), "Invalid header");
-    internal::AnalysisDataStorageFrameData* storedFrame;
+    internal::AnalysisDataStorageFrameData* storedFrame = nullptr;
     if (impl_->storeAll())
     {
         size_t size = header.index() + 1;
index 789e6fc1260550da3e69fd59f4d2c06ebf4c7039..fad12ae58f3e072a07f8bf239005f291569d5cbe 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_ANALYSISDATA_DATASTORAGE_H
 #define GMX_ANALYSISDATA_DATASTORAGE_H
 
+#include <memory>
 #include <vector>
 
 #include "gromacs/analysisdata/dataframe.h"
@@ -428,7 +429,7 @@ public:
 private:
     typedef internal::AnalysisDataStorageImpl Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 01e62d61e17a702b7fa2bd04855e194567bcaba1..63abd9c69fb389f90037f0a3d6a3cf5d577b2f09 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_ANALYSISDATA_MODULES_AVERAGE_H
 #define GMX_ANALYSISDATA_MODULES_AVERAGE_H
 
+#include <memory>
 #include <vector>
 
 #include "gromacs/analysisdata/abstractdata.h"
 #include "gromacs/analysisdata/arraydata.h"
 #include "gromacs/analysisdata/datamodule.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
@@ -138,7 +138,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 //! Smart pointer to manage an AnalysisDataAverageModule object.
@@ -182,7 +182,7 @@ private:
 
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 //! Smart pointer to manage an AnalysisDataFrameAverageModule object.
index 1468268f663fc215cb2ed5436f71362fffbd524c..6e5ffb9b5487ed4545990276053166756545fada 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -252,8 +252,6 @@ void AnalysisDataDisplacementModule::frameFinished(const AnalysisDataFrameHeader
         return;
     }
 
-    int step, i;
-
     if (_impl->nstored == 2)
     {
         if (_impl->histm)
@@ -266,7 +264,7 @@ void AnalysisDataDisplacementModule::frameFinished(const AnalysisDataFrameHeader
     AnalysisDataFrameHeader header(_impl->nstored - 2, _impl->t, 0);
     moduleManager().notifyFrameStart(header);
 
-    for (i = _impl->ci - _impl->nmax, step = 1; step < _impl->nstored && i != _impl->ci;
+    for (int i = _impl->ci - _impl->nmax, step = 1; step < _impl->nstored && i != _impl->ci;
          i -= _impl->nmax, ++step)
     {
         if (i < 0)
index 9cad05c3ca6122e7d46b3c3f0d5921c3d595fc62..12916d7b321cdd90b6c18678d09c36b8010e7f81 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -98,7 +98,7 @@ private:
 
     class Impl;
 
-    PrivateImplPointer<Impl> _impl;
+    std::unique_ptr<Impl> _impl;
 };
 
 //! Smart pointer to manage an AnalysisDataDisplacementModule object.
index 379750facfc14dc7de9cf8e6219f1ab903e6d773..45e4defdcc0a78d4146ae4317803e850784c555f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <vector>
 
+#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/real.h"
 
index 72fb6e5e752e9cba1493568cf07a66fab0664637..59d5ac6ac79556634eeb99681e611bbe7b5f1090 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -267,43 +267,22 @@ void AbstractAverageHistogram::init(const AnalysisHistogramSettings& settings)
 
 AverageHistogramPointer AbstractAverageHistogram::resampleDoubleBinWidth(bool bIntegerBins) const
 {
-    int nbins;
-    if (bIntegerBins)
-    {
-        nbins = (rowCount() + 1) / 2;
-    }
-    else
-    {
-        nbins = rowCount() / 2;
-    }
+    const int nbins = bIntegerBins ? (rowCount() + 1) / 2 : rowCount() / 2;
 
     AverageHistogramPointer dest(new StaticAverageHistogram(
             histogramFromBins(settings().firstEdge(), nbins, 2 * xstep()).integerBins(bIntegerBins)));
     dest->setColumnCount(columnCount());
     dest->allocateValues();
 
-    int i, j;
-    for (i = j = 0; i < nbins; ++i)
+    for (int i = 0, j = 0; i < nbins; ++i)
     {
         const bool bFirstHalfBin = (bIntegerBins && i == 0);
         for (int c = 0; c < columnCount(); ++c)
         {
-            real v1, v2;
-            real e1, e2;
-            if (bFirstHalfBin)
-            {
-                v1 = value(0, c).value();
-                e1 = value(0, c).error();
-                v2 = 0;
-                e2 = 0;
-            }
-            else
-            {
-                v1 = value(j, c).value();
-                e1 = value(j, c).error();
-                v2 = value(j + 1, c).value();
-                e2 = value(j + 1, c).error();
-            }
+            const real v1 = bFirstHalfBin ? value(0, c).value() : value(j, c).value();
+            const real v2 = bFirstHalfBin ? 0 : value(j + 1, c).value();
+            const real e1 = bFirstHalfBin ? value(0, c).error() : value(j, c).error();
+            const real e2 = bFirstHalfBin ? 0 : value(j + 1, c).error();
             dest->value(i, c).setValue(v1 + v2, std::sqrt(e1 * e1 + e2 * e2));
         }
         if (bFirstHalfBin)
index c15844c6c3438d9de25bb5ac68294770ee18b860..8f4b5c39dfa7b62dad16bb2af770b4e2d210be7b 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -425,7 +425,7 @@ private:
 
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     // Copy and assign disallowed by base.
 };
@@ -487,7 +487,7 @@ private:
 
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     // Copy and assign disallowed by base.
 };
@@ -535,7 +535,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     // Copy and assign disallowed by base.
 };
index f791cabd27dcfd1c4b59da5e6dc3ab86de8c9d64..70ad587c59e8ec23ee1ac49b45131c6b3f43bde9 100644 (file)
@@ -195,7 +195,8 @@ void AnalysisDataLifetimeModule::dataFinished()
         // if explicitly requested.
         std::vector<Impl::LifetimeHistogram>::iterator histogram;
         for (histogram = impl_->lifetimeHistograms_.begin();
-             histogram != impl_->lifetimeHistograms_.end(); ++histogram)
+             histogram != impl_->lifetimeHistograms_.end();
+             ++histogram)
         {
             Impl::LifetimeHistogram::iterator shorter, longer;
             for (shorter = histogram->begin(); shorter != histogram->end(); ++shorter)
@@ -221,8 +222,8 @@ void AnalysisDataLifetimeModule::dataFinished()
     setColumnCount(impl_->lifetimeHistograms_.size());
     std::vector<Impl::LifetimeHistogram>::const_iterator histogram;
     size_t                                               maxLifetime = 1;
-    for (histogram = impl_->lifetimeHistograms_.begin();
-         histogram != impl_->lifetimeHistograms_.end(); ++histogram)
+    for (histogram = impl_->lifetimeHistograms_.begin(); histogram != impl_->lifetimeHistograms_.end();
+         ++histogram)
     {
         maxLifetime = std::max(maxLifetime, histogram->size());
     }
@@ -231,8 +232,8 @@ void AnalysisDataLifetimeModule::dataFinished()
     // Fill up the output data from the histograms.
     allocateValues();
     int column = 0;
-    for (histogram = impl_->lifetimeHistograms_.begin();
-         histogram != impl_->lifetimeHistograms_.end(); ++histogram, ++column)
+    for (histogram = impl_->lifetimeHistograms_.begin(); histogram != impl_->lifetimeHistograms_.end();
+         ++histogram, ++column)
     {
         int                                     row = 0;
         Impl::LifetimeHistogram::const_iterator i;
index ede0b25babbd6c6df90a33c03fff030ac564af56..d77eb486c9555ba453347b7924cced101992d709 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_ANALYSISDATA_MODULES_LIFETIME_H
 #define GMX_ANALYSISDATA_MODULES_LIFETIME_H
 
+#include <memory>
+
 #include "gromacs/analysisdata/arraydata.h"
 #include "gromacs/analysisdata/datamodule.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
@@ -102,7 +103,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 //! Smart pointer to manage an AnalysisDataLifetimeModule object.
index 0ea52a0b8d054a779253b09c46c96b608c29a7f8..09fab9e125a4a4e020e8ef956acbcd9ac6bdf041 100644 (file)
@@ -89,8 +89,9 @@ void AnalysisDataPlotSettings::setSelectionCollection(const SelectionCollection*
  * Technically this duplicates a definition in pargs.cpp for legacy
  * support code, but as the latter will go away and the alternatives
  * are ugly, the duplication is acceptable. */
-const gmx::EnumerationArray<XvgFormat, const char*> c_xvgFormatNames = { { "xmgrace", "xmgr",
-                                                                           "none" } };
+const gmx::EnumerationArray<XvgFormat, const char*> c_xvgFormatNames = {
+    { "xmgrace", "xmgr", "none" }
+};
 
 void AnalysisDataPlotSettings::initOptions(IOptionsContainer* options)
 {
@@ -312,8 +313,8 @@ void AbstractPlotModule::dataStarted(AbstractAnalysisData* /* data */)
             gmx_output_env_t* oenv;
             output_env_init(&oenv, getProgramContext(), timeUnit, FALSE, xvgFormat, 0);
             const unique_cptr<gmx_output_env_t, output_env_done> oenvGuard(oenv);
-            impl_->fp_ = xvgropen(impl_->filename_.c_str(), impl_->title_.c_str(), impl_->xlabel_,
-                                  impl_->ylabel_, oenv);
+            impl_->fp_ = xvgropen(
+                    impl_->filename_.c_str(), impl_->title_.c_str(), impl_->xlabel_, impl_->ylabel_, oenv);
             const SelectionCollection* selections = impl_->settings_.selectionCollection();
             if (selections != nullptr && output_env_get_xvg_format(oenv) != XvgFormat::None)
             {
index 7064a49c22567d8f26d717a42d1422ecf29ea109..371fb8fabbf63da7b645c88b850b8c18df9a1bc5 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +49,6 @@
 
 #include "gromacs/analysisdata/datamodule.h"
 #include "gromacs/options/timeunitmanager.h"
-#include "gromacs/utility/classhelpers.h"
 
 enum class XvgFormat : int;
 
@@ -254,7 +253,7 @@ protected:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 
diff --git a/src/gromacs/analysisdata/tests/.clang-tidy b/src/gromacs/analysisdata/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index bcecb7340e7f0ca17cbf22adf1a96d2eb4d4371f..c55d59b055fcc4e6247ccc1ceb8f7b86923d40c3 100644 (file)
@@ -35,6 +35,7 @@
 gmx_add_unit_test_library(analysisdata-test-shared
                           datatest.cpp
                           mock_datamodule.cpp)
+target_link_libraries(analysisdata-test-shared PRIVATE legacy_api)
 
 gmx_add_unit_test(AnalysisDataUnitTests analysisdata-test
     CPP_SOURCE_FILES
index e8009f40a129cf1ce97c879ef4d9d2fda0edd4eb..4bf7a4ef12f3b5493d034b1804c16d9703a7e371 100644 (file)
@@ -216,12 +216,15 @@ void AnalysisDataTestFixture::presentDataFrame(const AnalysisDataTestInput& inpu
         {
             if (points.hasError(j))
             {
-                handle.setPoint(j + points.firstColumn(), points.y(j), points.error(j),
+                handle.setPoint(j + points.firstColumn(),
+                                points.y(j),
+                                points.error(j),
                                 AnalysisDataTestInputPointSet::present(j));
             }
             else
             {
-                handle.setPoint(j + points.firstColumn(), points.y(j),
+                handle.setPoint(j + points.firstColumn(),
+                                points.y(j),
                                 AnalysisDataTestInputPointSet::present(j));
             }
         }
index e0ccf94153c50985002e66628481ea912fa8882d..e99f5e893546eb81c7c96ad21596e5743bd673b3 100644 (file)
@@ -523,8 +523,8 @@ void MockAnalysisDataModule::setupStaticCheck(const AnalysisDataTestInput& data,
             for (int ps = 0; ps < frame.pointSetCount(); ++ps)
             {
                 const AnalysisDataTestInputPointSet& points = frame.pointSet(ps);
-                StaticDataPointsChecker              checker(&frame, &points, 0,
-                                                data.columnCount(points.dataSetIndex()));
+                StaticDataPointsChecker              checker(
+                        &frame, &points, 0, data.columnCount(points.dataSetIndex()));
                 EXPECT_CALL(*this, pointsAdded(Property(&AnalysisDataPointSetRef::frameIndex, row)))
                         .WillOnce(Invoke(checker));
             }
@@ -557,8 +557,8 @@ void MockAnalysisDataModule::setupStaticCheck(const AnalysisDataTestInput& data,
             for (int ps = 0; ps < frame.pointSetCount(); ++ps)
             {
                 const AnalysisDataTestInputPointSet& points = frame.pointSet(ps);
-                StaticDataPointsChecker              checker(&frame, &points, 0,
-                                                data.columnCount(points.dataSetIndex()));
+                StaticDataPointsChecker              checker(
+                        &frame, &points, 0, data.columnCount(points.dataSetIndex()));
                 EXPECT_CALL(*this, pointsAdded(_)).WillOnce(Invoke(checker));
             }
             EXPECT_CALL(*this, frameFinished(_)).WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
index 65eaf2b06a54a1af618c372a4afd9bbdbd33bb7b..1ce1025e70fd0b8c0b1792a3d30f83c4a2ec1b35 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2011,2012,2013,2014,2015 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +53,6 @@
 #include "gromacs/analysisdata/dataframe.h"
 #include "gromacs/analysisdata/datamodule.h"
 #include "gromacs/analysisdata/paralleloptions.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
@@ -90,7 +89,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 //! Smart pointer to manage an MockAnalysisDataModule object.
index 498d44a220d3a56134a412990a8954b135cb83aa..92e40d38959c80ff450ee052afa191664ba487b4 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 up the module library
+add_library(applied_forces INTERFACE)
+
+# Source files have the following private module dependencies.
+target_link_libraries(applied_forces PRIVATE
+                      #                      gmxlib
+                      #                      math
+                      #                      mdtypes
+                      #                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(applied_forces PUBLIC
+target_include_directories(applied_forces INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(applied_forces PUBLIC
+target_link_libraries(applied_forces INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when fileio is an OBJECT target
+#target_link_libraries(applied_forces PUBLIC legacy_api)
+#target_link_libraries(applied_forces PRIVATE common)
+
+# Module dependencies
+# This module convey transitive dependence on these modules.
+#target_link_libraries(applied_forces PUBLIC
+target_link_libraries(applied_forces INTERFACE
+                      #                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(applied_forces PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(applied_forces PRIVATE legacy_modules)
+
 gmx_add_libgromacs_sources(
     electricfield.cpp
     )
index 0f3c8c28b4c55c6e5436eaebb0bde15c06e469b5..de3ebea8911512bd6c7116cee960bd856db039de 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstring>
 
 #include <algorithm>
+#include <vector>
 
 #include "gromacs/fileio/enxio.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/mdrunutility/multisim.h"
 #include "gromacs/mdtypes/awh_history.h"
 #include "gromacs/mdtypes/awh_params.h"
@@ -114,15 +116,10 @@ struct BiasCoupledToSystem
  */
 static bool anyDimUsesPull(const AwhBiasParams& awhBiasParams)
 {
-    for (int d = 0; d < awhBiasParams.ndim; d++)
-    {
-        const AwhDimParams& awhDimParams = awhBiasParams.dimParams[d];
-        if (awhDimParams.eCoordProvider == eawhcoordproviderPULL)
-        {
-            return true;
-        }
-    }
-    return false;
+    return std::any_of(
+            awhBiasParams.dimParams().begin(), awhBiasParams.dimParams().end(), [](const auto& awhDimParam) {
+                return awhDimParam.coordinateProvider() == AwhCoordinateProviderType::Pull;
+            });
 }
 
 /*! \brief Checks whether any dimension uses pulling as a coordinate provider.
@@ -132,15 +129,9 @@ static bool anyDimUsesPull(const AwhBiasParams& awhBiasParams)
  */
 static bool anyDimUsesPull(const AwhParams& awhParams)
 {
-    for (int k = 0; k < awhParams.numBias; k++)
-    {
-        const AwhBiasParams& awhBiasParams = awhParams.awhBiasParams[k];
-        if (anyDimUsesPull(awhBiasParams))
-        {
-            return true;
-        }
-    }
-    return false;
+    return std::any_of(awhParams.awhBiasParams().begin(),
+                       awhParams.awhBiasParams().end(),
+                       [](const auto& awhBiasParam) { return anyDimUsesPull(awhBiasParam); });
 }
 
 /*! \brief Checks whether any dimension uses pulling as a coordinate provider.
@@ -150,14 +141,9 @@ static bool anyDimUsesPull(const AwhParams& awhParams)
  */
 static bool anyDimUsesPull(const ArrayRef<BiasCoupledToSystem> biasCoupledToSystem)
 {
-    for (const auto& biasCts : biasCoupledToSystem)
-    {
-        if (!biasCts.pullCoordIndex_.empty())
-        {
-            return true;
-        }
-    }
-    return false;
+    return std::any_of(biasCoupledToSystem.begin(), biasCoupledToSystem.end(), [](const auto& biasCts) {
+        return !biasCts.pullCoordIndex_.empty();
+    });
 }
 
 BiasCoupledToSystem::BiasCoupledToSystem(Bias bias, const std::vector<int>& pullCoordIndex) :
@@ -179,8 +165,8 @@ Awh::Awh(FILE*                 fplog,
          pull_t*               pull_work,
          int                   numFepLambdaStates,
          int                   fepLambdaState) :
-    seed_(awhParams.seed),
-    nstout_(awhParams.nstOut),
+    seed_(awhParams.seed()),
+    nstout_(awhParams.nstout()),
     commRecord_(commRecord),
     multiSimRecord_(multiSimRecord),
     pull_(pull_work),
@@ -209,41 +195,39 @@ Awh::Awh(FILE*                 fplog,
     }
 
     int numSharingSimulations = 1;
-    if (awhParams.shareBiasMultisim && isMultiSim(multiSimRecord_))
+    if (awhParams.shareBiasMultisim() && isMultiSim(multiSimRecord_))
     {
         numSharingSimulations = multiSimRecord_->numSimulations_;
     }
 
     /* Initialize all the biases */
-    const double beta = 1 / (BOLTZ * inputRecord.opts.ref_t[0]);
-    for (int k = 0; k < awhParams.numBias; k++)
+    const double beta          = 1 / (gmx::c_boltz * inputRecord.opts.ref_t[0]);
+    const auto&  awhBiasParams = awhParams.awhBiasParams();
+    for (int k = 0; k < gmx::ssize(awhBiasParams); k++)
     {
-        const AwhBiasParams& awhBiasParams = awhParams.awhBiasParams[k];
-
         std::vector<int>       pullCoordIndex;
         std::vector<DimParams> dimParams;
-        for (int d = 0; d < awhBiasParams.ndim; d++)
+        for (const auto& awhDimParam : awhBiasParams[k].dimParams())
         {
-            const AwhDimParams& awhDimParams = awhBiasParams.dimParams[d];
-            if (awhDimParams.eCoordProvider != eawhcoordproviderPULL
-                && awhDimParams.eCoordProvider != eawhcoordproviderFREE_ENERGY_LAMBDA)
+            if (awhDimParam.coordinateProvider() != AwhCoordinateProviderType::Pull
+                && awhDimParam.coordinateProvider() != AwhCoordinateProviderType::FreeEnergyLambda)
             {
                 GMX_THROW(
                         InvalidInputError("Currently only the pull code and lambda are supported "
                                           "as coordinate providers"));
             }
-            if (awhDimParams.eCoordProvider == eawhcoordproviderPULL)
+            if (awhDimParam.coordinateProvider() == AwhCoordinateProviderType::Pull)
             {
-                const t_pull_coord& pullCoord = inputRecord.pull->coord[awhDimParams.coordIndex];
-                if (pullCoord.eGeom == epullgDIRPBC)
+                const t_pull_coord& pullCoord = inputRecord.pull->coord[awhDimParam.coordinateIndex()];
+                if (pullCoord.eGeom == PullGroupGeometry::DirectionPBC)
                 {
                     GMX_THROW(InvalidInputError(
                             "Pull geometry 'direction-periodic' is not supported by AWH"));
                 }
-                double conversionFactor = pull_coordinate_is_angletype(&pullCoord) ? DEG2RAD : 1;
-                pullCoordIndex.push_back(awhDimParams.coordIndex);
-                dimParams.push_back(DimParams::pullDimParams(conversionFactor,
-                                                             awhDimParams.forceConstant, beta));
+                double conversionFactor = pull_conversion_factor_userinput2internal(pullCoord);
+                pullCoordIndex.push_back(awhDimParam.coordinateIndex());
+                dimParams.emplace_back(DimParams::pullDimParams(
+                        conversionFactor, awhDimParam.forceConstant(), beta));
             }
             else
             {
@@ -254,10 +238,16 @@ Awh::Awh(FILE*                 fplog,
         /* Construct the bias and couple it to the system. */
         Bias::ThisRankWillDoIO thisRankWillDoIO =
                 (MASTER(commRecord_) ? Bias::ThisRankWillDoIO::Yes : Bias::ThisRankWillDoIO::No);
-        biasCoupledToSystem_.emplace_back(
-                Bias(k, awhParams, awhParams.awhBiasParams[k], dimParams, beta, inputRecord.delta_t,
-                     numSharingSimulations, biasInitFilename, thisRankWillDoIO),
-                pullCoordIndex);
+        biasCoupledToSystem_.emplace_back(Bias(k,
+                                               awhParams,
+                                               awhBiasParams[k],
+                                               dimParams,
+                                               beta,
+                                               inputRecord.delta_t,
+                                               numSharingSimulations,
+                                               biasInitFilename,
+                                               thisRankWillDoIO),
+                                          pullCoordIndex);
 
         biasCoupledToSystem_.back().bias_.printInitializationToLog(fplog);
     }
@@ -285,7 +275,7 @@ bool Awh::isOutputStep(int64_t step) const
 }
 
 real Awh::applyBiasForcesAndUpdateBias(PbcType                pbcType,
-                                       const real*            masses,
+                                       ArrayRef<const real>   masses,
                                        ArrayRef<const double> neighborLambdaEnergies,
                                        ArrayRef<const double> neighborLambdaDhdl,
                                        const matrix           box,
@@ -300,7 +290,7 @@ real Awh::applyBiasForcesAndUpdateBias(PbcType                pbcType,
         GMX_ASSERT(forceWithVirial, "Need a valid ForceWithVirial object");
     }
 
-    wallcycle_start(wallcycle, ewcAWH);
+    wallcycle_start(wallcycle, WallCycleCounter::Awh);
 
     t_pbc pbc;
     set_pbc(&pbc, pbcType, box);
@@ -340,9 +330,18 @@ real Awh::applyBiasForcesAndUpdateBias(PbcType                pbcType,
         /* Note: In the near future this call will be split in calls
          *       to supports bias sharing within a single simulation.
          */
-        gmx::ArrayRef<const double> biasForce = biasCts.bias_.calcForceAndUpdateBias(
-                coordValue, neighborLambdaEnergies, neighborLambdaDhdl, &biasPotential,
-                &biasPotentialJump, commRecord_, multiSimRecord_, t, step, seed_, fplog);
+        gmx::ArrayRef<const double> biasForce =
+                biasCts.bias_.calcForceAndUpdateBias(coordValue,
+                                                     neighborLambdaEnergies,
+                                                     neighborLambdaDhdl,
+                                                     &biasPotential,
+                                                     &biasPotentialJump,
+                                                     commRecord_,
+                                                     multiSimRecord_,
+                                                     t,
+                                                     step,
+                                                     seed_,
+                                                     fplog);
 
         awhPotential += biasPotential;
 
@@ -358,8 +357,11 @@ real Awh::applyBiasForcesAndUpdateBias(PbcType                pbcType,
         {
             if (biasCts.bias_.dimParams()[d].isPullDimension())
             {
-                apply_external_pull_coord_force(pull_, biasCts.pullCoordIndex_[d - numLambdaDimsCounted],
-                                                biasForce[d], masses, forceWithVirial);
+                apply_external_pull_coord_force(pull_,
+                                                biasCts.pullCoordIndex_[d - numLambdaDimsCounted],
+                                                biasForce[d],
+                                                masses,
+                                                forceWithVirial);
             }
             else
             {
@@ -378,7 +380,7 @@ real Awh::applyBiasForcesAndUpdateBias(PbcType                pbcType,
         }
     }
 
-    wallcycle_stop(wallcycle, ewcAWH);
+    wallcycle_stop(wallcycle, WallCycleCounter::Awh);
 
     return MASTER(commRecord_) ? static_cast<real>(awhPotential) : 0;
 }
@@ -463,16 +465,14 @@ void Awh::registerAwhWithPull(const AwhParams& awhParams, pull_t* pull_work)
 {
     GMX_RELEASE_ASSERT(!anyDimUsesPull(awhParams) || pull_work, "Need a valid pull object");
 
-    for (int k = 0; k < awhParams.numBias; k++)
+    for (const auto& biasParam : awhParams.awhBiasParams())
     {
-        const AwhBiasParams& biasParams = awhParams.awhBiasParams[k];
-
-        for (int d = 0; d < biasParams.ndim; d++)
+        for (const auto& dimParam : biasParam.dimParams())
         {
-            if (biasParams.dimParams[d].eCoordProvider == eawhcoordproviderPULL)
+            if (dimParam.coordinateProvider() == AwhCoordinateProviderType::Pull)
             {
-                register_external_pull_potential(pull_work, biasParams.dimParams[d].coordIndex,
-                                                 Awh::externalPotentialString());
+                register_external_pull_potential(
+                        pull_work, dimParam.coordinateIndex(), Awh::externalPotentialString());
             }
         }
     }
@@ -492,7 +492,7 @@ void Awh::writeToEnergyFrame(int64_t step, t_enxframe* frame) const
 
     /* Get the total number of energy subblocks that AWH needs */
     int numSubblocks = 0;
-    for (auto& biasCoupledToSystem : biasCoupledToSystem_)
+    for (const auto& biasCoupledToSystem : biasCoupledToSystem_)
     {
         numSubblocks += biasCoupledToSystem.bias_.numEnergySubblocksToWrite();
     }
@@ -510,7 +510,7 @@ void Awh::writeToEnergyFrame(int64_t step, t_enxframe* frame) const
 
     /* Transfer AWH data blocks to energy sub blocks */
     int energySubblockCount = 0;
-    for (auto& biasCoupledToSystem : biasCoupledToSystem_)
+    for (const auto& biasCoupledToSystem : biasCoupledToSystem_)
     {
         energySubblockCount += biasCoupledToSystem.bias_.writeToEnergySubblocks(
                 &(awhEnergyBlock->sub[energySubblockCount]));
@@ -520,7 +520,8 @@ void Awh::writeToEnergyFrame(int64_t step, t_enxframe* frame) const
 bool Awh::hasFepLambdaDimension() const
 {
     return std::any_of(
-            std::begin(biasCoupledToSystem_), std::end(biasCoupledToSystem_),
+            std::begin(biasCoupledToSystem_),
+            std::end(biasCoupledToSystem_),
             [](const auto& coupledBias) { return coupledBias.bias_.hasFepLambdaDimension(); });
 }
 
@@ -539,14 +540,9 @@ bool Awh::needForeignEnergyDifferences(const int64_t step) const
     /* Check whether the bias(es) that has/have a FEP lambda dimension should sample coordinates
      * this step. Since the biases may have different sampleCoordStep it is necessary to check
      * this combination. */
-    for (const auto& biasCts : biasCoupledToSystem_)
-    {
-        if (biasCts.bias_.hasFepLambdaDimension() && biasCts.bias_.isSampleCoordStep(step))
-        {
-            return true;
-        }
-    }
-    return false;
+    return std::any_of(biasCoupledToSystem_.begin(), biasCoupledToSystem_.end(), [step](const auto& biasCts) {
+        return biasCts.bias_.hasFepLambdaDimension() && biasCts.bias_.isSampleCoordStep(step);
+    });
 }
 
 std::unique_ptr<Awh> prepareAwhModule(FILE*                 fplog,
@@ -568,9 +564,15 @@ std::unique_ptr<Awh> prepareAwhModule(FILE*                 fplog,
         GMX_THROW(InvalidInputError("AWH biasing does not support shell particles."));
     }
 
-    auto awh = std::make_unique<Awh>(
-            fplog, inputRecord, commRecord, multiSimRecord, *inputRecord.awhParams, biasInitFilename,
-            pull_work, inputRecord.fepvals->n_lambda, inputRecord.fepvals->init_fep_state);
+    auto awh = std::make_unique<Awh>(fplog,
+                                     inputRecord,
+                                     commRecord,
+                                     multiSimRecord,
+                                     *inputRecord.awhParams,
+                                     biasInitFilename,
+                                     pull_work,
+                                     inputRecord.fepvals->n_lambda,
+                                     inputRecord.fepvals->init_fep_state);
 
     if (startingFromCheckpoint)
     {
index 30b0a25b1a3506b9ecf778f7f6d603a8900df57e..d44f295eb2903fc381874b77b689cbcf63a5627d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ namespace gmx
 template<typename>
 class ArrayRef;
 struct AwhHistory;
-struct AwhParams;
+class AwhParams;
 class Bias;
 struct BiasCoupledToSystem;
 class ForceWithVirial;
@@ -186,7 +186,7 @@ public:
      * \returns the potential energy for the bias.
      */
     real applyBiasForcesAndUpdateBias(PbcType                pbcType,
-                                      const real*            masses,
+                                      ArrayRef<const real>   masses,
                                       ArrayRef<const double> neighborLambdaEnergies,
                                       ArrayRef<const double> neighborLambdaDhdl,
                                       const matrix           box,
@@ -275,7 +275,6 @@ private:
      */
     bool isOutputStep(int64_t step) const;
 
-private:
     std::vector<BiasCoupledToSystem> biasCoupledToSystem_; /**< AWH biases and definitions of their coupling to the system. */
     const int64_t    seed_;   /**< Random seed for MC jumping with umbrella type bias potential. */
     const int        nstout_; /**< Interval in steps for writing to energy file. */
index 7df5a236f9b3069968ca47b87458e2343b48a0d6..ea6d4a0795f1c783898c59be4ed181865cfe15f3 100644 (file)
@@ -144,8 +144,7 @@ gmx::ArrayRef<const double> Bias::calcForceAndUpdateBias(const awh_dvec
             state_.doSkippedUpdatesInNeighborhood(params_, grid_);
         }
         convolvedBias = state_.updateProbabilityWeightsAndConvolvedBias(
-                dimParams_, grid_, moveUmbrella ? neighborLambdaEnergies : ArrayRef<const double>{},
-                &probWeightNeighbor);
+                dimParams_, grid_, moveUmbrella ? neighborLambdaEnergies : ArrayRef<const double>{}, &probWeightNeighbor);
 
         if (isSampleCoordStep)
         {
@@ -165,9 +164,12 @@ gmx::ArrayRef<const double> Bias::calcForceAndUpdateBias(const awh_dvec
     double potential;
     if (params_.convolveForce)
     {
-        state_.calcConvolvedForce(dimParams_, grid_, probWeightNeighbor,
+        state_.calcConvolvedForce(dimParams_,
+                                  grid_,
+                                  probWeightNeighbor,
                                   moveUmbrella ? neighborLambdaDhdl : ArrayRef<const double>{},
-                                  tempForce_, biasForce_);
+                                  tempForce_,
+                                  biasForce_);
 
         potential = -convolvedBias * params_.invBeta;
     }
@@ -178,8 +180,11 @@ gmx::ArrayRef<const double> Bias::calcForceAndUpdateBias(const awh_dvec
                            "AWH bias grid point for the umbrella reference value is outside of the "
                            "target region.");
         potential = state_.calcUmbrellaForceAndPotential(
-                dimParams_, grid_, coordState.umbrellaGridpoint(),
-                moveUmbrella ? neighborLambdaDhdl : ArrayRef<const double>{}, biasForce_);
+                dimParams_,
+                grid_,
+                coordState.umbrellaGridpoint(),
+                moveUmbrella ? neighborLambdaDhdl : ArrayRef<const double>{},
+                biasForce_);
 
         /* Moving the umbrella results in a force correction and
          * a new potential. The umbrella center is sampled as often as
@@ -188,18 +193,25 @@ gmx::ArrayRef<const double> Bias::calcForceAndUpdateBias(const awh_dvec
          */
         if (moveUmbrella)
         {
-            double newPotential =
-                    state_.moveUmbrella(dimParams_, grid_, probWeightNeighbor, neighborLambdaDhdl,
-                                        biasForce_, step, seed, params_.biasIndex);
-            *potentialJump = newPotential - potential;
+            const bool onlySampleUmbrellaGridpoint = false;
+            double     newPotential                = state_.moveUmbrella(dimParams_,
+                                                      grid_,
+                                                      probWeightNeighbor,
+                                                      neighborLambdaDhdl,
+                                                      biasForce_,
+                                                      step,
+                                                      seed,
+                                                      params_.biasIndex,
+                                                      onlySampleUmbrellaGridpoint);
+            *potentialJump                         = newPotential - potential;
         }
     }
 
     /* Update the free energy estimates and bias and other history dependent method parameters */
     if (params_.isUpdateFreeEnergyStep(step))
     {
-        state_.updateFreeEnergyAndAddSamplesToHistogram(dimParams_, grid_, params_, commRecord, ms,
-                                                        t, step, fplog, &updateList_);
+        state_.updateFreeEnergyAndAddSamplesToHistogram(
+                dimParams_, grid_, params_, commRecord, ms, t, step, fplog, &updateList_);
 
         if (params_.convolveForce)
         {
@@ -208,6 +220,21 @@ gmx::ArrayRef<const double> Bias::calcForceAndUpdateBias(const awh_dvec
             *potentialJump      = newPotential - potential;
         }
     }
+    /* If there is a lambda axis it is still controlled using an umbrella even if the force
+     * is convolved in the other dimensions. */
+    if (moveUmbrella && params_.convolveForce && grid_.hasLambdaAxis())
+    {
+        const bool onlySampleUmbrellaGridpoint = true;
+        state_.moveUmbrella(dimParams_,
+                            grid_,
+                            probWeightNeighbor,
+                            neighborLambdaDhdl,
+                            biasForce_,
+                            step,
+                            seed,
+                            params_.biasIndex,
+                            onlySampleUmbrellaGridpoint);
+    }
 
     /* Return the potential. */
     *awhPotential = potential;
@@ -224,7 +251,7 @@ gmx::ArrayRef<const double> Bias::calcForceAndUpdateBias(const awh_dvec
  * \param[in] pointState  The state of the points in a bias.
  * \returns the total sample count.
  */
-static int64_t countSamples(const std::vector<PointState>& pointState)
+static int64_t countSamples(ArrayRef<const PointState> pointState)
 {
     double numSamples = 0;
     for (const PointState& point : pointState)
@@ -255,8 +282,11 @@ static void ensureStateAndRunConsistency(const BiasParams& params, const BiasSta
                 "The number of AWH updates in the checkpoint file (%" PRId64
                 ") does not match the total number of AWH samples divided by the number of samples "
                 "per update for %d sharing AWH bias(es) (%" PRId64 "/%d=%" PRId64 ")",
-                numUpdatesExpected, params.numSharedUpdate, numSamples,
-                params.numSamplesUpdateFreeEnergy_ * params.numSharedUpdate, numUpdatesFromSamples);
+                numUpdatesExpected,
+                params.numSharedUpdate,
+                numSamples,
+                params.numSamplesUpdateFreeEnergy_ * params.numSharedUpdate,
+                numUpdatesFromSamples);
         mesg += " Maybe you changed AWH parameters.";
         /* Unfortunately we currently do not store the number of simulations
          * sharing the bias or the state to checkpoint. But we can hint at
@@ -267,7 +297,8 @@ static void ensureStateAndRunConsistency(const BiasParams& params, const BiasSta
             mesg += gmx::formatString(
                     " Or the run you continued from used %" PRId64
                     " sharing simulations, whereas you now specified %d sharing simulations.",
-                    numUpdatesFromSamples / state.histogramSize().numUpdates(), params.numSharedUpdate);
+                    numUpdatesFromSamples / state.histogramSize().numUpdates(),
+                    params.numSharedUpdate);
         }
         GMX_THROW(InvalidInputError(mesg));
     }
@@ -329,15 +360,15 @@ void Bias::updateHistory(AwhBiasHistory* biasHistory) const
 Bias::Bias(int                            biasIndexInCollection,
            const AwhParams&               awhParams,
            const AwhBiasParams&           awhBiasParams,
-           const std::vector<DimParams>&  dimParamsInit,
+           ArrayRef<const DimParams>      dimParamsInit,
            double                         beta,
            double                         mdTimeStep,
            int                            numSharingSimulations,
            const std::string&             biasInitFilename,
            ThisRankWillDoIO               thisRankWillDoIO,
            BiasParams::DisableUpdateSkips disableUpdateSkips) :
-    dimParams_(dimParamsInit),
-    grid_(dimParamsInit, awhBiasParams.dimParams),
+    dimParams_(dimParamsInit.begin(), dimParamsInit.end()),
+    grid_(dimParamsInit, awhBiasParams.dimParams()),
     params_(awhParams,
             awhBiasParams,
             dimParams_,
@@ -357,7 +388,8 @@ Bias::Bias(int                            biasIndexInCollection,
     /* For a global update updateList covers all points, so reserve that */
     updateList_.reserve(grid_.numPoints());
 
-    state_.initGridPointState(awhBiasParams, dimParams_, grid_, params_, biasInitFilename, awhParams.numBias);
+    state_.initGridPointState(
+            awhBiasParams, dimParams_, grid_, params_, biasInitFilename, awhParams.numBias());
 
     if (thisRankDoesIO_)
     {
@@ -368,9 +400,12 @@ Bias::Bias(int                            biasIndexInCollection,
          */
         double blockLength = 0;
         /* Construct the force correlation object. */
-        forceCorrelationGrid_ = std::make_unique<CorrelationGrid>(
-                state_.points().size(), ndim(), blockLength,
-                CorrelationGrid::BlockLengthMeasure::Time, awhParams.nstSampleCoord * mdTimeStep);
+        forceCorrelationGrid_ =
+                std::make_unique<CorrelationGrid>(state_.points().size(),
+                                                  ndim(),
+                                                  blockLength,
+                                                  CorrelationGrid::BlockLengthMeasure::Time,
+                                                  awhParams.nstSampleCoord() * mdTimeStep);
 
         writer_ = std::make_unique<BiasWriter>(*this);
     }
@@ -385,11 +420,13 @@ void Bias::printInitializationToLog(FILE* fplog) const
         fprintf(fplog,
                 "%s initial force correlation block length = %g %s"
                 "%s force correlation number of blocks = %d",
-                prefix.c_str(), forceCorrelationGrid().getBlockLength(),
+                prefix.c_str(),
+                forceCorrelationGrid().getBlockLength(),
                 forceCorrelationGrid().blockLengthMeasure == CorrelationGrid::BlockLengthMeasure::Weight
                         ? ""
                         : "ps",
-                prefix.c_str(), forceCorrelationGrid().getNumBlocks());
+                prefix.c_str(),
+                forceCorrelationGrid().getNumBlocks());
     }
 }
 
@@ -415,8 +452,8 @@ void Bias::updateForceCorrelationGrid(gmx::ArrayRef<const double> probWeightNeig
            We actually add the force normalized by beta which has the units of 1/length. This means that the
            resulting correlation time integral is directly in units of friction time/length^2 which is really what
            we're interested in. */
-        state_.calcUmbrellaForceAndPotential(dimParams_, grid_, indexNeighbor, neighborLambdaDhdl,
-                                             forceFromNeighbor);
+        state_.calcUmbrellaForceAndPotential(
+                dimParams_, grid_, indexNeighbor, neighborLambdaDhdl, forceFromNeighbor);
 
         /* Note: we might want to give a whole list of data to add instead and have this loop in the data adding function */
         forceCorrelationGrid_->addData(indexNeighbor, weightNeighbor, forceFromNeighbor, t);
index 895bfe456aef5d1950291e564b5b1e15024c38ce..39eeb991b46966899116ec08c881417e5f57b596 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -73,9 +73,9 @@ namespace gmx
 {
 
 struct AwhBiasHistory;
-struct AwhBiasParams;
+class AwhBiasParams;
 struct AwhHistory;
-struct AwhParams;
+class AwhParams;
 struct AwhPointStateHistory;
 class CorrelationGrid;
 class BiasGrid;
@@ -166,7 +166,7 @@ public:
     Bias(int                            biasIndexInCollection,
          const AwhParams&               awhParams,
          const AwhBiasParams&           awhBiasParams,
-         const std::vector<DimParams>&  dimParams,
+         ArrayRef<const DimParams>      dimParams,
          double                         beta,
          double                         mdTimeStep,
          int                            numSharingSimulations,
@@ -279,7 +279,7 @@ public:
 
     /*! \brief Returns the dimension parameters.
      */
-    inline const std::vector<DimParams>& dimParams() const { return dimParams_; }
+    inline ArrayRef<const DimParams> dimParams() const { return dimParams_; }
 
     //! Returns the bias parameters
     inline const BiasParams& params() const { return params_; }
@@ -355,8 +355,9 @@ public:
      */
     bool hasFepLambdaDimension() const
     {
-        return std::any_of(std::begin(dimParams_), std::end(dimParams_),
-                           [](const auto& dimParam) { return dimParam.isFepLambdaDimension(); });
+        return std::any_of(std::begin(dimParams_), std::end(dimParams_), [](const auto& dimParam) {
+            return dimParam.isFepLambdaDimension();
+        });
     }
 
     /*! \brief
index 0db229cd865976a08fee9c177a3b168c057f7053..bd3fe10c58f4084e70f32ba3b0d2bcd24e5a71cd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -69,29 +69,33 @@ namespace
 {
 
 /*! \brief
- * Modify x so that it is periodic in [-period/2, +period/2).
+ * Return x so that it is periodic in [-period/2, +period/2).
  *
  * x is modified by shifting its value by a +/- a period if
  * needed. Thus, it is assumed that x is at most one period
  * away from this interval. For period = 0, x is not modified.
  *
- * \param[in,out] x       Pointer to the value to modify.
- * \param[in]     period  The period, or 0 if not periodic.
+ * \param[in] x       Pointer to the value to modify.
+ * \param[in] period  The period, or 0 if not periodic.
+ * \returns   Value that is within the period.
  */
-void centerPeriodicValueAroundZero(double* x, double period)
+double centerPeriodicValueAroundZero(const double x, double period)
 {
     GMX_ASSERT(period >= 0, "Periodic should not be negative");
 
     const double halfPeriod = period * 0.5;
 
-    if (*x >= halfPeriod)
+    double valueInPeriod = x;
+
+    if (valueInPeriod >= halfPeriod)
     {
-        *x -= period;
+        valueInPeriod -= period;
     }
-    else if (*x < -halfPeriod)
+    else if (valueInPeriod < -halfPeriod)
     {
-        *x += period;
+        valueInPeriod += period;
     }
+    return valueInPeriod;
 }
 
 /*! \brief
@@ -180,7 +184,7 @@ double getDeviationPeriodic(double x, double x0, double period)
 
     if (period > 0)
     {
-        centerPeriodicValueAroundZero(&dev, period);
+        dev = centerPeriodicValueAroundZero(dev, period);
     }
 
     return dev;
@@ -309,7 +313,7 @@ namespace
  * \param[in] indexMulti Multidimensional grid point index to convert to a linear one.
  * \returns the linear index.
  */
-int multiDimGridIndexToLinear(const std::vector<GridAxis>& axis, const awh_ivec indexMulti)
+int multiDimGridIndexToLinear(ArrayRef<const GridAxis> axis, const awh_ivec indexMulti)
 {
     awh_ivec numPointsDim = { 0 };
 
@@ -557,7 +561,7 @@ static int pointDistanceAlongAxis(const GridAxis& axis, double x, double x0)
  * \param[in] axis    The grid axes.
  * \returns true if the value is in the grid.
  */
-static bool valueIsInGrid(const awh_dvec value, const std::vector<GridAxis>& axis)
+static bool valueIsInGrid(const awh_dvec value, ArrayRef<const GridAxis> axis)
 {
     /* For each dimension get the one-dimensional index and check if it is in range. */
     for (size_t d = 0; d < axis.size(); d++)
@@ -634,7 +638,7 @@ int GridAxis::nearestIndex(double value) const
  * \param[in] axis   The grid axes.
  * \returns the point index nearest to the value.
  */
-static int getNearestIndexInGrid(const awh_dvec value, const std::vector<GridAxis>& axis)
+static int getNearestIndexInGrid(const awh_dvec value, ArrayRef<const GridAxis> axis)
 {
     awh_ivec indexMulti;
 
@@ -737,7 +741,8 @@ void BiasGrid::initPoints()
             if (axis_[d].period() > 0)
             {
                 /* Do we always want the values to be centered around 0 ? */
-                centerPeriodicValueAroundZero(&point.coordValue[d], axis_[d].period());
+                point.coordValue[d] =
+                        centerPeriodicValueAroundZero(point.coordValue[d], axis_[d].period());
             }
 
             point.index[d] = indexWork[d];
@@ -811,18 +816,19 @@ GridAxis::GridAxis(double origin, double end, double period, int numPoints, bool
     }
 }
 
-BiasGrid::BiasGrid(const std::vector<DimParams>& dimParams, const AwhDimParams* awhDimParams)
+BiasGrid::BiasGrid(ArrayRef<const DimParams> dimParams, ArrayRef<const AwhDimParams> awhDimParams)
 {
+    GMX_RELEASE_ASSERT(dimParams.size() == awhDimParams.size(), "Dimensions needs to be equal");
     /* Define the discretization along each dimension */
     awh_dvec period;
     int      numPoints = 1;
-    for (size_t d = 0; d < dimParams.size(); d++)
+    for (int d = 0; d < gmx::ssize(awhDimParams); d++)
     {
-        double origin = dimParams[d].scaleUserInputToInternal(awhDimParams[d].origin);
-        double end    = dimParams[d].scaleUserInputToInternal(awhDimParams[d].end);
-        if (awhDimParams[d].eCoordProvider == eawhcoordproviderPULL)
+        double origin = dimParams[d].scaleUserInputToInternal(awhDimParams[d].origin());
+        double end    = dimParams[d].scaleUserInputToInternal(awhDimParams[d].end());
+        if (awhDimParams[d].coordinateProvider() == AwhCoordinateProviderType::Pull)
         {
-            period[d] = dimParams[d].scaleUserInputToInternal(awhDimParams[d].period);
+            period[d] = dimParams[d].scaleUserInputToInternal(awhDimParams[d].period());
             static_assert(
                     c_numPointsPerSigma >= 1.0,
                     "The number of points per sigma should be at least 1.0 to get a uniformly "
@@ -897,7 +903,8 @@ void mapGridToDataGrid(std::vector<int>*    gridpointToDatapoint,
         std::string mesg = gmx::formatString(
                 "Could not extract data properly from %s. Wrong data format?"
                 "\n\n%s",
-                dataFilename.c_str(), correctFormatMessage.c_str());
+                dataFilename.c_str(),
+                correctFormatMessage.c_str());
         GMX_THROW(InvalidInputError(mesg));
     }
 
@@ -912,8 +919,8 @@ void mapGridToDataGrid(std::vector<int>*    gridpointToDatapoint,
         }
         else
         {
-            axis_.emplace_back(data[d][0], data[d][numDataPoints - 1], grid.axis(d).period(),
-                               numPoints[d], false);
+            axis_.emplace_back(
+                    data[d][0], data[d][numDataPoints - 1], grid.axis(d).period(), numPoints[d], false);
         }
     }
 
@@ -930,7 +937,8 @@ void mapGridToDataGrid(std::vector<int>*    gridpointToDatapoint,
                     "%s does not contain data for all coordinate values. "
                     "Make sure your input data covers the whole sampling domain "
                     "and is correctly formatted. \n\n%s",
-                    dataFilename.c_str(), correctFormatMessage.c_str());
+                    dataFilename.c_str(),
+                    correctFormatMessage.c_str());
             GMX_THROW(InvalidInputError(mesg));
         }
         (*gridpointToDatapoint)[m] = getNearestIndexInGrid(grid.point(m).coordValue, axis_);
index 9fd994daa7d23c5d1416ffa9663a4378ffbc161f..2c6777dcb2b488bd4dc3fe23eaf0cd00f6c5530a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <optional>
 #include <string>
 
+#include "gromacs/utility/arrayref.h"
+
 #include "dimparams.h" /* This is needed for awh_dvec */
 
 namespace gmx
 {
 
-struct AwhDimParams;
+class AwhDimParams;
 
 /*! \internal
  * \brief An axis, i.e. dimension, of the grid.
@@ -197,7 +199,7 @@ public:
      * coordinate living on the grid (determines the grid spacing).
      * \param[in] awhDimParams  Dimension params from inputrec.
      */
-    BiasGrid(const std::vector<DimParams>& dimParams, const AwhDimParams* awhDimParams);
+    BiasGrid(ArrayRef<const DimParams> dimParams, ArrayRef<const AwhDimParams> awhDimParams);
 
     /*! \brief Returns the number of points in the grid.
      *
@@ -221,7 +223,7 @@ public:
      *
      * \returns a constant reference to the grid axes.
      */
-    const std::vector<GridAxis>& axis() const { return axis_; }
+    ArrayRef<const GridAxis> axis() const { return axis_; }
 
     /*! \brief Returns a grid axis.
      *
@@ -249,8 +251,9 @@ public:
      */
     bool hasLambdaAxis() const
     {
-        return std::any_of(std::begin(axis_), std::end(axis_),
-                           [](const auto& axis) { return axis.isFepLambdaAxis(); });
+        return std::any_of(std::begin(axis_), std::end(axis_), [](const auto& axis) {
+            return axis.isFepLambdaAxis();
+        });
     }
 
     /*! \brief
index 8351520a12082e28e49ea9ab2619b2945f3bea73..f430226aa1fb678374a079e3a124252104ccb9a6 100644 (file)
@@ -82,26 +82,26 @@ int64_t calcTargetUpdateInterval(const AwhParams& awhParams, const AwhBiasParams
      * (this could be made a user-option but there is most likely no big need
      * for tweaking this for most users).
      */
-    switch (awhBiasParams.eTarget)
+    switch (awhBiasParams.targetDistribution())
     {
-        case eawhtargetCONSTANT: numStepsUpdateTarget = 0; break;
-        case eawhtargetCUTOFF:
-        case eawhtargetBOLTZMANN:
+        case AwhTargetType::Constant: numStepsUpdateTarget = 0; break;
+        case AwhTargetType::Cutoff:
+        case AwhTargetType::Boltzmann:
             /* Updating the target generally requires updating the whole grid so to keep the cost
                down we generally update the target less often than the free energy (unless the free
                energy update step is set to > 100 samples). */
-            numStepsUpdateTarget = std::max(100 % awhParams.numSamplesUpdateFreeEnergy,
-                                            awhParams.numSamplesUpdateFreeEnergy)
-                                   * awhParams.nstSampleCoord;
+            numStepsUpdateTarget = std::max(100 % awhParams.numSamplesUpdateFreeEnergy(),
+                                            awhParams.numSamplesUpdateFreeEnergy())
+                                   * awhParams.nstSampleCoord();
             break;
-        case eawhtargetLOCALBOLTZMANN:
+        case AwhTargetType::LocalBoltzmann:
             /* The target distribution is set equal to the reference histogram which is updated every free energy update.
                So the target has to be updated at the same time. This leads to a global update each time because it is
                assumed that a target distribution update can take any form. This is a bit unfortunate for a "local"
                target distribution. One could avoid the global update by making a local target update function (and
                postponing target updates for non-local points as for the free energy update). We avoid such additions
                for now and accept that this target type always does global updates. */
-            numStepsUpdateTarget = awhParams.numSamplesUpdateFreeEnergy * awhParams.nstSampleCoord;
+            numStepsUpdateTarget = awhParams.numSamplesUpdateFreeEnergy() * awhParams.nstSampleCoord();
             break;
         default: GMX_RELEASE_ASSERT(false, "Unknown AWH target type"); break;
     }
@@ -116,9 +116,9 @@ int64_t calcTargetUpdateInterval(const AwhParams& awhParams, const AwhBiasParams
  * \param[in] gridAxis          The BiasGrid axes.
  * \returns the check interval in steps.
  */
-int64_t calcCheckCoveringInterval(const AwhParams&              awhParams,
-                                  const std::vector<DimParams>& dimParams,
-                                  const std::vector<GridAxis>&  gridAxis)
+int64_t calcCheckCoveringInterval(const AwhParams&          awhParams,
+                                  ArrayRef<const DimParams> dimParams,
+                                  ArrayRef<const GridAxis>  gridAxis)
 {
     /* Each sample will have a width of sigma. To cover the axis a
        minimum number of samples of width sigma is required. */
@@ -153,11 +153,11 @@ int64_t calcCheckCoveringInterval(const AwhParams&              awhParams,
     /* Convert to number of steps using the sampling frequency. The
        check interval should be a multiple of the update step
        interval. */
-    int numStepsUpdate = awhParams.numSamplesUpdateFreeEnergy * awhParams.nstSampleCoord;
-    GMX_RELEASE_ASSERT(awhParams.numSamplesUpdateFreeEnergy > 0,
+    int numStepsUpdate = awhParams.numSamplesUpdateFreeEnergy() * awhParams.nstSampleCoord();
+    GMX_RELEASE_ASSERT(awhParams.numSamplesUpdateFreeEnergy() > 0,
                        "When checking for AWH coverings, the number of samples per AWH update need "
                        "to be > 0.");
-    int numUpdatesCheck = std::max(1, minNumSamplesCover / awhParams.numSamplesUpdateFreeEnergy);
+    int numUpdatesCheck = std::max(1, minNumSamplesCover / awhParams.numSamplesUpdateFreeEnergy());
     int numStepsCheck   = numUpdatesCheck * numStepsUpdate;
 
     GMX_RELEASE_ASSERT(numStepsCheck % numStepsUpdate == 0,
@@ -175,24 +175,25 @@ int64_t calcCheckCoveringInterval(const AwhParams&              awhParams,
  * \param[in] samplingTimestep  Sampling frequency of probability weights.
  * \returns estimate of initial histogram size.
  */
-double getInitialHistogramSizeEstimate(const AwhBiasParams&         awhBiasParams,
-                                       const std::vector<GridAxis>& gridAxis,
-                                       double                       beta,
-                                       double                       samplingTimestep)
+double getInitialHistogramSizeEstimate(const AwhBiasParams&     awhBiasParams,
+                                       ArrayRef<const GridAxis> gridAxis,
+                                       double                   beta,
+                                       double                   samplingTimestep)
 {
     /* Get diffusion factor */
     double              maxCrossingTime = 0.;
     std::vector<double> x;
+    const auto          awhDimParams = awhBiasParams.dimParams();
     for (size_t d = 0; d < gridAxis.size(); d++)
     {
-        GMX_RELEASE_ASSERT(awhBiasParams.dimParams[d].diffusion > 0, "We need positive diffusion");
+        GMX_RELEASE_ASSERT(awhDimParams[d].diffusion() > 0, "We need positive diffusion");
         // With diffusion it takes on average T = L^2/2D time to cross length L
         double axisLength   = gridAxis[d].isFepLambdaAxis() ? 1.0 : gridAxis[d].length();
-        double crossingTime = (axisLength * axisLength) / (2 * awhBiasParams.dimParams[d].diffusion);
+        double crossingTime = (axisLength * axisLength) / (2 * awhDimParams[d].diffusion());
         maxCrossingTime     = std::max(maxCrossingTime, crossingTime);
     }
     GMX_RELEASE_ASSERT(maxCrossingTime > 0, "We need at least one dimension with non-zero length");
-    double errorInitialInKT = beta * awhBiasParams.errorInitial;
+    double errorInitialInKT = beta * awhBiasParams.initialErrorEstimate();
     double histogramSize    = maxCrossingTime / (gmx::square(errorInitialInKT) * samplingTimestep);
 
     return histogramSize;
@@ -210,7 +211,7 @@ int getNumSharedUpdate(const AwhBiasParams& awhBiasParams, int numSharingSimulat
 
     int numShared = 1;
 
-    if (awhBiasParams.shareGroup > 0)
+    if (awhBiasParams.shareGroup() > 0)
     {
         /* We do not yet support sharing within a simulation */
         int numSharedWithinThisSimulation = 1;
@@ -222,31 +223,31 @@ int getNumSharedUpdate(const AwhBiasParams& awhBiasParams, int numSharingSimulat
 
 } // namespace
 
-BiasParams::BiasParams(const AwhParams&              awhParams,
-                       const AwhBiasParams&          awhBiasParams,
-                       const std::vector<DimParams>& dimParams,
-                       double                        beta,
-                       double                        mdTimeStep,
-                       DisableUpdateSkips            disableUpdateSkips,
-                       int                           numSharingSimulations,
-                       const std::vector<GridAxis>&  gridAxis,
-                       int                           biasIndex) :
+BiasParams::BiasParams(const AwhParams&          awhParams,
+                       const AwhBiasParams&      awhBiasParams,
+                       ArrayRef<const DimParams> dimParams,
+                       double                    beta,
+                       double                    mdTimeStep,
+                       DisableUpdateSkips        disableUpdateSkips,
+                       int                       numSharingSimulations,
+                       ArrayRef<const GridAxis>  gridAxis,
+                       int                       biasIndex) :
     invBeta(beta > 0 ? 1 / beta : 0),
-    numStepsSampleCoord_(awhParams.nstSampleCoord),
-    numSamplesUpdateFreeEnergy_(awhParams.numSamplesUpdateFreeEnergy),
+    numStepsSampleCoord_(awhParams.nstSampleCoord()),
+    numSamplesUpdateFreeEnergy_(awhParams.numSamplesUpdateFreeEnergy()),
     numStepsUpdateTarget_(calcTargetUpdateInterval(awhParams, awhBiasParams)),
     numStepsCheckCovering_(calcCheckCoveringInterval(awhParams, dimParams, gridAxis)),
-    eTarget(awhBiasParams.eTarget),
-    freeEnergyCutoffInKT(beta * awhBiasParams.targetCutoff),
-    temperatureScaleFactor(awhBiasParams.targetBetaScaling),
-    idealWeighthistUpdate(eTarget != eawhtargetLOCALBOLTZMANN),
+    eTarget(awhBiasParams.targetDistribution()),
+    freeEnergyCutoffInKT(beta * awhBiasParams.targetCutoff()),
+    temperatureScaleFactor(awhBiasParams.targetBetaScaling()),
+    idealWeighthistUpdate(eTarget != AwhTargetType::LocalBoltzmann),
     numSharedUpdate(getNumSharedUpdate(awhBiasParams, numSharingSimulations)),
     updateWeight(numSamplesUpdateFreeEnergy_ * numSharedUpdate),
-    localWeightScaling(eTarget == eawhtargetLOCALBOLTZMANN ? temperatureScaleFactor : 1),
-    initialErrorInKT(beta * awhBiasParams.errorInitial),
+    localWeightScaling(eTarget == AwhTargetType::LocalBoltzmann ? temperatureScaleFactor : 1),
+    initialErrorInKT(beta * awhBiasParams.initialErrorEstimate()),
     initialHistogramSize(
             getInitialHistogramSizeEstimate(awhBiasParams, gridAxis, beta, numStepsSampleCoord_ * mdTimeStep)),
-    convolveForce(awhParams.ePotential == eawhpotentialCONVOLVED),
+    convolveForce(awhParams.potential() == AwhPotentialType::Convolved),
     biasIndex(biasIndex),
     disableUpdateSkips_(disableUpdateSkips == DisableUpdateSkips::yes)
 {
@@ -255,11 +256,12 @@ BiasParams::BiasParams(const AwhParams&              awhParams,
         GMX_THROW(InvalidInputError("To use AWH, the beta=1/(k_B T) should be > 0"));
     }
 
-    for (int d = 0; d < awhBiasParams.ndim; d++)
+    const auto& awhDimParams = awhBiasParams.dimParams();
+    for (int d = 0; d < gmx::ssize(awhDimParams); d++)
     {
         /* The spacing in FEP dimensions is 1. The calculated coverRadius will be in lambda states
          * (cf points in other dimensions). */
-        double coverRadiusInNm = 0.5 * awhBiasParams.dimParams[d].coverDiameter;
+        double coverRadiusInNm = 0.5 * awhDimParams[d].coverDiameter();
         double spacing         = gridAxis[d].spacing();
         coverRadius_[d] = spacing > 0 ? static_cast<int>(std::round(coverRadiusInNm / spacing)) : 0;
     }
index 6b24e2bd094444fcab17b68bb444b8ac262f88a7..ec72ace256cb3a836c84c8cd794649e83855a5a5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 namespace gmx
 {
 
-struct AwhBiasParams;
-struct AwhParams;
+template<typename>
+class ArrayRef;
+class AwhBiasParams;
+class AwhParams;
 struct DimParams;
 class GridAxis;
+enum class AwhTargetType : int;
 
 /*! \internal \brief Constant parameters for the bias.
  */
@@ -188,15 +191,15 @@ public:
      * \param[in] disableUpdateSkips     If to disable update skips, useful for testing.
      * \param[in] biasIndex              Index of the bias.
      */
-    BiasParams(const AwhParams&              awhParams,
-               const AwhBiasParams&          awhBiasParams,
-               const std::vector<DimParams>& dimParams,
-               double                        beta,
-               double                        mdTimeStep,
-               DisableUpdateSkips            disableUpdateSkips,
-               int                           numSharingSimulations,
-               const std::vector<GridAxis>&  gridAxis,
-               int                           biasIndex);
+    BiasParams(const AwhParams&          awhParams,
+               const AwhBiasParams&      awhBiasParams,
+               ArrayRef<const DimParams> dimParams,
+               double                    beta,
+               double                    mdTimeStep,
+               DisableUpdateSkips        disableUpdateSkips,
+               int                       numSharingSimulations,
+               ArrayRef<const GridAxis>  gridAxis,
+               int                       biasIndex);
 
     /* Data members */
     const double invBeta; /**< 1/beta = kT in kJ/mol */
@@ -208,10 +211,10 @@ private:
     const int64_t numStepsUpdateTarget_; /**< Number of steps per updating the target distribution. */
     const int64_t numStepsCheckCovering_; /**< Number of steps per checking for covering. */
 public:
-    const int    eTarget;              /**< Type of target distribution. */
-    const double freeEnergyCutoffInKT; /**< Free energy cut-off in kT for cut-off target distribution. */
-    const double temperatureScaleFactor; /**< Temperature scaling factor for temperature scaled targed distributions. */
-    const bool   idealWeighthistUpdate; /**< Update reference weighthistogram using the target distribution? Otherwise use the realized distribution. */
+    const AwhTargetType eTarget;              /**< Type of target distribution. */
+    const double        freeEnergyCutoffInKT; /**< Free energy cut-off in kT for cut-off target distribution. */
+    const double        temperatureScaleFactor; /**< Temperature scaling factor for temperature scaled targed distributions. */
+    const bool          idealWeighthistUpdate; /**< Update reference weighthistogram using the target distribution? Otherwise use the realized distribution. */
     const int    numSharedUpdate; /**< The number of (multi-)simulations sharing the bias update */
     const double updateWeight;    /**< The probability weight accumulated for each update. */
     const double localWeightScaling; /**< Scaling factor applied to a sample before adding it to the reference weight histogram (= 1, usually). */
index b377931fa04bf2c538f774a93ae990abddf43ee0..50d2603778fe3f21325d0d4869202d9023abd9da 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,7 @@
 #include "gromacs/mdrunutility/multisim.h"
 #include "gromacs/mdtypes/awh_params.h"
 #include "gromacs/mdtypes/commrec.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/stringutil.h"
 
@@ -61,14 +62,16 @@ bool haveBiasSharingWithinSimulation(const AwhParams& awhParams)
 {
     bool haveSharing = false;
 
-    for (int k = 0; k < awhParams.numBias; k++)
+    const auto awhBiasParams = awhParams.awhBiasParams();
+    for (auto awhBiasParamIt = awhBiasParams.begin(); awhBiasParamIt != awhBiasParams.end(); ++awhBiasParamIt)
     {
-        int shareGroup = awhParams.awhBiasParams[k].shareGroup;
+        int shareGroup = awhBiasParamIt->shareGroup();
         if (shareGroup > 0)
         {
-            for (int i = k + 1; i < awhParams.numBias; i++)
+            for (auto awhBiasParamIt2 = awhBiasParamIt + 1; awhBiasParamIt2 != awhBiasParams.end();
+                 ++awhBiasParamIt2)
             {
-                if (awhParams.awhBiasParams[i].shareGroup == shareGroup)
+                if (awhBiasParamIt2->shareGroup() == shareGroup)
                 {
                     haveSharing = true;
                 }
@@ -79,9 +82,9 @@ bool haveBiasSharingWithinSimulation(const AwhParams& awhParams)
     return haveSharing;
 }
 
-void biasesAreCompatibleForSharingBetweenSimulations(const AwhParams&           awhParams,
-                                                     const std::vector<size_t>& pointSize,
-                                                     const gmx_multisim_t*      multiSimComm)
+void biasesAreCompatibleForSharingBetweenSimulations(const AwhParams&       awhParams,
+                                                     ArrayRef<const size_t> pointSize,
+                                                     const gmx_multisim_t*  multiSimComm)
 {
     const int numSim = multiSimComm->numSimulations_;
 
@@ -90,9 +93,9 @@ void biasesAreCompatibleForSharingBetweenSimulations(const AwhParams&
      * biases in order over the ranks and it does not restrict possibilities.
      */
     int numShare = 0;
-    for (int b = 0; b < awhParams.numBias; b++)
+    for (const auto& awhBiasParam : awhParams.awhBiasParams())
     {
-        int group = awhParams.awhBiasParams[b].shareGroup;
+        int group = awhBiasParam.shareGroup();
         if (group > 0)
         {
             numShare++;
@@ -117,8 +120,8 @@ void biasesAreCompatibleForSharingBetweenSimulations(const AwhParams&
     }
 
     std::vector<int> intervals(numSim * 2);
-    intervals[numSim * 0 + multiSimComm->simulationIndex_] = awhParams.nstSampleCoord;
-    intervals[numSim * 1 + multiSimComm->simulationIndex_] = awhParams.numSamplesUpdateFreeEnergy;
+    intervals[numSim * 0 + multiSimComm->simulationIndex_] = awhParams.nstSampleCoord();
+    intervals[numSim * 1 + multiSimComm->simulationIndex_] = awhParams.numSamplesUpdateFreeEnergy();
     gmx_sumi_sim(intervals.size(), intervals.data(), multiSimComm);
     for (int sim = 1; sim < numSim; sim++)
     {
@@ -137,9 +140,10 @@ void biasesAreCompatibleForSharingBetweenSimulations(const AwhParams&
     /* Check the point sizes. This is a sufficient condition for running
      * as shared multi-sim run. No physics checks are performed here.
      */
-    for (int b = 0; b < awhParams.numBias; b++)
+    const auto& awhBiasParams = awhParams.awhBiasParams();
+    for (int b = 0; b < gmx::ssize(awhBiasParams); b++)
     {
-        if (awhParams.awhBiasParams[b].shareGroup > 0)
+        if (awhBiasParams[b].shareGroup() > 0)
         {
             std::vector<int64_t> pointSizes(numSim);
             pointSizes[multiSimComm->simulationIndex_] = pointSize[b];
index 751fe2f9a5f9b7c8bbce89d6684013023dcdc437..1d06d0ec69791ff9a39a8f3317a30cff020759cf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +56,9 @@ struct gmx_multisim_t;
 namespace gmx
 {
 
-struct AwhParams;
+template<typename>
+class ArrayRef;
+class AwhParams;
 
 /*! \brief Returns if any bias is sharing within a simulation.
  *
@@ -75,9 +77,9 @@ bool haveBiasSharingWithinSimulation(const AwhParams& awhParams);
  * \param[in] pointSize     Vector of grid-point sizes for each bias.
  * \param[in] multiSimComm  Struct for multi-simulation communication.
  */
-void biasesAreCompatibleForSharingBetweenSimulations(const AwhParams&           awhParams,
-                                                     const std::vector<size_t>& pointSize,
-                                                     const gmx_multisim_t*      multiSimComm);
+void biasesAreCompatibleForSharingBetweenSimulations(const AwhParams&       awhParams,
+                                                     ArrayRef<const size_t> pointSize,
+                                                     const gmx_multisim_t*  multiSimComm);
 
 } // namespace gmx
 
index 50c646f023d9fb0144d216bc6e96e0260d129f61..55442b10fdc0578f712b40a4524ba8b219803cec 100644 (file)
@@ -59,6 +59,7 @@
 #include "gromacs/fileio/gmxfio.h"
 #include "gromacs/fileio/xvgr.h"
 #include "gromacs/gmxlib/network.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/mdrunutility/multisim.h"
 #include "gromacs/mdtypes/awh_history.h"
@@ -220,14 +221,14 @@ double freeEnergyMinimumValue(gmx::ArrayRef<const PointState> pointState)
  * \param[in] gridpointIndex         The index of the current grid point.
  * \returns the log of the biased probability weight.
  */
-double biasedLogWeightFromPoint(const std::vector<DimParams>&  dimParams,
-                                const std::vector<PointState>& points,
-                                const BiasGrid&                grid,
-                                int                            pointIndex,
-                                double                         pointBias,
-                                const awh_dvec                 value,
-                                gmx::ArrayRef<const double>    neighborLambdaEnergies,
-                                int                            gridpointIndex)
+double biasedLogWeightFromPoint(ArrayRef<const DimParams>  dimParams,
+                                ArrayRef<const PointState> points,
+                                const BiasGrid&            grid,
+                                int                        pointIndex,
+                                double                     pointBias,
+                                const awh_dvec             value,
+                                ArrayRef<const double>     neighborLambdaEnergies,
+                                int                        gridpointIndex)
 {
     double logWeight = detail::c_largeNegativeExponent;
 
@@ -275,9 +276,9 @@ double biasedLogWeightFromPoint(const std::vector<DimParams>&  dimParams,
  * \returns The calculated marginal distribution in a 1D array with
  * as many elements as there are points along the axis of interest.
  */
-std::vector<double> calculateFELambdaMarginalDistribution(const BiasGrid&          grid,
-                                                          gmx::ArrayRef<const int> neighbors,
-                                                          gmx::ArrayRef<const double> probWeightNeighbor)
+std::vector<double> calculateFELambdaMarginalDistribution(const BiasGrid&        grid,
+                                                          ArrayRef<const int>    neighbors,
+                                                          ArrayRef<const double> probWeightNeighbor)
 {
     const std::optional<int> lambdaAxisIndex = grid.lambdaAxisIndex();
     GMX_RELEASE_ASSERT(lambdaAxisIndex,
@@ -297,9 +298,9 @@ std::vector<double> calculateFELambdaMarginalDistribution(const BiasGrid&
 
 } // namespace
 
-void BiasState::calcConvolvedPmf(const std::vector<DimParams>& dimParams,
-                                 const BiasGrid&               grid,
-                                 std::vector<float>*           convolvedPmf) const
+void BiasState::calcConvolvedPmf(ArrayRef<const DimParams> dimParams,
+                                 const BiasGrid&           grid,
+                                 std::vector<float>*       convolvedPmf) const
 {
     size_t numPoints = grid.numPoints();
 
@@ -313,7 +314,7 @@ void BiasState::calcConvolvedPmf(const std::vector<DimParams>& dimParams,
     {
         double           freeEnergyWeights = 0;
         const GridPoint& point             = grid.point(m);
-        for (auto& neighbor : point.neighbor)
+        for (const auto& neighbor : point.neighbor)
         {
             /* Do not convolve the bias along a lambda axis - only use the pmf from the current point */
             if (!pointsHaveDifferentLambda(grid, m, neighbor))
@@ -324,8 +325,8 @@ void BiasState::calcConvolvedPmf(const std::vector<DimParams>& dimParams,
                 /* Add the convolved PMF weights for the neighbors of this point.
                 Note that this function only adds point within the target > 0 region.
                 Sum weights, take the logarithm last to get the free energy. */
-                double logWeight = biasedLogWeightFromPoint(dimParams, points_, grid, neighbor,
-                                                            biasNeighbor, point.coordValue, {}, m);
+                double logWeight = biasedLogWeightFromPoint(
+                        dimParams, points_, grid, neighbor, biasNeighbor, point.coordValue, {}, m);
                 freeEnergyWeights += std::exp(logWeight);
             }
         }
@@ -348,10 +349,10 @@ namespace
  * \param[in,out] pointState  The state of all points.
  * \param[in]     params      The bias parameters.
  */
-void updateTargetDistribution(gmx::ArrayRef<PointState> pointState, const BiasParams& params)
+void updateTargetDistribution(ArrayRef<PointState> pointState, const BiasParams& params)
 {
     double freeEnergyCutoff = 0;
-    if (params.eTarget == eawhtargetCUTOFF)
+    if (params.eTarget == AwhTargetType::Cutoff)
     {
         freeEnergyCutoff = freeEnergyMinimumValue(pointState) + params.freeEnergyCutoffInKT;
     }
@@ -410,7 +411,7 @@ int BiasState::warnForHistogramAnomalies(const BiasGrid& grid, int biasIndex, do
     /* Sum up the histograms and get their normalization */
     double sumVisits  = 0;
     double sumWeights = 0;
-    for (auto& pointState : points_)
+    for (const auto& pointState : points_)
     {
         if (pointState.inTargetRegion())
         {
@@ -456,7 +457,10 @@ int BiasState::warnForHistogramAnomalies(const BiasGrid& grid, int biasIndex, do
                     "If you are not certain about your settings you might want to increase your "
                     "pull force constant or "
                     "modify your sampling region.\n",
-                    biasIndex + 1, t, pointValueString.c_str(), maxHistogramRatio);
+                    biasIndex + 1,
+                    t,
+                    pointValueString.c_str(),
+                    maxHistogramRatio);
             gmx::TextLineWrapper wrapper;
             wrapper.settings().setLineLength(c_linewidth);
             fprintf(fplog, "%s", wrapper.wrapToString(warningMessage).c_str());
@@ -472,11 +476,11 @@ int BiasState::warnForHistogramAnomalies(const BiasGrid& grid, int biasIndex, do
     return numWarnings;
 }
 
-double BiasState::calcUmbrellaForceAndPotential(const std::vector<DimParams>& dimParams,
-                                                const BiasGrid&               grid,
-                                                int                           point,
-                                                ArrayRef<const double>        neighborLambdaDhdl,
-                                                gmx::ArrayRef<double>         force) const
+double BiasState::calcUmbrellaForceAndPotential(ArrayRef<const DimParams> dimParams,
+                                                const BiasGrid&           grid,
+                                                int                       point,
+                                                ArrayRef<const double>    neighborLambdaDhdl,
+                                                ArrayRef<double>          force) const
 {
     double potential = 0;
     for (size_t d = 0; d < dimParams.size(); d++)
@@ -505,12 +509,12 @@ double BiasState::calcUmbrellaForceAndPotential(const std::vector<DimParams>& di
     return potential;
 }
 
-void BiasState::calcConvolvedForce(const std::vector<DimParams>& dimParams,
-                                   const BiasGrid&               grid,
-                                   gmx::ArrayRef<const double>   probWeightNeighbor,
-                                   ArrayRef<const double>        neighborLambdaDhdl,
-                                   gmx::ArrayRef<double>         forceWorkBuffer,
-                                   gmx::ArrayRef<double>         force) const
+void BiasState::calcConvolvedForce(ArrayRef<const DimParams> dimParams,
+                                   const BiasGrid&           grid,
+                                   ArrayRef<const double>    probWeightNeighbor,
+                                   ArrayRef<const double>    neighborLambdaDhdl,
+                                   ArrayRef<double>          forceWorkBuffer,
+                                   ArrayRef<double>          force) const
 {
     for (size_t d = 0; d < dimParams.size(); d++)
     {
@@ -536,18 +540,24 @@ void BiasState::calcConvolvedForce(const std::vector<DimParams>& dimParams,
     }
 }
 
-double BiasState::moveUmbrella(const std::vector<DimParams>& dimParams,
-                               const BiasGrid&               grid,
-                               gmx::ArrayRef<const double>   probWeightNeighbor,
-                               ArrayRef<const double>        neighborLambdaDhdl,
-                               gmx::ArrayRef<double>         biasForce,
-                               int64_t                       step,
-                               int64_t                       seed,
-                               int                           indexSeed)
+double BiasState::moveUmbrella(ArrayRef<const DimParams> dimParams,
+                               const BiasGrid&           grid,
+                               ArrayRef<const double>    probWeightNeighbor,
+                               ArrayRef<const double>    neighborLambdaDhdl,
+                               ArrayRef<double>          biasForce,
+                               int64_t                   step,
+                               int64_t                   seed,
+                               int                       indexSeed,
+                               bool                      onlySampleUmbrellaGridpoint)
 {
     /* Generate and set a new coordinate reference value */
-    coordState_.sampleUmbrellaGridpoint(grid, coordState_.gridpointIndex(), probWeightNeighbor,
-                                        step, seed, indexSeed);
+    coordState_.sampleUmbrellaGridpoint(
+            grid, coordState_.gridpointIndex(), probWeightNeighbor, step, seed, indexSeed);
+
+    if (onlySampleUmbrellaGridpoint)
+    {
+        return 0;
+    }
 
     std::vector<double> newForce(dimParams.size());
     double              newPotential = calcUmbrellaForceAndPotential(
@@ -627,8 +637,8 @@ void BiasState::getSkippedUpdateHistogramScaleFactors(const BiasParams& params,
         /* In between global updates the reference histogram size is kept constant so we trivially
            know what the histogram size was at the time of the skipped update. */
         double histogramSize = histogramSize_.histogramSize();
-        setHistogramUpdateScaleFactors(params, histogramSize, histogramSize, weightHistScaling,
-                                       logPmfSumScaling);
+        setHistogramUpdateScaleFactors(
+                params, histogramSize, histogramSize, weightHistScaling, logPmfSumScaling);
     }
     else
     {
@@ -667,7 +677,7 @@ void BiasState::doSkippedUpdatesInNeighborhood(const BiasParams& params, const B
 
     /* For each neighbor point of the center point, refresh its state by adding the results of all past, skipped updates. */
     const std::vector<int>& neighbors = grid.point(coordState_.gridpointIndex()).neighbor;
-    for (auto& neighbor : neighbors)
+    for (const auto& neighbor : neighbors)
     {
         bool didUpdate = points_[neighbor].performPreviouslySkippedUpdates(
                 params, histogramSize_.numUpdates(), weightHistScaling, logPmfsumScaling);
@@ -728,11 +738,11 @@ void mergeSharedUpdateLists(std::vector<int>*     updateList,
  * last update. \param[in] endUpdatelist     The end of the rectangular that has been sampled since
  * last update. \param[in,out] updateList    Local update list to set (assumed >= npoints long).
  */
-void makeLocalUpdateList(const BiasGrid&                grid,
-                         const std::vector<PointState>& points,
-                         const awh_ivec                 originUpdatelist,
-                         const awh_ivec                 endUpdatelist,
-                         std::vector<int>*              updateList)
+void makeLocalUpdateList(const BiasGrid&            grid,
+                         ArrayRef<const PointState> points,
+                         const awh_ivec             originUpdatelist,
+                         const awh_ivec             endUpdatelist,
+                         std::vector<int>*          updateList)
 {
     awh_ivec origin;
     awh_ivec numPoints;
@@ -952,11 +962,11 @@ void labelCoveredPoints(const std::vector<bool>& visited,
 
 } // namespace
 
-bool BiasState::isSamplingRegionCovered(const BiasParams&             params,
-                                        const std::vector<DimParams>& dimParams,
-                                        const BiasGrid&               grid,
-                                        const t_commrec*              commRecord,
-                                        const gmx_multisim_t*         multiSimComm) const
+bool BiasState::isSamplingRegionCovered(const BiasParams&         params,
+                                        ArrayRef<const DimParams> dimParams,
+                                        const BiasGrid&           grid,
+                                        const t_commrec*          commRecord,
+                                        const gmx_multisim_t*     multiSimComm) const
 {
     /* Allocate and initialize arrays: one for checking visits along each dimension,
        one for keeping track of which points to check and one for the covered points.
@@ -987,7 +997,7 @@ bool BiasState::isSamplingRegionCovered(const BiasParams&             params,
     /* Set the free energy cutoff */
     double maxFreeEnergy = GMX_FLOAT_MAX;
 
-    if (params.eTarget == eawhtargetCUTOFF)
+    if (params.eTarget == AwhTargetType::Cutoff)
     {
         maxFreeEnergy = freeEnergyMinimumValue(points_) + params.freeEnergyCutoffInKT;
     }
@@ -1035,8 +1045,12 @@ bool BiasState::isSamplingRegionCovered(const BiasParams&             params,
     /* Label each point along each dimension as covered or not. */
     for (int d = 0; d < grid.numDimensions(); d++)
     {
-        labelCoveredPoints(checkDim[d].visited, checkDim[d].checkCovering, grid.axis(d).numPoints(),
-                           grid.axis(d).numPointsInPeriod(), params.coverRadius()[d], checkDim[d].covered);
+        labelCoveredPoints(checkDim[d].visited,
+                           checkDim[d].checkCovering,
+                           grid.axis(d).numPoints(),
+                           grid.axis(d).numPointsInPeriod(),
+                           params.coverRadius()[d],
+                           checkDim[d].covered);
     }
 
     /* Now check for global covering. Each dimension needs to be covered separately.
@@ -1060,7 +1074,8 @@ bool BiasState::isSamplingRegionCovered(const BiasParams&             params,
         {
             sumOverSimulations(
                     gmx::arrayRefFromArray(checkDim[d].covered.data(), grid.axis(d).numPoints()),
-                    commRecord, multiSimComm);
+                    commRecord,
+                    multiSimComm);
         }
     }
 
@@ -1092,15 +1107,15 @@ static void normalizeFreeEnergyAndPmfSum(std::vector<PointState>* pointState)
     }
 }
 
-void BiasState::updateFreeEnergyAndAddSamplesToHistogram(const std::vector<DimParams>& dimParams,
-                                                         const BiasGrid&               grid,
-                                                         const BiasParams&             params,
-                                                         const t_commrec*              commRecord,
-                                                         const gmx_multisim_t*         multiSimComm,
-                                                         double                        t,
-                                                         int64_t                       step,
-                                                         FILE*                         fplog,
-                                                         std::vector<int>*             updateList)
+void BiasState::updateFreeEnergyAndAddSamplesToHistogram(ArrayRef<const DimParams> dimParams,
+                                                         const BiasGrid&           grid,
+                                                         const BiasParams&         params,
+                                                         const t_commrec*          commRecord,
+                                                         const gmx_multisim_t*     multiSimComm,
+                                                         double                    t,
+                                                         int64_t                   step,
+                                                         FILE*                     fplog,
+                                                         std::vector<int>*         updateList)
 {
     /* Note hat updateList is only used in this scope and is always
      * re-initialized. We do not use a local vector, because that would
@@ -1144,7 +1159,7 @@ void BiasState::updateFreeEnergyAndAddSamplesToHistogram(const std::vector<DimPa
 
     /* Update target distribution? */
     bool needToUpdateTargetDistribution =
-            (params.eTarget != eawhtargetCONSTANT && params.isUpdateTargetStep(step));
+            (params.eTarget != AwhTargetType::Constant && params.isUpdateTargetStep(step));
 
     /* In the initial stage, the histogram grows dynamically as a function of the number of coverings. */
     bool detectedCovering = false;
@@ -1156,8 +1171,8 @@ void BiasState::updateFreeEnergyAndAddSamplesToHistogram(const std::vector<DimPa
     }
 
     /* The weighthistogram size after this update. */
-    double newHistogramSize = histogramSize_.newHistogramSize(params, t, detectedCovering, points_,
-                                                              weightSumCovering_, fplog);
+    double newHistogramSize = histogramSize_.newHistogramSize(
+            params, t, detectedCovering, points_, weightSumCovering_, fplog);
 
     /* Make the update list. Usually we try to only update local points,
      * but if the update has non-trivial or non-deterministic effects
@@ -1193,8 +1208,8 @@ void BiasState::updateFreeEnergyAndAddSamplesToHistogram(const std::vector<DimPa
     }
     double weightHistScalingNew;
     double logPmfsumScalingNew;
-    setHistogramUpdateScaleFactors(params, newHistogramSize, histogramSize_.histogramSize(),
-                                   &weightHistScalingNew, &logPmfsumScalingNew);
+    setHistogramUpdateScaleFactors(
+            params, newHistogramSize, histogramSize_.histogramSize(), &weightHistScalingNew, &logPmfsumScalingNew);
 
     /* Update free energy and reference weight histogram for points in the update list. */
     for (int pointIndex : *updateList)
@@ -1204,14 +1219,13 @@ void BiasState::updateFreeEnergyAndAddSamplesToHistogram(const std::vector<DimPa
         /* Do updates from previous update steps that were skipped because this point was at that time non-local. */
         if (params.skipUpdates())
         {
-            pointStateToUpdate->performPreviouslySkippedUpdates(params, histogramSize_.numUpdates(),
-                                                                weightHistScalingSkipped,
-                                                                logPmfsumScalingSkipped);
+            pointStateToUpdate->performPreviouslySkippedUpdates(
+                    params, histogramSize_.numUpdates(), weightHistScalingSkipped, logPmfsumScalingSkipped);
         }
 
         /* Now do an update with new sampling data. */
-        pointStateToUpdate->updateWithNewSampling(params, histogramSize_.numUpdates(),
-                                                  weightHistScalingNew, logPmfsumScalingNew);
+        pointStateToUpdate->updateWithNewSampling(
+                params, histogramSize_.numUpdates(), weightHistScalingNew, logPmfsumScalingNew);
     }
 
     /* Only update the histogram size after we are done with the local point updates */
@@ -1239,9 +1253,9 @@ void BiasState::updateFreeEnergyAndAddSamplesToHistogram(const std::vector<DimPa
     histogramSize_.incrementNumUpdates();
 }
 
-double BiasState::updateProbabilityWeightsAndConvolvedBias(const std::vector<DimParams>& dimParams,
-                                                           const BiasGrid&               grid,
-                                                           gmx::ArrayRef<const double> neighborLambdaEnergies,
+double BiasState::updateProbabilityWeightsAndConvolvedBias(ArrayRef<const DimParams> dimParams,
+                                                           const BiasGrid&           grid,
+                                                           ArrayRef<const double> neighborLambdaEnergies,
                                                            std::vector<double, AlignedAllocator<double>>* weight) const
 {
     /* Only neighbors of the current coordinate value will have a non-negligible chance of getting sampled */
@@ -1267,9 +1281,14 @@ double BiasState::updateProbabilityWeightsAndConvolvedBias(const std::vector<Dim
             if (n < neighbors.size())
             {
                 const int neighbor = neighbors[n];
-                (*weight)[n]       = biasedLogWeightFromPoint(
-                        dimParams, points_, grid, neighbor, points_[neighbor].bias(),
-                        coordState_.coordValue(), neighborLambdaEnergies, coordState_.gridpointIndex());
+                (*weight)[n]       = biasedLogWeightFromPoint(dimParams,
+                                                        points_,
+                                                        grid,
+                                                        neighbor,
+                                                        points_[neighbor].bias(),
+                                                        coordState_.coordValue(),
+                                                        neighborLambdaEnergies,
+                                                        coordState_.gridpointIndex());
             }
             else
             {
@@ -1322,9 +1341,9 @@ double BiasState::updateProbabilityWeightsAndConvolvedBias(const std::vector<Dim
     return std::log(weightSum);
 }
 
-double BiasState::calcConvolvedBias(const std::vector<DimParams>& dimParams,
-                                    const BiasGrid&               grid,
-                                    const awh_dvec&               coordValue) const
+double BiasState::calcConvolvedBias(ArrayRef<const DimParams> dimParams,
+                                    const BiasGrid&           grid,
+                                    const awh_dvec&           coordValue) const
 {
     int              point     = grid.nearestIndex(coordValue);
     const GridPoint& gridPoint = grid.point(point);
@@ -1338,8 +1357,8 @@ double BiasState::calcConvolvedBias(const std::vector<DimParams>& dimParams,
         {
             continue;
         }
-        double logWeight = biasedLogWeightFromPoint(dimParams, points_, grid, neighbor,
-                                                    points_[neighbor].bias(), coordValue, {}, point);
+        double logWeight = biasedLogWeightFromPoint(
+                dimParams, points_, grid, neighbor, points_[neighbor].bias(), coordValue, {}, point);
         weightSum += std::exp(logWeight);
     }
 
@@ -1430,8 +1449,10 @@ void BiasState::sampleCoordAndPmf(const std::vector<DimParams>& dimParams,
         std::vector<double> lambdaMarginalDistribution =
                 calculateFELambdaMarginalDistribution(grid, neighbors, probWeightNeighbor);
 
-        awh_dvec coordValueAlongLambda = { coordState_.coordValue()[0], coordState_.coordValue()[1],
-                                           coordState_.coordValue()[2], coordState_.coordValue()[3] };
+        awh_dvec coordValueAlongLambda = { coordState_.coordValue()[0],
+                                           coordState_.coordValue()[1],
+                                           coordState_.coordValue()[2],
+                                           coordState_.coordValue()[3] };
         for (size_t i = 0; i < neighbors.size(); i++)
         {
             const int neighbor = neighbors[i];
@@ -1541,13 +1562,12 @@ void BiasState::broadcast(const t_commrec* commRecord)
 
     gmx_bcast(points_.size() * sizeof(PointState), points_.data(), commRecord->mpi_comm_mygroup);
 
-    gmx_bcast(weightSumCovering_.size() * sizeof(double), weightSumCovering_.data(),
-              commRecord->mpi_comm_mygroup);
+    gmx_bcast(weightSumCovering_.size() * sizeof(double), weightSumCovering_.data(), commRecord->mpi_comm_mygroup);
 
     gmx_bcast(sizeof(histogramSize_), &histogramSize_, commRecord->mpi_comm_mygroup);
 }
 
-void BiasState::setFreeEnergyToConvolvedPmf(const std::vector<DimParams>& dimParams, const BiasGrid& grid)
+void BiasState::setFreeEnergyToConvolvedPmf(ArrayRef<const DimParams> dimParams, const BiasGrid& grid)
 {
     std::vector<float> convolvedPmf;
 
@@ -1607,12 +1627,12 @@ static int countTrailingZeroRows(const double* const* data, int numRows, int num
  * \param[in]     biasIndex   The index of the bias.
  * \param[in,out] pointState  The state of the points in this bias.
  */
-static void readUserPmfAndTargetDistribution(const std::vector<DimParams>& dimParams,
-                                             const BiasGrid&               grid,
-                                             const std::string&            filename,
-                                             int                           numBias,
-                                             int                           biasIndex,
-                                             std::vector<PointState>*      pointState)
+static void readUserPmfAndTargetDistribution(ArrayRef<const DimParams> dimParams,
+                                             const BiasGrid&           grid,
+                                             const std::string&        filename,
+                                             int                       numBias,
+                                             int                       biasIndex,
+                                             std::vector<PointState>*  pointState)
 {
     /* Read the PMF and target distribution.
        From the PMF, the convolved PMF, or the reference value free energy, can be calculated
@@ -1651,8 +1671,8 @@ static void readUserPmfAndTargetDistribution(const std::vector<DimParams>& dimPa
 
     if (numRows <= 0)
     {
-        std::string mesg = gmx::formatString("%s is empty!.\n\n%s", filename.c_str(),
-                                             correctFormatMessage.c_str());
+        std::string mesg = gmx::formatString(
+                "%s is empty!.\n\n%s", filename.c_str(), correctFormatMessage.c_str());
         GMX_THROW(InvalidInputError(mesg));
     }
 
@@ -1662,7 +1682,8 @@ static void readUserPmfAndTargetDistribution(const std::vector<DimParams>& dimPa
         std::string mesg = gmx::formatString(
                 "%s contains too few data points (%d)."
                 "The minimum number of points is 2.",
-                filename.c_str(), numRows);
+                filename.c_str(),
+                numRows);
         GMX_THROW(InvalidInputError(mesg));
     }
 
@@ -1690,7 +1711,9 @@ static void readUserPmfAndTargetDistribution(const std::vector<DimParams>& dimPa
         std::string mesg = gmx::formatString(
                 "The number of columns in %s should be at least %d."
                 "\n\n%s",
-                filename.c_str(), numColumnsMin, correctFormatMessage.c_str());
+                filename.c_str(),
+                numColumnsMin,
+                correctFormatMessage.c_str());
         GMX_THROW(InvalidInputError(mesg));
     }
 
@@ -1702,7 +1725,8 @@ static void readUserPmfAndTargetDistribution(const std::vector<DimParams>& dimPa
         std::string mesg = gmx::formatString(
                 "Found %d trailing zero data rows in %s. Please remove trailing empty lines and "
                 "try again.",
-                numZeroRows, filename.c_str());
+                numZeroRows,
+                filename.c_str());
         GMX_THROW(InvalidInputError(mesg));
     }
 
@@ -1737,7 +1761,9 @@ static void readUserPmfAndTargetDistribution(const std::vector<DimParams>& dimPa
         if (target < 0)
         {
             std::string mesg = gmx::formatString(
-                    "Target distribution weight at point %zu (%g) in %s is negative.", m, target,
+                    "Target distribution weight at point %zu (%g) in %s is negative.",
+                    m,
+                    target,
                     filename.c_str());
             GMX_THROW(InvalidInputError(mesg));
         }
@@ -1752,7 +1778,8 @@ static void readUserPmfAndTargetDistribution(const std::vector<DimParams>& dimPa
     {
         std::string mesg =
                 gmx::formatString("The target weights given in column %d in %s are all 0",
-                                  columnIndexTarget, filename.c_str());
+                                  columnIndexTarget,
+                                  filename.c_str());
         GMX_THROW(InvalidInputError(mesg));
     }
 
@@ -1795,24 +1822,24 @@ void BiasState::normalizePmf(int numSharingSims)
     }
 }
 
-void BiasState::initGridPointState(const AwhBiasParams&          awhBiasParams,
-                                   const std::vector<DimParams>& dimParams,
-                                   const BiasGrid&               grid,
-                                   const BiasParams&             params,
-                                   const std::string&            filename,
-                                   int                           numBias)
+void BiasState::initGridPointState(const AwhBiasParams&      awhBiasParams,
+                                   ArrayRef<const DimParams> dimParams,
+                                   const BiasGrid&           grid,
+                                   const BiasParams&         params,
+                                   const std::string&        filename,
+                                   int                       numBias)
 {
     /* Modify PMF, free energy and the constant target distribution factor
      * to user input values if there is data given.
      */
-    if (awhBiasParams.bUserData)
+    if (awhBiasParams.userPMFEstimate())
     {
         readUserPmfAndTargetDistribution(dimParams, grid, filename, numBias, params.biasIndex, &points_);
         setFreeEnergyToConvolvedPmf(dimParams, grid);
     }
 
     /* The local Boltzmann distribution is special because the target distribution is updated as a function of the reference weighthistogram. */
-    GMX_RELEASE_ASSERT(params.eTarget != eawhtargetLOCALBOLTZMANN || points_[0].weightSumRef() != 0,
+    GMX_RELEASE_ASSERT(params.eTarget != AwhTargetType::LocalBoltzmann || points_[0].weightSumRef() != 0,
                        "AWH reference weight histogram not initialized properly with local "
                        "Boltzmann target distribution.");
 
@@ -1843,10 +1870,10 @@ void BiasState::initGridPointState(const AwhBiasParams&          awhBiasParams,
     normalizePmf(params.numSharedUpdate);
 }
 
-BiasState::BiasState(const AwhBiasParams&          awhBiasParams,
-                     double                        histogramSizeInitial,
-                     const std::vector<DimParams>& dimParams,
-                     const BiasGrid&               grid) :
+BiasState::BiasState(const AwhBiasParams&      awhBiasParams,
+                     double                    histogramSizeInitial,
+                     ArrayRef<const DimParams> dimParams,
+                     const BiasGrid&           grid) :
     coordState_(awhBiasParams, dimParams, grid),
     points_(grid.numPoints()),
     weightSumCovering_(grid.numPoints()),
index 50603071e8d9b5df75795c54cd272e31ea16808b..859f524af6d48c52e53d84ee5b48a99a1bb62df2 100644 (file)
@@ -75,7 +75,6 @@ namespace gmx
 template<typename>
 class ArrayRef;
 struct AwhBiasHistory;
-struct AwhBiasParams;
 class BiasParams;
 class BiasGrid;
 class GridAxis;
@@ -107,10 +106,10 @@ public:
      * \param[in] dimParams             The dimension parameters.
      * \param[in] grid                  The bias grid.
      */
-    BiasState(const AwhBiasParams&          awhBiasParams,
-              double                        histogramSizeInitial,
-              const std::vector<DimParams>& dimParams,
-              const BiasGrid&               grid);
+    BiasState(const AwhBiasParams&      awhBiasParams,
+              double                    histogramSizeInitial,
+              ArrayRef<const DimParams> dimParams,
+              const BiasGrid&           grid);
 
     /*! \brief
      * Restore the bias state from history.
@@ -157,9 +156,9 @@ private:
      * \param[in] grid          The grid.
      * \param[in,out] convolvedPmf  Array returned will be of the same length as the AWH grid to store the convolved PMF in.
      */
-    void calcConvolvedPmf(const std::vector<DimParams>& dimParams,
-                          const BiasGrid&               grid,
-                          std::vector<float>*           convolvedPmf) const;
+    void calcConvolvedPmf(ArrayRef<const DimParams> dimParams,
+                          const BiasGrid&           grid,
+                          std::vector<float>*       convolvedPmf) const;
 
     /*! \brief
      * Convolves the PMF and sets the initial free energy to its convolution.
@@ -167,7 +166,7 @@ private:
      * \param[in] dimParams  The bias dimensions parameters
      * \param[in] grid       The bias grid.
      */
-    void setFreeEnergyToConvolvedPmf(const std::vector<DimParams>& dimParams, const BiasGrid& grid);
+    void setFreeEnergyToConvolvedPmf(ArrayRef<const DimParams> dimParams, const BiasGrid& grid);
 
     /*! \brief
      * Normalize the PMF histogram.
@@ -187,12 +186,12 @@ public:
      * \param[in] filename        Name of file to read PMF and target from.
      * \param[in] numBias         The number of biases.
      */
-    void initGridPointState(const AwhBiasParams&          awhBiasParams,
-                            const std::vector<DimParams>& dimParams,
-                            const BiasGrid&               grid,
-                            const BiasParams&             params,
-                            const std::string&            filename,
-                            int                           numBias);
+    void initGridPointState(const AwhBiasParams&      awhBiasParams,
+                            ArrayRef<const DimParams> dimParams,
+                            const BiasGrid&           grid,
+                            const BiasParams&         params,
+                            const std::string&        filename,
+                            int                       numBias);
 
     /*! \brief
      * Performs statistical checks on the collected histograms and warns if issues are detected.
@@ -224,11 +223,11 @@ public:
      * \param[in,out] force      Force vector to set.
      * Returns the umbrella potential.
      */
-    double calcUmbrellaForceAndPotential(const std::vector<DimParams>& dimParams,
-                                         const BiasGrid&               grid,
-                                         int                           point,
-                                         ArrayRef<const double>        neighborLambdaDhdl,
-                                         gmx::ArrayRef<double>         force) const;
+    double calcUmbrellaForceAndPotential(ArrayRef<const DimParams> dimParams,
+                                         const BiasGrid&           grid,
+                                         int                       point,
+                                         ArrayRef<const double>    neighborLambdaDhdl,
+                                         ArrayRef<double>          force) const;
 
     /*! \brief
      * Calculates and sets the convolved force acting on the coordinate.
@@ -248,12 +247,12 @@ public:
      * \param[in]     forceWorkBuffer     Force work buffer, values only used internally.
      * \param[in,out] force               Bias force vector to set.
      */
-    void calcConvolvedForce(const std::vector<DimParams>& dimParams,
-                            const BiasGrid&               grid,
-                            gmx::ArrayRef<const double>   probWeightNeighbor,
-                            ArrayRef<const double>        neighborLambdaDhdl,
-                            gmx::ArrayRef<double>         forceWorkBuffer,
-                            gmx::ArrayRef<double>         force) const;
+    void calcConvolvedForce(ArrayRef<const DimParams> dimParams,
+                            const BiasGrid&           grid,
+                            ArrayRef<const double>    probWeightNeighbor,
+                            ArrayRef<const double>    neighborLambdaDhdl,
+                            ArrayRef<double>          forceWorkBuffer,
+                            ArrayRef<double>          force) const;
 
     /*! \brief
      * Move the center point of the umbrella potential.
@@ -277,16 +276,19 @@ public:
      * \param[in] step                        Step number, needed for the random number generator.
      * \param[in] seed                        Random seed.
      * \param[in] indexSeed                   Second random seed, should be the bias Index.
+     * \param[in] onlySampleUmbrellaGridpoint Only sample the umbrella gridpoint without calculating
+     * force and potential.
      * \returns the new potential value.
      */
-    double moveUmbrella(const std::vector<DimParams>& dimParams,
-                        const BiasGrid&               grid,
-                        gmx::ArrayRef<const double>   probWeightNeighbor,
-                        ArrayRef<const double>        neighborLambdaDhdl,
-                        gmx::ArrayRef<double>         biasForce,
-                        int64_t                       step,
-                        int64_t                       seed,
-                        int                           indexSeed);
+    double moveUmbrella(ArrayRef<const DimParams> dimParams,
+                        const BiasGrid&           grid,
+                        ArrayRef<const double>    probWeightNeighbor,
+                        ArrayRef<const double>    neighborLambdaDhdl,
+                        ArrayRef<double>          biasForce,
+                        int64_t                   step,
+                        int64_t                   seed,
+                        int                       indexSeed,
+                        bool                      onlySampleUmbrellaGridpoint);
 
 private:
     /*! \brief
@@ -358,11 +360,11 @@ private:
      * \param[in] multiSimComm  Struct for multi-simulation communication.
      * \returns true if covered.
      */
-    bool isSamplingRegionCovered(const BiasParams&             params,
-                                 const std::vector<DimParams>& dimParams,
-                                 const BiasGrid&               grid,
-                                 const t_commrec*              commRecord,
-                                 const gmx_multisim_t*         multiSimComm) const;
+    bool isSamplingRegionCovered(const BiasParams&         params,
+                                 ArrayRef<const DimParams> dimParams,
+                                 const BiasGrid&           grid,
+                                 const t_commrec*          commRecord,
+                                 const gmx_multisim_t*     multiSimComm) const;
 
     /*! \brief
      * Return the new reference weight histogram size for the current update.
@@ -413,15 +415,15 @@ public:
      * \param[in,out] fplog       Log file.
      * \param[in,out] updateList  Work space to store a temporary list.
      */
-    void updateFreeEnergyAndAddSamplesToHistogram(const std::vector<DimParams>& dimParams,
-                                                  const BiasGrid&               grid,
-                                                  const BiasParams&             params,
-                                                  const t_commrec*              commRecord,
-                                                  const gmx_multisim_t*         ms,
-                                                  double                        t,
-                                                  int64_t                       step,
-                                                  FILE*                         fplog,
-                                                  std::vector<int>*             updateList);
+    void updateFreeEnergyAndAddSamplesToHistogram(ArrayRef<const DimParams> dimParams,
+                                                  const BiasGrid&           grid,
+                                                  const BiasParams&         params,
+                                                  const t_commrec*          commRecord,
+                                                  const gmx_multisim_t*     ms,
+                                                  double                    t,
+                                                  int64_t                   step,
+                                                  FILE*                     fplog,
+                                                  std::vector<int>*         updateList);
 
     /*! \brief
      * Update the probability weights and the convolved bias.
@@ -446,8 +448,8 @@ public:
      * \returns the convolved bias.
      */
 
-    double updateProbabilityWeightsAndConvolvedBias(const std::vector<DimParams>& dimParams,
-                                                    const BiasGrid&               grid,
+    double updateProbabilityWeightsAndConvolvedBias(ArrayRef<const DimParams> dimParams,
+                                                    const BiasGrid&           grid,
                                                     ArrayRef<const double> neighborLambdaEnergies,
                                                     std::vector<double, AlignedAllocator<double>>* weight) const;
 
@@ -461,7 +463,7 @@ public:
      * \param[in] grid                The grid.
      * \param[in] probWeightNeighbor  Probability weights of the neighbors.
      */
-    void sampleProbabilityWeights(const BiasGrid& grid, gmx::ArrayRef<const double> probWeightNeighbor);
+    void sampleProbabilityWeights(const BiasGrid& grid, ArrayRef<const double> probWeightNeighbor);
 
     /*! \brief
      * Sample the reaction coordinate and PMF for future updates or analysis.
@@ -476,7 +478,7 @@ public:
      */
     void sampleCoordAndPmf(const std::vector<DimParams>& dimParams,
                            const BiasGrid&               grid,
-                           gmx::ArrayRef<const double>   probWeightNeighbor,
+                           ArrayRef<const double>        probWeightNeighbor,
                            double                        convolvedBias);
     /*! \brief
      * Calculates the convolved bias for a given coordinate value.
@@ -493,9 +495,9 @@ public:
      * \param[in] coordValue  Coordinate value.
      * \returns the convolved bias >= -GMX_FLOAT_MAX.
      */
-    double calcConvolvedBias(const std::vector<DimParams>& dimParams,
-                             const BiasGrid&               grid,
-                             const awh_dvec&               coordValue) const;
+    double calcConvolvedBias(ArrayRef<const DimParams> dimParams,
+                             const BiasGrid&           grid,
+                             const awh_dvec&           coordValue) const;
 
     /*! \brief
      * Fills the given array with PMF values.
@@ -506,7 +508,7 @@ public:
      *
      * \param[out] pmf  Array(ref) to be filled with the PMF values, should have the same size as the bias grid.
      */
-    void getPmf(gmx::ArrayRef<float> /*pmf*/) const;
+    void getPmf(ArrayRef<float> /*pmf*/) const;
 
     /*! \brief Returns the current coordinate state.
      */
index 8fd09eedbca37be6fa5be9238867923a958b1b37..aa0b916dfea272d1e54c8ea433ee8b2c8c4e9ca9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -390,7 +390,7 @@ int BiasWriter::writeToEnergySubblocks(const Bias& bias, t_enxsubblock* sub)
 
     for (size_t b = 0; b < block_.size(); b++)
     {
-        sub[b].type = xdr_datatype_float;
+        sub[b].type = XdrDataType::Float;
         sub[b].nr   = block_[b].data().size();
         sub[b].fval = block_[b].data().data();
     }
index 420a26ff630de93f7d2bef46b9cecebb423e0549..20451d92151f6a8a6df16b2b868102850aaacd60 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +193,6 @@ private:
      */
     void prepareBiasOutput(const Bias& bias);
 
-private:
     std::vector<AwhEnergyBlock>       block_; /**< The data blocks */
     std::map<AwhOutputEntryType, int> outputTypeToBlock_; /**< Start block index for each variable, -1 when variable should not be written */
 };
index 6de883221315b2ab4cbd70adfc0653bffbc34a88..f29eee36b06f9d0702e44588f9e6f998598dbdaf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 namespace gmx
 {
 
-CoordState::CoordState(const AwhBiasParams&          awhBiasParams,
-                       const std::vector<DimParams>& dimParams,
-                       const BiasGrid&               grid)
+CoordState::CoordState(const AwhBiasParams&      awhBiasParams,
+                       ArrayRef<const DimParams> dimParams,
+                       const BiasGrid&           grid)
 {
-    for (size_t d = 0; d < dimParams.size(); d++)
+    GMX_RELEASE_ASSERT(awhBiasParams.ndim() == dimParams.ssize(),
+                       "Need to have identical size for dimensions");
+    const auto& awhDimParams = awhBiasParams.dimParams();
+    for (int d = 0; d < gmx::ssize(awhDimParams); d++)
     {
-        coordValue_[d] = dimParams[d].scaleUserInputToInternal(awhBiasParams.dimParams[d].coordValueInit);
+        coordValue_[d] = dimParams[d].scaleUserInputToInternal(awhDimParams[d].initialCoordinate());
     }
 
     /* The grid-point index is always the nearest point to the coordinate.
@@ -173,7 +176,10 @@ void CoordState::setCoordValue(const BiasGrid& grid, const awh_dvec coordValue)
                         "Coordinate %d of an AWH bias has a value %f which is more than %d sigma "
                         "out of the AWH range of [%f, %f]. You seem to have an unstable reaction "
                         "coordinate setup or an unequilibrated system.",
-                        dim + 1, coordValue[dim], c_marginInSigma, axis.origin(),
+                        dim + 1,
+                        coordValue[dim],
+                        c_marginInSigma,
+                        axis.origin(),
                         axis.origin() + axis.length());
                 GMX_THROW(SimulationInstabilityError(mesg));
             }
index f38ce86de98e2c27f0216138d849397f47654859..d9dff8fa68bdd263a4eaae9bab0233e61b536231 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ namespace gmx
 
 template<typename>
 class ArrayRef;
-struct AwhBiasParams;
+class AwhBiasParams;
 struct AwhBiasStateHistory;
 class BiasParams;
 class BiasGrid;
@@ -77,9 +77,7 @@ public:
      * \param[in] dimParams      The dimension Parameters.
      * \param[in] grid           The grid.
      */
-    CoordState(const AwhBiasParams&          awhBiasParams,
-               const std::vector<DimParams>& dimParams,
-               const BiasGrid&               grid);
+    CoordState(const AwhBiasParams& awhBiasParams, ArrayRef<const DimParams> dimParams, const BiasGrid& grid);
 
     /*! \brief
      * Sample a new umbrella reference point given the current coordinate value.
index 1181dd1999c14718fe9180ccf466921eae66601e..5a7b956e1b1c3390e9ccca114c6f88c2b30b0bc1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +46,8 @@
 
 #include "correlationgrid.h"
 
-#include "gromacs/math/utilities.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/real.h"
 
 namespace gmx
 {
index a1c4338d039954adee0fdc36736efb97153f8e26..eaaed1c22b472965105828c2b466091e3ba1e7e8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -150,7 +150,6 @@ public:
      */
     int getNumBlocks() const;
 
-public:
     const double             dtSample;           /**< Time in between samples. */
     const BlockLengthMeasure blockLengthMeasure; /**< The measure for the block length. */
 private:
index f77ba399387046ca91da0ce91c72505193043181..f24796ed37b8f10012c934004e138a547e635b47 100644 (file)
@@ -77,8 +77,10 @@ CorrelationGridHistory initCorrelationGridHistoryFromState(const CorrelationGrid
 {
     CorrelationGridHistory correlationGridHistory;
 
-    initCorrelationGridHistory(&correlationGridHistory, correlationGrid.tensors().size(),
-                               correlationGrid.tensorSize(), correlationGrid.blockDataListSize());
+    initCorrelationGridHistory(&correlationGridHistory,
+                               correlationGrid.tensors().size(),
+                               correlationGrid.tensorSize(),
+                               correlationGrid.blockDataListSize());
 
     return correlationGridHistory;
 }
index 2b3ac017205328a12e114f0093ac8dcd1be5560e..11fc93f83c2b50c09ce0dc704eba0279c854b787 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -103,7 +103,7 @@ public:
      * Builder function for pull dimension parameters.
      *
      * \param[in] conversionFactor  Conversion factor from user coordinate units to bias internal
-     * units (=DEG2RAD for angles).
+     * units (=c_deg2Rad for angles).
      * \param[in] forceConstant     The harmonic force constant.
      * \param[in] beta              1/(k_B T).
      */
index fcfd452d4a2e441553f9f6ab983c484566305ce3..c42e913f79bd73b9a296e7e517e5e49ccc9da743 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +67,8 @@ namespace gmx
 HistogramSize::HistogramSize(const AwhBiasParams& awhBiasParams, double histogramSizeInitial) :
     numUpdates_(0),
     histogramSize_(histogramSizeInitial),
-    inInitialStage_(awhBiasParams.eGrowth == eawhgrowthEXP_LINEAR),
-    equilibrateHistogram_(awhBiasParams.equilibrateHistogram),
+    inInitialStage_(awhBiasParams.growthType() == AwhHistogramGrowthType::ExponentialLinear),
+    equilibrateHistogram_(awhBiasParams.equilibrateHistogram()),
     logScaledSampleWeight_(0),
     maxLogScaledSampleWeight_(0),
     havePrintedAboutCovering_(false)
@@ -150,12 +150,12 @@ namespace
  * \param[in] pointStates  The state of the bias points.
  * \returns true if the histogram is equilibrated.
  */
-bool histogramIsEquilibrated(const std::vector<PointState>& pointStates)
+bool histogramIsEquilibrated(ArrayRef<const PointState> pointStates)
 {
     /* Get the total weight of the total weight histogram; needed for normalization. */
     double totalWeight     = 0;
     int    numTargetPoints = 0;
-    for (auto& pointState : pointStates)
+    for (const auto& pointState : pointStates)
     {
         if (!pointState.inTargetRegion())
         {
@@ -177,7 +177,7 @@ bool histogramIsEquilibrated(const std::vector<PointState>& pointStates)
     /* Sum up weight of points that do or don't pass the check. */
     double equilibratedWeight    = 0;
     double notEquilibratedWeight = 0;
-    for (auto& pointState : pointStates)
+    for (const auto& pointState : pointStates)
     {
         double targetWeight  = pointState.target();
         double sampledWeight = pointState.weightSumTot() * inverseTotalWeight;
@@ -207,12 +207,12 @@ bool histogramIsEquilibrated(const std::vector<PointState>& pointStates)
 
 } // namespace
 
-double HistogramSize::newHistogramSize(const BiasParams&              params,
-                                       double                         t,
-                                       bool                           covered,
-                                       const std::vector<PointState>& pointStates,
-                                       ArrayRef<double>               weightsumCovering,
-                                       FILE*                          fplog)
+double HistogramSize::newHistogramSize(const BiasParams&          params,
+                                       double                     t,
+                                       bool                       covered,
+                                       ArrayRef<const PointState> pointStates,
+                                       ArrayRef<double>           weightsumCovering,
+                                       FILE*                      fplog)
 {
     double newHistogramSize;
     if (inInitialStage_)
@@ -232,8 +232,10 @@ double HistogramSize::newHistogramSize(const BiasParams&              params,
                 }
                 else if (!havePrintedAboutCovering_)
                 {
-                    fprintf(fplog, "%s covered but histogram not equilibrated at t = %g ps.\n",
-                            prefix.c_str(), t);
+                    fprintf(fplog,
+                            "%s covered but histogram not equilibrated at t = %g ps.\n",
+                            prefix.c_str(),
+                            t);
                     havePrintedAboutCovering_ = true; /* Just print once. */
                 }
             }
index 7d9313549cd8443ec0e042e722e1785c25b9c94f..f0c5725d33026d3587a347065b8b06d3bdc7bb3b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +64,7 @@ namespace gmx
 template<typename>
 class ArrayRef;
 struct AwhBiasStateHistory;
-struct AwhBiasParams;
+class AwhBiasParams;
 class BiasParams;
 class PointState;
 
@@ -122,12 +122,12 @@ public:
      * \param[in,out] fplog              Log file.
      * \returns the new histogram size.
      */
-    double newHistogramSize(const BiasParams&              params,
-                            double                         t,
-                            bool                           covered,
-                            const std::vector<PointState>& pointStates,
-                            ArrayRef<double>               weightsumCovering,
-                            FILE*                          fplog);
+    double newHistogramSize(const BiasParams&          params,
+                            double                     t,
+                            bool                       covered,
+                            ArrayRef<const PointState> pointStates,
+                            ArrayRef<double>           weightsumCovering,
+                            FILE*                      fplog);
 
     /*! \brief Restores the histogram size from history.
      *
index a893140b6b90249bf24bdf0c9525de2c7b5cf52e..fd4b5e9cb6235951915b85b74c0cf4e9a0a1f8a2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -417,17 +417,18 @@ public:
     {
         switch (params.eTarget)
         {
-            case eawhtargetCONSTANT: target_ = 1; break;
-            case eawhtargetCUTOFF:
+            case AwhTargetType::Constant: target_ = 1; break;
+            case AwhTargetType::Cutoff:
             {
                 double df = freeEnergy_ - freeEnergyCutoff;
                 target_   = 1 / (1 + std::exp(df));
                 break;
             }
-            case eawhtargetBOLTZMANN:
+            case AwhTargetType::Boltzmann:
                 target_ = std::exp(-params.temperatureScaleFactor * freeEnergy_);
                 break;
-            case eawhtargetLOCALBOLTZMANN: target_ = weightSumRef_; break;
+            case AwhTargetType::LocalBoltzmann: target_ = weightSumRef_; break;
+            default: GMX_RELEASE_ASSERT(false, "Unhandled enum");
         }
 
         /* All target types can be modulated by a constant factor. */
index 8a4345959ff76b1bdf582b4147c7cb2cb13f97de..9f256ddf91290c92a43e46dfe7cd4092e3e7ecec 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.
  */
+
 #include "gmxpre.h"
 
 #include "read_params.h"
 
+#include <algorithm>
+
 #include "gromacs/applied_forces/awh/awh.h"
 #include "gromacs/fileio/readinp.h"
 #include "gromacs/fileio/warninp.h"
@@ -55,7 +58,9 @@
 #include "gromacs/random/seed.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/iserializer.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringutil.h"
 
 namespace gmx
 {
 
-const char* eawhtarget_names[eawhtargetNR + 1] = { "constant", "cutoff", "boltzmann",
-                                                   "local-boltzmann", nullptr };
+const char* enumValueToString(AwhTargetType enumValue)
+{
+    constexpr gmx::EnumerationArray<AwhTargetType, const char*> awhTargetTypeNames = {
+        "constant", "cutoff", "boltzmann", "local-boltzmann"
+    };
+    return awhTargetTypeNames[enumValue];
+}
 
-const char* eawhgrowth_names[eawhgrowthNR + 1] = { "exp-linear", "linear", nullptr };
+const char* enumValueToString(AwhHistogramGrowthType enumValue)
+{
+    constexpr gmx::EnumerationArray<AwhHistogramGrowthType, const char*> awhHistogramGrowthTypeNames = {
+        "exp-linear", "linear"
+    };
+    return awhHistogramGrowthTypeNames[enumValue];
+}
 
-const char* eawhpotential_names[eawhpotentialNR + 1] = { "convolved", "umbrella", nullptr };
+const char* enumValueToString(AwhPotentialType enumValue)
+{
+    constexpr gmx::EnumerationArray<AwhPotentialType, const char*> awhPotentialTypeNames = {
+        "convolved", "umbrella"
+    };
+    return awhPotentialTypeNames[enumValue];
+}
 
-const char* eawhcoordprovider_names[eawhcoordproviderNR + 1] = { "pull", "fep-lambda", nullptr };
+const char* enumValueToString(AwhCoordinateProviderType enumValue)
+{
+    constexpr gmx::EnumerationArray<AwhCoordinateProviderType, const char*> awhCoordinateProviderTypeNames = {
+        "pull", "fep-lambda"
+    };
+    return awhCoordinateProviderTypeNames[enumValue];
+}
 
 namespace
 {
@@ -94,15 +122,14 @@ void checkMtsConsistency(const t_inputrec& inputrec, warninp_t wi)
 
     bool usesPull = false;
     bool usesFep  = false;
-    for (int b = 0; b < inputrec.awhParams->numBias; b++)
+    for (const auto& awhBiasParam : inputrec.awhParams->awhBiasParams())
     {
-        const auto& biasParams = inputrec.awhParams->awhBiasParams[b];
-        for (int d = 0; d < biasParams.ndim; d++)
+        for (const auto& dimParam : awhBiasParam.dimParams())
         {
-            switch (biasParams.dimParams[d].eCoordProvider)
+            switch (dimParam.coordinateProvider())
             {
-                case eawhcoordproviderPULL: usesPull = true; break;
-                case eawhcoordproviderFREE_ENERGY_LAMBDA: usesFep = true; break;
+                case AwhCoordinateProviderType::Pull: usesPull = true; break;
+                case AwhCoordinateProviderType::FreeEnergyLambda: usesFep = true; break;
                 default: GMX_RELEASE_ASSERT(false, "Unsupported coord provider");
             }
         }
@@ -121,7 +148,7 @@ void checkMtsConsistency(const t_inputrec& inputrec, warninp_t wi)
                       "computed at the slow MTS level");
     }
 
-    if (inputrec.awhParams->nstSampleCoord % inputrec.mtsLevels[awhMtsLevel].stepFactor != 0)
+    if (inputrec.awhParams->nstSampleCoord() % inputrec.mtsLevels[awhMtsLevel].stepFactor != 0)
     {
         warning_error(wi,
                       "With MTS applied to AWH, awh-nstsample should be a multiple of mts-factor");
@@ -137,82 +164,97 @@ void checkMtsConsistency(const t_inputrec& inputrec, warninp_t wi)
  * \param[in,out] wi         Struct for bookeeping warnings.
  */
 void checkPullDimParams(const std::string&   prefix,
-                        AwhDimParams*        dimParams,
+                        const AwhDimParams&  dimParams,
                         const pull_params_t& pull_params,
                         warninp_t            wi)
 {
-    if (dimParams->coordIndex < 0)
+    if (dimParams.coordinateIndex() < 0)
     {
         gmx_fatal(FARGS,
                   "Failed to read a valid coordinate index for %s-coord-index. "
                   "Note that the pull coordinate indexing starts at 1.",
                   prefix.c_str());
     }
-    if (dimParams->coordIndex >= pull_params.ncoord)
+    if (dimParams.coordinateIndex() >= pull_params.ncoord)
     {
         gmx_fatal(FARGS,
                   "The given AWH coordinate index (%d) is larger than the number of pull "
                   "coordinates (%d)",
-                  dimParams->coordIndex + 1, pull_params.ncoord);
+                  dimParams.coordinateIndex() + 1,
+                  pull_params.ncoord);
     }
-    if (pull_params.coord[dimParams->coordIndex].rate != 0)
+    if (pull_params.coord[dimParams.coordinateIndex()].rate != 0)
     {
         auto message = formatString(
                 "Setting pull-coord%d-rate (%g) is incompatible with AWH biasing this coordinate",
-                dimParams->coordIndex + 1, pull_params.coord[dimParams->coordIndex].rate);
+                dimParams.coordinateIndex() + 1,
+                pull_params.coord[dimParams.coordinateIndex()].rate);
         warning_error(wi, message);
     }
 
-    if (gmx_within_tol(dimParams->end - dimParams->origin, 0, GMX_REAL_EPS))
+    if (gmx_within_tol(dimParams.end() - dimParams.origin(), 0, GMX_REAL_EPS))
     {
         auto message = formatString(
                 "The given interval length given by %s-start (%g) and %s-end (%g) is zero. "
                 "This will result in only one point along this axis in the coordinate value grid.",
-                prefix.c_str(), dimParams->origin, prefix.c_str(), dimParams->end);
+                prefix.c_str(),
+                dimParams.origin(),
+                prefix.c_str(),
+                dimParams.end());
         warning(wi, message);
     }
 
-    if (dimParams->forceConstant <= 0)
+    if (dimParams.forceConstant() <= 0)
     {
         warning_error(wi, "The force AWH bias force constant should be > 0");
     }
 
     /* Grid params for each axis */
-    int eGeom = pull_params.coord[dimParams->coordIndex].eGeom;
+    PullGroupGeometry eGeom = pull_params.coord[dimParams.coordinateIndex()].eGeom;
 
     /* Check that the requested interval is in allowed range */
-    if (eGeom == epullgDIST)
+    if (eGeom == PullGroupGeometry::Distance)
     {
-        if (dimParams->origin < 0 || dimParams->end < 0)
+        if (dimParams.origin() < 0 || dimParams.end() < 0)
         {
             gmx_fatal(FARGS,
                       "%s-start (%g) or %s-end (%g) set to a negative value. With pull "
                       "geometry distance coordinate values are non-negative. "
                       "Perhaps you want to use geometry %s instead?",
-                      prefix.c_str(), dimParams->origin, prefix.c_str(), dimParams->end,
-                      EPULLGEOM(epullgDIR));
+                      prefix.c_str(),
+                      dimParams.origin(),
+                      prefix.c_str(),
+                      dimParams.end(),
+                      enumValueToString(PullGroupGeometry::Direction));
         }
     }
-    else if (eGeom == epullgANGLE || eGeom == epullgANGLEAXIS)
+    else if (eGeom == PullGroupGeometry::Angle || eGeom == PullGroupGeometry::AngleAxis)
     {
-        if (dimParams->origin < 0 || dimParams->end > 180)
+        if (dimParams.origin() < 0 || dimParams.end() > 180)
         {
             gmx_fatal(FARGS,
                       "%s-start (%g) and %s-end (%g) are outside of the allowed range "
                       "0 to 180 deg for pull geometries %s and %s ",
-                      prefix.c_str(), dimParams->origin, prefix.c_str(), dimParams->end,
-                      EPULLGEOM(epullgANGLE), EPULLGEOM(epullgANGLEAXIS));
+                      prefix.c_str(),
+                      dimParams.origin(),
+                      prefix.c_str(),
+                      dimParams.end(),
+                      enumValueToString(PullGroupGeometry::Angle),
+                      enumValueToString(PullGroupGeometry::AngleAxis));
         }
     }
-    else if (eGeom == epullgDIHEDRAL)
+    else if (eGeom == PullGroupGeometry::Dihedral)
     {
-        if (dimParams->origin < -180 || dimParams->end > 180)
+        if (dimParams.origin() < -180 || dimParams.end() > 180)
         {
             gmx_fatal(FARGS,
                       "%s-start (%g) and %s-end (%g) are outside of the allowed range "
                       "-180 to 180 deg for pull geometry %s. ",
-                      prefix.c_str(), dimParams->origin, prefix.c_str(), dimParams->end,
-                      EPULLGEOM(epullgDIHEDRAL));
+                      prefix.c_str(),
+                      dimParams.origin(),
+                      prefix.c_str(),
+                      dimParams.end(),
+                      enumValueToString(PullGroupGeometry::Dihedral));
         }
     }
 }
@@ -226,11 +268,11 @@ void checkPullDimParams(const std::string&   prefix,
  * \param[in] efep           This is the type of FEP calculation (efep enumerator).
  * \param[in,out] wi         Struct for bookeeping warnings.
  */
-void checkFepLambdaDimParams(const std::string&  prefix,
-                             const AwhDimParams* dimParams,
-                             const t_lambda*     lambdaParams,
-                             const int           efep,
-                             warninp_t           wi)
+void checkFepLambdaDimParams(const std::string&               prefix,
+                             const AwhDimParams&              dimParams,
+                             const t_lambda*                  lambdaParams,
+                             const FreeEnergyPerturbationType efep,
+                             warninp_t                        wi)
 {
     std::string opt;
 
@@ -247,49 +289,56 @@ void checkFepLambdaDimParams(const std::string&  prefix,
                   "When running AWH coupled to the free energy lambda state all lambda states "
                   "should be used as neighbors in order to get correct probabilities, i.e. "
                   "calc-lambda-neighbors (%d) must be %d.",
-                  lambdaParams->lambda_neighbors, -1);
+                  lambdaParams->lambda_neighbors,
+                  -1);
     }
 
-    if (efep == efepSLOWGROWTH || lambdaParams->delta_lambda != 0)
+    if (efep == FreeEnergyPerturbationType::SlowGrowth || lambdaParams->delta_lambda != 0)
     {
         gmx_fatal(FARGS,
                   "AWH coupled to the free energy lambda state is not compatible with slow-growth "
                   "and delta-lambda must be 0.");
     }
 
-    if (efep == efepEXPANDED)
+    if (efep == FreeEnergyPerturbationType::Expanded)
     {
         gmx_fatal(FARGS,
                   "AWH is not treated like other expanded ensemble methods. Do not use expanded.");
     }
 
-    if (dimParams->origin < 0)
+    if (dimParams.origin() < 0)
     {
         opt = prefix + "-start";
         gmx_fatal(FARGS,
                   "When running AWH coupled to the free energy lambda state the lower lambda state "
                   "for AWH, %s (%.0f), must be >= 0.",
-                  opt.c_str(), dimParams->origin);
+                  opt.c_str(),
+                  dimParams.origin());
     }
-    if (dimParams->end >= lambdaParams->n_lambda)
+    if (dimParams.end() >= lambdaParams->n_lambda)
     {
         opt = prefix + "-end";
         gmx_fatal(FARGS,
                   "When running AWH coupled to the free energy lambda state the upper lambda state "
                   "for AWH, %s (%.0f), must be < n_lambda (%d).",
-                  opt.c_str(), dimParams->origin, lambdaParams->n_lambda);
+                  opt.c_str(),
+                  dimParams.origin(),
+                  lambdaParams->n_lambda);
     }
-    if (gmx_within_tol(dimParams->end - dimParams->origin, 0, GMX_REAL_EPS))
+    if (gmx_within_tol(dimParams.end() - dimParams.origin(), 0, GMX_REAL_EPS))
     {
         auto message = formatString(
                 "The given interval length given by %s-start (%g) and %s-end (%g) is zero. "
                 "This will result in only one lambda point along this free energy lambda state "
                 "axis in the coordinate value grid.",
-                prefix.c_str(), dimParams->origin, prefix.c_str(), dimParams->end);
+                prefix.c_str(),
+                dimParams.origin(),
+                prefix.c_str(),
+                dimParams.end());
         warning(wi, message);
     }
 
-    if (dimParams->forceConstant != 0)
+    if (dimParams.forceConstant() != 0)
     {
         warning_error(
                 wi,
@@ -322,78 +371,6 @@ void checkFepLambdaDimDecouplingConsistency(const gmx_mtop_t& mtop, warninp_t wi
     }
 }
 
-/*! \brief
- * Read parameters of an AWH bias dimension.
- *
- * \param[in,out] inp        Input file entries.
- * \param[in] prefix         Prefix for dimension parameters.
- * \param[in,out] dimParams  AWH dimensional parameters.
- * \param[in,out] wi         Struct for bookeeping warnings.
- * \param[in] bComment       True if comments should be printed.
- */
-void readDimParams(std::vector<t_inpfile>* inp,
-                   const std::string&      prefix,
-                   AwhDimParams*           dimParams,
-                   warninp_t               wi,
-                   bool                    bComment)
-{
-    std::string opt;
-    if (bComment)
-    {
-        printStringNoNewline(
-                inp,
-                "The provider of the reaction coordinate, "
-                "currently only 'pull' and 'fep-lambda' (free energy lambda state) is supported");
-    }
-    opt                       = prefix + "-coord-provider";
-    dimParams->eCoordProvider = get_eeenum(inp, opt, eawhcoordprovider_names, wi);
-
-    if (bComment)
-    {
-        printStringNoNewline(inp, "The coordinate index for this dimension");
-    }
-    opt = prefix + "-coord-index";
-    int coordIndexInput;
-    coordIndexInput = get_eint(inp, opt, 1, wi);
-
-    /* The pull coordinate indices start at 1 in the input file, at 0 internally */
-    dimParams->coordIndex = coordIndexInput - 1;
-
-    if (bComment)
-    {
-        printStringNoNewline(inp, "Start and end values for each coordinate dimension");
-    }
-    opt               = prefix + "-start";
-    dimParams->origin = get_ereal(inp, opt, 0., wi);
-    opt               = prefix + "-end";
-    dimParams->end    = get_ereal(inp, opt, 0., wi);
-
-    if (bComment)
-    {
-        printStringNoNewline(
-                inp, "The force constant for this coordinate (kJ/mol/nm^2 or kJ/mol/rad^2)");
-    }
-    opt                      = prefix + "-force-constant";
-    dimParams->forceConstant = get_ereal(inp, opt, 0, wi);
-
-    if (bComment)
-    {
-        printStringNoNewline(inp, "Estimated diffusion constant (nm^2/ps, rad^2/ps or ps^-1)");
-    }
-    opt                  = prefix + "-diffusion";
-    dimParams->diffusion = get_ereal(inp, opt, 0, wi);
-
-    if (bComment)
-    {
-        printStringNoNewline(inp,
-                             "Diameter that needs to be sampled around a point before it is "
-                             "considered covered. In FEP dimensions the cover diameter is "
-                             "specified in lambda states.");
-    }
-    opt                      = prefix + "-cover-diameter";
-    dimParams->coverDiameter = get_ereal(inp, opt, 0, wi);
-}
-
 /*! \brief
  * Check the parameters of an AWH bias dimension.
  *
@@ -402,27 +379,27 @@ void readDimParams(std::vector<t_inpfile>* inp,
  * \param[in] ir             Input parameter struct.
  * \param[in,out] wi         Struct for bookeeping warnings.
  */
-void checkDimParams(const std::string& prefix, AwhDimParams* dimParams, const t_inputrec* ir, warninp_t wi)
+void checkDimParams(const std::string& prefix, const AwhDimParams& dimParams, const t_inputrec& ir, warninp_t wi)
 {
-    if (dimParams->eCoordProvider == eawhcoordproviderPULL)
+    if (dimParams.coordinateProvider() == AwhCoordinateProviderType::Pull)
     {
-        if (!ir->bPull)
+        if (!ir.bPull)
         {
             gmx_fatal(FARGS,
                       "AWH biasing along a pull dimension is only compatible with COM pulling "
                       "turned on");
         }
-        checkPullDimParams(prefix, dimParams, *ir->pull, wi);
+        checkPullDimParams(prefix, dimParams, *ir.pull, wi);
     }
-    else if (dimParams->eCoordProvider == eawhcoordproviderFREE_ENERGY_LAMBDA)
+    else if (dimParams.coordinateProvider() == AwhCoordinateProviderType::FreeEnergyLambda)
     {
-        if (ir->efep == efepNO)
+        if (ir.efep == FreeEnergyPerturbationType::No)
         {
             gmx_fatal(FARGS,
                       "AWH biasing along a free energy lambda state dimension is only compatible "
                       "with free energy turned on");
         }
-        checkFepLambdaDimParams(prefix, dimParams, ir->fepvals, ir->efep, wi);
+        checkFepLambdaDimParams(prefix, dimParams, ir.fepvals.get(), ir.efep, wi);
     }
     else
     {
@@ -432,127 +409,6 @@ void checkDimParams(const std::string& prefix, AwhDimParams* dimParams, const t_
     }
 }
 
-/*! \brief
- * Check consistency of input at the AWH bias level.
- *
- * \param[in]     awhBiasParams  AWH bias parameters.
- * \param[in,out] wi             Struct for bookkeeping warnings.
- */
-void checkInputConsistencyAwhBias(const AwhBiasParams& awhBiasParams, warninp_t wi)
-{
-    /* Covering diameter and sharing warning. */
-    for (int d = 0; d < awhBiasParams.ndim; d++)
-    {
-        double coverDiameter = awhBiasParams.dimParams[d].coverDiameter;
-        if (awhBiasParams.shareGroup <= 0 && coverDiameter > 0)
-        {
-            warning(wi,
-                    "The covering diameter is only relevant to set for bias sharing simulations.");
-        }
-    }
-}
-
-/*! \brief
- * Read parameters of an AWH bias.
- *
- * \param[in,out] inp            Input file entries.
- * \param[in,out] awhBiasParams  AWH dimensional parameters.
- * \param[in]     prefix         Prefix for bias parameters.
- * \param[in,out] wi             Struct for bookeeping warnings.
- * \param[in]     bComment       True if comments should be printed.
- */
-void readBiasParams(std::vector<t_inpfile>* inp,
-                    AwhBiasParams*          awhBiasParams,
-                    const std::string&      prefix,
-                    warninp_t               wi,
-                    bool                    bComment)
-{
-    if (bComment)
-    {
-        printStringNoNewline(inp, "Estimated initial PMF error (kJ/mol)");
-    }
-
-    std::string opt             = prefix + "-error-init";
-    awhBiasParams->errorInitial = get_ereal(inp, opt, 10, wi);
-
-    if (bComment)
-    {
-        printStringNoNewline(inp,
-                             "Growth rate of the reference histogram determining the bias update "
-                             "size: exp-linear or linear");
-    }
-    opt                    = prefix + "-growth";
-    awhBiasParams->eGrowth = get_eeenum(inp, opt, eawhgrowth_names, wi);
-
-    if (bComment)
-    {
-        printStringNoNewline(inp,
-                             "Start the simulation by equilibrating histogram towards the target "
-                             "distribution: no or yes");
-    }
-    opt                                 = prefix + "-equilibrate-histogram";
-    awhBiasParams->equilibrateHistogram = (get_eeenum(inp, opt, yesno_names, wi) != 0);
-
-    if (bComment)
-    {
-        printStringNoNewline(
-                inp, "Target distribution type: constant, cutoff, boltzmann or local-boltzmann");
-    }
-    opt                    = prefix + "-target";
-    awhBiasParams->eTarget = get_eeenum(inp, opt, eawhtarget_names, wi);
-
-    if (bComment)
-    {
-        printStringNoNewline(inp,
-                             "Boltzmann beta scaling factor for target distribution types "
-                             "'boltzmann' and 'boltzmann-local'");
-    }
-    opt                              = prefix + "-target-beta-scaling";
-    awhBiasParams->targetBetaScaling = get_ereal(inp, opt, 0, wi);
-
-    if (bComment)
-    {
-        printStringNoNewline(inp, "Free energy cutoff value for target distribution type 'cutoff'");
-    }
-    opt                         = prefix + "-target-cutoff";
-    awhBiasParams->targetCutoff = get_ereal(inp, opt, 0, wi);
-
-    if (bComment)
-    {
-        printStringNoNewline(inp, "Initialize PMF and target with user data: no or yes");
-    }
-    opt                      = prefix + "-user-data";
-    awhBiasParams->bUserData = get_eeenum(inp, opt, yesno_names, wi);
-
-    if (bComment)
-    {
-        printStringNoNewline(inp, "Group index to share the bias with, 0 means not shared");
-    }
-    opt                       = prefix + "-share-group";
-    awhBiasParams->shareGroup = get_eint(inp, opt, 0, wi);
-
-    if (bComment)
-    {
-        printStringNoNewline(inp, "Dimensionality of the coordinate");
-    }
-    opt                 = prefix + "-ndim";
-    awhBiasParams->ndim = get_eint(inp, opt, 0, wi);
-
-    /* Check this before starting to read the AWH dimension parameters. */
-    if (awhBiasParams->ndim <= 0 || awhBiasParams->ndim > c_biasMaxNumDim)
-    {
-        gmx_fatal(FARGS, "%s (%d) needs to be > 0 and at most %d\n", opt.c_str(),
-                  awhBiasParams->ndim, c_biasMaxNumDim);
-    }
-    snew(awhBiasParams->dimParams, awhBiasParams->ndim);
-    for (int d = 0; d < awhBiasParams->ndim; d++)
-    {
-        bComment              = bComment && d == 0;
-        std::string prefixdim = prefix + formatString("-dim%d", d + 1);
-        readDimParams(inp, prefixdim, &awhBiasParams->dimParams[d], wi, bComment);
-    }
-}
-
 /*! \brief
  * Check the parameters of an AWH bias.
  *
@@ -561,106 +417,135 @@ void readBiasParams(std::vector<t_inpfile>* inp,
  * \param[in]     ir             Input parameter struct.
  * \param[in,out] wi             Struct for bookeeping warnings.
  */
-void checkBiasParams(const AwhBiasParams* awhBiasParams, const std::string& prefix, const t_inputrec* ir, warninp_t wi)
+void checkBiasParams(const AwhBiasParams& awhBiasParams, const std::string& prefix, const t_inputrec& ir, warninp_t wi)
 {
     std::string opt = prefix + "-error-init";
-    if (awhBiasParams->errorInitial <= 0)
+    if (awhBiasParams.initialErrorEstimate() <= 0)
     {
         gmx_fatal(FARGS, "%s needs to be > 0.", opt.c_str());
     }
 
     opt = prefix + "-equilibrate-histogram";
-    if (awhBiasParams->equilibrateHistogram && awhBiasParams->eGrowth != eawhgrowthEXP_LINEAR)
+    if (awhBiasParams.equilibrateHistogram()
+        && awhBiasParams.growthType() != AwhHistogramGrowthType::ExponentialLinear)
     {
         auto message =
                 formatString("Option %s will only have an effect for histogram growth type '%s'.",
-                             opt.c_str(), EAWHGROWTH(eawhgrowthEXP_LINEAR));
+                             opt.c_str(),
+                             enumValueToString(AwhHistogramGrowthType::ExponentialLinear));
         warning(wi, message);
     }
 
-    if ((awhBiasParams->eTarget == eawhtargetLOCALBOLTZMANN)
-        && (awhBiasParams->eGrowth == eawhgrowthEXP_LINEAR))
+    if ((awhBiasParams.targetDistribution() == AwhTargetType::LocalBoltzmann)
+        && (awhBiasParams.growthType() == AwhHistogramGrowthType::ExponentialLinear))
     {
         auto message = formatString(
                 "Target type '%s' combined with histogram growth type '%s' is not "
                 "expected to give stable bias updates. You probably want to use growth type "
                 "'%s' instead.",
-                EAWHTARGET(eawhtargetLOCALBOLTZMANN), EAWHGROWTH(eawhgrowthEXP_LINEAR),
-                EAWHGROWTH(eawhgrowthLINEAR));
+                enumValueToString(AwhTargetType::LocalBoltzmann),
+                enumValueToString(AwhHistogramGrowthType::ExponentialLinear),
+                enumValueToString(AwhHistogramGrowthType::Linear));
         warning(wi, message);
     }
 
     opt = prefix + "-target-beta-scaling";
-    switch (awhBiasParams->eTarget)
+    switch (awhBiasParams.targetDistribution())
     {
-        case eawhtargetBOLTZMANN:
-        case eawhtargetLOCALBOLTZMANN:
-            if (awhBiasParams->targetBetaScaling < 0 || awhBiasParams->targetBetaScaling > 1)
+        case AwhTargetType::Boltzmann:
+        case AwhTargetType::LocalBoltzmann:
+            if (awhBiasParams.targetBetaScaling() < 0 || awhBiasParams.targetBetaScaling() > 1)
             {
-                gmx_fatal(FARGS, "%s = %g is not useful for target type %s.", opt.c_str(),
-                          awhBiasParams->targetBetaScaling, EAWHTARGET(awhBiasParams->eTarget));
+                gmx_fatal(FARGS,
+                          "%s = %g is not useful for target type %s.",
+                          opt.c_str(),
+                          awhBiasParams.targetBetaScaling(),
+                          enumValueToString(awhBiasParams.targetDistribution()));
             }
             break;
         default:
-            if (awhBiasParams->targetBetaScaling != 0)
+            if (awhBiasParams.targetBetaScaling() != 0)
             {
                 gmx_fatal(
                         FARGS,
                         "Value for %s (%g) set explicitly but will not be used for target type %s.",
-                        opt.c_str(), awhBiasParams->targetBetaScaling,
-                        EAWHTARGET(awhBiasParams->eTarget));
+                        opt.c_str(),
+                        awhBiasParams.targetBetaScaling(),
+                        enumValueToString(awhBiasParams.targetDistribution()));
             }
             break;
     }
 
     opt = prefix + "-target-cutoff";
-    switch (awhBiasParams->eTarget)
+    switch (awhBiasParams.targetDistribution())
     {
-        case eawhtargetCUTOFF:
-            if (awhBiasParams->targetCutoff <= 0)
+        case AwhTargetType::Cutoff:
+            if (awhBiasParams.targetCutoff() <= 0)
             {
-                gmx_fatal(FARGS, "%s = %g is not useful for target type %s.", opt.c_str(),
-                          awhBiasParams->targetCutoff, EAWHTARGET(awhBiasParams->eTarget));
+                gmx_fatal(FARGS,
+                          "%s = %g is not useful for target type %s.",
+                          opt.c_str(),
+                          awhBiasParams.targetCutoff(),
+                          enumValueToString(awhBiasParams.targetDistribution()));
             }
             break;
         default:
-            if (awhBiasParams->targetCutoff != 0)
+            if (awhBiasParams.targetCutoff() != 0)
             {
                 gmx_fatal(
                         FARGS,
                         "Value for %s (%g) set explicitly but will not be used for target type %s.",
-                        opt.c_str(), awhBiasParams->targetCutoff, EAWHTARGET(awhBiasParams->eTarget));
+                        opt.c_str(),
+                        awhBiasParams.targetCutoff(),
+                        enumValueToString(awhBiasParams.targetDistribution()));
             }
             break;
     }
 
     opt = prefix + "-share-group";
-    if (awhBiasParams->shareGroup < 0)
+    if (awhBiasParams.shareGroup() < 0)
     {
         warning_error(wi, "AWH bias share-group should be >= 0");
     }
 
     opt = prefix + "-ndim";
-    if (awhBiasParams->ndim <= 0 || awhBiasParams->ndim > c_biasMaxNumDim)
+    if (awhBiasParams.ndim() <= 0 || awhBiasParams.ndim() > c_biasMaxNumDim)
     {
-        gmx_fatal(FARGS, "%s (%d) needs to be > 0 and at most %d\n", opt.c_str(),
-                  awhBiasParams->ndim, c_biasMaxNumDim);
+        gmx_fatal(FARGS, "%s (%d) needs to be > 0 and at most %d\n", opt.c_str(), awhBiasParams.ndim(), c_biasMaxNumDim);
     }
-    if (awhBiasParams->ndim > 2)
+    if (awhBiasParams.ndim() > 2)
     {
         warning_note(wi,
                      "For awh-dim > 2 the estimate based on the diffusion and the initial error is "
                      "currently only a rough guideline."
                      " You should verify its usefulness for your system before production runs!");
     }
-    for (int d = 0; d < awhBiasParams->ndim; d++)
+    for (int d = 0; d < awhBiasParams.ndim(); d++)
     {
         std::string prefixdim = prefix + formatString("-dim%d", d + 1);
-        checkDimParams(prefixdim, &awhBiasParams->dimParams[d], ir, wi);
+        checkDimParams(prefixdim, awhBiasParams.dimParams()[d], ir, wi);
     }
+}
 
-    /* Check consistencies here that cannot be checked at read time at a lower level. */
-    checkInputConsistencyAwhBias(*awhBiasParams, wi);
+/*! \brief
+ * Check consistency of input at the AWH bias level.
+ *
+ * \param[in]     awhBiasParams  AWH bias parameters.
+ * \param[in,out] wi             Struct for bookkeeping warnings.
+ */
+void checkInputConsistencyAwhBias(const AwhBiasParams& awhBiasParams, warninp_t wi)
+{
+    /* Covering diameter and sharing warning. */
+    auto awhBiasDimensionParams = awhBiasParams.dimParams();
+    for (const auto& dimensionParam : awhBiasDimensionParams)
+    {
+        double coverDiameter = dimensionParam.coverDiameter();
+        if (awhBiasParams.shareGroup() <= 0 && coverDiameter > 0)
+        {
+            warning(wi,
+                    "The covering diameter is only relevant to set for bias sharing simulations.");
+        }
+    }
 }
 
 /*! \brief
@@ -675,36 +560,38 @@ void checkInputConsistencyAwh(const AwhParams& awhParams, warninp_t wi)
      * Check that we have a shared bias when requesting multisim sharing.
      */
     bool haveSharedBias = false;
-    for (int k1 = 0; k1 < awhParams.numBias; k1++)
+    auto awhBiasParams  = awhParams.awhBiasParams();
+    for (int k1 = 0; k1 < awhParams.numBias(); k1++)
     {
-        const AwhBiasParams& awhBiasParams1 = awhParams.awhBiasParams[k1];
+        const AwhBiasParams& awhBiasParams1 = awhBiasParams[k1];
 
-        if (awhBiasParams1.shareGroup > 0)
+        if (awhBiasParams1.shareGroup() > 0)
         {
             haveSharedBias = true;
         }
 
         /* k1 is the reference AWH, k2 is the AWH we compare with (can be equal to k1) */
-        for (int k2 = k1; k2 < awhParams.numBias; k2++)
+        for (int k2 = k1; k2 < awhParams.numBias(); k2++)
         {
-            for (int d1 = 0; d1 < awhBiasParams1.ndim; d1++)
+            const AwhBiasParams& awhBiasParams2 = awhBiasParams[k2];
+            const auto&          dimParams1     = awhBiasParams1.dimParams();
+            const auto&          dimParams2     = awhBiasParams2.dimParams();
+            for (int d1 = 0; d1 < gmx::ssize(dimParams1); d1++)
             {
-                if (awhBiasParams1.dimParams[d1].eCoordProvider == eawhcoordproviderFREE_ENERGY_LAMBDA)
+                if (dimParams1[d1].coordinateProvider() == AwhCoordinateProviderType::FreeEnergyLambda)
                 {
                     continue;
                 }
-                const AwhBiasParams& awhBiasParams2 = awhParams.awhBiasParams[k2];
-
                 /* d1 is the reference dimension of the reference AWH. d2 is the dim index of the AWH to compare with. */
-                for (int d2 = 0; d2 < awhBiasParams2.ndim; d2++)
+                for (int d2 = 0; d2 < gmx::ssize(dimParams2); d2++)
                 {
-                    if (awhBiasParams2.dimParams[d2].eCoordProvider == eawhcoordproviderFREE_ENERGY_LAMBDA)
+                    if (dimParams2[d2].coordinateProvider() == AwhCoordinateProviderType::FreeEnergyLambda)
                     {
                         continue;
                     }
                     /* Give an error if (d1, k1) is different from (d2, k2) but the pull coordinate is the same */
                     if ((d1 != d2 || k1 != k2)
-                        && (awhBiasParams1.dimParams[d1].coordIndex == awhBiasParams2.dimParams[d2].coordIndex))
+                        && (dimParams1[d1].coordinateIndex() == dimParams2[d2].coordinateIndex()))
                     {
                         char errormsg[STRLEN];
                         sprintf(errormsg,
@@ -712,7 +599,10 @@ void checkInputConsistencyAwh(const AwhParams& awhParams, warninp_t wi)
                                 "dimensions (awh%d-dim%d and awh%d-dim%d). "
                                 "If this is really what you want to do you will have to duplicate "
                                 "this pull coordinate.",
-                                awhBiasParams1.dimParams[d1].coordIndex + 1, k1 + 1, d1 + 1, k2 + 1,
+                                dimParams1[d1].coordinateIndex() + 1,
+                                k1 + 1,
+                                d1 + 1,
+                                k2 + 1,
                                 d2 + 1);
                         gmx_fatal(FARGS, "%s", errormsg);
                     }
@@ -721,7 +611,7 @@ void checkInputConsistencyAwh(const AwhParams& awhParams, warninp_t wi)
         }
     }
 
-    if (awhParams.shareBiasMultisim && !haveSharedBias)
+    if (awhParams.shareBiasMultisim() && !haveSharedBias)
     {
         warning(wi,
                 "Sharing of biases over multiple simulations is requested, but no bias is marked "
@@ -736,142 +626,354 @@ void checkInputConsistencyAwh(const AwhParams& awhParams, warninp_t wi)
                 "this (yet)");
     }
 }
+
 } // namespace
 
-AwhParams* readAwhParams(std::vector<t_inpfile>* inp, warninp_t wi)
+AwhDimParams::AwhDimParams(std::vector<t_inpfile>* inp, const std::string& prefix, warninp_t wi, bool bComment)
+{
+    std::string opt;
+    if (bComment)
+    {
+        printStringNoNewline(
+                inp,
+                "The provider of the reaction coordinate, "
+                "currently only 'pull' and 'fep-lambda' (free energy lambda state) is supported");
+    }
+
+    opt             = prefix + "-coord-provider";
+    eCoordProvider_ = getEnum<AwhCoordinateProviderType>(inp, opt.c_str(), wi);
+
+    if (bComment)
+    {
+        printStringNoNewline(inp, "The coordinate index for this dimension");
+    }
+    opt = prefix + "-coord-index";
+    int coordIndexInput;
+    coordIndexInput = get_eint(inp, opt, 1, wi);
+    if (coordIndexInput < 1)
+    {
+        gmx_fatal(FARGS,
+                  "Failed to read a valid coordinate index for %s. "
+                  "Note that the pull coordinate indexing starts at 1.",
+                  opt.c_str());
+    }
+
+    /* The pull coordinate indices start at 1 in the input file, at 0 internally */
+    coordIndex_ = coordIndexInput - 1;
+
+    if (bComment)
+    {
+        printStringNoNewline(inp, "Start and end values for each coordinate dimension");
+    }
+
+    opt     = prefix + "-start";
+    origin_ = get_ereal(inp, opt, 0., wi);
+
+    opt  = prefix + "-end";
+    end_ = get_ereal(inp, opt, 0., wi);
+
+    if (bComment)
+    {
+        printStringNoNewline(
+                inp, "The force constant for this coordinate (kJ/mol/nm^2 or kJ/mol/rad^2)");
+    }
+    opt            = prefix + "-force-constant";
+    forceConstant_ = get_ereal(inp, opt, 0, wi);
+
+    if (bComment)
+    {
+        printStringNoNewline(inp, "Estimated diffusion constant (nm^2/ps or rad^2/ps or ps^-1)");
+    }
+    opt                   = prefix + "-diffusion";
+    double diffusionValue = get_ereal(inp, opt, 0, wi);
+    if (diffusionValue <= 0)
+    {
+        const double diffusion_default = 1e-5;
+        auto         message           = formatString(
+                "%s not explicitly set by user. You can choose to use a default "
+                "value (%g nm^2/ps or rad^2/ps) but this may very well be "
+                "non-optimal for your system!",
+                opt.c_str(),
+                diffusion_default);
+        warning(wi, message);
+        diffusionValue = diffusion_default;
+    }
+    diffusion_ = diffusionValue;
+
+    if (bComment)
+    {
+        printStringNoNewline(inp,
+                             "Diameter that needs to be sampled around a point before it is "
+                             "considered covered. In FEP dimensions the cover diameter is "
+                             "specified in lambda states.");
+    }
+    opt            = prefix + "-cover-diameter";
+    coverDiameter_ = get_ereal(inp, opt, 0, wi);
+}
+
+AwhDimParams::AwhDimParams(ISerializer* serializer)
+{
+    GMX_RELEASE_ASSERT(serializer->reading(),
+                       "Can not use writing serializer for creating datastructure");
+    serializer->doEnumAsInt(&eCoordProvider_);
+    serializer->doInt(&coordIndex_);
+    serializer->doDouble(&origin_);
+    serializer->doDouble(&end_);
+    serializer->doDouble(&period_);
+    serializer->doDouble(&forceConstant_);
+    serializer->doDouble(&diffusion_);
+    serializer->doDouble(&coordValueInit_);
+    serializer->doDouble(&coverDiameter_);
+}
+
+void AwhDimParams::serialize(ISerializer* serializer)
+{
+    GMX_RELEASE_ASSERT(!serializer->reading(),
+                       "Can not use reading serializer for writing datastructure");
+    serializer->doEnumAsInt(&eCoordProvider_);
+    serializer->doInt(&coordIndex_);
+    serializer->doDouble(&origin_);
+    serializer->doDouble(&end_);
+    serializer->doDouble(&period_);
+    serializer->doDouble(&forceConstant_);
+    serializer->doDouble(&diffusion_);
+    serializer->doDouble(&coordValueInit_);
+    serializer->doDouble(&coverDiameter_);
+}
+
+AwhBiasParams::AwhBiasParams(std::vector<t_inpfile>* inp, const std::string& prefix, warninp_t wi, bool bComment)
+{
+    if (bComment)
+    {
+        printStringNoNewline(inp, "Estimated initial PMF error (kJ/mol)");
+    }
+
+    std::string opt = prefix + "-error-init";
+    errorInitial_   = get_ereal(inp, opt, 10, wi);
+
+    if (bComment)
+    {
+        printStringNoNewline(inp,
+                             "Growth rate of the reference histogram determining the bias update "
+                             "size: exp-linear or linear");
+    }
+    opt      = prefix + "-growth";
+    eGrowth_ = getEnum<AwhHistogramGrowthType>(inp, opt.c_str(), wi);
+
+    if (bComment)
+    {
+        printStringNoNewline(inp,
+                             "Start the simulation by equilibrating histogram towards the target "
+                             "distribution: no or yes");
+    }
+    opt                   = prefix + "-equilibrate-histogram";
+    equilibrateHistogram_ = (getEnum<Boolean>(inp, opt.c_str(), wi) != Boolean::No);
+
+    if (bComment)
+    {
+        printStringNoNewline(
+                inp, "Target distribution type: constant, cutoff, boltzmann or local-boltzmann");
+    }
+    opt      = prefix + "-target";
+    eTarget_ = getEnum<AwhTargetType>(inp, opt.c_str(), wi);
+
+    if (bComment)
+    {
+        printStringNoNewline(inp,
+                             "Boltzmann beta scaling factor for target distribution types "
+                             "'boltzmann' and 'boltzmann-local'");
+    }
+    opt                = prefix + "-target-beta-scaling";
+    targetBetaScaling_ = get_ereal(inp, opt, 0, wi);
+
+    if (bComment)
+    {
+        printStringNoNewline(inp, "Free energy cutoff value for target distribution type 'cutoff'");
+    }
+    opt           = prefix + "-target-cutoff";
+    targetCutoff_ = get_ereal(inp, opt, 0, wi);
+
+    if (bComment)
+    {
+        printStringNoNewline(inp, "Initialize PMF and target with user data: no or yes");
+    }
+    opt        = prefix + "-user-data";
+    bUserData_ = getEnum<Boolean>(inp, opt.c_str(), wi) != Boolean::No;
+
+    if (bComment)
+    {
+        printStringNoNewline(inp, "Group index to share the bias with, 0 means not shared");
+    }
+    opt         = prefix + "-share-group";
+    shareGroup_ = get_eint(inp, opt, 0, wi);
+
+    if (bComment)
+    {
+        printStringNoNewline(inp, "Dimensionality of the coordinate");
+    }
+    opt      = prefix + "-ndim";
+    int ndim = get_eint(inp, opt, 0, wi);
+
+    /* Check this before starting to read the AWH dimension parameters. */
+    if (ndim <= 0 || ndim > c_biasMaxNumDim)
+    {
+        gmx_fatal(FARGS, "%s (%d) needs to be > 0 and at most %d\n", opt.c_str(), ndim, c_biasMaxNumDim);
+    }
+    for (int d = 0; d < ndim; d++)
+    {
+        bComment              = bComment && d == 0;
+        std::string prefixdim = prefix + formatString("-dim%d", d + 1);
+        dimParams_.emplace_back(inp, prefixdim, wi, bComment);
+    }
+}
+
+AwhBiasParams::AwhBiasParams(ISerializer* serializer)
+{
+    GMX_RELEASE_ASSERT(serializer->reading(),
+                       "Can not use writing serializer to create datastructure");
+    serializer->doEnumAsInt(&eTarget_);
+    serializer->doDouble(&targetBetaScaling_);
+    serializer->doDouble(&targetCutoff_);
+    serializer->doEnumAsInt(&eGrowth_);
+    int temp = 0;
+    serializer->doInt(&temp);
+    bUserData_ = static_cast<bool>(temp);
+    serializer->doDouble(&errorInitial_);
+    int numDimensions = dimParams_.size();
+    serializer->doInt(&numDimensions);
+    serializer->doInt(&shareGroup_);
+    serializer->doBool(&equilibrateHistogram_);
+
+    for (int k = 0; k < numDimensions; k++)
+    {
+        dimParams_.emplace_back(serializer);
+    }
+    /* Check consistencies here that cannot be checked at read time at a lower level. */
+    checkInputConsistencyAwhBias(*this, nullptr);
+}
+
+void AwhBiasParams::serialize(ISerializer* serializer)
+{
+    GMX_RELEASE_ASSERT(!serializer->reading(),
+                       "Can not use reading serializer to write datastructure");
+    serializer->doEnumAsInt(&eTarget_);
+    serializer->doDouble(&targetBetaScaling_);
+    serializer->doDouble(&targetCutoff_);
+    serializer->doEnumAsInt(&eGrowth_);
+    int temp = static_cast<int>(bUserData_);
+    serializer->doInt(&temp);
+    serializer->doDouble(&errorInitial_);
+    int numDimensions = ndim();
+    serializer->doInt(&numDimensions);
+    serializer->doInt(&shareGroup_);
+    serializer->doBool(&equilibrateHistogram_);
+
+    for (int k = 0; k < numDimensions; k++)
+    {
+        dimParams_[k].serialize(serializer);
+    }
+}
+
+AwhParams::AwhParams(std::vector<t_inpfile>* inp, warninp_t wi)
 {
-    AwhParams* awhParams;
-    snew(awhParams, 1);
     std::string opt;
 
     /* Parameters common for all biases */
 
     printStringNoNewline(inp, "The way to apply the biasing potential: convolved or umbrella");
-    opt                   = "awh-potential";
-    awhParams->ePotential = get_eeenum(inp, opt, eawhpotential_names, wi);
+    opt            = "awh-potential";
+    potentialEnum_ = getEnum<AwhPotentialType>(inp, opt.c_str(), wi);
 
     printStringNoNewline(inp,
                          "The random seed used for sampling the umbrella center in the case of "
                          "umbrella type potential");
-    opt             = "awh-seed";
-    awhParams->seed = get_eint(inp, opt, -1, wi);
-    if (awhParams->seed == -1)
+    opt   = "awh-seed";
+    seed_ = get_eint(inp, opt, -1, wi);
+    if (seed_ == -1)
     {
-        awhParams->seed = static_cast<int>(gmx::makeRandomSeed());
-        fprintf(stderr, "Setting the AWH bias MC random seed to %" PRId64 "\n", awhParams->seed);
+        seed_ = static_cast<int>(gmx::makeRandomSeed());
+        fprintf(stderr, "Setting the AWH bias MC random seed to %" PRId64 "\n", seed_);
     }
 
     printStringNoNewline(inp, "Data output interval in number of steps");
-    opt               = "awh-nstout";
-    awhParams->nstOut = get_eint(inp, opt, 100000, wi);
+    opt     = "awh-nstout";
+    nstOut_ = get_eint(inp, opt, 100000, wi);
 
     printStringNoNewline(inp, "Coordinate sampling interval in number of steps");
-    opt                       = "awh-nstsample";
-    awhParams->nstSampleCoord = get_eint(inp, opt, 10, wi);
+    opt             = "awh-nstsample";
+    nstSampleCoord_ = get_eint(inp, opt, 10, wi);
 
     printStringNoNewline(inp, "Free energy and bias update interval in number of samples");
-    opt                                   = "awh-nsamples-update";
-    awhParams->numSamplesUpdateFreeEnergy = get_eint(inp, opt, 10, wi);
+    opt                         = "awh-nsamples-update";
+    numSamplesUpdateFreeEnergy_ = get_eint(inp, opt, 10, wi);
 
     printStringNoNewline(
             inp, "When true, biases with share-group>0 are shared between multiple simulations");
-    opt                          = "awh-share-multisim";
-    awhParams->shareBiasMultisim = (get_eeenum(inp, opt, yesno_names, wi) != 0);
+    opt                = "awh-share-multisim";
+    shareBiasMultisim_ = (getEnum<Boolean>(inp, opt.c_str(), wi) != Boolean::No);
 
     printStringNoNewline(inp, "The number of independent AWH biases");
-    opt                = "awh-nbias";
-    awhParams->numBias = get_eint(inp, opt, 1, wi);
+    opt         = "awh-nbias";
+    int numBias = get_eint(inp, opt, 1, wi);
     /* Check this before starting to read the AWH biases. */
-    if (awhParams->numBias <= 0)
+    if (numBias <= 0)
     {
         gmx_fatal(FARGS, "%s needs to be an integer > 0", opt.c_str());
     }
 
     /* Read the parameters specific to each AWH bias */
-    snew(awhParams->awhBiasParams, awhParams->numBias);
-
-    for (int k = 0; k < awhParams->numBias; k++)
+    for (int k = 0; k < numBias; k++)
     {
         bool        bComment  = (k == 0);
         std::string prefixawh = formatString("awh%d", k + 1);
-        readBiasParams(inp, &awhParams->awhBiasParams[k], prefixawh, wi, bComment);
+        awhBiasParams_.emplace_back(inp, prefixawh, wi, bComment);
     }
-
-    return awhParams;
+    checkInputConsistencyAwh(*this, wi);
 }
 
-void checkAwhParams(const AwhParams* awhParams, const t_inputrec* ir, warninp_t wi)
+AwhParams::AwhParams(ISerializer* serializer)
 {
-    std::string opt;
-
-    checkMtsConsistency(*ir, wi);
-
-    opt = "awh-nstout";
-    if (awhParams->nstOut <= 0)
-    {
-        auto message = formatString("Not writing AWH output with AWH (%s = %d) does not make sense",
-                                    opt.c_str(), awhParams->nstOut);
-        warning_error(wi, message);
-    }
-    /* This restriction can be removed by changing a flag of print_ebin() */
-    if (ir->nstenergy == 0 || awhParams->nstOut % ir->nstenergy != 0)
-    {
-        auto message = formatString("%s (%d) should be a multiple of nstenergy (%d)", opt.c_str(),
-                                    awhParams->nstOut, ir->nstenergy);
-        warning_error(wi, message);
-    }
-
-    opt = "awh-nsamples-update";
-    if (awhParams->numSamplesUpdateFreeEnergy <= 0)
-    {
-        warning_error(wi, opt + " needs to be an integer > 0");
-    }
-
-    bool haveFepLambdaDim = false;
-    for (int k = 0; k < awhParams->numBias; k++)
-    {
-        std::string prefixawh = formatString("awh%d", k + 1);
-        checkBiasParams(&awhParams->awhBiasParams[k], prefixawh, ir, wi);
-        /* Check if there is a FEP lambda dimension. */
-        for (int l = 0; l < awhParams->awhBiasParams[k].ndim; l++)
+    GMX_RELEASE_ASSERT(serializer->reading(),
+                       "Can not use writing serializer to read AWH parameters");
+    int numberOfBiases = awhBiasParams_.size();
+    serializer->doInt(&numberOfBiases);
+    serializer->doInt(&nstOut_);
+    serializer->doInt64(&seed_);
+    serializer->doInt(&nstSampleCoord_);
+    serializer->doInt(&numSamplesUpdateFreeEnergy_);
+    serializer->doEnumAsInt(&potentialEnum_);
+    serializer->doBool(&shareBiasMultisim_);
+
+    if (numberOfBiases > 0)
+    {
+        for (int k = 0; k < numberOfBiases; k++)
         {
-            if (awhParams->awhBiasParams[k].dimParams[l].eCoordProvider == eawhcoordproviderFREE_ENERGY_LAMBDA)
-            {
-                haveFepLambdaDim = true;
-                break;
-            }
+            awhBiasParams_.emplace_back(serializer);
         }
     }
+    checkInputConsistencyAwh(*this, nullptr);
+}
 
-    if (haveFepLambdaDim)
-    {
-        if (awhParams->nstSampleCoord % ir->nstcalcenergy != 0)
-        {
-            opt          = "awh-nstsample";
-            auto message = formatString(
-                    "%s (%d) should be a multiple of nstcalcenergy (%d) when using AWH for "
-                    "sampling an FEP lambda dimension",
-                    opt.c_str(), awhParams->nstSampleCoord, ir->nstcalcenergy);
-            warning_error(wi, message);
-        }
-        if (awhParams->ePotential != eawhpotentialUMBRELLA)
+void AwhParams::serialize(ISerializer* serializer)
+{
+    GMX_RELEASE_ASSERT(!serializer->reading(),
+                       "Can not use reading serializer to write AWH parameters");
+    int numberOfBiases = numBias();
+    serializer->doInt(&numberOfBiases);
+    serializer->doInt(&nstOut_);
+    serializer->doInt64(&seed_);
+    serializer->doInt(&nstSampleCoord_);
+    serializer->doInt(&numSamplesUpdateFreeEnergy_);
+    serializer->doEnumAsInt(&potentialEnum_);
+    serializer->doBool(&shareBiasMultisim_);
+
+    if (numberOfBiases > 0)
+    {
+        for (int k = 0; k < numberOfBiases; k++)
         {
-            opt          = "awh-potential";
-            auto message = formatString(
-                    "%s (%s) must be set to %s when using AWH for sampling an FEP lambda dimension",
-                    opt.c_str(), eawhpotential_names[awhParams->ePotential],
-                    eawhpotential_names[eawhpotentialUMBRELLA]);
-            warning_error(wi, message);
+            awhBiasParams_[k].serialize(serializer);
         }
     }
-
-    /* Do a final consistency check before returning */
-    checkInputConsistencyAwh(*awhParams, wi);
-
-    if (ir->init_step != 0)
-    {
-        warning_error(wi, "With AWH init-step should be 0");
-    }
 }
 
 /*! \brief
@@ -886,7 +988,7 @@ static double get_pull_coord_period(const t_pull_coord& pullCoordParams, const t
 {
     double period = 0;
 
-    if (pullCoordParams.eGeom == epullgDIR)
+    if (pullCoordParams.eGeom == PullGroupGeometry::Direction)
     {
         const real margin = 0.001;
         // Make dims periodic when the interval covers > 95%
@@ -904,7 +1006,8 @@ static double get_pull_coord_period(const t_pull_coord& pullCoordParams, const t
                     gmx_fatal(FARGS,
                               "The AWH interval (%f nm) for a pull coordinate is larger than the "
                               "box size (%f nm)",
-                              intervalLength, boxLength);
+                              intervalLength,
+                              boxLength);
                 }
 
                 if (intervalLength > periodicFraction * boxLength)
@@ -914,7 +1017,7 @@ static double get_pull_coord_period(const t_pull_coord& pullCoordParams, const t
             }
         }
     }
-    else if (pullCoordParams.eGeom == epullgDIHEDRAL)
+    else if (pullCoordParams.eGeom == PullGroupGeometry::Dihedral)
     {
         /* The dihedral angle is periodic in -180 to 180 deg */
         period = 360;
@@ -977,24 +1080,30 @@ static bool valueIsInInterval(double origin, double end, double period, double v
  * \param[in]     awhParams  AWH parameters.
  * \param[in,out] wi         Struct for bookeeping warnings.
  */
-static void checkInputConsistencyInterval(const AwhParams* awhParams, warninp_t wi)
+static void checkInputConsistencyInterval(const AwhParams& awhParams, warninp_t wi)
 {
-    for (int k = 0; k < awhParams->numBias; k++)
+    const auto& awhBiasParams = awhParams.awhBiasParams();
+    for (int k = 0; k < gmx::ssize(awhBiasParams); k++)
     {
-        AwhBiasParams* awhBiasParams = &awhParams->awhBiasParams[k];
-        for (int d = 0; d < awhBiasParams->ndim; d++)
+        const auto& dimParams = awhBiasParams[k].dimParams();
+        for (int d = 0; d < gmx::ssize(dimParams); d++)
         {
-            AwhDimParams* dimParams  = &awhBiasParams->dimParams[d];
-            int           coordIndex = dimParams->coordIndex;
-            double origin = dimParams->origin, end = dimParams->end, period = dimParams->period;
-            double coordValueInit = dimParams->coordValueInit;
+            int    coordIndex = dimParams[d].coordinateIndex();
+            double origin = dimParams[d].origin(), end = dimParams[d].end(),
+                   period         = dimParams[d].period();
+            double coordValueInit = dimParams[d].initialCoordinate();
 
             if ((period == 0) && (origin > end))
             {
                 gmx_fatal(FARGS,
                           "For the non-periodic pull coordinates awh%d-dim%d-start (%f) cannot be "
                           "larger than awh%d-dim%d-end (%f)",
-                          k + 1, d + 1, origin, k + 1, d + 1, end);
+                          k + 1,
+                          d + 1,
+                          origin,
+                          k + 1,
+                          d + 1,
+                          end);
             }
 
             /* Currently we assume symmetric periodic intervals, meaning we use [-period/2, period/2] as the reference interval.
@@ -1014,7 +1123,15 @@ static void checkInputConsistencyInterval(const AwhParams* awhParams, warninp_t
                           "values in between "
                           "minus half a period and plus half a period, i.e. in the interval [%.8g, "
                           "%.8g].",
-                          k + 1, d + 1, origin, k + 1, d + 1, end, period, -0.5 * period, 0.5 * period);
+                          k + 1,
+                          d + 1,
+                          origin,
+                          k + 1,
+                          d + 1,
+                          end,
+                          period,
+                          -0.5 * period,
+                          0.5 * period);
             }
 
             /* Warn if the pull initial coordinate value is not in the grid */
@@ -1027,7 +1144,14 @@ static void checkInputConsistencyInterval(const AwhParams* awhParams, warninp_t
                         "(%.8g). "
                         "This can lead to large initial forces pulling the coordinate towards the "
                         "sampling interval.",
-                        coordValueInit, coordIndex + 1, k + 1, d + 1, origin, k + 1, d + 1, end);
+                        coordValueInit,
+                        coordIndex + 1,
+                        k + 1,
+                        d + 1,
+                        origin,
+                        k + 1,
+                        d + 1,
+                        end);
                 warning(wi, message);
             }
         }
@@ -1051,28 +1175,31 @@ static void checkInputConsistencyInterval(const AwhParams* awhParams, warninp_t
 static void setStateDependentAwhPullDimParams(AwhDimParams*        dimParams,
                                               const int            biasIndex,
                                               const int            dimIndex,
-                                              const pull_params_t* pull_params,
+                                              const pull_params_t& pull_params,
                                               pull_t*              pull_work,
                                               const t_pbc&         pbc,
                                               const tensor&        compressibility,
                                               warninp_t            wi)
 {
-    const t_pull_coord& pullCoordParams = pull_params->coord[dimParams->coordIndex];
+    const t_pull_coord& pullCoordParams = pull_params.coord[dimParams->coordinateIndex()];
 
-    if (pullCoordParams.eGeom == epullgDIRPBC)
+    if (pullCoordParams.eGeom == PullGroupGeometry::DirectionPBC)
     {
         gmx_fatal(FARGS,
                   "AWH does not support pull geometry '%s'. "
                   "If the maximum distance between the groups is always "
                   "less than half the box size, "
                   "you can use geometry '%s' instead.",
-                  EPULLGEOM(epullgDIRPBC), EPULLGEOM(epullgDIR));
+                  enumValueToString(PullGroupGeometry::DirectionPBC),
+                  enumValueToString(PullGroupGeometry::Direction));
     }
 
-    dimParams->period = get_pull_coord_period(pullCoordParams, pbc, dimParams->end - dimParams->origin);
+    dimParams->setPeriod(
+            get_pull_coord_period(pullCoordParams, pbc, dimParams->end() - dimParams->origin()));
     // We would like to check for scaling, but we don't have the full inputrec available here
-    if (dimParams->period > 0
-        && !(pullCoordParams.eGeom == epullgANGLE || pullCoordParams.eGeom == epullgDIHEDRAL))
+    if (dimParams->period() > 0
+        && !(pullCoordParams.eGeom == PullGroupGeometry::Angle
+             || pullCoordParams.eGeom == PullGroupGeometry::Dihedral))
     {
         bool coordIsScaled = false;
         for (int d2 = 0; d2 < DIM; d2++)
@@ -1086,17 +1213,19 @@ static void setStateDependentAwhPullDimParams(AwhDimParams*        dimParams,
         {
             std::string mesg = gmx::formatString(
                     "AWH dimension %d of bias %d is periodic with pull geometry '%s', "
-                    "while you should are applying pressure scaling to the "
+                    "while you should be applying pressure scaling to the "
                     "corresponding box vector, this is not supported.",
-                    dimIndex + 1, biasIndex + 1, EPULLGEOM(pullCoordParams.eGeom));
+                    dimIndex + 1,
+                    biasIndex + 1,
+                    enumValueToString(pullCoordParams.eGeom));
             warning(wi, mesg.c_str());
         }
     }
 
     /* The initial coordinate value, converted to external user units. */
-    dimParams->coordValueInit = get_pull_coord_value(pull_work, dimParams->coordIndex, &pbc);
-
-    dimParams->coordValueInit *= pull_conversion_factor_internal2userinput(&pullCoordParams);
+    double initialCoordinate = get_pull_coord_value(pull_work, dimParams->coordinateIndex(), &pbc);
+    initialCoordinate *= pull_conversion_factor_internal2userinput(pullCoordParams);
+    dimParams->setInitialCoordinate(initialCoordinate);
 }
 
 void setStateDependentAwhParams(AwhParams*           awhParams,
@@ -1131,29 +1260,101 @@ void setStateDependentAwhParams(AwhParams*           awhParams,
     t_pbc pbc;
     set_pbc(&pbc, pbcType, box);
 
-    for (int k = 0; k < awhParams->numBias; k++)
+    auto awhBiasParams = awhParams->awhBiasParams();
+    for (int k = 0; k < awhParams->numBias(); k++)
     {
-        AwhBiasParams* awhBiasParams = &awhParams->awhBiasParams[k];
-        for (int d = 0; d < awhBiasParams->ndim; d++)
+        auto awhBiasDimensionParams = awhBiasParams[k].dimParams();
+        for (int d = 0; d < awhBiasParams[k].ndim(); d++)
         {
-            AwhDimParams* dimParams = &awhBiasParams->dimParams[d];
-            if (dimParams->eCoordProvider == eawhcoordproviderPULL)
+            AwhDimParams* dimParams = &awhBiasDimensionParams[d];
+            if (dimParams->coordinateProvider() == AwhCoordinateProviderType::Pull)
             {
-                setStateDependentAwhPullDimParams(dimParams, k, d, &pull_params, pull_work, pbc,
-                                                  compressibility, wi);
+                setStateDependentAwhPullDimParams(
+                        dimParams, k, d, pull_params, pull_work, pbc, compressibility, wi);
             }
             else
             {
-                dimParams->coordValueInit = initLambda;
+                dimParams->setInitialCoordinate(initLambda);
                 checkFepLambdaDimDecouplingConsistency(mtop, wi);
             }
         }
     }
-    checkInputConsistencyInterval(awhParams, wi);
+    checkInputConsistencyInterval(*awhParams, wi);
 
     /* Register AWH as external potential with pull (for AWH dimensions that use pull as
      * reaction coordinate provider) to check consistency. */
     Awh::registerAwhWithPull(*awhParams, pull_work);
 }
 
+void checkAwhParams(const AwhParams& awhParams, const t_inputrec& ir, warninp_t wi)
+{
+    std::string opt;
+    checkMtsConsistency(ir, wi);
+
+    opt = "awh-nstout";
+    if (awhParams.nstout() <= 0)
+    {
+        auto message = formatString("Not writing AWH output with AWH (%s = %d) does not make sense",
+                                    opt.c_str(),
+                                    awhParams.nstout());
+        warning_error(wi, message);
+    }
+    /* This restriction can be removed by changing a flag of print_ebin() */
+    if (ir.nstenergy == 0 || awhParams.nstout() % ir.nstenergy != 0)
+    {
+        auto message = formatString(
+                "%s (%d) should be a multiple of nstenergy (%d)", opt.c_str(), awhParams.nstout(), ir.nstenergy);
+        warning_error(wi, message);
+    }
+
+    opt = "awh-nsamples-update";
+    if (awhParams.numSamplesUpdateFreeEnergy() <= 0)
+    {
+        warning_error(wi, opt + " needs to be an integer > 0");
+    }
+
+    bool       haveFepLambdaDim = false;
+    const auto awhBiasParams    = awhParams.awhBiasParams();
+    for (int k = 0; k < awhParams.numBias() && !haveFepLambdaDim; k++)
+    {
+        std::string prefixawh = formatString("awh%d", k + 1);
+        checkBiasParams(awhBiasParams[k], prefixawh, ir, wi);
+        /* Check if there is a FEP lambda dimension. */
+        const auto dimParams = awhBiasParams[k].dimParams();
+        haveFepLambdaDim = std::any_of(dimParams.begin(), dimParams.end(), [](const auto& dimParam) {
+            return dimParam.coordinateProvider() == AwhCoordinateProviderType::FreeEnergyLambda;
+        });
+    }
+
+    if (haveFepLambdaDim)
+    {
+        if (awhParams.nstSampleCoord() % ir.nstcalcenergy != 0)
+        {
+            opt          = "awh-nstsample";
+            auto message = formatString(
+                    "%s (%d) should be a multiple of nstcalcenergy (%d) when using AWH for "
+                    "sampling an FEP lambda dimension",
+                    opt.c_str(),
+                    awhParams.nstSampleCoord(),
+                    ir.nstcalcenergy);
+            warning_error(wi, message);
+        }
+        if (awhParams.potential() != AwhPotentialType::Umbrella)
+        {
+            opt          = "awh-potential";
+            auto message = formatString(
+                    "%s (%s) must be set to %s when using AWH for sampling an FEP lambda dimension",
+                    opt.c_str(),
+                    enumValueToString(awhParams.potential()),
+                    enumValueToString(AwhPotentialType::Umbrella));
+            warning_error(wi, message);
+        }
+    }
+
+    if (ir.init_step != 0)
+    {
+        warning_error(wi, "With AWH init-step should be 0");
+    }
+}
+
 } // namespace gmx
index bb1cd63fa9cdd5289d33125ff266c1ad16cda8bd..22247ae48065f2032f2b99b6a286719026d6e606 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,23 +59,17 @@ enum class PbcType : int;
 
 namespace gmx
 {
-struct AwhParams;
 
-/*! \brief Allocate and initialize the AWH parameters with values from the input file.
- *
- * \param[in,out] inp          Input file entries.
- * \param[in,out] wi           Struct for bookeeping warnings.
- * \returns AWH parameters.
- */
-AwhParams* readAwhParams(std::vector<t_inpfile>* inp, warninp_t wi);
+class AwhParams;
+class ISerializer;
 
 /*! \brief Check the AWH parameters.
  *
- * \param[in,out] awhParams    The AWH parameters.
+ * \param[in]     awhParams    The AWH parameters.
  * \param[in]     inputrec     Input parameter struct.
  * \param[in,out] wi           Struct for bookeeping warnings.
  */
-void checkAwhParams(const AwhParams* awhParams, const t_inputrec* inputrec, warninp_t wi);
+void checkAwhParams(const AwhParams& awhParams, const t_inputrec& inputrec, warninp_t wi);
 
 
 /*! \brief
diff --git a/src/gromacs/applied_forces/awh/tests/.clang-tidy b/src/gromacs/applied_forces/awh/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index bbce544ace5c1b3c58847fedf4216b5b49245b88..864dcabab884eb39718c6bb31f948cd75b9a7feb 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2017,2020, by the GROMACS development team, led by
+# Copyright (c) 2017,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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(AwhTest awh-test
     CPP_SOURCE_FILES
+        awh_setup.cpp
         bias.cpp
        biasgrid.cpp
         biasstate.cpp
diff --git a/src/gromacs/applied_forces/awh/tests/awh_setup.cpp b/src/gromacs/applied_forces/awh/tests/awh_setup.cpp
new file mode 100644 (file)
index 0000000..edb67b5
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 "awh_setup.h"
+
+#include <cmath>
+
+#include <memory>
+#include <tuple>
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gmock/gmock-matchers.h>
+#include <gtest/gtest.h>
+
+#include "gromacs/applied_forces/awh/bias.h"
+#include "gromacs/applied_forces/awh/correlationgrid.h"
+#include "gromacs/applied_forces/awh/pointstate.h"
+#include "gromacs/mdtypes/awh_params.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/inmemoryserializer.h"
+#include "gromacs/utility/stringutil.h"
+
+#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
+
+namespace gmx
+{
+
+namespace test
+{
+
+using ::testing::Eq;
+using ::testing::Pointwise;
+
+std::vector<char> awhDimParamSerialized(AwhCoordinateProviderType inputCoordinateProvider,
+                                        int                       inputCoordIndex,
+                                        double                    inputOrigin,
+                                        double                    inputEnd,
+                                        double                    inputPeriod,
+                                        double                    inputDiffusion)
+{
+    AwhCoordinateProviderType eCoordProvider = inputCoordinateProvider;
+    int                       coordIndex     = inputCoordIndex;
+    double                    forceConstant  = 10;
+    double                    period         = inputPeriod;
+    double                    diffusion      = inputDiffusion;
+    double                    origin         = inputOrigin;
+    double                    end            = inputEnd;
+    double                    coordValueInit = inputOrigin;
+    double                    coverDiameter  = 0;
+
+    gmx::InMemorySerializer serializer;
+    serializer.doEnumAsInt(&eCoordProvider);
+    serializer.doInt(&coordIndex);
+    serializer.doDouble(&origin);
+    serializer.doDouble(&end);
+    serializer.doDouble(&period);
+    serializer.doDouble(&forceConstant);
+    serializer.doDouble(&diffusion);
+    serializer.doDouble(&coordValueInit);
+    serializer.doDouble(&coverDiameter);
+    return serializer.finishAndGetBuffer();
+}
+
+/*! \internal \brief
+ * Prepare a memory buffer with serialized AwhBiasParams.
+ *
+ * \param[in] eawhgrowth Way to grow potential.
+ * \param[in] beta Value for 1/(kB*T).
+ * \param[in] inputErrorScaling Factor for initial error scaling.
+ * \param[in] dimensionParameterBuffers Buffers containing the dimension parameters.
+ * \param[in] inputUserData If there is a user provided PMF estimate.
+ */
+static std::vector<char> awhBiasParamSerialized(AwhHistogramGrowthType            eawhgrowth,
+                                                double                            beta,
+                                                double                            inputErrorScaling,
+                                                ArrayRef<const std::vector<char>> dimensionParameterBuffers,
+                                                bool                              inputUserData)
+{
+    int                    ndim                 = dimensionParameterBuffers.size();
+    AwhTargetType          eTarget              = AwhTargetType::Constant;
+    double                 targetBetaScaling    = 0;
+    double                 targetCutoff         = 0;
+    AwhHistogramGrowthType eGrowth              = eawhgrowth;
+    bool                   bUserData            = inputUserData;
+    double                 errorInitial         = inputErrorScaling / beta;
+    int                    shareGroup           = 0;
+    bool                   equilibrateHistogram = false;
+
+    gmx::InMemorySerializer serializer;
+    serializer.doEnumAsInt(&eTarget);
+    serializer.doDouble(&targetBetaScaling);
+    serializer.doDouble(&targetCutoff);
+    serializer.doEnumAsInt(&eGrowth);
+    int temp = static_cast<int>(bUserData);
+    serializer.doInt(&temp);
+    serializer.doDouble(&errorInitial);
+    serializer.doInt(&ndim);
+    serializer.doInt(&shareGroup);
+    serializer.doBool(&equilibrateHistogram);
+
+    auto awhDimBuffer  = awhDimParamSerialized();
+    auto awhBiasBuffer = serializer.finishAndGetBuffer();
+    for (const auto& dimParamBuffer : dimensionParameterBuffers)
+    {
+        awhBiasBuffer.insert(awhBiasBuffer.end(), dimParamBuffer.begin(), dimParamBuffer.end());
+    }
+    return awhBiasBuffer;
+}
+
+/*! \internal \brief
+ * Prepare a memory buffer with serialized AwhParams.
+ *
+ * \param[in] eawhgrowth Way to grow potential.
+ * \param[in] eawhpotential Which potential to use.
+ * \param[in] beta Value for 1/(kB*T).
+ * \param[in] inputErrorScaling Factor for initial error scaling.
+ * \param[in] inputSeed Seed value to use.
+ * \param[in] dimensionParameterBuffers Buffers containing the dimension parameters.
+ * \param[in] inputUserData If there is a user provided PMF estimate.
+ */
+static std::vector<char> awhParamSerialized(AwhHistogramGrowthType            eawhgrowth,
+                                            AwhPotentialType                  eawhpotential,
+                                            double                            beta,
+                                            double                            inputErrorScaling,
+                                            int64_t                           inputSeed,
+                                            ArrayRef<const std::vector<char>> dimensionParameterBuffers,
+                                            bool                              inputUserData)
+{
+    int              numBias                    = 1;
+    int64_t          seed                       = inputSeed;
+    int              nstOut                     = 0;
+    int              nstSampleCoord             = 1;
+    int              numSamplesUpdateFreeEnergy = 10;
+    AwhPotentialType ePotential                 = eawhpotential;
+    bool             shareBiasMultisim          = false;
+
+    gmx::InMemorySerializer serializer;
+    serializer.doInt(&numBias);
+    serializer.doInt(&nstOut);
+    serializer.doInt64(&seed);
+    serializer.doInt(&nstSampleCoord);
+    serializer.doInt(&numSamplesUpdateFreeEnergy);
+    serializer.doEnumAsInt(&ePotential);
+    serializer.doBool(&shareBiasMultisim);
+
+    auto awhParamBuffer = serializer.finishAndGetBuffer();
+    auto awhBiasBuffer  = awhBiasParamSerialized(
+            eawhgrowth, beta, inputErrorScaling, dimensionParameterBuffers, inputUserData);
+
+    awhParamBuffer.insert(awhParamBuffer.end(), awhBiasBuffer.begin(), awhBiasBuffer.end());
+
+    return awhParamBuffer;
+}
+
+AwhTestParameters::AwhTestParameters(ISerializer* serializer) : awhParams(serializer) {}
+/*! \brief
+ * Helper function to set up the C-style AWH parameters for the test.
+ *
+ * Builds the test input data from serialized data.
+ */
+AwhTestParameters getAwhTestParameters(AwhHistogramGrowthType            eawhgrowth,
+                                       AwhPotentialType                  eawhpotential,
+                                       ArrayRef<const std::vector<char>> dimensionParameterBuffers,
+                                       bool                              inputUserData,
+                                       double                            beta,
+                                       bool                              useAwhFep,
+                                       double                            inputErrorScaling,
+                                       int                               numFepLambdaStates)
+{
+    double  convFactor = 1;
+    double  k          = 1000;
+    int64_t seed       = 93471803;
+
+    auto awhParamBuffer = awhParamSerialized(
+            eawhgrowth, eawhpotential, beta, inputErrorScaling, seed, dimensionParameterBuffers, inputUserData);
+    gmx::InMemoryDeserializer deserializer(awhParamBuffer, false);
+    AwhTestParameters         params(&deserializer);
+
+    params.beta = beta;
+
+    if (useAwhFep)
+    {
+        params.dimParams.emplace_back(DimParams::fepLambdaDimParams(numFepLambdaStates, params.beta));
+    }
+    else
+    {
+        params.dimParams.emplace_back(DimParams::pullDimParams(convFactor, k, params.beta));
+    }
+    return params;
+}
+
+TEST(SerializationTest, CanSerializeDimParams)
+{
+    auto                      awhDimBuffer = awhDimParamSerialized();
+    gmx::InMemoryDeserializer deserializer(awhDimBuffer, false);
+    AwhDimParams              awhDimParams(&deserializer);
+    EXPECT_EQ(awhDimParams.coordinateProvider(), AwhCoordinateProviderType::Pull);
+    EXPECT_EQ(awhDimParams.coordinateIndex(), 0);
+    EXPECT_FLOAT_EQ(awhDimParams.forceConstant(), 10);
+    EXPECT_FLOAT_EQ(awhDimParams.period(), 0);
+    EXPECT_FLOAT_EQ(awhDimParams.diffusion(), 0.34690997);
+    EXPECT_FLOAT_EQ(awhDimParams.origin(), 0.5);
+    EXPECT_FLOAT_EQ(awhDimParams.end(), 1.5);
+    EXPECT_FLOAT_EQ(awhDimParams.initialCoordinate(), awhDimParams.origin());
+    EXPECT_FLOAT_EQ(awhDimParams.coverDiameter(), 0);
+
+    gmx::InMemorySerializer serializer;
+    awhDimParams.serialize(&serializer);
+    EXPECT_THAT(awhDimBuffer, Pointwise(Eq(), serializer.finishAndGetBuffer()));
+}
+
+TEST(SerializationTest, CanSerializeBiasParams)
+{
+    auto awhDimBuffer   = awhDimParamSerialized();
+    auto awhDimArrayRef = gmx::arrayRefFromArray(&awhDimBuffer, 1);
+    auto awhBiasBuffer  = awhBiasParamSerialized(
+            AwhHistogramGrowthType::ExponentialLinear, 0.4, 0.5, awhDimArrayRef, false);
+    gmx::InMemoryDeserializer deserializer(awhBiasBuffer, false);
+    AwhBiasParams             awhBiasParams(&deserializer);
+    EXPECT_EQ(awhBiasParams.ndim(), 1);
+    EXPECT_EQ(awhBiasParams.targetDistribution(), AwhTargetType::Constant);
+    EXPECT_FLOAT_EQ(awhBiasParams.targetBetaScaling(), 0);
+    EXPECT_FLOAT_EQ(awhBiasParams.targetCutoff(), 0);
+    EXPECT_EQ(awhBiasParams.growthType(), AwhHistogramGrowthType::ExponentialLinear);
+    EXPECT_EQ(awhBiasParams.userPMFEstimate(), 0);
+    EXPECT_FLOAT_EQ(awhBiasParams.initialErrorEstimate(), 0.5 / 0.4);
+    EXPECT_EQ(awhBiasParams.shareGroup(), 0);
+    EXPECT_EQ(awhBiasParams.equilibrateHistogram(), false);
+    const auto& awhDimParams = awhBiasParams.dimParams()[0];
+    EXPECT_EQ(awhDimParams.coordinateProvider(), AwhCoordinateProviderType::Pull);
+    EXPECT_EQ(awhDimParams.coordinateIndex(), 0);
+    EXPECT_FLOAT_EQ(awhDimParams.forceConstant(), 10);
+    EXPECT_FLOAT_EQ(awhDimParams.period(), 0);
+    EXPECT_FLOAT_EQ(awhDimParams.diffusion(), 0.34690997);
+    EXPECT_FLOAT_EQ(awhDimParams.origin(), 0.5);
+    EXPECT_FLOAT_EQ(awhDimParams.end(), 1.5);
+    EXPECT_FLOAT_EQ(awhDimParams.initialCoordinate(), awhDimParams.origin());
+    EXPECT_FLOAT_EQ(awhDimParams.coverDiameter(), 0);
+
+    gmx::InMemorySerializer serializer;
+    awhBiasParams.serialize(&serializer);
+    EXPECT_THAT(awhBiasBuffer, Pointwise(Eq(), serializer.finishAndGetBuffer()));
+}
+
+TEST(SerializationTest, CanSerializeAwhParams)
+{
+    auto awhDimBuffer   = awhDimParamSerialized();
+    auto awhDimArrayRef = gmx::arrayRefFromArray(&awhDimBuffer, 1);
+    auto awhParamBuffer = awhParamSerialized(
+            AwhHistogramGrowthType::ExponentialLinear, AwhPotentialType::Convolved, 0.4, 0.5, 1337, awhDimArrayRef, false);
+    gmx::InMemoryDeserializer deserializer(awhParamBuffer, false);
+    AwhParams                 awhParams(&deserializer);
+    EXPECT_EQ(awhParams.numBias(), 1);
+    EXPECT_EQ(awhParams.seed(), 1337);
+    EXPECT_EQ(awhParams.nstout(), 0);
+    EXPECT_EQ(awhParams.nstSampleCoord(), 1);
+    EXPECT_EQ(awhParams.numSamplesUpdateFreeEnergy(), 10);
+    EXPECT_EQ(awhParams.potential(), AwhPotentialType::Convolved);
+    EXPECT_EQ(awhParams.shareBiasMultisim(), false);
+    const auto& awhBiasParams = awhParams.awhBiasParams()[0];
+    EXPECT_EQ(awhBiasParams.ndim(), 1);
+    EXPECT_EQ(awhBiasParams.targetDistribution(), AwhTargetType::Constant);
+    EXPECT_FLOAT_EQ(awhBiasParams.targetBetaScaling(), 0);
+    EXPECT_FLOAT_EQ(awhBiasParams.targetCutoff(), 0);
+    EXPECT_EQ(awhBiasParams.growthType(), AwhHistogramGrowthType::ExponentialLinear);
+    EXPECT_EQ(awhBiasParams.userPMFEstimate(), 0);
+    EXPECT_FLOAT_EQ(awhBiasParams.initialErrorEstimate(), 0.5 / 0.4);
+    EXPECT_EQ(awhBiasParams.shareGroup(), 0);
+    EXPECT_EQ(awhBiasParams.equilibrateHistogram(), false);
+    const auto& awhDimParams = awhBiasParams.dimParams()[0];
+    EXPECT_EQ(awhDimParams.coordinateProvider(), AwhCoordinateProviderType::Pull);
+    EXPECT_EQ(awhDimParams.coordinateIndex(), 0);
+    EXPECT_FLOAT_EQ(awhDimParams.forceConstant(), 10);
+    EXPECT_FLOAT_EQ(awhDimParams.period(), 0);
+    EXPECT_FLOAT_EQ(awhDimParams.diffusion(), 0.34690997);
+    EXPECT_FLOAT_EQ(awhDimParams.origin(), 0.5);
+    EXPECT_FLOAT_EQ(awhDimParams.end(), 1.5);
+    EXPECT_FLOAT_EQ(awhDimParams.initialCoordinate(), awhDimParams.origin());
+    EXPECT_FLOAT_EQ(awhDimParams.coverDiameter(), 0);
+
+    gmx::InMemorySerializer serializer;
+    awhParams.serialize(&serializer);
+    EXPECT_THAT(awhParamBuffer, Pointwise(Eq(), serializer.finishAndGetBuffer()));
+}
+
+} // namespace test
+} // namespace gmx
diff --git a/src/gromacs/applied_forces/awh/tests/awh_setup.h b/src/gromacs/applied_forces/awh/tests/awh_setup.h
new file mode 100644 (file)
index 0000000..18bd4be
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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_AWH_TEST_SETUP_H
+#define GMX_AWH_TEST_SETUP_H
+
+#include "gmxpre.h"
+
+#include <memory>
+#include <vector>
+
+#include "gromacs/applied_forces/awh/bias.h"
+#include "gromacs/mdtypes/awh_params.h"
+
+namespace gmx
+{
+
+template<typename>
+class ArrayRef;
+
+namespace test
+{
+
+/*! \internal \brief
+ * Prepare a memory buffer with serialized AwhDimParams.
+ */
+std::vector<char> awhDimParamSerialized(
+        AwhCoordinateProviderType inputCoordinateProvider = AwhCoordinateProviderType::Pull,
+        int                       inputCoordIndex         = 0,
+        double                    inputOrigin             = 0.5,
+        double                    inputEnd                = 1.5,
+        double                    inputPeriod             = 0,
+        // Correction for removal of GaussianGeometryFactor/2 in histogram size
+        double inputDiffusion = 0.1 / (0.144129616073222 * 2));
+
+/*! \internal \brief
+ * Struct that gathers all input for setting up and using a Bias
+ */
+struct AwhTestParameters
+{
+    explicit AwhTestParameters(ISerializer* serializer);
+    //! Move constructor
+    AwhTestParameters(AwhTestParameters&& o) noexcept :
+        beta(o.beta),
+        awhParams(std::move(o.awhParams)),
+        dimParams(std::move(o.dimParams))
+    {
+    }
+    //! 1/(kB*T).
+    double beta;
+
+    //! AWH parameters, this is the struct to actually use.
+    AwhParams awhParams;
+    //! Dimension parameters for setting up Bias.
+    std::vector<DimParams> dimParams;
+};
+
+/*! \brief
+ * Helper function to set up the C-style AWH parameters for the test.
+ *
+ * Builds the test input data from serialized data.
+ */
+AwhTestParameters getAwhTestParameters(AwhHistogramGrowthType            eawhgrowth,
+                                       AwhPotentialType                  eawhpotential,
+                                       ArrayRef<const std::vector<char>> dimensionParameterBuffers,
+                                       bool                              inputUserData,
+                                       double                            beta,
+                                       bool                              useAwhFep,
+                                       double                            inputErrorScaling,
+                                       int                               numFepLambdaStates);
+
+} // namespace test
+} // namespace gmx
+
+#endif
index a0f8aae73531ea71382916a301088e4511016785..880ae18f90af618a3940dbc3695124309101a6a9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <gmock/gmock.h>
+#include <gmock/gmock-matchers.h>
 #include <gtest/gtest.h>
 
 #include "gromacs/applied_forces/awh/correlationgrid.h"
 #include "gromacs/applied_forces/awh/pointstate.h"
 #include "gromacs/mdtypes/awh_params.h"
+#include "gromacs/utility/inmemoryserializer.h"
 #include "gromacs/utility/stringutil.h"
 
+#include "gromacs/applied_forces/awh/tests/awh_setup.h"
 #include "testutils/refdata.h"
 #include "testutils/testasserts.h"
 
@@ -59,98 +62,24 @@ namespace gmx
 namespace test
 {
 
-/*! \internal \brief
- * Struct that gathers all input for setting up and using a Bias
- */
-struct AwhTestParameters
-{
-    AwhTestParameters() = default;
-    //! Move constructor
-    AwhTestParameters(AwhTestParameters&& o) noexcept :
-        beta(o.beta),
-        awhDimParams(o.awhDimParams),
-        awhBiasParams(o.awhBiasParams),
-        awhParams(o.awhParams),
-        dimParams(std::move(o.dimParams))
-    {
-        awhBiasParams.dimParams = &awhDimParams;
-        awhParams.awhBiasParams = &awhBiasParams;
-    }
-    double beta; //!< 1/(kB*T)
-
-    AwhDimParams  awhDimParams;  //!< Dimension parameters pointed to by \p awhBiasParams
-    AwhBiasParams awhBiasParams; //!< Bias parameters pointed to by \[ awhParams
-    AwhParams     awhParams;     //!< AWH parameters, this is the struct to actually use
-
-    std::vector<DimParams> dimParams; //!< Dimension parameters for setting up Bias
-};
-
-//! Helper function to set up the C-style AWH parameters for the test
-static AwhTestParameters getAwhTestParameters(int eawhgrowth, int eawhpotential)
-{
-    AwhTestParameters params;
-
-    params.beta = 0.4;
-
-    AwhDimParams& awhDimParams = params.awhDimParams;
-
-    awhDimParams.period = 0;
-    // Correction for removal of GaussianGeometryFactor/2 in histogram size
-    awhDimParams.diffusion      = 0.1 / (0.144129616073222 * 2);
-    awhDimParams.origin         = 0.5;
-    awhDimParams.end            = 1.5;
-    awhDimParams.coordValueInit = awhDimParams.origin;
-    awhDimParams.coverDiameter  = 0;
-    awhDimParams.eCoordProvider = eawhcoordproviderPULL;
-
-    AwhBiasParams& awhBiasParams = params.awhBiasParams;
-
-    awhBiasParams.ndim                 = 1;
-    awhBiasParams.dimParams            = &awhDimParams;
-    awhBiasParams.eTarget              = eawhtargetCONSTANT;
-    awhBiasParams.targetBetaScaling    = 0;
-    awhBiasParams.targetCutoff         = 0;
-    awhBiasParams.eGrowth              = eawhgrowth;
-    awhBiasParams.bUserData            = FALSE;
-    awhBiasParams.errorInitial         = 0.5 / params.beta;
-    awhBiasParams.shareGroup           = 0;
-    awhBiasParams.equilibrateHistogram = FALSE;
-
-    double  convFactor = 1;
-    double  k          = 1000;
-    int64_t seed       = 93471803;
-
-    params.dimParams.push_back(DimParams::pullDimParams(convFactor, k, params.beta));
-
-    AwhParams& awhParams = params.awhParams;
-
-    awhParams.numBias                    = 1;
-    awhParams.awhBiasParams              = &awhBiasParams;
-    awhParams.seed                       = seed;
-    awhParams.nstOut                     = 0;
-    awhParams.nstSampleCoord             = 1;
-    awhParams.numSamplesUpdateFreeEnergy = 10;
-    awhParams.ePotential                 = eawhpotential;
-    awhParams.shareBiasMultisim          = FALSE;
-
-    return params;
-}
-
 //! Database of 21 test coordinates that represent a trajectory */
-const double g_coords[] = { 0.62, 0.70, 0.68, 0.80, 0.93, 0.87, 1.16, 1.14, 0.95, 0.89, 0.91,
-                            0.86, 0.88, 0.79, 0.75, 0.82, 0.74, 0.70, 0.68, 0.71, 0.73 };
+constexpr double g_coords[] = { 0.62, 0.70, 0.68, 0.80, 0.93, 0.87, 1.16, 1.14, 0.95, 0.89, 0.91,
+                                0.86, 0.88, 0.79, 0.75, 0.82, 0.74, 0.70, 0.68, 0.71, 0.73 };
 
 //! Convenience typedef: growth type enum, potential type enum, disable update skips
-typedef std::tuple<int, int, BiasParams::DisableUpdateSkips> BiasTestParameters;
+typedef std::tuple<AwhHistogramGrowthType, AwhPotentialType, BiasParams::DisableUpdateSkips> BiasTestParameters;
 
 /*! \brief Test fixture for testing Bias updates
  */
 class BiasTest : public ::testing::TestWithParam<BiasTestParameters>
 {
+private:
+    //! Storage for test parameters.
+    std::unique_ptr<AwhTestParameters> params_;
+
 public:
     //! Random seed for AWH MC sampling
     int64_t seed_;
-
     //! Coordinates representing a trajectory in time
     std::vector<double> coordinates_;
     //! The awh Bias
@@ -173,8 +102,8 @@ public:
          *       and disableUpdateSkips do not affect the point state.
          *       But the reference data will also ensure this.
          */
-        int                            eawhgrowth;
-        int                            eawhpotential;
+        AwhHistogramGrowthType         eawhgrowth;
+        AwhPotentialType               eawhpotential;
         BiasParams::DisableUpdateSkips disableUpdateSkips;
         std::tie(eawhgrowth, eawhpotential, disableUpdateSkips) = GetParam();
 
@@ -183,21 +112,31 @@ public:
          * The idea is to, among other things, have part of the interval
          * not covered by samples.
          */
-        const AwhTestParameters params = getAwhTestParameters(eawhgrowth, eawhpotential);
+        auto awhDimBuffer   = awhDimParamSerialized();
+        auto awhDimArrayRef = gmx::arrayRefFromArray(&awhDimBuffer, 1);
+        params_             = std::make_unique<AwhTestParameters>(getAwhTestParameters(
+                eawhgrowth, eawhpotential, awhDimArrayRef, false, 0.4, false, 0.5, 0));
 
-        seed_ = params.awhParams.seed;
+        seed_ = params_->awhParams.seed();
 
-        double mdTimeStep = 0.1;
+        constexpr double mdTimeStep = 0.1;
 
         int numSamples = coordinates_.size() - 1; // No sample taken at step 0
-        GMX_RELEASE_ASSERT(numSamples % params.awhParams.numSamplesUpdateFreeEnergy == 0,
+        GMX_RELEASE_ASSERT(numSamples % params_->awhParams.numSamplesUpdateFreeEnergy() == 0,
                            "This test is intended to reproduce the situation when the might need "
                            "to write output during a normal AWH run, therefore the number of "
                            "samples should be a multiple of the free-energy update interval (but "
                            "the test should also runs fine without this condition).");
 
-        bias_ = std::make_unique<Bias>(-1, params.awhParams, params.awhBiasParams, params.dimParams,
-                                       params.beta, mdTimeStep, 1, "", Bias::ThisRankWillDoIO::No,
+        bias_ = std::make_unique<Bias>(-1,
+                                       params_->awhParams,
+                                       params_->awhParams.awhBiasParams()[0],
+                                       params_->dimParams,
+                                       params_->beta,
+                                       mdTimeStep,
+                                       1,
+                                       "",
+                                       Bias::ThisRankWillDoIO::No,
                                        disableUpdateSkips);
     }
 };
@@ -230,9 +169,8 @@ TEST_P(BiasTest, ForcesBiasPmf)
 
         awh_dvec                    coordValue = { coord, 0, 0, 0 };
         double                      potential  = 0;
-        gmx::ArrayRef<const double> biasForce =
-                bias.calcForceAndUpdateBias(coordValue, {}, {}, &potential, &potentialJump, nullptr,
-                                            nullptr, step, step, seed_, nullptr);
+        gmx::ArrayRef<const double> biasForce  = bias.calcForceAndUpdateBias(
+                coordValue, {}, {}, &potential, &potentialJump, nullptr, nullptr, step, step, seed_, nullptr);
 
         force.push_back(biasForce[0]);
         pot.push_back(potential);
@@ -250,7 +188,7 @@ TEST_P(BiasTest, ForcesBiasPmf)
     }
 
     std::vector<double> pointBias, logPmfsum;
-    for (auto& point : bias.state().points())
+    for (const auto& point : bias.state().points())
     {
         pointBias.push_back(point.bias());
         logPmfsum.push_back(point.logPmfSum());
@@ -281,29 +219,47 @@ TEST_P(BiasTest, ForcesBiasPmf)
  */
 INSTANTIATE_TEST_CASE_P(WithParameters,
                         BiasTest,
-                        ::testing::Combine(::testing::Values(eawhgrowthLINEAR, eawhgrowthEXP_LINEAR),
-                                           ::testing::Values(eawhpotentialUMBRELLA, eawhpotentialCONVOLVED),
+                        ::testing::Combine(::testing::Values(AwhHistogramGrowthType::Linear,
+                                                             AwhHistogramGrowthType::ExponentialLinear),
+                                           ::testing::Values(AwhPotentialType::Umbrella,
+                                                             AwhPotentialType::Convolved),
                                            ::testing::Values(BiasParams::DisableUpdateSkips::yes,
                                                              BiasParams::DisableUpdateSkips::no)));
 
 // Test that we detect coverings and exit the initial stage at the correct step
 TEST(BiasTest, DetectsCovering)
 {
-    const AwhTestParameters params = getAwhTestParameters(eawhgrowthEXP_LINEAR, eawhpotentialCONVOLVED);
-    const AwhDimParams&     awhDimParams = params.awhParams.awhBiasParams[0].dimParams[0];
-
-    const double mdTimeStep = 0.1;
-
-    Bias bias(-1, params.awhParams, params.awhBiasParams, params.dimParams, params.beta, mdTimeStep,
-              1, "", Bias::ThisRankWillDoIO::No);
+    const std::vector<char> serializedAwhParametersPerDim = awhDimParamSerialized();
+    auto awhDimArrayRef            = gmx::arrayRefFromArray(&serializedAwhParametersPerDim, 1);
+    const AwhTestParameters params = getAwhTestParameters(AwhHistogramGrowthType::ExponentialLinear,
+                                                          AwhPotentialType::Convolved,
+                                                          awhDimArrayRef,
+                                                          false,
+                                                          0.4,
+                                                          false,
+                                                          0.5,
+                                                          0);
+    const AwhDimParams&     awhDimParams = params.awhParams.awhBiasParams()[0].dimParams()[0];
+
+    constexpr double mdTimeStep = 0.1;
+
+    Bias bias(-1,
+              params.awhParams,
+              params.awhParams.awhBiasParams()[0],
+              params.dimParams,
+              params.beta,
+              mdTimeStep,
+              1,
+              "",
+              Bias::ThisRankWillDoIO::No);
 
     /* We use a trajectory of the sum of two sines to cover the reaction
      * coordinate range in a semi-realistic way. The period is 4*pi=12.57.
      * We get out of the initial stage after 4 coverings at step 300.
      */
-    const int64_t exitStepRef = 300;
-    const double  midPoint    = 0.5 * (awhDimParams.end + awhDimParams.origin);
-    const double  halfWidth   = 0.5 * (awhDimParams.end - awhDimParams.origin);
+    constexpr int64_t exitStepRef = 300;
+    const double      midPoint    = 0.5 * (awhDimParams.end() + awhDimParams.origin());
+    const double      halfWidth   = 0.5 * (awhDimParams.end() - awhDimParams.origin());
 
     bool inInitialStage = bias.state().inInitialStage();
     /* Normally this loop exits at exitStepRef, but we extend with failure */
@@ -316,8 +272,17 @@ TEST(BiasTest, DetectsCovering)
         awh_dvec coordValue    = { coord, 0, 0, 0 };
         double   potential     = 0;
         double   potentialJump = 0;
-        bias.calcForceAndUpdateBias(coordValue, {}, {}, &potential, &potentialJump, nullptr,
-                                    nullptr, step, step, params.awhParams.seed, nullptr);
+        bias.calcForceAndUpdateBias(coordValue,
+                                    {},
+                                    {},
+                                    &potential,
+                                    &potentialJump,
+                                    nullptr,
+                                    nullptr,
+                                    step,
+                                    step,
+                                    params.awhParams.seed(),
+                                    nullptr);
 
         inInitialStage = bias.state().inInitialStage();
         if (!inInitialStage)
index 1d536446bfff1558bb6f71d31bfdadb6e200167a..5eb21950b7473f8d8a19efcd8c0f0e695a49f4bd 100644 (file)
@@ -49,6 +49,7 @@
 #include "gromacs/mdtypes/awh_params.h"
 #include "gromacs/utility/stringutil.h"
 
+#include "gromacs/applied_forces/awh/tests/awh_setup.h"
 #include "testutils/refdata.h"
 #include "testutils/testasserts.h"
 
@@ -59,90 +60,20 @@ namespace test
 {
 
 //! The number of lambda states to use in the tests.
-const int numLambdaStates = 16;
+static constexpr int c_numLambdaStates = 16;
 
-/*! \internal \brief
- * Struct that gathers all input for setting up and using a Bias
- */
-struct AwhFepLambdaStateTestParameters
-{
-    AwhFepLambdaStateTestParameters() = default;
-    //! Move constructor
-    AwhFepLambdaStateTestParameters(AwhFepLambdaStateTestParameters&& o) noexcept :
-        beta(o.beta),
-        awhDimParams(o.awhDimParams),
-        awhBiasParams(o.awhBiasParams),
-        awhParams(o.awhParams),
-        dimParams(std::move(o.dimParams))
-    {
-        awhBiasParams.dimParams = &awhDimParams;
-        awhParams.awhBiasParams = &awhBiasParams;
-    }
-    double beta; //!< 1/(kB*T)
-
-    AwhDimParams  awhDimParams;  //!< Dimension parameters pointed to by \p awhBiasParams
-    AwhBiasParams awhBiasParams; //!< Bias parameters pointed to by \[ awhParams
-    AwhParams     awhParams;     //!< AWH parameters, this is the struct to actually use
-
-    std::vector<DimParams> dimParams; //!< Dimension parameters for setting up Bias
-};
-
-//! Helper function to set up the C-style AWH parameters for the test
-static AwhFepLambdaStateTestParameters getAwhFepLambdaTestParameters(int eawhgrowth, int eawhpotential)
-{
-    AwhFepLambdaStateTestParameters params;
-
-    params.beta = 0.4;
-
-    AwhDimParams& awhDimParams = params.awhDimParams;
-
-    awhDimParams.period = 0;
-    // Correction for removal of GaussianGeometryFactor/2 in histogram size
-    awhDimParams.diffusion      = 1e-4 / (0.12927243028700 * 2);
-    awhDimParams.origin         = 0;
-    awhDimParams.end            = numLambdaStates - 1;
-    awhDimParams.coordValueInit = awhDimParams.origin;
-    awhDimParams.coverDiameter  = 0;
-    awhDimParams.eCoordProvider = eawhcoordproviderFREE_ENERGY_LAMBDA;
-
-    AwhBiasParams& awhBiasParams = params.awhBiasParams;
-
-    awhBiasParams.ndim                 = 1;
-    awhBiasParams.dimParams            = &awhDimParams;
-    awhBiasParams.eTarget              = eawhtargetCONSTANT;
-    awhBiasParams.targetBetaScaling    = 0;
-    awhBiasParams.targetCutoff         = 0;
-    awhBiasParams.eGrowth              = eawhgrowth;
-    awhBiasParams.bUserData            = FALSE;
-    awhBiasParams.errorInitial         = 1.0 / params.beta;
-    awhBiasParams.shareGroup           = 0;
-    awhBiasParams.equilibrateHistogram = FALSE;
-
-    int64_t seed = 93471803;
-
-    params.dimParams.push_back(DimParams::fepLambdaDimParams(numLambdaStates, params.beta));
-
-    AwhParams& awhParams = params.awhParams;
-
-    awhParams.numBias                    = 1;
-    awhParams.awhBiasParams              = &awhBiasParams;
-    awhParams.seed                       = seed;
-    awhParams.nstOut                     = 0;
-    awhParams.nstSampleCoord             = 1;
-    awhParams.numSamplesUpdateFreeEnergy = 10;
-    awhParams.ePotential                 = eawhpotential;
-    awhParams.shareBiasMultisim          = FALSE;
-
-    return params;
-}
 
 //! Convenience typedef: growth type enum, potential type enum, disable update skips
-typedef std::tuple<int, int, BiasParams::DisableUpdateSkips> BiasTestParameters;
+typedef std::tuple<AwhHistogramGrowthType, AwhPotentialType, BiasParams::DisableUpdateSkips> BiasTestParameters;
 
 /*! \brief Test fixture for testing Bias updates
  */
 class BiasFepLambdaStateTest : public ::testing::TestWithParam<BiasTestParameters>
 {
+private:
+    //! Storage for test parameters.
+    std::unique_ptr<AwhTestParameters> params_;
+
 public:
     //! Random seed for AWH MC sampling
     int64_t seed_;
@@ -165,23 +96,40 @@ public:
          *       and disableUpdateSkips do not affect the point state.
          *       But the reference data will also ensure this.
          */
-        int                            eawhgrowth;
-        int                            eawhpotential;
+        AwhHistogramGrowthType         eawhgrowth;
+        AwhPotentialType               eawhpotential;
         BiasParams::DisableUpdateSkips disableUpdateSkips;
         std::tie(eawhgrowth, eawhpotential, disableUpdateSkips) = GetParam();
 
         /* Set up a basic AWH setup with a single, 1D bias with parameters
          * such that we can measure the effects of different parameters.
          */
-        const AwhFepLambdaStateTestParameters params =
-                getAwhFepLambdaTestParameters(eawhgrowth, eawhpotential);
-
-        seed_ = params.awhParams.seed;
+        constexpr AwhCoordinateProviderType coordinateProvider = AwhCoordinateProviderType::FreeEnergyLambda;
+        constexpr int                       coordIndex = 0;
+        constexpr double                    origin     = 0;
+        constexpr double                    end        = c_numLambdaStates - 1;
+        constexpr double                    period     = 0;
+        // Correction for removal of GaussianGeometryFactor/2 in histogram size
+        constexpr double diffusion = 1e-4 / (0.12927243028700 * 2);
+        const auto       awhDimBuffer =
+                awhDimParamSerialized(coordinateProvider, coordIndex, origin, end, period, diffusion);
+        const auto awhDimArrayRef = gmx::arrayRefFromArray(&awhDimBuffer, 1);
+        params_                   = std::make_unique<AwhTestParameters>(getAwhTestParameters(
+                eawhgrowth, eawhpotential, awhDimArrayRef, false, 0.4, true, 1.0, c_numLambdaStates));
+
+        seed_ = params_->awhParams.seed();
 
         double mdTimeStep = 0.1;
 
-        bias_ = std::make_unique<Bias>(-1, params.awhParams, params.awhBiasParams, params.dimParams,
-                                       params.beta, mdTimeStep, 1, "", Bias::ThisRankWillDoIO::No,
+        bias_ = std::make_unique<Bias>(-1,
+                                       params_->awhParams,
+                                       params_->awhParams.awhBiasParams()[0],
+                                       params_->dimParams,
+                                       params_->beta,
+                                       mdTimeStep,
+                                       1,
+                                       "",
+                                       Bias::ThisRankWillDoIO::No,
                                        disableUpdateSkips);
     }
 };
@@ -210,10 +158,10 @@ TEST_P(BiasFepLambdaStateTest, ForcesBiasPmf)
     int    nSteps        = 501;
 
     /* Some energies to use as base values (to which some noise is added later on). */
-    std::vector<double> neighborLambdaEnergies(numLambdaStates);
-    std::vector<double> neighborLambdaDhdl(numLambdaStates);
+    std::vector<double> neighborLambdaEnergies(c_numLambdaStates);
+    std::vector<double> neighborLambdaDhdl(c_numLambdaStates);
     const double        magnitude = 12.0;
-    for (int i = 0; i < numLambdaStates; i++)
+    for (int i = 0; i < c_numLambdaStates; i++)
     {
         neighborLambdaEnergies[i] = magnitude * std::sin(i * 0.1);
         neighborLambdaDhdl[i]     = magnitude * std::cos(i * 0.1);
@@ -224,9 +172,17 @@ TEST_P(BiasFepLambdaStateTest, ForcesBiasPmf)
         int      umbrellaGridpointIndex = bias.state().coordState().umbrellaGridpoint();
         awh_dvec coordValue = { bias.getGridCoordValue(umbrellaGridpointIndex)[0], 0, 0, 0 };
         double   potential  = 0;
-        gmx::ArrayRef<const double> biasForce = bias.calcForceAndUpdateBias(
-                coordValue, neighborLambdaEnergies, neighborLambdaDhdl, &potential, &potentialJump,
-                nullptr, nullptr, step * mdTimeStep, step, seed_, nullptr);
+        gmx::ArrayRef<const double> biasForce = bias.calcForceAndUpdateBias(coordValue,
+                                                                            neighborLambdaEnergies,
+                                                                            neighborLambdaDhdl,
+                                                                            &potential,
+                                                                            &potentialJump,
+                                                                            nullptr,
+                                                                            nullptr,
+                                                                            step * mdTimeStep,
+                                                                            step,
+                                                                            seed_,
+                                                                            nullptr);
 
         force.push_back(biasForce[0]);
         pot.push_back(potential);
@@ -241,7 +197,7 @@ TEST_P(BiasFepLambdaStateTest, ForcesBiasPmf)
     }
 
     std::vector<double> pointBias, logPmfsum;
-    for (auto& point : bias.state().points())
+    for (const auto& point : bias.state().points())
     {
         pointBias.push_back(point.bias());
         logPmfsum.push_back(point.logPmfSum());
@@ -265,31 +221,54 @@ TEST_P(BiasFepLambdaStateTest, ForcesBiasPmf)
  */
 INSTANTIATE_TEST_CASE_P(WithParameters,
                         BiasFepLambdaStateTest,
-                        ::testing::Combine(::testing::Values(eawhgrowthLINEAR, eawhgrowthEXP_LINEAR),
-                                           ::testing::Values(eawhpotentialUMBRELLA),
+                        ::testing::Combine(::testing::Values(AwhHistogramGrowthType::Linear,
+                                                             AwhHistogramGrowthType::ExponentialLinear),
+                                           ::testing::Values(AwhPotentialType::Umbrella),
                                            ::testing::Values(BiasParams::DisableUpdateSkips::yes,
                                                              BiasParams::DisableUpdateSkips::no)));
 
 // Test that we detect coverings and exit the initial stage at the correct step
 TEST(BiasFepLambdaStateTest, DetectsCovering)
 {
-    const AwhFepLambdaStateTestParameters params =
-            getAwhFepLambdaTestParameters(eawhgrowthEXP_LINEAR, eawhpotentialUMBRELLA);
+    constexpr AwhCoordinateProviderType coordinateProvider = AwhCoordinateProviderType::FreeEnergyLambda;
+    constexpr int                       coordIndex         = 0;
+    constexpr double                    origin             = 0;
+    constexpr double                    end                = c_numLambdaStates - 1;
+    constexpr double                    period             = 0;
+    constexpr double                    diffusion          = 1e-4 / (0.12927243028700 * 2);
+    auto                                awhDimBuffer =
+            awhDimParamSerialized(coordinateProvider, coordIndex, origin, end, period, diffusion);
+    auto                    awhDimArrayRef = gmx::arrayRefFromArray(&awhDimBuffer, 1);
+    const AwhTestParameters params(getAwhTestParameters(AwhHistogramGrowthType::ExponentialLinear,
+                                                        AwhPotentialType::Umbrella,
+                                                        awhDimArrayRef,
+                                                        false,
+                                                        0.4,
+                                                        true,
+                                                        1.0,
+                                                        c_numLambdaStates));
 
     const double mdTimeStep = 0.1;
 
-    Bias bias(-1, params.awhParams, params.awhBiasParams, params.dimParams, params.beta, mdTimeStep,
-              1, "", Bias::ThisRankWillDoIO::No);
+    Bias bias(-1,
+              params.awhParams,
+              params.awhParams.awhBiasParams()[0],
+              params.dimParams,
+              params.beta,
+              mdTimeStep,
+              1,
+              "",
+              Bias::ThisRankWillDoIO::No);
 
     const int64_t exitStepRef = 320;
 
     bool inInitialStage = bias.state().inInitialStage();
 
     /* Some energies to use as base values (to which some noise is added later on). */
-    std::vector<double> neighborLambdaEnergies(numLambdaStates);
-    std::vector<double> neighborLambdaDhdl(numLambdaStates);
+    std::vector<double> neighborLambdaEnergies(c_numLambdaStates);
+    std::vector<double> neighborLambdaDhdl(c_numLambdaStates);
     const double        magnitude = 12.0;
-    for (int i = 0; i < numLambdaStates; i++)
+    for (int i = 0; i < c_numLambdaStates; i++)
     {
         neighborLambdaEnergies[i] = magnitude * std::sin(i * 0.1);
         neighborLambdaDhdl[i]     = magnitude * std::cos(i * 0.1);
@@ -304,9 +283,17 @@ TEST(BiasFepLambdaStateTest, DetectsCovering)
 
         double potential     = 0;
         double potentialJump = 0;
-        bias.calcForceAndUpdateBias(coordValue, neighborLambdaEnergies, neighborLambdaDhdl,
-                                    &potential, &potentialJump, nullptr, nullptr, step, step,
-                                    params.awhParams.seed, nullptr);
+        bias.calcForceAndUpdateBias(coordValue,
+                                    neighborLambdaEnergies,
+                                    neighborLambdaDhdl,
+                                    &potential,
+                                    &potentialJump,
+                                    nullptr,
+                                    nullptr,
+                                    step,
+                                    step,
+                                    params.awhParams.seed(),
+                                    nullptr);
 
         inInitialStage = bias.state().inInitialStage();
         if (!inInitialStage)
index 9337d0632de0579ffe42d0fa2961e1c2eeca76f0..3d4d2565bc6bae0ff81c754fd4a4b82ebd752131 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +46,9 @@
 
 #include "gromacs/mdtypes/awh_params.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/inmemoryserializer.h"
 
+#include "gromacs/applied_forces/awh/tests/awh_setup.h"
 #include "testutils/testasserts.h"
 
 namespace gmx
@@ -71,15 +73,29 @@ TEST(biasGridTest, neighborhood)
      */
 
     const int                 numDim = 2;
-    std::vector<AwhDimParams> awhDimParams(numDim);
-
-    awhDimParams[0].origin = -5;
-    awhDimParams[0].end    = 5;
-    awhDimParams[0].period = 10;
-
-    awhDimParams[1].origin = 0.5;
-    awhDimParams[1].end    = 2.0;
-    awhDimParams[1].period = 0;
+    std::vector<AwhDimParams> awhDimParams;
+    AwhCoordinateProviderType coordinateProvider = AwhCoordinateProviderType::Pull;
+    double                    diffusion          = 0.1;
+    {
+        int    coordIndex = 0;
+        double origin     = -5;
+        double end        = 5;
+        double period     = 10;
+        auto   awhDimBuffer =
+                awhDimParamSerialized(coordinateProvider, coordIndex, origin, end, period, diffusion);
+        gmx::InMemoryDeserializer serializer(awhDimBuffer, false);
+        awhDimParams.emplace_back(AwhDimParams(&serializer));
+    }
+    {
+        int    coordIndex = 1;
+        double origin     = 0.5;
+        double end        = 2;
+        double period     = 0;
+        auto   awhDimBuffer =
+                awhDimParamSerialized(coordinateProvider, coordIndex, origin, end, period, diffusion);
+        gmx::InMemoryDeserializer serializer(awhDimBuffer, false);
+        awhDimParams.emplace_back(AwhDimParams(&serializer));
+    }
 
     const real conversionFactor = 1;
     const real beta             = 3.0;
@@ -89,7 +105,7 @@ TEST(biasGridTest, neighborhood)
     dimParams.push_back(DimParams::pullDimParams(conversionFactor, 1 / (beta * 0.7 * 0.7), beta));
     dimParams.push_back(DimParams::pullDimParams(conversionFactor, 1 / (beta * 0.1 * 0.1), beta));
 
-    BiasGrid grid(dimParams, awhDimParams.data());
+    BiasGrid grid(dimParams, awhDimParams);
 
     const int numPoints = grid.numPoints();
 
@@ -133,7 +149,7 @@ TEST(biasGridTest, neighborhood)
             haveCorrectNumNeighbors = false;
         }
 
-        for (auto& j : point.neighbor)
+        for (const auto& j : point.neighbor)
         {
             if (j >= 0 && j < numPoints)
             {
@@ -171,7 +187,7 @@ TEST(biasGridTest, neighborhood)
         }
 
         /* Clear the marked points in the checking grid */
-        for (auto& neighbor : point.neighbor)
+        for (const auto& neighbor : point.neighbor)
         {
             if (neighbor >= 0 && neighbor < numPoints)
             {
index a1e68b6460b6cb5c287c2a326b3c55304de49806..2fad0ae2ac910f61f196c80cc5764f7604920fd8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,7 @@
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/smalloc.h"
 
+#include "gromacs/applied_forces/awh/tests/awh_setup.h"
 #include "testutils/testasserts.h"
 #include "testutils/testfilemanager.h"
 
@@ -60,98 +61,53 @@ namespace gmx
 namespace test
 {
 
-/*! \internal \brief
- * Struct that gathers all input for setting up and using a Bias
- */
-struct AwhTestParameters
-{
-    double beta; //!< 1/(kB*T)
-
-    AwhDimParams  awhDimParams[2]; //!< Dimension parameters pointed to by \p awhBiasParams
-    AwhBiasParams awhBiasParams;   //!< Bias parameters pointed to by \[ awhParams
-    AwhParams     awhParams;       //!< AWH parameters, this is the struct to actually use
-};
-
-//! Helper function to set up the C-style AWH parameters for the test
-static AwhTestParameters getAwhTestParameters()
-{
-    AwhTestParameters params;
-
-    params.beta = 1.0;
-
-    AwhParams& awhParams = params.awhParams;
-    snew(params.awhParams.awhBiasParams, 1);
-    AwhBiasParams& awhBiasParams = params.awhParams.awhBiasParams[0];
-    snew(awhBiasParams.dimParams, 2);
-
-    AwhDimParams& awhDimParams0 = awhBiasParams.dimParams[0];
-
-    awhDimParams0.period         = 0;
-    awhDimParams0.diffusion      = 0.1;
-    awhDimParams0.origin         = 0.5;
-    awhDimParams0.end            = 1.5;
-    awhDimParams0.coordValueInit = awhDimParams0.origin;
-    awhDimParams0.coverDiameter  = 0;
-    awhDimParams0.eCoordProvider = eawhcoordproviderPULL;
-
-    AwhDimParams& awhDimParams1 = awhBiasParams.dimParams[1];
-
-    awhDimParams1.period         = 0;
-    awhDimParams1.diffusion      = 0.1;
-    awhDimParams1.origin         = 0.8;
-    awhDimParams1.end            = 1.3;
-    awhDimParams1.coordValueInit = awhDimParams1.origin;
-    awhDimParams1.coverDiameter  = 0;
-    awhDimParams1.eCoordProvider = eawhcoordproviderPULL;
-
-    awhBiasParams.ndim                 = 2;
-    awhBiasParams.eTarget              = eawhtargetCONSTANT;
-    awhBiasParams.targetBetaScaling    = 0;
-    awhBiasParams.targetCutoff         = 0;
-    awhBiasParams.eGrowth              = eawhgrowthLINEAR;
-    awhBiasParams.bUserData            = TRUE;
-    awhBiasParams.errorInitial         = 0.5;
-    awhBiasParams.shareGroup           = 0;
-    awhBiasParams.equilibrateHistogram = FALSE;
-
-    awhParams.numBias                    = 1;
-    awhParams.seed                       = 93471803;
-    awhParams.nstOut                     = 0;
-    awhParams.nstSampleCoord             = 1;
-    awhParams.numSamplesUpdateFreeEnergy = 10;
-    awhParams.ePotential                 = eawhpotentialCONVOLVED;
-    awhParams.shareBiasMultisim          = FALSE;
-
-    return params;
-}
-
 /*! \brief Test fixture for testing Bias updates
  */
 class BiasStateTest : public ::testing::TestWithParam<const char*>
 {
+private:
+    std::unique_ptr<AwhTestParameters> params_;
+
 public:
     std::unique_ptr<BiasState> biasState_; //!< The bias state
 
     BiasStateTest()
     {
-        AwhTestParameters      params        = getAwhTestParameters();
-        const AwhParams&       awhParams     = params.awhParams;
-        const AwhBiasParams&   awhBiasParams = awhParams.awhBiasParams[0];
+        std::vector<std::vector<char>> awhDimParameters;
+        AwhCoordinateProviderType      coordinateProvider = AwhCoordinateProviderType::Pull;
+        double                         diffusion          = 0.1;
+        {
+            int    coordIndex = 0;
+            double origin     = 0.5;
+            double end        = 1.5;
+            double period     = 0;
+            awhDimParameters.emplace_back(awhDimParamSerialized(
+                    coordinateProvider, coordIndex, origin, end, period, diffusion));
+        }
+        {
+            int    coordIndex = 1;
+            double origin     = 0.8;
+            double end        = 1.3;
+            double period     = 0;
+            awhDimParameters.emplace_back(awhDimParamSerialized(
+                    coordinateProvider, coordIndex, origin, end, period, diffusion));
+        }
+        params_                          = std::make_unique<AwhTestParameters>(getAwhTestParameters(
+                AwhHistogramGrowthType::Linear, AwhPotentialType::Convolved, awhDimParameters, true, 1.0, false, 0.5, 0));
+        const AwhParams&       awhParams = params_->awhParams;
+        const AwhBiasParams&   awhBiasParams = awhParams.awhBiasParams()[0];
         std::vector<DimParams> dimParams;
-        dimParams.push_back(DimParams::pullDimParams(1.0, 15.0, params.beta));
-        dimParams.push_back(DimParams::pullDimParams(1.0, 15.0, params.beta));
-        BiasGrid   grid(dimParams, awhBiasParams.dimParams);
-        BiasParams biasParams(awhParams, awhBiasParams, dimParams, 1.0, 1.0,
-                              BiasParams::DisableUpdateSkips::no, 1, grid.axis(), 0);
+        dimParams.push_back(DimParams::pullDimParams(1.0, 15.0, params_->beta));
+        dimParams.push_back(DimParams::pullDimParams(1.0, 15.0, params_->beta));
+        BiasGrid   grid(dimParams, awhBiasParams.dimParams());
+        BiasParams biasParams(
+                awhParams, awhBiasParams, dimParams, 1.0, 1.0, BiasParams::DisableUpdateSkips::no, 1, grid.axis(), 0);
         biasState_ = std::make_unique<BiasState>(awhBiasParams, 1.0, dimParams, grid);
 
         // Here we initialize the grid point state using the input file
         std::string filename = gmx::test::TestFileManager::getInputFilePath(GetParam());
-        biasState_->initGridPointState(awhBiasParams, dimParams, grid, biasParams, filename,
-                                       params.awhParams.numBias);
-
-        sfree(params.awhParams.awhBiasParams[0].dimParams);
-        sfree(params.awhParams.awhBiasParams);
+        biasState_->initGridPointState(
+                awhBiasParams, dimParams, grid, biasParams, filename, params_->awhParams.numBias());
     }
 };
 
index b2e173b4ca56b121279fd33fa0a640bda3250796..bf578357c131e75a608e0137134a4ae28078c00f 100644 (file)
@@ -57,7 +57,7 @@
 #include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/keyvaluetreebuilder.h"
-#include "gromacs/utility/mdmodulenotification.h"
+#include "gromacs/utility/mdmodulesnotifiers.h"
 
 #include "densityfittingforceprovider.h"
 #include "densityfittingoptions.h"
@@ -82,7 +82,7 @@ namespace
  * the DensityFitting class needs access to parameters that become available
  * only during simulation setup.
  *
- * This class collects these parameters via MdModuleNotifications in the
+ * This class collects these parameters via MDModulesNotifiers in the
  * simulation setup phase and provides a check if all necessary parameters have
  * been provided.
  */
@@ -164,17 +164,17 @@ public:
             GMX_THROW(InternalError("Need to set reference density before normalizing it."));
         }
 
-        const real sumOfDensityData = std::accumulate(begin(referenceDensity_->asView()),
-                                                      end(referenceDensity_->asView()), 0.);
+        const real sumOfDensityData = std::accumulate(
+                begin(referenceDensity_->asView()), end(referenceDensity_->asView()), 0.);
         for (float& referenceDensityVoxel : referenceDensity_->asView())
         {
             referenceDensityVoxel /= sumOfDensityData;
         }
     }
-    /*! \brief Set the periodic boundary condition via MdModuleNotifier.
+    /*! \brief Set the periodic boundary condition via MDModuleNotifier.
      *
      * The pbc type is wrapped in PeriodicBoundaryConditionType to
-     * allow the MdModuleNotifier to statically distinguish the callback
+     * allow the MDModuleNotifier to statically distinguish the callback
      * function type from other 'int' function callbacks.
      *
      * \param[in] pbcType enumerates the periodic boundary condition.
@@ -199,7 +199,7 @@ public:
     void setSimulationTimeStep(double timeStep) { simulationTimeStep_ = timeStep; }
 
     //! Return the simulation time step
-    double simulationTimeStep() { return simulationTimeStep_; }
+    double simulationTimeStep() const { return simulationTimeStep_; }
 
 private:
     //! The reference density to fit to
@@ -231,7 +231,7 @@ public:
 
     /*! \brief Request to be notified during pre-processing.
      *
-     * \param[in] notifier allows the module to subscribe to notifications from MdModules.
+     * \param[in] notifiers allows the module to subscribe to notifications from MDModules.
      *
      * The density fitting code subscribes to these notifications:
      *   - setting atom group indices in the densityFittingOptions_ from an
@@ -240,9 +240,9 @@ public:
      *     key-value-tree during pre-processing by a function taking a
      *     KeyValueTreeObjectBuilder as parameter
      */
-    void subscribeToPreProcessingNotifications(MdModulesNotifier* notifier) override
+    void subscribeToPreProcessingNotifications(MDModulesNotifiers* notifiers) override
     {
-        // Callbacks for several kinds of MdModuleNotification are created
+        // Callbacks for several kinds of MDModulesNotifier are created
         // and subscribed, and will be dispatched correctly at run time
         // based on the type of the parameter required by the lambda.
 
@@ -255,20 +255,20 @@ public:
         const auto setFitGroupIndicesFunction = [this](const IndexGroupsAndNames& indexGroupsAndNames) {
             densityFittingOptions_.setFitGroupIndices(indexGroupsAndNames);
         };
-        notifier->preProcessingNotifications_.subscribe(setFitGroupIndicesFunction);
+        notifiers->preProcessingNotifier_.subscribe(setFitGroupIndicesFunction);
 
         // Writing internal parameters during pre-processing
         const auto writeInternalParametersFunction = [this](KeyValueTreeObjectBuilder treeBuilder) {
             densityFittingOptions_.writeInternalParametersToKvt(treeBuilder);
         };
-        notifier->preProcessingNotifications_.subscribe(writeInternalParametersFunction);
+        notifiers->preProcessingNotifier_.subscribe(writeInternalParametersFunction);
 
         // Checking for consistency with all .mdp options
         const auto checkEnergyCaluclationFrequencyFunction =
                 [this](EnergyCalculationFrequencyErrors* energyCalculationFrequencyErrors) {
                     densityFittingOptions_.checkEnergyCaluclationFrequency(energyCalculationFrequencyErrors);
                 };
-        notifier->preProcessingNotifications_.subscribe(checkEnergyCaluclationFrequencyFunction);
+        notifiers->preProcessingNotifier_.subscribe(checkEnergyCaluclationFrequencyFunction);
     }
 
     /*! \brief Request to be notified.
@@ -280,13 +280,13 @@ public:
      *   - the type of periodic boundary conditions that are used
      *     by taking a PeriodicBoundaryConditionType as parameter
      *   - the writing of checkpoint data
-     *     by taking a MdModulesWriteCheckpointData as parameter
+     *     by taking a MDModulesWriteCheckpointData as parameter
      *   - the reading of checkpoint data
-     *     by taking a MdModulesCheckpointReadingDataOnMaster as parameter
+     *     by taking a MDModulesCheckpointReadingDataOnMaster as parameter
      *   - the broadcasting of checkpoint data
-     *     by taking MdModulesCheckpointReadingBroadcast as parameter
+     *     by taking MDModulesCheckpointReadingBroadcast as parameter
      */
-    void subscribeToSimulationSetupNotifications(MdModulesNotifier* notifier) override
+    void subscribeToSimulationSetupNotifications(MDModulesNotifiers* notifiers) override
     {
         if (!densityFittingOptions_.active())
         {
@@ -297,51 +297,51 @@ public:
         const auto readInternalParametersFunction = [this](const KeyValueTreeObject& tree) {
             densityFittingOptions_.readInternalParametersFromKvt(tree);
         };
-        notifier->simulationSetupNotifications_.subscribe(readInternalParametersFunction);
+        notifiers->simulationSetupNotifier_.subscribe(readInternalParametersFunction);
 
         // constructing local atom sets during simulation setup
         const auto setLocalAtomSetFunction = [this](LocalAtomSetManager* localAtomSetManager) {
             this->constructLocalAtomSet(localAtomSetManager);
         };
-        notifier->simulationSetupNotifications_.subscribe(setLocalAtomSetFunction);
+        notifiers->simulationSetupNotifier_.subscribe(setLocalAtomSetFunction);
 
         // constructing local atom sets during simulation setup
         const auto setPeriodicBoundaryContionsFunction = [this](const PbcType& pbc) {
             this->densityFittingSimulationParameters_.setPeriodicBoundaryConditionType(pbc);
         };
-        notifier->simulationSetupNotifications_.subscribe(setPeriodicBoundaryContionsFunction);
+        notifiers->simulationSetupNotifier_.subscribe(setPeriodicBoundaryContionsFunction);
 
         // setting the simulation time step
         const auto setSimulationTimeStepFunction = [this](const SimulationTimeStep& simulationTimeStep) {
             this->densityFittingSimulationParameters_.setSimulationTimeStep(simulationTimeStep.delta_t);
         };
-        notifier->simulationSetupNotifications_.subscribe(setSimulationTimeStepFunction);
+        notifiers->simulationSetupNotifier_.subscribe(setSimulationTimeStepFunction);
 
         // adding output to energy file
         const auto requestEnergyOutput =
-                [this](MdModulesEnergyOutputToDensityFittingRequestChecker* energyOutputRequest) {
+                [this](MDModulesEnergyOutputToDensityFittingRequestChecker* energyOutputRequest) {
                     this->setEnergyOutputRequest(energyOutputRequest);
                 };
-        notifier->simulationSetupNotifications_.subscribe(requestEnergyOutput);
+        notifiers->simulationSetupNotifier_.subscribe(requestEnergyOutput);
 
         // writing checkpoint data
-        const auto checkpointDataWriting = [this](MdModulesWriteCheckpointData checkpointData) {
+        const auto checkpointDataWriting = [this](MDModulesWriteCheckpointData checkpointData) {
             forceProvider_->writeCheckpointData(checkpointData, DensityFittingModuleInfo::name_);
         };
-        notifier->checkpointingNotifications_.subscribe(checkpointDataWriting);
+        notifiers->checkpointingNotifier_.subscribe(checkpointDataWriting);
 
         // reading checkpoint data
-        const auto checkpointDataReading = [this](MdModulesCheckpointReadingDataOnMaster checkpointData) {
+        const auto checkpointDataReading = [this](MDModulesCheckpointReadingDataOnMaster checkpointData) {
             densityFittingState_.readState(checkpointData.checkpointedData_,
                                            DensityFittingModuleInfo::name_);
         };
-        notifier->checkpointingNotifications_.subscribe(checkpointDataReading);
+        notifiers->checkpointingNotifier_.subscribe(checkpointDataReading);
 
         // broadcasting checkpoint data
-        const auto checkpointDataBroadcast = [this](MdModulesCheckpointReadingBroadcast checkpointData) {
+        const auto checkpointDataBroadcast = [this](MDModulesCheckpointReadingBroadcast checkpointData) {
             densityFittingState_.broadcastState(checkpointData.communicator_, checkpointData.isParallelRun_);
         };
-        notifier->checkpointingNotifications_.subscribe(checkpointDataBroadcast);
+        notifiers->checkpointingNotifier_.subscribe(checkpointDataBroadcast);
     }
 
     //! From IMDModule
@@ -360,11 +360,13 @@ public:
                 densityFittingSimulationParameters_.normalizeReferenceDensity();
             }
             forceProvider_ = std::make_unique<DensityFittingForceProvider>(
-                    parameters, densityFittingSimulationParameters_.referenceDensity(),
+                    parameters,
+                    densityFittingSimulationParameters_.referenceDensity(),
                     densityFittingSimulationParameters_.transformationToDensityLattice(),
                     densityFittingSimulationParameters_.localAtomSet(),
                     densityFittingSimulationParameters_.periodicBoundaryConditionType(),
-                    densityFittingSimulationParameters_.simulationTimeStep(), densityFittingState_);
+                    densityFittingSimulationParameters_.simulationTimeStep(),
+                    densityFittingState_);
             forceProviders->addForceProvider(forceProvider_.get());
         }
     }
@@ -374,7 +376,7 @@ public:
 
     /*! \brief Set up the local atom sets that are used by this module.
      *
-     * \note When density fitting is set up with MdModuleNotification in
+     * \note When density fitting is set up with MDModulesNotifier in
      *       the constructor, this function is called back.
      *
      * \param[in] localAtomSetManager the manager to add local atom sets.
@@ -387,7 +389,7 @@ public:
 
     /*! \brief Request energy output to energy file during simulation.
      */
-    void setEnergyOutputRequest(MdModulesEnergyOutputToDensityFittingRequestChecker* energyOutputRequest)
+    void setEnergyOutputRequest(MDModulesEnergyOutputToDensityFittingRequestChecker* energyOutputRequest)
     {
         energyOutputRequest->energyOutputToDensityFitting_ = densityFittingOptions_.active();
     }
index 27be15efb38e7f7ea9c0517d5a30add61bed8372..75d1d26a077558a3425bf0dc27245b0e6184de39 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +46,7 @@
 #include <algorithm>
 #include <vector>
 
-#include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/arrayref.h"
 
 namespace gmx
@@ -62,8 +62,10 @@ public:
     DensityFittingAmplitudeLookupImpl(const DensityFittingAmplitudeLookupImpl&) = default;
     virtual ~DensityFittingAmplitudeLookupImpl()                                = default;
 
-    virtual const std::vector<real>& operator()(const t_mdatoms& atoms, ArrayRef<const int> localIndex) = 0;
-    virtual std::unique_ptr<DensityFittingAmplitudeLookupImpl> clone() = 0;
+    virtual const std::vector<real>& operator()(ArrayRef<const real> /*chargeA*/,
+                                                ArrayRef<const real> /*massT*/,
+                                                ArrayRef<const int> localIndex) = 0;
+    virtual std::unique_ptr<DensityFittingAmplitudeLookupImpl> clone()          = 0;
 };
 
 namespace
@@ -75,7 +77,9 @@ public:
     UnitAmplitudes(const UnitAmplitudes&) = default;
     ~UnitAmplitudes() override            = default;
     std::unique_ptr<DensityFittingAmplitudeLookupImpl> clone() override;
-    const std::vector<real>& operator()(const t_mdatoms& atoms, ArrayRef<const int> localIndex) override;
+    const std::vector<real>&                           operator()(ArrayRef<const real> /*chargeA*/,
+                                        ArrayRef<const real> /*massT*/,
+                                        ArrayRef<const int> localIndex) override;
 
 private:
     std::vector<real> amplitude_;
@@ -86,7 +90,9 @@ std::unique_ptr<DensityFittingAmplitudeLookupImpl> UnitAmplitudes::clone()
     return std::make_unique<UnitAmplitudes>(*this);
 };
 
-const std::vector<real>& UnitAmplitudes::operator()(const t_mdatoms& /*atoms*/, ArrayRef<const int> localIndex)
+const std::vector<real>& UnitAmplitudes::operator()(ArrayRef<const real> /*chargeA*/,
+                                                    ArrayRef<const real> /*massT*/,
+                                                    ArrayRef<const int> localIndex)
 {
     if (amplitude_.size() != localIndex.size())
     {
@@ -103,7 +109,9 @@ public:
     ChargesAsAmplitudes(const ChargesAsAmplitudes&) = default;
     ~ChargesAsAmplitudes() override                 = default;
     std::unique_ptr<DensityFittingAmplitudeLookupImpl> clone() override;
-    const std::vector<real>& operator()(const t_mdatoms& atoms, ArrayRef<const int> localIndex) override;
+    const std::vector<real>&                           operator()(ArrayRef<const real> chargeA,
+                                        ArrayRef<const real> /*massT*/,
+                                        ArrayRef<const int> localIndex) override;
 
 private:
     std::vector<real> amplitude_;
@@ -114,15 +122,19 @@ std::unique_ptr<DensityFittingAmplitudeLookupImpl> ChargesAsAmplitudes::clone()
     return std::make_unique<ChargesAsAmplitudes>(*this);
 };
 
-const std::vector<real>& ChargesAsAmplitudes::operator()(const t_mdatoms& atoms, ArrayRef<const int> localIndex)
+const std::vector<real>& ChargesAsAmplitudes::operator()(ArrayRef<const real> chargeA,
+                                                         ArrayRef<const real> /*massT*/,
+                                                         ArrayRef<const int> localIndex)
 {
     if (amplitude_.size() != localIndex.size())
     {
         amplitude_.resize(localIndex.size());
     }
 
-    std::transform(std::begin(localIndex), std::end(localIndex), std::begin(amplitude_),
-                   [&atoms](gmx::index index) { return atoms.chargeA[index]; });
+    std::transform(std::begin(localIndex),
+                   std::end(localIndex),
+                   std::begin(amplitude_),
+                   [&chargeA](gmx::index index) { return chargeA[index]; });
     return amplitude_;
 }
 
@@ -133,7 +145,9 @@ public:
     MassesAsAmplitudes(const MassesAsAmplitudes&) = default;
     ~MassesAsAmplitudes() override                = default;
     std::unique_ptr<DensityFittingAmplitudeLookupImpl> clone() override;
-    const std::vector<real>& operator()(const t_mdatoms& atoms, ArrayRef<const int> localIndex) override;
+    const std::vector<real>&                           operator()(ArrayRef<const real> /*chargeA*/,
+                                        ArrayRef<const real> massT,
+                                        ArrayRef<const int>  localIndex) override;
 
 private:
     std::vector<real> amplitude_;
@@ -144,15 +158,19 @@ std::unique_ptr<DensityFittingAmplitudeLookupImpl> MassesAsAmplitudes::clone()
     return std::make_unique<MassesAsAmplitudes>(*this);
 };
 
-const std::vector<real>& MassesAsAmplitudes::operator()(const t_mdatoms& atoms, ArrayRef<const int> localIndex)
+const std::vector<real>& MassesAsAmplitudes::operator()(ArrayRef<const real> /*chargeA*/,
+                                                        ArrayRef<const real> massT,
+                                                        ArrayRef<const int>  localIndex)
 {
     if (amplitude_.size() != localIndex.size())
     {
         amplitude_.resize(localIndex.size());
     }
 
-    std::transform(std::begin(localIndex), std::end(localIndex), std::begin(amplitude_),
-                   [&atoms](gmx::index index) { return atoms.massT[index]; });
+    std::transform(std::begin(localIndex),
+                   std::end(localIndex),
+                   std::begin(amplitude_),
+                   [&massT](gmx::index index) { return massT[index]; });
     return amplitude_;
 }
 
@@ -180,10 +198,11 @@ DensityFittingAmplitudeLookup::DensityFittingAmplitudeLookup(const DensityFittin
     }
 }
 
-const std::vector<real>& DensityFittingAmplitudeLookup::operator()(const t_mdatoms&    atoms,
-                                                                   ArrayRef<const int> localIndex)
+const std::vector<real>& DensityFittingAmplitudeLookup::operator()(ArrayRef<const real> chargeA,
+                                                                   ArrayRef<const real> massT,
+                                                                   ArrayRef<const int>  localIndex)
 {
-    return (*impl_)(atoms, localIndex);
+    return (*impl_)(chargeA, massT, localIndex);
 }
 
 DensityFittingAmplitudeLookup::~DensityFittingAmplitudeLookup() = default;
index 86675bcec649c882f9021e06867e2d569bcd3561..92b21f1e2b5505055631f33159c4a23c094c628d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +49,6 @@
 #include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/real.h"
 
-struct t_mdatoms;
-
 namespace gmx
 {
 
@@ -88,11 +86,14 @@ public:
     //! Move assignment
     DensityFittingAmplitudeLookup& operator=(DensityFittingAmplitudeLookup&& other) noexcept;
     /*! \brief Return the amplitudes for spreading atoms of a given local index.
-     * \param[in] atoms the atom information
+     * \param[in] chargeA Atom charges
+     * \param[in] massT   Atom masses.
      * \param[in] localIndex the local atom indices
      * \returns amplitudes
      */
-    const std::vector<real>& operator()(const t_mdatoms& atoms, ArrayRef<const int> localIndex);
+    const std::vector<real>& operator()(ArrayRef<const real> chargeA,
+                                        ArrayRef<const real> massT,
+                                        ArrayRef<const int>  localIndex);
 
 private:
     std::unique_ptr<DensityFittingAmplitudeLookupImpl> impl_;
index c2442bbd385e01be8f3b46b27b7ff99ea6501f66..9a4f5d7e86bd033a6cf058f672767c4e0bb9644c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -79,8 +79,7 @@ GaussianSpreadKernelParameters::Shape makeSpreadKernel(real sigma, real nSigma,
 {
     RVec sigmaInLatticeCoordinates{ sigma, sigma, sigma };
     scaleToLattice(&sigmaInLatticeCoordinates);
-    return { DVec{ sigmaInLatticeCoordinates[XX], sigmaInLatticeCoordinates[YY],
-                   sigmaInLatticeCoordinates[ZZ] },
+    return { DVec{ sigmaInLatticeCoordinates[XX], sigmaInLatticeCoordinates[YY], sigmaInLatticeCoordinates[ZZ] },
              nSigma };
 }
 
@@ -102,10 +101,10 @@ const std::string DensityFittingForceProviderState::stepsSinceLastCalculationNam
 void DensityFittingForceProviderState::writeState(KeyValueTreeObjectBuilder kvtBuilder,
                                                   const std::string&        identifier) const
 {
-    writeKvtCheckpointValue(stepsSinceLastCalculation_, stepsSinceLastCalculationName_, identifier,
-                            kvtBuilder);
-    writeKvtCheckpointValue(adaptiveForceConstantScale_, adaptiveForceConstantScaleName_,
-                            identifier, kvtBuilder);
+    writeKvtCheckpointValue(
+            stepsSinceLastCalculation_, stepsSinceLastCalculationName_, identifier, kvtBuilder);
+    writeKvtCheckpointValue(
+            adaptiveForceConstantScale_, adaptiveForceConstantScaleName_, identifier, kvtBuilder);
 
     KeyValueTreeObjectBuilder exponentialMovingAverageKvtEntry =
             kvtBuilder.addObject(identifier + "-" + exponentialMovingAverageStateName_);
@@ -117,9 +116,13 @@ void DensityFittingForceProviderState::readState(const KeyValueTreeObject& kvtDa
                                                  const std::string&        identifier)
 {
     readKvtCheckpointValue(compat::make_not_null(&stepsSinceLastCalculation_),
-                           stepsSinceLastCalculationName_, identifier, kvtData);
+                           stepsSinceLastCalculationName_,
+                           identifier,
+                           kvtData);
     readKvtCheckpointValue(compat::make_not_null(&adaptiveForceConstantScale_),
-                           adaptiveForceConstantScaleName_, identifier, kvtData);
+                           adaptiveForceConstantScaleName_,
+                           identifier,
+                           kvtData);
 
     if (kvtData.keyExists(identifier + "-" + exponentialMovingAverageStateName_))
     {
@@ -266,7 +269,8 @@ void DensityFittingForceProvider::Impl::calculateForces(const ForceProviderInput
 
     transformedCoordinates_.resize(localAtomSet_.numAtomsLocal());
     // pick and copy atom coordinates
-    std::transform(std::cbegin(localAtomSet_.localIndex()), std::cend(localAtomSet_.localIndex()),
+    std::transform(std::cbegin(localAtomSet_.localIndex()),
+                   std::cend(localAtomSet_.localIndex()),
                    std::begin(transformedCoordinates_),
                    [&forceProviderInput](int index) { return forceProviderInput.x_[index]; });
 
@@ -294,8 +298,8 @@ void DensityFittingForceProvider::Impl::calculateForces(const ForceProviderInput
     // spread atoms on grid
     gaussTransform_.setZero();
 
-    std::vector<real> amplitudes =
-            amplitudeLookup_(forceProviderInput.mdatoms_, localAtomSet_.localIndex());
+    std::vector<real> amplitudes = amplitudeLookup_(
+            forceProviderInput.chargeA_, forceProviderInput.massT_, localAtomSet_.localIndex());
 
     if (parameters_.normalizeDensities_)
     {
@@ -323,7 +327,8 @@ void DensityFittingForceProvider::Impl::calculateForces(const ForceProviderInput
     {
         // \todo update to real once GaussTransform class returns real
         gmx_sumf(gaussTransform_.view().mapping().required_span_size(),
-                 gaussTransform_.view().data(), &forceProviderInput.cr_);
+                 gaussTransform_.view().data(),
+                 &forceProviderInput.cr_);
     }
 
     // calculate grid derivative
@@ -332,8 +337,11 @@ void DensityFittingForceProvider::Impl::calculateForces(const ForceProviderInput
     // calculate forces
     forces_.resize(localAtomSet_.numAtomsLocal());
     std::transform(
-            std::begin(transformedCoordinates_), std::end(transformedCoordinates_), std::begin(amplitudes),
-            std::begin(forces_), [&densityDerivative, this](const RVec r, real amplitude) {
+            std::begin(transformedCoordinates_),
+            std::end(transformedCoordinates_),
+            std::begin(amplitudes),
+            std::begin(forces_),
+            [&densityDerivative, this](const RVec r, real amplitude) {
                 return densityFittingForce_.evaluateForce({ r, amplitude }, densityDerivative);
             });
 
@@ -409,7 +417,7 @@ void DensityFittingForceProvider::calculateForces(const ForceProviderInput& forc
     impl_->calculateForces(forceProviderInput, forceProviderOutput);
 }
 
-void DensityFittingForceProvider::writeCheckpointData(MdModulesWriteCheckpointData checkpointWriting,
+void DensityFittingForceProvider::writeCheckpointData(MDModulesWriteCheckpointData checkpointWriting,
                                                       const std::string&           moduleName)
 {
     impl_->stateToCheckpoint().writeState(checkpointWriting.builder_, moduleName);
index 98616ebd97c2d7b13f4b8e715de07fec3b984c78..c31d1a694d145f82ee6a8570e8c7911da21d44ea 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@
 #include "gromacs/math/exponentialmovingaverage.h"
 #include "gromacs/mdspan/extensions.h"
 #include "gromacs/mdtypes/iforceprovider.h"
-#include "gromacs/utility/classhelpers.h"
 
 enum class PbcType : int;
 
@@ -143,11 +142,11 @@ public:
      * \note The provided state to checkpoint has to change if checkpointing
      *       is moved before the force provider call in the MD-loop.
      */
-    void writeCheckpointData(MdModulesWriteCheckpointData checkpointWriting, const std::string& moduleName);
+    void writeCheckpointData(MDModulesWriteCheckpointData checkpointWriting, const std::string& moduleName);
 
 private:
     class Impl;
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index a3cb45794be772bde3c13ef916b7c9f60d2238cc..b7693599fec0348729fb85874d49aca391d13404 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/exceptions.h"
 #include "gromacs/utility/keyvaluetreebuilder.h"
 #include "gromacs/utility/keyvaluetreetransform.h"
-#include "gromacs/utility/mdmodulenotification.h"
+#include "gromacs/utility/mdmodulesnotifiers.h"
 #include "gromacs/utility/strconvert.h"
 
 #include "densityfittingamplitudelookup.h"
@@ -130,37 +130,39 @@ void DensityFittingOptions::initMdpTransform(IKeyValueTreeTransformRules* rules)
     const auto& stringIdentityTransform = [](std::string s) { return s; };
     densityfittingMdpTransformFromString<bool>(rules, &fromStdString<bool>, c_activeTag_);
     densityfittingMdpTransformFromString<std::string>(rules, stringIdentityTransform, c_groupTag_);
-    densityfittingMdpTransformFromString<std::string>(rules, stringIdentityTransform,
-                                                      c_similarityMeasureTag_);
+    densityfittingMdpTransformFromString<std::string>(
+            rules, stringIdentityTransform, c_similarityMeasureTag_);
     densityfittingMdpTransformFromString<std::string>(rules, stringIdentityTransform, c_amplitudeMethodTag_);
     densityfittingMdpTransformFromString<real>(rules, &fromStdString<real>, c_forceConstantTag_);
-    densityfittingMdpTransformFromString<real>(rules, &fromStdString<real>,
-                                               c_gaussianTransformSpreadingWidthTag_);
+    densityfittingMdpTransformFromString<real>(
+            rules, &fromStdString<real>, c_gaussianTransformSpreadingWidthTag_);
     densityfittingMdpTransformFromString<real>(
             rules, &fromStdString<real>, c_gaussianTransformSpreadingRangeInMultiplesOfWidthTag_);
-    densityfittingMdpTransformFromString<std::string>(rules, stringIdentityTransform,
-                                                      c_referenceDensityFileNameTag_);
-    densityfittingMdpTransformFromString<std::int64_t>(rules, &fromStdString<std::int64_t>,
-                                                       c_everyNStepsTag_);
+    densityfittingMdpTransformFromString<std::string>(
+            rules, stringIdentityTransform, c_referenceDensityFileNameTag_);
+    densityfittingMdpTransformFromString<std::int64_t>(
+            rules, &fromStdString<std::int64_t>, c_everyNStepsTag_);
     densityfittingMdpTransformFromString<bool>(rules, &fromStdString<bool>, c_normalizeDensitiesTag_);
     densityfittingMdpTransformFromString<bool>(rules, &fromStdString<bool>, c_adaptiveForceScalingTag_);
-    densityfittingMdpTransformFromString<real>(rules, &fromStdString<real>,
-                                               c_adaptiveForceScalingTimeConstantTag_);
+    densityfittingMdpTransformFromString<real>(
+            rules, &fromStdString<real>, c_adaptiveForceScalingTimeConstantTag_);
     const auto& stringRVecToStringRVecWithCheck = [](const std::string& str) {
         return stringIdentityTransformWithArrayCheck<real, 3>(
-                str, "Reading three real values as vector while parsing the .mdp input failed in "
-                             + DensityFittingModuleInfo::name_ + ".");
+                str,
+                "Reading three real values as vector while parsing the .mdp input failed in "
+                        + DensityFittingModuleInfo::name_ + ".");
     };
-    densityfittingMdpTransformFromString<std::string>(rules, stringRVecToStringRVecWithCheck,
-                                                      c_translationTag_);
+    densityfittingMdpTransformFromString<std::string>(
+            rules, stringRVecToStringRVecWithCheck, c_translationTag_);
 
     const auto& stringMatrixToStringMatrixWithCheck = [](const std::string& str) {
         return stringIdentityTransformWithArrayCheck<real, 9>(
-                str, "Reading nine real values as vector while parsing the .mdp input failed in "
-                             + DensityFittingModuleInfo::name_ + ".");
+                str,
+                "Reading nine real values as vector while parsing the .mdp input failed in "
+                        + DensityFittingModuleInfo::name_ + ".");
     };
-    densityfittingMdpTransformFromString<std::string>(rules, stringMatrixToStringMatrixWithCheck,
-                                                      c_transformationMatrixTag_);
+    densityfittingMdpTransformFromString<std::string>(
+            rules, stringMatrixToStringMatrixWithCheck, c_transformationMatrixTag_);
 }
 
 //! Name the methods that may be used to evaluate similarity between densities
@@ -189,20 +191,23 @@ void DensityFittingOptions::buildMdpOutput(KeyValueTreeObjectBuilder* builder) c
                 "cross-correlation",
                 c_similarityMeasureTag_);
         addDensityFittingMdpOutputValue<std::string>(
-                builder, c_densitySimilarityMeasureMethodNames[parameters_.similarityMeasureMethod_],
+                builder,
+                c_densitySimilarityMeasureMethodNames[parameters_.similarityMeasureMethod_],
                 c_similarityMeasureTag_);
 
         addDensityFittingMdpOutputValueComment(
-                builder, "; Atom amplitude for spreading onto grid: unity, mass, or charge",
-                c_amplitudeMethodTag_);
+                builder, "; Atom amplitude for spreading onto grid: unity, mass, or charge", c_amplitudeMethodTag_);
         addDensityFittingMdpOutputValue<std::string>(
-                builder, c_densityFittingAmplitudeMethodNames[parameters_.amplitudeLookupMethod_],
+                builder,
+                c_densityFittingAmplitudeMethodNames[parameters_.amplitudeLookupMethod_],
                 c_amplitudeMethodTag_);
 
         addDensityFittingMdpOutputValue(builder, parameters_.forceConstant_, c_forceConstantTag_);
-        addDensityFittingMdpOutputValue(builder, parameters_.gaussianTransformSpreadingWidth_,
+        addDensityFittingMdpOutputValue(builder,
+                                        parameters_.gaussianTransformSpreadingWidth_,
                                         c_gaussianTransformSpreadingWidthTag_);
-        addDensityFittingMdpOutputValue(builder, parameters_.gaussianTransformSpreadingRangeInMultiplesOfWidth_,
+        addDensityFittingMdpOutputValue(builder,
+                                        parameters_.gaussianTransformSpreadingRangeInMultiplesOfWidth_,
                                         c_gaussianTransformSpreadingRangeInMultiplesOfWidthTag_);
         addDensityFittingMdpOutputValueComment(builder,
                                                "; Reference density file location as absolute path "
@@ -213,14 +218,15 @@ void DensityFittingOptions::buildMdpOutput(KeyValueTreeObjectBuilder* builder) c
         addDensityFittingMdpOutputValueComment(
                 builder, "; Normalize the sum of density voxel values to one", c_normalizeDensitiesTag_);
         addDensityFittingMdpOutputValue(builder, parameters_.normalizeDensities_, c_normalizeDensitiesTag_);
-        addDensityFittingMdpOutputValueComment(builder, "; Apply adaptive force scaling",
-                                               c_adaptiveForceScalingTag_);
-        addDensityFittingMdpOutputValue(builder, parameters_.adaptiveForceScaling_,
-                                        c_adaptiveForceScalingTag_);
+        addDensityFittingMdpOutputValueComment(
+                builder, "; Apply adaptive force scaling", c_adaptiveForceScalingTag_);
+        addDensityFittingMdpOutputValue(
+                builder, parameters_.adaptiveForceScaling_, c_adaptiveForceScalingTag_);
         addDensityFittingMdpOutputValueComment(builder,
                                                "; Time constant for adaptive force scaling in ps",
                                                c_adaptiveForceScalingTimeConstantTag_);
-        addDensityFittingMdpOutputValue(builder, parameters_.adaptiveForceScalingTimeConstant_,
+        addDensityFittingMdpOutputValue(builder,
+                                        parameters_.adaptiveForceScalingTimeConstant_,
                                         c_adaptiveForceScalingTimeConstantTag_);
     }
 }
@@ -306,7 +312,9 @@ void DensityFittingOptions::readInternalParametersFromKvt(const KeyValueTreeObje
     }
     auto kvtIndexArray = tree[DensityFittingModuleInfo::name_ + "-" + c_groupTag_].asArray().values();
     parameters_.indices_.resize(kvtIndexArray.size());
-    std::transform(std::begin(kvtIndexArray), std::end(kvtIndexArray), std::begin(parameters_.indices_),
+    std::transform(std::begin(kvtIndexArray),
+                   std::end(kvtIndexArray),
+                   std::begin(parameters_.indices_),
                    [](const KeyValueTreeValue& val) { return val.cast<std::int64_t>(); });
 }
 
index 0e123ef5bc4efc1a4b5df76871b1e2f886c83016..f6dc43ae956b53307824369bf18c2056ff8fffdc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +83,9 @@ struct DensityFittingParameters
     //! The time constant for the adaptive force scaling in ps
     real adaptiveForceScalingTimeConstant_ = 4;
     //! Translation of the structure, so that the coordinates that are fitted are x+translation
-    std::string translationString_ = "";
+    std::string translationString_;
     //! Linear transformation of the structure, so that the coordinates that are fitted are Matrix * x
-    std::string transformationMatrixString_ = "";
+    std::string transformationMatrixString_;
 };
 
 /*!\brief Check if two structs holding density fitting parameters are equal.
diff --git a/src/gromacs/applied_forces/densityfitting/tests/.clang-tidy b/src/gromacs/applied_forces/densityfitting/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index f9b09904e207956a373a2d65b69b05c1208151c5..36e6e3a1e9633935020d2ef88428b7b4c8db3aca 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/options/treesupport.h"
 #include "gromacs/utility/keyvaluetreebuilder.h"
 #include "gromacs/utility/keyvaluetreetransform.h"
-#include "gromacs/utility/mdmodulenotification.h"
+#include "gromacs/utility/mdmodulesnotifiers.h"
 #include "gromacs/utility/real.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringcompare.h"
@@ -78,8 +78,7 @@ class DensityFittingTest : public ::testing::Test
 public:
     void addMdpOptionDensityFittingActive()
     {
-        mdpValueBuilder_.rootObject().addValue("density-guided-simulation-active",
-                                               std::string("yes"));
+        mdpValueBuilder_.rootObject().addValue("density-guided-simulation-active", std::string("yes"));
     }
 
     void addMdpOptionReferenceDensity()
index d0eeb3a9e3df47523225265a2395f97fc85d05e5..7ffc527d22bbf8753d85be0f5524363ac3356ae6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,14 +55,6 @@ namespace gmx
 
 class DensityFittingAmplitudeLookupTest : public ::testing::Test
 {
-public:
-    DensityFittingAmplitudeLookupTest()
-    {
-        atoms_.nr      = numberOfAtoms_;
-        atoms_.massT   = masses_.data();
-        atoms_.chargeA = charges_.data();
-    }
-
 protected:
     int               numberOfAtoms_ = 3;
     std::vector<real> masses_        = { 2, 3, 4 };
@@ -74,7 +66,7 @@ protected:
 TEST_F(DensityFittingAmplitudeLookupTest, Unity)
 {
     DensityFittingAmplitudeLookup lookup(DensityFittingAmplitudeMethod::Unity);
-    const auto                    lookupResult = lookup(atoms_, lookupIndices_);
+    const auto                    lookupResult = lookup(charges_, masses_, lookupIndices_);
     EXPECT_EQ(lookupResult[0], 1);
     EXPECT_EQ(lookupResult[1], 1);
 }
@@ -82,7 +74,7 @@ TEST_F(DensityFittingAmplitudeLookupTest, Unity)
 TEST_F(DensityFittingAmplitudeLookupTest, Charge)
 {
     DensityFittingAmplitudeLookup lookup(DensityFittingAmplitudeMethod::Charge);
-    const auto                    lookupResult = lookup(atoms_, lookupIndices_);
+    const auto                    lookupResult = lookup(charges_, masses_, lookupIndices_);
     EXPECT_EQ(lookupResult[0], 30);
     EXPECT_EQ(lookupResult[1], 40);
 }
@@ -90,7 +82,7 @@ TEST_F(DensityFittingAmplitudeLookupTest, Charge)
 TEST_F(DensityFittingAmplitudeLookupTest, Masses)
 {
     DensityFittingAmplitudeLookup lookup(DensityFittingAmplitudeMethod::Mass);
-    const auto                    lookupResult = lookup(atoms_, lookupIndices_);
+    const auto                    lookupResult = lookup(charges_, masses_, lookupIndices_);
     EXPECT_EQ(lookupResult[0], 3);
     EXPECT_EQ(lookupResult[1], 4);
 }
@@ -99,7 +91,7 @@ TEST_F(DensityFittingAmplitudeLookupTest, CanCopyAssign)
 {
     DensityFittingAmplitudeLookup lookup(DensityFittingAmplitudeMethod::Unity);
     DensityFittingAmplitudeLookup lookupCopied = lookup;
-    const auto                    lookupResult = lookupCopied(atoms_, lookupIndices_);
+    const auto                    lookupResult = lookupCopied(charges_, masses_, lookupIndices_);
     EXPECT_EQ(lookupResult[0], 1);
     EXPECT_EQ(lookupResult[1], 1);
 }
@@ -108,7 +100,7 @@ TEST_F(DensityFittingAmplitudeLookupTest, CanCopyConstruct)
 {
     DensityFittingAmplitudeLookup lookup(DensityFittingAmplitudeMethod::Unity);
     DensityFittingAmplitudeLookup lookupCopied(lookup);
-    const auto                    lookupResult = lookupCopied(atoms_, lookupIndices_);
+    const auto                    lookupResult = lookupCopied(charges_, masses_, lookupIndices_);
     EXPECT_EQ(lookupResult[0], 1);
     EXPECT_EQ(lookupResult[1], 1);
 }
@@ -117,7 +109,7 @@ TEST_F(DensityFittingAmplitudeLookupTest, CanMoveAssign)
 {
     DensityFittingAmplitudeLookup lookup(DensityFittingAmplitudeMethod::Unity);
     DensityFittingAmplitudeLookup lookupCopied = std::move(lookup);
-    const auto                    lookupResult = lookupCopied(atoms_, lookupIndices_);
+    const auto                    lookupResult = lookupCopied(charges_, masses_, lookupIndices_);
     EXPECT_EQ(lookupResult[0], 1);
     EXPECT_EQ(lookupResult[1], 1);
 }
@@ -126,7 +118,7 @@ TEST_F(DensityFittingAmplitudeLookupTest, CanMoveConstruct)
 {
     DensityFittingAmplitudeLookup lookup(DensityFittingAmplitudeMethod::Unity);
     DensityFittingAmplitudeLookup lookupCopied(std::move(lookup));
-    const auto                    lookupResult = lookupCopied(atoms_, lookupIndices_);
+    const auto                    lookupResult = lookupCopied(charges_, masses_, lookupIndices_);
     EXPECT_EQ(lookupResult[0], 1);
     EXPECT_EQ(lookupResult[1], 1);
 }
index 54600746e0efd28520721b49e99640d47f9db5e1..e6d04175ce7d2f6b4f334fad7237aa48f96415a4 100644 (file)
@@ -95,8 +95,7 @@ public:
     {
         // Prepare MDP inputs
         KeyValueTreeBuilder mdpValueBuilder;
-        mdpValueBuilder.rootObject().addValue("density-guided-simulation-active",
-                                              std::string("yes"));
+        mdpValueBuilder.rootObject().addValue("density-guided-simulation-active", std::string("yes"));
         return mdpValueBuilder.build();
     }
 
@@ -104,8 +103,9 @@ public:
     {
         done_blocka(&defaultGroups_);
         stupid_fill_blocka(&defaultGroups_, 3);
-        std::vector<std::string> groupNames   = { "A", "protein", "C" };
-        const char* const namesAsConstChar[3] = { groupNames[0].c_str(), groupNames[1].c_str(),
+        std::vector<std::string> groupNames          = { "A", "protein", "C" };
+        const char* const        namesAsConstChar[3] = { groupNames[0].c_str(),
+                                                  groupNames[1].c_str(),
                                                   groupNames[2].c_str() };
         return { defaultGroups_, namesAsConstChar };
     }
@@ -114,8 +114,9 @@ public:
     {
         done_blocka(&defaultGroups_);
         stupid_fill_blocka(&defaultGroups_, 3);
-        std::vector<std::string> groupNames   = { "protein", "C", "A" };
-        const char* const namesAsConstChar[3] = { groupNames[0].c_str(), groupNames[1].c_str(),
+        std::vector<std::string> groupNames          = { "protein", "C", "A" };
+        const char* const        namesAsConstChar[3] = { groupNames[0].c_str(),
+                                                  groupNames[1].c_str(),
                                                   groupNames[2].c_str() };
         return { defaultGroups_, namesAsConstChar };
     }
index 9ebb7cb21f4805c602d521ddc2df72a34580a810..ab3a5f0b8f16e7f4fc7c372e18c48ac20f8f45fc 100644 (file)
@@ -59,7 +59,6 @@
 #include "gromacs/mdtypes/imdmodule.h"
 #include "gromacs/mdtypes/imdoutputprovider.h"
 #include "gromacs/mdtypes/imdpoptionprovider.h"
-#include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/options/ioptionscontainerwithsections.h"
 #include "gromacs/options/optionsection.h"
@@ -178,8 +177,8 @@ public:
     void calculateForces(const ForceProviderInput& forceProviderInput,
                          ForceProviderOutput*      forceProviderOutput) override;
 
-    void subscribeToSimulationSetupNotifications(MdModulesNotifier* /* notifier */) override {}
-    void subscribeToPreProcessingNotifications(MdModulesNotifier* /* notifier */) override {}
+    void subscribeToSimulationSetupNotifications(MDModulesNotifiers* /* notifiers */) override {}
+    void subscribeToPreProcessingNotifications(MDModulesNotifiers* /* notifiers */) override {}
 
 private:
     //! Return whether or not to apply a field
@@ -268,8 +267,11 @@ void ElectricField::initOutput(FILE* fplog, int nfile, const t_filenm fnm[], boo
             }
             else
             {
-                fpField_ = xvgropen(opt2fn("-field", nfile, fnm), "Applied electric field",
-                                    "Time (ps)", "E (V/nm)", oenv);
+                fpField_ = xvgropen(opt2fn("-field", nfile, fnm),
+                                    "Applied electric field",
+                                    "Time (ps)",
+                                    "E (V/nm)",
+                                    oenv);
             }
         }
     }
@@ -306,24 +308,24 @@ void ElectricField::calculateForces(const ForceProviderInput& forceProviderInput
 {
     if (isActive())
     {
-        const t_mdatoms& mdatoms = forceProviderInput.mdatoms_;
-        const double     t       = forceProviderInput.t_;
-        const t_commrec& cr      = forceProviderInput.cr_;
+        const double     t  = forceProviderInput.t_;
+        const t_commrec& cr = forceProviderInput.cr_;
 
         // NOTE: The non-conservative electric field does not have a virial
         ArrayRef<RVec> f = forceProviderOutput->forceWithVirial_.force_;
 
+        auto chargeA = forceProviderInput.chargeA_;
         for (int m = 0; (m < DIM); m++)
         {
-            const real fieldStrength = FIELDFAC * field(m, t);
+            const real fieldStrength = gmx::c_fieldfac * field(m, t);
 
             if (fieldStrength != 0)
             {
                 // TODO: Check parallellism
-                for (int i = 0; i < mdatoms.homenr; ++i)
+                for (int i = 0; i < forceProviderInput.homenr_; ++i)
                 {
                     // NOTE: Not correct with perturbed charges
-                    f[i][m] += mdatoms.chargeA[i] * fieldStrength;
+                    f[i][m] += chargeA[i] * fieldStrength;
                 }
             }
         }
diff --git a/src/gromacs/applied_forces/tests/.clang-tidy b/src/gromacs/applied_forces/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 8e19955ae37654f42471b1793933e171251ec962..fc514edae3e9d995fe3f6b9f82740b3f87013bb0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -106,13 +106,10 @@ public:
         }
 
         // Prepare a ForceProviderInput
-        t_mdatoms         md;
-        std::vector<real> chargeA{ 1 };
-        md.homenr  = ssize(chargeA);
-        md.chargeA = chargeA.data();
+        std::vector<real>  chargeA{ 1 };
         t_commrec          cr;
         matrix             boxDummy = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } };
-        ForceProviderInput forceProviderInput({}, md, 0.0, boxDummy, cr);
+        ForceProviderInput forceProviderInput({}, ssize(chargeA), chargeA, {}, 0.0, boxDummy, cr);
 
         // Prepare a ForceProviderOutput
         PaddedVector<RVec>  f = { { 0, 0, 0 } };
index 990e2f1233f6a283a19d0fdca5f2eaded86d699e..86078c36d79704de728a613d732e9b30d02c309c 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2012,2013,2014,2015,2019, by the GROMACS development team, led by
+# Copyright (c) 2012,2013,2014,2015,2019,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+add_library(commandline INTERFACE)
 file(GLOB COMMANDLINE_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${COMMANDLINE_SOURCES} PARENT_SCOPE)
 
+# Source files have the following private module dependencies.
+target_link_libraries(commandline PRIVATE
+#                      gmxlib
+#                      math
+#                      mdtypes
+#                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(commandline PUBLIC
+target_include_directories(commandline INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(commandline PUBLIC
+target_link_libraries(commandline INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when commandline is an OBJECT target
+#target_link_libraries(commandline PUBLIC legacy_api)
+#target_link_libraries(commandline PRIVATE common)
+
+# Module dependencies
+# commandline interfaces convey transitive dependence on these modules.
+#target_link_libraries(commandline PUBLIC
+target_link_libraries(commandline INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(commandline PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(commandline PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index aa7216cb5bf10127cafeab529ef461125fe702e1..04abd8681705843c318cffd5ac7ba0a14120ad4d 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -62,6 +62,7 @@ namespace
  *
  * \ingroup module_commandline
  */
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 const CommandLineHelpContext* g_globalContext = nullptr;
 
 } // namespace
index a2158603a93206f110bcf68f3144d8cf1bfc26d5..59d82bedb3d040bcd5296ae9749e785e404ef3bf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_COMMANDLINE_CMDLINEHELPCONTEXT_H
 #define GMX_COMMANDLINE_CMDLINEHELPCONTEXT_H
 
+#include <memory>
 #include <string>
 
 #include "gromacs/onlinehelp/helpwritercontext.h"
@@ -127,7 +128,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     GMX_DISALLOW_ASSIGN(CommandLineHelpContext);
 };
index 95b4acfa61fe15c5591075a849b0f77e7338b12c..4518c54515e7f9d2d49d346a99d21e20833b79c0 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +59,7 @@
 #include "gromacs/options/options.h"
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/baseversion.h"
+#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fileredirector.h"
 #include "gromacs/utility/gmxassert.h"
@@ -528,7 +529,8 @@ HelpExportReStructuredText::HelpExportReStructuredText(const CommandLineHelpModu
     while (linksFile.readLine(&line))
     {
         links_.addLink("[REF]." + line + "[ref]",
-                       formatString(":ref:`.%s <%s>`", line.c_str(), line.c_str()), line);
+                       formatString(":ref:`.%s <%s>`", line.c_str(), line.c_str()),
+                       line);
         links_.addLink("[REF]" + line + "[ref]", formatString(":ref:`%s`", line.c_str()), line);
     }
     linksFile.close();
@@ -539,8 +541,8 @@ void HelpExportReStructuredText::startModuleExport()
 {
     indexFile_ = std::make_unique<TextWriter>(
             outputRedirector_->openTextOutputFile("fragments/byname.rst"));
-    indexFile_->writeLine(formatString("* :doc:`%s </onlinehelp/%s>` - %s", binaryName_.c_str(),
-                                       binaryName_.c_str(), RootHelpText::title));
+    indexFile_->writeLine(formatString(
+            "* :doc:`%s </onlinehelp/%s>` - %s", binaryName_.c_str(), binaryName_.c_str(), RootHelpText::title));
     manPagesFile_ =
             std::make_unique<TextWriter>(outputRedirector_->openTextOutputFile("conf-man.py"));
     manPagesFile_->writeLine("man_pages = [");
@@ -554,12 +556,6 @@ void HelpExportReStructuredText::exportModuleHelp(const ICommandLineModule& modu
             outputRedirector_->openTextOutputFile("onlinehelp/" + tag + ".rst");
     TextWriter writer(file);
     writer.writeLine(formatString(".. _%s:", displayName.c_str()));
-    if (displayName == binaryName_ + " mdrun")
-    {
-        // Make an extra link target for the convenience of
-        // MPI-specific documentation
-        writer.writeLine(".. _mdrun_mpi:");
-    }
     writer.ensureEmptyLine();
 
     CommandLineHelpContext context(&writer, eHelpOutputFormat_Rst, &links_, binaryName_);
@@ -579,10 +575,12 @@ void HelpExportReStructuredText::exportModuleHelp(const ICommandLineModule& modu
             "   More information about |Gromacs| is available at <http://www.gromacs.org/>.");
     file->close();
 
-    indexFile_->writeLine(formatString("* :doc:`%s </onlinehelp/%s>` - %s", displayName.c_str(),
-                                       tag.c_str(), module.shortDescription()));
+    indexFile_->writeLine(formatString(
+            "* :doc:`%s </onlinehelp/%s>` - %s", displayName.c_str(), tag.c_str(), module.shortDescription()));
     manPagesFile_->writeLine(formatString("    ('onlinehelp/%s', '%s', \"%s\", '', 1),",
-                                          tag.c_str(), tag.c_str(), module.shortDescription()));
+                                          tag.c_str(),
+                                          tag.c_str(),
+                                          module.shortDescription()));
 }
 
 void HelpExportReStructuredText::finishModuleExport()
@@ -591,7 +589,9 @@ void HelpExportReStructuredText::finishModuleExport()
     indexFile_.reset();
     // TODO: Generalize.
     manPagesFile_->writeLine(formatString("    ('onlinehelp/%s', '%s', '%s', '', 1)",
-                                          binaryName_.c_str(), binaryName_.c_str(), RootHelpText::title));
+                                          binaryName_.c_str(),
+                                          binaryName_.c_str(),
+                                          RootHelpText::title));
     manPagesFile_->writeLine("]");
     manPagesFile_->close();
     manPagesFile_.reset();
@@ -625,8 +625,8 @@ void HelpExportReStructuredText::exportModuleGroup(const char* title, const Modu
         GMX_RELEASE_ASSERT(dashPos != std::string::npos,
                            "There should always be at least one dash in the tag");
         displayName[dashPos] = ' ';
-        indexFile_->writeLine(formatString(":doc:`%s </onlinehelp/%s>`\n  %s", displayName.c_str(),
-                                           tag.c_str(), module->second));
+        indexFile_->writeLine(formatString(
+                ":doc:`%s </onlinehelp/%s>`\n  %s", displayName.c_str(), tag.c_str(), module->second));
         manPagesFile_->writeLine(formatString(":manpage:`%s(1)`\n  %s", tag.c_str(), module->second));
     }
 }
index aebdf285f8297123f21896651c49550ea5743655..9b32961ca4b8c1c9d2790e1dc078e75d9c615a2a 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_COMMANDLINE_CMDLINEHELPMODULE_H
 #define GMX_COMMANDLINE_CMDLINEHELPMODULE_H
 
+#include <memory>
+
 #include "gromacs/commandline/cmdlinemodule.h"
 #include "gromacs/onlinehelp/ihelptopic.h"
-#include "gromacs/utility/classhelpers.h"
 
 #include "cmdlinemodulemanager_impl.h"
 
@@ -134,7 +135,7 @@ public:
 private:
     typedef CommandLineHelpModuleImpl Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index df9bc173f450b6bc5249e903e387f368bc7397e3..bd03eebe65bee7f62ca83599a3b5e80a51eaa4bb 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -548,8 +548,8 @@ void CommandLineHelpWriter::writeHelp(const CommandLineHelpContext& context)
         SynopsisFormatter synopsisFormatter(writerContext);
         synopsisFormatter.start(context.moduleDisplayName());
         filter.formatSelected(OptionsFilter::eSelectInputFileOptions, &synopsisFormatter, impl_->options_);
-        filter.formatSelected(OptionsFilter::eSelectInputOutputFileOptions, &synopsisFormatter,
-                              impl_->options_);
+        filter.formatSelected(
+                OptionsFilter::eSelectInputOutputFileOptions, &synopsisFormatter, impl_->options_);
         filter.formatSelected(OptionsFilter::eSelectOutputFileOptions, &synopsisFormatter, impl_->options_);
         filter.formatSelected(OptionsFilter::eSelectOtherOptions, &synopsisFormatter, impl_->options_);
         synopsisFormatter.finish();
index 051790201dff7b8d65f2eb3ebb9685e4d6c0f3a4..8f6ac37b27ad2c103967ac7e12c96c1e1450d179 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2015,2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_COMMANDLINE_CMDLINEHELPWRITER_H
 #define GMX_COMMANDLINE_CMDLINEHELPWRITER_H
 
+#include <memory>
 #include <string>
 
-#include "gromacs/utility/classhelpers.h"
-
 namespace gmx
 {
 
@@ -120,7 +119,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index f94da3846deef62dc8fe60e05ad25db17b920c1b..ee3492b7fc82c50ca565078eb14f5974a717c461 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +72,10 @@ namespace
 
 // These never release ownership.
 //! Global context instance initialized in initForCommandLine().
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 std::unique_ptr<CommandLineProgramContext> g_commandLineContext;
 //! Global library data file finder that respects GMXLIB.
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 std::unique_ptr<DataFileFinder> g_libFileFinder;
 
 /*! \brief
index f810043f5d318eda1292137f660a2562dc5c27f3..509993f55ebb56cb162c5e6f9160e598e1b90212 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +43,7 @@
 #ifndef GMX_COMMANDLINE_CMDLINEMODULE_H
 #define GMX_COMMANDLINE_CMDLINEMODULE_H
 
-#include "gromacs/utility/classhelpers.h"
+#include <memory>
 
 namespace gmx
 {
@@ -78,7 +78,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \brief
index 066495cd67405afb42cf59e44c136fb4661a2268..d95328e474df3bcf0f0418eebbac19d71ac9bc46 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
index 9575de0c4d525dcdeda6583c1ee2a98a5c171b37..c1bca865591af320faff8743b3eb7e2279900669 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <memory>
 
 #include "gromacs/onlinehelp/ihelptopic.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
@@ -344,7 +343,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \libinternal \brief
index b2ecfe491f27dc2a6a7f927811c6698017557275..ef49a131982114c7fa9f767fdfcf5cb4a8c2e148 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2016,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_COMMANDLINE_CMDLINEPARSER_H
 #define GMX_COMMANDLINE_CMDLINEPARSER_H
 
+#include <memory>
 #include <string>
 #include <vector>
 
-#include "gromacs/utility/classhelpers.h"
-
 namespace gmx
 {
 
@@ -143,7 +142,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index dd573cc1abe4ffbae0bc606aff98f9a68e46c4ce..5c4b5b89f0e6161a587c5b92703f7a04bcbd5046 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstdlib>
 #include <cstring>
 
+#include <mutex>
 #include <string>
 #include <vector>
 
 #include "buildinfo.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
-#include "gromacs/utility/mutex.h"
 #include "gromacs/utility/path.h"
 #include "gromacs/utility/stringutil.h"
 
@@ -306,7 +306,7 @@ public:
     mutable std::string          fullBinaryPath_;
     mutable std::string          installationPrefix_;
     mutable bool                 bSourceLayout_;
-    mutable Mutex                binaryPathMutex_;
+    mutable std::mutex           binaryPathMutex_;
 };
 
 CommandLineProgramContext::Impl::Impl() : programName_("GROMACS"), bSourceLayout_(false) {}
@@ -388,14 +388,14 @@ const char* CommandLineProgramContext::commandLine() const
 
 const char* CommandLineProgramContext::fullBinaryPath() const
 {
-    lock_guard<Mutex> lock(impl_->binaryPathMutex_);
+    std::lock_guard<std::mutex> lock(impl_->binaryPathMutex_);
     impl_->findBinaryPath();
     return impl_->fullBinaryPath_.c_str();
 }
 
 InstallationPrefixInfo CommandLineProgramContext::installationPrefix() const
 {
-    lock_guard<Mutex> lock(impl_->binaryPathMutex_);
+    std::lock_guard<std::mutex> lock(impl_->binaryPathMutex_);
     if (impl_->installationPrefix_.empty())
     {
         impl_->findBinaryPath();
index 00a3699ddf820f95c7faefa333f9511196ee8f0e..70d06df13f2cbd13aeb4f475fa1c70e9254b145b 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +53,6 @@
 #include <string>
 #include <vector>
 
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/programcontext.h"
 
 namespace gmx
@@ -188,7 +187,6 @@ public:
      * Returns the full path of the running binary.
      *
      * \throws std::bad_alloc if out of memory.
-     * \throws tMPI::system_error on thread synchronization errors.
      *
      * Returns argv[0] if there was an error in finding the absolute path.
      */
@@ -197,7 +195,6 @@ public:
      * Returns the installation prefix (for finding \Gromacs data files).
      *
      * \throws std::bad_alloc if out of memory.
-     * \throws tMPI::system_error on thread synchronization errors.
      *
      * Returns a hardcoded path set during configuration time if there is
      * an error in finding the library data files.
@@ -213,7 +210,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 5cc0e620a15b1781a7f0962311abea25de300f70..1a3c8a80bb6f2596c3585a1c291d8c7b1aed969e 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -50,7 +50,6 @@
 #include <vector>
 
 #include "gromacs/fileio/filetypes.h"
-#include "gromacs/utility/basedefinitions.h"
 
 
 //! \addtogroup module_commandline
@@ -149,10 +148,10 @@ gmx::ArrayRef<const std::string> ftp2fns(int ftp, int nfile, const t_filenm fnm[
 #define ftp2FILE(ftp, nfile, fnm, mode) gmx_ffopen(ftp2fn(ftp, nfile, fnm), mode)
 
 //! Returns TRUE when this file type has been found on the cmd-line.
-gmx_bool ftp2bSet(int ftp, int nfile, const t_filenm fnm[]);
+bool ftp2bSet(int ftp, int nfile, const t_filenm fnm[]);
 
 //! Returns TRUE when this option has been found on the cmd-line.
-gmx_bool opt2bSet(const char* opt, int nfile, const t_filenm fnm[]);
+bool opt2bSet(const char* opt, int nfile, const t_filenm fnm[]);
 
 /*! \brief
  * Returns the file name belonging top cmd-line option opt, or NULL when
@@ -170,13 +169,13 @@ const char* opt2fn_null(const char* opt, int nfile, const t_filenm fnm[]);
 const char* ftp2fn_null(int ftp, int nfile, const t_filenm fnm[]);
 
 //! Returns whether or not this filenm is optional.
-gmx_bool is_optional(const t_filenm* fnm);
+bool is_optional(const t_filenm* fnm);
 
 //! Returns whether or not this filenm is output.
-gmx_bool is_output(const t_filenm* fnm);
+bool is_output(const t_filenm* fnm);
 
 //! Returns whether or not this filenm is set.
-gmx_bool is_set(const t_filenm* fnm);
+bool is_set(const t_filenm* fnm);
 
 /*! \brief Return whether \c filename might have been produced by mdrun -noappend.
  *
index 1b4f6a8c523a994490fca7a4e8179a6369419bf8..c027dba96aa5260d66fbfb620faa4dea2a001cf7 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +189,9 @@ namespace
 {
 
 //! Names for XvgFormat
-const gmx::EnumerationArray<XvgFormat, const char*> c_xvgFormatNames = { { "xmgrace", "xmgr",
-                                                                           "none" } };
+const gmx::EnumerationArray<XvgFormat, const char*> c_xvgFormatNames = {
+    { "xmgrace", "xmgr", "none" }
+};
 
 /*! \brief Returns the default xvg format, as modified by GMX_VIEW_XVG
  * if that environment variable is set.
@@ -565,15 +566,15 @@ gmx_bool parse_common_args(int*               argc,
         /* Extract Time info from arguments */
         if (bBeginTimeSet)
         {
-            setTimeValue(TBEGIN, tbegin);
+            setTimeValue(TimeControl::Begin, tbegin);
         }
         if (bEndTimeSet)
         {
-            setTimeValue(TEND, tend);
+            setTimeValue(TimeControl::End, tend);
         }
         if (bDtSet)
         {
-            setTimeValue(TDELTA, tdelta);
+            setTimeValue(TimeControl::Delta, tdelta);
         }
 
         adapter.copyValues();
index 77b1603d2a1d4fcebd7fbe3c19a6144c608ce5f8..3ceb0acc81684f5c0a92db120db15c3828426249 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@
 #include "gromacs/commandline/filenm.h"
 #include "gromacs/fileio/oenv.h"
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
 struct gmx_output_env_t;
@@ -120,7 +119,7 @@ typedef struct
          */
         const char** c;
         /** Boolean value for etBOOL. */
-        gmx_bool* b;
+        bool* b;
         /** Vector value for etRVEC. */
         rvec* rv;
     } u;
@@ -168,7 +167,7 @@ int opt2parg_int(const char* option, int nparg, t_pargs pa[]);
  *
  * \p option must specify a valid argument in \p pa of the correct type.
  */
-gmx_bool opt2parg_bool(const char* option, int nparg, t_pargs pa[]);
+bool opt2parg_bool(const char* option, int nparg, t_pargs pa[]);
 
 /*! \brief
  * Returns value of an etREAL/etTIME option.
@@ -216,7 +215,7 @@ const char* opt2parg_enum(const char* option, int nparg, t_pargs pa[]);
  *
  * \p option must specify a valid argument in \p pa.
  */
-gmx_bool opt2parg_bSet(const char* option, int nparg, const t_pargs* pa);
+bool opt2parg_bSet(const char* option, int nparg, const t_pargs* pa);
 
 
 /** Add option -w to view output files (must be implemented in program). */
@@ -258,18 +257,18 @@ gmx_bool opt2parg_bSet(const char* option, int nparg, const t_pargs* pa);
  *
  * \see gmx_run_cmain().
  */
-gmx_bool parse_common_args(int*               argc,
-                           char*              argv[],
-                           unsigned long      Flags,
-                           int                nfile,
-                           t_filenm           fnm[],
-                           int                npargs,
-                           t_pargs*           pa,
-                           int                ndesc,
-                           const char**       desc,
-                           int                nbugs,
-                           const char**       bugs,
-                           gmx_output_env_t** oenv);
+bool parse_common_args(int*               argc,
+                       char*              argv[],
+                       unsigned long      Flags,
+                       int                nfile,
+                       t_filenm           fnm[],
+                       int                npargs,
+                       t_pargs*           pa,
+                       int                ndesc,
+                       const char**       desc,
+                       int                nbugs,
+                       const char**       bugs,
+                       gmx_output_env_t** oenv);
 
 /*! \} */
 
index 28db8f9bd5e595ddec183d77d1e12b0dc59e041a..ef7d17d868568aed09cc87dd8546efa4e45b0b0c 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,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_COMMANDLINE_SHELLCOMPLETIONS_H
 #define GMX_COMMANDLINE_SHELLCOMPLETIONS_H
 
+#include <memory>
 #include <string>
 #include <vector>
 
-#include "gromacs/utility/classhelpers.h"
-
 namespace gmx
 {
 
@@ -87,7 +86,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
diff --git a/src/gromacs/commandline/tests/.clang-tidy b/src/gromacs/commandline/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index c8dd3e9f28191149d126b22d041ccd7ff19581d7..0bb8fa240179d252c65335343a9b7b5b62e23a82 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +81,8 @@ void CommandLineHelpWriterTest::checkHelp(gmx::CommandLineHelpWriter* writer)
 {
     gmx::StringOutputStream     stream;
     gmx::TextWriter             streamWriter(&stream);
-    gmx::CommandLineHelpContext context(&streamWriter, gmx::eHelpOutputFormat_Console, nullptr,
-                                        "test");
+    gmx::CommandLineHelpContext context(
+            &streamWriter, gmx::eHelpOutputFormat_Console, nullptr, "test");
     context.setShowHidden(bHidden_);
     writer->writeHelp(context);
     stream.close();
@@ -132,30 +132,32 @@ TEST_F(CommandLineHelpWriterTest, HandlesOptionTypes)
     std::string filename;
     options.addOption(FileNameOption("f")
                               .description("Input file description")
-                              .filetype(eftTrajectory)
+                              .filetype(OptionFileType::Trajectory)
                               .inputFile()
                               .required()
                               .defaultBasename("traj"));
     options.addOption(FileNameOption("mult")
                               .description("Multiple file description")
-                              .filetype(eftTrajectory)
+                              .filetype(OptionFileType::Trajectory)
                               .inputFile()
                               .multiValue()
                               .defaultBasename("traj"));
     options.addOption(FileNameOption("lib")
                               .description("Library file description")
-                              .filetype(eftGenericData)
+                              .filetype(OptionFileType::GenericData)
                               .inputFile()
                               .libraryFile()
                               .defaultBasename("libdata"));
     options.addOption(FileNameOption("io")
                               .store(&filename)
                               .description("Input/Output file description")
-                              .filetype(eftGenericData)
+                              .filetype(OptionFileType::GenericData)
                               .inputOutputFile()
                               .defaultBasename("inout"));
-    options.addOption(
-            FileNameOption("o").description("Output file description").filetype(eftPlot).outputFile());
+    options.addOption(FileNameOption("o")
+                              .description("Output file description")
+                              .filetype(OptionFileType::Plot)
+                              .outputFile());
 
     CommandLineHelpWriter writer(options);
     bHidden_ = true;
@@ -209,37 +211,36 @@ TEST_F(CommandLineHelpWriterTest, HandlesDefaultValuesFromVariables)
  */
 TEST_F(CommandLineHelpWriterTest, HandlesLongFileOptions)
 {
-    using gmx::eftGenericData;
-    using gmx::eftTrajectory;
     using gmx::FileNameOption;
+    using gmx::OptionFileType;
 
     gmx::Options options;
     options.addOption(FileNameOption("f")
                               .description("File name option with a long value")
-                              .filetype(eftTrajectory)
+                              .filetype(OptionFileType::Trajectory)
                               .inputFile()
                               .required()
                               .defaultBasename("path/to/long/trajectory/name"));
     options.addOption(FileNameOption("f2")
                               .description("File name option with a long value")
-                              .filetype(eftTrajectory)
+                              .filetype(OptionFileType::Trajectory)
                               .inputFile()
                               .required()
                               .defaultBasename("path/to/long/trajectory"));
     options.addOption(FileNameOption("lib")
                               .description("File name option with a long value and type")
-                              .filetype(eftTrajectory)
+                              .filetype(OptionFileType::Trajectory)
                               .inputFile()
                               .libraryFile()
                               .defaultBasename("path/to/long/trajectory/name"));
     options.addOption(FileNameOption("longfileopt")
                               .description("File name option with a long name")
-                              .filetype(eftGenericData)
+                              .filetype(OptionFileType::GenericData)
                               .inputFile()
                               .defaultBasename("deffile"));
     options.addOption(FileNameOption("longfileopt2")
                               .description("File name option with multiple long fields")
-                              .filetype(eftGenericData)
+                              .filetype(OptionFileType::GenericData)
                               .inputFile()
                               .libraryFile()
                               .defaultBasename("path/to/long/file/name"));
index fe4077ba185c766647af6f8b6afbc31bf67a2947..9d7684be2e616bda64bab5ba7dabbfa4f40ca91b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -143,7 +143,7 @@ CommandLineModuleManagerTestBase::~CommandLineModuleManagerTestBase() {}
 void CommandLineModuleManagerTestBase::initManager(const CommandLine& args, const char* realBinaryName)
 {
     GMX_RELEASE_ASSERT(impl_ == nullptr, "initManager() called more than once in test");
-    impl_.reset(new Impl(args, realBinaryName));
+    impl_ = std::make_unique<Impl>(args, realBinaryName);
 }
 
 MockModule& CommandLineModuleManagerTestBase::addModule(const char* name, const char* description)
@@ -157,8 +157,8 @@ MockOptionsModule& CommandLineModuleManagerTestBase::addOptionsModule(const char
 {
     std::unique_ptr<MockOptionsModule> modulePtr(new MockOptionsModule());
     MockOptionsModule*                 module = modulePtr.get();
-    gmx::ICommandLineOptionsModule::registerModuleDirect(&manager(), name, description,
-                                                         std::move(modulePtr));
+    gmx::ICommandLineOptionsModule::registerModuleDirect(
+            &manager(), name, description, std::move(modulePtr));
     return *module;
 }
 
index 493d1c0b33896dd933babb24283736e3f41dce21..e560eabb2313edbbe269f11541118a6670b352b9 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_COMMANDLINE_CMDLINEMODULEMANAGERTEST_H
 #define GMX_COMMANDLINE_CMDLINEMODULEMANAGERTEST_H
 
+#include <memory>
 #include <string>
 
 #include <gmock/gmock.h>
@@ -50,7 +51,6 @@
 #include "gromacs/commandline/cmdlinehelpcontext.h"
 #include "gromacs/commandline/cmdlinemodule.h"
 #include "gromacs/commandline/cmdlineoptionsmodule.h"
-#include "gromacs/utility/classhelpers.h"
 
 #include "testutils/stringtest.h"
 
@@ -152,7 +152,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace test
index c5049530320c1822027e0cf3751ae773924c2a8b..f11b5def85823bb67d93a24d54f455515cc3a1d0 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +83,8 @@ public:
     void parseFromArgs(unsigned long flags, gmx::ArrayRef<t_filenm> fnm, gmx::ArrayRef<t_pargs> pa)
     {
         fileCount_ = fnm.size();
-        bool bOk   = parse_common_args(&args_.argc(), args_.argv(), flags, fnm.size(), fnm.data(),
-                                     pa.size(), pa.data(), 0, nullptr, 0, nullptr, &oenv_);
+        bool bOk   = parse_common_args(
+                &args_.argc(), args_.argv(), flags, fnm.size(), fnm.data(), pa.size(), pa.data(), 0, nullptr, 0, nullptr, &oenv_);
         EXPECT_TRUE(bOk);
     }
     void parseFromArray(gmx::ArrayRef<const char* const> cmdline,
@@ -191,6 +191,40 @@ TEST_F(ParseCommonArgsTest, ParsesBooleanArgs)
     EXPECT_TRUE(value3);
 }
 
+TEST_F(ParseCommonArgsTest, ParsesBooleanArgsToValuesOfSuitableEnum)
+{
+    enum class LikeBool : bool
+    {
+        No  = false,
+        Yes = true
+    };
+    // Set up the default values
+    LikeBool value1 = LikeBool::No;
+    LikeBool value2 = LikeBool::No;
+    LikeBool value3 = LikeBool::No;
+    LikeBool value4 = LikeBool::Yes;
+    LikeBool value5 = LikeBool::Yes;
+    LikeBool value6 = LikeBool::Yes;
+    // Set up 6 options
+    t_pargs pa[] = { { "-b1", FALSE, etBOOL, { &value1 }, "Description" },
+                     { "-b2", FALSE, etBOOL, { &value2 }, "Description" },
+                     { "-b3", FALSE, etBOOL, { &value3 }, "Description" },
+                     { "-b4", FALSE, etBOOL, { &value4 }, "Description" },
+                     { "-b5", FALSE, etBOOL, { &value5 }, "Description" },
+                     { "-b6", FALSE, etBOOL, { &value6 }, "Description" } };
+    // Set some to yes and no, leave some as default
+    const char* const cmdline[] = { "test", "-b1", "-nob2", "-b4", "-nob5" };
+
+    parseFromArray(cmdline, 0, {}, pa);
+    // Expetactions
+    EXPECT_EQ(value1, LikeBool::Yes) << "set to yes";
+    EXPECT_EQ(value2, LikeBool::No) << "set to no";
+    EXPECT_EQ(value3, LikeBool::No) << "preserves the default of no";
+    EXPECT_EQ(value4, LikeBool::Yes) << "set to yes";
+    EXPECT_EQ(value5, LikeBool::No) << "set to no";
+    EXPECT_EQ(value6, LikeBool::Yes) << "preserves the default of yes";
+}
+
 TEST_F(ParseCommonArgsTest, ParsesVectorArgs)
 {
     rvec              value1 = { 0, 0, 0 }, value2 = { 0, 0, 0 }, value3 = { 1, 2, 3 };
index a2b1ae28259aedf459f333431f01ef47aa6d89c0..d9a071f582027c70b3af1369b762d9020cc35101 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstdlib>
 #include <cstring>
 
+#include <array>
+#include <type_traits>
+
 #include "gromacs/commandline/filenm.h"
 #include "gromacs/fileio/oenv.h"
 #include "gromacs/utility/arraysize.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 
-static const int can_view_ftp[] = { 0, efEPS, efXPM, efXVG, efPDB };
-#define NVIEW asize(can_view_ftp)
-static const char* view_program[] = { nullptr, "ghostview", "display", nullptr, "xterm -e rasmol" };
+static constexpr std::array<int, 5> canViewFileType = { 0, efEPS, efXPM, efXVG, efPDB };
+
+static constexpr int numberOfPossibleFiles = canViewFileType.size();
 
 static int can_view(int ftp)
 {
-    int i;
-
-    for (i = 1; i < NVIEW; i++)
+    for (int i = 1; i < numberOfPossibleFiles; i++)
     {
-        if (ftp == can_view_ftp[i])
+        if (ftp == canViewFileType[i])
         {
             return i;
         }
@@ -70,6 +71,9 @@ static int can_view(int ftp)
 
 void do_view(const gmx_output_env_t* oenv, const char* fn, const char* opts)
 {
+    std::array<const char*, 5> viewProgram = {
+        nullptr, "ghostview", "display", nullptr, "xterm -e rasmol"
+    };
     char        buf[STRLEN], env[STRLEN];
     const char* cmd;
     int         ftp, n;
@@ -105,7 +109,7 @@ void do_view(const gmx_output_env_t* oenv, const char* fn, const char* opts)
                     {
                         if (!(cmd = getenv(env)))
                         {
-                            cmd = view_program[n];
+                            cmd = viewProgram[n];
                         }
                     }
                     else
index 83326015337c60ce8d07a2a823d1ed62d957a109..8b4190ecf6e8b81fc6bd97c38bc20904c262ed9d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2018,2019, by the GROMACS development team, led by
+# Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+add_library(compat INTERFACE)
+
+# Source files have the following private module dependencies.
+target_link_libraries(compat PRIVATE
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(compat PUBLIC
+target_include_directories(compat INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(compat PUBLIC
+target_link_libraries(compat INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when compat is an OBJECT target
+#target_link_libraries(compat PUBLIC legacy_api)
+#target_link_libraries(compat PRIVATE common)
+
+# Module dependencies
+# compat interfaces convey transitive dependence on these modules.
+#target_link_libraries(compat PUBLIC
+target_link_libraries(compat INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(compat PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(compat PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index 37689a919033a1927d7491a0cea59d6254578a9b..5bb1ff627ab4804bc81273575f8c92fa1ddb205d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,16 +58,8 @@ namespace compat
 
 //! Contract-assurance macros that work like a simple version of the GSL ones
 //! \{
-#if !defined(__INTEL_COMPILER) || !(__INTEL_COMPILER == 1800 && __INTEL_COMPILER_UPDATE == 0)
-#    define Expects(cond) GMX_ASSERT((cond), "Precondition violation")
-#    define Ensures(cond) GMX_ASSERT((cond), "Postcondition violation")
-#else
-// icc 18.0.0 in a RelWithAssert build has an ICE, even if we directly
-// embed the contents of GMX_ASSERT, so it seems the lambda in
-// GMX_ASSERT is too complex for it in this use case.
-#    define Expects(cond)
-#    define Ensures(cond)
-#endif
+#define Expects(cond) GMX_ASSERT((cond), "Precondition violation")
+#define Ensures(cond) GMX_ASSERT((cond), "Postcondition violation")
 //! \}
 
 /*! \libinternal
diff --git a/src/gromacs/compat/tests/.clang-tidy b/src/gromacs/compat/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 4131ed28993f2bbb484b3f7844ca11bc2f03177e..e7201196646b5721d5e604682b2a55822db083cd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -62,17 +62,8 @@ TEST(NotNullConstruction, Works)
     not_null<std::shared_ptr<int>> sharedPointer(std::make_shared<int>(10));
 
 #ifndef NDEBUG
-/* The workaround here is needed because the intel implementation
- * will not trigger the assert when using the pointer without
- * a valid object. This was needed due to an internal error
- * being triggered instead with the compiler under this condition.
- *
- * Death tests can also not be used safely in a parallel environment.
- */
-#    if !defined(__INTEL_COMPILER) || !(__INTEL_COMPILER == 1800 && __INTEL_COMPILER_UPDATE == 0)
     int* nullPointer = nullptr;
     GMX_EXPECT_DEATH_IF_SUPPORTED(not_null<int*> invalidNullPointer(nullPointer), "");
-#    endif
 #endif
 
     int  value        = 20;
index 6e73817f45daba4a5a815932a17f65c5761fcaa0..ffcc961f7322b8e0b9c3515c64244871fe67528d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2019, by the GROMACS development team, led by
+# Copyright (c) 2019,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(coordinateio INTERFACE)
 file(GLOB COORDINATEIO_SOURCES *.cpp outputadapters/*.cpp)
-
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${COORDINATEIO_SOURCES} PARENT_SCOPE)
 
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(coordinateio PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(coordinateio PUBLIC
+target_include_directories(coordinateio INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(coordinateio PUBLIC
+target_link_libraries(coordinateio INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when coordinateio is an OBJECT target
+#target_link_libraries(coordinateio PUBLIC legacy_api)
+#target_link_libraries(coordinateio PRIVATE common)
+
+# Module dependencies
+# coordinateio interfaces convey transitive dependence on these modules.
+#target_link_libraries(coordinateio PUBLIC
+target_link_libraries(coordinateio INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(coordinateio PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(coordinateio PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
      add_subdirectory(tests)
 endif()
index 09fc9733c10142e4c815ea33e1c8aafccfce7842..549e37693e5547f67a3053df764c271e0b7a6d26 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -346,16 +346,24 @@ static t_trxstatus* openTNG(const std::string& name, const Selection& sel, const
     if (sel.isValid())
     {
         GMX_ASSERT(sel.hasOnlyAtoms(), "Can only work with selections consisting out of atoms");
-        return trjtools_gmx_prepare_tng_writing(name.c_str(), filemode[0],
+        return trjtools_gmx_prepare_tng_writing(name.c_str(),
+                                                filemode[0],
                                                 nullptr, // infile_, //how to get the input file here?
-                                                nullptr, sel.atomCount(), mtop, sel.atomIndices(),
+                                                nullptr,
+                                                sel.atomCount(),
+                                                mtop,
+                                                sel.atomIndices(),
                                                 sel.name());
     }
     else
     {
-        return trjtools_gmx_prepare_tng_writing(name.c_str(), filemode[0],
+        return trjtools_gmx_prepare_tng_writing(name.c_str(),
+                                                filemode[0],
                                                 nullptr, // infile_, //how to get the input file here?
-                                                nullptr, mtop->natoms, mtop, get_atom_index(mtop),
+                                                nullptr,
+                                                mtop->natoms,
+                                                mtop,
+                                                get_atom_index(*mtop),
                                                 "System");
     }
 }
@@ -400,8 +408,8 @@ void TrajectoryFrameWriter::prepareAndWriteFrame(const int framenumber, const t_
         {
             localF_.resize(input.natoms);
         }
-        deepCopy_t_trxframe(input, &local, localX_.data(), localV_.data(), localF_.data(),
-                            localIndex_.data());
+        deepCopy_t_trxframe(
+                input, &local, localX_.data(), localV_.data(), localF_.data(), localIndex_.data());
         for (const auto& outputAdapter : outputAdapters_.getAdapters())
         {
             if (outputAdapter)
index d2febd7064af6457600d30840d287b4dba9ca52d..079c46d272ce9919fdeed11bc3308751a1b3fdfb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +64,8 @@ void OutputAdapterContainer::addAdapter(OutputAdapterPointer adapter, Coordinate
 
 bool OutputAdapterContainer::isEmpty() const
 {
-    return std::none_of(outputAdapters_.begin(), outputAdapters_.end(),
-                        [](const auto& adapter) { return adapter != nullptr; });
+    return std::none_of(outputAdapters_.begin(), outputAdapters_.end(), [](const auto& adapter) {
+        return adapter != nullptr;
+    });
 }
 } // namespace gmx
index f5d2fd67b2b1d1ffe9c33a759a85e29091763e2b..19d6fca7bf437515681e2e39e9736b902f0ea41c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +49,6 @@
 
 #include "gromacs/coordinateio/ioutputadapter.h"
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/enumerationhelpers.h"
 
 namespace gmx
diff --git a/src/gromacs/coordinateio/tests/.clang-tidy b/src/gromacs/coordinateio/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 98f278c38f793b07aa8a66409454d0532572275f..5e4939022613745e2e1984ad2305fbada0cef1e9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -86,7 +86,9 @@ inline TrajectoryFrameWriterPointer createMinimalTrajectoryFrameWriter(const std
                                                                        const Selection& selection,
                                                                        OutputRequirements requirements)
 {
-    return createTrajectoryFrameWriter(topology.mtop(), selection, filename,
+    return createTrajectoryFrameWriter(topology.mtop(),
+                                       selection,
+                                       filename,
                                        topology.hasTopology() ? topology.copyAtoms() : nullptr,
                                        requirements);
 }
@@ -186,7 +188,7 @@ public:
      * \param[in] requirements Requirements for adding to the object.
      * \returns The newly created object.
      */
-    TrajectoryFrameWriterPointer runTest(const char* filename, const OutputRequirements& requirements)
+    TrajectoryFrameWriterPointer runTest(const char* filename, const OutputRequirements& requirements) const
     {
         return createMinimalTrajectoryFrameWriter(filename, dummyTopology_, dummySelection_, requirements);
     }
index 37f24b6eb9870266c1032c3c31e8a7aef4178542..64569a0217f9b005730ab04678b78ca2d2693e0b 100644 (file)
@@ -289,7 +289,8 @@ const char* const anySupported[] = { "spc2-traj.trr",
 #if GMX_USE_TNG
                                      "spc2-traj.tng",
 #endif
-                                     "spc2-traj.xtc", "spc2-traj.g96" };
+                                     "spc2-traj.xtc",
+                                     "spc2-traj.g96" };
 
 //! Names here work for setVelocity module
 const char* const setVelocitySupported[] = {
@@ -312,7 +313,9 @@ const char* const setForceSupported[] = {
 };
 
 //! Names here don't work for setForce module
-const char* const setForceUnSupported[] = { "spc2-traj.xtc", "spc2-traj.pdb", "spc2-traj.gro",
+const char* const setForceUnSupported[] = { "spc2-traj.xtc",
+                                            "spc2-traj.pdb",
+                                            "spc2-traj.gro",
                                             "spc2-traj.g96" };
 
 //! Names here work for setPrecision module
@@ -324,7 +327,9 @@ const char* const setPrecisionSupported[] = {
 };
 
 //! Names here don't work for setPrecision module
-const char* const setPrecisionUnSupported[] = { "spc2-traj.trr", "spc2-traj.pdb", "spc2-traj.gro",
+const char* const setPrecisionUnSupported[] = { "spc2-traj.trr",
+                                                "spc2-traj.pdb",
+                                                "spc2-traj.gro",
                                                 "spc2-traj.g96" };
 
 
index 564c52f14018b0430123051b31e89a3091f1a25b..8822da78994f1869c730165c08d02e2e376dc598 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
+# Copyright (c) 2014,2015,2016,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(correlationfunctions INTERFACE)
+
 file(GLOB GMXCORRFUNC_SOURCES *.cpp)
 
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${GMXCORRFUNC_SOURCES} PARENT_SCOPE)
+
+# Source files have the following private module dependencies.
+target_link_libraries(correlationfunctions PRIVATE
+                      #                      gmxlib
+                      #                      math
+                      #                      mdtypes
+                      #                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(correlationfunctions PUBLIC
+target_include_directories(correlationfunctions INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(correlationfunctions PUBLIC
+target_link_libraries(correlationfunctions INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when fileio is an OBJECT target
+#target_link_libraries(correlationfunctions PUBLIC legacy_api)
+#target_link_libraries(correlationfunctions PRIVATE common)
+
+# Module dependencies
+# This module convey transitive dependence on these modules.
+#target_link_libraries(correlationfunctions PUBLIC
+target_link_libraries(correlationfunctions INTERFACE
+                      #                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(correlationfunctions PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(correlationfunctions PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index 3c6b4b7018dd1c796695ba993535452e19da5115..680b3f56611eab7095ce4dc3d8a668f00534ba81 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -78,9 +78,11 @@ typedef struct
 } t_acf;
 
 /*! \brief Global variable set true if initialization routines are called. */
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static gmx_bool bACFinit = FALSE;
 
 /*! \brief Data structure for storing command line variables. */
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static t_acf acf;
 
 enum
@@ -141,8 +143,7 @@ static void do_ac_core(int nframes, int nout, real corr[], real c1[], int nresta
     }
     if (debug)
     {
-        fprintf(debug, "Starting do_ac_core: nframes=%d, nout=%d, nrestart=%d,mode=%lu\n", nframes,
-                nout, nrestart, mode);
+        fprintf(debug, "Starting do_ac_core: nframes=%d, nout=%d, nrestart=%d,mode=%lu\n", nframes, nout, nrestart, mode);
     }
 
     for (j = 0; (j < nout); j++)
@@ -191,8 +192,15 @@ static void do_ac_core(int nframes, int nout, real corr[], real c1[], int nresta
 
                 if (cth - 1.0 > 1.0e-15)
                 {
-                    printf("j: %d, k: %d, xj:(%g,%g,%g), xk:(%g,%g,%g)\n", j, k, xj[XX], xj[YY],
-                           xj[ZZ], xk[XX], xk[YY], xk[ZZ]);
+                    printf("j: %d, k: %d, xj:(%g,%g,%g), xk:(%g,%g,%g)\n",
+                           j,
+                           k,
+                           xj[XX],
+                           xj[YY],
+                           xj[ZZ],
+                           xk[XX],
+                           xk[YY],
+                           xk[ZZ]);
                 }
                 mmm = 1;
                 if (MODE(eacP2))
@@ -582,10 +590,11 @@ void low_do_autocorr(const char*             fn,
     /* Print flags and parameters */
     if (bVerbose)
     {
-        printf("Will calculate %s of %d thingies for %d frames\n",
-               title ? title : "autocorrelation", nitem, nframes);
-        printf("bAver = %s, bFour = %s bNormalize= %s\n", gmx::boolToString(bAver),
-               gmx::boolToString(bFour), gmx::boolToString(bNormalize));
+        printf("Will calculate %s of %d thingies for %d frames\n", title ? title : "autocorrelation", nitem, nframes);
+        printf("bAver = %s, bFour = %s bNormalize= %s\n",
+               gmx::boolToString(bAver),
+               gmx::boolToString(bFour),
+               gmx::boolToString(bNormalize));
         printf("mode = %lu, dt = %g, nrestart = %d\n", mode, dt, nrestart);
     }
     /* Allocate temp arrays */
@@ -698,7 +707,8 @@ void low_do_autocorr(const char*             fn,
         {
             Ctav /= nitem;
             Ct2av /= nitem;
-            printf("Average correlation time %.3f Std. Dev. %.3f Error %.3f (ps)\n", Ctav,
+            printf("Average correlation time %.3f Std. Dev. %.3f Error %.3f (ps)\n",
+                   Ctav,
                    std::sqrt((Ct2av - gmx::square(Ctav))),
                    std::sqrt((Ct2av - gmx::square(Ctav)) / (nitem - 1)));
         }
@@ -711,6 +721,7 @@ void low_do_autocorr(const char*             fn,
 }
 
 /*! \brief Legend for selecting Legendre polynomials. */
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static const char* Leg[] = { nullptr, "0", "1", "2", "3", nullptr };
 
 t_pargs* add_acf_pargs(int* npargs, t_pargs* pa)
@@ -803,8 +814,22 @@ void do_autocorr(const char*             fn,
         default: break;
     }
 
-    low_do_autocorr(fn, oenv, title, nframes, nitem, acf.nout, c1, dt, mode, acf.nrestart, bAver,
-                    acf.bNormalize, bDebugMode(), acf.tbeginfit, acf.tendfit, acf.fitfn);
+    low_do_autocorr(fn,
+                    oenv,
+                    title,
+                    nframes,
+                    nitem,
+                    acf.nout,
+                    c1,
+                    dt,
+                    mode,
+                    acf.nrestart,
+                    bAver,
+                    acf.bNormalize,
+                    bDebugMode(),
+                    acf.tbeginfit,
+                    acf.tendfit,
+                    acf.fitfn);
 }
 
 int get_acfnout()
index d57ba055c9670e9b76e1b42596b9678e77874ab6..97bfe7eb5f8358b7666777c079da6bb8c993cf82 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-2019, by the GROMACS development team, led by
+ * Copyright (c) 2013-2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -69,12 +69,14 @@ static const int nfp_ffn[effnNR] = { 0, 1, 2, 3, 5, 7, 9, 2, 4, 3, 6 };
  * hence there are many more NULL field (which have to be at the end of
  * the array).
  */
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 const char* s_ffn[effnNR + 2] = { nullptr, "none",  "exp",   "aexp",  "exp_exp", "exp5", "exp7",
                                   "exp9",  nullptr, nullptr, nullptr, nullptr,   nullptr };
 
 // clang-format off
 // needed because clang-format wants to break the lines below
 /*! \brief Long description for each fitting function type */
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static const char* longs_ffn[effnNR]
         = { "no fit",
             "y = exp(-x/|a0|)",
@@ -389,6 +391,7 @@ static double lmc_errest_3_parm(double x, const double* a)
 }
 
 /*! \brief array of fitting functions corresponding to the pre-defined types */
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 t_lmcurve lmcurves[effnNR + 1] = { lmc_exp_one_parm,  lmc_exp_one_parm, lmc_exp_two_parm,
                                    lmc_exp_exp,       lmc_exp_5_parm,   lmc_exp_7_parm,
                                    lmc_exp_9_parm,    lmc_vac_2_parm,   lmc_erffit,
@@ -566,8 +569,12 @@ static void print_chi2_params(FILE*        fp,
         double yfit = lmcurves[eFitFn](x[i], fitparms);
         chi2 += gmx::square(y[i] - yfit);
     }
-    fprintf(fp, "There are %d data points, %d parameters, %s chi2 = %g\nparams:", nfitpnts,
-            effnNparams(eFitFn), label, chi2);
+    fprintf(fp,
+            "There are %d data points, %d parameters, %s chi2 = %g\nparams:",
+            nfitpnts,
+            effnNparams(eFitFn),
+            label,
+            chi2);
     for (i = 0; (i < effnNparams(eFitFn)); i++)
     {
         fprintf(fp, "  %10g", fitparms[i]);
@@ -601,8 +608,7 @@ real do_lmfit(int                     ndata,
     if (debug)
     {
         fprintf(debug, "There are %d points to fit %d vars!\n", ndata, effnNparams(eFitFn));
-        fprintf(debug, "Fit to function %d from %g through %g, dt=%g\n", eFitFn, begintimefit,
-                endtimefit, dt);
+        fprintf(debug, "Fit to function %d from %g through %g, dt=%g\n", eFitFn, begintimefit, endtimefit, dt);
     }
 
     snew(x, ndata);
@@ -761,19 +767,24 @@ real fit_acf(int                     ncorr,
 
     if (bPrint)
     {
-        printf("COR: Correlation time (plain integral from %6.3f to %6.3f ps) = %8.5f ps\n", 0.0,
-               dt * nf_int, sum);
+        printf("COR: Correlation time (plain integral from %6.3f to %6.3f ps) = %8.5f ps\n", 0.0, dt * nf_int, sum);
         printf("COR: Relaxation times are computed as fit to an exponential:\n");
         printf("COR:   %s\n", effnDescription(fitfn));
         printf("COR: Fit to correlation function from %6.3f ps to %6.3f ps, results in a\n",
-               tbeginfit, std::min(ncorr * dt, tendfit));
+               tbeginfit,
+               std::min(ncorr * dt, tendfit));
     }
 
     tStart = 0;
     if (bPrint)
     {
-        printf("COR:%11s%11s%11s%11s%11s%11s%11s\n", "Fit from", "Integral", "Tail Value",
-               "Sum (ps)", " a1 (ps)", (effnNparams(fitfn) >= 2) ? " a2 ()" : "",
+        printf("COR:%11s%11s%11s%11s%11s%11s%11s\n",
+               "Fit from",
+               "Integral",
+               "Tail Value",
+               "Sum (ps)",
+               " a1 (ps)",
+               (effnNparams(fitfn) >= 2) ? " a2 ()" : "",
                (effnNparams(fitfn) >= 3) ? " a3 (ps)" : "");
     }
 
@@ -843,9 +854,9 @@ real fit_acf(int                     ncorr,
 
         nf_int    = std::min(ncorr, static_cast<int>((tStart + 1e-4) / dt));
         sum       = print_and_integrate(debug, nf_int, dt, c1, nullptr, 1);
-        tail_corr = do_lmfit(ncorr, c1, sig, dt, nullptr, tStart, tendfit, oenv, bDebugMode(),
-                             fitfn, fitparm, 0, nullptr);
-        sumtot    = sum + tail_corr;
+        tail_corr = do_lmfit(
+                ncorr, c1, sig, dt, nullptr, tStart, tendfit, oenv, bDebugMode(), fitfn, fitparm, 0, nullptr);
+        sumtot = sum + tail_corr;
         if (fit && ((jmax == 1) || (j == 1)))
         {
             double mfp[3];
index d006d5563258a8ef78af2ece87c186137b62d273..a17efa477699882eba29488cecc6dc395f5e5c2f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -73,6 +73,7 @@ enum
  * This is exported for now in order to use when
  * calling parse_common_args.
  */
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 extern const char* s_ffn[effnNR + 2];
 
 /*! \brief
index f31daf4f8b13866f7673da322bd49ecbc6c694e8..f70317db7454748a650113fdd963ac45b20049d1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -169,8 +169,11 @@ bool lmfit_exp(int          nfit,
         chisq = gmx::square(status->fnorm);
         if (bVerbose)
         {
-            printf("status: fnorm = %g, nfev = %d, userbreak = %d\noutcome = %s\n", status->fnorm,
-                   status->nfev, status->userbreak, lm_infmsg[status->outcome]);
+            printf("status: fnorm = %g, nfev = %d, userbreak = %d\noutcome = %s\n",
+                   status->fnorm,
+                   status->nfev,
+                   status->userbreak,
+                   lm_infmsg[status->outcome]);
         }
         if (bVerbose)
         {
index 473eba167ce076d283b1fc0f0686244ac8c30bdf..28864796ee15674c58adca3f5b5fcecac1b0e51f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +60,7 @@ bool lmfit_exp(int          nfit,
                int          eFitFn,
                int          nfix);
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 extern t_lmcurve lmcurves[effnNR + 1];
 
 #endif
index c23d4c694e45069b8fea0de97f160108a75b082c..3a2866b6a3cf7985bb3752d266aaa0042cb8cc1a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +67,11 @@ int many_auto_correl(std::vector<std::vector<real>>* c)
         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));
+            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));
         }
     }
diff --git a/src/gromacs/correlationfunctions/tests/.clang-tidy b/src/gromacs/correlationfunctions/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index eb6e17e1c15ab72ce148b351c5351b4c2b2371de..f4d8515d31829e74acce606cfa28765c958f071a 100644 (file)
@@ -124,9 +124,22 @@ protected:
             }
         }
         real* ptr = result.data();
-        low_do_autocorr(nullptr, nullptr, nullptr, nrFrames_, 1, get_acfnout(), &ptr,
-                        data_->getDt(), mode, nrRestart, bAverage, bNormalize, bVerbose,
-                        data_->getStartTime(), data_->getEndTime(), effnNONE);
+        low_do_autocorr(nullptr,
+                        nullptr,
+                        nullptr,
+                        nrFrames_,
+                        1,
+                        get_acfnout(),
+                        &ptr,
+                        data_->getDt(),
+                        mode,
+                        nrRestart,
+                        bAverage,
+                        bNormalize,
+                        bVerbose,
+                        data_->getStartTime(),
+                        data_->getEndTime(),
+                        effnNONE);
 
         double testResult = 0;
         for (int i = 0; i < get_acfnout(); i++)
index 3b49626e95de5dcde9cc63492c5c52c0934ce57c..86cacc037157516ead386728da68588df0609ff5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #ifndef GMX_CORRELATIONDATASET_H
 #define GMX_CORRELATIONDATASET_H
 
+#include <memory>
 #include <string>
 #include <vector>
 
index c7427688f33daa7bb9d40fa76a7971bfe4e0cfbf..3189af7e220972c50b2b391653c54cb544acfdf9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -130,9 +130,19 @@ protected:
             GMX_THROW(InvalidInputError("testType out of range"));
         }
         output_env_init_default(&oenv);
-        do_lmfit(data_[testType].nrLines_, &(data_[testType].y_[0]), nullptr, data_[testType].dt_,
-                 &(data_[testType].x_[0]), data_[testType].startTime_, data_[testType].endTime_,
-                 oenv, false, type, result, 0, nullptr);
+        do_lmfit(data_[testType].nrLines_,
+                 &(data_[testType].y_[0]),
+                 nullptr,
+                 data_[testType].dt_,
+                 &(data_[testType].x_[0]),
+                 data_[testType].startTime_,
+                 data_[testType].endTime_,
+                 oenv,
+                 false,
+                 type,
+                 result,
+                 0,
+                 nullptr);
         output_env_done(oenv);
         checker_.setDefaultTolerance(test::relativeToleranceAsFloatingPoint(1, tolerance));
         checker_.checkSequenceArray(nfitparm, result, "result");
index d57300371103bb1f17b690a93ac1716f31560432..48fca9eebf94efc4d3d885c364acca8bee4595d1 100644 (file)
@@ -32,6 +32,8 @@
 # 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 up the module library
+add_library(domdec INTERFACE)
 file(GLOB DOMDEC_SOURCES *.cpp)
 
 if(GMX_GPU_CUDA)
@@ -40,6 +42,36 @@ endif()
 
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${DOMDEC_SOURCES} ${DOMDEC_CUDA_SOURCES} PARENT_SCOPE)
 
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(domdec PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(domdec PUBLIC
+target_include_directories(domdec INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(domdec PUBLIC
+target_link_libraries(domdec INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when domdec is an OBJECT target
+#target_link_libraries(domdec PUBLIC legacy_api)
+#target_link_libraries(domdec PRIVATE common)
+
+# Module dependencies
+# domdec interfaces convey transitive dependence on these modules.
+#target_link_libraries(domdec PUBLIC
+target_link_libraries(domdec INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(domdec PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(domdec PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index 8c342f84380cac78f50f71b896a70352cf4f466a..a614ebe2026b1637327b224684a326ce5d65f771 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2009,2010,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/domdec/domdec.h"
 #include "gromacs/domdec/domdec_network.h"
 #include "gromacs/domdec/domdec_struct.h"
+#include "gromacs/domdec/nsgrid.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/vec.h"
-#include "gromacs/mdlib/nsgrid.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/pbcutil/pbc.h"
@@ -124,16 +124,12 @@ static void calc_pos_av_stddev(gmx::ArrayRef<const gmx::RVec> x, rvec av, rvec s
 /*! \brief Determines if dimensions require triclinic treatment and stores this info in ddbox */
 static void set_tric_dir(const ivec* dd_nc, gmx_ddbox_t* ddbox, const matrix box)
 {
-    int   npbcdim, d, i, j;
-    rvec *v, *normal;
-    real  dep, inv_skew_fac2;
-
-    npbcdim = ddbox->npbcdim;
-    normal  = ddbox->normal;
-    for (d = 0; d < DIM; d++)
+    int   npbcdim = ddbox->npbcdim;
+    rvec* normal  = ddbox->normal;
+    for (int d = 0; d < DIM; d++)
     {
         ddbox->tric_dir[d] = 0;
-        for (j = d + 1; j < npbcdim; j++)
+        for (int j = d + 1; j < npbcdim; j++)
         {
             if (box[j][d] != 0)
             {
@@ -144,8 +140,13 @@ static void set_tric_dir(const ivec* dd_nc, gmx_ddbox_t* ddbox, const matrix box
                               "Domain decomposition has not been implemented for box vectors that "
                               "have non-zero components in directions that do not use domain "
                               "decomposition: ncells = %d %d %d, box vector[%d] = %f %f %f",
-                              (*dd_nc)[XX], (*dd_nc)[YY], (*dd_nc)[ZZ], j + 1, box[j][XX],
-                              box[j][YY], box[j][ZZ]);
+                              (*dd_nc)[XX],
+                              (*dd_nc)[YY],
+                              (*dd_nc)[ZZ],
+                              j + 1,
+                              box[j][XX],
+                              box[j][YY],
+                              box[j][ZZ]);
                 }
             }
         }
@@ -161,13 +162,13 @@ static void set_tric_dir(const ivec* dd_nc, gmx_ddbox_t* ddbox, const matrix box
          */
         if (ddbox->tric_dir[d])
         {
-            inv_skew_fac2 = 1;
-            v             = ddbox->v[d];
+            real  inv_skew_fac2 = 1;
+            rvec* v             = ddbox->v[d];
             if (d == XX || d == YY)
             {
                 /* Normalize such that the "diagonal" is 1 */
                 svmul(1 / box[d + 1][d + 1], box[d + 1], v[d + 1]);
-                for (i = 0; i < d; i++)
+                for (int i = 0; i < d; i++)
                 {
                     v[d + 1][i] = 0;
                 }
@@ -177,8 +178,8 @@ static void set_tric_dir(const ivec* dd_nc, gmx_ddbox_t* ddbox, const matrix box
                     /* Normalize such that the "diagonal" is 1 */
                     svmul(1 / box[d + 2][d + 2], box[d + 2], v[d + 2]);
                     /* Set v[d+2][d+1] to zero by shifting along v[d+1] */
-                    dep = v[d + 2][d + 1] / v[d + 1][d + 1];
-                    for (i = 0; i < DIM; i++)
+                    const real dep = v[d + 2][d + 1] / v[d + 1][d + 1];
+                    for (int i = 0; i < DIM; i++)
                     {
                         v[d + 2][i] -= dep * v[d + 1][i];
                     }
@@ -196,7 +197,7 @@ static void set_tric_dir(const ivec* dd_nc, gmx_ddbox_t* ddbox, const matrix box
                 if (debug)
                 {
                     fprintf(debug, "box[%d]  %.3f %.3f %.3f\n", d, box[d][XX], box[d][YY], box[d][ZZ]);
-                    for (i = d + 1; i < DIM; i++)
+                    for (int i = d + 1; i < DIM; i++)
                     {
                         fprintf(debug, "  v[%d]  %.3f %.3f %.3f\n", i, v[i][XX], v[i][YY], v[i][ZZ]);
                     }
@@ -204,21 +205,20 @@ static void set_tric_dir(const ivec* dd_nc, gmx_ddbox_t* ddbox, const matrix box
             }
             ddbox->skew_fac[d] = 1.0 / std::sqrt(inv_skew_fac2);
             /* Set the normal vector length to skew_fac */
-            dep = ddbox->skew_fac[d] / norm(normal[d]);
+            const real dep = ddbox->skew_fac[d] / norm(normal[d]);
             svmul(dep, normal[d], normal[d]);
 
             if (debug)
             {
                 fprintf(debug, "skew_fac[%d] = %f\n", d, ddbox->skew_fac[d]);
-                fprintf(debug, "normal[%d]  %.3f %.3f %.3f\n", d, normal[d][XX], normal[d][YY],
-                        normal[d][ZZ]);
+                fprintf(debug, "normal[%d]  %.3f %.3f %.3f\n", d, normal[d][XX], normal[d][YY], normal[d][ZZ]);
             }
         }
         else
         {
             ddbox->skew_fac[d] = 1;
 
-            for (i = 0; i < DIM; i++)
+            for (int i = 0; i < DIM; i++)
             {
                 clear_rvec(ddbox->v[d][i]);
                 ddbox->v[d][i][i] = 1;
@@ -240,13 +240,11 @@ static void low_set_ddbox(int                            numPbcDimensions,
                           gmx_ddbox_t*                   ddbox)
 {
     rvec av, stddev;
-    real b0, b1;
-    int  d;
 
     ddbox->npbcdim     = numPbcDimensions;
     ddbox->nboundeddim = numBoundedDimensions;
 
-    for (d = 0; d < numBoundedDimensions; d++)
+    for (int d = 0; d < numBoundedDimensions; d++)
     {
         ddbox->box0[d]     = 0;
         ddbox->box_size[d] = box[d][d];
@@ -256,14 +254,14 @@ static void low_set_ddbox(int                            numPbcDimensions,
     {
         calc_pos_av_stddev(x, av, stddev, mpiCommunicator);
 
-        /* GRID_STDDEV_FAC * stddev
+        /* c_gridStdDevFactor * stddev
          * gives a uniform load for a rectangular block of cg's.
          * For a sphere it is not a bad approximation for 4x1x1 up to 4x2x2.
          */
-        for (d = ddbox->nboundeddim; d < DIM; d++)
+        for (int d = ddbox->nboundeddim; d < DIM; d++)
         {
-            b0 = av[d] - GRID_STDDEV_FAC * stddev[d];
-            b1 = av[d] + GRID_STDDEV_FAC * stddev[d];
+            const real b0 = av[d] - c_gridStdDevFactor * stddev[d];
+            const real b1 = av[d] + c_gridStdDevFactor * stddev[d];
             if (debug)
             {
                 fprintf(debug, "Setting global DD grid boundaries to %f - %f\n", b0, b1);
@@ -289,9 +287,14 @@ void set_ddbox(const gmx_domdec_t&            dd,
         gmx::ArrayRef<const gmx::RVec> xRef = constArrayRefFromArray(
                 x.data(), masterRankHasTheSystemState ? x.size() : dd.comm->atomRanges.numHomeAtoms());
 
-        low_set_ddbox(dd.unitCellInfo.npbcdim, dd.unitCellInfo.numBoundedDimensions, &dd.numCells,
-                      box, calculateUnboundedSize, xRef,
-                      needToReduceCoordinateData ? &dd.mpi_comm_all : nullptr, ddbox);
+        low_set_ddbox(dd.unitCellInfo.npbcdim,
+                      dd.unitCellInfo.numBoundedDimensions,
+                      &dd.numCells,
+                      box,
+                      calculateUnboundedSize,
+                      xRef,
+                      needToReduceCoordinateData ? &dd.mpi_comm_all : nullptr,
+                      ddbox);
     }
 
     if (masterRankHasTheSystemState)
@@ -310,8 +313,8 @@ void set_ddbox_cr(DDRole                         ddRole,
 {
     if (ddRole == DDRole::Master)
     {
-        low_set_ddbox(numPbcDimensions(ir.pbcType), inputrec2nboundeddim(&ir), dd_nc, box, true, x,
-                      nullptr, ddbox);
+        low_set_ddbox(
+                numPbcDimensions(ir.pbcType), inputrec2nboundeddim(&ir), dd_nc, box, true, x, nullptr, ddbox);
     }
 
     gmx_bcast(sizeof(gmx_ddbox_t), ddbox, communicator);
index 01239c8058a5c9c5b2048de02acd7c2aea310f41..0c6e764664a2e6ac11be4a297412cfeac8699fb5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_DOMDEC_BUILDER_H
 #define GMX_DOMDEC_BUILDER_H
 
+#include <memory>
+
 #include "gromacs/math/vectypes.h"
 #include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/classhelpers.h"
 
 struct gmx_domdec_t;
 struct gmx_mtop_t;
@@ -91,7 +92,7 @@ public:
 private:
     class Impl;
     //! Pimpl to hide implementation details
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 4867f64330aebaac43ddc9c040398bae851ae8f0..ed1e6dbbcd389ed62f103df083cfdef73b86194e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,15 +63,11 @@ static void set_pme_maxshift(gmx_domdec_t*      dd,
                              const gmx_ddbox_t* ddbox,
                              const real*        cellFrac)
 {
-    gmx_domdec_comm_t* comm;
-    int                nc, ns, s;
-    int *              xmin, *xmax;
-    real               range, pme_boundary;
-    int                sh;
+    int sh = 0;
 
-    comm = dd->comm;
-    nc   = dd->numCells[ddpme->dim];
-    ns   = ddpme->nslab;
+    gmx_domdec_comm_t* comm = dd->comm;
+    const int          nc   = dd->numCells[ddpme->dim];
+    const int          ns   = ddpme->nslab;
 
     if (!ddpme->dim_match)
     {
@@ -88,22 +84,22 @@ static void set_pme_maxshift(gmx_domdec_t*      dd,
         /* We need to check for all pme nodes which nodes they
          * could possibly need to communicate with.
          */
-        xmin = ddpme->pp_min;
-        xmax = ddpme->pp_max;
+        const int* xmin = ddpme->pp_min;
+        const int* xmax = ddpme->pp_max;
         /* Allow for atoms to be maximally 2/3 times the cut-off
          * out of their DD cell. This is a reasonable balance between
          * between performance and support for most charge-group/cut-off
          * combinations.
          */
-        range = 2.0 / 3.0 * comm->systemInfo.cutoff / ddbox->box_size[ddpme->dim];
+        real range = 2.0 / 3.0 * comm->systemInfo.cutoff / ddbox->box_size[ddpme->dim];
         /* Avoid extra communication when we are exactly at a boundary */
         range *= 0.999;
 
         sh = 1;
-        for (s = 0; s < ns; s++)
+        for (int s = 0; s < ns; s++)
         {
             /* PME slab s spreads atoms between box frac. s/ns and (s+1)/ns */
-            pme_boundary = static_cast<real>(s) / ns;
+            real pme_boundary = static_cast<real>(s) / ns;
             while (sh + 1 < ns
                    && ((s - (sh + 1) >= 0 && cellFrac[xmax[s - (sh + 1)] + 1] + range > pme_boundary)
                        || (s - (sh + 1) < 0 && cellFrac[xmax[s - (sh + 1) + ns] + 1] - 1 + range > pme_boundary)))
@@ -130,11 +126,9 @@ static void set_pme_maxshift(gmx_domdec_t*      dd,
 
 static void check_box_size(const gmx_domdec_t* dd, const gmx_ddbox_t* ddbox)
 {
-    int d, dim;
-
-    for (d = 0; d < dd->ndim; d++)
+    for (int d = 0; d < dd->ndim; d++)
     {
-        dim = dd->dim[d];
+        const int dim = dd->dim[d];
         if (dim < ddbox->nboundeddim
             && ddbox->box_size[dim] * ddbox->skew_fac[dim]
                        < dd->numCells[dim] * dd->comm->cellsize_limit * DD_CELL_MARGIN)
@@ -143,7 +137,10 @@ static void check_box_size(const gmx_domdec_t* dd, const gmx_ddbox_t* ddbox)
                     FARGS,
                     "The %c-size of the box (%f) times the triclinic skew factor (%f) is smaller "
                     "than the number of DD cells (%d) times the smallest allowed cell size (%f)\n",
-                    dim2char(dim), ddbox->box_size[dim], ddbox->skew_fac[dim], dd->numCells[dim],
+                    dim2char(dim),
+                    ddbox->box_size[dim],
+                    ddbox->skew_fac[dim],
+                    dd->numCells[dim],
                     dd->comm->cellsize_limit);
         }
     }
@@ -151,15 +148,13 @@ static void check_box_size(const gmx_domdec_t* dd, const gmx_ddbox_t* ddbox)
 
 real grid_jump_limit(const gmx_domdec_comm_t* comm, real cutoff, int dim_ind)
 {
-    real grid_jump_limit;
-
     /* The distance between the boundaries of cells at distance
      * x+-1,y+-1 or y+-1,z+-1 is limited by the cut-off restrictions
      * and by the fact that cells should not be shifted by more than
      * half their size, such that cg's only shift by one cell
      * at redecomposition.
      */
-    grid_jump_limit = comm->cellsize_limit;
+    real grid_jump_limit = comm->cellsize_limit;
     if (!comm->bVacDLBNoLimit)
     {
         if (comm->bPMELoadBalDLBLimits)
@@ -179,9 +174,7 @@ real grid_jump_limit(const gmx_domdec_comm_t* comm, real cutoff, int dim_ind)
  */
 static real cellsize_min_dlb(gmx_domdec_comm_t* comm, int dim_ind, int dim)
 {
-    real cellsize_min;
-
-    cellsize_min = comm->cellsize_min[dim];
+    real cellsize_min = comm->cellsize_min[dim];
 
     if (!comm->bVacDLBNoLimit)
     {
@@ -294,8 +287,13 @@ set_dd_cell_sizes_slb(gmx_domdec_t* dd, const gmx_ddbox_t* ddbox, int setmode, i
                     "The box size in direction %c (%f) times the triclinic skew factor (%f) is too "
                     "small for a cut-off of %f with %d domain decomposition cells, use 1 or more "
                     "than %d %s or increase the box size in this direction",
-                    dim2char(d), ddbox->box_size[d], ddbox->skew_fac[d], comm->systemInfo.cutoff,
-                    dd->numCells[d], dd->numCells[d], dd->nnodes > dd->numCells[d] ? "cells" : "ranks");
+                    dim2char(d),
+                    ddbox->box_size[d],
+                    ddbox->skew_fac[d],
+                    comm->systemInfo.cutoff,
+                    dd->numCells[d],
+                    dd->numCells[d],
+                    dd->nnodes > dd->numCells[d] ? "cells" : "ranks");
 
             if (setmode == setcellsizeslbLOCAL)
             {
@@ -316,7 +314,10 @@ set_dd_cell_sizes_slb(gmx_domdec_t* dd, const gmx_ddbox_t* ddbox, int setmode, i
     DDRankSetup& ddRankSetup = comm->ddRankSetup;
     for (int d = 0; d < ddRankSetup.npmedecompdim; d++)
     {
-        set_pme_maxshift(dd, &ddRankSetup.ddpme[d], comm->slb_frac[dd->dim[d]] == nullptr, ddbox,
+        set_pme_maxshift(dd,
+                         &ddRankSetup.ddpme[d],
+                         comm->slb_frac[dd->dim[d]] == nullptr,
+                         ddbox,
                          ddRankSetup.ddpme[d].slb_dim_f);
     }
 
@@ -334,17 +335,15 @@ static void dd_cell_sizes_dlb_root_enforce_limits(gmx_domdec_t*      dd,
                                                   real               cellsize_limit_f,
                                                   int                range[])
 {
-    gmx_domdec_comm_t* comm;
-    real               halfway, cellsize_limit_f_i, region_size;
-    gmx_bool           bLastHi  = FALSE;
-    int                nrange[] = { range[0], range[1] };
+    gmx_bool bLastHi  = FALSE;
+    int      nrange[] = { range[0], range[1] };
 
-    region_size = rowMaster->cellFrac[range[1]] - rowMaster->cellFrac[range[0]];
+    const real region_size = rowMaster->cellFrac[range[1]] - rowMaster->cellFrac[range[0]];
 
     GMX_ASSERT(region_size >= (range[1] - range[0]) * cellsize_limit_f,
                "The region should fit all cells at minimum size");
 
-    comm = dd->comm;
+    gmx_domdec_comm_t* comm = dd->comm;
 
     const int ncd = dd->numCells[dim];
 
@@ -367,8 +366,8 @@ static void dd_cell_sizes_dlb_root_enforce_limits(gmx_domdec_t*      dd,
     {
         rowMaster->isCellMin[i] = false;
     }
-    int nmin = 0;
-    int nmin_old;
+    int nmin     = 0;
+    int nmin_old = 0;
     do
     {
         nmin_old = nmin;
@@ -391,14 +390,8 @@ static void dd_cell_sizes_dlb_root_enforce_limits(gmx_domdec_t*      dd,
             if (!rowMaster->isCellMin[i])
             {
                 cell_size[i] *= fac;
-                if (!dimHasPbc && (i == 0 || i == dd->numCells[dim] - 1))
-                {
-                    cellsize_limit_f_i = 0;
-                }
-                else
-                {
-                    cellsize_limit_f_i = cellsize_limit_f;
-                }
+                const real cellsize_limit_f_i =
+                        (!dimHasPbc && (i == 0 || i == dd->numCells[dim] - 1)) ? 0 : cellsize_limit_f;
                 if (cell_size[i] < cellsize_limit_f_i)
                 {
                     rowMaster->isCellMin[i] = true;
@@ -425,8 +418,12 @@ static void dd_cell_sizes_dlb_root_enforce_limits(gmx_domdec_t*      dd,
         gmx_fatal(FARGS,
                   "step %s: the dynamic load balancing could not balance dimension %c: box size "
                   "%f, triclinic skew factor %f, #cells %d, minimum cell size %f\n",
-                  gmx_step_str(step, buf), dim2char(dim), ddbox->box_size[dim],
-                  ddbox->skew_fac[dim], ncd, comm->cellsize_min[dim]);
+                  gmx_step_str(step, buf),
+                  dim2char(dim),
+                  ddbox->box_size[dim],
+                  ddbox->skew_fac[dim],
+                  ncd,
+                  comm->cellsize_min[dim]);
     }
 
     rowMaster->dlbIsLimited = (nmin > 0) || (range[0] > 0) || (range[1] < ncd);
@@ -443,7 +440,7 @@ static void dd_cell_sizes_dlb_root_enforce_limits(gmx_domdec_t*      dd,
          */
         for (int i = range[0] + 1; i < range[1]; i++)
         {
-            halfway = 0.5 * (rowMaster->oldCellFrac[i] + rowMaster->oldCellFrac[i - 1]);
+            real halfway = 0.5 * (rowMaster->oldCellFrac[i] + rowMaster->oldCellFrac[i - 1]);
             if (rowMaster->cellFrac[i] < halfway)
             {
                 rowMaster->cellFrac[i] = halfway;
@@ -502,13 +499,13 @@ static void dd_cell_sizes_dlb_root_enforce_limits(gmx_domdec_t*      dd,
                     rowMaster->cellFrac[i] = 0.5 * (bounds.boundMin + bounds.boundMax);
                     nrange[0]              = range[0];
                     nrange[1]              = i;
-                    dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, rowMaster, ddbox, bUniform,
-                                                          step, cellsize_limit_f, nrange);
+                    dd_cell_sizes_dlb_root_enforce_limits(
+                            dd, d, dim, rowMaster, ddbox, bUniform, step, cellsize_limit_f, nrange);
 
                     nrange[0] = i;
                     nrange[1] = range[1];
-                    dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, rowMaster, ddbox, bUniform,
-                                                          step, cellsize_limit_f, nrange);
+                    dd_cell_sizes_dlb_root_enforce_limits(
+                            dd, d, dim, rowMaster, ddbox, bUniform, step, cellsize_limit_f, nrange);
 
                     return;
                 }
@@ -524,14 +521,14 @@ static void dd_cell_sizes_dlb_root_enforce_limits(gmx_domdec_t*      dd,
                     if (nrange[1] < range[1]) /* found a LimLo before */
                     {
                         rowMaster->cellFrac[nrange[1]] = rowMaster->bounds[nrange[1]].boundMin;
-                        dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, rowMaster, ddbox, bUniform,
-                                                              step, cellsize_limit_f, nrange);
+                        dd_cell_sizes_dlb_root_enforce_limits(
+                                dd, d, dim, rowMaster, ddbox, bUniform, step, cellsize_limit_f, nrange);
                         nrange[0] = nrange[1];
                     }
                     rowMaster->cellFrac[i] = rowMaster->bounds[i].boundMax;
                     nrange[1]              = i;
-                    dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, rowMaster, ddbox, bUniform,
-                                                          step, cellsize_limit_f, nrange);
+                    dd_cell_sizes_dlb_root_enforce_limits(
+                            dd, d, dim, rowMaster, ddbox, bUniform, step, cellsize_limit_f, nrange);
                     nrange[0] = i;
                     nrange[1] = range[1];
                 }
@@ -539,17 +536,17 @@ static void dd_cell_sizes_dlb_root_enforce_limits(gmx_domdec_t*      dd,
             if (nrange[1] < range[1]) /* found last a LimLo */
             {
                 rowMaster->cellFrac[nrange[1]] = rowMaster->bounds[nrange[1]].boundMin;
-                dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, rowMaster, ddbox, bUniform, step,
-                                                      cellsize_limit_f, nrange);
+                dd_cell_sizes_dlb_root_enforce_limits(
+                        dd, d, dim, rowMaster, ddbox, bUniform, step, cellsize_limit_f, nrange);
                 nrange[0] = nrange[1];
                 nrange[1] = range[1];
-                dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, rowMaster, ddbox, bUniform, step,
-                                                      cellsize_limit_f, nrange);
+                dd_cell_sizes_dlb_root_enforce_limits(
+                        dd, d, dim, rowMaster, ddbox, bUniform, step, cellsize_limit_f, nrange);
             }
             else if (nrange[0] > range[0]) /* found at least one LimHi */
             {
-                dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, rowMaster, ddbox, bUniform, step,
-                                                      cellsize_limit_f, nrange);
+                dd_cell_sizes_dlb_root_enforce_limits(
+                        dd, d, dim, rowMaster, ddbox, bUniform, step, cellsize_limit_f, nrange);
             }
         }
     }
@@ -594,16 +591,14 @@ static void set_dd_cell_sizes_dlb_root(gmx_domdec_t*      dd,
     {
         real load_aver  = comm->load[d].sum_m / ncd;
         real change_max = 0;
-        real load_i;
-        real change;
         for (int i = 0; i < ncd; i++)
         {
             /* Determine the relative imbalance of cell i */
-            load_i         = comm->load[d].load[i * comm->load[d].nload + 2];
-            real imbalance = (load_i - load_aver) / (load_aver > 0 ? load_aver : 1);
+            const real load_i    = comm->load[d].load[i * comm->load[d].nload + 2];
+            const real imbalance = (load_i - load_aver) / (load_aver > 0 ? load_aver : 1);
             /* Determine the change of the cell size using underrelaxation */
-            change     = -c_relax * imbalance;
-            change_max = std::max(change_max, std::max(change, -change));
+            const real change = -c_relax * imbalance;
+            change_max        = std::max(change_max, std::max(change, -change));
         }
         /* Limit the amount of scaling.
          * We need to use the same rescaling for all cells in one row,
@@ -617,10 +612,10 @@ static void set_dd_cell_sizes_dlb_root(gmx_domdec_t*      dd,
         for (int i = 0; i < ncd; i++)
         {
             /* Determine the relative imbalance of cell i */
-            load_i         = comm->load[d].load[i * comm->load[d].nload + 2];
-            real imbalance = (load_i - load_aver) / (load_aver > 0 ? load_aver : 1);
+            const real load_i    = comm->load[d].load[i * comm->load[d].nload + 2];
+            const real imbalance = (load_i - load_aver) / (load_aver > 0 ? load_aver : 1);
             /* Determine the change of the cell size using underrelaxation */
-            change       = -sc * imbalance;
+            const real change = -sc * imbalance;
             cell_size[i] = (rowMaster->cellFrac[i + 1] - rowMaster->cellFrac[i]) * (1 + change);
         }
     }
@@ -664,17 +659,23 @@ static void set_dd_cell_sizes_dlb_root(gmx_domdec_t*      dd,
             }
             if (debug)
             {
-                fprintf(debug, "dim %d boundary %d %.3f < %.3f < %.3f < %.3f < %.3f\n", d, i,
-                        boundsNeighbor.cellFracLowerMax + dist_min_f, bounds.boundMin,
-                        rowMaster->cellFrac[i], bounds.boundMax, bounds.cellFracUpperMin - dist_min_f);
+                fprintf(debug,
+                        "dim %d boundary %d %.3f < %.3f < %.3f < %.3f < %.3f\n",
+                        d,
+                        i,
+                        boundsNeighbor.cellFracLowerMax + dist_min_f,
+                        bounds.boundMin,
+                        rowMaster->cellFrac[i],
+                        bounds.boundMax,
+                        bounds.cellFracUpperMin - dist_min_f);
             }
         }
     }
     range[1]                 = ncd;
     rowMaster->cellFrac[0]   = 0;
     rowMaster->cellFrac[ncd] = 1;
-    dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, rowMaster, ddbox, bUniform, step,
-                                          cellsize_limit_f, range);
+    dd_cell_sizes_dlb_root_enforce_limits(
+            dd, d, dim, rowMaster, ddbox, bUniform, step, cellsize_limit_f, range);
 
 
     /* After the checks above, the cells should obey the cut-off
@@ -684,16 +685,23 @@ static void set_dd_cell_sizes_dlb_root(gmx_domdec_t*      dd,
     {
         if (debug)
         {
-            fprintf(debug, "Relative bounds dim %d  cell %d: %f %f\n", dim, i,
-                    rowMaster->cellFrac[i], rowMaster->cellFrac[i + 1]);
+            fprintf(debug,
+                    "Relative bounds dim %d  cell %d: %f %f\n",
+                    dim,
+                    i,
+                    rowMaster->cellFrac[i],
+                    rowMaster->cellFrac[i + 1]);
         }
 
         if ((bPBC || (i != 0 && i != dd->numCells[dim] - 1))
             && rowMaster->cellFrac[i + 1] - rowMaster->cellFrac[i] < cellsize_limit_f / DD_CELL_MARGIN)
         {
             char buf[22];
-            fprintf(stderr, "\nWARNING step %s: direction %c, cell %d too small: %f\n",
-                    gmx_step_str(step, buf), dim2char(dim), i,
+            fprintf(stderr,
+                    "\nWARNING step %s: direction %c, cell %d too small: %f\n",
+                    gmx_step_str(step, buf),
+                    dim2char(dim),
+                    i,
                     (rowMaster->cellFrac[i + 1] - rowMaster->cellFrac[i]) * ddbox->box_size[dim]
                             * ddbox->skew_fac[dim]);
         }
@@ -750,7 +758,10 @@ static void distribute_dd_cell_sizes_dlb(gmx_domdec_t*       dd,
     /* Each node would only need to know two fractions,
      * but it is probably cheaper to broadcast the whole array.
      */
-    MPI_Bcast(cellFracRow.data(), ddCellFractionBufferSize(dd, d) * sizeof(real), MPI_BYTE, 0,
+    MPI_Bcast(cellFracRow.data(),
+              ddCellFractionBufferSize(dd, d) * sizeof(real),
+              MPI_BYTE,
+              0,
               comm.mpi_comm_load[d]);
 #endif
     /* Copy the fractions for this dimension from the buffer */
@@ -820,13 +831,11 @@ static void set_dd_cell_sizes_dlb_change(gmx_domdec_t*      dd,
 
 static void set_dd_cell_sizes_dlb_nochange(gmx_domdec_t* dd, const gmx_ddbox_t* ddbox)
 {
-    int d;
-
     /* This function assumes the box is static and should therefore
      * not be called when the box has changed since the last
      * call to dd_partition_system.
      */
-    for (d = 0; d < dd->ndim; d++)
+    for (int d = 0; d < dd->ndim; d++)
     {
         relative_to_absolute_cell_bounds(dd, ddbox, d);
     }
@@ -839,18 +848,15 @@ static void set_dd_cell_sizes_dlb(gmx_domdec_t*      dd,
                                   gmx_bool           bUniform,
                                   gmx_bool           bDoDLB,
                                   int64_t            step,
-                                  gmx_wallcycle_t    wcycle)
+                                  gmx_wallcycle    wcycle)
 {
-    gmx_domdec_comm_t* comm;
-    int                dim;
-
-    comm = dd->comm;
+    gmx_domdec_comm_t* comm = dd->comm;
 
     if (bDoDLB)
     {
-        wallcycle_start(wcycle, ewcDDCOMMBOUND);
+        wallcycle_start(wcycle, WallCycleCounter::DDCommBound);
         set_dd_cell_sizes_dlb_change(dd, ddbox, bDynamicBox, bUniform, step);
-        wallcycle_stop(wcycle, ewcDDCOMMBOUND);
+        wallcycle_stop(wcycle, WallCycleCounter::DDCommBound);
     }
     else if (bDynamicBox)
     {
@@ -858,7 +864,7 @@ static void set_dd_cell_sizes_dlb(gmx_domdec_t*      dd,
     }
 
     /* Set the dimensions for which no DD is used */
-    for (dim = 0; dim < DIM; dim++)
+    for (int dim = 0; dim < DIM; dim++)
     {
         if (dd->numCells[dim] == 1)
         {
@@ -879,7 +885,7 @@ void set_dd_cell_sizes(gmx_domdec_t*      dd,
                        gmx_bool           bUniform,
                        gmx_bool           bDoDLB,
                        int64_t            step,
-                       gmx_wallcycle_t    wcycle)
+                       gmx_wallcycle    wcycle)
 {
     gmx_domdec_comm_t* comm = dd->comm;
 
@@ -914,7 +920,9 @@ void set_dd_cell_sizes(gmx_domdec_t*      dd,
                     fprintf(debug,
                             "Changing the number of halo communication pulses along dim %c from %d "
                             "to %d\n",
-                            dim2char(dd->dim[d]), cd.numPulses(), numPulsesDim);
+                            dim2char(dd->dim[d]),
+                            cd.numPulses(),
+                            numPulsesDim);
                 }
                 cd.ind.resize(numPulsesDim);
             }
@@ -925,8 +933,12 @@ void set_dd_cell_sizes(gmx_domdec_t*      dd,
     {
         for (int d = 0; d < DIM; d++)
         {
-            fprintf(debug, "cell_x[%d] %f - %f skew_fac %f\n", d, comm->cell_x0[d],
-                    comm->cell_x1[d], ddbox->skew_fac[d]);
+            fprintf(debug,
+                    "cell_x[%d] %f - %f skew_fac %f\n",
+                    d,
+                    comm->cell_x0[d],
+                    comm->cell_x1[d],
+                    ddbox->skew_fac[d]);
         }
     }
 }
index cf07585e89c62133cae9a41c677865a55608d826..794eb27457972125d3ccf940868e547df6d8a952 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@ void set_dd_cell_sizes(gmx_domdec_t*      dd,
                        gmx_bool           bUniform,
                        gmx_bool           bDoDLB,
                        int64_t            step,
-                       gmx_wallcycle_t    wcycle);
+                       gmx_wallcycle    wcycle);
 
 #endif
index 0924461f7889ff28364c06e9e66241240df54235..6d6c4a2dc45087ac5ef096b69ea445954894f5b7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/domdec/domdec_network.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdtypes/state.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 
 #include "atomdistribution.h"
@@ -134,7 +135,9 @@ static void dd_collect_cg(gmx_domdec_t*            dd,
     }
 
     /* Collect the charge group indices on the master */
-    dd_gatherv(dd, atomGroups.size() * sizeof(int), atomGroups.data(),
+    dd_gatherv(dd,
+               atomGroups.size() * sizeof(int),
+               atomGroups.data(),
                DDMASTER(dd) ? ma->intBuffer.data() : nullptr,
                DDMASTER(dd) ? ma->intBuffer.data() + dd->nnodes : nullptr,
                DDMASTER(dd) ? ma->atomGroups.data() : nullptr);
@@ -151,7 +154,11 @@ static void dd_collect_vec_sendrecv(gmx_domdec_t*                  dd,
 #if GMX_MPI
         const int numHomeAtoms = dd->comm->atomRanges.numHomeAtoms();
         MPI_Send(const_cast<void*>(static_cast<const void*>(lv.data())),
-                 numHomeAtoms * sizeof(rvec), MPI_BYTE, dd->masterrank, dd->rank, dd->mpi_comm_all);
+                 numHomeAtoms * sizeof(rvec),
+                 MPI_BYTE,
+                 dd->masterrank,
+                 dd->rank,
+                 dd->mpi_comm_all);
 #endif
     }
     else
@@ -183,8 +190,13 @@ static void dd_collect_vec_sendrecv(gmx_domdec_t*                  dd,
                 }
 
 #if GMX_MPI
-                MPI_Recv(ma.rvecBuffer.data(), domainGroups.numAtoms * sizeof(rvec), MPI_BYTE, rank,
-                         rank, dd->mpi_comm_all, MPI_STATUS_IGNORE);
+                MPI_Recv(ma.rvecBuffer.data(),
+                         domainGroups.numAtoms * sizeof(rvec),
+                         MPI_BYTE,
+                         rank,
+                         rank,
+                         dd->mpi_comm_all,
+                         MPI_STATUS_IGNORE);
 #endif
                 int localAtom = 0;
                 for (const int& globalAtom : domainGroups.atomGroups)
@@ -209,7 +221,11 @@ static void dd_collect_vec_gatherv(gmx_domdec_t*                  dd,
     }
 
     const int numHomeAtoms = dd->comm->atomRanges.numHomeAtoms();
-    dd_gatherv(dd, numHomeAtoms * sizeof(rvec), lv.data(), recvCounts, displacements,
+    dd_gatherv(dd,
+               numHomeAtoms * sizeof(rvec),
+               lv.data(),
+               recvCounts,
+               displacements,
                DDMASTER(dd) ? dd->ma->rvecBuffer.data() : nullptr);
 
     if (DDMASTER(dd))
@@ -257,7 +273,7 @@ void dd_collect_state(gmx_domdec_t* dd, const t_state* state_local, t_state* sta
         GMX_RELEASE_ASSERT(state->nhchainlength == nh,
                            "The global and local Nose-Hoover chain lengths should match");
 
-        for (int i = 0; i < efptNR; i++)
+        for (auto i : gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real>::keys())
         {
             state->lambda[i] = state_local->lambda[i];
         }
@@ -290,22 +306,34 @@ void dd_collect_state(gmx_domdec_t* dd, const t_state* state_local, t_state* sta
         state->baros_integral     = state_local->baros_integral;
         state->pull_com_prev_step = state_local->pull_com_prev_step;
     }
-    if (state_local->flags & (1 << estX))
+    if (state_local->flags & enumValueToBitMask(StateEntry::X))
     {
         auto globalXRef = state ? state->x : gmx::ArrayRef<gmx::RVec>();
-        dd_collect_vec(dd, state_local->ddp_count, state_local->ddp_count_cg_gl, state_local->cg_gl,
-                       state_local->x, globalXRef);
+        dd_collect_vec(dd,
+                       state_local->ddp_count,
+                       state_local->ddp_count_cg_gl,
+                       state_local->cg_gl,
+                       state_local->x,
+                       globalXRef);
     }
-    if (state_local->flags & (1 << estV))
+    if (state_local->flags & enumValueToBitMask(StateEntry::V))
     {
         auto globalVRef = state ? state->v : gmx::ArrayRef<gmx::RVec>();
-        dd_collect_vec(dd, state_local->ddp_count, state_local->ddp_count_cg_gl, state_local->cg_gl,
-                       state_local->v, globalVRef);
+        dd_collect_vec(dd,
+                       state_local->ddp_count,
+                       state_local->ddp_count_cg_gl,
+                       state_local->cg_gl,
+                       state_local->v,
+                       globalVRef);
     }
-    if (state_local->flags & (1 << estCGP))
+    if (state_local->flags & enumValueToBitMask(StateEntry::Cgp))
     {
         auto globalCgpRef = state ? state->cg_p : gmx::ArrayRef<gmx::RVec>();
-        dd_collect_vec(dd, state_local->ddp_count, state_local->ddp_count_cg_gl, state_local->cg_gl,
-                       state_local->cg_p, globalCgpRef);
+        dd_collect_vec(dd,
+                       state_local->ddp_count,
+                       state_local->ddp_count_cg_gl,
+                       state_local->cg_gl,
+                       state_local->cg_p,
+                       globalCgpRef);
     }
 }
index 062acc6b570c712254536c922220ad6dcb1a1adc..8e1f05c9d64cbd33348cfd0e0622aa99a90726bb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/mdtypes/df_history.h"
 #include "gromacs/mdtypes/state.h"
 #include "gromacs/topology/topology.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/logger.h"
 
@@ -87,8 +88,7 @@ static void distributeVecSendrecv(gmx_domdec_t*                  dd,
                                    "The index count and number of indices should match");
 
 #if GMX_MPI
-                MPI_Send(buffer.data(), domainGroups.numAtoms * sizeof(gmx::RVec), MPI_BYTE, rank,
-                         rank, dd->mpi_comm_all);
+                MPI_Send(buffer.data(), domainGroups.numAtoms * sizeof(gmx::RVec), MPI_BYTE, rank, rank, dd->mpi_comm_all);
 #endif
             }
         }
@@ -104,8 +104,13 @@ static void distributeVecSendrecv(gmx_domdec_t*                  dd,
     {
 #if GMX_MPI
         int numHomeAtoms = dd->comm->atomRanges.numHomeAtoms();
-        MPI_Recv(localVec.data(), numHomeAtoms * sizeof(gmx::RVec), MPI_BYTE, dd->masterrank,
-                 MPI_ANY_TAG, dd->mpi_comm_all, MPI_STATUS_IGNORE);
+        MPI_Recv(localVec.data(),
+                 numHomeAtoms * sizeof(gmx::RVec),
+                 MPI_BYTE,
+                 dd->masterrank,
+                 MPI_ANY_TAG,
+                 dd->mpi_comm_all,
+                 MPI_STATUS_IGNORE);
 #endif
     }
 }
@@ -136,8 +141,12 @@ static void distributeVecScatterv(gmx_domdec_t*                  dd,
     }
 
     int numHomeAtoms = dd->comm->atomRanges.numHomeAtoms();
-    dd_scatterv(dd, sendCounts, displacements, DDMASTER(dd) ? dd->ma->rvecBuffer.data() : nullptr,
-                numHomeAtoms * sizeof(gmx::RVec), localVec.data());
+    dd_scatterv(dd,
+                sendCounts,
+                displacements,
+                DDMASTER(dd) ? dd->ma->rvecBuffer.data() : nullptr,
+                numHomeAtoms * sizeof(gmx::RVec),
+                localVec.data());
 }
 
 static void distributeVec(gmx_domdec_t*                  dd,
@@ -196,7 +205,7 @@ static void dd_distribute_state(gmx_domdec_t* dd, const t_state* state, t_state*
         GMX_RELEASE_ASSERT(state->nhchainlength == nh,
                            "The global and local Nose-Hoover chain lengths should match");
 
-        for (int i = 0; i < efptNR; i++)
+        for (auto i : gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real>::keys())
         {
             state_local->lambda[i] = state->lambda[i];
         }
@@ -231,7 +240,9 @@ static void dd_distribute_state(gmx_domdec_t* dd, const t_state* state, t_state*
         }
         state_local->baros_integral = state->baros_integral;
     }
-    dd_bcast(dd, ((efptNR) * sizeof(real)), state_local->lambda.data());
+    dd_bcast(dd,
+             (static_cast<int>(FreeEnergyPerturbationCouplingType::Count) * 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);
@@ -251,15 +262,15 @@ static void dd_distribute_state(gmx_domdec_t* dd, const t_state* state, t_state*
 
     state_change_natoms(state_local, dd->comm->atomRanges.numHomeAtoms());
 
-    if (state_local->flags & (1 << estX))
+    if (state_local->flags & enumValueToBitMask(StateEntry::X))
     {
         distributeVec(dd, DDMASTER(dd) ? state->x : gmx::ArrayRef<const gmx::RVec>(), state_local->x);
     }
-    if (state_local->flags & (1 << estV))
+    if (state_local->flags & enumValueToBitMask(StateEntry::V))
     {
         distributeVec(dd, DDMASTER(dd) ? state->v : gmx::ArrayRef<const gmx::RVec>(), state_local->v);
     }
-    if (state_local->flags & (1 << estCGP))
+    if (state_local->flags & enumValueToBitMask(StateEntry::Cgp))
     {
         distributeVec(dd, DDMASTER(dd) ? state->cg_p : gmx::ArrayRef<const gmx::RVec>(), state_local->cg_p);
     }
@@ -278,7 +289,7 @@ static inline int computeAtomGroupDomainIndex(const gmx_domdec_t& dd,
                                               const matrix                           box,
                                               rvec*                                  pos)
 {
-    /* Set the reference location cg_cm for assigning the group */
+    /* Set the reference location for assigning the group */
     rvec cog;
     int  numAtoms = atomEnd - atomBegin;
     if (numAtoms == 1)
@@ -395,18 +406,17 @@ static std::vector<std::vector<int>> getAtomGroupDistribution(const gmx::MDLogge
         for (const gmx_molblock_t& molblock : mtop.molblock)
         {
             const auto& updateGrouping =
-                    dd->comm->systemInfo.updateGroupingPerMoleculetype[molblock.type];
+                    dd->comm->systemInfo.updateGroupingsPerMoleculeType[molblock.type];
 
             for (int mol = 0; mol < molblock.nmol; mol++)
             {
                 for (int g = 0; g < updateGrouping.numBlocks(); g++)
                 {
-                    const auto& block     = updateGrouping.block(g);
-                    const int   atomBegin = atomOffset + block.begin();
-                    const int   atomEnd   = atomOffset + block.end();
-                    const int   domainIndex =
-                            computeAtomGroupDomainIndex(*dd, ddbox, triclinicCorrectionMatrix,
-                                                        cellBoundaries, atomBegin, atomEnd, box, pos);
+                    const auto& block       = updateGrouping.block(g);
+                    const int   atomBegin   = atomOffset + block.begin();
+                    const int   atomEnd     = atomOffset + block.end();
+                    const int   domainIndex = computeAtomGroupDomainIndex(
+                            *dd, ddbox, triclinicCorrectionMatrix, cellBoundaries, atomBegin, atomEnd, box, pos);
 
                     for (int atomIndex : block)
                     {
@@ -426,8 +436,8 @@ static std::vector<std::vector<int>> getAtomGroupDistribution(const gmx::MDLogge
         /* Compute the center of geometry for all atoms */
         for (int atom = 0; atom < mtop.natoms; atom++)
         {
-            int domainIndex = computeAtomGroupDomainIndex(*dd, ddbox, triclinicCorrectionMatrix,
-                                                          cellBoundaries, atom, atom + 1, box, pos);
+            int domainIndex = computeAtomGroupDomainIndex(
+                    *dd, ddbox, triclinicCorrectionMatrix, cellBoundaries, atom, atom + 1, box, pos);
 
             indices[domainIndex].push_back(atom);
             ma.domainGroups[domainIndex].numAtoms += 1;
@@ -437,13 +447,10 @@ static std::vector<std::vector<int>> getAtomGroupDistribution(const gmx::MDLogge
     {
         // Use double for the sums to avoid natoms^2 overflowing
         // (65537^2 > 2^32)
-        int    nat_sum, nat_min, nat_max;
-        double nat2_sum;
-
-        nat_sum  = 0;
-        nat2_sum = 0;
-        nat_min  = ma.domainGroups[0].numAtoms;
-        nat_max  = ma.domainGroups[0].numAtoms;
+        int    nat_sum  = 0;
+        double nat2_sum = 0;
+        int    nat_min  = ma.domainGroups[0].numAtoms;
+        int    nat_max  = ma.domainGroups[0].numAtoms;
         for (int rank = 0; rank < dd->nnodes; rank++)
         {
             int numAtoms = ma.domainGroups[rank].numAtoms;
@@ -459,9 +466,11 @@ static std::vector<std::vector<int>> getAtomGroupDistribution(const gmx::MDLogge
         GMX_LOG(mdlog.info)
                 .appendTextFormatted(
                         "Atom distribution over %d domains: av %d stddev %d min %d max %d",
-                        dd->nnodes, nat_sum,
+                        dd->nnodes,
+                        nat_sum,
                         gmx::roundToInt(std::sqrt(nat2_sum - gmx::square(static_cast<double>(nat_sum)))),
-                        nat_min, nat_max);
+                        nat_min,
+                        nat_max);
     }
 
     return indices;
@@ -474,8 +483,8 @@ static void distributeAtomGroups(const gmx::MDLogger& mdlog,
                                  const gmx_ddbox_t*   ddbox,
                                  rvec                 pos[])
 {
-    AtomDistribution* ma = dd->ma.get();
-    int *             ibuf, buf2[2] = { 0, 0 };
+    AtomDistribution* ma   = dd->ma.get();
+    int *             ibuf = nullptr, buf2[2] = { 0, 0 };
     gmx_bool          bMaster = DDMASTER(dd);
 
     std::vector<std::vector<int>> groupIndices;
@@ -519,8 +528,8 @@ static void distributeAtomGroups(const gmx::MDLogger& mdlog,
             ma->intBuffer[rank]              = groupIndices[rank].size() * sizeof(int);
             ma->intBuffer[dd->nnodes + rank] = groupOffset * sizeof(int);
 
-            ma->atomGroups.insert(ma->atomGroups.end(), groupIndices[rank].begin(),
-                                  groupIndices[rank].end());
+            ma->atomGroups.insert(
+                    ma->atomGroups.end(), groupIndices[rank].begin(), groupIndices[rank].end());
 
             ma->domainGroups[rank].atomGroups = gmx::constArrayRefFromArray(
                     ma->atomGroups.data() + groupOffset, groupIndices[rank].size());
@@ -529,9 +538,11 @@ static void distributeAtomGroups(const gmx::MDLogger& mdlog,
         }
     }
 
-    dd_scatterv(dd, bMaster ? ma->intBuffer.data() : nullptr,
+    dd_scatterv(dd,
+                bMaster ? ma->intBuffer.data() : nullptr,
                 bMaster ? ma->intBuffer.data() + dd->nnodes : nullptr,
-                bMaster ? ma->atomGroups.data() : nullptr, dd->ncg_home * sizeof(int),
+                bMaster ? ma->atomGroups.data() : nullptr,
+                dd->ncg_home * sizeof(int),
                 dd->globalAtomGroupIndices.data());
 
     if (debug)
index 1c1fd9376eed0da5bb1ee8185efbbe12ab90fbe4..c13fc4a8b4781b3f5f387c940c3e42e45821fe04 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -175,17 +175,13 @@ void DDBalanceRegionHandler::closeRegionGpuImpl(float waitGpuCyclesInCpuRegion,
 //! Accumulates flop counts for force calculations.
 static double force_flop_count(const t_nrnb* nrnb)
 {
-    int         i;
-    double      sum;
-    const char* name;
-
-    sum = 0;
-    for (i = 0; i < eNR_NBKERNEL_FREE_ENERGY; i++)
+    double sum = 0;
+    for (int i = 0; i < eNR_NBKERNEL_FREE_ENERGY; i++)
     {
         /* To get closer to the real timings, we half the count
          * for the normal loops and again half it for water loops.
          */
-        name = nrnb_str(i);
+        const char* name = nrnb_str(i);
         if (strstr(name, "W3") != nullptr || strstr(name, "W4") != nullptr)
         {
             sum += nrnb->n[i] * 0.25 * cost_nrnb(i);
@@ -195,15 +191,15 @@ static double force_flop_count(const t_nrnb* nrnb)
             sum += nrnb->n[i] * 0.50 * cost_nrnb(i);
         }
     }
-    for (i = eNR_NBKERNEL_FREE_ENERGY; i <= eNR_NB14; i++)
+    for (int i = eNR_NBKERNEL_FREE_ENERGY; i <= eNR_NB14; i++)
     {
-        name = nrnb_str(i);
+        const char* name = nrnb_str(i);
         if (strstr(name, "W3") != nullptr || strstr(name, "W4") != nullptr)
         {
             sum += nrnb->n[i] * cost_nrnb(i);
         }
     }
-    for (i = eNR_BONDS; i <= eNR_WALLS; i++)
+    for (int i = eNR_BONDS; i <= eNR_WALLS; i++)
     {
         sum += nrnb->n[i] * cost_nrnb(i);
     }
@@ -230,9 +226,7 @@ void dd_force_flop_stop(gmx_domdec_t* dd, t_nrnb* nrnb)
 
 void clear_dd_cycle_counts(gmx_domdec_t* dd)
 {
-    int i;
-
-    for (i = 0; i < ddCyclNr; i++)
+    for (int i = 0; i < ddCyclNr; i++)
     {
         dd->comm->cycl[i]     = 0;
         dd->comm->cycl_n[i]   = 0;
index d3ba5aba08ef2f8e997bb988ab5baab865303824..346a09bf6df9bc03d3b1a80e8f800ca1bbe3f139 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2005,2006,2007,2008,2009 by the GROMACS development team.
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
  * Copyright (c) 2015,2016,2017,2018,2019 by the GROMACS development team.
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -92,6 +92,7 @@
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/basenetwork.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxmpi.h"
@@ -119,7 +120,13 @@ using gmx::DdRankOrder;
 using gmx::DlbOption;
 using gmx::DomdecOptions;
 
-static const char* edlbs_names[int(DlbState::nr)] = { "off", "off", "auto", "locked", "on", "on" };
+static const char* enumValueToString(DlbState enumValue)
+{
+    static constexpr gmx::EnumerationArray<DlbState, const char*> dlbStateNames = {
+        "off", "off", "auto", "locked", "on", "on"
+    };
+    return dlbStateNames[enumValue];
+}
 
 /* The size per atom group of the cggl_flag buffer in gmx_domdec_comm_t */
 #define DD_CGIBS 2
@@ -178,7 +185,7 @@ static int ddcoord2ddnodeid(gmx_domdec_t* dd, ivec c)
 
 int ddglatnr(const gmx_domdec_t* dd, int i)
 {
-    int atnr;
+    int atnr = 0;
 
     if (dd == nullptr)
     {
@@ -190,7 +197,8 @@ int ddglatnr(const gmx_domdec_t* dd, int i)
         {
             gmx_fatal(FARGS,
                       "glatnr called with %d, which is larger than the local number of atoms (%d)",
-                      i, dd->comm->atomRanges.numAtomsTotal());
+                      i,
+                      dd->comm->atomRanges.numAtomsTotal());
         }
         atnr = dd->globalAtomIndices[i] + 1;
     }
@@ -198,28 +206,26 @@ int ddglatnr(const gmx_domdec_t* dd, int i)
     return atnr;
 }
 
-gmx::ArrayRef<const gmx::RangePartitioning> getUpdateGroupingPerMoleculetype(const gmx_domdec_t& dd)
+gmx::ArrayRef<const gmx::RangePartitioning> getUpdateGroupingsPerMoleculeType(const gmx_domdec_t& dd)
 {
     GMX_RELEASE_ASSERT(dd.comm, "Need a valid dd.comm");
-    return dd.comm->systemInfo.updateGroupingPerMoleculetype;
+    return dd.comm->systemInfo.updateGroupingsPerMoleculeType;
 }
 
-void dd_store_state(gmx_domdec_t* dd, t_state* state)
+void dd_store_state(const gmx_domdec_t& dd, t_state* state)
 {
-    int i;
-
-    if (state->ddp_count != dd->ddp_count)
+    if (state->ddp_count != dd.ddp_count)
     {
         gmx_incons("The MD state does not match the domain decomposition state");
     }
 
-    state->cg_gl.resize(dd->ncg_home);
-    for (i = 0; i < dd->ncg_home; i++)
+    state->cg_gl.resize(dd.ncg_home);
+    for (int i = 0; i < dd.ncg_home; i++)
     {
-        state->cg_gl[i] = dd->globalAtomGroupIndices[i];
+        state->cg_gl[i] = dd.globalAtomGroupIndices[i];
     }
 
-    state->ddp_count_cg_gl = dd->ddp_count;
+    state->ddp_count_cg_gl = dd.ddp_count;
 }
 
 gmx_domdec_zones_t* domdec_zones(gmx_domdec_t* dd)
@@ -237,49 +243,45 @@ int dd_numHomeAtoms(const gmx_domdec_t& dd)
     return dd.comm->atomRanges.numHomeAtoms();
 }
 
-int dd_natoms_mdatoms(const gmx_domdec_t* dd)
+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->atomRanges.numAtomsTotal();
+    return dd.comm->atomRanges.numAtomsTotal();
 }
 
-int dd_natoms_vsite(const gmx_domdec_t* dd)
+int dd_natoms_vsite(const gmx_domdec_t& dd)
 {
-    return dd->comm->atomRanges.end(DDAtomRanges::Type::Vsites);
+    return dd.comm->atomRanges.end(DDAtomRanges::Type::Vsites);
 }
 
-void dd_get_constraint_range(const gmx_domdec_t* dd, int* at_start, int* at_end)
+void dd_get_constraint_range(const gmx_domdec_t& dd, int* at_start, int* at_end)
 {
-    *at_start = dd->comm->atomRanges.start(DDAtomRanges::Type::Constraints);
-    *at_end   = dd->comm->atomRanges.end(DDAtomRanges::Type::Constraints);
+    *at_start = dd.comm->atomRanges.start(DDAtomRanges::Type::Constraints);
+    *at_end   = dd.comm->atomRanges.end(DDAtomRanges::Type::Constraints);
 }
 
 void dd_move_x(gmx_domdec_t* dd, const matrix box, gmx::ArrayRef<gmx::RVec> x, gmx_wallcycle* wcycle)
 {
-    wallcycle_start(wcycle, ewcMOVEX);
+    wallcycle_start(wcycle, WallCycleCounter::MoveX);
 
-    int                    nzone, nat_tot;
-    gmx_domdec_comm_t*     comm;
-    gmx_domdec_comm_dim_t* cd;
-    rvec                   shift = { 0, 0, 0 };
-    gmx_bool               bPBC, bScrew;
+    rvec shift = { 0, 0, 0 };
 
-    comm = dd->comm;
+    gmx_domdec_comm_t* comm = dd->comm;
 
-    nzone   = 1;
-    nat_tot = comm->atomRanges.numHomeAtoms();
+    int nzone   = 1;
+    int nat_tot = comm->atomRanges.numHomeAtoms();
     for (int d = 0; d < dd->ndim; d++)
     {
-        bPBC   = (dd->ci[dd->dim[d]] == 0);
-        bScrew = (bPBC && dd->unitCellInfo.haveScrewPBC && dd->dim[d] == XX);
+        const bool bPBC   = (dd->ci[dd->dim[d]] == 0);
+        const bool bScrew = (bPBC && dd->unitCellInfo.haveScrewPBC && dd->dim[d] == XX);
         if (bPBC)
         {
             copy_rvec(box[dd->dim[d]], shift);
         }
-        cd = &comm->cd[d];
+        gmx_domdec_comm_dim_t* cd = &comm->cd[d];
         for (const gmx_domdec_ind_t& ind : cd->ind)
         {
             DDBufferAccess<gmx::RVec> sendBufferAccess(comm->rvecBuffer, ind.nsend[nzone + 1]);
@@ -352,12 +354,12 @@ void dd_move_x(gmx_domdec_t* dd, const matrix box, gmx::ArrayRef<gmx::RVec> x, g
         nzone += nzone;
     }
 
-    wallcycle_stop(wcycle, ewcMOVEX);
+    wallcycle_stop(wcycle, WallCycleCounter::MoveX);
 }
 
 void dd_move_f(gmx_domdec_t* dd, gmx::ForceWithShiftForces* forceWithShiftForces, gmx_wallcycle* wcycle)
 {
-    wallcycle_start(wcycle, ewcMOVEF);
+    wallcycle_start(wcycle, WallCycleCounter::MoveF);
 
     gmx::ArrayRef<gmx::RVec> f      = forceWithShiftForces->force();
     gmx::ArrayRef<gmx::RVec> fshift = forceWithShiftForces->shiftForces();
@@ -376,7 +378,7 @@ void dd_move_f(gmx_domdec_t* dd, gmx::ForceWithShiftForces* forceWithShiftForces
         /* Determine which shift vector we need */
         ivec vis        = { 0, 0, 0 };
         vis[dd->dim[d]] = 1;
-        const int is    = IVEC2IS(vis);
+        const int is    = gmx::ivecToShiftIndex(vis);
 
         /* Loop over the pulses */
         const gmx_domdec_comm_dim_t& cd = comm.cd[d];
@@ -461,7 +463,7 @@ void dd_move_f(gmx_domdec_t* dd, gmx::ForceWithShiftForces* forceWithShiftForces
         }
         nzone /= 2;
     }
-    wallcycle_stop(wcycle, ewcMOVEF);
+    wallcycle_stop(wcycle, WallCycleCounter::MoveF);
 }
 
 /* Convenience function for extracting a real buffer from an rvec buffer
@@ -478,17 +480,13 @@ static gmx::ArrayRef<real> realArrayRefFromRvecArrayRef(gmx::ArrayRef<gmx::RVec>
 
 void dd_atom_spread_real(gmx_domdec_t* dd, real v[])
 {
-    int                    nzone, nat_tot;
-    gmx_domdec_comm_t*     comm;
-    gmx_domdec_comm_dim_t* cd;
-
-    comm = dd->comm;
+    gmx_domdec_comm_t* comm = dd->comm;
 
-    nzone   = 1;
-    nat_tot = comm->atomRanges.numHomeAtoms();
+    int nzone   = 1;
+    int nat_tot = comm->atomRanges.numHomeAtoms();
     for (int d = 0; d < dd->ndim; d++)
     {
-        cd = &comm->cd[d];
+        gmx_domdec_comm_dim_t* cd = &comm->cd[d];
         for (const gmx_domdec_ind_t& ind : cd->ind)
         {
             /* Note: We provision for RVec instead of real, so a factor of 3
@@ -536,17 +534,13 @@ void dd_atom_spread_real(gmx_domdec_t* dd, real v[])
 
 void dd_atom_sum_real(gmx_domdec_t* dd, real v[])
 {
-    int                    nzone, nat_tot;
-    gmx_domdec_comm_t*     comm;
-    gmx_domdec_comm_dim_t* cd;
-
-    comm = dd->comm;
+    gmx_domdec_comm_t* comm = dd->comm;
 
-    nzone   = comm->zones.n / 2;
-    nat_tot = comm->atomRanges.end(DDAtomRanges::Type::Zones);
+    int nzone   = comm->zones.n / 2;
+    int nat_tot = comm->atomRanges.end(DDAtomRanges::Type::Zones);
     for (int d = dd->ndim - 1; d >= 0; d--)
     {
-        cd = &comm->cd[d];
+        gmx_domdec_comm_dim_t* cd = &comm->cd[d];
         for (int p = cd->numPulses() - 1; p >= 0; p--)
         {
             const gmx_domdec_ind_t& ind = cd->ind[p];
@@ -629,9 +623,7 @@ real dd_cutoff_multibody(const gmx_domdec_t* dd)
 
 real dd_cutoff_twobody(const gmx_domdec_t* dd)
 {
-    real r_mb;
-
-    r_mb = dd_cutoff_multibody(dd);
+    const real r_mb = dd_cutoff_multibody(dd);
 
     return std::max(dd->comm->systemInfo.cutoff, r_mb);
 }
@@ -685,17 +677,14 @@ static std::vector<int> dd_interleaved_pme_ranks(const DDRankSetup& ddRankSetup)
     return pmeRanks;
 }
 
-static int gmx_ddcoord2pmeindex(const t_commrec* cr, int x, int y, int z)
+static int gmx_ddcoord2pmeindex(const gmx_domdec_t& dd, int x, int y, int z)
 {
-    gmx_domdec_t* dd;
-    ivec          coords;
-    int           slab;
+    ivec coords;
 
-    dd         = cr->dd;
-    coords[XX] = x;
-    coords[YY] = y;
-    coords[ZZ] = z;
-    slab       = ddindex2pmeindex(dd->comm->ddRankSetup, dd_index(dd->numCells, coords));
+    coords[XX]     = x;
+    coords[YY]     = y;
+    coords[ZZ]     = z;
+    const int slab = ddindex2pmeindex(dd.comm->ddRankSetup, dd_index(dd.numCells, coords));
 
     return slab;
 }
@@ -723,7 +712,7 @@ static int ddcoord2simnodeid(const t_commrec* cr, int x, int y, int z)
         {
             if (cr->dd->comm->ddRankSetup.usePmeOnlyRanks)
             {
-                nodeid = ddindex + gmx_ddcoord2pmeindex(cr, x, y, z);
+                nodeid = ddindex + gmx_ddcoord2pmeindex(*cr->dd, x, y, z);
             }
             else
             {
@@ -835,7 +824,7 @@ std::vector<int> get_pme_ddranks(const t_commrec* cr, const int pmenodeid)
                 else
                 {
                     /* The slab corresponds to the nodeid in the PME group */
-                    if (gmx_ddcoord2pmeindex(cr, x, y, z) == pmenodeid)
+                    if (gmx_ddcoord2pmeindex(*cr->dd, x, y, z) == pmenodeid)
                     {
                         ddranks.push_back(ddcoord2simnodeid(cr, x, y, z));
                     }
@@ -848,7 +837,7 @@ std::vector<int> get_pme_ddranks(const t_commrec* cr, const int pmenodeid)
 
 static gmx_bool receive_vir_ener(const gmx_domdec_t* dd, gmx::ArrayRef<const int> pmeRanks, const t_commrec* cr)
 {
-    gmx_bool bReceive = TRUE;
+    bool bReceive = true;
 
     const DDRankSetup& ddRankSetup = dd->comm->ddRankSetup;
     if (ddRankSetup.usePmeOnlyRanks)
@@ -863,7 +852,7 @@ static gmx_bool receive_vir_ener(const gmx_domdec_t* dd, gmx::ArrayRef<const int
             coords[cartSetup.cartpmedim]++;
             if (coords[cartSetup.cartpmedim] < dd->numCells[cartSetup.cartpmedim])
             {
-                int rank;
+                int rank = 0;
                 MPI_Cart_rank(cr->mpi_comm_mysim, coords, &rank);
                 if (dd_simnode2pmenode(ddRankSetup, cartSetup, pmeRanks, cr, rank) == pmenode)
                 {
@@ -894,14 +883,11 @@ static gmx_bool receive_vir_ener(const gmx_domdec_t* dd, gmx::ArrayRef<const int
 
 static void set_slb_pme_dim_f(gmx_domdec_t* dd, int dim, real** dim_f)
 {
-    gmx_domdec_comm_t* comm;
-    int                i;
-
-    comm = dd->comm;
+    gmx_domdec_comm_t* comm = dd->comm;
 
     snew(*dim_f, dd->numCells[dim] + 1);
     (*dim_f)[0] = 0;
-    for (i = 1; i < dd->numCells[dim]; i++)
+    for (int i = 1; i < dd->numCells[dim]; i++)
     {
         if (comm->slb_frac[dim])
         {
@@ -954,16 +940,8 @@ static void init_ddpme(gmx_domdec_t* dd, gmx_ddpme_t* ddpme, int dimind)
          */
         if (dimind == 0 || xyz[XX] == dd->ci[XX])
         {
-            const int pmeindex = ddindex2pmeindex(ddRankSetup, i);
-            int       slab;
-            if (dimind == 0)
-            {
-                slab = pmeindex / nso;
-            }
-            else
-            {
-                slab = pmeindex % ddpme->nslab;
-            }
+            const int pmeindex  = ddindex2pmeindex(ddRankSetup, i);
+            const int slab      = (dimind == 0) ? (pmeindex / nso) : (pmeindex % ddpme->nslab);
             ddpme->pp_min[slab] = std::min(ddpme->pp_min[slab], xyz[dimind]);
             ddpme->pp_max[slab] = std::max(ddpme->pp_max[slab], xyz[dimind]);
         }
@@ -972,9 +950,9 @@ static void init_ddpme(gmx_domdec_t* dd, gmx_ddpme_t* ddpme, int dimind)
     set_slb_pme_dim_f(dd, ddpme->dim, &ddpme->slb_dim_f);
 }
 
-int dd_pme_maxshift_x(const gmx_domdec_t* dd)
+int dd_pme_maxshift_x(const gmx_domdec_t& dd)
 {
-    const DDRankSetup& ddRankSetup = dd->comm->ddRankSetup;
+    const DDRankSetup& ddRankSetup = dd.comm->ddRankSetup;
 
     if (ddRankSetup.ddpme[0].dim == XX)
     {
@@ -986,9 +964,9 @@ int dd_pme_maxshift_x(const gmx_domdec_t* dd)
     }
 }
 
-int dd_pme_maxshift_y(const gmx_domdec_t* dd)
+int dd_pme_maxshift_y(const gmx_domdec_t& dd)
 {
-    const DDRankSetup& ddRankSetup = dd->comm->ddRankSetup;
+    const DDRankSetup& ddRankSetup = dd.comm->ddRankSetup;
 
     if (ddRankSetup.ddpme[0].dim == YY)
     {
@@ -1004,9 +982,9 @@ int dd_pme_maxshift_y(const gmx_domdec_t* dd)
     }
 }
 
-bool ddHaveSplitConstraints(const gmx_domdec_t& dd)
+bool ddMayHaveSplitConstraints(const gmx_domdec_t& dd)
 {
-    return dd.comm->systemInfo.haveSplitConstraints;
+    return dd.comm->systemInfo.mayHaveSplitConstraints;
 }
 
 bool ddUsesUpdateGroups(const gmx_domdec_t& dd)
@@ -1037,17 +1015,16 @@ void dd_cycles_add(const gmx_domdec_t* dd, float cycles, int ddCycl)
 #if GMX_MPI
 static void make_load_communicator(gmx_domdec_t* dd, int dim_ind, ivec loc)
 {
-    MPI_Comm c_row;
-    int      dim, i, rank;
+    MPI_Comm c_row = MPI_COMM_NULL;
     ivec     loc_c;
-    gmx_bool bPartOfGroup = FALSE;
+    bool     bPartOfGroup = false;
 
-    dim = dd->dim[dim_ind];
+    const int dim = dd->dim[dim_ind];
     copy_ivec(loc, loc_c);
-    for (i = 0; i < dd->numCells[dim]; i++)
+    for (int i = 0; i < dd->numCells[dim]; i++)
     {
-        loc_c[dim] = i;
-        rank       = dd_index(dd->numCells, loc_c);
+        loc_c[dim]     = i;
+        const int rank = dd_index(dd->numCells, loc_c);
         if (rank == dd->rank)
         {
             /* This process is part of the group */
@@ -1094,9 +1071,7 @@ static void make_load_communicator(gmx_domdec_t* dd, int dim_ind, ivec loc)
 void dd_setup_dlb_resource_sharing(const t_commrec* cr, int gpu_id)
 {
 #if GMX_MPI
-    int           physicalnode_id_hash;
-    gmx_domdec_t* dd;
-    MPI_Comm      mpi_comm_pp_physicalnode;
+    MPI_Comm mpi_comm_pp_physicalnode = MPI_COMM_NULL;
 
     if (!thisRankHasDuty(cr, DUTY_PP) || gpu_id < 0)
     {
@@ -1106,15 +1081,14 @@ void dd_setup_dlb_resource_sharing(const t_commrec* cr, int gpu_id)
         return;
     }
 
-    physicalnode_id_hash = gmx_physicalnode_id_hash();
+    const int physicalnode_id_hash = gmx_physicalnode_id_hash();
 
-    dd = cr->dd;
+    gmx_domdec_t* dd = cr->dd;
 
     if (debug)
     {
         fprintf(debug, "dd_setup_dd_dlb_gpu_sharing:\n");
-        fprintf(debug, "DD PP rank %d physical node hash %d gpu_id %d\n", dd->rank,
-                physicalnode_id_hash, gpu_id);
+        fprintf(debug, "DD PP rank %d physical node hash %d gpu_id %d\n", dd->rank, physicalnode_id_hash, gpu_id);
     }
     /* Split the PP communicator over the physical nodes */
     /* TODO: See if we should store this (before), as it's also used for
@@ -1147,7 +1121,6 @@ void dd_setup_dlb_resource_sharing(const t_commrec* cr, int gpu_id)
 static void make_load_communicators(gmx_domdec_t gmx_unused* dd)
 {
 #if GMX_MPI
-    int  dim0, dim1, i, j;
     ivec loc;
 
     if (debug)
@@ -1167,8 +1140,8 @@ static void make_load_communicators(gmx_domdec_t gmx_unused* dd)
     make_load_communicator(dd, 0, loc);
     if (dd->ndim > 1)
     {
-        dim0 = dd->dim[0];
-        for (i = 0; i < dd->numCells[dim0]; i++)
+        const int dim0 = dd->dim[0];
+        for (int i = 0; i < dd->numCells[dim0]; i++)
         {
             loc[dim0] = i;
             make_load_communicator(dd, 1, loc);
@@ -1176,12 +1149,12 @@ static void make_load_communicators(gmx_domdec_t gmx_unused* dd)
     }
     if (dd->ndim > 2)
     {
-        dim0 = dd->dim[0];
-        for (i = 0; i < dd->numCells[dim0]; i++)
+        const int dim0 = dd->dim[0];
+        for (int i = 0; i < dd->numCells[dim0]; i++)
         {
-            loc[dim0] = i;
-            dim1      = dd->dim[1];
-            for (j = 0; j < dd->numCells[dim1]; j++)
+            loc[dim0]      = i;
+            const int dim1 = dd->dim[1];
+            for (int j = 0; j < dd->numCells[dim1]; j++)
             {
                 loc[dim1] = j;
                 make_load_communicator(dd, 2, loc);
@@ -1199,14 +1172,12 @@ static void make_load_communicators(gmx_domdec_t gmx_unused* dd)
 /*! \brief Sets up the relation between neighboring domains and zones */
 static void setup_neighbor_relations(gmx_domdec_t* dd)
 {
-    int                 d, dim, m;
-    ivec                tmp, s;
-    gmx_domdec_zones_t* zones;
+    ivec tmp, s;
     GMX_ASSERT((dd->ndim >= 0) && (dd->ndim <= DIM), "Must have valid number of dimensions for DD");
 
-    for (d = 0; d < dd->ndim; d++)
+    for (int d = 0; d < dd->ndim; d++)
     {
-        dim = dd->dim[d];
+        const int dim = dd->dim[d];
         copy_ivec(dd->ci, tmp);
         tmp[dim]           = (tmp[dim] + 1) % dd->numCells[dim];
         dd->neighbor[d][0] = ddcoord2ddnodeid(dd, tmp);
@@ -1215,8 +1186,12 @@ static void setup_neighbor_relations(gmx_domdec_t* dd)
         dd->neighbor[d][1] = ddcoord2ddnodeid(dd, tmp);
         if (debug)
         {
-            fprintf(debug, "DD rank %d neighbor ranks in dir %d are + %d - %d\n", dd->rank, dim,
-                    dd->neighbor[d][0], dd->neighbor[d][1]);
+            fprintf(debug,
+                    "DD rank %d neighbor ranks in dir %d are + %d - %d\n",
+                    dd->rank,
+                    dim,
+                    dd->neighbor[d][0],
+                    dd->neighbor[d][1]);
         }
     }
 
@@ -1224,13 +1199,13 @@ static void setup_neighbor_relations(gmx_domdec_t* dd)
     int nizone = (1 << std::max(dd->ndim - 1, 0));
     assert(nizone >= 1 && nizone <= DD_MAXIZONE);
 
-    zones = &dd->comm->zones;
+    gmx_domdec_zones_t* zones = &dd->comm->zones;
 
     for (int i = 0; i < nzone; i++)
     {
-        m = 0;
+        int m = 0;
         clear_ivec(zones->shift[i]);
-        for (d = 0; d < dd->ndim; d++)
+        for (int d = 0; d < dd->ndim; d++)
         {
             zones->shift[i][dd->dim[d]] = dd_zo[i][m++];
         }
@@ -1239,7 +1214,7 @@ static void setup_neighbor_relations(gmx_domdec_t* dd)
     zones->n = nzone;
     for (int i = 0; i < nzone; i++)
     {
-        for (d = 0; d < DIM; d++)
+        for (int d = 0; d < DIM; d++)
         {
             s[d] = dd->ci[d] - zones->shift[i][d];
             if (s[d] < 0)
@@ -1265,7 +1240,7 @@ static void setup_neighbor_relations(gmx_domdec_t* dd)
          */
         iZone.jZoneRange = gmx::Range<int>(std::min(ddNonbondedZonePairRanges[iZoneIndex][1], nzone),
                                            std::min(ddNonbondedZonePairRanges[iZoneIndex][2], nzone));
-        for (dim = 0; dim < DIM; dim++)
+        for (int dim = 0; dim < DIM; dim++)
         {
             if (dd->numCells[dim] == 1)
             {
@@ -1321,16 +1296,17 @@ static void make_pp_communicator(const gmx::MDLogger& mdlog,
         /* Set up cartesian communication for the particle-particle part */
         GMX_LOG(mdlog.info)
                 .appendTextFormatted("Will use a Cartesian communicator: %d x %d x %d",
-                                     dd->numCells[XX], dd->numCells[YY], dd->numCells[ZZ]);
+                                     dd->numCells[XX],
+                                     dd->numCells[YY],
+                                     dd->numCells[ZZ]);
 
         ivec periods;
         for (int i = 0; i < DIM; i++)
         {
             periods[i] = TRUE;
         }
-        MPI_Comm comm_cart;
-        MPI_Cart_create(cr->mpi_comm_mygroup, DIM, dd->numCells, periods, static_cast<int>(reorder),
-                        &comm_cart);
+        MPI_Comm comm_cart = MPI_COMM_NULL;
+        MPI_Cart_create(cr->mpi_comm_mygroup, DIM, dd->numCells, periods, static_cast<int>(reorder), &comm_cart);
         /* We overwrite the old communicator with the new cartesian one */
         cr->mpi_comm_mygroup = comm_cart;
     }
@@ -1349,15 +1325,7 @@ static void make_pp_communicator(const gmx::MDLogger& mdlog,
         /* Get the rank of the DD master,
          * above we made sure that the master node is a PP node.
          */
-        int rank;
-        if (MASTER(cr))
-        {
-            rank = dd->rank;
-        }
-        else
-        {
-            rank = 0;
-        }
+        int rank = MASTER(cr) ? dd->rank : 0;
         MPI_Allreduce(&rank, &dd->masterrank, 1, MPI_INT, MPI_SUM, dd->mpi_comm_all);
     }
     else if (cartSetup.bCartesianPP)
@@ -1383,8 +1351,7 @@ static void make_pp_communicator(const gmx::MDLogger& mdlog,
             buf[dd_index(dd->numCells, dd->ci)] = cr->sim_nodeid;
         }
         /* Communicate the ddindex to simulation nodeid index */
-        MPI_Allreduce(buf.data(), cartSetup.ddindex2simnodeid.data(), dd->nnodes, MPI_INT, MPI_SUM,
-                      cr->mpi_comm_mysim);
+        MPI_Allreduce(buf.data(), cartSetup.ddindex2simnodeid.data(), dd->nnodes, MPI_INT, MPI_SUM, cr->mpi_comm_mysim);
 
         /* Determine the master coordinates and rank.
          * The DD master should be the same node as the master of this sim.
@@ -1414,12 +1381,19 @@ static void make_pp_communicator(const gmx::MDLogger& mdlog,
 #endif
 
     GMX_LOG(mdlog.info)
-            .appendTextFormatted("Domain decomposition rank %d, coordinates %d %d %d\n", dd->rank,
-                                 dd->ci[XX], dd->ci[YY], dd->ci[ZZ]);
+            .appendTextFormatted("Domain decomposition rank %d, coordinates %d %d %d\n",
+                                 dd->rank,
+                                 dd->ci[XX],
+                                 dd->ci[YY],
+                                 dd->ci[ZZ]);
     if (debug)
     {
-        fprintf(debug, "Domain decomposition rank %d, coordinates %d %d %d\n\n", dd->rank,
-                dd->ci[XX], dd->ci[YY], dd->ci[ZZ]);
+        fprintf(debug,
+                "Domain decomposition rank %d, coordinates %d %d %d\n\n",
+                dd->rank,
+                dd->ci[XX],
+                dd->ci[YY],
+                dd->ci[ZZ]);
     }
 }
 
@@ -1437,8 +1411,7 @@ static void receive_ddindex2simnodeid(gmx_domdec_t* dd, t_commrec* cr)
             buf[dd_index(dd->numCells, dd->ci)] = cr->sim_nodeid;
         }
         /* Communicate the ddindex to simulation nodeid index */
-        MPI_Allreduce(buf.data(), cartSetup.ddindex2simnodeid.data(), dd->nnodes, MPI_INT, MPI_SUM,
-                      cr->mpi_comm_mysim);
+        MPI_Allreduce(buf.data(), cartSetup.ddindex2simnodeid.data(), dd->nnodes, MPI_INT, MPI_SUM, cr->mpi_comm_mysim);
     }
 #else
     GMX_UNUSED_VALUE(dd);
@@ -1498,8 +1471,11 @@ static CartesianRankSetup split_communicator(const gmx::MDLogger& mdlog,
                     .appendTextFormatted(
                             "Number of PME-only ranks (%d) is not a multiple of nx*ny (%d*%d) or "
                             "nx*nz (%d*%d)",
-                            ddRankSetup.numRanksDoingPme, numDDCells[XX], numDDCells[YY],
-                            numDDCells[XX], numDDCells[ZZ]);
+                            ddRankSetup.numRanksDoingPme,
+                            numDDCells[XX],
+                            numDDCells[YY],
+                            numDDCells[XX],
+                            numDDCells[ZZ]);
             GMX_LOG(mdlog.info)
                     .appendText("Will not use a Cartesian communicator for PP <-> PME\n");
         }
@@ -1508,21 +1484,22 @@ static CartesianRankSetup split_communicator(const gmx::MDLogger& mdlog,
     if (cartSetup.bCartesianPP_PME)
     {
 #if GMX_MPI
-        int  rank;
+        int  rank = 0;
         ivec periods;
 
         GMX_LOG(mdlog.info)
                 .appendTextFormatted(
                         "Will use a Cartesian communicator for PP <-> PME: %d x %d x %d",
-                        cartSetup.ntot[XX], cartSetup.ntot[YY], cartSetup.ntot[ZZ]);
+                        cartSetup.ntot[XX],
+                        cartSetup.ntot[YY],
+                        cartSetup.ntot[ZZ]);
 
         for (int i = 0; i < DIM; i++)
         {
             periods[i] = TRUE;
         }
-        MPI_Comm comm_cart;
-        MPI_Cart_create(cr->mpi_comm_mysim, DIM, cartSetup.ntot, periods, static_cast<int>(reorder),
-                        &comm_cart);
+        MPI_Comm comm_cart = MPI_COMM_NULL;
+        MPI_Cart_create(cr->mpi_comm_mysim, DIM, cartSetup.ntot, periods, static_cast<int>(reorder), &comm_cart);
         MPI_Comm_rank(comm_cart, &rank);
         if (MASTER(cr) && rank != 0)
         {
@@ -1538,8 +1515,11 @@ static CartesianRankSetup split_communicator(const gmx::MDLogger& mdlog,
         MPI_Cart_coords(cr->mpi_comm_mysim, cr->sim_nodeid, DIM, ddCellIndex);
 
         GMX_LOG(mdlog.info)
-                .appendTextFormatted("Cartesian rank %d, coordinates %d %d %d\n", cr->sim_nodeid,
-                                     ddCellIndex[XX], ddCellIndex[YY], ddCellIndex[ZZ]);
+                .appendTextFormatted("Cartesian rank %d, coordinates %d %d %d\n",
+                                     cr->sim_nodeid,
+                                     ddCellIndex[XX],
+                                     ddCellIndex[YY],
+                                     ddCellIndex[ZZ]);
 
         if (ddCellIndex[cartSetup.cartpmedim] < numDDCells[cartSetup.cartpmedim])
         {
@@ -1552,8 +1532,10 @@ static CartesianRankSetup split_communicator(const gmx::MDLogger& mdlog,
         }
 
         /* Split the sim communicator into PP and PME only nodes */
-        MPI_Comm_split(cr->mpi_comm_mysim, getThisRankDuties(cr),
-                       dd_index(cartSetup.ntot, ddCellIndex), &cr->mpi_comm_mygroup);
+        MPI_Comm_split(cr->mpi_comm_mysim,
+                       getThisRankDuties(cr),
+                       dd_index(cartSetup.ntot, ddCellIndex),
+                       &cr->mpi_comm_mygroup);
 #else
         GMX_UNUSED_VALUE(ddCellIndex);
 #endif
@@ -1623,8 +1605,8 @@ static CartesianRankSetup makeGroupCommunicators(const gmx::MDLogger& mdlog,
     if (ddRankSetup.usePmeOnlyRanks)
     {
         /* Split the communicator into a PP and PME part */
-        cartSetup = split_communicator(mdlog, cr, ddRankOrder, ddSettings.useCartesianReorder,
-                                       ddRankSetup, ddCellIndex, pmeRanks);
+        cartSetup = split_communicator(
+                mdlog, cr, ddRankOrder, ddSettings.useCartesianReorder, ddRankSetup, ddCellIndex, pmeRanks);
     }
     else
     {
@@ -1675,7 +1657,9 @@ static void setupGroupCommunication(const gmx::MDLogger&     mdlog,
         dd->pme_receive_vir_ener = receive_vir_ener(dd, pmeRanks, cr);
         if (debug)
         {
-            fprintf(debug, "My pme_nodeid %d receive ener %s\n", dd->pme_nodeid,
+            fprintf(debug,
+                    "My pme_nodeid %d receive ener %s\n",
+                    dd->pme_nodeid,
                     gmx::boolToString(dd->pme_receive_vir_ener));
         }
     }
@@ -1693,25 +1677,23 @@ static void setupGroupCommunication(const gmx::MDLogger&     mdlog,
 
 static real* get_slb_frac(const gmx::MDLogger& mdlog, const char* dir, int nc, const char* size_string)
 {
-    real * slb_frac, tot;
-    int    i, n;
-    double dbl;
-
-    slb_frac = nullptr;
+    real* slb_frac = nullptr;
     if (nc > 1 && size_string != nullptr)
     {
         GMX_LOG(mdlog.info).appendTextFormatted("Using static load balancing for the %s direction", dir);
         snew(slb_frac, nc);
-        tot = 0;
-        for (i = 0; i < nc; i++)
+        real tot = 0;
+        for (int i = 0; i < nc; i++)
         {
-            dbl = 0;
+            double dbl = 0;
+            int    n   = 0;
             sscanf(size_string, "%20lf%n", &dbl, &n);
             if (dbl == 0)
             {
                 gmx_fatal(FARGS,
                           "Incorrect or not enough DD cell size entries for direction %s: '%s'",
-                          dir, size_string);
+                          dir,
+                          size_string);
             }
             slb_frac[i] = dbl;
             size_string += n;
@@ -1719,7 +1701,7 @@ static real* get_slb_frac(const gmx::MDLogger& mdlog, const char* dir, int nc, c
         }
         /* Normalize */
         std::string relativeCellSizes = "Relative cell sizes:";
-        for (i = 0; i < nc; i++)
+        for (int i = 0; i < nc; i++)
         {
             slb_frac[i] /= tot;
             relativeCellSizes += gmx::formatString(" %5.3f", slb_frac[i]);
@@ -1730,18 +1712,16 @@ static real* get_slb_frac(const gmx::MDLogger& mdlog, const char* dir, int nc, c
     return slb_frac;
 }
 
-static int multi_body_bondeds_count(const gmx_mtop_t* mtop)
+static int multi_body_bondeds_count(const gmx_mtop_t& mtop)
 {
-    int                  n     = 0;
-    gmx_mtop_ilistloop_t iloop = gmx_mtop_ilistloop_init(mtop);
-    int                  nmol;
-    while (const InteractionLists* ilists = gmx_mtop_ilistloop_next(iloop, &nmol))
+    int n = 0;
+    for (const auto ilists : IListRange(mtop))
     {
-        for (auto& ilist : extractILists(*ilists, IF_BOND))
+        for (auto& ilist : extractILists(ilists.list(), IF_BOND))
         {
             if (NRAL(ilist.functionType) > 2)
             {
-                n += nmol * (ilist.iatoms.size() / ilistStride(ilist));
+                n += ilists.nmol() * (ilist.iatoms.size() / ilistStride(ilist));
             }
         }
     }
@@ -1751,11 +1731,8 @@ static int multi_body_bondeds_count(const gmx_mtop_t* mtop)
 
 static int dd_getenv(const gmx::MDLogger& mdlog, const char* env_var, int def)
 {
-    char* val;
-    int   nst;
-
-    nst = def;
-    val = getenv(env_var);
+    int   nst = def;
+    char* val = getenv(env_var);
     if (val)
     {
         if (sscanf(val, "%20d", &nst) <= 0)
@@ -1768,21 +1745,22 @@ static int dd_getenv(const gmx::MDLogger& mdlog, const char* env_var, int def)
     return nst;
 }
 
-static void check_dd_restrictions(const gmx_domdec_t* dd, const t_inputrec* ir, const gmx::MDLogger& mdlog)
+static void check_dd_restrictions(const gmx_domdec_t* dd, const t_inputrec& inputrec, const gmx::MDLogger& mdlog)
 {
-    if (ir->pbcType == PbcType::Screw
+    if (inputrec.pbcType == PbcType::Screw
         && (dd->numCells[XX] == 1 || dd->numCells[YY] > 1 || dd->numCells[ZZ] > 1))
     {
-        gmx_fatal(FARGS, "With pbc=%s can only do domain decomposition in the x-direction",
-                  c_pbcTypeNames[ir->pbcType].c_str());
+        gmx_fatal(FARGS,
+                  "With pbc=%s can only do domain decomposition in the x-direction",
+                  c_pbcTypeNames[inputrec.pbcType].c_str());
     }
 
-    if (ir->nstlist == 0)
+    if (inputrec.nstlist == 0)
     {
         gmx_fatal(FARGS, "Domain decomposition does not work with nstlist=0");
     }
 
-    if (ir->comm_mode == ecmANGULAR && ir->pbcType != PbcType::No)
+    if (inputrec.comm_mode == ComRemovalAlgorithm::Angular && inputrec.pbcType != PbcType::No)
     {
         GMX_LOG(mdlog.warning)
                 .appendText(
@@ -1837,14 +1815,14 @@ static DlbState forceDlbOffOrBail(DlbState             cmdlineDlbState,
  * \param [in] dlbOption   Enum value for the DLB option.
  * \param [in] bRecordLoad True if the load balancer is recording load information.
  * \param [in] mdrunOptions  Options for mdrun.
- * \param [in] ir          Pointer mdrun to input parameters.
+ * \param [in] inputrec    Pointer mdrun to input parameters.
  * \returns                DLB initial/startup state.
  */
 static DlbState determineInitialDlbState(const gmx::MDLogger&     mdlog,
                                          DlbOption                dlbOption,
                                          gmx_bool                 bRecordLoad,
                                          const gmx::MdrunOptions& mdrunOptions,
-                                         const t_inputrec*        ir)
+                                         const t_inputrec&        inputrec)
 {
     DlbState dlbState = DlbState::offCanTurnOn;
 
@@ -1864,10 +1842,11 @@ static DlbState determineInitialDlbState(const gmx::MDLogger&     mdlog,
     }
 
     /* Unsupported integrators */
-    if (!EI_DYNAMICS(ir->eI))
+    if (!EI_DYNAMICS(inputrec.eI))
     {
-        auto reasonStr = gmx::formatString(
-                "it is only supported with dynamics, not with integrator '%s'.", EI(ir->eI));
+        auto reasonStr =
+                gmx::formatString("it is only supported with dynamics, not with integrator '%s'.",
+                                  enumValueToString(inputrec.eI));
         return forceDlbOffOrBail(dlbState, reasonStr, mdlog);
     }
 
@@ -1900,7 +1879,8 @@ static DlbState determineInitialDlbState(const gmx::MDLogger&     mdlog,
                                   "ensured.",
                         mdlog);
             default:
-                gmx_fatal(FARGS, "Death horror: undefined case (%d) for load balancing choice",
+                gmx_fatal(FARGS,
+                          "Death horror: undefined case (%d) for load balancing choice",
                           static_cast<int>(dlbState));
         }
     }
@@ -1939,17 +1919,9 @@ static gmx_domdec_comm_t* init_dd_comm()
 /* Returns whether mtop contains constraints and/or vsites */
 static bool systemHasConstraintsOrVsites(const gmx_mtop_t& mtop)
 {
-    auto ilistLoop = gmx_mtop_ilistloop_init(mtop);
-    int  nmol;
-    while (const InteractionLists* ilists = gmx_mtop_ilistloop_next(ilistLoop, &nmol))
-    {
-        if (!extractILists(*ilists, IF_CONSTRAINT | IF_VSITE).empty())
-        {
-            return true;
-        }
-    }
-
-    return false;
+    return std::any_of(IListRange(mtop).begin(), IListRange(mtop).end(), [](const auto ilist) {
+        return !extractILists(ilist.list(), IF_CONSTRAINT | IF_VSITE).empty();
+    });
 }
 
 static void setupUpdateGroups(const gmx::MDLogger& mdlog,
@@ -1967,8 +1939,8 @@ static void setupUpdateGroups(const gmx::MDLogger& mdlog,
         return;
     }
 
-    systemInfo->updateGroupingPerMoleculetype = gmx::makeUpdateGroups(mtop);
-    systemInfo->useUpdateGroups               = (!systemInfo->updateGroupingPerMoleculetype.empty()
+    systemInfo->updateGroupingsPerMoleculeType = gmx::makeUpdateGroupingsPerMoleculeType(mtop);
+    systemInfo->useUpdateGroups = (!systemInfo->updateGroupingsPerMoleculeType.empty()
                                    && getenv("GMX_NO_UPDATEGROUPS") == nullptr);
 
     if (systemInfo->useUpdateGroups)
@@ -1977,11 +1949,11 @@ static void setupUpdateGroups(const gmx::MDLogger& mdlog,
         for (const auto& molblock : mtop.molblock)
         {
             numUpdateGroups += molblock.nmol
-                               * systemInfo->updateGroupingPerMoleculetype[molblock.type].numBlocks();
+                               * systemInfo->updateGroupingsPerMoleculeType[molblock.type].numBlocks();
         }
 
         systemInfo->maxUpdateGroupRadius = computeMaxUpdateGroupRadius(
-                mtop, systemInfo->updateGroupingPerMoleculetype, maxReferenceTemperature(inputrec));
+                mtop, systemInfo->updateGroupingsPerMoleculeType, maxReferenceTemperature(inputrec));
 
         /* To use update groups, the large domain-to-domain cutoff distance
          * should be compatible with the box size.
@@ -1994,7 +1966,8 @@ static void setupUpdateGroups(const gmx::MDLogger& mdlog,
                     .appendTextFormatted(
                             "Using update groups, nr %d, average size %.1f atoms, max. radius %.3f "
                             "nm\n",
-                            numUpdateGroups, mtop.natoms / static_cast<double>(numUpdateGroups),
+                            numUpdateGroups,
+                            mtop.natoms / static_cast<double>(numUpdateGroups),
                             systemInfo->maxUpdateGroupRadius);
         }
         else
@@ -2003,7 +1976,7 @@ static void setupUpdateGroups(const gmx::MDLogger& mdlog,
                     .appendTextFormatted(
                             "The combination of rlist and box size prohibits the use of update "
                             "groups\n");
-            systemInfo->updateGroupingPerMoleculetype.clear();
+            systemInfo->updateGroupingsPerMoleculeType.clear();
         }
     }
 }
@@ -2019,15 +1992,15 @@ UnitCellInfo::UnitCellInfo(const t_inputrec& ir) :
 /* Returns whether molecules are always whole, i.e. not broken by PBC */
 static bool moleculesAreAlwaysWhole(const gmx_mtop_t&                           mtop,
                                     const bool                                  useUpdateGroups,
-                                    gmx::ArrayRef<const gmx::RangePartitioning> updateGroupingPerMoleculetype)
+                                    gmx::ArrayRef<const gmx::RangePartitioning> updateGroupingsPerMoleculeType)
 {
     if (useUpdateGroups)
     {
-        GMX_RELEASE_ASSERT(updateGroupingPerMoleculetype.size() == mtop.moltype.size(),
+        GMX_RELEASE_ASSERT(updateGroupingsPerMoleculeType.size() == mtop.moltype.size(),
                            "Need one grouping per moltype");
         for (size_t mol = 0; mol < mtop.moltype.size(); mol++)
         {
-            if (updateGroupingPerMoleculetype[mol].numBlocks() > 1)
+            if (updateGroupingsPerMoleculeType[mol].numBlocks() > 1)
             {
                 return false;
             }
@@ -2063,29 +2036,29 @@ static DDSystemInfo getSystemInfo(const gmx::MDLogger&           mdlog,
 
     /* We need to decide on update groups early, as this affects communication distances */
     systemInfo.useUpdateGroups = false;
-    if (ir.cutoff_scheme == ecutsVERLET)
+    if (ir.cutoff_scheme == CutoffScheme::Verlet)
     {
         real cutoffMargin = std::sqrt(max_cutoff2(ir.pbcType, box)) - ir.rlist;
         setupUpdateGroups(mdlog, mtop, ir, cutoffMargin, &systemInfo);
     }
 
     systemInfo.moleculesAreAlwaysWhole = moleculesAreAlwaysWhole(
-            mtop, systemInfo.useUpdateGroups, systemInfo.updateGroupingPerMoleculetype);
+            mtop, systemInfo.useUpdateGroups, systemInfo.updateGroupingsPerMoleculeType);
     systemInfo.haveInterDomainBondeds =
             (!systemInfo.moleculesAreAlwaysWhole || mtop.bIntermolecularInteractions);
     systemInfo.haveInterDomainMultiBodyBondeds =
-            (systemInfo.haveInterDomainBondeds && multi_body_bondeds_count(&mtop) > 0);
+            (systemInfo.haveInterDomainBondeds && multi_body_bondeds_count(mtop) > 0);
 
     if (systemInfo.useUpdateGroups)
     {
-        systemInfo.haveSplitConstraints = false;
-        systemInfo.haveSplitSettles     = false;
+        systemInfo.mayHaveSplitConstraints = false;
+        systemInfo.mayHaveSplitSettles     = false;
     }
     else
     {
-        systemInfo.haveSplitConstraints = (gmx_mtop_ftype_count(mtop, F_CONSTR) > 0
-                                           || gmx_mtop_ftype_count(mtop, F_CONSTRNC) > 0);
-        systemInfo.haveSplitSettles     = (gmx_mtop_ftype_count(mtop, F_SETTLE) > 0);
+        systemInfo.mayHaveSplitConstraints = (gmx_mtop_ftype_count(mtop, F_CONSTR) > 0
+                                              || gmx_mtop_ftype_count(mtop, F_CONSTRNC) > 0);
+        systemInfo.mayHaveSplitSettles     = (gmx_mtop_ftype_count(mtop, F_SETTLE) > 0);
     }
 
     if (ir.rlist == 0)
@@ -2115,7 +2088,7 @@ static DDSystemInfo getSystemInfo(const gmx::MDLogger&           mdlog,
      */
     constexpr real c_chanceThatAtomMovesBeyondDomain = 1e-12;
     const real     limitForAtomDisplacement          = minCellSizeForAtomDisplacement(
-            mtop, ir, systemInfo.updateGroupingPerMoleculetype, c_chanceThatAtomMovesBeyondDomain);
+            mtop, ir, systemInfo.updateGroupingsPerMoleculeType, c_chanceThatAtomMovesBeyondDomain);
     GMX_LOG(mdlog.info).appendTextFormatted("Minimum cell size due to atom displacement: %.3f nm", limitForAtomDisplacement);
 
     systemInfo.cellsizeLimit = std::max(systemInfo.cellsizeLimit, limitForAtomDisplacement);
@@ -2159,12 +2132,12 @@ static DDSystemInfo getSystemInfo(const gmx::MDLogger&           mdlog,
         }
         else
         {
-            real r_2b, r_mb;
+            real r_2b = 0;
+            real r_mb = 0;
 
             if (ddRole == DDRole::Master)
             {
-                dd_bonded_cg_distance(mdlog, &mtop, &ir, xGlobal, box,
-                                      options.checkBondedInteractions, &r_2b, &r_mb);
+                dd_bonded_cg_distance(mdlog, mtop, ir, xGlobal, box, options.ddBondedChecking, &r_2b, &r_mb);
             }
             gmx_bcast(sizeof(r_2b), &r_2b, communicator);
             gmx_bcast(sizeof(r_mb), &r_mb, communicator);
@@ -2207,7 +2180,7 @@ static DDSystemInfo getSystemInfo(const gmx::MDLogger&           mdlog,
     }
 
     systemInfo.constraintCommunicationRange = 0;
-    if (systemInfo.haveSplitConstraints && options.constraintCommunicationRange <= 0)
+    if (systemInfo.mayHaveSplitConstraints && options.constraintCommunicationRange <= 0)
     {
         /* There is a cell size limit due to the constraints (P-LINCS) */
         systemInfo.constraintCommunicationRange = gmx::constr_r_max(mdlog, &mtop, &ir);
@@ -2252,19 +2225,24 @@ static void checkDDGridSetup(const DDGridSetup&   ddGridSetup,
 {
     if (options.numCells[XX] <= 0 && (ddGridSetup.numDomains[XX] == 0))
     {
-        char     buf[STRLEN];
-        gmx_bool bC = (systemInfo.haveSplitConstraints
-                       && systemInfo.constraintCommunicationRange > systemInfo.minCutoffForMultiBody);
-        sprintf(buf, "Change the number of ranks or mdrun option %s%s%s", !bC ? "-rdd" : "-rcon",
-                ddSettings.initialDlbState != DlbState::offUser ? " or -dds" : "",
-                bC ? " or your LINCS settings" : "");
-
-        gmx_fatal_collective(FARGS, communicator, ddRole == DDRole::Master,
+        const bool  bC = (systemInfo.mayHaveSplitConstraints
+                         && systemInfo.constraintCommunicationRange > systemInfo.minCutoffForMultiBody);
+        std::string message =
+                gmx::formatString("Change the number of ranks or mdrun option %s%s%s",
+                                  !bC ? "-rdd" : "-rcon",
+                                  ddSettings.initialDlbState != DlbState::offUser ? " or -dds" : "",
+                                  bC ? " or your LINCS settings" : "");
+
+        gmx_fatal_collective(FARGS,
+                             communicator,
+                             ddRole == DDRole::Master,
                              "There is no domain decomposition for %d ranks that is compatible "
                              "with the given box and a minimum cell size of %g nm\n"
                              "%s\n"
                              "Look in the log file for details on the domain decomposition",
-                             numNodes - ddGridSetup.numPmeOnlyRanks, cellsizeLimit, buf);
+                             numNodes - ddGridSetup.numPmeOnlyRanks,
+                             cellsizeLimit,
+                             message.c_str());
     }
 
     const real acs = average_cellsize_min(ddbox, ddGridSetup.numDomains);
@@ -2279,10 +2257,13 @@ static void checkDDGridSetup(const DDGridSetup&   ddGridSetup,
         else
         {
             gmx_fatal_collective(
-                    FARGS, communicator, ddRole == DDRole::Master,
+                    FARGS,
+                    communicator,
+                    ddRole == DDRole::Master,
                     "The initial cell size (%f) is smaller than the cell size limit (%f), change "
                     "options -dd, -rdd or -rcon, see the log file for details",
-                    acs, cellsizeLimit);
+                    acs,
+                    cellsizeLimit);
         }
     }
 
@@ -2290,17 +2271,24 @@ static void checkDDGridSetup(const DDGridSetup&   ddGridSetup,
             ddGridSetup.numDomains[XX] * ddGridSetup.numDomains[YY] * ddGridSetup.numDomains[ZZ];
     if (numNodes - numPPRanks != ddGridSetup.numPmeOnlyRanks)
     {
-        gmx_fatal_collective(FARGS, communicator, ddRole == DDRole::Master,
+        gmx_fatal_collective(FARGS,
+                             communicator,
+                             ddRole == DDRole::Master,
                              "The size of the domain decomposition grid (%d) does not match the "
                              "number of PP ranks (%d). The total number of ranks is %d",
-                             numPPRanks, numNodes - ddGridSetup.numPmeOnlyRanks, numNodes);
+                             numPPRanks,
+                             numNodes - ddGridSetup.numPmeOnlyRanks,
+                             numNodes);
     }
     if (ddGridSetup.numPmeOnlyRanks > numPPRanks)
     {
-        gmx_fatal_collective(FARGS, communicator, ddRole == DDRole::Master,
+        gmx_fatal_collective(FARGS,
+                             communicator,
+                             ddRole == DDRole::Master,
                              "The number of separate PME ranks (%d) is larger than the number of "
                              "PP ranks (%d), this is not supported.",
-                             ddGridSetup.numPmeOnlyRanks, numPPRanks);
+                             ddGridSetup.numPmeOnlyRanks,
+                             numPPRanks);
     }
 }
 
@@ -2312,8 +2300,10 @@ static DDRankSetup getDDRankSetup(const gmx::MDLogger& mdlog,
 {
     GMX_LOG(mdlog.info)
             .appendTextFormatted("Domain decomposition grid %d x %d x %d, separate PME ranks %d",
-                                 ddGridSetup.numDomains[XX], ddGridSetup.numDomains[YY],
-                                 ddGridSetup.numDomains[ZZ], ddGridSetup.numPmeOnlyRanks);
+                                 ddGridSetup.numDomains[XX],
+                                 ddGridSetup.numDomains[YY],
+                                 ddGridSetup.numDomains[ZZ],
+                                 ddGridSetup.numPmeOnlyRanks);
 
     DDRankSetup ddRankSetup;
 
@@ -2370,7 +2360,9 @@ static DDRankSetup getDDRankSetup(const gmx::MDLogger& mdlog,
         }
         GMX_LOG(mdlog.info)
                 .appendTextFormatted("PME domain decomposition: %d x %d x %d",
-                                     ddRankSetup.npmenodes_x, ddRankSetup.npmenodes_y, 1);
+                                     ddRankSetup.npmenodes_x,
+                                     ddRankSetup.npmenodes_y,
+                                     1);
     }
     else
     {
@@ -2391,8 +2383,8 @@ static void set_dd_limits(const gmx::MDLogger& mdlog,
                           const DDSystemInfo&  systemInfo,
                           const DDGridSetup&   ddGridSetup,
                           const int            numPPRanks,
-                          const gmx_mtop_t*    mtop,
-                          const t_inputrec*    ir,
+                          const gmx_mtop_t&    mtop,
+                          const t_inputrec&    ir,
                           const gmx_ddbox_t&   ddbox)
 {
     gmx_domdec_comm_t* comm = dd->comm;
@@ -2421,10 +2413,9 @@ static void set_dd_limits(const gmx::MDLogger& mdlog,
          *       but that is not yet available here. But this anyhow only
          *       affect performance up to the second dd_partition_system call.
          */
-        const int homeAtomCountEstimate = mtop->natoms / numPPRanks;
+        const int homeAtomCountEstimate = mtop.natoms / numPPRanks;
         comm->updateGroupsCog           = std::make_unique<gmx::UpdateGroupsCog>(
-                *mtop, systemInfo.updateGroupingPerMoleculetype, maxReferenceTemperature(*ir),
-                homeAtomCountEstimate);
+                mtop, systemInfo.updateGroupingsPerMoleculeType, maxReferenceTemperature(ir), homeAtomCountEstimate);
     }
 
     /* Set the DD setup given by ddGridSetup */
@@ -2490,7 +2481,8 @@ static void set_dd_limits(const gmx::MDLogger& mdlog,
         fprintf(debug,
                 "Bonded atom communication beyond the cut-off: %s\n"
                 "cellsize limit %f\n",
-                gmx::boolToString(systemInfo.filterBondedCommunication), comm->cellsize_limit);
+                gmx::boolToString(systemInfo.filterBondedCommunication),
+                comm->cellsize_limit);
     }
 
     if (ddRole == DDRole::Master)
@@ -2499,51 +2491,20 @@ static void set_dd_limits(const gmx::MDLogger& mdlog,
     }
 }
 
-void dd_init_bondeds(FILE*                           fplog,
-                     gmx_domdec_t*                   dd,
-                     const gmx_mtop_t&               mtop,
-                     const gmx::VirtualSitesHandler* vsite,
-                     const t_inputrec*               ir,
-                     gmx_bool                        bBCheck,
-                     gmx::ArrayRef<cginfo_mb_t>      cginfo_mb)
-{
-    gmx_domdec_comm_t* comm;
-
-    dd_make_reverse_top(fplog, dd, &mtop, vsite, ir, bBCheck);
-
-    comm = dd->comm;
-
-    if (comm->systemInfo.filterBondedCommunication)
-    {
-        /* Communicate atoms beyond the cut-off for bonded interactions */
-        comm->bondedLinks = makeBondedLinks(mtop, cginfo_mb);
-    }
-    else
-    {
-        /* Only communicate atoms based on cut-off */
-        comm->bondedLinks = nullptr;
-    }
-}
-
 static void writeSettings(gmx::TextWriter*   log,
                           gmx_domdec_t*      dd,
-                          const gmx_mtop_t*  mtop,
-                          const t_inputrec*  ir,
+                          const gmx_mtop_t&  mtop,
+                          const t_inputrec&  ir,
                           gmx_bool           bDynLoadBal,
                           real               dlb_scale,
                           const gmx_ddbox_t* ddbox)
 {
-    gmx_domdec_comm_t* comm;
-    int                d;
-    ivec               np;
-    real               limit, shrink;
-
-    comm = dd->comm;
+    gmx_domdec_comm_t* comm = dd->comm;
 
     if (bDynLoadBal)
     {
         log->writeString("The maximum number of communication pulses is:");
-        for (d = 0; d < dd->ndim; d++)
+        for (int d = 0; d < dd->ndim; d++)
         {
             log->writeStringFormatted(" %c %d", dim2char(dd->dim[d]), comm->cd[d].np_dlb);
         }
@@ -2552,19 +2513,15 @@ static void writeSettings(gmx::TextWriter*   log,
                                 comm->cellsize_limit);
         log->writeLineFormatted("The requested allowed shrink of DD cells (option -dds) is: %.2f", dlb_scale);
         log->writeString("The allowed shrink of domain decomposition cells is:");
-        for (d = 0; d < DIM; d++)
+        for (int d = 0; d < DIM; d++)
         {
             if (dd->numCells[d] > 1)
             {
-                if (d >= ddbox->npbcdim && dd->numCells[d] == 2)
-                {
-                    shrink = 0;
-                }
-                else
-                {
-                    shrink = comm->cellsize_min_dlb[d]
-                             / (ddbox->box_size[d] * ddbox->skew_fac[d] / dd->numCells[d]);
-                }
+                const real shrink =
+                        (d >= ddbox->npbcdim && dd->numCells[d] == 2)
+                                ? 0
+                                : comm->cellsize_min_dlb[d]
+                                          / (ddbox->box_size[d] * ddbox->skew_fac[d] / dd->numCells[d]);
                 log->writeStringFormatted(" %c %.2f", dim2char(d), shrink);
             }
         }
@@ -2572,15 +2529,16 @@ static void writeSettings(gmx::TextWriter*   log,
     }
     else
     {
+        ivec np;
         set_dd_cell_sizes_slb(dd, ddbox, setcellsizeslbPULSE_ONLY, np);
         log->writeString("The initial number of communication pulses is:");
-        for (d = 0; d < dd->ndim; d++)
+        for (int d = 0; d < dd->ndim; d++)
         {
             log->writeStringFormatted(" %c %d", dim2char(dd->dim[d]), np[dd->dim[d]]);
         }
         log->ensureLineBreak();
         log->writeString("The initial domain decomposition cell size is:");
-        for (d = 0; d < DIM; d++)
+        for (int d = 0; d < DIM; d++)
         {
             if (dd->numCells[d] > 1)
             {
@@ -2592,10 +2550,10 @@ static void writeSettings(gmx::TextWriter*   log,
     }
 
     const bool haveInterDomainVsites =
-            (countInterUpdategroupVsites(*mtop, comm->systemInfo.updateGroupingPerMoleculetype) != 0);
+            (countInterUpdategroupVsites(mtop, comm->systemInfo.updateGroupingsPerMoleculeType) != 0);
 
     if (comm->systemInfo.haveInterDomainBondeds || haveInterDomainVsites
-        || comm->systemInfo.haveSplitConstraints || comm->systemInfo.haveSplitSettles)
+        || comm->systemInfo.mayHaveSplitConstraints || comm->systemInfo.mayHaveSplitSettles)
     {
         std::string decompUnits;
         if (comm->systemInfo.useUpdateGroups)
@@ -2609,9 +2567,10 @@ static void writeSettings(gmx::TextWriter*   log,
 
         log->writeLineFormatted("The maximum allowed distance for %s involved in interactions is:",
                                 decompUnits.c_str());
-        log->writeLineFormatted("%40s  %-7s %6.3f nm", "non-bonded interactions", "",
-                                comm->systemInfo.cutoff);
+        log->writeLineFormatted(
+                "%40s  %-7s %6.3f nm", "non-bonded interactions", "", comm->systemInfo.cutoff);
 
+        real limit = 0;
         if (bDynLoadBal)
         {
             limit = dd->comm->cellsize_limit;
@@ -2625,7 +2584,7 @@ static void writeSettings(gmx::TextWriter*   log,
                         "deformation)");
             }
             limit = dd->comm->cellsize_min[XX];
-            for (d = 1; d < DIM; d++)
+            for (int d = 1; d < DIM; d++)
             {
                 limit = std::min(limit, dd->comm->cellsize_min[d]);
             }
@@ -2633,9 +2592,12 @@ static void writeSettings(gmx::TextWriter*   log,
 
         if (comm->systemInfo.haveInterDomainBondeds)
         {
-            log->writeLineFormatted("%40s  %-7s %6.3f nm", "two-body bonded interactions", "(-rdd)",
+            log->writeLineFormatted("%40s  %-7s %6.3f nm",
+                                    "two-body bonded interactions",
+                                    "(-rdd)",
                                     std::max(comm->systemInfo.cutoff, comm->cutoff_mbody));
-            log->writeLineFormatted("%40s  %-7s %6.3f nm", "multi-body bonded interactions",
+            log->writeLineFormatted("%40s  %-7s %6.3f nm",
+                                    "multi-body bonded interactions",
                                     "(-rdd)",
                                     (comm->systemInfo.filterBondedCommunication || isDlbOn(dd->comm))
                                             ? comm->cutoff_mbody
@@ -2645,10 +2607,10 @@ static void writeSettings(gmx::TextWriter*   log,
         {
             log->writeLineFormatted("%40s  %-7s %6.3f nm", "virtual site constructions", "(-rcon)", limit);
         }
-        if (comm->systemInfo.haveSplitConstraints || comm->systemInfo.haveSplitSettles)
+        if (comm->systemInfo.mayHaveSplitConstraints || comm->systemInfo.mayHaveSplitSettles)
         {
             std::string separation =
-                    gmx::formatString("atoms separated by up to %d constraints", 1 + ir->nProjOrder);
+                    gmx::formatString("atoms separated by up to %d constraints", 1 + ir.nProjOrder);
             log->writeLineFormatted("%40s  %-7s %6.3f nm\n", separation.c_str(), "(-rcon)", limit);
         }
         log->ensureLineBreak();
@@ -2657,8 +2619,8 @@ static void writeSettings(gmx::TextWriter*   log,
 
 static void logSettings(const gmx::MDLogger& mdlog,
                         gmx_domdec_t*        dd,
-                        const gmx_mtop_t*    mtop,
-                        const t_inputrec*    ir,
+                        const gmx_mtop_t&    mtop,
+                        const t_inputrec&    ir,
                         real                 dlb_scale,
                         const gmx_ddbox_t*   ddbox)
 {
@@ -2680,16 +2642,16 @@ static void logSettings(const gmx::MDLogger& mdlog,
 static void set_cell_limits_dlb(const gmx::MDLogger& mdlog,
                                 gmx_domdec_t*        dd,
                                 real                 dlb_scale,
-                                const t_inputrec*    ir,
+                                const t_inputrec&    inputrec,
                                 const gmx_ddbox_t*   ddbox)
 {
-    gmx_domdec_comm_t* comm;
-    int                d, dim, npulse, npulse_d_max, npulse_d;
-    gmx_bool           bNoCutOff;
+    int npulse       = 0;
+    int npulse_d_max = 0;
+    int npulse_d     = 0;
 
-    comm = dd->comm;
+    gmx_domdec_comm_t* comm = dd->comm;
 
-    bNoCutOff = (ir->rvdw == 0 || ir->rcoulomb == 0);
+    bool bNoCutOff = (inputrec.rvdw == 0 || inputrec.rcoulomb == 0);
 
     /* Determine the maximum number of comm. pulses in one dimension */
 
@@ -2721,9 +2683,9 @@ static void set_cell_limits_dlb(const gmx::MDLogger& mdlog,
     {
         /* See if we can do with less pulses, based on dlb_scale */
         npulse_d_max = 0;
-        for (d = 0; d < dd->ndim; d++)
+        for (int d = 0; d < dd->ndim; d++)
         {
-            dim      = dd->dim[d];
+            int dim  = dd->dim[d];
             npulse_d = static_cast<int>(
                     1
                     + dd->numCells[dim] * comm->systemInfo.cutoff
@@ -2734,15 +2696,15 @@ static void set_cell_limits_dlb(const gmx::MDLogger& mdlog,
     }
 
     /* This env var can override npulse */
-    d = dd_getenv(mdlog, "GMX_DD_NPULSE", 0);
-    if (d > 0)
+    const int ddPulseEnv = dd_getenv(mdlog, "GMX_DD_NPULSE", 0);
+    if (ddPulseEnv > 0)
     {
-        npulse = d;
+        npulse = ddPulseEnv;
     }
 
     comm->maxpulse       = 1;
-    comm->bVacDLBNoLimit = (ir->pbcType == PbcType::No);
-    for (d = 0; d < dd->ndim; d++)
+    comm->bVacDLBNoLimit = (inputrec.pbcType == PbcType::No);
+    for (int d = 0; d < dd->ndim; d++)
     {
         comm->cd[d].np_dlb = std::min(npulse, dd->numCells[dd->dim[d]] - 1);
         comm->maxpulse     = std::max(comm->maxpulse, comm->cd[d].np_dlb);
@@ -2759,7 +2721,7 @@ static void set_cell_limits_dlb(const gmx::MDLogger& mdlog,
     }
     comm->cellsize_limit = std::max(comm->cellsize_limit, comm->cutoff_mbody);
     /* Set the minimum cell size for each DD dimension */
-    for (d = 0; d < dd->ndim; d++)
+    for (int d = 0; d < dd->ndim; d++)
     {
         if (comm->bVacDLBNoLimit || comm->cd[d].np_dlb * comm->cellsize_limit >= comm->systemInfo.cutoff)
         {
@@ -2785,29 +2747,29 @@ bool dd_moleculesAreAlwaysWhole(const gmx_domdec_t& dd)
     return dd.comm->systemInfo.moleculesAreAlwaysWhole;
 }
 
-gmx_bool dd_bonded_molpbc(const gmx_domdec_t* dd, PbcType pbcType)
+bool dd_bonded_molpbc(const gmx_domdec_t& dd, PbcType pbcType)
 {
     /* If each molecule is a single charge group
      * or we use domain decomposition for each periodic dimension,
      * we do not need to take pbc into account for the bonded interactions.
      */
-    return (pbcType != PbcType::No && dd->comm->systemInfo.haveInterDomainBondeds
-            && !(dd->numCells[XX] > 1 && dd->numCells[YY] > 1
-                 && (dd->numCells[ZZ] > 1 || pbcType == PbcType::XY)));
+    return (pbcType != PbcType::No && dd.comm->systemInfo.haveInterDomainBondeds
+            && !(dd.numCells[XX] > 1 && dd.numCells[YY] > 1
+                 && (dd.numCells[ZZ] > 1 || pbcType == PbcType::XY)));
 }
 
 /*! \brief Sets grid size limits and PP-PME setup, prints settings to log */
 static void set_ddgrid_parameters(const gmx::MDLogger& mdlog,
                                   gmx_domdec_t*        dd,
                                   real                 dlb_scale,
-                                  const gmx_mtop_t*    mtop,
-                                  const t_inputrec*    ir,
+                                  const gmx_mtop_t&    mtop,
+                                  const t_inputrec&    inputrec,
                                   const gmx_ddbox_t*   ddbox)
 {
     gmx_domdec_comm_t* comm        = dd->comm;
     DDRankSetup&       ddRankSetup = comm->ddRankSetup;
 
-    if (EEL_PME(ir->coulombtype) || EVDW_PME(ir->vdwtype))
+    if (EEL_PME(inputrec.coulombtype) || EVDW_PME(inputrec.vdwtype))
     {
         init_ddpme(dd, &ddRankSetup.ddpme[0], 0);
         if (ddRankSetup.npmedecompdim >= 2)
@@ -2820,7 +2782,9 @@ static void set_ddgrid_parameters(const gmx::MDLogger& mdlog,
         ddRankSetup.numRanksDoingPme = 0;
         if (dd->pme_nodeid >= 0)
         {
-            gmx_fatal_collective(FARGS, dd->mpi_comm_all, DDMASTER(dd),
+            gmx_fatal_collective(FARGS,
+                                 dd->mpi_comm_all,
+                                 DDMASTER(dd),
                                  "Can not have separate PME ranks without PME electrostatics");
         }
     }
@@ -2831,26 +2795,20 @@ static void set_ddgrid_parameters(const gmx::MDLogger& mdlog,
     }
     if (!isDlbDisabled(comm))
     {
-        set_cell_limits_dlb(mdlog, dd, dlb_scale, ir, ddbox);
+        set_cell_limits_dlb(mdlog, dd, dlb_scale, inputrec, ddbox);
     }
 
-    logSettings(mdlog, dd, mtop, ir, dlb_scale, ddbox);
+    logSettings(mdlog, dd, mtop, inputrec, dlb_scale, ddbox);
 
-    real vol_frac;
-    if (ir->pbcType == PbcType::No)
-    {
-        vol_frac = 1 - 1 / static_cast<double>(dd->nnodes);
-    }
-    else
-    {
-        vol_frac = (1 + comm_box_frac(dd->numCells, comm->systemInfo.cutoff, *ddbox))
-                   / static_cast<double>(dd->nnodes);
-    }
+    const real vol_frac = (inputrec.pbcType == PbcType::No)
+                                  ? (1 - 1 / static_cast<double>(dd->nnodes))
+                                  : ((1 + comm_box_frac(dd->numCells, comm->systemInfo.cutoff, *ddbox))
+                                     / static_cast<double>(dd->nnodes));
     if (debug)
     {
         fprintf(debug, "Volume fraction for all DD zones: %f\n", vol_frac);
     }
-    int natoms_tot = mtop->natoms;
+    int natoms_tot = mtop.natoms;
 
     dd->ga2la = new gmx_ga2la_t(natoms_tot, static_cast<int>(vol_frac * natoms_tot));
 }
@@ -2892,17 +2850,19 @@ static DDSettings getDDSettings(const gmx::MDLogger&     mdlog,
         ddSettings.recordLoad = (wallcycle_have_counter() && recload > 0);
     }
 
-    ddSettings.initialDlbState = determineInitialDlbState(mdlog, options.dlbOption,
-                                                          ddSettings.recordLoad, mdrunOptions, &ir);
+    ddSettings.initialDlbState =
+            determineInitialDlbState(mdlog, options.dlbOption, ddSettings.recordLoad, mdrunOptions, ir);
     GMX_LOG(mdlog.info)
             .appendTextFormatted("Dynamic load balancing: %s",
-                                 edlbs_names[static_cast<int>(ddSettings.initialDlbState)]);
+                                 enumValueToString(ddSettings.initialDlbState));
 
     return ddSettings;
 }
 
 gmx_domdec_t::gmx_domdec_t(const t_inputrec& ir) : unitCellInfo(ir) {}
 
+gmx_domdec_t::~gmx_domdec_t() = default;
+
 namespace gmx
 {
 
@@ -2984,35 +2944,59 @@ DomainDecompositionBuilder::Impl::Impl(const MDLogger&      mdlog,
         srand(1 + cr_->rankInDefaultCommunicator);
     }
 
-    systemInfo_ = getSystemInfo(mdlog_, MASTER(cr_) ? DDRole::Master : DDRole::Agent,
-                                cr->mpiDefaultCommunicator, options_, mtop_, ir_, box, xGlobal);
+    systemInfo_ = getSystemInfo(mdlog_,
+                                MASTER(cr_) ? DDRole::Master : DDRole::Agent,
+                                cr->mpiDefaultCommunicator,
+                                options_,
+                                mtop_,
+                                ir_,
+                                box,
+                                xGlobal);
 
     const int  numRanksRequested         = cr_->sizeOfDefaultCommunicator;
     const bool checkForLargePrimeFactors = (options_.numCells[0] <= 0);
-    checkForValidRankCountRequests(numRanksRequested, EEL_PME(ir_.coulombtype),
-                                   options_.numPmeRanks, checkForLargePrimeFactors);
+    checkForValidRankCountRequests(
+            numRanksRequested, EEL_PME(ir_.coulombtype), options_.numPmeRanks, checkForLargePrimeFactors);
 
     // DD grid setup uses a more different cell size limit for
     // automated setup than the one in systemInfo_. The latter is used
     // in set_dd_limits() to configure DLB, for example.
     const real gridSetupCellsizeLimit =
-            getDDGridSetupCellSizeLimit(mdlog_, !isDlbDisabled(ddSettings_.initialDlbState),
-                                        options_.dlbScaling, ir_, systemInfo_.cellsizeLimit);
-    ddGridSetup_ =
-            getDDGridSetup(mdlog_, MASTER(cr_) ? DDRole::Master : DDRole::Agent,
-                           cr->mpiDefaultCommunicator, numRanksRequested, options_, ddSettings_,
-                           systemInfo_, gridSetupCellsizeLimit, mtop_, ir_, box, xGlobal, &ddbox_);
-    checkDDGridSetup(ddGridSetup_, MASTER(cr_) ? DDRole::Master : DDRole::Agent,
-                     cr->mpiDefaultCommunicator, cr->sizeOfDefaultCommunicator, options_,
-                     ddSettings_, systemInfo_, gridSetupCellsizeLimit, ddbox_);
+            getDDGridSetupCellSizeLimit(mdlog_,
+                                        !isDlbDisabled(ddSettings_.initialDlbState),
+                                        options_.dlbScaling,
+                                        ir_,
+                                        systemInfo_.cellsizeLimit);
+    ddGridSetup_ = getDDGridSetup(mdlog_,
+                                  MASTER(cr_) ? DDRole::Master : DDRole::Agent,
+                                  cr->mpiDefaultCommunicator,
+                                  numRanksRequested,
+                                  options_,
+                                  ddSettings_,
+                                  systemInfo_,
+                                  gridSetupCellsizeLimit,
+                                  mtop_,
+                                  ir_,
+                                  box,
+                                  xGlobal,
+                                  &ddbox_);
+    checkDDGridSetup(ddGridSetup_,
+                     MASTER(cr_) ? DDRole::Master : DDRole::Agent,
+                     cr->mpiDefaultCommunicator,
+                     cr->sizeOfDefaultCommunicator,
+                     options_,
+                     ddSettings_,
+                     systemInfo_,
+                     gridSetupCellsizeLimit,
+                     ddbox_);
 
     cr_->npmenodes = ddGridSetup_.numPmeOnlyRanks;
 
     ddRankSetup_ = getDDRankSetup(mdlog_, cr_->sizeOfDefaultCommunicator, ddGridSetup_, ir_);
 
     /* Generate the group communicator, also decides the duty of each rank */
-    cartSetup_ = makeGroupCommunicators(mdlog_, ddSettings_, options_.rankOrder, ddRankSetup_, cr_,
-                                        ddCellIndex_, &pmeRanks_);
+    cartSetup_ = makeGroupCommunicators(
+            mdlog_, ddSettings_, options_.rankOrder, ddRankSetup_, cr_, ddCellIndex_, &pmeRanks_);
 }
 
 gmx_domdec_t* DomainDecompositionBuilder::Impl::build(LocalAtomSetManager* atomSets)
@@ -3026,20 +3010,29 @@ gmx_domdec_t* DomainDecompositionBuilder::Impl::build(LocalAtomSetManager* atomS
     dd->comm->ddRankSetup        = ddRankSetup_;
     dd->comm->cartesianRankSetup = cartSetup_;
 
-    set_dd_limits(mdlog_, MASTER(cr_) ? DDRole::Master : DDRole::Agent, dd, options_, ddSettings_,
-                  systemInfo_, ddGridSetup_, ddRankSetup_.numPPRanks, &mtop_, &ir_, ddbox_);
+    set_dd_limits(mdlog_,
+                  MASTER(cr_) ? DDRole::Master : DDRole::Agent,
+                  dd,
+                  options_,
+                  ddSettings_,
+                  systemInfo_,
+                  ddGridSetup_,
+                  ddRankSetup_.numPPRanks,
+                  mtop_,
+                  ir_,
+                  ddbox_);
 
     setupGroupCommunication(mdlog_, ddSettings_, pmeRanks_, cr_, mtop_.natoms, dd);
 
     if (thisRankHasDuty(cr_, DUTY_PP))
     {
-        set_ddgrid_parameters(mdlog_, dd, options_.dlbScaling, &mtop_, &ir_, &ddbox_);
+        set_ddgrid_parameters(mdlog_, dd, options_.dlbScaling, mtop_, ir_, &ddbox_);
 
         setup_neighbor_relations(dd);
     }
 
     /* Set overallocation to avoid frequent reallocation of arrays */
-    set_over_alloc_dd(TRUE);
+    set_over_alloc_dd(true);
 
     dd->atomSets = atomSets;
 
@@ -3070,9 +3063,7 @@ DomainDecompositionBuilder::~DomainDecompositionBuilder() = default;
 static gmx_bool test_dd_cutoff(const t_commrec* cr, const matrix box, gmx::ArrayRef<const gmx::RVec> x, real cutoffRequested)
 {
     gmx_ddbox_t ddbox;
-    int         d, dim, np;
-    real        inv_cell_size;
-    int         LocallyLimited;
+    int         LocallyLimited = 0;
 
     const auto* dd = cr->dd;
 
@@ -3080,17 +3071,17 @@ static gmx_bool test_dd_cutoff(const t_commrec* cr, const matrix box, gmx::Array
 
     LocallyLimited = 0;
 
-    for (d = 0; d < dd->ndim; d++)
+    for (int d = 0; d < dd->ndim; d++)
     {
-        dim = dd->dim[d];
+        const int dim = dd->dim[d];
 
-        inv_cell_size = DD_CELL_MARGIN * dd->numCells[dim] / ddbox.box_size[dim];
+        real inv_cell_size = DD_CELL_MARGIN * dd->numCells[dim] / ddbox.box_size[dim];
         if (dd->unitCellInfo.ddBoxIsDynamic)
         {
             inv_cell_size *= DD_PRES_SCALE_MARGIN;
         }
 
-        np = 1 + static_cast<int>(cutoffRequested * inv_cell_size * ddbox.skew_fac[dim]);
+        const int np = 1 + static_cast<int>(cutoffRequested * inv_cell_size * ddbox.skew_fac[dim]);
 
         if (!isDlbDisabled(dd->comm) && (dim < ddbox.npbcdim) && (dd->comm->cd[d].np_dlb > 0))
         {
@@ -3117,7 +3108,7 @@ static gmx_bool test_dd_cutoff(const t_commrec* cr, const matrix box, gmx::Array
         /* If DLB is not active yet, we don't need to check the grid jumps.
          * Actually we shouldn't, because then the grid jump data is not set.
          */
-        if (isDlbOn(dd->comm) && check_grid_jump(0, dd, cutoffRequested, &ddbox, FALSE))
+        if (isDlbOn(dd->comm) && gmx::check_grid_jump(0, dd, cutoffRequested, &ddbox, FALSE))
         {
             LocallyLimited = 1;
         }
@@ -3133,11 +3124,9 @@ static gmx_bool test_dd_cutoff(const t_commrec* cr, const matrix box, gmx::Array
     return TRUE;
 }
 
-gmx_bool change_dd_cutoff(t_commrec* cr, const matrix box, gmx::ArrayRef<const gmx::RVec> x, real cutoffRequested)
+bool change_dd_cutoff(t_commrec* cr, const matrix box, gmx::ArrayRef<const gmx::RVec> x, real cutoffRequested)
 {
-    gmx_bool bCutoffAllowed;
-
-    bCutoffAllowed = test_dd_cutoff(cr, box, x, cutoffRequested);
+    bool bCutoffAllowed = test_dd_cutoff(cr, box, x, cutoffRequested);
 
     if (bCutoffAllowed)
     {
@@ -3174,9 +3163,14 @@ void constructGpuHaloExchange(const gmx::MDLogger&            mdlog,
         for (int pulse = cr.dd->gpuHaloExchange[d].size(); pulse < cr.dd->comm->cd[d].numPulses(); pulse++)
         {
             cr.dd->gpuHaloExchange[d].push_back(std::make_unique<gmx::GpuHaloExchange>(
-                    cr.dd, d, cr.mpi_comm_mysim, deviceStreamManager.context(),
+                    cr.dd,
+                    d,
+                    cr.mpi_comm_mygroup,
+                    deviceStreamManager.context(),
                     deviceStreamManager.stream(gmx::DeviceStreamType::NonBondedLocal),
-                    deviceStreamManager.stream(gmx::DeviceStreamType::NonBondedNonLocal), pulse, wcycle));
+                    deviceStreamManager.stream(gmx::DeviceStreamType::NonBondedNonLocal),
+                    pulse,
+                    wcycle));
         }
     }
 }
index 2b65e1989b822eb638f3375b86f29fe0d1f2c681..f60c429b6ad1a09507663246f81fd3e5bc2d08ee 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2005 - 2014, The GROMACS development team.
  * Copyright (c) 2015,2016,2017,2018,2019 by the GROMACS development team.
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +64,6 @@
 
 #include "gromacs/gpu_utils/devicebuffer_datatype.h"
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
 struct cginfo_mb_t;
@@ -74,8 +72,6 @@ struct gmx_ddbox_t;
 struct gmx_domdec_zones_t;
 struct gmx_localtop_t;
 struct gmx_mtop_t;
-struct t_block;
-struct t_blocka;
 struct t_commrec;
 struct t_forcerec;
 struct t_inputrec;
@@ -94,6 +90,9 @@ class ForceWithShiftForces;
 class MDLogger;
 class RangePartitioning;
 class VirtualSitesHandler;
+template<typename>
+class ArrayRef;
+enum class DDBondedChecking : bool;
 } // namespace gmx
 
 /*! \brief Returns the global topology atom number belonging to local atom index i.
@@ -105,13 +104,13 @@ class VirtualSitesHandler;
 int ddglatnr(const gmx_domdec_t* dd, int i);
 
 /*! \brief Returns a list of update group partitioning for each molecule type or empty when update groups are not used */
-gmx::ArrayRef<const gmx::RangePartitioning> getUpdateGroupingPerMoleculetype(const gmx_domdec_t& dd);
+gmx::ArrayRef<const gmx::RangePartitioning> getUpdateGroupingsPerMoleculeType(const gmx_domdec_t& dd);
 
 /*! \brief Store the global cg indices of the home cgs in state,
  *
  * This means it can be reset, even after a new DD partitioning.
  */
-void dd_store_state(struct gmx_domdec_t* dd, t_state* state);
+void dd_store_state(const gmx_domdec_t& dd, t_state* state);
 
 /*! \brief Returns a pointer to the gmx_domdec_zones_t struct */
 struct gmx_domdec_zones_t* domdec_zones(struct gmx_domdec_t* dd);
@@ -123,13 +122,13 @@ int dd_numAtomsZones(const gmx_domdec_t& dd);
 int dd_numHomeAtoms(const gmx_domdec_t& dd);
 
 /*! \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);
+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);
+int dd_natoms_vsite(const gmx_domdec_t& dd);
 
 /*! \brief Sets the atom range for atom in the local state for atoms received in constraints communication */
-void dd_get_constraint_range(const gmx_domdec_t* dd, int* at_start, int* at_end);
+void dd_get_constraint_range(const gmx_domdec_t& dd, int* at_start, int* at_end);
 
 /*! \libinternal \brief Struct for passing around the number of PME domains */
 struct NumPmeDomains
@@ -145,31 +144,22 @@ NumPmeDomains getNumPmeDomains(const gmx_domdec_t* dd);
 std::vector<int> get_pme_ddranks(const t_commrec* cr, int pmenodeid);
 
 /*! \brief Returns the maximum shift for coordinate communication in PME, dim x */
-int dd_pme_maxshift_x(const gmx_domdec_t* dd);
+int dd_pme_maxshift_x(const gmx_domdec_t& dd);
 
 /*! \brief Returns the maximum shift for coordinate communication in PME, dim y */
-int dd_pme_maxshift_y(const gmx_domdec_t* dd);
+int dd_pme_maxshift_y(const gmx_domdec_t& dd);
 
-/*! \brief Return whether constraints, not including settles, cross domain boundaries */
-bool ddHaveSplitConstraints(const gmx_domdec_t& dd);
+/*! \brief Return whether constraints, not including settles, may cross domain boundaries */
+bool ddMayHaveSplitConstraints(const gmx_domdec_t& dd);
 
 /*! \brief Return whether update groups are used */
 bool ddUsesUpdateGroups(const gmx_domdec_t& dd);
 
-/*! \brief Initialize data structures for bonded interactions */
-void dd_init_bondeds(FILE*                           fplog,
-                     gmx_domdec_t*                   dd,
-                     const gmx_mtop_t&               mtop,
-                     const gmx::VirtualSitesHandler* vsite,
-                     const t_inputrec*               ir,
-                     gmx_bool                        bBCheck,
-                     gmx::ArrayRef<cginfo_mb_t>      cginfo_mb);
-
 /*! \brief Returns whether molecules are always whole, i.e. not broken by PBC */
 bool dd_moleculesAreAlwaysWhole(const gmx_domdec_t& dd);
 
 /*! \brief Returns if we need to do pbc for calculating bonded interactions */
-gmx_bool dd_bonded_molpbc(const gmx_domdec_t* dd, PbcType pbcType);
+bool dd_bonded_molpbc(const gmx_domdec_t& dd, PbcType pbcType);
 
 /*! \brief Change the DD non-bonded communication cut-off.
  *
@@ -181,7 +171,7 @@ gmx_bool dd_bonded_molpbc(const gmx_domdec_t* dd, PbcType pbcType);
  * \param[in] x                Position vector, used for computing the dimensions of the system
  * \param[in] cutoffRequested  The requested atom to atom cut-off distance, usually the pair-list cutoff distance
  */
-gmx_bool change_dd_cutoff(t_commrec* cr, const matrix box, gmx::ArrayRef<const gmx::RVec> x, real cutoffRequested);
+bool change_dd_cutoff(t_commrec* cr, const matrix box, gmx::ArrayRef<const gmx::RVec> x, real cutoffRequested);
 
 /*! \brief Set up communication for averaging GPU wait times over domains
  *
@@ -238,10 +228,12 @@ void dd_move_x_constraints(struct gmx_domdec_t*     dd,
                            const matrix             box,
                            gmx::ArrayRef<gmx::RVec> x0,
                            gmx::ArrayRef<gmx::RVec> x1,
-                           gmx_bool                 bX1IsCoord);
+                           bool                     bX1IsCoord);
 
 /*! \brief Communicates the coordinates involved in virtual sites */
 void dd_move_x_vsites(const gmx_domdec_t& dd, const matrix box, rvec* x);
+/*! \brief Communicates the positions and velocities involved in virtual sites */
+void dd_move_x_and_v_vsites(const gmx_domdec_t& dd, const matrix box, rvec* x, rvec* v);
 
 /*! \brief Returns the local atom count array for all constraints
  *
@@ -259,7 +251,7 @@ gmx::ArrayRef<const int> dd_constraints_nlocalatoms(const gmx_domdec_t* dd);
 [[noreturn]] void dd_print_missing_interactions(const gmx::MDLogger&           mdlog,
                                                 t_commrec*                     cr,
                                                 int                            local_count,
-                                                const gmx_mtop_t*              top_global,
+                                                const gmx_mtop_t&              top_global,
                                                 const gmx_localtop_t*          top_local,
                                                 gmx::ArrayRef<const gmx::RVec> x,
                                                 const matrix                   box);
@@ -267,42 +259,71 @@ gmx::ArrayRef<const int> dd_constraints_nlocalatoms(const gmx_domdec_t* dd);
 /*! \brief Generate and store the reverse topology */
 void dd_make_reverse_top(FILE*                           fplog,
                          gmx_domdec_t*                   dd,
-                         const gmx_mtop_t*               mtop,
+                         const gmx_mtop_t&               mtop,
                          const gmx::VirtualSitesHandler* vsite,
-                         const t_inputrec*               ir,
-                         gmx_bool                        bBCheck);
+                         const t_inputrec&               inputrec,
+                         gmx::DDBondedChecking           ddBondedChecking);
+
+/*! \brief Return whether the total bonded interaction count across
+ * domains should be checked this step. */
+bool shouldCheckNumberOfBondedInteractions(const gmx_domdec_t& dd);
+
+//! Return the number of bonded interactions in this domain.
+int numBondedInteractions(const gmx_domdec_t& dd);
+
+/*! \brief Set total bonded interaction count across domains. */
+void setNumberOfBondedInteractionsOverAllDomains(const gmx_domdec_t& dd, int newValue);
+
+/*! \brief Check whether bonded interactions are missing from the reverse topology
+ * produced by domain decomposition.
+ *
+ * Must only be called when DD is active.
+ *
+ * \param[in]    mdlog                                  Logger
+ * \param[in]    cr                                     Communication object
+ * \param[in]    top_global                             Global topology for the error message
+ * \param[in]    top_local                              Local topology for the error message
+ * \param[in]    x                                      Position vector for the error message
+ * \param[in]    box                                    Box matrix for the error message
+ */
+void checkNumberOfBondedInteractions(const gmx::MDLogger&           mdlog,
+                                     t_commrec*                     cr,
+                                     const gmx_mtop_t&              top_global,
+                                     const gmx_localtop_t*          top_local,
+                                     gmx::ArrayRef<const gmx::RVec> x,
+                                     const matrix                   box);
 
 /*! \brief Generate the local topology and virtual site data */
-void dd_make_local_top(struct gmx_domdec_t*       dd,
-                       struct gmx_domdec_zones_t* zones,
-                       int                        npbcdim,
-                       matrix                     box,
-                       rvec                       cellsize_min,
-                       const ivec                 npulse,
-                       t_forcerec*                fr,
-                       rvec*                      cgcm_or_x,
-                       const gmx_mtop_t&          top,
-                       gmx_localtop_t*            ltop);
+void dd_make_local_top(struct gmx_domdec_t*           dd,
+                       struct gmx_domdec_zones_t*     zones,
+                       int                            npbcdim,
+                       matrix                         box,
+                       rvec                           cellsize_min,
+                       const ivec                     npulse,
+                       t_forcerec*                    fr,
+                       gmx::ArrayRef<const gmx::RVec> coordinates,
+                       const gmx_mtop_t&              top,
+                       gmx_localtop_t*                ltop);
 
 /*! \brief Sort ltop->ilist when we are doing free energy. */
-void dd_sort_local_top(gmx_domdec_t* dd, const t_mdatoms* mdatoms, gmx_localtop_t* ltop);
+void dd_sort_local_top(const gmx_domdec_t& dd, const t_mdatoms* mdatoms, gmx_localtop_t* ltop);
 
 /*! \brief Construct local state */
-void dd_init_local_state(struct gmx_domdec_t* dd, const t_state* state_global, t_state* local_state);
+void dd_init_local_state(const gmx_domdec_t& dd, const t_state* state_global, t_state* local_state);
 
 /*! \brief Generate a list of links between atoms that are linked by bonded interactions
  *
  * Also stores whether atoms are linked in \p cginfo_mb.
  */
-t_blocka* makeBondedLinks(const gmx_mtop_t& mtop, gmx::ArrayRef<cginfo_mb_t> cginfo_mb);
+void makeBondedLinks(gmx_domdec_t* dd, const gmx_mtop_t& mtop, gmx::ArrayRef<cginfo_mb_t> cginfo_mb);
 
 /*! \brief Calculate the maximum distance involved in 2-body and multi-body bonded interactions */
 void dd_bonded_cg_distance(const gmx::MDLogger&           mdlog,
-                           const gmx_mtop_t*              mtop,
-                           const t_inputrec*              ir,
+                           const gmx_mtop_t&              mtop,
+                           const t_inputrec&              ir,
                            gmx::ArrayRef<const gmx::RVec> x,
                            const matrix                   box,
-                           gmx_bool                       bBCheck,
+                           gmx::DDBondedChecking          ddBondedChecking,
                            real*                          r_2b,
                            real*                          r_mb);
 
index b11ef6bdb335f738add0841c2b5991bd159ace8f..cd6fec86c7c0f867b5029c052ead5db9b378423d 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2006,2007,2008,2009,2010 by the GROMACS development team.
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,12 +107,12 @@ void dd_move_x_constraints(gmx_domdec_t*            dd,
                            const matrix             box,
                            gmx::ArrayRef<gmx::RVec> x0,
                            gmx::ArrayRef<gmx::RVec> x1,
-                           gmx_bool                 bX1IsCoord)
+                           bool                     bX1IsCoord)
 {
     if (dd->constraint_comm)
     {
-        dd_move_x_specat(dd, dd->constraint_comm, box, as_rvec_array(x0.data()),
-                         as_rvec_array(x1.data()), bX1IsCoord);
+        dd_move_x_specat(
+                dd, dd->constraint_comm, box, as_rvec_array(x0.data()), as_rvec_array(x1.data()), bX1IsCoord);
 
         ddReopenBalanceRegionCpu(dd);
     }
@@ -210,19 +210,10 @@ static void walk_out(int                       con,
             {
                 /* Walk further */
                 const int* iap = constr_iatomptr(ia1, ia2, coni);
-                int        b;
-                if (a == iap[1])
-                {
-                    b = iap[2];
-                }
-                else
-                {
-                    b = iap[1];
-                }
+                const int  b   = (a == iap[1]) ? iap[2] : iap[1];
                 if (!ga2la.findHome(offset + b))
                 {
-                    walk_out(coni, con_offset, b, offset, nrec - 1, ia1, ia2, at2con, ga2la, FALSE,
-                             dc, dcc, il_local, ireq);
+                    walk_out(coni, con_offset, b, offset, nrec - 1, ia1, ia2, at2con, ga2la, FALSE, dc, dcc, il_local, ireq);
                 }
             }
         }
@@ -231,7 +222,7 @@ static void walk_out(int                       con,
 
 /*! \brief Looks up SETTLE constraints for a range of charge-groups */
 static void atoms_to_settles(gmx_domdec_t*                         dd,
-                             const gmx_mtop_t*                     mtop,
+                             const gmx_mtop_t&                     mtop,
                              const int*                            cginfo,
                              gmx::ArrayRef<const std::vector<int>> at2settle_mt,
                              int                                   cg_start,
@@ -247,18 +238,18 @@ static void atoms_to_settles(gmx_domdec_t*                         dd,
     {
         if (GET_CGINFO_SETTLE(cginfo[a]))
         {
-            int a_gl = dd->globalAtomIndices[a];
-            int a_mol;
+            int a_gl  = dd->globalAtomIndices[a];
+            int a_mol = 0;
             mtopGetMolblockIndex(mtop, a_gl, &mb, nullptr, &a_mol);
 
-            const gmx_molblock_t* molb   = &mtop->molblock[mb];
+            const gmx_molblock_t* molb   = &mtop.molblock[mb];
             int                   settle = at2settle_mt[molb->type][a_mol];
 
             if (settle >= 0)
             {
                 int offset = a_gl - a_mol;
 
-                const int* ia1 = mtop->moltype[molb->type].ilist[F_SETTLE].iatoms.data();
+                const int* ia1 = mtop.moltype[molb->type].ilist[F_SETTLE].iatoms.data();
 
                 int      a_gls[3];
                 gmx_bool bAssign = FALSE;
@@ -306,7 +297,7 @@ static void atoms_to_settles(gmx_domdec_t*                         dd,
 
 /*! \brief Looks up constraint for the local atoms */
 static void atoms_to_constraints(gmx_domdec_t*                         dd,
-                                 const gmx_mtop_t*                     mtop,
+                                 const gmx_mtop_t&                     mtop,
                                  const int*                            cginfo,
                                  gmx::ArrayRef<const ListOfLists<int>> at2con_mt,
                                  int                                   nrec,
@@ -327,14 +318,15 @@ static void atoms_to_constraints(gmx_domdec_t*                         dd,
     {
         if (GET_CGINFO_CONSTR(cginfo[a]))
         {
-            int a_gl = dd->globalAtomIndices[a];
-            int molnr, a_mol;
+            int a_gl  = dd->globalAtomIndices[a];
+            int molnr = 0;
+            int a_mol = 0;
             mtopGetMolblockIndex(mtop, a_gl, &mb, &molnr, &a_mol);
 
-            const gmx_molblock_t& molb = mtop->molblock[mb];
+            const gmx_molblock_t& molb = mtop.molblock[mb];
 
-            gmx::ArrayRef<const int> ia1 = mtop->moltype[molb.type].ilist[F_CONSTR].iatoms;
-            gmx::ArrayRef<const int> ia2 = mtop->moltype[molb.type].ilist[F_CONSTRNC].iatoms;
+            gmx::ArrayRef<const int> ia1 = mtop.moltype[molb.type].ilist[F_CONSTR].iatoms;
+            gmx::ArrayRef<const int> ia2 = mtop.moltype[molb.type].ilist[F_CONSTRNC].iatoms;
 
             /* Calculate the global constraint number offset for the molecule.
              * This is only required for the global index to make sure
@@ -348,8 +340,8 @@ static void atoms_to_constraints(gmx_domdec_t*                         dd,
             const auto& at2con = at2con_mt[molb.type];
             for (const int con : at2con[a_mol])
             {
-                const int* iap = constr_iatomptr(ia1, ia2, con);
-                int        b_mol;
+                const int* iap   = constr_iatomptr(ia1, ia2, con);
+                int        b_mol = 0;
                 if (a_mol == iap[1])
                 {
                     b_mol = iap[2];
@@ -383,8 +375,7 @@ static void atoms_to_constraints(gmx_domdec_t*                         dd,
                      * Therefore we call walk_out with nrec recursions to go
                      * after this first call.
                      */
-                    walk_out(con, con_offset, b_mol, offset, nrec, ia1, ia2, at2con, ga2la, TRUE,
-                             dc, dcc, ilc_local, ireq);
+                    walk_out(con, con_offset, b_mol, offset, nrec, ia1, ia2, at2con, ga2la, TRUE, dc, dcc, ilc_local, ireq);
                 }
             }
         }
@@ -397,28 +388,26 @@ static void atoms_to_constraints(gmx_domdec_t*                         dd,
 
     if (debug)
     {
-        fprintf(debug, "Constraints: home %3d border %3d atoms: %3zu\n", nhome, dc->ncon - nhome,
+        fprintf(debug,
+                "Constraints: home %3d border %3d atoms: %3zu\n",
+                nhome,
+                dc->ncon - nhome,
                 dd->constraint_comm ? ireq->size() : 0);
     }
 }
 
 int dd_make_local_constraints(gmx_domdec_t*                  dd,
                               int                            at_start,
-                              const struct gmx_mtop_t*       mtop,
+                              const struct gmx_mtop_t&       mtop,
                               const int*                     cginfo,
                               gmx::Constraints*              constr,
                               int                            nrec,
                               gmx::ArrayRef<InteractionList> il_local)
 {
-    gmx_domdec_constraints_t* dc;
-    InteractionList *         ilc_local, *ils_local;
-    gmx::HashedMap<int>*      ga2la_specat;
-    int                       at_end, i, j;
-
     // This code should not be called unless this condition is true,
     // because that's the only time init_domdec_constraints is
     // called...
-    GMX_RELEASE_ASSERT(dd->comm->systemInfo.haveSplitConstraints || dd->comm->systemInfo.haveSplitSettles,
+    GMX_RELEASE_ASSERT(dd->comm->systemInfo.mayHaveSplitConstraints || dd->comm->systemInfo.mayHaveSplitSettles,
                        "dd_make_local_constraints called when there are no local constraints");
     // ... and init_domdec_constraints always sets
     // dd->constraint_comm...
@@ -430,10 +419,10 @@ int dd_make_local_constraints(gmx_domdec_t*                  dd,
     // true. dd->constraint_comm is unilaterally dereferenced before
     // the call to atoms_to_settles.
 
-    dc = dd->constraints;
+    gmx_domdec_constraints_t* dc = dd->constraints;
 
-    ilc_local = &il_local[F_CONSTR];
-    ils_local = &il_local[F_SETTLE];
+    InteractionList* ilc_local = &il_local[F_CONSTR];
+    InteractionList* ils_local = &il_local[F_SETTLE];
 
     dc->ncon = 0;
     gmx::ArrayRef<const ListOfLists<int>> at2con_mt;
@@ -450,7 +439,7 @@ int dd_make_local_constraints(gmx_domdec_t*                  dd,
 
     gmx::ArrayRef<const std::vector<int>> at2settle_mt;
     /* When settle works inside charge groups, we assigned them already */
-    if (dd->comm->systemInfo.haveSplitSettles)
+    if (dd->comm->systemInfo.mayHaveSplitSettles)
     {
         // TODO Perhaps gmx_domdec_constraints_t should keep a valid constr?
         GMX_RELEASE_ASSERT(constr != nullptr, "Must have valid constraints object");
@@ -464,12 +453,10 @@ int dd_make_local_constraints(gmx_domdec_t*                  dd,
     }
     else
     {
-        int t0_set;
-
         /* Do the constraints, if present, on the first thread.
          * Do the settles on all other threads.
          */
-        t0_set = ((!at2con_mt.empty() && dc->nthread > 1) ? 1 : 0);
+        const int t0_set = ((!at2con_mt.empty() && dc->nthread > 1) ? 1 : 0);
 
 #pragma omp parallel for num_threads(dc->nthread) schedule(static)
         for (int thread = 0; thread < dc->nthread; thread++)
@@ -483,23 +470,13 @@ int dd_make_local_constraints(gmx_domdec_t*                  dd,
 
                 if (thread >= t0_set)
                 {
-                    int              cg0, cg1;
-                    InteractionList* ilst;
-
                     /* Distribute the settle check+assignments over
                      * dc->nthread or dc->nthread-1 threads.
                      */
-                    cg0 = (dd->ncg_home * (thread - t0_set)) / (dc->nthread - t0_set);
-                    cg1 = (dd->ncg_home * (thread - t0_set + 1)) / (dc->nthread - t0_set);
+                    const int cg0 = (dd->ncg_home * (thread - t0_set)) / (dc->nthread - t0_set);
+                    const int cg1 = (dd->ncg_home * (thread - t0_set + 1)) / (dc->nthread - t0_set);
 
-                    if (thread == t0_set)
-                    {
-                        ilst = ils_local;
-                    }
-                    else
-                    {
-                        ilst = &dc->ils[thread];
-                    }
+                    InteractionList* ilst = (thread == t0_set) ? ils_local : &dc->ils[thread];
                     ilst->clear();
 
                     std::vector<int>& ireqt = dc->requestedGlobalAtomIndices[thread];
@@ -532,21 +509,26 @@ int dd_make_local_constraints(gmx_domdec_t*                  dd,
         }
     }
 
+    int at_end = 0;
     if (dd->constraint_comm)
     {
-        int nral1;
-
-        at_end = setup_specat_communication(dd, ireq, dd->constraint_comm, dd->constraints->ga2la.get(),
-                                            at_start, 2, "constraint", " or lincs-order");
+        at_end = setup_specat_communication(dd,
+                                            ireq,
+                                            dd->constraint_comm,
+                                            dd->constraints->ga2la.get(),
+                                            at_start,
+                                            2,
+                                            "constraint",
+                                            " or lincs-order");
 
         /* Fill in the missing indices */
-        ga2la_specat = dd->constraints->ga2la.get();
+        gmx::HashedMap<int>* ga2la_specat = dd->constraints->ga2la.get();
 
-        nral1 = 1 + NRAL(F_CONSTR);
-        for (i = 0; i < ilc_local->size(); i += nral1)
+        int nral1 = 1 + NRAL(F_CONSTR);
+        for (int i = 0; i < ilc_local->size(); i += nral1)
         {
             int* iap = ilc_local->iatoms.data() + i;
-            for (j = 1; j < nral1; j++)
+            for (int j = 1; j < nral1; j++)
             {
                 if (iap[j] < 0)
                 {
@@ -558,10 +540,10 @@ int dd_make_local_constraints(gmx_domdec_t*                  dd,
         }
 
         nral1 = 1 + NRAL(F_SETTLE);
-        for (i = 0; i < ils_local->size(); i += nral1)
+        for (int i = 0; i < ils_local->size(); i += nral1)
         {
             int* iap = ils_local->iatoms.data() + i;
-            for (j = 1; j < nral1; j++)
+            for (int j = 1; j < nral1; j++)
             {
                 if (iap[j] < 0)
                 {
@@ -581,29 +563,26 @@ int dd_make_local_constraints(gmx_domdec_t*                  dd,
     return at_end;
 }
 
-void init_domdec_constraints(gmx_domdec_t* dd, const gmx_mtop_t* mtop)
+void init_domdec_constraints(gmx_domdec_t* dd, const gmx_mtop_t& mtop)
 {
-    gmx_domdec_constraints_t* dc;
-    const gmx_molblock_t*     molb;
-
     if (debug)
     {
         fprintf(debug, "Begin init_domdec_constraints\n");
     }
 
-    dd->constraints = new gmx_domdec_constraints_t;
-    dc              = dd->constraints;
+    dd->constraints              = new gmx_domdec_constraints_t;
+    gmx_domdec_constraints_t* dc = dd->constraints;
 
-    dc->molb_con_offset.resize(mtop->molblock.size());
-    dc->molb_ncon_mol.resize(mtop->molblock.size());
+    dc->molb_con_offset.resize(mtop.molblock.size());
+    dc->molb_ncon_mol.resize(mtop.molblock.size());
 
     int ncon = 0;
-    for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
+    for (size_t mb = 0; mb < mtop.molblock.size(); mb++)
     {
-        molb                    = &mtop->molblock[mb];
-        dc->molb_con_offset[mb] = ncon;
-        dc->molb_ncon_mol[mb]   = mtop->moltype[molb->type].ilist[F_CONSTR].size() / 3
-                                + mtop->moltype[molb->type].ilist[F_CONSTRNC].size() / 3;
+        const gmx_molblock_t* molb = &mtop.molblock[mb];
+        dc->molb_con_offset[mb]    = ncon;
+        dc->molb_ncon_mol[mb]      = mtop.moltype[molb->type].ilist[F_CONSTR].size() / 3
+                                + mtop.moltype[molb->type].ilist[F_CONSTRNC].size() / 3;
         ncon += molb->nmol * dc->molb_ncon_mol[mb];
     }
 
@@ -615,10 +594,10 @@ void init_domdec_constraints(gmx_domdec_t* dd, const gmx_mtop_t* mtop)
     /* Use a hash table for the global to local index.
      * The number of keys is a rough estimate, it will be optimized later.
      */
-    int numKeysEstimate = std::min(mtop->natoms / 20, mtop->natoms / (2 * dd->nnodes));
+    int numKeysEstimate = std::min(mtop.natoms / 20, mtop.natoms / (2 * dd->nnodes));
     dc->ga2la           = std::make_unique<gmx::HashedMap<int>>(numKeysEstimate);
 
-    dc->nthread = gmx_omp_nthreads_get(emntDomdec);
+    dc->nthread = gmx_omp_nthreads_get(ModuleMultiThread::Domdec);
     dc->ils.resize(dc->nthread);
 
     dd->constraint_comm = new gmx_domdec_specat_comm_t;
index de25e404a02433974fedda35e998023310ebac2e..e2a5772b180954ab96c26c5d11c2c45f3fba8367 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2005,2006,2007,2008,2009 by the GROMACS development team.
  * Copyright (c) 2010,2012,2013,2014,2015 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,13 +63,13 @@ void dd_clear_local_constraint_indices(gmx_domdec_t* dd);
 /*! \brief Sets up communication and atom indices for all local+connected constraints */
 int dd_make_local_constraints(struct gmx_domdec_t*           dd,
                               int                            at_start,
-                              const struct gmx_mtop_t*       mtop,
+                              const struct gmx_mtop_t&       mtop,
                               const int*                     cginfo,
                               gmx::Constraints*              constr,
                               int                            nrec,
                               gmx::ArrayRef<InteractionList> il_local);
 
 /*! \brief Initializes the data structures for constraint communication */
-void init_domdec_constraints(gmx_domdec_t* dd, const gmx_mtop_t* mtop);
+void init_domdec_constraints(gmx_domdec_t* dd, const gmx_mtop_t& mtop);
 
 #endif
index 691b0b87aa4cef053579f538791b82c868beb2d7..ddfa6b847ffa2b027bcf03c0207639774599efb1 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ enum class DlbState
     offTemporarilyLocked, /**< DLB is off and temporarily can't turn on */
     onCanTurnOff,         /**< DLB is on and can turn off when slow */
     onUser,               /**< DLB is permanently on per user request */
-    nr                    /**< The number of DLB states */
+    Count                 /**< The number of DLB states */
 };
 
 /*! \brief The PME domain decomposition for one dimension */
@@ -423,7 +423,7 @@ struct DDSystemInfo
     //! True when update groups are used
     bool useUpdateGroups = false;
     //! Update atom grouping for each molecule type
-    std::vector<gmx::RangePartitioning> updateGroupingPerMoleculetype;
+    std::vector<gmx::RangePartitioning> updateGroupingsPerMoleculeType;
     //! The maximum radius over all update groups
     real maxUpdateGroupRadius;
 
@@ -442,9 +442,9 @@ struct DDSystemInfo
     real cellsizeLimit = 0;
 
     //! Can atoms connected by constraints be assigned to different domains?
-    bool haveSplitConstraints = false;
+    bool mayHaveSplitConstraints = false;
     //! Can atoms connected by settles be assigned to different domains?
-    bool haveSplitSettles = false;
+    bool mayHaveSplitSettles = false;
     //! Estimated communication range needed for constraints
     real constraintCommunicationRange = 0;
 
@@ -583,35 +583,35 @@ struct gmx_domdec_comm_t // NOLINT (clang-analyzer-optin.performance.Padding)
     /**< Cut-off for multi-body interactions, also 2-body bonded when \p cutoff_mody > \p cutoff */
     real cutoff_mbody = 0;
     /**< The minimum guaranteed cell-size, Cartesian indexing */
-    rvec cellsize_min = {};
+    gmx::RVec cellsize_min = { 0, 0, 0 };
     /**< The minimum guaranteed cell-size with dlb=auto */
-    rvec cellsize_min_dlb = {};
+    gmx::RVec cellsize_min_dlb = { 0, 0, 0 };
     /**< The lower limit for the DD cell size with DLB */
     real cellsize_limit = 0;
     /**< Effectively no NB cut-off limit with DLB for systems without PBC? */
-    gmx_bool bVacDLBNoLimit = false;
+    bool bVacDLBNoLimit = false;
 
     /** With PME load balancing we set limits on DLB */
-    gmx_bool bPMELoadBalDLBLimits = false;
+    bool bPMELoadBalDLBLimits = false;
     /** DLB needs to take into account that we want to allow this maximum
      *  cut-off (for PME load balancing), this could limit cell boundaries.
      */
     real PMELoadBal_max_cutoff = 0;
 
     /**< box lower corner, required with dim's without pbc and -gcom */
-    rvec box0 = {};
+    gmx::RVec box0 = { 0, 0, 0 };
     /**< box size, required with dim's without pbc and -gcom */
-    rvec box_size = {};
+    gmx::RVec box_size = { 0, 0, 0 };
 
     /**< The DD cell lower corner, in triclinic space */
-    rvec cell_x0 = {};
+    gmx::RVec cell_x0 = { 0, 0, 0 };
     /**< The DD cell upper corner, in triclinic space */
-    rvec cell_x1 = {};
+    gmx::RVec cell_x1 = { 0, 0, 0 };
 
     /**< The old \p cell_x0, to check cg displacements */
-    rvec old_cell_x0 = {};
+    gmx::RVec old_cell_x0 = { 0, 0, 0 };
     /**< The old \p cell_x1, to check cg displacements */
-    rvec old_cell_x1 = {};
+    gmx::RVec old_cell_x1 = { 0, 0, 0 };
 
     /** The communication setup and charge group boundaries for the zones */
     gmx_domdec_zones_t zones;
@@ -621,12 +621,12 @@ struct gmx_domdec_comm_t // NOLINT (clang-analyzer-optin.performance.Padding)
      * dynamic load balancing.
      */
     /**< Zone limits for dim 1 with staggered grids */
-    gmx_ddzone_t zone_d1[2];
+    std::array<gmx_ddzone_t, 2> zone_d1;
     /**< Zone limits for dim 2 with staggered grids */
     gmx_ddzone_t zone_d2[2][2];
 
     /** The coordinate/force communication setup and indices */
-    gmx_domdec_comm_dim_t cd[DIM];
+    std::array<gmx_domdec_comm_dim_t, DIM> cd;
     /** Restricts the maximum number of cells to communicate with in one dimension
      *
      * Dynamic load balancing is not permitted to change sizes if it
@@ -639,7 +639,7 @@ struct gmx_domdec_comm_t // NOLINT (clang-analyzer-optin.performance.Padding)
     int64_t master_cg_ddp_count = 0;
 
     /** The number of cg's received from the direct neighbors */
-    int zone_ncg1[DD_MAXZONE] = { 0 };
+    std::array<int, DD_MAXZONE> zone_ncg1 = { 0 };
 
     /** The atom ranges in the local state */
     DDAtomRanges atomRanges;
@@ -687,11 +687,11 @@ struct gmx_domdec_comm_t // NOLINT (clang-analyzer-optin.performance.Padding)
 
     /* Cycle counters over nstlist steps */
     /**< Total cycles counted */
-    float cycl[ddCyclNr] = {};
+    std::array<float, ddCyclNr> cycl = { 0 };
     /**< The number of cycle recordings */
-    int cycl_n[ddCyclNr] = {};
+    std::array<int, ddCyclNr> cycl_n = { 0 };
     /**< The maximum cycle count */
-    float cycl_max[ddCyclNr] = {};
+    std::array<float, ddCyclNr> cycl_max = { 0 };
     /**< Total flops counted */
     double flop = 0.0;
     /**< The number of flop recordings */
@@ -727,7 +727,7 @@ struct gmx_domdec_comm_t // NOLINT (clang-analyzer-optin.performance.Padding)
     /**< Max \p load_sum over the ranks */
     double load_max = 0.0;
     /**< Was load balancing limited, per DD dim */
-    ivec load_lim = {};
+    gmx::IVec load_lim = { 0, 0, 0 };
     /**< Total time on PP done during PME overlap time */
     double load_mdf = 0.0;
     /**< Total time on our PME-only rank */
@@ -799,4 +799,18 @@ static constexpr double DD_PRES_SCALE_MARGIN = 1.02;
 
 /*! \endcond */
 
+//! \internal \brief Reverse topology class
+struct gmx_reverse_top_t
+{
+    //! Constructor
+    gmx_reverse_top_t(const gmx_mtop_t& mtop, bool useFreeEnergy, const ReverseTopOptions& reverseTopOptions);
+    //! Destructor
+    ~gmx_reverse_top_t();
+
+    //! Private implementation definition
+    struct Impl;
+    //! Private implementation declaration
+    std::unique_ptr<Impl> impl_;
+};
+
 #endif
index 9bc3b993445358bd91b17fcdf46cf51797d28e4f..c6363362febb09c5786eae80b5a315f399b8ee80 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2008-2019, by the GROMACS development team, led by
+ * Copyright (c) 2008-2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +83,18 @@ void ddSendrecv(const struct gmx_domdec_t* dd,
     MPI_Status    mpiStatus;
     if (numElementsToSend > 0 && numElementsToReceive > 0)
     {
-        MPI_Sendrecv(sendBuffer, numElementsToSend * sizeof(T), MPI_BYTE, sendRank, mpiTag,
-                     receiveBuffer, numElementsToReceive * sizeof(T), MPI_BYTE, receiveRank, mpiTag,
-                     dd->mpi_comm_all, &mpiStatus);
+        MPI_Sendrecv(sendBuffer,
+                     numElementsToSend * sizeof(T),
+                     MPI_BYTE,
+                     sendRank,
+                     mpiTag,
+                     receiveBuffer,
+                     numElementsToReceive * sizeof(T),
+                     MPI_BYTE,
+                     receiveRank,
+                     mpiTag,
+                     dd->mpi_comm_all,
+                     &mpiStatus);
     }
     else if (numElementsToSend > 0)
     {
@@ -93,8 +102,7 @@ void ddSendrecv(const struct gmx_domdec_t* dd,
     }
     else if (numElementsToReceive > 0)
     {
-        MPI_Recv(receiveBuffer, numElementsToReceive * sizeof(T), MPI_BYTE, receiveRank, mpiTag,
-                 dd->mpi_comm_all, &mpiStatus);
+        MPI_Recv(receiveBuffer, numElementsToReceive * sizeof(T), MPI_BYTE, receiveRank, mpiTag, dd->mpi_comm_all, &mpiStatus);
     }
 #else  // GMX_MPI
     GMX_UNUSED_VALUE(dd);
@@ -121,8 +129,13 @@ void ddSendrecv(const gmx_domdec_t* dd,
                 gmx::ArrayRef<T>    sendBuffer,
                 gmx::ArrayRef<T>    receiveBuffer)
 {
-    ddSendrecv(dd, ddDimensionIndex, direction, sendBuffer.data(), sendBuffer.size(),
-               receiveBuffer.data(), receiveBuffer.size());
+    ddSendrecv(dd,
+               ddDimensionIndex,
+               direction,
+               sendBuffer.data(),
+               sendBuffer.size(),
+               receiveBuffer.data(),
+               receiveBuffer.size());
 }
 
 //! Specialization of extern template for int
@@ -144,12 +157,11 @@ void dd_sendrecv2_rvec(const struct gmx_domdec_t gmx_unused* dd,
                        int gmx_unused n_r_bw)
 {
 #if GMX_MPI
-    int         rank_fw, rank_bw, nreq;
     MPI_Request req[4];
     MPI_Status  stat[4];
 
-    rank_fw = dd->neighbor[ddimind][0];
-    rank_bw = dd->neighbor[ddimind][1];
+    int rank_fw = dd->neighbor[ddimind][0];
+    int rank_bw = dd->neighbor[ddimind][1];
 
     if (!dd->comm->ddSettings.useSendRecv2)
     {
@@ -161,26 +173,22 @@ void dd_sendrecv2_rvec(const struct gmx_domdec_t gmx_unused* dd,
          * are slower.
          * SendRecv2 can be turned on with the env.var. GMX_DD_SENDRECV2
          */
-        nreq = 0;
+        int nreq = 0;
         if (n_r_fw)
         {
-            MPI_Irecv(buf_r_fw[0], n_r_fw * sizeof(rvec), MPI_BYTE, rank_bw, 0, dd->mpi_comm_all,
-                      &req[nreq++]);
+            MPI_Irecv(buf_r_fw[0], n_r_fw * sizeof(rvec), MPI_BYTE, rank_bw, 0, dd->mpi_comm_all, &req[nreq++]);
         }
         if (n_r_bw)
         {
-            MPI_Irecv(buf_r_bw[0], n_r_bw * sizeof(rvec), MPI_BYTE, rank_fw, 1, dd->mpi_comm_all,
-                      &req[nreq++]);
+            MPI_Irecv(buf_r_bw[0], n_r_bw * sizeof(rvec), MPI_BYTE, rank_fw, 1, dd->mpi_comm_all, &req[nreq++]);
         }
         if (n_s_fw)
         {
-            MPI_Isend(buf_s_fw[0], n_s_fw * sizeof(rvec), MPI_BYTE, rank_fw, 0, dd->mpi_comm_all,
-                      &req[nreq++]);
+            MPI_Isend(buf_s_fw[0], n_s_fw * sizeof(rvec), MPI_BYTE, rank_fw, 0, dd->mpi_comm_all, &req[nreq++]);
         }
         if (n_s_bw)
         {
-            MPI_Isend(buf_s_bw[0], n_s_bw * sizeof(rvec), MPI_BYTE, rank_bw, 1, dd->mpi_comm_all,
-                      &req[nreq++]);
+            MPI_Isend(buf_s_bw[0], n_s_bw * sizeof(rvec), MPI_BYTE, rank_bw, 1, dd->mpi_comm_all, &req[nreq++]);
         }
         if (nreq)
         {
@@ -194,11 +202,31 @@ void dd_sendrecv2_rvec(const struct gmx_domdec_t gmx_unused* dd,
          * with a single full-duplex network connection per machine.
          */
         /* Forward */
-        MPI_Sendrecv(buf_s_fw[0], n_s_fw * sizeof(rvec), MPI_BYTE, rank_fw, 0, buf_r_fw[0],
-                     n_r_fw * sizeof(rvec), MPI_BYTE, rank_bw, 0, dd->mpi_comm_all, &stat[0]);
+        MPI_Sendrecv(buf_s_fw[0],
+                     n_s_fw * sizeof(rvec),
+                     MPI_BYTE,
+                     rank_fw,
+                     0,
+                     buf_r_fw[0],
+                     n_r_fw * sizeof(rvec),
+                     MPI_BYTE,
+                     rank_bw,
+                     0,
+                     dd->mpi_comm_all,
+                     &stat[0]);
         /* Backward */
-        MPI_Sendrecv(buf_s_bw[0], n_s_bw * sizeof(rvec), MPI_BYTE, rank_bw, 0, buf_r_bw[0],
-                     n_r_bw * sizeof(rvec), MPI_BYTE, rank_fw, 0, dd->mpi_comm_all, &stat[0]);
+        MPI_Sendrecv(buf_s_bw[0],
+                     n_s_bw * sizeof(rvec),
+                     MPI_BYTE,
+                     rank_bw,
+                     0,
+                     buf_r_bw[0],
+                     n_r_bw * sizeof(rvec),
+                     MPI_BYTE,
+                     rank_fw,
+                     0,
+                     dd->mpi_comm_all,
+                     &stat[0]);
     }
 #endif
 }
@@ -233,8 +261,7 @@ void dd_scatter(const gmx_domdec_t gmx_unused* dd, int gmx_unused nbytes, const
     if (dd->nnodes > 1)
     {
         /* 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);
+        MPI_Scatter(const_cast<void*>(src), nbytes, MPI_BYTE, dest, nbytes, MPI_BYTE, DDMASTERRANK(dd), dd->mpi_comm_all);
     }
     else
 #endif
@@ -254,8 +281,7 @@ void dd_gather(const gmx_domdec_t gmx_unused* dd,
 {
 #if GMX_MPI
     /* 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);
+    MPI_Gather(const_cast<void*>(src), nbytes, MPI_BYTE, dest, nbytes, MPI_BYTE, DDMASTERRANK(dd), dd->mpi_comm_all);
 #endif
 }
 
@@ -267,7 +293,7 @@ void dd_scatterv(const gmx_domdec_t gmx_unused* dd,
                  void*           rbuf)
 {
 #if GMX_MPI
-    int dum;
+    int dum = 0;
 
     if (dd->nnodes > 1)
     {
@@ -277,8 +303,8 @@ void dd_scatterv(const gmx_domdec_t gmx_unused* dd,
             rbuf = &dum;
         }
         /* 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);
+        MPI_Scatterv(
+                const_cast<void*>(sbuf), scounts, disps, MPI_BYTE, rbuf, rcount, MPI_BYTE, DDMASTERRANK(dd), dd->mpi_comm_all);
     }
     else
 #endif
@@ -299,7 +325,7 @@ void dd_gatherv(const gmx_domdec_t gmx_unused* dd,
                 void gmx_unused* rbuf)
 {
 #if GMX_MPI
-    int dum;
+    int dum = 0;
 
     if (scount == 0)
     {
@@ -307,7 +333,7 @@ void dd_gatherv(const gmx_domdec_t gmx_unused* dd,
         sbuf = &dum;
     }
     /* 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);
+    MPI_Gatherv(
+            const_cast<void*>(sbuf), scount, MPI_BYTE, rbuf, rcounts, disps, MPI_BYTE, DDMASTERRANK(dd), dd->mpi_comm_all);
 #endif
 }
index 1b058becc5b7c0168faa3609c8a6783e9ed8e2e1..38bfa5c59188fa36110cab83daab532af9ec096c 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2008,2009,2010,2011,2012 by the GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cmath>
 #include <cstdio>
 
+#include <numeric>
+
 #include "gromacs/domdec/domdec.h"
 #include "gromacs/domdec/domdec_struct.h"
 #include "gromacs/domdec/options.h"
 #include "gromacs/ewald/pme.h"
 #include "gromacs/gmxlib/network.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/perf_est.h"
@@ -126,23 +129,6 @@ static int largest_divisor(int n)
     return div.back();
 }
 
-/*! \brief Compute largest common divisor of \p n1 and \b n2 */
-static int lcd(int n1, int n2)
-{
-    int d, i;
-
-    d = 1;
-    for (i = 2; (i <= n1 && i <= n2); i++)
-    {
-        if (n1 % i == 0 && n2 % i == 0)
-        {
-            d = i;
-        }
-    }
-
-    return d;
-}
-
 /*! \brief Returns TRUE when there are enough PME ranks for the ratio */
 static gmx_bool fits_pme_ratio(int nrank_tot, int nrank_pme, float ratio)
 {
@@ -174,7 +160,7 @@ static gmx_bool fits_pp_pme_perf(int ntot, int npme, float ratio)
      * The factor of 2 allows for a maximum ratio of 2^2=4
      * between nx_pme and ny_pme.
      */
-    if (lcd(ntot - npme, npme) * 2 < npme_root2)
+    if (std::gcd(ntot - npme, npme) * 2 < npme_root2)
     {
         return FALSE;
     }
@@ -190,10 +176,7 @@ static int guess_npme(const gmx::MDLogger& mdlog,
                       const matrix         box,
                       int                  nrank_tot)
 {
-    float ratio;
-    int   npme;
-
-    ratio = pme_load_estimate(mtop, ir, box);
+    float ratio = pme_load_estimate(mtop, ir, box);
 
     GMX_LOG(mdlog.info).appendTextFormatted("Guess for relative PME load: %.2f", ratio);
 
@@ -216,7 +199,7 @@ static int guess_npme(const gmx::MDLogger& mdlog,
      * We start with a minimum PME node fraction of 1/16
      * and avoid ratios which lead to large prime factors in nnodes-npme.
      */
-    npme = (nrank_tot + 15) / 16;
+    int npme = (nrank_tot + 15) / 16;
     while (npme <= nrank_tot / 3)
     {
         if (nrank_tot % npme == 0)
@@ -253,7 +236,11 @@ static int guess_npme(const gmx::MDLogger& mdlog,
                   "grid_y=%d).\n"
                   "Use the -npme option of mdrun or change the number of ranks or the PME grid "
                   "dimensions, see the manual for details.",
-                  ratio, gmx::roundToInt(0.95 * ratio * nrank_tot), nrank_tot / 2, ir.nkx, ir.nky);
+                  ratio,
+                  gmx::roundToInt(0.95 * ratio * nrank_tot),
+                  nrank_tot / 2,
+                  ir.nkx,
+                  ir.nky);
     }
     else
     {
@@ -261,7 +248,8 @@ static int guess_npme(const gmx::MDLogger& mdlog,
                 .appendTextFormatted(
                         "Will use %d particle-particle and %d PME only ranks\n"
                         "This is a guess, check the performance at the end of the log file",
-                        nrank_tot - npme, npme);
+                        nrank_tot - npme,
+                        npme);
     }
 
     return npme;
@@ -275,28 +263,26 @@ static int div_up(int n, int f)
 
 real comm_box_frac(const gmx::IVec& dd_nc, real cutoff, const gmx_ddbox_t& ddbox)
 {
-    int  i, j, k;
     rvec nw;
-    real comm_vol;
 
-    for (i = 0; i < DIM; i++)
+    for (int i = 0; i < DIM; i++)
     {
         real bt = ddbox.box_size[i] * ddbox.skew_fac[i];
         nw[i]   = dd_nc[i] * cutoff / bt;
     }
 
-    comm_vol = 0;
-    for (i = 0; i < DIM; i++)
+    real comm_vol = 0;
+    for (int i = 0; i < DIM; i++)
     {
         if (dd_nc[i] > 1)
         {
             comm_vol += nw[i];
-            for (j = i + 1; j < DIM; j++)
+            for (int j = i + 1; j < DIM; j++)
             {
                 if (dd_nc[j] > 1)
                 {
                     comm_vol += nw[i] * nw[j] * M_PI / 4;
-                    for (k = j + 1; k < DIM; k++)
+                    for (int k = j + 1; k < DIM; k++)
                     {
                         if (dd_nc[k] > 1)
                         {
@@ -314,8 +300,8 @@ real comm_box_frac(const gmx::IVec& dd_nc, real cutoff, const gmx_ddbox_t& ddbox
 /*! \brief Return whether the DD inhomogeneous in the z direction */
 static gmx_bool inhomogeneous_z(const t_inputrec& ir)
 {
-    return ((EEL_PME(ir.coulombtype) || ir.coulombtype == eelEWALD) && ir.pbcType == PbcType::Xyz
-            && ir.ewald_geometry == eewg3DC);
+    return ((EEL_PME(ir.coulombtype) || ir.coulombtype == CoulombInteractionType::Ewald)
+            && ir.pbcType == PbcType::Xyz && ir.ewald_geometry == EwaldGeometry::ThreeDC);
 }
 
 /*! \brief Estimate cost of PME FFT communication
@@ -328,9 +314,7 @@ static gmx_bool inhomogeneous_z(const t_inputrec& ir)
 static float comm_pme_cost_vol(int npme, int a, int b, int c)
 {
     /* We use a float here, since an integer might overflow */
-    float comm_vol;
-
-    comm_vol = npme - 1;
+    float comm_vol = npme - 1;
     comm_vol *= npme;
     comm_vol *= div_up(a, npme);
     comm_vol *= div_up(b, npme);
@@ -351,9 +335,7 @@ static float comm_cost_est(real               limit,
                            const gmx::IVec&   nc)
 {
     gmx::IVec npme = { 1, 1, 1 };
-    int       i, j, nk, overlap;
     rvec      bt;
-    float     comm_vol, comm_vol_xf, comm_pme, cost_pbcdx;
     /* This is the cost of a pbc_dx call relative to the cost
      * of communicating the coordinate and force of an atom.
      * This will be machine dependent.
@@ -361,7 +343,6 @@ static float comm_cost_est(real               limit,
      */
     float pbcdx_rect_fac = 0.1;
     float pbcdx_tric_fac = 0.2;
-    float temp;
 
     /* Check the DD algorithm restrictions */
     if ((ir.pbcType == PbcType::XY && ir.nwall < 2 && nc[ZZ] > 1)
@@ -378,11 +359,12 @@ static float comm_cost_est(real               limit,
     assert(ddbox.npbcdim <= DIM);
 
     /* Check if the triclinic requirements are met */
-    for (i = 0; i < DIM; i++)
+    for (int i = 0; i < DIM; i++)
     {
-        for (j = i + 1; j < ddbox.npbcdim; j++)
+        for (int j = i + 1; j < ddbox.npbcdim; j++)
         {
-            if (box[j][i] != 0 || ir.deform[j][i] != 0 || (ir.epc != epcNO && ir.compress[j][i] != 0))
+            if (box[j][i] != 0 || ir.deform[j][i] != 0
+                || (ir.epc != PressureCoupling::No && ir.compress[j][i] != 0))
             {
                 if (nc[j] > 1 && nc[i] == 1)
                 {
@@ -392,7 +374,7 @@ static float comm_cost_est(real               limit,
         }
     }
 
-    for (i = 0; i < DIM; i++)
+    for (int i = 0; i < DIM; i++)
     {
         bt[i] = ddbox.box_size[i] * ddbox.skew_fac[i];
 
@@ -446,8 +428,8 @@ static float comm_cost_est(real               limit,
          */
         bool useThreads     = true;
         bool errorsAreFatal = false;
-        if (!gmx_pme_check_restrictions(ir.pme_order, ir.nkx, ir.nky, ir.nkz, npme_x, useThreads,
-                                        errorsAreFatal))
+        if (!gmx_pme_check_restrictions(
+                    ir.pme_order, ir.nkx, ir.nky, ir.nkz, npme_x, useThreads, errorsAreFatal))
         {
             return -1;
         }
@@ -457,9 +439,9 @@ static float comm_cost_est(real               limit,
      * for the smallest index, so the decomposition does not
      * depend sensitively on the rounding of the box elements.
      */
-    for (i = 0; i < DIM; i++)
+    for (int i = 0; i < DIM; i++)
     {
-        for (j = i + 1; j < DIM; j++)
+        for (int j = i + 1; j < DIM; j++)
         {
             /* Check if the box size is nearly identical,
              * in that case we prefer nx > ny  and ny > nz.
@@ -488,31 +470,26 @@ static float comm_cost_est(real               limit,
      * and the "back"-communication cost is identical to the forward cost.
      */
 
-    comm_vol = comm_box_frac(nc, cutoff, ddbox);
+    float comm_vol = comm_box_frac(nc, cutoff, ddbox);
 
-    comm_pme = 0;
-    for (i = 0; i < 2; i++)
+    float comm_pme = 0;
+    for (int i = 0; i < 2; i++)
     {
         /* Determine the largest volume for PME x/f redistribution */
         if (nc[i] % npme[i] != 0)
         {
-            if (nc[i] > npme[i])
-            {
-                comm_vol_xf = (npme[i] == 2 ? 1.0 / 3.0 : 0.5);
-            }
-            else
-            {
-                comm_vol_xf = 1.0 - lcd(nc[i], npme[i]) / static_cast<double>(npme[i]);
-            }
+            float comm_vol_xf =
+                    (nc[i] > npme[i]) ? (npme[i] == 2 ? 1.0 / 3.0 : 0.5)
+                                      : (1.0 - std::gcd(nc[i], npme[i]) / static_cast<double>(npme[i]));
             comm_pme += 3 * natoms * comm_vol_xf;
         }
 
         /* Grid overlap communication */
         if (npme[i] > 1)
         {
-            nk      = (i == 0 ? ir.nkx : ir.nky);
-            overlap = (nk % npme[i] == 0 ? ir.pme_order - 1 : ir.pme_order);
-            temp    = npme[i];
+            const int nk      = (i == 0 ? ir.nkx : ir.nky);
+            const int overlap = (nk % npme[i] == 0 ? ir.pme_order - 1 : ir.pme_order);
+            float     temp    = npme[i];
             temp *= overlap;
             temp *= ir.nkx;
             temp *= ir.nky;
@@ -527,7 +504,7 @@ static float comm_cost_est(real               limit,
     comm_pme += comm_pme_cost_vol(npme[XX], ir.nkx, ir.nky, ir.nkz);
 
     /* Add cost of pbc_dx for bondeds */
-    cost_pbcdx = 0;
+    float cost_pbcdx = 0;
     if ((nc[XX] == 1 || nc[YY] == 1) || (nc[ZZ] == 1 && ir.pbcType != PbcType::XY))
     {
         if ((ddbox.tric_dir[XX] && nc[XX] == 1) || (ddbox.tric_dir[YY] && nc[YY] == 1))
@@ -542,9 +519,17 @@ static float comm_cost_est(real               limit,
 
     if (debug)
     {
-        fprintf(debug, "nc %2d %2d %2d %2d %2d vol pp %6.4f pbcdx %6.4f pme %9.3e tot %9.3e\n",
-                nc[XX], nc[YY], nc[ZZ], npme[XX], npme[YY], comm_vol, cost_pbcdx,
-                comm_pme / (3 * natoms), comm_vol + cost_pbcdx + comm_pme / (3 * natoms));
+        fprintf(debug,
+                "nc %2d %2d %2d %2d %2d vol pp %6.4f pbcdx %6.4f pme %9.3e tot %9.3e\n",
+                nc[XX],
+                nc[YY],
+                nc[ZZ],
+                npme[XX],
+                npme[YY],
+                comm_vol,
+                cost_pbcdx,
+                comm_pme / (3 * natoms),
+                comm_vol + cost_pbcdx + comm_pme / (3 * natoms));
     }
 
     return 3 * natoms * (comm_vol + cost_pbcdx) + comm_pme;
@@ -566,14 +551,12 @@ static void assign_factors(const real         limit,
                            gmx::IVec*         irTryPtr,
                            gmx::IVec*         opt)
 {
-    int        x, y, i;
-    float      ce;
     gmx::IVec& ir_try = *irTryPtr;
 
     if (ndiv == 0)
     {
 
-        ce = comm_cost_est(limit, cutoff, box, ddbox, natoms, ir, pbcdxr, npme, ir_try);
+        const float ce = comm_cost_est(limit, cutoff, box, ddbox, natoms, ir, pbcdxr, npme, ir_try);
         if (ce >= 0
             && ((*opt)[XX] == 0
                 || ce < comm_cost_est(limit, cutoff, box, ddbox, natoms, ir, pbcdxr, npme, *opt)))
@@ -584,37 +567,37 @@ static void assign_factors(const real         limit,
         return;
     }
 
-    for (x = mdiv[0]; x >= 0; x--)
+    for (int x = mdiv[0]; x >= 0; x--)
     {
-        for (i = 0; i < x; i++)
+        for (int i = 0; i < x; i++)
         {
             ir_try[XX] *= div[0];
         }
-        for (y = mdiv[0] - x; y >= 0; y--)
+        for (int y = mdiv[0] - x; y >= 0; y--)
         {
-            for (i = 0; i < y; i++)
+            for (int i = 0; i < y; i++)
             {
                 ir_try[YY] *= div[0];
             }
-            for (i = 0; i < mdiv[0] - x - y; i++)
+            for (int i = 0; i < mdiv[0] - x - y; i++)
             {
                 ir_try[ZZ] *= div[0];
             }
 
             /* recurse */
-            assign_factors(limit, cutoff, box, ddbox, natoms, ir, pbcdxr, npme, ndiv - 1, div + 1,
-                           mdiv + 1, irTryPtr, opt);
+            assign_factors(
+                    limit, cutoff, box, ddbox, natoms, ir, pbcdxr, npme, ndiv - 1, div + 1, mdiv + 1, irTryPtr, opt);
 
-            for (i = 0; i < mdiv[0] - x - y; i++)
+            for (int i = 0; i < mdiv[0] - x - y; i++)
             {
                 ir_try[ZZ] /= div[0];
             }
-            for (i = 0; i < y; i++)
+            for (int i = 0; i < y; i++)
             {
                 ir_try[YY] /= div[0];
             }
         }
-        for (i = 0; i < x; i++)
+        for (int i = 0; i < x; i++)
         {
             ir_try[XX] /= div[0];
         }
@@ -636,21 +619,22 @@ static gmx::IVec optimizeDDCells(const gmx::MDLogger& mdlog,
                                  const t_inputrec&    ir,
                                  const DDSystemInfo&  systemInfo)
 {
-    double pbcdxr;
+    double pbcdxr = 0;
 
     const int numPPRanks = numRanksRequested - numPmeOnlyRanks;
 
     GMX_LOG(mdlog.info)
             .appendTextFormatted(
                     "Optimizing the DD grid for %d cells with a minimum initial size of %.3f nm",
-                    numPPRanks, cellSizeLimit);
+                    numPPRanks,
+                    cellSizeLimit);
     if (inhomogeneous_z(ir))
     {
         GMX_LOG(mdlog.info)
                 .appendTextFormatted(
                         "Ewald_geometry=%s: assuming inhomogeneous particle distribution in z, "
                         "will not decompose in z.",
-                        eewg_names[ir.ewald_geometry]);
+                        enumValueToString(ir.ewald_geometry));
     }
 
 
@@ -706,8 +690,19 @@ static gmx::IVec optimizeDDCells(const gmx::MDLogger& mdlog,
 
     gmx::IVec itry       = { 1, 1, 1 };
     gmx::IVec numDomains = { 0, 0, 0 };
-    assign_factors(cellSizeLimit, systemInfo.cutoff, box, ddbox, mtop.natoms, ir, pbcdxr,
-                   numRanksDoingPmeWork, div.size(), div.data(), mdiv.data(), &itry, &numDomains);
+    assign_factors(cellSizeLimit,
+                   systemInfo.cutoff,
+                   box,
+                   ddbox,
+                   mtop.natoms,
+                   ir,
+                   pbcdxr,
+                   numRanksDoingPmeWork,
+                   div.size(),
+                   div.data(),
+                   mdiv.data(),
+                   &itry,
+                   &numDomains);
 
     return numDomains;
 }
@@ -729,11 +724,10 @@ real getDDGridSetupCellSizeLimit(const gmx::MDLogger& mdlog,
         }
         GMX_LOG(mdlog.info)
                 .appendTextFormatted(
-                        "Scaling the initial minimum size with 1/%g (option -dds) = %g", dlb_scale,
-                        1 / dlb_scale);
+                        "Scaling the initial minimum size with 1/%g (option -dds) = %g", dlb_scale, 1 / dlb_scale);
         cellSizeLimit /= dlb_scale;
     }
-    else if (ir.epc != epcNO)
+    else if (ir.epc != PressureCoupling::No)
     {
         GMX_LOG(mdlog.info)
                 .appendTextFormatted(
@@ -758,7 +752,8 @@ void checkForValidRankCountRequests(const int  numRanksRequested,
             gmx_fatal(FARGS,
                       "Cannot have %d separate PME ranks with only %d PP ranks, choose fewer or no "
                       "separate PME ranks",
-                      numPmeRanksRequested, numPPRanksRequested);
+                      numPmeRanksRequested,
+                      numPPRanksRequested);
         }
     }
 
@@ -776,7 +771,8 @@ void checkForValidRankCountRequests(const int  numRanksRequested,
                       "contains a large prime factor %d. In most cases this will lead to "
                       "bad performance. Choose a number with smaller prime factors or "
                       "set the decomposition (option -dd) manually.",
-                      numPPRanksRequested, largestDivisor);
+                      numPPRanksRequested,
+                      largestDivisor);
         }
     }
 }
@@ -791,8 +787,8 @@ static int getNumPmeOnlyRanksToUse(const gmx::MDLogger& mdlog,
                                    const matrix         box,
                                    const int            numRanksRequested)
 {
-    int         numPmeOnlyRanks;
-    const char* extraMessage = "";
+    int         numPmeOnlyRanks = 0;
+    const char* extraMessage    = "";
 
     if (options.numCells[XX] > 0)
     {
@@ -917,8 +913,8 @@ DDGridSetup getDDGridSetup(const gmx::MDLogger&           mdlog,
 
         if (ddRole == DDRole::Master)
         {
-            numDomains = optimizeDDCells(mdlog, numRanksRequested, numPmeOnlyRanks, cellSizeLimit,
-                                         mtop, box, *ddbox, ir, systemInfo);
+            numDomains = optimizeDDCells(
+                    mdlog, numRanksRequested, numPmeOnlyRanks, cellSizeLimit, mtop, box, *ddbox, ir, systemInfo);
         }
     }
 
index 2c543a034369a565317b012d29d2e262067c4926..948041d7d789f881792e744b5c27f85c5dd4cbbc 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2006,2007,2008,2009,2010 by the GROMACS development team.
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 void dd_move_f_specat(const gmx_domdec_t* dd, gmx_domdec_specat_comm_t* spac, rvec* f, rvec* fshift)
 {
-    gmx_specatsend_t* spas;
-    rvec*             vbuf;
-    int               n, n0, n1, dim, dir;
-    ivec              vis;
-    int               is;
-    gmx_bool          bPBC, bScrew;
+    ivec vis;
 
-    n = spac->at_end;
+    int n = spac->at_end;
     for (int d = dd->ndim - 1; d >= 0; d--)
     {
-        dim = dd->dim[d];
+        const int dim = dd->dim[d];
         if (dd->numCells[dim] > 2)
         {
             /* Pulse the grid forward and backward */
-            spas = spac->spas[d];
-            n0   = spas[0].nrecv;
-            n1   = spas[1].nrecv;
+            gmx_specatsend_t* spas = spac->spas[d];
+            int               n0   = spas[0].nrecv;
+            int               n1   = spas[1].nrecv;
             n -= n1 + n0;
-            vbuf = as_rvec_array(spac->vbuf.data());
+            rvec* vbuf = as_rvec_array(spac->vbuf.data());
             /* Send and receive the coordinates */
-            dd_sendrecv2_rvec(dd, d, f + n + n1, n0, vbuf, spas[0].a.size(), f + n, n1,
-                              vbuf + spas[0].a.size(), spas[1].a.size());
-            for (dir = 0; dir < 2; dir++)
+            dd_sendrecv2_rvec(dd,
+                              d,
+                              f + n + n1,
+                              n0,
+                              vbuf,
+                              spas[0].a.size(),
+                              f + n,
+                              n1,
+                              vbuf + spas[0].a.size(),
+                              spas[1].a.size());
+            for (int dir = 0; dir < 2; dir++)
             {
-                bPBC   = ((dir == 0 && dd->ci[dim] == 0)
-                        || (dir == 1 && dd->ci[dim] == dd->numCells[dim] - 1));
-                bScrew = (bPBC && dd->unitCellInfo.haveScrewPBC && dim == XX);
+                bool bPBC   = ((dir == 0 && dd->ci[dim] == 0)
+                             || (dir == 1 && dd->ci[dim] == dd->numCells[dim] - 1));
+                bool bScrew = (bPBC && dd->unitCellInfo.haveScrewPBC && dim == XX);
 
-                spas = &spac->spas[d][dir];
+                gmx_specatsend_t* spas = &spac->spas[d][dir];
                 /* Sum the buffer into the required forces */
                 if (!bPBC || (!bScrew && fshift == nullptr))
                 {
@@ -109,7 +112,7 @@ void dd_move_f_specat(const gmx_domdec_t* dd, gmx_domdec_specat_comm_t* spac, rv
                 {
                     clear_ivec(vis);
                     vis[dim] = (dir == 0 ? 1 : -1);
-                    is       = IVEC2IS(vis);
+                    int is   = gmx::ivecToShiftIndex(vis);
                     if (!bScrew)
                     {
                         /* Sum and add to shift forces */
@@ -141,11 +144,10 @@ void dd_move_f_specat(const gmx_domdec_t* dd, gmx_domdec_specat_comm_t* spac, rv
         else
         {
             /* Two cells, so we only need to communicate one way */
-            spas = &spac->spas[d][0];
+            gmx_specatsend_t* spas = &spac->spas[d][0];
             n -= spas->nrecv;
             /* Send and receive the coordinates */
-            ddSendrecv(dd, d, dddirForward, f + n, spas->nrecv, as_rvec_array(spac->vbuf.data()),
-                       spas->a.size());
+            ddSendrecv(dd, d, dddirForward, f + n, spas->nrecv, as_rvec_array(spac->vbuf.data()), spas->a.size());
             /* Sum the buffer into the required forces */
             if (dd->unitCellInfo.haveScrewPBC && dim == XX
                 && (dd->ci[dim] == 0 || dd->ci[dim] == dd->numCells[dim] - 1))
@@ -180,49 +182,43 @@ void dd_move_x_specat(const gmx_domdec_t*       dd,
                       rvec*                     x1,
                       gmx_bool                  bX1IsCoord)
 {
-    gmx_specatsend_t* spas;
-    int               nvec, v, n, nn, ns0, ns1, nr0, nr1, nr, d, dim, dir, i;
-    gmx_bool          bPBC, bScrew = FALSE;
-    rvec              shift = { 0, 0, 0 };
+    rvec shift = { 0, 0, 0 };
 
-    nvec = 1;
+    int nvec = 1;
     if (x1 != nullptr)
     {
         nvec++;
     }
 
-    n = spac->at_start;
-    for (d = 0; d < dd->ndim; d++)
+    int n = spac->at_start;
+    for (int d = 0; d < dd->ndim; d++)
     {
-        dim = dd->dim[d];
+        int dim = dd->dim[d];
         if (dd->numCells[dim] > 2)
         {
             /* Pulse the grid forward and backward */
             rvec* vbuf = as_rvec_array(spac->vbuf.data());
-            for (dir = 0; dir < 2; dir++)
+            for (int dir = 0; dir < 2; dir++)
             {
+                bool bPBC   = false;
+                bool bScrew = false;
                 if (dir == 0 && dd->ci[dim] == 0)
                 {
-                    bPBC   = TRUE;
+                    bPBC   = true;
                     bScrew = (dd->unitCellInfo.haveScrewPBC && dim == XX);
                     copy_rvec(box[dim], shift);
                 }
                 else if (dir == 1 && dd->ci[dim] == dd->numCells[dim] - 1)
                 {
-                    bPBC   = TRUE;
+                    bPBC   = true;
                     bScrew = (dd->unitCellInfo.haveScrewPBC && dim == XX);
-                    for (i = 0; i < DIM; i++)
+                    for (int i = 0; i < DIM; i++)
                     {
                         shift[i] = -box[dim][i];
                     }
                 }
-                else
-                {
-                    bPBC   = FALSE;
-                    bScrew = FALSE;
-                }
-                spas = &spac->spas[d][dir];
-                for (v = 0; v < nvec; v++)
+                gmx_specatsend_t* spas = &spac->spas[d][dir];
+                for (int v = 0; v < nvec; v++)
                 {
                     rvec* x = (v == 0 ? x0 : x1);
                     /* Copy the required coordinates to the send buffer */
@@ -258,11 +254,11 @@ void dd_move_x_specat(const gmx_domdec_t*       dd,
                 }
             }
             /* Send and receive the coordinates */
-            spas = spac->spas[d];
-            ns0  = spas[0].a.size();
-            nr0  = spas[0].nrecv;
-            ns1  = spas[1].a.size();
-            nr1  = spas[1].nrecv;
+            gmx_specatsend_t* spas = spac->spas[d];
+            int               ns0  = spas[0].a.size();
+            int               nr0  = spas[0].nrecv;
+            int               ns1  = spas[1].a.size();
+            int               nr1  = spas[1].nrecv;
             if (nvec == 1)
             {
                 rvec* vbuf = as_rvec_array(spac->vbuf.data());
@@ -273,17 +269,17 @@ void dd_move_x_specat(const gmx_domdec_t*       dd,
                 rvec* vbuf = as_rvec_array(spac->vbuf.data());
                 /* Communicate both vectors in one buffer */
                 rvec* rbuf = as_rvec_array(spac->vbuf2.data());
-                dd_sendrecv2_rvec(dd, d, vbuf + 2 * ns0, 2 * ns1, rbuf, 2 * nr1, vbuf, 2 * ns0,
-                                  rbuf + 2 * nr1, 2 * nr0);
+                dd_sendrecv2_rvec(
+                        dd, d, vbuf + 2 * ns0, 2 * ns1, rbuf, 2 * nr1, vbuf, 2 * ns0, rbuf + 2 * nr1, 2 * nr0);
                 /* Split the buffer into the two vectors */
-                nn = n;
-                for (dir = 1; dir >= 0; dir--)
+                int nn = n;
+                for (int dir = 1; dir >= 0; dir--)
                 {
-                    nr = spas[dir].nrecv;
-                    for (v = 0; v < 2; v++)
+                    int nr = spas[dir].nrecv;
+                    for (int v = 0; v < 2; v++)
                     {
                         rvec* x = (v == 0 ? x0 : x1);
-                        for (i = 0; i < nr; i++)
+                        for (int i = 0; i < nr; i++)
                         {
                             copy_rvec(*rbuf, x[nn + i]);
                             rbuf++;
@@ -296,10 +292,10 @@ void dd_move_x_specat(const gmx_domdec_t*       dd,
         }
         else
         {
-            spas = &spac->spas[d][0];
+            gmx_specatsend_t* spas = &spac->spas[d][0];
             /* Copy the required coordinates to the send buffer */
             rvec* vbuf = as_rvec_array(spac->vbuf.data());
-            for (v = 0; v < nvec; v++)
+            for (int v = 0; v < nvec; v++)
             {
                 rvec* x = (v == 0 ? x0 : x1);
                 if (dd->unitCellInfo.haveScrewPBC && dim == XX
@@ -338,11 +334,11 @@ void dd_move_x_specat(const gmx_domdec_t*       dd,
                 rvec* rbuf = as_rvec_array(spac->vbuf2.data());
                 ddSendrecv(dd, d, dddirBackward, vbuf, 2 * spas->a.size(), rbuf, 2 * spas->nrecv);
                 /* Split the buffer into the two vectors */
-                nr = spas[0].nrecv;
-                for (v = 0; v < 2; v++)
+                int nr = spas[0].nrecv;
+                for (int v = 0; v < 2; v++)
                 {
                     rvec* x = (v == 0 ? x0 : x1);
-                    for (i = 0; i < nr; i++)
+                    for (int i = 0; i < nr; i++)
                     {
                         copy_rvec(*rbuf, x[n + i]);
                         rbuf++;
@@ -363,11 +359,8 @@ int setup_specat_communication(gmx_domdec_t*             dd,
                                const char*               specat_type,
                                const char*               add_err)
 {
-    int               nsend[2], nlast, nsend_zero[2] = { 0, 0 }, *nsend_ptr;
-    int               dim, ndir, nr, ns, nrecv_local, n0, start, buf[2];
-    int               nat_tot_specat, nat_tot_prev;
-    gmx_bool          bPBC;
-    gmx_specatsend_t* spas;
+    int nsend[2], nsend_zero[2] = { 0, 0 };
+    int buf[2];
 
     if (debug)
     {
@@ -381,21 +374,18 @@ int setup_specat_communication(gmx_domdec_t*             dd,
     const int numRequested = ireq->size();
     nsend[0]               = ireq->size();
     nsend[1]               = nsend[0];
-    nlast                  = nsend[1];
+    int nlast              = nsend[1];
     for (int d = dd->ndim - 1; d >= 0; d--)
     {
         /* Pulse the grid forward and backward */
-        dim  = dd->dim[d];
-        bPBC = (dim < dd->unitCellInfo.npbcdim);
-        if (dd->numCells[dim] == 2)
-        {
-            /* Only 2 cells, so we only need to communicate once */
-            ndir = 1;
-        }
-        else
-        {
-            ndir = 2;
-        }
+        int       dim  = dd->dim[d];
+        bool      bPBC = (dim < dd->unitCellInfo.npbcdim);
+        const int ndir = (dd->numCells[dim] == 2)
+                                 ?
+                                 /* Only 2 cells, so we only need to communicate once */
+                                 1
+                                 : 2;
+        int* nsend_ptr = nullptr;
         for (int dir = 0; dir < ndir; dir++)
         {
             if (!bPBC && dd->numCells[dim] > 2
@@ -409,13 +399,17 @@ int setup_specat_communication(gmx_domdec_t*             dd,
                 nsend_ptr = nsend;
             }
             /* Communicate the number of indices */
-            ddSendrecv(dd, d, dir == 0 ? dddirForward : dddirBackward, nsend_ptr, 2,
-                       spac->nreq[d][dir], 2);
-            nr = spac->nreq[d][dir][1];
+            ddSendrecv(dd, d, dir == 0 ? dddirForward : dddirBackward, nsend_ptr, 2, spac->nreq[d][dir], 2);
+            int nr = spac->nreq[d][dir][1];
             ireq->resize(nlast + nr);
             /* Communicate the indices */
-            ddSendrecv(dd, d, dir == 0 ? dddirForward : dddirBackward, ireq->data(), nsend_ptr[1],
-                       ireq->data() + nlast, nr);
+            ddSendrecv(dd,
+                       d,
+                       dir == 0 ? dddirForward : dddirBackward,
+                       ireq->data(),
+                       nsend_ptr[1],
+                       ireq->data() + nlast,
+                       nr);
             nlast += nr;
         }
         nsend[1] = nlast;
@@ -426,20 +420,13 @@ int setup_specat_communication(gmx_domdec_t*             dd,
     }
 
     /* Search for the requested atoms and communicate the indices we have */
-    nat_tot_specat = at_start;
-    nrecv_local    = 0;
+    int nat_tot_specat = at_start;
+    int nrecv_local    = 0;
     for (int d = 0; d < dd->ndim; d++)
     {
         /* Pulse the grid forward and backward */
-        if (dd->dim[d] >= dd->unitCellInfo.npbcdim || dd->numCells[dd->dim[d]] > 2)
-        {
-            ndir = 2;
-        }
-        else
-        {
-            ndir = 1;
-        }
-        nat_tot_prev = nat_tot_specat;
+        const int ndir = (dd->dim[d] >= dd->unitCellInfo.npbcdim || dd->numCells[dd->dim[d]] > 2) ? 2 : 1;
+        int       nat_tot_prev = nat_tot_specat;
         for (int dir = ndir - 1; dir >= 0; dir--)
         {
             /* To avoid cost of clearing by resize(), we only increase size */
@@ -448,21 +435,21 @@ int setup_specat_communication(gmx_domdec_t*             dd,
                 /* Note: resize initializes new elements to false, which is actually needed here */
                 spac->sendAtom.resize(nat_tot_specat);
             }
-            spas = &spac->spas[d][dir];
-            n0   = spac->nreq[d][dir][0];
-            nr   = spac->nreq[d][dir][1];
+            gmx_specatsend_t* spas = &spac->spas[d][dir];
+            const int         n0   = spac->nreq[d][dir][0];
+            const int         nr   = spac->nreq[d][dir][1];
             if (debug)
             {
                 fprintf(debug, "dim=%d, dir=%d, searching for %d atoms\n", d, dir, nr);
             }
-            start = nlast - nr;
+            const int start = nlast - nr;
             spas->a.clear();
             spac->ibuf.clear();
             nsend[0] = 0;
             for (int i = 0; i < nr; i++)
             {
                 const int indr = (*ireq)[start + i];
-                int       ind;
+                int       ind  = 0;
                 /* Check if this is a home atom and if so ind will be set */
                 if (const int* homeIndex = dd->ga2la->findHome(indr))
                 {
@@ -512,7 +499,11 @@ int setup_specat_communication(gmx_domdec_t*             dd,
                 fprintf(debug,
                         "Send to rank %d, %d (%d) indices, "
                         "receive from rank %d, %d (%d) indices\n",
-                        dd->neighbor[d][1 - dir], nsend[1], nsend[0], dd->neighbor[d][dir], buf[1],
+                        dd->neighbor[d][1 - dir],
+                        nsend[1],
+                        nsend[0],
+                        dd->neighbor[d][dir],
+                        buf[1],
                         buf[0]);
                 if (gmx_debug_at)
                 {
@@ -527,14 +518,19 @@ int setup_specat_communication(gmx_domdec_t*             dd,
             spas->nrecv = buf[1];
             dd->globalAtomIndices.resize(nat_tot_specat + spas->nrecv);
             /* Send and receive the indices */
-            ddSendrecv(dd, d, dir == 0 ? dddirBackward : dddirForward, spac->ibuf.data(),
-                       spac->ibuf.size(), dd->globalAtomIndices.data() + nat_tot_specat, spas->nrecv);
+            ddSendrecv(dd,
+                       d,
+                       dir == 0 ? dddirBackward : dddirForward,
+                       spac->ibuf.data(),
+                       spac->ibuf.size(),
+                       dd->globalAtomIndices.data() + nat_tot_specat,
+                       spas->nrecv);
             nat_tot_specat += spas->nrecv;
         }
 
         /* Increase the x/f communication buffer sizes, when necessary */
-        ns = spac->spas[d][0].a.size();
-        nr = spac->spas[d][0].nrecv;
+        int ns = spac->spas[d][0].a.size();
+        int nr = spac->spas[d][0].nrecv;
         if (ndir == 2)
         {
             ns += spac->spas[d][1].a.size();
@@ -561,7 +557,10 @@ int setup_specat_communication(gmx_domdec_t*             dd,
     {
         if (debug)
         {
-            fprintf(debug, "Requested %d, received %d (tot recv %d)\n", numRequested, nrecv_local,
+            fprintf(debug,
+                    "Requested %d, received %d (tot recv %d)\n",
+                    numRequested,
+                    nrecv_local,
                     nat_tot_specat - at_start);
             if (gmx_debug_at)
             {
@@ -573,8 +572,11 @@ int setup_specat_communication(gmx_domdec_t*             dd,
                 fprintf(debug, "\n");
             }
         }
-        fprintf(stderr, "\nDD cell %d %d %d: Neighboring cells do not have atoms:", dd->ci[XX],
-                dd->ci[YY], dd->ci[ZZ]);
+        fprintf(stderr,
+                "\nDD cell %d %d %d: Neighboring cells do not have atoms:",
+                dd->ci[XX],
+                dd->ci[YY],
+                dd->ci[ZZ]);
         for (int i = 0; i < numRequested; i++)
         {
             if (!ga2la_specat->find((*ireq)[i]))
@@ -588,8 +590,15 @@ int setup_specat_communication(gmx_domdec_t*             dd,
                   "%ss from the neighboring cells. This probably means your %s lengths are too "
                   "long compared to the domain decomposition cell size. Decrease the number of "
                   "domain decomposition grid cells%s%s.",
-                  dd->ci[XX], dd->ci[YY], dd->ci[ZZ], nrecv_local, numRequested, specat_type,
-                  specat_type, add_err, dd_dlb_is_on(dd) ? " or use the -rcon option of mdrun" : "");
+                  dd->ci[XX],
+                  dd->ci[YY],
+                  dd->ci[ZZ],
+                  nrecv_local,
+                  numRequested,
+                  specat_type,
+                  specat_type,
+                  add_err,
+                  dd_dlb_is_on(dd) ? " or use the -rcon option of mdrun" : "");
     }
 
     spac->at_start = at_start;
index db67680fb1465e67889d9f6ce471a3dba34668af..e4e2c784cece6581e1d5fb129dd3c6e6bd1c4e98 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,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +53,6 @@
 
 #include "gromacs/math/vectypes.h"
 #include "gromacs/topology/block.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/gmxmpi.h"
 #include "gromacs/utility/range.h"
 #include "gromacs/utility/real.h"
@@ -69,8 +68,10 @@ struct gmx_domdec_constraints_t;
 struct gmx_domdec_specat_comm_t;
 class gmx_ga2la_t;
 struct gmx_pme_comm_n_box_t;
-struct gmx_reverse_top_t;
 struct t_inputrec;
+struct gmx_reverse_top_t;
+struct gmx_mtop_t;
+struct ReverseTopOptions;
 
 namespace gmx
 {
@@ -116,13 +117,13 @@ struct gmx_domdec_zones_t
     /* The number of zones including the home zone */
     int n = 0;
     /* The shift of the zones with respect to the home zone */
-    ivec shift[DD_MAXZONE] = {};
+    std::array<ivec, DD_MAXZONE> shift;
     /* The charge group boundaries for the zones */
-    int cg_range[DD_MAXZONE + 1] = {};
+    std::array<int, DD_MAXZONE + 1> cg_range;
     /* The pair interaction zone and atom ranges per each i-zone */
     std::vector<DDPairInteractionRanges> iZones;
     /* Boundaries of the zones */
-    gmx_domdec_zone_size_t size[DD_MAXZONE];
+    std::array<gmx_domdec_zone_size_t, DD_MAXZONE> size;
     /* The cg density of the home zone */
     real dens_zone0 = 0;
 };
@@ -162,6 +163,7 @@ struct gmx_domdec_t
 { //NOLINT(clang-analyzer-optin.performance.Padding)
     //! Constructor, only partial for now
     gmx_domdec_t(const t_inputrec& ir);
+    ~gmx_domdec_t();
 
     /* The DD particle-particle nodes only */
     /* The communication setup within the communicator all
@@ -197,9 +199,7 @@ struct gmx_domdec_t
     std::unique_ptr<AtomDistribution> ma;
 
     /* Global atom number to interaction list */
-    gmx_reverse_top_t* reverse_top    = nullptr;
-    int                nbonded_global = 0;
-    int                nbonded_local  = 0;
+    std::unique_ptr<gmx_reverse_top_t> reverse_top;
 
     /* Whether we have non-self exclusion */
     bool haveExclusions = false;
index 59815003f13adb6376e5c5adac4cb2fe9f0863b1..3a9f715cf40f11011599982dfeb40facdc0392e4 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2006 - 2014, The GROMACS development team.
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <memory>
+#include <optional>
 #include <string>
 
 #include "gromacs/domdec/domdec.h"
 #include "gromacs/domdec/domdec_network.h"
 #include "gromacs/domdec/ga2la.h"
+#include "gromacs/domdec/options.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/forcerec.h"
@@ -91,6 +93,7 @@
 #include "dump.h"
 
 using gmx::ArrayRef;
+using gmx::DDBondedChecking;
 using gmx::ListOfLists;
 using gmx::RVec;
 
@@ -123,21 +126,42 @@ struct thread_work_t
 
     InteractionDefinitions         idef;               /**< Partial local topology */
     std::unique_ptr<gmx::VsitePbc> vsitePbc = nullptr; /**< vsite PBC structure */
-    int                            nbonded  = 0;       /**< The number of bondeds in this struct */
-    ListOfLists<int>               excl;               /**< List of exclusions */
-    int                            excl_count = 0;     /**< The total exclusion count for \p excl */
+    int              numBondedInteractions  = 0; /**< The number of bonded interactions observed */
+    ListOfLists<int> excl;                       /**< List of exclusions */
 };
 
-/*! \brief Struct for the reverse topology: links bonded interactions to atomsx */
-struct gmx_reverse_top_t
+/*! \brief Options for setting up gmx_reverse_top_t */
+struct ReverseTopOptions
 {
+    //! Constructor, constraints and settles are not including with a single argument
+    ReverseTopOptions(DDBondedChecking ddBondedChecking,
+                      bool             includeConstraints = false,
+                      bool             includeSettles     = false) :
+        ddBondedChecking(ddBondedChecking),
+        includeConstraints(includeConstraints),
+        includeSettles(includeSettles)
+    {
+    }
+
+    //! \brief For which bonded interactions to check assignments
+    const DDBondedChecking ddBondedChecking;
+    //! \brief Whether constraints are stored in this reverse top
+    const bool includeConstraints;
+    //! \brief Whether settles are stored in this reverse top
+    const bool includeSettles;
+};
+
+/*! \brief Struct for the reverse topology: links bonded interactions to atoms */
+struct gmx_reverse_top_t::Impl
+{
+    //! Constructs a reverse topology from \p mtop
+    Impl(const gmx_mtop_t& mtop, bool useFreeEnergy, const ReverseTopOptions& reverseTopOptions);
+
     //! @cond Doxygen_Suppress
-    //! \brief Are there constraints in this revserse top?
-    bool bConstr = false;
-    //! \brief Are there settles in this revserse top?
-    bool bSettle = false;
-    //! \brief All bonded interactions have to be assigned?
-    bool bBCheck = false;
+    //! Options for the setup of this reverse topology
+    const ReverseTopOptions options;
+    //! Are there interaction of type F_POSRES and/or F_FBPOSRES
+    bool havePositionRestraints;
     //! \brief Are there bondeds/exclusions between atoms?
     bool bInterAtomicInteractions = false;
     //! \brief Reverse ilist for all moltypes
@@ -154,18 +178,46 @@ struct gmx_reverse_top_t
     //! \brief Intermolecular reverse ilist
     reverse_ilist_t ril_intermol;
 
+    /*! \brief Data to help check reverse topology construction
+     *
+     * Partitioning could incorrectly miss a bonded interaction.
+     * However, checking for that requires a global communication
+     * stage, which does not otherwise happen during partitioning. So,
+     * for performance, we do that alongside the first global energy
+     * reduction after a new DD is made. These variables handle
+     * whether the check happens, its input for this domain, output
+     * across all domains, and the expected value it should match. */
+    /*! \{ */
+    /*! \brief Number of bonded interactions found in the reverse
+     * topology for this domain. */
+    int numBondedInteractions = 0;
+    /*! \brief Whether to check at the next global communication
+     * stage the total number of bonded interactions found.
+     *
+     * Cleared after that number is found. */
+    bool shouldCheckNumberOfBondedInteractions = false;
+    /*! \brief The total number of bonded interactions found in
+     * the reverse topology across all domains.
+     *
+     * Only has a value after reduction across all ranks, which is
+     * removed when it is again time to check after a new
+     * partition. */
+    std::optional<int> numBondedInteractionsOverAllDomains;
+    //! The number of bonded interactions computed from the full topology
+    int expectedNumGlobalBondedInteractions = 0;
+    /*! \} */
+
     /* Work data structures for multi-threading */
     //! \brief Thread work array for local topology generation
     std::vector<thread_work_t> th_work;
     //! @endcond
 };
 
+
 /*! \brief Returns the number of atom entries for il in gmx_reverse_top_t */
 static int nral_rt(int ftype)
 {
-    int nral;
-
-    nral = NRAL(ftype);
+    int nral = NRAL(ftype);
     if (interaction_function[ftype].flags & IF_VSITE)
     {
         /* With vsites the reverse topology contains an extra entry
@@ -178,12 +230,14 @@ static int nral_rt(int ftype)
 }
 
 /*! \brief Return whether interactions of type \p ftype need to be assigned exactly once */
-static gmx_bool dd_check_ftype(int ftype, gmx_bool bBCheck, gmx_bool bConstr, gmx_bool bSettle)
+static gmx_bool dd_check_ftype(const int ftype, const ReverseTopOptions rtOptions)
 {
     return ((((interaction_function[ftype].flags & IF_BOND) != 0U)
              && ((interaction_function[ftype].flags & IF_VSITE) == 0U)
-             && (bBCheck || ((interaction_function[ftype].flags & IF_LIMZERO) == 0U)))
-            || (bConstr && (ftype == F_CONSTR || ftype == F_CONSTRNC)) || (bSettle && ftype == F_SETTLE));
+             && ((rtOptions.ddBondedChecking == DDBondedChecking::All)
+                 || ((interaction_function[ftype].flags & IF_LIMZERO) == 0U)))
+            || (rtOptions.includeConstraints && (ftype == F_CONSTR || ftype == F_CONSTRNC))
+            || (rtOptions.includeSettles && ftype == F_SETTLE));
 }
 
 /*! \brief Checks whether interactions have been assigned for one function type
@@ -275,10 +329,10 @@ static std::string printMissingInteractionsMolblock(t_commrec*               cr,
 
     for (int ftype = 0; ftype < F_NRE; ftype++)
     {
-        if (dd_check_ftype(ftype, rt.bBCheck, rt.bConstr, rt.bSettle))
+        if (dd_check_ftype(ftype, rt.impl_->options))
         {
-            flagInteractionsForType(ftype, idef.il[ftype], ril, atomRange, numAtomsPerMolecule,
-                                    cr->dd->globalAtomIndices, isAssigned);
+            flagInteractionsForType(
+                    ftype, idef.il[ftype], ril, atomRange, numAtomsPerMolecule, cr->dd->globalAtomIndices, isAssigned);
         }
     }
 
@@ -306,8 +360,8 @@ static std::string printMissingInteractionsMolblock(t_commrec*               cr,
                                 numMissingToPrint);
                     }
                     log.writeStringFormatted("%20s atoms", interaction_function[ftype].longname);
-                    int a;
-                    for (a = 0; a < nral; a++)
+                    int a = 0;
+                    for (; a < nral; a++)
                     {
                         log.writeStringFormatted("%5d", ril.il[j_mol + 2 + a] + 1);
                     }
@@ -317,10 +371,11 @@ static std::string printMissingInteractionsMolblock(t_commrec*               cr,
                         a++;
                     }
                     log.writeString(" global");
-                    for (a = 0; a < nral; a++)
+                    for (int a = 0; a < nral; a++)
                     {
-                        log.writeStringFormatted("%6d", atomRange.begin() + mol * numAtomsPerMolecule
-                                                                + ril.il[j_mol + 2 + a] + 1);
+                        log.writeStringFormatted("%6d",
+                                                 atomRange.begin() + mol * numAtomsPerMolecule
+                                                         + ril.il[j_mol + 2 + a] + 1);
                     }
                     log.ensureLineBreak();
                 }
@@ -354,38 +409,36 @@ static void printMissingInteractionsAtoms(const gmx::MDLogger&          mdlog,
         a_end                        = a_start + molb.nmol * moltype.atoms.nr;
         const gmx::Range<int> atomRange(a_start, a_end);
 
-        auto warning = printMissingInteractionsMolblock(cr, rt, *(moltype.name), rt.ril_mt[molb.type],
-                                                        atomRange, moltype.atoms.nr, molb.nmol, idef);
+        auto warning = printMissingInteractionsMolblock(
+                cr, rt, *(moltype.name), rt.impl_->ril_mt[molb.type], atomRange, moltype.atoms.nr, molb.nmol, idef);
 
         GMX_LOG(mdlog.warning).appendText(warning);
     }
 }
 
-void dd_print_missing_interactions(const gmx::MDLogger&           mdlog,
-                                   t_commrec*                     cr,
-                                   int                            local_count,
-                                   const gmx_mtop_t*              top_global,
-                                   const gmx_localtop_t*          top_local,
+void dd_print_missing_interactions(const gmx::MDLogger&  mdlog,
+                                   t_commrec*            cr,
+                                   int                   numBondedInteractionsOverAllDomains,
+                                   const gmx_mtop_t&     top_global,
+                                   const gmx_localtop_t* top_local,
                                    gmx::ArrayRef<const gmx::RVec> x,
                                    const matrix                   box)
 {
-    int           ndiff_tot, cl[F_NRE], n, ndiff, rest_global, rest_local;
-    int           ftype, nral;
-    gmx_domdec_t* dd;
-
-    dd = cr->dd;
+    int           cl[F_NRE];
+    gmx_domdec_t* dd = cr->dd;
 
     GMX_LOG(mdlog.warning)
             .appendText(
                     "Not all bonded interactions have been properly assigned to the domain "
                     "decomposition cells");
 
-    ndiff_tot = local_count - dd->nbonded_global;
+    const int ndiff_tot = numBondedInteractionsOverAllDomains
+                          - dd->reverse_top->impl_->expectedNumGlobalBondedInteractions;
 
-    for (ftype = 0; ftype < F_NRE; ftype++)
+    for (int ftype = 0; ftype < F_NRE; ftype++)
     {
-        nral      = NRAL(ftype);
-        cl[ftype] = top_local->idef.il[ftype].size() / (1 + nral);
+        const int nral = NRAL(ftype);
+        cl[ftype]      = top_local->idef.il[ftype].size() / (1 + nral);
     }
 
     gmx_sumi(F_NRE, cl, cr);
@@ -393,44 +446,43 @@ void dd_print_missing_interactions(const gmx::MDLogger&           mdlog,
     if (DDMASTER(dd))
     {
         GMX_LOG(mdlog.warning).appendText("A list of missing interactions:");
-        rest_global = dd->nbonded_global;
-        rest_local  = local_count;
-        for (ftype = 0; ftype < F_NRE; ftype++)
+        int rest_global = dd->reverse_top->impl_->expectedNumGlobalBondedInteractions;
+        int rest        = numBondedInteractionsOverAllDomains;
+        for (int ftype = 0; ftype < F_NRE; ftype++)
         {
             /* In the reverse and local top all constraints are merged
              * into F_CONSTR. So in the if statement we skip F_CONSTRNC
              * and add these constraints when doing F_CONSTR.
              */
-            if (((interaction_function[ftype].flags & IF_BOND)
-                 && (dd->reverse_top->bBCheck || !(interaction_function[ftype].flags & IF_LIMZERO)))
-                || (dd->reverse_top->bConstr && ftype == F_CONSTR)
-                || (dd->reverse_top->bSettle && ftype == F_SETTLE))
+            if (dd_check_ftype(ftype, dd->reverse_top->impl_->options) && ftype != F_CONSTRNC)
             {
-                n = gmx_mtop_ftype_count(top_global, ftype);
+                int n = gmx_mtop_ftype_count(top_global, ftype);
                 if (ftype == F_CONSTR)
                 {
                     n += gmx_mtop_ftype_count(top_global, F_CONSTRNC);
                 }
-                ndiff = cl[ftype] - n;
+                int ndiff = cl[ftype] - n;
                 if (ndiff != 0)
                 {
                     GMX_LOG(mdlog.warning)
                             .appendTextFormatted("%20s of %6d missing %6d",
-                                                 interaction_function[ftype].longname, n, -ndiff);
+                                                 interaction_function[ftype].longname,
+                                                 n,
+                                                 -ndiff);
                 }
                 rest_global -= n;
-                rest_local -= cl[ftype];
+                rest -= cl[ftype];
             }
         }
 
-        ndiff = rest_local - rest_global;
+        int ndiff = rest - rest_global;
         if (ndiff != 0)
         {
             GMX_LOG(mdlog.warning).appendTextFormatted("%20s of %6d missing %6d", "exclusions", rest_global, -ndiff);
         }
     }
 
-    printMissingInteractionsAtoms(mdlog, cr, *top_global, top_local->idef);
+    printMissingInteractionsAtoms(mdlog, cr, top_global, top_local->idef);
     write_dd_pdb("dd_dump_err", 0, "dump", top_global, cr, -1, as_rvec_array(x.data()), box);
 
     std::string errorMessage;
@@ -448,18 +500,26 @@ void dd_print_missing_interactions(const gmx::MDLogger&           mdlog,
                 "involved moved further apart than the multi-body cut-off distance (%g nm) or the "
                 "two-body cut-off distance (%g nm), see option -rdd, for pairs and tabulated bonds "
                 "also see option -ddcheck",
-                -ndiff_tot, cr->dd->nbonded_global, dd_cutoff_multibody(dd), dd_cutoff_twobody(dd));
+                -ndiff_tot,
+                dd->reverse_top->impl_->expectedNumGlobalBondedInteractions,
+                dd_cutoff_multibody(dd),
+                dd_cutoff_twobody(dd));
     }
     gmx_fatal_collective(FARGS, cr->mpi_comm_mygroup, MASTER(cr), "%s", errorMessage.c_str());
 }
 
 /*! \brief Return global topology molecule information for global atom index \p i_gl */
-static void global_atomnr_to_moltype_ind(const gmx_reverse_top_t* rt, int i_gl, int* mb, int* mt, int* mol, int* i_mol)
+static void global_atomnr_to_moltype_ind(ArrayRef<const MolblockIndices> molblockIndices,
+                                         int                             i_gl,
+                                         int*                            mb,
+                                         int*                            mt,
+                                         int*                            mol,
+                                         int*                            i_mol)
 {
-    const MolblockIndices* mbi   = rt->mbi.data();
+    const MolblockIndices* mbi   = molblockIndices.data();
     int                    start = 0;
-    int                    end   = rt->mbi.size(); /* exclusive */
-    int                    mid;
+    int                    end   = molblockIndices.size(); /* exclusive */
+    int                    mid   = 0;
 
     /* binary search for molblock_ind */
     while (TRUE)
@@ -505,61 +565,53 @@ static int getMaxNumExclusionsPerAtom(const ListOfLists<int>& excls)
     return maxNumExcls;
 }
 
+//! Options for linking atoms in make_reverse_ilist
+enum class AtomLinkRule
+{
+    FirstAtom,        //!< Link all interactions to the first atom in the atom list
+    AllAtomsInBondeds //!< Link bonded interactions to all atoms involved, don't link vsites
+};
+
 /*! \brief Run the reverse ilist generation and store it in r_il when \p bAssign = TRUE */
 static int low_make_reverse_ilist(const InteractionLists&  il_mt,
                                   const t_atom*            atom,
                                   int*                     count,
-                                  gmx_bool                 bConstr,
-                                  gmx_bool                 bSettle,
-                                  gmx_bool                 bBCheck,
+                                  const ReverseTopOptions& rtOptions,
                                   gmx::ArrayRef<const int> r_index,
                                   gmx::ArrayRef<int>       r_il,
-                                  gmx_bool                 bLinkToAllAtoms,
-                                  gmx_bool                 bAssign)
+                                  const AtomLinkRule       atomLinkRule,
+                                  const bool               assignReverseIlist)
 {
-    int ftype, j, nlink, link;
-    int a;
-    int nint;
+    const bool             includeConstraints = rtOptions.includeConstraints;
+    const bool             includeSettles     = rtOptions.includeSettles;
+    const DDBondedChecking ddBondedChecking   = rtOptions.ddBondedChecking;
+
+    int nint = 0;
 
-    nint = 0;
-    for (ftype = 0; ftype < F_NRE; ftype++)
+    for (int ftype = 0; ftype < F_NRE; ftype++)
     {
         if ((interaction_function[ftype].flags & (IF_BOND | IF_VSITE))
-            || (bConstr && (ftype == F_CONSTR || ftype == F_CONSTRNC)) || (bSettle && ftype == F_SETTLE))
+            || (includeConstraints && (ftype == F_CONSTR || ftype == F_CONSTRNC))
+            || (includeSettles && ftype == F_SETTLE))
         {
-            const bool  bVSite = ((interaction_function[ftype].flags & IF_VSITE) != 0U);
-            const int   nral   = NRAL(ftype);
-            const auto& il     = il_mt[ftype];
+            const bool  isVSite = ((interaction_function[ftype].flags & IF_VSITE) != 0U);
+            const int   nral    = NRAL(ftype);
+            const auto& il      = il_mt[ftype];
             for (int i = 0; i < il.size(); i += 1 + nral)
             {
                 const int* ia = il.iatoms.data() + i;
-                if (bLinkToAllAtoms)
+                // Virtual sites should not be linked for bonded interactions
+                const int nlink = (atomLinkRule == AtomLinkRule::FirstAtom) ? 1 : (isVSite ? 0 : nral);
+                for (int link = 0; link < nlink; link++)
                 {
-                    if (bVSite)
-                    {
-                        /* We don't need the virtual sites for the cg-links */
-                        nlink = 0;
-                    }
-                    else
-                    {
-                        nlink = nral;
-                    }
-                }
-                else
-                {
-                    /* Couple to the first atom in the interaction */
-                    nlink = 1;
-                }
-                for (link = 0; link < nlink; link++)
-                {
-                    a = ia[1 + link];
-                    if (bAssign)
+                    const int a = ia[1 + link];
+                    if (assignReverseIlist)
                     {
                         GMX_ASSERT(!r_il.empty(), "with bAssign not allowed to be empty");
                         GMX_ASSERT(!r_index.empty(), "with bAssign not allowed to be empty");
                         r_il[r_index[a] + count[a]]     = (ftype == F_CONSTRNC ? F_CONSTR : ftype);
                         r_il[r_index[a] + count[a] + 1] = ia[0];
-                        for (j = 1; j < 1 + nral; j++)
+                        for (int j = 1; j < 1 + nral; j++)
                         {
                             /* Store the molecular atom number */
                             r_il[r_index[a] + count[a] + 1 + j] = ia[j];
@@ -567,16 +619,16 @@ static int low_make_reverse_ilist(const InteractionLists&  il_mt,
                     }
                     if (interaction_function[ftype].flags & IF_VSITE)
                     {
-                        if (bAssign)
+                        if (assignReverseIlist)
                         {
                             /* Add an entry to iatoms for storing
                              * which of the constructing atoms are
                              * vsites again.
                              */
                             r_il[r_index[a] + count[a] + 2 + nral] = 0;
-                            for (j = 2; j < 1 + nral; j++)
+                            for (int j = 2; j < 1 + nral; j++)
                             {
-                                if (atom[ia[j]].ptype == eptVSite)
+                                if (atom[ia[j]].ptype == ParticleType::VSite)
                                 {
                                     r_il[r_index[a] + count[a] + 2 + nral] |= (2 << j);
                                 }
@@ -589,7 +641,8 @@ static int low_make_reverse_ilist(const InteractionLists&  il_mt,
                          * uniquely assigned and can be assigned
                          * to multiple nodes with recursive vsites.
                          */
-                        if (bBCheck || !(interaction_function[ftype].flags & IF_LIMZERO))
+                        if (ddBondedChecking == DDBondedChecking::All
+                            || !(interaction_function[ftype].flags & IF_LIMZERO))
                         {
                             nint++;
                         }
@@ -604,24 +657,19 @@ static int low_make_reverse_ilist(const InteractionLists&  il_mt,
 }
 
 /*! \brief Make the reverse ilist: a list of bonded interactions linked to atoms */
-static int make_reverse_ilist(const InteractionLists& ilist,
-                              const t_atoms*          atoms,
-                              gmx_bool                bConstr,
-                              gmx_bool                bSettle,
-                              gmx_bool                bBCheck,
-                              gmx_bool                bLinkToAllAtoms,
-                              reverse_ilist_t*        ril_mt)
+static int make_reverse_ilist(const InteractionLists&  ilist,
+                              const t_atoms*           atoms,
+                              const ReverseTopOptions& rtOptions,
+                              const AtomLinkRule       atomLinkRule,
+                              reverse_ilist_t*         ril_mt)
 {
-    int nat_mt, *count, i, nint_mt;
-
     /* Count the interactions */
-    nat_mt = atoms->nr;
-    snew(count, nat_mt);
-    low_make_reverse_ilist(ilist, atoms->atom, count, bConstr, bSettle, bBCheck, {}, {},
-                           bLinkToAllAtoms, FALSE);
+    const int        nat_mt = atoms->nr;
+    std::vector<int> count(nat_mt);
+    low_make_reverse_ilist(ilist, atoms->atom, count.data(), rtOptions, {}, {}, atomLinkRule, FALSE);
 
     ril_mt->index.push_back(0);
-    for (i = 0; i < nat_mt; i++)
+    for (int i = 0; i < nat_mt; i++)
     {
         ril_mt->index.push_back(ril_mt->index[i] + count[i]);
         count[i] = 0;
@@ -629,116 +677,114 @@ static int make_reverse_ilist(const InteractionLists& ilist,
     ril_mt->il.resize(ril_mt->index[nat_mt]);
 
     /* Store the interactions */
-    nint_mt = low_make_reverse_ilist(ilist, atoms->atom, count, bConstr, bSettle, bBCheck,
-                                     ril_mt->index, ril_mt->il, bLinkToAllAtoms, TRUE);
-
-    sfree(count);
+    int nint_mt = low_make_reverse_ilist(
+            ilist, atoms->atom, count.data(), rtOptions, ril_mt->index, ril_mt->il, atomLinkRule, TRUE);
 
     ril_mt->numAtomsInMolecule = atoms->nr;
 
     return nint_mt;
 }
 
-/*! \brief Generate the reverse topology */
-static gmx_reverse_top_t make_reverse_top(const gmx_mtop_t* mtop,
-                                          gmx_bool          bFE,
-                                          gmx_bool          bConstr,
-                                          gmx_bool          bSettle,
-                                          gmx_bool          bBCheck,
-                                          int*              nint)
+gmx_reverse_top_t::gmx_reverse_top_t(const gmx_mtop_t&        mtop,
+                                     bool                     useFreeEnergy,
+                                     const ReverseTopOptions& reverseTopOptions) :
+    impl_(std::make_unique<Impl>(mtop, useFreeEnergy, reverseTopOptions))
 {
-    gmx_reverse_top_t rt;
+}
 
-    /* Should we include constraints (for SHAKE) in rt? */
-    rt.bConstr = bConstr;
-    rt.bSettle = bSettle;
-    rt.bBCheck = bBCheck;
+gmx_reverse_top_t::~gmx_reverse_top_t() {}
 
-    rt.bInterAtomicInteractions = mtop->bIntermolecularInteractions;
-    rt.ril_mt.resize(mtop->moltype.size());
-    rt.ril_mt_tot_size = 0;
+/*! \brief Generate the reverse topology */
+gmx_reverse_top_t::Impl::Impl(const gmx_mtop_t&        mtop,
+                              const bool               useFreeEnergy,
+                              const ReverseTopOptions& reverseTopOptions) :
+    options(reverseTopOptions),
+    havePositionRestraints(
+            gmx_mtop_ftype_count(mtop, F_POSRES) + gmx_mtop_ftype_count(mtop, F_FBPOSRES) > 0),
+    bInterAtomicInteractions(mtop.bIntermolecularInteractions)
+{
+    bInterAtomicInteractions = mtop.bIntermolecularInteractions;
+    ril_mt.resize(mtop.moltype.size());
+    ril_mt_tot_size = 0;
     std::vector<int> nint_mt;
-    for (size_t mt = 0; mt < mtop->moltype.size(); mt++)
+    for (size_t mt = 0; mt < mtop.moltype.size(); mt++)
     {
-        const gmx_moltype_t& molt = mtop->moltype[mt];
+        const gmx_moltype_t& molt = mtop.moltype[mt];
         if (molt.atoms.nr > 1)
         {
-            rt.bInterAtomicInteractions = true;
+            bInterAtomicInteractions = true;
         }
 
         /* Make the atom to interaction list for this molecule type */
         int numberOfInteractions = make_reverse_ilist(
-                molt.ilist, &molt.atoms, rt.bConstr, rt.bSettle, rt.bBCheck, FALSE, &rt.ril_mt[mt]);
+                molt.ilist, &molt.atoms, options, AtomLinkRule::FirstAtom, &ril_mt[mt]);
         nint_mt.push_back(numberOfInteractions);
 
-        rt.ril_mt_tot_size += rt.ril_mt[mt].index[molt.atoms.nr];
+        ril_mt_tot_size += ril_mt[mt].index[molt.atoms.nr];
     }
     if (debug)
     {
-        fprintf(debug, "The total size of the atom to interaction index is %d integers\n",
-                rt.ril_mt_tot_size);
+        fprintf(debug, "The total size of the atom to interaction index is %d integers\n", ril_mt_tot_size);
     }
 
-    *nint = 0;
-    for (const gmx_molblock_t& molblock : mtop->molblock)
+    expectedNumGlobalBondedInteractions = 0;
+    for (const gmx_molblock_t& molblock : mtop.molblock)
     {
-        *nint += molblock.nmol * nint_mt[molblock.type];
+        expectedNumGlobalBondedInteractions += molblock.nmol * nint_mt[molblock.type];
     }
 
     /* Make an intermolecular reverse top, if necessary */
-    rt.bIntermolecularInteractions = mtop->bIntermolecularInteractions;
-    if (rt.bIntermolecularInteractions)
+    bIntermolecularInteractions = mtop.bIntermolecularInteractions;
+    if (bIntermolecularInteractions)
     {
         t_atoms atoms_global;
 
-        atoms_global.nr   = mtop->natoms;
+        atoms_global.nr   = mtop.natoms;
         atoms_global.atom = nullptr; /* Only used with virtual sites */
 
-        GMX_RELEASE_ASSERT(mtop->intermolecular_ilist,
+        GMX_RELEASE_ASSERT(mtop.intermolecular_ilist,
                            "We should have an ilist when intermolecular interactions are on");
 
-        *nint += make_reverse_ilist(*mtop->intermolecular_ilist, &atoms_global, rt.bConstr,
-                                    rt.bSettle, rt.bBCheck, FALSE, &rt.ril_intermol);
+        expectedNumGlobalBondedInteractions += make_reverse_ilist(
+                *mtop.intermolecular_ilist, &atoms_global, options, AtomLinkRule::FirstAtom, &ril_intermol);
     }
 
-    if (bFE && gmx_mtop_bondeds_free_energy(mtop))
+    if (useFreeEnergy && gmx_mtop_bondeds_free_energy(&mtop))
     {
-        rt.ilsort = ilsortFE_UNSORTED;
+        ilsort = ilsortFE_UNSORTED;
     }
     else
     {
-        rt.ilsort = ilsortNO_FE;
+        ilsort = ilsortNO_FE;
     }
 
     /* Make a molblock index for fast searching */
     int i = 0;
-    for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
+    for (size_t mb = 0; mb < mtop.molblock.size(); mb++)
     {
-        const gmx_molblock_t& molb           = mtop->molblock[mb];
-        const int             numAtomsPerMol = mtop->moltype[molb.type].atoms.nr;
-        MolblockIndices       mbi;
-        mbi.a_start = i;
+        const gmx_molblock_t& molb           = mtop.molblock[mb];
+        const int             numAtomsPerMol = mtop.moltype[molb.type].atoms.nr;
+        MolblockIndices       mbiMolblock;
+        mbiMolblock.a_start = i;
         i += molb.nmol * numAtomsPerMol;
-        mbi.a_end      = i;
-        mbi.natoms_mol = numAtomsPerMol;
-        mbi.type       = molb.type;
-        rt.mbi.push_back(mbi);
+        mbiMolblock.a_end      = i;
+        mbiMolblock.natoms_mol = numAtomsPerMol;
+        mbiMolblock.type       = molb.type;
+        mbi.push_back(mbiMolblock);
     }
 
-    for (int th = 0; th < gmx_omp_nthreads_get(emntDomdec); th++)
+    for (int th = 0; th < gmx_omp_nthreads_get(ModuleMultiThread::Domdec); th++)
     {
-        rt.th_work.emplace_back(mtop->ffparams);
+        th_work.emplace_back(mtop.ffparams);
     }
-
-    return rt;
 }
 
 void dd_make_reverse_top(FILE*                           fplog,
                          gmx_domdec_t*                   dd,
-                         const gmx_mtop_t*               mtop,
+                         const gmx_mtop_t&               mtop,
                          const gmx::VirtualSitesHandler* vsite,
-                         const t_inputrec*               ir,
-                         gmx_bool                        bBCheck)
+                         const t_inputrec&               inputrec,
+                         const DDBondedChecking          ddBondedChecking)
 {
     if (fplog)
     {
@@ -750,16 +796,20 @@ void dd_make_reverse_top(FILE*                           fplog,
      * Otherwise we need to assign them to multiple domains and set up
      * the parallel version constraint algorithm(s).
      */
+    GMX_RELEASE_ASSERT(ddBondedChecking == DDBondedChecking::ExcludeZeroLimit
+                               || ddBondedChecking == DDBondedChecking::All,
+                       "Invalid enum value for mdrun -ddcheck");
+    const ReverseTopOptions rtOptions(ddBondedChecking,
+                                      !dd->comm->systemInfo.mayHaveSplitConstraints,
+                                      !dd->comm->systemInfo.mayHaveSplitSettles);
 
-    dd->reverse_top = new gmx_reverse_top_t;
-    *dd->reverse_top =
-            make_reverse_top(mtop, ir->efep != efepNO, !dd->comm->systemInfo.haveSplitConstraints,
-                             !dd->comm->systemInfo.haveSplitSettles, bBCheck, &dd->nbonded_global);
+    dd->reverse_top = std::make_unique<gmx_reverse_top_t>(
+            mtop, inputrec.efep != FreeEnergyPerturbationType::No, rtOptions);
 
     dd->haveExclusions = false;
-    for (const gmx_molblock_t& molb : mtop->molblock)
+    for (const gmx_molblock_t& molb : mtop.molblock)
     {
-        const int maxNumExclusionsPerAtom = getMaxNumExclusionsPerAtom(mtop->moltype[molb.type].excls);
+        const int maxNumExclusionsPerAtom = getMaxNumExclusionsPerAtom(mtop.moltype[molb.type].excls);
         // We checked above that max 1 exclusion means only self exclusions
         if (maxNumExclusionsPerAtom > 1)
         {
@@ -767,19 +817,22 @@ void dd_make_reverse_top(FILE*                           fplog,
         }
     }
 
-    if (vsite && vsite->numInterUpdategroupVirtualSites() > 0)
+    const int numInterUpdategroupVirtualSites =
+            (vsite == nullptr ? 0 : vsite->numInterUpdategroupVirtualSites());
+    if (numInterUpdategroupVirtualSites > 0)
     {
         if (fplog)
         {
             fprintf(fplog,
                     "There are %d inter update-group virtual sites,\n"
-                    "will an extra communication step for selected coordinates and forces\n",
-                    vsite->numInterUpdategroupVirtualSites());
+                    "will perform an extra communication step for selected coordinates and "
+                    "forces\n",
+                    numInterUpdategroupVirtualSites);
         }
-        init_domdec_vsites(dd, vsite->numInterUpdategroupVirtualSites());
+        init_domdec_vsites(dd, numInterUpdategroupVirtualSites);
     }
 
-    if (dd->comm->systemInfo.haveSplitConstraints || dd->comm->systemInfo.haveSplitSettles)
+    if (dd->comm->systemInfo.mayHaveSplitConstraints || dd->comm->systemInfo.mayHaveSplitSettles)
     {
         init_domdec_constraints(dd, mtop);
     }
@@ -844,8 +897,8 @@ static inline void add_ifunc_for_vsites(t_iatom*           tiatoms,
 static void add_posres(int                     mol,
                        int                     a_mol,
                        int                     numAtomsInMolecule,
-                       const gmx_molblock_t*   molb,
-                       t_iatom*                iatoms,
+                       const gmx_molblock_t&   molb,
+                       gmx::ArrayRef<int>      iatoms,
                        const t_iparams*        ip_in,
                        InteractionDefinitions* idef)
 {
@@ -856,18 +909,18 @@ static void add_posres(int                     mol,
 
     /* Get the position restraint coordinates from the molblock */
     const int a_molb = mol * numAtomsInMolecule + a_mol;
-    GMX_ASSERT(a_molb < ssize(molb->posres_xA),
+    GMX_ASSERT(a_molb < ssize(molb.posres_xA),
                "We need a sufficient number of position restraint coordinates");
     /* Copy the force constants */
     t_iparams ip        = ip_in[iatoms[0]];
-    ip.posres.pos0A[XX] = molb->posres_xA[a_molb][XX];
-    ip.posres.pos0A[YY] = molb->posres_xA[a_molb][YY];
-    ip.posres.pos0A[ZZ] = molb->posres_xA[a_molb][ZZ];
-    if (!molb->posres_xB.empty())
+    ip.posres.pos0A[XX] = molb.posres_xA[a_molb][XX];
+    ip.posres.pos0A[YY] = molb.posres_xA[a_molb][YY];
+    ip.posres.pos0A[ZZ] = molb.posres_xA[a_molb][ZZ];
+    if (!molb.posres_xB.empty())
     {
-        ip.posres.pos0B[XX] = molb->posres_xB[a_molb][XX];
-        ip.posres.pos0B[YY] = molb->posres_xB[a_molb][YY];
-        ip.posres.pos0B[ZZ] = molb->posres_xB[a_molb][ZZ];
+        ip.posres.pos0B[XX] = molb.posres_xB[a_molb][XX];
+        ip.posres.pos0B[YY] = molb.posres_xB[a_molb][YY];
+        ip.posres.pos0B[ZZ] = molb.posres_xB[a_molb][ZZ];
     }
     else
     {
@@ -887,8 +940,8 @@ static void add_posres(int                     mol,
 static void add_fbposres(int                     mol,
                          int                     a_mol,
                          int                     numAtomsInMolecule,
-                         const gmx_molblock_t*   molb,
-                         t_iatom*                iatoms,
+                         const gmx_molblock_t&   molb,
+                         gmx::ArrayRef<int>      iatoms,
                          const t_iparams*        ip_in,
                          InteractionDefinitions* idef)
 {
@@ -899,14 +952,14 @@ static void add_fbposres(int                     mol,
 
     /* Get the position restraint coordinats from the molblock */
     const int a_molb = mol * numAtomsInMolecule + a_mol;
-    GMX_ASSERT(a_molb < ssize(molb->posres_xA),
+    GMX_ASSERT(a_molb < ssize(molb.posres_xA),
                "We need a sufficient number of position restraint coordinates");
     /* Copy the force constants */
     t_iparams ip = ip_in[iatoms[0]];
     /* Take reference positions from A position of normal posres */
-    ip.fbposres.pos0[XX] = molb->posres_xA[a_molb][XX];
-    ip.fbposres.pos0[YY] = molb->posres_xA[a_molb][YY];
-    ip.fbposres.pos0[ZZ] = molb->posres_xA[a_molb][ZZ];
+    ip.fbposres.pos0[XX] = molb.posres_xA[a_molb][XX];
+    ip.fbposres.pos0[YY] = molb.posres_xA[a_molb][YY];
+    ip.fbposres.pos0[ZZ] = molb.posres_xA[a_molb][ZZ];
 
     /* Note: no B-type for flat-bottom posres */
 
@@ -931,9 +984,7 @@ static void add_vsite(const gmx_ga2la_t&       ga2la,
                       const t_iatom*           iatoms,
                       InteractionDefinitions*  idef)
 {
-    int     k;
     t_iatom tiatoms[1 + MAXATOMLIST];
-    int     j, ftype_r, nral_r;
 
     /* Add this interaction to the local topology */
     add_ifunc_for_vsites(tiatoms, ga2la, nral, bHomeA, a, a_gl, a_mol, iatoms, &idef->il[ftype]);
@@ -941,29 +992,40 @@ static void add_vsite(const gmx_ga2la_t&       ga2la,
     if (iatoms[1 + nral])
     {
         /* Check for recursion */
-        for (k = 2; k < 1 + nral; k++)
+        for (int k = 2; k < 1 + nral; k++)
         {
             if ((iatoms[1 + nral] & (2 << k)) && (tiatoms[k] < 0))
             {
                 /* This construction atoms is a vsite and not a home atom */
                 if (gmx_debug_at)
                 {
-                    fprintf(debug, "Constructing atom %d of vsite atom %d is a vsite and non-home\n",
-                            iatoms[k] + 1, a_mol + 1);
+                    fprintf(debug,
+                            "Constructing atom %d of vsite atom %d is a vsite and non-home\n",
+                            iatoms[k] + 1,
+                            a_mol + 1);
                 }
                 /* Find the vsite construction */
 
                 /* Check all interactions assigned to this atom */
-                j = index[iatoms[k]];
+                int j = index[iatoms[k]];
                 while (j < index[iatoms[k] + 1])
                 {
-                    ftype_r = rtil[j++];
-                    nral_r  = NRAL(ftype_r);
+                    int ftype_r = rtil[j++];
+                    int nral_r  = NRAL(ftype_r);
                     if (interaction_function[ftype_r].flags & IF_VSITE)
                     {
                         /* Add this vsite (recursion) */
-                        add_vsite(ga2la, index, rtil, ftype_r, nral_r, FALSE, -1,
-                                  a_gl + iatoms[k] - iatoms[1], iatoms[k], rtil.data() + j, idef);
+                        add_vsite(ga2la,
+                                  index,
+                                  rtil,
+                                  ftype_r,
+                                  nral_r,
+                                  FALSE,
+                                  -1,
+                                  a_gl + iatoms[k] - iatoms[1],
+                                  iatoms[k],
+                                  rtil.data() + j,
+                                  idef);
                     }
                     j += 1 + nral_rt(ftype_r);
                 }
@@ -973,17 +1035,17 @@ static void add_vsite(const gmx_ga2la_t&       ga2la,
 }
 
 /*! \brief Returns the squared distance between atoms \p i and \p j */
-static real dd_dist2(t_pbc* pbc_null, const rvec* x, const int i, int j)
+static real dd_dist2(const t_pbc* pbc_null, ArrayRef<const RVec> coordinates, const int i, const int j)
 {
     rvec dx;
 
     if (pbc_null)
     {
-        pbc_dx_aiuc(pbc_null, x[i], x[j], dx);
+        pbc_dx_aiuc(pbc_null, coordinates[i], coordinates[j], dx);
     }
     else
     {
-        rvec_sub(x[i], x[j], dx);
+        rvec_sub(coordinates[i], coordinates[j], dx);
     }
 
     return norm2(dx);
@@ -992,9 +1054,7 @@ static real dd_dist2(t_pbc* pbc_null, const rvec* x, const int i, int j)
 /*! \brief Append t_idef structures 1 to nsrc in src to *dest */
 static void combine_idef(InteractionDefinitions* dest, gmx::ArrayRef<const thread_work_t> src)
 {
-    int ftype;
-
-    for (ftype = 0; ftype < F_NRE; ftype++)
+    for (int ftype = 0; ftype < F_NRE; ftype++)
     {
         int n = 0;
         for (gmx::index s = 1; s < src.ssize(); s++)
@@ -1043,35 +1103,44 @@ static void combine_idef(InteractionDefinitions* dest, gmx::ArrayRef<const threa
     }
 }
 
-/*! \brief Check and when available assign bonded interactions for local atom i
+//! Options for assigning interactions for atoms
+enum class InteractionConnectivity
+{
+    Intramolecular, //!< Only intra-molecular interactions
+    Intermolecular  //!< Only inter-molecular interactions
+};
+
+/*! \brief Determine whether the local domain has responsibility for
+ * any of the bonded interactions for local atom \p atomIndex
+ * and assign those to the local domain.
+ *
+ * \returns The total number of bonded interactions for this atom for
+ * which this domain is responsible.
  */
-static inline void check_assign_interactions_atom(int                       i,
-                                                  int                       i_gl,
-                                                  int                       mol,
-                                                  int                       i_mol,
-                                                  int                       numAtomsInMolecule,
-                                                  gmx::ArrayRef<const int>  index,
-                                                  gmx::ArrayRef<const int>  rtil,
-                                                  gmx_bool                  bInterMolInteractions,
-                                                  int                       ind_start,
-                                                  int                       ind_end,
-                                                  const gmx_domdec_t*       dd,
-                                                  const gmx_domdec_zones_t* zones,
-                                                  const gmx_molblock_t*     molb,
-                                                  gmx_bool                  bRCheckMB,
-                                                  const ivec                rcheck,
-                                                  gmx_bool                  bRCheck2B,
-                                                  real                      rc2,
-                                                  t_pbc*                    pbc_null,
-                                                  rvec*                     cg_cm,
-                                                  const t_iparams*          ip_in,
-                                                  InteractionDefinitions*   idef,
-                                                  int                       iz,
-                                                  gmx_bool                  bBCheck,
-                                                  int*                      nbonded_local)
+template<InteractionConnectivity interactionConnectivity>
+static inline int assignInteractionsForAtom(const int                 atomIndex,
+                                            const int                 globalAtomIndex,
+                                            const int                 atomIndexInMolecule,
+                                            gmx::ArrayRef<const int>  index,
+                                            gmx::ArrayRef<const int>  rtil,
+                                            const int                 ind_start,
+                                            const int                 ind_end,
+                                            const gmx_ga2la_t&        ga2la,
+                                            const gmx_domdec_zones_t* zones,
+                                            const bool                checkDistanceMultiBody,
+                                            const ivec                rcheck,
+                                            const bool                checkDistanceTwoBody,
+                                            const real                cutoffSquared,
+                                            const t_pbc*              pbc_null,
+                                            ArrayRef<const RVec>      coordinates,
+                                            InteractionDefinitions*   idef,
+                                            const int                 iz,
+                                            const DDBondedChecking    ddBondedChecking)
 {
     gmx::ArrayRef<const DDPairInteractionRanges> iZones = zones->iZones;
 
+    int numBondedInteractions = 0;
+
     int j = ind_start;
     while (j < ind_end)
     {
@@ -1082,40 +1151,44 @@ static inline void check_assign_interactions_atom(int                       i,
         const int nral   = NRAL(ftype);
         if (interaction_function[ftype].flags & IF_VSITE)
         {
-            assert(!bInterMolInteractions);
+            GMX_ASSERT(interactionConnectivity == InteractionConnectivity::Intramolecular,
+                       "All vsites should be intramolecular");
+
             /* The vsite construction goes where the vsite itself is */
             if (iz == 0)
             {
-                add_vsite(*dd->ga2la, index, rtil, ftype, nral, TRUE, i, i_gl, i_mol, iatoms.data(), idef);
+                add_vsite(ga2la,
+                          index,
+                          rtil,
+                          ftype,
+                          nral,
+                          TRUE,
+                          atomIndex,
+                          globalAtomIndex,
+                          atomIndexInMolecule,
+                          iatoms.data(),
+                          idef);
             }
         }
         else
         {
-            gmx_bool bUse;
+            bool bUse = false;
 
             /* Copy the type */
             tiatoms[0] = iatoms[0];
 
             if (nral == 1)
             {
-                assert(!bInterMolInteractions);
-                /* Assign single-body interactions to the home zone */
-                if (iz == 0)
-                {
-                    bUse       = TRUE;
-                    tiatoms[1] = i;
-                    if (ftype == F_POSRES)
-                    {
-                        add_posres(mol, i_mol, numAtomsInMolecule, molb, tiatoms, ip_in, idef);
-                    }
-                    else if (ftype == F_FBPOSRES)
-                    {
-                        add_fbposres(mol, i_mol, numAtomsInMolecule, molb, tiatoms, ip_in, idef);
-                    }
-                }
-                else
+                GMX_ASSERT(interactionConnectivity == InteractionConnectivity::Intramolecular,
+                           "All interactions that involve a single atom are intramolecular");
+
+                /* Assign single-body interactions to the home zone.
+                 * Position restraints are not handled here, but separately.
+                 */
+                if (iz == 0 && !(ftype == F_POSRES || ftype == F_FBPOSRES))
                 {
-                    bUse = FALSE;
+                    bUse       = true;
+                    tiatoms[1] = atomIndex;
                 }
             }
             else if (nral == 2)
@@ -1123,18 +1196,12 @@ static inline void check_assign_interactions_atom(int                       i,
                 /* This is a two-body interaction, we can assign
                  * analogous to the non-bonded assignments.
                  */
-                int k_gl;
-
-                if (!bInterMolInteractions)
-                {
-                    /* Get the global index using the offset in the molecule */
-                    k_gl = i_gl + iatoms[2] - i_mol;
-                }
-                else
-                {
-                    k_gl = iatoms[2];
-                }
-                if (const auto* entry = dd->ga2la->find(k_gl))
+                const int k_gl = (interactionConnectivity == InteractionConnectivity::Intramolecular)
+                                         ?
+                                         /* Get the global index using the offset in the molecule */
+                                         (globalAtomIndex + iatoms[2] - atomIndexInMolecule)
+                                         : iatoms[2];
+                if (const auto* entry = ga2la.find(k_gl))
                 {
                     int kz = entry->cell;
                     if (kz >= zones->n)
@@ -1149,12 +1216,13 @@ static inline void check_assign_interactions_atom(int                       i,
                         GMX_ASSERT(ftype != F_CONSTR || (iz == 0 && kz == 0),
                                    "Constraint assigned here should only involve home atoms");
 
-                        tiatoms[1] = i;
+                        tiatoms[1] = atomIndex;
                         tiatoms[2] = entry->la;
                         /* If necessary check the cgcm distance */
-                        if (bRCheck2B && dd_dist2(pbc_null, cg_cm, tiatoms[1], tiatoms[2]) >= rc2)
+                        if (checkDistanceTwoBody
+                            && dd_dist2(pbc_null, coordinates, tiatoms[1], tiatoms[2]) >= cutoffSquared)
                         {
-                            bUse = FALSE;
+                            bUse = false;
                         }
                     }
                 }
@@ -1166,30 +1234,24 @@ static inline void check_assign_interactions_atom(int                       i,
             else
             {
                 /* Assign this multi-body bonded interaction to
-                 * the local node if we have all the atoms involved
+                 * the local domain if we have all the atoms involved
                  * (local or communicated) and the minimum zone shift
                  * in each dimension is zero, for dimensions
                  * with 2 DD cells an extra check may be necessary.
                  */
                 ivec k_zero, k_plus;
-                int  k;
-
-                bUse = TRUE;
+                bUse = true;
                 clear_ivec(k_zero);
                 clear_ivec(k_plus);
-                for (k = 1; k <= nral && bUse; k++)
+                for (int k = 1; k <= nral && bUse; k++)
                 {
-                    int k_gl;
-                    if (!bInterMolInteractions)
-                    {
-                        /* Get the global index using the offset in the molecule */
-                        k_gl = i_gl + iatoms[k] - i_mol;
-                    }
-                    else
-                    {
-                        k_gl = iatoms[k];
-                    }
-                    const auto* entry = dd->ga2la->find(k_gl);
+                    const int k_gl =
+                            (interactionConnectivity == InteractionConnectivity::Intramolecular)
+                                    ?
+                                    /* Get the global index using the offset in the molecule */
+                                    (globalAtomIndex + iatoms[k] - atomIndexInMolecule)
+                                    : iatoms[k];
+                    const auto* entry = ga2la.find(k_gl);
                     if (entry == nullptr || entry->cell >= zones->n)
                     {
                         /* We do not have this atom of this interaction
@@ -1200,10 +1262,8 @@ static inline void check_assign_interactions_atom(int                       i,
                     }
                     else
                     {
-                        int d;
-
                         tiatoms[k] = entry->la;
-                        for (d = 0; d < DIM; d++)
+                        for (int d = 0; d < DIM; d++)
                         {
                             if (zones->shift[entry->cell][d] == 0)
                             {
@@ -1217,18 +1277,17 @@ static inline void check_assign_interactions_atom(int                       i,
                     }
                 }
                 bUse = (bUse && (k_zero[XX] != 0) && (k_zero[YY] != 0) && (k_zero[ZZ] != 0));
-                if (bRCheckMB)
+                if (checkDistanceMultiBody)
                 {
-                    int d;
-
-                    for (d = 0; (d < DIM && bUse); d++)
+                    for (int d = 0; (d < DIM && bUse); d++)
                     {
-                        /* Check if the cg_cm distance falls within
+                        /* Check if the distance falls within
                          * the cut-off to avoid possible multiple
                          * assignments of bonded interactions.
                          */
                         if (rcheck[d] && k_plus[d]
-                            && dd_dist2(pbc_null, cg_cm, tiatoms[k_zero[d]], tiatoms[k_plus[d]]) >= rc2)
+                            && dd_dist2(pbc_null, coordinates, tiatoms[k_zero[d]], tiatoms[k_plus[d]])
+                                       >= cutoffSquared)
                         {
                             bUse = FALSE;
                         }
@@ -1242,14 +1301,65 @@ static inline void check_assign_interactions_atom(int                       i,
                 /* Sum so we can check in global_stat
                  * if we have everything.
                  */
-                if (bBCheck || !(interaction_function[ftype].flags & IF_LIMZERO))
+                if (ddBondedChecking == DDBondedChecking::All
+                    || !(interaction_function[ftype].flags & IF_LIMZERO))
                 {
-                    (*nbonded_local)++;
+                    numBondedInteractions++;
                 }
             }
         }
         j += 1 + nral_rt(ftype);
     }
+
+    return numBondedInteractions;
+}
+
+/*! \brief Determine whether the local domain has responsibility for
+ * any of the position restraints for local atom \p atomIndex
+ * and assign those to the local domain.
+ *
+ * \returns The total number of bonded interactions for this atom for
+ * which this domain is responsible.
+ */
+static inline int assignPositionRestraintsForAtom(const int                atomIndex,
+                                                  const int                mol,
+                                                  const int                atomIndexInMolecule,
+                                                  const int                numAtomsInMolecule,
+                                                  gmx::ArrayRef<const int> rtil,
+                                                  const int                ind_start,
+                                                  const int                ind_end,
+                                                  const gmx_molblock_t&    molb,
+                                                  const t_iparams*         ip_in,
+                                                  InteractionDefinitions*  idef)
+{
+    constexpr int nral = 1;
+
+    int numBondedInteractions = 0;
+
+    int j = ind_start;
+    while (j < ind_end)
+    {
+        const int ftype  = rtil[j++];
+        auto      iatoms = gmx::constArrayRefFromArray(rtil.data() + j, rtil.size() - j);
+
+        if (ftype == F_POSRES || ftype == F_FBPOSRES)
+        {
+            std::array<int, 1 + nral> tiatoms = { iatoms[0], atomIndex };
+            if (ftype == F_POSRES)
+            {
+                add_posres(mol, atomIndexInMolecule, numAtomsInMolecule, molb, tiatoms, ip_in, idef);
+            }
+            else
+            {
+                add_fbposres(mol, atomIndexInMolecule, numAtomsInMolecule, molb, tiatoms, ip_in, idef);
+            }
+            idef->il[ftype].push_back(tiatoms[0], nral, tiatoms.data() + 1);
+            numBondedInteractions++;
+        }
+        j += 1 + nral_rt(ftype);
+    }
+
+    return numBondedInteractions;
 }
 
 /*! \brief This function looks up and assigns bonded interactions for zone iz.
@@ -1257,65 +1367,112 @@ static inline void check_assign_interactions_atom(int                       i,
  * With thread parallelizing each thread acts on a different atom range:
  * at_start to at_end.
  */
-static int make_bondeds_zone(gmx_domdec_t*                      dd,
+static int make_bondeds_zone(gmx_reverse_top_t*                 rt,
+                             ArrayRef<const int>                globalAtomIndices,
+                             const gmx_ga2la_t&                 ga2la,
                              const gmx_domdec_zones_t*          zones,
                              const std::vector<gmx_molblock_t>& molb,
-                             gmx_bool                           bRCheckMB,
-                             ivec                               rcheck,
-                             gmx_bool                           bRCheck2B,
-                             real                               rc2,
-                             t_pbc*                             pbc_null,
-                             rvec*                              cg_cm,
+                             const bool                         checkDistanceMultiBody,
+                             const ivec                         rcheck,
+                             const bool                         checkDistanceTwoBody,
+                             const real                         cutoffSquared,
+                             const t_pbc*                       pbc_null,
+                             ArrayRef<const RVec>               coordinates,
                              const t_iparams*                   ip_in,
                              InteractionDefinitions*            idef,
                              int                                izone,
                              const gmx::Range<int>&             atomRange)
 {
-    int                mb, mt, mol, i_mol;
-    gmx_bool           bBCheck;
-    gmx_reverse_top_t* rt;
-    int                nbonded_local;
-
-    rt = dd->reverse_top;
+    int mb                  = 0;
+    int mt                  = 0;
+    int mol                 = 0;
+    int atomIndexInMolecule = 0;
 
-    bBCheck = rt->bBCheck;
+    const auto ddBondedChecking = rt->impl_->options.ddBondedChecking;
 
-    nbonded_local = 0;
+    int numBondedInteractions = 0;
 
     for (int i : atomRange)
     {
         /* Get the global atom number */
-        const int i_gl = dd->globalAtomIndices[i];
-        global_atomnr_to_moltype_ind(rt, i_gl, &mb, &mt, &mol, &i_mol);
+        const int globalAtomIndex = globalAtomIndices[i];
+        global_atomnr_to_moltype_ind(rt->impl_->mbi, globalAtomIndex, &mb, &mt, &mol, &atomIndexInMolecule);
         /* Check all intramolecular interactions assigned to this atom */
-        gmx::ArrayRef<const int>     index = rt->ril_mt[mt].index;
-        gmx::ArrayRef<const t_iatom> rtil  = rt->ril_mt[mt].il;
-
-        check_assign_interactions_atom(i, i_gl, mol, i_mol, rt->ril_mt[mt].numAtomsInMolecule,
-                                       index, rtil, FALSE, index[i_mol], index[i_mol + 1], dd,
-                                       zones, &molb[mb], bRCheckMB, rcheck, bRCheck2B, rc2,
-                                       pbc_null, cg_cm, ip_in, idef, izone, bBCheck, &nbonded_local);
-
+        gmx::ArrayRef<const int>     index = rt->impl_->ril_mt[mt].index;
+        gmx::ArrayRef<const t_iatom> rtil  = rt->impl_->ril_mt[mt].il;
+
+        numBondedInteractions += assignInteractionsForAtom<InteractionConnectivity::Intramolecular>(
+                i,
+                globalAtomIndex,
+                atomIndexInMolecule,
+                index,
+                rtil,
+                index[atomIndexInMolecule],
+                index[atomIndexInMolecule + 1],
+                ga2la,
+                zones,
+                checkDistanceMultiBody,
+                rcheck,
+                checkDistanceTwoBody,
+                cutoffSquared,
+                pbc_null,
+                coordinates,
+                idef,
+                izone,
+                ddBondedChecking);
+
+        // Assign position restraints, when present, for the home zone
+        if (izone == 0 && rt->impl_->havePositionRestraints)
+        {
+            numBondedInteractions +=
+                    assignPositionRestraintsForAtom(i,
+                                                    mol,
+                                                    atomIndexInMolecule,
+                                                    rt->impl_->ril_mt[mt].numAtomsInMolecule,
+                                                    rtil,
+                                                    index[atomIndexInMolecule],
+                                                    index[atomIndexInMolecule + 1],
+                                                    molb[mb],
+                                                    ip_in,
+                                                    idef);
+        }
 
-        if (rt->bIntermolecularInteractions)
+        if (rt->impl_->bIntermolecularInteractions)
         {
             /* Check all intermolecular interactions assigned to this atom */
-            index = rt->ril_intermol.index;
-            rtil  = rt->ril_intermol.il;
-
-            check_assign_interactions_atom(i, i_gl, mol, i_mol, rt->ril_mt[mt].numAtomsInMolecule,
-                                           index, rtil, TRUE, index[i_gl], index[i_gl + 1], dd, zones,
-                                           &molb[mb], bRCheckMB, rcheck, bRCheck2B, rc2, pbc_null,
-                                           cg_cm, ip_in, idef, izone, bBCheck, &nbonded_local);
+            index = rt->impl_->ril_intermol.index;
+            rtil  = rt->impl_->ril_intermol.il;
+
+            numBondedInteractions += assignInteractionsForAtom<InteractionConnectivity::Intermolecular>(
+                    i,
+                    -1, // not used
+                    -1, // not used
+                    index,
+                    rtil,
+                    index[globalAtomIndex],
+                    index[globalAtomIndex + 1],
+                    ga2la,
+                    zones,
+                    checkDistanceMultiBody,
+                    rcheck,
+                    checkDistanceTwoBody,
+                    cutoffSquared,
+                    pbc_null,
+                    coordinates,
+                    idef,
+                    izone,
+                    ddBondedChecking);
         }
     }
 
-    return nbonded_local;
+    return numBondedInteractions;
 }
 
 /*! \brief Set the exclusion data for i-zone \p iz */
-static void make_exclusions_zone(gmx_domdec_t*                     dd,
+static void make_exclusions_zone(ArrayRef<const int>               globalAtomIndices,
+                                 const gmx_ga2la_t&                ga2la,
                                  gmx_domdec_zones_t*               zones,
+                                 ArrayRef<const MolblockIndices>   molblockIndices,
                                  const std::vector<gmx_moltype_t>& moltype,
                                  const int*                        cginfo,
                                  ListOfLists<int>*                 lexcls,
@@ -1324,8 +1481,6 @@ static void make_exclusions_zone(gmx_domdec_t*                     dd,
                                  int                               at_end,
                                  const gmx::ArrayRef<const int>    intermolecularExclusionGroup)
 {
-    const gmx_ga2la_t& ga2la = *dd->ga2la;
-
     const auto& jAtomRange = zones->iZones[iz].jAtomRange;
 
     const gmx::index oldNumLists = lexcls->ssize();
@@ -1337,11 +1492,14 @@ static void make_exclusions_zone(gmx_domdec_t*                     dd,
 
         if (GET_CGINFO_EXCL_INTER(cginfo[at]))
         {
-            int a_gl, mb, mt, mol, a_mol;
+            int mb    = 0;
+            int mt    = 0;
+            int mol   = 0;
+            int a_mol = 0;
 
             /* Copy the exclusions from the global top */
-            a_gl = dd->globalAtomIndices[at];
-            global_atomnr_to_moltype_ind(dd->reverse_top, a_gl, &mb, &mt, &mol, &a_mol);
+            int a_gl = globalAtomIndices[at];
+            global_atomnr_to_moltype_ind(molblockIndices, a_gl, &mb, &mt, &mol, &a_mol);
             const auto excls = moltype[mt].excls[a_mol];
             for (const int aj_mol : excls)
             {
@@ -1361,14 +1519,15 @@ static void make_exclusions_zone(gmx_domdec_t*                     dd,
 
         bool isExcludedAtom = !intermolecularExclusionGroup.empty()
                               && std::find(intermolecularExclusionGroup.begin(),
-                                           intermolecularExclusionGroup.end(), dd->globalAtomIndices[at])
+                                           intermolecularExclusionGroup.end(),
+                                           globalAtomIndices[at])
                                          != intermolecularExclusionGroup.end();
 
         if (isExcludedAtom)
         {
             for (int qmAtomGlobalIndex : intermolecularExclusionGroup)
             {
-                if (const auto* entry = dd->ga2la->find(qmAtomGlobalIndex))
+                if (const auto* entry = ga2la.find(qmAtomGlobalIndex))
                 {
                     exclusionsForAtom.push_back(entry->la);
                 }
@@ -1385,27 +1544,22 @@ static void make_exclusions_zone(gmx_domdec_t*                     dd,
 }
 
 /*! \brief Generate and store all required local bonded interactions in \p idef and local exclusions in \p lexcls */
-static int make_local_bondeds_excls(gmx_domdec_t*           dd,
-                                    gmx_domdec_zones_t*     zones,
-                                    const gmx_mtop_t*       mtop,
-                                    const int*              cginfo,
-                                    gmx_bool                bRCheckMB,
-                                    ivec                    rcheck,
-                                    gmx_bool                bRCheck2B,
-                                    real                    rc,
-                                    t_pbc*                  pbc_null,
-                                    rvec*                   cg_cm,
-                                    InteractionDefinitions* idef,
-                                    ListOfLists<int>*       lexcls,
-                                    int*                    excl_count)
+static void make_local_bondeds_excls(gmx_domdec_t*           dd,
+                                     gmx_domdec_zones_t*     zones,
+                                     const gmx_mtop_t&       mtop,
+                                     const int*              cginfo,
+                                     const bool              checkDistanceMultiBody,
+                                     const ivec              rcheck,
+                                     const gmx_bool          checkDistanceTwoBody,
+                                     const real              cutoff,
+                                     const t_pbc*            pbc_null,
+                                     ArrayRef<const RVec>    coordinates,
+                                     InteractionDefinitions* idef,
+                                     ListOfLists<int>*       lexcls)
 {
-    int                nzone_bondeds;
-    int                cg0, cg1;
-    real               rc2;
-    int                nbonded_local;
-    gmx_reverse_top_t* rt;
+    int nzone_bondeds = 0;
 
-    if (dd->reverse_top->bInterAtomicInteractions)
+    if (dd->reverse_top->impl_->bInterAtomicInteractions)
     {
         nzone_bondeds = zones->n;
     }
@@ -1420,33 +1574,31 @@ static int make_local_bondeds_excls(gmx_domdec_t*           dd,
     /* We only use exclusions from i-zones to i- and j-zones */
     const int numIZonesForExclusions = (dd->haveExclusions ? zones->iZones.size() : 0);
 
-    rt = dd->reverse_top;
+    gmx_reverse_top_t* rt = dd->reverse_top.get();
 
-    rc2 = rc * rc;
+    const real cutoffSquared = gmx::square(cutoff);
 
     /* Clear the counts */
     idef->clear();
-    nbonded_local = 0;
+    dd->reverse_top->impl_->numBondedInteractions = 0;
 
     lexcls->clear();
-    *excl_count = 0;
 
     for (int izone = 0; izone < nzone_bondeds; izone++)
     {
-        cg0 = zones->cg_range[izone];
-        cg1 = zones->cg_range[izone + 1];
+        const int cg0 = zones->cg_range[izone];
+        const int cg1 = zones->cg_range[izone + 1];
 
-        const int numThreads = rt->th_work.size();
+        const int numThreads = rt->impl_->th_work.size();
 #pragma omp parallel for num_threads(numThreads) schedule(static)
         for (int thread = 0; thread < numThreads; thread++)
         {
             try
             {
-                int                     cg0t, cg1t;
-                InteractionDefinitions* idef_t;
+                InteractionDefinitions* idef_t = nullptr;
 
-                cg0t = cg0 + ((cg1 - cg0) * thread) / numThreads;
-                cg1t = cg0 + ((cg1 - cg0) * (thread + 1)) / numThreads;
+                int cg0t = cg0 + ((cg1 - cg0) * thread) / numThreads;
+                int cg1t = cg0 + ((cg1 - cg0) * (thread + 1)) / numThreads;
 
                 if (thread == 0)
                 {
@@ -1454,17 +1606,30 @@ static int make_local_bondeds_excls(gmx_domdec_t*           dd,
                 }
                 else
                 {
-                    idef_t = &rt->th_work[thread].idef;
+                    idef_t = &rt->impl_->th_work[thread].idef;
                     idef_t->clear();
                 }
 
-                rt->th_work[thread].nbonded = make_bondeds_zone(
-                        dd, zones, mtop->molblock, bRCheckMB, rcheck, bRCheck2B, rc2, pbc_null,
-                        cg_cm, idef->iparams.data(), idef_t, izone, gmx::Range<int>(cg0t, cg1t));
+                rt->impl_->th_work[thread].numBondedInteractions =
+                        make_bondeds_zone(rt,
+                                          dd->globalAtomIndices,
+                                          *dd->ga2la,
+                                          zones,
+                                          mtop.molblock,
+                                          checkDistanceMultiBody,
+                                          rcheck,
+                                          checkDistanceTwoBody,
+                                          cutoffSquared,
+                                          pbc_null,
+                                          coordinates,
+                                          idef->iparams.data(),
+                                          idef_t,
+                                          izone,
+                                          gmx::Range<int>(cg0t, cg1t));
 
                 if (izone < numIZonesForExclusions)
                 {
-                    ListOfLists<int>* excl_t;
+                    ListOfLists<int>* excl_t = nullptr;
                     if (thread == 0)
                     {
                         // Thread 0 stores exclusions directly in the final storage
@@ -1473,75 +1638,136 @@ static int make_local_bondeds_excls(gmx_domdec_t*           dd,
                     else
                     {
                         // Threads > 0 store in temporary storage, starting at list index 0
-                        excl_t = &rt->th_work[thread].excl;
+                        excl_t = &rt->impl_->th_work[thread].excl;
                         excl_t->clear();
                     }
 
                     /* No charge groups and no distance check required */
-                    make_exclusions_zone(dd, zones, mtop->moltype, cginfo, excl_t, izone, cg0t,
-                                         cg1t, mtop->intermolecularExclusionGroup);
+                    make_exclusions_zone(dd->globalAtomIndices,
+                                         *dd->ga2la,
+                                         zones,
+                                         rt->impl_->mbi,
+                                         mtop.moltype,
+                                         cginfo,
+                                         excl_t,
+                                         izone,
+                                         cg0t,
+                                         cg1t,
+                                         mtop.intermolecularExclusionGroup);
                 }
             }
             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
         }
 
-        if (rt->th_work.size() > 1)
+        if (rt->impl_->th_work.size() > 1)
         {
-            combine_idef(idef, rt->th_work);
+            combine_idef(idef, rt->impl_->th_work);
         }
 
-        for (const thread_work_t& th_work : rt->th_work)
+        for (const thread_work_t& th_work : rt->impl_->th_work)
         {
-            nbonded_local += th_work.nbonded;
+            dd->reverse_top->impl_->numBondedInteractions += th_work.numBondedInteractions;
         }
 
         if (izone < numIZonesForExclusions)
         {
-            for (std::size_t th = 1; th < rt->th_work.size(); th++)
+            for (std::size_t th = 1; th < rt->impl_->th_work.size(); th++)
             {
-                lexcls->appendListOfLists(rt->th_work[th].excl);
-            }
-            for (const thread_work_t& th_work : rt->th_work)
-            {
-                *excl_count += th_work.excl_count;
+                lexcls->appendListOfLists(rt->impl_->th_work[th].excl);
             }
         }
     }
 
+    // Note that it's possible for this to still be true from the last
+    // time it was set, e.g. if repartitioning was triggered before
+    // global communication that would have acted on the true
+    // value. This could happen for example when replica exchange took
+    // place soon after a partition.
+    dd->reverse_top->impl_->shouldCheckNumberOfBondedInteractions = true;
+    // Clear the old global value, which is now invalid
+    dd->reverse_top->impl_->numBondedInteractionsOverAllDomains.reset();
+
     if (debug)
     {
-        fprintf(debug, "We have %d exclusions, check count %d\n", lexcls->numElements(), *excl_count);
+        fprintf(debug, "We have %d exclusions\n", lexcls->numElements());
     }
+}
 
-    return nbonded_local;
+bool shouldCheckNumberOfBondedInteractions(const gmx_domdec_t& dd)
+{
+    return dd.reverse_top->impl_->shouldCheckNumberOfBondedInteractions;
 }
 
-void dd_make_local_top(gmx_domdec_t*       dd,
-                       gmx_domdec_zones_t* zones,
-                       int                 npbcdim,
-                       matrix              box,
-                       rvec                cellsize_min,
-                       const ivec          npulse,
-                       t_forcerec*         fr,
-                       rvec*               cgcm_or_x,
-                       const gmx_mtop_t&   mtop,
-                       gmx_localtop_t*     ltop)
+int numBondedInteractions(const gmx_domdec_t& dd)
 {
-    gmx_bool bRCheckMB, bRCheck2B;
-    real     rc = -1;
-    ivec     rcheck;
-    int      d, nexcl;
-    t_pbc    pbc, *pbc_null = nullptr;
+    return dd.reverse_top->impl_->numBondedInteractions;
+}
+
+void setNumberOfBondedInteractionsOverAllDomains(const gmx_domdec_t& dd, int newValue)
+{
+    GMX_RELEASE_ASSERT(!dd.reverse_top->impl_->numBondedInteractionsOverAllDomains.has_value(),
+                       "Cannot set number of bonded interactions because it is already set");
+    dd.reverse_top->impl_->numBondedInteractionsOverAllDomains.emplace(newValue);
+}
+
+void checkNumberOfBondedInteractions(const gmx::MDLogger&           mdlog,
+                                     t_commrec*                     cr,
+                                     const gmx_mtop_t&              top_global,
+                                     const gmx_localtop_t*          top_local,
+                                     gmx::ArrayRef<const gmx::RVec> x,
+                                     const matrix                   box)
+{
+    GMX_RELEASE_ASSERT(
+            DOMAINDECOMP(cr),
+            "No need to check number of bonded interactions when not using domain decomposition");
+    if (cr->dd->reverse_top->impl_->shouldCheckNumberOfBondedInteractions)
+    {
+        GMX_RELEASE_ASSERT(cr->dd->reverse_top->impl_->numBondedInteractionsOverAllDomains.has_value(),
+                           "The check for the total number of bonded interactions requires the "
+                           "value to have been reduced across all domains");
+        if (cr->dd->reverse_top->impl_->numBondedInteractionsOverAllDomains.value()
+            != cr->dd->reverse_top->impl_->expectedNumGlobalBondedInteractions)
+        {
+            dd_print_missing_interactions(
+                    mdlog,
+                    cr,
+                    cr->dd->reverse_top->impl_->numBondedInteractionsOverAllDomains.value(),
+                    top_global,
+                    top_local,
+                    x,
+                    box); // Does not return
+        }
+        // Now that the value is set and the check complete, future
+        // global communication should not compute the value until
+        // after the next partitioning.
+        cr->dd->reverse_top->impl_->shouldCheckNumberOfBondedInteractions = false;
+    }
+}
+
+void dd_make_local_top(gmx_domdec_t*        dd,
+                       gmx_domdec_zones_t*  zones,
+                       int                  npbcdim,
+                       matrix               box,
+                       rvec                 cellsize_min,
+                       const ivec           npulse,
+                       t_forcerec*          fr,
+                       ArrayRef<const RVec> coordinates,
+                       const gmx_mtop_t&    mtop,
+                       gmx_localtop_t*      ltop)
+{
+    real  rc = -1;
+    ivec  rcheck;
+    t_pbc pbc, *pbc_null = nullptr;
 
     if (debug)
     {
         fprintf(debug, "Making local topology\n");
     }
 
-    bRCheckMB = FALSE;
-    bRCheck2B = FALSE;
+    bool checkDistanceMultiBody = false;
+    bool checkDistanceTwoBody   = false;
 
-    if (dd->reverse_top->bInterAtomicInteractions)
+    if (dd->reverse_top->impl_->bInterAtomicInteractions)
     {
         /* We need to check to which cell bondeds should be assigned */
         rc = dd_cutoff_twobody(dd);
@@ -1550,8 +1776,8 @@ void dd_make_local_top(gmx_domdec_t*       dd,
             fprintf(debug, "Two-body bonded cut-off distance is %g\n", rc);
         }
 
-        /* Should we check cg_cm distances when assigning bonded interactions? */
-        for (d = 0; d < DIM; d++)
+        /* Should we check distances when assigning bonded interactions? */
+        for (int d = 0; d < DIM; d++)
         {
             rcheck[d] = FALSE;
             /* Only need to check for dimensions where the part of the box
@@ -1562,22 +1788,27 @@ void dd_make_local_top(gmx_domdec_t*       dd,
             {
                 if (dd->numCells[d] == 2)
                 {
-                    rcheck[d] = TRUE;
-                    bRCheckMB = TRUE;
+                    rcheck[d]              = TRUE;
+                    checkDistanceMultiBody = TRUE;
                 }
                 /* Check for interactions between two atoms,
                  * where we can allow interactions up to the cut-off,
                  * instead of up to the smallest cell dimension.
                  */
-                bRCheck2B = TRUE;
+                checkDistanceTwoBody = TRUE;
             }
             if (debug)
             {
-                fprintf(debug, "dim %d cellmin %f bonded rcheck[%d] = %d, bRCheck2B = %s\n", d,
-                        cellsize_min[d], d, rcheck[d], gmx::boolToString(bRCheck2B));
+                fprintf(debug,
+                        "dim %d cellmin %f bonded rcheck[%d] = %d, checkDistanceTwoBody = %s\n",
+                        d,
+                        cellsize_min[d],
+                        d,
+                        rcheck[d],
+                        gmx::boolToString(checkDistanceTwoBody));
             }
         }
-        if (bRCheckMB || bRCheck2B)
+        if (checkDistanceMultiBody || checkDistanceTwoBody)
         {
             if (fr->bMolPBC)
             {
@@ -1590,9 +1821,18 @@ void dd_make_local_top(gmx_domdec_t*       dd,
         }
     }
 
-    dd->nbonded_local = make_local_bondeds_excls(dd, zones, &mtop, fr->cginfo.data(), bRCheckMB,
-                                                 rcheck, bRCheck2B, rc, pbc_null, cgcm_or_x,
-                                                 &ltop->idef, &ltop->excls, &nexcl);
+    make_local_bondeds_excls(dd,
+                             zones,
+                             mtop,
+                             fr->cginfo.data(),
+                             checkDistanceMultiBody,
+                             rcheck,
+                             checkDistanceTwoBody,
+                             rc,
+                             pbc_null,
+                             coordinates,
+                             &ltop->idef,
+                             &ltop->excls);
 
     /* The ilist is not sorted yet,
      * we can only do this when we have the charge arrays.
@@ -1600,9 +1840,9 @@ void dd_make_local_top(gmx_domdec_t*       dd,
     ltop->idef.ilsort = ilsortUNKNOWN;
 }
 
-void dd_sort_local_top(gmx_domdec_t* dd, const t_mdatoms* mdatoms, gmx_localtop_t* ltop)
+void dd_sort_local_top(const gmx_domdec_t& dd, const t_mdatoms* mdatoms, gmx_localtop_t* ltop)
 {
-    if (dd->reverse_top->ilsort == ilsortNO_FE)
+    if (dd.reverse_top->impl_->ilsort == ilsortNO_FE)
     {
         ltop->idef.ilsort = ilsortNO_FE;
     }
@@ -1612,7 +1852,7 @@ void dd_sort_local_top(gmx_domdec_t* dd, const t_mdatoms* mdatoms, gmx_localtop_
     }
 }
 
-void dd_init_local_state(gmx_domdec_t* dd, const t_state* state_global, t_state* state_local)
+void dd_init_local_state(const gmx_domdec_t& dd, const t_state* state_global, t_state* state_local)
 {
     int buf[NITEM_DD_INIT_LOCAL_STATE];
 
@@ -1624,7 +1864,7 @@ void dd_init_local_state(gmx_domdec_t* dd, const t_state* state_global, t_state*
         buf[3] = state_global->nhchainlength;
         buf[4] = state_global->dfhist ? state_global->dfhist->nlambda : 0;
     }
-    dd_bcast(dd, NITEM_DD_INIT_LOCAL_STATE * sizeof(int), buf);
+    dd_bcast(&dd, NITEM_DD_INIT_LOCAL_STATE * sizeof(int), buf);
 
     init_gtc_state(state_local, buf[1], buf[2], buf[3]);
     init_dfhist_state(state_local, buf[4]);
@@ -1634,11 +1874,8 @@ void dd_init_local_state(gmx_domdec_t* dd, const t_state* state_global, t_state*
 /*! \brief Check if a link is stored in \p link between charge groups \p cg_gl and \p cg_gl_j and if not so, store a link */
 static void check_link(t_blocka* link, int cg_gl, int cg_gl_j)
 {
-    int      k;
-    gmx_bool bFound;
-
-    bFound = FALSE;
-    for (k = link->index[cg_gl]; k < link->index[cg_gl + 1]; k++)
+    bool bFound = false;
+    for (int k = link->index[cg_gl]; k < link->index[cg_gl + 1]; k++)
     {
         GMX_RELEASE_ASSERT(link->a, "Inconsistent NULL pointer while making charge-group links");
         if (link->a[k] == cg_gl_j)
@@ -1661,10 +1898,17 @@ static void check_link(t_blocka* link, int cg_gl, int cg_gl_j)
     }
 }
 
-t_blocka* makeBondedLinks(const gmx_mtop_t& mtop, gmx::ArrayRef<cginfo_mb_t> cginfo_mb)
+void makeBondedLinks(gmx_domdec_t* dd, const gmx_mtop_t& mtop, gmx::ArrayRef<cginfo_mb_t> cginfo_mb)
 {
-    t_blocka*    link;
-    cginfo_mb_t* cgi_mb;
+
+    if (!dd->comm->systemInfo.filterBondedCommunication)
+    {
+        /* Only communicate atoms based on cut-off */
+        dd->comm->bondedLinks = nullptr;
+        return;
+    }
+
+    t_blocka* link = nullptr;
 
     /* For each atom make a list of other atoms in the system
      * that a linked to it via bonded interactions
@@ -1682,7 +1926,9 @@ t_blocka* makeBondedLinks(const gmx_mtop_t& mtop, gmx::ArrayRef<cginfo_mb_t> cgi
         GMX_RELEASE_ASSERT(mtop.intermolecular_ilist,
                            "We should have an ilist when intermolecular interactions are on");
 
-        make_reverse_ilist(*mtop.intermolecular_ilist, &atoms, FALSE, FALSE, FALSE, TRUE, &ril_intermol);
+        ReverseTopOptions rtOptions(DDBondedChecking::ExcludeZeroLimit);
+        make_reverse_ilist(
+                *mtop.intermolecular_ilist, &atoms, rtOptions, AtomLinkRule::AllAtomsInBondeds, &ril_intermol);
     }
 
     snew(link, 1);
@@ -1705,12 +1951,13 @@ t_blocka* makeBondedLinks(const gmx_mtop_t& mtop, gmx::ArrayRef<cginfo_mb_t> cgi
          * to all atoms, not only the first atom as in gmx_reverse_top.
          * The constraints are discarded here.
          */
-        reverse_ilist_t ril;
-        make_reverse_ilist(molt.ilist, &molt.atoms, FALSE, FALSE, FALSE, TRUE, &ril);
+        ReverseTopOptions rtOptions(DDBondedChecking::ExcludeZeroLimit);
+        reverse_ilist_t   ril;
+        make_reverse_ilist(molt.ilist, &molt.atoms, rtOptions, AtomLinkRule::AllAtomsInBondeds, &ril);
 
-        cgi_mb = &cginfo_mb[mb];
+        cginfo_mb_t* cgi_mb = &cginfo_mb[mb];
 
-        int mol;
+        int mol = 0;
         for (mol = 0; mol < (mtop.bIntermolecularInteractions ? molb.nmol : 1); mol++)
         {
             for (int a = 0; a < molt.atoms.nr; a++)
@@ -1768,8 +2015,11 @@ t_blocka* makeBondedLinks(const gmx_mtop_t& mtop, gmx::ArrayRef<cginfo_mb_t> cgi
 
         if (debug)
         {
-            fprintf(debug, "molecule type '%s' %d atoms has %d atom links through bonded interac.\n",
-                    *molt.name, molt.atoms.nr, nlink_mol);
+            fprintf(debug,
+                    "molecule type '%s' %d atoms has %d atom links through bonded interac.\n",
+                    *molt.name,
+                    molt.atoms.nr,
+                    nlink_mol);
         }
 
         if (molb.nmol > mol)
@@ -1804,7 +2054,7 @@ t_blocka* makeBondedLinks(const gmx_mtop_t& mtop, gmx::ArrayRef<cginfo_mb_t> cgi
         fprintf(debug, "Of the %d atoms %d are linked via bonded interactions\n", mtop.natoms, ncgi);
     }
 
-    return link;
+    dd->comm->bondedLinks = link;
 }
 
 typedef struct
@@ -1828,16 +2078,18 @@ static void update_max_bonded_distance(real r2, int ftype, int a1, int a2, bonde
 }
 
 /*! \brief Set the distance, function type and atom indices for the longest distance between atoms of molecule type \p molt for two-body and multi-body bonded interactions */
-static void bonded_cg_distance_mol(const gmx_moltype_t* molt,
-                                   gmx_bool             bBCheck,
-                                   gmx_bool             bExcl,
-                                   ArrayRef<const RVec> x,
-                                   bonded_distance_t*   bd_2b,
-                                   bonded_distance_t*   bd_mb)
+static void bonded_cg_distance_mol(const gmx_moltype_t*   molt,
+                                   const DDBondedChecking ddBondedChecking,
+                                   gmx_bool               bExcl,
+                                   ArrayRef<const RVec>   x,
+                                   bonded_distance_t*     bd_2b,
+                                   bonded_distance_t*     bd_mb)
 {
+    const ReverseTopOptions rtOptions(ddBondedChecking);
+
     for (int ftype = 0; ftype < F_NRE; ftype++)
     {
-        if (dd_check_ftype(ftype, bBCheck, FALSE, FALSE))
+        if (dd_check_ftype(ftype, rtOptions))
         {
             const auto& il   = molt->ilist[ftype];
             int         nral = NRAL(ftype);
@@ -1855,8 +2107,8 @@ static void bonded_cg_distance_mol(const gmx_moltype_t* molt,
                             {
                                 real rij2 = distance2(x[atomI], x[atomJ]);
 
-                                update_max_bonded_distance(rij2, ftype, atomI, atomJ,
-                                                           (nral == 2) ? bd_2b : bd_mb);
+                                update_max_bonded_distance(
+                                        rij2, ftype, atomI, atomJ, (nral == 2) ? bd_2b : bd_mb);
                             }
                         }
                     }
@@ -1885,7 +2137,7 @@ static void bonded_cg_distance_mol(const gmx_moltype_t* molt,
 
 /*! \brief Set the distance, function type and atom indices for the longest atom distance involved in intermolecular interactions for two-body and multi-body bonded interactions */
 static void bonded_distance_intermol(const InteractionLists& ilists_intermol,
-                                     gmx_bool                bBCheck,
+                                     const DDBondedChecking  ddBondedChecking,
                                      ArrayRef<const RVec>    x,
                                      PbcType                 pbcType,
                                      const matrix            box,
@@ -1896,9 +2148,11 @@ static void bonded_distance_intermol(const InteractionLists& ilists_intermol,
 
     set_pbc(&pbc, pbcType, box);
 
+    const ReverseTopOptions rtOptions(ddBondedChecking);
+
     for (int ftype = 0; ftype < F_NRE; ftype++)
     {
-        if (dd_check_ftype(ftype, bBCheck, FALSE, FALSE))
+        if (dd_check_ftype(ftype, rtOptions))
         {
             const auto& il   = ilists_intermol[ftype];
             int         nral = NRAL(ftype);
@@ -1915,13 +2169,12 @@ static void bonded_distance_intermol(const InteractionLists& ilists_intermol,
                     for (int aj = ai + 1; aj < nral; aj++)
                     {
                         rvec dx;
-                        real rij2;
 
                         int atom_j = il.iatoms[i + 1 + aj];
 
                         pbc_dx(&pbc, x[atom_i], x[atom_j], dx);
 
-                        rij2 = norm2(dx);
+                        const real rij2 = norm2(dx);
 
                         update_max_bonded_distance(rij2, ftype, atom_i, atom_j, (nral == 2) ? bd_2b : bd_mb);
                     }
@@ -1955,8 +2208,6 @@ static void getWholeMoleculeCoordinates(const gmx_moltype_t*  molt,
                                         ArrayRef<const RVec>  x,
                                         ArrayRef<RVec>        xs)
 {
-    int n, i;
-
     if (pbcType != PbcType::No)
     {
         mk_mshift(nullptr, graph, pbcType, box, as_rvec_array(x.data()));
@@ -1975,8 +2226,7 @@ static void getWholeMoleculeCoordinates(const gmx_moltype_t*  molt,
          * unchanged, just to be 100% sure that we do not affect
          * binary reproducibility of simulations.
          */
-        n = molt->atoms.nr;
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < molt->atoms.nr; i++)
         {
             copy_rvec(x[i], xs[i]);
         }
@@ -1988,28 +2238,26 @@ static void getWholeMoleculeCoordinates(const gmx_moltype_t*  molt,
     }
 }
 
-void dd_bonded_cg_distance(const gmx::MDLogger& mdlog,
-                           const gmx_mtop_t*    mtop,
-                           const t_inputrec*    ir,
-                           ArrayRef<const RVec> x,
-                           const matrix         box,
-                           gmx_bool             bBCheck,
-                           real*                r_2b,
-                           real*                r_mb)
+void dd_bonded_cg_distance(const gmx::MDLogger&   mdlog,
+                           const gmx_mtop_t&      mtop,
+                           const t_inputrec&      inputrec,
+                           ArrayRef<const RVec>   x,
+                           const matrix           box,
+                           const DDBondedChecking ddBondedChecking,
+                           real*                  r_2b,
+                           real*                  r_mb)
 {
-    gmx_bool          bExclRequired;
-    int               at_offset;
     bonded_distance_t bd_2b = { 0, -1, -1, -1 };
     bonded_distance_t bd_mb = { 0, -1, -1, -1 };
 
-    bExclRequired = inputrecExclForces(ir);
+    bool bExclRequired = inputrecExclForces(&inputrec);
 
-    *r_2b     = 0;
-    *r_mb     = 0;
-    at_offset = 0;
-    for (const gmx_molblock_t& molb : mtop->molblock)
+    *r_2b         = 0;
+    *r_mb         = 0;
+    int at_offset = 0;
+    for (const gmx_molblock_t& molb : mtop.molblock)
     {
-        const gmx_moltype_t& molt = mtop->moltype[molb.type];
+        const gmx_moltype_t& molt = mtop.moltype[molb.type];
         if (molt.atoms.nr == 1 || molb.nmol == 0)
         {
             at_offset += molb.nmol * molt.atoms.nr;
@@ -2017,7 +2265,7 @@ void dd_bonded_cg_distance(const gmx::MDLogger& mdlog,
         else
         {
             t_graph graph;
-            if (ir->pbcType != PbcType::No)
+            if (inputrec.pbcType != PbcType::No)
             {
                 graph = mk_graph_moltype(molt);
             }
@@ -2025,31 +2273,43 @@ void dd_bonded_cg_distance(const gmx::MDLogger& mdlog,
             std::vector<RVec> xs(molt.atoms.nr);
             for (int mol = 0; mol < molb.nmol; mol++)
             {
-                getWholeMoleculeCoordinates(&molt, &mtop->ffparams, ir->pbcType, &graph, box,
-                                            x.subArray(at_offset, molt.atoms.nr), xs);
+                getWholeMoleculeCoordinates(&molt,
+                                            &mtop.ffparams,
+                                            inputrec.pbcType,
+                                            &graph,
+                                            box,
+                                            x.subArray(at_offset, molt.atoms.nr),
+                                            xs);
 
                 bonded_distance_t bd_mol_2b = { 0, -1, -1, -1 };
                 bonded_distance_t bd_mol_mb = { 0, -1, -1, -1 };
 
-                bonded_cg_distance_mol(&molt, bBCheck, bExclRequired, xs, &bd_mol_2b, &bd_mol_mb);
+                bonded_cg_distance_mol(&molt, ddBondedChecking, bExclRequired, xs, &bd_mol_2b, &bd_mol_mb);
 
                 /* Process the mol data adding the atom index offset */
-                update_max_bonded_distance(bd_mol_2b.r2, bd_mol_2b.ftype, at_offset + bd_mol_2b.a1,
-                                           at_offset + bd_mol_2b.a2, &bd_2b);
-                update_max_bonded_distance(bd_mol_mb.r2, bd_mol_mb.ftype, at_offset + bd_mol_mb.a1,
-                                           at_offset + bd_mol_mb.a2, &bd_mb);
+                update_max_bonded_distance(bd_mol_2b.r2,
+                                           bd_mol_2b.ftype,
+                                           at_offset + bd_mol_2b.a1,
+                                           at_offset + bd_mol_2b.a2,
+                                           &bd_2b);
+                update_max_bonded_distance(bd_mol_mb.r2,
+                                           bd_mol_mb.ftype,
+                                           at_offset + bd_mol_mb.a1,
+                                           at_offset + bd_mol_mb.a2,
+                                           &bd_mb);
 
                 at_offset += molt.atoms.nr;
             }
         }
     }
 
-    if (mtop->bIntermolecularInteractions)
+    if (mtop.bIntermolecularInteractions)
     {
-        GMX_RELEASE_ASSERT(mtop->intermolecular_ilist,
+        GMX_RELEASE_ASSERT(mtop.intermolecular_ilist,
                            "We should have an ilist when intermolecular interactions are on");
 
-        bonded_distance_intermol(*mtop->intermolecular_ilist, bBCheck, x, ir->pbcType, box, &bd_2b, &bd_mb);
+        bonded_distance_intermol(
+                *mtop.intermolecular_ilist, ddBondedChecking, x, inputrec.pbcType, box, &bd_2b, &bd_mb);
     }
 
     *r_2b = sqrt(bd_2b.r2);
@@ -2062,16 +2322,21 @@ void dd_bonded_cg_distance(const gmx::MDLogger& mdlog,
         {
             GMX_LOG(mdlog.info)
                     .appendTextFormatted(
-                            "    two-body bonded interactions: %5.3f nm, %s, atoms %d %d", *r_2b,
+                            "    two-body bonded interactions: %5.3f nm, %s, atoms %d %d",
+                            *r_2b,
                             (bd_2b.ftype >= 0) ? interaction_function[bd_2b.ftype].longname : "Exclusion",
-                            bd_2b.a1 + 1, bd_2b.a2 + 1);
+                            bd_2b.a1 + 1,
+                            bd_2b.a2 + 1);
         }
         if (*r_mb > 0)
         {
             GMX_LOG(mdlog.info)
                     .appendTextFormatted(
-                            "  multi-body bonded interactions: %5.3f nm, %s, atoms %d %d", *r_mb,
-                            interaction_function[bd_mb.ftype].longname, bd_mb.a1 + 1, bd_mb.a2 + 1);
+                            "  multi-body bonded interactions: %5.3f nm, %s, atoms %d %d",
+                            *r_mb,
+                            interaction_function[bd_mb.ftype].longname,
+                            bd_mb.a1 + 1,
+                            bd_mb.a2 + 1);
         }
     }
 }
index 0fe374ee45223796bb03b70b152009a7550efa7f..bde62216cac50b28fdcf065a008c61f76da94b23 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2006,2007,2008,2009,2010 by the GROMACS development team.
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -93,6 +93,14 @@ void dd_move_x_vsites(const gmx_domdec_t& dd, const matrix box, rvec* x)
     }
 }
 
+void dd_move_x_and_v_vsites(const gmx_domdec_t& dd, const matrix box, rvec* x, rvec* v)
+{
+    if (dd.vsite_comm)
+    {
+        dd_move_x_specat(&dd, dd.vsite_comm, box, x, v, FALSE);
+    }
+}
+
 void dd_clear_local_vsite_indices(gmx_domdec_t* dd)
 {
     if (dd->vsite_comm)
@@ -142,8 +150,8 @@ int dd_make_local_vsites(gmx_domdec_t* dd, int at_start, gmx::ArrayRef<Interacti
         }
     }
 
-    int at_end = setup_specat_communication(dd, &ireq, dd->vsite_comm, ga2la_specat, at_start, 1,
-                                            "vsite", "");
+    int at_end = setup_specat_communication(
+            dd, &ireq, dd->vsite_comm, ga2la_specat, at_start, 2, "vsite", "");
 
     /* Fill in the missing indices */
     for (int ftype = 0; ftype < F_NRE; ftype++)
index c3f7eaad13a8d541419432038697c88943cb1055..7a7324cd4ab68f4ea86d63f4cbae00c24a7b0475 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +119,21 @@ void write_dd_grid_pdb(const char* fn, int64_t step, gmx_domdec_t* dd, matrix bo
                         cx[YY] = grid_r[i * 2 + y][YY];
                         cx[ZZ] = grid_r[i * 2 + z][ZZ];
                         mvmul(tric, cx, r);
-                        gmx_fprintf_pdb_atomline(out, epdbATOM, a++, "CA", ' ', "GLY", ' ', i + 1, ' ',
-                                                 10 * r[XX], 10 * r[YY], 10 * r[ZZ], 1.0, vol, "");
+                        gmx_fprintf_pdb_atomline(out,
+                                                 PdbRecordType::Atom,
+                                                 a++,
+                                                 "CA",
+                                                 ' ',
+                                                 "GLY",
+                                                 ' ',
+                                                 i + 1,
+                                                 ' ',
+                                                 10 * r[XX],
+                                                 10 * r[YY],
+                                                 10 * r[ZZ],
+                                                 1.0,
+                                                 vol,
+                                                 "");
                     }
                 }
             }
@@ -146,7 +159,7 @@ void write_dd_grid_pdb(const char* fn, int64_t step, gmx_domdec_t* dd, matrix bo
 void write_dd_pdb(const char*       fn,
                   int64_t           step,
                   const char*       title,
-                  const gmx_mtop_t* mtop,
+                  const gmx_mtop_t& mtop,
                   const t_commrec*  cr,
                   int               natoms,
                   const rvec        x[],
@@ -194,8 +207,21 @@ void write_dd_pdb(const char*       fn,
         {
             b = dd->comm->zones.n + 1;
         }
-        gmx_fprintf_pdb_atomline(out, epdbATOM, ii + 1, atomname, ' ', resname, ' ', resnr, ' ',
-                                 10 * x[i][XX], 10 * x[i][YY], 10 * x[i][ZZ], 1.0, b, "");
+        gmx_fprintf_pdb_atomline(out,
+                                 PdbRecordType::Atom,
+                                 ii + 1,
+                                 atomname,
+                                 ' ',
+                                 resname,
+                                 ' ',
+                                 resnr,
+                                 ' ',
+                                 10 * x[i][XX],
+                                 10 * x[i][YY],
+                                 10 * x[i][ZZ],
+                                 1.0,
+                                 b,
+                                 "");
     }
     fprintf(out, "TER\n");
 
index fabc6a588732af6fd03fc264a0973d10dc02db3d..01c004a4203a04ac02b05f43e57d2c227a96bb56 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 @@ void write_dd_grid_pdb(const char* fn, int64_t step, gmx_domdec_t* dd, matrix bo
 void write_dd_pdb(const char*       fn,
                   int64_t           step,
                   const char*       title,
-                  const gmx_mtop_t* mtop,
+                  const gmx_mtop_t& mtop,
                   const t_commrec*  cr,
                   int               natoms,
                   const rvec        x[],
index be4a3abc8ffbbb9853499f98aade6594f9e02d8f..adc8d667127fe4f0c14361d8fd4f4c529e052ce1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_DOMDEC_GPUHALOEXCHANGE_H
 #define GMX_DOMDEC_GPUHALOEXCHANGE_H
 
+#include <memory>
+
 #include "gromacs/gpu_utils/devicebuffer_datatype.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/gmxmpi.h"
 
 struct gmx_domdec_t;
@@ -73,8 +74,7 @@ public:
      * after the local coordinates buffer operations (where the
      * coordinates are copied to the device and hence the \c
      * coordinatesReadyOnDeviceEvent is recorded). Force Halo exchange
-     * will be performed in \c streamNonLocal (also potentally
-     * with buffer clearing in \c streamLocal)and the \c
+     * will be performed in \c streamNonLocal and the \c
      * communicateHaloForces method must be called after the
      * non-local buffer operations, after the local force buffer
      * has been copied to the GPU (if CPU forces are present), and
@@ -133,7 +133,7 @@ public:
 
 private:
     class Impl;
-    gmx::PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 8b84aa985b41746fef55d8e801a50d2dc958919e..f32a95bae7b8d9a1e331cc4f19cf96afe317f8e9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -134,8 +134,8 @@ __global__ void unpackRecvBufKernel(float3* __restrict__ data,
 
 void GpuHaloExchange::Impl::reinitHalo(float3* d_coordinatesBuffer, float3* d_forcesBuffer)
 {
-    wallcycle_start(wcycle_, ewcDOMDEC);
-    wallcycle_sub_start(wcycle_, ewcsDD_GPU);
+    wallcycle_start(wcycle_, WallCycleCounter::Domdec);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::DDGpu);
 
     d_x_ = d_coordinatesBuffer;
     d_f_ = d_forcesBuffer;
@@ -180,8 +180,18 @@ void GpuHaloExchange::Impl::reinitHalo(float3* d_coordinatesBuffer, float3* d_fo
 
     xSendSize_ = newSize;
 #if GMX_MPI
-    MPI_Sendrecv(&xSendSize_, sizeof(int), MPI_BYTE, sendRankX_, 0, &xRecvSize_, sizeof(int),
-                 MPI_BYTE, recvRankX_, 0, mpi_comm_mysim_, MPI_STATUS_IGNORE);
+    MPI_Sendrecv(&xSendSize_,
+                 sizeof(int),
+                 MPI_BYTE,
+                 sendRankX_,
+                 0,
+                 &xRecvSize_,
+                 sizeof(int),
+                 MPI_BYTE,
+                 recvRankX_,
+                 0,
+                 mpi_comm_mysim_,
+                 MPI_STATUS_IGNORE);
 #endif
     fSendSize_ = xRecvSize_;
     fRecvSize_ = xSendSize_;
@@ -193,44 +203,94 @@ void GpuHaloExchange::Impl::reinitHalo(float3* d_coordinatesBuffer, float3* d_fo
                    "halo exchange index mapping array");
         std::copy(ind.index.begin(), ind.index.end(), h_indexMap_.begin());
 
-        copyToDeviceBuffer(&d_indexMap_, h_indexMap_.data(), 0, newSize, nonLocalStream_,
-                           GpuApiCallBehavior::Async, nullptr);
+        copyToDeviceBuffer(
+                &d_indexMap_, h_indexMap_.data(), 0, newSize, nonLocalStream_, GpuApiCallBehavior::Async, nullptr);
     }
-    // This rank will push data to its neighbor, so needs to know
-    // the remote receive address and similarly send its receive
-    // address to other neighbour. We can do this here in reinit fn
-    // since the pointers will not change until the next NS step.
 
-    // Coordinates buffer:
-    void* recvPtr = static_cast<void*>(&d_x_[atomOffset_]);
 #if GMX_MPI
-    MPI_Sendrecv(&recvPtr, sizeof(void*), MPI_BYTE, recvRankX_, 0, &remoteXPtr_, sizeof(void*),
-                 MPI_BYTE, sendRankX_, 0, mpi_comm_mysim_, MPI_STATUS_IGNORE);
-
-    // Force buffer:
-    recvPtr = static_cast<void*>(d_recvBuf_);
-    MPI_Sendrecv(&recvPtr, sizeof(void*), MPI_BYTE, recvRankF_, 0, &remoteFPtr_, sizeof(void*),
-                 MPI_BYTE, sendRankF_, 0, mpi_comm_mysim_, MPI_STATUS_IGNORE);
+    // Exchange of remote addresses from neighboring ranks is needed only with CUDA-direct as cudamemcpy needs both src/dst pointer
+    // MPI calls such as MPI_send doesn't worry about receiving address, that is taken care by MPI_recv call in neighboring rank
+    if (GMX_THREAD_MPI)
+    {
+        // This rank will push data to its neighbor, so needs to know
+        // the remote receive address and similarly send its receive
+        // address to other neighbour. We can do this here in reinit fn
+        // since the pointers will not change until the next NS step.
+
+        // Coordinates buffer:
+        float3* recvPtr = &d_x_[atomOffset_];
+        MPI_Sendrecv(&recvPtr,
+                     sizeof(void*),
+                     MPI_BYTE,
+                     recvRankX_,
+                     0,
+                     &remoteXPtr_,
+                     sizeof(void*),
+                     MPI_BYTE,
+                     sendRankX_,
+                     0,
+                     mpi_comm_mysim_,
+                     MPI_STATUS_IGNORE);
+
+        // Force buffer:
+        recvPtr = d_recvBuf_;
+        MPI_Sendrecv(&recvPtr,
+                     sizeof(void*),
+                     MPI_BYTE,
+                     recvRankF_,
+                     0,
+                     &remoteFPtr_,
+                     sizeof(void*),
+                     MPI_BYTE,
+                     sendRankF_,
+                     0,
+                     mpi_comm_mysim_,
+                     MPI_STATUS_IGNORE);
+    }
 #endif
 
-    wallcycle_sub_stop(wcycle_, ewcsDD_GPU);
-    wallcycle_stop(wcycle_, ewcDOMDEC);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::DDGpu);
+    wallcycle_stop(wcycle_, WallCycleCounter::Domdec);
 
     return;
 }
 
+void GpuHaloExchange::Impl::enqueueWaitRemoteCoordinatesReadyEvent(GpuEventSynchronizer* coordinatesReadyOnDeviceEvent)
+{
+    GMX_ASSERT(coordinatesReadyOnDeviceEvent != nullptr,
+               "Co-ordinate Halo exchange requires valid co-ordinate ready event");
+
+    // Wait for event from receiving task that remote coordinates are ready, and enqueue that event to stream used
+    // for subsequent data push. This avoids a race condition with the remote data being written in the previous timestep.
+    // Similarly send event to task that will push data to this task.
+    GpuEventSynchronizer* remoteCoordinatesReadyOnDeviceEvent;
+    MPI_Sendrecv(&coordinatesReadyOnDeviceEvent,
+                 sizeof(GpuEventSynchronizer*),
+                 MPI_BYTE,
+                 recvRankX_,
+                 0,
+                 &remoteCoordinatesReadyOnDeviceEvent,
+                 sizeof(GpuEventSynchronizer*),
+                 MPI_BYTE,
+                 sendRankX_,
+                 0,
+                 mpi_comm_mysim_,
+                 MPI_STATUS_IGNORE);
+    remoteCoordinatesReadyOnDeviceEvent->enqueueWaitEvent(nonLocalStream_);
+}
+
 void GpuHaloExchange::Impl::communicateHaloCoordinates(const matrix          box,
                                                        GpuEventSynchronizer* coordinatesReadyOnDeviceEvent)
 {
 
-    wallcycle_start(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_start(wcycle_, WallCycleCounter::LaunchGpu);
     if (pulse_ == 0)
     {
         // ensure stream waits until coordinate data is available on device
         coordinatesReadyOnDeviceEvent->enqueueWaitEvent(nonLocalStream_);
     }
 
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_GPU_MOVEX);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchGpuMoveX);
 
     // launch kernel to pack send buffer
     KernelLaunchConfig config;
@@ -252,7 +312,8 @@ void GpuHaloExchange::Impl::communicateHaloCoordinates(const matrix          box
     // is used every step to pass the shift vector as an argument of
     // the packing kernel.
     const int    boxDimensionIndex = dd_->dim[dimIndex_];
-    const float3 coordinateShift{ box[boxDimensionIndex][XX], box[boxDimensionIndex][YY],
+    const float3 coordinateShift{ box[boxDimensionIndex][XX],
+                                  box[boxDimensionIndex][YY],
                                   box[boxDimensionIndex][ZZ] };
 
     // Avoid launching kernel when there is no work to do
@@ -260,23 +321,31 @@ void GpuHaloExchange::Impl::communicateHaloCoordinates(const matrix          box
     {
         auto kernelFn = usePBC_ ? packSendBufKernel<true> : packSendBufKernel<false>;
 
-        const auto kernelArgs = prepareGpuKernelArguments(kernelFn, config, &sendBuf, &d_x,
-                                                          &indexMap, &size, &coordinateShift);
+        const auto kernelArgs = prepareGpuKernelArguments(
+                kernelFn, config, &sendBuf, &d_x, &indexMap, &size, &coordinateShift);
 
-        launchGpuKernel(kernelFn, config, nonLocalStream_, nullptr,
-                        "Domdec GPU Apply X Halo Exchange", kernelArgs);
+        launchGpuKernel(
+                kernelFn, config, nonLocalStream_, nullptr, "Domdec GPU Apply X Halo Exchange", kernelArgs);
     }
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_GPU_MOVEX);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchGpuMoveX);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 
     // Consider time spent in communicateHaloData as Comm.X counter
     // ToDo: We need further refinement here as communicateHaloData includes launch time for cudamemcpyasync
-    wallcycle_start(wcycle_, ewcMOVEX);
+    wallcycle_start(wcycle_, WallCycleCounter::MoveX);
+
+    // wait for remote co-ordinates is implicit with process-MPI as non-local stream is synchronized before MPI calls
+    // and MPI_Waitall call makes sure both neighboring ranks' non-local stream is synchronized before data transfer is initiated
+    if (GMX_THREAD_MPI && pulse_ == 0)
+    {
+        enqueueWaitRemoteCoordinatesReadyEvent(coordinatesReadyOnDeviceEvent);
+    }
 
-    communicateHaloData(d_x_, HaloQuantity::HaloCoordinates, coordinatesReadyOnDeviceEvent);
+    float3* recvPtr = GMX_THREAD_MPI ? remoteXPtr_ : &d_x_[atomOffset_];
+    communicateHaloData(d_sendBuf_, xSendSize_, sendRankX_, recvPtr, xRecvSize_, recvRankX_);
 
-    wallcycle_stop(wcycle_, ewcMOVEX);
+    wallcycle_stop(wcycle_, WallCycleCounter::MoveX);
 
     return;
 }
@@ -287,15 +356,17 @@ void GpuHaloExchange::Impl::communicateHaloForces(bool accumulateForces)
 {
     // Consider time spent in communicateHaloData as Comm.F counter
     // ToDo: We need further refinement here as communicateHaloData includes launch time for cudamemcpyasync
-    wallcycle_start(wcycle_, ewcMOVEF);
+    wallcycle_start(wcycle_, WallCycleCounter::MoveF);
+
+    float3* recvPtr = GMX_THREAD_MPI ? remoteFPtr_ : d_recvBuf_;
 
     // Communicate halo data (in non-local stream)
-    communicateHaloData(d_f_, HaloQuantity::HaloForces, nullptr);
+    communicateHaloData(&(d_f_[atomOffset_]), fSendSize_, sendRankF_, recvPtr, fRecvSize_, recvRankF_);
 
-    wallcycle_stop(wcycle_, ewcMOVEF);
+    wallcycle_stop(wcycle_, WallCycleCounter::MoveF);
 
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_GPU_MOVEF);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchGpuMoveF);
 
     float3* d_f = d_f_;
     // If this is the last pulse and index (noting the force halo
@@ -304,16 +375,9 @@ void GpuHaloExchange::Impl::communicateHaloForces(bool accumulateForces)
     // activities
     if ((pulse_ == (dd_->comm->cd[dimIndex_].numPulses() - 1)) && (dimIndex_ == (dd_->ndim - 1)))
     {
-        if (!accumulateForces)
-        {
-            // Clear local portion of force array (in local stream)
-            cudaMemsetAsync(d_f, 0, numHomeAtoms_ * sizeof(rvec), localStream_.stream());
-        }
-
         // ensure non-local stream waits for local stream, due to dependence on
         // the previous H2D copy of CPU forces (if accumulateForces is true)
-        // or the above clearing.
-        // TODO remove this dependency on localStream - edmine Issue #3093
+        // or local force clearing.
         GpuEventSynchronizer eventLocal;
         eventLocal.markEvent(localStream_);
         eventLocal.enqueueWaitEvent(nonLocalStream_);
@@ -349,8 +413,8 @@ void GpuHaloExchange::Impl::communicateHaloForces(bool accumulateForces)
         const auto kernelArgs =
                 prepareGpuKernelArguments(kernelFn, config, &d_f, &recvBuf, &indexMap, &size);
 
-        launchGpuKernel(kernelFn, config, nonLocalStream_, nullptr,
-                        "Domdec GPU Apply F Halo Exchange", kernelArgs);
+        launchGpuKernel(
+                kernelFn, config, nonLocalStream_, nullptr, "Domdec GPU Apply F Halo Exchange", kernelArgs);
     }
 
     if (pulse_ == 0)
@@ -358,60 +422,66 @@ void GpuHaloExchange::Impl::communicateHaloForces(bool accumulateForces)
         fReadyOnDevice_.markEvent(nonLocalStream_);
     }
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_GPU_MOVEF);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchGpuMoveF);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
-
-void GpuHaloExchange::Impl::communicateHaloData(float3*               d_ptr,
-                                                HaloQuantity          haloQuantity,
-                                                GpuEventSynchronizer* coordinatesReadyOnDeviceEvent)
+void GpuHaloExchange::Impl::communicateHaloData(float3* sendPtr,
+                                                int     sendSize,
+                                                int     sendRank,
+                                                float3* recvPtr,
+                                                int     recvSize,
+                                                int     recvRank)
 {
-
-    void* sendPtr;
-    int   sendSize;
-    void* remotePtr;
-    int   sendRank;
-    int   recvRank;
-
-    if (haloQuantity == HaloQuantity::HaloCoordinates)
+    if (GMX_THREAD_MPI)
     {
-        sendPtr   = static_cast<void*>(d_sendBuf_);
-        sendSize  = xSendSize_;
-        remotePtr = remoteXPtr_;
-        sendRank  = sendRankX_;
-        recvRank  = recvRankX_;
-
-#if GMX_MPI
-        // Wait for event from receiving task that remote coordinates are ready, and enqueue that event to stream used
-        // for subsequent data push. This avoids a race condition with the remote data being written in the previous timestep.
-        // Similarly send event to task that will push data to this task.
-        GpuEventSynchronizer* remoteCoordinatesReadyOnDeviceEvent;
-        MPI_Sendrecv(&coordinatesReadyOnDeviceEvent, sizeof(GpuEventSynchronizer*), MPI_BYTE,
-                     recvRank, 0, &remoteCoordinatesReadyOnDeviceEvent, sizeof(GpuEventSynchronizer*),
-                     MPI_BYTE, sendRank, 0, mpi_comm_mysim_, MPI_STATUS_IGNORE);
-        remoteCoordinatesReadyOnDeviceEvent->enqueueWaitEvent(nonLocalStream_);
-#else
-        GMX_UNUSED_VALUE(coordinatesReadyOnDeviceEvent);
-#endif
+        // no need to explicitly sync with GMX_THREAD_MPI as all operations are
+        // anyway launched in correct stream
+        communicateHaloDataWithCudaDirect(sendPtr, sendSize, sendRank, recvPtr, recvRank);
     }
     else
     {
-        sendPtr   = static_cast<void*>(&(d_ptr[atomOffset_]));
-        sendSize  = fSendSize_;
-        remotePtr = remoteFPtr_;
-        sendRank  = sendRankF_;
-        recvRank  = recvRankF_;
+        communicateHaloDataWithCudaMPI(sendPtr, sendSize, sendRank, recvPtr, recvSize, recvRank);
     }
+}
 
-    communicateHaloDataWithCudaDirect(sendPtr, sendSize, sendRank, remotePtr, recvRank);
+void GpuHaloExchange::Impl::communicateHaloDataWithCudaMPI(float3* sendPtr,
+                                                           int     sendSize,
+                                                           int     sendRank,
+                                                           float3* recvPtr,
+                                                           int     recvSize,
+                                                           int     recvRank)
+{
+    // no need to wait for haloDataReadyOnDevice event if this rank is not sending any data
+    if (sendSize > 0)
+    {
+        // wait for non local stream to complete all outstanding
+        // activities, to ensure that buffer is up-to-date in GPU memory
+        // before transferring to remote rank
+
+        // ToDo: Replace stream synchronize with event synchronize
+        nonLocalStream_.synchronize();
+    }
+
+    // perform halo exchange directly in device buffers
+#if GMX_MPI
+    MPI_Request request;
+
+    // recv remote data into halo region
+    MPI_Irecv(recvPtr, recvSize * DIM, MPI_FLOAT, recvRank, 0, mpi_comm_mysim_, &request);
+
+    // send data to remote halo region
+    MPI_Send(sendPtr, sendSize * DIM, MPI_FLOAT, sendRank, 0, mpi_comm_mysim_);
+
+    MPI_Wait(&request, MPI_STATUS_IGNORE);
+#endif
 }
 
-void GpuHaloExchange::Impl::communicateHaloDataWithCudaDirect(void* sendPtr,
-                                                              int   sendSize,
-                                                              int   sendRank,
-                                                              void* remotePtr,
-                                                              int   recvRank)
+void GpuHaloExchange::Impl::communicateHaloDataWithCudaDirect(float3* sendPtr,
+                                                              int     sendSize,
+                                                              int     sendRank,
+                                                              float3* remotePtr,
+                                                              int     recvRank)
 {
 
     cudaError_t stat;
@@ -425,8 +495,11 @@ void GpuHaloExchange::Impl::communicateHaloDataWithCudaDirect(void* sendPtr,
     // send data to neighbor, if any data exists to send
     if (sendSize > 0)
     {
-        stat = cudaMemcpyAsync(remotePtr, sendPtr, sendSize * DIM * sizeof(float),
-                               cudaMemcpyDeviceToDevice, nonLocalStream_.stream());
+        stat = cudaMemcpyAsync(remotePtr,
+                               sendPtr,
+                               sendSize * DIM * sizeof(float),
+                               cudaMemcpyDeviceToDevice,
+                               nonLocalStream_.stream());
 
         CU_RET_ERR(stat, "cudaMemcpyAsync on GPU Domdec CUDA direct data transfer failed");
     }
@@ -438,11 +511,23 @@ void GpuHaloExchange::Impl::communicateHaloDataWithCudaDirect(void* sendPtr,
     // to its stream.
     GpuEventSynchronizer* haloDataTransferRemote;
 
+    GMX_ASSERT(haloDataTransferLaunched_ != nullptr,
+               "Halo exchange requires valid event to synchronize data transfer initiated in "
+               "remote rank");
     haloDataTransferLaunched_->markEvent(nonLocalStream_);
 
-    MPI_Sendrecv(&haloDataTransferLaunched_, sizeof(GpuEventSynchronizer*), MPI_BYTE, sendRank, 0,
-                 &haloDataTransferRemote, sizeof(GpuEventSynchronizer*), MPI_BYTE, recvRank, 0,
-                 mpi_comm_mysim_, MPI_STATUS_IGNORE);
+    MPI_Sendrecv(&haloDataTransferLaunched_,
+                 sizeof(GpuEventSynchronizer*),
+                 MPI_BYTE,
+                 sendRank,
+                 0,
+                 &haloDataTransferRemote,
+                 sizeof(GpuEventSynchronizer*),
+                 MPI_BYTE,
+                 recvRank,
+                 0,
+                 mpi_comm_mysim_,
+                 MPI_STATUS_IGNORE);
 
     haloDataTransferRemote->enqueueWaitEvent(nonLocalStream_);
 #else
@@ -471,7 +556,7 @@ GpuHaloExchange::Impl::Impl(gmx_domdec_t*        dd,
     sendRankF_(dd->neighbor[dimIndex][0]),
     recvRankF_(dd->neighbor[dimIndex][1]),
     usePBC_(dd->ci[dd->dim[dimIndex]] == 0),
-    haloDataTransferLaunched_(new GpuEventSynchronizer()),
+    haloDataTransferLaunched_(GMX_THREAD_MPI ? new GpuEventSynchronizer() : nullptr),
     mpi_comm_mysim_(mpi_comm_mysim),
     deviceContext_(deviceContext),
     localStream_(localStream),
@@ -480,10 +565,6 @@ GpuHaloExchange::Impl::Impl(gmx_domdec_t*        dd,
     pulse_(pulse),
     wcycle_(wcycle)
 {
-
-    GMX_RELEASE_ASSERT(GMX_THREAD_MPI,
-                       "GPU Halo exchange is currently only supported with thread-MPI enabled");
-
     if (usePBC_ && dd->unitCellInfo.haveScrewPBC)
     {
         gmx_fatal(FARGS, "Error: screw is not yet supported in GPU halo exchange\n");
index 5dd619a343fe5827e93c0a9103dd2d47588734f1..89ee12a2ea5edb20efd355a20eb5b2acd1dda800 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -117,22 +117,43 @@ public:
 
 private:
     /*! \brief Data transfer wrapper for GPU halo exchange
-     * \param [inout] d_ptr      pointer to coordinates or force buffer in GPU memory
-     * \param [in] haloQuantity  switch on whether X or F halo exchange is being performed
-     * \param [in] coordinatesReadyOnDeviceEvent event recorded when coordinates have been copied to device
+     * \param [in] sendPtr      send buffer address
+     * \param [in] sendSize     number of elements to send
+     * \param [in] sendRank     rank of destination
+     * \param [in] recvPtr      receive buffer address
+     * \param [in] recvSize     number of elements to receive
+     * \param [in] recvRank     rank of source
      */
-    void communicateHaloData(float3*               d_ptr,
-                             HaloQuantity          haloQuantity,
-                             GpuEventSynchronizer* coordinatesReadyOnDeviceEvent);
+    void communicateHaloData(float3* sendPtr, int sendSize, int sendRank, float3* recvPtr, int recvSize, int recvRank);
 
     /*! \brief Data transfer for GPU halo exchange using CUDA memcopies
      * \param [inout] sendPtr    address to send data from
      * \param [in] sendSize      number of atoms to be sent
      * \param [in] sendRank      rank to send data to
-     * \param [inout] remotePtr  remote address to recv data
+     * \param [in] remotePtr     remote address to recv data
      * \param [in] recvRank      rank to recv data from
      */
-    void communicateHaloDataWithCudaDirect(void* sendPtr, int sendSize, int sendRank, void* remotePtr, int recvRank);
+    void communicateHaloDataWithCudaDirect(float3* sendPtr, int sendSize, int sendRank, float3* remotePtr, int recvRank);
+
+    /*! \brief Data transfer wrapper for GPU halo exchange using MPI_send and MPI_Recv
+     * \param [in] sendPtr      send buffer address
+     * \param [in] sendSize     number of elements to send
+     * \param [in] sendRank     rank of destination
+     * \param [in] recvPtr      receive buffer address
+     * \param [in] recvSize     number of elements to receive
+     * \param [in] recvRank     rank of source
+     */
+    void communicateHaloDataWithCudaMPI(float3* sendPtr,
+                                        int     sendSize,
+                                        int     sendRank,
+                                        float3* recvPtr,
+                                        int     recvSize,
+                                        int     recvRank);
+
+    /*! \brief Exchange coordinate-ready event with neighbor ranks and enqueue wait in non-local
+     * stream \param [in] eventSync    event recorded when coordinates/forces are ready to device
+     */
+    void enqueueWaitRemoteCoordinatesReadyEvent(GpuEventSynchronizer* coordinatesReadyOnDeviceEvent);
 
     //! Domain decomposition object
     gmx_domdec_t* dd_ = nullptr;
@@ -177,9 +198,9 @@ private:
     //! number of home atoms - offset of local halo region
     int numHomeAtoms_ = 0;
     //! remote GPU coordinates buffer pointer for pushing data
-    void* remoteXPtr_ = nullptr;
+    float3* remoteXPtr_ = nullptr;
     //! remote GPU force buffer pointer for pushing data
-    void* remoteFPtr_ = nullptr;
+    float3* remoteFPtr_ = nullptr;
     //! Periodic Boundary Conditions for this rank
     bool usePBC_ = false;
     //! force shift buffer on device
index bff851974512d261e04e2f0107a088587e47906f..497efd7ee6305e9f4f478cca7d3bb617c99dfdaa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <memory>
 
 #include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/classhelpers.h"
 
 class gmx_ga2la_t;
 
@@ -102,7 +101,7 @@ public:
 
 private:
     class Impl;
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 90f28d18a77bc64e8ea5fcc0c6f6c39caf8e47a0..ead9a61fd1c67f6c38f66624a9253ce24e5216e7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +52,7 @@
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
 
@@ -64,7 +65,7 @@ namespace gmx
  * for initialization and atom-data setup.
  */
 void mdAlgorithmsSetupAtomData(const t_commrec*     cr,
-                               const t_inputrec*    ir,
+                               const t_inputrec&    inputrec,
                                const gmx_mtop_t&    top_global,
                                gmx_localtop_t*      top,
                                t_forcerec*          fr,
@@ -82,9 +83,9 @@ void mdAlgorithmsSetupAtomData(const t_commrec*     cr,
 
     if (usingDomDec)
     {
-        numAtomIndex  = dd_natoms_mdatoms(cr->dd);
+        numAtomIndex  = dd_natoms_mdatoms(*cr->dd);
         numHomeAtoms  = dd_numHomeAtoms(*cr->dd);
-        numTotalAtoms = dd_natoms_mdatoms(cr->dd);
+        numTotalAtoms = dd_natoms_mdatoms(*cr->dd);
     }
     else
     {
@@ -98,22 +99,29 @@ void mdAlgorithmsSetupAtomData(const t_commrec*     cr,
         force->resize(numTotalAtoms);
     }
 
-    atoms2md(&top_global, ir, numAtomIndex,
-             usingDomDec ? cr->dd->globalAtomIndices : std::vector<int>(), numHomeAtoms, mdAtoms);
+    atoms2md(top_global,
+             inputrec,
+             numAtomIndex,
+             usingDomDec ? cr->dd->globalAtomIndices : std::vector<int>(),
+             numHomeAtoms,
+             mdAtoms);
 
-    auto mdatoms = mdAtoms->mdatoms();
+    t_mdatoms* mdatoms = mdAtoms->mdatoms();
     if (usingDomDec)
     {
-        dd_sort_local_top(cr->dd, mdatoms, top);
+        dd_sort_local_top(*cr->dd, mdatoms, top);
     }
     else
     {
-        gmx_mtop_generate_local_top(top_global, top, ir->efep != efepNO);
+        gmx_mtop_generate_local_top(top_global, top, inputrec.efep != FreeEnergyPerturbationType::No);
     }
 
     if (vsite)
     {
-        vsite->setVirtualSites(top->idef.il, *mdatoms);
+        vsite->setVirtualSites(top->idef.il,
+                               mdatoms->nr,
+                               mdatoms->homenr,
+                               gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr));
     }
 
     /* Note that with DD only flexible constraints, not shells, are supported
@@ -124,7 +132,7 @@ void mdAlgorithmsSetupAtomData(const t_commrec*     cr,
      */
     if (!usingDomDec && shellfc)
     {
-        make_local_shells(cr, mdatoms, shellfc);
+        make_local_shells(cr, *mdatoms, shellfc);
     }
 
     for (auto& listedForces : fr->listedForces)
@@ -138,13 +146,25 @@ void mdAlgorithmsSetupAtomData(const t_commrec*     cr,
          * For PME-only ranks, gmx_pmeonly() has its own call to gmx_pme_reinit_atoms().
          */
         const int numPmeAtoms = numHomeAtoms - fr->n_tpi;
-        gmx_pme_reinit_atoms(fr->pmedata, numPmeAtoms, mdatoms->chargeA, mdatoms->chargeB);
+        gmx_pme_reinit_atoms(fr->pmedata,
+                             numPmeAtoms,
+                             mdatoms->chargeA ? gmx::arrayRefFromArray(mdatoms->chargeA, mdatoms->nr)
+                                              : gmx::ArrayRef<real>{},
+                             mdatoms->chargeB ? gmx::arrayRefFromArray(mdatoms->chargeB, mdatoms->nr)
+                                              : gmx::ArrayRef<real>{});
     }
 
     if (constr)
     {
-        constr->setConstraints(top, mdatoms->nr, mdatoms->homenr, mdatoms->massT, mdatoms->invmass,
-                               mdatoms->nMassPerturbed != 0, mdatoms->lambda, mdatoms->cFREEZE);
+        constr->setConstraints(top,
+                               mdatoms->nr,
+                               mdatoms->homenr,
+                               gmx::arrayRefFromArray(mdatoms->massT, mdatoms->nr),
+                               gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
+                               mdatoms->nMassPerturbed != 0,
+                               mdatoms->lambda,
+                               mdatoms->cFREEZE ? gmx::arrayRefFromArray(mdatoms->cFREEZE, mdatoms->nr)
+                                                : gmx::ArrayRef<const unsigned short>());
     }
 }
 
index ab0da8fcf16f398beeace4c119e42ea610c462a9..0023b797c93983fbee2d2eb564b07f3f287587d7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 VirtualSitesHandler;
  * \param[in]     md        The MD atom data
  * \param[in,out] shfc      The shell/flexible-constraint data
  */
-void make_local_shells(const t_commrec* cr, const t_mdatoms* md, gmx_shellfc_t* shfc);
+void make_local_shells(const t_commrec* cr, const t_mdatoms& md, gmx_shellfc_t* shfc);
 
 /*! \brief Sets atom data for several MD algorithms
  *
@@ -77,7 +77,7 @@ void make_local_shells(const t_commrec* cr, const t_mdatoms* md, gmx_shellfc_t*
  * 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]     inputrec   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
@@ -88,7 +88,7 @@ void make_local_shells(const t_commrec* cr, const t_mdatoms* md, gmx_shellfc_t*
  * \param[in,out] shellfc    The shell/flexible-constraint data, can be NULL
  */
 void mdAlgorithmsSetupAtomData(const t_commrec*     cr,
-                               const t_inputrec*    ir,
+                               const t_inputrec&    inputrec,
                                const gmx_mtop_t&    top_global,
                                gmx_localtop_t*      top,
                                t_forcerec*          fr,
diff --git a/src/gromacs/domdec/nsgrid.cpp b/src/gromacs/domdec/nsgrid.cpp
new file mode 100644 (file)
index 0000000..8506189
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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,2017,2018 by the GROMACS development team.
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 "nsgrid.h"
+
+#include <cmath>
+#include <cstdio>
+
+#include "gromacs/domdec/dlb.h"
+#include "gromacs/domdec/domdec.h"
+#include "gromacs/domdec/domdec_struct.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/utility/fatalerror.h"
+
+/*! \brief The extent of the neighborsearch grid is a bit larger than sqrt(3)
+ * to account for less dense regions at the edges of the system.
+ */
+constexpr real c_stdDevFactor = 2.0;
+
+/***********************************
+ *         Grid Routines
+ ***********************************/
+
+static void calc_x_av_stddev(int n, rvec* x, rvec av, rvec stddev)
+{
+    dvec s1, s2;
+    int  i, d;
+
+    clear_dvec(s1);
+    clear_dvec(s2);
+
+    for (i = 0; i < n; i++)
+    {
+        for (d = 0; d < DIM; d++)
+        {
+            s1[d] += x[i][d];
+            s2[d] += x[i][d] * x[i][d];
+        }
+    }
+
+    dsvmul(1.0 / n, s1, s1);
+    dsvmul(1.0 / n, s2, s2);
+
+    for (d = 0; d < DIM; d++)
+    {
+        av[d]     = s1[d];
+        stddev[d] = std::sqrt(s2[d] - s1[d] * s1[d]);
+    }
+}
+
+static void get_nsgrid_boundaries_vac(real av, real stddev, real* bound0, real* bound1, real* bdens0, real* bdens1)
+{
+    /* Set the grid to 2 times the standard deviation of
+     * the charge group centers in both directions.
+     * For a uniform bounded distribution the width is sqrt(3)*stddev,
+     * so all charge groups fall within the width.
+     * For a sphere stddev is r/sqrt(5): 99.2% falls within the width.
+     * For a Gaussian distribution 98% fall within the width.
+     */
+    *bound0 = av - c_stdDevFactor * stddev;
+    *bound1 = av + c_stdDevFactor * stddev;
+
+    *bdens0 = av - c_gridStdDevFactor * stddev;
+    *bdens1 = av + c_gridStdDevFactor * stddev;
+}
+
+static void dd_box_bounds_to_ns_bounds(real box0, real box_size, real* gr0, real* gr1)
+{
+    real av, stddev;
+
+    /* Redetermine av and stddev from the DD box boundaries */
+    av     = box0 + 0.5 * box_size;
+    stddev = 0.5 * box_size / c_gridStdDevFactor;
+
+    *gr0 = av - c_stdDevFactor * stddev;
+    *gr1 = av + c_stdDevFactor * stddev;
+}
+
+void get_nsgrid_boundaries(int           nboundeddim,
+                           matrix        box,
+                           gmx_domdec_t* dd,
+                           gmx_ddbox_t*  ddbox,
+                           gmx::RVec*    gr0,
+                           gmx::RVec*    gr1,
+                           int           ncg,
+                           rvec*         cgcm,
+                           rvec          grid_x0,
+                           rvec          grid_x1)
+{
+    rvec av, stddev;
+    real vol, bdens0, bdens1;
+    int  d;
+
+    if (nboundeddim < DIM)
+    {
+        calc_x_av_stddev(ncg, cgcm, av, stddev);
+    }
+
+    vol = 1;
+    for (d = 0; d < DIM; d++)
+    {
+        if (d < nboundeddim)
+        {
+            grid_x0[d] = (gr0 != nullptr ? (*gr0)[d] : 0);
+            grid_x1[d] = (gr1 != nullptr ? (*gr1)[d] : box[d][d]);
+            vol *= (grid_x1[d] - grid_x0[d]);
+        }
+        else
+        {
+            if (ddbox == nullptr)
+            {
+                get_nsgrid_boundaries_vac(av[d], stddev[d], &grid_x0[d], &grid_x1[d], &bdens0, &bdens1);
+            }
+            else
+            {
+                /* Temporary fix which uses global ddbox boundaries
+                 * for unbounded dimensions.
+                 * Should be replaced by local boundaries, which makes
+                 * the ns grid smaller and does not require global comm.
+                 */
+                dd_box_bounds_to_ns_bounds(ddbox->box0[d], ddbox->box_size[d], &grid_x0[d], &grid_x1[d]);
+                bdens0 = grid_x0[d];
+                bdens1 = grid_x1[d];
+            }
+            /* Check for a DD cell not at a lower edge */
+            if (dd != nullptr && gr0 != nullptr && dd->ci[d] > 0)
+            {
+                grid_x0[d] = (*gr0)[d];
+                bdens0     = (*gr0)[d];
+            }
+            /* Check for a DD cell not at a higher edge */
+            if (dd != nullptr && gr1 != nullptr && dd->ci[d] < dd->numCells[d] - 1)
+            {
+                grid_x1[d] = (*gr1)[d];
+                bdens1     = (*gr1)[d];
+            }
+            vol *= (bdens1 - bdens0);
+        }
+
+        if (debug)
+        {
+            fprintf(debug, "Set grid boundaries dim %d: %f %f\n", d, grid_x0[d], grid_x1[d]);
+        }
+    }
+}
diff --git a/src/gromacs/domdec/nsgrid.h b/src/gromacs/domdec/nsgrid.h
new file mode 100644 (file)
index 0000000..f5d1f6a
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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,2019,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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_NSGRID_H
+#define GMX_MDLIB_NSGRID_H
+
+#include "gromacs/math/vectypes.h"
+#include "gromacs/utility/real.h"
+
+struct gmx_domdec_t;
+struct gmx_ddbox_t;
+
+/*! \brief Used when estimating the interaction density.
+ *
+ * c_gridStdDevFactor * stddev estimates the interaction density. The
+ * value sqrt(3) == 1.73205080757 gives a uniform load for a
+ * rectangular 3D block of charge groups. For a sphere, it is not a
+ * bad approximation for 4x1x1 up to 4x2x2.
+ *
+ * \todo It would be nicer to use sqrt(3) here, when all code that
+ * includes this file is in C++, which will let us cope with the
+ * std::sqrt<T> on Windows. */
+constexpr real c_gridStdDevFactor = 1.73205080757;
+
+void get_nsgrid_boundaries(int                  nboundeddim,
+                           matrix               box,
+                           struct gmx_domdec_t* dd,
+                           gmx_ddbox_t*         ddbox,
+                           gmx::RVec*           gr0,
+                           gmx::RVec*           gr1,
+                           int                  ncg,
+                           rvec*                cgcm,
+                           rvec                 grid_x0,
+                           rvec                 grid_x1);
+/* Return the ns grid boundaries grid_x0 and grid_x1
+ * and the estimate for the grid density.
+ * For non-bounded dimensions the boundaries are determined
+ * from the average and std.dev. of cgcm.
+ * The are determined from box, unless gr0!=NULL or gr1!=NULL,
+ * then they are taken from gr0 or gr1.
+ * With dd and unbounded dimensions, the proper grid borders for cells
+ * on the edges are determined from cgcm.
+ */
+
+#endif
index 0ed617f677031468c7326e6ce822158c4b60d6ca..6d5b29174b766ef8e8b24b79f9b5d6290afb3ad8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -73,11 +73,20 @@ enum class DlbOption
     Count             //!< The number of options
 };
 
+/*! \brief Options for checking bonded interactions.
+ *
+ * These values must match the bool false and true used for mdrun -ddcheck */
+enum class DDBondedChecking : bool
+{
+    ExcludeZeroLimit = false, //!< Do not check bonded interactions that go to 0 for large distances
+    All              = true   //!< Check all bonded interactions
+};
+
 /*! \libinternal \brief Structure containing all (command line) options for the domain decomposition */
 struct DomdecOptions
 {
-    //! If true, check that all bonded interactions have been assigned to exactly one domain/rank.
-    bool checkBondedInteractions = true;
+    //! Style of bonded-interaction checking
+    DDBondedChecking ddBondedChecking = DDBondedChecking::All;
     //! If true, don't communicate all atoms between the non-bonded cut-off and the larger bonded cut-off, but only those that have non-local bonded interactions. This significantly reduces the communication volume.
     bool useBondedCommunication = true;
     //! The domain decomposition grid cell count, 0 means let domdec choose based on the number of ranks.
index 67a79d8e854631e8998d4bbf7eb6009364f09103..9a9409422c21accab930841751f0f0a07e4c4291 100644 (file)
@@ -43,6 +43,7 @@
 
 #include "gmxpre.h"
 
+#include "gromacs/utility/arrayref.h"
 #include "partition.h"
 
 #include "config.h"
@@ -60,6 +61,7 @@
 #include "gromacs/domdec/ga2la.h"
 #include "gromacs/domdec/localatomsetmanager.h"
 #include "gromacs/domdec/mdsetup.h"
+#include "gromacs/domdec/nsgrid.h"
 #include "gromacs/ewald/pme_pp.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nrnb.h"
@@ -69,7 +71,6 @@
 #include "gromacs/mdlib/forcerec.h"
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
 #include "gromacs/mdlib/mdatoms.h"
-#include "gromacs/mdlib/nsgrid.h"
 #include "gromacs/mdlib/vsite.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/forcerec.h"
@@ -120,7 +121,15 @@ static void print_ddzone(FILE* fp, int d, int i, int j, gmx_ddzone_t* zone)
     fprintf(fp,
             "zone d0 %d d1 %d d2 %d  min0 %6.3f max1 %6.3f mch0 %6.3f mch1 %6.3f p1_0 %6.3f p1_1 "
             "%6.3f\n",
-            d, i, j, zone->min0, zone->max1, zone->mch0, zone->mch0, zone->p1_0, zone->p1_1);
+            d,
+            i,
+            j,
+            zone->min0,
+            zone->max1,
+            zone->mch0,
+            zone->mch0,
+            zone->p1_0,
+            zone->p1_1);
 }
 
 /*! \brief Using the home grid size as input in cell_ns_x0 and cell_ns_x1
@@ -251,7 +260,10 @@ static void dd_move_cellx(gmx_domdec_t* dd, const gmx_ddbox_t* ddbox, rvec cell_
                     "Here we expect gmx_ddzone_t to consist of c_ddzoneNumReals reals (only)");
 
             int numReals = numElementsInBuffer * c_ddzoneNumReals;
-            ddSendrecv(dd, d, dddirBackward, gmx::arrayRefFromArray(&buf_s[0].min0, numReals),
+            ddSendrecv(dd,
+                       d,
+                       dddirBackward,
+                       gmx::arrayRefFromArray(&buf_s[0].min0, numReals),
                        gmx::arrayRefFromArray(&buf_r[0].min0, numReals));
 
             rvec dh = { 0 };
@@ -412,7 +424,10 @@ static void dd_move_cellx(gmx_domdec_t* dd, const gmx_ddbox_t* ddbox, rvec cell_
         cellsizes[d].fracUpperMin = extr_s[d - 1][1];
         if (debug)
         {
-            fprintf(debug, "Cell fraction d %d, max0 %f, min1 %f\n", d, cellsizes[d].fracLowerMax,
+            fprintf(debug,
+                    "Cell fraction d %d, max0 %f, min1 %f\n",
+                    d,
+                    cellsizes[d].fracLowerMax,
                     cellsizes[d].fracUpperMin);
         }
     }
@@ -477,8 +492,8 @@ static void dd_set_cginfo(gmx::ArrayRef<const int> index_gl, int cg0, int cg1, t
 static void make_dd_indices(gmx_domdec_t* dd, const int atomStart)
 {
     const int                numZones               = dd->comm->zones.n;
-    const int*               zone2cg                = dd->comm->zones.cg_range;
-    const int*               zone_ncg1              = dd->comm->zone_ncg1;
+    gmx::ArrayRef<const int> zone2cg                = dd->comm->zones.cg_range;
+    gmx::ArrayRef<const int> zone_ncg1              = dd->comm->zone_ncg1;
     gmx::ArrayRef<const int> globalAtomGroupIndices = dd->globalAtomGroupIndices;
 
     std::vector<int>& globalAtomIndices = dd->globalAtomIndices;
@@ -537,8 +552,12 @@ static void check_index_consistency(const gmx_domdec_t* dd, int natoms_sys, cons
             int globalAtomIndex = dd->globalAtomIndices[a];
             if (have[globalAtomIndex] > 0)
             {
-                fprintf(stderr, "DD rank %d: global atom %d occurs twice: index %d and %d\n",
-                        dd->rank, globalAtomIndex + 1, have[globalAtomIndex], a + 1);
+                fprintf(stderr,
+                        "DD rank %d: global atom %d occurs twice: index %d and %d\n",
+                        dd->rank,
+                        globalAtomIndex + 1,
+                        have[globalAtomIndex],
+                        a + 1);
             }
             else
             {
@@ -552,7 +571,7 @@ static void check_index_consistency(const gmx_domdec_t* dd, int natoms_sys, cons
     int ngl = 0;
     for (int i = 0; i < natoms_sys; i++)
     {
-        if (const auto entry = dd->ga2la->find(i))
+        if (const auto* entry = dd->ga2la->find(i))
         {
             const int a = entry->la;
             if (a >= numAtomsInZones)
@@ -560,7 +579,10 @@ static void check_index_consistency(const gmx_domdec_t* dd, int natoms_sys, cons
                 fprintf(stderr,
                         "DD rank %d: global atom %d marked as local atom %d, which is larger than "
                         "nat_tot (%d)\n",
-                        dd->rank, i + 1, a + 1, numAtomsInZones);
+                        dd->rank,
+                        i + 1,
+                        a + 1,
+                        numAtomsInZones);
                 nerr++;
             }
             else
@@ -571,7 +593,10 @@ static void check_index_consistency(const gmx_domdec_t* dd, int natoms_sys, cons
                     fprintf(stderr,
                             "DD rank %d: global atom %d marked as local atom %d, which has global "
                             "atom index %d\n",
-                            dd->rank, i + 1, a + 1, dd->globalAtomIndices[a] + 1);
+                            dd->rank,
+                            i + 1,
+                            a + 1,
+                            dd->globalAtomIndices[a] + 1);
                     nerr++;
                 }
             }
@@ -580,15 +605,18 @@ static void check_index_consistency(const gmx_domdec_t* dd, int natoms_sys, cons
     }
     if (ngl != numAtomsInZones)
     {
-        fprintf(stderr, "DD rank %d, %s: %d global atom indices, %d local atoms\n", dd->rank, where,
-                ngl, numAtomsInZones);
+        fprintf(stderr, "DD rank %d, %s: %d global atom indices, %d local atoms\n", dd->rank, where, ngl, numAtomsInZones);
     }
     for (int a = 0; a < numAtomsInZones; a++)
     {
         if (have[a] == 0)
         {
-            fprintf(stderr, "DD rank %d, %s: local atom %d, global %d has no global index\n",
-                    dd->rank, where, a + 1, dd->globalAtomIndices[a] + 1);
+            fprintf(stderr,
+                    "DD rank %d, %s: local atom %d, global %d has no global index\n",
+                    dd->rank,
+                    where,
+                    a + 1,
+                    dd->globalAtomIndices[a] + 1);
         }
     }
 
@@ -625,44 +653,6 @@ static void clearDDStateIndices(gmx_domdec_t* dd, const bool keepLocalAtomIndice
     }
 }
 
-bool check_grid_jump(int64_t step, const gmx_domdec_t* dd, real cutoff, const gmx_ddbox_t* ddbox, gmx_bool bFatal)
-{
-    gmx_domdec_comm_t* comm    = dd->comm;
-    bool               invalid = false;
-
-    for (int d = 1; d < dd->ndim; d++)
-    {
-        const DDCellsizesWithDlb& cellsizes = comm->cellsizesWithDlb[d];
-        const int                 dim       = dd->dim[d];
-        const real                limit     = grid_jump_limit(comm, cutoff, d);
-        real                      bfac      = ddbox->box_size[dim];
-        if (ddbox->tric_dir[dim])
-        {
-            bfac *= ddbox->skew_fac[dim];
-        }
-        if ((cellsizes.fracUpper - cellsizes.fracLowerMax) * bfac < limit
-            || (cellsizes.fracLower - cellsizes.fracUpperMin) * bfac > -limit)
-        {
-            invalid = true;
-
-            if (bFatal)
-            {
-                char buf[22];
-
-                /* This error should never be triggered under normal
-                 * circumstances, but you never know ...
-                 */
-                gmx_fatal(FARGS,
-                          "step %s: The domain decomposition grid has shifted too much in the "
-                          "%c-direction around cell %d %d %d. This should not have happened. "
-                          "Running with fewer ranks might avoid this issue.",
-                          gmx_step_str(step, buf), dim2char(dim), dd->ci[XX], dd->ci[YY], dd->ci[ZZ]);
-            }
-        }
-    }
-
-    return invalid;
-}
 //! Return the duration of force calculations on this rank.
 static float dd_force_load(gmx_domdec_comm_t* comm)
 {
@@ -742,9 +732,14 @@ static void comm_dd_ns_cell_sizes(gmx_domdec_t* dd, gmx_ddbox_t* ddbox, rvec cel
                       "step %s: The %c-size (%f) times the triclinic skew factor (%f) is smaller "
                       "than the smallest allowed cell size (%f) for domain decomposition grid cell "
                       "%d %d %d",
-                      gmx_step_str(step, buf), dim2char(dim),
-                      comm->cell_x1[dim] - comm->cell_x0[dim], ddbox->skew_fac[dim],
-                      dd->comm->cellsize_min[dim], dd->ci[XX], dd->ci[YY], dd->ci[ZZ]);
+                      gmx_step_str(step, buf),
+                      dim2char(dim),
+                      comm->cell_x1[dim] - comm->cell_x0[dim],
+                      ddbox->skew_fac[dim],
+                      dd->comm->cellsize_min[dim],
+                      dd->ci[XX],
+                      dd->ci[YY],
+                      dd->ci[ZZ]);
         }
     }
 
@@ -754,13 +749,13 @@ static void comm_dd_ns_cell_sizes(gmx_domdec_t* dd, gmx_ddbox_t* ddbox, rvec cel
         dd_move_cellx(dd, ddbox, cell_ns_x0, cell_ns_x1);
         if (isDlbOn(dd->comm) && dd->ndim > 1)
         {
-            check_grid_jump(step, dd, dd->comm->systemInfo.cutoff, ddbox, TRUE);
+            gmx::check_grid_jump(step, dd, dd->comm->systemInfo.cutoff, ddbox, TRUE);
         }
     }
 }
 
 //! Compute and communicate to determine the load distribution across PP ranks.
-static void get_load_distribution(gmx_domdec_t* dd, gmx_wallcycle_t wcycle)
+static void get_load_distribution(gmx_domdec_t* dd, gmx_wallcycle* wcycle)
 {
     gmx_domdec_comm_t* comm;
     domdec_load_t*     load;
@@ -772,7 +767,7 @@ static void get_load_distribution(gmx_domdec_t* dd, gmx_wallcycle_t wcycle)
         fprintf(debug, "get_load_distribution start\n");
     }
 
-    wallcycle_start(wcycle, ewcDDCOMMLOAD);
+    wallcycle_start(wcycle, WallCycleCounter::DDCommLoad);
 
     comm = dd->comm;
 
@@ -785,17 +780,19 @@ static void get_load_distribution(gmx_domdec_t* dd, gmx_wallcycle_t wcycle)
         comm->load[0].pme = comm->cycl[ddCyclPME];
     }
 
+    // Either we have DLB off, or we have it on and the array is large enough
+    GMX_ASSERT(!isDlbOn(dd->comm) || static_cast<int>(dd->comm->cellsizesWithDlb.size()) == dd->ndim,
+               "DLB cell sizes data not set up properly ");
     for (int d = dd->ndim - 1; d >= 0; d--)
     {
-        const DDCellsizesWithDlb* cellsizes = (isDlbOn(dd->comm) ? &comm->cellsizesWithDlb[d] : nullptr);
-        const int                 dim       = dd->dim[d];
+        const int dim = dd->dim[d];
         /* Check if we participate in the communication in this dimension */
         if (d == dd->ndim - 1 || (dd->ci[dd->dim[d + 1]] == 0 && dd->ci[dd->dim[dd->ndim - 1]] == 0))
         {
             load = &comm->load[d];
             if (isDlbOn(dd->comm))
             {
-                cell_frac = cellsizes->fracUpper - cellsizes->fracLower;
+                cell_frac = comm->cellsizesWithDlb[d].fracUpper - comm->cellsizesWithDlb[d].fracLower;
             }
             int pos = 0;
             if (d == dd->ndim - 1)
@@ -808,8 +805,8 @@ static void get_load_distribution(gmx_domdec_t* dd, gmx_wallcycle_t wcycle)
                     sbuf[pos++] = cell_frac;
                     if (d > 0)
                     {
-                        sbuf[pos++] = cellsizes->fracLowerMax;
-                        sbuf[pos++] = cellsizes->fracUpperMin;
+                        sbuf[pos++] = comm->cellsizesWithDlb[d].fracLowerMax;
+                        sbuf[pos++] = comm->cellsizesWithDlb[d].fracUpperMin;
                     }
                 }
                 if (bSepPME)
@@ -829,8 +826,8 @@ static void get_load_distribution(gmx_domdec_t* dd, gmx_wallcycle_t wcycle)
                     sbuf[pos++] = comm->load[d + 1].flags;
                     if (d > 0)
                     {
-                        sbuf[pos++] = cellsizes->fracLowerMax;
-                        sbuf[pos++] = cellsizes->fracUpperMin;
+                        sbuf[pos++] = comm->cellsizesWithDlb[d].fracLowerMax;
+                        sbuf[pos++] = comm->cellsizesWithDlb[d].fracUpperMin;
                     }
                 }
                 if (bSepPME)
@@ -844,8 +841,14 @@ static void get_load_distribution(gmx_domdec_t* dd, gmx_wallcycle_t wcycle)
              * The communicators are setup such that the root always has rank 0.
              */
 #if GMX_MPI
-            MPI_Gather(sbuf, load->nload * sizeof(float), MPI_BYTE, load->load,
-                       load->nload * sizeof(float), MPI_BYTE, 0, comm->mpi_comm_load[d]);
+            MPI_Gather(sbuf,
+                       load->nload * sizeof(float),
+                       MPI_BYTE,
+                       load->load,
+                       load->nload * sizeof(float),
+                       MPI_BYTE,
+                       0,
+                       comm->mpi_comm_load[d]);
 #endif
             if (dd->ci[dim] == dd->master_ci[dim])
             {
@@ -854,7 +857,7 @@ static void get_load_distribution(gmx_domdec_t* dd, gmx_wallcycle_t wcycle)
 
                 if (isDlbOn(comm))
                 {
-                    rowMaster = cellsizes->rowMaster.get();
+                    rowMaster = comm->cellsizesWithDlb[d].rowMaster.get();
                 }
                 load->sum      = 0;
                 load->max      = 0;
@@ -935,7 +938,7 @@ static void get_load_distribution(gmx_domdec_t* dd, gmx_wallcycle_t wcycle)
         }
     }
 
-    wallcycle_stop(wcycle, ewcDDCOMMLOAD);
+    wallcycle_stop(wcycle, WallCycleCounter::DDCommLoad);
 
     if (debug)
     {
@@ -1074,7 +1077,8 @@ static void print_dd_load_av(FILE* fplog, gmx_domdec_t* dd)
         sprintf(buf, " Average PME mesh/force load: %5.3f\n", pmeForceRatio);
         fprintf(fplog, "%s", buf);
         fprintf(stderr, "%s", buf);
-        sprintf(buf, " Part of the total run time spent waiting due to PP/PME imbalance: %.1f %%\n",
+        sprintf(buf,
+                " Part of the total run time spent waiting due to PP/PME imbalance: %.1f %%\n",
                 std::fabs(lossFractionPme) * 100);
         fprintf(fplog, "%s", buf);
         fprintf(stderr, "%s", buf);
@@ -1125,7 +1129,8 @@ static void print_dd_load_av(FILE* fplog, gmx_domdec_t* dd)
                 "      had %s work to do than the PP ranks.\n"
                 "      You might want to %s the number of PME ranks\n"
                 "      or %s the cut-off and the grid spacing.\n",
-                std::fabs(lossFractionPme * 100), (lossFractionPme < 0) ? "less" : "more",
+                std::fabs(lossFractionPme * 100),
+                (lossFractionPme < 0) ? "less" : "more",
                 (lossFractionPme < 0) ? "decrease" : "increase",
                 (lossFractionPme < 0) ? "decrease" : "increase");
         fprintf(fplog, "%s\n", buf);
@@ -1231,7 +1236,8 @@ static void turn_on_dlb(const gmx::MDLogger& mdlog, gmx_domdec_t* dd, int64_t st
                         "step %s Measured %.1f %% performance loss due to load imbalance, "
                         "but the minimum cell size is smaller than 1.05 times the cell size limit. "
                         "Will no longer try dynamic load balancing.",
-                        gmx::toString(step).c_str(), dd_force_imb_perf_loss(dd) * 100);
+                        gmx::toString(step).c_str(),
+                        dd_force_imb_perf_loss(dd) * 100);
 
         comm->dlbState = DlbState::offForever;
         return;
@@ -1241,7 +1247,8 @@ static void turn_on_dlb(const gmx::MDLogger& mdlog, gmx_domdec_t* dd, int64_t st
             .appendTextFormatted(
                     "step %s Turning on dynamic load balancing, because the performance loss due "
                     "to load imbalance is %.1f %%.",
-                    gmx::toString(step).c_str(), dd_force_imb_perf_loss(dd) * 100);
+                    gmx::toString(step).c_str(),
+                    dd_force_imb_perf_loss(dd) * 100);
     comm->dlbState = DlbState::onCanTurnOff;
 
     /* Store the non-DLB performance, so we can check if DLB actually
@@ -1541,39 +1548,39 @@ static void set_dd_corners(const gmx_domdec_t* dd, int dim0, int dim1, int dim2,
     }
 }
 
-/*! \brief Add the atom groups we need to send in this pulse from this
- * zone to \p localAtomGroups and \p work. */
-static void get_zone_pulse_cgs(gmx_domdec_t*            dd,
-                               int                      zonei,
-                               int                      zone,
-                               int                      cg0,
-                               int                      cg1,
-                               gmx::ArrayRef<const int> globalAtomGroupIndices,
-                               int                      dim,
-                               int                      dim_ind,
-                               int                      dim0,
-                               int                      dim1,
-                               int                      dim2,
-                               real                     r_comm2,
-                               real                     r_bcomm2,
-                               matrix                   box,
-                               bool                     distanceIsTriclinic,
-                               rvec*                    normal,
-                               real                     skew_fac2_d,
-                               real                     skew_fac_01,
-                               rvec*                    v_d,
-                               rvec*                    v_0,
-                               rvec*                    v_1,
-                               const dd_corners_t*      c,
-                               const rvec               sf2_round,
-                               gmx_bool                 bDistBonded,
-                               gmx_bool                 bBondComm,
-                               gmx_bool                 bDist2B,
-                               gmx_bool                 bDistMB,
-                               rvec*                    cg_cm,
-                               gmx::ArrayRef<const int> cginfo,
-                               std::vector<int>*        localAtomGroups,
-                               dd_comm_setup_work_t*    work)
+/*! \brief Add the atom groups and coordinates we need to send in this
+ * pulse from this zone to \p localAtomGroups and \p work. */
+static void get_zone_pulse_groups(gmx_domdec_t*                  dd,
+                                  int                            zonei,
+                                  int                            zone,
+                                  int                            cg0,
+                                  int                            cg1,
+                                  gmx::ArrayRef<const int>       globalAtomGroupIndices,
+                                  int                            dim,
+                                  int                            dim_ind,
+                                  int                            dim0,
+                                  int                            dim1,
+                                  int                            dim2,
+                                  real                           r_comm2,
+                                  real                           r_bcomm2,
+                                  matrix                         box,
+                                  bool                           distanceIsTriclinic,
+                                  rvec*                          normal,
+                                  real                           skew_fac2_d,
+                                  real                           skew_fac_01,
+                                  rvec*                          v_d,
+                                  rvec*                          v_0,
+                                  rvec*                          v_1,
+                                  const dd_corners_t*            c,
+                                  const rvec                     sf2_round,
+                                  gmx_bool                       bDistBonded,
+                                  gmx_bool                       bBondComm,
+                                  gmx_bool                       bDist2B,
+                                  gmx_bool                       bDistMB,
+                                  gmx::ArrayRef<const gmx::RVec> coordinates,
+                                  gmx::ArrayRef<const int>       cginfo,
+                                  std::vector<int>*              localAtomGroups,
+                                  dd_comm_setup_work_t*          work)
 {
     gmx_domdec_comm_t* comm;
     gmx_bool           bScrew;
@@ -1603,14 +1610,14 @@ static void get_zone_pulse_cgs(gmx_domdec_t*            dd,
         if (!distanceIsTriclinic)
         {
             /* Rectangular direction, easy */
-            r = cg_cm[cg][dim] - c->c[dim_ind][zone];
+            r = coordinates[cg][dim] - c->c[dim_ind][zone];
             if (r > 0)
             {
                 r2 += r * r;
             }
             if (bDistMB_pulse)
             {
-                r = cg_cm[cg][dim] - c->bc[dim_ind];
+                r = coordinates[cg][dim] - c->bc[dim_ind];
                 if (r > 0)
                 {
                     rb2 += r * r;
@@ -1621,7 +1628,7 @@ static void get_zone_pulse_cgs(gmx_domdec_t*            dd,
              */
             if (dim_ind >= 1 && (zonei == 1 || zonei == 2))
             {
-                r = cg_cm[cg][dim0] - c->cr0;
+                r = coordinates[cg][dim0] - c->cr0;
                 /* This is the first dimension, so always r >= 0 */
                 r2 += r * r;
                 if (bDistMB_pulse)
@@ -1631,14 +1638,14 @@ static void get_zone_pulse_cgs(gmx_domdec_t*            dd,
             }
             if (dim_ind == 2 && (zonei == 2 || zonei == 3))
             {
-                r = cg_cm[cg][dim1] - c->cr1[zone];
+                r = coordinates[cg][dim1] - c->cr1[zone];
                 if (r > 0)
                 {
                     r2 += r * r;
                 }
                 if (bDistMB_pulse)
                 {
-                    r = cg_cm[cg][dim1] - c->bcr1;
+                    r = coordinates[cg][dim1] - c->bcr1;
                     if (r > 0)
                     {
                         rb2 += r * r;
@@ -1656,10 +1663,10 @@ static void get_zone_pulse_cgs(gmx_domdec_t*            dd,
              */
             if (dim_ind >= 1 && (zonei == 1 || zonei == 2))
             {
-                rn[dim0] = cg_cm[cg][dim0] - c->cr0;
+                rn[dim0] = coordinates[cg][dim0] - c->cr0;
                 for (i = dim0 + 1; i < DIM; i++)
                 {
-                    rn[dim0] -= cg_cm[cg][i] * v_0[i][dim0];
+                    rn[dim0] -= coordinates[cg][i] * v_0[i][dim0];
                 }
                 r2 = rn[dim0] * rn[dim0] * sf2_round[dim0];
                 if (bDistMB_pulse)
@@ -1686,11 +1693,11 @@ static void get_zone_pulse_cgs(gmx_domdec_t*            dd,
             if (dim_ind == 2 && (zonei == 2 || zonei == 3))
             {
                 GMX_ASSERT(dim1 >= 0 && dim1 < DIM, "Must have a valid dimension index");
-                rn[dim1] += cg_cm[cg][dim1] - c->cr1[zone];
+                rn[dim1] += coordinates[cg][dim1] - c->cr1[zone];
                 tric_sh = 0;
                 for (i = dim1 + 1; i < DIM; i++)
                 {
-                    tric_sh -= cg_cm[cg][i] * v_1[i][dim1];
+                    tric_sh -= coordinates[cg][i] * v_1[i][dim1];
                 }
                 rn[dim1] += tric_sh;
                 if (rn[dim1] > 0)
@@ -1710,7 +1717,7 @@ static void get_zone_pulse_cgs(gmx_domdec_t*            dd,
                 }
                 if (bDistMB_pulse)
                 {
-                    rb[dim1] += cg_cm[cg][dim1] - c->bcr1 + tric_sh;
+                    rb[dim1] += coordinates[cg][dim1] - c->bcr1 + tric_sh;
                     if (rb[dim1] > 0)
                     {
                         rb2 += rb[dim1] * rb[dim1] * sf2_round[dim1];
@@ -1729,11 +1736,11 @@ static void get_zone_pulse_cgs(gmx_domdec_t*            dd,
                 }
             }
             /* The distance along the communication direction */
-            rn[dim] += cg_cm[cg][dim] - c->c[dim_ind][zone];
+            rn[dim] += coordinates[cg][dim] - c->c[dim_ind][zone];
             tric_sh = 0;
             for (i = dim + 1; i < DIM; i++)
             {
-                tric_sh -= cg_cm[cg][i] * v_d[i][dim];
+                tric_sh -= coordinates[cg][i] * v_d[i][dim];
             }
             rn[dim] += tric_sh;
             if (rn[dim] > 0)
@@ -1751,7 +1758,7 @@ static void get_zone_pulse_cgs(gmx_domdec_t*            dd,
             {
                 clear_rvec(rb);
                 GMX_ASSERT(dim >= 0 && dim < DIM, "Must have a valid dimension index");
-                rb[dim] += cg_cm[cg][dim] - c->bc[dim_ind] + tric_sh;
+                rb[dim] += coordinates[cg][dim] - c->bc[dim_ind] + tric_sh;
                 if (rb[dim] > 0)
                 {
                     rb2 += rb[dim] * rb[dim] * skew_fac2_d;
@@ -1780,8 +1787,8 @@ static void get_zone_pulse_cgs(gmx_domdec_t*            dd,
             rvec posPbc;
             if (dd->ci[dim] == 0)
             {
-                /* Correct cg_cm for pbc */
-                rvec_add(cg_cm[cg], box[dim], posPbc);
+                /* Correct coordinates for pbc */
+                rvec_add(coordinates[cg], box[dim], posPbc);
                 if (bScrew)
                 {
                     posPbc[YY] = box[YY][YY] - posPbc[YY];
@@ -1790,7 +1797,7 @@ static void get_zone_pulse_cgs(gmx_domdec_t*            dd,
             }
             else
             {
-                copy_rvec(cg_cm[cg], posPbc);
+                copy_rvec(coordinates[cg], posPbc);
             }
             vbuf.emplace_back(posPbc[XX], posPbc[YY], posPbc[ZZ]);
 
@@ -1841,7 +1848,7 @@ static void setup_dd_communication(gmx_domdec_t* dd, matrix box, gmx_ddbox_t* dd
          * This can not be done in init_domain_decomposition,
          * as the numbers of threads is determined later.
          */
-        int numThreads = gmx_omp_nthreads_get(emntDomdec);
+        int numThreads = gmx_omp_nthreads_get(ModuleMultiThread::Domdec);
         comm->dth.resize(numThreads);
     }
 
@@ -1895,7 +1902,7 @@ static void setup_dd_communication(gmx_domdec_t* dd, matrix box, gmx_ddbox_t* dd
         v_1 = ddbox->v[dim1];
     }
 
-    zone_cg_range                        = zones->cg_range;
+    zone_cg_range                        = zones->cg_range.data();
     gmx::ArrayRef<cginfo_mb_t> cginfo_mb = fr->cginfo_mb;
 
     zone_cg_range[0]   = 0;
@@ -2011,13 +2018,38 @@ static void setup_dd_communication(gmx_domdec_t* dd, matrix box, gmx_ddbox_t* dd
                         int cg0_th = cg0 + ((cg1 - cg0) * th) / numThreads;
                         int cg1_th = cg0 + ((cg1 - cg0) * (th + 1)) / numThreads;
 
-                        /* Get the cg's for this pulse in this zone */
-                        get_zone_pulse_cgs(dd, zonei, zone, cg0_th, cg1_th, dd->globalAtomGroupIndices,
-                                           dim, dim_ind, dim0, dim1, dim2, r_comm2, r_bcomm2, box,
-                                           distanceIsTriclinic, normal, skew_fac2_d, skew_fac_01,
-                                           v_d, v_0, v_1, &corners, sf2_round, bDistBonded, bBondComm,
-                                           bDist2B, bDistMB, state->x.rvec_array(), fr->cginfo,
-                                           th == 0 ? &ind->index : &work.localAtomGroupBuffer, &work);
+                        /* Get the atom groups and coordinates for this pulse in this zone */
+                        get_zone_pulse_groups(dd,
+                                              zonei,
+                                              zone,
+                                              cg0_th,
+                                              cg1_th,
+                                              dd->globalAtomGroupIndices,
+                                              dim,
+                                              dim_ind,
+                                              dim0,
+                                              dim1,
+                                              dim2,
+                                              r_comm2,
+                                              r_bcomm2,
+                                              box,
+                                              distanceIsTriclinic,
+                                              normal,
+                                              skew_fac2_d,
+                                              skew_fac_01,
+                                              v_d,
+                                              v_0,
+                                              v_1,
+                                              &corners,
+                                              sf2_round,
+                                              bDistBonded,
+                                              bBondComm,
+                                              bDist2B,
+                                              bDistMB,
+                                              state->x,
+                                              fr->cginfo,
+                                              th == 0 ? &ind->index : &work.localAtomGroupBuffer,
+                                              &work);
                     }
                     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
                 } // END
@@ -2030,12 +2062,13 @@ static void setup_dd_communication(gmx_domdec_t* dd, matrix box, gmx_ddbox_t* dd
                 {
                     const dd_comm_setup_work_t& dth = comm->dth[th];
 
-                    ind->index.insert(ind->index.end(), dth.localAtomGroupBuffer.begin(),
+                    ind->index.insert(ind->index.end(),
+                                      dth.localAtomGroupBuffer.begin(),
                                       dth.localAtomGroupBuffer.end());
-                    atomGroups.insert(atomGroups.end(), dth.atomGroupBuffer.begin(),
-                                      dth.atomGroupBuffer.end());
-                    positions.insert(positions.end(), dth.positionBuffer.begin(),
-                                     dth.positionBuffer.end());
+                    atomGroups.insert(
+                            atomGroups.end(), dth.atomGroupBuffer.begin(), dth.atomGroupBuffer.end());
+                    positions.insert(
+                            positions.end(), dth.positionBuffer.begin(), dth.positionBuffer.end());
                     comm->dth[0].nat += dth.nat;
                     ind->nsend[zone] += dth.nsend_zone;
                 }
@@ -2089,7 +2122,7 @@ static void setup_dd_communication(gmx_domdec_t* dd, matrix box, gmx_ddbox_t* dd
             }
             ddSendrecv<int>(dd, dim_ind, dddirBackward, work.atomGroupBuffer, integerBufferRef);
 
-            /* Make space for cg_cm */
+            /* Make space for cginfo */
             dd_resize_atominfo_and_state(fr, state, pos_cg + ind->nrecv[nzone]);
 
             /* Communicate the coordinates */
@@ -2127,8 +2160,15 @@ static void setup_dd_communication(gmx_domdec_t* dd, matrix box, gmx_ddbox_t* dd
             else
             {
                 /* This part of the code is never executed with bBondComm. */
-                merge_cg_buffers(nzone, cd, p, zone_cg_range, dd->globalAtomGroupIndices,
-                                 integerBufferRef.data(), state->x, rvecBufferRef, fr->cginfo_mb,
+                merge_cg_buffers(nzone,
+                                 cd,
+                                 p,
+                                 zone_cg_range,
+                                 dd->globalAtomGroupIndices,
+                                 integerBufferRef.data(),
+                                 state->x,
+                                 rvecBufferRef,
+                                 fr->cginfo_mb,
                                  fr->cginfo);
                 pos_cg += ind->nrecv[nzone];
             }
@@ -2433,12 +2473,24 @@ static void set_zones_size(gmx_domdec_t*      dd,
     {
         for (z = zone_start; z < zone_end; z++)
         {
-            fprintf(debug, "zone %d    %6.3f - %6.3f  %6.3f - %6.3f  %6.3f - %6.3f\n", z,
-                    zones->size[z].x0[XX], zones->size[z].x1[XX], zones->size[z].x0[YY],
-                    zones->size[z].x1[YY], zones->size[z].x0[ZZ], zones->size[z].x1[ZZ]);
-            fprintf(debug, "zone %d bb %6.3f - %6.3f  %6.3f - %6.3f  %6.3f - %6.3f\n", z,
-                    zones->size[z].bb_x0[XX], zones->size[z].bb_x1[XX], zones->size[z].bb_x0[YY],
-                    zones->size[z].bb_x1[YY], zones->size[z].bb_x0[ZZ], zones->size[z].bb_x1[ZZ]);
+            fprintf(debug,
+                    "zone %d    %6.3f - %6.3f  %6.3f - %6.3f  %6.3f - %6.3f\n",
+                    z,
+                    zones->size[z].x0[XX],
+                    zones->size[z].x1[XX],
+                    zones->size[z].x0[YY],
+                    zones->size[z].x1[YY],
+                    zones->size[z].x0[ZZ],
+                    zones->size[z].x1[ZZ]);
+            fprintf(debug,
+                    "zone %d bb %6.3f - %6.3f  %6.3f - %6.3f  %6.3f - %6.3f\n",
+                    z,
+                    zones->size[z].bb_x0[XX],
+                    zones->size[z].bb_x1[XX],
+                    zones->size[z].bb_x0[YY],
+                    zones->size[z].bb_x1[YY],
+                    zones->size[z].bb_x0[ZZ],
+                    zones->size[z].bb_x1[ZZ]);
         }
     }
 }
@@ -2525,15 +2577,15 @@ static void dd_sort_state(gmx_domdec_t* dd, t_forcerec* fr, t_state* state)
     gmx::ArrayRef<const gmx_cgsort_t> cgsort = sort->sorted;
     GMX_RELEASE_ASSERT(cgsort.ssize() == dd->ncg_home, "We should sort all the home atom groups");
 
-    if (state->flags & (1 << estX))
+    if (state->flags & enumValueToBitMask(StateEntry::X))
     {
         orderVector(cgsort, makeArrayRef(state->x), rvecBuffer.buffer);
     }
-    if (state->flags & (1 << estV))
+    if (state->flags & enumValueToBitMask(StateEntry::V))
     {
         orderVector(cgsort, makeArrayRef(state->v), rvecBuffer.buffer);
     }
-    if (state->flags & (1 << estCGP))
+    if (state->flags & enumValueToBitMask(StateEntry::Cgp))
     {
         orderVector(cgsort, makeArrayRef(state->cg_p), rvecBuffer.buffer);
     }
@@ -2581,7 +2633,53 @@ void reset_dd_statistics_counters(gmx_domdec_t* dd)
     comm->load_pme = 0;
 }
 
-void print_dd_statistics(const t_commrec* cr, const t_inputrec* ir, FILE* fplog)
+namespace gmx
+{
+
+bool check_grid_jump(int64_t step, const gmx_domdec_t* dd, real cutoff, const gmx_ddbox_t* ddbox, bool bFatal)
+{
+    gmx_domdec_comm_t* comm    = dd->comm;
+    bool               invalid = false;
+
+    for (int d = 1; d < dd->ndim; d++)
+    {
+        const DDCellsizesWithDlb& cellsizes = comm->cellsizesWithDlb[d];
+        const int                 dim       = dd->dim[d];
+        const real                limit     = grid_jump_limit(comm, cutoff, d);
+        real                      bfac      = ddbox->box_size[dim];
+        if (ddbox->tric_dir[dim])
+        {
+            bfac *= ddbox->skew_fac[dim];
+        }
+        if ((cellsizes.fracUpper - cellsizes.fracLowerMax) * bfac < limit
+            || (cellsizes.fracLower - cellsizes.fracUpperMin) * bfac > -limit)
+        {
+            invalid = true;
+
+            if (bFatal)
+            {
+                char buf[22];
+
+                /* This error should never be triggered under normal
+                 * circumstances, but you never know ...
+                 */
+                gmx_fatal(FARGS,
+                          "step %s: The domain decomposition grid has shifted too much in the "
+                          "%c-direction around cell %d %d %d. This should not have happened. "
+                          "Running with fewer ranks might avoid this issue.",
+                          gmx_step_str(step, buf),
+                          dim2char(dim),
+                          dd->ci[XX],
+                          dd->ci[YY],
+                          dd->ci[ZZ]);
+            }
+        }
+    }
+
+    return invalid;
+}
+
+void print_dd_statistics(const t_commrec* cr, const t_inputrec& inputrec, FILE* fplog)
 {
     gmx_domdec_comm_t* comm = cr->dd->comm;
 
@@ -2607,15 +2705,22 @@ void print_dd_statistics(const t_commrec* cr, const t_inputrec* ir, FILE* fplog)
             case DDAtomRanges::Type::Vsites:
                 if (cr->dd->vsite_comm)
                 {
-                    fprintf(fplog, " av. #atoms communicated per step for vsites: %d x %.1f\n",
-                            (EEL_PME(ir->coulombtype) || ir->coulombtype == eelEWALD) ? 3 : 2, av);
+                    fprintf(fplog,
+                            " av. #atoms communicated per step for vsites: %d x %.1f\n",
+                            (EEL_PME(inputrec.coulombtype)
+                             || inputrec.coulombtype == CoulombInteractionType::Ewald)
+                                    ? 3
+                                    : 2,
+                            av);
                 }
                 break;
             case DDAtomRanges::Type::Constraints:
                 if (cr->dd->constraint_comm)
                 {
-                    fprintf(fplog, " av. #atoms communicated per step for LINCS:  %d x %.1f\n",
-                            1 + ir->nLincsIter, av);
+                    fprintf(fplog,
+                            " av. #atoms communicated per step for LINCS:  %d x %.1f\n",
+                            1 + inputrec.nLincsIter,
+                            av);
                 }
                 break;
             default: gmx_incons(" Unknown type for DD statistics");
@@ -2623,7 +2728,7 @@ void print_dd_statistics(const t_commrec* cr, const t_inputrec* ir, FILE* fplog)
     }
     fprintf(fplog, "\n");
 
-    if (comm->ddSettings.recordLoad && EI_DYNAMICS(ir->eI))
+    if (comm->ddSettings.recordLoad && EI_DYNAMICS(inputrec.eI))
     {
         print_dd_load_av(fplog, cr->dd);
     }
@@ -2634,11 +2739,11 @@ void dd_partition_system(FILE*                     fplog,
                          const gmx::MDLogger&      mdlog,
                          int64_t                   step,
                          const t_commrec*          cr,
-                         gmx_bool                  bMasterState,
+                         bool                      bMasterState,
                          int                       nstglobalcomm,
                          t_state*                  state_global,
                          const gmx_mtop_t&         top_global,
-                         const t_inputrec*         ir,
+                         const t_inputrec&         inputrec,
                          gmx::ImdSession*          imdSession,
                          pull_t*                   pull_work,
                          t_state*                  state_local,
@@ -2650,29 +2755,21 @@ void dd_partition_system(FILE*                     fplog,
                          gmx::Constraints*         constr,
                          t_nrnb*                   nrnb,
                          gmx_wallcycle*            wcycle,
-                         gmx_bool                  bVerbose)
+                         bool                      bVerbose)
 {
-    gmx_domdec_t*      dd;
-    gmx_domdec_comm_t* comm;
-    gmx_ddbox_t        ddbox = { 0 };
-    int64_t            step_pcoupl;
-    rvec               cell_ns_x0, cell_ns_x1;
-    int                ncgindex_set, ncg_moved, nat_f_novirsum;
-    gmx_bool           bBoxChanged, bNStGlobalComm, bDoDLB, bCheckWhetherToTurnDlbOn, bLogLoad;
-    gmx_bool           bRedist;
-    ivec               np;
-    real               grid_density;
-    char               sbuf[22];
-
-    wallcycle_start(wcycle, ewcDOMDEC);
-
-    dd   = cr->dd;
-    comm = dd->comm;
+    gmx_ddbox_t ddbox = { 0 };
+    int         ncgindex_set;
+    char        sbuf[22];
+
+    wallcycle_start(wcycle, WallCycleCounter::Domdec);
+
+    gmx_domdec_t*      dd   = cr->dd;
+    gmx_domdec_comm_t* comm = dd->comm;
 
     // TODO if the update code becomes accessible here, use
     // upd->deform for this logic.
-    bBoxChanged = (bMasterState || inputrecDeform(ir));
-    if (ir->epc != epcNO)
+    bool bBoxChanged = (bMasterState || inputrecDeform(&inputrec));
+    if (inputrec.epc != PressureCoupling::No)
     {
         /* With nstpcouple > 1 pressure coupling happens.
          * one step after calculating the pressure.
@@ -2683,7 +2780,8 @@ void dd_partition_system(FILE*                     fplog,
          * We need to determine the last step in which p-coupling occurred.
          * MRS -- need to validate this for vv?
          */
-        int n = ir->nstpcouple;
+        int     n = inputrec.nstpcouple;
+        int64_t step_pcoupl;
         if (n == 1)
         {
             step_pcoupl = step - 1;
@@ -2694,15 +2792,15 @@ void dd_partition_system(FILE*                     fplog,
         }
         if (step_pcoupl >= comm->partition_step)
         {
-            bBoxChanged = TRUE;
+            bBoxChanged = true;
         }
     }
 
-    bNStGlobalComm = (step % nstglobalcomm == 0);
-
+    bool bNStGlobalComm = (step % nstglobalcomm == 0);
+    bool bDoDLB;
     if (!isDlbOn(comm))
     {
-        bDoDLB = FALSE;
+        bDoDLB = false;
     }
     else
     {
@@ -2710,7 +2808,7 @@ void dd_partition_system(FILE*                     fplog,
          * Since it requires (possibly expensive) global communication,
          * we might want to do DLB less frequently.
          */
-        if (bBoxChanged || ir->epc != epcNO)
+        if (bBoxChanged || inputrec.epc != PressureCoupling::No)
         {
             bDoDLB = bBoxChanged;
         }
@@ -2723,17 +2821,18 @@ void dd_partition_system(FILE*                     fplog,
     /* Check if we have recorded loads on the nodes */
     if (comm->ddSettings.recordLoad && dd_load_count(comm) > 0)
     {
-        bCheckWhetherToTurnDlbOn = dd_dlb_get_should_check_whether_to_turn_dlb_on(dd);
+        bool bCheckWhetherToTurnDlbOn = dd_dlb_get_should_check_whether_to_turn_dlb_on(dd);
 
         /* Print load every nstlog, first and last step to the log file */
-        bLogLoad = ((ir->nstlog > 0 && step % ir->nstlog == 0) || comm->n_load_collect == 0
-                    || (ir->nsteps >= 0 && (step + ir->nstlist > ir->init_step + ir->nsteps)));
+        bool bLogLoad = ((inputrec.nstlog > 0 && step % inputrec.nstlog == 0) || comm->n_load_collect == 0
+                         || (inputrec.nsteps >= 0
+                             && (step + inputrec.nstlist > inputrec.init_step + inputrec.nsteps)));
 
         /* Avoid extra communication due to verbose screen output
          * when nstglobalcomm is set.
          */
         if (bDoDLB || bLogLoad || bCheckWhetherToTurnDlbOn
-            || (bVerbose && (ir->nstlist == 0 || nstglobalcomm <= ir->nstlist)))
+            || (bVerbose && (inputrec.nstlist == 0 || nstglobalcomm <= inputrec.nstlist)))
         {
             get_load_distribution(dd, wcycle);
             if (DDMASTER(dd))
@@ -2762,7 +2861,7 @@ void dd_partition_system(FILE*                     fplog,
                 if (comm->dlbState == DlbState::onCanTurnOff
                     && dd->comm->n_load_have % c_checkTurnDlbOffInterval == c_checkTurnDlbOffInterval - 1)
                 {
-                    gmx_bool turnOffDlb;
+                    bool turnOffDlb;
                     if (DDMASTER(dd))
                     {
                         /* If the running averaged cycles with DLB are more
@@ -2777,15 +2876,15 @@ void dd_partition_system(FILE*                     fplog,
                     {
                         /* To turn off DLB, we need to redistribute the atoms */
                         dd_collect_state(dd, state_local, state_global);
-                        bMasterState = TRUE;
+                        bMasterState = true;
                         turn_off_dlb(mdlog, dd, step);
                     }
                 }
             }
             else if (bCheckWhetherToTurnDlbOn)
             {
-                gmx_bool turnOffDlbForever = FALSE;
-                gmx_bool turnOnDlb         = FALSE;
+                bool turnOffDlbForever = false;
+                bool turnOnDlb         = false;
 
                 /* Since the timings are node dependent, the master decides */
                 if (DDMASTER(dd))
@@ -2810,7 +2909,7 @@ void dd_partition_system(FILE*                     fplog,
                         if (comm->dlbSlowerPartitioningCount > 0
                             && dd->ddp_count < comm->dlbSlowerPartitioningCount + 10 * c_checkTurnDlbOnInterval)
                         {
-                            turnOffDlbForever = TRUE;
+                            turnOffDlbForever = true;
                         }
                         comm->haveTurnedOffDlb = false;
                         /* Register when we last measured DLB slowdown */
@@ -2827,7 +2926,7 @@ void dd_partition_system(FILE*                     fplog,
                          */
                         if (comm->ddRankSetup.usePmeOnlyRanks && dd_pme_f_ratio(dd) > 1 - DD_PERF_LOSS_DLB_ON)
                         {
-                            turnOnDlb = FALSE;
+                            turnOnDlb = false;
                         }
                         else
                         {
@@ -2837,8 +2936,8 @@ void dd_partition_system(FILE*                     fplog,
                 }
                 struct
                 {
-                    gmx_bool turnOffDlbForever;
-                    gmx_bool turnOnDlb;
+                    bool turnOffDlbForever;
+                    bool turnOnDlb;
                 } bools{ turnOffDlbForever, turnOnDlb };
                 dd_bcast(dd, sizeof(bools), &bools);
                 if (bools.turnOffDlbForever)
@@ -2848,14 +2947,14 @@ void dd_partition_system(FILE*                     fplog,
                 else if (bools.turnOnDlb)
                 {
                     turn_on_dlb(mdlog, dd, step);
-                    bDoDLB = TRUE;
+                    bDoDLB = true;
                 }
             }
         }
         comm->n_load_have++;
     }
 
-    bRedist = FALSE;
+    bool bRedist = false;
     if (bMasterState)
     {
         /* Clear the old state */
@@ -2882,7 +2981,8 @@ void dd_partition_system(FILE*                     fplog,
             gmx_fatal(FARGS,
                       "Internal inconsistency state_local->ddp_count (%d) > dd->ddp_count (%" PRId64
                       ")",
-                      state_local->ddp_count, dd->ddp_count);
+                      state_local->ddp_count,
+                      dd->ddp_count);
         }
 
         if (state_local->ddp_count_cg_gl != state_local->ddp_count)
@@ -2890,7 +2990,8 @@ void dd_partition_system(FILE*                     fplog,
             gmx_fatal(FARGS,
                       "Internal inconsistency state_local->ddp_count_cg_gl (%d) != "
                       "state_local->ddp_count (%d)",
-                      state_local->ddp_count_cg_gl, state_local->ddp_count);
+                      state_local->ddp_count_cg_gl,
+                      state_local->ddp_count);
         }
 
         /* Clear the old state */
@@ -2928,8 +3029,8 @@ void dd_partition_system(FILE*                     fplog,
         }
         set_ddbox(*dd, bMasterState, state_local->box, bNStGlobalComm, state_local->x, &ddbox);
 
-        bBoxChanged = TRUE;
-        bRedist     = TRUE;
+        bBoxChanged = true;
+        bRedist     = true;
     }
     /* Copy needed for dim's without pbc when avoiding communication */
     copy_rvec(ddbox.box0, comm->box0);
@@ -2956,10 +3057,10 @@ void dd_partition_system(FILE*                     fplog,
      * Thus we need to keep track of how many charge groups will move for
      * obtaining correct local charge group / atom counts.
      */
-    ncg_moved = 0;
+    int ncg_moved = 0;
     if (bRedist)
     {
-        wallcycle_sub_start(wcycle, ewcsDD_REDIST);
+        wallcycle_sub_start(wcycle, WallCycleSubCounter::DDRedist);
 
         ncgindex_set = dd->ncg_home;
         dd_redistribute_cg(fplog, step, dd, ddbox.tric_dir, state_local, fr, nrnb, &ncg_moved);
@@ -2973,13 +3074,20 @@ void dd_partition_system(FILE*                     fplog,
                     state_local->x);
         }
 
-        wallcycle_sub_stop(wcycle, ewcsDD_REDIST);
+        wallcycle_sub_stop(wcycle, WallCycleSubCounter::DDRedist);
     }
 
-    // TODO: Integrate this code in the nbnxm module
-    get_nsgrid_boundaries(ddbox.nboundeddim, state_local->box, dd, &ddbox, &comm->cell_x0,
-                          &comm->cell_x1, dd->ncg_home, as_rvec_array(state_local->x.data()),
-                          cell_ns_x0, cell_ns_x1, &grid_density);
+    RVec cell_ns_x0, cell_ns_x1;
+    get_nsgrid_boundaries(ddbox.nboundeddim,
+                          state_local->box,
+                          dd,
+                          &ddbox,
+                          &comm->cell_x0,
+                          &comm->cell_x1,
+                          dd->ncg_home,
+                          as_rvec_array(state_local->x.data()),
+                          cell_ns_x0,
+                          cell_ns_x1);
 
     if (bBoxChanged)
     {
@@ -2988,7 +3096,7 @@ void dd_partition_system(FILE*                     fplog,
 
     if (bSortCG)
     {
-        wallcycle_sub_start(wcycle, ewcsDD_GRID);
+        wallcycle_sub_start(wcycle, WallCycleSubCounter::DDGrid);
 
         /* Sort the state on charge group position.
          * This enables exact restarts from this step.
@@ -3003,15 +3111,22 @@ void dd_partition_system(FILE*                     fplog,
 
         set_zones_size(dd, state_local->box, &ddbox, 0, 1, ncg_moved);
 
-        nbnxn_put_on_grid(fr->nbv.get(), state_local->box, 0, comm->zones.size[0].bb_x0,
-                          comm->zones.size[0].bb_x1, comm->updateGroupsCog.get(),
-                          { 0, dd->ncg_home }, comm->zones.dens_zone0, fr->cginfo, state_local->x,
-                          ncg_moved, bRedist ? comm->movedBuffer.data() : nullptr);
+        nbnxn_put_on_grid(fr->nbv.get(),
+                          state_local->box,
+                          0,
+                          comm->zones.size[0].bb_x0,
+                          comm->zones.size[0].bb_x1,
+                          comm->updateGroupsCog.get(),
+                          { 0, dd->ncg_home },
+                          comm->zones.dens_zone0,
+                          fr->cginfo,
+                          state_local->x,
+                          ncg_moved,
+                          bRedist ? comm->movedBuffer.data() : nullptr);
 
         if (debug)
         {
-            fprintf(debug, "Step %s, sorting the %d home charge groups\n", gmx_step_str(step, sbuf),
-                    dd->ncg_home);
+            fprintf(debug, "Step %s, sorting the %d home charge groups\n", gmx_step_str(step, sbuf), dd->ncg_home);
         }
         dd_sort_state(dd, fr, state_local);
 
@@ -3022,14 +3137,14 @@ void dd_partition_system(FILE*                     fplog,
         dd->ga2la->clear();
         ncgindex_set = 0;
 
-        wallcycle_sub_stop(wcycle, ewcsDD_GRID);
+        wallcycle_sub_stop(wcycle, WallCycleSubCounter::DDGrid);
     }
     else
     {
         /* With the group scheme the sorting array is part of the DD state,
          * but it just got out of sync, so mark as invalid by emptying it.
          */
-        if (ir->cutoff_scheme == ecutsGROUP)
+        if (inputrec.cutoff_scheme == CutoffScheme::Group)
         {
             comm->sort->sorted.clear();
         }
@@ -3043,7 +3158,7 @@ void dd_partition_system(FILE*                     fplog,
         comm->updateGroupsCog->clear();
     }
 
-    wallcycle_sub_start(wcycle, ewcsDD_SETUPCOMM);
+    wallcycle_sub_start(wcycle, WallCycleSubCounter::DDSetupComm);
 
     /* Set the induces for the home atoms */
     set_zones_ncg_home(dd);
@@ -3061,31 +3176,41 @@ void dd_partition_system(FILE*                     fplog,
     /* When bSortCG=true, we have already set the size for zone 0 */
     set_zones_size(dd, state_local->box, &ddbox, bSortCG ? 1 : 0, comm->zones.n, 0);
 
-    wallcycle_sub_stop(wcycle, ewcsDD_SETUPCOMM);
+    wallcycle_sub_stop(wcycle, WallCycleSubCounter::DDSetupComm);
 
     /*
        write_dd_pdb("dd_home",step,"dump",top_global,cr,
                  -1,state_local->x.rvec_array(),state_local->box);
      */
 
-    wallcycle_sub_start(wcycle, ewcsDD_MAKETOP);
+    wallcycle_sub_start(wcycle, WallCycleSubCounter::DDMakeTop);
 
     /* Extract a local topology from the global topology */
+    IVec numPulses;
     for (int i = 0; i < dd->ndim; i++)
     {
-        np[dd->dim[i]] = comm->cd[i].numPulses();
+        numPulses[dd->dim[i]] = comm->cd[i].numPulses();
     }
-    dd_make_local_top(dd, &comm->zones, dd->unitCellInfo.npbcdim, state_local->box,
-                      comm->cellsize_min, np, fr, state_local->x.rvec_array(), top_global, top_local);
+    dd_make_local_top(dd,
+                      &comm->zones,
+                      dd->unitCellInfo.npbcdim,
+                      state_local->box,
+                      comm->cellsize_min,
+                      numPulses,
+                      fr,
+                      state_local->x,
+                      top_global,
+                      top_local);
 
-    wallcycle_sub_stop(wcycle, ewcsDD_MAKETOP);
+    wallcycle_sub_stop(wcycle, WallCycleSubCounter::DDMakeTop);
 
-    wallcycle_sub_start(wcycle, ewcsDD_MAKECONSTR);
+    wallcycle_sub_start(wcycle, WallCycleSubCounter::DDMakeConstr);
 
     /* Set up the special atom communication */
     int n = comm->atomRanges.end(DDAtomRanges::Type::Zones);
     for (int i = static_cast<int>(DDAtomRanges::Type::Zones) + 1;
-         i < static_cast<int>(DDAtomRanges::Type::Number); i++)
+         i < static_cast<int>(DDAtomRanges::Type::Number);
+         i++)
     {
         auto range = static_cast<DDAtomRanges::Type>(i);
         switch (range)
@@ -3097,11 +3222,16 @@ void dd_partition_system(FILE*                     fplog,
                 }
                 break;
             case DDAtomRanges::Type::Constraints:
-                if (dd->comm->systemInfo.haveSplitConstraints || dd->comm->systemInfo.haveSplitSettles)
+                if (dd->comm->systemInfo.mayHaveSplitConstraints || dd->comm->systemInfo.mayHaveSplitSettles)
                 {
                     /* Only for inter-cg constraints we need special code */
-                    n = dd_make_local_constraints(dd, n, &top_global, fr->cginfo.data(), constr,
-                                                  ir->nProjOrder, top_local->idef.il);
+                    n = dd_make_local_constraints(dd,
+                                                  n,
+                                                  top_global,
+                                                  fr->cginfo.data(),
+                                                  constr,
+                                                  inputrec.nProjOrder,
+                                                  top_local->idef.il);
                 }
                 break;
             default: gmx_incons("Unknown special atom type setup");
@@ -3109,9 +3239,9 @@ void dd_partition_system(FILE*                     fplog,
         comm->atomRanges.setEnd(range, n);
     }
 
-    wallcycle_sub_stop(wcycle, ewcsDD_MAKECONSTR);
+    wallcycle_sub_stop(wcycle, WallCycleSubCounter::DDMakeConstr);
 
-    wallcycle_sub_start(wcycle, ewcsDD_TOPOTHER);
+    wallcycle_sub_start(wcycle, WallCycleSubCounter::DDTopOther);
 
     /* Make space for the extra coordinates for virtual site
      * or constraint communication.
@@ -3120,13 +3250,14 @@ void dd_partition_system(FILE*                     fplog,
 
     state_change_natoms(state_local, state_local->natoms);
 
+    int nat_f_novirsum;
     if (vsite && vsite->numInterUpdategroupVirtualSites())
     {
         nat_f_novirsum = comm->atomRanges.end(DDAtomRanges::Type::Vsites);
     }
     else
     {
-        if (EEL_FULL(ir->coulombtype) && dd->haveExclusions)
+        if (EEL_FULL(inputrec.coulombtype) && dd->haveExclusions)
         {
             nat_f_novirsum = comm->atomRanges.end(DDAtomRanges::Type::Zones);
         }
@@ -3142,20 +3273,37 @@ void dd_partition_system(FILE*                     fplog,
      * allocation, zeroing and copying, but this is probably not worth
      * the complications and checking.
      */
-    forcerec_set_ranges(fr, comm->atomRanges.end(DDAtomRanges::Type::Zones),
-                        comm->atomRanges.end(DDAtomRanges::Type::Constraints), nat_f_novirsum);
+    forcerec_set_ranges(fr,
+                        comm->atomRanges.end(DDAtomRanges::Type::Zones),
+                        comm->atomRanges.end(DDAtomRanges::Type::Constraints),
+                        nat_f_novirsum);
 
     /* Update atom data for mdatoms and several algorithms */
-    mdAlgorithmsSetupAtomData(cr, ir, top_global, top_local, fr, f, mdAtoms, constr, vsite, nullptr);
+    mdAlgorithmsSetupAtomData(cr, inputrec, top_global, top_local, fr, f, mdAtoms, constr, vsite, nullptr);
 
-    auto mdatoms = mdAtoms->mdatoms();
+    auto* mdatoms = mdAtoms->mdatoms();
     if (!thisRankHasDuty(cr, DUTY_PME))
     {
         /* Send the charges and/or c6/sigmas to our PME only node */
-        gmx_pme_send_parameters(cr, fr->ic, mdatoms->nChargePerturbed != 0,
-                                mdatoms->nTypePerturbed != 0, mdatoms->chargeA, mdatoms->chargeB,
-                                mdatoms->sqrt_c6A, mdatoms->sqrt_c6B, mdatoms->sigmaA,
-                                mdatoms->sigmaB, dd_pme_maxshift_x(dd), dd_pme_maxshift_y(dd));
+        gmx_pme_send_parameters(
+                cr,
+                *fr->ic,
+                mdatoms->nChargePerturbed != 0,
+                mdatoms->nTypePerturbed != 0,
+                mdatoms->chargeA ? gmx::arrayRefFromArray(mdatoms->chargeA, mdatoms->nr)
+                                 : gmx::ArrayRef<real>{},
+                mdatoms->chargeB ? gmx::arrayRefFromArray(mdatoms->chargeB, mdatoms->nr)
+                                 : gmx::ArrayRef<real>{},
+                mdatoms->sqrt_c6A ? gmx::arrayRefFromArray(mdatoms->sqrt_c6A, mdatoms->nr)
+                                  : gmx::ArrayRef<real>{},
+                mdatoms->sqrt_c6B ? gmx::arrayRefFromArray(mdatoms->sqrt_c6B, mdatoms->nr)
+                                  : gmx::ArrayRef<real>{},
+                mdatoms->sigmaA ? gmx::arrayRefFromArray(mdatoms->sigmaA, mdatoms->nr)
+                                : gmx::ArrayRef<real>{},
+                mdatoms->sigmaB ? gmx::arrayRefFromArray(mdatoms->sigmaB, mdatoms->nr)
+                                : gmx::ArrayRef<real>{},
+                dd_pme_maxshift_x(*dd),
+                dd_pme_maxshift_y(*dd));
     }
 
     if (dd->atomSets != nullptr)
@@ -3165,13 +3313,13 @@ void dd_partition_system(FILE*                     fplog,
     }
 
     // The pull group construction can need the atom sets updated above
-    if (ir->bPull)
+    if (inputrec.bPull)
     {
         /* Update the local pull groups */
         dd_make_local_pull_groups(cr, pull_work);
     }
 
-    /* Update the local atoms to be communicated via the IMD protocol if bIMD is TRUE. */
+    /* Update the local atoms to be communicated via the IMD protocol if bIMD is true. */
     imdSession->dd_make_local_IMD_atoms(dd);
 
     add_dd_statistics(dd);
@@ -3185,12 +3333,18 @@ void dd_partition_system(FILE*                     fplog,
      */
     dd_move_x_vsites(*dd, state_local->box, state_local->x.rvec_array());
 
-    wallcycle_sub_stop(wcycle, ewcsDD_TOPOTHER);
+    wallcycle_sub_stop(wcycle, WallCycleSubCounter::DDTopOther);
 
     if (comm->ddSettings.nstDDDump > 0 && step % comm->ddSettings.nstDDDump == 0)
     {
-        dd_move_x(dd, state_local->box, state_local->x, nullWallcycle);
-        write_dd_pdb("dd_dump", step, "dump", &top_global, cr, -1, state_local->x.rvec_array(),
+        dd_move_x(dd, state_local->box, state_local->x, nullptr);
+        write_dd_pdb("dd_dump",
+                     step,
+                     "dump",
+                     top_global,
+                     cr,
+                     -1,
+                     state_local->x.rvec_array(),
                      state_local->box);
     }
 
@@ -3215,26 +3369,7 @@ void dd_partition_system(FILE*                     fplog,
         check_index_consistency(dd, top_global.natoms, "after partitioning");
     }
 
-    wallcycle_stop(wcycle, ewcDOMDEC);
+    wallcycle_stop(wcycle, WallCycleCounter::Domdec);
 }
 
-/*! \brief Check whether bonded interactions are missing, if appropriate */
-void checkNumberOfBondedInteractions(const gmx::MDLogger&           mdlog,
-                                     t_commrec*                     cr,
-                                     int                            totalNumberOfBondedInteractions,
-                                     const gmx_mtop_t*              top_global,
-                                     const gmx_localtop_t*          top_local,
-                                     gmx::ArrayRef<const gmx::RVec> x,
-                                     const matrix                   box,
-                                     bool* shouldCheckNumberOfBondedInteractions)
-{
-    if (*shouldCheckNumberOfBondedInteractions)
-    {
-        if (totalNumberOfBondedInteractions != cr->dd->nbonded_global)
-        {
-            dd_print_missing_interactions(mdlog, cr, totalNumberOfBondedInteractions, top_global,
-                                          top_local, x, box); // Does not return
-        }
-        *shouldCheckNumberOfBondedInteractions = false;
-    }
-}
+} // namespace gmx
index de05c4a73847b7cebcb1f9cd78892d2074085e0d..7f7d8152c373342e7613d2d50de20f67868c14c3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@
 #include <cstdio>
 
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
 struct gmx_ddbox_t;
@@ -73,13 +72,12 @@ class ImdSession;
 class MDAtoms;
 class MDLogger;
 class VirtualSitesHandler;
-} // namespace gmx
 
 //! Check whether the DD grid has moved too far for correctness.
-bool check_grid_jump(int64_t step, const gmx_domdec_t* dd, real cutoff, const gmx_ddbox_t* ddbox, gmx_bool bFatal);
+bool check_grid_jump(int64_t step, const gmx_domdec_t* dd, real cutoff, const gmx_ddbox_t* ddbox, bool bFatal);
 
 /*! \brief Print statistics for domain decomposition communication */
-void print_dd_statistics(const t_commrec* cr, const t_inputrec* ir, FILE* fplog);
+void print_dd_statistics(const t_commrec* cr, const t_inputrec& inputrec, FILE* fplog);
 
 /*! \brief Partition the system over the nodes.
  *
@@ -96,7 +94,7 @@ void print_dd_statistics(const t_commrec* cr, const t_inputrec* ir, FILE* fplog)
  * \param[in] nstglobalcomm Will globals be computed on this step
  * \param[in] state_global  Global state
  * \param[in] top_global    Global topology
- * \param[in] ir            Input record
+ * \param[in] inputrec      Input record
  * \param[in] imdSession    IMD handle
  * \param[in] pull_work     Pulling data
  * \param[in] state_local   Local state
@@ -114,11 +112,11 @@ void dd_partition_system(FILE*                     fplog,
                          const gmx::MDLogger&      mdlog,
                          int64_t                   step,
                          const t_commrec*          cr,
-                         gmx_bool                  bMasterState,
+                         bool                      bMasterState,
                          int                       nstglobalcomm,
                          t_state*                  state_global,
                          const gmx_mtop_t&         top_global,
-                         const t_inputrec*         ir,
+                         const t_inputrec&         inputrec,
                          gmx::ImdSession*          imdSession,
                          pull_t*                   pull_work,
                          t_state*                  state_local,
@@ -130,26 +128,7 @@ void dd_partition_system(FILE*                     fplog,
                          gmx::Constraints*         constr,
                          t_nrnb*                   nrnb,
                          gmx_wallcycle*            wcycle,
-                         gmx_bool                  bVerbose);
-
-/*! \brief Check whether bonded interactions are missing, if appropriate
- *
- * \param[in]    mdlog                                  Logger
- * \param[in]    cr                                     Communication object
- * \param[in]    totalNumberOfBondedInteractions        Result of the global reduction over the number of bonds treated in each domain
- * \param[in]    top_global                             Global topology for the error message
- * \param[in]    top_local                              Local topology for the error message
- * \param[in]    x                                      Position vector for the error message
- * \param[in]    box                                    Box matrix for the error message
- * \param[in,out] shouldCheckNumberOfBondedInteractions Whether we should do the check. Always set to false.
- */
-void checkNumberOfBondedInteractions(const gmx::MDLogger&           mdlog,
-                                     t_commrec*                     cr,
-                                     int                            totalNumberOfBondedInteractions,
-                                     const gmx_mtop_t*              top_global,
-                                     const gmx_localtop_t*          top_local,
-                                     gmx::ArrayRef<const gmx::RVec> x,
-                                     const matrix                   box,
-                                     bool* shouldCheckNumberOfBondedInteractions);
+                         bool                      bVerbose);
 
+} // namespace gmx
 #endif
index 6b985c1345aa6d6a24407d1664cbab611a82282e..d47243969bd898afb7f154371e8744623d2a4a24 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2005,2006,2007,2008,2009 by the GROMACS development team.
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
  * Copyright (c) 2015,2016,2017,2018,2019 by the GROMACS development team.
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@
 #include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
-#include "gromacs/mdlib/nsgrid.h"
 #include "gromacs/mdtypes/forcerec.h"
 #include "gromacs/mdtypes/nblist.h"
 #include "gromacs/mdtypes/state.h"
@@ -184,17 +183,24 @@ static void print_cg_move(FILE*               fplog,
     mesg += gmx::formatString(" in direction %c\n", dim2char(dim));
     fprintf(fplog, "%s", mesg.c_str());
 
-    fprintf(fplog, "distance out of cell %f\n",
+    fprintf(fplog,
+            "distance out of cell %f\n",
             dir == 1 ? pos_d - comm->cell_x1[dim] : pos_d - comm->cell_x0[dim]);
     if (bHaveCgcmOld)
     {
         fprintf(fplog, "Old coordinates: %8.3f %8.3f %8.3f\n", cm_old[XX], cm_old[YY], cm_old[ZZ]);
     }
     fprintf(fplog, "New coordinates: %8.3f %8.3f %8.3f\n", cm_new[XX], cm_new[YY], cm_new[ZZ]);
-    fprintf(fplog, "Old cell boundaries in direction %c: %8.3f %8.3f\n", dim2char(dim),
-            comm->old_cell_x0[dim], comm->old_cell_x1[dim]);
-    fprintf(fplog, "New cell boundaries in direction %c: %8.3f %8.3f\n", dim2char(dim),
-            comm->cell_x0[dim], comm->cell_x1[dim]);
+    fprintf(fplog,
+            "Old cell boundaries in direction %c: %8.3f %8.3f\n",
+            dim2char(dim),
+            comm->old_cell_x0[dim],
+            comm->old_cell_x1[dim]);
+    fprintf(fplog,
+            "New cell boundaries in direction %c: %8.3f %8.3f\n",
+            dim2char(dim),
+            comm->cell_x0[dim],
+            comm->cell_x1[dim]);
 }
 
 [[noreturn]] static void cg_move_error(FILE*               fplog,
@@ -221,20 +227,20 @@ static void print_cg_move(FILE*               fplog,
 
 static void rotate_state_atom(t_state* state, int a)
 {
-    if (state->flags & (1 << estX))
+    if (state->flags & enumValueToBitMask(StateEntry::X))
     {
         auto x = makeArrayRef(state->x);
         /* Rotate the complete state; for a rectangular box only */
         x[a][YY] = state->box[YY][YY] - x[a][YY];
         x[a][ZZ] = state->box[ZZ][ZZ] - x[a][ZZ];
     }
-    if (state->flags & (1 << estV))
+    if (state->flags & enumValueToBitMask(StateEntry::V))
     {
         auto v   = makeArrayRef(state->v);
         v[a][YY] = -v[a][YY];
         v[a][ZZ] = -v[a][ZZ];
     }
-    if (state->flags & (1 << estCGP))
+    if (state->flags & enumValueToBitMask(StateEntry::Cgp))
     {
         auto cg_p   = makeArrayRef(state->cg_p);
         cg_p[a][YY] = -cg_p[a][YY];
@@ -363,8 +369,8 @@ static void calc_cg_move(FILE*              fplog,
                 {
                     if (pos_d >= moveLimits.upper[d])
                     {
-                        cg_move_error(fplog, dd, step, a, d, 1, false, moveLimits.distance[d],
-                                      cm_new, cm_new, pos_d);
+                        cg_move_error(
+                                fplog, dd, step, a, d, 1, false, moveLimits.distance[d], cm_new, cm_new, pos_d);
                     }
                     dev[d] = 1;
                     if (dd->ci[d] == dd->numCells[d] - 1)
@@ -386,8 +392,8 @@ static void calc_cg_move(FILE*              fplog,
                 {
                     if (pos_d < moveLimits.lower[d])
                     {
-                        cg_move_error(fplog, dd, step, a, d, -1, false, moveLimits.distance[d],
-                                      cm_new, cm_new, pos_d);
+                        cg_move_error(
+                                fplog, dd, step, a, d, -1, false, moveLimits.distance[d], cm_new, cm_new, pos_d);
                     }
                     dev[d] = -1;
                     if (dd->ci[d] == 0)
@@ -486,8 +492,8 @@ static void calcGroupMove(FILE*                     fplog,
                 {
                     if (pos_d >= moveLimits.upper[d])
                     {
-                        cg_move_error(fplog, dd, step, g, d, 1, true, moveLimits.distance[d],
-                                      cogOld, cog, pos_d);
+                        cg_move_error(
+                                fplog, dd, step, g, d, 1, true, moveLimits.distance[d], cogOld, cog, pos_d);
                     }
                     dev[d] = 1;
                     if (dd->ci[d] == dd->numCells[d] - 1)
@@ -499,8 +505,8 @@ static void calcGroupMove(FILE*                     fplog,
                 {
                     if (pos_d < moveLimits.lower[d])
                     {
-                        cg_move_error(fplog, dd, step, g, d, -1, true, moveLimits.distance[d],
-                                      cogOld, cog, pos_d);
+                        cg_move_error(
+                                fplog, dd, step, g, d, -1, true, moveLimits.distance[d], cogOld, cog, pos_d);
                     }
                     dev[d] = -1;
                     if (dd->ci[d] == 0)
@@ -564,8 +570,8 @@ void dd_redistribute_cg(FILE*         fplog,
     }
 
     // Positions are always present, so there's nothing to flag
-    bool bV   = (state->flags & (1 << estV)) != 0;
-    bool bCGP = (state->flags & (1 << estCGP)) != 0;
+    bool bV   = (state->flags & enumValueToBitMask(StateEntry::V)) != 0;
+    bool bCGP = (state->flags & enumValueToBitMask(StateEntry::Cgp)) != 0;
 
     DDBufferAccess<int> moveBuffer(comm->intBuffer, dd->ncg_home);
     gmx::ArrayRef<int>  move = moveBuffer.buffer;
@@ -611,7 +617,7 @@ void dd_redistribute_cg(FILE*         fplog,
     matrix tcm;
     make_tric_corr_matrix(npbcdim, state->box, tcm);
 
-    const int nthread = gmx_omp_nthreads_get(emntDomdec);
+    const int nthread = gmx_omp_nthreads_get(ModuleMultiThread::Domdec);
 
     /* Compute the center of geometry for all home charge groups
      * and put them in the box and determine where they should go.
@@ -629,21 +635,43 @@ void dd_redistribute_cg(FILE*         fplog,
             {
                 const auto& updateGroupsCog = *comm->updateGroupsCog;
                 const int   numGroups       = updateGroupsCog.numCogs();
-                calcGroupMove(fplog, step, dd, state, tric_dir, tcm, cell_x0, cell_x1, moveLimits,
-                              (thread * numGroups) / nthread, ((thread + 1) * numGroups) / nthread,
+                calcGroupMove(fplog,
+                              step,
+                              dd,
+                              state,
+                              tric_dir,
+                              tcm,
+                              cell_x0,
+                              cell_x1,
+                              moveLimits,
+                              (thread * numGroups) / nthread,
+                              ((thread + 1) * numGroups) / nthread,
                               pbcAndFlags);
                 /* We need a barrier as atoms below can be in a COG of a different thread */
 #pragma omp barrier
                 const int numHomeAtoms = comm->atomRanges.numHomeAtoms();
-                applyPbcAndSetMoveFlags(updateGroupsCog, pbcAndFlags, (thread * numHomeAtoms) / nthread,
-                                        ((thread + 1) * numHomeAtoms) / nthread, state->x, move);
+                applyPbcAndSetMoveFlags(updateGroupsCog,
+                                        pbcAndFlags,
+                                        (thread * numHomeAtoms) / nthread,
+                                        ((thread + 1) * numHomeAtoms) / nthread,
+                                        state->x,
+                                        move);
             }
             else
             {
                 /* Here we handle single atoms or charge groups */
-                calc_cg_move(fplog, step, dd, state, tric_dir, tcm, cell_x0, cell_x1, moveLimits,
+                calc_cg_move(fplog,
+                             step,
+                             dd,
+                             state,
+                             tric_dir,
+                             tcm,
+                             cell_x0,
+                             cell_x1,
+                             moveLimits,
                              (thread * dd->ncg_home) / nthread,
-                             ((thread + 1) * dd->ncg_home) / nthread, move);
+                             ((thread + 1) * dd->ncg_home) / nthread,
+                             move);
             }
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
@@ -764,16 +792,26 @@ void dd_redistribute_cg(FILE*         fplog,
             flagBuffer.resize((ncg_recv + rbuf[0]) * DD_CGIBS);
 
             /* Communicate the charge group indices, sizes and flags */
-            ddSendrecv(dd, d, dir, comm->cggl_flag[cdd].data(), sbuf[0] * DD_CGIBS,
-                       flagBuffer.buffer.data() + ncg_recv * DD_CGIBS, rbuf[0] * DD_CGIBS);
+            ddSendrecv(dd,
+                       d,
+                       dir,
+                       comm->cggl_flag[cdd].data(),
+                       sbuf[0] * DD_CGIBS,
+                       flagBuffer.buffer.data() + ncg_recv * DD_CGIBS,
+                       rbuf[0] * DD_CGIBS);
 
             const int nvs = ncg[cdd] + nat[cdd] * nvec;
             const int i   = rbuf[0] + rbuf[1] * nvec;
             rvecBuffer.resize(nvr + i);
 
             /* Communicate cgcm and state */
-            ddSendrecv(dd, d, dir, as_rvec_array(comm->cgcm_state[cdd].data()), nvs,
-                       as_rvec_array(rvecBuffer.buffer.data()) + nvr, i);
+            ddSendrecv(dd,
+                       d,
+                       dir,
+                       as_rvec_array(comm->cgcm_state[cdd].data()),
+                       nvs,
+                       as_rvec_array(rvecBuffer.buffer.data()) + nvr,
+                       i);
             ncg_recv += rbuf[0];
             nvr += i;
         }
@@ -797,8 +835,8 @@ void dd_redistribute_cg(FILE*         fplog,
                     || ((flag & DD_FLAG_BW(d)) && cog[dim] < cell_x0[dim]))
                 {
                     rvec pos = { cog[0], cog[1], cog[2] };
-                    cg_move_error(fplog, dd, step, cg, dim, (flag & DD_FLAG_FW(d)) ? 1 : 0, false,
-                                  0, pos, pos, pos[dim]);
+                    cg_move_error(
+                            fplog, dd, step, cg, dim, (flag & DD_FLAG_FW(d)) ? 1 : 0, false, 0, pos, pos, pos[dim]);
                 }
             }
 
@@ -927,8 +965,10 @@ void dd_redistribute_cg(FILE*         fplog,
                 }
                 /* Copy from the receive to the send buffers */
                 memcpy(comm->cggl_flag[mc].data() + ncg[mc] * DD_CGIBS,
-                       flagBuffer.buffer.data() + cg * DD_CGIBS, DD_CGIBS * sizeof(int));
-                memcpy(comm->cgcm_state[mc][nvr], rvecBuffer.buffer.data() + buf_pos,
+                       flagBuffer.buffer.data() + cg * DD_CGIBS,
+                       DD_CGIBS * sizeof(int));
+                memcpy(comm->cgcm_state[mc][nvr],
+                       rvecBuffer.buffer.data() + buf_pos,
                        (1 + nrcg * nvec) * sizeof(rvec));
                 buf_pos += 1 + nrcg * nvec;
                 ncg[mc] += 1;
@@ -957,7 +997,9 @@ void dd_redistribute_cg(FILE*         fplog,
 
     if (debug)
     {
-        fprintf(debug, "Finished repartitioning: cgs moved out %d, new home %d\n", *ncg_moved,
+        fprintf(debug,
+                "Finished repartitioning: cgs moved out %d, new home %d\n",
+                *ncg_moved,
                 dd->ncg_home - *ncg_moved);
     }
 }
diff --git a/src/gromacs/domdec/tests/.clang-tidy b/src/gromacs/domdec/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 9b3eb6678d3c4c4f92204c8b23f1031254329c54..c763db0a9e58c57772a3f8a7450058d5ba0f451a 100644 (file)
@@ -150,8 +150,8 @@ void gpuHalo(gmx_domdec_t* dd, matrix box, HostVector<RVec>* h_x, int numAtomsTo
     {
         for (int pulse = 0; pulse < dd->comm->cd[d].numPulses(); pulse++)
         {
-            gpuHaloExchange[d].push_back(GpuHaloExchange(dd, d, MPI_COMM_WORLD, deviceContext,
-                                                         deviceStream, deviceStream, pulse, nullptr));
+            gpuHaloExchange[d].push_back(GpuHaloExchange(
+                    dd, d, MPI_COMM_WORLD, deviceContext, deviceStream, deviceStream, pulse, nullptr));
         }
     }
 
@@ -170,8 +170,8 @@ void gpuHalo(gmx_domdec_t* dd, matrix box, HostVector<RVec>* h_x, int numAtomsTo
     haloCompletedEvent.waitForEvent();
 
     // Copy results back to host
-    copyFromDeviceBuffer(h_x->data(), &d_x, 0, numAtomsTotal, deviceStream,
-                         GpuApiCallBehavior::Sync, nullptr);
+    copyFromDeviceBuffer(
+            h_x->data(), &d_x, 0, numAtomsTotal, deviceStream, GpuApiCallBehavior::Sync, nullptr);
 
     freeDeviceBuffer(d_x);
 #else
diff --git a/src/gromacs/energyanalysis/tests/.clang-tidy b/src/gromacs/energyanalysis/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 1edaf7a796dc55c901aa7ae376905af4fe4a2153..3f5304064b2c2375b998240a63bb171eedadcd9e 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,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+add_library(essentialdynamics INTERFACE)
+
 file(GLOB ESSENTIALDYNAMICS_SOURCES *.cpp)
+
+# Source files have the following private module dependencies.
+target_link_libraries(essentialdynamics PRIVATE
+                      #                      gmxlib
+                      #                      math
+                      #                      mdtypes
+                      #                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(essentialdynamics PUBLIC
+target_include_directories(essentialdynamics INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(essentialdynamics PUBLIC
+target_link_libraries(essentialdynamics INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when fileio is an OBJECT target
+#target_link_libraries(fileio PUBLIC legacy_api)
+#target_link_libraries(fileio PRIVATE common)
+
+# Module dependencies
+# fileio interfaces convey transitive dependence on these modules.
+#target_link_libraries(essentialdynamics PUBLIC
+target_link_libraries(essentialdynamics INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(essentialdynamics PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(essentialdynamics PRIVATE legacy_modules)
+
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${ESSENTIALDYNAMICS_SOURCES} PARENT_SCOPE)
 
 if (BUILD_TESTING)
index aebd672980e33fa4eadd1843f523a45086755c60..605c36d485780c12ea150b839618bf0d190b8183 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gmxlib/nrnb.h"
 #include "gromacs/linearalgebra/nrjac.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/math/vectypes.h"
@@ -493,7 +494,7 @@ real calc_radius(const t_eigvec& vec)
         rad += gmx::square((vec.refproj[i] - vec.xproj[i]));
     }
 
-    return rad = sqrt(rad);
+    return sqrt(rad);
 }
 } // namespace
 
@@ -903,14 +904,14 @@ static void update_adaption(t_edpar* edi)
 }
 
 
-static void do_single_flood(FILE*            edo,
-                            const rvec       x[],
-                            rvec             force[],
-                            t_edpar*         edi,
-                            int64_t          step,
-                            const matrix     box,
-                            const t_commrec* cr,
-                            gmx_bool         bNS) /* Are we in a neighbor searching step? */
+static void do_single_flood(FILE*                          edo,
+                            gmx::ArrayRef<const gmx::RVec> coords,
+                            gmx::ArrayRef<gmx::RVec>       force,
+                            t_edpar*                       edi,
+                            int64_t                        step,
+                            const matrix                   box,
+                            const t_commrec*               cr,
+                            gmx_bool bNS) /* Are we in a neighbor searching step? */
 {
     int                i;
     matrix             rotmat;   /* rotation matrix */
@@ -926,16 +927,34 @@ static void do_single_flood(FILE*            edo,
     /* Broadcast the positions of the AVERAGE structure such that they are known on
      * every processor. Each node contributes its local positions x and stores them in
      * the collective ED array buf->xcoll */
-    communicate_group_positions(cr, buf->xcoll, buf->shifts_xcoll, buf->extra_shifts_xcoll, bNS, x,
-                                edi->sav.nr, edi->sav.nr_loc, edi->sav.anrs_loc, edi->sav.c_ind,
-                                edi->sav.x_old, box);
+    communicate_group_positions(cr,
+                                buf->xcoll,
+                                buf->shifts_xcoll,
+                                buf->extra_shifts_xcoll,
+                                bNS,
+                                as_rvec_array(coords.data()),
+                                edi->sav.nr,
+                                edi->sav.nr_loc,
+                                edi->sav.anrs_loc,
+                                edi->sav.c_ind,
+                                edi->sav.x_old,
+                                box);
 
     /* Only assembly REFERENCE positions if their indices differ from the average ones */
     if (!edi->bRefEqAv)
     {
-        communicate_group_positions(cr, buf->xc_ref, buf->shifts_xc_ref, buf->extra_shifts_xc_ref,
-                                    bNS, x, edi->sref.nr, edi->sref.nr_loc, edi->sref.anrs_loc,
-                                    edi->sref.c_ind, edi->sref.x_old, box);
+        communicate_group_positions(cr,
+                                    buf->xc_ref,
+                                    buf->shifts_xc_ref,
+                                    buf->extra_shifts_xc_ref,
+                                    bNS,
+                                    as_rvec_array(coords.data()),
+                                    edi->sref.nr,
+                                    edi->sref.nr_loc,
+                                    edi->sref.anrs_loc,
+                                    edi->sref.c_ind,
+                                    edi->sref.x_old,
+                                    box);
     }
 
     /* If bUpdateShifts was TRUE, the shifts have just been updated in get_positions.
@@ -1009,20 +1028,20 @@ static void do_single_flood(FILE*            edo,
 
 
 /* Main flooding routine, called from do_force */
-extern void do_flood(const t_commrec*  cr,
-                     const t_inputrec* ir,
-                     const rvec        x[],
-                     rvec              force[],
-                     gmx_edsam*        ed,
-                     const matrix      box,
-                     int64_t           step,
-                     gmx_bool          bNS)
+void do_flood(const t_commrec*               cr,
+              const t_inputrec&              ir,
+              gmx::ArrayRef<const gmx::RVec> coords,
+              gmx::ArrayRef<gmx::RVec>       force,
+              gmx_edsam*                     ed,
+              const matrix                   box,
+              int64_t                        step,
+              bool                           bNS)
 {
     /* Write time to edo, when required. Output the time anyhow since we need
      * it in the output file for ED constraints. */
     if (MASTER(cr) && do_per_step(step, ed->edpar.begin()->outfrq))
     {
-        fprintf(ed->edo, "\n%12f", ir->init_t + step * ir->delta_t);
+        fprintf(ed->edo, "\n%12f", ir.init_t + step * ir.delta_t);
     }
 
     if (ed->eEDtype != EssentialDynamicsType::Flooding)
@@ -1035,7 +1054,7 @@ extern void do_flood(const t_commrec*  cr,
         /* Call flooding for one matrix */
         if (edi.flood.vecs.neig)
         {
-            do_single_flood(ed->edo, x, force, &edi, step, box, cr, bNS);
+            do_single_flood(ed->edo, coords, force, &edi, step, box, cr, bNS);
         }
     }
 }
@@ -1057,7 +1076,9 @@ static void init_flood(t_edpar* edi, gmx_edsam* ed, real dt)
         /* If in any of the ED groups we find a flooding vector, flooding is turned on */
         ed->eEDtype = EssentialDynamicsType::Flooding;
 
-        fprintf(stderr, "ED: Flooding %d eigenvector%s.\n", edi->flood.vecs.neig,
+        fprintf(stderr,
+                "ED: Flooding %d eigenvector%s.\n",
+                edi->flood.vecs.neig,
                 edi->flood.vecs.neig > 1 ? "s" : "");
 
         if (edi->flood.bConstForce)
@@ -1069,8 +1090,10 @@ static void init_flood(t_edpar* edi, gmx_edsam* ed, real dt)
             {
                 edi->flood.vecs.fproj[i] = edi->flood.vecs.stpsz[i];
 
-                fprintf(stderr, "ED: applying on eigenvector %d a constant force of %g\n",
-                        edi->flood.vecs.ieig[i], edi->flood.vecs.fproj[i]);
+                fprintf(stderr,
+                        "ED: applying on eigenvector %d a constant force of %g\n",
+                        edi->flood.vecs.ieig[i],
+                        edi->flood.vecs.fproj[i]);
             }
         }
     }
@@ -1135,8 +1158,8 @@ static std::unique_ptr<gmx::EssentialDynamics> ed_open(int
                                                        const gmx_output_env_t*     oenv,
                                                        const t_commrec*            cr)
 {
-    auto edHandle = std::make_unique<gmx::EssentialDynamics>();
-    auto ed       = edHandle->getLegacyED();
+    auto  edHandle = std::make_unique<gmx::EssentialDynamics>();
+    auto* ed       = edHandle->getLegacyED();
     /* We want to perform ED (this switch might later be upgraded to EssentialDynamicsType::Flooding) */
     ed->eEDtype = EssentialDynamicsType::EDSampling;
 
@@ -1170,8 +1193,11 @@ static std::unique_ptr<gmx::EssentialDynamics> ed_open(int
         }
         else
         {
-            ed->edo = xvgropen(edoFileName, "Essential dynamics / flooding output", "Time (ps)",
-                               "RMSDs (nm), projections on EVs (nm), ...", oenv);
+            ed->edo = xvgropen(edoFileName,
+                               "Essential dynamics / flooding output",
+                               "Time (ps)",
+                               "RMSDs (nm), projections on EVs (nm), ...",
+                               oenv);
 
             /* Make a descriptive legend */
             write_edo_legend(ed, EDstate->nED, oenv);
@@ -1199,8 +1225,7 @@ static void bc_ed_positions(const t_commrec* cr, struct gmx_edx* s, EssentialDyn
          * There, also memory is allocated */
         s->nalloc_loc = 0;                    /* allocation size of s->anrs_loc */
         snew_bc(MASTER(cr), s->x_old, s->nr); /* To be able to always make the ED molecule whole, ... */
-        nblock_bc(cr->mpi_comm_mygroup, s->nr,
-                  s->x_old); /* ... keep track of shift changes with the help of old coords */
+        nblock_bc(cr->mpi_comm_mygroup, s->nr, s->x_old); /* ... keep track of shift changes with the help of old coords */
     }
 
     /* broadcast masses for the reference structure (for mass-weighted fitting) */
@@ -1265,10 +1290,8 @@ static void broadcast_ed_data(const t_commrec* cr, gmx_edsam* ed)
         block_bc(cr->mpi_comm_mygroup, edi);
 
         /* Broadcast positions */
-        bc_ed_positions(cr, &(edi.sref),
-                        EssentialDynamicsStructure::Reference); /* reference positions (don't broadcast masses)    */
-        bc_ed_positions(cr, &(edi.sav),
-                        EssentialDynamicsStructure::Average); /* average positions (do broadcast masses as well) */
+        bc_ed_positions(cr, &(edi.sref), EssentialDynamicsStructure::Reference); /* reference positions (don't broadcast masses)    */
+        bc_ed_positions(cr, &(edi.sav), EssentialDynamicsStructure::Average); /* average positions (do broadcast masses as well) */
         bc_ed_positions(cr, &(edi.star), EssentialDynamicsStructure::Target); /* target positions */
         bc_ed_positions(cr, &(edi.sori), EssentialDynamicsStructure::Origin); /* origin positions */
 
@@ -1295,7 +1318,7 @@ static void broadcast_ed_data(const t_commrec* cr, gmx_edsam* ed)
 
 
 /* init-routine called for every *.edi-cycle, initialises t_edpar structure */
-static void init_edi(const gmx_mtop_t* mtop, t_edpar* edi)
+static void init_edi(const gmx_mtop_t& mtop, t_edpar* edi)
 {
     int  i;
     real totalmass = 0.0;
@@ -1328,7 +1351,9 @@ static void init_edi(const gmx_mtop_t* mtop, t_edpar* edi)
                       ">0.\n"
                       "Either make the covariance analysis non-mass-weighted, or exclude massless\n"
                       "atoms from the reference structure by creating a proper index group.\n",
-                      i, edi->sref.anrs[i] + 1, edi->sref.m[i]);
+                      i,
+                      edi->sref.anrs[i] + 1,
+                      edi->sref.m[i]);
         }
 
         totalmass += edi->sref.m[i];
@@ -1360,7 +1385,9 @@ static void init_edi(const gmx_mtop_t* mtop, t_edpar* edi)
                       ">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, edi->sav.m[i]);
+                      i,
+                      edi->sav.anrs[i] + 1,
+                      edi->sav.m[i]);
         }
     }
 
@@ -1383,7 +1410,8 @@ static void check(const char* line, const char* label)
         gmx_fatal(FARGS,
                   "Could not find input parameter %s at expected position in edsam input-file "
                   "(.edi)\nline read instead is %s",
-                  label, line);
+                  label,
+                  line);
     }
 }
 
@@ -1558,8 +1586,8 @@ bool readEdVecWithReferenceProjection(FILE*     in,
         double    stepSize            = 0.;
         double    referenceProjection = 0.;
         double    referenceSlope      = 0.;
-        const int nscan = sscanf(line, max_ev_fmt_dlflflf, &numEigenVectors, &stepSize,
-                                 &referenceProjection, &referenceSlope);
+        const int nscan               = sscanf(
+                line, max_ev_fmt_dlflflf, &numEigenVectors, &stepSize, &referenceProjection, &referenceSlope);
         /* Zero out values which were not scanned */
         switch (nscan)
         {
@@ -1732,8 +1760,7 @@ t_edpar read_edi(FILE* in, int nr_mdatoms, bool hasConstForceFlooding, const cha
     edi.nini = read_edint(in, &bEOF);
     if (edi.nini != nr_mdatoms)
     {
-        gmx_fatal(FARGS, "Nr of atoms in %s (%d) does not match nr of md atoms (%d)", fn, edi.nini,
-                  nr_mdatoms);
+        gmx_fatal(FARGS, "Nr of atoms in %s (%d) does not match nr of md atoms (%d)", fn, edi.nini, nr_mdatoms);
     }
 
     /* Done checking. For the rest we blindly trust the input */
@@ -1788,7 +1815,9 @@ t_edpar read_edi(FILE* in, int nr_mdatoms, bool hasConstForceFlooding, const cha
     bool bHaveReference = false;
     if (edi.flood.bHarmonic)
     {
-        bHaveReference = readEdVecWithReferenceProjection(in, edi.sav.nr, &edi.flood.vecs,
+        bHaveReference = readEdVecWithReferenceProjection(in,
+                                                          edi.sav.nr,
+                                                          &edi.flood.vecs,
                                                           &edi.flood.initialReferenceProjection,
                                                           &edi.flood.referenceProjectionSlope);
     }
@@ -1855,7 +1884,9 @@ std::vector<t_edpar> read_edi_file(const char* fn, int nr_mdatoms)
         gmx_fatal(FARGS, "No complete ED data set found in edi file %s.", fn);
     }
 
-    fprintf(stderr, "ED: Found %zu ED group%s.\n", essentialDynamicsParameters.size(),
+    fprintf(stderr,
+            "ED: Found %zu ED group%s.\n",
+            essentialDynamicsParameters.size(),
             essentialDynamicsParameters.size() > 1 ? "s" : "");
 
     /* Close the .edi file again */
@@ -1960,13 +1991,23 @@ void dd_make_local_ed_indices(gmx_domdec_t* dd, struct gmx_edsam* ed)
              * if their indices differ from the average ones */
             if (!edi.bRefEqAv)
             {
-                dd_make_local_group_indices(dd->ga2la, edi.sref.nr, edi.sref.anrs, &edi.sref.nr_loc,
-                                            &edi.sref.anrs_loc, &edi.sref.nalloc_loc, edi.sref.c_ind);
+                dd_make_local_group_indices(dd->ga2la,
+                                            edi.sref.nr,
+                                            edi.sref.anrs,
+                                            &edi.sref.nr_loc,
+                                            &edi.sref.anrs_loc,
+                                            &edi.sref.nalloc_loc,
+                                            edi.sref.c_ind);
             }
 
             /* Local atoms of the average structure (on these ED will be performed) */
-            dd_make_local_group_indices(dd->ga2la, edi.sav.nr, edi.sav.anrs, &edi.sav.nr_loc,
-                                        &edi.sav.anrs_loc, &edi.sav.nalloc_loc, edi.sav.c_ind);
+            dd_make_local_group_indices(dd->ga2la,
+                                        edi.sav.nr,
+                                        edi.sav.anrs,
+                                        &edi.sav.nr_loc,
+                                        &edi.sav.anrs_loc,
+                                        &edi.sav.nalloc_loc,
+                                        edi.sav.c_ind);
 
             /* Indicate that the ED shift vectors for this structure need to be updated
              * at the next call to communicate_group_positions, since obviously we are in a NS step */
@@ -2382,14 +2423,18 @@ static void crosscheck_edi_file_vs_checkpoint(const gmx_edsam& ed, edsamhistory_
             gmx_fatal(FARGS,
                       "The number of reference structure atoms in ED group %c is\n"
                       "not the same in .cpt (NREF=%d) and .edi (NREF=%d) files!\n",
-                      get_EDgroupChar(edinum + 1, 0), EDstate->nref[edinum], ed.edpar[edinum].sref.nr);
+                      get_EDgroupChar(edinum + 1, 0),
+                      EDstate->nref[edinum],
+                      ed.edpar[edinum].sref.nr);
         }
         if (EDstate->nav[edinum] != ed.edpar[edinum].sav.nr)
         {
             gmx_fatal(FARGS,
                       "The number of average structure atoms in ED group %c is\n"
                       "not the same in .cpt (NREF=%d) and .edi (NREF=%d) files!\n",
-                      get_EDgroupChar(edinum + 1, 0), EDstate->nav[edinum], ed.edpar[edinum].sav.nr);
+                      get_EDgroupChar(edinum + 1, 0),
+                      EDstate->nav[edinum],
+                      ed.edpar[edinum].sav.nr);
         }
     }
 
@@ -2399,7 +2444,8 @@ static void crosscheck_edi_file_vs_checkpoint(const gmx_edsam& ed, edsamhistory_
                   "The number of essential dynamics / flooding groups is not consistent.\n"
                   "There are %d ED groups in the .cpt file, but %zu in the .edi file!\n"
                   "Are you sure this is the correct .edi file?\n",
-                  EDstate->nED, ed.edpar.size());
+                  EDstate->nED,
+                  ed.edpar.size());
     }
 }
 
@@ -2522,29 +2568,37 @@ static void write_edo_legend(gmx_edsam* ed, int nED, const gmx_output_env_t* oen
 
     auto edi = ed->edpar.begin();
 
-    fprintf(ed->edo, "# Output will be written every %d step%s\n", edi->outfrq,
-            edi->outfrq != 1 ? "s" : "");
+    fprintf(ed->edo, "# Output will be written every %d step%s\n", edi->outfrq, edi->outfrq != 1 ? "s" : "");
 
     for (nr_edi = 1; nr_edi <= nED; nr_edi++)
     {
         fprintf(ed->edo, "#\n");
-        fprintf(ed->edo, "# Summary of applied con/restraints for the ED group %c\n",
+        fprintf(ed->edo,
+                "# Summary of applied con/restraints for the ED group %c\n",
                 get_EDgroupChar(nr_edi, nED));
         fprintf(ed->edo, "# Atoms in average structure: %d\n", edi->sav.nr);
-        fprintf(ed->edo, "#    monitor  : %d vec%s\n", edi->vecs.mon.neig,
-                edi->vecs.mon.neig != 1 ? "s" : "");
-        fprintf(ed->edo, "#    LINFIX   : %d vec%s\n", edi->vecs.linfix.neig,
+        fprintf(ed->edo, "#    monitor  : %d vec%s\n", edi->vecs.mon.neig, edi->vecs.mon.neig != 1 ? "s" : "");
+        fprintf(ed->edo,
+                "#    LINFIX   : %d vec%s\n",
+                edi->vecs.linfix.neig,
                 edi->vecs.linfix.neig != 1 ? "s" : "");
-        fprintf(ed->edo, "#    LINACC   : %d vec%s\n", edi->vecs.linacc.neig,
+        fprintf(ed->edo,
+                "#    LINACC   : %d vec%s\n",
+                edi->vecs.linacc.neig,
                 edi->vecs.linacc.neig != 1 ? "s" : "");
-        fprintf(ed->edo, "#    RADFIX   : %d vec%s\n", edi->vecs.radfix.neig,
+        fprintf(ed->edo,
+                "#    RADFIX   : %d vec%s\n",
+                edi->vecs.radfix.neig,
                 edi->vecs.radfix.neig != 1 ? "s" : "");
-        fprintf(ed->edo, "#    RADACC   : %d vec%s\n", edi->vecs.radacc.neig,
+        fprintf(ed->edo,
+                "#    RADACC   : %d vec%s\n",
+                edi->vecs.radacc.neig,
                 edi->vecs.radacc.neig != 1 ? "s" : "");
-        fprintf(ed->edo, "#    RADCON   : %d vec%s\n", edi->vecs.radcon.neig,
+        fprintf(ed->edo,
+                "#    RADCON   : %d vec%s\n",
+                edi->vecs.radcon.neig,
                 edi->vecs.radcon.neig != 1 ? "s" : "");
-        fprintf(ed->edo, "#    FLOODING : %d vec%s  ", edi->flood.vecs.neig,
-                edi->flood.vecs.neig != 1 ? "s" : "");
+        fprintf(ed->edo, "#    FLOODING : %d vec%s  ", edi->flood.vecs.neig, edi->flood.vecs.neig != 1 ? "s" : "");
 
         if (edi->flood.vecs.neig)
         {
@@ -2653,32 +2707,53 @@ static void write_edo_legend(gmx_edsam* ed, int nED, const gmx_output_env_t* oen
             nice_legend(&setname, &nsets, &LegendStr, "RMSD to ref", "nm", get_EDgroupChar(nr_edi, nED));
 
             /* Essential dynamics, projections on eigenvectors */
-            nice_legend_evec(&setname, &nsets, &LegendStr, &edi->vecs.mon,
-                             get_EDgroupChar(nr_edi, nED), "MON");
-            nice_legend_evec(&setname, &nsets, &LegendStr, &edi->vecs.linfix,
-                             get_EDgroupChar(nr_edi, nED), "LINFIX");
-            nice_legend_evec(&setname, &nsets, &LegendStr, &edi->vecs.linacc,
-                             get_EDgroupChar(nr_edi, nED), "LINACC");
-            nice_legend_evec(&setname, &nsets, &LegendStr, &edi->vecs.radfix,
-                             get_EDgroupChar(nr_edi, nED), "RADFIX");
+            nice_legend_evec(&setname,
+                             &nsets,
+                             &LegendStr,
+                             &edi->vecs.mon,
+                             get_EDgroupChar(nr_edi, nED),
+                             "MON");
+            nice_legend_evec(&setname,
+                             &nsets,
+                             &LegendStr,
+                             &edi->vecs.linfix,
+                             get_EDgroupChar(nr_edi, nED),
+                             "LINFIX");
+            nice_legend_evec(&setname,
+                             &nsets,
+                             &LegendStr,
+                             &edi->vecs.linacc,
+                             get_EDgroupChar(nr_edi, nED),
+                             "LINACC");
+            nice_legend_evec(&setname,
+                             &nsets,
+                             &LegendStr,
+                             &edi->vecs.radfix,
+                             get_EDgroupChar(nr_edi, nED),
+                             "RADFIX");
             if (edi->vecs.radfix.neig)
             {
-                nice_legend(&setname, &nsets, &LegendStr, "RADFIX radius", "nm",
-                            get_EDgroupChar(nr_edi, nED));
+                nice_legend(&setname, &nsets, &LegendStr, "RADFIX radius", "nm", get_EDgroupChar(nr_edi, nED));
             }
-            nice_legend_evec(&setname, &nsets, &LegendStr, &edi->vecs.radacc,
-                             get_EDgroupChar(nr_edi, nED), "RADACC");
+            nice_legend_evec(&setname,
+                             &nsets,
+                             &LegendStr,
+                             &edi->vecs.radacc,
+                             get_EDgroupChar(nr_edi, nED),
+                             "RADACC");
             if (edi->vecs.radacc.neig)
             {
-                nice_legend(&setname, &nsets, &LegendStr, "RADACC radius", "nm",
-                            get_EDgroupChar(nr_edi, nED));
+                nice_legend(&setname, &nsets, &LegendStr, "RADACC radius", "nm", get_EDgroupChar(nr_edi, nED));
             }
-            nice_legend_evec(&setname, &nsets, &LegendStr, &edi->vecs.radcon,
-                             get_EDgroupChar(nr_edi, nED), "RADCON");
+            nice_legend_evec(&setname,
+                             &nsets,
+                             &LegendStr,
+                             &edi->vecs.radcon,
+                             get_EDgroupChar(nr_edi, nED),
+                             "RADCON");
             if (edi->vecs.radcon.neig)
             {
-                nice_legend(&setname, &nsets, &LegendStr, "RADCON radius", "nm",
-                            get_EDgroupChar(nr_edi, nED));
+                nice_legend(&setname, &nsets, &LegendStr, "RADCON radius", "nm", get_EDgroupChar(nr_edi, nED));
             }
         }
         ++edi;
@@ -2691,7 +2766,10 @@ static void write_edo_legend(gmx_edsam* ed, int nED, const gmx_output_env_t* oen
     fprintf(ed->edo,
             "#\n"
             "# Legend for %d column%s of flooding plus %d column%s of essential dynamics data:\n",
-            n_flood, 1 == n_flood ? "" : "s", n_edsam, 1 == n_edsam ? "" : "s");
+            n_flood,
+            1 == n_flood ? "" : "s",
+            n_edsam,
+            1 == n_edsam ? "" : "s");
     fprintf(ed->edo, "%s", LegendStr);
     sfree(LegendStr);
 
@@ -2704,8 +2782,8 @@ static void write_edo_legend(gmx_edsam* ed, int nED, const gmx_output_env_t* oen
 std::unique_ptr<gmx::EssentialDynamics> init_edsam(const gmx::MDLogger&        mdlog,
                                                    const char*                 ediFileName,
                                                    const char*                 edoFileName,
-                                                   const gmx_mtop_t*           mtop,
-                                                   const t_inputrec*           ir,
+                                                   const gmx_mtop_t&           mtop,
+                                                   const t_inputrec&           ir,
                                                    const t_commrec*            cr,
                                                    gmx::Constraints*           constr,
                                                    const t_state*              globalState,
@@ -2740,8 +2818,8 @@ std::unique_ptr<gmx::EssentialDynamics> init_edsam(const gmx::MDLogger&        m
                     "gmx grompp and the related .mdp options may change also.");
 
     /* Open input and output files, allocate space for ED data structure */
-    auto edHandle = ed_open(mtop->natoms, oh, ediFileName, edoFileName, startingBehavior, oenv, cr);
-    auto ed       = edHandle->getLegacyED();
+    auto  edHandle = ed_open(mtop.natoms, oh, ediFileName, edoFileName, startingBehavior, oenv, cr);
+    auto* ed       = edHandle->getLegacyED();
     GMX_RELEASE_ASSERT(constr != nullptr, "Must have valid constraints object");
     constr->saveEdsamPointer(ed);
 
@@ -2760,7 +2838,7 @@ std::unique_ptr<gmx::EssentialDynamics> init_edsam(const gmx::MDLogger&        m
         for (auto& edi : ed->edpar)
         {
             init_edi(mtop, &edi);
-            init_flood(&edi, ed, ir->delta_t);
+            init_flood(&edi, ed, ir.delta_t);
         }
     }
 
@@ -2773,9 +2851,9 @@ std::unique_ptr<gmx::EssentialDynamics> init_edsam(const gmx::MDLogger&        m
         if (!EDstate->bFromCpt)
         {
             /* Remove PBC, make molecule(s) subject to ED whole. */
-            snew(x_pbc, mtop->natoms);
-            copy_rvecn(globalState->x.rvec_array(), x_pbc, 0, mtop->natoms);
-            do_pbc_first_mtop(nullptr, ir->pbcType, globalState->box, mtop, x_pbc);
+            snew(x_pbc, mtop.natoms);
+            copy_rvecn(globalState->x.rvec_array(), x_pbc, 0, mtop.natoms);
+            do_pbc_first_mtop(nullptr, ir.pbcType, globalState->box, &mtop, x_pbc);
         }
         /* Reset pointer to first ED data set which contains the actual ED data */
         auto edi = ed->edpar.begin();
@@ -2832,7 +2910,8 @@ std::unique_ptr<gmx::EssentialDynamics> init_edsam(const gmx::MDLogger&        m
 
             /* Output how well we fit to the reference at the start */
             translate_and_rotate(xfit, edi->sref.nr, fit_transvec, fit_rotmat);
-            fprintf(stderr, "ED: Initial RMSD from reference after fit = %f nm",
+            fprintf(stderr,
+                    "ED: Initial RMSD from reference after fit = %f nm",
                     rmsd_from_structure(xfit, &edi->sref));
             if (EDstate->nED > 1)
             {
@@ -2954,12 +3033,13 @@ std::unique_ptr<gmx::EssentialDynamics> init_edsam(const gmx::MDLogger&        m
             {
                 for (i = 0; i < edi->flood.vecs.neig; i++)
                 {
-                    fprintf(stdout, "ED: EV %d flooding potential center: %11.4e",
-                            edi->flood.vecs.ieig[i], edi->flood.vecs.refproj[i]);
+                    fprintf(stdout,
+                            "ED: EV %d flooding potential center: %11.4e",
+                            edi->flood.vecs.ieig[i],
+                            edi->flood.vecs.refproj[i]);
                     if (edi->flood.bHarmonic)
                     {
-                        fprintf(stdout, " (adding %11.4e/timestep)",
-                                edi->flood.referenceProjectionSlope[i]);
+                        fprintf(stdout, " (adding %11.4e/timestep)", edi->flood.referenceProjectionSlope[i]);
                     }
                     fprintf(stdout, "\n");
                 }
@@ -3062,7 +3142,13 @@ std::unique_ptr<gmx::EssentialDynamics> init_edsam(const gmx::MDLogger&        m
 }
 
 
-void do_edsam(const t_inputrec* ir, int64_t step, const t_commrec* cr, rvec xs[], rvec v[], const matrix box, gmx_edsam* ed)
+void do_edsam(const t_inputrec*        ir,
+              int64_t                  step,
+              const t_commrec*         cr,
+              gmx::ArrayRef<gmx::RVec> coords,
+              gmx::ArrayRef<gmx::RVec> velocities,
+              const matrix             box,
+              gmx_edsam*               ed)
 {
     int    i, edinr, iupdate = 500;
     matrix rotmat;         /* rotation matrix */
@@ -3106,17 +3192,34 @@ void do_edsam(const t_inputrec* ir, int64_t step, const t_commrec* cr, rvec xs[]
              * the collective buf->xcoll array. Note that for edinr > 1
              * xs could already have been modified by an earlier ED */
 
-            communicate_group_positions(cr, buf->xcoll, buf->shifts_xcoll, buf->extra_shifts_xcoll,
-                                        PAR(cr) ? buf->bUpdateShifts : TRUE, xs, edi.sav.nr, edi.sav.nr_loc,
-                                        edi.sav.anrs_loc, edi.sav.c_ind, edi.sav.x_old, box);
+            communicate_group_positions(cr,
+                                        buf->xcoll,
+                                        buf->shifts_xcoll,
+                                        buf->extra_shifts_xcoll,
+                                        PAR(cr) ? buf->bUpdateShifts : TRUE,
+                                        as_rvec_array(coords.data()),
+                                        edi.sav.nr,
+                                        edi.sav.nr_loc,
+                                        edi.sav.anrs_loc,
+                                        edi.sav.c_ind,
+                                        edi.sav.x_old,
+                                        box);
 
             /* Only assembly reference positions if their indices differ from the average ones */
             if (!edi.bRefEqAv)
             {
-                communicate_group_positions(
-                        cr, buf->xc_ref, buf->shifts_xc_ref, buf->extra_shifts_xc_ref,
-                        PAR(cr) ? buf->bUpdateShifts : TRUE, xs, edi.sref.nr, edi.sref.nr_loc,
-                        edi.sref.anrs_loc, edi.sref.c_ind, edi.sref.x_old, box);
+                communicate_group_positions(cr,
+                                            buf->xc_ref,
+                                            buf->shifts_xc_ref,
+                                            buf->extra_shifts_xc_ref,
+                                            PAR(cr) ? buf->bUpdateShifts : TRUE,
+                                            as_rvec_array(coords.data()),
+                                            edi.sref.nr,
+                                            edi.sref.nr_loc,
+                                            edi.sref.anrs_loc,
+                                            edi.sref.c_ind,
+                                            edi.sref.x_old,
+                                            box);
             }
 
             /* If bUpdateShifts was TRUE then the shifts have just been updated in communicate_group_positions.
@@ -3212,21 +3315,21 @@ void do_edsam(const t_inputrec* ir, int64_t step, const t_commrec* cr, rvec xs[]
                 for (i = 0; i < edi.sav.nr_loc; i++)
                 {
                     /* Unshift local ED coordinate and store in x_unsh */
-                    ed_unshift_single_coord(box, buf->xcoll[edi.sav.c_ind[i]],
-                                            buf->shifts_xcoll[edi.sav.c_ind[i]], x_unsh);
+                    ed_unshift_single_coord(
+                            box, buf->xcoll[edi.sav.c_ind[i]], buf->shifts_xcoll[edi.sav.c_ind[i]], x_unsh);
 
                     /* dx is the ED correction to the positions: */
-                    rvec_sub(x_unsh, xs[edi.sav.anrs_loc[i]], dx);
+                    rvec_sub(x_unsh, coords[edi.sav.anrs_loc[i]], dx);
 
-                    if (v != nullptr)
+                    if (!velocities.empty())
                     {
                         /* dv is the ED correction to the velocity: */
                         svmul(dt_1, dx, dv);
                         /* apply the velocity correction: */
-                        rvec_inc(v[edi.sav.anrs_loc[i]], dv);
+                        rvec_inc(velocities[edi.sav.anrs_loc[i]], dv);
                     }
                     /* Finally apply the position correction due to ED: */
-                    copy_rvec(x_unsh, xs[edi.sav.anrs_loc[i]]);
+                    copy_rvec(x_unsh, coords[edi.sav.anrs_loc[i]]);
                 }
             }
         } /* END of if ( bNeedDoEdsam(edi) ) */
index 502abde6beae2c787b6ad4a7a9df21b41560f1db..957f8c8f0297d73e20db96c39b6f4863bfe65b8b 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@
 #include <memory>
 
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/classhelpers.h"
 
 /*! \brief Abstract type for essential dynamics
  *
@@ -73,6 +71,9 @@ namespace gmx
 {
 enum class StartingBehavior;
 class Constraints;
+template<typename>
+class ArrayRef;
+
 class EssentialDynamics
 {
 public:
@@ -88,7 +89,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 class MDLogger;
 } // namespace gmx
@@ -98,18 +99,18 @@ class MDLogger;
  * \param ir                MD input parameter record.
  * \param step              Number of the time step.
  * \param cr                Data needed for MPI communication.
- * \param xs                The local positions on this processor.
- * \param v                 The local velocities.
+ * \param coords            The local positions on this processor.
+ * \param velocities        The local velocities.
  * \param box               The simulation box.
  * \param ed                The essential dynamics data.
  */
-void do_edsam(const t_inputrec* ir,
-              int64_t           step,
-              const t_commrec*  cr,
-              rvec              xs[],
-              rvec              v[],
-              const matrix      box,
-              gmx_edsam*        ed);
+void do_edsam(const t_inputrec*        ir,
+              int64_t                  step,
+              const t_commrec*         cr,
+              gmx::ArrayRef<gmx::RVec> coords,
+              gmx::ArrayRef<gmx::RVec> velocities,
+              const matrix             box,
+              gmx_edsam*               ed);
 
 
 /*! \brief Initializes the essential dynamics and flooding module.
@@ -131,8 +132,8 @@ void do_edsam(const t_inputrec* ir,
 std::unique_ptr<gmx::EssentialDynamics> init_edsam(const gmx::MDLogger&    mdlog,
                                                    const char*             ediFileName,
                                                    const char*             edoFileName,
-                                                   const gmx_mtop_t*       mtop,
-                                                   const t_inputrec*       ir,
+                                                   const gmx_mtop_t&       mtop,
+                                                   const t_inputrec&       ir,
                                                    const t_commrec*        cr,
                                                    gmx::Constraints*       constr,
                                                    const t_state*          globalState,
@@ -154,20 +155,20 @@ void dd_make_local_ed_indices(gmx_domdec_t* dd, gmx_edsam* ed);
  *
  * \param cr                Data needed for MPI communication.
  * \param ir                MD input parameter record.
- * \param x                 Positions on the local processor.
+ * \param coords            Positions on the local processor.
  * \param force             Forcefield forces to which the flooding forces are added.
  * \param ed                The essential dynamics data.
  * \param box               The simulation box.
  * \param step              Number of the time step.
  * \param bNS               Are we in a neighbor searching step?
  */
-void do_flood(const t_commrec*  cr,
-              const t_inputrec* ir,
-              const rvec        x[],
-              rvec              force[],
-              gmx_edsam*        ed,
-              const matrix      box,
-              int64_t           step,
-              gmx_bool          bNS);
+void do_flood(const t_commrec*               cr,
+              const t_inputrec&              ir,
+              gmx::ArrayRef<const gmx::RVec> coords,
+              gmx::ArrayRef<gmx::RVec>       force,
+              gmx_edsam*                     ed,
+              const matrix                   box,
+              int64_t                        step,
+              bool                           bNS);
 
 #endif
index ba9faa378e93ad6155e43b81cd1681610c33c8c6..ac50cc1a4811948787c6e9366f7b71efa2712e9c 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
-# Copyright (c) 2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -33,6 +33,8 @@
 # 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 up the module library
+add_library(ewald INTERFACE)
 gmx_add_libgromacs_sources(
     calculate_spline_moduli.cpp
     ewald.cpp
@@ -74,7 +76,7 @@ if (GMX_GPU_CUDA)
         # Must add these files so they can include device_information.h
         pme_gpu_internal.cpp
         pme_gpu_timings.cpp
-       )
+        )
 elseif (GMX_GPU_OPENCL)
     gmx_add_libgromacs_sources(
         # OpenCL-specific sources
@@ -88,11 +90,18 @@ elseif (GMX_GPU_OPENCL)
 elseif (GMX_GPU_SYCL)
     # SYCL-TODO: proper implementation
     gmx_add_libgromacs_sources(
-        pme_gpu_program_impl.cpp
+        # Files that implement stubs
+        pme_gpu_sycl_stubs.cpp
+        # GPU-specific sources
+        pme_gpu.cpp
+        pme_gpu_internal.cpp
+        pme_gpu_timings.cpp
         )
     _gmx_add_files_to_property(SYCL_SOURCES
-        pme_gpu_program_impl.cpp
+        pme_gpu_internal.cpp
         pme_gpu_program.cpp
+        pme_gpu_sycl_stubs.cpp
+        pme_gpu_timings.cpp
         )
 else()
     gmx_add_libgromacs_sources(
@@ -101,6 +110,38 @@ else()
         )
 endif()
 
+# Source files have the following private module dependencies.
+target_link_libraries(ewald PRIVATE
+                      #                      gmxlib
+                      #                      math
+                      #                      mdtypes
+                      #                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(ewald PUBLIC
+target_include_directories(ewald INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(ewald PUBLIC
+target_link_libraries(ewald INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when fileio is an OBJECT target
+#target_link_libraries(ewald PUBLIC legacy_api)
+#target_link_libraries(ewald PRIVATE common)
+
+# Module dependencies
+# This module convey transitive dependence on these modules.
+#target_link_libraries(ewald PUBLIC
+target_link_libraries(ewald INTERFACE
+                      #                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(ewald PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(ewald PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index 09dc3998fb67f01018a761d46d0a24e4a835a2bd..c428a5654a85e188f48234e2ccdb286c71c42439 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 
 #include <algorithm>
 
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/utility/exceptions.h"
index 6e089c2b99c511867ac4f7fa33c608667d4e5c00..3a62f306d1f906baf7ea398209fc52d02a0357e4 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/interaction_const.h"
 #include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
 
-struct gmx_ewald_tab_t
-{
-    int        nx, ny, nz, kmax;
-    cvec**     eir;
-    t_complex *tab_xy, *tab_qxyz;
-};
+using cvec = std::array<t_complex, DIM>;
 
-void init_ewald_tab(struct gmx_ewald_tab_t** et, const t_inputrec* ir, FILE* fp)
+gmx_ewald_tab_t::gmx_ewald_tab_t(const t_inputrec& ir, FILE* fp)
 {
-    snew(*et, 1);
     if (fp)
     {
         fprintf(fp, "Will do ordinary reciprocal space Ewald sum.\n");
     }
 
-    (*et)->nx       = ir->nkx + 1;
-    (*et)->ny       = ir->nky + 1;
-    (*et)->nz       = ir->nkz + 1;
-    (*et)->kmax     = std::max((*et)->nx, std::max((*et)->ny, (*et)->nz));
-    (*et)->eir      = nullptr;
-    (*et)->tab_xy   = nullptr;
-    (*et)->tab_qxyz = nullptr;
+    nx   = ir.nkx + 1;
+    ny   = ir.nky + 1;
+    nz   = ir.nkz + 1;
+    kmax = std::max(nx, std::max(ny, nz));
 }
 
+gmx_ewald_tab_t::~gmx_ewald_tab_t() = default;
+
 //! Calculates wave vectors.
 static void calc_lll(const rvec box, rvec lll)
 {
@@ -104,7 +98,7 @@ static void calc_lll(const rvec box, rvec lll)
 }
 
 //! Make tables for the structure factor parts
-static void tabulateStructureFactors(int natom, const rvec x[], int kmax, cvec** eir, const rvec lll)
+static void tabulateStructureFactors(int natom, gmx::ArrayRef<const gmx::RVec> x, int kmax, cvec** eir, const rvec lll)
 {
     int i, j, m;
 
@@ -137,27 +131,27 @@ static void tabulateStructureFactors(int natom, const rvec x[], int kmax, cvec**
     }
 }
 
-real do_ewald(const t_inputrec* ir,
-              const rvec        x[],
-              rvec              f[],
-              const real        chargeA[],
-              const real        chargeB[],
-              const matrix      box,
-              const t_commrec*  cr,
-              int               natoms,
-              matrix            lrvir,
-              real              ewaldcoeff,
-              real              lambda,
-              real*             dvdlambda,
-              gmx_ewald_tab_t*  et)
+real do_ewald(const t_inputrec&              ir,
+              gmx::ArrayRef<const gmx::RVec> x,
+              gmx::ArrayRef<gmx::RVec>       f,
+              gmx::ArrayRef<const real>      chargeA,
+              gmx::ArrayRef<const real>      chargeB,
+              const matrix                   box,
+              const t_commrec*               cr,
+              int                            natoms,
+              matrix                         lrvir,
+              real                           ewaldcoeff,
+              real                           lambda,
+              real*                          dvdlambda,
+              gmx_ewald_tab_t*               et)
 {
-    real        factor = -1.0 / (4 * ewaldcoeff * ewaldcoeff);
-    const real* charge;
-    real        energy_AB[2], energy;
-    rvec        lll;
-    int         lowiy, lowiz, ix, iy, iz, n, q;
-    real        tmp, cs, ss, ak, akv, mx, my, mz, m2, scale;
-    gmx_bool    bFreeEnergy;
+    real   factor = -1.0 / (4 * ewaldcoeff * ewaldcoeff);
+    real   energy_AB[2], energy;
+    rvec   lll;
+    int    lowiy, lowiz, ix, iy, iz, n, q;
+    real   tmp, cs, ss, ak, akv, mx, my, mz, m2, scale;
+    cvec** eir;
+    bool   bFreeEnergy;
 
     if (cr != nullptr)
     {
@@ -169,7 +163,7 @@ real do_ewald(const t_inputrec* ir,
 
     /* Scale box with Ewald wall factor */
     matrix          scaledBox;
-    EwaldBoxZScaler boxScaler(*ir);
+    EwaldBoxZScaler boxScaler(ir);
     boxScaler.scaleBox(box, scaledBox);
 
     rvec boxDiag;
@@ -179,26 +173,25 @@ real do_ewald(const t_inputrec* ir,
     }
 
     /* 1/(Vol*e0) */
-    real scaleRecip = 4.0 * M_PI / (boxDiag[XX] * boxDiag[YY] * boxDiag[ZZ]) * ONE_4PI_EPS0 / ir->epsilon_r;
+    real scaleRecip =
+            4.0 * M_PI / (boxDiag[XX] * boxDiag[YY] * boxDiag[ZZ]) * gmx::c_one4PiEps0 / ir.epsilon_r;
 
-    if (!et->eir) /* allocate if we need to */
+    snew(eir, et->kmax);
+    for (n = 0; n < et->kmax; n++)
     {
-        snew(et->eir, et->kmax);
-        for (n = 0; n < et->kmax; n++)
-        {
-            snew(et->eir[n], natoms);
-        }
-        snew(et->tab_xy, natoms);
-        snew(et->tab_qxyz, natoms);
+        snew(eir[n], natoms);
     }
+    et->tab_xy.resize(natoms);
+    et->tab_qxyz.resize(natoms);
 
-    bFreeEnergy = (ir->efep != efepNO);
+    bFreeEnergy = (ir.efep != FreeEnergyPerturbationType::No);
 
     clear_mat(lrvir);
 
     calc_lll(boxDiag, lll);
-    tabulateStructureFactors(natoms, x, et->kmax, et->eir, lll);
+    tabulateStructureFactors(natoms, x, et->kmax, eir, lll);
 
+    gmx::ArrayRef<const real> charge;
     for (q = 0; q < (bFreeEnergy ? 2 : 1); q++)
     {
         if (!bFreeEnergy)
@@ -229,14 +222,14 @@ real do_ewald(const t_inputrec* ir,
                 {
                     for (n = 0; n < natoms; n++)
                     {
-                        et->tab_xy[n] = cmul(et->eir[ix][n][XX], et->eir[iy][n][YY]);
+                        et->tab_xy[n] = cmul(eir[ix][n][XX], eir[iy][n][YY]);
                     }
                 }
                 else
                 {
                     for (n = 0; n < natoms; n++)
                     {
-                        et->tab_xy[n] = cmul(et->eir[ix][n][XX], conjugate(et->eir[-iy][n][YY]));
+                        et->tab_xy[n] = cmul(eir[ix][n][XX], conjugate(eir[-iy][n][YY]));
                     }
                 }
                 for (iz = lowiz; iz < et->nz; iz++)
@@ -249,15 +242,15 @@ real do_ewald(const t_inputrec* ir,
                     {
                         for (n = 0; n < natoms; n++)
                         {
-                            et->tab_qxyz[n] = rcmul(charge[n], cmul(et->tab_xy[n], et->eir[iz][n][ZZ]));
+                            et->tab_qxyz[n] = rcmul(charge[n], cmul(et->tab_xy[n], eir[iz][n][ZZ]));
                         }
                     }
                     else
                     {
                         for (n = 0; n < natoms; n++)
                         {
-                            et->tab_qxyz[n] = rcmul(
-                                    charge[n], cmul(et->tab_xy[n], conjugate(et->eir[-iz][n][ZZ])));
+                            et->tab_qxyz[n] =
+                                    rcmul(charge[n], cmul(et->tab_xy[n], conjugate(eir[-iz][n][ZZ])));
                         }
                     }
 
@@ -337,7 +330,7 @@ real ewald_charge_correction(const t_commrec*  cr,
         /* Apply charge correction */
         vol = box[XX][XX] * box[YY][YY] * box[ZZ][ZZ];
 
-        fac = M_PI * ONE_4PI_EPS0
+        fac = M_PI * gmx::c_one4PiEps0
               / (fr->ic->epsilon_r * 2.0 * vol * vol * gmx::square(fr->ic->ewaldcoeff_q));
 
         qs2A = fr->qsum[0] * fr->qsum[0];
index 77fc79b3fa16b066e4ffd752bb59f0acfe4253bd..2d4d20bc98c8ded83c0253c6693eb2963d27c4b0 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <stdio.h>
 
+#include <vector>
+
 #include "gromacs/math/vectypes.h"
 #include "gromacs/utility/real.h"
 
 struct t_commrec;
 struct t_forcerec;
 struct t_inputrec;
+struct t_complex;
+
+namespace gmx
+{
+template<typename>
+class ArrayRef;
+}
+
+struct gmx_ewald_tab_t
+{
+    gmx_ewald_tab_t(const t_inputrec& ir, FILE* fp);
+
+    ~gmx_ewald_tab_t();
 
-/* Forward declaration of type for managing Ewald tables */
-struct gmx_ewald_tab_t;
+    int nx;
+    int ny;
+    int nz;
+    int kmax;
 
-/*! \brief Initialize the tables used in the Ewald long-ranged part */
-void init_ewald_tab(struct gmx_ewald_tab_t** et, const t_inputrec* ir, FILE* fp);
+    std::vector<t_complex> tab_xy;
+    std::vector<t_complex> tab_qxyz;
+};
 
 /*! \brief Do the long-ranged part of an Ewald calculation */
-real do_ewald(const t_inputrec* ir,
-              const rvec        x[],
-              rvec              f[],
-              const real        chargeA[],
-              const real        chargeB[],
-              const matrix      box,
-              const t_commrec*  cr,
-              int               natoms,
-              matrix            lrvir,
-              real              ewaldcoeff,
-              real              lambda,
-              real*             dvdlambda,
-              gmx_ewald_tab_t*  et);
+real do_ewald(const t_inputrec&              ir,
+              gmx::ArrayRef<const gmx::RVec> x,
+              gmx::ArrayRef<gmx::RVec>       f,
+              gmx::ArrayRef<const real>      chargeA,
+              gmx::ArrayRef<const real>      chargeB,
+              const matrix                   box,
+              const t_commrec*               cr,
+              int                            natoms,
+              matrix                         lrvir,
+              real                           ewaldcoeff,
+              real                           lambda,
+              real*                          dvdlambda,
+              gmx_ewald_tab_t*               et);
 
 /*! \brief Calculate the correction to the Ewald sum, due to a net system
  * charge.
index 9f77967c377a927c5a7ab55a0d0ec59218a14db2..4639d1571ba911c1d0bd36c009c0f6887edf3df6 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,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2017,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +122,7 @@ public:
      * \param[in] box        The current box matrix
      * \param[out] scaledBox Scaled copy of the box matrix.
      */
-    void scaleBox(const matrix box, matrix scaledBox)
+    void scaleBox(const matrix box, matrix scaledBox) const
     {
         GMX_ASSERT(box, "invalid source box pointer");
         GMX_ASSERT(scaledBox, "invalid target box pointer");
index b62a25e58ccb22529fffbab3f8846b1212730747..b5791ead4746be2ef7935312c5cbc0e3a8f213ea 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * perturbations. The parameter vectors for LJ-PME are likewise
  * undefined when LJ-PME is not active. This works because
  * bHaveChargeOrTypePerturbed handles the control flow. */
-void ewald_LRcorrection(const int         numAtomsLocal,
-                        const t_commrec*  cr,
-                        int               numThreads,
-                        int               thread,
-                        const t_forcerec& fr,
-                        const t_inputrec& ir,
-                        const real*       chargeA,
-                        const real*       chargeB,
-                        gmx_bool          bHaveChargePerturbed,
-                        const rvec        x[],
-                        const matrix      box,
-                        const rvec        mu_tot[],
-                        rvec*             f,
-                        real*             Vcorr_q,
-                        real              lambda_q,
-                        real*             dvdlambda_q)
+void ewald_LRcorrection(const int                      numAtomsLocal,
+                        const t_commrec*               cr,
+                        int                            numThreads,
+                        int                            thread,
+                        const t_forcerec&              fr,
+                        const t_inputrec&              ir,
+                        gmx::ArrayRef<const real>      chargeA,
+                        gmx::ArrayRef<const real>      chargeB,
+                        bool                           bHaveChargePerturbed,
+                        gmx::ArrayRef<const gmx::RVec> x,
+                        const matrix                   box,
+                        gmx::ArrayRef<const gmx::RVec> mu_tot,
+                        gmx::ArrayRef<gmx::RVec>       f,
+                        real*                          Vcorr_q,
+                        real                           lambda_q,
+                        real*                          dvdlambda_q)
 {
     /* We need to correct only self interactions */
     const int start = (numAtomsLocal * thread) / numThreads;
@@ -98,7 +98,7 @@ void ewald_LRcorrection(const int         numAtomsLocal,
     EwaldBoxZScaler boxScaler(ir);
     boxScaler.scaleBox(box, scaledBox);
 
-    one_4pi_eps = ONE_4PI_EPS0 / fr.ic->epsilon_r;
+    one_4pi_eps = gmx::c_one4PiEps0 / fr.ic->epsilon_r;
     Vexcl_q     = 0;
     dvdl_excl_q = 0;
     Vdipole[0]  = 0;
@@ -109,8 +109,8 @@ void ewald_LRcorrection(const int         numAtomsLocal,
      */
     for (i = 0; (i < DIM); i++)
     {
-        mutot[0][i] = mu_tot[0][i] * DEBYE2ENM;
-        mutot[1][i] = mu_tot[1][i] * DEBYE2ENM;
+        mutot[0][i] = mu_tot[0][i] * gmx::c_debye2Enm;
+        mutot[1][i] = mu_tot[1][i] * gmx::c_debye2Enm;
         dipcorrA[i] = 0;
         dipcorrB[i] = 0;
     }
@@ -119,10 +119,10 @@ void ewald_LRcorrection(const int         numAtomsLocal,
     real boxVolume = scaledBox[XX][XX] * scaledBox[YY][YY] * scaledBox[ZZ][ZZ];
     switch (ir.ewald_geometry)
     {
-        case eewg3D:
+        case EwaldGeometry::ThreeD:
             if (ir.epsilon_surface != 0)
             {
-                dipole_coeff = 2 * M_PI * ONE_4PI_EPS0
+                dipole_coeff = 2 * M_PI * gmx::c_one4PiEps0
                                / ((2 * ir.epsilon_surface + fr.ic->epsilon_r) * boxVolume);
                 for (i = 0; (i < DIM); i++)
                 {
@@ -131,7 +131,7 @@ void ewald_LRcorrection(const int         numAtomsLocal,
                 }
             }
             break;
-        case eewg3DC:
+        case EwaldGeometry::ThreeDC:
             dipole_coeff = 2 * M_PI * one_4pi_eps / boxVolume;
             dipcorrA[ZZ] = 2 * dipole_coeff * mutot[0][ZZ];
             dipcorrB[ZZ] = 2 * dipole_coeff * mutot[1][ZZ];
@@ -195,11 +195,11 @@ void ewald_LRcorrection(const int         numAtomsLocal,
              */
             if (dipole_coeff != 0)
             {
-                if (ir.ewald_geometry == eewg3D)
+                if (ir.ewald_geometry == EwaldGeometry::ThreeD)
                 {
                     Vdipole[q] = dipole_coeff * iprod(mutot[q], mutot[q]);
                 }
-                else if (ir.ewald_geometry == eewg3DC)
+                else if (ir.ewald_geometry == EwaldGeometry::ThreeDC)
                 {
                     Vdipole[q] = dipole_coeff * mutot[q][ZZ] * mutot[q][ZZ];
 
@@ -211,11 +211,11 @@ void ewald_LRcorrection(const int         numAtomsLocal,
                          * We could implement a reduction over threads,
                          * but this case is rarely used.
                          */
-                        const real* qPtr   = (q == 0 ? chargeA : chargeB);
-                        real        sumQZ2 = 0;
+                        gmx::ArrayRef<const real> charge = (q == 0 ? chargeA : chargeB);
+                        real                      sumQZ2 = 0;
                         for (int i = 0; i < numAtomsLocal; i++)
                         {
-                            sumQZ2 += qPtr[i] * x[i][ZZ] * x[i][ZZ];
+                            sumQZ2 += charge[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);
@@ -237,14 +237,17 @@ void ewald_LRcorrection(const int         numAtomsLocal,
     if (debug)
     {
         fprintf(debug, "Long Range corrections for Ewald interactions:\n");
-        fprintf(debug, "q2sum = %g, Vself_q=%g\n", L1_q * fr.q2sum[0] + lambda_q * fr.q2sum[1],
+        fprintf(debug,
+                "q2sum = %g, Vself_q=%g\n",
+                L1_q * fr.q2sum[0] + lambda_q * fr.q2sum[1],
                 L1_q * Vself_q[0] + lambda_q * Vself_q[1]);
         fprintf(debug, "Electrostatic Long Range correction: Vexcl=%g\n", Vexcl_q);
         if (MASTER(cr) && thread == 0)
         {
-            if (ir.epsilon_surface > 0 || ir.ewald_geometry == eewg3DC)
+            if (ir.epsilon_surface > 0 || ir.ewald_geometry == EwaldGeometry::ThreeDC)
             {
-                fprintf(debug, "Total dipole correction: Vdipole=%g\n",
+                fprintf(debug,
+                        "Total dipole correction: Vdipole=%g\n",
                         L1_q * Vdipole[0] + lambda_q * Vdipole[1]);
             }
         }
index df0a7405695f847ce1e8d2b8c9440a8fb978300c..f6fb0c5e8cc1d36c18e996a433cdfb573621d88d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_EWALD_LONG_RANGE_CORRECTION_H
 
 #include "gromacs/math/vectypes.h"
-#include "gromacs/topology/block.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
 struct t_commrec;
 struct t_forcerec;
 struct t_inputrec;
 
+namespace gmx
+{
+template<typename>
+class ArrayRef;
+}
+
 /*! \brief Calculate long-range Ewald correction terms.
  *
  * Calculate correction for electrostatic surface dipole terms.
  */
-void ewald_LRcorrection(int               numAtomsLocal,
-                        const t_commrec*  cr,
-                        int               numThreads,
-                        int               thread,
-                        const t_forcerec& fr,
-                        const t_inputrec& ir,
-                        const real*       chargeA,
-                        const real*       chargeB,
-                        gmx_bool          bHaveChargePerturbed,
-                        const rvec        x[],
-                        const matrix      box,
-                        const rvec        mu_tot[],
-                        rvec*             f,
-                        real*             Vcorr_q,
-                        real              lambda_q,
-                        real*             dvdlambda_q);
+void ewald_LRcorrection(int                            numAtomsLocal,
+                        const t_commrec*               cr,
+                        int                            numThreads,
+                        int                            thread,
+                        const t_forcerec&              fr,
+                        const t_inputrec&              ir,
+                        gmx::ArrayRef<const real>      chargeA,
+                        gmx::ArrayRef<const real>      chargeB,
+                        bool                           bHaveChargePerturbed,
+                        gmx::ArrayRef<const gmx::RVec> x,
+                        const matrix                   box,
+                        gmx::ArrayRef<const gmx::RVec> mu_tot,
+                        gmx::ArrayRef<gmx::RVec>       f,
+                        real*                          Vcorr_q,
+                        real                           lambda_q,
+                        real*                          dvdlambda_q);
 
 #endif
index 76051509ecd8d499821b82fd8ed07e7bf290a18d..efea5c7a06786dc624de6a27d464435e39fd10ab 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 The GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -475,8 +475,18 @@ static void init_overlap_comm(pme_overlap_t* ol, int norder, MPI_Comm comm, int
     MPI_Status stat;
     for (size_t b = 0; b < ol->comm_data.size(); b++)
     {
-        MPI_Sendrecv(&ol->send_size, 1, MPI_INT, ol->comm_data[b].send_id, b, &ol->comm_data[b].recv_size,
-                     1, MPI_INT, ol->comm_data[b].recv_id, b, ol->mpi_comm, &stat);
+        MPI_Sendrecv(&ol->send_size,
+                     1,
+                     MPI_INT,
+                     ol->comm_data[b].send_id,
+                     b,
+                     &ol->comm_data[b].recv_size,
+                     1,
+                     MPI_INT,
+                     ol->comm_data[b].recv_id,
+                     b,
+                     ol->mpi_comm,
+                     &stat);
     }
 #endif
 
@@ -514,7 +524,8 @@ bool gmx_pme_check_restrictions(int pme_order, int nkx, int nky, int nkz, int nu
         std::string message = gmx::formatString(
                 "pme_order (%d) is larger than the maximum allowed value (%d). Modify and "
                 "recompile the code if you really need such a high order.",
-                pme_order, PME_ORDER_MAX);
+                pme_order,
+                PME_ORDER_MAX);
         GMX_THROW(gmx::InconsistentInputError(message));
     }
 
@@ -545,7 +556,8 @@ bool gmx_pme_check_restrictions(int pme_order, int nkx, int nky, int nkz, int nu
                   "threads, the number of grid lines per rank along x should be >= pme_order (%d) "
                   "or = pmeorder-1. To resolve this issue, use fewer ranks along x (and possibly "
                   "more along y and/or z) by specifying -dd manually.",
-                  nkx / static_cast<double>(numPmeDomainsAlongX), pme_order);
+                  nkx / static_cast<double>(numPmeDomainsAlongX),
+                  pme_order);
     }
 
     return true;
@@ -649,9 +661,13 @@ gmx_pme_t* gmx_pme_init(const t_commrec*     cr,
             pme->ndecompdim = 2;
 
 #if GMX_MPI
-            MPI_Comm_split(pme->mpi_comm, pme->nodeid % numPmeDomains.y, pme->nodeid,
+            MPI_Comm_split(pme->mpi_comm,
+                           pme->nodeid % numPmeDomains.y,
+                           pme->nodeid,
                            &pme->mpi_comm_d[0]); /* My communicator along major dimension */
-            MPI_Comm_split(pme->mpi_comm, pme->nodeid / numPmeDomains.y, pme->nodeid,
+            MPI_Comm_split(pme->mpi_comm,
+                           pme->nodeid / numPmeDomains.y,
+                           pme->nodeid,
                            &pme->mpi_comm_d[1]); /* My communicator along minor dimension */
 
             MPI_Comm_rank(pme->mpi_comm_d[0], &pme->nodeid_major);
@@ -694,15 +710,15 @@ gmx_pme_t* gmx_pme_init(const t_commrec*     cr,
      * 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") != nullptr);
+    pme->doCoulomb = EEL_PME(ir->coulombtype);
+    pme->doLJ      = EVDW_PME(ir->vdwtype);
+    pme->bFEP_q    = ((ir->efep != FreeEnergyPerturbationType::No) && bFreeEnergy_q);
+    pme->bFEP_lj   = ((ir->efep != FreeEnergyPerturbationType::No) && 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 == CoulombInteractionType::P3mAD || getenv("GMX_PME_P3M") != nullptr);
     pme->pme_order     = ir->pme_order;
     pme->ewaldcoeff_q  = ewaldcoeff_q;
     pme->ewaldcoeff_lj = ewaldcoeff_lj;
@@ -719,8 +735,8 @@ gmx_pme_t* gmx_pme_init(const t_commrec*     cr,
     pme->boxScaler = new EwaldBoxZScaler(*ir);
 
     /* If we violate restrictions, generate a fatal error here */
-    gmx_pme_check_restrictions(pme->pme_order, pme->nkx, pme->nky, pme->nkz, pme->nnodes_major,
-                               pme->bUseThreads, true);
+    gmx_pme_check_restrictions(
+            pme->pme_order, pme->nkx, pme->nky, pme->nkz, pme->nnodes_major, pme->bUseThreads, true);
 
     if (pme->nnodes > 1)
     {
@@ -751,8 +767,13 @@ gmx_pme_t* gmx_pme_init(const t_commrec*     cr,
                             "      and PME grid_y (%d) and grid_z (%d) should be divisible by "
                             "#PME_ranks_y "
                             "(%d)",
-                            gmx::roundToInt((imbal - 1) * 100), pme->nkx, pme->nky,
-                            pme->nnodes_major, pme->nky, pme->nkz, pme->nnodes_minor);
+                            gmx::roundToInt((imbal - 1) * 100),
+                            pme->nkx,
+                            pme->nky,
+                            pme->nnodes_major,
+                            pme->nky,
+                            pme->nkz,
+                            pme->nnodes_minor);
         }
     }
 
@@ -761,8 +782,12 @@ gmx_pme_t* gmx_pme_init(const t_commrec*     cr,
      * y is always copied through a buffer: we don't need padding in z,
      * but we do need the overlap in x because of the communication order.
      */
-    init_overlap_comm(&pme->overlap[0], pme->pme_order, pme->mpi_comm_d[0], pme->nnodes_major,
-                      pme->nodeid_major, pme->nkx,
+    init_overlap_comm(&pme->overlap[0],
+                      pme->pme_order,
+                      pme->mpi_comm_d[0],
+                      pme->nnodes_major,
+                      pme->nodeid_major,
+                      pme->nkx,
                       (div_round_up(pme->nky, pme->nnodes_minor) + pme->pme_order)
                               * (pme->nkz + pme->pme_order - 1));
 
@@ -770,8 +795,12 @@ gmx_pme_t* gmx_pme_init(const t_commrec*     cr,
      * We do this with an offset buffer of equal size, so we need to allocate
      * extra for the offset. That's what the (+1)*pme->nkz is for.
      */
-    init_overlap_comm(&pme->overlap[1], pme->pme_order, pme->mpi_comm_d[1], pme->nnodes_minor,
-                      pme->nodeid_minor, pme->nky,
+    init_overlap_comm(&pme->overlap[1],
+                      pme->pme_order,
+                      pme->mpi_comm_d[1],
+                      pme->nnodes_minor,
+                      pme->nodeid_minor,
+                      pme->nky,
                       (div_round_up(pme->nkx, pme->nnodes_major) + pme->pme_order + 1) * pme->nkz);
 
     /* Double-check for a limitation of the (current) sum_fftgrid_dd code.
@@ -803,12 +832,12 @@ gmx_pme_t* gmx_pme_init(const t_commrec*     cr,
     pme->pmegrid_start_iy = pme->overlap[1].s2g0[pme->nodeid_minor];
     pme->pmegrid_start_iz = 0;
 
-    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);
+    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);
 
@@ -820,7 +849,7 @@ gmx_pme_t* gmx_pme_init(const t_commrec*     cr,
      */
     if (pme->doLJ)
     {
-        pme->ngrids = ((ir->ljpme_combination_rule == eljpmeLB) ? DO_Q_AND_LJ_LB : DO_Q_AND_LJ);
+        pme->ngrids = ((ir->ljpme_combination_rule == LongRangeVdW::LB) ? DO_Q_AND_LJ_LB : DO_Q_AND_LJ);
     }
     else
     {
@@ -834,10 +863,16 @@ gmx_pme_t* gmx_pme_init(const t_commrec*     cr,
     {
         if ((i < DO_Q && pme->doCoulomb && (i == 0 || bFreeEnergy_q))
             || (i >= DO_Q && pme->doLJ
-                && (i == 2 || bFreeEnergy_lj || ir->ljpme_combination_rule == eljpmeLB)))
+                && (i == 2 || bFreeEnergy_lj || ir->ljpme_combination_rule == LongRangeVdW::LB)))
         {
-            pmegrids_init(&pme->pmegrid[i], pme->pmegrid_nx, pme->pmegrid_ny, pme->pmegrid_nz,
-                          pme->pmegrid_nz_base, pme->pme_order, pme->bUseThreads, pme->nthread,
+            pmegrids_init(&pme->pmegrid[i],
+                          pme->pmegrid_nx,
+                          pme->pmegrid_ny,
+                          pme->pmegrid_nz,
+                          pme->pmegrid_nz_base,
+                          pme->pme_order,
+                          pme->bUseThreads,
+                          pme->nthread,
                           pme->overlap[0].s2g1[pme->nodeid_major]
                                   - pme->overlap[0].s2g0[pme->nodeid_major + 1],
                           pme->overlap[1].s2g1[pme->nodeid_minor]
@@ -846,8 +881,14 @@ gmx_pme_t* gmx_pme_init(const t_commrec*     cr,
             const auto allocateRealGridForGpu = (pme->runMode == PmeRunMode::Mixed)
                                                         ? gmx::PinningPolicy::PinnedIfSupported
                                                         : gmx::PinningPolicy::CannotBePinned;
-            gmx_parallel_3dfft_init(&pme->pfft_setup[i], ndata, &pme->fftgrid[i], &pme->cfftgrid[i],
-                                    pme->mpi_comm_d, bReproducible, pme->nthread, allocateRealGridForGpu);
+            gmx_parallel_3dfft_init(&pme->pfft_setup[i],
+                                    ndata,
+                                    &pme->fftgrid[i],
+                                    &pme->cfftgrid[i],
+                                    pme->mpi_comm_d,
+                                    bReproducible,
+                                    pme->nthread,
+                                    allocateRealGridForGpu);
         }
     }
 
@@ -928,15 +969,27 @@ void gmx_pme_reinit(struct gmx_pme_t** pmedata,
         const gmx::MDLogger dummyLogger;
         GMX_ASSERT(pmedata, "Invalid PME pointer");
         NumPmeDomains numPmeDomains = { pme_src->nnodes_major, pme_src->nnodes_minor };
-        *pmedata = gmx_pme_init(cr, numPmeDomains, &irc, pme_src->bFEP_q, pme_src->bFEP_lj, FALSE,
-                                ewaldcoeff_q, ewaldcoeff_lj, pme_src->nthread, pme_src->runMode,
-                                pme_src->gpu, nullptr, nullptr, nullptr, dummyLogger);
+        *pmedata                    = gmx_pme_init(cr,
+                                numPmeDomains,
+                                &irc,
+                                pme_src->bFEP_q,
+                                pme_src->bFEP_lj,
+                                FALSE,
+                                ewaldcoeff_q,
+                                ewaldcoeff_lj,
+                                pme_src->nthread,
+                                pme_src->runMode,
+                                pme_src->gpu,
+                                nullptr,
+                                nullptr,
+                                nullptr,
+                                dummyLogger);
         /* When running PME on the CPU not using domain decomposition,
          * the atom data is allocated once only in gmx_pme_(re)init().
          */
         if (!pme_src->gpu && pme_src->nnodes == 1)
         {
-            gmx_pme_reinit_atoms(*pmedata, pme_src->atc[0].numAtoms(), nullptr, nullptr);
+            gmx_pme_reinit_atoms(*pmedata, pme_src->atc[0].numAtoms(), {}, {});
         }
         // TODO this is mostly passing around current values
     }
@@ -947,7 +1000,7 @@ void gmx_pme_reinit(struct gmx_pme_t** pmedata,
     /* We would like to reuse the fft grids, but that's harder */
 }
 
-void gmx_pme_calc_energy(gmx_pme_t* pme, gmx::ArrayRef<const gmx::RVec> x, gmx::ArrayRef<const real> q, real* V)
+real gmx_pme_calc_energy(gmx_pme_t* pme, gmx::ArrayRef<const gmx::RVec> x, gmx::ArrayRef<const real> q)
 {
     pmegrids_t* grid;
 
@@ -975,11 +1028,13 @@ void gmx_pme_calc_energy(gmx_pme_t* pme, gmx::ArrayRef<const gmx::RVec> x, gmx::
     /* Only calculate the spline coefficients, don't actually spread */
     spread_on_grid(pme, atc, nullptr, TRUE, FALSE, pme->fftgrid[PME_GRID_QA], FALSE, PME_GRID_QA);
 
-    *V = gather_energy_bsplines(pme, grid->grid.grid, atc);
+    return gather_energy_bsplines(pme, grid->grid.grid, atc);
 }
 
 /*! \brief Calculate initial Lorentz-Berthelot coefficients for LJ-PME */
-static void calc_initial_lb_coeffs(gmx::ArrayRef<real> coefficient, const real* local_c6, const real* local_sigma)
+static void calc_initial_lb_coeffs(gmx::ArrayRef<real>       coefficient,
+                                   gmx::ArrayRef<const real> local_c6,
+                                   gmx::ArrayRef<const real> local_sigma)
 {
     for (gmx::index i = 0; i < coefficient.ssize(); ++i)
     {
@@ -991,7 +1046,7 @@ static void calc_initial_lb_coeffs(gmx::ArrayRef<real> coefficient, const real*
 }
 
 /*! \brief Calculate next Lorentz-Berthelot coefficients for LJ-PME */
-static void calc_next_lb_coeffs(gmx::ArrayRef<real> coefficient, const real* local_sigma)
+static void calc_next_lb_coeffs(gmx::ArrayRef<real> coefficient, gmx::ArrayRef<const real> local_sigma)
 {
     for (gmx::index i = 0; i < coefficient.ssize(); ++i)
     {
@@ -1002,12 +1057,12 @@ static void calc_next_lb_coeffs(gmx::ArrayRef<real> coefficient, const real* loc
 int gmx_pme_do(struct gmx_pme_t*              pme,
                gmx::ArrayRef<const gmx::RVec> coordinates,
                gmx::ArrayRef<gmx::RVec>       forces,
-               real                           chargeA[],
-               real                           chargeB[],
-               real                           c6A[],
-               real                           c6B[],
-               real                           sigmaA[],
-               real                           sigmaB[],
+               gmx::ArrayRef<const real>      chargeA,
+               gmx::ArrayRef<const real>      chargeB,
+               gmx::ArrayRef<const real>      c6A,
+               gmx::ArrayRef<const real>      c6B,
+               gmx::ArrayRef<const real>      sigmaA,
+               gmx::ArrayRef<const real>      sigmaB,
                const matrix                   box,
                const t_commrec*               cr,
                int                            maxshift_x,
@@ -1027,21 +1082,21 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
     GMX_ASSERT(pme->runMode == PmeRunMode::CPU,
                "gmx_pme_do should not be called on the GPU PME run.");
 
-    int                  d, npme, grid_index, max_grid_index;
-    PmeAtomComm&         atc         = pme->atc[0];
-    pmegrids_t*          pmegrid     = nullptr;
-    real*                grid        = nullptr;
-    real*                coefficient = nullptr;
-    PmeOutput            output[2]; // The second is used for the B state with FEP
-    real                 scale, lambda;
-    gmx_bool             bClearF;
-    gmx_parallel_3dfft_t pfft_setup;
-    real*                fftgrid;
-    t_complex*           cfftgrid;
-    int                  thread;
-    gmx_bool             bFirst, bDoSplines;
-    int                  fep_state;
-    int                  fep_states_lj = pme->bFEP_lj ? 2 : 1;
+    int                       d, npme, grid_index, max_grid_index;
+    PmeAtomComm&              atc     = pme->atc[0];
+    pmegrids_t*               pmegrid = nullptr;
+    real*                     grid    = nullptr;
+    gmx::ArrayRef<const real> coefficient;
+    PmeOutput                 output[2]; // The second is used for the B state with FEP
+    real                      scale, lambda;
+    gmx_bool                  bClearF;
+    gmx_parallel_3dfft_t      pfft_setup;
+    real*                     fftgrid;
+    t_complex*                cfftgrid;
+    int                       thread;
+    gmx_bool                  bFirst, bDoSplines;
+    int                       fep_state;
+    int                       fep_states_lj = pme->bFEP_lj ? 2 : 1;
     // There's no support for computing energy without virial, or vice versa
     const bool computeEnergyAndVirial = (stepWork.computeEnergy || stepWork.computeVirial);
 
@@ -1102,7 +1157,7 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
      */
 
     /* If we are doing LJ-PME with LB, we only do Q here */
-    max_grid_index = (pme->ljpme_combination_rule == eljpmeLB) ? DO_Q : DO_Q_AND_LJ;
+    max_grid_index = (pme->ljpme_combination_rule == LongRangeVdW::LB) ? DO_Q : DO_Q_AND_LJ;
 
     for (grid_index = 0; grid_index < max_grid_index; ++grid_index)
     {
@@ -1143,14 +1198,14 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
 
         if (pme->nnodes == 1)
         {
-            atc.coefficient = gmx::arrayRefFromArray(coefficient, coordinates.size());
+            atc.coefficient = coefficient;
         }
         else
         {
-            wallcycle_start(wcycle, ewcPME_REDISTXF);
+            wallcycle_start(wcycle, WallCycleCounter::PmeRedistXF);
             do_redist_pos_coeffs(pme, cr, bFirst, coordinates, coefficient);
 
-            wallcycle_stop(wcycle, ewcPME_REDISTXF);
+            wallcycle_stop(wcycle, WallCycleCounter::PmeRedistXF);
         }
 
         if (debug)
@@ -1158,7 +1213,7 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
             fprintf(debug, "Rank= %6d, pme local particles=%6d\n", cr->nodeid, atc.numAtoms());
         }
 
-        wallcycle_start(wcycle, ewcPME_SPREAD);
+        wallcycle_start(wcycle, WallCycleCounter::PmeSpread);
 
         /* Spread the coefficients on a grid */
         spread_on_grid(pme, &atc, pmegrid, bFirst, TRUE, fftgrid, bDoSplines, grid_index);
@@ -1182,7 +1237,7 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
             copy_pmegrid_to_fftgrid(pme, grid, fftgrid, grid_index);
         }
 
-        wallcycle_stop(wcycle, ewcPME_SPREAD);
+        wallcycle_stop(wcycle, WallCycleCounter::PmeSpread);
 
         /* TODO If the OpenMP and single-threaded implementations
            converge, then spread_on_grid() and
@@ -1201,48 +1256,59 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
                 /* do 3d-fft */
                 if (thread == 0)
                 {
-                    wallcycle_start(wcycle, ewcPME_FFT);
+                    wallcycle_start(wcycle, WallCycleCounter::PmeFft);
                 }
                 gmx_parallel_3dfft_execute(pfft_setup, GMX_FFT_REAL_TO_COMPLEX, thread, wcycle);
                 if (thread == 0)
                 {
-                    wallcycle_stop(wcycle, ewcPME_FFT);
+                    wallcycle_stop(wcycle, WallCycleCounter::PmeFft);
                 }
 
                 /* solve in k-space for our local cells */
                 if (thread == 0)
                 {
-                    wallcycle_start(wcycle, (grid_index < DO_Q ? ewcPME_SOLVE : ewcLJPME));
+                    wallcycle_start(
+                            wcycle,
+                            (grid_index < DO_Q ? WallCycleCounter::PmeSolve : WallCycleCounter::LJPme));
                 }
                 if (grid_index < DO_Q)
                 {
-                    loop_count = solve_pme_yzx(
-                            pme, cfftgrid, scaledBox[XX][XX] * scaledBox[YY][YY] * scaledBox[ZZ][ZZ],
-                            computeEnergyAndVirial, pme->nthread, thread);
+                    loop_count = solve_pme_yzx(pme,
+                                               cfftgrid,
+                                               scaledBox[XX][XX] * scaledBox[YY][YY] * scaledBox[ZZ][ZZ],
+                                               computeEnergyAndVirial,
+                                               pme->nthread,
+                                               thread);
                 }
                 else
                 {
                     loop_count =
-                            solve_pme_lj_yzx(pme, &cfftgrid, FALSE,
+                            solve_pme_lj_yzx(pme,
+                                             &cfftgrid,
+                                             FALSE,
                                              scaledBox[XX][XX] * scaledBox[YY][YY] * scaledBox[ZZ][ZZ],
-                                             computeEnergyAndVirial, pme->nthread, thread);
+                                             computeEnergyAndVirial,
+                                             pme->nthread,
+                                             thread);
                 }
 
                 if (thread == 0)
                 {
-                    wallcycle_stop(wcycle, (grid_index < DO_Q ? ewcPME_SOLVE : ewcLJPME));
+                    wallcycle_stop(
+                            wcycle,
+                            (grid_index < DO_Q ? WallCycleCounter::PmeSolve : WallCycleCounter::LJPme));
                     inc_nrnb(nrnb, eNR_SOLVEPME, loop_count);
                 }
 
                 /* do 3d-invfft */
                 if (thread == 0)
                 {
-                    wallcycle_start(wcycle, ewcPME_FFT);
+                    wallcycle_start(wcycle, WallCycleCounter::PmeFft);
                 }
                 gmx_parallel_3dfft_execute(pfft_setup, GMX_FFT_COMPLEX_TO_REAL, thread, wcycle);
                 if (thread == 0)
                 {
-                    wallcycle_stop(wcycle, ewcPME_FFT);
+                    wallcycle_stop(wcycle, WallCycleCounter::PmeFft);
 
 
                     if (pme->nodeid == 0)
@@ -1255,7 +1321,7 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
                     /* Note: this wallcycle region is closed below
                        outside an OpenMP region, so take care if
                        refactoring code here. */
-                    wallcycle_start(wcycle, ewcPME_GATHER);
+                    wallcycle_start(wcycle, WallCycleCounter::PmeGather);
                 }
 
                 copy_fftgrid_to_pmegrid(pme, fftgrid, grid, grid_index, pme->nthread, thread);
@@ -1290,18 +1356,21 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
             {
                 try
                 {
-                    gather_f_bsplines(pme, grid, bClearF, &atc, &atc.spline[thread],
+                    gather_f_bsplines(pme,
+                                      grid,
+                                      bClearF,
+                                      &atc,
+                                      &atc.spline[thread],
                                       pme->bFEP ? (grid_index % 2 == 0 ? 1.0 - lambda : lambda) : 1.0);
                 }
                 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
             }
 
 
-            inc_nrnb(nrnb, eNR_GATHERFBSP,
-                     pme->pme_order * pme->pme_order * pme->pme_order * atc.numAtoms());
+            inc_nrnb(nrnb, eNR_GATHERFBSP, pme->pme_order * pme->pme_order * pme->pme_order * atc.numAtoms());
             /* Note: this wallcycle region is opened above inside an OpenMP
                region, so take care if refactoring code here. */
-            wallcycle_stop(wcycle, ewcPME_GATHER);
+            wallcycle_stop(wcycle, WallCycleCounter::PmeGather);
         }
 
         if (computeEnergyAndVirial)
@@ -1324,13 +1393,16 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
     /* For Lorentz-Berthelot combination rules in LJ-PME, we need to calculate
      * seven terms. */
 
-    if (pme->doLJ && pme->ljpme_combination_rule == eljpmeLB)
+    if (pme->doLJ && pme->ljpme_combination_rule == LongRangeVdW::LB)
     {
         /* Loop over A- and B-state if we are doing FEP */
         for (fep_state = 0; fep_state < fep_states_lj; ++fep_state)
         {
-            real *local_c6 = nullptr, *local_sigma = nullptr, *RedistC6 = nullptr, *RedistSigma = nullptr;
-            gmx::ArrayRef<real> coefficientBuffer;
+            std::vector<real>         local_c6;
+            std::vector<real>         local_sigma;
+            gmx::ArrayRef<const real> RedistC6;
+            gmx::ArrayRef<const real> RedistSigma;
+            gmx::ArrayRef<real>       coefficientBuffer;
             if (pme->nnodes == 1)
             {
                 pme->lb_buf1.resize(atc.numAtoms());
@@ -1338,12 +1410,12 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
                 switch (fep_state)
                 {
                     case 0:
-                        local_c6    = c6A;
-                        local_sigma = sigmaA;
+                        local_c6.assign(c6A.begin(), c6A.end());
+                        local_sigma.assign(sigmaA.begin(), sigmaA.end());
                         break;
                     case 1:
-                        local_c6    = c6B;
-                        local_sigma = sigmaB;
+                        local_c6.assign(c6B.begin(), c6B.end());
+                        local_sigma.assign(sigmaB.begin(), sigmaB.end());
                         break;
                     default: gmx_incons("Trying to access wrong FEP-state in LJ-PME routine");
                 }
@@ -1363,25 +1435,25 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
                         break;
                     default: gmx_incons("Trying to access wrong FEP-state in LJ-PME routine");
                 }
-                wallcycle_start(wcycle, ewcPME_REDISTXF);
+                wallcycle_start(wcycle, WallCycleCounter::PmeRedistXF);
 
                 do_redist_pos_coeffs(pme, cr, bFirst, coordinates, RedistC6);
                 pme->lb_buf1.resize(atc.numAtoms());
                 pme->lb_buf2.resize(atc.numAtoms());
-                local_c6 = pme->lb_buf1.data();
+                local_c6.assign(pme->lb_buf1.begin(), pme->lb_buf1.end());
                 for (int i = 0; i < atc.numAtoms(); ++i)
                 {
                     local_c6[i] = atc.coefficient[i];
                 }
 
                 do_redist_pos_coeffs(pme, cr, FALSE, coordinates, RedistSigma);
-                local_sigma = pme->lb_buf2.data();
+                local_sigma.assign(pme->lb_buf2.begin(), pme->lb_buf2.end());
                 for (int i = 0; i < atc.numAtoms(); ++i)
                 {
                     local_sigma[i] = atc.coefficient[i];
                 }
 
-                wallcycle_stop(wcycle, ewcPME_REDISTXF);
+                wallcycle_stop(wcycle, WallCycleCounter::PmeRedistXF);
             }
             atc.coefficient = coefficientBuffer;
             calc_initial_lb_coeffs(coefficientBuffer, local_c6, local_sigma);
@@ -1396,7 +1468,7 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
                 calc_next_lb_coeffs(coefficientBuffer, local_sigma);
                 grid = pmegrid->grid.grid;
 
-                wallcycle_start(wcycle, ewcPME_SPREAD);
+                wallcycle_start(wcycle, WallCycleCounter::PmeSpread);
                 /* Spread the c6 on a grid */
                 spread_on_grid(pme, &atc, pmegrid, bFirst, TRUE, fftgrid, bDoSplines, grid_index);
 
@@ -1405,7 +1477,8 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
                     inc_nrnb(nrnb, eNR_WEIGHTS, DIM * atc.numAtoms());
                 }
 
-                inc_nrnb(nrnb, eNR_SPREADBSP,
+                inc_nrnb(nrnb,
+                         eNR_SPREADBSP,
                          pme->pme_order * pme->pme_order * pme->pme_order * atc.numAtoms());
                 if (pme->nthread == 1)
                 {
@@ -1417,7 +1490,7 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
                     }
                     copy_pmegrid_to_fftgrid(pme, grid, fftgrid, grid_index);
                 }
-                wallcycle_stop(wcycle, ewcPME_SPREAD);
+                wallcycle_stop(wcycle, WallCycleCounter::PmeSpread);
 
                 /*Here we start a large thread parallel region*/
 #pragma omp parallel num_threads(pme->nthread) private(thread)
@@ -1428,13 +1501,13 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
                         /* do 3d-fft */
                         if (thread == 0)
                         {
-                            wallcycle_start(wcycle, ewcPME_FFT);
+                            wallcycle_start(wcycle, WallCycleCounter::PmeFft);
                         }
 
                         gmx_parallel_3dfft_execute(pfft_setup, GMX_FFT_REAL_TO_COMPLEX, thread, wcycle);
                         if (thread == 0)
                         {
-                            wallcycle_stop(wcycle, ewcPME_FFT);
+                            wallcycle_stop(wcycle, WallCycleCounter::PmeFft);
                         }
                     }
                     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
@@ -1450,16 +1523,20 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
                     thread = gmx_omp_get_thread_num();
                     if (thread == 0)
                     {
-                        wallcycle_start(wcycle, ewcLJPME);
+                        wallcycle_start(wcycle, WallCycleCounter::LJPme);
                     }
 
                     loop_count =
-                            solve_pme_lj_yzx(pme, &pme->cfftgrid[2], TRUE,
+                            solve_pme_lj_yzx(pme,
+                                             &pme->cfftgrid[2],
+                                             TRUE,
                                              scaledBox[XX][XX] * scaledBox[YY][YY] * scaledBox[ZZ][ZZ],
-                                             computeEnergyAndVirial, pme->nthread, thread);
+                                             computeEnergyAndVirial,
+                                             pme->nthread,
+                                             thread);
                     if (thread == 0)
                     {
-                        wallcycle_stop(wcycle, ewcLJPME);
+                        wallcycle_stop(wcycle, WallCycleCounter::LJPme);
                         inc_nrnb(nrnb, eNR_SOLVEPME, loop_count);
                     }
                 }
@@ -1492,13 +1569,13 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
                         /* do 3d-invfft */
                         if (thread == 0)
                         {
-                            wallcycle_start(wcycle, ewcPME_FFT);
+                            wallcycle_start(wcycle, WallCycleCounter::PmeFft);
                         }
 
                         gmx_parallel_3dfft_execute(pfft_setup, GMX_FFT_COMPLEX_TO_REAL, thread, wcycle);
                         if (thread == 0)
                         {
-                            wallcycle_stop(wcycle, ewcPME_FFT);
+                            wallcycle_stop(wcycle, WallCycleCounter::PmeFft);
 
 
                             if (pme->nodeid == 0)
@@ -1507,7 +1584,7 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
                                 npme      = static_cast<int>(ntot * std::log(ntot) / std::log(2.0));
                                 inc_nrnb(nrnb, eNR_FFT, 2 * npme);
                             }
-                            wallcycle_start(wcycle, ewcPME_GATHER);
+                            wallcycle_start(wcycle, WallCycleCounter::PmeGather);
                         }
 
                         copy_fftgrid_to_pmegrid(pme, fftgrid, grid, grid_index, pme->nthread, thread);
@@ -1535,26 +1612,27 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
                     {
                         try
                         {
-                            gather_f_bsplines(pme, grid, bClearF, &pme->atc[0],
-                                              &pme->atc[0].spline[thread], scale);
+                            gather_f_bsplines(
+                                    pme, grid, bClearF, &pme->atc[0], &pme->atc[0].spline[thread], scale);
                         }
                         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
                     }
 
 
-                    inc_nrnb(nrnb, eNR_GATHERFBSP,
+                    inc_nrnb(nrnb,
+                             eNR_GATHERFBSP,
                              pme->pme_order * pme->pme_order * pme->pme_order * pme->atc[0].numAtoms());
                 }
-                wallcycle_stop(wcycle, ewcPME_GATHER);
+                wallcycle_stop(wcycle, WallCycleCounter::PmeGather);
 
                 bFirst = FALSE;
             } /* for (grid_index = 8; grid_index >= 2; --grid_index) */
         }     /* for (fep_state = 0; fep_state < fep_states_lj; ++fep_state) */
-    }         /* if (pme->doLJ && pme->ljpme_combination_rule == eljpmeLB) */
+    }         /* if (pme->doLJ && pme->ljpme_combination_rule == LongRangeVdW::LB) */
 
     if (stepWork.computeForces && pme->nnodes > 1)
     {
-        wallcycle_start(wcycle, ewcPME_REDISTXF);
+        wallcycle_start(wcycle, WallCycleCounter::PmeRedistXF);
         for (d = 0; d < pme->ndecompdim; d++)
         {
             gmx::ArrayRef<gmx::RVec> forcesRef;
@@ -1574,7 +1652,7 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
             }
         }
 
-        wallcycle_stop(wcycle, ewcPME_REDISTXF);
+        wallcycle_stop(wcycle, WallCycleCounter::PmeRedistXF);
     }
 
     if (computeEnergyAndVirial)
@@ -1700,13 +1778,16 @@ void gmx_pme_destroy(gmx_pme_t* pme)
     delete pme;
 }
 
-void gmx_pme_reinit_atoms(gmx_pme_t* pme, const int numAtoms, const real* chargesA, const real* chargesB)
+void gmx_pme_reinit_atoms(gmx_pme_t*                pme,
+                          const int                 numAtoms,
+                          gmx::ArrayRef<const real> chargesA,
+                          gmx::ArrayRef<const real> chargesB)
 {
     if (pme->gpu != nullptr)
     {
-        GMX_ASSERT(!(pme->bFEP_q && chargesB == nullptr),
+        GMX_ASSERT(!(pme->bFEP_q && !chargesB.empty()),
                    "B state charges must be specified if running Coulomb FEP on the GPU");
-        pme_gpu_reinit_atoms(pme->gpu, numAtoms, chargesA, pme->bFEP_q ? chargesB : nullptr);
+        pme_gpu_reinit_atoms(pme->gpu, numAtoms, chargesA.data(), pme->bFEP_q ? chargesB.data() : nullptr);
     }
     else
     {
@@ -1719,3 +1800,23 @@ bool gmx_pme_grid_matches(const gmx_pme_t& pme, const ivec grid_size)
 {
     return (pme.nkx == grid_size[XX] && pme.nky == grid_size[YY] && pme.nkz == grid_size[ZZ]);
 }
+
+void gmx::SeparatePmeRanksPermitted::disablePmeRanks(const std::string& reason)
+{
+    permitSeparatePmeRanks_ = false;
+
+    if (!reason.empty())
+    {
+        reasons_.push_back(reason);
+    }
+}
+
+bool gmx::SeparatePmeRanksPermitted::permitSeparatePmeRanks() const
+{
+    return permitSeparatePmeRanks_;
+}
+
+std::string gmx::SeparatePmeRanksPermitted::reasonsWhyDisabled() const
+{
+    return joinStrings(reasons_, "; ");
+}
index 29411cad0d864694c17c239677887797f93b9f36..1e32caf265bbd2feb25a20c31d93bcd884248d53 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_EWALD_PME_H
 
 #include <string>
+#include <vector>
 
 #include "gromacs/gpu_utils/devicebuffer_datatype.h"
 #include "gromacs/gpu_utils/gpu_macros.h"
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
 struct gmx_hw_info_t;
@@ -83,6 +83,29 @@ class ForceWithVirial;
 class MDLogger;
 enum class PinningPolicy : int;
 class StepWorkload;
+
+/*! \libinternal \brief Class for managing usage of separate PME-only ranks
+ *
+ * Used for checking if some parts of the code could not use PME-only ranks
+ *
+ */
+class SeparatePmeRanksPermitted
+{
+public:
+    //! Disables PME ranks permitted flag with a reason
+    void disablePmeRanks(const std::string& reason);
+    //! Return status of PME ranks usage
+    bool permitSeparatePmeRanks() const;
+    //! Returns all reasons, for not using PME ranks
+    std::string reasonsWhyDisabled() const;
+
+private:
+    //! Flag that informs whether simualtion could use dedicated PME ranks
+    bool permitSeparatePmeRanks_ = true;
+    //! Storage for all reasons, why PME ranks could not be used
+    std::vector<std::string> reasons_;
+};
+
 } // namespace gmx
 
 enum
@@ -181,12 +204,12 @@ void gmx_pme_destroy(gmx_pme_t* pme);
 int gmx_pme_do(struct gmx_pme_t*              pme,
                gmx::ArrayRef<const gmx::RVec> coordinates,
                gmx::ArrayRef<gmx::RVec>       forces,
-               real                           chargeA[],
-               real                           chargeB[],
-               real                           c6A[],
-               real                           c6B[],
-               real                           sigmaA[],
-               real                           sigmaB[],
+               gmx::ArrayRef<const real>      chargeA,
+               gmx::ArrayRef<const real>      chargeB,
+               gmx::ArrayRef<const real>      c6A,
+               gmx::ArrayRef<const real>      c6B,
+               gmx::ArrayRef<const real>      sigmaA,
+               gmx::ArrayRef<const real>      sigmaB,
                const matrix                   box,
                const t_commrec*               cr,
                int                            maxshift_x,
@@ -210,7 +233,7 @@ int gmx_pme_do(struct gmx_pme_t*              pme,
  * pme struct. Currently does not work in parallel or with free
  * energy.
  */
-void gmx_pme_calc_energy(gmx_pme_t* pme, gmx::ArrayRef<const gmx::RVec> x, gmx::ArrayRef<const real> q, real* V);
+real gmx_pme_calc_energy(gmx_pme_t* pme, gmx::ArrayRef<const gmx::RVec> x, gmx::ArrayRef<const real> q);
 
 /*! \brief
  * This function updates the local atom data on GPU after DD (charges, coordinates, etc.).
@@ -224,7 +247,10 @@ void gmx_pme_calc_energy(gmx_pme_t* pme, gmx::ArrayRef<const gmx::RVec> x, gmx::
  * \param[in]     chargesB   The pointer to the array of particle charges in state B. Only used if
  * charges are perturbed and can otherwise be nullptr.
  */
-void gmx_pme_reinit_atoms(gmx_pme_t* pme, int numAtoms, const real* chargesA, const real* chargesB);
+void gmx_pme_reinit_atoms(gmx_pme_t*                pme,
+                          int                       numAtoms,
+                          gmx::ArrayRef<const real> chargesA,
+                          gmx::ArrayRef<const real> chargesB);
 
 /* A block of PME GPU functions */
 
@@ -443,12 +469,12 @@ GPU_FUNC_QUALIFIER void pme_gpu_set_device_x(const gmx_pme_t*        GPU_FUNC_AR
  * \param[in] pme            The PME data structure.
  * \returns                  Pointer to force data
  */
-GPU_FUNC_QUALIFIER void* pme_gpu_get_device_f(const gmx_pme_t* GPU_FUNC_ARGUMENT(pme))
-        GPU_FUNC_TERM_WITH_RETURN(nullptr);
+GPU_FUNC_QUALIFIER DeviceBuffer<gmx::RVec> pme_gpu_get_device_f(const gmx_pme_t* GPU_FUNC_ARGUMENT(pme))
+        GPU_FUNC_TERM_WITH_RETURN(DeviceBuffer<gmx::RVec>{});
 
 /*! \brief Get pointer to the device synchronizer object that allows syncing on PME force calculation completion
  * \param[in] pme            The PME data structure.
- * \returns                  Pointer to sychronizer
+ * \returns                  Pointer to synchronizer
  */
 GPU_FUNC_QUALIFIER GpuEventSynchronizer* pme_gpu_get_f_ready_synchronizer(const gmx_pme_t* GPU_FUNC_ARGUMENT(pme))
         GPU_FUNC_TERM_WITH_RETURN(nullptr);
index 144bd27fddcf042366ffcfd609277ceb948c859a..81f640df409a4110f8c71796e598114e06a2dac4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_PMECOORDINATERECEIVERGPU_H
 #define GMX_PMECOORDINATERECEIVERGPU_H
 
+#include <memory>
+
 #include "gromacs/gpu_utils/devicebuffer_datatype.h"
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/gmxmpi.h"
 
 class DeviceStream;
@@ -76,19 +77,29 @@ public:
 
 
     /*! \brief
-     * launch receive of coordinate data from PP rank
-     * \param[in] ppRank  PP rank to send data
+     * Receive coordinate synchronizer pointer from the PP ranks.
+     * \param[in] ppRank  PP rank to receive the synchronizer from.
+     */
+    void receiveCoordinatesSynchronizerFromPpCudaDirect(int ppRank);
+
+    /*! \brief
+     * Used for lib MPI, receives co-ordinates from PP ranks
+     * \param[in] recvbuf   coordinates buffer in GPU memory
+     * \param[in] numAtoms  starting element in buffer
+     * \param[in] numBytes  number of bytes to transfer
+     * \param[in] ppRank    PP rank to send data
      */
-    void launchReceiveCoordinatesFromPpCudaDirect(int ppRank);
+    void launchReceiveCoordinatesFromPpCudaMpi(DeviceBuffer<RVec> recvbuf, int numAtoms, int numBytes, int ppRank);
 
     /*! \brief
-     * enqueue wait for coordinate data from PP ranks
+     * For lib MPI, wait for coordinates from PP ranks
+     * For thread MPI, enqueue PP co-ordinate transfer event into PME stream
      */
-    void enqueueWaitReceiveCoordinatesFromPpCudaDirect();
+    void synchronizeOnCoordinatesFromPpRanks();
 
 private:
     class Impl;
-    gmx::PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index be4cf2a16acb58f9945a184020b31572e6201e92..4e997d319bd42cd32e9d32879178a99f3ca4a5fb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -82,14 +82,24 @@ void PmeCoordinateReceiverGpu::sendCoordinateBufferAddressToPpRanks(DeviceBuffer
                "correct implementation.");
 }
 
-void PmeCoordinateReceiverGpu::launchReceiveCoordinatesFromPpCudaDirect(int /* ppRank */)
+void PmeCoordinateReceiverGpu::receiveCoordinatesSynchronizerFromPpCudaDirect(int /* ppRank */)
 {
     GMX_ASSERT(!impl_,
                "A CPU stub for PME-PP GPU communication was called instead of the correct "
                "implementation.");
 }
 
-void PmeCoordinateReceiverGpu::enqueueWaitReceiveCoordinatesFromPpCudaDirect()
+void PmeCoordinateReceiverGpu::launchReceiveCoordinatesFromPpCudaMpi(DeviceBuffer<RVec> /* recvbuf */,
+                                                                     int /* numAtoms */,
+                                                                     int /* numBytes */,
+                                                                     int /* ppRank */)
+{
+    GMX_ASSERT(!impl_,
+               "A CPU stub for PME-PP GPU communication was called instead of the correct "
+               "implementation.");
+}
+
+void PmeCoordinateReceiverGpu::synchronizeOnCoordinatesFromPpRanks()
 {
     GMX_ASSERT(!impl_,
                "A CPU stub for PME-PP GPU communication was called instead of the correct "
index db81fb7b0aad4d80f401cf4a2a4c2ce4cf5124d7..7fa2122dfb8a1cc5a65f03084e9356de114fc7a9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
  */
 #include "gmxpre.h"
 
+#include "gromacs/ewald/pme_pp_communication.h"
 #include "pme_coordinate_receiver_gpu_impl.h"
 
 #include "config.h"
@@ -62,9 +63,6 @@ PmeCoordinateReceiverGpu::Impl::Impl(const DeviceStream&    pmeStream,
     comm_(comm),
     ppRanks_(ppRanks)
 {
-    GMX_RELEASE_ASSERT(
-            GMX_THREAD_MPI,
-            "PME-PP GPU Communication is currently only supported with thread-MPI enabled");
     request_.resize(ppRanks.size());
     ppSync_.resize(ppRanks.size());
 }
@@ -73,52 +71,83 @@ PmeCoordinateReceiverGpu::Impl::~Impl() = default;
 
 void PmeCoordinateReceiverGpu::Impl::sendCoordinateBufferAddressToPpRanks(DeviceBuffer<RVec> d_x)
 {
-
-    int ind_start = 0;
-    int ind_end   = 0;
-    for (const auto& receiver : ppRanks_)
+    // Need to send address to PP rank only for thread-MPI as PP rank pushes data using cudamemcpy
+    if (GMX_THREAD_MPI)
     {
-        ind_start = ind_end;
-        ind_end   = ind_start + receiver.numAtoms;
-
-        // Data will be transferred directly from GPU.
-        void* sendBuf = reinterpret_cast<void*>(&d_x[ind_start]);
+        int ind_start = 0;
+        int ind_end   = 0;
+        for (const auto& receiver : ppRanks_)
+        {
+            ind_start = ind_end;
+            ind_end   = ind_start + receiver.numAtoms;
 
+            // Data will be transferred directly from GPU.
+            void* sendBuf = reinterpret_cast<void*>(&d_x[ind_start]);
 #if GMX_MPI
-        MPI_Send(&sendBuf, sizeof(void**), MPI_BYTE, receiver.rankId, 0, comm_);
+            MPI_Send(&sendBuf, sizeof(void**), MPI_BYTE, receiver.rankId, 0, comm_);
 #else
-        GMX_UNUSED_VALUE(sendBuf);
+            GMX_UNUSED_VALUE(sendBuf);
 #endif
+        }
     }
 }
 
-/*! \brief Receive coordinate data directly using CUDA memory copy */
-void PmeCoordinateReceiverGpu::Impl::launchReceiveCoordinatesFromPpCudaDirect(int ppRank)
+/*! \brief Receive coordinate synchronizer pointer from the PP ranks. */
+void PmeCoordinateReceiverGpu::Impl::receiveCoordinatesSynchronizerFromPpCudaDirect(int ppRank)
 {
+    GMX_ASSERT(GMX_THREAD_MPI,
+               "receiveCoordinatesSynchronizerFromPpCudaDirect is expected to be called only for "
+               "Thread-MPI");
+
     // Data will be pushed directly from PP task
 
 #if GMX_MPI
     // Receive event from PP task
-    MPI_Irecv(&ppSync_[recvCount_], sizeof(GpuEventSynchronizer*), MPI_BYTE, ppRank, 0, comm_,
-              &request_[recvCount_]);
+    MPI_Irecv(&ppSync_[recvCount_], sizeof(GpuEventSynchronizer*), MPI_BYTE, ppRank, 0, comm_, &request_[recvCount_]);
     recvCount_++;
 #else
     GMX_UNUSED_VALUE(ppRank);
 #endif
 }
 
-void PmeCoordinateReceiverGpu::Impl::enqueueWaitReceiveCoordinatesFromPpCudaDirect()
+/*! \brief Receive coordinate data using CUDA-aware MPI */
+void PmeCoordinateReceiverGpu::Impl::launchReceiveCoordinatesFromPpCudaMpi(DeviceBuffer<RVec> recvbuf,
+                                                                           int numAtoms,
+                                                                           int numBytes,
+                                                                           int ppRank)
+{
+    GMX_ASSERT(GMX_LIB_MPI,
+               "launchReceiveCoordinatesFromPpCudaMpi is expected to be called only for Lib-MPI");
+
+#if GMX_MPI
+    MPI_Irecv(&recvbuf[numAtoms], numBytes, MPI_BYTE, ppRank, eCommType_COORD_GPU, comm_, &request_[recvCount_++]);
+#else
+    GMX_UNUSED_VALUE(recvbuf);
+    GMX_UNUSED_VALUE(numAtoms);
+    GMX_UNUSED_VALUE(numBytes);
+    GMX_UNUSED_VALUE(ppRank);
+#endif
+}
+
+void PmeCoordinateReceiverGpu::Impl::synchronizeOnCoordinatesFromPpRanks()
 {
     if (recvCount_ > 0)
     {
-        // ensure PME calculation doesn't commence until coordinate data has been transferred
+        // ensure PME calculation doesn't commence until coordinate data/remote events
+        // has been transferred
 #if GMX_MPI
         MPI_Waitall(recvCount_, request_.data(), MPI_STATUS_IGNORE);
 #endif
-        for (int i = 0; i < recvCount_; i++)
+
+        // Make PME stream wait on PP to PME data trasnfer events
+        if (GMX_THREAD_MPI)
         {
-            ppSync_[i]->enqueueWaitEvent(pmeStream_);
+            for (int i = 0; i < recvCount_; i++)
+            {
+                ppSync_[i]->enqueueWaitEvent(pmeStream_);
+            }
         }
+
         // reset receive counter
         recvCount_ = 0;
     }
@@ -138,14 +167,22 @@ void PmeCoordinateReceiverGpu::sendCoordinateBufferAddressToPpRanks(DeviceBuffer
     impl_->sendCoordinateBufferAddressToPpRanks(d_x);
 }
 
-void PmeCoordinateReceiverGpu::launchReceiveCoordinatesFromPpCudaDirect(int ppRank)
+void PmeCoordinateReceiverGpu::receiveCoordinatesSynchronizerFromPpCudaDirect(int ppRank)
+{
+    impl_->receiveCoordinatesSynchronizerFromPpCudaDirect(ppRank);
+}
+
+void PmeCoordinateReceiverGpu::launchReceiveCoordinatesFromPpCudaMpi(DeviceBuffer<RVec> recvbuf,
+                                                                     int                numAtoms,
+                                                                     int                numBytes,
+                                                                     int                ppRank)
 {
-    impl_->launchReceiveCoordinatesFromPpCudaDirect(ppRank);
+    impl_->launchReceiveCoordinatesFromPpCudaMpi(recvbuf, numAtoms, numBytes, ppRank);
 }
 
-void PmeCoordinateReceiverGpu::enqueueWaitReceiveCoordinatesFromPpCudaDirect()
+void PmeCoordinateReceiverGpu::synchronizeOnCoordinatesFromPpRanks()
 {
-    impl_->enqueueWaitReceiveCoordinatesFromPpCudaDirect();
+    impl_->synchronizeOnCoordinatesFromPpRanks();
 }
 
 } // namespace gmx
index 9094a7c7b3483cdc64744ce13f2e150506b7f073..604079c0b0fbcead4bebf03ae2a99eea132c5962 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -73,15 +73,25 @@ public:
     void sendCoordinateBufferAddressToPpRanks(DeviceBuffer<RVec> d_x);
 
     /*! \brief
-     * launch receive of coordinate data from PP rank
-     * \param[in] ppRank  PP rank to send data
+     * Receive coordinate synchronizer pointer from the PP ranks.
+     * \param[in] ppRank  PP rank to receive the synchronizer from.
      */
-    void launchReceiveCoordinatesFromPpCudaDirect(int ppRank);
+    void receiveCoordinatesSynchronizerFromPpCudaDirect(int ppRank);
 
     /*! \brief
-     * enqueue wait for coordinate data from PP ranks
+     * Used for lib MPI, receives co-ordinates from PP ranks
+     * \param[in] recvbuf   coordinates buffer in GPU memory
+     * \param[in] numAtoms  starting element in buffer
+     * \param[in] numBytes  number of bytes to transfer
+     * \param[in] ppRank    PP rank to send data
      */
-    void enqueueWaitReceiveCoordinatesFromPpCudaDirect();
+    void launchReceiveCoordinatesFromPpCudaMpi(DeviceBuffer<RVec> recvbuf, int numAtoms, int numBytes, int ppRank);
+
+    /*! \brief
+     * For lib MPI, wait for coordinates from PP ranks
+     * For thread MPI, enqueue PP co-ordinate transfer event into PME stream
+     */
+    void synchronizeOnCoordinatesFromPpRanks();
 
 private:
     //! CUDA stream for PME operations
index df8e1873f8ecb4e9b36df823778be1fea4c404e3..e06f582ae8c948ab8f22bccae677ddbf5f40d923 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_PMEFORCESENDERGPU_H
 #define GMX_PMEFORCESENDERGPU_H
 
+#include <memory>
+
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/classhelpers.h"
+#include "gromacs/gpu_utils/devicebuffer_datatype.h"
 #include "gromacs/utility/gmxmpi.h"
 
-class DeviceStream;
+class GpuEventSynchronizer;
 
 /*! \libinternal
  * \brief Contains information about the PP ranks that partner this PME rank. */
@@ -71,28 +73,38 @@ class PmeForceSenderGpu
 
 public:
     /*! \brief Creates PME GPU Force sender object
-     * \param[in] pmeStream       CUDA stream used for PME computations
+     * \param[in] pmeForcesReady  Event synchronizer marked when PME forces are ready on the GPU
      * \param[in] comm            Communicator used for simulation
      * \param[in] ppRanks         List of PP ranks
      */
-    PmeForceSenderGpu(const DeviceStream& pmeStream, MPI_Comm comm, gmx::ArrayRef<PpRanks> ppRanks);
+    PmeForceSenderGpu(GpuEventSynchronizer* pmeForcesReady, MPI_Comm comm, gmx::ArrayRef<PpRanks> ppRanks);
     ~PmeForceSenderGpu();
 
     /*! \brief
      * Initialization of GPU PME Force sender
      * \param[in] d_f   force buffer in GPU memory
      */
-    void sendForceBufferAddressToPpRanks(rvec* d_f);
+    void sendForceBufferAddressToPpRanks(DeviceBuffer<RVec> d_f);
 
     /*! \brief
-     * Send PP data to PP rank
+     * Send force synchronizer to PP rank (used with Thread-MPI)
      * \param[in] ppRank           PP rank to receive data
      */
-    void sendFToPpCudaDirect(int ppRank);
+    void sendFSynchronizerToPpCudaDirect(int ppRank);
+
+    /*! \brief
+     * Send force to PP rank (used with Lib-MPI)
+     * \param[in] sendbuf  force buffer in GPU memory
+     * \param[in] offset   starting element in buffer
+     * \param[in] numBytes number of bytes to transfer
+     * \param[in] ppRank   PP rank to receive data
+     * \param[in] request  MPI request to track asynchronous MPI call status
+     */
+    void sendFToPpCudaMpi(DeviceBuffer<RVec> sendbuf, int offset, int numBytes, int ppRank, MPI_Request* request);
 
 private:
     class Impl;
-    gmx::PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index a30384a8c28135949ca4238a73ad101a5c2eb6aa..f7cd9c5cc47c1e6e1e9f964d34e07723b1f2bab3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
 #include "config.h"
 
 #include "gromacs/ewald/pme_force_sender_gpu.h"
+#include "gromacs/gpu_utils/devicebuffer_datatype.h"
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/gmxassert.h"
 
@@ -62,7 +63,7 @@ class PmeForceSenderGpu::Impl
 };
 
 /*!\brief Constructor stub. */
-PmeForceSenderGpu::PmeForceSenderGpu(const DeviceStream& /*pmeStream */,
+PmeForceSenderGpu::PmeForceSenderGpu(GpuEventSynchronizer* /*pmeForcesReady */,
                                      MPI_Comm /* comm     */,
                                      gmx::ArrayRef<PpRanks> /* ppRanks */) :
     impl_(nullptr)
@@ -75,14 +76,25 @@ PmeForceSenderGpu::PmeForceSenderGpu(const DeviceStream& /*pmeStream */,
 PmeForceSenderGpu::~PmeForceSenderGpu() = default;
 
 /*!\brief init PME-PP GPU communication stub */
-void PmeForceSenderGpu::sendForceBufferAddressToPpRanks(rvec* /* d_f */)
+void PmeForceSenderGpu::sendForceBufferAddressToPpRanks(DeviceBuffer<RVec> /* d_f */)
 {
     GMX_ASSERT(!impl_,
                "A CPU stub for PME-PP GPU communication initialization was called instead of the "
                "correct implementation.");
 }
 
-void PmeForceSenderGpu::sendFToPpCudaDirect(int /* ppRank */)
+void PmeForceSenderGpu::sendFSynchronizerToPpCudaDirect(int /* ppRank */)
+{
+    GMX_ASSERT(!impl_,
+               "A CPU stub for PME-PP GPU communication was called instead of the correct "
+               "implementation.");
+}
+
+void PmeForceSenderGpu::sendFToPpCudaMpi(DeviceBuffer<RVec> /* sendbuf */,
+                                         int /* offset */,
+                                         int /* numBytes */,
+                                         int /* ppRank */,
+                                         MPI_Request* /* request */)
 {
     GMX_ASSERT(!impl_,
                "A CPU stub for PME-PP GPU communication was called instead of the correct "
index 6e6d21eaf2ee7b98f338e51b6877de2bbb4cebfc..b124c03136e19cf66ab0f2ca729566ead93546a6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,21 +55,27 @@ namespace gmx
 {
 
 /*! \brief Create PME-PP GPU communication object */
-PmeForceSenderGpu::Impl::Impl(const DeviceStream& pmeStream, MPI_Comm comm, gmx::ArrayRef<PpRanks> ppRanks) :
-    pmeStream_(pmeStream),
+PmeForceSenderGpu::Impl::Impl(GpuEventSynchronizer*  pmeForcesReady,
+                              MPI_Comm               comm,
+                              gmx::ArrayRef<PpRanks> ppRanks) :
+    pmeForcesReady_(pmeForcesReady),
     comm_(comm),
     ppRanks_(ppRanks)
 {
-    GMX_RELEASE_ASSERT(
-            GMX_THREAD_MPI,
-            "PME-PP GPU Communication is currently only supported with thread-MPI enabled");
 }
 
 PmeForceSenderGpu::Impl::~Impl() = default;
 
 /*! \brief  sends force buffer address to PP ranks */
-void PmeForceSenderGpu::Impl::sendForceBufferAddressToPpRanks(rvec* d_f)
+void PmeForceSenderGpu::Impl::sendForceBufferAddressToPpRanks(DeviceBuffer<Float3> d_f)
 {
+    // Need to send address to PP rank only for thread-MPI as PP rank pulls
+    // data using cudamemcpy
+    if (!GMX_THREAD_MPI)
+    {
+        return;
+    }
+#if GMX_MPI
     int ind_start = 0;
     int ind_end   = 0;
     for (const auto& receiver : ppRanks_)
@@ -78,51 +84,82 @@ void PmeForceSenderGpu::Impl::sendForceBufferAddressToPpRanks(rvec* d_f)
         ind_end   = ind_start + receiver.numAtoms;
 
         // Data will be transferred directly from GPU.
-        void* sendBuf = reinterpret_cast<void*>(&d_f[ind_start]);
+        Float3* sendBuf = &d_f[ind_start];
 
-#if GMX_MPI
-        MPI_Send(&sendBuf, sizeof(void**), MPI_BYTE, receiver.rankId, 0, comm_);
+        MPI_Send(&sendBuf, sizeof(Float3*), MPI_BYTE, receiver.rankId, 0, comm_);
+    }
 #else
-        GMX_UNUSED_VALUE(sendBuf);
+    GMX_UNUSED_VALUE(d_f);
 #endif
-    }
 }
 
-/*! \brief Send PME data directly using CUDA memory copy */
-void PmeForceSenderGpu::Impl::sendFToPpCudaDirect(int ppRank)
+/*! \brief Send PME synchronizer directly using CUDA memory copy */
+void PmeForceSenderGpu::Impl::sendFSynchronizerToPpCudaDirect(int ppRank)
 {
-    // Data will be pulled directly from PP task
+    GMX_ASSERT(GMX_THREAD_MPI,
+               "sendFSynchronizerToPpCudaDirect is expected to be called only for Thread-MPI");
 
-    // Record and send event to ensure PME force calcs are completed before PP task pulls data
-    pmeSync_.markEvent(pmeStream_);
-    GpuEventSynchronizer* pmeSyncPtr = &pmeSync_;
+    // Data will be pulled directly from PP task
 #if GMX_MPI
     // TODO Using MPI_Isend would be more efficient, particularly when
     // sending to multiple PP ranks
-    MPI_Send(&pmeSyncPtr, sizeof(GpuEventSynchronizer*), MPI_BYTE, ppRank, 0, comm_);
+    MPI_Send(&pmeForcesReady_, sizeof(GpuEventSynchronizer*), MPI_BYTE, ppRank, 0, comm_);
 #else
-    GMX_UNUSED_VALUE(pmeSyncPtr);
     GMX_UNUSED_VALUE(ppRank);
 #endif
 }
 
-PmeForceSenderGpu::PmeForceSenderGpu(const DeviceStream&    pmeStream,
+/*! \brief Send PME data directly using CUDA-aware MPI */
+void PmeForceSenderGpu::Impl::sendFToPpCudaMpi(DeviceBuffer<RVec> sendbuf,
+                                               int                offset,
+                                               int                numBytes,
+                                               int                ppRank,
+                                               MPI_Request*       request)
+{
+    GMX_ASSERT(GMX_LIB_MPI, "sendFToPpCudaMpi is expected to be called only for Lib-MPI");
+
+#if GMX_MPI
+    // if using GPU direct comm with CUDA-aware MPI, make sure forces are ready on device
+    // before sending it to PP ranks
+    pmeForcesReady_->waitForEvent();
+
+    MPI_Isend(sendbuf[offset], numBytes, MPI_BYTE, ppRank, 0, comm_, request);
+
+#else
+    GMX_UNUSED_VALUE(sendbuf);
+    GMX_UNUSED_VALUE(offset);
+    GMX_UNUSED_VALUE(numBytes);
+    GMX_UNUSED_VALUE(ppRank);
+    GMX_UNUSED_VALUE(request);
+#endif
+}
+
+PmeForceSenderGpu::PmeForceSenderGpu(GpuEventSynchronizer*  pmeForcesReady,
                                      MPI_Comm               comm,
                                      gmx::ArrayRef<PpRanks> ppRanks) :
-    impl_(new Impl(pmeStream, comm, ppRanks))
+    impl_(new Impl(pmeForcesReady, comm, ppRanks))
 {
 }
 
 PmeForceSenderGpu::~PmeForceSenderGpu() = default;
 
-void PmeForceSenderGpu::sendForceBufferAddressToPpRanks(rvec* d_f)
+void PmeForceSenderGpu::sendForceBufferAddressToPpRanks(DeviceBuffer<RVec> d_f)
 {
     impl_->sendForceBufferAddressToPpRanks(d_f);
 }
 
-void PmeForceSenderGpu::sendFToPpCudaDirect(int ppRank)
+void PmeForceSenderGpu::sendFSynchronizerToPpCudaDirect(int ppRank)
+{
+    impl_->sendFSynchronizerToPpCudaDirect(ppRank);
+}
+
+void PmeForceSenderGpu::sendFToPpCudaMpi(DeviceBuffer<RVec> sendbuf,
+                                         int                offset,
+                                         int                numBytes,
+                                         int                ppRank,
+                                         MPI_Request*       request)
 {
-    impl_->sendFToPpCudaDirect(ppRank);
+    impl_->sendFToPpCudaMpi(sendbuf, offset, numBytes, ppRank, request);
 }
 
 
index 91fe1c1140d271651bd9f9bf40c248e9f7385b70..0e0ad8122cbdccf5ce6bcd3bbd1d73570f1ae700 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_PMEFORCESENDERGPU_IMPL_H
 
 #include "gromacs/ewald/pme_force_sender_gpu.h"
-#include "gromacs/gpu_utils/gpueventsynchronizer.cuh"
+#include "gromacs/gpu_utils/devicebuffer_datatype.h"
+#include "gromacs/gpu_utils/gputraits.h"
 #include "gromacs/utility/arrayref.h"
 
+class GpuEventSynchronizer;
+
 namespace gmx
 {
 
@@ -57,30 +60,38 @@ class PmeForceSenderGpu::Impl
 
 public:
     /*! \brief Creates PME GPU Force sender object
-     * \param[in] pmeStream       CUDA stream used for PME computations
+     * \param[in] pmeForcesReady  Event synchronizer marked when PME forces are ready on the GPU
      * \param[in] comm            Communicator used for simulation
      * \param[in] ppRanks         List of PP ranks
      */
-    Impl(const DeviceStream& pmeStream, MPI_Comm comm, gmx::ArrayRef<PpRanks> ppRanks);
+    Impl(GpuEventSynchronizer* pmeForcesReady, MPI_Comm comm, gmx::ArrayRef<PpRanks> ppRanks);
     ~Impl();
 
     /*! \brief
      * sends force buffer address to PP rank
      * \param[in] d_f   force buffer in GPU memory
      */
-    void sendForceBufferAddressToPpRanks(rvec* d_f);
+    void sendForceBufferAddressToPpRanks(DeviceBuffer<Float3> d_f);
 
     /*! \brief
-     * Send PP data to PP rank
+     * Send force synchronizer to PP rank (used with Thread-MPI)
      * \param[in] ppRank           PP rank to receive data
      */
-    void sendFToPpCudaDirect(int ppRank);
+    void sendFSynchronizerToPpCudaDirect(int ppRank);
+
+    /*! \brief
+     * Send force to PP rank (used with Lib-MPI)
+     * \param[in] sendbuf  force buffer in GPU memory
+     * \param[in] offset   starting element in buffer
+     * \param[in] numBytes number of bytes to transfer
+     * \param[in] ppRank   PP rank to receive data
+     * \param[in] request  MPI request to track asynchronous MPI call status
+     */
+    void sendFToPpCudaMpi(DeviceBuffer<RVec> sendbuf, int offset, int numBytes, int ppRank, MPI_Request* request);
 
 private:
-    //! CUDA stream for PME operations
-    const DeviceStream& pmeStream_;
-    //! Event triggered when to allow remote PP stream to syn with pme stream
-    GpuEventSynchronizer pmeSync_;
+    //! Event indicating when PME forces are ready on the GPU in order for PP stream to sync with the PME stream
+    GpuEventSynchronizer* pmeForcesReady_;
     //! communicator for simulation
     MPI_Comm comm_;
     //! list of PP ranks
index 98cac0f2824c4ba445485ba3f167e2f93544dea4..361461b4176bbda2bfd42187285ab4de3ef37aab 100644 (file)
@@ -390,8 +390,8 @@ __kernel void CUSTOMIZED_KERNEL_NAME(pme_gather_kernel)(const struct PmeOpenCLKe
 
     if (chargeCheck)
     {
-        sumForceComponents(&fx, &fy, &fz, ixBase, nx, pny, pnz, constOffset, splineIndexBase, tdy,
-                           tdz, sm_splineParams, gm_gridA);
+        sumForceComponents(
+                &fx, &fy, &fz, ixBase, nx, pny, pnz, constOffset, splineIndexBase, tdy, tdz, sm_splineParams, gm_gridA);
     }
 
     // Reduction of partial force contributions
@@ -400,8 +400,16 @@ __kernel void CUSTOMIZED_KERNEL_NAME(pme_gather_kernel)(const struct PmeOpenCLKe
     __local float  sm_forceReduction[totalSharedMemory];
     __local float* sm_forceTemp[DIM];
 
-    reduce_atom_forces(sm_forces, atomIndexLocal, splineIndex, lineIndex,
-                       kernelParams.grid.realGridSizeFP, fx, fy, fz, sm_forceReduction, sm_forceTemp);
+    reduce_atom_forces(sm_forces,
+                       atomIndexLocal,
+                       splineIndex,
+                       lineIndex,
+                       kernelParams.grid.realGridSizeFP,
+                       fx,
+                       fy,
+                       fz,
+                       sm_forceReduction,
+                       sm_forceTemp);
     barrier(CLK_LOCAL_MEM_FENCE);
 
     /* Calculating the final forces with no component branching, atomsPerBlock threads */
@@ -410,8 +418,8 @@ __kernel void CUSTOMIZED_KERNEL_NAME(pme_gather_kernel)(const struct PmeOpenCLKe
     const float scale            = kernelParams.current.scale;
     if (forceIndexLocal < atomsPerBlock)
     {
-        calculateAndStoreGridForces(sm_forces, forceIndexLocal, forceIndexGlobal,
-                                    kernelParams.current.recipBox, scale, gm_coefficientsA);
+        calculateAndStoreGridForces(
+                sm_forces, forceIndexLocal, forceIndexGlobal, kernelParams.current.recipBox, scale, gm_coefficientsA);
     }
 
 #if !defined(_AMD_SOURCE_) && !defined(_NVIDIA_SOURCE_)
@@ -448,16 +456,28 @@ __kernel void CUSTOMIZED_KERNEL_NAME(pme_gather_kernel)(const struct PmeOpenCLKe
         chargeCheck = pme_gpu_check_atom_charge(gm_coefficientsB[atomIndexGlobal]);
         if (chargeCheck)
         {
-            sumForceComponents(&fx, &fy, &fz, ixBase, nx, pny, pnz, constOffset, splineIndexBase,
-                               tdy, tdz, sm_splineParams, gm_gridB);
+            sumForceComponents(
+                    &fx, &fy, &fz, ixBase, nx, pny, pnz, constOffset, splineIndexBase, tdy, tdz, sm_splineParams, gm_gridB);
         }
-        reduce_atom_forces(sm_forces, atomIndexLocal, splineIndex, lineIndex,
-                           kernelParams.grid.realGridSizeFP, fx, fy, fz, sm_forceReduction, sm_forceTemp);
+        reduce_atom_forces(sm_forces,
+                           atomIndexLocal,
+                           splineIndex,
+                           lineIndex,
+                           kernelParams.grid.realGridSizeFP,
+                           fx,
+                           fy,
+                           fz,
+                           sm_forceReduction,
+                           sm_forceTemp);
         barrier(CLK_LOCAL_MEM_FENCE);
         if (forceIndexLocal < atomsPerBlock)
         {
-            calculateAndStoreGridForces(sm_forces, forceIndexLocal, forceIndexGlobal,
-                                        kernelParams.current.recipBox, 1.0F - scale, gm_coefficientsB);
+            calculateAndStoreGridForces(sm_forces,
+                                        forceIndexLocal,
+                                        forceIndexGlobal,
+                                        kernelParams.current.recipBox,
+                                        1.0F - scale,
+                                        gm_coefficientsB);
         }
 
 #if !defined(_AMD_SOURCE_) && !defined(_NVIDIA_SOURCE_)
index 160f544d3ecb3ace27be9eba5a7265f5a5845697..095c47acf89e6ec9c73a9cd26ca9ad9a81aae5c7 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020 by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -92,7 +93,7 @@ __device__ __forceinline__ void reduce_atom_forces(float3* __restrict__ sm_force
                                                    float&       fy,
                                                    float&       fz)
 {
-    if (!(order & (order - 1))) // Only for orders of power of 2
+    if (gmx::isPowerOfTwo(order)) // Only for orders of power of 2
     {
         const unsigned int activeMask = c_fullWarpMask;
 
@@ -350,7 +351,8 @@ __launch_bounds__(c_gatherMaxThreadsPerBlock, c_gatherMinBlocksPerMP) __global__
     const float* __restrict__ gm_coefficientsB = kernelParams.atoms.d_coefficients[1];
     const float* __restrict__ gm_gridA         = kernelParams.grid.d_realGrid[0];
     const float* __restrict__ gm_gridB         = kernelParams.grid.d_realGrid[1];
-    float* __restrict__ gm_forces              = kernelParams.atoms.d_forces;
+    static_assert(sizeof(*kernelParams.atoms.d_forces) == 3 * sizeof(float));
+    float* __restrict__ gm_forces = reinterpret_cast<float*>(kernelParams.atoms.d_forces);
 
     /* Global memory pointers for readGlobal */
     const float* __restrict__ gm_theta         = kernelParams.atoms.d_theta;
@@ -494,14 +496,29 @@ __launch_bounds__(c_gatherMaxThreadsPerBlock, c_gatherMinBlocksPerMP) __global__
     const int ithyMax = (threadsPerAtom == ThreadsPerAtom::Order) ? order : threadIdx.y + 1;
     if (chargeCheck)
     {
-        sumForceComponents<order, atomsPerWarp, wrapX, wrapY>(
-                &fx, &fy, &fz, ithyMin, ithyMax, ixBase, iz, nx, ny, pny, pnz, atomIndexLocal,
-                splineIndexBase, tdz, sm_gridlineIndices, sm_theta, sm_dtheta, gm_gridA);
+        sumForceComponents<order, atomsPerWarp, wrapX, wrapY>(&fx,
+                                                              &fy,
+                                                              &fz,
+                                                              ithyMin,
+                                                              ithyMax,
+                                                              ixBase,
+                                                              iz,
+                                                              nx,
+                                                              ny,
+                                                              pny,
+                                                              pnz,
+                                                              atomIndexLocal,
+                                                              splineIndexBase,
+                                                              tdz,
+                                                              sm_gridlineIndices,
+                                                              sm_theta,
+                                                              sm_dtheta,
+                                                              gm_gridA);
     }
     // Reduction of partial force contributions
     __shared__ float3 sm_forces[atomsPerBlock];
-    reduce_atom_forces<order, atomDataSize, blockSize>(sm_forces, atomIndexLocal, splineIndex, lineIndex,
-                                                       kernelParams.grid.realGridSizeFP, fx, fy, fz);
+    reduce_atom_forces<order, atomDataSize, blockSize>(
+            sm_forces, atomIndexLocal, splineIndex, lineIndex, kernelParams.grid.realGridSizeFP, fx, fy, fz);
     __syncthreads();
 
     /* Calculating the final forces with no component branching, atomsPerBlock threads */
@@ -510,8 +527,8 @@ __launch_bounds__(c_gatherMaxThreadsPerBlock, c_gatherMinBlocksPerMP) __global__
     const float scale            = kernelParams.current.scale;
     if (forceIndexLocal < atomsPerBlock)
     {
-        calculateAndStoreGridForces(sm_forces, forceIndexLocal, forceIndexGlobal,
-                                    kernelParams.current.recipBox, scale, gm_coefficientsA);
+        calculateAndStoreGridForces(
+                sm_forces, forceIndexLocal, forceIndexGlobal, kernelParams.current.recipBox, scale, gm_coefficientsA);
     }
 
     __syncwarp();
@@ -543,21 +560,39 @@ __launch_bounds__(c_gatherMaxThreadsPerBlock, c_gatherMinBlocksPerMP) __global__
         const int chargeCheck = pme_gpu_check_atom_charge(gm_coefficientsB[atomIndexGlobal]);
         if (chargeCheck)
         {
-            sumForceComponents<order, atomsPerWarp, wrapX, wrapY>(
-                    &fx, &fy, &fz, ithyMin, ithyMax, ixBase, iz, nx, ny, pny, pnz, atomIndexLocal,
-                    splineIndexBase, tdz, sm_gridlineIndices, sm_theta, sm_dtheta, gm_gridB);
+            sumForceComponents<order, atomsPerWarp, wrapX, wrapY>(&fx,
+                                                                  &fy,
+                                                                  &fz,
+                                                                  ithyMin,
+                                                                  ithyMax,
+                                                                  ixBase,
+                                                                  iz,
+                                                                  nx,
+                                                                  ny,
+                                                                  pny,
+                                                                  pnz,
+                                                                  atomIndexLocal,
+                                                                  splineIndexBase,
+                                                                  tdz,
+                                                                  sm_gridlineIndices,
+                                                                  sm_theta,
+                                                                  sm_dtheta,
+                                                                  gm_gridB);
         }
         // Reduction of partial force contributions
-        reduce_atom_forces<order, atomDataSize, blockSize>(sm_forces, atomIndexLocal, splineIndex,
-                                                           lineIndex, kernelParams.grid.realGridSizeFP,
-                                                           fx, fy, fz);
+        reduce_atom_forces<order, atomDataSize, blockSize>(
+                sm_forces, atomIndexLocal, splineIndex, lineIndex, kernelParams.grid.realGridSizeFP, fx, fy, fz);
         __syncthreads();
 
         /* Calculating the final forces with no component branching, atomsPerBlock threads */
         if (forceIndexLocal < atomsPerBlock)
         {
-            calculateAndStoreGridForces(sm_forces, forceIndexLocal, forceIndexGlobal,
-                                        kernelParams.current.recipBox, 1.0F - scale, gm_coefficientsB);
+            calculateAndStoreGridForces(sm_forces,
+                                        forceIndexLocal,
+                                        forceIndexGlobal,
+                                        kernelParams.current.recipBox,
+                                        1.0F - scale,
+                                        gm_coefficientsB);
         }
 
         __syncwarp();
index fcae02ab6917b1d93fb6e5ea53f354dc2b0d77be..084bb3f6cc53f81355e63e7e225006b25304601c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,25 +123,25 @@ int pme_gpu_get_block_size(const gmx_pme_t* pme)
 void inline parallel_3dfft_execute_gpu_wrapper(gmx_pme_t*             pme,
                                                const int              gridIndex,
                                                enum gmx_fft_direction dir,
-                                               gmx_wallcycle_t        wcycle)
+                                               gmx_wallcycle        wcycle)
 {
     if (pme_gpu_settings(pme->gpu).performGPUFFT)
     {
-        wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU);
-        wallcycle_sub_start_nocount(wcycle, ewcsLAUNCH_GPU_PME);
+        wallcycle_start_nocount(wcycle, WallCycleCounter::LaunchGpu);
+        wallcycle_sub_start_nocount(wcycle, WallCycleSubCounter::LaunchGpuPme);
         pme_gpu_3dfft(pme->gpu, dir, gridIndex);
-        wallcycle_sub_stop(wcycle, ewcsLAUNCH_GPU_PME);
-        wallcycle_stop(wcycle, ewcLAUNCH_GPU);
+        wallcycle_sub_stop(wcycle, WallCycleSubCounter::LaunchGpuPme);
+        wallcycle_stop(wcycle, WallCycleCounter::LaunchGpu);
     }
     else
     {
-        wallcycle_start(wcycle, ewcPME_FFT_MIXED_MODE);
+        wallcycle_start(wcycle, WallCycleCounter::PmeFftMixedMode);
 #pragma omp parallel for num_threads(pme->nthread) schedule(static)
         for (int thread = 0; thread < pme->nthread; thread++)
         {
             gmx_parallel_3dfft_execute(pme->pfft_setup[gridIndex], dir, thread, wcycle);
         }
-        wallcycle_stop(wcycle, ewcPME_FFT_MIXED_MODE);
+        wallcycle_stop(wcycle, WallCycleCounter::PmeFftMixedMode);
     }
 }
 
@@ -172,11 +172,11 @@ void pme_gpu_prepare_computation(gmx_pme_t*               pme,
 
     if (stepWork.haveDynamicBox || shouldUpdateBox) // || is to make the first computation always update
     {
-        wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU);
-        wallcycle_sub_start_nocount(wcycle, ewcsLAUNCH_GPU_PME);
+        wallcycle_start_nocount(wcycle, WallCycleCounter::LaunchGpu);
+        wallcycle_sub_start_nocount(wcycle, WallCycleSubCounter::LaunchGpuPme);
         pme_gpu_update_input_box(pmeGpu, box);
-        wallcycle_sub_stop(wcycle, ewcsLAUNCH_GPU_PME);
-        wallcycle_stop(wcycle, ewcLAUNCH_GPU);
+        wallcycle_sub_stop(wcycle, WallCycleSubCounter::LaunchGpuPme);
+        wallcycle_stop(wcycle, WallCycleCounter::LaunchGpu);
 
         if (!pme_gpu_settings(pmeGpu).performGPUSolve)
         {
@@ -213,11 +213,11 @@ void pme_gpu_launch_spread(gmx_pme_t*            pme,
     /* Spread the coefficients on a grid */
     const bool computeSplines = true;
     const bool spreadCharges  = true;
-    wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU);
-    wallcycle_sub_start_nocount(wcycle, ewcsLAUNCH_GPU_PME);
+    wallcycle_start_nocount(wcycle, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start_nocount(wcycle, WallCycleSubCounter::LaunchGpuPme);
     pme_gpu_spread(pmeGpu, xReadyOnDevice, fftgrids, computeSplines, spreadCharges, lambdaQ);
-    wallcycle_sub_stop(wcycle, ewcsLAUNCH_GPU_PME);
-    wallcycle_stop(wcycle, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle, WallCycleSubCounter::LaunchGpuPme);
+    wallcycle_stop(wcycle, WallCycleCounter::LaunchGpu);
 }
 
 void pme_gpu_launch_complex_transforms(gmx_pme_t* pme, gmx_wallcycle* wcycle, const gmx::StepWorkload& stepWork)
@@ -228,9 +228,9 @@ void pme_gpu_launch_complex_transforms(gmx_pme_t* pme, gmx_wallcycle* wcycle, co
     const bool computeEnergyAndVirial = stepWork.computeEnergy || stepWork.computeVirial;
     if (!settings.performGPUFFT)
     {
-        wallcycle_start(wcycle, ewcWAIT_GPU_PME_SPREAD);
+        wallcycle_start(wcycle, WallCycleCounter::WaitGpuPmeSpread);
         pme_gpu_sync_spread_grid(pme->gpu);
-        wallcycle_stop(wcycle, ewcWAIT_GPU_PME_SPREAD);
+        wallcycle_stop(wcycle, WallCycleCounter::WaitGpuPmeSpread);
     }
 
     try
@@ -248,22 +248,21 @@ void pme_gpu_launch_complex_transforms(gmx_pme_t* pme, gmx_wallcycle* wcycle, co
             {
                 const auto gridOrdering =
                         settings.useDecomposition ? GridOrdering::YZX : GridOrdering::XYZ;
-                wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU);
-                wallcycle_sub_start_nocount(wcycle, ewcsLAUNCH_GPU_PME);
+                wallcycle_start_nocount(wcycle, WallCycleCounter::LaunchGpu);
+                wallcycle_sub_start_nocount(wcycle, WallCycleSubCounter::LaunchGpuPme);
                 pme_gpu_solve(pmeGpu, gridIndex, cfftgrid, gridOrdering, computeEnergyAndVirial);
-                wallcycle_sub_stop(wcycle, ewcsLAUNCH_GPU_PME);
-                wallcycle_stop(wcycle, ewcLAUNCH_GPU);
+                wallcycle_sub_stop(wcycle, WallCycleSubCounter::LaunchGpuPme);
+                wallcycle_stop(wcycle, WallCycleCounter::LaunchGpu);
             }
             else
             {
-                wallcycle_start(wcycle, ewcPME_SOLVE_MIXED_MODE);
+                wallcycle_start(wcycle, WallCycleCounter::PmeSolveMixedMode);
 #pragma omp parallel for num_threads(pme->nthread) schedule(static)
                 for (int thread = 0; thread < pme->nthread; thread++)
                 {
-                    solve_pme_yzx(pme, cfftgrid, pme->boxVolume, computeEnergyAndVirial,
-                                  pme->nthread, thread);
+                    solve_pme_yzx(pme, cfftgrid, pme->boxVolume, computeEnergyAndVirial, pme->nthread, thread);
                 }
-                wallcycle_stop(wcycle, ewcPME_SOLVE_MIXED_MODE);
+                wallcycle_stop(wcycle, WallCycleCounter::PmeSolveMixedMode);
             }
 
             parallel_3dfft_execute_gpu_wrapper(pme, gridIndex, GMX_FFT_COMPLEX_TO_REAL, wcycle);
@@ -281,13 +280,13 @@ void pme_gpu_launch_gather(const gmx_pme_t* pme, gmx_wallcycle gmx_unused* wcycl
         return;
     }
 
-    wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU);
-    wallcycle_sub_start_nocount(wcycle, ewcsLAUNCH_GPU_PME);
+    wallcycle_start_nocount(wcycle, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start_nocount(wcycle, WallCycleSubCounter::LaunchGpuPme);
 
     float** fftgrids = pme->fftgrid;
     pme_gpu_gather(pme->gpu, fftgrids, lambdaQ);
-    wallcycle_sub_stop(wcycle, ewcsLAUNCH_GPU_PME);
-    wallcycle_stop(wcycle, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle, WallCycleSubCounter::LaunchGpuPme);
+    wallcycle_stop(wcycle, WallCycleCounter::LaunchGpu);
 }
 
 //! Accumulate the \c forcesToAdd to \c f, using the available threads.
@@ -295,7 +294,7 @@ static void sum_forces(gmx::ArrayRef<gmx::RVec> f, gmx::ArrayRef<const gmx::RVec
 {
     const int end = forceToAdd.size();
 
-    int gmx_unused nt = gmx_omp_nthreads_get(emntPME);
+    int gmx_unused nt = gmx_omp_nthreads_get(ModuleMultiThread::Pme);
 #pragma omp parallel for num_threads(nt) schedule(static)
     for (int i = 0; i < end; i++)
     {
@@ -310,7 +309,7 @@ static void pme_gpu_reduce_outputs(const bool            computeEnergyAndVirial,
                                    gmx::ForceWithVirial* forceWithVirial,
                                    gmx_enerdata_t*       enerd)
 {
-    wallcycle_start(wcycle, ewcPME_GPU_F_REDUCTION);
+    wallcycle_start(wcycle, WallCycleCounter::PmeGpuFReduction);
     GMX_ASSERT(forceWithVirial, "Invalid force pointer");
 
     if (computeEnergyAndVirial)
@@ -318,13 +317,13 @@ static void pme_gpu_reduce_outputs(const bool            computeEnergyAndVirial,
         GMX_ASSERT(enerd, "Invalid energy output manager");
         forceWithVirial->addVirialContribution(output.coulombVirial_);
         enerd->term[F_COUL_RECIP] += output.coulombEnergy_;
-        enerd->dvdl_lin[efptCOUL] += output.coulombDvdl_;
+        enerd->dvdl_lin[FreeEnergyPerturbationCouplingType::Coul] += output.coulombDvdl_;
     }
     if (output.haveForceOutput_)
     {
         sum_forces(forceWithVirial->force_, output.forces_);
     }
-    wallcycle_stop(wcycle, ewcPME_GPU_F_REDUCTION);
+    wallcycle_stop(wcycle, WallCycleCounter::PmeGpuFReduction);
 }
 
 bool pme_gpu_try_finish_task(gmx_pme_t*               pme,
@@ -349,11 +348,11 @@ bool pme_gpu_try_finish_task(gmx_pme_t*               pme,
     // TODO: implement c_streamQuerySupported with an additional GpuEventSynchronizer per stream (#2521)
     if ((completionKind == GpuTaskCompletion::Check) && c_streamQuerySupported)
     {
-        wallcycle_start_nocount(wcycle, ewcWAIT_GPU_PME_GATHER);
+        wallcycle_start_nocount(wcycle, WallCycleCounter::WaitGpuPmeGather);
         // Query the PME stream for completion of all tasks enqueued and
         // if we're not done, stop the timer before early return.
         const bool pmeGpuDone = pme_gpu_stream_query(pme->gpu);
-        wallcycle_stop(wcycle, ewcWAIT_GPU_PME_GATHER);
+        wallcycle_stop(wcycle, WallCycleCounter::WaitGpuPmeGather);
 
         if (!pmeGpuDone)
         {
@@ -362,7 +361,7 @@ bool pme_gpu_try_finish_task(gmx_pme_t*               pme,
         needToSynchronize = false;
     }
 
-    wallcycle_start(wcycle, ewcWAIT_GPU_PME_GATHER);
+    wallcycle_start(wcycle, WallCycleCounter::WaitGpuPmeGather);
     // If the above check passed, then there is no need to make an
     // explicit synchronization call.
     if (needToSynchronize)
@@ -373,9 +372,9 @@ bool pme_gpu_try_finish_task(gmx_pme_t*               pme,
     pme_gpu_update_timings(pme->gpu);
     // There's no support for computing energy without virial, or vice versa
     const bool computeEnergyAndVirial = stepWork.computeEnergy || stepWork.computeVirial;
-    PmeOutput  output                 = pme_gpu_getOutput(*pme, computeEnergyAndVirial,
-                                         pme->gpu->common->ngrids > 1 ? lambdaQ : 1.0);
-    wallcycle_stop(wcycle, ewcWAIT_GPU_PME_GATHER);
+    PmeOutput  output                 = pme_gpu_getOutput(
+            *pme, computeEnergyAndVirial, pme->gpu->common->ngrids > 1 ? lambdaQ : 1.0);
+    wallcycle_stop(wcycle, WallCycleCounter::WaitGpuPmeGather);
 
     GMX_ASSERT(pme->gpu->settings.useGpuForceReduction == !output.haveForceOutput_,
                "When forces are reduced on the CPU, there needs to be force output");
@@ -392,7 +391,7 @@ PmeOutput pme_gpu_wait_finish_task(gmx_pme_t*     pme,
 {
     GMX_ASSERT(pme_gpu_active(pme), "This should be a GPU run of PME but it is not enabled.");
 
-    wallcycle_start(wcycle, ewcWAIT_GPU_PME_GATHER);
+    wallcycle_start(wcycle, WallCycleCounter::WaitGpuPmeGather);
 
     // Synchronize the whole PME stream at once, including D2H result transfers
     // if there are outputs we need to wait for at this step; we still call getOutputs
@@ -402,9 +401,9 @@ PmeOutput pme_gpu_wait_finish_task(gmx_pme_t*     pme,
         pme_gpu_synchronize(pme->gpu);
     }
 
-    PmeOutput output = pme_gpu_getOutput(*pme, computeEnergyAndVirial,
-                                         pme->gpu->common->ngrids > 1 ? lambdaQ : 1.0);
-    wallcycle_stop(wcycle, ewcWAIT_GPU_PME_GATHER);
+    PmeOutput output = pme_gpu_getOutput(
+            *pme, computeEnergyAndVirial, pme->gpu->common->ngrids > 1 ? lambdaQ : 1.0);
+    wallcycle_stop(wcycle, WallCycleCounter::WaitGpuPmeGather);
     return output;
 }
 
@@ -429,23 +428,23 @@ void pme_gpu_reinit_computation(const gmx_pme_t* pme, gmx_wallcycle* wcycle)
 {
     GMX_ASSERT(pme_gpu_active(pme), "This should be a GPU run of PME but it is not enabled.");
 
-    wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU);
-    wallcycle_sub_start_nocount(wcycle, ewcsLAUNCH_GPU_PME);
+    wallcycle_start_nocount(wcycle, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start_nocount(wcycle, WallCycleSubCounter::LaunchGpuPme);
 
     pme_gpu_update_timings(pme->gpu);
 
     pme_gpu_clear_grids(pme->gpu);
     pme_gpu_clear_energy_virial(pme->gpu);
 
-    wallcycle_sub_stop(wcycle, ewcsLAUNCH_GPU_PME);
-    wallcycle_stop(wcycle, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle, WallCycleSubCounter::LaunchGpuPme);
+    wallcycle_stop(wcycle, WallCycleCounter::LaunchGpu);
 }
 
-void* pme_gpu_get_device_f(const gmx_pme_t* pme)
+DeviceBuffer<gmx::RVec> pme_gpu_get_device_f(const gmx_pme_t* pme)
 {
     if (!pme || !pme_gpu_active(pme))
     {
-        return nullptr;
+        return DeviceBuffer<gmx::RVec>{};
     }
     return pme_gpu_get_kernelparam_forces(pme->gpu);
 }
index ec928f745ab4817b7928098f3d9a1bc14304db15..1a8e9c577b86578f7a1598e9116c277c05f37115 100644 (file)
@@ -95,13 +95,30 @@ GpuParallel3dFft::GpuParallel3dFft(const PmeGpu* pmeGpu, const int gridIndex)
      */
 
     const int rank = 3, batch = 1;
-    result = cufftPlanMany(&planR2C_, rank, realGridSize, realGridSizePadded, 1, realGridSizePaddedTotal,
-                           complexGridSizePadded, 1, complexGridSizePaddedTotal, CUFFT_R2C, batch);
+    result = cufftPlanMany(&planR2C_,
+                           rank,
+                           realGridSize,
+                           realGridSizePadded,
+                           1,
+                           realGridSizePaddedTotal,
+                           complexGridSizePadded,
+                           1,
+                           complexGridSizePaddedTotal,
+                           CUFFT_R2C,
+                           batch);
     handleCufftError(result, "cufftPlanMany R2C plan failure");
 
-    result = cufftPlanMany(&planC2R_, rank, realGridSize, complexGridSizePadded, 1,
-                           complexGridSizePaddedTotal, realGridSizePadded, 1,
-                           realGridSizePaddedTotal, CUFFT_C2R, batch);
+    result = cufftPlanMany(&planC2R_,
+                           rank,
+                           realGridSize,
+                           complexGridSizePadded,
+                           1,
+                           complexGridSizePaddedTotal,
+                           realGridSizePadded,
+                           1,
+                           realGridSizePaddedTotal,
+                           CUFFT_C2R,
+                           batch);
     handleCufftError(result, "cufftPlanMany C2R plan failure");
 
     cudaStream_t stream = pmeGpu->archSpecific->pmeStream_.stream();
index a39f751babc7192d87083459105329c4b5eb970e..d71e43522ca59c73849d8c677c6e93393c186aa6 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 +57,8 @@
 
 #    include "gromacs/gpu_utils/gmxopencl.h"
 #    include "gromacs/gpu_utils/gputraits_ocl.h"
+#elif GMX_GPU_SYCL
+#    include "gromacs/gpu_utils/gputraits_sycl.h"
 #endif
 
 #include "gromacs/fft/fft.h" // for the enum gmx_fft_direction
index 4ba6649497494df884b6d86868834edb6b527a37..f9a5f11f060e59d3426381741af4885adfb10567 100644 (file)
@@ -89,10 +89,12 @@ GpuParallel3dFft::GpuParallel3dFft(const PmeGpu* pmeGpu, const int gridIndex)
 
     // clFFT expects row-major, so dimensions/strides are reversed (ZYX instead of XYZ)
     std::array<size_t, DIM> realGridDimensions = { realGridSize[ZZ], realGridSize[YY], realGridSize[XX] };
-    std::array<size_t, DIM> realGridStrides    = { 1, realGridSizePadded[ZZ],
+    std::array<size_t, DIM> realGridStrides    = { 1,
+                                                realGridSizePadded[ZZ],
                                                 realGridSizePadded[YY] * realGridSizePadded[ZZ] };
-    std::array<size_t, DIM> complexGridStrides = { 1, complexGridSizePadded[ZZ],
-                                                   complexGridSizePadded[YY] * complexGridSizePadded[ZZ] };
+    std::array<size_t, DIM> complexGridStrides = {
+        1, complexGridSizePadded[ZZ], complexGridSizePadded[YY] * complexGridSizePadded[ZZ]
+    };
 
     constexpr clfftDim dims = CLFFT_3D;
     handleClfftError(clfftCreateDefaultPlan(&planR2C_, context, dims, realGridDimensions.data()),
@@ -166,8 +168,15 @@ void GpuParallel3dFft::perform3dFft(gmx_fft_direction dir, CommandEvent* timingE
             GMX_THROW(
                     gmx::NotImplementedError("The chosen 3D-FFT case is not implemented on GPUs"));
     }
-    handleClfftError(clfftEnqueueTransform(plan, direction, deviceStreams_.size(),
-                                           deviceStreams_.data(), waitEvents.size(), waitEvents.data(),
-                                           timingEvent, inputGrids, outputGrids, tempBuffer),
+    handleClfftError(clfftEnqueueTransform(plan,
+                                           direction,
+                                           deviceStreams_.size(),
+                                           deviceStreams_.data(),
+                                           waitEvents.size(),
+                                           waitEvents.data(),
+                                           timingEvent,
+                                           inputGrids,
+                                           outputGrids,
+                                           tempBuffer),
                      "clFFT execution failure");
 }
index fc319eb1c23a78e53f18505bc8f1c9a41a5f9a37..8e8496da8fc36bca3bb58eea71b59a0f973c39fb 100644 (file)
@@ -277,12 +277,12 @@ __device__ __forceinline__ void calculate_splines(const PmeGpuCudaKernelParams k
 
             // TODO have shared table for both parameters to share the fetch, as index is always same?
             // TODO compare texture/LDG performance
-            sm_fractCoords[sharedMemoryIndex] +=
-                    fetchFromParamLookupTable(kernelParams.grid.d_fractShiftsTable,
-                                              kernelParams.fractShiftsTableTexture, tableIndex);
+            sm_fractCoords[sharedMemoryIndex] += fetchFromParamLookupTable(
+                    kernelParams.grid.d_fractShiftsTable, kernelParams.fractShiftsTableTexture, tableIndex);
             sm_gridlineIndices[sharedMemoryIndex] =
                     fetchFromParamLookupTable(kernelParams.grid.d_gridlineIndicesTable,
-                                              kernelParams.gridlineIndicesTableTexture, tableIndex);
+                                              kernelParams.gridlineIndicesTableTexture,
+                                              tableIndex);
             if (writeGlobal)
             {
                 gm_gridlineIndices[atomIndexOffset * DIM + sharedMemoryIndex] =
index c67e471ca3c86118b89d4061e046c8b824bebe1d..798a9be9ef3563485370ca9d39bd7b18c37b3398 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gpu_utils/device_context.h"
 #include "gromacs/gpu_utils/device_stream.h"
 #include "gromacs/gpu_utils/gpu_utils.h"
+#include "gromacs/gpu_utils/pmalloc.h"
+#if GMX_GPU_SYCL
+#    include "gromacs/gpu_utils/syclutils.h"
+#endif
 #include "gromacs/hardware/device_information.h"
 #include "gromacs/math/invertmatrix.h"
 #include "gromacs/math/units.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/logger.h"
 #include "gromacs/utility/stringutil.h"
+#include "gromacs/ewald/pme.h"
 
 #if GMX_GPU_CUDA
-#    include "gromacs/gpu_utils/pmalloc_cuda.h"
-
 #    include "pme.cuh"
-#elif GMX_GPU_OPENCL
-#    include "gromacs/gpu_utils/gmxopencl.h"
 #endif
 
-#include "gromacs/ewald/pme.h"
-
 #include "pme_gpu_3dfft.h"
 #include "pme_gpu_calculate_splines.h"
 #include "pme_gpu_constants.h"
@@ -142,7 +142,8 @@ void pme_gpu_alloc_energy_virial(PmeGpu* pmeGpu)
     for (int gridIndex = 0; gridIndex < pmeGpu->common->ngrids; gridIndex++)
     {
         allocateDeviceBuffer(&pmeGpu->kernelParams->constants.d_virialAndEnergy[gridIndex],
-                             c_virialAndEnergyCount, pmeGpu->archSpecific->deviceContext_);
+                             c_virialAndEnergyCount,
+                             pmeGpu->archSpecific->deviceContext_);
         pmalloc(reinterpret_cast<void**>(&pmeGpu->staging.h_virialAndEnergy[gridIndex]), energyAndVirialSize);
     }
 }
@@ -161,8 +162,10 @@ void pme_gpu_clear_energy_virial(const PmeGpu* pmeGpu)
 {
     for (int gridIndex = 0; gridIndex < pmeGpu->common->ngrids; gridIndex++)
     {
-        clearDeviceBufferAsync(&pmeGpu->kernelParams->constants.d_virialAndEnergy[gridIndex], 0,
-                               c_virialAndEnergyCount, pmeGpu->archSpecific->pmeStream_);
+        clearDeviceBufferAsync(&pmeGpu->kernelParams->constants.d_virialAndEnergy[gridIndex],
+                               0,
+                               c_virialAndEnergyCount,
+                               pmeGpu->archSpecific->pmeStream_);
     }
 }
 
@@ -174,7 +177,8 @@ void pme_gpu_realloc_and_copy_bspline_values(PmeGpu* pmeGpu, const int gridIndex
     GMX_ASSERT(gridIndex < pmeGpu->common->ngrids,
                "Invalid combination of gridIndex and number of grids");
 
-    const int splineValuesOffset[DIM] = { 0, pmeGpu->kernelParams->grid.realGridSize[XX],
+    const int splineValuesOffset[DIM] = { 0,
+                                          pmeGpu->kernelParams->grid.realGridSize[XX],
                                           pmeGpu->kernelParams->grid.realGridSize[XX]
                                                   + pmeGpu->kernelParams->grid.realGridSize[YY] };
     memcpy(&pmeGpu->kernelParams->grid.splineValuesOffset, &splineValuesOffset, sizeof(splineValuesOffset));
@@ -184,7 +188,8 @@ void pme_gpu_realloc_and_copy_bspline_values(PmeGpu* pmeGpu, const int gridIndex
                                     + pmeGpu->kernelParams->grid.realGridSize[ZZ];
     const bool shouldRealloc = (newSplineValuesSize > pmeGpu->archSpecific->splineValuesSize[gridIndex]);
     reallocateDeviceBuffer(&pmeGpu->kernelParams->grid.d_splineModuli[gridIndex],
-                           newSplineValuesSize, &pmeGpu->archSpecific->splineValuesSize[gridIndex],
+                           newSplineValuesSize,
+                           &pmeGpu->archSpecific->splineValuesSize[gridIndex],
                            &pmeGpu->archSpecific->splineValuesCapacity[gridIndex],
                            pmeGpu->archSpecific->deviceContext_);
     if (shouldRealloc)
@@ -197,12 +202,17 @@ void pme_gpu_realloc_and_copy_bspline_values(PmeGpu* pmeGpu, const int gridIndex
     for (int i = 0; i < DIM; i++)
     {
         memcpy(pmeGpu->staging.h_splineModuli[gridIndex] + splineValuesOffset[i],
-               pmeGpu->common->bsp_mod[i].data(), pmeGpu->common->bsp_mod[i].size() * sizeof(float));
+               pmeGpu->common->bsp_mod[i].data(),
+               pmeGpu->common->bsp_mod[i].size() * sizeof(float));
     }
     /* TODO: pin original buffer instead! */
     copyToDeviceBuffer(&pmeGpu->kernelParams->grid.d_splineModuli[gridIndex],
-                       pmeGpu->staging.h_splineModuli[gridIndex], 0, newSplineValuesSize,
-                       pmeGpu->archSpecific->pmeStream_, pmeGpu->settings.transferKind, nullptr);
+                       pmeGpu->staging.h_splineModuli[gridIndex],
+                       0,
+                       newSplineValuesSize,
+                       pmeGpu->archSpecific->pmeStream_,
+                       pmeGpu->settings.transferKind,
+                       nullptr);
 }
 
 void pme_gpu_free_bspline_values(const PmeGpu* pmeGpu)
@@ -216,10 +226,12 @@ void pme_gpu_free_bspline_values(const PmeGpu* pmeGpu)
 
 void pme_gpu_realloc_forces(PmeGpu* pmeGpu)
 {
-    const size_t newForcesSize = pmeGpu->nAtomsAlloc * DIM;
+    const size_t newForcesSize = pmeGpu->nAtomsAlloc;
     GMX_ASSERT(newForcesSize > 0, "Bad number of atoms in PME GPU");
-    reallocateDeviceBuffer(&pmeGpu->kernelParams->atoms.d_forces, newForcesSize,
-                           &pmeGpu->archSpecific->forcesSize, &pmeGpu->archSpecific->forcesSizeAlloc,
+    reallocateDeviceBuffer(&pmeGpu->kernelParams->atoms.d_forces,
+                           newForcesSize,
+                           &pmeGpu->archSpecific->forcesSize,
+                           &pmeGpu->archSpecific->forcesSizeAlloc,
                            pmeGpu->archSpecific->deviceContext_);
     pmeGpu->staging.h_forces.reserveWithPadding(pmeGpu->nAtomsAlloc);
     pmeGpu->staging.h_forces.resizeWithPadding(pmeGpu->kernelParams->atoms.nAtoms);
@@ -233,19 +245,25 @@ void pme_gpu_free_forces(const PmeGpu* pmeGpu)
 void pme_gpu_copy_input_forces(PmeGpu* pmeGpu)
 {
     GMX_ASSERT(pmeGpu->kernelParams->atoms.nAtoms > 0, "Bad number of atoms in PME GPU");
-    float* h_forcesFloat = reinterpret_cast<float*>(pmeGpu->staging.h_forces.data());
-    copyToDeviceBuffer(&pmeGpu->kernelParams->atoms.d_forces, h_forcesFloat, 0,
-                       DIM * pmeGpu->kernelParams->atoms.nAtoms, pmeGpu->archSpecific->pmeStream_,
-                       pmeGpu->settings.transferKind, nullptr);
+    copyToDeviceBuffer(&pmeGpu->kernelParams->atoms.d_forces,
+                       pmeGpu->staging.h_forces.data(),
+                       0,
+                       pmeGpu->kernelParams->atoms.nAtoms,
+                       pmeGpu->archSpecific->pmeStream_,
+                       pmeGpu->settings.transferKind,
+                       nullptr);
 }
 
 void pme_gpu_copy_output_forces(PmeGpu* pmeGpu)
 {
     GMX_ASSERT(pmeGpu->kernelParams->atoms.nAtoms > 0, "Bad number of atoms in PME GPU");
-    float* h_forcesFloat = reinterpret_cast<float*>(pmeGpu->staging.h_forces.data());
-    copyFromDeviceBuffer(h_forcesFloat, &pmeGpu->kernelParams->atoms.d_forces, 0,
-                         DIM * pmeGpu->kernelParams->atoms.nAtoms, pmeGpu->archSpecific->pmeStream_,
-                         pmeGpu->settings.transferKind, nullptr);
+    copyFromDeviceBuffer(pmeGpu->staging.h_forces.data(),
+                         &pmeGpu->kernelParams->atoms.d_forces,
+                         0,
+                         pmeGpu->kernelParams->atoms.nAtoms,
+                         pmeGpu->archSpecific->pmeStream_,
+                         pmeGpu->settings.transferKind,
+                         nullptr);
 }
 
 void pme_gpu_realloc_and_copy_input_coefficients(const PmeGpu* pmeGpu,
@@ -256,19 +274,26 @@ void pme_gpu_realloc_and_copy_input_coefficients(const PmeGpu* pmeGpu,
     const size_t newCoefficientsSize = pmeGpu->nAtomsAlloc;
     GMX_ASSERT(newCoefficientsSize > 0, "Bad number of atoms in PME GPU");
     reallocateDeviceBuffer(&pmeGpu->kernelParams->atoms.d_coefficients[gridIndex],
-                           newCoefficientsSize, &pmeGpu->archSpecific->coefficientsSize[gridIndex],
+                           newCoefficientsSize,
+                           &pmeGpu->archSpecific->coefficientsSize[gridIndex],
                            &pmeGpu->archSpecific->coefficientsCapacity[gridIndex],
                            pmeGpu->archSpecific->deviceContext_);
     copyToDeviceBuffer(&pmeGpu->kernelParams->atoms.d_coefficients[gridIndex],
-                       const_cast<float*>(h_coefficients), 0, pmeGpu->kernelParams->atoms.nAtoms,
-                       pmeGpu->archSpecific->pmeStream_, pmeGpu->settings.transferKind, nullptr);
+                       const_cast<float*>(h_coefficients),
+                       0,
+                       pmeGpu->kernelParams->atoms.nAtoms,
+                       pmeGpu->archSpecific->pmeStream_,
+                       pmeGpu->settings.transferKind,
+                       nullptr);
 
     const size_t paddingIndex = pmeGpu->kernelParams->atoms.nAtoms;
     const size_t paddingCount = pmeGpu->nAtomsAlloc - paddingIndex;
     if (paddingCount > 0)
     {
-        clearDeviceBufferAsync(&pmeGpu->kernelParams->atoms.d_coefficients[gridIndex], paddingIndex,
-                               paddingCount, pmeGpu->archSpecific->pmeStream_);
+        clearDeviceBufferAsync(&pmeGpu->kernelParams->atoms.d_coefficients[gridIndex],
+                               paddingIndex,
+                               paddingCount,
+                               pmeGpu->archSpecific->pmeStream_);
     }
 }
 
@@ -289,10 +314,15 @@ void pme_gpu_realloc_spline_data(PmeGpu* pmeGpu)
     const bool shouldRealloc        = (newSplineDataSize > pmeGpu->archSpecific->splineDataSize);
     int        currentSizeTemp      = pmeGpu->archSpecific->splineDataSize;
     int        currentSizeTempAlloc = pmeGpu->archSpecific->splineDataSizeAlloc;
-    reallocateDeviceBuffer(&pmeGpu->kernelParams->atoms.d_theta, newSplineDataSize, &currentSizeTemp,
-                           &currentSizeTempAlloc, pmeGpu->archSpecific->deviceContext_);
-    reallocateDeviceBuffer(&pmeGpu->kernelParams->atoms.d_dtheta, newSplineDataSize,
-                           &pmeGpu->archSpecific->splineDataSize, &pmeGpu->archSpecific->splineDataSizeAlloc,
+    reallocateDeviceBuffer(&pmeGpu->kernelParams->atoms.d_theta,
+                           newSplineDataSize,
+                           &currentSizeTemp,
+                           &currentSizeTempAlloc,
+                           pmeGpu->archSpecific->deviceContext_);
+    reallocateDeviceBuffer(&pmeGpu->kernelParams->atoms.d_dtheta,
+                           newSplineDataSize,
+                           &pmeGpu->archSpecific->splineDataSize,
+                           &pmeGpu->archSpecific->splineDataSizeAlloc,
                            pmeGpu->archSpecific->deviceContext_);
     // the host side reallocation
     if (shouldRealloc)
@@ -317,7 +347,8 @@ void pme_gpu_realloc_grid_indices(PmeGpu* pmeGpu)
 {
     const size_t newIndicesSize = DIM * pmeGpu->nAtomsAlloc;
     GMX_ASSERT(newIndicesSize > 0, "Bad number of atoms in PME GPU");
-    reallocateDeviceBuffer(&pmeGpu->kernelParams->atoms.d_gridlineIndices, newIndicesSize,
+    reallocateDeviceBuffer(&pmeGpu->kernelParams->atoms.d_gridlineIndices,
+                           newIndicesSize,
                            &pmeGpu->archSpecific->gridlineIndicesSize,
                            &pmeGpu->archSpecific->gridlineIndicesSizeAlloc,
                            pmeGpu->archSpecific->deviceContext_);
@@ -347,11 +378,13 @@ void pme_gpu_realloc_grids(PmeGpu* pmeGpu)
         if (pmeGpu->archSpecific->performOutOfPlaceFFT)
         {
             /* 2 separate grids */
-            reallocateDeviceBuffer(&kernelParamsPtr->grid.d_fourierGrid[gridIndex], newComplexGridSize,
+            reallocateDeviceBuffer(&kernelParamsPtr->grid.d_fourierGrid[gridIndex],
+                                   newComplexGridSize,
                                    &pmeGpu->archSpecific->complexGridSize[gridIndex],
                                    &pmeGpu->archSpecific->complexGridCapacity[gridIndex],
                                    pmeGpu->archSpecific->deviceContext_);
-            reallocateDeviceBuffer(&kernelParamsPtr->grid.d_realGrid[gridIndex], newRealGridSize,
+            reallocateDeviceBuffer(&kernelParamsPtr->grid.d_realGrid[gridIndex],
+                                   newRealGridSize,
                                    &pmeGpu->archSpecific->realGridSize[gridIndex],
                                    &pmeGpu->archSpecific->realGridCapacity[gridIndex],
                                    pmeGpu->archSpecific->deviceContext_);
@@ -360,7 +393,8 @@ void pme_gpu_realloc_grids(PmeGpu* pmeGpu)
         {
             /* A single buffer so that any grid will fit */
             const int newGridsSize = std::max(newRealGridSize, newComplexGridSize);
-            reallocateDeviceBuffer(&kernelParamsPtr->grid.d_realGrid[gridIndex], newGridsSize,
+            reallocateDeviceBuffer(&kernelParamsPtr->grid.d_realGrid[gridIndex],
+                                   newGridsSize,
                                    &pmeGpu->archSpecific->realGridSize[gridIndex],
                                    &pmeGpu->archSpecific->realGridCapacity[gridIndex],
                                    pmeGpu->archSpecific->deviceContext_);
@@ -388,7 +422,8 @@ void pme_gpu_clear_grids(const PmeGpu* pmeGpu)
 {
     for (int gridIndex = 0; gridIndex < pmeGpu->common->ngrids; gridIndex++)
     {
-        clearDeviceBufferAsync(&pmeGpu->kernelParams->grid.d_realGrid[gridIndex], 0,
+        clearDeviceBufferAsync(&pmeGpu->kernelParams->grid.d_realGrid[gridIndex],
+                               0,
                                pmeGpu->archSpecific->realGridSize[gridIndex],
                                pmeGpu->archSpecific->pmeStream_);
     }
@@ -411,12 +446,16 @@ void pme_gpu_realloc_and_copy_fract_shifts(PmeGpu* pmeGpu)
     const int newFractShiftsSize = cellCount * (nx + ny + nz);
 
     initParamLookupTable(&kernelParamsPtr->grid.d_fractShiftsTable,
-                         &kernelParamsPtr->fractShiftsTableTexture, pmeGpu->common->fsh.data(),
-                         newFractShiftsSize, pmeGpu->archSpecific->deviceContext_);
+                         &kernelParamsPtr->fractShiftsTableTexture,
+                         pmeGpu->common->fsh.data(),
+                         newFractShiftsSize,
+                         pmeGpu->archSpecific->deviceContext_);
 
     initParamLookupTable(&kernelParamsPtr->grid.d_gridlineIndicesTable,
-                         &kernelParamsPtr->gridlineIndicesTableTexture, pmeGpu->common->nn.data(),
-                         newFractShiftsSize, pmeGpu->archSpecific->deviceContext_);
+                         &kernelParamsPtr->gridlineIndicesTableTexture,
+                         pmeGpu->common->nn.data(),
+                         newFractShiftsSize,
+                         pmeGpu->archSpecific->deviceContext_);
 }
 
 void pme_gpu_free_fract_shifts(const PmeGpu* pmeGpu)
@@ -427,7 +466,7 @@ void pme_gpu_free_fract_shifts(const PmeGpu* pmeGpu)
                             kernelParamsPtr->fractShiftsTableTexture);
     destroyParamLookupTable(&kernelParamsPtr->grid.d_gridlineIndicesTable,
                             kernelParamsPtr->gridlineIndicesTableTexture);
-#elif GMX_GPU_OPENCL
+#elif GMX_GPU_OPENCL || GMX_GPU_SYCL
     freeDeviceBuffer(&kernelParamsPtr->grid.d_fractShiftsTable);
     freeDeviceBuffer(&kernelParamsPtr->grid.d_gridlineIndicesTable);
 #endif
@@ -440,16 +479,24 @@ bool pme_gpu_stream_query(const PmeGpu* pmeGpu)
 
 void pme_gpu_copy_input_gather_grid(const PmeGpu* pmeGpu, const float* h_grid, const int gridIndex)
 {
-    copyToDeviceBuffer(&pmeGpu->kernelParams->grid.d_realGrid[gridIndex], h_grid, 0,
+    copyToDeviceBuffer(&pmeGpu->kernelParams->grid.d_realGrid[gridIndex],
+                       h_grid,
+                       0,
                        pmeGpu->archSpecific->realGridSize[gridIndex],
-                       pmeGpu->archSpecific->pmeStream_, pmeGpu->settings.transferKind, nullptr);
+                       pmeGpu->archSpecific->pmeStream_,
+                       pmeGpu->settings.transferKind,
+                       nullptr);
 }
 
 void pme_gpu_copy_output_spread_grid(const PmeGpu* pmeGpu, float* h_grid, const int gridIndex)
 {
-    copyFromDeviceBuffer(h_grid, &pmeGpu->kernelParams->grid.d_realGrid[gridIndex], 0,
+    copyFromDeviceBuffer(h_grid,
+                         &pmeGpu->kernelParams->grid.d_realGrid[gridIndex],
+                         0,
                          pmeGpu->archSpecific->realGridSize[gridIndex],
-                         pmeGpu->archSpecific->pmeStream_, pmeGpu->settings.transferKind, nullptr);
+                         pmeGpu->archSpecific->pmeStream_,
+                         pmeGpu->settings.transferKind,
+                         nullptr);
     pmeGpu->archSpecific->syncSpreadGridD2H.markEvent(pmeGpu->archSpecific->pmeStream_);
 }
 
@@ -457,13 +504,27 @@ void pme_gpu_copy_output_spread_atom_data(const PmeGpu* pmeGpu)
 {
     const size_t splinesCount    = DIM * pmeGpu->nAtomsAlloc * pmeGpu->common->pme_order;
     auto*        kernelParamsPtr = pmeGpu->kernelParams.get();
-    copyFromDeviceBuffer(pmeGpu->staging.h_dtheta, &kernelParamsPtr->atoms.d_dtheta, 0, splinesCount,
-                         pmeGpu->archSpecific->pmeStream_, pmeGpu->settings.transferKind, nullptr);
-    copyFromDeviceBuffer(pmeGpu->staging.h_theta, &kernelParamsPtr->atoms.d_theta, 0, splinesCount,
-                         pmeGpu->archSpecific->pmeStream_, pmeGpu->settings.transferKind, nullptr);
-    copyFromDeviceBuffer(pmeGpu->staging.h_gridlineIndices, &kernelParamsPtr->atoms.d_gridlineIndices,
-                         0, kernelParamsPtr->atoms.nAtoms * DIM, pmeGpu->archSpecific->pmeStream_,
-                         pmeGpu->settings.transferKind, nullptr);
+    copyFromDeviceBuffer(pmeGpu->staging.h_dtheta,
+                         &kernelParamsPtr->atoms.d_dtheta,
+                         0,
+                         splinesCount,
+                         pmeGpu->archSpecific->pmeStream_,
+                         pmeGpu->settings.transferKind,
+                         nullptr);
+    copyFromDeviceBuffer(pmeGpu->staging.h_theta,
+                         &kernelParamsPtr->atoms.d_theta,
+                         0,
+                         splinesCount,
+                         pmeGpu->archSpecific->pmeStream_,
+                         pmeGpu->settings.transferKind,
+                         nullptr);
+    copyFromDeviceBuffer(pmeGpu->staging.h_gridlineIndices,
+                         &kernelParamsPtr->atoms.d_gridlineIndices,
+                         0,
+                         kernelParamsPtr->atoms.nAtoms * DIM,
+                         pmeGpu->archSpecific->pmeStream_,
+                         pmeGpu->settings.transferKind,
+                         nullptr);
 }
 
 void pme_gpu_copy_input_gather_atom_data(const PmeGpu* pmeGpu)
@@ -472,22 +533,40 @@ void pme_gpu_copy_input_gather_atom_data(const PmeGpu* pmeGpu)
     auto*        kernelParamsPtr = pmeGpu->kernelParams.get();
 
     // TODO: could clear only the padding and not the whole thing, but this is a test-exclusive code anyway
-    clearDeviceBufferAsync(&kernelParamsPtr->atoms.d_gridlineIndices, 0, pmeGpu->nAtomsAlloc * DIM,
+    clearDeviceBufferAsync(&kernelParamsPtr->atoms.d_gridlineIndices,
+                           0,
+                           pmeGpu->nAtomsAlloc * DIM,
                            pmeGpu->archSpecific->pmeStream_);
-    clearDeviceBufferAsync(&kernelParamsPtr->atoms.d_dtheta, 0,
+    clearDeviceBufferAsync(&kernelParamsPtr->atoms.d_dtheta,
+                           0,
                            pmeGpu->nAtomsAlloc * pmeGpu->common->pme_order * DIM,
                            pmeGpu->archSpecific->pmeStream_);
-    clearDeviceBufferAsync(&kernelParamsPtr->atoms.d_theta, 0,
+    clearDeviceBufferAsync(&kernelParamsPtr->atoms.d_theta,
+                           0,
                            pmeGpu->nAtomsAlloc * pmeGpu->common->pme_order * DIM,
                            pmeGpu->archSpecific->pmeStream_);
 
-    copyToDeviceBuffer(&kernelParamsPtr->atoms.d_dtheta, pmeGpu->staging.h_dtheta, 0, splinesCount,
-                       pmeGpu->archSpecific->pmeStream_, pmeGpu->settings.transferKind, nullptr);
-    copyToDeviceBuffer(&kernelParamsPtr->atoms.d_theta, pmeGpu->staging.h_theta, 0, splinesCount,
-                       pmeGpu->archSpecific->pmeStream_, pmeGpu->settings.transferKind, nullptr);
-    copyToDeviceBuffer(&kernelParamsPtr->atoms.d_gridlineIndices, pmeGpu->staging.h_gridlineIndices,
-                       0, kernelParamsPtr->atoms.nAtoms * DIM, pmeGpu->archSpecific->pmeStream_,
-                       pmeGpu->settings.transferKind, nullptr);
+    copyToDeviceBuffer(&kernelParamsPtr->atoms.d_dtheta,
+                       pmeGpu->staging.h_dtheta,
+                       0,
+                       splinesCount,
+                       pmeGpu->archSpecific->pmeStream_,
+                       pmeGpu->settings.transferKind,
+                       nullptr);
+    copyToDeviceBuffer(&kernelParamsPtr->atoms.d_theta,
+                       pmeGpu->staging.h_theta,
+                       0,
+                       splinesCount,
+                       pmeGpu->archSpecific->pmeStream_,
+                       pmeGpu->settings.transferKind,
+                       nullptr);
+    copyToDeviceBuffer(&kernelParamsPtr->atoms.d_gridlineIndices,
+                       pmeGpu->staging.h_gridlineIndices,
+                       0,
+                       kernelParamsPtr->atoms.nAtoms * DIM,
+                       pmeGpu->archSpecific->pmeStream_,
+                       pmeGpu->settings.transferKind,
+                       nullptr);
 }
 
 void pme_gpu_sync_spread_grid(const PmeGpu* pmeGpu)
@@ -814,7 +893,7 @@ static void pme_gpu_init(gmx_pme_t*           pme,
     GMX_ASSERT(pmeGpu->common->epsilon_r != 0.0F, "PME GPU: bad electrostatic coefficient");
 
     auto* kernelParamsPtr               = pme_gpu_get_kernel_params_base_ptr(pmeGpu);
-    kernelParamsPtr->constants.elFactor = ONE_4PI_EPS0 / pmeGpu->common->epsilon_r;
+    kernelParamsPtr->constants.elFactor = gmx::c_one4PiEps0 / pmeGpu->common->epsilon_r;
 }
 
 void pme_gpu_get_real_grid_sizes(const PmeGpu* pmeGpu, gmx::IVec* gridSize, gmx::IVec* paddedGridSize)
@@ -934,23 +1013,23 @@ void pme_gpu_reinit_atoms(PmeGpu* pmeGpu, const int nAtoms, const real* chargesA
  * In CUDA result can be nullptr stub, per GpuRegionTimer implementation.
  *
  * \param[in] pmeGpu         The PME GPU data structure.
- * \param[in] PMEStageId     The PME GPU stage gtPME_ index from the enum in src/gromacs/timing/gpu_timing.h
+ * \param[in] pmeStageId     The PME GPU stage gtPME_ index from the enum in src/gromacs/timing/gpu_timing.h
  */
-static CommandEvent* pme_gpu_fetch_timing_event(const PmeGpu* pmeGpu, size_t PMEStageId)
+static CommandEvent* pme_gpu_fetch_timing_event(const PmeGpu* pmeGpu, PmeStage pmeStageId)
 {
     CommandEvent* timingEvent = nullptr;
     if (pme_gpu_timings_enabled(pmeGpu))
     {
-        GMX_ASSERT(PMEStageId < pmeGpu->archSpecific->timingEvents.size(),
-                   "Wrong PME GPU timing event index");
-        timingEvent = pmeGpu->archSpecific->timingEvents[PMEStageId].fetchNextEvent();
+        GMX_ASSERT(pmeStageId < PmeStage::Count, "Wrong PME GPU timing event index");
+        timingEvent = pmeGpu->archSpecific->timingEvents[pmeStageId].fetchNextEvent();
     }
     return timingEvent;
 }
 
 void pme_gpu_3dfft(const PmeGpu* pmeGpu, gmx_fft_direction dir, const int grid_index)
 {
-    int timerId = (dir == GMX_FFT_REAL_TO_COMPLEX) ? gtPME_FFT_R2C : gtPME_FFT_C2R;
+    PmeStage timerId = (dir == GMX_FFT_REAL_TO_COMPLEX) ? PmeStage::FftTransformR2C
+                                                        : PmeStage::FftTransformC2R;
 
     pme_gpu_start_timing(pmeGpu, timerId);
     pmeGpu->archSpecific->fftSetup[grid_index]->perform3dFft(
@@ -1231,30 +1310,34 @@ void pme_gpu_spread(const PmeGpu*         pmeGpu,
     config.gridSize[0]  = dimGrid.first;
     config.gridSize[1]  = dimGrid.second;
 
-    int                                timingId;
+    PmeStage                           timingId;
     PmeGpuProgramImpl::PmeKernelHandle kernelPtr = nullptr;
     if (computeSplines)
     {
         if (spreadCharges)
         {
-            timingId  = gtPME_SPLINEANDSPREAD;
-            kernelPtr = selectSplineAndSpreadKernelPtr(pmeGpu, pmeGpu->settings.threadsPerAtom,
+            timingId  = PmeStage::SplineAndSpread;
+            kernelPtr = selectSplineAndSpreadKernelPtr(pmeGpu,
+                                                       pmeGpu->settings.threadsPerAtom,
                                                        writeGlobal || (!recalculateSplines),
                                                        pmeGpu->common->ngrids);
         }
         else
         {
-            timingId  = gtPME_SPLINE;
-            kernelPtr = selectSplineKernelPtr(pmeGpu, pmeGpu->settings.threadsPerAtom,
+            timingId  = PmeStage::Spline;
+            kernelPtr = selectSplineKernelPtr(pmeGpu,
+                                              pmeGpu->settings.threadsPerAtom,
                                               writeGlobal || (!recalculateSplines),
                                               pmeGpu->common->ngrids);
         }
     }
     else
     {
-        timingId  = gtPME_SPREAD;
-        kernelPtr = selectSpreadKernelPtr(pmeGpu, pmeGpu->settings.threadsPerAtom,
-                                          writeGlobal || (!recalculateSplines), pmeGpu->common->ngrids);
+        timingId  = PmeStage::Spread;
+        kernelPtr = selectSpreadKernelPtr(pmeGpu,
+                                          pmeGpu->settings.threadsPerAtom,
+                                          writeGlobal || (!recalculateSplines),
+                                          pmeGpu->common->ngrids);
     }
 
 
@@ -1263,17 +1346,24 @@ void pme_gpu_spread(const PmeGpu*         pmeGpu,
 #if c_canEmbedBuffers
     const auto kernelArgs = prepareGpuKernelArguments(kernelPtr, config, kernelParamsPtr);
 #else
-    const auto kernelArgs = prepareGpuKernelArguments(
-            kernelPtr, config, kernelParamsPtr, &kernelParamsPtr->atoms.d_theta,
-            &kernelParamsPtr->atoms.d_dtheta, &kernelParamsPtr->atoms.d_gridlineIndices,
-            &kernelParamsPtr->grid.d_realGrid[FEP_STATE_A], &kernelParamsPtr->grid.d_realGrid[FEP_STATE_B],
-            &kernelParamsPtr->grid.d_fractShiftsTable, &kernelParamsPtr->grid.d_gridlineIndicesTable,
-            &kernelParamsPtr->atoms.d_coefficients[FEP_STATE_A],
-            &kernelParamsPtr->atoms.d_coefficients[FEP_STATE_B], &kernelParamsPtr->atoms.d_coordinates);
+    const auto kernelArgs =
+            prepareGpuKernelArguments(kernelPtr,
+                                      config,
+                                      kernelParamsPtr,
+                                      &kernelParamsPtr->atoms.d_theta,
+                                      &kernelParamsPtr->atoms.d_dtheta,
+                                      &kernelParamsPtr->atoms.d_gridlineIndices,
+                                      &kernelParamsPtr->grid.d_realGrid[FEP_STATE_A],
+                                      &kernelParamsPtr->grid.d_realGrid[FEP_STATE_B],
+                                      &kernelParamsPtr->grid.d_fractShiftsTable,
+                                      &kernelParamsPtr->grid.d_gridlineIndicesTable,
+                                      &kernelParamsPtr->atoms.d_coefficients[FEP_STATE_A],
+                                      &kernelParamsPtr->atoms.d_coefficients[FEP_STATE_B],
+                                      &kernelParamsPtr->atoms.d_coordinates);
 #endif
 
-    launchGpuKernel(kernelPtr, config, pmeGpu->archSpecific->pmeStream_, timingEvent,
-                    "PME spline/spread", kernelArgs);
+    launchGpuKernel(
+            kernelPtr, config, pmeGpu->archSpecific->pmeStream_, timingEvent, "PME spline/spread", kernelArgs);
     pme_gpu_stop_timing(pmeGpu, timingId);
 
     const auto& settings    = pmeGpu->settings;
@@ -1314,9 +1404,13 @@ void pme_gpu_solve(const PmeGpu* pmeGpu,
     float* h_gridFloat = reinterpret_cast<float*>(h_grid);
     if (copyInputAndOutputGrid)
     {
-        copyToDeviceBuffer(&kernelParamsPtr->grid.d_fourierGrid[gridIndex], h_gridFloat, 0,
+        copyToDeviceBuffer(&kernelParamsPtr->grid.d_fourierGrid[gridIndex],
+                           h_gridFloat,
+                           0,
                            pmeGpu->archSpecific->complexGridSize[gridIndex],
-                           pmeGpu->archSpecific->pmeStream_, pmeGpu->settings.transferKind, nullptr);
+                           pmeGpu->archSpecific->pmeStream_,
+                           pmeGpu->settings.transferKind,
+                           nullptr);
     }
 
     int majorDim = -1, middleDim = -1, minorDim = -1;
@@ -1366,7 +1460,7 @@ void pme_gpu_solve(const PmeGpu* pmeGpu,
                          / gridLinesPerBlock;
     config.gridSize[2] = pmeGpu->kernelParams->grid.complexGridSize[majorDim];
 
-    int                                timingId  = gtPME_SOLVE;
+    PmeStage                           timingId  = PmeStage::Solve;
     PmeGpuProgramImpl::PmeKernelHandle kernelPtr = nullptr;
     if (gridOrdering == GridOrdering::YZX)
     {
@@ -1400,28 +1494,37 @@ void pme_gpu_solve(const PmeGpu* pmeGpu,
 #if c_canEmbedBuffers
     const auto kernelArgs = prepareGpuKernelArguments(kernelPtr, config, kernelParamsPtr);
 #else
-    const auto kernelArgs = prepareGpuKernelArguments(
-            kernelPtr, config, kernelParamsPtr, &kernelParamsPtr->grid.d_splineModuli[gridIndex],
-            &kernelParamsPtr->constants.d_virialAndEnergy[gridIndex],
-            &kernelParamsPtr->grid.d_fourierGrid[gridIndex]);
+    const auto kernelArgs =
+            prepareGpuKernelArguments(kernelPtr,
+                                      config,
+                                      kernelParamsPtr,
+                                      &kernelParamsPtr->grid.d_splineModuli[gridIndex],
+                                      &kernelParamsPtr->constants.d_virialAndEnergy[gridIndex],
+                                      &kernelParamsPtr->grid.d_fourierGrid[gridIndex]);
 #endif
-    launchGpuKernel(kernelPtr, config, pmeGpu->archSpecific->pmeStream_, timingEvent, "PME solve",
-                    kernelArgs);
+    launchGpuKernel(kernelPtr, config, pmeGpu->archSpecific->pmeStream_, timingEvent, "PME solve", kernelArgs);
     pme_gpu_stop_timing(pmeGpu, timingId);
 
     if (computeEnergyAndVirial)
     {
         copyFromDeviceBuffer(pmeGpu->staging.h_virialAndEnergy[gridIndex],
-                             &kernelParamsPtr->constants.d_virialAndEnergy[gridIndex], 0,
-                             c_virialAndEnergyCount, pmeGpu->archSpecific->pmeStream_,
-                             pmeGpu->settings.transferKind, nullptr);
+                             &kernelParamsPtr->constants.d_virialAndEnergy[gridIndex],
+                             0,
+                             c_virialAndEnergyCount,
+                             pmeGpu->archSpecific->pmeStream_,
+                             pmeGpu->settings.transferKind,
+                             nullptr);
     }
 
     if (copyInputAndOutputGrid)
     {
-        copyFromDeviceBuffer(h_gridFloat, &kernelParamsPtr->grid.d_fourierGrid[gridIndex], 0,
+        copyFromDeviceBuffer(h_gridFloat,
+                             &kernelParamsPtr->grid.d_fourierGrid[gridIndex],
+                             0,
                              pmeGpu->archSpecific->complexGridSize[gridIndex],
-                             pmeGpu->archSpecific->pmeStream_, pmeGpu->settings.transferKind, nullptr);
+                             pmeGpu->archSpecific->pmeStream_,
+                             pmeGpu->settings.transferKind,
+                             nullptr);
     }
 }
 
@@ -1549,10 +1652,12 @@ void pme_gpu_gather(PmeGpu* pmeGpu, real** h_grids, const float lambda)
 
     // TODO test different cache configs
 
-    int                                timingId = gtPME_GATHER;
+    PmeStage                           timingId = PmeStage::Gather;
     PmeGpuProgramImpl::PmeKernelHandle kernelPtr =
-            selectGatherKernelPtr(pmeGpu, pmeGpu->settings.threadsPerAtom,
-                                  readGlobal || (!recalculateSplines), pmeGpu->common->ngrids);
+            selectGatherKernelPtr(pmeGpu,
+                                  pmeGpu->settings.threadsPerAtom,
+                                  readGlobal || (!recalculateSplines),
+                                  pmeGpu->common->ngrids);
     // TODO design kernel selection getters and make PmeGpu a friend of PmeGpuProgramImpl
 
     pme_gpu_start_timing(pmeGpu, timingId);
@@ -1570,15 +1675,20 @@ void pme_gpu_gather(PmeGpu* pmeGpu, real** h_grids, const float lambda)
 #if c_canEmbedBuffers
     const auto kernelArgs = prepareGpuKernelArguments(kernelPtr, config, kernelParamsPtr);
 #else
-    const auto kernelArgs = prepareGpuKernelArguments(
-            kernelPtr, config, kernelParamsPtr, &kernelParamsPtr->atoms.d_coefficients[FEP_STATE_A],
-            &kernelParamsPtr->atoms.d_coefficients[FEP_STATE_B],
-            &kernelParamsPtr->grid.d_realGrid[FEP_STATE_A], &kernelParamsPtr->grid.d_realGrid[FEP_STATE_B],
-            &kernelParamsPtr->atoms.d_theta, &kernelParamsPtr->atoms.d_dtheta,
-            &kernelParamsPtr->atoms.d_gridlineIndices, &kernelParamsPtr->atoms.d_forces);
+    const auto kernelArgs =
+            prepareGpuKernelArguments(kernelPtr,
+                                      config,
+                                      kernelParamsPtr,
+                                      &kernelParamsPtr->atoms.d_coefficients[FEP_STATE_A],
+                                      &kernelParamsPtr->atoms.d_coefficients[FEP_STATE_B],
+                                      &kernelParamsPtr->grid.d_realGrid[FEP_STATE_A],
+                                      &kernelParamsPtr->grid.d_realGrid[FEP_STATE_B],
+                                      &kernelParamsPtr->atoms.d_theta,
+                                      &kernelParamsPtr->atoms.d_dtheta,
+                                      &kernelParamsPtr->atoms.d_gridlineIndices,
+                                      &kernelParamsPtr->atoms.d_forces);
 #endif
-    launchGpuKernel(kernelPtr, config, pmeGpu->archSpecific->pmeStream_, timingEvent, "PME gather",
-                    kernelArgs);
+    launchGpuKernel(kernelPtr, config, pmeGpu->archSpecific->pmeStream_, timingEvent, "PME gather", kernelArgs);
     pme_gpu_stop_timing(pmeGpu, timingId);
 
     if (pmeGpu->settings.useGpuForceReduction)
@@ -1591,7 +1701,7 @@ void pme_gpu_gather(PmeGpu* pmeGpu, real** h_grids, const float lambda)
     }
 }
 
-void* pme_gpu_get_kernelparam_forces(const PmeGpu* pmeGpu)
+DeviceBuffer<gmx::RVec> pme_gpu_get_kernelparam_forces(const PmeGpu* pmeGpu)
 {
     if (pmeGpu && pmeGpu->kernelParams)
     {
@@ -1599,7 +1709,7 @@ void* pme_gpu_get_kernelparam_forces(const PmeGpu* pmeGpu)
     }
     else
     {
-        return nullptr;
+        return DeviceBuffer<gmx::RVec>{};
     }
 }
 
index 632557d13e737163981578361de03da4a2238f72..7baa6bd3475eb1a79ff5e7f498c0554a7eb5f735 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -405,8 +405,8 @@ GPU_FUNC_QUALIFIER void pme_gpu_set_kernelparam_coordinates(const PmeGpu* GPU_FU
  * \param[in] pmeGpu         The PME GPU structure.
  * \returns                  Pointer to force data
  */
-GPU_FUNC_QUALIFIER void* pme_gpu_get_kernelparam_forces(const PmeGpu* GPU_FUNC_ARGUMENT(pmeGpu))
-        GPU_FUNC_TERM_WITH_RETURN(nullptr);
+GPU_FUNC_QUALIFIER DeviceBuffer<gmx::RVec> pme_gpu_get_kernelparam_forces(const PmeGpu* GPU_FUNC_ARGUMENT(pmeGpu))
+        GPU_FUNC_TERM_WITH_RETURN(DeviceBuffer<gmx::RVec>{});
 
 /*! \brief Return pointer to the sync object triggered after the PME force calculation completion
  * \param[in] pmeGpu         The PME GPU structure.
index a6ceac16ee7128b6abb996edba3e040dfbf0cfcf..b296f082f81cf888489f03fc5f5747d917f4c8fe 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
index 13587938074146861d8013619fc9e7a0346c4f20..b7830fa60b99f4dae6e80229225b69f1be222723 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,74 +60,74 @@ constexpr int c_stateB = 1;
 
 //! PME CUDA kernels forward declarations. Kernels are documented in their respective files.
 template<int order, bool computeSplines, bool spreadCharges, bool wrapX, bool wrapY, int mode, bool writeGlobal, ThreadsPerAtom threadsPerAtom>
-void pme_spline_and_spread_kernel(const PmeGpuCudaKernelParams kernelParams);
+__global__ void pme_spline_and_spread_kernel(const PmeGpuCudaKernelParams kernelParams);
 
 // Add extern declarations to inform that there will be a definition
 // provided in another translation unit.
 // clang-format off
-extern template void
+extern template void __global__
 pme_spline_and_spread_kernel<c_pmeOrder, true, true, c_wrapX, c_wrapY, 1, true, ThreadsPerAtom::Order>(const PmeGpuCudaKernelParams);
-extern template void
+extern template void __global__
 pme_spline_and_spread_kernel<c_pmeOrder, true, true, c_wrapX, c_wrapY, 1, true, ThreadsPerAtom::OrderSquared>(const PmeGpuCudaKernelParams);
-extern template void
+extern template void __global__
 pme_spline_and_spread_kernel<c_pmeOrder, true, false, c_wrapX, c_wrapY, 1, true, ThreadsPerAtom::Order>(const PmeGpuCudaKernelParams);
-extern template void
+extern template void __global__
 pme_spline_and_spread_kernel<c_pmeOrder, true, false, c_wrapX, c_wrapY, 1, true, ThreadsPerAtom::OrderSquared>(const PmeGpuCudaKernelParams);
-extern template void
+extern template __global__ void
 pme_spline_and_spread_kernel<c_pmeOrder, false, true, c_wrapX, c_wrapY, 1, true, ThreadsPerAtom::Order>(const PmeGpuCudaKernelParams);
-extern template void
+extern template __global__ void
 pme_spline_and_spread_kernel<c_pmeOrder, false, true, c_wrapX, c_wrapY, 1, true, ThreadsPerAtom::OrderSquared>(const PmeGpuCudaKernelParams);
-extern template void
+extern template __global__ void
 pme_spline_and_spread_kernel<c_pmeOrder, true, true, c_wrapX, c_wrapY, 1, false, ThreadsPerAtom::Order>(const PmeGpuCudaKernelParams);
-extern template void
+extern template __global__ void
 pme_spline_and_spread_kernel<c_pmeOrder, true, true, c_wrapX, c_wrapY, 1, false, ThreadsPerAtom::OrderSquared>(const PmeGpuCudaKernelParams);
-extern template void
+extern template __global__ void
 pme_spline_and_spread_kernel<c_pmeOrder, true, true, c_wrapX, c_wrapY, 2, true, ThreadsPerAtom::Order>(const PmeGpuCudaKernelParams);
-extern template void
+extern template __global__ void
 pme_spline_and_spread_kernel<c_pmeOrder, true, true, c_wrapX, c_wrapY, 2, true, ThreadsPerAtom::OrderSquared>(const PmeGpuCudaKernelParams);
-extern template void
+extern template __global__ void
 pme_spline_and_spread_kernel<c_pmeOrder, true, false, c_wrapX, c_wrapY, 2, true, ThreadsPerAtom::Order>(const PmeGpuCudaKernelParams);
-extern template void
+extern template __global__ void
 pme_spline_and_spread_kernel<c_pmeOrder, true, false, c_wrapX, c_wrapY, 2, true, ThreadsPerAtom::OrderSquared>(const PmeGpuCudaKernelParams);
-extern template void
+extern template __global__ void
 pme_spline_and_spread_kernel<c_pmeOrder, false, true, c_wrapX, c_wrapY, 2, true, ThreadsPerAtom::Order>(const PmeGpuCudaKernelParams);
-extern template void
+extern template __global__ void
 pme_spline_and_spread_kernel<c_pmeOrder, false, true, c_wrapX, c_wrapY, 2, true, ThreadsPerAtom::OrderSquared>(const PmeGpuCudaKernelParams);
-extern template void
+extern template __global__ void
 pme_spline_and_spread_kernel<c_pmeOrder, true, true, c_wrapX, c_wrapY, 2, false, ThreadsPerAtom::Order>(const PmeGpuCudaKernelParams);
-extern template void
+extern template __global__ void
 pme_spline_and_spread_kernel<c_pmeOrder, true, true, c_wrapX, c_wrapY, 2, false, ThreadsPerAtom::OrderSquared>(const PmeGpuCudaKernelParams);
 
 template<GridOrdering gridOrdering, bool computeEnergyAndVirial, const int gridIndex> /* It is significantly slower to pass gridIndex as a kernel parameter */
-void pme_solve_kernel(const PmeGpuCudaKernelParams kernelParams);
+__global__ void pme_solve_kernel(const PmeGpuCudaKernelParams kernelParams);
 
 // Add extern declarations to inform that there will be a definition
 // provided in another translation unit.
 // clang-format off
-extern template void pme_solve_kernel<GridOrdering::XYZ, false, c_stateA>(const PmeGpuCudaKernelParams);
-extern template void pme_solve_kernel<GridOrdering::XYZ, true, c_stateA>(const PmeGpuCudaKernelParams);
-extern template void pme_solve_kernel<GridOrdering::YZX, false, c_stateA>(const PmeGpuCudaKernelParams);
-extern template void pme_solve_kernel<GridOrdering::YZX, true, c_stateA>(const PmeGpuCudaKernelParams);
-extern template void pme_solve_kernel<GridOrdering::XYZ, false, c_stateB>(const PmeGpuCudaKernelParams);
-extern template void pme_solve_kernel<GridOrdering::XYZ, true, c_stateB>(const PmeGpuCudaKernelParams);
-extern template void pme_solve_kernel<GridOrdering::YZX, false, c_stateB>(const PmeGpuCudaKernelParams);
-extern template void pme_solve_kernel<GridOrdering::YZX, true, c_stateB>(const PmeGpuCudaKernelParams);
+extern template __global__ void pme_solve_kernel<GridOrdering::XYZ, false, c_stateA>(const PmeGpuCudaKernelParams);
+extern template __global__ void pme_solve_kernel<GridOrdering::XYZ, true, c_stateA>(const PmeGpuCudaKernelParams);
+extern template __global__ void pme_solve_kernel<GridOrdering::YZX, false, c_stateA>(const PmeGpuCudaKernelParams);
+extern template __global__ void pme_solve_kernel<GridOrdering::YZX, true, c_stateA>(const PmeGpuCudaKernelParams);
+extern template __global__ void pme_solve_kernel<GridOrdering::XYZ, false, c_stateB>(const PmeGpuCudaKernelParams);
+extern template __global__ void pme_solve_kernel<GridOrdering::XYZ, true, c_stateB>(const PmeGpuCudaKernelParams);
+extern template __global__ void pme_solve_kernel<GridOrdering::YZX, false, c_stateB>(const PmeGpuCudaKernelParams);
+extern template __global__ void pme_solve_kernel<GridOrdering::YZX, true, c_stateB>(const PmeGpuCudaKernelParams);
 // clang-format on
 
 template<int order, bool wrapX, bool wrapY, int nGrids, bool readGlobal, ThreadsPerAtom threadsPerAtom>
-void pme_gather_kernel(const PmeGpuCudaKernelParams kernelParams);
+__global__ void pme_gather_kernel(const PmeGpuCudaKernelParams kernelParams);
 
 // Add extern declarations to inform that there will be a definition
 // provided in another translation unit.
 // clang-format off
-extern template void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 1, true, ThreadsPerAtom::Order>        (const PmeGpuCudaKernelParams);
-extern template void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 1, false, ThreadsPerAtom::Order>       (const PmeGpuCudaKernelParams);
-extern template void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 1, true, ThreadsPerAtom::OrderSquared> (const PmeGpuCudaKernelParams);
-extern template void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 1, false, ThreadsPerAtom::OrderSquared>(const PmeGpuCudaKernelParams);
-extern template void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 2, true, ThreadsPerAtom::Order>          (const PmeGpuCudaKernelParams);
-extern template void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 2, false, ThreadsPerAtom::Order>         (const PmeGpuCudaKernelParams);
-extern template void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 2, true, ThreadsPerAtom::OrderSquared>   (const PmeGpuCudaKernelParams);
-extern template void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 2, false, ThreadsPerAtom::OrderSquared>  (const PmeGpuCudaKernelParams);
+extern template __global__ void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 1, true, ThreadsPerAtom::Order>        (const PmeGpuCudaKernelParams);
+extern template __global__ void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 1, false, ThreadsPerAtom::Order>       (const PmeGpuCudaKernelParams);
+extern template __global__ void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 1, true, ThreadsPerAtom::OrderSquared> (const PmeGpuCudaKernelParams);
+extern template __global__ void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 1, false, ThreadsPerAtom::OrderSquared>(const PmeGpuCudaKernelParams);
+extern template __global__ void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 2, true, ThreadsPerAtom::Order>          (const PmeGpuCudaKernelParams);
+extern template __global__ void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 2, false, ThreadsPerAtom::Order>         (const PmeGpuCudaKernelParams);
+extern template __global__ void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 2, true, ThreadsPerAtom::OrderSquared>   (const PmeGpuCudaKernelParams);
+extern template __global__ void pme_gather_kernel<c_pmeOrder, c_wrapX, c_wrapY, 2, false, ThreadsPerAtom::OrderSquared>  (const PmeGpuCudaKernelParams);
 // clang-format on
 
 PmeGpuProgramImpl::PmeGpuProgramImpl(const DeviceContext& deviceContext) :
@@ -179,4 +179,4 @@ PmeGpuProgramImpl::PmeGpuProgramImpl(const DeviceContext& deviceContext) :
     // clang-format on
 }
 
-PmeGpuProgramImpl::~PmeGpuProgramImpl() {}
+PmeGpuProgramImpl::~PmeGpuProgramImpl() = default;
index 6255e460546fb6965fa94391777c3ba91aee2789..8a1e8afaf110a84a6b06d96328225bd5ee35ca6a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
 
 #include "config.h"
 
+#include <memory>
+
 #include "gromacs/gpu_utils/device_context.h"
 #include "gromacs/utility/classhelpers.h"
 
@@ -168,6 +170,7 @@ struct PmeGpuProgramImpl
     PmeGpuProgramImpl() = delete;
     //! Constructor for the given device
     explicit PmeGpuProgramImpl(const DeviceContext& deviceContext);
+    // NOLINTNEXTLINE(performance-trivially-destructible)
     ~PmeGpuProgramImpl();
     GMX_DISALLOW_COPY_AND_ASSIGN(PmeGpuProgramImpl);
 
index c88baf40e5fca4782d2b4be594ef934d69afd4fc..85cee2f008e072a32ba879995b946e07fe8f8c3e 100644 (file)
@@ -89,7 +89,8 @@ PmeGpuProgramImpl::~PmeGpuProgramImpl()
     stat |= clReleaseKernel(solveYZXKernelB);
     stat |= clReleaseKernel(solveYZXEnergyKernelB);
     GMX_ASSERT(stat == CL_SUCCESS,
-               gmx::formatString("Failed to release PME OpenCL resources %d: %s", stat,
+               gmx::formatString("Failed to release PME OpenCL resources %d: %s",
+                                 stat,
                                  ocl_get_error_string(stat).c_str())
                        .c_str());
 }
@@ -116,7 +117,10 @@ static void checkRequiredWarpSize(cl_kernel kernel, const char* kernelName, cons
                     "PME OpenCL kernels require >=%d execution width, but the %s kernel "
                     "has been compiled for the device %s to a %d width and therefore it can not "
                     "execute correctly.",
-                    minKernelWarpSize, kernelName, deviceInfo.device_name, kernelWarpSize);
+                    minKernelWarpSize,
+                    kernelName,
+                    deviceInfo.device_name,
+                    kernelWarpSize);
             GMX_THROW(gmx::InternalError(errorString));
         }
     }
@@ -150,17 +154,30 @@ void PmeGpuProgramImpl::compileKernels(const DeviceInformation& deviceInfo)
                 "-DDIM=%d -DXX=%d -DYY=%d -DZZ=%d "
                 // decomposition parameter placeholders
                 "-DwrapX=true -DwrapY=true ",
-                warpSize_, c_pmeGpuOrder, c_pmeGpuOrder * c_pmeGpuOrder,
-                static_cast<float>(c_pmeMaxUnitcellShift), static_cast<int>(c_skipNeutralAtoms),
-                c_virialAndEnergyCount, spreadWorkGroupSize, solveMaxWorkGroupSize,
-                gatherWorkGroupSize, DIM, XX, YY, ZZ);
+                warpSize_,
+                c_pmeGpuOrder,
+                c_pmeGpuOrder * c_pmeGpuOrder,
+                static_cast<float>(c_pmeMaxUnitcellShift),
+                static_cast<int>(c_skipNeutralAtoms),
+                c_virialAndEnergyCount,
+                spreadWorkGroupSize,
+                solveMaxWorkGroupSize,
+                gatherWorkGroupSize,
+                DIM,
+                XX,
+                YY,
+                ZZ);
         try
         {
             /* TODO when we have a proper MPI-aware logging module,
                the log output here should be written there */
-            program = gmx::ocl::compileProgram(stderr, "gromacs/ewald", "pme_program.cl",
-                                               commonDefines, deviceContext_.context(),
-                                               deviceInfo.oclDeviceId, deviceInfo.deviceVendor);
+            program = gmx::ocl::compileProgram(stderr,
+                                               "gromacs/ewald",
+                                               "pme_program.cl",
+                                               commonDefines,
+                                               deviceContext_.context(),
+                                               deviceInfo.oclDeviceId,
+                                               deviceInfo.deviceVendor);
         }
         catch (gmx::GromacsException& e)
         {
@@ -181,7 +198,9 @@ void PmeGpuProgramImpl::compileKernels(const DeviceInformation& deviceInfo)
     {
         const std::string errorString = gmx::formatString(
                 "Failed to create kernels for PME on GPU #%s:\n OpenCL error %d: %s",
-                deviceInfo.device_name, clError, ocl_get_error_string(clError).c_str());
+                deviceInfo.device_name,
+                clError,
+                ocl_get_error_string(clError).c_str());
         GMX_THROW(gmx::InternalError(errorString));
     }
     kernels.resize(actualKernelCount);
@@ -189,13 +208,15 @@ void PmeGpuProgramImpl::compileKernels(const DeviceInformation& deviceInfo)
     std::array<char, 100> kernelNamesBuffer;
     for (const auto& kernel : kernels)
     {
-        clError = clGetKernelInfo(kernel, CL_KERNEL_FUNCTION_NAME, kernelNamesBuffer.size(),
-                                  kernelNamesBuffer.data(), nullptr);
+        clError = clGetKernelInfo(
+                kernel, CL_KERNEL_FUNCTION_NAME, kernelNamesBuffer.size(), kernelNamesBuffer.data(), nullptr);
         if (clError != CL_SUCCESS)
         {
             const std::string errorString = gmx::formatString(
                     "Failed to parse kernels for PME on GPU #%s:\n OpenCL error %d: %s",
-                    deviceInfo.device_name, clError, ocl_get_error_string(clError).c_str());
+                    deviceInfo.device_name,
+                    clError,
+                    ocl_get_error_string(clError).c_str());
             GMX_THROW(gmx::InternalError(errorString));
         }
 
similarity index 56%
rename from src/gromacs/gmxlib/nonbonded/nb_kernel.h
rename to src/gromacs/ewald/pme_gpu_sycl_stubs.cpp
index ff75e9159a77affa82c9ec88f3e04ab6a52c4c2d..c6f6c1c303132c330acc96d9331386d5a5fd2554 100644 (file)
@@ -1,8 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 _nb_kernel_h_
-#define _nb_kernel_h_
 
-#include <stdio.h>
+/*! \internal \file
+ * \brief Implements stubs of high-level PME GPU functions for SYCL.
+ *
+ * \author Andrey Alekseenko <al42and@gmail.com>
+ *
+ * \ingroup module_ewald
+ */
+#include "gmxpre.h"
 
-#include "gromacs/gmxlib/nrnb.h"
-#include "gromacs/math/vectypes.h"
-#include "gromacs/mdtypes/nblist.h"
-#include "gromacs/utility/real.h"
+#include "gromacs/ewald/ewald_utils.h"
 
-struct t_blocka;
-struct t_mdatoms;
+#include "pme_gpu_3dfft.h"
+#include "pme_gpu_internal.h"
+#include "pme_gpu_program_impl.h"
 
-/* Structure to collect kernel data not available in forcerec or mdatoms structures.
- * This is only used inside the nonbonded module.
- */
-typedef struct
+PmeGpuProgramImpl::PmeGpuProgramImpl(const DeviceContext& deviceContext) :
+    deviceContext_(deviceContext),
+    warpSize_(0),
+    spreadWorkGroupSize(0),
+    gatherWorkGroupSize(0),
+    solveMaxWorkGroupSize(0)
 {
-    int                    flags;
-    const struct t_blocka* exclusions;
-    const real*            lambda;
-    real*                  dvdl;
+    // SYCL-TODO
+}
 
-    /* pointers to tables */
-    t_forcetable* table_elec;
-    t_forcetable* table_vdw;
-    t_forcetable* table_elec_vdw;
+PmeGpuProgramImpl::~PmeGpuProgramImpl() = default;
 
-    /* potentials */
-    real* energygrp_elec;
-    real* energygrp_vdw;
-} nb_kernel_data_t;
+// [[noreturn]] attributes must be added in the common headers, so it's easier to silence the warning here
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-noreturn"
 
+GpuParallel3dFft::GpuParallel3dFft(PmeGpu const* /*pmeGpu*/, int /*gridIndex*/)
+{
+    GMX_THROW(gmx::NotImplementedError("PME is not implemented in SYCL"));
+}
+
+GpuParallel3dFft::~GpuParallel3dFft() = default;
 
-typedef void nb_kernel_t(t_nblist* gmx_restrict nlist,
-                         rvec* gmx_restrict x,
-                         rvec* gmx_restrict f,
-                         struct t_forcerec* gmx_restrict fr,
-                         t_mdatoms* gmx_restrict mdatoms,
-                         nb_kernel_data_t* gmx_restrict kernel_data,
-                         t_nrnb* gmx_restrict nrnb);
+void GpuParallel3dFft::perform3dFft(gmx_fft_direction /*dir*/, CommandEvent* /*timingEvent*/)
+{
+    GMX_THROW(gmx::NotImplementedError("Not implemented on SYCL yet"));
+}
 
-#endif /* _nb_kernel_h_ */
+#pragma clang diagnostic pop
index 3a1f45746857d78d5a099b83507c38b47b8c08e7..205564b6a59f0c5c3db0361dd255c6713ce19e15 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,23 +55,21 @@ bool pme_gpu_timings_enabled(const PmeGpu* pmeGpu)
     return pmeGpu->archSpecific->useTiming;
 }
 
-void pme_gpu_start_timing(const PmeGpu* pmeGpu, size_t PMEStageId)
+void pme_gpu_start_timing(const PmeGpu* pmeGpu, PmeStage pmeStageId)
 {
     if (pme_gpu_timings_enabled(pmeGpu))
     {
-        GMX_ASSERT(PMEStageId < pmeGpu->archSpecific->timingEvents.size(),
-                   "Wrong PME GPU timing event index");
-        pmeGpu->archSpecific->timingEvents[PMEStageId].openTimingRegion(pmeGpu->archSpecific->pmeStream_);
+        GMX_ASSERT(pmeStageId < PmeStage::Count, "Wrong PME GPU timing event index");
+        pmeGpu->archSpecific->timingEvents[pmeStageId].openTimingRegion(pmeGpu->archSpecific->pmeStream_);
     }
 }
 
-void pme_gpu_stop_timing(const PmeGpu* pmeGpu, size_t PMEStageId)
+void pme_gpu_stop_timing(const PmeGpu* pmeGpu, PmeStage pmeStageId)
 {
     if (pme_gpu_timings_enabled(pmeGpu))
     {
-        GMX_ASSERT(PMEStageId < pmeGpu->archSpecific->timingEvents.size(),
-                   "Wrong PME GPU timing event index");
-        pmeGpu->archSpecific->timingEvents[PMEStageId].closeTimingRegion(pmeGpu->archSpecific->pmeStream_);
+        GMX_ASSERT(pmeStageId < PmeStage::Count, "Wrong PME GPU timing event index");
+        pmeGpu->archSpecific->timingEvents[pmeStageId].closeTimingRegion(pmeGpu->archSpecific->pmeStream_);
     }
 }
 
@@ -80,10 +78,10 @@ void pme_gpu_get_timings(const PmeGpu* pmeGpu, gmx_wallclock_gpu_pme_t* timings)
     if (pme_gpu_timings_enabled(pmeGpu))
     {
         GMX_RELEASE_ASSERT(timings, "Null GPU timing pointer");
-        for (size_t i = 0; i < pmeGpu->archSpecific->timingEvents.size(); i++)
+        for (auto key : keysOf(timings->timing))
         {
-            timings->timing[i].t = pmeGpu->archSpecific->timingEvents[i].getTotalTime();
-            timings->timing[i].c = pmeGpu->archSpecific->timingEvents[i].getCallCount();
+            timings->timing[key].t = pmeGpu->archSpecific->timingEvents[key].getTotalTime();
+            timings->timing[key].c = pmeGpu->archSpecific->timingEvents[key].getCallCount();
         }
     }
 }
@@ -92,7 +90,7 @@ void pme_gpu_update_timings(const PmeGpu* pmeGpu)
 {
     if (pme_gpu_timings_enabled(pmeGpu))
     {
-        for (const size_t& activeTimer : pmeGpu->archSpecific->activeTimers)
+        for (const auto& activeTimer : pmeGpu->archSpecific->activeTimers)
         {
             pmeGpu->archSpecific->timingEvents[activeTimer].getLastRangeTime();
         }
@@ -104,21 +102,21 @@ void pme_gpu_reinit_timings(const PmeGpu* pmeGpu)
     if (pme_gpu_timings_enabled(pmeGpu))
     {
         pmeGpu->archSpecific->activeTimers.clear();
-        pmeGpu->archSpecific->activeTimers.insert(gtPME_SPLINEANDSPREAD);
+        pmeGpu->archSpecific->activeTimers.insert(PmeStage::SplineAndSpread);
         const auto& settings = pme_gpu_settings(pmeGpu);
         // TODO: no separate gtPME_SPLINE and gtPME_SPREAD as they are not used currently
         if (settings.performGPUFFT)
         {
-            pmeGpu->archSpecific->activeTimers.insert(gtPME_FFT_C2R);
-            pmeGpu->archSpecific->activeTimers.insert(gtPME_FFT_R2C);
+            pmeGpu->archSpecific->activeTimers.insert(PmeStage::FftTransformC2R);
+            pmeGpu->archSpecific->activeTimers.insert(PmeStage::FftTransformR2C);
         }
         if (settings.performGPUSolve)
         {
-            pmeGpu->archSpecific->activeTimers.insert(gtPME_SOLVE);
+            pmeGpu->archSpecific->activeTimers.insert(PmeStage::Solve);
         }
         if (settings.performGPUGather)
         {
-            pmeGpu->archSpecific->activeTimers.insert(gtPME_GATHER);
+            pmeGpu->archSpecific->activeTimers.insert(PmeStage::Gather);
         }
     }
 }
@@ -127,9 +125,9 @@ void pme_gpu_reset_timings(const PmeGpu* pmeGpu)
 {
     if (pme_gpu_timings_enabled(pmeGpu))
     {
-        for (size_t i = 0; i < pmeGpu->archSpecific->timingEvents.size(); i++)
+        for (auto key : keysOf(pmeGpu->archSpecific->timingEvents))
         {
-            pmeGpu->archSpecific->timingEvents[i].reset();
+            pmeGpu->archSpecific->timingEvents[key].reset();
         }
     }
 }
index f7c222b6b2ec7a32e57c13f4fe05522d28cc85e3..d57452215e120cc9045a329682063a1ee4529772 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 gmx_wallclock_gpu_pme_t;
 struct PmeGpu;
 
+enum class PmeStage : int;
+
 /*! \libinternal \brief
  * Starts timing the certain PME GPU stage during a single computation (if timings are enabled).
  *
  * \param[in] pmeGpu         The PME GPU data structure.
- * \param[in] PMEStageId     The PME GPU stage gtPME_ index from the enum in src/gromacs/timing/gpu_timing.h
+ * \param[in] pmeStageId     The PME GPU stage gtPME_ index from the enum in src/gromacs/timing/gpu_timing.h
  */
-void pme_gpu_start_timing(const PmeGpu* pmeGpu, size_t PMEStageId);
+void pme_gpu_start_timing(const PmeGpu* pmeGpu, PmeStage pmeStageId);
 
 /*! \libinternal \brief
  * Stops timing the certain PME GPU stage during a single computation (if timings are enabled).
  *
  * \param[in] pmeGpu         The PME GPU data structure.
- * \param[in] PMEStageId     The PME GPU stage gtPME_ index from the enum in src/gromacs/timing/gpu_timing.h
+ * \param[in] pmeStageId     The PME GPU stage gtPME_ index from the enum in src/gromacs/timing/gpu_timing.h
  */
-void pme_gpu_stop_timing(const PmeGpu* pmeGpu, size_t PMEStageId);
+void pme_gpu_stop_timing(const PmeGpu* pmeGpu, PmeStage pmeStageId);
 
 /*! \brief
  * Tells if CUDA-based performance tracking is enabled for PME.
index 4274f095d99619e642b4e6d423e161af180a51bc..e2c067390ad2c82f28d514e1951ba00d0a3595d9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -100,7 +100,7 @@ static_assert(sizeof(DeviceBuffer<int>) == 8,
  */
 struct PmeGpuConstParams
 {
-    /*! \brief Electrostatics coefficient = ONE_4PI_EPS0 / pme->epsilon_r */
+    /*! \brief Electrostatics coefficient = c_one4PiEps0 / pme->epsilon_r */
     float elFactor;
     /*! \brief Virial and energy GPU array. Size is c_virialAndEnergyCount (7) floats.
      * The element order is virxx, viryy, virzz, virxy, virxz, viryz, energy. */
@@ -171,7 +171,7 @@ struct PmeGpuAtomParams
      * The forces change and need to be copied from (and possibly to) the GPU for every PME
      * computation, but reallocation happens only at DD.
      */
-    HIDE_FROM_OPENCL_COMPILER(DeviceBuffer<float>) d_forces;
+    HIDE_FROM_OPENCL_COMPILER(DeviceBuffer<gmx::RVec>) d_forces;
     /*! \brief Global GPU memory array handle with ivec atom gridline indices.
      * Computed on GPU in the spline calculation part.
      */
index 26405433f53ab92397a24e24b8fb8a2a6db633be..055e61e5d8c0ec6bcb6a0389208e2cfb427b46f7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -78,7 +78,7 @@ typedef int PmeGpuSpecific;
 struct PmeGpuCudaKernelParams;
 /*! \brief A typedef for including the GPU kernel arguments data by pointer */
 typedef PmeGpuCudaKernelParams PmeGpuKernelParams;
-#elif GMX_GPU_OPENCL
+#elif GMX_GPU_OPENCL || GMX_GPU_SYCL
 struct PmeGpuKernelParamsBase;
 /*! \brief A typedef for including the GPU kernel arguments data by pointer */
 typedef PmeGpuKernelParamsBase PmeGpuKernelParams;
index cf98d701c54fe4f3c6fd9cd2f8eece9b03a0d31a..8204a9123f7ebe12c90e719dee55f6a52f30aab2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #define PMEGPUTYPESHOSTIMPL_H
 
 #include "config.h"
+#include "gromacs/utility/enumerationhelpers.h"
 
 #include <array>
 #include <set>
@@ -56,6 +57,9 @@
 #elif GMX_GPU_OPENCL
 #    include "gromacs/gpu_utils/gpueventsynchronizer_ocl.h"
 #    include "gromacs/gpu_utils/gpuregiontimer_ocl.h"
+#elif GMX_GPU_SYCL
+#    include "gromacs/gpu_utils/gpueventsynchronizer_sycl.h"
+#    include "gromacs/gpu_utils/gpuregiontimer_sycl.h"
 #endif
 
 #include "gromacs/timing/gpu_timing.h" // for gtPME_EVENT_COUNT
@@ -116,10 +120,10 @@ struct PmeGpuSpecific
     std::vector<std::unique_ptr<GpuParallel3dFft>> fftSetup;
 
     //! All the timers one might use
-    std::array<GpuRegionTimer, gtPME_EVENT_COUNT> timingEvents;
+    gmx::EnumerationArray<PmeStage, GpuRegionTimer> timingEvents;
 
     //! Indices of timingEvents actually used
-    std::set<size_t> activeTimers;
+    std::set<PmeStage> activeTimers;
 
     /* GPU arrays element counts (not the arrays sizes in bytes!).
      * They might be larger than the actual meaningful data sizes.
index 3d277d314666eb1d123aa07be7455d5a8b69fca0..3f3eb48c238518c9280bef29762cef993f179365 100644 (file)
@@ -108,8 +108,12 @@ void gmx_sum_qgrid_dd(gmx_pme_t* pme, real* grid, const int direction)
         /* Copy data to contiguous send buffer */
         if (debug)
         {
-            fprintf(debug, "PME send rank %d %d -> %d grid start %d Communicating %d to %d\n",
-                    pme->nodeid, overlap->nodeid, send_id, pme->pmegrid_start_iy,
+            fprintf(debug,
+                    "PME send rank %d %d -> %d grid start %d Communicating %d to %d\n",
+                    pme->nodeid,
+                    overlap->nodeid,
+                    send_id,
+                    pme->pmegrid_start_iy,
                     send_index0 - pme->pmegrid_start_iy,
                     send_index0 - pme->pmegrid_start_iy + send_nindex);
         }
@@ -131,15 +135,28 @@ void gmx_sum_qgrid_dd(gmx_pme_t* pme, real* grid, const int direction)
 
         datasize = pme->pmegrid_nx * pme->nkz;
 
-        MPI_Sendrecv(overlap->sendbuf.data(), send_nindex * datasize, GMX_MPI_REAL, send_id, ipulse,
-                     overlap->recvbuf.data(), recv_nindex * datasize, GMX_MPI_REAL, recv_id, ipulse,
-                     overlap->mpi_comm, &stat);
+        MPI_Sendrecv(overlap->sendbuf.data(),
+                     send_nindex * datasize,
+                     GMX_MPI_REAL,
+                     send_id,
+                     ipulse,
+                     overlap->recvbuf.data(),
+                     recv_nindex * datasize,
+                     GMX_MPI_REAL,
+                     recv_id,
+                     ipulse,
+                     overlap->mpi_comm,
+                     &stat);
 
         /* Get data from contiguous recv buffer */
         if (debug)
         {
-            fprintf(debug, "PME recv rank %d %d <- %d grid start %d Communicating %d to %d\n",
-                    pme->nodeid, overlap->nodeid, recv_id, pme->pmegrid_start_iy,
+            fprintf(debug,
+                    "PME recv rank %d %d <- %d grid start %d Communicating %d to %d\n",
+                    pme->nodeid,
+                    overlap->nodeid,
+                    recv_id,
+                    pme->pmegrid_start_iy,
                     recv_index0 - pme->pmegrid_start_iy,
                     recv_index0 - pme->pmegrid_start_iy + recv_nindex);
         }
@@ -203,18 +220,36 @@ void gmx_sum_qgrid_dd(gmx_pme_t* pme, real* grid, const int direction)
 
         if (debug)
         {
-            fprintf(debug, "PME send rank %d %d -> %d grid start %d Communicating %d to %d\n",
-                    pme->nodeid, overlap->nodeid, send_id, pme->pmegrid_start_ix,
+            fprintf(debug,
+                    "PME send rank %d %d -> %d grid start %d Communicating %d to %d\n",
+                    pme->nodeid,
+                    overlap->nodeid,
+                    send_id,
+                    pme->pmegrid_start_ix,
                     send_index0 - pme->pmegrid_start_ix,
                     send_index0 - pme->pmegrid_start_ix + send_nindex);
-            fprintf(debug, "PME recv rank %d %d <- %d grid start %d Communicating %d to %d\n",
-                    pme->nodeid, overlap->nodeid, recv_id, pme->pmegrid_start_ix,
+            fprintf(debug,
+                    "PME recv rank %d %d <- %d grid start %d Communicating %d to %d\n",
+                    pme->nodeid,
+                    overlap->nodeid,
+                    recv_id,
+                    pme->pmegrid_start_ix,
                     recv_index0 - pme->pmegrid_start_ix,
                     recv_index0 - pme->pmegrid_start_ix + recv_nindex);
         }
 
-        MPI_Sendrecv(sendptr, send_nindex * datasize, GMX_MPI_REAL, send_id, ipulse, recvptr,
-                     recv_nindex * datasize, GMX_MPI_REAL, recv_id, ipulse, overlap->mpi_comm, &stat);
+        MPI_Sendrecv(sendptr,
+                     send_nindex * datasize,
+                     GMX_MPI_REAL,
+                     send_id,
+                     ipulse,
+                     recvptr,
+                     recv_nindex * datasize,
+                     GMX_MPI_REAL,
+                     recv_id,
+                     ipulse,
+                     overlap->mpi_comm,
+                     &stat);
 
         /* ADD data from contiguous recv buffer */
         if (direction == GMX_SUM_GRID_FORWARD)
@@ -244,8 +279,8 @@ int copy_pmegrid_to_fftgrid(const gmx_pme_t* pme, const real* pmegrid, real* fft
     int  pmeidx, fftidx;
 
     /* Dimensions should be identical for A/B grid, so we just use A here */
-    gmx_parallel_3dfft_real_limits(pme->pfft_setup[grid_index], local_fft_ndata, local_fft_offset,
-                                   local_fft_size);
+    gmx_parallel_3dfft_real_limits(
+            pme->pfft_setup[grid_index], local_fft_ndata, local_fft_offset, local_fft_size);
 
     local_pme_size[0] = pme->pmegrid_nx;
     local_pme_size[1] = pme->pmegrid_ny;
@@ -280,14 +315,31 @@ int copy_pmegrid_to_fftgrid(const gmx_pme_t* pme, const real* pmegrid, real* fft
                     val = 100 * pmegrid[pmeidx];
                     if (pmegrid[pmeidx] != 0)
                     {
-                        gmx_fprintf_pdb_atomline(fp, epdbATOM, pmeidx, "CA", ' ', "GLY", ' ', pmeidx,
-                                                 ' ', 5.0 * ix, 5.0 * iy, 5.0 * iz, 1.0, val, "");
+                        gmx_fprintf_pdb_atomline(fp,
+                                                 epdbATOM,
+                                                 pmeidx,
+                                                 "CA",
+                                                 ' ',
+                                                 "GLY",
+                                                 ' ',
+                                                 pmeidx,
+                                                 ' ',
+                                                 5.0 * ix,
+                                                 5.0 * iy,
+                                                 5.0 * iz,
+                                                 1.0,
+                                                 val,
+                                                 "");
                     }
                     if (pmegrid[pmeidx] != 0)
                     {
-                        fprintf(fp2, "%-12s  %5d  %5d  %5d  %12.5e\n", "qgrid",
-                                pme->pmegrid_start_ix + ix, pme->pmegrid_start_iy + iy,
-                                pme->pmegrid_start_iz + iz, pmegrid[pmeidx]);
+                        fprintf(fp2,
+                                "%-12s  %5d  %5d  %5d  %12.5e\n",
+                                "qgrid",
+                                pme->pmegrid_start_ix + ix,
+                                pme->pmegrid_start_iy + iy,
+                                pme->pmegrid_start_iz + iz,
+                                pmegrid[pmeidx]);
                     }
 #endif
                 }
@@ -331,8 +383,8 @@ int copy_fftgrid_to_pmegrid(struct gmx_pme_t* pme, const real* fftgrid, real* pm
     c1 = omp_cyc_start();
 #endif
     /* Dimensions should be identical for A/B grid, so we just use A here */
-    gmx_parallel_3dfft_real_limits(pme->pfft_setup[grid_index], local_fft_ndata, local_fft_offset,
-                                   local_fft_size);
+    gmx_parallel_3dfft_real_limits(
+            pme->pfft_setup[grid_index], local_fft_ndata, local_fft_offset, local_fft_size);
 
     local_pme_size[0] = pme->pmegrid_nx;
     local_pme_size[1] = pme->pmegrid_ny;
@@ -630,7 +682,10 @@ static void make_subgrid_division(const ivec n, int ovl, int nthread, ivec nsub)
         gmx_fatal(FARGS,
                   "PME grid thread division (%d x %d x %d) does not match the total number of "
                   "threads (%d)",
-                  nsub[XX], nsub[YY], nsub[ZZ], nthread);
+                  nsub[XX],
+                  nsub[YY],
+                  nsub[ZZ],
+                  nthread);
     }
 }
 
@@ -675,17 +730,20 @@ void pmegrids_init(pmegrids_t* grids,
 
         if (debug)
         {
-            fprintf(debug, "pmegrid thread local division: %d x %d x %d\n", grids->nc[XX],
-                    grids->nc[YY], grids->nc[ZZ]);
-            fprintf(debug, "pmegrid %d %d %d max thread pmegrid %d %d %d\n", nx, ny, nz, nst[XX],
-                    nst[YY], nst[ZZ]);
+            fprintf(debug,
+                    "pmegrid thread local division: %d x %d x %d\n",
+                    grids->nc[XX],
+                    grids->nc[YY],
+                    grids->nc[ZZ]);
+            fprintf(debug, "pmegrid %d %d %d max thread pmegrid %d %d %d\n", nx, ny, nz, nst[XX], nst[YY], nst[ZZ]);
         }
 
         snew(grids->grid_th, grids->nthread);
         t        = 0;
         gridsize = nst[XX] * nst[YY] * nst[ZZ];
         set_gridsize_alignment(&gridsize, pme_order);
-        snew_aligned(grids->grid_all, grids->nthread * gridsize + (grids->nthread + 1) * GMX_CACHE_SEP,
+        snew_aligned(grids->grid_all,
+                     grids->nthread * gridsize + (grids->nthread + 1) * GMX_CACHE_SEP,
                      SIMD4_ALIGNMENT);
 
         for (x = 0; x < grids->nc[XX]; x++)
@@ -694,10 +752,18 @@ void pmegrids_init(pmegrids_t* grids,
             {
                 for (z = 0; z < grids->nc[ZZ]; z++)
                 {
-                    pmegrid_init(&grids->grid_th[t], x, y, z, (n[XX] * (x)) / grids->nc[XX],
-                                 (n[YY] * (y)) / grids->nc[YY], (n[ZZ] * (z)) / grids->nc[ZZ],
-                                 (n[XX] * (x + 1)) / grids->nc[XX], (n[YY] * (y + 1)) / grids->nc[YY],
-                                 (n[ZZ] * (z + 1)) / grids->nc[ZZ], TRUE, pme_order,
+                    pmegrid_init(&grids->grid_th[t],
+                                 x,
+                                 y,
+                                 z,
+                                 (n[XX] * (x)) / grids->nc[XX],
+                                 (n[YY] * (y)) / grids->nc[YY],
+                                 (n[ZZ] * (z)) / grids->nc[ZZ],
+                                 (n[XX] * (x + 1)) / grids->nc[XX],
+                                 (n[YY] * (y + 1)) / grids->nc[YY],
+                                 (n[ZZ] * (z + 1)) / grids->nc[ZZ],
+                                 TRUE,
+                                 pme_order,
                                  grids->grid_all + GMX_CACHE_SEP + t * (gridsize + GMX_CACHE_SEP));
                     t++;
                 }
@@ -742,7 +808,9 @@ void pmegrids_init(pmegrids_t* grids,
         }
         if (debug != nullptr)
         {
-            fprintf(debug, "pmegrid thread grid communication range in %c: %d\n", 'x' + d,
+            fprintf(debug,
+                    "pmegrid thread grid communication range in %c: %d\n",
+                    'x' + d,
                     grids->nthread_comm[d]);
         }
         /* It should be possible to make grids->nthread_comm[d]==grids->nc[d]
index a4af8154de90709f18f06827d9135ec8c5eb1495..c97f9e2948460c11c51c1ac2d70349ffa53112a1 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +76,7 @@ struct t_inputrec;
 struct PmeGpu;
 
 enum class PmeRunMode;
+enum class LongRangeVdW : int;
 
 //@{
 //! Grid indices for A state for charge and Lennard-Jones C6
@@ -357,7 +358,7 @@ struct gmx_pme_t
     class EwaldBoxZScaler* boxScaler; /**< The scaling data Ewald uses with walls (set at pme_init constant for the entire run) */
 
 
-    int ljpme_combination_rule; /* Type of combination rule in LJ-PME */
+    LongRangeVdW ljpme_combination_rule; /* Type of combination rule in LJ-PME */
 
     int ngrids; /* number of grids we maintain for pmegrid, (c)fftgrid and pfft_setups*/
 
index 542c730156912408abe24c004ffb4ec1b242c431..f554e43827c1e4e2eb6a2de614a3bfafdd76460d 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "gmxpre.h"
 
+#include "gromacs/utility/enumerationhelpers.h"
 #include "pme_load_balancing.h"
 
 #include <cassert>
@@ -142,20 +143,28 @@ const int c_numPostSwitchTuningIntervalSkip = 1;
 const double c_startupTimeDelay = 5.0;
 
 /*! \brief Enumeration whose values describe the effect limiting the load balancing */
-enum epmelb
+enum class PmeLoadBalancingLimit : int
 {
-    epmelblimNO,
-    epmelblimBOX,
-    epmelblimDD,
-    epmelblimPMEGRID,
-    epmelblimMAXSCALING,
-    epmelblimNR
+    No,
+    Box,
+    DD,
+    PmeGrid,
+    MaxScaling,
+    Count
 };
 
-/*! \brief Descriptive strings matching ::epmelb */
-static const char* pmelblim_str[epmelblimNR] = { "no", "box size", "domain decompostion",
-                                                 "PME grid restriction",
-                                                 "maximum allowed grid scaling" };
+/*! \brief Descriptive strings for PmeLoadBalancingLimit \c enumValue */
+static const char* enumValueToString(PmeLoadBalancingLimit enumValue)
+{
+    constexpr gmx::EnumerationArray<PmeLoadBalancingLimit, const char*> pmeLoadBalancingLimitNames = {
+        "no",
+        "box size",
+        "domain decompostion",
+        "PME grid restriction",
+        "maximum allowed grid scaling"
+    };
+    return pmeLoadBalancingLimitNames[enumValue];
+}
 
 struct pme_load_balancing_t
 {
@@ -181,8 +190,8 @@ struct pme_load_balancing_t
     int                      lower_limit;        /**< don't go below this setup index */
     int                      start;    /**< start of setup index range to consider in stage>0 */
     int                      end;      /**< end   of setup index range to consider in stage>0 */
-    int                      elimited; /**< was the balancing limited, uses enum above */
-    int                      cutoff_scheme; /**< Verlet or group cut-offs */
+    PmeLoadBalancingLimit    elimited; /**< was the balancing limited, uses enum above */
+    CutoffScheme             cutoff_scheme; /**< Verlet or group cut-offs */
 
     int stage; /**< the current stage */
 
@@ -262,8 +271,7 @@ void pme_loadbal_init(pme_load_balancing_t**     pme_lb_p,
 
     if (!pme_lb->bSepPMERanks)
     {
-        GMX_RELEASE_ASSERT(pmedata,
-                           "On ranks doing both PP and PME we need a valid pmedata object");
+        GMX_RELEASE_ASSERT(pmedata, "On ranks doing both PP and PME we need a valid pmedata object");
         pme_lb->setup[0].pmedata = pmedata;
     }
 
@@ -293,7 +301,7 @@ void pme_loadbal_init(pme_load_balancing_t**     pme_lb_p,
     pme_lb->lower_limit = 0;
     pme_lb->start       = 0;
     pme_lb->end         = 0;
-    pme_lb->elimited    = epmelblimNO;
+    pme_lb->elimited    = PmeLoadBalancingLimit::No;
 
     pme_lb->cycles_n = 0;
     pme_lb->cycles_c = 0;
@@ -377,16 +385,21 @@ static gmx_bool pme_loadbal_increase_cutoff(pme_load_balancing_t* pme_lb, int pm
 
         fac *= 1.01;
         clear_ivec(set.grid);
-        sp = calcFftGrid(nullptr, pme_lb->box_start, fac * pme_lb->setup[pme_lb->cur].spacing,
-                         minimalPmeGridSize(pme_order), &set.grid[XX], &set.grid[YY], &set.grid[ZZ]);
+        sp = calcFftGrid(nullptr,
+                         pme_lb->box_start,
+                         fac * pme_lb->setup[pme_lb->cur].spacing,
+                         minimalPmeGridSize(pme_order),
+                         &set.grid[XX],
+                         &set.grid[YY],
+                         &set.grid[ZZ]);
 
         /* As here we can't easily check if one of the PME ranks
          * uses threading, we do a conservative grid check.
          * This means we can't use pme_order or less grid lines
          * per PME rank along x, which is not a strong restriction.
          */
-        grid_ok = gmx_pme_check_restrictions(pme_order, set.grid[XX], set.grid[YY], set.grid[ZZ],
-                                             numPmeDomains.x, true, false);
+        grid_ok = gmx_pme_check_restrictions(
+                pme_order, set.grid[XX], set.grid[YY], set.grid[ZZ], numPmeDomains.x, true, false);
     } while (sp <= 1.001 * pme_lb->setup[pme_lb->cur].spacing || !grid_ok);
 
     set.rcut_coulomb = pme_lb->cut_spacing * sp;
@@ -400,7 +413,7 @@ static gmx_bool pme_loadbal_increase_cutoff(pme_load_balancing_t* pme_lb, int pm
         set.rcut_coulomb = pme_lb->rcut_coulomb_start;
     }
 
-    if (pme_lb->cutoff_scheme == ecutsVERLET)
+    if (pme_lb->cutoff_scheme == CutoffScheme::Verlet)
     {
         /* Never decrease the Coulomb and VdW list buffers */
         set.rlistOuter = std::max(set.rcut_coulomb + pme_lb->rbufOuter_coulomb,
@@ -438,8 +451,12 @@ static gmx_bool pme_loadbal_increase_cutoff(pme_load_balancing_t* pme_lb, int pm
 
     if (debug)
     {
-        fprintf(debug, "PME loadbal: grid %d %d %d, coulomb cutoff %f\n", set.grid[XX],
-                set.grid[YY], set.grid[ZZ], set.rcut_coulomb);
+        fprintf(debug,
+                "PME loadbal: grid %d %d %d, coulomb cutoff %f\n",
+                set.grid[XX],
+                set.grid[YY],
+                set.grid[ZZ],
+                set.rcut_coulomb);
     }
     pme_lb->setup.push_back(set);
     return TRUE;
@@ -448,8 +465,13 @@ static gmx_bool pme_loadbal_increase_cutoff(pme_load_balancing_t* pme_lb, int pm
 /*! \brief Print the PME grid */
 static void print_grid(FILE* fp_err, FILE* fp_log, const char* pre, const char* desc, const pme_setup_t* set, double cycles)
 {
-    auto buf = gmx::formatString("%-11s%10s pme grid %d %d %d, coulomb cutoff %.3f", pre, desc,
-                                 set->grid[XX], set->grid[YY], set->grid[ZZ], set->rcut_coulomb);
+    auto buf = gmx::formatString("%-11s%10s pme grid %d %d %d, coulomb cutoff %.3f",
+                                 pre,
+                                 desc,
+                                 set->grid[XX],
+                                 set->grid[YY],
+                                 set->grid[ZZ],
+                                 set->rcut_coulomb);
     if (cycles >= 0)
     {
         buf += gmx::formatString(": %.1f M-cycles", cycles * 1e-6);
@@ -484,7 +506,8 @@ static void print_loadbal_limited(FILE* fp_err, FILE* fp_log, int64_t step, pme_
 {
     auto buf = gmx::formatString(
             "step %4s: the %s limits the PME load balancing to a coulomb cut-off of %.3f",
-            gmx::int64ToString(step).c_str(), pmelblim_str[pme_lb->elimited],
+            gmx::int64ToString(step).c_str(),
+            enumValueToString(pme_lb->elimited),
             pme_lb->setup[pme_loadbal_end(pme_lb) - 1].rcut_coulomb);
     if (fp_err != nullptr)
     {
@@ -612,8 +635,13 @@ static void pme_load_balance(pme_load_balancing_t*          pme_lb,
                         "is more than %f\n"
                         "Increased the number stages to %d"
                         " and ignoring the previous performance\n",
-                        set->grid[XX], set->grid[YY], set->grid[ZZ], set->cycles * 1e-6,
-                        cycles * 1e-6, maxFluctuationAccepted, pme_lb->nstage);
+                        set->grid[XX],
+                        set->grid[YY],
+                        set->grid[ZZ],
+                        set->cycles * 1e-6,
+                        cycles * 1e-6,
+                        maxFluctuationAccepted,
+                        pme_lb->nstage);
             }
         }
         set->cycles = std::min(set->cycles, cycles);
@@ -673,7 +701,7 @@ static void pme_load_balance(pme_load_balancing_t*          pme_lb,
 
                 if (!OK)
                 {
-                    pme_lb->elimited = epmelblimPMEGRID;
+                    pme_lb->elimited = PmeLoadBalancingLimit::PmeGrid;
                 }
             }
 
@@ -681,7 +709,7 @@ static void pme_load_balance(pme_load_balancing_t*          pme_lb,
                 && pme_lb->setup[pme_lb->cur + 1].spacing > c_maxSpacingScaling * pme_lb->setup[0].spacing)
             {
                 OK               = FALSE;
-                pme_lb->elimited = epmelblimMAXSCALING;
+                pme_lb->elimited = PmeLoadBalancingLimit::MaxScaling;
             }
 
             if (OK && ir.pbcType != PbcType::No)
@@ -690,7 +718,7 @@ static void pme_load_balance(pme_load_balancing_t*          pme_lb,
                       <= max_cutoff2(ir.pbcType, box));
                 if (!OK)
                 {
-                    pme_lb->elimited = epmelblimBOX;
+                    pme_lb->elimited = PmeLoadBalancingLimit::Box;
                 }
             }
 
@@ -705,7 +733,7 @@ static void pme_load_balance(pme_load_balancing_t*          pme_lb,
                     {
                         /* Failed: do not use this setup */
                         pme_lb->cur--;
-                        pme_lb->elimited = epmelblimDD;
+                        pme_lb->elimited = PmeLoadBalancingLimit::DD;
                     }
                 }
             }
@@ -797,7 +825,7 @@ static void pme_load_balance(pme_load_balancing_t*          pme_lb,
             /* Limit the range to below the current cut-off, scan from start */
             pme_lb->end      = pme_lb->cur;
             pme_lb->cur      = pme_lb->start;
-            pme_lb->elimited = epmelblimDD;
+            pme_lb->elimited = PmeLoadBalancingLimit::DD;
             print_loadbal_limited(fp_err, fp_log, step, pme_lb);
         }
     }
@@ -810,7 +838,7 @@ static void pme_load_balance(pme_load_balancing_t*          pme_lb,
     nbv->changePairlistRadii(set->rlistOuter, set->rlistInner);
     ic->ewaldcoeff_q = set->ewaldcoeff_q;
     /* TODO: centralize the code that sets the potentials shifts */
-    if (ic->coulomb_modifier == eintmodPOTSHIFT)
+    if (ic->coulomb_modifier == InteractionModifiers::PotShift)
     {
         GMX_RELEASE_ASSERT(ic->rcoulomb != 0, "Cutoff radius cannot be zero");
         ic->sh_ewald = std::erfc(ic->ewaldcoeff_q * ic->rcoulomb) / ic->rcoulomb;
@@ -820,7 +848,7 @@ static void pme_load_balance(pme_load_balancing_t*          pme_lb,
         /* We have PME for both Coulomb and VdW, set rvdw equal to rcoulomb */
         ic->rvdw          = set->rcut_coulomb;
         ic->ewaldcoeff_lj = set->ewaldcoeff_lj;
-        if (ic->vdw_modifier == eintmodPOTSHIFT)
+        if (ic->vdw_modifier == InteractionModifiers::PotShift)
         {
             real crc2;
 
@@ -835,7 +863,7 @@ static void pme_load_balance(pme_load_balancing_t*          pme_lb,
     /* We always re-initialize the tables whether they are used or not */
     init_interaction_const_tables(nullptr, ic, set->rlistOuter, ir.tabext);
 
-    Nbnxm::gpu_pme_loadbal_update_param(nbv, ic);
+    Nbnxm::gpu_pme_loadbal_update_param(nbv, *ic);
 
     if (!pme_lb->bSepPMERanks)
     {
@@ -852,8 +880,8 @@ static void pme_load_balance(pme_load_balancing_t*          pme_lb,
             /* Generate a new PME data structure,
              * copying part of the old pointers.
              */
-            gmx_pme_reinit(&set->pmedata, cr, pme_lb->setup[0].pmedata, &ir, set->grid,
-                           set->ewaldcoeff_q, set->ewaldcoeff_lj);
+            gmx_pme_reinit(
+                    &set->pmedata, cr, pme_lb->setup[0].pmedata, &ir, set->grid, set->ewaldcoeff_q, set->ewaldcoeff_lj);
         }
         *pmedata = set->pmedata;
     }
@@ -907,7 +935,7 @@ void pme_loadbal_do(pme_load_balancing_t*          pme_lb,
                     t_forcerec*                    fr,
                     const matrix                   box,
                     gmx::ArrayRef<const gmx::RVec> x,
-                    gmx_wallcycle_t                wcycle,
+                    gmx_wallcycle                wcycle,
                     int64_t                        step,
                     int64_t                        step_rel,
                     gmx_bool*                      bPrinting,
@@ -925,7 +953,7 @@ void pme_loadbal_do(pme_load_balancing_t*          pme_lb,
 
     n_prev      = pme_lb->cycles_n;
     cycles_prev = pme_lb->cycles_c;
-    wallcycle_get(wcycle, ewcSTEP, &pme_lb->cycles_n, &pme_lb->cycles_c);
+    wallcycle_get(wcycle, WallCycleCounter::Step, &pme_lb->cycles_n, &pme_lb->cycles_c);
 
     /* Before the first step we haven't done any steps yet.
      * Also handle cases where ir.init_step % ir.nstlist != 0.
@@ -1037,13 +1065,24 @@ void pme_loadbal_do(pme_load_balancing_t*          pme_lb,
          * since init_step might not be a multiple of nstlist,
          * but the first data collected is skipped anyhow.
          */
-        pme_load_balance(pme_lb, cr, fp_err, fp_log, mdlog, ir, box, x,
-                         pme_lb->cycles_c - cycles_prev, fr->ic, fr->nbv.get(), &fr->pmedata, step);
+        pme_load_balance(pme_lb,
+                         cr,
+                         fp_err,
+                         fp_log,
+                         mdlog,
+                         ir,
+                         box,
+                         x,
+                         pme_lb->cycles_c - cycles_prev,
+                         fr->ic.get(),
+                         fr->nbv.get(),
+                         &fr->pmedata,
+                         step);
 
         /* Update deprecated rlist in forcerec to stay in sync with fr->nbv */
         fr->rlist = fr->nbv->pairlistOuterRadius();
 
-        if (ir.eDispCorr != edispcNO)
+        if (ir.eDispCorr != DispersionCorrectionType::No)
         {
             fr->dispersionCorrection->setParameters(*fr->ic);
         }
@@ -1078,9 +1117,16 @@ static int pme_grid_points(const pme_setup_t* setup)
 /*! \brief Print one load-balancing setting */
 static void print_pme_loadbal_setting(FILE* fplog, const char* name, const pme_setup_t* setup)
 {
-    fprintf(fplog, "   %-7s %6.3f nm %6.3f nm     %3d %3d %3d   %5.3f nm  %5.3f nm\n", name,
-            setup->rcut_coulomb, setup->rlistInner, setup->grid[XX], setup->grid[YY],
-            setup->grid[ZZ], setup->spacing, 1 / setup->ewaldcoeff_q);
+    fprintf(fplog,
+            "   %-7s %6.3f nm %6.3f nm     %3d %3d %3d   %5.3f nm  %5.3f nm\n",
+            name,
+            setup->rcut_coulomb,
+            setup->rlistInner,
+            setup->grid[XX],
+            setup->grid[YY],
+            setup->grid[ZZ],
+            setup->spacing,
+            1 / setup->ewaldcoeff_q);
 }
 
 /*! \brief Print all load-balancing settings */
@@ -1101,12 +1147,13 @@ static void print_pme_loadbal_settings(pme_load_balancing_t* pme_lb,
     fprintf(fplog, "       P P   -   P M E   L O A D   B A L A N C I N G\n");
     fprintf(fplog, "\n");
     /* Here we only warn when the optimal setting is the last one */
-    if (pme_lb->elimited != epmelblimNO && pme_lb->cur == pme_loadbal_end(pme_lb) - 1)
+    if (pme_lb->elimited != PmeLoadBalancingLimit::No && pme_lb->cur == pme_loadbal_end(pme_lb) - 1)
     {
-        fprintf(fplog, " NOTE: The PP/PME load balancing was limited by the %s,\n",
-                pmelblim_str[pme_lb->elimited]);
+        fprintf(fplog,
+                " NOTE: The PP/PME load balancing was limited by the %s,\n",
+                enumValueToString(pme_lb->elimited));
         fprintf(fplog, "       you might not have reached a good load balance.\n");
-        if (pme_lb->elimited == epmelblimDD)
+        if (pme_lb->elimited == PmeLoadBalancingLimit::DD)
         {
             fprintf(fplog, "       Try different mdrun -dd settings or lower the -dds value.\n");
         }
@@ -1139,7 +1186,7 @@ static void print_pme_loadbal_settings(pme_load_balancing_t* pme_lb,
 
 void pme_loadbal_done(pme_load_balancing_t* pme_lb, FILE* fplog, const gmx::MDLogger& mdlog, gmx_bool bNonBondedOnGPU)
 {
-    if (fplog != nullptr && (pme_lb->cur > 0 || pme_lb->elimited != epmelblimNO))
+    if (fplog != nullptr && (pme_lb->cur > 0 || pme_lb->elimited != PmeLoadBalancingLimit::No))
     {
         print_pme_loadbal_settings(pme_lb, fplog, mdlog, bNonBondedOnGPU);
     }
index bb98635ca239238b9fd262317641f5508dc15d22..38ba5c74e64674ac4ef06d9a9dc7055dad260463 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -92,7 +92,7 @@ void pme_loadbal_init(pme_load_balancing_t**     pme_lb_p,
  *
  * Process the cycles measured over the last nstlist steps and then
  * either continue balancing or check if we need to trigger balancing.
- * Should be called after the ewcSTEP cycle counter has been stopped.
+ * Should be called after the WallCycleCounter::Step cycle counter has been stopped.
  * Returns if the load balancing is printing to fp_err.
  */
 void pme_loadbal_do(pme_load_balancing_t*          pme_lb,
@@ -104,7 +104,7 @@ void pme_loadbal_do(pme_load_balancing_t*          pme_lb,
                     t_forcerec*                    fr,
                     const matrix                   box,
                     gmx::ArrayRef<const gmx::RVec> x,
-                    gmx_wallcycle_t                wcycle,
+                    gmx_wallcycle                wcycle,
                     int64_t                        step,
                     int64_t                        step_rel,
                     gmx_bool*                      bPrinting,
index de9386f63979df36dce8bf7f62fe8149c5739180..82d6574866a5223cc74b44a31ae53313c805c671 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "pme_output.h"
 #include "pme_pp_communication.h"
 
-/*! \brief environment variable to enable GPU P2P communication */
-static const bool c_enableGpuPmePpComms =
-        GMX_GPU_CUDA && GMX_THREAD_MPI && (getenv("GMX_GPU_PME_PP_COMMS") != nullptr);
-
 /*! \brief Master PP-PME communication data structure */
 struct gmx_pme_pp
 {
@@ -167,17 +163,17 @@ static std::unique_ptr<gmx_pme_pp> gmx_pme_pp_init(const t_commrec* cr)
     return pme_pp;
 }
 
-static void reset_pmeonly_counters(gmx_wallcycle_t           wcycle,
+static void reset_pmeonly_counters(gmx_wallcycle           wcycle,
                                    gmx_walltime_accounting_t walltime_accounting,
                                    t_nrnb*                   nrnb,
                                    int64_t                   step,
                                    bool                      useGpuForPme)
 {
     /* Reset all the counters related to performance over the run */
-    wallcycle_stop(wcycle, ewcRUN);
+    wallcycle_stop(wcycle, WallCycleCounter::Run);
     wallcycle_reset_all(wcycle);
     *nrnb = { 0 };
-    wallcycle_start(wcycle, ewcRUN);
+    wallcycle_start(wcycle, WallCycleCounter::Run);
     walltime_accounting_reset_time(walltime_accounting, step);
 
     if (useGpuForPme)
@@ -274,8 +270,7 @@ static int gmx_pme_recv_coeffs_coords(struct gmx_pme_t*            pme,
         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->peerRankId, eCommType_CNB,
-                 pme_pp->mpi_comm_mysim, MPI_STATUS_IGNORE);
+        MPI_Recv(&cnb, sizeof(cnb), MPI_BYTE, pme_pp->peerRankId, eCommType_CNB, pme_pp->mpi_comm_mysim, MPI_STATUS_IGNORE);
 
         /* We accumulate all received flags */
         flags |= cnb.flags;
@@ -284,7 +279,8 @@ static int gmx_pme_recv_coeffs_coords(struct gmx_pme_t*            pme,
 
         if (debug)
         {
-            fprintf(debug, "PME only rank receiving:%s%s%s%s%s\n",
+            fprintf(debug,
+                    "PME only rank receiving:%s%s%s%s%s\n",
                     (cnb.flags & PP_PME_CHARGE) ? " charges" : "",
                     (cnb.flags & PP_PME_COORD) ? " coordinates" : "",
                     (cnb.flags & PP_PME_FINISH) ? " finish" : "",
@@ -331,8 +327,13 @@ static int gmx_pme_recv_coeffs_coords(struct gmx_pme_t*            pme,
                 }
                 else
                 {
-                    MPI_Irecv(&sender.numAtoms, sizeof(sender.numAtoms), MPI_BYTE, sender.rankId,
-                              eCommType_CNB, pme_pp->mpi_comm_mysim, &pme_pp->req[messages++]);
+                    MPI_Irecv(&sender.numAtoms,
+                              sizeof(sender.numAtoms),
+                              MPI_BYTE,
+                              sender.rankId,
+                              eCommType_CNB,
+                              pme_pp->mpi_comm_mysim,
+                              &pme_pp->req[messages++]);
                 }
             }
             MPI_Waitall(messages, pme_pp->req.data(), pme_pp->stat.data());
@@ -399,12 +400,19 @@ static int gmx_pme_recv_coeffs_coords(struct gmx_pme_t*            pme,
                 {
                     if (sender.numAtoms > 0)
                     {
-                        MPI_Irecv(bufferPtr + nat, sender.numAtoms * sizeof(real), MPI_BYTE,
-                                  sender.rankId, q, pme_pp->mpi_comm_mysim, &pme_pp->req[messages++]);
+                        MPI_Irecv(bufferPtr + nat,
+                                  sender.numAtoms * sizeof(real),
+                                  MPI_BYTE,
+                                  sender.rankId,
+                                  q,
+                                  pme_pp->mpi_comm_mysim,
+                                  &pme_pp->req[messages++]);
                         nat += sender.numAtoms;
                         if (debug)
                         {
-                            fprintf(debug, "Received from PP rank %d: %d %s\n", sender.rankId,
+                            fprintf(debug,
+                                    "Received from PP rank %d: %d %s\n",
+                                    sender.rankId,
                                     sender.numAtoms,
                                     (q == eCommType_ChargeA || q == eCommType_ChargeB) ? "charges"
                                                                                        : "params");
@@ -418,7 +426,7 @@ static int gmx_pme_recv_coeffs_coords(struct gmx_pme_t*            pme,
         {
             if (atomSetChanged)
             {
-                gmx_pme_reinit_atoms(pme, nat, pme_pp->chargeA.data(), pme_pp->chargeB.data());
+                gmx_pme_reinit_atoms(pme, nat, pme_pp->chargeA, pme_pp->chargeB);
                 if (useGpuForPme)
                 {
                     stateGpu->reinit(nat, nat);
@@ -433,8 +441,7 @@ static int gmx_pme_recv_coeffs_coords(struct gmx_pme_t*            pme,
                     // This rank will have its data accessed directly by PP rank, so needs to send the remote addresses.
                     pme_pp->pmeCoordinateReceiverGpu->sendCoordinateBufferAddressToPpRanks(
                             stateGpu->getCoordinates());
-                    pme_pp->pmeForceSenderGpu->sendForceBufferAddressToPpRanks(
-                            reinterpret_cast<rvec*>(pme_gpu_get_device_f(pme)));
+                    pme_pp->pmeForceSenderGpu->sendForceBufferAddressToPpRanks(pme_gpu_get_device_f(pme));
                 }
             }
 
@@ -455,13 +462,26 @@ static int gmx_pme_recv_coeffs_coords(struct gmx_pme_t*            pme,
                 {
                     if (pme_pp->useGpuDirectComm)
                     {
-                        pme_pp->pmeCoordinateReceiverGpu->launchReceiveCoordinatesFromPpCudaDirect(
-                                sender.rankId);
+                        if (GMX_THREAD_MPI)
+                        {
+                            pme_pp->pmeCoordinateReceiverGpu->receiveCoordinatesSynchronizerFromPpCudaDirect(
+                                    sender.rankId);
+                        }
+                        else
+                        {
+                            pme_pp->pmeCoordinateReceiverGpu->launchReceiveCoordinatesFromPpCudaMpi(
+                                    stateGpu->getCoordinates(), nat, sender.numAtoms * sizeof(rvec), sender.rankId);
+                        }
                     }
                     else
                     {
-                        MPI_Irecv(pme_pp->x[nat], sender.numAtoms * sizeof(rvec), MPI_BYTE, sender.rankId,
-                                  eCommType_COORD, pme_pp->mpi_comm_mysim, &pme_pp->req[messages++]);
+                        MPI_Irecv(pme_pp->x[nat],
+                                  sender.numAtoms * sizeof(rvec),
+                                  MPI_BYTE,
+                                  sender.rankId,
+                                  eCommType_COORD,
+                                  pme_pp->mpi_comm_mysim,
+                                  &pme_pp->req[messages++]);
                     }
                     nat += sender.numAtoms;
                     if (debug)
@@ -469,14 +489,15 @@ static int gmx_pme_recv_coeffs_coords(struct gmx_pme_t*            pme,
                         fprintf(debug,
                                 "Received from PP rank %d: %d "
                                 "coordinates\n",
-                                sender.rankId, sender.numAtoms);
+                                sender.rankId,
+                                sender.numAtoms);
                     }
                 }
             }
 
             if (pme_pp->useGpuDirectComm)
             {
-                pme_pp->pmeCoordinateReceiverGpu->enqueueWaitReceiveCoordinatesFromPpCudaDirect();
+                pme_pp->pmeCoordinateReceiverGpu->synchronizeOnCoordinatesFromPpRanks();
             }
 
             status = pmerecvqxX;
@@ -513,29 +534,6 @@ static int gmx_pme_recv_coeffs_coords(struct gmx_pme_t*            pme,
     return status;
 }
 
-#if GMX_MPI
-/*! \brief Send force data to PP ranks */
-static void sendFToPP(void* sendbuf, PpRanks receiver, gmx_pme_pp* pme_pp, int* messages)
-{
-
-    if (pme_pp->useGpuDirectComm)
-    {
-        GMX_ASSERT((pme_pp->pmeForceSenderGpu != nullptr),
-                   "The use of GPU direct communication for PME-PP is enabled, "
-                   "but the PME GPU force reciever object does not exist");
-
-        pme_pp->pmeForceSenderGpu->sendFToPpCudaDirect(receiver.rankId);
-    }
-    else
-    {
-        // Send using MPI
-        MPI_Isend(sendbuf, receiver.numAtoms * sizeof(rvec), MPI_BYTE, receiver.rankId, 0,
-                  pme_pp->mpi_comm_mysim, &pme_pp->req[*messages]);
-        *messages = *messages + 1;
-    }
-}
-#endif
-
 /*! \brief Send the PME mesh force, virial and energy to the PP-only ranks. */
 static void gmx_pme_send_force_vir_ener(const gmx_pme_t& pme,
                                         gmx_pme_pp*      pme_pp,
@@ -554,16 +552,42 @@ static void gmx_pme_send_force_vir_ener(const gmx_pme_t& pme,
     ind_end  = 0;
     for (const auto& receiver : pme_pp->ppRanks)
     {
-        ind_start     = ind_end;
-        ind_end       = ind_start + receiver.numAtoms;
-        void* sendbuf = const_cast<void*>(static_cast<const void*>(output.forces_[ind_start]));
+        ind_start = ind_end;
+        ind_end   = ind_start + receiver.numAtoms;
         if (pme_pp->useGpuDirectComm)
         {
-            // Data will be transferred directly from GPU.
-            rvec* d_f = reinterpret_cast<rvec*>(pme_gpu_get_device_f(&pme));
-            sendbuf   = reinterpret_cast<void*>(&d_f[ind_start]);
+            GMX_ASSERT((pme_pp->pmeForceSenderGpu != nullptr),
+                       "The use of GPU direct communication for PME-PP is enabled, "
+                       "but the PME GPU force reciever object does not exist");
+
+            if (GMX_THREAD_MPI)
+            {
+                pme_pp->pmeForceSenderGpu->sendFSynchronizerToPpCudaDirect(receiver.rankId);
+            }
+            else
+            {
+                pme_pp->pmeForceSenderGpu->sendFToPpCudaMpi(pme_gpu_get_device_f(&pme),
+                                                            ind_start,
+                                                            receiver.numAtoms * sizeof(rvec),
+                                                            receiver.rankId,
+                                                            &pme_pp->req[messages]);
+
+                messages++;
+            }
+        }
+        else
+        {
+            void* sendbuf = const_cast<void*>(static_cast<const void*>(output.forces_[ind_start]));
+            // Send using MPI
+            MPI_Isend(sendbuf,
+                      receiver.numAtoms * sizeof(rvec),
+                      MPI_BYTE,
+                      receiver.rankId,
+                      0,
+                      pme_pp->mpi_comm_mysim,
+                      &pme_pp->req[messages]);
+            messages++;
         }
-        sendFToPP(sendbuf, receiver, pme_pp, &messages);
     }
 
     /* send virial and energy to our last PP node */
@@ -582,8 +606,7 @@ static void gmx_pme_send_force_vir_ener(const gmx_pme_t& pme,
     {
         fprintf(debug, "PME rank sending to PP rank %d: virial and energy\n", pme_pp->peerRankId);
     }
-    MPI_Isend(&cve, sizeof(cve), MPI_BYTE, pme_pp->peerRankId, 1, pme_pp->mpi_comm_mysim,
-              &pme_pp->req[messages++]);
+    MPI_Isend(&cve, sizeof(cve), MPI_BYTE, pme_pp->peerRankId, 1, pme_pp->mpi_comm_mysim, &pme_pp->req[messages++]);
 
     /* Wait for the forces to arrive */
     MPI_Waitall(messages, pme_pp->req.data(), pme_pp->stat.data());
@@ -605,6 +628,7 @@ int gmx_pmeonly(struct gmx_pme_t*               pme,
                 gmx_walltime_accounting_t       walltime_accounting,
                 t_inputrec*                     ir,
                 PmeRunMode                      runMode,
+                bool                            useGpuPmePpCommunication,
                 const gmx::DeviceStreamManager* deviceStreamManager)
 {
     int     ret;
@@ -637,20 +661,23 @@ int gmx_pmeonly(struct gmx_pme_t*               pme,
                            "Device stream can not be nullptr when using GPU in PME-only rank");
         changePinningPolicy(&pme_pp->chargeA, pme_get_pinning_policy());
         changePinningPolicy(&pme_pp->x, pme_get_pinning_policy());
-        if (c_enableGpuPmePpComms)
+        if (useGpuPmePpCommunication)
         {
             pme_pp->pmeCoordinateReceiverGpu = std::make_unique<gmx::PmeCoordinateReceiverGpu>(
-                    deviceStreamManager->stream(gmx::DeviceStreamType::Pme), pme_pp->mpi_comm_mysim,
+                    deviceStreamManager->stream(gmx::DeviceStreamType::Pme),
+                    pme_pp->mpi_comm_mysim,
                     pme_pp->ppRanks);
             pme_pp->pmeForceSenderGpu = std::make_unique<gmx::PmeForceSenderGpu>(
-                    deviceStreamManager->stream(gmx::DeviceStreamType::Pme), pme_pp->mpi_comm_mysim,
-                    pme_pp->ppRanks);
+                    pme_gpu_get_f_ready_synchronizer(pme), pme_pp->mpi_comm_mysim, pme_pp->ppRanks);
         }
         // TODO: Special PME-only constructor is used here. There is no mechanism to prevent from using the other constructor here.
         //       This should be made safer.
         stateGpu = std::make_unique<gmx::StatePropagatorDataGpu>(
-                &deviceStreamManager->stream(gmx::DeviceStreamType::Pme), deviceStreamManager->context(),
-                GpuApiCallBehavior::Async, pme_gpu_get_block_size(pme), wcycle);
+                &deviceStreamManager->stream(gmx::DeviceStreamType::Pme),
+                deviceStreamManager->context(),
+                GpuApiCallBehavior::Async,
+                pme_gpu_get_block_size(pme),
+                wcycle);
     }
 
     clear_nrnb(mynrnb);
@@ -664,10 +691,22 @@ int gmx_pmeonly(struct gmx_pme_t*               pme,
             /* Domain decomposition */
             ivec newGridSize;
             real ewaldcoeff_q = 0, ewaldcoeff_lj = 0;
-            ret = gmx_pme_recv_coeffs_coords(pme, pme_pp.get(), &natoms, box, &maxshift_x, &maxshift_y,
-                                             &lambda_q, &lambda_lj, &computeEnergyAndVirial, &step,
-                                             &newGridSize, &ewaldcoeff_q, &ewaldcoeff_lj,
-                                             useGpuForPme, stateGpu.get(), runMode);
+            ret = gmx_pme_recv_coeffs_coords(pme,
+                                             pme_pp.get(),
+                                             &natoms,
+                                             box,
+                                             &maxshift_x,
+                                             &maxshift_y,
+                                             &lambda_q,
+                                             &lambda_lj,
+                                             &computeEnergyAndVirial,
+                                             &step,
+                                             &newGridSize,
+                                             &ewaldcoeff_q,
+                                             &ewaldcoeff_lj,
+                                             useGpuForPme,
+                                             stateGpu.get(),
+                                             runMode);
 
             if (ret == pmerecvqxSWITCHGRID)
             {
@@ -690,11 +729,11 @@ int gmx_pmeonly(struct gmx_pme_t*               pme,
 
         if (count == 0)
         {
-            wallcycle_start(wcycle, ewcRUN);
+            wallcycle_start(wcycle, WallCycleCounter::Run);
             walltime_accounting_start_time(walltime_accounting);
         }
 
-        wallcycle_start(wcycle, ewcPMEMESH);
+        wallcycle_start(wcycle, WallCycleCounter::PmeMesh);
 
         dvdlambda_q  = 0;
         dvdlambda_lj = 0;
@@ -734,16 +773,34 @@ int gmx_pmeonly(struct gmx_pme_t*               pme,
             GMX_ASSERT(pme_pp->x.size() == static_cast<size_t>(natoms),
                        "The coordinate buffer should have size natoms");
 
-            gmx_pme_do(pme, pme_pp->x, pme_pp->f, pme_pp->chargeA.data(), pme_pp->chargeB.data(),
-                       pme_pp->sqrt_c6A.data(), pme_pp->sqrt_c6B.data(), pme_pp->sigmaA.data(),
-                       pme_pp->sigmaB.data(), box, cr, maxshift_x, maxshift_y, mynrnb, wcycle,
-                       output.coulombVirial_, output.lennardJonesVirial_, &output.coulombEnergy_,
-                       &output.lennardJonesEnergy_, lambda_q, lambda_lj, &dvdlambda_q,
-                       &dvdlambda_lj, stepWork);
+            gmx_pme_do(pme,
+                       pme_pp->x,
+                       pme_pp->f,
+                       pme_pp->chargeA,
+                       pme_pp->chargeB,
+                       pme_pp->sqrt_c6A,
+                       pme_pp->sqrt_c6B,
+                       pme_pp->sigmaA,
+                       pme_pp->sigmaB,
+                       box,
+                       cr,
+                       maxshift_x,
+                       maxshift_y,
+                       mynrnb,
+                       wcycle,
+                       output.coulombVirial_,
+                       output.lennardJonesVirial_,
+                       &output.coulombEnergy_,
+                       &output.lennardJonesEnergy_,
+                       lambda_q,
+                       lambda_lj,
+                       &dvdlambda_q,
+                       &dvdlambda_lj,
+                       stepWork);
             output.forces_ = pme_pp->f;
         }
 
-        cycles = wallcycle_stop(wcycle, ewcPMEMESH);
+        cycles = wallcycle_stop(wcycle, WallCycleCounter::PmeMesh);
         gmx_pme_send_force_vir_ener(*pme, pme_pp.get(), output, dvdlambda_q, dvdlambda_lj, cycles);
 
         count++;
index 1a71ea195c1b74ad44d168bd20753cfb0706e4d4..150a5dad550439b534ce36b8f4c69334f8dda7d6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -69,6 +69,7 @@ int gmx_pmeonly(gmx_pme_t*                      pme,
                 gmx_walltime_accounting_t       walltime_accounting,
                 t_inputrec*                     ir,
                 PmeRunMode                      runMode,
+                bool                            useGpuPmePpCommunication,
                 const gmx::DeviceStreamManager* deviceStreamManager);
 
 #endif
index f788992e52b594a149386805a3199be3ec1c1201..3ae6dd655fc7fee388f567ee8fa597c0c53a65c7 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -94,16 +94,16 @@ static void gmx_pme_send_coeffs_coords_wait(gmx_domdec_t* dd)
 }
 
 /*! \brief Send data to PME ranks */
-static void gmx_pme_send_coeffs_coords(t_forcerec*      fr,
-                                       const 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,
-                                       const matrix     box,
+static void gmx_pme_send_coeffs_coords(t_forcerec*         fr,
+                                       const t_commrec*    cr,
+                                       unsigned int        flags,
+                                       gmx::ArrayRef<real> chargeA,
+                                       gmx::ArrayRef<real> chargeB,
+                                       gmx::ArrayRef<real> c6A,
+                                       gmx::ArrayRef<real> c6B,
+                                       gmx::ArrayRef<real> sigmaA,
+                                       gmx::ArrayRef<real> sigmaB,
+                                       const matrix        box,
                                        const rvec gmx_unused* x,
                                        real                   lambda_q,
                                        real                   lambda_lj,
@@ -124,9 +124,15 @@ static void gmx_pme_send_coeffs_coords(t_forcerec*      fr,
 
     if (debug)
     {
-        fprintf(debug, "PP rank %d sending to PME rank %d: %d%s%s%s%s\n", cr->sim_nodeid, dd->pme_nodeid,
-                n, (flags & PP_PME_CHARGE) ? " charges" : "", (flags & PP_PME_SQRTC6) ? " sqrtC6" : "",
-                (flags & PP_PME_SIGMA) ? " sigma" : "", (flags & PP_PME_COORD) ? " coordinates" : "");
+        fprintf(debug,
+                "PP rank %d sending to PME rank %d: %d%s%s%s%s\n",
+                cr->sim_nodeid,
+                dd->pme_nodeid,
+                n,
+                (flags & PP_PME_CHARGE) ? " charges" : "",
+                (flags & PP_PME_SQRTC6) ? " sqrtC6" : "",
+                (flags & PP_PME_SIGMA) ? " sigma" : "",
+                (flags & PP_PME_COORD) ? " coordinates" : "");
     }
 
     if (useGpuPmePpComms)
@@ -161,7 +167,12 @@ static void gmx_pme_send_coeffs_coords(t_forcerec*      fr,
             copy_mat(box, cnb->box);
         }
 #if GMX_MPI
-        MPI_Isend(cnb, sizeof(*cnb), MPI_BYTE, dd->pme_nodeid, eCommType_CNB, cr->mpi_comm_mysim,
+        MPI_Isend(cnb,
+                  sizeof(*cnb),
+                  MPI_BYTE,
+                  dd->pme_nodeid,
+                  eCommType_CNB,
+                  cr->mpi_comm_mysim,
                   &dd->req_pme[dd->nreq_pme++]);
 #endif
     }
@@ -169,7 +180,12 @@ static void gmx_pme_send_coeffs_coords(t_forcerec*      fr,
     {
 #if GMX_MPI
         /* Communicate only the number of atoms */
-        MPI_Isend(&n, sizeof(n), MPI_BYTE, dd->pme_nodeid, eCommType_CNB, cr->mpi_comm_mysim,
+        MPI_Isend(&n,
+                  sizeof(n),
+                  MPI_BYTE,
+                  dd->pme_nodeid,
+                  eCommType_CNB,
+                  cr->mpi_comm_mysim,
                   &dd->req_pme[dd->nreq_pme++]);
 #endif
     }
@@ -179,33 +195,63 @@ static void gmx_pme_send_coeffs_coords(t_forcerec*      fr,
     {
         if (flags & PP_PME_CHARGE)
         {
-            MPI_Isend(chargeA, n * sizeof(real), MPI_BYTE, dd->pme_nodeid, eCommType_ChargeA,
-                      cr->mpi_comm_mysim, &dd->req_pme[dd->nreq_pme++]);
+            MPI_Isend(chargeA.data(),
+                      n * sizeof(real),
+                      MPI_BYTE,
+                      dd->pme_nodeid,
+                      eCommType_ChargeA,
+                      cr->mpi_comm_mysim,
+                      &dd->req_pme[dd->nreq_pme++]);
         }
         if (flags & PP_PME_CHARGEB)
         {
-            MPI_Isend(chargeB, n * sizeof(real), MPI_BYTE, dd->pme_nodeid, eCommType_ChargeB,
-                      cr->mpi_comm_mysim, &dd->req_pme[dd->nreq_pme++]);
+            MPI_Isend(chargeB.data(),
+                      n * sizeof(real),
+                      MPI_BYTE,
+                      dd->pme_nodeid,
+                      eCommType_ChargeB,
+                      cr->mpi_comm_mysim,
+                      &dd->req_pme[dd->nreq_pme++]);
         }
         if (flags & PP_PME_SQRTC6)
         {
-            MPI_Isend(c6A, n * sizeof(real), MPI_BYTE, dd->pme_nodeid, eCommType_SQRTC6A,
-                      cr->mpi_comm_mysim, &dd->req_pme[dd->nreq_pme++]);
+            MPI_Isend(c6A.data(),
+                      n * sizeof(real),
+                      MPI_BYTE,
+                      dd->pme_nodeid,
+                      eCommType_SQRTC6A,
+                      cr->mpi_comm_mysim,
+                      &dd->req_pme[dd->nreq_pme++]);
         }
         if (flags & PP_PME_SQRTC6B)
         {
-            MPI_Isend(c6B, n * sizeof(real), MPI_BYTE, dd->pme_nodeid, eCommType_SQRTC6B,
-                      cr->mpi_comm_mysim, &dd->req_pme[dd->nreq_pme++]);
+            MPI_Isend(c6B.data(),
+                      n * sizeof(real),
+                      MPI_BYTE,
+                      dd->pme_nodeid,
+                      eCommType_SQRTC6B,
+                      cr->mpi_comm_mysim,
+                      &dd->req_pme[dd->nreq_pme++]);
         }
         if (flags & PP_PME_SIGMA)
         {
-            MPI_Isend(sigmaA, n * sizeof(real), MPI_BYTE, dd->pme_nodeid, eCommType_SigmaA,
-                      cr->mpi_comm_mysim, &dd->req_pme[dd->nreq_pme++]);
+            MPI_Isend(sigmaA.data(),
+                      n * sizeof(real),
+                      MPI_BYTE,
+                      dd->pme_nodeid,
+                      eCommType_SigmaA,
+                      cr->mpi_comm_mysim,
+                      &dd->req_pme[dd->nreq_pme++]);
         }
         if (flags & PP_PME_SIGMAB)
         {
-            MPI_Isend(sigmaB, n * sizeof(real), MPI_BYTE, dd->pme_nodeid, eCommType_SigmaB,
-                      cr->mpi_comm_mysim, &dd->req_pme[dd->nreq_pme++]);
+            MPI_Isend(sigmaB.data(),
+                      n * sizeof(real),
+                      MPI_BYTE,
+                      dd->pme_nodeid,
+                      eCommType_SigmaB,
+                      cr->mpi_comm_mysim,
+                      &dd->req_pme[dd->nreq_pme++]);
         }
         if (flags & PP_PME_COORD)
         {
@@ -219,21 +265,37 @@ static void gmx_pme_send_coeffs_coords(t_forcerec*      fr,
             real* xRealPtr = const_cast<real*>(x[0]);
             if (useGpuPmePpComms && (fr != nullptr))
             {
-                void* sendPtr = sendCoordinatesFromGpu
-                                        ? static_cast<void*>(fr->stateGpu->getCoordinates())
-                                        : static_cast<void*>(xRealPtr);
-                fr->pmePpCommGpu->sendCoordinatesToPmeCudaDirect(sendPtr, n, sendCoordinatesFromGpu,
-                                                                 coordinatesReadyOnDeviceEvent);
+                if (sendCoordinatesFromGpu)
+                {
+                    fr->pmePpCommGpu->sendCoordinatesToPmeFromGpu(
+                            fr->stateGpu->getCoordinates(), n, coordinatesReadyOnDeviceEvent);
+                }
+                else
+                {
+                    fr->pmePpCommGpu->sendCoordinatesToPmeFromCpu(
+                            reinterpret_cast<gmx::RVec*>(xRealPtr), n, coordinatesReadyOnDeviceEvent);
+                }
             }
             else
             {
-                MPI_Isend(xRealPtr, n * sizeof(rvec), MPI_BYTE, dd->pme_nodeid, eCommType_COORD,
-                          cr->mpi_comm_mysim, &dd->req_pme[dd->nreq_pme++]);
+                MPI_Isend(xRealPtr,
+                          n * sizeof(rvec),
+                          MPI_BYTE,
+                          dd->pme_nodeid,
+                          eCommType_COORD,
+                          cr->mpi_comm_mysim,
+                          &dd->req_pme[dd->nreq_pme++]);
             }
         }
     }
 #else
     GMX_UNUSED_VALUE(fr);
+    GMX_UNUSED_VALUE(chargeA);
+    GMX_UNUSED_VALUE(chargeB);
+    GMX_UNUSED_VALUE(c6A);
+    GMX_UNUSED_VALUE(c6B);
+    GMX_UNUSED_VALUE(sigmaA);
+    GMX_UNUSED_VALUE(sigmaB);
     GMX_UNUSED_VALUE(reinitGpuPmePpComms);
     GMX_UNUSED_VALUE(sendCoordinatesFromGpu);
     GMX_UNUSED_VALUE(coordinatesReadyOnDeviceEvent);
@@ -249,25 +311,25 @@ static void gmx_pme_send_coeffs_coords(t_forcerec*      fr,
 }
 
 void gmx_pme_send_parameters(const t_commrec*           cr,
-                             const interaction_const_t* ic,
-                             gmx_bool                   bFreeEnergy_q,
-                             gmx_bool                   bFreeEnergy_lj,
-                             real*                      chargeA,
-                             real*                      chargeB,
-                             real*                      sqrt_c6A,
-                             real*                      sqrt_c6B,
-                             real*                      sigmaA,
-                             real*                      sigmaB,
+                             const interaction_const_t& interactionConst,
+                             bool                       bFreeEnergy_q,
+                             bool                       bFreeEnergy_lj,
+                             gmx::ArrayRef<real>        chargeA,
+                             gmx::ArrayRef<real>        chargeB,
+                             gmx::ArrayRef<real>        sqrt_c6A,
+                             gmx::ArrayRef<real>        sqrt_c6B,
+                             gmx::ArrayRef<real>        sigmaA,
+                             gmx::ArrayRef<real>        sigmaB,
                              int                        maxshift_x,
                              int                        maxshift_y)
 {
     unsigned int flags = 0;
 
-    if (EEL_PME(ic->eeltype))
+    if (EEL_PME(interactionConst.eeltype))
     {
         flags |= PP_PME_CHARGE;
     }
-    if (EVDW_PME(ic->vdwtype))
+    if (EVDW_PME(interactionConst.vdwtype))
     {
         flags |= (PP_PME_SQRTC6 | PP_PME_SIGMA);
     }
@@ -278,9 +340,26 @@ void gmx_pme_send_parameters(const t_commrec*           cr,
         flags |= (flags << 1);
     }
 
-    gmx_pme_send_coeffs_coords(nullptr, cr, flags, chargeA, chargeB, sqrt_c6A, sqrt_c6B, sigmaA,
-                               sigmaB, nullptr, nullptr, 0, 0, maxshift_x, maxshift_y, -1, false,
-                               false, false, nullptr);
+    gmx_pme_send_coeffs_coords(nullptr,
+                               cr,
+                               flags,
+                               chargeA,
+                               chargeB,
+                               sqrt_c6A,
+                               sqrt_c6B,
+                               sigmaA,
+                               sigmaB,
+                               nullptr,
+                               nullptr,
+                               0,
+                               0,
+                               maxshift_x,
+                               maxshift_y,
+                               -1,
+                               false,
+                               false,
+                               false,
+                               nullptr);
 }
 
 void gmx_pme_send_coordinates(t_forcerec*           fr,
@@ -297,27 +376,43 @@ void gmx_pme_send_coordinates(t_forcerec*           fr,
                               GpuEventSynchronizer* coordinatesReadyOnDeviceEvent,
                               gmx_wallcycle*        wcycle)
 {
-    wallcycle_start(wcycle, ewcPP_PMESENDX);
+    wallcycle_start(wcycle, WallCycleCounter::PpPmeSendX);
 
     unsigned int flags = PP_PME_COORD;
     if (computeEnergyAndVirial)
     {
         flags |= PP_PME_ENER_VIR;
     }
-    gmx_pme_send_coeffs_coords(fr, cr, flags, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
-                               box, x, lambda_q, lambda_lj, 0, 0, step, useGpuPmePpComms,
-                               receiveCoordinateAddressFromPme, sendCoordinatesFromGpu,
+    gmx_pme_send_coeffs_coords(fr,
+                               cr,
+                               flags,
+                               {},
+                               {},
+                               {},
+                               {},
+                               {},
+                               {},
+                               box,
+                               x,
+                               lambda_q,
+                               lambda_lj,
+                               0,
+                               0,
+                               step,
+                               useGpuPmePpComms,
+                               receiveCoordinateAddressFromPme,
+                               sendCoordinatesFromGpu,
                                coordinatesReadyOnDeviceEvent);
 
-    wallcycle_stop(wcycle, ewcPP_PMESENDX);
+    wallcycle_stop(wcycle, WallCycleCounter::PpPmeSendX);
 }
 
 void gmx_pme_send_finish(const t_commrec* cr)
 {
     unsigned int flags = PP_PME_FINISH;
 
-    gmx_pme_send_coeffs_coords(nullptr, cr, flags, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
-                               nullptr, nullptr, 0, 0, 0, 0, -1, false, false, false, nullptr);
+    gmx_pme_send_coeffs_coords(
+            nullptr, cr, flags, {}, {}, {}, {}, {}, {}, nullptr, nullptr, 0, 0, 0, 0, -1, false, false, false, nullptr);
 }
 
 void gmx_pme_send_switchgrid(const t_commrec* cr, ivec grid_size, real ewaldcoeff_q, real ewaldcoeff_lj)
@@ -376,8 +471,10 @@ static void receive_virial_energy(const t_commrec*      cr,
     {
         if (debug)
         {
-            fprintf(debug, "PP rank %d receiving from PME rank %d: virial and energy\n",
-                    cr->sim_nodeid, cr->dd->pme_nodeid);
+            fprintf(debug,
+                    "PP rank %d receiving from PME rank %d: virial and energy\n",
+                    cr->sim_nodeid,
+                    cr->dd->pme_nodeid);
         }
 #if GMX_MPI
         MPI_Recv(&cve, sizeof(cve), MPI_BYTE, cr->dd->pme_nodeid, 1, cr->mpi_comm_mysim, MPI_STATUS_IGNORE);
@@ -393,7 +490,7 @@ static void receive_virial_energy(const t_commrec*      cr,
         *dvdlambda_lj += cve.dvdlambda_lj;
         *pme_cycles = cve.cycles;
 
-        if (cve.stop_cond != gmx_stop_cond_none)
+        if (cve.stop_cond != StopCondition::None)
         {
             gmx_set_stop_condition(cve.stop_cond);
         }
@@ -417,15 +514,14 @@ static void recvFFromPme(gmx::PmePpCommGpu* pmePpCommGpu,
     if (useGpuPmePpComms)
     {
         GMX_ASSERT(pmePpCommGpu != nullptr, "Need valid pmePpCommGpu");
-        // Receive directly using CUDA memory copy
-        pmePpCommGpu->receiveForceFromPmeCudaDirect(recvptr, n, receivePmeForceToGpu);
+        // Receive forces from PME rank
+        pmePpCommGpu->receiveForceFromPme(static_cast<gmx::RVec*>(recvptr), n, receivePmeForceToGpu);
     }
     else
     {
         // Receive data using MPI
 #if GMX_MPI
-        MPI_Recv(recvptr, n * sizeof(rvec), MPI_BYTE, cr->dd->pme_nodeid, 0, cr->mpi_comm_mysim,
-                 MPI_STATUS_IGNORE);
+        MPI_Recv(recvptr, n * sizeof(rvec), MPI_BYTE, cr->dd->pme_nodeid, 0, cr->mpi_comm_mysim, MPI_STATUS_IGNORE);
 #else
         GMX_UNUSED_VALUE(cr);
 #endif
@@ -457,7 +553,7 @@ void gmx_pme_receive_f(gmx::PmePpCommGpu*    pmePpCommGpu,
     void* recvptr = reinterpret_cast<void*>(buffer.data());
     recvFFromPme(pmePpCommGpu, recvptr, natoms, cr, useGpuPmePpComms, receivePmeForceToGpu);
 
-    int nt = gmx_omp_nthreads_get_simple_rvec_task(emntDefault, natoms);
+    int nt = gmx_omp_nthreads_get_simple_rvec_task(ModuleMultiThread::Default, natoms);
 
     gmx::ArrayRef<gmx::RVec> f = forceWithVirial->force_;
 
index 3bdc5753d0698d2fb44ae7c5ca422174f5c1f816..c1eba32554bd2e62a00d32e65755b70f0ff95d2e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,19 +59,21 @@ namespace gmx
 {
 class ForceWithVirial;
 class PmePpCommGpu;
+template<typename>
+class ArrayRef;
 } // namespace gmx
 
 /*! \brief Send the charges and maxshift to out PME-only node. */
 void gmx_pme_send_parameters(const t_commrec*           cr,
-                             const interaction_const_t* ic,
+                             const interaction_const_t& interactionConst,
                              gmx_bool                   bFreeEnergy_q,
                              gmx_bool                   bFreeEnergy_lj,
-                             real*                      chargeA,
-                             real*                      chargeB,
-                             real*                      sqrt_c6A,
-                             real*                      sqrt_c6B,
-                             real*                      sigmaA,
-                             real*                      sigmaB,
+                             gmx::ArrayRef<real>        chargeA,
+                             gmx::ArrayRef<real>        chargeB,
+                             gmx::ArrayRef<real>        sqrt_c6A,
+                             gmx::ArrayRef<real>        sqrt_c6B,
+                             gmx::ArrayRef<real>        sigmaA,
+                             gmx::ArrayRef<real>        sigmaB,
                              int                        maxshift_x,
                              int                        maxshift_y);
 
index a3e0239e589f0f3c294a0f4318334d9a11cae185..1e4e614cd99920f7a50af358ed7c963dff8ee96b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_PME_PP_COMM_GPU_H
 #define GMX_PME_PP_COMM_GPU_H
 
-#include "gromacs/utility/classhelpers.h"
+#include <memory>
+
+#include "gromacs/gpu_utils/devicebuffer_datatype.h"
+#include "gromacs/math/vectypes.h"
 #include "gromacs/utility/gmxmpi.h"
 
 class DeviceContext;
@@ -82,23 +85,30 @@ public:
      * \param[in]  recvSize Number of elements to receive
      * \param[in] recvPmeForceToGpu Whether receive is to GPU, otherwise CPU
      */
-    void receiveForceFromPmeCudaDirect(void* recvPtr, int recvSize, bool recvPmeForceToGpu);
+    void receiveForceFromPme(RVec* recvPtr, int recvSize, bool recvPmeForceToGpu);
 
     /*! \brief Push coordinates buffer directly to GPU memory on PME task
      * \param[in] sendPtr Buffer with coordinate data
      * \param[in] sendSize Number of elements to send
-     * \param[in] sendPmeCoordinatesFromGpu Whether send is from GPU, otherwise CPU
      * \param[in] coordinatesReadyOnDeviceEvent Event recorded when coordinates are available on device
      */
-    void sendCoordinatesToPmeCudaDirect(void*                 sendPtr,
-                                        int                   sendSize,
-                                        bool                  sendPmeCoordinatesFromGpu,
-                                        GpuEventSynchronizer* coordinatesReadyOnDeviceEvent);
+    void sendCoordinatesToPmeFromGpu(DeviceBuffer<RVec>    sendPtr,
+                                     int                   sendSize,
+                                     GpuEventSynchronizer* coordinatesReadyOnDeviceEvent);
+
+    /*! \brief Push coordinates buffer from host memory directly to GPU memory on PME task
+     * \param[in] sendPtr Buffer with coordinate data
+     * \param[in] sendSize Number of elements to send
+     * \param[in] coordinatesReadyOnDeviceEvent Event recorded when coordinates are available on device
+     */
+    void sendCoordinatesToPmeFromCpu(RVec*                 sendPtr,
+                                     int                   sendSize,
+                                     GpuEventSynchronizer* coordinatesReadyOnDeviceEvent);
 
     /*! \brief
      * Return pointer to buffer used for staging PME force on GPU
      */
-    void* getGpuForceStagingPtr();
+    DeviceBuffer<gmx::RVec> getGpuForceStagingPtr();
 
     /*! \brief
      * Return pointer to event recorded when forces are ready
@@ -107,7 +117,7 @@ public:
 
 private:
     class Impl;
-    gmx::PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index d19004e7edada326327458cdc937ae8bfdc7b040..e7339f9c7ea49f03821aa1653ada6ecd6ec9df6e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,31 +83,37 @@ void PmePpCommGpu::reinit(int /* size */)
                "correct implementation.");
 }
 
-void PmePpCommGpu::receiveForceFromPmeCudaDirect(void* /* recvPtr */,
-                                                 int /* recvSize */,
-                                                 bool /* receivePmeForceToGpu */)
+void PmePpCommGpu::receiveForceFromPme(RVec* /* recvPtr */, int /* recvSize */, bool /* receivePmeForceToGpu */)
 {
     GMX_ASSERT(!impl_,
                "A CPU stub for PME-PP GPU communication was called instead of the correct "
                "implementation.");
 }
 
-void PmePpCommGpu::sendCoordinatesToPmeCudaDirect(void* /* sendPtr */,
-                                                  int /* sendSize */,
-                                                  bool /* sendPmeCoordinatesFromGpu */,
-                                                  GpuEventSynchronizer* /* coordinatesOnDeviceEvent */)
+void PmePpCommGpu::sendCoordinatesToPmeFromGpu(DeviceBuffer<RVec> /* sendPtr */,
+                                               int /* sendSize */,
+                                               GpuEventSynchronizer* /* coordinatesOnDeviceEvent */)
 {
     GMX_ASSERT(!impl_,
                "A CPU stub for PME-PP GPU communication was called instead of the correct "
                "implementation.");
 }
 
-void* PmePpCommGpu::getGpuForceStagingPtr()
+void PmePpCommGpu::sendCoordinatesToPmeFromCpu(RVec* /* sendPtr */,
+                                               int /* sendSize */,
+                                               GpuEventSynchronizer* /* coordinatesOnDeviceEvent */)
 {
     GMX_ASSERT(!impl_,
                "A CPU stub for PME-PP GPU communication was called instead of the correct "
                "implementation.");
-    return nullptr;
+}
+
+DeviceBuffer<gmx::RVec> PmePpCommGpu::getGpuForceStagingPtr()
+{
+    GMX_ASSERT(!impl_,
+               "A CPU stub for PME-PP GPU communication was called instead of the correct "
+               "implementation.");
+    return DeviceBuffer<gmx::RVec>{};
 }
 
 GpuEventSynchronizer* PmePpCommGpu::getForcesReadySynchronizer()
index acb5998b02271170377c8911d0df2e7a75e5c775..2e242a074f91676abbc75da860a49c96754f5cb1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
  */
 #include "gmxpre.h"
 
+#include "gromacs/ewald/pme_pp_communication.h"
 #include "pme_pp_comm_gpu_impl.h"
 
 #include "config.h"
@@ -52,6 +53,7 @@
 #include "gromacs/gpu_utils/device_stream.h"
 #include "gromacs/gpu_utils/devicebuffer.h"
 #include "gromacs/gpu_utils/gpueventsynchronizer.cuh"
+#include "gromacs/gpu_utils/typecasts.cuh"
 #include "gromacs/utility/gmxmpi.h"
 
 namespace gmx
@@ -64,11 +66,9 @@ PmePpCommGpu::Impl::Impl(MPI_Comm             comm,
     deviceContext_(deviceContext),
     pmePpCommStream_(deviceStream),
     comm_(comm),
-    pmeRank_(pmeRank)
+    pmeRank_(pmeRank),
+    d_pmeForces_(nullptr)
 {
-    GMX_RELEASE_ASSERT(
-            GMX_THREAD_MPI,
-            "PME-PP GPU Communication is currently only supported with thread-MPI enabled");
 }
 
 PmePpCommGpu::Impl::~Impl() = default;
@@ -77,20 +77,22 @@ void PmePpCommGpu::Impl::reinit(int size)
 {
     // This rank will access PME rank memory directly, so needs to receive the remote PME buffer addresses.
 #if GMX_MPI
-    MPI_Recv(&remotePmeXBuffer_, sizeof(void**), MPI_BYTE, pmeRank_, 0, comm_, MPI_STATUS_IGNORE);
-    MPI_Recv(&remotePmeFBuffer_, sizeof(void**), MPI_BYTE, pmeRank_, 0, comm_, MPI_STATUS_IGNORE);
+
+    if (GMX_THREAD_MPI)
+    {
+        // receive device buffer address from PME rank
+        MPI_Recv(&remotePmeXBuffer_, sizeof(float3*), MPI_BYTE, pmeRank_, 0, comm_, MPI_STATUS_IGNORE);
+        MPI_Recv(&remotePmeFBuffer_, sizeof(float3*), MPI_BYTE, pmeRank_, 0, comm_, MPI_STATUS_IGNORE);
+    }
+
+#endif
 
     // Reallocate buffer used for staging PME force on GPU
     reallocateDeviceBuffer(&d_pmeForces_, size, &d_pmeForcesSize_, &d_pmeForcesSizeAlloc_, deviceContext_);
-#else
-    GMX_UNUSED_VALUE(size);
-#endif
     return;
 }
 
-// TODO make this asynchronous by splitting into this into
-// launchRecvForceFromPmeCudaDirect() and sycnRecvForceFromPmeCudaDirect()
-void PmePpCommGpu::Impl::receiveForceFromPmeCudaDirect(void* recvPtr, int recvSize, bool receivePmeForceToGpu)
+void PmePpCommGpu::Impl::receiveForceFromPmeCudaDirect(float3* pmeForcePtr, int recvSize, bool receivePmeForceToGpu)
 {
 #if GMX_MPI
     // Receive event from PME task and add to stream, to ensure pull of data doesn't
@@ -98,11 +100,14 @@ void PmePpCommGpu::Impl::receiveForceFromPmeCudaDirect(void* recvPtr, int recvSi
     GpuEventSynchronizer* pmeSync;
     MPI_Recv(&pmeSync, sizeof(GpuEventSynchronizer*), MPI_BYTE, pmeRank_, 0, comm_, MPI_STATUS_IGNORE);
     pmeSync->enqueueWaitEvent(pmePpCommStream_);
+#endif
 
     // Pull force data from remote GPU
-    void*       pmeForcePtr = receivePmeForceToGpu ? static_cast<void*>(d_pmeForces_) : recvPtr;
-    cudaError_t stat = cudaMemcpyAsync(pmeForcePtr, remotePmeFBuffer_, recvSize * DIM * sizeof(float),
-                                       cudaMemcpyDefault, pmePpCommStream_.stream());
+    cudaError_t stat = cudaMemcpyAsync(pmeForcePtr,
+                                       remotePmeFBuffer_,
+                                       recvSize * DIM * sizeof(float),
+                                       cudaMemcpyDefault,
+                                       pmePpCommStream_.stream());
     CU_RET_ERR(stat, "cudaMemcpyAsync on Recv from PME CUDA direct data transfer failed");
 
     if (receivePmeForceToGpu)
@@ -116,47 +121,100 @@ void PmePpCommGpu::Impl::receiveForceFromPmeCudaDirect(void* recvPtr, int recvSi
     {
         // Ensure CPU waits for PME forces to be copied before reducing
         // them with other forces on the CPU
-        cudaStreamSynchronize(pmePpCommStream_.stream());
+        pmePpCommStream_.synchronize();
     }
+}
+
+void PmePpCommGpu::Impl::receiveForceFromPmeCudaMpi(float3* pmeForcePtr, int recvSize)
+{
+#if GMX_MPI
+    MPI_Recv(pmeForcePtr, recvSize * DIM, MPI_FLOAT, pmeRank_, 0, comm_, MPI_STATUS_IGNORE);
 #else
-    GMX_UNUSED_VALUE(recvPtr);
+    GMX_UNUSED_VALUE(pmeForcePtr);
     GMX_UNUSED_VALUE(recvSize);
-    GMX_UNUSED_VALUE(receivePmeForceToGpu);
 #endif
 }
 
-void PmePpCommGpu::Impl::sendCoordinatesToPmeCudaDirect(void* sendPtr,
-                                                        int   sendSize,
-                                                        bool gmx_unused sendPmeCoordinatesFromGpu,
+void PmePpCommGpu::Impl::receiveForceFromPme(float3* recvPtr, int recvSize, bool receivePmeForceToGpu)
+{
+    float3* pmeForcePtr = receivePmeForceToGpu ? asFloat3(d_pmeForces_) : recvPtr;
+    if (GMX_THREAD_MPI)
+    {
+        receiveForceFromPmeCudaDirect(pmeForcePtr, recvSize, receivePmeForceToGpu);
+    }
+    else
+    {
+        receiveForceFromPmeCudaMpi(pmeForcePtr, recvSize);
+    }
+}
+
+void PmePpCommGpu::Impl::sendCoordinatesToPmeCudaDirect(float3*               sendPtr,
+                                                        int                   sendSize,
                                                         GpuEventSynchronizer* coordinatesReadyOnDeviceEvent)
 {
-#if GMX_MPI
     // ensure stream waits until coordinate data is available on device
     coordinatesReadyOnDeviceEvent->enqueueWaitEvent(pmePpCommStream_);
 
-    cudaError_t stat = cudaMemcpyAsync(remotePmeXBuffer_, sendPtr, sendSize * DIM * sizeof(float),
-                                       cudaMemcpyDefault, pmePpCommStream_.stream());
+    cudaError_t stat = cudaMemcpyAsync(remotePmeXBuffer_,
+                                       sendPtr,
+                                       sendSize * DIM * sizeof(float),
+                                       cudaMemcpyDefault,
+                                       pmePpCommStream_.stream());
     CU_RET_ERR(stat, "cudaMemcpyAsync on Send to PME CUDA direct data transfer failed");
 
+#if GMX_MPI
     // Record and send event to allow PME task to sync to above transfer before commencing force calculations
     pmeCoordinatesSynchronizer_.markEvent(pmePpCommStream_);
     GpuEventSynchronizer* pmeSync = &pmeCoordinatesSynchronizer_;
     MPI_Send(&pmeSync, sizeof(GpuEventSynchronizer*), MPI_BYTE, pmeRank_, 0, comm_);
+#endif
+}
+
+void PmePpCommGpu::Impl::sendCoordinatesToPmeCudaMpi(float3*               sendPtr,
+                                                     int                   sendSize,
+                                                     GpuEventSynchronizer* coordinatesReadyOnDeviceEvent)
+{
+    // ensure coordinate data is available on device before we start transfer
+    coordinatesReadyOnDeviceEvent->waitForEvent();
+
+#if GMX_MPI
+    float3* sendptr_x = sendPtr;
+
+    MPI_Send(sendptr_x, sendSize * DIM, MPI_FLOAT, pmeRank_, eCommType_COORD_GPU, comm_);
 #else
     GMX_UNUSED_VALUE(sendPtr);
     GMX_UNUSED_VALUE(sendSize);
-    GMX_UNUSED_VALUE(sendPmeCoordinatesFromGpu);
-    GMX_UNUSED_VALUE(coordinatesReadyOnDeviceEvent);
 #endif
 }
-void* PmePpCommGpu::Impl::getGpuForceStagingPtr()
+
+void PmePpCommGpu::Impl::sendCoordinatesToPme(float3*               sendPtr,
+                                              int                   sendSize,
+                                              GpuEventSynchronizer* coordinatesReadyOnDeviceEvent)
+{
+    if (GMX_THREAD_MPI)
+    {
+        sendCoordinatesToPmeCudaDirect(sendPtr, sendSize, coordinatesReadyOnDeviceEvent);
+    }
+    else
+    {
+        sendCoordinatesToPmeCudaMpi(sendPtr, sendSize, coordinatesReadyOnDeviceEvent);
+    }
+}
+DeviceBuffer<Float3> PmePpCommGpu::Impl::getGpuForceStagingPtr()
 {
-    return static_cast<void*>(d_pmeForces_);
+    return d_pmeForces_;
 }
 
 GpuEventSynchronizer* PmePpCommGpu::Impl::getForcesReadySynchronizer()
 {
-    return &forcesReadySynchronizer_;
+    if (GMX_THREAD_MPI)
+    {
+        return &forcesReadySynchronizer_;
+    }
+    else
+    {
+        return nullptr;
+    }
 }
 
 PmePpCommGpu::PmePpCommGpu(MPI_Comm             comm,
@@ -174,21 +232,26 @@ void PmePpCommGpu::reinit(int size)
     impl_->reinit(size);
 }
 
-void PmePpCommGpu::receiveForceFromPmeCudaDirect(void* recvPtr, int recvSize, bool receivePmeForceToGpu)
+void PmePpCommGpu::receiveForceFromPme(RVec* recvPtr, int recvSize, bool receivePmeForceToGpu)
+{
+    impl_->receiveForceFromPme(asFloat3(recvPtr), recvSize, receivePmeForceToGpu);
+}
+
+void PmePpCommGpu::sendCoordinatesToPmeFromGpu(DeviceBuffer<RVec>    sendPtr,
+                                               int                   sendSize,
+                                               GpuEventSynchronizer* coordinatesReadyOnDeviceEvent)
 {
-    impl_->receiveForceFromPmeCudaDirect(recvPtr, recvSize, receivePmeForceToGpu);
+    impl_->sendCoordinatesToPme(asFloat3(sendPtr), sendSize, coordinatesReadyOnDeviceEvent);
 }
 
-void PmePpCommGpu::sendCoordinatesToPmeCudaDirect(void*                 sendPtr,
-                                                  int                   sendSize,
-                                                  bool                  sendPmeCoordinatesFromGpu,
-                                                  GpuEventSynchronizer* coordinatesReadyOnDeviceEvent)
+void PmePpCommGpu::sendCoordinatesToPmeFromCpu(RVec*                 sendPtr,
+                                               int                   sendSize,
+                                               GpuEventSynchronizer* coordinatesReadyOnDeviceEvent)
 {
-    impl_->sendCoordinatesToPmeCudaDirect(sendPtr, sendSize, sendPmeCoordinatesFromGpu,
-                                          coordinatesReadyOnDeviceEvent);
+    impl_->sendCoordinatesToPme(asFloat3(sendPtr), sendSize, coordinatesReadyOnDeviceEvent);
 }
 
-void* PmePpCommGpu::getGpuForceStagingPtr()
+DeviceBuffer<Float3> PmePpCommGpu::getGpuForceStagingPtr()
 {
     return impl_->getGpuForceStagingPtr();
 }
index 0630084e59b6950b5c09cdd28969cfd7b3ab1522..d4ee85872e9aa5c3c1a6372574b1aaaf8313ecfc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -73,7 +73,7 @@ public:
 
     /*! \brief Pull force buffer directly from GPU memory on PME
      * rank to either GPU or CPU memory on PP task using CUDA
-     * Memory copy.
+     * Memory copy or CUDA-aware MPI.
      *
      * recvPtr should be in GPU or CPU memory if recvPmeForceToGpu
      * is true or false, respectively. If receiving to GPU, this
@@ -87,51 +87,86 @@ public:
      * \param[in] recvSize Number of elements to receive
      * \param[in] receivePmeForceToGpu Whether receive is to GPU, otherwise CPU
      */
-    void receiveForceFromPmeCudaDirect(void* recvPtr, int recvSize, bool receivePmeForceToGpu);
+    void receiveForceFromPme(float3* recvPtr, int recvSize, bool receivePmeForceToGpu);
 
 
     /*! \brief Push coordinates buffer directly to GPU memory on PME
      * task, from either GPU or CPU memory on PP task using CUDA
-     * Memory copy. sendPtr should be in GPU or CPU memory if
-     * sendPmeCoordinatesFromGpu is true or false respectively. If
-     * sending from GPU, this method should be called after the
-     * local GPU coordinate buffer operations. The remote PME task will
-     * automatically wait for data to be copied before commencing PME force calculations.
+     * Memory copy or CUDA-aware MPI. If sending from GPU, this method should
+     * be called after the local GPU coordinate buffer operations.
+     * The remote PME task will automatically wait for data to be copied
+     * before commencing PME force calculations.
      * \param[in] sendPtr Buffer with coordinate data
      * \param[in] sendSize Number of elements to send
-     * \param[in] sendPmeCoordinatesFromGpu Whether send is from GPU, otherwise CPU
      * \param[in] coordinatesReadyOnDeviceEvent Event recorded when coordinates are available on device
      */
-    void sendCoordinatesToPmeCudaDirect(void*                 sendPtr,
-                                        int                   sendSize,
-                                        bool                  sendPmeCoordinatesFromGpu,
-                                        GpuEventSynchronizer* coordinatesReadyOnDeviceEvent);
+    void sendCoordinatesToPme(float3* sendPtr, int sendSize, GpuEventSynchronizer* coordinatesReadyOnDeviceEvent);
 
     /*! \brief
      * Return pointer to buffer used for staging PME force on GPU
      */
-    void* getGpuForceStagingPtr();
+    DeviceBuffer<Float3> getGpuForceStagingPtr();
 
     /*! \brief
      * Return pointer to event recorded when forces are ready
      */
     GpuEventSynchronizer* getForcesReadySynchronizer();
 
+private:
+    /*! \brief Pull force buffer directly from GPU memory on PME
+     * rank to either GPU or CPU memory on PP task using CUDA
+     * Memory copy. This method is used with Thread-MPI.
+     * \param[out] recvPtr CPU buffer to receive PME force data
+     * \param[in] recvSize Number of elements to receive
+     * \param[in] receivePmeForceToGpu Whether receive is to GPU, otherwise CPU
+     */
+    void receiveForceFromPmeCudaDirect(float3* recvPtr, int recvSize, bool receivePmeForceToGpu);
+
+    /*! \brief Pull force buffer directly from GPU memory on PME
+     * rank to either GPU or CPU memory on PP task using CUDA-aware
+     * MPI. This method is used with process-MPI.
+     * \param[out] recvPtr CPU buffer to receive PME force data
+     * \param[in] recvSize Number of elements to receive
+     */
+    void receiveForceFromPmeCudaMpi(float3* recvPtr, int recvSize);
+
+    /*! \brief Push coordinates buffer directly to GPU memory on PME
+     * task, from either GPU or CPU memory on PP task using CUDA Memory copy.
+     * This method is used with Thread-MPI.
+     * \param[in] sendPtr Buffer with coordinate data
+     * \param[in] sendSize Number of elements to send
+     * \param[in] coordinatesReadyOnDeviceEvent Event recorded when coordinates are available on device
+     */
+    void sendCoordinatesToPmeCudaDirect(float3*               sendPtr,
+                                        int                   sendSize,
+                                        GpuEventSynchronizer* coordinatesReadyOnDeviceEvent);
+
+    /*! \brief Push coordinates buffer directly to GPU memory on PME
+     * task, from either GPU or CPU memory on PP task using CUDA-aware MPI.
+     * This method is used with process-MPI.
+     * \param[in] sendPtr Buffer with coordinate data
+     * \param[in] sendSize Number of elements to send
+     * \param[in] coordinatesReadyOnDeviceEvent Event recorded when coordinates are available on device
+     */
+    void sendCoordinatesToPmeCudaMpi(float3*               sendPtr,
+                                     int                   sendSize,
+                                     GpuEventSynchronizer* coordinatesReadyOnDeviceEvent);
+
 private:
     //! GPU context handle (not used in CUDA)
     const DeviceContext& deviceContext_;
     //! Handle for CUDA stream used for the communication operations in this class
     const DeviceStream& pmePpCommStream_;
     //! Remote location of PME coordinate data buffer
-    void* remotePmeXBuffer_ = nullptr;
+    float3* remotePmeXBuffer_ = nullptr;
     //! Remote location of PME force data buffer
-    void* remotePmeFBuffer_ = nullptr;
+    float3* remotePmeFBuffer_ = nullptr;
     //! communicator for simulation
     MPI_Comm comm_;
     //! Rank of PME task
     int pmeRank_ = -1;
     //! Buffer for staging PME force on GPU
-    rvec* d_pmeForces_ = nullptr;
+    DeviceBuffer<gmx::RVec> d_pmeForces_;
     //! number of atoms in PME force staging array
     int d_pmeForcesSize_ = -1;
     //! number of atoms allocated in recvbuf array
index 329284d4e4404e88feebf06a1d7636d8727c866c..d5fbd960d93fc30afb0b3b9241d3b98a0e5ef602 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -62,6 +62,7 @@ enum
     eCommType_SigmaB,
     eCommType_NR,
     eCommType_COORD,
+    eCommType_COORD_GPU,
     eCommType_CNB
 };
 
@@ -136,6 +137,6 @@ struct gmx_pme_comm_vir_ene_t
     real   dvdlambda_q;
     real   dvdlambda_lj;
     //@}
-    float           cycles;    /**< Counter of CPU cycles used */
-    gmx_stop_cond_t stop_cond; /**< Flag used in responding to an external signal to terminate */
+    float         cycles;    /**< Counter of CPU cycles used */
+    StopCondition stop_cond; /**< Flag used in responding to an external signal to terminate */
 };
index 063ceded374705b431baa37b3007176d5b293949..e70e45ef2e9ab5be605bb67f89cb1beb7e8087d2 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -135,8 +135,12 @@ static void pme_calc_pidx_wrapper(gmx::ArrayRef<const gmx::RVec> x, const matrix
         try
         {
             const int natoms = x.ssize();
-            pme_calc_pidx(natoms * thread / nthread, natoms * (thread + 1) / nthread, recipbox, x,
-                          atc, atc->count_thread[thread].data());
+            pme_calc_pidx(natoms * thread / nthread,
+                          natoms * (thread + 1) / nthread,
+                          recipbox,
+                          x,
+                          atc,
+                          atc->count_thread[thread].data());
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
     }
@@ -264,8 +268,8 @@ static void pme_dd_sendrecv(PmeAtomComm gmx_unused* atc,
 
     if (nbyte_s > 0 && nbyte_r > 0)
     {
-        MPI_Sendrecv(buf_s, nbyte_s, MPI_BYTE, dest, shift, buf_r, nbyte_r, MPI_BYTE, src, shift,
-                     atc->mpi_comm, &stat);
+        MPI_Sendrecv(
+                buf_s, nbyte_s, MPI_BYTE, dest, shift, buf_r, nbyte_r, MPI_BYTE, src, shift, atc->mpi_comm, &stat);
     }
     else if (nbyte_s > 0)
     {
@@ -282,7 +286,7 @@ static void pme_dd_sendrecv(PmeAtomComm gmx_unused* atc,
 static void dd_pmeredist_pos_coeffs(gmx_pme_t*                     pme,
                                     const gmx_bool                 bX,
                                     gmx::ArrayRef<const gmx::RVec> x,
-                                    const real*                    data,
+                                    gmx::ArrayRef<const real>      data,
                                     PmeAtomComm*                   atc)
 {
     int nnodes_comm, i, local_pos, buf_pos, node;
@@ -306,7 +310,9 @@ static void dd_pmeredist_pos_coeffs(gmx_pme_t*                     pme,
                     "%zd particles communicated to PME rank %d are more than 2/3 times the cut-off "
                     "out of the domain decomposition cell of their charge group in dimension %c.\n"
                     "This usually means that your system is not well equilibrated.",
-                    x.ssize() - (sendCount[atc->nodeid] + nsend), pme->nodeid, 'x' + atc->dimind);
+                    x.ssize() - (sendCount[atc->nodeid] + nsend),
+                    pme->nodeid,
+                    'x' + atc->dimind);
         }
 
         if (nsend > pme->buf_nalloc)
@@ -324,11 +330,10 @@ static void dd_pmeredist_pos_coeffs(gmx_pme_t*                     pme,
             /* Communicate the count */
             if (debug)
             {
-                fprintf(debug, "dimind %d PME rank %d send to rank %d: %d\n", atc->dimind,
-                        atc->nodeid, commnode, scount);
+                fprintf(debug, "dimind %d PME rank %d send to rank %d: %d\n", atc->dimind, atc->nodeid, commnode, scount);
             }
-            pme_dd_sendrecv(atc, FALSE, i, &scount, sizeof(int), &atc->slabCommSetup[i].rcount,
-                            sizeof(int));
+            pme_dd_sendrecv(
+                    atc, FALSE, i, &scount, sizeof(int), &atc->slabCommSetup[i].rcount, sizeof(int));
             numAtoms += atc->slabCommSetup[i].rcount;
         }
 
@@ -372,12 +377,22 @@ static void dd_pmeredist_pos_coeffs(gmx_pme_t*                     pme,
             if (bX)
             {
                 /* Communicate the coordinates */
-                pme_dd_sendrecv(atc, FALSE, i, pme->bufv + buf_pos, scount * sizeof(rvec),
-                                atc->xBuffer.data() + local_pos, rcount * sizeof(rvec));
+                pme_dd_sendrecv(atc,
+                                FALSE,
+                                i,
+                                pme->bufv + buf_pos,
+                                scount * sizeof(rvec),
+                                atc->xBuffer.data() + local_pos,
+                                rcount * sizeof(rvec));
             }
             /* Communicate the coefficients */
-            pme_dd_sendrecv(atc, FALSE, i, pme->bufr + buf_pos, scount * sizeof(real),
-                            atc->coefficientBuffer.data() + local_pos, rcount * sizeof(real));
+            pme_dd_sendrecv(atc,
+                            FALSE,
+                            i,
+                            pme->bufr + buf_pos,
+                            scount * sizeof(real),
+                            atc->coefficientBuffer.data() + local_pos,
+                            rcount * sizeof(real));
             buf_pos += scount;
             local_pos += atc->slabCommSetup[i].rcount;
         }
@@ -401,8 +416,13 @@ void dd_pmeredist_f(struct gmx_pme_t* pme, PmeAtomComm* atc, gmx::ArrayRef<gmx::
         if (scount > 0 || rcount > 0)
         {
             /* Communicate the forces */
-            pme_dd_sendrecv(atc, TRUE, i, atc->f.data() + local_pos, scount * sizeof(rvec),
-                            pme->bufv + buf_pos, rcount * sizeof(rvec));
+            pme_dd_sendrecv(atc,
+                            TRUE,
+                            i,
+                            atc->f.data() + local_pos,
+                            scount * sizeof(rvec),
+                            pme->bufv + buf_pos,
+                            rcount * sizeof(rvec));
             local_pos += scount;
         }
         atc->slabCommSetup[commnode].buf_index = buf_pos;
@@ -454,12 +474,12 @@ void do_redist_pos_coeffs(struct gmx_pme_t*              pme,
                           const t_commrec*               cr,
                           gmx_bool                       bFirst,
                           gmx::ArrayRef<const gmx::RVec> x,
-                          const real*                    data)
+                          gmx::ArrayRef<const real>      data)
 {
     for (int d = pme->ndecompdim - 1; d >= 0; d--)
     {
         gmx::ArrayRef<const gmx::RVec> xRef;
-        const real*                    param_d;
+        gmx::ArrayRef<const real>      param_d;
         if (d == pme->ndecompdim - 1)
         {
             /* Start out with the local coordinates and charges */
@@ -471,7 +491,7 @@ void do_redist_pos_coeffs(struct gmx_pme_t*              pme,
             /* Redistribute the data collected along the previous dimension */
             const PmeAtomComm& atc = pme->atc[d + 1];
             xRef                   = atc.x;
-            param_d                = atc.coefficient.data();
+            param_d                = atc.coefficient;
         }
         PmeAtomComm& atc = pme->atc[d];
         atc.pd.resize(xRef.size());
index 975b298d16edd3b68c644dedac2d688d0fcd27f7..1b277a830b3808a7dcf74d29fe875a1ff6d6839c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@ void do_redist_pos_coeffs(struct gmx_pme_t*              pme,
                           const t_commrec*               cr,
                           gmx_bool                       bFirst,
                           gmx::ArrayRef<const gmx::RVec> x,
-                          const real*                    data);
+                          gmx::ArrayRef<const real>      data);
 
 #endif
index 99ffa7f12038ed6b041fdafc8f27119c59f752d4..416f67b3e14aa3829d18a68992bad215b4d447a1 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -94,8 +94,7 @@ constexpr int c_simdWidth = 4;
 template<unsigned int factor>
 static size_t roundUpToMultipleOfFactor(size_t number)
 {
-    static_assert(factor > 0 && (factor & (factor - 1)) == 0,
-                  "factor should be >0 and a power of 2");
+    static_assert(gmx::isPowerOfTwo(factor));
 
     /* We need to add a most factor-1 and because factor is a power of 2,
      * we get the result by masking out the bits corresponding to factor-1.
@@ -110,7 +109,8 @@ static size_t roundUpToMultipleOfFactor(size_t number)
 static void reallocSimdAlignedAndPadded(real** ptr, int unpaddedNumElements)
 {
     sfree_aligned(*ptr);
-    snew_aligned(*ptr, roundUpToMultipleOfFactor<c_simdWidth>(unpaddedNumElements),
+    snew_aligned(*ptr,
+                 roundUpToMultipleOfFactor<c_simdWidth>(unpaddedNumElements),
                  c_simdWidth * sizeof(real));
 }
 
@@ -352,15 +352,15 @@ int solve_pme_yzx(const gmx_pme_t* pme, t_complex* grid, real vol, bool computeE
     ivec                     local_ndata, local_offset, local_size;
     real                     elfac;
 
-    elfac = ONE_4PI_EPS0 / pme->epsilon_r;
+    elfac = gmx::c_one4PiEps0 / pme->epsilon_r;
 
     nx = pme->nkx;
     ny = pme->nky;
     nz = pme->nkz;
 
     /* Dimensions should be identical for A/B grid, so we just use A here */
-    gmx_parallel_3dfft_complex_limits(pme->pfft_setup[PME_GRID_QA], complex_order, local_ndata,
-                                      local_offset, local_size);
+    gmx_parallel_3dfft_complex_limits(
+            pme->pfft_setup[PME_GRID_QA], complex_order, local_ndata, local_offset, local_size);
 
     rxx = pme->recipbox[XX][XX];
     ryx = pme->recipbox[YY][XX];
@@ -480,7 +480,9 @@ int solve_pme_yzx(const gmx_pme_t* pme, t_complex* grid, real vol, bool computeE
             }
 
             calc_exponentials_q(
-                    kxstart, kxend, elfac,
+                    kxstart,
+                    kxend,
+                    elfac,
                     ArrayRef<PME_T>(denom, denom + roundUpToMultipleOfFactor<c_simdWidth>(kxend)),
                     ArrayRef<PME_T>(tmp1, tmp1 + roundUpToMultipleOfFactor<c_simdWidth>(kxend)),
                     ArrayRef<PME_T>(eterm, eterm + roundUpToMultipleOfFactor<c_simdWidth>(kxend)));
@@ -546,7 +548,9 @@ int solve_pme_yzx(const gmx_pme_t* pme, t_complex* grid, real vol, bool computeE
             }
 
             calc_exponentials_q(
-                    kxstart, kxend, elfac,
+                    kxstart,
+                    kxend,
+                    elfac,
                     ArrayRef<PME_T>(denom, denom + roundUpToMultipleOfFactor<c_simdWidth>(kxend)),
                     ArrayRef<PME_T>(tmp1, tmp1 + roundUpToMultipleOfFactor<c_simdWidth>(kxend)),
                     ArrayRef<PME_T>(eterm, eterm + roundUpToMultipleOfFactor<c_simdWidth>(kxend)));
@@ -618,8 +622,8 @@ int solve_pme_lj_yzx(const gmx_pme_t* pme,
     nz = pme->nkz;
 
     /* Dimensions should be identical for A/B grid, so we just use A here */
-    gmx_parallel_3dfft_complex_limits(pme->pfft_setup[PME_GRID_C6A], complex_order, local_ndata,
-                                      local_offset, local_size);
+    gmx_parallel_3dfft_complex_limits(
+            pme->pfft_setup[PME_GRID_C6A], complex_order, local_ndata, local_offset, local_size);
     rxx = pme->recipbox[XX][XX];
     ryx = pme->recipbox[YY][XX];
     ryy = pme->recipbox[YY][YY];
@@ -726,7 +730,8 @@ int solve_pme_lj_yzx(const gmx_pme_t* pme,
             }
 
             calc_exponentials_lj(
-                    kxstart, kxend,
+                    kxstart,
+                    kxend,
                     ArrayRef<PME_T>(tmp1, tmp1 + roundUpToMultipleOfFactor<c_simdWidth>(kxend)),
                     ArrayRef<PME_T>(tmp2, tmp2 + roundUpToMultipleOfFactor<c_simdWidth>(kxend)),
                     ArrayRef<PME_T>(denom, denom + roundUpToMultipleOfFactor<c_simdWidth>(kxend)));
@@ -868,7 +873,8 @@ int solve_pme_lj_yzx(const gmx_pme_t* pme,
             }
 
             calc_exponentials_lj(
-                    kxstart, kxend,
+                    kxstart,
+                    kxend,
                     ArrayRef<PME_T>(tmp1, tmp1 + roundUpToMultipleOfFactor<c_simdWidth>(kxend)),
                     ArrayRef<PME_T>(tmp2, tmp2 + roundUpToMultipleOfFactor<c_simdWidth>(kxend)),
                     ArrayRef<PME_T>(denom, denom + roundUpToMultipleOfFactor<c_simdWidth>(kxend)));
index 9e887a9e6efb7fe14eab0007065baf83b7f46ac4..d63c40ecbcd62bf920cd0e97ac9b1d39a333d669 100644 (file)
@@ -452,9 +452,18 @@ __attribute__((reqd_work_group_size(order, order, atomsPerBlock))) __kernel void
         pme_gpu_stage_atom_data(sm_coordinates, gm_coordinates, DIM);
 
         barrier(CLK_LOCAL_MEM_FENCE);
-        calculate_splines(kernelParams, atomIndexOffset, sm_coordinates, sm_coefficients, sm_theta,
-                          sm_gridlineIndices, sm_fractCoords, gm_theta, gm_dtheta,
-                          gm_gridlineIndices, gm_fractShiftsTable, gm_gridlineIndicesTable);
+        calculate_splines(kernelParams,
+                          atomIndexOffset,
+                          sm_coordinates,
+                          sm_coefficients,
+                          sm_theta,
+                          sm_gridlineIndices,
+                          sm_fractCoords,
+                          gm_theta,
+                          gm_dtheta,
+                          gm_gridlineIndices,
+                          gm_fractShiftsTable,
+                          gm_gridlineIndicesTable);
 #if !defined(_AMD_SOURCE_) && !defined(_NVIDIA_SOURCE_)
         /* This is only here for execution of e.g. 32-sized warps on 16-wide hardware; this was
          * __syncwarp() in CUDA. #2519
@@ -471,8 +480,8 @@ __attribute__((reqd_work_group_size(order, order, atomsPerBlock))) __kernel void
         /* Spline data - only thetas (dthetas will only be needed in gather) */
         pme_gpu_stage_atom_data(sm_theta, gm_theta, DIM * order);
         /* Gridline indices - they're actually int and not float, but C99 is angry about overloads */
-        pme_gpu_stage_atom_data((__local float*)sm_gridlineIndices,
-                                (__global const float*)gm_gridlineIndices, DIM);
+        pme_gpu_stage_atom_data(
+                (__local float*)sm_gridlineIndices, (__global const float*)gm_gridlineIndices, DIM);
 
         barrier(CLK_LOCAL_MEM_FENCE);
     }
index c5711797a46c428be93b15126c7c886b4a036b5a..5fe1660c3f4eff882127ae43390a61997555a68a 100644 (file)
@@ -417,8 +417,8 @@ static void copy_local_grid(const gmx_pme_t* pme, const pmegrids_t* pmegrids, in
     int   d;
     real* grid_th;
 
-    gmx_parallel_3dfft_real_limits(pme->pfft_setup[grid_index], local_fft_ndata, local_fft_offset,
-                                   local_fft_size);
+    gmx_parallel_3dfft_real_limits(
+            pme->pfft_setup[grid_index], local_fft_ndata, local_fft_offset, local_fft_size);
     fft_my = local_fft_size[YY];
     fft_mz = local_fft_size[ZZ];
 
@@ -478,8 +478,8 @@ static void reduce_threadgrid_overlap(const gmx_pme_t*  pme,
     const real*      grid_th;
     real*            commbuf = nullptr;
 
-    gmx_parallel_3dfft_real_limits(pme->pfft_setup[grid_index], local_fft_ndata, local_fft_offset,
-                                   local_fft_size);
+    gmx_parallel_3dfft_real_limits(
+            pme->pfft_setup[grid_index], local_fft_ndata, local_fft_offset, local_fft_size);
     fft_nx = local_fft_ndata[XX];
     fft_ny = local_fft_ndata[YY];
     fft_nz = local_fft_ndata[ZZ];
@@ -608,9 +608,27 @@ static void reduce_threadgrid_overlap(const gmx_pme_t*  pme,
 #ifdef DEBUG_PME_REDUCE
                 printf("n%d t%d add %d  %2d %2d %2d  %2d %2d %2d  %2d-%2d %2d-%2d, %2d-%2d "
                        "%2d-%2d, %2d-%2d %2d-%2d\n",
-                       pme->nodeid, thread, thread_f, pme->pmegrid_start_ix, pme->pmegrid_start_iy,
-                       pme->pmegrid_start_iz, sx, sy, sz, offx - ox, tx1 - ox, offx, tx1, offy - oy,
-                       ty1 - oy, offy, ty1, offz - oz, tz1 - oz, offz, tz1);
+                       pme->nodeid,
+                       thread,
+                       thread_f,
+                       pme->pmegrid_start_ix,
+                       pme->pmegrid_start_iy,
+                       pme->pmegrid_start_iz,
+                       sx,
+                       sy,
+                       sz,
+                       offx - ox,
+                       tx1 - ox,
+                       offx,
+                       tx1,
+                       offy - oy,
+                       ty1 - oy,
+                       offy,
+                       ty1,
+                       offz - oz,
+                       tz1 - oz,
+                       offz,
+                       tz1);
 #endif
 
                 if (!(bCommX || bCommY))
@@ -716,8 +734,8 @@ static void sum_fftgrid_dd(const gmx_pme_t* pme, real* fftgrid, int grid_index)
      * communication setup.
      */
 
-    gmx_parallel_3dfft_real_limits(pme->pfft_setup[grid_index], local_fft_ndata, local_fft_offset,
-                                   local_fft_size);
+    gmx_parallel_3dfft_real_limits(
+            pme->pfft_setup[grid_index], local_fft_ndata, local_fft_offset, local_fft_size);
 
     if (pme->nnodes_minor > 1)
     {
@@ -752,15 +770,28 @@ static void sum_fftgrid_dd(const gmx_pme_t* pme, real* fftgrid, int grid_index)
 
             if (debug != nullptr)
             {
-                fprintf(debug, "PME fftgrid comm y %2d x %2d x %2d\n", local_fft_ndata[XX],
-                        send_nindex, local_fft_ndata[ZZ]);
+                fprintf(debug,
+                        "PME fftgrid comm y %2d x %2d x %2d\n",
+                        local_fft_ndata[XX],
+                        send_nindex,
+                        local_fft_ndata[ZZ]);
             }
 
 #if GMX_MPI
             int send_id = overlap->comm_data[ipulse].send_id;
             int recv_id = overlap->comm_data[ipulse].recv_id;
-            MPI_Sendrecv(sendptr, send_size_y * datasize, GMX_MPI_REAL, send_id, ipulse, recvptr,
-                         recv_size_y * datasize, GMX_MPI_REAL, recv_id, ipulse, overlap->mpi_comm, &stat);
+            MPI_Sendrecv(sendptr,
+                         send_size_y * datasize,
+                         GMX_MPI_REAL,
+                         send_id,
+                         ipulse,
+                         recvptr,
+                         recv_size_y * datasize,
+                         GMX_MPI_REAL,
+                         recv_id,
+                         ipulse,
+                         overlap->mpi_comm,
+                         &stat);
 #endif
 
             for (x = 0; x < local_fft_ndata[XX]; x++)
@@ -813,7 +844,10 @@ static void sum_fftgrid_dd(const gmx_pme_t* pme, real* fftgrid, int grid_index)
 
         if (debug != nullptr)
         {
-            fprintf(debug, "PME fftgrid comm x %2d x %2d x %2d\n", send_nindex, local_fft_ndata[YY],
+            fprintf(debug,
+                    "PME fftgrid comm x %2d x %2d x %2d\n",
+                    send_nindex,
+                    local_fft_ndata[YY],
                     local_fft_ndata[ZZ]);
         }
 
@@ -823,8 +857,18 @@ static void sum_fftgrid_dd(const gmx_pme_t* pme, real* fftgrid, int grid_index)
         int   recv_id  = overlap->comm_data[ipulse].recv_id;
         auto* sendptr  = const_cast<real*>(overlap->sendbuf.data());
         auto* recvptr  = const_cast<real*>(overlap->recvbuf.data());
-        MPI_Sendrecv(sendptr, send_nindex * datasize, GMX_MPI_REAL, send_id, ipulse, recvptr,
-                     recv_nindex * datasize, GMX_MPI_REAL, recv_id, ipulse, overlap->mpi_comm, &stat);
+        MPI_Sendrecv(sendptr,
+                     send_nindex * datasize,
+                     GMX_MPI_REAL,
+                     send_id,
+                     ipulse,
+                     recvptr,
+                     recv_nindex * datasize,
+                     GMX_MPI_REAL,
+                     recv_id,
+                     ipulse,
+                     overlap->mpi_comm,
+                     &stat);
 #endif
 
         for (x = 0; x < recv_nindex; x++)
@@ -925,9 +969,14 @@ void spread_on_grid(const gmx_pme_t*  pme,
 
             if (bCalcSplines)
             {
-                make_bsplines(spline->theta.coefficients, spline->dtheta.coefficients,
-                              pme->pme_order, as_rvec_array(atc->fractx.data()), spline->n,
-                              spline->ind.data(), atc->coefficient.data(), bDoSplines);
+                make_bsplines(spline->theta.coefficients,
+                              spline->dtheta.coefficients,
+                              pme->pme_order,
+                              as_rvec_array(atc->fractx.data()),
+                              spline->n,
+                              spline->ind.data(),
+                              atc->coefficient.data(),
+                              bDoSplines);
             }
 
             if (bSpread)
@@ -967,9 +1016,13 @@ void spread_on_grid(const gmx_pme_t*  pme,
         {
             try
             {
-                reduce_threadgrid_overlap(pme, grids, thread, fftgrid,
+                reduce_threadgrid_overlap(pme,
+                                          grids,
+                                          thread,
+                                          fftgrid,
                                           const_cast<real*>(pme->overlap[0].sendbuf.data()),
-                                          const_cast<real*>(pme->overlap[1].sendbuf.data()), grid_index);
+                                          const_cast<real*>(pme->overlap[1].sendbuf.data()),
+                                          grid_index);
             }
             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
         }
index 3cf3a1f7ca77599297e51adb4a0d57b043f7117c..62f3a61c8bcbf5ecae1c6240805878e9c4bb399f 100644 (file)
@@ -274,8 +274,8 @@ __launch_bounds__(c_spreadMaxThreadsPerBlock) CLANG_DISABLE_OPTIMIZATION_ATTRIBU
     /* Spreading */
     if (spreadCharges)
     {
-        spread_charges<order, wrapX, wrapY, 0, threadsPerAtom>(kernelParams, &atomCharge,
-                                                               sm_gridlineIndices, sm_theta);
+        spread_charges<order, wrapX, wrapY, 0, threadsPerAtom>(
+                kernelParams, &atomCharge, sm_gridlineIndices, sm_theta);
     }
     if (numGrids == 2)
     {
@@ -293,8 +293,8 @@ __launch_bounds__(c_spreadMaxThreadsPerBlock) CLANG_DISABLE_OPTIMIZATION_ATTRIBU
         }
         if (spreadCharges)
         {
-            spread_charges<order, wrapX, wrapY, 1, threadsPerAtom>(kernelParams, &atomCharge,
-                                                                   sm_gridlineIndices, sm_theta);
+            spread_charges<order, wrapX, wrapY, 1, threadsPerAtom>(
+                    kernelParams, &atomCharge, sm_gridlineIndices, sm_theta);
         }
     }
 }
diff --git a/src/gromacs/ewald/tests/.clang-tidy b/src/gromacs/ewald/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 61da015d2dae8308ef455d75098398bcb863373e..ee7eaa7f36433b0b09c3140cd404760373af7a86 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2016,2017,2020, by the GROMACS development team, led by
+# Copyright (c) 2016,2017,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -39,4 +39,5 @@ gmx_add_unit_test(EwaldUnitTests ewald-test HARDWARE_DETECTION
         pmesolvetest.cpp
         pmesplinespreadtest.cpp
         pmetestcommon.cpp
+        pme.cpp
 )
diff --git a/src/gromacs/ewald/tests/pme.cpp b/src/gromacs/ewald/tests/pme.cpp
new file mode 100644 (file)
index 0000000..5452cb4
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 pme related classes:
+ * class SeparatePmeRanksPermitted
+ *
+ * \author Dmitry Morozov <dmitry.morozov@jyu.fi>
+ * \ingroup module_ewald
+ */
+#include "gmxpre.h"
+
+#include <gtest/gtest.h>
+
+#include "gromacs/utility/real.h"
+#include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringcompare.h"
+
+#include "testutils/testasserts.h"
+#include "testutils/testmatchers.h"
+
+#include "pmetestcommon.h"
+
+namespace gmx
+{
+
+namespace test
+{
+
+class SeparatePmeRanksPermittedTest : public ::testing::Test
+{
+public:
+    void disableFirstReason() { separatePmeRanksPermitted_.disablePmeRanks("First reason"); }
+
+    void disableSecondReason() { separatePmeRanksPermitted_.disablePmeRanks("Second reason"); }
+
+    void disableEmptyReason() { separatePmeRanksPermitted_.disablePmeRanks(""); }
+
+protected:
+    SeparatePmeRanksPermitted separatePmeRanksPermitted_;
+};
+
+TEST_F(SeparatePmeRanksPermittedTest, ZeroPmeDisableReasons)
+{
+    // Expect that SeparatePmeRanksPermitted is enabled by default
+    EXPECT_TRUE(separatePmeRanksPermitted_.permitSeparatePmeRanks());
+}
+
+TEST_F(SeparatePmeRanksPermittedTest, CanBeDisabled)
+{
+    // Test if disablePmeRanks works
+    EXPECT_NO_THROW(disableFirstReason(););
+}
+
+TEST_F(SeparatePmeRanksPermittedTest, OneDisableReasonFlag)
+{
+    disableFirstReason();
+
+    // Expect that SeparatePmeRanksPermitted is disabled now
+    EXPECT_FALSE(separatePmeRanksPermitted_.permitSeparatePmeRanks());
+}
+
+TEST_F(SeparatePmeRanksPermittedTest, OneDisableReasonText)
+{
+    disableFirstReason();
+
+    // Expect that reasonsWhyDisabled works with one reason
+    EXPECT_TRUE(separatePmeRanksPermitted_.reasonsWhyDisabled() == "First reason");
+}
+
+TEST_F(SeparatePmeRanksPermittedTest, TwoDisableReasonText)
+{
+    disableFirstReason();
+    disableSecondReason();
+
+    // Expect that reasonsWhyDisabled works with two reasons
+    EXPECT_TRUE(separatePmeRanksPermitted_.reasonsWhyDisabled() == "First reason; Second reason");
+}
+
+TEST_F(SeparatePmeRanksPermittedTest, EmptyDisableReasonText)
+{
+    disableEmptyReason();
+
+    // Expect that reasonsWhyDisabled works with empty reason
+    EXPECT_TRUE(separatePmeRanksPermitted_.reasonsWhyDisabled().empty());
+}
+
+} // namespace test
+
+} // namespace gmx
index b6a4e9e35f81b69e24f16180b26b36bfcabcd898..7c38a52c91599c1e60d7fc7899e476fa7296b248 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,16 +90,20 @@ public:
         /* Describing the test in case it fails */
         SCOPED_TRACE(formatString(
                 "Testing B-spline moduli creation (%s) for PME order %d, grid size %d %d %d",
-                (moduliType == ModuliType::P3M) ? "P3M" : "plain", pmeOrder, gridSize[XX],
-                gridSize[YY], gridSize[ZZ]));
+                (moduliType == ModuliType::P3M) ? "P3M" : "plain",
+                pmeOrder,
+                gridSize[XX],
+                gridSize[YY],
+                gridSize[ZZ]));
 
         /* Storing the input where it's needed */
         t_inputrec inputRec;
         inputRec.nkx         = gridSize[XX];
         inputRec.nky         = gridSize[YY];
         inputRec.nkz         = gridSize[ZZ];
-        inputRec.coulombtype = (moduliType == ModuliType::P3M) ? eelP3M_AD : eelPME;
-        inputRec.pme_order   = pmeOrder;
+        inputRec.coulombtype = (moduliType == ModuliType::P3M) ? CoulombInteractionType::P3mAD
+                                                               : CoulombInteractionType::Pme;
+        inputRec.pme_order = pmeOrder;
 
         /* PME initialization call which checks the inputs and computes the B-spline moduli according to the grid sizes. */
         PmeSafePointer pme = pmeInitEmpty(&inputRec);
@@ -147,7 +151,9 @@ std::vector<BSplineModuliInputParameters> const invalidInputs{
     BSplineModuliInputParameters{ IVec{ 64, 2, 64 }, sanePmeOrder, ModuliType::PME },
     /* Invalid interpolation orders */
     BSplineModuliInputParameters{
-            saneGridSize, 8 + 1, ModuliType::P3M // P3M only supports orders up to 8
+            saneGridSize,
+            8 + 1,
+            ModuliType::P3M // P3M only supports orders up to 8
     },
     BSplineModuliInputParameters{ saneGridSize, PME_ORDER_MAX + 1, ModuliType::PME },
 };
index 1190caea1de56244be0bf6bb1da966608fb86ce4..160b319fdb09b87a95dd5436b82d8ee637276471 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -276,7 +276,7 @@ public:
         inputRec.nky         = gridSize[YY];
         inputRec.nkz         = gridSize[ZZ];
         inputRec.pme_order   = pmeOrder;
-        inputRec.coulombtype = eelPME;
+        inputRec.coulombtype = CoulombInteractionType::Pme;
         inputRec.epsilon_r   = 1.0;
 
         TestReferenceData refData;
@@ -298,13 +298,19 @@ public:
             SCOPED_TRACE(
                     formatString("Testing force gathering on %s for PME grid size %d %d %d"
                                  ", order %d, %zu atoms",
-                                 pmeTestHardwareContext->description().c_str(), gridSize[XX],
-                                 gridSize[YY], gridSize[ZZ], pmeOrder, atomCount));
-
-            PmeSafePointer pmeSafe =
-                    pmeInitWrapper(&inputRec, codePath, pmeTestHardwareContext->deviceContext(),
-                                   pmeTestHardwareContext->deviceStream(),
-                                   pmeTestHardwareContext->pmeGpuProgram(), box);
+                                 pmeTestHardwareContext->description().c_str(),
+                                 gridSize[XX],
+                                 gridSize[YY],
+                                 gridSize[ZZ],
+                                 pmeOrder,
+                                 atomCount));
+
+            PmeSafePointer                          pmeSafe = pmeInitWrapper(&inputRec,
+                                                    codePath,
+                                                    pmeTestHardwareContext->deviceContext(),
+                                                    pmeTestHardwareContext->deviceStream(),
+                                                    pmeTestHardwareContext->pmeGpuProgram(),
+                                                    box);
             std::unique_ptr<StatePropagatorDataGpu> stateGpu =
                     (codePath == CodePath::GPU)
                             ? makeStatePropagatorDataGpu(*pmeSafe.get(),
@@ -312,7 +318,10 @@ public:
                                                          pmeTestHardwareContext->deviceStream())
                             : nullptr;
 
-            pmeInitAtoms(pmeSafe.get(), stateGpu.get(), codePath, inputAtomData.coordinates,
+            pmeInitAtoms(pmeSafe.get(),
+                         stateGpu.get(),
+                         codePath,
+                         inputAtomData.coordinates,
                          inputAtomData.charges);
 
             /* Setting some more inputs */
@@ -320,10 +329,16 @@ public:
             pmeSetGridLineIndices(pmeSafe.get(), codePath, inputAtomData.gridLineIndices);
             for (int dimIndex = 0; dimIndex < DIM; dimIndex++)
             {
-                pmeSetSplineData(pmeSafe.get(), codePath, inputAtomSplineData.splineValues[dimIndex],
-                                 PmeSplineDataType::Values, dimIndex);
-                pmeSetSplineData(pmeSafe.get(), codePath, inputAtomSplineData.splineDerivatives[dimIndex],
-                                 PmeSplineDataType::Derivatives, dimIndex);
+                pmeSetSplineData(pmeSafe.get(),
+                                 codePath,
+                                 inputAtomSplineData.splineValues[dimIndex],
+                                 PmeSplineDataType::Values,
+                                 dimIndex);
+                pmeSetSplineData(pmeSafe.get(),
+                                 codePath,
+                                 inputAtomSplineData.splineDerivatives[dimIndex],
+                                 PmeSplineDataType::Derivatives,
+                                 dimIndex);
             }
 
             /* Explicitly copying the sample forces to be able to modify them */
index 578fa8caa748b2925eb1977902f6426c9b18d491..57ed877302062762c7db49e7f14c98917db21b59 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -98,13 +98,13 @@ public:
         inputRec.nky         = gridSize[YY];
         inputRec.nkz         = gridSize[ZZ];
         inputRec.pme_order   = 4;
-        inputRec.coulombtype = eelPME;
+        inputRec.coulombtype = CoulombInteractionType::Pme;
         inputRec.epsilon_r   = epsilon_r;
         switch (method)
         {
             case PmeSolveAlgorithm::Coulomb: break;
 
-            case PmeSolveAlgorithm::LennardJones: inputRec.vdwtype = evdwPME; break;
+            case PmeSolveAlgorithm::LennardJones: inputRec.vdwtype = VanDerWaalsType::Pme; break;
 
             default: GMX_THROW(InternalError("Unknown PME solver"));
         }
@@ -119,9 +119,9 @@ public:
             if (!supportedInput)
             {
                 /* Testing the failure for the unsupported input */
-                EXPECT_THROW_GMX(pmeInitWrapper(&inputRec, codePath, nullptr, nullptr, nullptr, box,
-                                                ewaldCoeff_q, ewaldCoeff_lj),
-                                 NotImplementedError);
+                EXPECT_THROW_GMX(
+                        pmeInitWrapper(&inputRec, codePath, nullptr, nullptr, nullptr, box, ewaldCoeff_q, ewaldCoeff_lj),
+                        NotImplementedError);
                 continue;
             }
 
@@ -140,20 +140,28 @@ public:
                             "Testing solving (%s, %s, %s energy/virial) on %s for PME grid "
                             "size %d %d %d, Ewald coefficients %g %g",
                             (method == PmeSolveAlgorithm::LennardJones) ? "Lennard-Jones" : "Coulomb",
-                            gridOrdering.second.c_str(), computeEnergyAndVirial ? "with" : "without",
-                            pmeTestHardwareContext->description().c_str(), gridSize[XX],
-                            gridSize[YY], gridSize[ZZ], ewaldCoeff_q, ewaldCoeff_lj));
+                            gridOrdering.second.c_str(),
+                            computeEnergyAndVirial ? "with" : "without",
+                            pmeTestHardwareContext->description().c_str(),
+                            gridSize[XX],
+                            gridSize[YY],
+                            gridSize[ZZ],
+                            ewaldCoeff_q,
+                            ewaldCoeff_lj));
 
                     /* Running the test */
-                    PmeSafePointer pmeSafe = pmeInitWrapper(
-                            &inputRec, codePath, pmeTestHardwareContext->deviceContext(),
-                            pmeTestHardwareContext->deviceStream(),
-                            pmeTestHardwareContext->pmeGpuProgram(), box, ewaldCoeff_q, ewaldCoeff_lj);
+                    PmeSafePointer pmeSafe = pmeInitWrapper(&inputRec,
+                                                            codePath,
+                                                            pmeTestHardwareContext->deviceContext(),
+                                                            pmeTestHardwareContext->deviceStream(),
+                                                            pmeTestHardwareContext->pmeGpuProgram(),
+                                                            box,
+                                                            ewaldCoeff_q,
+                                                            ewaldCoeff_lj);
                     pmeSetComplexGrid(pmeSafe.get(), codePath, gridOrdering.first, nonZeroGridValues);
                     const real cellVolume = box[0] * box[4] * box[8];
                     // FIXME - this is box[XX][XX] * box[YY][YY] * box[ZZ][ZZ], should be stored in the PME structure
-                    pmePerformSolve(pmeSafe.get(), codePath, method, cellVolume, gridOrdering.first,
-                                    computeEnergyAndVirial);
+                    pmePerformSolve(pmeSafe.get(), codePath, method, cellVolume, gridOrdering.first, computeEnergyAndVirial);
                     pmeFinalizeTest(pmeSafe.get(), codePath);
 
                     /* Check the outputs */
@@ -181,7 +189,8 @@ public:
                     const uint64_t splineModuliDoublePrecisionUlps =
                             getSplineModuliDoublePrecisionUlps(inputRec.pme_order + 1);
                     auto gridTolerance = relativeToleranceAsPrecisionDependentUlp(
-                            gridValuesMagnitude, gridUlpToleranceFactor * c_splineModuliSinglePrecisionUlps,
+                            gridValuesMagnitude,
+                            gridUlpToleranceFactor * c_splineModuliSinglePrecisionUlps,
                             gridUlpToleranceFactor * splineModuliDoublePrecisionUlps);
                     gridValuesChecker.setDefaultTolerance(gridTolerance);
 
@@ -220,7 +229,8 @@ public:
                         // TODO This factor is arbitrary, do a proper error-propagation analysis
                         uint64_t energyUlpToleranceFactor = gridUlpToleranceFactor * 2;
                         auto     energyTolerance = relativeToleranceAsPrecisionDependentUlp(
-                                energyMagnitude, energyUlpToleranceFactor * c_splineModuliSinglePrecisionUlps,
+                                energyMagnitude,
+                                energyUlpToleranceFactor * c_splineModuliSinglePrecisionUlps,
                                 energyUlpToleranceFactor * splineModuliDoublePrecisionUlps);
                         TestReferenceChecker energyChecker(checker);
                         energyChecker.setDefaultTolerance(energyTolerance);
@@ -231,7 +241,8 @@ public:
                         // TODO This factor is arbitrary, do a proper error-propagation analysis
                         uint64_t virialUlpToleranceFactor = energyUlpToleranceFactor * 2;
                         auto     virialTolerance = relativeToleranceAsPrecisionDependentUlp(
-                                virialMagnitude, virialUlpToleranceFactor * c_splineModuliSinglePrecisionUlps,
+                                virialMagnitude,
+                                virialUlpToleranceFactor * c_splineModuliSinglePrecisionUlps,
                                 virialUlpToleranceFactor * splineModuliDoublePrecisionUlps);
                         TestReferenceChecker virialChecker(
                                 checker.checkCompound("Matrix", "Virial"));
index 4765acbddbd5319308e5d67be406273c26da3313..10a2840ee2f643e40a958e04f2b0043a3870390d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -106,7 +106,7 @@ public:
         inputRec.nky         = gridSize[YY];
         inputRec.nkz         = gridSize[ZZ];
         inputRec.pme_order   = pmeOrder;
-        inputRec.coulombtype = eelPME;
+        inputRec.coulombtype = CoulombInteractionType::Pme;
         inputRec.epsilon_r   = 1.0;
 
         const std::map<PmeSplineAndSpreadOptions, std::string> optionsToTest = {
@@ -145,18 +145,25 @@ public:
             {
                 /* Describing the test uniquely in case it fails */
 
-                SCOPED_TRACE(formatString(
-                        "Testing %s on %s for PME grid size %d %d %d"
-                        ", order %d, %zu atoms",
-                        option.second.c_str(), pmeTestHardwareContext->description().c_str(),
-                        gridSize[XX], gridSize[YY], gridSize[ZZ], pmeOrder, atomCount));
+                SCOPED_TRACE(
+                        formatString("Testing %s on %s for PME grid size %d %d %d"
+                                     ", order %d, %zu atoms",
+                                     option.second.c_str(),
+                                     pmeTestHardwareContext->description().c_str(),
+                                     gridSize[XX],
+                                     gridSize[YY],
+                                     gridSize[ZZ],
+                                     pmeOrder,
+                                     atomCount));
 
                 /* Running the test */
 
-                PmeSafePointer pmeSafe =
-                        pmeInitWrapper(&inputRec, codePath, pmeTestHardwareContext->deviceContext(),
-                                       pmeTestHardwareContext->deviceStream(),
-                                       pmeTestHardwareContext->pmeGpuProgram(), box);
+                PmeSafePointer                          pmeSafe = pmeInitWrapper(&inputRec,
+                                                        codePath,
+                                                        pmeTestHardwareContext->deviceContext(),
+                                                        pmeTestHardwareContext->deviceStream(),
+                                                        pmeTestHardwareContext->pmeGpuProgram(),
+                                                        box);
                 std::unique_ptr<StatePropagatorDataGpu> stateGpu =
                         (codePath == CodePath::GPU)
                                 ? makeStatePropagatorDataGpu(*pmeSafe.get(),
@@ -211,8 +218,8 @@ public:
                     {
                         auto splineValuesDim =
                                 pmeGetSplineData(pmeSafe.get(), codePath, PmeSplineDataType::Values, i);
-                        splineValuesChecker.checkSequence(splineValuesDim.begin(),
-                                                          splineValuesDim.end(), dimString[i]);
+                        splineValuesChecker.checkSequence(
+                                splineValuesDim.begin(), splineValuesDim.end(), dimString[i]);
                     }
 
                     /* Spline derivatives */
@@ -234,8 +241,8 @@ public:
 
                     /* Particle gridline indices */
                     auto gridLineIndices = pmeGetGridlineIndices(pmeSafe.get(), codePath);
-                    rootChecker.checkSequence(gridLineIndices.begin(), gridLineIndices.end(),
-                                              "Gridline indices");
+                    rootChecker.checkSequence(
+                            gridLineIndices.begin(), gridLineIndices.end(), "Gridline indices");
                 }
 
                 if (spreadCharges)
@@ -308,28 +315,40 @@ auto const c_sampleCharges13 = ChargesVector(c_sampleChargesFull).subArray(3, 13
 //! Random coordinate vectors
 CoordinatesVector const c_sampleCoordinatesFull{ { 5.59F, 1.37F, 0.95F },
                                                  {
-                                                         16.0F, 1.02F, 0.22F // 2 box lengths in x
+                                                         16.0F,
+                                                         1.02F,
+                                                         0.22F // 2 box lengths in x
                                                  },
                                                  { 0.034F, 1.65F, 0.22F },
                                                  { 0.33F, 0.92F, 1.56F },
                                                  { 1.16F, 0.75F, 0.39F },
                                                  { 0.5F, 1.63F, 1.14F },
                                                  {
-                                                         16.0001F, 1.52F, 1.19F // > 2 box lengths in x
+                                                         16.0001F,
+                                                         1.52F,
+                                                         1.19F // > 2 box lengths in x
                                                  },
                                                  {
-                                                         1.43F, 1.1F, 4.1F // > 2 box lengths in z
+                                                         1.43F,
+                                                         1.1F,
+                                                         4.1F // > 2 box lengths in z
                                                  },
                                                  {
-                                                         -1.08F, 1.19F, 0.08F // negative x
+                                                         -1.08F,
+                                                         1.19F,
+                                                         0.08F // negative x
                                                  },
                                                  { 1.6F, 0.93F, 0.53F },
                                                  {
-                                                         1.32F, -1.48F, 0.16F // negative y
+                                                         1.32F,
+                                                         -1.48F,
+                                                         0.16F // negative y
                                                  },
                                                  { 0.87F, 0.0F, 0.33F },
                                                  {
-                                                         0.95F, 7.7F, -0.48F // > 2 box lengths in y, negative z
+                                                         0.95F,
+                                                         7.7F,
+                                                         -0.48F // > 2 box lengths in y, negative z
                                                  },
                                                  { 1.23F, 0.91F, 0.68F },
                                                  { 0.19F, 1.45F, 0.94F },
index eb1e170411bbf090582852ed283fe65824919143..c8e8530ee7924c87d24f9f30ec77a479f1190c83 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -120,9 +120,21 @@ PmeSafePointer pmeInitWrapper(const t_inputrec*    inputRec,
     const auto     runMode       = (mode == CodePath::CPU) ? PmeRunMode::CPU : PmeRunMode::Mixed;
     t_commrec      dummyCommrec  = { 0 };
     NumPmeDomains  numPmeDomains = { 1, 1 };
-    gmx_pme_t* pmeDataRaw = gmx_pme_init(&dummyCommrec, numPmeDomains, inputRec, false, false, true,
-                                         ewaldCoeff_q, ewaldCoeff_lj, 1, runMode, nullptr,
-                                         deviceContext, deviceStream, pmeGpuProgram, dummyLogger);
+    gmx_pme_t*     pmeDataRaw    = gmx_pme_init(&dummyCommrec,
+                                         numPmeDomains,
+                                         inputRec,
+                                         false,
+                                         false,
+                                         true,
+                                         ewaldCoeff_q,
+                                         ewaldCoeff_lj,
+                                         1,
+                                         runMode,
+                                         nullptr,
+                                         deviceContext,
+                                         deviceStream,
+                                         pmeGpuProgram,
+                                         dummyLogger);
     PmeSafePointer pme(pmeDataRaw); // taking ownership
 
     // TODO get rid of this with proper matrix type
@@ -166,8 +178,8 @@ std::unique_ptr<StatePropagatorDataGpu> makeStatePropagatorDataGpu(const gmx_pme
     // TODO: Pin the host buffer and use async memory copies
     // TODO: Special constructor for PME-only rank / PME-tests is used here. There should be a mechanism to
     //       restrict one from using other constructor here.
-    return std::make_unique<StatePropagatorDataGpu>(deviceStream, *deviceContext, GpuApiCallBehavior::Sync,
-                                                    pme_gpu_get_block_size(&pme), nullptr);
+    return std::make_unique<StatePropagatorDataGpu>(
+            deviceStream, *deviceContext, GpuApiCallBehavior::Sync, pme_gpu_get_block_size(&pme), nullptr);
 }
 
 //! PME initialization with atom data
@@ -187,7 +199,7 @@ void pmeInitAtoms(gmx_pme_t*               pme,
             atc              = &(pme->atc[0]);
             atc->x           = coordinates;
             atc->coefficient = charges;
-            gmx_pme_reinit_atoms(pme, atomCount, charges.data(), nullptr);
+            gmx_pme_reinit_atoms(pme, atomCount, charges, {});
             /* With decomposition there would be more boilerplate atc code here, e.g. do_redist_pos_coeffs */
             break;
 
@@ -196,7 +208,7 @@ void pmeInitAtoms(gmx_pme_t*               pme,
             atc = &(pme->atc[0]);
             // We need to set atc->n for passing the size in the tests
             atc->setNumAtoms(atomCount);
-            gmx_pme_reinit_atoms(pme, atomCount, charges.data(), nullptr);
+            gmx_pme_reinit_atoms(pme, atomCount, charges, {});
 
             stateGpu->reinit(atomCount, atomCount);
             stateGpu->copyCoordinatesToGpu(arrayRefFromArray(coordinates.data(), coordinates.size()),
@@ -227,8 +239,8 @@ static void pmeGetRealGridSizesInternal(const gmx_pme_t* pme,
     switch (mode)
     {
         case CodePath::CPU:
-            gmx_parallel_3dfft_real_limits(pme->pfft_setup[gridIndex], gridSize, gridOffsetUnused,
-                                           paddedGridSize);
+            gmx_parallel_3dfft_real_limits(
+                    pme->pfft_setup[gridIndex], gridSize, gridOffsetUnused, paddedGridSize);
             break;
 
         case CodePath::GPU:
@@ -253,8 +265,8 @@ static void pmeGetComplexGridSizesInternal(const gmx_pme_t* pme,
 {
     const size_t gridIndex = 0;
     IVec         gridOffsetUnused, complexOrderUnused;
-    gmx_parallel_3dfft_complex_limits(pme->pfft_setup[gridIndex], complexOrderUnused, gridSize,
-                                      gridOffsetUnused, paddedGridSize); // TODO: what about YZX ordering?
+    gmx_parallel_3dfft_complex_limits(
+            pme->pfft_setup[gridIndex], complexOrderUnused, gridSize, gridOffsetUnused, paddedGridSize); // TODO: what about YZX ordering?
 }
 
 //! Getting the PME grid memory buffer and its sizes - template definition
@@ -266,7 +278,7 @@ static void pmeGetGridAndSizesInternal(const gmx_pme_t* /*unused*/,
                                        IVec& /*unused*/)       //NOLINT(google-runtime-references)
 {
     GMX_THROW(InternalError("Deleted function call"));
-    // explicitly deleting general template does not compile in clang/icc, see https://llvm.org/bugs/show_bug.cgi?id=17537
+    // explicitly deleting general template does not compile in clang, see https://llvm.org/bugs/show_bug.cgi?id=17537
 }
 
 //! Getting the PME real grid memory buffer and its sizes
@@ -305,9 +317,14 @@ void pmePerformSplineAndSpread(gmx_pme_t* pme,
     switch (mode)
     {
         case CodePath::CPU:
-            spread_on_grid(pme, atc, &pme->pmegrid[gridIndex], computeSplines, spreadCharges,
+            spread_on_grid(pme,
+                           atc,
+                           &pme->pmegrid[gridIndex],
+                           computeSplines,
+                           spreadCharges,
                            fftgrid != nullptr ? fftgrid[gridIndex] : nullptr,
-                           computeSplinesForZeroCharges, gridIndex);
+                           computeSplinesForZeroCharges,
+                           gridIndex);
             if (spreadCharges && !pme->bUseThreads)
             {
                 wrap_periodic_pmegrid(pme, pmegrid);
@@ -381,8 +398,13 @@ void pmePerformSolve(const gmx_pme_t*  pme,
                     break;
 
                 case PmeSolveAlgorithm::LennardJones:
-                    solve_pme_lj_yzx(pme, &h_grid, useLorentzBerthelot, cellVolume,
-                                     computeEnergyAndVirial, pme->nthread, threadIndex);
+                    solve_pme_lj_yzx(pme,
+                                     &h_grid,
+                                     useLorentzBerthelot,
+                                     cellVolume,
+                                     computeEnergyAndVirial,
+                                     pme->nthread,
+                                     threadIndex);
                     break;
 
                 default: GMX_THROW(InternalError("Test not implemented for this mode"));
@@ -659,7 +681,8 @@ void pmeSetGridLineIndices(gmx_pme_t* pme, CodePath mode, const GridLineIndicesV
     switch (mode)
     {
         case CodePath::GPU:
-            memcpy(pme_gpu_staging(pme->gpu).h_gridlineIndices, gridLineIndices.data(),
+            memcpy(pme_gpu_staging(pme->gpu).h_gridlineIndices,
+                   gridLineIndices.data(),
                    atomCount * sizeof(gridLineIndices[0]));
             break;
 
@@ -705,8 +728,7 @@ static void pmeSetGridInternal(const gmx_pme_t*                        pme,
     {
         case CodePath::GPU: // intentional absence of break, the grid will be copied from the host buffer in testing mode
         case CodePath::CPU:
-            std::memset(grid, 0,
-                        paddedGridSize[XX] * paddedGridSize[YY] * paddedGridSize[ZZ] * sizeof(ValueType));
+            std::memset(grid, 0, paddedGridSize[XX] * paddedGridSize[YY] * paddedGridSize[ZZ] * sizeof(ValueType));
             for (const auto& gridValue : gridValues)
             {
                 for (int i = 0; i < DIM; i++)
index a1eaabc71569b03b1a183af09358289f50d5db75..bbcd6972a8a2505eca7473d1929a71d1f7e5a966 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2013,2014,2015,2018,2019, by the GROMACS development team, led by
+# Copyright (c) 2013,2014,2015,2018,2019,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -32,6 +32,9 @@
 # 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 up the module library
+add_library(fft INTERFACE)
+
 gmx_add_libgromacs_sources(
      calcgrid.cpp
      fft.cpp
@@ -51,6 +54,38 @@ if (GMX_FFT_MKL)
     gmx_add_libgromacs_sources(fft_mkl.cpp)
 endif()
 
+# Source files have the following private module dependencies.
+target_link_libraries(fft PRIVATE
+                      #                      gmxlib
+                      #                      math
+                      #                      mdtypes
+                      #                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(fft PUBLIC
+target_include_directories(fft INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(fft PUBLIC
+target_link_libraries(fft INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when fft is an OBJECT target
+#target_link_libraries(fft PUBLIC legacy_api)
+#target_link_libraries(fft PRIVATE common)
+
+# Module dependencies
+# This module convey transitive dependence on these modules.
+#target_link_libraries(fft PUBLIC
+target_link_libraries(fft INTERFACE
+                      #                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(fft PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(fft PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index de0bbb1b9a10eeb98b1d857a37e79e2238b5ea44..22a842f35c13b16ba4ef8eda470eea388a1deb8f 100644 (file)
@@ -107,8 +107,11 @@ real calcFftGrid(FILE* fp, const matrix box, real gridSpacing, int minGridPoints
     {
         if (nullptr != fp)
         {
-            fprintf(fp, "Calculating fourier grid dimensions for%s%s%s\n", *nx > 0 ? "" : " X",
-                    *ny > 0 ? "" : " Y", *nz > 0 ? "" : " Z");
+            fprintf(fp,
+                    "Calculating fourier grid dimensions for%s%s%s\n",
+                    *nx > 0 ? "" : " X",
+                    *ny > 0 ? "" : " Y",
+                    *nz > 0 ? "" : " Z");
         }
     }
 
@@ -161,8 +164,14 @@ real calcFftGrid(FILE* fp, const matrix box, real gridSpacing, int minGridPoints
     *nz = n[ZZ];
     if (nullptr != fp)
     {
-        fprintf(fp, "Using a fourier grid of %dx%dx%d, spacing %.3f %.3f %.3f\n", *nx, *ny, *nz,
-                spacing[XX], spacing[YY], spacing[ZZ]);
+        fprintf(fp,
+                "Using a fourier grid of %dx%dx%d, spacing %.3f %.3f %.3f\n",
+                *nx,
+                *ny,
+                *nz,
+                spacing[XX],
+                spacing[YY],
+                spacing[ZZ]);
     }
 
     return max_spacing;
index e01d28027b527bac7492abfb37e25badf4383483..39fbed3d42294b2c1bdb2838f6bb36ca161f8063 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2009-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -86,11 +86,14 @@ FILE* debug = 0;
 
 #if GMX_FFT_FFTW3
 
+#    include <mutex>
+
 #    include "gromacs/utility/exceptions.h"
-#    include "gromacs/utility/mutex.h"
+
 /* none of the fftw3 calls, except execute(), are thread-safe, so
    we need to serialize them with this mutex. */
-static gmx::Mutex big_fftw_mutex;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static std::mutex big_fftw_mutex;
 #    define FFTW_LOCK              \
         try                        \
         {                          \
@@ -223,8 +226,14 @@ fft5d_plan fft5d_plan_3d(int                NG,
             fprintf(debug,
                     "FFT5D: N: %d, M: %d, K: %d, P: %dx%d, real2complex: %d, backward: %d, order "
                     "yz: %d, debug %d\n",
-                    NG, MG, KG, P[0], P[1], int((flags & FFT5D_REALCOMPLEX) > 0),
-                    int((flags & FFT5D_BACKWARD) > 0), int((flags & FFT5D_ORDER_YZ) > 0),
+                    NG,
+                    MG,
+                    KG,
+                    P[0],
+                    P[1],
+                    int((flags & FFT5D_REALCOMPLEX) > 0),
+                    int((flags & FFT5D_BACKWARD) > 0),
+                    int((flags & FFT5D_ORDER_YZ) > 0),
                     int((flags & FFT5D_DEBUG) > 0));
         }
         /* The check below is not correct, one prime factor 11 or 13 is ok.
@@ -582,16 +591,20 @@ fft5d_plan fft5d_plan_3d(int                NG,
 #    endif
         if ((flags & FFT5D_REALCOMPLEX) && !(flags & FFT5D_BACKWARD))
         {
-            plan->p3d = FFTW(plan_guru_dft_r2c)(/*rank*/ 3, dims,
-                                                /*howmany*/ 0, /*howmany_dims*/ nullptr,
+            plan->p3d = FFTW(plan_guru_dft_r2c)(/*rank*/ 3,
+                                                dims,
+                                                /*howmany*/ 0,
+                                                /*howmany_dims*/ nullptr,
                                                 reinterpret_cast<real*>(lin),
                                                 reinterpret_cast<FFTW(complex)*>(lout),
                                                 /*flags*/ fftwflags);
         }
         else if ((flags & FFT5D_REALCOMPLEX) && (flags & FFT5D_BACKWARD))
         {
-            plan->p3d = FFTW(plan_guru_dft_c2r)(/*rank*/ 3, dims,
-                                                /*howmany*/ 0, /*howmany_dims*/ nullptr,
+            plan->p3d = FFTW(plan_guru_dft_c2r)(/*rank*/ 3,
+                                                dims,
+                                                /*howmany*/ 0,
+                                                /*howmany_dims*/ nullptr,
                                                 reinterpret_cast<FFTW(complex)*>(lin),
                                                 reinterpret_cast<real*>(lout),
                                                 /*flags*/ fftwflags);
@@ -599,10 +612,14 @@ fft5d_plan fft5d_plan_3d(int                NG,
         else
         {
             plan->p3d = FFTW(plan_guru_dft)(
-                    /*rank*/ 3, dims,
-                    /*howmany*/ 0, /*howmany_dims*/ nullptr, reinterpret_cast<FFTW(complex)*>(lin),
+                    /*rank*/ 3,
+                    dims,
+                    /*howmany*/ 0,
+                    /*howmany_dims*/ nullptr,
+                    reinterpret_cast<FFTW(complex)*>(lin),
                     reinterpret_cast<FFTW(complex)*>(lout),
-                    /*sign*/ (flags & FFT5D_BACKWARD) ? 1 : -1, /*flags*/ fftwflags);
+                    /*sign*/ (flags & FFT5D_BACKWARD) ? 1 : -1,
+                    /*flags*/ fftwflags);
         }
 #    ifdef FFT5D_THREADS
 #        ifdef FFT5D_FFTW_THREADS
@@ -618,8 +635,7 @@ fft5d_plan fft5d_plan_3d(int                NG,
         {
             if (debug)
             {
-                fprintf(debug, "FFT5D: Plan s %d rC %d M %d pK %d C %d lsize %d\n", s, rC[s], M[s],
-                        pK[s], C[s], lsize);
+                fprintf(debug, "FFT5D: Plan s %d rC %d M %d pK %d C %d lsize %d\n", s, rC[s], M[s], pK[s], C[s], lsize);
             }
             plan->p1d[s] = static_cast<gmx_fft_t*>(malloc(sizeof(gmx_fft_t) * nthreads));
 
@@ -640,12 +656,16 @@ fft5d_plan fft5d_plan_3d(int                NG,
                                 || ((flags & FFT5D_BACKWARD) && s == 2)))
                         {
                             gmx_fft_init_many_1d_real(
-                                    &plan->p1d[s][t], rC[s], tsize,
+                                    &plan->p1d[s][t],
+                                    rC[s],
+                                    tsize,
                                     (flags & FFT5D_NOMEASURE) ? GMX_FFT_FLAG_CONSERVATIVE : 0);
                         }
                         else
                         {
-                            gmx_fft_init_many_1d(&plan->p1d[s][t], C[s], tsize,
+                            gmx_fft_init_many_1d(&plan->p1d[s][t],
+                                                 C[s],
+                                                 tsize,
                                                  (flags & FFT5D_NOMEASURE) ? GMX_FFT_FLAG_CONSERVATIVE : 0);
                         }
                     }
@@ -673,15 +693,13 @@ fft5d_plan fft5d_plan_3d(int                NG,
     {
         if ((s == 0 && !(flags & FFT5D_ORDER_YZ)) || (s == 1 && (flags & FFT5D_ORDER_YZ)))
         {
-            plan->mpip[s] = FFTW(mpi_plan_many_transpose)(nP[s], nP[s], N[s] * K[s] * pM[s] * 2, 1,
-                                                          1, (real*)lout2, (real*)lout3,
-                                                          plan->cart[s], FFTW_PATIENT);
+            plan->mpip[s] = FFTW(mpi_plan_many_transpose)(
+                    nP[s], nP[s], N[s] * K[s] * pM[s] * 2, 1, 1, (real*)lout2, (real*)lout3, plan->cart[s], FFTW_PATIENT);
         }
         else
         {
-            plan->mpip[s] = FFTW(mpi_plan_many_transpose)(nP[s], nP[s], N[s] * pK[s] * M[s] * 2, 1,
-                                                          1, (real*)lout2, (real*)lout3,
-                                                          plan->cart[s], FFTW_PATIENT);
+            plan->mpip[s] = FFTW(mpi_plan_many_transpose)(
+                    nP[s], nP[s], N[s] * pK[s] * M[s] * 2, 1, 1, (real*)lout2, (real*)lout3, plan->cart[s], FFTW_PATIENT);
         }
     }
     FFTW_UNLOCK;
@@ -1085,7 +1103,8 @@ static void print_localdata(const t_complex* lin, const char* txt, int s, fft5d_
             {
                 for (l = 0; l < ll; l++)
                 {
-                    fprintf(debug, "%f ",
+                    fprintf(debug,
+                            "%f ",
                             reinterpret_cast<const real*>(
                                     lin)[(z * xs[2] + y * xs[1]) * 2 + (x * xs[0]) * ll + l]);
                 }
@@ -1195,13 +1214,15 @@ void fft5d_execute(fft5d_plan plan, int thread, fft5d_time times)
             gmx_fft_many_1d_real(p1d[s][thread],
                                  (plan->flags & FFT5D_BACKWARD) ? GMX_FFT_COMPLEX_TO_REAL
                                                                 : GMX_FFT_REAL_TO_COMPLEX,
-                                 lin + tstart, fftout + tstart);
+                                 lin + tstart,
+                                 fftout + tstart);
         }
         else
         {
             gmx_fft_many_1d(p1d[s][thread],
                             (plan->flags & FFT5D_BACKWARD) ? GMX_FFT_BACKWARD : GMX_FFT_FORWARD,
-                            lin + tstart, fftout + tstart);
+                            lin + tstart,
+                            fftout + tstart);
         }
 
 #ifdef NOGMX
@@ -1233,8 +1254,20 @@ void fft5d_execute(fft5d_plan plan, int thread, fft5d_time times)
             {
                 tend = ((thread + 1) * pM[s] * pK[s] / plan->nthreads);
                 tstart /= C[s];
-                splitaxes(lout2, lout, N[s], M[s], K[s], pM[s], P[s], C[s], iNout[s], oNout[s],
-                          tstart % pM[s], tstart / pM[s], tend % pM[s], tend / pM[s]);
+                splitaxes(lout2,
+                          lout,
+                          N[s],
+                          M[s],
+                          K[s],
+                          pM[s],
+                          P[s],
+                          C[s],
+                          iNout[s],
+                          oNout[s],
+                          tstart % pM[s],
+                          tstart / pM[s],
+                          tend % pM[s],
+                          tend / pM[s]);
             }
 #pragma omp barrier /*barrier required before AllToAll (all input has to be their) - before timing to make timing more acurate*/
 #ifdef NOGMX
@@ -1254,7 +1287,7 @@ void fft5d_execute(fft5d_plan plan, int thread, fft5d_time times)
                     time = MPI_Wtime();
                 }
 #else
-                wallcycle_start(times, ewcPME_FFTCOMM);
+                wallcycle_start(times, WallCycleCounter::PmeFftComm);
 #endif
 #ifdef FFT5D_MPI_TRANSPOSE
                 FFTW(execute)(mpip[s]);
@@ -1265,17 +1298,21 @@ void fft5d_execute(fft5d_plan plan, int thread, fft5d_time times)
                 {
                     MPI_Alltoall(reinterpret_cast<real*>(lout2),
                                  N[s] * pM[s] * K[s] * sizeof(t_complex) / sizeof(real),
-                                 GMX_MPI_REAL, reinterpret_cast<real*>(lout3),
+                                 GMX_MPI_REAL,
+                                 reinterpret_cast<real*>(lout3),
                                  N[s] * pM[s] * K[s] * sizeof(t_complex) / sizeof(real),
-                                 GMX_MPI_REAL, cart[s]);
+                                 GMX_MPI_REAL,
+                                 cart[s]);
                 }
                 else
                 {
                     MPI_Alltoall(reinterpret_cast<real*>(lout2),
                                  N[s] * M[s] * pK[s] * sizeof(t_complex) / sizeof(real),
-                                 GMX_MPI_REAL, reinterpret_cast<real*>(lout3),
+                                 GMX_MPI_REAL,
+                                 reinterpret_cast<real*>(lout3),
                                  N[s] * M[s] * pK[s] * sizeof(t_complex) / sizeof(real),
-                                 GMX_MPI_REAL, cart[s]);
+                                 GMX_MPI_REAL,
+                                 cart[s]);
                 }
 #    else
                 GMX_RELEASE_ASSERT(false, "Invalid call to fft5d_execute");
@@ -1287,7 +1324,7 @@ void fft5d_execute(fft5d_plan plan, int thread, fft5d_time times)
                     time_mpi[s] = MPI_Wtime() - time;
                 }
 #else
-                wallcycle_stop(times, ewcPME_FFTCOMM);
+                wallcycle_stop(times, WallCycleCounter::PmeFftComm);
 #endif
             }       /*master*/
         }           /* bPrallelDim */
@@ -1322,8 +1359,20 @@ void fft5d_execute(fft5d_plan plan, int thread, fft5d_time times)
             {
                 tstart = (thread * pM[s] * pN[s] / plan->nthreads);
                 tend   = ((thread + 1) * pM[s] * pN[s] / plan->nthreads);
-                joinAxesTrans13(lin, joinin, N[s], pM[s], K[s], pM[s], P[s], C[s + 1], iNin[s + 1],
-                                oNin[s + 1], tstart % pM[s], tstart / pM[s], tend % pM[s], tend / pM[s]);
+                joinAxesTrans13(lin,
+                                joinin,
+                                N[s],
+                                pM[s],
+                                K[s],
+                                pM[s],
+                                P[s],
+                                C[s + 1],
+                                iNin[s + 1],
+                                oNin[s + 1],
+                                tstart % pM[s],
+                                tstart / pM[s],
+                                tend % pM[s],
+                                tend / pM[s]);
             }
         }
         else
@@ -1332,8 +1381,20 @@ void fft5d_execute(fft5d_plan plan, int thread, fft5d_time times)
             {
                 tstart = (thread * pK[s] * pN[s] / plan->nthreads);
                 tend   = ((thread + 1) * pK[s] * pN[s] / plan->nthreads);
-                joinAxesTrans12(lin, joinin, N[s], M[s], pK[s], pN[s], P[s], C[s + 1], iNin[s + 1],
-                                oNin[s + 1], tstart % pN[s], tstart / pN[s], tend % pN[s], tend / pN[s]);
+                joinAxesTrans12(lin,
+                                joinin,
+                                N[s],
+                                M[s],
+                                pK[s],
+                                pN[s],
+                                P[s],
+                                C[s + 1],
+                                iNin[s + 1],
+                                oNin[s + 1],
+                                tstart % pN[s],
+                                tstart / pN[s],
+                                tend % pN[s],
+                                tend / pN[s]);
             }
         }
 
@@ -1368,12 +1429,15 @@ void fft5d_execute(fft5d_plan plan, int thread, fft5d_time times)
     {
         gmx_fft_many_1d_real(p1d[s][thread],
                              (plan->flags & FFT5D_BACKWARD) ? GMX_FFT_COMPLEX_TO_REAL : GMX_FFT_REAL_TO_COMPLEX,
-                             lin + tstart, lout + tstart);
+                             lin + tstart,
+                             lout + tstart);
     }
     else
     {
-        gmx_fft_many_1d(p1d[s][thread], (plan->flags & FFT5D_BACKWARD) ? GMX_FFT_BACKWARD : GMX_FFT_FORWARD,
-                        lin + tstart, lout + tstart);
+        gmx_fft_many_1d(p1d[s][thread],
+                        (plan->flags & FFT5D_BACKWARD) ? GMX_FFT_BACKWARD : GMX_FFT_FORWARD,
+                        lin + tstart,
+                        lout + tstart);
     }
     /* ------------ END FFT ---------*/
 
@@ -1594,7 +1658,13 @@ void fft5d_compare_data(const t_complex* lin, const t_complex* in, fft5d_plan pl
                         if (std::fabs(a - b) > 2 * NG[0] * NG[1] * NG[2] * GMX_REAL_EPS)
                         {
                             printf("result incorrect on %d,%d at %d,%d,%d: FFT5D:%f reference:%f\n",
-                                   coor[0], coor[1], x, y, z, a, b);
+                                   coor[0],
+                                   coor[1],
+                                   x,
+                                   y,
+                                   z,
+                                   a,
+                                   b);
                         }
                         /*                        assert(fabs(a-b)<2*NG[0]*NG[1]*NG[2]*GMX_REAL_EPS);*/
                     }
index 71d86817a07e1079ad62a523fca175d0d46716fb..b4e5d008e4d7aba64416cc27d44331b4ee1bdea9 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2009-2017, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -73,7 +73,7 @@ struct fft5d_time_t
 typedef struct fft5d_time_t* fft5d_time;
 #else
 #    include "gromacs/timing/wallcycle.h"
-typedef gmx_wallcycle_t fft5d_time;
+typedef gmx_wallcycle* fft5d_time;
 #endif
 
 namespace gmx
index 33c9b8c1841a904ede1190da3a9f2aada1d5a27e..f525af402609cefe4452405fc353b557fa77323a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2003 David van der Spoel, Erik Lindahl, University of Groningen.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cerrno>
 #include <cstdlib>
 
+#include <mutex>
+
 #include <fftw3.h>
 
 #include "gromacs/fft/fft.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
-#include "gromacs/utility/mutex.h"
 
 #if GMX_DOUBLE
 #    define FFTWPREFIX(name) fftw_##name
@@ -56,7 +57,8 @@
 
 /* none of the fftw3 calls, except execute(), are thread-safe, so
    we need to serialize them with this mutex. */
-static gmx::Mutex big_fftw_mutex;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static std::mutex big_fftw_mutex;
 #define FFTW_LOCK              \
     try                        \
     {                          \
@@ -176,22 +178,22 @@ int gmx_fft_init_many_1d(gmx_fft_t* pfft, int nx, int howmany, gmx_fft_flag flag
                                   fftw_complex *out, const int *onembed,
                                   int ostride, int odist,
                                   int sign, unsigned flags */
-    fft->plan[0][0][0] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, up1, &nx, 1, nx, up2, &nx, 1,
-                                                   nx, FFTW_BACKWARD, fftw_flags);
-    fft->plan[0][0][1] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, up1, &nx, 1, nx, up2, &nx, 1,
-                                                   nx, FFTW_FORWARD, fftw_flags);
-    fft->plan[0][1][0] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, up1, &nx, 1, nx, up1, &nx, 1,
-                                                   nx, FFTW_BACKWARD, fftw_flags);
-    fft->plan[0][1][1] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, up1, &nx, 1, nx, up1, &nx, 1,
-                                                   nx, FFTW_FORWARD, fftw_flags);
-    fft->plan[1][0][0] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, p1, &nx, 1, nx, p2, &nx, 1, nx,
-                                                   FFTW_BACKWARD, fftw_flags);
-    fft->plan[1][0][1] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, p1, &nx, 1, nx, p2, &nx, 1, nx,
-                                                   FFTW_FORWARD, fftw_flags);
-    fft->plan[1][1][0] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, p1, &nx, 1, nx, p1, &nx, 1, nx,
-                                                   FFTW_BACKWARD, fftw_flags);
-    fft->plan[1][1][1] = FFTWPREFIX(plan_many_dft)(1, &nx, howmany, p1, &nx, 1, nx, p1, &nx, 1, nx,
-                                                   FFTW_FORWARD, fftw_flags);
+    fft->plan[0][0][0] = FFTWPREFIX(plan_many_dft)(
+            1, &nx, howmany, up1, &nx, 1, nx, up2, &nx, 1, nx, FFTW_BACKWARD, fftw_flags);
+    fft->plan[0][0][1] = FFTWPREFIX(plan_many_dft)(
+            1, &nx, howmany, up1, &nx, 1, nx, up2, &nx, 1, nx, FFTW_FORWARD, fftw_flags);
+    fft->plan[0][1][0] = FFTWPREFIX(plan_many_dft)(
+            1, &nx, howmany, up1, &nx, 1, nx, up1, &nx, 1, nx, FFTW_BACKWARD, fftw_flags);
+    fft->plan[0][1][1] = FFTWPREFIX(plan_many_dft)(
+            1, &nx, howmany, up1, &nx, 1, nx, up1, &nx, 1, nx, FFTW_FORWARD, fftw_flags);
+    fft->plan[1][0][0] = FFTWPREFIX(plan_many_dft)(
+            1, &nx, howmany, p1, &nx, 1, nx, p2, &nx, 1, nx, FFTW_BACKWARD, fftw_flags);
+    fft->plan[1][0][1] = FFTWPREFIX(plan_many_dft)(
+            1, &nx, howmany, p1, &nx, 1, nx, p2, &nx, 1, nx, FFTW_FORWARD, fftw_flags);
+    fft->plan[1][1][0] = FFTWPREFIX(plan_many_dft)(
+            1, &nx, howmany, p1, &nx, 1, nx, p1, &nx, 1, nx, FFTW_BACKWARD, fftw_flags);
+    fft->plan[1][1][1] = FFTWPREFIX(plan_many_dft)(
+            1, &nx, howmany, p1, &nx, 1, nx, p1, &nx, 1, nx, FFTW_FORWARD, fftw_flags);
 
     for (i = 0; i < 2; i++)
     {
@@ -294,31 +296,103 @@ int gmx_fft_init_many_1d_real(gmx_fft_t* pfft, int nx, int howmany, gmx_fft_flag
                                       fftw_complex *out, const int *onembed,
                                       int ostride, int odist,
                                       unsigned flag    */
-    fft->plan[0][0][1] = FFTWPREFIX(plan_many_dft_r2c)(
-            1, &nx, howmany, up1, nullptr, 1, (nx / 2 + 1) * 2,
-            reinterpret_cast<FFTWPREFIX(complex)*>(up2), nullptr, 1, (nx / 2 + 1), fftw_flags);
-    fft->plan[0][1][1] = FFTWPREFIX(plan_many_dft_r2c)(
-            1, &nx, howmany, up1, nullptr, 1, (nx / 2 + 1) * 2,
-            reinterpret_cast<FFTWPREFIX(complex)*>(up1), nullptr, 1, (nx / 2 + 1), fftw_flags);
-    fft->plan[1][0][1] = FFTWPREFIX(plan_many_dft_r2c)(
-            1, &nx, howmany, p1, nullptr, 1, (nx / 2 + 1) * 2,
-            reinterpret_cast<FFTWPREFIX(complex)*>(p2), nullptr, 1, (nx / 2 + 1), fftw_flags);
-    fft->plan[1][1][1] = FFTWPREFIX(plan_many_dft_r2c)(
-            1, &nx, howmany, p1, nullptr, 1, (nx / 2 + 1) * 2,
-            reinterpret_cast<FFTWPREFIX(complex)*>(p1), nullptr, 1, (nx / 2 + 1), fftw_flags);
-
-    fft->plan[0][0][0] = FFTWPREFIX(plan_many_dft_c2r)(
-            1, &nx, howmany, reinterpret_cast<FFTWPREFIX(complex)*>(up1), nullptr, 1, (nx / 2 + 1),
-            up2, nullptr, 1, (nx / 2 + 1) * 2, fftw_flags);
-    fft->plan[0][1][0] = FFTWPREFIX(plan_many_dft_c2r)(
-            1, &nx, howmany, reinterpret_cast<FFTWPREFIX(complex)*>(up1), nullptr, 1, (nx / 2 + 1),
-            up1, nullptr, 1, (nx / 2 + 1) * 2, fftw_flags);
-    fft->plan[1][0][0] = FFTWPREFIX(plan_many_dft_c2r)(
-            1, &nx, howmany, reinterpret_cast<FFTWPREFIX(complex)*>(p1), nullptr, 1, (nx / 2 + 1),
-            p2, nullptr, 1, (nx / 2 + 1) * 2, fftw_flags);
-    fft->plan[1][1][0] = FFTWPREFIX(plan_many_dft_c2r)(
-            1, &nx, howmany, reinterpret_cast<FFTWPREFIX(complex)*>(p1), nullptr, 1, (nx / 2 + 1),
-            p1, nullptr, 1, (nx / 2 + 1) * 2, fftw_flags);
+    fft->plan[0][0][1] = FFTWPREFIX(plan_many_dft_r2c)(1,
+                                                       &nx,
+                                                       howmany,
+                                                       up1,
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1) * 2,
+                                                       reinterpret_cast<FFTWPREFIX(complex)*>(up2),
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1),
+                                                       fftw_flags);
+    fft->plan[0][1][1] = FFTWPREFIX(plan_many_dft_r2c)(1,
+                                                       &nx,
+                                                       howmany,
+                                                       up1,
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1) * 2,
+                                                       reinterpret_cast<FFTWPREFIX(complex)*>(up1),
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1),
+                                                       fftw_flags);
+    fft->plan[1][0][1] = FFTWPREFIX(plan_many_dft_r2c)(1,
+                                                       &nx,
+                                                       howmany,
+                                                       p1,
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1) * 2,
+                                                       reinterpret_cast<FFTWPREFIX(complex)*>(p2),
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1),
+                                                       fftw_flags);
+    fft->plan[1][1][1] = FFTWPREFIX(plan_many_dft_r2c)(1,
+                                                       &nx,
+                                                       howmany,
+                                                       p1,
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1) * 2,
+                                                       reinterpret_cast<FFTWPREFIX(complex)*>(p1),
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1),
+                                                       fftw_flags);
+
+    fft->plan[0][0][0] = FFTWPREFIX(plan_many_dft_c2r)(1,
+                                                       &nx,
+                                                       howmany,
+                                                       reinterpret_cast<FFTWPREFIX(complex)*>(up1),
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1),
+                                                       up2,
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1) * 2,
+                                                       fftw_flags);
+    fft->plan[0][1][0] = FFTWPREFIX(plan_many_dft_c2r)(1,
+                                                       &nx,
+                                                       howmany,
+                                                       reinterpret_cast<FFTWPREFIX(complex)*>(up1),
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1),
+                                                       up1,
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1) * 2,
+                                                       fftw_flags);
+    fft->plan[1][0][0] = FFTWPREFIX(plan_many_dft_c2r)(1,
+                                                       &nx,
+                                                       howmany,
+                                                       reinterpret_cast<FFTWPREFIX(complex)*>(p1),
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1),
+                                                       p2,
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1) * 2,
+                                                       fftw_flags);
+    fft->plan[1][1][0] = FFTWPREFIX(plan_many_dft_c2r)(1,
+                                                       &nx,
+                                                       howmany,
+                                                       reinterpret_cast<FFTWPREFIX(complex)*>(p1),
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1),
+                                                       p1,
+                                                       nullptr,
+                                                       1,
+                                                       (nx / 2 + 1) * 2,
+                                                       fftw_flags);
 
     for (i = 0; i < 2; i++)
     {
@@ -478,7 +552,8 @@ int gmx_fft_1d(gmx_fft_t fft, enum gmx_fft_direction dir, void* in_data, void* o
     }
 
     FFTWPREFIX(execute_dft)
-    (fft->plan[aligned][inplace][isforward], static_cast<FFTWPREFIX(complex)*>(in_data),
+    (fft->plan[aligned][inplace][isforward],
+     static_cast<FFTWPREFIX(complex)*>(in_data),
      static_cast<FFTWPREFIX(complex)*>(out_data));
 
     return 0;
@@ -506,13 +581,15 @@ int gmx_fft_1d_real(gmx_fft_t fft, enum gmx_fft_direction dir, void* in_data, vo
     if (isforward)
     {
         FFTWPREFIX(execute_dft_r2c)
-        (fft->plan[aligned][inplace][isforward], static_cast<real*>(in_data),
+        (fft->plan[aligned][inplace][isforward],
+         static_cast<real*>(in_data),
          static_cast<FFTWPREFIX(complex)*>(out_data));
     }
     else
     {
         FFTWPREFIX(execute_dft_c2r)
-        (fft->plan[aligned][inplace][isforward], static_cast<FFTWPREFIX(complex)*>(in_data),
+        (fft->plan[aligned][inplace][isforward],
+         static_cast<FFTWPREFIX(complex)*>(in_data),
          static_cast<real*>(out_data));
     }
 
@@ -541,13 +618,15 @@ int gmx_fft_2d_real(gmx_fft_t fft, enum gmx_fft_direction dir, void* in_data, vo
     if (isforward)
     {
         FFTWPREFIX(execute_dft_r2c)
-        (fft->plan[aligned][inplace][isforward], static_cast<real*>(in_data),
+        (fft->plan[aligned][inplace][isforward],
+         static_cast<real*>(in_data),
          static_cast<FFTWPREFIX(complex)*>(out_data));
     }
     else
     {
         FFTWPREFIX(execute_dft_c2r)
-        (fft->plan[aligned][inplace][isforward], static_cast<FFTWPREFIX(complex)*>(in_data),
+        (fft->plan[aligned][inplace][isforward],
+         static_cast<FFTWPREFIX(complex)*>(in_data),
          static_cast<real*>(out_data));
     }
 
index 8b842fe5ac5f9130e9354aedcdb5e64e01395b14..33d916ec20bf731fab6033a0f4f54ce552bcdf64 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 1991-2005 David van der Spoel, Erik Lindahl, University of Groningen.
- * Copyright (c) 2013,2014,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,12 +87,19 @@ int gmx_parallel_3dfft_init(gmx_parallel_3dfft_t* pfft_setup,
         Kb = M; /* currently always true because ORDER_YZ always set */
     }
 
-    (*pfft_setup)->p1 = fft5d_plan_3d(rN, M, K, rcomm, flags, reinterpret_cast<t_complex**>(real_data),
-                                      complex_data, &buf1, &buf2, nthreads, realGridAllocation);
+    (*pfft_setup)->p1 = fft5d_plan_3d(
+            rN, M, K, rcomm, flags, reinterpret_cast<t_complex**>(real_data), complex_data, &buf1, &buf2, nthreads, realGridAllocation);
 
-    (*pfft_setup)->p2 = fft5d_plan_3d(
-            Nb, Mb, Kb, rcomm, (flags | FFT5D_BACKWARD | FFT5D_NOMALLOC) ^ FFT5D_ORDER_YZ,
-            complex_data, reinterpret_cast<t_complex**>(real_data), &buf1, &buf2, nthreads);
+    (*pfft_setup)->p2 = fft5d_plan_3d(Nb,
+                                      Mb,
+                                      Kb,
+                                      rcomm,
+                                      (flags | FFT5D_BACKWARD | FFT5D_NOMALLOC) ^ FFT5D_ORDER_YZ,
+                                      complex_data,
+                                      reinterpret_cast<t_complex**>(real_data),
+                                      &buf1,
+                                      &buf2,
+                                      nthreads);
 
     return static_cast<int>((*pfft_setup)->p1 != nullptr && (*pfft_setup)->p2 != nullptr);
 }
@@ -163,13 +170,12 @@ int gmx_parallel_3dfft_complex_limits(gmx_parallel_3dfft_t pfft_setup,
 int gmx_parallel_3dfft_execute(gmx_parallel_3dfft_t   pfft_setup,
                                enum gmx_fft_direction dir,
                                int                    thread,
-                               gmx_wallcycle_t        wcycle)
+                               gmx_wallcycle        wcycle)
 {
     if (((pfft_setup->p1->flags & FFT5D_REALCOMPLEX) == 0)
         ^ (dir == GMX_FFT_FORWARD || dir == GMX_FFT_BACKWARD))
     {
-        gmx_fatal(FARGS,
-                  "Invalid transform. Plan and execution don't match regarding reel/complex");
+        gmx_fatal(FARGS, "Invalid transform. Plan and execution don't match regarding reel/complex");
     }
     if (dir == GMX_FFT_FORWARD || dir == GMX_FFT_REAL_TO_COMPLEX)
     {
index 91cd66103f9ec39f37d5dd72ae1b024815155e46..5652f4c42237bd4f19e04046b76a97c7de0ad09b 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 1991-2005 David van der Spoel, Erik Lindahl, University of Groningen.
- * Copyright (c) 2013,2014,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ int gmx_parallel_3dfft_complex_limits(gmx_parallel_3dfft_t pfft_setup,
 int gmx_parallel_3dfft_execute(gmx_parallel_3dfft_t   pfft_setup,
                                enum gmx_fft_direction dir,
                                int                    thread,
-                               gmx_wallcycle_t        wcycle);
+                               gmx_wallcycle        wcycle);
 
 
 /*! \brief Release all data in parallel fft setup
diff --git a/src/gromacs/fft/tests/.clang-tidy b/src/gromacs/fft/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index f422241309002388ef9fbf90d4fd41913feef507..10bb57b5070c1813ce46fc6a776624f3df2ca902 100644 (file)
@@ -311,8 +311,8 @@ TEST_F(FFFTest3D, Real5_6_9)
     gmx_parallel_3dfft_execute(fft_, GMX_FFT_COMPLEX_TO_REAL, 0, nullptr);
     for (int i = 0; i < ndata[0] * ndata[1]; i++) // check sequence but skip unused data
     {
-        checker_.checkSequenceArray(ndata[2], rdata + i * rsize[2],
-                                    gmx::formatString("backward %d", i).c_str());
+        checker_.checkSequenceArray(
+                ndata[2], rdata + i * rsize[2], gmx::formatString("backward %d", i).c_str());
     }
 }
 
index f0e81bb03cd50c4434b9afc32eaf3138b0fd7053..16c4892c79de83f2dcfca2b70740aa78fbee9a2e 100644 (file)
@@ -32,6 +32,8 @@
 # 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 up the module library
+add_library(fileio INTERFACE)
 file(GLOB FILEIO_SOURCES *.cpp)
 
 if(GMX_USE_PLUGINS)
@@ -47,18 +49,39 @@ else()
     list(FILTER FILEIO_SOURCES EXCLUDE REGEX ".*vmdio.cpp$")
 endif()
 
-target_sources(libgromacs PRIVATE ${FILEIO_SOURCES})
+# Source files have the following private module dependencies.
+target_link_libraries(fileio PRIVATE
+#                      gmxlib
+#                      math
+#                      mdtypes
+#                      tng_io
+                      )
 
-if(GMX_INSTALL_LEGACY_API)
-  install(FILES
-          oenv.h
-         confio.h
-          pdbio.h
-          tpxio.h
-          trxio.h
-         filetypes.h
-          DESTINATION include/gromacs/fileio)
-endif()
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(fileio PUBLIC
+target_include_directories(fileio INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(fileio PUBLIC
+target_link_libraries(fileio INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when fileio is an OBJECT target
+#target_link_libraries(fileio PUBLIC legacy_api)
+#target_link_libraries(fileio PRIVATE common)
+
+# Module dependencies
+# fileio interfaces convey transitive dependence on these modules.
+#target_link_libraries(fileio PUBLIC
+target_link_libraries(fileio INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(fileio PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(fileio PRIVATE legacy_modules)
+
+target_sources(libgromacs PRIVATE ${FILEIO_SOURCES})
 
 if (BUILD_TESTING)
      add_subdirectory(tests)
index fadc3d283e1e015c38ae83c6a8378f499dfecc65..5b7a215af76cf376f82f620ed839cf274743b73c 100644 (file)
@@ -77,6 +77,7 @@
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/baseversion.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/gmxassert.h"
@@ -84,7 +85,7 @@
 #include "gromacs/utility/keyvaluetree.h"
 #include "gromacs/utility/keyvaluetreebuilder.h"
 #include "gromacs/utility/keyvaluetreeserializer.h"
-#include "gromacs/utility/mdmodulenotification.h"
+#include "gromacs/utility/mdmodulesnotifiers.h"
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/sysinfo.h"
@@ -157,7 +158,7 @@ enum cptv
     cptv_RemoveBuildMachineInformation, /**< remove functionality that makes mdrun builds non-reproducible */
     cptv_ComPrevStepAsPullGroupReference, /**< Allow using COM of previous step as pull group PBC reference */
     cptv_PullAverage,      /**< Added possibility to output average pull force and position */
-    cptv_MdModules,        /**< Added checkpointing for MdModules */
+    cptv_MDModules,        /**< Added checkpointing for MDModules */
     cptv_ModularSimulator, /**< Added checkpointing for modular simulator */
     cptv_Count             /**< the total number of cptv versions */
 };
@@ -179,182 +180,228 @@ enum cptv
  * the correct code path. */
 static const int cpt_version = cptv_Count - 1;
 
+const char* enumValueToString(StateEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StateEntry, const char*> stateEntryNames = {
+        "FE-lambda",
+        "box",
+        "box-rel",
+        "box-v",
+        "pres_prev",
+        "nosehoover-xi",
+        "thermostat-integral",
+        "x",
+        "v",
+        "sdx-unsupported",
+        "CGp",
+        "LD-rng-unsupported",
+        "LD-rng-i-unsupported",
+        "disre_initf",
+        "disre_rm3tav",
+        "orire_initf",
+        "orire_Dtav",
+        "svir_prev",
+        "nosehoover-vxi",
+        "v_eta",
+        "vol0",
+        "nhpres_xi",
+        "nhpres_vxi",
+        "fvir_prev",
+        "fep_state",
+        "MC-rng-unsupported",
+        "MC-rng-i-unsupported",
+        "barostat-integral"
+    };
+    return stateEntryNames[enumValue];
+}
 
-const char* est_names[estNR] = { "FE-lambda",
-                                 "box",
-                                 "box-rel",
-                                 "box-v",
-                                 "pres_prev",
-                                 "nosehoover-xi",
-                                 "thermostat-integral",
-                                 "x",
-                                 "v",
-                                 "sdx-unsupported",
-                                 "CGp",
-                                 "LD-rng-unsupported",
-                                 "LD-rng-i-unsupported",
-                                 "disre_initf",
-                                 "disre_rm3tav",
-                                 "orire_initf",
-                                 "orire_Dtav",
-                                 "svir_prev",
-                                 "nosehoover-vxi",
-                                 "v_eta",
-                                 "vol0",
-                                 "nhpres_xi",
-                                 "nhpres_vxi",
-                                 "fvir_prev",
-                                 "fep_state",
-                                 "MC-rng-unsupported",
-                                 "MC-rng-i-unsupported",
-                                 "barostat-integral" };
-
-enum
-{
-    eeksEKIN_N,
-    eeksEKINH,
-    eeksDEKINDL,
-    eeksMVCOS,
-    eeksEKINF,
-    eeksEKINO,
-    eeksEKINSCALEF,
-    eeksEKINSCALEH,
-    eeksVSCALE,
-    eeksEKINTOTAL,
-    eeksNR
+enum class StateKineticEntry : int
+{
+    EkinNumber,
+    EkinHalfStep,
+    DEkinDLambda,
+    Mvcos,
+    EkinFullStep,
+    EkinHalfStepOld,
+    EkinNoseHooverScaleFullStep,
+    EkinNoseHooverScaleHalfStep,
+    VelocityScale,
+    EkinTotal,
+    Count
 };
 
-static const char* eeks_names[eeksNR] = { "Ekin_n",         "Ekinh",          "dEkindlambda",
-                                          "mv_cos",         "Ekinf",          "Ekinh_old",
-                                          "EkinScaleF_NHC", "EkinScaleH_NHC", "Vscale_NHC",
-                                          "Ekin_Total" };
-
-enum
-{
-    eenhENERGY_N,
-    eenhENERGY_AVER,
-    eenhENERGY_SUM,
-    eenhENERGY_NSUM,
-    eenhENERGY_SUM_SIM,
-    eenhENERGY_NSUM_SIM,
-    eenhENERGY_NSTEPS,
-    eenhENERGY_NSTEPS_SIM,
-    eenhENERGY_DELTA_H_NN,
-    eenhENERGY_DELTA_H_LIST,
-    eenhENERGY_DELTA_H_STARTTIME,
-    eenhENERGY_DELTA_H_STARTLAMBDA,
-    eenhNR
+static const char* enumValueToString(StateKineticEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StateKineticEntry, const char*> stateKineticEntryNames = {
+        "Ekin_n",    "Ekinh",          "dEkindlambda",   "mv_cos",     "Ekinf",
+        "Ekinh_old", "EkinScaleF_NHC", "EkinScaleH_NHC", "Vscale_NHC", "Ekin_Total"
+    };
+    return stateKineticEntryNames[enumValue];
+}
+
+enum class StateEnergyEntry : int
+{
+    N,
+    Aver,
+    Sum,
+    NumSum,
+    SumSim,
+    NumSumSim,
+    NumSteps,
+    NumStepsSim,
+    DeltaHNN,
+    DeltaHList,
+    DeltaHStartTime,
+    DeltaHStartLambda,
+    Count
 };
 
-enum
+enum class StatePullEntry : int
 {
-    epullhPULL_NUMCOORDINATES,
-    epullhPULL_NUMGROUPS,
-    epullhPULL_NUMVALUESINXSUM,
-    epullhPULL_NUMVALUESINFSUM,
-    epullhNR
+    NumCoordinates,
+    NumGroups,
+    NumValuesInXSum,
+    NumValuesInFSum,
+    Count
 };
 
-enum
+enum class StatePullCoordEntry : int
 {
-    epullcoordh_VALUE_REF_SUM,
-    epullcoordh_VALUE_SUM,
-    epullcoordh_DR01_SUM,
-    epullcoordh_DR23_SUM,
-    epullcoordh_DR45_SUM,
-    epullcoordh_FSCAL_SUM,
-    epullcoordh_DYNAX_SUM,
-    epullcoordh_NR
+    ValueReferenceSum,
+    ValueSum,
+    DR01Sum,
+    DR23Sum,
+    DR45Sum,
+    FScalarSum,
+    DynaxSum,
+    Count
 };
 
-enum
+static const char* enumValueToString(StatePullCoordEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StatePullCoordEntry, const char*> statePullCoordEntryNames = {
+        "reference-sum", "sum", "dr01-sum", "dr23-sum", "dr45-sum", "fscal-sum", "dynax-sum"
+    };
+    return statePullCoordEntryNames[enumValue];
+}
+
+enum class StatePullGroupEntry : int
 {
-    epullgrouph_X_SUM,
-    epullgrouph_NR
+    XSum,
+    Count
 };
 
-static const char* eenh_names[eenhNR] = { "energy_n",
-                                          "energy_aver",
-                                          "energy_sum",
-                                          "energy_nsum",
-                                          "energy_sum_sim",
-                                          "energy_nsum_sim",
-                                          "energy_nsteps",
-                                          "energy_nsteps_sim",
-                                          "energy_delta_h_nn",
-                                          "energy_delta_h_list",
-                                          "energy_delta_h_start_time",
-                                          "energy_delta_h_start_lambda" };
-
-static const char* ePullhNames[epullhNR] = { "pullhistory_numcoordinates", "pullhistory_numgroups",
-                                             "pullhistory_numvaluesinxsum",
-                                             "pullhistory_numvaluesinfsum" };
+static const char* enumValueToString(StatePullGroupEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StatePullGroupEntry, const char*> statePullGroupEntryNames = {
+        "coordinate-sum"
+    };
+    return statePullGroupEntryNames[enumValue];
+}
+
+static const char* enumValueToString(StateEnergyEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StateEnergyEntry, const char*> stateEnergyEntryNames = {
+        "energy_n",
+        "energy_aver",
+        "energy_sum",
+        "energy_nsum",
+        "energy_sum_sim",
+        "energy_nsum_sim",
+        "energy_nsteps",
+        "energy_nsteps_sim",
+        "energy_delta_h_nn",
+        "energy_delta_h_list",
+        "energy_delta_h_start_time",
+        "energy_delta_h_start_lambda"
+    };
+    return stateEnergyEntryNames[enumValue];
+}
+
+static const char* enumValueToString(StatePullEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StatePullEntry, const char*> statePullEntryNames = {
+        "pullhistory_numcoordinates",
+        "pullhistory_numgroups",
+        "pullhistory_numvaluesinxsum",
+        "pullhistory_numvaluesinfsum"
+    };
+    return statePullEntryNames[enumValue];
+}
 
 /* free energy history variables -- need to be preserved over checkpoint */
-enum
-{
-    edfhBEQUIL,
-    edfhNATLAMBDA,
-    edfhWLHISTO,
-    edfhWLDELTA,
-    edfhSUMWEIGHTS,
-    edfhSUMDG,
-    edfhSUMMINVAR,
-    edfhSUMVAR,
-    edfhACCUMP,
-    edfhACCUMM,
-    edfhACCUMP2,
-    edfhACCUMM2,
-    edfhTIJ,
-    edfhTIJEMP,
-    edfhNR
-};
-/* free energy history variable names  */
-static const char* edfh_names[edfhNR] = { "bEquilibrated",
-                                          "N_at_state",
-                                          "Wang-Landau Histogram",
-                                          "Wang-Landau Delta",
-                                          "Weights",
-                                          "Free Energies",
-                                          "minvar",
-                                          "variance",
-                                          "accumulated_plus",
-                                          "accumulated_minus",
-                                          "accumulated_plus_2",
-                                          "accumulated_minus_2",
-                                          "Tij",
-                                          "Tij_empirical" };
-
-/* AWH biasing history variables */
-enum
-{
-    eawhhIN_INITIAL,
-    eawhhEQUILIBRATEHISTOGRAM,
-    eawhhHISTSIZE,
-    eawhhNPOINTS,
-    eawhhCOORDPOINT,
-    eawhhUMBRELLAGRIDPOINT,
-    eawhhUPDATELIST,
-    eawhhLOGSCALEDSAMPLEWEIGHT,
-    eawhhNUMUPDATES,
-    eawhhFORCECORRELATIONGRID,
-    eawhhNR
+enum class StateFepEntry : int
+{
+    IsEquilibrated,
+    NumAtLambda,
+    WangLandauHistogram,
+    WangLandauDelta,
+    SumWeights,
+    SumDG,
+    SumMinVar,
+    SumVar,
+    Accump,
+    Accumm,
+    Accump2,
+    Accumm2,
+    Tij,
+    TijEmp,
+    Count
 };
 
-static const char* eawhh_names[eawhhNR] = { "awh_in_initial", "awh_equilibrateHistogram",
-                                            "awh_histsize",   "awh_npoints",
-                                            "awh_coordpoint", "awh_umbrellaGridpoint",
-                                            "awh_updatelist", "awh_logScaledSampleWeight",
-                                            "awh_numupdates", "awh_forceCorrelationGrid" };
+//! free energy history names
+static const char* enumValueToString(StateFepEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StateFepEntry, const char*> stateFepEntryNames = {
+        "bEquilibrated",
+        "N_at_state",
+        "Wang-Landau Histogram",
+        "Wang-Landau Delta",
+        "Weights",
+        "Free Energies",
+        "minvar",
+        "variance",
+        "accumulated_plus",
+        "accumulated_minus",
+        "accumulated_plus_2",
+        "accumulated_minus_2",
+        "Tij",
+        "Tij_empirical"
+    };
+    return stateFepEntryNames[enumValue];
+}
 
-enum
-{
-    epullsPREVSTEPCOM,
-    epullsNR
+//! AWH biasing history variables
+enum class StateAwhEntry : int
+{
+    InInitial,
+    EquilibrateHistogram,
+    HistogramSize,
+    NumPoints,
+    CoordPoint,
+    UmbrellaGridPoint,
+    UpdateList,
+    LogScaledSampleWeight,
+    NumUpdates,
+    ForceCorrelationGrid,
+    Count
 };
 
-static const char* epull_prev_step_com_names[epullsNR] = { "Pull groups prev step COM" };
+static const char* enumValueToString(StateAwhEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StateAwhEntry, const char*> stateAwhEntryNames = {
+        "awh_in_initial", "awh_equilibrateHistogram", "awh_histsize",   "awh_npoints",
+        "awh_coordpoint", "awh_umbrellaGridpoint",    "awh_updatelist", "awh_logScaledSampleWeight",
+        "awh_numupdates", "awh_forceCorrelationGrid"
+    };
+    return stateAwhEntryNames[enumValue];
+}
 
+enum class StatePullCommunicationEntry : int
+{
+    PreviousStepCom,
+    Count
+};
 
 //! Higher level vector element type, only used for formatting checkpoint dumps
 enum class CptElementType
@@ -365,35 +412,6 @@ enum class CptElementType
     matrix3x3 //!< float[3][3] or double[3][3], not linked to precision of type real
 };
 
-//! \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
-    accWeightHistogram, //!< Accelerated weight histogram method state
-    pullState,          //!< COM of previous step.
-    pullHistory         //!< Pull history statistics (sums since last written output)
-};
-
-//! \brief Return the name of a checkpoint entry based on part and part entry
-static const char* entryName(StatePart part, int ecpt)
-{
-    switch (part)
-    {
-        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];
-        case StatePart::accWeightHistogram: return eawhh_names[ecpt];
-        case StatePart::pullState: return epull_prev_step_com_names[ecpt];
-        case StatePart::pullHistory: return ePullhNames[ecpt];
-    }
-
-    return nullptr;
-}
-
 static void cp_warning(FILE* fp)
 {
     fprintf(fp, "\nWARNING: Checkpoint file is corrupted or truncated\n\n");
@@ -457,6 +475,40 @@ static int do_cpt_u_chars(XDR* xd, const char* desc, int n, unsigned char* i, FI
     return 0;
 }
 
+template<typename EnumType>
+static int do_cpt_enum_as_int(XDR* xd, const char* desc, EnumType* enumValue, FILE* list)
+{
+    static_assert(std::is_same<std::underlying_type_t<EnumType>, int>::value,
+                  "Only enums with underlying type int are supported.");
+    auto castedValue = static_cast<int>(*enumValue);
+    if (xdr_int(xd, &castedValue) == 0)
+    {
+        return -1;
+    }
+    *enumValue = static_cast<EnumType>(castedValue);
+    if (list)
+    {
+        fprintf(list, "%s = %d\n", desc, castedValue);
+    }
+    return 0;
+}
+
+template<typename EnumType>
+static int do_cpt_n_enum_as_int(XDR* xd, const char* desc, int n, EnumType* enumValue, FILE* list)
+{
+    bool_t res = 1;
+    for (int j = 0; j < n && res; j++)
+    {
+        res &= do_cpt_enum_as_int<EnumType>(xd, desc, &enumValue[j], list);
+    }
+    if (res == 0)
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
 static void do_cpt_int_err(XDR* xd, const char* desc, int* i, FILE* list)
 {
     if (do_cpt_int(xd, desc, i, list) < 0)
@@ -540,29 +592,29 @@ struct xdr_type
 template<>
 struct xdr_type<int>
 {
-    static const int value = xdr_datatype_int;
+    static const XdrDataType value = XdrDataType::Int;
 };
 
 template<>
 struct xdr_type<float>
 {
-    static const int value = xdr_datatype_float;
+    static const XdrDataType value = XdrDataType::Float;
 };
 
 template<>
 struct xdr_type<double>
 {
-    static const int value = xdr_datatype_double;
+    static const XdrDataType value = XdrDataType::Double;
 };
 
-//! \brief Returns size in byte of an xdr_datatype
-static inline unsigned int sizeOfXdrType(int xdrType)
+//! \brief Returns size in byte of an XdrDataType
+static inline unsigned int sizeOfXdrType(XdrDataType xdrType)
 {
     switch (xdrType)
     {
-        case xdr_datatype_int: return sizeof(int);
-        case xdr_datatype_float: return sizeof(float);
-        case xdr_datatype_double: return sizeof(double);
+        case XdrDataType::Int: return sizeof(int);
+        case XdrDataType::Float: return sizeof(float);
+        case XdrDataType::Double: return sizeof(double);
         default: GMX_RELEASE_ASSERT(false, "XDR data type not implemented");
     }
 
@@ -570,13 +622,13 @@ static inline unsigned int sizeOfXdrType(int xdrType)
 }
 
 //! \brief Returns the XDR process function for i/o of an XDR type
-static inline xdrproc_t xdrProc(int xdrType)
+static inline xdrproc_t xdrProc(XdrDataType xdrType)
 {
     switch (xdrType)
     {
-        case xdr_datatype_int: return reinterpret_cast<xdrproc_t>(xdr_int);
-        case xdr_datatype_float: return reinterpret_cast<xdrproc_t>(xdr_float);
-        case xdr_datatype_double: return reinterpret_cast<xdrproc_t>(xdr_double);
+        case XdrDataType::Int: return reinterpret_cast<xdrproc_t>(xdr_int);
+        case XdrDataType::Float: return reinterpret_cast<xdrproc_t>(xdr_float);
+        case XdrDataType::Double: return reinterpret_cast<xdrproc_t>(xdr_double);
         default: GMX_RELEASE_ASSERT(false, "XDR data type not implemented");
     }
 
@@ -590,7 +642,8 @@ static inline xdrproc_t xdrProc(int xdrType)
  * The formatting of the printing is set by \p cptElementType.
  * When list==NULL only reads the elements.
  */
-static bool_t listXdrVector(XDR* xd, StatePart part, int ecpt, int nf, int xdrType, FILE* list, CptElementType cptElementType)
+template<typename Enum>
+static bool_t listXdrVector(XDR* xd, Enum ecpt, int nf, XdrDataType xdrType, FILE* list, CptElementType cptElementType)
 {
     bool_t res = 0;
 
@@ -602,37 +655,33 @@ static bool_t listXdrVector(XDR* xd, StatePart part, int ecpt, int nf, int xdrTy
     {
         switch (xdrType)
         {
-            case xdr_datatype_int:
-                pr_ivec(list, 0, entryName(part, ecpt), reinterpret_cast<const int*>(data.data()), nf, TRUE);
+            case XdrDataType::Int:
+                pr_ivec(list, 0, enumValueToString(ecpt), reinterpret_cast<const int*>(data.data()), nf, TRUE);
                 break;
-            case xdr_datatype_float:
+            case XdrDataType::Float:
 #if !GMX_DOUBLE
                 if (cptElementType == CptElementType::real3)
                 {
-                    pr_rvecs(list, 0, entryName(part, ecpt),
-                             reinterpret_cast<const rvec*>(data.data()), nf / 3);
+                    pr_rvecs(list, 0, enumValueToString(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 */
-                    pr_fvec(list, 0, entryName(part, ecpt),
-                            reinterpret_cast<const float*>(data.data()), nf, TRUE);
+                    pr_fvec(list, 0, enumValueToString(ecpt), reinterpret_cast<const float*>(data.data()), nf, TRUE);
                 }
                 break;
-            case xdr_datatype_double:
+            case XdrDataType::Double:
 #if GMX_DOUBLE
                 if (cptElementType == CptElementType::real3)
                 {
-                    pr_rvecs(list, 0, entryName(part, ecpt),
-                             reinterpret_cast<const rvec*>(data.data()), nf / 3);
+                    pr_rvecs(list, 0, enumValueToString(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 */
-                    pr_dvec(list, 0, entryName(part, ecpt),
-                            reinterpret_cast<const double*>(data.data()), nf, TRUE);
+                    pr_dvec(list, 0, enumValueToString(ecpt), reinterpret_cast<const double*>(data.data()), nf, TRUE);
                 }
                 break;
             default: GMX_RELEASE_ASSERT(false, "Data type not implemented for listing");
@@ -688,10 +737,9 @@ static void convertArrayRealPrecision(const char gmx_unused* c, int gmx_unused*
  * 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, typename AllocatorType>
+template<typename T, typename AllocatorType, typename Enum>
 static int doVectorLow(XDR*                           xd,
-                       StatePart                      part,
-                       int                            ecpt,
+                       Enum                           ecpt,
                        int                            sflags,
                        int                            nval,
                        int*                           nptr,
@@ -734,15 +782,17 @@ static int doVectorLow(XDR*                           xd,
         return -1;
     }
     /* Read/write the element data type */
-    constexpr int xdrTypeInTheCode = xdr_type<T>::value;
-    int           xdrTypeInTheFile = xdrTypeInTheCode;
-    res                            = xdr_int(xd, &xdrTypeInTheFile);
+    constexpr XdrDataType xdrTypeInTheCode      = xdr_type<T>::value;
+    XdrDataType           xdrTypeInTheFile      = xdrTypeInTheCode;
+    int                   xdrTypeInTheFileAsInt = static_cast<int>(xdrTypeInTheFile);
+    res                                         = xdr_int(xd, &xdrTypeInTheFileAsInt);
+    xdrTypeInTheFile                            = static_cast<XdrDataType>(xdrTypeInTheFileAsInt);
     if (res == 0)
     {
         return -1;
     }
 
-    if (list == nullptr && (sflags & (1 << ecpt)))
+    if (list == nullptr && (sflags & enumValueToBitMask(ecpt)))
     {
         if (nval >= 0)
         {
@@ -750,7 +800,9 @@ static int doVectorLow(XDR*                           xd,
             {
                 gmx_fatal(FARGS,
                           "Count mismatch for state entry %s, code count is %d, file count is %d\n",
-                          entryName(part, ecpt), nval, numElemInTheFile);
+                          enumValueToString(ecpt),
+                          nval,
+                          numElemInTheFile);
             }
         }
         else if (nptr != nullptr)
@@ -762,15 +814,18 @@ static int doVectorLow(XDR*                           xd,
         if (!typesMatch)
         {
             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]);
+            sprintf(buf,
+                    "mismatch for state entry %s, code precision is %s, file precision is %s",
+                    enumValueToString(ecpt),
+                    enumValueToString(xdrTypeInTheCode),
+                    enumValueToString(xdrTypeInTheFile));
 
             /* Matching int and real should never occur, but check anyhow */
-            if (xdrTypeInTheFile == xdr_datatype_int || xdrTypeInTheCode == xdr_datatype_int)
+            if (xdrTypeInTheFile == XdrDataType::Int || xdrTypeInTheCode == XdrDataType::Int)
             {
                 gmx_fatal(FARGS,
-                          "Type %s: incompatible checkpoint formats or corrupted checkpoint file.", buf);
+                          "Type %s: incompatible checkpoint formats or corrupted checkpoint file.",
+                          buf);
             }
         }
 
@@ -806,8 +861,8 @@ static int doVectorLow(XDR*                           xd,
         {
             snew(vChar, numElemInTheFile * sizeOfXdrType(xdrTypeInTheFile));
         }
-        res = xdr_vector(xd, vChar, numElemInTheFile, sizeOfXdrType(xdrTypeInTheFile),
-                         xdrProc(xdrTypeInTheFile));
+        res = xdr_vector(
+                xd, vChar, numElemInTheFile, sizeOfXdrType(xdrTypeInTheFile), xdrProc(xdrTypeInTheFile));
         if (res == 0)
         {
             return -1;
@@ -826,27 +881,27 @@ static int doVectorLow(XDR*                           xd,
     }
     else
     {
-        res = listXdrVector(xd, part, ecpt, numElemInTheFile, xdrTypeInTheFile, list, cptElementType);
+        res = listXdrVector(xd, ecpt, numElemInTheFile, xdrTypeInTheFile, list, cptElementType);
     }
 
     return 0;
 }
 
 //! \brief Read/Write a std::vector, on read checks the number of elements matches \p numElements, if specified.
-template<typename T>
-static int
-doVector(XDR* xd, StatePart part, int ecpt, int sflags, std::vector<T>* vector, FILE* list, int numElements = -1)
+template<typename T, typename Enum>
+static int doVector(XDR* xd, Enum ecpt, int sflags, std::vector<T>* vector, FILE* list, int numElements = -1)
 {
-    return doVectorLow<T>(xd, part, ecpt, sflags, numElements, nullptr, nullptr, vector, list,
-                          CptElementType::real);
+    return doVectorLow<T>(
+            xd, ecpt, sflags, numElements, nullptr, nullptr, vector, list, CptElementType::real);
 }
 
 //! \brief Read/Write an ArrayRef<real>.
-static int doRealArrayRef(XDR* xd, StatePart part, int ecpt, int sflags, gmx::ArrayRef<real> vector, FILE* list)
+template<typename Enum>
+static int doRealArrayRef(XDR* xd, Enum ecpt, int sflags, gmx::ArrayRef<real> vector, FILE* list)
 {
     real* v_real = vector.data();
-    return doVectorLow<real, std::allocator<real>>(xd, part, ecpt, sflags, vector.size(), nullptr,
-                                                   &v_real, nullptr, list, CptElementType::real);
+    return doVectorLow<real, std::allocator<real>>(
+            xd, ecpt, sflags, vector.size(), nullptr, &v_real, nullptr, list, CptElementType::real);
 }
 
 //! Convert from view of RVec to view of real.
@@ -856,20 +911,19 @@ static gmx::ArrayRef<real> realArrayRefFromRVecArrayRef(gmx::ArrayRef<gmx::RVec>
 }
 
 //! \brief Read/Write a PaddedVector whose value_type is RVec.
-template<typename PaddedVectorOfRVecType>
-static int
-doRvecVector(XDR* xd, StatePart part, int ecpt, int sflags, PaddedVectorOfRVecType* v, int numAtoms, FILE* list)
+template<typename PaddedVectorOfRVecType, typename Enum>
+static int doRvecVector(XDR* xd, Enum ecpt, int sflags, PaddedVectorOfRVecType* v, int numAtoms, FILE* list)
 {
     const int numReals = numAtoms * DIM;
 
     if (list == nullptr)
     {
         GMX_RELEASE_ASSERT(
-                sflags & (1 << ecpt),
+                sflags & enumValueToBitMask(ecpt),
                 "When not listing, the flag for the entry should be set when requesting i/o");
         GMX_RELEASE_ASSERT(v->size() == numAtoms, "v should have sufficient size for numAtoms");
 
-        return doRealArrayRef(xd, part, ecpt, sflags, realArrayRefFromRVecArrayRef(makeArrayRef(*v)), list);
+        return doRealArrayRef(xd, ecpt, sflags, realArrayRefFromRVecArrayRef(makeArrayRef(*v)), list);
     }
     else
     {
@@ -877,8 +931,8 @@ doRvecVector(XDR* xd, StatePart part, int ecpt, int sflags, PaddedVectorOfRVecTy
         // allocator from RVec to real.
         using realAllocator =
                 typename std::allocator_traits<typename PaddedVectorOfRVecType::allocator_type>::template rebind_alloc<real>;
-        return doVectorLow<real, realAllocator>(xd, part, ecpt, sflags, numReals, nullptr, nullptr,
-                                                nullptr, list, CptElementType::real);
+        return doVectorLow<real, realAllocator>(
+                xd, ecpt, sflags, numReals, nullptr, nullptr, nullptr, list, CptElementType::real);
     }
 }
 
@@ -886,77 +940,75 @@ doRvecVector(XDR* xd, StatePart part, int ecpt, int sflags, PaddedVectorOfRVecTy
  * 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, StatePart part, int ecpt, int sflags, int n, real** v, FILE* list)
+template<typename Enum>
+static int do_cpte_reals(XDR* xd, Enum ecpt, int sflags, int n, real** v, FILE* list)
 {
-    return doVectorLow<real, std::allocator<real>>(xd, part, ecpt, sflags, n, nullptr, v, nullptr,
-                                                   list, CptElementType::real);
+    return doVectorLow<real, std::allocator<real>>(
+            xd, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::real);
 }
 
-/* This function does the same as do_cpte_reals,
- * except that on reading it ignores the passed value of *n
- * and stores the value read from the checkpoint file in *n.
- */
-static int do_cpte_n_reals(XDR* xd, StatePart part, int ecpt, int sflags, int* n, real** v, FILE* list)
+template<typename Enum>
+static int do_cpte_real(XDR* xd, Enum ecpt, int sflags, real* r, FILE* list)
 {
-    return doVectorLow<real, std::allocator<real>>(xd, part, ecpt, sflags, -1, n, v, nullptr, list,
-                                                   CptElementType::real);
+    return doVectorLow<real, std::allocator<real>>(
+            xd, ecpt, sflags, 1, nullptr, &r, nullptr, list, CptElementType::real);
 }
 
-static int do_cpte_real(XDR* xd, StatePart part, int ecpt, int sflags, real* r, FILE* list)
+template<typename Enum>
+static int do_cpte_ints(XDR* xd, Enum ecpt, int sflags, int n, int** v, FILE* list)
 {
-    return doVectorLow<real, std::allocator<real>>(xd, part, ecpt, sflags, 1, nullptr, &r, nullptr,
-                                                   list, CptElementType::real);
+    return doVectorLow<int, std::allocator<int>>(
+            xd, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::integer);
 }
 
-static int do_cpte_ints(XDR* xd, StatePart part, int ecpt, int sflags, int n, int** v, FILE* list)
+template<typename Enum>
+static int do_cpte_int(XDR* xd, Enum ecpt, int sflags, int* i, FILE* list)
 {
-    return doVectorLow<int, std::allocator<int>>(xd, part, ecpt, sflags, n, nullptr, v, nullptr,
-                                                 list, CptElementType::integer);
+    return do_cpte_ints(xd, ecpt, sflags, 1, &i, list);
 }
 
-static int do_cpte_int(XDR* xd, StatePart part, int ecpt, int sflags, int* i, FILE* list)
-{
-    return do_cpte_ints(xd, part, ecpt, sflags, 1, &i, list);
-}
-
-static int do_cpte_bool(XDR* xd, StatePart part, int ecpt, int sflags, bool* b, FILE* list)
+template<typename Enum>
+static int do_cpte_bool(XDR* xd, Enum ecpt, int sflags, bool* b, FILE* list)
 {
     int i   = static_cast<int>(*b);
-    int ret = do_cpte_int(xd, part, ecpt, sflags, &i, list);
+    int ret = do_cpte_int(xd, ecpt, sflags, &i, list);
     *b      = (i != 0);
     return ret;
 }
 
-static int do_cpte_doubles(XDR* xd, StatePart part, int ecpt, int sflags, int n, double** v, FILE* list)
+template<typename Enum>
+static int do_cpte_doubles(XDR* xd, Enum ecpt, int sflags, int n, double** v, FILE* list)
 {
-    return doVectorLow<double, std::allocator<double>>(xd, part, ecpt, sflags, n, nullptr, v,
-                                                       nullptr, list, CptElementType::real);
+    return doVectorLow<double, std::allocator<double>>(
+            xd, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::real);
 }
 
-static int do_cpte_double(XDR* xd, StatePart part, int ecpt, int sflags, double* r, FILE* list)
+template<typename Enum>
+static int do_cpte_double(XDR* xd, Enum ecpt, int sflags, double* r, FILE* list)
 {
-    return do_cpte_doubles(xd, part, ecpt, sflags, 1, &r, list);
+    return do_cpte_doubles(xd, ecpt, sflags, 1, &r, list);
 }
 
-static int do_cpte_matrix(XDR* xd, StatePart part, int ecpt, int sflags, matrix v, FILE* list)
+template<typename Enum>
+static int do_cpte_matrix(XDR* xd, Enum ecpt, int sflags, matrix v, FILE* list)
 {
     real* vr;
     int   ret;
 
     vr  = &(v[0][0]);
-    ret = doVectorLow<real, std::allocator<real>>(xd, part, ecpt, sflags, DIM * DIM, nullptr, &vr,
-                                                  nullptr, nullptr, CptElementType::matrix3x3);
+    ret = doVectorLow<real, std::allocator<real>>(
+            xd, ecpt, sflags, DIM * DIM, nullptr, &vr, nullptr, nullptr, CptElementType::matrix3x3);
 
     if (list && ret == 0)
     {
-        pr_rvecs(list, 0, entryName(part, ecpt), v, DIM);
+        pr_rvecs(list, 0, enumValueToString(ecpt), v, DIM);
     }
 
     return ret;
 }
 
-
-static int do_cpte_nmatrix(XDR* xd, StatePart part, int ecpt, int sflags, int n, real** v, FILE* list)
+template<typename Enum>
+static int do_cpte_nmatrix(XDR* xd, Enum ecpt, int sflags, int n, real** v, FILE* list)
 {
     int  i;
     int  ret, reti;
@@ -969,11 +1021,11 @@ static int do_cpte_nmatrix(XDR* xd, StatePart part, int ecpt, int sflags, int n,
     }
     for (i = 0; i < n; i++)
     {
-        reti = doVectorLow<real, std::allocator<real>>(xd, part, ecpt, sflags, n, nullptr, &(v[i]),
-                                                       nullptr, nullptr, CptElementType::matrix3x3);
+        reti = doVectorLow<real, std::allocator<real>>(
+                xd, ecpt, sflags, n, nullptr, &(v[i]), nullptr, nullptr, CptElementType::matrix3x3);
         if (list && reti == 0)
         {
-            sprintf(name, "%s[%d]", entryName(part, ecpt), i);
+            sprintf(name, "%s[%d]", enumValueToString(ecpt), i);
             pr_reals(list, 0, name, v[i], n);
         }
         if (reti != 0)
@@ -984,7 +1036,8 @@ static int do_cpte_nmatrix(XDR* xd, StatePart part, int ecpt, int sflags, int n,
     return ret;
 }
 
-static int do_cpte_matrices(XDR* xd, StatePart part, int ecpt, int sflags, int n, matrix** v, FILE* list)
+template<typename Enum>
+static int do_cpte_matrices(XDR* xd, Enum ecpt, int sflags, int n, matrix** v, FILE* list)
 {
     bool_t  res = 0;
     matrix *vp, *va = nullptr;
@@ -1000,10 +1053,13 @@ static int do_cpte_matrices(XDR* xd, StatePart part, int ecpt, int sflags, int n
     }
     if (list == nullptr && nf != n)
     {
-        gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n",
-                  entryName(part, ecpt), n, nf);
+        gmx_fatal(FARGS,
+                  "Count mismatch for state entry %s, code count is %d, file count is %d\n",
+                  enumValueToString(ecpt),
+                  n,
+                  nf);
     }
-    if (list || !(sflags & (1 << ecpt)))
+    if (list || !(sflags & enumValueToBitMask(ecpt)))
     {
         snew(va, nf);
         vp = va;
@@ -1027,8 +1083,8 @@ static int do_cpte_matrices(XDR* xd, StatePart part, int ecpt, int sflags, int n
             }
         }
     }
-    ret = doVectorLow<real, std::allocator<real>>(xd, part, ecpt, sflags, nf * DIM * DIM, nullptr,
-                                                  &vr, nullptr, nullptr, CptElementType::matrix3x3);
+    ret = doVectorLow<real, std::allocator<real>>(
+            xd, ecpt, sflags, nf * DIM * DIM, nullptr, &vr, nullptr, nullptr, CptElementType::matrix3x3);
     for (i = 0; i < nf; i++)
     {
         for (j = 0; j < DIM; j++)
@@ -1045,7 +1101,7 @@ static int do_cpte_matrices(XDR* xd, StatePart part, int ecpt, int sflags, int n
     {
         for (i = 0; i < nf; i++)
         {
-            pr_rvecs(list, 0, entryName(part, ecpt), vp[i], DIM);
+            pr_rvecs(list, 0, enumValueToString(ecpt), vp[i], DIM);
         }
     }
     if (va)
@@ -1080,7 +1136,8 @@ static void do_cpt_header(XDR* xd, gmx_bool bRead, FILE* list, CheckpointHeaderC
         gmx_fatal(FARGS,
                   "Start of file magic number mismatch, checkpoint file has %d, should be %d\n"
                   "The checkpoint file is corrupted or not a checkpoint file",
-                  magic, CPT_MAGIC1);
+                  magic,
+                  CPT_MAGIC1);
     }
     char fhost[255];
     if (!bRead)
@@ -1105,7 +1162,8 @@ static void do_cpt_header(XDR* xd, gmx_bool bRead, FILE* list, CheckpointHeaderC
     {
         gmx_fatal(FARGS,
                   "Attempting to read a checkpoint file of version %d with code of version %d\n",
-                  contents->file_version, cpt_version);
+                  contents->file_version,
+                  cpt_version);
     }
     if (contents->file_version >= 13)
     {
@@ -1145,7 +1203,14 @@ static void do_cpt_header(XDR* xd, gmx_bool bRead, FILE* list, CheckpointHeaderC
     {
         contents->nlambda = 0;
     }
-    do_cpt_int_err(xd, "integrator", &contents->eIntegrator, list);
+    {
+        int integrator = static_cast<int>(contents->eIntegrator);
+        do_cpt_int_err(xd, "integrator", &integrator, list);
+        if (bRead)
+        {
+            contents->eIntegrator = static_cast<IntegrationAlgorithm>(integrator);
+        }
+    }
     if (contents->file_version >= 3)
     {
         do_cpt_int_err(xd, "simulation part #", &contents->simulation_part, list);
@@ -1178,11 +1243,12 @@ static void do_cpt_header(XDR* xd, gmx_bool bRead, FILE* list, CheckpointHeaderC
     }
     else
     {
-        contents->flags_eks   = 0;
-        contents->flags_enh   = (contents->flags_state >> (estORIRE_DTAV + 1));
+        contents->flags_eks = 0;
+        contents->flags_enh = (contents->flags_state >> (static_cast<int>(StateEntry::OrireDtav) + 1));
         contents->flags_state = (contents->flags_state
-                                 & ~((1 << (estORIRE_DTAV + 1)) | (1 << (estORIRE_DTAV + 2))
-                                     | (1 << (estORIRE_DTAV + 3))));
+                                 & ~((1 << (static_cast<int>(StateEntry::OrireDtav) + 1))
+                                     | (1 << (static_cast<int>(StateEntry::OrireDtav) + 2))
+                                     | (1 << (static_cast<int>(StateEntry::OrireDtav) + 3))));
     }
     if (contents->file_version >= 14)
     {
@@ -1204,11 +1270,16 @@ static void do_cpt_header(XDR* xd, gmx_bool bRead, FILE* list, CheckpointHeaderC
 
     if (contents->file_version >= 16)
     {
-        do_cpt_int_err(xd, "swap", &contents->eSwapCoords, list);
+        int swapState = static_cast<int>(contents->eSwapCoords);
+        do_cpt_int_err(xd, "swap", &swapState, list);
+        if (bRead)
+        {
+            contents->eSwapCoords = static_cast<SwapType>(swapState);
+        }
     }
     else
     {
-        contents->eSwapCoords = eswapNO;
+        contents->eSwapCoords = SwapType::No;
     }
 
     if (contents->file_version >= 17)
@@ -1231,8 +1302,8 @@ static void do_cpt_header(XDR* xd, gmx_bool bRead, FILE* list, CheckpointHeaderC
 
     if (contents->file_version >= cptv_ModularSimulator)
     {
-        do_cpt_bool_err(xd, "Is modular simulator checkpoint",
-                        &contents->isModularSimulatorCheckpoint, list);
+        do_cpt_bool_err(
+                xd, "Is modular simulator checkpoint", &contents->isModularSimulatorCheckpoint, list);
     }
     else
     {
@@ -1264,101 +1335,102 @@ static int do_cpt_footer(XDR* xd, int file_version)
 
 static int do_cpt_state(XDR* xd, int fflags, t_state* state, FILE* list)
 {
-    int             ret    = 0;
-    const StatePart part   = StatePart::microState;
-    const int       sflags = state->flags;
+    int       ret    = 0;
+    const int sflags = state->flags;
     // If reading, state->natoms was probably just read, so
     // allocations need to be managed. If writing, this won't change
     // anything that matters.
+    using StateFlags = gmx::EnumerationArray<StateEntry, bool>;
     state_change_natoms(state, state->natoms);
-    for (int i = 0; (i < estNR && ret == 0); i++)
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        if (fflags & (1 << i))
+        if (fflags & enumValueToBitMask(*i))
         {
-            switch (i)
+            switch (*i)
             {
-                case estLAMBDA:
-                    ret = doRealArrayRef(
-                            xd, part, i, sflags,
-                            gmx::arrayRefFromArray<real>(state->lambda.data(), state->lambda.size()),
-                            list);
+                case StateEntry::Lambda:
+                    ret = doRealArrayRef(xd, *i, sflags, state->lambda, list);
+                    break;
+                case StateEntry::FepState:
+                    ret = do_cpte_int(xd, *i, sflags, &state->fep_state, list);
                     break;
-                case estFEPSTATE:
-                    ret = do_cpte_int(xd, part, i, sflags, &state->fep_state, list);
+                case StateEntry::Box: ret = do_cpte_matrix(xd, *i, sflags, state->box, list); break;
+                case StateEntry::BoxRel:
+                    ret = do_cpte_matrix(xd, *i, sflags, state->box_rel, 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);
+                case StateEntry::BoxV:
+                    ret = do_cpte_matrix(xd, *i, sflags, state->boxv, 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);
+                case StateEntry::PressurePrevious:
+                    ret = do_cpte_matrix(xd, *i, sflags, state->pres_prev, list);
                     break;
-                case estSVIR_PREV:
-                    ret = do_cpte_matrix(xd, part, i, sflags, state->svir_prev, list);
+                case StateEntry::SVirPrev:
+                    ret = do_cpte_matrix(xd, *i, sflags, state->svir_prev, list);
                     break;
-                case estFVIR_PREV:
-                    ret = do_cpte_matrix(xd, part, i, sflags, state->fvir_prev, list);
+                case StateEntry::FVirPrev:
+                    ret = do_cpte_matrix(xd, *i, sflags, state->fvir_prev, list);
                     break;
-                case estNH_XI:
-                    ret = doVector<double>(xd, part, i, sflags, &state->nosehoover_xi, list);
+                case StateEntry::Nhxi:
+                    ret = doVector<double>(xd, *i, sflags, &state->nosehoover_xi, list);
                     break;
-                case estNH_VXI:
-                    ret = doVector<double>(xd, part, i, sflags, &state->nosehoover_vxi, list);
+                case StateEntry::Nhvxi:
+                    ret = doVector<double>(xd, *i, sflags, &state->nosehoover_vxi, list);
                     break;
-                case estNHPRES_XI:
-                    ret = doVector<double>(xd, part, i, sflags, &state->nhpres_xi, list);
+                case StateEntry::Nhpresxi:
+                    ret = doVector<double>(xd, *i, sflags, &state->nhpres_xi, list);
                     break;
-                case estNHPRES_VXI:
-                    ret = doVector<double>(xd, part, i, sflags, &state->nhpres_vxi, list);
+                case StateEntry::Nhpresvxi:
+                    ret = doVector<double>(xd, *i, sflags, &state->nhpres_vxi, list);
                     break;
-                case estTHERM_INT:
-                    ret = doVector<double>(xd, part, i, sflags, &state->therm_integral, list);
+                case StateEntry::ThermInt:
+                    ret = doVector<double>(xd, *i, sflags, &state->therm_integral, list);
                     break;
-                case estBAROS_INT:
-                    ret = do_cpte_double(xd, part, i, sflags, &state->baros_integral, list);
+                case StateEntry::BarosInt:
+                    ret = do_cpte_double(xd, *i, sflags, &state->baros_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 = doRvecVector(xd, part, i, sflags, &state->x, state->natoms, list);
+                case StateEntry::Veta:
+                    ret = do_cpte_real(xd, *i, sflags, &state->veta, list);
                     break;
-                case estV:
-                    ret = doRvecVector(xd, part, i, sflags, &state->v, state->natoms, list);
+                case StateEntry::Vol0:
+                    ret = do_cpte_real(xd, *i, sflags, &state->vol0, list);
+                    break;
+                case StateEntry::X:
+                    ret = doRvecVector(xd, *i, sflags, &state->x, state->natoms, list);
+                    break;
+                case StateEntry::V:
+                    ret = doRvecVector(xd, *i, sflags, &state->v, state->natoms, list);
                     break;
                 /* The RNG entries are no longer written,
                  * the next 4 lines are only for reading old files.
                  * It's OK that three case statements fall through.
                  */
-                case estLD_RNG_NOTSUPPORTED:
-                case estLD_RNGI_NOTSUPPORTED:
-                case estMC_RNG_NOTSUPPORTED:
-                case estMC_RNGI_NOTSUPPORTED:
-                    ret = do_cpte_ints(xd, part, i, sflags, 0, nullptr, list);
+                case StateEntry::LDRngNotSupported:
+                case StateEntry::LDRngINotSupported:
+                case StateEntry::MCRngNotSupported:
+                case StateEntry::MCRngINotSupported:
+                    ret = do_cpte_ints(xd, *i, sflags, 0, nullptr, list);
                     break;
-                case estDISRE_INITF:
-                    ret = do_cpte_real(xd, part, i, sflags, &state->hist.disre_initf, list);
+                case StateEntry::DisreInitF:
+                    ret = do_cpte_real(xd, *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);
+                case StateEntry::DisreRm3Tav:
+                    ret = doVector<real>(xd, *i, sflags, &state->hist.disre_rm3tav, list);
                     break;
-                case estORIRE_INITF:
-                    ret = do_cpte_real(xd, part, i, sflags, &state->hist.orire_initf, list);
+                case StateEntry::OrireInitF:
+                    ret = do_cpte_real(xd, *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);
+                case StateEntry::OrireDtav:
+                    ret = doVector<real>(xd, *i, sflags, &state->hist.orire_Dtav, list);
                     break;
-                case estPULLCOMPREVSTEP:
-                    ret = doVector<double>(xd, part, i, sflags, &state->pull_com_prev_step, list);
+                case StateEntry::PullComPrevStep:
+                    ret = doVector<double>(xd, *i, sflags, &state->pull_com_prev_step, 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);
+                              enumValueToBitMask(*i));
             }
         }
     }
@@ -1369,47 +1441,49 @@ static int do_cpt_ekinstate(XDR* xd, int fflags, ekinstate_t* ekins, FILE* list)
 {
     int ret = 0;
 
-    const StatePart part = StatePart::kineticEnergy;
-    for (int i = 0; (i < eeksNR && ret == 0); i++)
+    using StateFlags = gmx::EnumerationArray<StateKineticEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        if (fflags & (1 << i))
+        if (fflags & enumValueToBitMask(*i))
         {
-            switch (i)
+            switch (*i)
             {
 
-                case eeksEKIN_N:
-                    ret = do_cpte_int(xd, part, i, fflags, &ekins->ekin_n, list);
+                case StateKineticEntry::EkinNumber:
+                    ret = do_cpte_int(xd, *i, fflags, &ekins->ekin_n, list);
                     break;
-                case eeksEKINH:
-                    ret = do_cpte_matrices(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinh, list);
+                case StateKineticEntry::EkinHalfStep:
+                    ret = do_cpte_matrices(xd, *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);
+                case StateKineticEntry::EkinFullStep:
+                    ret = do_cpte_matrices(xd, *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);
+                case StateKineticEntry::EkinHalfStepOld:
+                    ret = do_cpte_matrices(xd, *i, fflags, ekins->ekin_n, &ekins->ekinh_old, list);
                     break;
-                case eeksEKINTOTAL:
-                    ret = do_cpte_matrix(xd, part, i, fflags, ekins->ekin_total, list);
+                case StateKineticEntry::EkinTotal:
+                    ret = do_cpte_matrix(xd, *i, fflags, ekins->ekin_total, list);
                     break;
-                case eeksEKINSCALEF:
-                    ret = doVector<double>(xd, part, i, fflags, &ekins->ekinscalef_nhc, list);
+                case StateKineticEntry::EkinNoseHooverScaleFullStep:
+                    ret = doVector<double>(xd, *i, fflags, &ekins->ekinscalef_nhc, list);
                     break;
-                case eeksVSCALE:
-                    ret = doVector<double>(xd, part, i, fflags, &ekins->vscale_nhc, list);
+                case StateKineticEntry::VelocityScale:
+                    ret = doVector<double>(xd, *i, fflags, &ekins->vscale_nhc, list);
                     break;
-                case eeksEKINSCALEH:
-                    ret = doVector<double>(xd, part, i, fflags, &ekins->ekinscaleh_nhc, list);
+                case StateKineticEntry::EkinNoseHooverScaleHalfStep:
+                    ret = doVector<double>(xd, *i, fflags, &ekins->ekinscaleh_nhc, list);
                     break;
-                case eeksDEKINDL:
-                    ret = do_cpte_real(xd, part, i, fflags, &ekins->dekindl, list);
+                case StateKineticEntry::DEkinDLambda:
+                    ret = do_cpte_real(xd, *i, fflags, &ekins->dekindl, list);
+                    break;
+                case StateKineticEntry::Mvcos:
+                    ret = do_cpte_real(xd, *i, fflags, &ekins->mvcos, 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);
+                              enumValueToBitMask(*i));
             }
         }
     }
@@ -1418,11 +1492,11 @@ static int do_cpt_ekinstate(XDR* xd, int fflags, ekinstate_t* ekins, FILE* list)
 }
 
 
-static int do_cpt_swapstate(XDR* xd, gmx_bool bRead, int eSwapCoords, swaphistory_t* swapstate, FILE* list)
+static int do_cpt_swapstate(XDR* xd, gmx_bool bRead, SwapType eSwapCoords, swaphistory_t* swapstate, FILE* list)
 {
     int swap_cpt_version = 2;
 
-    if (eSwapCoords == eswapNO)
+    if (eSwapCoords == SwapType::No)
     {
         return 0;
     }
@@ -1448,7 +1522,7 @@ static int do_cpt_swapstate(XDR* xd, gmx_bool bRead, int eSwapCoords, swaphistor
         snew(swapstate->ionType, swapstate->nIonTypes);
     }
 
-    for (int ic = 0; ic < eCompNR; ic++)
+    for (auto ic : gmx::EnumerationWrapper<Compartment>{})
     {
         for (int ii = 0; ii < swapstate->nIonTypes; ii++)
         {
@@ -1492,7 +1566,7 @@ static int do_cpt_swapstate(XDR* xd, gmx_bool bRead, int eSwapCoords, swaphistor
     }
 
     /* Ion flux per channel */
-    for (int ic = 0; ic < eChanNR; ic++)
+    for (auto ic : gmx::EnumerationWrapper<Channel>{})
     {
         for (int ii = 0; ii < swapstate->nIonTypes; ii++)
         {
@@ -1532,27 +1606,32 @@ static int do_cpt_swapstate(XDR* xd, gmx_bool bRead, int eSwapCoords, swaphistor
             snew(gs->comp_from, gs->nMol);
         }
 
-        do_cpt_u_chars(xd, "channel history", gs->nMol, gs->channel_label, list);
-        do_cpt_u_chars(xd, "domain history", gs->nMol, gs->comp_from, list);
+        do_cpt_n_enum_as_int<ChannelHistory>(xd, "channel history", gs->nMol, gs->channel_label, list);
+        do_cpt_n_enum_as_int<Domain>(xd, "domain history", gs->nMol, gs->comp_from, list);
     }
 
     /* Save the last known whole positions to checkpoint
      * file to be able to also make multimeric channels whole in PBC */
-    do_cpt_int_err(xd, "Ch0 atoms", &swapstate->nat[eChan0], list);
-    do_cpt_int_err(xd, "Ch1 atoms", &swapstate->nat[eChan1], list);
+    do_cpt_int_err(xd, "Ch0 atoms", &swapstate->nat[Channel::Zero], list);
+    do_cpt_int_err(xd, "Ch1 atoms", &swapstate->nat[Channel::One], list);
     if (bRead)
     {
-        snew(swapstate->xc_old_whole[eChan0], swapstate->nat[eChan0]);
-        snew(swapstate->xc_old_whole[eChan1], swapstate->nat[eChan1]);
-        do_cpt_n_rvecs_err(xd, "Ch0 whole x", swapstate->nat[eChan0], swapstate->xc_old_whole[eChan0], list);
-        do_cpt_n_rvecs_err(xd, "Ch1 whole x", swapstate->nat[eChan1], swapstate->xc_old_whole[eChan1], list);
+        snew(swapstate->xc_old_whole[Channel::Zero], swapstate->nat[Channel::Zero]);
+        snew(swapstate->xc_old_whole[Channel::One], swapstate->nat[Channel::One]);
+        do_cpt_n_rvecs_err(
+                xd, "Ch0 whole x", swapstate->nat[Channel::Zero], swapstate->xc_old_whole[Channel::Zero], list);
+        do_cpt_n_rvecs_err(
+                xd, "Ch1 whole x", swapstate->nat[Channel::One], swapstate->xc_old_whole[Channel::One], list);
     }
     else
     {
-        do_cpt_n_rvecs_err(xd, "Ch0 whole x", swapstate->nat[eChan0],
-                           *swapstate->xc_old_whole_p[eChan0], list);
-        do_cpt_n_rvecs_err(xd, "Ch1 whole x", swapstate->nat[eChan1],
-                           *swapstate->xc_old_whole_p[eChan1], list);
+        do_cpt_n_rvecs_err(xd,
+                           "Ch0 whole x",
+                           swapstate->nat[Channel::Zero],
+                           *swapstate->xc_old_whole_p[Channel::Zero],
+                           list);
+        do_cpt_n_rvecs_err(
+                xd, "Ch1 whole x", swapstate->nat[Channel::One], *swapstate->xc_old_whole_p[Channel::One], list);
     }
 
     return 0;
@@ -1568,8 +1647,7 @@ static int do_cpt_enerhist(XDR* xd, gmx_bool bRead, int fflags, energyhistory_t*
         return ret;
     }
 
-    GMX_RELEASE_ASSERT(enerhist != nullptr,
-                       "With energy history, we need a valid enerhist pointer");
+    GMX_RELEASE_ASSERT(enerhist != nullptr, "With energy history, we need a valid enerhist pointer");
 
     /* This is stored/read for backward compatibility */
     int energyHistoryNumEnergies = 0;
@@ -1586,45 +1664,45 @@ static int do_cpt_enerhist(XDR* xd, gmx_bool bRead, int fflags, energyhistory_t*
     }
 
     delta_h_history_t* deltaH = enerhist->deltaHForeignLambdas.get();
-    const StatePart    part   = StatePart::energyHistory;
-    for (int i = 0; (i < eenhNR && ret == 0); i++)
+    using StateFlags          = gmx::EnumerationArray<StateEnergyEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        if (fflags & (1 << i))
+        if (fflags & enumValueToBitMask(*i))
         {
-            switch (i)
+            switch (*i)
             {
-                case eenhENERGY_N:
-                    ret = do_cpte_int(xd, part, i, fflags, &energyHistoryNumEnergies, list);
+                case StateEnergyEntry::N:
+                    ret = do_cpte_int(xd, *i, fflags, &energyHistoryNumEnergies, list);
                     break;
-                case eenhENERGY_AVER:
-                    ret = doVector<double>(xd, part, i, fflags, &enerhist->ener_ave, list);
+                case StateEnergyEntry::Aver:
+                    ret = doVector<double>(xd, *i, fflags, &enerhist->ener_ave, list);
                     break;
-                case eenhENERGY_SUM:
-                    ret = doVector<double>(xd, part, i, fflags, &enerhist->ener_sum, list);
+                case StateEnergyEntry::Sum:
+                    ret = doVector<double>(xd, *i, fflags, &enerhist->ener_sum, list);
                     break;
-                case eenhENERGY_NSUM:
-                    do_cpt_step_err(xd, eenh_names[i], &enerhist->nsum, list);
+                case StateEnergyEntry::NumSum:
+                    do_cpt_step_err(xd, enumValueToString(*i), &enerhist->nsum, list);
                     break;
-                case eenhENERGY_SUM_SIM:
-                    ret = doVector<double>(xd, part, i, fflags, &enerhist->ener_sum_sim, list);
+                case StateEnergyEntry::SumSim:
+                    ret = doVector<double>(xd, *i, fflags, &enerhist->ener_sum_sim, list);
                     break;
-                case eenhENERGY_NSUM_SIM:
-                    do_cpt_step_err(xd, eenh_names[i], &enerhist->nsum_sim, list);
+                case StateEnergyEntry::NumSumSim:
+                    do_cpt_step_err(xd, enumValueToString(*i), &enerhist->nsum_sim, list);
                     break;
-                case eenhENERGY_NSTEPS:
-                    do_cpt_step_err(xd, eenh_names[i], &enerhist->nsteps, list);
+                case StateEnergyEntry::NumSteps:
+                    do_cpt_step_err(xd, enumValueToString(*i), &enerhist->nsteps, list);
                     break;
-                case eenhENERGY_NSTEPS_SIM:
-                    do_cpt_step_err(xd, eenh_names[i], &enerhist->nsteps_sim, list);
+                case StateEnergyEntry::NumStepsSim:
+                    do_cpt_step_err(xd, enumValueToString(*i), &enerhist->nsteps_sim, list);
                     break;
-                case eenhENERGY_DELTA_H_NN:
+                case StateEnergyEntry::DeltaHNN:
                 {
                     int numDeltaH = 0;
                     if (!bRead && deltaH != nullptr)
                     {
                         numDeltaH = deltaH->dh.size();
                     }
-                    do_cpt_int_err(xd, eenh_names[i], &numDeltaH, list);
+                    do_cpt_int_err(xd, enumValueToString(*i), &numDeltaH, list);
                     if (bRead)
                     {
                         if (deltaH == nullptr)
@@ -1637,39 +1715,42 @@ static int do_cpt_enerhist(XDR* xd, gmx_bool bRead, int fflags, energyhistory_t*
                     }
                     break;
                 }
-                case eenhENERGY_DELTA_H_LIST:
+                case StateEnergyEntry::DeltaHList:
                     for (auto dh : deltaH->dh)
                     {
-                        ret = doVector<real>(xd, part, i, fflags, &dh, list);
+                        ret = doVector<real>(xd, *i, fflags, &dh, list);
                     }
                     break;
-                case eenhENERGY_DELTA_H_STARTTIME:
-                    ret = do_cpte_double(xd, part, i, fflags, &(deltaH->start_time), list);
+                case StateEnergyEntry::DeltaHStartTime:
+                    ret = do_cpte_double(xd, *i, fflags, &(deltaH->start_time), list);
                     break;
-                case eenhENERGY_DELTA_H_STARTLAMBDA:
-                    ret = do_cpte_double(xd, part, i, fflags, &(deltaH->start_lambda), list);
+                case StateEnergyEntry::DeltaHStartLambda:
+                    ret = do_cpte_double(xd, *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);
+                              enumValueToBitMask(*i));
             }
         }
     }
 
-    if ((fflags & (1 << eenhENERGY_SUM)) && !(fflags & (1 << eenhENERGY_SUM_SIM)))
+    if ((fflags & enumValueToBitMask(StateEnergyEntry::Sum))
+        && !(fflags & enumValueToBitMask(StateEnergyEntry::SumSim)))
     {
         /* Assume we have an old file format and copy sum to sum_sim */
         enerhist->ener_sum_sim = enerhist->ener_sum;
     }
 
-    if ((fflags & (1 << eenhENERGY_NSUM)) && !(fflags & (1 << eenhENERGY_NSTEPS)))
+    if ((fflags & enumValueToBitMask(StateEnergyEntry::NumSum))
+        && !(fflags & enumValueToBitMask(StateEnergyEntry::NumSteps)))
     {
         /* Assume we have an old file format and copy nsum to nsteps */
         enerhist->nsteps = enerhist->nsum;
     }
-    if ((fflags & (1 << eenhENERGY_NSUM_SIM)) && !(fflags & (1 << eenhENERGY_NSTEPS_SIM)))
+    if ((fflags & enumValueToBitMask(StateEnergyEntry::NumSumSim))
+        && !(fflags & enumValueToBitMask(StateEnergyEntry::NumStepsSim)))
     {
         /* Assume we have an old file format and copy nsum to nsteps */
         enerhist->nsteps_sim = enerhist->nsum_sim;
@@ -1678,75 +1759,83 @@ static int do_cpt_enerhist(XDR* xd, gmx_bool bRead, int fflags, energyhistory_t*
     return ret;
 }
 
-static int doCptPullCoordHist(XDR* xd, PullCoordinateHistory* pullCoordHist, const StatePart part, FILE* list)
+static int doCptPullCoordHist(XDR* xd, PullCoordinateHistory* pullCoordHist, FILE* list)
 {
     int ret   = 0;
     int flags = 0;
 
-    flags |= ((1 << epullcoordh_VALUE_REF_SUM) | (1 << epullcoordh_VALUE_SUM)
-              | (1 << epullcoordh_DR01_SUM) | (1 << epullcoordh_DR23_SUM)
-              | (1 << epullcoordh_DR45_SUM) | (1 << epullcoordh_FSCAL_SUM));
+    flags |= (enumValueToBitMask(StatePullCoordEntry::ValueReferenceSum)
+              | enumValueToBitMask(StatePullCoordEntry::ValueSum)
+              | enumValueToBitMask(StatePullCoordEntry::DR01Sum)
+              | enumValueToBitMask(StatePullCoordEntry::DR23Sum)
+              | enumValueToBitMask(StatePullCoordEntry::DR45Sum)
+              | enumValueToBitMask(StatePullCoordEntry::FScalarSum));
 
-    for (int i = 0; i < epullcoordh_NR && ret == 0; i++)
+    using StateFlags = gmx::EnumerationArray<StatePullCoordEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        switch (i)
+        switch (*i)
         {
-            case epullcoordh_VALUE_REF_SUM:
-                ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->valueRef), list);
+            case StatePullCoordEntry::ValueReferenceSum:
+                ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->valueRef), list);
                 break;
-            case epullcoordh_VALUE_SUM:
-                ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->value), list);
+            case StatePullCoordEntry::ValueSum:
+                ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->value), list);
                 break;
-            case epullcoordh_DR01_SUM:
+            case StatePullCoordEntry::DR01Sum:
                 for (int j = 0; j < DIM && ret == 0; j++)
                 {
-                    ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->dr01[j]), list);
+                    ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->dr01[j]), list);
                 }
                 break;
-            case epullcoordh_DR23_SUM:
+            case StatePullCoordEntry::DR23Sum:
                 for (int j = 0; j < DIM && ret == 0; j++)
                 {
-                    ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->dr23[j]), list);
+                    ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->dr23[j]), list);
                 }
                 break;
-            case epullcoordh_DR45_SUM:
+            case StatePullCoordEntry::DR45Sum:
                 for (int j = 0; j < DIM && ret == 0; j++)
                 {
-                    ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->dr45[j]), list);
+                    ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->dr45[j]), list);
                 }
                 break;
-            case epullcoordh_FSCAL_SUM:
-                ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->scalarForce), list);
+            case StatePullCoordEntry::FScalarSum:
+                ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->scalarForce), list);
                 break;
-            case epullcoordh_DYNAX_SUM:
+            case StatePullCoordEntry::DynaxSum:
                 for (int j = 0; j < DIM && ret == 0; j++)
                 {
-                    ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->dynaX[j]), list);
+                    ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->dynaX[j]), list);
                 }
                 break;
+            default:
+                gmx_fatal(FARGS, "Unhandled StatePullCoordEntry enum value: %d", enumValueToBitMask(*i));
         }
     }
 
     return ret;
 }
 
-static int doCptPullGroupHist(XDR* xd, PullGroupHistory* pullGroupHist, const StatePart part, FILE* list)
+static int doCptPullGroupHist(XDR* xd, PullGroupHistory* pullGroupHist, FILE* list)
 {
     int ret   = 0;
     int flags = 0;
 
-    flags |= ((1 << epullgrouph_X_SUM));
+    flags |= (enumValueToBitMask(StatePullGroupEntry::XSum));
 
-    for (int i = 0; i < epullgrouph_NR; i++)
+    using StateFlags = gmx::EnumerationArray<StatePullGroupEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        switch (i)
+        switch (*i)
         {
-            case epullgrouph_X_SUM:
+            case StatePullGroupEntry::XSum:
                 for (int j = 0; j < DIM && ret == 0; j++)
                 {
-                    ret = do_cpte_double(xd, part, i, flags, &(pullGroupHist->x[j]), list);
+                    ret = do_cpte_double(xd, *i, flags, &(pullGroupHist->x[j]), list);
                 }
                 break;
+            default: gmx_fatal(FARGS, "Unhandled pull group state entry");
         }
     }
 
@@ -1754,7 +1843,7 @@ static int doCptPullGroupHist(XDR* xd, PullGroupHistory* pullGroupHist, const St
 }
 
 
-static int doCptPullHist(XDR* xd, gmx_bool bRead, int fflags, PullHistory* pullHist, const StatePart part, FILE* list)
+static int doCptPullHist(XDR* xd, gmx_bool bRead, int fflags, PullHistory* pullHist, FILE* list)
 {
     int ret                       = 0;
     int pullHistoryNumCoordinates = 0;
@@ -1778,29 +1867,30 @@ static int doCptPullHist(XDR* xd, gmx_bool bRead, int fflags, PullHistory* pullH
         GMX_RELEASE_ASSERT(fflags == 0, "Without pull history, all flags should be off");
     }
 
-    for (int i = 0; (i < epullhNR && ret == 0); i++)
+    using StateFlags = gmx::EnumerationArray<StatePullEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        if (fflags & (1 << i))
+        if (fflags & (1 << enumValueToBitMask(*i)))
         {
-            switch (i)
+            switch (*i)
             {
-                case epullhPULL_NUMCOORDINATES:
-                    ret = do_cpte_int(xd, part, i, fflags, &pullHistoryNumCoordinates, list);
+                case StatePullEntry::NumCoordinates:
+                    ret = do_cpte_int(xd, *i, fflags, &pullHistoryNumCoordinates, list);
                     break;
-                case epullhPULL_NUMGROUPS:
-                    do_cpt_int_err(xd, eenh_names[i], &pullHistoryNumGroups, list);
+                case StatePullEntry::NumGroups:
+                    do_cpt_int_err(xd, enumValueToString(*i), &pullHistoryNumGroups, list);
                     break;
-                case epullhPULL_NUMVALUESINXSUM:
-                    do_cpt_int_err(xd, eenh_names[i], &pullHist->numValuesInXSum, list);
+                case StatePullEntry::NumValuesInXSum:
+                    do_cpt_int_err(xd, enumValueToString(*i), &pullHist->numValuesInXSum, list);
                     break;
-                case epullhPULL_NUMVALUESINFSUM:
-                    do_cpt_int_err(xd, eenh_names[i], &pullHist->numValuesInFSum, list);
+                case StatePullEntry::NumValuesInFSum:
+                    do_cpt_int_err(xd, enumValueToString(*i), &pullHist->numValuesInFSum, list);
                     break;
                 default:
                     gmx_fatal(FARGS,
                               "Unknown pull history entry %d\n"
                               "You are probably reading a new checkpoint file with old code",
-                              i);
+                              enumValueToBitMask(*i));
             }
         }
     }
@@ -1813,11 +1903,11 @@ static int doCptPullHist(XDR* xd, gmx_bool bRead, int fflags, PullHistory* pullH
     {
         for (size_t i = 0; i < pullHist->pullCoordinateSums.size() && ret == 0; i++)
         {
-            ret = doCptPullCoordHist(xd, &(pullHist->pullCoordinateSums[i]), part, list);
+            ret = doCptPullCoordHist(xd, &(pullHist->pullCoordinateSums[i]), list);
         }
         for (size_t i = 0; i < pullHist->pullGroupSums.size() && ret == 0; i++)
         {
-            ret = doCptPullGroupHist(xd, &(pullHist->pullGroupSums[i]), part, list);
+            ret = doCptPullGroupHist(xd, &(pullHist->pullGroupSums[i]), list);
         }
     }
 
@@ -1841,61 +1931,61 @@ static int do_cpt_df_hist(XDR* xd, int fflags, int nlambda, df_history_t** dfhis
     }
     df_history_t* dfhist = *dfhistPtr;
 
-    const StatePart part = StatePart::freeEnergyHistory;
-    for (int i = 0; (i < edfhNR && ret == 0); i++)
+    using StateFlags = gmx::EnumerationArray<StateFepEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        if (fflags & (1 << i))
+        if (fflags & enumValueToBitMask(*i))
         {
-            switch (i)
+            switch (*i)
             {
-                case edfhBEQUIL:
-                    ret = do_cpte_bool(xd, part, i, fflags, &dfhist->bEquil, list);
+                case StateFepEntry::IsEquilibrated:
+                    ret = do_cpte_bool(xd, *i, fflags, &dfhist->bEquil, list);
                     break;
-                case edfhNATLAMBDA:
-                    ret = do_cpte_ints(xd, part, i, fflags, nlambda, &dfhist->n_at_lam, list);
+                case StateFepEntry::NumAtLambda:
+                    ret = do_cpte_ints(xd, *i, fflags, nlambda, &dfhist->n_at_lam, list);
                     break;
-                case edfhWLHISTO:
-                    ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->wl_histo, list);
+                case StateFepEntry::WangLandauHistogram:
+                    ret = do_cpte_reals(xd, *i, fflags, nlambda, &dfhist->wl_histo, list);
                     break;
-                case edfhWLDELTA:
-                    ret = do_cpte_real(xd, part, i, fflags, &dfhist->wl_delta, list);
+                case StateFepEntry::WangLandauDelta:
+                    ret = do_cpte_real(xd, *i, fflags, &dfhist->wl_delta, list);
                     break;
-                case edfhSUMWEIGHTS:
-                    ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_weights, list);
+                case StateFepEntry::SumWeights:
+                    ret = do_cpte_reals(xd, *i, fflags, nlambda, &dfhist->sum_weights, list);
                     break;
-                case edfhSUMDG:
-                    ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_dg, list);
+                case StateFepEntry::SumDG:
+                    ret = do_cpte_reals(xd, *i, fflags, nlambda, &dfhist->sum_dg, list);
                     break;
-                case edfhSUMMINVAR:
-                    ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_minvar, list);
+                case StateFepEntry::SumMinVar:
+                    ret = do_cpte_reals(xd, *i, fflags, nlambda, &dfhist->sum_minvar, list);
                     break;
-                case edfhSUMVAR:
-                    ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_variance, list);
+                case StateFepEntry::SumVar:
+                    ret = do_cpte_reals(xd, *i, fflags, nlambda, &dfhist->sum_variance, list);
                     break;
-                case edfhACCUMP:
-                    ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_p, list);
+                case StateFepEntry::Accump:
+                    ret = do_cpte_nmatrix(xd, *i, fflags, nlambda, dfhist->accum_p, list);
                     break;
-                case edfhACCUMM:
-                    ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_m, list);
+                case StateFepEntry::Accumm:
+                    ret = do_cpte_nmatrix(xd, *i, fflags, nlambda, dfhist->accum_m, list);
                     break;
-                case edfhACCUMP2:
-                    ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_p2, list);
+                case StateFepEntry::Accump2:
+                    ret = do_cpte_nmatrix(xd, *i, fflags, nlambda, dfhist->accum_p2, list);
                     break;
-                case edfhACCUMM2:
-                    ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_m2, list);
+                case StateFepEntry::Accumm2:
+                    ret = do_cpte_nmatrix(xd, *i, fflags, nlambda, dfhist->accum_m2, list);
                     break;
-                case edfhTIJ:
-                    ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->Tij, list);
+                case StateFepEntry::Tij:
+                    ret = do_cpte_nmatrix(xd, *i, fflags, nlambda, dfhist->Tij, list);
                     break;
-                case edfhTIJEMP:
-                    ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->Tij_empirical, list);
+                case StateFepEntry::TijEmp:
+                    ret = do_cpte_nmatrix(xd, *i, fflags, nlambda, dfhist->Tij_empirical, list);
                     break;
 
                 default:
                     gmx_fatal(FARGS,
                               "Unknown df history entry %d\n"
                               "You are probably reading a new checkpoint file with old code",
-                              i);
+                              enumValueToBitMask(*i));
             }
         }
     }
@@ -1969,33 +2059,35 @@ static int do_cpt_correlation_grid(XDR*                         xd,
                                    gmx_unused int               fflags,
                                    gmx::CorrelationGridHistory* corrGrid,
                                    FILE*                        list,
-                                   int                          eawhh)
+                                   StateAwhEntry                eawhh)
 {
     int ret = 0;
 
-    do_cpt_int_err(xd, eawhh_names[eawhh], &(corrGrid->numCorrelationTensors), list);
-    do_cpt_int_err(xd, eawhh_names[eawhh], &(corrGrid->tensorSize), list);
-    do_cpt_int_err(xd, eawhh_names[eawhh], &(corrGrid->blockDataListSize), list);
+    do_cpt_int_err(xd, enumValueToString(eawhh), &(corrGrid->numCorrelationTensors), list);
+    do_cpt_int_err(xd, enumValueToString(eawhh), &(corrGrid->tensorSize), list);
+    do_cpt_int_err(xd, enumValueToString(eawhh), &(corrGrid->blockDataListSize), list);
 
     if (bRead)
     {
-        initCorrelationGridHistory(corrGrid, corrGrid->numCorrelationTensors, corrGrid->tensorSize,
-                                   corrGrid->blockDataListSize);
+        initCorrelationGridHistory(
+                corrGrid, corrGrid->numCorrelationTensors, corrGrid->tensorSize, corrGrid->blockDataListSize);
     }
 
     for (gmx::CorrelationBlockDataHistory& blockData : corrGrid->blockDataBuffer)
     {
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockSumWeight), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockSumSquareWeight), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockSumWeightX), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockSumWeightY), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.sumOverBlocksSquareBlockWeight), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.sumOverBlocksBlockSquareWeight), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.sumOverBlocksBlockWeightBlockWeightX), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.sumOverBlocksBlockWeightBlockWeightY), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockLength), list);
-        do_cpt_int_err(xd, eawhh_names[eawhh], &(blockData.previousBlockIndex), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.correlationIntegral), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.blockSumWeight), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.blockSumSquareWeight), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.blockSumWeightX), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.blockSumWeightY), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.sumOverBlocksSquareBlockWeight), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.sumOverBlocksBlockSquareWeight), list);
+        do_cpt_double_err(
+                xd, enumValueToString(eawhh), &(blockData.sumOverBlocksBlockWeightBlockWeightX), list);
+        do_cpt_double_err(
+                xd, enumValueToString(eawhh), &(blockData.sumOverBlocksBlockWeightBlockWeightY), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.blockLength), list);
+        do_cpt_int_err(xd, enumValueToString(eawhh), &(blockData.previousBlockIndex), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.correlationIntegral), list);
     }
 
     return ret;
@@ -2006,70 +2098,71 @@ static int do_cpt_awh_bias(XDR* xd, gmx_bool bRead, int fflags, gmx::AwhBiasHist
     int ret = 0;
 
     gmx::AwhBiasStateHistory* state = &biasHistory->state;
-    for (int i = 0; (i < eawhhNR && ret == 0); i++)
+    using StateFlags                = gmx::EnumerationArray<StateAwhEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        if (fflags & (1 << i))
+        if (fflags & enumValueToBitMask(*i))
         {
-            switch (i)
+            switch (*i)
             {
-                case eawhhIN_INITIAL:
-                    do_cpt_bool_err(xd, eawhh_names[i], &state->in_initial, list);
+                case StateAwhEntry::InInitial:
+                    do_cpt_bool_err(xd, enumValueToString(*i), &state->in_initial, list);
                     break;
-                case eawhhEQUILIBRATEHISTOGRAM:
-                    do_cpt_bool_err(xd, eawhh_names[i], &state->equilibrateHistogram, list);
+                case StateAwhEntry::EquilibrateHistogram:
+                    do_cpt_bool_err(xd, enumValueToString(*i), &state->equilibrateHistogram, list);
                     break;
-                case eawhhHISTSIZE:
-                    do_cpt_double_err(xd, eawhh_names[i], &state->histSize, list);
+                case StateAwhEntry::HistogramSize:
+                    do_cpt_double_err(xd, enumValueToString(*i), &state->histSize, list);
                     break;
-                case eawhhNPOINTS:
+                case StateAwhEntry::NumPoints:
                 {
                     int numPoints;
                     if (!bRead)
                     {
                         numPoints = biasHistory->pointState.size();
                     }
-                    do_cpt_int_err(xd, eawhh_names[i], &numPoints, list);
+                    do_cpt_int_err(xd, enumValueToString(*i), &numPoints, list);
                     if (bRead)
                     {
                         biasHistory->pointState.resize(numPoints);
                     }
                 }
                 break;
-                case eawhhCOORDPOINT:
+                case StateAwhEntry::CoordPoint:
                     for (auto& psh : biasHistory->pointState)
                     {
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.target, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.free_energy, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.bias, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.weightsum_iteration, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.weightsum_covering, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.weightsum_tot, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.weightsum_ref, list);
-                        do_cpt_step_err(xd, eawhh_names[i], &psh.last_update_index, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.log_pmfsum, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.visits_iteration, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.visits_tot, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.target, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.free_energy, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.bias, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.weightsum_iteration, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.weightsum_covering, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.weightsum_tot, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.weightsum_ref, list);
+                        do_cpt_step_err(xd, enumValueToString(*i), &psh.last_update_index, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.log_pmfsum, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.visits_iteration, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.visits_tot, list);
                     }
                     break;
-                case eawhhUMBRELLAGRIDPOINT:
-                    do_cpt_int_err(xd, eawhh_names[i], &(state->umbrellaGridpoint), list);
+                case StateAwhEntry::UmbrellaGridPoint:
+                    do_cpt_int_err(xd, enumValueToString(*i), &(state->umbrellaGridpoint), list);
                     break;
-                case eawhhUPDATELIST:
-                    do_cpt_int_err(xd, eawhh_names[i], &(state->origin_index_updatelist), list);
-                    do_cpt_int_err(xd, eawhh_names[i], &(state->end_index_updatelist), list);
+                case StateAwhEntry::UpdateList:
+                    do_cpt_int_err(xd, enumValueToString(*i), &(state->origin_index_updatelist), list);
+                    do_cpt_int_err(xd, enumValueToString(*i), &(state->end_index_updatelist), list);
                     break;
-                case eawhhLOGSCALEDSAMPLEWEIGHT:
-                    do_cpt_double_err(xd, eawhh_names[i], &(state->logScaledSampleWeight), list);
-                    do_cpt_double_err(xd, eawhh_names[i], &(state->maxLogScaledSampleWeight), list);
+                case StateAwhEntry::LogScaledSampleWeight:
+                    do_cpt_double_err(xd, enumValueToString(*i), &(state->logScaledSampleWeight), list);
+                    do_cpt_double_err(xd, enumValueToString(*i), &(state->maxLogScaledSampleWeight), list);
                     break;
-                case eawhhNUMUPDATES:
-                    do_cpt_step_err(xd, eawhh_names[i], &(state->numUpdates), list);
+                case StateAwhEntry::NumUpdates:
+                    do_cpt_step_err(xd, enumValueToString(*i), &(state->numUpdates), list);
                     break;
-                case eawhhFORCECORRELATIONGRID:
-                    ret = do_cpt_correlation_grid(xd, bRead, fflags,
-                                                  &biasHistory->forceCorrelationGrid, list, i);
+                case StateAwhEntry::ForceCorrelationGrid:
+                    ret = do_cpt_correlation_grid(
+                            xd, bRead, fflags, &biasHistory->forceCorrelationGrid, list, *i);
                     break;
-                default: gmx_fatal(FARGS, "Unknown awh history entry %d\n", i);
+                default: gmx_fatal(FARGS, "Unknown awh history entry %d\n", enumValueToBitMask(*i));
             }
         }
     }
@@ -2128,12 +2221,12 @@ static int do_cpt_awh(XDR* xd, gmx_bool bRead, int fflags, gmx::AwhHistory* awhH
     return ret;
 }
 
-static void do_cpt_mdmodules(int                           fileVersion,
-                             t_fileio*                     checkpointFileHandle,
-                             const gmx::MdModulesNotifier& mdModulesNotifier,
-                             FILE*                         outputFile)
+static void do_cpt_mdmodules(int                            fileVersion,
+                             t_fileio*                      checkpointFileHandle,
+                             const gmx::MDModulesNotifiers& mdModulesNotifiers,
+                             FILE*                          outputFile)
 {
-    if (fileVersion >= cptv_MdModules)
+    if (fileVersion >= cptv_MDModules)
     {
         gmx::FileIOXdrSerializer serializer(checkpointFileHandle);
         gmx::KeyValueTreeObject  mdModuleCheckpointParameterTree =
@@ -2143,10 +2236,10 @@ static void do_cpt_mdmodules(int                           fileVersion,
             gmx::TextWriter textWriter(outputFile);
             gmx::dumpKeyValueTree(&textWriter, mdModuleCheckpointParameterTree);
         }
-        gmx::MdModulesCheckpointReadingDataOnMaster mdModuleCheckpointReadingDataOnMaster = {
+        gmx::MDModulesCheckpointReadingDataOnMaster mdModuleCheckpointReadingDataOnMaster = {
             mdModuleCheckpointParameterTree, fileVersion
         };
-        mdModulesNotifier.checkpointingNotifications_.notify(mdModuleCheckpointReadingDataOnMaster);
+        mdModulesNotifiers.checkpointingNotifier_.notify(mdModuleCheckpointReadingDataOnMaster);
     }
 }
 
@@ -2219,8 +2312,7 @@ static int do_cpt_files(XDR* xd, gmx_bool bRead, std::vector<gmx_file_position_t
             {
                 return -1;
             }
-            if (do_cpt_u_chars(xd, "file_checksum", outputfile.checksum.size(),
-                               outputfile.checksum.data(), list)
+            if (do_cpt_u_chars(xd, "file_checksum", outputfile.checksum.size(), outputfile.checksum.data(), list)
                 != 0)
             {
                 return -1;
@@ -2237,19 +2329,25 @@ static int do_cpt_files(XDR* xd, gmx_bool bRead, std::vector<gmx_file_position_t
 void write_checkpoint_data(t_fileio*                         fp,
                            CheckpointHeaderContents          headerContents,
                            gmx_bool                          bExpanded,
-                           int                               elamstats,
+                           LambdaWeightCalculation           elamstats,
                            t_state*                          state,
                            ObservablesHistory*               observablesHistory,
-                           const gmx::MdModulesNotifier&     mdModulesNotifier,
+                           const gmx::MDModulesNotifiers&    mdModulesNotifiers,
                            std::vector<gmx_file_position_t>* outputfiles,
                            gmx::WriteCheckpointDataHolder*   modularSimulatorCheckpointData)
 {
     headerContents.flags_eks = 0;
     if (state->ekinstate.bUpToDate)
     {
-        headerContents.flags_eks = ((1 << eeksEKIN_N) | (1 << eeksEKINH) | (1 << eeksEKINF)
-                                    | (1 << eeksEKINO) | (1 << eeksEKINSCALEF) | (1 << eeksEKINSCALEH)
-                                    | (1 << eeksVSCALE) | (1 << eeksDEKINDL) | (1 << eeksMVCOS));
+        headerContents.flags_eks = (enumValueToBitMask(StateKineticEntry::EkinNumber)
+                                    | enumValueToBitMask(StateKineticEntry::EkinHalfStep)
+                                    | enumValueToBitMask(StateKineticEntry::EkinFullStep)
+                                    | enumValueToBitMask(StateKineticEntry::EkinHalfStepOld)
+                                    | enumValueToBitMask(StateKineticEntry::EkinNoseHooverScaleFullStep)
+                                    | enumValueToBitMask(StateKineticEntry::EkinNoseHooverScaleHalfStep)
+                                    | enumValueToBitMask(StateKineticEntry::VelocityScale)
+                                    | enumValueToBitMask(StateKineticEntry::DEkinDLambda)
+                                    | enumValueToBitMask(StateKineticEntry::Mvcos));
     }
     headerContents.isModularSimulatorCheckpoint = !modularSimulatorCheckpointData->empty();
 
@@ -2257,22 +2355,26 @@ void write_checkpoint_data(t_fileio*                         fp,
     headerContents.flags_enh  = 0;
     if (enerhist != nullptr && (enerhist->nsum > 0 || enerhist->nsum_sim > 0))
     {
-        headerContents.flags_enh |=
-                (1 << eenhENERGY_N) | (1 << eenhENERGY_NSTEPS) | (1 << eenhENERGY_NSTEPS_SIM);
+        headerContents.flags_enh |= enumValueToBitMask(StateEnergyEntry::N)
+                                    | enumValueToBitMask(StateEnergyEntry::NumSteps)
+                                    | enumValueToBitMask(StateEnergyEntry::NumStepsSim);
         if (enerhist->nsum > 0)
         {
-            headerContents.flags_enh |=
-                    ((1 << eenhENERGY_AVER) | (1 << eenhENERGY_SUM) | (1 << eenhENERGY_NSUM));
+            headerContents.flags_enh |= (enumValueToBitMask(StateEnergyEntry::Aver)
+                                         | enumValueToBitMask(StateEnergyEntry::Sum)
+                                         | enumValueToBitMask(StateEnergyEntry::NumSum));
         }
         if (enerhist->nsum_sim > 0)
         {
-            headerContents.flags_enh |= ((1 << eenhENERGY_SUM_SIM) | (1 << eenhENERGY_NSUM_SIM));
+            headerContents.flags_enh |= (enumValueToBitMask(StateEnergyEntry::SumSim)
+                                         | enumValueToBitMask(StateEnergyEntry::NumSumSim));
         }
         if (enerhist->deltaHForeignLambdas != nullptr)
         {
-            headerContents.flags_enh |=
-                    ((1 << eenhENERGY_DELTA_H_NN) | (1 << eenhENERGY_DELTA_H_LIST)
-                     | (1 << eenhENERGY_DELTA_H_STARTTIME) | (1 << eenhENERGY_DELTA_H_STARTLAMBDA));
+            headerContents.flags_enh |= (enumValueToBitMask(StateEnergyEntry::DeltaHNN)
+                                         | enumValueToBitMask(StateEnergyEntry::DeltaHList)
+                                         | enumValueToBitMask(StateEnergyEntry::DeltaHStartTime)
+                                         | enumValueToBitMask(StateEnergyEntry::DeltaHStartLambda));
         }
     }
 
@@ -2280,36 +2382,50 @@ void write_checkpoint_data(t_fileio*                         fp,
     headerContents.flagsPullHistory = 0;
     if (pullHist != nullptr && (pullHist->numValuesInXSum > 0 || pullHist->numValuesInFSum > 0))
     {
-        headerContents.flagsPullHistory |= (1 << epullhPULL_NUMCOORDINATES);
-        headerContents.flagsPullHistory |= ((1 << epullhPULL_NUMGROUPS) | (1 << epullhPULL_NUMVALUESINXSUM)
-                                            | (1 << epullhPULL_NUMVALUESINFSUM));
+        headerContents.flagsPullHistory |= enumValueToBitMask(StatePullEntry::NumCoordinates);
+        headerContents.flagsPullHistory |= (enumValueToBitMask(StatePullEntry::NumGroups)
+                                            | enumValueToBitMask(StatePullEntry::NumValuesInXSum)
+                                            | enumValueToBitMask(StatePullEntry::NumValuesInFSum));
     }
 
     headerContents.flags_dfh = 0;
     if (bExpanded)
     {
-        headerContents.flags_dfh = ((1 << edfhBEQUIL) | (1 << edfhNATLAMBDA) | (1 << edfhSUMWEIGHTS)
-                                    | (1 << edfhSUMDG) | (1 << edfhTIJ) | (1 << edfhTIJEMP));
+        headerContents.flags_dfh =
+                (enumValueToBitMask(StateFepEntry::IsEquilibrated)
+                 | enumValueToBitMask(StateFepEntry::NumAtLambda)
+                 | enumValueToBitMask(StateFepEntry::SumWeights) | enumValueToBitMask(StateFepEntry::SumDG)
+                 | enumValueToBitMask(StateFepEntry::Tij) | enumValueToBitMask(StateFepEntry::TijEmp));
         if (EWL(elamstats))
         {
-            headerContents.flags_dfh |= ((1 << edfhWLDELTA) | (1 << edfhWLHISTO));
+            headerContents.flags_dfh |= (enumValueToBitMask(StateFepEntry::WangLandauDelta)
+                                         | enumValueToBitMask(StateFepEntry::WangLandauHistogram));
         }
-        if ((elamstats == elamstatsMINVAR) || (elamstats == elamstatsBARKER)
-            || (elamstats == elamstatsMETROPOLIS))
+        if ((elamstats == LambdaWeightCalculation::Minvar) || (elamstats == LambdaWeightCalculation::Barker)
+            || (elamstats == LambdaWeightCalculation::Metropolis))
         {
-            headerContents.flags_dfh |= ((1 << edfhACCUMP) | (1 << edfhACCUMM) | (1 << edfhACCUMP2)
-                                         | (1 << edfhACCUMM2) | (1 << edfhSUMMINVAR) | (1 << edfhSUMVAR));
+            headerContents.flags_dfh |= (enumValueToBitMask(StateFepEntry::Accump)
+                                         | enumValueToBitMask(StateFepEntry::Accumm)
+                                         | enumValueToBitMask(StateFepEntry::Accump2)
+                                         | enumValueToBitMask(StateFepEntry::Accumm2)
+                                         | enumValueToBitMask(StateFepEntry::SumMinVar)
+                                         | enumValueToBitMask(StateFepEntry::SumVar));
         }
     }
 
     headerContents.flags_awhh = 0;
     if (state->awhHistory != nullptr && !state->awhHistory->bias.empty())
     {
-        headerContents.flags_awhh |=
-                ((1 << eawhhIN_INITIAL) | (1 << eawhhEQUILIBRATEHISTOGRAM) | (1 << eawhhHISTSIZE)
-                 | (1 << eawhhNPOINTS) | (1 << eawhhCOORDPOINT) | (1 << eawhhUMBRELLAGRIDPOINT)
-                 | (1 << eawhhUPDATELIST) | (1 << eawhhLOGSCALEDSAMPLEWEIGHT)
-                 | (1 << eawhhNUMUPDATES) | (1 << eawhhFORCECORRELATIONGRID));
+        headerContents.flags_awhh |= (enumValueToBitMask(StateAwhEntry::InInitial)
+                                      | enumValueToBitMask(StateAwhEntry::EquilibrateHistogram)
+                                      | enumValueToBitMask(StateAwhEntry::HistogramSize)
+                                      | enumValueToBitMask(StateAwhEntry::NumPoints)
+                                      | enumValueToBitMask(StateAwhEntry::CoordPoint)
+                                      | enumValueToBitMask(StateAwhEntry::UmbrellaGridPoint)
+                                      | enumValueToBitMask(StateAwhEntry::UpdateList)
+                                      | enumValueToBitMask(StateAwhEntry::LogScaledSampleWeight)
+                                      | enumValueToBitMask(StateAwhEntry::NumUpdates)
+                                      | enumValueToBitMask(StateAwhEntry::ForceCorrelationGrid));
     }
 
     do_cpt_header(gmx_fio_getxdr(fp), FALSE, nullptr, &headerContents);
@@ -2317,30 +2433,30 @@ void write_checkpoint_data(t_fileio*                         fp,
     if ((do_cpt_state(gmx_fio_getxdr(fp), state->flags, state, nullptr) < 0)
         || (do_cpt_ekinstate(gmx_fio_getxdr(fp), headerContents.flags_eks, &state->ekinstate, nullptr) < 0)
         || (do_cpt_enerhist(gmx_fio_getxdr(fp), FALSE, headerContents.flags_enh, enerhist, nullptr) < 0)
-        || (doCptPullHist(gmx_fio_getxdr(fp), FALSE, headerContents.flagsPullHistory, pullHist,
-                          StatePart::pullHistory, nullptr)
-            < 0)
-        || (do_cpt_df_hist(gmx_fio_getxdr(fp), headerContents.flags_dfh, headerContents.nlambda,
-                           &state->dfhist, nullptr)
+        || (doCptPullHist(gmx_fio_getxdr(fp), FALSE, headerContents.flagsPullHistory, pullHist, nullptr) < 0)
+        || (do_cpt_df_hist(gmx_fio_getxdr(fp), headerContents.flags_dfh, headerContents.nlambda, &state->dfhist, nullptr)
             < 0)
-        || (do_cpt_EDstate(gmx_fio_getxdr(fp), FALSE, headerContents.nED,
-                           observablesHistory->edsamHistory.get(), nullptr)
+        || (do_cpt_EDstate(
+                    gmx_fio_getxdr(fp), FALSE, headerContents.nED, observablesHistory->edsamHistory.get(), nullptr)
             < 0)
         || (do_cpt_awh(gmx_fio_getxdr(fp), FALSE, headerContents.flags_awhh, state->awhHistory.get(), nullptr) < 0)
-        || (do_cpt_swapstate(gmx_fio_getxdr(fp), FALSE, headerContents.eSwapCoords,
-                             observablesHistory->swapHistory.get(), nullptr)
+        || (do_cpt_swapstate(gmx_fio_getxdr(fp),
+                             FALSE,
+                             headerContents.eSwapCoords,
+                             observablesHistory->swapHistory.get(),
+                             nullptr)
             < 0)
         || (do_cpt_files(gmx_fio_getxdr(fp), FALSE, outputfiles, nullptr, headerContents.file_version) < 0))
     {
         gmx_file("Cannot read/write checkpoint; corrupt file, or maybe you are out of disk space?");
     }
 
-    // Checkpointing MdModules
+    // Checkpointing MDModules
     {
         gmx::KeyValueTreeBuilder          builder;
-        gmx::MdModulesWriteCheckpointData mdModulesWriteCheckpoint = { builder.rootObject(),
+        gmx::MDModulesWriteCheckpointData mdModulesWriteCheckpoint = { builder.rootObject(),
                                                                        headerContents.file_version };
-        mdModulesNotifier.checkpointingNotifications_.notify(mdModulesWriteCheckpoint);
+        mdModulesNotifiers.checkpointingNotifier_.notify(mdModulesWriteCheckpoint);
         auto                     tree = builder.build();
         gmx::FileIOXdrSerializer serializer(fp);
         gmx::serializeKeyValueTree(tree, &serializer);
@@ -2435,8 +2551,8 @@ static void check_match(FILE*                           fplog,
 
     if (reproducibilityRequested)
     {
-        check_string(fplog, "Program name", gmx::getProgramContext().fullBinaryPath(),
-                     headerContents.fprog, &mm);
+        check_string(
+                fplog, "Program name", gmx::getProgramContext().fullBinaryPath(), headerContents.fprog, &mm);
 
         check_int(fplog, "#ranks", cr->nnodes, headerContents.nnodes, &mm);
     }
@@ -2511,13 +2627,13 @@ static void read_checkpoint(const char*                    fn,
                             t_fileio*                      logfio,
                             const t_commrec*               cr,
                             const ivec                     dd_nc,
-                            int                            eIntegrator,
+                            IntegrationAlgorithm           eIntegrator,
                             int*                           init_fep_state,
                             CheckpointHeaderContents*      headerContents,
                             t_state*                       state,
                             ObservablesHistory*            observablesHistory,
                             gmx_bool                       reproducibilityRequested,
-                            const gmx::MdModulesNotifier&  mdModulesNotifier,
+                            const gmx::MDModulesNotifiers& mdModulesNotifiers,
                             gmx::ReadCheckpointDataHolder* modularSimulatorCheckpointData,
                             bool                           useModularSimulator)
 {
@@ -2552,21 +2668,24 @@ static void read_checkpoint(const char*                    fn,
         gmx_fatal(FARGS,
                   "Checkpoint file is for a system of %d atoms, while the current system consists "
                   "of %d atoms",
-                  headerContents->natoms, state->natoms);
+                  headerContents->natoms,
+                  state->natoms);
     }
     if (headerContents->ngtc != state->ngtc)
     {
         gmx_fatal(FARGS,
                   "Checkpoint file is for a system of %d T-coupling groups, while the current "
                   "system consists of %d T-coupling groups",
-                  headerContents->ngtc, state->ngtc);
+                  headerContents->ngtc,
+                  state->ngtc);
     }
     if (headerContents->nnhpres != state->nnhpres)
     {
         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",
-                  headerContents->nnhpres, state->nnhpres);
+                  headerContents->nnhpres,
+                  state->nnhpres);
     }
 
     int nlambdaHistory = (state->dfhist ? state->dfhist->nlambda : 0);
@@ -2575,10 +2694,13 @@ static void read_checkpoint(const char*                    fn,
         gmx_fatal(FARGS,
                   "Checkpoint file is for a system with %d lambda states, while the current system "
                   "consists of %d lambda states",
-                  headerContents->nlambda, nlambdaHistory);
+                  headerContents->nlambda,
+                  nlambdaHistory);
     }
 
-    init_gtc_state(state, state->ngtc, state->nnhpres,
+    init_gtc_state(state,
+                   state->ngtc,
+                   state->nnhpres,
                    headerContents->nhchainlength); /* need to keep this here to keep the tpr format working */
     /* write over whatever was read; we use the number of Nose-Hoover chains from the checkpoint */
 
@@ -2635,20 +2757,21 @@ static void read_checkpoint(const char*                    fn,
     {
         cp_error();
     }
-    state->ekinstate.hasReadEkinState = (((headerContents->flags_eks & (1 << eeksEKINH)) != 0)
-                                         || ((headerContents->flags_eks & (1 << eeksEKINF)) != 0)
-                                         || ((headerContents->flags_eks & (1 << eeksEKINO)) != 0)
-                                         || (((headerContents->flags_eks & (1 << eeksEKINSCALEF))
-                                              | (headerContents->flags_eks & (1 << eeksEKINSCALEH))
-                                              | (headerContents->flags_eks & (1 << eeksVSCALE)))
-                                             != 0));
+    state->ekinstate.hasReadEkinState =
+            (((headerContents->flags_eks & enumValueToBitMask(StateKineticEntry::EkinHalfStep)) != 0)
+             || ((headerContents->flags_eks & enumValueToBitMask(StateKineticEntry::EkinFullStep)) != 0)
+             || ((headerContents->flags_eks & enumValueToBitMask(StateKineticEntry::EkinHalfStepOld)) != 0)
+             || (((headerContents->flags_eks & enumValueToBitMask(StateKineticEntry::EkinNoseHooverScaleFullStep))
+                  | (headerContents->flags_eks & enumValueToBitMask(StateKineticEntry::EkinNoseHooverScaleHalfStep))
+                  | (headerContents->flags_eks & enumValueToBitMask(StateKineticEntry::VelocityScale)))
+                 != 0));
 
     if (headerContents->flags_enh && observablesHistory->energyHistory == nullptr)
     {
         observablesHistory->energyHistory = std::make_unique<energyhistory_t>();
     }
-    ret = do_cpt_enerhist(gmx_fio_getxdr(fp), TRUE, headerContents->flags_enh,
-                          observablesHistory->energyHistory.get(), nullptr);
+    ret = do_cpt_enerhist(
+            gmx_fio_getxdr(fp), TRUE, headerContents->flags_enh, observablesHistory->energyHistory.get(), nullptr);
     if (ret)
     {
         cp_error();
@@ -2660,8 +2783,11 @@ static void read_checkpoint(const char*                    fn,
         {
             observablesHistory->pullHistory = std::make_unique<PullHistory>();
         }
-        ret = doCptPullHist(gmx_fio_getxdr(fp), TRUE, headerContents->flagsPullHistory,
-                            observablesHistory->pullHistory.get(), StatePart::pullHistory, nullptr);
+        ret = doCptPullHist(gmx_fio_getxdr(fp),
+                            TRUE,
+                            headerContents->flagsPullHistory,
+                            observablesHistory->pullHistory.get(),
+                            nullptr);
         if (ret)
         {
             cp_error();
@@ -2674,8 +2800,8 @@ static void read_checkpoint(const char*                    fn,
                   "Continuing from checkpoint files written before GROMACS 4.5 is not supported");
     }
 
-    ret = do_cpt_df_hist(gmx_fio_getxdr(fp), headerContents->flags_dfh, headerContents->nlambda,
-                         &state->dfhist, nullptr);
+    ret = do_cpt_df_hist(
+            gmx_fio_getxdr(fp), headerContents->flags_dfh, headerContents->nlambda, &state->dfhist, nullptr);
     if (ret)
     {
         cp_error();
@@ -2685,8 +2811,8 @@ static void read_checkpoint(const char*                    fn,
     {
         observablesHistory->edsamHistory = std::make_unique<edsamhistory_t>(edsamhistory_t{});
     }
-    ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, headerContents->nED,
-                         observablesHistory->edsamHistory.get(), nullptr);
+    ret = do_cpt_EDstate(
+            gmx_fio_getxdr(fp), TRUE, headerContents->nED, observablesHistory->edsamHistory.get(), nullptr);
     if (ret)
     {
         cp_error();
@@ -2702,12 +2828,12 @@ static void read_checkpoint(const char*                    fn,
         cp_error();
     }
 
-    if (headerContents->eSwapCoords != eswapNO && observablesHistory->swapHistory == nullptr)
+    if (headerContents->eSwapCoords != SwapType::No && observablesHistory->swapHistory == nullptr)
     {
         observablesHistory->swapHistory = std::make_unique<swaphistory_t>(swaphistory_t{});
     }
-    ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, headerContents->eSwapCoords,
-                           observablesHistory->swapHistory.get(), nullptr);
+    ret = do_cpt_swapstate(
+            gmx_fio_getxdr(fp), TRUE, headerContents->eSwapCoords, observablesHistory->swapHistory.get(), nullptr);
     if (ret)
     {
         cp_error();
@@ -2719,7 +2845,7 @@ static void read_checkpoint(const char*                    fn,
     {
         cp_error();
     }
-    do_cpt_mdmodules(headerContents->file_version, fp, mdModulesNotifier, nullptr);
+    do_cpt_mdmodules(headerContents->file_version, fp, mdModulesNotifiers, nullptr);
     if (headerContents->file_version >= cptv_ModularSimulator)
     {
         gmx::FileIOXdrSerializer serializer(fp);
@@ -2745,7 +2871,7 @@ void load_checkpoint(const char*                    fn,
                      t_state*                       state,
                      ObservablesHistory*            observablesHistory,
                      gmx_bool                       reproducibilityRequested,
-                     const gmx::MdModulesNotifier&  mdModulesNotifier,
+                     const gmx::MDModulesNotifiers& mdModulesNotifiers,
                      gmx::ReadCheckpointDataHolder* modularSimulatorCheckpointData,
                      bool                           useModularSimulator)
 {
@@ -2753,17 +2879,27 @@ void load_checkpoint(const char*                    fn,
     if (SIMMASTER(cr))
     {
         /* Read the state from the checkpoint file */
-        read_checkpoint(fn, logfio, cr, dd_nc, ir->eI, &(ir->fepvals->init_fep_state),
-                        &headerContents, state, observablesHistory, reproducibilityRequested,
-                        mdModulesNotifier, modularSimulatorCheckpointData, useModularSimulator);
+        read_checkpoint(fn,
+                        logfio,
+                        cr,
+                        dd_nc,
+                        ir->eI,
+                        &(ir->fepvals->init_fep_state),
+                        &headerContents,
+                        state,
+                        observablesHistory,
+                        reproducibilityRequested,
+                        mdModulesNotifiers,
+                        modularSimulatorCheckpointData,
+                        useModularSimulator);
     }
     if (PAR(cr))
     {
         gmx_bcast(sizeof(headerContents.step), &headerContents.step, cr->mpiDefaultCommunicator);
-        gmx::MdModulesCheckpointReadingBroadcast broadcastCheckPointData = {
+        gmx::MDModulesCheckpointReadingBroadcast broadcastCheckPointData = {
             cr->mpiDefaultCommunicator, PAR(cr), headerContents.file_version
         };
-        mdModulesNotifier.checkpointingNotifications_.notify(broadcastCheckPointData);
+        mdModulesNotifiers.checkpointingNotifier_.notify(broadcastCheckPointData);
     }
     ir->bContinuation = TRUE;
     if (ir->nsteps >= 0)
@@ -2845,15 +2981,14 @@ static CheckpointHeaderContents read_checkpoint_data(t_fileio*
         cp_error();
     }
     PullHistory pullHist = {};
-    ret = doCptPullHist(gmx_fio_getxdr(fp), TRUE, headerContents.flagsPullHistory, &pullHist,
-                        StatePart::pullHistory, nullptr);
+    ret = doCptPullHist(gmx_fio_getxdr(fp), TRUE, headerContents.flagsPullHistory, &pullHist, nullptr);
     if (ret)
     {
         cp_error();
     }
 
-    ret = do_cpt_df_hist(gmx_fio_getxdr(fp), headerContents.flags_dfh, headerContents.nlambda,
-                         &state->dfhist, nullptr);
+    ret = do_cpt_df_hist(
+            gmx_fio_getxdr(fp), headerContents.flags_dfh, headerContents.nlambda, &state->dfhist, nullptr);
     if (ret)
     {
         cp_error();
@@ -2885,8 +3020,8 @@ static CheckpointHeaderContents read_checkpoint_data(t_fileio*
     {
         cp_error();
     }
-    gmx::MdModulesNotifier mdModuleNotifier;
-    do_cpt_mdmodules(headerContents.file_version, fp, mdModuleNotifier, nullptr);
+    gmx::MDModulesNotifiers mdModuleNotifiers;
+    do_cpt_mdmodules(headerContents.file_version, fp, mdModuleNotifiers, nullptr);
     if (headerContents.file_version >= cptv_ModularSimulator)
     {
         // Store modular checkpoint data into modularSimulatorCheckpointData
@@ -2920,21 +3055,21 @@ void read_checkpoint_trxframe(t_fileio* fp, t_trxframe* fr)
     fr->bTime     = TRUE;
     fr->time      = headerContents.t;
     fr->bLambda   = TRUE;
-    fr->lambda    = state.lambda[efptFEP];
+    fr->lambda    = state.lambda[FreeEnergyPerturbationCouplingType::Fep];
     fr->fep_state = state.fep_state;
     fr->bAtoms    = FALSE;
-    fr->bX        = ((state.flags & (1 << estX)) != 0);
+    fr->bX        = ((state.flags & enumValueToBitMask(StateEntry::X)) != 0);
     if (fr->bX)
     {
         fr->x = makeRvecArray(state.x, state.natoms);
     }
-    fr->bV = ((state.flags & (1 << estV)) != 0);
+    fr->bV = ((state.flags & enumValueToBitMask(StateEntry::V)) != 0);
     if (fr->bV)
     {
         fr->v = makeRvecArray(state.v, state.natoms);
     }
     fr->bF   = FALSE;
-    fr->bBox = ((state.flags & (1 << estBOX)) != 0);
+    fr->bBox = ((state.flags & enumValueToBitMask(StateEntry::Box)) != 0);
     if (fr->bBox)
     {
         copy_mat(state.box, fr->box);
@@ -2973,14 +3108,13 @@ void list_checkpoint(const char* fn, FILE* out)
     if (ret == 0)
     {
         PullHistory pullHist = {};
-        ret = doCptPullHist(gmx_fio_getxdr(fp), TRUE, headerContents.flagsPullHistory, &pullHist,
-                            StatePart::pullHistory, out);
+        ret = doCptPullHist(gmx_fio_getxdr(fp), TRUE, headerContents.flagsPullHistory, &pullHist, out);
     }
 
     if (ret == 0)
     {
-        ret = do_cpt_df_hist(gmx_fio_getxdr(fp), headerContents.flags_dfh, headerContents.nlambda,
-                             &state.dfhist, out);
+        ret = do_cpt_df_hist(
+                gmx_fio_getxdr(fp), headerContents.flags_dfh, headerContents.nlambda, &state.dfhist, out);
     }
 
     if (ret == 0)
@@ -3005,8 +3139,8 @@ void list_checkpoint(const char* fn, FILE* out)
         std::vector<gmx_file_position_t> outputfiles;
         ret = do_cpt_files(gmx_fio_getxdr(fp), TRUE, &outputfiles, out, headerContents.file_version);
     }
-    gmx::MdModulesNotifier mdModuleNotifier;
-    do_cpt_mdmodules(headerContents.file_version, fp, mdModuleNotifier, out);
+    gmx::MDModulesNotifiers mdModuleNotifiers;
+    do_cpt_mdmodules(headerContents.file_version, fp, mdModuleNotifiers, out);
     if (headerContents.file_version >= cptv_ModularSimulator)
     {
         gmx::FileIOXdrSerializer      serializer(fp);
index c3dbc3c1077ee06c3eb055250e74c70823d6e0b3..c6a996ac16e4a8e1c46a73020dd3f3e4d9962455 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
-#ifndef _checkpoint_h
-#define _checkpoint_h
+#ifndef GMX_FILEIO_CHECKPOINT_H
+#define GMX_FILEIO_CHECKPOINT_H
 
 #include <cstdio>
 
@@ -57,11 +57,14 @@ struct t_fileio;
 struct t_inputrec;
 class t_state;
 struct t_trxframe;
+enum class IntegrationAlgorithm : int;
+enum class SwapType : int;
+enum class LambdaWeightCalculation : int;
 
 namespace gmx
 {
 
-struct MdModulesNotifier;
+struct MDModulesNotifiers;
 class KeyValueTreeObject;
 class ReadCheckpointDataHolder;
 class WriteCheckpointDataHolder;
@@ -122,20 +125,20 @@ extern template void writeKvtCheckpointValue(const real&               value,
                                              KeyValueTreeObjectBuilder kvtBuilder);
 
 /*! \libinternal
- * \brief Provides the MdModules with the checkpointed data on the master rank.
+ * \brief Provides the MDModules with the checkpointed data on the master rank.
  */
-struct MdModulesCheckpointReadingDataOnMaster
+struct MDModulesCheckpointReadingDataOnMaster
 {
-    //! The data of the MdModules that is stored in the checkpoint file
+    //! The data of the MDModules that is stored in the checkpoint file
     const KeyValueTreeObject& checkpointedData_;
     //! The version of the read ceckpoint file
     int checkpointFileVersion_;
 };
 
 /*! \libinternal
- * \brief Provides the MdModules with the communication record to broadcast.
+ * \brief Provides the MDModules with the communication record to broadcast.
  */
-struct MdModulesCheckpointReadingBroadcast
+struct MDModulesCheckpointReadingBroadcast
 {
     //! The communicator
     MPI_Comm communicator_;
@@ -145,11 +148,11 @@ struct MdModulesCheckpointReadingBroadcast
     int checkpointFileVersion_;
 };
 
-/*! \libinternal \brief Writing the MdModules data to a checkpoint file.
+/*! \libinternal \brief Writing the MDModules data to a checkpoint file.
  */
-struct MdModulesWriteCheckpointData
+struct MDModulesWriteCheckpointData
 {
-    //! Builder for the Key-Value-Tree to store the MdModule checkpoint data
+    //! Builder for the Key-Value-Tree to store the MDModule checkpoint data
     KeyValueTreeObjectBuilder builder_;
     //! The version of the read file version
     int checkpointFileVersion_;
@@ -199,7 +202,7 @@ struct CheckpointHeaderContents
     //! Time string.
     char ftime[CPTSTRLEN];
     //! Which integrator is in use.
-    int eIntegrator;
+    IntegrationAlgorithm eIntegrator;
     //! Which part of the simulation this is.
     int simulation_part;
     //! Which step the checkpoint is at.
@@ -237,7 +240,7 @@ struct CheckpointHeaderContents
     //! Essential dynamics states.
     int nED;
     //! Enum for coordinate swapping.
-    int eSwapCoords;
+    SwapType eSwapCoords;
     //! Whether the checkpoint was written by modular simulator.
     bool isModularSimulatorCheckpoint = false;
 };
@@ -246,10 +249,10 @@ struct CheckpointHeaderContents
 void write_checkpoint_data(t_fileio*                         fp,
                            CheckpointHeaderContents          headerContents,
                            gmx_bool                          bExpanded,
-                           int                               elamstats,
+                           LambdaWeightCalculation           elamstats,
                            t_state*                          state,
                            ObservablesHistory*               observablesHistory,
-                           const gmx::MdModulesNotifier&     notifier,
+                           const gmx::MDModulesNotifiers&    mdModulesNotifiers,
                            std::vector<gmx_file_position_t>* outputfiles,
                            gmx::WriteCheckpointDataHolder*   modularSimulatorCheckpointData);
 
@@ -268,7 +271,7 @@ void load_checkpoint(const char*                    fn,
                      t_state*                       state,
                      ObservablesHistory*            observablesHistory,
                      gmx_bool                       reproducibilityRequested,
-                     const gmx::MdModulesNotifier&  mdModulesNotifier,
+                     const gmx::MDModulesNotifiers& mdModulesNotifiers,
                      gmx::ReadCheckpointDataHolder* modularSimulatorCheckpointData,
                      bool                           useModularSimulator);
 
index 7114d54c6d7e56862080fd25fcaaddc440d98e1b..5e68256a82bc727f4615a690b3f917fe40a55c4b 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +37,7 @@
  */
 #include "gmxpre.h"
 
-#include "confio.h"
+#include "gromacs/fileio/confio.h"
 
 #include <cstdio>
 #include <cstring>
@@ -107,8 +107,8 @@ void write_sto_conf_indexed(const char*    outfile,
         case efENT:
         case efPQR:
             out = gmx_fio_fopen(outfile, "w");
-            write_pdbfile_indexed(out, title, atoms, x, pbcType, box, ' ', -1, nindex, index,
-                                  nullptr, ftp == efPQR);
+            write_pdbfile_indexed(
+                    out, title, atoms, x, pbcType, box, ' ', -1, nindex, index, nullptr, ftp == efPQR);
             gmx_fio_fclose(out);
             break;
         case efESP:
@@ -174,7 +174,7 @@ void write_sto_conf(const char*    outfile,
 
 void write_sto_conf_mtop(const char*       outfile,
                          const char*       title,
-                         const gmx_mtop_t* mtop,
+                         const gmx_mtop_t& mtop,
                          const rvec        x[],
                          const rvec*       v,
                          PbcType           pbcType,
@@ -268,7 +268,7 @@ void ChainIdFiller::fill(t_atoms* atoms, const int startAtomIndex, const int end
     {
         // We always assign a new chain number, but only assign a chain id
         // characters for larger molecules.
-        int chainIdToAssign;
+        char chainIdToAssign;
         if (endAtomIndex - startAtomIndex >= s_chainMinAtoms && !outOfIds_)
         {
             /* Set the chain id for the output */
@@ -407,7 +407,7 @@ void readConfAndAtoms(const char* infile,
         readConfAndTopology(infile, &haveTopology, &mtop, pbcType, x, v, box);
         *symtab                          = mtop.symtab;
         *name                            = gmx_strdup(*mtop.name);
-        *atoms                           = gmx_mtop_global_atoms(&mtop);
+        *atoms                           = gmx_mtop_global_atoms(mtop);
         gmx::RangePartitioning molecules = gmx_mtop_molecules(mtop);
         makeChainIdentifiersAfterTprReading(atoms, molecules);
 
@@ -473,8 +473,8 @@ void readConfAndTopology(const char* infile,
             snew(*v, header.natoms);
         }
         int     natoms;
-        PbcType pbcType_tmp = read_tpx(infile, nullptr, box, &natoms, (x == nullptr) ? nullptr : *x,
-                                       (v == nullptr) ? nullptr : *v, mtop);
+        PbcType pbcType_tmp = read_tpx(
+                infile, nullptr, box, &natoms, (x == nullptr) ? nullptr : *x, (v == nullptr) ? nullptr : *v, mtop);
         if (pbcType != nullptr)
         {
             *pbcType = pbcType_tmp;
index f36118b55187d7ffa5a80207c546ceb3b4574e52..1903e26346fa8c03fbfa5ea74f01a2f81ffdf196 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 @@
 /* This number should be increased whenever the file format changes! */
 static const int enx_version = 5;
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 const char* enx_block_id_name[] = { "Averaged orientation restraints",
                                     "Instantaneous orientation restraints",
                                     "Orientation restraint order tensor(s)",
@@ -100,9 +101,9 @@ static void enxsubblock_init(t_enxsubblock* sb)
 {
     sb->nr = 0;
 #if GMX_DOUBLE
-    sb->type = xdr_datatype_double;
+    sb->type = XdrDataType::Double;
 #else
-    sb->type            = xdr_datatype_float;
+    sb->type                = XdrDataType::Float;
 #endif
     sb->fval       = nullptr;
     sb->dval       = nullptr;
@@ -173,42 +174,42 @@ static void enxsubblock_alloc(t_enxsubblock* sb)
     /* allocate the appropriate amount of memory */
     switch (sb->type)
     {
-        case xdr_datatype_float:
+        case XdrDataType::Float:
             if (sb->nr > sb->fval_alloc)
             {
                 srenew(sb->fval, sb->nr);
                 sb->fval_alloc = sb->nr;
             }
             break;
-        case xdr_datatype_double:
+        case XdrDataType::Double:
             if (sb->nr > sb->dval_alloc)
             {
                 srenew(sb->dval, sb->nr);
                 sb->dval_alloc = sb->nr;
             }
             break;
-        case xdr_datatype_int:
+        case XdrDataType::Int:
             if (sb->nr > sb->ival_alloc)
             {
                 srenew(sb->ival, sb->nr);
                 sb->ival_alloc = sb->nr;
             }
             break;
-        case xdr_datatype_int64:
+        case XdrDataType::Int64:
             if (sb->nr > sb->lval_alloc)
             {
                 srenew(sb->lval, sb->nr);
                 sb->lval_alloc = sb->nr;
             }
             break;
-        case xdr_datatype_char:
+        case XdrDataType::Char:
             if (sb->nr > sb->cval_alloc)
             {
                 srenew(sb->cval, sb->nr);
                 sb->cval_alloc = sb->nr;
             }
             break;
-        case xdr_datatype_string:
+        case XdrDataType::String:
             if (sb->nr > sb->sval_alloc)
             {
                 int i;
@@ -336,7 +337,9 @@ static void enx_warning(const char* msg)
     }
     else
     {
-        gmx_fatal(FARGS, "%s\n%s", msg,
+        gmx_fatal(FARGS,
+                  "%s\n%s",
+                  msg,
                   "If you want to use the correct frames before the corrupted frame and avoid this "
                   "fatal error set the env.var. GMX_ENX_NO_FATAL");
     }
@@ -424,8 +427,11 @@ void do_enxnms(ener_file_t ef, int* nre, gmx_enxnm_t** nms)
         xdr_int(xdr, &file_version);
         if (file_version > enx_version)
         {
-            gmx_fatal(FARGS, "reading tpx file (%s) version %d with version %d program",
-                      gmx_fio_getname(ef->fio), file_version, enx_version);
+            gmx_fatal(FARGS,
+                      "reading tpx file (%s) version %d with version %d program",
+                      gmx_fio_getname(ef->fio),
+                      file_version,
+                      enx_version);
         }
         xdr_int(xdr, nre);
     }
@@ -451,9 +457,9 @@ static gmx_bool do_eheader(ener_file_t ef,
     int      ndisre = 0;
     int      startb = 0;
 #if !GMX_DOUBLE
-    xdr_datatype dtreal = xdr_datatype_float;
+    XdrDataType xdrDataType = XdrDataType::Float;
 #else
-    xdr_datatype dtreal = xdr_datatype_double;
+    XdrDataType xdrDataType = XdrDataType::Double;
 #endif
 
     if (bWrongPrecision)
@@ -507,8 +513,11 @@ static gmx_bool do_eheader(ener_file_t ef,
         }
         if (*bOK && *file_version > enx_version)
         {
-            gmx_fatal(FARGS, "reading tpx file (%s) version %d with version %d program",
-                      gmx_fio_getname(ef->fio), *file_version, enx_version);
+            gmx_fatal(FARGS,
+                      "reading tpx file (%s) version %d with version %d program",
+                      gmx_fio_getname(ef->fio),
+                      *file_version,
+                      enx_version);
         }
         if (!gmx_fio_do_double(ef->fio, fr->t))
         {
@@ -635,8 +644,8 @@ static gmx_bool do_eheader(ener_file_t ef,
         fr->block[0].id          = enxDISRE;
         fr->block[0].sub[0].nr   = ndisre;
         fr->block[0].sub[1].nr   = ndisre;
-        fr->block[0].sub[0].type = dtreal;
-        fr->block[0].sub[1].type = dtreal;
+        fr->block[0].sub[0].type = xdrDataType;
+        fr->block[0].sub[1].type = xdrDataType;
         startb++;
     }
 
@@ -659,7 +668,7 @@ static gmx_bool do_eheader(ener_file_t ef,
                 {
                     gmx_incons("Writing an old version .edr file with too many subblocks");
                 }
-                if (fr->block[b].sub[0].type != dtreal)
+                if (fr->block[b].sub[0].type != xdrDataType)
                 {
                     gmx_incons("Writing an old version .edr file the wrong subblock type");
                 }
@@ -672,7 +681,7 @@ static gmx_bool do_eheader(ener_file_t ef,
             }
             fr->block[b].id          = b - startb;
             fr->block[b].sub[0].nr   = nrint;
-            fr->block[b].sub[0].type = dtreal;
+            fr->block[b].sub[0].type = xdrDataType;
         }
         else
         {
@@ -693,12 +702,12 @@ static gmx_bool do_eheader(ener_file_t ef,
             for (i = 0; i < nsub; i++)
             {
                 t_enxsubblock* sub    = &(fr->block[b].sub[i]); /* shortcut */
-                int            typenr = sub->type;
+                int            typenr = static_cast<int>(sub->type);
 
                 *bOK = *bOK && gmx_fio_do_int(ef->fio, typenr);
                 *bOK = *bOK && gmx_fio_do_int(ef->fio, sub->nr);
 
-                sub->type = static_cast<xdr_datatype>(typenr);
+                sub->type = static_cast<XdrDataType>(typenr);
             }
         }
     }
@@ -970,14 +979,12 @@ gmx_bool do_enx(ener_file_t ef, t_enxframe* fr)
     {
         if (bRead)
         {
-            fprintf(stderr, "\rLast energy frame read %d time %8.3f         ", ef->framenr - 1,
-                    ef->frametime);
+            fprintf(stderr, "\rLast energy frame read %d time %8.3f         ", ef->framenr - 1, ef->frametime);
             fflush(stderr);
 
             if (!bOK)
             {
-                fprintf(stderr, "\nWARNING: Incomplete energy frame: nr %d time %8.3f\n",
-                        ef->framenr, fr->t);
+                fprintf(stderr, "\nWARNING: Incomplete energy frame: nr %d time %8.3f\n", ef->framenr, fr->t);
             }
         }
         else
@@ -1004,10 +1011,15 @@ gmx_bool do_enx(ener_file_t ef, t_enxframe* fr)
     }
     if (!((fr->step >= 0) && bSane) && bRead)
     {
-        fprintf(stderr, "\nWARNING: there may be something wrong with energy file %s\n",
+        fprintf(stderr,
+                "\nWARNING: there may be something wrong with energy file %s\n",
                 gmx_fio_getname(ef->fio));
-        fprintf(stderr, "Found: step=%" PRId64 ", nre=%d, nblock=%d, time=%g.\n", fr->step, fr->nre,
-                fr->nblock, fr->t);
+        fprintf(stderr,
+                "Found: step=%" PRId64 ", nre=%d, nblock=%d, time=%g.\n",
+                fr->step,
+                fr->nre,
+                fr->nblock,
+                fr->t);
     }
     if (bRead && fr->nre > fr->e_alloc)
     {
@@ -1081,20 +1093,20 @@ gmx_bool do_enx(ener_file_t ef, t_enxframe* fr)
             /* read/write data */
             switch (sub->type)
             {
-                case xdr_datatype_float:
+                case XdrDataType::Float:
                     bOK1 = gmx_fio_ndo_float(ef->fio, sub->fval, sub->nr);
                     break;
-                case xdr_datatype_double:
+                case XdrDataType::Double:
                     bOK1 = gmx_fio_ndo_double(ef->fio, sub->dval, sub->nr);
                     break;
-                case xdr_datatype_int: bOK1 = gmx_fio_ndo_int(ef->fio, sub->ival, sub->nr); break;
-                case xdr_datatype_int64:
+                case XdrDataType::Int: bOK1 = gmx_fio_ndo_int(ef->fio, sub->ival, sub->nr); break;
+                case XdrDataType::Int64:
                     bOK1 = gmx_fio_ndo_int64(ef->fio, sub->lval, sub->nr);
                     break;
-                case xdr_datatype_char:
+                case XdrDataType::Char:
                     bOK1 = gmx_fio_ndo_uchar(ef->fio, sub->cval, sub->nr);
                     break;
-                case xdr_datatype_string:
+                case XdrDataType::String:
                     bOK1 = gmx_fio_ndo_string(ef->fio, sub->sval, sub->nr);
                     break;
                 default:
@@ -1187,7 +1199,7 @@ void get_enx_state(const char* fn, real t, const SimulationGroups& groups, t_inp
     }
 
     npcoupl = TRICLINIC(ir->compress) ? 6 : 3;
-    if (ir->epc == epcPARRINELLORAHMAN)
+    if (ir->epc == PressureCoupling::ParrinelloRahman)
     {
         clear_mat(state->boxv);
         for (i = 0; i < npcoupl; i++)
@@ -1197,7 +1209,7 @@ void get_enx_state(const char* fn, real t, const SimulationGroups& groups, t_inp
         fprintf(stderr, "\nREAD %d BOX VELOCITIES FROM %s\n\n", npcoupl, fn);
     }
 
-    if (ir->etc == etcNOSEHOOVER)
+    if (ir->etc == TemperatureCoupling::NoseHoover)
     {
         char cns[20];
 
@@ -1376,8 +1388,13 @@ static void cmp_energies(FILE*        fp,
         }
         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);
+            fprintf(fp,
+                    "%-15s  step %3d:  %12g,  step %3d: %12g\n",
+                    enm1[ind1[i]].name,
+                    step1,
+                    e1[ind1[i]].e,
+                    step2,
+                    e2[ind2[i]].e);
         }
     }
 
@@ -1439,37 +1456,37 @@ static void cmp_eblocks(t_enxframe* fr1, t_enxframe* fr2, real ftol, real abstol
                     {
                         switch (s1->type)
                         {
-                            case xdr_datatype_float:
+                            case XdrDataType::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:
+                            case XdrDataType::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:
+                            case XdrDataType::Int:
                                 for (k = 0; k < s1->nr; k++)
                                 {
                                     cmp_int(stdout, buf, i, s1->ival[k], s2->ival[k]);
                                 }
                                 break;
-                            case xdr_datatype_int64:
+                            case XdrDataType::Int64:
                                 for (k = 0; k < s1->nr; k++)
                                 {
                                     cmp_int64(stdout, buf, s1->lval[k], s2->lval[k]);
                                 }
                                 break;
-                            case xdr_datatype_char:
+                            case XdrDataType::Char:
                                 for (k = 0; k < s1->nr; k++)
                                 {
                                     cmp_uc(stdout, buf, i, s1->cval[k], s2->cval[k]);
                                 }
                                 break;
-                            case xdr_datatype_string:
+                            case XdrDataType::String:
                                 for (k = 0; k < s1->nr; k++)
                                 {
                                     cmp_str(stdout, buf, i, s1->sval[k], s2->sval[k]);
@@ -1581,8 +1598,8 @@ void comp_enx(const char* fn1, const char* fn2, real ftol, real abstol, const ch
             /* 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_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);
index 18c46aa79cc549abe194f7c667d4d5c425a94fd8..741d12a8eee01159af4412d17c977d63eaa1ed22 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -95,6 +95,7 @@ enum
 };
 
 /* names for the above enum */
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 extern const char* enx_block_id_name[];
 
 
@@ -102,8 +103,8 @@ extern const char* enx_block_id_name[];
    has a number of values of a single data type in a .edr file. */
 struct t_enxsubblock
 {
-    int          nr;   /* number of items in subblock */
-    xdr_datatype type; /* the block type */
+    int         nr;   /* number of items in subblock */
+    XdrDataType type; /* the block type */
 
     /* the values: pointers for each type */
     float*         fval;
index a380ffafc598e31da5d89a0b47a22620eeb5fef0..800628e32ade6c40bbcf10ff380a45d82cbd67de 100644 (file)
@@ -327,8 +327,7 @@ void gmx_espresso_read_conf(const char* infile, t_symtab* symtab, char** name, t
                         }
                         else
                         {
-                            sprintf(buf, "T%c%c", 'A' + atoms->atom[i].type / 26,
-                                    'A' + atoms->atom[i].type % 26);
+                            sprintf(buf, "T%c%c", 'A' + atoms->atom[i].type / 26, 'A' + atoms->atom[i].type % 26);
                         }
                         t_atoms_set_resinfo(atoms, i, symtab, buf, i, ' ', 0, ' ');
                     }
@@ -347,7 +346,8 @@ void gmx_espresso_read_conf(const char* infile, t_symtab* symtab, char** name, t
                 gmx_fatal(FARGS,
                           "Internal inconsistency in Espresso routines, read %d atoms, expected %d "
                           "atoms",
-                          i, atoms->nr);
+                          i,
+                          atoms->nr);
             }
         }
         else if (level == 1 && std::strcmp(word, "variable") == 0 && !bFoundVariable)
@@ -469,7 +469,13 @@ void write_espresso_conf_indexed(FILE*          out,
         {
             j = i;
         }
-        fprintf(out, "\t{%d %f %f %f %hu %g", j, x[j][XX], x[j][YY], x[j][ZZ], atoms->atom[j].type,
+        fprintf(out,
+                "\t{%d %f %f %f %hu %g",
+                j,
+                x[j][XX],
+                x[j][YY],
+                x[j][ZZ],
+                atoms->atom[j].type,
                 atoms->atom[j].q);
         if (v)
         {
index 2371bc235566d908523c062372be30da9d1a8d8b..b3e9be6d201dba4c8f7e8e3e8eb8b9c68abfb72d 100644 (file)
@@ -37,7 +37,7 @@
  */
 #include "gmxpre.h"
 
-#include "filetypes.h"
+#include "gromacs/fileio/filetypes.h"
 
 #include <cstring>
 
@@ -95,8 +95,13 @@ static const t_deffile deffile[efNR] = {
     { eftGEN, ".???", "trajout", "-f", "Trajectory", NTROS, tros },
     { eftGEN, ".???", "traj", nullptr, "Full precision trajectory", NTRNS, trns },
     { eftXDR, ".trr", "traj", nullptr, "Trajectory in portable xdr format" },
-    { eftGEN, ".???", "traj_comp", nullptr,
-      "Compressed trajectory (tng format or portable xdr format)", NTRCOMPRESSED, trcompressed },
+    { eftGEN,
+      ".???",
+      "traj_comp",
+      nullptr,
+      "Compressed trajectory (tng format or portable xdr format)",
+      NTRCOMPRESSED,
+      trcompressed },
     { eftXDR, ".xtc", "traj", nullptr, "Compressed trajectory (portable xdr format): xtc" },
     { eftTNG, ".tng", "traj", nullptr, "Trajectory file (tng format)" },
     { eftXDR, ".edr", "ener", nullptr, "Energy file" },
index e046b03d4dd624bc932ca9ec10d1dfd8db82d62d..cf0bd86cdb79968a2d0303609bf3ecb98d2d9f3f 100644 (file)
@@ -107,8 +107,7 @@ static int read_g96_pos(char line[], t_symtab* symtab, FILE* fp, const char* inf
                 }
                 if ((nwanted != -1) && (natoms >= nwanted))
                 {
-                    gmx_fatal(FARGS, "Found more coordinates (%d) in %s than expected %d\n", natoms,
-                              infile, nwanted);
+                    gmx_fatal(FARGS, "Found more coordinates (%d) in %s than expected %d\n", natoms, infile, nwanted);
                 }
                 if (atoms)
                 {
@@ -133,8 +132,7 @@ static int read_g96_pos(char line[], t_symtab* symtab, FILE* fp, const char* inf
                         newres++;
                         if (newres >= atoms->nr)
                         {
-                            gmx_fatal(FARGS, "More residues than atoms in %s (natoms = %d)", infile,
-                                      atoms->nr);
+                            gmx_fatal(FARGS, "More residues than atoms in %s (natoms = %d)", infile, atoms->nr);
                         }
                         atoms->atom[natoms].resind = newres;
                         if (newres + 1 > atoms->nres)
@@ -159,8 +157,7 @@ static int read_g96_pos(char line[], t_symtab* symtab, FILE* fp, const char* inf
         }
         if ((nwanted != -1) && natoms != nwanted)
         {
-            fprintf(stderr, "Warning: found less coordinates (%d) in %s than expected %d\n", natoms,
-                    infile, nwanted);
+            fprintf(stderr, "Warning: found less coordinates (%d) in %s than expected %d\n", natoms, infile, nwanted);
         }
     }
 
@@ -200,8 +197,7 @@ static int read_g96_vel(char line[], FILE* fp, const char* infile, t_trxframe* f
                 }
                 if ((nwanted != -1) && (natoms >= nwanted))
                 {
-                    gmx_fatal(FARGS, "Found more velocities (%d) in %s than expected %d\n", natoms,
-                              infile, nwanted);
+                    gmx_fatal(FARGS, "Found more velocities (%d) in %s than expected %d\n", natoms, infile, nwanted);
                 }
                 if (fr->v)
                 {
@@ -214,8 +210,7 @@ static int read_g96_vel(char line[], FILE* fp, const char* infile, t_trxframe* f
         }
         if ((nwanted != -1) && (natoms != nwanted))
         {
-            fprintf(stderr, "Warning: found less velocities (%d) in %s than expected %d\n", natoms,
-                    infile, nwanted);
+            fprintf(stderr, "Warning: found less velocities (%d) in %s than expected %d\n", natoms, infile, nwanted);
         }
     }
 
@@ -312,8 +307,17 @@ int read_g96_conf(FILE* fp, const char* infile, char** name, t_trxframe* fr, t_s
                 bEnd = (strncmp(line, "END", 3) == 0);
                 if (!bEnd && (line[0] != '#'))
                 {
-                    nbp = sscanf(line, "%15lf%15lf%15lf%15lf%15lf%15lf%15lf%15lf%15lf", &db1, &db2,
-                                 &db3, &db4, &db5, &db6, &db7, &db8, &db9);
+                    nbp = sscanf(line,
+                                 "%15lf%15lf%15lf%15lf%15lf%15lf%15lf%15lf%15lf",
+                                 &db1,
+                                 &db2,
+                                 &db3,
+                                 &db4,
+                                 &db5,
+                                 &db6,
+                                 &db7,
+                                 &db8,
+                                 &db9);
                     if (nbp < 3)
                     {
                         gmx_fatal(FARGS, "Found a BOX line, but no box in %s", infile);
@@ -378,10 +382,15 @@ void write_g96_conf(FILE* out, const char* title, const t_trxframe* fr, int nind
                 {
                     a = i;
                 }
-                fprintf(out, "%5d %-5s %-5s%7d%15.9f%15.9f%15.9f\n",
+                fprintf(out,
+                        "%5d %-5s %-5s%7d%15.9f%15.9f%15.9f\n",
                         (atoms->resinfo[atoms->atom[a].resind].nr) % 100000,
-                        *atoms->resinfo[atoms->atom[a].resind].name, *atoms->atomname[a],
-                        (i + 1) % 10000000, fr->x[a][XX], fr->x[a][YY], fr->x[a][ZZ]);
+                        *atoms->resinfo[atoms->atom[a].resind].name,
+                        *atoms->atomname[a],
+                        (i + 1) % 10000000,
+                        fr->x[a][XX],
+                        fr->x[a][YY],
+                        fr->x[a][ZZ]);
             }
         }
         else
@@ -417,10 +426,15 @@ void write_g96_conf(FILE* out, const char* title, const t_trxframe* fr, int nind
                 {
                     a = i;
                 }
-                fprintf(out, "%5d %-5s %-5s%7d%15.9f%15.9f%15.9f\n",
+                fprintf(out,
+                        "%5d %-5s %-5s%7d%15.9f%15.9f%15.9f\n",
                         (atoms->resinfo[atoms->atom[a].resind].nr) % 100000,
-                        *atoms->resinfo[atoms->atom[a].resind].name, *atoms->atomname[a],
-                        (i + 1) % 10000000, fr->v[a][XX], fr->v[a][YY], fr->v[a][ZZ]);
+                        *atoms->resinfo[atoms->atom[a].resind].name,
+                        *atoms->atomname[a],
+                        (i + 1) % 10000000,
+                        fr->v[a][XX],
+                        fr->v[a][YY],
+                        fr->v[a][ZZ]);
             }
         }
         else
@@ -448,8 +462,14 @@ void write_g96_conf(FILE* out, const char* title, const t_trxframe* fr, int nind
         if ((fr->box[XX][YY] != 0.0F) || (fr->box[XX][ZZ] != 0.0F) || (fr->box[YY][XX] != 0.0F)
             || (fr->box[YY][ZZ] != 0.0F) || (fr->box[ZZ][XX] != 0.0F) || (fr->box[ZZ][YY] != 0.0F))
         {
-            fprintf(out, "%15.9f%15.9f%15.9f%15.9f%15.9f%15.9f", fr->box[XX][YY], fr->box[XX][ZZ],
-                    fr->box[YY][XX], fr->box[YY][ZZ], fr->box[ZZ][XX], fr->box[ZZ][YY]);
+            fprintf(out,
+                    "%15.9f%15.9f%15.9f%15.9f%15.9f%15.9f",
+                    fr->box[XX][YY],
+                    fr->box[XX][ZZ],
+                    fr->box[YY][XX],
+                    fr->box[YY][ZZ],
+                    fr->box[ZZ][XX],
+                    fr->box[ZZ][YY]);
         }
         fprintf(out, "\n");
         fprintf(out, "END\n");
index cad75e64eb44fadf5b60f3d1dabbfaf8732f21e7..fad104947fd7f42b27242955a8e3f6f85730440e 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstdio>
 #include <cstring>
 
+#include <mutex>
 #include <vector>
 
 #if HAVE_IO_H
@@ -60,7 +61,6 @@
 #include "gromacs/fileio/md5.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
-#include "gromacs/utility/mutex.h"
 #include "gromacs/utility/smalloc.h"
 
 #include "gmxfio_impl.h"
@@ -70,6 +70,7 @@
 
 /* the list of open files is a linked list, with a dummy element at its head;
        it is initialized when the first file is opened. */
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static t_fileio* open_files = nullptr;
 
 
@@ -82,9 +83,10 @@ static t_fileio* open_files = nullptr;
    opening and closing of files, or during global operations like
    iterating along all open files. All these cases should be rare
    during the simulation. */
-static gmx::Mutex open_file_mutex;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static std::mutex open_file_mutex;
 
-using Lock = gmx::lock_guard<gmx::Mutex>;
+using Lock = std::lock_guard<std::mutex>;
 
 /******************************************************************
  *
index 7df93fe4ef27ce4eb9b6f9578c9a00b239e1f0df..6e9282453c817b11e43bf3a55f61efb67348d7a9 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/fileio/gmxfio.h"
 #include "gromacs/fileio/xdrf.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
 #include "gmxfio_impl.h"
 
 /* Enumerated for data types in files */
-enum
-{
-    eioREAL,
-    eioFLOAT,
-    eioDOUBLE,
-    eioINT,
-    eioINT32,
-    eioINT64,
-    eioUCHAR,
-    eioCHAR,
-    eioNCHAR,
-    eioNUCHAR,
-    eioUSHORT,
-    eioRVEC,
-    eioNRVEC,
-    eioIVEC,
-    eioSTRING,
-    eioOPAQUE,
-    eioNR
+enum class InputOutputType : int
+{
+    Real,
+    Float,
+    Double,
+    Int,
+    Int32,
+    Int64,
+    UnsignedChar,
+    Char,
+    CharArray,
+    UnsignedCharArray,
+    UnsignedShort,
+    RVec,
+    RVecArray,
+    IVec,
+    String,
+    Opaque,
+    Count
 };
 
-static const char* eioNames[eioNR] = { "REAL",  "FLOAT", "DOUBLE", "INT",    "INT32",  "INT64",
-                                       "UCHAR", "CHAR",  "NCHAR",  "NUCHAR", "USHORT", "RVEC",
-                                       "NRVEC", "IVEC",  "STRING", "OPAQUE" };
+static const char* enumValueToString(InputOutputType enumValue)
+{
+    constexpr gmx::EnumerationArray<InputOutputType, const char*> ioTypeNames = {
+        "REAL",  "FLOAT",  "DOUBLE", "INT",  "INT32", "INT64", "UCHAR",  "CHAR",
+        "NCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC", "IVEC",  "STRING", "OPAQUE"
+    };
+    return ioTypeNames[enumValue];
+}
 
 void gmx_fio_setprecision(t_fileio* fio, gmx_bool bDouble)
 {
@@ -106,30 +112,48 @@ XDR* gmx_fio_getxdr(t_fileio* fio)
 }
 
 /* check the number of items given against the type */
-static void gmx_fio_check_nitem(int eio, std::size_t nitem, const char* file, int line)
+static void gmx_fio_check_nitem(InputOutputType eio, std::size_t nitem, const char* file, int line)
 {
     if ((nitem != 1)
-        && !((eio == eioNRVEC) || (eio == eioNUCHAR) || (eio == eioNCHAR) || (eio == eioOPAQUE)))
+        && !((eio == InputOutputType::RVecArray) || (eio == InputOutputType::UnsignedCharArray)
+             || (eio == InputOutputType::CharArray) || (eio == InputOutputType::Opaque)))
     {
         gmx_fatal(FARGS,
                   "nitem may differ from 1 only for %s, %s, %s or %s, not for %s"
                   "(%s, %d)",
-                  eioNames[eioNUCHAR], eioNames[eioNRVEC], eioNames[eioNCHAR], eioNames[eioOPAQUE],
-                  eioNames[eio], file, line);
+                  enumValueToString(InputOutputType::UnsignedCharArray),
+                  enumValueToString(InputOutputType::RVecArray),
+                  enumValueToString(InputOutputType::CharArray),
+                  enumValueToString(InputOutputType::Opaque),
+                  enumValueToString(eio),
+                  file,
+                  line);
     }
 }
 
 /* output a data type error. */
-[[noreturn]] static void gmx_fio_fe(t_fileio* fio, int eio, const char* desc, const char* srcfile, int line)
+[[noreturn]] static void
+gmx_fio_fe(t_fileio* fio, InputOutputType eio, const char* desc, const char* srcfile, int line)
 {
-    gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d", fio->bRead ? "read" : "write",
-              desc, eio, ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown", srcfile, line);
+    gmx_fatal(FARGS,
+              "Trying to %s %s type %d (%s), src %s, line %d",
+              fio->bRead ? "read" : "write",
+              desc,
+              static_cast<int>(eio),
+              ((eio >= InputOutputType::Real) && (eio < InputOutputType::Count)) ? enumValueToString(eio)
+                                                                                 : "unknown",
+              srcfile,
+              line);
 }
 
 /* This is the part that reads xdr files.  */
-
-static gmx_bool
-do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc, const char* srcfile, int line)
+static gmx_bool do_xdr(t_fileio*       fio,
+                       void*           item,
+                       std::size_t     nitem,
+                       InputOutputType eio,
+                       const char*     desc,
+                       const char*     srcfile,
+                       int             line)
 {
     unsigned char  ucdum, *ucptr;
     char           cdum, *cptr;
@@ -148,7 +172,7 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
     gmx_fio_check_nitem(eio, nitem, srcfile, line);
     switch (eio)
     {
-        case eioREAL:
+        case InputOutputType::Real:
             if (fio->bDouble)
             {
                 if (item && !fio->bRead)
@@ -174,7 +198,7 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                 }
             }
             break;
-        case eioFLOAT:
+        case InputOutputType::Float:
             if (item && !fio->bRead)
             {
                 f = *(static_cast<float*>(item));
@@ -185,7 +209,7 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                 *(static_cast<float*>(item)) = f;
             }
             break;
-        case eioDOUBLE:
+        case InputOutputType::Double:
             if (item && !fio->bRead)
             {
                 d = *(static_cast<double*>(item));
@@ -196,7 +220,7 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                 *(static_cast<double*>(item)) = d;
             }
             break;
-        case eioINT:
+        case InputOutputType::Int:
             if (item && !fio->bRead)
             {
                 idum = *static_cast<int*>(item);
@@ -207,7 +231,7 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                 *static_cast<int*>(item) = idum;
             }
             break;
-        case eioINT32:
+        case InputOutputType::Int32:
             if (item && !fio->bRead)
             {
                 s32dum = *static_cast<int32_t*>(item);
@@ -218,7 +242,7 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                 *static_cast<int32_t*>(item) = s32dum;
             }
             break;
-        case eioINT64:
+        case InputOutputType::Int64:
             if (item && !fio->bRead)
             {
                 s64dum = *static_cast<int64_t*>(item);
@@ -229,7 +253,7 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                 *static_cast<int64_t*>(item) = s64dum;
             }
             break;
-        case eioUCHAR:
+        case InputOutputType::UnsignedChar:
             if (item && !fio->bRead)
             {
                 ucdum = *static_cast<unsigned char*>(item);
@@ -240,7 +264,7 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                 *static_cast<unsigned char*>(item) = ucdum;
             }
             break;
-        case eioCHAR:
+        case InputOutputType::Char:
             if (item && !fio->bRead)
             {
                 cdum = *static_cast<char*>(item);
@@ -251,23 +275,27 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                 *static_cast<char*>(item) = cdum;
             }
             break;
-        case eioNCHAR:
+        case InputOutputType::CharArray:
             cptr = static_cast<char*>(item);
             GMX_RELEASE_ASSERT(nitem < static_cast<std::size_t>(std::numeric_limits<int>::max()),
                                "The XDR interface cannot handle array lengths > 2^31");
-            res = xdr_vector(fio->xdr, cptr, static_cast<int>(nitem),
+            res = xdr_vector(fio->xdr,
+                             cptr,
+                             static_cast<int>(nitem),
                              static_cast<unsigned int>(sizeof(char)),
                              reinterpret_cast<xdrproc_t>(xdr_char));
             break;
-        case eioNUCHAR:
+        case InputOutputType::UnsignedCharArray:
             ucptr = static_cast<unsigned char*>(item);
             GMX_RELEASE_ASSERT(nitem < static_cast<std::size_t>(std::numeric_limits<int>::max()),
                                "The XDR interface cannot handle array lengths > 2^31");
-            res = xdr_vector(fio->xdr, reinterpret_cast<char*>(ucptr), static_cast<int>(nitem),
+            res = xdr_vector(fio->xdr,
+                             reinterpret_cast<char*>(ucptr),
+                             static_cast<int>(nitem),
                              static_cast<unsigned int>(sizeof(unsigned char)),
                              reinterpret_cast<xdrproc_t>(xdr_u_char));
             break;
-        case eioUSHORT:
+        case InputOutputType::UnsignedShort:
             if (item && !fio->bRead)
             {
                 us = *static_cast<unsigned short*>(item);
@@ -278,7 +306,7 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                 *static_cast<unsigned short*>(item) = us;
             }
             break;
-        case eioRVEC:
+        case InputOutputType::RVec:
             if (fio->bDouble)
             {
                 if (item && !fio->bRead)
@@ -288,7 +316,9 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                         dvec[m] = (static_cast<real*>(item))[m];
                     }
                 }
-                res = xdr_vector(fio->xdr, reinterpret_cast<char*>(dvec), DIM,
+                res = xdr_vector(fio->xdr,
+                                 reinterpret_cast<char*>(dvec),
+                                 DIM,
                                  static_cast<unsigned int>(sizeof(double)),
                                  reinterpret_cast<xdrproc_t>(xdr_double));
                 if (item)
@@ -308,7 +338,9 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                         fvec[m] = (static_cast<real*>(item))[m];
                     }
                 }
-                res = xdr_vector(fio->xdr, reinterpret_cast<char*>(fvec), DIM,
+                res = xdr_vector(fio->xdr,
+                                 reinterpret_cast<char*>(fvec),
+                                 DIM,
                                  static_cast<unsigned int>(sizeof(float)),
                                  reinterpret_cast<xdrproc_t>(xdr_float));
                 if (item)
@@ -320,7 +352,7 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                 }
             }
             break;
-        case eioNRVEC:
+        case InputOutputType::RVecArray:
             ptr = nullptr;
             res = 1;
             for (std::size_t j = 0; j < nitem && res; j++)
@@ -329,10 +361,10 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                 {
                     ptr = (static_cast<rvec*>(item))[j];
                 }
-                res = static_cast<bool_t>(do_xdr(fio, ptr, 1, eioRVEC, desc, srcfile, line));
+                res = static_cast<bool_t>(do_xdr(fio, ptr, 1, InputOutputType::RVec, desc, srcfile, line));
             }
             break;
-        case eioIVEC:
+        case InputOutputType::IVec:
             iptr = static_cast<int*>(item);
             res  = 1;
             for (m = 0; (m < DIM) && res; m++)
@@ -348,7 +380,7 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                 }
             }
             break;
-        case eioSTRING:
+        case InputOutputType::String:
         {
             char* cptr;
             int   slen;
@@ -374,7 +406,10 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
                 gmx_fatal(FARGS,
                           "wrong string length %d for string %s"
                           " (source %s, line %d)",
-                          slen, desc, srcfile, line);
+                          slen,
+                          desc,
+                          srcfile,
+                          line);
             }
             if (!item && fio->bRead)
             {
@@ -398,7 +433,7 @@ do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc,
             }
             break;
         }
-        case eioOPAQUE:
+        case InputOutputType::Opaque:
         {
             if (item == nullptr && nitem > 0)
             {
@@ -447,7 +482,7 @@ gmx_bool gmx_fio_writee_string(t_fileio* fio, const char* item, const char* desc
     gmx_bool ret;
     void*    it = const_cast<char*>(item); /* ugh.. */
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, it, 1, eioSTRING, desc, srcfile, line);
+    ret = do_xdr(fio, it, 1, InputOutputType::String, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -456,7 +491,7 @@ gmx_bool gmx_fio_doe_real(t_fileio* fio, real* item, const char* desc, const cha
 {
     gmx_bool ret;
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, item, 1, eioREAL, desc, srcfile, line);
+    ret = do_xdr(fio, item, 1, InputOutputType::Real, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -465,7 +500,7 @@ gmx_bool gmx_fio_doe_float(t_fileio* fio, float* item, const char* desc, const c
 {
     gmx_bool ret;
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, item, 1, eioFLOAT, desc, srcfile, line);
+    ret = do_xdr(fio, item, 1, InputOutputType::Float, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -474,7 +509,7 @@ gmx_bool gmx_fio_doe_double(t_fileio* fio, double* item, const char* desc, const
 {
     gmx_bool ret;
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, item, 1, eioDOUBLE, desc, srcfile, line);
+    ret = do_xdr(fio, item, 1, InputOutputType::Double, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -488,13 +523,13 @@ gmx_bool gmx_fio_doe_gmx_bool(t_fileio* fio, gmx_bool* item, const char* desc, c
     if (fio->bRead)
     {
         int itmp = 0;
-        ret      = do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
+        ret      = do_xdr(fio, &itmp, 1, InputOutputType::Int, desc, srcfile, line);
         *item    = (itmp != 0);
     }
     else
     {
         int itmp = static_cast<int>(*item);
-        ret      = do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
+        ret      = do_xdr(fio, &itmp, 1, InputOutputType::Int, desc, srcfile, line);
     }
     gmx_fio_unlock(fio);
     return ret;
@@ -504,7 +539,7 @@ gmx_bool gmx_fio_doe_int(t_fileio* fio, int* item, const char* desc, const char*
 {
     gmx_bool ret;
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, item, 1, eioINT, desc, srcfile, line);
+    ret = do_xdr(fio, item, 1, InputOutputType::Int, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -513,7 +548,7 @@ gmx_bool gmx_fio_doe_int32(t_fileio* fio, int32_t* item, const char* desc, const
 {
     gmx_bool ret;
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, item, 1, eioINT32, desc, srcfile, line);
+    ret = do_xdr(fio, item, 1, InputOutputType::Int32, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -522,7 +557,7 @@ gmx_bool gmx_fio_doe_int64(t_fileio* fio, int64_t* item, const char* desc, const
 {
     gmx_bool ret;
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, item, 1, eioINT64, desc, srcfile, line);
+    ret = do_xdr(fio, item, 1, InputOutputType::Int64, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -531,7 +566,7 @@ gmx_bool gmx_fio_doe_uchar(t_fileio* fio, unsigned char* item, const char* desc,
 {
     gmx_bool ret;
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, item, 1, eioUCHAR, desc, srcfile, line);
+    ret = do_xdr(fio, item, 1, InputOutputType::UnsignedChar, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -540,7 +575,7 @@ gmx_bool gmx_fio_doe_char(t_fileio* fio, char* item, const char* desc, const cha
 {
     gmx_bool ret;
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, item, 1, eioCHAR, desc, srcfile, line);
+    ret = do_xdr(fio, item, 1, InputOutputType::Char, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -549,7 +584,7 @@ gmx_bool gmx_fio_doe_ushort(t_fileio* fio, unsigned short* item, const char* des
 {
     gmx_bool ret;
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, item, 1, eioUSHORT, desc, srcfile, line);
+    ret = do_xdr(fio, item, 1, InputOutputType::UnsignedShort, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -558,7 +593,7 @@ gmx_bool gmx_fio_doe_rvec(t_fileio* fio, rvec* item, const char* desc, const cha
 {
     gmx_bool ret;
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, item, 1, eioRVEC, desc, srcfile, line);
+    ret = do_xdr(fio, item, 1, InputOutputType::RVec, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -567,7 +602,7 @@ gmx_bool gmx_fio_doe_ivec(t_fileio* fio, ivec* item, const char* desc, const cha
 {
     gmx_bool ret;
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, item, 1, eioIVEC, desc, srcfile, line);
+    ret = do_xdr(fio, item, 1, InputOutputType::IVec, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -576,7 +611,7 @@ gmx_bool gmx_fio_doe_string(t_fileio* fio, char* item, const char* desc, const c
 {
     gmx_bool ret;
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, item, 1, eioSTRING, desc, srcfile, line);
+    ret = do_xdr(fio, item, 1, InputOutputType::String, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -585,7 +620,7 @@ gmx_bool gmx_fio_doe_opaque(t_fileio* fio, char* data, std::size_t size, const c
 {
     gmx_bool ret;
     gmx_fio_lock(fio);
-    ret = do_xdr(fio, data, size, eioOPAQUE, desc, srcfile, line);
+    ret = do_xdr(fio, data, size, InputOutputType::Opaque, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -599,7 +634,7 @@ gmx_bool gmx_fio_ndoe_real(t_fileio* fio, real* item, int n, const char* desc, c
     gmx_fio_lock(fio);
     for (i = 0; i < n; i++)
     {
-        ret = ret && do_xdr(fio, &(item[i]), 1, eioREAL, desc, srcfile, line);
+        ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::Real, desc, srcfile, line);
     }
     gmx_fio_unlock(fio);
     return ret;
@@ -613,7 +648,7 @@ gmx_bool gmx_fio_ndoe_float(t_fileio* fio, float* item, int n, const char* desc,
     gmx_fio_lock(fio);
     for (i = 0; i < n; i++)
     {
-        ret = ret && do_xdr(fio, &(item[i]), 1, eioFLOAT, desc, srcfile, line);
+        ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::Float, desc, srcfile, line);
     }
     gmx_fio_unlock(fio);
     return ret;
@@ -627,7 +662,7 @@ gmx_bool gmx_fio_ndoe_double(t_fileio* fio, double* item, int n, const char* des
     gmx_fio_lock(fio);
     for (i = 0; i < n; i++)
     {
-        ret = ret && do_xdr(fio, &(item[i]), 1, eioDOUBLE, desc, srcfile, line);
+        ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::Double, desc, srcfile, line);
     }
     gmx_fio_unlock(fio);
     return ret;
@@ -645,13 +680,13 @@ gmx_bool gmx_fio_ndoe_gmx_bool(t_fileio* fio, gmx_bool* item, int n, const char*
         if (fio->bRead)
         {
             int itmp = 0;
-            ret      = ret && do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
+            ret      = ret && do_xdr(fio, &itmp, 1, InputOutputType::Int, desc, srcfile, line);
             item[i]  = (itmp != 0);
         }
         else
         {
             int itmp = static_cast<int>(item[i]);
-            ret      = ret && do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
+            ret      = ret && do_xdr(fio, &itmp, 1, InputOutputType::Int, desc, srcfile, line);
         }
     }
     gmx_fio_unlock(fio);
@@ -665,7 +700,7 @@ gmx_bool gmx_fio_ndoe_int(t_fileio* fio, int* item, int n, const char* desc, con
     gmx_fio_lock(fio);
     for (i = 0; i < n; i++)
     {
-        ret = ret && do_xdr(fio, &(item[i]), 1, eioINT, desc, srcfile, line);
+        ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::Int, desc, srcfile, line);
     }
     gmx_fio_unlock(fio);
     return ret;
@@ -679,7 +714,7 @@ gmx_bool gmx_fio_ndoe_int64(t_fileio* fio, int64_t* item, int n, const char* des
     gmx_fio_lock(fio);
     for (i = 0; i < n; i++)
     {
-        ret = ret && do_xdr(fio, &(item[i]), 1, eioINT64, desc, srcfile, line);
+        ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::Int64, desc, srcfile, line);
     }
     gmx_fio_unlock(fio);
     return ret;
@@ -690,7 +725,7 @@ gmx_bool gmx_fio_ndoe_uchar(t_fileio* fio, unsigned char* item, int n, const cha
 {
     gmx_bool ret = TRUE;
     gmx_fio_lock(fio);
-    ret = ret && do_xdr(fio, item, n, eioNUCHAR, desc, srcfile, line);
+    ret = ret && do_xdr(fio, item, n, InputOutputType::UnsignedCharArray, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -699,7 +734,7 @@ gmx_bool gmx_fio_ndoe_char(t_fileio* fio, char* item, int n, const char* desc, c
 {
     gmx_bool ret = TRUE;
     gmx_fio_lock(fio);
-    ret = ret && do_xdr(fio, item, n, eioNCHAR, desc, srcfile, line);
+    ret = ret && do_xdr(fio, item, n, InputOutputType::CharArray, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -712,7 +747,7 @@ gmx_bool gmx_fio_ndoe_ushort(t_fileio* fio, unsigned short* item, int n, const c
     gmx_fio_lock(fio);
     for (i = 0; i < n; i++)
     {
-        ret = ret && do_xdr(fio, &(item[i]), 1, eioUSHORT, desc, srcfile, line);
+        ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::UnsignedShort, desc, srcfile, line);
     }
     gmx_fio_unlock(fio);
     return ret;
@@ -723,7 +758,7 @@ gmx_bool gmx_fio_ndoe_rvec(t_fileio* fio, rvec* item, int n, const char* desc, c
 {
     gmx_bool ret = TRUE;
     gmx_fio_lock(fio);
-    ret = ret && do_xdr(fio, item, n, eioNRVEC, desc, srcfile, line);
+    ret = ret && do_xdr(fio, item, n, InputOutputType::RVecArray, desc, srcfile, line);
     gmx_fio_unlock(fio);
     return ret;
 }
@@ -736,7 +771,7 @@ gmx_bool gmx_fio_ndoe_ivec(t_fileio* fio, ivec* item, int n, const char* desc, c
     gmx_fio_lock(fio);
     for (i = 0; i < n; i++)
     {
-        ret = ret && do_xdr(fio, &(item[i]), 1, eioIVEC, desc, srcfile, line);
+        ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::IVec, desc, srcfile, line);
     }
     gmx_fio_unlock(fio);
     return ret;
@@ -750,7 +785,7 @@ gmx_bool gmx_fio_ndoe_string(t_fileio* fio, char* item[], int n, const char* des
     gmx_fio_lock(fio);
     for (i = 0; i < n; i++)
     {
-        ret = ret && do_xdr(fio, &(item[i]), 1, eioSTRING, desc, srcfile, line);
+        ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::String, desc, srcfile, line);
     }
     gmx_fio_unlock(fio);
     return ret;
index 45527bcee0806d45bc5f7408f934faad6afbee91..4852b720b8b8127c24954ecbb96cb37d86463758 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -121,7 +121,8 @@ static gmx_bool get_w_conf(FILE*       in,
         fprintf(stderr,
                 "Warning: gro file contains less atoms (%d) than expected"
                 " (%d)\n",
-                natoms, atoms->nr);
+                natoms,
+                atoms->nr);
     }
 
     atoms->haveMass    = FALSE;
@@ -294,8 +295,7 @@ static gmx_bool get_w_conf(FILE*       in,
         {
             box[m][m] = (xmax[m] - xmin[m]);
         }
-        fprintf(stderr, "Generated a cubic box %8.3f x %8.3f x %8.3f\n", box[XX][XX], box[YY][YY],
-                box[ZZ][ZZ]);
+        fprintf(stderr, "Generated a cubic box %8.3f x %8.3f x %8.3f\n", box[XX][XX], box[YY][YY], box[ZZ][ZZ]);
     }
     else
     {
@@ -406,7 +406,8 @@ gmx_bool gro_next_x_or_v(FILE* status, t_trxframe* fr)
         gmx_fatal(FARGS,
                   "Number of atoms in gro frame (%d) doesn't match the number in the previous "
                   "frame (%d)",
-                  atoms.nr, fr->natoms);
+                  atoms.nr,
+                  fr->natoms);
     }
 
     return TRUE;
@@ -450,9 +451,17 @@ static void write_hconf_box(FILE* out, const matrix box)
     if ((box[XX][YY] != 0.0F) || (box[XX][ZZ] != 0.0F) || (box[YY][XX] != 0.0F)
         || (box[YY][ZZ] != 0.0F) || (box[ZZ][XX] != 0.0F) || (box[ZZ][YY] != 0.0F))
     {
-        fprintf(out, "%10.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f\n", box[XX][XX],
-                box[YY][YY], box[ZZ][ZZ], box[XX][YY], box[XX][ZZ], box[YY][XX], box[YY][ZZ],
-                box[ZZ][XX], box[ZZ][YY]);
+        fprintf(out,
+                "%10.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f\n",
+                box[XX][XX],
+                box[YY][YY],
+                box[ZZ][ZZ],
+                box[XX][YY],
+                box[XX][ZZ],
+                box[YY][XX],
+                box[YY][ZZ],
+                box[ZZ][XX],
+                box[ZZ][YY]);
     }
     else
     {
@@ -520,14 +529,14 @@ void write_hconf_indexed_p(FILE*          out,
     fflush(out);
 }
 
-void write_hconf_mtop(FILE* out, const char* title, const gmx_mtop_t* mtop, const rvec* x, const rvec* v, const matrix box)
+void write_hconf_mtop(FILE* out, const char* title, const gmx_mtop_t& mtop, const rvec* x, const rvec* v, const matrix box)
 {
     fprintf(out, "%s\n", (title && title[0]) ? title : gmx::bromacs().c_str());
-    fprintf(out, "%5d\n", mtop->natoms);
+    fprintf(out, "%5d\n", mtop.natoms);
 
     const char* format = get_hconf_format(v != nullptr);
 
-    for (const AtomProxy atomP : AtomRange(*mtop))
+    for (const AtomProxy atomP : AtomRange(mtop))
     {
         int         i             = atomP.globalAtomNumber();
         int         residueNumber = atomP.residueNumber();
index 3361893f9a93a5bf877699cc4a5b85098283f538..c310cf6ef699e2aed9253b2d3542b2a7fefcd723 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -65,7 +65,7 @@ void write_hconf_indexed_p(FILE*          out,
                            const rvec*    v,
                            const matrix   box);
 
-void write_hconf_mtop(FILE* out, const char* title, const gmx_mtop_t* mtop, const rvec* x, const rvec* v, const matrix box);
+void write_hconf_mtop(FILE* out, const char* title, const gmx_mtop_t& mtop, const rvec* x, const rvec* v, const matrix box);
 
 void write_hconf_p(FILE* out, const char* title, const t_atoms* atoms, const rvec* x, const rvec* v, const matrix box);
 /* Write a Gromos file with precision ndec: number of decimal places in x,
index 2e64a58682fefd055129d30dc6fabb02b87d774d..823262ac7838b8f87e42d0cfad7705b6103843d1 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/xdr_datatype.h"
 #include "gromacs/fileio/xdrf.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/futil.h"
 
 /* This is just for clarity - it can never be anything but 4! */
 #define XDR_INT_SIZE 4
 
-/* same order as the definition of xdr_datatype */
-const char* xdr_datatype_names[] = { "int", "float", "double", "large int", "char", "string" };
+/* Human-friendly names for XdrDataType enum class */
+const char* enumValueToString(XdrDataType enumValue)
+{
+    constexpr gmx::EnumerationArray<XdrDataType, const char*> xdrDataTypeNames = {
+        "int", "float", "double", "large int", "char", "string"
+    };
+    return xdrDataTypeNames[enumValue];
+}
 
 
 /*___________________________________________________________________________
@@ -244,7 +251,8 @@ static void sendints(int          buf[],
             fprintf(stderr,
                     "major breakdown in sendints num %u doesn't "
                     "match size %u\n",
-                    nums[i], sizes[i]);
+                    nums[i],
+                    sizes[i]);
             exit(1);
         }
         /* use one step multiply */
@@ -450,7 +458,9 @@ int xdr3dfcoord(XDR* xdrs, float* fp, int* size, float* precision)
          */
         if (*size <= 9)
         {
-            return (xdr_vector(xdrs, reinterpret_cast<char*>(fp), static_cast<unsigned int>(size3),
+            return (xdr_vector(xdrs,
+                               reinterpret_cast<char*>(fp),
+                               static_cast<unsigned int>(size3),
                                static_cast<unsigned int>(sizeof(*fp)),
                                reinterpret_cast<xdrproc_t>(xdr_float)));
         }
@@ -790,14 +800,17 @@ int xdr3dfcoord(XDR* xdrs, float* fp, int* size, float* precision)
             fprintf(stderr,
                     "wrong number of coordinates in xdr3dfcoord; "
                     "%d arg vs %d in file",
-                    *size, lsize);
+                    *size,
+                    lsize);
         }
         *size = lsize;
         size3 = *size * 3;
         if (*size <= 9)
         {
             *precision = -1;
-            return (xdr_vector(xdrs, reinterpret_cast<char*>(fp), static_cast<unsigned int>(size3),
+            return (xdr_vector(xdrs,
+                               reinterpret_cast<char*>(fp),
+                               static_cast<unsigned int>(size3),
                                static_cast<unsigned int>(sizeof(*fp)),
                                reinterpret_cast<xdrproc_t>(xdr_float)));
         }
index 7d99fdf79cf89eec158c1e2d9be808c5f87c0f7c..a75a63ad48348cf7dfa6334aafaf06c890b21d5f 100644 (file)
@@ -144,7 +144,9 @@ static std::vector<t_mapping> getcmap(FILE* in, const char* fn)
             gmx_fatal(FARGS,
                       "Not enough lines in colormap file %s"
                       "(should be %d, found only %d)",
-                      fn, n + 1, i);
+                      fn,
+                      n + 1,
+                      i);
         }
         sscanf(line, "%s%s%lf%lf%lf", code, desc, &r, &g, &b);
         m[i].code.c1 = code[0];
@@ -171,8 +173,13 @@ void printcmap(FILE* out, int n, t_mapping map[])
     fprintf(out, "%d\n", n);
     for (i = 0; (i < n); i++)
     {
-        fprintf(out, "%c%c  %20s  %10g  %10g  %10g\n", map[i].code.c1 ? map[i].code.c1 : ' ',
-                map[i].code.c2 ? map[i].code.c2 : ' ', map[i].desc, map[i].rgb.r, map[i].rgb.g,
+        fprintf(out,
+                "%c%c  %20s  %10g  %10g  %10g\n",
+                map[i].code.c1 ? map[i].code.c1 : ' ',
+                map[i].code.c2 ? map[i].code.c2 : ' ',
+                map[i].desc,
+                map[i].rgb.r,
+                map[i].rgb.g,
                 map[i].rgb.b);
     }
 }
@@ -327,7 +334,11 @@ static t_matrix read_xpm_entry(FILE* in)
 
     if (debug)
     {
-        fprintf(debug, "%s %s %s %s\n", mm.title.c_str(), mm.legend.c_str(), mm.label_x.c_str(),
+        fprintf(debug,
+                "%s %s %s %s\n",
+                mm.title.c_str(),
+                mm.legend.c_str(),
+                mm.label_x.c_str(),
                 mm.label_y.c_str());
     }
 
@@ -443,7 +454,8 @@ static t_matrix read_xpm_entry(FILE* in)
         gmx_fatal(FARGS,
                   "Number of read colors map entries (%d) does not match the number in the header "
                   "(%d)",
-                  m, nmap);
+                  m,
+                  nmap);
     }
 
     /* Read axes, if there are any */
@@ -588,7 +600,8 @@ real** matrix2real(t_matrix* in, real** out)
             fprintf(stderr,
                     "Could not convert matrix to reals,\n"
                     "color map entry %zd has a non-real description: \"%s\"\n",
-                    i, in->map[i].desc);
+                    i,
+                    in->map[i].desc);
             return nullptr;
         }
         rmap[i] = tmp;
@@ -653,7 +666,9 @@ write_xpm_map3(FILE* out, int n_x, int n_y, int* nlevels, real lo, real mid, rea
 
     if (*nlevels > NMAP * NMAP)
     {
-        fprintf(stderr, "Warning, too many levels (%d) in matrix, using %d only\n", *nlevels,
+        fprintf(stderr,
+                "Warning, too many levels (%d) in matrix, using %d only\n",
+                *nlevels,
                 static_cast<int>(NMAP * NMAP));
         *nlevels = NMAP * NMAP;
     }
@@ -678,18 +693,23 @@ write_xpm_map3(FILE* out, int n_x, int n_y, int* nlevels, real lo, real mid, rea
         r = rlo.r + (i * (rmid.r - rlo.r) / clev_lo);
         g = rlo.g + (i * (rmid.g - rlo.g) / clev_lo);
         b = rlo.b + (i * (rmid.b - rlo.b) / clev_lo);
-        fprintf(out, "\"%c%c c #%02X%02X%02X \" /* \"%.3g\" */,\n", mapper[i % NMAP],
+        fprintf(out,
+                "\"%c%c c #%02X%02X%02X \" /* \"%.3g\" */,\n",
+                mapper[i % NMAP],
                 (*nlevels <= NMAP) ? ' ' : mapper[i / NMAP],
                 static_cast<unsigned int>(std::round(255 * r)),
                 static_cast<unsigned int>(std::round(255 * g)),
-                static_cast<unsigned int>(std::round(255 * b)), ((nmid - i) * lo + i * mid) / clev_lo);
+                static_cast<unsigned int>(std::round(255 * b)),
+                ((nmid - i) * lo + i * mid) / clev_lo);
     }
     for (i = 0; (i < (*nlevels - nmid)); i++)
     {
         r = rmid.r + (i * (rhi.r - rmid.r) / clev_hi);
         g = rmid.g + (i * (rhi.g - rmid.g) / clev_hi);
         b = rmid.b + (i * (rhi.b - rmid.b) / clev_hi);
-        fprintf(out, "\"%c%c c #%02X%02X%02X \" /* \"%.3g\" */,\n", mapper[(i + nmid) % NMAP],
+        fprintf(out,
+                "\"%c%c c #%02X%02X%02X \" /* \"%.3g\" */,\n",
+                mapper[(i + nmid) % NMAP],
                 (*nlevels <= NMAP) ? ' ' : mapper[(i + nmid) / NMAP],
                 static_cast<unsigned int>(std::round(255 * r)),
                 static_cast<unsigned int>(std::round(255 * g)),
@@ -709,11 +729,14 @@ static void pr_simple_cmap(FILE* out, real lo, real hi, int nlevel, t_rgb rlo, t
         r   = rlo.r + fac * (rhi.r - rlo.r);
         g   = rlo.g + fac * (rhi.g - rlo.g);
         b   = rlo.b + fac * (rhi.b - rlo.b);
-        fprintf(out, "\"%c%c c #%02X%02X%02X \" /* \"%.3g\" */,\n", mapper[(i + i0) % NMAP],
+        fprintf(out,
+                "\"%c%c c #%02X%02X%02X \" /* \"%.3g\" */,\n",
+                mapper[(i + i0) % NMAP],
                 (nlevel <= NMAP) ? ' ' : mapper[(i + i0) / NMAP],
                 static_cast<unsigned int>(std::round(255 * r)),
                 static_cast<unsigned int>(std::round(255 * g)),
-                static_cast<unsigned int>(std::round(255 * b)), lo + fac * (hi - lo));
+                static_cast<unsigned int>(std::round(255 * b)),
+                lo + fac * (hi - lo));
     }
 }
 
@@ -744,11 +767,14 @@ static void pr_discrete_cmap(FILE* out, int* nlevel, int i0)
     n       = *nlevel;
     for (i = 0; (i < n); i++)
     {
-        fprintf(out, "\"%c%c c #%02X%02X%02X \" /* \"%3d\" */,\n", mapper[(i + i0) % NMAP],
+        fprintf(out,
+                "\"%c%c c #%02X%02X%02X \" /* \"%3d\" */,\n",
+                mapper[(i + i0) % NMAP],
                 (n <= NMAP) ? ' ' : mapper[(i + i0) / NMAP],
                 static_cast<unsigned int>(round(255 * rgbd[i].r)),
                 static_cast<unsigned int>(round(255 * rgbd[i].g)),
-                static_cast<unsigned int>(round(255 * rgbd[i].b)), i);
+                static_cast<unsigned int>(round(255 * rgbd[i].b)),
+                i);
     }
 }
 
@@ -799,7 +825,9 @@ static void write_xpm_map(FILE* out, int n_x, int n_y, int* nlevels, real lo, re
 
     if (*nlevels > NMAP * NMAP)
     {
-        fprintf(stderr, "Warning, too many levels (%d) in matrix, using %d only\n", *nlevels,
+        fprintf(stderr,
+                "Warning, too many levels (%d) in matrix, using %d only\n",
+                *nlevels,
                 static_cast<int>(NMAP * NMAP));
         *nlevels = NMAP * NMAP;
     }
@@ -819,11 +847,14 @@ static void write_xpm_map(FILE* out, int n_x, int n_y, int* nlevels, real lo, re
         r   = (nlo * rlo.r + i * rhi.r) * invlevel;
         g   = (nlo * rlo.g + i * rhi.g) * invlevel;
         b   = (nlo * rlo.b + i * rhi.b) * invlevel;
-        fprintf(out, "\"%c%c c #%02X%02X%02X \" /* \"%.3g\" */,\n", mapper[i % NMAP],
+        fprintf(out,
+                "\"%c%c c #%02X%02X%02X \" /* \"%.3g\" */,\n",
+                mapper[i % NMAP],
                 (*nlevels <= NMAP) ? ' ' : mapper[i / NMAP],
                 static_cast<unsigned int>(std::round(255 * r)),
                 static_cast<unsigned int>(std::round(255 * g)),
-                static_cast<unsigned int>(std::round(255 * b)), (nlo * lo + i * hi) * invlevel);
+                static_cast<unsigned int>(std::round(255 * b)),
+                (nlo * lo + i * hi) * invlevel);
     }
 }
 
@@ -985,7 +1016,12 @@ static void write_xpm_data_split(FILE*  out,
                     gmx_fatal(FARGS,
                               "Range checking i = %d, j = %d, c = %d, bot = %d, top = %d "
                               "matrix[i,j] = %f",
-                              i, j, c, nlevel_bot, nlevel_top, mat[i][j]);
+                              i,
+                              j,
+                              c,
+                              nlevel_bot,
+                              nlevel_top,
+                              mat[i][j]);
                 }
             }
             else if (i > j)
@@ -996,7 +1032,12 @@ static void write_xpm_data_split(FILE*  out,
                     gmx_fatal(FARGS,
                               "Range checking i = %d, j = %d, c = %d, bot = %d, top = %d "
                               "matrix[i,j] = %f",
-                              i, j, c, nlevel_bot, nlevel_top, mat[i][j]);
+                              i,
+                              j,
+                              c,
+                              nlevel_bot,
+                              nlevel_top,
+                              mat[i][j]);
                 }
             }
             else
@@ -1028,10 +1069,14 @@ void write_xpm_m(FILE* out, t_matrix m)
     fprintf(out, "\"%d %d   %zu %d\",\n", m.nx, m.ny, m.map.size(), bOneChar ? 1 : 2);
     for (const auto& map : m.map)
     {
-        fprintf(out, "\"%c%c c #%02X%02X%02X \" /* \"%s\" */,\n", map.code.c1,
-                bOneChar ? ' ' : map.code.c2, static_cast<unsigned int>(round(map.rgb.r * 255)),
+        fprintf(out,
+                "\"%c%c c #%02X%02X%02X \" /* \"%s\" */,\n",
+                map.code.c1,
+                bOneChar ? ' ' : map.code.c2,
+                static_cast<unsigned int>(round(map.rgb.r * 255)),
                 static_cast<unsigned int>(round(map.rgb.g * 255)),
-                static_cast<unsigned int>(round(map.rgb.b * 255)), map.desc);
+                static_cast<unsigned int>(round(map.rgb.b * 255)),
+                map.desc);
     }
     writeXpmAxis(out, "x", m.axis_x);
     writeXpmAxis(out, "y", m.axis_y);
@@ -1144,8 +1189,8 @@ void write_xpm_split(FILE*              out,
     }
 
     write_xpm_header(out, title, legend, label_x, label_y, FALSE);
-    write_xpm_map_split(out, n_x, n_y, nlevel_top, lo_top, hi_top, rlo_top, rhi_top, bDiscreteColor,
-                        nlevel_bot, lo_bot, hi_bot, rlo_bot, rhi_bot);
+    write_xpm_map_split(
+            out, n_x, n_y, nlevel_top, lo_top, hi_top, rlo_top, rhi_top, bDiscreteColor, nlevel_bot, lo_bot, hi_bot, rlo_bot, rhi_bot);
     writeXpmAxis(out, "x", ArrayRef<real>(axis_x, axis_x + n_x + ((flags & MAT_SPATIAL_X) != 0U ? 1 : 0)));
     writeXpmAxis(out, "y", ArrayRef<real>(axis_y, axis_y + n_y + ((flags & MAT_SPATIAL_Y) != 0U ? 1 : 0)));
     write_xpm_data_split(out, n_x, n_y, mat, lo_top, hi_top, *nlevel_top, lo_bot, hi_bot, *nlevel_bot);
index de5dad28041eb79c895f8d5f712bc2d3bc53ae99..2fd3e5aa0fd6278652e435d95496bd62224d080a 100644 (file)
@@ -84,8 +84,8 @@ std::vector<char> readCharBufferFromFile(const std::string& filename)
     gmx_fseek(gmx_fio_getfp(mrcFile), 0, SEEK_SET);
     // Read whole file into buffer the size of the file
     std::vector<char> fileContentBuffer(fileSize);
-    size_t readSize = fread(fileContentBuffer.data(), sizeof(char), fileContentBuffer.size(),
-                            gmx_fio_getfp(mrcFile));
+    size_t            readSize = fread(
+            fileContentBuffer.data(), sizeof(char), fileContentBuffer.size(), gmx_fio_getfp(mrcFile));
     gmx_fio_close(mrcFile);
 
     if (fileContentBuffer.size() != readSize)
@@ -223,7 +223,8 @@ MultiDimArray<std::vector<float>, dynamicExtents3D> MrcDensityMapOfFloatFromFile
 {
     MultiDimArray<std::vector<float>, dynamicExtents3D> result(
             getDynamicExtents3D(impl_->reader().header()));
-    std::copy(std::begin(impl_->reader().constView()), std::end(impl_->reader().constView()),
+    std::copy(std::begin(impl_->reader().constView()),
+              std::end(impl_->reader().constView()),
               begin(result.asView()));
     return result;
 }
index aec1d970ac94a26375f37e59c28e8f79e4dd6ecc..ec1c60a7a0118bb1d61ebdb1aaccc3f577b95ea8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * \inlibraryapi
  * \ingroup module_fileio
  */
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "gromacs/math/multidimarray.h"
 #include "gromacs/mdspan/extensions.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
@@ -78,7 +78,7 @@ public:
 
 private:
     class Impl;
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \libinternal \brief Read an mrc density map from a given file.
@@ -118,7 +118,7 @@ public:
 
 private:
     class Impl;
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \libinternal \brief Write an mrc/ccp4 file that contains float values.
@@ -142,7 +142,7 @@ public:
 
 private:
     class Impl;
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index faaefc5773a77b12c7289d99fb48c91513739acc..d38a76caa70a92e6d723b50b25c68ac9ea3ef761 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -65,8 +65,9 @@ bool anySmallerZero(Container values)
 template<typename Container>
 bool anyLargerThanValue(Container values, typename Container::value_type boundaryValue)
 {
-    return std::any_of(std::begin(values), std::end(values),
-                       [boundaryValue](auto v) { return v > boundaryValue; });
+    return std::any_of(std::begin(values), std::end(values), [boundaryValue](auto v) {
+        return v > boundaryValue;
+    });
 }
 
 } // namespace
@@ -92,7 +93,8 @@ TranslateAndScale getCoordinateTransformationToLattice(const MrcDensityMapHeader
     RVec       scale = { header.extent_[XX] / (header.cellLength_[XX] * c_AAtoNmConversion),
                    header.extent_[YY] / (header.cellLength_[YY] * c_AAtoNmConversion),
                    header.extent_[ZZ] / (header.cellLength_[ZZ] * c_AAtoNmConversion) };
-    const RVec emdbOrigin{ header.userDefinedFloat_[12], header.userDefinedFloat_[13],
+    const RVec emdbOrigin{ header.userDefinedFloat_[12],
+                           header.userDefinedFloat_[13],
                            header.userDefinedFloat_[14] };
     RVec       translation;
     if (emdbOrigin[XX] == 0. && emdbOrigin[YY] == 0. && emdbOrigin[ZZ] == 0.)
@@ -103,7 +105,8 @@ TranslateAndScale getCoordinateTransformationToLattice(const MrcDensityMapHeader
     }
     else
     {
-        translation = { -emdbOrigin[XX] * c_AAtoNmConversion, -emdbOrigin[YY] * c_AAtoNmConversion,
+        translation = { -emdbOrigin[XX] * c_AAtoNmConversion,
+                        -emdbOrigin[YY] * c_AAtoNmConversion,
                         -emdbOrigin[ZZ] * c_AAtoNmConversion };
     }
     return { scale, translation };
@@ -111,7 +114,8 @@ TranslateAndScale getCoordinateTransformationToLattice(const MrcDensityMapHeader
 
 dynamicExtents3D getDynamicExtents3D(const MrcDensityMapHeader& header)
 {
-    return { header.numColumnRowSection_[ZZ], header.numColumnRowSection_[YY],
+    return { header.numColumnRowSection_[ZZ],
+             header.numColumnRowSection_[YY],
              header.numColumnRowSection_[XX] };
 };
 
index b4b8cb1f30f655c87b9a14c6e2dc8343d421a2eb..4b567dcecb90161209a0692f46b5e80395918d99 100644 (file)
@@ -181,8 +181,10 @@ void gmx_mtxio_read(const char* filename, int* nrow, int* ncol, real** full_matr
     }
     gmx_fio_do_int(fio, prec);
 
-    fprintf(stderr, "Reading %s precision matrix generated by GROMACS %s\n",
-            (prec == 1) ? "double" : "single", gmxver);
+    fprintf(stderr,
+            "Reading %s precision matrix generated by GROMACS %s\n",
+            (prec == 1) ? "double" : "single",
+            gmxver);
 
     gmx_fio_do_int(fio, i);
     *nrow = i;
index 0c99fa191a521704831fc02f86b81c540e23b968..e51c52ccc1b525eb2d935828d8b8e29d067c377b 100644 (file)
@@ -37,7 +37,7 @@
  */
 #include "gmxpre.h"
 
-#include "oenv.h"
+#include "gromacs/fileio/oenv.h"
 
 #include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/exceptions.h"
index f551dde39129a3e06e80fd3f854f0325377f421b..1b3c4ec0ca9caca148c44e34fc0cd1d3425d54ea 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +37,9 @@
  */
 #include "gmxpre.h"
 
-#include "pdbio.h"
+#include "gromacs/fileio/pdbio.h"
 
+#include <algorithm>
 #include <cctype>
 #include <cmath>
 #include <cstdlib>
@@ -48,6 +49,7 @@
 
 #include "gromacs/fileio/gmxfio.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/atomprop.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/coolstuff.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/snprintf.h"
+#include "gromacs/utility/stringtoenumvalueconverter.h"
 
 typedef struct
 {
@@ -74,8 +78,14 @@ typedef struct gmx_conect_t
     gmx_conection_t* conect;
 } gmx_conect_t;
 
-static const char* pdbtp[epdbNR] = { "ATOM  ", "HETATM", "ANISOU", "CRYST1", "COMPND", "MODEL",
-                                     "ENDMDL", "TER",    "HEADER", "TITLE",  "REMARK", "CONECT" };
+const char* enumValueToString(PdbRecordType enumValue)
+{
+    static constexpr gmx::EnumerationArray<PdbRecordType, const char*> pdbRecordTypeName = {
+        "ATOM  ", "HETATM", "ANISOU", "CRYST1", "COMPND", "MODEL",
+        "ENDMDL", "TER",    "HEADER", "TITLE",  "REMARK", "CONECT"
+    };
+    return pdbRecordTypeName[enumValue];
+}
 
 #define REMARK_SIM_BOX "REMARK    THIS IS A SIMULATION BOX"
 
@@ -95,7 +105,7 @@ void gmx_write_pdb_box(FILE* out, PbcType pbcType, const matrix box)
 
     if (norm2(box[YY]) * norm2(box[ZZ]) != 0)
     {
-        alpha = RAD2DEG * gmx_angle(box[YY], box[ZZ]);
+        alpha = gmx::c_rad2Deg * gmx_angle(box[YY], box[ZZ]);
     }
     else
     {
@@ -103,7 +113,7 @@ void gmx_write_pdb_box(FILE* out, PbcType pbcType, const matrix box)
     }
     if (norm2(box[XX]) * norm2(box[ZZ]) != 0)
     {
-        beta = RAD2DEG * gmx_angle(box[XX], box[ZZ]);
+        beta = gmx::c_rad2Deg * gmx_angle(box[XX], box[ZZ]);
     }
     else
     {
@@ -111,7 +121,7 @@ void gmx_write_pdb_box(FILE* out, PbcType pbcType, const matrix box)
     }
     if (norm2(box[XX]) * norm2(box[YY]) != 0)
     {
-        gamma = RAD2DEG * gmx_angle(box[XX], box[YY]);
+        gamma = gmx::c_rad2Deg * gmx_angle(box[XX], box[YY]);
     }
     else
     {
@@ -120,14 +130,30 @@ void gmx_write_pdb_box(FILE* out, PbcType pbcType, const matrix box)
     fprintf(out, "REMARK    THIS IS A SIMULATION BOX\n");
     if (pbcType != PbcType::Screw)
     {
-        fprintf(out, "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n", 10 * norm(box[XX]),
-                10 * norm(box[YY]), 10 * norm(box[ZZ]), alpha, beta, gamma, "P 1", 1);
+        fprintf(out,
+                "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n",
+                10 * norm(box[XX]),
+                10 * norm(box[YY]),
+                10 * norm(box[ZZ]),
+                alpha,
+                beta,
+                gamma,
+                "P 1",
+                1);
     }
     else
     {
         /* Double the a-vector length and write the correct space group */
-        fprintf(out, "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n", 20 * norm(box[XX]),
-                10 * norm(box[YY]), 10 * norm(box[ZZ]), alpha, beta, gamma, "P 21 1 1", 1);
+        fprintf(out,
+                "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n",
+                20 * norm(box[XX]),
+                10 * norm(box[YY]),
+                10 * norm(box[ZZ]),
+                alpha,
+                beta,
+                gamma,
+                "P 21 1 1",
+                1);
     }
 }
 
@@ -181,7 +207,7 @@ static void read_cryst1(char* line, PbcType* pbcType, matrix box)
         {
             if (alpha != 90.0)
             {
-                cosa = std::cos(alpha * DEG2RAD);
+                cosa = std::cos(alpha * gmx::c_deg2Rad);
             }
             else
             {
@@ -189,7 +215,7 @@ static void read_cryst1(char* line, PbcType* pbcType, matrix box)
             }
             if (beta != 90.0)
             {
-                cosb = std::cos(beta * DEG2RAD);
+                cosb = std::cos(beta * gmx::c_deg2Rad);
             }
             else
             {
@@ -197,8 +223,8 @@ static void read_cryst1(char* line, PbcType* pbcType, matrix box)
             }
             if (gamma != 90.0)
             {
-                cosg = std::cos(gamma * DEG2RAD);
-                sing = std::sin(gamma * DEG2RAD);
+                cosg = std::cos(gamma * gmx::c_deg2Rad);
+                sing = std::sin(gamma * gmx::c_deg2Rad);
             }
             else
             {
@@ -219,20 +245,20 @@ static void read_cryst1(char* line, PbcType* pbcType, matrix box)
     }
 }
 
-static int gmx_fprintf_pqr_atomline(FILE*           fp,
-                                    enum PDB_record record,
-                                    int             atom_seq_number,
-                                    const char*     atom_name,
-                                    const char*     res_name,
-                                    char            chain_id,
-                                    int             res_seq_number,
-                                    real            x,
-                                    real            y,
-                                    real            z,
-                                    real            occupancy,
-                                    real            b_factor)
+static int gmx_fprintf_pqr_atomline(FILE*         fp,
+                                    PdbRecordType record,
+                                    int           atom_seq_number,
+                                    const char*   atom_name,
+                                    const char*   res_name,
+                                    char          chain_id,
+                                    int           res_seq_number,
+                                    real          x,
+                                    real          y,
+                                    real          z,
+                                    real          occupancy,
+                                    real          b_factor)
 {
-    GMX_RELEASE_ASSERT(record == epdbATOM || record == epdbHETATM,
+    GMX_RELEASE_ASSERT(record == PdbRecordType::Atom || record == PdbRecordType::Hetatm,
                        "Can only print PQR atom lines as ATOM or HETATM records");
 
     /* Check atom name */
@@ -245,9 +271,19 @@ static int gmx_fprintf_pqr_atomline(FILE*           fp,
     atom_seq_number = atom_seq_number % 100000;
     res_seq_number  = res_seq_number % 10000;
 
-    int n = fprintf(fp, "%-6s%5d %-4.4s%4.4s%c%4d %8.3f %8.3f %8.3f %6.2f %6.2f\n", pdbtp[record],
-                    atom_seq_number, atom_name, res_name, chain_id, res_seq_number, x, y, z,
-                    occupancy, b_factor);
+    int n = fprintf(fp,
+                    "%-6s%5d %-4.4s%4.4s%c%4d %8.3f %8.3f %8.3f %6.2f %6.2f\n",
+                    enumValueToString(record),
+                    atom_seq_number,
+                    atom_name,
+                    res_name,
+                    chain_id,
+                    res_seq_number,
+                    x,
+                    y,
+                    z,
+                    occupancy,
+                    b_factor);
 
     return n;
 }
@@ -265,11 +301,11 @@ void write_pdbfile_indexed(FILE*          out,
                            gmx_conect     conect,
                            bool           usePqrFormat)
 {
-    gmx_conect_t*   gc = static_cast<gmx_conect_t*>(conect);
-    enum PDB_record type;
-    char            altloc;
-    real            occup, bfac;
-    gmx_bool        bOccup;
+    gmx_conect_t* gc = static_cast<gmx_conect_t*>(conect);
+    PdbRecordType type;
+    char          altloc;
+    real          occup, bfac;
+    gmx_bool      bOccup;
 
 
     fprintf(out, "TITLE     %s\n", (title && title[0]) ? title : gmx::bromacs().c_str());
@@ -333,7 +369,7 @@ void write_pdbfile_indexed(FILE*          out,
         {
             gmx_pdbinfo_init_default(&pdbinfo);
         }
-        type   = static_cast<enum PDB_record>(pdbinfo.type);
+        type   = pdbinfo.type;
         altloc = pdbinfo.altloc;
         if (!isalnum(altloc))
         {
@@ -343,22 +379,54 @@ void write_pdbfile_indexed(FILE*          out,
         bfac  = pdbinfo.bfac;
         if (!usePqrFormat)
         {
-            gmx_fprintf_pdb_atomline(out, type, i + 1, nm.c_str(), altloc, resnm.c_str(), ch, resnr,
-                                     resic, 10 * x[i][XX], 10 * x[i][YY], 10 * x[i][ZZ], occup,
-                                     bfac, atoms->atom[i].elem);
+            gmx_fprintf_pdb_atomline(out,
+                                     type,
+                                     i + 1,
+                                     nm.c_str(),
+                                     altloc,
+                                     resnm.c_str(),
+                                     ch,
+                                     resnr,
+                                     resic,
+                                     10 * x[i][XX],
+                                     10 * x[i][YY],
+                                     10 * x[i][ZZ],
+                                     occup,
+                                     bfac,
+                                     atoms->atom[i].elem);
 
             if (atoms->pdbinfo && atoms->pdbinfo[i].bAnisotropic)
             {
-                fprintf(out, "ANISOU%5d  %-4.4s%4.4s%c%4d%c %7d%7d%7d%7d%7d%7d\n", (i + 1) % 100000,
-                        nm.c_str(), resnm.c_str(), ch, resnr, (resic == '\0') ? ' ' : resic,
-                        atoms->pdbinfo[i].uij[0], atoms->pdbinfo[i].uij[1], atoms->pdbinfo[i].uij[2],
-                        atoms->pdbinfo[i].uij[3], atoms->pdbinfo[i].uij[4], atoms->pdbinfo[i].uij[5]);
+                fprintf(out,
+                        "ANISOU%5d  %-4.4s%4.4s%c%4d%c %7d%7d%7d%7d%7d%7d\n",
+                        (i + 1) % 100000,
+                        nm.c_str(),
+                        resnm.c_str(),
+                        ch,
+                        resnr,
+                        (resic == '\0') ? ' ' : resic,
+                        atoms->pdbinfo[i].uij[0],
+                        atoms->pdbinfo[i].uij[1],
+                        atoms->pdbinfo[i].uij[2],
+                        atoms->pdbinfo[i].uij[3],
+                        atoms->pdbinfo[i].uij[4],
+                        atoms->pdbinfo[i].uij[5]);
             }
         }
         else
         {
-            gmx_fprintf_pqr_atomline(out, type, i + 1, nm.c_str(), resnm.c_str(), ch, resnr,
-                                     10 * x[i][XX], 10 * x[i][YY], 10 * x[i][ZZ], occup, bfac);
+            gmx_fprintf_pqr_atomline(out,
+                                     type,
+                                     i + 1,
+                                     nm.c_str(),
+                                     resnm.c_str(),
+                                     ch,
+                                     resnr,
+                                     10 * x[i][XX],
+                                     10 * x[i][YY],
+                                     10 * x[i][ZZ],
+                                     occup,
+                                     bfac);
         }
     }
 
@@ -392,33 +460,11 @@ void write_pdbfile(FILE*          out,
     {
         index[i] = i;
     }
-    write_pdbfile_indexed(out, title, atoms, x, pbcType, box, chainid, model_nr, atoms->nr, index,
-                          conect, false);
+    write_pdbfile_indexed(
+            out, title, atoms, x, pbcType, box, chainid, model_nr, atoms->nr, index, conect, false);
     sfree(index);
 }
 
-static int line2type(const char* line)
-{
-    int  k;
-    char type[8];
-
-    for (k = 0; (k < 6); k++)
-    {
-        type[k] = line[k];
-    }
-    type[k] = '\0';
-
-    for (k = 0; (k < epdbNR); k++)
-    {
-        if (std::strncmp(type, pdbtp[k], strlen(pdbtp[k])) == 0)
-        {
-            break;
-        }
-    }
-
-    return k;
-}
-
 static void read_anisou(char line[], int natom, t_atoms* atoms)
 {
     int  i, j, k, atomnr;
@@ -458,9 +504,14 @@ static void read_anisou(char line[], int natom, t_atoms* atoms)
     }
     else
     {
-        if (sscanf(line + 29, "%d%d%d%d%d%d", &atoms->pdbinfo[i].uij[U11], &atoms->pdbinfo[i].uij[U22],
-                   &atoms->pdbinfo[i].uij[U33], &atoms->pdbinfo[i].uij[U12],
-                   &atoms->pdbinfo[i].uij[U13], &atoms->pdbinfo[i].uij[U23])
+        if (sscanf(line + 29,
+                   "%d%d%d%d%d%d",
+                   &atoms->pdbinfo[i].uij[U11],
+                   &atoms->pdbinfo[i].uij[U22],
+                   &atoms->pdbinfo[i].uij[U33],
+                   &atoms->pdbinfo[i].uij[U12],
+                   &atoms->pdbinfo[i].uij[U13],
+                   &atoms->pdbinfo[i].uij[U23])
             == 6)
         {
             atoms->pdbinfo[i].bAnisotropic = TRUE;
@@ -524,22 +575,25 @@ void get_pdb_atomnumber(const t_atoms* atoms, AtomProperties* aps)
                 atomNumberSet = true;
             }
         }
-        std::string buf;
+        static constexpr size_t sc_maxElementNameLength = 3;
+        static_assert(sizeof(atoms->atom[i].elem) >= sc_maxElementNameLength + 1);
+        std::string element;
         if (atomNumberSet)
         {
             atoms->atom[i].atomnumber = atomnumber;
-            buf                       = aps->elementFromAtomNumber(atomnumber);
+            element                   = aps->elementFromAtomNumber(atomnumber);
             if (debug)
             {
                 fprintf(debug, "Atomnumber for atom '%s' is %d\n", anm, atomnumber);
             }
         }
-        buf.resize(3);
-        std::strncpy(atoms->atom[i].elem, buf.c_str(), 4);
+        element.resize(sc_maxElementNameLength);
+        std::strcpy(atoms->atom[i].elem, element.c_str());
     }
 }
 
-static int read_atom(t_symtab* symtab, const char line[], int type, int natom, t_atoms* atoms, rvec x[], int chainnum)
+static int
+read_atom(t_symtab* symtab, const char line[], PdbRecordType type, int natom, t_atoms* atoms, rvec x[], int chainnum)
 {
     t_atom*       atomn;
     int           j, k;
@@ -798,7 +852,6 @@ int read_pdbfile(FILE*      in,
     gmx_bool      bCOMPND;
     gmx_bool      bConnWarn = FALSE;
     char          line[STRLEN + 1];
-    int           line_type;
     char *        c, *d;
     int           natom, chainnum;
     gmx_bool      bStop = FALSE;
@@ -823,28 +876,39 @@ int read_pdbfile(FILE*      in,
     title[0] = '\0';
     natom    = 0;
     chainnum = 0;
+    static const gmx::StringToEnumValueConverter<PdbRecordType, enumValueToString, gmx::StringCompareType::Exact, gmx::StripStrings::Yes>
+            sc_pdbRecordTypeIdentifier;
     while (!bStop && (fgets2(line, STRLEN, in) != nullptr))
     {
-        line_type = line2type(line);
+        // Convert line to a null-terminated string, then take a substring of at most 6 chars
+        std::string                  lineAsString(line);
+        std::optional<PdbRecordType> line_type =
+                sc_pdbRecordTypeIdentifier.valueFrom(lineAsString.substr(0, 6));
+        if (!line_type)
+        {
+            // Skip this line because it does not start with a
+            // recognized leading string describing a PDB record type.
+            continue;
+        }
 
-        switch (line_type)
+        switch (line_type.value())
         {
-            case epdbATOM:
-            case epdbHETATM:
-                natom = read_atom(symtab, line, line_type, natom, atoms, x, chainnum);
+            case PdbRecordType::Atom:
+            case PdbRecordType::Hetatm:
+                natom = read_atom(symtab, line, line_type.value(), natom, atoms, x, chainnum);
                 break;
 
-            case epdbANISOU:
+            case PdbRecordType::Anisou:
                 if (atoms->havePdbInfo)
                 {
                     read_anisou(line, natom, atoms);
                 }
                 break;
 
-            case epdbCRYST1: read_cryst1(line, pbcType, box); break;
+            case PdbRecordType::Cryst1: read_cryst1(line, pbcType, box); break;
 
-            case epdbTITLE:
-            case epdbHEADER:
+            case PdbRecordType::Title:
+            case PdbRecordType::Header:
                 if (std::strlen(line) > 6)
                 {
                     c = line + 6;
@@ -870,7 +934,7 @@ int read_pdbfile(FILE*      in,
                 }
                 break;
 
-            case epdbCOMPND:
+            case PdbRecordType::Compound:
                 if ((!std::strstr(line, ": ")) || (std::strstr(line + 6, "MOLECULE:")))
                 {
                     if (!(c = std::strstr(line + 6, "MOLECULE:")))
@@ -912,17 +976,17 @@ int read_pdbfile(FILE*      in,
                 }
                 break;
 
-            case epdbTER: chainnum++; break;
+            case PdbRecordType::Ter: chainnum++; break;
 
-            case epdbMODEL:
+            case PdbRecordType::Model:
                 if (model_nr)
                 {
                     sscanf(line, "%*s%d", model_nr);
                 }
                 break;
 
-            case epdbENDMDL: bStop = TRUE; break;
-            case epdbCONECT:
+            case PdbRecordType::EndModel: bStop = TRUE; break;
+            case PdbRecordType::Conect:
                 if (gc)
                 {
                     gmx_conect_addline(gc, line);
@@ -992,27 +1056,27 @@ gmx_conect gmx_conect_generate(const t_topology* top)
     return gc;
 }
 
-int gmx_fprintf_pdb_atomline(FILE*           fp,
-                             enum PDB_record record,
-                             int             atom_seq_number,
-                             const char*     atom_name,
-                             char            alternate_location,
-                             const char*     res_name,
-                             char            chain_id,
-                             int             res_seq_number,
-                             char            res_insertion_code,
-                             real            x,
-                             real            y,
-                             real            z,
-                             real            occupancy,
-                             real            b_factor,
-                             const char*     element)
+int gmx_fprintf_pdb_atomline(FILE*         fp,
+                             PdbRecordType record,
+                             int           atom_seq_number,
+                             const char*   atom_name,
+                             char          alternate_location,
+                             const char*   res_name,
+                             char          chain_id,
+                             int           res_seq_number,
+                             char          res_insertion_code,
+                             real          x,
+                             real          y,
+                             real          z,
+                             real          occupancy,
+                             real          b_factor,
+                             const char*   element)
 {
     char     tmp_atomname[6], tmp_resname[6];
     gmx_bool start_name_in_col13;
     int      n;
 
-    if (record != epdbATOM && record != epdbHETATM)
+    if (record != PdbRecordType::Atom && record != PdbRecordType::Hetatm)
     {
         gmx_fatal(FARGS, "Can only print PDB atom lines as ATOM or HETATM records");
     }
@@ -1055,9 +1119,21 @@ int gmx_fprintf_pdb_atomline(FILE*           fp,
     atom_seq_number = atom_seq_number % 100000;
     res_seq_number  = res_seq_number % 10000;
 
-    n = fprintf(fp, "%-6s%5d %-4.4s%c%4.4s%c%4d%c   %8.3f%8.3f%8.3f%6.2f%6.2f          %2s\n",
-                pdbtp[record], atom_seq_number, tmp_atomname, alternate_location, tmp_resname,
-                chain_id, res_seq_number, res_insertion_code, x, y, z, occupancy, b_factor,
+    n = fprintf(fp,
+                "%-6s%5d %-4.4s%c%4.4s%c%4d%c   %8.3f%8.3f%8.3f%6.2f%6.2f          %2s\n",
+                enumValueToString(record),
+                atom_seq_number,
+                tmp_atomname,
+                alternate_location,
+                tmp_resname,
+                chain_id,
+                res_seq_number,
+                res_insertion_code,
+                x,
+                y,
+                z,
+                occupancy,
+                b_factor,
                 (element != nullptr) ? element : "");
 
     return n;
index 5d497b8cd740c9a518dda0eb1eff25bbfb12770e..09076b74a30a7c18d0730e73bb53c7a3450f3af7 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/binaryinformation.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/keyvaluetreebuilder.h"
@@ -160,7 +161,7 @@ gmx::KeyValueTreeObject flatKeyValueTreeFromInpFile(gmx::ArrayRef<const t_inpfil
 {
     gmx::KeyValueTreeBuilder builder;
     auto                     root = builder.rootObject();
-    for (auto& local : inp)
+    for (const auto& local : inp)
     {
         root.addValue<std::string>(local.name_, !local.value_.empty() ? local.value_ : "");
     }
@@ -225,7 +226,8 @@ void write_inpfile(gmx::TextOutputStream*  stream,
             }
             else
             {
-                writer.writeLine(formatString("%-24s = %s", local.name_.c_str(),
+                writer.writeLine(formatString("%-24s = %s",
+                                              local.name_.c_str(),
                                               !local.value_.empty() ? local.value_.c_str() : ""));
             }
         }
@@ -263,7 +265,8 @@ void replace_inp_entry(gmx::ArrayRef<t_inpfile> inp, const char* old_entry, cons
                     gmx_fatal(FARGS,
                               "A parameter is present with both the old name '%s' and the new name "
                               "'%s'.",
-                              local.name_.c_str(), inp[foundIndex].name_.c_str());
+                              local.name_.c_str(),
+                              inp[foundIndex].name_.c_str());
                 }
 
                 local.name_.assign(new_entry);
@@ -306,7 +309,7 @@ void mark_einp_set(gmx::ArrayRef<t_inpfile> inp, const char* name)
     }
 }
 
-static int get_einp(std::vector<t_inpfile>* inp, const char* name)
+int get_einp(std::vector<t_inpfile>* inp, const char* name)
 {
     std::vector<t_inpfile>& inpRef   = *inp;
     bool                    notfound = false;
@@ -363,7 +366,8 @@ int get_eint(std::vector<t_inpfile>* inp, const char* name, int def, warninp_t w
             sprintf(warn_buf,
                     "Right hand side '%s' for parameter '%s' in parameter file is not an integer "
                     "value\n",
-                    inpRef[ii].value_.c_str(), inpRef[ii].name_.c_str());
+                    inpRef[ii].value_.c_str(),
+                    inpRef[ii].name_.c_str());
             warning_error(wi, warn_buf);
         }
 
@@ -399,7 +403,8 @@ int64_t get_eint64(std::vector<t_inpfile>* inp, const char* name, int64_t def, w
             sprintf(warn_buf,
                     "Right hand side '%s' for parameter '%s' in parameter file is not an integer "
                     "value\n",
-                    inpRef[ii].value_.c_str(), inpRef[ii].name_.c_str());
+                    inpRef[ii].value_.c_str(),
+                    inpRef[ii].name_.c_str());
             warning_error(wi, warn_buf);
         }
 
@@ -435,7 +440,8 @@ double get_ereal(std::vector<t_inpfile>* inp, const char* name, double def, warn
             sprintf(warn_buf,
                     "Right hand side '%s' for parameter '%s' in parameter file is not a real "
                     "value\n",
-                    inpRef[ii].value_.c_str(), inpRef[ii].name_.c_str());
+                    inpRef[ii].value_.c_str(),
+                    inpRef[ii].name_.c_str());
             warning_error(wi, warn_buf);
         }
 
@@ -505,8 +511,11 @@ int get_eeenum(std::vector<t_inpfile>* inp, const char* name, const char** defs,
 
     if (defs[i] == nullptr)
     {
-        n += sprintf(buf, "Invalid enum '%s' for variable %s, using '%s'\n",
-                     inpRef[ii].value_.c_str(), name, defs[0]);
+        n += sprintf(buf,
+                     "Invalid enum '%s' for variable %s, using '%s'\n",
+                     inpRef[ii].value_.c_str(),
+                     name,
+                     defs[0]);
         n += sprintf(buf + n, "Next time use one of:");
         int j = 0;
         while (defs[j])
index 37034e7c7dc234a5afe3739cf2091c0ec165a8b7..3fd3db59f962a38f564378e578d4f6f68c63f842 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <utility>
 #include <vector>
 
+#include "gromacs/fileio/warninp.h"
 #include "gromacs/utility/basedefinitions.h"
-
-struct warninp;
-typedef warninp* warninp_t;
+#include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
+#include "gromacs/utility/stringutil.h"
 
 namespace gmx
 {
@@ -160,6 +161,74 @@ int get_eeenum(std::vector<t_inpfile>* inp, const std::string& name, const char*
 int get_eenum(std::vector<t_inpfile>* inp, const char* name, const char** defs);
 /* defs must be NULL terminated */
 
+//! Get index of option `name`. Exposed here so that `getEnum` can access it.
+int get_einp(std::vector<t_inpfile>* inp, const char* name);
+
+/*! \brief Read option from input and return corresponding enum value
+ *
+ * If the option is not set, return the first value of the enum as default.
+ * Defined here so we don't need to instantiate the templates in the source file.
+ *
+ * \tparam EnumType  The type of enum to be returned
+ * \param[in]  inp   The input file vector
+ * \param[in]  name  The name of the option to be read
+ * \param[out] wi    Handler for context-sensitive warnings.
+ * \return  Enum value corresponding to read input
+ */
+template<typename EnumType>
+EnumType getEnum(std::vector<t_inpfile>* inp, const char* name, warninp* wi)
+{
+    // If there's no valid option, we'll use the EnumType::Default.
+    // Note, this assumes the enum is zero based, which is also assumed by
+    // EnumerationWrapper and EnumerationArray.
+    const auto  defaultEnumValue = EnumType::Default;
+    const auto& defaultName      = enumValueToString(defaultEnumValue);
+    // Get index of option in input
+    const auto ii = get_einp(inp, name);
+    if (ii == -1)
+    {
+        // If the option wasn't set, we return EnumType::Default
+        inp->back().value_.assign(defaultName);
+        return defaultEnumValue;
+    }
+
+    // Check if option string can be mapped to a valid enum value.
+    //
+    // Note that this cannot be replaced with
+    // StringToEnumValueConverter until all instantiations of this
+    // function have a matching enumValueToString, and all of the
+    // latter are in the same namespace. Currently some of those
+    // function declarations are in gmx namespace and some are not.
+    const auto* optionString = (*inp)[ii].value_.c_str();
+    for (auto enumValue : gmx::EnumerationWrapper<EnumType>{})
+    {
+        if (gmx_strcasecmp_min(enumValueToString(enumValue), optionString) == 0)
+        {
+            return enumValue;
+        }
+    }
+
+    // If we get here, the option set is invalid. Print error.
+    std::string errorMessage = gmx::formatString(
+            "Invalid enum '%s' for variable %s, using '%s'\n", optionString, name, defaultName);
+    errorMessage += gmx::formatString("Next time, use one of:");
+    for (auto enumValue : gmx::EnumerationWrapper<EnumType>{})
+    {
+        errorMessage += gmx::formatString(" '%s'", enumValueToString(enumValue));
+    }
+    if (wi != nullptr)
+    {
+        warning_error(wi, errorMessage);
+    }
+    else
+    {
+        fprintf(stderr, "%s\n", errorMessage.c_str());
+    }
+    (*inp)[ii].value_.assign(defaultName);
+    return defaultEnumValue;
+}
+
+
 //! Replace for macro CCTYPE, prints comment string after newline
 void printStringNewline(std::vector<t_inpfile>* inp, const char* line);
 //! Replace for macro CTYPE, prints comment string
diff --git a/src/gromacs/fileio/tests/.clang-tidy b/src/gromacs/fileio/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 62731d49aa006d450e2cf0056a0cd095a5b46be6..577a09c1099815b816ddaaf7149da2df3241c4df 100644 (file)
@@ -49,3 +49,4 @@ gmx_add_unit_test(FileIOTests fileio-test
         ${tng_sources}
         xvgio.cpp
     )
+target_link_libraries(fileio-test PRIVATE legacy_api)
index 53a1216ff3352abfbdd0008996f0ac1f1dd15fc2..70544f3d7a1ebaa9a5c3bb5655d92464806d1eb6 100644 (file)
@@ -103,8 +103,13 @@ public:
 
     void writeReferenceFile()
     {
-        write_sto_conf(referenceFilename_.c_str(), *refTop_->name, &refTop_->atoms,
-                       as_rvec_array(refX_.data()), nullptr, PbcType::Unset, refBox_);
+        write_sto_conf(referenceFilename_.c_str(),
+                       *refTop_->name,
+                       &refTop_->atoms,
+                       as_rvec_array(refX_.data()),
+                       nullptr,
+                       PbcType::Unset,
+                       refBox_);
     }
 
     void readReferenceFileTps()
@@ -121,8 +126,8 @@ public:
 
     void writeTestFileAndTest()
     {
-        write_sto_conf(testFilename_.c_str(), *testTop_->name, &testTop_->atoms, testX_, nullptr,
-                       PbcType::Unset, testBox_);
+        write_sto_conf(
+                testFilename_.c_str(), *testTop_->name, &testTop_->atoms, testX_, nullptr, PbcType::Unset, testBox_);
         testFilesEqual(referenceFilename_, testFilename_);
     }
 
index 8c6042eee249229a5e8f09d29cfc31a141208c5c..841fe4c5c4addc05fc70c971a093fa8ef3492c1e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ namespace
 class FileMD5Test : public ::testing::Test
 {
 public:
-    void prepareFile(int lengthInBytes)
+    void prepareFile(int lengthInBytes) const
     {
         // Fill some memory with some arbitrary bits.
         std::vector<char> data(lengthInBytes);
index d142f0fb4be4c68c0f3b1c46b9738c71d0115401..57879d58fcbe0d6d41975e0330f1d3693a6556f2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -135,7 +135,8 @@ TEST(MrcDensityMap, ReadsDensityDataFromFile)
 
     TestReferenceData    refData;
     TestReferenceChecker checker(refData.rootChecker());
-    checker.checkSequence(begin(densityData.asConstView()), end(densityData.asConstView()),
+    checker.checkSequence(begin(densityData.asConstView()),
+                          end(densityData.asConstView()),
                           "data ellipsoid density");
 }
 
index 20d82b537c5f80fd4ace34a4a7e6e0c6413d738f..f40afab03de25e938c79f8903f3cef5a84fa92e3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ public:
 
     void useStringAsXvgFile(const std::string& xvgString) { referenceContents_ = xvgString; }
 
-    void writeXvgFile()
+    void writeXvgFile() const
     {
         gmx::TextWriter::writeFileFromString(referenceFilename(), referenceContents());
     }
index fae0dd6b8d7eb31caee4b550b9abc752933df554..4ee04f8942af30579eac3ac390c488454b27479c 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,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "gromacs/utility/enumerationhelpers.h"
 #include "timecontrol.h"
 
-#include "thread_mpi/threads.h"
+#include <mutex>
 
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/fatalerror.h"
          Please keep it that way. */
 
 /* Globals for trajectory input */
-typedef struct
+struct t_timecontrol
 {
-    real     t;
-    gmx_bool bSet;
-} t_timecontrol;
+    t_timecontrol(real inputT, bool inputSet) : t(inputT), bSet(inputSet) {}
+    real t;
+    bool bSet;
+};
 
-static t_timecontrol timecontrol[TNR] = { { 0, FALSE }, { 0, FALSE }, { 0, FALSE } };
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static gmx::EnumerationArray<TimeControl, t_timecontrol> timecontrol = { t_timecontrol(0, false),
+                                                                         t_timecontrol(0, false),
+                                                                         t_timecontrol(0, false) };
 
-static tMPI_Thread_mutex_t tc_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static std::mutex g_timeControlMutex;
 
-gmx_bool bTimeSet(int tcontrol)
+gmx_bool bTimeSet(TimeControl tcontrol)
 {
     gmx_bool ret;
 
-    tMPI_Thread_mutex_lock(&tc_mutex);
-    range_check(tcontrol, 0, TNR);
+    const std::lock_guard<std::mutex> lock(g_timeControlMutex);
     ret = timecontrol[tcontrol].bSet;
-    tMPI_Thread_mutex_unlock(&tc_mutex);
 
     return ret;
 }
 
-real rTimeValue(int tcontrol)
+real rTimeValue(TimeControl tcontrol)
 {
     real ret;
 
-    tMPI_Thread_mutex_lock(&tc_mutex);
-    range_check(tcontrol, 0, TNR);
+    const std::lock_guard<std::mutex> lock(g_timeControlMutex);
     ret = timecontrol[tcontrol].t;
-    tMPI_Thread_mutex_unlock(&tc_mutex);
     return ret;
 }
 
-void setTimeValue(int tcontrol, real value)
+void setTimeValue(TimeControl tcontrol, real value)
 {
-    tMPI_Thread_mutex_lock(&tc_mutex);
-    range_check(tcontrol, 0, TNR);
+    const std::lock_guard<std::mutex> lock(g_timeControlMutex);
     timecontrol[tcontrol].t    = value;
     timecontrol[tcontrol].bSet = TRUE;
-    tMPI_Thread_mutex_unlock(&tc_mutex);
 }
index 52f7b37ceedb5f54753bd1783d805501469882d1..651cfbf1b979da27388953e9af50ffb1e284383b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 /* The code below is to facilitate controlled begin and end of
  * trajectory reading.
  */
-enum
+enum class TimeControl : int
 {
-    TBEGIN,
-    TEND,
-    TDELTA,
-    TNR
+    Begin,
+    End,
+    Delta,
+    Count
 };
 
-gmx_bool bTimeSet(int tcontrol);
+bool bTimeSet(TimeControl tcontrol);
 
-real rTimeValue(int tcontrol);
+real rTimeValue(TimeControl tcontrol);
 
-void setTimeValue(int tcontrol, real value);
+void setTimeValue(TimeControl tcontrol, real value);
 
 #endif
index a872a8793b69083d340baaced6b7353ee3be53a6..485d3e35b21741d4e27e03eba96240c9fadfd71f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -158,8 +158,7 @@ void gmx_tng_open(const char* filename, char mode, gmx_tng_trajectory_t* gmx_tng
 #    if GMX_DOUBLE
         precisionString = " (double precision)";
 #    endif
-        sprintf(programInfo, "%.100s %.128s%.24s", gmx::getProgramContext().displayName(),
-                gmx_version(), precisionString);
+        sprintf(programInfo, "%.100s %.128s%.24s", gmx::getProgramContext().displayName(), gmx_version(), precisionString);
         if (mode == 'w')
         {
             tng_first_program_name_set(*tng, programInfo);
@@ -266,8 +265,8 @@ static void addTngMoleculeFromTopology(gmx_tng_trajectory_t gmx_tng,
                  * number the latter should be used. Wait for TNG 2.0*/
                 tng_chain_residue_add(tng, tngChain, *resInfo->name, &tngRes);
             }
-            tng_residue_atom_add(tng, tngRes, *(atoms->atomname[atomIndex]),
-                                 *(atoms->atomtype[atomIndex]), &tngAtom);
+            tng_residue_atom_add(
+                    tng, tngRes, *(atoms->atomname[atomIndex]), *(atoms->atomtype[atomIndex]), &tngAtom);
         }
     }
     tng_molecule_cnt_set(tng, *tngMol, numMolecules);
@@ -342,18 +341,37 @@ void gmx_tng_add_mtop(gmx_tng_trajectory_t gmx_tng, const gmx_mtop_t* mtop)
         }
         for (int molCounter = 1; molCounter < molBlock.nmol; molCounter++)
         {
-            std::copy_n(atomCharges.end() - molType->atoms.nr, molType->atoms.nr,
+            std::copy_n(atomCharges.end() - molType->atoms.nr,
+                        molType->atoms.nr,
                         std::back_inserter(atomCharges));
-            std::copy_n(atomMasses.end() - molType->atoms.nr, molType->atoms.nr,
-                        std::back_inserter(atomMasses));
+            std::copy_n(atomMasses.end() - molType->atoms.nr, molType->atoms.nr, std::back_inserter(atomMasses));
         }
     }
     /* Write the TNG data blocks. */
-    tng_particle_data_block_add(tng, TNG_TRAJ_PARTIAL_CHARGES, "PARTIAL CHARGES", datatype,
-                                TNG_NON_TRAJECTORY_BLOCK, 1, 1, 1, 0, mtop->natoms,
-                                TNG_GZIP_COMPRESSION, atomCharges.data());
-    tng_particle_data_block_add(tng, TNG_TRAJ_MASSES, "ATOM MASSES", datatype, TNG_NON_TRAJECTORY_BLOCK,
-                                1, 1, 1, 0, mtop->natoms, TNG_GZIP_COMPRESSION, atomMasses.data());
+    tng_particle_data_block_add(tng,
+                                TNG_TRAJ_PARTIAL_CHARGES,
+                                "PARTIAL CHARGES",
+                                datatype,
+                                TNG_NON_TRAJECTORY_BLOCK,
+                                1,
+                                1,
+                                1,
+                                0,
+                                mtop->natoms,
+                                TNG_GZIP_COMPRESSION,
+                                atomCharges.data());
+    tng_particle_data_block_add(tng,
+                                TNG_TRAJ_MASSES,
+                                "ATOM MASSES",
+                                datatype,
+                                TNG_NON_TRAJECTORY_BLOCK,
+                                1,
+                                1,
+                                1,
+                                0,
+                                mtop->natoms,
+                                TNG_GZIP_COMPRESSION,
+                                atomMasses.data());
 }
 
 /*! \libinternal \brief Compute greatest common divisor of n1 and n2
@@ -427,8 +445,7 @@ static void set_writing_intervals(gmx_tng_trajectory_t gmx_tng,
     /* Define pointers to specific writing functions depending on if we
      * write float or double data */
     typedef tng_function_status (*set_writing_interval_func_pointer)(
-            tng_trajectory_t, const int64_t, const int64_t, const int64_t, const char*, const char,
-            const char);
+            tng_trajectory_t, const int64_t, const int64_t, const 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
@@ -467,8 +484,8 @@ static void set_writing_intervals(gmx_tng_trajectory_t gmx_tng,
     }
     if (xout)
     {
-        set_writing_interval(tng, xout, 3, TNG_TRAJ_POSITIONS, "POSITIONS", TNG_PARTICLE_BLOCK_DATA,
-                             compression);
+        set_writing_interval(
+                tng, xout, 3, TNG_TRAJ_POSITIONS, "POSITIONS", TNG_PARTICLE_BLOCK_DATA, compression);
         /* TODO: if/when we write energies to TNG also, reconsider how
          * and when box information is written, because GROMACS
          * behaviour pre-5.0 was to write the box with every
@@ -483,8 +500,8 @@ static void set_writing_intervals(gmx_tng_trajectory_t gmx_tng,
     }
     if (vout)
     {
-        set_writing_interval(tng, vout, 3, TNG_TRAJ_VELOCITIES, "VELOCITIES",
-                             TNG_PARTICLE_BLOCK_DATA, compression);
+        set_writing_interval(
+                tng, vout, 3, TNG_TRAJ_VELOCITIES, "VELOCITIES", TNG_PARTICLE_BLOCK_DATA, compression);
 
         gcd = greatest_common_divisor_if_positive(gcd, vout);
         if (lowest < 0 || vout < lowest)
@@ -494,8 +511,8 @@ static void set_writing_intervals(gmx_tng_trajectory_t gmx_tng,
     }
     if (fout)
     {
-        set_writing_interval(tng, fout, 3, TNG_TRAJ_FORCES, "FORCES", TNG_PARTICLE_BLOCK_DATA,
-                             TNG_GZIP_COMPRESSION);
+        set_writing_interval(
+                tng, fout, 3, TNG_TRAJ_FORCES, "FORCES", TNG_PARTICLE_BLOCK_DATA, TNG_GZIP_COMPRESSION);
 
         gcd = greatest_common_divisor_if_positive(gcd, fout);
         if (lowest < 0 || fout < lowest)
@@ -507,11 +524,11 @@ static void set_writing_intervals(gmx_tng_trajectory_t gmx_tng,
     {
         /* Lambdas and box shape written at an interval of the lowest common
            denominator of other output */
-        set_writing_interval(tng, gcd, 1, TNG_GMX_LAMBDA, "LAMBDAS", TNG_NON_PARTICLE_BLOCK_DATA,
-                             TNG_GZIP_COMPRESSION);
+        set_writing_interval(
+                tng, gcd, 1, TNG_GMX_LAMBDA, "LAMBDAS", TNG_NON_PARTICLE_BLOCK_DATA, TNG_GZIP_COMPRESSION);
 
-        set_writing_interval(tng, gcd, 9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
-                             TNG_NON_PARTICLE_BLOCK_DATA, TNG_GZIP_COMPRESSION);
+        set_writing_interval(
+                tng, gcd, 9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE", TNG_NON_PARTICLE_BLOCK_DATA, TNG_GZIP_COMPRESSION);
         gmx_tng->lambdaOutputInterval = gcd;
         gmx_tng->boxOutputInterval    = gcd;
         if (gcd < lowest / 10)
@@ -520,7 +537,8 @@ static void set_writing_intervals(gmx_tng_trajectory_t gmx_tng,
                     "The lowest common denominator of trajectory output is "
                     "every %d step(s), whereas the shortest output interval "
                     "is every %d steps.",
-                    gcd, lowest);
+                    gcd,
+                    lowest);
         }
     }
 }
@@ -531,7 +549,7 @@ void gmx_tng_prepare_md_writing(gmx_tng_trajectory_t gmx_tng, const gmx_mtop_t*
 #if GMX_USE_TNG
     gmx_tng_add_mtop(gmx_tng, mtop);
     set_writing_intervals(gmx_tng, FALSE, ir);
-    tng_time_per_frame_set(gmx_tng->tng, ir->delta_t * PICO);
+    tng_time_per_frame_set(gmx_tng->tng, ir->delta_t * gmx::c_pico);
     gmx_tng->timePerFrameIsSet = true;
 #else
     GMX_UNUSED_VALUE(gmx_tng);
@@ -657,8 +675,12 @@ static void add_selection_groups(gmx_tng_trajectory_t gmx_tng, const gmx_mtop_t*
                      * original residue IDs - otherwise there might be conflicts. */
                     tng_chain_residue_add(tng, chain, res_name, &res);
                 }
-                tng_residue_atom_w_id_add(tng, res, *(atoms->atomname[atomIndex]),
-                                          *(atoms->atomtype[atomIndex]), atom_offset + atomIndex, &atom);
+                tng_residue_atom_w_id_add(tng,
+                                          res,
+                                          *(atoms->atomname[atomIndex]),
+                                          *(atoms->atomtype[atomIndex]),
+                                          atom_offset + atomIndex,
+                                          &atom);
                 bAtomsAdded = TRUE;
             }
             /* Add bonds. */
@@ -674,15 +696,13 @@ static void add_selection_groups(gmx_tng_trajectory_t gmx_tng, const gmx_mtop_t*
                             int atom1, atom2;
                             atom1 = ilist.iatoms[l] + atom_offset;
                             atom2 = ilist.iatoms[l + 1] + atom_offset;
-                            if (getGroupType(mtop->groups,
-                                             SimulationAtomGroupType::CompressedPositionOutput, atom1)
+                            if (getGroupType(mtop->groups, SimulationAtomGroupType::CompressedPositionOutput, atom1)
                                         == 0
-                                && getGroupType(mtop->groups,
-                                                SimulationAtomGroupType::CompressedPositionOutput, atom2)
+                                && getGroupType(mtop->groups, SimulationAtomGroupType::CompressedPositionOutput, atom2)
                                            == 0)
                             {
-                                tng_molecule_bond_add(tng, mol, ilist.iatoms[l],
-                                                      ilist.iatoms[l + 1], &tngBond);
+                                tng_molecule_bond_add(
+                                        tng, mol, ilist.iatoms[l], ilist.iatoms[l + 1], &tngBond);
                             }
                         }
                     }
@@ -745,7 +765,7 @@ void gmx_tng_prepare_low_prec_writing(gmx_tng_trajectory_t gmx_tng, const gmx_mt
     gmx_tng_add_mtop(gmx_tng, mtop);
     add_selection_groups(gmx_tng, mtop);
     set_writing_intervals(gmx_tng, TRUE, ir);
-    tng_time_per_frame_set(gmx_tng->tng, ir->delta_t * PICO);
+    tng_time_per_frame_set(gmx_tng->tng, ir->delta_t * gmx::c_pico);
     gmx_tng->timePerFrameIsSet = true;
     gmx_tng_set_compression_precision(gmx_tng, ir->x_compression_precision);
 #else
@@ -767,15 +787,21 @@ void gmx_fwrite_tng(gmx_tng_trajectory_t gmx_tng,
                     const rvec*          f)
 {
 #if GMX_USE_TNG
-    typedef tng_function_status (*write_data_func_pointer)(
-            tng_trajectory_t, const int64_t, const double, const real*, const int64_t,
-            const int64_t, const char*, const char, const char);
+    typedef tng_function_status (*write_data_func_pointer)(tng_trajectory_t,
+                                                           const int64_t,
+                                                           const double,
+                                                           const real*,
+                                                           const int64_t,
+                                                           const int64_t,
+                                                           const char*,
+                                                           const char,
+                                                           const char);
 #    if GMX_DOUBLE
     static write_data_func_pointer write_data = tng_util_generic_with_time_double_write;
 #    else
     static write_data_func_pointer    write_data           = tng_util_generic_with_time_write;
 #    endif
-    double  elapsedSeconds = elapsedPicoSeconds * PICO;
+    double  elapsedSeconds = elapsedPicoSeconds * gmx::c_pico;
     int64_t nParticles;
     char    compression;
 
@@ -845,8 +871,15 @@ void gmx_fwrite_tng(gmx_tng_trajectory_t gmx_tng,
     {
         GMX_ASSERT(box, "Need a non-NULL box if positions are written");
 
-        if (write_data(tng, step, elapsedSeconds, reinterpret_cast<const real*>(x), 3,
-                       TNG_TRAJ_POSITIONS, "POSITIONS", TNG_PARTICLE_BLOCK_DATA, compression)
+        if (write_data(tng,
+                       step,
+                       elapsedSeconds,
+                       reinterpret_cast<const real*>(x),
+                       3,
+                       TNG_TRAJ_POSITIONS,
+                       "POSITIONS",
+                       TNG_PARTICLE_BLOCK_DATA,
+                       compression)
             != TNG_SUCCESS)
         {
             gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?");
@@ -855,8 +888,15 @@ void gmx_fwrite_tng(gmx_tng_trajectory_t gmx_tng,
 
     if (v)
     {
-        if (write_data(tng, step, elapsedSeconds, reinterpret_cast<const real*>(v), 3,
-                       TNG_TRAJ_VELOCITIES, "VELOCITIES", TNG_PARTICLE_BLOCK_DATA, compression)
+        if (write_data(tng,
+                       step,
+                       elapsedSeconds,
+                       reinterpret_cast<const real*>(v),
+                       3,
+                       TNG_TRAJ_VELOCITIES,
+                       "VELOCITIES",
+                       TNG_PARTICLE_BLOCK_DATA,
+                       compression)
             != TNG_SUCCESS)
         {
             gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?");
@@ -867,8 +907,15 @@ void gmx_fwrite_tng(gmx_tng_trajectory_t gmx_tng,
     {
         /* TNG-MF1 compression only compresses positions and velocities. Use lossless
          * compression for forces regardless of output mode */
-        if (write_data(tng, step, elapsedSeconds, reinterpret_cast<const real*>(f), 3,
-                       TNG_TRAJ_FORCES, "FORCES", TNG_PARTICLE_BLOCK_DATA, TNG_GZIP_COMPRESSION)
+        if (write_data(tng,
+                       step,
+                       elapsedSeconds,
+                       reinterpret_cast<const real*>(f),
+                       3,
+                       TNG_TRAJ_FORCES,
+                       "FORCES",
+                       TNG_PARTICLE_BLOCK_DATA,
+                       TNG_GZIP_COMPRESSION)
             != TNG_SUCCESS)
         {
             gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?");
@@ -879,8 +926,15 @@ void gmx_fwrite_tng(gmx_tng_trajectory_t gmx_tng,
     {
         /* TNG-MF1 compression only compresses positions and velocities. Use lossless
          * compression for box shape regardless of output mode */
-        if (write_data(tng, step, elapsedSeconds, reinterpret_cast<const real*>(box), 9,
-                       TNG_TRAJ_BOX_SHAPE, "BOX SHAPE", TNG_NON_PARTICLE_BLOCK_DATA, TNG_GZIP_COMPRESSION)
+        if (write_data(tng,
+                       step,
+                       elapsedSeconds,
+                       reinterpret_cast<const real*>(box),
+                       9,
+                       TNG_TRAJ_BOX_SHAPE,
+                       "BOX SHAPE",
+                       TNG_NON_PARTICLE_BLOCK_DATA,
+                       TNG_GZIP_COMPRESSION)
             != TNG_SUCCESS)
         {
             gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?");
@@ -891,8 +945,15 @@ void gmx_fwrite_tng(gmx_tng_trajectory_t gmx_tng,
     {
         /* TNG-MF1 compression only compresses positions and velocities. Use lossless
          * compression for lambda regardless of output mode */
-        if (write_data(tng, step, elapsedSeconds, reinterpret_cast<const real*>(&lambda), 1,
-                       TNG_GMX_LAMBDA, "LAMBDAS", TNG_NON_PARTICLE_BLOCK_DATA, TNG_GZIP_COMPRESSION)
+        if (write_data(tng,
+                       step,
+                       elapsedSeconds,
+                       reinterpret_cast<const real*>(&lambda),
+                       1,
+                       TNG_GMX_LAMBDA,
+                       "LAMBDAS",
+                       TNG_NON_PARTICLE_BLOCK_DATA,
+                       TNG_GZIP_COMPRESSION)
             != TNG_SUCCESS)
         {
             gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?");
@@ -943,7 +1004,7 @@ float gmx_tng_get_time_of_final_frame(gmx_tng_trajectory_t gmx_tng)
     tng_num_frames_get(tng, &nFrames);
     tng_util_time_of_frame_get(tng, nFrames - 1, &time);
 
-    fTime = time / PICO;
+    fTime = time / gmx::c_pico;
     return fTime;
 #else
     GMX_UNUSED_VALUE(gmx_tng);
@@ -963,15 +1024,16 @@ void gmx_prepare_tng_writing(const char*              filename,
 #if GMX_USE_TNG
     tng_trajectory_t* input = (gmx_tng_input && *gmx_tng_input) ? &(*gmx_tng_input)->tng : nullptr;
     /* FIXME after 5.0: Currently only standard block types are read */
-    const int      defaultNumIds                    = 5;
-    static 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" };
+    const int      defaultNumIds              = 5;
+    static 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 int64_t, const int64_t, const int64_t, const char*, const char,
-            const char);
+            tng_trajectory_t, const int64_t, const int64_t, const 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
@@ -1016,21 +1078,41 @@ void gmx_prepare_tng_writing(const char*              filename,
                 {
                     case TNG_TRAJ_POSITIONS:
                     case TNG_TRAJ_VELOCITIES:
-                        set_writing_interval(*output, interval, 3, fallbackIds[i], fallbackNames[i],
-                                             TNG_PARTICLE_BLOCK_DATA, compression_type);
+                        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);
+                        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);
+                        set_writing_interval(*output,
+                                             interval,
+                                             9,
+                                             fallbackIds[i],
+                                             fallbackNames[i],
+                                             TNG_NON_PARTICLE_BLOCK_DATA,
+                                             TNG_GZIP_COMPRESSION);
                         (*gmx_tng_output)->boxOutputInterval = interval;
                         break;
                     case TNG_GMX_LAMBDA:
-                        set_writing_interval(*output, interval, 1, fallbackIds[i], fallbackNames[i],
-                                             TNG_NON_PARTICLE_BLOCK_DATA, TNG_GZIP_COMPRESSION);
+                        set_writing_interval(*output,
+                                             interval,
+                                             1,
+                                             fallbackIds[i],
+                                             fallbackNames[i],
+                                             TNG_NON_PARTICLE_BLOCK_DATA,
+                                             TNG_GZIP_COMPRESSION);
                         (*gmx_tng_output)->lambdaOutputInterval = interval;
                         break;
                     default: continue;
@@ -1082,8 +1164,8 @@ void gmx_write_tng_from_trxframe(gmx_tng_trajectory_t gmx_tng_output, const t_tr
     {
         natoms = frame->natoms;
     }
-    gmx_fwrite_tng(gmx_tng_output, TRUE, frame->step, frame->time, 0, frame->box, natoms, frame->x,
-                   frame->v, frame->f);
+    gmx_fwrite_tng(
+            gmx_tng_output, TRUE, frame->step, frame->time, 0, frame->box, natoms, frame->x, frame->v, frame->f);
 #else
     GMX_UNUSED_VALUE(gmx_tng_output);
     GMX_UNUSED_VALUE(frame);
@@ -1189,8 +1271,8 @@ real getDistanceScaleFactor(gmx_tng_trajectory_t in)
     // GROMACS expects distances in nm
     switch (exp)
     {
-        case 9: distanceScaleFactor = NANO / NANO; break;
-        case 10: distanceScaleFactor = NANO / ANGSTROM; break;
+        case 9: distanceScaleFactor = gmx::c_nano / gmx::c_nano; break;
+        case 10: distanceScaleFactor = gmx::c_nano / gmx::c_angstrom; break;
         default: distanceScaleFactor = pow(10.0, exp + 9.0);
     }
 
@@ -1309,10 +1391,10 @@ gmx_bool gmx_read_next_tng_frame(gmx_tng_trajectory_t gmx_tng_input,
     double              frameTime = -1.0;
     int                 size, blockDependency;
     double              prec;
-    const int           defaultNumIds                  = 5;
-    static int64_t fallbackRequestedIds[defaultNumIds] = { TNG_TRAJ_BOX_SHAPE, TNG_TRAJ_POSITIONS,
-                                                           TNG_TRAJ_VELOCITIES, TNG_TRAJ_FORCES,
-                                                           TNG_GMX_LAMBDA };
+    const int           defaultNumIds                       = 5;
+    static int64_t      fallbackRequestedIds[defaultNumIds] = {
+        TNG_TRAJ_BOX_SHAPE, TNG_TRAJ_POSITIONS, TNG_TRAJ_VELOCITIES, TNG_TRAJ_FORCES, TNG_GMX_LAMBDA
+    };
 
 
     fr->bStep   = FALSE;
@@ -1359,13 +1441,13 @@ gmx_bool gmx_read_next_tng_frame(gmx_tng_trajectory_t gmx_tng_input,
         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);
+            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);
+            stat = tng_util_non_particle_data_next_frame_read(
+                    input, blockId, &values, &datatype, &frameNumber, &frameTime);
         }
         if (stat == TNG_CRITICAL)
         {
@@ -1390,14 +1472,20 @@ gmx_bool gmx_read_next_tng_frame(gmx_tng_trajectory_t gmx_tng_input,
                 {
                     convert_array_to_real_array(reinterpret_cast<char*>(values) + size * i * DIM,
                                                 reinterpret_cast<real*>(fr->box[i]),
-                                                getDistanceScaleFactor(gmx_tng_input), 1, DIM, datatype);
+                                                getDistanceScaleFactor(gmx_tng_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(gmx_tng_input), fr->natoms, DIM,
+                convert_array_to_real_array(values,
+                                            reinterpret_cast<real*>(fr->x),
+                                            getDistanceScaleFactor(gmx_tng_input),
+                                            fr->natoms,
+                                            DIM,
                                             datatype);
                 fr->bX = TRUE;
                 tng_util_frame_current_compression_get(input, blockId, &codecId, &prec);
@@ -1410,8 +1498,11 @@ gmx_bool gmx_read_next_tng_frame(gmx_tng_trajectory_t gmx_tng_input,
                 break;
             case TNG_TRAJ_VELOCITIES:
                 srenew(fr->v, fr->natoms);
-                convert_array_to_real_array(values, reinterpret_cast<real*>(fr->v),
-                                            getDistanceScaleFactor(gmx_tng_input), fr->natoms, DIM,
+                convert_array_to_real_array(values,
+                                            reinterpret_cast<real*>(fr->v),
+                                            getDistanceScaleFactor(gmx_tng_input),
+                                            fr->natoms,
+                                            DIM,
                                             datatype);
                 fr->bV = TRUE;
                 tng_util_frame_current_compression_get(input, blockId, &codecId, &prec);
@@ -1424,8 +1515,11 @@ gmx_bool gmx_read_next_tng_frame(gmx_tng_trajectory_t gmx_tng_input,
                 break;
             case TNG_TRAJ_FORCES:
                 srenew(fr->f, fr->natoms);
-                convert_array_to_real_array(values, reinterpret_cast<real*>(fr->f),
-                                            getDistanceScaleFactor(gmx_tng_input), fr->natoms, DIM,
+                convert_array_to_real_array(values,
+                                            reinterpret_cast<real*>(fr->f),
+                                            getDistanceScaleFactor(gmx_tng_input),
+                                            fr->natoms,
+                                            DIM,
                                             datatype);
                 fr->bF = TRUE;
                 break;
@@ -1451,7 +1545,7 @@ gmx_bool gmx_read_next_tng_frame(gmx_tng_trajectory_t gmx_tng_input,
     fr->bStep = TRUE;
 
     // Convert the time to ps
-    fr->time  = frameTime / PICO;
+    fr->time  = frameTime / gmx::c_pico;
     fr->bTime = (frameTime > 0);
 
     // TODO This does not leak, but is not exception safe.
@@ -1573,8 +1667,14 @@ void gmx_print_tng_molecule_system(gmx_tng_trajectory_t gmx_tng_input, FILE* str
     }
 
     tng_num_particles_get(input, &nAtoms);
-    stat = tng_particle_data_vector_get(input, TNG_TRAJ_PARTIAL_CHARGES, &data, &nFramesRead,
-                                        &strideLength, &nParticlesRead, &nValuesPerFrameRead, &datatype);
+    stat = tng_particle_data_vector_get(input,
+                                        TNG_TRAJ_PARTIAL_CHARGES,
+                                        &data,
+                                        &nFramesRead,
+                                        &strideLength,
+                                        &nParticlesRead,
+                                        &nValuesPerFrameRead,
+                                        &datatype);
     if (stat == TNG_SUCCESS)
     {
         atomCharges.resize(nAtoms);
@@ -1592,8 +1692,8 @@ void gmx_print_tng_molecule_system(gmx_tng_trajectory_t gmx_tng_input, FILE* str
         }
     }
 
-    stat = tng_particle_data_vector_get(input, TNG_TRAJ_MASSES, &data, &nFramesRead, &strideLength,
-                                        &nParticlesRead, &nValuesPerFrameRead, &datatype);
+    stat = tng_particle_data_vector_get(
+            input, TNG_TRAJ_MASSES, &data, &nFramesRead, &strideLength, &nParticlesRead, &nValuesPerFrameRead, &datatype);
     if (stat == TNG_SUCCESS)
     {
         atomMasses.resize(nAtoms);
@@ -1688,15 +1788,15 @@ gmx_bool gmx_get_tng_data_next_frame_of_block_type(gmx_tng_trajectory_t gmx_tng_
     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);
+        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);
+        stat = tng_util_non_particle_data_next_frame_read(
+                input, blockId, &data, &datatype, frameNumber, frameTime);
     }
     if (stat == TNG_CRITICAL)
     {
@@ -1714,8 +1814,8 @@ gmx_bool gmx_get_tng_data_next_frame_of_block_type(gmx_tng_trajectory_t gmx_tng_
         gmx_file("Cannot read next frame of TNG file");
     }
     srenew(*values, sizeof(real) * *nValuesPerFrame * *nAtoms);
-    convert_array_to_real_array(data, *values, getDistanceScaleFactor(gmx_tng_input), *nAtoms,
-                                *nValuesPerFrame, datatype);
+    convert_array_to_real_array(
+            data, *values, getDistanceScaleFactor(gmx_tng_input), *nAtoms, *nValuesPerFrame, datatype);
 
     tng_util_frame_current_compression_get(input, blockId, &codecId, &localPrec);
 
index 2d87034417e51a835f728d7409cd5bd5232db580..6109039cd599fde116a70ec26723b7b2858be90f 100644 (file)
@@ -39,7 +39,7 @@
 
 /* This file is completely threadsafe - keep it that way! */
 
-#include "tpxio.h"
+#include "gromacs/fileio/tpxio.h"
 
 #include <cstdio>
 #include <cstdlib>
@@ -49,6 +49,7 @@
 #include <memory>
 #include <vector>
 
+#include "gromacs/applied_forces/awh/read_params.h"
 #include "gromacs/fileio/filetypes.h"
 #include "gromacs/fileio/gmxfio.h"
 #include "gromacs/fileio/gmxfio_xdr.h"
@@ -75,6 +76,7 @@
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/inmemoryserializer.h"
+#include "gromacs/utility/iserializer.h"
 #include "gromacs/utility/keyvaluetreebuilder.h"
 #include "gromacs/utility/keyvaluetreeserializer.h"
 #include "gromacs/utility/smalloc.h"
@@ -93,7 +95,7 @@
  * merging with mainstream GROMACS, set this tag string back to
  * TPX_TAG_RELEASE, and instead add an element to tpxv.
  */
-static const char* tpx_tag = TPX_TAG_RELEASE;
+static const std::string tpx_tag = TPX_TAG_RELEASE;
 
 /*! \brief Enum of values that describe the contents of a tpr file
  * whose format matches a version number
@@ -134,7 +136,8 @@ enum tpxv
     tpxv_StoreNonBondedInteractionExclusionGroup, /**< Store the non bonded interaction exclusion group in the topology */
     tpxv_VSite1,                                  /**< Added 1 type virtual site */
     tpxv_MTS,                                     /**< Added multiple time stepping */
-    tpxv_Count                                    /**< the total number of tpxv versions */
+    tpxv_RemovedConstantAcceleration, /**< Removed support for constant acceleration NEMD. */
+    tpxv_Count                        /**< the total number of tpxv versions */
 };
 
 /*! \brief Version number of the file format written to run input
@@ -290,16 +293,16 @@ static void do_pull_group(gmx::ISerializer* serializer, t_pull_group* pgrp)
 static void do_pull_coord(gmx::ISerializer* serializer,
                           t_pull_coord*     pcrd,
                           int               file_version,
-                          int               ePullOld,
-                          int               eGeomOld,
+                          PullingAlgorithm  ePullOld,
+                          PullGroupGeometry eGeomOld,
                           ivec              dimOld)
 {
     if (file_version >= tpxv_PullCoordNGroup)
     {
-        serializer->doInt(&pcrd->eType);
+        serializer->doEnumAsInt(&pcrd->eType);
         if (file_version >= tpxv_PullExternalPotential)
         {
-            if (pcrd->eType == epullEXTERNAL)
+            if (pcrd->eType == PullingAlgorithm::External)
             {
                 std::string buf;
                 if (serializer->reading())
@@ -329,7 +332,7 @@ static void do_pull_coord(gmx::ISerializer* serializer,
          * changing the tpx version. This requires checks when printing the
          * geometry string and a check and fatal_error in init_pull.
          */
-        serializer->doInt(&pcrd->eGeom);
+        serializer->doEnumAsInt(&pcrd->eGeom);
         serializer->doInt(&pcrd->ngroup);
         if (pcrd->ngroup <= c_pullCoordNgroupMax)
         {
@@ -358,9 +361,9 @@ static void do_pull_coord(gmx::ISerializer* serializer,
         serializer->doInt(&pcrd->group[1]);
         if (file_version >= tpxv_PullCoordTypeGeom)
         {
-            pcrd->ngroup = (pcrd->eGeom == epullgDIRRELATIVE ? 4 : 2);
-            serializer->doInt(&pcrd->eType);
-            serializer->doInt(&pcrd->eGeom);
+            pcrd->ngroup = (pcrd->eGeom == PullGroupGeometry::DirectionRelative ? 4 : 2);
+            serializer->doEnumAsInt(&pcrd->eType);
+            serializer->doEnumAsInt(&pcrd->eGeom);
             if (pcrd->ngroup == 4)
             {
                 serializer->doInt(&pcrd->group[2]);
@@ -403,17 +406,14 @@ static void do_expandedvals(gmx::ISerializer* serializer, t_expanded* expand, t_
     {
         if (n_lambda > 0)
         {
-            if (serializer->reading())
-            {
-                snew(expand->init_lambda_weights, n_lambda);
-            }
-            serializer->doRealArray(expand->init_lambda_weights, n_lambda);
+            expand->init_lambda_weights.resize(n_lambda);
+            serializer->doRealArray(expand->init_lambda_weights.data(), n_lambda);
             serializer->doBool(&expand->bInit_weights);
         }
 
         serializer->doInt(&expand->nstexpanded);
-        serializer->doInt(&expand->elmcmove);
-        serializer->doInt(&expand->elamstats);
+        serializer->doEnumAsInt(&expand->elmcmove);
+        serializer->doEnumAsInt(&expand->elamstats);
         serializer->doInt(&expand->lmc_repeats);
         serializer->doInt(&expand->gibbsdeltalam);
         serializer->doInt(&expand->lmc_forced_nstart);
@@ -427,7 +427,7 @@ static void do_expandedvals(gmx::ISerializer* serializer, t_expanded* expand, t_
         serializer->doReal(&expand->wl_ratio);
         serializer->doReal(&expand->init_wl_delta);
         serializer->doBool(&expand->bWLoneovert);
-        serializer->doInt(&expand->elmceq);
+        serializer->doEnumAsInt(&expand->elmceq);
         serializer->doInt(&expand->equil_steps);
         serializer->doInt(&expand->equil_samples);
         serializer->doInt(&expand->equil_n_at_lam);
@@ -440,16 +440,16 @@ static void do_simtempvals(gmx::ISerializer* serializer, t_simtemp* simtemp, int
 {
     if (file_version >= 79)
     {
-        serializer->doInt(&simtemp->eSimTempScale);
+        serializer->doEnumAsInt(&simtemp->eSimTempScale);
         serializer->doReal(&simtemp->simtemp_high);
         serializer->doReal(&simtemp->simtemp_low);
         if (n_lambda > 0)
         {
             if (serializer->reading())
             {
-                snew(simtemp->temperatures, n_lambda);
+                simtemp->temperatures.resize(n_lambda);
             }
-            serializer->doRealArray(simtemp->temperatures, n_lambda);
+            serializer->doRealArray(simtemp->temperatures.data(), n_lambda);
         }
     }
 }
@@ -467,7 +467,6 @@ static void do_imd(gmx::ISerializer* serializer, t_IMD* imd)
 static void do_fepvals(gmx::ISerializer* serializer, t_lambda* fepvals, int file_version)
 {
     /* i is defined in the ndo_double macro; use g to iterate. */
-    int  g;
     real rdum;
 
     /* free energy values */
@@ -493,24 +492,17 @@ static void do_fepvals(gmx::ISerializer* serializer, t_lambda* fepvals, int file
     if (file_version >= 79)
     {
         serializer->doInt(&fepvals->n_lambda);
-        if (serializer->reading())
-        {
-            snew(fepvals->all_lambda, efptNR);
-        }
-        for (g = 0; g < efptNR; g++)
+        for (auto g : keysOf(fepvals->all_lambda))
         {
             if (fepvals->n_lambda > 0)
             {
-                if (serializer->reading())
-                {
-                    snew(fepvals->all_lambda[g], fepvals->n_lambda);
-                }
-                serializer->doDoubleArray(fepvals->all_lambda[g], fepvals->n_lambda);
-                serializer->doBoolArray(fepvals->separate_dvdl, efptNR);
+                fepvals->all_lambda[g].resize(fepvals->n_lambda);
+                serializer->doDoubleArray(fepvals->all_lambda[g].data(), fepvals->n_lambda);
+                serializer->doBoolArray(fepvals->separate_dvdl.begin(), fepvals->separate_dvdl.size());
             }
             else if (fepvals->init_lambda >= 0)
             {
-                fepvals->separate_dvdl[efptFEP] = TRUE;
+                fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Fep] = TRUE;
             }
         }
     }
@@ -519,36 +511,33 @@ static void do_fepvals(gmx::ISerializer* serializer, t_lambda* fepvals, int file
         serializer->doInt(&fepvals->n_lambda);
         if (serializer->reading())
         {
-            int g;
-
-            snew(fepvals->all_lambda, efptNR);
             /* still allocate the all_lambda array's contents. */
-            for (g = 0; g < efptNR; g++)
+            for (auto g : keysOf(fepvals->all_lambda))
             {
                 if (fepvals->n_lambda > 0)
                 {
-                    snew(fepvals->all_lambda[g], fepvals->n_lambda);
+                    fepvals->all_lambda[g].resize(fepvals->n_lambda);
                 }
             }
         }
-        serializer->doDoubleArray(fepvals->all_lambda[efptFEP], fepvals->n_lambda);
+        serializer->doDoubleArray(fepvals->all_lambda[FreeEnergyPerturbationCouplingType::Fep].data(),
+                                  fepvals->n_lambda);
         if (fepvals->init_lambda >= 0)
         {
-            int g, h;
-
-            fepvals->separate_dvdl[efptFEP] = TRUE;
+            fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Fep] = TRUE;
 
             if (serializer->reading())
             {
                 /* copy the contents of the efptFEP lambda component to all
                    the other components */
-                for (g = 0; g < efptNR; g++)
+                for (auto g : keysOf(fepvals->all_lambda))
                 {
-                    for (h = 0; h < fepvals->n_lambda; h++)
+                    for (int h = 0; h < fepvals->n_lambda; h++)
                     {
-                        if (g != efptFEP)
+                        if (g != FreeEnergyPerturbationCouplingType::Fep)
                         {
-                            fepvals->all_lambda[g][h] = fepvals->all_lambda[efptFEP][h];
+                            fepvals->all_lambda[g][h] =
+                                    fepvals->all_lambda[FreeEnergyPerturbationCouplingType::Fep][h];
                         }
                     }
                 }
@@ -557,11 +546,10 @@ static void do_fepvals(gmx::ISerializer* serializer, t_lambda* fepvals, int file
     }
     else
     {
-        fepvals->n_lambda   = 0;
-        fepvals->all_lambda = nullptr;
+        fepvals->n_lambda = 0;
         if (fepvals->init_lambda >= 0)
         {
-            fepvals->separate_dvdl[efptFEP] = TRUE;
+            fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Fep] = TRUE;
         }
     }
     serializer->doReal(&fepvals->sc_alpha);
@@ -609,13 +597,13 @@ static void do_fepvals(gmx::ISerializer* serializer, t_lambda* fepvals, int file
 
     if (file_version >= 73)
     {
-        serializer->doInt(&fepvals->separate_dhdl_file);
-        serializer->doInt(&fepvals->dhdl_derivatives);
+        serializer->doEnumAsInt(&fepvals->separate_dhdl_file);
+        serializer->doEnumAsInt(&fepvals->dhdl_derivatives);
     }
     else
     {
-        fepvals->separate_dhdl_file = esepdhdlfileYES;
-        fepvals->dhdl_derivatives   = edhdlderivativesYES;
+        fepvals->separate_dhdl_file = SeparateDhdlFile::Yes;
+        fepvals->dhdl_derivatives   = DhDlDerivativeCalculation::Yes;
     }
     if (file_version >= 71)
     {
@@ -629,11 +617,11 @@ static void do_fepvals(gmx::ISerializer* serializer, t_lambda* fepvals, int file
     }
     if (file_version >= 79)
     {
-        serializer->doInt(&fepvals->edHdLPrintEnergy);
+        serializer->doEnumAsInt(&fepvals->edHdLPrintEnergy);
     }
     else
     {
-        fepvals->edHdLPrintEnergy = edHdLPrintEnergyNO;
+        fepvals->edHdLPrintEnergy = FreeEnergyPrintEnergy::No;
     }
 
     /* handle lambda_neighbors */
@@ -667,68 +655,11 @@ static void do_fepvals(gmx::ISerializer* serializer, t_lambda* fepvals, int file
     }
 }
 
-static void do_awhBias(gmx::ISerializer* serializer, gmx::AwhBiasParams* awhBiasParams, int gmx_unused file_version)
-{
-    serializer->doInt(&awhBiasParams->eTarget);
-    serializer->doDouble(&awhBiasParams->targetBetaScaling);
-    serializer->doDouble(&awhBiasParams->targetCutoff);
-    serializer->doInt(&awhBiasParams->eGrowth);
-    serializer->doInt(&awhBiasParams->bUserData);
-    serializer->doDouble(&awhBiasParams->errorInitial);
-    serializer->doInt(&awhBiasParams->ndim);
-    serializer->doInt(&awhBiasParams->shareGroup);
-    serializer->doBool(&awhBiasParams->equilibrateHistogram);
-
-    if (serializer->reading())
-    {
-        snew(awhBiasParams->dimParams, awhBiasParams->ndim);
-    }
-
-    for (int d = 0; d < awhBiasParams->ndim; d++)
-    {
-        gmx::AwhDimParams* dimParams = &awhBiasParams->dimParams[d];
-
-        serializer->doInt(&dimParams->eCoordProvider);
-        serializer->doInt(&dimParams->coordIndex);
-        serializer->doDouble(&dimParams->origin);
-        serializer->doDouble(&dimParams->end);
-        serializer->doDouble(&dimParams->period);
-        serializer->doDouble(&dimParams->forceConstant);
-        serializer->doDouble(&dimParams->diffusion);
-        serializer->doDouble(&dimParams->coordValueInit);
-        serializer->doDouble(&dimParams->coverDiameter);
-    }
-}
-
-static void do_awh(gmx::ISerializer* serializer, gmx::AwhParams* awhParams, int gmx_unused file_version)
+static void do_pull(gmx::ISerializer* serializer, pull_params_t* pull, int file_version, PullingAlgorithm ePullOld)
 {
-    serializer->doInt(&awhParams->numBias);
-    serializer->doInt(&awhParams->nstOut);
-    serializer->doInt64(&awhParams->seed);
-    serializer->doInt(&awhParams->nstSampleCoord);
-    serializer->doInt(&awhParams->numSamplesUpdateFreeEnergy);
-    serializer->doInt(&awhParams->ePotential);
-    serializer->doBool(&awhParams->shareBiasMultisim);
-
-    if (awhParams->numBias > 0)
-    {
-        if (serializer->reading())
-        {
-            snew(awhParams->awhBiasParams, awhParams->numBias);
-        }
-
-        for (int k = 0; k < awhParams->numBias; k++)
-        {
-            do_awhBias(serializer, &awhParams->awhBiasParams[k], file_version);
-        }
-    }
-}
-
-static void do_pull(gmx::ISerializer* serializer, pull_params_t* pull, int file_version, int ePullOld)
-{
-    int  eGeomOld = -1;
-    ivec dimOld;
-    int  g;
+    PullGroupGeometry eGeomOld = PullGroupGeometry::Count;
+    ivec              dimOld;
+    int               g;
 
     if (file_version >= 95)
     {
@@ -743,7 +674,7 @@ static void do_pull(gmx::ISerializer* serializer, pull_params_t* pull, int file_
     {
         real dum;
 
-        serializer->doInt(&eGeomOld);
+        serializer->doEnumAsInt(&eGeomOld);
         serializer->doIvec(&dimOld);
         /* The inner cylinder radius, now removed */
         serializer->doReal(&dum);
@@ -787,13 +718,25 @@ static void do_pull(gmx::ISerializer* serializer, pull_params_t* pull, int file_
     if (file_version < 95)
     {
         /* epullgPOS for position pulling, before epullgDIRPBC was removed */
-        if (eGeomOld == epullgDIRPBC)
+        if (eGeomOld == PullGroupGeometry::DirectionPBC)
         {
             gmx_fatal(FARGS, "pull-geometry=position is no longer supported");
         }
-        if (eGeomOld > epullgDIRPBC)
+        if (eGeomOld > PullGroupGeometry::DirectionPBC)
         {
-            eGeomOld -= 1;
+            switch (eGeomOld)
+            {
+                case (PullGroupGeometry::DirectionRelative):
+                    eGeomOld = PullGroupGeometry::DirectionPBC;
+                    break;
+                case (PullGroupGeometry::Angle):
+                    eGeomOld = PullGroupGeometry::DirectionRelative;
+                    break;
+                case (PullGroupGeometry::Dihedral): eGeomOld = PullGroupGeometry::Angle; break;
+                case (PullGroupGeometry::AngleAxis): eGeomOld = PullGroupGeometry::Dihedral; break;
+                case (PullGroupGeometry::Count): eGeomOld = PullGroupGeometry::AngleAxis; break;
+                default: GMX_RELEASE_ASSERT(false, "Unhandled old pull type");
+            }
         }
 
         for (g = 0; g < pull->ngroup; g++)
@@ -818,6 +761,10 @@ static void do_pull(gmx::ISerializer* serializer, pull_params_t* pull, int file_
         for (g = 0; g < pull->ncoord; g++)
         {
             do_pull_coord(serializer, &pull->coord[g], file_version, ePullOld, eGeomOld, dimOld);
+            if (serializer->reading())
+            {
+                pull->coord[g].coordIndex = g;
+            }
         }
     }
     if (file_version >= tpxv_PullAverage)
@@ -836,8 +783,18 @@ static void do_pull(gmx::ISerializer* serializer, pull_params_t* pull, int file_
 
 static void do_rotgrp(gmx::ISerializer* serializer, t_rotgrp* rotg)
 {
-    serializer->doInt(&rotg->eType);
-    serializer->doInt(&rotg->bMassW);
+    serializer->doEnumAsInt(&rotg->eType);
+    if (serializer->reading())
+    {
+        int temp = 0;
+        serializer->doInt(&temp);
+        rotg->bMassW = static_cast<bool>(temp);
+    }
+    else
+    {
+        int temp = static_cast<int>(rotg->bMassW);
+        serializer->doInt(&temp);
+    }
     serializer->doInt(&rotg->nat);
     if (serializer->reading())
     {
@@ -856,7 +813,7 @@ static void do_rotgrp(gmx::ISerializer* serializer, t_rotgrp* rotg)
     serializer->doReal(&rotg->slab_dist);
     serializer->doReal(&rotg->min_gaussian);
     serializer->doReal(&rotg->eps);
-    serializer->doInt(&rotg->eFittype);
+    serializer->doEnumAsInt(&rotg->eFittype);
     serializer->doInt(&rotg->PotAngle_nstep);
     serializer->doReal(&rotg->PotAngle_step);
 }
@@ -906,7 +863,7 @@ static void do_swapgroup(gmx::ISerializer* serializer, t_swapGroup* g)
     serializer->doIntArray(g->ind, g->nat);
 
     /* Requested counts for compartments A and B */
-    serializer->doIntArray(g->nmolReq, eCompNR);
+    serializer->doIntArray(g->nmolReq.data(), static_cast<int>(Compartment::Count));
 }
 
 static void do_swapcoords_tpx(gmx::ISerializer* serializer, t_swapcoords* swap, int file_version)
@@ -958,17 +915,18 @@ static void do_swapcoords_tpx(gmx::ISerializer* serializer, t_swapcoords* swap,
         swap->ngrp = 5;
         snew(swap->grp, swap->ngrp);
 
-        swap->grp[eGrpSplit0].molname  = gmx_strdup("split0");  // group 0: split0
-        swap->grp[eGrpSplit1].molname  = gmx_strdup("split1");  // group 1: split1
-        swap->grp[eGrpSolvent].molname = gmx_strdup("solvent"); // group 2: solvent
-        swap->grp[3].molname           = gmx_strdup("anions");  // group 3: anions
-        swap->grp[4].molname           = gmx_strdup("cations"); // group 4: cations
+        swap->grp[static_cast<int>(SwapGroupSplittingType::Split0)].molname = gmx_strdup("split0"); // group 0: split0
+        swap->grp[static_cast<int>(SwapGroupSplittingType::Split1)].molname = gmx_strdup("split1"); // group 1: split1
+        swap->grp[static_cast<int>(SwapGroupSplittingType::Solvent)].molname =
+                gmx_strdup("solvent");                // group 2: solvent
+        swap->grp[3].molname = gmx_strdup("anions");  // group 3: anions
+        swap->grp[4].molname = gmx_strdup("cations"); // group 4: cations
 
         serializer->doInt(&swap->grp[3].nat);
-        serializer->doInt(&swap->grp[eGrpSolvent].nat);
-        serializer->doInt(&swap->grp[eGrpSplit0].nat);
+        serializer->doInt(&swap->grp[static_cast<int>(SwapGroupSplittingType::Solvent)].nat);
+        serializer->doInt(&swap->grp[static_cast<int>(SwapGroupSplittingType::Split0)].nat);
         serializer->doBool(&swap->massw_split[eChannel0]);
-        serializer->doInt(&swap->grp[eGrpSplit1].nat);
+        serializer->doInt(&swap->grp[static_cast<int>(SwapGroupSplittingType::Split1)].nat);
         serializer->doBool(&swap->massw_split[eChannel1]);
         serializer->doInt(&swap->nstswap);
         serializer->doInt(&swap->nAverage);
@@ -983,7 +941,10 @@ static void do_swapcoords_tpx(gmx::ISerializer* serializer, t_swapcoords* swap,
         // The order[] array keeps compatibility with older .tpr files
         // by reading in the groups in the classic order
         {
-            const int order[4] = { 3, eGrpSolvent, eGrpSplit0, eGrpSplit1 };
+            const int order[4] = { 3,
+                                   static_cast<int>(SwapGroupSplittingType::Solvent),
+                                   static_cast<int>(SwapGroupSplittingType::Split0),
+                                   static_cast<int>(SwapGroupSplittingType::Split1) };
 
             for (int ig = 0; ig < 4; ig++)
             {
@@ -1065,7 +1026,7 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     gmx::KeyValueTreeObjectBuilder paramsObj = paramsBuilder.rootObject();
 
     /* Basic inputrec stuff */
-    serializer->doInt(&ir->eI);
+    serializer->doEnumAsInt(&ir->eI);
     if (file_version >= 62)
     {
         serializer->doInt64(&ir->nsteps);
@@ -1121,15 +1082,21 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     }
     if (file_version >= 81)
     {
-        serializer->doInt(&ir->cutoff_scheme);
+        serializer->doEnumAsInt(&ir->cutoff_scheme);
         if (file_version < 94)
         {
-            ir->cutoff_scheme = 1 - ir->cutoff_scheme;
+            // Need to invert the scheme order
+            switch (ir->cutoff_scheme)
+            {
+                case (CutoffScheme::Group): ir->cutoff_scheme = CutoffScheme::Verlet; break;
+                case (CutoffScheme::Verlet): ir->cutoff_scheme = CutoffScheme::Group; break;
+                default: GMX_RELEASE_ASSERT(false, "Unhandled cutoff scheme type");
+            }
         }
     }
     else
     {
-        ir->cutoff_scheme = ecutsGROUP;
+        ir->cutoff_scheme = CutoffScheme::Group;
     }
     serializer->doInt(&idum); /* used to be ns_type; not used anymore */
     serializer->doInt(&ir->nstlist);
@@ -1138,7 +1105,7 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     serializer->doReal(&ir->rtpi);
 
     serializer->doInt(&ir->nstcomm);
-    serializer->doInt(&ir->comm_mode);
+    serializer->doEnumAsInt(&ir->comm_mode);
 
     /* ignore nstcheckpoint */
     if (file_version < tpxv_RemoveObsoleteParameters1)
@@ -1210,29 +1177,31 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
         int dummy_nstcalclr = -1;
         serializer->doInt(&dummy_nstcalclr);
     }
-    serializer->doInt(&ir->coulombtype);
+    serializer->doEnumAsInt(&ir->coulombtype);
     if (file_version >= 81)
     {
-        serializer->doInt(&ir->coulomb_modifier);
+        serializer->doEnumAsInt(&ir->coulomb_modifier);
     }
     else
     {
-        ir->coulomb_modifier = (ir->cutoff_scheme == ecutsVERLET ? eintmodPOTSHIFT : eintmodNONE);
+        ir->coulomb_modifier = (ir->cutoff_scheme == CutoffScheme::Verlet ? InteractionModifiers::PotShift
+                                                                          : InteractionModifiers::None);
     }
     serializer->doReal(&ir->rcoulomb_switch);
     serializer->doReal(&ir->rcoulomb);
-    serializer->doInt(&ir->vdwtype);
+    serializer->doEnumAsInt(&ir->vdwtype);
     if (file_version >= 81)
     {
-        serializer->doInt(&ir->vdw_modifier);
+        serializer->doEnumAsInt(&ir->vdw_modifier);
     }
     else
     {
-        ir->vdw_modifier = (ir->cutoff_scheme == ecutsVERLET ? eintmodPOTSHIFT : eintmodNONE);
+        ir->vdw_modifier = (ir->cutoff_scheme == CutoffScheme::Verlet ? InteractionModifiers::PotShift
+                                                                      : InteractionModifiers::None);
     }
     serializer->doReal(&ir->rvdw_switch);
     serializer->doReal(&ir->rvdw);
-    serializer->doInt(&ir->eDispCorr);
+    serializer->doEnumAsInt(&ir->eDispCorr);
     serializer->doReal(&ir->epsilon_r);
     serializer->doReal(&ir->epsilon_rf);
     serializer->doReal(&ir->tabext);
@@ -1291,7 +1260,7 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     {
         ir->ewald_rtol_lj = ir->ewald_rtol;
     }
-    serializer->doInt(&ir->ewald_geometry);
+    serializer->doEnumAsInt(&ir->ewald_geometry);
     serializer->doReal(&ir->epsilon_surface);
 
     /* ignore bOptFFT */
@@ -1302,10 +1271,10 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
 
     if (file_version >= 93)
     {
-        serializer->doInt(&ir->ljpme_combination_rule);
+        serializer->doEnumAsInt(&ir->ljpme_combination_rule);
     }
     serializer->doBool(&ir->bContinuation);
-    serializer->doInt(&ir->etc);
+    serializer->doEnumAsInt(&ir->etc);
     /* before version 18, ir->etc was a gmx_bool (ir->btc),
      * but the values 0 and 1 still mean no and
      * berendsen temperature coupling, respectively.
@@ -1322,8 +1291,8 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     {
         ir->nsttcouple = ir->nstcalcenergy;
     }
-    serializer->doInt(&ir->epc);
-    serializer->doInt(&ir->epct);
+    serializer->doEnumAsInt(&ir->epc);
+    serializer->doEnumAsInt(&ir->epct);
     if (file_version >= 71)
     {
         serializer->doInt(&ir->nstpcouple);
@@ -1339,7 +1308,7 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     serializer->doRvec(&ir->compress[XX]);
     serializer->doRvec(&ir->compress[YY]);
     serializer->doRvec(&ir->compress[ZZ]);
-    serializer->doInt(&ir->refcoord_scaling);
+    serializer->doEnumAsInt(&ir->refcoord_scaling);
     serializer->doRvec(&ir->posres_com);
     serializer->doRvec(&ir->posres_comB);
 
@@ -1354,8 +1323,12 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
 
     serializer->doReal(&ir->shake_tol);
 
-    serializer->doInt(&ir->efep);
-    do_fepvals(serializer, ir->fepvals, file_version);
+    serializer->doEnumAsInt(&ir->efep);
+    if (serializer->reading())
+    {
+        ir->fepvals = std::make_unique<t_lambda>();
+    }
+    do_fepvals(serializer, ir->fepvals.get(), file_version);
 
     if (file_version >= 79)
     {
@@ -1371,7 +1344,11 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     }
     if (ir->bSimTemp)
     {
-        do_simtempvals(serializer, ir->simtempvals, ir->fepvals->n_lambda, file_version);
+        if (serializer->reading())
+        {
+            ir->simtempvals = std::make_unique<t_simtemp>();
+        }
+        do_simtempvals(serializer, ir->simtempvals.get(), ir->fepvals->n_lambda, file_version);
     }
 
     if (file_version >= 79)
@@ -1380,11 +1357,15 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     }
     if (ir->bExpanded)
     {
-        do_expandedvals(serializer, ir->expandedvals, ir->fepvals, file_version);
+        if (serializer->reading())
+        {
+            ir->expandedvals = std::make_unique<t_expanded>();
+        }
+        do_expandedvals(serializer, ir->expandedvals.get(), ir->fepvals.get(), file_version);
     }
 
-    serializer->doInt(&ir->eDisre);
-    serializer->doInt(&ir->eDisreWeighting);
+    serializer->doEnumAsInt(&ir->eDisre);
+    serializer->doEnumAsInt(&ir->eDisreWeighting);
     serializer->doBool(&ir->bDisreMixed);
     serializer->doReal(&ir->dr_fc);
     serializer->doReal(&ir->dr_tau);
@@ -1404,7 +1385,7 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     serializer->doBool(&ir->bShakeSOR);
     serializer->doInt(&ir->niter);
     serializer->doReal(&ir->fc_stepsize);
-    serializer->doInt(&ir->eConstrAlg);
+    serializer->doEnumAsInt(&ir->eConstrAlg);
     serializer->doInt(&ir->nProjOrder);
     serializer->doReal(&ir->LincsWarnAngle);
     serializer->doInt(&ir->nLincsIter);
@@ -1475,7 +1456,7 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
 
     /* pull stuff */
     {
-        int ePullOld = 0;
+        PullingAlgorithm ePullOld = PullingAlgorithm::Umbrella;
 
         if (file_version >= tpxv_PullCoordTypeGeom)
         {
@@ -1483,10 +1464,28 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
         }
         else
         {
-            serializer->doInt(&ePullOld);
-            ir->bPull = (ePullOld > 0);
+            serializer->doEnumAsInt(&ePullOld);
+            ir->bPull = (ePullOld != PullingAlgorithm::Umbrella);
             /* We removed the first ePull=ePullNo for the enum */
-            ePullOld -= 1;
+            switch (ePullOld)
+            {
+                case (PullingAlgorithm::Umbrella): break; // this is equal to not using pulling
+                case (PullingAlgorithm::Constraint): ePullOld = PullingAlgorithm::Umbrella; break;
+                case (PullingAlgorithm::ConstantForce):
+                    ePullOld = PullingAlgorithm::Constraint;
+                    break;
+                case (PullingAlgorithm::FlatBottom):
+                    ePullOld = PullingAlgorithm::ConstantForce;
+                    break;
+                case (PullingAlgorithm::FlatBottomHigh):
+                    ePullOld = PullingAlgorithm::FlatBottom;
+                    break;
+                case (PullingAlgorithm::External):
+                    ePullOld = PullingAlgorithm::FlatBottomHigh;
+                    break;
+                case (PullingAlgorithm::Count): ePullOld = PullingAlgorithm::External; break;
+                default: GMX_RELEASE_ASSERT(false, "Unhandled old pull algorithm");
+            }
         }
         if (ir->bPull)
         {
@@ -1506,9 +1505,12 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
         {
             if (serializer->reading())
             {
-                snew(ir->awhParams, 1);
+                ir->awhParams = std::make_unique<gmx::AwhParams>(serializer);
+            }
+            else
+            {
+                ir->awhParams->serialize(serializer);
             }
-            do_awh(serializer, ir->awhParams, file_version);
         }
     }
     else
@@ -1563,7 +1565,11 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     {
         ir->opts.nhchainlength = 1;
     }
-    serializer->doInt(&ir->opts.ngacc);
+    int removedOptsNgacc = 0;
+    if (serializer->reading() && file_version < tpxv_RemovedConstantAcceleration)
+    {
+        serializer->doInt(&removedOptsNgacc);
+    }
     serializer->doInt(&ir->opts.ngfrz);
     serializer->doInt(&ir->opts.ngener);
 
@@ -1577,7 +1583,6 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
         snew(ir->opts.anneal_temp, ir->opts.ngtc);
         snew(ir->opts.tau_t, ir->opts.ngtc);
         snew(ir->opts.nFreeze, ir->opts.ngfrz);
-        snew(ir->opts.acc, ir->opts.ngacc);
         snew(ir->opts.egp_flags, ir->opts.ngener * ir->opts.ngener);
     }
     if (ir->opts.ngtc > 0)
@@ -1590,14 +1595,23 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     {
         serializer->doIvecArray(ir->opts.nFreeze, ir->opts.ngfrz);
     }
-    if (ir->opts.ngacc > 0)
+    if (serializer->reading() && file_version < tpxv_RemovedConstantAcceleration && removedOptsNgacc > 0)
+    {
+        std::vector<gmx::RVec> dummy;
+        dummy.resize(removedOptsNgacc);
+        serializer->doRvecArray(reinterpret_cast<rvec*>(dummy.data()), removedOptsNgacc);
+        ir->useConstantAcceleration = std::any_of(dummy.begin(), dummy.end(), [](const gmx::RVec& vec) {
+            return vec[XX] != 0.0 || vec[YY] != 0.0 || vec[ZZ] != 0.0;
+        });
+    }
+    else
     {
-        serializer->doRvecArray(ir->opts.acc, ir->opts.ngacc);
+        ir->useConstantAcceleration = false;
     }
     serializer->doIntArray(ir->opts.egp_flags, ir->opts.ngener * ir->opts.ngener);
 
     /* First read the lists with annealing and npoints for each group */
-    serializer->doIntArray(ir->opts.annealing, ir->opts.ngtc);
+    serializer->doEnumArrayAsInt(ir->opts.annealing, ir->opts.ngtc);
     serializer->doIntArray(ir->opts.anneal_npoints, ir->opts.ngtc);
     for (j = 0; j < (ir->opts.ngtc); j++)
     {
@@ -1613,7 +1627,7 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     /* Walls */
     {
         serializer->doInt(&ir->nwall);
-        serializer->doInt(&ir->wall_type);
+        serializer->doEnumAsInt(&ir->wall_type);
         serializer->doReal(&ir->wall_r_linpot);
         serializer->doInt(&ir->wall_atomtype[0]);
         serializer->doInt(&ir->wall_atomtype[1]);
@@ -1631,8 +1645,8 @@ static void do_inputrec(gmx::ISerializer* serializer, t_inputrec* ir, int file_v
     /* Swap ions */
     if (file_version >= tpxv_ComputationalElectrophysiology)
     {
-        serializer->doInt(&ir->eSwapCoords);
-        if (ir->eSwapCoords != eswapNO)
+        serializer->doEnumAsInt(&ir->eSwapCoords);
+        if (ir->eSwapCoords != SwapType::No)
         {
             if (serializer->reading())
             {
@@ -2019,8 +2033,12 @@ static void do_iparams(gmx::ISerializer* serializer, t_functype ftype, t_iparams
             serializer->doInt(&iparams->cmap.cmapB);
             break;
         default:
-            gmx_fatal(FARGS, "unknown function type %d (%s) in %s line %d", ftype,
-                      interaction_function[ftype].name, __FILE__, __LINE__);
+            gmx_fatal(FARGS,
+                      "unknown function type %d (%s) in %s line %d",
+                      ftype,
+                      interaction_function[ftype].name,
+                      __FILE__,
+                      __LINE__);
     }
 }
 
@@ -2216,7 +2234,7 @@ static void do_atom(gmx::ISerializer* serializer, t_atom* atom)
     serializer->doReal(&atom->qB);
     serializer->doUShort(&atom->type);
     serializer->doUShort(&atom->typeB);
-    serializer->doInt(&atom->ptype);
+    serializer->doEnumAsInt(&atom->ptype);
     serializer->doInt(&atom->resind);
     serializer->doInt(&atom->atomnumber);
     if (serializer->reading())
@@ -2515,15 +2533,11 @@ static void do_molblock(gmx::ISerializer* serializer, gmx_molblock_t* molb, int
 
 static void set_disres_npair(gmx_mtop_t* mtop)
 {
-    gmx_mtop_ilistloop_t iloop;
-    int                  nmol;
-
     gmx::ArrayRef<t_iparams> ip = mtop->ffparams.iparams;
 
-    iloop = gmx_mtop_ilistloop_init(mtop);
-    while (const InteractionLists* ilist = gmx_mtop_ilistloop_next(iloop, &nmol))
+    for (const auto ilist : IListRange(*mtop))
     {
-        const InteractionList& il = (*ilist)[F_DISRES];
+        const InteractionList& il = ilist.list()[F_DISRES];
 
         if (!il.empty())
         {
@@ -2604,6 +2618,11 @@ static void do_mtop(gmx::ISerializer* serializer, gmx_mtop_t* mtop, int file_ver
     }
 
     do_groups(serializer, &mtop->groups, &(mtop->symtab));
+    if (file_version < tpxv_RemovedConstantAcceleration)
+    {
+        mtop->groups.groups[SimulationAtomGroupType::AccelerationUnused].clear();
+        mtop->groups.groupNumbers[SimulationAtomGroupType::AccelerationUnused].clear();
+    }
 
     mtop->haveMoleculeIndices = true;
 
@@ -2682,10 +2701,16 @@ static void do_tpxheader(gmx::FileIOXdrSerializer* serializer,
             gmx_fatal(FARGS,
                       "Unknown precision in file %s: real is %d bytes "
                       "instead of %zu or %zu",
-                      filename, precision, sizeof(float), sizeof(double));
+                      filename,
+                      precision,
+                      sizeof(float),
+                      sizeof(double));
         }
         gmx_fio_setprecision(fio, tpx->isDouble);
-        fprintf(stderr, "Reading file %s, %s (%s precision)\n", filename, buf.c_str(),
+        fprintf(stderr,
+                "Reading file %s, %s (%s precision)\n",
+                filename,
+                buf.c_str(),
                 tpx->isDouble ? "double" : "single");
     }
     else
@@ -2694,7 +2719,7 @@ static void do_tpxheader(gmx::FileIOXdrSerializer* serializer,
         serializer->doString(&buf);
         gmx_fio_setprecision(fio, tpx->isDouble);
         serializer->doInt(&precision);
-        fileTag = gmx::formatString("%s", tpx_tag);
+        fileTag = tpx_tag;
     }
 
     /* Check versions! */
@@ -2726,7 +2751,7 @@ static void do_tpxheader(gmx::FileIOXdrSerializer* serializer,
 
         if (fileTag != tpx_tag)
         {
-            fprintf(stderr, "Note: file tpx tag '%s', software tpx tag '%s'\n", fileTag.c_str(), tpx_tag);
+            fprintf(stderr, "Note: file tpx tag '%s', software tpx tag '%s'\n", fileTag.c_str(), tpx_tag.c_str());
 
             /* We only support reading tpx files with the same tag as the code
              * or tpx files with the release tag and with lower version number.
@@ -2736,7 +2761,11 @@ static void do_tpxheader(gmx::FileIOXdrSerializer* serializer,
                 gmx_fatal(FARGS,
                           "tpx tag/version mismatch: reading tpx file (%s) version %d, tag '%s' "
                           "with program for tpx version %d, tag '%s'",
-                          filename, tpx->fileVersion, fileTag.c_str(), tpx_version, tpx_tag);
+                          filename,
+                          tpx->fileVersion,
+                          fileTag.c_str(),
+                          tpx_version,
+                          tpx_tag.c_str());
             }
         }
     }
@@ -2745,8 +2774,11 @@ static void do_tpxheader(gmx::FileIOXdrSerializer* serializer,
         || ((tpx->fileVersion > tpx_version) && !TopOnlyOK) || (tpx->fileGeneration > tpx_generation)
         || tpx_version == 80) /*80 was used by both 5.0-dev and 4.6-dev*/
     {
-        gmx_fatal(FARGS, "reading tpx file (%s) version %d with version %d program", filename,
-                  tpx->fileVersion, tpx_version);
+        gmx_fatal(FARGS,
+                  "reading tpx file (%s) version %d with version %d program",
+                  filename,
+                  tpx->fileVersion,
+                  tpx_version);
     }
 
     serializer->doInt(&tpx->natoms);
@@ -2912,11 +2944,11 @@ static void do_tpx_state_second(gmx::ISerializer* serializer, TpxFileHeader* tpx
             // of the tpx file.
             if (tpx->bX)
             {
-                state->flags |= (1 << estX);
+                state->flags |= enumValueToBitMask(StateEntry::X);
             }
             if (tpx->bV)
             {
-                state->flags |= (1 << estV);
+                state->flags |= enumValueToBitMask(StateEntry::V);
             }
             state_change_natoms(state, tpx->natoms);
         }
@@ -2932,7 +2964,7 @@ static void do_tpx_state_second(gmx::ISerializer* serializer, TpxFileHeader* tpx
     {
         if (serializer->reading())
         {
-            state->flags |= (1 << estX);
+            state->flags |= enumValueToBitMask(StateEntry::X);
         }
         serializer->doRvecArray(x, tpx->natoms);
     }
@@ -2942,7 +2974,7 @@ static void do_tpx_state_second(gmx::ISerializer* serializer, TpxFileHeader* tpx
     {
         if (serializer->reading())
         {
-            state->flags |= (1 << estV);
+            state->flags |= enumValueToBitMask(StateEntry::V);
         }
         if (!v)
         {
@@ -3050,14 +3082,9 @@ static void do_tpx_finalize(TpxFileHeader* tpx, t_inputrec* ir, t_state* state,
         {
             if (tpx->fileVersion < 57)
             {
-                if (!mtop->moltype[0].ilist[F_DISRES].empty())
-                {
-                    ir->eDisre = edrSimple;
-                }
-                else
-                {
-                    ir->eDisre = edrNone;
-                }
+                ir->eDisre = !mtop->moltype[0].ilist[F_DISRES].empty()
+                                     ? DistanceRestraintRefinement::Simple
+                                     : DistanceRestraintRefinement::None;
             }
         }
     }
@@ -3148,11 +3175,11 @@ static TpxFileHeader populateTpxHeader(const t_state& state, const t_inputrec* i
     header.natoms         = state.natoms;
     header.ngtc           = state.ngtc;
     header.fep_state      = state.fep_state;
-    header.lambda         = state.lambda[efptFEP];
+    header.lambda         = state.lambda[FreeEnergyPerturbationCouplingType::Fep];
     header.bIr            = ir != nullptr;
     header.bTop           = mtop != nullptr;
-    header.bX             = (state.flags & (1 << estX)) != 0;
-    header.bV             = (state.flags & (1 << estV)) != 0;
+    header.bX             = (state.flags & enumValueToBitMask(StateEntry::X)) != 0;
+    header.bV             = (state.flags & enumValueToBitMask(StateEntry::V)) != 0;
     header.bF             = false;
     header.bBox           = true;
     header.fileVersion    = tpx_version;
@@ -3264,7 +3291,7 @@ TpxFileHeader readTpxHeader(const char* fileName, bool canReadTopologyOnly)
     return tpx;
 }
 
-void write_tpx_state(const char* fn, const t_inputrec* ir, const t_state* state, const gmx_mtop_t* mtop)
+void write_tpx_state(const char* fn, const t_inputrec* ir, const t_state* state, const gmx_mtop_t& mtop)
 {
     /* To write a state, we first need to write the state information to a buffer before
      * we append the raw bytes to the file. For this, the header information needs to be
@@ -3274,7 +3301,7 @@ void write_tpx_state(const char* fn, const t_inputrec* ir, const t_state* state,
 
     t_fileio* fio;
 
-    TpxFileHeader tpx = populateTpxHeader(*state, ir, mtop);
+    TpxFileHeader tpx = populateTpxHeader(*state, ir, &mtop);
     // Long-term we should move to use little endian in files to avoid extra byte swapping,
     // but since we just used the default XDR format (which is big endian) for the TPR
     // header it would cause third-party libraries reading our raw data to tear their hair
@@ -3282,8 +3309,13 @@ void write_tpx_state(const char* fn, const t_inputrec* ir, const t_state* state,
     // TPR file for now - and thus we ask the serializer to swap if this host is little endian.
     gmx::InMemorySerializer tprBodySerializer(gmx::EndianSwapBehavior::SwapIfHostIsLittleEndian);
 
-    do_tpx_body(&tprBodySerializer, &tpx, const_cast<t_inputrec*>(ir), const_cast<t_state*>(state),
-                nullptr, nullptr, const_cast<gmx_mtop_t*>(mtop));
+    do_tpx_body(&tprBodySerializer,
+                &tpx,
+                const_cast<t_inputrec*>(ir),
+                const_cast<t_state*>(state),
+                nullptr,
+                nullptr,
+                const_cast<gmx_mtop_t*>(&mtop));
 
     std::vector<char> tprBody = tprBodySerializer.finishAndGetBuffer();
     tpx.sizeOfTprBody         = tprBody.size();
index e9f227e4caa654c0f30b603de59628505c8e8f95..e1cdadd30bea253ac559a083fc936cb716bc7a98 100644 (file)
@@ -295,8 +295,16 @@ void gmx_trr_write_single_frame(const char* fn,
                                 const rvec* f)
 {
     t_fileio* fio = gmx_trr_open(fn, "w");
-    do_trr_frame(fio, false, &step, &t, &lambda, const_cast<rvec*>(box), &natoms,
-                 const_cast<rvec*>(x), const_cast<rvec*>(v), const_cast<rvec*>(f));
+    do_trr_frame(fio,
+                 false,
+                 &step,
+                 &t,
+                 &lambda,
+                 const_cast<rvec*>(box),
+                 &natoms,
+                 const_cast<rvec*>(x),
+                 const_cast<rvec*>(v),
+                 const_cast<rvec*>(f));
     gmx_trr_close(fio);
 }
 
@@ -325,8 +333,16 @@ void gmx_trr_write_frame(t_fileio*   fio,
                          const rvec* v,
                          const rvec* f)
 {
-    if (!do_trr_frame(fio, false, &step, &t, &lambda, const_cast<rvec*>(box), &natoms,
-                      const_cast<rvec*>(x), const_cast<rvec*>(v), const_cast<rvec*>(f)))
+    if (!do_trr_frame(fio,
+                      false,
+                      &step,
+                      &t,
+                      &lambda,
+                      const_cast<rvec*>(box),
+                      &natoms,
+                      const_cast<rvec*>(x),
+                      const_cast<rvec*>(v),
+                      const_cast<rvec*>(f)))
     {
         gmx_file("Cannot write trajectory frame; maybe you are out of disk space?");
     }
index b1f3a82014f34fe862d64fd769e5beba5d337688..e731f427718f85868ce62697acd0fc9567b0e078 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +37,7 @@
  */
 #include "gmxpre.h"
 
-#include "trxio.h"
+#include "gromacs/fileio/trxio.h"
 
 #include "config.h"
 
@@ -83,7 +83,7 @@
 struct t_trxstatus
 {
     int  flags; /* flags for read_first/next_frame  */
-    int  __frame;
+    int  currentFrame;
     real t0;                 /* time of the first frame, needed  *
                               * for skipping frames with -dt     */
     real                 tf; /* internal frame time              */
@@ -124,9 +124,10 @@ int check_times2(real t, real t0, gmx_bool bDouble)
 #endif
 
     r = -1;
-    if ((!bTimeSet(TBEGIN) || (t >= rTimeValue(TBEGIN))) && (!bTimeSet(TEND) || (t <= rTimeValue(TEND))))
+    if ((!bTimeSet(TimeControl::Begin) || (t >= rTimeValue(TimeControl::Begin)))
+        && (!bTimeSet(TimeControl::End) || (t <= rTimeValue(TimeControl::End))))
     {
-        if (bTimeSet(TDELTA) && !bRmod_fd(t, t0, rTimeValue(TDELTA), bDouble))
+        if (bTimeSet(TimeControl::Delta) && !bRmod_fd(t, t0, rTimeValue(TimeControl::Delta), bDouble))
         {
             r = -1;
         }
@@ -135,14 +136,20 @@ int check_times2(real t, real t0, gmx_bool bDouble)
             r = 0;
         }
     }
-    else if (bTimeSet(TEND) && (t >= rTimeValue(TEND)))
+    else if (bTimeSet(TimeControl::End) && (t >= rTimeValue(TimeControl::End)))
     {
         r = 1;
     }
     if (debug)
     {
-        fprintf(debug, "t=%g, t0=%g, b=%g, e=%g, dt=%g: r=%d\n", t, t0, rTimeValue(TBEGIN),
-                rTimeValue(TEND), rTimeValue(TDELTA), r);
+        fprintf(debug,
+                "t=%g, t0=%g, b=%g, e=%g, dt=%g: r=%d\n",
+                t,
+                t0,
+                rTimeValue(TimeControl::Begin),
+                rTimeValue(TimeControl::End),
+                rTimeValue(TimeControl::Delta),
+                r);
     }
     return r;
 }
@@ -154,7 +161,7 @@ int check_times(real t)
 
 static void initcount(t_trxstatus* status)
 {
-    status->__frame = -1;
+    status->currentFrame = -1;
 }
 
 static void status_init(t_trxstatus* status)
@@ -162,7 +169,7 @@ static void status_init(t_trxstatus* status)
     status->flags           = 0;
     status->xframe          = nullptr;
     status->fio             = nullptr;
-    status->__frame         = -1;
+    status->currentFrame    = -1;
     status->t0              = 0;
     status->tf              = 0;
     status->persistent_line = nullptr;
@@ -172,24 +179,24 @@ static void status_init(t_trxstatus* status)
 
 int nframes_read(t_trxstatus* status)
 {
-    return status->__frame;
+    return status->currentFrame;
 }
 
 static void printcount_(t_trxstatus* status, const gmx_output_env_t* oenv, const char* l, real t)
 {
-    if ((status->__frame < 2 * SKIP1 || status->__frame % SKIP1 == 0)
-        && (status->__frame < 2 * SKIP2 || status->__frame % SKIP2 == 0)
-        && (status->__frame < 2 * SKIP3 || status->__frame % SKIP3 == 0)
+    if ((status->currentFrame < 2 * SKIP1 || status->currentFrame % SKIP1 == 0)
+        && (status->currentFrame < 2 * SKIP2 || status->currentFrame % SKIP2 == 0)
+        && (status->currentFrame < 2 * SKIP3 || status->currentFrame % SKIP3 == 0)
         && output_env_get_trajectory_io_verbosity(oenv) != 0)
     {
-        fprintf(stderr, "\r%-14s %6d time %8.3f   ", l, status->__frame, output_env_conv_time(oenv, t));
+        fprintf(stderr, "\r%-14s %6d time %8.3f   ", l, status->currentFrame, output_env_conv_time(oenv, t));
         fflush(stderr);
     }
 }
 
 static void printcount(t_trxstatus* status, const gmx_output_env_t* oenv, real t, gmx_bool bSkip)
 {
-    status->__frame++;
+    status->currentFrame++;
     printcount_(status, oenv, bSkip ? "Skipping frame" : "Reading frame", t);
 }
 
@@ -204,11 +211,11 @@ static void printincomp(t_trxstatus* status, t_trxframe* fr)
 {
     if (fr->not_ok & HEADER_NOT_OK)
     {
-        fprintf(stderr, "WARNING: Incomplete header: nr %d time %g\n", status->__frame + 1, fr->time);
+        fprintf(stderr, "WARNING: Incomplete header: nr %d time %g\n", status->currentFrame + 1, fr->time);
     }
     else if (fr->not_ok)
     {
-        fprintf(stderr, "WARNING: Incomplete frame: nr %d time %g\n", status->__frame + 1, fr->time);
+        fprintf(stderr, "WARNING: Incomplete frame: nr %d time %g\n", status->currentFrame + 1, fr->time);
     }
     fflush(stderr);
 }
@@ -242,8 +249,8 @@ float trx_get_time_of_final_frame(t_trxstatus* status)
 
     if (filetype == efXTC)
     {
-        lasttime = xdr_xtc_get_last_frame_time(gmx_fio_getfp(stfio), gmx_fio_getxdr(stfio),
-                                               status->natoms, &bOK);
+        lasttime = xdr_xtc_get_last_frame_time(
+                gmx_fio_getfp(stfio), gmx_fio_getxdr(stfio), status->natoms, &bOK);
         if (!bOK)
         {
             gmx_fatal(FARGS, "Error reading last frame. Maybe seek not supported.");
@@ -391,8 +398,8 @@ int write_trxframe_indexed(t_trxstatus* status, const t_trxframe* fr, int nind,
         case efTNG: gmx_write_tng_from_trxframe(status->tng, fr, nind); break;
         case efXTC: write_xtc(status->fio, nind, fr->step, fr->time, fr->box, xout, prec); break;
         case efTRR:
-            gmx_trr_write_frame(status->fio, nframes_read(status), fr->time, fr->step, fr->box,
-                                nind, xout, vout, fout);
+            gmx_trr_write_frame(
+                    status->fio, nframes_read(status), fr->time, fr->step, fr->box, nind, xout, vout, fout);
             break;
         case efGRO:
         case efPDB:
@@ -405,13 +412,29 @@ int write_trxframe_indexed(t_trxstatus* status, const t_trxframe* fr, int nind,
             sprintf(title, "frame t= %.3f", fr->time);
             if (ftp == efGRO)
             {
-                write_hconf_indexed_p(gmx_fio_getfp(status->fio), title, fr->atoms, nind, ind,
-                                      fr->x, fr->bV ? fr->v : nullptr, fr->box);
+                write_hconf_indexed_p(gmx_fio_getfp(status->fio),
+                                      title,
+                                      fr->atoms,
+                                      nind,
+                                      ind,
+                                      fr->x,
+                                      fr->bV ? fr->v : nullptr,
+                                      fr->box);
             }
             else
             {
-                write_pdbfile_indexed(gmx_fio_getfp(status->fio), title, fr->atoms, fr->x,
-                                      PbcType::Unset, fr->box, ' ', fr->step, nind, ind, gc, FALSE);
+                write_pdbfile_indexed(gmx_fio_getfp(status->fio),
+                                      title,
+                                      fr->atoms,
+                                      fr->x,
+                                      PbcType::Unset,
+                                      fr->box,
+                                      ' ',
+                                      fr->step,
+                                      nind,
+                                      ind,
+                                      gc,
+                                      FALSE);
             }
             break;
         case efG96:
@@ -461,23 +484,23 @@ t_trxstatus* trjtools_gmx_prepare_tng_writing(const char*              filename,
 
     if (in != nullptr)
     {
-        gmx_prepare_tng_writing(filename, filemode, &in->tng, &out->tng, natoms, mtop, index,
-                                index_group_name);
+        gmx_prepare_tng_writing(
+                filename, filemode, &in->tng, &out->tng, natoms, mtop, index, index_group_name);
     }
     else if ((infile) && (efTNG == fn2ftp(infile)))
     {
         gmx_tng_trajectory_t tng_in;
         gmx_tng_open(infile, 'r', &tng_in);
 
-        gmx_prepare_tng_writing(filename, filemode, &tng_in, &out->tng, natoms, mtop, index,
-                                index_group_name);
+        gmx_prepare_tng_writing(
+                filename, filemode, &tng_in, &out->tng, natoms, mtop, index, index_group_name);
     }
     else
     {
         // we start from a file that is not a tng file or have been unable to load the
         // input file, so we need to populate the fields independently of it
-        gmx_prepare_tng_writing(filename, filemode, nullptr, &out->tng, natoms, mtop, index,
-                                index_group_name);
+        gmx_prepare_tng_writing(
+                filename, filemode, nullptr, &out->tng, natoms, mtop, index, index_group_name);
     }
     return out;
 }
@@ -516,7 +539,8 @@ int write_trxframe(t_trxstatus* status, t_trxframe* fr, gmx_conect gc)
         default:
             if (!fr->bX)
             {
-                gmx_fatal(FARGS, "Need coordinates to write a %s trajectory",
+                gmx_fatal(FARGS,
+                          "Need coordinates to write a %s trajectory",
                           ftp2ext(gmx_fio_getftp(status->fio)));
             }
             break;
@@ -528,8 +552,14 @@ int write_trxframe(t_trxstatus* status, t_trxframe* fr, gmx_conect gc)
             write_xtc(status->fio, fr->natoms, fr->step, fr->time, fr->box, fr->x, prec);
             break;
         case efTRR:
-            gmx_trr_write_frame(status->fio, fr->step, fr->time, fr->lambda, fr->box, fr->natoms,
-                                fr->bX ? fr->x : nullptr, fr->bV ? fr->v : nullptr,
+            gmx_trr_write_frame(status->fio,
+                                fr->step,
+                                fr->time,
+                                fr->lambda,
+                                fr->box,
+                                fr->natoms,
+                                fr->bX ? fr->x : nullptr,
+                                fr->bV ? fr->v : nullptr,
                                 fr->bF ? fr->f : nullptr);
             break;
         case efGRO:
@@ -538,25 +568,32 @@ int write_trxframe(t_trxstatus* status, t_trxframe* fr, gmx_conect gc)
         case efENT:
             if (!fr->bAtoms)
             {
-                gmx_fatal(FARGS, "Can not write a %s file without atom names",
+                gmx_fatal(FARGS,
+                          "Can not write a %s file without atom names",
                           ftp2ext(gmx_fio_getftp(status->fio)));
             }
             sprintf(title, "frame t= %.3f", fr->time);
             if (gmx_fio_getftp(status->fio) == efGRO)
             {
-                write_hconf_p(gmx_fio_getfp(status->fio), title, fr->atoms, fr->x,
-                              fr->bV ? fr->v : nullptr, fr->box);
+                write_hconf_p(
+                        gmx_fio_getfp(status->fio), title, fr->atoms, fr->x, fr->bV ? fr->v : nullptr, fr->box);
             }
             else
             {
-                write_pdbfile(gmx_fio_getfp(status->fio), title, fr->atoms, fr->x,
-                              fr->bPBC ? fr->pbcType : PbcType::Unset, fr->box, ' ', fr->step, gc);
+                write_pdbfile(gmx_fio_getfp(status->fio),
+                              title,
+                              fr->atoms,
+                              fr->x,
+                              fr->bPBC ? fr->pbcType : PbcType::Unset,
+                              fr->box,
+                              ' ',
+                              fr->step,
+                              gc);
             }
             break;
         case efG96: write_g96_conf(gmx_fio_getfp(status->fio), title, fr, -1, nullptr); break;
         default:
-            gmx_fatal(FARGS, "Sorry, write_trxframe can not write %s",
-                      ftp2ext(gmx_fio_getftp(status->fio)));
+            gmx_fatal(FARGS, "Sorry, write_trxframe can not write %s", ftp2ext(gmx_fio_getftp(status->fio)));
     }
 
     return 0;
@@ -742,8 +779,11 @@ static gmx_bool pdb_next_x(t_trxstatus* status, FILE* fp, t_trxframe* fr)
     {
         if (na != fr->natoms)
         {
-            gmx_fatal(FARGS, "Number of atoms in pdb frame %d is %d instead of %d",
-                      nframes_read(status), na, fr->natoms);
+            gmx_fatal(FARGS,
+                      "Number of atoms in pdb frame %d is %d instead of %d",
+                      nframes_read(status),
+                      na,
+                      fr->natoms);
         }
         return TRUE;
     }
@@ -799,25 +839,24 @@ bool read_next_frame(const gmx_output_env_t* oenv, t_trxstatus* status, t_trxfra
             case efG96:
             {
                 t_symtab* symtab = nullptr;
-                read_g96_conf(gmx_fio_getfp(status->fio), nullptr, nullptr, fr, symtab,
-                              status->persistent_line);
+                read_g96_conf(gmx_fio_getfp(status->fio), nullptr, nullptr, fr, symtab, status->persistent_line);
                 bRet = (fr->natoms > 0);
                 break;
             }
             case efXTC:
-                if (bTimeSet(TBEGIN) && (status->tf < rTimeValue(TBEGIN)))
+                if (bTimeSet(TimeControl::Begin) && (status->tf < rTimeValue(TimeControl::Begin)))
                 {
-                    if (xtc_seek_time(status->fio, rTimeValue(TBEGIN), fr->natoms, TRUE))
+                    if (xtc_seek_time(status->fio, rTimeValue(TimeControl::Begin), fr->natoms, TRUE))
                     {
                         gmx_fatal(FARGS,
                                   "Specified frame (time %f) doesn't exist or file "
                                   "corrupt/inconsistent.",
-                                  rTimeValue(TBEGIN));
+                                  rTimeValue(TimeControl::Begin));
                     }
                     initcount(status);
                 }
-                bRet = (read_next_xtc(status->fio, fr->natoms, &fr->step, &fr->time, fr->box, fr->x,
-                                      &fr->prec, &bOK)
+                bRet      = (read_next_xtc(
+                                status->fio, fr->natoms, &fr->step, &fr->time, fr->box, fr->x, &fr->prec, &bOK)
                         != 0);
                 fr->bPrec = (bRet && fr->prec > 0);
                 fr->bStep = bRet;
@@ -838,8 +877,10 @@ bool read_next_frame(const gmx_output_env_t* oenv, t_trxstatus* status, t_trxfra
 #if GMX_USE_PLUGINS
                 bRet = read_next_vmd_frame(status->vmdplugin, fr);
 #else
-                gmx_fatal(FARGS, "DEATH HORROR in read_next_frame ftp=%s,status=%s",
-                          ftp2ext(gmx_fio_getftp(status->fio)), gmx_fio_getname(status->fio));
+                gmx_fatal(FARGS,
+                          "DEATH HORROR in read_next_frame ftp=%s,status=%s",
+                          ftp2ext(gmx_fio_getftp(status->fio)),
+                          gmx_fio_getname(status->fio));
 #endif
         }
         status->tf = fr->time;
index a94cdae472f43e89db7334391a06b439ca25470d..ea9be527bc46e03bd7112dd22be37c8150ad005c 100644 (file)
@@ -146,8 +146,7 @@ static int load_sharedlibrary_plugins(const char* fullpath, gmx_vmdplugin_t* vmd
     {
         if (debug)
         {
-            fprintf(debug, "\nUnable to open dynamic library %s.\n%s\n", fullpath,
-                    vmddlerror()); /*only to debug because of stdc++ erros */
+            fprintf(debug, "\nUnable to open dynamic library %s.\n%s\n", fullpath, vmddlerror()); /*only to debug because of stdc++ erros */
         }
         return 0;
     }
index f186ff95621756a724375d8a0421a7091a1f014e..43d481eac258a0b07ff5b375cbe3588a1da800ec 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +119,7 @@ static void low_warning(warninp_t wi, const char* wtype, int n, const char* s)
     {
         if (wi->lineno != -1)
         {
-            fprintf(stderr, "\n%s %d [file %s, line %d]:\n%s\n\n", wtype, n, wi->filenm.c_str(),
-                    wi->lineno, temp2);
+            fprintf(stderr, "\n%s %d [file %s, line %d]:\n%s\n\n", wtype, n, wi->filenm.c_str(), wi->lineno, temp2);
         }
         else
         {
@@ -189,8 +188,13 @@ static void print_warn_count(const char* type, int n)
     print_warn_count("note", wi->nwarn_note);
     print_warn_count("warning", wi->nwarn_warn);
 
-    gmx_fatal(f_errno, file, line, "There %s %d error%s in input file(s)",
-              (wi->nwarn_error == 1) ? "was" : "were", wi->nwarn_error, (wi->nwarn_error == 1) ? "" : "s");
+    gmx_fatal(f_errno,
+              file,
+              line,
+              "There %s %d error%s in input file(s)",
+              (wi->nwarn_error == 1) ? "was" : "were",
+              wi->nwarn_error,
+              (wi->nwarn_error == 1) ? "" : "s");
 }
 
 void check_warning_error(warninp_t wi, int f_errno, const char* file, int line)
@@ -229,7 +233,9 @@ void done_warning(warninp_t wi, int f_errno, const char* file, int line)
 
     if (wi->maxwarn >= 0 && wi->nwarn_warn > wi->maxwarn)
     {
-        gmx_fatal(f_errno, file, line,
+        gmx_fatal(f_errno,
+                  file,
+                  line,
                   "Too many warnings (%d).\n"
                   "If you are sure all warnings are harmless, use the -maxwarn option.",
                   wi->nwarn_warn);
@@ -243,7 +249,7 @@ void free_warning(warninp_t wi)
     delete wi;
 }
 
-void _too_few(warninp_t wi, const char* fn, int line)
+void too_few_function(warninp_t wi, const char* fn, int line)
 {
     char buf[STRLEN];
 
@@ -251,7 +257,7 @@ void _too_few(warninp_t wi, const char* fn, int line)
     warning(wi, buf);
 }
 
-void _incorrect_n_param(warninp_t wi, const char* fn, int line)
+void incorrect_n_param_function(warninp_t wi, const char* fn, int line)
 {
     char buf[STRLEN];
 
index 7d21c03d5214725c8c4fe71d5d1f137ca01add28..15b71f0b0372a6540f92402771b1b48e53c8feb0 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2010,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -131,12 +131,12 @@ void done_warning(warninp_t wi, int f_errno, const char* file, int line);
 void free_warning(warninp_t wi);
 /* Frees the data structure pointed to by wi. */
 
-void _too_few(warninp_t wi, const char* fn, int line);
-#define too_few(wi) _too_few(wi, __FILE__, __LINE__)
+void too_few_function(warninp_t wi, const char* fn, int line);
+#define too_few(wi) too_few_function(wi, __FILE__, __LINE__)
 /* Issue a warning stating 'Too few parameters' */
 
-void _incorrect_n_param(warninp_t wi, const char* fn, int line);
-#define incorrect_n_param(wi) _incorrect_n_param(wi, __FILE__, __LINE__)
+void incorrect_n_param_function(warninp_t wi, const char* fn, int line);
+#define incorrect_n_param(wi) incorrect_n_param_function(wi, __FILE__, __LINE__)
 /* Issue a warning stating 'Incorrect number of parameters' */
 
 #endif
index 808bbaf9cc0b85bb186b4f58eaee4bee7fa140bd..85de599702dde5d0bde5f448f8607114d590980a 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "writeps.h"
 
 #include "gromacs/fileio/gmxfio.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 
 using namespace gmx;
 
-const char* fontnm[efontNR] = {
-    "Times-Roman", "Times-Italic",      "Times-Bold",     "Times-BoldItalic",
-    "Helvetica",   "Helvetica-Oblique", "Helvetica-Bold", "Helvetica-BoldOblique",
-    "Courier",     "Courier-Oblique",   "Courier-Bold",   "Courier-BoldOblique"
-};
+const char* enumValueToString(Fonts enumValue)
+{
+    gmx::EnumerationArray<Fonts, const char*> fontNames = {
+        "Times-Roman", "Times-Italic",      "Times-Bold",     "Times-BoldItalic",
+        "Helvetica",   "Helvetica-Oblique", "Helvetica-Bold", "Helvetica-BoldOblique",
+        "Courier",     "Courier-Oblique",   "Courier-Bold",   "Courier-BoldOblique"
+    };
+    return fontNames[enumValue];
+}
 
 t_psdata ps_open(const char* fn, real x1, real y1, real x2, real y2)
 {
@@ -127,7 +132,12 @@ void ps_init_rgb_nbox(t_psdata* ps, real xbox, real ybox)
     fprintf(ps->fp,
             "/by {def currentpoint "
             "%g y r %g %g r %g y neg r %g %g r f y add moveto} bind def\n",
-            0.0, xbox, 0.0, 0.0, -xbox, 0.0);
+            0.0,
+            xbox,
+            0.0,
+            0.0,
+            -xbox,
+            0.0);
     /* macro bn is used in ps_rgb_nbox to draw rectangular boxes */
 }
 
@@ -155,7 +165,15 @@ void ps_init_rgb_box(t_psdata* ps, real xbox, real ybox)
     fprintf(ps->fp,
             "/b {currentpoint "
             "%g %g r %g %g r %g %g r %g %g r f %g add moveto} bind def\n",
-            0.0, ybox, xbox, 0.0, 0.0, -ybox, -xbox, 0.0, ybox);
+            0.0,
+            ybox,
+            xbox,
+            0.0,
+            0.0,
+            -ybox,
+            -xbox,
+            0.0,
+            ybox);
     /* macro b is used in search_col to define macro B */
 }
 
@@ -225,14 +243,12 @@ void ps_fillarc(t_psdata* ps, real x1, real y1, real rad, real a0, real a1)
 
 void ps_arcslice(t_psdata* ps, real xc, real yc, real rad1, real rad2, real a0, real a1)
 {
-    fprintf(ps->fp, "newpath %g %g %g %g %g arc %g %g %g %g %g arcn closepath s\n", xc, yc, rad1,
-            a0, a1, xc, yc, rad2, a1, a0);
+    fprintf(ps->fp, "newpath %g %g %g %g %g arc %g %g %g %g %g arcn closepath s\n", xc, yc, rad1, a0, a1, xc, yc, rad2, a1, a0);
 }
 
 void ps_fillarcslice(t_psdata* ps, real xc, real yc, real rad1, real rad2, real a0, real a1)
 {
-    fprintf(ps->fp, "newpath %g %g %g %g %g arc %g %g %g %g %g arcn closepath f\n", xc, yc, rad1,
-            a0, a1, xc, yc, rad2, a1, a0);
+    fprintf(ps->fp, "newpath %g %g %g %g %g arc %g %g %g %g %g arcn closepath f\n", xc, yc, rad1, a0, a1, xc, yc, rad2, a1, a0);
 }
 
 void ps_circle(t_psdata* ps, real x1, real y1, real rad)
@@ -240,15 +256,15 @@ void ps_circle(t_psdata* ps, real x1, real y1, real rad)
     ps_arc(ps, x1, y1, rad, 0, 360);
 }
 
-void ps_font(t_psdata* ps, int font, real size)
+void ps_font(t_psdata* ps, Fonts font, real size)
 {
 
-    if ((font < 0) || (font > efontNR))
+    if (font == Fonts::Count)
     {
-        fprintf(stderr, "Invalid Font: %d, using %s\n", font, fontnm[0]);
-        font = 0;
+        fprintf(stderr, "Invalid Font: %d, using %s\n", static_cast<int>(font), enumValueToString(Fonts::Times));
+        font = Fonts::Times;
     }
-    fprintf(ps->fp, "/%s findfont\n", fontnm[font]);
+    fprintf(ps->fp, "/%s findfont\n", enumValueToString(font));
     fprintf(ps->fp, "%g scalefont setfont\n", size);
 }
 
index d6449e9adcda406bc46f2ffe5d1ea0c177856c05..d0518b6196833bfb65769da0eb186acaf23c34ab 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,2019, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2015,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,21 +63,21 @@ typedef enum
     eYBottom
 } eYPos;
 
-enum
+enum class Fonts : int
 {
-    efontTIMES,
-    efontTIMESITALIC,
-    efontTIMESBOLD,
-    efontTIMESBOLDITALIC,
-    efontHELV,
-    efontHELVITALIC,
-    efontHELVBOLD,
-    efontHELVBOLDITALIC,
-    efontCOUR,
-    efontCOURITALIC,
-    efontCOURBOLD,
-    efontCOURBOLDITALIC,
-    efontNR
+    Times,
+    TimesItalic,
+    TimesBold,
+    TimesBoldItalic,
+    Helvetica,
+    HelveticaItalic,
+    HelveticaBold,
+    HelveticaBoldItalic,
+    Courier,
+    CourierItalic,
+    CourierBold,
+    CourierBoldItalic,
+    Count
 };
 
 
@@ -91,7 +91,7 @@ struct t_psdata
 };
 
 
-extern const char* fontnm[efontNR];
+const char* enumValueToString(Fonts enumValue);
 
 t_psdata ps_open(const char* fn, real x1, real y1, real x2, real y2);
 
@@ -122,7 +122,7 @@ void ps_fillarcslice(t_psdata* ps, real xc, real yc, real rad1, real rad2, real
 
 void ps_circle(t_psdata* ps, real x1, real y1, real rad);
 
-void ps_font(t_psdata* ps, int font, real size);
+void ps_font(t_psdata* ps, Fonts font, real size);
 void ps_strfont(t_psdata* ps, char* font, real size);
 
 void ps_text(t_psdata* ps, real x1, real y1, const std::string& str);
index 108bd92c586d791b0d8b918f0bbde4b37467558c..6b097e867eccc19ae21fece0c944fde8a0855477 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,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 /* the xdr data types; note that there is no data type 'real' because
    here we deal with the types as they are actually written to disk.  */
-typedef enum
+enum class XdrDataType : int
 {
-    xdr_datatype_int,
-    xdr_datatype_float,
-    xdr_datatype_double,
-    xdr_datatype_int64,
-    xdr_datatype_char,
-    xdr_datatype_string
-} xdr_datatype;
+    Int,
+    Float,
+    Double,
+    Int64,
+    Char,
+    String,
+    Count
+};
 
-/* names corresponding to the xdr_datatype enum */
-extern const char* xdr_datatype_names[];
+/* names corresponding to the XdrDataType enum */
+const char* enumValueToString(XdrDataType enumValue);
 
 #endif
index c5ceb8338d1ff16430859bbe6023a54390d82c95..99763a73b52dcd6f565127a11ca3e349813d7b60 100644 (file)
@@ -102,7 +102,9 @@ static int xtc_check(const char* str, gmx_bool bResult, const char* file, int li
             fprintf(debug,
                     "\nXTC error: read/write of %s failed, "
                     "source file %s, line %d\n",
-                    str, file, line);
+                    str,
+                    file,
+                    line);
         }
         return 0;
     }
@@ -221,8 +223,7 @@ int write_xtc(t_fileio* fio, int natoms, int64_t step, real time, const rvec* bo
     }
 
     /* write data */
-    bOK = xtc_coord(xd, &natoms, const_cast<rvec*>(box), const_cast<rvec*>(x), &prec,
-                    FALSE); /* bOK will be 1 if writing went well */
+    bOK = xtc_coord(xd, &natoms, const_cast<rvec*>(box), const_cast<rvec*>(x), &prec, FALSE); /* bOK will be 1 if writing went well */
 
     if (bOK)
     {
index 4cc0794db209f054572792d7cb3866376d44ffe5..2cafa953cb2f93c39fa2da22c8a646dfccb20c6d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -39,6 +39,7 @@
 
 #include "xvgr.h"
 
+#include <array>
 #include <cassert>
 #include <cctype>
 #include <cstring>
@@ -88,7 +89,8 @@ static char* xvgrstr(const std::string& gmx, const gmx_output_env_t* oenv, char*
             gmx_fatal(FARGS,
                       "Output buffer length in xvgstr (%d) too small to process xvg input string "
                       "'%s'",
-                      buflen, gmx.c_str());
+                      buflen,
+                      gmx.c_str());
         }
         if (gmx[g] == '\\')
         {
@@ -318,7 +320,10 @@ void xvgr_world(FILE* out, real xmin, real ymin, real xmax, real ymax, const gmx
                 "@ world ymin %g\n"
                 "@ world xmax %g\n"
                 "@ world ymax %g\n",
-                xmin, ymin, xmax, ymax);
+                xmin,
+                ymin,
+                xmax,
+                ymax);
     }
 }
 
@@ -386,13 +391,14 @@ void xvgr_new_dataset(FILE* out, int nr_first, int nsets, const char** setname,
             {
                 if (output_env_get_xvg_format(oenv) == XvgFormat::Xmgr)
                 {
-                    fprintf(out, "@ legend string %d \"%s\"\n", i + nr_first,
+                    fprintf(out,
+                            "@ legend string %d \"%s\"\n",
+                            i + nr_first,
                             xvgrstr(setname[i], oenv, buf, STRLEN));
                 }
                 else
                 {
-                    fprintf(out, "@ s%d legend \"%s\"\n", i + nr_first,
-                            xvgrstr(setname[i], oenv, buf, STRLEN));
+                    fprintf(out, "@ s%d legend \"%s\"\n", i + nr_first, xvgrstr(setname[i], oenv, buf, STRLEN));
                 }
             }
         }
@@ -413,8 +419,8 @@ void xvgr_line_props(FILE* out, int NrSet, int LineStyle, int LineColor, const g
     }
 }
 
-static const char* LocTypeStr[] = { "view", "world" };
-static const char* BoxFillStr[] = { "none", "color", "pattern" };
+static constexpr std::array<const char*, 2> LocTypeStr = { "view", "world" };
+static constexpr std::array<const char*, 3> BoxFillStr = { "none", "color", "pattern" };
 
 void xvgr_box(FILE*                   out,
               int                     LocType,
@@ -1001,7 +1007,9 @@ real** read_xvg_time(const char* fn,
                             fprintf(stderr,
                                     "Invalid line in %s:\n%s"
                                     "Using zeros for the last %d sets\n",
-                                    fn, line0, narg - a);
+                                    fn,
+                                    line0,
+                                    narg - a);
                         }
                         n++;
                     }
index 3a3a581a95e2f48bf84dd1e7244091917f616d80..1c3f989f34539b0b6b2cfa59fa2317138e2feebc 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2013,2014,2015,2017,2019, by the GROMACS development team, led by
+# Copyright (c) 2013,2014,2015,2017,2019,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(gmxana INTERFACE)
+
 file(GLOB GMXANA_SOURCES *.cpp)
 
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${GMXANA_SOURCES} PARENT_SCOPE)
 
+# Source files have the following private module dependencies.
+target_link_libraries(gmxana PRIVATE
+        )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(gmxana PUBLIC
+target_include_directories(gmxana INTERFACE
+        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(gmxana PUBLIC
+target_link_libraries(gmxana INTERFACE
+        legacy_api
+        )
+
+# TODO: when gmxana is an OBJECT target
+#target_link_libraries(gmxana PUBLIC legacy_api)
+#target_link_libraries(gmxana PRIVATE common)
+
+# Module dependencies
+# gmxana interfaces convey transitive dependence on these modules.
+#target_link_libraries(gmxana PUBLIC
+target_link_libraries(gmxana INTERFACE
+        utility
+        )
+
 if(BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index 3a3a952f312d2fe0d68ae31e6e6c7ae50f6c57e8..6bae98b5599a0f5af104622f6ecbe2e56368a6aa 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,7 @@
 #include "gromacs/listed_forces/bonded.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/math/vecdump.h"
 #include "gromacs/pbcutil/pbc.h"
@@ -107,7 +108,7 @@ static int calc_RBbin(real phi, int gmx_unused multiplicity, real gmx_unused cor
 
 static int calc_Nbin(real phi, int multiplicity, real core_frac)
 {
-    static const real r360 = 360 * DEG2RAD;
+    static const real r360 = 360 * gmx::c_deg2Rad;
     real              rot_width, core_width, core_offset, low, hi;
     int               bin;
     /* with multiplicity 3 and core_frac 0.5
@@ -127,8 +128,8 @@ static int calc_Nbin(real phi, int multiplicity, real core_frac)
     {
         low = ((bin - 1) * rot_width) + core_offset;
         hi  = ((bin - 1) * rot_width) + core_offset + core_width;
-        low *= DEG2RAD;
-        hi *= DEG2RAD;
+        low *= gmx::c_deg2Rad;
+        hi *= gmx::c_deg2Rad;
         if ((phi > low) && (phi < hi))
         {
             return bin;
@@ -161,8 +162,8 @@ void ana_dih_trans(const char*             fn_trans,
         multiplicity[k] = 3;
     }
 
-    low_ana_dih_trans(TRUE, fn_trans, TRUE, fn_histo, maxchi, dih, nlist, dlist, nframes, nangles,
-                      grpname, multiplicity, time, bRb, 0.5, oenv);
+    low_ana_dih_trans(
+            TRUE, fn_trans, TRUE, fn_histo, maxchi, dih, nlist, dlist, nframes, nangles, grpname, multiplicity, time, bRb, 0.5, oenv);
     sfree(dlist);
     sfree(multiplicity);
 }
@@ -575,8 +576,7 @@ void get_chi_product_traj(real**                  dih,
             if (bAll)
             {
                 /* print cuml rotamer vs time */
-                print_one(oenv, "chiproduct", dlist[i].name, "chi product for",
-                          "cumulative rotamer", nframes, time, chi_prtrj);
+                print_one(oenv, "chiproduct", dlist[i].name, "chi product for", "cumulative rotamer", nframes, time, chi_prtrj);
             }
 
             /* make a histogram pf culm. rotamer occupancy too */
@@ -698,13 +698,12 @@ static void calc_angles(struct t_pbc* pbc, int n3, int index[], real ang[], rvec
 
     for (i = ix = 0; (ix < n3); i++, ix += 3)
     {
-        ang[i] = bond_angle(x_s[index[ix]], x_s[index[ix + 1]], x_s[index[ix + 2]], pbc, r_ij, r_kj,
-                            &costh, &t1, &t2);
+        ang[i] = bond_angle(
+                x_s[index[ix]], x_s[index[ix + 1]], x_s[index[ix + 2]], pbc, r_ij, r_kj, &costh, &t1, &t2);
     }
     if (debug)
     {
-        fprintf(debug, "Angle[0]=%g, costh=%g, index0 = %d, %d, %d\n", ang[0], costh, index[0],
-                index[1], index[2]);
+        fprintf(debug, "Angle[0]=%g, costh=%g, index0 = %d, %d, %d\n", ang[0], costh, index[0], index[1], index[2]);
         pr_rvec(debug, 0, "rij", r_ij, DIM, TRUE);
         pr_rvec(debug, 0, "rkj", r_kj, DIM, TRUE);
     }
@@ -718,7 +717,7 @@ static real calc_fraction(const real angles[], int nangles)
 
     for (i = 0; i < nangles; i++)
     {
-        angle = angles[i] * RAD2DEG;
+        angle = angles[i] * gmx::c_rad2Deg;
 
         if (angle > 135 && angle < 225)
         {
@@ -747,8 +746,19 @@ static void calc_dihs(struct t_pbc* pbc, int n4, const int index[], real ang[],
 
     for (i = ix = 0; (ix < n4); i++, ix += 4)
     {
-        aaa = dih_angle(x_s[index[ix]], x_s[index[ix + 1]], x_s[index[ix + 2]], x_s[index[ix + 3]],
-                        pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3);
+        aaa = dih_angle(x_s[index[ix]],
+                        x_s[index[ix + 1]],
+                        x_s[index[ix + 2]],
+                        x_s[index[ix + 3]],
+                        pbc,
+                        r_ij,
+                        r_kj,
+                        r_kl,
+                        m,
+                        n,
+                        &t1,
+                        &t2,
+                        &t3);
 
         ang[i] = aaa; /* not taking into account ryckaert bellemans yet */
     }
@@ -772,8 +782,7 @@ void make_histo(FILE* log, int ndata, real data[], int npoints, int histo[], rea
     dx = npoints / (maxx - minx);
     if (debug)
     {
-        fprintf(debug, "Histogramming: ndata=%d, nhisto=%d, minx=%g,maxx=%g,dx=%g\n", ndata,
-                npoints, minx, maxx, dx);
+        fprintf(debug, "Histogramming: ndata=%d, nhisto=%d, minx=%g,maxx=%g,dx=%g\n", ndata, npoints, minx, maxx, dx);
     }
     for (i = 0; (i < ndata); i++)
     {
index 52ab32a3be5252ed88a008ccd382ab095d8aa6ca..feed719fcfaa9611304a3041a550c373b88a95eb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +35,7 @@
 #ifndef GMX_GMXANA_ANGLE_CORRECTION_H
 #define GMX_GMXANA_ANGLE_CORRECTION_H
 
-#include "gromacs/math/units.h"
+#include "gromacs/utility/real.h"
 
 /*! \brief
  * Return the angle in radians after correcting to be within range of -PI < \p angle < PI.
index 15684e8379c4b63f3d5a8c84bf7e316b5b95ece2..49ffb369f807cc170bec5daf01405442261faf90 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2013,2014,2015 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -33,8 +33,8 @@
  * 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 _binsearch_h
-#define _binsearch_h
+#ifndef GMX_GMXANA_BINSEARCH_H
+#define GMX_GMXANA_BINSEARCH_H
 
 #include "gromacs/utility/real.h"
 
diff --git a/src/gromacs/gmxana/cluster_methods.cpp b/src/gromacs/gmxana/cluster_methods.cpp
new file mode 100644 (file)
index 0000000..a0d1f47
--- /dev/null
@@ -0,0 +1,606 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 "cluster_methods.h"
+
+#include "gromacs/fileio/matio.h"
+#include "gromacs/fileio/xvgr.h"
+#include "gromacs/gmxana/cmat.h"
+#include "gromacs/linearalgebra/eigensolver.h"
+#include "gromacs/random/threefry.h"
+#include "gromacs/random/uniformintdistribution.h"
+#include "gromacs/random/uniformrealdistribution.h"
+#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/futil.h"
+#include "gromacs/utility/smalloc.h"
+
+void mc_optimize(FILE* log, t_mat* m, real* time, int maxiter, int nrandom, int seed, real kT, const char* conv, gmx_output_env_t* oenv)
+{
+    FILE*  fp = nullptr;
+    real   ecur, enext, emin, prob, enorm;
+    int    i, j, iswap, jswap, nn, nuphill = 0;
+    t_mat* minimum;
+
+    if (seed == 0)
+    {
+        seed = static_cast<int>(gmx::makeRandomSeed());
+    }
+    gmx::DefaultRandomEngine rng(seed);
+
+    if (m->n1 != m->nn)
+    {
+        fprintf(stderr, "Can not do Monte Carlo optimization with a non-square matrix.\n");
+        return;
+    }
+    printf("\nDoing Monte Carlo optimization to find the smoothest trajectory\n");
+    printf("by reordering the frames to minimize the path between the two structures\n");
+    printf("that have the largest pairwise RMSD.\n");
+    printf("Using random seed %d.\n", seed);
+
+    iswap = jswap = -1;
+    enorm         = m->mat[0][0];
+    for (i = 0; (i < m->n1); i++)
+    {
+        for (j = 0; (j < m->nn); j++)
+        {
+            if (m->mat[i][j] > enorm)
+            {
+                enorm = m->mat[i][j];
+                iswap = i;
+                jswap = j;
+            }
+        }
+    }
+    if ((iswap == -1) || (jswap == -1))
+    {
+        fprintf(stderr, "Matrix contains identical values in all fields\n");
+        return;
+    }
+    swap_rows(m, 0, iswap);
+    swap_rows(m, m->n1 - 1, jswap);
+    emin = ecur = mat_energy(m);
+    printf("Largest distance %g between %d and %d. Energy: %g.\n", enorm, iswap, jswap, emin);
+
+    nn = m->nn;
+
+    /* Initiate and store global minimum */
+    minimum     = init_mat(nn, m->b1D);
+    minimum->nn = nn;
+    copy_t_mat(minimum, m);
+
+    if (nullptr != conv)
+    {
+        fp = xvgropen(conv, "Convergence of the MC optimization", "Energy", "Step", oenv);
+    }
+
+    gmx::UniformIntDistribution<int>   intDistNN(1, nn - 2); // [1,nn-2]
+    gmx::UniformRealDistribution<real> realDistOne;          // [0,1)
+
+    for (i = 0; (i < maxiter); i++)
+    {
+        /* Generate new swapping candidates */
+        do
+        {
+            iswap = intDistNN(rng);
+            jswap = intDistNN(rng);
+        } while ((iswap == jswap) || (iswap >= nn - 1) || (jswap >= nn - 1));
+
+        /* Apply swap and compute energy */
+        swap_rows(m, iswap, jswap);
+        enext = mat_energy(m);
+
+        /* Compute probability */
+        prob = 0;
+        if ((enext < ecur) || (i < nrandom))
+        {
+            prob = 1;
+            if (enext < emin)
+            {
+                /* Store global minimum */
+                copy_t_mat(minimum, m);
+                emin = enext;
+            }
+        }
+        else if (kT > 0)
+        {
+            /* Try Monte Carlo step */
+            prob = std::exp(-(enext - ecur) / (enorm * kT));
+        }
+
+        if (prob == 1 || realDistOne(rng) < prob)
+        {
+            if (enext > ecur)
+            {
+                nuphill++;
+            }
+
+            fprintf(log, "Iter: %d Swapped %4d and %4d (energy: %g prob: %g)\n", i, iswap, jswap, enext, prob);
+            if (nullptr != fp)
+            {
+                fprintf(fp, "%6d  %10g\n", i, enext);
+            }
+            ecur = enext;
+        }
+        else
+        {
+            swap_rows(m, jswap, iswap);
+        }
+    }
+    fprintf(log, "%d uphill steps were taken during optimization\n", nuphill);
+
+    /* Now swap the matrix to get it into global minimum mode */
+    copy_t_mat(m, minimum);
+
+    fprintf(log, "Global minimum energy %g\n", mat_energy(minimum));
+    fprintf(log, "Global minimum energy %g\n", mat_energy(m));
+    fprintf(log, "Swapped time and frame indices and RMSD to next neighbor:\n");
+    for (i = 0; (i < m->nn); i++)
+    {
+        fprintf(log,
+                "%10g  %5d  %10g\n",
+                time[m->m_ind[i]],
+                m->m_ind[i],
+                (i < m->nn - 1) ? m->mat[m->m_ind[i]][m->m_ind[i + 1]] : 0);
+    }
+
+    if (nullptr != fp)
+    {
+        xvgrclose(fp);
+    }
+}
+
+static bool rms_dist_comp(const t_dist& a, const t_dist& b)
+{
+    return a.dist < b.dist;
+}
+
+static bool clust_id_comp(const t_clustid& a, const t_clustid& b)
+{
+    return a.clust < b.clust;
+}
+
+static bool nrnb_comp(const t_nnb& a, const t_nnb& b)
+{
+    /* return b<a, we want highest first */
+    return b.nr < a.nr;
+}
+
+void gather(t_mat* m, real cutoff, t_clusters* clust)
+{
+    t_clustid* c;
+    t_dist*    d;
+    int        i, j, k, nn, cid, n1, diff;
+    gmx_bool   bChange;
+
+    /* First we sort the entries in the RMSD matrix */
+    n1 = m->nn;
+    nn = ((n1 - 1) * n1) / 2;
+    snew(d, nn);
+    for (i = k = 0; (i < n1); i++)
+    {
+        for (j = i + 1; (j < n1); j++, k++)
+        {
+            d[k].i    = i;
+            d[k].j    = j;
+            d[k].dist = m->mat[i][j];
+        }
+    }
+    if (k != nn)
+    {
+        gmx_incons("gather algortihm");
+    }
+    std::sort(d, d + nn, rms_dist_comp);
+
+    /* Now we make a cluster index for all of the conformations */
+    c = new_clustid(n1);
+
+    /* Now we check the closest structures, and equalize their cluster numbers */
+    fprintf(stderr, "Linking structures ");
+    do
+    {
+        fprintf(stderr, "*");
+        bChange = FALSE;
+        for (k = 0; (k < nn) && (d[k].dist < cutoff); k++)
+        {
+            diff = c[d[k].j].clust - c[d[k].i].clust;
+            if (diff)
+            {
+                bChange = TRUE;
+                if (diff > 0)
+                {
+                    c[d[k].j].clust = c[d[k].i].clust;
+                }
+                else
+                {
+                    c[d[k].i].clust = c[d[k].j].clust;
+                }
+            }
+        }
+    } while (bChange);
+    fprintf(stderr, "\nSorting and renumbering clusters\n");
+    /* Sort on cluster number */
+    std::sort(c, c + n1, clust_id_comp);
+
+    /* Renumber clusters */
+    cid = 1;
+    for (k = 1; k < n1; k++)
+    {
+        if (c[k].clust != c[k - 1].clust)
+        {
+            c[k - 1].clust = cid;
+            cid++;
+        }
+        else
+        {
+            c[k - 1].clust = cid;
+        }
+    }
+    c[k - 1].clust = cid;
+    if (debug)
+    {
+        for (k = 0; (k < n1); k++)
+        {
+            fprintf(debug, "Cluster index for conformation %d: %d\n", c[k].conf, c[k].clust);
+        }
+    }
+    clust->ncl = cid;
+    for (k = 0; k < n1; k++)
+    {
+        clust->cl[c[k].conf] = c[k].clust;
+    }
+
+    sfree(c);
+    sfree(d);
+}
+
+static gmx_bool jp_same(int** nnb, int i, int j, int P)
+{
+    gmx_bool bIn;
+    int      k, ii, jj, pp;
+
+    bIn = FALSE;
+    for (k = 0; nnb[i][k] >= 0; k++)
+    {
+        bIn = bIn || (nnb[i][k] == j);
+    }
+    if (!bIn)
+    {
+        return FALSE;
+    }
+
+    bIn = FALSE;
+    for (k = 0; nnb[j][k] >= 0; k++)
+    {
+        bIn = bIn || (nnb[j][k] == i);
+    }
+    if (!bIn)
+    {
+        return FALSE;
+    }
+
+    pp = 0;
+    for (ii = 0; nnb[i][ii] >= 0; ii++)
+    {
+        for (jj = 0; nnb[j][jj] >= 0; jj++)
+        {
+            if ((nnb[i][ii] == nnb[j][jj]) && (nnb[i][ii] != -1))
+            {
+                pp++;
+            }
+        }
+    }
+
+    return (pp >= P);
+}
+
+void jarvis_patrick(int n1, real** mat, int M, int P, real rmsdcut, t_clusters* clust)
+{
+    t_dist*    row;
+    t_clustid* c;
+    int**      nnb;
+    int        i, j, k, cid, diff, maxval;
+    gmx_bool   bChange;
+    real**     mcpy = nullptr;
+
+    if (rmsdcut < 0)
+    {
+        rmsdcut = 10000;
+    }
+
+    /* First we sort the entries in the RMSD matrix row by row.
+     * This gives us the nearest neighbor list.
+     */
+    snew(nnb, n1);
+    snew(row, n1);
+    for (i = 0; (i < n1); i++)
+    {
+        for (j = 0; (j < n1); j++)
+        {
+            row[j].j    = j;
+            row[j].dist = mat[i][j];
+        }
+        std::sort(row, row + n1, rms_dist_comp);
+        if (M > 0)
+        {
+            /* Put the M nearest neighbors in the list */
+            snew(nnb[i], M + 1);
+            for (j = k = 0; (k < M) && (j < n1) && (mat[i][row[j].j] < rmsdcut); j++)
+            {
+                if (row[j].j != i)
+                {
+                    nnb[i][k] = row[j].j;
+                    k++;
+                }
+            }
+            nnb[i][k] = -1;
+        }
+        else
+        {
+            /* Put all neighbors nearer than rmsdcut in the list */
+            maxval = 0;
+            k      = 0;
+            for (j = 0; (j < n1) && (mat[i][row[j].j] < rmsdcut); j++)
+            {
+                if (row[j].j != i)
+                {
+                    if (k >= maxval)
+                    {
+                        maxval += 10;
+                        srenew(nnb[i], maxval);
+                    }
+                    nnb[i][k] = row[j].j;
+                    k++;
+                }
+            }
+            if (k == maxval)
+            {
+                srenew(nnb[i], maxval + 1);
+            }
+            nnb[i][k] = -1;
+        }
+    }
+    sfree(row);
+    if (debug)
+    {
+        fprintf(debug, "Nearest neighborlist. M = %d, P = %d\n", M, P);
+        for (i = 0; (i < n1); i++)
+        {
+            fprintf(debug, "i:%5d nbs:", i);
+            for (j = 0; nnb[i][j] >= 0; j++)
+            {
+                fprintf(debug, "%5d[%5.3f]", nnb[i][j], mat[i][nnb[i][j]]);
+            }
+            fprintf(debug, "\n");
+        }
+    }
+
+    c = new_clustid(n1);
+    fprintf(stderr, "Linking structures ");
+    /* Use mcpy for temporary storage of booleans */
+    mcpy = mk_matrix(n1, n1, FALSE);
+    for (i = 0; i < n1; i++)
+    {
+        for (j = i + 1; j < n1; j++)
+        {
+            mcpy[i][j] = static_cast<real>(jp_same(nnb, i, j, P));
+        }
+    }
+    do
+    {
+        fprintf(stderr, "*");
+        bChange = FALSE;
+        for (i = 0; i < n1; i++)
+        {
+            for (j = i + 1; j < n1; j++)
+            {
+                if (mcpy[i][j] != 0.0F)
+                {
+                    diff = c[j].clust - c[i].clust;
+                    if (diff)
+                    {
+                        bChange = TRUE;
+                        if (diff > 0)
+                        {
+                            c[j].clust = c[i].clust;
+                        }
+                        else
+                        {
+                            c[i].clust = c[j].clust;
+                        }
+                    }
+                }
+            }
+        }
+    } while (bChange);
+
+    fprintf(stderr, "\nSorting and renumbering clusters\n");
+    /* Sort on cluster number */
+    std::sort(c, c + n1, clust_id_comp);
+
+    /* Renumber clusters */
+    cid = 1;
+    for (k = 1; k < n1; k++)
+    {
+        if (c[k].clust != c[k - 1].clust)
+        {
+            c[k - 1].clust = cid;
+            cid++;
+        }
+        else
+        {
+            c[k - 1].clust = cid;
+        }
+    }
+    c[k - 1].clust = cid;
+    clust->ncl     = cid;
+    for (k = 0; k < n1; k++)
+    {
+        clust->cl[c[k].conf] = c[k].clust;
+    }
+    if (debug)
+    {
+        for (k = 0; (k < n1); k++)
+        {
+            fprintf(debug, "Cluster index for conformation %d: %d\n", c[k].conf, c[k].clust);
+        }
+    }
+
+    done_matrix(n1, &mcpy);
+
+    sfree(c);
+    for (i = 0; (i < n1); i++)
+    {
+        sfree(nnb[i]);
+    }
+    sfree(nnb);
+}
+
+static void dump_nnb(FILE* fp, const char* title, int n1, t_nnb* nnb)
+{
+    int i, j;
+
+    /* dump neighbor list */
+    fprintf(fp, "%s", title);
+    for (i = 0; (i < n1); i++)
+    {
+        fprintf(fp, "i:%5d #:%5d nbs:", i, nnb[i].nr);
+        for (j = 0; j < nnb[i].nr; j++)
+        {
+            fprintf(fp, "%5d", nnb[i].nb[j]);
+        }
+        fprintf(fp, "\n");
+    }
+}
+
+void gromos(int n1, real** mat, real rmsdcut, t_clusters* clust)
+{
+    t_nnb* nnb;
+    int    i, j, k, j1, maxval;
+
+    /* Put all neighbors nearer than rmsdcut in the list */
+    fprintf(stderr, "Making list of neighbors within cutoff ");
+    snew(nnb, n1);
+    for (i = 0; (i < n1); i++)
+    {
+        maxval = 0;
+        k      = 0;
+        /* put all neighbors within cut-off in list */
+        for (j = 0; j < n1; j++)
+        {
+            if (mat[i][j] < rmsdcut)
+            {
+                if (k >= maxval)
+                {
+                    maxval += 10;
+                    srenew(nnb[i].nb, maxval);
+                }
+                nnb[i].nb[k] = j;
+                k++;
+            }
+        }
+        /* store nr of neighbors, we'll need that */
+        nnb[i].nr = k;
+        if (i % (1 + n1 / 100) == 0)
+        {
+            fprintf(stderr, "%3d%%\b\b\b\b", (i * 100 + 1) / n1);
+        }
+    }
+    fprintf(stderr, "%3d%%\n", 100);
+
+    /* sort neighbor list on number of neighbors, largest first */
+    std::sort(nnb, nnb + n1, nrnb_comp);
+
+    if (debug)
+    {
+        dump_nnb(debug, "Nearest neighborlist after sort.\n", n1, nnb);
+    }
+
+    /* turn first structure with all its neighbors (largest) into cluster
+       remove them from pool of structures and repeat for all remaining */
+    fprintf(stderr, "Finding clusters %4d", 0);
+    /* cluster id's start at 1: */
+    k = 1;
+    while (nnb[0].nr)
+    {
+        /* set cluster id (k) for first item in neighborlist */
+        for (j = 0; j < nnb[0].nr; j++)
+        {
+            clust->cl[nnb[0].nb[j]] = k;
+        }
+        /* mark as done */
+        nnb[0].nr = 0;
+        sfree(nnb[0].nb);
+
+        /* adjust number of neighbors for others, taking removals into account: */
+        for (i = 1; i < n1 && nnb[i].nr; i++)
+        {
+            j1 = 0;
+            for (j = 0; j < nnb[i].nr; j++)
+            {
+                /* if this neighbor wasn't removed */
+                if (clust->cl[nnb[i].nb[j]] == 0)
+                {
+                    /* shift the rest (j1<=j) */
+                    nnb[i].nb[j1] = nnb[i].nb[j];
+                    /* next */
+                    j1++;
+                }
+            }
+            /* now j1 is the new number of neighbors */
+            nnb[i].nr = j1;
+        }
+        /* sort again on nnb[].nr, because we have new # neighbors: */
+        /* but we only need to sort upto i, i.e. when nnb[].nr>0 */
+        std::sort(nnb, nnb + i, nrnb_comp);
+
+        fprintf(stderr, "\b\b\b\b%4d", k);
+        /* new cluster id */
+        k++;
+    }
+    fprintf(stderr, "\n");
+    sfree(nnb);
+    if (debug)
+    {
+        fprintf(debug, "Clusters (%d):\n", k);
+        for (i = 0; i < n1; i++)
+        {
+            fprintf(debug, " %3d", clust->cl[i]);
+        }
+        fprintf(debug, "\n");
+    }
+
+    clust->ncl = k - 1;
+}
diff --git a/src/gromacs/gmxana/cluster_methods.h b/src/gromacs/gmxana/cluster_methods.h
new file mode 100644 (file)
index 0000000..d512f90
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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_GMXANA_CLUSTER_METHODS_H
+#define GMX_GMXANA_CLUSTER_METHODS_H
+
+#include <stdio.h>
+
+#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/real.h"
+
+struct gmx_output_env_t;
+struct t_mat;
+
+struct t_clusters
+{
+    int  ncl;
+    int* cl;
+};
+
+struct t_nnb
+{
+    int  nr;
+    int* nb;
+};
+
+
+void mc_optimize(FILE*             log,
+                 t_mat*            m,
+                 real*             time,
+                 int               maxiter,
+                 int               nrandom,
+                 int               seed,
+                 real              kT,
+                 const char*       conv,
+                 gmx_output_env_t* oenv);
+
+void gather(t_mat* m, real cutoff, t_clusters* clust);
+
+void jarvis_patrick(int n1, real** mat, int M, int P, real rmsdcut, t_clusters* clust);
+
+void gromos(int n1, real** mat, real rmsdcut, t_clusters* clust);
+
+#endif
index 304f48e986557063031af06f5738467c599afefa..714eec39dd46f89e7f3cda78f6082baa4896be93 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,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +35,8 @@
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
-#ifndef _cmat_h
-#define _cmat_h
+#ifndef GMX_GMXANA_CMAT_H
+#define GMX_GMXANA_CMAT_H
 
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
@@ -54,7 +54,7 @@ typedef struct
     int conf, clust;
 } t_clustid;
 
-typedef struct
+struct t_mat
 {
     int      n1, nn;
     int*     m_ind;
@@ -62,7 +62,7 @@ typedef struct
     real     minrms, maxrms, sumrms;
     real*    erow;
     real**   mat;
-} t_mat;
+};
 
 /* The matrix is indexed using the matrix index */
 #define EROW(m, i) m->erow[i]
index aa6f1f7234da325ffa4728a1f056e3afdba1c6d4..4a8f43ae583e6ecc78bbeee1a6242c293d474f16 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2013,2014,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2011,2013,2014,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -33,8 +33,8 @@
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
-#ifndef _dens_filter_h
-#define _dens_filter_h
+#ifndef GMX_GMXANA_DENS_FILTER_H
+#define GMX_GMXANA_DENS_FILTER_H
 
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
index 908f0fa8ac67848dd35d057db46d44d9b479df74..f71e69fd2b75135f2ca2024241af1523004dc706 100644 (file)
@@ -246,7 +246,8 @@ t_dlist* mk_dlist(FILE*          log,
             fprintf(debug,
                     "Could not find N atom but could find other atoms"
                     " in residue %s%d\n",
-                    thisres, ires + r0);
+                    thisres,
+                    ires + r0);
         }
     }
     fprintf(stderr, "\n");
@@ -404,29 +405,45 @@ void pr_dlist(FILE*    fp,
         }
         if (bPhi)
         {
-            fprintf(fp, "   Phi [%5d,%5d,%5d,%5d]",
-                    (dl[i].atm.H == -1) ? 1 + dl[i].atm.minC : 1 + dl[i].atm.H, 1 + dl[i].atm.N,
-                    1 + dl[i].atm.Cn[1], 1 + dl[i].atm.C);
+            fprintf(fp,
+                    "   Phi [%5d,%5d,%5d,%5d]",
+                    (dl[i].atm.H == -1) ? 1 + dl[i].atm.minC : 1 + dl[i].atm.H,
+                    1 + dl[i].atm.N,
+                    1 + dl[i].atm.Cn[1],
+                    1 + dl[i].atm.C);
             pr_props(fp, &dl[i], edPhi, dt);
         }
         if (bPsi)
         {
-            fprintf(fp, "   Psi [%5d,%5d,%5d,%5d]", 1 + dl[i].atm.N, 1 + dl[i].atm.Cn[1],
-                    1 + dl[i].atm.C, 1 + dl[i].atm.O);
+            fprintf(fp,
+                    "   Psi [%5d,%5d,%5d,%5d]",
+                    1 + dl[i].atm.N,
+                    1 + dl[i].atm.Cn[1],
+                    1 + dl[i].atm.C,
+                    1 + dl[i].atm.O);
             pr_props(fp, &dl[i], edPsi, dt);
         }
         if (bOmega && has_dihedral(edOmega, &(dl[i])))
         {
-            fprintf(fp, " Omega [%5d,%5d,%5d,%5d]", 1 + dl[i].atm.minCalpha, 1 + dl[i].atm.minC,
-                    1 + dl[i].atm.N, 1 + dl[i].atm.Cn[1]);
+            fprintf(fp,
+                    " Omega [%5d,%5d,%5d,%5d]",
+                    1 + dl[i].atm.minCalpha,
+                    1 + dl[i].atm.minC,
+                    1 + dl[i].atm.N,
+                    1 + dl[i].atm.Cn[1]);
             pr_props(fp, &dl[i], edOmega, dt);
         }
         for (Xi = 0; Xi < MAXCHI; Xi++)
         {
             if (bChi && (Xi < maxchi) && (dl[i].atm.Cn[Xi + 3] != -1))
             {
-                fprintf(fp, "   Chi%d[%5d,%5d,%5d,%5d]", Xi + 1, 1 + dl[i].atm.Cn[Xi],
-                        1 + dl[i].atm.Cn[Xi + 1], 1 + dl[i].atm.Cn[Xi + 2], 1 + dl[i].atm.Cn[Xi + 3]);
+                fprintf(fp,
+                        "   Chi%d[%5d,%5d,%5d,%5d]",
+                        Xi + 1,
+                        1 + dl[i].atm.Cn[Xi],
+                        1 + dl[i].atm.Cn[Xi + 1],
+                        1 + dl[i].atm.Cn[Xi + 2],
+                        1 + dl[i].atm.Cn[Xi + 3]);
                 pr_props(fp, &dl[i], Xi + edChi1, dt); /* Xi+2 was wrong here */
             }
         }
index 4433fb463c248804a46d769933ef19d6c7781b01..45d1a9075c8b95a597019392c97cfdefadae9710 100644 (file)
@@ -84,8 +84,11 @@ void read_eigenvectors(const char* file,
         *bFit = (head.lambda > -0.5);
         if (*bFit)
         {
-            fprintf(stderr, "Read %smass weighted reference structure with %d atoms from %s\n",
-                    *bDMR ? "" : "non ", *natoms, file);
+            fprintf(stderr,
+                    "Read %smass weighted reference structure with %d atoms from %s\n",
+                    *bDMR ? "" : "non ",
+                    *natoms,
+                    file);
         }
         else
         {
@@ -112,8 +115,11 @@ void read_eigenvectors(const char* file,
     }
     else
     {
-        fprintf(stderr, "Read %smass weighted average/minimum structure with %d atoms from %s\n",
-                *bDMA ? "" : "non ", *natoms, file);
+        fprintf(stderr,
+                "Read %smass weighted average/minimum structure with %d atoms from %s\n",
+                *bDMA ? "" : "non ",
+                *natoms,
+                file);
     }
 
     snew(x, *natoms);
@@ -171,8 +177,12 @@ void write_eigenvectors(const char* trrname,
     clear_mat(zerobox);
     snew(x, natoms);
 
-    fprintf(stderr, "\nWriting %saverage structure & eigenvectors %d--%d to %s\n",
-            (WriteXref == eWXR_YES) ? "reference, " : "", begin, end, trrname);
+    fprintf(stderr,
+            "\nWriting %saverage structure & eigenvectors %d--%d to %s\n",
+            (WriteXref == eWXR_YES) ? "reference, " : "",
+            begin,
+            end,
+            trrname);
 
     trrout = gmx_trr_open(trrname, "w");
     if (WriteXref == eWXR_YES)
index 673315141794c44274580e8b6056498fcdc73b13..9413f3f78e70edfb79b137c35ead342abe4742c4 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
-#ifndef _eigio_h
-#define _eigio_h
+#ifndef GMX_GMXANA_EIGIO_H
+#define GMX_GMXANA_EIGIO_H
 
 #include "gromacs/math/vectypes.h"
 #include "gromacs/utility/basedefinitions.h"
index f38d2d77f430fe48bad3d3d967388ff66512f411..6ee406803b927a3c803b1eafd0a518d04d32db7d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "fitahx.h"
 
 #include <cmath>
+#include <vector>
 
 #include "gromacs/math/do_fit.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/math/vectypes.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
 
@@ -75,24 +77,24 @@ static void my_sub_xcm(int nbb, const int bbind[], rvec x[], rvec xcm)
 
 real fit_ahx(int nres, t_bb bb[], int natoms, int nall, int allindex[], rvec x[], int nca, int caindex[], gmx_bool bFit)
 {
-    static rvec* xref = nullptr;
-    static real* mass = nullptr;
-    const real      = 0.15;  /* Rise per residue (nm)    */
-    const real   tw   = 1.745; /* Twist per residue (rad)  */
-    const real   rad  = 0.23;  /* Radius of the helix (nm) */
-    real         phi0, trms, rms;
-    rvec         dx, xcm;
-    int          ai, i, nmass;
+    static std::vector<gmx::RVec> xref;
+    static std::vector<real>      mass;
+    const real                    d   = 0.15;  /* Rise per residue (nm)    */
+    const real                    tw  = 1.745; /* Twist per residue (rad)  */
+    const real                    rad = 0.23;  /* Radius of the helix (nm) */
+    real                          phi0, trms, rms;
+    rvec                          dx, xcm;
+    int                           ai, i, nmass;
 
     if (nca < 3)
     {
         gmx_fatal(FARGS, "Need at least 3 Calphas to fit to, (now %d)...\n", nca);
     }
 
-    if (xref == nullptr)
+    if (xref.empty())
     {
-        snew(xref, natoms);
-        snew(mass, natoms);
+        xref.resize(natoms);
+        mass.resize(natoms);
     }
     phi0 = 0;
     for (i = 0; (i < nca); i++)
@@ -106,15 +108,22 @@ real fit_ahx(int nres, t_bb bb[], int natoms, int nall, int allindex[], rvec x[]
         mass[ai] = 10.0;
 /*#define DEBUG*/
 #ifdef DEBUG
-        fprintf(stderr, "%5d  %8.3f  %8.3f  %8.3f  %8.3f  %8.3f  %8.3f\n", ai, x[ai][XX], x[ai][YY],
-                x[ai][ZZ], xref[ai][XX], xref[ai][YY], xref[ai][ZZ]);
+        fprintf(stderr,
+                "%5d  %8.3f  %8.3f  %8.3f  %8.3f  %8.3f  %8.3f\n",
+                ai,
+                x[ai][XX],
+                x[ai][YY],
+                x[ai][ZZ],
+                xref[ai][XX],
+                xref[ai][YY],
+                xref[ai][ZZ]);
 #endif
         phi0 += tw;
     }
 
     /* Center the referece around the origin */
-    my_calc_xcm(nca, caindex, xref, xcm);
-    my_sub_xcm(nca, caindex, xref, xcm);
+    my_calc_xcm(nca, caindex, as_rvec_array(xref.data()), xcm);
+    my_sub_xcm(nca, caindex, as_rvec_array(xref.data()), xcm);
 
     if (bFit)
     {
@@ -142,7 +151,7 @@ real fit_ahx(int nres, t_bb bb[], int natoms, int nall, int allindex[], rvec x[]
     /* Now call the fitting routine */
     if (bFit)
     {
-        do_fit(natoms, mass, xref, x);
+        do_fit(natoms, mass.data(), as_rvec_array(xref.data()), x);
     }
 
     /* Reset masses and calc rms */
index f3ffaf5155a0b7ec8c543f9c0ca92cd78381bb10..5fa57da3a325d7358bf07e97c04f3f48fe5268de 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,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +35,8 @@
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
-#ifndef _fitahx_h
-#define _fitahx_h
+#ifndef GMX_GMXANA_FITAHX_H
+#define GMX_GMXANA_FITAHX_H
 
 
 #include "gromacs/gmxana/hxprops.h"
index 7f0623b34d505a525b46d07f8eb1d83774cd8972..881e01279e24bcb1b4e7f458b42da974871e0ae7 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
-#ifndef _gmx_ana_h
-#    define _gmx_ana_h
+#ifndef GMX_GMXANA_GMX_ANA_H
+#    define GMX_GMXANA_GMX_ANA_H
 
 int gmx_analyze(int argc, char* argv[]);
 
@@ -103,8 +103,6 @@ int gmx_make_edi(int argc, char* argv[]);
 
 int gmx_mindist(int argc, char* argv[]);
 
-int gmx_msd(int argc, char* argv[]);
-
 int gmx_nmeig(int argc, char* argv[]);
 
 int gmx_nmens(int argc, char* argv[]);
index 08a5a7419494cff3ce04fc3fb76be897d91d3ebf..b64b1bae02e0e29ca0a40bda91ccb110bb6a332c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +70,6 @@
 
 #include "thermochemistry.h"
 
-static const char* proj_unit;
-
 static real tick_spacing(real range, int minticks)
 {
     real sp;
@@ -280,8 +278,10 @@ compare(int natoms, int n1, rvec** eigvec1, int n2, rvec** eigvec2, real* eigval
     fprintf(stdout, "Trace of the two matrices: %g and %g\n", sum1, sum2);
     if (neig1 != n || neig2 != n)
     {
-        fprintf(stdout, "this is %d%% and %d%% of the total trace\n",
-                gmx::roundToInt(100 * sum1 / trace1), gmx::roundToInt(100 * sum2 / trace2));
+        fprintf(stdout,
+                "this is %d%% and %d%% of the total trace\n",
+                gmx::roundToInt(100 * sum1 / trace1),
+                gmx::roundToInt(100 * sum2 / trace2));
     }
     fprintf(stdout, "Square root of the traces: %g and %g\n", std::sqrt(sum1), std::sqrt(sum2));
 
@@ -414,8 +414,7 @@ static void inprod_matrix(const char* matfile,
     rhi.b   = 0;
     nlevels = 41;
     out     = gmx_ffopen(matfile, "w");
-    write_xpm(out, 0, "Eigenvector inner-products", "in.prod.", "run 1", "run 2", nx, ny, t_x, t_y,
-              mat, 0.0, maxval, rlo, rhi, &nlevels);
+    write_xpm(out, 0, "Eigenvector inner-products", "in.prod.", "run 1", "run 2", nx, ny, t_x, t_y, mat, 0.0, maxval, rlo, rhi, &nlevels);
     gmx_ffclose(out);
 }
 
@@ -472,6 +471,7 @@ static void project(const char*             trajfile,
                     const char*             twodplotfile,
                     const char*             threedplotfile,
                     const char*             filterfile,
+                    const char*             projUnit,
                     int                     skip,
                     const char*             extremefile,
                     gmx_bool                bExtrAll,
@@ -544,7 +544,8 @@ static void project(const char*             trajfile,
             gmx_fatal(FARGS,
                       "the number of atoms in your trajectory (%d) is larger than the number of "
                       "atoms in your structure file (%d)",
-                      nat, atoms->nr);
+                      nat,
+                      atoms->nr);
         }
         snew(all_at, nat);
 
@@ -647,16 +648,28 @@ static void project(const char*             trajfile,
             sprintf(str, "vec %d", eignr[outvec[v]] + 1);
             ylabel[v] = gmx_strdup(str);
         }
-        sprintf(str, "projection on eigenvectors (%s)", proj_unit);
-        write_xvgr_graphs(projfile, noutvec, 1, str, nullptr, output_env_get_xvgr_tlabel(oenv),
-                          ylabel, nframes, inprod[noutvec], inprod, nullptr,
-                          output_env_get_time_factor(oenv), FALSE, bSplit, oenv);
+        sprintf(str, "projection on eigenvectors (%s)", projUnit);
+        write_xvgr_graphs(projfile,
+                          noutvec,
+                          1,
+                          str,
+                          nullptr,
+                          output_env_get_xvgr_tlabel(oenv),
+                          ylabel,
+                          nframes,
+                          inprod[noutvec],
+                          inprod,
+                          nullptr,
+                          output_env_get_time_factor(oenv),
+                          FALSE,
+                          bSplit,
+                          oenv);
     }
 
     if (twodplotfile)
     {
-        sprintf(str, "projection on eigenvector %d (%s)", eignr[outvec[0]] + 1, proj_unit);
-        sprintf(str2, "projection on eigenvector %d (%s)", eignr[outvec[noutvec - 1]] + 1, proj_unit);
+        sprintf(str, "projection on eigenvector %d (%s)", eignr[outvec[0]] + 1, projUnit);
+        sprintf(str2, "projection on eigenvector %d (%s)", eignr[outvec[noutvec - 1]] + 1, projUnit);
         xvgrout = xvgropen(twodplotfile, "2D projection of trajectory", str, str2, oenv);
         for (i = 0; i < nframes; i++)
         {
@@ -696,13 +709,20 @@ static void project(const char*             trajfile,
                     "You have selected four or more eigenvectors:\n"
                     "fourth eigenvector will be plotted "
                     "in bfactor field of pdb file\n");
-            sprintf(str, "4D proj. of traj. on eigenv. %d, %d, %d and %d", eignr[outvec[0]] + 1,
-                    eignr[outvec[1]] + 1, eignr[outvec[2]] + 1, eignr[outvec[3]] + 1);
+            sprintf(str,
+                    "4D proj. of traj. on eigenv. %d, %d, %d and %d",
+                    eignr[outvec[0]] + 1,
+                    eignr[outvec[1]] + 1,
+                    eignr[outvec[2]] + 1,
+                    eignr[outvec[3]] + 1);
         }
         else
         {
-            sprintf(str, "3D proj. of traj. on eigenv. %d, %d and %d", eignr[outvec[0]] + 1,
-                    eignr[outvec[1]] + 1, eignr[outvec[2]] + 1);
+            sprintf(str,
+                    "3D proj. of traj. on eigenv. %d, %d and %d",
+                    eignr[outvec[0]] + 1,
+                    eignr[outvec[1]] + 1,
+                    eignr[outvec[2]] + 1);
         }
         init_t_atoms(&atoms, nframes, FALSE);
         snew(x, nframes);
@@ -753,9 +773,21 @@ static void project(const char*             trajfile,
                     fprintf(out, "TER\n");
                     j = 0;
                 }
-                gmx_fprintf_pdb_atomline(out, epdbATOM, i + 1, "C", ' ', "PRJ", ' ', j + 1, ' ',
-                                         10 * x[i][XX], 10 * x[i][YY], 10 * x[i][ZZ], 1.0,
-                                         10 * b[i], "");
+                gmx_fprintf_pdb_atomline(out,
+                                         PdbRecordType::Atom,
+                                         i + 1,
+                                         "C",
+                                         ' ',
+                                         "PRJ",
+                                         ' ',
+                                         j + 1,
+                                         ' ',
+                                         10 * x[i][XX],
+                                         10 * x[i][YY],
+                                         10 * x[i][ZZ],
+                                         1.0,
+                                         10 * b[i],
+                                         "");
                 if (j > 0)
                 {
                     fprintf(out, "CONECT%5d%5d\n", i, i + 1);
@@ -798,8 +830,7 @@ static void project(const char*             trajfile,
                 }
                 pmin[v] = inprod[v][imin];
                 pmax[v] = inprod[v][imax];
-                fprintf(stderr, "%7d     %10.6f %10d %10.6f %10d\n", eignr[outvec[v]] + 1, pmin[v],
-                        imin, pmax[v], imax);
+                fprintf(stderr, "%7d     %10.6f %10d %10.6f %10d\n", eignr[outvec[v]] + 1, pmin[v], imin, pmax[v], imax);
             }
         }
         else
@@ -895,9 +926,21 @@ static void components(const char*             outfile,
             }
         }
     }
-    write_xvgr_graphs(outfile, noutvec, 4, "Eigenvector components",
-                      "black: total, red: x, green: y, blue: z", "Atom number", ylabel, natoms, x,
-                      nullptr, y, 1, FALSE, FALSE, oenv);
+    write_xvgr_graphs(outfile,
+                      noutvec,
+                      4,
+                      "Eigenvector components",
+                      "black: total, red: x, green: y, blue: z",
+                      "Atom number",
+                      ylabel,
+                      natoms,
+                      x,
+                      nullptr,
+                      y,
+                      1,
+                      FALSE,
+                      FALSE,
+                      oenv);
     fprintf(stderr, "\n");
 }
 
@@ -939,8 +982,10 @@ static void rmsf(const char*             outfile,
         v = outvec[g];
         if (eignr[v] >= neig)
         {
-            gmx_fatal(FARGS, "Selected vector %d is larger than the number of eigenvalues (%d)",
-                      eignr[v] + 1, neig);
+            gmx_fatal(FARGS,
+                      "Selected vector %d is larger than the number of eigenvalues (%d)",
+                      eignr[v] + 1,
+                      neig);
         }
         sprintf(str, "vec %d", eignr[v] + 1);
         ylabel[g] = gmx_strdup(str);
@@ -950,8 +995,8 @@ static void rmsf(const char*             outfile,
             y[g][i] = std::sqrt(eigval[eignr[v]] * norm2(eigvec[v][i])) / sqrtm[i];
         }
     }
-    write_xvgr_graphs(outfile, noutvec, 1, "RMS fluctuation (nm) ", nullptr, "Atom number", ylabel,
-                      natoms, x, y, nullptr, 1, TRUE, FALSE, oenv);
+    write_xvgr_graphs(
+            outfile, noutvec, 1, "RMS fluctuation (nm) ", nullptr, "Atom number", ylabel, natoms, x, y, nullptr, 1, TRUE, FALSE, oenv);
     fprintf(stderr, "\n");
 }
 
@@ -1109,8 +1154,8 @@ int gmx_anaeig(int argc, char* argv[])
     };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW, NFILE, fnm,
-                           NPA, pa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW, NFILE, fnm, NPA, pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -1149,15 +1194,18 @@ int gmx_anaeig(int argc, char* argv[])
     bCompare = (Vec2File != nullptr) || (Eig2File != nullptr);
     bPDB3D   = fn2ftp(ThreeDPlotFile) == efPDB;
 
-    read_eigenvectors(VecFile, &natoms, &bFit1, &xref1, &bDMR1, &xav1, &bDMA1, &nvec1, &eignr1,
-                      &eigvec1, &eigval1);
+    read_eigenvectors(
+            VecFile, &natoms, &bFit1, &xref1, &bDMR1, &xav1, &bDMA1, &nvec1, &eignr1, &eigvec1, &eigval1);
     neig1 = std::min(nvec1, DIM * natoms);
     if (nvec1 != DIM * natoms)
     {
         fprintf(stderr,
                 "Warning: number of eigenvectors %d does not match three times\n"
                 "the number of atoms %d in %s. Using %d eigenvectors.\n\n",
-                nvec1, natoms, VecFile, neig1);
+                nvec1,
+                natoms,
+                VecFile,
+                neig1);
     }
 
     /* Overwrite eigenvalues from separate files if the user provides them */
@@ -1168,7 +1216,8 @@ int gmx_anaeig(int argc, char* argv[])
         {
             fprintf(stderr,
                     "Warning: number of eigenvalues in xvg file (%d) does not mtch trr file (%d)\n",
-                    neig1, natoms);
+                    neig1,
+                    natoms);
         }
         neig1 = neig_tmp;
         srenew(eigval1, neig1);
@@ -1178,8 +1227,7 @@ int gmx_anaeig(int argc, char* argv[])
             eigval1[j] = xvgdata[1][j];
             if (debug && (eigval1[j] != tmp))
             {
-                fprintf(debug, "Replacing eigenvalue %d. From trr: %10g, from xvg: %10g\n", j, tmp,
-                        eigval1[j]);
+                fprintf(debug, "Replacing eigenvalue %d. From trr: %10g, from xvg: %10g\n", j, tmp, eigval1[j]);
             }
         }
         for (j = 0; j < i; j++)
@@ -1211,8 +1259,8 @@ int gmx_anaeig(int argc, char* argv[])
             gmx_fatal(FARGS, "Need a second eigenvector file to do this analysis.");
         }
         int natoms2;
-        read_eigenvectors(Vec2File, &natoms2, &bFit2, &xref2, &bDMR2, &xav2, &bDMA2, &nvec2,
-                          &eignr2, &eigvec2, &eigval2);
+        read_eigenvectors(
+                Vec2File, &natoms2, &bFit2, &xref2, &bDMR2, &xav2, &bDMA2, &nvec2, &eignr2, &eigvec2, &eigval2);
 
         neig2 = std::min(nvec2, DIM * natoms2);
         if (neig2 != neig1)
@@ -1301,7 +1349,8 @@ int gmx_anaeig(int argc, char* argv[])
                     gmx_fatal(FARGS,
                               "you selected a group with %d elements instead of %d, your selection "
                               "does not fit the reference structure in the eigenvector file.",
-                              nfit, natoms);
+                              nfit,
+                              natoms);
                 }
                 for (i = 0; (i < nfit); i++)
                 {
@@ -1333,9 +1382,10 @@ int gmx_anaeig(int argc, char* argv[])
     }
 
     snew(sqrtm, natoms);
+    std::string projUnit;
     if (bM && bDMA1)
     {
-        proj_unit = "u\\S1/2\\Nnm";
+        projUnit = "u\\S1/2\\Nnm";
         for (i = 0; (i < natoms); i++)
         {
             sqrtm[i] = std::sqrt(atoms->atom[index[i]].m);
@@ -1343,7 +1393,7 @@ int gmx_anaeig(int argc, char* argv[])
     }
     else
     {
-        proj_unit = "nm";
+        projUnit = "nm";
         for (i = 0; (i < natoms); i++)
         {
             sqrtm[i] = 1.0;
@@ -1465,10 +1515,36 @@ int gmx_anaeig(int argc, char* argv[])
 
     if (bProj)
     {
-        project(bTraj ? opt2fn("-f", NFILE, fnm) : nullptr, bTop ? &top : nullptr, pbcType, topbox,
-                ProjOnVecFile, TwoDPlotFile, ThreeDPlotFile, FilterFile, skip, ExtremeFile,
-                bFirstLastSet, max, nextr, atoms, natoms, index, bFit1, xrefp, nfit, ifit, w_rls,
-                sqrtm, xav1, eignr1, eigvec1, noutvec, outvec, bSplit, oenv);
+        project(bTraj ? opt2fn("-f", NFILE, fnm) : nullptr,
+                bTop ? &top : nullptr,
+                pbcType,
+                topbox,
+                ProjOnVecFile,
+                TwoDPlotFile,
+                ThreeDPlotFile,
+                FilterFile,
+                projUnit.c_str(),
+                skip,
+                ExtremeFile,
+                bFirstLastSet,
+                max,
+                nextr,
+                atoms,
+                natoms,
+                index,
+                bFit1,
+                xrefp,
+                nfit,
+                ifit,
+                w_rls,
+                sqrtm,
+                xav1,
+                eignr1,
+                eigvec1,
+                noutvec,
+                outvec,
+                bSplit,
+                oenv);
     }
 
     if (OverlapFile)
@@ -1478,8 +1554,8 @@ int gmx_anaeig(int argc, char* argv[])
 
     if (InpMatFile)
     {
-        inprod_matrix(InpMatFile, natoms, nvec1, eignr1, eigvec1, nvec2, eignr2, eigvec2,
-                      bFirstLastSet, noutvec, outvec);
+        inprod_matrix(
+                InpMatFile, natoms, nvec1, eignr1, eigvec1, nvec2, eignr2, eigvec2, bFirstLastSet, noutvec, outvec);
     }
 
     if (bCompare)
index 75888d57fc5093e1170fe6c57adef84baeb375c2..baaf2e968ee8620ce99bbfed6ddd8df35d007ad8 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,7 @@
 #include "gromacs/gmxana/gstat.h"
 #include "gromacs/linearalgebra/matrix.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/statistics/statistics.h"
@@ -163,8 +164,8 @@ static void plot_coscont(const char* ccfile, int n, int nset, real** val, const
 
 static void regression_analysis(int n, gmx_bool bXYdy, real* x, int nset, real** val)
 {
-    real S, chi2, a, b, da, db, r = 0;
-    int  ok;
+    real             S, chi2, a, b, da, db, r = 0;
+    StatisticsStatus ok;
 
     if (bXYdy || (nset == 1))
     {
@@ -174,16 +175,17 @@ static void regression_analysis(int n, gmx_bool bXYdy, real* x, int nset, real**
         printf("(use option -xydy).\n\n");
         if (bXYdy)
         {
-            if ((ok = lsq_y_ax_b_error(n, x, val[0], val[1], &a, &b, &da, &db, &r, &S)) != estatsOK)
+            if ((ok = lsq_y_ax_b_error(n, x, val[0], val[1], &a, &b, &da, &db, &r, &S))
+                != StatisticsStatus::Ok)
             {
-                gmx_fatal(FARGS, "Error fitting the data: %s", gmx_stats_message(ok));
+                gmx_stats_message(ok);
             }
         }
         else
         {
-            if ((ok = lsq_y_ax_b(n, x, val[0], &a, &b, &r, &S)) != estatsOK)
+            if ((ok = lsq_y_ax_b(n, x, val[0], &a, &b, &r, &S)) != StatisticsStatus::Ok)
             {
-                gmx_fatal(FARGS, "Error fitting the data: %s", gmx_stats_message(ok));
+                gmx_stats_message(ok);
             }
         }
         chi2 = gmx::square((n - 2) * S);
@@ -337,7 +339,8 @@ static void average(const char* avfile, int avbar_opt, int n, int nset, real** v
             fprintf(stdout,
                     "Errorbars: discarding %d points on both sides: %d%%"
                     " interval\n",
-                    edge, gmx::roundToInt(100. * (nset - 2 * edge) / nset));
+                    edge,
+                    gmx::roundToInt(100. * (nset - 2 * edge) / nset));
         }
         else
         {
@@ -575,8 +578,7 @@ static void estimate_error(const char*             eefile,
                  * to halfway between tau1_est and the total time (on log scale).
                  */
                 fitparm[2] = std::sqrt(tau1_est * (n - 1) * dt);
-                do_lmfit(nbs, ybs, fitsig, 0, tbs, 0, dt * n, oenv, bDebugMode(), effnERREST,
-                         fitparm, 0, nullptr);
+                do_lmfit(nbs, ybs, fitsig, 0, tbs, 0, dt * n, oenv, bDebugMode(), effnERREST, fitparm, 0, nullptr);
             }
             if (bSingleExpFit || fitparm[0] < 0 || fitparm[2] < 0 || fitparm[1] < 0
                 || (fitparm[1] > 1 && !bAllowNegLTCorr) || fitparm[2] > (n - 1) * dt)
@@ -594,8 +596,11 @@ static void estimate_error(const char*             eefile,
                     {
                         fprintf(stdout, "a fitted parameter is negative\n");
                     }
-                    fprintf(stdout, "invalid fit:  e.e. %g  a %g  tau1 %g  tau2 %g\n",
-                            optimal_error_estimate(sig[s], fitparm, n * dt), fitparm[1], fitparm[0],
+                    fprintf(stdout,
+                            "invalid fit:  e.e. %g  a %g  tau1 %g  tau2 %g\n",
+                            optimal_error_estimate(sig[s], fitparm, n * dt),
+                            fitparm[1],
+                            fitparm[0],
                             fitparm[2]);
                     /* Do a fit with tau2 fixed at the total time.
                      * One could also choose any other large value for tau2.
@@ -604,25 +609,26 @@ static void estimate_error(const char*             eefile,
                     fitparm[1] = 0.95;
                     fitparm[2] = (n - 1) * dt;
                     fprintf(stdout, "Will fix tau2 at the total time: %g\n", fitparm[2]);
-                    do_lmfit(nbs, ybs, fitsig, 0, tbs, 0, dt * n, oenv, bDebugMode(), effnERREST,
-                             fitparm, 4, nullptr);
+                    do_lmfit(nbs, ybs, fitsig, 0, tbs, 0, dt * n, oenv, bDebugMode(), effnERREST, fitparm, 4, nullptr);
                 }
                 if (bSingleExpFit || fitparm[0] < 0 || fitparm[1] < 0 || (fitparm[1] > 1 && !bAllowNegLTCorr))
                 {
                     if (!bSingleExpFit)
                     {
                         fprintf(stdout, "a fitted parameter is negative\n");
-                        fprintf(stdout, "invalid fit:  e.e. %g  a %g  tau1 %g  tau2 %g\n",
-                                optimal_error_estimate(sig[s], fitparm, n * dt), fitparm[1],
-                                fitparm[0], fitparm[2]);
+                        fprintf(stdout,
+                                "invalid fit:  e.e. %g  a %g  tau1 %g  tau2 %g\n",
+                                optimal_error_estimate(sig[s], fitparm, n * dt),
+                                fitparm[1],
+                                fitparm[0],
+                                fitparm[2]);
                     }
                     /* Do a single exponential fit */
                     fprintf(stderr, "Will use a single exponential fit for set %d\n", s + 1);
                     fitparm[0] = tau1_est;
                     fitparm[1] = 1.0;
                     fitparm[2] = 0.0;
-                    do_lmfit(nbs, ybs, fitsig, 0, tbs, 0, dt * n, oenv, bDebugMode(), effnERREST,
-                             fitparm, 6, nullptr);
+                    do_lmfit(nbs, ybs, fitsig, 0, tbs, 0, dt * n, oenv, bDebugMode(), effnERREST, fitparm, 6, nullptr);
                 }
             }
             ee   = optimal_error_estimate(sig[s], fitparm, n * dt);
@@ -634,18 +640,22 @@ static void estimate_error(const char*             eefile,
         if (output_env_get_xvg_format(oenv) == XvgFormat::Xmgr)
         {
             fprintf(fp, "@ legend string %d \"av %f\"\n", 2 * s, av[s]);
-            fprintf(fp, "@ legend string %d \"ee %6g\"\n", 2 * s + 1,
+            fprintf(fp,
+                    "@ legend string %d \"ee %6g\"\n",
+                    2 * s + 1,
                     optimal_error_estimate(sig[s], fitparm, n * dt));
         }
         else if (output_env_get_xvg_format(oenv) == XvgFormat::Xmgrace)
         {
             fprintf(fp, "@ s%d legend \"av %f\"\n", 2 * s, av[s]);
-            fprintf(fp, "@ s%d legend \"ee %6g\"\n", 2 * s + 1,
-                    optimal_error_estimate(sig[s], fitparm, n * dt));
+            fprintf(fp, "@ s%d legend \"ee %6g\"\n", 2 * s + 1, optimal_error_estimate(sig[s], fitparm, n * dt));
         }
         for (i = 0; i < nbs; i++)
         {
-            fprintf(fp, "%g %g %g\n", tbs[i], sig[s] * std::sqrt(ybs[i] / (n * dt)),
+            fprintf(fp,
+                    "%g %g %g\n",
+                    tbs[i],
+                    sig[s] * std::sqrt(ybs[i] / (n * dt)),
                     sig[s] * std::sqrt(fit_function(effnERREST, fitparm, tbs[i]) / (n * dt)));
         }
 
@@ -668,8 +678,8 @@ static void estimate_error(const char*             eefile,
                     fitsig[i] = 1;
                 }
             }
-            low_do_autocorr(nullptr, oenv, nullptr, n, 1, -1, &ac, dt, eacNormal, 1, FALSE, TRUE,
-                            FALSE, 0, 0, effnNONE);
+            low_do_autocorr(
+                    nullptr, oenv, nullptr, n, 1, -1, &ac, dt, eacNormal, 1, FALSE, TRUE, FALSE, 0, 0, effnNONE);
 
             fitlen = n / nb_min;
 
@@ -690,17 +700,23 @@ static void estimate_error(const char*             eefile,
             ac_fit[0] = 0.5 * acint;
             ac_fit[1] = 0.95;
             ac_fit[2] = 10 * acint;
-            do_lmfit(n / nb_min, ac, fitsig, dt, nullptr, 0, fitlen * dt, oenv, bDebugMode(),
-                     effnEXPEXP, ac_fit, 0, nullptr);
+            do_lmfit(n / nb_min, ac, fitsig, dt, nullptr, 0, fitlen * dt, oenv, bDebugMode(), effnEXPEXP, ac_fit, 0, nullptr);
             ac_fit[3] = 1 - ac_fit[1];
 
-            fprintf(stdout, "Set %3d:  ac erest %g  a %g  tau1 %g  tau2 %g\n", s + 1,
-                    optimal_error_estimate(sig[s], ac_fit, n * dt), ac_fit[1], ac_fit[0], ac_fit[2]);
+            fprintf(stdout,
+                    "Set %3d:  ac erest %g  a %g  tau1 %g  tau2 %g\n",
+                    s + 1,
+                    optimal_error_estimate(sig[s], ac_fit, n * dt),
+                    ac_fit[1],
+                    ac_fit[0],
+                    ac_fit[2]);
 
             fprintf(fp, "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
             for (i = 0; i < nbs; i++)
             {
-                fprintf(fp, "%g %g\n", tbs[i],
+                fprintf(fp,
+                        "%g %g\n",
+                        tbs[i],
                         sig[s] * std::sqrt(fit_function(effnERREST, ac_fit, tbs[i])) / (n * dt));
             }
 
@@ -1173,8 +1189,8 @@ int gmx_analyze(int argc, char* argv[])
     npargs = asize(pa);
     ppa    = add_acf_pargs(&npargs, pa);
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, npargs, ppa, asize(desc), desc, 0,
-                           nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, nullptr, &oenv))
     {
         sfree(ppa);
         return 0;
@@ -1195,8 +1211,17 @@ int gmx_analyze(int argc, char* argv[])
         fitfile = opt2fn_null("-g", NFILE, fnm);
     }
 
-    val = read_xvg_time(opt2fn("-f", NFILE, fnm), bHaveT, opt2parg_bSet("-b", npargs, ppa), tb,
-                        opt2parg_bSet("-e", npargs, ppa), te, nsets_in, &nset, &n, &dt, &t);
+    val = read_xvg_time(opt2fn("-f", NFILE, fnm),
+                        bHaveT,
+                        opt2parg_bSet("-b", npargs, ppa),
+                        tb,
+                        opt2parg_bSet("-e", npargs, ppa),
+                        te,
+                        nsets_in,
+                        &nset,
+                        &n,
+                        &dt,
+                        &t);
     printf("Read %d sets of %d points, dt = %g\n\n", nset, n, dt);
 
     if (bDer)
@@ -1235,8 +1260,8 @@ int gmx_analyze(int argc, char* argv[])
 
     if (fitfile != nullptr)
     {
-        print_fitted_function(fitfile, opt2fn_null("-fitted", NFILE, fnm), bXYdy, nset, n, t, val,
-                              npargs, ppa, oenv);
+        print_fitted_function(
+                fitfile, opt2fn_null("-fitted", NFILE, fnm), bXYdy, nset, n, t, val, npargs, ppa, oenv);
     }
 
     printf("                                      std. dev.    relative deviation of\n");
@@ -1276,7 +1301,11 @@ int gmx_analyze(int argc, char* argv[])
         {
             error = 0;
         }
-        printf("SS%d  %13.6e   %12.6e   %12.6e      %6.3f   %6.3f\n", s + 1, av[s], sig[s], error,
+        printf("SS%d  %13.6e   %12.6e   %12.6e      %6.3f   %6.3f\n",
+               s + 1,
+               av[s],
+               sig[s],
+               error,
                sig[s] != 0.0 ? cum3 / (sig[s] * sig[s] * sig[s] * std::sqrt(8 / M_PI)) : 0,
                sig[s] != 0.0 ? cum4 / (sig[s] * sig[s] * sig[s] * sig[s] * 3) - 1 : 0);
     }
index 70f006512aa2ec3f47278245fd1f64fe615aeb05..98f2c4ef9771b563cc9e62f49f7a1f169a1d6026 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +52,7 @@
 #include "gromacs/gmxana/gstat.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/topology/index.h"
 #include "gromacs/utility/arraysize.h"
@@ -192,8 +193,8 @@ int gmx_g_angle(int argc, char* argv[])
 
     npargs = asize(pa);
     ppa    = add_acf_pargs(&npargs, pa);
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa,
-                           asize(desc), desc, asize(bugs), bugs, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
         sfree(ppa);
         return 0;
@@ -240,7 +241,8 @@ int gmx_g_angle(int argc, char* argv[])
         gmx_fatal(FARGS,
                   "number of index elements not multiple of %d, "
                   "these can not be %s\n",
-                  mult, (mult == 3) ? "angle triplets" : "dihedral quadruplets");
+                  mult,
+                  (mult == 3) ? "angle triplets" : "dihedral quadruplets");
     }
 
 
@@ -287,9 +289,21 @@ int gmx_g_angle(int argc, char* argv[])
 
     snew(angstat, maxangstat);
 
-    read_ang_dih(ftp2fn(efTRX, NFILE, fnm), (mult == 3),
-                 bALL || bCorr || bTrans || opt2bSet("-or", NFILE, fnm), bRb, bPBC, maxangstat,
-                 angstat, &nframes, &time, isize, index, &trans_frac, &aver_angle, dih, oenv);
+    read_ang_dih(ftp2fn(efTRX, NFILE, fnm),
+                 (mult == 3),
+                 bALL || bCorr || bTrans || opt2bSet("-or", NFILE, fnm),
+                 bRb,
+                 bPBC,
+                 maxangstat,
+                 angstat,
+                 &nframes,
+                 &time,
+                 isize,
+                 index,
+                 &trans_frac,
+                 &aver_angle,
+                 dih,
+                 oenv);
 
     dt = (time[nframes - 1] - time[0]) / (nframes - 1);
 
@@ -299,7 +313,7 @@ int gmx_g_angle(int argc, char* argv[])
         out = xvgropen(opt2fn("-ov", NFILE, fnm), title, "Time (ps)", "Angle (degrees)", oenv);
         for (i = 0; (i < nframes); i++)
         {
-            fprintf(out, "%10.5f  %8.3f", time[i], aver_angle[i] * RAD2DEG);
+            fprintf(out, "%10.5f  %8.3f", time[i], aver_angle[i] * gmx::c_rad2Deg);
             if (bALL)
             {
                 for (j = 0; (j < nangles); j++)
@@ -307,11 +321,11 @@ int gmx_g_angle(int argc, char* argv[])
                     if (bPBC)
                     {
                         real dd = dih[j][i];
-                        fprintf(out, "  %8.3f", std::atan2(std::sin(dd), std::cos(dd)) * RAD2DEG);
+                        fprintf(out, "  %8.3f", std::atan2(std::sin(dd), std::cos(dd)) * gmx::c_rad2Deg);
                     }
                     else
                     {
-                        fprintf(out, "  %8.3f", dih[j][i] * RAD2DEG);
+                        fprintf(out, "  %8.3f", dih[j][i] * gmx::c_rad2Deg);
                     }
                 }
             }
@@ -343,8 +357,8 @@ int gmx_g_angle(int argc, char* argv[])
 
     if (bTrans)
     {
-        ana_dih_trans(opt2fn("-ot", NFILE, fnm), opt2fn("-oh", NFILE, fnm), dih, nframes, nangles,
-                      grpname, time, bRb, oenv);
+        ana_dih_trans(
+                opt2fn("-ot", NFILE, fnm), opt2fn("-oh", NFILE, fnm), dih, nframes, nangles, grpname, time, bRb, oenv);
     }
 
     if (bCorr)
@@ -359,7 +373,7 @@ int gmx_g_angle(int argc, char* argv[])
 
             if (bChandler)
             {
-                real     dval, sixty = DEG2RAD * 60;
+                real     dval, sixty = gmx::c_deg2Rad * 60;
                 gmx_bool bTest;
 
                 for (i = 0; (i < nangles); i++)
@@ -394,8 +408,15 @@ int gmx_g_angle(int argc, char* argv[])
             {
                 mode = eacCos;
             }
-            do_autocorr(opt2fn("-oc", NFILE, fnm), oenv, "Dihedral Autocorrelation Function",
-                        nframes, nangles, dih, dt, mode, bAverCorr);
+            do_autocorr(opt2fn("-oc", NFILE, fnm),
+                        oenv,
+                        "Dihedral Autocorrelation Function",
+                        nframes,
+                        nangles,
+                        dih,
+                        dt,
+                        mode,
+                        bAverCorr);
         }
     }
 
@@ -435,8 +456,8 @@ int gmx_g_angle(int argc, char* argv[])
     }
     aver /= nframes;
     double aversig = correctRadianAngleRange(aver);
-    aversig *= RAD2DEG;
-    aver *= RAD2DEG;
+    aversig *= gmx::c_rad2Deg;
+    aver *= gmx::c_rad2Deg;
     printf(" < angle >  = %g\n", aversig);
 
     if (mult == 3)
index f68beb07e9f36e335e460503f39f25b2049a7acb..f83e9ba3a661c21c2c532086c7fbe15473c9c7de 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +52,7 @@
 #include <memory>
 #include <string>
 
+#include "gromacs/applied_forces/awh/read_params.h"
 #include "gromacs/commandline/pargs.h"
 #include "gromacs/fileio/enxio.h"
 #include "gromacs/fileio/gmxfio.h"
@@ -122,7 +123,7 @@ public:
      */
     void initializeAwhOutputFile(int                  subBlockStart,
                                  int                  numSubBlocks,
-                                 const AwhBiasParams* awhBiasParams,
+                                 const AwhBiasParams& awhBiasParams,
                                  AwhGraphSelection    graphSelection,
                                  EnergyUnit           energyUnit,
                                  real                 kTValue);
@@ -137,7 +138,7 @@ public:
      */
     void initializeFrictionOutputFile(int                  subBlockStart,
                                       int                  numSubBlocks,
-                                      const AwhBiasParams* awhBiasParams,
+                                      const AwhBiasParams& awhBiasParams,
                                       EnergyUnit           energyUnit,
                                       real                 kTValue);
 
@@ -210,7 +211,7 @@ class AwhReader
 {
 public:
     //! Constructor
-    AwhReader(const AwhParams*  awhParams,
+    AwhReader(const AwhParams&  awhParams,
               int               numFileOptions,
               const t_filenm*   filenames,
               AwhGraphSelection awhGraphSelection,
@@ -246,18 +247,20 @@ enum class OutputFileType
 constexpr int maxAwhGraphs = 6;
 
 /*! \brief Constructs a legend for a standard awh output file */
-std::vector<std::string> makeLegend(const AwhBiasParams* awhBiasParams,
+std::vector<std::string> makeLegend(const AwhBiasParams& awhBiasParams,
                                     OutputFileType       outputFileType,
                                     size_t               numLegend)
 {
-    const std::array<std::string, maxAwhGraphs> legendBase = {
-        { "PMF", "Coord bias", "Coord distr", "Ref value distr", "Target ref value distr",
-          "Friction metric" }
-    };
+    const std::array<std::string, maxAwhGraphs> legendBase = { { "PMF",
+                                                                 "Coord bias",
+                                                                 "Coord distr",
+                                                                 "Ref value distr",
+                                                                 "Target ref value distr",
+                                                                 "Friction metric" } };
 
     std::vector<std::string> legend;
     /* Give legends to dimensions higher than the first */
-    for (int d = 1; d < awhBiasParams->ndim; d++)
+    for (int d = 1; d < awhBiasParams.ndim(); d++)
     {
         legend.push_back(gmx::formatString("dim%d", d));
     }
@@ -276,7 +279,7 @@ std::vector<std::string> makeLegend(const AwhBiasParams* awhBiasParams,
         }
         break;
         case OutputFileType::Friction:
-            for (int i0 = 0; i0 < awhBiasParams->ndim; i0++)
+            for (int i0 = 0; i0 < awhBiasParams.ndim(); i0++)
             {
                 for (int i1 = 0; i1 <= i0; i1++)
                 {
@@ -313,13 +316,13 @@ OutputFile::OutputFile(const std::string& filename, const std::string& baseTitle
 
 void OutputFile::initializeAwhOutputFile(int                  subblockStart,
                                          int                  numSubBlocks,
-                                         const AwhBiasParams* awhBiasParams,
+                                         const AwhBiasParams& awhBiasParams,
                                          AwhGraphSelection    graphSelection,
                                          EnergyUnit           energyUnit,
                                          real                 kTValue)
 {
     /* The first subblock with actual graph y-values is index 1 + ndim */
-    numDim_             = awhBiasParams->ndim;
+    numDim_             = awhBiasParams.ndim();
     firstGraphSubBlock_ = subblockStart + 1 + numDim_;
     if (graphSelection == AwhGraphSelection::All)
     {
@@ -344,20 +347,20 @@ void OutputFile::initializeAwhOutputFile(int                  subblockStart,
     yLabel_ = useKTForEnergy_ ? "(k\\sB\\NT)" : "(kJ/mol)";
     if (graphSelection == AwhGraphSelection::All)
     {
-        yLabel_ += gmx::formatString(", (nm\\S-%d\\N or rad\\S-%d\\N), (-)", awhBiasParams->ndim,
-                                     awhBiasParams->ndim);
+        yLabel_ += gmx::formatString(
+                ", (nm\\S-%d\\N or rad\\S-%d\\N), (-)", awhBiasParams.ndim(), awhBiasParams.ndim());
     }
 }
 
 /*! \brief Initializes the output file setup for the fricion output (note that the filename is not set here). */
 void OutputFile::initializeFrictionOutputFile(int                  subBlockStart,
                                               int                  numSubBlocks,
-                                              const AwhBiasParams* awhBiasParams,
+                                              const AwhBiasParams& awhBiasParams,
                                               EnergyUnit           energyUnit,
                                               real                 kTValue)
 {
     /* The first subblock with actual graph y-values is index 1 + ndim */
-    numDim_               = awhBiasParams->ndim;
+    numDim_               = awhBiasParams.ndim();
     int numTensorElements = (numDim_ * (numDim_ + 1)) / 2;
 
     /* The friction tensor elements are always the last subblocks */
@@ -390,7 +393,7 @@ void OutputFile::initializeFrictionOutputFile(int                  subBlockStart
     }
 }
 
-AwhReader::AwhReader(const AwhParams*  awhParams,
+AwhReader::AwhReader(const AwhParams&  awhParams,
                      int               numFileOptions,
                      const t_filenm*   filenames,
                      AwhGraphSelection awhGraphSelection,
@@ -411,30 +414,30 @@ AwhReader::AwhReader(const AwhParams*  awhParams,
 
     /* Keep track of the first subblock of this AWH */
     int subblockStart = 0;
-    for (int k = 0; k < awhParams->numBias; k++)
+    for (int k = 0; k < awhParams.numBias(); k++)
     {
-        AwhBiasParams* awhBiasParams = &awhParams->awhBiasParams[k];
+        const AwhBiasParams& awhBiasParams = awhParams.awhBiasParams()[k];
 
         int numSubBlocks = static_cast<int>(block->sub[subblockStart].fval[0]);
 
         std::unique_ptr<OutputFile> awhOutputFile(new OutputFile(
-                opt2fn("-o", numFileOptions, filenames), "AWH", awhParams->numBias, k));
+                opt2fn("-o", numFileOptions, filenames), "AWH", awhParams.numBias(), k));
 
-        awhOutputFile->initializeAwhOutputFile(subblockStart, numSubBlocks, awhBiasParams,
-                                               awhGraphSelection, energyUnit, kT);
+        awhOutputFile->initializeAwhOutputFile(
+                subblockStart, numSubBlocks, awhBiasParams, awhGraphSelection, energyUnit, kT);
 
         std::unique_ptr<OutputFile> frictionOutputFile;
         if (outputFriction)
         {
             frictionOutputFile = std::make_unique<OutputFile>(
-                    opt2fn("-fric", numFileOptions, filenames), "Friction tensor", awhParams->numBias, k);
+                    opt2fn("-fric", numFileOptions, filenames), "Friction tensor", awhParams.numBias(), k);
 
-            frictionOutputFile->initializeFrictionOutputFile(subblockStart, numSubBlocks,
-                                                             awhBiasParams, energyUnit, kT);
+            frictionOutputFile->initializeFrictionOutputFile(
+                    subblockStart, numSubBlocks, awhBiasParams, energyUnit, kT);
         }
 
-        biasOutputSetups_.emplace_back(BiasOutputSetup(subblockStart, std::move(awhOutputFile),
-                                                       std::move(frictionOutputFile)));
+        biasOutputSetups_.emplace_back(BiasOutputSetup(
+                subblockStart, std::move(awhOutputFile), std::move(frictionOutputFile)));
 
         subblockStart += numSubBlocks;
     }
@@ -487,8 +490,10 @@ void AwhReader::processAwhFrame(const t_enxblock& block, double time, const gmx_
             FILE* fpAwh = awhOutputFile.openBiasOutputFile(time, oenv);
 
             /* Now do the actual printing. Metadata in first subblock is treated separately. */
-            fprintf(fpAwh, "# AWH metadata: target error = %.2f kT = %.2f kJ/mol\n",
-                    block.sub[subStart].fval[1], block.sub[subStart].fval[1] * kT_);
+            fprintf(fpAwh,
+                    "# AWH metadata: target error = %.2f kT = %.2f kJ/mol\n",
+                    block.sub[subStart].fval[1],
+                    block.sub[subStart].fval[1] * kT_);
 
             fprintf(fpAwh, "# AWH metadata: log sample weight = %4.2f\n", block.sub[subStart].fval[2]);
 
@@ -548,8 +553,18 @@ int gmx_awh(int argc, char* argv[])
                        { efXVG, "-o", "awh", ffWRITE },
                        { efXVG, "-fric", "friction", ffOPTWR } };
     const int nfile = asize(fnm);
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END, nfile, fnm,
-                           asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(&argc,
+                           argv,
+                           PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END,
+                           nfile,
+                           fnm,
+                           asize(pa),
+                           pa,
+                           asize(desc),
+                           desc,
+                           0,
+                           nullptr,
+                           &oenv))
     {
         return 0;
     }
@@ -616,8 +631,13 @@ int gmx_awh(int argc, char* argv[])
                 AwhGraphSelection awhGraphSelection =
                         (moreGraphs ? AwhGraphSelection::All : AwhGraphSelection::Pmf);
                 EnergyUnit energyUnit = (kTUnit ? EnergyUnit::KT : EnergyUnit::KJPerMol);
-                awhReader = std::make_unique<AwhReader>(ir.awhParams, nfile, fnm, awhGraphSelection,
-                                                        energyUnit, BOLTZ * ir.opts.ref_t[0], block);
+                awhReader             = std::make_unique<AwhReader>(*ir.awhParams,
+                                                        nfile,
+                                                        fnm,
+                                                        awhGraphSelection,
+                                                        energyUnit,
+                                                        gmx::c_boltz * ir.opts.ref_t[0],
+                                                        block);
             }
 
             awhReader->processAwhFrame(*block, frame->t, oenv);
index 04c9dda231201530f19d03dc4f78e3730e915000..9f02e4aa89b714c8aa6513d3a9e74e28b9acf712 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -745,18 +745,24 @@ static void sample_coll_insert_sample(sample_coll_t* sc, samples_t* s, sample_ra
     GMX_ASSERT(sc->next->s, "Next not properly initialized!");
     if (sc->temp != s->temp)
     {
-        gmx_fatal(FARGS, "Temperatures in files %s and %s are not the same!", s->filename,
+        gmx_fatal(FARGS,
+                  "Temperatures in files %s and %s are not the same!",
+                  s->filename,
                   sc->next->s[0]->filename);
     }
     if (!lambda_vec_same(sc->native_lambda, s->native_lambda))
     {
-        gmx_fatal(FARGS, "Native lambda in files %s and %s are not the same (and they should be)!",
-                  s->filename, sc->next->s[0]->filename);
+        gmx_fatal(FARGS,
+                  "Native lambda in files %s and %s are not the same (and they should be)!",
+                  s->filename,
+                  sc->next->s[0]->filename);
     }
     if (!lambda_vec_same(sc->foreign_lambda, s->foreign_lambda))
     {
-        gmx_fatal(FARGS, "Foreign lambda in files %s and %s are not the same (and they should be)!",
-                  s->filename, sc->next->s[0]->filename);
+        gmx_fatal(FARGS,
+                  "Foreign lambda in files %s and %s are not the same (and they should be)!",
+                  s->filename,
+                  sc->next->s[0]->filename);
     }
 
     /* check if there's room */
@@ -1153,7 +1159,8 @@ static barres_t* barres_list_create(sim_data_t* sd, int* nres, gmx_bool use_dhdl
                       "them.\nAlternatively, use the -extp option if (and only if) the "
                       "Hamiltonian\ndepends linearly on lambda, which is NOT normally the "
                       "case.\n\n%s\n%s\n",
-                      descX, descY);
+                      descX,
+                      descY);
         }
 
         /* normal delta H */
@@ -1165,7 +1172,8 @@ static barres_t* barres_list_create(sim_data_t* sd, int* nres, gmx_bool use_dhdl
             gmx_fatal(FARGS,
                       "Could not find a set for foreign lambda (state X below)\nin the files for "
                       "main lambda (state Y below)\n\n%s\n%s\n",
-                      descX, descY);
+                      descX,
+                      descY);
         }
         if (!sc)
         {
@@ -1175,7 +1183,8 @@ static barres_t* barres_list_create(sim_data_t* sd, int* nres, gmx_bool use_dhdl
             gmx_fatal(FARGS,
                       "Could not find a set for foreign lambda (state X below)\nin the files for "
                       "main lambda (state Y below)\n\n%s\n%s\n",
-                      descX, descY);
+                      descX,
+                      descY);
         }
         br->a = scprev;
         br->b = sc;
@@ -1631,7 +1640,7 @@ static double calc_bar_lowlevel(sample_coll_t* ca, sample_coll_t* cb, double tem
     double DG0, DG1, DG2, dDG1;
     double n1, n2; /* numbers of samples as doubles */
 
-    kT   = BOLTZ * temp;
+    kT   = gmx::c_boltz * temp;
     beta = 1 / kT;
 
     /* count the numbers of samples */
@@ -1762,7 +1771,7 @@ static void calc_rel_entropy(sample_coll_t* ca, sample_coll_t* cb, double temp,
     double Wfac1, Wfac2;
     double n1, n2;
 
-    kT   = BOLTZ * temp;
+    kT   = gmx::c_boltz * temp;
     beta = 1 / kT;
 
     /* count the numbers of samples */
@@ -1876,7 +1885,7 @@ static void calc_dg_stddev(sample_coll_t* ca, sample_coll_t* cb, double temp, do
     double Wfac1, Wfac2;
     double n1, n2;
 
-    kT   = BOLTZ * temp;
+    kT   = gmx::c_boltz * temp;
     beta = 1 / kT;
 
     /* count the numbers of samples */
@@ -2592,7 +2601,8 @@ static gmx_bool subtitle2lambda(const char* subtitle, xvg_t* ba, const char* fn,
                 if (!lambda_components_check(lc, 0, "", 0))
                 {
                     gmx_fatal(FARGS,
-                              "lambda vector components in %s don't match those previously read", fn);
+                              "lambda vector components in %s don't match those previously read",
+                              fn);
                 }
             }
             else
@@ -2758,8 +2768,12 @@ static void read_bar_xvg(const char* fn, real* temp, sim_data_t* sd)
     snew(s, barsim->nset);
     for (i = 0; i < barsim->nset; i++)
     {
-        samples_init(s + i, &(barsim->native_lambda), &(barsim->lambda[i]), barsim->temp,
-                     lambda_vec_same(&(barsim->native_lambda), &(barsim->lambda[i])), fn);
+        samples_init(s + i,
+                     &(barsim->native_lambda),
+                     &(barsim->lambda[i]),
+                     barsim->temp,
+                     lambda_vec_same(&(barsim->native_lambda), &(barsim->lambda[i])),
+                     fn);
         s[i].du  = barsim->y[i];
         s[i].ndu = barsim->np[i];
         s[i].t   = barsim->t;
@@ -2770,8 +2784,11 @@ static void read_bar_xvg(const char* fn, real* temp, sim_data_t* sd)
         char buf[STRLEN];
 
         lambda_vec_print(s[0].native_lambda, buf, FALSE);
-        printf("%s: %.1f - %.1f; lambda = %s\n    dH/dl & foreign lambdas:\n", fn, s[0].t[0],
-               s[0].t[s[0].ndu - 1], buf);
+        printf("%s: %.1f - %.1f; lambda = %s\n    dH/dl & foreign lambdas:\n",
+               fn,
+               s[0].t[0],
+               s[0].t[s[0].ndu - 1],
+               buf);
         for (i = 0; i < barsim->nset; i++)
         {
             lambda_vec_print(s[i].foreign_lambda, buf, TRUE);
@@ -2798,8 +2815,9 @@ static void read_edr_rawdh_block(samples_t**   smp,
     int           startj;
 
     /* check the block types etc. */
-    if ((blk->nsub < 3) || (blk->sub[0].type != xdr_datatype_int) || (blk->sub[1].type != xdr_datatype_double)
-        || ((blk->sub[2].type != xdr_datatype_float) && (blk->sub[2].type != xdr_datatype_double))
+    if ((blk->nsub < 3) || (blk->sub[0].type != XdrDataType::Int)
+        || (blk->sub[1].type != XdrDataType::Double)
+        || ((blk->sub[2].type != XdrDataType::Float) && (blk->sub[2].type != XdrDataType::Double))
         || (blk->sub[0].nr < 1) || (blk->sub[1].nr < 1))
     {
         gmx_fatal(FARGS, "Unexpected/corrupted block data in file %s around time %f.", filename, start_time);
@@ -2866,7 +2884,7 @@ static void read_edr_rawdh_block(samples_t**   smp,
     /* and copy the data*/
     for (j = 0; j < blk->sub[2].nr; j++)
     {
-        if (blk->sub[2].type == xdr_datatype_float)
+        if (blk->sub[2].type == XdrDataType::Float)
         {
             s->du[startj + j] = blk->sub[2].fval[j];
         }
@@ -2898,8 +2916,8 @@ static samples_t* read_edr_hist_block(int*          nsamples,
     int           nbins[2];
 
     /* check the block types etc. */
-    if ((blk->nsub < 2) || (blk->sub[0].type != xdr_datatype_double)
-        || (blk->sub[1].type != xdr_datatype_int64) || (blk->sub[0].nr < 2) || (blk->sub[1].nr < 2))
+    if ((blk->nsub < 2) || (blk->sub[0].type != XdrDataType::Double)
+        || (blk->sub[1].type != XdrDataType::Int64) || (blk->sub[0].nr < 2) || (blk->sub[1].nr < 2))
     {
         gmx_fatal(FARGS, "Unexpected/corrupted block data in file %s around time %f", filename, start_time);
     }
@@ -3066,7 +3084,7 @@ static void read_barsim_edr(const char* fn, real* temp, sim_data_t* sd)
             if (fr->block[i].id == enxDHCOLL)
             {
                 nlam++;
-                if ((fr->block[i].nsub < 1) || (fr->block[i].sub[0].type != xdr_datatype_double)
+                if ((fr->block[i].nsub < 1) || (fr->block[i].sub[0].type != XdrDataType::Double)
                     || (fr->block[i].sub[0].nr < 5))
                 {
                     gmx_fatal(FARGS, "Unexpected block data in file %s", fn);
@@ -3086,7 +3104,8 @@ static void read_barsim_edr(const char* fn, real* temp, sim_data_t* sd)
                 if ((*temp != rtemp) && (*temp > 0))
                 {
                     gmx_fatal(FARGS,
-                              "Temperature in file %s different from earlier files or setting\n", fn);
+                              "Temperature in file %s different from earlier files or setting\n",
+                              fn);
                 }
                 *temp = rtemp;
 
@@ -3124,7 +3143,9 @@ static void read_barsim_edr(const char* fn, real* temp, sim_data_t* sd)
                     n_lambda_vec = fr->block[i].sub[1].ival[1];
                     for (j = 0; j < n_lambda_vec; j++)
                     {
-                        const char* name = efpt_singular_names[fr->block[i].sub[1].ival[1 + j]];
+                        const char* name =
+                                enumValueToStringSingular(static_cast<FreeEnergyPerturbationCouplingType>(
+                                        fr->block[i].sub[1].ival[1 + j]));
                         if (check)
                         {
                             /* check the components */
@@ -3189,12 +3210,18 @@ static void read_barsim_edr(const char* fn, real* temp, sim_data_t* sd)
                 gmx_fatal(FARGS,
                           "Native lambda not constant in file %s: started at %f, and becomes %f at "
                           "time %f",
-                          fn, native_lambda->val[0], start_lambda.val[0], start_time);
+                          fn,
+                          native_lambda->val[0],
+                          start_lambda.val[0],
+                          start_time);
             }
             /* check the number of samples against the previous number */
             if (((nblocks_raw + nblocks_hist) != nsamples) || (nlam != 1))
             {
-                gmx_fatal(FARGS, "Unexpected block count in %s: was %d, now %d\n", fn, nsamples + 1,
+                gmx_fatal(FARGS,
+                          "Unexpected block count in %s: was %d, now %d\n",
+                          fn,
+                          nsamples + 1,
                           nblocks_raw + nblocks_hist + nlam);
             }
             /* check whether last iterations's end time matches with
@@ -3226,8 +3253,15 @@ static void read_barsim_edr(const char* fn, real* temp, sim_data_t* sd)
                 if (type == dhbtDH || type == dhbtDHDL)
                 {
                     int ndu;
-                    read_edr_rawdh_block(&(samples_rawdh[k]), &ndu, &(fr->block[i]), start_time,
-                                         delta_time, native_lambda, rtemp, &last_t, fn);
+                    read_edr_rawdh_block(&(samples_rawdh[k]),
+                                         &ndu,
+                                         &(fr->block[i]),
+                                         start_time,
+                                         delta_time,
+                                         native_lambda,
+                                         rtemp,
+                                         &last_t,
+                                         fn);
                     npts[k] += ndu;
                     if (samples_rawdh[k])
                     {
@@ -3244,8 +3278,8 @@ static void read_barsim_edr(const char* fn, real* temp, sim_data_t* sd)
                     int        j;
                     int        nb = 0;
                     samples_t* s; /* this is where the data will go */
-                    s = read_edr_hist_block(&nb, &(fr->block[i]), start_time, delta_time,
-                                            native_lambda, rtemp, &last_t, fn);
+                    s = read_edr_hist_block(
+                            &nb, &(fr->block[i]), start_time, delta_time, native_lambda, rtemp, &last_t, fn);
                     nhists[k] += nb;
                     if (nb > 0)
                     {
@@ -3457,8 +3491,8 @@ int gmx_bar(int argc, char* argv[])
     double   sum_histrange_err = 0.; /* histogram range error */
     double   stat_err          = 0.; /* statistical error */
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc,
-                           0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -3551,8 +3585,8 @@ int gmx_bar(int argc, char* argv[])
     if (opt2bSet("-o", NFILE, fnm))
     {
         sprintf(buf, "%s (%s)", "\\DeltaG", "kT");
-        fpb = xvgropen_type(opt2fn("-o", NFILE, fnm), "Free energy differences", "\\lambda", buf,
-                            exvggtXYDY, oenv);
+        fpb = xvgropen_type(
+                opt2fn("-o", NFILE, fnm), "Free energy differences", "\\lambda", buf, exvggtXYDY, oenv);
     }
 
     fpi = nullptr;
@@ -3589,7 +3623,7 @@ int gmx_bar(int argc, char* argv[])
     }
 
     /* print results in kT */
-    kT = BOLTZ * temp;
+    kT = gmx::c_boltz * temp;
 
     printf("\nTemperature: %g K\n", temp);
 
index a55cde5f9596dcfa5865a0457f8f074bdbde9f93..c3daa88a03647dc1dc0ccc66f83a1bfc192fe1bb 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -39,6 +39,7 @@
 
 #include <cmath>
 #include <cstring>
+#include <vector>
 
 #include "gromacs/commandline/pargs.h"
 #include "gromacs/fileio/confio.h"
@@ -47,6 +48,7 @@
 #include "gromacs/gmxana/gmx_ana.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/rmpbc.h"
 #include "gromacs/topology/index.h"
@@ -156,14 +158,14 @@ static void calc_axes(rvec x[], t_atom atom[], const int gnx[], int* index[], gm
 
 static void dump_axes(t_trxstatus* status, t_trxframe* fr, t_atoms* outat, t_bundle* bun)
 {
-    t_trxframe   frout;
-    static rvec* xout = nullptr;
-    int          i;
+    t_trxframe                    frout;
+    static std::vector<gmx::RVec> xout;
+    int                           i;
 
     GMX_ASSERT(outat->nr >= bun->n, "");
-    if (xout == nullptr)
+    if (xout.empty())
     {
-        snew(xout, outat->nr);
+        xout.resize(outat->nr);
     }
 
     for (i = 0; i < bun->n; i++)
@@ -186,7 +188,7 @@ static void dump_axes(t_trxstatus* status, t_trxframe* fr, t_atoms* outat, t_bun
     frout.bAtoms = TRUE;
     frout.natoms = outat->nr;
     frout.atoms  = outat;
-    frout.x      = xout;
+    frout.x      = as_rvec_array(xout.data());
     write_trxframe(status, &frout, nullptr);
 }
 
@@ -257,8 +259,8 @@ int gmx_bundle(int argc, char* argv[])
     };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -298,31 +300,52 @@ int gmx_bundle(int argc, char* argv[])
     snew(bun.dir, n);
     snew(bun.len, n);
 
-    flen   = xvgropen(opt2fn("-ol", NFILE, fnm), "Axis lengths", output_env_get_xvgr_tlabel(oenv),
-                    "(nm)", oenv);
-    fdist  = xvgropen(opt2fn("-od", NFILE, fnm), "Distance of axis centers",
-                     output_env_get_xvgr_tlabel(oenv), "(nm)", oenv);
-    fz     = xvgropen(opt2fn("-oz", NFILE, fnm), "Z-shift of axis centers",
-                  output_env_get_xvgr_tlabel(oenv), "(nm)", oenv);
-    ftilt  = xvgropen(opt2fn("-ot", NFILE, fnm), "Axis tilts", output_env_get_xvgr_tlabel(oenv),
-                     "(degrees)", oenv);
-    ftiltr = xvgropen(opt2fn("-otr", NFILE, fnm), "Radial axis tilts",
-                      output_env_get_xvgr_tlabel(oenv), "(degrees)", oenv);
-    ftiltl = xvgropen(opt2fn("-otl", NFILE, fnm), "Lateral axis tilts",
-                      output_env_get_xvgr_tlabel(oenv), "(degrees)", oenv);
+    flen = xvgropen(
+            opt2fn("-ol", NFILE, fnm), "Axis lengths", output_env_get_xvgr_tlabel(oenv), "(nm)", oenv);
+    fdist = xvgropen(opt2fn("-od", NFILE, fnm),
+                     "Distance of axis centers",
+                     output_env_get_xvgr_tlabel(oenv),
+                     "(nm)",
+                     oenv);
+    fz    = xvgropen(opt2fn("-oz", NFILE, fnm),
+                  "Z-shift of axis centers",
+                  output_env_get_xvgr_tlabel(oenv),
+                  "(nm)",
+                  oenv);
+    ftilt = xvgropen(
+            opt2fn("-ot", NFILE, fnm), "Axis tilts", output_env_get_xvgr_tlabel(oenv), "(degrees)", oenv);
+    ftiltr = xvgropen(opt2fn("-otr", NFILE, fnm),
+                      "Radial axis tilts",
+                      output_env_get_xvgr_tlabel(oenv),
+                      "(degrees)",
+                      oenv);
+    ftiltl = xvgropen(opt2fn("-otl", NFILE, fnm),
+                      "Lateral axis tilts",
+                      output_env_get_xvgr_tlabel(oenv),
+                      "(degrees)",
+                      oenv);
 
     if (bKink)
     {
-        fkink = xvgropen(opt2fn("-ok", NFILE, fnm), "Kink angles", output_env_get_xvgr_tlabel(oenv),
-                         "(degrees)", oenv);
-        fkinkr = xvgropen(opt2fn("-okr", NFILE, fnm), "Radial kink angles",
-                          output_env_get_xvgr_tlabel(oenv), "(degrees)", oenv);
+        fkink  = xvgropen(opt2fn("-ok", NFILE, fnm),
+                         "Kink angles",
+                         output_env_get_xvgr_tlabel(oenv),
+                         "(degrees)",
+                         oenv);
+        fkinkr = xvgropen(opt2fn("-okr", NFILE, fnm),
+                          "Radial kink angles",
+                          output_env_get_xvgr_tlabel(oenv),
+                          "(degrees)",
+                          oenv);
         if (output_env_get_print_xvgr_codes(oenv))
         {
             fprintf(fkinkr, "@ subtitle \"+ = ) (   - = ( )\"\n");
         }
-        fkinkl = xvgropen(opt2fn("-okl", NFILE, fnm), "Lateral kink angles",
-                          output_env_get_xvgr_tlabel(oenv), "(degrees)", oenv);
+        fkinkl = xvgropen(opt2fn("-okl", NFILE, fnm),
+                          "Lateral kink angles",
+                          output_env_get_xvgr_tlabel(oenv),
+                          "(degrees)",
+                          oenv);
     }
 
     if (opt2bSet("-oa", NFILE, fnm))
@@ -370,27 +393,27 @@ int gmx_bundle(int argc, char* argv[])
             fprintf(flen, " %6g", bun.len[i]);
             fprintf(fdist, " %6g", norm(bun.mid[i]));
             fprintf(fz, " %6g", bun.mid[i][ZZ]);
-            fprintf(ftilt, " %6g", RAD2DEG * acos(bun.dir[i][ZZ]));
+            fprintf(ftilt, " %6g", gmx::c_rad2Deg * acos(bun.dir[i][ZZ]));
             comp = bun.mid[i][XX] * bun.dir[i][XX] + bun.mid[i][YY] * bun.dir[i][YY];
-            fprintf(ftiltr, " %6g", RAD2DEG * std::asin(comp / std::hypot(comp, bun.dir[i][ZZ])));
+            fprintf(ftiltr, " %6g", gmx::c_rad2Deg * std::asin(comp / std::hypot(comp, bun.dir[i][ZZ])));
             comp = bun.mid[i][YY] * bun.dir[i][XX] - bun.mid[i][XX] * bun.dir[i][YY];
-            fprintf(ftiltl, " %6g", RAD2DEG * std::asin(comp / std::hypot(comp, bun.dir[i][ZZ])));
+            fprintf(ftiltl, " %6g", gmx::c_rad2Deg * std::asin(comp / std::hypot(comp, bun.dir[i][ZZ])));
             if (bKink)
             {
                 rvec_sub(bun.end[0][i], bun.end[2][i], va);
                 rvec_sub(bun.end[2][i], bun.end[1][i], vb);
                 unitv(va, va);
                 unitv(vb, vb);
-                fprintf(fkink, " %6g", RAD2DEG * acos(iprod(va, vb)));
+                fprintf(fkink, " %6g", gmx::c_rad2Deg * acos(iprod(va, vb)));
                 cprod(va, vb, vc);
                 copy_rvec(bun.mid[i], vr);
                 vr[ZZ] = 0;
                 unitv(vr, vr);
-                fprintf(fkinkr, " %6g", RAD2DEG * std::asin(iprod(vc, vr)));
+                fprintf(fkinkr, " %6g", gmx::c_rad2Deg * std::asin(iprod(vc, vr)));
                 vl[XX] = vr[YY];
                 vl[YY] = -vr[XX];
                 vl[ZZ] = 0;
-                fprintf(fkinkl, " %6g", RAD2DEG * std::asin(iprod(vc, vl)));
+                fprintf(fkinkl, " %6g", gmx::c_rad2Deg * std::asin(iprod(vc, vl)));
             }
         }
         fprintf(flen, "\n");
index c30d7e641d61fd4e1668b4e998d8ece1b046e2f0..a23ff444a65202e395f23b1d633326d0ef8b72c6 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -130,7 +130,7 @@ static gmx_bool bAllowed(real phi, real psi)
 #define NPP asize(map)
     int x, y;
 
-#define INDEX(ppp) (((static_cast<int>(360 + (ppp)*RAD2DEG)) % 360) / 6)
+#define INDEX(ppp) (((static_cast<int>(360 + (ppp)*gmx::c_rad2Deg)) % 360) / 6)
     x = INDEX(phi);
     y = INDEX(psi);
 #undef INDEX
@@ -596,8 +596,7 @@ static void histogramming(FILE*                   log,
                     }
                     else if (debug)
                     {
-                        fprintf(debug, "Res. %d has imcomplete occupancy or bfacs > %g\n",
-                                dlist[i].resnr, bfac_max);
+                        fprintf(debug, "Res. %d has imcomplete occupancy or bfacs > %g\n", dlist[i].resnr, bfac_max);
                     }
                 }
                 else
@@ -767,8 +766,7 @@ static void histogramming(FILE*                   log,
                         break;
                     default:
                         sprintf(hisfile, "histo-chi%d%s", Dih - NONCHI + 1, residue_name);
-                        sprintf(title, "\\xc\\f{}\\s%d\\N Distribution for %s", Dih - NONCHI + 1,
-                                residue_name);
+                        sprintf(title, "\\xc\\f{}\\s%d\\N Distribution for %s", Dih - NONCHI + 1, residue_name);
                 }
                 std::strcpy(hhisfile, hisfile);
                 std::strcat(hhisfile, ".xvg");
@@ -934,16 +932,18 @@ static void do_rama(int                     nf,
             Psi = dlist[i].j0[edPsi];
             for (j = 0; (j < nf); j++)
             {
-                phi = RAD2DEG * dih[Phi][j];
-                psi = RAD2DEG * dih[Psi][j];
+                phi = gmx::c_rad2Deg * dih[Phi][j];
+                psi = gmx::c_rad2Deg * dih[Psi][j];
                 fprintf(fp, "%10g  %10g\n", phi, psi);
                 if (bViol)
                 {
-                    fprintf(gp, "%d\n", static_cast<int>(!bAllowed(dih[Phi][j], RAD2DEG * dih[Psi][j])));
+                    fprintf(gp,
+                            "%d\n",
+                            static_cast<int>(!bAllowed(dih[Phi][j], gmx::c_rad2Deg * dih[Psi][j])));
                 }
                 if (bOm)
                 {
-                    omega = RAD2DEG * dih[Om][j];
+                    omega = gmx::c_rad2Deg * dih[Om][j];
                     mat[static_cast<int>(((phi * NMAT) / 360) + gmx::exactDiv(NMAT, 2))]
                        [static_cast<int>(((psi * NMAT) / 360) + gmx::exactDiv(NMAT, 2))] += omega;
                 }
@@ -987,8 +987,24 @@ static void do_rama(int                     nf,
                 lo += 180;
                 hi += 180;
                 nlevels = 20;
-                write_xpm3(fp, 0, "Omega/Ramachandran Plot", "Deg", "Phi", "Psi", NMAT, NMAT, axis,
-                           axis, mat, lo, 180.0, hi, rlo, rmid, rhi, &nlevels);
+                write_xpm3(fp,
+                           0,
+                           "Omega/Ramachandran Plot",
+                           "Deg",
+                           "Phi",
+                           "Psi",
+                           NMAT,
+                           NMAT,
+                           axis,
+                           axis,
+                           mat,
+                           lo,
+                           180.0,
+                           hi,
+                           rlo,
+                           rmid,
+                           rhi,
+                           &nlevels);
                 gmx_ffclose(fp);
                 for (j = 0; (j < NMAT); j++)
                 {
@@ -1000,13 +1016,16 @@ static void do_rama(int                     nf,
         if ((has_dihedral(edChi1, &(dlist[i]))) && (has_dihedral(edChi2, &(dlist[i]))))
         {
             sprintf(fn, "ramaX1X2%s.xvg", dlist[i].name);
-            fp  = rama_file(fn, "\\8c\\4\\s1\\N-\\8c\\4\\s2\\N Ramachandran Plot",
-                           "\\8c\\4\\s1\\N (deg)", "\\8c\\4\\s2\\N (deg)", oenv);
+            fp  = rama_file(fn,
+                           "\\8c\\4\\s1\\N-\\8c\\4\\s2\\N Ramachandran Plot",
+                           "\\8c\\4\\s1\\N (deg)",
+                           "\\8c\\4\\s2\\N (deg)",
+                           oenv);
             Xi1 = dlist[i].j0[edChi1];
             Xi2 = dlist[i].j0[edChi2];
             for (j = 0; (j < nf); j++)
             {
-                fprintf(fp, "%10g  %10g\n", RAD2DEG * dih[Xi1][j], RAD2DEG * dih[Xi2][j]);
+                fprintf(fp, "%10g  %10g\n", gmx::c_rad2Deg * dih[Xi1][j], gmx::c_rad2Deg * dih[Xi2][j]);
             }
             xvgrclose(fp);
         }
@@ -1195,8 +1214,20 @@ static void order_params(FILE*                   log,
         z0 *= 10.0; /* nm -> angstrom */
         for (i = 0; (i < 10); i++)
         {
-            gmx_fprintf_pdb_atomline(fp, epdbATOM, atoms->nr + 1 + i, "CA", ' ', "LEG", ' ',
-                                     atoms->nres + 1, ' ', x0, y0, z0 + (1.2 * i), 0.0, -0.1 * i,
+            gmx_fprintf_pdb_atomline(fp,
+                                     PdbRecordType::Atom,
+                                     atoms->nr + 1 + i,
+                                     "CA",
+                                     ' ',
+                                     "LEG",
+                                     ' ',
+                                     atoms->nres + 1,
+                                     ' ',
+                                     x0,
+                                     y0,
+                                     z0 + (1.2 * i),
+                                     0.0,
+                                     -0.1 * i,
                                      "");
         }
         gmx_ffclose(fp);
@@ -1435,8 +1466,8 @@ int gmx_chi(int argc, char* argv[])
 
     npargs = asize(pa);
     ppa    = add_acf_pargs(&npargs, pa);
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa,
-                           asize(desc), desc, asize(bugs), bugs, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
         sfree(ppa);
         return 0;
@@ -1513,8 +1544,8 @@ int gmx_chi(int argc, char* argv[])
     snew(dih, ndih);
 
     /* COMPUTE ALL DIHEDRALS! */
-    read_ang_dih(ftp2fn(efTRX, NFILE, fnm), FALSE, TRUE, FALSE, bPBC, 1, &idum, &nf, &time, isize,
-                 index, &trans_frac, &aver_angle, dih, oenv);
+    read_ang_dih(
+            ftp2fn(efTRX, NFILE, fnm), FALSE, TRUE, FALSE, bPBC, 1, &idum, &nf, &time, isize, index, &trans_frac, &aver_angle, dih, oenv);
 
     dt = (time[nf - 1] - time[0]) / (nf - 1); /* might want this for corr or n. transit*/
     if (bCorr)
@@ -1536,9 +1567,27 @@ int gmx_chi(int argc, char* argv[])
     }
 
     /* Histogramming & J coupling constants & calc of S2 order params */
-    histogramming(log, nbin, &rt, nf, maxchi, dih, nlist, dlist, index, bPhi, bPsi, bOmega, bChi,
-                  bNormHisto, bSSHisto, ftp2fn(efDAT, NFILE, fnm), bfac_max, &atoms, bDo_jc,
-                  opt2fn("-jc", NFILE, fnm), oenv);
+    histogramming(log,
+                  nbin,
+                  &rt,
+                  nf,
+                  maxchi,
+                  dih,
+                  nlist,
+                  dlist,
+                  index,
+                  bPhi,
+                  bPsi,
+                  bOmega,
+                  bChi,
+                  bNormHisto,
+                  bSSHisto,
+                  ftp2fn(efDAT, NFILE, fnm),
+                  bfac_max,
+                  &atoms,
+                  bDo_jc,
+                  opt2fn("-jc", NFILE, fnm),
+                  oenv);
 
     /* transitions
      *
@@ -1567,12 +1616,39 @@ int gmx_chi(int argc, char* argv[])
     }
 
 
-    low_ana_dih_trans(bDo_ot, opt2fn("-ot", NFILE, fnm), bDo_oh, opt2fn("-oh", NFILE, fnm), maxchi, dih,
-                      nlist, dlist, nf, nactdih, grpname, multiplicity, time, FALSE, core_frac, oenv);
+    low_ana_dih_trans(bDo_ot,
+                      opt2fn("-ot", NFILE, fnm),
+                      bDo_oh,
+                      opt2fn("-oh", NFILE, fnm),
+                      maxchi,
+                      dih,
+                      nlist,
+                      dlist,
+                      nf,
+                      nactdih,
+                      grpname,
+                      multiplicity,
+                      time,
+                      FALSE,
+                      core_frac,
+                      oenv);
 
     /* Order parameters */
-    order_params(log, opt2fn("-o", NFILE, fnm), maxchi, nlist, dlist, ftp2fn_null(efPDB, NFILE, fnm),
-                 bfac_init, &atoms, x, pbcType, box, bPhi, bPsi, bChi, oenv);
+    order_params(log,
+                 opt2fn("-o", NFILE, fnm),
+                 maxchi,
+                 nlist,
+                 dlist,
+                 ftp2fn_null(efPDB, NFILE, fnm),
+                 bfac_init,
+                 &atoms,
+                 x,
+                 pbcType,
+                 box,
+                 bPhi,
+                 bPsi,
+                 bChi,
+                 oenv);
 
     /* Print ramachandran maps! */
     if (bRama)
@@ -1606,8 +1682,20 @@ int gmx_chi(int argc, char* argv[])
         }
         mk_chi_lookup(chi_lookup, maxchi, nlist, dlist);
 
-        get_chi_product_traj(dih, nf, nactdih, maxchi, dlist, time, chi_lookup, multiplicity, FALSE,
-                             bNormHisto, core_frac, bAll, opt2fn("-cp", NFILE, fnm), oenv);
+        get_chi_product_traj(dih,
+                             nf,
+                             nactdih,
+                             maxchi,
+                             dlist,
+                             time,
+                             chi_lookup,
+                             multiplicity,
+                             FALSE,
+                             bNormHisto,
+                             core_frac,
+                             bAll,
+                             opt2fn("-cp", NFILE, fnm),
+                             oenv);
 
         for (i = 0; i < nlist; i++)
         {
@@ -1618,8 +1706,7 @@ int gmx_chi(int argc, char* argv[])
     /* Correlation comes last because it messes up the angles */
     if (bCorr)
     {
-        do_dihcorr(opt2fn("-corr", NFILE, fnm), nf, ndih, dih, dt, nlist, dlist, time, maxchi, bPhi,
-                   bPsi, bChi, bOmega, oenv);
+        do_dihcorr(opt2fn("-corr", NFILE, fnm), nf, ndih, dih, dt, nlist, dlist, time, maxchi, bPhi, bPsi, bChi, bOmega, oenv);
     }
 
 
index 751c62f6d0f6515f428c441674a812634f64ffc0..80462f5540264ed5440702616369178b05bc34b6 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/fileio/matio.h"
 #include "gromacs/fileio/trxio.h"
 #include "gromacs/fileio/xvgr.h"
+#include "gromacs/gmxana/cluster_methods.h"
 #include "gromacs/gmxana/cmat.h"
 #include "gromacs/gmxana/gmx_ana.h"
 #include "gromacs/linearalgebra/eigensolver.h"
@@ -123,159 +124,6 @@ static inline void ffprintf_ss(FILE* fp1, FILE* fp2, char* buf, const char* fmt,
     lo_ffprintf(fp1, fp2, buf);
 }
 
-typedef struct
-{
-    int  ncl;
-    int* cl;
-} t_clusters;
-
-typedef struct
-{
-    int  nr;
-    int* nb;
-} t_nnb;
-
-static void mc_optimize(FILE*             log,
-                        t_mat*            m,
-                        real*             time,
-                        int               maxiter,
-                        int               nrandom,
-                        int               seed,
-                        real              kT,
-                        const char*       conv,
-                        gmx_output_env_t* oenv)
-{
-    FILE*  fp = nullptr;
-    real   ecur, enext, emin, prob, enorm;
-    int    i, j, iswap, jswap, nn, nuphill = 0;
-    t_mat* minimum;
-
-    if (seed == 0)
-    {
-        seed = static_cast<int>(gmx::makeRandomSeed());
-    }
-    gmx::DefaultRandomEngine rng(seed);
-
-    if (m->n1 != m->nn)
-    {
-        fprintf(stderr, "Can not do Monte Carlo optimization with a non-square matrix.\n");
-        return;
-    }
-    printf("\nDoing Monte Carlo optimization to find the smoothest trajectory\n");
-    printf("by reordering the frames to minimize the path between the two structures\n");
-    printf("that have the largest pairwise RMSD.\n");
-    printf("Using random seed %d.\n", seed);
-
-    iswap = jswap = -1;
-    enorm         = m->mat[0][0];
-    for (i = 0; (i < m->n1); i++)
-    {
-        for (j = 0; (j < m->nn); j++)
-        {
-            if (m->mat[i][j] > enorm)
-            {
-                enorm = m->mat[i][j];
-                iswap = i;
-                jswap = j;
-            }
-        }
-    }
-    if ((iswap == -1) || (jswap == -1))
-    {
-        fprintf(stderr, "Matrix contains identical values in all fields\n");
-        return;
-    }
-    swap_rows(m, 0, iswap);
-    swap_rows(m, m->n1 - 1, jswap);
-    emin = ecur = mat_energy(m);
-    printf("Largest distance %g between %d and %d. Energy: %g.\n", enorm, iswap, jswap, emin);
-
-    nn = m->nn;
-
-    /* Initiate and store global minimum */
-    minimum     = init_mat(nn, m->b1D);
-    minimum->nn = nn;
-    copy_t_mat(minimum, m);
-
-    if (nullptr != conv)
-    {
-        fp = xvgropen(conv, "Convergence of the MC optimization", "Energy", "Step", oenv);
-    }
-
-    gmx::UniformIntDistribution<int>   intDistNN(1, nn - 2); // [1,nn-2]
-    gmx::UniformRealDistribution<real> realDistOne;          // [0,1)
-
-    for (i = 0; (i < maxiter); i++)
-    {
-        /* Generate new swapping candidates */
-        do
-        {
-            iswap = intDistNN(rng);
-            jswap = intDistNN(rng);
-        } while ((iswap == jswap) || (iswap >= nn - 1) || (jswap >= nn - 1));
-
-        /* Apply swap and compute energy */
-        swap_rows(m, iswap, jswap);
-        enext = mat_energy(m);
-
-        /* Compute probability */
-        prob = 0;
-        if ((enext < ecur) || (i < nrandom))
-        {
-            prob = 1;
-            if (enext < emin)
-            {
-                /* Store global minimum */
-                copy_t_mat(minimum, m);
-                emin = enext;
-            }
-        }
-        else if (kT > 0)
-        {
-            /* Try Monte Carlo step */
-            prob = std::exp(-(enext - ecur) / (enorm * kT));
-        }
-
-        if (prob == 1 || realDistOne(rng) < prob)
-        {
-            if (enext > ecur)
-            {
-                nuphill++;
-            }
-
-            fprintf(log, "Iter: %d Swapped %4d and %4d (energy: %g prob: %g)\n", i, iswap, jswap,
-                    enext, prob);
-            if (nullptr != fp)
-            {
-                fprintf(fp, "%6d  %10g\n", i, enext);
-            }
-            ecur = enext;
-        }
-        else
-        {
-            swap_rows(m, jswap, iswap);
-        }
-    }
-    fprintf(log, "%d uphill steps were taken during optimization\n", nuphill);
-
-    /* Now swap the matrix to get it into global minimum mode */
-    copy_t_mat(m, minimum);
-
-    fprintf(log, "Global minimum energy %g\n", mat_energy(minimum));
-    fprintf(log, "Global minimum energy %g\n", mat_energy(m));
-    fprintf(log, "Swapped time and frame indices and RMSD to next neighbor:\n");
-    for (i = 0; (i < m->nn); i++)
-    {
-        fprintf(log, "%10g  %5d  %10g\n", time[m->m_ind[i]], m->m_ind[i],
-                (i < m->nn - 1) ? m->mat[m->m_ind[i]][m->m_ind[i + 1]] : 0);
-    }
-
-    if (nullptr != fp)
-    {
-        xvgrclose(fp);
-    }
-}
-
 static void calc_dist(int nind, rvec x[], real** d)
 {
     int   i, j;
@@ -315,429 +163,6 @@ static real rms_dist(int isize, real** d, real** d_r)
     return std::sqrt(r2);
 }
 
-static bool rms_dist_comp(const t_dist& a, const t_dist& b)
-{
-    return a.dist < b.dist;
-}
-
-static bool clust_id_comp(const t_clustid& a, const t_clustid& b)
-{
-    return a.clust < b.clust;
-}
-
-static bool nrnb_comp(const t_nnb& a, const t_nnb& b)
-{
-    /* return b<a, we want highest first */
-    return b.nr < a.nr;
-}
-
-static void gather(t_mat* m, real cutoff, t_clusters* clust)
-{
-    t_clustid* c;
-    t_dist*    d;
-    int        i, j, k, nn, cid, n1, diff;
-    gmx_bool   bChange;
-
-    /* First we sort the entries in the RMSD matrix */
-    n1 = m->nn;
-    nn = ((n1 - 1) * n1) / 2;
-    snew(d, nn);
-    for (i = k = 0; (i < n1); i++)
-    {
-        for (j = i + 1; (j < n1); j++, k++)
-        {
-            d[k].i    = i;
-            d[k].j    = j;
-            d[k].dist = m->mat[i][j];
-        }
-    }
-    if (k != nn)
-    {
-        gmx_incons("gather algortihm");
-    }
-    std::sort(d, d + nn, rms_dist_comp);
-
-    /* Now we make a cluster index for all of the conformations */
-    c = new_clustid(n1);
-
-    /* Now we check the closest structures, and equalize their cluster numbers */
-    fprintf(stderr, "Linking structures ");
-    do
-    {
-        fprintf(stderr, "*");
-        bChange = FALSE;
-        for (k = 0; (k < nn) && (d[k].dist < cutoff); k++)
-        {
-            diff = c[d[k].j].clust - c[d[k].i].clust;
-            if (diff)
-            {
-                bChange = TRUE;
-                if (diff > 0)
-                {
-                    c[d[k].j].clust = c[d[k].i].clust;
-                }
-                else
-                {
-                    c[d[k].i].clust = c[d[k].j].clust;
-                }
-            }
-        }
-    } while (bChange);
-    fprintf(stderr, "\nSorting and renumbering clusters\n");
-    /* Sort on cluster number */
-    std::sort(c, c + n1, clust_id_comp);
-
-    /* Renumber clusters */
-    cid = 1;
-    for (k = 1; k < n1; k++)
-    {
-        if (c[k].clust != c[k - 1].clust)
-        {
-            c[k - 1].clust = cid;
-            cid++;
-        }
-        else
-        {
-            c[k - 1].clust = cid;
-        }
-    }
-    c[k - 1].clust = cid;
-    if (debug)
-    {
-        for (k = 0; (k < n1); k++)
-        {
-            fprintf(debug, "Cluster index for conformation %d: %d\n", c[k].conf, c[k].clust);
-        }
-    }
-    clust->ncl = cid;
-    for (k = 0; k < n1; k++)
-    {
-        clust->cl[c[k].conf] = c[k].clust;
-    }
-
-    sfree(c);
-    sfree(d);
-}
-
-static gmx_bool jp_same(int** nnb, int i, int j, int P)
-{
-    gmx_bool bIn;
-    int      k, ii, jj, pp;
-
-    bIn = FALSE;
-    for (k = 0; nnb[i][k] >= 0; k++)
-    {
-        bIn = bIn || (nnb[i][k] == j);
-    }
-    if (!bIn)
-    {
-        return FALSE;
-    }
-
-    bIn = FALSE;
-    for (k = 0; nnb[j][k] >= 0; k++)
-    {
-        bIn = bIn || (nnb[j][k] == i);
-    }
-    if (!bIn)
-    {
-        return FALSE;
-    }
-
-    pp = 0;
-    for (ii = 0; nnb[i][ii] >= 0; ii++)
-    {
-        for (jj = 0; nnb[j][jj] >= 0; jj++)
-        {
-            if ((nnb[i][ii] == nnb[j][jj]) && (nnb[i][ii] != -1))
-            {
-                pp++;
-            }
-        }
-    }
-
-    return (pp >= P);
-}
-
-static void jarvis_patrick(int n1, real** mat, int M, int P, real rmsdcut, t_clusters* clust)
-{
-    t_dist*    row;
-    t_clustid* c;
-    int**      nnb;
-    int        i, j, k, cid, diff, maxval;
-    gmx_bool   bChange;
-    real**     mcpy = nullptr;
-
-    if (rmsdcut < 0)
-    {
-        rmsdcut = 10000;
-    }
-
-    /* First we sort the entries in the RMSD matrix row by row.
-     * This gives us the nearest neighbor list.
-     */
-    snew(nnb, n1);
-    snew(row, n1);
-    for (i = 0; (i < n1); i++)
-    {
-        for (j = 0; (j < n1); j++)
-        {
-            row[j].j    = j;
-            row[j].dist = mat[i][j];
-        }
-        std::sort(row, row + n1, rms_dist_comp);
-        if (M > 0)
-        {
-            /* Put the M nearest neighbors in the list */
-            snew(nnb[i], M + 1);
-            for (j = k = 0; (k < M) && (j < n1) && (mat[i][row[j].j] < rmsdcut); j++)
-            {
-                if (row[j].j != i)
-                {
-                    nnb[i][k] = row[j].j;
-                    k++;
-                }
-            }
-            nnb[i][k] = -1;
-        }
-        else
-        {
-            /* Put all neighbors nearer than rmsdcut in the list */
-            maxval = 0;
-            k      = 0;
-            for (j = 0; (j < n1) && (mat[i][row[j].j] < rmsdcut); j++)
-            {
-                if (row[j].j != i)
-                {
-                    if (k >= maxval)
-                    {
-                        maxval += 10;
-                        srenew(nnb[i], maxval);
-                    }
-                    nnb[i][k] = row[j].j;
-                    k++;
-                }
-            }
-            if (k == maxval)
-            {
-                srenew(nnb[i], maxval + 1);
-            }
-            nnb[i][k] = -1;
-        }
-    }
-    sfree(row);
-    if (debug)
-    {
-        fprintf(debug, "Nearest neighborlist. M = %d, P = %d\n", M, P);
-        for (i = 0; (i < n1); i++)
-        {
-            fprintf(debug, "i:%5d nbs:", i);
-            for (j = 0; nnb[i][j] >= 0; j++)
-            {
-                fprintf(debug, "%5d[%5.3f]", nnb[i][j], mat[i][nnb[i][j]]);
-            }
-            fprintf(debug, "\n");
-        }
-    }
-
-    c = new_clustid(n1);
-    fprintf(stderr, "Linking structures ");
-    /* Use mcpy for temporary storage of booleans */
-    mcpy = mk_matrix(n1, n1, FALSE);
-    for (i = 0; i < n1; i++)
-    {
-        for (j = i + 1; j < n1; j++)
-        {
-            mcpy[i][j] = static_cast<real>(jp_same(nnb, i, j, P));
-        }
-    }
-    do
-    {
-        fprintf(stderr, "*");
-        bChange = FALSE;
-        for (i = 0; i < n1; i++)
-        {
-            for (j = i + 1; j < n1; j++)
-            {
-                if (mcpy[i][j] != 0.0F)
-                {
-                    diff = c[j].clust - c[i].clust;
-                    if (diff)
-                    {
-                        bChange = TRUE;
-                        if (diff > 0)
-                        {
-                            c[j].clust = c[i].clust;
-                        }
-                        else
-                        {
-                            c[i].clust = c[j].clust;
-                        }
-                    }
-                }
-            }
-        }
-    } while (bChange);
-
-    fprintf(stderr, "\nSorting and renumbering clusters\n");
-    /* Sort on cluster number */
-    std::sort(c, c + n1, clust_id_comp);
-
-    /* Renumber clusters */
-    cid = 1;
-    for (k = 1; k < n1; k++)
-    {
-        if (c[k].clust != c[k - 1].clust)
-        {
-            c[k - 1].clust = cid;
-            cid++;
-        }
-        else
-        {
-            c[k - 1].clust = cid;
-        }
-    }
-    c[k - 1].clust = cid;
-    clust->ncl     = cid;
-    for (k = 0; k < n1; k++)
-    {
-        clust->cl[c[k].conf] = c[k].clust;
-    }
-    if (debug)
-    {
-        for (k = 0; (k < n1); k++)
-        {
-            fprintf(debug, "Cluster index for conformation %d: %d\n", c[k].conf, c[k].clust);
-        }
-    }
-
-    done_matrix(n1, &mcpy);
-
-    sfree(c);
-    for (i = 0; (i < n1); i++)
-    {
-        sfree(nnb[i]);
-    }
-    sfree(nnb);
-}
-
-static void dump_nnb(FILE* fp, const char* title, int n1, t_nnb* nnb)
-{
-    int i, j;
-
-    /* dump neighbor list */
-    fprintf(fp, "%s", title);
-    for (i = 0; (i < n1); i++)
-    {
-        fprintf(fp, "i:%5d #:%5d nbs:", i, nnb[i].nr);
-        for (j = 0; j < nnb[i].nr; j++)
-        {
-            fprintf(fp, "%5d", nnb[i].nb[j]);
-        }
-        fprintf(fp, "\n");
-    }
-}
-
-static void gromos(int n1, real** mat, real rmsdcut, t_clusters* clust)
-{
-    t_nnb* nnb;
-    int    i, j, k, j1, maxval;
-
-    /* Put all neighbors nearer than rmsdcut in the list */
-    fprintf(stderr, "Making list of neighbors within cutoff ");
-    snew(nnb, n1);
-    for (i = 0; (i < n1); i++)
-    {
-        maxval = 0;
-        k      = 0;
-        /* put all neighbors within cut-off in list */
-        for (j = 0; j < n1; j++)
-        {
-            if (mat[i][j] < rmsdcut)
-            {
-                if (k >= maxval)
-                {
-                    maxval += 10;
-                    srenew(nnb[i].nb, maxval);
-                }
-                nnb[i].nb[k] = j;
-                k++;
-            }
-        }
-        /* store nr of neighbors, we'll need that */
-        nnb[i].nr = k;
-        if (i % (1 + n1 / 100) == 0)
-        {
-            fprintf(stderr, "%3d%%\b\b\b\b", (i * 100 + 1) / n1);
-        }
-    }
-    fprintf(stderr, "%3d%%\n", 100);
-
-    /* sort neighbor list on number of neighbors, largest first */
-    std::sort(nnb, nnb + n1, nrnb_comp);
-
-    if (debug)
-    {
-        dump_nnb(debug, "Nearest neighborlist after sort.\n", n1, nnb);
-    }
-
-    /* turn first structure with all its neighbors (largest) into cluster
-       remove them from pool of structures and repeat for all remaining */
-    fprintf(stderr, "Finding clusters %4d", 0);
-    /* cluster id's start at 1: */
-    k = 1;
-    while (nnb[0].nr)
-    {
-        /* set cluster id (k) for first item in neighborlist */
-        for (j = 0; j < nnb[0].nr; j++)
-        {
-            clust->cl[nnb[0].nb[j]] = k;
-        }
-        /* mark as done */
-        nnb[0].nr = 0;
-        sfree(nnb[0].nb);
-
-        /* adjust number of neighbors for others, taking removals into account: */
-        for (i = 1; i < n1 && nnb[i].nr; i++)
-        {
-            j1 = 0;
-            for (j = 0; j < nnb[i].nr; j++)
-            {
-                /* if this neighbor wasn't removed */
-                if (clust->cl[nnb[i].nb[j]] == 0)
-                {
-                    /* shift the rest (j1<=j) */
-                    nnb[i].nb[j1] = nnb[i].nb[j];
-                    /* next */
-                    j1++;
-                }
-            }
-            /* now j1 is the new number of neighbors */
-            nnb[i].nr = j1;
-        }
-        /* sort again on nnb[].nr, because we have new # neighbors: */
-        /* but we only need to sort upto i, i.e. when nnb[].nr>0 */
-        std::sort(nnb, nnb + i, nrnb_comp);
-
-        fprintf(stderr, "\b\b\b\b%4d", k);
-        /* new cluster id */
-        k++;
-    }
-    fprintf(stderr, "\n");
-    sfree(nnb);
-    if (debug)
-    {
-        fprintf(debug, "Clusters (%d):\n", k);
-        for (i = 0; i < n1; i++)
-        {
-            fprintf(debug, " %3d", clust->cl[i]);
-        }
-        fprintf(debug, "\n");
-    }
-
-    clust->ncl = k - 1;
-}
-
 static rvec** read_whole_trj(const char*             fn,
                              int                     isize,
                              const int               index[],
@@ -942,16 +367,33 @@ static void ana_trans(t_clusters*             clust,
                                                  trans[clust->cl[i] - 1][clust->cl[i - 1] - 1]));
         }
     }
-    ffprintf_dd(stderr, log, buf,
+    ffprintf_dd(stderr,
+                log,
+                buf,
                 "Counted %d transitions in total, "
                 "max %d between two specific clusters\n",
-                ntranst, maxtrans);
+                ntranst,
+                maxtrans);
     if (transfn)
     {
         fp = gmx_ffopen(transfn, "w");
         i  = std::min(maxtrans + 1, 80);
-        write_xpm(fp, 0, "Cluster Transitions", "# transitions", "from cluster", "to cluster",
-                  clust->ncl, clust->ncl, axis, axis, trans, 0, maxtrans, rlo, rhi, &i);
+        write_xpm(fp,
+                  0,
+                  "Cluster Transitions",
+                  "# transitions",
+                  "from cluster",
+                  "to cluster",
+                  clust->ncl,
+                  clust->ncl,
+                  axis,
+                  axis,
+                  trans,
+                  0,
+                  maxtrans,
+                  rlo,
+                  rhi,
+                  &i);
         gmx_ffclose(fp);
     }
     if (ntransfn)
@@ -1026,8 +468,12 @@ static void analyze_clusters(int                     nf,
             trxsfn = parse_filename(trxfn, std::max(write_ncl, clust->ncl));
             snew(bWrite, nf);
         }
-        ffprintf_ss(stderr, log, buf, "Writing %s structure for each cluster to %s\n",
-                    bAverage ? "average" : "middle", trxfn);
+        ffprintf_ss(stderr,
+                    log,
+                    buf,
+                    "Writing %s structure for each cluster to %s\n",
+                    bAverage ? "average" : "middle",
+                    trxfn);
         if (write_ncl)
         {
             /* find out what we want to tell the user:
@@ -1107,7 +553,12 @@ static void analyze_clusters(int                     nf,
     }
 
     snew(structure, nf);
-    fprintf(log, "\n%3s | %3s  %4s | %6s %4s | cluster members\n", "cl.", "#st", "rmsd", "middle",
+    fprintf(log,
+            "\n%3s | %3s  %4s | %6s %4s | cluster members\n",
+            "cl.",
+            "#st",
+            "rmsd",
+            "middle",
             "rmsd");
     for (cl = 1; cl <= clust->ncl; cl++)
     {
@@ -1266,8 +717,16 @@ static void analyze_clusters(int                     nf,
                     }
                     if (bWrite[i])
                     {
-                        write_trx(trxsout, iosize, outidx, atoms, i, time[structure[i]],
-                                  boxes[structure[i]], xx[structure[i]], nullptr, nullptr);
+                        write_trx(trxsout,
+                                  iosize,
+                                  outidx,
+                                  atoms,
+                                  i,
+                                  time[structure[i]],
+                                  boxes[structure[i]],
+                                  xx[structure[i]],
+                                  nullptr,
+                                  nullptr);
                     }
                 }
                 close_trx(trxsout);
@@ -1565,8 +1024,18 @@ int gmx_cluster(int argc, char* argv[])
     };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm,
-                           asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(&argc,
+                           argv,
+                           PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT,
+                           NFILE,
+                           fnm,
+                           asize(pa),
+                           pa,
+                           asize(desc),
+                           desc,
+                           0,
+                           nullptr,
+                           &oenv))
     {
         return 0;
     }
@@ -1586,8 +1055,10 @@ int gmx_cluster(int argc, char* argv[])
     }
     if (bReadMat && output_env_get_time_factor(oenv) != 1)
     {
-        fprintf(stderr, "\nWarning: assuming the time unit in %s is %s\n",
-                opt2fn("-dm", NFILE, fnm), output_env_get_time_unit(oenv).c_str());
+        fprintf(stderr,
+                "\nWarning: assuming the time unit in %s is %s\n",
+                opt2fn("-dm", NFILE, fnm),
+                output_env_get_time_unit(oenv).c_str());
     }
     if (trx_out_fn && !bReadTraj)
     {
@@ -1766,7 +1237,9 @@ int gmx_cluster(int argc, char* argv[])
             gmx_fatal(FARGS,
                       "Matrix size (%dx%d) does not match the number of "
                       "frames (%d)",
-                      readmat[0].nx, readmat[0].ny, nf);
+                      readmat[0].nx,
+                      readmat[0].ny,
+                      nf);
         }
 
         nf = readmat[0].nx;
@@ -1863,7 +1336,9 @@ int gmx_cluster(int argc, char* argv[])
         fprintf(stderr,
                 "WARNING: rmsd cutoff %g is outside range of rmsd values "
                 "%g to %g\n",
-                rmsdcut, rms->minrms, rms->maxrms);
+                rmsdcut,
+                rms->minrms,
+                rms->maxrms);
     }
     if (bAnalyze && (rmsmin < rms->minrms))
     {
@@ -1910,8 +1385,11 @@ int gmx_cluster(int argc, char* argv[])
             eigensolver(eigenvectors, nf, 0, nf, eigenvalues, rms->mat[0]);
             sfree(eigenvectors);
 
-            fp = xvgropen(opt2fn("-ev", NFILE, fnm), "RMSD matrix Eigenvalues", "Eigenvector index",
-                          "Eigenvalues (nm\\S2\\N)", oenv);
+            fp = xvgropen(opt2fn("-ev", NFILE, fnm),
+                          "RMSD matrix Eigenvalues",
+                          "Eigenvector index",
+                          "Eigenvalues (nm\\S2\\N)",
+                          oenv);
             for (i = 0; (i < nf); i++)
             {
                 fprintf(fp, "%10d  %10g\n", i, eigenvalues[i]);
@@ -1957,12 +1435,36 @@ int gmx_cluster(int argc, char* argv[])
             copy_rvec(xtps[index[i]], usextps[i]);
         }
         useatoms.nr = isize;
-        analyze_clusters(nf, &clust, rms->mat, isize, &useatoms, usextps, mass, xx, time, boxes,
-                         frameindices, ifsize, fitidx, iosize, outidx,
-                         bReadTraj ? trx_out_fn : nullptr, opt2fn_null("-sz", NFILE, fnm),
-                         opt2fn_null("-tr", NFILE, fnm), opt2fn_null("-ntr", NFILE, fnm),
-                         opt2fn_null("-clid", NFILE, fnm), opt2fn_null("-clndx", NFILE, fnm),
-                         bAverage, write_ncl, write_nst, rmsmin, bFit, log, rlo_bot, rhi_bot, oenv);
+        analyze_clusters(nf,
+                         &clust,
+                         rms->mat,
+                         isize,
+                         &useatoms,
+                         usextps,
+                         mass,
+                         xx,
+                         time,
+                         boxes,
+                         frameindices,
+                         ifsize,
+                         fitidx,
+                         iosize,
+                         outidx,
+                         bReadTraj ? trx_out_fn : nullptr,
+                         opt2fn_null("-sz", NFILE, fnm),
+                         opt2fn_null("-tr", NFILE, fnm),
+                         opt2fn_null("-ntr", NFILE, fnm),
+                         opt2fn_null("-clid", NFILE, fnm),
+                         opt2fn_null("-clndx", NFILE, fnm),
+                         bAverage,
+                         write_ncl,
+                         write_nst,
+                         rmsmin,
+                         bFit,
+                         log,
+                         rlo_bot,
+                         rhi_bot,
+                         oenv);
         sfree(boxes);
         sfree(frameindices);
     }
@@ -1987,9 +1489,22 @@ int gmx_cluster(int argc, char* argv[])
     fprintf(stderr, "Writing rms distance/clustering matrix ");
     if (bReadMat)
     {
-        write_xpm(fp, 0, readmat[0].title, readmat[0].legend, readmat[0].label_x,
-                  readmat[0].label_y, nf, nf, readmat[0].axis_x.data(), readmat[0].axis_y.data(),
-                  rms->mat, 0.0, rms->maxrms, rlo_top, rhi_top, &nlevels);
+        write_xpm(fp,
+                  0,
+                  readmat[0].title,
+                  readmat[0].legend,
+                  readmat[0].label_x,
+                  readmat[0].label_y,
+                  nf,
+                  nf,
+                  readmat[0].axis_x.data(),
+                  readmat[0].axis_y.data(),
+                  rms->mat,
+                  0.0,
+                  rms->maxrms,
+                  rlo_top,
+                  rhi_top,
+                  &nlevels);
     }
     else
     {
@@ -1997,14 +1512,47 @@ int gmx_cluster(int argc, char* argv[])
         auto title = gmx::formatString("RMS%sDeviation / Cluster Index", bRMSdist ? " Distance " : " ");
         if (minstruct > 1)
         {
-            write_xpm_split(fp, 0, title, "RMSD (nm)", timeLabel, timeLabel, nf, nf, time, time,
-                            rms->mat, 0.0, rms->maxrms, &nlevels, rlo_top, rhi_top, 0.0, ncluster,
-                            &ncluster, TRUE, rlo_bot, rhi_bot);
+            write_xpm_split(fp,
+                            0,
+                            title,
+                            "RMSD (nm)",
+                            timeLabel,
+                            timeLabel,
+                            nf,
+                            nf,
+                            time,
+                            time,
+                            rms->mat,
+                            0.0,
+                            rms->maxrms,
+                            &nlevels,
+                            rlo_top,
+                            rhi_top,
+                            0.0,
+                            ncluster,
+                            &ncluster,
+                            TRUE,
+                            rlo_bot,
+                            rhi_bot);
         }
         else
         {
-            write_xpm(fp, 0, title, "RMSD (nm)", timeLabel, timeLabel, nf, nf, time, time, rms->mat,
-                      0.0, rms->maxrms, rlo_top, rhi_top, &nlevels);
+            write_xpm(fp,
+                      0,
+                      title,
+                      "RMSD (nm)",
+                      timeLabel,
+                      timeLabel,
+                      nf,
+                      nf,
+                      time,
+                      time,
+                      rms->mat,
+                      0.0,
+                      rms->maxrms,
+                      rlo_top,
+                      rhi_top,
+                      &nlevels);
         }
     }
     fprintf(stderr, "\n");
@@ -2014,8 +1562,22 @@ int gmx_cluster(int argc, char* argv[])
         fp             = opt2FILE("-om", NFILE, fnm, "w");
         auto timeLabel = output_env_get_time_label(oenv);
         auto title     = gmx::formatString("RMS%sDeviation", bRMSdist ? " Distance " : " ");
-        write_xpm(fp, 0, title, "RMSD (nm)", timeLabel, timeLabel, nf, nf, time, time, orig->mat,
-                  0.0, orig->maxrms, rlo_top, rhi_top, &nlevels);
+        write_xpm(fp,
+                  0,
+                  title,
+                  "RMSD (nm)",
+                  timeLabel,
+                  timeLabel,
+                  nf,
+                  nf,
+                  time,
+                  time,
+                  orig->mat,
+                  0.0,
+                  orig->maxrms,
+                  rlo_top,
+                  rhi_top,
+                  &nlevels);
         gmx_ffclose(fp);
         done_mat(&orig);
         sfree(orig);
index fd64ddf7f9e8c59a4d11f76f86d5f25a90ad0051..154728d519c9ad3584ca564297e4543b9f019b06 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2007, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -96,7 +96,7 @@ static void clust_size(const char*             ndx,
     /* Topology stuff */
     t_trxframe    fr;
     TpxFileHeader tpxh;
-    gmx_mtop_t*   mtop    = nullptr;
+    gmx_mtop_t    mtop;
     PbcType       pbcType = PbcType::Unset;
     int           ii, jj;
     real          temp, tfac;
@@ -127,13 +127,12 @@ static void clust_size(const char*             ndx,
 
     if (tpr)
     {
-        mtop = new gmx_mtop_t;
         tpxh = readTpxHeader(tpr, true);
         if (tpxh.natoms != natoms)
         {
             gmx_fatal(FARGS, "tpr (%d atoms) and trajectory (%d atoms) do not match!", tpxh.natoms, natoms);
         }
-        pbcType = read_tpx(tpr, nullptr, nullptr, &natoms, nullptr, nullptr, mtop);
+        pbcType = read_tpx(tpr, nullptr, nullptr, &natoms, nullptr, nullptr, &mtop);
     }
     if (ndf <= -1)
     {
@@ -151,8 +150,8 @@ static void clust_size(const char*             ndx,
         {
             printf("Using molecules rather than atoms. Not reading index file %s\n", ndx);
         }
-        GMX_RELEASE_ASSERT(mtop != nullptr, "Trying to access mtop->mols from NULL mtop pointer");
-        mols = gmx_mtop_molecules(*mtop);
+        GMX_RELEASE_ASSERT(tpr, "Cannot access topology without having read it from TPR");
+        mols = gmx_mtop_molecules(mtop);
 
         /* Make dummy index */
         nindex = mols.numBlocks();
@@ -266,8 +265,10 @@ static void clust_size(const char*             ndx,
                                 {
                                     if (clust_size[cj] <= 0)
                                     {
-                                        gmx_fatal(FARGS, "negative cluster size %d for element %d",
-                                                  clust_size[cj], cj);
+                                        gmx_fatal(FARGS,
+                                                  "negative cluster size %d for element %d",
+                                                  clust_size[cj],
+                                                  cj);
                                     }
                                     clust_size[cj]--;
                                     clust_index[k] = ci;
@@ -352,7 +353,7 @@ static void clust_size(const char*             ndx,
                             ekin += 0.5 * m * iprod(v[ai], v[ai]);
                         }
                     }
-                    temp = (ekin * 2.0) / (3.0 * tfac * max_clust_size * BOLTZ);
+                    temp = (ekin * 2.0) / (3.0 * tfac * max_clust_size * gmx::c_boltz);
                     fprintf(tp, "%10.3f  %10.3f\n", frameTime, temp);
                 }
             }
@@ -430,8 +431,24 @@ static void clust_size(const char*             ndx,
     fprintf(stderr, "cmid: %g, cmax: %g, max_size: %d\n", cmid, cmax, max_size);
     cmid = 1;
     fp   = gmx_ffopen(xpm, "w");
-    write_xpm3(fp, 0, "Cluster size distribution", "# clusters", timeLabel, "Size", n_x, max_size,
-               t_x, t_y, cs_dist, 0, cmid, cmax, rlo, rmid, rhi, &nlevels);
+    write_xpm3(fp,
+               0,
+               "Cluster size distribution",
+               "# clusters",
+               timeLabel,
+               "Size",
+               n_x,
+               max_size,
+               t_x,
+               t_y,
+               cs_dist,
+               0,
+               cmid,
+               cmax,
+               rlo,
+               rmid,
+               rhi,
+               &nlevels);
     gmx_ffclose(fp);
     cmid = 100.0;
     cmax = 0.0;
@@ -449,10 +466,25 @@ static void clust_size(const char*             ndx,
     }
     fprintf(stderr, "cmid: %g, cmax: %g, max_size: %d\n", cmid, cmax, max_size);
     fp = gmx_ffopen(xpmw, "w");
-    write_xpm3(fp, 0, "Weighted cluster size distribution", "Fraction", timeLabel, "Size", n_x,
-               max_size, t_x, t_y, cs_dist, 0, cmid, cmax, rlo, rmid, rhi, &nlevels);
+    write_xpm3(fp,
+               0,
+               "Weighted cluster size distribution",
+               "Fraction",
+               timeLabel,
+               "Size",
+               n_x,
+               max_size,
+               t_x,
+               t_y,
+               cs_dist,
+               0,
+               cmid,
+               cmax,
+               rlo,
+               rmid,
+               rhi,
+               &nlevels);
     gmx_ffclose(fp);
-    delete mtop;
     sfree(t_x);
     sfree(t_y);
     for (i = 0; (i < n_x); i++)
@@ -546,8 +578,8 @@ int gmx_clustsize(int argc, char* argv[])
     };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm,
-                           NPA, pa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, NPA, pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -566,10 +598,26 @@ int gmx_clustsize(int argc, char* argv[])
         gmx_fatal(FARGS, "You need a tpr file for the -mol option");
     }
 
-    clust_size(fnNDX, ftp2fn(efTRX, NFILE, fnm), opt2fn("-o", NFILE, fnm), opt2fn("-ow", NFILE, fnm),
-               opt2fn("-nc", NFILE, fnm), opt2fn("-ac", NFILE, fnm), opt2fn("-mc", NFILE, fnm),
-               opt2fn("-hc", NFILE, fnm), opt2fn("-temp", NFILE, fnm), opt2fn("-mcn", NFILE, fnm),
-               bMol, bPBC, fnTPR, cutoff, nskip, nlevels, rgblo, rgbhi, ndf, oenv);
+    clust_size(fnNDX,
+               ftp2fn(efTRX, NFILE, fnm),
+               opt2fn("-o", NFILE, fnm),
+               opt2fn("-ow", NFILE, fnm),
+               opt2fn("-nc", NFILE, fnm),
+               opt2fn("-ac", NFILE, fnm),
+               opt2fn("-mc", NFILE, fnm),
+               opt2fn("-hc", NFILE, fnm),
+               opt2fn("-temp", NFILE, fnm),
+               opt2fn("-mcn", NFILE, fnm),
+               bMol,
+               bPBC,
+               fnTPR,
+               cutoff,
+               nskip,
+               nlevels,
+               rgblo,
+               rgbhi,
+               ndf,
+               oenv);
 
     output_env_done(oenv);
 
index 213aaf11304477045b1329da1721281a2920a46e..6b157f347477bc0fe8bde5ac325374314a33cf62 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,7 @@
 #include "gromacs/gmxana/gmx_ana.h"
 #include "gromacs/math/do_fit.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/rmpbc.h"
@@ -280,7 +281,12 @@ static int find_next_match_res(int*       rnr1,
     {
         if (debug)
         {
-            fprintf(debug, "%d.%d.%dX%sX%s", dx, rr1, rr2, *resinfo1[index1[rr1 + 1]].name,
+            fprintf(debug,
+                    "%d.%d.%dX%sX%s",
+                    dx,
+                    rr1,
+                    rr2,
+                    *resinfo1[index1[rr1 + 1]].name,
                     *resinfo2[index2[rr2 + 1]].name);
         }
         dx = 1;
@@ -417,8 +423,16 @@ static void find_matching_names(int*           isize1,
             }
             if (debug)
             {
-                fprintf(debug, " -> %s%d-%s%d %s%d-%s%d", *resinfo1[rnr1].name, rnr1, *atnms1[index1[i1]],
-                        index1[i1], *resinfo2[rnr2].name, rnr2, *atnms2[index2[i2]], index2[i2]);
+                fprintf(debug,
+                        " -> %s%d-%s%d %s%d-%s%d",
+                        *resinfo1[rnr1].name,
+                        rnr1,
+                        *atnms1[index1[i1]],
+                        index1[i1],
+                        *resinfo2[rnr2].name,
+                        rnr2,
+                        *atnms2[index2[i2]],
+                        index2[i2]);
             }
             m1 = find_res_end(i1, *isize1, index1, atoms1);
             m2 = find_res_end(i2, *isize2, index2, atoms2);
@@ -550,8 +564,8 @@ int gmx_confrms(int argc, char* argv[])
     real* msds;
 
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc,
-                           0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -601,8 +615,12 @@ int gmx_confrms(int argc, char* argv[])
         if (matchndxfile)
         {
             fp = gmx_ffopen(matchndxfile, "w");
-            fprintf(fp, "; Matching atoms between %s from %s and %s from %s\n", groupnames1,
-                    conf1file, groupnames2, conf2file);
+            fprintf(fp,
+                    "; Matching atoms between %s from %s and %s from %s\n",
+                    groupnames1,
+                    conf1file,
+                    groupnames2,
+                    conf2file);
             fprintf(fp, "[ Match_%s_%s ]\n", conf1file, groupnames1);
             for (i = 0; i < isize1; i++)
             {
@@ -630,8 +648,13 @@ int gmx_confrms(int argc, char* argv[])
         {
             if (warn < 20)
             {
-                fprintf(stderr, "Warning: atomnames at index %d don't match: %d %s, %d %s\n", i + 1,
-                        index1[i] + 1, name1, index2[i] + 1, name2);
+                fprintf(stderr,
+                        "Warning: atomnames at index %d don't match: %d %s, %d %s\n",
+                        i + 1,
+                        index1[i] + 1,
+                        name1,
+                        index2[i] + 1,
+                        name2);
             }
             warn++;
         }
@@ -736,7 +759,7 @@ int gmx_confrms(int argc, char* argv[])
                 /* Avoid segfaults when writing the pdb-file */
                 for (i = 0; i < atoms1->nr; i++)
                 {
-                    atoms1->pdbinfo[i].type         = eptAtom;
+                    atoms1->pdbinfo[i].type         = PdbRecordType::Atom;
                     atoms1->pdbinfo[i].occup        = 1.00;
                     atoms1->pdbinfo[i].bAnisotropic = FALSE;
                     if (bBfac)
@@ -765,7 +788,7 @@ int gmx_confrms(int argc, char* argv[])
 
                 for (i = 0; i < atoms2->nr; i++)
                 {
-                    atoms2->pdbinfo[i].type         = eptAtom;
+                    atoms2->pdbinfo[i].type         = PdbRecordType::Atom;
                     atoms2->pdbinfo[i].occup        = 1.00;
                     atoms2->pdbinfo[i].bAnisotropic = FALSE;
                     if (bBfac)
@@ -814,12 +837,14 @@ int gmx_confrms(int argc, char* argv[])
         default:
             if (bBfac)
             {
-                fprintf(stderr, "WARNING: cannot write B-factor values to %s file\n",
+                fprintf(stderr,
+                        "WARNING: cannot write B-factor values to %s file\n",
                         ftp2ext(fn2ftp(outfile)));
             }
             if (!bOne)
             {
-                fprintf(stderr, "WARNING: cannot write the reference structure to %s file\n",
+                fprintf(stderr,
+                        "WARNING: cannot write the reference structure to %s file\n",
                         ftp2ext(fn2ftp(outfile)));
             }
             write_sto_conf(outfile, *top2->name, atoms2, x2, v2, pbcType2, box2);
index 7d07f0a37b7d25a68690ff0dcbb0b9b6c7934a67..33c3fae1bc9bd96a9e3f53ec7756792af671354b 100644 (file)
@@ -186,8 +186,8 @@ int gmx_covar(int argc, char* argv[])
     };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -307,7 +307,8 @@ int gmx_covar(int argc, char* argv[])
         fprintf(stderr,
                 "\nWARNING: number of atoms in structure file (%d) and trajectory (%d) do not "
                 "match\n",
-                natoms, nat);
+                natoms,
+                nat);
     }
     gmx::throwErrorIfIndexOutOfBounds({ ifit, ifit + nfit }, nat, "fitting");
     gmx::throwErrorIfIndexOutOfBounds({ index, index + natoms }, nat, "analysis");
@@ -341,11 +342,13 @@ int gmx_covar(int argc, char* argv[])
             xread[index[i]][d] = xav[i][d];
         }
     }
-    write_sto_conf_indexed(opt2fn("-av", NFILE, fnm), "Average structure", atoms, xread, nullptr,
-                           PbcType::No, zerobox, natoms, index);
+    write_sto_conf_indexed(
+            opt2fn("-av", NFILE, fnm), "Average structure", atoms, xread, nullptr, PbcType::No, zerobox, natoms, index);
     sfree(xread);
 
-    fprintf(stderr, "Constructing covariance matrix (%dx%d) ...\n", static_cast<int>(ndim),
+    fprintf(stderr,
+            "Constructing covariance matrix (%dx%d) ...\n",
+            static_cast<int>(ndim),
             static_cast<int>(ndim));
     nframes = 0;
     nat     = read_first_x(oenv, &status, trxfile, &t, &xread, box);
@@ -455,8 +458,7 @@ int gmx_covar(int argc, char* argv[])
         {
             for (i = 0; i < ndim; i += 3)
             {
-                fprintf(out, "%g %g %g\n", mat[ndim * j + i], mat[ndim * j + i + 1],
-                        mat[ndim * j + i + 2]);
+                fprintf(out, "%g %g %g\n", mat[ndim * j + i], mat[ndim * j + i + 1], mat[ndim * j + i + 2]);
             }
         }
         gmx_ffclose(out);
@@ -498,8 +500,24 @@ int gmx_covar(int argc, char* argv[])
         rhi.b   = 0;
         out     = gmx_ffopen(xpmfile, "w");
         nlevels = 80;
-        write_xpm3(out, 0, "Covariance", bM ? "u nm^2" : "nm^2", "dim", "dim", ndim, ndim, axis,
-                   axis, mat2, min, 0.0, max, rlo, rmi, rhi, &nlevels);
+        write_xpm3(out,
+                   0,
+                   "Covariance",
+                   bM ? "u nm^2" : "nm^2",
+                   "dim",
+                   "dim",
+                   ndim,
+                   ndim,
+                   axis,
+                   axis,
+                   mat2,
+                   min,
+                   0.0,
+                   max,
+                   rlo,
+                   rmi,
+                   rhi,
+                   &nlevels);
         gmx_ffclose(out);
         sfree(axis);
         sfree(mat2);
@@ -550,8 +568,24 @@ int gmx_covar(int argc, char* argv[])
         rhi.b   = 0;
         out     = gmx_ffopen(xpmafile, "w");
         nlevels = 80;
-        write_xpm3(out, 0, "Covariance", bM ? "u nm^2" : "nm^2", "atom", "atom", ndim / DIM,
-                   ndim / DIM, axis, axis, mat2, min, 0.0, max, rlo, rmi, rhi, &nlevels);
+        write_xpm3(out,
+                   0,
+                   "Covariance",
+                   bM ? "u nm^2" : "nm^2",
+                   "atom",
+                   "atom",
+                   ndim / DIM,
+                   ndim / DIM,
+                   axis,
+                   axis,
+                   mat2,
+                   min,
+                   0.0,
+                   max,
+                   rlo,
+                   rmi,
+                   rhi,
+                   &nlevels);
         gmx_ffclose(out);
         sfree(axis);
         for (i = 0; i < ndim / DIM; i++)
@@ -593,8 +627,7 @@ int gmx_covar(int argc, char* argv[])
         if (nframes - 1 < ndim)
         {
             end = nframes - 1;
-            fprintf(stderr,
-                    "\nWARNING: there are fewer frames in your trajectory than there are\n");
+            fprintf(stderr, "\nWARNING: there are fewer frames in your trajectory than there are\n");
             fprintf(stderr, "degrees of freedom in your system. Only generating the first\n");
             fprintf(stderr, "%d out of %d eigenvectors and eigenvalues.\n", end, static_cast<int>(ndim));
         }
@@ -636,8 +669,8 @@ int gmx_covar(int argc, char* argv[])
         WriteXref = eWXR_NOFIT;
     }
 
-    write_eigenvectors(eigvecfile, natoms, mat, TRUE, 1, end, WriteXref, x, bDiffMass1, xproj, bM,
-                       eigenvalues);
+    write_eigenvectors(
+            eigvecfile, natoms, mat, TRUE, 1, end, WriteXref, x, bDiffMass1, xproj, bM, eigenvalues);
 
     out = gmx_ffopen(logfile, "w");
 
@@ -648,8 +681,12 @@ int gmx_covar(int argc, char* argv[])
 
     fprintf(out, "Working directory: %s\n\n", str);
 
-    fprintf(out, "Read %d frames from %s (time %g to %g %s)\n", nframes, trxfile,
-            output_env_conv_time(oenv, tstart), output_env_conv_time(oenv, tend),
+    fprintf(out,
+            "Read %d frames from %s (time %g to %g %s)\n",
+            nframes,
+            trxfile,
+            output_env_conv_time(oenv, tstart),
+            output_env_conv_time(oenv, tend),
             output_env_get_time_unit(oenv).c_str());
     if (bFit)
     {
@@ -675,8 +712,7 @@ int gmx_covar(int argc, char* argv[])
     {
         fprintf(out, "Fit is %smass weighted\n", bDiffMass1 ? "" : "non-");
     }
-    fprintf(out, "Diagonalized the %dx%d covariance matrix\n", static_cast<int>(ndim),
-            static_cast<int>(ndim));
+    fprintf(out, "Diagonalized the %dx%d covariance matrix\n", static_cast<int>(ndim), static_cast<int>(ndim));
     fprintf(out, "Trace of the covariance matrix before diagonalizing: %g\n", trace);
     fprintf(out, "Trace of the covariance matrix after diagonalizing: %g\n\n", sum);
 
index 067f46c797df0162caf343c1733dd9b0304cfa5c..78c58596a921c0120e73931e4af4a7b16b0244e8 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2008,2009,2010,2011,2012 by the GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
 
-#define EPSI0 (EPSILON0 * E_CHARGE * E_CHARGE * AVOGADRO / (KILO * NANO)) /* EPSILON0 in SI units */
+constexpr double EPSI0 = (gmx::c_epsilon0 * gmx::c_electronCharge * gmx::c_electronCharge * gmx::c_avogadro
+                          / (gmx::c_kilo * gmx::c_nano)); /* c_epsilon0 in SI units */
 
 static void index_atom2mol(int* n, int* index, t_block* mols)
 {
@@ -614,10 +615,22 @@ static void dielectric(FILE*                   fmj,
         mj2 += iprod(mtrans[nfr], mtrans[nfr]);
         md2 += iprod(mu[nfr], mu[nfr]);
 
-        fprintf(fmj, "%.3f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\n", time[nfr], mtrans[nfr][XX],
-                mtrans[nfr][YY], mtrans[nfr][ZZ], mj2 / refr, norm(mja_tmp) / refr);
-        fprintf(fmd, "%.3f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\n", time[nfr], mu[nfr][XX],
-                mu[nfr][YY], mu[nfr][ZZ], md2 / refr, norm(mdvec) / refr);
+        fprintf(fmj,
+                "%.3f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\n",
+                time[nfr],
+                mtrans[nfr][XX],
+                mtrans[nfr][YY],
+                mtrans[nfr][ZZ],
+                mj2 / refr,
+                norm(mja_tmp) / refr);
+        fprintf(fmd,
+                "%.3f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\t%8.5f\n",
+                time[nfr],
+                mu[nfr][XX],
+                mu[nfr][YY],
+                mu[nfr][ZZ],
+                md2 / refr,
+                norm(mdvec) / refr);
 
         nfr++;
 
@@ -628,11 +641,11 @@ static void dielectric(FILE*                   fmj,
     volume_av /= refr;
 
     prefactor = 1.0;
-    prefactor /= 3.0 * EPSILON0 * volume_av * BOLTZ * temp;
+    prefactor /= 3.0 * gmx::c_epsilon0 * volume_av * gmx::c_boltz * temp;
 
 
-    prefactorav = E_CHARGE * E_CHARGE;
-    prefactorav /= volume_av * BOLTZMANN * temp * NANO * 6.0;
+    prefactorav = gmx::c_electronCharge * gmx::c_electronCharge;
+    prefactorav /= volume_av * gmx::c_boltzmann * temp * gmx::c_nano * 6.0;
 
     fprintf(stderr, "Prefactor fit E-H: 1 / 6.0*V*k_B*T: %g\n", prefactorav);
 
@@ -657,9 +670,17 @@ static void dielectric(FILE*                   fmj,
 
     printf("\n\nAverage translational dipole moment M_J [enm] after %d frames (|M|^2): %f %f %f "
            "(%f)\n",
-           nfr, mja_tmp[XX], mja_tmp[YY], mja_tmp[ZZ], mj2);
+           nfr,
+           mja_tmp[XX],
+           mja_tmp[YY],
+           mja_tmp[ZZ],
+           mj2);
     printf("\n\nAverage molecular dipole moment M_D [enm] after %d frames (|M|^2): %f %f %f (%f)\n",
-           nfr, mdvec[XX], mdvec[YY], mdvec[ZZ], md2);
+           nfr,
+           mdvec[XX],
+           mdvec[YY],
+           mdvec[ZZ],
+           md2);
 
     if (v0 != nullptr)
     {
@@ -674,7 +695,7 @@ static void dielectric(FILE*                   fmj,
         {
 
             printf("\nCalculating current autocorrelation ... \n");
-            sgk = calc_cacf(outf, prefactorav / PICO, cacf, time, nvfr, vfr, ie, nshift);
+            sgk = calc_cacf(outf, prefactorav / gmx::c_pico, cacf, time, nvfr, vfr, ie, nshift);
 
             if (ie > ii)
             {
@@ -716,8 +737,7 @@ static void dielectric(FILE*                   fmj,
 
     dk_f = calceps(prefactor, md2 - mdav2, mj2 - mj, mjd - mjdav, eps_rf, FALSE);
     fprintf(stderr, "\n\nFluctuations:\n epsilon=%f\n\n", dk_f);
-    fprintf(stderr, "\n deltaM_D , deltaM_J, deltaM_JD:  (%f, %f, %f)\n", md2 - mdav2, mj2 - mj,
-            mjd - mjdav);
+    fprintf(stderr, "\n deltaM_D , deltaM_J, deltaM_JD:  (%f, %f, %f)\n", md2 - mdav2, mj2 - mj, mjd - mjdav);
     fprintf(stderr, "\n********************************************\n");
     if (bINT)
     {
@@ -734,8 +754,7 @@ static void dielectric(FILE*                   fmj,
     if (bACF && (ii < nvfr))
     {
         fprintf(stderr, "Integral and integrated fit to the current acf yields at t=%f:\n", time[vfr[ii]]);
-        fprintf(stderr, "sigma=%8.3f (pure integral: %.3f)\n",
-                sgk - malt * std::pow(time[vfr[ii]], sigma), sgk);
+        fprintf(stderr, "sigma=%8.3f (pure integral: %.3f)\n", sgk - malt * std::pow(time[vfr[ii]], sigma), sgk);
     }
 
     if (ei > bi)
@@ -934,8 +953,8 @@ int gmx_current(int argc, char* argv[])
 
 
     /* At first the arguments will be parsed and the system information processed */
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -976,41 +995,81 @@ int gmx_current(int argc, char* argv[])
     {
         if (bACF)
         {
-            outf = xvgropen(opt2fn("-caf", NFILE, fnm), "Current autocorrelation function",
-                            output_env_get_xvgr_tlabel(oenv), "ACF (e nm/ps)\\S2", oenv);
+            outf = xvgropen(opt2fn("-caf", NFILE, fnm),
+                            "Current autocorrelation function",
+                            output_env_get_xvgr_tlabel(oenv),
+                            "ACF (e nm/ps)\\S2",
+                            oenv);
             fprintf(outf, "# time\t acf\t average \t std.dev\n");
         }
-        fcur = xvgropen(opt2fn("-o", NFILE, fnm), "Current", output_env_get_xvgr_tlabel(oenv),
-                        "J(t) (e nm/ps)", oenv);
+        fcur = xvgropen(opt2fn("-o", NFILE, fnm),
+                        "Current",
+                        output_env_get_xvgr_tlabel(oenv),
+                        "J(t) (e nm/ps)",
+                        oenv);
         fprintf(fcur, "# time\t Jx\t Jy \t J_z \n");
         if (bINT)
         {
             mcor = xvgropen(opt2fn("-mc", NFILE, fnm),
                             "M\\sD\\N - current  autocorrelation function",
                             output_env_get_xvgr_tlabel(oenv),
-                            "< M\\sD\\N (0)\\c7\\CJ(t) >  (e nm/ps)\\S2", oenv);
+                            "< M\\sD\\N (0)\\c7\\CJ(t) >  (e nm/ps)\\S2",
+                            oenv);
             fprintf(mcor, "# time\t M_D(0) J(t) acf \t Integral acf\n");
         }
     }
 
-    fmj = xvgropen(opt2fn("-mj", NFILE, fnm), "Averaged translational part of M",
-                   output_env_get_xvgr_tlabel(oenv), "< M\\sJ\\N > (enm)", oenv);
+    fmj = xvgropen(opt2fn("-mj", NFILE, fnm),
+                   "Averaged translational part of M",
+                   output_env_get_xvgr_tlabel(oenv),
+                   "< M\\sJ\\N > (enm)",
+                   oenv);
     fprintf(fmj, "# time\t x\t y \t z \t average of M_J^2 \t std.dev\n");
-    fmd = xvgropen(opt2fn("-md", NFILE, fnm), "Averaged rotational part of M",
-                   output_env_get_xvgr_tlabel(oenv), "< M\\sD\\N > (enm)", oenv);
+    fmd = xvgropen(opt2fn("-md", NFILE, fnm),
+                   "Averaged rotational part of M",
+                   output_env_get_xvgr_tlabel(oenv),
+                   "< M\\sD\\N > (enm)",
+                   oenv);
     fprintf(fmd, "# time\t x\t y \t z \t average of M_D^2 \t std.dev\n");
 
     fmjdsp = xvgropen(
-            opt2fn("-dsp", NFILE, fnm), "MSD of the squared translational dipole moment M",
+            opt2fn("-dsp", NFILE, fnm),
+            "MSD of the squared translational dipole moment M",
             output_env_get_xvgr_tlabel(oenv),
-            "<|M\\sJ\\N(t)-M\\sJ\\N(0)|\\S2\\N > / 6.0*V*k\\sB\\N*T / Sm\\S-1\\Nps\\S-1\\N", oenv);
+            "<|M\\sJ\\N(t)-M\\sJ\\N(0)|\\S2\\N > / 6.0*V*k\\sB\\N*T / Sm\\S-1\\Nps\\S-1\\N",
+            oenv);
 
 
     /* System information is read and prepared, dielectric() processes the frames
      * and calculates the requested quantities */
 
-    dielectric(fmj, fmd, outf, fcur, mcor, fmjdsp, bNoJump, bACF, bINT, pbcType, top, fr, temp, bfit, efit,
-               bvit, evit, status, isize, nmols, nshift, index0, indexm, mass2, qmol, eps_rf, oenv);
+    dielectric(fmj,
+               fmd,
+               outf,
+               fcur,
+               mcor,
+               fmjdsp,
+               bNoJump,
+               bACF,
+               bINT,
+               pbcType,
+               top,
+               fr,
+               temp,
+               bfit,
+               efit,
+               bvit,
+               evit,
+               status,
+               isize,
+               nmols,
+               nshift,
+               index0,
+               indexm,
+               mass2,
+               qmol,
+               eps_rf,
+               oenv);
 
     xvgrclose(fmj);
     xvgrclose(fmd);
index 1a15db384e0c55c3b19b18d5d0909fc41c072c7d..cade69fe5dd42564f16d67c9cf8c83bdf0acfd02 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +144,11 @@ static void center_coords(t_atoms* atoms, const int* index_center, int ncenter,
         i = index_center[k];
         if (i >= atoms->nr)
         {
-            gmx_fatal(FARGS, "Index %d refers to atom %d, which is larger than natoms (%d).", k + 1,
-                      i + 1, atoms->nr);
+            gmx_fatal(FARGS,
+                      "Index %d refers to atom %d, which is larger than natoms (%d).",
+                      k + 1,
+                      i + 1,
+                      atoms->nr);
         }
         mm = atoms->atom[i].m;
         tmass += mm;
@@ -287,12 +290,16 @@ static void calc_electron_density(const char*             fn,
 
                 /* now find the number of electrons. This is not efficient. */
                 found = static_cast<t_electron*>(
-                        bsearch(&sought, eltab, nr, sizeof(t_electron),
+                        bsearch(&sought,
+                                eltab,
+                                nr,
+                                sizeof(t_electron),
                                 reinterpret_cast<int (*)(const void*, const void*)>(compare)));
 
                 if (found == nullptr)
                 {
-                    fprintf(stderr, "Couldn't find %s. Add it to the .dat file\n",
+                    fprintf(stderr,
+                            "Couldn't find %s. Add it to the .dat file\n",
                             *(top->atoms.atomname[index[n][i]]));
                 }
                 else
@@ -582,7 +589,7 @@ static void plot_density(double*                 slDensity[],
             }
             if (dens_opt[0][0] == 'm')
             {
-                fprintf(den, "   %12g", ddd * AMU / (NANO * NANO * NANO));
+                fprintf(den, "   %12g", ddd * gmx::c_amu / (gmx::c_nano * gmx::c_nano * gmx::c_nano));
             }
             else
             {
@@ -729,8 +736,8 @@ int gmx_density(int argc, char* argv[])
 
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, asize(bugs), bugs, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
         return 0;
     }
@@ -774,18 +781,46 @@ int gmx_density(int argc, char* argv[])
         nr_electrons = get_electrons(&el_tab, ftp2fn(efDAT, NFILE, fnm));
         fprintf(stderr, "Read %d atomtypes from datafile\n", nr_electrons);
 
-        calc_electron_density(ftp2fn(efTRX, NFILE, fnm), index, ngx, &density, &nslices, top,
-                              pbcType, axis, ngrps, &slWidth, el_tab, nr_electrons, bCenter,
-                              index_center, ncenter, bRelative, oenv);
+        calc_electron_density(ftp2fn(efTRX, NFILE, fnm),
+                              index,
+                              ngx,
+                              &density,
+                              &nslices,
+                              top,
+                              pbcType,
+                              axis,
+                              ngrps,
+                              &slWidth,
+                              el_tab,
+                              nr_electrons,
+                              bCenter,
+                              index_center,
+                              ncenter,
+                              bRelative,
+                              oenv);
     }
     else
     {
-        calc_density(ftp2fn(efTRX, NFILE, fnm), index, ngx, &density, &nslices, top, pbcType, axis,
-                     ngrps, &slWidth, bCenter, index_center, ncenter, bRelative, oenv, dens_opt);
-    }
-
-    plot_density(density, opt2fn("-o", NFILE, fnm), nslices, ngrps, grpname, slWidth, dens_opt,
-                 bCenter, bRelative, bSymmetrize, oenv);
+        calc_density(ftp2fn(efTRX, NFILE, fnm),
+                     index,
+                     ngx,
+                     &density,
+                     &nslices,
+                     top,
+                     pbcType,
+                     axis,
+                     ngrps,
+                     &slWidth,
+                     bCenter,
+                     index_center,
+                     ncenter,
+                     bRelative,
+                     oenv,
+                     dens_opt);
+    }
+
+    plot_density(
+            density, opt2fn("-o", NFILE, fnm), nslices, ngrps, grpname, slWidth, dens_opt, bCenter, bRelative, bSymmetrize, oenv);
 
     do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy"); /* view xvgr file */
     return 0;
index f9c838b2a723f28db2e0c8245be4be1a8494c358..973aed745fa73ed02dbbbc82abd050591562af81 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/fileio/trxio.h"
 #include "gromacs/gmxana/gmx_ana.h"
 #include "gromacs/gmxana/gstat.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/pbc.h"
@@ -147,8 +148,8 @@ int gmx_densmap(int argc, char* argv[])
 
     npargs = asize(pa);
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, npargs, pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, npargs, pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -518,9 +519,22 @@ int gmx_densmap(int argc, char* argv[])
     else
     {
         fp = gmx_ffopen(ftp2fn(efXPM, NFILE, fnm), "w");
-        write_xpm(fp, MAT_SPATIAL_X | MAT_SPATIAL_Y, buf, unit, bRadial ? "axial (nm)" : label[c1],
-                  bRadial ? "r (nm)" : label[c2], n1, n2, tickx, tickz, grid, dmin, maxgrid, rlo,
-                  rhi, &nlev);
+        write_xpm(fp,
+                  MAT_SPATIAL_X | MAT_SPATIAL_Y,
+                  buf,
+                  unit,
+                  bRadial ? "axial (nm)" : label[c1],
+                  bRadial ? "r (nm)" : label[c2],
+                  n1,
+                  n2,
+                  tickx,
+                  tickz,
+                  grid,
+                  dmin,
+                  maxgrid,
+                  rlo,
+                  rhi,
+                  &nlev);
         gmx_ffclose(fp);
     }
 
index 0942cda75c196793ee994a10f7347ede56e58994..b9bebf3c8b0d5b494085a0e4d48d604af7d30987 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -184,8 +184,13 @@ static void density_in_time(const char*             fn,
             *yslices = 1;
         }
     }
-    fprintf(stderr, "\nDividing the box in %5d x %5d x %5d slices with binw %f along axis %d\n",
-            *xslices, *yslices, *zslices, bw, axis);
+    fprintf(stderr,
+            "\nDividing the box in %5d x %5d x %5d slices with binw %f along axis %d\n",
+            *xslices,
+            *yslices,
+            *zslices,
+            bw,
+            axis);
 
 
     /****Start trajectory processing***/
@@ -223,8 +228,9 @@ static void density_in_time(const char*             fn,
             (*Densdevel)[*tblock] = Densslice;
         }
 
-        dscale = (*xslices) * (*yslices) * (*zslices) * AMU
-                 / (box[ax1][ax1] * box[ax2][ax2] * box[axis][axis] * nsttblock * (NANO * NANO * NANO));
+        dscale = (*xslices) * (*yslices) * (*zslices) * gmx::c_amu
+                 / (box[ax1][ax1] * box[ax2][ax2] * box[axis][axis] * nsttblock
+                    * (gmx::c_nano * gmx::c_nano * gmx::c_nano));
 
         if (bCenter)
         {
@@ -501,8 +507,8 @@ static void interfaces_txy(real****                Densmap,
 
         if (debug)
         {
-            xvg = xvgropen("DensprofileonZ.xvg", "Averaged Densityprofile on Z", "z[nm]",
-                           "Density[kg/m^3]", oenv);
+            xvg = xvgropen(
+                    "DensprofileonZ.xvg", "Averaged Densityprofile on Z", "z[nm]", "Density[kg/m^3]", oenv);
             for (k = 0; k < zslices; k++)
             {
                 fprintf(xvg, "%4f.3   %8f.4\n", k * binwidth, zDensavg[k]);
@@ -513,11 +519,9 @@ static void interfaces_txy(real****                Densmap,
         /*Fit average density in z over whole trajectory to obtain tentative fit-parameters in fit1 and fit2*/
 
         /*Fit 1st half of box*/
-        do_lmfit(zslices, zDensavg, sigma1, binwidth, nullptr, startpoint, splitpoint, oenv, FALSE,
-                 effnERF, beginfit1, 8, nullptr);
+        do_lmfit(zslices, zDensavg, sigma1, binwidth, nullptr, startpoint, splitpoint, oenv, FALSE, effnERF, beginfit1, 8, nullptr);
         /*Fit 2nd half of box*/
-        do_lmfit(zslices, zDensavg, sigma2, binwidth, nullptr, splitpoint, endpoint, oenv, FALSE,
-                 effnERF, beginfit2, 8, nullptr);
+        do_lmfit(zslices, zDensavg, sigma2, binwidth, nullptr, splitpoint, endpoint, oenv, FALSE, effnERF, beginfit2, 8, nullptr);
 
         /*Initialise the const arrays for storing the average fit parameters*/
         avgfit1 = beginfit1;
@@ -540,12 +544,34 @@ static void interfaces_txy(real****                Densmap,
                         fit2[k] = avgfit2[k];
                     }
                     /*Now fit and store in structures in row-major order int[n][i][j]*/
-                    do_lmfit(zslices, Densmap[n][i][j], sigma1, binwidth, nullptr, startpoint,
-                             splitpoint, oenv, FALSE, effnERF, fit1, 0, nullptr);
+                    do_lmfit(zslices,
+                             Densmap[n][i][j],
+                             sigma1,
+                             binwidth,
+                             nullptr,
+                             startpoint,
+                             splitpoint,
+                             oenv,
+                             FALSE,
+                             effnERF,
+                             fit1,
+                             0,
+                             nullptr);
                     int1[n][j + (yslices * i)]->Z = fit1[2];
                     int1[n][j + (yslices * i)]->t = fit1[3];
-                    do_lmfit(zslices, Densmap[n][i][j], sigma2, binwidth, nullptr, splitpoint,
-                             endpoint, oenv, FALSE, effnERF, fit2, 0, nullptr);
+                    do_lmfit(zslices,
+                             Densmap[n][i][j],
+                             sigma2,
+                             binwidth,
+                             nullptr,
+                             splitpoint,
+                             endpoint,
+                             oenv,
+                             FALSE,
+                             effnERF,
+                             fit2,
+                             0,
+                             nullptr);
                     int2[n][j + (yslices * i)]->Z = fit2[2];
                     int2[n][j + (yslices * i)]->t = fit2[3];
                 }
@@ -631,10 +657,8 @@ static void writesurftoxpms(t_interf***                      surf1,
             }
         }
 
-        write_xpm(xpmfile1, 3, numbuf, "Height", "x[nm]", "y[nm]", xbins, ybins, xticks, yticks,
-                  profile1, min1, max1, lo, hi, &maplevels);
-        write_xpm(xpmfile2, 3, numbuf, "Height", "x[nm]", "y[nm]", xbins, ybins, xticks, yticks,
-                  profile2, min2, max2, lo, hi, &maplevels);
+        write_xpm(xpmfile1, 3, numbuf, "Height", "x[nm]", "y[nm]", xbins, ybins, xticks, yticks, profile1, min1, max1, lo, hi, &maplevels);
+        write_xpm(xpmfile2, 3, numbuf, "Height", "x[nm]", "y[nm]", xbins, ybins, xticks, yticks, profile2, min2, max2, lo, hi, &maplevels);
     }
 
     gmx_ffclose(xpmfile1);
@@ -679,9 +703,17 @@ static void writeraw(t_interf***                      int1,
         {
             for (j = 0; j < ybins; j++)
             {
-                fprintf(raw1, "%i  %i  %8.5f  %6.4f\n", i, j, (int1[n][j + ybins * i])->Z,
+                fprintf(raw1,
+                        "%i  %i  %8.5f  %6.4f\n",
+                        i,
+                        j,
+                        (int1[n][j + ybins * i])->Z,
                         (int1[n][j + ybins * i])->t);
-                fprintf(raw2, "%i  %i  %8.5f  %6.4f\n", i, j, (int2[n][j + ybins * i])->Z,
+                fprintf(raw2,
+                        "%i  %i  %8.5f  %6.4f\n",
+                        i,
+                        j,
+                        (int2[n][j + ybins * i])->Z,
                         (int2[n][j + ybins * i])->t);
             }
         }
@@ -765,12 +797,9 @@ int gmx_densorder(int argc, char* argv[])
         { efTPR, "-s", nullptr, ffREAD }, /* this is for the topology */
         { efTRX, "-f", nullptr, ffREAD }, /* and this for the trajectory */
         { efNDX, "-n", nullptr, ffREAD }, /* this is to select groups */
-        { efDAT, "-o", "Density4D",
-          ffOPTWR }, /* This is for outputting the entire 4D densityfield in binary format */
-        { efOUT, "-or", nullptr,
-          ffOPTWRMULT }, /* This is for writing out the entire information in the t_interf arrays */
-        { efXPM, "-og", "interface",
-          ffOPTWRMULT }, /* This is for writing out the interface meshes - one xpm-file per tblock*/
+        { efDAT, "-o", "Density4D", ffOPTWR }, /* This is for outputting the entire 4D densityfield in binary format */
+        { efOUT, "-or", nullptr, ffOPTWRMULT }, /* This is for writing out the entire information in the t_interf arrays */
+        { efXPM, "-og", "interface", ffOPTWRMULT }, /* This is for writing out the interface meshes - one xpm-file per tblock*/
         { efOUT, "-Spect", "intfspect", ffOPTWRMULT }, /* This is for the trajectory averaged Fourier-spectra*/
     };
 
@@ -778,8 +807,8 @@ int gmx_densorder(int argc, char* argv[])
 
     /* This is the routine responsible for adding default options,
      * calling the X/motif interface, etc. */
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -800,8 +829,23 @@ int gmx_densorder(int argc, char* argv[])
 
     get_index(&top->atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, ngx, index, grpname);
 
-    density_in_time(ftp2fn(efTRX, NFILE, fnm), index, ngx, binw, binwz, nsttblock, &Densmap,
-                    &xslices, &yslices, &zslices, &tblock, top, pbcType, axis, bCenter, b1d, oenv);
+    density_in_time(ftp2fn(efTRX, NFILE, fnm),
+                    index,
+                    ngx,
+                    binw,
+                    binwz,
+                    nsttblock,
+                    &Densmap,
+                    &xslices,
+                    &yslices,
+                    &zslices,
+                    &tblock,
+                    top,
+                    pbcType,
+                    axis,
+                    bCenter,
+                    b1d,
+                    oenv);
 
     if (ftorder > 0)
     {
@@ -813,8 +857,8 @@ int gmx_densorder(int argc, char* argv[])
         outputfield(opt2fn("-o", NFILE, fnm), Densmap, xslices, yslices, zslices, tblock);
     }
 
-    interfaces_txy(Densmap, xslices, yslices, zslices, tblock, binwz, eMeth, dens1, dens2, &surf1,
-                   &surf2, oenv);
+    interfaces_txy(
+            Densmap, xslices, yslices, zslices, tblock, binwz, eMeth, dens1, dens2, &surf1, &surf2, oenv);
 
     if (bGraph)
     {
index 3ab32fd48236b93c0565fd1d5e3e8d45966bb212..ae2563b5756625d423a55806f1b74fe9a8792fc6 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +52,7 @@
 #include "gromacs/gmxana/gmx_ana.h"
 #include "gromacs/gmxana/gstat.h"
 #include "gromacs/math/gmxcomplex.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/utility/arraysize.h"
 #include "gromacs/utility/fatalerror.h"
@@ -236,7 +237,9 @@ static void do_four(const char*             fn,
         fprintf(fp, "%10.5e  %10.5e  %10.5e\n", nu, kw.re, kw.im);
         fprintf(cp, "%10.5e  %10.5e\n", kw.re, kw.im);
     }
-    printf("MAXEPS = %10.5e at frequency %10.5e GHz (tauD = %8.1f ps)\n", maxeps, numax,
+    printf("MAXEPS = %10.5e at frequency %10.5e GHz (tauD = %8.1f ps)\n",
+           maxeps,
+           numax,
            1000 / (2 * M_PI * numax));
     xvgrclose(fp);
     xvgrclose(cp);
@@ -319,8 +322,8 @@ int gmx_dielectric(int argc, char* argv[])
         { "-nsmooth", FALSE, etINT, { &nsmooth }, "Number of points for smoothing" }
     };
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -414,9 +417,13 @@ int gmx_dielectric(int argc, char* argv[])
     }
     printf("DATA INTEGRAL: %5.1f, tauD(old) = %5.1f ps, "
            "tau_slope = %5.1f, tau_slope,D = %5.1f ps\n",
-           integral, integral * rffac, fitparms[0], fitparms[0] * rffac);
+           integral,
+           integral * rffac,
+           fitparms[0],
+           fitparms[0] * rffac);
 
-    printf("tau_D from tau1 = %8.3g , eps(Infty) = %8.3f\n", fitparms[0] * (1 + fitparms[1] * lambda),
+    printf("tau_D from tau1 = %8.3g , eps(Infty) = %8.3f\n",
+           fitparms[0] * (1 + fitparms[1] * lambda),
            1 + ((1 - fitparms[1]) * (eps0 - 1)) / (1 + fitparms[1] * lambda));
 
     fitintegral = numerical_deriv(nx, y[0], y[1], y[3], y[4], y[5], tendInt, nsmooth);
index 4f5e8f2d001ef1d82abbd07f52557b97f55f59fc..5f1d64283b3d626eaac42a45b3d93cb651b9040c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +74,9 @@
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
 
-#define e2d(x) ENM2DEBYE*(x)
-#define EANG2CM (E_CHARGE * 1.0e-10)    /* e Angstrom to Coulomb meter */
-#define CM2D (SPEED_OF_LIGHT * 1.0e+24) /* Coulomb meter to Debye */
+#define e2d(x) gmx::c_enm2Debye*(x)
+constexpr double EANG2CM = gmx::c_electronCharge * 1.0e-10; /* e Angstrom to Coulomb meter */
+constexpr double CM2D    = gmx::c_speedOfLight * 1.0e+24;   /* Coulomb meter to Debye */
 
 typedef struct
 {
@@ -257,8 +257,19 @@ static void do_gkr(t_gkrbin*     gb,
                     copy_rvec(xcm[grp1][j], xk);
                     rvec_add(xj, mu[gi], xi);
                     rvec_add(xk, mu[gj], xl);
-                    phi  = dih_angle(xi, xj, xk, xl, &pbc, r_ij, r_kj, r_kl, mm, nn, /* out */
-                                    &t1, &t2, &t3);
+                    phi  = dih_angle(xi,
+                                    xj,
+                                    xk,
+                                    xl,
+                                    &pbc,
+                                    r_ij,
+                                    r_kj,
+                                    r_kl,
+                                    mm,
+                                    nn, /* out */
+                                    &t1,
+                                    &t2,
+                                    &t3);
                     cosa = std::cos(phi);
                 }
                 else
@@ -271,8 +282,18 @@ static void do_gkr(t_gkrbin*     gb,
                     fprintf(debug ? debug : stderr,
                             "mu[%d] = %5.2f %5.2f %5.2f |mi| = %5.2f, mu[%d] = %5.2f %5.2f %5.2f "
                             "|mj| = %5.2f rr = %5.2f cosa = %5.2f\n",
-                            gi, mu[gi][XX], mu[gi][YY], mu[gi][ZZ], norm(mu[gi]), gj, mu[gj][XX],
-                            mu[gj][YY], mu[gj][ZZ], norm(mu[gj]), rr, cosa);
+                            gi,
+                            mu[gi][XX],
+                            mu[gi][YY],
+                            mu[gi][ZZ],
+                            norm(mu[gi]),
+                            gj,
+                            mu[gj][XX],
+                            mu[gj][YY],
+                            mu[gj][ZZ],
+                            norm(mu[gj]),
+                            rr,
+                            cosa);
                 }
 
                 add2gkr(gb, rr, cosa, phi);
@@ -334,8 +355,22 @@ static void print_cmap(const char* cmap, t_gkrbin* gb, int* nlevels)
         /*2.0*j/(gb->ny-1.0)-1.0;*/
     }
     out = gmx_ffopen(cmap, "w");
-    write_xpm(out, 0, "Dipole Orientation Distribution", "Fraction", "r (nm)", gb->bPhi ? "Phi" : "Alpha",
-              gb->nx, gb->ny, xaxis, yaxis, gb->cmap, 0, hi, rlo, rhi, nlevels);
+    write_xpm(out,
+              0,
+              "Dipole Orientation Distribution",
+              "Fraction",
+              "r (nm)",
+              gb->bPhi ? "Phi" : "Alpha",
+              gb->nx,
+              gb->ny,
+              xaxis,
+              yaxis,
+              gb->cmap,
+              0,
+              hi,
+              rlo,
+              rhi,
+              nlevels);
     gmx_ffclose(out);
     sfree(xaxis);
     sfree(yaxis);
@@ -405,7 +440,7 @@ static void print_gkrbin(const char* fn, t_gkrbin* gb, int ngrp, int nframes, re
         {
             cosav = 0;
         }
-        ener = -0.5 * cosav * ONE_4PI_EPS0 / (x1 * x1 * x1);
+        ener = -0.5 * cosav * gmx::c_one4PiEps0 / (x1 * x1 * x1);
 
         fprintf(fp, "%10.5e %12.5e %12.5e %12.5e %12.5e  %12.5e\n", x1, Gkr, cosav, hOO, gOO, ener);
 
@@ -428,7 +463,10 @@ read_mu_from_enx(ener_file_t fmu, int Vol, const ivec iMu, rvec mu, real* vol, r
         fprintf(stderr,
                 "Something strange: expected %d entries in energy file at step %s\n(time %g) but "
                 "found %d entries\n",
-                nre, gmx_step_str(fr->step, buf), fr->t, fr->nre);
+                nre,
+                gmx_step_str(fr->step, buf),
+                fr->t,
+                fr->nre);
     }
 
     if (bCont)
@@ -635,7 +673,8 @@ static real calc_eps(double M_diff, double volume, double epsRF, double temp)
     double eps_0 = 8.854187817e-12; /* epsilon_0 in C^2 J^-1 m^-1 */
     double fac   = 1.112650021e-59; /* converts Debye^2 to C^2 m^2 */
 
-    A = M_diff * fac / (3 * eps_0 * volume * NANO * NANO * NANO * BOLTZMANN * temp);
+    A = M_diff * fac
+        / (3 * eps_0 * volume * gmx::c_nano * gmx::c_nano * gmx::c_nano * gmx::c_boltzmann * temp);
 
     if (epsRF == 0.0)
     {
@@ -678,8 +717,10 @@ static void dump_slab_dipoles(const char*             fn,
     char        buf[STRLEN];
     int         i;
     real        mutot;
-    const char* leg_dim[4] = { "\\f{12}m\\f{4}\\sX\\N", "\\f{12}m\\f{4}\\sY\\N",
-                               "\\f{12}m\\f{4}\\sZ\\N", "\\f{12}m\\f{4}\\stot\\N" };
+    const char* leg_dim[4] = { "\\f{12}m\\f{4}\\sX\\N",
+                               "\\f{12}m\\f{4}\\sY\\N",
+                               "\\f{12}m\\f{4}\\sZ\\N",
+                               "\\f{12}m\\f{4}\\stot\\N" };
 
     sprintf(buf, "Box-%c (nm)", 'X' + idim);
     fp = xvgropen(fn, "Average dipole moment per slab", buf, "\\f{12}m\\f{4} (D)", oenv);
@@ -687,9 +728,13 @@ static void dump_slab_dipoles(const char*             fn,
     for (i = 0; (i < nslice); i++)
     {
         mutot = norm(slab_dipole[i]) / nframes;
-        fprintf(fp, "%10.3f  %10.3f  %10.3f  %10.3f  %10.3f\n",
-                ((i + 0.5) * box[idim][idim]) / nslice, slab_dipole[i][XX] / nframes,
-                slab_dipole[i][YY] / nframes, slab_dipole[i][ZZ] / nframes, mutot);
+        fprintf(fp,
+                "%10.3f  %10.3f  %10.3f  %10.3f  %10.3f\n",
+                ((i + 0.5) * box[idim][idim]) / nslice,
+                slab_dipole[i][XX] / nframes,
+                slab_dipole[i][YY] / nframes,
+                slab_dipole[i][ZZ] / nframes,
+                mutot);
     }
     xvgrclose(fp);
     do_view(oenv, fn, "-autoscale xy -nxy");
@@ -768,10 +813,13 @@ static void do_dip(const t_topology*       top,
 #define NLEGMTOT asize(leg_mtot)
     const char* leg_eps[] = { "epsilon", "G\\sk", "g\\sk" };
 #define NLEGEPS asize(leg_eps)
-    const char* leg_aver[] = { "< |M|\\S2\\N >", "< |M| >\\S2\\N", "< |M|\\S2\\N > - < |M| >\\S2\\N",
+    const char* leg_aver[] = { "< |M|\\S2\\N >",
+                               "< |M| >\\S2\\N",
+                               "< |M|\\S2\\N > - < |M| >\\S2\\N",
                                "< |M| >\\S2\\N / < |M|\\S2\\N >" };
 #define NLEGAVER asize(leg_aver)
-    const char* leg_cosaver[] = { "\\f{4}<|cos\\f{12}q\\f{4}\\sij\\N|>", "RMSD cos",
+    const char* leg_cosaver[] = { "\\f{4}<|cos\\f{12}q\\f{4}\\sij\\N|>",
+                                  "RMSD cos",
                                   "\\f{4}<|cos\\f{12}q\\f{4}\\siX\\N|>",
                                   "\\f{4}<|cos\\f{12}q\\f{4}\\siY\\N|>",
                                   "\\f{4}<|cos\\f{12}q\\f{4}\\siZ\\N|>" };
@@ -896,8 +944,11 @@ static void do_dip(const t_topology*       top,
     mulsq = gmx_stats_init();
 
     /* Open all the files */
-    outmtot = xvgropen(out_mtot, "Total dipole moment of the simulation box vs. time", "Time (ps)",
-                       "Total Dipole Moment (Debye)", oenv);
+    outmtot = xvgropen(out_mtot,
+                       "Total dipole moment of the simulation box vs. time",
+                       "Time (ps)",
+                       "Total Dipole Moment (Debye)",
+                       oenv);
     outeps  = xvgropen(out_eps, "Epsilon and Kirkwood factors", "Time (ps)", "", oenv);
     outaver = xvgropen(out_aver, "Total dipole moment", "Time (ps)", "D", oenv);
     if (bSlab)
@@ -930,8 +981,11 @@ static void do_dip(const t_topology*       top,
     }
     if (cosaver)
     {
-        caver = xvgropen(cosaver, bPairs ? "Average pair orientation" : "Average absolute dipole orientation",
-                         "Time (ps)", "", oenv);
+        caver = xvgropen(cosaver,
+                         bPairs ? "Average pair orientation" : "Average absolute dipole orientation",
+                         "Time (ps)",
+                         "",
+                         oenv);
         xvgr_legend(caver, NLEGCOSAVER, bPairs ? leg_cosaver : &(leg_cosaver[1]), oenv);
     }
 
@@ -1171,9 +1225,16 @@ static void do_dip(const t_topology*       top,
                         {
                             fprintf(dip3d,
                                     "set arrow %d from %f, %f, %f to %f, %f, %f lt %d  # %d %d\n",
-                                    i + 1, x[ind0][XX], x[ind0][YY], x[ind0][ZZ],
-                                    x[ind0][XX] + dipole[i][XX] / 25, x[ind0][YY] + dipole[i][YY] / 25,
-                                    x[ind0][ZZ] + dipole[i][ZZ] / 25, ncolour, ind0, i);
+                                    i + 1,
+                                    x[ind0][XX],
+                                    x[ind0][YY],
+                                    x[ind0][ZZ],
+                                    x[ind0][XX] + dipole[i][XX] / 25,
+                                    x[ind0][YY] + dipole[i][YY] / 25,
+                                    x[ind0][ZZ] + dipole[i][ZZ] / 25,
+                                    ncolour,
+                                    ind0,
+                                    i);
                         }
                     }
                 } /* End loop of all molecules in frame */
@@ -1202,13 +1263,24 @@ static void do_dip(const t_topology*       top,
                                 + gmx::square(dipaxis[ZZ] - 0.5));
             if (bPairs)
             {
-                fprintf(caver, "%10.3e  %10.3e  %10.3e  %10.3e  %10.3e  %10.3e\n", t, dd, rms_cos,
-                        dipaxis[XX], dipaxis[YY], dipaxis[ZZ]);
+                fprintf(caver,
+                        "%10.3e  %10.3e  %10.3e  %10.3e  %10.3e  %10.3e\n",
+                        t,
+                        dd,
+                        rms_cos,
+                        dipaxis[XX],
+                        dipaxis[YY],
+                        dipaxis[ZZ]);
             }
             else
             {
-                fprintf(caver, "%10.3e  %10.3e  %10.3e  %10.3e  %10.3e\n", t, rms_cos, dipaxis[XX],
-                        dipaxis[YY], dipaxis[ZZ]);
+                fprintf(caver,
+                        "%10.3e  %10.3e  %10.3e  %10.3e  %10.3e\n",
+                        t,
+                        rms_cos,
+                        dipaxis[XX],
+                        dipaxis[YY],
+                        dipaxis[ZZ]);
             }
         }
 
@@ -1230,7 +1302,12 @@ static void do_dip(const t_topology*       top,
          */
         if ((skip == 0) || ((teller % skip) == 0))
         {
-            fprintf(outmtot, "%10g  %12.8e %12.8e %12.8e %12.8e\n", t, M_av[XX], M_av[YY], M_av[ZZ],
+            fprintf(outmtot,
+                    "%10g  %12.8e %12.8e %12.8e %12.8e\n",
+                    t,
+                    M_av[XX],
+                    M_av[YY],
+                    M_av[ZZ],
                     std::sqrt(M_av2[XX] + M_av2[YY] + M_av2[ZZ]));
         }
 
@@ -1270,8 +1347,7 @@ static void do_dip(const t_topology*       top,
              * the two. Here M is sum mu_i. Further write the finite system
              * Kirkwood G factor and epsilon.
              */
-            fprintf(outaver, "%10g  %10.3e %10.3e %10.3e %10.3e\n", t, M2_ave, M_ave2, M_diff,
-                    M_ave2 / M2_ave);
+            fprintf(outaver, "%10g  %10.3e %10.3e %10.3e %10.3e\n", t, M2_ave, M_ave2, M_diff, M_ave2 / M2_ave);
 
             if (fnadip)
             {
@@ -1377,13 +1453,20 @@ static void do_dip(const t_topology*       top,
 
             if (bTotal)
             {
-                do_autocorr(corf, oenv, "Autocorrelation Function of Total Dipole", teller, 1,
-                            muall, dt, mode, TRUE);
+                do_autocorr(
+                        corf, oenv, "Autocorrelation Function of Total Dipole", teller, 1, muall, dt, mode, TRUE);
             }
             else
             {
-                do_autocorr(corf, oenv, "Dipole Autocorrelation Function", teller, gnx_tot, muall,
-                            dt, mode, std::strcmp(corrtype, "molsep") != 0);
+                do_autocorr(corf,
+                            oenv,
+                            "Dipole Autocorrelation Function",
+                            teller,
+                            gnx_tot,
+                            muall,
+                            dt,
+                            mode,
+                            std::strcmp(corrtype, "molsep") != 0);
             }
         }
     }
@@ -1465,8 +1548,10 @@ static void dipole_atom2molindex(int* n, int* index, const t_block* mols)
         }
         if (m == mols->nr)
         {
-            gmx_fatal(FARGS, "index[%d]=%d does not correspond to the first atom of a molecule",
-                      i + 1, index[i] + 1);
+            gmx_fatal(FARGS,
+                      "index[%d]=%d does not correspond to the first atom of a molecule",
+                      i + 1,
+                      index[i] + 1);
         }
         for (j = mols->index[m]; j < mols->index[m + 1]; j++)
         {
@@ -1629,8 +1714,8 @@ int gmx_dipoles(int argc, char* argv[])
 
     npargs = asize(pa);
     ppa    = add_acf_pargs(&npargs, pa);
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, npargs, ppa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, nullptr, &oenv))
     {
         sfree(ppa);
         return 0;
@@ -1695,13 +1780,44 @@ int gmx_dipoles(int argc, char* argv[])
     }
     nFF[0] = nFA;
     nFF[1] = nFB;
-    do_dip(top, pbcType, det(box), ftp2fn(efTRX, NFILE, fnm), opt2fn("-o", NFILE, fnm),
-           opt2fn("-eps", NFILE, fnm), opt2fn("-a", NFILE, fnm), opt2fn("-d", NFILE, fnm),
-           opt2fn_null("-cos", NFILE, fnm), opt2fn_null("-dip3d", NFILE, fnm),
-           opt2fn_null("-adip", NFILE, fnm), bPairs, corrtype[0], opt2fn("-c", NFILE, fnm), bGkr,
-           opt2fn("-g", NFILE, fnm), bPhi, &nlevels, ndegrees, ncos, opt2fn("-cmap", NFILE, fnm),
-           rcmax, bQuad, bMU, opt2fn("-en", NFILE, fnm), gnx, grpindex, mu_max, mu_aver, epsilonRF,
-           temp, nFF, skip, bSlab, nslices, axtitle, opt2fn("-slab", NFILE, fnm), oenv);
+    do_dip(top,
+           pbcType,
+           det(box),
+           ftp2fn(efTRX, NFILE, fnm),
+           opt2fn("-o", NFILE, fnm),
+           opt2fn("-eps", NFILE, fnm),
+           opt2fn("-a", NFILE, fnm),
+           opt2fn("-d", NFILE, fnm),
+           opt2fn_null("-cos", NFILE, fnm),
+           opt2fn_null("-dip3d", NFILE, fnm),
+           opt2fn_null("-adip", NFILE, fnm),
+           bPairs,
+           corrtype[0],
+           opt2fn("-c", NFILE, fnm),
+           bGkr,
+           opt2fn("-g", NFILE, fnm),
+           bPhi,
+           &nlevels,
+           ndegrees,
+           ncos,
+           opt2fn("-cmap", NFILE, fnm),
+           rcmax,
+           bQuad,
+           bMU,
+           opt2fn("-en", NFILE, fnm),
+           gnx,
+           grpindex,
+           mu_max,
+           mu_aver,
+           epsilonRF,
+           temp,
+           nFF,
+           skip,
+           bSlab,
+           nslices,
+           axtitle,
+           opt2fn("-slab", NFILE, fnm),
+           oenv);
 
     do_view(oenv, opt2fn("-o", NFILE, fnm), "-autoscale xy -nxy");
     do_view(oenv, opt2fn("-eps", NFILE, fnm), "-autoscale xy -nxy");
index 045481ac3ec5fb4412e8bf856f3fda804b389090..7333fbb6cc4b63d042b63f865cbef17f1d795259 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 The GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +83,10 @@ typedef struct
     real v;
 } t_toppop;
 
-static t_toppop* top  = nullptr;
-static int       ntop = 0;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static t_toppop* top = nullptr;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static int ntop = 0;
 
 typedef struct
 {
@@ -198,14 +200,13 @@ static void check_viol(FILE*                          log,
             gmx_fatal(FARGS,
                       "Label mismatch in distance restrains. Label for restraint %d is %d, "
                       "expected it to be either %d or %d",
-                      i / nat, label, label_old, label_old + 1);
+                      i / nat,
+                      label,
+                      label_old,
+                      label_old + 1);
         }
     }
 
-    // Set up t_fcdata, only needed for calling ta_disres()
-    t_fcdata fcd;
-    fcd.disres = disresdata;
-
     // Get offset for label index
     label_old = forceparams[forceatoms[0]].disres.label;
     for (i = 0; (i < disres.size());)
@@ -237,9 +238,8 @@ static void check_viol(FILE*                          log,
         dr[clust_id].aver_3[ndr] += drt;
         dr[clust_id].aver_6[ndr] += disresdata->Rt_6[label];
 
-        snew(fshift, SHIFTS);
-        ta_disres(n, &forceatoms[i], forceparams.data(), x, f, fshift, pbc, lam, &dvdl, nullptr,
-                  &fcd, nullptr);
+        snew(fshift, gmx::c_numShiftVectors);
+        ta_disres(n, &forceatoms[i], forceparams.data(), x, f, fshift, pbc, lam, &dvdl, {}, nullptr, disresdata, nullptr, nullptr);
         sfree(fshift);
         viol = disresdata->sumviol;
 
@@ -356,9 +356,17 @@ static void dump_viol(FILE* log, int ndr, t_dr_stats* drs, gmx_bool bLinear)
         {
             break;
         }
-        fprintf(log, "%6d%5s%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f\n", drs[i].label,
-                yesno_names[drs[i].bCore], drs[i].up1, drs[i].r, drs[i].rT3, drs[i].rT6,
-                drs[i].viol, drs[i].violT3, drs[i].violT6);
+        fprintf(log,
+                "%6d%5s%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f\n",
+                drs[i].label,
+                booleanValueToString(drs[i].bCore),
+                drs[i].up1,
+                drs[i].r,
+                drs[i].rT3,
+                drs[i].rT6,
+                drs[i].viol,
+                drs[i].violT3,
+                drs[i].violT6);
     }
 }
 
@@ -417,8 +425,9 @@ static void dump_stats(FILE*                          log,
     dump_viol(log, dd.nres, drs, FALSE);
 
     fprintf(log, "+++ Sorted by linear averaged violations: +++\n");
-    std::sort(drs, drs + dd.nres,
-              [](const t_dr_stats& a, const t_dr_stats& b) { return a.viol > b.viol; }); // Reverse sort
+    std::sort(drs, drs + dd.nres, [](const t_dr_stats& a, const t_dr_stats& b) {
+        return a.viol > b.viol;
+    }); // Reverse sort
     dump_viol(log, dd.nres, drs, TRUE);
 
     dump_dump(log, dd.nres, drs);
@@ -457,7 +466,9 @@ static void dump_clust_stats(FILE*                          fp,
             gmx_fatal(FARGS,
                       "Inconsistency in cluster %s.\n"
                       "Found %d frames in trajectory rather than the expected %d\n",
-                      clust_name[k], dr[k].nframes, clust->index[k + 1] - clust->index[k]);
+                      clust_name[k],
+                      dr[k].nframes,
+                      clust->index[k + 1] - clust->index[k]);
         }
         if (!clust_name[k])
         {
@@ -505,8 +516,16 @@ static void dump_clust_stats(FILE*                          fp,
         {
             mmm++;
         }
-        fprintf(fp, "%-10s%6d%8.3f  %8.3f  %8.3f  %8.3f  %8.3f  %8.3f\n", clust_name[k],
-                dr[k].nframes, sumV, maxV, sumVT3, maxVT3, sumVT6, maxVT6);
+        fprintf(fp,
+                "%-10s%6d%8.3f  %8.3f  %8.3f  %8.3f  %8.3f  %8.3f\n",
+                clust_name[k],
+                dr[k].nframes,
+                sumV,
+                maxV,
+                sumVT3,
+                maxVT3,
+                sumVT6,
+                maxVT6);
     }
     fflush(fp);
     sfree(drs);
@@ -649,14 +668,29 @@ static void dump_disre_matrix(const char*                   fn,
         {
             printf("Warning: the maxdr that you have specified (%g) is smaller than\nthe largest "
                    "value in your simulation (%g)\n",
-                   max_dr, hi);
+                   max_dr,
+                   hi);
         }
         hi = max_dr;
     }
     printf("Highest level in the matrix will be %g\n", hi);
     fp = gmx_ffopen(fn, "w");
-    write_xpm(fp, 0, "Distance Violations", "<V> (nm)", "Residue", "Residue", n_res, n_res, t_res,
-              t_res, matrix, 0, hi, rlo, rhi, &nlevels);
+    write_xpm(fp,
+              0,
+              "Distance Violations",
+              "<V> (nm)",
+              "Residue",
+              "Residue",
+              n_res,
+              n_res,
+              t_res,
+              t_res,
+              matrix,
+              0,
+              hi,
+              rlo,
+              rhi,
+              &nlevels);
     gmx_ffclose(fp);
 }
 
@@ -732,8 +766,8 @@ int gmx_disre(int argc, char* argv[])
                        { efNDX, "-c", "clust", ffOPTRD },   { efXPM, "-x", "matrix", ffOPTWR } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -774,7 +808,7 @@ int gmx_disre(int argc, char* argv[])
     }
 
     gmx_localtop_t top(topInfo.mtop()->ffparams);
-    gmx_mtop_generate_local_top(*topInfo.mtop(), &top, ir->efep != efepNO);
+    gmx_mtop_generate_local_top(*topInfo.mtop(), &top, ir->efep != FreeEnergyPerturbationType::No);
     const InteractionDefinitions& idef = top.idef;
 
     pbc_null = nullptr;
@@ -806,8 +840,17 @@ int gmx_disre(int argc, char* argv[])
 
     ir->dr_tau = 0.0;
     t_disresdata disresdata;
-    init_disres(fplog, topInfo.mtop(), ir, DisResRunMode::AnalysisTool, DDRole::Master,
-                NumRanks::Single, MPI_COMM_NULL, nullptr, &disresdata, nullptr, FALSE);
+    init_disres(fplog,
+                *topInfo.mtop(),
+                ir,
+                DisResRunMode::AnalysisTool,
+                DDRole::Master,
+                NumRanks::Single,
+                MPI_COMM_NULL,
+                nullptr,
+                &disresdata,
+                nullptr,
+                FALSE);
 
     int natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
     snew(f, 5 * natoms);
@@ -831,7 +874,7 @@ int gmx_disre(int argc, char* argv[])
     }
 
     auto mdAtoms = gmx::makeMDAtoms(fplog, *topInfo.mtop(), *ir, false);
-    atoms2md(topInfo.mtop(), ir, -1, {}, ntopatoms, mdAtoms.get());
+    atoms2md(*topInfo.mtop(), *ir, -1, {}, ntopatoms, mdAtoms.get());
     update_mdatoms(mdAtoms->mdatoms(), ir->fepvals->init_lambda);
     if (ir->pbcType != PbcType::No)
     {
@@ -864,13 +907,12 @@ int gmx_disre(int argc, char* argv[])
             }
             my_clust = clust->inv_clust[j];
             range_check(my_clust, 0, clust->clust->nr);
-            check_viol(fplog, idef.il[F_DISRES], idef.iparams, x, f, pbc_null, dr_clust, my_clust,
-                       isize, index, vvindex, &disresdata);
+            check_viol(
+                    fplog, idef.il[F_DISRES], idef.iparams, x, f, pbc_null, dr_clust, my_clust, isize, index, vvindex, &disresdata);
         }
         else
         {
-            check_viol(fplog, idef.il[F_DISRES], idef.iparams, x, f, pbc_null, &dr, 0, isize, index,
-                       vvindex, &disresdata);
+            check_viol(fplog, idef.il[F_DISRES], idef.iparams, x, f, pbc_null, &dr, 0, isize, index, vvindex, &disresdata);
         }
         if (bPDB)
         {
@@ -913,20 +955,24 @@ int gmx_disre(int argc, char* argv[])
 
     if (clust)
     {
-        dump_clust_stats(fplog, disresdata, idef.il[F_DISRES], idef.iparams, clust->clust, dr_clust,
-                         clust->grpname, isize, index);
+        dump_clust_stats(
+                fplog, disresdata, idef.il[F_DISRES], idef.iparams, clust->clust, dr_clust, clust->grpname, isize, index);
     }
     else
     {
-        dump_stats(fplog, j, disresdata, idef.il[F_DISRES], idef.iparams, &dr, isize, index,
-                   bPDB ? atoms.get() : nullptr);
+        dump_stats(fplog, j, disresdata, idef.il[F_DISRES], idef.iparams, &dr, isize, index, bPDB ? atoms.get() : nullptr);
         if (bPDB)
         {
-            write_sto_conf(opt2fn("-q", NFILE, fnm), "Coloured by average violation in Angstrom",
-                           atoms.get(), xav, nullptr, ir->pbcType, box);
+            write_sto_conf(opt2fn("-q", NFILE, fnm),
+                           "Coloured by average violation in Angstrom",
+                           atoms.get(),
+                           xav,
+                           nullptr,
+                           ir->pbcType,
+                           box);
         }
-        dump_disre_matrix(opt2fn_null("-x", NFILE, fnm), &dr, disresdata.nres, j, idef,
-                          topInfo.mtop(), max_dr, nlevels, bThird);
+        dump_disre_matrix(
+                opt2fn_null("-x", NFILE, fnm), &dr, disresdata.nres, j, idef, topInfo.mtop(), max_dr, nlevels, bThird);
         xvgrclose(out);
         xvgrclose(aver);
         xvgrclose(numv);
index 1cfcde6f3876650d12fe9f2c2f8951bbd8cacf8f..206e33b1cc251d584e7740e71a11d9a9d5cf91fd 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +90,13 @@ static void printDsspResult(char* dssp, const DsspInputStrings& strings, const s
 #if HAVE_PIPES || GMX_NATIVE_WINDOWS
     sprintf(dssp, "%s -i %s %s", strings.dptr.c_str(), strings.pdbfile.c_str(), redirectionString.c_str());
 #else
-    sprintf(dssp, "%s -i %s -o %s > %s %s", strings.dptr.c_str(), strings.pdbfile.c_str(),
-            strings.tmpfile.c_str(), NULL_DEVICE, redirectionString.c_str());
+    sprintf(dssp,
+            "%s -i %s -o %s > %s %s",
+            strings.dptr.c_str(),
+            strings.pdbfile.c_str(),
+            strings.tmpfile.c_str(),
+            NULL_DEVICE,
+            redirectionString.c_str());
 #endif
 }
 
@@ -106,13 +111,13 @@ static int strip_dssp(FILE*                   tapeout,
                       int                     average_area[],
                       const gmx_output_env_t* oenv)
 {
-    static gmx_bool bFirst = TRUE;
-    static char*    ssbuf;
-    char            buf[STRLEN + 1];
-    char            SSTP;
-    int             nr, iacc, nresidues;
-    int             naccf, naccb; /* Count hydrophobic and hydrophilic residues */
-    real            iaccf, iaccb;
+    static gmx_bool    bFirst = TRUE;
+    static std::string ssbuf;
+    char               buf[STRLEN + 1];
+    char               SSTP;
+    int                nr, iacc, nresidues;
+    int                naccf, naccb; /* Count hydrophobic and hydrophilic residues */
+    real               iaccf, iaccb;
 
 
     /* Skip header */
@@ -128,7 +133,7 @@ static int strip_dssp(FILE*                   tapeout,
          * we allocate 2*nres-1, since for each chain there is a
          * separating line in the temp file. (At most each residue
          * could have been defined as a separate chain.) */
-        snew(ssbuf, 2 * nres - 1);
+        ssbuf.resize(2 * nres - 1);
     }
 
     iaccb = iaccf = 0;
@@ -176,8 +181,7 @@ static int strip_dssp(FILE*                   tapeout,
     {
         if (nullptr != acc)
         {
-            fprintf(stderr, "%d residues were classified as hydrophobic and %d as hydrophilic.\n",
-                    naccb, naccf);
+            fprintf(stderr, "%d residues were classified as hydrophobic and %d as hydrophilic.\n", naccb, naccf);
         }
 
         mat->title     = "Secondary structure";
@@ -245,7 +249,9 @@ static gmx_bool* bPhobics(t_atoms* atoms)
     if (i != j)
     {
         fprintf(stderr,
-                "Not all residues were recognized (%d from %d), the result may be inaccurate!\n", j, i);
+                "Not all residues were recognized (%d from %d), the result may be inaccurate!\n",
+                j,
+                i);
     }
 
     for (i = 0; (i < n_surf); i++)
@@ -299,8 +305,7 @@ static void norm_acc(t_atoms* atoms, int nres, const real av_area[], real norm_a
         }
         else
         {
-            fprintf(stderr, "Residue %s not found in surface database (%s)\n",
-                    *atoms->resinfo[i].name, surffn);
+            fprintf(stderr, "Residue %s not found in surface database (%s)\n", *atoms->resinfo[i].name, surffn);
         }
     }
 }
@@ -361,8 +366,22 @@ static void write_sas_mat(const char* fn, real** accr, int nframe, int nres, t_m
         }
         fp   = gmx_ffopen(fn, "w");
         nlev = static_cast<int>(hi - lo + 1);
-        write_xpm(fp, 0, "Solvent Accessible Surface", "Surface (A^2)", "Time", "Residue Index",
-                  nframe, nres, mat->axis_x.data(), mat->axis_y.data(), accr, lo, hi, rlo, rhi, &nlev);
+        write_xpm(fp,
+                  0,
+                  "Solvent Accessible Surface",
+                  "Surface (A^2)",
+                  "Time",
+                  "Residue Index",
+                  nframe,
+                  nres,
+                  mat->axis_x.data(),
+                  mat->axis_y.data(),
+                  accr,
+                  lo,
+                  hi,
+                  rlo,
+                  rhi,
+                  &nlev);
         gmx_ffclose(fp);
     }
 }
@@ -385,8 +404,8 @@ static void analyse_ss(const char* outfile, t_matrix* mat, const char* ss_string
         leg.emplace_back(m.desc);
     }
 
-    fp = xvgropen(outfile, "Secondary Structure", output_env_get_xvgr_tlabel(oenv),
-                  "Number of Residues", oenv);
+    fp = xvgropen(
+            outfile, "Secondary Structure", output_env_get_xvgr_tlabel(oenv), "Number of Residues", oenv);
     if (output_env_get_print_xvgr_codes(oenv))
     {
         fprintf(fp, "@ subtitle \"Structure = ");
@@ -458,13 +477,16 @@ static void analyse_ss(const char* outfile, t_matrix* mat, const char* ss_string
 int gmx_do_dssp(int argc, char* argv[])
 {
     const char* desc[] = {
-        "[THISMODULE] ", "reads a trajectory file and computes the secondary structure for",
-        "each time frame ", "calling the dssp program. If you do not have the dssp program,",
+        "[THISMODULE] ",
+        "reads a trajectory file and computes the secondary structure for",
+        "each time frame ",
+        "calling the dssp program. If you do not have the dssp program,",
         "get it from http://swift.cmbi.ru.nl/gv/dssp. [THISMODULE] assumes ",
         "that the dssp executable is located in ",
         // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
         "[TT]" GMX_DSSP_PROGRAM_PATH "[tt]. If this is not the case, then you should",
-        "set an environment variable [TT]DSSP[tt] pointing to the dssp", "executable, e.g.: [PAR]",
+        "set an environment variable [TT]DSSP[tt] pointing to the dssp",
+        "executable, e.g.: [PAR]",
         "[TT]setenv DSSP /opt/dssp/bin/dssp[tt][PAR]",
         "Since version 2.0.0, dssp is invoked with a syntax that differs",
         "from earlier versions. If you have an older version of dssp,",
@@ -476,7 +498,8 @@ int gmx_do_dssp(int argc, char* argv[])
         "[REF].xpm[ref] matrix file. This file can be visualized with for instance",
         "[TT]xv[tt] and can be converted to postscript with [TT]xpm2ps[tt].",
         "Individual chains are separated by light grey lines in the [REF].xpm[ref] and",
-        "postscript files.", "The number of residues with each secondary structure type and the",
+        "postscript files.",
+        "The number of residues with each secondary structure type and the",
         "total secondary structure ([TT]-sss[tt]) count as a function of",
         "time are also written to file ([TT]-sc[tt]).[PAR]",
         "Solvent accessible surface (SAS) per residue can be calculated, both in",
@@ -538,8 +561,18 @@ int gmx_do_dssp(int argc, char* argv[])
     };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW | PCA_TIME_UNIT, NFILE, fnm,
-                           asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(&argc,
+                           argv,
+                           PCA_CAN_TIME | PCA_CAN_VIEW | PCA_TIME_UNIT,
+                           NFILE,
+                           fnm,
+                           asize(pa),
+                           pa,
+                           asize(desc),
+                           desc,
+                           0,
+                           nullptr,
+                           &oenv))
     {
         return 0;
     }
@@ -635,8 +668,11 @@ int gmx_do_dssp(int argc, char* argv[])
 
     if (fnTArea)
     {
-        fTArea = xvgropen(fnTArea, "Solvent Accessible Surface Area",
-                          output_env_get_xvgr_tlabel(oenv), "Area (nm\\S2\\N)", oenv);
+        fTArea = xvgropen(fnTArea,
+                          "Solvent Accessible Surface Area",
+                          output_env_get_xvgr_tlabel(oenv),
+                          "Area (nm\\S2\\N)",
+                          oenv);
         xvgr_legend(fTArea, 2, leg, oenv);
     }
     else
index 2c1a9717c4e8f6817d4a0b5320c5f81dd951453a..25d2acc2f2be1b2a813758e785d87d3cf3216325 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2011-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,12 +190,12 @@ static double calc_Shs(double f, double y)
 {
     double fy = f * y;
 
-    return BOLTZ * (std::log(calc_compress(fy)) + fy * (3 * fy - 4) / gmx::square(1 - fy));
+    return gmx::c_boltz * (std::log(calc_compress(fy)) + fy * (3 * fy - 4) / gmx::square(1 - fy));
 }
 
 static real wCsolid(real nu, real beta)
 {
-    real bhn = beta * PLANCK * nu;
+    real bhn = beta * gmx::c_planck * nu;
     real ebn, koko;
 
     if (bhn == 0)
@@ -212,7 +212,7 @@ static real wCsolid(real nu, real beta)
 
 static real wSsolid(real nu, real beta)
 {
-    real bhn = beta * PLANCK * nu;
+    real bhn = beta * gmx::c_planck * nu;
 
     if (bhn == 0)
     {
@@ -226,7 +226,7 @@ static real wSsolid(real nu, real beta)
 
 static real wAsolid(real nu, real beta)
 {
-    real bhn = beta * PLANCK * nu;
+    real bhn = beta * gmx::c_planck * nu;
 
     if (bhn == 0)
     {
@@ -240,7 +240,7 @@ static real wAsolid(real nu, real beta)
 
 static real wEsolid(real nu, real beta)
 {
-    real bhn = beta * PLANCK * nu;
+    real bhn = beta * gmx::c_planck * nu;
 
     if (bhn == 0)
     {
@@ -334,14 +334,14 @@ int gmx_dos(int argc, char* argv[])
 
     npargs = asize(pa);
     ppa    = add_acf_pargs(&npargs, pa);
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa,
-                           asize(desc), desc, asize(bugs), bugs, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
         sfree(ppa);
         return 0;
     }
 
-    beta = 1 / (Temp * BOLTZ);
+    beta = 1 / (Temp * gmx::c_boltz);
 
     fplog = gmx_fio_fopen(ftp2fn(efLOG, NFILE, fnm), "w");
     fprintf(fplog, "Doing density of states analysis based on trajectory.\n");
@@ -410,8 +410,7 @@ int gmx_dos(int argc, char* argv[])
 
     if (nframes < min_frames)
     {
-        gmx_fatal(FARGS, "You need at least %d frames in the trajectory and you only have %d.",
-                  min_frames, nframes);
+        gmx_fatal(FARGS, "You need at least %d frames in the trajectory and you only have %d.", min_frames, nframes);
     }
     dt = (t1 - t0) / (nframes - 1);
     if (nV > 0)
@@ -437,8 +436,8 @@ int gmx_dos(int argc, char* argv[])
     normalizeAutocorrelation = opt2parg_bool("-normalize", npargs, ppa);
 
     /* Note that we always disable normalization here, regardless of user settings */
-    low_do_autocorr(nullptr, oenv, nullptr, nframes, gnx, nframes, c1, dt, eacNormal, 0, FALSE,
-                    FALSE, FALSE, -1, -1, 0);
+    low_do_autocorr(
+            nullptr, oenv, nullptr, nframes, gnx, nframes, c1, dt, eacNormal, 0, FALSE, FALSE, FALSE, -1, -1, 0);
     snew(dos, DOS_NR);
     for (j = 0; (j < DOS_NR); j++)
     {
@@ -460,8 +459,8 @@ int gmx_dos(int argc, char* argv[])
         }
     }
 
-    fp = xvgropen(opt2fn("-vacf", NFILE, fnm), "Velocity autocorrelation function", "Time (ps)",
-                  "C(t)", oenv);
+    fp = xvgropen(
+            opt2fn("-vacf", NFILE, fnm), "Velocity autocorrelation function", "Time (ps)", "C(t)", oenv);
     snew(tt, nframes / 2);
 
     invNormalize = normalizeAutocorrelation ? 1.0 / dos[VACF][0] : 1.0;
@@ -473,8 +472,11 @@ int gmx_dos(int argc, char* argv[])
     }
     xvgrclose(fp);
 
-    fp = xvgropen(opt2fn("-mvacf", NFILE, fnm), "Mass-weighted velocity autocorrelation function",
-                  "Time (ps)", "C(t)", oenv);
+    fp = xvgropen(opt2fn("-mvacf", NFILE, fnm),
+                  "Mass-weighted velocity autocorrelation function",
+                  "Time (ps)",
+                  "C(t)",
+                  oenv);
 
     invNormalize = normalizeAutocorrelation ? 1.0 / dos[VACF][0] : 1.0;
 
@@ -525,15 +527,16 @@ int gmx_dos(int argc, char* argv[])
     DoS0 = dos[DOS][0];
 
     /* Note this eqn. is incorrect in Pascal2011a! */
-    Delta = ((2 * DoS0 / (9 * Natom)) * std::sqrt(M_PI * BOLTZ * Temp * Natom / tmass)
+    Delta = ((2 * DoS0 / (9 * Natom)) * std::sqrt(M_PI * gmx::c_boltz * Temp * Natom / tmass)
              * std::pow((Natom / V), 1.0 / 3.0) * std::pow(6.0 / M_PI, 2.0 / 3.0));
     f     = calc_fluidicity(Delta, toler);
     y     = calc_y(f, Delta, toler);
     z     = calc_compress(y);
-    Sig   = BOLTZ
-          * (5.0 / 2.0 + std::log(2 * M_PI * BOLTZ * Temp / (gmx::square(PLANCK)) * V / (f * Natom)));
+    Sig   = gmx::c_boltz
+          * (5.0 / 2.0
+             + std::log(2 * M_PI * gmx::c_boltz * Temp / (gmx::square(gmx::c_planck)) * V / (f * Natom)));
     Shs   = Sig + calc_Shs(f, y);
-    rho   = (tmass * AMU) / (V * NANO * NANO * NANO);
+    rho   = (tmass * gmx::c_amu) / (V * gmx::c_nano * gmx::c_nano * gmx::c_nano);
     sigHS = std::cbrt(6 * y * V / (M_PI * Natom));
 
     fprintf(fplog, "System = \"%s\"\n", *top.name);
@@ -559,22 +562,29 @@ int gmx_dos(int argc, char* argv[])
     fprintf(fplog, "DoSTot = %g\n", dostot);
 
     /* Now compute solid (2) and diffusive (3) components */
-    fp = xvgropen(opt2fn("-dos", NFILE, fnm), "Density of states",
-                  bRecip ? "E (cm\\S-1\\N)" : "\\f{12}n\\f{4} (1/ps)", "\\f{4}S(\\f{12}n\\f{4})", oenv);
+    fp = xvgropen(opt2fn("-dos", NFILE, fnm),
+                  "Density of states",
+                  bRecip ? "E (cm\\S-1\\N)" : "\\f{12}n\\f{4} (1/ps)",
+                  "\\f{4}S(\\f{12}n\\f{4})",
+                  oenv);
     xvgr_legend(fp, asize(DoSlegend), DoSlegend, oenv);
-    recip_fac = bRecip ? (1e7 / SPEED_OF_LIGHT) : 1.0;
+    recip_fac = bRecip ? (1e7 / gmx::c_speedOfLight) : 1.0;
     for (j = 0; (j < nframes / 4); j++)
     {
         dos[DOS_DIFF][j]  = DoS0 / (1 + gmx::square(DoS0 * M_PI * nu[j] / (6 * f * Natom)));
         dos[DOS_SOLID][j] = dos[DOS][j] - dos[DOS_DIFF][j];
-        fprintf(fp, "%10g  %10g  %10g  %10g\n", recip_fac * nu[j], dos[DOS][j] / recip_fac,
-                dos[DOS_SOLID][j] / recip_fac, dos[DOS_DIFF][j] / recip_fac);
+        fprintf(fp,
+                "%10g  %10g  %10g  %10g\n",
+                recip_fac * nu[j],
+                dos[DOS][j] / recip_fac,
+                dos[DOS_SOLID][j] / recip_fac,
+                dos[DOS_DIFF][j] / recip_fac);
     }
     xvgrclose(fp);
 
     /* Finally analyze the results! */
     wCdiff = 0.5;
-    wSdiff = Shs / (3 * BOLTZ); /* Is this correct? */
+    wSdiff = Shs / (3 * gmx::c_boltz); /* Is this correct? */
     wEdiff = 0.5;
     wAdiff = wEdiff - wSdiff;
     for (j = 0; (j < nframes / 4); j++)
@@ -589,7 +599,8 @@ int gmx_dos(int argc, char* argv[])
     fprintf(fplog, "Diffusion coefficient from VACF %g 10^-5 cm^2/s\n", DiffCoeff);
     fprintf(fplog, "Diffusion coefficient from DoS %g 10^-5 cm^2/s\n", 1000 * DoS0 / (12 * tmass * beta));
 
-    cP = BOLTZ * evaluate_integral(nframes / 4, nu, dos[DOS_CP], nullptr, int{ nframes / 4 }, &stddev);
+    cP = gmx::c_boltz
+         * evaluate_integral(nframes / 4, nu, dos[DOS_CP], nullptr, int{ nframes / 4 }, &stddev);
     fprintf(fplog, "Heat capacity %g J/mol K\n", 1000 * cP / Nmol);
     fprintf(fplog, "\nArrivederci!\n");
     gmx_fio_fclose(fplog);
index 301ca77e8ee8da3abecf420d2a35eae848faf289..c32ddfc29ad36fc0e5c881d3f95e1e1f5ee33884 100644 (file)
@@ -125,8 +125,18 @@ int gmx_dyecoupl(int argc, char* argv[])
                              rrange, krange, rincr, kincr, Rfrac;
     int rkcount = 0, rblocksallocated = 0, kblocksallocated = 0;
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_BEGIN | PCA_CAN_END | PCA_CAN_VIEW | PCA_TIME_UNIT,
-                           NFILE, fnm, NPA, pa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(&argc,
+                           argv,
+                           PCA_CAN_BEGIN | PCA_CAN_END | PCA_CAN_VIEW | PCA_TIME_UNIT,
+                           NFILE,
+                           fnm,
+                           NPA,
+                           pa,
+                           asize(desc),
+                           desc,
+                           0,
+                           nullptr,
+                           &oenv))
     {
         return 0;
     }
@@ -228,15 +238,21 @@ int gmx_dyecoupl(int argc, char* argv[])
 
             if (bRKout)
             {
-                rkfp = xvgropen(out_xvgrkfile, "Distance and \\f{Symbol}k\\f{}\\S2\\N trajectory",
-                                "Time (ps)", "Distance (nm) / \\f{Symbol}k\\f{}\\S2\\N", oenv);
+                rkfp = xvgropen(out_xvgrkfile,
+                                "Distance and \\f{Symbol}k\\f{}\\S2\\N trajectory",
+                                "Time (ps)",
+                                "Distance (nm) / \\f{Symbol}k\\f{}\\S2\\N",
+                                oenv);
                 xvgr_legend(rkfp, 2, rkleg, oenv);
             }
 
             if (bInstEffout)
             {
-                iefp = xvgropen(out_xvginstefffile, "Instantaneous RET Efficiency", "Time (ps)",
-                                "RET Efficiency", oenv);
+                iefp = xvgropen(out_xvginstefffile,
+                                "Instantaneous RET Efficiency",
+                                "Time (ps)",
+                                "RET Efficiency",
+                                oenv);
                 xvgr_legend(iefp, 1, ieleg, oenv);
             }
 
@@ -396,13 +412,16 @@ int gmx_dyecoupl(int argc, char* argv[])
                     {
                         rhist[i] /= rkcount * rrange / histbins;
                     }
-                    rhfp = xvgropen(out_xvgrhistfile, "Distance Distribution", "R (nm)",
-                                    "Normalized Probability", oenv);
+                    rhfp = xvgropen(out_xvgrhistfile,
+                                    "Distance Distribution",
+                                    "R (nm)",
+                                    "Normalized Probability",
+                                    oenv);
                 }
                 else
                 {
-                    rhfp = xvgropen(out_xvgrhistfile, "Distance Distribution", "R (nm)",
-                                    "Probability", oenv);
+                    rhfp = xvgropen(
+                            out_xvgrhistfile, "Distance Distribution", "R (nm)", "Probability", oenv);
                 }
                 xvgr_legend(rhfp, 1, rhleg, oenv);
                 for (i = 0; i < histbins; i++)
@@ -429,13 +448,19 @@ int gmx_dyecoupl(int argc, char* argv[])
                     {
                         khist[i] /= rkcount * krange / histbins;
                     }
-                    khfp = xvgropen(out_xvgkhistfile, "\\f{Symbol}k\\f{}\\S2\\N Distribution",
-                                    "\\f{Symbol}k\\f{}\\S2\\N", "Normalized Probability", oenv);
+                    khfp = xvgropen(out_xvgkhistfile,
+                                    "\\f{Symbol}k\\f{}\\S2\\N Distribution",
+                                    "\\f{Symbol}k\\f{}\\S2\\N",
+                                    "Normalized Probability",
+                                    oenv);
                 }
                 else
                 {
-                    khfp = xvgropen(out_xvgkhistfile, "\\f{Symbol}k\\f{}\\S2\\N Distribution",
-                                    "\\f{Symbol}k\\f{}\\S2\\N", "Probability", oenv);
+                    khfp = xvgropen(out_xvgkhistfile,
+                                    "\\f{Symbol}k\\f{}\\S2\\N Distribution",
+                                    "\\f{Symbol}k\\f{}\\S2\\N",
+                                    "Probability",
+                                    oenv);
                 }
                 xvgr_legend(khfp, 1, khleg, oenv);
                 for (i = 0; i < histbins; i++)
index 25b5db751300e6417cf675caed0d6de5476311a6..ae4341958dd14fe4a33ca86067884734faa0aa98 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +83,22 @@ static int search_str2(int nstr, char** str, char* key)
     return -1;
 }
 
+// The non-bonded energy terms accumulated for energy group pairs. These were superseded elsewhere
+// by NonBondedEnergyTerms but not updated here due to the need for refactoring here first.
+enum
+{
+    egCOULSR,
+    egLJSR,
+    egBHAMSR,
+    egCOUL14,
+    egLJ14,
+    egNR
+};
+
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static const char* egrp_nm[egNR + 1] = { "Coul-SR", "LJ-SR", "Buck-SR", "Coul-14", "LJ-14", nullptr };
+
+
 int gmx_enemat(int argc, char* argv[])
 {
     const char* desc[] = {
@@ -190,8 +206,8 @@ int gmx_enemat(int argc, char* argv[])
                        { efXVG, "-etot", "energy", ffWRITE } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -254,7 +270,9 @@ int gmx_enemat(int argc, char* argv[])
                         fprintf(stderr,
                                 "WARNING! could not find group %s (%d,%d) "
                                 "in energy file\n",
-                                groupname, i, j);
+                                groupname,
+                                i,
+                                j);
                     }
                     else
                     {
@@ -330,7 +348,9 @@ int gmx_enemat(int argc, char* argv[])
     fprintf(stderr,
             "Will build energy half-matrix of %d groups, %d elements, "
             "over %d frames\n",
-            ngroups, nset, nenergy);
+            ngroups,
+            nset,
+            nenergy);
 
     snew(emat, egNR + egSP);
     for (j = 0; (j < egNR + egSP); j++)
@@ -415,7 +435,7 @@ int gmx_enemat(int argc, char* argv[])
                 }
                 eaver[i] /= nenergy;
             }
-            beta = 1.0 / (BOLTZ * reftemp);
+            beta = 1.0 / (gmx::c_boltz * reftemp);
             snew(efree, ngroups);
             snew(edif, ngroups);
             for (i = 0; (i < ngroups); i++)
@@ -476,7 +496,8 @@ int gmx_enemat(int argc, char* argv[])
                     fprintf(stderr,
                             "Matrix of %s energy is uniform at %f "
                             "(will not produce output).\n",
-                            egrp_nm[m], emax);
+                            egrp_nm[m],
+                            emax);
                 }
                 else
                 {
@@ -499,21 +520,62 @@ int gmx_enemat(int argc, char* argv[])
                     out = gmx_ffopen(fn, "w");
                     if (emin >= emid)
                     {
-                        write_xpm(out, 0, label, "Energy (kJ/mol)", "Residue Index",
-                                  "Residue Index", ngroups, ngroups, groupnr, groupnr, emat[m],
-                                  emid, emax, rmid, rhi, &nlevels);
+                        write_xpm(out,
+                                  0,
+                                  label,
+                                  "Energy (kJ/mol)",
+                                  "Residue Index",
+                                  "Residue Index",
+                                  ngroups,
+                                  ngroups,
+                                  groupnr,
+                                  groupnr,
+                                  emat[m],
+                                  emid,
+                                  emax,
+                                  rmid,
+                                  rhi,
+                                  &nlevels);
                     }
                     else if (emax <= emid)
                     {
-                        write_xpm(out, 0, label, "Energy (kJ/mol)", "Residue Index",
-                                  "Residue Index", ngroups, ngroups, groupnr, groupnr, emat[m],
-                                  emin, emid, rlo, rmid, &nlevels);
+                        write_xpm(out,
+                                  0,
+                                  label,
+                                  "Energy (kJ/mol)",
+                                  "Residue Index",
+                                  "Residue Index",
+                                  ngroups,
+                                  ngroups,
+                                  groupnr,
+                                  groupnr,
+                                  emat[m],
+                                  emin,
+                                  emid,
+                                  rlo,
+                                  rmid,
+                                  &nlevels);
                     }
                     else
                     {
-                        write_xpm3(out, 0, label, "Energy (kJ/mol)", "Residue Index",
-                                   "Residue Index", ngroups, ngroups, groupnr, groupnr, emat[m],
-                                   emin, emid, emax, rlo, rmid, rhi, &nlevels);
+                        write_xpm3(out,
+                                   0,
+                                   label,
+                                   "Energy (kJ/mol)",
+                                   "Residue Index",
+                                   "Residue Index",
+                                   ngroups,
+                                   ngroups,
+                                   groupnr,
+                                   groupnr,
+                                   emat[m],
+                                   emin,
+                                   emid,
+                                   emax,
+                                   rlo,
+                                   rmid,
+                                   rhi,
+                                   &nlevels);
                     }
                     gmx_ffclose(out);
                 }
index 25e6a2e9c73f10e1baac5de8b46f5476024df6a2..b62f88bf0c130a852912e772744d2efd97ec6aec 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -340,8 +340,8 @@ static void einstein_visco(const char*             fn,
         avold[i] = 0;
     }
     fp0 = xvgropen(fni, "Shear viscosity integral", "Time (ps)", "(kg m\\S-1\\N s\\S-1\\N ps)", oenv);
-    fp1 = xvgropen(fn, "Shear viscosity using Einstein relation", "Time (ps)",
-                   "(kg m\\S-1\\N s\\S-1\\N)", oenv);
+    fp1 = xvgropen(
+            fn, "Shear viscosity using Einstein relation", "Time (ps)", "(kg m\\S-1\\N s\\S-1\\N)", oenv);
     for (i = 0; i < nf4; i++)
     {
         for (m = 0; m <= nsets; m++)
@@ -359,7 +359,8 @@ static void einstein_visco(const char*             fn,
             }
         }
         /* Convert to SI for the viscosity */
-        fac = (V * NANO * NANO * NANO * PICO * 1e10) / (2 * BOLTZMANN * T) / (nint - i);
+        fac = (V * gmx::c_nano * gmx::c_nano * gmx::c_nano * gmx::c_pico * 1e10)
+              / (2 * gmx::c_boltzmann * T) / (nint - i);
         fprintf(fp0, "%10g", i * dt);
         for (m = 0; (m <= nsets); m++)
         {
@@ -596,8 +597,12 @@ static void calc_averages(int nset, enerdata_t* edat, int nbmin, int nbmax)
             if (debug)
             {
                 char buf1[STEPSTRSIZE], buf2[STEPSTRSIZE];
-                fprintf(debug, "Requested %d blocks, we have %d blocks, min %s nsteps %s\n", nb,
-                        eee[nb].b, gmx_step_str(eee[nb].nst_min, buf1), gmx_step_str(edat->nsteps, buf2));
+                fprintf(debug,
+                        "Requested %d blocks, we have %d blocks, min %s nsteps %s\n",
+                        nb,
+                        eee[nb].b,
+                        gmx_step_str(eee[nb].nst_min, buf1),
+                        gmx_step_str(edat->nsteps, buf2));
             }
             if (eee[nb].b == nb && 5 * nb * eee[nb].nst_min >= 4 * edat->nsteps)
             {
@@ -733,7 +738,7 @@ static void calc_fluctuation_props(FILE*       fp,
     const char* my_ener[] = { "Volume", "Enthalpy", "Temperature", "Total Energy" };
     int         ii[eNR];
 
-    NANO3 = NANO * NANO * NANO;
+    NANO3 = gmx::c_nano * gmx::c_nano * gmx::c_nano;
     if (!bDriftCorr)
     {
         fprintf(fp,
@@ -766,15 +771,15 @@ if ((ii[eVol] < nset) && (ii[eTemp] < nset))
 {
     vv    = edat->s[ii[eVol]].av * NANO3;
     varv  = gmx::square(edat->s[ii[eVol]].rmsd * NANO3);
-    kappa = (varv / vv) / (BOLTZMANN * tt);
+    kappa = (varv / vv) / (gmx::c_boltzmann * tt);
 }
 /* Enthalpy */
 hh = varh = NOTSET;
 if ((ii[eEnth] < nset) && (ii[eTemp] < nset))
 {
-    hh   = KILO * edat->s[ii[eEnth]].av / AVOGADRO;
-    varh = gmx::square(KILO * edat->s[ii[eEnth]].rmsd / AVOGADRO);
-    cp   = AVOGADRO * ((varh / nmol) / (BOLTZMANN * tt * tt));
+    hh   = gmx::c_kilo * edat->s[ii[eEnth]].av / gmx::c_avogadro;
+    varh = gmx::square(gmx::c_kilo * edat->s[ii[eEnth]].rmsd / gmx::c_avogadro);
+    cp   = gmx::c_avogadro * ((varh / nmol) / (gmx::c_boltzmann * tt * tt));
 }
 /* Total energy */
 if ((ii[eEtot] < nset) && (hh == NOTSET) && (tt != NOTSET))
@@ -783,7 +788,7 @@ if ((ii[eEtot] < nset) && (hh == NOTSET) && (tt != NOTSET))
        by checking whether the enthalpy was computed.
      */
     varet = gmx::square(edat->s[ii[eEtot]].rmsd);
-    cv    = KILO * ((varet / nmol) / (BOLTZ * tt * tt));
+    cv    = gmx::c_kilo * ((varet / nmol) / (gmx::c_boltz * tt * tt));
 }
 /* Alpha, dcp */
 if ((ii[eVol] < nset) && (ii[eEnth] < nset) && (ii[eTemp] < nset))
@@ -793,7 +798,7 @@ if ((ii[eVol] < nset) && (ii[eEnth] < nset) && (ii[eTemp] < nset))
     for (j = 0; (j < edat->nframes); j++)
     {
         v = edat->s[ii[eVol]].ener[j] * NANO3;
-        h = KILO * edat->s[ii[eEnth]].ener[j] / AVOGADRO;
+        h = gmx::c_kilo * edat->s[ii[eEnth]].ener[j] / gmx::c_avogadro;
         v_sum += v;
         h_sum += h;
         vh_sum += (v * h);
@@ -801,8 +806,8 @@ if ((ii[eVol] < nset) && (ii[eEnth] < nset) && (ii[eTemp] < nset))
     vh_aver = vh_sum / edat->nframes;
     v_aver  = v_sum / edat->nframes;
     h_aver  = h_sum / edat->nframes;
-    alpha   = (vh_aver - v_aver * h_aver) / (v_aver * BOLTZMANN * tt * tt);
-    dcp     = (v_aver * AVOGADRO / nmol) * tt * gmx::square(alpha) / (kappa);
+    alpha   = (vh_aver - v_aver * h_aver) / (v_aver * gmx::c_boltzmann * tt * tt);
+    dcp     = (v_aver * gmx::c_avogadro / nmol) * tt * gmx::square(alpha) / (kappa);
 }
 
 if (tt != NOTSET)
@@ -823,17 +828,18 @@ if (tt != NOTSET)
     {
         if (varv != NOTSET)
         {
-            fprintf(fp, "varv  =  %10g (m^6)\n", varv * AVOGADRO / nmol);
+            fprintf(fp, "varv  =  %10g (m^6)\n", varv * gmx::c_avogadro / nmol);
         }
     }
     if (vv != NOTSET)
     {
-        fprintf(fp, "Volume                                   = %10g m^3/mol\n", vv * AVOGADRO / nmol);
+        fprintf(fp, "Volume                                   = %10g m^3/mol\n", vv * gmx::c_avogadro / nmol);
     }
     if (varh != NOTSET)
     {
-        fprintf(fp, "Enthalpy                                 = %10g kJ/mol\n",
-                hh * AVOGADRO / (KILO * nmol));
+        fprintf(fp,
+                "Enthalpy                                 = %10g kJ/mol\n",
+                hh * gmx::c_avogadro / (gmx::c_kilo * nmol));
     }
     if (alpha != NOTSET)
     {
@@ -913,8 +919,12 @@ static void analyse_ener(gmx_bool                bCorr,
         /* Calculate the time difference */
         delta_t = t - start_t;
 
-        fprintf(stdout, "\nStatistics over %s steps [ %.4f through %.4f ps ], %d data sets\n",
-                gmx_step_str(nsteps, buf), start_t, t, nset);
+        fprintf(stdout,
+                "\nStatistics over %s steps [ %.4f through %.4f ps ], %d data sets\n",
+                gmx_step_str(nsteps, buf),
+                start_t,
+                t,
+                nset);
 
         calc_averages(nset, edat, nbmin, nbmax);
 
@@ -963,13 +973,20 @@ static void analyse_ener(gmx_bool                bCorr,
                     fprintf(stdout, " '%s'", leg[i]);
                 }
             }
-            fprintf(stdout, " %s has statistics over %d points (frames)\n",
-                    nnotexact == 1 ? "is" : "are", edat->nframes);
+            fprintf(stdout,
+                    " %s has statistics over %d points (frames)\n",
+                    nnotexact == 1 ? "is" : "are",
+                    edat->nframes);
             fprintf(stdout, "All other statistics are over %s points\n", gmx_step_str(edat->npoints, buf));
         }
         fprintf(stdout, "\n");
 
-        fprintf(stdout, "%-24s %10s %10s %10s %10s", "Energy", "Average", "Err.Est.", "RMSD",
+        fprintf(stdout,
+                "%-24s %10s %10s %10s %10s",
+                "Energy",
+                "Average",
+                "Err.Est.",
+                "RMSD",
                 "Tot-Drift");
         if (bFee)
         {
@@ -987,7 +1004,7 @@ static void analyse_ener(gmx_bool                bCorr,
         expEtot = 0;
         if (bFee)
         {
-            beta = 1.0 / (BOLTZ * reftemp);
+            beta = 1.0 / (gmx::c_boltz * reftemp);
             snew(fee, nset);
         }
         for (i = 0; (i < nset); i++)
@@ -1063,12 +1080,20 @@ static void analyse_ener(gmx_bool                bCorr,
         {
             totaldrift = (edat->nsteps - 1) * esum->s[0].slope;
             ee_pr(esum->s[0].ee / nmol, sizeof(eebuf), eebuf);
-            fprintf(stdout, "%-24s %10g %10s %10s %10g  (%s)", "Total", esum->s[0].av / nmol, eebuf,
-                    "--", totaldrift / nmol, enm[set[0]].unit);
+            fprintf(stdout,
+                    "%-24s %10g %10s %10s %10g  (%s)",
+                    "Total",
+                    esum->s[0].av / nmol,
+                    eebuf,
+                    "--",
+                    totaldrift / nmol,
+                    enm[set[0]].unit);
             /* pr_aver,pr_stddev,a,totaldrift */
             if (bFee)
             {
-                fprintf(stdout, "  %10g  %10g\n", std::log(expEtot) / beta + esum->s[0].av / nmol,
+                fprintf(stdout,
+                        "  %10g  %10g\n",
+                        std::log(expEtot) / beta + esum->s[0].av / nmol,
                         std::log(expEtot) / beta);
             }
             else
@@ -1148,15 +1173,43 @@ static void analyse_ener(gmx_bool                bCorr,
             /*do_autocorr(corrfn,buf,nenergy,3,eneset,Dt,eacNormal,TRUE);*/
             /* Do it for shear viscosity */
             std::strcpy(buf, "Shear Viscosity");
-            low_do_autocorr(corrfn, oenv, buf, edat->nframes, 3, (edat->nframes + 1) / 2, eneset,
-                            Dt, eacNormal, 1, TRUE, FALSE, FALSE, 0.0, 0.0, 0);
+            low_do_autocorr(corrfn,
+                            oenv,
+                            buf,
+                            edat->nframes,
+                            3,
+                            (edat->nframes + 1) / 2,
+                            eneset,
+                            Dt,
+                            eacNormal,
+                            1,
+                            TRUE,
+                            FALSE,
+                            FALSE,
+                            0.0,
+                            0.0,
+                            0);
 
             /* Now for bulk viscosity */
             std::strcpy(buf, "Bulk Viscosity");
-            low_do_autocorr(corrfn, oenv, buf, edat->nframes, 1, (edat->nframes + 1) / 2,
-                            &(eneset[11]), Dt, eacNormal, 1, TRUE, FALSE, FALSE, 0.0, 0.0, 0);
-
-            factor = (Vaver * 1e-26 / (BOLTZMANN * Temp)) * Dt;
+            low_do_autocorr(corrfn,
+                            oenv,
+                            buf,
+                            edat->nframes,
+                            1,
+                            (edat->nframes + 1) / 2,
+                            &(eneset[11]),
+                            Dt,
+                            eacNormal,
+                            1,
+                            TRUE,
+                            FALSE,
+                            FALSE,
+                            0.0,
+                            0.0,
+                            0);
+
+            factor = (Vaver * 1e-26 / (gmx::c_boltzmann * Temp)) * Dt;
             fp     = xvgropen(visfn, buf, "Time (ps)", "\\8h\\4 (cp)", oenv);
             xvgr_legend(fp, asize(leg), leg, oenv);
 
@@ -1195,7 +1248,7 @@ static void analyse_ener(gmx_bool                bCorr,
 #if 0
             do_autocorr(corrfn, oenv, buf, edat->nframes,
                         bSum ? 1                 : nset,
-                        bSum ? &edat->s[nset-1].ener : eneset,
+                        bSum ? &edat->s[nset-1].energyGroupPairTerms : eneset,
                         (delta_t/edat->nframes), eacNormal, FALSE);
 #endif
         }
@@ -1285,8 +1338,11 @@ static void fec(const char*             ene2fn,
 
                 if (fr->t != time[nenergy2])
                 {
-                    fprintf(stderr, "\nWARNING time mismatch %g!=%g at frame %s\n", fr->t,
-                            time[nenergy2], gmx_step_str(fr->step, buf));
+                    fprintf(stderr,
+                            "\nWARNING time mismatch %g!=%g at frame %s\n",
+                            fr->t,
+                            time[nenergy2],
+                            gmx_step_str(fr->step, buf));
                 }
                 for (i = 0; i < nset; i++)
                 {
@@ -1308,13 +1364,16 @@ static void fec(const char*             ene2fn,
     fp = nullptr;
     if (runavgfn)
     {
-        fp = xvgropen(runavgfn, "Running average free energy difference", "Time (" unit_time ")",
-                      "\\8D\\4E (" unit_energy ")", oenv);
+        fp = xvgropen(runavgfn,
+                      "Running average free energy difference",
+                      "Time (" unit_time ")",
+                      "\\8D\\4E (" unit_energy ")",
+                      oenv);
         xvgr_legend(fp, asize(ravgleg), ravgleg, oenv);
     }
     fprintf(stdout, "\n%-24s %10s\n", "Energy", "dF = -kT ln < exp(-(EB-EA)/kT) >A");
     sum  = 0;
-    beta = 1.0 / (BOLTZ * reftemp);
+    beta = 1.0 / (gmx::c_boltz * reftemp);
     for (i = 0; i < nset; i++)
     {
         if (gmx_strcasecmp(leg[i], enm[set[i]].name) != 0)
@@ -1327,10 +1386,10 @@ static void fec(const char*             ene2fn,
             sum += std::exp(-dE * beta);
             if (fp)
             {
-                fprintf(fp, "%10g %10g %10g\n", time[j], dE, -BOLTZ * reftemp * std::log(sum / (j + 1)));
+                fprintf(fp, "%10g %10g %10g\n", time[j], dE, -gmx::c_boltz * reftemp * std::log(sum / (j + 1)));
             }
         }
-        aver = -BOLTZ * reftemp * std::log(sum / nenergy);
+        aver = -gmx::c_boltz * reftemp * std::log(sum / nenergy);
         fprintf(stdout, "%-24s %10g\n", leg[i], aver);
     }
     if (fp)
@@ -1379,7 +1438,7 @@ static void do_dhdl(t_enxframe*             fr,
         else if (fr->block[i].id == enxDHCOLL)
         {
             nblock_dhcoll++;
-            if ((fr->block[i].nsub < 1) || (fr->block[i].sub[0].type != xdr_datatype_double)
+            if ((fr->block[i].nsub < 1) || (fr->block[i].sub[0].type != XdrDataType::Double)
                 || (fr->block[i].sub[0].nr < 5))
             {
                 gmx_fatal(FARGS, "Unexpected block data");
@@ -1409,7 +1468,9 @@ static void do_dhdl(t_enxframe*             fr,
                 for (j = 0; j < n_lambda_vec; j++)
                 {
                     native_lambda_vec[j] = fr->block[i].sub[0].dval[5 + j];
-                    lambda_components[j] = efpt_singular_names[fr->block[i].sub[1].ival[2 + j]];
+                    lambda_components[j] =
+                            enumValueToStringSingular(static_cast<FreeEnergyPerturbationCouplingType>(
+                                    fr->block[i].sub[1].ival[2 + j]));
                 }
             }
         }
@@ -1470,8 +1531,8 @@ static void do_dhdl(t_enxframe*             fr,
                 int     nhist, derivative;
 
                 /* check the block types etc. */
-                if ((blk->nsub < 2) || (blk->sub[0].type != xdr_datatype_double)
-                    || (blk->sub[1].type != xdr_datatype_int64) || (blk->sub[0].nr < 2)
+                if ((blk->nsub < 2) || (blk->sub[0].type != XdrDataType::Double)
+                    || (blk->sub[1].type != XdrDataType::Int64) || (blk->sub[0].nr < 2)
                     || (blk->sub[1].nr < 2))
                 {
                     gmx_fatal(FARGS, "Unexpected block data in file");
@@ -1487,8 +1548,7 @@ static void do_dhdl(t_enxframe*             fr,
 
                     if (!derivative)
                     {
-                        sprintf(legend, "N(%s(%s=%g) | %s=%g)", deltag, lambda, foreign_lambda,
-                                lambda, start_lambda);
+                        sprintf(legend, "N(%s(%s=%g) | %s=%g)", deltag, lambda, foreign_lambda, lambda, start_lambda);
                     }
                     else
                     {
@@ -1556,7 +1616,7 @@ static void do_dhdl(t_enxframe*             fr,
                 if (blk->id == enxDH)
                 {
                     double value;
-                    if (blk->sub[2].type == xdr_datatype_float)
+                    if (blk->sub[2].type == XdrDataType::Float)
                     {
                         value = blk->sub[2].fval[i];
                     }
@@ -1568,8 +1628,7 @@ static void do_dhdl(t_enxframe*             fr,
 
                     if (j == 1 && ir->bExpanded)
                     {
-                        fprintf(*fp_dhdl, "%4d",
-                                static_cast<int>(value)); /* if expanded ensembles and zero, this is a state value, it's an integer. We need a cleaner conditional than if j==1! */
+                        fprintf(*fp_dhdl, "%4d", static_cast<int>(value)); /* if expanded ensembles and zero, this is a state value, it's an integer. We need a cleaner conditional than if j==1! */
                     }
                     else
                     {
@@ -1768,8 +1827,8 @@ int gmx_energy(int argc, char* argv[])
 
     npargs = asize(pa);
     ppa    = add_acf_pargs(&npargs, pa);
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END, NFILE, fnm,
-                           npargs, ppa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, nullptr, &oenv))
     {
         sfree(ppa);
         return 0;
@@ -2021,8 +2080,7 @@ int gmx_energy(int argc, char* argv[])
             }
             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);
             }
 
             /*******************************************
@@ -2110,11 +2168,32 @@ int gmx_energy(int argc, char* argv[])
     else
     {
         double dt = (frame[cur].t - start_t) / (edat.nframes - 1);
-        analyse_ener(opt2bSet("-corr", NFILE, fnm), opt2fn("-corr", NFILE, fnm),
-                     opt2fn("-evisco", NFILE, fnm), opt2fn("-eviscoi", NFILE, fnm), bFee, bSum,
-                     bFluct, bVisco, opt2fn("-vis", NFILE, fnm), nmol, start_step, start_t,
-                     frame[cur].step, frame[cur].t, reftemp, &edat, nset, set, bIsEner, leg, enm,
-                     Vaver, ezero, nbmin, nbmax, oenv);
+        analyse_ener(opt2bSet("-corr", NFILE, fnm),
+                     opt2fn("-corr", NFILE, fnm),
+                     opt2fn("-evisco", NFILE, fnm),
+                     opt2fn("-eviscoi", NFILE, fnm),
+                     bFee,
+                     bSum,
+                     bFluct,
+                     bVisco,
+                     opt2fn("-vis", NFILE, fnm),
+                     nmol,
+                     start_step,
+                     start_t,
+                     frame[cur].step,
+                     frame[cur].t,
+                     reftemp,
+                     &edat,
+                     nset,
+                     set,
+                     bIsEner,
+                     leg,
+                     enm,
+                     Vaver,
+                     ezero,
+                     nbmin,
+                     nbmax,
+                     oenv);
         if (bFluctProps)
         {
             calc_fluctuation_props(stdout, bDriftCorr, dt, nset, nmol, leg, &edat, nbmin, nbmax);
@@ -2122,8 +2201,7 @@ int gmx_energy(int argc, char* argv[])
     }
     if (opt2bSet("-f2", NFILE, fnm))
     {
-        fec(opt2fn("-f2", NFILE, fnm), opt2fn("-ravg", NFILE, fnm), reftemp, nset, set, leg, &edat,
-            time, oenv);
+        fec(opt2fn("-f2", NFILE, fnm), opt2fn("-ravg", NFILE, fnm), reftemp, nset, set, leg, &edat, time, oenv);
     }
     // Clean up!
     done_enerdata_t(nset, &edat);
index c9567a806b3c9a39195219fdc9ebe8ee9b432c2a..e8b95b1a3b53ee92121cd43d6eabe2bd3e9cd9e1 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,2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gmxana/gmx_ana.h"
 #include "gromacs/gmxana/princ.h"
 #include "gromacs/math/do_fit.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/pbc.h"
@@ -119,8 +120,8 @@ int gmx_filter(int argc, char* argv[])
                        { efTRO, "-oh", "highpass", ffOPTWR } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -298,8 +299,16 @@ int gmx_filter(int argc, char* argv[])
             }
             if (outl && (bLowAll || fr % nf == nf - 1))
             {
-                write_trx(outl, nat, ind, topfile ? &(top.atoms) : nullptr, 0, t[nf - 1],
-                          bFit ? topbox : boxf, xf, nullptr, nullptr);
+                write_trx(outl,
+                          nat,
+                          ind,
+                          topfile ? &(top.atoms) : nullptr,
+                          0,
+                          t[nf - 1],
+                          bFit ? topbox : boxf,
+                          xf,
+                          nullptr,
+                          nullptr);
             }
             if (outh)
             {
@@ -325,8 +334,16 @@ int gmx_filter(int argc, char* argv[])
                         boxf[j][d] = topbox[j][d] + box[nf - 1][j][d] - boxf[j][d];
                     }
                 }
-                write_trx(outh, nat, ind, topfile ? &(top.atoms) : nullptr, 0, t[nf - 1],
-                          bFit ? topbox : boxf, xf, nullptr, nullptr);
+                write_trx(outh,
+                          nat,
+                          ind,
+                          topfile ? &(top.atoms) : nullptr,
+                          0,
+                          t[nf - 1],
+                          bFit ? topbox : boxf,
+                          xf,
+                          nullptr,
+                          nullptr);
             }
         }
         /* Cycle all the pointer and the box by one */
index 6df19ae6fefeb385c95e1a13455e2c4b519df7d2..540c7904723b4e990a5677738e4f0724f4b2aa62 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -39,6 +39,7 @@
 
 #include <cmath>
 #include <cstring>
+#include <vector>
 
 #include "gromacs/commandline/pargs.h"
 #include "gromacs/commandline/viewit.h"
@@ -50,6 +51,7 @@
 #include "gromacs/gmxana/gstat.h"
 #include "gromacs/gmxana/princ.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/rmpbc.h"
@@ -120,15 +122,15 @@ static real calc_gyro(rvec     x[],
 
 static void calc_gyro_z(rvec x[], matrix box, int gnx, const int index[], t_atom atom[], int nz, real time, FILE* out)
 {
-    static dvec*   inertia = nullptr;
-    static double* tm      = nullptr;
-    int            i, ii, j, zi;
-    real           zf, w, sdet, e1, e2;
+    static std::vector<gmx::DVec> inertia;
+    static std::vector<double>    tm;
+    int                           i, ii, j, zi;
+    real                          zf, w, sdet, e1, e2;
 
-    if (inertia == nullptr)
+    if (inertia.empty())
     {
-        snew(inertia, nz);
-        snew(tm, nz);
+        inertia.resize(nz);
+        tm.resize(nz);
     }
 
     for (i = 0; i < nz; i++)
@@ -252,8 +254,8 @@ int gmx_gyrate(int argc, char* argv[])
     npargs = asize(pa);
     ppa    = add_acf_pargs(&npargs, pa);
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, npargs, ppa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, nullptr, &oenv))
     {
         sfree(ppa);
         return 0;
@@ -299,18 +301,27 @@ int gmx_gyrate(int argc, char* argv[])
     t0 = t;
     if (bQ)
     {
-        out = xvgropen(ftp2fn(efXVG, NFILE, fnm), "Radius of Charge (total and around axes)",
-                       "Time (ps)", "Rg (nm)", oenv);
+        out = xvgropen(ftp2fn(efXVG, NFILE, fnm),
+                       "Radius of Charge (total and around axes)",
+                       "Time (ps)",
+                       "Rg (nm)",
+                       oenv);
     }
     else if (bMOI)
     {
-        out = xvgropen(ftp2fn(efXVG, NFILE, fnm), "Moments of inertia (total and around axes)",
-                       "Time (ps)", "I (a.m.u. nm\\S2\\N)", oenv);
+        out = xvgropen(ftp2fn(efXVG, NFILE, fnm),
+                       "Moments of inertia (total and around axes)",
+                       "Time (ps)",
+                       "I (a.m.u. nm\\S2\\N)",
+                       oenv);
     }
     else
     {
-        out = xvgropen(ftp2fn(efXVG, NFILE, fnm), "Radius of gyration (total and around axes)",
-                       "Time (ps)", "Rg (nm)", oenv);
+        out = xvgropen(ftp2fn(efXVG, NFILE, fnm),
+                       "Radius of gyration (total and around axes)",
+                       "Time (ps)",
+                       "Rg (nm)",
+                       oenv);
     }
     if (bMOI)
     {
@@ -347,8 +358,8 @@ int gmx_gyrate(int argc, char* argv[])
             tm = sub_xcm(nz == 0 ? x_s : x, nam, index + mol * nam, top.atoms.atom, xcm, bQ);
             if (nz == 0)
             {
-                gyro += calc_gyro(x_s, nam, index + mol * nam, top.atoms.atom, tm, gvec1, d1, bQ,
-                                  bRot, bMOI, trans);
+                gyro += calc_gyro(
+                        x_s, nam, index + mol * nam, top.atoms.atom, tm, gvec1, d1, bQ, bRot, bMOI, trans);
             }
             else
             {
@@ -401,8 +412,15 @@ int gmx_gyrate(int argc, char* argv[])
     {
         int mode = eacVector;
 
-        do_autocorr(opt2fn("-acf", NFILE, fnm), oenv, "Moment of inertia vector ACF", j, 3,
-                    moi_trans, (t - t0) / j, mode, FALSE);
+        do_autocorr(opt2fn("-acf", NFILE, fnm),
+                    oenv,
+                    "Moment of inertia vector ACF",
+                    j,
+                    3,
+                    moi_trans,
+                    (t - t0) / j,
+                    mode,
+                    FALSE);
         do_view(oenv, opt2fn("-acf", NFILE, fnm), "-nxy");
     }
 
index 509801a57292a95c46647a7da56057469c0ffa9d..b3f4b46a7b650400315cae34310c618a0bee7d2b 100644 (file)
@@ -252,8 +252,13 @@ static void h2order_plot(rvec dipole[], real order[], const char* afile, int nsl
 
     for (slice = 0; slice < nslices; slice++)
     {
-        fprintf(ord, "%8.3f %8.3f %8.3f %8.3f %e\n", slWidth * slice, factor * dipole[slice][XX],
-                factor * dipole[slice][YY], factor * dipole[slice][ZZ], order[slice]);
+        fprintf(ord,
+                "%8.3f %8.3f %8.3f %8.3f %e\n",
+                slWidth * slice,
+                factor * dipole[slice][XX],
+                factor * dipole[slice][YY],
+                factor * dipole[slice][ZZ],
+                order[slice]);
     }
 
     xvgrclose(ord);
@@ -326,8 +331,8 @@ int gmx_h2order(int argc, char* argv[])
 #define NFILE asize(fnm)
 
     // Parse the user input in argv into pa
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, asize(bugs), bugs, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
         return 0;
     }
@@ -355,8 +360,20 @@ int gmx_h2order(int argc, char* argv[])
         rd_index(opt2fn("-nm", NFILE, fnm), 1, &nmic, &micelle, &micname);
     }
 
-    calc_h2order(ftp2fn(efTRX, NFILE, fnm), index, ngx, &slDipole, &slOrder, &slWidth, &nslices,
-                 top, pbcType, axis, bMicel, micelle, nmic, oenv);
+    calc_h2order(ftp2fn(efTRX, NFILE, fnm),
+                 index,
+                 ngx,
+                 &slDipole,
+                 &slOrder,
+                 &slWidth,
+                 &nslices,
+                 top,
+                 pbcType,
+                 axis,
+                 bMicel,
+                 micelle,
+                 nmic,
+                 oenv);
 
     h2order_plot(slDipole, slOrder, opt2fn("-o", NFILE, fnm), nslices, slWidth, oenv);
 
index b9bb443893eb3f393389fa65df1e6c6a868e8072..7cb4a978d7d13c7928c38021dad3dd7c0ec8310c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +60,7 @@
 #include "gromacs/gmxana/gstat.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/pbcutil/pbc.h"
@@ -80,6 +81,7 @@
 #define max_hx 7
 typedef int t_hx[max_hx];
 #define NRHXTYPES max_hx
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static const char* hxtypenames[NRHXTYPES] = { "n-n",   "n-n+1", "n-n+2", "n-n+3",
                                               "n-n+4", "n-n+5", "n-n>6" };
 #define MAXHH 4
@@ -107,9 +109,9 @@ static const unsigned char c_acceptorMask = (1 << 0);
 static const unsigned char c_donorMask    = (1 << 1);
 static const unsigned char c_inGroupMask  = (1 << 2);
 
-
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static const char* grpnames[grNR] = { "0", "1", "I" };
-
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static gmx_bool bDebug = FALSE;
 
 #define HB_NO 0
@@ -265,7 +267,7 @@ static void add_frames(t_hbdata* hb, int nframes)
 #define OFFSET(frame) ((frame) / 32)
 #define MASK(frame) (1 << ((frame) % 32))
 
-static void _set_hb(unsigned int hbexist[], unsigned int frame, gmx_bool bValue)
+static void set_hb_function(unsigned int hbexist[], unsigned int frame, gmx_bool bValue)
 {
     if (bValue)
     {
@@ -299,7 +301,7 @@ static void set_hb(t_hbdata* hb, int id, int ih, int ia, int frame, int ihb)
         gmx_fatal(FARGS, "Incomprehensible iValue %d in set_hb", ihb);
     }
 
-    _set_hb(ghptr, frame - hb->hbmap[id][ia]->n0, TRUE);
+    set_hb_function(ghptr, frame - hb->hbmap[id][ia]->n0, TRUE);
 }
 
 static void add_ff(t_hbdata* hbd, int id, int h, int ia, int frame, int ihb)
@@ -368,7 +370,7 @@ static void inc_nhbonds(t_donors* ddd, int d, int h)
     }
 }
 
-static int _acceptor_index(t_acceptors* a, int grp, int i, const char* file, int line)
+static int acceptor_index_function(t_acceptors* a, int grp, int i, const char* file, int line)
 {
     int ai = a->aptr[i];
 
@@ -376,8 +378,7 @@ static int _acceptor_index(t_acceptors* a, int grp, int i, const char* file, int
     {
         if (debug && bDebug)
         {
-            fprintf(debug, "Acc. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n", ai,
-                    a->grp[ai], grp, file, line);
+            fprintf(debug, "Acc. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n", ai, a->grp[ai], grp, file, line);
         }
         return NOTSET;
     }
@@ -386,9 +387,9 @@ static int _acceptor_index(t_acceptors* a, int grp, int i, const char* file, int
         return ai;
     }
 }
-#define acceptor_index(a, grp, i) _acceptor_index(a, grp, i, __FILE__, __LINE__)
+#define acceptor_index(a, grp, i) acceptor_index_function(a, grp, i, __FILE__, __LINE__)
 
-static int _donor_index(t_donors* d, int grp, int i, const char* file, int line)
+static int donor_index_function(t_donors* d, int grp, int i, const char* file, int line)
 {
     int di = d->dptr[i];
 
@@ -401,8 +402,7 @@ static int _donor_index(t_donors* d, int grp, int i, const char* file, int line)
     {
         if (debug && bDebug)
         {
-            fprintf(debug, "Don. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n", di,
-                    d->grp[di], grp, file, line);
+            fprintf(debug, "Don. group inconsist.. grp[%d] = %d, grp = %d (%s, %d)\n", di, d->grp[di], grp, file, line);
         }
         return NOTSET;
     }
@@ -411,7 +411,7 @@ static int _donor_index(t_donors* d, int grp, int i, const char* file, int line)
         return di;
     }
 }
-#define donor_index(d, grp, i) _donor_index(d, grp, i, __FILE__, __LINE__)
+#define donor_index(d, grp, i) donor_index_function(d, grp, i, __FILE__, __LINE__)
 
 static gmx_bool isInterchangable(t_hbdata* hb, int d, int a, int grpa, int grpd)
 {
@@ -436,8 +436,7 @@ add_hbond(t_hbdata* hb, int d, int a, int h, int grpd, int grpa, int frame, gmx_
     }
     else if (grpd != hb->d.grp[id])
     {
-        gmx_fatal(FARGS, "Inconsistent donor groups, %d instead of %d, atom %d", grpd,
-                  hb->d.grp[id], d + 1);
+        gmx_fatal(FARGS, "Inconsistent donor groups, %d instead of %d, atom %d", grpd, hb->d.grp[id], d + 1);
     }
     if ((ia = hb->a.aptr[a]) == NOTSET)
     {
@@ -445,8 +444,7 @@ add_hbond(t_hbdata* hb, int d, int a, int h, int grpd, int grpa, int frame, gmx_
     }
     else if (grpa != hb->a.grp[ia])
     {
-        gmx_fatal(FARGS, "Inconsistent acceptor groups, %d instead of %d, atom %d", grpa,
-                  hb->a.grp[ia], a + 1);
+        gmx_fatal(FARGS, "Inconsistent acceptor groups, %d instead of %d, atom %d", grpa, hb->a.grp[ia], a + 1);
     }
 
     if (bMerge)
@@ -470,8 +468,11 @@ add_hbond(t_hbdata* hb, int d, int a, int h, int grpd, int grpa, int frame, gmx_
             }
             else if (grpd != hb->d.grp[id])
             {
-                gmx_fatal(FARGS, "Inconsistent donor groups, %d instead of %d, atom %d", grpd,
-                          hb->d.grp[id], d + 1);
+                gmx_fatal(FARGS,
+                          "Inconsistent donor groups, %d instead of %d, atom %d",
+                          grpd,
+                          hb->d.grp[id],
+                          d + 1);
             }
             if ((ia = hb->a.aptr[a]) == NOTSET)
             {
@@ -479,8 +480,11 @@ add_hbond(t_hbdata* hb, int d, int a, int h, int grpd, int grpa, int frame, gmx_
             }
             else if (grpa != hb->a.grp[ia])
             {
-                gmx_fatal(FARGS, "Inconsistent acceptor groups, %d instead of %d, atom %d", grpa,
-                          hb->a.grp[ia], a + 1);
+                gmx_fatal(FARGS,
+                          "Inconsistent acceptor groups, %d instead of %d, atom %d",
+                          grpa,
+                          hb->a.grp[ia],
+                          a + 1);
             }
         }
     }
@@ -900,8 +904,7 @@ static t_gridcell*** init_grid(gmx_bool bBox, rvec box[], real rcut, ivec ngrid)
     }
     else
     {
-        printf("\nWill do grid-search on %dx%dx%d grid, rcut=%3.8f\n", ngrid[XX], ngrid[YY],
-               ngrid[ZZ], rcut);
+        printf("\nWill do grid-search on %dx%dx%d grid, rcut=%3.8f\n", ngrid[XX], ngrid[YY], ngrid[ZZ], rcut);
     }
     if (((ngrid[XX] * ngrid[YY] * ngrid[ZZ]) * sizeof(grid)) > INT_MAX)
     {
@@ -910,8 +913,14 @@ static t_gridcell*** init_grid(gmx_bool bBox, rvec box[], real rcut, ivec ngrid)
                   "the maximum of %zu. "
                   "You are likely either using a box that is too large (box dimensions are %3.8f "
                   "nm x%3.8f nm x%3.8f nm) or a cutoff (%3.8f nm) that is too small.",
-                  ngrid[XX], ngrid[YY], ngrid[ZZ], INT_MAX / sizeof(grid), box[XX][XX], box[YY][YY],
-                  box[ZZ][ZZ], rcut);
+                  ngrid[XX],
+                  ngrid[YY],
+                  ngrid[ZZ],
+                  INT_MAX / sizeof(grid),
+                  box[XX][XX],
+                  box[YY][YY],
+                  box[ZZ][ZZ],
+                  rcut);
     }
     snew(grid, ngrid[ZZ]);
     for (z = 0; z < ngrid[ZZ]; z++)
@@ -1453,8 +1462,8 @@ static void do_merge(t_hbdata* hb, int ntmp, bool htmp[], bool gtmp[], t_hbond*
     /* Copy temp array to target array */
     for (m = 0; (m <= nnframes); m++)
     {
-        _set_hb(hb0->h[0], m, htmp[m]);
-        _set_hb(hb0->g[0], m, gtmp[m]);
+        set_hb_function(hb0->h[0], m, htmp[m]);
+        set_hb_function(hb0->g[0], m, gtmp[m]);
     }
 
     /* Set scalar variables */
@@ -1638,8 +1647,8 @@ static void do_hblife(const char* fn, t_hbdata* hb, gmx_bool bMerge, gmx_bool bC
     }
     else
     {
-        fp = xvgropen(fn, "Uninterrupted hydrogen bond lifetime", output_env_get_xvgr_tlabel(oenv),
-                      "()", oenv);
+        fp = xvgropen(
+                fn, "Uninterrupted hydrogen bond lifetime", output_env_get_xvgr_tlabel(oenv), "()", oenv);
     }
 
     xvgr_legend(fp, asize(leg), leg, oenv);
@@ -1734,14 +1743,14 @@ static real calc_dg(real tau, real temp)
 {
     real kbt;
 
-    kbt = BOLTZ * temp;
+    kbt = gmx::c_boltz * temp;
     if (tau <= 0)
     {
         return -666;
     }
     else
     {
-        return kbt * std::log(kbt * tau / PLANCK);
+        return kbt * std::log(kbt * tau / gmx::c_planck);
     }
 }
 
@@ -1855,19 +1864,27 @@ void analyse_corr(int  n,
                 {
                     chi2 += gmx::square(k * ct[i] - kp * nt[i] - kt[i]);
                 }
-                compute_weighted_rates(n, t, ct, nt, kt, sigma_ct, sigma_nt, sigma_kt, &k, &kp,
-                                       &sigma_k, &sigma_kp, fit_start);
+                compute_weighted_rates(
+                        n, t, ct, nt, kt, sigma_ct, sigma_nt, sigma_kt, &k, &kp, &sigma_k, &sigma_kp, fit_start);
                 Q   = 0; /* quality_of_fit(chi2, 2);*/
-                ddg = BOLTZ * temp * sigma_k / k;
+                ddg = gmx::c_boltz * temp * sigma_k / k;
                 printf("Fitting paramaters chi^2 = %10g, Quality of fit = %10g\n", chi2, Q);
                 printf("The Rate and Delta G are followed by an error estimate\n");
                 printf("----------------------------------------------------------\n"
                        "Type      Rate (1/ps)  Sigma Time (ps)  DG (kJ/mol)  Sigma\n");
-                printf("Forward    %10.3f %6.2f   %8.3f  %10.3f %6.2f\n", k, sigma_k, 1 / k,
-                       calc_dg(1 / k, temp), ddg);
-                ddg = BOLTZ * temp * sigma_kp / kp;
-                printf("Backward   %10.3f %6.2f   %8.3f  %10.3f %6.2f\n", kp, sigma_kp, 1 / kp,
-                       calc_dg(1 / kp, temp), ddg);
+                printf("Forward    %10.3f %6.2f   %8.3f  %10.3f %6.2f\n",
+                       k,
+                       sigma_k,
+                       1 / k,
+                       calc_dg(1 / k, temp),
+                       ddg);
+                ddg = gmx::c_boltz * temp * sigma_kp / kp;
+                printf("Backward   %10.3f %6.2f   %8.3f  %10.3f %6.2f\n",
+                       kp,
+                       sigma_kp,
+                       1 / kp,
+                       calc_dg(1 / kp, temp),
+                       ddg);
             }
             else
             {
@@ -1886,18 +1903,29 @@ void analyse_corr(int  n,
         if (sc2 > 0)
         {
             kow = 2 * sck / sc2;
-            printf("One-way    %10.3f   %s%8.3f  %10.3f\n", kow, bError ? "       " : "", 1 / kow,
+            printf("One-way    %10.3f   %s%8.3f  %10.3f\n",
+                   kow,
+                   bError ? "       " : "",
+                   1 / kow,
                    calc_dg(1 / kow, temp));
         }
         else
         {
             printf(" - Numerical problems computing HB thermodynamics:\n"
                    "sc2 = %g  sn2 = %g  sk2 = %g sck = %g snk = %g scn = %g\n",
-                   sc2, sn2, sk2, sck, snk, scn);
+                   sc2,
+                   sn2,
+                   sk2,
+                   sck,
+                   snk,
+                   scn);
         }
         /* Determine integral of the correlation function */
         tau_hb = evaluate_integral(n, t, ct, nullptr, (t[n - 1] - t[0]) / 2, &dtau);
-        printf("Integral   %10.3f   %s%8.3f  %10.3f\n", 1 / tau_hb, bError ? "       " : "", tau_hb,
+        printf("Integral   %10.3f   %s%8.3f  %10.3f\n",
+               1 / tau_hb,
+               bError ? "       " : "",
+               tau_hb,
                calc_dg(tau_hb, temp));
         e_1 = std::exp(-1.0);
         for (i = 0; (i < n - 2); i++)
@@ -1911,8 +1939,11 @@ void analyse_corr(int  n,
         {
             /* Determine tau_relax from linear interpolation */
             tau_rlx = t[i] - t[0] + (e_1 - ct[i]) * (t[i + 1] - t[i]) / (ct[i + 1] - ct[i]);
-            printf("Relaxation %10.3f   %8.3f  %s%10.3f\n", 1 / tau_rlx, tau_rlx,
-                   bError ? "       " : "", calc_dg(tau_rlx, temp));
+            printf("Relaxation %10.3f   %8.3f  %s%10.3f\n",
+                   1 / tau_rlx,
+                   tau_rlx,
+                   bError ? "       " : "",
+                   calc_dg(tau_rlx, temp));
         }
     }
     else
@@ -1973,14 +2004,16 @@ static void do_hbac(const char*             fn,
     FILE* fp;
     int   i, j, k, m, ihb, idist, n2, nn;
 
-    const char* legLuzar[] = { "Ac\\sfin sys\\v{}\\z{}(t)", "Ac(t)", "Cc\\scontact,hb\\v{}\\z{}(t)",
+    const char*    legLuzar[] = { "Ac\\sfin sys\\v{}\\z{}(t)",
+                               "Ac(t)",
+                               "Cc\\scontact,hb\\v{}\\z{}(t)",
                                "-dAc\\sfs\\v{}\\z{}/dt" };
-    gmx_bool    bNorm      = FALSE;
-    double      nhb        = 0;
-    real *      rhbex      = nullptr, *ht, *gt, *ght, *dght, *kt;
-    real *      ct, tail, tail2, dtail, *cct;
-    const real  tol     = 1e-3;
-    int         nframes = hb->nframes;
+    gmx_bool       bNorm      = FALSE;
+    double         nhb        = 0;
+    real *         rhbex      = nullptr, *ht, *gt, *ght, *dght, *kt;
+    real *         ct, tail, tail2, dtail, *cct;
+    const real     tol     = 1e-3;
+    int            nframes = hb->nframes;
     unsigned int **h = nullptr, **g = nullptr;
     int            nh, nhbonds, nhydro;
     t_hbond*       hbh;
@@ -2131,9 +2164,22 @@ static void do_hbac(const char*             fn,
                     }
 
                     /* The autocorrelation function is normalized after summation only */
-                    low_do_autocorr(nullptr, oenv, nullptr, nframes, 1, -1, &rhbex,
-                                    hb->time[1] - hb->time[0], eacNormal, 1, FALSE, bNorm, FALSE, 0,
-                                    -1, 0);
+                    low_do_autocorr(nullptr,
+                                    oenv,
+                                    nullptr,
+                                    nframes,
+                                    1,
+                                    -1,
+                                    &rhbex,
+                                    hb->time[1] - hb->time[0],
+                                    eacNormal,
+                                    1,
+                                    FALSE,
+                                    bNorm,
+                                    FALSE,
+                                    0,
+                                    -1,
+                                    0);
 
                     /* Cross correlation analysis for thermodynamics */
                     for (j = nframes; (j < n2); j++)
@@ -2176,7 +2222,9 @@ static void do_hbac(const char*             fn,
         printf("\nWARNING: Correlation function is probably not long enough\n"
                "because the standard deviation in the tail of C(t) > %g\n"
                "Tail value (average C(t) over second half of acf): %g +/- %g\n",
-               tol, tail, dtail);
+               tol,
+               tail,
+               dtail);
     }
     for (j = 0; (j < nn); j++)
     {
@@ -2204,8 +2252,7 @@ static void do_hbac(const char*             fn,
 
     for (j = 0; (j < nn); j++)
     {
-        fprintf(fp, "%10g  %10g  %10g  %10g  %10g\n", hb->time[j] - hb->time[0], ct[j], cct[j],
-                ght[j], kt[j]);
+        fprintf(fp, "%10g  %10g  %10g  %10g  %10g\n", hb->time[j] - hb->time[0], ct[j], cct[j], ght[j], kt[j]);
     }
     xvgrclose(fp);
 
@@ -2436,7 +2483,8 @@ int gmx_hbond(int argc, char* argv[])
 
         "If you set [TT]-shell[tt], you will be asked for an additional index group",
         "which should contain exactly one atom. In this case, only hydrogen",
-        "bonds between atoms within the shell distance from the one atom are", "considered.[PAR]",
+        "bonds between atoms within the shell distance from the one atom are",
+        "considered.[PAR]",
 
         "With option -ac, rate constants for hydrogen bonding can be derived with the",
         "model of Luzar and Chandler (Nature 379:55, 1996; J. Chem. Phys. 113:23, 2000).",
@@ -2444,7 +2492,8 @@ int gmx_hbond(int argc, char* argv[])
         "n(t) can be defined as either all pairs that are not within contact distance r at time t",
         "(corresponding to leaving the -r2 option at the default value 0) or all pairs that",
         "are within distance r2 (corresponding to setting a second cut-off value with option -r2).",
-        "See mentioned literature for more details and definitions.", "[PAR]",
+        "See mentioned literature for more details and definitions.",
+        "[PAR]",
 
         /*    "It is also possible to analyse specific hydrogen bonds with",
               "[TT]-sel[tt]. This index file must contain a group of atom triplets",
@@ -2460,7 +2509,9 @@ int gmx_hbond(int argc, char* argv[])
            "note also that no check is made for the types of atoms.[PAR]",
          */
 
-        "[BB]Output:[bb]", "", " * [TT]-num[tt]:  number of hydrogen bonds as a function of time.",
+        "[BB]Output:[bb]",
+        "",
+        " * [TT]-num[tt]:  number of hydrogen bonds as a function of time.",
         " * [TT]-ac[tt]:   average over all autocorrelations of the existence",
         "   functions (either 0 or 1) of all hydrogen bonds.",
         " * [TT]-dist[tt]: distance distribution of all hydrogen bonds.",
@@ -2474,11 +2525,13 @@ int gmx_hbond(int argc, char* argv[])
         "   all solvent atoms involved in insertion.",
         " * [TT]-hbm[tt]:  existence matrix for all hydrogen bonds over all",
         "   frames, this also contains information on solvent insertion",
-        "   into hydrogen bonds. Ordering is identical to that in [TT]-hbn[tt]", "   index file.",
+        "   into hydrogen bonds. Ordering is identical to that in [TT]-hbn[tt]",
+        "   index file.",
         " * [TT]-dan[tt]: write out the number of donors and acceptors analyzed for",
         "   each timeframe. This is especially useful when using [TT]-shell[tt].",
         " * [TT]-nhbdist[tt]: compute the number of HBonds per hydrogen in order to",
-        "   compare results to Raman Spectroscopy.", "",
+        "   compare results to Raman Spectroscopy.",
+        "",
         "Note: options [TT]-ac[tt], [TT]-life[tt], [TT]-hbn[tt] and [TT]-hbm[tt]",
         "require an amount of memory proportional to the total numbers of donors",
         "times the total number of acceptors in the selected group(s)."
@@ -2635,8 +2688,8 @@ int gmx_hbond(int argc, char* argv[])
     npargs = asize(pa);
     ppa    = add_acf_pargs(&npargs, pa);
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, npargs, ppa,
-                           asize(desc), desc, asize(bugs), bugs, &oenv))
+    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;
@@ -2644,7 +2697,7 @@ int gmx_hbond(int argc, char* argv[])
 
     /* process input */
     bSelected = FALSE;
-    ccut      = std::cos(acut * DEG2RAD);
+    ccut      = std::cos(acut * gmx::c_deg2Rad);
 
     if (bContact)
     {
@@ -2665,8 +2718,11 @@ int gmx_hbond(int argc, char* argv[])
     if (opt2bSet("-nhbdist", NFILE, fnm))
     {
         const char* leg[MAXHH + 1] = { "0 HBs", "1 HB", "2 HBs", "3 HBs", "Total" };
-        fpnhb = xvgropen(opt2fn("-nhbdist", NFILE, fnm), "Number of donor-H with N HBs",
-                         output_env_get_xvgr_tlabel(oenv), "N", oenv);
+        fpnhb                      = xvgropen(opt2fn("-nhbdist", NFILE, fnm),
+                         "Number of donor-H with N HBs",
+                         output_env_get_xvgr_tlabel(oenv),
+                         "N",
+                         oenv);
         xvgr_legend(fpnhb, asize(leg), leg, oenv);
     }
 
@@ -2734,8 +2790,7 @@ int gmx_hbond(int argc, char* argv[])
             {
                 if (ISINGRP(datable[index[1][i]]))
                 {
-                    gmx_fatal(FARGS, "Partial overlap between groups '%s' and '%s'", grpnames[0],
-                              grpnames[1]);
+                    gmx_fatal(FARGS, "Partial overlap between groups '%s' and '%s'", grpnames[0], grpnames[1]);
                 }
             }
         }
@@ -2743,13 +2798,19 @@ int gmx_hbond(int argc, char* argv[])
         {
             printf("Calculating %s "
                    "between %s (%d atoms) and %s (%d atoms)\n",
-                   bContact ? "contacts" : "hydrogen bonds", grpnames[0], isize[0], grpnames[1],
+                   bContact ? "contacts" : "hydrogen bonds",
+                   grpnames[0],
+                   isize[0],
+                   grpnames[1],
                    isize[1]);
         }
         else
         {
-            fprintf(stderr, "Calculating %s in %s (%d atoms)\n",
-                    bContact ? "contacts" : "hydrogen bonds", grpnames[0], isize[0]);
+            fprintf(stderr,
+                    "Calculating %s in %s (%d atoms)\n",
+                    bContact ? "contacts" : "hydrogen bonds",
+                    grpnames[0],
+                    isize[0]);
         }
     }
     sfree(datable);
@@ -2763,10 +2824,9 @@ int gmx_hbond(int argc, char* argv[])
             gen_datable(index[i], isize[i], datable, top.atoms.nr);
             if (bContact)
             {
-                search_acceptors(&top, isize[i], index[i], &hb->a, i, bNitAcc, TRUE,
-                                 (bTwo && (i == gr0)) || !bTwo, datable);
-                search_donors(&top, isize[i], index[i], &hb->d, i, TRUE,
-                              (bTwo && (i == gr1)) || !bTwo, datable);
+                search_acceptors(
+                        &top, isize[i], index[i], &hb->a, i, bNitAcc, TRUE, (bTwo && (i == gr0)) || !bTwo, datable);
+                search_donors(&top, isize[i], index[i], &hb->d, i, TRUE, (bTwo && (i == gr1)) || !bTwo, datable);
             }
             else
             {
@@ -2838,7 +2898,8 @@ int gmx_hbond(int argc, char* argv[])
         shatom = shidx[0];
         printf("Will calculate hydrogen bonds within a shell "
                "of %g nm around atom %i\n",
-               rshell, shatom + 1);
+               rshell,
+               shatom + 1);
     }
 
     /* Analyze trajectory */
@@ -2856,17 +2917,17 @@ int gmx_hbond(int argc, char* argv[])
     snew(rdist, nrbin + 1);
 
 #if !GMX_OPENMP
-#    define __ADIST adist
-#    define __RDIST rdist
-#    define __HBDATA hb
-#else /* GMX_OPENMP ==================================================    \
-       * Set up the OpenMP stuff,                                       | \
-       * like the number of threads and such                            | \
-       * Also start the parallel loop.                                  | \
-       */
-#    define __ADIST p_adist[threadNr]
-#    define __RDIST p_rdist[threadNr]
-#    define __HBDATA p_hb[threadNr]
+#    define __ADIST adist // NOLINT(bugprone-reserved-identifier)
+#    define __RDIST rdist // NOLINT(bugprone-reserved-identifier)
+#    define __HBDATA hb   // NOLINT(bugprone-reserved-identifier)
+#else                     /* GMX_OPENMP ==================================================    \
+                           * Set up the OpenMP stuff,                                       | \
+                           * like the number of threads and such                            | \
+                           * Also start the parallel loop.                                  | \
+                           */
+#    define __ADIST p_adist[threadNr] // NOLINT(bugprone-reserved-identifier)
+#    define __RDIST p_rdist[threadNr] // NOLINT(bugprone-reserved-identifier)
+#    define __HBDATA p_hb[threadNr]   // NOLINT(bugprone-reserved-identifier)
 #endif
     if (bOMP)
     {
@@ -2920,9 +2981,34 @@ int gmx_hbond(int argc, char* argv[])
     /* Make a thread pool here,
      * instead of forking anew at every frame. */
 
-#pragma omp parallel firstprivate(i) private(                                                   \
-        j, h, ii, hh, xi, yi, zi, xj, yj, zj, threadNr, dist, ang, icell, jcell, grp, ogrp, ai, \
-        aj, xjj, yjj, zjj, ihb, resdist, k, bTric, bEdge_xjj, bEdge_yjj) default(shared)
+#pragma omp parallel firstprivate(i) private(j,         \
+                                             h,         \
+                                             ii,        \
+                                             hh,        \
+                                             xi,        \
+                                             yi,        \
+                                             zi,        \
+                                             xj,        \
+                                             yj,        \
+                                             zj,        \
+                                             threadNr,  \
+                                             dist,      \
+                                             ang,       \
+                                             icell,     \
+                                             jcell,     \
+                                             grp,       \
+                                             ogrp,      \
+                                             ai,        \
+                                             aj,        \
+                                             xjj,       \
+                                             yjj,       \
+                                             zjj,       \
+                                             ihb,       \
+                                             resdist,   \
+                                             k,         \
+                                             bTric,     \
+                                             bEdge_xjj, \
+                                             bEdge_yjj) default(shared)
     { /* Start of parallel region */
         if (bOMP)
         {
@@ -2945,8 +3031,7 @@ int gmx_hbond(int argc, char* argv[])
             {
                 try
                 {
-                    build_grid(hb, x, x[shatom], bBox, box, hbox, (rcut > r2cut) ? rcut : r2cut,
-                               rshell, ngrid, grid);
+                    build_grid(hb, x, x[shatom], bBox, box, hbox, (rcut > r2cut) ? rcut : r2cut, rshell, ngrid, grid);
                     reset_nhbonds(&(hb->d));
 
                     if (debug && bDebug)
@@ -2984,8 +3069,8 @@ int gmx_hbond(int argc, char* argv[])
                             int dd       = index[0][i];
                             int aa       = index[0][i + 2];
                             /* int */ hh = index[0][i + 1];
-                            ihb = is_hbond(hb, ii, ii, dd, aa, rcut, r2cut, ccut, x, bBox, box,
-                                           hbox, &dist, &ang, bDA, &h, bContact, bMerge);
+                            ihb          = is_hbond(
+                                    hb, ii, ii, dd, aa, rcut, r2cut, ccut, x, bBox, box, hbox, &dist, &ang, bDA, &h, bContact, bMerge);
 
                             if (ihb)
                             {
@@ -3034,7 +3119,8 @@ int gmx_hbond(int argc, char* argv[])
 
                                         /* loop over all adjacent gridcells (xj,yj,zj) */
                                         for (zjj = grid_loop_begin(ngrid[ZZ], zi, bTric, FALSE);
-                                             zjj <= grid_loop_end(ngrid[ZZ], zi, bTric, FALSE); zjj++)
+                                             zjj <= grid_loop_end(ngrid[ZZ], zi, bTric, FALSE);
+                                             zjj++)
                                         {
                                             zj        = grid_mod(zjj, ngrid[ZZ]);
                                             bEdge_yjj = (zj == 0) || (zj == ngrid[ZZ] - 1);
@@ -3059,17 +3145,30 @@ int gmx_hbond(int argc, char* argv[])
                                                         j = jcell->atoms[aj];
 
                                                         /* check if this once was a h-bond */
-                                                        ihb = is_hbond(__HBDATA, grp, ogrp, i, j,
-                                                                       rcut, r2cut, ccut, x, bBox,
-                                                                       box, hbox, &dist, &ang, bDA,
-                                                                       &h, bContact, bMerge);
+                                                        ihb = is_hbond(__HBDATA,
+                                                                       grp,
+                                                                       ogrp,
+                                                                       i,
+                                                                       j,
+                                                                       rcut,
+                                                                       r2cut,
+                                                                       ccut,
+                                                                       x,
+                                                                       bBox,
+                                                                       box,
+                                                                       hbox,
+                                                                       &dist,
+                                                                       &ang,
+                                                                       bDA,
+                                                                       &h,
+                                                                       bContact,
+                                                                       bMerge);
 
                                                         if (ihb)
                                                         {
                                                             /* add to index if not already there */
                                                             /* Add a hbond */
-                                                            add_hbond(__HBDATA, i, j, h, grp, ogrp,
-                                                                      nframes, bMerge, ihb, bContact);
+                                                            add_hbond(__HBDATA, i, j, h, grp, ogrp, nframes, bMerge, ihb, bContact);
 
                                                             /* make angle and distance distributions */
                                                             if (ihb == hbHB && !bContact)
@@ -3083,7 +3182,7 @@ int gmx_hbond(int argc, char* argv[])
                                                                             "for an hbond: %f",
                                                                             dist);
                                                                 }
-                                                                ang *= RAD2DEG;
+                                                                ang *= gmx::c_rad2Deg;
                                                                 __ADIST[static_cast<int>(ang / abin)]++;
                                                                 __RDIST[static_cast<int>(dist / rbin)]++;
                                                                 if (!bTwo)
@@ -3092,7 +3191,8 @@ int gmx_hbond(int argc, char* argv[])
                                                                     {
                                                                         gmx_fatal(
                                                                                 FARGS,
-                                                                                "Invalid donor %d", i);
+                                                                                "Invalid donor %d",
+                                                                                i);
                                                                     }
                                                                     if (acceptor_index(&hb->a, ogrp, j)
                                                                         == NOTSET)
@@ -3239,8 +3339,7 @@ int gmx_hbond(int argc, char* argv[])
 
     if (nframes < 2 && (opt2bSet("-ac", NFILE, fnm) || opt2bSet("-life", NFILE, fnm)))
     {
-        gmx_fatal(FARGS,
-                  "Cannot calculate autocorrelation of life times with less than two frames");
+        gmx_fatal(FARGS, "Cannot calculate autocorrelation of life times with less than two frames");
     }
 
     free_grid(ngrid, &grid);
@@ -3277,7 +3376,9 @@ int gmx_hbond(int argc, char* argv[])
         {
             printf("Found %d different %s in trajectory\n"
                    "Found %d different atom-pairs within %s distance\n",
-                   hb->nrhb, bContact ? "contacts" : "hydrogen bonds", hb->nrdist,
+                   hb->nrhb,
+                   bContact ? "contacts" : "hydrogen bonds",
+                   hb->nrdist,
                    (r2cut > 0) ? "second cut-off" : "hydrogen bonding");
 
             if (bMerge)
@@ -3298,8 +3399,11 @@ int gmx_hbond(int argc, char* argv[])
     /* Print out number of hbonds and distances */
     aver_nhb  = 0;
     aver_dist = 0;
-    fp        = xvgropen(opt2fn("-num", NFILE, fnm), bContact ? "Contacts" : "Hydrogen Bonds",
-                  output_env_get_xvgr_tlabel(oenv), "Number", oenv);
+    fp        = xvgropen(opt2fn("-num", NFILE, fnm),
+                  bContact ? "Contacts" : "Hydrogen Bonds",
+                  output_env_get_xvgr_tlabel(oenv),
+                  "Number",
+                  oenv);
     snew(leg, 2);
     snew(leg[0], STRLEN);
     snew(leg[1], STRLEN);
@@ -3329,9 +3433,11 @@ int gmx_hbond(int argc, char* argv[])
             sum += rdist[i];
         }
 
-        fp = xvgropen(opt2fn("-dist", NFILE, fnm), "Hydrogen Bond Distribution",
+        fp = xvgropen(opt2fn("-dist", NFILE, fnm),
+                      "Hydrogen Bond Distribution",
                       bDA ? "Donor - Acceptor Distance (nm)" : "Hydrogen - Acceptor Distance (nm)",
-                      "", oenv);
+                      "",
+                      oenv);
         for (i = 0; i < nrbin; i++)
         {
             fprintf(fp, "%10g %10g\n", (i + 0.5) * rbin, rdist[i] / (rbin * sum));
@@ -3350,8 +3456,11 @@ int gmx_hbond(int argc, char* argv[])
             sum += adist[i];
         }
 
-        fp = xvgropen(opt2fn("-ang", NFILE, fnm), "Hydrogen Bond Distribution",
-                      "Hydrogen - Donor - Acceptor Angle (\\SO\\N)", "", oenv);
+        fp = xvgropen(opt2fn("-ang", NFILE, fnm),
+                      "Hydrogen Bond Distribution",
+                      "Hydrogen - Donor - Acceptor Angle (\\SO\\N)",
+                      "",
+                      oenv);
         for (i = 0; i < nabin; i++)
         {
             fprintf(fp, "%10g %10g\n", (i + 0.5) * abin, adist[i] / (abin * sum));
@@ -3362,8 +3471,11 @@ int gmx_hbond(int argc, char* argv[])
     /* Print HB in alpha-helix */
     if (opt2bSet("-hx", NFILE, fnm))
     {
-        fp = xvgropen(opt2fn("-hx", NFILE, fnm), "Hydrogen Bonds", output_env_get_xvgr_tlabel(oenv),
-                      "Count", oenv);
+        fp = xvgropen(opt2fn("-hx", NFILE, fnm),
+                      "Hydrogen Bonds",
+                      output_env_get_xvgr_tlabel(oenv),
+                      "Count",
+                      oenv);
         xvgr_legend(fp, NRHXTYPES, hxtypenames, oenv);
         for (i = 0; i < nframes; i++)
         {
@@ -3378,7 +3490,9 @@ int gmx_hbond(int argc, char* argv[])
     }
 
     printf("Average number of %s per timeframe %.3f out of %g possible\n",
-           bContact ? "contacts" : "hbonds", bContact ? aver_dist : aver_nhb, max_nhb);
+           bContact ? "contacts" : "hbonds",
+           bContact ? aver_dist : aver_nhb,
+           max_nhb);
 
     /* Do Autocorrelation etc. */
     if (hb->bHBmap)
@@ -3393,8 +3507,7 @@ int gmx_hbond(int argc, char* argv[])
         }
         if (opt2bSet("-ac", NFILE, fnm))
         {
-            do_hbac(opt2fn("-ac", NFILE, fnm), hb, nDump, bMerge, bContact, fit_start, temp,
-                    r2cut > 0, oenv, nThreads);
+            do_hbac(opt2fn("-ac", NFILE, fnm), hb, nDump, bMerge, bContact, fit_start, temp, r2cut > 0, oenv, nThreads);
         }
         if (opt2bSet("-life", NFILE, fnm))
         {
@@ -3481,8 +3594,11 @@ int gmx_hbond(int argc, char* argv[])
 
 #define USE_THIS_GROUP(j) (((j) == gr0) || (bTwo && ((j) == gr1)))
 
-        fp   = xvgropen(opt2fn("-dan", NFILE, fnm), "Donors and Acceptors",
-                      output_env_get_xvgr_tlabel(oenv), "Count", oenv);
+        fp   = xvgropen(opt2fn("-dan", NFILE, fnm),
+                      "Donors and Acceptors",
+                      output_env_get_xvgr_tlabel(oenv),
+                      "Count",
+                      oenv);
         nleg = (bTwo ? 2 : 1) * 2;
         snew(legnames, nleg);
         i = 0;
index 0b9399ae094ec89db859d024e4b06bf4a98b2f3e..a5362468d4100e0c87472d037d901586545f9ca3 100644 (file)
@@ -159,8 +159,8 @@ int gmx_helix(int argc, char* argv[])
     };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -176,11 +176,19 @@ int gmx_helix(int argc, char* argv[])
         gmx_fatal(FARGS,
                   "Sorry can only run when the number of atoms in the run input file (%d) is equal "
                   "to the number in the trajectory (%d)",
-                  top->atoms.nr, natoms);
+                  top->atoms.nr,
+                  natoms);
     }
 
-    bb = mkbbind(ftp2fn(efNDX, NFILE, fnm), &nres, &nbb, r0, &nall, &allindex, top->atoms.atomname,
-                 top->atoms.atom, top->atoms.resinfo);
+    bb = mkbbind(ftp2fn(efNDX, NFILE, fnm),
+                 &nres,
+                 &nbb,
+                 r0,
+                 &nall,
+                 &allindex,
+                 top->atoms.atomname,
+                 top->atoms.atom,
+                 top->atoms.resinfo);
     snew(bbindex, natoms);
     snew(caindex, nres);
 
@@ -237,8 +245,8 @@ int gmx_helix(int argc, char* argv[])
 
             if (teller == 1)
             {
-                write_sto_conf(opt2fn("-cz", NFILE, fnm), "Helix fitted to Z-Axis", &(top->atoms),
-                               x, nullptr, pbcType, box);
+                write_sto_conf(
+                        opt2fn("-cz", NFILE, fnm), "Helix fitted to Z-Axis", &(top->atoms), x, nullptr, pbcType, box);
             }
 
             xf[efhRAD].val   = radius(xf[efhRAD].fp2, nca, caindex, x);
@@ -257,8 +265,15 @@ int gmx_helix(int argc, char* argv[])
             }
 
             av_phipsi(xf[efhPHI].fp, xf[efhPSI].fp, xf[efhPHI].fp2, xf[efhPSI].fp2, t, nres, bb);
-            av_hblen(xf[efhHB3].fp, xf[efhHB3].fp2, xf[efhHB4].fp, xf[efhHB4].fp2, xf[efhHB5].fp,
-                     xf[efhHB5].fp2, t, nres, bb);
+            av_hblen(xf[efhHB3].fp,
+                     xf[efhHB3].fp2,
+                     xf[efhHB4].fp,
+                     xf[efhHB4].fp2,
+                     xf[efhHB5].fp,
+                     xf[efhHB5].fp2,
+                     t,
+                     nres,
+                     bb);
         }
     } while (read_next_x(oenv, status, &t, x, box));
     fprintf(stderr, "\n");
@@ -274,8 +289,7 @@ int gmx_helix(int argc, char* argv[])
             fprintf(xf[efhRMSA].fp, "%10d  %10g\n", r0 + i, bb[i].rmsa / bb[i].nrms);
         }
         fprintf(xf[efhAHX].fp, "%10d  %10g\n", r0 + i, (bb[i].nhx * 100.0) / static_cast<real>(teller));
-        fprintf(xf[efhJCA].fp, "%10d  %10g\n", r0 + i,
-                140.3 + (bb[i].jcaha / static_cast<double>(teller)));
+        fprintf(xf[efhJCA].fp, "%10d  %10g\n", r0 + i, 140.3 + (bb[i].jcaha / static_cast<double>(teller)));
     }
 
     for (i = 0; (i < efhNR); i++)
index c5651ce84ae7d0e38f686ff007ff2aaf06915d5a..618e47a4601d46c3422db84056676f4e3829bf5b 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,2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gmxana/gmx_ana.h"
 #include "gromacs/gmxana/gstat.h"
 #include "gromacs/math/do_fit.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/pbc.h"
@@ -162,8 +163,8 @@ int gmx_helixorient(int argc, char* argv[])
     };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME, NFILE, fnm, NPA, pa, asize(desc), desc, 0,
-                           nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME, NFILE, fnm, NPA, pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -231,17 +232,29 @@ int gmx_helixorient(int argc, char* argv[])
 
     if (bIncremental)
     {
-        fptilt = xvgropen(opt2fn("-otilt", NFILE, fnm), "Incremental local helix tilt", "Time(ps)",
-                          "Tilt (degrees)", oenv);
-        fprotation = xvgropen(opt2fn("-orot", NFILE, fnm), "Incremental local helix rotation",
-                              "Time(ps)", "Rotation (degrees)", oenv);
+        fptilt     = xvgropen(opt2fn("-otilt", NFILE, fnm),
+                          "Incremental local helix tilt",
+                          "Time(ps)",
+                          "Tilt (degrees)",
+                          oenv);
+        fprotation = xvgropen(opt2fn("-orot", NFILE, fnm),
+                              "Incremental local helix rotation",
+                              "Time(ps)",
+                              "Rotation (degrees)",
+                              oenv);
     }
     else
     {
-        fptilt = xvgropen(opt2fn("-otilt", NFILE, fnm), "Cumulative local helix tilt", "Time(ps)",
-                          "Tilt (degrees)", oenv);
-        fprotation = xvgropen(opt2fn("-orot", NFILE, fnm), "Cumulative local helix rotation",
-                              "Time(ps)", "Rotation (degrees)", oenv);
+        fptilt     = xvgropen(opt2fn("-otilt", NFILE, fnm),
+                          "Cumulative local helix tilt",
+                          "Time(ps)",
+                          "Tilt (degrees)",
+                          oenv);
+        fprotation = xvgropen(opt2fn("-orot", NFILE, fnm),
+                              "Cumulative local helix rotation",
+                              "Time(ps)",
+                              "Rotation (degrees)",
+                              oenv);
     }
 
     clear_rvecs(3, unitaxes);
@@ -357,10 +370,16 @@ int gmx_helixorient(int argc, char* argv[])
                 rvec_sub(bSC ? x_SC[i] : x_CA[i], residueorigin[i], residuevector[i]);
                 svmul(1.0 / norm(residuevector[i]), residuevector[i], residuevector[i]);
                 cprod(residuehelixaxis[i], residuevector[i], axis3[i]);
-                fprintf(fpaxis, "%15.12g %15.12g %15.12g       ", residuehelixaxis[i][0],
-                        residuehelixaxis[i][1], residuehelixaxis[i][2]);
-                fprintf(fpcenter, "%15.12g %15.12g %15.12g       ", residueorigin[i][0],
-                        residueorigin[i][1], residueorigin[i][2]);
+                fprintf(fpaxis,
+                        "%15.12g %15.12g %15.12g       ",
+                        residuehelixaxis[i][0],
+                        residuehelixaxis[i][1],
+                        residuehelixaxis[i][2]);
+                fprintf(fpcenter,
+                        "%15.12g %15.12g %15.12g       ",
+                        residueorigin[i][0],
+                        residueorigin[i][1],
+                        residueorigin[i][2]);
 
                 fprintf(fprise, "%15.12g  ", residuerise[i]);
                 fprintf(fpradius, "%15.12g  ", residueradius[i]);
index 9e45a5ba7d157842597cdb64ab9d28dde809a6f1..6cf1c4e6c303a46953a92898a754a60037e95312 100644 (file)
@@ -366,8 +366,8 @@ static void calc_tetra_order_interface(const char*       fnNDX,
             }
         }
 
-        find_tetra_order_grid(top, pbcType, natoms, box, x, isize[0], index[0], &sg, &sk, *nslicex,
-                              *nslicey, nslicez, sg_grid, sk_grid);
+        find_tetra_order_grid(
+                top, pbcType, natoms, box, x, isize[0], index[0], &sg, &sk, *nslicex, *nslicey, nslicez, sg_grid, sk_grid);
         GMX_RELEASE_ASSERT(sk_fravg != nullptr, "Trying to dereference NULL sk_fravg pointer");
         for (i = 0; i < *nslicex; i++)
         {
@@ -401,10 +401,10 @@ static void calc_tetra_order_interface(const char*       fnNDX,
     /*Debugging for printing out the entire order parameter meshes.*/
     if (debug)
     {
-        fpsg = xvgropen("sg_ang_mesh", "S\\sg\\N Angle Order Parameter / Meshpoint", "(nm)",
-                        "S\\sg\\N", oenv);
-        fpsk = xvgropen("sk_dist_mesh", "S\\sk\\N Distance Order Parameter / Meshpoint", "(nm)",
-                        "S\\sk\\N", oenv);
+        fpsg = xvgropen(
+                "sg_ang_mesh", "S\\sg\\N Angle Order Parameter / Meshpoint", "(nm)", "S\\sg\\N", oenv);
+        fpsk = xvgropen(
+                "sk_dist_mesh", "S\\sk\\N Distance Order Parameter / Meshpoint", "(nm)", "S\\sk\\N", oenv);
         for (n = 0; n < (*nframes); n++)
         {
             fprintf(fpsg, "%i\n", n);
@@ -415,12 +415,18 @@ static void calc_tetra_order_interface(const char*       fnNDX,
                 {
                     for (k = 0; k < nslicez; k++)
                     {
-                        fprintf(fpsg, "%4f  %4f  %4f  %8f\n", (i + 0.5) * box[XX][XX] / (*nslicex),
+                        fprintf(fpsg,
+                                "%4f  %4f  %4f  %8f\n",
+                                (i + 0.5) * box[XX][XX] / (*nslicex),
                                 (j + 0.5) * box[YY][YY] / (*nslicey),
-                                (k + 0.5) * box[ZZ][ZZ] / nslicez, sg_4d[n][i][j][k]);
-                        fprintf(fpsk, "%4f  %4f  %4f  %8f\n", (i + 0.5) * box[XX][XX] / (*nslicex),
+                                (k + 0.5) * box[ZZ][ZZ] / nslicez,
+                                sg_4d[n][i][j][k]);
+                        fprintf(fpsk,
+                                "%4f  %4f  %4f  %8f\n",
+                                (i + 0.5) * box[XX][XX] / (*nslicex),
                                 (j + 0.5) * box[YY][YY] / (*nslicey),
-                                (k + 0.5) * box[ZZ][ZZ] / nslicez, sk_4d[n][i][j][k]);
+                                (k + 0.5) * box[ZZ][ZZ] / nslicez,
+                                sk_4d[n][i][j][k]);
                     }
                 }
             }
@@ -549,10 +555,8 @@ static void writesurftoxpms(real***                          surf,
             }
         }
 
-        write_xpm(xpmfile1, 3, numbuf, "Height", "x[nm]", "y[nm]", xbins, ybins, xticks, yticks,
-                  profile1, min1, max1, lo, hi, &maplevels);
-        write_xpm(xpmfile2, 3, numbuf, "Height", "x[nm]", "y[nm]", xbins, ybins, xticks, yticks,
-                  profile2, min2, max2, lo, hi, &maplevels);
+        write_xpm(xpmfile1, 3, numbuf, "Height", "x[nm]", "y[nm]", xbins, ybins, xticks, yticks, profile1, min1, max1, lo, hi, &maplevels);
+        write_xpm(xpmfile2, 3, numbuf, "Height", "x[nm]", "y[nm]", xbins, ybins, xticks, yticks, profile2, min2, max2, lo, hi, &maplevels);
     }
 
     gmx_ffclose(xpmfile1);
@@ -643,8 +647,8 @@ int gmx_hydorder(int argc, char* argv[])
     const char *      ndxfnm, *tpsfnm, *trxfnm;
     gmx_output_env_t* oenv;
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -694,8 +698,8 @@ int gmx_hydorder(int argc, char* argv[])
     {
         gmx_fatal(FARGS, "No or not correct number (2) of output-files: %td", intfn.ssize());
     }
-    calc_tetra_order_interface(ndxfnm, tpsfnm, trxfnm, binwidth, nsttblock, &frames, &xslices,
-                               &yslices, sg1, sg2, &intfpos, oenv);
+    calc_tetra_order_interface(
+            ndxfnm, tpsfnm, trxfnm, binwidth, nsttblock, &frames, &xslices, &yslices, sg1, sg2, &intfpos, oenv);
     writesurftoxpms(intfpos, frames, xslices, yslices, binwidth, intfn, nlevels);
 
     if (bFourier)
index 7ad065cbf823cae0421a6bad342dfaf13eea5581..580de7876c51354effc637235bbde928fddbfd73 100644 (file)
@@ -184,8 +184,8 @@ int gmx_lie(int argc, char* argv[])
     t_filenm fnm[] = { { efEDR, "-f", "ener", ffREAD }, { efXVG, "-o", "lie", ffWRITE } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, NPA, pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, NPA, pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -196,8 +196,8 @@ int gmx_lie(int argc, char* argv[])
     ld = analyze_names(nre, enm, ligand);
     snew(fr, 1);
 
-    out = xvgropen(ftp2fn(efXVG, NFILE, fnm), "LIE free energy estimate", "Time (ps)",
-                   "DGbind (kJ/mol)", oenv);
+    out = xvgropen(
+            ftp2fn(efXVG, NFILE, fnm), "LIE free energy estimate", "Time (ps)", "DGbind (kJ/mol)", oenv);
     while (do_enx(fp, fr))
     {
         ct = check_times(fr->t);
@@ -216,7 +216,8 @@ int gmx_lie(int argc, char* argv[])
 
     if (nframes > 0)
     {
-        printf("DGbind = %.3f (%.3f)\n", lieaver / nframes,
+        printf("DGbind = %.3f (%.3f)\n",
+               lieaver / nframes,
                std::sqrt(lieav2 / nframes - gmx::square(lieaver / nframes)));
     }
 
index 288cff7feddf509f77bce3d1c9f3b1487e841d78..7f154cd85e60783189f1cf9f121fb5088113bc47 100644 (file)
@@ -304,19 +304,26 @@ static int sscan_list(int* list[], const char* str, const char* listname)
 
             /* format error occured */
             case sError:
-                gmx_fatal(FARGS, "Error in the list of eigenvectors for %s at pos %td with char %c",
-                          listname, pos - startpos, *(pos - 1));
+                gmx_fatal(FARGS,
+                          "Error in the list of eigenvectors for %s at pos %td with char %c",
+                          listname,
+                          pos - startpos,
+                          *(pos - 1));
             /* logical error occured */
             case sZero:
                 gmx_fatal(FARGS,
                           "Error in the list of eigenvectors for %s at pos %td: eigenvector 0 is "
                           "not valid",
-                          listname, pos - startpos);
+                          listname,
+                          pos - startpos);
             case sSmaller:
                 gmx_fatal(FARGS,
                           "Error in the list of eigenvectors for %s at pos %td: second index %d is "
                           "not bigger than %d",
-                          listname, pos - startpos, end_number, number);
+                          listname,
+                          pos - startpos,
+                          end_number,
+                          number);
         }
         ++pos; /* read next character */
     }          /*scanner has finished */
@@ -369,7 +376,8 @@ write_eigvec(FILE* fp, int natoms, int eig_list[], rvec** eigvecs, int nvec, con
                 gmx_fatal(FARGS,
                           "Selected eigenvector %d is higher than maximum number %d of available "
                           "eigenvectors",
-                          eig_list[n], nvec);
+                          eig_list[n],
+                          nvec);
             }
             copy_rvec(eigvecs[eig_list[n] - 1][i], x);
             fprintf(fp, "%8.5f %8.5f %8.5f\n", x[XX], x[YY], x[ZZ]);
@@ -405,16 +413,25 @@ static void write_the_whole_thing(FILE*     fp,
     /* write edi-file */
 
     /*Header*/
-    fprintf(fp, "#MAGIC\n %d \n#NINI\n %d\n#FITMAS\n %d\n#ANALYSIS_MAS\n %d\n", MAGIC, edpars->nini,
-            int(edpars->fitmas), int(edpars->pcamas));
-    fprintf(fp, "#OUTFRQ\n %d\n#MAXLEN\n %d\n#SLOPECRIT\n %f\n", edpars->outfrq, edpars->maxedsteps,
-            edpars->slope);
+    fprintf(fp,
+            "#MAGIC\n %d \n#NINI\n %d\n#FITMAS\n %d\n#ANALYSIS_MAS\n %d\n",
+            MAGIC,
+            edpars->nini,
+            int(edpars->fitmas),
+            int(edpars->pcamas));
+    fprintf(fp, "#OUTFRQ\n %d\n#MAXLEN\n %d\n#SLOPECRIT\n %f\n", edpars->outfrq, edpars->maxedsteps, edpars->slope);
     fprintf(fp,
             "#PRESTEPS\n %d\n#DELTA_F0\n %f\n#INIT_DELTA_F\n %f\n#TAU\n %f\n#EFL_NULL\n "
             "%f\n#ALPHA2\n %f\n#KT\n %f\n#HARMONIC\n %d\n#CONST_FORCE_FLOODING\n %d\n",
-            edpars->presteps, edpars->flood.deltaF0, edpars->flood.deltaF, edpars->flood.tau,
-            edpars->flood.constEfl, edpars->flood.alpha2, edpars->flood.kT,
-            int(edpars->flood.bHarmonic), int(edpars->flood.bConstForce));
+            edpars->presteps,
+            edpars->flood.deltaF0,
+            edpars->flood.deltaF,
+            edpars->flood.tau,
+            edpars->flood.constEfl,
+            edpars->flood.alpha2,
+            edpars->flood.kT,
+            int(edpars->flood.bHarmonic),
+            int(edpars->flood.bConstForce));
 
     /* Average and reference positions */
     write_t_edx(fp, edpars->sref, "NREF, XREF");
@@ -423,16 +440,12 @@ static void write_the_whole_thing(FILE*     fp,
     /*Eigenvectors */
 
     write_eigvec(fp, edpars->ned, eig_listen[evMON], eigvecs, nvec, "COMPONENTS GROUP 1", nullptr);
-    write_eigvec(fp, edpars->ned, eig_listen[evLINFIX], eigvecs, nvec, "COMPONENTS GROUP 2",
-                 evStepList[evLINFIX]);
-    write_eigvec(fp, edpars->ned, eig_listen[evLINACC], eigvecs, nvec, "COMPONENTS GROUP 3",
-                 evStepList[evLINACC]);
-    write_eigvec(fp, edpars->ned, eig_listen[evRADFIX], eigvecs, nvec, "COMPONENTS GROUP 4",
-                 evStepList[evRADFIX]);
+    write_eigvec(fp, edpars->ned, eig_listen[evLINFIX], eigvecs, nvec, "COMPONENTS GROUP 2", evStepList[evLINFIX]);
+    write_eigvec(fp, edpars->ned, eig_listen[evLINACC], eigvecs, nvec, "COMPONENTS GROUP 3", evStepList[evLINACC]);
+    write_eigvec(fp, edpars->ned, eig_listen[evRADFIX], eigvecs, nvec, "COMPONENTS GROUP 4", evStepList[evRADFIX]);
     write_eigvec(fp, edpars->ned, eig_listen[evRADACC], eigvecs, nvec, "COMPONENTS GROUP 5", nullptr);
     write_eigvec(fp, edpars->ned, eig_listen[evRADCON], eigvecs, nvec, "COMPONENTS GROUP 6", nullptr);
-    write_eigvec(fp, edpars->ned, eig_listen[evFLOOD], eigvecs, nvec, "COMPONENTS GROUP 7",
-                 evStepList[evFLOOD]);
+    write_eigvec(fp, edpars->ned, eig_listen[evFLOOD], eigvecs, nvec, "COMPONENTS GROUP 7", evStepList[evFLOOD]);
 
 
     /*Target and Origin positions */
@@ -600,7 +613,8 @@ static void get_structure(const t_atoms* atoms,
     ntar = read_conffile(StructureFile, &xtar);
     printf("Select an index group of %d elements that corresponds to the atoms in the structure "
            "file %s\n",
-           ntar, StructureFile);
+           ntar,
+           StructureFile);
     get_index(atoms, IndexFile, 1, &ngro, &igro, &grpname);
     if (ngro != ntar)
     {
@@ -930,15 +944,15 @@ int gmx_make_edi(int argc, char* argv[])
         if (opt2parg_bSet(evOptions[ev_class], NPA, pa))
         {
             /*get list of eigenvectors*/
-            nvecs = sscan_list(&(listen[ev_class]), opt2parg_str(evOptions[ev_class], NPA, pa),
-                               evOptions[ev_class]);
+            nvecs = sscan_list(
+                    &(listen[ev_class]), opt2parg_str(evOptions[ev_class], NPA, pa), evOptions[ev_class]);
             if (ev_class < evStepNr - 2)
             {
                 /*if apropriate get list of stepsizes for these eigenvectors*/
                 if (opt2parg_bSet(evStepOptions[ev_class], NPA, pa))
                 {
-                    evStepList[ev_class] = scan_vecparams(opt2parg_str(evStepOptions[ev_class], NPA, pa),
-                                                          evStepOptions[ev_class], nvecs);
+                    evStepList[ev_class] = scan_vecparams(
+                            opt2parg_str(evStepOptions[ev_class], NPA, pa), evStepOptions[ev_class], nvecs);
                 }
                 else /*if list is not given fill with zeros */
                 {
@@ -996,8 +1010,8 @@ int gmx_make_edi(int argc, char* argv[])
     EigvecFile = opt2fn("-f", NFILE, fnm);
 
     /*read eigenvectors from eigvec.trr*/
-    read_eigenvectors(EigvecFile, &nav, &bFit1, &xref1, &edi_params.fitmas, &xav1,
-                      &edi_params.pcamas, &nvec1, &eignr1, &eigvec1, &eigval1);
+    read_eigenvectors(
+            EigvecFile, &nav, &bFit1, &xref1, &edi_params.fitmas, &xav1, &edi_params.pcamas, &nvec1, &eignr1, &eigvec1, &eigval1);
 
     read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &pbcType, &xtop, nullptr, topbox, false);
     atoms = &top.atoms;
@@ -1052,8 +1066,8 @@ int gmx_make_edi(int argc, char* argv[])
 
         if (listen[evFLOOD][0] != 0)
         {
-            read_eigenvalues(listen[evFLOOD], opt2fn("-eig", NFILE, fnm), evStepList[evFLOOD],
-                             bHesse, kB * T, nav);
+            read_eigenvalues(
+                    listen[evFLOOD], opt2fn("-eig", NFILE, fnm), evStepList[evFLOOD], bHesse, kB * T, nav);
         }
 
         edi_params.flood.tau       = tau;
index a6a9058d7aeb6878ad564bc9b8309adc7fdad4b3..dd567d225eed789c8663c83fa661461b2ffc2ae0 100644 (file)
@@ -229,8 +229,8 @@ int gmx_mdmat(int argc, char* argv[])
     gmx_output_env_t* oenv;
     gmx_rmpbc_t       gpbc = nullptr;
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc,
-                           0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -268,9 +268,13 @@ int gmx_mdmat(int argc, char* argv[])
             useatoms.resinfo[i] = top.atoms.resinfo[prevres];
             if (debug)
             {
-                fprintf(debug, "New residue: atom %5s %5s %6d, index entry %5d, newres %5d\n",
+                fprintf(debug,
+                        "New residue: atom %5s %5s %6d, index entry %5d, newres %5d\n",
                         *(top.atoms.resinfo[top.atoms.atom[ii].resind].name),
-                        *(top.atoms.atomname[ii]), ii, i, newres);
+                        *(top.atoms.atomname[ii]),
+                        ii,
+                        i,
+                        newres);
             }
         }
         useatoms.atom[i].resind = newres;
@@ -344,8 +348,22 @@ int gmx_mdmat(int argc, char* argv[])
         if (bFrames)
         {
             sprintf(label, "t=%.0f ps", t);
-            write_xpm(out, 0, label, "Distance (nm)", "Residue Index", "Residue Index", nres, nres,
-                      resnr, resnr, mdmat, 0, truncate, rlo, rhi, &nlevels);
+            write_xpm(out,
+                      0,
+                      label,
+                      "Distance (nm)",
+                      "Residue Index",
+                      "Residue Index",
+                      nres,
+                      nres,
+                      resnr,
+                      resnr,
+                      mdmat,
+                      0,
+                      truncate,
+                      rlo,
+                      rhi,
+                      &nlevels);
         }
     } while (read_next_x(oenv, status, &t, x, box));
     fprintf(stderr, "\n");
@@ -365,9 +383,22 @@ int gmx_mdmat(int argc, char* argv[])
             totmdmat[i][j] /= nframes;
         }
     }
-    write_xpm(opt2FILE("-mean", NFILE, fnm, "w"), 0, "Mean smallest distance", "Distance (nm)",
-              "Residue Index", "Residue Index", nres, nres, resnr, resnr, totmdmat, 0, truncate,
-              rlo, rhi, &nlevels);
+    write_xpm(opt2FILE("-mean", NFILE, fnm, "w"),
+              0,
+              "Mean smallest distance",
+              "Distance (nm)",
+              "Residue Index",
+              "Residue Index",
+              nres,
+              nres,
+              resnr,
+              resnr,
+              totmdmat,
+              0,
+              truncate,
+              rlo,
+              rhi,
+              &nlevels);
 
     if (bCalcN)
     {
@@ -379,8 +410,8 @@ int gmx_mdmat(int argc, char* argv[])
             snew(legend[i], STRLEN);
         }
         tot_nmat(nres, natoms, nframes, totnmat, tot_n, mean_n);
-        fp = xvgropen(ftp2fn(efXVG, NFILE, fnm), "Increase in number of contacts", "Residue",
-                      "Ratio", oenv);
+        fp = xvgropen(
+                ftp2fn(efXVG, NFILE, fnm), "Increase in number of contacts", "Residue", "Ratio", oenv);
         sprintf(legend[0], "Total/mean");
         sprintf(legend[1], "Total");
         sprintf(legend[2], "Mean");
@@ -397,8 +428,14 @@ int gmx_mdmat(int argc, char* argv[])
             {
                 ratio = tot_n[i] / mean_n[i];
             }
-            fprintf(fp, "%3d  %8.3f  %3d  %8.3f  %3d  %8.3f\n", i + 1, ratio, tot_n[i], mean_n[i],
-                    natm[i], mean_n[i] / natm[i]);
+            fprintf(fp,
+                    "%3d  %8.3f  %3d  %8.3f  %3d  %8.3f\n",
+                    i + 1,
+                    ratio,
+                    tot_n[i],
+                    mean_n[i],
+                    natm[i],
+                    mean_n[i] / natm[i]);
         }
         xvgrclose(fp);
     }
index ed51f851d9a415b1f73a8feec5181a1d4a6896ee..4fae52563020c8f0492c7a97200073fe51153cad 100644 (file)
@@ -161,8 +161,11 @@ static void periodic_mindist_plot(const char*             trxfn,
 
     check_index(nullptr, n, index, nullptr, natoms);
 
-    out = xvgropen(outfn, "Minimum distance to periodic image", output_env_get_time_label(oenv),
-                   "Distance (nm)", oenv);
+    out = xvgropen(outfn,
+                   "Minimum distance to periodic image",
+                   output_env_get_time_label(oenv),
+                   "Distance (nm)",
+                   oenv);
     if (output_env_get_print_xvgr_codes(oenv))
     {
         fprintf(out, "@ subtitle \"and maximum internal distance\"\n");
@@ -197,8 +200,14 @@ static void periodic_mindist_plot(const char*             trxfn,
         {
             fprintf(out, "%s\n", output_env_get_print_xvgr_codes(oenv) ? "&" : "");
         }
-        fprintf(out, "\t%g\t%6.3f %6.3f %6.3f %6.3f %6.3f\n", output_env_conv_time(oenv, t), rmin,
-                rmax, norm(box[0]), norm(box[1]), norm(box[2]));
+        fprintf(out,
+                "\t%g\t%6.3f %6.3f %6.3f %6.3f %6.3f\n",
+                output_env_conv_time(oenv, t),
+                rmin,
+                rmax,
+                norm(box[0]),
+                norm(box[1]),
+                norm(box[2]));
         bFirst = FALSE;
     } while (read_next_x(oenv, status, &t, x, box));
 
@@ -212,8 +221,11 @@ static void periodic_mindist_plot(const char*             trxfn,
     fprintf(stdout,
             "\nThe shortest periodic distance is %g (nm) at time %g (%s),\n"
             "between atoms %d and %d\n",
-            rmint, output_env_conv_time(oenv, tmint), output_env_get_time_unit(oenv).c_str(),
-            index[ind_mini] + 1, index[ind_minj] + 1);
+            rmint,
+            output_env_conv_time(oenv, tmint),
+            output_env_get_time_unit(oenv).c_str(),
+            index[ind_mini] + 1,
+            index[ind_minj] + 1);
 }
 
 static void calc_dist(real     rcut,
@@ -450,7 +462,8 @@ static void dist_plot(const char*             fn,
 
             for (j = 0; j < nres; j++)
             {
-                fprintf(respertime, "%s%d ",
+                fprintf(respertime,
+                        "%s%d ",
                         *(atoms->resinfo[atoms->atom[index[0][residue[j]]].resind].name),
                         atoms->atom[index[0][residue[j]]].resind);
             }
@@ -498,8 +511,24 @@ static void dist_plot(const char*             fn,
         {
             if (ng == 1)
             {
-                calc_dist(rcut, bPBC, pbcType, box, x0, gnx[0], gnx[0], index[0], index[0], bGroup,
-                          &dmin, &dmax, &nmin, &nmax, &min1, &min2, &max1, &max2);
+                calc_dist(rcut,
+                          bPBC,
+                          pbcType,
+                          box,
+                          x0,
+                          gnx[0],
+                          gnx[0],
+                          index[0],
+                          index[0],
+                          bGroup,
+                          &dmin,
+                          &dmax,
+                          &nmin,
+                          &nmax,
+                          &min1,
+                          &min2,
+                          &max1,
+                          &max2);
                 fprintf(dist, "  %12e", bMin ? dmin : dmax);
                 if (num)
                 {
@@ -512,8 +541,24 @@ static void dist_plot(const char*             fn,
                 {
                     for (k = i + 1; (k < ng); k++)
                     {
-                        calc_dist(rcut, bPBC, pbcType, box, x0, gnx[i], gnx[k], index[i], index[k],
-                                  bGroup, &dmin, &dmax, &nmin, &nmax, &min1, &min2, &max1, &max2);
+                        calc_dist(rcut,
+                                  bPBC,
+                                  pbcType,
+                                  box,
+                                  x0,
+                                  gnx[i],
+                                  gnx[k],
+                                  index[i],
+                                  index[k],
+                                  bGroup,
+                                  &dmin,
+                                  &dmax,
+                                  &nmin,
+                                  &nmax,
+                                  &min1,
+                                  &min2,
+                                  &max1,
+                                  &max2);
                         fprintf(dist, "  %12e", bMin ? dmin : dmax);
                         if (num)
                         {
@@ -528,8 +573,24 @@ static void dist_plot(const char*             fn,
             GMX_RELEASE_ASSERT(ng > 1, "Must have more than one group when not using -matrix");
             for (i = 1; (i < ng); i++)
             {
-                calc_dist(rcut, bPBC, pbcType, box, x0, gnx[0], gnx[i], index[0], index[i], bGroup,
-                          &dmin, &dmax, &nmin, &nmax, &min1, &min2, &max1, &max2);
+                calc_dist(rcut,
+                          bPBC,
+                          pbcType,
+                          box,
+                          x0,
+                          gnx[0],
+                          gnx[i],
+                          index[0],
+                          index[i],
+                          bGroup,
+                          &dmin,
+                          &dmax,
+                          &nmin,
+                          &nmax,
+                          &min1,
+                          &min2,
+                          &max1,
+                          &max2);
                 fprintf(dist, "  %12e", bMin ? dmin : dmax);
                 if (num)
                 {
@@ -539,9 +600,24 @@ static void dist_plot(const char*             fn,
                 {
                     for (j = 0; j < nres; j++)
                     {
-                        calc_dist(rcut, bPBC, pbcType, box, x0, residue[j + 1] - residue[j], gnx[i],
-                                  &(index[0][residue[j]]), index[i], bGroup, &dmin, &dmax, &nmin,
-                                  &nmax, &min1r, &min2r, &max1r, &max2r);
+                        calc_dist(rcut,
+                                  bPBC,
+                                  pbcType,
+                                  box,
+                                  x0,
+                                  residue[j + 1] - residue[j],
+                                  gnx[i],
+                                  &(index[0][residue[j]]),
+                                  index[i],
+                                  bGroup,
+                                  &dmin,
+                                  &dmax,
+                                  &nmin,
+                                  &nmax,
+                                  &min1r,
+                                  &min2r,
+                                  &max1r,
+                                  &max2r);
                         mindres[i - 1][j] = std::min(mindres[i - 1][j], dmin);
                         maxdres[i - 1][j] = std::max(maxdres[i - 1][j], dmax);
                     }
@@ -557,8 +633,11 @@ static void dist_plot(const char*             fn,
         {
             if (atm)
             {
-                fprintf(atm, "%12e  %12d  %12d\n", output_env_conv_time(oenv, t),
-                        1 + (bMin ? min1 : max1), 1 + (bMin ? min2 : max2));
+                fprintf(atm,
+                        "%12e  %12d  %12d\n",
+                        output_env_conv_time(oenv, t),
+                        1 + (bMin ? min1 : max1),
+                        1 + (bMin ? min2 : max2));
             }
         }
 
@@ -755,8 +834,18 @@ int gmx_mindist(int argc, char* argv[])
                        { efTRO, "-ox", "mindist", ffOPTWR }, { efXVG, "-or", "mindistres", ffOPTWR } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm,
-                           asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(&argc,
+                           argv,
+                           PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT,
+                           NFILE,
+                           fnm,
+                           asize(pa),
+                           pa,
+                           asize(desc),
+                           desc,
+                           0,
+                           nullptr,
+                           &oenv))
     {
         return 0;
     }
@@ -848,9 +937,29 @@ int gmx_mindist(int argc, char* argv[])
     }
     else
     {
-        dist_plot(trxfnm, atmfnm, distfnm, numfnm, resfnm, oxfnm, rcutoff, bMat,
-                  top ? &(top->atoms) : nullptr, ng, index, gnx, grpname, bSplit, !bMax, nres,
-                  residues, bPBC, pbcType, bGroup, bEachResEachTime, bPrintResName, oenv);
+        dist_plot(trxfnm,
+                  atmfnm,
+                  distfnm,
+                  numfnm,
+                  resfnm,
+                  oxfnm,
+                  rcutoff,
+                  bMat,
+                  top ? &(top->atoms) : nullptr,
+                  ng,
+                  index,
+                  gnx,
+                  grpname,
+                  bSplit,
+                  !bMax,
+                  nres,
+                  residues,
+                  bPBC,
+                  pbcType,
+                  bGroup,
+                  bEachResEachTime,
+                  bPrintResName,
+                  oenv);
     }
 
     do_view(oenv, distfnm, "-nxy");
diff --git a/src/gromacs/gmxana/gmx_msd.cpp b/src/gromacs/gmxana/gmx_msd.cpp
deleted file mode 100644 (file)
index 20db415..0000000
+++ /dev/null
@@ -1,1229 +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,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cmath>
-#include <cstring>
-
-#include <memory>
-
-#include "gromacs/commandline/pargs.h"
-#include "gromacs/commandline/viewit.h"
-#include "gromacs/fileio/confio.h"
-#include "gromacs/fileio/trxio.h"
-#include "gromacs/fileio/xvgr.h"
-#include "gromacs/gmxana/gmx_ana.h"
-#include "gromacs/gmxana/gstat.h"
-#include "gromacs/math/functions.h"
-#include "gromacs/math/utilities.h"
-#include "gromacs/math/vec.h"
-#include "gromacs/math/vectypes.h"
-#include "gromacs/pbcutil/rmpbc.h"
-#include "gromacs/statistics/statistics.h"
-#include "gromacs/topology/index.h"
-#include "gromacs/topology/topology.h"
-#include "gromacs/utility/arraysize.h"
-#include "gromacs/utility/fatalerror.h"
-#include "gromacs/utility/futil.h"
-#include "gromacs/utility/gmxassert.h"
-#include "gromacs/utility/smalloc.h"
-
-static constexpr double diffusionConversionFactor = 1000.0; /* Convert nm^2/ps to 10e-5 cm^2/s */
-/* NORMAL = total diffusion coefficient (default). X,Y,Z is diffusion
-   coefficient in X,Y,Z direction. LATERAL is diffusion coefficient in
-   plane perpendicular to axis
- */
-typedef enum
-{
-    NOT_USED,
-    NORMAL,
-    X,
-    Y,
-    Z,
-    LATERAL
-} msd_type;
-
-// TODO : Group related fields into a struct
-struct t_corr
-{
-    real t0;                                  /* start time and time increment between  */
-    real delta_t;                             /* time between restart points */
-    real beginfit,                            /* the begin/end time for fits as reals between */
-            endfit;                           /* 0 and 1 */
-    real dim_factor;                          /* the dimensionality factor for the diffusion
-                                                 constant */
-    std::vector<std::vector<real>> data;      /* the displacement data. First index is the group
-                                                 number, second is frame number */
-    std::vector<real>                   time; /* frame time */
-    std::vector<real>                   mass; /* masses for mass-weighted msd */
-    matrix**                            datam;
-    std::vector<std::vector<gmx::RVec>> x0;   /* original positions */
-    std::vector<gmx::RVec>              com;  /* center of mass correction for each frame */
-    gmx_stats_t**                       lsq;  /* fitting stats for individual molecule msds */
-    msd_type                            type; /* the type of msd to calculate (lateral, etc.)*/
-    int                                 axis; /* the axis along which to calculate */
-    int                                 ncoords;
-    int                                 nrestart; /* number of restart points */
-    int                                 nmol;     /* number of molecules (for bMol) */
-    int                                 nframes;  /* number of frames */
-    int                                 nlast;
-    int                                 ngrp; /* number of groups to use for msd calculation */
-    std::vector<int>                    n_offs;
-    std::vector<std::vector<int>>       ndata; /* the number of msds (particles/mols) per data
-                                                  point. */
-    t_corr(int               nrgrp,
-           int               type,
-           int               axis,
-           real              dim_factor,
-           int               nrmol,
-           gmx_bool          bTen,
-           gmx_bool          bMass,
-           real              dt,
-           const t_topology* top,
-           real              beginfit,
-           real              endfit) :
-        t0(0),
-        delta_t(dt),
-        beginfit((1 - 2 * GMX_REAL_EPS) * beginfit),
-        endfit((1 + 2 * GMX_REAL_EPS) * endfit),
-        dim_factor(dim_factor),
-        data(nrgrp, std::vector<real>()),
-        datam(nullptr),
-        lsq(nullptr),
-        type(static_cast<msd_type>(type)),
-        axis(axis),
-        ncoords(0),
-        nrestart(0),
-        nmol(nrmol),
-        nframes(0),
-        nlast(0),
-        ngrp(nrgrp),
-        ndata(nrgrp, std::vector<int>())
-    {
-
-        if (bTen)
-        {
-            snew(datam, nrgrp);
-            for (int i = 0; i < nrgrp; i++)
-            {
-                datam[i] = nullptr;
-            }
-        }
-
-        if (nmol > 0)
-        {
-            mass.resize(nmol, 1);
-        }
-        else
-        {
-            if (bMass)
-            {
-                const t_atoms* atoms = &top->atoms;
-                mass.resize(atoms->nr);
-                for (int i = 0; (i < atoms->nr); i++)
-                {
-                    mass[i] = atoms->atom[i].m;
-                }
-            }
-        }
-    }
-    ~t_corr()
-    {
-        for (int i = 0; i < nrestart; i++)
-        {
-            for (int j = 0; j < nmol; j++)
-            {
-                gmx_stats_free(lsq[i][j]);
-            }
-        }
-        sfree(lsq);
-    }
-};
-
-typedef real
-t_calc_func(t_corr* curr, int nx, const int index[], int nx0, rvec xc[], const rvec dcom, gmx_bool bTen, matrix mat);
-
-static real thistime(t_corr* curr)
-{
-    return curr->time[curr->nframes];
-}
-
-static int in_data(t_corr* curr, int nx00)
-{
-    return curr->nframes - curr->n_offs[nx00];
-}
-
-static void corr_print(t_corr*                 curr,
-                       gmx_bool                bTen,
-                       const char*             fn,
-                       const char*             title,
-                       const char*             yaxis,
-                       real                    msdtime,
-                       real                    beginfit,
-                       real                    endfit,
-                       real*                   DD,
-                       real*                   SigmaD,
-                       char*                   grpname[],
-                       const gmx_output_env_t* oenv)
-{
-    FILE* out;
-    int   i, j;
-
-    out = xvgropen(fn, title, output_env_get_xvgr_tlabel(oenv), yaxis, oenv);
-    if (DD)
-    {
-        fprintf(out, "# MSD gathered over %g %s with %d restarts\n", msdtime,
-                output_env_get_time_unit(oenv).c_str(), curr->nrestart);
-        fprintf(out, "# Diffusion constants fitted from time %g to %g %s\n", beginfit, endfit,
-                output_env_get_time_unit(oenv).c_str());
-        for (i = 0; i < curr->ngrp; i++)
-        {
-            fprintf(out, "# D[%10s] = %.4f (+/- %.4f) (1e-5 cm^2/s)\n", grpname[i], DD[i], SigmaD[i]);
-        }
-    }
-    for (i = 0; i < curr->nframes; i++)
-    {
-        fprintf(out, "%10g", output_env_conv_time(oenv, curr->time[i]));
-        for (j = 0; j < curr->ngrp; j++)
-        {
-            fprintf(out, "  %10g", curr->data[j][i]);
-            if (bTen)
-            {
-                fprintf(out, " %10g %10g %10g %10g %10g %10g", curr->datam[j][i][XX][XX],
-                        curr->datam[j][i][YY][YY], curr->datam[j][i][ZZ][ZZ], curr->datam[j][i][YY][XX],
-                        curr->datam[j][i][ZZ][XX], curr->datam[j][i][ZZ][YY]);
-            }
-        }
-        fprintf(out, "\n");
-    }
-    xvgrclose(out);
-}
-
-/* called from corr_loop, to do the main calculations */
-static void
-calc_corr(t_corr* curr, int nr, int nx, int index[], rvec xc[], gmx_bool bRmCOMM, rvec com, t_calc_func* calc1, gmx_bool bTen)
-{
-    int    nx0;
-    real   g;
-    matrix mat;
-    rvec   dcom;
-
-    /* Check for new starting point */
-    if (curr->nlast < curr->nrestart)
-    {
-        if ((thistime(curr) >= (curr->nlast * curr->delta_t)) && (nr == 0))
-        {
-            std::memcpy(curr->x0[curr->nlast].data()->as_vec(), xc, curr->ncoords * sizeof(xc[0]));
-            curr->n_offs[curr->nlast] = curr->nframes;
-            copy_rvec(com, curr->com[curr->nlast]);
-            curr->nlast++;
-        }
-    }
-
-    /* nx0 appears to be the number of new starting points,
-     * so for all starting points, call calc1.
-     */
-    for (nx0 = 0; (nx0 < curr->nlast); nx0++)
-    {
-        if (bRmCOMM)
-        {
-            rvec_sub(com, curr->com[nx0], dcom);
-        }
-        else
-        {
-            clear_rvec(dcom);
-        }
-        g = calc1(curr, nx, index, nx0, xc, dcom, bTen, mat);
-#ifdef DEBUG2
-        printf("g[%d]=%g\n", nx0, g);
-#endif
-        curr->data[nr][in_data(curr, nx0)] += g;
-        if (bTen)
-        {
-            m_add(curr->datam[nr][in_data(curr, nx0)], mat, curr->datam[nr][in_data(curr, nx0)]);
-        }
-        curr->ndata[nr][in_data(curr, nx0)]++;
-    }
-}
-
-/* the non-mass-weighted mean-squared displacement calculation */
-static real
-calc1_norm(t_corr* curr, int nx, const int index[], int nx0, rvec xc[], const rvec dcom, gmx_bool bTen, matrix mat)
-{
-    int  i, ix, m, m2;
-    real g, r, r2;
-    rvec rv;
-
-    g = 0.0;
-    clear_mat(mat);
-
-    for (i = 0; (i < nx); i++)
-    {
-        ix = index[i];
-        r2 = 0.0;
-        switch (curr->type)
-        {
-            case NORMAL:
-                for (m = 0; (m < DIM); m++)
-                {
-                    rv[m] = xc[ix][m] - curr->x0[nx0][ix][m] - dcom[m];
-                    r2 += rv[m] * rv[m];
-                    if (bTen)
-                    {
-                        for (m2 = 0; m2 <= m; m2++)
-                        {
-                            mat[m][m2] += rv[m] * rv[m2];
-                        }
-                    }
-                }
-                break;
-            case X:
-            case Y:
-            case Z:
-                r = xc[ix][curr->type - X] - curr->x0[nx0][ix][curr->type - X] - dcom[curr->type - X];
-                r2 += r * r;
-                break;
-            case LATERAL:
-                for (m = 0; (m < DIM); m++)
-                {
-                    if (m != curr->axis)
-                    {
-                        r = xc[ix][m] - curr->x0[nx0][ix][m] - dcom[m];
-                        r2 += r * r;
-                    }
-                }
-                break;
-            default: gmx_fatal(FARGS, "Error: did not expect option value %d", curr->type);
-        }
-        g += r2;
-    }
-    g /= nx;
-    msmul(mat, 1.0 / nx, mat);
-
-    return g;
-}
-
-/* calculate the com of molecules in x and put it into xa */
-static void
-calc_mol_com(int nmol, const int* molindex, const t_block* mols, const t_atoms* atoms, rvec* x, rvec* xa)
-{
-    int  m, mol, i, d;
-    rvec xm;
-    real mass, mtot;
-
-    for (m = 0; m < nmol; m++)
-    {
-        mol = molindex[m];
-        clear_rvec(xm);
-        mtot = 0;
-        for (i = mols->index[mol]; i < mols->index[mol + 1]; i++)
-        {
-            mass = atoms->atom[i].m;
-            for (d = 0; d < DIM; d++)
-            {
-                xm[d] += mass * x[i][d];
-            }
-            mtot += mass;
-        }
-        svmul(1 / mtot, xm, xa[m]);
-    }
-}
-
-static real calc_one_mw(t_corr* curr, int ix, int nx0, rvec xc[], real* tm, const rvec dcom, gmx_bool bTen, matrix mat)
-{
-    real r2, r, mm;
-    rvec rv;
-    int  m, m2;
-
-    mm = curr->mass[ix];
-    if (mm == 0)
-    {
-        return 0;
-    }
-    (*tm) += mm;
-    r2 = 0.0;
-    switch (curr->type)
-    {
-        case NORMAL:
-            for (m = 0; (m < DIM); m++)
-            {
-                rv[m] = xc[ix][m] - curr->x0[nx0][ix][m] - dcom[m];
-                r2 += mm * rv[m] * rv[m];
-                if (bTen)
-                {
-                    for (m2 = 0; m2 <= m; m2++)
-                    {
-                        mat[m][m2] += mm * rv[m] * rv[m2];
-                    }
-                }
-            }
-            break;
-        case X:
-        case Y:
-        case Z:
-            r  = xc[ix][curr->type - X] - curr->x0[nx0][ix][curr->type - X] - dcom[curr->type - X];
-            r2 = mm * r * r;
-            break;
-        case LATERAL:
-            for (m = 0; (m < DIM); m++)
-            {
-                if (m != curr->axis)
-                {
-                    r = xc[ix][m] - curr->x0[nx0][ix][m] - dcom[m];
-                    r2 += mm * r * r;
-                }
-            }
-            break;
-        default: gmx_fatal(FARGS, "Options got screwed. Did not expect value %d\n", curr->type);
-    } /* end switch */
-    return r2;
-}
-
-/* the normal, mass-weighted mean-squared displacement calcuation */
-static real calc1_mw(t_corr* curr, int nx, const int index[], int nx0, rvec xc[], const rvec dcom, gmx_bool bTen, matrix mat)
-{
-    int  i;
-    real g, tm;
-
-    g = tm = 0.0;
-    clear_mat(mat);
-    for (i = 0; (i < nx); i++)
-    {
-        g += calc_one_mw(curr, index[i], nx0, xc, &tm, dcom, bTen, mat);
-    }
-
-    g /= tm;
-    if (bTen)
-    {
-        msmul(mat, 1 / tm, mat);
-    }
-
-    return g;
-}
-
-/* prepare the coordinates by removing periodic boundary crossings.
-   gnx = the number of atoms/molecules
-   index = the indices
-   xcur = the current coordinates
-   xprev = the previous coordinates
-   box = the box matrix */
-static void prep_data(gmx_bool bMol, int gnx, const int index[], rvec xcur[], rvec xprev[], matrix box)
-{
-    int  i, m, ind;
-    rvec hbox;
-
-    /* Remove periodicity */
-    for (m = 0; (m < DIM); m++)
-    {
-        hbox[m] = 0.5 * box[m][m];
-    }
-
-    for (i = 0; (i < gnx); i++)
-    {
-        if (bMol)
-        {
-            ind = i;
-        }
-        else
-        {
-            ind = index[i];
-        }
-
-        for (m = DIM - 1; m >= 0; m--)
-        {
-            if (hbox[m] == 0)
-            {
-                continue;
-            }
-            while (xcur[ind][m] - xprev[ind][m] <= -hbox[m])
-            {
-                rvec_inc(xcur[ind], box[m]);
-            }
-            while (xcur[ind][m] - xprev[ind][m] > hbox[m])
-            {
-                rvec_dec(xcur[ind], box[m]);
-            }
-        }
-    }
-}
-
-/* calculate the center of mass for a group
-   gnx = the number of atoms/molecules
-   index = the indices
-   xcur = the current coordinates
-   xprev = the previous coordinates
-   box = the box matrix
-   atoms = atom data (for mass)
-   com(output) = center of mass  */
-static void
-calc_com(gmx_bool bMol, int gnx, int index[], rvec xcur[], rvec xprev[], matrix box, const t_atoms* atoms, rvec com)
-{
-    int    i, m, ind;
-    real   mass;
-    double tmass;
-    dvec   sx;
-
-    clear_dvec(sx);
-    tmass = 0;
-
-    prep_data(bMol, gnx, index, xcur, xprev, box);
-    for (i = 0; (i < gnx); i++)
-    {
-        if (bMol)
-        {
-            ind = i;
-        }
-        else
-        {
-            ind = index[i];
-        }
-
-
-        mass = atoms->atom[ind].m;
-        for (m = 0; m < DIM; m++)
-        {
-            sx[m] += mass * xcur[ind][m];
-        }
-        tmass += mass;
-    }
-    for (m = 0; m < DIM; m++)
-    {
-        com[m] = sx[m] / tmass;
-    }
-}
-
-
-static real calc1_mol(t_corr*   curr,
-                      int       nx,
-                      const int gmx_unused index[],
-                      int                  nx0,
-                      rvec                 xc[],
-                      const rvec           dcom,
-                      gmx_bool             bTen,
-                      matrix               mat)
-{
-    int  i;
-    real g, tm, gtot, tt;
-
-    tt   = curr->time[in_data(curr, nx0)];
-    gtot = 0;
-    tm   = 0;
-    clear_mat(mat);
-    for (i = 0; (i < nx); i++)
-    {
-        g = calc_one_mw(curr, i, nx0, xc, &tm, dcom, bTen, mat);
-        /* We don't need to normalize as the mass was set to 1 */
-        gtot += g;
-        if (tt >= curr->beginfit && (curr->endfit < 0 || tt <= curr->endfit))
-        {
-            gmx_stats_add_point(curr->lsq[nx0][i], tt, g, 0, 0);
-        }
-    }
-    msmul(mat, 1.0 / nx, mat);
-
-    return gtot / nx;
-}
-
-static void printmol(t_corr*                 curr,
-                     const char*             fn,
-                     const char*             fn_pdb,
-                     const int*              molindex,
-                     const t_topology*       top,
-                     rvec*                   x,
-                     PbcType                 pbcType,
-                     matrix                  box,
-                     const gmx_output_env_t* oenv)
-{
-    FILE*       out;
-    gmx_stats_t lsq1;
-    int         i, j;
-    real        a, b, D, Dav, D2av, VarD, sqrtD, sqrtD_max, scale;
-    t_pdbinfo*  pdbinfo = nullptr;
-    const int*  mol2a   = nullptr;
-
-    out = xvgropen(fn, "Diffusion Coefficients / Molecule", "Molecule", "D (1e-5 cm^2/s)", oenv);
-
-    if (fn_pdb)
-    {
-        pdbinfo = top->atoms.pdbinfo;
-        mol2a   = top->mols.index;
-    }
-
-    Dav = D2av = 0;
-    sqrtD_max  = 0;
-    for (i = 0; (i < curr->nmol); i++)
-    {
-        lsq1 = gmx_stats_init();
-        for (j = 0; (j < curr->nrestart); j++)
-        {
-            real xx, yy, dx, dy;
-
-            while (gmx_stats_get_point(curr->lsq[j][i], &xx, &yy, &dx, &dy, 0) == estatsOK)
-            {
-                gmx_stats_add_point(lsq1, xx, yy, dx, dy);
-            }
-        }
-        gmx_stats_get_ab(lsq1, elsqWEIGHT_NONE, &a, &b, nullptr, nullptr, nullptr, nullptr);
-        gmx_stats_free(lsq1);
-        D = a * diffusionConversionFactor / curr->dim_factor;
-        if (D < 0)
-        {
-            D = 0;
-        }
-        Dav += D;
-        D2av += gmx::square(D);
-        fprintf(out, "%10d  %10g\n", i, D);
-        if (pdbinfo)
-        {
-            sqrtD = std::sqrt(D);
-            if (sqrtD > sqrtD_max)
-            {
-                sqrtD_max = sqrtD;
-            }
-            for (j = mol2a[molindex[i]]; j < mol2a[molindex[i] + 1]; j++)
-            {
-                pdbinfo[j].bfac = sqrtD;
-            }
-        }
-    }
-    xvgrclose(out);
-    fprintf(stdout, "Wrote per-molecule output to %s\n", fn);
-    do_view(oenv, fn, "-graphtype bar");
-
-    /* Compute variance, stddev and error */
-    Dav /= curr->nmol;
-    D2av /= curr->nmol;
-    VarD = D2av - gmx::square(Dav);
-    printf("<D> = %.4f Std. Dev. = %.4f Error = %.4f\n", Dav, std::sqrt(VarD),
-           std::sqrt(VarD / curr->nmol));
-
-    if (fn_pdb && x)
-    {
-        scale = 1;
-        while (scale * sqrtD_max > 10)
-        {
-            scale *= 0.1;
-        }
-        while (scale * sqrtD_max < 0.1)
-        {
-            scale *= 10;
-        }
-        GMX_RELEASE_ASSERT(pdbinfo != nullptr, "Internal error - pdbinfo not set for PDB input");
-        for (i = 0; i < top->atoms.nr; i++)
-        {
-            pdbinfo[i].bfac *= scale;
-        }
-        write_sto_conf(fn_pdb, "molecular MSD", &top->atoms, x, nullptr, pbcType, box);
-        fprintf(stdout, "Wrote frame for -tpdb to %s\n", fn_pdb);
-    }
-}
-
-/* this is the main loop for the correlation type functions
- * fx and nx are file pointers to things like read_first_x and
- * read_next_x
- */
-static int corr_loop(t_corr*                  curr,
-                     const char*              fn,
-                     const t_topology*        top,
-                     PbcType                  pbcType,
-                     gmx_bool                 bMol,
-                     int                      gnx[],
-                     int*                     index[],
-                     t_calc_func*             calc1,
-                     gmx_bool                 bTen,
-                     gmx::ArrayRef<const int> gnx_com,
-                     int*                     index_com[],
-                     real                     dt,
-                     real                     t_pdb,
-                     rvec**                   x_pdb,
-                     matrix                   box_pdb,
-                     const gmx_output_env_t*  oenv)
-{
-    rvec*        x[2];  /* the coordinates to read */
-    rvec*        xa[2]; /* the coordinates to calculate displacements for */
-    rvec         com = { 0 };
-    real         t, t_prev = 0;
-    int          natoms, i, j, cur = 0, maxframes = 0;
-    t_trxstatus* status;
-#define prev (1 - cur)
-    matrix      box;
-    gmx_bool    bFirst;
-    gmx_rmpbc_t gpbc = nullptr;
-
-    natoms = read_first_x(oenv, &status, fn, &curr->t0, &(x[cur]), box);
-#ifdef DEBUG
-    fprintf(stderr, "Read %d atoms for first frame\n", natoms);
-#endif
-    if ((!gnx_com.empty()) && natoms < top->atoms.nr)
-    {
-        fprintf(stderr,
-                "WARNING: The trajectory only contains part of the system (%d of %d atoms) and "
-                "therefore the COM motion of only this part of the system will be removed\n",
-                natoms, top->atoms.nr);
-    }
-
-    snew(x[prev], natoms);
-
-    // if com is requested, the data structure needs to be large enough to do this
-    // to prevent overflow
-    if (bMol && gnx_com.empty())
-    {
-        curr->ncoords = curr->nmol;
-        snew(xa[0], curr->ncoords);
-        snew(xa[1], curr->ncoords);
-    }
-    else
-    {
-        curr->ncoords = natoms;
-        xa[0]         = x[0];
-        xa[1]         = x[1];
-    }
-
-    bFirst = TRUE;
-    t      = curr->t0;
-    if (x_pdb)
-    {
-        *x_pdb = nullptr;
-    }
-
-    if (bMol)
-    {
-        gpbc = gmx_rmpbc_init(&top->idef, pbcType, natoms);
-    }
-
-    /* the loop over all frames */
-    do
-    {
-        if (x_pdb
-            && ((bFirst && t_pdb < t)
-                || (!bFirst && t_pdb > t - 0.5 * (t - t_prev) && t_pdb < t + 0.5 * (t - t_prev))))
-        {
-            if (*x_pdb == nullptr)
-            {
-                snew(*x_pdb, natoms);
-            }
-            for (i = 0; i < natoms; i++)
-            {
-                copy_rvec(x[cur][i], (*x_pdb)[i]);
-            }
-            copy_mat(box, box_pdb);
-        }
-
-
-        /* check whether we've reached a restart point */
-        if (bRmod(t, curr->t0, dt))
-        {
-            curr->nrestart++;
-
-            curr->x0.resize(curr->nrestart);
-            curr->x0[curr->nrestart - 1].resize(curr->ncoords);
-            curr->com.resize(curr->nrestart);
-            curr->n_offs.resize(curr->nrestart);
-            srenew(curr->lsq, curr->nrestart);
-            snew(curr->lsq[curr->nrestart - 1], curr->nmol);
-            for (i = 0; i < curr->nmol; i++)
-            {
-                curr->lsq[curr->nrestart - 1][i] = gmx_stats_init();
-            }
-
-            if (debug)
-            {
-                fprintf(debug, "Extended data structures because of new restart %d\n", curr->nrestart);
-            }
-        }
-        /* create or extend the frame-based arrays */
-        if (curr->nframes >= maxframes - 1)
-        {
-            if (maxframes == 0)
-            {
-                for (i = 0; (i < curr->ngrp); i++)
-                {
-                    if (bTen)
-                    {
-                        curr->datam[i] = nullptr;
-                    }
-                }
-            }
-            maxframes += 10;
-            for (i = 0; (i < curr->ngrp); i++)
-            {
-                curr->ndata[i].resize(maxframes);
-                curr->data[i].resize(maxframes);
-                if (bTen)
-                {
-                    srenew(curr->datam[i], maxframes);
-                }
-                for (j = maxframes - 10; j < maxframes; j++)
-                {
-                    curr->ndata[i][j] = 0;
-                    curr->data[i][j]  = 0;
-                    if (bTen)
-                    {
-                        clear_mat(curr->datam[i][j]);
-                    }
-                }
-            }
-            curr->time.resize(maxframes);
-        }
-
-        /* set the time */
-        curr->time[curr->nframes] = t - curr->t0;
-
-        /* make the molecules whole */
-        if (bMol)
-        {
-            gmx_rmpbc(gpbc, natoms, box, x[cur]);
-        }
-
-        /* calculate the molecules' centers of masses and put them into xa */
-        // NOTE and WARNING! If above both COM removal and individual molecules have been
-        // requested, x and xa point to the same memory, and the coordinate
-        // data becomes overwritten by the molecule data.
-        if (bMol)
-        {
-            calc_mol_com(gnx[0], index[0], &top->mols, &top->atoms, x[cur], xa[cur]);
-        }
-
-        /* for the first frame, the previous frame is a copy of the first frame */
-        if (bFirst)
-        {
-            std::memcpy(xa[prev], xa[cur], curr->ncoords * sizeof(xa[prev][0]));
-            bFirst = FALSE;
-        }
-
-        /* first remove the periodic boundary condition crossings */
-        for (i = 0; i < curr->ngrp; i++)
-        {
-            prep_data(bMol, gnx[i], index[i], xa[cur], xa[prev], box);
-        }
-
-        /* calculate the center of mass */
-        if (!gnx_com.empty())
-        {
-            GMX_RELEASE_ASSERT(index_com != nullptr,
-                               "Center-of-mass removal must have valid index group");
-            calc_com(bMol, gnx_com[0], index_com[0], xa[cur], xa[prev], box, &top->atoms, com);
-        }
-
-        /* loop over all groups in index file */
-        for (i = 0; (i < curr->ngrp); i++)
-        {
-            /* calculate something useful, like mean square displacements */
-            calc_corr(curr, i, gnx[i], index[i], xa[cur], (!gnx_com.empty()), com, calc1, bTen);
-        }
-        cur    = prev;
-        t_prev = t;
-
-        curr->nframes++;
-    } while (read_next_x(oenv, status, &t, x[cur], box));
-    fprintf(stderr, "\nUsed %d restart points spaced %g %s over %g %s\n\n", curr->nrestart,
-            output_env_conv_time(oenv, dt), output_env_get_time_unit(oenv).c_str(),
-            output_env_conv_time(oenv, curr->time[curr->nframes - 1]),
-            output_env_get_time_unit(oenv).c_str());
-
-    if (bMol)
-    {
-        gmx_rmpbc_done(gpbc);
-    }
-
-    close_trx(status);
-
-    return natoms;
-}
-
-static void index_atom2mol(int* n, int* index, const t_block* mols)
-{
-    int nat, i, nmol, mol, j;
-
-    nat  = *n;
-    i    = 0;
-    nmol = 0;
-    mol  = 0;
-    while (i < nat)
-    {
-        while (index[i] > mols->index[mol])
-        {
-            mol++;
-            if (mol >= mols->nr)
-            {
-                gmx_fatal(FARGS, "Atom index out of range: %d", index[i] + 1);
-            }
-        }
-        for (j = mols->index[mol]; j < mols->index[mol + 1]; j++)
-        {
-            if (i >= nat || index[i] != j)
-            {
-                gmx_fatal(FARGS, "The index group does not consist of whole molecules");
-            }
-            i++;
-        }
-        index[nmol++] = mol;
-    }
-
-    fprintf(stderr, "Split group of %d atoms into %d molecules\n", nat, nmol);
-
-    *n = nmol;
-}
-
-static void do_corr(const char*             trx_file,
-                    const char*             ndx_file,
-                    const char*             msd_file,
-                    const char*             mol_file,
-                    const char*             pdb_file,
-                    real                    t_pdb,
-                    int                     nrgrp,
-                    t_topology*             top,
-                    PbcType                 pbcType,
-                    gmx_bool                bTen,
-                    gmx_bool                bMW,
-                    gmx_bool                bRmCOMM,
-                    int                     type,
-                    real                    dim_factor,
-                    int                     axis,
-                    real                    dt,
-                    real                    beginfit,
-                    real                    endfit,
-                    const gmx_output_env_t* oenv)
-{
-    std::unique_ptr<t_corr> msd;
-    std::vector<int>        gnx, gnx_com; /* the selected groups' sizes */
-    int**                   index;        /* selected groups' indices */
-    char**                  grpname;
-    int                     i, i0, i1, j, N, nat_trx;
-    std::vector<real>       SigmaD, DD;
-    real                    a, a2, b, r, chi2;
-    rvec*                   x = nullptr;
-    matrix                  box;
-    int**                   index_com   = nullptr; /* the COM removal group atom indices */
-    char**                  grpname_com = nullptr; /* the COM removal group name */
-
-    gnx.resize(nrgrp);
-    snew(index, nrgrp);
-    snew(grpname, nrgrp);
-
-    fprintf(stderr, "\nSelect a group to calculate mean squared displacement for:\n");
-    get_index(&top->atoms, ndx_file, nrgrp, gnx.data(), index, grpname);
-
-    if (bRmCOMM)
-    {
-        gnx_com.resize(1);
-        snew(index_com, 1);
-        snew(grpname_com, 1);
-
-        fprintf(stderr, "\nNow select a group for center of mass removal:\n");
-        get_index(&top->atoms, ndx_file, 1, gnx_com.data(), index_com, grpname_com);
-    }
-
-    if (mol_file)
-    {
-        index_atom2mol(&gnx[0], index[0], &top->mols);
-    }
-
-    msd = std::make_unique<t_corr>(nrgrp, type, axis, dim_factor, mol_file == nullptr ? 0 : gnx[0],
-                                   bTen, bMW, dt, top, beginfit, endfit);
-
-    nat_trx = corr_loop(msd.get(), trx_file, top, pbcType, mol_file ? gnx[0] != 0 : false, gnx.data(),
-                        index, (mol_file != nullptr) ? calc1_mol : (bMW ? calc1_mw : calc1_norm),
-                        bTen, gnx_com, index_com, dt, t_pdb, pdb_file ? &x : nullptr, box, oenv);
-
-    /* Correct for the number of points */
-    for (j = 0; (j < msd->ngrp); j++)
-    {
-        for (i = 0; (i < msd->nframes); i++)
-        {
-            msd->data[j][i] /= msd->ndata[j][i];
-            if (bTen)
-            {
-                msmul(msd->datam[j][i], 1.0 / msd->ndata[j][i], msd->datam[j][i]);
-            }
-        }
-    }
-
-    if (mol_file)
-    {
-        if (pdb_file && x == nullptr)
-        {
-            fprintf(stderr,
-                    "\nNo frame found need time tpdb = %g ps\n"
-                    "Can not write %s\n\n",
-                    t_pdb, pdb_file);
-        }
-        i             = top->atoms.nr;
-        top->atoms.nr = nat_trx;
-        if (pdb_file && top->atoms.pdbinfo == nullptr)
-        {
-            snew(top->atoms.pdbinfo, top->atoms.nr);
-        }
-        printmol(msd.get(), mol_file, pdb_file, index[0], top, x, pbcType, box, oenv);
-        top->atoms.nr = i;
-    }
-
-    if (beginfit == -1)
-    {
-        i0       = gmx::roundToInt(0.1 * (msd->nframes - 1));
-        beginfit = msd->time[i0];
-    }
-    else
-    {
-        for (i0 = 0; i0 < msd->nframes && msd->time[i0] < beginfit; i0++) {}
-    }
-
-    if (endfit == -1)
-    {
-        i1     = gmx::roundToInt(0.9 * (msd->nframes - 1)) + 1;
-        endfit = msd->time[i1 - 1];
-    }
-    else
-    {
-        for (i1 = i0; i1 < msd->nframes && msd->time[i1] <= endfit; i1++) {}
-    }
-    fprintf(stdout, "Fitting from %g to %g %s\n\n", beginfit, endfit,
-            output_env_get_time_unit(oenv).c_str());
-
-    N = i1 - i0;
-    if (N <= 2)
-    {
-        fprintf(stdout,
-                "Not enough points for fitting (%d).\n"
-                "Can not determine the diffusion constant.\n",
-                N);
-    }
-    else
-    {
-        DD.resize(msd->ngrp);
-        SigmaD.resize(msd->ngrp);
-        for (j = 0; j < msd->ngrp; j++)
-        {
-            if (N >= 4)
-            {
-                lsq_y_ax_b(N / 2, &(msd->time[i0]), &(msd->data[j][i0]), &a, &b, &r, &chi2);
-                lsq_y_ax_b(N / 2, &(msd->time[i0 + N / 2]), &(msd->data[j][i0 + N / 2]), &a2, &b, &r, &chi2);
-                SigmaD[j] = std::abs(a - a2);
-            }
-            else
-            {
-                SigmaD[j] = 0;
-            }
-            lsq_y_ax_b(N, &(msd->time[i0]), &(msd->data[j][i0]), &(DD[j]), &b, &r, &chi2);
-            DD[j] *= diffusionConversionFactor / msd->dim_factor;
-            SigmaD[j] *= diffusionConversionFactor / msd->dim_factor;
-            if (DD[j] > 0.01 && DD[j] < 1e4)
-            {
-                fprintf(stdout, "D[%10s] %.4f (+/- %.4f) 1e-5 cm^2/s\n", grpname[j], DD[j], SigmaD[j]);
-            }
-            else
-            {
-                fprintf(stdout, "D[%10s] %.4g (+/- %.4g) 1e-5 cm^2/s\n", grpname[j], DD[j], SigmaD[j]);
-            }
-        }
-    }
-    /* Print mean square displacement */
-    corr_print(msd.get(), bTen, msd_file, "Mean Square Displacement", "MSD (nm\\S2\\N)",
-               msd->time[msd->nframes - 1], beginfit, endfit, DD.data(), SigmaD.data(), grpname, oenv);
-}
-
-int gmx_msd(int argc, char* argv[])
-{
-    const char* desc[] = {
-        "[THISMODULE] computes the mean square displacement (MSD) of atoms from",
-        "a set of initial positions. This provides an easy way to compute",
-        "the diffusion constant using the Einstein relation.",
-        "The time between the reference points for the MSD calculation",
-        "is set with [TT]-trestart[tt].",
-        "The diffusion constant is calculated by least squares fitting a",
-        "straight line (D*t + c) through the MSD(t) from [TT]-beginfit[tt] to",
-        "[TT]-endfit[tt] (note that t is time from the reference positions,",
-        "not simulation time). An error estimate given, which is the difference",
-        "of the diffusion coefficients obtained from fits over the two halves",
-        "of the fit interval.[PAR]",
-        "There are three, mutually exclusive, options to determine different",
-        "types of mean square displacement: [TT]-type[tt], [TT]-lateral[tt]",
-        "and [TT]-ten[tt]. Option [TT]-ten[tt] writes the full MSD tensor for",
-        "each group, the order in the output is: trace xx yy zz yx zx zy.[PAR]",
-        "If [TT]-mol[tt] is set, [THISMODULE] plots the MSD for individual molecules",
-        "(including making molecules whole across periodic boundaries): ",
-        "for each individual molecule a diffusion constant is computed for ",
-        "its center of mass. The chosen index group will be split into ",
-        "molecules.[PAR]",
-        "The default way to calculate a MSD is by using mass-weighted averages.",
-        "This can be turned off with [TT]-nomw[tt].[PAR]",
-        "With the option [TT]-rmcomm[tt], the center of mass motion of a ",
-        "specific group can be removed. For trajectories produced with ",
-        "GROMACS this is usually not necessary, ",
-        "as [gmx-mdrun] usually already removes the center of mass motion.",
-        "When you use this option be sure that the whole system is stored",
-        "in the trajectory file.[PAR]",
-        "The diffusion coefficient is determined by linear regression of the MSD.",
-        "When [TT]-beginfit[tt] is -1, fitting starts at 10%",
-        "and when [TT]-endfit[tt] is -1, fitting goes to 90%.",
-        "Using this option one also gets an accurate error estimate",
-        "based on the statistics between individual molecules.",
-        "Note that this diffusion coefficient and error estimate are only",
-        "accurate when the MSD is completely linear between",
-        "[TT]-beginfit[tt] and [TT]-endfit[tt].[PAR]",
-        "Option [TT]-pdb[tt] writes a [REF].pdb[ref] file with the coordinates of the frame",
-        "at time [TT]-tpdb[tt] with in the B-factor field the square root of",
-        "the diffusion coefficient of the molecule.",
-        "This option implies option [TT]-mol[tt]."
-    };
-    static const char* normtype[] = { nullptr, "no", "x", "y", "z", nullptr };
-    static const char* axtitle[]  = { nullptr, "no", "x", "y", "z", nullptr };
-    static int         ngroup     = 1;
-    static real        dt         = 10;
-    static real        t_pdb      = 0;
-    static real        beginfit   = -1;
-    static real        endfit     = -1;
-    static gmx_bool    bTen       = FALSE;
-    static gmx_bool    bMW        = TRUE;
-    static gmx_bool    bRmCOMM    = FALSE;
-    t_pargs            pa[]       = {
-        { "-type", FALSE, etENUM, { normtype }, "Compute diffusion coefficient in one direction" },
-        { "-lateral",
-          FALSE,
-          etENUM,
-          { axtitle },
-          "Calculate the lateral diffusion in a plane perpendicular to" },
-        { "-ten", FALSE, etBOOL, { &bTen }, "Calculate the full tensor" },
-        { "-ngroup", FALSE, etINT, { &ngroup }, "Number of groups to calculate MSD for" },
-        { "-mw", FALSE, etBOOL, { &bMW }, "Mass weighted MSD" },
-        { "-rmcomm", FALSE, etBOOL, { &bRmCOMM }, "Remove center of mass motion" },
-        { "-tpdb", FALSE, etTIME, { &t_pdb }, "The frame to use for option [TT]-pdb[tt] (%t)" },
-        { "-trestart", FALSE, etTIME, { &dt }, "Time between restarting points in trajectory (%t)" },
-        { "-beginfit",
-          FALSE,
-          etTIME,
-          { &beginfit },
-          "Start time for fitting the MSD (%t), -1 is 10%" },
-        { "-endfit", FALSE, etTIME, { &endfit }, "End time for fitting the MSD (%t), -1 is 90%" }
-    };
-
-    t_filenm fnm[] = {
-        { efTRX, nullptr, nullptr, ffREAD },    { efTPS, nullptr, nullptr, ffREAD },
-        { efNDX, nullptr, nullptr, ffOPTRD },   { efXVG, nullptr, "msd", ffWRITE },
-        { efXVG, "-mol", "diff_mol", ffOPTWR }, { efPDB, "-pdb", "diff_mol", ffOPTWR }
-    };
-#define NFILE asize(fnm)
-
-    t_topology        top;
-    PbcType           pbcType;
-    matrix            box;
-    const char *      trx_file, *tps_file, *ndx_file, *msd_file, *mol_file, *pdb_file;
-    rvec*             xdum;
-    gmx_bool          bTop;
-    int               axis, type;
-    real              dim_factor;
-    gmx_output_env_t* oenv;
-
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END | PCA_TIME_UNIT,
-                           NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
-    {
-        return 0;
-    }
-    trx_file = ftp2fn_null(efTRX, NFILE, fnm);
-    tps_file = ftp2fn_null(efTPS, NFILE, fnm);
-    ndx_file = ftp2fn_null(efNDX, NFILE, fnm);
-    msd_file = ftp2fn_null(efXVG, NFILE, fnm);
-    pdb_file = opt2fn_null("-pdb", NFILE, fnm);
-    if (pdb_file)
-    {
-        mol_file = opt2fn("-mol", NFILE, fnm);
-    }
-    else
-    {
-        mol_file = opt2fn_null("-mol", NFILE, fnm);
-    }
-
-    if (ngroup < 1)
-    {
-        gmx_fatal(FARGS, "Must have at least 1 group (now %d)", ngroup);
-    }
-    if (mol_file && ngroup > 1)
-    {
-        gmx_fatal(FARGS, "With molecular msd can only have 1 group (now %d)", ngroup);
-    }
-
-
-    if (mol_file)
-    {
-        bMW = TRUE;
-        fprintf(stderr, "Calculating diffusion coefficients for molecules.\n");
-    }
-
-    GMX_RELEASE_ASSERT(normtype[0] != nullptr, "Options inconsistency; normtype[0] is NULL");
-    GMX_RELEASE_ASSERT(axtitle[0] != nullptr, "Options inconsistency; axtitle[0] is NULL");
-
-    if (normtype[0][0] != 'n')
-    {
-        type       = normtype[0][0] - 'x' + X; /* See defines above */
-        dim_factor = 2.0;
-    }
-    else
-    {
-        type       = NORMAL;
-        dim_factor = 6.0;
-    }
-    if ((type == NORMAL) && (axtitle[0][0] != 'n'))
-    {
-        type       = LATERAL;
-        dim_factor = 4.0;
-        axis       = (axtitle[0][0] - 'x'); /* See defines above */
-    }
-    else
-    {
-        axis = 0;
-    }
-
-    if (bTen && type != NORMAL)
-    {
-        gmx_fatal(FARGS, "Can only calculate the full tensor for 3D msd");
-    }
-
-    bTop = read_tps_conf(tps_file, &top, &pbcType, &xdum, nullptr, box, bMW || bRmCOMM);
-    if (mol_file && !bTop)
-    {
-        gmx_fatal(FARGS, "Could not read a topology from %s. Try a tpr file instead.", tps_file);
-    }
-
-    do_corr(trx_file, ndx_file, msd_file, mol_file, pdb_file, t_pdb, ngroup, &top, pbcType, bTen,
-            bMW, bRmCOMM, type, dim_factor, axis, dt, beginfit, endfit, oenv);
-
-    done_top(&top);
-    view_all(oenv, NFILE, fnm);
-
-    return 0;
-}
index 2df043607d1114c8829400a4519bfae9da0de0cd..8d31e789275ed3ec1be783e741e4c9417afbdd23 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 static double cv_corr(double nu, double T)
 {
-    double x  = PLANCK * nu / (BOLTZ * T);
+    double x  = gmx::c_planck * nu / (gmx::c_boltz * T);
     double ex = std::exp(x);
 
     if (nu <= 0)
     {
-        return BOLTZ * KILO;
+        return gmx::c_boltz * gmx::c_kilo;
     }
     else
     {
-        return BOLTZ * KILO * (ex * gmx::square(x) / gmx::square(ex - 1) - 1);
+        return gmx::c_boltz * gmx::c_kilo * (ex * gmx::square(x) / gmx::square(ex - 1) - 1);
     }
 }
 
 static double u_corr(double nu, double T)
 {
-    double x  = PLANCK * nu / (BOLTZ * T);
+    double x  = gmx::c_planck * nu / (gmx::c_boltz * T);
     double ex = std::exp(x);
 
     if (nu <= 0)
     {
-        return BOLTZ * T;
+        return gmx::c_boltz * T;
     }
     else
     {
-        return BOLTZ * T * (0.5 * x - 1 + x / (ex - 1));
+        return gmx::c_boltz * T * (0.5 * x - 1 + x / (ex - 1));
     }
 }
 
@@ -271,7 +271,10 @@ static real* allocateEigenvectors(int nrow, int first, int last, bool ignoreBegi
         gmx_fatal(FARGS,
                   "You asked to store %d eigenvectors of size %d, which requires more than the "
                   "supported %d elements; %sdecrease -last",
-                  numVector, nrow, INT_MAX, ignoreBegin ? "" : "increase -first and/or ");
+                  numVector,
+                  nrow,
+                  INT_MAX,
+                  ignoreBegin ? "" : "increase -first and/or ");
     }
 
     real* eigenvectors;
@@ -284,14 +287,14 @@ static real* allocateEigenvectors(int nrow, int first, int last, bool ignoreBegi
  */
 static double calcTranslationalHeatCapacity()
 {
-    return RGAS * 1.5;
+    return gmx::c_universalGasConstant * 1.5;
 }
 
 /*! \brief Compute internal energy due to translational motion
  */
 static double calcTranslationalInternalEnergy(double T)
 {
-    return BOLTZ * T * 1.5;
+    return gmx::c_boltz * T * 1.5;
 }
 
 /*! \brief Compute heat capacity due to rotational motion
@@ -304,11 +307,11 @@ static double calcRotationalInternalEnergy(gmx_bool linear, double T)
 {
     if (linear)
     {
-        return BOLTZ * T;
+        return gmx::c_boltz * T;
     }
     else
     {
-        return BOLTZ * T * 1.5;
+        return gmx::c_boltz * T * 1.5;
     }
 }
 
@@ -321,11 +324,11 @@ static double calcRotationalHeatCapacity(gmx_bool linear)
 {
     if (linear)
     {
-        return RGAS;
+        return gmx::c_universalGasConstant;
     }
     else
     {
-        return RGAS * 1.5;
+        return gmx::c_universalGasConstant * 1.5;
     }
 }
 
@@ -358,9 +361,9 @@ static void analyzeThermochemistry(FILE*                    fp,
     principal_comp(index.size(), index.data(), top.atoms.atom, as_rvec_array(x_com.data()), trans, inertia);
     bool linear = (inertia[XX] / inertia[YY] < linear_toler && inertia[XX] / inertia[ZZ] < linear_toler);
     // (kJ/mol ps)^2/(Dalton nm^2 kJ/mol K) =
-    // KILO kg m^2 ps^2/(s^2 mol g/mol nm^2 K) =
-    // KILO^2 10^18 / 10^24 K = 1/K
-    double rot_const = gmx::square(PLANCK) / (8 * gmx::square(M_PI) * BOLTZ);
+    // c_kilo kg m^2 ps^2/(s^2 mol g/mol nm^2 K) =
+    // c_kilo^2 10^18 / 10^24 K = 1/K
+    double rot_const = gmx::square(gmx::c_planck) / (8 * gmx::square(M_PI) * gmx::c_boltz);
     // Rotational temperature (1/K)
     rvec theta = { 0, 0, 0 };
     if (linear)
@@ -542,7 +545,7 @@ int gmx_nmeig(int argc, char* argv[])
     {
         nharm = get_nharm(&mtop);
     }
-    std::vector<int> atom_index = get_atom_index(&mtop);
+    std::vector<int> atom_index = get_atom_index(mtop);
 
     top = gmx_mtop_t_to_t_topology(&mtop, true);
 
@@ -589,7 +592,9 @@ int gmx_nmeig(int argc, char* argv[])
             gmx_fatal(FARGS,
                       "Hessian size is %d x %d, which is larger than the maximum allowed %d "
                       "elements.",
-                      nrow, ncol, INT_MAX);
+                      nrow,
+                      ncol,
+                      INT_MAX);
         }
         snew(full_hessian, hessianSize);
         for (i = 0; i < nrow * ncol; i++)
@@ -648,8 +653,11 @@ int gmx_nmeig(int argc, char* argv[])
 
     /* now write the output */
     fprintf(stderr, "Writing eigenvalues...\n");
-    out = xvgropen(opt2fn("-ol", NFILE, fnm), "Eigenvalues", "Eigenvalue index",
-                   "Eigenvalue [Gromacs units]", oenv);
+    out = xvgropen(opt2fn("-ol", NFILE, fnm),
+                   "Eigenvalues",
+                   "Eigenvalue index",
+                   "Eigenvalue [Gromacs units]",
+                   oenv);
     if (output_env_get_print_xvgr_codes(oenv))
     {
         if (bM)
@@ -681,8 +689,11 @@ int gmx_nmeig(int argc, char* argv[])
     }
     printf("Writing eigenfrequencies - negative eigenvalues will be set to zero.\n");
 
-    out = xvgropen(opt2fn("-of", NFILE, fnm), "Eigenfrequencies", "Eigenvector index",
-                   "Wavenumber [cm\\S-1\\N]", oenv);
+    out = xvgropen(opt2fn("-of", NFILE, fnm),
+                   "Eigenfrequencies",
+                   "Eigenvector index",
+                   "Wavenumber [cm\\S-1\\N]",
+                   oenv);
     if (output_env_get_print_xvgr_codes(oenv))
     {
         if (bM)
@@ -701,7 +712,9 @@ int gmx_nmeig(int argc, char* argv[])
         snew(spectrum, maxspec);
         spec = xvgropen(opt2fn("-os", NFILE, fnm),
                         "Vibrational spectrum based on harmonic approximation",
-                        "\\f{12}w\\f{4} (cm\\S-1\\N)", "Intensity [Gromacs units]", oenv);
+                        "\\f{12}w\\f{4} (cm\\S-1\\N)",
+                        "Intensity [Gromacs units]",
+                        oenv);
         for (i = 0; (i < maxspec); i++)
         {
             spectrum[i] = 0;
@@ -716,8 +729,8 @@ int gmx_nmeig(int argc, char* argv[])
      * light. Do this by first converting to omega^2 (units 1/s), take the square
      * root, and finally divide by the speed of light (nm/ps in gromacs).
      */
-    factor_gmx_to_omega2       = 1.0E21 / (AVOGADRO * AMU);
-    factor_omega_to_wavenumber = 1.0E-5 / (2.0 * M_PI * SPEED_OF_LIGHT);
+    factor_gmx_to_omega2       = 1.0E21 / (gmx::c_avogadro * gmx::c_amu);
+    factor_omega_to_wavenumber = 1.0E-5 / (2.0 * M_PI * gmx::c_speedOfLight);
 
     value = 0;
     for (i = begin; (i <= end); i++)
@@ -745,8 +758,8 @@ int gmx_nmeig(int argc, char* argv[])
             qu  = u_corr(nu, T);
             if (i > end - nharm)
             {
-                qcv += BOLTZ * KILO;
-                qu += BOLTZ * T;
+                qcv += gmx::c_boltz * gmx::c_kilo;
+                qu += gmx::c_boltz * T;
             }
             fprintf(qc, "%6d %15g %15g\n", i, qcv, qu);
             qcvtot += qcv;
@@ -793,13 +806,23 @@ int gmx_nmeig(int argc, char* argv[])
         /* The sparse matrix diagonalization store all eigenvectors up to end */
         eigenvectorPtr = eigenvectors + (begin - 1) * atom_index.size();
     }
-    write_eigenvectors(opt2fn("-v", NFILE, fnm), atom_index.size(), eigenvectorPtr, FALSE, begin,
-                       end, eWXR_NO, nullptr, FALSE, top_x, bM, eigenvalues);
+    write_eigenvectors(opt2fn("-v", NFILE, fnm),
+                       atom_index.size(),
+                       eigenvectorPtr,
+                       FALSE,
+                       begin,
+                       end,
+                       eWXR_NO,
+                       nullptr,
+                       FALSE,
+                       top_x,
+                       bM,
+                       eigenvalues);
 
     if (begin == 1)
     {
-        analyzeThermochemistry(stdout, top, top_x, atom_index, eigenvalues, T, P, sigma_r,
-                               scale_factor, linear_toler);
+        analyzeThermochemistry(
+                stdout, top, top_x, atom_index, eigenvalues, T, P, sigma_r, scale_factor, linear_toler);
         please_cite(stdout, "Spoel2018a");
     }
     else
index 78859917b490e235375a61b168d584d730a4ebef..63ae3e5226752c437bdfefd24c92f957af232da2 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -120,8 +120,8 @@ int gmx_nmens(int argc, char* argv[])
 
     indexfile = ftp2fn_null(efNDX, NFILE, fnm);
 
-    read_eigenvectors(opt2fn("-v", NFILE, fnm), &natoms, &bFit, &xref, &bDMR, &xav, &bDMA, &nvec,
-                      &eignr, &eigvec, &eigval);
+    read_eigenvectors(
+            opt2fn("-v", NFILE, fnm), &natoms, &bFit, &xref, &bDMR, &xav, &bDMA, &nvec, &eignr, &eigvec, &eigval);
 
     read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &pbcType, &xtop, nullptr, box, bDMA);
     atoms = &top.atoms;
@@ -232,7 +232,7 @@ int gmx_nmens(int argc, char* argv[])
             /* (r-0.5) n times:  var_n = n * var_1 = n/12
                n=4:  var_n = 1/3, so multiply with 3 */
 
-            rfac  = std::sqrt(3.0 * BOLTZ * temp / eigval[iout[j]]);
+            rfac  = std::sqrt(3.0 * gmx::c_boltz * temp / eigval[iout[j]]);
             rhalf = 2.0 * rfac;
             rfac  = rfac / im;
 
index 8d597542cd9af214a854ffd4ee2b8bde7843f4cc..3b742e9110dca1ebd144912e1d903672069122f8 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -73,7 +73,7 @@
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/strconvert.h"
 
-static real minthird = -1.0 / 3.0, minsixth = -1.0 / 6.0;
+static constexpr real minthird = -1.0 / 3.0, minsixth = -1.0 / 6.0;
 
 static double mypow(double x, double y)
 {
@@ -90,11 +90,11 @@ static double mypow(double x, double y)
 static real blk_value(t_enxblock* blk, int sub, int index)
 {
     range_check(index, 0, blk->sub[sub].nr);
-    if (blk->sub[sub].type == xdr_datatype_float)
+    if (blk->sub[sub].type == XdrDataType::Float)
     {
         return blk->sub[sub].fval[index];
     }
-    else if (blk->sub[sub].type == xdr_datatype_double)
+    else if (blk->sub[sub].type == XdrDataType::Double)
     {
         return blk->sub[sub].dval[index];
     }
@@ -446,8 +446,8 @@ int gmx_nmr(int argc, char* argv[])
     int npargs;
 
     npargs = asize(pa);
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END, NFILE, fnm,
-                           npargs, pa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END, NFILE, fnm, npargs, pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -557,8 +557,8 @@ int gmx_nmr(int argc, char* argv[])
                 }
                 if (bORT)
                 {
-                    fort = xvgropen(opt2fn("-ort", NFILE, fnm), "Calculated orientations",
-                                    "Time (ps)", "", oenv);
+                    fort = xvgropen(
+                            opt2fn("-ort", NFILE, fnm), "Calculated orientations", "Time (ps)", "", oenv);
                     if (bOrinst && output_env_get_print_xvgr_codes(oenv))
                     {
                         fprintf(fort, "%s", orinst_sub);
@@ -567,8 +567,11 @@ int gmx_nmr(int argc, char* argv[])
                 }
                 if (bODT)
                 {
-                    fodt = xvgropen(opt2fn("-odt", NFILE, fnm), "Orientation restraint deviation",
-                                    "Time (ps)", "", oenv);
+                    fodt = xvgropen(opt2fn("-odt", NFILE, fnm),
+                                    "Orientation restraint deviation",
+                                    "Time (ps)",
+                                    "",
+                                    oenv);
                     if (bOrinst && output_env_get_print_xvgr_codes(oenv))
                     {
                         fprintf(fodt, "%s", orinst_sub);
@@ -615,7 +618,8 @@ int gmx_nmr(int argc, char* argv[])
         {
             topInfo.fillFromInputFile(ftp2fn(efTPR, NFILE, fnm));
             top = std::make_unique<gmx_localtop_t>(topInfo.mtop()->ffparams);
-            gmx_mtop_generate_local_top(*topInfo.mtop(), top.get(), ir->efep != efepNO);
+            gmx_mtop_generate_local_top(
+                    *topInfo.mtop(), top.get(), ir->efep != FreeEnergyPerturbationType::No);
         }
         nbounds = get_bounds(&bounds, &index, &pair, &npairs, top->idef);
         snew(violaver, npairs);
@@ -623,8 +627,8 @@ int gmx_nmr(int argc, char* argv[])
         xvgr_legend(out_disre, 2, drleg, oenv);
         if (bDRAll)
         {
-            fp_pairs = xvgropen(opt2fn("-pairs", NFILE, fnm), "Pair Distances", "Time (ps)",
-                                "Distance (nm)", oenv);
+            fp_pairs = xvgropen(
+                    opt2fn("-pairs", NFILE, fnm), "Pair Distances", "Time (ps)", "Distance (nm)", oenv);
             if (output_env_get_print_xvgr_codes(oenv))
             {
                 fprintf(fp_pairs, "@ subtitle \"averaged (tau=%g) and instantaneous\"\n", ir->dr_tau);
@@ -672,7 +676,8 @@ int gmx_nmr(int argc, char* argv[])
                     gmx_fatal(FARGS,
                               "Number of disre pairs in the energy file (%d) does not match the "
                               "number in the run input file (%d)\n",
-                              ndisre, ilist.size() / 3);
+                              ndisre,
+                              ilist.size() / 3);
                 }
                 snew(pairleg, ndisre);
                 int molb = 0;
@@ -681,9 +686,15 @@ int gmx_nmr(int argc, char* argv[])
                     snew(pairleg[i], 30);
                     j = fa[3 * i + 1];
                     k = fa[3 * i + 2];
-                    mtopGetAtomAndResidueName(topInfo.mtop(), j, &molb, &anm_j, &resnr_j, &resnm_j, nullptr);
-                    mtopGetAtomAndResidueName(topInfo.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,
+                    GMX_ASSERT(topInfo.hasTopology(), "Need to have a valid topology");
+                    mtopGetAtomAndResidueName(*topInfo.mtop(), j, &molb, &anm_j, &resnr_j, &resnm_j, nullptr);
+                    mtopGetAtomAndResidueName(*topInfo.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);
                 }
                 set = select_it(ndisre, pairleg, &nset);
@@ -727,8 +738,8 @@ int gmx_nmr(int argc, char* argv[])
                         }
 
                         /* Subtract bounds from distances, to calculate violations */
-                        calc_violations(disre_rt, disre_rm3tav, nbounds, pair, bounds, violaver,
-                                        &sumt, &sumaver);
+                        calc_violations(
+                                disre_rt, disre_rm3tav, nbounds, pair, bounds, violaver, &sumt, &sumaver);
 
                         fprintf(out_disre, "  %8.4f  %8.4f\n", sumaver, sumt);
                         if (bDRAll)
@@ -764,7 +775,8 @@ int gmx_nmr(int argc, char* argv[])
                             gmx_fatal(FARGS,
                                       "Number of orientation restraints in energy file (%d) does "
                                       "not match with the topology (%d)",
-                                      blk->sub[0].nr, nor);
+                                      blk->sub[0].nr,
+                                      nor);
                         }
                         if (bORA || bODA)
                         {
@@ -814,7 +826,8 @@ int gmx_nmr(int argc, char* argv[])
                             gmx_fatal(FARGS,
                                       "Number of orientation experiments in energy file (%d) does "
                                       "not match with the topology (%d)",
-                                      blk->sub[0].nr / 12, nex);
+                                      blk->sub[0].nr / 12,
+                                      nex);
                         }
                         fprintf(foten, "  %10f", fr.t);
                         for (i = 0; i < nex; i++)
@@ -855,8 +868,8 @@ int gmx_nmr(int argc, char* argv[])
     }
     if (bORA)
     {
-        FILE* out = xvgropen(opt2fn("-ora", NFILE, fnm), "Average calculated orientations",
-                             "Restraint label", "", oenv);
+        FILE* out = xvgropen(
+                opt2fn("-ora", NFILE, fnm), "Average calculated orientations", "Restraint label", "", oenv);
         if (bOrinst && output_env_get_print_xvgr_codes(oenv))
         {
             fprintf(out, "%s", orinst_sub);
@@ -869,8 +882,8 @@ int gmx_nmr(int argc, char* argv[])
     }
     if (bODA)
     {
-        FILE* out = xvgropen(opt2fn("-oda", NFILE, fnm), "Average restraint deviation",
-                             "Restraint label", "", oenv);
+        FILE* out = xvgropen(
+                opt2fn("-oda", NFILE, fnm), "Average restraint deviation", "Restraint label", "", oenv);
         if (bOrinst && output_env_get_print_xvgr_codes(oenv))
         {
             fprintf(out, "%s", orinst_sub);
@@ -883,8 +896,11 @@ int gmx_nmr(int argc, char* argv[])
     }
     if (bODR)
     {
-        FILE* out = xvgropen(opt2fn("-odr", NFILE, fnm), "RMS orientation restraint deviations",
-                             "Restraint label", "", oenv);
+        FILE* out = xvgropen(opt2fn("-odr", NFILE, fnm),
+                             "RMS orientation restraint deviations",
+                             "Restraint label",
+                             "",
+                             oenv);
         if (bOrinst && output_env_get_print_xvgr_codes(oenv))
         {
             fprintf(out, "%s", orinst_sub);
@@ -908,8 +924,7 @@ int gmx_nmr(int argc, char* argv[])
 
     if (bDisRe)
     {
-        analyse_disre(opt2fn("-viol", NFILE, fnm), teller_disre, violaver, bounds, index, pair,
-                      nbounds, oenv);
+        analyse_disre(opt2fn("-viol", NFILE, fnm), teller_disre, violaver, bounds, index, pair, nbounds, oenv);
     }
     {
         const char* nxy = "-nxy";
index c752308e9217b59df0f8758f17a159e64e6db284..1ee9de463eee51e1ec69f6aa649077cdb63830e4 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,2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -127,8 +127,8 @@ int gmx_nmtraj(int argc, char* argv[])
         return 0;
     }
 
-    read_eigenvectors(opt2fn("-v", NFILE, fnm), &natoms, &bFit, &xref, &bDMR, &xav, &bDMA, &nvec,
-                      &eignr, &eigvec, &eigval);
+    read_eigenvectors(
+            opt2fn("-v", NFILE, fnm), &natoms, &bFit, &xref, &bDMR, &xav, &bDMA, &nvec, &eignr, &eigvec, &eigval);
 
     read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &pbcType, &xtop, nullptr, box, bDMA);
 
@@ -231,7 +231,7 @@ int gmx_nmtraj(int argc, char* argv[])
             /* Derive amplitude from temperature and eigenvalue if we can */
 
             /* Convert eigenvalue to angular frequency, in units s^(-1) */
-            omega = std::sqrt(eigval[kmode] * 1.0E21 / (AVOGADRO * AMU));
+            omega = std::sqrt(eigval[kmode] * 1.0E21 / (gmx::c_avogadro * gmx::c_amu));
             /* Harmonic motion will be x=x0 + A*sin(omega*t)*eigenvec.
              * The velocity is thus:
              *
@@ -261,10 +261,10 @@ int gmx_nmtraj(int argc, char* argv[])
             /* Convert Ekin from amu*(nm/s)^2 to J, i.e., kg*(m/s)^2
              * This will also be proportional to A^2
              */
-            Ekin *= AMU * 1E-18;
+            Ekin *= gmx::c_amu * 1E-18;
 
             /* Set the amplitude so the energy is kT/2 */
-            amplitude[i] = std::sqrt(0.5 * BOLTZMANN * temp / Ekin);
+            amplitude[i] = std::sqrt(0.5 * gmx::c_boltzmann * temp / Ekin);
         }
         else
         {
index aa97af5f97d8b4a63cc17e1f475a8eef32838a6b..f0e0857ccd9b0f497ad0f0548b7ab986d361818b 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,7 @@
 #include "gromacs/gmxana/gmx_ana.h"
 #include "gromacs/gmxana/gstat.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/pbc.h"
@@ -328,8 +329,8 @@ static void calc_tetra_order_parm(const char*             fnNDX,
     nframes = 0;
     do
     {
-        find_nearest_neighbours(pbcType, natoms, box, x, isize[0], index[0], &sg, &sk, nslice,
-                                slice_dim, sg_slice, sk_slice, gpbc);
+        find_nearest_neighbours(
+                pbcType, natoms, box, x, isize[0], index[0], &sg, &sk, nslice, slice_dim, sg_slice, sk_slice, gpbc);
         for (i = 0; (i < nslice); i++)
         {
             sg_slice_tot[i] += sg_slice[i];
@@ -353,9 +354,13 @@ static void calc_tetra_order_parm(const char*             fnNDX,
     fpsk = xvgropen(skslfn, "S\\sk\\N Distance Order Parameter / Slab", "(nm)", "S\\sk\\N", oenv);
     for (i = 0; (i < nslice); i++)
     {
-        fprintf(fpsg, "%10g  %10g\n", (i + 0.5) * box[slice_dim][slice_dim] / nslice,
+        fprintf(fpsg,
+                "%10g  %10g\n",
+                (i + 0.5) * box[slice_dim][slice_dim] / nslice,
                 sg_slice_tot[i] / static_cast<real>(nframes));
-        fprintf(fpsk, "%10g  %10g\n", (i + 0.5) * box[slice_dim][slice_dim] / nslice,
+        fprintf(fpsk,
+                "%10g  %10g\n",
+                (i + 0.5) * box[slice_dim][slice_dim] / nslice,
                 sk_slice_tot[i] / static_cast<real>(nframes));
     }
     xvgrclose(fpsg);
@@ -371,8 +376,11 @@ static void print_types(const int index[], int a[], int ngrps, char* groups[], c
     fprintf(stderr, "Using following groups: \n");
     for (i = 0; i < ngrps; i++)
     {
-        fprintf(stderr, "Groupname: %s First atomname: %s First atomnr %d\n", groups[i],
-                *(top->atoms.atomname[a[index[i]]]), a[index[i]]);
+        fprintf(stderr,
+                "Groupname: %s First atomname: %s First atomnr %d\n",
+                groups[i],
+                *(top->atoms.atomname[a[index[i]]]),
+                a[index[i]]);
     }
     fprintf(stderr, "\n");
 }
@@ -384,7 +392,9 @@ static void check_length(real length, int a, int b)
         fprintf(stderr,
                 "WARNING: distance between atoms %d and "
                 "%d > 0.3 nm (%f). Index file might be corrupt.\n",
-                a, b, length);
+                a,
+                b,
+                length);
     }
 }
 
@@ -746,7 +756,11 @@ static void calc_order(const char*             fn,
     for (i = 1; i < ngrps - 1; i++)
     {
         svmul(1.0 / nr_frames, (*order)[i], (*order)[i]);
-        fprintf(stderr, "Atom %d Tensor: x=%g , y=%g, z=%g\n", i, (*order)[i][XX], (*order)[i][YY],
+        fprintf(stderr,
+                "Atom %d Tensor: x=%g , y=%g, z=%g\n",
+                i,
+                (*order)[i][XX],
+                (*order)[i][YY],
                 (*order)[i][ZZ]);
         if (bSliced || permolecule)
         {
@@ -766,7 +780,8 @@ static void calc_order(const char*             fn,
 
     if (bUnsat)
     {
-        fprintf(stderr, "Average angle between double bond and normal: %f\n",
+        fprintf(stderr,
+                "Average angle between double bond and normal: %f\n",
                 180 * sdbangle / (nr_frames * static_cast<real>(size) * M_PI));
     }
 
@@ -813,7 +828,9 @@ static void order_plot(rvec                    order[],
         slOrd = xvgropen(bfile, buf, "Molecule", "S", oenv);
         for (atom = 1; atom < ngrps - 1; atom++)
         {
-            fprintf(ord, "%12d   %12g\n", atom,
+            fprintf(ord,
+                    "%12d   %12g\n",
+                    atom,
                     -1.0 * (2.0 / 3.0 * order[atom][XX] + 1.0 / 3.0 * order[atom][YY]));
         }
 
@@ -852,8 +869,7 @@ static void order_plot(rvec                    order[],
             {
                 S += slOrder[slice][atom];
             }
-            fprintf(slOrd, "%12g     %12g\n", static_cast<real>(slice) * slWidth,
-                    S / static_cast<real>(atom));
+            fprintf(slOrd, "%12g     %12g\n", static_cast<real>(slice) * slWidth, S / static_cast<real>(atom));
         }
     }
     else
@@ -865,9 +881,10 @@ static void order_plot(rvec                    order[],
 
         for (atom = 1; atom < ngrps - 1; atom++)
         {
-            fprintf(ord, "%12d   %12g   %12g   %12g\n", atom, order[atom][XX], order[atom][YY],
-                    order[atom][ZZ]);
-            fprintf(slOrd, "%12d   %12g\n", atom,
+            fprintf(ord, "%12d   %12g   %12g   %12g\n", atom, order[atom][XX], order[atom][YY], order[atom][ZZ]);
+            fprintf(slOrd,
+                    "%12d   %12g\n",
+                    atom,
                     -1.0 * (2.0 / 3.0 * order[atom][XX] + 1.0 / 3.0 * order[atom][YY]));
         }
     }
@@ -912,7 +929,7 @@ static void write_bfactors(t_filenm*         fnm,
     /*initialize PDBinfo*/
     for (i = 0; i < useatoms.nr; ++i)
     {
-        useatoms.pdbinfo[i].type         = 0;
+        useatoms.pdbinfo[i].type         = PdbRecordType::Atom;
         useatoms.pdbinfo[i].occup        = 0.0;
         useatoms.pdbinfo[i].bfac         = 0.0;
         useatoms.pdbinfo[i].bAnisotropic = FALSE;
@@ -937,8 +954,8 @@ static void write_bfactors(t_filenm*         fnm,
         }
     }
 
-    write_sto_conf(opt2fn("-ob", nfile, fnm), "Order parameters", &useatoms, frout.x, nullptr,
-                   frout.pbcType, frout.box);
+    write_sto_conf(
+            opt2fn("-ob", nfile, fnm), "Order parameters", &useatoms, frout.x, nullptr, frout.pbcType, frout.box);
 
     sfree(frout.x);
     done_atom(&useatoms);
@@ -1034,8 +1051,8 @@ int gmx_order(int argc, char* argv[])
     const char *      sgfnm, *skfnm, *ndxfnm, *tpsfnm, *trxfnm;
     gmx_output_env_t* oenv;
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -1081,8 +1098,16 @@ int gmx_order(int argc, char* argv[])
         /* If either of theoptions is set we compute both */
         sgfnm = opt2fn("-Sg", NFILE, fnm);
         skfnm = opt2fn("-Sk", NFILE, fnm);
-        calc_tetra_order_parm(ndxfnm, tpsfnm, trxfnm, sgfnm, skfnm, nslices, axis,
-                              opt2fn("-Sgsl", NFILE, fnm), opt2fn("-Sksl", NFILE, fnm), oenv);
+        calc_tetra_order_parm(ndxfnm,
+                              tpsfnm,
+                              trxfnm,
+                              sgfnm,
+                              skfnm,
+                              nslices,
+                              axis,
+                              opt2fn("-Sgsl", NFILE, fnm),
+                              opt2fn("-Sksl", NFILE, fnm),
+                              oenv);
         /* view xvgr files */
         do_view(oenv, opt2fn("-Sg", NFILE, fnm), nullptr);
         do_view(oenv, opt2fn("-Sk", NFILE, fnm), nullptr);
@@ -1136,18 +1161,43 @@ int gmx_order(int argc, char* argv[])
         /* show atomtypes, to check if index file is correct */
         print_types(index, a, ngrps, grpname, top);
 
-        calc_order(ftp2fn(efTRX, NFILE, fnm), index, a, &order, &slOrder, &slWidth, nslices,
-                   bSliced, bUnsat, top, pbcType, ngrps, axis, permolecule, radial, distcalc,
-                   opt2fn_null("-nr", NFILE, fnm), &distvals, oenv);
+        calc_order(ftp2fn(efTRX, NFILE, fnm),
+                   index,
+                   a,
+                   &order,
+                   &slOrder,
+                   &slWidth,
+                   nslices,
+                   bSliced,
+                   bUnsat,
+                   top,
+                   pbcType,
+                   ngrps,
+                   axis,
+                   permolecule,
+                   radial,
+                   distcalc,
+                   opt2fn_null("-nr", NFILE, fnm),
+                   &distvals,
+                   oenv);
 
         if (radial)
         {
             ngrps--; /*don't print the last group--was used for
                                center-of-mass determination*/
         }
-        order_plot(order, slOrder, opt2fn("-o", NFILE, fnm), opt2fn("-os", NFILE, fnm),
-                   opt2fn("-od", NFILE, fnm), ngrps, nslices, slWidth, bSzonly, permolecule,
-                   distvals, oenv);
+        order_plot(order,
+                   slOrder,
+                   opt2fn("-o", NFILE, fnm),
+                   opt2fn("-os", NFILE, fnm),
+                   opt2fn("-od", NFILE, fnm),
+                   ngrps,
+                   nslices,
+                   slWidth,
+                   bSzonly,
+                   permolecule,
+                   distvals,
+                   oenv);
 
         if (opt2bSet("-ob", NFILE, fnm))
         {
index ee1cfe1af4e367e400a820bcde332bd361fc6ad9..c60fd3af615f72094998a9960a489ee99ae2fc9f 100644 (file)
@@ -170,8 +170,18 @@ int gmx_polystat(int argc, char* argv[])
     char **           legp, buf[STRLEN];
     gmx_rmpbc_t       gpbc = nullptr;
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm,
-                           asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(&argc,
+                           argv,
+                           PCA_CAN_VIEW | PCA_CAN_TIME | PCA_TIME_UNIT,
+                           NFILE,
+                           fnm,
+                           asize(pa),
+                           pa,
+                           asize(desc),
+                           desc,
+                           0,
+                           nullptr,
+                           &oenv))
     {
         return 0;
     }
@@ -213,8 +223,11 @@ int gmx_polystat(int argc, char* argv[])
 
     if (opt2bSet("-v", NFILE, fnm))
     {
-        outv = xvgropen(opt2fn("-v", NFILE, fnm), "Principal components",
-                        output_env_get_xvgr_tlabel(oenv), "(nm)", oenv);
+        outv = xvgropen(opt2fn("-v", NFILE, fnm),
+                        "Principal components",
+                        output_env_get_xvgr_tlabel(oenv),
+                        "(nm)",
+                        oenv);
         snew(legp, DIM * DIM);
         for (d = 0; d < DIM; d++)
         {
@@ -233,8 +246,11 @@ int gmx_polystat(int argc, char* argv[])
 
     if (opt2bSet("-p", NFILE, fnm))
     {
-        outp = xvgropen(opt2fn("-p", NFILE, fnm), "Persistence length",
-                        output_env_get_xvgr_tlabel(oenv), "bonds", oenv);
+        outp = xvgropen(opt2fn("-p", NFILE, fnm),
+                        "Persistence length",
+                        output_env_get_xvgr_tlabel(oenv),
+                        "bonds",
+                        oenv);
         snew(bond, nat_max - 1);
         snew(sum_inp, nat_min / 2);
         snew(ninp, nat_min / 2);
@@ -246,9 +262,9 @@ int gmx_polystat(int argc, char* argv[])
 
     if (opt2bSet("-i", NFILE, fnm))
     {
-        outi = xvgropen(opt2fn("-i", NFILE, fnm), "Internal distances", "n",
-                        "<R\\S2\\N(n)>/n (nm\\S2\\N)", oenv);
-        i    = index[molind[1] - 1] - index[molind[0]]; /* Length of polymer -1 */
+        outi = xvgropen(
+                opt2fn("-i", NFILE, fnm), "Internal distances", "n", "<R\\S2\\N(n)>/n (nm\\S2\\N)", oenv);
+        i = index[molind[1] - 1] - index[molind[0]]; /* Length of polymer -1 */
         snew(intd, i);
     }
     else
@@ -391,8 +407,13 @@ int gmx_polystat(int argc, char* argv[])
 
         gyro_eigen(gyr_all, eig, eigv, ord);
 
-        fprintf(out, "%10.3f %8.4f %8.4f %8.4f %8.4f %8.4f", t * output_env_get_time_factor(oenv),
-                std::sqrt(sum_eed2), sqrt(sum_gyro), std::sqrt(eig[ord[0]]), std::sqrt(eig[ord[1]]),
+        fprintf(out,
+                "%10.3f %8.4f %8.4f %8.4f %8.4f %8.4f",
+                t * output_env_get_time_factor(oenv),
+                std::sqrt(sum_eed2),
+                sqrt(sum_gyro),
+                std::sqrt(eig[ord[0]]),
+                std::sqrt(eig[ord[1]]),
                 std::sqrt(eig[ord[2]]));
         if (bPC)
         {
index fb417b0f8f5815b63625efa4faf85b129eb60c7e..8138ec4162f509fafdb8353dfd8937e3836354d6 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
 #include "gromacs/gmxana/gmx_ana.h"
 #include "gromacs/gmxana/princ.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/rmpbc.h"
 /* This probably sucks but it seems to work.                                */
 /****************************************************************************/
 
-static int ce = 0, cb = 0;
-
 /* this routine integrates the array data and returns the resulting array */
 /* routine uses simple trapezoid rule                                     */
-static void p_integrate(double* result, const double data[], int ndata, double slWidth)
+static void p_integrate(double* result, const double data[], int ndata, double slWidth, int cb, int ce)
 {
     int    i, slice;
     double sum;
@@ -116,6 +115,8 @@ static void calc_potential(const char*             fn,
                            double                  fudge_z,
                            gmx_bool                bSpherical,
                            gmx_bool                bCorrect,
+                           int                     cb,
+                           int                     ce,
                            const gmx_output_env_t* oenv)
 {
     rvec*        x0;     /* coordinates without pbc */
@@ -194,7 +195,8 @@ static void calc_potential(const char*             fn,
                 gmx_fatal(FARGS,
                           "You selected a group with %d atoms, but only %d atoms\n"
                           "were found in the trajectory.\n",
-                          gnx[n], natoms);
+                          gnx[n],
+                          natoms);
             }
             for (i = 0; i < gnx[n]; i++) /* loop over all atoms in index file */
             {
@@ -315,7 +317,7 @@ static void calc_potential(const char*             fn,
     for (n = 0; n < nr_grps; n++)
     {
         /* integrate twice to get field and potential */
-        p_integrate((*slField)[n], (*slCharge)[n], *nslices, *slWidth);
+        p_integrate((*slField)[n], (*slCharge)[n], *nslices, *slWidth, cb, ce);
     }
 
 
@@ -346,7 +348,7 @@ static void calc_potential(const char*             fn,
 
     for (n = 0; n < nr_grps; n++)
     {
-        p_integrate((*slPotential)[n], (*slField)[n], *nslices, *slWidth);
+        p_integrate((*slPotential)[n], (*slField)[n], *nslices, *slWidth, cb, ce);
     }
 
     /* Now correct for eps0 and in spherical case for r*/
@@ -380,6 +382,8 @@ static void plot_potential(double*                 potential[],
                            int                     nr_grps,
                            const char* const       grpname[],
                            double                  slWidth,
+                           int                     cb,
+                           int                     ce,
                            const gmx_output_env_t* oenv)
 {
     FILE *pot,     /* xvgr file with potential */
@@ -441,6 +445,8 @@ int gmx_potential(int argc, char* argv[])
     static gmx_bool    bSpherical = FALSE; /* default is bilayer types   */
     static real        fudge_z    = 0;     /* translate coordinates      */
     static gmx_bool    bCorrect   = false;
+    int                cb         = 0;
+    int                ce         = 0;
     t_pargs            pa[]       = {
         { "-d",
           FALSE,
@@ -499,8 +505,8 @@ int gmx_potential(int argc, char* argv[])
 
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, asize(bugs), bugs, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
         return 0;
     }
@@ -517,11 +523,38 @@ int gmx_potential(int argc, char* argv[])
     rd_index(ftp2fn(efNDX, NFILE, fnm), ngrps, ngx, index, grpname);
 
 
-    calc_potential(ftp2fn(efTRX, NFILE, fnm), index, ngx, &potential, &charge, &field, &nslices,
-                   top, pbcType, axis, ngrps, &slWidth, fudge_z, bSpherical, bCorrect, oenv);
-
-    plot_potential(potential, charge, field, opt2fn("-o", NFILE, fnm), opt2fn("-oc", NFILE, fnm),
-                   opt2fn("-of", NFILE, fnm), nslices, ngrps, grpname, slWidth, oenv);
+    calc_potential(ftp2fn(efTRX, NFILE, fnm),
+                   index,
+                   ngx,
+                   &potential,
+                   &charge,
+                   &field,
+                   &nslices,
+                   top,
+                   pbcType,
+                   axis,
+                   ngrps,
+                   &slWidth,
+                   fudge_z,
+                   bSpherical,
+                   bCorrect,
+                   cb,
+                   ce,
+                   oenv);
+
+    plot_potential(potential,
+                   charge,
+                   field,
+                   opt2fn("-o", NFILE, fnm),
+                   opt2fn("-oc", NFILE, fnm),
+                   opt2fn("-of", NFILE, fnm),
+                   nslices,
+                   ngrps,
+                   grpname,
+                   slWidth,
+                   cb,
+                   ce,
+                   oenv);
 
     do_view(oenv, opt2fn("-o", NFILE, fnm), nullptr);  /* view xvgr file */
     do_view(oenv, opt2fn("-oc", NFILE, fnm), nullptr); /* view xvgr file */
index 40092a218fa8188db069a20b35768dfa40d08d86..94376e129f73bfc8b4ed8ad908b38883ebc9d136 100644 (file)
@@ -104,8 +104,18 @@ int gmx_principal(int argc, char* argv[])
                        { efXVG, "-om", "moi", ffWRITE } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW, NFILE, fnm,
-                           asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(&argc,
+                           argv,
+                           PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW,
+                           NFILE,
+                           fnm,
+                           asize(pa),
+                           pa,
+                           asize(desc),
+                           desc,
+                           0,
+                           nullptr,
+                           &oenv))
     {
         return 0;
     }
@@ -117,24 +127,36 @@ int gmx_principal(int argc, char* argv[])
         sprintf(legend[i], "%c component", 'X' + i);
     }
 
-    axis1 = xvgropen(opt2fn("-a1", NFILE, fnm), "Principal axis 1 (major axis)",
-                     output_env_get_xvgr_tlabel(oenv), "Component (nm)", oenv);
+    axis1 = xvgropen(opt2fn("-a1", NFILE, fnm),
+                     "Principal axis 1 (major axis)",
+                     output_env_get_xvgr_tlabel(oenv),
+                     "Component (nm)",
+                     oenv);
     xvgr_legend(axis1, DIM, legend, oenv);
 
-    axis2 = xvgropen(opt2fn("-a2", NFILE, fnm), "Principal axis 2 (middle axis)",
-                     output_env_get_xvgr_tlabel(oenv), "Component (nm)", oenv);
+    axis2 = xvgropen(opt2fn("-a2", NFILE, fnm),
+                     "Principal axis 2 (middle axis)",
+                     output_env_get_xvgr_tlabel(oenv),
+                     "Component (nm)",
+                     oenv);
     xvgr_legend(axis2, DIM, legend, oenv);
 
-    axis3 = xvgropen(opt2fn("-a3", NFILE, fnm), "Principal axis 3 (minor axis)",
-                     output_env_get_xvgr_tlabel(oenv), "Component (nm)", oenv);
+    axis3 = xvgropen(opt2fn("-a3", NFILE, fnm),
+                     "Principal axis 3 (minor axis)",
+                     output_env_get_xvgr_tlabel(oenv),
+                     "Component (nm)",
+                     oenv);
     xvgr_legend(axis3, DIM, legend, oenv);
 
     sprintf(legend[XX], "Axis 1 (major)");
     sprintf(legend[YY], "Axis 2 (middle)");
     sprintf(legend[ZZ], "Axis 3 (minor)");
 
-    fmoi = xvgropen(opt2fn("-om", NFILE, fnm), "Moments of inertia around inertial axes",
-                    output_env_get_xvgr_tlabel(oenv), "I (au nm\\S2\\N)", oenv);
+    fmoi = xvgropen(opt2fn("-om", NFILE, fnm),
+                    "Moments of inertia around inertial axes",
+                    output_env_get_xvgr_tlabel(oenv),
+                    "I (au nm\\S2\\N)",
+                    oenv);
     xvgr_legend(fmoi, DIM, legend, oenv);
 
     for (i = 0; i < DIM; i++)
@@ -157,12 +179,9 @@ int gmx_principal(int argc, char* argv[])
 
         calc_principal_axes(&top, x, index, gnx, axes, moi);
 
-        fprintf(axis1, "%15.10f     %15.10f  %15.10f  %15.10f\n", t, axes[XX][XX], axes[XX][YY],
-                axes[XX][ZZ]);
-        fprintf(axis2, "%15.10f     %15.10f  %15.10f  %15.10f\n", t, axes[YY][XX], axes[YY][YY],
-                axes[YY][ZZ]);
-        fprintf(axis3, "%15.10f     %15.10f  %15.10f  %15.10f\n", t, axes[ZZ][XX], axes[ZZ][YY],
-                axes[ZZ][ZZ]);
+        fprintf(axis1, "%15.10f     %15.10f  %15.10f  %15.10f\n", t, axes[XX][XX], axes[XX][YY], axes[XX][ZZ]);
+        fprintf(axis2, "%15.10f     %15.10f  %15.10f  %15.10f\n", t, axes[YY][XX], axes[YY][YY], axes[YY][ZZ]);
+        fprintf(axis3, "%15.10f     %15.10f  %15.10f  %15.10f\n", t, axes[ZZ][XX], axes[ZZ][YY], axes[ZZ][ZZ]);
         fprintf(fmoi, "%15.10f     %15.10f  %15.10f  %15.10f\n", t, moi[XX], moi[YY], moi[ZZ]);
     } while (read_next_x(oenv, status, &t, x, box));
 
index f0646dabd08da529609be953cfc8eb1d5817d344..57930776ceb9b0241e3bf459d73845cfba4dde46 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,2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gmxana/gmx_ana.h"
 #include "gromacs/gmxana/nrama.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/utility/arraysize.h"
 #include "gromacs/utility/futil.h"
@@ -58,8 +59,8 @@ static void plot_rama(FILE* out, t_xrama* xr)
 
     for (i = 0; (i < xr->npp); i++)
     {
-        phi = xr->dih[xr->pp[i].iphi].ang * RAD2DEG;
-        psi = xr->dih[xr->pp[i].ipsi].ang * RAD2DEG;
+        phi = xr->dih[xr->pp[i].iphi].ang * gmx::c_rad2Deg;
+        psi = xr->dih[xr->pp[i].ipsi].ang * gmx::c_rad2Deg;
         fprintf(out, "%g  %g  %s\n", phi, psi, xr->pp[i].label);
     }
 }
@@ -81,8 +82,8 @@ int gmx_rama(int argc, char* argv[])
                        { efXVG, nullptr, "rama", ffWRITE } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, 0, nullptr,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, 0, nullptr, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
index 43c3419d25c2e3ffa14ec82c3c2fdc63f3f92f8b..728a58fbceaf1f174c15a4062a9d167d03e712dc 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gmxana/princ.h"
 #include "gromacs/math/do_fit.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/rmpbc.h"
@@ -241,8 +242,18 @@ int gmx_rms(int argc, char* argv[])
     };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW, NFILE, fnm,
-                           asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(&argc,
+                           argv,
+                           PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW,
+                           NFILE,
+                           fnm,
+                           asize(pa),
+                           pa,
+                           asize(desc),
+                           desc,
+                           0,
+                           nullptr,
+                           &oenv))
     {
         return 0;
     }
@@ -462,8 +473,7 @@ int gmx_rms(int argc, char* argv[])
     natoms_trx = read_first_x(oenv, &status, opt2fn("-f", NFILE, fnm), &t, &x, box);
     if (natoms_trx != top.atoms.nr)
     {
-        fprintf(stderr, "\nWARNING: topology has %d atoms, whereas trajectory has %d\n",
-                top.atoms.nr, natoms_trx);
+        fprintf(stderr, "\nWARNING: topology has %d atoms, whereas trajectory has %d\n", top.atoms.nr, natoms_trx);
     }
     natoms = std::min(top.atoms.nr, natoms_trx);
     if (bMat || bBond || bPrev)
@@ -701,7 +711,8 @@ int gmx_rms(int argc, char* argv[])
             gmx_fatal(FARGS,
                       "Second trajectory (%d atoms) does not match the first one"
                       " (%d atoms)",
-                      natoms_trx2, natoms_trx);
+                      natoms_trx2,
+                      natoms_trx);
         }
         frame2 = 0;
         do
@@ -859,8 +870,8 @@ int gmx_rms(int argc, char* argv[])
                 {
                     if (bFile2 || (i < j))
                     {
-                        rmsd_mat[i][j] = calc_similar_ind(ewhat != ewRMSD, irms[0], ind_rms_m,
-                                                          w_rms_m, mat_x[i], mat_x2_j);
+                        rmsd_mat[i][j] = calc_similar_ind(
+                                ewhat != ewRMSD, irms[0], ind_rms_m, w_rms_m, mat_x[i], mat_x2_j);
                         if (rmsd_mat[i][j] > rmsd_max)
                         {
                             rmsd_max = rmsd_mat[i][j];
@@ -972,9 +983,22 @@ int gmx_rms(int argc, char* argv[])
                 fprintf(stderr, "Min and Max value set to resp. %f and %f\n", rmsd_min, rmsd_max);
             }
             sprintf(buf, "%s %s matrix", gn_rms[0], whatname[ewhat]);
-            write_xpm(opt2FILE("-m", NFILE, fnm, "w"), 0, buf, whatlabel[ewhat],
-                      output_env_get_time_label(oenv), output_env_get_time_label(oenv), tel_mat,
-                      tel_mat2, axis, axis2, rmsd_mat, rmsd_min, rmsd_max, rlo, rhi, &nlevels);
+            write_xpm(opt2FILE("-m", NFILE, fnm, "w"),
+                      0,
+                      buf,
+                      whatlabel[ewhat],
+                      output_env_get_time_label(oenv),
+                      output_env_get_time_label(oenv),
+                      tel_mat,
+                      tel_mat2,
+                      axis,
+                      axis2,
+                      rmsd_mat,
+                      rmsd_min,
+                      rmsd_max,
+                      rlo,
+                      rhi,
+                      &nlevels);
             /* Print the distribution of RMSD values */
             if (opt2bSet("-dist", NFILE, fnm))
             {
@@ -1033,9 +1057,22 @@ int gmx_rms(int argc, char* argv[])
                 }
                 sprintf(buf, "%s %s vs. delta t", gn_rms[0], whatname[ewhat]);
                 fp = gmx_ffopen("delta.xpm", "w");
-                write_xpm(fp, 0, buf, "density", output_env_get_time_label(oenv), whatlabel[ewhat],
-                          delta_xsize, del_lev + 1, del_xaxis, del_yaxis, delta, 0.0, delta_max,
-                          rlo, rhi, &nlevels);
+                write_xpm(fp,
+                          0,
+                          buf,
+                          "density",
+                          output_env_get_time_label(oenv),
+                          whatlabel[ewhat],
+                          delta_xsize,
+                          del_lev + 1,
+                          del_xaxis,
+                          del_yaxis,
+                          delta,
+                          0.0,
+                          delta_max,
+                          rlo,
+                          rhi,
+                          &nlevels);
                 gmx_ffclose(fp);
             }
             if (opt2bSet("-bin", NFILE, fnm))
@@ -1068,7 +1105,8 @@ int gmx_rms(int argc, char* argv[])
                 fprintf(stderr,
                         "Bond angle Min and Max set to:\n"
                         "Min. angle: %f, Max. angle: %f\n",
-                        bond_min, bond_max);
+                        bond_min,
+                        bond_max);
             }
             rlo.r = 1;
             rlo.g = 1;
@@ -1077,9 +1115,22 @@ int gmx_rms(int argc, char* argv[])
             rhi.g = 0;
             rhi.b = 0;
             sprintf(buf, "%s av. bond angle deviation", gn_rms[0]);
-            write_xpm(opt2FILE("-bm", NFILE, fnm, "w"), 0, buf, "degrees",
-                      output_env_get_time_label(oenv), output_env_get_time_label(oenv), tel_mat,
-                      tel_mat2, axis, axis2, bond_mat, bond_min, bond_max, rlo, rhi, &nlevels);
+            write_xpm(opt2FILE("-bm", NFILE, fnm, "w"),
+                      0,
+                      buf,
+                      "degrees",
+                      output_env_get_time_label(oenv),
+                      output_env_get_time_label(oenv),
+                      tel_mat,
+                      tel_mat2,
+                      axis,
+                      axis2,
+                      bond_mat,
+                      bond_min,
+                      bond_max,
+                      rlo,
+                      rhi,
+                      &nlevels);
         }
     }
 
@@ -1092,15 +1143,22 @@ int gmx_rms(int argc, char* argv[])
     }
     else
     {
-        sprintf(buf, "%s with frame %g %s ago", whatxvgname[ewhat], time[prev * freq] - time[0],
+        sprintf(buf,
+                "%s with frame %g %s ago",
+                whatxvgname[ewhat],
+                time[prev * freq] - time[0],
                 output_env_get_time_label(oenv).c_str());
     }
-    fp = xvgropen(opt2fn("-o", NFILE, fnm), buf, output_env_get_xvgr_tlabel(oenv),
-                  whatxvglabel[ewhat], oenv);
+    fp = xvgropen(opt2fn("-o", NFILE, fnm), buf, output_env_get_xvgr_tlabel(oenv), whatxvglabel[ewhat], oenv);
     if (output_env_get_print_xvgr_codes(oenv))
     {
-        fprintf(fp, "@ subtitle \"%s%s after %s%s%s\"\n", (nrms == 1) ? "" : "of ", gn_rms[0],
-                fitgraphlabel[efit], bFit ? " to " : "", bFit ? gn_fit : "");
+        fprintf(fp,
+                "@ subtitle \"%s%s after %s%s%s\"\n",
+                (nrms == 1) ? "" : "of ",
+                gn_rms[0],
+                fitgraphlabel[efit],
+                bFit ? " to " : "",
+                bFit ? gn_fit : "");
     }
     if (nrms != 1)
     {
@@ -1135,8 +1193,7 @@ int gmx_rms(int argc, char* argv[])
         {
             if (output_env_get_print_xvgr_codes(oenv))
             {
-                fprintf(fp, "@ subtitle \"of %s after lsq fit to mirror of %s\"\n", gn_rms[0],
-                        bFit ? gn_fit : "");
+                fprintf(fp, "@ subtitle \"of %s after lsq fit to mirror of %s\"\n", gn_rms[0], bFit ? gn_fit : "");
             }
         }
         else
index af6235491905e7c1e5ea5f31562bc0c976375e1a..709018ef49d9b58681c505798b89212201c5b6be 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -150,7 +150,7 @@ static void calc_nmr(int nind, int nframes, real** dtot1_3, real** dtot1_6, real
     }
 }
 
-static char Hnum[] = "123";
+static const char Hnum[] = "123";
 
 typedef struct
 {
@@ -326,8 +326,14 @@ static int analyze_noe_equivalent(const char*    eq_fn,
                     j      = i + 1;
                     rnri   = atoms->atom[index[i]].resind;
                     rnrj   = atoms->atom[index[j]].resind;
-                    bEquiv = is_equiv(neq, equiv, &nnm[i], rnri, *atoms->resinfo[rnri].name,
-                                      *atoms->atomname[index[i]], rnrj, *atoms->resinfo[rnrj].name,
+                    bEquiv = is_equiv(neq,
+                                      equiv,
+                                      &nnm[i],
+                                      rnri,
+                                      *atoms->resinfo[rnri].name,
+                                      *atoms->atomname[index[i]],
+                                      rnrj,
+                                      *atoms->resinfo[rnrj].name,
                                       *atoms->atomname[index[j]]);
                     if (nnm[i] && bEquiv)
                     {
@@ -398,8 +404,12 @@ static int analyze_noe_equivalent(const char*    eq_fn,
         for (i = 0; i < isize; i++)
         {
             rnri = atoms->atom[index[i]].resind;
-            fprintf(debug, "%s %s %d -> %s\n", *atoms->atomname[index[i]],
-                    *atoms->resinfo[rnri].name, rnri, nnm[i] ? nnm[i] : "");
+            fprintf(debug,
+                    "%s %s %d -> %s\n",
+                    *atoms->atomname[index[i]],
+                    *atoms->resinfo[rnri].name,
+                    rnri,
+                    nnm[i] ? nnm[i] : "");
         }
     }
 
@@ -427,8 +437,15 @@ static int analyze_noe_equivalent(const char*    eq_fn,
             /* dump group definitions */
             if (debug)
             {
-                fprintf(debug, "%d %d %d %d %s %s %d\n", i, gi, noe_gr[gi].ianr, noe_gr[gi].anr,
-                        noe_gr[gi].aname, noe_gr[gi].rname, noe_gr[gi].rnr);
+                fprintf(debug,
+                        "%d %d %d %d %s %s %d\n",
+                        i,
+                        gi,
+                        noe_gr[gi].ianr,
+                        noe_gr[gi].anr,
+                        noe_gr[gi].aname,
+                        noe_gr[gi].rname,
+                        noe_gr[gi].rnr);
             }
         }
     }
@@ -508,9 +525,24 @@ static void write_noe(FILE* fp, int gnr, t_noe** noe, t_noe_gr* noe_gr, real rma
     t_noe_gr gri, grj;
 
     min3 = min6 = 1e6;
-    fprintf(fp, ";%4s %3s %4s %4s%3s %4s %4s %4s %4s%3s %5s %5s %8s %2s %2s %s\n", "ianr", "anr",
-            "anm", "rnm", "rnr", "ianr", "anr", "anm", "rnm", "rnr", "1/r^3", "1/r^6", "intnsty",
-            "Dr", "Da", "scale");
+    fprintf(fp,
+            ";%4s %3s %4s %4s%3s %4s %4s %4s %4s%3s %5s %5s %8s %2s %2s %s\n",
+            "ianr",
+            "anr",
+            "anm",
+            "rnm",
+            "rnr",
+            "ianr",
+            "anr",
+            "anm",
+            "rnm",
+            "rnr",
+            "1/r^3",
+            "1/r^6",
+            "intnsty",
+            "Dr",
+            "Da",
+            "scale");
     for (i = 0; i < gnr; i++)
     {
         gri = noe_gr[i];
@@ -547,10 +579,24 @@ static void write_noe(FILE* fp, int gnr, t_noe** noe, t_noe_gr* noe_gr, real rma
                 {
                     std::strcpy(b6, "-");
                 }
-                fprintf(fp, "%4d %4d %4s %4s%3d %4d %4d %4s %4s%3d %5s %5s %8d %2d %2s %s\n",
-                        gri.ianr + 1, gri.anr + 1, gri.aname, gri.rname, gri.rnr + 1, grj.ianr + 1,
-                        grj.anr + 1, grj.aname, grj.rname, grj.rnr + 1, b3, b6,
-                        gmx::roundToInt(noe[i][j].i_6), grj.rnr - gri.rnr, buf, noe2scale(r3, r6, rmax));
+                fprintf(fp,
+                        "%4d %4d %4s %4s%3d %4d %4d %4s %4s%3d %5s %5s %8d %2d %2s %s\n",
+                        gri.ianr + 1,
+                        gri.anr + 1,
+                        gri.aname,
+                        gri.rname,
+                        gri.rnr + 1,
+                        grj.ianr + 1,
+                        grj.anr + 1,
+                        grj.aname,
+                        grj.rname,
+                        grj.rnr + 1,
+                        b3,
+                        b6,
+                        gmx::roundToInt(noe[i][j].i_6),
+                        grj.rnr - gri.rnr,
+                        buf,
+                        noe2scale(r3, r6, rmax));
             }
         }
     }
@@ -562,7 +608,9 @@ static void write_noe(FILE* fp, int gnr, t_noe** noe, t_noe_gr* noe_gr, real rma
             fprintf(stdout,
                     "NOTE: no 1/r^%d averaged distances found below %g, "
                     "smallest was %g\n",
-                    i, rmax, MINI);
+                    i,
+                    rmax,
+                    MINI);
         }
         else
         {
@@ -714,8 +762,8 @@ int gmx_rmsdist(int argc, char* argv[])
     };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -834,8 +882,8 @@ int gmx_rmsdist(int argc, char* argv[])
         /* make list of noe atom groups */
         snew(noe_index, isize + 1);
         snew(noe_gr, isize);
-        gnr = analyze_noe_equivalent(opt2fn_null("-equiv", NFILE, fnm), atoms, isize, index, bSumH,
-                                     noe_index, noe_gr);
+        gnr = analyze_noe_equivalent(
+                opt2fn_null("-equiv", NFILE, fnm), atoms, isize, index, bSumH, noe_index, noe_gr);
         fprintf(stdout, "Found %d non-equivalent atom-groups in %d atoms\n", gnr, isize);
         /* make half matrix of of noe-group distances from atom distances */
         snew(noe, gnr);
@@ -855,34 +903,101 @@ int gmx_rmsdist(int argc, char* argv[])
 
     if (bRMS)
     {
-        write_xpm(opt2FILE("-rms", NFILE, fnm, "w"), 0, "RMS of distance", "RMS (nm)", "Atom Index",
-                  "Atom Index", isize, isize, resnr, resnr, rms, 0.0, rmsmax, rlo, rhi, &nlevels);
+        write_xpm(opt2FILE("-rms", NFILE, fnm, "w"),
+                  0,
+                  "RMS of distance",
+                  "RMS (nm)",
+                  "Atom Index",
+                  "Atom Index",
+                  isize,
+                  isize,
+                  resnr,
+                  resnr,
+                  rms,
+                  0.0,
+                  rmsmax,
+                  rlo,
+                  rhi,
+                  &nlevels);
     }
 
     if (bScale)
     {
-        write_xpm(opt2FILE("-scl", NFILE, fnm, "w"), 0, "Relative RMS", "RMS", "Atom Index",
-                  "Atom Index", isize, isize, resnr, resnr, rmsc, 0.0, rmscmax, rlo, rhi, &nlevels);
+        write_xpm(opt2FILE("-scl", NFILE, fnm, "w"),
+                  0,
+                  "Relative RMS",
+                  "RMS",
+                  "Atom Index",
+                  "Atom Index",
+                  isize,
+                  isize,
+                  resnr,
+                  resnr,
+                  rmsc,
+                  0.0,
+                  rmscmax,
+                  rlo,
+                  rhi,
+                  &nlevels);
     }
 
     if (bMean)
     {
-        write_xpm(opt2FILE("-mean", NFILE, fnm, "w"), 0, "Mean Distance", "Distance (nm)",
-                  "Atom Index", "Atom Index", isize, isize, resnr, resnr, mean, 0.0, meanmax, rlo,
-                  rhi, &nlevels);
+        write_xpm(opt2FILE("-mean", NFILE, fnm, "w"),
+                  0,
+                  "Mean Distance",
+                  "Distance (nm)",
+                  "Atom Index",
+                  "Atom Index",
+                  isize,
+                  isize,
+                  resnr,
+                  resnr,
+                  mean,
+                  0.0,
+                  meanmax,
+                  rlo,
+                  rhi,
+                  &nlevels);
     }
 
     if (bNMR3)
     {
-        write_xpm(opt2FILE("-nmr3", NFILE, fnm, "w"), 0, "1/r^3 averaged distances",
-                  "Distance (nm)", "Atom Index", "Atom Index", isize, isize, resnr, resnr, dtot1_3,
-                  0.0, max1_3, rlo, rhi, &nlevels);
+        write_xpm(opt2FILE("-nmr3", NFILE, fnm, "w"),
+                  0,
+                  "1/r^3 averaged distances",
+                  "Distance (nm)",
+                  "Atom Index",
+                  "Atom Index",
+                  isize,
+                  isize,
+                  resnr,
+                  resnr,
+                  dtot1_3,
+                  0.0,
+                  max1_3,
+                  rlo,
+                  rhi,
+                  &nlevels);
     }
     if (bNMR6)
     {
-        write_xpm(opt2FILE("-nmr6", NFILE, fnm, "w"), 0, "1/r^6 averaged distances",
-                  "Distance (nm)", "Atom Index", "Atom Index", isize, isize, resnr, resnr, dtot1_6,
-                  0.0, max1_6, rlo, rhi, &nlevels);
+        write_xpm(opt2FILE("-nmr6", NFILE, fnm, "w"),
+                  0,
+                  "1/r^6 averaged distances",
+                  "Distance (nm)",
+                  "Atom Index",
+                  "Atom Index",
+                  isize,
+                  isize,
+                  resnr,
+                  resnr,
+                  dtot1_6,
+                  0.0,
+                  max1_6,
+                  rlo,
+                  rhi,
+                  &nlevels);
     }
 
     if (bNOE)
index c0c439afd6af2c7174b364df59c64825402f4914..233f217e944b25f0340ff3203e75b8d4a7a79fbe 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +52,7 @@
 #include "gromacs/linearalgebra/eigensolver.h"
 #include "gromacs/math/do_fit.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/rmpbc.h"
@@ -278,8 +279,8 @@ int gmx_rmsf(int argc, char* argv[])
                        { efXVG, "-oc", "correl", ffOPTWR },  { efLOG, "-dir", "rmsf", ffOPTWR } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pargs),
-                           pargs, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pargs), pargs, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -492,12 +493,14 @@ int gmx_rmsf(int argc, char* argv[])
                 || top.atoms.atom[index[i]].resind != top.atoms.atom[index[i + 1]].resind)
             {
                 resind   = top.atoms.atom[index[i]].resind;
-                pdb_bfac = find_pdb_bfac(pdbatoms, &top.atoms.resinfo[resind],
-                                         *(top.atoms.atomname[index[i]]));
+                pdb_bfac = find_pdb_bfac(
+                        pdbatoms, &top.atoms.resinfo[resind], *(top.atoms.atomname[index[i]]));
 
-                fprintf(fp, "%5d  %10.5f  %10.5f\n",
+                fprintf(fp,
+                        "%5d  %10.5f  %10.5f\n",
                         bRes ? top.atoms.resinfo[top.atoms.atom[index[i]].resind].nr : index[i] + 1,
-                        rmsf[i] * bfac, pdb_bfac);
+                        rmsf[i] * bfac,
+                        pdb_bfac);
             }
         }
         xvgrclose(fp);
@@ -510,7 +513,8 @@ int gmx_rmsf(int argc, char* argv[])
             if (!bRes || i + 1 == isize
                 || top.atoms.atom[index[i]].resind != top.atoms.atom[index[i + 1]].resind)
             {
-                fprintf(fp, "%5d %8.4f\n",
+                fprintf(fp,
+                        "%5d %8.4f\n",
                         bRes ? top.atoms.resinfo[top.atoms.atom[index[i]].resind].nr : index[i] + 1,
                         std::sqrt(rmsf[i]));
             }
@@ -540,7 +544,8 @@ int gmx_rmsf(int argc, char* argv[])
             if (!bRes || i + 1 == isize
                 || top.atoms.atom[index[i]].resind != top.atoms.atom[index[i + 1]].resind)
             {
-                fprintf(fp, "%5d %8.4f\n",
+                fprintf(fp,
+                        "%5d %8.4f\n",
                         bRes ? top.atoms.resinfo[top.atoms.atom[index[i]].resind].nr : index[i] + 1,
                         std::sqrt(rmsf[i]));
             }
@@ -555,8 +560,8 @@ int gmx_rmsf(int argc, char* argv[])
         {
             rvec_inc(pdbx[index[i]], xcm);
         }
-        write_sto_conf_indexed(opt2fn("-oq", NFILE, fnm), title, pdbatoms, pdbx, nullptr, pbcType,
-                               pdbbox, isize, index);
+        write_sto_conf_indexed(
+                opt2fn("-oq", NFILE, fnm), title, pdbatoms, pdbx, nullptr, pbcType, pdbbox, isize, index);
     }
     if (opt2bSet("-ox", NFILE, fnm))
     {
@@ -570,8 +575,8 @@ int gmx_rmsf(int argc, char* argv[])
             }
         }
         /* Write a .pdb file with B-factors and optionally anisou records */
-        write_sto_conf_indexed(opt2fn("-ox", NFILE, fnm), title, pdbatoms, bFactorX, nullptr,
-                               pbcType, pdbbox, isize, index);
+        write_sto_conf_indexed(
+                opt2fn("-ox", NFILE, fnm), title, pdbatoms, bFactorX, nullptr, pbcType, pdbbox, isize, index);
         sfree(bFactorX);
     }
     if (bAniso)
index 048c663158d1d9159c38c548c70d82e78d5d2d50..7b5f2ffe3bccff8a3d64b1960de639fe8d45c66d 100644 (file)
@@ -113,8 +113,8 @@ int gmx_rotacf(int argc, char* argv[])
     npargs = asize(pa);
     ppa    = add_acf_pargs(&npargs, pa);
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, nullptr, &oenv))
     {
         sfree(ppa);
         return 0;
@@ -228,8 +228,8 @@ int gmx_rotacf(int argc, char* argv[])
 
         mode = eacVector;
 
-        do_autocorr(ftp2fn(efXVG, NFILE, fnm), oenv, "Rotational Correlation Function", teller,
-                    nvec, c1, dt, mode, bAver);
+        do_autocorr(
+                ftp2fn(efXVG, NFILE, fnm), oenv, "Rotational Correlation Function", teller, nvec, c1, dt, mode, bAver);
     }
 
     do_view(oenv, ftp2fn(efXVG, NFILE, fnm), nullptr);
index 6bc93086afa5c94e42dda1c545480e5843f78482..2a0959aee1f8105eb832ca5fe90c6e0cffa5fb85 100644 (file)
@@ -92,7 +92,8 @@ static void get_refx(gmx_output_env_t* oenv,
         {
             gmx_fatal(FARGS,
                       "Atom index (%d) is larger than the number of atoms in the trajecory (%d)",
-                      index[a] + 1, natoms);
+                      index[a] + 1,
+                      natoms);
         }
         w_rls[a] = (bMW ? top->atoms.atom[index[a]].m : 1.0);
         tot_mass += w_rls[a];
@@ -246,8 +247,8 @@ int gmx_rotmat(int argc, char* argv[])
                        { efXVG, nullptr, "rotmat", ffWRITE } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -263,8 +264,7 @@ int gmx_rotmat(int argc, char* argv[])
     GMX_RELEASE_ASSERT(reffit[0] != nullptr, "Options inconsistency; reffit[0] is NULL");
     if (reffit[0][0] != 'n')
     {
-        get_refx(oenv, ftp2fn(efTRX, NFILE, fnm), reffit[0][2] == 'z' ? 3 : 2, skip, gnx, index,
-                 bMW, &top, pbcType, x_ref);
+        get_refx(oenv, ftp2fn(efTRX, NFILE, fnm), reffit[0][2] == 'z' ? 3 : 2, skip, gnx, index, bMW, &top, pbcType, x_ref);
     }
 
     natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
@@ -276,7 +276,8 @@ int gmx_rotmat(int argc, char* argv[])
         {
             gmx_fatal(FARGS,
                       "Atom index (%d) is larger than the number of atoms in the trajecory (%d)",
-                      index[i] + 1, natoms);
+                      index[i] + 1,
+                      natoms);
         }
         w_rls[index[i]] = (bMW ? top.atoms.atom[index[i]].m : 1.0);
     }
@@ -302,8 +303,18 @@ int gmx_rotmat(int argc, char* argv[])
 
         calc_fit_R(DIM, natoms, w_rls, x_ref, x, R);
 
-        fprintf(out, "%7g %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f\n", t, R[XX][XX],
-                R[XX][YY], R[XX][ZZ], R[YY][XX], R[YY][YY], R[YY][ZZ], R[ZZ][XX], R[ZZ][YY], R[ZZ][ZZ]);
+        fprintf(out,
+                "%7g %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f\n",
+                t,
+                R[XX][XX],
+                R[XX][YY],
+                R[XX][ZZ],
+                R[YY][XX],
+                R[YY][YY],
+                R[YY][ZZ],
+                R[ZZ][XX],
+                R[ZZ][YY],
+                R[ZZ][ZZ]);
     } while (read_next_x(oenv, status, &t, x, box));
 
     gmx_rmpbc_done(gpbc);
index 46faac366874ede6ebfe40754e4f519d5ef9ea7c..bf21debe3cbb96130be2696b169738482bf977d4 100644 (file)
@@ -150,8 +150,8 @@ int gmx_saltbr(int argc, char* argv[])
     matrix            box;
     gmx_output_env_t* oenv;
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc,
-                           0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
index ab77d08a1cf938135939bbaa950ae93a6eb278b0..b6ac442c472fd6ff8e1f5368f7c7c0b0824815a8 100644 (file)
@@ -157,8 +157,8 @@ int gmx_sans(int argc, char* argv[])
 
     nthreads = gmx_omp_get_max_threads();
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -213,8 +213,7 @@ int gmx_sans(int argc, char* argv[])
     fnTRX = ftp2fn(efTRX, NFILE, fnm);
 
     gnsf = gmx_neutronstructurefactors_init(fnDAT);
-    fprintf(stderr, "Read %d atom names from %s with neutron scattering parameters\n\n",
-            gnsf->nratoms, fnDAT);
+    fprintf(stderr, "Read %d atom names from %s with neutron scattering parameters\n\n", gnsf->nratoms, fnDAT);
 
     snew(top, 1);
     snew(grpname, 1);
@@ -237,8 +236,10 @@ int gmx_sans(int argc, char* argv[])
     natoms = read_first_x(oenv, &status, fnTRX, &t, &x, box);
     if (natoms != top->atoms.nr)
     {
-        fprintf(stderr, "\nWARNING: number of atoms in tpx (%d) and trajectory (%d) do not match\n",
-                natoms, top->atoms.nr);
+        fprintf(stderr,
+                "\nWARNING: number of atoms in tpx (%d) and trajectory (%d) do not match\n",
+                natoms,
+                top->atoms.nr);
     }
 
     do
@@ -254,8 +255,8 @@ int gmx_sans(int argc, char* argv[])
             snew(pr, 1);
         }
         /*  realy calc p(r) */
-        prframecurrent = calc_radial_distribution_histogram(gsans, x, box, index, isize, binwidth,
-                                                            bMC, bNORM, mcover, seed);
+        prframecurrent = calc_radial_distribution_histogram(
+                gsans, x, box, index, isize, binwidth, bMC, bNORM, mcover, seed);
         /* copy prframecurrent -> pr and summ up pr->gr[i] */
         /* allocate and/or resize memory for pr->gr[i] and pr->r[i] */
         if (pr->gr == nullptr)
@@ -296,8 +297,11 @@ int gmx_sans(int argc, char* argv[])
             auto fnmdup = filenames;
             sprintf(suffix, "-t%.2f", t);
             add_suffix_to_output_names(fnmdup.data(), NFILE, suffix);
-            fp = xvgropen(opt2fn_null("-prframe", NFILE, fnmdup.data()), hdr, "Distance (nm)",
-                          "Probability", oenv);
+            fp = xvgropen(opt2fn_null("-prframe", NFILE, fnmdup.data()),
+                          hdr,
+                          "Distance (nm)",
+                          "Probability",
+                          oenv);
             for (i = 0; i < prframecurrent->grn; i++)
             {
                 fprintf(fp, "%10.6f%10.6f\n", prframecurrent->r[i], prframecurrent->gr[i]);
@@ -316,8 +320,8 @@ int gmx_sans(int argc, char* argv[])
             auto fnmdup = filenames;
             sprintf(suffix, "-t%.2f", t);
             add_suffix_to_output_names(fnmdup.data(), NFILE, suffix);
-            fp = xvgropen(opt2fn_null("-sqframe", NFILE, fnmdup.data()), hdr, "q (nm^-1)",
-                          "s(q)/s(0)", oenv);
+            fp = xvgropen(
+                    opt2fn_null("-sqframe", NFILE, fnmdup.data()), hdr, "q (nm^-1)", "s(q)/s(0)", oenv);
             for (i = 0; i < sqframecurrent->qn; i++)
             {
                 fprintf(fp, "%10.6f%10.6f\n", sqframecurrent->q[i], sqframecurrent->s[i]);
index 6827fa1c8d448c5352ac29db06b4d44a3f83a0eb..9db2db1fda8bf01f6c75330772c80c7bacbb1ed0 100644 (file)
@@ -72,8 +72,8 @@ int gmx_saxs(int argc, char* argv[])
         { efXVG, "-sq", "sq", ffWRITE },
     };
 #define NFILE asize(fnm)
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME, NFILE, fnm, NPA, pa, asize(desc), desc, 0,
-                           nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME, NFILE, fnm, NPA, pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -83,8 +83,8 @@ int gmx_saxs(int argc, char* argv[])
     fnDAT = ftp2fn(efDAT, NFILE, fnm);
     fnNDX = ftp2fn_null(efNDX, NFILE, fnm);
 
-    do_scattering_intensity(fnTPS, fnNDX, opt2fn("-sq", NFILE, fnm), fnTRX, fnDAT, start_q, end_q,
-                            energy, ngroups, oenv);
+    do_scattering_intensity(
+            fnTPS, fnNDX, opt2fn("-sq", NFILE, fnm), fnTRX, fnDAT, start_q, end_q, energy, ngroups, oenv);
 
     please_cite(stdout, "Cromer1968a");
 
index cc7d8f9e88bb07e9fc63a1915c86d29d85d3aa80..44dffff46d3b1601c729fccc3743b4d4bd1dbb27 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +52,7 @@
 #include "gromacs/gmxana/gstat.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/arraysize.h"
@@ -112,10 +113,25 @@ static void lo_write_xplor(XplorMap* map, const char* file)
     fprintf(fp, "\n       2 !NTITLE\n");
     fprintf(fp, " REMARKS Energy Landscape from GROMACS\n");
     fprintf(fp, " REMARKS DATE: 2004-12-21 \n");
-    fprintf(fp, " %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", map->Nx, map->dmin[0], map->dmax[0],
-            map->Ny, map->dmin[1], map->dmax[1], map->Nz, map->dmin[2], map->dmax[2]);
-    fprintf(fp, "%12.5E%12.5E%12.5E%12.5E%12.5E%12.5E\n", map->cell[0], map->cell[1], map->cell[2],
-            map->cell[3], map->cell[4], map->cell[5]);
+    fprintf(fp,
+            " %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
+            map->Nx,
+            map->dmin[0],
+            map->dmax[0],
+            map->Ny,
+            map->dmin[1],
+            map->dmax[1],
+            map->Nz,
+            map->dmin[2],
+            map->dmax[2]);
+    fprintf(fp,
+            "%12.5E%12.5E%12.5E%12.5E%12.5E%12.5E\n",
+            map->cell[0],
+            map->cell[1],
+            map->cell[2],
+            map->cell[3],
+            map->cell[4],
+            map->cell[5]);
     fprintf(fp, "ZYX\n");
 
     z = map->dmin[2];
@@ -233,7 +249,9 @@ static inline void print_minimum(FILE* fp, int num, const t_minimum* min)
     fprintf(fp,
             "Minimum %d at index "
             "%" PRId64 " energy %10.3f\n",
-            num, min->index, min->ener);
+            num,
+            min->index,
+            min->ener);
 }
 
 static inline void add_minimum(FILE* fp, int num, const t_minimum* min, t_minimum* mm)
@@ -314,14 +332,14 @@ static void pick_minima(const char* logfile, int* ibox, int ndim, int len, real
                         this_min.index = index3(ibox, i, j, k);
                         this_min.ener  = W[this_min.index];
                         if (is_local_minimum_from_below(&this_min, i, 0, index3(ibox, i - 1, j, k), W)
-                            && is_local_minimum_from_above(&this_min, i, ibox[0] - 1,
-                                                           index3(ibox, i + 1, j, k), W)
+                            && is_local_minimum_from_above(
+                                       &this_min, i, ibox[0] - 1, index3(ibox, i + 1, j, k), W)
                             && is_local_minimum_from_below(&this_min, j, 0, index3(ibox, i, j - 1, k), W)
-                            && is_local_minimum_from_above(&this_min, j, ibox[1] - 1,
-                                                           index3(ibox, i, j + 1, k), W)
+                            && is_local_minimum_from_above(
+                                       &this_min, j, ibox[1] - 1, index3(ibox, i, j + 1, k), W)
                             && is_local_minimum_from_below(&this_min, k, 0, index3(ibox, i, j, k - 1), W)
-                            && is_local_minimum_from_above(&this_min, k, ibox[2] - 1,
-                                                           index3(ibox, i, j, k + 1), W))
+                            && is_local_minimum_from_above(
+                                       &this_min, k, ibox[2] - 1, index3(ibox, i, j, k + 1), W))
                         {
                             add_minimum(fp, nmin, &this_min, mm);
                             nmin++;
@@ -365,12 +383,12 @@ static void pick_minima(const char* logfile, int* ibox, int ndim, int len, real
                     int index = this_point[i];
                     this_point[i]--;
                     bMin = bMin
-                           && is_local_minimum_from_below(&this_min, index, 0,
-                                                          indexn(ndim, ibox, this_point), W);
+                           && is_local_minimum_from_below(
+                                      &this_min, index, 0, indexn(ndim, ibox, this_point), W);
                     this_point[i] += 2;
                     bMin = bMin
-                           && is_local_minimum_from_above(&this_min, index, ibox[i] - 1,
-                                                          indexn(ndim, ibox, this_point), W);
+                           && is_local_minimum_from_above(
+                                      &this_min, index, ibox[i] - 1, indexn(ndim, ibox, this_point), W);
                     this_point[i]--;
                 }
                 if (bMin)
@@ -481,8 +499,10 @@ static void do_sham(const char* fn,
         {
             if (max_eig[i] > xmax[i])
             {
-                gmx_warning("Your xmax[%d] value %f is smaller than the largest data point %f", i,
-                            xmax[i], max_eig[i]);
+                gmx_warning("Your xmax[%d] value %f is smaller than the largest data point %f",
+                            i,
+                            xmax[i],
+                            max_eig[i]);
             }
             max_eig[i] = xmax[i];
         }
@@ -495,8 +515,10 @@ static void do_sham(const char* fn,
         {
             if (min_eig[i] < xmin[i])
             {
-                gmx_warning("Your xmin[%d] value %f is larger than the smallest data point %f", i,
-                            xmin[i], min_eig[i]);
+                gmx_warning("Your xmin[%d] value %f is larger than the smallest data point %f",
+                            i,
+                            xmin[i],
+                            min_eig[i]);
             }
             min_eig[i] = xmin[i];
         }
@@ -507,7 +529,7 @@ static void do_sham(const char* fn,
         bfac[i] = ibox[i] / (max_eig[i] - min_eig[i]);
     }
     /* Do the binning */
-    bref = 1 / (BOLTZ * Tref);
+    bref = 1 / (gmx::c_boltz * Tref);
     snew(bE, n);
     if (bGE || nenerT == 2)
     {
@@ -521,7 +543,7 @@ static void do_sham(const char* fn,
             }
             else
             {
-                bE[j] = (bref - 1 / (BOLTZ * enerT[1][j])) * enerT[0][j];
+                bE[j] = (bref - 1 / (gmx::c_boltz * enerT[1][j])) * enerT[0][j];
             }
             Emin = std::min(Emin, static_cast<double>(bE[j]));
         }
@@ -584,7 +606,7 @@ static void do_sham(const char* fn,
                 }
                 else if (idim[i] == -1)
                 {
-                    efac /= std::sin(DEG2RAD * eig[i][j]);
+                    efac /= std::sin(gmx::c_deg2Rad * eig[i][j]);
                 }
             }
             /* Update the probability */
@@ -614,7 +636,7 @@ static void do_sham(const char* fn,
         if (P[i] != 0)
         {
             Pmax = std::max(P[i], Pmax);
-            W[i] = -BOLTZ * Tref * std::log(P[i]);
+            W[i] = -gmx::c_boltz * Tref * std::log(P[i]);
             if (W[i] < Wmin)
             {
                 Wmin = W[i];
@@ -744,20 +766,76 @@ static void do_sham(const char* fn,
             SS[i] = &(S[i * ibox[1]]);
         }
         fp = gmx_ffopen(xpmP, "w");
-        write_xpm(fp, flags, "Probability Distribution", "", "PC1", "PC2", ibox[0], ibox[1], axis_x,
-                  axis_y, PP, 0, Pmax, rlo, rhi, &nlevels);
+        write_xpm(fp,
+                  flags,
+                  "Probability Distribution",
+                  "",
+                  "PC1",
+                  "PC2",
+                  ibox[0],
+                  ibox[1],
+                  axis_x,
+                  axis_y,
+                  PP,
+                  0,
+                  Pmax,
+                  rlo,
+                  rhi,
+                  &nlevels);
         gmx_ffclose(fp);
         fp = gmx_ffopen(xpm, "w");
-        write_xpm(fp, flags, "Gibbs Energy Landscape", "G (kJ/mol)", "PC1", "PC2", ibox[0], ibox[1],
-                  axis_x, axis_y, WW, 0, gmax, rlo, rhi, &nlevels);
+        write_xpm(fp,
+                  flags,
+                  "Gibbs Energy Landscape",
+                  "G (kJ/mol)",
+                  "PC1",
+                  "PC2",
+                  ibox[0],
+                  ibox[1],
+                  axis_x,
+                  axis_y,
+                  WW,
+                  0,
+                  gmax,
+                  rlo,
+                  rhi,
+                  &nlevels);
         gmx_ffclose(fp);
         fp = gmx_ffopen(xpm2, "w");
-        write_xpm(fp, flags, "Enthalpy Landscape", "H (kJ/mol)", "PC1", "PC2", ibox[0], ibox[1],
-                  axis_x, axis_y, EE, emin ? *emin : Emin, emax ? *emax : Einf, rlo, rhi, &nlevels);
+        write_xpm(fp,
+                  flags,
+                  "Enthalpy Landscape",
+                  "H (kJ/mol)",
+                  "PC1",
+                  "PC2",
+                  ibox[0],
+                  ibox[1],
+                  axis_x,
+                  axis_y,
+                  EE,
+                  emin ? *emin : Emin,
+                  emax ? *emax : Einf,
+                  rlo,
+                  rhi,
+                  &nlevels);
         gmx_ffclose(fp);
         fp = gmx_ffopen(xpm3, "w");
-        write_xpm(fp, flags, "Entropy Landscape", "TDS (kJ/mol)", "PC1", "PC2", ibox[0], ibox[1],
-                  axis_x, axis_y, SS, 0, Sinf, rlo, rhi, &nlevels);
+        write_xpm(fp,
+                  flags,
+                  "Entropy Landscape",
+                  "TDS (kJ/mol)",
+                  "PC1",
+                  "PC2",
+                  ibox[0],
+                  ibox[1],
+                  axis_x,
+                  axis_y,
+                  SS,
+                  0,
+                  Sinf,
+                  rlo,
+                  rhi,
+                  &nlevels);
         gmx_ffclose(fp);
     }
     else if (neig == 3)
@@ -776,9 +854,18 @@ static void do_sham(const char* fn,
                     index   = index3(ibox, i, j, k);
                     if (P[index] > 0)
                     {
-                        fprintf(fp, "%-6s%5d  %-4.4s%3.3s  %4d    %8.3f%8.3f%8.3f%6.2f%6.2f\n",
-                                "ATOM", (index + 1) % 10000, "H", "H", (index + 1) % 10000, xxx[XX],
-                                xxx[YY], xxx[ZZ], 1.0, W[index]);
+                        fprintf(fp,
+                                "%-6s%5d  %-4.4s%3.3s  %4d    %8.3f%8.3f%8.3f%6.2f%6.2f\n",
+                                "ATOM",
+                                (index + 1) % 10000,
+                                "H",
+                                "H",
+                                (index + 1) % 10000,
+                                xxx[XX],
+                                xxx[YY],
+                                xxx[ZZ],
+                                1.0,
+                                W[index]);
                     }
                 }
             }
@@ -800,8 +887,22 @@ static void do_sham(const char* fn,
         sprintf(buf, "%s", xpm);
         sprintf(&buf[std::strlen(xpm) - 4], "12.xpm");
         fp = gmx_ffopen(buf, "w");
-        write_xpm(fp, flags, "Gibbs Energy Landscape", "W (kJ/mol)", "PC1", "PC2", ibox[0], ibox[1],
-                  axis_x, axis_y, WW, 0, gmax, rlo, rhi, &nlevels);
+        write_xpm(fp,
+                  flags,
+                  "Gibbs Energy Landscape",
+                  "W (kJ/mol)",
+                  "PC1",
+                  "PC2",
+                  ibox[0],
+                  ibox[1],
+                  axis_x,
+                  axis_y,
+                  WW,
+                  0,
+                  gmax,
+                  rlo,
+                  rhi,
+                  &nlevels);
         gmx_ffclose(fp);
         for (i = 0; (i < ibox[0]); i++)
         {
@@ -812,8 +913,22 @@ static void do_sham(const char* fn,
         }
         sprintf(&buf[std::strlen(xpm) - 4], "13.xpm");
         fp = gmx_ffopen(buf, "w");
-        write_xpm(fp, flags, "SHAM Energy Landscape", "kJ/mol", "PC1", "PC3", ibox[0], ibox[2],
-                  axis_x, axis_z, WW, 0, gmax, rlo, rhi, &nlevels);
+        write_xpm(fp,
+                  flags,
+                  "SHAM Energy Landscape",
+                  "kJ/mol",
+                  "PC1",
+                  "PC3",
+                  ibox[0],
+                  ibox[2],
+                  axis_x,
+                  axis_z,
+                  WW,
+                  0,
+                  gmax,
+                  rlo,
+                  rhi,
+                  &nlevels);
         gmx_ffclose(fp);
         for (i = 0; (i < ibox[1]); i++)
         {
@@ -824,8 +939,22 @@ static void do_sham(const char* fn,
         }
         sprintf(&buf[std::strlen(xpm) - 4], "23.xpm");
         fp = gmx_ffopen(buf, "w");
-        write_xpm(fp, flags, "SHAM Energy Landscape", "kJ/mol", "PC2", "PC3", ibox[1], ibox[2],
-                  axis_y, axis_z, WW, 0, gmax, rlo, rhi, &nlevels);
+        write_xpm(fp,
+                  flags,
+                  "SHAM Energy Landscape",
+                  "kJ/mol",
+                  "PC2",
+                  "PC3",
+                  ibox[1],
+                  ibox[2],
+                  axis_y,
+                  axis_z,
+                  WW,
+                  0,
+                  gmax,
+                  rlo,
+                  rhi,
+                  &nlevels);
         gmx_ffclose(fp);
         sfree(buf);
     }
@@ -1011,14 +1140,23 @@ int gmx_sham(int argc, char* argv[])
     int npargs;
 
     npargs = asize(pa);
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, npargs, pa, asize(desc), desc, 0,
-                           nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW, NFILE, fnm, npargs, pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
 
-    val = read_xvg_time(opt2fn("-f", NFILE, fnm), bHaveT, opt2parg_bSet("-b", npargs, pa), tb - ttol,
-                        opt2parg_bSet("-e", npargs, pa), te + ttol, nsets_in, &nset, &n, &dt, &t);
+    val = read_xvg_time(opt2fn("-f", NFILE, fnm),
+                        bHaveT,
+                        opt2parg_bSet("-b", npargs, pa),
+                        tb - ttol,
+                        opt2parg_bSet("-e", npargs, pa),
+                        te + ttol,
+                        nsets_in,
+                        &nset,
+                        &n,
+                        &dt,
+                        &t);
     printf("Read %d sets of %d points, dt = %g\n\n", nset, n, dt);
 
     fn_ge  = opt2fn_null("-ge", NFILE, fnm);
@@ -1031,9 +1169,17 @@ int gmx_sham(int argc, char* argv[])
 
     if (fn_ge || fn_ene)
     {
-        et_val = read_xvg_time(fn_ge ? fn_ge : fn_ene, bHaveT, opt2parg_bSet("-b", npargs, pa),
-                               tb - ttol, opt2parg_bSet("-e", npargs, pa), te + ttol, 1, &e_nset,
-                               &e_n, &e_dt, &e_t);
+        et_val = read_xvg_time(fn_ge ? fn_ge : fn_ene,
+                               bHaveT,
+                               opt2parg_bSet("-b", npargs, pa),
+                               tb - ttol,
+                               opt2parg_bSet("-e", npargs, pa),
+                               te + ttol,
+                               1,
+                               &e_nset,
+                               &e_n,
+                               &e_dt,
+                               &e_t);
         if (fn_ge)
         {
             if (e_nset != 1)
@@ -1046,13 +1192,17 @@ int gmx_sham(int argc, char* argv[])
             if (e_nset != 1 && e_nset != 2)
             {
                 gmx_fatal(FARGS,
-                          "Can only handle one energy component or one energy and one T in %s", fn_ene);
+                          "Can only handle one energy component or one energy and one T in %s",
+                          fn_ene);
             }
         }
         if (e_n != n)
         {
-            gmx_fatal(FARGS, "Number of energies (%d) does not match number of entries (%d) in %s",
-                      e_n, n, opt2fn("-f", NFILE, fnm));
+            gmx_fatal(FARGS,
+                      "Number of energies (%d) does not match number of entries (%d) in %s",
+                      e_n,
+                      n,
+                      opt2fn("-f", NFILE, fnm));
         }
     }
     else
@@ -1098,12 +1248,33 @@ int gmx_sham(int argc, char* argv[])
     }
     /* The number of grid points fits in a int64_t. */
 
-    do_sham(opt2fn("-dist", NFILE, fnm), opt2fn("-bin", NFILE, fnm), opt2fn("-lp", NFILE, fnm),
-            opt2fn("-ls", NFILE, fnm), opt2fn("-lsh", NFILE, fnm), opt2fn("-lss", NFILE, fnm),
-            opt2fn("-ls3", NFILE, fnm), opt2fn("-g", NFILE, fnm), n, nset, val, fn_ge != nullptr,
-            e_nset, et_val, Tref, pmax, gmax, opt2parg_bSet("-emin", NPA, pa) ? &emin : nullptr,
-            opt2parg_bSet("-emax", NPA, pa) ? &emax : nullptr, nlevels, pmin, idim, ibox,
-            opt2parg_bSet("-xmin", NPA, pa), rmin, opt2parg_bSet("-xmax", NPA, pa), rmax);
+    do_sham(opt2fn("-dist", NFILE, fnm),
+            opt2fn("-bin", NFILE, fnm),
+            opt2fn("-lp", NFILE, fnm),
+            opt2fn("-ls", NFILE, fnm),
+            opt2fn("-lsh", NFILE, fnm),
+            opt2fn("-lss", NFILE, fnm),
+            opt2fn("-ls3", NFILE, fnm),
+            opt2fn("-g", NFILE, fnm),
+            n,
+            nset,
+            val,
+            fn_ge != nullptr,
+            e_nset,
+            et_val,
+            Tref,
+            pmax,
+            gmax,
+            opt2parg_bSet("-emin", NPA, pa) ? &emin : nullptr,
+            opt2parg_bSet("-emax", NPA, pa) ? &emax : nullptr,
+            nlevels,
+            pmin,
+            idim,
+            ibox,
+            opt2parg_bSet("-xmin", NPA, pa),
+            rmin,
+            opt2parg_bSet("-xmax", NPA, pa),
+            rmax);
 
     return 0;
 }
index 498416abcfd540f71ad938856163f37b6de8e5ad..6b102699f4ba0db2ba44456495625233a8aae120 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +53,7 @@
 
 static real pot(real x, real qq, real c6, real cn, int npow)
 {
-    return cn * pow(x, -npow) - c6 / gmx::power6(x) + qq * ONE_4PI_EPS0 / x;
+    return cn * pow(x, -npow) - c6 / gmx::power6(x) + qq * gmx::c_one4PiEps0 / x;
 }
 
 static real bhpot(real x, real A, real B, real C)
@@ -64,7 +64,7 @@ static real bhpot(real x, real A, real B, real C)
 static real dpot(real x, real qq, real c6, real cn, int npow)
 {
     return -(npow * cn * std::pow(x, -npow - 1) - 6 * c6 / (x * gmx::power6(x))
-             + qq * ONE_4PI_EPS0 / gmx::square(x));
+             + qq * gmx::c_one4PiEps0 / gmx::square(x));
 }
 
 int gmx_sigeps(int argc, char* argv[])
@@ -104,8 +104,8 @@ int gmx_sigeps(int argc, char* argv[])
     int         cur = 0;
 #define next (1 - cur)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc,
-                           0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -169,8 +169,7 @@ int gmx_sigeps(int argc, char* argv[])
             {
                 minimum = oldx + dp[cur] * (x - oldx) / (dp[cur] - dp[next]);
                 mval    = pot(minimum, qq, c6, cn, npow);
-                printf("Van der Waals + Coulomb minimum at r = %g (nm). Value = %g (kJ/mol)\n",
-                       minimum, mval);
+                printf("Van der Waals + Coulomb minimum at r = %g (nm). Value = %g (kJ/mol)\n", minimum, mval);
             }
         }
         cur  = next;
index 4561a28a807b66c01ed2c4d7621823bcb8e310a7..905769d4ce42f5ea3a12c2ad5146b06798dd3420 100644 (file)
@@ -195,8 +195,8 @@ int gmx_sorient(int argc, char* argv[])
                        { efXVG, "-co", "scum", ffWRITE },    { efXVG, "-rc", "scount", ffWRITE } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -415,7 +415,10 @@ int gmx_sorient(int argc, char* argv[])
     xvgr_legend(fp, 2, legr, oenv);
     for (i = 0; i < nrbin; i++)
     {
-        fprintf(fp, "%g %g %g\n", (i + 0.5) * rbinw, histn[i] ? histi1[i] / histn[i] : 0,
+        fprintf(fp,
+                "%g %g %g\n",
+                (i + 0.5) * rbinw,
+                histn[i] ? histi1[i] / histn[i] : 0,
                 histn[i] ? histi2[i] / histn[i] : 0);
     }
     xvgrclose(fp);
index 0ec43ffafda9f4a68fdc4bbe948b17d00c0755d8..81ea6d0c771e69ab82f7ac83cb57570e5f56c4f4 100644 (file)
@@ -190,8 +190,8 @@ int gmx_spatial(int argc, char* argv[])
 
     /* This is the routine responsible for adding default options,
      * calling the X/motif interface, etc. */
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, asize(bugs), bugs, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
         return 0;
     }
@@ -284,10 +284,17 @@ int gmx_spatial(int argc, char* argv[])
             {
                 printf("There was an item outside of the allocated memory. Increase the value "
                        "given with the -nab option.\n");
-                printf("Memory was allocated for [%f,%f,%f]\tto\t[%f,%f,%f]\n", MINBIN[XX],
-                       MINBIN[YY], MINBIN[ZZ], MAXBIN[XX], MAXBIN[YY], MAXBIN[ZZ]);
-                printf("Memory was required for [%f,%f,%f]\n", fr.x[index[i]][XX],
-                       fr.x[index[i]][YY], fr.x[index[i]][ZZ]);
+                printf("Memory was allocated for [%f,%f,%f]\tto\t[%f,%f,%f]\n",
+                       MINBIN[XX],
+                       MINBIN[YY],
+                       MINBIN[ZZ],
+                       MAXBIN[XX],
+                       MAXBIN[YY],
+                       MAXBIN[ZZ]);
+                printf("Memory was required for [%f,%f,%f]\n",
+                       fr.x[index[i]][XX],
+                       fr.x[index[i]][YY],
+                       fr.x[index[i]][ZZ]);
                 exit(1);
             }
             x = static_cast<int>(std::ceil((fr.x[index[i]][XX] - MINBIN[XX]) / rBINWIDTH));
@@ -341,16 +348,15 @@ int gmx_spatial(int argc, char* argv[])
     flp = gmx_ffopen("grid.cube", "w");
     fprintf(flp, "Spatial Distribution Function\n");
     fprintf(flp, "test\n");
-    fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", nidxp,
+    fprintf(flp,
+            "%5d%12.6f%12.6f%12.6f\n",
+            nidxp,
             (MINBIN[XX] + (minx + iIGNOREOUTER) * rBINWIDTH) * 10. / bohr,
             (MINBIN[YY] + (miny + iIGNOREOUTER) * rBINWIDTH) * 10. / bohr,
             (MINBIN[ZZ] + (minz + iIGNOREOUTER) * rBINWIDTH) * 10. / bohr);
-    fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", maxx - minx + 1 - (2 * iIGNOREOUTER),
-            rBINWIDTH * 10. / bohr, 0., 0.);
-    fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", maxy - miny + 1 - (2 * iIGNOREOUTER), 0.,
-            rBINWIDTH * 10. / bohr, 0.);
-    fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", maxz - minz + 1 - (2 * iIGNOREOUTER), 0., 0.,
-            rBINWIDTH * 10. / bohr);
+    fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", maxx - minx + 1 - (2 * iIGNOREOUTER), rBINWIDTH * 10. / bohr, 0., 0.);
+    fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", maxy - miny + 1 - (2 * iIGNOREOUTER), 0., rBINWIDTH * 10. / bohr, 0.);
+    fprintf(flp, "%5d%12.6f%12.6f%12.6f\n", maxz - minz + 1 - (2 * iIGNOREOUTER), 0., 0., rBINWIDTH * 10. / bohr);
     for (i = 0; i < nidxp; i++)
     {
         v = 2;
@@ -374,8 +380,13 @@ int gmx_spatial(int argc, char* argv[])
         {
             v = 16;
         }
-        fprintf(flp, "%5d%12.6f%12.6f%12.6f%12.6f\n", v, 0., fr.x[indexp[i]][XX] * 10.0 / bohr,
-                fr.x[indexp[i]][YY] * 10.0 / bohr, fr.x[indexp[i]][ZZ] * 10.0 / bohr);
+        fprintf(flp,
+                "%5d%12.6f%12.6f%12.6f%12.6f\n",
+                v,
+                0.,
+                fr.x[indexp[i]][XX] * 10.0 / bohr,
+                fr.x[indexp[i]][YY] * 10.0 / bohr,
+                fr.x[indexp[i]][ZZ] * 10.0 / bohr);
     }
 
     tot = 0;
@@ -481,14 +492,18 @@ int gmx_spatial(int argc, char* argv[])
     if (bCALCDIV)
     {
         printf("Counts per frame in all %d cubes divided by %le\n", numcu, 1.0 / norm);
-        printf("Normalized data: average %le, min %le, max %le\n", 1.0, minval * norm / numfr,
+        printf("Normalized data: average %le, min %le, max %le\n",
+               1.0,
+               minval * norm / numfr,
                maxval * norm / numfr);
     }
     else
     {
         printf("grid.cube contains counts per frame in all %d cubes\n", numcu);
-        printf("Raw data: average %le, min %le, max %le\n", 1.0 / norm,
-               static_cast<double>(minval) / numfr, static_cast<double>(maxval) / numfr);
+        printf("Raw data: average %le, min %le, max %le\n",
+               1.0 / norm,
+               static_cast<double>(minval) / numfr,
+               static_cast<double>(maxval) / numfr);
     }
 
     return 0;
index d67045be907debdfe1c247d4f380ea00665b474d..d4321ed96fd4e8defc814e2a42ce250cc1e0a5f8 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +129,10 @@ static void spol_atom2molindex(int* n, int* index, const t_block* mols)
         }
         if (m == mols->nr)
         {
-            gmx_fatal(FARGS, "index[%d]=%d does not correspond to the first atom of a molecule",
-                      i + 1, index[i] + 1);
+            gmx_fatal(FARGS,
+                      "index[%d]=%d does not correspond to the first atom of a molecule",
+                      i + 1,
+                      index[i] + 1);
         }
         for (j = mols->index[m]; j < mols->index[m + 1]; j++)
         {
@@ -210,8 +212,8 @@ int gmx_spol(int argc, char* argv[])
                        { efXVG, nullptr, "scdist", ffWRITE } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -333,7 +335,7 @@ int gmx_spol(int argc, char* argv[])
                 }
                 unitv(dir, dir);
 
-                svmul(ENM2DEBYE, dip, dip);
+                svmul(gmx::c_enm2Debye, dip, dip);
                 dip2 = norm2(dip);
                 sdip += std::sqrt(dip2);
                 sdip2 += dip2;
@@ -356,15 +358,16 @@ int gmx_spol(int argc, char* argv[])
     sfree(x);
     close_trx(status);
 
-    fprintf(stderr, "Average number of molecules within %g nm is %.1f\n", rmax,
-            static_cast<real>(ntot) / nf);
+    fprintf(stderr, "Average number of molecules within %g nm is %.1f\n", rmax, static_cast<real>(ntot) / nf);
     if (ntot > 0)
     {
         sdip /= ntot;
         sdip2 /= ntot;
         sinp /= ntot;
         sdinp /= ntot;
-        fprintf(stderr, "Average dipole:                               %f (D), std.dev. %f\n", sdip,
+        fprintf(stderr,
+                "Average dipole:                               %f (D), std.dev. %f\n",
+                sdip,
                 std::sqrt(sdip2 - gmx::square(sdip)));
         fprintf(stderr, "Average radial component of the dipole:       %f (D)\n", sinp);
         fprintf(stderr, "Average radial component of the polarization: %f (D)\n", sdinp);
index 03e9f2c6ad4d7f0022bcbbf6bf941b21563e0ad9..95b0cc1c0003c40e60d2972936729d5c467ece7c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 NKC0 4
 static const int kset_c[NKC + 1] = { 0, 3, 9, 13, 16, 19, NK };
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static rvec v0[NK] = { { 1, 0, 0 },  { 0, 1, 0 },  { 0, 0, 1 },  { 1, 1, 0 },  { 1, -1, 0 },
                        { 1, 0, 1 },  { 1, 0, -1 }, { 0, 1, 1 },  { 0, 1, -1 }, { 1, 1, 1 },
                        { 1, 1, -1 }, { 1, -1, 1 }, { -1, 1, 1 }, { 2, 0, 0 },  { 0, 2, 0 },
                        { 0, 0, 2 },  { 3, 0, 0 },  { 0, 3, 0 },  { 0, 0, 3 },  { 4, 0, 0 },
                        { 0, 4, 0 },  { 0, 0, 4 } };
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static rvec v1[NK] = { { 0, 1, 0 },  { 0, 0, 1 },  { 1, 0, 0 },  { 0, 0, 1 }, { 0, 0, 1 },
                        { 0, 1, 0 },  { 0, 1, 0 },  { 1, 0, 0 },  { 1, 0, 0 }, { 1, -1, 0 },
                        { 1, -1, 0 }, { 1, 0, -1 }, { 0, 1, -1 }, { 0, 1, 0 }, { 0, 0, 1 },
                        { 1, 0, 0 },  { 0, 1, 0 },  { 0, 0, 1 },  { 1, 0, 0 }, { 0, 1, 0 },
                        { 0, 0, 1 },  { 1, 0, 0 } };
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static rvec v2[NK] = { { 0, 0, 1 },  { 1, 0, 0 }, { 0, 1, 0 },  { 1, -1, 0 }, { 1, 1, 0 },
                        { 1, 0, -1 }, { 1, 0, 1 }, { 0, 1, -1 }, { 0, 1, 1 },  { 1, 1, -2 },
                        { 1, 1, 2 },  { 1, 2, 1 }, { 2, 1, 1 },  { 0, 0, 1 },  { 1, 0, 0 },
@@ -151,8 +154,22 @@ static void process_tcaf(int                     nframes,
         sig[i] = std::exp(0.5 * i * dt / wt);
     }
 
-    low_do_autocorr(fn_tca, oenv, "Transverse Current Autocorrelation Functions", nframes, ntc,
-                    ncorr, tc, dt, eacNormal, 1, FALSE, FALSE, FALSE, 0, 0, 0);
+    low_do_autocorr(fn_tca,
+                    oenv,
+                    "Transverse Current Autocorrelation Functions",
+                    nframes,
+                    ntc,
+                    ncorr,
+                    tc,
+                    dt,
+                    eacNormal,
+                    1,
+                    FALSE,
+                    FALSE,
+                    FALSE,
+                    0,
+                    0,
+                    0);
     do_view(oenv, fn_tca, "-nxy");
 
     fp = xvgropen(fn_tc, "Transverse Current Autocorrelation Functions", "Time (ps)", "TCAF", oenv);
@@ -226,9 +243,9 @@ static void process_tcaf(int                     nframes,
         tcaf[k][0]  = 1.0;
         fitparms[0] = 1;
         fitparms[1] = 1;
-        do_lmfit(ncorr, tcaf[k], sig, dt, nullptr, 0, ncorr * dt, oenv, bDebugMode(), effnVAC,
-                 fitparms, 0, nullptr);
-        eta = 1000 * fitparms[1] * rho / (4 * fitparms[0] * PICO * norm2(kfac[k]) / (NANO * NANO));
+        do_lmfit(ncorr, tcaf[k], sig, dt, nullptr, 0, ncorr * dt, oenv, bDebugMode(), effnVAC, fitparms, 0, nullptr);
+        eta = 1000 * fitparms[1] * rho
+              / (4 * fitparms[0] * gmx::c_pico * norm2(kfac[k]) / (gmx::c_nano * gmx::c_nano));
         fprintf(stdout, "k %6.3f  tau %6.3f  eta %8.5f 10^-3 kg/(m s)\n", norm(kfac[k]), fitparms[0], eta);
         fprintf(fp_vk, "%6.3f %g\n", norm(kfac[k]), eta);
         for (i = 0; i < ncorr; i++)
@@ -249,12 +266,15 @@ static void process_tcaf(int                     nframes,
             tcafc[k][0] = 1.0;
             fitparms[0] = 1;
             fitparms[1] = 1;
-            do_lmfit(ncorr, tcafc[k], sig, dt, nullptr, 0, ncorr * dt, oenv, bDebugMode(), effnVAC,
-                     fitparms, 0, nullptr);
+            do_lmfit(ncorr, tcafc[k], sig, dt, nullptr, 0, ncorr * dt, oenv, bDebugMode(), effnVAC, fitparms, 0, nullptr);
             eta = 1000 * fitparms[1] * rho
-                  / (4 * fitparms[0] * PICO * norm2(kfac[kset_c[k]]) / (NANO * NANO));
-            fprintf(stdout, "k %6.3f  tau %6.3f  Omega %6.3f  eta %8.5f 10^-3 kg/(m s)\n",
-                    norm(kfac[kset_c[k]]), fitparms[0], fitparms[1], eta);
+                  / (4 * fitparms[0] * gmx::c_pico * norm2(kfac[kset_c[k]]) / (gmx::c_nano * gmx::c_nano));
+            fprintf(stdout,
+                    "k %6.3f  tau %6.3f  Omega %6.3f  eta %8.5f 10^-3 kg/(m s)\n",
+                    norm(kfac[kset_c[k]]),
+                    fitparms[0],
+                    fitparms[1],
+                    eta);
             fprintf(fp_vk, "%6.3f %g\n", norm(kfac[kset_c[k]]), eta);
             for (i = 0; i < ncorr; i++)
             {
@@ -350,8 +370,8 @@ int gmx_tcaf(int argc, char* argv[])
     npargs = asize(pa);
     ppa    = add_acf_pargs(&npargs, pa);
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, nullptr, &oenv))
     {
         sfree(ppa);
         return 0;
@@ -492,11 +512,22 @@ int gmx_tcaf(int argc, char* argv[])
 
     dt = (t1 - t0) / (nframes - 1);
 
-    rho *= sysmass / nframes * AMU / (NANO * NANO * NANO);
+    rho *= sysmass / nframes * gmx::c_amu / (gmx::c_nano * gmx::c_nano * gmx::c_nano);
     fprintf(stdout, "Density = %g (kg/m^3)\n", rho);
-    process_tcaf(nframes, dt, nkc, tc, kfac, rho, wt, opt2fn_null("-ot", NFILE, fnm),
-                 opt2fn("-oa", NFILE, fnm), opt2fn("-o", NFILE, fnm), opt2fn("-of", NFILE, fnm),
-                 opt2fn_null("-oc", NFILE, fnm), opt2fn("-ov", NFILE, fnm), oenv);
+    process_tcaf(nframes,
+                 dt,
+                 nkc,
+                 tc,
+                 kfac,
+                 rho,
+                 wt,
+                 opt2fn_null("-ot", NFILE, fnm),
+                 opt2fn("-oa", NFILE, fnm),
+                 opt2fn("-o", NFILE, fnm),
+                 opt2fn("-of", NFILE, fnm),
+                 opt2fn_null("-oc", NFILE, fnm),
+                 opt2fn("-ov", NFILE, fnm),
+                 oenv);
 
     return 0;
 }
index 93c811bb5a223ab7d2032910864ba7564630cfb5..4ba21505de49542cf59c48fc5a5725664e481c99 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 
 #include <algorithm>
 #include <string>
+#include <vector>
 
 #include "gromacs/commandline/pargs.h"
 #include "gromacs/commandline/viewit.h"
@@ -160,16 +161,16 @@ static void print_data(FILE*       fp,
                        gmx_bool    bDim[],
                        const char* sffmt)
 {
-    static rvec* xav = nullptr;
+    static std::vector<gmx::RVec> xav;
 
     if (bCom)
     {
-        if (xav == nullptr)
+        if (xav.empty())
         {
-            snew(xav, ngrps);
+            xav.resize(ngrps);
         }
-        average_data(x, xav, mass, ngrps, isize, index);
-        low_print_data(fp, time, xav, ngrps, nullptr, bDim, sffmt);
+        average_data(x, as_rvec_array(xav.data()), mass, ngrps, isize, index);
+        low_print_data(fp, time, as_rvec_array(xav.data()), ngrps, nullptr, bDim, sffmt);
     }
     else
     {
@@ -185,16 +186,17 @@ static void write_trx_x(t_trxstatus*      status,
                         int               isize[],
                         int**             index)
 {
-    static rvec*    xav   = nullptr;
+    static std::vector<gmx::RVec> xav;
+    // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
     static t_atoms* atoms = nullptr;
     t_trxframe      fr_av;
     int             i;
 
     if (bCom)
     {
-        if (xav == nullptr)
+        if (xav.empty())
         {
-            snew(xav, ngrps);
+            xav.resize(ngrps);
             snew(atoms, 1);
             *atoms = *fr->atoms;
             snew(atoms->atom, ngrps);
@@ -208,11 +210,11 @@ static void write_trx_x(t_trxstatus*      status,
                 atoms->atomname[i] = fr->atoms->atomname[index[i][0]];
             }
         }
-        average_data(fr->x, xav, mass, ngrps, isize, index);
+        average_data(fr->x, as_rvec_array(xav.data()), mass, ngrps, isize, index);
         fr_av        = *fr;
         fr_av.natoms = ngrps;
         fr_av.atoms  = atoms;
-        fr_av.x      = xav;
+        fr_av.x      = as_rvec_array(xav.data());
         write_trxframe(status, &fr_av, nullptr);
     }
     else
@@ -389,7 +391,7 @@ static real temp(rvec v[], const real mass[], int isize, const int index[])
         ekin2 += mass[j] * norm2(v[j]);
     }
 
-    return ekin2 / (3 * isize * BOLTZ);
+    return ekin2 / (3 * isize * gmx::c_boltz);
 }
 
 static void remove_jump(matrix box, int natoms, rvec xp[], rvec x[])
@@ -478,8 +480,12 @@ static void write_pdb_bfac(const char*             fname,
         fp = xvgropen(xname, title, "Atom", "Spatial component", oenv);
         for (i = 0; i < isize; i++)
         {
-            fprintf(fp, "%-5d  %10.3f  %10.3f  %10.3f\n", 1 + i, sum[index[i]][XX],
-                    sum[index[i]][YY], sum[index[i]][ZZ]);
+            fprintf(fp,
+                    "%-5d  %10.3f  %10.3f  %10.3f\n",
+                    1 + i,
+                    sum[index[i]][XX],
+                    sum[index[i]][YY],
+                    sum[index[i]][ZZ]);
         }
         xvgrclose(fp);
         max  = 0;
@@ -516,8 +522,12 @@ static void write_pdb_bfac(const char*             fname,
             }
         }
 
-        printf("Maximum %s is %g on atom %d %s, res. %s %d\n", title, std::sqrt(max), maxi + 1,
-               *(atoms->atomname[maxi]), *(atoms->resinfo[atoms->atom[maxi].resind].name),
+        printf("Maximum %s is %g on atom %d %s, res. %s %d\n",
+               title,
+               std::sqrt(max),
+               maxi + 1,
+               *(atoms->atomname[maxi]),
+               *(atoms->resinfo[atoms->atom[maxi].resind].name),
                atoms->resinfo[atoms->atom[maxi].resind].nr);
 
         if (atoms->pdbinfo == nullptr)
@@ -707,8 +717,18 @@ int gmx_traj(int argc, char* argv[])
     };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW, NFILE, fnm,
-                           asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(&argc,
+                           argv,
+                           PCA_CAN_TIME | PCA_TIME_UNIT | PCA_CAN_VIEW,
+                           NFILE,
+                           fnm,
+                           asize(pa),
+                           pa,
+                           asize(desc),
+                           desc,
+                           0,
+                           nullptr,
+                           &oenv))
     {
         return 0;
     }
@@ -751,7 +771,12 @@ int gmx_traj(int argc, char* argv[])
     }
     std::string sffmt6 = gmx::formatString("%s%s%s%s%s%s", sffmt, sffmt, sffmt, sffmt, sffmt, sffmt);
 
-    bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &pbcType, &xtop, nullptr, topbox,
+    bTop = read_tps_conf(ftp2fn(efTPS, NFILE, fnm),
+                         &top,
+                         &pbcType,
+                         &xtop,
+                         nullptr,
+                         topbox,
                          bCom && (bOX || bOXT || bOV || bOT || bEKT || bEKR));
     sfree(xtop);
     if ((bMol || bCV || bCF) && !bTop)
@@ -788,8 +813,7 @@ int gmx_traj(int argc, char* argv[])
         {
             if (index0[0][i] < 0 || index0[0][i] >= mols->nr)
             {
-                gmx_fatal(FARGS, "Molecule index (%d) is out of range (%d-%d)", index0[0][i] + 1, 1,
-                          mols->nr);
+                gmx_fatal(FARGS, "Molecule index (%d) is out of range (%d-%d)", index0[0][i] + 1, 1, mols->nr);
             }
             isize[i] = atndx[index0[0][i] + 1] - atndx[index0[0][i]];
             snew(index[i], isize[i]);
@@ -822,8 +846,11 @@ int gmx_traj(int argc, char* argv[])
     if (bOX)
     {
         flags = flags | TRX_READ_X;
-        outx  = xvgropen(opt2fn("-ox", NFILE, fnm), bCom ? "Center of mass" : "Coordinate", label,
-                        "Coordinate (nm)", oenv);
+        outx  = xvgropen(opt2fn("-ox", NFILE, fnm),
+                        bCom ? "Center of mass" : "Coordinate",
+                        label,
+                        "Coordinate (nm)",
+                        oenv);
         make_legend(outx, ngroups, isize0[0], index0[0], grpname, bCom, bMol, bDim, oenv);
     }
     if (bOXT)
@@ -834,15 +861,18 @@ int gmx_traj(int argc, char* argv[])
     if (bOV)
     {
         flags = flags | TRX_READ_V;
-        outv  = xvgropen(opt2fn("-ov", NFILE, fnm), bCom ? "Center of mass velocity" : "Velocity",
-                        label, "Velocity (nm/ps)", oenv);
+        outv  = xvgropen(opt2fn("-ov", NFILE, fnm),
+                        bCom ? "Center of mass velocity" : "Velocity",
+                        label,
+                        "Velocity (nm/ps)",
+                        oenv);
         make_legend(outv, ngroups, isize0[0], index0[0], grpname, bCom, bMol, bDim, oenv);
     }
     if (bOF)
     {
         flags = flags | TRX_READ_F;
-        outf  = xvgropen(opt2fn("-of", NFILE, fnm), "Force", label,
-                        "Force (kJ mol\\S-1\\N nm\\S-1\\N)", oenv);
+        outf  = xvgropen(
+                opt2fn("-of", NFILE, fnm), "Force", label, "Force (kJ mol\\S-1\\N nm\\S-1\\N)", oenv);
         make_legend(outf, ngroups, isize0[0], index0[0], grpname, bCom, bMol, bDim, oenv);
     }
     if (bOB)
@@ -868,8 +898,11 @@ int gmx_traj(int argc, char* argv[])
         bDum[ZZ]  = FALSE;
         bDum[DIM] = TRUE;
         flags     = flags | TRX_READ_V;
-        outekt    = xvgropen(opt2fn("-ekt", NFILE, fnm), "Center of mass translation", label,
-                          "Energy (kJ mol\\S-1\\N)", oenv);
+        outekt    = xvgropen(opt2fn("-ekt", NFILE, fnm),
+                          "Center of mass translation",
+                          label,
+                          "Energy (kJ mol\\S-1\\N)",
+                          oenv);
         make_legend(outekt, ngroups, isize[0], index[0], grpname, bCom, bMol, bDum, oenv);
     }
     if (bEKR)
@@ -879,8 +912,11 @@ int gmx_traj(int argc, char* argv[])
         bDum[ZZ]  = FALSE;
         bDum[DIM] = TRUE;
         flags     = flags | TRX_READ_X | TRX_READ_V;
-        outekr    = xvgropen(opt2fn("-ekr", NFILE, fnm), "Center of mass rotation", label,
-                          "Energy (kJ mol\\S-1\\N)", oenv);
+        outekr    = xvgropen(opt2fn("-ekr", NFILE, fnm),
+                          "Center of mass rotation",
+                          label,
+                          "Energy (kJ mol\\S-1\\N)",
+                          oenv);
         make_legend(outekr, ngroups, isize[0], index[0], grpname, bCom, bMol, bDum, oenv);
     }
     if (bVD)
@@ -989,8 +1025,14 @@ int gmx_traj(int argc, char* argv[])
         if (bOB && fr.bBox)
         {
             fprintf(outb, "\t%g", fr.time);
-            fprintf(outb, sffmt6.c_str(), fr.box[XX][XX], fr.box[YY][YY], fr.box[ZZ][ZZ],
-                    fr.box[YY][XX], fr.box[ZZ][XX], fr.box[ZZ][YY]);
+            fprintf(outb,
+                    sffmt6.c_str(),
+                    fr.box[XX][XX],
+                    fr.box[YY][YY],
+                    fr.box[ZZ][ZZ],
+                    fr.box[YY][XX],
+                    fr.box[ZZ][XX],
+                    fr.box[ZZ][YY]);
             fprintf(outb, "\n");
         }
         if (bOT && fr.bV)
@@ -1117,15 +1159,39 @@ int gmx_traj(int argc, char* argv[])
     }
     if (bCV)
     {
-        write_pdb_bfac(opt2fn("-cv", NFILE, fnm), opt2fn("-av", NFILE, fnm), "average velocity",
-                       &(top.atoms), pbcType, topbox, isize[0], index[0], nr_xfr, sumx, nr_vfr,
-                       sumv, bDim, scale, oenv);
+        write_pdb_bfac(opt2fn("-cv", NFILE, fnm),
+                       opt2fn("-av", NFILE, fnm),
+                       "average velocity",
+                       &(top.atoms),
+                       pbcType,
+                       topbox,
+                       isize[0],
+                       index[0],
+                       nr_xfr,
+                       sumx,
+                       nr_vfr,
+                       sumv,
+                       bDim,
+                       scale,
+                       oenv);
     }
     if (bCF)
     {
-        write_pdb_bfac(opt2fn("-cf", NFILE, fnm), opt2fn("-af", NFILE, fnm), "average force",
-                       &(top.atoms), pbcType, topbox, isize[0], index[0], nr_xfr, sumx, nr_ffr,
-                       sumf, bDim, scale, oenv);
+        write_pdb_bfac(opt2fn("-cf", NFILE, fnm),
+                       opt2fn("-af", NFILE, fnm),
+                       "average force",
+                       &(top.atoms),
+                       pbcType,
+                       topbox,
+                       isize[0],
+                       index[0],
+                       nr_xfr,
+                       sumx,
+                       nr_ffr,
+                       sumf,
+                       bDim,
+                       scale,
+                       oenv);
     }
 
     /* view it */
index 96966c9a00ab73368617ba7a440d798eda65cfbf..386b4a745d0d0607fc650fb01d0c877abe3fde68 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +63,7 @@ typedef struct
     real d2;
 } t_order;
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static t_order* order;
 
 static int ocomp(const void* a, const void* b)
@@ -151,8 +152,8 @@ int gmx_trjorder(int argc, char* argv[])
                        { efXVG, "-nshell", "nshell", ffOPTWR } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc,
-                           0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -201,8 +202,10 @@ int gmx_trjorder(int argc, char* argv[])
 
     if ((isize_sol % na) != 0)
     {
-        gmx_fatal(FARGS, "Number of atoms in the molecule group (%d) is not a multiple of na (%d)",
-                  isize[1], na);
+        gmx_fatal(FARGS,
+                  "Number of atoms in the molecule group (%d) is not a multiple of na (%d)",
+                  isize[1],
+                  na);
     }
 
     nwat = isize_sol / na;
index 44edc6539d9f985ecc044f0a04e5909e107305c5..011063a4b284c820e10887298447809074d16920 100644 (file)
@@ -150,8 +150,8 @@ int gmx_vanhove(int argc, char* argv[])
     FILE* fp;
     t_rgb rlo = { 1, 1, 1 }, rhi = { 0, 0, 0 };
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -430,9 +430,22 @@ int gmx_vanhove(int argc, char* argv[])
             ticky[i] = i * rbin;
         }
         fp = gmx_ffopen(matfile, "w");
-        write_xpm(fp, MAT_SPATIAL_Y, "Van Hove function", "G (1/nm)",
-                  sbin == 0 ? "time (ps)" : "sqrt(time) (ps^1/2)", "r (nm)", mat_nx, nbin, tickx,
-                  ticky, mat, 0, matmax, rlo, rhi, &nlev);
+        write_xpm(fp,
+                  MAT_SPATIAL_Y,
+                  "Van Hove function",
+                  "G (1/nm)",
+                  sbin == 0 ? "time (ps)" : "sqrt(time) (ps^1/2)",
+                  "r (nm)",
+                  mat_nx,
+                  nbin,
+                  tickx,
+                  ticky,
+                  mat,
+                  0,
+                  matmax,
+                  rlo,
+                  rhi,
+                  &nlev);
         gmx_ffclose(fp);
     }
 
@@ -455,7 +468,8 @@ int gmx_vanhove(int argc, char* argv[])
             fprintf(fp, "%g", i * rbin);
             for (fbin = 0; fbin < nr; fbin++)
             {
-                fprintf(fp, " %g",
+                fprintf(fp,
+                        " %g",
                         static_cast<real>(pr[fbin][i]
                                           / (rcount[fbin] * isize * rbin * (i == 0 ? 0.5 : 1.0))));
             }
index 48a0ee567f4001618c9445a0bd8394db0f73fcf5..b12cfbb021ac3ebf10244cb7682bd85fddb8de6d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -143,8 +143,11 @@ static void calc_spectrum(int n, const real c[], real dt, const char* fn, gmx_ou
     {
         gmx_fatal(FARGS, "Invalid fft return status %d", status);
     }
-    fp = xvgropen(fn, "Vibrational Power Spectrum",
-                  bRecip ? "\\f{12}w\\f{4} (cm\\S-1\\N)" : "\\f{12}n\\f{4} (ps\\S-1\\N)", "a.u.", oenv);
+    fp = xvgropen(fn,
+                  "Vibrational Power Spectrum",
+                  bRecip ? "\\f{12}w\\f{4} (cm\\S-1\\N)" : "\\f{12}n\\f{4} (ps\\S-1\\N)",
+                  "a.u.",
+                  oenv);
     /* This is difficult.
      * The length of the ACF is dt (as passed to this routine).
      * We pass the vacf with N time steps from 0 to dt.
@@ -158,7 +161,7 @@ static void calc_spectrum(int n, const real c[], real dt, const char* fn, gmx_ou
      * The timestep between saving the trajectory is
      * 1e7 is to convert nanometer to cm
      */
-    recip_fac = bRecip ? (1e7 / SPEED_OF_LIGHT) : 1.0;
+    recip_fac = bRecip ? (1e7 / gmx::c_speedOfLight) : 1.0;
     for (i = 0; (i < n); i += 2)
     {
         nu    = i / (2 * dt);
@@ -229,8 +232,8 @@ int gmx_velacc(int argc, char* argv[])
 
     npargs = asize(pa);
     ppa    = add_acf_pargs(&npargs, pa);
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa,
-                           asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME, NFILE, fnm, npargs, ppa, asize(desc), desc, 0, nullptr, &oenv))
     {
         sfree(ppa);
         return 0;
@@ -340,9 +343,15 @@ int gmx_velacc(int argc, char* argv[])
     {
         /* Compute time step between frames */
         dt = (t1 - t0) / (counter - 1);
-        do_autocorr(opt2fn("-o", NFILE, fnm), oenv,
+        do_autocorr(opt2fn("-o", NFILE, fnm),
+                    oenv,
                     bMass ? "Momentum Autocorrelation Function" : "Velocity Autocorrelation Function",
-                    counter, gnx, c1, dt, eacVector, TRUE);
+                    counter,
+                    gnx,
+                    c1,
+                    dt,
+                    eacVector,
+                    TRUE);
 
         do_view(oenv, opt2fn("-o", NFILE, fnm), "-nxy");
 
index 9162bbcd4e261732652a3293f19cd3f69ff4be6f..55be0a50c6f094bcbffe014ac2feb85e57f9475e 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +53,6 @@
 #include <cstring>
 
 #include <algorithm>
-#include <sstream>
 
 #include "gromacs/commandline/pargs.h"
 #include "gromacs/fileio/tpxio.h"
@@ -96,14 +95,13 @@ enum
     enNr
 };
 /*! \brief
- * enum for type of input files (pdos, tpr, or pullf)
+ * enum for type of input files (tpr or pullx/pullf)
  */
 enum
 {
     whamin_unknown,
     whamin_tpr,
     whamin_pullxf,
-    whamin_pdo
 };
 
 /*! \brief enum for bootstrapping method
@@ -138,14 +136,14 @@ enum
 //! Parameters of one pull coodinate
 typedef struct
 {
-    int  pull_type;       //!< such as constraint, umbrella, ...
-    int  geometry;        //!< such as distance, direction, cylinder
-    int  ngroup;          //!< the number of pull groups involved
-    ivec dim;             //!< pull dimension with geometry distance
-    int  ndim;            //!< nr of pull_dim != 0
-    real k;               //!< force constants in tpr file
-    real init_dist;       //!< reference displacement
-    char coord_unit[256]; //!< unit of the displacement
+    PullingAlgorithm  pull_type;       //!< such as constraint, umbrella, ...
+    PullGroupGeometry geometry;        //!< such as distance, direction, cylinder
+    int               ngroup;          //!< the number of pull groups involved
+    ivec              dim;             //!< pull dimension with geometry distance
+    int               ndim;            //!< nr of pull_dim != 0
+    real              k;               //!< force constants in tpr file
+    real              init_dist;       //!< reference displacement
+    char              coord_unit[256]; //!< unit of the displacement
 } t_pullcoord;
 
 //! Parameters of the umbrella potentials
@@ -162,25 +160,12 @@ typedef struct
     gmx_bool     bPrintComp;     //!< Components of pull distance written to pullx.xvg ?
 
     /*!\}*/
-    /*!
-     * \name Using PDO files common until gromacs 3.x
-     */
-    /*!\{*/
-    int    nSkip;
-    char   Reference[256];
-    int    nPull;
-    int    nDim;
-    ivec   Dims;
-    char   PullName[4][256];
-    double UmbPos[4][3];
-    double UmbCons[4][3];
-    /*!\}*/
 } t_UmbrellaHeader;
 
 //! Data in the umbrella histograms
 typedef struct
 {
-    int      nPull; //!< nr of pull groups in this pdo or pullf/x file
+    int      nPull; //!< nr of pull groups in this pullf/pullx file
     double** Histo; //!< nPull histograms
     double** cum;   //!< nPull cumulative distribution functions
     int      nBin;  //!< nr of bins. identical to opt->bins
@@ -231,9 +216,9 @@ typedef struct UmbrellaOptions // NOLINT(clang-analyzer-optin.performance.Paddin
      */
     /*!\{*/
     const char *fnTpr, *fnPullf, *fnCoordSel;
-    const char *fnPdo, *fnPullx;            //!< file names of input
-    gmx_bool    bTpr, bPullf, bPdo, bPullx; //!< input file types given?
-    real        tmin, tmax, dt;             //!< only read input within tmin and tmax with dt
+    const char* fnPullx;              //!< file names of input
+    gmx_bool    bTpr, bPullf, bPullx; //!< input file types given?
+    real        tmin, tmax, dt;       //!< only read input within tmin and tmax with dt
 
     gmx_bool bInitPotByIntegration; //!< before WHAM, guess potential by force integration. Yields 1.5 to 2 times faster convergence
     int stepUpdateContrib; //!< update contribution table every ... iterations. Accelerates WHAM.
@@ -444,109 +429,10 @@ static void setup_tab(const char* fn, t_UmbrellaOptions* opt)
         opt->tabX[i] = y[0][i];
         opt->tabY[i] = y[1][i];
     }
-    printf("Found equally spaced tabulated potential from %g to %g, spacing %g\n", opt->tabMin,
-           opt->tabMax, opt->tabDz);
-}
-
-//! Read the header of an PDO file (position, force const, nr of groups)
-static void read_pdo_header(FILE* file, t_UmbrellaHeader* header, t_UmbrellaOptions* opt)
-{
-    char               line[2048];
-    char               Buffer0[256], Buffer1[256], Buffer2[256], Buffer3[256], Buffer4[256];
-    int                i;
-    std::istringstream ist;
-
-    /*  line 1 */
-    if (fgets(line, 2048, file) == nullptr)
-    {
-        gmx_fatal(FARGS, "Error reading header from pdo file\n");
-    }
-    ist.str(line);
-    ist >> Buffer0 >> Buffer1 >> Buffer2;
-    if (std::strcmp(Buffer1, "UMBRELLA") != 0)
-    {
-        gmx_fatal(FARGS,
-                  "This does not appear to be a valid pdo file. Found %s, expected %s\n"
-                  "(Found in first line: `%s')\n",
-                  Buffer1, "UMBRELLA", line);
-    }
-    if (std::strcmp(Buffer2, "3.0") != 0)
-    {
-        gmx_fatal(FARGS, "This does not appear to be a version 3.0 pdo file");
-    }
-
-    /*  line 2 */
-    if (fgets(line, 2048, file) == nullptr)
-    {
-        gmx_fatal(FARGS, "Error reading header from pdo file\n");
-    }
-    ist.str(line);
-    ist >> Buffer0 >> Buffer1 >> Buffer2 >> header->Dims[0] >> header->Dims[1] >> header->Dims[2];
-    /* printf("%d %d %d\n", header->Dims[0],header->Dims[1],header->Dims[2]); */
-
-    header->nDim = header->Dims[0] + header->Dims[1] + header->Dims[2];
-    if (header->nDim != 1)
-    {
-        gmx_fatal(FARGS, "Currently only supports one dimension");
-    }
-
-    /* line3 */
-    if (fgets(line, 2048, file) == nullptr)
-    {
-        gmx_fatal(FARGS, "Error reading header from pdo file\n");
-    }
-    ist.str(line);
-    ist >> Buffer0 >> Buffer1 >> header->nSkip;
-
-    /* line 4 */
-    if (fgets(line, 2048, file) == nullptr)
-    {
-        gmx_fatal(FARGS, "Error reading header from pdo file\n");
-    }
-    ist.str(line);
-    ist >> Buffer0 >> Buffer1 >> Buffer2 >> header->Reference;
-
-    /* line 5 */
-    if (fgets(line, 2048, file) == nullptr)
-    {
-        gmx_fatal(FARGS, "Error reading header from pdo file\n");
-    }
-    ist.str(line);
-    ist >> Buffer0 >> Buffer1 >> Buffer2 >> Buffer3 >> Buffer4 >> header->nPull;
-
-    if (opt->verbose)
-    {
-        printf("\tFound nPull=%d , nSkip=%d, ref=%s\n", header->nPull, header->nSkip, header->Reference);
-    }
-
-    for (i = 0; i < header->nPull; ++i)
-    {
-        if (fgets(line, 2048, file) == nullptr)
-        {
-            gmx_fatal(FARGS, "Error reading header from pdo file\n");
-        }
-        ist.str(line);
-        ist >> Buffer0 >> Buffer1 >> Buffer2 >> header->PullName[i];
-        ist >> Buffer0 >> Buffer1 >> header->UmbPos[i][0];
-        ist >> Buffer0 >> Buffer1 >> header->UmbCons[i][0];
-
-        if (opt->verbose)
-        {
-            printf("\tpullgroup %d, pullname = %s, UmbPos = %g, UmbConst = %g\n", i,
-                   header->PullName[i], header->UmbPos[i][0], header->UmbCons[i][0]);
-        }
-    }
-
-    if (fgets(line, 2048, file) == nullptr)
-    {
-        gmx_fatal(FARGS, "Cannot read from file\n");
-    }
-    ist.str(line);
-    ist >> Buffer3;
-    if (std::strcmp(Buffer3, "#####") != 0)
-    {
-        gmx_fatal(FARGS, "Expected '#####', found %s. Hick.\n", Buffer3);
-    }
+    printf("Found equally spaced tabulated potential from %g to %g, spacing %g\n",
+           opt->tabMin,
+           opt->tabMax,
+           opt->tabDz);
 }
 
 //! smarter fgets
@@ -580,220 +466,6 @@ static char* fgets3(FILE* fp, char ptr[], int* len)
     return ptr;
 }
 
-/*! \brief Read the data columns of and PDO file.
- *
- *  TO DO: Get rid of the scanf function to avoid the clang warning.
- *         At the moment, this warning is avoided by hiding the format string
- *         the variable fmtlf.
- */
-static void read_pdo_data(FILE*              file,
-                          t_UmbrellaHeader*  header,
-                          int                fileno,
-                          t_UmbrellaWindow*  win,
-                          t_UmbrellaOptions* opt,
-                          gmx_bool           bGetMinMax,
-                          real*              mintmp,
-                          real*              maxtmp)
-{
-    int               i, inttemp, bins, count, ntot;
-    real              minval, maxval, minfound = 1e20, maxfound = -1e20;
-    double            temp, time, time0 = 0, dt;
-    char*             ptr    = nullptr;
-    t_UmbrellaWindow* window = nullptr;
-    gmx_bool          timeok, dt_ok = true;
-    char *            tmpbuf = nullptr, fmt[256], fmtign[256], fmtlf[5] = "%lf";
-    int               len = STRLEN, dstep = 1;
-    const int         blocklen = 4096;
-    int*              lennow   = nullptr;
-
-    if (!bGetMinMax)
-    {
-        bins   = opt->bins;
-        minval = opt->min;
-        maxval = opt->max;
-
-        window = win + fileno;
-        /* Need to alocate memory and set up structure */
-        window->nPull = header->nPull;
-        window->nBin  = bins;
-
-        snew(window->Histo, window->nPull);
-        snew(window->z, window->nPull);
-        snew(window->k, window->nPull);
-        snew(window->pos, window->nPull);
-        snew(window->N, window->nPull);
-        snew(window->Ntot, window->nPull);
-        snew(window->g, window->nPull);
-        snew(window->bsWeight, window->nPull);
-
-        window->bContrib = nullptr;
-
-        if (opt->bCalcTauInt)
-        {
-            snew(window->ztime, window->nPull);
-        }
-        else
-        {
-            window->ztime = nullptr;
-        }
-        snew(lennow, window->nPull);
-
-        for (i = 0; i < window->nPull; ++i)
-        {
-            window->z[i]        = 1;
-            window->bsWeight[i] = 1.;
-            snew(window->Histo[i], bins);
-            window->k[i]    = header->UmbCons[i][0];
-            window->pos[i]  = header->UmbPos[i][0];
-            window->N[i]    = 0;
-            window->Ntot[i] = 0;
-            window->g[i]    = 1.;
-            if (opt->bCalcTauInt)
-            {
-                window->ztime[i] = nullptr;
-            }
-        }
-
-        /* Done with setup */
-    }
-    else
-    {
-        minfound = 1e20;
-        maxfound = -1e20;
-        minval = maxval = bins = 0; /* Get rid of warnings */
-    }
-
-    count = 0;
-    snew(tmpbuf, len);
-    while ((ptr = fgets3(file, tmpbuf, &len)) != nullptr)
-    {
-        trim(ptr);
-
-        if (ptr[0] == '#' || std::strlen(ptr) < 2)
-        {
-            continue;
-        }
-
-        /* Initiate format string */
-        fmtign[0] = '\0';
-        std::strcat(fmtign, "%*s");
-
-        sscanf(ptr, fmtlf, &time); /* printf("Time %f\n",time); */
-        /* Round time to fs */
-        time = 1.0 / 1000 * (gmx::roundToInt64(time * 1000));
-
-        /* get time step of pdo file */
-        if (count == 0)
-        {
-            time0 = time;
-        }
-        else if (count == 1)
-        {
-            dt = time - time0;
-            if (opt->dt > 0.0)
-            {
-                dstep = gmx::roundToInt(opt->dt / dt);
-                if (dstep == 0)
-                {
-                    dstep = 1;
-                }
-            }
-            if (!bGetMinMax)
-            {
-                window->dt = dt * dstep;
-            }
-        }
-        count++;
-
-        dt_ok  = ((count - 1) % dstep == 0);
-        timeok = (dt_ok && time >= opt->tmin && time <= opt->tmax);
-        /* if (opt->verbose)
-           printf(" time = %f, (tmin,tmax)=(%e,%e), dt_ok=%d timeok=%d\n",
-           time,opt->tmin, opt->tmax, dt_ok,timeok); */
-
-        if (timeok)
-        {
-            for (i = 0; i < header->nPull; ++i)
-            {
-                std::strcpy(fmt, fmtign);
-                std::strcat(fmt, "%lf");    /* Creating a format stings such as "%*s...%*s%lf" */
-                std::strcat(fmtign, "%*s"); /* ignoring one more entry in the next loop */
-                if (sscanf(ptr, fmt, &temp))
-                {
-                    temp += header->UmbPos[i][0];
-                    if (bGetMinMax)
-                    {
-                        if (temp < minfound)
-                        {
-                            minfound = temp;
-                        }
-                        if (temp > maxfound)
-                        {
-                            maxfound = temp;
-                        }
-                    }
-                    else
-                    {
-                        if (opt->bCalcTauInt)
-                        {
-                            /* save time series for autocorrelation analysis */
-                            ntot = window->Ntot[i];
-                            if (ntot >= lennow[i])
-                            {
-                                lennow[i] += blocklen;
-                                srenew(window->ztime[i], lennow[i]);
-                            }
-                            window->ztime[i][ntot] = temp;
-                        }
-
-                        temp -= minval;
-                        temp /= (maxval - minval);
-                        temp *= bins;
-                        temp = std::floor(temp);
-
-                        inttemp = static_cast<int>(temp);
-                        if (opt->bCycl)
-                        {
-                            if (inttemp < 0)
-                            {
-                                inttemp += bins;
-                            }
-                            else if (inttemp >= bins)
-                            {
-                                inttemp -= bins;
-                            }
-                        }
-
-                        if (inttemp >= 0 && inttemp < bins)
-                        {
-                            window->Histo[i][inttemp] += 1.;
-                            window->N[i]++;
-                        }
-                        window->Ntot[i]++;
-                    }
-                }
-            }
-        }
-        if (time > opt->tmax)
-        {
-            if (opt->verbose)
-            {
-                printf("time %f larger than tmax %f, stop reading pdo file\n", time, opt->tmax);
-            }
-            break;
-        }
-    }
-
-    if (bGetMinMax)
-    {
-        *mintmp = minfound;
-        *maxtmp = maxfound;
-    }
-
-    sfree(lennow);
-    sfree(tmpbuf);
-}
-
 /*! \brief Set identical weights for all histograms
  *
  * Normally, the weight is given by the number data points in each
@@ -840,7 +512,9 @@ static double tabulated_pot(double dist, t_UmbrellaOptions* opt)
         gmx_fatal(FARGS,
                   "Distance %f out of bounds of tabulated potential (jl=%d, ju=%d).\n"
                   "Provide an extended table.",
-                  dist, jl, ju);
+                  dist,
+                  jl,
+                  ju);
     }
     pl = opt->tabY[jl];
     pu = opt->tabY[ju];
@@ -906,8 +580,8 @@ static void setup_acc_wham(const double* profile, t_UmbrellaWindow* window, int
                     }
                 }
                 /* Note: there are two contributions to bin k in the wham equations:
-                   i)  N[j]*exp(- U/(BOLTZ*opt->Temperature) + window[i].z[j])
-                   ii) exp(- U/(BOLTZ*opt->Temperature))
+                   i)  N[j]*exp(- U/(c_boltz*opt->Temperature) + window[i].z[j])
+                   ii) exp(- U/(c_boltz*opt->Temperature))
                    where U is the umbrella potential
                    If any of these number is larger wham_contrib_lim, I set contrib=TRUE
                  */
@@ -920,8 +594,9 @@ static void setup_acc_wham(const double* profile, t_UmbrellaWindow* window, int
                 {
                     U = tabulated_pot(distance, opt); /* Use tabulated potential     */
                 }
-                contrib1 = profile[k] * std::exp(-U / (BOLTZ * opt->Temperature));
-                contrib2 = window[i].N[j] * std::exp(-U / (BOLTZ * opt->Temperature) + window[i].z[j]);
+                contrib1 = profile[k] * std::exp(-U / (gmx::c_boltz * opt->Temperature));
+                contrib2 = window[i].N[j]
+                           * std::exp(-U / (gmx::c_boltz * opt->Temperature) + window[i].z[j]);
                 window[i].bContrib[j][k] = (contrib1 > wham_contrib_lim || contrib2 > wham_contrib_lim);
                 bAnyContrib              = bAnyContrib || window[i].bContrib[j][k];
                 if (window[i].bContrib[j][k])
@@ -946,7 +621,9 @@ static void setup_acc_wham(const double* profile, t_UmbrellaWindow* window, int
     {
         printf("Initialized rapid wham stuff (contrib tolerance %g)\n"
                "Evaluating only %d of %d expressions.\n\n",
-               wham_contrib_lim, nContrib, nTot);
+               wham_contrib_lim,
+               nContrib,
+               nTot);
     }
 
     if (opt->verbose)
@@ -1013,7 +690,7 @@ static void calc_profile(double* profile, t_UmbrellaWindow* window, int nWindows
                             U = tabulated_pot(distance, opt); /* Use tabulated potential     */
                         }
                         denom += invg * window[j].N[k]
-                                 * std::exp(-U / (BOLTZ * opt->Temperature) + window[j].z[k]);
+                                 * std::exp(-U / (gmx::c_boltz * opt->Temperature) + window[j].z[k]);
                     }
                 }
                 profile[i] = num / denom;
@@ -1079,7 +756,7 @@ static double calc_z(const double* profile, t_UmbrellaWindow* window, int nWindo
                         {
                             U = tabulated_pot(distance, opt); /* Use tabulated potential     */
                         }
-                        total += profile[k] * std::exp(-U / (BOLTZ * opt->Temperature));
+                        total += profile[k] * std::exp(-U / (gmx::c_boltz * opt->Temperature));
                     }
                     /* Avoid floating point exception if window is far outside min and max */
                     if (total != 0.0)
@@ -1125,8 +802,7 @@ static void symmetrizeProfile(double* profile, t_UmbrellaOptions* opt)
 
     if (min > 0. || max < 0.)
     {
-        gmx_fatal(FARGS, "Cannot symmetrize profile around z=0 with min=%f and max=%f\n", opt->min,
-                  opt->max);
+        gmx_fatal(FARGS, "Cannot symmetrize profile around z=0 with min=%f and max=%f\n", opt->min, opt->max);
     }
 
     snew(prof2, bins);
@@ -1177,11 +853,11 @@ static void prof_normalization_and_unit(double* profile, t_UmbrellaOptions* opt)
     }
     else if (opt->unit == en_kJ)
     {
-        unit_factor = BOLTZ * opt->Temperature;
+        unit_factor = gmx::c_boltz * opt->Temperature;
     }
     else if (opt->unit == en_kCal)
     {
-        unit_factor = (BOLTZ / CAL2JOULE) * opt->Temperature;
+        unit_factor = (gmx::c_boltz / gmx::c_cal2Joule) * opt->Temperature;
     }
     else
     {
@@ -1249,7 +925,11 @@ static void getRandomIntArray(int nPull, int blockLength, int* randomArray, gmx:
             gmx_fatal(FARGS,
                       "Ups, random iWin = %d, nPull = %d, nr = %d, "
                       "blockLength = %d, blockBase = %d\n",
-                      ipullRandom, nPull, nr, blockLength, blockBase);
+                      ipullRandom,
+                      nPull,
+                      nr,
+                      blockLength,
+                      blockBase);
         }
         randomArray[ipull] = ipullRandom;
     }
@@ -1796,7 +1476,7 @@ static void do_bootstrapping(const char*        fnres,
     printf("Wrote boot strap result to %s\n", fnres);
 }
 
-//! Return type of input file based on file extension (xvg, pdo, or tpr)
+//! Return type of input file based on file extension (xvg or tpr)
 static int whaminFileType(char* fn)
 {
     int len;
@@ -1809,17 +1489,16 @@ static int whaminFileType(char* fn)
     {
         return whamin_pullxf;
     }
-    else if (std::strcmp(fn + len - 3, "pdo") == 0 || std::strcmp(fn + len - 6, "pdo.gz") == 0)
-    {
-        return whamin_pdo;
-    }
     else
     {
-        gmx_fatal(FARGS, "Unknown file type of %s. Should be tpr, xvg, or pdo.\n", fn);
+        gmx_fatal(FARGS,
+                  "Unknown file type of %s. Should be tpr or xvg. Use GROMACS 2021 or earlier to "
+                  "read pdo files.\n",
+                  fn);
     }
 }
 
-//! Read the files names in pdo-files.dat, pullf/x-files.dat, tpr-files.dat
+//! Read the files names in pullf/pullx-files.dat, tpr-files.dat
 static void read_wham_in(const char* fn, char*** filenamesRet, int* nfilesRet, t_UmbrellaOptions* opt)
 {
     char **filename = nullptr, tmp[WHAM_MAXFILELEN + 2];
@@ -1860,188 +1539,6 @@ static void read_wham_in(const char* fn, char*** filenamesRet, int* nfilesRet, t
     *nfilesRet    = nread;
 }
 
-//! Open a file or a pipe to a gzipped file
-static FILE* open_pdo_pipe(const char* fn, t_UmbrellaOptions* opt, gmx_bool* bPipeOpen)
-{
-    char            Buffer[2048], gunzip[1024], *Path = nullptr;
-    FILE*           pipe   = nullptr;
-    static gmx_bool bFirst = true;
-
-    /* gzipped pdo file? */
-    if ((std::strcmp(fn + std::strlen(fn) - 3, ".gz") == 0))
-    {
-        /* search gunzip executable */
-        if (!(Path = getenv("GMX_PATH_GZIP")))
-        {
-            if (gmx_fexist("/bin/gunzip"))
-            {
-                sprintf(gunzip, "%s", "/bin/gunzip");
-            }
-            else if (gmx_fexist("/usr/bin/gunzip"))
-            {
-                sprintf(gunzip, "%s", "/usr/bin/gunzip");
-            }
-            else
-            {
-                gmx_fatal(FARGS,
-                          "Cannot find executable gunzip in /bin or /usr/bin.\n"
-                          "You may want to define the path to gunzip "
-                          "with the environment variable GMX_PATH_GZIP.");
-            }
-        }
-        else
-        {
-            sprintf(gunzip, "%s/gunzip", Path);
-            if (!gmx_fexist(gunzip))
-            {
-                gmx_fatal(FARGS,
-                          "Cannot find executable %s. Please define the path to gunzip"
-                          " in the environmental varialbe GMX_PATH_GZIP.",
-                          gunzip);
-            }
-        }
-        if (bFirst)
-        {
-            printf("Using gunzip executable %s\n", gunzip);
-            bFirst = false;
-        }
-        if (!gmx_fexist(fn))
-        {
-            gmx_fatal(FARGS, "File %s does not exist.\n", fn);
-        }
-        sprintf(Buffer, "%s -c < %s", gunzip, fn);
-        if (opt->verbose)
-        {
-            printf("Executing command '%s'\n", Buffer);
-        }
-#if HAVE_PIPES
-        if ((pipe = popen(Buffer, "r")) == nullptr)
-        {
-            gmx_fatal(FARGS, "Unable to open pipe to `%s'\n", Buffer);
-        }
-#else
-        gmx_fatal(FARGS, "Cannot open a compressed file on platform without pipe support");
-#endif
-        *bPipeOpen = TRUE;
-    }
-    else
-    {
-        pipe       = gmx_ffopen(fn, "r");
-        *bPipeOpen = FALSE;
-    }
-
-    return pipe;
-}
-
-//! Close file or pipe
-static void pdo_close_file(FILE* fp)
-{
-#if HAVE_PIPES
-    pclose(fp);
-#else
-    gmx_ffclose(fp);
-#endif
-}
-
-//! Reading all pdo files
-static void read_pdo_files(char** fn, int nfiles, t_UmbrellaHeader* header, t_UmbrellaWindow* window, t_UmbrellaOptions* opt)
-{
-    FILE*    file;
-    real     mintmp, maxtmp, done = 0.;
-    int      i;
-    gmx_bool bPipeOpen;
-    /* char Buffer0[1000]; */
-
-    if (nfiles < 1)
-    {
-        gmx_fatal(FARGS, "No files found. Hick.");
-    }
-
-    /* if min and max are not given, get min and max from the input files */
-    if (opt->bAuto)
-    {
-        printf("Automatic determination of boundaries from %d pdo files...\n", nfiles);
-        opt->min = 1e20;
-        opt->max = -1e20;
-        for (i = 0; i < nfiles; ++i)
-        {
-            file = open_pdo_pipe(fn[i], opt, &bPipeOpen);
-            /*fgets(Buffer0,999,file);
-               fprintf(stderr,"First line '%s'\n",Buffer0); */
-            done = 100.0 * (i + 1) / nfiles;
-            fprintf(stdout, "\rOpening %s ... [%2.0f%%]", fn[i], done);
-            fflush(stdout);
-            if (opt->verbose)
-            {
-                printf("\n");
-            }
-            read_pdo_header(file, header, opt);
-            /* here only determine min and max of this window */
-            read_pdo_data(file, header, i, nullptr, opt, TRUE, &mintmp, &maxtmp);
-            if (maxtmp > opt->max)
-            {
-                opt->max = maxtmp;
-            }
-            if (mintmp < opt->min)
-            {
-                opt->min = mintmp;
-            }
-            if (bPipeOpen)
-            {
-                pdo_close_file(file);
-            }
-            else
-            {
-                gmx_ffclose(file);
-            }
-        }
-        printf("\n");
-        printf("\nDetermined boundaries to %f and %f\n\n", opt->min, opt->max);
-        if (opt->bBoundsOnly)
-        {
-            printf("Found option -boundsonly, now exiting.\n");
-            exit(0);
-        }
-    }
-    /* store stepsize in profile */
-    opt->dz = (opt->max - opt->min) / opt->bins;
-
-    /* Having min and max, we read in all files */
-    /* Loop over all files */
-    for (i = 0; i < nfiles; ++i)
-    {
-        done = 100.0 * (i + 1) / nfiles;
-        fprintf(stdout, "\rOpening %s ... [%2.0f%%]", fn[i], done);
-        fflush(stdout);
-        if (opt->verbose)
-        {
-            printf("\n");
-        }
-        file = open_pdo_pipe(fn[i], opt, &bPipeOpen);
-        read_pdo_header(file, header, opt);
-        /* load data into window */
-        read_pdo_data(file, header, i, window, opt, FALSE, nullptr, nullptr);
-        if ((window + i)->Ntot[0] == 0)
-        {
-            fprintf(stderr, "\nWARNING, no data points read from file %s (check -b option)\n", fn[i]);
-        }
-        if (bPipeOpen)
-        {
-            pdo_close_file(file);
-        }
-        else
-        {
-            gmx_ffclose(file);
-        }
-    }
-    printf("\n");
-    for (i = 0; i < nfiles; ++i)
-    {
-        sfree(fn[i]);
-    }
-    sfree(fn);
-}
-
 //! translate 0/1 to N/Y to write pull dimensions
 #define int2YN(a) (((a) == 0) ? ("N") : ("Y"))
 
@@ -2083,18 +1580,17 @@ static void read_tpr_header(const char* fn, t_UmbrellaHeader* header, t_Umbrella
          * so we need to multiply with the internal units (radians for angle)
          * to user units (degrees for an angle) with the same power.
          */
-        header->pcrd[i].k =
-                ir->pull->coord[i].k
-                / gmx::square(pull_conversion_factor_internal2userinput(&ir->pull->coord[i]));
+        header->pcrd[i].k = ir->pull->coord[i].k
+                            / gmx::square(pull_conversion_factor_internal2userinput(ir->pull->coord[i]));
         header->pcrd[i].init_dist = ir->pull->coord[i].init;
 
         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]));
+        std::strcpy(header->pcrd[i].coord_unit, pull_coordinate_units(ir->pull->coord[i]));
 
-        if (ir->efep != efepNO && ir->pull->coord[i].k != ir->pull->coord[i].kB)
+        if (ir->efep != FreeEnergyPerturbationType::No && 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 "
@@ -2106,26 +1602,30 @@ static void read_tpr_header(const char* fn, t_UmbrellaHeader* header, t_Umbrella
             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);
+                      ir->pull->ncoord,
+                      fn,
+                      coordsel->n);
         }
     }
 
     /* Check pull coords for consistency */
-    int  geom          = -1;
-    ivec thedim        = { 0, 0, 0 };
-    bool geometryIsSet = false;
+    PullGroupGeometry geom          = PullGroupGeometry::Count;
+    ivec              thedim        = { 0, 0, 0 };
+    bool              geometryIsSet = false;
     for (int i = 0; i < ir->pull->ncoord; i++)
     {
         if (coordsel == nullptr || coordsel->bUse[i])
         {
-            if (header->pcrd[i].pull_type != epullUMBRELLA)
+            if (header->pcrd[i].pull_type != PullingAlgorithm::Umbrella)
             {
                 gmx_fatal(FARGS,
                           "%s: Pull coordinate %d is of type \"%s\", expected \"umbrella\". Only "
                           "umbrella coodinates can enter WHAM.\n"
                           "If you have umrella and non-umbrella coordinates, you can select the "
                           "umbrella coordinates with gmx wham -is\n",
-                          fn, i + 1, epull_names[header->pcrd[i].pull_type]);
+                          fn,
+                          i + 1,
+                          enumValueToString(header->pcrd[i].pull_type));
             }
             if (!geometryIsSet)
             {
@@ -2140,7 +1640,10 @@ static void read_tpr_header(const char* fn, t_UmbrellaHeader* header, t_Umbrella
                           "%s, coordinate %d: %s)\n"
                           "If you want to use only some pull coordinates in WHAM, please select "
                           "them with option gmx wham -is\n",
-                          fn, epullg_names[geom], i + 1, epullg_names[header->pcrd[i].geometry]);
+                          fn,
+                          enumValueToString(geom),
+                          i + 1,
+                          enumValueToString(header->pcrd[i].geometry));
             }
             if (thedim[XX] != header->pcrd[i].dim[XX] || thedim[YY] != header->pcrd[i].dim[YY]
                 || thedim[ZZ] != header->pcrd[i].dim[ZZ])
@@ -2150,11 +1653,16 @@ static void read_tpr_header(const char* fn, t_UmbrellaHeader* header, t_Umbrella
                           "%s %s %s, coordinate %d: %s %s %s)\n"
                           "If you want to use only some pull coordinates in WHAM, please select "
                           "them with option gmx wham -is\n",
-                          fn, int2YN(thedim[XX]), int2YN(thedim[YY]), int2YN(thedim[ZZ]), i + 1,
-                          int2YN(header->pcrd[i].dim[XX]), int2YN(header->pcrd[i].dim[YY]),
+                          fn,
+                          int2YN(thedim[XX]),
+                          int2YN(thedim[YY]),
+                          int2YN(thedim[ZZ]),
+                          i + 1,
+                          int2YN(header->pcrd[i].dim[XX]),
+                          int2YN(header->pcrd[i].dim[YY]),
                           int2YN(header->pcrd[i].dim[ZZ]));
             }
-            if (header->pcrd[i].geometry == epullgCYL)
+            if (header->pcrd[i].geometry == PullGroupGeometry::Cylinder)
             {
                 if (header->pcrd[i].dim[XX] || header->pcrd[i].dim[YY] || (!header->pcrd[i].dim[ZZ]))
                 {
@@ -2162,7 +1670,8 @@ static void read_tpr_header(const char* fn, t_UmbrellaHeader* header, t_Umbrella
                             FARGS,
                             "With pull geometry 'cylinder', expected pulling in Z direction only.\n"
                             "However, found dimensions [%s %s %s]\n",
-                            int2YN(header->pcrd[i].dim[XX]), int2YN(header->pcrd[i].dim[YY]),
+                            int2YN(header->pcrd[i].dim[XX]),
+                            int2YN(header->pcrd[i].dim[YY]),
                             int2YN(header->pcrd[i].dim[ZZ]));
                 }
             }
@@ -2171,7 +1680,9 @@ static void read_tpr_header(const char* fn, t_UmbrellaHeader* header, t_Umbrella
                 gmx_fatal(FARGS,
                           "%s: Pull coordinate %d has force constant of of %g.\n"
                           "That doesn't seem to be an Umbrella tpr.\n",
-                          fn, i + 1, header->pcrd[i].k);
+                          fn,
+                          i + 1,
+                          header->pcrd[i].k);
             }
         }
     }
@@ -2182,7 +1693,7 @@ static void read_tpr_header(const char* fn, t_UmbrellaHeader* header, t_Umbrella
         int maxlen = 0;
         for (int i = 0; i < ir->pull->ncoord; i++)
         {
-            int lentmp = strlen(epullg_names[header->pcrd[i].geometry]);
+            int lentmp = strlen(enumValueToString(header->pcrd[i].geometry));
             maxlen     = (lentmp > maxlen) ? lentmp : maxlen;
         }
         char fmt[STRLEN];
@@ -2193,9 +1704,15 @@ static void read_tpr_header(const char* fn, t_UmbrellaHeader* header, t_Umbrella
         for (int i = 0; i < ir->pull->ncoord; i++)
         {
             bool use = (coordsel == nullptr || 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(fmt,
+                   enumValueToString(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);
         }
@@ -2301,7 +1818,9 @@ static void read_pull_xf(const char*        fn,
             printf("\t\treaction coordinate:             %d\n"
                    "\t\tcenter-of-mass of groups:        %d\n"
                    "\t\treference position column:       %s\n",
-                   1, nColCOMCrd[i], (header->bPrintRefValue ? "Yes" : "No"));
+                   1,
+                   nColCOMCrd[i],
+                   (header->bPrintRefValue ? "Yes" : "No"));
         }
         printf("\tFound %d times in %s\n", nt, fn);
         bFirst = FALSE;
@@ -2311,7 +1830,9 @@ static void read_pull_xf(const char*        fn,
         gmx_fatal(FARGS,
                   "Expected %d columns (including time column) in %s, but found %d."
                   " Maybe you confused options -if and -ix ?",
-                  nColExpect, fn, ny);
+                  nColExpect,
+                  fn,
+                  ny);
     }
 
     if (!bGetMinMax)
@@ -2338,7 +1859,8 @@ static void read_pull_xf(const char*        fn,
                 gmx_fatal(FARGS,
                           "tpr file contains %d pull groups, but expected %d from group selection "
                           "file\n",
-                          header->npullcrds, coordsel->n);
+                          header->npullcrds,
+                          coordsel->n);
             }
             window->nPull = coordsel->nUse;
         }
@@ -2409,7 +1931,7 @@ static void read_pull_xf(const char*        fn,
         /* Do you want that time frame? */
         t = 1.0 / 1000 * (gmx::roundToInt64((y[0][i] * 1000))); /* round time to fs */
 
-        /* get time step of pdo file and get dstep from opt->dt */
+        /* get time step and get dstep from opt->dt */
         if (i == 0)
         {
             time0 = t;
@@ -2491,7 +2013,8 @@ static void read_pull_xf(const char*        fn,
                         gmx_fatal(FARGS,
                                   "gUsed too large (%d, nPull=%d). This error should have been "
                                   "caught before.\n",
-                                  gUsed, window->nPull);
+                                  gUsed,
+                                  window->nPull);
                     }
 
                     if (opt->bCalcTauInt && !bGetMinMax)
@@ -2579,9 +2102,16 @@ static void read_tpr_pullxf_files(char**             fnTprs,
             if (whaminFileType(fnPull[i]) != whamin_pullxf)
             {
                 gmx_fatal(FARGS,
-                          "Expected the %d'th file in input file to be a xvg (pullx/pullf) file\n", i);
-            }
-            read_pull_xf(fnPull[i], header, nullptr, opt, TRUE, &mintmp, &maxtmp,
+                          "Expected the %d'th file in input file to be a xvg (pullx/pullf) file\n",
+                          i);
+            }
+            read_pull_xf(fnPull[i],
+                         header,
+                         nullptr,
+                         opt,
+                         TRUE,
+                         &mintmp,
+                         &maxtmp,
                          (opt->nCoordsel > 0) ? &opt->coordsel[i] : nullptr);
             if (maxtmp > opt->max)
             {
@@ -2612,10 +2142,16 @@ static void read_tpr_pullxf_files(char**             fnTprs,
         read_tpr_header(fnTprs[i], header, opt, (opt->nCoordsel > 0) ? &opt->coordsel[i] : nullptr);
         if (whaminFileType(fnPull[i]) != whamin_pullxf)
         {
-            gmx_fatal(FARGS,
-                      "Expected the %d'th file in input file to be a xvg (pullx/pullf) file\n", i);
+            gmx_fatal(
+                    FARGS, "Expected the %d'th file in input file to be a xvg (pullx/pullf) file\n", i);
         }
-        read_pull_xf(fnPull[i], header, window + i, opt, FALSE, nullptr, nullptr,
+        read_pull_xf(fnPull[i],
+                     header,
+                     window + i,
+                     opt,
+                     FALSE,
+                     nullptr,
+                     nullptr,
                      (opt->nCoordsel > 0) ? &opt->coordsel[i] : nullptr);
         if (window[i].Ntot[0] == 0)
         {
@@ -2656,8 +2192,11 @@ static void readIntegratedAutocorrelationTimes(t_UmbrellaWindow* window, int nwi
     nlines = read_xvg(fn, &iact, &ny);
     if (nlines != nwins)
     {
-        gmx_fatal(FARGS, "Found %d lines with integrated autocorrelation times in %s.\nExpected %d",
-                  nlines, fn, nwins);
+        gmx_fatal(FARGS,
+                  "Found %d lines with integrated autocorrelation times in %s.\nExpected %d",
+                  nlines,
+                  fn,
+                  nwins);
     }
     for (i = 0; i < nlines; i++)
     {
@@ -2758,14 +2297,18 @@ static void calcIntegratedAutocorrelationTimes(t_UmbrellaWindow*  window,
 
     if (opt->verbose)
     {
-        fpcorr = xvgropen("hist_autocorr.xvg", "Autocorrelation functions of umbrella windows",
-                          "time [ps]", "autocorrelation function", opt->oenv);
+        fpcorr = xvgropen("hist_autocorr.xvg",
+                          "Autocorrelation functions of umbrella windows",
+                          "time [ps]",
+                          "autocorrelation function",
+                          opt->oenv);
     }
 
     printf("\n");
     for (i = 0; i < nwins; i++)
     {
-        fprintf(stdout, "\rEstimating integrated autocorrelation times ... [%2.0f%%] ...",
+        fprintf(stdout,
+                "\rEstimating integrated autocorrelation times ... [%2.0f%%] ...",
                 100. * (i + 1) / nwins);
         fflush(stdout);
         ntot = window[i].Ntot[0];
@@ -2797,7 +2340,8 @@ static void calcIntegratedAutocorrelationTimes(t_UmbrellaWindow*  window,
                 gmx_fatal(FARGS,
                           "Encountered different nr of frames in different pull groups.\n"
                           "That should not happen. (%d and %d)\n",
-                          ntot, window[i].Ntot[ig]);
+                          ntot,
+                          window[i].Ntot[ig]);
             }
             ztime = window[i].ztime[ig];
 
@@ -3064,7 +2608,8 @@ static void checkReactionCoordinateCovered(t_UmbrellaWindow* window, int nwins,
             fprintf(stderr,
                     "\nWARNING, no data point in bin %d (z=%g) !\n"
                     "You may not get a reasonable profile. Check your histograms!\n",
-                    j, z);
+                    j,
+                    z);
         }
         /* and check for poor sampling */
         else if (relcount < 0.005 && !bBoundary)
@@ -3166,7 +2711,7 @@ static void guessPotByIntegration(t_UmbrellaWindow* window, int nWindows, t_Umbr
      */
     for (j = 0; j < opt->bins; ++j)
     {
-        pot[j] = std::exp(-pot[j] / (BOLTZ * opt->Temperature));
+        pot[j] = std::exp(-pot[j] / (gmx::c_boltz * opt->Temperature));
     }
     calc_z(pot, window, nWindows, opt, TRUE);
 
@@ -3256,7 +2801,9 @@ static void readPullCoordSelection(t_UmbrellaOptions* opt, char** fnTpr, int nTp
     printf("\nUse only these pull coordinates:\n");
     for (iline = 0; iline < nTpr; iline++)
     {
-        printf("%s (%d of %d coordinates):", fnTpr[iline], opt->coordsel[iline].nUse,
+        printf("%s (%d of %d coordinates):",
+               fnTpr[iline],
+               opt->coordsel[iline].nUse,
                opt->coordsel[iline].n);
         for (i = 0; i < opt->coordsel[iline].n; i++)
         {
@@ -3303,27 +2850,7 @@ int gmx_wham(int argc, char* argv[])
         "  provides the pull force output file names ([TT]pullf.xvg[tt]) with option [TT]-if[tt].",
         "  From the pull force the position in the umbrella potential is",
         "  computed. This does not work with tabulated umbrella potentials.",
-        "* With option [TT]-ip[tt], the user provides file names of (gzipped) [REF].pdo[ref] ",
-        "  files, i.e.",
-        "  the GROMACS 3.3 umbrella output files. If you have some unusual",
-        "  reaction coordinate you may also generate your own [REF].pdo[ref] files and",
-        "  feed them with the [TT]-ip[tt] option into to [THISMODULE]. The [REF].pdo[ref] file ",
-        "  header must be similar to the following::",
-        "",
-        "  # UMBRELLA      3.0",
-        "  # Component selection: 0 0 1",
-        "  # nSkip 1",
-        "  # Ref. Group 'TestAtom'",
-        "  # Nr. of pull groups 2",
-        "  # Group 1 'GR1'  Umb. Pos. 5.0 Umb. Cons. 1000.0",
-        "  # Group 2 'GR2'  Umb. Pos. 2.0 Umb. Cons. 500.0",
-        "  #####",
         "",
-        "  The number of pull groups, umbrella positions, force constants, and names ",
-        "  may (of course) differ. Following the header, a time column and ",
-        "  a data column for each pull group follows (i.e. the displacement",
-        "  with respect to the umbrella center). Up to four pull groups are possible ",
-        "  per [REF].pdo[ref] file at present.[PAR]",
         "By default, all pull coordinates found in all pullx/pullf files are used in WHAM. If ",
         "only ",
         "some of the pull coordinates should be used, a pull coordinate selection file (option ",
@@ -3348,7 +2875,7 @@ int gmx_wham(int argc, char* argv[])
         "",
         "Always check whether the histograms sufficiently overlap.[PAR]",
         "The umbrella potential is assumed to be harmonic and the force constants are ",
-        "read from the [REF].tpr[ref] or [REF].pdo[ref] files. If a non-harmonic umbrella force ",
+        "read from the [REF].tpr[ref] files. If a non-harmonic umbrella force ",
         "was applied ",
         "a tabulated potential can be provided with [TT]-tab[tt].",
         "",
@@ -3401,7 +2928,7 @@ int gmx_wham(int argc, char* argv[])
         "less robust) method such as fitting to a double exponential, you can ",
         "compute the IACTs with [gmx-analyze] and provide them to [THISMODULE] with the file ",
         "[TT]iact-in.dat[tt] (option [TT]-iiact[tt]), which should contain one line per ",
-        "input file ([REF].pdo[ref] or pullx/f file) and one column per pull coordinate in the ",
+        "input file (pullx/pullf file) and one column per pull coordinate in the ",
         "respective file.",
         "",
         "Error analysis",
@@ -3553,7 +3080,6 @@ int gmx_wham(int argc, char* argv[])
         { efDAT, "-ix", "pullx-files", ffOPTRD }, /* wham input: pullf.xvg's and tprs           */
         { efDAT, "-if", "pullf-files", ffOPTRD }, /* wham input: pullf.xvg's and tprs           */
         { efDAT, "-it", "tpr-files", ffOPTRD },   /* wham input: tprs                           */
-        { efDAT, "-ip", "pdo-files", ffOPTRD },   /* wham input: pdo files (gmx3 style)         */
         { efDAT, "-is", "coordsel", ffOPTRD },    /* input: select pull coords to use           */
         { efXVG, "-o", "profile", ffWRITE },      /* output file for profile                     */
         { efXVG, "-hist", "histo", ffWRITE },     /* output file for histograms                  */
@@ -3569,7 +3095,7 @@ int gmx_wham(int argc, char* argv[])
     t_UmbrellaWindow* window = nullptr;
     double *          profile, maxchange = 1e20;
     gmx_bool          bMinSet, bMaxSet, bAutoSet, bExact = FALSE;
-    char **           fninTpr, **fninPull, **fninPdo;
+    char **           fninTpr, **fninPull;
     const char*       fnPull;
     FILE *            histout, *profout;
     char              xlabel[STRLEN], ylabel[256], title[256];
@@ -3610,8 +3136,8 @@ int gmx_wham(int argc, char* argv[])
     opt.stepchange            = 100;
     opt.stepUpdateContrib     = 100;
 
-    if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr,
-                           &opt.oenv))
+    if (!parse_common_args(
+                &argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &opt.oenv))
     {
         return 0;
     }
@@ -3622,7 +3148,6 @@ int gmx_wham(int argc, char* argv[])
     opt.bProf0Set = opt2parg_bSet("-zprof0", asize(pa), pa);
 
     opt.bTab         = opt2bSet("-tab", NFILE, fnm);
-    opt.bPdo         = opt2bSet("-ip", NFILE, fnm);
     opt.bTpr         = opt2bSet("-it", NFILE, fnm);
     opt.bPullx       = opt2bSet("-ix", NFILE, fnm);
     opt.bPullf       = opt2bSet("-if", NFILE, fnm);
@@ -3631,21 +3156,14 @@ int gmx_wham(int argc, char* argv[])
     {
         gmx_fatal(FARGS,
                   "Force input does not work with tabulated potentials. "
-                  "Provide pullx.xvg or pdo files!");
+                  "Provide pullx.xvg files!");
     }
 
-    if (!opt.bPdo && !WHAMBOOLXOR(opt.bPullx, opt.bPullf))
+    if (!WHAMBOOLXOR(opt.bPullx, opt.bPullf))
     {
         gmx_fatal(FARGS, "Give either pullx (-ix) OR pullf (-if) data. Not both.");
     }
-    if (!opt.bPdo && !(opt.bTpr || opt.bPullf || opt.bPullx))
-    {
-        gmx_fatal(FARGS,
-                  "gmx wham supports three input modes, pullx, pullf, or pdo file input."
-                  "\n\n Check gmx wham -h !");
-    }
 
-    opt.fnPdo      = opt2fn("-ip", NFILE, fnm);
     opt.fnTpr      = opt2fn("-it", NFILE, fnm);
     opt.fnPullf    = opt2fn("-if", NFILE, fnm);
     opt.fnPullx    = opt2fn("-ix", NFILE, fnm);
@@ -3691,43 +3209,30 @@ int gmx_wham(int argc, char* argv[])
     }
 
     /* Reading gmx4/gmx5 pull output and tpr files */
-    if (opt.bTpr || opt.bPullf || opt.bPullx)
-    {
-        read_wham_in(opt.fnTpr, &fninTpr, &nfiles, &opt);
-
-        fnPull = opt.bPullf ? opt.fnPullf : opt.fnPullx;
-        read_wham_in(fnPull, &fninPull, &nfiles2, &opt);
-        printf("Found %d tpr and %d pull %s files in %s and %s, respectively\n", nfiles, nfiles2,
-               opt.bPullf ? "force" : "position", opt.fnTpr, fnPull);
-        if (nfiles != nfiles2)
-        {
-            gmx_fatal(FARGS, "Found %d file names in %s, but %d in %s\n", nfiles, opt.fnTpr, nfiles2, fnPull);
-        }
-
-        /* Read file that selects the pull group to be used */
-        if (opt.fnCoordSel != nullptr)
-        {
-            readPullCoordSelection(&opt, fninTpr, nfiles);
-        }
+    read_wham_in(opt.fnTpr, &fninTpr, &nfiles, &opt);
 
-        window = initUmbrellaWindows(nfiles);
-        read_tpr_pullxf_files(fninTpr, fninPull, nfiles, &header, window, &opt);
+    fnPull = opt.bPullf ? opt.fnPullf : opt.fnPullx;
+    read_wham_in(fnPull, &fninPull, &nfiles2, &opt);
+    printf("Found %d tpr and %d pull %s files in %s and %s, respectively\n",
+           nfiles,
+           nfiles2,
+           opt.bPullf ? "force" : "position",
+           opt.fnTpr,
+           fnPull);
+    if (nfiles != nfiles2)
+    {
+        gmx_fatal(FARGS, "Found %d file names in %s, but %d in %s\n", nfiles, opt.fnTpr, nfiles2, fnPull);
     }
-    else
-    { /* reading pdo files */
-        if (opt.fnCoordSel != nullptr)
-        {
-            gmx_fatal(FARGS,
-                      "Reading a -is file is not supported with PDO input files.\n"
-                      "Use awk or a similar tool to pick the required pull groups from your PDO "
-                      "files\n");
-        }
-        read_wham_in(opt.fnPdo, &fninPdo, &nfiles, &opt);
-        printf("Found %d pdo files in %s\n", nfiles, opt.fnPdo);
-        window = initUmbrellaWindows(nfiles);
-        read_pdo_files(fninPdo, nfiles, &header, window, &opt);
+
+    /* Read file that selects the pull group to be used */
+    if (opt.fnCoordSel != nullptr)
+    {
+        readPullCoordSelection(&opt, fninTpr, nfiles);
     }
 
+    window = initUmbrellaWindows(nfiles);
+    read_tpr_pullxf_files(fninTpr, fninPull, nfiles, &header, window, &opt);
+
     /* It is currently assumed that all pull coordinates have the same geometry, so they also have the same coordinate units.
        We can therefore get the units for the xlabel from the first coordinate. */
     sprintf(xlabel, "\\xx\\f{} (%s)", header.pcrd[0].coord_unit);
@@ -3860,8 +3365,15 @@ int gmx_wham(int argc, char* argv[])
     /* Bootstrap Method */
     if (opt.nBootStrap)
     {
-        do_bootstrapping(opt2fn("-bsres", NFILE, fnm), opt2fn("-bsprof", NFILE, fnm),
-                         opt2fn("-hist", NFILE, fnm), xlabel, ylabel, profile, window, nwins, &opt);
+        do_bootstrapping(opt2fn("-bsres", NFILE, fnm),
+                         opt2fn("-bsprof", NFILE, fnm),
+                         opt2fn("-hist", NFILE, fnm),
+                         xlabel,
+                         ylabel,
+                         profile,
+                         window,
+                         nwins,
+                         &opt);
     }
 
     sfree(profile);
index dbb5514dd03df56fca5ad6b5d135e02e369dac08..516d76d480d5f1f3962d601393c3742af3559ac8 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -121,13 +121,13 @@ static void wheel(const char* fn, int nres, char* resnm[], int r0, real rot0, ch
     xc           = box;
     yc           = box;
 
-    ps_font(&out, efontHELV, 1.5 * fontsize);
+    ps_font(&out, Fonts::Helvetica, 1.5 * fontsize);
     ps_translate(&out, xc, yc);
     if (title)
     {
         ps_ctext(&out, 0, -fontsize * 1.5 / 2.0, title, eXCenter);
     }
-    ps_font(&out, efontHELV, fontsize);
+    ps_font(&out, Fonts::Helvetica, fontsize);
     ps_rotate(&out, rot0);
     for (i = 0; (i < nres);)
     {
@@ -179,14 +179,14 @@ static void wheel2(const char* fn, int nres, char* resnm[], real rot0, char* tit
     xc           = box;
     yc           = box;
 
-    ps_font(&out, efontHELV, 1.5 * fontsize);
+    ps_font(&out, Fonts::Helvetica, 1.5 * fontsize);
     ps_translate(&out, xc, yc);
     ps_color(&out, 0, 0, 0);
     if (title)
     {
         ps_ctext(&out, 0, -fontsize * 1.5 / 2.0, title, eXCenter);
     }
-    ps_font(&out, efontHELV, fontsize);
+    ps_font(&out, Fonts::Helvetica, fontsize);
 
     ps_rotate(&out, rot0);
     for (i = 0; (i < nres);)
@@ -220,10 +220,10 @@ int gmx_wheel(int argc, char* argv[])
         "the number of residues and each consecutive line contains a residue name."
     };
     gmx_output_env_t* oenv;
-    static real       rot0  = 0;
-    static gmx_bool   bNum  = TRUE;
-    static char*      title = nullptr;
-    static int        r0    = 1;
+    real              rot0  = 0;
+    gmx_bool          bNum  = TRUE;
+    char*             title = nullptr;
+    int               r0    = 1;
     t_pargs  pa[]  = { { "-r0", FALSE, etINT, { &r0 }, "The first residue number in the sequence" },
                      { "-rot0",
                        FALSE,
index 579e7b236914d319eb09eca6dac603eaaa382299..19cf4393f9ce2f42c0f1e577034cdf2279212b62 100644 (file)
@@ -207,10 +207,13 @@ static void get_params(const char* mpin, const char* mpout, t_psrec* psr)
     done_warning(wi, FARGS);
 }
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static t_rgb black = { 0, 0, 0 };
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static t_rgb white = { 1, 1, 1 };
 #define BLACK (&black)
 /* this must correspond to *colors[] in get_params */
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static t_rgb* linecolors[] = { nullptr, &black, &white, nullptr };
 
 static void leg_discrete(t_psdata*                      ps,
@@ -422,8 +425,7 @@ static void draw_boxes(t_psdata* ps, real x0, real y0, real w, gmx::ArrayRef<t_m
                 /* Plot label on lowest graph only */
                 if (m == mat.begin())
                 {
-                    ps_ctext(ps, xx, yy00 - DDD - psr->X.majorticklen - psr->X.tickfontsize * 0.8,
-                             xtick[x], eXCenter);
+                    ps_ctext(ps, xx, yy00 - DDD - psr->X.majorticklen - psr->X.tickfontsize * 0.8, xtick[x], eXCenter);
                 }
             }
             else if (bRmod(m->axis_x[x], psr->X.offset, psr->X.minor)
@@ -454,8 +456,7 @@ static void draw_boxes(t_psdata* ps, real x0, real y0, real w, gmx::ArrayRef<t_m
                 /* Major ticks */
                 strlength = std::max(strlength, std::strlen(ytick[y]));
                 ps_line(ps, xx00, yy, xx00 - psr->Y.majorticklen, yy);
-                ps_ctext(ps, xx00 - psr->Y.majorticklen - DDD, yy - psr->Y.tickfontsize / 3.0,
-                         ytick[y], eXRight);
+                ps_ctext(ps, xx00 - psr->Y.majorticklen - DDD, yy - psr->Y.tickfontsize / 3.0, ytick[y], eXRight);
             }
             else if (bRmod(m->axis_y[y], psr->Y.offset, psr->Y.minor))
             {
@@ -503,9 +504,11 @@ static void draw_boxes(t_psdata* ps, real x0, real y0, real w, gmx::ArrayRef<t_m
     if (!mylab.empty())
     {
         ps_strfont(ps, psr->X.font, psr->X.fontsize);
-        ps_ctext(ps, x0 + w / 2,
+        ps_ctext(ps,
+                 x0 + w / 2,
                  y0 - DDD - psr->X.majorticklen - psr->X.tickfontsize * FUDGE - psr->X.fontsize,
-                 mylab, eXCenter);
+                 mylab,
+                 eXCenter);
     }
 }
 
@@ -641,8 +644,10 @@ static std::vector<t_mapping> add_maps(gmx::ArrayRef<t_mapping> map1, gmx::Array
     {
         gmx_fatal(FARGS, "Not enough symbols to merge the two colormaps\n");
     }
-    printf("Combining colormaps of %zu and %zu elements into one of %zu elements\n", map1.size(),
-           map2.size(), map.size());
+    printf("Combining colormaps of %zu and %zu elements into one of %zu elements\n",
+           map1.size(),
+           map2.size(),
+           map.size());
     gmx::index k = 0;
     for (gmx::index j = 0; j < gmx::ssize(map1) && k < gmx::ssize(map); ++j, ++k)
     {
@@ -814,7 +819,11 @@ static void ps_mat(const char*             outf,
     if (psr->X.major <= 0)
     {
         tick_spacing((mat[0].flags & MAT_SPATIAL_X) ? mat[0].nx + 1 : mat[0].nx,
-                     mat[0].axis_x.data(), psr->X.offset, 'X', &(psr->X.major), &(psr->X.minor));
+                     mat[0].axis_x.data(),
+                     psr->X.offset,
+                     'X',
+                     &(psr->X.major),
+                     &(psr->X.minor));
     }
     if (psr->X.minor <= 0)
     {
@@ -823,7 +832,11 @@ static void ps_mat(const char*             outf,
     if (psr->Y.major <= 0)
     {
         tick_spacing((mat[0].flags & MAT_SPATIAL_Y) ? mat[0].ny + 1 : mat[0].ny,
-                     mat[0].axis_y.data(), psr->Y.offset, 'Y', &(psr->Y.major), &(psr->Y.minor));
+                     mat[0].axis_y.data(),
+                     psr->Y.offset,
+                     'Y',
+                     &(psr->Y.major),
+                     &(psr->Y.minor));
     }
     if (psr->Y.minor <= 0)
     {
@@ -1031,14 +1044,14 @@ static void ps_mat(const char*             outf,
         {
             if (elegend != elBoth)
             {
-                leg_continuous(&out, x0 + w / 2, w / 2, DDD, legend, psr->legfontsize, psr->legfont,
-                               leg_map, mapoffset);
+                leg_continuous(
+                        &out, x0 + w / 2, w / 2, DDD, legend, psr->legfontsize, psr->legfont, leg_map, mapoffset);
             }
             else
             {
                 assert(!mat2.empty());
-                leg_bicontinuous(&out, x0 + w / 2, w, DDD, mat[0].legend, mat2[0].legend,
-                                 psr->legfontsize, psr->legfont, map1, map2);
+                leg_bicontinuous(
+                        &out, x0 + w / 2, w, DDD, mat[0].legend, mat2[0].legend, psr->legfontsize, psr->legfont, map1, map2);
             }
         }
         ps_comment(&out, "Done processing");
@@ -1072,8 +1085,12 @@ static void prune_mat(gmx::ArrayRef<t_matrix> mat, gmx::ArrayRef<t_matrix> mat2,
                        "Matrix pruning requires matrices of the same size");
     for (gmx::index i = 0; i != gmx::ssize(mat); ++i)
     {
-        fprintf(stderr, "converting %dx%d matrix to %dx%d\n", mat[i].nx, mat[i].ny,
-                (mat[i].nx + skip - 1) / skip, (mat[i].ny + skip - 1) / skip);
+        fprintf(stderr,
+                "converting %dx%d matrix to %dx%d\n",
+                mat[i].nx,
+                mat[i].ny,
+                (mat[i].nx + skip - 1) / skip,
+                (mat[i].ny + skip - 1) / skip);
         /* walk through matrix */
         int xs = 0;
         for (int x = 0; (x < mat[i].nx); x++)
@@ -1181,7 +1198,11 @@ static void write_combined_matrix(int                     ecombine,
             gmx_fatal(FARGS,
                       "Size of frame %zd in 1st (%dx%d) and 2nd matrix (%dx%d) do"
                       " not match.\n",
-                      k, mat1[k].nx, mat1[k].ny, mat2[k].nx, mat2[k].ny);
+                      k,
+                      mat1[k].nx,
+                      mat1[k].ny,
+                      mat2[k].nx,
+                      mat2[k].ny);
         }
         printf("Combining two %dx%d matrices\n", mat1[k].nx, mat1[k].ny);
         rmat1 = matrix2real(&mat1[k], nullptr);
@@ -1226,9 +1247,22 @@ static void write_combined_matrix(int                     ecombine,
         }
         else
         {
-            write_xpm(out, mat1[k].flags, mat1[k].title, mat1[k].legend, mat1[k].label_x,
-                      mat1[k].label_y, mat1[k].nx, mat1[k].ny, mat1[k].axis_x.data(),
-                      mat1[k].axis_y.data(), rmat1, rlo, rhi, white, black, &nlevels);
+            write_xpm(out,
+                      mat1[k].flags,
+                      mat1[k].title,
+                      mat1[k].legend,
+                      mat1[k].label_x,
+                      mat1[k].label_y,
+                      mat1[k].nx,
+                      mat1[k].ny,
+                      mat1[k].axis_x.data(),
+                      mat1[k].axis_y.data(),
+                      rmat1,
+                      rlo,
+                      rhi,
+                      white,
+                      black,
+                      &nlevels);
         }
     }
     gmx_ffclose(out);
@@ -1265,7 +1299,11 @@ static void do_mat(gmx::ArrayRef<t_matrix> mat,
                 gmx_fatal(FARGS,
                           "WAKE UP!! Size of frame %zd in 2nd matrix file (%dx%d) does not match "
                           "size of 1st matrix (%dx%d) or the other way around.\n",
-                          k, mat2[k].nx, mat2[k].ny, mat[k].nx, mat[k].ny);
+                          k,
+                          mat2[k].nx,
+                          mat2[k].ny,
+                          mat[k].nx,
+                          mat[k].ny);
             }
             for (int j = 0; (j < mat[k].ny); j++)
             {
@@ -1295,8 +1333,7 @@ static void do_mat(gmx::ArrayRef<t_matrix> mat,
 
     if (epsfile != nullptr)
     {
-        ps_mat(epsfile, mat, mat2, bFrame, bDiag, bFirstDiag, bTitle, bTitleOnce, bYonce, elegend,
-               size, boxx, boxy, m2p, m2pout, mapoffset);
+        ps_mat(epsfile, mat, mat2, bFrame, bDiag, bFirstDiag, bTitle, bTitleOnce, bYonce, elegend, size, boxx, boxy, m2p, m2pout, mapoffset);
     }
     if (xpmfile != nullptr)
     {
@@ -1503,8 +1540,8 @@ int gmx_xpm2ps(int argc, char* argv[])
                        { efEPS, "-o", nullptr, ffOPTWR },     { efXPM, "-xpm", nullptr, ffOPTWR } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, NPA, pa, asize(desc), desc, 0,
-                           nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW, NFILE, fnm, NPA, pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -1557,14 +1594,22 @@ int gmx_xpm2ps(int argc, char* argv[])
     fn = opt2fn("-f", NFILE, fnm);
     std::vector<t_matrix> mat, mat2;
     mat = read_xpm_matrix(fn);
-    fprintf(stderr, "There %s %zu matri%s in %s\n", (mat.size() > 1) ? "are" : "is", mat.size(),
-            (mat.size() > 1) ? "ces" : "x", fn);
+    fprintf(stderr,
+            "There %s %zu matri%s in %s\n",
+            (mat.size() > 1) ? "are" : "is",
+            mat.size(),
+            (mat.size() > 1) ? "ces" : "x",
+            fn);
     fn = opt2fn_null("-f2", NFILE, fnm);
     if (fn)
     {
         mat2 = read_xpm_matrix(fn);
-        fprintf(stderr, "There %s %zu matri%s in %s\n", (mat2.size() > 1) ? "are" : "is",
-                mat2.size(), (mat2.size() > 1) ? "ces" : "x", fn);
+        fprintf(stderr,
+                "There %s %zu matri%s in %s\n",
+                (mat2.size() > 1) ? "are" : "is",
+                mat2.size(),
+                (mat2.size() > 1) ? "ces" : "x",
+                fn);
         if (mat.size() != mat2.size())
         {
             fprintf(stderr, "Different number of matrices, using the smallest number.\n");
@@ -1626,14 +1671,34 @@ int gmx_xpm2ps(int argc, char* argv[])
 
     if (ecombine && ecombine != ecHalves)
     {
-        write_combined_matrix(ecombine, xpmfile, mat, mat2, opt2parg_bSet("-cmin", NPA, pa) ? &cmin : nullptr,
+        write_combined_matrix(ecombine,
+                              xpmfile,
+                              mat,
+                              mat2,
+                              opt2parg_bSet("-cmin", NPA, pa) ? &cmin : nullptr,
                               opt2parg_bSet("-cmax", NPA, pa) ? &cmax : nullptr);
     }
     else
     {
-        do_mat(mat, mat2, bFrame, bZeroLine, bDiag, bFirstDiag, bTitle, bTitleOnce, bYonce, elegend,
-               size, boxx, boxy, epsfile, xpmfile, opt2fn_null("-di", NFILE, fnm),
-               opt2fn_null("-do", NFILE, fnm), skip, mapoffset);
+        do_mat(mat,
+               mat2,
+               bFrame,
+               bZeroLine,
+               bDiag,
+               bFirstDiag,
+               bTitle,
+               bTitleOnce,
+               bYonce,
+               elegend,
+               size,
+               boxx,
+               boxy,
+               epsfile,
+               xpmfile,
+               opt2fn_null("-di", NFILE, fnm),
+               opt2fn_null("-do", NFILE, fnm),
+               skip,
+               mapoffset);
     }
 
     view_all(oenv, NFILE, fnm);
index 59206dd2ea61e1f5169738804c72cbcd72d4a1a1..6f66fd5a2ad437401dd8fead2a65fa76bf58e5da 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/listed_forces/bonded.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/topology/index.h"
 #include "gromacs/topology/topology.h"
@@ -143,7 +144,7 @@ static real rot(rvec x1, const rvec x2)
     xx   = cp * x2[XX] + sp * x2[YY];
     yy   = -sp * x2[XX] + cp * x2[YY];
 
-    dphi = RAD2DEG * std::atan2(yy, xx);
+    dphi = gmx::c_rad2Deg * std::atan2(yy, xx);
 
     return dphi;
 }
@@ -190,7 +191,7 @@ real ca_phi(int gnx, const int index[], rvec x[])
         aj  = index[i + 1];
         ak  = index[i + 2];
         al  = index[i + 3];
-        phi = RAD2DEG
+        phi = gmx::c_rad2Deg
               * dih_angle(x[ai], x[aj], x[ak], x[al], nullptr, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3);
         phitot += phi;
     }
@@ -329,30 +330,30 @@ t_bb* mkbbind(const char* fn,
 #define NBB asize(bb_nm)
     t_bb* bb;
     char* grpname;
-    int   ai, i, i0, i1, j, k, rnr, gnx, r0, r1;
+    int   gnx, r0, r1;
 
     fprintf(stderr, "Please select a group containing the entire backbone\n");
     rd_index(fn, 1, &gnx, index, &grpname);
     *nall = gnx;
     fprintf(stderr, "Checking group %s\n", grpname);
     r0 = r1 = atom[(*index)[0]].resind;
-    for (i = 1; (i < gnx); i++)
+    for (int i = 1; (i < gnx); i++)
     {
         r0 = std::min(r0, atom[(*index)[i]].resind);
         r1 = std::max(r1, atom[(*index)[i]].resind);
     }
-    rnr = r1 - r0 + 1;
+    int rnr = r1 - r0 + 1;
     fprintf(stderr, "There are %d residues\n", rnr);
     snew(bb, rnr);
-    for (i = 0; (i < rnr); i++)
+    for (int i = 0; (i < rnr); i++)
     {
         bb[i].N = bb[i].H = bb[i].CA = bb[i].C = bb[i].O = -1;
         bb[i].resno                                      = res0 + i;
     }
 
-    for (i = j = 0; (i < gnx); i++)
+    for (int i = 0; (i < gnx); i++)
     {
-        ai = (*index)[i];
+        int ai = (*index)[i];
         // Create an index into the residue index for the topology.
         int resindex = atom[ai].resind;
         // Create an index into the residues present in the selected
@@ -367,7 +368,8 @@ t_bb* mkbbind(const char* fn,
                 bb[bbindex].H = ai;
             }
         }
-        for (k = 0; (k < NBB); k++)
+        int k = 0;
+        for (; (k < NBB); k++)
         {
             if (std::strcmp(bb_nm[k], *(atomname[ai])) == 0)
             {
@@ -389,7 +391,8 @@ t_bb* mkbbind(const char* fn,
         }
     }
 
-    for (i0 = 0; (i0 < rnr); i0++)
+    int i0 = 0;
+    for (; (i0 < rnr); i0++)
     {
         if ((bb[i0].N != -1) && (bb[i0].H != -1) && (bb[i0].CA != -1) && (bb[i0].C != -1)
             && (bb[i0].O != -1))
@@ -397,7 +400,8 @@ t_bb* mkbbind(const char* fn,
             break;
         }
     }
-    for (i1 = rnr - 1; (i1 >= 0); i1--)
+    int i1 = rnr - 1;
+    for (; (i1 >= 0); i1--)
     {
         if ((bb[i1].N != -1) && (bb[i1].H != -1) && (bb[i1].CA != -1) && (bb[i1].C != -1)
             && (bb[i1].O != -1))
@@ -414,25 +418,24 @@ t_bb* mkbbind(const char* fn,
         i1--;
     }
 
-    for (i = i0; (i < i1); i++)
+    for (int i = i0; (i < i1); i++)
     {
         bb[i].Cprev = bb[i - 1].C;
         bb[i].Nnext = bb[i + 1].N;
     }
     rnr = std::max(0, i1 - i0 + 1);
-    fprintf(stderr, "There are %d complete backbone residues (from %d to %d)\n", rnr, bb[i0].resno,
-            bb[i1].resno);
+    fprintf(stderr, "There are %d complete backbone residues (from %d to %d)\n", rnr, bb[i0].resno, bb[i1].resno);
     if (rnr == 0)
     {
         gmx_fatal(FARGS, "Zero complete backbone residues were found, cannot proceed");
     }
-    for (i = 0; (i < rnr); i++, i0++)
+    for (int i = 0; (i < rnr); i++, i0++)
     {
         bb[i] = bb[i0];
     }
 
     /* Set the labels */
-    for (i = 0; (i < rnr); i++)
+    for (int i = 0; (i < rnr); i++)
     {
         int resindex = atom[bb[i].CA].resind;
         sprintf(bb[i].label, "%s%d", *(resinfo[resindex].name), resinfo[resindex].nr);
@@ -495,17 +498,39 @@ void calc_hxprops(int nres, t_bb bb[], const rvec x[])
             bb[i].d5 = norm(dx);
         }
 
-        bb[i].phi = RAD2DEG
-                    * dih_angle(x[bb[i].Cprev], x[bb[i].N], x[bb[i].CA], x[bb[i].C], nullptr, r_ij,
-                                r_kj, r_kl, m, n, &t1, &t2, &t3);
-        bb[i].psi = RAD2DEG
-                    * dih_angle(x[bb[i].N], x[bb[i].CA], x[bb[i].C], x[bb[i].Nnext], nullptr, r_ij,
-                                r_kj, r_kl, m, n, &t1, &t2, &t3);
+        bb[i].phi = gmx::c_rad2Deg
+                    * dih_angle(x[bb[i].Cprev],
+                                x[bb[i].N],
+                                x[bb[i].CA],
+                                x[bb[i].C],
+                                nullptr,
+                                r_ij,
+                                r_kj,
+                                r_kl,
+                                m,
+                                n,
+                                &t1,
+                                &t2,
+                                &t3);
+        bb[i].psi = gmx::c_rad2Deg
+                    * dih_angle(x[bb[i].N],
+                                x[bb[i].CA],
+                                x[bb[i].C],
+                                x[bb[i].Nnext],
+                                nullptr,
+                                r_ij,
+                                r_kj,
+                                r_kl,
+                                m,
+                                n,
+                                &t1,
+                                &t2,
+                                &t3);
         bb[i].pprms2 = gmx::square(bb[i].phi - PHI_AHX) + gmx::square(bb[i].psi - PSI_AHX);
 
-        bb[i].jcaha += 1.4 * std::sin((bb[i].psi + 138.0) * DEG2RAD)
-                       - 4.1 * std::cos(2.0 * DEG2RAD * (bb[i].psi + 138.0))
-                       + 2.0 * std::cos(2.0 * DEG2RAD * (bb[i].phi + 30.0));
+        bb[i].jcaha += 1.4 * std::sin((bb[i].psi + 138.0) * gmx::c_deg2Rad)
+                       - 4.1 * std::cos(2.0 * gmx::c_deg2Rad * (bb[i].psi + 138.0))
+                       + 2.0 * std::cos(2.0 * gmx::c_deg2Rad * (bb[i].phi + 30.0));
     }
 }
 
@@ -581,12 +606,33 @@ void pr_bb(FILE* fp, int nres, t_bb bb[])
     int i;
 
     fprintf(fp, "\n");
-    fprintf(fp, "%3s %3s %3s %3s %3s %7s %7s %7s %7s %7s %3s\n", "AA", "N", "Ca", "C", "O", "Phi",
-            "Psi", "D3", "D4", "D5", "Hx?");
+    fprintf(fp,
+            "%3s %3s %3s %3s %3s %7s %7s %7s %7s %7s %3s\n",
+            "AA",
+            "N",
+            "Ca",
+            "C",
+            "O",
+            "Phi",
+            "Psi",
+            "D3",
+            "D4",
+            "D5",
+            "Hx?");
     for (i = 0; (i < nres); i++)
     {
-        fprintf(fp, "%3d %3d %3d %3d %3d %7.2f %7.2f %7.3f %7.3f %7.3f %3s\n", bb[i].resno, bb[i].N,
-                bb[i].CA, bb[i].C, bb[i].O, bb[i].phi, bb[i].psi, bb[i].d3, bb[i].d4, bb[i].d5,
+        fprintf(fp,
+                "%3d %3d %3d %3d %3d %7.2f %7.2f %7.3f %7.3f %7.3f %3s\n",
+                bb[i].resno,
+                bb[i].N,
+                bb[i].CA,
+                bb[i].C,
+                bb[i].O,
+                bb[i].phi,
+                bb[i].psi,
+                bb[i].d3,
+                bb[i].d4,
+                bb[i].d5,
                 bb[i].bHelix ? "Yes" : "No");
     }
     fprintf(fp, "\n");
index 4ec0380083cba0ed72d9a3728aedb8ea5aa5519e..8dadfadbd6c8259e06b74135a9ef5615e9d9546f 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
-#ifndef _hxprops_h
-#define _hxprops_h
+#ifndef GMX_GMXANA_HXPROPS_H
+#define GMX_GMXANA_HXPROPS_H
 
 #include <stdio.h>
 
index cf7de12ebdb5a79d3928fa3c0d0b410fabc60942..e1f15aa28fbd19fe87093cc23fc0eb2b053c5b15 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2013,2014,2015 by the GROMACS development team.
- * Copyright (c) 2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +34,8 @@
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
-#ifndef _interf_h
-#define _interf_h
+#ifndef GMX_GMXANA_INTERF_H
+#define GMX_GMXANA_INTERF_H
 
 #include "gromacs/utility/real.h"
 
index f1bf5bb89e71b700572f09f3e23a1278da75e964..c5f6ccce607874c9ed6f4760eb5d74de2a9a9a90 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,7 +51,7 @@
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/smalloc.h"
 
-static const char* pp_pat[] = { "C", "N", "CA", "C", "N" };
+static const char* const pp_pat[] = { "C", "N", "CA", "C", "N" };
 #define NPP (sizeof(pp_pat) / sizeof(pp_pat[0]))
 
 static bool d_comp(const t_dih& a, const t_dih& b)
@@ -85,8 +85,19 @@ static void calc_dihs(t_xrama* xr)
     for (i = 0; (i < xr->ndih); i++)
     {
         dd      = &(xr->dih[i]);
-        dd->ang = dih_angle(xr->x[dd->ai[0]], xr->x[dd->ai[1]], xr->x[dd->ai[2]], xr->x[dd->ai[3]],
-                            nullptr, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3);
+        dd->ang = dih_angle(xr->x[dd->ai[0]],
+                            xr->x[dd->ai[1]],
+                            xr->x[dd->ai[2]],
+                            xr->x[dd->ai[3]],
+                            nullptr,
+                            r_ij,
+                            r_kj,
+                            r_kl,
+                            m,
+                            n,
+                            &t1,
+                            &t2,
+                            &t3);
     }
 }
 
@@ -136,7 +147,9 @@ static void add_xr(t_xrama* xr, const int ff[5], const t_atoms* atoms)
     xr->pp[xr->npp].iphi  = xr->ndih - 2;
     xr->pp[xr->npp].ipsi  = xr->ndih - 1;
     xr->pp[xr->npp].bShow = FALSE;
-    sprintf(buf, "%s-%d", *atoms->resinfo[atoms->atom[ff[1]].resind].name,
+    sprintf(buf,
+            "%s-%d",
+            *atoms->resinfo[atoms->atom[ff[1]].resind].name,
             atoms->resinfo[atoms->atom[ff[1]].resind].nr);
     xr->pp[xr->npp].label = gmx_strdup(buf);
     xr->npp++;
@@ -229,8 +242,11 @@ static void get_dih_props(t_xrama* xr, const t_idef* idef, int mult)
     {
         if (xr->dih[i].mult == 0)
         {
-            fprintf(stderr, "Dihedral around %d,%d not found in topology. Using mult=%d\n",
-                    xr->dih[i].ai[1], xr->dih[i].ai[2], mult);
+            fprintf(stderr,
+                    "Dihedral around %d,%d not found in topology. Using mult=%d\n",
+                    xr->dih[i].ai[1],
+                    xr->dih[i].ai[2],
+                    mult);
             xr->dih[i].mult = mult;
             xr->dih[i].phi0 = 180;
         }
index e56b568d756502b9ce707536d2b2b89d6a50ff6a..4b3af0c0cbf9e1918611771ae05874dd393b7d58 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016, The GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -256,7 +256,6 @@ gmx_radial_distribution_histogram_t* calc_radial_distribution_histogram(gmx_sans
             gmx::UniformIntDistribution<int> tdist(0, isize - 1);
             tid = gmx_omp_get_thread_num();
             /* now starting parallel threads */
-            INTEL_DIAGNOSTIC_IGNORE(593)
 #    pragma omp for
             for (int64_t mc = 0; mc < mc_max; mc++)
             {
@@ -273,7 +272,6 @@ gmx_radial_distribution_histogram_t* calc_radial_distribution_histogram(gmx_sans
                 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
             }
         }
-        INTEL_DIAGNOSTIC_RESET
         /* collecting data from threads */
         for (i = 0; i < pr->grn; i++)
         {
index e37bb57c1738b5de697145ea52446722da65fcf5..e8b83fec698385781a88d890a68618de8652997b 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2013,2014,2015 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +34,8 @@
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
-#ifndef _powerspect_h
-#define _powerspect_h
+#ifndef GMX_GMXANA_POWERSPECT_H
+#define GMX_GMXANA_POWERSPECT_H
 
 #include <string>
 #include <vector>
index cbb4a0d58a2ba9dcb260bfa992a8432afda264bc..1cbf6381d535ba9fb32ab9917f9dcfddbbed01fc 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,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/fileio/matio.h"
 #include "gromacs/gmxana/gstat.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/gmxassert.h"
@@ -119,13 +120,13 @@ static void dump_sd(const char* fn, t_shiftdata* sd)
     {
         snew(newdata[i], nny);
         phi      = i * 2 * M_PI / (nnx - 1);
-        x_phi[i] = phi * RAD2DEG - 180;
+        x_phi[i] = phi * gmx::c_rad2Deg - 180;
         for (j = 0; (j < nny); j++)
         {
             psi = j * 2 * M_PI / (nny - 1);
             if (i == 0)
             {
-                y_psi[j] = psi * RAD2DEG - 180;
+                y_psi[j] = psi * gmx::c_rad2Deg - 180;
             }
             /*if (((i % nfac) == 0) && ((j % nfac) == 0))
                newdata[i][j] = sd->data[i/nfac][j/nfac];
@@ -222,7 +223,12 @@ void do_pp2shifts(FILE* fp, int nf, int nlist, t_dlist dlist[], real** dih)
 
     fprintf(fp, "\n *** Chemical shifts from the chemical shift index ***\n");
     please_cite(fp, "Wishart98a");
-    fprintf(fp, "%12s  %10s  %10s  %10s  %10s\n", "Residue", "delta Ca", "delta Ha", "delta CO",
+    fprintf(fp,
+            "%12s  %10s  %10s  %10s  %10s\n",
+            "Residue",
+            "delta Ca",
+            "delta Ha",
+            "delta CO",
             "delta Cb");
     for (i = 0; (i < nlist); i++)
     {
@@ -241,8 +247,7 @@ void do_pp2shifts(FILE* fp, int nf, int nlist, t_dlist dlist[], real** dih)
                 co += interpolate(phi, psi, co_sd);
                 ha += interpolate(phi, psi, ha_sd);
             }
-            fprintf(fp, "%12s  %10g  %10g  %10g  %10g\n", dlist[i].name, ca / nf, ha / nf, co / nf,
-                    cb / nf);
+            fprintf(fp, "%12s  %10g  %10g  %10g  %10g\n", dlist[i].name, ca / nf, ha / nf, co / nf, cb / nf);
         }
     }
     fprintf(fp, "\n");
index 8f32afa7b342e5ecc3367c253a3b1417caeae03f..ded0e6fc9e7039063941eaedd3702dfc0a1c5209 100644 (file)
@@ -75,8 +75,7 @@ static void ptrans(char* s, real** inten, real d[], real e[])
         y = inten[m][2];
         z = inten[m][3];
         n = x * x + y * y + z * z;
-        fprintf(stderr, "%8s %8.3f %8.3f %8.3f, norm:%8.3f, d:%8.3f, e:%8.3f\n", s, x, y, z,
-                std::sqrt(n), d[m], e[m]);
+        fprintf(stderr, "%8s %8.3f %8.3f %8.3f, norm:%8.3f, d:%8.3f, e:%8.3f\n", s, x, y, z, std::sqrt(n), d[m], e[m]);
     }
     fprintf(stderr, "\n");
 }
index 87b08d6e84fdac5856b32ba5e8ef67770593968a..164c8cb556f8309edc02c75d08bf2db39c4bf3da 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
 #include "gromacs/fileio/trxio.h"
 #include "gromacs/fileio/xvgr.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdtypes/md_enums.h"
@@ -295,8 +296,7 @@ extern gmx_structurefactors_t* gmx_structurefactors_init(const char* datfn)
     while (get_a_line(fp.get(), line, STRLEN))
     {
         i = line_no;
-        if (sscanf(line, "%s %d %lf %lf %lf %lf %lf %lf %lf %lf %lf", atomn, &p, &a1, &a2, &a3, &a4,
-                   &b1, &b2, &b3, &b4, &c)
+        if (sscanf(line, "%s %d %lf %lf %lf %lf %lf %lf %lf %lf %lf", atomn, &p, &a1, &a2, &a3, &a4, &b1, &b2, &b3, &b4, &c)
             == 11)
         {
             gsf->atomnm[i] = gmx_strdup(atomn);
@@ -541,8 +541,8 @@ extern int do_scattering_intensity(const char*             fnTPS,
         {
             rearrange_atoms(red[i], &fr, index[i], isize[i], &top, FALSE, gmx_sf);
 
-            compute_structure_factor(static_cast<structure_factor_t*>(sf), box, red[i], isize[i],
-                                     start_q, end_q, i, sf_table);
+            compute_structure_factor(
+                    static_cast<structure_factor_t*>(sf), box, red[i], isize[i], start_q, end_q, i, sf_table);
         }
     }
 
@@ -612,7 +612,6 @@ extern void save_data(structure_factor_t*     sft,
     xvgrclose(fp);
 }
 
-
 extern double CMSF(gmx_structurefactors_t* gsf, int type, int nh, double lambda, double sin_theta)
 /*
  * return Cromer-Mann fit for the atomic scattering factor:
diff --git a/src/gromacs/gmxana/tests/.clang-tidy b/src/gromacs/gmxana/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 381d847f0636230dec31593c1ed53a389c9a7da1..696071831fdb2e1ec9bb5e0b0f0392fb2abe51b4 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
-# Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -39,6 +39,5 @@ gmx_add_gtest_executable(${exename}
         entropy.cpp
         gmx_traj.cpp
         gmx_mindist.cpp
-        gmx_msd.cpp
         )
 gmx_register_gtest_test(GmxAnaTest ${exename} INTEGRATION_TEST IGNORE_LEAKS)
diff --git a/src/gromacs/gmxana/tests/gmx_msd.cpp b/src/gromacs/gmxana/tests/gmx_msd.cpp
deleted file mode 100644 (file)
index bca2bd8..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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 gmx msd.
- *
- * \author Kevin Boyd <kevin.boyd@uconn.edu>
- */
-
-#include "gmxpre.h"
-
-#include <cstdio>
-#include <cstdlib>
-
-#include "gromacs/gmxana/gmx_ana.h"
-#include "gromacs/gmxpreprocess/grompp.h"
-#include "gromacs/utility/futil.h"
-#include "gromacs/utility/path.h"
-#include "gromacs/utility/textreader.h"
-
-#include "testutils/cmdlinetest.h"
-#include "testutils/refdata.h"
-#include "testutils/testfilemanager.h"
-#include "testutils/textblockmatchers.h"
-#include "testutils/xvgtest.h"
-
-namespace
-{
-
-using gmx::test::CommandLine;
-using gmx::test::XvgMatch;
-
-class MsdTest : public gmx::test::CommandLineTestBase
-{
-public:
-    MsdTest()
-    {
-        setOutputFile("-o", "msd.xvg", XvgMatch());
-        setInputFile("-f", "msd_traj.xtc");
-        setInputFile("-s", "msd_coords.gro");
-        setInputFile("-n", "msd.ndx");
-    }
-
-    void runTest(const CommandLine& args)
-    {
-        CommandLine& cmdline = commandLine();
-        cmdline.merge(args);
-        ASSERT_EQ(0, gmx_msd(cmdline.argc(), cmdline.argv()));
-        checkOutputFiles();
-    }
-};
-
-class MsdMolTest : public gmx::test::CommandLineTestBase
-{
-public:
-    MsdMolTest()
-    {
-        double    tolerance = 1e-5;
-        XvgMatch  xvg;
-        XvgMatch& toler = xvg.tolerance(gmx::test::relativeToleranceAsFloatingPoint(1, tolerance));
-        setOutputFile("-mol", "msdmol.xvg", toler);
-    }
-
-    void runTest(const CommandLine& args, const char* ndxfile, const std::string& simulationName)
-    {
-        setInputFile("-f", simulationName + ".pdb");
-        std::string tpr = fileManager().getTemporaryFilePath(".tpr");
-        std::string mdp = fileManager().getTemporaryFilePath(".mdp");
-        FILE*       fp  = fopen(mdp.c_str(), "w");
-        fprintf(fp, "cutoff-scheme = verlet\n");
-        fprintf(fp, "rcoulomb      = 0.85\n");
-        fprintf(fp, "rvdw          = 0.85\n");
-        fprintf(fp, "rlist         = 0.85\n");
-        fclose(fp);
-
-        // Prepare a .tpr file
-        {
-            CommandLine caller;
-            auto        simDB = gmx::test::TestFileManager::getTestSimulationDatabaseDirectory();
-            auto        base  = gmx::Path::join(simDB, simulationName);
-            caller.append("grompp");
-            caller.addOption("-maxwarn", 0);
-            caller.addOption("-f", mdp.c_str());
-            std::string gro = (base + ".pdb");
-            caller.addOption("-c", gro.c_str());
-            std::string top = (base + ".top");
-            caller.addOption("-p", top.c_str());
-            std::string ndx = (base + ".ndx");
-            caller.addOption("-n", ndx.c_str());
-            caller.addOption("-o", tpr.c_str());
-            ASSERT_EQ(0, gmx_grompp(caller.argc(), caller.argv()));
-        }
-        // Run the MSD analysis
-        {
-            setInputFile("-n", ndxfile);
-            CommandLine& cmdline = commandLine();
-            cmdline.merge(args);
-            cmdline.addOption("-s", tpr.c_str());
-            ASSERT_EQ(0, gmx_msd(cmdline.argc(), cmdline.argv()));
-            checkOutputFiles();
-        }
-    }
-};
-
-/* msd_traj.xtc contains a 10 frame (1 ps per frame) simulation
- * containing 3 atoms, with different starting positions but identical
- * displacements. The displacements are calculated to yield the following
- * diffusion coefficients when lag is calculated ONLY FROM TIME 0
- * D_x = 8 * 10 ^ -5 cm^2 /s, D_y = 4 * 10^ -5 cm^2 /s , D_z = 0
- *
- * To test for these results, -trestart is set to a larger value than the
- * total simulation length, so that only lag 0 is calculated
- */
-
-// for 3D, (8 + 4 + 0) / 3 should yield 4 cm^2 / s
-TEST_F(MsdTest, threeDimensionalDiffusion)
-{
-    const char* const cmdline[] = {
-        "msd", "-mw", "no", "-trestart", "200",
-    };
-    runTest(CommandLine(cmdline));
-}
-
-// for lateral z, (8 + 4) / 2 should yield 6 cm^2 /s
-TEST_F(MsdTest, twoDimensionalDiffusion)
-{
-    const char* const cmdline[] = { "msd", "-mw", "no", "-trestart", "200", "-lateral", "z" };
-    runTest(CommandLine(cmdline));
-}
-
-// for type x, should yield 8 cm^2 / s
-TEST_F(MsdTest, oneDimensionalDiffusion)
-{
-    const char* const cmdline[] = { "msd", "-mw", "no", "-trestart", "200", "-type", "x" };
-    runTest(CommandLine(cmdline));
-}
-
-// Test the diffusion per molecule output, mass weighted
-TEST_F(MsdMolTest, diffMolMassWeighted)
-{
-    const char* const cmdline[] = { "msd", "-trestart", "200" };
-    runTest(CommandLine(cmdline), "spc5.ndx", "spc5");
-}
-
-// Test the diffusion per molecule output, non-mass weighted
-TEST_F(MsdMolTest, diffMolNonMassWeighted)
-{
-    const char* const cmdline[] = { "msd", "-trestart", "200", "-mw", "no" };
-    runTest(CommandLine(cmdline), "spc5.ndx", "spc5");
-}
-
-// Test the diffusion per molecule output, with selection
-TEST_F(MsdMolTest, diffMolSelected)
-{
-    const char* const cmdline[] = { "msd", "-trestart", "200" };
-    runTest(CommandLine(cmdline), "spc5_3.ndx", "spc5");
-}
-
-} // namespace
diff --git a/src/gromacs/gmxana/tests/refdata/MsdMolTest_diffMolMassWeighted.xml b/src/gromacs/gmxana/tests/refdata/MsdMolTest_diffMolMassWeighted.xml
deleted file mode 100644 (file)
index 9f4b165..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
-<ReferenceData>
-  <OutputFiles Name="Files">
-    <File Name="-mol">
-      <XvgLegend Name="Legend">
-        <String Name="XvgLegend"><![CDATA[
-title "Diffusion Coefficients / Molecule"
-xaxis  label "Molecule"
-yaxis  label "D (1e-5 cm^2/s)"
-TYPE xy
-]]></String>
-      </XvgLegend>
-      <XvgData Name="Data">
-        <Sequence Name="Row0">
-          <Int Name="Length">2</Int>
-          <Real>0</Real>
-          <Real>0.747088</Real>
-        </Sequence>
-        <Sequence Name="Row1">
-          <Int Name="Length">2</Int>
-          <Real>1</Real>
-          <Real>0.129497</Real>
-        </Sequence>
-        <Sequence Name="Row2">
-          <Int Name="Length">2</Int>
-          <Real>2</Real>
-          <Real>1.00167</Real>
-        </Sequence>
-        <Sequence Name="Row3">
-          <Int Name="Length">2</Int>
-          <Real>3</Real>
-          <Real>21.2013</Real>
-        </Sequence>
-        <Sequence Name="Row4">
-          <Int Name="Length">2</Int>
-          <Real>4</Real>
-          <Real>9.28605</Real>
-        </Sequence>
-      </XvgData>
-    </File>
-  </OutputFiles>
-</ReferenceData>
diff --git a/src/gromacs/gmxana/tests/refdata/MsdMolTest_diffMolNonMassWeighted.xml b/src/gromacs/gmxana/tests/refdata/MsdMolTest_diffMolNonMassWeighted.xml
deleted file mode 100644 (file)
index 9f4b165..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
-<ReferenceData>
-  <OutputFiles Name="Files">
-    <File Name="-mol">
-      <XvgLegend Name="Legend">
-        <String Name="XvgLegend"><![CDATA[
-title "Diffusion Coefficients / Molecule"
-xaxis  label "Molecule"
-yaxis  label "D (1e-5 cm^2/s)"
-TYPE xy
-]]></String>
-      </XvgLegend>
-      <XvgData Name="Data">
-        <Sequence Name="Row0">
-          <Int Name="Length">2</Int>
-          <Real>0</Real>
-          <Real>0.747088</Real>
-        </Sequence>
-        <Sequence Name="Row1">
-          <Int Name="Length">2</Int>
-          <Real>1</Real>
-          <Real>0.129497</Real>
-        </Sequence>
-        <Sequence Name="Row2">
-          <Int Name="Length">2</Int>
-          <Real>2</Real>
-          <Real>1.00167</Real>
-        </Sequence>
-        <Sequence Name="Row3">
-          <Int Name="Length">2</Int>
-          <Real>3</Real>
-          <Real>21.2013</Real>
-        </Sequence>
-        <Sequence Name="Row4">
-          <Int Name="Length">2</Int>
-          <Real>4</Real>
-          <Real>9.28605</Real>
-        </Sequence>
-      </XvgData>
-    </File>
-  </OutputFiles>
-</ReferenceData>
diff --git a/src/gromacs/gmxana/tests/refdata/MsdMolTest_diffMolSelected.xml b/src/gromacs/gmxana/tests/refdata/MsdMolTest_diffMolSelected.xml
deleted file mode 100644 (file)
index 4c05484..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
-<ReferenceData>
-  <OutputFiles Name="Files">
-    <File Name="-mol">
-      <XvgLegend Name="Legend">
-        <String Name="XvgLegend"><![CDATA[
-title "Diffusion Coefficients / Molecule"
-xaxis  label "Molecule"
-yaxis  label "D (1e-5 cm^2/s)"
-TYPE xy
-]]></String>
-      </XvgLegend>
-      <XvgData Name="Data">
-        <Sequence Name="Row0">
-          <Int Name="Length">2</Int>
-          <Real>0</Real>
-          <Real>0.747088</Real>
-        </Sequence>
-        <Sequence Name="Row1">
-          <Int Name="Length">2</Int>
-          <Real>1</Real>
-          <Real>0.129497</Real>
-        </Sequence>
-        <Sequence Name="Row2">
-          <Int Name="Length">2</Int>
-          <Real>2</Real>
-          <Real>21.2013</Real>
-        </Sequence>
-      </XvgData>
-    </File>
-  </OutputFiles>
-</ReferenceData>
index b9124abe5d4cc5dc040a851dc92b7d64ee61d354..ca80d660f3390780338fd5b1ba10acc5900903d6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 static double eigval_to_frequency(double eigval)
 {
-    double factor_gmx_to_omega2 = 1.0E21 / (AVOGADRO * AMU);
+    double factor_gmx_to_omega2 = 1.0E21 / (gmx::c_avogadro * gmx::c_amu);
     return std::sqrt(std::max(0.0, eigval) * factor_gmx_to_omega2);
 }
 
 double calcZeroPointEnergy(gmx::ArrayRef<const real> eigval, real scale_factor)
 {
     // Convert frequency (ps^-1) to energy (kJ/mol)
-    double factor = PLANCK * PICO / (2.0 * M_PI);
+    double factor = gmx::c_planck * gmx::c_pico / (2.0 * M_PI);
     double zpe    = 0;
-    for (auto& r : eigval)
+    for (const auto& r : eigval)
     {
         double omega = eigval_to_frequency(r);
         zpe += 0.5 * factor * scale_factor * omega;
@@ -67,67 +67,78 @@ double calcVibrationalInternalEnergy(gmx::ArrayRef<const real> eigval, real temp
 {
     size_t nskip = linear ? 5 : 6;
     double Evib  = 0;
-    double hbar  = PLANCK1 / (2 * M_PI);
+    double hbar  = gmx::c_planck1 / (2 * M_PI);
     for (gmx::index i = nskip; i < eigval.ssize(); i++)
     {
         if (eigval[i] > 0)
         {
             double omega = scale_factor * eigval_to_frequency(eigval[i]);
-            double hwkT  = (hbar * omega) / (BOLTZMANN * temperature);
+            double hwkT  = (hbar * omega) / (gmx::c_boltzmann * temperature);
             // Prevent overflow by checking for unreasonably large numbers.
             if (hwkT < 100)
             {
                 double dEvib = hwkT * (0.5 + 1.0 / (std::expm1(hwkT)));
                 if (debug)
                 {
-                    fprintf(debug, "i %d eigval %g omega %g hwkT %g dEvib %g\n",
-                            static_cast<int>(i + 1), static_cast<double>(eigval[i]), omega, hwkT, dEvib);
+                    fprintf(debug,
+                            "i %d eigval %g omega %g hwkT %g dEvib %g\n",
+                            static_cast<int>(i + 1),
+                            static_cast<double>(eigval[i]),
+                            omega,
+                            hwkT,
+                            dEvib);
                 }
                 Evib += dEvib;
             }
         }
     }
-    return temperature * BOLTZ * Evib;
+    return temperature * gmx::c_boltz * Evib;
 }
 
 double calcVibrationalHeatCapacity(gmx::ArrayRef<const real> eigval, real temperature, gmx_bool linear, real scale_factor)
 {
     size_t nskip = linear ? 5 : 6;
     double cv    = 0;
-    double hbar  = PLANCK1 / (2 * M_PI);
+    double hbar  = gmx::c_planck1 / (2 * M_PI);
     for (gmx::index i = nskip; i < eigval.ssize(); i++)
     {
         if (eigval[i] > 0)
         {
             double omega = scale_factor * eigval_to_frequency(eigval[i]);
-            double hwkT  = (hbar * omega) / (BOLTZMANN * temperature);
+            double hwkT  = (hbar * omega) / (gmx::c_boltzmann * temperature);
             // Prevent overflow by checking for unreasonably large numbers.
             if (hwkT < 100)
             {
                 double dcv = std::exp(hwkT) * gmx::square(hwkT / std::expm1(hwkT));
                 if (debug)
                 {
-                    fprintf(debug, "i %d eigval %g omega %g hwkT %g dcv %g\n",
-                            static_cast<int>(i + 1), static_cast<double>(eigval[i]), omega, hwkT, dcv);
+                    fprintf(debug,
+                            "i %d eigval %g omega %g hwkT %g dcv %g\n",
+                            static_cast<int>(i + 1),
+                            static_cast<double>(eigval[i]),
+                            omega,
+                            hwkT,
+                            dcv);
                 }
                 cv += dcv;
             }
         }
     }
-    return RGAS * cv;
+    return gmx::c_universalGasConstant * cv;
 }
 
 double calcTranslationalEntropy(real mass, real temperature, real pressure)
 {
-    double kT = BOLTZ * temperature;
+    double kT = gmx::c_boltz * temperature;
 
     GMX_RELEASE_ASSERT(mass > 0, "Molecular mass should be larger than zero");
     GMX_RELEASE_ASSERT(pressure > 0, "Pressure should be larger than zero");
     GMX_RELEASE_ASSERT(temperature > 0, "Temperature should be larger than zero");
     // Convert bar to Pascal
-    double P = pressure * 1e5;
-    double qT = (std::pow(2 * M_PI * mass * kT / gmx::square(PLANCK), 1.5) * (kT / P) * (1e30 / AVOGADRO));
-    return RGAS * (std::log(qT) + 2.5);
+    double P  = pressure * 1e5;
+    double qT = (std::pow(2 * M_PI * mass * kT / gmx::square(gmx::c_planck), 1.5) * (kT / P)
+                 * (1e30 / gmx::c_avogadro));
+    return gmx::c_universalGasConstant * (std::log(qT) + 2.5);
 }
 
 double calcRotationalEntropy(real temperature, int natom, gmx_bool linear, const rvec theta, real sigma_r)
@@ -142,14 +153,14 @@ double calcRotationalEntropy(real temperature, int natom, gmx_bool linear, const
         {
             GMX_RELEASE_ASSERT(theta[0] > 0, "Theta should be larger than zero");
             double qR = temperature / (sigma_r * theta[0]);
-            sR        = RGAS * (std::log(qR) + 1);
+            sR        = gmx::c_universalGasConstant * (std::log(qR) + 1);
         }
         else
         {
             double Q = theta[XX] * theta[YY] * theta[ZZ];
             GMX_RELEASE_ASSERT(Q > 0, "Q should be larger than zero");
             double qR = std::sqrt(M_PI * std::pow(temperature, 3) / Q) / sigma_r;
-            sR        = RGAS * (std::log(qR) + 1.5);
+            sR        = gmx::c_universalGasConstant * (std::log(qR) + 1.5);
         }
     }
     return sR;
@@ -159,19 +170,24 @@ double calcQuasiHarmonicEntropy(gmx::ArrayRef<const real> eigval, real temperatu
 {
     size_t nskip = bLinear ? 5 : 6;
     double S     = 0;
-    double hbar  = PLANCK1 / (2 * M_PI);
+    double hbar  = gmx::c_planck1 / (2 * M_PI);
     for (gmx::index i = nskip; (i < eigval.ssize()); i++)
     {
         if (eigval[i] > 0)
         {
             double omega = scale_factor * eigval_to_frequency(eigval[i]);
-            double hwkT  = (hbar * omega) / (BOLTZMANN * temperature);
+            double hwkT  = (hbar * omega) / (gmx::c_boltzmann * temperature);
             double dS    = (hwkT / std::expm1(hwkT) - std::log1p(-std::exp(-hwkT)));
             S += dS;
             if (debug)
             {
-                fprintf(debug, "i = %5d eigval = %10g w = %10g hwkT = %10g dS = %10g\n",
-                        static_cast<int>(i + 1), static_cast<double>(eigval[i]), omega, hwkT, dS);
+                fprintf(debug,
+                        "i = %5d eigval = %10g w = %10g hwkT = %10g dS = %10g\n",
+                        static_cast<int>(i + 1),
+                        static_cast<double>(eigval[i]),
+                        omega,
+                        hwkT,
+                        dS);
             }
         }
         else if (debug)
@@ -179,16 +195,16 @@ double calcQuasiHarmonicEntropy(gmx::ArrayRef<const real> eigval, real temperatu
             fprintf(debug, "eigval[%d] = %g\n", static_cast<int>(i + 1), static_cast<double>(eigval[i]));
         }
     }
-    return S * RGAS;
+    return S * gmx::c_universalGasConstant;
 }
 
 double calcSchlitterEntropy(gmx::ArrayRef<const real> eigval, real temperature, gmx_bool bLinear)
 {
     size_t nskip  = bLinear ? 5 : 6;
-    double hbar   = PLANCK1 / (2 * M_PI);               // J s
-    double kt     = BOLTZMANN * temperature;            // J
+    double hbar   = gmx::c_planck1 / (2 * M_PI);        // J s
+    double kt     = gmx::c_boltzmann * temperature;     // J
     double kteh   = kt * std::exp(2.0) / (hbar * hbar); // 1/(J s^2) = 1/(kg m^2)
-    double evcorr = NANO * NANO * AMU;
+    double evcorr = gmx::c_nano * gmx::c_nano * gmx::c_amu;
     if (debug)
     {
         fprintf(debug, "n = %td, kteh = %g evcorr = %g\n", ssize(eigval), kteh, evcorr);
@@ -199,5 +215,5 @@ double calcSchlitterEntropy(gmx::ArrayRef<const real> eigval, real temperature,
         double dd = 1 + kteh * eigval[i] * evcorr;
         deter += std::log(dd);
     }
-    return 0.5 * RGAS * deter;
+    return 0.5 * gmx::c_universalGasConstant * deter;
 }
index 2e20112e902b41ba22604617ff0fbbc286cb981e..acb56892a68de5e5aaee21620e00a879ea6ea97d 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2009,2010,2012,2014,2015 by the GROMACS development team.
-# Copyright (c) 2016,2020, by the GROMACS development team, led by
+# Copyright (c) 2016,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -33,6 +33,8 @@
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
+add_library(gmxlib INTERFACE)
+
 add_subdirectory(nonbonded)
 
 # The nonbonded directory contains subdirectories that are only
@@ -41,6 +43,38 @@ file(GLOB GMXLIB_SOURCES *.cpp)
 
 set(GMXLIB_SOURCES ${GMXLIB_SOURCES} ${NONBONDED_SOURCES} PARENT_SCOPE)
 
-# if(BUILD_TESTING)
-#     add_subdirectory(tests)
-# endif()
+# Source files have the following private module dependencies.
+target_link_libraries(gmxlib PRIVATE
+                      #                      gmxlib
+                      #                      math
+                      #                      mdtypes
+                      #                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(gmxlib PUBLIC
+target_include_directories(gmxlib INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(gmxlib PUBLIC
+target_link_libraries(gmxlib INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when fileio is an OBJECT target
+#target_link_libraries(gmxlib PUBLIC legacy_api)
+#target_link_libraries(gmxlib PRIVATE common)
+
+# Module dependencies
+# fileio interfaces convey transitive dependence on these modules.
+#target_link_libraries(gmxlib PUBLIC
+target_link_libraries(gmxlib INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(gmxlib PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(gmxlib PRIVATE legacy_modules)
+
+if(BUILD_TESTING)
+    add_subdirectory(nonbonded/tests)
+endif()
index 66023edac82d5019ea91da73ac32f9902e91babd..f4adc6931cee105fa6bbe691e144f22acf94214d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +190,9 @@ void gmx_setup_nodecomm(FILE gmx_unused* fplog, t_commrec* cr)
         nc->bUse = TRUE;
         if (fplog)
         {
-            fprintf(fplog, "Using two step summing over %d groups of on average %.1f ranks\n\n", ng,
+            fprintf(fplog,
+                    "Using two step summing over %d groups of on average %.1f ranks\n\n",
+                    ng,
                     (real)n / (real)ng);
         }
         if (nc->rank_intra > 0)
@@ -240,7 +242,6 @@ void gmx_sumd(int gmx_unused nr, double gmx_unused r[], const t_commrec gmx_unus
 #if !GMX_MPI
     GMX_RELEASE_ASSERT(false, "Invalid call to gmx_sumd");
 #else
-#    if MPI_IN_PLACE_EXISTS
     if (cr->nc.bUse)
     {
         if (cr->nc.rank_intra == 0)
@@ -262,34 +263,6 @@ void gmx_sumd(int gmx_unused nr, double gmx_unused r[], const t_commrec gmx_unus
     {
         MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_DOUBLE, MPI_SUM, cr->mpi_comm_mygroup);
     }
-#    else
-    int i;
-
-    if (nr > cr->mpb->dbuf_alloc)
-    {
-        cr->mpb->dbuf_alloc = nr;
-        srenew(cr->mpb->dbuf, cr->mpb->dbuf_alloc);
-    }
-    if (cr->nc.bUse)
-    {
-        /* Use two step summing */
-        MPI_Allreduce(r, cr->mpb->dbuf, nr, MPI_DOUBLE, MPI_SUM, cr->nc.comm_intra);
-        if (cr->nc.rank_intra == 0)
-        {
-            /* Sum with the buffers reversed */
-            MPI_Allreduce(cr->mpb->dbuf, r, nr, MPI_DOUBLE, MPI_SUM, cr->nc.comm_inter);
-        }
-        MPI_Bcast(r, nr, MPI_DOUBLE, 0, cr->nc.comm_intra);
-    }
-    else
-    {
-        MPI_Allreduce(r, cr->mpb->dbuf, nr, MPI_DOUBLE, MPI_SUM, cr->mpi_comm_mygroup);
-        for (i = 0; i < nr; i++)
-        {
-            r[i] = cr->mpb->dbuf[i];
-        }
-    }
-#    endif
 #endif
 }
 
@@ -298,7 +271,6 @@ void gmx_sumf(int gmx_unused nr, float gmx_unused r[], const t_commrec gmx_unuse
 #if !GMX_MPI
     GMX_RELEASE_ASSERT(false, "Invalid call to gmx_sumf");
 #else
-#    if MPI_IN_PLACE_EXISTS
     if (cr->nc.bUse)
     {
         /* Use two step summing.  */
@@ -320,34 +292,6 @@ void gmx_sumf(int gmx_unused nr, float gmx_unused r[], const t_commrec gmx_unuse
     {
         MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_FLOAT, MPI_SUM, cr->mpi_comm_mygroup);
     }
-#    else
-    int i;
-
-    if (nr > cr->mpb->fbuf_alloc)
-    {
-        cr->mpb->fbuf_alloc = nr;
-        srenew(cr->mpb->fbuf, cr->mpb->fbuf_alloc);
-    }
-    if (cr->nc.bUse)
-    {
-        /* Use two step summing */
-        MPI_Allreduce(r, cr->mpb->fbuf, nr, MPI_FLOAT, MPI_SUM, cr->nc.comm_intra);
-        if (cr->nc.rank_intra == 0)
-        {
-            /* Sum with the buffers reversed */
-            MPI_Allreduce(cr->mpb->fbuf, r, nr, MPI_FLOAT, MPI_SUM, cr->nc.comm_inter);
-        }
-        MPI_Bcast(r, nr, MPI_FLOAT, 0, cr->nc.comm_intra);
-    }
-    else
-    {
-        MPI_Allreduce(r, cr->mpb->fbuf, nr, MPI_FLOAT, MPI_SUM, cr->mpi_comm_mygroup);
-        for (i = 0; i < nr; i++)
-        {
-            r[i] = cr->mpb->fbuf[i];
-        }
-    }
-#    endif
 #endif
 }
 
@@ -356,7 +300,6 @@ void gmx_sumi(int gmx_unused nr, int gmx_unused r[], const t_commrec gmx_unused*
 #if !GMX_MPI
     GMX_RELEASE_ASSERT(false, "Invalid call to gmx_sumi");
 #else
-#    if MPI_IN_PLACE_EXISTS
     if (cr->nc.bUse)
     {
         /* Use two step summing */
@@ -378,34 +321,6 @@ void gmx_sumi(int gmx_unused nr, int gmx_unused r[], const t_commrec gmx_unused*
     {
         MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_INT, MPI_SUM, cr->mpi_comm_mygroup);
     }
-#    else
-    int i;
-
-    if (nr > cr->mpb->ibuf_alloc)
-    {
-        cr->mpb->ibuf_alloc = nr;
-        srenew(cr->mpb->ibuf, cr->mpb->ibuf_alloc);
-    }
-    if (cr->nc.bUse)
-    {
-        /* Use two step summing */
-        MPI_Allreduce(r, cr->mpb->ibuf, nr, MPI_INT, MPI_SUM, cr->nc.comm_intra);
-        if (cr->nc.rank_intra == 0)
-        {
-            /* Sum with the buffers reversed */
-            MPI_Allreduce(cr->mpb->ibuf, r, nr, MPI_INT, MPI_SUM, cr->nc.comm_inter);
-        }
-        MPI_Bcast(r, nr, MPI_INT, 0, cr->nc.comm_intra);
-    }
-    else
-    {
-        MPI_Allreduce(r, cr->mpb->ibuf, nr, MPI_INT, MPI_SUM, cr->mpi_comm_mygroup);
-        for (i = 0; i < nr; i++)
-        {
-            r[i] = cr->mpb->ibuf[i];
-        }
-    }
-#    endif
 #endif
 }
 
@@ -414,7 +329,6 @@ void gmx_sumli(int gmx_unused nr, int64_t gmx_unused r[], const t_commrec gmx_un
 #if !GMX_MPI
     GMX_RELEASE_ASSERT(false, "Invalid call to gmx_sumli");
 #else
-#    if MPI_IN_PLACE_EXISTS
     if (cr->nc.bUse)
     {
         /* Use two step summing */
@@ -436,34 +350,6 @@ void gmx_sumli(int gmx_unused nr, int64_t gmx_unused r[], const t_commrec gmx_un
     {
         MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_INT64_T, MPI_SUM, cr->mpi_comm_mygroup);
     }
-#    else
-    int i;
-
-    if (nr > cr->mpb->libuf_alloc)
-    {
-        cr->mpb->libuf_alloc = nr;
-        srenew(cr->mpb->libuf, cr->mpb->libuf_alloc);
-    }
-    if (cr->nc.bUse)
-    {
-        /* Use two step summing */
-        MPI_Allreduce(r, cr->mpb->libuf, nr, MPI_INT64_T, MPI_SUM, cr->nc.comm_intra);
-        if (cr->nc.rank_intra == 0)
-        {
-            /* Sum with the buffers reversed */
-            MPI_Allreduce(cr->mpb->libuf, r, nr, MPI_INT64_T, MPI_SUM, cr->nc.comm_inter);
-        }
-        MPI_Bcast(r, nr, MPI_INT64_T, 0, cr->nc.comm_intra);
-    }
-    else
-    {
-        MPI_Allreduce(r, cr->mpb->libuf, nr, MPI_INT64_T, MPI_SUM, cr->mpi_comm_mygroup);
-        for (i = 0; i < nr; i++)
-        {
-            r[i] = cr->mpb->libuf[i];
-        }
-    }
-#    endif
 #endif
 }
 
index 6573583c7e50bb06fc1e0ee8594a4f66fc7bb7de..6f51cee1719de33b9676c411f265f135c23f09b8 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +46,6 @@
 #include <algorithm>
 
 #include "gromacs/gmxlib/nrnb.h"
-#include "gromacs/gmxlib/nonbonded/nb_kernel.h"
 #include "gromacs/gmxlib/nonbonded/nonbonded.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdtypes/interaction_const.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/mdtypes/nblist.h"
 #include "gromacs/simd/simd.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/arrayref.h"
 
 
 //! Scalar (non-SIMD) data types.
@@ -88,54 +89,54 @@ static inline void pthRoot(const RealType r, RealType* pthRoot, RealType* invPth
 }
 
 template<class RealType>
-static inline RealType calculateRinv6(const RealType rinvV)
+static inline RealType calculateRinv6(const RealType rInvV)
 {
-    RealType rinv6 = rinvV * rinvV;
-    return (rinv6 * rinv6 * rinv6);
+    RealType rInv6 = rInvV * rInvV;
+    return (rInv6 * rInv6 * rInv6);
 }
 
 template<class RealType>
-static inline RealType calculateVdw6(const RealType c6, const RealType rinv6)
+static inline RealType calculateVdw6(const RealType c6, const RealType rInv6)
 {
-    return (c6 * rinv6);
+    return (c6 * rInv6);
 }
 
 template<class RealType>
-static inline RealType calculateVdw12(const RealType c12, const RealType rinv6)
+static inline RealType calculateVdw12(const RealType c12, const RealType rInv6)
 {
-    return (c12 * rinv6 * rinv6);
+    return (c12 * rInv6 * rInv6);
 }
 
 /* reaction-field electrostatics */
 template<class RealType>
 static inline RealType reactionFieldScalarForce(const RealType qq,
-                                                const RealType rinv,
+                                                const RealType rInv,
                                                 const RealType r,
                                                 const real     krf,
                                                 const real     two)
 {
-    return (qq * (rinv - two * krf * r * r));
+    return (qq * (rInv - two * krf * r * r));
 }
 template<class RealType>
 static inline RealType reactionFieldPotential(const RealType qq,
-                                              const RealType rinv,
+                                              const RealType rInv,
                                               const RealType r,
                                               const real     krf,
                                               const real     potentialShift)
 {
-    return (qq * (rinv + krf * r * r - potentialShift));
+    return (qq * (rInv + krf * r * r - potentialShift));
 }
 
 /* Ewald electrostatics */
 template<class RealType>
-static inline RealType ewaldScalarForce(const RealType coulomb, const RealType rinv)
+static inline RealType ewaldScalarForce(const RealType coulomb, const RealType rInv)
 {
-    return (coulomb * rinv);
+    return (coulomb * rInv);
 }
 template<class RealType>
-static inline RealType ewaldPotential(const RealType coulomb, const RealType rinv, const real potentialShift)
+static inline RealType ewaldPotential(const RealType coulomb, const RealType rInv, const real potentialShift)
 {
-    return (coulomb * (rinv - potentialShift));
+    return (coulomb * (rInv - potentialShift));
 }
 
 /* cutoff LJ */
@@ -151,16 +152,16 @@ static inline RealType lennardJonesPotential(const RealType v6,
                                              const RealType c12,
                                              const real     repulsionShift,
                                              const real     dispersionShift,
-                                             const real     onesixth,
-                                             const real     onetwelfth)
+                                             const real     oneSixth,
+                                             const real     oneTwelfth)
 {
-    return ((v12 + c12 * repulsionShift) * onetwelfth - (v6 + c6 * dispersionShift) * onesixth);
+    return ((v12 + c12 * repulsionShift) * oneTwelfth - (v6 + c6 * dispersionShift) * oneSixth);
 }
 
 /* Ewald LJ */
-static inline real ewaldLennardJonesGridSubtract(const real c6grid, const real potentialShift, const real onesixth)
+static inline real ewaldLennardJonesGridSubtract(const real c6grid, const real potentialShift, const real oneSixth)
 {
-    return (c6grid * potentialShift * onesixth);
+    return (c6grid * potentialShift * oneSixth);
 }
 
 /* LJ Potential switch */
@@ -198,12 +199,24 @@ static inline RealType potSwitchPotentialMod(const RealType potentialInp,
 
 //! Templated free-energy non-bonded kernel
 template<typename DataTypes, bool useSoftCore, bool scLambdasOrAlphasDiffer, bool vdwInteractionTypeIsEwald, bool elecInteractionTypeIsEwald, bool vdwModifierIsPotSwitch>
-static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
-                                  rvec* gmx_restrict         xx,
-                                  gmx::ForceWithShiftForces* forceWithShiftForces,
-                                  const t_forcerec* gmx_restrict fr,
-                                  const t_mdatoms* gmx_restrict mdatoms,
-                                  nb_kernel_data_t* gmx_restrict kernel_data,
+static void nb_free_energy_kernel(const t_nblist&                nlist,
+                                  gmx::ArrayRef<const gmx::RVec> coords,
+                                  gmx::ForceWithShiftForces*     forceWithShiftForces,
+                                  const int                      ntype,
+                                  const real                     rlist,
+                                  const interaction_const_t&     ic,
+                                  gmx::ArrayRef<const gmx::RVec> shiftvec,
+                                  gmx::ArrayRef<const real>      nbfp,
+                                  gmx::ArrayRef<const real>      nbfp_grid,
+                                  gmx::ArrayRef<const real>      chargeA,
+                                  gmx::ArrayRef<const real>      chargeB,
+                                  gmx::ArrayRef<const int>       typeA,
+                                  gmx::ArrayRef<const int>       typeB,
+                                  int                            flags,
+                                  gmx::ArrayRef<const real>      lambda,
+                                  gmx::ArrayRef<real>            dvdl,
+                                  gmx::ArrayRef<real>            energygrp_elec,
+                                  gmx::ArrayRef<real>            energygrp_vdw,
                                   t_nrnb* gmx_restrict nrnb)
 {
 #define STATE_A 0
@@ -214,66 +227,52 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
     using IntType  = typename DataTypes::IntType;
 
     /* FIXME: How should these be handled with SIMD? */
-    constexpr real onetwelfth = 1.0 / 12.0;
-    constexpr real onesixth   = 1.0 / 6.0;
+    constexpr real oneTwelfth = 1.0 / 12.0;
+    constexpr real oneSixth   = 1.0 / 6.0;
     constexpr real zero       = 0.0;
     constexpr real half       = 0.5;
     constexpr real one        = 1.0;
     constexpr real two        = 2.0;
     constexpr real six        = 6.0;
 
-    /* Extract pointer to non-bonded interaction constants */
-    const interaction_const_t* ic = fr->ic;
-
     // Extract pair list data
-    const int  nri    = nlist->nri;
-    const int* iinr   = nlist->iinr;
-    const int* jindex = nlist->jindex;
-    const int* jjnr   = nlist->jjnr;
-    const int* shift  = nlist->shift;
-    const int* gid    = nlist->gid;
-
-    const real* shiftvec      = fr->shift_vec[0];
-    const real* chargeA       = mdatoms->chargeA;
-    const real* chargeB       = mdatoms->chargeB;
-    real*       Vc            = kernel_data->energygrp_elec;
-    const int*  typeA         = mdatoms->typeA;
-    const int*  typeB         = mdatoms->typeB;
-    const int   ntype         = fr->ntype;
-    const real* nbfp          = fr->nbfp.data();
-    const real* nbfp_grid     = fr->ljpme_c6grid;
-    real*       Vv            = kernel_data->energygrp_vdw;
-    const real  lambda_coul   = kernel_data->lambda[efptCOUL];
-    const real  lambda_vdw    = kernel_data->lambda[efptVDW];
-    real*       dvdl          = kernel_data->dvdl;
-    const auto& scParams      = *ic->softCoreParameters;
+    const int                nri    = nlist.nri;
+    gmx::ArrayRef<const int> iinr   = nlist.iinr;
+    gmx::ArrayRef<const int> jindex = nlist.jindex;
+    gmx::ArrayRef<const int> jjnr   = nlist.jjnr;
+    gmx::ArrayRef<const int> shift  = nlist.shift;
+    gmx::ArrayRef<const int> gid    = nlist.gid;
+
+    const real  lambda_coul   = lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)];
+    const real  lambda_vdw    = lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)];
+    const auto& scParams      = *ic.softCoreParameters;
     const real  alpha_coul    = scParams.alphaCoulomb;
     const real  alpha_vdw     = scParams.alphaVdw;
     const real  lam_power     = scParams.lambdaPower;
     const real  sigma6_def    = scParams.sigma6WithInvalidSigma;
     const real  sigma6_min    = scParams.sigma6Minimum;
-    const bool  doForces      = ((kernel_data->flags & GMX_NONBONDED_DO_FORCE) != 0);
-    const bool  doShiftForces = ((kernel_data->flags & GMX_NONBONDED_DO_SHIFTFORCE) != 0);
-    const bool  doPotential   = ((kernel_data->flags & GMX_NONBONDED_DO_POTENTIAL) != 0);
+    const bool  doForces      = ((flags & GMX_NONBONDED_DO_FORCE) != 0);
+    const bool  doShiftForces = ((flags & GMX_NONBONDED_DO_SHIFTFORCE) != 0);
+    const bool  doPotential   = ((flags & GMX_NONBONDED_DO_POTENTIAL) != 0);
 
     // Extract data from interaction_const_t
-    const real facel           = ic->epsfac;
-    const real rcoulomb        = ic->rcoulomb;
-    const real krf             = ic->k_rf;
-    const real crf             = ic->c_rf;
-    const real sh_lj_ewald     = ic->sh_lj_ewald;
-    const real rvdw            = ic->rvdw;
-    const real dispersionShift = ic->dispersion_shift.cpot;
-    const real repulsionShift  = ic->repulsion_shift.cpot;
+    const real facel           = ic.epsfac;
+    const real rCoulomb        = ic.rcoulomb;
+    const real krf             = ic.reactionFieldCoefficient;
+    const real crf             = ic.reactionFieldShift;
+    const real shLjEwald       = ic.sh_lj_ewald;
+    const real rVdw            = ic.rvdw;
+    const real dispersionShift = ic.dispersion_shift.cpot;
+    const real repulsionShift  = ic.repulsion_shift.cpot;
 
     // Note that the nbnxm kernels do not support Coulomb potential switching at all
-    GMX_ASSERT(ic->coulomb_modifier != eintmodPOTSWITCH,
+    GMX_ASSERT(ic.coulomb_modifier != InteractionModifiers::PotSwitch,
                "Potential switching is not supported for Coulomb with FEP");
 
     real vdw_swV3, vdw_swV4, vdw_swV5, vdw_swF2, vdw_swF3, vdw_swF4;
     if (vdwModifierIsPotSwitch)
     {
-        const real d = ic->rvdw - ic->rvdw_switch;
+        const real d = ic.rvdw - ic.rvdw_switch;
         vdw_swV3     = -10.0 / (d * d * d);
         vdw_swV4     = 15.0 / (d * d * d * d);
         vdw_swV5     = -6.0 / (d * d * d * d * d);
@@ -287,17 +286,17 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
         vdw_swV3 = vdw_swV4 = vdw_swV5 = vdw_swF2 = vdw_swF3 = vdw_swF4 = 0.0;
     }
 
-    int icoul;
-    if (ic->eeltype == eelCUT || EEL_RF(ic->eeltype))
+    NbkernelElecType icoul;
+    if (ic.eeltype == CoulombInteractionType::Cut || EEL_RF(ic.eeltype))
     {
-        icoul = GMX_NBKERNEL_ELEC_REACTIONFIELD;
+        icoul = NbkernelElecType::ReactionField;
     }
     else
     {
-        icoul = GMX_NBKERNEL_ELEC_NONE;
+        icoul = NbkernelElecType::None;
     }
 
-    real rcutoff_max2 = std::max(ic->rcoulomb, ic->rvdw);
+    real rcutoff_max2 = std::max(ic.rcoulomb, ic.rvdw);
     rcutoff_max2      = rcutoff_max2 * rcutoff_max2;
 
     const real* tab_ewald_F_lj           = nullptr;
@@ -310,18 +309,18 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
     real        sh_ewald                 = 0;
     if (elecInteractionTypeIsEwald || vdwInteractionTypeIsEwald)
     {
-        sh_ewald = ic->sh_ewald;
+        sh_ewald = ic.sh_ewald;
     }
     if (elecInteractionTypeIsEwald)
     {
-        const auto& coulombTables = *ic->coulombEwaldTables;
+        const auto& coulombTables = *ic.coulombEwaldTables;
         ewtab                     = coulombTables.tableFDV0.data();
         coulombTableScale         = coulombTables.scale;
         coulombTableScaleInvHalf  = half / coulombTableScale;
     }
     if (vdwInteractionTypeIsEwald)
     {
-        const auto& vdwTables = *ic->vdwEwaldTables;
+        const auto& vdwTables = *ic.vdwEwaldTables;
         tab_ewald_F_lj        = vdwTables.tableF.data();
         tab_ewald_V_lj        = vdwTables.tableV.data();
         vdwTableScale         = vdwTables.scale;
@@ -343,8 +342,8 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
     GMX_RELEASE_ASSERT(!(vdwInteractionTypeIsEwald && vdwModifierIsPotSwitch),
                        "Can not apply soft-core to switched Ewald potentials");
 
-    real dvdl_coul = 0;
-    real dvdl_vdw  = 0;
+    real dvdlCoul = 0;
+    real dvdlVdw  = 0;
 
     /* Lambda factor for state A, 1-lambda*/
     real LFC[NSTATES], LFV[NSTATES];
@@ -360,22 +359,22 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
     DLF[STATE_A] = -1;
     DLF[STATE_B] = 1;
 
-    real           lfac_coul[NSTATES], dlfac_coul[NSTATES], lfac_vdw[NSTATES], dlfac_vdw[NSTATES];
+    real           lFacCoul[NSTATES], dlFacCoul[NSTATES], lFacVdw[NSTATES], dlFacVdw[NSTATES];
     constexpr real sc_r_power = 6.0_real;
     for (int i = 0; i < NSTATES; i++)
     {
-        lfac_coul[i]  = (lam_power == 2 ? (1 - LFC[i]) * (1 - LFC[i]) : (1 - LFC[i]));
-        dlfac_coul[i] = DLF[i] * lam_power / sc_r_power * (lam_power == 2 ? (1 - LFC[i]) : 1);
-        lfac_vdw[i]   = (lam_power == 2 ? (1 - LFV[i]) * (1 - LFV[i]) : (1 - LFV[i]));
-        dlfac_vdw[i]  = DLF[i] * lam_power / sc_r_power * (lam_power == 2 ? (1 - LFV[i]) : 1);
+        lFacCoul[i]  = (lam_power == 2 ? (1 - LFC[i]) * (1 - LFC[i]) : (1 - LFC[i]));
+        dlFacCoul[i] = DLF[i] * lam_power / sc_r_power * (lam_power == 2 ? (1 - LFC[i]) : 1);
+        lFacVdw[i]   = (lam_power == 2 ? (1 - LFV[i]) * (1 - LFV[i]) : (1 - LFV[i]));
+        dlFacVdw[i]  = DLF[i] * lam_power / sc_r_power * (lam_power == 2 ? (1 - LFV[i]) : 1);
     }
 
     // TODO: We should get rid of using pointers to real
-    const real* x             = xx[0];
+    const real* x             = coords[0];
     real* gmx_restrict f      = &(forceWithShiftForces->force()[0][0]);
     real* gmx_restrict fshift = &(forceWithShiftForces->shiftForces()[0][0]);
 
-    const real rlistSquared = gmx::square(fr->rlist);
+    const real rlistSquared = gmx::square(rlist);
 
     int numExcludedPairsBeyondRlist = 0;
 
@@ -383,10 +382,11 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
     {
         int npair_within_cutoff = 0;
 
-        const int  is3   = 3 * shift[n];
-        const real shX   = shiftvec[is3];
-        const real shY   = shiftvec[is3 + 1];
-        const real shZ   = shiftvec[is3 + 2];
+        const int  is    = shift[n];
+        const int  is3   = DIM * is;
+        const real shX   = shiftvec[is][XX];
+        const real shY   = shiftvec[is][YY];
+        const real shZ   = shiftvec[is][ZZ];
         const int  nj0   = jindex[n];
         const int  nj1   = jindex[n + 1];
         const int  ii    = iinr[n];
@@ -398,29 +398,29 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
         const real iqB   = facel * chargeB[ii];
         const int  ntiA  = 2 * ntype * typeA[ii];
         const int  ntiB  = 2 * ntype * typeB[ii];
-        real       vctot = 0;
-        real       vvtot = 0;
-        real       fix   = 0;
-        real       fiy   = 0;
-        real       fiz   = 0;
+        real       vCTot = 0;
+        real       vVTot = 0;
+        real       fIX   = 0;
+        real       fIY   = 0;
+        real       fIZ   = 0;
 
         for (int k = nj0; k < nj1; k++)
         {
             int            tj[NSTATES];
             const int      jnr = jjnr[k];
             const int      j3  = 3 * jnr;
-            RealType       c6[NSTATES], c12[NSTATES], qq[NSTATES], Vcoul[NSTATES], Vvdw[NSTATES];
-            RealType       r, rinv, rp, rpm2;
-            RealType       alpha_vdw_eff, alpha_coul_eff, sigma6[NSTATES];
-            const RealType dx  = ix - x[j3];
-            const RealType dy  = iy - x[j3 + 1];
-            const RealType dz  = iz - x[j3 + 2];
-            const RealType rsq = dx * dx + dy * dy + dz * dz;
-            RealType       FscalC[NSTATES], FscalV[NSTATES];
+            RealType       c6[NSTATES], c12[NSTATES], qq[NSTATES], vCoul[NSTATES], vVdw[NSTATES];
+            RealType       r, rInv, rp, rpm2;
+            RealType       alphaVdwEff, alphaCoulEff, sigma6[NSTATES];
+            const RealType dX  = ix - x[j3];
+            const RealType dY  = iy - x[j3 + 1];
+            const RealType dZ  = iz - x[j3 + 2];
+            const RealType rSq = dX * dX + dY * dY + dZ * dZ;
+            RealType       fScalC[NSTATES], fScalV[NSTATES];
             /* Check if this pair on the exlusions list.*/
-            const bool bPairIncluded = nlist->excl_fep == nullptr || nlist->excl_fep[k];
+            const bool bPairIncluded = nlist.excl_fep.empty() || nlist.excl_fep[k];
 
-            if (rsq >= rcutoff_max2 && bPairIncluded)
+            if (rSq >= rcutoff_max2 && bPairIncluded)
             {
                 /* We save significant time by skipping all code below.
                  * Note that with soft-core interactions, the actual cut-off
@@ -435,21 +435,21 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
             }
             npair_within_cutoff++;
 
-            if (rsq > rlistSquared)
+            if (rSq > rlistSquared)
             {
                 numExcludedPairsBeyondRlist++;
             }
 
-            if (rsq > 0)
+            if (rSq > 0)
             {
                 /* Note that unlike in the nbnxn kernels, we do not need
-                 * to clamp the value of rsq before taking the invsqrt
+                 * to clamp the value of rSq before taking the invsqrt
                  * to avoid NaN in the LJ calculation, since here we do
                  * not calculate LJ interactions when C6 and C12 are zero.
                  */
 
-                rinv = gmx::invsqrt(rsq);
-                r    = rsq * rinv;
+                rInv = gmx::invsqrt(rSq);
+                r    = rSq * rInv;
             }
             else
             {
@@ -457,14 +457,14 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
                  * But note that the potential is in general non-zero,
                  * since the soft-cored r will be non-zero.
                  */
-                rinv = 0;
+                rInv = 0;
                 r    = 0;
             }
 
             if (useSoftCore)
             {
-                rpm2 = rsq * rsq;  /* r4 */
-                rp   = rpm2 * rsq; /* r6 */
+                rpm2 = rSq * rSq;  /* r4 */
+                rp   = rpm2 * rSq; /* r6 */
             }
             else
             {
@@ -472,11 +472,11 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
                  * with not using soft-core, so we use power of 0 which gives
                  * the simplest math and cheapest code.
                  */
-                rpm2 = rinv * rinv;
+                rpm2 = rInv * rInv;
                 rp   = 1;
             }
 
-            RealType Fscal = 0;
+            RealType fScal = 0;
 
             qq[STATE_A] = iqA * chargeA[jnr];
             qq[STATE_B] = iqB * chargeB[jnr];
@@ -515,24 +515,24 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
                     /* only use softcore if one of the states has a zero endstate - softcore is for avoiding infinities!*/
                     if ((c12[STATE_A] > 0) && (c12[STATE_B] > 0))
                     {
-                        alpha_vdw_eff  = 0;
-                        alpha_coul_eff = 0;
+                        alphaVdwEff  = 0;
+                        alphaCoulEff = 0;
                     }
                     else
                     {
-                        alpha_vdw_eff  = alpha_vdw;
-                        alpha_coul_eff = alpha_coul;
+                        alphaVdwEff  = alpha_vdw;
+                        alphaCoulEff = alpha_coul;
                     }
                 }
 
                 for (int i = 0; i < NSTATES; i++)
                 {
-                    FscalC[i] = 0;
-                    FscalV[i] = 0;
-                    Vcoul[i]  = 0;
-                    Vvdw[i]   = 0;
+                    fScalC[i] = 0;
+                    fScalV[i] = 0;
+                    vCoul[i]  = 0;
+                    vVdw[i]   = 0;
 
-                    RealType rinvC, rinvV, rC, rV, rpinvC, rpinvV;
+                    RealType rInvC, rInvV, rC, rV, rPInvC, rPInvV;
 
                     /* Only spend time on A or B state if it is non-zero */
                     if ((qq[i] != 0) || (c6[i] != 0) || (c12[i] != 0))
@@ -540,29 +540,29 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
                         /* this section has to be inside the loop because of the dependence on sigma6 */
                         if (useSoftCore)
                         {
-                            rpinvC = one / (alpha_coul_eff * lfac_coul[i] * sigma6[i] + rp);
-                            pthRoot(rpinvC, &rinvC, &rC);
+                            rPInvC = one / (alphaCoulEff * lFacCoul[i] * sigma6[i] + rp);
+                            pthRoot(rPInvC, &rInvC, &rC);
                             if (scLambdasOrAlphasDiffer)
                             {
-                                rpinvV = one / (alpha_vdw_eff * lfac_vdw[i] * sigma6[i] + rp);
-                                pthRoot(rpinvV, &rinvV, &rV);
+                                rPInvV = one / (alphaVdwEff * lFacVdw[i] * sigma6[i] + rp);
+                                pthRoot(rPInvV, &rInvV, &rV);
                             }
                             else
                             {
                                 /* We can avoid one expensive pow and one / operation */
-                                rpinvV = rpinvC;
-                                rinvV  = rinvC;
+                                rPInvV = rPInvC;
+                                rInvV  = rInvC;
                                 rV     = rC;
                             }
                         }
                         else
                         {
-                            rpinvC = 1;
-                            rinvC  = rinv;
+                            rPInvC = 1;
+                            rInvC  = rInv;
                             rC     = r;
 
-                            rpinvV = 1;
-                            rinvV  = rinv;
+                            rPInvV = 1;
+                            rInvV  = rInv;
                             rV     = r;
                         }
 
@@ -570,20 +570,20 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
                          * and if we either include all entries in the list (no cutoff
                          * used in the kernel), or if we are within the cutoff.
                          */
-                        bool computeElecInteraction = (elecInteractionTypeIsEwald && r < rcoulomb)
-                                                      || (!elecInteractionTypeIsEwald && rC < rcoulomb);
+                        bool computeElecInteraction = (elecInteractionTypeIsEwald && r < rCoulomb)
+                                                      || (!elecInteractionTypeIsEwald && rC < rCoulomb);
 
                         if ((qq[i] != 0) && computeElecInteraction)
                         {
                             if (elecInteractionTypeIsEwald)
                             {
-                                Vcoul[i]  = ewaldPotential(qq[i], rinvC, sh_ewald);
-                                FscalC[i] = ewaldScalarForce(qq[i], rinvC);
+                                vCoul[i]  = ewaldPotential(qq[i], rInvC, sh_ewald);
+                                fScalC[i] = ewaldScalarForce(qq[i], rInvC);
                             }
                             else
                             {
-                                Vcoul[i]  = reactionFieldPotential(qq[i], rinvC, rC, krf, crf);
-                                FscalC[i] = reactionFieldScalarForce(qq[i], rinvC, rC, krf, two);
+                                vCoul[i]  = reactionFieldPotential(qq[i], rInvC, rC, krf, crf);
+                                fScalC[i] = reactionFieldScalarForce(qq[i], rInvC, rC, krf, two);
                             }
                         }
 
@@ -592,89 +592,89 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
                          * include all entries in the list (no cutoff used
                          * in the kernel), or if we are within the cutoff.
                          */
-                        bool computeVdwInteraction = (vdwInteractionTypeIsEwald && r < rvdw)
-                                                     || (!vdwInteractionTypeIsEwald && rV < rvdw);
+                        bool computeVdwInteraction = (vdwInteractionTypeIsEwald && r < rVdw)
+                                                     || (!vdwInteractionTypeIsEwald && rV < rVdw);
                         if ((c6[i] != 0 || c12[i] != 0) && computeVdwInteraction)
                         {
-                            RealType rinv6;
+                            RealType rInv6;
                             if (useSoftCore)
                             {
-                                rinv6 = rpinvV;
+                                rInv6 = rPInvV;
                             }
                             else
                             {
-                                rinv6 = calculateRinv6(rinvV);
+                                rInv6 = calculateRinv6(rInvV);
                             }
-                            RealType Vvdw6  = calculateVdw6(c6[i], rinv6);
-                            RealType Vvdw12 = calculateVdw12(c12[i], rinv6);
+                            RealType vVdw6  = calculateVdw6(c6[i], rInv6);
+                            RealType vVdw12 = calculateVdw12(c12[i], rInv6);
 
-                            Vvdw[i] = lennardJonesPotential(Vvdw6, Vvdw12, c6[i], c12[i], repulsionShift,
-                                                            dispersionShift, onesixth, onetwelfth);
-                            FscalV[i] = lennardJonesScalarForce(Vvdw6, Vvdw12);
+                            vVdw[i] = lennardJonesPotential(
+                                    vVdw6, vVdw12, c6[i], c12[i], repulsionShift, dispersionShift, oneSixth, oneTwelfth);
+                            fScalV[i] = lennardJonesScalarForce(vVdw6, vVdw12);
 
                             if (vdwInteractionTypeIsEwald)
                             {
                                 /* Subtract the grid potential at the cut-off */
-                                Vvdw[i] += ewaldLennardJonesGridSubtract(nbfp_grid[tj[i]],
-                                                                         sh_lj_ewald, onesixth);
+                                vVdw[i] += ewaldLennardJonesGridSubtract(
+                                        nbfp_grid[tj[i]], shLjEwald, oneSixth);
                             }
 
                             if (vdwModifierIsPotSwitch)
                             {
-                                RealType d        = rV - ic->rvdw_switch;
+                                RealType d        = rV - ic.rvdw_switch;
                                 d                 = (d > zero) ? d : zero;
                                 const RealType d2 = d * d;
                                 const RealType sw =
                                         one + d2 * d * (vdw_swV3 + d * (vdw_swV4 + d * vdw_swV5));
                                 const RealType dsw = d2 * (vdw_swF2 + d * (vdw_swF3 + d * vdw_swF4));
 
-                                FscalV[i] = potSwitchScalarForceMod(FscalV[i], Vvdw[i], sw, rV,
-                                                                    rvdw, dsw, zero);
-                                Vvdw[i]   = potSwitchPotentialMod(Vvdw[i], sw, rV, rvdw, zero);
+                                fScalV[i] = potSwitchScalarForceMod(
+                                        fScalV[i], vVdw[i], sw, rV, rVdw, dsw, zero);
+                                vVdw[i] = potSwitchPotentialMod(vVdw[i], sw, rV, rVdw, zero);
                             }
                         }
 
-                        /* FscalC (and FscalV) now contain: dV/drC * rC
+                        /* fScalC (and fScalV) now contain: dV/drC * rC
                          * Now we multiply by rC^-p, so it will be: dV/drC * rC^1-p
                          * Further down we first multiply by r^p-2 and then by
                          * the vector r, which in total gives: dV/drC * (r/rC)^1-p
                          */
-                        FscalC[i] *= rpinvC;
-                        FscalV[i] *= rpinvV;
+                        fScalC[i] *= rPInvC;
+                        fScalV[i] *= rPInvV;
                     }
                 } // end for (int i = 0; i < NSTATES; i++)
 
                 /* Assemble A and B states */
                 for (int i = 0; i < NSTATES; i++)
                 {
-                    vctot += LFC[i] * Vcoul[i];
-                    vvtot += LFV[i] * Vvdw[i];
+                    vCTot += LFC[i] * vCoul[i];
+                    vVTot += LFV[i] * vVdw[i];
 
-                    Fscal += LFC[i] * FscalC[i] * rpm2;
-                    Fscal += LFV[i] * FscalV[i] * rpm2;
+                    fScal += LFC[i] * fScalC[i] * rpm2;
+                    fScal += LFV[i] * fScalV[i] * rpm2;
 
                     if (useSoftCore)
                     {
-                        dvdl_coul += Vcoul[i] * DLF[i]
-                                     + LFC[i] * alpha_coul_eff * dlfac_coul[i] * FscalC[i] * sigma6[i];
-                        dvdl_vdw += Vvdw[i] * DLF[i]
-                                    + LFV[i] * alpha_vdw_eff * dlfac_vdw[i] * FscalV[i] * sigma6[i];
+                        dvdlCoul += vCoul[i] * DLF[i]
+                                    + LFC[i] * alphaCoulEff * dlFacCoul[i] * fScalC[i] * sigma6[i];
+                        dvdlVdw += vVdw[i] * DLF[i]
+                                   + LFV[i] * alphaVdwEff * dlFacVdw[i] * fScalV[i] * sigma6[i];
                     }
                     else
                     {
-                        dvdl_coul += Vcoul[i] * DLF[i];
-                        dvdl_vdw += Vvdw[i] * DLF[i];
+                        dvdlCoul += vCoul[i] * DLF[i];
+                        dvdlVdw += vVdw[i] * DLF[i];
                     }
                 }
             } // end if (bPairIncluded)
-            else if (icoul == GMX_NBKERNEL_ELEC_REACTIONFIELD)
+            else if (icoul == NbkernelElecType::ReactionField)
             {
                 /* For excluded pairs, which are only in this pair list when
                  * using the Verlet scheme, we don't use soft-core.
                  * As there is no singularity, there is no need for soft-core.
                  */
                 const real FF = -two * krf;
-                RealType   VV = krf * rsq - crf;
+                RealType   VV = krf * rSq - crf;
 
                 if (ii == jnr)
                 {
@@ -683,13 +683,13 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
 
                 for (int i = 0; i < NSTATES; i++)
                 {
-                    vctot += LFC[i] * qq[i] * VV;
-                    Fscal += LFC[i] * qq[i] * FF;
-                    dvdl_coul += DLF[i] * qq[i] * VV;
+                    vCTot += LFC[i] * qq[i] * VV;
+                    fScal += LFC[i] * qq[i] * FF;
+                    dvdlCoul += DLF[i] * qq[i] * VV;
                 }
             }
 
-            if (elecInteractionTypeIsEwald && (r < rcoulomb || !bPairIncluded))
+            if (elecInteractionTypeIsEwald && (r < rCoulomb || !bPairIncluded))
             {
                 /* See comment in the preamble. When using Ewald interactions
                  * (unless we use a switch modifier) we subtract the reciprocal-space
@@ -707,7 +707,7 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
                 ewitab                = 4 * ewitab;
                 f_lr                  = ewtab[ewitab] + eweps * ewtab[ewitab + 1];
                 v_lr = (ewtab[ewitab + 2] - coulombTableScaleInvHalf * eweps * (ewtab[ewitab] + f_lr));
-                f_lr *= rinv;
+                f_lr *= rInv;
 
                 /* Note that any possible Ewald shift has already been applied in
                  * the normal interaction part above.
@@ -725,13 +725,13 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
 
                 for (int i = 0; i < NSTATES; i++)
                 {
-                    vctot -= LFC[i] * qq[i] * v_lr;
-                    Fscal -= LFC[i] * qq[i] * f_lr;
-                    dvdl_coul -= (DLF[i] * qq[i]) * v_lr;
+                    vCTot -= LFC[i] * qq[i] * v_lr;
+                    fScal -= LFC[i] * qq[i] * f_lr;
+                    dvdlCoul -= (DLF[i] * qq[i]) * v_lr;
                 }
             }
 
-            if (vdwInteractionTypeIsEwald && (r < rvdw || !bPairIncluded))
+            if (vdwInteractionTypeIsEwald && (r < rVdw || !bPairIncluded))
             {
                 /* See comment in the preamble. When using LJ-Ewald interactions
                  * (unless we use a switch modifier) we subtract the reciprocal-space
@@ -746,14 +746,14 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
                  * r close to 0 for non-interacting pairs.
                  */
 
-                const RealType rs   = rsq * rinv * vdwTableScale;
+                const RealType rs   = rSq * rInv * vdwTableScale;
                 const IntType  ri   = static_cast<IntType>(rs);
                 const RealType frac = rs - ri;
                 const RealType f_lr = (1 - frac) * tab_ewald_F_lj[ri] + frac * tab_ewald_F_lj[ri + 1];
                 /* TODO: Currently the Ewald LJ table does not contain
                  * the factor 1/6, we should add this.
                  */
-                const RealType FF = f_lr * rinv / six;
+                const RealType FF = f_lr * rInv / six;
                 RealType       VV =
                         (tab_ewald_V_lj[ri] - vdwTableScaleInvHalf * frac * (tab_ewald_F_lj[ri] + f_lr))
                         / six;
@@ -771,20 +771,20 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
                 for (int i = 0; i < NSTATES; i++)
                 {
                     const real c6grid = nbfp_grid[tj[i]];
-                    vvtot += LFV[i] * c6grid * VV;
-                    Fscal += LFV[i] * c6grid * FF;
-                    dvdl_vdw += (DLF[i] * c6grid) * VV;
+                    vVTot += LFV[i] * c6grid * VV;
+                    fScal += LFV[i] * c6grid * FF;
+                    dvdlVdw += (DLF[i] * c6grid) * VV;
                 }
             }
 
             if (doForces)
             {
-                const real tx = Fscal * dx;
-                const real ty = Fscal * dy;
-                const real tz = Fscal * dz;
-                fix           = fix + tx;
-                fiy           = fiy + ty;
-                fiz           = fiz + tz;
+                const real tX = fScal * dX;
+                const real tY = fScal * dY;
+                const real tZ = fScal * dZ;
+                fIX           = fIX + tX;
+                fIY           = fIY + tY;
+                fIZ           = fIZ + tZ;
                 /* OpenMP atomics are expensive, but this kernels is also
                  * expensive, so we can take this hit, instead of using
                  * thread-local output buffers and extra reduction.
@@ -793,11 +793,11 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
                  * not throw, so no need for try/catch.
                  */
 #pragma omp atomic
-                f[j3] -= tx;
+                f[j3] -= tX;
 #pragma omp atomic
-                f[j3 + 1] -= ty;
+                f[j3 + 1] -= tY;
 #pragma omp atomic
-                f[j3 + 2] -= tz;
+                f[j3 + 2] -= tZ;
             }
         } // end for (int k = nj0; k < nj1; k++)
 
@@ -811,43 +811,42 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
             if (doForces)
             {
 #pragma omp atomic
-                f[ii3] += fix;
+                f[ii3] += fIX;
 #pragma omp atomic
-                f[ii3 + 1] += fiy;
+                f[ii3 + 1] += fIY;
 #pragma omp atomic
-                f[ii3 + 2] += fiz;
+                f[ii3 + 2] += fIZ;
             }
             if (doShiftForces)
             {
 #pragma omp atomic
-                fshift[is3] += fix;
+                fshift[is3] += fIX;
 #pragma omp atomic
-                fshift[is3 + 1] += fiy;
+                fshift[is3 + 1] += fIY;
 #pragma omp atomic
-                fshift[is3 + 2] += fiz;
+                fshift[is3 + 2] += fIZ;
             }
             if (doPotential)
             {
                 int ggid = gid[n];
 #pragma omp atomic
-                Vc[ggid] += vctot;
+                energygrp_elec[ggid] += vCTot;
 #pragma omp atomic
-                Vv[ggid] += vvtot;
+                energygrp_vdw[ggid] += vVTot;
             }
         }
     } // end for (int n = 0; n < nri; n++)
 
 #pragma omp atomic
-    dvdl[efptCOUL] += dvdl_coul;
+    dvdl[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)] += dvdlCoul;
 #pragma omp atomic
-    dvdl[efptVDW] += dvdl_vdw;
+    dvdl[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)] += dvdlVdw;
 
     /* Estimate flops, average for free energy stuff:
      * 12  flops per outer iteration
      * 150 flops per inner iteration
      */
-#pragma omp atomic
-    inc_nrnb(nrnb, eNR_NBKERNEL_FREE_ENERGY, nlist->nri * 12 + nlist->jindex[nri] * 150);
+    atomicNrnbIncrement(nrnb, eNR_NBKERNEL_FREE_ENERGY, nlist.nri * 12 + nlist.jindex[nri] * 150);
 
     if (numExcludedPairsBeyondRlist > 0)
     {
@@ -859,16 +858,29 @@ static void nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
                   "latter is the case, you can try to increase nstlist or rlist to avoid this."
                   "The error is likely triggered by the use of couple-intramol=no "
                   "and the maximal distance in the decoupled molecule exceeding rlist.",
-                  numExcludedPairsBeyondRlist, fr->rlist);
+                  numExcludedPairsBeyondRlist,
+                  rlist);
     }
 }
 
-typedef void (*KernelFunction)(const t_nblist* gmx_restrict nlist,
-                               rvec* gmx_restrict         xx,
-                               gmx::ForceWithShiftForces* forceWithShiftForces,
-                               const t_forcerec* gmx_restrict fr,
-                               const t_mdatoms* gmx_restrict mdatoms,
-                               nb_kernel_data_t* gmx_restrict kernel_data,
+typedef void (*KernelFunction)(const t_nblist&                nlist,
+                               gmx::ArrayRef<const gmx::RVec> coords,
+                               gmx::ForceWithShiftForces*     forceWithShiftForces,
+                               const int                      ntype,
+                               const real                     rlist,
+                               const interaction_const_t&     ic,
+                               gmx::ArrayRef<const gmx::RVec> shiftvec,
+                               gmx::ArrayRef<const real>      nbfp,
+                               gmx::ArrayRef<const real>      nbfp_grid,
+                               gmx::ArrayRef<const real>      chargeA,
+                               gmx::ArrayRef<const real>      chargeB,
+                               gmx::ArrayRef<const int>       typeA,
+                               gmx::ArrayRef<const int>       typeB,
+                               int                            flags,
+                               gmx::ArrayRef<const real>      lambda,
+                               gmx::ArrayRef<real>            dvdl,
+                               gmx::ArrayRef<real>            energygrp_elec,
+                               gmx::ArrayRef<real>            energygrp_vdw,
                                t_nrnb* gmx_restrict nrnb);
 
 template<bool useSoftCore, bool scLambdasOrAlphasDiffer, bool vdwInteractionTypeIsEwald, bool elecInteractionTypeIsEwald, bool vdwModifierIsPotSwitch>
@@ -878,17 +890,14 @@ static KernelFunction dispatchKernelOnUseSimd(const bool useSimd)
     {
 #if GMX_SIMD_HAVE_REAL && GMX_SIMD_HAVE_INT32_ARITHMETICS && GMX_USE_SIMD_KERNELS
         /* FIXME: Here SimdDataTypes should be used to enable SIMD. So far, the code in nb_free_energy_kernel is not adapted to SIMD */
-        return (nb_free_energy_kernel<ScalarDataTypes, useSoftCore, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald,
-                                      elecInteractionTypeIsEwald, vdwModifierIsPotSwitch>);
+        return (nb_free_energy_kernel<ScalarDataTypes, useSoftCore, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald, vdwModifierIsPotSwitch>);
 #else
-        return (nb_free_energy_kernel<ScalarDataTypes, useSoftCore, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald,
-                                      elecInteractionTypeIsEwald, vdwModifierIsPotSwitch>);
+        return (nb_free_energy_kernel<ScalarDataTypes, useSoftCore, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald, vdwModifierIsPotSwitch>);
 #endif
     }
     else
     {
-        return (nb_free_energy_kernel<ScalarDataTypes, useSoftCore, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald,
-                                      elecInteractionTypeIsEwald, vdwModifierIsPotSwitch>);
+        return (nb_free_energy_kernel<ScalarDataTypes, useSoftCore, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald, vdwModifierIsPotSwitch>);
     }
 }
 
@@ -897,13 +906,13 @@ static KernelFunction dispatchKernelOnVdwModifier(const bool vdwModifierIsPotSwi
 {
     if (vdwModifierIsPotSwitch)
     {
-        return (dispatchKernelOnUseSimd<useSoftCore, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald,
-                                        elecInteractionTypeIsEwald, true>(useSimd));
+        return (dispatchKernelOnUseSimd<useSoftCore, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald, true>(
+                useSimd));
     }
     else
     {
-        return (dispatchKernelOnUseSimd<useSoftCore, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald,
-                                        elecInteractionTypeIsEwald, false>(useSimd));
+        return (dispatchKernelOnUseSimd<useSoftCore, scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald, false>(
+                useSimd));
     }
 }
 
@@ -970,38 +979,53 @@ static KernelFunction dispatchKernel(const bool                 scLambdasOrAlpha
 {
     if (ic.softCoreParameters->alphaCoulomb == 0 && ic.softCoreParameters->alphaVdw == 0)
     {
-        return (dispatchKernelOnScLambdasOrAlphasDifference<false>(
-                scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald,
-                vdwModifierIsPotSwitch, useSimd));
+        return (dispatchKernelOnScLambdasOrAlphasDifference<false>(scLambdasOrAlphasDiffer,
+                                                                   vdwInteractionTypeIsEwald,
+                                                                   elecInteractionTypeIsEwald,
+                                                                   vdwModifierIsPotSwitch,
+                                                                   useSimd));
     }
     else
     {
-        return (dispatchKernelOnScLambdasOrAlphasDifference<true>(
-                scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald, elecInteractionTypeIsEwald,
-                vdwModifierIsPotSwitch, useSimd));
+        return (dispatchKernelOnScLambdasOrAlphasDifference<true>(scLambdasOrAlphasDiffer,
+                                                                  vdwInteractionTypeIsEwald,
+                                                                  elecInteractionTypeIsEwald,
+                                                                  vdwModifierIsPotSwitch,
+                                                                  useSimd));
     }
 }
 
 
-void gmx_nb_free_energy_kernel(const t_nblist*            nlist,
-                               rvec*                      xx,
-                               gmx::ForceWithShiftForces* ff,
-                               const t_forcerec*          fr,
-                               const t_mdatoms*           mdatoms,
-                               nb_kernel_data_t*          kernel_data,
-                               t_nrnb*                    nrnb)
+void gmx_nb_free_energy_kernel(const t_nblist&                nlist,
+                               gmx::ArrayRef<const gmx::RVec> coords,
+                               gmx::ForceWithShiftForces*     ff,
+                               const bool                     useSimd,
+                               const int                      ntype,
+                               const real                     rlist,
+                               const interaction_const_t&     ic,
+                               gmx::ArrayRef<const gmx::RVec> shiftvec,
+                               gmx::ArrayRef<const real>      nbfp,
+                               gmx::ArrayRef<const real>      nbfp_grid,
+                               gmx::ArrayRef<const real>      chargeA,
+                               gmx::ArrayRef<const real>      chargeB,
+                               gmx::ArrayRef<const int>       typeA,
+                               gmx::ArrayRef<const int>       typeB,
+                               int                            flags,
+                               gmx::ArrayRef<const real>      lambda,
+                               gmx::ArrayRef<real>            dvdl,
+                               gmx::ArrayRef<real>            energygrp_elec,
+                               gmx::ArrayRef<real>            energygrp_vdw,
+                               t_nrnb*                        nrnb)
 {
-    const interaction_const_t& ic = *fr->ic;
-    GMX_ASSERT(EEL_PME_EWALD(ic.eeltype) || ic.eeltype == eelCUT || EEL_RF(ic.eeltype),
+    GMX_ASSERT(EEL_PME_EWALD(ic.eeltype) || ic.eeltype == CoulombInteractionType::Cut || EEL_RF(ic.eeltype),
                "Unsupported eeltype with free energy");
     GMX_ASSERT(ic.softCoreParameters, "We need soft-core parameters");
 
     const auto& scParams                   = *ic.softCoreParameters;
     const bool  vdwInteractionTypeIsEwald  = (EVDW_PME(ic.vdwtype));
     const bool  elecInteractionTypeIsEwald = (EEL_PME_EWALD(ic.eeltype));
-    const bool  vdwModifierIsPotSwitch     = (ic.vdw_modifier == eintmodPOTSWITCH);
+    const bool  vdwModifierIsPotSwitch     = (ic.vdw_modifier == InteractionModifiers::PotSwitch);
     bool        scLambdasOrAlphasDiffer    = true;
-    const bool  useSimd                    = fr->use_simd_kernels;
 
     if (scParams.alphaCoulomb == 0 && scParams.alphaVdw == 0)
     {
@@ -1009,7 +1033,8 @@ void gmx_nb_free_energy_kernel(const t_nblist*            nlist,
     }
     else
     {
-        if (kernel_data->lambda[efptCOUL] == kernel_data->lambda[efptVDW]
+        if (lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)]
+                    == lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)]
             && scParams.alphaCoulomb == scParams.alphaVdw)
         {
             scLambdasOrAlphasDiffer = false;
@@ -1017,7 +1042,29 @@ void gmx_nb_free_energy_kernel(const t_nblist*            nlist,
     }
 
     KernelFunction kernelFunc;
-    kernelFunc = dispatchKernel(scLambdasOrAlphasDiffer, vdwInteractionTypeIsEwald,
-                                elecInteractionTypeIsEwald, vdwModifierIsPotSwitch, useSimd, ic);
-    kernelFunc(nlist, xx, ff, fr, mdatoms, kernel_data, nrnb);
+    kernelFunc = dispatchKernel(scLambdasOrAlphasDiffer,
+                                vdwInteractionTypeIsEwald,
+                                elecInteractionTypeIsEwald,
+                                vdwModifierIsPotSwitch,
+                                useSimd,
+                                ic);
+    kernelFunc(nlist,
+               coords,
+               ff,
+               ntype,
+               rlist,
+               ic,
+               shiftvec,
+               nbfp,
+               nbfp_grid,
+               chargeA,
+               chargeB,
+               typeA,
+               typeB,
+               flags,
+               lambda,
+               dvdl,
+               energygrp_elec,
+               energygrp_vdw,
+               nrnb);
 }
index ee78e7fe0241b5cb6aee7c2072402e4f07a84cba..534b7527d6c412adc651cf36589a9ad279c3a807 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,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
-#ifndef _nb_free_energy_h_
-#define _nb_free_energy_h_
+#ifndef GMX_GMXLIB_NONBONDED_NB_FREE_ENERGY_H
+#define GMX_GMXLIB_NONBONDED_NB_FREE_ENERGY_H
 
-#include "gromacs/gmxlib/nrnb.h"
-#include "gromacs/gmxlib/nonbonded/nb_kernel.h"
 #include "gromacs/math/vectypes.h"
-#include "gromacs/mdtypes/nblist.h"
+#include "gromacs/utility/basedefinitions.h"
 
 struct t_forcerec;
-struct t_mdatoms;
+struct t_nrnb;
+struct t_nblist;
+struct interaction_const_t;
 namespace gmx
 {
 class ForceWithShiftForces;
-}
+template<typename>
+class ArrayRef;
+} // namespace gmx
 
-void gmx_nb_free_energy_kernel(const t_nblist* gmx_restrict nlist,
-                               rvec* gmx_restrict         xx,
-                               gmx::ForceWithShiftForces* forceWithShiftForces,
-                               const t_forcerec* gmx_restrict fr,
-                               const t_mdatoms* gmx_restrict mdatoms,
-                               nb_kernel_data_t* gmx_restrict kernel_data,
+void gmx_nb_free_energy_kernel(const t_nblist&                nlist,
+                               gmx::ArrayRef<const gmx::RVec> coords,
+                               gmx::ForceWithShiftForces*     forceWithShiftForces,
+                               bool                           useSimd,
+                               int                            ntype,
+                               real                           rlist,
+                               const interaction_const_t&     ic,
+                               gmx::ArrayRef<const gmx::RVec> shiftvec,
+                               gmx::ArrayRef<const real>      nbfp,
+                               gmx::ArrayRef<const real>      nbfp_grid,
+                               gmx::ArrayRef<const real>      chargeA,
+                               gmx::ArrayRef<const real>      chargeB,
+                               gmx::ArrayRef<const int>       typeA,
+                               gmx::ArrayRef<const int>       typeB,
+                               int                            flags,
+                               gmx::ArrayRef<const real>      lambda,
+                               gmx::ArrayRef<real>            dvdl,
+                               gmx::ArrayRef<real>            energygrp_elec,
+                               gmx::ArrayRef<real>            energygrp_vdw,
                                t_nrnb* gmx_restrict nrnb);
 
 #endif
similarity index 72%
rename from cmake/gmxManageFujitsuSparc64.cmake
rename to src/gromacs/gmxlib/nonbonded/tests/CMakeLists.txt
index ac8ad950a5ba97572f5154b4cab85cefdb9071c4..ba9b6b92b61a1e2671c99184b51f11354553d685 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2012,2013,2014,2020, by the GROMACS development team, led by
+# Copyright (c) 2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
-# Managing configuration for Fujitsu PrimeHPC Sparc64
-# For now this is mainly used for K computer.
-message(STATUS "Configuring for Fujitsu Sparc64 (deprecated)")
-
-set(BUILD_SHARED_LIBS OFF CACHE BOOL "Use static linking by default on Fujitsu Sparc64" FORCE)
-set(GMX_GPU OFF CACHE BOOL "Cannot do GPU acceleration on Fujitsu Sparc64" FORCE)
-
-set(GMX_SOFTWARE_INVSQRT OFF CACHE BOOL "Use native 1.0/sqrt(x) on Fujitsu Sparc64" FORCE)
-set(GMX_X11 OFF CACHE BOOL "X11 not compatible with Fujitsu Sparc64 cross-compile, disabled." FORCE)
-
+gmx_add_unit_test(GmxlibTests nonbonded-fep-test
+    CPP_SOURCE_FILES
+        nb_free_energy.cpp
+    )
diff --git a/src/gromacs/gmxlib/nonbonded/tests/nb_free_energy.cpp b/src/gromacs/gmxlib/nonbonded/tests/nb_free_energy.cpp
new file mode 100644 (file)
index 0000000..5b7e084
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 nonbonded fep kernel
+ *
+ * Implements the test logic from the bonded interactions also for the
+ * nonbonded fep kernel. This requires setting up some more input
+ * structures that in the bonded case.
+ *
+ * The test setup consists of an atom pair that is evaluated in an fep setting
+ * (vanishing charge and lennard-jones parameters of atom #2) with and without
+ * softcore Potentials.
+ *
+ * \author Sebastian Kehl <sebastian.kehl@mpcdf.mpg.de>
+ * \ingroup module_gmxlib_nonbonded
+ */
+#include "gmxpre.h"
+
+#include "gromacs/gmxlib/nonbonded/nb_free_energy.h"
+#include "gromacs/gmxlib/nonbonded/nonbonded.h"
+
+#include <cmath>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/math/paddedvector.h"
+#include "gromacs/math/units.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/math/vectypes.h"
+#include "gromacs/math/arrayrefwithpadding.h"
+#include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/mdtypes/enerdata.h"
+#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/interaction_const.h"
+#include "gromacs/mdtypes/nblist.h"
+#include "gromacs/mdtypes/forceoutput.h"
+#include "gromacs/mdlib/forcerec.h"
+#include "gromacs/tables/forcetable.h"
+#include "gromacs/pbcutil/ishift.h"
+#include "gromacs/pbcutil/pbc.h"
+#include "gromacs/topology/idef.h"
+#include "gromacs/topology/forcefieldparameters.h"
+#include "gromacs/utility/enumerationhelpers.h"
+#include "gromacs/utility/strconvert.h"
+#include "gromacs/utility/stringstream.h"
+#include "gromacs/utility/textwriter.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/smalloc.h"
+#include "gromacs/ewald/ewald_utils.h"
+#include "gromacs/gmxlib/nrnb.h"
+
+#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
+
+namespace gmx
+{
+namespace test
+{
+namespace
+{
+
+//! Number of atoms used in these tests.
+constexpr int c_numAtoms     = 4;
+constexpr int c_numAtomTypes = 3;
+
+/*! \brief Output from nonbonded fep kernel
+ *
+ */
+struct OutputQuantities
+{
+    OutputQuantities() :
+        energy(static_cast<int>(NonBondedEnergyTerms::Count)),
+        dvdLambda(static_cast<int>(FreeEnergyPerturbationCouplingType::Count), 0.0),
+        fShift(1, { 0.0, 0.0, 0.0 }),
+        f(c_numAtoms, { 0.0, 0.0, 0.0 })
+    {
+    }
+
+    //! Energies of this interaction (size EgNR)
+    gmx_grppairener_t energy;
+    //! Derivative with respect to lambda (size efptNR)
+    std::vector<real> dvdLambda;
+    //! Shift force vectors (size N_IVEC but in this test only 1)
+    std::vector<RVec> fShift;
+    //! Forces (size c_numAtoms)
+    PaddedVector<RVec> f;
+};
+
+/*! \brief Utility to check the output from nonbonded test
+ *
+ * \param[in] checker Reference checker
+ * \param[in] output  The output from the test to check
+ */
+void checkOutput(TestReferenceChecker* checker, const OutputQuantities& output)
+{
+    checker->checkReal(output.energy.energyGroupPairTerms[NonBondedEnergyTerms::LJSR][0], "EVdw ");
+    checker->checkReal(output.energy.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR][0],
+                       "ECoul ");
+    checker->checkReal(output.dvdLambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)],
+                       "dVdlCoul ");
+    checker->checkReal(output.dvdLambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)],
+                       "dVdlVdw ");
+
+    checker->checkSequence(std::begin(output.f), std::end(output.f), "Forces");
+
+    auto shiftForcesChecker = checker->checkCompound("Shift-Forces", "Shift-forces");
+    shiftForcesChecker.checkVector(output.fShift[0], "Central");
+}
+
+class InteractionConstHelper
+{
+public:
+    InteractionConstHelper() {}
+
+    //! init data to construct interaction_const
+    void initInteractionConst(CoulombInteractionType coulType, VanDerWaalsType vdwType, InteractionModifiers vdwMod)
+    {
+        coulType_ = coulType;
+        vdwType_  = vdwType;
+        vdwMod_   = vdwMod;
+
+        // initialize correction tables
+        interaction_const_t tmp;
+        tmp.ewaldcoeff_q       = calc_ewaldcoeff_q(1.0, 1.0e-5);
+        tmp.ewaldcoeff_lj      = calc_ewaldcoeff_lj(1.0, 1.0e-5);
+        tmp.eeltype            = coulType;
+        tmp.vdwtype            = vdwType;
+        tmp.coulombEwaldTables = std::make_unique<EwaldCorrectionTables>();
+        tmp.vdwEwaldTables     = std::make_unique<EwaldCorrectionTables>();
+
+        init_interaction_const_tables(nullptr, &tmp, 1.0, 0.0);
+        coulombTables_ = *tmp.coulombEwaldTables;
+        vdwTables_     = *tmp.vdwEwaldTables;
+    }
+
+    /*! \brief Setup interaction_const_t
+     *
+     * \param[in]  fepVals t_lambda struct of fep values
+     * \param[out] ic      interaction_const_t pointer with data
+     */
+    void getInteractionConst(const t_lambda& fepVals, interaction_const_t* ic)
+    {
+        ic->softCoreParameters = std::unique_ptr<interaction_const_t::SoftCoreParameters>(
+                new interaction_const_t::SoftCoreParameters(fepVals));
+
+        ic->coulombEwaldTables  = std::unique_ptr<EwaldCorrectionTables>(new EwaldCorrectionTables);
+        *ic->coulombEwaldTables = coulombTables_;
+
+        ic->vdwEwaldTables  = std::unique_ptr<EwaldCorrectionTables>(new EwaldCorrectionTables);
+        *ic->vdwEwaldTables = vdwTables_;
+
+        // set coulomb and vdw types
+        ic->eeltype      = coulType_;
+        ic->vdwtype      = vdwType_;
+        ic->vdw_modifier = vdwMod_;
+
+        // some non default parameters used in this testcase
+        ic->epsfac                   = gmx::c_one4PiEps0 * 0.25;
+        ic->reactionFieldCoefficient = 0.0; // former k_rf
+        ic->reactionFieldShift       = 1.0; // former c_rf
+        ic->sh_ewald                 = 1.0e-5;
+        ic->sh_lj_ewald              = -1.0;
+        ic->dispersion_shift.cpot    = -1.0;
+        ic->repulsion_shift.cpot     = -1.0;
+    }
+
+private:
+    //! correction tables
+    EwaldCorrectionTables coulombTables_;
+    EwaldCorrectionTables vdwTables_;
+
+    //! coulomb and vdw type specifiers
+    CoulombInteractionType coulType_;
+    VanDerWaalsType        vdwType_;
+    InteractionModifiers   vdwMod_;
+};
+
+
+/* \brief Utility class to setup forcerec
+ *
+ * This helper takes care of handling the neccessary data that are kept
+ * at various places and in various forms in the forcerec hierarchy such
+ * that this class can safely be used.
+ *
+ * Data is only initialized as necessary for the nonbonded kernel to work!
+ */
+class ForcerecHelper
+{
+public:
+    ForcerecHelper()
+    {
+        fepVals_.sc_alpha     = 0.3;
+        fepVals_.sc_power     = 1;
+        fepVals_.sc_r_power   = 6.0;
+        fepVals_.sc_sigma     = 0.3;
+        fepVals_.sc_sigma_min = 0.3;
+        fepVals_.bScCoul      = true;
+    }
+
+    //! initialize data structure to construct forcerec
+    void initForcerec(const gmx_ffparams_t&  idef,
+                      CoulombInteractionType coulType,
+                      VanDerWaalsType        vdwType,
+                      InteractionModifiers   vdwMod)
+    {
+        icHelper_.initInteractionConst(coulType, vdwType, vdwMod);
+        nbfp_ = makeNonBondedParameterLists(idef, false);
+        t_forcerec frTmp;
+        ljPmeC6Grid_ = makeLJPmeC6GridCorrectionParameters(idef, frTmp);
+    }
+
+    void setSoftcoreAlpha(const real scAlpha) { fepVals_.sc_alpha = scAlpha; }
+    void setSoftcoreCoulomb(const real scCoulomb) { fepVals_.bScCoul = scCoulomb; }
+
+    //! get forcerec data as wanted by the nonbonded kernel
+    void getForcerec(t_forcerec* fr)
+    {
+        fr->ic = std::make_unique<interaction_const_t>();
+
+        // set data in ic
+        icHelper_.getInteractionConst(fepVals_, fr->ic.get());
+
+        // set data in fr
+        fr->ljpme_c6grid = ljPmeC6Grid_;
+        fr->nbfp         = nbfp_;
+        fr->shift_vec    = { { 0.0, 0.0, 0.0 } };
+        fr->rlist        = rlist_;
+        fr->ntype        = c_numAtomTypes;
+
+        // simd
+        fr->use_simd_kernels = GMX_USE_SIMD_KERNELS;
+    }
+
+private:
+    InteractionConstHelper icHelper_;
+    std::vector<real>      ljPmeC6Grid_;
+    std::vector<real>      nbfp_;
+    t_lambda               fepVals_;
+    real                   rlist_ = 1.0;
+};
+
+/*! \brief Utility structure to hold atoms data
+ *
+ * A system having 4 interactions with the following perturbation pattern:
+ *  - no perturbation
+ *  - vdw- and coulomb-perturbation
+ *  - coulomb-perturbation only
+ *  - vdw-perturbation only
+ *
+ * This is realized by defining 3 different atom types that control
+ * the vdw-perturbation. The coulomb-perturbation is controlled by directly
+ * setting the charge of the atoms at the lambda states A/B.
+ */
+struct AtomData
+{
+    AtomData()
+    {
+        idef.atnr = c_numAtomTypes;
+        idef.iparams.resize(2 * c_numAtomTypes * c_numAtomTypes);
+
+        // set interaction parameters for different combinations of types
+        idef.iparams[0].lj = { 0.001458, 1.0062882e-6 }; // 0-0
+        idef.iparams[1].lj = { 0.0, 0.0 };               // 0-1
+        idef.iparams[2].lj = { 0.001458, 1.0062882e-6 }; // 0-2
+        idef.iparams[3].lj = { 0.0, 0.0 };               // 1-0
+        idef.iparams[4].lj = { 0.0, 0.0 };               // 1-1
+        idef.iparams[5].lj = { 0.0, 0.0 };               // 1-2
+        idef.iparams[6].lj = { 0.001458, 1.0062882e-6 }; // 2-0
+        idef.iparams[7].lj = { 0.0, 0.0 };               // 2-1
+        idef.iparams[8].lj = { 0.001458, 1.0062882e-6 }; // 2-2
+
+        GMX_ASSERT(chargeA.size() == c_numAtoms, "This test wants 4 atoms");
+        GMX_ASSERT(chargeB.size() == c_numAtoms, "This test wants 4 atoms");
+        GMX_ASSERT(typeA.size() == c_numAtoms, "This test wants 4 atoms");
+        GMX_ASSERT(typeB.size() == c_numAtoms, "This test wants 4 atoms");
+    }
+
+    // forcefield parameters
+    gmx_ffparams_t idef;
+
+    // atom data
+    std::vector<real> chargeA = { 1.0, -1.0, -1.0, 1.0 };
+    std::vector<real> chargeB = { 1.0, 0.0, 0.0, 1.0 };
+    std::vector<int>  typeA   = { 0, 0, 0, 0 };
+    std::vector<int>  typeB   = { 0, 1, 2, 1 };
+    // perturbation pattern: {no-pert, vdw- and coul-pert, coul-pert, vdw-pert}
+
+    // neighbourhood information
+    std::vector<int> iAtoms  = { 0 };
+    std::vector<int> jAtoms  = { 0, 1, 2, 3 };
+    std::vector<int> jIndex  = { 0, 4 };
+    std::vector<int> shift   = { 0 };
+    std::vector<int> gid     = { 0 };
+    std::vector<int> exclFep = { 0, 1, 1, 1 };
+
+    // construct t_nblist
+    t_nblist getNbList()
+    {
+        t_nblist nbl;
+        nbl.nri      = 1;
+        nbl.nrj      = 4;
+        nbl.iinr     = iAtoms;
+        nbl.jindex   = jIndex;
+        nbl.jjnr     = jAtoms;
+        nbl.shift    = shift;
+        nbl.gid      = gid;
+        nbl.excl_fep = exclFep;
+        return nbl;
+    }
+};
+
+/*! \brief Input structure for nonbonded fep kernel
+ */
+struct ListInput
+{
+public:
+    //! Function type
+    int fType = F_LJ;
+    //! Tolerance for float evaluation
+    float floatToler = 1e-6;
+    //! Tolerance for double evaluation
+    double doubleToler = 1e-8;
+    //! atom parameters
+    AtomData atoms;
+    //! forcerec helper
+    ForcerecHelper frHelper;
+
+    //! Constructor
+    ListInput() {}
+
+    /*! \brief Constructor with tolerance
+     *
+     * \param[in] ftol Single precision tolerance
+     * \param[in] dtol Double precision tolerance
+     */
+    ListInput(float ftol, double dtol)
+    {
+        floatToler  = ftol;
+        doubleToler = dtol;
+    }
+
+    /*! \brief Set parameters for nonbonded interaction
+     *
+     * \param[in] coulType coulomb type
+     * \param[in] vdwType  vdw type
+     * \param[in] vdwMod   vdw potential modifier
+     */
+    ListInput setInteraction(CoulombInteractionType coulType, VanDerWaalsType vdwType, InteractionModifiers vdwMod)
+    {
+        frHelper.initForcerec(atoms.idef, coulType, vdwType, vdwMod);
+        return *this;
+    }
+};
+
+class NonbondedFepTest :
+    public ::testing::TestWithParam<std::tuple<ListInput, PaddedVector<RVec>, real, real, bool>>
+{
+protected:
+    PaddedVector<RVec>   x_;
+    ListInput            input_;
+    real                 lambda_;
+    real                 softcoreAlpha_;
+    bool                 softcoreCoulomb_;
+    TestReferenceData    refData_;
+    TestReferenceChecker checker_;
+
+    NonbondedFepTest() : checker_(refData_.rootChecker())
+    {
+        input_           = std::get<0>(GetParam());
+        x_               = std::get<1>(GetParam());
+        lambda_          = std::get<2>(GetParam());
+        softcoreAlpha_   = std::get<3>(GetParam());
+        softcoreCoulomb_ = std::get<4>(GetParam());
+
+        test::FloatingPointTolerance tolerance(
+                input_.floatToler, input_.doubleToler, 1.0e-6, 1.0e-12, 10000, 100, false);
+        checker_.setDefaultTolerance(tolerance);
+    }
+
+    void testKernel()
+    {
+        input_.frHelper.setSoftcoreAlpha(softcoreAlpha_);
+        input_.frHelper.setSoftcoreCoulomb(softcoreCoulomb_);
+
+        // get forcerec and interaction_const
+        t_forcerec fr;
+        input_.frHelper.getForcerec(&fr);
+
+        // t_nblist
+        t_nblist nbl = input_.atoms.getNbList();
+
+        // output buffers
+        OutputQuantities output;
+
+        // lambda vector
+        int numFepCouplingTerms = static_cast<int>(FreeEnergyPerturbationCouplingType::Count);
+        std::vector<real> lambdas(numFepCouplingTerms, lambda_);
+
+        // fep kernel data
+        int doNBFlags = 0;
+        doNBFlags |= GMX_NONBONDED_DO_FORCE;
+        doNBFlags |= GMX_NONBONDED_DO_SHIFTFORCE;
+        doNBFlags |= GMX_NONBONDED_DO_POTENTIAL;
+
+        // force buffers
+        bool                      unusedBool = true; // this bool has no effect in the kernel
+        gmx::ForceWithShiftForces forces(output.f.arrayRefWithPadding(), unusedBool, output.fShift);
+
+        // dummy counter
+        t_nrnb nrnb;
+
+        // run fep kernel
+        gmx_nb_free_energy_kernel(nbl,
+                                  x_.arrayRefWithPadding().unpaddedArrayRef(),
+                                  &forces,
+                                  fr.use_simd_kernels,
+                                  fr.ntype,
+                                  fr.rlist,
+                                  *fr.ic,
+                                  fr.shift_vec,
+                                  fr.nbfp,
+                                  fr.ljpme_c6grid,
+                                  input_.atoms.chargeA,
+                                  input_.atoms.chargeB,
+                                  input_.atoms.typeA,
+                                  input_.atoms.typeB,
+                                  doNBFlags,
+                                  lambdas,
+                                  output.dvdLambda,
+                                  output.energy.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR],
+                                  output.energy.energyGroupPairTerms[NonBondedEnergyTerms::LJSR],
+                                  &nrnb);
+
+        checkOutput(&checker_, output);
+    }
+};
+
+TEST_P(NonbondedFepTest, testKernel)
+{
+    testKernel();
+}
+
+//! configurations to test
+std::vector<ListInput> c_interaction = {
+    { ListInput(1e-6, 1e-8).setInteraction(CoulombInteractionType::Cut, VanDerWaalsType::Cut, InteractionModifiers::None) },
+    { ListInput(1e-6, 1e-8).setInteraction(CoulombInteractionType::Cut, VanDerWaalsType::Cut, InteractionModifiers::PotSwitch) },
+    { ListInput(1e-6, 1e-8).setInteraction(CoulombInteractionType::Pme, VanDerWaalsType::Pme, InteractionModifiers::None) }
+};
+
+//! test parameters
+std::vector<real> c_fepLambdas      = { 0.0, 0.5, 1.0 };
+std::vector<real> c_softcoreAlphas  = { 0.0, 0.3 };
+std::vector<bool> c_softcoreCoulomb = { true, false };
+
+//! Coordinates for testing
+std::vector<PaddedVector<RVec>> c_coordinates = {
+    { { 1.0, 1.0, 1.0 }, { 1.1, 1.15, 1.2 }, { 0.9, 0.85, 0.8 }, { 1.1, 1.15, 0.8 } }
+};
+
+INSTANTIATE_TEST_CASE_P(NBInteraction,
+                        NonbondedFepTest,
+                        ::testing::Combine(::testing::ValuesIn(c_interaction),
+                                           ::testing::ValuesIn(c_coordinates),
+                                           ::testing::ValuesIn(c_fepLambdas),
+                                           ::testing::ValuesIn(c_softcoreAlphas),
+                                           ::testing::ValuesIn(c_softcoreCoulomb)));
+
+} // namespace
+
+} // namespace test
+
+} // namespace gmx
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_0.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_0.xml
new file mode 100644 (file)
index 0000000..0f00800
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">9.3145478052213058</Real>
+  <Real Name="ECoul ">-111.63140175473714</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-6.2096985368142033</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-260.95857104646757</Real>
+      <Real Name="Y">-391.43785656970101</Real>
+      <Real Name="Z">521.9171420929348</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-94.898901947422004</Real>
+      <Real Name="Y">-142.3483529211328</Real>
+      <Real Name="Z">-189.79780389484378</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">94.898901947421891</Real>
+      <Real Name="Y">142.34835292113289</Real>
+      <Real Name="Z">189.79780389484378</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">260.95857104646768</Real>
+      <Real Name="Y">391.4378565697009</Real>
+      <Real Name="Z">-521.9171420929348</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-260.95857104646757</Real>
+      <Real Name="Y">-391.43785656970101</Real>
+      <Real Name="Z">521.9171420929348</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_1.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_1.xml
new file mode 100644 (file)
index 0000000..0f00800
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">9.3145478052213058</Real>
+  <Real Name="ECoul ">-111.63140175473714</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-6.2096985368142033</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-260.95857104646757</Real>
+      <Real Name="Y">-391.43785656970101</Real>
+      <Real Name="Z">521.9171420929348</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-94.898901947422004</Real>
+      <Real Name="Y">-142.3483529211328</Real>
+      <Real Name="Z">-189.79780389484378</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">94.898901947421891</Real>
+      <Real Name="Y">142.34835292113289</Real>
+      <Real Name="Z">189.79780389484378</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">260.95857104646768</Real>
+      <Real Name="Y">391.4378565697009</Real>
+      <Real Name="Z">-521.9171420929348</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-260.95857104646757</Real>
+      <Real Name="Y">-391.43785656970101</Real>
+      <Real Name="Z">521.9171420929348</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_10.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_10.xml
new file mode 100644 (file)
index 0000000..516db05
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">3.1048492684071043</Real>
+  <Real Name="ECoul ">76.897537343641645</Real>
+  <Real Name="dVdlCoul ">200.86758822144873</Real>
+  <Real Name="dVdlVdw ">-0.73574306288264069</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-94.898901947422047</Real>
+      <Real Name="Y">-142.34835292113266</Real>
+      <Real Name="Z">521.91714209293491</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-83.029834549522803</Real>
+      <Real Name="Y">-124.54475182428425</Real>
+      <Real Name="Z">-166.05966909904561</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">177.92873649694485</Real>
+      <Real Name="Y">266.89310474541691</Real>
+      <Real Name="Z">-355.8574729938893</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-94.898901947422047</Real>
+      <Real Name="Y">-142.34835292113266</Real>
+      <Real Name="Z">521.91714209293491</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_11.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_11.xml
new file mode 100644 (file)
index 0000000..4bf4726
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">3.1048492684071043</Real>
+  <Real Name="ECoul ">76.897537343641645</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-0.86321750690201693</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-94.898901947422047</Real>
+      <Real Name="Y">-142.34835292113266</Real>
+      <Real Name="Z">521.91714209293491</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-83.029834549522803</Real>
+      <Real Name="Y">-124.54475182428425</Real>
+      <Real Name="Z">-166.05966909904561</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">177.92873649694485</Real>
+      <Real Name="Y">266.89310474541691</Real>
+      <Real Name="Z">-355.8574729938893</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-94.898901947422047</Real>
+      <Real Name="Y">-142.34835292113266</Real>
+      <Real Name="Z">521.91714209293491</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_12.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_12.xml
new file mode 100644 (file)
index 0000000..b5fed0e
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">8.1515314473352767</Real>
+  <Real Name="ECoul ">-111.63140175473714</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-5.4343542982235178</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-251.93068947881358</Real>
+      <Real Name="Y">-377.89603421822011</Real>
+      <Real Name="Z">503.86137895762681</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-103.926783515076</Real>
+      <Real Name="Y">-155.89017527261376</Real>
+      <Real Name="Z">-207.85356703015177</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">103.92678351507588</Real>
+      <Real Name="Y">155.89017527261387</Real>
+      <Real Name="Z">207.85356703015177</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">251.93068947881369</Real>
+      <Real Name="Y">377.89603421822</Real>
+      <Real Name="Z">-503.86137895762681</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-251.93068947881358</Real>
+      <Real Name="Y">-377.89603421822011</Real>
+      <Real Name="Z">503.86137895762681</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_13.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_13.xml
new file mode 100644 (file)
index 0000000..b5fed0e
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">8.1515314473352767</Real>
+  <Real Name="ECoul ">-111.63140175473714</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-5.4343542982235178</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-251.93068947881358</Real>
+      <Real Name="Y">-377.89603421822011</Real>
+      <Real Name="Z">503.86137895762681</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-103.926783515076</Real>
+      <Real Name="Y">-155.89017527261376</Real>
+      <Real Name="Z">-207.85356703015177</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">103.92678351507588</Real>
+      <Real Name="Y">155.89017527261387</Real>
+      <Real Name="Z">207.85356703015177</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">251.93068947881369</Real>
+      <Real Name="Y">377.89603421822</Real>
+      <Real Name="Z">-503.86137895762681</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-251.93068947881358</Real>
+      <Real Name="Y">-377.89603421822011</Real>
+      <Real Name="Z">503.86137895762681</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_14.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_14.xml
new file mode 100644 (file)
index 0000000..95992cf
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">8.1515314473352838</Real>
+  <Real Name="ECoul ">-111.63140175473714</Real>
+  <Real Name="dVdlCoul ">179.13707363564816</Real>
+  <Real Name="dVdlVdw ">-15.697835624983551</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-251.93068947881363</Real>
+      <Real Name="Y">-377.89603421822017</Real>
+      <Real Name="Z">503.86137895762693</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-103.92678351507598</Real>
+      <Real Name="Y">-155.89017527261373</Real>
+      <Real Name="Z">-207.85356703015174</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">103.92678351507587</Real>
+      <Real Name="Y">155.89017527261385</Real>
+      <Real Name="Z">207.85356703015174</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">251.93068947881375</Real>
+      <Real Name="Y">377.89603421822005</Real>
+      <Real Name="Z">-503.86137895762693</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-251.93068947881363</Real>
+      <Real Name="Y">-377.89603421822017</Real>
+      <Real Name="Z">503.86137895762693</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_15.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_15.xml
new file mode 100644 (file)
index 0000000..3baedd8
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">8.1515314473352838</Real>
+  <Real Name="ECoul ">-111.63140175473714</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-15.15135030534281</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-251.93068947881363</Real>
+      <Real Name="Y">-377.89603421822017</Real>
+      <Real Name="Z">503.86137895762693</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-103.92678351507598</Real>
+      <Real Name="Y">-155.89017527261373</Real>
+      <Real Name="Z">-207.85356703015174</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">103.92678351507587</Real>
+      <Real Name="Y">155.89017527261385</Real>
+      <Real Name="Z">207.85356703015174</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">251.93068947881375</Real>
+      <Real Name="Y">377.89603421822005</Real>
+      <Real Name="Z">-503.86137895762693</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-251.93068947881363</Real>
+      <Real Name="Y">-377.89603421822017</Real>
+      <Real Name="Z">503.86137895762693</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_16.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_16.xml
new file mode 100644 (file)
index 0000000..51292d9
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">5.4343542982235178</Real>
+  <Real Name="ECoul ">-17.366932205547741</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-5.4343542982235178</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-177.92873649694485</Real>
+      <Real Name="Y">-266.89310474541685</Real>
+      <Real Name="Z">503.86137895762681</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-51.963391757537998</Real>
+      <Real Name="Y">-77.94508763630688</Real>
+      <Real Name="Z">-103.92678351507588</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">14.962415266603566</Real>
+      <Real Name="Y">22.443622899905357</Real>
+      <Real Name="Z">29.924830533207132</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">214.92971298787927</Real>
+      <Real Name="Y">322.39456948181839</Real>
+      <Real Name="Z">-429.85942597575803</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-177.92873649694485</Real>
+      <Real Name="Y">-266.89310474541685</Real>
+      <Real Name="Z">503.86137895762681</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_17.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_17.xml
new file mode 100644 (file)
index 0000000..51292d9
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">5.4343542982235178</Real>
+  <Real Name="ECoul ">-17.366932205547741</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-5.4343542982235178</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-177.92873649694485</Real>
+      <Real Name="Y">-266.89310474541685</Real>
+      <Real Name="Z">503.86137895762681</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-51.963391757537998</Real>
+      <Real Name="Y">-77.94508763630688</Real>
+      <Real Name="Z">-103.92678351507588</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">14.962415266603566</Real>
+      <Real Name="Y">22.443622899905357</Real>
+      <Real Name="Z">29.924830533207132</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">214.92971298787927</Real>
+      <Real Name="Y">322.39456948181839</Real>
+      <Real Name="Z">-429.85942597575803</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-177.92873649694485</Real>
+      <Real Name="Y">-266.89310474541685</Real>
+      <Real Name="Z">503.86137895762681</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_18.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_18.xml
new file mode 100644 (file)
index 0000000..a80b81e
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">3.761435515884914</Real>
+  <Real Name="ECoul ">-20.022624722133244</Real>
+  <Real Name="dVdlCoul ">187.81393532738895</Real>
+  <Real Name="dVdlVdw ">-4.1916248207515459</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-111.57199247569103</Real>
+      <Real Name="Y">-167.35798871353634</Real>
+      <Real Name="Z">367.76618196621394</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-51.11796452031161</Real>
+      <Real Name="Y">-76.676946780467304</Real>
+      <Real Name="Z">-102.23592904062311</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">14.962415266603525</Real>
+      <Real Name="Y">22.443622899905296</Real>
+      <Real Name="Z">29.92483053320705</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">147.72754172939912</Real>
+      <Real Name="Y">221.59131259409835</Real>
+      <Real Name="Z">-295.4550834587979</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-111.57199247569103</Real>
+      <Real Name="Y">-167.35798871353634</Real>
+      <Real Name="Z">367.76618196621394</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_19.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_19.xml
new file mode 100644 (file)
index 0000000..6f1a096
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">3.8186569219444455</Real>
+  <Real Name="ECoul ">-17.366932205547741</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-4.2823914414719937</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-135.5995394305331</Real>
+      <Real Name="Y">-203.39930914579941</Real>
+      <Real Name="Z">503.86137895762693</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-73.127990290743867</Real>
+      <Real Name="Y">-109.69198543611563</Real>
+      <Real Name="Z">-146.25598058148756</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">14.962415266603525</Real>
+      <Real Name="Y">22.443622899905296</Real>
+      <Real Name="Z">29.92483053320705</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">193.76511445467344</Real>
+      <Real Name="Y">290.64767168200973</Real>
+      <Real Name="Z">-387.53022890934642</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-135.5995394305331</Real>
+      <Real Name="Y">-203.39930914579941</Real>
+      <Real Name="Z">503.86137895762693</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_2.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_2.xml
new file mode 100644 (file)
index 0000000..e58373a
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">9.3145478052213129</Real>
+  <Real Name="ECoul ">-111.63140175473714</Real>
+  <Real Name="dVdlCoul ">179.13707363564816</Real>
+  <Real Name="dVdlVdw ">-17.725275114526866</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-260.95857104646763</Real>
+      <Real Name="Y">-391.43785656970118</Real>
+      <Real Name="Z">521.91714209293491</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-94.898901947421962</Real>
+      <Real Name="Y">-142.34835292113274</Real>
+      <Real Name="Z">-189.79780389484372</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">94.898901947421862</Real>
+      <Real Name="Y">142.34835292113286</Real>
+      <Real Name="Z">189.79780389484372</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">260.95857104646774</Real>
+      <Real Name="Y">391.43785656970107</Real>
+      <Real Name="Z">-521.91714209293491</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-260.95857104646763</Real>
+      <Real Name="Y">-391.43785656970118</Real>
+      <Real Name="Z">521.91714209293491</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_20.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_20.xml
new file mode 100644 (file)
index 0000000..d050e9f
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">2.7171771491117589</Real>
+  <Real Name="ECoul ">76.897537343641645</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-5.4343542982235178</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-103.9267835150761</Real>
+      <Real Name="Y">-155.89017527261367</Real>
+      <Real Name="Z">503.86137895762681</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-74.001952981868754</Real>
+      <Real Name="Y">-111.00292947280317</Real>
+      <Real Name="Z">-148.00390596373751</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">177.92873649694485</Real>
+      <Real Name="Y">266.89310474541685</Real>
+      <Real Name="Z">-355.8574729938893</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-103.9267835150761</Real>
+      <Real Name="Y">-155.89017527261367</Real>
+      <Real Name="Z">503.86137895762681</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_21.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_21.xml
new file mode 100644 (file)
index 0000000..d050e9f
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">2.7171771491117589</Real>
+  <Real Name="ECoul ">76.897537343641645</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-5.4343542982235178</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-103.9267835150761</Real>
+      <Real Name="Y">-155.89017527261367</Real>
+      <Real Name="Z">503.86137895762681</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-74.001952981868754</Real>
+      <Real Name="Y">-111.00292947280317</Real>
+      <Real Name="Z">-148.00390596373751</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">177.92873649694485</Real>
+      <Real Name="Y">266.89310474541685</Real>
+      <Real Name="Z">-355.8574729938893</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-103.9267835150761</Real>
+      <Real Name="Y">-155.89017527261367</Real>
+      <Real Name="Z">503.86137895762681</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_22.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_22.xml
new file mode 100644 (file)
index 0000000..d054f7e
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">2.7171771491117611</Real>
+  <Real Name="ECoul ">76.897537343641645</Real>
+  <Real Name="dVdlCoul ">200.86758822144873</Real>
+  <Real Name="dVdlVdw ">-0.62492893998153254</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-103.92678351507604</Real>
+      <Real Name="Y">-155.89017527261365</Real>
+      <Real Name="Z">503.86137895762693</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-74.001952981868811</Real>
+      <Real Name="Y">-111.00292947280326</Real>
+      <Real Name="Z">-148.00390596373762</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">177.92873649694485</Real>
+      <Real Name="Y">266.89310474541691</Real>
+      <Real Name="Z">-355.8574729938893</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-103.92678351507604</Real>
+      <Real Name="Y">-155.89017527261365</Real>
+      <Real Name="Z">503.86137895762693</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_23.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_23.xml
new file mode 100644 (file)
index 0000000..d0ca51c
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">2.7171771491117611</Real>
+  <Real Name="ECoul ">76.897537343641645</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-0.73424360351625861</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-103.92678351507604</Real>
+      <Real Name="Y">-155.89017527261365</Real>
+      <Real Name="Z">503.86137895762693</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-74.001952981868811</Real>
+      <Real Name="Y">-111.00292947280326</Real>
+      <Real Name="Z">-148.00390596373762</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">177.92873649694485</Real>
+      <Real Name="Y">266.89310474541691</Real>
+      <Real Name="Z">-355.8574729938893</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-103.92678351507604</Real>
+      <Real Name="Y">-155.89017527261365</Real>
+      <Real Name="Z">503.86137895762693</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_24.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_24.xml
new file mode 100644 (file)
index 0000000..47ea9c0
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">11.244864181870648</Real>
+  <Real Name="ECoul ">-91.43161122279804</Real>
+  <Real Name="dVdlCoul ">60.44738282828024</Real>
+  <Real Name="dVdlVdw ">-7.1291612299081022</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-209.02699861275136</Real>
+      <Real Name="Y">-313.54049791912666</Real>
+      <Real Name="Z">418.05399722550226</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-40.828136036689216</Real>
+      <Real Name="Y">-61.242204055033739</Real>
+      <Real Name="Z">-81.656272073378346</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">40.828136036689173</Real>
+      <Real Name="Y">61.242204055033781</Real>
+      <Real Name="Z">81.656272073378346</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">209.02699861275138</Real>
+      <Real Name="Y">313.54049791912661</Real>
+      <Real Name="Z">-418.05399722550226</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-209.02699861275136</Real>
+      <Real Name="Y">-313.54049791912666</Real>
+      <Real Name="Z">418.05399722550226</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_25.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_25.xml
new file mode 100644 (file)
index 0000000..47ea9c0
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">11.244864181870648</Real>
+  <Real Name="ECoul ">-91.43161122279804</Real>
+  <Real Name="dVdlCoul ">60.44738282828024</Real>
+  <Real Name="dVdlVdw ">-7.1291612299081022</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-209.02699861275136</Real>
+      <Real Name="Y">-313.54049791912666</Real>
+      <Real Name="Z">418.05399722550226</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-40.828136036689216</Real>
+      <Real Name="Y">-61.242204055033739</Real>
+      <Real Name="Z">-81.656272073378346</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">40.828136036689173</Real>
+      <Real Name="Y">61.242204055033781</Real>
+      <Real Name="Z">81.656272073378346</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">209.02699861275138</Real>
+      <Real Name="Y">313.54049791912661</Real>
+      <Real Name="Z">-418.05399722550226</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-209.02699861275136</Real>
+      <Real Name="Y">-313.54049791912666</Real>
+      <Real Name="Z">418.05399722550226</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_26.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_26.xml
new file mode 100644 (file)
index 0000000..6f31f86
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">11.244864181870655</Real>
+  <Real Name="ECoul ">-91.43161122279804</Real>
+  <Real Name="dVdlCoul ">51.055517365549605</Real>
+  <Real Name="dVdlVdw ">-18.644737807620768</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-209.02699861275141</Real>
+      <Real Name="Y">-313.54049791912678</Real>
+      <Real Name="Z">418.05399722550248</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-40.828136036689187</Real>
+      <Real Name="Y">-61.242204055033682</Real>
+      <Real Name="Z">-81.656272073378275</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">40.828136036689138</Real>
+      <Real Name="Y">61.242204055033731</Real>
+      <Real Name="Z">81.656272073378275</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">209.02699861275147</Real>
+      <Real Name="Y">313.54049791912672</Real>
+      <Real Name="Z">-418.05399722550248</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-209.02699861275141</Real>
+      <Real Name="Y">-313.54049791912678</Real>
+      <Real Name="Z">418.05399722550248</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_27.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_27.xml
new file mode 100644 (file)
index 0000000..0202545
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">11.244864181870655</Real>
+  <Real Name="ECoul ">-91.43161122279804</Real>
+  <Real Name="dVdlCoul ">60.44738282828024</Real>
+  <Real Name="dVdlVdw ">-18.031583913092721</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-209.02699861275141</Real>
+      <Real Name="Y">-313.54049791912678</Real>
+      <Real Name="Z">418.05399722550248</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-40.828136036689187</Real>
+      <Real Name="Y">-61.242204055033682</Real>
+      <Real Name="Z">-81.656272073378275</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">40.828136036689138</Real>
+      <Real Name="Y">61.242204055033731</Real>
+      <Real Name="Z">81.656272073378275</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">209.02699861275147</Real>
+      <Real Name="Y">313.54049791912672</Real>
+      <Real Name="Z">-418.05399722550248</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-209.02699861275141</Real>
+      <Real Name="Y">-313.54049791912678</Real>
+      <Real Name="Z">418.05399722550248</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_28.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_28.xml
new file mode 100644 (file)
index 0000000..4b877de
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">7.6802835669165956</Real>
+  <Real Name="ECoul ">-61.20791980865792</Real>
+  <Real Name="dVdlCoul ">60.44738282828024</Real>
+  <Real Name="dVdlVdw ">-7.1291612299081022</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-124.92756732472033</Real>
+      <Real Name="Y">-187.39135098708019</Real>
+      <Real Name="Z">418.05399722550231</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-20.414068018344608</Real>
+      <Real Name="Y">-30.621102027516869</Real>
+      <Real Name="Z">-40.828136036689173</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-21.635647625670902</Real>
+      <Real Name="Y">-32.453471438506362</Real>
+      <Real Name="Z">-43.271295251341805</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">166.97728296873584</Real>
+      <Real Name="Y">250.46592445310341</Real>
+      <Real Name="Z">-333.95456593747133</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-124.92756732472033</Real>
+      <Real Name="Y">-187.39135098708019</Real>
+      <Real Name="Z">418.05399722550231</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_29.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_29.xml
new file mode 100644 (file)
index 0000000..4b877de
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">7.6802835669165956</Real>
+  <Real Name="ECoul ">-61.20791980865792</Real>
+  <Real Name="dVdlCoul ">60.44738282828024</Real>
+  <Real Name="dVdlVdw ">-7.1291612299081022</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-124.92756732472033</Real>
+      <Real Name="Y">-187.39135098708019</Real>
+      <Real Name="Z">418.05399722550231</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-20.414068018344608</Real>
+      <Real Name="Y">-30.621102027516869</Real>
+      <Real Name="Z">-40.828136036689173</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-21.635647625670902</Real>
+      <Real Name="Y">-32.453471438506362</Real>
+      <Real Name="Z">-43.271295251341805</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">166.97728296873584</Real>
+      <Real Name="Y">250.46592445310341</Real>
+      <Real Name="Z">-333.95456593747133</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-124.92756732472033</Real>
+      <Real Name="Y">-187.39135098708019</Real>
+      <Real Name="Z">418.05399722550231</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_3.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_3.xml
new file mode 100644 (file)
index 0000000..a87e13a
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">9.3145478052213129</Real>
+  <Real Name="ECoul ">-111.63140175473714</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-17.112121219998826</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-260.95857104646763</Real>
+      <Real Name="Y">-391.43785656970118</Real>
+      <Real Name="Z">521.91714209293491</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-94.898901947421962</Real>
+      <Real Name="Y">-142.34835292113274</Real>
+      <Real Name="Z">-189.79780389484372</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">94.898901947421862</Real>
+      <Real Name="Y">142.34835292113286</Real>
+      <Real Name="Z">189.79780389484372</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">260.95857104646774</Real>
+      <Real Name="Y">391.43785656970107</Real>
+      <Real Name="Z">-521.91714209293491</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-260.95857104646763</Real>
+      <Real Name="Y">-391.43785656970118</Real>
+      <Real Name="Z">521.91714209293491</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_30.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_30.xml
new file mode 100644 (file)
index 0000000..a91ddbd
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">5.7877856110730166</Real>
+  <Real Name="ECoul ">-63.863612325243423</Real>
+  <Real Name="dVdlCoul ">59.732379057290416</Real>
+  <Real Name="dVdlVdw ">-5.7498617329574744</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-53.906398242222338</Real>
+      <Real Name="Y">-80.859597363333336</Real>
+      <Real Name="Z">281.95880023408944</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-21.900853311740317</Real>
+      <Real Name="Y">-32.851279967610424</Real>
+      <Real Name="Z">-43.801706623480584</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-21.635647625670948</Real>
+      <Real Name="Y">-32.453471438506433</Real>
+      <Real Name="Z">-43.271295251341897</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">97.442899179633599</Real>
+      <Real Name="Y">146.16434876945019</Real>
+      <Real Name="Z">-194.88579835926697</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-53.906398242222338</Real>
+      <Real Name="Y">-80.859597363333336</Real>
+      <Real Name="Z">281.95880023408944</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_31.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_31.xml
new file mode 100644 (file)
index 0000000..dddf605
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">5.853205445506128</Real>
+  <Real Name="ECoul ">-61.20791980865792</Real>
+  <Real Name="dVdlCoul ">60.44738282828024</Real>
+  <Real Name="dVdlVdw ">-5.8511380489996379</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-78.08967666351046</Real>
+      <Real Name="Y">-117.13451499526545</Real>
+      <Real Name="Z">418.05399722550243</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-43.833013348949535</Real>
+      <Real Name="Y">-65.749520023424211</Real>
+      <Real Name="Z">-87.666026697898971</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-21.635647625670948</Real>
+      <Real Name="Y">-32.453471438506433</Real>
+      <Real Name="Z">-43.271295251341897</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">143.55833763813095</Real>
+      <Real Name="Y">215.3375064571961</Real>
+      <Real Name="Z">-287.11667527626156</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-78.08967666351046</Real>
+      <Real Name="Y">-117.13451499526545</Real>
+      <Real Name="Z">418.05399722550243</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_32.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_32.xml
new file mode 100644 (file)
index 0000000..60b2660
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">4.1157029519625441</Real>
+  <Real Name="ECoul ">-30.9842283945178</Real>
+  <Real Name="dVdlCoul ">60.44738282828024</Real>
+  <Real Name="dVdlVdw ">-7.1291612299081022</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-40.828136036689301</Real>
+      <Real Name="Y">-61.242204055033611</Real>
+      <Real Name="Z">418.05399722550226</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-84.099431288030971</Real>
+      <Real Name="Y">-126.14914693204652</Real>
+      <Real Name="Z">-168.19886257606194</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">124.92756732472027</Real>
+      <Real Name="Y">187.39135098708013</Real>
+      <Real Name="Z">-249.85513464944029</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-40.828136036689301</Real>
+      <Real Name="Y">-61.242204055033611</Real>
+      <Real Name="Z">418.05399722550226</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_33.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_33.xml
new file mode 100644 (file)
index 0000000..60b2660
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">4.1157029519625441</Real>
+  <Real Name="ECoul ">-30.9842283945178</Real>
+  <Real Name="dVdlCoul ">60.44738282828024</Real>
+  <Real Name="dVdlVdw ">-7.1291612299081022</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-40.828136036689301</Real>
+      <Real Name="Y">-61.242204055033611</Real>
+      <Real Name="Z">418.05399722550226</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-84.099431288030971</Real>
+      <Real Name="Y">-126.14914693204652</Real>
+      <Real Name="Z">-168.19886257606194</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">124.92756732472027</Real>
+      <Real Name="Y">187.39135098708013</Real>
+      <Real Name="Z">-249.85513464944029</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-40.828136036689301</Real>
+      <Real Name="Y">-61.242204055033611</Real>
+      <Real Name="Z">418.05399722550226</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_34.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_34.xml
new file mode 100644 (file)
index 0000000..1396356
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">4.1157029519625468</Real>
+  <Real Name="ECoul ">-30.9842283945178</Real>
+  <Real Name="dVdlCoul ">72.786031951350168</Real>
+  <Real Name="dVdlVdw ">-1.6552057559765398</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-40.828136036689301</Real>
+      <Real Name="Y">-61.242204055033611</Real>
+      <Real Name="Z">418.05399722550243</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-84.099431288031028</Real>
+      <Real Name="Y">-126.14914693204661</Real>
+      <Real Name="Z">-168.19886257606206</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">124.92756732472033</Real>
+      <Real Name="Y">187.39135098708022</Real>
+      <Real Name="Z">-249.85513464944037</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-40.828136036689301</Real>
+      <Real Name="Y">-61.242204055033611</Real>
+      <Real Name="Z">418.05399722550243</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_35.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_35.xml
new file mode 100644 (file)
index 0000000..566fe07
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">4.1157029519625468</Real>
+  <Real Name="ECoul ">-30.9842283945178</Real>
+  <Real Name="dVdlCoul ">60.44738282828024</Real>
+  <Real Name="dVdlVdw ">-1.7826801999959161</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-40.828136036689301</Real>
+      <Real Name="Y">-61.242204055033611</Real>
+      <Real Name="Z">418.05399722550243</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-84.099431288031028</Real>
+      <Real Name="Y">-126.14914693204661</Real>
+      <Real Name="Z">-168.19886257606206</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">124.92756732472033</Real>
+      <Real Name="Y">187.39135098708022</Real>
+      <Real Name="Z">-249.85513464944037</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-40.828136036689301</Real>
+      <Real Name="Y">-61.242204055033611</Real>
+      <Real Name="Z">418.05399722550243</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_4.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_4.xml
new file mode 100644 (file)
index 0000000..8ff39ee
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">6.2096985368142033</Real>
+  <Real Name="ECoul ">-17.366932205547741</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-6.2096985368142033</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-177.92873649694485</Real>
+      <Real Name="Y">-266.89310474541691</Real>
+      <Real Name="Z">521.9171420929348</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-47.449450973711002</Real>
+      <Real Name="Y">-71.1741764605664</Real>
+      <Real Name="Z">-94.898901947421891</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">5.9345336989495747</Real>
+      <Real Name="Y">8.9018005484243652</Real>
+      <Real Name="Z">11.869067397899149</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">219.44365377170627</Real>
+      <Real Name="Y">329.16548065755893</Real>
+      <Real Name="Z">-438.88730754341202</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-177.92873649694485</Real>
+      <Real Name="Y">-266.89310474541691</Real>
+      <Real Name="Z">521.9171420929348</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_5.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_5.xml
new file mode 100644 (file)
index 0000000..8ff39ee
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">6.2096985368142033</Real>
+  <Real Name="ECoul ">-17.366932205547741</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-6.2096985368142033</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-177.92873649694485</Real>
+      <Real Name="Y">-266.89310474541691</Real>
+      <Real Name="Z">521.9171420929348</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-47.449450973711002</Real>
+      <Real Name="Y">-71.1741764605664</Real>
+      <Real Name="Z">-94.898901947421891</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">5.9345336989495747</Real>
+      <Real Name="Y">8.9018005484243652</Real>
+      <Real Name="Z">11.869067397899149</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">219.44365377170627</Real>
+      <Real Name="Y">329.16548065755893</Real>
+      <Real Name="Z">-438.88730754341202</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-177.92873649694485</Real>
+      <Real Name="Y">-266.89310474541691</Real>
+      <Real Name="Z">521.9171420929348</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_6.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_6.xml
new file mode 100644 (file)
index 0000000..08a0677
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">4.3172005809706242</Real>
+  <Real Name="ECoul ">-20.022624722133244</Real>
+  <Real Name="dVdlCoul ">187.81393532738895</Real>
+  <Real Name="dVdlVdw ">-4.8303990398635737</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-106.90756741444682</Real>
+      <Real Name="Y">-160.36135112167005</Real>
+      <Real Name="Z">385.82194510152198</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-48.936236267106707</Real>
+      <Real Name="Y">-73.404354400659955</Real>
+      <Real Name="Z">-97.872472534213301</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">5.9345336989495294</Real>
+      <Real Name="Y">8.9018005484242977</Real>
+      <Real Name="Z">11.869067397899059</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">149.909269982604</Real>
+      <Real Name="Y">224.8639049739057</Real>
+      <Real Name="Z">-299.81853996520772</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-106.90756741444682</Real>
+      <Real Name="Y">-160.36135112167005</Real>
+      <Real Name="Z">385.82194510152198</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_7.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_7.xml
new file mode 100644 (file)
index 0000000..bbf4351
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">4.3826204154037347</Real>
+  <Real Name="ECoul ">-17.366932205547741</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-4.9316753559057389</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-131.09084583573497</Real>
+      <Real Name="Y">-196.63626875360214</Real>
+      <Real Name="Z">521.91714209293491</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-70.868396304315922</Real>
+      <Real Name="Y">-106.30259445647374</Real>
+      <Real Name="Z">-141.7367926086317</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">5.9345336989495294</Real>
+      <Real Name="Y">8.9018005484242977</Real>
+      <Real Name="Z">11.869067397899059</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">196.02470844110135</Real>
+      <Real Name="Y">294.03706266165159</Real>
+      <Real Name="Z">-392.04941688220231</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-131.09084583573497</Real>
+      <Real Name="Y">-196.63626875360214</Real>
+      <Real Name="Z">521.91714209293491</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_8.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_8.xml
new file mode 100644 (file)
index 0000000..b88870b
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">3.1048492684071016</Real>
+  <Real Name="ECoul ">76.897537343641645</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-6.2096985368142033</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-94.898901947422104</Real>
+      <Real Name="Y">-142.34835292113269</Real>
+      <Real Name="Z">521.9171420929348</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-83.029834549522747</Real>
+      <Real Name="Y">-124.54475182428416</Real>
+      <Real Name="Z">-166.05966909904549</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">177.92873649694485</Real>
+      <Real Name="Y">266.89310474541685</Real>
+      <Real Name="Z">-355.8574729938893</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-94.898901947422104</Real>
+      <Real Name="Y">-142.34835292113269</Real>
+      <Real Name="Z">521.9171420929348</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
diff --git a/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_9.xml b/src/gromacs/gmxlib/nonbonded/tests/refdata/NBInteraction_NonbondedFepTest_testKernel_9.xml
new file mode 100644 (file)
index 0000000..b88870b
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Real Name="EVdw ">3.1048492684071016</Real>
+  <Real Name="ECoul ">76.897537343641645</Real>
+  <Real Name="dVdlCoul ">188.52893909837877</Real>
+  <Real Name="dVdlVdw ">-6.2096985368142033</Real>
+  <Sequence Name="Forces">
+    <Int Name="Length">4</Int>
+    <Vector>
+      <Real Name="X">-94.898901947422104</Real>
+      <Real Name="Y">-142.34835292113269</Real>
+      <Real Name="Z">521.9171420929348</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">-83.029834549522747</Real>
+      <Real Name="Y">-124.54475182428416</Real>
+      <Real Name="Z">-166.05966909904549</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">177.92873649694485</Real>
+      <Real Name="Y">266.89310474541685</Real>
+      <Real Name="Z">-355.8574729938893</Real>
+    </Vector>
+  </Sequence>
+  <Shift-Forces Name="Shift-forces">
+    <Vector Name="Central">
+      <Real Name="X">-94.898901947422104</Real>
+      <Real Name="Y">-142.34835292113269</Real>
+      <Real Name="Z">521.9171420929348</Real>
+    </Vector>
+  </Shift-Forces>
+</ReferenceData>
index 1366d351e51c93f6abbec57f2234fd6300bea1e5..5239e7506da312931ab2a16a4caa75b43a2fea71 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstdlib>
 #include <cstring>
 
-#include <algorithm>
-#include <vector>
-
-#include "gromacs/mdtypes/commrec.h"
-#include "gromacs/mdtypes/md_enums.h"
-#include "gromacs/utility/arraysize.h"
-
 typedef struct
 {
     const char* name;
@@ -205,8 +198,8 @@ static void pr_two(FILE* out, int c, int i)
 
 static void pr_difftime(FILE* out, double dt)
 {
-    int      ndays, nhours, nmins, nsecs;
-    gmx_bool bPrint, bPrinted;
+    int  ndays, nhours, nmins, nsecs;
+    bool bPrint, bPrinted;
 
     ndays    = static_cast<int>(dt / (24 * 3600));
     dt       = dt - 24 * 3600 * ndays;
@@ -260,29 +253,15 @@ static void pr_difftime(FILE* out, double dt)
 
 void clear_nrnb(t_nrnb* nrnb)
 {
-    int i;
-
-    for (i = 0; (i < eNRNB); i++)
+    for (int i = 0; (i < eNRNB); i++)
     {
         nrnb->n[i] = 0.0;
     }
 }
 
-void add_nrnb(t_nrnb* dest, t_nrnb* s1, t_nrnb* s2)
-{
-    int i;
-
-    for (i = 0; (i < eNRNB); i++)
-    {
-        dest->n[i] = s1->n[i] + s2->n[i];
-    }
-}
-
 void print_nrnb(FILE* out, t_nrnb* nrnb)
 {
-    int i;
-
-    for (i = 0; (i < eNRNB); i++)
+    for (int i = 0; (i < eNRNB); i++)
     {
         if (nrnb->n[i] > 0)
         {
@@ -291,36 +270,32 @@ void print_nrnb(FILE* out, t_nrnb* nrnb)
     }
 }
 
-void _inc_nrnb(t_nrnb* nrnb, int enr, int inc, char gmx_unused* file, int gmx_unused line)
-{
-    nrnb->n[enr] += inc;
-#ifdef DEBUG_NRNB
-    printf("nrnb %15s(%2d) incremented with %8d from file %s line %d\n", nbdata[enr].name, enr, inc,
-           file, line);
-#endif
-}
-
 /* Returns in enr is the index of a full nbnxn VdW kernel */
-static gmx_bool nrnb_is_nbnxn_vdw_kernel(int enr)
+static bool nrnb_is_nbnxn_vdw_kernel(int enr)
 {
     return (enr >= eNR_NBNXN_LJ_RF && enr <= eNR_NBNXN_LJ_E);
 }
 
 /* Returns in enr is the index of an nbnxn kernel addition (LJ modification) */
-static gmx_bool nrnb_is_nbnxn_kernel_addition(int enr)
+static bool nrnb_is_nbnxn_kernel_addition(int enr)
 {
     return (enr >= eNR_NBNXN_ADD_LJ_FSW && enr <= eNR_NBNXN_ADD_LJ_EWALD_E);
 }
 
+void atomicNrnbIncrement(t_nrnb* nrnb, int index, int increment)
+{
+#pragma omp atomic
+    nrnb->n[index] += increment;
+}
+
 void print_flop(FILE* out, t_nrnb* nrnb, double* nbfs, double* mflop)
 {
-    int         i, j;
     double      mni, frac, tfrac, tflop;
     const char* myline =
             "-----------------------------------------------------------------------------";
 
     *nbfs = 0.0;
-    for (i = 0; (i < eNR_NBKERNEL_TOTAL_NR); i++)
+    for (int i = 0; (i < eNR_NBKERNEL_TOTAL_NR); i++)
     {
         if (std::strstr(nbdata[i].name, "W3-W3") != nullptr)
         {
@@ -344,7 +319,7 @@ void print_flop(FILE* out, t_nrnb* nrnb, double* nbfs, double* mflop)
         }
     }
     tflop = 0;
-    for (i = 0; (i < eNRNB); i++)
+    for (int i = 0; (i < eNRNB); i++)
     {
         tflop += 1e-6 * nrnb->n[i] * nbdata[i].flop;
     }
@@ -371,7 +346,7 @@ void print_flop(FILE* out, t_nrnb* nrnb, double* nbfs, double* mflop)
     }
     *mflop = 0.0;
     tfrac  = 0.0;
-    for (i = 0; (i < eNRNB); i++)
+    for (int i = 0; (i < eNRNB); i++)
     {
         mni = 1e-6 * nrnb->n[i];
         /* Skip empty entries and nbnxn additional flops,
@@ -385,7 +360,7 @@ void print_flop(FILE* out, t_nrnb* nrnb, double* nbfs, double* mflop)
             if (nrnb_is_nbnxn_vdw_kernel(i))
             {
                 /* Possibly add the cost of an LJ switch/Ewald function */
-                for (j = eNR_NBNXN_ADD_LJ_FSW; j <= eNR_NBNXN_ADD_LJ_EWALD; j += 2)
+                for (int j = eNR_NBNXN_ADD_LJ_FSW; j <= eNR_NBNXN_ADD_LJ_EWALD; j += 2)
                 {
                     int e_kernel_add;
 
@@ -439,8 +414,7 @@ void print_perf(FILE*   out,
     if (time_per_node > 0)
     {
         fprintf(out, "%12s %12s %12s %10s\n", "", "Core t (s)", "Wall t (s)", "(%)");
-        fprintf(out, "%12s %12.3f %12.3f %10.1f\n", "Time:", time_per_thread, time_per_node,
-                100.0 * time_per_thread / time_per_node);
+        fprintf(out, "%12s %12.3f %12.3f %10.1f\n", "Time:", time_per_thread, time_per_node, 100.0 * time_per_thread / time_per_node);
         /* only print day-hour-sec format if time_per_node is more than 30 min */
         if (time_per_node > 30 * 60)
         {
@@ -455,15 +429,27 @@ void print_perf(FILE*   out,
             if (getenv("GMX_DETAILED_PERF_STATS") == nullptr)
             {
                 fprintf(out, "%12s %12s %12s\n", "", "(ns/day)", "(hour/ns)");
-                fprintf(out, "%12s %12.3f %12.3f\n", "Performance:", wallclocktime * 24 * 3.6 / time_per_node,
+                fprintf(out,
+                        "%12s %12.3f %12.3f\n",
+                        "Performance:",
+                        wallclocktime * 24 * 3.6 / time_per_node,
                         1000 * time_per_node / (3600 * wallclocktime));
             }
             else
             {
-                fprintf(out, "%12s %12s %12s %12s %12s\n", "", "(Mnbf/s)",
-                        (mflop > 1000) ? "(GFlops)" : "(MFlops)", "(ns/day)", "(hour/ns)");
-                fprintf(out, "%12s %12.3f %12.3f %12.3f %12.3f\n", "Performance:", nbfs / time_per_node,
-                        (mflop > 1000) ? (mflop / 1000) : mflop, wallclocktime * 24 * 3.6 / time_per_node,
+                fprintf(out,
+                        "%12s %12s %12s %12s %12s\n",
+                        "",
+                        "(Mnbf/s)",
+                        (mflop > 1000) ? "(GFlops)" : "(MFlops)",
+                        "(ns/day)",
+                        "(hour/ns)");
+                fprintf(out,
+                        "%12s %12.3f %12.3f %12.3f %12.3f\n",
+                        "Performance:",
+                        nbfs / time_per_node,
+                        (mflop > 1000) ? (mflop / 1000) : mflop,
+                        wallclocktime * 24 * 3.6 / time_per_node,
                         1000 * time_per_node / (3600 * wallclocktime));
             }
         }
@@ -476,10 +462,18 @@ void print_perf(FILE*   out,
             }
             else
             {
-                fprintf(out, "%12s %12s %12s %14s\n", "", "(Mnbf/s)",
-                        (mflop > 1000) ? "(GFlops)" : "(MFlops)", "(steps/hour)");
-                fprintf(out, "%12s %12.3f %12.3f %14.1f\n", "Performance:", nbfs / time_per_node,
-                        (mflop > 1000) ? (mflop / 1000) : mflop, nsteps * 3600.0 / time_per_node);
+                fprintf(out,
+                        "%12s %12s %12s %14s\n",
+                        "",
+                        "(Mnbf/s)",
+                        (mflop > 1000) ? "(GFlops)" : "(MFlops)",
+                        "(steps/hour)");
+                fprintf(out,
+                        "%12s %12.3f %12.3f %14.1f\n",
+                        "Performance:",
+                        nbfs / time_per_node,
+                        (mflop > 1000) ? (mflop / 1000) : mflop,
+                        nsteps * 3600.0 / time_per_node);
             }
         }
     }
@@ -494,131 +488,3 @@ const char* nrnb_str(int enr)
 {
     return nbdata[enr].name;
 }
-
-static const int force_index[] = {
-    eNR_BONDS,  eNR_ANGLES, eNR_PROPER, eNR_IMPROPER, eNR_RB,
-    eNR_DISRES, eNR_ORIRES, eNR_POSRES, eNR_FBPOSRES, eNR_NS,
-};
-#define NFORCE_INDEX asize(force_index)
-
-static const int constr_index[] = { eNR_SHAKE,  eNR_SHAKE_RIJ,  eNR_SETTLE,  eNR_UPDATE,
-                                    eNR_PCOUPL, eNR_CONSTR_VIR, eNR_CONSTR_V };
-#define NCONSTR_INDEX asize(constr_index)
-
-static double pr_av(FILE* log, t_commrec* cr, double fav, const double ftot[], const char* title)
-{
-    int    i, perc;
-    double dperc, unb;
-
-    unb = 0;
-    if (fav > 0)
-    {
-        fav /= cr->nnodes - cr->npmenodes;
-        fprintf(log, "\n %-26s", title);
-        for (i = 0; (i < cr->nnodes); i++)
-        {
-            dperc = (100.0 * ftot[i]) / fav;
-            unb   = std::max(unb, dperc);
-            perc  = static_cast<int>(dperc);
-            fprintf(log, "%3d ", perc);
-        }
-        if (unb > 0)
-        {
-            perc = static_cast<int>(10000.0 / unb);
-            fprintf(log, "%6d%%\n\n", perc);
-        }
-        else
-        {
-            fprintf(log, "\n\n");
-        }
-    }
-    return unb;
-}
-
-void pr_load(FILE* log, t_commrec* cr, t_nrnb nrnb[])
-{
-    t_nrnb av;
-
-    std::vector<double> ftot(cr->nnodes);
-    std::vector<double> stot(cr->nnodes);
-    for (int i = 0; (i < cr->nnodes); i++)
-    {
-        add_nrnb(&av, &av, &(nrnb[i]));
-        /* Cost due to forces */
-        for (int j = 0; (j < eNR_NBKERNEL_TOTAL_NR); j++)
-        {
-            ftot[i] += nrnb[i].n[j] * cost_nrnb(j);
-        }
-        for (int j = 0; (j < NFORCE_INDEX); j++)
-        {
-            ftot[i] += nrnb[i].n[force_index[j]] * cost_nrnb(force_index[j]);
-        }
-        /* Due to shake */
-        for (int j = 0; (j < NCONSTR_INDEX); j++)
-        {
-            stot[i] += nrnb[i].n[constr_index[j]] * cost_nrnb(constr_index[j]);
-        }
-    }
-    for (int j = 0; (j < eNRNB); j++)
-    {
-        av.n[j] = av.n[j] / static_cast<double>(cr->nnodes - cr->npmenodes);
-    }
-
-    fprintf(log, "\nDetailed load balancing info in percentage of average\n");
-
-    fprintf(log, " Type                 RANK:");
-    for (int i = 0; (i < cr->nnodes); i++)
-    {
-        fprintf(log, "%3d ", i);
-    }
-    fprintf(log, "Scaling\n");
-    fprintf(log, "---------------------------");
-    for (int i = 0; (i < cr->nnodes); i++)
-    {
-        fprintf(log, "----");
-    }
-    fprintf(log, "-------\n");
-
-    for (int j = 0; (j < eNRNB); j++)
-    {
-        double unb = 100.0;
-        if (av.n[j] > 0)
-        {
-            double dperc;
-            int    perc;
-            fprintf(log, " %-26s", nrnb_str(j));
-            for (int i = 0; (i < cr->nnodes); i++)
-            {
-                dperc = (100.0 * nrnb[i].n[j]) / av.n[j];
-                unb   = std::max(unb, dperc);
-                perc  = static_cast<int>(dperc);
-                fprintf(log, "%3d ", perc);
-            }
-            if (unb > 0)
-            {
-                perc = static_cast<int>(10000.0 / unb);
-                fprintf(log, "%6d%%\n", perc);
-            }
-            else
-            {
-                fprintf(log, "\n");
-            }
-        }
-    }
-    double fav = 0;
-    double sav = 0;
-    for (int i = 0; (i < cr->nnodes); i++)
-    {
-        fav += ftot[i];
-        sav += stot[i];
-    }
-    double uf = pr_av(log, cr, fav, ftot.data(), "Total Force");
-    double us = pr_av(log, cr, sav, stot.data(), "Total Constr.");
-
-    double unb = (uf * fav + us * sav) / (fav + sav);
-    if (unb > 0)
-    {
-        unb = 10000.0 / unb;
-        fprintf(log, "\nTotal Scaling: %.0f%% of max performance\n\n", unb);
-    }
-}
index 847c6cdb9d345ca3d168c95e7cbf42d3c7cdc0c4..a21d13ed79d7348cb79e72642dce5eaf64f99563 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_GMXLIB_NRNB_H
 #define GMX_GMXLIB_NRNB_H
 
-#include <stdio.h>
-
-#include "gromacs/utility/basedefinitions.h"
-
-#define eNR_NBKERNEL_NONE (-1)
+#include <array>
+#include <cstdint>
+#include <cstdio>
 
 enum
 {
@@ -175,25 +173,33 @@ enum
 
 struct t_nrnb
 {
-    double n[eNRNB] = { 0 };
+    std::array<double, eNRNB> n = { 0 };
 };
 
-struct t_commrec;
-
 void clear_nrnb(t_nrnb* nrnb);
 
-void add_nrnb(t_nrnb* dest, t_nrnb* s1, t_nrnb* s2);
-
 void print_nrnb(FILE* out, t_nrnb* nrnb);
 
-void _inc_nrnb(t_nrnb* nrnb, int enr, int inc, char* file, int line);
-
-#ifdef DEBUG_NRNB
-#    define inc_nrnb(nrnb, enr, inc) _inc_nrnb(nrnb, enr, inc, __FILE__, __LINE__)
-#else
-#    define inc_nrnb(nrnb, enr, inc) (nrnb)->n[enr] += inc
-#endif
+/*! \brief Increment the nonbonded kernel flop counters
+ *
+ * \param nrnb The nonbonded kernel flop counters.
+ * \param index Which counter to incrememnt.
+ * \param increment How much to increment the counter by.
+ */
+static inline void inc_nrnb(t_nrnb* nrnb, int index, int increment)
+{
+    nrnb->n[index] += increment;
+}
 
+/*! \brief Atomic increment of nonbonded kernel flop counters
+ *
+ * \param nrnb The nonbonded kernel flop counters.
+ * \param index Which counter to incrememnt.
+ * \param increment How much to increment the counter by.
+ *
+ * Same as inc_nrnb but includes omp atomic pragma
+ */
+void atomicNrnbIncrement(t_nrnb* nrnb, int index, int increment);
 
 void print_flop(FILE* out, t_nrnb* nrnb, double* nbfs, double* mflop);
 /* Calculates the non-bonded forces and flop count.
@@ -203,9 +209,6 @@ void print_flop(FILE* out, t_nrnb* nrnb, double* nbfs, double* mflop);
 void print_perf(FILE* out, double nodetime, double realtime, int64_t nsteps, double delta_t, double nbfs, double mflop);
 /* Prints the performance, nbfs and mflop come from print_flop */
 
-void pr_load(FILE* log, struct t_commrec* cr, t_nrnb nrnb[]);
-/* Print detailed load balancing info */
-
 int cost_nrnb(int enr);
 /* Cost in i860 cycles of this component of MD */
 
index 8dd9c8aad8791d0b71f09189b7b7cc34451748b4..ad4abac97b8b98e65024a3b2fb898f04530d2547 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2011,2013,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2011,2013,2014,2015,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(gmxpreprocess INTERFACE)
+
 file(GLOB GMXPREPROCESS_SOURCES *.cpp)
 
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${GMXPREPROCESS_SOURCES} PARENT_SCOPE)
 
+# Source files have the following private module dependencies.
+target_link_libraries(gmxpreprocess PRIVATE
+                      #                      gmxlib
+                      #                      math
+                      #                      mdtypes
+                      #                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(gmxpreprocess PUBLIC
+target_include_directories(gmxpreprocess INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(gmxpreprocess PUBLIC
+target_link_libraries(gmxpreprocess INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when is an OBJECT target
+#target_link_libraries(gmxpreprocess PUBLIC legacy_api)
+#target_link_libraries(gmxpreprocess PRIVATE common)
+
+# Module dependencies
+# This module convey transitive dependence on these modules.
+#target_link_libraries(gmxpreprocess PUBLIC
+target_link_libraries(gmxpreprocess INTERFACE
+                      #                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(gmxpreprocess PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(gmxpreprocess PRIVATE legacy_modules)
+
 if(BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index aac7f94e74db9ea46c5e7b706d7b8efadb00de2a..a07152567859b6f7de6927f445946ba1490bc3e4 100644 (file)
@@ -159,7 +159,9 @@ int search_jtype(const PreprocessResidue& localPpResidue, const char* name, bool
     }
     if (jmax == -1)
     {
-        gmx_fatal(FARGS, "Atom %s not found in rtp database in residue %s", searchname,
+        gmx_fatal(FARGS,
+                  "Atom %s not found in rtp database in residue %s",
+                  searchname,
                   localPpResidue.resname.c_str());
     }
     if (kmax != strlen(searchname))
@@ -167,7 +169,9 @@ int search_jtype(const PreprocessResidue& localPpResidue, const char* name, bool
         gmx_fatal(FARGS,
                   "Atom %s not found in rtp database in residue %s, "
                   "it looks a bit like %s",
-                  searchname, localPpResidue.resname.c_str(), *(localPpResidue.atomname[jmax]));
+                  searchname,
+                  localPpResidue.resname.c_str(),
+                  *(localPpResidue.atomname[jmax]));
     }
     return jmax;
 }
index 24572cd44b9de91c3cdd5f748295373a40f3e1fe..18a2043ba203b7c475be6a622b1dec7ba7e8763e 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,2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2015,2016,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -97,9 +97,9 @@ void calc_h_pos(int nht, rvec xa[], rvec xh[], int* l)
 #define alfaHpl (2 * M_PI / 3) /* 120 degrees */
 #define distH 0.1
 
-#define alfaCOM (DEG2RAD * 117)
-#define alfaCO (DEG2RAD * 121)
-#define alfaCOA (DEG2RAD * 115)
+#define alfaCOM (gmx::c_deg2Rad * 117)
+#define alfaCO (gmx::c_deg2Rad * 121)
+#define alfaCOA (gmx::c_deg2Rad * 115)
 
 #define distO 0.123
 #define distOA 0.125
index 225086c52f6dd3aaad4e99bc7615b83666381425..37b59f1eb5bce38d43afe26566dab8f77d221dcf 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,22 +66,29 @@ static int round_check(real r, int limit, int ftype, const char* name)
 
     if (r - i > 0.01 || r - i < -0.01)
     {
-        gmx_fatal(FARGS, "A non-integer value (%f) was supplied for '%s' in %s", r, name,
+        gmx_fatal(FARGS,
+                  "A non-integer value (%f) was supplied for '%s' in %s",
+                  r,
+                  name,
                   interaction_function[ftype].longname);
     }
 
     if (i < limit)
     {
-        gmx_fatal(FARGS, "Value of '%s' in %s is %d, which is smaller than the minimum of %d", name,
-                  interaction_function[ftype].longname, i, limit);
+        gmx_fatal(FARGS,
+                  "Value of '%s' in %s is %d, which is smaller than the minimum of %d",
+                  name,
+                  interaction_function[ftype].longname,
+                  i,
+                  limit);
     }
 
     return i;
 }
 
-static void set_ljparams(int comb, double reppow, double v, double w, real* c6, real* c12)
+static void set_ljparams(CombinationRule comb, double reppow, double v, double w, real* c6, real* c12)
 {
-    if (comb == eCOMB_ARITHMETIC || comb == eCOMB_GEOM_SIG_EPS)
+    if (comb == CombinationRule::Arithmetic || comb == CombinationRule::GeomSigEps)
     {
         if (v >= 0)
         {
@@ -105,7 +112,11 @@ static void set_ljparams(int comb, double reppow, double v, double w, real* c6,
 /* A return value of 0 means parameters were assigned successfully,
  * returning -1 means this is an all-zero interaction that should not be added.
  */
-static int assign_param(t_functype ftype, t_iparams* newparam, gmx::ArrayRef<const real> old, int comb, double reppow)
+static int assign_param(t_functype                ftype,
+                        t_iparams*                newparam,
+                        gmx::ArrayRef<const real> old,
+                        CombinationRule           comb,
+                        double                    reppow)
 {
     bool all_param_zero = true;
 
@@ -134,9 +145,9 @@ static int assign_param(t_functype ftype, t_iparams* newparam, gmx::ArrayRef<con
     {
         case F_G96ANGLES:
             /* Post processing of input data: store cosine iso angle itself */
-            newparam->harmonic.rA  = cos(old[0] * DEG2RAD);
+            newparam->harmonic.rA  = cos(old[0] * gmx::c_deg2Rad);
             newparam->harmonic.krA = old[1];
-            newparam->harmonic.rB  = cos(old[2] * DEG2RAD);
+            newparam->harmonic.rB  = cos(old[2] * gmx::c_deg2Rad);
             newparam->harmonic.krB = old[3];
             break;
         case F_G96BONDS:
@@ -327,7 +338,8 @@ static int assign_param(t_functype ftype, t_iparams* newparam, gmx::ArrayRef<con
                 gmx_fatal(FARGS,
                           "Invalid geometry for flat-bottomed position restraint.\n"
                           "Expected number between 1 and %d. Found %d\n",
-                          efbposresNR - 1, newparam->fbposres.geom);
+                          efbposresNR - 1,
+                          newparam->fbposres.geom);
             }
             newparam->fbposres.r        = old[1];
             newparam->fbposres.k        = old[2];
@@ -418,8 +430,8 @@ static int assign_param(t_functype ftype, t_iparams* newparam, gmx::ArrayRef<con
             newparam->vsite.f = old[5];
             break;
         case F_VSITE3FAD:
-            newparam->vsite.a = old[1] * cos(DEG2RAD * old[0]);
-            newparam->vsite.b = old[1] * sin(DEG2RAD * old[0]);
+            newparam->vsite.a = old[1] * cos(gmx::c_deg2Rad * old[0]);
+            newparam->vsite.b = old[1] * sin(gmx::c_deg2Rad * old[0]);
             newparam->vsite.c = old[2];
             newparam->vsite.d = old[3];
             newparam->vsite.e = old[4];
@@ -445,7 +457,7 @@ static int assign_param(t_functype ftype, t_iparams* newparam, gmx::ArrayRef<con
 static int enter_params(gmx_ffparams_t*           ffparams,
                         t_functype                ftype,
                         gmx::ArrayRef<const real> forceparams,
-                        int                       comb,
+                        CombinationRule           comb,
                         real                      reppow,
                         int                       start,
                         bool                      bAppend)
@@ -508,7 +520,7 @@ static void append_interaction(InteractionList* ilist, int type, gmx::ArrayRef<c
 
 static void enter_function(const InteractionsOfType* p,
                            t_functype                ftype,
-                           int                       comb,
+                           CombinationRule           comb,
                            real                      reppow,
                            gmx_ffparams_t*           ffparams,
                            InteractionList*          il,
@@ -517,7 +529,7 @@ static void enter_function(const InteractionsOfType* p,
 {
     int start = ffparams->numTypes();
 
-    for (auto& parm : p->interactionTypes)
+    for (const auto& parm : p->interactionTypes)
     {
         int type = enter_params(ffparams, ftype, parm.forceParam(), comb, reppow, start, bAppend);
         /* Type==-1 is used as a signal that this interaction is all-zero and should not be added. */
@@ -535,7 +547,7 @@ void convertInteractionsOfType(int                                      atnr,
                                gmx::ArrayRef<const InteractionsOfType>  nbtypes,
                                gmx::ArrayRef<const MoleculeInformation> mi,
                                const MoleculeInformation*               intermolecular_interactions,
-                               int                                      comb,
+                               CombinationRule                          comb,
                                double                                   reppow,
                                real                                     fudgeQQ,
                                gmx_mtop_t*                              mtop)
@@ -552,8 +564,8 @@ void convertInteractionsOfType(int                                      atnr,
     ffp->reppow = reppow;
 
     enter_function(&(nbtypes[F_LJ]), static_cast<t_functype>(F_LJ), comb, reppow, ffp, nullptr, TRUE, TRUE);
-    enter_function(&(nbtypes[F_BHAM]), static_cast<t_functype>(F_BHAM), comb, reppow, ffp, nullptr,
-                   TRUE, TRUE);
+    enter_function(
+            &(nbtypes[F_BHAM]), static_cast<t_functype>(F_BHAM), comb, reppow, ffp, nullptr, TRUE, TRUE);
 
     for (size_t mt = 0; mt < mtop->moltype.size(); mt++)
     {
@@ -568,8 +580,14 @@ void convertInteractionsOfType(int                                      atnr,
             if ((i != F_LJ) && (i != F_BHAM)
                 && ((flags & IF_BOND) || (flags & IF_VSITE) || (flags & IF_CONSTRAINT)))
             {
-                enter_function(&(interactions[i]), static_cast<t_functype>(i), comb, reppow, ffp,
-                               &molt->ilist[i], FALSE, (i == F_POSRES || i == F_FBPOSRES));
+                enter_function(&(interactions[i]),
+                               static_cast<t_functype>(i),
+                               comb,
+                               reppow,
+                               ffp,
+                               &molt->ilist[i],
+                               FALSE,
+                               (i == F_POSRES || i == F_FBPOSRES));
             }
         }
     }
@@ -615,8 +633,14 @@ void convertInteractionsOfType(int                                      atnr,
                 }
                 else
                 {
-                    enter_function(&(interactions[i]), static_cast<t_functype>(i), comb, reppow,
-                                   ffp, &(*mtop->intermolecular_ilist)[i], FALSE, FALSE);
+                    enter_function(&(interactions[i]),
+                                   static_cast<t_functype>(i),
+                                   comb,
+                                   reppow,
+                                   ffp,
+                                   &(*mtop->intermolecular_ilist)[i],
+                                   FALSE,
+                                   FALSE);
 
                     mtop->bIntermolecularInteractions = TRUE;
                 }
index a3d65b8e846219e96e7daf97bb782a0a25581823..eac7e911aeb9f0d78fe473dca6ef04af884b6f2b 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,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 struct gmx_mtop_t;
 struct MoleculeInformation;
 struct InteractionsOfType;
+enum class CombinationRule : int;
 
 namespace gmx
 {
@@ -54,7 +55,7 @@ void convertInteractionsOfType(int                                      atnr,
                                gmx::ArrayRef<const InteractionsOfType>  nbtypes,
                                gmx::ArrayRef<const MoleculeInformation> mi,
                                const MoleculeInformation*               intermolecular_interactions,
-                               int                                      comb,
+                               CombinationRule                          comb,
                                double                                   reppow,
                                real                                     fudgeQQ,
                                gmx_mtop_t*                              mtop);
index 45f02a99ccc937e1ed5ef6771b395b8d136fbb77..7bd30084b93f04a647cf515ce19a00b43548f20c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +55,7 @@
 #include "gromacs/gmxlib/conformation_utilities.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/pbcutil/rmpbc.h"
@@ -79,8 +80,10 @@ static real calc_mass(t_atoms* atoms, gmx_bool bGetMass, AtomProperties* aps)
     {
         if (bGetMass)
         {
-            aps->setAtomProperty(epropMass, std::string(*atoms->resinfo[atoms->atom[i].resind].name),
-                                 std::string(*atoms->atomname[i]), &(atoms->atom[i].m));
+            aps->setAtomProperty(epropMass,
+                                 std::string(*atoms->resinfo[atoms->atom[i].resind].name),
+                                 std::string(*atoms->atomname[i]),
+                                 &(atoms->atom[i].m));
         }
         tmass += atoms->atom[i].m;
     }
@@ -244,7 +247,8 @@ static void set_pdb_conf_bfac(int natoms, int nres, t_atoms* atoms, int n_bfac,
         fprintf(stderr,
                 "Range of values for B-factors too large (min %g, max %g) "
                 "will scale down a factor 10\n",
-                bfac_min, bfac_max);
+                bfac_min,
+                bfac_max);
         for (i = 0; (i < n_bfac); i++)
         {
             bfac[i] /= 10;
@@ -257,7 +261,8 @@ static void set_pdb_conf_bfac(int natoms, int nres, t_atoms* atoms, int n_bfac,
         fprintf(stderr,
                 "Range of values for B-factors too small (min %g, max %g) "
                 "will scale up a factor 10\n",
-                bfac_min, bfac_max);
+                bfac_min,
+                bfac_max);
         for (i = 0; (i < n_bfac); i++)
         {
             bfac[i] *= 10;
@@ -323,9 +328,20 @@ static void pdb_legend(FILE* out, int natoms, int nres, t_atoms* atoms, rvec x[]
     fprintf(stderr, "B-factors range from %g to %g\n", bfac_min, bfac_max);
     for (i = 1; (i < 12); i++)
     {
-        fprintf(out, "%-6s%5d  %-4.4s%3.3s %c%4d%c   %8.3f%8.3f%8.3f%6.2f%6.2f\n", "ATOM  ",
-                natoms + 1 + i, "CA", "LEG", space, nres + 1, space, (xmin + (i * 0.12)) * 10,
-                ymin * 10, zmin * 10, 1.0, bfac_min + ((i - 1.0) * (bfac_max - bfac_min) / 10));
+        fprintf(out,
+                "%-6s%5d  %-4.4s%3.3s %c%4d%c   %8.3f%8.3f%8.3f%6.2f%6.2f\n",
+                "ATOM  ",
+                natoms + 1 + i,
+                "CA",
+                "LEG",
+                space,
+                nres + 1,
+                space,
+                (xmin + (i * 0.12)) * 10,
+                ymin * 10,
+                zmin * 10,
+                1.0,
+                bfac_min + ((i - 1.0) * (bfac_max - bfac_min) / 10));
     }
 }
 
@@ -401,9 +417,21 @@ static void visualize_box(FILE* out, int a0, int r0, matrix box, const rvec grid
 
         for (i = 0; i < nat; i++)
         {
-            gmx_fprintf_pdb_atomline(out, epdbATOM, a0 + i, "C", ' ', "BOX", 'K' + i / NCUCVERT,
-                                     r0 + i, ' ', 10 * vert[i][XX], 10 * vert[i][YY],
-                                     10 * vert[i][ZZ], 1.0, 0.0, "");
+            gmx_fprintf_pdb_atomline(out,
+                                     PdbRecordType::Atom,
+                                     a0 + i,
+                                     "C",
+                                     ' ',
+                                     "BOX",
+                                     'K' + i / NCUCVERT,
+                                     r0 + i,
+                                     ' ',
+                                     10 * vert[i][XX],
+                                     10 * vert[i][YY],
+                                     10 * vert[i][ZZ],
+                                     1.0,
+                                     0.0,
+                                     "");
         }
 
         edge = compact_unitcell_edges();
@@ -411,7 +439,9 @@ static void visualize_box(FILE* out, int a0, int r0, matrix box, const rvec grid
         {
             for (i = 0; i < NCUCEDGE; i++)
             {
-                fprintf(out, "CONECT%5d%5d\n", a0 + j * NCUCVERT + edge[2 * i],
+                fprintf(out,
+                        "CONECT%5d%5d\n",
+                        a0 + j * NCUCVERT + edge[2 * i],
                         a0 + j * NCUCVERT + edge[2 * i + 1]);
             }
         }
@@ -427,9 +457,21 @@ static void visualize_box(FILE* out, int a0, int r0, matrix box, const rvec grid
             {
                 for (x = 0; x <= 1; x++)
                 {
-                    gmx_fprintf_pdb_atomline(out, epdbATOM, a0 + i, "C", ' ', "BOX", 'K' + i / 8,
-                                             r0 + i, ' ', x * 10 * box[XX][XX], y * 10 * box[YY][YY],
-                                             z * 10 * box[ZZ][ZZ], 1.0, 0.0, "");
+                    gmx_fprintf_pdb_atomline(out,
+                                             PdbRecordType::Atom,
+                                             a0 + i,
+                                             "C",
+                                             ' ',
+                                             "BOX",
+                                             'K' + i / 8,
+                                             r0 + i,
+                                             ' ',
+                                             x * 10 * box[XX][XX],
+                                             y * 10 * box[YY][YY],
+                                             z * 10 * box[ZZ][ZZ],
+                                             1.0,
+                                             0.0,
+                                             "");
                     i++;
                 }
             }
@@ -452,9 +494,16 @@ static void calc_rotmatrix(rvec principal_axis, rvec targetvec, matrix rotmatrix
     /* Determine rotation from cross product with target vector */
     cprod(principal_axis, targetvec, rotvec);
     unitv(rotvec, rotvec);
-    printf("Aligning %g %g %g to %g %g %g : xprod  %g %g %g\n", principal_axis[XX],
-           principal_axis[YY], principal_axis[ZZ], targetvec[XX], targetvec[YY], targetvec[ZZ],
-           rotvec[XX], rotvec[YY], rotvec[ZZ]);
+    printf("Aligning %g %g %g to %g %g %g : xprod  %g %g %g\n",
+           principal_axis[XX],
+           principal_axis[YY],
+           principal_axis[ZZ],
+           targetvec[XX],
+           targetvec[YY],
+           targetvec[ZZ],
+           rotvec[XX],
+           rotvec[YY],
+           rotvec[ZZ]);
 
     ux              = rotvec[XX];
     uy              = rotvec[YY];
@@ -469,9 +518,16 @@ static void calc_rotmatrix(rvec principal_axis, rvec targetvec, matrix rotmatrix
     rotmatrix[2][1] = uy * uz * (1 - costheta) + ux * sintheta;
     rotmatrix[2][2] = uz * uz + (1.0 - uz * uz) * costheta;
 
-    printf("Rotation matrix: \n%g %g %g\n%g %g %g\n%g %g %g\n", rotmatrix[0][0], rotmatrix[0][1],
-           rotmatrix[0][2], rotmatrix[1][0], rotmatrix[1][1], rotmatrix[1][2], rotmatrix[2][0],
-           rotmatrix[2][1], rotmatrix[2][2]);
+    printf("Rotation matrix: \n%g %g %g\n%g %g %g\n%g %g %g\n",
+           rotmatrix[0][0],
+           rotmatrix[0][1],
+           rotmatrix[0][2],
+           rotmatrix[1][0],
+           rotmatrix[1][1],
+           rotmatrix[1][2],
+           rotmatrix[2][0],
+           rotmatrix[2][1],
+           rotmatrix[2][2]);
 }
 
 static void renum_resnr(t_atoms* atoms, int isize, const int* index, int resnr_start)
@@ -697,8 +753,8 @@ int gmx_editconf(int argc, char* argv[])
                        { efDAT, "-bf", "bfact", ffOPTRD } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_VIEW, NFILE, fnm, NPA, pa, asize(desc), desc,
-                           asize(bugs), bugs, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_CAN_VIEW, NFILE, fnm, NPA, pa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
         return 0;
     }
@@ -792,7 +848,8 @@ int gmx_editconf(int argc, char* argv[])
     if (pbcType != PbcType::No)
     {
         real vol = det(box);
-        printf("Volume: %g nm^3, corresponds to roughly %d electrons\n", vol,
+        printf("Volume: %g nm^3, corresponds to roughly %d electrons\n",
+               vol,
                100 * (static_cast<int>(vol * 4.5)));
     }
 
@@ -814,8 +871,10 @@ int gmx_editconf(int argc, char* argv[])
             /* Determine the Van der Waals radius from the force field */
             if (bReadVDW)
             {
-                if (!aps.setAtomProperty(epropVDW, *top->atoms.resinfo[top->atoms.atom[i].resind].name,
-                                         *top->atoms.atomname[i], &vdw))
+                if (!aps.setAtomProperty(epropVDW,
+                                         *top->atoms.resinfo[top->atoms.atom[i].resind].name,
+                                         *top->atoms.atomname[i],
+                                         &vdw))
                 {
                     vdw = rvdw;
                 }
@@ -912,9 +971,9 @@ int gmx_editconf(int argc, char* argv[])
         printf("    center      :%7.3f%7.3f%7.3f (nm)\n", gc[XX], gc[YY], gc[ZZ]);
         printf("    box vectors :%7.3f%7.3f%7.3f (nm)\n", norm(box[XX]), norm(box[YY]), norm(box[ZZ]));
         printf("    box angles  :%7.2f%7.2f%7.2f (degrees)\n",
-               norm2(box[ZZ]) == 0 ? 0 : RAD2DEG * gmx_angle(box[YY], box[ZZ]),
-               norm2(box[ZZ]) == 0 ? 0 : RAD2DEG * gmx_angle(box[XX], box[ZZ]),
-               norm2(box[YY]) == 0 ? 0 : RAD2DEG * gmx_angle(box[XX], box[YY]));
+               norm2(box[ZZ]) == 0 ? 0 : gmx::c_rad2Deg * gmx_angle(box[YY], box[ZZ]),
+               norm2(box[ZZ]) == 0 ? 0 : gmx::c_rad2Deg * gmx_angle(box[XX], box[ZZ]),
+               norm2(box[YY]) == 0 ? 0 : gmx::c_rad2Deg * gmx_angle(box[XX], box[YY]));
         printf("    box volume  :%7.2f               (nm^3)\n", det(box));
     }
 
@@ -947,7 +1006,7 @@ int gmx_editconf(int argc, char* argv[])
             real vol, dens;
 
             vol  = det(box);
-            dens = (mass * AMU) / (vol * NANO * NANO * NANO);
+            dens = (mass * gmx::c_amu) / (vol * gmx::c_nano * gmx::c_nano * gmx::c_nano);
             fprintf(stderr, "Volume  of input %g (nm^3)\n", vol);
             fprintf(stderr, "Mass    of input %g (a.m.u.)\n", mass);
             fprintf(stderr, "Density of input %g (g/l)\n", dens);
@@ -956,7 +1015,8 @@ int gmx_editconf(int argc, char* argv[])
                 gmx_fatal(FARGS,
                           "Cannot scale density with "
                           "zero mass (%g) or volume (%g)\n",
-                          mass, vol);
+                          mass,
+                          vol);
             }
 
             scale[XX] = scale[YY] = scale[ZZ] = std::cbrt(dens / rho);
@@ -982,8 +1042,14 @@ int gmx_editconf(int argc, char* argv[])
             }
         }
         printf("Aligning %d atoms (out of %d) to %g %g %g, center of rotation %g %g %g\n",
-               numAlignmentAtoms, natom, targetvec[XX], targetvec[YY], targetvec[ZZ],
-               aligncenter[XX], aligncenter[YY], aligncenter[ZZ]);
+               numAlignmentAtoms,
+               natom,
+               targetvec[XX],
+               targetvec[YY],
+               targetvec[ZZ],
+               aligncenter[XX],
+               aligncenter[YY],
+               aligncenter[ZZ]);
         /*subtract out pivot point*/
         for (i = 0; i < numAlignmentAtoms; i++)
         {
@@ -1030,8 +1096,12 @@ int gmx_editconf(int argc, char* argv[])
             ssize  = atoms.nr;
             sindex = nullptr;
         }
-        printf("Translating %d atoms (out of %d) by %g %g %g nm\n", ssize, natom, translation[XX],
-               translation[YY], translation[ZZ]);
+        printf("Translating %d atoms (out of %d) by %g %g %g nm\n",
+               ssize,
+               natom,
+               translation[XX],
+               translation[YY],
+               translation[ZZ]);
         if (sindex)
         {
             for (i = 0; i < ssize; i++)
@@ -1051,10 +1121,12 @@ int gmx_editconf(int argc, char* argv[])
     {
         /* Rotate */
         printf("Rotating %g, %g, %g degrees around the X, Y and Z axis respectively\n",
-               rotangles[XX], rotangles[YY], rotangles[ZZ]);
+               rotangles[XX],
+               rotangles[YY],
+               rotangles[ZZ]);
         for (i = 0; i < DIM; i++)
         {
-            rotangles[i] *= DEG2RAD;
+            rotangles[i] *= gmx::c_deg2Rad;
         }
         rotate_conf(natom, x, v, rotangles[XX], rotangles[YY], rotangles[ZZ]);
     }
@@ -1164,9 +1236,9 @@ int gmx_editconf(int argc, char* argv[])
     {
         printf("new box vectors :%7.3f%7.3f%7.3f (nm)\n", norm(box[XX]), norm(box[YY]), norm(box[ZZ]));
         printf("new box angles  :%7.2f%7.2f%7.2f (degrees)\n",
-               norm2(box[ZZ]) == 0 ? 0 : RAD2DEG * gmx_angle(box[YY], box[ZZ]),
-               norm2(box[ZZ]) == 0 ? 0 : RAD2DEG * gmx_angle(box[XX], box[ZZ]),
-               norm2(box[YY]) == 0 ? 0 : RAD2DEG * gmx_angle(box[XX], box[YY]));
+               norm2(box[ZZ]) == 0 ? 0 : gmx::c_rad2Deg * gmx_angle(box[YY], box[ZZ]),
+               norm2(box[ZZ]) == 0 ? 0 : gmx::c_rad2Deg * gmx_angle(box[XX], box[ZZ]),
+               norm2(box[YY]) == 0 ? 0 : gmx::c_rad2Deg * gmx_angle(box[XX], box[YY]));
         printf("new box volume  :%7.2f               (nm^3)\n", det(box));
     }
 
@@ -1236,8 +1308,8 @@ int gmx_editconf(int argc, char* argv[])
         }
         else
         {
-            write_sto_conf_indexed(outfile, name, &atoms, x, bHaveV ? v : nullptr, pbcType, box,
-                                   isize, index);
+            write_sto_conf_indexed(
+                    outfile, name, &atoms, x, bHaveV ? v : nullptr, pbcType, box, isize, index);
         }
         sfree(grpname);
         sfree(index);
@@ -1292,8 +1364,8 @@ int gmx_editconf(int argc, char* argv[])
             {
                 index[i] = i;
             }
-            write_pdbfile_indexed(out, name, &atoms, x, pbcType, box, ' ', -1, atoms.nr, index,
-                                  conect, outftp == efPQR);
+            write_pdbfile_indexed(
+                    out, name, &atoms, x, pbcType, box, ' ', -1, atoms.nr, index, conect, outftp == efPQR);
             sfree(index);
             if (bLegend)
             {
@@ -1301,8 +1373,11 @@ int gmx_editconf(int argc, char* argv[])
             }
             if (visbox[0] > 0)
             {
-                visualize_box(out, bLegend ? atoms.nr + 12 : atoms.nr,
-                              bLegend ? atoms.nres = 12 : atoms.nres, box, visbox);
+                visualize_box(out,
+                              bLegend ? atoms.nr + 12 : atoms.nr,
+                              bLegend ? atoms.nres = 12 : atoms.nres,
+                              box,
+                              visbox);
             }
             gmx_ffclose(out);
         }
index 9942775507f008c588a81bf8201b3d30a847ef75..3fd538825cdc87c76f70c26df0129d8020cb1b70 100644 (file)
@@ -108,7 +108,8 @@ std::vector<std::string> fflib_search_file_end(const char* ffdir, const char* fi
             std::string message = gmx::formatString(
                     "Could not find any files ending on '%s' "
                     "in the force field directory '%s'",
-                    file_end, ffdir);
+                    file_end,
+                    ffdir);
             GMX_THROW(gmx::InvalidInputError(message));
         }
         for (std::string& filename : result)
@@ -145,7 +146,8 @@ std::vector<gmx::DataFileInfo> fflib_enumerate_forcefields()
         std::string message = gmx::formatString(
                 "No force fields found (files with name '%s' "
                 "in subdirectories ending on '%s')",
-                filename, dirend);
+                filename,
+                dirend);
         GMX_THROW(gmx::InvalidInputError(message));
     }
 
index 8c3a4a399808b1d90a9406de745cc172da0d8c71..a39d5c881084e5a3e2b29c89704a49c8409d8f3b 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +58,7 @@
 #include "gromacs/math/vec.h"
 #include "gromacs/topology/ifunc.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
 
@@ -129,9 +130,10 @@ static bool dcomp(const InteractionOfType& d1, const InteractionOfType& d2)
     {
         // AMBER force fields with type 9 dihedrals can reach here, where we sort on
         // the contents of the string that names the macro for the parameters.
-        return std::lexicographical_compare(
-                d1.interactionTypeName().begin(), d1.interactionTypeName().end(),
-                d2.interactionTypeName().begin(), d2.interactionTypeName().end());
+        return std::lexicographical_compare(d1.interactionTypeName().begin(),
+                                            d1.interactionTypeName().end(),
+                                            d2.interactionTypeName().begin(),
+                                            d2.interactionTypeName().end());
     }
 }
 
@@ -299,7 +301,8 @@ static std::vector<InteractionOfType> clean_dih(gmx::ArrayRef<const InteractionO
                 int minh = 2;
                 int next = dihedral->second + 1;
                 for (int l = dihedral->second;
-                     (l < next && is_dihedral_on_same_bond(dihedral->first, dih[l])); l++)
+                     (l < next && is_dihedral_on_same_bond(dihedral->first, dih[l]));
+                     l++)
                 {
                     int nh = n_hydro(dih[l].atoms(), atoms->atomname);
                     if (nh < minh)
@@ -347,15 +350,15 @@ static std::vector<InteractionOfType> get_impropers(t_atoms*
     {
         for (int i = 0; (i < atoms->nres); i++)
         {
-            BondedInteractionList* impropers = &globalPatches[i].rb[ebtsIDIHS];
+            BondedInteractionList* impropers = &globalPatches[i].rb[BondedTypes::ImproperDihedrals];
             for (const auto& bondeds : impropers->b)
             {
                 bool             bStop = false;
                 std::vector<int> ai;
                 for (int k = 0; (k < 4) && !bStop; k++)
                 {
-                    const int entry = search_atom(bondeds.a[k].c_str(), start, atoms, "improper",
-                                                  bAllowMissing, cyclicBondsIndex);
+                    const int entry = search_atom(
+                            bondeds.a[k].c_str(), start, atoms, "improper", bAllowMissing, cyclicBondsIndex);
 
                     if (entry != -1)
                     {
@@ -451,7 +454,7 @@ static void gen_excls(t_atoms*                             atoms,
         int r = atoms->atom[a].resind;
         if (a == atoms->nr - 1 || atoms->atom[a + 1].resind != r)
         {
-            BondedInteractionList* hbexcl = &globalPatches[r].rb[ebtsEXCLS];
+            BondedInteractionList* hbexcl = &globalPatches[r].rb[BondedTypes::Exclusions];
 
             for (const auto& bondeds : hbexcl->b)
             {
@@ -605,9 +608,9 @@ void gen_pad(t_atoms*                               atoms,
         /* mark all entries as not matched yet */
         for (int i = 0; i < atoms->nres; i++)
         {
-            for (int j = 0; j < ebtsNR; j++)
+            for (auto bondedsList : globalPatches[i].rb)
             {
-                for (auto& bondeds : globalPatches[i].rb[j].b)
+                for (auto& bondeds : bondedsList.b)
                 {
                     bondeds.match = false;
                 }
@@ -649,7 +652,7 @@ void gen_pad(t_atoms*                               atoms,
                             {
                                 res += maxres - minres;
                                 get_atomnames_min(3, anm, res, atoms, atomNumbers);
-                                BondedInteractionList* hbang = &globalPatches[res].rb[ebtsANGLES];
+                                BondedInteractionList* hbang = &globalPatches[res].rb[BondedTypes::Angles];
                                 for (auto& bondeds : hbang->b)
                                 {
                                     if (anm[1] == bondeds.aj())
@@ -700,7 +703,8 @@ void gen_pad(t_atoms*                               atoms,
                                     {
                                         res += maxres - minres;
                                         get_atomnames_min(4, anm, res, atoms, atomNumbers);
-                                        BondedInteractionList* hbdih = &globalPatches[res].rb[ebtsPDIHS];
+                                        BondedInteractionList* hbdih =
+                                                &globalPatches[res].rb[BondedTypes::ProperDihedrals];
                                         for (auto& bondeds : hbdih->b)
                                         {
                                             bool bFound = false;
@@ -773,7 +777,7 @@ void gen_pad(t_atoms*                               atoms,
         for (int i = 0; i < atoms->nres; i++)
         {
             /* Add remaining angles from hackblock */
-            BondedInteractionList* hbang = &globalPatches[i].rb[ebtsANGLES];
+            BondedInteractionList* hbang = &globalPatches[i].rb[BondedTypes::Angles];
             for (auto& bondeds : hbang->b)
             {
                 if (bondeds.match)
@@ -824,7 +828,7 @@ void gen_pad(t_atoms*                               atoms,
             }
 
             /* Add remaining dihedrals from hackblock */
-            BondedInteractionList* hbdih = &globalPatches[i].rb[ebtsPDIHS];
+            BondedInteractionList* hbdih = &globalPatches[i].rb[BondedTypes::ProperDihedrals];
             for (auto& bondeds : hbdih->b)
             {
                 if (bondeds.match)
@@ -913,8 +917,7 @@ void gen_pad(t_atoms*                               atoms,
     if (!dih.empty())
     {
         fprintf(stderr, "Before cleaning: %zu dihedrals\n", dih.size());
-        dih = clean_dih(dih, improper, atoms, rtpFFDB[0].bKeepAllGeneratedDihedrals,
-                        rtpFFDB[0].bRemoveDihedralIfWithImproper);
+        dih = clean_dih(dih, improper, atoms, rtpFFDB[0].bKeepAllGeneratedDihedrals, rtpFFDB[0].bRemoveDihedralIfWithImproper);
     }
 
     /* Now we have unique lists of angles and dihedrals
index 41d53a1d3c4d589b2e9d90da34a091f2e8cea082..b02735d60d481d607113e4516baff37f1755db72 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 static void low_mspeed(real tempi, gmx_mtop_t* mtop, rvec v[], gmx::ThreeFry2x64<>* rng, const gmx::MDLogger& logger)
 {
     int                                    nrdf;
-    real                                   boltz;
     real                                   ekin, temp;
     gmx::TabulatedNormalDistribution<real> normalDist;
 
-    boltz = BOLTZ * tempi;
-    ekin  = 0.0;
-    nrdf  = 0;
+    ekin = 0.0;
+    nrdf = 0;
     for (const AtomProxy atomP : AtomRange(*mtop))
     {
         const t_atom& local = atomP.atom();
@@ -70,7 +68,7 @@ static void low_mspeed(real tempi, gmx_mtop_t* mtop, rvec v[], gmx::ThreeFry2x64
         if (mass > 0)
         {
             rng->restart(i, 0);
-            real sd = std::sqrt(boltz / mass);
+            real sd = std::sqrt(gmx::c_boltz * tempi / mass);
             for (int m = 0; (m < DIM); m++)
             {
                 v[i][m] = sd * normalDist(*rng);
@@ -79,7 +77,7 @@ static void low_mspeed(real tempi, gmx_mtop_t* mtop, rvec v[], gmx::ThreeFry2x64
             nrdf += DIM;
         }
     }
-    temp = (2.0 * ekin) / (nrdf * BOLTZ);
+    temp = (2.0 * ekin) / (nrdf * gmx::c_boltz);
     if (temp > 0)
     {
         real scal = std::sqrt(tempi / temp);
@@ -99,7 +97,8 @@ static void low_mspeed(real tempi, gmx_mtop_t* mtop, rvec v[], gmx::ThreeFry2x64
         fprintf(debug,
                 "Velocities were taken from a Maxwell distribution\n"
                 "Initial generated temperature: %12.5e (scaled to: %12.5e)\n",
-                temp, tempi);
+                temp,
+                tempi);
     }
 }
 
index cb0735fce79848b34450c7adf4632a8c07bfc9f4..448b5de2fa47a2d78d95ed80fe1a265e22c304bf 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstring>
 
 #include <algorithm>
+#include <optional>
 #include <string>
 #include <utility>
 #include <vector>
@@ -58,6 +59,7 @@
 #include "gromacs/gmxpreprocess/toputil.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/topology/ifunc.h"
@@ -272,7 +274,7 @@ static void read_vsite_database(const char*                            ddbname,
         {
             if (pline[0] == OPENDIR)
             {
-                strncpy(dirstr, pline + 1, STRLEN - 2);
+                strncpy(dirstr, pline + 1, STRLEN - 1);
                 if ((ch = strchr(dirstr, CLOSEDIR)) != nullptr)
                 {
                     (*ch) = 0;
@@ -365,21 +367,23 @@ static void read_vsite_database(const char*                            ddbname,
                         else if (numberOfSites == 4)
                         {
                             /* angle */
-                            vsitetoplist->back().angle.emplace_back(s1String, s2String, s3String,
-                                                                    strtod(s4, nullptr));
+                            vsitetoplist->back().angle.emplace_back(
+                                    s1String, s2String, s3String, strtod(s4, nullptr));
                             /* angle */
                         }
                         else
                         {
                             gmx_fatal(FARGS,
                                       "Need 3 or 4 values to specify bond/angle values in %s: %s\n",
-                                      ddbname, pline);
+                                      ddbname,
+                                      pline);
                         }
                     }
                     break;
                     default:
                         gmx_fatal(FARGS,
-                                  "Didnt find a case for directive %s in read_vsite_database\n", dirstr);
+                                  "Didnt find a case for directive %s in read_vsite_database\n",
+                                  dirstr);
                 }
             }
         }
@@ -450,8 +454,11 @@ static real get_ddb_bond(gmx::ArrayRef<const VirtualSiteTopology> vsitetop,
             });
     if (foundBond == found->bond.end())
     {
-        gmx_fatal(FARGS, "Couldnt find bond %s-%s for residue %s in vsite database.\n",
-                  atom1.c_str(), atom2.c_str(), res.c_str());
+        gmx_fatal(FARGS,
+                  "Couldnt find bond %s-%s for residue %s in vsite database.\n",
+                  atom1.c_str(),
+                  atom2.c_str(),
+                  res.c_str());
     }
 
     return foundBond->value;
@@ -482,8 +489,12 @@ static real get_ddb_angle(gmx::ArrayRef<const VirtualSiteTopology> vsitetop,
 
     if (foundAngle == found->angle.end())
     {
-        gmx_fatal(FARGS, "Couldnt find angle %s-%s-%s for residue %s in vsite database.\n",
-                  atom1.c_str(), atom2.c_str(), atom3.c_str(), res.c_str());
+        gmx_fatal(FARGS,
+                  "Couldnt find angle %s-%s-%s for residue %s in vsite database.\n",
+                  atom1.c_str(),
+                  atom2.c_str(),
+                  atom3.c_str(),
+                  res.c_str());
     }
 
     return foundAngle->value;
@@ -505,7 +516,8 @@ static void count_bonds(int                 atom,
     /* find heavy atom bound to this hydrogen */
     heavy = NOTSET;
     for (auto parm = psb->interactionTypes.begin();
-         (parm != psb->interactionTypes.end()) && (heavy == NOTSET); parm++)
+         (parm != psb->interactionTypes.end()) && (heavy == NOTSET);
+         parm++)
     {
         if (parm->ai() == atom)
         {
@@ -598,15 +610,13 @@ static int get_atype(int atom, t_atoms* at, gmx::ArrayRef<const PreprocessResidu
 
 static int vsite_nm2type(const char* name, PreprocessingAtomTypes* atype)
 {
-    int tp;
-
-    tp = atype->atomTypeFromName(name);
-    if (tp == NOTSET)
+    auto tp = atype->atomTypeFromName(name);
+    if (!tp.has_value())
     {
         gmx_fatal(FARGS, "Dummy mass type (%s) not found in atom type database", name);
     }
 
-    return tp;
+    return *tp;
 }
 
 static real get_amass(int atom, t_atoms* at, gmx::ArrayRef<const PreprocessResidue> rtpFFDB, ResidueType* rt)
@@ -668,7 +678,8 @@ static void add_vsites(gmx::ArrayRef<InteractionsOfType> plist,
                 gmx_fatal(FARGS,
                           "cannot make constraint in add_vsites for %d heavy "
                           "atoms and %d hydrogen atoms",
-                          nrheavies, nrHatoms);
+                          nrheavies,
+                          nrHatoms);
             }
             my_add_param(&(plist[F_CONSTRNC]), Hatoms[i], heavies[0], NOTSET);
         }
@@ -681,8 +692,10 @@ static void add_vsites(gmx::ArrayRef<InteractionsOfType> plist,
                 case F_VSITE3OUT:
                     if (nrheavies < 2)
                     {
-                        gmx_fatal(FARGS, "Not enough heavy atoms (%d) for %s (min 3)",
-                                  nrheavies + 1, interaction_function[vsite_type[Hatoms[i]]].name);
+                        gmx_fatal(FARGS,
+                                  "Not enough heavy atoms (%d) for %s (min 3)",
+                                  nrheavies + 1,
+                                  interaction_function[vsite_type[Hatoms[i]]].name);
                     }
                     add_vsite3_atoms(&plist[ftype], Hatoms[i], Heavy, heavies[0], heavies[1], bSwapParity);
                     break;
@@ -725,21 +738,24 @@ static void add_vsites(gmx::ArrayRef<InteractionsOfType> plist,
                 case F_VSITE4FDN:
                     if (nrheavies < 3)
                     {
-                        gmx_fatal(FARGS, "Not enough heavy atoms (%d) for %s (min 4)",
-                                  nrheavies + 1, interaction_function[vsite_type[Hatoms[i]]].name);
+                        gmx_fatal(FARGS,
+                                  "Not enough heavy atoms (%d) for %s (min 4)",
+                                  nrheavies + 1,
+                                  interaction_function[vsite_type[Hatoms[i]]].name);
                     }
                     add_vsite4_atoms(&plist[ftype], Hatoms[0], Heavy, heavies[0], heavies[1], heavies[2]);
                     break;
 
                 default:
-                    gmx_fatal(FARGS, "can't use add_vsites for interaction function %s",
+                    gmx_fatal(FARGS,
+                              "can't use add_vsites for interaction function %s",
                               interaction_function[vsite_type[Hatoms[i]]].name);
             } /* switch ftype */
         }     /* else */
     }         /* for i */
 }
 
-#define ANGLE_6RING (DEG2RAD * 120)
+#define ANGLE_6RING (gmx::c_deg2Rad * 120)
 
 /* cosine rule: a^2 = b^2 + c^2 - 2 b c cos(alpha) */
 /* get a^2 when a, b and alpha are given: */
@@ -1004,21 +1020,21 @@ static int gen_vsites_trp(PreprocessingAtomTypes*                  atype,
     b_CE3_HE3 = get_ddb_bond(vsitetop, "TRP", "CE3", "HE3");
     b_CZ3_HZ3 = get_ddb_bond(vsitetop, "TRP", "CZ3", "HZ3");
 
-    a_NE1_CE2_CD2 = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "NE1", "CE2", "CD2");
-    a_CE2_CD2_CG  = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "CE2", "CD2", "CG");
-    a_CB_CG_CD2   = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "CB", "CG", "CD2");
-    a_CD2_CG_CD1  = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "CD2", "CG", "CD1");
-
-    a_CE2_CD2_CE3 = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "CE2", "CD2", "CE3");
-    a_CD2_CE2_CZ2 = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "CD2", "CE2", "CZ2");
-    a_CD2_CE3_CZ3 = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "CD2", "CE3", "CZ3");
-    a_CE3_CZ3_HZ3 = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "CE3", "CZ3", "HZ3");
-    a_CZ2_CH2_HH2 = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "CZ2", "CH2", "HH2");
-    a_CE2_CZ2_HZ2 = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "CE2", "CZ2", "HZ2");
-    a_CE2_CZ2_CH2 = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "CE2", "CZ2", "CH2");
-    a_CG_CD1_HD1  = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "CG", "CD1", "HD1");
-    a_HE1_NE1_CE2 = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "HE1", "NE1", "CE2");
-    a_CD2_CE3_HE3 = DEG2RAD * get_ddb_angle(vsitetop, "TRP", "CD2", "CE3", "HE3");
+    a_NE1_CE2_CD2 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "NE1", "CE2", "CD2");
+    a_CE2_CD2_CG  = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "CE2", "CD2", "CG");
+    a_CB_CG_CD2   = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "CB", "CG", "CD2");
+    a_CD2_CG_CD1  = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "CD2", "CG", "CD1");
+
+    a_CE2_CD2_CE3 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "CE2", "CD2", "CE3");
+    a_CD2_CE2_CZ2 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "CD2", "CE2", "CZ2");
+    a_CD2_CE3_CZ3 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "CD2", "CE3", "CZ3");
+    a_CE3_CZ3_HZ3 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "CE3", "CZ3", "HZ3");
+    a_CZ2_CH2_HH2 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "CZ2", "CH2", "HH2");
+    a_CE2_CZ2_HZ2 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "CE2", "CZ2", "HZ2");
+    a_CE2_CZ2_CH2 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "CE2", "CZ2", "CH2");
+    a_CG_CD1_HD1  = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "CG", "CD1", "HD1");
+    a_HE1_NE1_CE2 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "HE1", "NE1", "CE2");
+    a_CD2_CE3_HE3 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TRP", "CD2", "CE3", "HE3");
 
     /* Calculate local coordinates.
      * y-axis (x=0) is the bond CD2-CE2.
@@ -1143,15 +1159,15 @@ static int gen_vsites_trp(PreprocessingAtomTypes*                  atype,
      */
     rvec_sub(x[ats[atCB]], x[ats[atCG]], r_ij);
     rvec_sub(x[ats[atCD2]], x[ats[atCG]], r_ik);
-    calc_vsite3_param(xcom[0], ycom[0], xi[atCG], yi[atCG], xi[atCB], yi[atCB], xi[atCD2],
-                      yi[atCD2], &a, &b);
+    calc_vsite3_param(
+            xcom[0], ycom[0], xi[atCG], yi[atCG], xi[atCB], yi[atCB], xi[atCD2], yi[atCD2], &a, &b);
     svmul(a, r_ij, t1);
     svmul(b, r_ik, t2);
     rvec_add(t1, t2, t1);
     rvec_add(t1, x[ats[atCG]], (*newx)[atM[0]]);
 
-    calc_vsite3_param(xcom[1], ycom[1], xi[atCG], yi[atCG], xi[atCB], yi[atCB], xi[atCD2],
-                      yi[atCD2], &a, &b);
+    calc_vsite3_param(
+            xcom[1], ycom[1], xi[atCG], yi[atCG], xi[atCB], yi[atCB], xi[atCD2], yi[atCD2], &a, &b);
     svmul(a, r_ij, t1);
     svmul(b, r_ik, t2);
     rvec_add(t1, t2, t1);
@@ -1165,7 +1181,7 @@ static int gen_vsites_trp(PreprocessingAtomTypes*                  atype,
         (*newatom)[atM[j]].m = (*newatom)[atM[j]].mB = mM[j];
         (*newatom)[atM[j]].q = (*newatom)[atM[j]].qB = 0.0;
         (*newatom)[atM[j]].type = (*newatom)[atM[j]].typeB = tpM;
-        (*newatom)[atM[j]].ptype                           = eptAtom;
+        (*newatom)[atM[j]].ptype                           = ParticleType::Atom;
         (*newatom)[atM[j]].resind                          = at->atom[i0].resind;
         (*newatom)[atM[j]].elem[0]                         = 'M';
         (*newatom)[atM[j]].elem[1]                         = '\0';
@@ -1205,10 +1221,10 @@ static int gen_vsites_trp(PreprocessingAtomTypes*                  atype,
     {
         if ((*vsite_type)[ats[i]] == F_VSITE3)
         {
-            calc_vsite3_param(xi[i], yi[i], xcom[0], ycom[0], xcom[1], ycom[1], xi[atCB], yi[atCB],
-                              &a, &b);
-            add_vsite3_param(&plist[F_VSITE3], ats[i], add_shift + atM[0], add_shift + atM[1],
-                             ats[atCB], a, b);
+            calc_vsite3_param(
+                    xi[i], yi[i], xcom[0], ycom[0], xcom[1], ycom[1], xi[atCB], yi[atCB], &a, &b);
+            add_vsite3_param(
+                    &plist[F_VSITE3], ats[i], add_shift + atM[0], add_shift + atM[1], ats[atCB], a, b);
         }
     }
     return nvsite;
@@ -1276,7 +1292,7 @@ static int gen_vsites_tyr(PreprocessingAtomTypes*                  atype,
     bond_ch   = get_ddb_bond(vsitetop, "TYR", "CD1", "HD1");
     bond_co   = get_ddb_bond(vsitetop, "TYR", "CZ", "OH");
     bond_oh   = get_ddb_bond(vsitetop, "TYR", "OH", "HH");
-    angle_coh = DEG2RAD * get_ddb_angle(vsitetop, "TYR", "CZ", "OH", "HH");
+    angle_coh = gmx::c_deg2Rad * get_ddb_angle(vsitetop, "TYR", "CZ", "OH", "HH");
 
     xi[atCG]  = -bond_cc + bond_cc * std::cos(ANGLE_6RING);
     xi[atCD1] = -bond_cc;
@@ -1361,7 +1377,7 @@ static int gen_vsites_tyr(PreprocessingAtomTypes*                  atype,
     (*newatom)[atM].m = (*newatom)[atM].mB = mM;
     (*newatom)[atM].q = (*newatom)[atM].qB = 0.0;
     (*newatom)[atM].type = (*newatom)[atM].typeB = tpM;
-    (*newatom)[atM].ptype                        = eptAtom;
+    (*newatom)[atM].ptype                        = ParticleType::Atom;
     (*newatom)[atM].resind                       = at->atom[i0].resind;
     (*newatom)[atM].elem[0]                      = 'M';
     (*newatom)[atM].elem[1]                      = '\0';
@@ -1456,30 +1472,30 @@ static int gen_vsites_his(t_atoms*                                 at,
     b_CE1_NE2     = get_ddb_bond(vsitetop, resname, "CE1", "NE2");
     b_CG_CD2      = get_ddb_bond(vsitetop, resname, "CG", "CD2");
     b_CD2_NE2     = get_ddb_bond(vsitetop, resname, "CD2", "NE2");
-    a_CG_ND1_CE1  = DEG2RAD * get_ddb_angle(vsitetop, resname, "CG", "ND1", "CE1");
-    a_CG_CD2_NE2  = DEG2RAD * get_ddb_angle(vsitetop, resname, "CG", "CD2", "NE2");
-    a_ND1_CE1_NE2 = DEG2RAD * get_ddb_angle(vsitetop, resname, "ND1", "CE1", "NE2");
-    a_CE1_NE2_CD2 = DEG2RAD * get_ddb_angle(vsitetop, resname, "CE1", "NE2", "CD2");
+    a_CG_ND1_CE1  = gmx::c_deg2Rad * get_ddb_angle(vsitetop, resname, "CG", "ND1", "CE1");
+    a_CG_CD2_NE2  = gmx::c_deg2Rad * get_ddb_angle(vsitetop, resname, "CG", "CD2", "NE2");
+    a_ND1_CE1_NE2 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, resname, "ND1", "CE1", "NE2");
+    a_CE1_NE2_CD2 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, resname, "CE1", "NE2", "CD2");
 
     if (ats[atHD1] != NOTSET)
     {
         b_ND1_HD1     = get_ddb_bond(vsitetop, resname, "ND1", "HD1");
-        a_CE1_ND1_HD1 = DEG2RAD * get_ddb_angle(vsitetop, resname, "CE1", "ND1", "HD1");
+        a_CE1_ND1_HD1 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, resname, "CE1", "ND1", "HD1");
     }
     if (ats[atHE2] != NOTSET)
     {
         b_NE2_HE2     = get_ddb_bond(vsitetop, resname, "NE2", "HE2");
-        a_CE1_NE2_HE2 = DEG2RAD * get_ddb_angle(vsitetop, resname, "CE1", "NE2", "HE2");
+        a_CE1_NE2_HE2 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, resname, "CE1", "NE2", "HE2");
     }
     if (ats[atHD2] != NOTSET)
     {
         b_CD2_HD2     = get_ddb_bond(vsitetop, resname, "CD2", "HD2");
-        a_NE2_CD2_HD2 = DEG2RAD * get_ddb_angle(vsitetop, resname, "NE2", "CD2", "HD2");
+        a_NE2_CD2_HD2 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, resname, "NE2", "CD2", "HD2");
     }
     if (ats[atHE1] != NOTSET)
     {
         b_CE1_HE1     = get_ddb_bond(vsitetop, resname, "CE1", "HE1");
-        a_NE2_CE1_HE1 = DEG2RAD * get_ddb_angle(vsitetop, resname, "NE2", "CE1", "HE1");
+        a_NE2_CE1_HE1 = gmx::c_deg2Rad * get_ddb_angle(vsitetop, resname, "NE2", "CE1", "HE1");
     }
 
     /* constraints between CG, CE1 and NE1 */
@@ -1584,40 +1600,40 @@ static int gen_vsites_his(t_atoms*                                 at,
     /* HE1 */
     if (ats[atHE1] != NOTSET)
     {
-        calc_vsite3_param(x[atHE1], y[atHE1], x[atCE1], y[atCE1], x[atNE2], y[atNE2], x[atCG],
-                          y[atCG], &a, &b);
+        calc_vsite3_param(
+                x[atHE1], y[atHE1], x[atCE1], y[atCE1], x[atNE2], y[atNE2], x[atCG], y[atCG], &a, &b);
         add_vsite3_param(&plist[F_VSITE3], ats[atHE1], ats[atCE1], ats[atNE2], ats[atCG], a, b);
     }
     /* HE2 */
     if (ats[atHE2] != NOTSET)
     {
-        calc_vsite3_param(x[atHE2], y[atHE2], x[atNE2], y[atNE2], x[atCE1], y[atCE1], x[atCG],
-                          y[atCG], &a, &b);
+        calc_vsite3_param(
+                x[atHE2], y[atHE2], x[atNE2], y[atNE2], x[atCE1], y[atCE1], x[atCG], y[atCG], &a, &b);
         add_vsite3_param(&plist[F_VSITE3], ats[atHE2], ats[atNE2], ats[atCE1], ats[atCG], a, b);
     }
 
     /* ND1 */
-    calc_vsite3_param(x[atND1], y[atND1], x[atNE2], y[atNE2], x[atCE1], y[atCE1], x[atCG], y[atCG],
-                      &a, &b);
+    calc_vsite3_param(
+            x[atND1], y[atND1], x[atNE2], y[atNE2], x[atCE1], y[atCE1], x[atCG], y[atCG], &a, &b);
     add_vsite3_param(&plist[F_VSITE3], ats[atND1], ats[atNE2], ats[atCE1], ats[atCG], a, b);
 
     /* CD2 */
-    calc_vsite3_param(x[atCD2], y[atCD2], x[atCE1], y[atCE1], x[atNE2], y[atNE2], x[atCG], y[atCG],
-                      &a, &b);
+    calc_vsite3_param(
+            x[atCD2], y[atCD2], x[atCE1], y[atCE1], x[atNE2], y[atNE2], x[atCG], y[atCG], &a, &b);
     add_vsite3_param(&plist[F_VSITE3], ats[atCD2], ats[atCE1], ats[atNE2], ats[atCG], a, b);
 
     /* HD1 */
     if (ats[atHD1] != NOTSET)
     {
-        calc_vsite3_param(x[atHD1], y[atHD1], x[atNE2], y[atNE2], x[atCE1], y[atCE1], x[atCG],
-                          y[atCG], &a, &b);
+        calc_vsite3_param(
+                x[atHD1], y[atHD1], x[atNE2], y[atNE2], x[atCE1], y[atCE1], x[atCG], y[atCG], &a, &b);
         add_vsite3_param(&plist[F_VSITE3], ats[atHD1], ats[atNE2], ats[atCE1], ats[atCG], a, b);
     }
     /* HD2 */
     if (ats[atHD2] != NOTSET)
     {
-        calc_vsite3_param(x[atHD2], y[atHD2], x[atCE1], y[atCE1], x[atNE2], y[atNE2], x[atCG],
-                          y[atCG], &a, &b);
+        calc_vsite3_param(
+                x[atHD2], y[atHD2], x[atCE1], y[atCE1], x[atNE2], y[atNE2], x[atCG], y[atCG], &a, &b);
         add_vsite3_param(&plist[F_VSITE3], ats[atHD2], ats[atCE1], ats[atNE2], ats[atCG], a, b);
     }
     return nvsite;
@@ -1641,7 +1657,7 @@ static bool is_vsite(int vsite_type)
     }
 }
 
-static char atomnamesuffix[] = "1234";
+static const char atomnamesuffix[] = "1234";
 
 void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
                PreprocessingAtomTypes*                atype,
@@ -1690,17 +1706,58 @@ void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
     /* the atnms for every residue MUST correspond to the enums in the
        gen_vsites_* (one for each residue) routines! */
     /* also the atom names in atnms MUST be in the same order as in the .rtp! */
-    const char* atnms[resNR][MAXATOMSPERRESIDUE + 1] = {
-        { "CG", /* PHE */
-          "CD1", "HD1", "CD2", "HD2", "CE1", "HE1", "CE2", "HE2", "CZ", "HZ", nullptr },
-        { "CB", /* TRP */
-          "CG", "CD1", "HD1", "CD2", "NE1", "HE1", "CE2", "CE3", "HE3", "CZ2", "HZ2", "CZ3", "HZ3",
-          "CH2", "HH2", nullptr },
-        { "CG", /* TYR */
-          "CD1", "HD1", "CD2", "HD2", "CE1", "HE1", "CE2", "HE2", "CZ", "OH", "HH", nullptr },
-        { "CG", /* HIS */
-          "ND1", "HD1", "CD2", "HD2", "CE1", "HE1", "NE2", "HE2", nullptr }
-    };
+    const char* atnms[resNR][MAXATOMSPERRESIDUE + 1] = { { "CG", /* PHE */
+                                                           "CD1",
+                                                           "HD1",
+                                                           "CD2",
+                                                           "HD2",
+                                                           "CE1",
+                                                           "HE1",
+                                                           "CE2",
+                                                           "HE2",
+                                                           "CZ",
+                                                           "HZ",
+                                                           nullptr },
+                                                         { "CB", /* TRP */
+                                                           "CG",
+                                                           "CD1",
+                                                           "HD1",
+                                                           "CD2",
+                                                           "NE1",
+                                                           "HE1",
+                                                           "CE2",
+                                                           "CE3",
+                                                           "HE3",
+                                                           "CZ2",
+                                                           "HZ2",
+                                                           "CZ3",
+                                                           "HZ3",
+                                                           "CH2",
+                                                           "HH2",
+                                                           nullptr },
+                                                         { "CG", /* TYR */
+                                                           "CD1",
+                                                           "HD1",
+                                                           "CD2",
+                                                           "HD2",
+                                                           "CE1",
+                                                           "HE1",
+                                                           "CE2",
+                                                           "HE2",
+                                                           "CZ",
+                                                           "OH",
+                                                           "HH",
+                                                           nullptr },
+                                                         { "CG", /* HIS */
+                                                           "ND1",
+                                                           "HD1",
+                                                           "CD2",
+                                                           "HD2",
+                                                           "CE1",
+                                                           "HE1",
+                                                           "NE2",
+                                                           "HE2",
+                                                           nullptr } };
 
     if (debug)
     {
@@ -1818,7 +1875,10 @@ void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
                                   "not enough atoms found (%d, need %d) in "
                                   "residue %s %d while\n             "
                                   "generating aromatics virtual site construction",
-                                  nrfound, needed, resnm, at->resinfo[resind].nr);
+                                  nrfound,
+                                  needed,
+                                  resnm,
+                                  at->resinfo[resind].nr);
                     }
                     /* Advance overall atom counter */
                     i++;
@@ -1839,18 +1899,48 @@ void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
                     {
                         fprintf(stderr, "TRP at %d\n", o2n[ats[0]] + 1);
                     }
-                    nvsite += gen_vsites_trp(atype, &newx, &newatom, &newatomname, &o2n,
-                                             &newvsite_type, &newcgnr, symtab, &nadd, *x, cgnr, at,
-                                             vsite_type, plist, nrfound, ats, add_shift, vsitetop);
+                    nvsite += gen_vsites_trp(atype,
+                                             &newx,
+                                             &newatom,
+                                             &newatomname,
+                                             &o2n,
+                                             &newvsite_type,
+                                             &newcgnr,
+                                             symtab,
+                                             &nadd,
+                                             *x,
+                                             cgnr,
+                                             at,
+                                             vsite_type,
+                                             plist,
+                                             nrfound,
+                                             ats,
+                                             add_shift,
+                                             vsitetop);
                     break;
                 case resTYR:
                     if (debug)
                     {
                         fprintf(stderr, "TYR at %d\n", o2n[ats[0]] + 1);
                     }
-                    nvsite += gen_vsites_tyr(atype, &newx, &newatom, &newatomname, &o2n,
-                                             &newvsite_type, &newcgnr, symtab, &nadd, *x, cgnr, at,
-                                             vsite_type, plist, nrfound, ats, add_shift, vsitetop);
+                    nvsite += gen_vsites_tyr(atype,
+                                             &newx,
+                                             &newatom,
+                                             &newatomname,
+                                             &o2n,
+                                             &newvsite_type,
+                                             &newcgnr,
+                                             symtab,
+                                             &nadd,
+                                             *x,
+                                             cgnr,
+                                             at,
+                                             vsite_type,
+                                             plist,
+                                             nrfound,
+                                             ats,
+                                             add_shift,
+                                             vsitetop);
                     break;
                 case resHIS:
                     if (debug)
@@ -1877,11 +1967,10 @@ void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
         {
             /* find heavy atom, count #bonds from it and #H atoms bound to it
                and return H atom numbers (Hatoms) and heavy atom numbers (heavies) */
-            count_bonds(i, &plist[F_BONDS], at->atomname, &nrbonds, &nrHatoms, Hatoms, &Heavy,
-                        &nrheavies, heavies);
+            count_bonds(i, &plist[F_BONDS], at->atomname, &nrbonds, &nrHatoms, Hatoms, &Heavy, &nrheavies, heavies);
             /* get Heavy atom type */
             tpHeavy = get_atype(Heavy, at, rtpFFDB, &rt);
-            strcpy(tpname, atype->atomNameFromAtomType(tpHeavy));
+            strcpy(tpname, *atype->atomNameFromAtomType(tpHeavy));
 
             bWARNING       = FALSE;
             bAddVsiteParam = TRUE;
@@ -1979,7 +2068,7 @@ void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
                     /* get dummy mass type from first char of heavy atom type (N or C) */
 
                     strcpy(nexttpname,
-                           atype->atomNameFromAtomType(get_atype(heavies[0], at, rtpFFDB, &rt)));
+                           *atype->atomNameFromAtomType(get_atype(heavies[0], at, rtpFFDB, &rt)));
                     std::string ch = get_dummymass_name(vsiteconflist, tpname, nexttpname);
                     std::string name;
                     if (ch.empty())
@@ -1990,14 +2079,16 @@ void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
                                     FARGS,
                                     "Can't find dummy mass for type %s bonded to type %s in the "
                                     "virtual site database (.vsd files). Add it to the database!\n",
-                                    tpname, nexttpname);
+                                    tpname,
+                                    nexttpname);
                         }
                         else
                         {
                             gmx_fatal(FARGS,
                                       "A dummy mass for type %s bonded to type %s is required, but "
                                       "no virtual site database (.vsd) files where found.\n",
-                                      tpname, nexttpname);
+                                      tpname,
+                                      nexttpname);
                         }
                     }
                     else
@@ -2084,7 +2175,7 @@ void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
                         newatom[ni0 + j].m = newatom[ni0 + j].mB = mtot / NMASS;
                         newatom[ni0 + j].q = newatom[ni0 + j].qB = 0.0;
                         newatom[ni0 + j].type = newatom[ni0 + j].typeB = tpM;
-                        newatom[ni0 + j].ptype                         = eptAtom;
+                        newatom[ni0 + j].ptype                         = ParticleType::Atom;
                         newatom[ni0 + j].resind                        = at->atom[i0].resind;
                         newatom[ni0 + j].elem[0]                       = 'M';
                         newatom[ni0 + j].elem[1]                       = '\0';
@@ -2099,12 +2190,20 @@ void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
 
                     /* generate Heavy, H1, H2 and H3 from M1, M2 and heavies[0] */
                     /* note that vsite_type cannot be NOTSET, because we just set it */
-                    add_vsite3_atoms(&plist[(*vsite_type)[Heavy]], Heavy, heavies[0],
-                                     add_shift + ni0, add_shift + ni0 + 1, FALSE);
+                    add_vsite3_atoms(&plist[(*vsite_type)[Heavy]],
+                                     Heavy,
+                                     heavies[0],
+                                     add_shift + ni0,
+                                     add_shift + ni0 + 1,
+                                     FALSE);
                     for (int j = 0; j < nrHatoms; j++)
                     {
-                        add_vsite3_atoms(&plist[(*vsite_type)[Hatoms[j]]], Hatoms[j], heavies[0],
-                                         add_shift + ni0, add_shift + ni0 + 1, Hat_SwapParity[j]);
+                        add_vsite3_atoms(&plist[(*vsite_type)[Hatoms[j]]],
+                                         Hatoms[j],
+                                         heavies[0],
+                                         add_shift + ni0,
+                                         add_shift + ni0 + 1,
+                                         Hat_SwapParity[j]);
                     }
 #undef NMASS
                 }
@@ -2119,7 +2218,11 @@ void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
                           "Cannot convert atom %d %s (bound to a heavy atom "
                           "%s with \n"
                           "         %d bonds and %d bound hydrogens atoms) to virtual site\n",
-                          i + 1, *(at->atomname[i]), tpname, nrbonds, nrHatoms);
+                          i + 1,
+                          *(at->atomname[i]),
+                          tpname,
+                          nrbonds,
+                          nrHatoms);
             }
             if (bAddVsiteParam)
             {
@@ -2152,8 +2255,12 @@ void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
         fprintf(debug, "Before inserting new atoms:\n");
         for (int i = 0; i < at->nr; i++)
         {
-            fprintf(debug, "%4d %4d %4s %4d %4s %6d %-10s\n", i + 1, o2n[i] + 1,
-                    at->atomname[i] ? *(at->atomname[i]) : "(NULL)", at->resinfo[at->atom[i].resind].nr,
+            fprintf(debug,
+                    "%4d %4d %4s %4d %4s %6d %-10s\n",
+                    i + 1,
+                    o2n[i] + 1,
+                    at->atomname[i] ? *(at->atomname[i]) : "(NULL)",
+                    at->resinfo[at->atom[i].resind].nr,
                     at->resinfo[at->atom[i].resind].name ? *(at->resinfo[at->atom[i].resind].name) : "(NULL)",
                     (*cgnr)[i],
                     ((*vsite_type)[i] == NOTSET) ? "NOTSET" : interaction_function[(*vsite_type)[i]].name);
@@ -2163,8 +2270,12 @@ void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
         {
             if (newatomname[i])
             {
-                fprintf(debug, "%4d %4s %4d %6d %-10s\n", i + 1,
-                        newatomname[i] ? *(newatomname[i]) : "(NULL)", newatom[i].resind, newcgnr[i],
+                fprintf(debug,
+                        "%4d %4s %4d %6d %-10s\n",
+                        i + 1,
+                        newatomname[i] ? *(newatomname[i]) : "(NULL)",
+                        newatom[i].resind,
+                        newcgnr[i],
                         (newvsite_type[i] == NOTSET) ? "NOTSET"
                                                      : interaction_function[newvsite_type[i]].name);
             }
@@ -2197,7 +2308,8 @@ void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
         gmx_fatal(FARGS,
                   "Added impossible amount of dummy masses "
                   "(%d on a total of %d atoms)\n",
-                  nadd, at->nr - nadd);
+                  nadd,
+                  at->nr - nadd);
     }
 
     if (debug)
@@ -2205,8 +2317,11 @@ void do_vsites(gmx::ArrayRef<const PreprocessResidue> rtpFFDB,
         fprintf(debug, "After inserting new atoms:\n");
         for (int i = 0; i < at->nr; i++)
         {
-            fprintf(debug, "%4d %4s %4d %4s %6d %-10s\n", i + 1,
-                    at->atomname[i] ? *(at->atomname[i]) : "(NULL)", at->resinfo[at->atom[i].resind].nr,
+            fprintf(debug,
+                    "%4d %4s %4d %4s %6d %-10s\n",
+                    i + 1,
+                    at->atomname[i] ? *(at->atomname[i]) : "(NULL)",
+                    at->resinfo[at->atom[i].resind].nr,
                     at->resinfo[at->atom[i].resind].name ? *(at->resinfo[at->atom[i].resind].name) : "(NULL)",
                     (*cgnr)[i],
                     ((*vsite_type)[i] == NOTSET) ? "NOTSET" : interaction_function[(*vsite_type)[i]].name);
@@ -2279,7 +2394,8 @@ void do_h_mass(InteractionsOfType* psb, int vsite_type[], t_atoms* at, real mHmu
             /* find bonded heavy atom */
             int a = NOTSET;
             for (auto parm = psb->interactionTypes.begin();
-                 (parm != psb->interactionTypes.end()) && (a == NOTSET); parm++)
+                 (parm != psb->interactionTypes.end()) && (a == NOTSET);
+                 parm++)
             {
                 /* if other atom is not a virtual site, it is the one we want */
                 if ((parm->ai() == i) && !is_vsite(vsite_type[parm->aj()]))
index 37d6384f6e7847d06df60e54475ec7ae6052da29..d660eb37fad512c241bd7fe58e59d0a41e572573 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #include "gromacs/fileio/confio.h"
 #include "gromacs/fileio/trxio.h"
 #include "gromacs/math/3dtransforms.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdtypes/md_enums.h"
@@ -152,8 +153,8 @@ int gmx_genconf(int argc, char* argv[])
         { "-renumber", FALSE, etBOOL, { &bRenum }, "Renumber residues" }
     };
 
-    if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc,
-                           asize(bugs), bugs, &oenv))
+    if (!parse_common_args(
+                &argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
         return 0;
     }
@@ -179,7 +180,7 @@ int gmx_genconf(int argc, char* argv[])
     gmx_mtop_t mtop;
     bool       haveTop = false;
     readConfAndTopology(opt2fn("-f", NFILE, fnm), &haveTop, &mtop, &pbcType, &x, &v, box);
-    t_atoms atoms = gmx_mtop_global_atoms(&mtop);
+    t_atoms atoms = gmx_mtop_global_atoms(mtop);
     natoms        = atoms.nr;
     nres          = atoms.nres; /* nr of residues in one element? */
     /* make space for all the atoms */
index b2a4d0abca5bf60e0fd3b336524861a663ce0606..b9c8680c2ef9310cffb36646e6ffefea4f297764 100644 (file)
@@ -177,7 +177,7 @@ static void expand_hackblocks_one(const MoleculePatchDatabase& newPatch,
 {
     /* we'll recursively add atoms to atoms */
     int pos = 0;
-    for (auto& singlePatch : newPatch.hack)
+    for (const auto& singlePatch : newPatch.hack)
     {
         /* first check if we're in the N- or C-terminus, then we should ignore
            all hacks involving atoms from resp. previous or next residue
@@ -227,7 +227,9 @@ static void expand_hackblocks_one(const MoleculePatchDatabase& newPatch,
                     {
                         fprintf(debug,
                                 "Hack '%s' %d, replacing nname '%s' with '%s' (old name '%s')\n",
-                                localAtomName.c_str(), pos, patch->nname.c_str(),
+                                localAtomName.c_str(),
+                                pos,
+                                patch->nname.c_str(),
                                 singlePatch.nname.c_str(),
                                 patch->oname.empty() ? "" : patch->oname.c_str());
                     }
@@ -262,8 +264,11 @@ static void expand_hackblocks_one(const MoleculePatchDatabase& newPatch,
                 for (int k = 0; k < singlePatch.nr; k++)
                 {
                     expand_hackblocks_one(
-                            newPatch, globalPatches->at(globalPatches->size() - singlePatch.nr + k).nname,
-                            globalPatches, bN, bC);
+                            newPatch,
+                            globalPatches->at(globalPatches->size() - singlePatch.nr + k).nname,
+                            globalPatches,
+                            bN,
+                            bC);
                 }
             }
         }
@@ -369,8 +374,12 @@ static void calc_all_pos(const t_atoms*                            pdba,
                 bool bFoundAll = true;
                 for (int m = 0; (m < patch->nctl && bFoundAll); m++)
                 {
-                    int ia = pdbasearch_atom(patch->a[m].c_str(), rnr, pdba, bCheckMissing ? "atom" : "check",
-                                             !bCheckMissing, cyclicBondsIndex);
+                    int ia = pdbasearch_atom(patch->a[m].c_str(),
+                                             rnr,
+                                             pdba,
+                                             bCheckMissing ? "atom" : "check",
+                                             !bCheckMissing,
+                                             cyclicBondsIndex);
                     if (ia < 0)
                     {
                         /* not found in original atoms, might still be in
@@ -389,8 +398,10 @@ static void calc_all_pos(const t_atoms*                            pdba,
                                           "Atom %s not found in residue %s %d"
                                           ", rtp entry %s"
                                           " while adding hydrogens",
-                                          patch->a[m].c_str(), *pdba->resinfo[rnr].name,
-                                          pdba->resinfo[rnr].nr, *pdba->resinfo[rnr].rtp);
+                                          patch->a[m].c_str(),
+                                          *pdba->resinfo[rnr].name,
+                                          pdba->resinfo[rnr].nr,
+                                          *pdba->resinfo[rnr].rtp);
                             }
                         }
                     }
@@ -532,7 +543,9 @@ static int add_h_low(t_atoms**                                   initialAtoms,
                     {
                         if (gmx_debug_at)
                         {
-                            fprintf(debug, "Replacing %d '%s' with (old name '%s') %s\n", newi,
+                            fprintf(debug,
+                                    "Replacing %d '%s' with (old name '%s') %s\n",
+                                    newi,
                                     ((*modifiedAtoms)->atomname[newi] && *(*modifiedAtoms)->atomname[newi])
                                             ? *(*modifiedAtoms)->atomname[newi]
                                             : "",
@@ -547,8 +560,11 @@ static int add_h_low(t_atoms**                                   initialAtoms,
                     }
                     if (debug)
                     {
-                        fprintf(debug, " %s %g %g", *(*modifiedAtoms)->atomname[newi],
-                                (*modifiedAtoms)->atom[newi].m, (*modifiedAtoms)->atom[newi].q);
+                        fprintf(debug,
+                                " %s %g %g",
+                                *(*modifiedAtoms)->atomname[newi],
+                                (*modifiedAtoms)->atom[newi].m,
+                                (*modifiedAtoms)->atom[newi].q);
                     }
                 }
             }
@@ -589,8 +605,8 @@ int add_h(t_atoms**                                   initialAtoms,
     do
     {
         nold = nnew;
-        nnew = add_h_low(initialAtoms, localAtoms, xptr, globalPatches, symtab, nterpairs, ntdb,
-                         ctdb, rN, rC, FALSE, cyclicBondsIndex);
+        nnew = add_h_low(
+                initialAtoms, localAtoms, xptr, globalPatches, symtab, nterpairs, ntdb, ctdb, rN, rC, FALSE, cyclicBondsIndex);
         niter++;
         if (niter > 100)
         {
@@ -603,8 +619,7 @@ int add_h(t_atoms**                                   initialAtoms,
     if (!bAllowMissing)
     {
         /* Call add_h_low once more, now only for the missing atoms check */
-        add_h_low(initialAtoms, localAtoms, xptr, globalPatches, symtab, nterpairs, ntdb, ctdb, rN,
-                  rC, TRUE, cyclicBondsIndex);
+        add_h_low(initialAtoms, localAtoms, xptr, globalPatches, symtab, nterpairs, ntdb, ctdb, rN, rC, TRUE, cyclicBondsIndex);
     }
 
     return nnew;
index 487ffa0c8feb23ab488125a7ac2e994cf4cf7d60..049921fb4612a4488db0de1fac947c0c51083d68 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -155,8 +155,11 @@ static void insert_ion(int                      nsa,
         gmx_fatal(FARGS, "No more replaceable solvent!");
     }
 
-    fprintf(stderr, "Replacing solvent molecule %d (atom %d) with %s\n",
-            solventMoleculesForReplacement->back(), solventMoleculeAtomsToBeReplaced[0], ionname);
+    fprintf(stderr,
+            "Replacing solvent molecule %d (atom %d) with %s\n",
+            solventMoleculesForReplacement->back(),
+            solventMoleculeAtomsToBeReplaced[0],
+            ionname);
 
     /* Replace solvent molecule charges with ion charge */
     notSolventGroup->push_back(solventMoleculeAtomsToBeReplaced[0]);
@@ -166,7 +169,8 @@ static void insert_ion(int                      nsa,
     // charge while the rest of the solvent molecule atoms is set to 0 charge.
     atoms->atom[solventMoleculeAtomsToBeReplaced.front()].q = q;
     for (auto replacedMoleculeAtom = solventMoleculeAtomsToBeReplaced.begin() + 1;
-         replacedMoleculeAtom != solventMoleculeAtomsToBeReplaced.end(); ++replacedMoleculeAtom)
+         replacedMoleculeAtom != solventMoleculeAtomsToBeReplaced.end();
+         ++replacedMoleculeAtom)
     {
         atoms->atom[*replacedMoleculeAtom].q = 0;
     }
@@ -350,7 +354,8 @@ static void update_topol(const char* topinout, int p_num, int n_num, const char*
         gmx_ffclose(fpout);
         gmx_fatal(FARGS,
                   "No line with moleculetype '%s' found the [ molecules ] section of file '%s'",
-                  grpname, topinout);
+                  grpname,
+                  topinout);
     }
     if (nsol_last < p_num + n_num)
     {
@@ -358,7 +363,10 @@ static void update_topol(const char* topinout, int p_num, int n_num, const char*
         gmx_fatal(FARGS,
                   "The last entry for moleculetype '%s' in the [ molecules ] section of file '%s' "
                   "has less solvent molecules (%d) than were replaced (%d)",
-                  grpname, topinout, nsol_last, p_num + n_num);
+                  grpname,
+                  topinout,
+                  nsol_last,
+                  p_num + n_num);
     }
 
     /* Print all the molecule entries */
@@ -372,7 +380,12 @@ static void update_topol(const char* topinout, int p_num, int n_num, const char*
         {
             printf("Replacing %d solute molecules in topology file (%s) "
                    " by %d %s and %d %s ions.\n",
-                   p_num + n_num, topinout, p_num, p_name, n_num, n_name);
+                   p_num + n_num,
+                   topinout,
+                   p_num,
+                   p_name,
+                   n_num,
+                   n_name);
             nsol_last -= p_num + n_num;
             if (nsol_last > 0)
             {
@@ -417,8 +430,7 @@ static std::vector<int> invertIndexGroup(int nrAtoms, std::vector<int> indexGrou
         if (numIndicesToAdd > 0)
         {
             invertedGroup.resize(invertedGroup.size() + numIndicesToAdd);
-            std::iota(std::end(invertedGroup) - numIndicesToAdd, std::end(invertedGroup),
-                      firstToAddToInvertedGroup);
+            std::iota(std::end(invertedGroup) - numIndicesToAdd, std::end(invertedGroup), firstToAddToInvertedGroup);
         }
     }
 
@@ -490,8 +502,8 @@ int gmx_genion(int argc, char* argv[])
                        { efTOP, "-p", "topol", ffOPTRW } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc,
-                           asize(bugs), bugs, &oenv))
+    if (!parse_common_args(
+                &argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
         if (oenv != nullptr)
         {
@@ -528,7 +540,7 @@ int gmx_genion(int argc, char* argv[])
     {
         /* Compute number of ions to be added */
         vol   = det(box);
-        nsalt = gmx::roundToInt(conc * vol * AVOGADRO / 1e24);
+        nsalt = gmx::roundToInt(conc * vol * gmx::c_avogadro / 1e24);
         p_num = abs(nsalt * n_q);
         n_num = abs(nsalt * p_q);
     }
@@ -544,7 +556,8 @@ int gmx_genion(int argc, char* argv[])
             gmx_fatal(FARGS,
                       "Can't neutralize this system using -nq %d and"
                       " -pq %d.\n",
-                      n_q, p_q);
+                      n_q,
+                      p_q);
         }
 
         while (qdelta != 0)
@@ -594,7 +607,11 @@ int gmx_genion(int argc, char* argv[])
                 gmx_fatal(FARGS,
                           "The solvent group %s is not continuous: "
                           "index[%d]=%d, index[%d]=%d",
-                          grpname, int(i), solventGroup[i - 1] + 1, int(i + 1), solventGroup[i] + 1);
+                          grpname,
+                          int(i),
+                          solventGroup[i - 1] + 1,
+                          int(i + 1),
+                          solventGroup[i] + 1);
             }
         }
         nsa = 1;
@@ -605,8 +622,10 @@ int gmx_genion(int argc, char* argv[])
         }
         if (solventGroup.size() % nsa != 0)
         {
-            gmx_fatal(FARGS, "Your solvent group size (%td) is not a multiple of %d",
-                      gmx::ssize(solventGroup), nsa);
+            gmx_fatal(FARGS,
+                      "Your solvent group size (%td) is not a multiple of %d",
+                      gmx::ssize(solventGroup),
+                      nsa);
         }
         nw = solventGroup.size() / nsa;
         fprintf(stderr, "Number of (%d-atomic) solvent molecules: %d\n", nsa, nw);
@@ -640,19 +659,19 @@ int gmx_genion(int argc, char* argv[])
         // Randomly shuffle the solvent molecules that shall be replaced by ions
         // then pick molecules from the back of the list as replacement candidates
         gmx::DefaultRandomEngine rng(seed);
-        std::shuffle(std::begin(solventMoleculesForReplacement),
-                     std::end(solventMoleculesForReplacement), rng);
+        std::shuffle(
+                std::begin(solventMoleculesForReplacement), std::end(solventMoleculesForReplacement), rng);
 
         /* Now loop over the ions that have to be placed */
         while (p_num-- > 0)
         {
-            insert_ion(nsa, &solventMoleculesForReplacement, repl, solventGroup, x, &pbc, 1, p_q,
-                       p_name, &atoms, rmin, &notSolventGroup);
+            insert_ion(
+                    nsa, &solventMoleculesForReplacement, repl, solventGroup, x, &pbc, 1, p_q, p_name, &atoms, rmin, &notSolventGroup);
         }
         while (n_num-- > 0)
         {
-            insert_ion(nsa, &solventMoleculesForReplacement, repl, solventGroup, x, &pbc, -1, n_q,
-                       n_name, &atoms, rmin, &notSolventGroup);
+            insert_ion(
+                    nsa, &solventMoleculesForReplacement, repl, solventGroup, x, &pbc, -1, n_q, n_name, &atoms, rmin, &notSolventGroup);
         }
         fprintf(stderr, "\n");
 
index 7c488ab20e62192e7c0d7bc5c5d6baee6274eaa3..8a4c60c746ad5ad91bf14a36ecb7f6a746280059 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +190,7 @@ int gmx_genrestr(int argc, char* argv[])
         fprintf(stderr, "\nReading structure file\n");
         readConfAndTopology(xfn, &haveTopology, &mtop, nullptr, &x, &v, box);
         title = *mtop.name;
-        atoms = gmx_mtop_global_atoms(&mtop);
+        atoms = gmx_mtop_global_atoms(mtop);
         if (atoms.pdbinfo == nullptr)
         {
             snew(atoms.pdbinfo, atoms.nr);
@@ -232,8 +232,17 @@ int gmx_genrestr(int argc, char* argv[])
         {
             fprintf(out, "; distance restraints for %s of %s\n\n", indexGroupNames, title);
             fprintf(out, "[ distance_restraints ]\n");
-            fprintf(out, ";%4s %5s %1s %5s %10s %10s %10s %10s %10s\n", "i", "j", "?", "label",
-                    "funct", "lo", "up1", "up2", "weight");
+            fprintf(out,
+                    ";%4s %5s %1s %5s %10s %10s %10s %10s %10s\n",
+                    "i",
+                    "j",
+                    "?",
+                    "label",
+                    "funct",
+                    "lo",
+                    "up1",
+                    "up2",
+                    "weight");
         }
         for (i = k = 0; i < igrp; i++)
         {
@@ -259,8 +268,17 @@ int gmx_genrestr(int argc, char* argv[])
                         }
                         lo = std::max(0.0_real, d - dd);
                         hi = d + dd;
-                        fprintf(out, "%5d %5d %1d %5d %10d %10g %10g %10g %10g\n", indexGroups[i] + 1,
-                                indexGroups[j] + 1, 1, k, 1, lo, hi, hi + disre_up2, 1.0);
+                        fprintf(out,
+                                "%5d %5d %1d %5d %10d %10g %10g %10g %10g\n",
+                                indexGroups[i] + 1,
+                                indexGroups[j] + 1,
+                                1,
+                                k,
+                                1,
+                                lo,
+                                hi,
+                                hi + disre_up2,
+                                1.0);
                     }
                 }
             }
index c359c7a450851cbabcafe7686df08df1b98075ce..bde57d24434cb7766a6dd52788c9ff27e55acf08 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -477,8 +477,8 @@ static int process_directive(gmx_cpp_t* handlep, const std::string& dname, const
         std::string inc_fn = dval.substr(i0, len);
 
         /* Open include file and store it as a child in the handle structure */
-        int status = cpp_open_file(inc_fn.c_str(), &(handle->child), nullptr, &handle->defines,
-                                   &handle->includes);
+        int status = cpp_open_file(
+                inc_fn.c_str(), &(handle->child), nullptr, &handle->defines, &handle->includes);
         if (status != eCPP_OK)
         {
             handle->child = nullptr;
@@ -751,9 +751,12 @@ char* cpp_error(gmx_cpp_t* handlep, int status)
         status = eCPP_NR;
     }
 
-    sprintf(buf, "%s - File %s, line %d\nLast line read:\n'%s'", ecpp[status],
+    sprintf(buf,
+            "%s - File %s, line %d\nLast line read:\n'%s'",
+            ecpp[status],
             (handle && !handle->fn.empty()) ? handle->fn.c_str() : "unknown",
-            (handle) ? handle->line_nr : -1, !handle->line.empty() ? handle->line.c_str() : "");
+            (handle) ? handle->line_nr : -1,
+            !handle->line.empty() ? handle->line.c_str() : "");
 
     return gmx_strdup(buf);
 }
@@ -767,7 +770,7 @@ std::string checkAndWarnForUnusedDefines(const gmx_cpp& handle)
                 "The following macros were defined in the 'define' mdp field with the -D prefix, "
                 "but "
                 "were not used in the topology:\n";
-        for (auto& str : handle.unmatched_defines)
+        for (const auto& str : handle.unmatched_defines)
         {
             warning += ("    " + str + "\n");
         }
index 46376534a0941c3609fe59e83bfc014311793cd0..429de6bd30245ec78a588539bdcc910f2b0689c4 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2011,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstring>
 
 #include <algorithm>
+#include <optional>
 
 #include "gromacs/gmxpreprocess/grompp_impl.h"
 #include "gromacs/gmxpreprocess/notset.h"
@@ -86,6 +87,8 @@ public:
     size_t size() const { return types.size(); }
     //! The actual atom type data.
     std::vector<AtomTypeData> types;
+    //! Map from \c types[i].name to \c i for quick look-up in \ref atomTypeFromName. Ref #3974.
+    std::unordered_map<std::string, int> nameToAtomType;
 };
 
 bool PreprocessingAtomTypes::isSet(int nt) const
@@ -93,18 +96,19 @@ bool PreprocessingAtomTypes::isSet(int nt) const
     return ((nt >= 0) && (nt < gmx::ssize(*this)));
 }
 
-int PreprocessingAtomTypes::atomTypeFromName(const std::string& str) const
+std::optional<int> PreprocessingAtomTypes::atomTypeFromName(const std::string& str) const
 {
     /* Atom types are always case sensitive */
-    auto found = std::find_if(impl_->types.begin(), impl_->types.end(),
-                              [&str](const auto& type) { return str == *type.name_; });
-    if (found == impl_->types.end())
+    const auto found = impl_->nameToAtomType.find(str);
+    if (found == impl_->nameToAtomType.end())
     {
-        return NOTSET;
+        return std::nullopt;
     }
     else
     {
-        return std::distance(impl_->types.begin(), found);
+        GMX_ASSERT(str == *impl_->types[found->second].name_,
+                   "Invalid data in atomTypeFromName lookup table");
+        return std::make_optional(found->second);
     }
 }
 
@@ -113,48 +117,48 @@ size_t PreprocessingAtomTypes::size() const
     return impl_->size();
 }
 
-const char* PreprocessingAtomTypes::atomNameFromAtomType(int nt) const
+std::optional<const char*> PreprocessingAtomTypes::atomNameFromAtomType(int nt) const
 {
-    return isSet(nt) ? *(impl_->types[nt].name_) : nullptr;
+    return isSet(nt) ? std::make_optional(*(impl_->types[nt].name_)) : std::nullopt;
 }
 
-real PreprocessingAtomTypes::atomMassFromAtomType(int nt) const
+std::optional<real> PreprocessingAtomTypes::atomMassFromAtomType(int nt) const
 {
-    return isSet(nt) ? impl_->types[nt].atom_.m : NOTSET;
+    return isSet(nt) ? std::make_optional(impl_->types[nt].atom_.m) : std::nullopt;
 }
 
-real PreprocessingAtomTypes::atomChargeFromAtomType(int nt) const
+std::optional<real> PreprocessingAtomTypes::atomChargeFromAtomType(int nt) const
 {
-    return isSet(nt) ? impl_->types[nt].atom_.q : NOTSET;
+    return isSet(nt) ? std::make_optional(impl_->types[nt].atom_.q) : std::nullopt;
 }
 
-int PreprocessingAtomTypes::atomParticleTypeFromAtomType(int nt) const
+std::optional<ParticleType> PreprocessingAtomTypes::atomParticleTypeFromAtomType(int nt) const
 {
-    return isSet(nt) ? impl_->types[nt].atom_.ptype : NOTSET;
+    return isSet(nt) ? std::make_optional(impl_->types[nt].atom_.ptype) : std::nullopt;
 }
 
-int PreprocessingAtomTypes::bondAtomTypeFromAtomType(int nt) const
+std::optional<int> PreprocessingAtomTypes::bondAtomTypeFromAtomType(int nt) const
 {
-    return isSet(nt) ? impl_->types[nt].bondAtomType_ : NOTSET;
+    return isSet(nt) ? std::make_optional(impl_->types[nt].bondAtomType_) : std::nullopt;
 }
 
-int PreprocessingAtomTypes::atomNumberFromAtomType(int nt) const
+std::optional<int> PreprocessingAtomTypes::atomNumberFromAtomType(int nt) const
 {
-    return isSet(nt) ? impl_->types[nt].atomNumber_ : NOTSET;
+    return isSet(nt) ? std::make_optional(impl_->types[nt].atomNumber_) : std::nullopt;
 }
 
-real PreprocessingAtomTypes::atomNonBondedParamFromAtomType(int nt, int param) const
+std::optional<real> PreprocessingAtomTypes::atomNonBondedParamFromAtomType(int nt, int param) const
 {
     if (!isSet(nt))
     {
-        return NOTSET;
+        return std::nullopt;
     }
     gmx::ArrayRef<const real> forceParam = impl_->types[nt].nb_.forceParam();
     if ((param < 0) || (param >= MAXFORCEPARAM))
     {
-        return NOTSET;
+        return std::nullopt;
     }
-    return forceParam[param];
+    return std::make_optional(forceParam[param]);
 }
 
 PreprocessingAtomTypes::PreprocessingAtomTypes() : impl_(new Impl) {}
@@ -179,29 +183,31 @@ int PreprocessingAtomTypes::addType(t_symtab*                tab,
                                     int                      bondAtomType,
                                     int                      atomNumber)
 {
-    int position = atomTypeFromName(name);
-    if (position == NOTSET)
+    auto position = atomTypeFromName(name);
+    if (!position.has_value())
     {
         impl_->types.emplace_back(a, put_symtab(tab, name.c_str()), nb, bondAtomType, atomNumber);
-        return atomTypeFromName(name);
+        const int newType           = impl_->types.size() - 1;
+        impl_->nameToAtomType[name] = newType;
+        return newType;
     }
     else
     {
-        return position;
+        return *position;
     }
 }
 
-int PreprocessingAtomTypes::setType(int                      nt,
-                                    t_symtab*                tab,
-                                    const t_atom&            a,
-                                    const std::string&       name,
-                                    const InteractionOfType& nb,
-                                    int                      bondAtomType,
-                                    int                      atomNumber)
+std::optional<int> PreprocessingAtomTypes::setType(int                      nt,
+                                                   t_symtab*                tab,
+                                                   const t_atom&            a,
+                                                   const std::string&       name,
+                                                   const InteractionOfType& nb,
+                                                   int                      bondAtomType,
+                                                   int                      atomNumber)
 {
     if (!isSet(nt))
     {
-        return NOTSET;
+        return std::nullopt;
     }
 
     impl_->types[nt].atom_         = a;
@@ -210,18 +216,30 @@ int PreprocessingAtomTypes::setType(int                      nt,
     impl_->types[nt].bondAtomType_ = bondAtomType;
     impl_->types[nt].atomNumber_   = atomNumber;
 
-    return nt;
+    return std::make_optional(nt);
 }
 
 void PreprocessingAtomTypes::printTypes(FILE* out)
 {
-    fprintf(out, "[ %s ]\n", dir2str(Directive::d_atomtypes));
-    fprintf(out, "; %6s  %8s  %8s  %8s  %12s  %12s\n", "type", "mass", "charge", "particle", "c6",
+    fprintf(out, "[ %s ]\n", enumValueToString(Directive::d_atomtypes));
+    fprintf(out,
+            "; %6s  %8s  %8s  %8s  %12s  %12s\n",
+            "type",
+            "mass",
+            "charge",
+            "particle",
+            "c6",
             "c12");
     for (auto& entry : impl_->types)
     {
-        fprintf(out, "%8s  %8.3f  %8.3f  %8s  %12e  %12e\n", *(entry.name_), entry.atom_.m,
-                entry.atom_.q, "A", entry.nb_.c0(), entry.nb_.c1());
+        fprintf(out,
+                "%8s  %8.3f  %8.3f  %8s  %12e  %12e\n",
+                *(entry.name_),
+                entry.atom_.m,
+                entry.atom_.q,
+                "A",
+                entry.nb_.c0(),
+                entry.nb_.c1());
     }
 
     fprintf(out, "\n");
@@ -263,7 +281,8 @@ static int search_atomtypes(const PreprocessingAtomTypes*          ga,
 
             /* Check atomnumber */
             int tli = typelist[i];
-            bFound = bFound && (ga->atomNumberFromAtomType(tli) == ga->atomNumberFromAtomType(thistype));
+            bFound  = bFound
+                     && (*ga->atomNumberFromAtomType(tli) == *ga->atomNumberFromAtomType(thistype));
         }
         if (bFound)
         {
@@ -328,10 +347,10 @@ void PreprocessingAtomTypes::renumberTypes(gmx::ArrayRef<InteractionsOfType> pli
         const t_atoms* atoms = &moltype.atoms;
         for (int i = 0; (i < atoms->nr); i++)
         {
-            atoms->atom[i].type  = search_atomtypes(this, &nat, typelist, atoms->atom[i].type,
-                                                   plist[ftype].interactionTypes, ftype);
-            atoms->atom[i].typeB = search_atomtypes(this, &nat, typelist, atoms->atom[i].typeB,
-                                                    plist[ftype].interactionTypes, ftype);
+            atoms->atom[i].type = search_atomtypes(
+                    this, &nat, typelist, atoms->atom[i].type, plist[ftype].interactionTypes, ftype);
+            atoms->atom[i].typeB = search_atomtypes(
+                    this, &nat, typelist, atoms->atom[i].typeB, plist[ftype].interactionTypes, ftype);
         }
     }
 
@@ -339,8 +358,8 @@ void PreprocessingAtomTypes::renumberTypes(gmx::ArrayRef<InteractionsOfType> pli
     {
         if (wall_atomtype[i] >= 0)
         {
-            wall_atomtype[i] = search_atomtypes(this, &nat, typelist, wall_atomtype[i],
-                                                plist[ftype].interactionTypes, ftype);
+            wall_atomtype[i] = search_atomtypes(
+                    this, &nat, typelist, wall_atomtype[i], plist[ftype].interactionTypes, ftype);
         }
     }
 
@@ -350,6 +369,9 @@ void PreprocessingAtomTypes::renumberTypes(gmx::ArrayRef<InteractionsOfType> pli
     /* Renumber nlist */
     std::vector<InteractionOfType> nbsnew;
 
+    // Reset the map used for fast lookups, and refill it below
+    impl_->nameToAtomType.clear();
+
     for (int i = 0; (i < nat); i++)
     {
         int mi = typelist[i];
@@ -357,10 +379,12 @@ void PreprocessingAtomTypes::renumberTypes(gmx::ArrayRef<InteractionsOfType> pli
         {
             int                      mj              = typelist[j];
             const InteractionOfType& interactionType = plist[ftype].interactionTypes[ntype * mi + mj];
-            nbsnew.emplace_back(interactionType.atoms(), interactionType.forceParam(),
+            nbsnew.emplace_back(interactionType.atoms(),
+                                interactionType.forceParam(),
                                 interactionType.interactionTypeName());
         }
         new_types.push_back(impl_->types[mi]);
+        impl_->nameToAtomType[std::string(*impl_->types[mi].name_)] = new_types.size() - 1;
     }
 
     mtop->ffparams.atnr = nat;
index 8b6c7f08de3f3b1cce52c871fd2a102846b56b2c..6d28b0c456ed7b91aced5872cfc42dd0ab1518db 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,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2011,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <memory>
+#include <optional>
 #include <string>
 
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/real.h"
 
 struct gmx_mtop_t;
@@ -59,7 +60,7 @@ struct t_atomtypes;
 class InteractionOfType;
 struct InteractionsOfType;
 struct t_symtab;
-
+enum class ParticleType : int;
 namespace gmx
 {
 template<typename>
@@ -82,16 +83,16 @@ public:
     ~PreprocessingAtomTypes();
 
     /*! \brief
-     *  Get atom type index for atom type name if present in the database, or NOTSET.
+     *  Get atom type index for atom type name if present in the database, or empty optional.
      *
      *  \todo The code should be changed to instead use a gmx::compat version
      *  of std::optional to return an iterator to the element being searched,
      *  or an empty optional construct if the entry has not been found.
      *
      *  \param[in] str Input string to search type for.
-     *  \returns Atomtype as integer.
+     *  \returns Optional atomtype as integer.
      */
-    int atomTypeFromName(const std::string& str) const;
+    std::optional<int> atomTypeFromName(const std::string& str) const;
 
     //! Get number of defined atom types.
     size_t size() const;
@@ -100,58 +101,58 @@ public:
      * Get name of atom from internal atom type number.
      *
      * \param[in] nt Internal number of atom type.
-     * \returns The type name.
+     * \returns The optional type name.
      */
-    const char* atomNameFromAtomType(int nt) const;
+    std::optional<const char*> atomNameFromAtomType(int nt) const;
 
     /*! \brief
      * Get normal mass of atom from internal atom type number.
      *
      * \param[in] nt Internal number of atom type.
-     * \returns The mass for the atom or NOTSET.
+     * \returns The optional mass for the atom.
      */
-    real atomMassFromAtomType(int nt) const;
+    std::optional<real> atomMassFromAtomType(int nt) const;
 
     /*! \brief
      * Get normal charge of atom from internal atom type number.
      *
      * \param[in] nt Internal number of atom type.
-     * \returns The charge for the atom or NOTSET.
+     * \returns The optional charge for the atom.
      */
-    real atomChargeFromAtomType(int nt) const;
+    std::optional<real> atomChargeFromAtomType(int nt) const;
 
     /*! \brief
      * Get particle type for atom type \p nt
      *
      * \param[in] nt Internal number of atom type.
-     * \returns The particle type or NOTSET.
+     * \returns The optional particle type.
      */
-    int atomParticleTypeFromAtomType(int nt) const;
+    std::optional<ParticleType> atomParticleTypeFromAtomType(int nt) const;
 
     /*! \brief
      * Get bond atom parameter of atom from internal atom type number.
      *
      * \param[in] nt Internal number of atom type.
-     * \returns The bond atom parameter or NOTSET.
+     * \returns The optional bond atom parameter.
      */
-    int bondAtomTypeFromAtomType(int nt) const;
+    std::optional<int> bondAtomTypeFromAtomType(int nt) const;
 
     /*! \brief
      * Get atomic number of atom from internal atom type number.
      *
      * \param[in] nt Internal number of atom type.
-     * \returns The atomic number type or NOTSET.
+     * \returns The optional atomic number type.
      */
-    int atomNumberFromAtomType(int nt) const;
+    std::optional<int> atomNumberFromAtomType(int nt) const;
 
     /*! \brief
      * Get the value of \p param of type \p nt.
      *
      * \param[in] param The parameter value to find.
      * \param[in] nt The number of the type.
-     * \returns The value of the parameter or NOTSET.
+     * \returns The optional value of the parameter.
      */
-    real atomNonBondedParamFromAtomType(int nt, int param) const;
+    std::optional<real> atomNonBondedParamFromAtomType(int nt, int param) const;
 
     /*! \brief
      * If a value is within the range of the current types or not.
@@ -178,18 +179,18 @@ public:
      * \param[in] nb Nonbonded parameters.
      * \param[in] bondAtomType What kind of bonded interactions are there.
      * \param[in] atomNumber Atomic number of the entry.
-     * \returns Number of the type set or NOTSET
+     * \returns Optional number of the type set.
      */
-    int setType(int                      nt,
-                t_symtab*                tab,
-                const t_atom&            a,
-                const std::string&       name,
-                const InteractionOfType& nb,
-                int                      bondAtomType,
-                int                      atomNumber);
+    std::optional<int> setType(int                      nt,
+                               t_symtab*                tab,
+                               const t_atom&            a,
+                               const std::string&       name,
+                               const InteractionOfType& nb,
+                               int                      bondAtomType,
+                               int                      atomNumber);
 
     /*! \brief
-     * Add new atom type to database.
+     * Add a unique type to the database.
      *
      * \param[in] tab Symbol table.
      * \param[in] a Atom information.
@@ -197,7 +198,8 @@ public:
      * \param[in] nb Nonbonded parameters.
      * \param[in] bondAtomType What kind of bonded interactions are there.
      * \param[in] atomNumber Atomic number of the entry.
-     * \returns Number of entries in database.
+     * \returns Index to the type in the database. If the type shares
+     *          a name with an existing type, return the index of that type.
      */
     int addType(t_symtab*                tab,
                 const t_atom&            a,
@@ -226,7 +228,7 @@ public:
 private:
     class Impl;
     //! Pimpl that holds the data.
-    gmx::PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 #endif
index 395bf76067b574131085025d86cf6ffc7cbb6f8b..c81d0ec11c4f562a936d63feb5cda5816afae1ff 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2011,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstring>
 
 #include <algorithm>
+#include <optional>
 #include <vector>
 
 #include "gromacs/gmxpreprocess/notset.h"
 #include "gromacs/topology/symtab.h"
-#include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/smalloc.h"
 
 class PreprocessingBondAtomType::Impl
@@ -56,25 +56,25 @@ public:
     std::vector<char**> typeNames;
 };
 
-int PreprocessingBondAtomType::bondAtomTypeFromName(const std::string& str) const
+std::optional<int> PreprocessingBondAtomType::bondAtomTypeFromName(const std::string& str) const
 {
     /* Atom types are always case sensitive */
-    auto found =
-            std::find_if(impl_->typeNames.begin(), impl_->typeNames.end(),
-                         [&str](const auto& type) { return str == const_cast<const char*>(*type); });
+    auto found = std::find_if(impl_->typeNames.begin(),
+                              impl_->typeNames.end(),
+                              [&str](const auto& type) { return str == std::string(*type); });
     if (found == impl_->typeNames.end())
     {
-        return NOTSET;
+        return std::nullopt;
     }
     else
     {
-        return std::distance(impl_->typeNames.begin(), found);
+        return std::make_optional(std::distance(impl_->typeNames.begin(), found));
     }
 }
 
-const char* PreprocessingBondAtomType::atomNameFromBondAtomType(int nt) const
+std::optional<const char*> PreprocessingBondAtomType::atomNameFromBondAtomType(int nt) const
 {
-    return isSet(nt) ? *impl_->typeNames[nt] : nullptr;
+    return isSet(nt) ? *impl_->typeNames[nt] : std::optional<const char*>{};
 }
 
 PreprocessingBondAtomType::PreprocessingBondAtomType() : impl_(new Impl) {}
@@ -83,15 +83,23 @@ PreprocessingBondAtomType::~PreprocessingBondAtomType() {}
 
 int PreprocessingBondAtomType::addBondAtomType(t_symtab* tab, const std::string& name)
 {
-    int position = bondAtomTypeFromName(name);
-    if (position == NOTSET)
+    auto position = bondAtomTypeFromName(name);
+    if (!position.has_value())
     {
         impl_->typeNames.emplace_back(put_symtab(tab, name.c_str()));
-        return bondAtomTypeFromName(name);
+        if (auto bondAtomType = bondAtomTypeFromName(name); bondAtomType.has_value())
+        {
+            return *bondAtomType;
+        }
+        else
+        {
+            GMX_RELEASE_ASSERT(false, "Unhandled error in adding bond atom type");
+            return 0;
+        }
     }
     else
     {
-        return position;
+        return *position;
     }
 }
 
index 3c1220dc425ecca2f9cd8b1f87641e8d3b02141f..7226e30b94d694f90614464c441f0cb4bfb802c8 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,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2011,2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <memory>
+#include <optional>
 #include <string>
 
-#include "gromacs/utility/classhelpers.h"
-
 struct t_symtab;
 
 /*! \libinternal \brief
@@ -70,9 +70,9 @@ public:
      * Get name of atom from internal bond atom type number.
      *
      * \param[in] nt Internal number of atom type.
-     * \returns The type name.
+     * \returns The optional type name.
      */
-    const char* atomNameFromBondAtomType(int nt) const;
+    std::optional<const char*> atomNameFromBondAtomType(int nt) const;
 
     /*! \brief
      *  Get bond atom type index for atom type name if present in the database, or NOTSET.
@@ -82,16 +82,17 @@ public:
      *  or an empty optional construct if the entry has not been found.
      *
      *  \param[in] str Input string to search type for.
-     *  \returns Atomtype as integer.
+     *  \returns Optional atomtype as integer.
      */
-    int bondAtomTypeFromName(const std::string& str) const;
+    std::optional<int> bondAtomTypeFromName(const std::string& str) const;
 
     /*! \brief
-     * Add a complete new bond atom type.
+     * Add a unique type to the database.
      *
      * \param[in] tab Symbol table.
      * \param[in] name Atom name.
-     * \returns The number of entries in database or the type number of an already set type.
+     * \returns Index to the type in the database. If the type shares
+     *          a name with an existing type, return the index of that type.
      */
     int addBondAtomType(t_symtab* tab, const std::string& name);
 
@@ -106,7 +107,7 @@ public:
 private:
     class Impl;
     //! Pimpl that holds the data.
-    gmx::PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 #endif
index 9c4fc7f255b27b597c5884446540cabf8e4f5251..63f93ae8db332692d91f8316fa314d7d56696a69 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "grompp.h"
 
+#include <array>
 #include <cerrno>
 #include <climits>
 #include <cmath>
@@ -79,6 +80,7 @@
 #include "gromacs/mdlib/calc_verletbuf.h"
 #include "gromacs/mdlib/compute_io.h"
 #include "gromacs/mdlib/constr.h"
+#include "gromacs/mdlib/md_support.h"
 #include "gromacs/mdlib/perf_est.h"
 #include "gromacs/mdlib/vsite.h"
 #include "gromacs/mdrun/mdmodules.h"
 #include "gromacs/utility/listoflists.h"
 #include "gromacs/utility/logger.h"
 #include "gromacs/utility/loggerbuilder.h"
-#include "gromacs/utility/mdmodulenotification.h"
+#include "gromacs/utility/mdmodulesnotifiers.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/snprintf.h"
 
 InteractionOfType::InteractionOfType(gmx::ArrayRef<const int>  atoms,
                                      gmx::ArrayRef<const real> params,
                                      const std::string&        name) :
-    atoms_(atoms.begin(), atoms.end()),
-    interactionTypeName_(name)
+    atoms_(atoms.begin(), atoms.end()), interactionTypeName_(name)
 {
     GMX_RELEASE_ASSERT(
             params.size() <= forceParam_.size(),
             gmx::formatString("Cannot have more parameters than the maximum number possible (%d)", MAXFORCEPARAM)
                     .c_str());
-    auto forceParamIt = forceParam_.begin();
+    std::array<real, MAXFORCEPARAM>::iterator forceParamIt = forceParam_.begin();
     for (const auto param : params)
     {
         *forceParamIt++ = param;
@@ -297,8 +298,12 @@ static int check_atom_names(const char*          fn1,
                         GMX_LOG(logger.warning)
                                 .asParagraph()
                                 .appendTextFormatted(
-                                        "atom name %d in %s and %s does not match (%s - %s)", i + 1,
-                                        fn1, fn2, *(tat->atomname[j]), *(at->atomname[i]));
+                                        "atom name %d in %s and %s does not match (%s - %s)",
+                                        i + 1,
+                                        fn1,
+                                        fn2,
+                                        *(tat->atomname[j]),
+                                        *(at->atomname[i]));
                     }
                     else if (nmismatch == c_maxNumberOfMismatches)
                     {
@@ -436,9 +441,14 @@ static void check_bonds_timestep(const gmx_mtop_t* mtop, double dt, warninp* wi)
                 "oscillational period of %.1e ps, which is less than %d times the time step of "
                 "%.1e ps.\n"
                 "%s",
-                *w_moltype->name, w_a1 + 1, *w_moltype->atoms.atomname[w_a1], w_a2 + 1,
-                *w_moltype->atoms.atomname[w_a2], std::sqrt(w_period2),
-                bWarn ? min_steps_warn : min_steps_note, dt,
+                *w_moltype->name,
+                w_a1 + 1,
+                *w_moltype->atoms.atomname[w_a1],
+                w_a2 + 1,
+                *w_moltype->atoms.atomname[w_a2],
+                std::sqrt(w_period2),
+                bWarn ? min_steps_warn : min_steps_note,
+                dt,
                 bWater ? "Maybe you asked for fexible water."
                        : "Maybe you forgot to change the constraints mdp option.");
         if (bWarn)
@@ -458,7 +468,8 @@ static void check_vel(gmx_mtop_t* mtop, rvec v[])
     {
         const t_atom& local = atomP.atom();
         int           i     = atomP.globalAtomNumber();
-        if (local.ptype == eptShell || local.ptype == eptBond || local.ptype == eptVSite)
+        if (local.ptype == ParticleType::Shell || local.ptype == ParticleType::Bond
+            || local.ptype == ParticleType::VSite)
         {
             clear_rvec(v[i]);
         }
@@ -472,7 +483,7 @@ static void check_shells_inputrec(gmx_mtop_t* mtop, t_inputrec* ir, warninp* wi)
     for (const AtomProxy atomP : AtomRange(*mtop))
     {
         const t_atom& local = atomP.atom();
-        if (local.ptype == eptShell || local.ptype == eptBond)
+        if (local.ptype == ParticleType::Shell || local.ptype == ParticleType::Bond)
         {
             nshells++;
         }
@@ -576,7 +587,7 @@ static void new_status(const char*                           topfile,
                        std::vector<MoleculeInformation>*     mi,
                        std::unique_ptr<MoleculeInformation>* intermolecular_interactions,
                        gmx::ArrayRef<InteractionsOfType>     interactions,
-                       int*                                  comb,
+                       CombinationRule*                      comb,
                        double*                               reppow,
                        real*                                 fudgeQQ,
                        gmx_bool                              bMorse,
@@ -588,9 +599,24 @@ static void new_status(const char*                           topfile,
     bool                        ffParametrizedWithHBondConstraints;
 
     /* TOPOLOGY processing */
-    sys->name = do_top(bVerbose, topfile, topppfile, opts, bZero, &(sys->symtab), interactions,
-                       comb, reppow, fudgeQQ, atypes, mi, intermolecular_interactions, ir,
-                       &molblock, &ffParametrizedWithHBondConstraints, wi, logger);
+    sys->name = do_top(bVerbose,
+                       topfile,
+                       topppfile,
+                       opts,
+                       bZero,
+                       &(sys->symtab),
+                       interactions,
+                       comb,
+                       reppow,
+                       fudgeQQ,
+                       atypes,
+                       mi,
+                       intermolecular_interactions,
+                       ir,
+                       &molblock,
+                       &ffParametrizedWithHBondConstraints,
+                       wi,
+                       logger);
 
     sys->molblock.clear();
 
@@ -621,7 +647,7 @@ static void new_status(const char*                           topfile,
         convert_harmonics(*mi, atypes);
     }
 
-    if (ir->eDisre == edrNone)
+    if (ir->eDisre == DistanceRestraintRefinement::None)
     {
         i = rm_interactions(F_DISRES, *mi);
         if (i > 0)
@@ -654,7 +680,7 @@ static void new_status(const char*                           topfile,
      * constraints only. Do not print note with large timesteps or vsites.
      */
     if (opts->nshake == eshALLBONDS && ffParametrizedWithHBondConstraints && ir->delta_t < 0.0026
-        && gmx_mtop_ftype_count(sys, F_VSITE3FD) == 0)
+        && gmx_mtop_ftype_count(*sys, F_VSITE3FD) == 0)
     {
         set_warning_line(wi, "unknown", -1);
         warning_note(wi,
@@ -681,15 +707,18 @@ static void new_status(const char*                           topfile,
         gmx_fatal(FARGS,
                   "number of coordinates in coordinate file (%s, %d)\n"
                   "             does not match topology (%s, %d)",
-                  confin, state->natoms, topfile, sys->natoms);
+                  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->flags |= enumValueToBitMask(StateEntry::X);
     if (v != nullptr)
     {
-        state->flags |= (1 << estV);
+        state->flags |= enumValueToBitMask(StateEntry::V);
     }
     state_change_natoms(state, state->natoms);
     std::copy(x, x + state->natoms, state->x.data());
@@ -712,7 +741,10 @@ static void new_status(const char*                           topfile,
                 "%d non-matching atom name%s\n"
                 "atom names from %s will be used\n"
                 "atom names from %s will be ignored\n",
-                nmismatch, (nmismatch == 1) ? "" : "s", topfile, confin);
+                nmismatch,
+                (nmismatch == 1) ? "" : "s",
+                topfile,
+                confin);
         warning(wi, warningMessage.c_str());
     }
 
@@ -747,7 +779,7 @@ static void new_status(const char*                           topfile,
             opts->seed = static_cast<int>(gmx::makeRandomSeed());
             GMX_LOG(logger.info).asParagraph().appendTextFormatted("Setting gen_seed to %d", opts->seed);
         }
-        state->flags |= (1 << estV);
+        state->flags |= enumValueToBitMask(StateEntry::V);
         maxwell_speed(opts->tempi, opts->seed, sys, state->v.rvec_array(), logger);
 
         stop_cm(logger, state->natoms, mass, state->x.rvec_array(), state->v.rvec_array());
@@ -876,7 +908,7 @@ static void cont_status(const char*             slog,
     GMX_LOG(logger.info).asParagraph().appendTextFormatted("Using frame at t = %g ps", use_time);
     GMX_LOG(logger.info).asParagraph().appendTextFormatted("Starting time for run is %g ps", ir->init_t);
 
-    if ((ir->epc != epcNO || ir->etc == etcNOSEHOOVER) && ener)
+    if ((ir->epc != PressureCoupling::No || ir->etc == TemperatureCoupling::NoseHoover) && ener)
     {
         get_enx_state(ener, use_time, sys->groups, ir, state);
         preserve_box_shape(ir, state->box_rel, state->boxv);
@@ -887,7 +919,7 @@ static void read_posres(gmx_mtop_t*                              mtop,
                         gmx::ArrayRef<const MoleculeInformation> molinfo,
                         gmx_bool                                 bTopB,
                         const char*                              fn,
-                        int                                      rc_scaling,
+                        RefCoordScaling                          rc_scaling,
                         PbcType                                  pbcType,
                         rvec                                     com,
                         warninp*                                 wi,
@@ -913,14 +945,18 @@ static void read_posres(gmx_mtop_t*                              mtop,
         std::string warningMessage = gmx::formatString(
                 "The number of atoms in %s (%d) does not match the number of atoms in the topology "
                 "(%d). Will assume that the first %d atoms in the topology and %s match.",
-                fn, natoms, mtop->natoms, std::min(mtop->natoms, natoms), fn);
+                fn,
+                natoms,
+                mtop->natoms,
+                std::min(mtop->natoms, natoms),
+                fn);
         warning(wi, warningMessage.c_str());
     }
 
     npbcdim = numPbcDimensions(pbcType);
     GMX_RELEASE_ASSERT(npbcdim <= DIM, "Invalid npbcdim");
     clear_rvec(com);
-    if (rc_scaling != erscNO)
+    if (rc_scaling != RefCoordScaling::No)
     {
         copy_mat(box, invbox);
         for (int j = npbcdim; j < DIM; j++)
@@ -952,10 +988,13 @@ static void read_posres(gmx_mtop_t*                              mtop,
                     gmx_fatal(FARGS,
                               "Position restraint atom index (%d) in moltype '%s' is larger than "
                               "number of atoms in %s (%d).\n",
-                              ai + 1, *molinfo[molb.type].name, fn, natoms);
+                              ai + 1,
+                              *molinfo[molb.type].name,
+                              fn,
+                              natoms);
                 }
                 hadAtom[ai] = TRUE;
-                if (rc_scaling == erscCOM)
+                if (rc_scaling == RefCoordScaling::Com)
                 {
                     /* Determine the center of mass of the posres reference coordinates */
                     for (int j = 0; j < npbcdim; j++)
@@ -974,9 +1013,12 @@ static void read_posres(gmx_mtop_t*                              mtop,
                     gmx_fatal(FARGS,
                               "Position restraint atom index (%d) in moltype '%s' is larger than "
                               "number of atoms in %s (%d).\n",
-                              ai + 1, *molinfo[molb.type].name, fn, natoms);
+                              ai + 1,
+                              *molinfo[molb.type].name,
+                              fn,
+                              natoms);
                 }
-                if (rc_scaling == erscCOM && !hadAtom[ai])
+                if (rc_scaling == RefCoordScaling::Com && !hadAtom[ai])
                 {
                     /* Determine the center of mass of the posres reference coordinates */
                     for (int j = 0; j < npbcdim; j++)
@@ -1005,7 +1047,7 @@ static void read_posres(gmx_mtop_t*                              mtop,
         }
         a += nat_molb;
     }
-    if (rc_scaling == erscCOM)
+    if (rc_scaling == RefCoordScaling::Com)
     {
         if (totmass == 0)
         {
@@ -1019,10 +1061,12 @@ static void read_posres(gmx_mtop_t*                              mtop,
                 .asParagraph()
                 .appendTextFormatted(
                         "The center of mass of the position restraint coord's is %6.3f %6.3f %6.3f",
-                        com[XX], com[YY], com[ZZ]);
+                        com[XX],
+                        com[YY],
+                        com[ZZ]);
     }
 
-    if (rc_scaling != erscNO)
+    if (rc_scaling != RefCoordScaling::No)
     {
         GMX_ASSERT(npbcdim <= DIM, "Only DIM dimensions can have PBC");
 
@@ -1036,7 +1080,7 @@ static void read_posres(gmx_mtop_t*                              mtop,
                 {
                     for (int j = 0; j < npbcdim; j++)
                     {
-                        if (rc_scaling == erscALL)
+                        if (rc_scaling == RefCoordScaling::All)
                         {
                             /* Convert from Cartesian to crystal coordinates */
                             xp[i][j] *= invbox[j][j];
@@ -1045,7 +1089,7 @@ static void read_posres(gmx_mtop_t*                              mtop,
                                 xp[i][j] += invbox[k][j] * xp[i][k];
                             }
                         }
-                        else if (rc_scaling == erscCOM)
+                        else if (rc_scaling == RefCoordScaling::Com)
                         {
                             /* Subtract the center of mass */
                             xp[i][j] -= com[j];
@@ -1055,7 +1099,7 @@ static void read_posres(gmx_mtop_t*                              mtop,
             }
         }
 
-        if (rc_scaling == erscCOM)
+        if (rc_scaling == RefCoordScaling::Com)
         {
             /* Convert the COM from Cartesian to crystal coordinates */
             for (int j = 0; j < npbcdim; j++)
@@ -1078,7 +1122,7 @@ static void gen_posres(gmx_mtop_t*                              mtop,
                        gmx::ArrayRef<const MoleculeInformation> mi,
                        const char*                              fnA,
                        const char*                              fnB,
-                       int                                      rc_scaling,
+                       RefCoordScaling                          rc_scaling,
                        PbcType                                  pbcType,
                        rvec                                     com,
                        rvec                                     comB,
@@ -1106,13 +1150,17 @@ static void set_wall_atomtype(PreprocessingAtomTypes* at,
     }
     for (i = 0; i < ir->nwall; i++)
     {
-        ir->wall_atomtype[i] = at->atomTypeFromName(opts->wall_atomtype[i]);
-        if (ir->wall_atomtype[i] == NOTSET)
+        auto atomType = at->atomTypeFromName(opts->wall_atomtype[i]);
+        if (!atomType.has_value())
         {
             std::string warningMessage = gmx::formatString(
                     "Specified wall atom type %s is not defined", opts->wall_atomtype[i]);
             warning_error(wi, warningMessage.c_str());
         }
+        else
+        {
+            ir->wall_atomtype[i] = *atomType;
+        }
     }
 }
 
@@ -1124,7 +1172,8 @@ static int nrdf_internal(const t_atoms* atoms)
     for (i = 0; i < atoms->nr; i++)
     {
         /* Vsite ptype might not be set here yet, so also check the mass */
-        if ((atoms->atom[i].ptype == eptAtom || atoms->atom[i].ptype == eptNucleus) && atoms->atom[i].m > 0)
+        if ((atoms->atom[i].ptype == ParticleType::Atom || atoms->atom[i].ptype == ParticleType::Nucleus)
+            && atoms->atom[i].m > 0)
         {
             nmass++;
         }
@@ -1221,7 +1270,10 @@ static void setup_cmap(int grid_spacing, int nc, gmx::ArrayRef<const real> grid,
 
         for (i = 0; i < 2 * grid_spacing; i++)
         {
-            spline1d(dx, &(tmp_grid[2 * grid_spacing * i]), 2 * grid_spacing, tmp_u.data(),
+            spline1d(dx,
+                     &(tmp_grid[2 * grid_spacing * i]),
+                     2 * grid_spacing,
+                     tmp_u.data(),
                      &(tmp_t2[2 * grid_spacing * i]));
         }
 
@@ -1237,8 +1289,13 @@ static void setup_cmap(int grid_spacing, int nc, gmx::ArrayRef<const real> grid,
 
                 for (k = 0; k < 2 * grid_spacing; k++)
                 {
-                    interpolate1d(xmin, dx, &(tmp_grid[2 * grid_spacing * k]),
-                                  &(tmp_t2[2 * grid_spacing * k]), psi, &tmp_yy[k], &tmp_y1[k]);
+                    interpolate1d(xmin,
+                                  dx,
+                                  &(tmp_grid[2 * grid_spacing * k]),
+                                  &(tmp_t2[2 * grid_spacing * k]),
+                                  psi,
+                                  &tmp_yy[k],
+                                  &tmp_y1[k]);
                 }
 
                 spline1d(dx, tmp_yy.data(), 2 * grid_spacing, tmp_u.data(), tmp_u2.data());
@@ -1300,7 +1357,9 @@ static int count_constraints(const gmx_mtop_t* mtop, gmx::ArrayRef<const Molecul
                     "Molecule type '%s' has %d constraints.\n"
                     "For stability and efficiency there should not be more constraints than "
                     "internal number of degrees of freedom: %d.\n",
-                    *mi[molb.type].name, count_mol, nrdf_internal(&mi[molb.type].atoms));
+                    *mi[molb.type].name,
+                    count_mol,
+                    nrdf_internal(&mi[molb.type].atoms));
             warning(wi, warningMessage.c_str());
         }
         count += molb.nmol * count_mol;
@@ -1325,7 +1384,7 @@ static real calc_temp(const gmx_mtop_t* mtop, const t_inputrec* ir, rvec* v)
         nrdf += ir->opts.nrdf[g];
     }
 
-    return sum_mv2 / (nrdf * BOLTZ);
+    return sum_mv2 / (nrdf * gmx::c_boltz);
 }
 
 static real get_max_reference_temp(const t_inputrec* ir, warninp* wi)
@@ -1397,7 +1456,7 @@ static void checkForUnboundAtoms(const gmx_moltype_t* molt, gmx_bool bVerbose, w
     int numDanglingAtoms = 0;
     for (int a = 0; a < atoms->nr; a++)
     {
-        if (atoms->atom[a].ptype != eptVSite && count[a] == 0)
+        if (atoms->atom[a].ptype != ParticleType::VSite && count[a] == 0)
         {
             if (bVerbose)
             {
@@ -1406,7 +1465,9 @@ static void checkForUnboundAtoms(const gmx_moltype_t* molt, gmx_bool bVerbose, w
                         .appendTextFormatted(
                                 "Atom %d '%s' in moleculetype '%s' is not bound by a potential or "
                                 "constraint to any other atom in the same moleculetype.",
-                                a + 1, *atoms->atomname[a], *molt->name);
+                                a + 1,
+                                *atoms->atomname[a],
+                                *molt->name);
             }
             numDanglingAtoms++;
         }
@@ -1420,7 +1481,8 @@ static void checkForUnboundAtoms(const gmx_moltype_t* molt, gmx_bool bVerbose, w
                 "issues in a simulation, this often means that the user forgot to add a "
                 "bond/potential/constraint or put multiple molecules in the same moleculetype "
                 "definition by mistake. Run with -v to get information for each atom.",
-                *molt->name, numDanglingAtoms);
+                *molt->name,
+                numDanglingAtoms);
         warning_note(wi, warningMessage.c_str());
     }
 }
@@ -1549,11 +1611,12 @@ static void checkDecoupledModeAccuracy(const gmx_mtop_t* mtop, const t_inputrec*
     const int  lincsOrderThreshold      = 4;
     const real shakeToleranceThreshold  = 0.005 * ir->delta_t;
 
-    bool lincsWithSufficientTolerance = (ir->eConstrAlg == econtLINCS && ir->nLincsIter >= lincsIterationThreshold
-                                         && ir->nProjOrder >= lincsOrderThreshold);
-    bool shakeWithSufficientTolerance =
-            (ir->eConstrAlg == econtSHAKE && ir->shake_tol <= 1.1 * shakeToleranceThreshold);
-    if (ir->cutoff_scheme == ecutsVERLET && ir->verletbuf_tol <= 1.1 * bufferToleranceThreshold
+    bool lincsWithSufficientTolerance =
+            (ir->eConstrAlg == ConstraintAlgorithm::Lincs
+             && ir->nLincsIter >= lincsIterationThreshold && ir->nProjOrder >= lincsOrderThreshold);
+    bool shakeWithSufficientTolerance = (ir->eConstrAlg == ConstraintAlgorithm::Shake
+                                         && ir->shake_tol <= 1.1 * shakeToleranceThreshold);
+    if (ir->cutoff_scheme == CutoffScheme::Verlet && ir->verletbuf_tol <= 1.1 * bufferToleranceThreshold
         && (lincsWithSufficientTolerance || shakeWithSufficientTolerance))
     {
         return;
@@ -1575,7 +1638,7 @@ static void checkDecoupledModeAccuracy(const gmx_mtop_t* mtop, const t_inputrec*
                 "and with masses that differ by more than a factor of %g. This means "
                 "that there are likely dynamic modes that are only very weakly coupled.",
                 massFactorThreshold);
-        if (ir->cutoff_scheme == ecutsVERLET)
+        if (ir->cutoff_scheme == CutoffScheme::Verlet)
         {
             message += gmx::formatString(
                     " To ensure good equipartitioning, you need to either not use "
@@ -1583,8 +1646,11 @@ static void checkDecoupledModeAccuracy(const gmx_mtop_t* mtop, const t_inputrec*
                     "hydrogens) or use integrator = %s or decrease one or more tolerances: "
                     "verlet-buffer-tolerance <= %g, LINCS iterations >= %d, LINCS order "
                     ">= %d or SHAKE tolerance <= %g",
-                    ei_names[eiSD1], bufferToleranceThreshold, lincsIterationThreshold,
-                    lincsOrderThreshold, shakeToleranceThreshold);
+                    enumValueToString(IntegrationAlgorithm::SD1),
+                    bufferToleranceThreshold,
+                    lincsIterationThreshold,
+                    lincsOrderThreshold,
+                    shakeToleranceThreshold);
         }
         else
         {
@@ -1592,7 +1658,7 @@ static void checkDecoupledModeAccuracy(const gmx_mtop_t* mtop, const t_inputrec*
                     " To ensure good equipartitioning, we suggest to switch to the %s "
                     "cutoff-scheme, since that allows for better control over the Verlet "
                     "buffer size and thus over the energy drift.",
-                    ecutscheme_names[ecutsVERLET]);
+                    enumValueToString(CutoffScheme::Verlet));
         }
         warning(wi, message);
     }
@@ -1609,19 +1675,20 @@ static void set_verlet_buffer(const gmx_mtop_t*    mtop,
             .asParagraph()
             .appendTextFormatted(
                     "Determining Verlet buffer for a tolerance of %g kJ/mol/ps at %g K",
-                    ir->verletbuf_tol, buffer_temp);
+                    ir->verletbuf_tol,
+                    buffer_temp);
 
     /* Calculate the buffer size for simple atom vs atoms list */
     VerletbufListSetup listSetup1x1;
     listSetup1x1.cluster_size_i = 1;
     listSetup1x1.cluster_size_j = 1;
-    const real rlist_1x1 = calcVerletBufferSize(*mtop, det(box), *ir, ir->nstlist, ir->nstlist - 1,
-                                                buffer_temp, listSetup1x1);
+    const real rlist_1x1        = calcVerletBufferSize(
+            *mtop, det(box), *ir, ir->nstlist, ir->nstlist - 1, buffer_temp, listSetup1x1);
 
     /* Set the pair-list buffer size in ir */
     VerletbufListSetup listSetup4x4 = verletbufGetSafeListSetup(ListSetupType::CpuNoSimd);
-    ir->rlist = calcVerletBufferSize(*mtop, det(box), *ir, ir->nstlist, ir->nstlist - 1,
-                                     buffer_temp, listSetup4x4);
+    ir->rlist                       = calcVerletBufferSize(
+            *mtop, det(box), *ir, ir->nstlist, ir->nstlist - 1, buffer_temp, listSetup4x4);
 
     const int n_nonlin_vsite = gmx::countNonlinearVsites(*mtop);
     if (n_nonlin_vsite > 0)
@@ -1637,14 +1704,19 @@ static void set_verlet_buffer(const gmx_mtop_t*    mtop,
     GMX_LOG(logger.info)
             .asParagraph()
             .appendTextFormatted(
-                    "Calculated rlist for %dx%d atom pair-list as %.3f nm, buffer size %.3f nm", 1,
-                    1, rlist_1x1, rlist_1x1 - std::max(ir->rvdw, ir->rcoulomb));
+                    "Calculated rlist for %dx%d atom pair-list as %.3f nm, buffer size %.3f nm",
+                    1,
+                    1,
+                    rlist_1x1,
+                    rlist_1x1 - std::max(ir->rvdw, ir->rcoulomb));
 
     GMX_LOG(logger.info)
             .asParagraph()
             .appendTextFormatted(
                     "Set rlist, assuming %dx%d atom pair-list, to %.3f nm, buffer size %.3f nm",
-                    listSetup4x4.cluster_size_i, listSetup4x4.cluster_size_j, ir->rlist,
+                    listSetup4x4.cluster_size_i,
+                    listSetup4x4.cluster_size_j,
+                    ir->rlist,
                     ir->rlist - std::max(ir->rvdw, ir->rcoulomb));
 
     GMX_LOG(logger.info)
@@ -1658,7 +1730,8 @@ static void set_verlet_buffer(const gmx_mtop_t*    mtop,
                   "The pair-list cut-off (%g nm) is longer than half the shortest box vector or "
                   "longer than the smallest box diagonal element (%g nm). Increase the box size or "
                   "decrease nstlist or increase verlet-buffer-tolerance.",
-                  ir->rlist, std::sqrt(max_cutoff2(ir->pbcType, box)));
+                  ir->rlist,
+                  std::sqrt(max_cutoff2(ir->pbcType, box)));
     }
 }
 
@@ -1677,9 +1750,7 @@ int gmx_grompp(int argc, char* argv[])
         "Then a coordinate file is read and velocities can be generated",
         "from a Maxwellian distribution if requested.",
         "[THISMODULE] also reads parameters for [gmx-mdrun] ",
-        "(eg. number of MD steps, time step, cut-off), and others such as",
-        "NEMD parameters, which are corrected so that the net acceleration",
-        "is zero.",
+        "(eg. number of MD steps, time step, cut-off).",
         "Eventually a binary file is produced that can serve as the sole input",
         "file for the MD program.[PAR]",
 
@@ -1764,7 +1835,8 @@ int gmx_grompp(int argc, char* argv[])
     };
     std::vector<MoleculeInformation>     mi;
     std::unique_ptr<MoleculeInformation> intermolecular_interactions;
-    int                                  nvsite, comb;
+    int                                  nvsite;
+    CombinationRule                      comb;
     real                                 fudgeQQ;
     double                               reppow;
     const char*                          mdparin;
@@ -1854,7 +1926,7 @@ int gmx_grompp(int argc, char* argv[])
     }
     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
 
-    // Now that the MdModules have their options assigned from get_ir, subscribe
+    // Now that the MDModules have their options assigned from get_ir, subscribe
     // to eventual notifications during pre-processing their data
     mdModules.subscribeToPreProcessingNotifications();
 
@@ -1865,7 +1937,7 @@ int gmx_grompp(int argc, char* argv[])
                 .asParagraph()
                 .appendTextFormatted("checking input for internal consistency...");
     }
-    check_ir(mdparin, mdModules.notifier(), ir, opts, wi);
+    check_ir(mdparin, mdModules.notifiers(), ir, opts, wi);
 
     if (ir->ld_seed == -1)
     {
@@ -1909,9 +1981,26 @@ int gmx_grompp(int argc, char* argv[])
     }
 
     t_state state;
-    new_status(fn, opt2fn_null("-pp", NFILE, fnm), opt2fn("-c", NFILE, fnm), opts, ir, bZero,
-               bGenVel, bVerbose, &state, &atypes, &sys, &mi, &intermolecular_interactions,
-               interactions, &comb, &reppow, &fudgeQQ, opts->bMorse, wi, logger);
+    new_status(fn,
+               opt2fn_null("-pp", NFILE, fnm),
+               opt2fn("-c", NFILE, fnm),
+               opts,
+               ir,
+               bZero,
+               bGenVel,
+               bVerbose,
+               &state,
+               &atypes,
+               &sys,
+               &mi,
+               &intermolecular_interactions,
+               interactions,
+               &comb,
+               &reppow,
+               &fudgeQQ,
+               opts->bMorse,
+               wi,
+               logger);
 
     if (debug)
     {
@@ -1934,25 +2023,28 @@ int gmx_grompp(int argc, char* argv[])
         }
     }
 
-    if ((count_constraints(&sys, mi, wi) != 0) && (ir->eConstrAlg == econtSHAKE))
+    if ((count_constraints(&sys, mi, wi) != 0) && (ir->eConstrAlg == ConstraintAlgorithm::Shake))
     {
-        if (ir->eI == eiCG || ir->eI == eiLBFGS)
+        if (ir->eI == IntegrationAlgorithm::CG || ir->eI == IntegrationAlgorithm::LBFGS)
         {
             std::string warningMessage =
-                    gmx::formatString("Can not do %s with %s, use %s", EI(ir->eI),
-                                      econstr_names[econtSHAKE], econstr_names[econtLINCS]);
+                    gmx::formatString("Can not do %s with %s, use %s",
+                                      enumValueToString(ir->eI),
+                                      enumValueToString(ConstraintAlgorithm::Shake),
+                                      enumValueToString(ConstraintAlgorithm::Lincs));
             warning_error(wi, warningMessage);
         }
         if (ir->bPeriodicMols)
         {
             std::string warningMessage =
                     gmx::formatString("Can not do periodic molecules with %s, use %s",
-                                      econstr_names[econtSHAKE], econstr_names[econtLINCS]);
+                                      enumValueToString(ConstraintAlgorithm::Shake),
+                                      enumValueToString(ConstraintAlgorithm::Lincs));
             warning_error(wi, warningMessage);
         }
     }
 
-    if (EI_SD(ir->eI) && ir->etc != etcNO)
+    if (EI_SD(ir->eI) && ir->etc != TemperatureCoupling::No)
     {
         warning_note(wi, "Temperature coupling is ignored with SD integrators.");
     }
@@ -1964,13 +2056,14 @@ int gmx_grompp(int argc, char* argv[])
 
     if (nint_ftype(&sys, mi, F_POSRES) > 0 || nint_ftype(&sys, mi, F_FBPOSRES) > 0)
     {
-        if (ir->epc == epcPARRINELLORAHMAN || ir->epc == epcMTTK)
+        if (ir->epc == PressureCoupling::ParrinelloRahman || ir->epc == PressureCoupling::Mttk)
         {
             std::string warningMessage = gmx::formatString(
                     "You are combining position restraints with %s pressure coupling, which can "
                     "lead to instabilities. If you really want to combine position restraints with "
                     "pressure coupling, we suggest to use %s pressure coupling instead.",
-                    EPCOUPLTYPE(ir->epc), EPCOUPLTYPE(epcBERENDSEN));
+                    enumValueToString(ir->epc),
+                    enumValueToString(PressureCoupling::Berendsen));
             warning_note(wi, warningMessage);
         }
 
@@ -2014,17 +2107,19 @@ int gmx_grompp(int argc, char* argv[])
             }
             GMX_LOG(logger.info).asParagraph().appendText(message);
         }
-        gen_posres(&sys, mi, fn, fnB, ir->refcoord_scaling, ir->pbcType, ir->posres_com,
-                   ir->posres_comB, wi, logger);
+        gen_posres(&sys, mi, fn, fnB, ir->refcoord_scaling, ir->pbcType, ir->posres_com, ir->posres_comB, wi, logger);
     }
 
     /* If we are using CMAP, setup the pre-interpolation grid */
     if (interactions[F_CMAP].ncmap() > 0)
     {
-        init_cmap_grid(&sys.ffparams.cmap_grid, interactions[F_CMAP].cmapAngles,
+        init_cmap_grid(&sys.ffparams.cmap_grid,
+                       interactions[F_CMAP].cmapAngles,
                        interactions[F_CMAP].cmakeGridSpacing);
-        setup_cmap(interactions[F_CMAP].cmakeGridSpacing, interactions[F_CMAP].cmapAngles,
-                   interactions[F_CMAP].cmap, &sys.ffparams.cmap_grid);
+        setup_cmap(interactions[F_CMAP].cmakeGridSpacing,
+                   interactions[F_CMAP].cmapAngles,
+                   interactions[F_CMAP].cmap,
+                   &sys.ffparams.cmap_grid);
     }
 
     set_wall_atomtype(&atypes, opts, ir, wi, logger);
@@ -2052,8 +2147,8 @@ int gmx_grompp(int argc, char* argv[])
     }
 
     const int ntype = atypes.size();
-    convertInteractionsOfType(ntype, interactions, mi, intermolecular_interactions.get(), comb,
-                              reppow, fudgeQQ, &sys);
+    convertInteractionsOfType(
+            ntype, interactions, mi, intermolecular_interactions.get(), comb, reppow, fudgeQQ, &sys);
 
     if (debug)
     {
@@ -2090,7 +2185,7 @@ int gmx_grompp(int argc, char* argv[])
 
     checkForUnboundAtoms(&sys, bVerbose, wi, logger);
 
-    if (EI_DYNAMICS(ir->eI) && ir->eI != eiBD)
+    if (EI_DYNAMICS(ir->eI) && ir->eI != IntegrationAlgorithm::BD)
     {
         check_bonds_timestep(&sys, ir->delta_t, wi);
     }
@@ -2113,15 +2208,15 @@ int gmx_grompp(int argc, char* argv[])
     {
         GMX_LOG(logger.info).asParagraph().appendTextFormatted("initialising group options...");
     }
-    do_index(mdparin, ftp2fn_null(efNDX, NFILE, fnm), &sys, bVerbose, mdModules.notifier(), ir, wi);
+    do_index(mdparin, ftp2fn_null(efNDX, NFILE, fnm), &sys, bVerbose, mdModules.notifiers(), ir, wi);
 
-    if (ir->cutoff_scheme == ecutsVERLET && ir->verletbuf_tol > 0)
+    if (ir->cutoff_scheme == CutoffScheme::Verlet && ir->verletbuf_tol > 0)
     {
         if (EI_DYNAMICS(ir->eI) && inputrec2nboundeddim(ir) == 3)
         {
             real buffer_temp;
 
-            if (EI_MD(ir->eI) && ir->etc == etcNO)
+            if (EI_MD(ir->eI) && ir->etc == TemperatureCoupling::No)
             {
                 if (bGenVel)
                 {
@@ -2153,7 +2248,7 @@ int gmx_grompp(int argc, char* argv[])
                 buffer_temp = get_max_reference_temp(ir, wi);
             }
 
-            if (EI_MD(ir->eI) && ir->etc == etcNO && buffer_temp == 0)
+            if (EI_MD(ir->eI) && ir->etc == TemperatureCoupling::No && buffer_temp == 0)
             {
                 /* NVE with initial T=0: we add a fixed ratio to rlist.
                  * Since we don't actually use verletbuf_tol, we set it to -1
@@ -2169,14 +2264,14 @@ int gmx_grompp(int argc, char* argv[])
                  * Note that we can't warn when nsteps=0, since we don't
                  * know how many steps the user intends to run.
                  */
-                if (EI_MD(ir->eI) && ir->etc == etcNO && ir->nstlist > 1 && ir->nsteps > 0)
+                if (EI_MD(ir->eI) && ir->etc == TemperatureCoupling::No && ir->nstlist > 1 && ir->nsteps > 0)
                 {
                     const real driftTolerance = 0.01;
                     /* We use 2 DOF per atom = 2kT pot+kin energy,
                      * to be on the safe side with constraints.
                      */
                     const real totalEnergyDriftPerAtomPerPicosecond =
-                            2 * BOLTZ * buffer_temp / (ir->nsteps * ir->delta_t);
+                            2 * gmx::c_boltz * buffer_temp / (ir->nsteps * ir->delta_t);
 
                     if (ir->verletbuf_tol > 1.1 * driftTolerance * totalEnergyDriftPerAtomPerPicosecond)
                     {
@@ -2185,7 +2280,8 @@ int gmx_grompp(int argc, char* argv[])
                                 "NVE simulation of length %g ps, which can give a final drift of "
                                 "%d%%. For conserving energy to %d%% when using constraints, you "
                                 "might need to set verlet-buffer-tolerance to %.1e.",
-                                ir->verletbuf_tol, ir->nsteps * ir->delta_t,
+                                ir->verletbuf_tol,
+                                ir->nsteps * ir->delta_t,
                                 gmx::roundToInt(ir->verletbuf_tol / totalEnergyDriftPerAtomPerPicosecond * 100),
                                 gmx::roundToInt(100 * driftTolerance),
                                 driftTolerance * totalEnergyDriftPerAtomPerPicosecond);
@@ -2213,7 +2309,7 @@ int gmx_grompp(int argc, char* argv[])
         pr_symtab(debug, 0, "After close", &sys.symtab);
     }
 
-    if (ir->eI == eiMimic)
+    if (ir->eI == IntegrationAlgorithm::Mimic)
     {
         generate_qmexcl(&sys, ir, logger);
     }
@@ -2226,8 +2322,16 @@ int gmx_grompp(int argc, char* argv[])
                     .asParagraph()
                     .appendTextFormatted("getting data from old trajectory ...");
         }
-        cont_status(ftp2fn(efTRN, NFILE, fnm), ftp2fn_null(efEDR, NFILE, fnm), bNeedVel, bGenVel,
-                    fr_time, ir, &state, &sys, oenv, logger);
+        cont_status(ftp2fn(efTRN, NFILE, fnm),
+                    ftp2fn_null(efEDR, NFILE, fnm),
+                    bNeedVel,
+                    bGenVel,
+                    fr_time,
+                    ir,
+                    &state,
+                    &sys,
+                    oenv,
+                    logger);
     }
 
     if (ir->pbcType == PbcType::XY && ir->nwall != 2)
@@ -2254,8 +2358,7 @@ int gmx_grompp(int argc, char* argv[])
                     wi, "Some of the Fourier grid sizes are set, but all of them need to be set.");
         }
         const int minGridSize = minimalPmeGridSize(ir->pme_order);
-        calcFftGrid(stdout, scaledBox, ir->fourier_spacing, minGridSize, &(ir->nkx), &(ir->nky),
-                    &(ir->nkz));
+        calcFftGrid(stdout, scaledBox, ir->fourier_spacing, minGridSize, &(ir->nkx), &(ir->nky), &(ir->nkz));
         if (ir->nkx < minGridSize || ir->nky < minGridSize || ir->nkz < minGridSize)
         {
             warning_error(wi,
@@ -2267,10 +2370,10 @@ int gmx_grompp(int argc, char* argv[])
     /* MRS: eventually figure out better logic for initializing the fep
        values that makes declaring the lambda and declaring the state not
        potentially conflict if not handled correctly. */
-    if (ir->efep != efepNO)
+    if (ir->efep != FreeEnergyPerturbationType::No)
     {
         state.fep_state = ir->fepvals->init_fep_state;
-        for (i = 0; i < efptNR; i++)
+        for (i = 0; i < static_cast<int>(FreeEnergyPerturbationCouplingType::Count); i++)
         {
             /* init_lambda trumps state definitions*/
             if (ir->fepvals->init_lambda >= 0)
@@ -2279,7 +2382,7 @@ int gmx_grompp(int argc, char* argv[])
             }
             else
             {
-                if (ir->fepvals->all_lambda[i] == nullptr)
+                if (ir->fepvals->all_lambda[i].empty())
                 {
                     gmx_fatal(FARGS, "Values of lambda not set for a free energy calculation!");
                 }
@@ -2295,7 +2398,8 @@ int gmx_grompp(int argc, char* argv[])
 
     if (ir->bPull)
     {
-        pull = set_pull_init(ir, &sys, state.x.rvec_array(), state.box, state.lambda[efptMASS], wi);
+        pull = set_pull_init(
+                ir, sys, state.x, state.box, state.lambda[FreeEnergyPerturbationCouplingType::Mass], wi);
     }
 
     /* Modules that supply external potential for pull coordinates
@@ -2306,14 +2410,23 @@ int gmx_grompp(int argc, char* argv[])
     if (ir->bDoAwh)
     {
         tensor compressibility = { { 0 } };
-        if (ir->epc != epcNO)
+        if (ir->epc != PressureCoupling::No)
         {
             copy_mat(ir->compress, compressibility);
         }
         setStateDependentAwhParams(
-                ir->awhParams, *ir->pull, pull, state.box, ir->pbcType, compressibility, &ir->opts,
-                ir->efep != efepNO ? ir->fepvals->all_lambda[efptFEP][ir->fepvals->init_fep_state] : 0,
-                sys, wi);
+                ir->awhParams.get(),
+                *ir->pull,
+                pull,
+                state.box,
+                ir->pbcType,
+                compressibility,
+                &ir->opts,
+                ir->efep != FreeEnergyPerturbationType::No ? ir->fepvals->all_lambda[static_cast<int>(
+                        FreeEnergyPerturbationCouplingType::Fep)][ir->fepvals->init_fep_state]
+                                                           : 0,
+                sys,
+                wi);
     }
 
     if (ir->bPull)
@@ -2323,8 +2436,12 @@ int gmx_grompp(int argc, char* argv[])
 
     if (ir->bRot)
     {
-        set_reference_positions(ir->rot, state.x.rvec_array(), state.box,
-                                opt2fn("-ref", NFILE, fnm), opt2bSet("-ref", NFILE, fnm), wi);
+        set_reference_positions(ir->rot,
+                                state.x.rvec_array(),
+                                state.box,
+                                opt2fn("-ref", NFILE, fnm),
+                                opt2bSet("-ref", NFILE, fnm),
+                                wi);
     }
 
     /*  reset_multinr(sys); */
@@ -2340,14 +2457,15 @@ int gmx_grompp(int argc, char* argv[])
          * charges. This will double the cost, but the optimal performance will
          * then probably be at a slightly larger cut-off and grid spacing.
          */
-        if ((ir->efep == efepNO && ratio > 1.0 / 2.0) || (ir->efep != efepNO && ratio > 2.0 / 3.0))
+        if ((ir->efep == FreeEnergyPerturbationType::No && ratio > 1.0 / 2.0)
+            || (ir->efep != FreeEnergyPerturbationType::No && ratio > 2.0 / 3.0))
         {
             warning_note(
                     wi,
                     "The optimal PME mesh load for parallel simulations is below 0.5\n"
                     "and for highly parallel simulations between 0.25 and 0.33,\n"
                     "for higher performance, increase the cut-off and the PME grid spacing.\n");
-            if (ir->efep != efepNO)
+            if (ir->efep != FreeEnergyPerturbationType::No)
             {
                 warning_note(wi,
                              "For free energy simulations, the optimal load limit increases from "
@@ -2376,26 +2494,47 @@ int gmx_grompp(int argc, char* argv[])
 
     {
         gmx::KeyValueTreeBuilder internalParameterBuilder;
-        mdModules.notifier().preProcessingNotifications_.notify(internalParameterBuilder.rootObject());
+        mdModules.notifiers().preProcessingNotifier_.notify(internalParameterBuilder.rootObject());
         ir->internalParameters =
                 std::make_unique<gmx::KeyValueTreeObject>(internalParameterBuilder.build());
     }
 
+    if (ir->comm_mode != ComRemovalAlgorithm::No)
+    {
+        const int nstglobalcomm = computeGlobalCommunicationPeriod(ir);
+        if (ir->nstcomm % nstglobalcomm != 0)
+        {
+            warning_note(
+                    wi,
+                    gmx::formatString(
+                            "COM removal frequency is set to (%d).\n"
+                            "Other settings require a global communication frequency of %d.\n"
+                            "Note that this will require additional global communication steps,\n"
+                            "which will reduce performance when using multiple ranks.\n"
+                            "Consider setting nstcomm to a multiple of %d.",
+                            ir->nstcomm,
+                            nstglobalcomm,
+                            nstglobalcomm));
+        }
+    }
+
     if (bVerbose)
     {
         GMX_LOG(logger.info).asParagraph().appendTextFormatted("writing run input file...");
     }
 
     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 */
-    gmx::write_IMDgroup_to_file(ir->bIMD, ir, &state, &sys, NFILE, fnm);
+    gmx::write_IMDgroup_to_file(ir->bIMD, ir, &state, sys, NFILE, fnm);
 
     sfree(opts->define);
     sfree(opts->wall_atomtype[0]);
     sfree(opts->wall_atomtype[1]);
     sfree(opts->include);
+    sfree(opts->couple_moltype);
+
     for (auto& mol : mi)
     {
         // Some of the contents of molinfo have been stolen, so
index 9092fc8310f61d1579a6076741dc109644837da4..14b4528320aa9e1f922875f22a7b4a723192e42d 100644 (file)
@@ -98,8 +98,11 @@ void read_ab(char* line, const char* fn, MoleculePatch* hack)
     hack->tp = tp;
     if ((tp < 1) || (tp >= maxcontrol))
     {
-        gmx_fatal(FARGS, "Error in hdb file %s:\nH-type should be in 1-%d. Offending line:\n%s", fn,
-                  maxcontrol - 1, line);
+        gmx_fatal(FARGS,
+                  "Error in hdb file %s:\nH-type should be in 1-%d. Offending line:\n%s",
+                  fn,
+                  maxcontrol - 1,
+                  line);
     }
 
     hack->nctl = ns - 3;
@@ -108,7 +111,10 @@ void read_ab(char* line, const char* fn, MoleculePatch* hack)
         gmx_fatal(FARGS,
                   "Error in hdb file %s:\nWrong number of control atoms (%d instead of %d) on "
                   "line:\n%s\n",
-                  fn, hack->nctl, ncontrol[hack->tp], line);
+                  fn,
+                  hack->nctl,
+                  ncontrol[hack->tp],
+                  line);
     }
     for (int i = 0; (i < hack->nctl); i++)
     {
@@ -167,7 +173,10 @@ static void read_h_db_file(const char* hfn, std::vector<MoleculePatchDatabase>*
                     gmx_fatal(FARGS,
                               "Expected %d lines of hydrogens, found only %d "
                               "while reading Hydrogen Database %s residue %s",
-                              nab, i - 1, block->name.c_str(), hfn);
+                              nab,
+                              i - 1,
+                              block->name.c_str(),
+                              hfn);
                 }
                 if (nullptr == fgets(buf, STRLEN, in))
                 {
@@ -183,13 +192,16 @@ static void read_h_db_file(const char* hfn, std::vector<MoleculePatchDatabase>*
     if (!globalPatches->empty())
     {
         /* Sort the list for searching later */
-        std::sort(globalPatches->begin(), globalPatches->end(),
+        std::sort(globalPatches->begin(),
+                  globalPatches->end(),
                   [](const MoleculePatchDatabase& a1, const MoleculePatchDatabase& a2) {
-                      return std::lexicographical_compare(
-                              a1.name.begin(), a1.name.end(), a2.name.begin(), a2.name.end(),
-                              [](const char& c1, const char& c2) {
-                                  return std::toupper(c1) < std::toupper(c2);
-                              });
+                      return std::lexicographical_compare(a1.name.begin(),
+                                                          a1.name.end(),
+                                                          a2.name.begin(),
+                                                          a2.name.end(),
+                                                          [](const char& c1, const char& c2) {
+                                                              return std::toupper(c1) < std::toupper(c2);
+                                                          });
                   });
     }
 }
@@ -212,7 +224,7 @@ int read_h_db(const char* ffdir, std::vector<MoleculePatchDatabase>* globalPatch
 gmx::ArrayRef<const MoleculePatchDatabase>::iterator
 search_h_db(gmx::ArrayRef<const MoleculePatchDatabase> globalPatches, const char* key)
 {
-    return std::find_if(
-            globalPatches.begin(), globalPatches.end(),
-            [&key](const MoleculePatchDatabase& a) { return gmx::equalCaseInsensitive(key, a.name); });
+    return std::find_if(globalPatches.begin(), globalPatches.end(), [&key](const MoleculePatchDatabase& a) {
+        return gmx::equalCaseInsensitive(key, a.name);
+    });
 }
index 2459141ae6e9744a00c7369cd8429236ae179b79..956e0d72e13d43cf370dacc68164c74296c43da5 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2011,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/symtab.h"
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringcompare.h"
 
-/* these MUST correspond to the enum in hackblock.h */
-const char* btsNames[ebtsNR] = { "bonds", "angles", "dihedrals", "impropers", "exclusions", "cmap" };
-const int   btsNiatoms[ebtsNR] = { 2, 3, 4, 4, 2, 5 };
+const char* enumValueToString(BondedTypes enumValue)
+{
+    /* these MUST correspond to the enum in hackblock.h */
+    constexpr gmx::EnumerationArray<BondedTypes, const char*> bondedTypeNames = {
+        "bonds", "angles", "dihedrals", "impropers", "exclusions", "cmap"
+    };
+    return bondedTypeNames[enumValue];
+}
+
+int enumValueToNumIAtoms(BondedTypes enumValue)
+{
+    constexpr gmx::EnumerationArray<BondedTypes, int> bondedTypeIAtoms = { 2, 3, 4, 4, 2, 5 };
+    return bondedTypeIAtoms[enumValue];
+}
 
 MoleculePatchType MoleculePatch::type() const
 {
@@ -83,9 +95,9 @@ void clearModificationBlock(MoleculePatchDatabase* globalPatches)
 {
     globalPatches->name.clear();
     globalPatches->hack.clear();
-    for (int i = 0; i < ebtsNR; i++)
+    for (auto bondedsList : globalPatches->rb)
     {
-        globalPatches->rb[i].b.clear();
+        bondedsList.b.clear();
     }
 }
 
@@ -152,9 +164,10 @@ bool mergeBondedInteractionList(gmx::ArrayRef<const BondedInteractionList> s,
                                 bool                                       bPlus)
 {
     bool bBondsRemoved = false;
-    for (int i = 0; i < ebtsNR; i++)
+    for (auto i : gmx::EnumerationWrapper<BondedTypes>{})
     {
-        if (!s[i].b.empty())
+        int value = static_cast<int>(i);
+        if (!s[value].b.empty())
         {
             /* Record how many bonds we have in the destination when we start.
              *
@@ -171,15 +184,15 @@ bool mergeBondedInteractionList(gmx::ArrayRef<const BondedInteractionList> s,
              * it is a hackblock entry meant to override the main rtp, and then
              * we don't add the main rtp one.
              */
-            int nbHackblockStart = d[i].b.size();
+            int nbHackblockStart = d[value].b.size();
 
-            for (const auto& b : s[i].b)
+            for (const auto& b : s[value].b)
             {
                 /* Check if this bonded string already exists before adding.
                  * We are merging from the main RTP to the hackblocks, so this
                  * will mean the hackblocks overwrite the man RTP, as intended.
                  */
-                int index = rbonded_find_atoms_in_list(b, d[i].b, btsNiatoms[i]);
+                int index = rbonded_find_atoms_in_list(b, d[value].b, enumValueToNumIAtoms(i));
                 /* - If we did not find this interaction at all, the index will be -1,
                  *   and then we should definitely add it to the merged hackblock and rtp.
                  *
@@ -200,9 +213,9 @@ bool mergeBondedInteractionList(gmx::ArrayRef<const BondedInteractionList> s,
                 {
                     if (!(bMin && contains_char(b, '-')) && !(bPlus && contains_char(b, '+')))
                     {
-                        d[i].b.push_back(b);
+                        d[value].b.push_back(b);
                     }
-                    else if (i == ebtsBONDS)
+                    else if (i == BondedTypes::Bonds)
                     {
                         bBondsRemoved = true;
                     }
@@ -237,7 +250,7 @@ void copyPreprocessResidues(const PreprocessResidue& s, PreprocessResidue* d, t_
     {
         d->cgnr.push_back(c);
     }
-    for (int i = 0; i < ebtsNR; i++)
+    for (auto i : gmx::EnumerationWrapper<BondedTypes>{})
     {
         d->rb[i].type = s.rb[i].type;
         d->rb[i].b.clear();
@@ -264,9 +277,9 @@ void copyModificationBlocks(const MoleculePatchDatabase& s, MoleculePatchDatabas
     *d      = s;
     d->name = s.name;
     d->hack.clear();
-    for (int i = 0; i < ebtsNR; i++)
+    for (auto bondedList : d->rb)
     {
-        d->rb[i].b.clear();
+        bondedList.b.clear();
     }
     mergeAtomAndBondModifications(s, d);
 }
index 33613291bb5212fd69233d9c59a45ac9fed21251..8e5e9c272295773664c698106aace6aee5d6b0c9 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,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gmxpreprocess/notset.h"
 #include "gromacs/topology/ifunc.h"
+#include "gromacs/utility/enumerationhelpers.h"
 
 struct t_atom;
 struct t_symtab;
@@ -61,23 +62,23 @@ class ArrayRef;
 
 /*! \brief
  * Used for reading .rtp/.tdb
- * ebtsBONDS must be the first, new types can be added to the end
+ * BondedTypes::Bonds must be the first, new types can be added to the end
  * these *MUST* correspond to the arrays in hackblock.cpp
  */
-enum
+enum class BondedTypes : int
 {
-    ebtsBONDS,
-    ebtsANGLES,
-    ebtsPDIHS,
-    ebtsIDIHS,
-    ebtsEXCLS,
-    ebtsCMAP,
-    ebtsNR
+    Bonds,
+    Angles,
+    ProperDihedrals,
+    ImproperDihedrals,
+    Exclusions,
+    Cmap,
+    Count
 };
 //! Names for interaction type entries
-extern const char* btsNames[ebtsNR];
+const char* enumValueToString(BondedTypes enumValue);
 //! Numbers for atoms in the interactions.
-extern const int btsNiatoms[ebtsNR];
+int enumValueToNumIAtoms(BondedTypes enumValue);
 
 /* if changing any of these structs, make sure that all of the
    free/clear/copy/merge_t_* functions stay updated */
@@ -145,7 +146,7 @@ struct PreprocessResidue
     //! Delete dihedrals also defined by impropers.
     bool bRemoveDihedralIfWithImproper = false;
     //! List of bonded interactions to potentially add.
-    std::array<BondedInteractionList, ebtsNR> rb;
+    gmx::EnumerationArray<BondedTypes, BondedInteractionList> rb;
     //! Get number of atoms in residue.
     int natom() const { return atom.size(); }
 };
@@ -223,7 +224,7 @@ struct MoleculePatchDatabase
     //! List of changes to atoms.
     std::vector<MoleculePatch> hack;
     //! List of bonded interactions to potentially add.
-    std::array<BondedInteractionList, ebtsNR> rb;
+    gmx::EnumerationArray<BondedTypes, BondedInteractionList> rb;
     //! Number of atoms to modify
     int nhack() const { return hack.size(); }
 };
index 83ba164b66bac4fca2a4ff4650a6e8e9358d0610..946ada2f392d7730f2c79414ff9b8818c7f23c4d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gmxpreprocess/toputil.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/topology/block.h"
 #include "gromacs/topology/symtab.h"
@@ -145,7 +146,7 @@ static bool chk_hbonds(int i, t_atoms* pdba, rvec x[], const bool ad[], bool hbo
                 d2 = distance2(x[i], x[j]);
                 rvec_sub(x[i], xh, nh);
                 rvec_sub(x[aj], xh, oh);
-                a = RAD2DEG * acos(cos_angle(nh, oh));
+                a = gmx::c_rad2Deg * acos(cos_angle(nh, oh));
                 if ((d2 < dist2) && (a > angle))
                 {
                     hbond[i] = TRUE;
@@ -179,15 +180,16 @@ void set_histp(t_atoms* pdba, rvec* x, t_symtab* symtab, real angle, real dist)
                                       "NZ", "OG",  "OG1", "OH", "NE1", "OW" };
 #define NPD asize(prot_don)
 
-    bool *    donor, *acceptor;
-    bool*     hbond;
-    bool      bHDd, bHEd;
-    rvec      xh1, xh2;
-    int       natom;
-    int       i, j, nd, na, hisind, type = -1;
-    int       nd1, ne2, cg, cd2, ce1;
-    t_blocka* hb;
-    char*     atomnm;
+    bool *          donor, *acceptor;
+    bool*           hbond;
+    bool            bHDd, bHEd;
+    rvec            xh1, xh2;
+    int             natom;
+    int             i, j, nd, na, hisind;
+    HistidineStates type = HistidineStates::Count;
+    int             nd1, ne2, cg, cd2, ce1;
+    t_blocka*       hb;
+    char*           atomnm;
 
     natom = pdba->nr;
 
@@ -287,25 +289,28 @@ void set_histp(t_atoms* pdba, rvec* x, t_symtab* symtab, real angle, real dist)
                     {
                         if (bHEd)
                         {
-                            type = ehisH;
+                            type = HistidineStates::H;
                         }
                         else
                         {
-                            type = ehisA;
+                            type = HistidineStates::A;
                         }
                     }
                     else
                     {
-                        type = ehisB;
+                        type = HistidineStates::B;
                     }
-                    fprintf(stderr, "Will use %s for residue %d\n", hh[type], pdba->resinfo[hisind].nr);
+                    fprintf(stderr,
+                            "Will use %s for residue %d\n",
+                            enumValueToString(type),
+                            pdba->resinfo[hisind].nr);
                 }
                 else
                 {
                     gmx_fatal(FARGS, "Incomplete ring in HIS%d", pdba->resinfo[hisind].nr);
                 }
 
-                pdba->resinfo[hisind].rtp = put_symtab(symtab, hh[type]);
+                pdba->resinfo[hisind].rtp = put_symtab(symtab, enumValueToString(type));
             }
         }
     }
index 94cde0b968457025ee9637f91b9441495cb9b310..06e4ec1b2259ef633ab2699e0d51d1102fa9002f 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +52,7 @@
 #include "gromacs/gmxlib/conformation_utilities.h"
 #include "gromacs/gmxpreprocess/makeexclusiondistances.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/options/basicoptions.h"
@@ -88,8 +89,9 @@ enum class RotationType : int
     None,
     Count
 };
-static const gmx::EnumerationArray<RotationType, const char*> c_rotationTypeNames = { { "xyz", "z",
-                                                                                        "none" } };
+static const gmx::EnumerationArray<RotationType, const char*> c_rotationTypeNames = {
+    { "xyz", "z", "none" }
+};
 
 static void center_molecule(gmx::ArrayRef<RVec> x)
 {
@@ -264,8 +266,11 @@ static void insert_mols(int                  nmol_insrt,
             // Skip a position if ntry trials were not successful.
             if (trial >= firstTrial + ntry)
             {
-                fprintf(stderr, " skipped position (%.3f, %.3f, %.3f)\n", rpos[XX][mol],
-                        rpos[YY][mol], rpos[ZZ][mol]);
+                fprintf(stderr,
+                        " skipped position (%.3f, %.3f, %.3f)\n",
+                        rpos[XX][mol],
+                        rpos[YY][mol],
+                        rpos[ZZ][mol]);
                 ++mol;
                 ++failed;
                 firstTrial = trial;
@@ -282,11 +287,12 @@ static void insert_mols(int                  nmol_insrt,
         generate_trial_conf(x_insrt, offset_x, enum_rot, &rng, &x_n);
         gmx::AnalysisNeighborhoodPositions pos(*x);
         gmx::AnalysisNeighborhoodSearch    search = nb.initSearch(&pbc, pos);
-        if (isInsertionAllowed(&search, exclusionDistances, x_n, exclusionDistances_insrt, *atoms,
-                               removableAtoms, &remover))
+        if (isInsertionAllowed(
+                    &search, exclusionDistances, x_n, exclusionDistances_insrt, *atoms, removableAtoms, &remover))
         {
             x->insert(x->end(), x_n.begin(), x_n.end());
-            exclusionDistances.insert(exclusionDistances.end(), exclusionDistances_insrt.begin(),
+            exclusionDistances.insert(exclusionDistances.end(),
+                                      exclusionDistances_insrt.begin(),
                                       exclusionDistances_insrt.end());
             builder.mergeAtoms(atoms_insrt);
             ++mol;
@@ -306,7 +312,9 @@ static void insert_mols(int                  nmol_insrt,
     remover.removeMarkedAtoms(atoms);
     if (atoms->nr < originalAtomCount)
     {
-        fprintf(stderr, "Replaced %d residues (%d atoms)\n", originalResidueCount - atoms->nres,
+        fprintf(stderr,
+                "Replaced %d residues (%d atoms)\n",
+                originalResidueCount - atoms->nres,
                 originalAtomCount - atoms->nr);
     }
 
@@ -445,7 +453,7 @@ void InsertMolecules::initOptions(IOptionsContainer* options, ICommandLineOption
                                .defaultBasename("insert")
                                .description("Configuration to insert"));
     options->addOption(FileNameOption("ip")
-                               .filetype(eftGenericData)
+                               .filetype(OptionFileType::GenericData)
                                .inputFile()
                                .store(&positionFile_)
                                .defaultBasename("positions")
@@ -508,8 +516,8 @@ void InsertMolecules::optionsFinished()
         bool  bTprFileWasRead;
         rvec* temporaryX = nullptr;
         fprintf(stderr, "Reading solute configuration\n");
-        readConfAndTopology(inputConfFile_.c_str(), &bTprFileWasRead, &top_, &pbcType_, &temporaryX,
-                            nullptr, box_);
+        readConfAndTopology(
+                inputConfFile_.c_str(), &bTprFileWasRead, &top_, &pbcType_, &temporaryX, nullptr, box_);
         x_.assign(temporaryX, temporaryX + top_.natoms);
         sfree(temporaryX);
         if (top_.natoms == 0)
@@ -563,11 +571,11 @@ int InsertMolecules::run()
         PbcType pbcType_dummy;
         matrix  box_dummy;
         rvec*   temporaryX;
-        readConfAndTopology(insertConfFile_.c_str(), &bTprFileWasRead, &topInserted, &pbcType_dummy,
-                            &temporaryX, nullptr, box_dummy);
+        readConfAndTopology(
+                insertConfFile_.c_str(), &bTprFileWasRead, &topInserted, &pbcType_dummy, &temporaryX, nullptr, box_dummy);
         xInserted.assign(temporaryX, temporaryX + topInserted.natoms);
         sfree(temporaryX);
-        atomsInserted = gmx_mtop_global_atoms(&topInserted);
+        atomsInserted = gmx_mtop_global_atoms(topInserted);
         if (atomsInserted.nr == 0)
         {
             gmx_fatal(FARGS, "No molecule in %s, please check your input", insertConfFile_.c_str());
@@ -582,18 +590,31 @@ int InsertMolecules::run()
         }
     }
 
-    t_atoms atoms = gmx_mtop_global_atoms(&top_);
+    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_, &atoms, &top_.symtab,
-                &x_, removableAtoms, atomsInserted, xInserted, pbcTypeForOutput, box_,
-                positionFile_, deltaR_, enumRot_);
+    insert_mols(nmolIns_,
+                nmolTry_,
+                seed_,
+                defaultDistance_,
+                scaleFactor_,
+                &atoms,
+                &top_.symtab,
+                &x_,
+                removableAtoms,
+                atomsInserted,
+                xInserted,
+                pbcTypeForOutput,
+                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, &atoms, as_rvec_array(x_.data()), nullptr,
-                   pbcTypeForOutput, box_);
+    write_sto_conf(
+            outputConfFile_.c_str(), *top_.name, &atoms, as_rvec_array(x_.data()), nullptr, pbcTypeForOutput, box_);
 
     /* print size of generated configuration */
     fprintf(stderr, "\nOutput configuration contains %d atoms in %d residues\n", atoms.nr, atoms.nres);
index 3258fc0591021921b4aa203b05ce9b9a88b0e820..f60352418333b61e73dbb780d65608b7bf9b33dd 100644 (file)
@@ -53,8 +53,10 @@ std::vector<real> makeExclusionDistances(const t_atoms* a, AtomProperties* aps,
         for (int i = 0; i < a->nr; ++i)
         {
             real value;
-            if (!aps->setAtomProperty(epropVDW, std::string(*(a->resinfo[a->atom[i].resind].name)),
-                                      std::string(*(a->atomname[i])), &value))
+            if (!aps->setAtomProperty(epropVDW,
+                                      std::string(*(a->resinfo[a->atom[i].resind].name)),
+                                      std::string(*(a->atomname[i])),
+                                      &value))
             {
                 value = defaultDistance;
             }
index 035daabf2a3806c9c0b9da8f97efb7b43d30788e..5b54ef7f7fb07ee25c96c3e32b4cb413ac4c2ae2 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -151,8 +151,7 @@ void dump_nm2type(FILE* fp, int nnm, t_nm2type nm2t[])
     fprintf(fp, "; nm2type database\n");
     for (i = 0; (i < nnm); i++)
     {
-        fprintf(fp, "%-8s %-8s %8.4f %8.4f %-4d", nm2t[i].elem, nm2t[i].type, nm2t[i].q, nm2t[i].m,
-                nm2t[i].nbonds);
+        fprintf(fp, "%-8s %-8s %8.4f %8.4f %-4d", nm2t[i].elem, nm2t[i].type, nm2t[i].q, nm2t[i].m, nm2t[i].nbonds);
         for (j = 0; (j < nm2t[i].nbonds); j++)
         {
             fprintf(fp, " %-5s %6.4f", nm2t[i].bond[j], nm2t[i].blen[j]);
@@ -335,13 +334,18 @@ int nm2type(int                     nnm,
             double      mm   = nm2t[best].m;
             const char* type = nm2t[best].type;
 
-            int k;
-            if ((k = atype->atomTypeFromName(type)) == NOTSET)
+            auto atomType = atype->atomTypeFromName(type);
+            int  k;
+            if (!atomType.has_value())
             {
                 atoms->atom[i].qB = alpha;
                 atoms->atom[i].m = atoms->atom[i].mB = mm;
-                k = atype->addType(tab, atoms->atom[i], type, InteractionOfType({}, {}),
-                                   atoms->atom[i].type, atomnr);
+                k                                    = atype->addType(
+                        tab, atoms->atom[i], type, InteractionOfType({}, {}), atoms->atom[i].type, atomnr);
+            }
+            else
+            {
+                k = *atomType;
             }
             atoms->atom[i].type  = k;
             atoms->atom[i].typeB = k;
@@ -353,8 +357,11 @@ int nm2type(int                     nnm,
         }
         else
         {
-            fprintf(stderr, "Can not find forcefield for atom %s-%d with %d bonds\n",
-                    *atoms->atomname[i], i + 1, nb);
+            fprintf(stderr,
+                    "Can not find forcefield for atom %s-%d with %d bonds\n",
+                    *atoms->atomname[i],
+                    i + 1,
+                    nb);
         }
     }
     sfree(bbb);
index ff1fc32edd0c74d785c017f69124cb44b2059ca7..d230a9ef7625d04c1073e507549f9f429b62495e 100644 (file)
@@ -37,6 +37,7 @@
  */
 #include "gmxpre.h"
 
+#include "gromacs/utility/enumerationhelpers.h"
 #include "pdb2gmx.h"
 
 #include <cctype>
 struct RtpRename
 {
     RtpRename(const char* newGmx, const char* newMain, const char* newNter, const char* newCter, const char* newBter) :
-        gmx(newGmx),
-        main(newMain),
-        nter(newNter),
-        cter(newCter),
-        bter(newBter)
+        gmx(newGmx), main(newMain), nter(newNter), cter(newCter), bter(newBter)
     {
     }
     std::string gmx;
@@ -121,17 +118,133 @@ const char* res2bb_notermini(const std::string& name, gmx::ArrayRef<const RtpRen
     return found != rr.end() ? found->main.c_str() : name.c_str();
 }
 
-const char* select_res(int                            nr,
-                       int                            resnr,
-                       const char*                    name[],
-                       const char*                    expl[],
-                       const char*                    title,
-                       gmx::ArrayRef<const RtpRename> rr)
+const char* enumValueToLongString(HistidineStates enumValue)
+{
+    constexpr gmx::EnumerationArray<HistidineStates, const char*> histidineStatesLongNames = {
+        "H on ND1 only", "H on NE2 only", "H on ND1 and NE2", "Coupled to Heme"
+    };
+    return histidineStatesLongNames[enumValue];
+}
+
+enum class AspartateStates : int
+{
+    Deprot,
+    Prot,
+    Count
+};
+
+const char* enumValueToString(AspartateStates enumValue)
+{
+    constexpr gmx::EnumerationArray<AspartateStates, const char*> aspartateStateNames = { "ASP",
+                                                                                          "ASPH" };
+    return aspartateStateNames[enumValue];
+}
+
+const char* enumValueToLongString(AspartateStates enumValue)
+{
+    constexpr gmx::EnumerationArray<AspartateStates, const char*> aspartateStateLongNames = {
+        "Not protonated (charge -1)", "Protonated (charge 0)"
+    };
+    return aspartateStateLongNames[enumValue];
+}
+
+enum class GlutamateStates : int
+{
+    Deprot,
+    Prot,
+    Count
+};
+
+const char* enumValueToString(GlutamateStates enumValue)
+{
+    constexpr gmx::EnumerationArray<GlutamateStates, const char*> glutamateStateNames = { "GLU",
+                                                                                          "GLUH" };
+    return glutamateStateNames[enumValue];
+}
+
+const char* enumValueToLongString(GlutamateStates enumValue)
+{
+    constexpr gmx::EnumerationArray<GlutamateStates, const char*> glutamateStateLongNames = {
+        "Not protonated (charge -1)", "Protonated (charge 0)"
+    };
+    return glutamateStateLongNames[enumValue];
+}
+
+enum class GlutamineStates : int
+{
+    Deprot,
+    Prot,
+    Count
+};
+
+const char* enumValueToString(GlutamineStates enumValue)
+{
+    constexpr gmx::EnumerationArray<GlutamineStates, const char*> glutamineStateNames = { "GLN",
+                                                                                          "QLN" };
+    return glutamineStateNames[enumValue];
+}
+
+const char* enumValueToLongString(GlutamineStates enumValue)
+{
+    constexpr gmx::EnumerationArray<GlutamineStates, const char*> glutamineStateLongNames = {
+        "Not protonated (charge 0)", "Protonated (charge +1)"
+    };
+    return glutamineStateLongNames[enumValue];
+}
+
+enum class LysineStates : int
+{
+    Deprot,
+    Prot,
+    Count
+};
+
+const char* enumValueToString(LysineStates enumValue)
+{
+    constexpr gmx::EnumerationArray<LysineStates, const char*> lysineStateNames = { "LYSN", "LYS" };
+    return lysineStateNames[enumValue];
+}
+
+const char* enumValueToLongString(LysineStates enumValue)
+{
+    constexpr gmx::EnumerationArray<LysineStates, const char*> lysineStateLongNames = {
+        "Not protonated (charge 0)", "Protonated (charge +1)"
+    };
+    return lysineStateLongNames[enumValue];
+}
+
+enum class ArginineStates : int
+{
+    Deprot,
+    Prot,
+    Count
+};
+
+const char* enumValueToString(ArginineStates enumValue)
+{
+    constexpr gmx::EnumerationArray<ArginineStates, const char*> arginineStatesNames = { "ARGN",
+                                                                                         "ARG" };
+    return arginineStatesNames[enumValue];
+}
+
+const char* enumValueToLongString(ArginineStates enumValue)
+{
+    constexpr gmx::EnumerationArray<ArginineStates, const char*> arginineStatesLongNames = {
+        "Not protonated (charge 0)", "Protonated (charge +1)"
+    };
+    return arginineStatesLongNames[enumValue];
+}
+
+template<typename EnumType>
+const char* select_res(int resnr, const char* title, gmx::ArrayRef<const RtpRename> rr)
 {
     printf("Which %s type do you want for residue %d\n", title, resnr + 1);
-    for (int sel = 0; (sel < nr); sel++)
+    for (auto sel : gmx::EnumerationWrapper<EnumType>{})
     {
-        printf("%d. %s (%s)\n", sel, expl[sel], res2bb_notermini(name[sel], rr));
+        printf("%d. %s (%s)\n",
+               static_cast<int>(sel),
+               enumValueToString(sel),
+               res2bb_notermini(enumValueToString(sel), rr));
     }
     printf("\nType a number:");
     fflush(stdout);
@@ -142,85 +255,37 @@ const char* select_res(int                            nr,
         gmx_fatal(FARGS, "Answer me for res %s %d!", title, resnr + 1);
     }
 
-    return name[userSelection];
+    return enumValueToLongString(static_cast<EnumType>(userSelection));
 }
 
 const char* get_asptp(int resnr, gmx::ArrayRef<const RtpRename> rr)
 {
-    enum
-    {
-        easp,
-        easpH,
-        easpNR
-    };
-    const char* lh[easpNR]   = { "ASP", "ASPH" };
-    const char* expl[easpNR] = { "Not protonated (charge -1)", "Protonated (charge 0)" };
-
-    return select_res(easpNR, resnr, lh, expl, "ASPARTIC ACID", rr);
+    return select_res<AspartateStates>(resnr, "ASPARTIC ACID", rr);
 }
 
 const char* get_glutp(int resnr, gmx::ArrayRef<const RtpRename> rr)
 {
-    enum
-    {
-        eglu,
-        egluH,
-        egluNR
-    };
-    const char* lh[egluNR]   = { "GLU", "GLUH" };
-    const char* expl[egluNR] = { "Not protonated (charge -1)", "Protonated (charge 0)" };
-
-    return select_res(egluNR, resnr, lh, expl, "GLUTAMIC ACID", rr);
+    return select_res<GlutamateStates>(resnr, "GLUTAMIC ACID", rr);
 }
 
 const char* get_glntp(int resnr, gmx::ArrayRef<const RtpRename> rr)
 {
-    enum
-    {
-        egln,
-        eglnH,
-        eglnNR
-    };
-    const char* lh[eglnNR]   = { "GLN", "QLN" };
-    const char* expl[eglnNR] = { "Not protonated (charge 0)", "Protonated (charge +1)" };
-
-    return select_res(eglnNR, resnr, lh, expl, "GLUTAMINE", rr);
+    return select_res<GlutamineStates>(resnr, "GLUTAMINE", rr);
 }
 
 const char* get_lystp(int resnr, gmx::ArrayRef<const RtpRename> rr)
 {
-    enum
-    {
-        elys,
-        elysH,
-        elysNR
-    };
-    const char* lh[elysNR]   = { "LYSN", "LYS" };
-    const char* expl[elysNR] = { "Not protonated (charge 0)", "Protonated (charge +1)" };
-
-    return select_res(elysNR, resnr, lh, expl, "LYSINE", rr);
+    return select_res<LysineStates>(resnr, "LYSINE", rr);
 }
 
 const char* get_argtp(int resnr, gmx::ArrayRef<const RtpRename> rr)
 {
-    enum
-    {
-        earg,
-        eargH,
-        eargNR
-    };
-    const char* lh[eargNR]   = { "ARGN", "ARG" };
-    const char* expl[eargNR] = { "Not protonated (charge 0)", "Protonated (charge +1)" };
-
-    return select_res(eargNR, resnr, lh, expl, "ARGININE", rr);
+    return select_res<ArginineStates>(resnr, "ARGININE", rr);
 }
 
 const char* get_histp(int resnr, gmx::ArrayRef<const RtpRename> rr)
 {
-    const char* expl[ehisNR] = { "H on ND1 only", "H on NE2 only", "H on ND1 and NE2",
-                                 "Coupled to Heme" };
-
-    return select_res(ehisNR, resnr, hh, expl, "HISTIDINE", rr);
+    return select_res<HistidineStates>(resnr, "HISTIDINE", rr);
 }
 
 void read_rtprename(const char* fname, FILE* fp, std::vector<RtpRename>* rtprename)
@@ -251,8 +316,12 @@ void read_rtprename(const char* fname, FILE* fp, std::vector<RtpRename>* rtprena
         {
             if (nc != 2 && nc != 5)
             {
-                gmx_fatal(FARGS, "Residue renaming database '%s' has %d columns instead of %d or %d",
-                          fname, ncol, 2, 5);
+                gmx_fatal(FARGS,
+                          "Residue renaming database '%s' has %d columns instead of %d or %d",
+                          fname,
+                          ncol,
+                          2,
+                          5);
             }
             ncol = nc;
         }
@@ -261,7 +330,9 @@ void read_rtprename(const char* fname, FILE* fp, std::vector<RtpRename>* rtprena
             gmx_fatal(FARGS,
                       "A line in residue renaming database '%s' has %d columns, while previous "
                       "lines have %d columns",
-                      fname, nc, ncol);
+                      fname,
+                      nc,
+                      ncol);
         }
 
         if (nc == 2)
@@ -307,7 +378,9 @@ std::string search_resrename(gmx::ArrayRef<const RtpRename> rr, const char* name
 
         if (newName[0] == '-')
         {
-            gmx_fatal(FARGS, "In the chosen force field there is no residue type for '%s'%s", name,
+            gmx_fatal(FARGS,
+                      "In the chosen force field there is no residue type for '%s'%s",
+                      name,
                       bStart ? (bEnd ? " as a standalone (starting & ending) residue" : " as a starting terminus")
                              : (bEnd ? " as an ending terminus" : ""));
         }
@@ -365,7 +438,8 @@ void rename_resrtp(t_atoms*                       pdba,
                 GMX_LOG(logger.info)
                         .asParagraph()
                         .appendTextFormatted("Changing rtp entry of residue %d %s to '%s'",
-                                             pdba->resinfo[r].nr, *pdba->resinfo[r].name,
+                                             pdba->resinfo[r].nr,
+                                             *pdba->resinfo[r].name,
                                              newName.c_str());
             }
             pdba->resinfo[r].rtp = put_symtab(symtab, newName.c_str());
@@ -442,7 +516,10 @@ void renameResidue(const gmx::MDLogger& logger,
                 .appendTextFormatted(
                         "Replaced %d residue%s named %s to the default %s. Use interactive "
                         "selection of protonated residues if that is what you need.",
-                        numMatchesFound, numMatchesFound > 1 ? "s" : "", oldnm, newnm);
+                        numMatchesFound,
+                        numMatchesFound > 1 ? "s" : "",
+                        oldnm,
+                        newnm);
     }
 }
 
@@ -502,7 +579,8 @@ void check_occupancy(t_atoms* atoms, const char* filename, bool bVerbose, const
                             .appendTextFormatted("Occupancy for atom %s%d-%s is %f rather than 1",
                                                  *atoms->resinfo[atoms->atom[i].resind].name,
                                                  atoms->resinfo[atoms->atom[i].resind].nr,
-                                                 *atoms->atomname[i], atoms->pdbinfo[i].occup);
+                                                 *atoms->atomname[i],
+                                                 atoms->pdbinfo[i].occup);
                 }
                 if (atoms->pdbinfo[i].occup == 0)
                 {
@@ -529,7 +607,9 @@ void check_occupancy(t_atoms* atoms, const char* filename, bool bVerbose, const
                             "there were %d atoms with zero occupancy and %d atoms with "
                             "         occupancy unequal to one (out of %d atoms). Check your pdb "
                             "file.",
-                            nzero, nnotone, atoms->nr);
+                            nzero,
+                            nnotone,
+                            atoms->nr);
         }
         else
         {
@@ -552,7 +632,11 @@ void write_posres(const char* fn, t_atoms* pdba, real fc)
             "\n"
             "[ position_restraints ]\n"
             "; %4s%6s%8s%8s%8s\n",
-            "atom", "type", "fx", "fy", "fz");
+            "atom",
+            "type",
+            "fx",
+            "fy",
+            "fz");
     for (i = 0; (i < pdba->nr); i++)
     {
         if (!is_hydrogen(*pdba->atomname[i]) && !is_dummymass(*pdba->atomname[i]))
@@ -766,15 +850,18 @@ void sort_pdbatoms(gmx::ArrayRef<const PreprocessResidue> restp_chain,
         atomnm                                  = *pdba->atomname[i];
         const PreprocessResidue* localPpResidue = &restp_chain[pdba->atom[i].resind];
         auto                     found =
-                std::find_if(localPpResidue->atomname.begin(), localPpResidue->atomname.end(),
+                std::find_if(localPpResidue->atomname.begin(),
+                             localPpResidue->atomname.end(),
                              [&atomnm](char** it) { return gmx::equalCaseInsensitive(atomnm, *it); });
         if (found == localPpResidue->atomname.end())
         {
             std::string buf = gmx::formatString(
                     "Atom %s in residue %s %d was not found in rtp entry %s with %d atoms\n"
                     "while sorting atoms.\n%s",
-                    atomnm, *pdba->resinfo[pdba->atom[i].resind].name,
-                    pdba->resinfo[pdba->atom[i].resind].nr, localPpResidue->resname.c_str(),
+                    atomnm,
+                    *pdba->resinfo[pdba->atom[i].resind].name,
+                    pdba->resinfo[pdba->atom[i].resind].nr,
+                    localPpResidue->resname.c_str(),
                     localPpResidue->natom(),
                     is_hydrogen(atomnm)
                             ? "\nFor a hydrogen, this can be a different protonation state, or it\n"
@@ -848,7 +935,10 @@ int remove_duplicate_atoms(t_atoms* pdba, gmx::ArrayRef<gmx::RVec> x, bool bVerb
                 GMX_LOG(logger.info)
                         .asParagraph()
                         .appendTextFormatted("deleting duplicate atom %4s  %s%4d%c",
-                                             *pdba->atomname[i], *ri->name, ri->nr, ri->ic);
+                                             *pdba->atomname[i],
+                                             *ri->name,
+                                             ri->nr,
+                                             ri->ic);
                 if (ri->chainid && (ri->chainid != ' '))
                 {
                     printf(" ch %c", ri->chainid);
@@ -923,8 +1013,11 @@ void checkResidueTypeSanity(t_atoms* pdba, int r0, int r1, ResidueType* rt)
         gmx_fatal(FARGS,
                   "The chain covering the range %s--%s does not have a consistent chain ID. "
                   "The first residue has ID '%c', while residue %s has ID '%c'.",
-                  startResidueString.c_str(), endResidueString.c_str(), chainID0,
-                  residueString.c_str(), chainID);
+                  startResidueString.c_str(),
+                  endResidueString.c_str(),
+                  chainID0,
+                  residueString.c_str(),
+                  chainID);
     }
 
     // At this point all residues have the same ID. If they are also non-blank
@@ -956,8 +1049,11 @@ void checkResidueTypeSanity(t_atoms* pdba, int r0, int r1, ResidueType* rt)
                       "file in the GROMACS library directory. If there are other molecules "
                       "such as ligands, they should not have the same chain ID as the "
                       "adjacent protein chain since it's a separate molecule.",
-                      startResidueString.c_str(), endResidueString.c_str(), restype0.c_str(),
-                      residueString.c_str(), restype.c_str());
+                      startResidueString.c_str(),
+                      endResidueString.c_str(),
+                      restype0.c_str(),
+                      residueString.c_str(),
+                      restype.c_str());
         }
     }
 }
@@ -1003,7 +1099,8 @@ void find_nc_ter(t_atoms* pdba, int r0, int r1, int* r_start, int* r_end, Residu
             GMX_LOG(logger.info)
                     .asParagraph()
                     .appendTextFormatted("Identified residue %s%d as a starting terminus.",
-                                         *pdba->resinfo[i].name, pdba->resinfo[i].nr);
+                                         *pdba->resinfo[i].name,
+                                         pdba->resinfo[i].nr);
             *r_start = i;
         }
         else if (gmx::equalCaseInsensitive(*startrestype, "Ion"))
@@ -1015,7 +1112,8 @@ void find_nc_ter(t_atoms* pdba, int r0, int r1, int* r_start, int* r_end, Residu
                         .appendTextFormatted(
                                 "Residue %s%d has type 'Ion', assuming it is not linked into a "
                                 "chain.",
-                                *pdba->resinfo[i].name, pdba->resinfo[i].nr);
+                                *pdba->resinfo[i].name,
+                                pdba->resinfo[i].nr);
             }
             if (ionNotes == 4)
             {
@@ -1046,7 +1144,9 @@ void find_nc_ter(t_atoms* pdba, int r0, int r1, int* r_start, int* r_end, Residu
                                     "be catastrophic if they should in fact be linked. Please "
                                     "check your structure, "
                                     "and add %s to residuetypes.dat if this was not correct.",
-                                    *pdba->resinfo[i].name, pdba->resinfo[i].nr, *pdba->resinfo[i].name);
+                                    *pdba->resinfo[i].name,
+                                    pdba->resinfo[i].nr,
+                                    *pdba->resinfo[i].name);
                 }
                 else
                 {
@@ -1061,7 +1161,8 @@ void find_nc_ter(t_atoms* pdba, int r0, int r1, int* r_start, int* r_end, Residu
                                     "and add all "
                                     "necessary residue names to residuetypes.dat if this was not "
                                     "correct.",
-                                    *pdba->resinfo[i].name, pdba->resinfo[i].nr);
+                                    *pdba->resinfo[i].name,
+                                    pdba->resinfo[i].nr);
                 }
             }
             if (startWarnings == 4)
@@ -1100,7 +1201,8 @@ void find_nc_ter(t_atoms* pdba, int r0, int r1, int* r_start, int* r_end, Residu
                             .appendTextFormatted(
                                     "Residue %s%d has type 'Ion', assuming it is not linked into a "
                                     "chain.",
-                                    *pdba->resinfo[i].name, pdba->resinfo[i].nr);
+                                    *pdba->resinfo[i].name,
+                                    pdba->resinfo[i].nr);
                 }
                 if (ionNotes == 4)
                 {
@@ -1133,9 +1235,13 @@ void find_nc_ter(t_atoms* pdba, int r0, int r1, int* r_start, int* r_end, Residu
                                     "linked. Please check your structure, and add %s to "
                                     "residuetypes.dat "
                                     "if this was not correct.",
-                                    *pdba->resinfo[i].name, pdba->resinfo[i].nr, restype->c_str(),
-                                    *pdba->resinfo[*r_start].name, pdba->resinfo[*r_start].nr,
-                                    startrestype->c_str(), *pdba->resinfo[i].name);
+                                    *pdba->resinfo[i].name,
+                                    pdba->resinfo[i].nr,
+                                    restype->c_str(),
+                                    *pdba->resinfo[*r_start].name,
+                                    pdba->resinfo[*r_start].nr,
+                                    startrestype->c_str(),
+                                    *pdba->resinfo[i].name);
                 }
                 if (endWarnings == 4)
                 {
@@ -1155,7 +1261,8 @@ void find_nc_ter(t_atoms* pdba, int r0, int r1, int* r_start, int* r_end, Residu
         GMX_LOG(logger.info)
                 .asParagraph()
                 .appendTextFormatted("Identified residue %s%d as a ending terminus.",
-                                     *pdba->resinfo[*r_end].name, pdba->resinfo[*r_end].nr);
+                                     *pdba->resinfo[*r_end].name,
+                                     pdba->resinfo[*r_end].nr);
     }
 }
 
@@ -1271,9 +1378,16 @@ void modify_chain_numbers(t_atoms* pdba, ChainSeparationType chainSeparation, co
                                         "Split the chain (and introduce termini) between residue %s%d (chain id '%c', atom %d %s)\
 "
                                         "and residue %s%d (chain id '%c', atom %d %s) ? [n/y]",
-                                        prev_resname, prev_resnum, prev_chainid, prev_atomnum,
-                                        prev_atomname, this_resname, this_resnum, this_chainid,
-                                        this_atomnum, this_atomname);
+                                        prev_resname,
+                                        prev_resnum,
+                                        prev_chainid,
+                                        prev_atomnum,
+                                        prev_atomname,
+                                        this_resname,
+                                        this_resnum,
+                                        this_chainid,
+                                        this_atomnum,
+                                        this_atomname);
 
                         if (nullptr == fgets(select, STRLEN - 1, stdin))
                         {
@@ -1320,7 +1434,7 @@ bool checkChainCyclicity(t_atoms*                               pdba,
     auto        res = getDatabaseEntry(newName, rtpFFDB);
     const char *name_ai, *name_aj;
 
-    for (const auto& patch : res->rb[ebtsBONDS].b)
+    for (const auto& patch : res->rb[BondedTypes::Bonds].b)
     { /* Search backward bond for n/5' terminus */
         name_ai = patch.ai().c_str();
         name_aj = patch.aj().c_str();
@@ -1349,7 +1463,7 @@ bool checkChainCyclicity(t_atoms*                               pdba,
             newName = rtpname;
         }
         res = getDatabaseEntry(newName, rtpFFDB);
-        for (const auto& patch : res->rb[ebtsBONDS].b)
+        for (const auto& patch : res->rb[BondedTypes::Bonds].b)
         {
             /* Seach forward bond for c/3' terminus */
             name_ai = patch.ai().c_str();
@@ -1387,7 +1501,7 @@ bool checkChainCyclicity(t_atoms*                               pdba,
 struct t_pdbchain
 {
     char             chainid   = ' ';
-    char             chainnum  = ' ';
+    int              chainnum  = ' '; // char, but stored as int to make clang-tidy happy
     int              start     = -1;
     int              natom     = -1;
     bool             bAllWat   = false;
@@ -1418,8 +1532,9 @@ enum class VSitesType : int
     Aromatics,
     Count
 };
-const gmx::EnumerationArray<VSitesType, const char*> c_vsitesTypeNames = { { "none", "hydrogens",
-                                                                             "aromatics" } };
+const gmx::EnumerationArray<VSitesType, const char*> c_vsitesTypeNames = {
+    { "none", "hydrogens", "aromatics" }
+};
 
 enum class WaterType : int
 {
@@ -1444,8 +1559,9 @@ enum class MergeType : int
     Interactive,
     Count
 };
-const gmx::EnumerationArray<MergeType, const char*> c_mergeTypeNames = { { "no", "all",
-                                                                           "interactive" } };
+const gmx::EnumerationArray<MergeType, const char*> c_mergeTypeNames = {
+    { "no", "all", "interactive" }
+};
 
 } // namespace
 
@@ -1829,8 +1945,12 @@ void pdb2gmx::optionsFinished()
     }
 
     /* Force field selection, interactive or direct */
-    choose_ff(strcmp(ff_.c_str(), "select") == 0 ? nullptr : ff_.c_str(), forcefield_,
-              sizeof(forcefield_), ffdir_, sizeof(ffdir_), loggerOwner_->logger());
+    choose_ff(strcmp(ff_.c_str(), "select") == 0 ? nullptr : ff_.c_str(),
+              forcefield_,
+              sizeof(forcefield_),
+              ffdir_,
+              sizeof(ffdir_),
+              loggerOwner_->logger());
 
     if (strlen(forcefield_) > 0)
     {
@@ -1943,8 +2063,20 @@ int pdb2gmx::run()
     PbcType        pbcType;
     t_atoms        pdba_all;
     rvec*          pdbx;
-    int natom = read_pdball(inputConfFile_.c_str(), bOutputSet_, outFile_.c_str(), &title, &pdba_all,
-                            &pdbx, &pbcType, box, bRemoveH_, &symtab, &rt, watres, &aps, bVerbose_);
+    int            natom = read_pdball(inputConfFile_.c_str(),
+                            bOutputSet_,
+                            outFile_.c_str(),
+                            &title,
+                            &pdba_all,
+                            &pdbx,
+                            &pbcType,
+                            box,
+                            bRemoveH_,
+                            &symtab,
+                            &rt,
+                            watres,
+                            &aps,
+                            bVerbose_);
 
     if (natom == 0)
     {
@@ -2018,9 +2150,16 @@ int pdb2gmx::run()
                                     "%s) and chain starting with "
                                     "residue %s%d (chain id '%c', atom %d %s) into a single "
                                     "moleculetype (keeping termini)? [n/y]",
-                                    prev_resname, prev_resnum, prev_chainid, prev_atomnum,
-                                    prev_atomname, this_resname, this_resnum, this_chainid,
-                                    this_atomnum, this_atomname);
+                                    prev_resname,
+                                    prev_resnum,
+                                    prev_chainid,
+                                    prev_atomnum,
+                                    prev_atomname,
+                                    this_resname,
+                                    this_resnum,
+                                    this_chainid,
+                                    this_atomnum,
+                                    this_atomname);
 
                     if (nullptr == fgets(select, STRLEN - 1, stdin))
                     {
@@ -2175,7 +2314,10 @@ int pdb2gmx::run()
             .appendTextFormatted(
                     "There are %d chains and %d blocks of water and "
                     "%d residues with %d atoms",
-                    numChains - nwaterchain, nwaterchain, pdba_all.nres, natom);
+                    numChains - nwaterchain,
+                    nwaterchain,
+                    pdba_all.nres,
+                    natom);
 
     GMX_LOG(logger.info)
             .asParagraph()
@@ -2184,9 +2326,12 @@ int pdb2gmx::run()
     {
         GMX_LOG(logger.info)
                 .asParagraph()
-                .appendTextFormatted("  %d '%c' %5d %6d  %s\n", i + 1,
-                                     chains[i].chainid ? chains[i].chainid : '-', chains[i].pdba->nres,
-                                     chains[i].pdba->nr, chains[i].bAllWat ? "(only water)" : "");
+                .appendTextFormatted("  %d '%c' %5d %6d  %s\n",
+                                     i + 1,
+                                     chains[i].chainid ? chains[i].chainid : '-',
+                                     chains[i].pdba->nres,
+                                     chains[i].pdba->nr,
+                                     chains[i].bAllWat ? "(only water)" : "");
     }
 
     check_occupancy(&pdba_all, inputConfFile_.c_str(), bVerbose_, logger);
@@ -2247,29 +2392,46 @@ int pdb2gmx::run()
             GMX_LOG(logger.info)
                     .asParagraph()
                     .appendTextFormatted("Processing chain %d '%c' (%d atoms, %d residues)",
-                                         chain + 1, cc->chainid, natom, nres);
+                                         chain + 1,
+                                         cc->chainid,
+                                         natom,
+                                         nres);
         }
         else
         {
             GMX_LOG(logger.info)
                     .asParagraph()
-                    .appendTextFormatted("Processing chain %d (%d atoms, %d residues)", chain + 1,
-                                         natom, nres);
-        }
-
-        process_chain(logger, pdba, x, bUnA_, bUnA_, bUnA_, bLysMan_, bAspMan_, bGluMan_, bHisMan_,
-                      bArgMan_, bGlnMan_, angle_, distance_, &symtab, rtprename);
+                    .appendTextFormatted(
+                            "Processing chain %d (%d atoms, %d residues)", chain + 1, natom, nres);
+        }
+
+        process_chain(logger,
+                      pdba,
+                      x,
+                      bUnA_,
+                      bUnA_,
+                      bUnA_,
+                      bLysMan_,
+                      bAspMan_,
+                      bGluMan_,
+                      bHisMan_,
+                      bArgMan_,
+                      bGlnMan_,
+                      angle_,
+                      distance_,
+                      &symtab,
+                      rtprename);
 
         cc->chainstart[cc->nterpairs] = pdba->nres;
         j                             = 0;
         for (int i = 0; i < cc->nterpairs; i++)
         {
-            find_nc_ter(pdba, cc->chainstart[i], cc->chainstart[i + 1], &(cc->r_start[j]),
-                        &(cc->r_end[j]), &rt, logger);
+            find_nc_ter(
+                    pdba, cc->chainstart[i], cc->chainstart[i + 1], &(cc->r_start[j]), &(cc->r_end[j]), &rt, logger);
             if (cc->r_start[j] >= 0 && cc->r_end[j] >= 0)
             {
-                if (checkChainCyclicity(pdba, pdbx, cc->r_start[j], cc->r_end[j], rtpFFDB,
-                                        rtprename, long_bond_dist_, short_bond_dist_))
+                if (checkChainCyclicity(
+                            pdba, pdbx, cc->r_start[j], cc->r_end[j], rtpFFDB, rtprename, long_bond_dist_, short_bond_dist_))
                 {
                     cc->cyclicBondsIndex.push_back(cc->r_start[j]);
                     cc->cyclicBondsIndex.push_back(cc->r_end[j]);
@@ -2328,8 +2490,10 @@ int pdb2gmx::run()
                 {
                     if (bTerMan_ && !tdblist.empty())
                     {
-                        sprintf(select, "Select start terminus type for %s-%d",
-                                *pdba->resinfo[cc->r_start[i]].name, pdba->resinfo[cc->r_start[i]].nr);
+                        sprintf(select,
+                                "Select start terminus type for %s-%d",
+                                *pdba->resinfo[cc->r_start[i]].name,
+                                pdba->resinfo[cc->r_start[i]].nr);
                         cc->ntdb.push_back(choose_ter(tdblist, select));
                     }
                     else
@@ -2337,8 +2501,10 @@ int pdb2gmx::run()
                         cc->ntdb.push_back(tdblist[0]);
                     }
 
-                    printf("Start terminus %s-%d: %s\n", *pdba->resinfo[cc->r_start[i]].name,
-                           pdba->resinfo[cc->r_start[i]].nr, (cc->ntdb[i])->name.c_str());
+                    printf("Start terminus %s-%d: %s\n",
+                           *pdba->resinfo[cc->r_start[i]].name,
+                           pdba->resinfo[cc->r_start[i]].nr,
+                           (cc->ntdb[i])->name.c_str());
                     tdblist.clear();
                 }
             }
@@ -2366,16 +2532,20 @@ int pdb2gmx::run()
                 {
                     if (bTerMan_ && !tdblist.empty())
                     {
-                        sprintf(select, "Select end terminus type for %s-%d",
-                                *pdba->resinfo[cc->r_end[i]].name, pdba->resinfo[cc->r_end[i]].nr);
+                        sprintf(select,
+                                "Select end terminus type for %s-%d",
+                                *pdba->resinfo[cc->r_end[i]].name,
+                                pdba->resinfo[cc->r_end[i]].nr);
                         cc->ctdb.push_back(choose_ter(tdblist, select));
                     }
                     else
                     {
                         cc->ctdb.push_back(tdblist[0]);
                     }
-                    printf("End terminus %s-%d: %s\n", *pdba->resinfo[cc->r_end[i]].name,
-                           pdba->resinfo[cc->r_end[i]].nr, (cc->ctdb[i])->name.c_str());
+                    printf("End terminus %s-%d: %s\n",
+                           *pdba->resinfo[cc->r_end[i]].name,
+                           pdba->resinfo[cc->r_end[i]].nr,
+                           (cc->ctdb[i])->name.c_str());
                     tdblist.clear();
                 }
             }
@@ -2387,8 +2557,19 @@ int pdb2gmx::run()
         std::vector<MoleculePatchDatabase> hb_chain;
         /* lookup hackblocks and rtp for all residues */
         std::vector<PreprocessResidue> restp_chain;
-        get_hackblocks_rtp(&hb_chain, &restp_chain, rtpFFDB, pdba->nres, pdba->resinfo, cc->nterpairs,
-                           &symtab, cc->ntdb, cc->ctdb, cc->r_start, cc->r_end, bAllowMissing_, logger);
+        get_hackblocks_rtp(&hb_chain,
+                           &restp_chain,
+                           rtpFFDB,
+                           pdba->nres,
+                           pdba->resinfo,
+                           cc->nterpairs,
+                           &symtab,
+                           cc->ntdb,
+                           cc->ctdb,
+                           cc->r_start,
+                           cc->r_end,
+                           bAllowMissing_,
+                           logger);
         /* ideally, now we would not need the rtp itself anymore, but do
            everything using the hb and restp arrays. Unfortunately, that
            requires some re-thinking of code in gen_vsite.c, which I won't
@@ -2440,8 +2621,18 @@ int pdb2gmx::run()
                 .asParagraph()
                 .appendTextFormatted(
                         "Generating any missing hydrogen atoms and/or adding termini.");
-        add_h(&pdba, &localAtoms[chain], &x, ah, &symtab, cc->nterpairs, cc->ntdb, cc->ctdb,
-              cc->r_start, cc->r_end, bAllowMissing_, cc->cyclicBondsIndex);
+        add_h(&pdba,
+              &localAtoms[chain],
+              &x,
+              ah,
+              &symtab,
+              cc->nterpairs,
+              cc->ntdb,
+              cc->ctdb,
+              cc->r_start,
+              cc->r_end,
+              bAllowMissing_,
+              cc->cyclicBondsIndex);
         GMX_LOG(logger.info)
                 .asParagraph()
                 .appendTextFormatted("Now there are %d residues with %d atoms", pdba->nres, pdba->nr);
@@ -2554,10 +2745,31 @@ int pdb2gmx::run()
             top_file2 = top_file;
         }
 
-        pdb2top(top_file2, posre_fn.c_str(), molname.c_str(), pdba, &x, &atype, &symtab, rtpFFDB,
-                restp_chain, hb_chain, bAllowMissing_, bVsites_, bVsiteAromatics_, ffdir_, mHmult_,
-                ssbonds, long_bond_dist_, short_bond_dist_, bDeuterate_, bChargeGroups_, bCmap_,
-                bRenumRes_, bRTPresname_, cc->cyclicBondsIndex, logger);
+        pdb2top(top_file2,
+                posre_fn.c_str(),
+                molname.c_str(),
+                pdba,
+                &x,
+                &atype,
+                &symtab,
+                rtpFFDB,
+                restp_chain,
+                hb_chain,
+                bAllowMissing_,
+                bVsites_,
+                bVsiteAromatics_,
+                ffdir_,
+                mHmult_,
+                ssbonds,
+                long_bond_dist_,
+                short_bond_dist_,
+                bDeuterate_,
+                bChargeGroups_,
+                bCmap_,
+                bRenumRes_,
+                bRTPresname_,
+                cc->cyclicBondsIndex,
+                logger);
 
         if (!cc->bAllWat)
         {
@@ -2597,7 +2809,8 @@ int pdb2gmx::run()
                     "The topology file '%s' for the selected water "
                     "model '%s' can not be found in the force field "
                     "directory. Select a different water model.",
-                    waterFile.c_str(), watermodel_);
+                    waterFile.c_str(),
+                    watermodel_);
             GMX_THROW(InconsistentInputError(message));
         }
     }
@@ -2632,7 +2845,9 @@ int pdb2gmx::run()
             GMX_LOG(logger.info)
                     .asParagraph()
                     .appendTextFormatted("Including chain %d in system: %d atoms %d residues",
-                                         i + 1, chains[i].pdba->nr, chains[i].pdba->nres);
+                                         i + 1,
+                                         chains[i].pdba->nr,
+                                         chains[i].pdba->nres);
         }
         for (int j = 0; (j < chains[i].pdba->nr); j++)
         {
@@ -2670,8 +2885,8 @@ int pdb2gmx::run()
     {
         make_new_box(atoms->nr, gmx::as_rvec_array(x.data()), box, box_space, false);
     }
-    write_sto_conf(outputConfFile_.c_str(), title, atoms, gmx::as_rvec_array(x.data()), nullptr,
-                   pbcType, box);
+    write_sto_conf(
+            outputConfFile_.c_str(), title, atoms, gmx::as_rvec_array(x.data()), nullptr, pbcType, box);
 
     done_symtab(&symtab);
     done_atom(&pdba_all);
@@ -2698,8 +2913,8 @@ int pdb2gmx::run()
     {
         GMX_LOG(logger.info)
                 .asParagraph()
-                .appendTextFormatted("The %s force field and the %s water model are used.", ffname_,
-                                     watermodel_);
+                .appendTextFormatted(
+                        "The %s force field and the %s water model are used.", ffname_, watermodel_);
         sfree(watermodel_);
     }
     else
index 351168fdc14c807a0b28a407182b4f7c18d0ff03..5a300debef2592d0ce05cad27a18105e194948e5 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -68,6 +68,7 @@
 #include "gromacs/utility/binaryinformation.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/dir_separator.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "hackblock.h"
 #include "resall.h"
 
-/* this must correspond to enum in pdb2top.h */
-const char* hh[ehisNR] = { "HISD", "HISE", "HISH", "HIS1" };
+const char* enumValueToString(HistidineStates enumValue)
+{
+    constexpr gmx::EnumerationArray<HistidineStates, const char*> histidineStateNames = {
+        "HISD", "HISE", "HISH", "HIS1"
+    };
+    return histidineStateNames[enumValue];
+}
 
 static int missing_atoms(const PreprocessResidue* rp, int resind, t_atoms* at, int i0, int i, const gmx::MDLogger& logger)
 {
@@ -104,7 +110,9 @@ static int missing_atoms(const PreprocessResidue* rp, int resind, t_atoms* at, i
             GMX_LOG(logger.warning)
                     .asParagraph()
                     .appendTextFormatted("atom %s is missing in residue %s %d in the pdb file",
-                                         name, *(at->resinfo[resind].name), at->resinfo[resind].nr);
+                                         name,
+                                         *(at->resinfo[resind].name),
+                                         at->resinfo[resind].nr);
             if (name[0] == 'H' || name[0] == 'h')
             {
                 GMX_LOG(logger.warning)
@@ -113,7 +121,9 @@ static int missing_atoms(const PreprocessResidue* rp, int resind, t_atoms* at, i
                                 "You might need to add atom %s to the hydrogen database of "
                                 "building block %s "
                                 "in the file %s.hdb (see the manual)",
-                                name, *(at->resinfo[resind].rtp), rp->filebase.c_str());
+                                name,
+                                *(at->resinfo[resind].rtp),
+                                rp->filebase.c_str());
             }
         }
     }
@@ -197,7 +207,8 @@ static void choose_ff_impl(const char*          ffsel,
                                 "Force field '%s' occurs in %d places. pdb2gmx is using the one in "
                                 "the current directory. Use interactive selection "
                                 "(not the -ff option) if you would prefer a different one.",
-                                ffsel, nfound);
+                                ffsel,
+                                nfound);
             }
             else
             {
@@ -206,7 +217,8 @@ static void choose_ff_impl(const char*          ffsel,
                         "the current directory.\n"
                         "Run without the -ff switch and select the force "
                         "field interactively.",
-                        ffsel, nfound);
+                        ffsel,
+                        nfound);
                 GMX_THROW(gmx::InconsistentInputError(message));
             }
         }
@@ -315,7 +327,8 @@ static void choose_ff_impl(const char*          ffsel,
                         "to point to the desired force field first, and/or "
                         "rename or move the force field directory present "
                         "in the current working directory.",
-                        ffs[sel].c_str(), fflib_forcefield_dir_ext());
+                        ffs[sel].c_str(),
+                        fflib_forcefield_dir_ext());
                 GMX_THROW(gmx::NotImplementedError(message));
             }
         }
@@ -328,7 +341,8 @@ static void choose_ff_impl(const char*          ffsel,
     if (ffs[sel].length() >= static_cast<size_t>(ff_maxlen))
     {
         std::string message = gmx::formatString("Length of force field name (%d) >= maxlen (%d)",
-                                                static_cast<int>(ffs[sel].length()), ff_maxlen);
+                                                static_cast<int>(ffs[sel].length()),
+                                                ff_maxlen);
         GMX_THROW(gmx::InvalidInputError(message));
     }
     strcpy(forcefield, ffs[sel].c_str());
@@ -345,7 +359,8 @@ static void choose_ff_impl(const char*          ffsel,
     if (ffpath.length() >= static_cast<size_t>(ffdir_maxlen))
     {
         std::string message = gmx::formatString("Length of force field dir (%d) >= maxlen (%d)",
-                                                static_cast<int>(ffpath.length()), ffdir_maxlen);
+                                                static_cast<int>(ffpath.length()),
+                                                ffdir_maxlen);
         GMX_THROW(gmx::InvalidInputError(message));
     }
     strcpy(ffdir, ffpath.c_str());
@@ -643,7 +658,7 @@ static void print_top_water(FILE* out, const char* ffdir, const char* water)
 
 static void print_top_system(FILE* out, const char* title)
 {
-    fprintf(out, "[ %s ]\n", dir2str(Directive::d_system));
+    fprintf(out, "[ %s ]\n", enumValueToString(Directive::d_system));
     fprintf(out, "; Name\n");
     fprintf(out, "%s\n\n", title[0] ? title : "Protein");
 }
@@ -674,7 +689,7 @@ void print_top_mols(FILE*                            out,
 
     if (!mols.empty())
     {
-        fprintf(out, "[ %s ]\n", dir2str(Directive::d_molecules));
+        fprintf(out, "[ %s ]\n", enumValueToString(Directive::d_molecules));
         fprintf(out, "; %-15s %5s\n", "Compound", "#mols");
         for (const auto& mol : mols)
         {
@@ -688,7 +703,7 @@ void write_top(FILE*                                   out,
                const char*                             molname,
                t_atoms*                                at,
                bool                                    bRTPresname,
-               int                                     bts[],
+               gmx::ArrayRef<const int>                bts,
                gmx::ArrayRef<const InteractionsOfType> plist,
                t_excls                                 excls[],
                PreprocessingAtomTypes*                 atype,
@@ -698,20 +713,32 @@ void write_top(FILE*                                   out,
 {
     if (at && atype && cgnr)
     {
-        fprintf(out, "[ %s ]\n", dir2str(Directive::d_moleculetype));
+        fprintf(out, "[ %s ]\n", enumValueToString(Directive::d_moleculetype));
         fprintf(out, "; %-15s %5s\n", "Name", "nrexcl");
         fprintf(out, "%-15s %5d\n\n", molname ? molname : "Protein", nrexcl);
 
         print_atoms(out, atype, at, cgnr, bRTPresname);
-        print_bondeds(out, at->nr, Directive::d_bonds, F_BONDS, bts[ebtsBONDS], plist);
+        print_bondeds(
+                out, at->nr, Directive::d_bonds, F_BONDS, bts[static_cast<int>(BondedTypes::Bonds)], plist);
         print_bondeds(out, at->nr, Directive::d_constraints, F_CONSTR, 0, plist);
         print_bondeds(out, at->nr, Directive::d_constraints, F_CONSTRNC, 0, plist);
         print_bondeds(out, at->nr, Directive::d_pairs, F_LJ14, 0, plist);
         print_excl(out, at->nr, excls);
-        print_bondeds(out, at->nr, Directive::d_angles, F_ANGLES, bts[ebtsANGLES], plist);
-        print_bondeds(out, at->nr, Directive::d_dihedrals, F_PDIHS, bts[ebtsPDIHS], plist);
-        print_bondeds(out, at->nr, Directive::d_dihedrals, F_IDIHS, bts[ebtsIDIHS], plist);
-        print_bondeds(out, at->nr, Directive::d_cmap, F_CMAP, bts[ebtsCMAP], plist);
+        print_bondeds(
+                out, at->nr, Directive::d_angles, F_ANGLES, bts[static_cast<int>(BondedTypes::Angles)], plist);
+        print_bondeds(out,
+                      at->nr,
+                      Directive::d_dihedrals,
+                      F_PDIHS,
+                      bts[static_cast<int>(BondedTypes::ProperDihedrals)],
+                      plist);
+        print_bondeds(out,
+                      at->nr,
+                      Directive::d_dihedrals,
+                      F_IDIHS,
+                      bts[static_cast<int>(BondedTypes::ImproperDihedrals)],
+                      plist);
+        print_bondeds(out, at->nr, Directive::d_cmap, F_CMAP, bts[static_cast<int>(BondedTypes::Cmap)], plist);
         print_bondeds(out, at->nr, Directive::d_polarization, F_POLARIZATION, 0, plist);
         print_bondeds(out, at->nr, Directive::d_thole_polarization, F_THOLE_POL, 0, plist);
         print_bondeds(out, at->nr, Directive::d_vsites2, F_VSITE2, 0, plist);
@@ -743,8 +770,10 @@ static void do_ssbonds(InteractionsOfType*                ps,
         int aj = search_res_atom(bond.secondAtom.c_str(), rj, atoms, "special bond", bAllowMissing);
         if ((ai == -1) || (aj == -1))
         {
-            gmx_fatal(FARGS, "Trying to make impossible special bond (%s-%s)!",
-                      bond.firstAtom.c_str(), bond.secondAtom.c_str());
+            gmx_fatal(FARGS,
+                      "Trying to make impossible special bond (%s-%s)!",
+                      bond.firstAtom.c_str(),
+                      bond.secondAtom.c_str());
         }
         add_param(ps, ai, aj, {}, nullptr);
     }
@@ -779,7 +808,7 @@ static void at2bonds(InteractionsOfType*                  psb,
     for (int resind = 0; (resind < atoms->nres) && (i < atoms->nr); resind++)
     {
         /* add bonds from list of bonded interactions */
-        for (const auto& patch : globalPatches[resind].rb[ebtsBONDS].b)
+        for (const auto& patch : globalPatches[resind].rb[BondedTypes::Bonds].b)
         {
             /* Unfortunately we can not issue errors or warnings
              * for missing atoms in bonds, as the hydrogens and terminal atoms
@@ -795,15 +824,15 @@ static void at2bonds(InteractionsOfType*                  psb,
                 {
                     GMX_LOG(logger.warning)
                             .asParagraph()
-                            .appendTextFormatted("Long Bond (%d-%d = %g nm)", ai + 1, aj + 1,
-                                                 std::sqrt(dist2));
+                            .appendTextFormatted(
+                                    "Long Bond (%d-%d = %g nm)", ai + 1, aj + 1, std::sqrt(dist2));
                 }
                 else if (dist2 < short_bond_dist2)
                 {
                     GMX_LOG(logger.warning)
                             .asParagraph()
-                            .appendTextFormatted("Short Bond (%d-%d = %g nm)", ai + 1, aj + 1,
-                                                 std::sqrt(dist2));
+                            .appendTextFormatted(
+                                    "Short Bond (%d-%d = %g nm)", ai + 1, aj + 1, std::sqrt(dist2));
                 }
                 add_param(psb, ai, aj, {}, patch.s.c_str());
             }
@@ -923,17 +952,20 @@ static void check_restp_type(const char* name, int t1, int t2)
 
 static void check_restp_types(const PreprocessResidue& r0, const PreprocessResidue& r1)
 {
-    check_restp_type("all dihedrals", static_cast<int>(r0.bKeepAllGeneratedDihedrals),
+    check_restp_type("all dihedrals",
+                     static_cast<int>(r0.bKeepAllGeneratedDihedrals),
                      static_cast<int>(r1.bKeepAllGeneratedDihedrals));
     check_restp_type("nrexcl", r0.nrexcl, r1.nrexcl);
-    check_restp_type("HH14", static_cast<int>(r0.bGenerateHH14Interactions),
+    check_restp_type("HH14",
+                     static_cast<int>(r0.bGenerateHH14Interactions),
                      static_cast<int>(r1.bGenerateHH14Interactions));
-    check_restp_type("remove dihedrals", static_cast<int>(r0.bRemoveDihedralIfWithImproper),
+    check_restp_type("remove dihedrals",
+                     static_cast<int>(r0.bRemoveDihedralIfWithImproper),
                      static_cast<int>(r1.bRemoveDihedralIfWithImproper));
 
-    for (int i = 0; i < ebtsNR; i++)
+    for (auto i : gmx::EnumerationWrapper<BondedTypes>{})
     {
-        check_restp_type(btsNames[i], r0.rb[i].type, r1.rb[i].type);
+        check_restp_type(enumValueToString(i), r0.rb[i].type, r1.rb[i].type);
     }
 }
 
@@ -1084,11 +1116,11 @@ void get_hackblocks_rtp(std::vector<MoleculePatchDatabase>*    globalPatches,
             if (patch->nr != 0)
             {
                 /* find atom in restp */
-                auto found = std::find_if(posres->atomname.begin(), posres->atomname.end(),
-                                          [&patch](char** name) {
-                                              return (patch->oname.empty() && patch->a[0] == *name)
-                                                     || (patch->oname == *name);
-                                          });
+                auto found = std::find_if(
+                        posres->atomname.begin(), posres->atomname.end(), [&patch](char** name) {
+                            return (patch->oname.empty() && patch->a[0] == *name)
+                                   || (patch->oname == *name);
+                        });
 
                 if (found == posres->atomname.end())
                 {
@@ -1105,7 +1137,8 @@ void get_hackblocks_rtp(std::vector<MoleculePatchDatabase>*    globalPatches,
                                   "atom %s not found in buiding block %d%s "
                                   "while combining tdb and rtp",
                                   patch->oname.empty() ? patch->a[0].c_str() : patch->oname.c_str(),
-                                  pos + 1, *resinfo[pos].rtp);
+                                  pos + 1,
+                                  *resinfo[pos].rtp);
                     }
                 }
                 else
@@ -1221,7 +1254,8 @@ static bool match_atomnames_with_rtp_atom(t_atoms*                     pdba,
             /* This atom still has the old name, rename it */
             std::string newnm = patch->nname;
             auto        found = std::find_if(
-                    localPpResidue->atomname.begin(), localPpResidue->atomname.end(),
+                    localPpResidue->atomname.begin(),
+                    localPpResidue->atomname.end(),
                     [&newnm](char** name) { return gmx::equalCaseInsensitive(newnm, *name); });
             if (found == localPpResidue->atomname.end())
             {
@@ -1234,7 +1268,8 @@ static bool match_atomnames_with_rtp_atom(t_atoms*                     pdba,
                  */
                 bool bFoundInAdd = false;
                 for (auto rtpModification = singlePatch.hack.begin();
-                     rtpModification != singlePatch.hack.end(); rtpModification++)
+                     rtpModification != singlePatch.hack.end();
+                     rtpModification++)
                 {
                     int         k = std::distance(localPpResidue->atomname.begin(), found);
                     std::string start_at;
@@ -1247,23 +1282,26 @@ static bool match_atomnames_with_rtp_atom(t_atoms*                     pdba,
                         }
                         else
                         {
-                            start_at = gmx::formatString("%s%d", singlePatch.hack[k].nname.c_str(),
-                                                         anmnr - 1);
+                            start_at = gmx::formatString(
+                                    "%s%d", singlePatch.hack[k].nname.c_str(), anmnr - 1);
                         }
-                        auto found2 =
-                                std::find_if(localPpResidue->atomname.begin(),
-                                             localPpResidue->atomname.end(), [&start_at](char** name) {
-                                                 return gmx::equalCaseInsensitive(start_at, *name);
-                                             });
+                        auto found2 = std::find_if(localPpResidue->atomname.begin(),
+                                                   localPpResidue->atomname.end(),
+                                                   [&start_at](char** name) {
+                                                       return gmx::equalCaseInsensitive(start_at, *name);
+                                                   });
                         if (found2 == localPpResidue->atomname.end())
                         {
                             gmx_fatal(FARGS,
                                       "Could not find atom '%s' in residue building block '%s' to "
                                       "add atom '%s' to",
-                                      start_at.c_str(), localPpResidue->resname.c_str(), newnm.c_str());
+                                      start_at.c_str(),
+                                      localPpResidue->resname.c_str(),
+                                      newnm.c_str());
                         }
                         /* We can add the atom after atom start_nr */
-                        add_atom_to_restp(localPpResidue, symtab,
+                        add_atom_to_restp(localPpResidue,
+                                          symtab,
                                           std::distance(localPpResidue->atomname.begin(), found2),
                                           &(*patch));
 
@@ -1277,7 +1315,9 @@ static bool match_atomnames_with_rtp_atom(t_atoms*                     pdba,
                               "Could not find an 'add' entry for atom named '%s' corresponding to "
                               "the 'replace' entry from atom name '%s' to '%s' for tdb or hdb "
                               "database of residue type '%s'",
-                              newnm.c_str(), patch->oname.c_str(), patch->nname.c_str(),
+                              newnm.c_str(),
+                              patch->oname.c_str(),
+                              patch->nname.c_str(),
                               localPpResidue->resname.c_str());
                 }
             }
@@ -1286,8 +1326,11 @@ static bool match_atomnames_with_rtp_atom(t_atoms*                     pdba,
             {
                 GMX_LOG(logger.info)
                         .asParagraph()
-                        .appendTextFormatted("Renaming atom '%s' in residue '%s' %d to '%s'", oldnm,
-                                             localPpResidue->resname.c_str(), resnr, newnm.c_str());
+                        .appendTextFormatted("Renaming atom '%s' in residue '%s' %d to '%s'",
+                                             oldnm,
+                                             localPpResidue->resname.c_str(),
+                                             resnr,
+                                             newnm.c_str());
             }
             /* Rename the atom in pdba */
             pdba->atomname[atind] = put_symtab(symtab, newnm.c_str());
@@ -1299,7 +1342,8 @@ static bool match_atomnames_with_rtp_atom(t_atoms*                     pdba,
              * in the rtp entry of this residue.
              */
             auto found3 = std::find_if(
-                    localPpResidue->atomname.begin(), localPpResidue->atomname.end(),
+                    localPpResidue->atomname.begin(),
+                    localPpResidue->atomname.end(),
                     [&oldnm](char** name) { return gmx::equalCaseInsensitive(oldnm, *name); });
             if (found3 == localPpResidue->atomname.end())
             {
@@ -1310,8 +1354,10 @@ static bool match_atomnames_with_rtp_atom(t_atoms*                     pdba,
                 {
                     GMX_LOG(logger.info)
                             .asParagraph()
-                            .appendTextFormatted("Deleting atom '%s' in residue '%s' %d", oldnm,
-                                                 localPpResidue->resname.c_str(), resnr);
+                            .appendTextFormatted("Deleting atom '%s' in residue '%s' %d",
+                                                 oldnm,
+                                                 localPpResidue->resname.c_str(),
+                                                 resnr);
                 }
                 /* We should free the atom name,
                  * but it might be used multiple times in the symtab.
@@ -1345,13 +1391,14 @@ void match_atomnames_with_rtp(gmx::ArrayRef<PreprocessResidue>     usedPpResidue
         const char*        oldnm          = *pdba->atomname[i];
         PreprocessResidue* localPpResidue = &usedPpResidues[pdba->atom[i].resind];
         auto               found          = std::find_if(
-                localPpResidue->atomname.begin(), localPpResidue->atomname.end(),
-                [&oldnm](char** name) { return gmx::equalCaseInsensitive(oldnm, *name); });
+                localPpResidue->atomname.begin(), localPpResidue->atomname.end(), [&oldnm](char** name) {
+                    return gmx::equalCaseInsensitive(oldnm, *name);
+                });
         if (found == localPpResidue->atomname.end())
         {
             /* Not found yet, check if we have to rename this atom */
-            if (match_atomnames_with_rtp_atom(pdba, x, symtab, i, localPpResidue,
-                                              globalPatches[pdba->atom[i].resind], bVerbose, logger))
+            if (match_atomnames_with_rtp_atom(
+                        pdba, x, symtab, i, localPpResidue, globalPatches[pdba->atom[i].resind], bVerbose, logger))
             {
                 /* We deleted this atom, decrease the atom counter by 1. */
                 i--;
@@ -1393,7 +1440,7 @@ static void gen_cmap(InteractionsOfType*                    psb,
     for (residx = 0; residx < nres; residx++)
     {
         /* Add CMAP terms from the list of CMAP interactions */
-        for (const auto& b : usedPpResidues[residx].rb[ebtsCMAP].b)
+        for (const auto& b : usedPpResidues[residx].rb[BondedTypes::Cmap].b)
         {
             bool bAddCMAP = true;
             /* Loop over atoms in a candidate CMAP interaction and
@@ -1451,8 +1498,13 @@ static void gen_cmap(InteractionsOfType*                    psb,
 
             if (bAddCMAP)
             {
-                add_cmap_param(psb, cmap_atomid[0], cmap_atomid[1], cmap_atomid[2], cmap_atomid[3],
-                               cmap_atomid[4], b.s.c_str());
+                add_cmap_param(psb,
+                               cmap_atomid[0],
+                               cmap_atomid[1],
+                               cmap_atomid[2],
+                               cmap_atomid[3],
+                               cmap_atomid[4],
+                               b.s.c_str());
             }
         }
 
@@ -1504,18 +1556,17 @@ void pdb2top(FILE*                                  top_file,
              gmx::ArrayRef<const int>               cyclicBondsIndex,
              const gmx::MDLogger&                   logger)
 {
-    std::array<InteractionsOfType, F_NRE> plist;
-    t_excls*                              excls;
-    int*                                  cgnr;
-    int*                                  vsite_type;
-    int                                   i, nmissat;
-    int                                   bts[ebtsNR];
+    std::array<InteractionsOfType, F_NRE>   plist;
+    t_excls*                                excls;
+    int*                                    cgnr;
+    int*                                    vsite_type;
+    int                                     i, nmissat;
+    gmx::EnumerationArray<BondedTypes, int> bts;
 
     ResidueType rt;
 
     /* Make bonds */
-    at2bonds(&(plist[F_BONDS]), globalPatches, atoms, *x, long_bond_dist, short_bond_dist,
-             cyclicBondsIndex, logger);
+    at2bonds(&(plist[F_BONDS]), globalPatches, atoms, *x, long_bond_dist, short_bond_dist, cyclicBondsIndex, logger);
 
     /* specbonds: disulphide bonds & heme-his */
     do_ssbonds(&(plist[F_BONDS]), atoms, ssbonds, bAllowMissing);
@@ -1534,7 +1585,8 @@ void pdb2top(FILE*                                  top_file,
             gmx_fatal(FARGS,
                       "There were %d missing atoms in molecule %s, if you want to use this "
                       "incomplete topology anyhow, use the option -missing",
-                      nmissat, molname);
+                      nmissat,
+                      molname);
         }
     }
 
@@ -1595,8 +1647,11 @@ void pdb2top(FILE*                                  top_file,
             .appendTextFormatted(
                     "There are %4zu dihedrals, %4zu impropers, %4zu angles\n"
                     "          %4zu pairs,     %4zu bonds and  %4zu virtual sites",
-                    plist[F_PDIHS].size(), plist[F_IDIHS].size(), plist[F_ANGLES].size(),
-                    plist[F_LJ14].size(), plist[F_BONDS].size(),
+                    plist[F_PDIHS].size(),
+                    plist[F_IDIHS].size(),
+                    plist[F_ANGLES].size(),
+                    plist[F_LJ14].size(),
+                    plist[F_BONDS].size(),
                     plist[F_VSITE2].size() + plist[F_VSITE3].size() + plist[F_VSITE3FD].size()
                             + plist[F_VSITE3FAD].size() + plist[F_VSITE3OUT].size()
                             + plist[F_VSITE4FD].size() + plist[F_VSITE4FDN].size());
@@ -1623,11 +1678,20 @@ void pdb2top(FILE*                                  top_file,
         /* We can copy the bonded types from the first restp,
          * since the types have to be identical for all residues in one molecule.
          */
-        for (i = 0; i < ebtsNR; i++)
+        for (auto i : gmx::EnumerationWrapper<BondedTypes>{})
         {
             bts[i] = usedPpResidues[0].rb[i].type;
         }
-        write_top(top_file, posre_fn, molname, atoms, bRTPresname, bts, plist, excls, atype, cgnr,
+        write_top(top_file,
+                  posre_fn,
+                  molname,
+                  atoms,
+                  bRTPresname,
+                  bts,
+                  plist,
+                  excls,
+                  atype,
+                  cgnr,
                   usedPpResidues[0].nrexcl);
     }
 
index 77d7f4b8cde4f42bd2f59a6ba6cbae4eb95b602c..c7c8ff2b1d87a81bd22acc3806a65f6832f96101 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,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <vector>
 
 #include "gromacs/math/vectypes.h"
+#include "gromacs/utility/enumerationhelpers.h"
 
 class PreprocessingAtomTypes;
 
@@ -64,16 +65,16 @@ struct PreprocessResidue;
 struct DisulfideBond;
 struct t_symtab;
 
-/* this *MUST* correspond to array in pdb2top.c */
-enum
+/* this *MUST* correspond to array in pdb2top.cpp */
+enum class HistidineStates : int
 {
-    ehisA,
-    ehisB,
-    ehisH,
-    ehis1,
-    ehisNR
+    A,
+    B,
+    H,
+    One,
+    Count
 };
-extern const char* hh[ehisNR];
+const char* enumValueToString(HistidineStates enumValue);
 
 void choose_ff(const char*          ffsel,
                char*                forcefield,
@@ -137,7 +138,7 @@ void write_top(FILE*                                   out,
                const char*                             molname,
                t_atoms*                                at,
                bool                                    bRTPresname,
-               int                                     bts[],
+               gmx::ArrayRef<const int>                bts,
                gmx::ArrayRef<const InteractionsOfType> plist,
                t_excls                                 excls[],
                PreprocessingAtomTypes*                 atype,
index c9387601d51dfbc63a0e8b7086e698902923a6f2..1c0afb4d8ec06c438bd7913111431e031f8969ab 100644 (file)
@@ -65,22 +65,29 @@ static void atom_not_found(int         fatal_errno,
     {
         if (0 != strcmp(bondtype, "atom"))
         {
-            snprintf(message_buffer, 1024,
+            snprintf(message_buffer,
+                     1024,
                      "Residue %d named %s of a molecule in the input file was mapped\n"
                      "to an entry in the topology database, but the atom %s used in\n"
                      "an interaction of type %s in that entry is not found in the\n"
                      "input file. Perhaps your atom and/or residue naming needs to be\n"
                      "fixed.\n",
-                     resind + 1, resname, atomname, bondtype);
+                     resind + 1,
+                     resname,
+                     atomname,
+                     bondtype);
         }
         else
         {
-            snprintf(message_buffer, 1024,
+            snprintf(message_buffer,
+                     1024,
                      "Residue %d named %s of a molecule in the input file was mapped\n"
                      "to an entry in the topology database, but the atom %s used in\n"
                      "that entry is not found in the input file. Perhaps your atom\n"
                      "and/or residue naming needs to be fixed.\n",
-                     resind + 1, resname, atomname);
+                     resind + 1,
+                     resname,
+                     atomname);
         }
         if (bAllowMissing)
         {
@@ -148,8 +155,7 @@ int search_atom(const char*              type,
         }
         if (!(bNext && at[start].resind == at[natoms - 1].resind))
         {
-            atom_not_found(FARGS, type, at[start].resind, *atoms->resinfo[resind].name, bondtype,
-                           bAllowMissing);
+            atom_not_found(FARGS, type, at[start].resind, *atoms->resinfo[resind].name, bondtype, bAllowMissing);
         }
     }
     else
@@ -188,8 +194,7 @@ int search_atom(const char*              type,
         }
         if (start > 0)
         {
-            atom_not_found(FARGS, type, at[start].resind, *atoms->resinfo[resind].name, bondtype,
-                           bAllowMissing);
+            atom_not_found(FARGS, type, at[start].resind, *atoms->resinfo[resind].name, bondtype, bAllowMissing);
         }
     }
     return -1;
index 2ca9db05869697bb49dd33d1649bc8b9e1bcb3f2..54008d57b91a7e56c63621fdbc9e502c6c4e874b 100644 (file)
@@ -46,6 +46,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <numeric>
 #include <string>
 
 #include "gromacs/applied_forces/awh/read_params.h"
 #include "gromacs/gmxpreprocess/toputil.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/calc_verletbuf.h"
 #include "gromacs/mdrun/mdmodules.h"
+#include "gromacs/mdtypes/awh_params.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/multipletimestepping.h"
@@ -83,7 +86,7 @@
 #include "gromacs/utility/keyvaluetreebuilder.h"
 #include "gromacs/utility/keyvaluetreemdpwriter.h"
 #include "gromacs/utility/keyvaluetreetransform.h"
-#include "gromacs/utility/mdmodulenotification.h"
+#include "gromacs/utility/mdmodulesnotifiers.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/strconvert.h"
 #include "gromacs/utility/stringcompare.h"
@@ -104,18 +107,18 @@ using gmx::BasicVector;
 
 struct gmx_inputrec_strings
 {
-    char tcgrps[STRLEN], tau_t[STRLEN], ref_t[STRLEN], acc[STRLEN], accgrps[STRLEN], freeze[STRLEN],
-            frdim[STRLEN], energy[STRLEN], user1[STRLEN], user2[STRLEN], vcm[STRLEN],
-            x_compressed_groups[STRLEN], couple_moltype[STRLEN], orirefitgrp[STRLEN],
-            egptable[STRLEN], egpexcl[STRLEN], wall_atomtype[STRLEN], wall_density[STRLEN],
-            deform[STRLEN], QMMM[STRLEN], imd_grp[STRLEN];
-    char                     fep_lambda[efptNR][STRLEN];
-    char                     lambda_weights[STRLEN];
-    std::vector<std::string> pullGroupNames;
-    std::vector<std::string> rotateGroupNames;
+    char tcgrps[STRLEN], tau_t[STRLEN], ref_t[STRLEN], freeze[STRLEN], frdim[STRLEN],
+            energy[STRLEN], user1[STRLEN], user2[STRLEN], vcm[STRLEN], x_compressed_groups[STRLEN],
+            couple_moltype[STRLEN], orirefitgrp[STRLEN], egptable[STRLEN], egpexcl[STRLEN],
+            wall_atomtype[STRLEN], wall_density[STRLEN], deform[STRLEN], QMMM[STRLEN], imd_grp[STRLEN];
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, std::string> fep_lambda;
+    char                                                                   lambda_weights[STRLEN];
+    std::vector<std::string>                                               pullGroupNames;
+    std::vector<std::string>                                               rotateGroupNames;
     char anneal[STRLEN], anneal_npoints[STRLEN], anneal_time[STRLEN], anneal_temp[STRLEN];
 };
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static gmx_inputrec_strings* inputrecStrings = nullptr;
 
 void init_inputrec_strings()
@@ -147,12 +150,14 @@ enum
                         * make a rest group for the remaining particles.    */
 };
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static const char* constraints[eshNR + 1] = { "none",     "h-bonds",    "all-bonds",
                                               "h-angles", "all-angles", nullptr };
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static const char* couple_lam[ecouplamNR + 1] = { "vdw-q", "vdw", "q", "none", nullptr };
 
-static void GetSimTemps(int ntemps, t_simtemp* simtemp, double* temperature_lambdas)
+static void getSimTemps(int ntemps, t_simtemp* simtemp, gmx::ArrayRef<double> temperature_lambdas)
 {
 
     int i;
@@ -160,20 +165,20 @@ static void GetSimTemps(int ntemps, t_simtemp* simtemp, double* temperature_lamb
     for (i = 0; i < ntemps; i++)
     {
         /* simple linear scaling -- allows more control */
-        if (simtemp->eSimTempScale == esimtempLINEAR)
+        if (simtemp->eSimTempScale == SimulatedTempering::Linear)
         {
             simtemp->temperatures[i] =
                     simtemp->simtemp_low
                     + (simtemp->simtemp_high - simtemp->simtemp_low) * temperature_lambdas[i];
         }
         else if (simtemp->eSimTempScale
-                 == esimtempGEOMETRIC) /* should give roughly equal acceptance for constant heat capacity . . . */
+                 == SimulatedTempering::Geometric) /* should give roughly equal acceptance for constant heat capacity . . . */
         {
             simtemp->temperatures[i] = simtemp->simtemp_low
                                        * std::pow(simtemp->simtemp_high / simtemp->simtemp_low,
                                                   static_cast<real>((1.0 * i) / (ntemps - 1)));
         }
-        else if (simtemp->eSimTempScale == esimtempEXPONENTIAL)
+        else if (simtemp->eSimTempScale == SimulatedTempering::Exponential)
         {
             simtemp->temperatures[i] = simtemp->simtemp_low
                                        + (simtemp->simtemp_high - simtemp->simtemp_low)
@@ -182,7 +187,7 @@ static void GetSimTemps(int ntemps, t_simtemp* simtemp, double* temperature_lamb
         else
         {
             char errorstr[128];
-            sprintf(errorstr, "eSimTempScale=%d not defined", simtemp->eSimTempScale);
+            sprintf(errorstr, "eSimTempScale=%s not defined", enumValueToString(simtemp->eSimTempScale));
             gmx_fatal(FARGS, "%s", errorstr);
         }
     }
@@ -210,135 +215,20 @@ static void check_nst(const char* desc_nst, int nst, const char* desc_p, int* p,
     }
 }
 
-static int lcd(int n1, int n2)
-{
-    int d, i;
-
-    d = 1;
-    for (i = 2; (i <= n1 && i <= n2); i++)
-    {
-        if (n1 % i == 0 && n2 % i == 0)
-        {
-            d = i;
-        }
-    }
-
-    return d;
-}
-
 //! Convert legacy mdp entries to modern ones.
-static void process_interaction_modifier(int* eintmod)
-{
-    if (*eintmod == eintmodPOTSHIFT_VERLET_UNSUPPORTED)
-    {
-        *eintmod = eintmodPOTSHIFT;
-    }
-}
-
-static void checkMtsRequirement(const t_inputrec& ir, const char* param, const int nstValue, warninp_t wi)
+static void process_interaction_modifier(InteractionModifiers* eintmod)
 {
-    GMX_RELEASE_ASSERT(ir.mtsLevels.size() >= 2, "Need at least two levels for MTS");
-    const int mtsFactor = ir.mtsLevels.back().stepFactor;
-    if (nstValue % mtsFactor != 0)
+    if (*eintmod == InteractionModifiers::PotShiftVerletUnsupported)
     {
-        auto message = gmx::formatString(
-                "With MTS, %s = %d should be a multiple of mts-factor = %d", param, nstValue, mtsFactor);
-        warning_error(wi, message.c_str());
+        *eintmod = InteractionModifiers::PotShift;
     }
 }
 
-static void setupMtsLevels(gmx::ArrayRef<gmx::MtsLevel> mtsLevels,
-                           const t_inputrec&            ir,
-                           const t_gromppopts&          opts,
-                           warninp_t                    wi)
-{
-    /* MD-VV has no MTS support yet.
-     * SD1 needs different scaling coefficients for the different MTS forces
-     * and the different forces are currently not available in ForceBuffers.
-     */
-    if (ir.eI != eiMD)
-    {
-        auto message = gmx::formatString(
-                "Multiple time stepping is only supported with integrator %s", ei_names[eiMD]);
-        warning_error(wi, message.c_str());
-    }
-    if (opts.numMtsLevels != 2)
-    {
-        warning_error(wi, "Only mts-levels = 2 is supported");
-    }
-    else
-    {
-        const std::vector<std::string> inputForceGroups = gmx::splitString(opts.mtsLevel2Forces);
-        auto&                          forceGroups      = mtsLevels[1].forceGroups;
-        for (const auto& inputForceGroup : inputForceGroups)
-        {
-            bool found     = false;
-            int  nameIndex = 0;
-            for (const auto& forceGroupName : gmx::mtsForceGroupNames)
-            {
-                if (gmx::equalCaseInsensitive(inputForceGroup, forceGroupName))
-                {
-                    forceGroups.set(nameIndex);
-                    found = true;
-                }
-                nameIndex++;
-            }
-            if (!found)
-            {
-                auto message =
-                        gmx::formatString("Unknown MTS force group '%s'", inputForceGroup.c_str());
-                warning_error(wi, message.c_str());
-            }
-        }
-
-        if (mtsLevels[1].stepFactor <= 1)
-        {
-            gmx_fatal(FARGS, "mts-factor should be larger than 1");
-        }
-
-        // Make the level 0 use the complement of the force groups of group 1
-        mtsLevels[0].forceGroups = ~mtsLevels[1].forceGroups;
-        mtsLevels[0].stepFactor  = 1;
-
-        if ((EEL_FULL(ir.coulombtype) || EVDW_PME(ir.vdwtype))
-            && !mtsLevels[1].forceGroups[static_cast<int>(gmx::MtsForceGroups::LongrangeNonbonded)])
-        {
-            warning_error(wi,
-                          "With long-range electrostatics and/or LJ treatment, the long-range part "
-                          "has to be part of the mts-level2-forces");
-        }
-
-        if (ir.nstcalcenergy > 0)
-        {
-            checkMtsRequirement(ir, "nstcalcenergy", ir.nstcalcenergy, wi);
-        }
-        checkMtsRequirement(ir, "nstenergy", ir.nstenergy, wi);
-        checkMtsRequirement(ir, "nstlog", ir.nstlog, wi);
-        if (ir.efep != efepNO)
-        {
-            checkMtsRequirement(ir, "nstdhdl", ir.fepvals->nstdhdl, wi);
-        }
-
-        if (ir.bPull)
-        {
-            const int pullMtsLevel = gmx::forceGroupMtsLevel(ir.mtsLevels, gmx::MtsForceGroups::Pull);
-            if (ir.pull->nstxout % ir.mtsLevels[pullMtsLevel].stepFactor != 0)
-            {
-                warning_error(wi, "pull-nstxout should be a multiple of mts-factor");
-            }
-            if (ir.pull->nstfout % ir.mtsLevels[pullMtsLevel].stepFactor != 0)
-            {
-                warning_error(wi, "pull-nstfout should be a multiple of mts-factor");
-            }
-        }
-    }
-}
-
-void check_ir(const char*                   mdparin,
-              const gmx::MdModulesNotifier& mdModulesNotifier,
-              t_inputrec*                   ir,
-              t_gromppopts*                 opts,
-              warninp_t                     wi)
+void check_ir(const char*                    mdparin,
+              const gmx::MDModulesNotifiers& mdModulesNotifiers,
+              t_inputrec*                    ir,
+              t_gromppopts*                  opts,
+              warninp_t                      wi)
 /* Check internal consistency.
  * NOTE: index groups are not set here yet, don't check things
  * like temperature coupling group options here, but in triple_check
@@ -352,15 +242,30 @@ void check_ir(const char*                   mdparin,
     char        err_buf[256], warn_buf[STRLEN];
     int         i, j;
     real        dt_pcoupl;
-    t_lambda*   fep    = ir->fepvals;
-    t_expanded* expand = ir->expandedvals;
+    t_lambda*   fep    = ir->fepvals.get();
+    t_expanded* expand = ir->expandedvals.get();
 
     set_warning_line(wi, mdparin, -1);
 
-    if (ir->coulombtype == eelRF_NEC_UNSUPPORTED)
+    /* We cannot check MTS requirements with an invalid MTS setup
+     * and we will already have generated errors with an invalid MTS setup.
+     */
+    if (gmx::haveValidMtsSetup(*ir))
     {
-        sprintf(warn_buf, "%s electrostatics is no longer supported", eel_names[eelRF_NEC_UNSUPPORTED]);
-        warning_error(wi, warn_buf);
+        std::vector<std::string> errorMessages = gmx::checkMtsRequirements(*ir);
+
+        for (const auto& errorMessage : errorMessages)
+        {
+            warning_error(wi, errorMessage.c_str());
+        }
+    }
+
+    if (ir->coulombtype == CoulombInteractionType::RFNecUnsupported)
+    {
+        std::string message =
+                gmx::formatString("%s electrostatics is no longer supported",
+                                  enumValueToString(CoulombInteractionType::RFNecUnsupported));
+        warning_error(wi, message);
     }
 
     /* BASIC CUT-OFF STUFF */
@@ -372,7 +277,7 @@ void check_ir(const char*                   mdparin,
     {
         warning_error(wi, "rvdw should be >= 0");
     }
-    if (ir->rlist < 0 && !(ir->cutoff_scheme == ecutsVERLET && ir->verletbuf_tol > 0))
+    if (ir->rlist < 0 && !(ir->cutoff_scheme == CutoffScheme::Verlet && ir->verletbuf_tol > 0))
     {
         warning_error(wi, "rlist should be >= 0");
     }
@@ -385,13 +290,13 @@ void check_ir(const char*                   mdparin,
     process_interaction_modifier(&ir->coulomb_modifier);
     process_interaction_modifier(&ir->vdw_modifier);
 
-    if (ir->cutoff_scheme == ecutsGROUP)
+    if (ir->cutoff_scheme == CutoffScheme::Group)
     {
         gmx_fatal(FARGS,
                   "The group cutoff scheme has been removed since GROMACS 2020. "
                   "Please use the Verlet cutoff scheme.");
     }
-    if (ir->cutoff_scheme == ecutsVERLET)
+    if (ir->cutoff_scheme == CutoffScheme::Verlet)
     {
         real rc_max;
 
@@ -406,8 +311,9 @@ void check_ir(const char*                   mdparin,
         {
             // Since we have PME coulomb + LJ cut-off kernels with rcoulomb>rvdw
             // for PME load balancing, we can support this exception.
-            bool bUsesPmeTwinRangeKernel = (EEL_PME_EWALD(ir->coulombtype) && ir->vdwtype == evdwCUT
-                                            && ir->rcoulomb > ir->rvdw);
+            bool bUsesPmeTwinRangeKernel =
+                    (EEL_PME_EWALD(ir->coulombtype) && ir->vdwtype == VanDerWaalsType::Cut
+                     && ir->rcoulomb > ir->rvdw);
             if (!bUsesPmeTwinRangeKernel)
             {
                 warning_error(wi,
@@ -416,50 +322,59 @@ void check_ir(const char*                   mdparin,
             }
         }
 
-        if (ir->vdwtype == evdwSHIFT || ir->vdwtype == evdwSWITCH)
+        if (ir->vdwtype == VanDerWaalsType::Shift || ir->vdwtype == VanDerWaalsType::Switch)
         {
-            if (ir->vdw_modifier == eintmodNONE || ir->vdw_modifier == eintmodPOTSHIFT)
+            if (ir->vdw_modifier == InteractionModifiers::None
+                || ir->vdw_modifier == InteractionModifiers::PotShift)
             {
-                ir->vdw_modifier = (ir->vdwtype == evdwSHIFT ? eintmodFORCESWITCH : eintmodPOTSWITCH);
+                ir->vdw_modifier =
+                        (ir->vdwtype == VanDerWaalsType::Shift ? InteractionModifiers::ForceSwitch
+                                                               : InteractionModifiers::PotSwitch);
 
                 sprintf(warn_buf,
                         "Replacing vdwtype=%s by the equivalent combination of vdwtype=%s and "
                         "vdw_modifier=%s",
-                        evdw_names[ir->vdwtype], evdw_names[evdwCUT], eintmod_names[ir->vdw_modifier]);
+                        enumValueToString(ir->vdwtype),
+                        enumValueToString(VanDerWaalsType::Cut),
+                        enumValueToString(ir->vdw_modifier));
                 warning_note(wi, warn_buf);
 
-                ir->vdwtype = evdwCUT;
+                ir->vdwtype = VanDerWaalsType::Cut;
             }
             else
             {
-                sprintf(warn_buf, "Unsupported combination of vdwtype=%s and vdw_modifier=%s",
-                        evdw_names[ir->vdwtype], eintmod_names[ir->vdw_modifier]);
+                sprintf(warn_buf,
+                        "Unsupported combination of vdwtype=%s and vdw_modifier=%s",
+                        enumValueToString(ir->vdwtype),
+                        enumValueToString(ir->vdw_modifier));
                 warning_error(wi, warn_buf);
             }
         }
 
-        if (!(ir->vdwtype == evdwCUT || ir->vdwtype == evdwPME))
+        if (!(ir->vdwtype == VanDerWaalsType::Cut || ir->vdwtype == VanDerWaalsType::Pme))
         {
             warning_error(wi,
                           "With Verlet lists only cut-off and PME LJ interactions are supported");
         }
-        if (!(ir->coulombtype == eelCUT || EEL_RF(ir->coulombtype) || EEL_PME(ir->coulombtype)
-              || ir->coulombtype == eelEWALD))
+        if (!(ir->coulombtype == CoulombInteractionType::Cut || EEL_RF(ir->coulombtype)
+              || EEL_PME(ir->coulombtype) || ir->coulombtype == CoulombInteractionType::Ewald))
         {
             warning_error(wi,
                           "With Verlet lists only cut-off, reaction-field, PME and Ewald "
                           "electrostatics are supported");
         }
-        if (!(ir->coulomb_modifier == eintmodNONE || ir->coulomb_modifier == eintmodPOTSHIFT))
+        if (!(ir->coulomb_modifier == InteractionModifiers::None
+              || ir->coulomb_modifier == InteractionModifiers::PotShift))
         {
-            sprintf(warn_buf, "coulomb_modifier=%s is not supported", eintmod_names[ir->coulomb_modifier]);
+            sprintf(warn_buf, "coulomb_modifier=%s is not supported", enumValueToString(ir->coulomb_modifier));
             warning_error(wi, warn_buf);
         }
 
         if (EEL_USER(ir->coulombtype))
         {
-            sprintf(warn_buf, "Coulomb type %s is not supported with the verlet scheme",
-                    eel_names[ir->coulombtype]);
+            sprintf(warn_buf,
+                    "Coulomb type %s is not supported with the verlet scheme",
+                    enumValueToString(ir->coulombtype));
             warning_error(wi, warn_buf);
         }
 
@@ -549,7 +464,7 @@ void check_ir(const char*                   mdparin,
     /* GENERAL INTEGRATOR STUFF */
     if (!EI_MD(ir->eI))
     {
-        if (ir->etc != etcNO)
+        if (ir->etc != TemperatureCoupling::No)
         {
             if (EI_RANDOM(ir->eI))
             {
@@ -557,37 +472,43 @@ void check_ir(const char*                   mdparin,
                         "Setting tcoupl from '%s' to 'no'. %s handles temperature coupling "
                         "implicitly. See the documentation for more information on which "
                         "parameters affect temperature for %s.",
-                        etcoupl_names[ir->etc], ei_names[ir->eI], ei_names[ir->eI]);
+                        enumValueToString(ir->etc),
+                        enumValueToString(ir->eI),
+                        enumValueToString(ir->eI));
             }
             else
             {
                 sprintf(warn_buf,
                         "Setting tcoupl from '%s' to 'no'. Temperature coupling does not apply to "
                         "%s.",
-                        etcoupl_names[ir->etc], ei_names[ir->eI]);
+                        enumValueToString(ir->etc),
+                        enumValueToString(ir->eI));
             }
             warning_note(wi, warn_buf);
         }
-        ir->etc = etcNO;
+        ir->etc = TemperatureCoupling::No;
     }
-    if (ir->eI == eiVVAK)
+    if (ir->eI == IntegrationAlgorithm::VVAK)
     {
         sprintf(warn_buf,
                 "Integrator method %s is implemented primarily for validation purposes; for "
                 "molecular dynamics, you should probably be using %s or %s",
-                ei_names[eiVVAK], ei_names[eiMD], ei_names[eiVV]);
+                enumValueToString(IntegrationAlgorithm::VVAK),
+                enumValueToString(IntegrationAlgorithm::MD),
+                enumValueToString(IntegrationAlgorithm::VV));
         warning_note(wi, warn_buf);
     }
     if (!EI_DYNAMICS(ir->eI))
     {
-        if (ir->epc != epcNO)
+        if (ir->epc != PressureCoupling::No)
         {
             sprintf(warn_buf,
                     "Setting pcoupl from '%s' to 'no'. Pressure coupling does not apply to %s.",
-                    epcoupl_names[ir->epc], ei_names[ir->eI]);
+                    enumValueToString(ir->epc),
+                    enumValueToString(ir->eI));
             warning_note(wi, warn_buf);
         }
-        ir->epc = epcNO;
+        ir->epc = PressureCoupling::No;
     }
     if (EI_DYNAMICS(ir->eI))
     {
@@ -601,7 +522,7 @@ void check_ir(const char*                   mdparin,
                  */
                 if (ir->nstlist > 0)
                 {
-                    ir->nstcalcenergy = lcd(ir->nstenergy, ir->nstlist);
+                    ir->nstcalcenergy = std::gcd(ir->nstenergy, ir->nstlist);
                 }
                 else
                 {
@@ -610,7 +531,7 @@ void check_ir(const char*                   mdparin,
             }
         }
         else if ((ir->nstenergy > 0 && ir->nstcalcenergy > ir->nstenergy)
-                 || (ir->efep != efepNO && ir->fepvals->nstdhdl > 0
+                 || (ir->efep != FreeEnergyPerturbationType::No && ir->fepvals->nstdhdl > 0
                      && (ir->nstcalcenergy > ir->fepvals->nstdhdl)))
 
         {
@@ -620,20 +541,19 @@ void check_ir(const char*                   mdparin,
             int         min_nst  = ir->nstenergy;
 
             /* find the smallest of ( nstenergy, nstdhdl ) */
-            if (ir->efep != efepNO && ir->fepvals->nstdhdl > 0
+            if (ir->efep != FreeEnergyPerturbationType::No && ir->fepvals->nstdhdl > 0
                 && (ir->nstenergy == 0 || ir->fepvals->nstdhdl < ir->nstenergy))
             {
                 min_nst  = ir->fepvals->nstdhdl;
                 min_name = nstdh;
             }
             /* If the user sets nstenergy small, we should respect that */
-            sprintf(warn_buf, "Setting nstcalcenergy (%d) equal to %s (%d)", ir->nstcalcenergy,
-                    min_name, min_nst);
+            sprintf(warn_buf, "Setting nstcalcenergy (%d) equal to %s (%d)", ir->nstcalcenergy, min_name, min_nst);
             warning_note(wi, warn_buf);
             ir->nstcalcenergy = min_nst;
         }
 
-        if (ir->epc != epcNO)
+        if (ir->epc != PressureCoupling::No)
         {
             if (ir->nstpcouple < 0)
             {
@@ -649,7 +569,7 @@ void check_ir(const char*                   mdparin,
 
         if (ir->nstcalcenergy > 0)
         {
-            if (ir->efep != efepNO)
+            if (ir->efep != FreeEnergyPerturbationType::No)
             {
                 /* nstdhdl should be a multiple of nstcalcenergy */
                 check_nst("nstcalcenergy", ir->nstcalcenergy, "nstdhdl", &ir->fepvals->nstdhdl, wi);
@@ -657,8 +577,7 @@ void check_ir(const char*                   mdparin,
             if (ir->bExpanded)
             {
                 /* nstexpanded should be a multiple of nstcalcenergy */
-                check_nst("nstcalcenergy", ir->nstcalcenergy, "nstexpanded",
-                          &ir->expandedvals->nstexpanded, wi);
+                check_nst("nstcalcenergy", ir->nstcalcenergy, "nstexpanded", &ir->expandedvals->nstexpanded, wi);
             }
             /* for storing exact averages nstenergy should be
              * a multiple of nstcalcenergy
@@ -666,10 +585,10 @@ void check_ir(const char*                   mdparin,
             check_nst("nstcalcenergy", ir->nstcalcenergy, "nstenergy", &ir->nstenergy, wi);
         }
 
-        // Inquire all MdModules, if their parameters match with the energy
+        // Inquire all MDModules, if their parameters match with the energy
         // calculation frequency
         gmx::EnergyCalculationFrequencyErrors energyCalculationFrequencyErrors(ir->nstcalcenergy);
-        mdModulesNotifier.preProcessingNotifications_.notify(&energyCalculationFrequencyErrors);
+        mdModulesNotifiers.preProcessingNotifier_.notify(&energyCalculationFrequencyErrors);
 
         // Emit all errors from the energy calculation frequency checks
         for (const std::string& energyFrequencyErrorMessage :
@@ -687,7 +606,7 @@ void check_ir(const char*                   mdparin,
     }
 
     /* LD STUFF */
-    if ((EI_SD(ir->eI) || ir->eI == eiBD) && ir->bContinuation && ir->ld_seed != -1)
+    if ((EI_SD(ir->eI) || ir->eI == IntegrationAlgorithm::BD) && ir->bContinuation && ir->ld_seed != -1)
     {
         warning_note(wi,
                      "You are doing a continuation with SD or BD, make sure that ld_seed is "
@@ -712,7 +631,7 @@ void check_ir(const char*                   mdparin,
         warning(wi, warn_buf);
     }
 
-    if ((EI_SD(ir->eI) || ir->eI == eiBD) && ir->bContinuation && ir->ld_seed != -1)
+    if ((EI_SD(ir->eI) || ir->eI == IntegrationAlgorithm::BD) && ir->bContinuation && ir->ld_seed != -1)
     {
         warning_note(wi,
                      "You are doing a continuation with SD or BD, make sure that ld_seed is "
@@ -725,10 +644,15 @@ void check_ir(const char*                   mdparin,
         bool bAllTempZero = TRUE;
         for (i = 0; i < fep->n_lambda; i++)
         {
-            sprintf(err_buf, "Entry %d for %s must be between 0 and 1, instead is %g", i,
-                    efpt_names[efptTEMPERATURE], fep->all_lambda[efptTEMPERATURE][i]);
-            CHECK((fep->all_lambda[efptTEMPERATURE][i] < 0) || (fep->all_lambda[efptTEMPERATURE][i] > 1));
-            if (fep->all_lambda[efptTEMPERATURE][i] > 0)
+            sprintf(err_buf,
+                    "Entry %d for %s must be between 0 and 1, instead is %g",
+                    i,
+                    enumValueToString(FreeEnergyPerturbationCouplingType::Temperature),
+                    fep->all_lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Temperature)][i]);
+            CHECK((fep->all_lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Temperature)][i] < 0)
+                  || (fep->all_lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Temperature)][i]
+                      > 1));
+            if (fep->all_lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Temperature)][i] > 0)
             {
                 bAllTempZero = FALSE;
             }
@@ -737,16 +661,16 @@ void check_ir(const char*                   mdparin,
         CHECK(bAllTempZero == TRUE);
 
         sprintf(err_buf, "Simulated tempering is currently only compatible with md-vv");
-        CHECK(ir->eI != eiVV);
+        CHECK(ir->eI != IntegrationAlgorithm::VV);
 
         /* check compatability of the temperature coupling with simulated tempering */
 
-        if (ir->etc == etcNOSEHOOVER)
+        if (ir->etc == TemperatureCoupling::NoseHoover)
         {
             sprintf(warn_buf,
                     "Nose-Hoover based temperature control such as [%s] my not be "
                     "entirelyconsistent with simulated tempering",
-                    etcoupl_names[ir->etc]);
+                    enumValueToString(ir->etc));
             warning_note(wi, warn_buf);
         }
 
@@ -755,23 +679,26 @@ void check_ir(const char*                   mdparin,
         sprintf(err_buf,
                 "Higher simulated tempering temperature (%g) must be >= than the simulated "
                 "tempering lower temperature (%g)",
-                ir->simtempvals->simtemp_high, ir->simtempvals->simtemp_low);
+                ir->simtempvals->simtemp_high,
+                ir->simtempvals->simtemp_low);
         CHECK(ir->simtempvals->simtemp_high <= ir->simtempvals->simtemp_low);
 
-        sprintf(err_buf, "Higher simulated tempering temperature (%g) must be >= zero",
+        sprintf(err_buf,
+                "Higher simulated tempering temperature (%g) must be >= zero",
                 ir->simtempvals->simtemp_high);
         CHECK(ir->simtempvals->simtemp_high <= 0);
 
-        sprintf(err_buf, "Lower simulated tempering temperature (%g) must be >= zero",
+        sprintf(err_buf,
+                "Lower simulated tempering temperature (%g) must be >= zero",
                 ir->simtempvals->simtemp_low);
         CHECK(ir->simtempvals->simtemp_low <= 0);
     }
 
     /* verify free energy options */
 
-    if (ir->efep != efepNO)
+    if (ir->efep != FreeEnergyPerturbationType::No)
     {
-        fep = ir->fepvals;
+        fep = ir->fepvals.get();
         sprintf(err_buf, "The soft-core power is %d and can only be 1 or 2", fep->sc_power);
         CHECK(fep->sc_alpha != 0 && fep->sc_power != 1 && fep->sc_power != 2);
 
@@ -787,28 +714,30 @@ void check_ir(const char*                   mdparin,
                 fep->delta_lambda);
         CHECK(fep->delta_lambda > 0 && ((fep->init_fep_state > 0) || (fep->init_lambda > 0)));
 
-        sprintf(err_buf, "Can't use positive delta-lambda (%g) with expanded ensemble simulations",
+        sprintf(err_buf,
+                "Can't use positive delta-lambda (%g) with expanded ensemble simulations",
                 fep->delta_lambda);
-        CHECK(fep->delta_lambda > 0 && (ir->efep == efepEXPANDED));
+        CHECK(fep->delta_lambda > 0 && (ir->efep == FreeEnergyPerturbationType::Expanded));
 
         sprintf(err_buf, "Can only use expanded ensemble with md-vv (for now)");
-        CHECK(!(EI_VV(ir->eI)) && (ir->efep == efepEXPANDED));
+        CHECK(!(EI_VV(ir->eI)) && (ir->efep == FreeEnergyPerturbationType::Expanded));
 
         sprintf(err_buf, "Free-energy not implemented for Ewald");
-        CHECK(ir->coulombtype == eelEWALD);
+        CHECK(ir->coulombtype == CoulombInteractionType::Ewald);
 
         /* check validty of lambda inputs */
         if (fep->n_lambda == 0)
         {
             /* Clear output in case of no states:*/
-            sprintf(err_buf, "init-lambda-state set to %d: no lambda states are defined.",
-                    fep->init_fep_state);
+            sprintf(err_buf, "init-lambda-state set to %d: no lambda states are defined.", fep->init_fep_state);
             CHECK((fep->init_fep_state >= 0) && (fep->n_lambda == 0));
         }
         else
         {
-            sprintf(err_buf, "initial thermodynamic state %d does not exist, only goes to %d",
-                    fep->init_fep_state, fep->n_lambda - 1);
+            sprintf(err_buf,
+                    "initial thermodynamic state %d does not exist, only goes to %d",
+                    fep->init_fep_state,
+                    fep->n_lambda - 1);
             CHECK((fep->init_fep_state >= fep->n_lambda));
         }
 
@@ -819,7 +748,8 @@ void check_ir(const char*                   mdparin,
         sprintf(err_buf,
                 "init-lambda=%g while init-lambda-state=%d. Lambda state must be set either with "
                 "init-lambda-state or with init-lambda, but not both",
-                fep->init_lambda, fep->init_fep_state);
+                fep->init_lambda,
+                fep->init_fep_state);
         CHECK((fep->init_fep_state >= 0) && (fep->init_lambda >= 0));
 
 
@@ -827,7 +757,7 @@ void check_ir(const char*                   mdparin,
         {
             int n_lambda_terms;
             n_lambda_terms = 0;
-            for (i = 0; i < efptNR; i++)
+            for (i = 0; i < static_cast<int>(FreeEnergyPerturbationCouplingType::Count); i++)
             {
                 if (fep->separate_dvdl[i])
                 {
@@ -851,12 +781,16 @@ void check_ir(const char*                   mdparin,
             }
         }
 
-        for (j = 0; j < efptNR; j++)
+        for (j = 0; j < static_cast<int>(FreeEnergyPerturbationCouplingType::Count); j++)
         {
             for (i = 0; i < fep->n_lambda; i++)
             {
-                sprintf(err_buf, "Entry %d for %s must be between 0 and 1, instead is %g", i,
-                        efpt_names[j], fep->all_lambda[j][i]);
+                auto enumValue = static_cast<FreeEnergyPerturbationCouplingType>(j);
+                sprintf(err_buf,
+                        "Entry %d for %s must be between 0 and 1, instead is %g",
+                        i,
+                        enumValueToString(enumValue),
+                        fep->all_lambda[j][i]);
                 CHECK((fep->all_lambda[j][i] < 0) || (fep->all_lambda[j][i] > 1));
             }
         }
@@ -869,10 +803,15 @@ void check_ir(const char*                   mdparin,
                         "For state %d, vdw-lambdas (%f) is changing with vdw softcore, while "
                         "coul-lambdas (%f) is nonzero without coulomb softcore: this will lead to "
                         "crashes, and is not supported.",
-                        i, fep->all_lambda[efptVDW][i], fep->all_lambda[efptCOUL][i]);
+                        i,
+                        fep->all_lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)][i],
+                        fep->all_lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)][i]);
                 CHECK((fep->sc_alpha > 0)
-                      && (((fep->all_lambda[efptCOUL][i] > 0.0) && (fep->all_lambda[efptCOUL][i] < 1.0))
-                          && ((fep->all_lambda[efptVDW][i] > 0.0) && (fep->all_lambda[efptVDW][i] < 1.0))));
+                      && (((fep->all_lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)][i] > 0.0)
+                           && (fep->all_lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)][i] < 1.0))
+                          && ((fep->all_lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)][i] > 0.0)
+                              && (fep->all_lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)][i]
+                                  < 1.0))));
             }
         }
 
@@ -891,84 +830,107 @@ void check_ir(const char*                   mdparin,
                     "energy conservation, but usually other effects dominate. With a common sigma "
                     "value of %g nm the fraction of the particle-particle potential at the cut-off "
                     "at lambda=%g is around %.1e, while ewald-rtol is %.1e.",
-                    fep->sc_r_power, sigma, lambda, r_sc - 1.0, ir->ewald_rtol);
+                    fep->sc_r_power,
+                    sigma,
+                    lambda,
+                    r_sc - 1.0,
+                    ir->ewald_rtol);
             warning_note(wi, warn_buf);
         }
 
         /*  Free Energy Checks -- In an ideal world, slow growth and FEP would
             be treated differently, but that's the next step */
 
-        for (i = 0; i < efptNR; i++)
+        for (i = 0; i < static_cast<int>(FreeEnergyPerturbationCouplingType::Count); i++)
         {
+            auto enumValue = static_cast<FreeEnergyPerturbationCouplingType>(i);
             for (j = 0; j < fep->n_lambda; j++)
             {
-                sprintf(err_buf, "%s[%d] must be between 0 and 1", efpt_names[i], j);
+                sprintf(err_buf, "%s[%d] must be between 0 and 1", enumValueToString(enumValue), j);
                 CHECK((fep->all_lambda[i][j] < 0) || (fep->all_lambda[i][j] > 1));
             }
         }
     }
 
-    if ((ir->bSimTemp) || (ir->efep == efepEXPANDED))
+    if ((ir->bSimTemp) || (ir->efep == FreeEnergyPerturbationType::Expanded))
     {
-        fep = ir->fepvals;
+        fep = ir->fepvals.get();
 
         /* checking equilibration of weights inputs for validity */
 
         sprintf(err_buf,
                 "weight-equil-number-all-lambda (%d) is ignored if lmc-weights-equil is not equal "
                 "to %s",
-                expand->equil_n_at_lam, elmceq_names[elmceqNUMATLAM]);
-        CHECK((expand->equil_n_at_lam > 0) && (expand->elmceq != elmceqNUMATLAM));
+                expand->equil_n_at_lam,
+                enumValueToString(LambdaWeightWillReachEquilibrium::NumAtLambda));
+        CHECK((expand->equil_n_at_lam > 0)
+              && (expand->elmceq != LambdaWeightWillReachEquilibrium::NumAtLambda));
 
         sprintf(err_buf,
                 "weight-equil-number-samples (%d) is ignored if lmc-weights-equil is not equal to "
                 "%s",
-                expand->equil_samples, elmceq_names[elmceqSAMPLES]);
-        CHECK((expand->equil_samples > 0) && (expand->elmceq != elmceqSAMPLES));
+                expand->equil_samples,
+                enumValueToString(LambdaWeightWillReachEquilibrium::Samples));
+        CHECK((expand->equil_samples > 0) && (expand->elmceq != LambdaWeightWillReachEquilibrium::Samples));
 
         sprintf(err_buf,
                 "weight-equil-number-steps (%d) is ignored if lmc-weights-equil is not equal to %s",
-                expand->equil_steps, elmceq_names[elmceqSTEPS]);
-        CHECK((expand->equil_steps > 0) && (expand->elmceq != elmceqSTEPS));
+                expand->equil_steps,
+                enumValueToString(LambdaWeightWillReachEquilibrium::Steps));
+        CHECK((expand->equil_steps > 0) && (expand->elmceq != LambdaWeightWillReachEquilibrium::Steps));
 
         sprintf(err_buf,
                 "weight-equil-wl-delta (%d) is ignored if lmc-weights-equil is not equal to %s",
-                expand->equil_samples, elmceq_names[elmceqWLDELTA]);
-        CHECK((expand->equil_wl_delta > 0) && (expand->elmceq != elmceqWLDELTA));
+                expand->equil_samples,
+                enumValueToString(LambdaWeightWillReachEquilibrium::WLDelta));
+        CHECK((expand->equil_wl_delta > 0) && (expand->elmceq != LambdaWeightWillReachEquilibrium::WLDelta));
 
         sprintf(err_buf,
                 "weight-equil-count-ratio (%f) is ignored if lmc-weights-equil is not equal to %s",
-                expand->equil_ratio, elmceq_names[elmceqRATIO]);
-        CHECK((expand->equil_ratio > 0) && (expand->elmceq != elmceqRATIO));
+                expand->equil_ratio,
+                enumValueToString(LambdaWeightWillReachEquilibrium::Ratio));
+        CHECK((expand->equil_ratio > 0) && (expand->elmceq != LambdaWeightWillReachEquilibrium::Ratio));
 
         sprintf(err_buf,
                 "weight-equil-number-all-lambda (%d) must be a positive integer if "
                 "lmc-weights-equil=%s",
-                expand->equil_n_at_lam, elmceq_names[elmceqNUMATLAM]);
-        CHECK((expand->equil_n_at_lam <= 0) && (expand->elmceq == elmceqNUMATLAM));
+                expand->equil_n_at_lam,
+                enumValueToString(LambdaWeightWillReachEquilibrium::NumAtLambda));
+        CHECK((expand->equil_n_at_lam <= 0)
+              && (expand->elmceq == LambdaWeightWillReachEquilibrium::NumAtLambda));
 
         sprintf(err_buf,
                 "weight-equil-number-samples (%d) must be a positive integer if "
                 "lmc-weights-equil=%s",
-                expand->equil_samples, elmceq_names[elmceqSAMPLES]);
-        CHECK((expand->equil_samples <= 0) && (expand->elmceq == elmceqSAMPLES));
+                expand->equil_samples,
+                enumValueToString(LambdaWeightWillReachEquilibrium::Samples));
+        CHECK((expand->equil_samples <= 0) && (expand->elmceq == LambdaWeightWillReachEquilibrium::Samples));
 
         sprintf(err_buf,
                 "weight-equil-number-steps (%d) must be a positive integer if lmc-weights-equil=%s",
-                expand->equil_steps, elmceq_names[elmceqSTEPS]);
-        CHECK((expand->equil_steps <= 0) && (expand->elmceq == elmceqSTEPS));
+                expand->equil_steps,
+                enumValueToString(LambdaWeightWillReachEquilibrium::Steps));
+        CHECK((expand->equil_steps <= 0) && (expand->elmceq == LambdaWeightWillReachEquilibrium::Steps));
 
-        sprintf(err_buf, "weight-equil-wl-delta (%f) must be > 0 if lmc-weights-equil=%s",
-                expand->equil_wl_delta, elmceq_names[elmceqWLDELTA]);
-        CHECK((expand->equil_wl_delta <= 0) && (expand->elmceq == elmceqWLDELTA));
+        sprintf(err_buf,
+                "weight-equil-wl-delta (%f) must be > 0 if lmc-weights-equil=%s",
+                expand->equil_wl_delta,
+                enumValueToString(LambdaWeightWillReachEquilibrium::WLDelta));
+        CHECK((expand->equil_wl_delta <= 0)
+              && (expand->elmceq == LambdaWeightWillReachEquilibrium::WLDelta));
 
-        sprintf(err_buf, "weight-equil-count-ratio (%f) must be > 0 if lmc-weights-equil=%s",
-                expand->equil_ratio, elmceq_names[elmceqRATIO]);
-        CHECK((expand->equil_ratio <= 0) && (expand->elmceq == elmceqRATIO));
+        sprintf(err_buf,
+                "weight-equil-count-ratio (%f) must be > 0 if lmc-weights-equil=%s",
+                expand->equil_ratio,
+                enumValueToString(LambdaWeightWillReachEquilibrium::Ratio));
+        CHECK((expand->equil_ratio <= 0) && (expand->elmceq == LambdaWeightWillReachEquilibrium::Ratio));
 
-        sprintf(err_buf, "lmc-weights-equil=%s only possible when lmc-stats = %s or lmc-stats %s",
-                elmceq_names[elmceqWLDELTA], elamstats_names[elamstatsWL], elamstats_names[elamstatsWWL]);
-        CHECK((expand->elmceq == elmceqWLDELTA) && (!EWL(expand->elamstats)));
+        sprintf(err_buf,
+                "lmc-weights-equil=%s only possible when lmc-stats = %s or lmc-stats %s",
+                enumValueToString(LambdaWeightWillReachEquilibrium::WLDelta),
+                enumValueToString(LambdaWeightCalculation::WL),
+                enumValueToString(LambdaWeightCalculation::WWL));
+        CHECK((expand->elmceq == LambdaWeightWillReachEquilibrium::WLDelta) && (!EWL(expand->elamstats)));
 
         sprintf(err_buf, "lmc-repeats (%d) must be greater than 0", expand->lmc_repeats);
         CHECK((expand->lmc_repeats <= 0));
@@ -979,12 +941,14 @@ void check_ir(const char*                   mdparin,
         sprintf(err_buf,
                 "init-lambda-state (%d) must be zero if lmc-forced-nstart (%d)> 0 and lmc-move != "
                 "'no'",
-                fep->init_fep_state, expand->lmc_forced_nstart);
+                fep->init_fep_state,
+                expand->lmc_forced_nstart);
         CHECK((fep->init_fep_state != 0) && (expand->lmc_forced_nstart > 0)
-              && (expand->elmcmove != elmcmoveNO));
+              && (expand->elmcmove != LambdaMoveCalculation::No));
         sprintf(err_buf, "lmc-forced-nstart (%d) must not be negative", expand->lmc_forced_nstart);
         CHECK((expand->lmc_forced_nstart < 0));
-        sprintf(err_buf, "init-lambda-state (%d) must be in the interval [0,number of lambdas)",
+        sprintf(err_buf,
+                "init-lambda-state (%d) must be in the interval [0,number of lambdas)",
                 fep->init_fep_state);
         CHECK((fep->init_fep_state < 0) || (fep->init_fep_state >= fep->n_lambda));
 
@@ -996,8 +960,8 @@ void check_ir(const char*                   mdparin,
         CHECK((expand->wl_scale <= 0) || (expand->wl_scale >= 1));
 
         /* if there is no temperature control, we need to specify an MC temperature */
-        if (!integratorHasReferenceTemperature(ir) && (expand->elmcmove != elmcmoveNO)
-            && (expand->mc_temp <= 0.0))
+        if (!integratorHasReferenceTemperature(ir)
+            && (expand->elmcmove != LambdaMoveCalculation::No) && (expand->mc_temp <= 0.0))
         {
             sprintf(err_buf,
                     "If there is no temperature control, and lmc-mcmove!='no', mc_temp must be set "
@@ -1013,7 +977,8 @@ void check_ir(const char*                   mdparin,
             {
                 sprintf(err_buf,
                         "nst-transition-matrix (%d) must be an integer multiple of nstlog (%d)",
-                        expand->nstTij, ir->nstlog);
+                        expand->nstTij,
+                        ir->nstlog);
                 CHECK((expand->nstTij % ir->nstlog) != 0);
             }
         }
@@ -1028,24 +993,26 @@ void check_ir(const char*                   mdparin,
     {
         if (ir->pbcType == PbcType::No)
         {
-            if (ir->epc != epcNO)
+            if (ir->epc != PressureCoupling::No)
             {
                 warning(wi, "Turning off pressure coupling for vacuum system");
-                ir->epc = epcNO;
+                ir->epc = PressureCoupling::No;
             }
         }
         else
         {
-            sprintf(err_buf, "Can not have pressure coupling with pbc=%s",
+            sprintf(err_buf,
+                    "Can not have pressure coupling with pbc=%s",
                     c_pbcTypeNames[ir->pbcType].c_str());
-            CHECK(ir->epc != epcNO);
+            CHECK(ir->epc != PressureCoupling::No);
         }
         sprintf(err_buf, "Can not have Ewald with pbc=%s", c_pbcTypeNames[ir->pbcType].c_str());
         CHECK(EEL_FULL(ir->coulombtype));
 
-        sprintf(err_buf, "Can not have dispersion correction with pbc=%s",
+        sprintf(err_buf,
+                "Can not have dispersion correction with pbc=%s",
                 c_pbcTypeNames[ir->pbcType].c_str());
-        CHECK(ir->eDispCorr != edispcNO);
+        CHECK(ir->eDispCorr != DispersionCorrectionType::No);
     }
 
     if (ir->rlist == 0.0)
@@ -1055,8 +1022,11 @@ void check_ir(const char*                   mdparin,
                 "with coulombtype = %s or coulombtype = %s\n"
                 "without periodic boundary conditions (pbc = %s) and\n"
                 "rcoulomb and rvdw set to zero",
-                eel_names[eelCUT], eel_names[eelUSER], c_pbcTypeNames[PbcType::No].c_str());
-        CHECK(((ir->coulombtype != eelCUT) && (ir->coulombtype != eelUSER))
+                enumValueToString(CoulombInteractionType::Cut),
+                enumValueToString(CoulombInteractionType::User),
+                c_pbcTypeNames[PbcType::No].c_str());
+        CHECK(((ir->coulombtype != CoulombInteractionType::Cut)
+               && (ir->coulombtype != CoulombInteractionType::User))
               || (ir->pbcType != PbcType::No) || (ir->rcoulomb != 0.0) || (ir->rvdw != 0.0));
 
         if (ir->nstlist > 0)
@@ -1072,9 +1042,9 @@ void check_ir(const char*                   mdparin,
     {
         // TODO Change this behaviour. There should be exactly one way
         // to turn off an algorithm.
-        ir->comm_mode = ecmNO;
+        ir->comm_mode = ComRemovalAlgorithm::No;
     }
-    if (ir->comm_mode != ecmNO)
+    if (ir->comm_mode != ComRemovalAlgorithm::No)
     {
         if (ir->nstcomm < 0)
         {
@@ -1097,7 +1067,7 @@ void check_ir(const char*                   mdparin,
             ir->nstcomm = ir->nstcalcenergy;
         }
 
-        if (ir->comm_mode == ecmANGULAR)
+        if (ir->comm_mode == ComRemovalAlgorithm::Angular)
         {
             sprintf(err_buf,
                     "Can not remove the rotation around the center of mass with periodic "
@@ -1113,26 +1083,27 @@ void check_ir(const char*                   mdparin,
         }
     }
 
-    if (EI_STATE_VELOCITY(ir->eI) && !EI_SD(ir->eI) && ir->pbcType == PbcType::No && ir->comm_mode != ecmANGULAR)
+    if (EI_STATE_VELOCITY(ir->eI) && !EI_SD(ir->eI) && ir->pbcType == PbcType::No
+        && ir->comm_mode != ComRemovalAlgorithm::Angular)
     {
         sprintf(warn_buf,
                 "Tumbling and flying ice-cubes: We are not removing rotation around center of mass "
                 "in a non-periodic system. You should probably set comm_mode = ANGULAR or use "
                 "integrator = %s.",
-                ei_names[eiSD1]);
+                enumValueToString(IntegrationAlgorithm::SD1));
         warning_note(wi, warn_buf);
     }
 
     /* TEMPERATURE COUPLING */
-    if (ir->etc == etcYES)
+    if (ir->etc == TemperatureCoupling::Yes)
     {
-        ir->etc = etcBERENDSEN;
+        ir->etc = TemperatureCoupling::Berendsen;
         warning_note(wi,
                      "Old option for temperature coupling given: "
                      "changing \"yes\" to \"Berendsen\"\n");
     }
 
-    if ((ir->etc == etcNOSEHOOVER) || (ir->epc == epcMTTK))
+    if ((ir->etc == TemperatureCoupling::NoseHoover) || (ir->epc == PressureCoupling::Mttk))
     {
         if (ir->opts.nhchainlength < 1)
         {
@@ -1144,7 +1115,7 @@ void check_ir(const char*                   mdparin,
             warning(wi, warn_buf);
         }
 
-        if (ir->etc == etcNOSEHOOVER && !EI_VV(ir->eI) && ir->opts.nhchainlength > 1)
+        if (ir->etc == TemperatureCoupling::NoseHoover && !EI_VV(ir->eI) && ir->opts.nhchainlength > 1)
         {
             warning_note(
                     wi,
@@ -1157,48 +1128,53 @@ void check_ir(const char*                   mdparin,
         ir->opts.nhchainlength = 0;
     }
 
-    if (ir->eI == eiVVAK)
+    if (ir->eI == IntegrationAlgorithm::VVAK)
     {
         sprintf(err_buf,
                 "%s implemented primarily for validation, and requires nsttcouple = 1 and "
                 "nstpcouple = 1.",
-                ei_names[eiVVAK]);
+                enumValueToString(IntegrationAlgorithm::VVAK));
         CHECK((ir->nsttcouple != 1) || (ir->nstpcouple != 1));
     }
 
     if (ETC_ANDERSEN(ir->etc))
     {
-        sprintf(err_buf, "%s temperature control not supported for integrator %s.",
-                etcoupl_names[ir->etc], ei_names[ir->eI]);
+        sprintf(err_buf,
+                "%s temperature control not supported for integrator %s.",
+                enumValueToString(ir->etc),
+                enumValueToString(ir->eI));
         CHECK(!(EI_VV(ir->eI)));
 
-        if (ir->nstcomm > 0 && (ir->etc == etcANDERSEN))
+        if (ir->nstcomm > 0 && (ir->etc == TemperatureCoupling::Andersen))
         {
             sprintf(warn_buf,
                     "Center of mass removal not necessary for %s.  All velocities of coupled "
                     "groups are rerandomized periodically, so flying ice cube errors will not "
                     "occur.",
-                    etcoupl_names[ir->etc]);
+                    enumValueToString(ir->etc));
             warning_note(wi, warn_buf);
         }
 
         sprintf(err_buf,
                 "nstcomm must be 1, not %d for %s, as velocities of atoms in coupled groups are "
                 "randomized every time step",
-                ir->nstcomm, etcoupl_names[ir->etc]);
-        CHECK(ir->nstcomm > 1 && (ir->etc == etcANDERSEN));
+                ir->nstcomm,
+                enumValueToString(ir->etc));
+        CHECK(ir->nstcomm > 1 && (ir->etc == TemperatureCoupling::Andersen));
     }
 
-    if (ir->etc == etcBERENDSEN)
+    if (ir->etc == TemperatureCoupling::Berendsen)
     {
         sprintf(warn_buf,
                 "The %s thermostat does not generate the correct kinetic energy distribution. You "
                 "might want to consider using the %s thermostat.",
-                ETCOUPLTYPE(ir->etc), ETCOUPLTYPE(etcVRESCALE));
+                enumValueToString(ir->etc),
+                enumValueToString(TemperatureCoupling::VRescale));
         warning_note(wi, warn_buf);
     }
 
-    if ((ir->etc == etcNOSEHOOVER || ETC_ANDERSEN(ir->etc)) && ir->epc == epcBERENDSEN)
+    if ((ir->etc == TemperatureCoupling::NoseHoover || ETC_ANDERSEN(ir->etc))
+        && ir->epc == PressureCoupling::Berendsen)
     {
         sprintf(warn_buf,
                 "Using Berendsen pressure coupling invalidates the "
@@ -1207,15 +1183,15 @@ void check_ir(const char*                   mdparin,
     }
 
     /* PRESSURE COUPLING */
-    if (ir->epc == epcISOTROPIC)
+    if (ir->epc == PressureCoupling::Isotropic)
     {
-        ir->epc = epcBERENDSEN;
+        ir->epc = PressureCoupling::Berendsen;
         warning_note(wi,
                      "Old option for pressure coupling given: "
                      "changing \"Isotropic\" to \"Berendsen\"\n");
     }
 
-    if (ir->epc != epcNO)
+    if (ir->epc != PressureCoupling::No)
     {
         dt_pcoupl = ir->nstpcouple * ir->delta_t;
 
@@ -1227,19 +1203,22 @@ void check_ir(const char*                   mdparin,
             sprintf(warn_buf,
                     "For proper integration of the %s barostat, tau-p (%g) should be at least %d "
                     "times larger than nstpcouple*dt (%g)",
-                    EPCOUPLTYPE(ir->epc), ir->tau_p, pcouple_min_integration_steps(ir->epc), dt_pcoupl);
+                    enumValueToString(ir->epc),
+                    ir->tau_p,
+                    pcouple_min_integration_steps(ir->epc),
+                    dt_pcoupl);
             warning(wi, warn_buf);
         }
 
         sprintf(err_buf,
                 "compressibility must be > 0 when using pressure"
                 " coupling %s\n",
-                EPCOUPLTYPE(ir->epc));
+                enumValueToString(ir->epc));
         CHECK(ir->compress[XX][XX] < 0 || ir->compress[YY][YY] < 0 || ir->compress[ZZ][ZZ] < 0
               || (trace(ir->compress) == 0 && ir->compress[YY][XX] <= 0 && ir->compress[ZZ][XX] <= 0
                   && ir->compress[ZZ][YY] <= 0));
 
-        if (epcPARRINELLORAHMAN == ir->epc && opts->bGenVel)
+        if (PressureCoupling::ParrinelloRahman == ir->epc && opts->bGenVel)
         {
             sprintf(warn_buf,
                     "You are generating velocities so I am assuming you "
@@ -1249,14 +1228,14 @@ void check_ir(const char*                   mdparin,
                     "equilibrating first with Berendsen pressure coupling. If "
                     "you are not equilibrating the system, you can probably "
                     "ignore this warning.",
-                    epcoupl_names[ir->epc]);
+                    enumValueToString(ir->epc));
             warning(wi, warn_buf);
         }
     }
 
     if (!EI_VV(ir->eI))
     {
-        if (ir->epc == epcMTTK)
+        if (ir->epc == PressureCoupling::Mttk)
         {
             warning_error(wi, "MTTK pressure coupling requires a Velocity-verlet integrator");
         }
@@ -1265,12 +1244,13 @@ void check_ir(const char*                   mdparin,
     /* ELECTROSTATICS */
     /* More checks are in triple check (grompp.c) */
 
-    if (ir->coulombtype == eelSWITCH)
+    if (ir->coulombtype == CoulombInteractionType::Switch)
     {
         sprintf(warn_buf,
                 "coulombtype = %s is only for testing purposes and can lead to serious "
                 "artifacts, advice: use coulombtype = %s",
-                eel_names[ir->coulombtype], eel_names[eelRF_ZERO]);
+                enumValueToString(ir->coulombtype),
+                enumValueToString(CoulombInteractionType::RFZero));
         warning(wi, warn_buf);
     }
 
@@ -1305,11 +1285,11 @@ void check_ir(const char*                   mdparin,
     {
         /* reaction field (at the cut-off) */
 
-        if (ir->coulombtype == eelRF_ZERO && ir->epsilon_rf != 0)
+        if (ir->coulombtype == CoulombInteractionType::RFZero && ir->epsilon_rf != 0)
         {
             sprintf(warn_buf,
                     "With coulombtype = %s, epsilon-rf must be 0, assuming you meant epsilon_rf=0",
-                    eel_names[ir->coulombtype]);
+                    enumValueToString(ir->coulombtype));
             warning(wi, warn_buf);
             ir->epsilon_rf = 0.0;
         }
@@ -1318,8 +1298,9 @@ void check_ir(const char*                   mdparin,
         CHECK((ir->epsilon_rf < ir->epsilon_r && ir->epsilon_rf != 0) || (ir->epsilon_r == 0));
         if (ir->epsilon_rf == ir->epsilon_r)
         {
-            sprintf(warn_buf, "Using epsilon-rf = epsilon-r with %s does not make sense",
-                    eel_names[ir->coulombtype]);
+            sprintf(warn_buf,
+                    "Using epsilon-rf = epsilon-r with %s does not make sense",
+                    enumValueToString(ir->coulombtype));
             warning(wi, warn_buf);
         }
     }
@@ -1334,28 +1315,28 @@ void check_ir(const char*                   mdparin,
             sprintf(err_buf,
                     "With coulombtype = %s rcoulomb_switch must be < rcoulomb. Or, better: Use the "
                     "potential modifier options!",
-                    eel_names[ir->coulombtype]);
+                    enumValueToString(ir->coulombtype));
             CHECK(ir->rcoulomb_switch >= ir->rcoulomb);
         }
     }
 
-    if (ir->coulombtype == eelSWITCH || ir->coulombtype == eelSHIFT)
+    if (ir->coulombtype == CoulombInteractionType::Switch || ir->coulombtype == CoulombInteractionType::Shift)
     {
         sprintf(err_buf,
                 "Explicit switch/shift coulomb interactions cannot be used in combination with a "
                 "secondary coulomb-modifier.");
-        CHECK(ir->coulomb_modifier != eintmodNONE);
+        CHECK(ir->coulomb_modifier != InteractionModifiers::None);
     }
-    if (ir->vdwtype == evdwSWITCH || ir->vdwtype == evdwSHIFT)
+    if (ir->vdwtype == VanDerWaalsType::Switch || ir->vdwtype == VanDerWaalsType::Shift)
     {
         sprintf(err_buf,
                 "Explicit switch/shift vdw interactions cannot be used in combination with a "
                 "secondary vdw-modifier.");
-        CHECK(ir->vdw_modifier != eintmodNONE);
+        CHECK(ir->vdw_modifier != InteractionModifiers::None);
     }
 
-    if (ir->coulombtype == eelSWITCH || ir->coulombtype == eelSHIFT || ir->vdwtype == evdwSWITCH
-        || ir->vdwtype == evdwSHIFT)
+    if (ir->coulombtype == CoulombInteractionType::Switch || ir->coulombtype == CoulombInteractionType::Shift
+        || ir->vdwtype == VanDerWaalsType::Switch || ir->vdwtype == VanDerWaalsType::Shift)
     {
         sprintf(warn_buf,
                 "The switch/shift interaction settings are just for compatibility; you will get "
@@ -1364,7 +1345,8 @@ void check_ir(const char*                   mdparin,
         warning_note(wi, warn_buf);
     }
 
-    if (ir->coulombtype == eelPMESWITCH || ir->coulomb_modifier == eintmodPOTSWITCH)
+    if (ir->coulombtype == CoulombInteractionType::PmeSwitch
+        || ir->coulomb_modifier == InteractionModifiers::PotSwitch)
     {
         if (ir->rcoulomb_switch / ir->rcoulomb < 0.9499)
         {
@@ -1373,12 +1355,15 @@ void check_ir(const char*                   mdparin,
                     "The switching range should be 5%% or less (currently %.2f%% using a switching "
                     "range of %4f-%4f) for accurate electrostatic energies, energy conservation "
                     "will be good regardless, since ewald_rtol = %g.",
-                    percentage, ir->rcoulomb_switch, ir->rcoulomb, ir->ewald_rtol);
+                    percentage,
+                    ir->rcoulomb_switch,
+                    ir->rcoulomb,
+                    ir->ewald_rtol);
             warning(wi, warn_buf);
         }
     }
 
-    if (ir->vdwtype == evdwSWITCH || ir->vdw_modifier == eintmodPOTSWITCH)
+    if (ir->vdwtype == VanDerWaalsType::Switch || ir->vdw_modifier == InteractionModifiers::PotSwitch)
     {
         if (ir->rvdw_switch == 0)
         {
@@ -1393,11 +1378,13 @@ void check_ir(const char*                   mdparin,
 
     if (EEL_FULL(ir->coulombtype))
     {
-        if (ir->coulombtype == eelPMESWITCH || ir->coulombtype == eelPMEUSER
-            || ir->coulombtype == eelPMEUSERSWITCH)
+        if (ir->coulombtype == CoulombInteractionType::PmeSwitch
+            || ir->coulombtype == CoulombInteractionType::PmeUser
+            || ir->coulombtype == CoulombInteractionType::PmeUserSwitch)
         {
-            sprintf(err_buf, "With coulombtype = %s, rcoulomb must be <= rlist",
-                    eel_names[ir->coulombtype]);
+            sprintf(err_buf,
+                    "With coulombtype = %s, rcoulomb must be <= rlist",
+                    enumValueToString(ir->coulombtype));
             CHECK(ir->rcoulomb > ir->rlist);
         }
     }
@@ -1406,32 +1393,41 @@ void check_ir(const char*                   mdparin,
     {
         // TODO: Move these checks into the ewald module with the options class
         int orderMin = 3;
-        int orderMax = (ir->coulombtype == eelP3M_AD ? 8 : 12);
+        int orderMax = (ir->coulombtype == CoulombInteractionType::P3mAD ? 8 : 12);
 
         if (ir->pme_order < orderMin || ir->pme_order > orderMax)
         {
-            sprintf(warn_buf, "With coulombtype = %s, you should have %d <= pme-order <= %d",
-                    eel_names[ir->coulombtype], orderMin, orderMax);
+            sprintf(warn_buf,
+                    "With coulombtype = %s, you should have %d <= pme-order <= %d",
+                    enumValueToString(ir->coulombtype),
+                    orderMin,
+                    orderMax);
             warning_error(wi, warn_buf);
         }
     }
 
     if (ir->nwall == 2 && EEL_FULL(ir->coulombtype))
     {
-        if (ir->ewald_geometry == eewg3D)
+        if (ir->ewald_geometry == EwaldGeometry::ThreeD)
         {
-            sprintf(warn_buf, "With pbc=%s you should use ewald-geometry=%s",
-                    c_pbcTypeNames[ir->pbcType].c_str(), eewg_names[eewg3DC]);
+            sprintf(warn_buf,
+                    "With pbc=%s you should use ewald-geometry=%s",
+                    c_pbcTypeNames[ir->pbcType].c_str(),
+                    enumValueToString(EwaldGeometry::ThreeDC));
             warning(wi, warn_buf);
         }
         /* This check avoids extra pbc coding for exclusion corrections */
         sprintf(err_buf, "wall-ewald-zfac should be >= 2");
         CHECK(ir->wall_ewald_zfac < 2);
     }
-    if ((ir->ewald_geometry == eewg3DC) && (ir->pbcType != PbcType::XY) && EEL_FULL(ir->coulombtype))
+    if ((ir->ewald_geometry == EwaldGeometry::ThreeDC) && (ir->pbcType != PbcType::XY)
+        && EEL_FULL(ir->coulombtype))
     {
-        sprintf(warn_buf, "With %s and ewald_geometry = %s you should use pbc = %s",
-                eel_names[ir->coulombtype], eewg_names[eewg3DC], c_pbcTypeNames[PbcType::XY].c_str());
+        sprintf(warn_buf,
+                "With %s and ewald_geometry = %s you should use pbc = %s",
+                enumValueToString(ir->coulombtype),
+                enumValueToString(EwaldGeometry::ThreeDC),
+                c_pbcTypeNames[PbcType::XY].c_str());
         warning(wi, warn_buf);
     }
     if ((ir->epsilon_surface != 0) && EEL_FULL(ir->coulombtype))
@@ -1458,22 +1454,27 @@ void check_ir(const char*                   mdparin,
                     "You are applying a switch function to vdw forces or potentials from %g to %g "
                     "nm, which is more than half the interaction range, whereas switch functions "
                     "are intended to act only close to the cut-off.",
-                    ir->rvdw_switch, ir->rvdw);
+                    ir->rvdw_switch,
+                    ir->rvdw);
             warning_note(wi, warn_buf);
         }
     }
 
-    if (ir->vdwtype == evdwPME)
+    if (ir->vdwtype == VanDerWaalsType::Pme)
     {
-        if (!(ir->vdw_modifier == eintmodNONE || ir->vdw_modifier == eintmodPOTSHIFT))
+        if (!(ir->vdw_modifier == InteractionModifiers::None
+              || ir->vdw_modifier == InteractionModifiers::PotShift))
         {
-            sprintf(err_buf, "With vdwtype = %s, the only supported modifiers are %s and %s",
-                    evdw_names[ir->vdwtype], eintmod_names[eintmodPOTSHIFT], eintmod_names[eintmodNONE]);
+            sprintf(err_buf,
+                    "With vdwtype = %s, the only supported modifiers are %s and %s",
+                    enumValueToString(ir->vdwtype),
+                    enumValueToString(InteractionModifiers::PotShift),
+                    enumValueToString(InteractionModifiers::None));
             warning_error(wi, err_buf);
         }
     }
 
-    if (ir->vdwtype == evdwUSER && ir->eDispCorr != edispcNO)
+    if (ir->vdwtype == VanDerWaalsType::User && ir->eDispCorr != DispersionCorrectionType::No)
     {
         warning_note(wi,
                      "You have selected user tables with dispersion correction, the dispersion "
@@ -1482,20 +1483,22 @@ void check_ir(const char*                   mdparin,
                      "really want dispersion correction to -C6/r^6.");
     }
 
-    if (ir->eI == eiLBFGS && (ir->coulombtype == eelCUT || ir->vdwtype == evdwCUT) && ir->rvdw != 0)
+    if (ir->eI == IntegrationAlgorithm::LBFGS
+        && (ir->coulombtype == CoulombInteractionType::Cut || ir->vdwtype == VanDerWaalsType::Cut)
+        && ir->rvdw != 0)
     {
         warning(wi, "For efficient BFGS minimization, use switch/shift/pme instead of cut-off.");
     }
 
-    if (ir->eI == eiLBFGS && ir->nbfgscorr <= 0)
+    if (ir->eI == IntegrationAlgorithm::LBFGS && ir->nbfgscorr <= 0)
     {
         warning(wi, "Using L-BFGS with nbfgscorr<=0 just gets you steepest descent.");
     }
 
     /* IMPLICIT SOLVENT */
-    if (ir->coulombtype == eelGB_NOTUSED)
+    if (ir->coulombtype == CoulombInteractionType::GBNotused)
     {
-        sprintf(warn_buf, "Invalid option %s for coulombtype", eel_names[ir->coulombtype]);
+        sprintf(warn_buf, "Invalid option %s for coulombtype", enumValueToString(ir->coulombtype));
         warning_error(wi, warn_buf);
     }
 
@@ -1510,7 +1513,7 @@ void check_ir(const char*                   mdparin,
     }
 
     // cosine acceleration is only supported in leap-frog
-    if (ir->cos_accel != 0.0 && ir->eI != eiMD)
+    if (ir->cos_accel != 0.0 && ir->eI != IntegrationAlgorithm::MD)
     {
         warning_error(wi, "cos-acceleration is only supported by integrator = md");
     }
@@ -1521,51 +1524,52 @@ void check_ir(const char*                   mdparin,
    str = the input string
    n = the (pre-allocated) number of doubles read
    r = the output array of doubles. */
-static void parse_n_real(char* str, int* n, real** r, warninp_t wi)
+static std::vector<real> parse_n_real(const std::string& str, int* n, warninp_t wi)
 {
     auto values = gmx::splitString(str);
     *n          = values.size();
 
-    snew(*r, *n);
+    std::vector<real> r;
     for (int i = 0; i < *n; i++)
     {
         try
         {
-            (*r)[i] = gmx::fromString<real>(values[i]);
+            r.emplace_back(gmx::fromString<real>(values[i]));
         }
         catch (gmx::GromacsException&)
         {
-            warning_error(wi, "Invalid value " + values[i]
-                                      + " in string in mdp file. Expected a real number.");
+            warning_error(wi,
+                          "Invalid value " + values[i]
+                                  + " in string in mdp file. Expected a real number.");
         }
     }
+    return r;
 }
 
 
-static void do_fep_params(t_inputrec* ir, char fep_lambda[][STRLEN], char weights[STRLEN], warninp_t wi)
+static void do_fep_params(t_inputrec* ir, gmx::ArrayRef<std::string> fep_lambda, char weights[STRLEN], warninp_t wi)
 {
 
-    int         i, j, max_n_lambda, nweights, nfep[efptNR];
-    t_lambda*   fep    = ir->fepvals;
-    t_expanded* expand = ir->expandedvals;
-    real**      count_fep_lambdas;
-    bool        bOneLambda = TRUE;
-
-    snew(count_fep_lambdas, efptNR);
+    int         i, j, max_n_lambda, nweights;
+    t_lambda*   fep    = ir->fepvals.get();
+    t_expanded* expand = ir->expandedvals.get();
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, std::vector<real>> count_fep_lambdas;
+    bool                                                                         bOneLambda = TRUE;
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, int>               nfep;
 
     /* FEP input processing */
     /* first, identify the number of lambda values for each type.
        All that are nonzero must have the same number */
 
-    for (i = 0; i < efptNR; i++)
+    for (auto i : keysOf(nfep))
     {
-        parse_n_real(fep_lambda[i], &(nfep[i]), &(count_fep_lambdas[i]), wi);
+        count_fep_lambdas[i] = parse_n_real(fep_lambda[static_cast<int>(i)], &(nfep[i]), wi);
     }
 
     /* now, determine the number of components.  All must be either zero, or equal. */
 
     max_n_lambda = 0;
-    for (i = 0; i < efptNR; i++)
+    for (auto i : keysOf(nfep))
     {
         if (nfep[i] > max_n_lambda)
         {
@@ -1575,7 +1579,7 @@ static void do_fep_params(t_inputrec* ir, char fep_lambda[][STRLEN], char weight
         }
     }
 
-    for (i = 0; i < efptNR; i++)
+    for (auto i : keysOf(nfep))
     {
         if (nfep[i] == 0)
         {
@@ -1583,7 +1587,7 @@ static void do_fep_params(t_inputrec* ir, char fep_lambda[][STRLEN], char weight
         }
         else if (nfep[i] == max_n_lambda)
         {
-            if (i != efptTEMPERATURE) /* we treat this differently -- not really a reason to compute
+            if (i != FreeEnergyPerturbationCouplingType::Temperature) /* we treat this differently -- not really a reason to compute
                                          the derivative with respect to the temperature currently */
             {
                 ir->fepvals->separate_dvdl[i] = TRUE;
@@ -1594,27 +1598,27 @@ static void do_fep_params(t_inputrec* ir, char fep_lambda[][STRLEN], char weight
             gmx_fatal(FARGS,
                       "Number of lambdas (%d) for FEP type %s not equal to number of other types "
                       "(%d)",
-                      nfep[i], efpt_names[i], max_n_lambda);
+                      nfep[i],
+                      enumValueToString(i),
+                      max_n_lambda);
         }
     }
     /* we don't print out dhdl if the temperature is changing, since we can't correctly define dhdl in this case */
-    ir->fepvals->separate_dvdl[efptTEMPERATURE] = FALSE;
+    ir->fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Temperature] = FALSE;
 
     /* the number of lambdas is the number we've read in, which is either zero
        or the same for all */
     fep->n_lambda = max_n_lambda;
 
-    /* allocate space for the array of lambda values */
-    snew(fep->all_lambda, efptNR);
     /* if init_lambda is defined, we need to set lambda */
     if ((fep->init_lambda > 0) && (fep->n_lambda == 0))
     {
-        ir->fepvals->separate_dvdl[efptFEP] = TRUE;
+        ir->fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Fep] = TRUE;
     }
     /* otherwise allocate the space for all of the lambdas, and transfer the data */
-    for (i = 0; i < efptNR; i++)
+    for (auto i : keysOf(nfep))
     {
-        snew(fep->all_lambda[i], fep->n_lambda);
+        fep->all_lambda[i].resize(fep->n_lambda);
         if (nfep[i] > 0) /* if it's zero, then the count_fep_lambda arrays
                             are zero */
         {
@@ -1622,19 +1626,17 @@ static void do_fep_params(t_inputrec* ir, char fep_lambda[][STRLEN], char weight
             {
                 fep->all_lambda[i][j] = static_cast<double>(count_fep_lambdas[i][j]);
             }
-            sfree(count_fep_lambdas[i]);
         }
     }
-    sfree(count_fep_lambdas);
 
     /* "fep-vals" is either zero or the full number. If zero, we'll need to define fep-lambdas for
        internal bookkeeping -- for now, init_lambda */
 
-    if ((nfep[efptFEP] == 0) && (fep->init_lambda >= 0))
+    if ((nfep[FreeEnergyPerturbationCouplingType::Fep] == 0) && (fep->init_lambda >= 0))
     {
         for (i = 0; i < fep->n_lambda; i++)
         {
-            fep->all_lambda[efptFEP][i] = fep->init_lambda;
+            fep->all_lambda[FreeEnergyPerturbationCouplingType::Fep][i] = fep->init_lambda;
         }
     }
 
@@ -1647,9 +1649,9 @@ static void do_fep_params(t_inputrec* ir, char fep_lambda[][STRLEN], char weight
     }
     else
     {
-        for (i = 0; i < efptNR; i++)
+        for (auto i : keysOf(nfep))
         {
-            if ((nfep[i] != 0) && (i != efptFEP))
+            if ((nfep[i] != 0) && (i != FreeEnergyPerturbationCouplingType::Fep))
             {
                 bOneLambda = FALSE;
             }
@@ -1664,30 +1666,32 @@ static void do_fep_params(t_inputrec* ir, char fep_lambda[][STRLEN], char weight
        specified (i.e. nfep[i] == 0).  This means if fep is not defined,
        they are all zero. */
 
-    for (i = 0; i < efptNR; i++)
+    for (auto i : keysOf(nfep))
     {
-        if ((nfep[i] == 0) && (i != efptFEP))
+        if ((nfep[i] == 0) && (i != FreeEnergyPerturbationCouplingType::Fep))
         {
             for (j = 0; j < fep->n_lambda; j++)
             {
-                fep->all_lambda[i][j] = fep->all_lambda[efptFEP][j];
+                fep->all_lambda[i][j] = fep->all_lambda[FreeEnergyPerturbationCouplingType::Fep][j];
             }
         }
     }
 
 
     /* now read in the weights */
-    parse_n_real(weights, &nweights, &(expand->init_lambda_weights), wi);
+    expand->init_lambda_weights = parse_n_real(weights, &nweights, wi);
     if (nweights == 0)
     {
-        snew(expand->init_lambda_weights, fep->n_lambda); /* initialize to zero */
+        expand->init_lambda_weights.resize(fep->n_lambda); /* initialize to zero */
     }
     else if (nweights != fep->n_lambda)
     {
-        gmx_fatal(FARGS, "Number of weights (%d) is not equal to number of lambda values (%d)",
-                  nweights, fep->n_lambda);
+        gmx_fatal(FARGS,
+                  "Number of weights (%d) is not equal to number of lambda values (%d)",
+                  nweights,
+                  fep->n_lambda);
     }
-    if ((expand->nstexpanded < 0) && (ir->efep != efepNO))
+    if ((expand->nstexpanded < 0) && (ir->efep != FreeEnergyPerturbationType::No))
     {
         expand->nstexpanded = fep->nstdhdl;
         /* if you don't specify nstexpanded when doing expanded ensemble free energy calcs, it is set to nstdhdl */
@@ -1697,9 +1701,10 @@ static void do_fep_params(t_inputrec* ir, char fep_lambda[][STRLEN], char weight
 
 static void do_simtemp_params(t_inputrec* ir)
 {
-
-    snew(ir->simtempvals->temperatures, ir->fepvals->n_lambda);
-    GetSimTemps(ir->fepvals->n_lambda, ir->simtempvals, ir->fepvals->all_lambda[efptTEMPERATURE]);
+    ir->simtempvals->temperatures.resize(ir->fepvals->n_lambda);
+    getSimTemps(ir->fepvals->n_lambda,
+                ir->simtempvals.get(),
+                ir->fepvals->all_lambda[FreeEnergyPerturbationCouplingType::Temperature]);
 }
 
 template<typename T>
@@ -1717,7 +1722,8 @@ void convertInts(warninp_t wi, gmx::ArrayRef<const std::string> inputs, const ch
             auto message = gmx::formatString(
                     "Invalid value for mdp option %s. %s should only consist of integers separated "
                     "by spaces.",
-                    name, name);
+                    name,
+                    name);
             warning_error(wi, message);
         }
         ++i;
@@ -1738,39 +1744,14 @@ static void convertReals(warninp_t wi, gmx::ArrayRef<const std::string> inputs,
             auto message = gmx::formatString(
                     "Invalid value for mdp option %s. %s should only consist of real numbers "
                     "separated by spaces.",
-                    name, name);
+                    name,
+                    name);
             warning_error(wi, message);
         }
         ++i;
     }
 }
 
-static void convertRvecs(warninp_t wi, gmx::ArrayRef<const std::string> inputs, const char* name, rvec* outputs)
-{
-    int i = 0, d = 0;
-    for (const auto& input : inputs)
-    {
-        try
-        {
-            outputs[i][d] = gmx::fromString<real>(input);
-        }
-        catch (gmx::GromacsException&)
-        {
-            auto message = gmx::formatString(
-                    "Invalid value for mdp option %s. %s should only consist of real numbers "
-                    "separated by spaces.",
-                    name, name);
-            warning_error(wi, message);
-        }
-        ++d;
-        if (d == DIM)
-        {
-            d = 0;
-            ++i;
-        }
-    }
-}
-
 static void do_wall_params(t_inputrec* ir, char* wall_atomtype, char* wall_density, t_gromppopts* opts, warninp_t wi)
 {
     opts->wall_atomtype[0] = nullptr;
@@ -1786,7 +1767,9 @@ static void do_wall_params(t_inputrec* ir, char* wall_atomtype, char* wall_densi
         auto wallAtomTypes = gmx::splitString(wall_atomtype);
         if (wallAtomTypes.size() != size_t(ir->nwall))
         {
-            gmx_fatal(FARGS, "Expected %d elements for wall_atomtype, found %zu", ir->nwall,
+            gmx_fatal(FARGS,
+                      "Expected %d elements for wall_atomtype, found %zu",
+                      ir->nwall,
                       wallAtomTypes.size());
         }
         GMX_RELEASE_ASSERT(ir->nwall < 3, "Invalid number of walls");
@@ -1795,12 +1778,14 @@ static void do_wall_params(t_inputrec* ir, char* wall_atomtype, char* wall_densi
             opts->wall_atomtype[i] = gmx_strdup(wallAtomTypes[i].c_str());
         }
 
-        if (ir->wall_type == ewt93 || ir->wall_type == ewt104)
+        if (ir->wall_type == WallType::NineThree || ir->wall_type == WallType::TenFour)
         {
             auto wallDensity = gmx::splitString(wall_density);
             if (wallDensity.size() != size_t(ir->nwall))
             {
-                gmx_fatal(FARGS, "Expected %d elements for wall-density, found %zu", ir->nwall,
+                gmx_fatal(FARGS,
+                          "Expected %d elements for wall-density, found %zu",
+                          ir->nwall,
                           wallDensity.size());
             }
             convertReals(wi, wallDensity, "wall-density", ir->wall_density);
@@ -1832,10 +1817,10 @@ static void read_expandedparams(std::vector<t_inpfile>* inp, t_expanded* expand,
 {
     /* read expanded ensemble parameters */
     printStringNewline(inp, "expanded ensemble variables");
-    expand->nstexpanded    = get_eint(inp, "nstexpanded", -1, wi);
-    expand->elamstats      = get_eeenum(inp, "lmc-stats", elamstats_names, wi);
-    expand->elmcmove       = get_eeenum(inp, "lmc-move", elmcmove_names, wi);
-    expand->elmceq         = get_eeenum(inp, "lmc-weights-equil", elmceq_names, wi);
+    expand->nstexpanded = get_eint(inp, "nstexpanded", -1, wi);
+    expand->elamstats   = getEnum<LambdaWeightCalculation>(inp, "lmc-stats", wi);
+    expand->elmcmove    = getEnum<LambdaMoveCalculation>(inp, "lmc-move", wi);
+    expand->elmceq      = getEnum<LambdaWeightWillReachEquilibrium>(inp, "lmc-weights-equil", wi);
     expand->equil_n_at_lam = get_eint(inp, "weight-equil-number-all-lambda", -1, wi);
     expand->equil_samples  = get_eint(inp, "weight-equil-number-samples", -1, wi);
     expand->equil_steps    = get_eint(inp, "weight-equil-number-steps", -1, wi);
@@ -1848,14 +1833,14 @@ static void read_expandedparams(std::vector<t_inpfile>* inp, t_expanded* expand,
     expand->gibbsdeltalam     = get_eint(inp, "lmc-gibbsdelta", -1, wi);
     expand->lmc_forced_nstart = get_eint(inp, "lmc-forced-nstart", 0, wi);
     expand->bSymmetrizedTMatrix =
-            (get_eeenum(inp, "symmetrized-transition-matrix", yesno_names, wi) != 0);
+            (getEnum<Boolean>(inp, "symmetrized-transition-matrix", wi) != Boolean::No);
     expand->nstTij        = get_eint(inp, "nst-transition-matrix", -1, wi);
     expand->minvarmin     = get_eint(inp, "mininum-var-min", 100, wi); /*default is reasonable */
     expand->c_range       = get_eint(inp, "weight-c-range", 0, wi);    /* default is just C=0 */
     expand->wl_scale      = get_ereal(inp, "wl-scale", 0.8, wi);
     expand->wl_ratio      = get_ereal(inp, "wl-ratio", 0.8, wi);
     expand->init_wl_delta = get_ereal(inp, "init-wl-delta", 1.0, wi);
-    expand->bWLoneovert   = (get_eeenum(inp, "wl-oneovert", yesno_names, wi) != 0);
+    expand->bWLoneovert   = (getEnum<Boolean>(inp, "wl-oneovert", wi) != Boolean::No);
 }
 
 /*! \brief Return whether an end state with the given coupling-lambda
@@ -1919,8 +1904,8 @@ void get_ir(const char*     mdparin,
     double      dumdub[2][6];
     int         i, j, m;
     char        warn_buf[STRLEN];
-    t_lambda*   fep    = ir->fepvals;
-    t_expanded* expand = ir->expandedvals;
+    t_lambda*   fep    = ir->fepvals.get();
+    t_expanded* expand = ir->expandedvals.get();
 
     const char* no_names[] = { "no", nullptr };
 
@@ -1987,7 +1972,7 @@ void get_ir(const char*     mdparin,
     setStringEntry(&inp, "define", opts->define, nullptr);
 
     printStringNewline(&inp, "RUN CONTROL PARAMETERS");
-    ir->eI = get_eeenum(&inp, "integrator", ei_names, wi);
+    ir->eI = getEnum<IntegrationAlgorithm>(&inp, "integrator", wi);
     printStringNoNewline(&inp, "Start time and timestep in ps");
     ir->init_t  = get_ereal(&inp, "tinit", 0.0, wi);
     ir->delta_t = get_ereal(&inp, "dt", 0.001, wi);
@@ -1998,24 +1983,22 @@ void get_ir(const char*     mdparin,
             &inp, "Part index is updated automatically on checkpointing (keeps files separate)");
     ir->simulation_part = get_eint(&inp, "simulation-part", 1, wi);
     printStringNoNewline(&inp, "Multiple time-stepping");
-    ir->useMts = (get_eeenum(&inp, "mts", yesno_names, wi) != 0);
+    ir->useMts = (getEnum<Boolean>(&inp, "mts", wi) != Boolean::No);
     if (ir->useMts)
     {
-        opts->numMtsLevels = get_eint(&inp, "mts-levels", 2, wi);
-        ir->mtsLevels.resize(2);
-        gmx::MtsLevel& mtsLevel = ir->mtsLevels[1];
-        opts->mtsLevel2Forces   = setStringEntry(&inp, "mts-level2-forces", "longrange-nonbonded");
-        mtsLevel.stepFactor     = get_eint(&inp, "mts-level2-factor", 2, wi);
+        gmx::GromppMtsOpts& mtsOpts = opts->mtsOpts;
+        mtsOpts.numLevels           = get_eint(&inp, "mts-levels", 2, wi);
+        mtsOpts.level2Forces = setStringEntry(&inp, "mts-level2-forces", "longrange-nonbonded");
+        mtsOpts.level2Factor = get_eint(&inp, "mts-level2-factor", 2, wi);
 
         // We clear after reading without dynamics to not force the user to remove MTS mdp options
         if (!EI_DYNAMICS(ir->eI))
         {
             ir->useMts = false;
-            ir->mtsLevels.clear();
         }
     }
     printStringNoNewline(&inp, "mode for center of mass motion removal");
-    ir->comm_mode = get_eeenum(&inp, "comm-mode", ecm_names, wi);
+    ir->comm_mode = getEnum<ComRemovalAlgorithm>(&inp, "comm-mode", wi);
     printStringNoNewline(&inp, "number of steps for center of mass motion removal");
     ir->nstcomm = get_eint(&inp, "nstcomm", 100, wi);
     printStringNoNewline(&inp, "group(s) for center of mass motion removal");
@@ -2065,7 +2048,7 @@ void get_ir(const char*     mdparin,
     /* Neighbor searching */
     printStringNewline(&inp, "NEIGHBORSEARCHING PARAMETERS");
     printStringNoNewline(&inp, "cut-off scheme (Verlet: particle based cut-offs)");
-    ir->cutoff_scheme = get_eeenum(&inp, "cutoff-scheme", ecutscheme_names, wi);
+    ir->cutoff_scheme = getEnum<CutoffScheme>(&inp, "cutoff-scheme", wi);
     printStringNoNewline(&inp, "nblist update frequency");
     ir->nstlist = get_eint(&inp, "nstlist", 10, wi);
     printStringNoNewline(&inp, "Periodic boundary conditions: xyz, no, xy");
@@ -2076,7 +2059,7 @@ void get_ir(const char*     mdparin,
         pbcTypesNamesChar.push_back(pbcTypeName.c_str());
     }
     ir->pbcType       = static_cast<PbcType>(get_eeenum(&inp, "pbc", pbcTypesNamesChar.data(), wi));
-    ir->bPeriodicMols = get_eeenum(&inp, "periodic-molecules", yesno_names, wi) != 0;
+    ir->bPeriodicMols = getEnum<Boolean>(&inp, "periodic-molecules", wi) != Boolean::No;
     printStringNoNewline(&inp,
                          "Allowed energy error due to the Verlet buffer in kJ/mol/ps per atom,");
     printStringNoNewline(&inp, "a value of -1 means: use rlist");
@@ -2088,23 +2071,22 @@ void get_ir(const char*     mdparin,
     /* Electrostatics */
     printStringNewline(&inp, "OPTIONS FOR ELECTROSTATICS AND VDW");
     printStringNoNewline(&inp, "Method for doing electrostatics");
-    ir->coulombtype      = get_eeenum(&inp, "coulombtype", eel_names, wi);
-    ir->coulomb_modifier = get_eeenum(&inp, "coulomb-modifier", eintmod_names, wi);
+    ir->coulombtype      = getEnum<CoulombInteractionType>(&inp, "coulombtype", wi);
+    ir->coulomb_modifier = getEnum<InteractionModifiers>(&inp, "coulomb-modifier", wi);
     printStringNoNewline(&inp, "cut-off lengths");
     ir->rcoulomb_switch = get_ereal(&inp, "rcoulomb-switch", 0.0, wi);
     ir->rcoulomb        = get_ereal(&inp, "rcoulomb", 1.0, wi);
-    printStringNoNewline(&inp,
-                         "Relative dielectric constant for the medium and the reaction field");
+    printStringNoNewline(&inp, "Relative dielectric constant for the medium and the reaction field");
     ir->epsilon_r  = get_ereal(&inp, "epsilon-r", 1.0, wi);
     ir->epsilon_rf = get_ereal(&inp, "epsilon-rf", 0.0, wi);
     printStringNoNewline(&inp, "Method for doing Van der Waals");
-    ir->vdwtype      = get_eeenum(&inp, "vdw-type", evdw_names, wi);
-    ir->vdw_modifier = get_eeenum(&inp, "vdw-modifier", eintmod_names, wi);
+    ir->vdwtype      = getEnum<VanDerWaalsType>(&inp, "vdw-type", wi);
+    ir->vdw_modifier = getEnum<InteractionModifiers>(&inp, "vdw-modifier", wi);
     printStringNoNewline(&inp, "cut-off lengths");
     ir->rvdw_switch = get_ereal(&inp, "rvdw-switch", 0.0, wi);
     ir->rvdw        = get_ereal(&inp, "rvdw", 1.0, wi);
     printStringNoNewline(&inp, "Apply long range dispersion corrections for Energy and Pressure");
-    ir->eDispCorr = get_eeenum(&inp, "DispCorr", edispc_names, wi);
+    ir->eDispCorr = getEnum<DispersionCorrectionType>(&inp, "DispCorr", wi);
     printStringNoNewline(&inp, "Extension of the potential lookup tables beyond the cut-off");
     ir->tabext = get_ereal(&inp, "table-extension", 1.0, wi);
     printStringNoNewline(&inp, "Separate tables between energy group pairs");
@@ -2119,8 +2101,8 @@ void get_ir(const char*     mdparin,
     ir->pme_order              = get_eint(&inp, "pme-order", 4, wi);
     ir->ewald_rtol             = get_ereal(&inp, "ewald-rtol", 0.00001, wi);
     ir->ewald_rtol_lj          = get_ereal(&inp, "ewald-rtol-lj", 0.001, wi);
-    ir->ljpme_combination_rule = get_eeenum(&inp, "lj-pme-comb-rule", eljpme_names, wi);
-    ir->ewald_geometry         = get_eeenum(&inp, "ewald-geometry", eewg_names, wi);
+    ir->ljpme_combination_rule = getEnum<LongRangeVdW>(&inp, "lj-pme-comb-rule", wi);
+    ir->ewald_geometry         = getEnum<EwaldGeometry>(&inp, "ewald-geometry", wi);
     ir->epsilon_surface        = get_ereal(&inp, "epsilon-surface", 0.0, wi);
 
     /* Implicit solvation is no longer supported, but we need grompp
@@ -2131,29 +2113,29 @@ void get_ir(const char*     mdparin,
     /* Coupling stuff */
     printStringNewline(&inp, "OPTIONS FOR WEAK COUPLING ALGORITHMS");
     printStringNoNewline(&inp, "Temperature coupling");
-    ir->etc                = get_eeenum(&inp, "tcoupl", etcoupl_names, wi);
+    ir->etc                = getEnum<TemperatureCoupling>(&inp, "tcoupl", wi);
     ir->nsttcouple         = get_eint(&inp, "nsttcouple", -1, wi);
     ir->opts.nhchainlength = get_eint(&inp, "nh-chain-length", 10, wi);
-    ir->bPrintNHChains = (get_eeenum(&inp, "print-nose-hoover-chain-variables", yesno_names, wi) != 0);
+    ir->bPrintNHChains = (getEnum<Boolean>(&inp, "print-nose-hoover-chain-variables", wi) != Boolean::No);
     printStringNoNewline(&inp, "Groups to couple separately");
     setStringEntry(&inp, "tc-grps", inputrecStrings->tcgrps, nullptr);
     printStringNoNewline(&inp, "Time constant (ps) and reference temperature (K)");
     setStringEntry(&inp, "tau-t", inputrecStrings->tau_t, nullptr);
     setStringEntry(&inp, "ref-t", inputrecStrings->ref_t, nullptr);
     printStringNoNewline(&inp, "pressure coupling");
-    ir->epc        = get_eeenum(&inp, "pcoupl", epcoupl_names, wi);
-    ir->epct       = get_eeenum(&inp, "pcoupltype", epcoupltype_names, wi);
+    ir->epc        = getEnum<PressureCoupling>(&inp, "pcoupl", wi);
+    ir->epct       = getEnum<PressureCouplingType>(&inp, "pcoupltype", wi);
     ir->nstpcouple = get_eint(&inp, "nstpcouple", -1, wi);
     printStringNoNewline(&inp, "Time constant (ps), compressibility (1/bar) and reference P (bar)");
     ir->tau_p = get_ereal(&inp, "tau-p", 1.0, wi);
     setStringEntry(&inp, "compressibility", dumstr[0], nullptr);
     setStringEntry(&inp, "ref-p", dumstr[1], nullptr);
     printStringNoNewline(&inp, "Scaling of reference coordinates, No, All or COM");
-    ir->refcoord_scaling = get_eeenum(&inp, "refcoord-scaling", erefscaling_names, wi);
+    ir->refcoord_scaling = getEnum<RefCoordScaling>(&inp, "refcoord-scaling", wi);
 
     /* QMMM */
     printStringNewline(&inp, "OPTIONS FOR QMMM calculations");
-    ir->bQMMM = (get_eeenum(&inp, "QMMM", yesno_names, wi) != 0);
+    ir->bQMMM = (getEnum<Boolean>(&inp, "QMMM", wi) != Boolean::No);
     printStringNoNewline(&inp, "Groups treated with MiMiC");
     setStringEntry(&inp, "QMMM-grps", inputrecStrings->QMMM, nullptr);
 
@@ -2171,7 +2153,7 @@ void get_ir(const char*     mdparin,
 
     /* Startup run */
     printStringNewline(&inp, "GENERATE VELOCITIES FOR STARTUP RUN");
-    opts->bGenVel = (get_eeenum(&inp, "gen-vel", yesno_names, wi) != 0);
+    opts->bGenVel = (getEnum<Boolean>(&inp, "gen-vel", wi) != Boolean::No);
     opts->tempi   = get_ereal(&inp, "gen-temp", 300.0, wi);
     opts->seed    = get_eint(&inp, "gen-seed", -1, wi);
 
@@ -2179,12 +2161,12 @@ void get_ir(const char*     mdparin,
     printStringNewline(&inp, "OPTIONS FOR BONDS");
     opts->nshake = get_eeenum(&inp, "constraints", constraints, wi);
     printStringNoNewline(&inp, "Type of constraint algorithm");
-    ir->eConstrAlg = get_eeenum(&inp, "constraint-algorithm", econstr_names, wi);
+    ir->eConstrAlg = getEnum<ConstraintAlgorithm>(&inp, "constraint-algorithm", wi);
     printStringNoNewline(&inp, "Do not constrain the start configuration");
-    ir->bContinuation = (get_eeenum(&inp, "continuation", yesno_names, wi) != 0);
+    ir->bContinuation = (getEnum<Boolean>(&inp, "continuation", wi) != Boolean::No);
     printStringNoNewline(&inp,
                          "Use successive overrelaxation to reduce the number of shake iterations");
-    ir->bShakeSOR = (get_eeenum(&inp, "Shake-SOR", yesno_names, wi) != 0);
+    ir->bShakeSOR = (getEnum<Boolean>(&inp, "Shake-SOR", wi) != Boolean::No);
     printStringNoNewline(&inp, "Relative tolerance of shake");
     ir->shake_tol = get_ereal(&inp, "shake-tol", 0.0001, wi);
     printStringNoNewline(&inp, "Highest order in the expansion of the constraint coupling matrix");
@@ -2197,7 +2179,7 @@ void get_ir(const char*     mdparin,
     printStringNoNewline(&inp, "rotates over more degrees than");
     ir->LincsWarnAngle = get_ereal(&inp, "lincs-warnangle", 30.0, wi);
     printStringNoNewline(&inp, "Convert harmonic bonds to morse potentials");
-    opts->bMorse = (get_eeenum(&inp, "morse", yesno_names, wi) != 0);
+    opts->bMorse = (getEnum<Boolean>(&inp, "morse", wi) != Boolean::No);
 
     /* Energy group exclusions */
     printStringNewline(&inp, "ENERGY GROUP EXCLUSIONS");
@@ -2210,7 +2192,7 @@ void get_ir(const char*     mdparin,
     printStringNoNewline(
             &inp, "Number of walls, type, atom types, densities and box-z scale factor for Ewald");
     ir->nwall         = get_eint(&inp, "nwall", 0, wi);
-    ir->wall_type     = get_eeenum(&inp, "wall-type", ewt_names, wi);
+    ir->wall_type     = getEnum<WallType>(&inp, "wall-type", wi);
     ir->wall_r_linpot = get_ereal(&inp, "wall-r-linpot", -1, wi);
     setStringEntry(&inp, "wall-atomtype", inputrecStrings->wall_atomtype, nullptr);
     setStringEntry(&inp, "wall-density", inputrecStrings->wall_density, nullptr);
@@ -2218,7 +2200,7 @@ void get_ir(const char*     mdparin,
 
     /* COM pulling */
     printStringNewline(&inp, "COM PULLING");
-    ir->bPull = (get_eeenum(&inp, "pull", yesno_names, wi) != 0);
+    ir->bPull = (getEnum<Boolean>(&inp, "pull", wi) != Boolean::No);
     if (ir->bPull)
     {
         ir->pull                        = std::make_unique<pull_params_t>();
@@ -2228,7 +2210,7 @@ void get_ir(const char*     mdparin,
         {
             for (int c = 0; c < ir->pull->ncoord; c++)
             {
-                if (ir->pull->coord[c].eType == epullCONSTRAINT)
+                if (ir->pull->coord[c].eType == PullingAlgorithm::Constraint)
                 {
                     warning_error(wi,
                                   "Constraint COM pulling is not supported in combination with "
@@ -2242,16 +2224,16 @@ void get_ir(const char*     mdparin,
     /* AWH biasing
        NOTE: needs COM pulling or free energy input */
     printStringNewline(&inp, "AWH biasing");
-    ir->bDoAwh = (get_eeenum(&inp, "awh", yesno_names, wi) != 0);
+    ir->bDoAwh = (getEnum<Boolean>(&inp, "awh", wi) != Boolean::No);
     if (ir->bDoAwh)
     {
-        ir->awhParams = gmx::readAwhParams(&inp, wi);
+        ir->awhParams = std::make_unique<gmx::AwhParams>(&inp, wi);
     }
 
     /* Enforced rotation */
     printStringNewline(&inp, "ENFORCED ROTATION");
     printStringNoNewline(&inp, "Enforced rotation: No or Yes");
-    ir->bRot = (get_eeenum(&inp, "rotation", yesno_names, wi) != 0);
+    ir->bRot = (getEnum<Boolean>(&inp, "rotation", wi) != Boolean::No);
     if (ir->bRot)
     {
         snew(ir->rot, 1);
@@ -2271,18 +2253,18 @@ void get_ir(const char*     mdparin,
     /* Refinement */
     printStringNewline(&inp, "NMR refinement stuff");
     printStringNoNewline(&inp, "Distance restraints type: No, Simple or Ensemble");
-    ir->eDisre = get_eeenum(&inp, "disre", edisre_names, wi);
+    ir->eDisre = getEnum<DistanceRestraintRefinement>(&inp, "disre", wi);
     printStringNoNewline(
             &inp, "Force weighting of pairs in one distance restraint: Conservative or Equal");
-    ir->eDisreWeighting = get_eeenum(&inp, "disre-weighting", edisreweighting_names, wi);
+    ir->eDisreWeighting = getEnum<DistanceRestraintWeighting>(&inp, "disre-weighting", wi);
     printStringNoNewline(&inp, "Use sqrt of the time averaged times the instantaneous violation");
-    ir->bDisreMixed = (get_eeenum(&inp, "disre-mixed", yesno_names, wi) != 0);
+    ir->bDisreMixed = (getEnum<Boolean>(&inp, "disre-mixed", wi) != Boolean::No);
     ir->dr_fc       = get_ereal(&inp, "disre-fc", 1000.0, wi);
     ir->dr_tau      = get_ereal(&inp, "disre-tau", 0.0, wi);
     printStringNoNewline(&inp, "Output frequency for pair distances to energy file");
     ir->nstdisreout = get_eint(&inp, "nstdisreout", 100, wi);
     printStringNoNewline(&inp, "Orientation restraints: No or Yes");
-    opts->bOrire = (get_eeenum(&inp, "orire", yesno_names, wi) != 0);
+    opts->bOrire = (getEnum<Boolean>(&inp, "orire", wi) != Boolean::No);
     printStringNoNewline(&inp, "Orientation restraints force constant and tau for time averaging");
     ir->orires_fc  = get_ereal(&inp, "orire-fc", 0.0, wi);
     ir->orires_tau = get_ereal(&inp, "orire-tau", 0.0, wi);
@@ -2292,11 +2274,11 @@ void get_ir(const char*     mdparin,
 
     /* free energy variables */
     printStringNewline(&inp, "Free energy variables");
-    ir->efep = get_eeenum(&inp, "free-energy", efep_names, wi);
+    ir->efep = getEnum<FreeEnergyPerturbationType>(&inp, "free-energy", wi);
     setStringEntry(&inp, "couple-moltype", inputrecStrings->couple_moltype, nullptr);
     opts->couple_lam0  = get_eeenum(&inp, "couple-lambda0", couple_lam, wi);
     opts->couple_lam1  = get_eeenum(&inp, "couple-lambda1", couple_lam, wi);
-    opts->bCoupleIntra = (get_eeenum(&inp, "couple-intramol", yesno_names, wi) != 0);
+    opts->bCoupleIntra = (getEnum<Boolean>(&inp, "couple-intramol", wi) != Boolean::No);
 
     fep->init_lambda = get_ereal(&inp, "init-lambda", -1, wi); /* start with -1 so
                                                                          we can recognize if
@@ -2304,32 +2286,37 @@ void get_ir(const char*     mdparin,
     fep->init_fep_state = get_eint(&inp, "init-lambda-state", -1, wi);
     fep->delta_lambda   = get_ereal(&inp, "delta-lambda", 0.0, wi);
     fep->nstdhdl        = get_eint(&inp, "nstdhdl", 50, wi);
-    setStringEntry(&inp, "fep-lambdas", inputrecStrings->fep_lambda[efptFEP], nullptr);
-    setStringEntry(&inp, "mass-lambdas", inputrecStrings->fep_lambda[efptMASS], nullptr);
-    setStringEntry(&inp, "coul-lambdas", inputrecStrings->fep_lambda[efptCOUL], nullptr);
-    setStringEntry(&inp, "vdw-lambdas", inputrecStrings->fep_lambda[efptVDW], nullptr);
-    setStringEntry(&inp, "bonded-lambdas", inputrecStrings->fep_lambda[efptBONDED], nullptr);
-    setStringEntry(&inp, "restraint-lambdas", inputrecStrings->fep_lambda[efptRESTRAINT], nullptr);
-    setStringEntry(&inp, "temperature-lambdas", inputrecStrings->fep_lambda[efptTEMPERATURE], nullptr);
+    inputrecStrings->fep_lambda[FreeEnergyPerturbationCouplingType::Fep] =
+            setStringEntry(&inp, "fep-lambdas", "");
+    inputrecStrings->fep_lambda[FreeEnergyPerturbationCouplingType::Mass] =
+            setStringEntry(&inp, "mass-lambdas", "");
+    inputrecStrings->fep_lambda[FreeEnergyPerturbationCouplingType::Coul] =
+            setStringEntry(&inp, "coul-lambdas", "");
+    inputrecStrings->fep_lambda[FreeEnergyPerturbationCouplingType::Vdw] =
+            setStringEntry(&inp, "vdw-lambdas", "");
+    inputrecStrings->fep_lambda[FreeEnergyPerturbationCouplingType::Bonded] =
+            setStringEntry(&inp, "bonded-lambdas", "");
+    inputrecStrings->fep_lambda[FreeEnergyPerturbationCouplingType::Restraint] =
+            setStringEntry(&inp, "restraint-lambdas", "");
+    inputrecStrings->fep_lambda[FreeEnergyPerturbationCouplingType::Temperature] =
+            setStringEntry(&inp, "temperature-lambdas", "");
     fep->lambda_neighbors = get_eint(&inp, "calc-lambda-neighbors", 1, wi);
     setStringEntry(&inp, "init-lambda-weights", inputrecStrings->lambda_weights, nullptr);
-    fep->edHdLPrintEnergy   = get_eeenum(&inp, "dhdl-print-energy", edHdLPrintEnergy_names, wi);
+    fep->edHdLPrintEnergy   = getEnum<FreeEnergyPrintEnergy>(&inp, "dhdl-print-energy", wi);
     fep->sc_alpha           = get_ereal(&inp, "sc-alpha", 0.0, wi);
     fep->sc_power           = get_eint(&inp, "sc-power", 1, wi);
     fep->sc_r_power         = get_ereal(&inp, "sc-r-power", 6.0, wi);
     fep->sc_sigma           = get_ereal(&inp, "sc-sigma", 0.3, wi);
-    fep->bScCoul            = (get_eeenum(&inp, "sc-coul", yesno_names, wi) != 0);
+    fep->bScCoul            = (getEnum<Boolean>(&inp, "sc-coul", wi) != Boolean::No);
     fep->dh_hist_size       = get_eint(&inp, "dh_hist_size", 0, wi);
     fep->dh_hist_spacing    = get_ereal(&inp, "dh_hist_spacing", 0.1, wi);
-    fep->separate_dhdl_file = get_eeenum(&inp, "separate-dhdl-file", separate_dhdl_file_names, wi);
-    fep->dhdl_derivatives   = get_eeenum(&inp, "dhdl-derivatives", dhdl_derivatives_names, wi);
+    fep->separate_dhdl_file = getEnum<SeparateDhdlFile>(&inp, "separate-dhdl-file", wi);
+    fep->dhdl_derivatives   = getEnum<DhDlDerivativeCalculation>(&inp, "dhdl-derivatives", wi);
     fep->dh_hist_size       = get_eint(&inp, "dh_hist_size", 0, wi);
     fep->dh_hist_spacing    = get_ereal(&inp, "dh_hist_spacing", 0.1, wi);
 
     /* Non-equilibrium MD stuff */
     printStringNewline(&inp, "Non-equilibrium MD stuff");
-    setStringEntry(&inp, "acc-grps", inputrecStrings->accgrps, nullptr);
-    setStringEntry(&inp, "accelerate", inputrecStrings->acc, nullptr);
     setStringEntry(&inp, "freezegrps", inputrecStrings->freeze, nullptr);
     setStringEntry(&inp, "freezedim", inputrecStrings->frdim, nullptr);
     ir->cos_accel = get_ereal(&inp, "cos-acceleration", 0, wi);
@@ -2337,13 +2324,13 @@ void get_ir(const char*     mdparin,
 
     /* simulated tempering variables */
     printStringNewline(&inp, "simulated tempering variables");
-    ir->bSimTemp = (get_eeenum(&inp, "simulated-tempering", yesno_names, wi) != 0);
-    ir->simtempvals->eSimTempScale = get_eeenum(&inp, "simulated-tempering-scaling", esimtemp_names, wi);
+    ir->bSimTemp = (getEnum<Boolean>(&inp, "simulated-tempering", wi) != Boolean::No);
+    ir->simtempvals->eSimTempScale = getEnum<SimulatedTempering>(&inp, "simulated-tempering-scaling", wi);
     ir->simtempvals->simtemp_low  = get_ereal(&inp, "sim-temp-low", 300.0, wi);
     ir->simtempvals->simtemp_high = get_ereal(&inp, "sim-temp-high", 300.0, wi);
 
     /* expanded ensemble variables */
-    if (ir->efep == efepEXPANDED || ir->bSimTemp)
+    if (ir->efep == FreeEnergyPerturbationType::Expanded || ir->bSimTemp)
     {
         read_expandedparams(&inp, expand, wi);
     }
@@ -2371,8 +2358,8 @@ void get_ir(const char*     mdparin,
     printStringNewline(&inp,
                        "Ion/water position swapping for computational electrophysiology setups");
     printStringNoNewline(&inp, "Swap positions along direction: no, X, Y, Z");
-    ir->eSwapCoords = get_eeenum(&inp, "swapcoords", eSwapTypes_names, wi);
-    if (ir->eSwapCoords != eswapNO)
+    ir->eSwapCoords = getEnum<SwapType>(&inp, "swapcoords", wi);
+    if (ir->eSwapCoords != SwapType::No)
     {
         char buf[STRLEN];
         int  nIonTypes;
@@ -2387,7 +2374,7 @@ void get_ir(const char*     mdparin,
         {
             warning_error(wi, "You need to provide at least one ion type for position exchanges.");
         }
-        ir->swap->ngrp = nIonTypes + eSwapFixedGrpNR;
+        ir->swap->ngrp = nIonTypes + static_cast<int>(SwapGroupSplittingType::Count);
         snew(ir->swap->grp, ir->swap->ngrp);
         for (i = 0; i < ir->swap->ngrp; i++)
         {
@@ -2395,16 +2382,25 @@ void get_ir(const char*     mdparin,
         }
         printStringNoNewline(&inp,
                              "Two index groups that contain the compartment-partitioning atoms");
-        setStringEntry(&inp, "split-group0", ir->swap->grp[eGrpSplit0].molname, nullptr);
-        setStringEntry(&inp, "split-group1", ir->swap->grp[eGrpSplit1].molname, nullptr);
+        setStringEntry(&inp,
+                       "split-group0",
+                       ir->swap->grp[static_cast<int>(SwapGroupSplittingType::Split0)].molname,
+                       nullptr);
+        setStringEntry(&inp,
+                       "split-group1",
+                       ir->swap->grp[static_cast<int>(SwapGroupSplittingType::Split1)].molname,
+                       nullptr);
         printStringNoNewline(&inp,
                              "Use center of mass of split groups (yes/no), otherwise center of "
                              "geometry is used");
-        ir->swap->massw_split[0] = (get_eeenum(&inp, "massw-split0", yesno_names, wi) != 0);
-        ir->swap->massw_split[1] = (get_eeenum(&inp, "massw-split1", yesno_names, wi) != 0);
+        ir->swap->massw_split[0] = (getEnum<Boolean>(&inp, "massw-split0", wi) != Boolean::No);
+        ir->swap->massw_split[1] = (getEnum<Boolean>(&inp, "massw-split1", wi) != Boolean::No);
 
         printStringNoNewline(&inp, "Name of solvent molecules");
-        setStringEntry(&inp, "solvent-group", ir->swap->grp[eGrpSolvent].molname, nullptr);
+        setStringEntry(&inp,
+                       "solvent-group",
+                       ir->swap->grp[static_cast<int>(SwapGroupSplittingType::Solvent)].molname,
+                       nullptr);
 
         printStringNoNewline(&inp,
                              "Split cylinder: radius, upper and lower extension (nm) (this will "
@@ -2434,7 +2430,7 @@ void get_ir(const char*     mdparin,
         printStringNoNewline(&inp, "-1 means fix the numbers as found in step 0");
         for (i = 0; i < nIonTypes; i++)
         {
-            int ig = eSwapFixedGrpNR + i;
+            int ig = static_cast<int>(SwapGroupSplittingType::Count) + i;
 
             sprintf(buf, "iontype%d-name", i);
             setStringEntry(&inp, buf, ir->swap->grp[ig].molname, nullptr);
@@ -2508,11 +2504,11 @@ void get_ir(const char*     mdparin,
         {
             dumdub[m][i] = 0.0;
         }
-        if (ir->epc)
+        if (ir->epc != PressureCoupling::No)
         {
             switch (ir->epct)
             {
-                case epctISOTROPIC:
+                case PressureCouplingType::Isotropic:
                     if (sscanf(dumstr[m], "%lf", &(dumdub[m][XX])) != 1)
                     {
                         warning_error(
@@ -2521,8 +2517,8 @@ void get_ir(const char*     mdparin,
                     }
                     dumdub[m][YY] = dumdub[m][ZZ] = dumdub[m][XX];
                     break;
-                case epctSEMIISOTROPIC:
-                case epctSURFACETENSION:
+                case PressureCouplingType::SemiIsotropic:
+                case PressureCouplingType::SurfaceTension:
                     if (sscanf(dumstr[m], "%lf%lf", &(dumdub[m][XX]), &(dumdub[m][ZZ])) != 2)
                     {
                         warning_error(
@@ -2531,9 +2527,15 @@ void get_ir(const char*     mdparin,
                     }
                     dumdub[m][YY] = dumdub[m][XX];
                     break;
-                case epctANISOTROPIC:
-                    if (sscanf(dumstr[m], "%lf%lf%lf%lf%lf%lf", &(dumdub[m][XX]), &(dumdub[m][YY]),
-                               &(dumdub[m][ZZ]), &(dumdub[m][3]), &(dumdub[m][4]), &(dumdub[m][5]))
+                case PressureCouplingType::Anisotropic:
+                    if (sscanf(dumstr[m],
+                               "%lf%lf%lf%lf%lf%lf",
+                               &(dumdub[m][XX]),
+                               &(dumdub[m][YY]),
+                               &(dumdub[m][ZZ]),
+                               &(dumdub[m][3]),
+                               &(dumdub[m][4]),
+                               &(dumdub[m][5]))
                         != 6)
                     {
                         warning_error(
@@ -2542,8 +2544,9 @@ void get_ir(const char*     mdparin,
                     }
                     break;
                 default:
-                    gmx_fatal(FARGS, "Pressure coupling type %s not implemented yet",
-                              epcoupltype_names[ir->epct]);
+                    gmx_fatal(FARGS,
+                              "Pressure coupling type %s not implemented yet",
+                              enumValueToString(ir->epct));
             }
         }
     }
@@ -2554,7 +2557,7 @@ void get_ir(const char*     mdparin,
         ir->ref_p[i][i]    = dumdub[1][i];
         ir->compress[i][i] = dumdub[0][i];
     }
-    if (ir->epct == epctANISOTROPIC)
+    if (ir->epct == PressureCouplingType::Anisotropic)
     {
         ir->ref_p[XX][YY] = dumdub[1][3];
         ir->ref_p[XX][ZZ] = dumdub[1][4];
@@ -2578,7 +2581,7 @@ void get_ir(const char*     mdparin,
         }
     }
 
-    if (ir->comm_mode == ecmNO)
+    if (ir->comm_mode == ComRemovalAlgorithm::No)
     {
         ir->nstcomm = 0;
     }
@@ -2586,14 +2589,15 @@ void get_ir(const char*     mdparin,
     opts->couple_moltype = nullptr;
     if (strlen(inputrecStrings->couple_moltype) > 0)
     {
-        if (ir->efep != efepNO)
+        if (ir->efep != FreeEnergyPerturbationType::No)
         {
             opts->couple_moltype = gmx_strdup(inputrecStrings->couple_moltype);
             if (opts->couple_lam0 == opts->couple_lam1)
             {
                 warning(wi, "The lambda=0 and lambda=1 states for coupling are identical");
             }
-            if (ir->eI == eiMD && (opts->couple_lam0 == ecouplamNONE || opts->couple_lam1 == ecouplamNONE))
+            if (ir->eI == IntegrationAlgorithm::MD
+                && (opts->couple_lam0 == ecouplamNONE || opts->couple_lam1 == ecouplamNONE))
             {
                 warning_note(
                         wi,
@@ -2609,23 +2613,23 @@ void get_ir(const char*     mdparin,
         }
     }
     /* FREE ENERGY AND EXPANDED ENSEMBLE OPTIONS */
-    if (ir->efep != efepNO)
+    if (ir->efep != FreeEnergyPerturbationType::No)
     {
         if (fep->delta_lambda != 0)
         {
-            ir->efep = efepSLOWGROWTH;
+            ir->efep = FreeEnergyPerturbationType::SlowGrowth;
         }
     }
 
-    if (fep->edHdLPrintEnergy == edHdLPrintEnergyYES)
+    if (fep->edHdLPrintEnergy == FreeEnergyPrintEnergy::Yes)
     {
-        fep->edHdLPrintEnergy = edHdLPrintEnergyTOTAL;
+        fep->edHdLPrintEnergy = FreeEnergyPrintEnergy::Total;
         warning_note(wi,
                      "Old option for dhdl-print-energy given: "
                      "changing \"yes\" to \"total\"\n");
     }
 
-    if (ir->bSimTemp && (fep->edHdLPrintEnergy == edHdLPrintEnergyNO))
+    if (ir->bSimTemp && (fep->edHdLPrintEnergy == FreeEnergyPrintEnergy::No))
     {
         /* always print out the energy to dhdl if we are doing
            expanded ensemble, since we need the total energy for
@@ -2634,13 +2638,13 @@ void get_ir(const char*     mdparin,
            we will allow that if the appropriate mdp setting has
            been enabled. Otherwise, total it is:
          */
-        fep->edHdLPrintEnergy = edHdLPrintEnergyTOTAL;
+        fep->edHdLPrintEnergy = FreeEnergyPrintEnergy::Total;
     }
 
-    if ((ir->efep != efepNO) || ir->bSimTemp)
+    if ((ir->efep != FreeEnergyPerturbationType::No) || ir->bSimTemp)
     {
         ir->bExpanded = FALSE;
-        if ((ir->efep == efepEXPANDED) || ir->bSimTemp)
+        if ((ir->efep == FreeEnergyPerturbationType::Expanded) || ir->bSimTemp)
         {
             ir->bExpanded = TRUE;
         }
@@ -2658,7 +2662,8 @@ void get_ir(const char*     mdparin,
          * If the (advanced) user does FEP through manual topology changes,
          * this check will not be triggered.
          */
-        if (ir->efep != efepNO && ir->fepvals->n_lambda == 0 && ir->fepvals->sc_alpha != 0
+        if (ir->efep != FreeEnergyPerturbationType::No && ir->fepvals->n_lambda == 0
+            && ir->fepvals->sc_alpha != 0
             && (couple_lambda_has_vdw_on(opts->couple_lam0) && couple_lambda_has_vdw_on(opts->couple_lam1)))
         {
             warning(wi,
@@ -2693,9 +2698,15 @@ void get_ir(const char*     mdparin,
     }
 
     double gmx_unused canary;
-    int ndeform = sscanf(inputrecStrings->deform, "%lf %lf %lf %lf %lf %lf %lf", &(dumdub[0][0]),
-                         &(dumdub[0][1]), &(dumdub[0][2]), &(dumdub[0][3]), &(dumdub[0][4]),
-                         &(dumdub[0][5]), &canary);
+    int               ndeform = sscanf(inputrecStrings->deform,
+                         "%lf %lf %lf %lf %lf %lf %lf",
+                         &(dumdub[0][0]),
+                         &(dumdub[0][1]),
+                         &(dumdub[0][2]),
+                         &(dumdub[0][3]),
+                         &(dumdub[0][4]),
+                         &(dumdub[0][5]),
+                         &canary);
 
     if (strlen(inputrecStrings->deform) > 0 && ndeform != 6)
     {
@@ -2712,7 +2723,7 @@ void get_ir(const char*     mdparin,
     ir->deform[YY][XX] = dumdub[0][3];
     ir->deform[ZZ][XX] = dumdub[0][4];
     ir->deform[ZZ][YY] = dumdub[0][5];
-    if (ir->epc != epcNO)
+    if (ir->epc != PressureCoupling::No)
     {
         for (i = 0; i < 3; i++)
         {
@@ -2747,7 +2758,7 @@ void get_ir(const char*     mdparin,
     }
 
     /* Ion/water position swapping checks */
-    if (ir->eSwapCoords != eswapNO)
+    if (ir->eSwapCoords != SwapType::No)
     {
         if (ir->swap->nstswap < 1)
         {
@@ -2766,12 +2777,18 @@ void get_ir(const char*     mdparin,
     /* Set up MTS levels, this needs to happen before checking AWH parameters */
     if (ir->useMts)
     {
-        setupMtsLevels(ir->mtsLevels, *ir, *opts, wi);
+        std::vector<std::string> errorMessages;
+        ir->mtsLevels = gmx::setupMtsLevels(opts->mtsOpts, &errorMessages);
+
+        for (const auto& errorMessage : errorMessages)
+        {
+            warning_error(wi, errorMessage.c_str());
+        }
     }
 
     if (ir->bDoAwh)
     {
-        gmx::checkAwhParams(ir->awhParams, ir, wi);
+        gmx::checkAwhParams(*ir->awhParams, *ir, wi);
     }
 
     sfree(dumstr[0]);
@@ -2861,8 +2878,7 @@ static void do_numbering(int                        natoms,
             const int ognr = cbuf[aj];
             if (ognr != NOGID)
             {
-                gmx_fatal(FARGS, "Atom %d in multiple %s groups (%d and %d)", aj + 1, title,
-                          ognr + 1, i + 1);
+                gmx_fatal(FARGS, "Atom %d in multiple %s groups (%d and %d)", aj + 1, title, ognr + 1, i + 1);
             }
             else
             {
@@ -2904,8 +2920,7 @@ static void do_numbering(int                        natoms,
         {
             if (bVerbose)
             {
-                fprintf(stderr, "Making dummy/rest group for %s containing %d elements\n", title,
-                        natoms - ntot);
+                fprintf(stderr, "Making dummy/rest group for %s containing %d elements\n", title, natoms - ntot);
             }
             /* Add group name "rest" */
             grps->emplace_back(restnm);
@@ -2975,7 +2990,8 @@ static void calc_nrdf(const gmx_mtop_t* mtop, t_inputrec* ir, char** gnames)
         nrdf_tc[i] = 0;
     }
     for (gmx::index i = 0;
-         i < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]) + 1; i++)
+         i < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]) + 1;
+         i++)
     {
         nrdf_vcm[i] = 0;
         clear_ivec(dof_vcm[i]);
@@ -2988,7 +3004,7 @@ static void calc_nrdf(const gmx_mtop_t* mtop, t_inputrec* ir, char** gnames)
         const t_atom& local = atomP.atom();
         int           i     = atomP.globalAtomNumber();
         nrdf2[i]            = 0;
-        if (local.ptype == eptAtom || local.ptype == eptNucleus)
+        if (local.ptype == ParticleType::Atom || local.ptype == ParticleType::Nucleus)
         {
             int g = getGroupType(groups, SimulationAtomGroupType::Freeze, i);
             for (int d = 0; d < DIM; d++)
@@ -3030,8 +3046,10 @@ static void calc_nrdf(const gmx_mtop_t* mtop, t_inputrec* ir, char** gnames)
                      */
                     int ai = as + ia[i + 1];
                     int aj = as + ia[i + 2];
-                    if (((atom[ia[i + 1]].ptype == eptNucleus) || (atom[ia[i + 1]].ptype == eptAtom))
-                        && ((atom[ia[i + 2]].ptype == eptNucleus) || (atom[ia[i + 2]].ptype == eptAtom)))
+                    if (((atom[ia[i + 1]].ptype == ParticleType::Nucleus)
+                         || (atom[ia[i + 1]].ptype == ParticleType::Atom))
+                        && ((atom[ia[i + 2]].ptype == ParticleType::Nucleus)
+                            || (atom[ia[i + 2]].ptype == ParticleType::Atom)))
                     {
                         if (nrdf2[ai] > 0)
                         {
@@ -3097,7 +3115,7 @@ static void calc_nrdf(const gmx_mtop_t* mtop, t_inputrec* ir, char** gnames)
 
         for (int i = 0; i < pull->ncoord; i++)
         {
-            if (pull->coord[i].eType != epullCONSTRAINT)
+            if (pull->coord[i].eType != PullingAlgorithm::Constraint)
             {
                 continue;
             }
@@ -3150,12 +3168,13 @@ static void calc_nrdf(const gmx_mtop_t* mtop, t_inputrec* ir, char** gnames)
          * Note that we do not and should not include the rest group here.
          */
         for (gmx::index j = 0;
-             j < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]); j++)
+             j < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]);
+             j++)
         {
             switch (ir->comm_mode)
             {
-                case ecmLINEAR:
-                case ecmLINEAR_ACCELERATION_CORRECTION:
+                case ComRemovalAlgorithm::Linear:
+                case ComRemovalAlgorithm::LinearAccelerationCorrection:
                     nrdf_vcm_sub[j] = 0;
                     for (int d = 0; d < ndim_rm_vcm; d++)
                     {
@@ -3165,17 +3184,19 @@ static void calc_nrdf(const gmx_mtop_t* mtop, t_inputrec* ir, char** gnames)
                         }
                     }
                     break;
-                case ecmANGULAR: nrdf_vcm_sub[j] = 6; break;
+                case ComRemovalAlgorithm::Angular: nrdf_vcm_sub[j] = 6; break;
                 default: gmx_incons("Checking comm_mode");
             }
         }
 
         for (gmx::index i = 0;
-             i < gmx::ssize(groups.groups[SimulationAtomGroupType::TemperatureCoupling]); i++)
+             i < gmx::ssize(groups.groups[SimulationAtomGroupType::TemperatureCoupling]);
+             i++)
         {
             /* Count the number of atoms of TC group i for every VCM group */
             for (gmx::index j = 0;
-                 j < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]) + 1; j++)
+                 j < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]) + 1;
+                 j++)
             {
                 na_vcm[j] = 0;
             }
@@ -3194,7 +3215,8 @@ static void calc_nrdf(const gmx_mtop_t* mtop, t_inputrec* ir, char** gnames)
             nrdf_uc    = nrdf_tc[i];
             nrdf_tc[i] = 0;
             for (gmx::index j = 0;
-                 j < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]) + 1; j++)
+                 j < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]) + 1;
+                 j++)
             {
                 if (nrdf_vcm[j] > nrdf_vcm_sub[j])
                 {
@@ -3211,8 +3233,10 @@ static void calc_nrdf(const gmx_mtop_t* mtop, t_inputrec* ir, char** gnames)
         {
             opts->nrdf[i] = 0;
         }
-        fprintf(stderr, "Number of degrees of freedom in T-Coupling group %s is %.2f\n",
-                gnames[groups.groups[SimulationAtomGroupType::TemperatureCoupling][i]], opts->nrdf[i]);
+        fprintf(stderr,
+                "Number of degrees of freedom in T-Coupling group %s is %.2f\n",
+                gnames[groups.groups[SimulationAtomGroupType::TemperatureCoupling][i]],
+                opts->nrdf[i]);
     }
 
     sfree(nrdf2);
@@ -3246,8 +3270,8 @@ static bool do_egp_flag(t_inputrec* ir, SimulationGroups* groups, const char* op
         j = 0;
         while ((j < nr)
                && gmx_strcasecmp(
-                          names[2 * i].c_str(),
-                          *(groups->groupNames[groups->groups[SimulationAtomGroupType::EnergyOutput][j]])))
+                       names[2 * i].c_str(),
+                       *(groups->groupNames[groups->groups[SimulationAtomGroupType::EnergyOutput][j]])))
         {
             j++;
         }
@@ -3258,8 +3282,8 @@ static bool do_egp_flag(t_inputrec* ir, SimulationGroups* groups, const char* op
         k = 0;
         while ((k < nr)
                && gmx_strcasecmp(
-                          names[2 * i + 1].c_str(),
-                          *(groups->groupNames[groups->groups[SimulationAtomGroupType::EnergyOutput][k]])))
+                       names[2 * i + 1].c_str(),
+                       *(groups->groupNames[groups->groups[SimulationAtomGroupType::EnergyOutput][k]])))
         {
             k++;
         }
@@ -3286,9 +3310,13 @@ static void make_swap_groups(t_swapcoords* swap, t_blocka* grps, char** gnames)
 
 
     /* Just a quick check here, more thorough checks are in mdrun */
-    if (strcmp(swap->grp[eGrpSplit0].molname, swap->grp[eGrpSplit1].molname) == 0)
+    if (strcmp(swap->grp[static_cast<int>(SwapGroupSplittingType::Split0)].molname,
+               swap->grp[static_cast<int>(SwapGroupSplittingType::Split1)].molname)
+        == 0)
     {
-        gmx_fatal(FARGS, "The split groups can not both be '%s'.", swap->grp[eGrpSplit0].molname);
+        gmx_fatal(FARGS,
+                  "The split groups can not both be '%s'.",
+                  swap->grp[static_cast<int>(SwapGroupSplittingType::Split0)].molname);
     }
 
     /* Get the index atoms of the split0, split1, solvent, and swap groups */
@@ -3300,8 +3328,11 @@ static void make_swap_groups(t_swapcoords* swap, t_blocka* grps, char** gnames)
 
         if (swapg->nat > 0)
         {
-            fprintf(stderr, "%s group '%s' contains %d atoms.\n",
-                    ig < 3 ? eSwapFixedGrp_names[ig] : "Swap", swap->grp[ig].molname, swapg->nat);
+            fprintf(stderr,
+                    "%s group '%s' contains %d atoms.\n",
+                    ig < 3 ? enumValueToString(static_cast<SwapGroupSplittingType>(ig)) : "Swap",
+                    swap->grp[ig].molname,
+                    swapg->nat);
             snew(swapg->ind, swapg->nat);
             for (i = 0; i < swapg->nat; i++)
             {
@@ -3329,7 +3360,8 @@ static void make_IMD_group(t_IMD* IMDgroup, char* IMDgname, t_blocka* grps, char
         fprintf(stderr,
                 "Group '%s' with %d atoms can be activated for interactive molecular dynamics "
                 "(IMD).\n",
-                IMDgname, IMDgroup->nat);
+                IMDgname,
+                IMDgroup->nat);
         snew(IMDgroup->ind, IMDgroup->nat);
         for (i = 0; i < IMDgroup->nat; i++)
         {
@@ -3407,7 +3439,8 @@ static void checkAndUpdateVcmFreezeGroupConsistency(SimulationGroups* groups,
                 "removal group(s), due to limitations in the code these still contribute to the "
                 "mass of the COM along frozen dimensions and therefore the COMM correction will be "
                 "too small.",
-                numPartiallyFrozenVcmAtoms, DIM);
+                numPartiallyFrozenVcmAtoms,
+                DIM);
         warning(wi, warningText.c_str());
     }
     if (numNonVcmAtoms > 0)
@@ -3421,13 +3454,13 @@ static void checkAndUpdateVcmFreezeGroupConsistency(SimulationGroups* groups,
     }
 }
 
-void do_index(const char*                   mdparin,
-              const char*                   ndx,
-              gmx_mtop_t*                   mtop,
-              bool                          bVerbose,
-              const gmx::MdModulesNotifier& notifier,
-              t_inputrec*                   ir,
-              warninp_t                     wi)
+void do_index(const char*                    mdparin,
+              const char*                    ndx,
+              gmx_mtop_t*                    mtop,
+              bool                           bVerbose,
+              const gmx::MDModulesNotifiers& mdModulesNotifiers,
+              t_inputrec*                    ir,
+              warninp_t                      wi)
 {
     t_blocka* defaultIndexGroups;
     int       natoms;
@@ -3450,7 +3483,7 @@ void do_index(const char*                   mdparin,
         snew(defaultIndexGroups, 1);
         snew(defaultIndexGroups->index, 1);
         snew(gnames, 1);
-        atoms_all = gmx_mtop_global_atoms(mtop);
+        atoms_all = gmx_mtop_global_atoms(*mtop);
         analyse(&atoms_all, defaultIndexGroups, &gnames, FALSE, TRUE);
         done_atom(&atoms_all);
     }
@@ -3484,20 +3517,28 @@ void do_index(const char*                   mdparin,
         gmx_fatal(FARGS,
                   "Invalid T coupling input: %zu groups, %zu ref-t values and "
                   "%zu tau-t values",
-                  temperatureCouplingGroupNames.size(), temperatureCouplingReferenceValues.size(),
+                  temperatureCouplingGroupNames.size(),
+                  temperatureCouplingReferenceValues.size(),
                   temperatureCouplingTauValues.size());
     }
 
     const bool useReferenceTemperature = integratorHasReferenceTemperature(ir);
-    do_numbering(natoms, groups, temperatureCouplingGroupNames, defaultIndexGroups, gnames,
-                 SimulationAtomGroupType::TemperatureCoupling, restnm,
-                 useReferenceTemperature ? egrptpALL : egrptpALL_GENREST, bVerbose, wi);
+    do_numbering(natoms,
+                 groups,
+                 temperatureCouplingGroupNames,
+                 defaultIndexGroups,
+                 gnames,
+                 SimulationAtomGroupType::TemperatureCoupling,
+                 restnm,
+                 useReferenceTemperature ? egrptpALL : egrptpALL_GENREST,
+                 bVerbose,
+                 wi);
     nr            = groups->groups[SimulationAtomGroupType::TemperatureCoupling].size();
     ir->opts.ngtc = nr;
     snew(ir->opts.nrdf, nr);
     snew(ir->opts.tau_t, nr);
     snew(ir->opts.ref_t, nr);
-    if (ir->eI == eiBD && ir->bd_fric == 0)
+    if (ir->eI == IntegrationAlgorithm::BD && ir->bd_fric == 0)
     {
         fprintf(stderr, "bd-fric=0, so tau-t will be used as the inverse friction constant(s)\n");
     }
@@ -3513,13 +3554,15 @@ void do_index(const char*                   mdparin,
         convertReals(wi, temperatureCouplingTauValues, "tau-t", ir->opts.tau_t);
         for (i = 0; (i < nr); i++)
         {
-            if ((ir->eI == eiBD) && ir->opts.tau_t[i] <= 0)
+            if ((ir->eI == IntegrationAlgorithm::BD) && ir->opts.tau_t[i] <= 0)
             {
-                sprintf(warn_buf, "With integrator %s tau-t should be larger than 0", ei_names[ir->eI]);
+                sprintf(warn_buf,
+                        "With integrator %s tau-t should be larger than 0",
+                        enumValueToString(ir->eI));
                 warning_error(wi, warn_buf);
             }
 
-            if (ir->etc != etcVRESCALE && ir->opts.tau_t[i] == 0)
+            if (ir->etc != TemperatureCoupling::VRescale && ir->opts.tau_t[i] == 0)
             {
                 warning_note(
                         wi,
@@ -3532,23 +3575,23 @@ void do_index(const char*                   mdparin,
                 tau_min = std::min(tau_min, ir->opts.tau_t[i]);
             }
         }
-        if (ir->etc != etcNO && ir->nsttcouple == -1)
+        if (ir->etc != TemperatureCoupling::No && ir->nsttcouple == -1)
         {
             ir->nsttcouple = ir_optimal_nsttcouple(ir);
         }
 
         if (EI_VV(ir->eI))
         {
-            if ((ir->etc == etcNOSEHOOVER) && (ir->epc == epcBERENDSEN))
+            if ((ir->etc == TemperatureCoupling::NoseHoover) && (ir->epc == PressureCoupling::Berendsen))
             {
                 gmx_fatal(FARGS,
                           "Cannot do Nose-Hoover temperature with Berendsen pressure control with "
                           "md-vv; use either vrescale temperature with berendsen pressure or "
                           "Nose-Hoover temperature with MTTK pressure");
             }
-            if (ir->epc == epcMTTK)
+            if (ir->epc == PressureCoupling::Mttk)
             {
-                if (ir->etc != etcNOSEHOOVER)
+                if (ir->etc != TemperatureCoupling::NoseHoover)
                 {
                     gmx_fatal(FARGS,
                               "Cannot do MTTK pressure coupling without Nose-Hoover temperature "
@@ -3593,7 +3636,10 @@ void do_index(const char*                   mdparin,
                 sprintf(warn_buf,
                         "For proper integration of the %s thermostat, tau-t (%g) should be at "
                         "least %d times larger than nsttcouple*dt (%g)",
-                        ETCOUPLTYPE(ir->etc), tau_min, nstcmin, ir->nsttcouple * ir->delta_t);
+                        enumValueToString(ir->etc),
+                        tau_min,
+                        nstcmin,
+                        ir->nsttcouple * ir->delta_t);
                 warning(wi, warn_buf);
             }
         }
@@ -3622,8 +3668,10 @@ void do_index(const char*                   mdparin,
     }
     if (!simulatedAnnealingGroupNames.empty() && gmx::ssize(simulatedAnnealingGroupNames) != nr)
     {
-        gmx_fatal(FARGS, "Wrong number of annealing values: %zu (for %d groups)\n",
-                  simulatedAnnealingGroupNames.size(), nr);
+        gmx_fatal(FARGS,
+                  "Wrong number of annealing values: %zu (for %d groups)\n",
+                  simulatedAnnealingGroupNames.size(),
+                  nr);
     }
     else
     {
@@ -3633,7 +3681,7 @@ void do_index(const char*                   mdparin,
         snew(ir->opts.anneal_temp, nr);
         for (i = 0; i < nr; i++)
         {
-            ir->opts.annealing[i]      = eannNO;
+            ir->opts.annealing[i]      = SimulatedAnnealing::No;
             ir->opts.anneal_npoints[i] = 0;
             ir->opts.anneal_time[i]    = nullptr;
             ir->opts.anneal_temp[i]    = nullptr;
@@ -3645,16 +3693,16 @@ void do_index(const char*                   mdparin,
             {
                 if (gmx::equalCaseInsensitive(simulatedAnnealingGroupNames[i], "N", 1))
                 {
-                    ir->opts.annealing[i] = eannNO;
+                    ir->opts.annealing[i] = SimulatedAnnealing::No;
                 }
                 else if (gmx::equalCaseInsensitive(simulatedAnnealingGroupNames[i], "S", 1))
                 {
-                    ir->opts.annealing[i] = eannSINGLE;
+                    ir->opts.annealing[i] = SimulatedAnnealing::Single;
                     bAnneal               = TRUE;
                 }
                 else if (gmx::equalCaseInsensitive(simulatedAnnealingGroupNames[i], "P", 1))
                 {
-                    ir->opts.annealing[i] = eannPERIODIC;
+                    ir->opts.annealing[i] = SimulatedAnnealing::Periodic;
                     bAnneal               = TRUE;
                 }
             }
@@ -3664,8 +3712,10 @@ void do_index(const char*                   mdparin,
                 auto simulatedAnnealingPoints = gmx::splitString(inputrecStrings->anneal_npoints);
                 if (simulatedAnnealingPoints.size() != simulatedAnnealingGroupNames.size())
                 {
-                    gmx_fatal(FARGS, "Found %zu annealing-npoints values for %zu groups\n",
-                              simulatedAnnealingPoints.size(), simulatedAnnealingGroupNames.size());
+                    gmx_fatal(FARGS,
+                              "Found %zu annealing-npoints values for %zu groups\n",
+                              simulatedAnnealingPoints.size(),
+                              simulatedAnnealingGroupNames.size());
                 }
                 convertInts(wi, simulatedAnnealingPoints, "annealing points", ir->opts.anneal_npoints);
                 size_t numSimulatedAnnealingFields = 0;
@@ -3686,21 +3736,26 @@ void do_index(const char*                   mdparin,
 
                 if (simulatedAnnealingTimes.size() != numSimulatedAnnealingFields)
                 {
-                    gmx_fatal(FARGS, "Found %zu annealing-time values, wanted %zu\n",
-                              simulatedAnnealingTimes.size(), numSimulatedAnnealingFields);
+                    gmx_fatal(FARGS,
+                              "Found %zu annealing-time values, wanted %zu\n",
+                              simulatedAnnealingTimes.size(),
+                              numSimulatedAnnealingFields);
                 }
                 auto simulatedAnnealingTemperatures = gmx::splitString(inputrecStrings->anneal_temp);
                 if (simulatedAnnealingTemperatures.size() != numSimulatedAnnealingFields)
                 {
-                    gmx_fatal(FARGS, "Found %zu annealing-temp values, wanted %zu\n",
-                              simulatedAnnealingTemperatures.size(), numSimulatedAnnealingFields);
+                    gmx_fatal(FARGS,
+                              "Found %zu annealing-temp values, wanted %zu\n",
+                              simulatedAnnealingTemperatures.size(),
+                              numSimulatedAnnealingFields);
                 }
 
                 std::vector<real> allSimulatedAnnealingTimes(numSimulatedAnnealingFields);
                 std::vector<real> allSimulatedAnnealingTemperatures(numSimulatedAnnealingFields);
-                convertReals(wi, simulatedAnnealingTimes, "anneal-time",
-                             allSimulatedAnnealingTimes.data());
-                convertReals(wi, simulatedAnnealingTemperatures, "anneal-temp",
+                convertReals(wi, simulatedAnnealingTimes, "anneal-time", allSimulatedAnnealingTimes.data());
+                convertReals(wi,
+                             simulatedAnnealingTemperatures,
+                             "anneal-temp",
                              allSimulatedAnnealingTemperatures.data());
                 for (i = 0, k = 0; i < nr; i++)
                 {
@@ -3723,12 +3778,14 @@ void do_index(const char*                   mdparin,
                                 gmx_fatal(FARGS,
                                           "Annealing timepoints out of order: t=%f comes after "
                                           "t=%f\n",
-                                          ir->opts.anneal_time[i][j], ir->opts.anneal_time[i][j - 1]);
+                                          ir->opts.anneal_time[i][j],
+                                          ir->opts.anneal_time[i][j - 1]);
                             }
                         }
                         if (ir->opts.anneal_temp[i][j] < 0)
                         {
-                            gmx_fatal(FARGS, "Found negative temperature in annealing: %f\n",
+                            gmx_fatal(FARGS,
+                                      "Found negative temperature in annealing: %f\n",
                                       ir->opts.anneal_temp[i][j]);
                         }
                         k++;
@@ -3737,30 +3794,38 @@ void do_index(const char*                   mdparin,
                 /* Print out some summary information, to make sure we got it right */
                 for (i = 0; i < nr; i++)
                 {
-                    if (ir->opts.annealing[i] != eannNO)
+                    if (ir->opts.annealing[i] != SimulatedAnnealing::No)
                     {
                         j = groups->groups[SimulationAtomGroupType::TemperatureCoupling][i];
-                        fprintf(stderr, "Simulated annealing for group %s: %s, %d timepoints\n",
-                                *(groups->groupNames[j]), eann_names[ir->opts.annealing[i]],
+                        fprintf(stderr,
+                                "Simulated annealing for group %s: %s, %d timepoints\n",
+                                *(groups->groupNames[j]),
+                                enumValueToString(ir->opts.annealing[i]),
                                 ir->opts.anneal_npoints[i]);
                         fprintf(stderr, "Time (ps)   Temperature (K)\n");
                         /* All terms except the last one */
                         for (j = 0; j < (ir->opts.anneal_npoints[i] - 1); j++)
                         {
-                            fprintf(stderr, "%9.1f      %5.1f\n", ir->opts.anneal_time[i][j],
+                            fprintf(stderr,
+                                    "%9.1f      %5.1f\n",
+                                    ir->opts.anneal_time[i][j],
                                     ir->opts.anneal_temp[i][j]);
                         }
 
                         /* Finally the last one */
                         j = ir->opts.anneal_npoints[i] - 1;
-                        if (ir->opts.annealing[i] == eannSINGLE)
+                        if (ir->opts.annealing[i] == SimulatedAnnealing::Single)
                         {
-                            fprintf(stderr, "%9.1f-     %5.1f\n", ir->opts.anneal_time[i][j],
+                            fprintf(stderr,
+                                    "%9.1f-     %5.1f\n",
+                                    ir->opts.anneal_time[i][j],
                                     ir->opts.anneal_temp[i][j]);
                         }
                         else
                         {
-                            fprintf(stderr, "%9.1f      %5.1f\n", ir->opts.anneal_time[i][j],
+                            fprintf(stderr,
+                                    "%9.1f      %5.1f\n",
+                                    ir->opts.anneal_time[i][j],
                                     ir->opts.anneal_temp[i][j]);
                             if (std::fabs(ir->opts.anneal_temp[i][j] - ir->opts.anneal_temp[i][0]) > GMX_REAL_EPS)
                             {
@@ -3779,8 +3844,8 @@ void do_index(const char*                   mdparin,
     {
         for (int i = 1; i < ir->pull->ngroup; i++)
         {
-            const int gid = search_string(inputrecStrings->pullGroupNames[i].c_str(),
-                                          defaultIndexGroups->nr, gnames);
+            const int gid = search_string(
+                    inputrecStrings->pullGroupNames[i].c_str(), defaultIndexGroups->nr, gnames);
             GMX_ASSERT(defaultIndexGroups, "Must have initialized default index groups");
             atomGroupRangeValidation(natoms, gid, *defaultIndexGroups);
         }
@@ -3795,7 +3860,7 @@ void do_index(const char*                   mdparin,
         make_rotation_groups(ir->rot, inputrecStrings->rotateGroupNames, defaultIndexGroups, gnames);
     }
 
-    if (ir->eSwapCoords != eswapNO)
+    if (ir->eSwapCoords != SwapType::No)
     {
         make_swap_groups(ir->swap, defaultIndexGroups, gnames);
     }
@@ -3808,32 +3873,27 @@ void do_index(const char*                   mdparin,
 
     gmx::IndexGroupsAndNames defaultIndexGroupsAndNames(
             *defaultIndexGroups, gmx::arrayRefFromArray(gnames, defaultIndexGroups->nr));
-    notifier.preProcessingNotifications_.notify(defaultIndexGroupsAndNames);
-
-    auto accelerations          = gmx::splitString(inputrecStrings->acc);
-    auto accelerationGroupNames = gmx::splitString(inputrecStrings->accgrps);
-    if (accelerationGroupNames.size() * DIM != accelerations.size())
-    {
-        gmx_fatal(FARGS, "Invalid Acceleration input: %zu groups and %zu acc. values",
-                  accelerationGroupNames.size(), accelerations.size());
-    }
-    do_numbering(natoms, groups, accelerationGroupNames, defaultIndexGroups, gnames,
-                 SimulationAtomGroupType::Acceleration, restnm, egrptpALL_GENREST, bVerbose, wi);
-    nr = groups->groups[SimulationAtomGroupType::Acceleration].size();
-    snew(ir->opts.acc, nr);
-    ir->opts.ngacc = nr;
-
-    convertRvecs(wi, accelerations, "anneal-time", ir->opts.acc);
+    mdModulesNotifiers.preProcessingNotifier_.notify(defaultIndexGroupsAndNames);
 
     auto freezeDims       = gmx::splitString(inputrecStrings->frdim);
     auto freezeGroupNames = gmx::splitString(inputrecStrings->freeze);
     if (freezeDims.size() != DIM * freezeGroupNames.size())
     {
-        gmx_fatal(FARGS, "Invalid Freezing input: %zu groups and %zu freeze values",
-                  freezeGroupNames.size(), freezeDims.size());
-    }
-    do_numbering(natoms, groups, freezeGroupNames, defaultIndexGroups, gnames,
-                 SimulationAtomGroupType::Freeze, restnm, egrptpALL_GENREST, bVerbose, wi);
+        gmx_fatal(FARGS,
+                  "Invalid Freezing input: %zu groups and %zu freeze values",
+                  freezeGroupNames.size(),
+                  freezeDims.size());
+    }
+    do_numbering(natoms,
+                 groups,
+                 freezeGroupNames,
+                 defaultIndexGroups,
+                 gnames,
+                 SimulationAtomGroupType::Freeze,
+                 restnm,
+                 egrptpALL_GENREST,
+                 bVerbose,
+                 wi);
     nr             = groups->groups[SimulationAtomGroupType::Freeze].size();
     ir->opts.ngfrz = nr;
     snew(ir->opts.nFreeze, nr);
@@ -3864,16 +3924,31 @@ void do_index(const char*                   mdparin,
     }
 
     auto energyGroupNames = gmx::splitString(inputrecStrings->energy);
-    do_numbering(natoms, groups, energyGroupNames, defaultIndexGroups, gnames,
-                 SimulationAtomGroupType::EnergyOutput, restnm, egrptpALL_GENREST, bVerbose, wi);
+    do_numbering(natoms,
+                 groups,
+                 energyGroupNames,
+                 defaultIndexGroups,
+                 gnames,
+                 SimulationAtomGroupType::EnergyOutput,
+                 restnm,
+                 egrptpALL_GENREST,
+                 bVerbose,
+                 wi);
     add_wall_energrps(groups, ir->nwall, symtab);
     ir->opts.ngener    = groups->groups[SimulationAtomGroupType::EnergyOutput].size();
     auto vcmGroupNames = gmx::splitString(inputrecStrings->vcm);
-    do_numbering(natoms, groups, vcmGroupNames, defaultIndexGroups, gnames,
-                 SimulationAtomGroupType::MassCenterVelocityRemoval, restnm,
-                 vcmGroupNames.empty() ? egrptpALL_GENREST : egrptpPART, bVerbose, wi);
-
-    if (ir->comm_mode != ecmNO)
+    do_numbering(natoms,
+                 groups,
+                 vcmGroupNames,
+                 defaultIndexGroups,
+                 gnames,
+                 SimulationAtomGroupType::MassCenterVelocityRemoval,
+                 restnm,
+                 vcmGroupNames.empty() ? egrptpALL_GENREST : egrptpPART,
+                 bVerbose,
+                 wi);
+
+    if (ir->comm_mode != ComRemovalAlgorithm::No)
     {
         checkAndUpdateVcmFreezeGroupConsistency(groups, natoms, ir->opts, wi);
     }
@@ -3882,18 +3957,49 @@ void do_index(const char*                   mdparin,
     calc_nrdf(mtop, ir, gnames);
 
     auto user1GroupNames = gmx::splitString(inputrecStrings->user1);
-    do_numbering(natoms, groups, user1GroupNames, defaultIndexGroups, gnames,
-                 SimulationAtomGroupType::User1, restnm, egrptpALL_GENREST, bVerbose, wi);
+    do_numbering(natoms,
+                 groups,
+                 user1GroupNames,
+                 defaultIndexGroups,
+                 gnames,
+                 SimulationAtomGroupType::User1,
+                 restnm,
+                 egrptpALL_GENREST,
+                 bVerbose,
+                 wi);
     auto user2GroupNames = gmx::splitString(inputrecStrings->user2);
-    do_numbering(natoms, groups, user2GroupNames, defaultIndexGroups, gnames,
-                 SimulationAtomGroupType::User2, restnm, egrptpALL_GENREST, bVerbose, wi);
+    do_numbering(natoms,
+                 groups,
+                 user2GroupNames,
+                 defaultIndexGroups,
+                 gnames,
+                 SimulationAtomGroupType::User2,
+                 restnm,
+                 egrptpALL_GENREST,
+                 bVerbose,
+                 wi);
     auto compressedXGroupNames = gmx::splitString(inputrecStrings->x_compressed_groups);
-    do_numbering(natoms, groups, compressedXGroupNames, defaultIndexGroups, gnames,
-                 SimulationAtomGroupType::CompressedPositionOutput, restnm, egrptpONE, bVerbose, wi);
+    do_numbering(natoms,
+                 groups,
+                 compressedXGroupNames,
+                 defaultIndexGroups,
+                 gnames,
+                 SimulationAtomGroupType::CompressedPositionOutput,
+                 restnm,
+                 egrptpONE,
+                 bVerbose,
+                 wi);
     auto orirefFitGroupNames = gmx::splitString(inputrecStrings->orirefitgrp);
-    do_numbering(natoms, groups, orirefFitGroupNames, defaultIndexGroups, gnames,
-                 SimulationAtomGroupType::OrientationRestraintsFit, restnm, egrptpALL_GENREST,
-                 bVerbose, wi);
+    do_numbering(natoms,
+                 groups,
+                 orirefFitGroupNames,
+                 defaultIndexGroups,
+                 gnames,
+                 SimulationAtomGroupType::OrientationRestraintsFit,
+                 restnm,
+                 egrptpALL_GENREST,
+                 bVerbose,
+                 wi);
 
     /* MiMiC QMMM input processing */
     auto qmGroupNames = gmx::splitString(inputrecStrings->QMMM);
@@ -3902,8 +4008,16 @@ void do_index(const char*                   mdparin,
         gmx_fatal(FARGS, "Currently, having more than one QM group in MiMiC is not supported");
     }
     /* group rest, if any, is always MM! */
-    do_numbering(natoms, groups, qmGroupNames, defaultIndexGroups, gnames,
-                 SimulationAtomGroupType::QuantumMechanics, restnm, egrptpALL_GENREST, bVerbose, wi);
+    do_numbering(natoms,
+                 groups,
+                 qmGroupNames,
+                 defaultIndexGroups,
+                 gnames,
+                 SimulationAtomGroupType::QuantumMechanics,
+                 restnm,
+                 egrptpALL_GENREST,
+                 bVerbose,
+                 wi);
     ir->opts.ngQM = qmGroupNames.size();
 
     /* end of MiMiC QMMM input */
@@ -3925,7 +4039,7 @@ void do_index(const char*                   mdparin,
     snew(ir->opts.egp_flags, nr * nr);
 
     bExcl = do_egp_flag(ir, groups, "energygrp-excl", inputrecStrings->egpexcl, EGP_EXCL);
-    if (bExcl && ir->cutoff_scheme == ecutsVERLET)
+    if (bExcl && ir->cutoff_scheme == CutoffScheme::Verlet)
     {
         warning_error(wi, "Energy group exclusions are currently not supported");
     }
@@ -3935,8 +4049,10 @@ void do_index(const char*                   mdparin,
     }
 
     bTable = do_egp_flag(ir, groups, "energygrp-table", inputrecStrings->egptable, EGP_TABLE);
-    if (bTable && !(ir->vdwtype == evdwUSER) && !(ir->coulombtype == eelUSER)
-        && !(ir->coulombtype == eelPMEUSER) && !(ir->coulombtype == eelPMEUSERSWITCH))
+    if (bTable && !(ir->vdwtype == VanDerWaalsType::User)
+        && !(ir->coulombtype == CoulombInteractionType::User)
+        && !(ir->coulombtype == CoulombInteractionType::PmeUser)
+        && !(ir->coulombtype == CoulombInteractionType::PmeUserSwitch))
     {
         gmx_fatal(FARGS,
                   "Can only have energy group pair tables in combination with user tables for VdW "
@@ -3949,11 +4065,12 @@ void do_index(const char*                   mdparin,
     if ((ir->expandedvals->nstexpanded < 0) && ir->bSimTemp)
     {
         ir->expandedvals->nstexpanded = 2 * static_cast<int>(ir->opts.tau_t[0] / ir->delta_t);
-        warning(wi, gmx::formatString(
-                            "the value for nstexpanded was not specified for "
-                            " expanded ensemble simulated tempering. It is set to 2*tau_t (%d) "
-                            "by default, but it is recommended to set it to an explicit value!",
-                            ir->expandedvals->nstexpanded));
+        warning(wi,
+                gmx::formatString(
+                        "the value for nstexpanded was not specified for "
+                        " expanded ensemble simulated tempering. It is set to 2*tau_t (%d) "
+                        "by default, but it is recommended to set it to an explicit value!",
+                        ir->expandedvals->nstexpanded));
     }
     for (i = 0; (i < defaultIndexGroups->nr); i++)
     {
@@ -3965,11 +4082,11 @@ void do_index(const char*                   mdparin,
 }
 
 
-static void check_disre(const gmx_mtop_t* mtop)
+static void check_disre(const gmx_mtop_t& mtop)
 {
     if (gmx_mtop_ftype_count(mtop, F_DISRES) > 0)
     {
-        const gmx_ffparams_t& ffparams  = mtop->ffparams;
+        const gmx_ffparams_t& ffparams  = mtop.ffparams;
         int                   ndouble   = 0;
         int                   old_label = -1;
         for (int i = 0; i < ffparams.numTypes(); i++)
@@ -4027,15 +4144,15 @@ static BasicVector<bool> havePositionRestraints(const gmx_mtop_t& sys)
 {
     BasicVector<bool> havePosres = { false, false, false };
 
-    gmx_mtop_ilistloop_t iloop = gmx_mtop_ilistloop_init(&sys);
-    int                  nmol;
-    while (const InteractionLists* ilist = gmx_mtop_ilistloop_next(iloop, &nmol))
+    for (const auto ilists : IListRange(sys))
     {
-        if (nmol > 0 && (!havePosres[XX] || !havePosres[YY] || !havePosres[ZZ]))
+        const auto& posResList   = ilists.list()[F_POSRES];
+        const auto& fbPosResList = ilists.list()[F_FBPOSRES];
+        if (ilists.nmol() > 0 && (!havePosres[XX] || !havePosres[YY] || !havePosres[ZZ]))
         {
-            for (int i = 0; i < (*ilist)[F_POSRES].size(); i += 2)
+            for (int i = 0; i < posResList.size(); i += 2)
             {
-                const t_iparams& pr = sys.ffparams.iparams[(*ilist)[F_POSRES].iatoms[i]];
+                const t_iparams& pr = sys.ffparams.iparams[posResList.iatoms[i]];
                 for (int d = 0; d < DIM; d++)
                 {
                     if (pr.posres.fcA[d] != 0)
@@ -4044,10 +4161,10 @@ static BasicVector<bool> havePositionRestraints(const gmx_mtop_t& sys)
                     }
                 }
             }
-            for (int i = 0; i < (*ilist)[F_FBPOSRES].size(); i += 2)
+            for (int i = 0; i < fbPosResList.size(); i += 2)
             {
                 /* Check for flat-bottom posres */
-                const t_iparams& pr = sys.ffparams.iparams[(*ilist)[F_FBPOSRES].iatoms[i]];
+                const t_iparams& pr = sys.ffparams.iparams[fbPosResList.iatoms[i]];
                 if (pr.fbposres.k != 0)
                 {
                     switch (pr.fbposres.geom)
@@ -4067,7 +4184,8 @@ static BasicVector<bool> havePositionRestraints(const gmx_mtop_t& sys)
                             gmx_fatal(FARGS,
                                       "Invalid geometry for flat-bottom position restraint.\n"
                                       "Expected nr between 1 and %d. Found %d\n",
-                                      efbposresNR - 1, pr.fbposres.geom);
+                                      efbposresNR - 1,
+                                      pr.fbposres.geom);
                     }
                 }
             }
@@ -4077,7 +4195,7 @@ static BasicVector<bool> havePositionRestraints(const gmx_mtop_t& sys)
     return havePosres;
 }
 
-static void check_combination_rule_differences(const gmx_mtop_t* mtop,
+static void check_combination_rule_differences(const gmx_mtop_t& mtop,
                                                int               state,
                                                bool* bC6ParametersWorkWithGeometricRules,
                                                bool* bC6ParametersWorkWithLBRules,
@@ -4099,13 +4217,13 @@ static void check_combination_rule_differences(const gmx_mtop_t* mtop,
     ptr = getenv("GMX_LJCOMB_TOL");
     if (ptr != nullptr)
     {
-        double dbl;
+        double            dbl;
         double gmx_unused canary;
 
         if (sscanf(ptr, "%lf%lf", &dbl, &canary) != 1)
         {
-            gmx_fatal(FARGS,
-                      "Could not parse a single floating-point number from GMX_LJCOMB_TOL (%s)", ptr);
+            gmx_fatal(
+                    FARGS, "Could not parse a single floating-point number from GMX_LJCOMB_TOL (%s)", ptr);
         }
         tol = dbl;
     }
@@ -4113,19 +4231,19 @@ static void check_combination_rule_differences(const gmx_mtop_t* mtop,
     *bC6ParametersWorkWithLBRules        = TRUE;
     *bC6ParametersWorkWithGeometricRules = TRUE;
     bCanDoLBRules                        = TRUE;
-    ntypes                               = mtop->ffparams.atnr;
+    ntypes                               = mtop.ffparams.atnr;
     snew(typecount, ntypes);
     gmx_mtop_count_atomtypes(mtop, state, typecount);
     *bLBRulesPossible = TRUE;
     for (tpi = 0; tpi < ntypes; ++tpi)
     {
-        c6i  = mtop->ffparams.iparams[(ntypes + 1) * tpi].lj.c6;
-        c12i = mtop->ffparams.iparams[(ntypes + 1) * tpi].lj.c12;
+        c6i  = mtop.ffparams.iparams[(ntypes + 1) * tpi].lj.c6;
+        c12i = mtop.ffparams.iparams[(ntypes + 1) * tpi].lj.c12;
         for (tpj = tpi; tpj < ntypes; ++tpj)
         {
-            c6j          = mtop->ffparams.iparams[(ntypes + 1) * tpj].lj.c6;
-            c12j         = mtop->ffparams.iparams[(ntypes + 1) * tpj].lj.c12;
-            c6           = mtop->ffparams.iparams[ntypes * tpi + tpj].lj.c6;
+            c6j          = mtop.ffparams.iparams[(ntypes + 1) * tpj].lj.c6;
+            c12j         = mtop.ffparams.iparams[(ntypes + 1) * tpj].lj.c12;
+            c6           = mtop.ffparams.iparams[ntypes * tpi + tpj].lj.c6;
             c6_geometric = std::sqrt(c6i * c6j);
             if (!gmx_numzero(c6_geometric))
             {
@@ -4161,13 +4279,13 @@ static void check_combination_rule_differences(const gmx_mtop_t* mtop,
     sfree(typecount);
 }
 
-static void check_combination_rules(const t_inputrec* ir, const gmx_mtop_t* mtop, warninp_t wi)
+static void check_combination_rules(const t_inputrec* ir, const gmx_mtop_t& mtop, warninp_t wi)
 {
     bool bLBRulesPossible, bC6ParametersWorkWithGeometricRules, bC6ParametersWorkWithLBRules;
 
-    check_combination_rule_differences(mtop, 0, &bC6ParametersWorkWithGeometricRules,
-                                       &bC6ParametersWorkWithLBRules, &bLBRulesPossible);
-    if (ir->ljpme_combination_rule == eljpmeLB)
+    check_combination_rule_differences(
+            mtop, 0, &bC6ParametersWorkWithGeometricRules, &bC6ParametersWorkWithLBRules, &bLBRulesPossible);
+    if (ir->ljpme_combination_rule == LongRangeVdW::LB)
     {
         if (!bC6ParametersWorkWithLBRules || !bLBRulesPossible)
         {
@@ -4181,7 +4299,7 @@ static void check_combination_rules(const t_inputrec* ir, const gmx_mtop_t* mtop
     {
         if (!bC6ParametersWorkWithGeometricRules)
         {
-            if (ir->eDispCorr != edispcNO)
+            if (ir->eDispCorr != DispersionCorrectionType::No)
             {
                 warning_note(wi,
                              "You are using geometric combination rules in "
@@ -4215,13 +4333,11 @@ static bool allTrue(const BasicVector<bool>& boolVector)
 void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_t wi)
 {
     // Not meeting MTS requirements should have resulted in a fatal error, so we can assert here
-    gmx::assertMtsRequirements(*ir);
+    GMX_ASSERT(gmx::checkMtsRequirements(*ir).empty(), "All MTS requirements should be met here");
 
     char                      err_buf[STRLEN];
     int                       i, m, c, nmol;
-    bool                      bCharge, bAcc;
-    real *                    mgrp, mt;
-    rvec                      acc;
+    bool                      bCharge;
     gmx_mtop_atomloop_block_t aloopb;
     char                      warn_buf[STRLEN];
 
@@ -4235,8 +4351,9 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
                      "macro-molecule, the artifacts are usually negligible.");
     }
 
-    if (ir->cutoff_scheme == ecutsVERLET && ir->verletbuf_tol > 0 && ir->nstlist > 1
-        && ((EI_MD(ir->eI) || EI_SD(ir->eI)) && (ir->etc == etcVRESCALE || ir->etc == etcBERENDSEN)))
+    if (ir->cutoff_scheme == CutoffScheme::Verlet && ir->verletbuf_tol > 0 && ir->nstlist > 1
+        && ((EI_MD(ir->eI) || EI_SD(ir->eI))
+            && (ir->etc == TemperatureCoupling::VRescale || ir->etc == TemperatureCoupling::Berendsen)))
     {
         /* Check if a too small Verlet buffer might potentially
          * cause more drift than the thermostat can couple off.
@@ -4263,7 +4380,7 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
              * of errors. The factor 0.5 is because energy distributes
              * equally over Ekin and Epot.
              */
-            max_T_error = 0.5 * tau * ir->verletbuf_tol / (nrdf_at * BOLTZ * T);
+            max_T_error = 0.5 * tau * ir->verletbuf_tol / (nrdf_at * gmx::c_boltz * T);
             if (max_T_error > T_error_warn)
             {
                 sprintf(warn_buf,
@@ -4271,7 +4388,11 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
                         "of %g and a tau_t of %g, your temperature might be off by up to %.1f%%. "
                         "To ensure the error is below %.1f%%, decrease verlet-buffer-tolerance to "
                         "%.0e or decrease tau_t.",
-                        ir->verletbuf_tol, T, tau, 100 * max_T_error, 100 * T_error_suggest,
+                        ir->verletbuf_tol,
+                        T,
+                        tau,
+                        100 * max_T_error,
+                        100 * T_error_suggest,
                         ir->verletbuf_tol * T_error_suggest / max_T_error);
                 warning(wi, warn_buf);
             }
@@ -4292,11 +4413,12 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
             sprintf(err_buf,
                     "all tau_t must be positive using Andersen temperature control, "
                     "tau_t[%d]=%10.6f",
-                    i, ir->opts.tau_t[i]);
+                    i,
+                    ir->opts.tau_t[i]);
             CHECK(ir->opts.tau_t[i] < 0);
         }
 
-        if (ir->etc == etcANDERSENMASSIVE && ir->comm_mode != ecmNO)
+        if (ir->etc == TemperatureCoupling::AndersenMassive && ir->comm_mode != ComRemovalAlgorithm::No)
         {
             for (i = 0; i < ir->opts.ngtc; i++)
             {
@@ -4306,13 +4428,18 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
                         "multiple of nstcomm (%d), as velocities of atoms in coupled groups are "
                         "randomized every time step. The input tau_t (%8.3f) leads to %d steps per "
                         "randomization",
-                        i, etcoupl_names[ir->etc], ir->nstcomm, ir->opts.tau_t[i], nsteps);
+                        i,
+                        enumValueToString(ir->etc),
+                        ir->nstcomm,
+                        ir->opts.tau_t[i],
+                        nsteps);
                 CHECK(nsteps % ir->nstcomm != 0);
             }
         }
     }
 
-    if (EI_DYNAMICS(ir->eI) && !EI_SD(ir->eI) && ir->eI != eiBD && ir->comm_mode == ecmNO
+    if (EI_DYNAMICS(ir->eI) && !EI_SD(ir->eI) && ir->eI != IntegrationAlgorithm::BD
+        && ir->comm_mode == ComRemovalAlgorithm::No
         && !(allTrue(haveAbsoluteReference(*ir)) || allTrue(havePositionRestraints(*sys)) || ir->nsteps <= 10)
         && !ETC_ANDERSEN(ir->etc))
     {
@@ -4321,7 +4448,7 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
                 "rounding errors can lead to build up of kinetic energy of the center of mass");
     }
 
-    if (ir->epc == epcPARRINELLORAHMAN && ir->etc == etcNOSEHOOVER)
+    if (ir->epc == PressureCoupling::ParrinelloRahman && ir->etc == TemperatureCoupling::NoseHoover)
     {
         real tau_t_max = 0;
         for (int g = 0; g < ir->opts.ngtc; g++)
@@ -4333,14 +4460,18 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
             std::string message = gmx::formatString(
                     "With %s T-coupling and %s p-coupling, "
                     "%s (%g) should be at least twice as large as %s (%g) to avoid resonances",
-                    etcoupl_names[ir->etc], epcoupl_names[ir->epc], "tau-p", ir->tau_p, "tau-t",
+                    enumValueToString(ir->etc),
+                    enumValueToString(ir->epc),
+                    "tau-p",
+                    ir->tau_p,
+                    "tau-t",
                     tau_t_max);
             warning(wi, message.c_str());
         }
     }
 
     /* Check for pressure coupling with absolute position restraints */
-    if (ir->epc != epcNO && ir->refcoord_scaling == erscNO)
+    if (ir->epc != PressureCoupling::No && ir->refcoord_scaling == RefCoordScaling::No)
     {
         const BasicVector<bool> havePosres = havePositionRestraints(*sys);
         {
@@ -4358,7 +4489,7 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
     }
 
     bCharge = FALSE;
-    aloopb  = gmx_mtop_atomloop_block_init(sys);
+    aloopb  = gmx_mtop_atomloop_block_init(*sys);
     const t_atom* atom;
     while (gmx_mtop_atomloop_block_next(aloopb, &atom, &nmol))
     {
@@ -4376,18 +4507,19 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
                     "You are using full electrostatics treatment %s for a system without charges.\n"
                     "This costs a lot of performance for just processing zeros, consider using %s "
                     "instead.\n",
-                    EELTYPE(ir->coulombtype), EELTYPE(eelCUT));
+                    enumValueToString(ir->coulombtype),
+                    enumValueToString(CoulombInteractionType::Cut));
             warning(wi, err_buf);
         }
     }
     else
     {
-        if (ir->coulombtype == eelCUT && ir->rcoulomb > 0)
+        if (ir->coulombtype == CoulombInteractionType::Cut && ir->rcoulomb > 0)
         {
             sprintf(err_buf,
                     "You are using a plain Coulomb cut-off, which might produce artifacts.\n"
                     "You might want to consider using %s electrostatics.\n",
-                    EELTYPE(eelPME));
+                    enumValueToString(CoulombInteractionType::Pme));
             warning_note(wi, err_buf);
         }
     }
@@ -4395,11 +4527,11 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
     /* Check if combination rules used in LJ-PME are the same as in the force field */
     if (EVDW_PME(ir->vdwtype))
     {
-        check_combination_rules(ir, sys, wi);
+        check_combination_rules(ir, *sys, wi);
     }
 
     /* Generalized reaction field */
-    if (ir->coulombtype == eelGRF_NOTUSED)
+    if (ir->coulombtype == CoulombInteractionType::GRFNotused)
     {
         warning_error(wi,
                       "Generalized reaction-field electrostatics is no longer supported. "
@@ -4407,58 +4539,7 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
                       "constant by hand.");
     }
 
-    bAcc = FALSE;
-    for (int i = 0; (i < gmx::ssize(sys->groups.groups[SimulationAtomGroupType::Acceleration])); i++)
-    {
-        for (m = 0; (m < DIM); m++)
-        {
-            if (fabs(ir->opts.acc[i][m]) > 1e-6)
-            {
-                bAcc = TRUE;
-            }
-        }
-    }
-    if (bAcc)
-    {
-        clear_rvec(acc);
-        snew(mgrp, sys->groups.groups[SimulationAtomGroupType::Acceleration].size());
-        for (const AtomProxy atomP : AtomRange(*sys))
-        {
-            const t_atom& local = atomP.atom();
-            int           i     = atomP.globalAtomNumber();
-            mgrp[getGroupType(sys->groups, SimulationAtomGroupType::Acceleration, i)] += local.m;
-        }
-        mt = 0.0;
-        for (i = 0; (i < gmx::ssize(sys->groups.groups[SimulationAtomGroupType::Acceleration])); i++)
-        {
-            for (m = 0; (m < DIM); m++)
-            {
-                acc[m] += ir->opts.acc[i][m] * mgrp[i];
-            }
-            mt += mgrp[i];
-        }
-        for (m = 0; (m < DIM); m++)
-        {
-            if (fabs(acc[m]) > 1e-6)
-            {
-                const char* dim[DIM] = { "X", "Y", "Z" };
-                fprintf(stderr, "Net Acceleration in %s direction, will %s be corrected\n", dim[m],
-                        ir->nstcomm != 0 ? "" : "not");
-                if (ir->nstcomm != 0 && m < ndof_com(ir))
-                {
-                    acc[m] /= mt;
-                    for (i = 0;
-                         (i < gmx::ssize(sys->groups.groups[SimulationAtomGroupType::Acceleration])); i++)
-                    {
-                        ir->opts.acc[i][m] -= acc[m];
-                    }
-                }
-            }
-        }
-        sfree(mgrp);
-    }
-
-    if (ir->efep != efepNO && ir->fepvals->sc_alpha != 0
+    if (ir->efep != FreeEnergyPerturbationType::No && ir->fepvals->sc_alpha != 0
         && !gmx_within_tol(sys->ffparams.reppow, 12.0, 10 * GMX_DOUBLE_EPS))
     {
         gmx_fatal(FARGS, "Soft-core interactions are only supported with VdW repulsion power 12");
@@ -4494,16 +4575,18 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
         {
             for (m = 0; m <= i; m++)
             {
-                if ((ir->epc != epcNO && ir->compress[i][m] != 0) || ir->deform[i][m] != 0)
+                if ((ir->epc != PressureCoupling::No && ir->compress[i][m] != 0) || ir->deform[i][m] != 0)
                 {
                     for (c = 0; c < ir->pull->ncoord; c++)
                     {
-                        if (ir->pull->coord[c].eGeom == epullgDIRPBC && ir->pull->coord[c].vec[m] != 0)
+                        if (ir->pull->coord[c].eGeom == PullGroupGeometry::DirectionPBC
+                            && ir->pull->coord[c].vec[m] != 0)
                         {
                             gmx_fatal(FARGS,
                                       "Can not have dynamic box while using pull geometry '%s' "
                                       "(dim %c)",
-                                      EPULLGEOM(ir->pull->coord[c].eGeom), 'x' + m);
+                                      enumValueToString(ir->pull->coord[c].eGeom),
+                                      'x' + m);
                         }
                     }
                 }
@@ -4511,7 +4594,7 @@ void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_
         }
     }
 
-    check_disre(sys);
+    check_disre(*sys);
 }
 
 void double_check(t_inputrec* ir, matrix box, bool bHasNormalConstraints, bool bHasAnyConstraints, warninp_t wi)
@@ -4525,7 +4608,7 @@ void double_check(t_inputrec* ir, matrix box, bool bHasNormalConstraints, bool b
         warning_error(wi, ptr);
     }
 
-    if (bHasNormalConstraints && ir->eConstrAlg == econtSHAKE)
+    if (bHasNormalConstraints && ir->eConstrAlg == ConstraintAlgorithm::Shake)
     {
         if (ir->shake_tol <= 0.0)
         {
@@ -4534,30 +4617,32 @@ void double_check(t_inputrec* ir, matrix box, bool bHasNormalConstraints, bool b
         }
     }
 
-    if ((ir->eConstrAlg == econtLINCS) && bHasNormalConstraints)
+    if ((ir->eConstrAlg == ConstraintAlgorithm::Lincs) && bHasNormalConstraints)
     {
         /* If we have Lincs constraints: */
-        if (ir->eI == eiMD && ir->etc == etcNO && ir->eConstrAlg == econtLINCS && ir->nLincsIter == 1)
+        if (ir->eI == IntegrationAlgorithm::MD && ir->etc == TemperatureCoupling::No
+            && ir->eConstrAlg == ConstraintAlgorithm::Lincs && ir->nLincsIter == 1)
         {
             sprintf(warn_buf,
                     "For energy conservation with LINCS, lincs_iter should be 2 or larger.\n");
             warning_note(wi, warn_buf);
         }
 
-        if ((ir->eI == eiCG || ir->eI == eiLBFGS) && (ir->nProjOrder < 8))
+        if ((ir->eI == IntegrationAlgorithm::CG || ir->eI == IntegrationAlgorithm::LBFGS)
+            && (ir->nProjOrder < 8))
         {
             sprintf(warn_buf,
                     "For accurate %s with LINCS constraints, lincs-order should be 8 or more.",
-                    ei_names[ir->eI]);
+                    enumValueToString(ir->eI));
             warning_note(wi, warn_buf);
         }
-        if (ir->epc == epcMTTK)
+        if (ir->epc == PressureCoupling::Mttk)
         {
             warning_error(wi, "MTTK not compatible with lincs -- use shake instead.");
         }
     }
 
-    if (bHasAnyConstraints && ir->epc == epcMTTK)
+    if (bHasAnyConstraints && ir->epc == PressureCoupling::Mttk)
     {
         warning_error(wi, "Constraints are not implemented with MTTK pressure control.");
     }
index 65050546ff4003ed05215ab1662986c553a95a47..9b7aa8194d4ef00c7d30cfce1afc024ea7bd466d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/readinp.h"
 #include "gromacs/math/vectypes.h"
+#include "gromacs/mdtypes/multipletimestepping.h"
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/real.h"
 
 namespace gmx
 {
 class MDModules;
-struct MdModulesNotifier;
+struct MDModulesNotifiers;
 } // namespace gmx
 
 struct gmx_mtop_t;
@@ -87,23 +88,22 @@ enum
 
 struct t_gromppopts
 {
-    int         warnings     = 0;
-    int         nshake       = 0;
-    char*       include      = nullptr;
-    char*       define       = nullptr;
-    bool        bGenVel      = false;
-    bool        bGenPairs    = false;
-    real        tempi        = 0;
-    int         seed         = 0;
-    int         numMtsLevels = 0;
-    std::string mtsLevel2Forces;
-    bool        bOrire           = false;
-    bool        bMorse           = false;
-    char*       wall_atomtype[2] = { nullptr, nullptr };
-    char*       couple_moltype   = nullptr;
-    int         couple_lam0      = 0;
-    int         couple_lam1      = 0;
-    bool        bCoupleIntra     = false;
+    int                warnings  = 0;
+    int                nshake    = 0;
+    char*              include   = nullptr;
+    char*              define    = nullptr;
+    bool               bGenVel   = false;
+    bool               bGenPairs = false;
+    real               tempi     = 0;
+    int                seed      = 0;
+    gmx::GromppMtsOpts mtsOpts;
+    bool               bOrire           = false;
+    bool               bMorse           = false;
+    char*              wall_atomtype[2] = { nullptr, nullptr };
+    char*              couple_moltype   = nullptr;
+    int                couple_lam0      = 0;
+    int                couple_lam1      = 0;
+    bool               bCoupleIntra     = false;
 };
 
 /*! \brief Initialise object to hold strings parsed from an .mdp file */
@@ -112,11 +112,11 @@ void init_inputrec_strings();
 /*! \brief Clean up object that holds strings parsed from an .mdp file */
 void done_inputrec_strings();
 
-void check_ir(const char*                   mdparin,
-              const gmx::MdModulesNotifier& mdModulesNotifier,
-              t_inputrec*                   ir,
-              t_gromppopts*                 opts,
-              warninp_t                     wi);
+void check_ir(const char*                    mdparin,
+              const gmx::MDModulesNotifiers& mdModulesNotifiers,
+              t_inputrec*                    ir,
+              t_gromppopts*                  opts,
+              warninp_t                      wi);
 /* Validate inputrec data.
  * Fatal errors will be added to nerror.
  */
@@ -141,13 +141,13 @@ void get_ir(const char*     mdparin,
  * function is called. Also prints the input file back to mdparout.
  */
 
-void do_index(const char*                   mdparin,
-              const char*                   ndx,
-              gmx_mtop_t*                   mtop,
-              bool                          bVerbose,
-              const gmx::MdModulesNotifier& notifier,
-              t_inputrec*                   ir,
-              warninp_t                     wi);
+void do_index(const char*                    mdparin,
+              const char*                    ndx,
+              gmx_mtop_t*                    mtop,
+              bool                           bVerbose,
+              const gmx::MDModulesNotifiers& mdModulesNotifiers,
+              t_inputrec*                    ir,
+              warninp_t                      wi);
 /* Read the index file and assign grp numbers to atoms.
  */
 
@@ -165,7 +165,12 @@ void checkPullCoords(gmx::ArrayRef<const t_pull_group> pullGroups,
                      gmx::ArrayRef<const t_pull_coord> pullCoords);
 /* Process the pull coordinates after reading the pull groups */
 
-pull_t* set_pull_init(t_inputrec* ir, const gmx_mtop_t* mtop, rvec* x, matrix box, real lambda, warninp_t wi);
+pull_t* set_pull_init(t_inputrec*                    ir,
+                      const gmx_mtop_t&              mtop,
+                      gmx::ArrayRef<const gmx::RVec> x,
+                      matrix                         box,
+                      real                           lambda,
+                      warninp_t                      wi);
 /* Prints the initial pull group distances in x.
  * If requested, adds the current distance to the initial reference location.
  * Returns the pull_t pull work struct. This should be passed to finish_pull()
index 0a5b1afea5b1d79603aa46c61cff74761da4e6dd..9259884432c0859fe8f2fbebf92317bacb5769d7 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,15 +119,16 @@ static void process_pull_dim(char* dim_buf, ivec dim, const t_pull_coord* pcrd)
     {
         gmx_fatal(FARGS, "All entries in pull dim are N");
     }
-    if ((pcrd->eGeom == epullgDIHEDRAL) && (ndim < 3))
+    if ((pcrd->eGeom == PullGroupGeometry::Dihedral) && (ndim < 3))
     {
         gmx_fatal(FARGS, "Pull geometry dihedral is only useful with pull-dim = Y Y Y");
     }
-    if ((pcrd->eGeom == epullgANGLE || pcrd->eGeom == epullgANGLEAXIS) && (ndim < 2))
+    if ((pcrd->eGeom == PullGroupGeometry::Angle || pcrd->eGeom == PullGroupGeometry::AngleAxis)
+        && (ndim < 2))
     {
         gmx_fatal(FARGS,
                   "Pull geometry %s is only useful with pull-dim = Y for at least 2 dimensions",
-                  EPULLGEOM(pcrd->eGeom));
+                  enumValueToString(pcrd->eGeom));
     }
 }
 
@@ -142,25 +143,31 @@ static void init_pull_coord(t_pull_coord* pcrd,
     dvec origin, vec;
     char buf[STRLEN];
 
-    if (pcrd->eType == epullCONSTRAINT
-        && (pcrd->eGeom == epullgCYL || pcrd->eGeom == epullgDIRRELATIVE || pcrd->eGeom == epullgANGLE
-            || pcrd->eGeom == epullgANGLEAXIS || pcrd->eGeom == epullgDIHEDRAL))
+    if (pcrd->eType == PullingAlgorithm::Constraint
+        && (pcrd->eGeom == PullGroupGeometry::Cylinder || pcrd->eGeom == PullGroupGeometry::DirectionRelative
+            || pcrd->eGeom == PullGroupGeometry::Angle || pcrd->eGeom == PullGroupGeometry::AngleAxis
+            || pcrd->eGeom == PullGroupGeometry::Dihedral))
     {
         gmx_fatal(FARGS,
                   "Pulling of type %s can not be combined with geometry %s. Consider using pull "
                   "type %s.",
-                  epull_names[pcrd->eType], epullg_names[pcrd->eGeom], epull_names[epullUMBRELLA]);
+                  enumValueToString(pcrd->eType),
+                  enumValueToString(pcrd->eGeom),
+                  enumValueToString(PullingAlgorithm::Umbrella));
     }
 
-    if (pcrd->eType == epullEXTERNAL)
+    if (pcrd->eType == PullingAlgorithm::External)
     {
         if (pcrd->externalPotentialProvider[0] == '\0')
         {
             sprintf(buf,
                     "The use of pull type '%s' for pull coordinate %d requires that the name of "
                     "the module providing the potential external is set with the option %s%d%s",
-                    epull_names[pcrd->eType], coord_index_for_output, "pull-coord",
-                    coord_index_for_output, "-potential-provider");
+                    enumValueToString(pcrd->eType),
+                    coord_index_for_output,
+                    "pull-coord",
+                    coord_index_for_output,
+                    "-potential-provider");
             warning_error(wi, buf);
         }
 
@@ -169,11 +176,12 @@ static void init_pull_coord(t_pull_coord* pcrd,
             sprintf(buf,
                     "The use of pull type '%s' for pull coordinate %d requires that the pull rate "
                     "is zero",
-                    epull_names[pcrd->eType], coord_index_for_output);
+                    enumValueToString(pcrd->eType),
+                    coord_index_for_output);
             warning_error(wi, buf);
         }
 
-        if (pcrd->eGeom == epullgCYL)
+        if (pcrd->eGeom == PullGroupGeometry::Cylinder)
         {
             /* Warn the user of a PBC restriction, caused by the fact that
              * there is no reference value with an external pull potential.
@@ -182,7 +190,8 @@ static void init_pull_coord(t_pull_coord* pcrd,
                     "With pull type '%s' and geometry '%s', the distance component along the "
                     "cylinder axis between atoms in the cylinder group and the COM of the pull "
                     "group should be smaller than half the box length",
-                    epull_names[pcrd->eType], epullg_names[pcrd->eGeom]);
+                    enumValueToString(pcrd->eType),
+                    enumValueToString(pcrd->eGeom));
             warning_note(wi, buf);
         }
     }
@@ -196,7 +205,7 @@ static void init_pull_coord(t_pull_coord* pcrd,
     }
 
     /* Check the given initial reference value and warn for dangerous values */
-    if (pcrd->eGeom == epullgDIST)
+    if (pcrd->eGeom == PullGroupGeometry::Distance)
     {
         if (pcrd->bStart && pcrd->init < 0)
         {
@@ -206,11 +215,13 @@ static void init_pull_coord(t_pull_coord* pcrd,
                     "This may work, since you have set pull-coord-start to 'yes' which modifies "
                     "this value, but only for certain starting distances. "
                     "If this is a mistake you may want to use geometry %s instead.",
-                    pcrd->init, EPULLGEOM(pcrd->eGeom), EPULLGEOM(epullgDIR));
+                    pcrd->init,
+                    enumValueToString(pcrd->eGeom),
+                    enumValueToString(PullGroupGeometry::Direction));
             warning(wi, buf);
         }
     }
-    else if (pcrd->eGeom == epullgANGLE || pcrd->eGeom == epullgANGLEAXIS)
+    else if (pcrd->eGeom == PullGroupGeometry::Angle || pcrd->eGeom == PullGroupGeometry::AngleAxis)
     {
         if (pcrd->bStart && (pcrd->init < 0 || pcrd->init > 180))
         {
@@ -220,11 +231,12 @@ static void init_pull_coord(t_pull_coord* pcrd,
                     "allowed range [0, 180] degrees for geometry (%s). "
                     "This may work, since you have set pull-coord-start to 'yes' which modifies "
                     "this value, but only for certain starting angles.",
-                    pcrd->init, EPULLGEOM(pcrd->eGeom));
+                    pcrd->init,
+                    enumValueToString(pcrd->eGeom));
             warning(wi, buf);
         }
     }
-    else if (pcrd->eGeom == epullgDIHEDRAL)
+    else if (pcrd->eGeom == PullGroupGeometry::Dihedral)
     {
         if (pcrd->bStart && (pcrd->init < -180 || pcrd->init > 180))
         {
@@ -233,7 +245,8 @@ static void init_pull_coord(t_pull_coord* pcrd,
                     "allowed range [-180, 180] degrees for geometry (%s). "
                     "This may work, since you have set pull-coord-start to 'yes' which modifies "
                     "this value, but only for certain starting angles.",
-                    pcrd->init, EPULLGEOM(pcrd->eGeom));
+                    pcrd->init,
+                    enumValueToString(pcrd->eGeom));
             warning(wi, buf);
         }
     }
@@ -242,13 +255,14 @@ static void init_pull_coord(t_pull_coord* pcrd,
     clear_dvec(vec);
     string2dvec(vec_buf, vec);
 
-    if (pcrd->eGeom == epullgDIR || pcrd->eGeom == epullgCYL || pcrd->eGeom == epullgDIRPBC
-        || pcrd->eGeom == epullgANGLEAXIS)
+    if (pcrd->eGeom == PullGroupGeometry::Direction || pcrd->eGeom == PullGroupGeometry::Cylinder
+        || pcrd->eGeom == PullGroupGeometry::DirectionPBC || pcrd->eGeom == PullGroupGeometry::AngleAxis)
     {
         if (dnorm2(vec) == 0)
         {
-            gmx_fatal(FARGS, "With pull geometry %s the pull vector can not be 0,0,0",
-                      epullg_names[pcrd->eGeom]);
+            gmx_fatal(FARGS,
+                      "With pull geometry %s the pull vector can not be 0,0,0",
+                      enumValueToString(pcrd->eGeom));
         }
         for (int d = 0; d < DIM; d++)
         {
@@ -257,7 +271,8 @@ static void init_pull_coord(t_pull_coord* pcrd,
                 gmx_fatal(FARGS,
                           "pull-coord-vec has non-zero %c-component while pull_dim for the "
                           "%c-dimension is set to N",
-                          'x' + d, 'x' + d);
+                          'x' + d,
+                          'x' + d);
             }
         }
 
@@ -272,8 +287,13 @@ static void init_pull_coord(t_pull_coord* pcrd,
                     "A pull vector is given (%g  %g  %g) but will not be used with geometry %s. If "
                     "you really want to use this "
                     "vector, consider using geometry %s instead.",
-                    vec[0], vec[1], vec[2], EPULLGEOM(pcrd->eGeom),
-                    pcrd->eGeom == epullgANGLE ? EPULLGEOM(epullgANGLEAXIS) : EPULLGEOM(epullgDIR));
+                    vec[0],
+                    vec[1],
+                    vec[2],
+                    enumValueToString(pcrd->eGeom),
+                    pcrd->eGeom == PullGroupGeometry::Angle
+                            ? enumValueToString(PullGroupGeometry::AngleAxis)
+                            : enumValueToString(PullGroupGeometry::Direction));
             warning(wi, buf);
         }
     }
@@ -295,14 +315,15 @@ std::vector<std::string> read_pullparams(std::vector<t_inpfile>* inp, pull_param
     printStringNoNewline(inp, "Cylinder radius for dynamic reaction force groups (nm)");
     pull->cylinder_r     = get_ereal(inp, "pull-cylinder-r", 1.5, wi);
     pull->constr_tol     = get_ereal(inp, "pull-constr-tol", 1E-6, wi);
-    pull->bPrintCOM      = (get_eeenum(inp, "pull-print-com", yesno_names, wi) != 0);
-    pull->bPrintRefValue = (get_eeenum(inp, "pull-print-ref-value", yesno_names, wi) != 0);
-    pull->bPrintComp     = (get_eeenum(inp, "pull-print-components", yesno_names, wi) != 0);
+    pull->bPrintCOM      = (getEnum<Boolean>(inp, "pull-print-com", wi) != Boolean::No);
+    pull->bPrintRefValue = (getEnum<Boolean>(inp, "pull-print-ref-value", wi) != Boolean::No);
+    pull->bPrintComp     = (getEnum<Boolean>(inp, "pull-print-components", wi) != Boolean::No);
     pull->nstxout        = get_eint(inp, "pull-nstxout", 50, wi);
     pull->nstfout        = get_eint(inp, "pull-nstfout", 50, wi);
-    pull->bSetPbcRefToPrevStepCOM = (get_eeenum(inp, "pull-pbc-ref-prev-step-com", yesno_names, wi) != 0);
-    pull->bXOutAverage            = (get_eeenum(inp, "pull-xout-average", yesno_names, wi) != 0);
-    pull->bFOutAverage            = (get_eeenum(inp, "pull-fout-average", yesno_names, wi) != 0);
+    pull->bSetPbcRefToPrevStepCOM =
+            (getEnum<Boolean>(inp, "pull-pbc-ref-prev-step-com", wi) != Boolean::No);
+    pull->bXOutAverage = (getEnum<Boolean>(inp, "pull-xout-average", wi) != Boolean::No);
+    pull->bFOutAverage = (getEnum<Boolean>(inp, "pull-fout-average", wi) != Boolean::No);
     printStringNoNewline(inp, "Number of pull groups");
     pull->ngroup = get_eint(inp, "pull-ngroups", 1, wi);
     printStringNoNewline(inp, "Number of pull coordinates");
@@ -330,14 +351,15 @@ std::vector<std::string> read_pullparams(std::vector<t_inpfile>* inp, pull_param
     pull->group.emplace_back(t_pull_group());
     for (int groupNum = 1; groupNum < pull->ngroup; groupNum++)
     {
-        t_pull_group pullGroup; //= &pull->group[groupNum];
+        t_pull_group pullGroup;
         sprintf(buf, "pull-group%d-name", groupNum);
         setStringEntry(inp, buf, readBuffer, "");
         pullGroups[groupNum] = readBuffer;
         sprintf(buf, "pull-group%d-weights", groupNum);
         setStringEntry(inp, buf, wbuf, "");
         sprintf(buf, "pull-group%d-pbcatom", groupNum);
-        pullGroup.pbcatom = get_eint(inp, buf, 0, wi);
+        pullGroup.pbcatom       = get_eint(inp, buf, 0, wi);
+        pullGroup.pbcatom_input = pullGroup.pbcatom;
 
         /* Initialize the pull group */
         pullGroup.weight = setupPullGroupWeights(wbuf);
@@ -349,31 +371,39 @@ std::vector<std::string> read_pullparams(std::vector<t_inpfile>* inp, pull_param
     {
         t_pull_coord pullCoord; // = &pull->coord[coordNum - 1];
         sprintf(buf, "pull-coord%d-type", coordNum);
-        pullCoord.eType = get_eeenum(inp, buf, epull_names, wi);
+        pullCoord.eType = getEnum<PullingAlgorithm>(inp, buf, wi);
         sprintf(buf, "pull-coord%d-potential-provider", coordNum);
         setStringEntry(inp, buf, provider, "");
-        pullCoord.externalPotentialProvider = gmx_strdup(provider);
+        pullCoord.externalPotentialProvider = provider;
         sprintf(buf, "pull-coord%d-geometry", coordNum);
-        pullCoord.eGeom = get_eeenum(inp, buf, epullg_names, wi);
+        pullCoord.eGeom = getEnum<PullGroupGeometry>(inp, buf, wi);
         sprintf(buf, "pull-coord%d-groups", coordNum);
         setStringEntry(inp, buf, groups, "");
 
         switch (pullCoord.eGeom)
         {
-            case epullgDIHEDRAL: pullCoord.ngroup = 6; break;
-            case epullgDIRRELATIVE:
-            case epullgANGLE: pullCoord.ngroup = 4; break;
+            case PullGroupGeometry::Dihedral: pullCoord.ngroup = 6; break;
+            case PullGroupGeometry::DirectionRelative:
+            case PullGroupGeometry::Angle: pullCoord.ngroup = 4; break;
             default: pullCoord.ngroup = 2; break;
         }
 
-        nscan = sscanf(groups, "%d %d %d %d %d %d %d", &pullCoord.group[0], &pullCoord.group[1],
-                       &pullCoord.group[2], &pullCoord.group[3], &pullCoord.group[4],
-                       &pullCoord.group[5], &idum);
+        nscan = sscanf(groups,
+                       "%d %d %d %d %d %d %d",
+                       &pullCoord.group[0],
+                       &pullCoord.group[1],
+                       &pullCoord.group[2],
+                       &pullCoord.group[3],
+                       &pullCoord.group[4],
+                       &pullCoord.group[5],
+                       &idum);
         if (nscan != pullCoord.ngroup)
         {
             auto message =
                     gmx::formatString("%s should contain %d pull group indices with geometry %s",
-                                      buf, pullCoord.ngroup, epullg_names[pullCoord.eGeom]);
+                                      buf,
+                                      pullCoord.ngroup,
+                                      enumValueToString(pullCoord.eGeom));
             set_warning_line(wi, nullptr, -1);
             warning_error(wi, message);
         }
@@ -384,7 +414,10 @@ std::vector<std::string> read_pullparams(std::vector<t_inpfile>* inp, pull_param
                 /* Quit with a fatal error to avoid invalid memory access */
                 gmx_fatal(FARGS,
                           "%s contains an invalid pull group %d, you should have %d <= group <= %d",
-                          buf, pullCoord.group[g], 0, pull->ngroup - 1);
+                          buf,
+                          pullCoord.group[g],
+                          0,
+                          pull->ngroup - 1);
             }
         }
 
@@ -395,7 +428,7 @@ std::vector<std::string> read_pullparams(std::vector<t_inpfile>* inp, pull_param
         sprintf(buf, "pull-coord%d-vec", coordNum);
         setStringEntry(inp, buf, vec_buf, "0.0 0.0 0.0");
         sprintf(buf, "pull-coord%d-start", coordNum);
-        pullCoord.bStart = (get_eeenum(inp, buf, yesno_names, wi) != 0);
+        pullCoord.bStart = (getEnum<Boolean>(inp, buf, wi) != Boolean::No);
         sprintf(buf, "pull-coord%d-init", coordNum);
         pullCoord.init = get_ereal(inp, buf, 0.0, wi);
         sprintf(buf, "pull-coord%d-rate", coordNum);
@@ -407,6 +440,8 @@ std::vector<std::string> read_pullparams(std::vector<t_inpfile>* inp, pull_param
 
         /* Initialize the pull coordinate */
         init_pull_coord(&pullCoord, coordNum, dim_buf, origin_buf, vec_buf, wi);
+
+        pullCoord.coordIndex = coordNum - 1;
         pull->coord.emplace_back(pullCoord);
     }
 
@@ -452,7 +487,9 @@ void process_pull_groups(gmx::ArrayRef<t_pull_group>      pullGroups,
             gmx_fatal(FARGS,
                       "Number of weights (%ld) for pull group %d '%s' does not match the number of "
                       "atoms (%ld)",
-                      gmx::ssize(pullGroup.weight), g, pullGroupNames[g].c_str(),
+                      gmx::ssize(pullGroup.weight),
+                      g,
+                      pullGroupNames[g].c_str(),
                       gmx::ssize(pullGroup.ind));
         }
 
@@ -485,7 +522,9 @@ void checkPullCoords(gmx::ArrayRef<const t_pull_group> pullGroups, gmx::ArrayRef
 {
     for (int c = 0; c < int(pullCoords.size()); c++)
     {
-        t_pull_coord pcrd = pullCoords[c];
+        const t_pull_coord& pcrd = pullCoords[c];
+
+        GMX_RELEASE_ASSERT(pcrd.coordIndex == c, "coordIndex should match the index in the vector");
 
         if (pcrd.group[0] < 0 || pcrd.group[0] >= int(pullGroups.size()) || pcrd.group[1] < 0
             || pcrd.group[1] >= int(pullGroups.size()))
@@ -493,15 +532,17 @@ void checkPullCoords(gmx::ArrayRef<const t_pull_group> pullGroups, gmx::ArrayRef
             gmx_fatal(FARGS,
                       "Pull group index in pull-coord%d-groups out of range, should be between %d "
                       "and %d",
-                      c + 1, 0, int(pullGroups.size()) + 1);
+                      pcrd.coordIndex + 1,
+                      0,
+                      int(pullGroups.size()) + 1);
         }
 
         if (pcrd.group[0] == pcrd.group[1])
         {
-            gmx_fatal(FARGS, "Identical pull group indices in pull-coord%d-groups", c + 1);
+            gmx_fatal(FARGS, "Identical pull group indices in pull-coord%d-groups", pcrd.coordIndex + 1);
         }
 
-        if (pcrd.eGeom == epullgCYL)
+        if (pcrd.eGeom == PullGroupGeometry::Cylinder)
         {
             if (!pullGroups[pcrd.group[0]].weight.empty())
             {
@@ -513,7 +554,12 @@ void checkPullCoords(gmx::ArrayRef<const t_pull_group> pullGroups, gmx::ArrayRef
     }
 }
 
-pull_t* set_pull_init(t_inputrec* ir, const gmx_mtop_t* mtop, rvec* x, matrix box, real lambda, warninp_t wi)
+pull_t* set_pull_init(t_inputrec*                    ir,
+                      const gmx_mtop_t&              mtop,
+                      gmx::ArrayRef<const gmx::RVec> x,
+                      matrix                         box,
+                      real                           lambda,
+                      warninp_t                      wi)
 {
     pull_t* pull_work;
     t_pbc   pbc;
@@ -522,11 +568,11 @@ pull_t* set_pull_init(t_inputrec* ir, const gmx_mtop_t* mtop, rvec* x, matrix bo
 
     pull_params_t*           pull = ir->pull.get();
     gmx::LocalAtomSetManager atomSets;
-    pull_work    = init_pull(nullptr, pull, ir, mtop, nullptr, &atomSets, lambda);
-    auto mdAtoms = gmx::makeMDAtoms(nullptr, *mtop, *ir, false);
-    auto md      = mdAtoms->mdatoms();
-    atoms2md(mtop, ir, -1, {}, mtop->natoms, mdAtoms.get());
-    if (ir->efep)
+    pull_work     = init_pull(nullptr, pull, ir, mtop, nullptr, &atomSets, lambda);
+    auto  mdAtoms = gmx::makeMDAtoms(nullptr, mtop, *ir, false);
+    auto* md      = mdAtoms->mdatoms();
+    atoms2md(mtop, *ir, -1, {}, mtop.natoms, mdAtoms.get());
+    if (ir->efep != FreeEnergyPerturbationType::No)
     {
         update_mdatoms(md, lambda);
     }
@@ -537,15 +583,14 @@ pull_t* set_pull_init(t_inputrec* ir, const gmx_mtop_t* mtop, rvec* x, matrix bo
 
     if (pull->bSetPbcRefToPrevStepCOM)
     {
-        initPullComFromPrevStep(nullptr, pull_work, md->massT, &pbc, x);
+        initPullComFromPrevStep(nullptr, pull_work, gmx::arrayRefFromArray(md->massT, md->nr), &pbc, x);
     }
-    pull_calc_coms(nullptr, pull_work, md->massT, &pbc, t_start, x, nullptr);
+    pull_calc_coms(nullptr, pull_work, gmx::arrayRefFromArray(md->massT, md->nr), &pbc, t_start, x, {});
 
     for (int g = 0; g < pull->ngroup; g++)
     {
-        bool groupObeysPbc = pullCheckPbcWithinGroup(
-                *pull_work, gmx::arrayRefFromArray(reinterpret_cast<gmx::RVec*>(x), mtop->natoms),
-                pbc, g, c_pullGroupSmallGroupThreshold);
+        bool groupObeysPbc =
+                pullCheckPbcWithinGroup(*pull_work, x, pbc, g, c_pullGroupSmallGroupThreshold);
         if (!groupObeysPbc)
         {
             char buf[STRLEN];
@@ -558,7 +603,8 @@ pull_t* set_pull_init(t_inputrec* ir, const gmx_mtop_t* mtop, rvec* x, matrix bo
                         "atom should be chosen as pbcatom. Pull group %d is larger than that and "
                         "does not have "
                         "a specific atom selected as reference atom.",
-                        c_pullGroupSmallGroupThreshold, g);
+                        c_pullGroupSmallGroupThreshold,
+                        g);
                 warning_error(wi, buf);
             }
             else if (!pull->bSetPbcRefToPrevStepCOM)
@@ -568,15 +614,15 @@ pull_t* set_pull_init(t_inputrec* ir, const gmx_mtop_t* mtop, rvec* x, matrix bo
                         "other "
                         "atoms in the group is larger than %g times half the box size. "
                         "Set the pull-pbc-ref-prev-step-com option to yes.",
-                        pull->group[g].pbcatom + 1, g, c_pullGroupSmallGroupThreshold);
+                        pull->group[g].pbcatom + 1,
+                        g,
+                        c_pullGroupSmallGroupThreshold);
                 warning_error(wi, buf);
             }
         }
         if (groupObeysPbc)
         {
-            groupObeysPbc = pullCheckPbcWithinGroup(
-                    *pull_work, gmx::arrayRefFromArray(reinterpret_cast<gmx::RVec*>(x), mtop->natoms),
-                    pbc, g, c_pullGroupPbcMargin);
+            groupObeysPbc = pullCheckPbcWithinGroup(*pull_work, x, pbc, g, c_pullGroupPbcMargin);
             if (!groupObeysPbc)
             {
                 char buf[STRLEN];
@@ -585,7 +631,9 @@ pull_t* set_pull_init(t_inputrec* ir, const gmx_mtop_t* mtop, rvec* x, matrix bo
                         "size from the PBC atom (%d). "
                         "If atoms are or will more beyond half the box size from the PBC atom, the "
                         "COM will be ill defined.",
-                        g, c_pullGroupPbcMargin, pull->group[g].pbcatom + 1);
+                        g,
+                        c_pullGroupPbcMargin,
+                        pull->group[g].pbcatom + 1);
                 set_warning_line(wi, nullptr, -1);
                 warning(wi, buf);
             }
@@ -615,22 +663,24 @@ pull_t* set_pull_init(t_inputrec* ir, const gmx_mtop_t* mtop, rvec* x, matrix bo
 
         value = get_pull_coord_value(pull_work, c, &pbc);
 
-        value *= pull_conversion_factor_internal2userinput(pcrd);
-        fprintf(stderr, " %10.3f %s", value, pull_coordinate_units(pcrd));
+        value *= pull_conversion_factor_internal2userinput(*pcrd);
+        fprintf(stderr, " %10.3f %s", value, pull_coordinate_units(*pcrd));
 
         if (pcrd->bStart)
         {
             pcrd->init = value + init;
         }
 
-        if (pcrd->eGeom == epullgDIST)
+        if (pcrd->eGeom == PullGroupGeometry::Distance)
         {
             if (pcrd->init < 0)
             {
                 gmx_fatal(FARGS,
                           "The initial pull distance (%g) needs to be non-negative with geometry "
                           "%s. If you want a signed distance, use geometry %s instead.",
-                          pcrd->init, EPULLGEOM(pcrd->eGeom), EPULLGEOM(epullgDIR));
+                          pcrd->init,
+                          enumValueToString(pcrd->eGeom),
+                          enumValueToString(PullGroupGeometry::Direction));
             }
 
             /* TODO: With a positive init but a negative rate things could still
@@ -641,7 +691,7 @@ pull_t* set_pull_init(t_inputrec* ir, const gmx_mtop_t* mtop, rvec* x, matrix bo
              * generalization of the pull code makes pull dim available here.
              */
         }
-        else if (pcrd->eGeom == epullgANGLE || pcrd->eGeom == epullgANGLEAXIS)
+        else if (pcrd->eGeom == PullGroupGeometry::Angle || pcrd->eGeom == PullGroupGeometry::AngleAxis)
         {
             if (pcrd->init < 0 || pcrd->init > 180)
             {
@@ -651,7 +701,7 @@ pull_t* set_pull_init(t_inputrec* ir, const gmx_mtop_t* mtop, rvec* x, matrix bo
                           pcrd->init);
             }
         }
-        else if (pcrd->eGeom == epullgDIHEDRAL)
+        else if (pcrd->eGeom == PullGroupGeometry::Dihedral)
         {
             if (pcrd->init < -180 || pcrd->init > 180)
             {
@@ -663,7 +713,7 @@ pull_t* set_pull_init(t_inputrec* ir, const gmx_mtop_t* mtop, rvec* x, matrix bo
         }
 
 
-        fprintf(stderr, "     %10.3f %s\n", pcrd->init, pull_coordinate_units(pcrd));
+        fprintf(stderr, "     %10.3f %s\n", pcrd->init, pull_coordinate_units(*pcrd));
     }
 
     return pull_work;
index 6ef252e7f5368aaa88bff4de1d7e3d3913f07019..262c658b2a950e3a8c8b7cb569e2c6ce7d87865c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/smalloc.h"
 #include "gromacs/utility/stringutil.h"
 
-static const char* RotStr = "Enforced rotation:";
-
-
-static char s_vec[STRLEN];
-
+static const std::string RotStr = "Enforced rotation:";
 
 static void string2dvec(char buf[], dvec nums)
 {
@@ -100,6 +96,7 @@ extern std::vector<std::string> read_rotparams(std::vector<t_inpfile>* inp, t_ro
     /* Read the rotation groups */
     std::vector<std::string> rotateGroups(rot->ngrp);
     char                     readBuffer[STRLEN];
+    char                     s_vec[STRLEN];
     for (g = 0; g < rot->ngrp; g++)
     {
         rotg = &rot->grp[g];
@@ -111,11 +108,11 @@ extern std::vector<std::string> read_rotparams(std::vector<t_inpfile>* inp, t_ro
                              "Rotation potential. Can be iso, iso-pf, pm, pm-pf, rm, rm-pf, rm2, "
                              "rm2-pf, flex, flex-t, flex2, flex2-t");
         sprintf(buf, "rot-type%d", g);
-        rotg->eType = get_eenum(inp, buf, erotg_names);
+        rotg->eType = getEnum<EnforcedRotationGroupType>(inp, buf, wi);
 
         printStringNoNewline(inp, "Use mass-weighting of the rotation group positions");
         sprintf(buf, "rot-massw%d", g);
-        rotg->bMassW = get_eenum(inp, buf, yesno_names);
+        rotg->bMassW = getEnum<Boolean>(inp, buf, wi) != Boolean::No;
 
         printStringNoNewline(inp, "Rotation vector, will get normalized");
         sprintf(buf, "rot-vec%d", g);
@@ -131,8 +128,14 @@ extern std::vector<std::string> read_rotparams(std::vector<t_inpfile>* inp, t_ro
             sprintf(warn_buf, "rot-vec%d = 0", g);
             warning_error(wi, warn_buf);
         }
-        fprintf(stderr, "%s Group %d (%s) normalized rot. vector: %f %f %f\n", RotStr, g,
-                erotg_names[rotg->eType], vec[0], vec[1], vec[2]);
+        fprintf(stderr,
+                "%s Group %d (%s) normalized rot. vector: %f %f %f\n",
+                RotStr.c_str(),
+                g,
+                enumValueToString(rotg->eType),
+                vec[0],
+                vec[1],
+                vec[2]);
         for (m = 0; m < DIM; m++)
         {
             rotg->inputVec[m] = vec[m];
@@ -142,8 +145,10 @@ extern std::vector<std::string> read_rotparams(std::vector<t_inpfile>* inp, t_ro
         sprintf(buf, "rot-pivot%d", g);
         setStringEntry(inp, buf, s_vec, "0.0 0.0 0.0");
         clear_dvec(vec);
-        if ((rotg->eType == erotgISO) || (rotg->eType == erotgPM) || (rotg->eType == erotgRM)
-            || (rotg->eType == erotgRM2))
+        if ((rotg->eType == EnforcedRotationGroupType::Iso)
+            || (rotg->eType == EnforcedRotationGroupType::Pm)
+            || (rotg->eType == EnforcedRotationGroupType::Rm)
+            || (rotg->eType == EnforcedRotationGroupType::Rm2))
         {
             string2dvec(s_vec, vec);
         }
@@ -188,7 +193,9 @@ extern std::vector<std::string> read_rotparams(std::vector<t_inpfile>* inp, t_ro
                 inp, "Value of additive constant epsilon' (nm^2) for rm2* and flex2* potentials");
         sprintf(buf, "rot-eps%d", g);
         rotg->eps = get_ereal(inp, buf, 1e-4, wi);
-        if ((rotg->eps <= 0.0) && (rotg->eType == erotgRM2 || rotg->eType == erotgFLEX2))
+        if ((rotg->eps <= 0.0)
+            && (rotg->eType == EnforcedRotationGroupType::Rm2
+                || rotg->eType == EnforcedRotationGroupType::Flex2))
         {
             sprintf(warn_buf, "rot-eps%d <= 0", g);
             warning_error(wi, warn_buf);
@@ -198,20 +205,19 @@ extern std::vector<std::string> read_rotparams(std::vector<t_inpfile>* inp, t_ro
                 inp,
                 "Fitting method to determine angle of rotation group (rmsd, norm, or potential)");
         sprintf(buf, "rot-fit-method%d", g);
-        rotg->eFittype = get_eenum(inp, buf, erotg_fitnames);
+        rotg->eFittype = getEnum<RotationGroupFitting>(inp, buf, wi);
         printStringNoNewline(inp,
                              "For fit type 'potential', nr. of angles around the reference for "
                              "which the pot. is evaluated");
         sprintf(buf, "rot-potfit-nsteps%d", g);
         rotg->PotAngle_nstep = get_eint(inp, buf, 21, wi);
-        if ((rotg->eFittype == erotgFitPOT) && (rotg->PotAngle_nstep < 1))
+        if ((rotg->eFittype == RotationGroupFitting::Pot) && (rotg->PotAngle_nstep < 1))
         {
             sprintf(warn_buf, "rot-potfit-nsteps%d < 1", g);
             warning_error(wi, warn_buf);
         }
         printStringNoNewline(
-                inp,
-                "For fit type 'potential', distance in degrees between two consecutive angles");
+                inp, "For fit type 'potential', distance in degrees between two consecutive angles");
         sprintf(buf, "rot-potfit-step%d", g);
         rotg->PotAngle_step = get_ereal(inp, buf, 0.25, wi);
     }
@@ -240,7 +246,7 @@ static void check_box_unchanged(matrix f_box, matrix box, const char fn[], warni
     }
     if (!bSame)
     {
-        sprintf(warn_buf, "%s Box size in reference file %s differs from actual box size!", RotStr, fn);
+        sprintf(warn_buf, "%s Box size in reference file %s differs from actual box size!", RotStr.c_str(), fn);
         warning(wi, warn_buf);
         pr_rvecs(stderr, 0, "Your box is:", box, 3);
         pr_rvecs(stderr, 0, "Box in file:", f_box, 3);
@@ -259,7 +265,7 @@ extern void set_reference_positions(t_rot* rot, rvec* x, matrix box, const char*
     for (g = 0; g < rot->ngrp; g++)
     {
         rotg = &rot->grp[g];
-        fprintf(stderr, "%s group %d has %d reference positions.\n", RotStr, g, rotg->nat);
+        fprintf(stderr, "%s group %d has %d reference positions.\n", RotStr.c_str(), g, rotg->nat);
         snew(rotg->x_ref, rotg->nat);
 
         /* Construct the name for the file containing the reference positions for this group: */
@@ -274,7 +280,9 @@ extern void set_reference_positions(t_rot* rot, rvec* x, matrix box, const char*
             gmx_fatal(FARGS,
                       "%s The file containing the reference positions was not found.\n"
                       "Expected the file '%s' for group %d.\n",
-                      RotStr, reffile, g);
+                      RotStr.c_str(),
+                      reffile,
+                      g);
         }
 
         if (gmx_fexist(reffile))
@@ -286,10 +294,12 @@ extern void set_reference_positions(t_rot* rot, rvec* x, matrix box, const char*
                 gmx_fatal(FARGS,
                           "Number of atoms in file %s (%d) does not match the number of atoms in "
                           "rotation group (%d)!\n",
-                          reffile, header.natoms, rotg->nat);
+                          reffile,
+                          header.natoms,
+                          rotg->nat);
             }
-            gmx_trr_read_single_frame(reffile, &header.step, &header.t, &header.lambda, f_box,
-                                      &header.natoms, rotg->x_ref, nullptr, nullptr);
+            gmx_trr_read_single_frame(
+                    reffile, &header.step, &header.t, &header.lambda, f_box, &header.natoms, rotg->x_ref, nullptr, nullptr);
 
             /* Check whether the box is unchanged and output a warning if not: */
             check_box_unchanged(f_box, box, reffile, wi);
@@ -325,8 +335,7 @@ extern void make_rotation_groups(t_rot*                           rot,
 
         if (rotg->nat > 0)
         {
-            fprintf(stderr, "Rotation group %d '%s' has %d atoms\n", g, rotateGroupNames[g].c_str(),
-                    rotg->nat);
+            fprintf(stderr, "Rotation group %d '%s' has %d atoms\n", g, rotateGroupNames[g].c_str(), rotg->nat);
             snew(rotg->ind, rotg->nat);
             for (i = 0; i < rotg->nat; i++)
             {
index 30a8b5cbb74b0da543dce6005f8c44c46768758a..749630a79e6ba434558f3cac48a2c623fa1be9ec 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstring>
 
 #include <algorithm>
+#include <optional>
 #include <string>
 #include <vector>
 
 #include "gromacs/topology/atoms.h"
 #include "gromacs/topology/symtab.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/logger.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/strdb.h"
+#include "gromacs/utility/stringtoenumvalueconverter.h"
 
 #include "hackblock.h"
 
@@ -112,14 +115,18 @@ static void print_resatoms(FILE* out, const PreprocessingAtomTypes& atype, const
 
     for (int j = 0; (j < rtpDBEntry.natom()); j++)
     {
-        int         tp   = rtpDBEntry.atom[j].type;
-        const char* tpnm = atype.atomNameFromAtomType(tp);
-        if (tpnm == nullptr)
+        int  tp   = rtpDBEntry.atom[j].type;
+        auto tpnm = atype.atomNameFromAtomType(tp);
+        if (!tpnm.has_value())
         {
             gmx_fatal(FARGS, "Incorrect atomtype (%d)", tp);
         }
-        fprintf(out, "%6s  %6s  %8.3f  %6d\n", *(rtpDBEntry.atomname[j]), tpnm,
-                rtpDBEntry.atom[j].q, rtpDBEntry.cgnr[j]);
+        fprintf(out,
+                "%6s  %6s  %8.3f  %6d\n",
+                *(rtpDBEntry.atomname[j]),
+                *tpnm,
+                rtpDBEntry.atom[j].q,
+                rtpDBEntry.cgnr[j]);
     }
 }
 
@@ -143,22 +150,23 @@ static bool read_atoms(FILE* in, char* line, PreprocessResidue* r0, t_symtab* ta
         r0->atom.emplace_back();
         r0->atom.back().q = q;
         r0->cgnr.push_back(cg);
-        int j = atype->atomTypeFromName(buf1);
-        if (j == NOTSET)
+        auto j = atype->atomTypeFromName(buf1);
+        if (!j.has_value())
         {
             gmx_fatal(FARGS,
                       "Atom type %s (residue %s) not found in atomtype "
                       "database",
-                      buf1, r0->resname.c_str());
+                      buf1,
+                      r0->resname.c_str());
         }
-        r0->atom.back().type = j;
-        r0->atom.back().m    = atype->atomMassFromAtomType(j);
+        r0->atom.back().type = *j;
+        r0->atom.back().m    = *atype->atomMassFromAtomType(*j);
     }
 
     return TRUE;
 }
 
-static bool read_bondeds(int bt, FILE* in, char* line, PreprocessResidue* rtpDBEntry)
+static bool read_bondeds(BondedTypes bt, FILE* in, char* line, PreprocessResidue* rtpDBEntry)
 {
     char str[STRLEN];
 
@@ -168,7 +176,7 @@ static bool read_bondeds(int bt, FILE* in, char* line, PreprocessResidue* rtpDBE
         int ni;
         rtpDBEntry->rb[bt].b.emplace_back();
         BondedInteraction* newBond = &rtpDBEntry->rb[bt].b.back();
-        for (int j = 0; j < btsNiatoms[bt]; j++)
+        for (int j = 0; j < enumValueToNumIAtoms(bt); j++)
         {
             if (sscanf(line + n, "%s%n", str, &ni) == 1)
             {
@@ -191,15 +199,15 @@ static bool read_bondeds(int bt, FILE* in, char* line, PreprocessResidue* rtpDBE
     return TRUE;
 }
 
-static void print_resbondeds(FILE* out, int bt, const PreprocessResidue& rtpDBEntry)
+static void print_resbondeds(FILE* out, BondedTypes bt, const PreprocessResidue& rtpDBEntry)
 {
     if (!rtpDBEntry.rb[bt].b.empty())
     {
-        fprintf(out, " [ %s ]\n", btsNames[bt]);
+        fprintf(out, " [ %s ]\n", enumValueToString(bt));
 
         for (const auto& b : rtpDBEntry.rb[bt].b)
         {
-            for (int j = 0; j < btsNiatoms[bt]; j++)
+            for (int j = 0; j < enumValueToNumIAtoms(bt); j++)
             {
                 fprintf(out, "%6s ", b.a[j].c_str());
             }
@@ -229,30 +237,27 @@ static void check_rtp(gmx::ArrayRef<const PreprocessResidue> rtpDBEntry,
     }
 }
 
-static int get_bt(char* header)
+static std::optional<BondedTypes> get_bt(char* header)
 {
-    int i;
-
-    for (i = 0; i < ebtsNR; i++)
-    {
-        if (gmx_strcasecmp(btsNames[i], header) == 0)
-        {
-            return i;
-        }
-    }
-    return NOTSET;
+    gmx::StringToEnumValueConverter<BondedTypes, enumValueToString> converter;
+    return converter.valueFrom(header);
 }
 
-/* print all the ebtsNR type numbers */
+/* print all the BondedTypes type numbers */
 static void print_resall_header(FILE* out, gmx::ArrayRef<const PreprocessResidue> rtpDBEntry)
 {
     fprintf(out, "[ bondedtypes ]\n");
     fprintf(out,
             "; bonds  angles  dihedrals  impropers all_dihedrals nr_exclusions  HH14  "
             "remove_dih\n");
-    fprintf(out, " %5d  %6d  %9d  %9d  %14d  %14d %14d %14d\n\n", rtpDBEntry[0].rb[0].type,
-            rtpDBEntry[0].rb[1].type, rtpDBEntry[0].rb[2].type, rtpDBEntry[0].rb[3].type,
-            static_cast<int>(rtpDBEntry[0].bKeepAllGeneratedDihedrals), rtpDBEntry[0].nrexcl,
+    fprintf(out,
+            " %5d  %6d  %9d  %9d  %14d  %14d %14d %14d\n\n",
+            rtpDBEntry[0].rb[0].type,
+            rtpDBEntry[0].rb[1].type,
+            rtpDBEntry[0].rb[2].type,
+            rtpDBEntry[0].rb[3].type,
+            static_cast<int>(rtpDBEntry[0].bKeepAllGeneratedDihedrals),
+            rtpDBEntry[0].nrexcl,
             static_cast<int>(rtpDBEntry[0].bGenerateHH14Interactions),
             static_cast<int>(rtpDBEntry[0].bRemoveDihedralIfWithImproper));
 }
@@ -268,12 +273,15 @@ static void print_resall_log(const gmx::MDLogger& logger, gmx::ArrayRef<const Pr
                     "remove_dih");
     GMX_LOG(logger.info)
             .asParagraph()
-            .appendTextFormatted(
-                    " %5d  %6d  %9d  %9d  %14d  %14d %14d %14d", rtpDBEntry[0].rb[0].type,
-                    rtpDBEntry[0].rb[1].type, rtpDBEntry[0].rb[2].type, rtpDBEntry[0].rb[3].type,
-                    static_cast<int>(rtpDBEntry[0].bKeepAllGeneratedDihedrals),
-                    rtpDBEntry[0].nrexcl, static_cast<int>(rtpDBEntry[0].bGenerateHH14Interactions),
-                    static_cast<int>(rtpDBEntry[0].bRemoveDihedralIfWithImproper));
+            .appendTextFormatted(" %5d  %6d  %9d  %9d  %14d  %14d %14d %14d",
+                                 rtpDBEntry[0].rb[0].type,
+                                 rtpDBEntry[0].rb[1].type,
+                                 rtpDBEntry[0].rb[2].type,
+                                 rtpDBEntry[0].rb[3].type,
+                                 static_cast<int>(rtpDBEntry[0].bKeepAllGeneratedDihedrals),
+                                 rtpDBEntry[0].nrexcl,
+                                 static_cast<int>(rtpDBEntry[0].bGenerateHH14Interactions),
+                                 static_cast<int>(rtpDBEntry[0].bRemoveDihedralIfWithImproper));
 }
 
 
@@ -291,7 +299,7 @@ void print_resall(FILE* out, gmx::ArrayRef<const PreprocessResidue> rtpDBEntry,
         if (r.natom() > 0)
         {
             print_resatoms(out, atype, r);
-            for (int bt = 0; bt < ebtsNR; bt++)
+            for (auto bt : gmx::EnumerationWrapper<BondedTypes>{})
             {
                 print_resbondeds(out, bt, r);
             }
@@ -308,7 +316,7 @@ void readResidueDatabase(const std::string&              rrdb,
 {
     FILE* in;
     char  filebase[STRLEN], line[STRLEN], header[STRLEN];
-    int   bt, nparam;
+    int   nparam;
     int   dum1, dum2, dum3;
     bool  bNextResidue, bError;
 
@@ -320,12 +328,12 @@ void readResidueDatabase(const std::string&              rrdb,
 
     /* these bonded parameters will overwritten be when  *
      * there is a [ bondedtypes ] entry in the .rtp file */
-    header_settings.rb[ebtsBONDS].type  = 1; /* normal bonds     */
-    header_settings.rb[ebtsANGLES].type = 1; /* normal angles    */
-    header_settings.rb[ebtsPDIHS].type  = 1; /* normal dihedrals */
-    header_settings.rb[ebtsIDIHS].type  = 2; /* normal impropers */
-    header_settings.rb[ebtsEXCLS].type  = 1; /* normal exclusions */
-    header_settings.rb[ebtsCMAP].type   = 1; /* normal cmap torsions */
+    header_settings.rb[BondedTypes::Bonds].type             = 1; /* normal bonds     */
+    header_settings.rb[BondedTypes::Angles].type            = 1; /* normal angles    */
+    header_settings.rb[BondedTypes::ProperDihedrals].type   = 1; /* normal dihedrals */
+    header_settings.rb[BondedTypes::ImproperDihedrals].type = 2; /* normal impropers */
+    header_settings.rb[BondedTypes::Exclusions].type        = 1; /* normal exclusions */
+    header_settings.rb[BondedTypes::Cmap].type              = 1; /* normal cmap torsions */
 
     header_settings.bKeepAllGeneratedDihedrals    = FALSE;
     header_settings.nrexcl                        = 3;
@@ -357,14 +365,22 @@ void readResidueDatabase(const std::string&              rrdb,
     if (gmx::equalCaseInsensitive("bondedtypes", header, 5))
     {
         get_a_line(in, line, STRLEN);
-        if ((nparam = sscanf(line, "%d %d %d %d %d %d %d %d", &header_settings.rb[ebtsBONDS].type,
-                             &header_settings.rb[ebtsANGLES].type,
-                             &header_settings.rb[ebtsPDIHS].type, &header_settings.rb[ebtsIDIHS].type,
-                             &dum1, &header_settings.nrexcl, &dum2, &dum3))
+        if ((nparam = sscanf(line,
+                             "%d %d %d %d %d %d %d %d",
+                             &header_settings.rb[BondedTypes::Bonds].type,
+                             &header_settings.rb[BondedTypes::Angles].type,
+                             &header_settings.rb[BondedTypes::ProperDihedrals].type,
+                             &header_settings.rb[BondedTypes::ImproperDihedrals].type,
+                             &dum1,
+                             &header_settings.nrexcl,
+                             &dum2,
+                             &dum3))
             < 4)
         {
-            gmx_fatal(FARGS, "need 4 to 8 parameters in the header of .rtp file %s at line:\n%s\n",
-                      rrdb.c_str(), line);
+            gmx_fatal(FARGS,
+                      "need 4 to 8 parameters in the header of .rtp file %s at line:\n%s\n",
+                      rrdb.c_str(),
+                      line);
         }
         header_settings.bKeepAllGeneratedDihedrals    = (dum1 != 0);
         header_settings.bGenerateHH14Interactions     = (dum2 != 0);
@@ -435,11 +451,11 @@ void readResidueDatabase(const std::string&              rrdb,
             }
             else
             {
-                bt = get_bt(header);
-                if (bt != NOTSET)
+                auto bt = get_bt(header);
+                if (bt.has_value())
                 {
                     /* header is an bonded directive */
-                    bError = !read_bondeds(bt, in, line, res);
+                    bError = !read_bondeds(*bt, in, line, res);
                 }
                 else if (gmx::equalCaseInsensitive("atoms", header, 5))
                 {
@@ -463,17 +479,16 @@ void readResidueDatabase(const std::string&              rrdb,
             gmx_fatal(FARGS, "No atoms found in .rtp file in residue %s\n", res->resname.c_str());
         }
 
-        auto found = std::find_if(rtpDBEntry->begin(), rtpDBEntry->end() - 1,
-                                  [&res](const PreprocessResidue& entry) {
-                                      return gmx::equalCaseInsensitive(entry.resname, res->resname);
-                                  });
+        auto found = std::find_if(
+                rtpDBEntry->begin(), rtpDBEntry->end() - 1, [&res](const PreprocessResidue& entry) {
+                    return gmx::equalCaseInsensitive(entry.resname, res->resname);
+                });
 
         if (found != rtpDBEntry->end() - 1)
         {
             if (found >= oldArrayEnd)
             {
-                gmx_fatal(FARGS, "Found a second entry for '%s' in '%s'", res->resname.c_str(),
-                          rrdb.c_str());
+                gmx_fatal(FARGS, "Found a second entry for '%s' in '%s'", res->resname.c_str(), rrdb.c_str());
             }
             if (bAllowOverrideRTP)
             {
@@ -482,7 +497,9 @@ void readResidueDatabase(const std::string&              rrdb,
                         .appendTextFormatted(
                                 "Found another rtp entry for '%s' in '%s',"
                                 " ignoring this entry and keeping the one from '%s.rtp'",
-                                res->resname.c_str(), rrdb.c_str(), found->filebase.c_str());
+                                res->resname.c_str(),
+                                rrdb.c_str(),
+                                found->filebase.c_str());
                 /* We should free all the data for this entry.
                  * The current code gives a lot of dangling pointers.
                  */
@@ -493,7 +510,9 @@ void readResidueDatabase(const std::string&              rrdb,
                 gmx_fatal(FARGS,
                           "Found rtp entries for '%s' in both '%s' and '%s'. If you want the first "
                           "definition to override the second one, set the -rtpo option of pdb2gmx.",
-                          res->resname.c_str(), found->filebase.c_str(), rrdb.c_str());
+                          res->resname.c_str(),
+                          found->filebase.c_str(),
+                          rrdb.c_str());
             }
         }
     }
@@ -501,7 +520,10 @@ void readResidueDatabase(const std::string&              rrdb,
 
     std::sort(rtpDBEntry->begin(), rtpDBEntry->end(), [](const PreprocessResidue& a, const PreprocessResidue& b) {
         return std::lexicographical_compare(
-                a.resname.begin(), a.resname.end(), b.resname.begin(), b.resname.end(),
+                a.resname.begin(),
+                a.resname.end(),
+                b.resname.begin(),
+                b.resname.end(),
                 [](const char& c1, const char& c2) { return std::toupper(c1) < std::toupper(c2); });
     });
 
@@ -589,8 +611,10 @@ std::string searchResidueDatabase(const std::string&                     key,
     }
     if (nbest > 1)
     {
-        gmx_fatal(FARGS, "Residue '%s' not found in residue topology database, looks a bit like %s",
-                  key.c_str(), bestbuf.c_str());
+        gmx_fatal(FARGS,
+                  "Residue '%s' not found in residue topology database, looks a bit like %s",
+                  key.c_str(),
+                  bestbuf.c_str());
     }
     else if (besti == -1)
     {
@@ -603,7 +627,8 @@ std::string searchResidueDatabase(const std::string&                     key,
                 .appendTextFormatted(
                         "'%s' not found in residue topology database, "
                         "trying to use '%s'",
-                        key.c_str(), rtpDBEntry[besti].resname.c_str());
+                        key.c_str(),
+                        rtpDBEntry[besti].resname.c_str());
     }
 
     return rtpDBEntry[besti].resname;
@@ -612,10 +637,10 @@ std::string searchResidueDatabase(const std::string&                     key,
 gmx::ArrayRef<const PreprocessResidue>::const_iterator
 getDatabaseEntry(const std::string& rtpname, gmx::ArrayRef<const PreprocessResidue> rtpDBEntry)
 {
-    auto found = std::find_if(rtpDBEntry.begin(), rtpDBEntry.end(),
-                              [&rtpname](const PreprocessResidue& entry) {
-                                  return gmx::equalCaseInsensitive(rtpname, entry.resname);
-                              });
+    auto found = std::find_if(
+            rtpDBEntry.begin(), rtpDBEntry.end(), [&rtpname](const PreprocessResidue& entry) {
+                return gmx::equalCaseInsensitive(rtpname, entry.resname);
+            });
     if (found == rtpDBEntry.end())
     {
         /* This should never happen, since searchResidueDatabase should have been called
index 054d5b223ac1f3dff596ecd101c6de159c960903..b0a9c09a57a4f70a0692ca148fc6de4431f5c2da 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -109,8 +109,8 @@ static void sort_molecule(t_atoms** atoms_solvt, t_atoms** newatoms, std::vector
                 {
                     numAtomsInMolType++;
                 }
-                molTypes.emplace_back(MoleculeType{ *atoms->resinfo[atoms->atom[i].resind].name,
-                                                    numAtomsInMolType, 1 });
+                molTypes.emplace_back(MoleculeType{
+                        *atoms->resinfo[atoms->atom[i].resind].name, numAtomsInMolType, 1 });
             }
             else
             {
@@ -119,12 +119,14 @@ static void sort_molecule(t_atoms** atoms_solvt, t_atoms** newatoms, std::vector
         }
     }
 
-    fprintf(stderr, "Found %zu%s molecule type%s:\n", molTypes.size(),
-            molTypes.size() == 1 ? "" : " different", molTypes.size() == 1 ? "" : "s");
+    fprintf(stderr,
+            "Found %zu%s molecule type%s:\n",
+            molTypes.size(),
+            molTypes.size() == 1 ? "" : " different",
+            molTypes.size() == 1 ? "" : "s");
     for (const auto& molType : molTypes)
     {
-        fprintf(stderr, "%7s (%4d atoms): %5d residues\n", molType.name.c_str(), molType.numAtoms,
-                molType.numMolecules);
+        fprintf(stderr, "%7s (%4d atoms): %5d residues\n", molType.name.c_str(), molType.numAtoms, molType.numMolecules);
     }
 
     /* if we have only 1 moleculetype, we don't have to sort */
@@ -277,8 +279,7 @@ static void replicateSolventBox(t_atoms*           atoms,
         }
         nmol *= n_box[i];
     }
-    fprintf(stderr, "Will generate new solvent configuration of %dx%dx%d boxes\n", n_box[XX],
-            n_box[YY], n_box[ZZ]);
+    fprintf(stderr, "Will generate new solvent configuration of %dx%dx%d boxes\n", n_box[XX], n_box[YY], n_box[ZZ]);
 
     // Create arrays for storing the generated system (cannot be done in-place
     // in case the target box is smaller than the original in one dimension,
@@ -460,8 +461,7 @@ static void removeSolventBoxOverlap(t_atoms*           atoms,
     remover.removeMarkedElements(r);
     const int originalAtomCount = atoms->nr;
     remover.removeMarkedAtoms(atoms);
-    fprintf(stderr, "Removed %d solvent atoms due to solvent-solvent overlap\n",
-            originalAtomCount - atoms->nr);
+    fprintf(stderr, "Removed %d solvent atoms due to solvent-solvent overlap\n", originalAtomCount - atoms->nr);
 }
 
 /*! \brief
@@ -508,8 +508,10 @@ static void removeSolventOutsideShell(t_atoms*                 atoms,
     remover.removeMarkedElements(r);
     const int originalAtomCount = atoms->nr;
     remover.removeMarkedAtoms(atoms);
-    fprintf(stderr, "Removed %d solvent atoms more than %f nm from solute.\n",
-            originalAtomCount - atoms->nr, rshell);
+    fprintf(stderr,
+            "Removed %d solvent atoms more than %f nm from solute.\n",
+            originalAtomCount - atoms->nr,
+            rshell);
 }
 
 /*! \brief
@@ -564,8 +566,7 @@ static void removeSolventOverlappingWithSolute(t_atoms*                 atoms,
     remover.removeMarkedElements(r);
     const int originalAtomCount = atoms->nr;
     remover.removeMarkedAtoms(atoms);
-    fprintf(stderr, "Removed %d solvent atoms due to solute-solvent overlap\n",
-            originalAtomCount - atoms->nr);
+    fprintf(stderr, "Removed %d solvent atoms due to solute-solvent overlap\n", originalAtomCount - atoms->nr);
 }
 
 /*! \brief
@@ -624,11 +625,16 @@ static void add_solv(const char*        filename,
     fprintf(stderr, "Reading solvent configuration\n");
     bool  bTprFileWasRead;
     rvec *temporaryX = nullptr, *temporaryV = nullptr;
-    readConfAndTopology(gmx::findLibraryFile(filename).c_str(), &bTprFileWasRead, &topSolvent,
-                        &pbcTypeSolvent, &temporaryX, &temporaryV, boxSolvent);
+    readConfAndTopology(gmx::findLibraryFile(filename).c_str(),
+                        &bTprFileWasRead,
+                        &topSolvent,
+                        &pbcTypeSolvent,
+                        &temporaryX,
+                        &temporaryV,
+                        boxSolvent);
     t_atoms* atomsSolvent;
     snew(atomsSolvent, 1);
-    *atomsSolvent = gmx_mtop_global_atoms(&topSolvent);
+    *atomsSolvent = gmx_mtop_global_atoms(topSolvent);
     xSolvent.assign(temporaryX, temporaryX + topSolvent.natoms);
     sfree(temporaryX);
     vSolvent.assign(temporaryV, temporaryV + topSolvent.natoms);
@@ -676,11 +682,11 @@ static void add_solv(const char*        filename,
     {
         if (rshell > 0.0)
         {
-            removeSolventOutsideShell(atomsSolvent, &xSolvent, &vSolvent, &exclusionDistances_solvt,
-                                      pbc, *x, rshell);
+            removeSolventOutsideShell(
+                    atomsSolvent, &xSolvent, &vSolvent, &exclusionDistances_solvt, pbc, *x, rshell);
         }
-        removeSolventOverlappingWithSolute(atomsSolvent, &xSolvent, &vSolvent,
-                                           &exclusionDistances_solvt, pbc, *x, exclusionDistances);
+        removeSolventOverlappingWithSolute(
+                atomsSolvent, &xSolvent, &vSolvent, &exclusionDistances_solvt, pbc, *x, exclusionDistances);
     }
 
     if (max_sol > 0 && atomsSolvent->nres > max_sol)
@@ -708,7 +714,9 @@ static void add_solv(const char*        filename,
         gmx::AtomsBuilder builder(atoms, symtab);
         builder.mergeAtoms(*sortedAtomsSolvent);
     }
-    fprintf(stderr, "Generated solvent containing %d atoms in %d residues\n", atomsSolvent->nr,
+    fprintf(stderr,
+            "Generated solvent containing %d atoms in %d residues\n",
+            atomsSolvent->nr,
             atomsSolvent->nres);
 
     if (newatoms)
@@ -744,15 +752,17 @@ static void update_top(t_atoms*        atoms,
     mtot = 0;
     for (i = 0; (i < atoms->nr); i++)
     {
-        aps->setAtomProperty(epropMass, std::string(*atoms->resinfo[atoms->atom[i].resind].name),
-                             std::string(*atoms->atomname[i]), &mm);
+        aps->setAtomProperty(epropMass,
+                             std::string(*atoms->resinfo[atoms->atom[i].resind].name),
+                             std::string(*atoms->atomname[i]),
+                             &mm);
         mtot += mm;
     }
 
     vol = det(box);
 
     fprintf(stderr, "Volume                 :  %10g (nm^3)\n", vol);
-    fprintf(stderr, "Density                :  %10g (g/l)\n", (mtot * 1e24) / (AVOGADRO * vol));
+    fprintf(stderr, "Density                :  %10g (g/l)\n", (mtot * 1e24) / (gmx::c_avogadro * vol));
     fprintf(stderr, "Number of solvent molecules:  %5d   \n\n", nsol);
 
     /* open topology file and append sol molecules */
@@ -825,7 +835,9 @@ static void update_top(t_atoms*        atoms,
                     fprintf(stdout,
                             "Adding line for %d solvent molecules with resname (%s) to "
                             "topology file (%s)\n",
-                            resCount, currRes.c_str(), topinout);
+                            resCount,
+                            currRes.c_str(),
+                            topinout);
                     fprintf(fpout, "%-15s %5d\n", currRes.c_str(), resCount);
                     currRes  = *atoms->resinfo[i].name;
                     resCount = 1;
@@ -835,7 +847,9 @@ static void update_top(t_atoms*        atoms,
             fprintf(stdout,
                     "Adding line for %d solvent molecules with resname (%s) to "
                     "topology file (%s)\n",
-                    resCount, currRes.c_str(), topinout);
+                    resCount,
+                    currRes.c_str(),
+                    topinout);
             fprintf(fpout, "%-15s %5d\n", currRes.c_str(), resCount);
         }
         gmx_ffclose(fpout);
@@ -941,8 +955,8 @@ int gmx_solvate(int argc, char* argv[])
         { "-vel", FALSE, etBOOL, { &bReadV }, "Keep velocities from input solute and solvent" },
     };
 
-    if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc,
-                           asize(bugs), bugs, &oenv))
+    if (!parse_common_args(
+                &argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
         return 0;
     }
@@ -975,9 +989,9 @@ int gmx_solvate(int argc, char* argv[])
         fprintf(stderr, "Reading solute configuration%s\n", bReadV ? " and velocities" : "");
         bool  bTprFileWasRead;
         rvec *temporaryX = nullptr, *temporaryV = nullptr;
-        readConfAndTopology(conf_prot, &bTprFileWasRead, &top, &pbcType, &temporaryX,
-                            bReadV ? &temporaryV : nullptr, box);
-        *atoms = gmx_mtop_global_atoms(&top);
+        readConfAndTopology(
+                conf_prot, &bTprFileWasRead, &top, &pbcType, &temporaryX, bReadV ? &temporaryV : nullptr, box);
+        *atoms = gmx_mtop_global_atoms(top);
         x.assign(temporaryX, temporaryX + top.natoms);
         sfree(temporaryX);
         if (temporaryV)
@@ -1015,15 +1029,19 @@ int gmx_solvate(int argc, char* argv[])
                   "or give explicit -box command line option");
     }
 
-    add_solv(solventFileName, atoms, &top.symtab, &x, &v, pbcTypeForOutput, box, &aps,
-             defaultDistance, scaleFactor, r_shell, max_sol);
+    add_solv(solventFileName, atoms, &top.symtab, &x, &v, pbcTypeForOutput, box, &aps, defaultDistance, scaleFactor, r_shell, max_sol);
 
     /* write new configuration 1 to file confout */
     confout = ftp2fn(efSTO, NFILE, fnm);
     fprintf(stderr, "Writing generated configuration to %s\n", confout);
     const char* outputTitle = (bProt ? *top.name : "Generated by gmx solvate");
-    write_sto_conf(confout, outputTitle, atoms, as_rvec_array(x.data()),
-                   !v.empty() ? as_rvec_array(v.data()) : nullptr, pbcTypeForOutput, box);
+    write_sto_conf(confout,
+                   outputTitle,
+                   atoms,
+                   as_rvec_array(x.data()),
+                   !v.empty() ? as_rvec_array(v.data()) : nullptr,
+                   pbcTypeForOutput,
+                   box);
 
     /* print size of generated configuration */
     fprintf(stderr, "\nOutput configuration contains %d atoms in %d residues\n", atoms->nr, atoms->nres);
index 5e30f10c28b57b2f4726e2f7a6c7db511177b258..f9e3c7750ff8815915ef3c0e288da4dae5b09557 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +88,7 @@ std::vector<SpecialBond> generateSpecialBonds()
     int nlines = get_lines(sbfile, &lines);
     for (int i = 0; (i < nlines); i++)
     {
-        if (sscanf(lines[i], "%s%s%d%s%s%d%lf%s%s", r1buf, a1buf, &nb1, r2buf, a2buf, &nb2, &length,
-                   nr1buf, nr2buf)
+        if (sscanf(lines[i], "%s%s%d%s%s%d%lf%s%s", r1buf, a1buf, &nb1, r2buf, a2buf, &nb2, &length, nr1buf, nr2buf)
             != 9)
         {
             fprintf(stderr, "Invalid line '%s' in %s\n", lines[i], sbfile);
@@ -115,25 +114,19 @@ std::vector<SpecialBond> generateSpecialBonds()
     {
         sfree(lines);
     }
-    fprintf(stderr, "%zu out of %d lines of %s converted successfully\n", specialBonds.size(),
-            nlines, sbfile);
+    fprintf(stderr, "%zu out of %d lines of %s converted successfully\n", specialBonds.size(), nlines, sbfile);
 
     return specialBonds;
 }
 
 static bool is_special(gmx::ArrayRef<const SpecialBond> sb, const char* res, const char* atom)
 {
-    for (const auto& bond : sb)
-    {
-        if (((strncmp(bond.firstResidue.c_str(), res, 3) == 0)
-             && (gmx::equalCaseInsensitive(bond.firstAtomName, atom)))
-            || ((strncmp(bond.secondResidue.c_str(), res, 3) == 0)
-                && (gmx::equalCaseInsensitive(bond.secondAtomName, atom))))
-        {
-            return TRUE;
-        }
-    }
-    return FALSE;
+    return std::any_of(sb.begin(), sb.end(), [res, atom](const auto& bond) {
+        return (((strncmp(bond.firstResidue.c_str(), res, 3) == 0)
+                 && (gmx::equalCaseInsensitive(bond.firstAtomName, atom)))
+                || ((strncmp(bond.secondResidue.c_str(), res, 3) == 0)
+                    && (gmx::equalCaseInsensitive(bond.secondAtomName, atom))));
+    });
 }
 
 static bool is_bond(gmx::ArrayRef<const SpecialBond> sb, t_atoms* pdba, int a1, int a2, real d, int* index_sb, bool* bSwap)
@@ -178,7 +171,9 @@ static void rename_1res(t_atoms* pdba, int resind, const char* newres, bool bVer
 {
     if (bVerbose)
     {
-        printf("Using rtp entry %s for %s %d\n", newres, *pdba->resinfo[resind].name,
+        printf("Using rtp entry %s for %s %d\n",
+               newres,
+               *pdba->resinfo[resind].name,
                pdba->resinfo[resind].nr);
     }
     /* this used to free *resname, which messes up the symtab! */
@@ -242,7 +237,9 @@ std::vector<DisulfideBond> makeDisulfideBonds(t_atoms* pdba, rvec x[], bool bInt
                 int e = std::min(b + MAXCOL, nspec - 1);
                 for (int i = b; (i < e); i++)
                 {
-                    sprintf(buf, "%s%d", *pdba->resinfo[pdba->atom[specialBondAtomIdxs[i]].resind].name,
+                    sprintf(buf,
+                            "%s%d",
+                            *pdba->resinfo[pdba->atom[specialBondAtomIdxs[i]].resind].name,
                             pdba->resinfo[specialBondResIdxs[i]].nr);
                     fprintf(stderr, "%8s", buf);
                 }
@@ -252,8 +249,8 @@ std::vector<DisulfideBond> makeDisulfideBonds(t_atoms* pdba, rvec x[], bool bInt
                 e = std::min(b + MAXCOL, nspec - 1);
                 for (int i = b; (i < e); i++)
                 {
-                    std::string buf = gmx::formatString("%s%d", *pdba->atomname[specialBondAtomIdxs[i]],
-                                                        specialBondAtomIdxs[i] + 1);
+                    std::string buf = gmx::formatString(
+                            "%s%d", *pdba->atomname[specialBondAtomIdxs[i]], specialBondAtomIdxs[i] + 1);
                     fprintf(stderr, "%8s", buf.c_str());
                 }
                 fprintf(stderr, "\n");
@@ -262,11 +259,12 @@ std::vector<DisulfideBond> makeDisulfideBonds(t_atoms* pdba, rvec x[], bool bInt
                 for (int i = b + 1; (i < nspec); i++)
                 {
                     std::string buf = gmx::formatString(
-                            "%s%d", *pdba->resinfo[pdba->atom[specialBondAtomIdxs[i]].resind].name,
+                            "%s%d",
+                            *pdba->resinfo[pdba->atom[specialBondAtomIdxs[i]].resind].name,
                             pdba->resinfo[specialBondResIdxs[i]].nr);
                     fprintf(stderr, "%8s", buf.c_str());
-                    buf = gmx::formatString("%s%d", *pdba->atomname[specialBondAtomIdxs[i]],
-                                            specialBondAtomIdxs[i] + 1);
+                    buf = gmx::formatString(
+                            "%s%d", *pdba->atomname[specialBondAtomIdxs[i]], specialBondAtomIdxs[i] + 1);
                     fprintf(stderr, "%8s", buf.c_str());
                     int e2 = std::min(i, e);
                     for (int j = b; (j < e2); j++)
@@ -288,11 +286,17 @@ std::vector<DisulfideBond> makeDisulfideBonds(t_atoms* pdba, rvec x[], bool bInt
                 if (bonds.size() < specialBondAtomIdxs.size()
                     && is_bond(specialBonds, pdba, ai, aj, d[i][j], &index_sb, &bSwap))
                 {
-                    fprintf(stderr, "%s %s-%d %s-%d and %s-%d %s-%d%s", bInteractive ? "Link" : "Linking",
+                    fprintf(stderr,
+                            "%s %s-%d %s-%d and %s-%d %s-%d%s",
+                            bInteractive ? "Link" : "Linking",
                             *pdba->resinfo[pdba->atom[ai].resind].name,
-                            pdba->resinfo[specialBondResIdxs[i]].nr, *pdba->atomname[ai], ai + 1,
+                            pdba->resinfo[specialBondResIdxs[i]].nr,
+                            *pdba->atomname[ai],
+                            ai + 1,
                             *pdba->resinfo[pdba->atom[aj].resind].name,
-                            pdba->resinfo[specialBondResIdxs[j]].nr, *pdba->atomname[aj], aj + 1,
+                            pdba->resinfo[specialBondResIdxs[j]].nr,
+                            *pdba->atomname[aj],
+                            aj + 1,
                             bInteractive ? " (y/n) ?" : "...\n");
                     bool bDoit = bInteractive ? yesno() : true;
 
@@ -308,17 +312,25 @@ std::vector<DisulfideBond> makeDisulfideBonds(t_atoms* pdba, rvec x[], bool bInt
                         /* rename residues */
                         if (bSwap)
                         {
-                            rename_1res(pdba, specialBondResIdxs[i],
-                                        specialBonds[index_sb].newSecondResidue.c_str(), bVerbose);
-                            rename_1res(pdba, specialBondResIdxs[j],
-                                        specialBonds[index_sb].newFirstResidue.c_str(), bVerbose);
+                            rename_1res(pdba,
+                                        specialBondResIdxs[i],
+                                        specialBonds[index_sb].newSecondResidue.c_str(),
+                                        bVerbose);
+                            rename_1res(pdba,
+                                        specialBondResIdxs[j],
+                                        specialBonds[index_sb].newFirstResidue.c_str(),
+                                        bVerbose);
                         }
                         else
                         {
-                            rename_1res(pdba, specialBondResIdxs[i],
-                                        specialBonds[index_sb].newFirstResidue.c_str(), bVerbose);
-                            rename_1res(pdba, specialBondResIdxs[j],
-                                        specialBonds[index_sb].newSecondResidue.c_str(), bVerbose);
+                            rename_1res(pdba,
+                                        specialBondResIdxs[i],
+                                        specialBonds[index_sb].newFirstResidue.c_str(),
+                                        bVerbose);
+                            rename_1res(pdba,
+                                        specialBondResIdxs[j],
+                                        specialBonds[index_sb].newSecondResidue.c_str(),
+                                        bVerbose);
                         }
                     }
                 }
index bdf1f3db8e57f7fc20713895356e9faa4eb896a9..2329cd324a20e59d1c388233071d0408add156ef 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "ter_db.h"
 
+#include <array>
 #include <cctype>
 #include <cstring>
 
 #include <algorithm>
+#include <optional>
 #include <string>
 #include <vector>
 
 #include "gromacs/gmxpreprocess/notset.h"
 #include "gromacs/gmxpreprocess/toputil.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/strdb.h"
+#include "gromacs/utility/stringtoenumvalueconverter.h"
 
 #include "hackblock.h"
 #include "resall.h"
 
 /* use bonded types definitions in hackblock.h */
-#define ekwRepl (ebtsNR + 1)
-#define ekwAdd (ebtsNR + 2)
-#define ekwDel (ebtsNR + 3)
-#define ekwNR 3
-static const char* kw_names[ekwNR] = { "replace", "add", "delete" };
-
-static int find_kw(char* keyw)
+enum class ReplaceType : int
 {
-    int i;
+    Repl,
+    Add,
+    Del,
+    Count
+};
 
-    for (i = 0; i < ebtsNR; i++)
-    {
-        if (gmx_strcasecmp(btsNames[i], keyw) == 0)
-        {
-            return i;
-        }
-    }
-    for (i = 0; i < ekwNR; i++)
-    {
-        if (gmx_strcasecmp(kw_names[i], keyw) == 0)
-        {
-            return ebtsNR + 1 + i;
-        }
-    }
+static const char* enumValueToString(ReplaceType enumValue)
+{
+    constexpr gmx::EnumerationArray<ReplaceType, const char*> replaceTypeNames = { "replace",
+                                                                                   "add",
+                                                                                   "delete" };
+    return replaceTypeNames[enumValue];
+}
 
-    return NOTSET;
+template<typename EnumType>
+static std::optional<EnumType> findTypeFromKeyword(char* keyw)
+{
+    gmx::StringToEnumValueConverter<EnumType, enumValueToString, gmx::StringCompareType::CaseInsensitive, gmx::StripStrings::Yes> converter;
+    return converter.valueFrom(keyw);
 }
 
 #define FATAL() gmx_fatal(FARGS, "Reading Termini Database: not enough items on line\n%s", line)
@@ -120,7 +119,10 @@ static void read_atom(char* line, bool bAdd, std::string* nname, t_atom* a, Prep
         gmx_fatal(FARGS,
                   "Reading Termini Database: expected %d or %d items of atom data in stead of %d "
                   "on line\n%s",
-                  3, 4, nr, line);
+                  3,
+                  4,
+                  nr,
+                  line);
     }
     i = 0;
     if (!bAdd)
@@ -134,7 +136,7 @@ static void read_atom(char* line, bool bAdd, std::string* nname, t_atom* a, Prep
             *nname = "";
         }
     }
-    a->type = atype->atomTypeFromName(buf[i++]);
+    a->type = *atype->atomTypeFromName(buf[i++]);
     sscanf(buf[i++], "%lf", &m);
     a->m = m;
     sscanf(buf[i++], "%lf", &q);
@@ -151,7 +153,7 @@ static void read_atom(char* line, bool bAdd, std::string* nname, t_atom* a, Prep
 
 static void print_atom(FILE* out, const t_atom& a, PreprocessingAtomTypes* atype)
 {
-    fprintf(out, "\t%s\t%g\t%g\n", atype->atomNameFromAtomType(a.type), a.m, a.q);
+    fprintf(out, "\t%s\t%g\t%g\n", *atype->atomNameFromAtomType(a.type), a.m, a.q);
 }
 
 static void print_ter_db(const char*                                ff,
@@ -166,10 +168,11 @@ static void print_ter_db(const char*                                ff,
     {
         fprintf(out, "[ %s ]\n", modification.name.c_str());
 
-        if (std::any_of(modification.hack.begin(), modification.hack.end(),
-                        [](const auto& mod) { return mod.type() == MoleculePatchType::Replace; }))
+        if (std::any_of(modification.hack.begin(), modification.hack.end(), [](const auto& mod) {
+                return mod.type() == MoleculePatchType::Replace;
+            }))
         {
-            fprintf(out, "[ %s ]\n", kw_names[ekwRepl - ebtsNR - 1]);
+            fprintf(out, "[ %s ]\n", enumValueToString(ReplaceType::Repl));
             for (const auto& hack : modification.hack)
             {
                 if (hack.type() == MoleculePatchType::Replace)
@@ -179,10 +182,11 @@ static void print_ter_db(const char*                                ff,
                 }
             }
         }
-        if (std::any_of(modification.hack.begin(), modification.hack.end(),
-                        [](const auto& mod) { return mod.type() == MoleculePatchType::Add; }))
+        if (std::any_of(modification.hack.begin(), modification.hack.end(), [](const auto& mod) {
+                return mod.type() == MoleculePatchType::Add;
+            }))
         {
-            fprintf(out, "[ %s ]\n", kw_names[ekwAdd - ebtsNR - 1]);
+            fprintf(out, "[ %s ]\n", enumValueToString(ReplaceType::Add));
             for (const auto& hack : modification.hack)
             {
                 if (hack.type() == MoleculePatchType::Add)
@@ -192,10 +196,11 @@ static void print_ter_db(const char*                                ff,
                 }
             }
         }
-        if (std::any_of(modification.hack.begin(), modification.hack.end(),
-                        [](const auto& mod) { return mod.type() == MoleculePatchType::Delete; }))
+        if (std::any_of(modification.hack.begin(), modification.hack.end(), [](const auto& mod) {
+                return mod.type() == MoleculePatchType::Delete;
+            }))
         {
-            fprintf(out, "[ %s ]\n", kw_names[ekwDel - ebtsNR - 1]);
+            fprintf(out, "[ %s ]\n", enumValueToString(ReplaceType::Del));
             for (const auto& hack : modification.hack)
             {
                 if (hack.type() == MoleculePatchType::Delete)
@@ -204,14 +209,14 @@ static void print_ter_db(const char*                                ff,
                 }
             }
         }
-        for (int bt = 0; bt < ebtsNR; bt++)
+        for (auto bt : gmx::EnumerationWrapper<BondedTypes>{})
         {
             if (!modification.rb[bt].b.empty())
             {
-                fprintf(out, "[ %s ]\n", btsNames[bt]);
+                fprintf(out, "[ %s ]\n", enumValueToString(bt));
                 for (const auto& b : modification.rb[bt].b)
                 {
-                    for (int k = 0; k < btsNiatoms[bt]; k++)
+                    for (int k = 0; k < enumValueToNumIAtoms(bt); k++)
                     {
                         fprintf(out, "%s%s", k ? "\t" : "", b.a[k].c_str());
                     }
@@ -245,7 +250,8 @@ static void read_ter_db_file(const char*                         fn,
 
     FILE* in = fflib_open(fn);
 
-    int kwnr = NOTSET;
+    std::optional<BondedTypes> btkw;
+    std::optional<ReplaceType> rtkw;
     get_a_line(in, line, STRLEN);
     MoleculePatchDatabase* block = nullptr;
     while (!feof(in))
@@ -253,9 +259,10 @@ static void read_ter_db_file(const char*                         fn,
         if (get_header(line, header))
         {
             /* this is a new block, or a new keyword */
-            kwnr = find_kw(header);
+            btkw = findTypeFromKeyword<BondedTypes>(header);
+            rtkw = findTypeFromKeyword<ReplaceType>(header);
 
-            if (kwnr == NOTSET)
+            if (!btkw.has_value() && !rtkw.has_value())
             {
                 tbptr->emplace_back(MoleculePatchDatabase());
                 block = &tbptr->back();
@@ -275,7 +282,7 @@ static void read_ter_db_file(const char*                         fn,
                           line);
             }
             /* this is not a header, so it must be data */
-            if (kwnr >= ebtsNR)
+            if (!btkw.has_value())
             {
                 /* this is a hack: add/rename/delete atoms */
                 /* make space for hacks */
@@ -284,33 +291,37 @@ static void read_ter_db_file(const char*                         fn,
 
                 /* get data */
                 int n = 0;
-                if (kwnr == ekwRepl || kwnr == ekwDel)
+                if (*rtkw == ReplaceType::Repl || *rtkw == ReplaceType::Del)
                 {
                     if (sscanf(line, "%s%n", buf, &n) != 1)
                     {
                         gmx_fatal(FARGS,
                                   "Reading Termini Database '%s': "
                                   "expected atom name on line\n%s",
-                                  fn, line);
+                                  fn,
+                                  line);
                     }
                     hack->oname = buf;
                     /* we only replace or delete one atom at a time */
                     hack->nr = 1;
                 }
-                else if (kwnr == ekwAdd)
+                else if (*rtkw == ReplaceType::Add)
                 {
                     read_ab(line, fn, hack);
                     get_a_line(in, line, STRLEN);
                 }
                 else
                 {
-                    gmx_fatal(FARGS, "unimplemented keyword number %d (%s:%d)", kwnr, __FILE__, __LINE__);
+                    gmx_fatal(FARGS,
+                              "unimplemented keyword number %d (%s:%d)",
+                              static_cast<int>(*rtkw),
+                              __FILE__,
+                              __LINE__);
                 }
-                if (kwnr == ekwRepl || kwnr == ekwAdd)
+                if (*rtkw == ReplaceType::Repl || *rtkw == ReplaceType::Add)
                 {
                     hack->atom.emplace_back();
-                    read_atom(line + n, kwnr == ekwAdd, &hack->nname, &hack->atom.back(), atype,
-                              &hack->cgnr);
+                    read_atom(line + n, *rtkw == ReplaceType::Add, &hack->nname, &hack->atom.back(), atype, &hack->cgnr);
                     if (hack->nname.empty())
                     {
                         if (!hack->oname.empty())
@@ -322,18 +333,19 @@ static void read_ter_db_file(const char*                         fn,
                             gmx_fatal(FARGS,
                                       "Reading Termini Database '%s': don't know which name the "
                                       "new atom should have on line\n%s",
-                                      fn, line);
+                                      fn,
+                                      line);
                         }
                     }
                 }
             }
-            else if (kwnr >= 0 && kwnr < ebtsNR)
+            else if (*btkw >= BondedTypes::Bonds && *btkw < BondedTypes::Count)
             {
                 /* this is bonded data: bonds, angles, dihedrals or impropers */
                 int n = 0;
-                block->rb[kwnr].b.emplace_back();
-                BondedInteraction* newBond = &block->rb[kwnr].b.back();
-                for (int j = 0; j < btsNiatoms[kwnr]; j++)
+                block->rb[*btkw].b.emplace_back();
+                BondedInteraction* newBond = &block->rb[*btkw].b.back();
+                for (int j = 0; j < enumValueToNumIAtoms(*btkw); j++)
                 {
                     int ni;
                     if (sscanf(line + n, "%s%n", buf, &ni) == 1)
@@ -345,7 +357,10 @@ static void read_ter_db_file(const char*                         fn,
                         gmx_fatal(FARGS,
                                   "Reading Termini Database '%s': expected %d atom names (found "
                                   "%d) on line\n%s",
-                                  fn, btsNiatoms[kwnr], j - 1, line);
+                                  fn,
+                                  enumValueToNumIAtoms(*btkw),
+                                  j - 1,
+                                  line);
                     }
                     n += ni;
                 }
@@ -501,7 +516,9 @@ MoleculePatchDatabase* choose_ter(gmx::ArrayRef<MoleculePatchDatabase*> tb, cons
     for (const auto& modification : tb)
     {
         bool bIsZwitterion = (0 == gmx_wcmatch("*ZWITTERION*", modification->name.c_str()));
-        printf("%2d: %s%s\n", i, modification->name.c_str(),
+        printf("%2d: %s%s\n",
+               i,
+               modification->name.c_str(),
                bIsZwitterion ? " (only use with zwitterions containing exactly one residue)" : "");
         i++;
     }
diff --git a/src/gromacs/gmxpreprocess/tests/.clang-tidy b/src/gromacs/gmxpreprocess/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..710212e
--- /dev/null
@@ -0,0 +1,96 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -cppcoreguidelines-init-variables
+# These shall be fixed eventually, but clang-tidy's automatic fix of 
+# initializing them with zeroes does not usually improve the code in
+# a meaningful way, and fixing them all manually is cumbersome.
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
diff --git a/src/gromacs/gmxpreprocess/tests/cyclic-dna.pdb b/src/gromacs/gmxpreprocess/tests/cyclic-dna.pdb
deleted file mode 100644 (file)
index 36c63b8..0000000
+++ /dev/null
@@ -1,3822 +0,0 @@
-TITLE     Protein
-REMARK    THIS IS A SIMULATION BOX
-CRYST1  114.390  114.390  114.390  90.00  90.00  90.00 P 1           1
-MODEL        1
-ATOM      1  P    DA A   1      88.580  48.340  55.060  1.00  0.00            
-ATOM      2  O1P  DA A   1      89.240  47.170  54.420  1.00  0.00            
-ATOM      3  O2P  DA A   1      87.630  48.030  56.150  1.00  0.00            
-ATOM      4  O5'  DA A   1      89.820  49.230  55.720  1.00  0.00            
-ATOM      5  C5'  DA A   1      91.170  49.170  55.220  1.00  0.00            
-ATOM      6 1H5'  DA A   1      91.100  49.410  54.160  1.00  0.00            
-ATOM      7 2H5'  DA A   1      91.500  48.130  55.280  1.00  0.00            
-ATOM      8  C4'  DA A   1      92.340  50.070  55.780  1.00  0.00            
-ATOM      9  H4'  DA A   1      93.180  49.900  55.120  1.00  0.00            
-ATOM     10  O4'  DA A   1      91.950  51.410  55.600  1.00  0.00            
-ATOM     11  C1'  DA A   1      91.800  52.010  56.880  1.00  0.00            
-ATOM     12  H1'  DA A   1      92.610  52.730  57.020  1.00  0.00            
-ATOM     13  N9   DA A   1      90.520  52.730  56.940  1.00  0.00            
-ATOM     14  C8   DA A   1      89.230  52.250  56.980  1.00  0.00            
-ATOM     15  H8   DA A   1      89.000  51.190  56.940  1.00  0.00            
-ATOM     16  N7   DA A   1      88.320  53.170  57.090  1.00  0.00            
-ATOM     17  C5   DA A   1      89.080  54.360  57.070  1.00  0.00            
-ATOM     18  C6   DA A   1      88.790  55.740  57.110  1.00  0.00            
-ATOM     19  N6   DA A   1      87.590  56.260  57.160  1.00  0.00            
-ATOM     20  H61  DA A   1      87.480  57.270  57.170  1.00  0.00            
-ATOM     21  H62  DA A   1      86.780  55.660  57.160  1.00  0.00            
-ATOM     22  N1   DA A   1      89.780  56.640  57.080  1.00  0.00            
-ATOM     23  C2   DA A   1      91.030  56.220  57.010  1.00  0.00            
-ATOM     24  H2   DA A   1      91.790  56.990  57.000  1.00  0.00            
-ATOM     25  N3   DA A   1      91.460  54.970  56.980  1.00  0.00            
-ATOM     26  C4   DA A   1      90.420  54.090  56.990  1.00  0.00            
-ATOM     27  C3'  DA A   1      92.920  49.980  57.240  1.00  0.00            
-ATOM     28  H3'  DA A   1      92.840  48.970  57.630  1.00  0.00            
-ATOM     29  C2'  DA A   1      91.930  50.910  57.930  1.00  0.00            
-ATOM     30 1H2'  DA A   1      90.980  50.400  58.080  1.00  0.00            
-ATOM     31 2H2'  DA A   1      92.320  51.290  58.870  1.00  0.00            
-ATOM     32  O3'  DA A   1      94.290  50.480  57.330  1.00  0.00            
-ATOM     33  P    DA A   2      95.280  50.440  58.660  1.00  0.00            
-ATOM     34  O1P  DA A   2      96.640  50.120  58.160  1.00  0.00            
-ATOM     35  O2P  DA A   2      94.690  49.470  59.610  1.00  0.00            
-ATOM     36  O5'  DA A   2      95.410  51.910  59.450  1.00  0.00            
-ATOM     37  C5'  DA A   2      96.480  52.850  59.170  1.00  0.00            
-ATOM     38 1H5'  DA A   2      96.470  53.000  58.090  1.00  0.00            
-ATOM     39 2H5'  DA A   2      97.420  52.370  59.410  1.00  0.00            
-ATOM     40  C4'  DA A   2      96.520  54.310  59.780  1.00  0.00            
-ATOM     41  H4'  DA A   2      97.290  54.840  59.220  1.00  0.00            
-ATOM     42  O4'  DA A   2      95.300  54.930  59.450  1.00  0.00            
-ATOM     43  C1'  DA A   2      94.640  55.290  60.650  1.00  0.00            
-ATOM     44  H1'  DA A   2      94.670  56.380  60.760  1.00  0.00            
-ATOM     45  N9   DA A   2      93.240  54.860  60.570  1.00  0.00            
-ATOM     46  C8   DA A   2      92.710  53.600  60.430  1.00  0.00            
-ATOM     47  H8   DA A   2      93.330  52.720  60.340  1.00  0.00            
-ATOM     48  N7   DA A   2      91.400  53.560  60.400  1.00  0.00            
-ATOM     49  C5   DA A   2      91.060  54.930  60.520  1.00  0.00            
-ATOM     50  C6   DA A   2      89.860  55.670  60.530  1.00  0.00            
-ATOM     51  N6   DA A   2      88.660  55.160  60.390  1.00  0.00            
-ATOM     52  H61  DA A   2      87.870  55.800  60.350  1.00  0.00            
-ATOM     53  H62  DA A   2      88.550  54.190  60.200  1.00  0.00            
-ATOM     54  N1   DA A   2      89.880  56.990  60.660  1.00  0.00            
-ATOM     55  C2   DA A   2      91.050  57.620  60.760  1.00  0.00            
-ATOM     56  H2   DA A   2      91.010  58.690  60.850  1.00  0.00            
-ATOM     57  N3   DA A   2      92.250  57.070  60.760  1.00  0.00            
-ATOM     58  C4   DA A   2      92.170  55.710  60.630  1.00  0.00            
-ATOM     59  C3'  DA A   2      96.800  54.670  61.290  1.00  0.00            
-ATOM     60  H3'  DA A   2      97.410  53.920  61.770  1.00  0.00            
-ATOM     61  C2'  DA A   2      95.380  54.640  61.820  1.00  0.00            
-ATOM     62 1H2'  DA A   2      95.050  53.610  61.960  1.00  0.00            
-ATOM     63 2H2'  DA A   2      95.260  55.220  62.730  1.00  0.00            
-ATOM     64  O3'  DA A   2      97.390  56.000  61.450  1.00  0.00            
-ATOM     65  P    DG A   3      97.900  56.690  62.870  1.00  0.00            
-ATOM     66  O1P  DG A   3      99.190  57.370  62.570  1.00  0.00            
-ATOM     67  O2P  DG A   3      97.960  55.600  63.880  1.00  0.00            
-ATOM     68  O5'  DG A   3      96.870  57.870  63.450  1.00  0.00            
-ATOM     69  C5'  DG A   3      97.000  59.270  63.090  1.00  0.00            
-ATOM     70 1H5'  DG A   3      97.020  59.280  62.000  1.00  0.00            
-ATOM     71 2H5'  DG A   3      97.960  59.630  63.430  1.00  0.00            
-ATOM     72  C4'  DG A   3      95.910  60.350  63.480  1.00  0.00            
-ATOM     73  H4'  DG A   3      96.080  61.200  62.820  1.00  0.00            
-ATOM     74  O4'  DG A   3      94.670  59.820  63.110  1.00  0.00            
-ATOM     75  C1'  DG A   3      93.830  59.770  64.250  1.00  0.00            
-ATOM     76  H1'  DG A   3      93.080  60.570  64.180  1.00  0.00            
-ATOM     77  N9   DG A   3      93.140  58.470  64.290  1.00  0.00            
-ATOM     78  C8   DG A   3      93.640  57.200  64.400  1.00  0.00            
-ATOM     79  H8   DG A   3      94.700  57.000  64.450  1.00  0.00            
-ATOM     80  N7   DG A   3      92.730  56.270  64.430  1.00  0.00            
-ATOM     81  C5   DG A   3      91.520  56.990  64.280  1.00  0.00            
-ATOM     82  C6   DG A   3      90.140  56.590  64.190  1.00  0.00            
-ATOM     83  O6   DG A   3      89.670  55.450  64.200  1.00  0.00            
-ATOM     84  N1   DG A   3      89.270  57.660  64.060  1.00  0.00            
-ATOM     85  H1   DG A   3      88.290  57.450  63.960  1.00  0.00            
-ATOM     86  C2   DG A   3      89.660  58.960  63.990  1.00  0.00            
-ATOM     87  N2   DG A   3      88.760  59.880  63.880  1.00  0.00            
-ATOM     88  H21  DG A   3      87.770  59.640  63.850  1.00  0.00            
-ATOM     89  H22  DG A   3      89.060  60.830  63.780  1.00  0.00            
-ATOM     90  N3   DG A   3      90.910  59.370  64.090  1.00  0.00            
-ATOM     91  C4   DG A   3      91.790  58.340  64.220  1.00  0.00            
-ATOM     92  C3'  DG A   3      95.720  60.970  64.910  1.00  0.00            
-ATOM     93  H3'  DG A   3      96.650  60.940  65.480  1.00  0.00            
-ATOM     94  C2'  DG A   3      94.700  60.010  65.480  1.00  0.00            
-ATOM     95 1H2'  DG A   3      95.190  59.090  65.800  1.00  0.00            
-ATOM     96 2H2'  DG A   3      94.120  60.450  66.300  1.00  0.00            
-ATOM     97  O3'  DG A   3      95.210  62.340  64.850  1.00  0.00            
-ATOM     98  P    DA A   4      94.880  63.320  66.140  1.00  0.00            
-ATOM     99  O1P  DA A   4      95.380  64.680  65.790  1.00  0.00            
-ATOM    100  O2P  DA A   4      95.490  62.690  67.330  1.00  0.00            
-ATOM    101  O5'  DA A   4      93.240  63.470  66.420  1.00  0.00            
-ATOM    102  C5'  DA A   4      92.390  64.390  65.680  1.00  0.00            
-ATOM    103 1H5'  DA A   4      92.590  64.200  64.630  1.00  0.00            
-ATOM    104 2H5'  DA A   4      92.720  65.410  65.890  1.00  0.00            
-ATOM    105  C4'  DA A   4      90.820  64.350  65.810  1.00  0.00            
-ATOM    106  H4'  DA A   4      90.430  64.880  64.940  1.00  0.00            
-ATOM    107  O4'  DA A   4      90.420  63.010  65.660  1.00  0.00            
-ATOM    108  C1'  DA A   4      89.600  62.630  66.750  1.00  0.00            
-ATOM    109  H1'  DA A   4      88.540  62.600  66.450  1.00  0.00            
-ATOM    110  N9   DA A   4      90.030  61.290  67.190  1.00  0.00            
-ATOM    111  C8   DA A   4      91.300  60.860  67.510  1.00  0.00            
-ATOM    112  H8   DA A   4      92.140  61.540  67.510  1.00  0.00            
-ATOM    113  N7   DA A   4      91.390  59.590  67.770  1.00  0.00            
-ATOM    114  C5   DA A   4      90.070  59.150  67.560  1.00  0.00            
-ATOM    115  C6   DA A   4      89.410  57.900  67.550  1.00  0.00            
-ATOM    116  N6   DA A   4      90.020  56.750  67.720  1.00  0.00            
-ATOM    117  H61  DA A   4      89.460  55.910  67.580  1.00  0.00            
-ATOM    118  H62  DA A   4      91.010  56.740  67.770  1.00  0.00            
-ATOM    119  N1   DA A   4      88.120  57.800  67.270  1.00  0.00            
-ATOM    120  C2   DA A   4      87.430  58.910  67.020  1.00  0.00            
-ATOM    121  H2   DA A   4      86.370  58.780  66.800  1.00  0.00            
-ATOM    122  N3   DA A   4      87.900  60.150  67.010  1.00  0.00            
-ATOM    123  C4   DA A   4      89.230  60.190  67.250  1.00  0.00            
-ATOM    124  C3'  DA A   4      90.030  64.920  67.030  1.00  0.00            
-ATOM    125  H3'  DA A   4      90.620  65.640  67.590  1.00  0.00            
-ATOM    126  C2'  DA A   4      89.800  63.660  67.850  1.00  0.00            
-ATOM    127 1H2'  DA A   4      90.690  63.440  68.440  1.00  0.00            
-ATOM    128 2H2'  DA A   4      88.920  63.730  68.490  1.00  0.00            
-ATOM    129  O3'  DA A   4      88.760  65.520  66.650  1.00  0.00            
-ATOM    130  P    DT A   5      87.640  66.150  67.690  1.00  0.00            
-ATOM    131  O1P  DT A   5      87.130  67.400  67.070  1.00  0.00            
-ATOM    132  O2P  DT A   5      88.340  66.310  68.990  1.00  0.00            
-ATOM    133  O5'  DT A   5      86.380  65.100  67.890  1.00  0.00            
-ATOM    134  C5'  DT A   5      85.310  64.910  66.910  1.00  0.00            
-ATOM    135 1H5'  DT A   5      85.810  64.770  65.950  1.00  0.00            
-ATOM    136 2H5'  DT A   5      84.740  65.830  66.840  1.00  0.00            
-ATOM    137  C4'  DT A   5      84.300  63.710  67.040  1.00  0.00            
-ATOM    138  H4'  DT A   5      83.870  63.540  66.050  1.00  0.00            
-ATOM    139  O4'  DT A   5      85.070  62.560  67.360  1.00  0.00            
-ATOM    140  C1'  DT A   5      84.450  61.860  68.420  1.00  0.00            
-ATOM    141  H1'  DT A   5      83.780  61.080  68.020  1.00  0.00            
-ATOM    142  N1   DT A   5      85.510  61.280  69.270  1.00  0.00            
-ATOM    143  C6   DT A   5      86.510  62.090  69.780  1.00  0.00            
-ATOM    144  H6   DT A   5      86.460  63.150  69.550  1.00  0.00            
-ATOM    145  C5   DT A   5      87.540  61.570  70.490  1.00  0.00            
-ATOM    146  C7   DT A   5      88.610  62.490  71.040  1.00  0.00            
-ATOM    147  H71  DT A   5      88.340  63.540  70.860  1.00  0.00            
-ATOM    148  H72  DT A   5      88.700  62.310  72.110  1.00  0.00            
-ATOM    149  H73  DT A   5      89.550  62.260  70.550  1.00  0.00            
-ATOM    150  C4   DT A   5      87.630  60.130  70.710  1.00  0.00            
-ATOM    151  O4   DT A   5      88.560  59.560  71.290  1.00  0.00            
-ATOM    152  N3   DT A   5      86.580  59.400  70.200  1.00  0.00            
-ATOM    153  H3   DT A   5      86.600  58.390  70.270  1.00  0.00            
-ATOM    154  C2   DT A   5      85.520  59.900  69.480  1.00  0.00            
-ATOM    155  O2   DT A   5      84.680  59.130  69.060  1.00  0.00            
-ATOM    156  C3'  DT A   5      83.080  63.720  68.020  1.00  0.00            
-ATOM    157  H3'  DT A   5      82.820  64.730  68.330  1.00  0.00            
-ATOM    158  C2'  DT A   5      83.620  62.900  69.180  1.00  0.00            
-ATOM    159 1H2'  DT A   5      84.240  63.540  69.810  1.00  0.00            
-ATOM    160 2H2'  DT A   5      82.840  62.430  69.770  1.00  0.00            
-ATOM    161  O3'  DT A   5      81.910  63.060  67.470  1.00  0.00            
-ATOM    162  P    DG A   6      80.460  62.930  68.240  1.00  0.00            
-ATOM    163  O1P  DG A   6      79.410  63.350  67.290  1.00  0.00            
-ATOM    164  O2P  DG A   6      80.590  63.740  69.480  1.00  0.00            
-ATOM    165  O5'  DG A   6      80.170  61.360  68.680  1.00  0.00            
-ATOM    166  C5'  DG A   6      79.700  60.350  67.750  1.00  0.00            
-ATOM    167 1H5'  DG A   6      80.380  60.420  66.900  1.00  0.00            
-ATOM    168 2H5'  DG A   6      78.710  60.630  67.390  1.00  0.00            
-ATOM    169  C4'  DG A   6      79.680  58.820  68.140  1.00  0.00            
-ATOM    170  H4'  DG A   6      79.610  58.260  67.220  1.00  0.00            
-ATOM    171  O4'  DG A   6      80.950  58.560  68.710  1.00  0.00            
-ATOM    172  C1'  DG A   6      80.740  58.160  70.050  1.00  0.00            
-ATOM    173  H1'  DG A   6      80.840  57.070  70.110  1.00  0.00            
-ATOM    174  N9   DG A   6      81.750  58.790  70.910  1.00  0.00            
-ATOM    175  C8   DG A   6      82.020  60.120  71.130  1.00  0.00            
-ATOM    176  H8   DG A   6      81.420  60.900  70.680  1.00  0.00            
-ATOM    177  N7   DG A   6      83.080  60.340  71.870  1.00  0.00            
-ATOM    178  C5   DG A   6      83.510  59.030  72.180  1.00  0.00            
-ATOM    179  C6   DG A   6      84.640  58.540  72.930  1.00  0.00            
-ATOM    180  O6   DG A   6      85.540  59.170  73.480  1.00  0.00            
-ATOM    181  N1   DG A   6      84.690  57.160  73.000  1.00  0.00            
-ATOM    182  H1   DG A   6      85.470  56.750  73.480  1.00  0.00            
-ATOM    183  C2   DG A   6      83.790  56.340  72.410  1.00  0.00            
-ATOM    184  N2   DG A   6      83.920  55.050  72.580  1.00  0.00            
-ATOM    185  H21  DG A   6      84.700  54.650  73.070  1.00  0.00            
-ATOM    186  H22  DG A   6      83.210  54.500  72.120  1.00  0.00            
-ATOM    187  N3   DG A   6      82.770  56.730  71.700  1.00  0.00            
-ATOM    188  C4   DG A   6      82.680  58.090  71.620  1.00  0.00            
-ATOM    189  C3'  DG A   6      78.650  58.150  69.110  1.00  0.00            
-ATOM    190  H3'  DG A   6      77.660  58.590  69.020  1.00  0.00            
-ATOM    191  C2'  DG A   6      79.310  58.520  70.430  1.00  0.00            
-ATOM    192 1H2'  DG A   6      79.200  59.580  70.630  1.00  0.00            
-ATOM    193 2H2'  DG A   6      78.940  57.910  71.260  1.00  0.00            
-ATOM    194  O3'  DG A   6      78.590  56.700  68.950  1.00  0.00            
-ATOM    195  P    DG A   7      77.600  55.670  69.770  1.00  0.00            
-ATOM    196  O1P  DG A   7      76.890  54.820  68.790  1.00  0.00            
-ATOM    197  O2P  DG A   7      76.780  56.500  70.690  1.00  0.00            
-ATOM    198  O5'  DG A   7      78.450  54.630  70.740  1.00  0.00            
-ATOM    199  C5'  DG A   7      78.970  53.370  70.300  1.00  0.00            
-ATOM    200 1H5'  DG A   7      79.680  53.610  69.500  1.00  0.00            
-ATOM    201 2H5'  DG A   7      78.170  52.790  69.840  1.00  0.00            
-ATOM    202  C4'  DG A   7      79.730  52.440  71.320  1.00  0.00            
-ATOM    203  H4'  DG A   7      80.280  51.710  70.730  1.00  0.00            
-ATOM    204  O4'  DG A   7      80.670  53.240  72.010  1.00  0.00            
-ATOM    205  C1'  DG A   7      80.180  53.420  73.330  1.00  0.00            
-ATOM    206  H1'  DG A   7      80.830  52.850  73.980  1.00  0.00            
-ATOM    207  N9   DG A   7      80.270  54.840  73.720  1.00  0.00            
-ATOM    208  C8   DG A   7      79.560  55.950  73.330  1.00  0.00            
-ATOM    209  H8   DG A   7      78.710  55.910  72.660  1.00  0.00            
-ATOM    210  N7   DG A   7      80.010  57.070  73.830  1.00  0.00            
-ATOM    211  C5   DG A   7      81.110  56.670  74.600  1.00  0.00            
-ATOM    212  C6   DG A   7      82.100  57.400  75.340  1.00  0.00            
-ATOM    213  O6   DG A   7      82.270  58.610  75.470  1.00  0.00            
-ATOM    214  N1   DG A   7      83.020  56.580  75.970  1.00  0.00            
-ATOM    215  H1   DG A   7      83.770  57.050  76.450  1.00  0.00            
-ATOM    216  C2   DG A   7      83.010  55.240  75.920  1.00  0.00            
-ATOM    217  N2   DG A   7      83.920  54.570  76.560  1.00  0.00            
-ATOM    218  H21  DG A   7      84.670  55.070  77.030  1.00  0.00            
-ATOM    219  H22  DG A   7      83.870  53.580  76.470  1.00  0.00            
-ATOM    220  N3   DG A   7      82.130  54.510  75.250  1.00  0.00            
-ATOM    221  C4   DG A   7      81.230  55.290  74.580  1.00  0.00            
-ATOM    222  C3'  DG A   7      79.000  51.650  72.460  1.00  0.00            
-ATOM    223  H3'  DG A   7      78.040  51.250  72.110  1.00  0.00            
-ATOM    224  C2'  DG A   7      78.790  52.800  73.420  1.00  0.00            
-ATOM    225 1H2'  DG A   7      78.020  53.480  73.060  1.00  0.00            
-ATOM    226 2H2'  DG A   7      78.560  52.450  74.420  1.00  0.00            
-ATOM    227  O3'  DG A   7      79.830  50.590  73.050  1.00  0.00            
-ATOM    228  P    DC A   8      79.390  49.550  74.260  1.00  0.00            
-ATOM    229  O1P  DC A   8      79.890  48.200  73.910  1.00  0.00            
-ATOM    230  O2P  DC A   8      77.940  49.690  74.490  1.00  0.00            
-ATOM    231  O5'  DC A   8      80.130  49.920  75.700  1.00  0.00            
-ATOM    232  C5'  DC A   8      81.390  49.350  76.090  1.00  0.00            
-ATOM    233 1H5'  DC A   8      82.090  49.610  75.300  1.00  0.00            
-ATOM    234 2H5'  DC A   8      81.290  48.260  76.070  1.00  0.00            
-ATOM    235  C4'  DC A   8      82.070  49.750  77.450  1.00  0.00            
-ATOM    236  H4'  DC A   8      83.090  49.370  77.400  1.00  0.00            
-ATOM    237  O4'  DC A   8      82.160  51.160  77.470  1.00  0.00            
-ATOM    238  C1'  DC A   8      81.340  51.640  78.520  1.00  0.00            
-ATOM    239  H1'  DC A   8      82.010  51.910  79.340  1.00  0.00            
-ATOM    240  N1   DC A   8      80.590  52.850  78.080  1.00  0.00            
-ATOM    241  C6   DC A   8      79.540  52.810  77.190  1.00  0.00            
-ATOM    242  H6   DC A   8      79.230  51.860  76.770  1.00  0.00            
-ATOM    243  C5   DC A   8      78.940  53.960  76.810  1.00  0.00            
-ATOM    244  H5   DC A   8      78.120  53.950  76.100  1.00  0.00            
-ATOM    245  C4   DC A   8      79.450  55.180  77.330  1.00  0.00            
-ATOM    246  N4   DC A   8      78.950  56.320  76.960  1.00  0.00            
-ATOM    247  H41  DC A   8      79.330  57.170  77.360  1.00  0.00            
-ATOM    248  H42  DC A   8      78.270  56.380  76.240  1.00  0.00            
-ATOM    249  N3   DC A   8      80.440  55.230  78.200  1.00  0.00            
-ATOM    250  C2   DC A   8      81.020  54.080  78.580  1.00  0.00            
-ATOM    251  O2   DC A   8      81.930  54.140  79.410  1.00  0.00            
-ATOM    252  C3'  DC A   8      81.520  49.340  78.860  1.00  0.00            
-ATOM    253  H3'  DC A   8      81.020  48.370  78.810  1.00  0.00            
-ATOM    254  C2'  DC A   8      80.510  50.470  79.030  1.00  0.00            
-ATOM    255 1H2'  DC A   8      79.640  50.290  78.400  1.00  0.00            
-ATOM    256 2H2'  DC A   8      80.210  50.590  80.070  1.00  0.00            
-ATOM    257  O3'  DC A   8      82.560  49.350  79.890  1.00  0.00            
-ATOM    258  P    DA A   9      82.440  48.820  81.460  1.00  0.00            
-ATOM    259  O1P  DA A   9      83.660  48.020  81.750  1.00  0.00            
-ATOM    260  O2P  DA A   9      81.150  48.100  81.600  1.00  0.00            
-ATOM    261  O5'  DA A   9      82.440  50.060  82.570  1.00  0.00            
-ATOM    262  C5'  DA A   9      83.650  50.520  83.210  1.00  0.00            
-ATOM    263 1H5'  DA A   9      84.350  50.720  82.390  1.00  0.00            
-ATOM    264 2H5'  DA A   9      84.070  49.690  83.780  1.00  0.00            
-ATOM    265  C4'  DA A   9      83.700  51.810  84.120  1.00  0.00            
-ATOM    266  H4'  DA A   9      84.750  51.990  84.300  1.00  0.00            
-ATOM    267  O4'  DA A   9      83.240  52.890  83.340  1.00  0.00            
-ATOM    268  C1'  DA A   9      82.050  53.390  83.920  1.00  0.00            
-ATOM    269  H1'  DA A   9      82.250  54.390  84.330  1.00  0.00            
-ATOM    270  N9   DA A   9      80.990  53.510  82.900  1.00  0.00            
-ATOM    271  C8   DA A   9      80.370  52.550  82.150  1.00  0.00            
-ATOM    272  H8   DA A   9      80.620  51.500  82.200  1.00  0.00            
-ATOM    273  N7   DA A   9      79.430  53.000  81.360  1.00  0.00            
-ATOM    274  C5   DA A   9      79.470  54.390  81.610  1.00  0.00            
-ATOM    275  C6   DA A   9      78.790  55.530  81.110  1.00  0.00            
-ATOM    276  N6   DA A   9      77.870  55.510  80.180  1.00  0.00            
-ATOM    277  H61  DA A   9      77.520  56.400  79.820  1.00  0.00            
-ATOM    278  H62  DA A   9      77.630  54.650  79.730  1.00  0.00            
-ATOM    279  N1   DA A   9      79.080  56.730  81.590  1.00  0.00            
-ATOM    280  C2   DA A   9      80.000  56.870  82.530  1.00  0.00            
-ATOM    281  H2   DA A   9      80.190  57.880  82.870  1.00  0.00            
-ATOM    282  N3   DA A   9      80.720  55.910  83.090  1.00  0.00            
-ATOM    283  C4   DA A   9      80.410  54.690  82.560  1.00  0.00            
-ATOM    284  C3'  DA A   9      83.000  51.950  85.520  1.00  0.00            
-ATOM    285  H3'  DA A   9      82.910  50.990  86.010  1.00  0.00            
-ATOM    286  C2'  DA A   9      81.650  52.460  85.070  1.00  0.00            
-ATOM    287 1H2'  DA A   9      81.040  51.630  84.700  1.00  0.00            
-ATOM    288 2H2'  DA A   9      81.130  53.010  85.850  1.00  0.00            
-ATOM    289  O3'  DA A   9      83.670  52.920  86.390  1.00  0.00            
-ATOM    290  P    DT A  10      83.250  53.280  87.960  1.00  0.00            
-ATOM    291  O1P  DT A  10      84.520  53.540  88.690  1.00  0.00            
-ATOM    292  O2P  DT A  10      82.430  52.150  88.460  1.00  0.00            
-ATOM    293  O5'  DT A  10      82.330  54.660  88.100  1.00  0.00            
-ATOM    294  C5'  DT A  10      82.920  55.980  88.350  1.00  0.00            
-ATOM    295 1H5'  DT A  10      83.720  56.080  87.620  1.00  0.00            
-ATOM    296 2H5'  DT A  10      83.380  55.960  89.330  1.00  0.00            
-ATOM    297  C4'  DT A  10      82.060  57.300  88.220  1.00  0.00            
-ATOM    298  H4'  DT A  10      82.770  58.100  88.010  1.00  0.00            
-ATOM    299  O4'  DT A  10      81.290  57.140  87.050  1.00  0.00            
-ATOM    300  C1'  DT A  10      79.960  57.510  87.310  1.00  0.00            
-ATOM    301  H1'  DT A  10      79.800  58.550  87.000  1.00  0.00            
-ATOM    302  N1   DT A  10      79.050  56.600  86.570  1.00  0.00            
-ATOM    303  C6   DT A  10      79.090  55.230  86.740  1.00  0.00            
-ATOM    304  H6   DT A  10      79.790  54.820  87.450  1.00  0.00            
-ATOM    305  C5   DT A  10      78.290  54.420  86.000  1.00  0.00            
-ATOM    306  C7   DT A  10      78.280  52.930  86.270  1.00  0.00            
-ATOM    307  H71  DT A  10      78.730  52.700  87.230  1.00  0.00            
-ATOM    308  H72  DT A  10      77.240  52.590  86.260  1.00  0.00            
-ATOM    309  H73  DT A  10      78.800  52.420  85.460  1.00  0.00            
-ATOM    310  C4   DT A  10      77.420  54.980  84.970  1.00  0.00            
-ATOM    311  O4   DT A  10      76.710  54.330  84.210  1.00  0.00            
-ATOM    312  N3   DT A  10      77.410  56.350  84.910  1.00  0.00            
-ATOM    313  H3   DT A  10      76.820  56.780  84.210  1.00  0.00            
-ATOM    314  C2   DT A  10      78.140  57.200  85.700  1.00  0.00            
-ATOM    315  O2   DT A  10      77.950  58.410  85.670  1.00  0.00            
-ATOM    316  C3'  DT A  10      81.120  57.870  89.340  1.00  0.00            
-ATOM    317  H3'  DT A  10      81.330  57.420  90.300  1.00  0.00            
-ATOM    318  C2'  DT A  10      79.760  57.420  88.820  1.00  0.00            
-ATOM    319 1H2'  DT A  10      79.570  56.400  89.140  1.00  0.00            
-ATOM    320 2H2'  DT A  10      78.960  58.090  89.140  1.00  0.00            
-ATOM    321  O3'  DT A  10      81.150  59.330  89.450  1.00  0.00            
-ATOM    322  P    DT A  11      80.300  60.230  90.560  1.00  0.00            
-ATOM    323  O1P  DT A  11      81.200  61.340  90.980  1.00  0.00            
-ATOM    324  O2P  DT A  11      79.890  59.300  91.630  1.00  0.00            
-ATOM    325  O5'  DT A  11      78.920  60.920  89.930  1.00  0.00            
-ATOM    326  C5'  DT A  11      78.910  62.220  89.270  1.00  0.00            
-ATOM    327 1H5'  DT A  11      79.740  62.220  88.570  1.00  0.00            
-ATOM    328 2H5'  DT A  11      79.120  62.990  90.010  1.00  0.00            
-ATOM    329  C4'  DT A  11      77.660  62.690  88.420  1.00  0.00            
-ATOM    330  H4'  DT A  11      78.040  63.390  87.680  1.00  0.00            
-ATOM    331  O4'  DT A  11      77.240  61.550  87.700  1.00  0.00            
-ATOM    332  C1'  DT A  11      75.830  61.440  87.760  1.00  0.00            
-ATOM    333  H1'  DT A  11      75.390  61.890  86.860  1.00  0.00            
-ATOM    334  N1   DT A  11      75.500  60.000  87.860  1.00  0.00            
-ATOM    335  C6   DT A  11      75.990  59.220  88.890  1.00  0.00            
-ATOM    336  H6   DT A  11      76.590  59.690  89.650  1.00  0.00            
-ATOM    337  C5   DT A  11      75.750  57.890  88.920  1.00  0.00            
-ATOM    338  C7   DT A  11      76.210  57.090  90.120  1.00  0.00            
-ATOM    339  H71  DT A  11      75.840  57.560  91.030  1.00  0.00            
-ATOM    340  H72  DT A  11      75.800  56.080  90.060  1.00  0.00            
-ATOM    341  H73  DT A  11      77.290  57.020  90.140  1.00  0.00            
-ATOM    342  C4   DT A  11      75.030  57.240  87.820  1.00  0.00            
-ATOM    343  O4   DT A  11      74.860  56.030  87.700  1.00  0.00            
-ATOM    344  N3   DT A  11      74.540  58.100  86.870  1.00  0.00            
-ATOM    345  H3   DT A  11      74.000  57.720  86.110  1.00  0.00            
-ATOM    346  C2   DT A  11      74.680  59.460  86.870  1.00  0.00            
-ATOM    347  O2   DT A  11      74.060  60.150  86.070  1.00  0.00            
-ATOM    348  C3'  DT A  11      76.380  63.380  89.010  1.00  0.00            
-ATOM    349  H3'  DT A  11      76.550  63.720  90.030  1.00  0.00            
-ATOM    350  C2'  DT A  11      75.380  62.230  88.990  1.00  0.00            
-ATOM    351 1H2'  DT A  11      75.480  61.650  89.900  1.00  0.00            
-ATOM    352 2H2'  DT A  11      74.350  62.580  88.860  1.00  0.00            
-ATOM    353  O3'  DT A  11      75.900  64.490  88.200  1.00  0.00            
-ATOM    354  P    DT A  12      74.550  65.400  88.520  1.00  0.00            
-ATOM    355  O1P  DT A  12      74.890  66.800  88.190  1.00  0.00            
-ATOM    356  O2P  DT A  12      74.200  65.130  89.940  1.00  0.00            
-ATOM    357  O5'  DT A  12      73.270  64.940  87.570  1.00  0.00            
-ATOM    358  C5'  DT A  12      73.100  65.340  86.180  1.00  0.00            
-ATOM    359 1H5'  DT A  12      74.070  65.190  85.700  1.00  0.00            
-ATOM    360 2H5'  DT A  12      72.900  66.410  86.140  1.00  0.00            
-ATOM    361  C4'  DT A  12      72.070  64.600  85.250  1.00  0.00            
-ATOM    362  H4'  DT A  12      72.420  64.730  84.220  1.00  0.00            
-ATOM    363  O4'  DT A  12      72.190  63.230  85.550  1.00  0.00            
-ATOM    364  C1'  DT A  12      70.900  62.650  85.640  1.00  0.00            
-ATOM    365  H1'  DT A  12      70.600  62.230  84.670  1.00  0.00            
-ATOM    366  N1   DT A  12      70.980  61.600  86.690  1.00  0.00            
-ATOM    367  C6   DT A  12      71.450  61.910  87.950  1.00  0.00            
-ATOM    368  H6   DT A  12      71.690  62.940  88.160  1.00  0.00            
-ATOM    369  C5   DT A  12      71.670  60.930  88.860  1.00  0.00            
-ATOM    370  C7   DT A  12      72.160  61.300  90.250  1.00  0.00            
-ATOM    371  H71  DT A  12      72.200  62.380  90.370  1.00  0.00            
-ATOM    372  H72  DT A  12      71.480  60.860  90.980  1.00  0.00            
-ATOM    373  H73  DT A  12      73.150  60.860  90.390  1.00  0.00            
-ATOM    374  C4   DT A  12      71.450  59.530  88.510  1.00  0.00            
-ATOM    375  O4   DT A  12      71.720  58.580  89.250  1.00  0.00            
-ATOM    376  N3   DT A  12      70.920  59.330  87.260  1.00  0.00            
-ATOM    377  H3   DT A  12      70.690  58.390  86.970  1.00  0.00            
-ATOM    378  C2   DT A  12      70.630  60.300  86.340  1.00  0.00            
-ATOM    379  O2   DT A  12      70.070  60.000  85.300  1.00  0.00            
-ATOM    380  C3'  DT A  12      70.540  64.930  85.200  1.00  0.00            
-ATOM    381  H3'  DT A  12      70.330  65.890  85.670  1.00  0.00            
-ATOM    382  C2'  DT A  12      69.960  63.790  86.020  1.00  0.00            
-ATOM    383 1H2'  DT A  12      70.010  64.030  87.080  1.00  0.00            
-ATOM    384 2H2'  DT A  12      68.930  63.550  85.740  1.00  0.00            
-ATOM    385  O3'  DT A  12      70.000  64.900  83.860  1.00  0.00            
-ATOM    386  P    DC A  13      68.420  65.200  83.480  1.00  0.00            
-ATOM    387  O1P  DC A  13      68.420  66.140  82.330  1.00  0.00            
-ATOM    388  O2P  DC A  13      67.790  65.680  84.730  1.00  0.00            
-ATOM    389  O5'  DC A  13      67.660  63.800  83.020  1.00  0.00            
-ATOM    390  C5'  DC A  13      67.850  63.130  81.740  1.00  0.00            
-ATOM    391 1H5'  DC A  13      68.920  63.080  81.580  1.00  0.00            
-ATOM    392 2H5'  DC A  13      67.440  63.760  80.950  1.00  0.00            
-ATOM    393  C4'  DC A  13      67.330  61.650  81.530  1.00  0.00            
-ATOM    394  H4'  DC A  13      67.840  61.250  80.660  1.00  0.00            
-ATOM    395  O4'  DC A  13      67.780  60.930  82.670  1.00  0.00            
-ATOM    396  C1'  DC A  13      66.670  60.270  83.250  1.00  0.00            
-ATOM    397  H1'  DC A  13      66.650  59.230  82.900  1.00  0.00            
-ATOM    398  N1   DC A  13      66.800  60.340  84.730  1.00  0.00            
-ATOM    399  C6   DC A  13      66.910  61.560  85.360  1.00  0.00            
-ATOM    400  H6   DC A  13      66.870  62.450  84.760  1.00  0.00            
-ATOM    401  C5   DC A  13      67.110  61.620  86.700  1.00  0.00            
-ATOM    402  H5   DC A  13      67.200  62.570  87.180  1.00  0.00            
-ATOM    403  C4   DC A  13      67.200  60.380  87.370  1.00  0.00            
-ATOM    404  N4   DC A  13      67.480  60.330  88.640  1.00  0.00            
-ATOM    405  H41  DC A  13      67.570  59.380  89.000  1.00  0.00            
-ATOM    406  H42  DC A  13      67.580  61.150  89.170  1.00  0.00            
-ATOM    407  N3   DC A  13      67.080  59.210  86.800  1.00  0.00            
-ATOM    408  C2   DC A  13      66.850  59.160  85.470  1.00  0.00            
-ATOM    409  O2   DC A  13      66.660  58.060  84.970  1.00  0.00            
-ATOM    410  C3'  DC A  13      65.830  61.270  81.320  1.00  0.00            
-ATOM    411  H3'  DC A  13      65.260  62.090  80.890  1.00  0.00            
-ATOM    412  C2'  DC A  13      65.430  60.990  82.750  1.00  0.00            
-ATOM    413 1H2'  DC A  13      65.250  61.930  83.270  1.00  0.00            
-ATOM    414 2H2'  DC A  13      64.570  60.340  82.810  1.00  0.00            
-ATOM    415  O3'  DC A  13      65.620  60.050  80.550  1.00  0.00            
-ATOM    416  P    DT A  14      64.130  59.420  80.190  1.00  0.00            
-ATOM    417  O1P  DT A  14      64.110  59.100  78.740  1.00  0.00            
-ATOM    418  O2P  DT A  14      63.130  60.400  80.690  1.00  0.00            
-ATOM    419  O5'  DT A  14      63.860  58.000  81.000  1.00  0.00            
-ATOM    420  C5'  DT A  14      64.360  56.720  80.560  1.00  0.00            
-ATOM    421 1H5'  DT A  14      65.440  56.850  80.460  1.00  0.00            
-ATOM    422 2H5'  DT A  14      63.980  56.530  79.550  1.00  0.00            
-ATOM    423  C4'  DT A  14      64.140  55.430  81.440  1.00  0.00            
-ATOM    424  H4'  DT A  14      64.900  54.710  81.120  1.00  0.00            
-ATOM    425  O4'  DT A  14      64.420  55.790  82.780  1.00  0.00            
-ATOM    426  C1'  DT A  14      63.220  55.680  83.520  1.00  0.00            
-ATOM    427  H1'  DT A  14      63.270  54.750  84.090  1.00  0.00            
-ATOM    428  N1   DT A  14      63.130  56.830  84.460  1.00  0.00            
-ATOM    429  C6   DT A  14      62.830  58.120  84.050  1.00  0.00            
-ATOM    430  H6   DT A  14      62.560  58.300  83.020  1.00  0.00            
-ATOM    431  C5   DT A  14      62.920  59.160  84.920  1.00  0.00            
-ATOM    432  C7   DT A  14      62.540  60.560  84.480  1.00  0.00            
-ATOM    433  H71  DT A  14      62.280  60.580  83.420  1.00  0.00            
-ATOM    434  H72  DT A  14      61.680  60.890  85.070  1.00  0.00            
-ATOM    435  H73  DT A  14      63.360  61.240  84.670  1.00  0.00            
-ATOM    436  C4   DT A  14      63.410  58.950  86.280  1.00  0.00            
-ATOM    437  O4   DT A  14      63.630  59.820  87.120  1.00  0.00            
-ATOM    438  N3   DT A  14      63.620  57.630  86.610  1.00  0.00            
-ATOM    439  H3   DT A  14      63.880  57.420  87.550  1.00  0.00            
-ATOM    440  C2   DT A  14      63.430  56.550  85.790  1.00  0.00            
-ATOM    441  O2   DT A  14      63.500  55.430  86.280  1.00  0.00            
-ATOM    442  C3'  DT A  14      62.790  54.650  81.500  1.00  0.00            
-ATOM    443  H3'  DT A  14      62.280  54.660  80.540  1.00  0.00            
-ATOM    444  C2'  DT A  14      62.070  55.520  82.520  1.00  0.00            
-ATOM    445 1H2'  DT A  14      61.790  56.470  82.070  1.00  0.00            
-ATOM    446 2H2'  DT A  14      61.210  55.030  82.950  1.00  0.00            
-ATOM    447  O3'  DT A  14      62.950  53.280  81.990  1.00  0.00            
-ATOM    448  P    DA A  15      61.750  52.150  82.120  1.00  0.00            
-ATOM    449  O1P  DA A  15      62.210  50.900  81.440  1.00  0.00            
-ATOM    450  O2P  DA A  15      60.490  52.750  81.650  1.00  0.00            
-ATOM    451  O5'  DA A  15      61.490  51.720  83.690  1.00  0.00            
-ATOM    452  C5'  DA A  15      62.190  50.650  84.340  1.00  0.00            
-ATOM    453 1H5'  DA A  15      63.250  50.910  84.280  1.00  0.00            
-ATOM    454 2H5'  DA A  15      62.050  49.740  83.760  1.00  0.00            
-ATOM    455  C4'  DA A  15      61.890  50.330  85.850  1.00  0.00            
-ATOM    456  H4'  DA A  15      62.670  49.650  86.180  1.00  0.00            
-ATOM    457  O4'  DA A  15      62.030  51.530  86.580  1.00  0.00            
-ATOM    458  C1'  DA A  15      60.740  51.960  86.980  1.00  0.00            
-ATOM    459  H1'  DA A  15      60.690  51.860  88.070  1.00  0.00            
-ATOM    460  N9   DA A  15      60.540  53.380  86.640  1.00  0.00            
-ATOM    461  C8   DA A  15      60.290  54.000  85.440  1.00  0.00            
-ATOM    462  H8   DA A  15      60.210  53.470  84.500  1.00  0.00            
-ATOM    463  N7   DA A  15      60.170  55.300  85.520  1.00  0.00            
-ATOM    464  C5   DA A  15      60.380  55.550  86.880  1.00  0.00            
-ATOM    465  C6   DA A  15      60.450  56.700  87.690  1.00  0.00            
-ATOM    466  N6   DA A  15      60.350  57.940  87.240  1.00  0.00            
-ATOM    467  H61  DA A  15      60.410  58.710  87.890  1.00  0.00            
-ATOM    468  H62  DA A  15      60.080  58.060  86.280  1.00  0.00            
-ATOM    469  N1   DA A  15      60.640  56.600  89.000  1.00  0.00            
-ATOM    470  C2   DA A  15      60.760  55.390  89.540  1.00  0.00            
-ATOM    471  H2   DA A  15      60.900  55.360  90.610  1.00  0.00            
-ATOM    472  N3   DA A  15      60.730  54.220  88.920  1.00  0.00            
-ATOM    473  C4   DA A  15      60.570  54.380  87.570  1.00  0.00            
-ATOM    474  C3'  DA A  15      60.530  49.720  86.330  1.00  0.00            
-ATOM    475  H3'  DA A  15      60.120  49.030  85.580  1.00  0.00            
-ATOM    476  C2'  DA A  15      59.710  51.000  86.370  1.00  0.00            
-ATOM    477 1H2'  DA A  15      59.440  51.320  85.360  1.00  0.00            
-ATOM    478 2H2'  DA A  15      58.830  50.890  86.990  1.00  0.00            
-ATOM    479  O3'  DA A  15      60.620  49.090  87.640  1.00  0.00            
-ATOM    480  P    DC A  16      59.410  48.300  88.450  1.00  0.00            
-ATOM    481  O1P  DC A  16      60.010  47.110  89.110  1.00  0.00            
-ATOM    482  O2P  DC A  16      58.320  48.020  87.480  1.00  0.00            
-ATOM    483  O5'  DC A  16      58.760  49.210  89.670  1.00  0.00            
-ATOM    484  C5'  DC A  16      59.320  49.230  91.000  1.00  0.00            
-ATOM    485 1H5'  DC A  16      60.360  49.510  90.880  1.00  0.00            
-ATOM    486 2H5'  DC A  16      59.300  48.220  91.380  1.00  0.00            
-ATOM    487  C4'  DC A  16      58.740  50.190  92.100  1.00  0.00            
-ATOM    488  H4'  DC A  16      59.430  50.140  92.940  1.00  0.00            
-ATOM    489  O4'  DC A  16      58.820  51.490  91.580  1.00  0.00            
-ATOM    490  C1'  DC A  16      57.530  52.060  91.560  1.00  0.00            
-ATOM    491  H1'  DC A  16      57.440  52.710  92.430  1.00  0.00            
-ATOM    492  N1   DC A  16      57.360  52.860  90.310  1.00  0.00            
-ATOM    493  C6   DC A  16      57.430  52.300  89.060  1.00  0.00            
-ATOM    494  H6   DC A  16      57.610  51.240  88.960  1.00  0.00            
-ATOM    495  C5   DC A  16      57.330  53.100  87.960  1.00  0.00            
-ATOM    496  H5   DC A  16      57.400  52.680  86.970  1.00  0.00            
-ATOM    497  C4   DC A  16      57.190  54.500  88.170  1.00  0.00            
-ATOM    498  N4   DC A  16      57.180  55.310  87.160  1.00  0.00            
-ATOM    499  H41  DC A  16      57.070  56.310  87.350  1.00  0.00            
-ATOM    500  H42  DC A  16      57.340  55.000  86.230  1.00  0.00            
-ATOM    501  N3   DC A  16      57.100  55.030  89.370  1.00  0.00            
-ATOM    502  C2   DC A  16      57.170  54.240  90.450  1.00  0.00            
-ATOM    503  O2   DC A  16      57.040  54.740  91.560  1.00  0.00            
-ATOM    504  C3'  DC A  16      57.300  50.040  92.720  1.00  0.00            
-ATOM    505  H3'  DC A  16      56.960  49.010  92.670  1.00  0.00            
-ATOM    506  C2'  DC A  16      56.540  50.910  91.730  1.00  0.00            
-ATOM    507 1H2'  DC A  16      56.380  50.370  90.800  1.00  0.00            
-ATOM    508 2H2'  DC A  16      55.600  51.250  92.160  1.00  0.00            
-ATOM    509  O3'  DC A  16      57.200  50.560  94.080  1.00  0.00            
-ATOM    510  P    DC A  17      55.880  50.460  95.080  1.00  0.00            
-ATOM    511  O1P  DC A  17      56.400  50.120  96.440  1.00  0.00            
-ATOM    512  O2P  DC A  17      54.950  49.480  94.480  1.00  0.00            
-ATOM    513  O5'  DC A  17      55.070  51.900  95.250  1.00  0.00            
-ATOM    514  C5'  DC A  17      55.360  52.870  96.290  1.00  0.00            
-ATOM    515 1H5'  DC A  17      56.440  53.020  96.250  1.00  0.00            
-ATOM    516 2H5'  DC A  17      55.140  52.410  97.250  1.00  0.00            
-ATOM    517  C4'  DC A  17      54.730  54.310  96.280  1.00  0.00            
-ATOM    518  H4'  DC A  17      55.340  54.910  96.960  1.00  0.00            
-ATOM    519  O4'  DC A  17      54.950  54.830  94.990  1.00  0.00            
-ATOM    520  C1'  DC A  17      53.710  55.200  94.420  1.00  0.00            
-ATOM    521  H1'  DC A  17      53.610  56.290  94.520  1.00  0.00            
-ATOM    522  N1   DC A  17      53.690  54.820  92.990  1.00  0.00            
-ATOM    523  C6   DC A  17      53.830  53.520  92.570  1.00  0.00            
-ATOM    524  H6   DC A  17      53.960  52.740  93.310  1.00  0.00            
-ATOM    525  C5   DC A  17      53.840  53.220  91.250  1.00  0.00            
-ATOM    526  H5   DC A  17      53.960  52.210  90.900  1.00  0.00            
-ATOM    527  C4   DC A  17      53.730  54.320  90.340  1.00  0.00            
-ATOM    528  N4   DC A  17      53.840  54.120  89.070  1.00  0.00            
-ATOM    529  H41  DC A  17      53.850  54.970  88.490  1.00  0.00            
-ATOM    530  H42  DC A  17      54.080  53.240  88.680  1.00  0.00            
-ATOM    531  N3   DC A  17      53.580  55.560  90.740  1.00  0.00            
-ATOM    532  C2   DC A  17      53.550  55.840  92.050  1.00  0.00            
-ATOM    533  O2   DC A  17      53.400  57.000  92.410  1.00  0.00            
-ATOM    534  C3'  DC A  17      53.240  54.670  96.640  1.00  0.00            
-ATOM    535  H3'  DC A  17      52.810  53.930  97.320  1.00  0.00            
-ATOM    536  C2'  DC A  17      52.610  54.560  95.260  1.00  0.00            
-ATOM    537 1H2'  DC A  17      52.470  53.510  94.990  1.00  0.00            
-ATOM    538 2H2'  DC A  17      51.680  55.110  95.180  1.00  0.00            
-ATOM    539  O3'  DC A  17      53.090  56.010  97.190  1.00  0.00            
-ATOM    540  P    DG A  18      51.690  56.700  97.770  1.00  0.00            
-ATOM    541  O1P  DG A  18      52.040  57.350  99.060  1.00  0.00            
-ATOM    542  O2P  DG A  18      50.680  55.620  97.840  1.00  0.00            
-ATOM    543  O5'  DG A  18      51.080  57.900  96.790  1.00  0.00            
-ATOM    544  C5'  DG A  18      51.460  59.300  96.920  1.00  0.00            
-ATOM    545 1H5'  DG A  18      52.550  59.300  96.930  1.00  0.00            
-ATOM    546 2H5'  DG A  18      51.140  59.650  97.900  1.00  0.00            
-ATOM    547  C4'  DG A  18      51.050  60.380  95.850  1.00  0.00            
-ATOM    548  H4'  DG A  18      51.710  61.230  96.010  1.00  0.00            
-ATOM    549  O4'  DG A  18      51.390  59.850  94.600  1.00  0.00            
-ATOM    550  C1'  DG A  18      50.220  59.780  93.800  1.00  0.00            
-ATOM    551  H1'  DG A  18      50.270  60.570  93.040  1.00  0.00            
-ATOM    552  N9   DG A  18      50.160  58.470  93.130  1.00  0.00            
-ATOM    553  C8   DG A  18      50.100  57.200  93.650  1.00  0.00            
-ATOM    554  H8   DG A  18      50.120  57.020  94.710  1.00  0.00            
-ATOM    555  N7   DG A  18      50.040  56.260  92.750  1.00  0.00            
-ATOM    556  C5   DG A  18      50.100  56.970  91.530  1.00  0.00            
-ATOM    557  C6   DG A  18      50.130  56.550  90.150  1.00  0.00            
-ATOM    558  O6   DG A  18      50.100  55.410  89.700  1.00  0.00            
-ATOM    559  N1   DG A  18      50.200  57.620  89.260  1.00  0.00            
-ATOM    560  H1   DG A  18      50.300  57.400  88.280  1.00  0.00            
-ATOM    561  C2   DG A  18      50.240  58.920  89.630  1.00  0.00            
-ATOM    562  N2   DG A  18      50.330  59.840  88.730  1.00  0.00            
-ATOM    563  H21  DG A  18      50.430  59.580  87.740  1.00  0.00            
-ATOM    564  H22  DG A  18      50.470  60.790  89.010  1.00  0.00            
-ATOM    565  N3   DG A  18      50.170  59.350  90.890  1.00  0.00            
-ATOM    566  C4   DG A  18      50.140  58.320  91.780  1.00  0.00            
-ATOM    567  C3'  DG A  18      49.610  61.000  95.700  1.00  0.00            
-ATOM    568  H3'  DG A  18      49.070  60.970  96.640  1.00  0.00            
-ATOM    569  C2'  DG A  18      49.020  60.030  94.700  1.00  0.00            
-ATOM    570 1H2'  DG A  18      48.710  59.110  95.200  1.00  0.00            
-ATOM    571 2H2'  DG A  18      48.190  60.460  94.140  1.00  0.00            
-ATOM    572  O3'  DG A  18      49.630  62.360  95.160  1.00  0.00            
-ATOM    573  P    DT A  19      48.300  63.300  94.840  1.00  0.00            
-ATOM    574  O1P  DT A  19      48.620  64.670  95.300  1.00  0.00            
-ATOM    575  O2P  DT A  19      47.150  62.650  95.500  1.00  0.00            
-ATOM    576  O5'  DT A  19      47.970  63.390  93.210  1.00  0.00            
-ATOM    577  C5'  DT A  19      48.630  64.320  92.310  1.00  0.00            
-ATOM    578 1H5'  DT A  19      49.700  64.220  92.500  1.00  0.00            
-ATOM    579 2H5'  DT A  19      48.360  65.340  92.590  1.00  0.00            
-ATOM    580  C4'  DT A  19      48.470  64.190  90.740  1.00  0.00            
-ATOM    581  H4'  DT A  19      49.360  64.660  90.310  1.00  0.00            
-ATOM    582  O4'  DT A  19      48.560  62.820  90.430  1.00  0.00            
-ATOM    583  C1'  DT A  19      47.540  62.470  89.520  1.00  0.00            
-ATOM    584  H1'  DT A  19      47.930  62.480  88.490  1.00  0.00            
-ATOM    585  N1   DT A  19      47.050  61.120  89.880  1.00  0.00            
-ATOM    586  C6   DT A  19      46.630  60.850  91.170  1.00  0.00            
-ATOM    587  H6   DT A  19      46.650  61.650  91.890  1.00  0.00            
-ATOM    588  C5   DT A  19      46.260  59.590  91.520  1.00  0.00            
-ATOM    589  C7   DT A  19      45.760  59.330  92.930  1.00  0.00            
-ATOM    590  H71  DT A  19      45.500  60.270  93.420  1.00  0.00            
-ATOM    591  H72  DT A  19      44.880  58.690  92.870  1.00  0.00            
-ATOM    592  H73  DT A  19      46.540  58.810  93.490  1.00  0.00            
-ATOM    593  C4   DT A  19      46.330  58.490  90.560  1.00  0.00            
-ATOM    594  O4   DT A  19      46.060  57.320  90.810  1.00  0.00            
-ATOM    595  N3   DT A  19      46.710  58.870  89.300  1.00  0.00            
-ATOM    596  H3   DT A  19      46.820  58.150  88.590  1.00  0.00            
-ATOM    597  C2   DT A  19      47.050  60.130  88.890  1.00  0.00            
-ATOM    598  O2   DT A  19      47.310  60.360  87.720  1.00  0.00            
-ATOM    599  C3'  DT A  19      47.270  64.780  89.930  1.00  0.00            
-ATOM    600  H3'  DT A  19      46.700  65.490  90.520  1.00  0.00            
-ATOM    601  C2'  DT A  19      46.450  63.530  89.660  1.00  0.00            
-ATOM    602 1H2'  DT A  19      45.800  63.320  90.520  1.00  0.00            
-ATOM    603 2H2'  DT A  19      45.850  63.600  88.760  1.00  0.00            
-ATOM    604  O3'  DT A  19      47.680  65.390  88.680  1.00  0.00            
-ATOM    605  P    DA A  20      46.670  66.080  87.570  1.00  0.00            
-ATOM    606  O1P  DA A  20      47.300  67.350  87.130  1.00  0.00            
-ATOM    607  O2P  DA A  20      45.350  66.220  88.250  1.00  0.00            
-ATOM    608  O5'  DA A  20      46.480  65.090  86.250  1.00  0.00            
-ATOM    609  C5'  DA A  20      47.470  64.970  85.190  1.00  0.00            
-ATOM    610 1H5'  DA A  20      48.440  64.840  85.680  1.00  0.00            
-ATOM    611 2H5'  DA A  20      47.520  65.910  84.640  1.00  0.00            
-ATOM    612  C4'  DA A  20      47.400  63.790  84.140  1.00  0.00            
-ATOM    613  H4'  DA A  20      48.390  63.680  83.700  1.00  0.00            
-ATOM    614  O4'  DA A  20      47.140  62.630  84.890  1.00  0.00            
-ATOM    615  C1'  DA A  20      46.030  61.960  84.340  1.00  0.00            
-ATOM    616  H1'  DA A  20      46.370  61.140  83.670  1.00  0.00            
-ATOM    617  N9   DA A  20      45.230  61.430  85.440  1.00  0.00            
-ATOM    618  C8   DA A  20      44.710  62.110  86.520  1.00  0.00            
-ATOM    619  H8   DA A  20      44.840  63.180  86.620  1.00  0.00            
-ATOM    620  N7   DA A  20      44.080  61.360  87.390  1.00  0.00            
-ATOM    621  C5   DA A  20      44.240  60.080  86.830  1.00  0.00            
-ATOM    622  C6   DA A  20      43.910  58.770  87.220  1.00  0.00            
-ATOM    623  N6   DA A  20      43.310  58.470  88.350  1.00  0.00            
-ATOM    624  H61  DA A  20      43.150  57.490  88.550  1.00  0.00            
-ATOM    625  H62  DA A  20      43.040  59.230  88.940  1.00  0.00            
-ATOM    626  N1   DA A  20      44.220  57.710  86.480  1.00  0.00            
-ATOM    627  C2   DA A  20      44.840  57.910  85.320  1.00  0.00            
-ATOM    628  H2   DA A  20      45.070  57.040  84.730  1.00  0.00            
-ATOM    629  N3   DA A  20      45.230  59.080  84.830  1.00  0.00            
-ATOM    630  C4   DA A  20      44.910  60.120  85.640  1.00  0.00            
-ATOM    631  C3'  DA A  20      46.400  63.770  82.930  1.00  0.00            
-ATOM    632  H3'  DA A  20      46.100  64.770  82.640  1.00  0.00            
-ATOM    633  C2'  DA A  20      45.250  62.990  83.530  1.00  0.00            
-ATOM    634 1H2'  DA A  20      44.660  63.640  84.180  1.00  0.00            
-ATOM    635 2H2'  DA A  20      44.610  62.510  82.790  1.00  0.00            
-ATOM    636  O3'  DA A  20      46.930  63.050  81.780  1.00  0.00            
-ATOM    637  P    DA A  21      46.130  62.860  80.350  1.00  0.00            
-ATOM    638  O1P  DA A  21      47.050  63.280  79.270  1.00  0.00            
-ATOM    639  O2P  DA A  21      44.870  63.620  80.480  1.00  0.00            
-ATOM    640  O5'  DA A  21      45.730  61.260  80.100  1.00  0.00            
-ATOM    641  C5'  DA A  21      46.670  60.260  79.610  1.00  0.00            
-ATOM    642 1H5'  DA A  21      47.550  60.340  80.250  1.00  0.00            
-ATOM    643 2H5'  DA A  21      46.980  60.530  78.610  1.00  0.00            
-ATOM    644  C4'  DA A  21      46.270  58.730  79.620  1.00  0.00            
-ATOM    645  H4'  DA A  21      47.200  58.160  79.580  1.00  0.00            
-ATOM    646  O4'  DA A  21      45.670  58.480  80.880  1.00  0.00            
-ATOM    647  C1'  DA A  21      44.330  58.070  80.650  1.00  0.00            
-ATOM    648  H1'  DA A  21      44.270  56.990  80.770  1.00  0.00            
-ATOM    649  N9   DA A  21      43.460  58.740  81.620  1.00  0.00            
-ATOM    650  C8   DA A  21      43.190  60.080  81.780  1.00  0.00            
-ATOM    651  H8   DA A  21      43.610  60.830  81.130  1.00  0.00            
-ATOM    652  N7   DA A  21      42.400  60.360  82.800  1.00  0.00            
-ATOM    653  C5   DA A  21      42.180  59.080  83.330  1.00  0.00            
-ATOM    654  C6   DA A  21      41.500  58.580  84.460  1.00  0.00            
-ATOM    655  N6   DA A  21      40.880  59.350  85.330  1.00  0.00            
-ATOM    656  H61  DA A  21      40.450  58.920  86.140  1.00  0.00            
-ATOM    657  H62  DA A  21      40.880  60.330  85.140  1.00  0.00            
-ATOM    658  N1   DA A  21      41.450  57.280  84.750  1.00  0.00            
-ATOM    659  C2   DA A  21      42.070  56.440  83.920  1.00  0.00            
-ATOM    660  H2   DA A  21      42.010  55.390  84.160  1.00  0.00            
-ATOM    661  N3   DA A  21      42.760  56.750  82.840  1.00  0.00            
-ATOM    662  C4   DA A  21      42.790  58.090  82.610  1.00  0.00            
-ATOM    663  C3'  DA A  21      45.320  58.060  78.570  1.00  0.00            
-ATOM    664  H3'  DA A  21      45.440  58.500  77.580  1.00  0.00            
-ATOM    665  C2'  DA A  21      43.990  58.420  79.200  1.00  0.00            
-ATOM    666 1H2'  DA A  21      43.790  59.480  79.070  1.00  0.00            
-ATOM    667 2H2'  DA A  21      43.170  57.810  78.820  1.00  0.00            
-ATOM    668  O3'  DA A  21      45.470  56.600  78.510  1.00  0.00            
-ATOM    669  P    DA A  22      44.650  55.600  77.480  1.00  0.00            
-ATOM    670  O1P  DA A  22      45.630  54.730  76.800  1.00  0.00            
-ATOM    671  O2P  DA A  22      43.800  56.470  76.630  1.00  0.00            
-ATOM    672  O5'  DA A  22      43.620  54.590  78.290  1.00  0.00            
-ATOM    673  C5'  DA A  22      44.000  53.290  78.790  1.00  0.00            
-ATOM    674 1H5'  DA A  22      44.820  53.470  79.490  1.00  0.00            
-ATOM    675 2H5'  DA A  22      44.410  52.710  77.960  1.00  0.00            
-ATOM    676  C4'  DA A  22      42.950  52.400  79.550  1.00  0.00            
-ATOM    677  H4'  DA A  22      43.530  51.630  80.070  1.00  0.00            
-ATOM    678  O4'  DA A  22      42.340  53.210  80.530  1.00  0.00            
-ATOM    679  C1'  DA A  22      41.000  53.450  80.120  1.00  0.00            
-ATOM    680  H1'  DA A  22      40.350  52.900  80.810  1.00  0.00            
-ATOM    681  N9   DA A  22      40.690  54.880  80.240  1.00  0.00            
-ATOM    682  C8   DA A  22      41.080  55.960  79.470  1.00  0.00            
-ATOM    683  H8   DA A  22      41.700  55.870  78.590  1.00  0.00            
-ATOM    684  N7   DA A  22      40.650  57.120  79.910  1.00  0.00            
-ATOM    685  C5   DA A  22      39.910  56.750  81.040  1.00  0.00            
-ATOM    686  C6   DA A  22      39.180  57.450  82.030  1.00  0.00            
-ATOM    687  N6   DA A  22      39.080  58.760  82.080  1.00  0.00            
-ATOM    688  H61  DA A  22      38.560  59.190  82.820  1.00  0.00            
-ATOM    689  H62  DA A  22      39.570  59.270  81.370  1.00  0.00            
-ATOM    690  N1   DA A  22      38.570  56.810  83.020  1.00  0.00            
-ATOM    691  C2   DA A  22      38.660  55.490  83.060  1.00  0.00            
-ATOM    692  H2   DA A  22      38.140  55.000  83.880  1.00  0.00            
-ATOM    693  N3   DA A  22      39.290  54.690  82.230  1.00  0.00            
-ATOM    694  C4   DA A  22      39.920  55.400  81.240  1.00  0.00            
-ATOM    695  C3'  DA A  22      41.760  51.660  78.850  1.00  0.00            
-ATOM    696  H3'  DA A  22      42.050  51.290  77.870  1.00  0.00            
-ATOM    697  C2'  DA A  22      40.820  52.850  78.730  1.00  0.00            
-ATOM    698 1H2'  DA A  22      41.160  53.540  77.960  1.00  0.00            
-ATOM    699 2H2'  DA A  22      39.790  52.550  78.550  1.00  0.00            
-ATOM    700  O3'  DA A  22      41.190  50.590  79.670  1.00  0.00            
-ATOM    701  P    DG A  23      39.990  49.540  79.240  1.00  0.00            
-ATOM    702  O1P  DG A  23      40.380  48.180  79.720  1.00  0.00            
-ATOM    703  O2P  DG A  23      39.740  49.680  77.790  1.00  0.00            
-ATOM    704  O5'  DG A  23      38.550  49.850  80.010  1.00  0.00            
-ATOM    705  C5'  DG A  23      38.220  49.260  81.280  1.00  0.00            
-ATOM    706 1H5'  DG A  23      39.000  49.590  81.970  1.00  0.00            
-ATOM    707 2H5'  DG A  23      38.310  48.180  81.180  1.00  0.00            
-ATOM    708  C4'  DG A  23      36.850  49.560  82.000  1.00  0.00            
-ATOM    709  H4'  DG A  23      36.930  49.090  82.980  1.00  0.00            
-ATOM    710  O4'  DG A  23      36.790  50.950  82.230  1.00  0.00            
-ATOM    711  C1'  DG A  23      35.790  51.480  81.380  1.00  0.00            
-ATOM    712  H1'  DG A  23      34.960  51.800  82.020  1.00  0.00            
-ATOM    713  N9   DG A  23      36.290  52.670  80.670  1.00  0.00            
-ATOM    714  C8   DG A  23      37.150  52.810  79.610  1.00  0.00            
-ATOM    715  H8   DG A  23      37.630  51.970  79.130  1.00  0.00            
-ATOM    716  N7   DG A  23      37.350  54.050  79.250  1.00  0.00            
-ATOM    717  C5   DG A  23      36.580  54.790  80.160  1.00  0.00            
-ATOM    718  C6   DG A  23      36.380  56.200  80.360  1.00  0.00            
-ATOM    719  O6   DG A  23      36.860  57.170  79.780  1.00  0.00            
-ATOM    720  N1   DG A  23      35.490  56.490  81.370  1.00  0.00            
-ATOM    721  H1   DG A  23      35.330  57.460  81.550  1.00  0.00            
-ATOM    722  C2   DG A  23      34.880  55.560  82.130  1.00  0.00            
-ATOM    723  N2   DG A  23      34.020  55.940  83.030  1.00  0.00            
-ATOM    724  H21  DG A  23      33.880  56.940  83.190  1.00  0.00            
-ATOM    725  H22  DG A  23      33.590  55.220  83.560  1.00  0.00            
-ATOM    726  N3   DG A  23      35.030  54.250  82.010  1.00  0.00            
-ATOM    727  C4   DG A  23      35.910  53.940  81.010  1.00  0.00            
-ATOM    728  C3'  DG A  23      35.440  49.180  81.440  1.00  0.00            
-ATOM    729  H3'  DG A  23      35.480  48.240  80.890  1.00  0.00            
-ATOM    730  C2'  DG A  23      35.270  50.360  80.490  1.00  0.00            
-ATOM    731 1H2'  DG A  23      35.910  50.240  79.610  1.00  0.00            
-ATOM    732 2H2'  DG A  23      34.240  50.510  80.190  1.00  0.00            
-ATOM    733  O3'  DG A  23      34.410  49.150  82.490  1.00  0.00            
-ATOM    734  P    DA A  24      32.830  48.700  82.350  1.00  0.00            
-ATOM    735  O1P  DA A  24      32.490  47.910  83.570  1.00  0.00            
-ATOM    736  O2P  DA A  24      32.660  47.990  81.060  1.00  0.00            
-ATOM    737  O5'  DA A  24      31.760  49.980  82.350  1.00  0.00            
-ATOM    738  C5'  DA A  24      31.160  50.490  83.560  1.00  0.00            
-ATOM    739 1H5'  DA A  24      31.990  50.700  84.230  1.00  0.00            
-ATOM    740 2H5'  DA A  24      30.590  49.680  84.010  1.00  0.00            
-ATOM    741  C4'  DA A  24      30.250  51.780  83.590  1.00  0.00            
-ATOM    742  H4'  DA A  24      30.070  51.980  84.650  1.00  0.00            
-ATOM    743  O4'  DA A  24      31.030  52.860  83.120  1.00  0.00            
-ATOM    744  C1'  DA A  24      30.440  53.360  81.940  1.00  0.00            
-ATOM    745  H1'  DA A  24      30.030  54.360  82.140  1.00  0.00            
-ATOM    746  N9   DA A  24      31.460  53.480  80.880  1.00  0.00            
-ATOM    747  C8   DA A  24      32.230  52.520  80.290  1.00  0.00            
-ATOM    748  H8   DA A  24      32.180  51.470  80.550  1.00  0.00            
-ATOM    749  N7   DA A  24      33.050  52.970  79.370  1.00  0.00            
-ATOM    750  C5   DA A  24      32.800  54.350  79.390  1.00  0.00            
-ATOM    751  C6   DA A  24      33.320  55.490  78.740  1.00  0.00            
-ATOM    752  N6   DA A  24      34.340  55.490  77.910  1.00  0.00            
-ATOM    753  H61  DA A  24      34.690  56.370  77.550  1.00  0.00            
-ATOM    754  H62  DA A  24      34.860  54.640  77.740  1.00  0.00            
-ATOM    755  N1   DA A  24      32.830  56.700  79.010  1.00  0.00            
-ATOM    756  C2   DA A  24      31.850  56.830  79.880  1.00  0.00            
-ATOM    757  H2   DA A  24      31.490  57.840  80.050  1.00  0.00            
-ATOM    758  N3   DA A  24      31.260  55.870  80.580  1.00  0.00            
-ATOM    759  C4   DA A  24      31.810  54.660  80.290  1.00  0.00            
-ATOM    760  C3'  DA A  24      28.850  51.920  82.900  1.00  0.00            
-ATOM    761  H3'  DA A  24      28.360  50.950  82.810  1.00  0.00            
-ATOM    762  C2'  DA A  24      29.300  52.430  81.540  1.00  0.00            
-ATOM    763 1H2'  DA A  24      29.670  51.600  80.940  1.00  0.00            
-ATOM    764 2H2'  DA A  24      28.510  52.970  81.020  1.00  0.00            
-ATOM    765  O3'  DA A  24      27.970  52.890  83.560  1.00  0.00            
-ATOM    766  P    DT A  25      26.400  53.240  83.140  1.00  0.00            
-ATOM    767  O1P  DT A  25      25.690  53.520  84.410  1.00  0.00            
-ATOM    768  O2P  DT A  25      25.900  52.090  82.360  1.00  0.00            
-ATOM    769  O5'  DT A  25      26.250  54.610  82.200  1.00  0.00            
-ATOM    770  C5'  DT A  25      25.990  55.930  82.760  1.00  0.00            
-ATOM    771 1H5'  DT A  25      26.730  56.050  83.560  1.00  0.00            
-ATOM    772 2H5'  DT A  25      25.010  55.910  83.240  1.00  0.00            
-ATOM    773  C4'  DT A  25      26.090  57.240  81.890  1.00  0.00            
-ATOM    774  H4'  DT A  25      26.280  58.050  82.600  1.00  0.00            
-ATOM    775  O4'  DT A  25      27.260  57.120  81.120  1.00  0.00            
-ATOM    776  C1'  DT A  25      26.970  57.450  79.770  1.00  0.00            
-ATOM    777  H1'  DT A  25      27.240  58.490  79.600  1.00  0.00            
-ATOM    778  N1   DT A  25      27.770  56.550  78.910  1.00  0.00            
-ATOM    779  C6   DT A  25      27.590  55.180  78.920  1.00  0.00            
-ATOM    780  H6   DT A  25      26.840  54.760  79.560  1.00  0.00            
-ATOM    781  C5   DT A  25      28.390  54.380  78.170  1.00  0.00            
-ATOM    782  C7   DT A  25      28.150  52.880  78.150  1.00  0.00            
-ATOM    783  H71  DT A  25      27.190  52.630  78.610  1.00  0.00            
-ATOM    784  H72  DT A  25      28.150  52.550  77.110  1.00  0.00            
-ATOM    785  H73  DT A  25      28.960  52.380  78.670  1.00  0.00            
-ATOM    786  C4   DT A  25      29.480  54.940  77.370  1.00  0.00            
-ATOM    787  O4   DT A  25      30.290  54.290  76.720  1.00  0.00            
-ATOM    788  N3   DT A  25      29.570  56.300  77.420  1.00  0.00            
-ATOM    789  H3   DT A  25      30.300  56.740  76.880  1.00  0.00            
-ATOM    790  C2   DT A  25      28.760  57.150  78.120  1.00  0.00            
-ATOM    791  O2   DT A  25      28.920  58.370  78.060  1.00  0.00            
-ATOM    792  C3'  DT A  25      24.960  57.790  80.950  1.00  0.00            
-ATOM    793  H3'  DT A  25      24.000  57.350  81.190  1.00  0.00            
-ATOM    794  C2'  DT A  25      25.460  57.300  79.600  1.00  0.00            
-ATOM    795 1H2'  DT A  25      25.170  56.260  79.450  1.00  0.00            
-ATOM    796 2H2'  DT A  25      25.100  57.910  78.770  1.00  0.00            
-ATOM    797  O3'  DT A  25      24.870  59.250  80.970  1.00  0.00            
-ATOM    798  P    DG A  26      23.750  60.170  80.170  1.00  0.00            
-ATOM    799  O1P  DG A  26      23.350  61.260  81.100  1.00  0.00            
-ATOM    800  O2P  DG A  26      22.670  59.260  79.750  1.00  0.00            
-ATOM    801  O5'  DG A  26      24.370  60.910  78.810  1.00  0.00            
-ATOM    802  C5'  DG A  26      25.040  62.200  78.840  1.00  0.00            
-ATOM    803 1H5'  DG A  26      25.770  62.130  79.650  1.00  0.00            
-ATOM    804 2H5'  DG A  26      24.320  62.950  79.140  1.00  0.00            
-ATOM    805  C4'  DG A  26      25.870  62.760  77.620  1.00  0.00            
-ATOM    806  H4'  DG A  26      26.520  63.530  78.030  1.00  0.00            
-ATOM    807  O4'  DG A  26      26.710  61.720  77.190  1.00  0.00            
-ATOM    808  C1'  DG A  26      26.540  61.520  75.800  1.00  0.00            
-ATOM    809  H1'  DG A  26      27.390  61.950  75.260  1.00  0.00            
-ATOM    810  N9   DG A  26      26.510  60.070  75.570  1.00  0.00            
-ATOM    811  C8   DG A  26      25.700  59.110  76.120  1.00  0.00            
-ATOM    812  H8   DG A  26      24.920  59.360  76.820  1.00  0.00            
-ATOM    813  N7   DG A  26      25.980  57.890  75.750  1.00  0.00            
-ATOM    814  C5   DG A  26      27.080  58.070  74.890  1.00  0.00            
-ATOM    815  C6   DG A  26      27.930  57.140  74.190  1.00  0.00            
-ATOM    816  O6   DG A  26      27.860  55.900  74.180  1.00  0.00            
-ATOM    817  N1   DG A  26      28.930  57.760  73.450  1.00  0.00            
-ATOM    818  H1   DG A  26      29.600  57.170  72.980  1.00  0.00            
-ATOM    819  C2   DG A  26      29.130  59.100  73.420  1.00  0.00            
-ATOM    820  N2   DG A  26      30.130  59.570  72.740  1.00  0.00            
-ATOM    821  H21  DG A  26      30.770  58.940  72.250  1.00  0.00            
-ATOM    822  H22  DG A  26      30.300  60.560  72.760  1.00  0.00            
-ATOM    823  N3   DG A  26      28.380  59.990  74.050  1.00  0.00            
-ATOM    824  C4   DG A  26      27.390  59.400  74.770  1.00  0.00            
-ATOM    825  C3'  DG A  26      25.260  63.410  76.330  1.00  0.00            
-ATOM    826  H3'  DG A  26      24.250  63.770  76.500  1.00  0.00            
-ATOM    827  C2'  DG A  26      25.250  62.210  75.390  1.00  0.00            
-ATOM    828 1H2'  DG A  26      24.390  61.580  75.590  1.00  0.00            
-ATOM    829 2H2'  DG A  26      25.280  62.500  74.330  1.00  0.00            
-ATOM    830  O3'  DG A  26      26.100  64.480  75.820  1.00  0.00            
-ATOM    831  P    DG A  27      25.830  65.380  74.470  1.00  0.00            
-ATOM    832  O1P  DG A  27      26.180  66.780  74.810  1.00  0.00            
-ATOM    833  O2P  DG A  27      24.410  65.150  74.090  1.00  0.00            
-ATOM    834  O5'  DG A  27      26.800  64.910  73.200  1.00  0.00            
-ATOM    835  C5'  DG A  27      28.200  65.280  73.090  1.00  0.00            
-ATOM    836 1H5'  DG A  27      28.650  65.050  74.060  1.00  0.00            
-ATOM    837 2H5'  DG A  27      28.270  66.360  72.960  1.00  0.00            
-ATOM    838  C4'  DG A  27      29.150  64.610  72.030  1.00  0.00            
-ATOM    839  H4'  DG A  27      30.180  64.770  72.370  1.00  0.00            
-ATOM    840  O4'  DG A  27      28.910  63.220  72.090  1.00  0.00            
-ATOM    841  C1'  DG A  27      28.710  62.730  70.780  1.00  0.00            
-ATOM    842  H1'  DG A  27      29.640  62.320  70.370  1.00  0.00            
-ATOM    843  N9   DG A  27      27.680  61.680  70.840  1.00  0.00            
-ATOM    844  C8   DG A  27      26.430  61.740  71.400  1.00  0.00            
-ATOM    845  H8   DG A  27      26.050  62.660  71.820  1.00  0.00            
-ATOM    846  N7   DG A  27      25.790  60.610  71.400  1.00  0.00            
-ATOM    847  C5   DG A  27      26.720  59.720  70.840  1.00  0.00            
-ATOM    848  C6   DG A  27      26.710  58.290  70.670  1.00  0.00            
-ATOM    849  O6   DG A  27      25.830  57.490  70.990  1.00  0.00            
-ATOM    850  N1   DG A  27      27.880  57.790  70.110  1.00  0.00            
-ATOM    851  H1   DG A  27      27.990  56.790  70.050  1.00  0.00            
-ATOM    852  C2   DG A  27      28.930  58.560  69.730  1.00  0.00            
-ATOM    853  N2   DG A  27      29.980  57.970  69.240  1.00  0.00            
-ATOM    854  H21  DG A  27      30.050  56.960  69.190  1.00  0.00            
-ATOM    855  H22  DG A  27      30.780  58.540  69.020  1.00  0.00            
-ATOM    856  N3   DG A  27      28.970  59.880  69.850  1.00  0.00            
-ATOM    857  C4   DG A  27      27.850  60.390  70.440  1.00  0.00            
-ATOM    858  C3'  DG A  27      29.170  64.980  70.510  1.00  0.00            
-ATOM    859  H3'  DG A  27      28.770  65.980  70.330  1.00  0.00            
-ATOM    860  C2'  DG A  27      28.260  63.910  69.940  1.00  0.00            
-ATOM    861 1H2'  DG A  27      27.220  64.160  70.140  1.00  0.00            
-ATOM    862 2H2'  DG A  27      28.430  63.730  68.880  1.00  0.00            
-ATOM    863  O3'  DG A  27      30.490  64.870  69.930  1.00  0.00            
-ATOM    864  P    DC A  28      30.870  65.150  68.350  1.00  0.00            
-ATOM    865  O1P  DC A  28      32.060  66.030  68.330  1.00  0.00            
-ATOM    866  O2P  DC A  28      29.630  65.700  67.730  1.00  0.00            
-ATOM    867  O5'  DC A  28      31.250  63.730  67.580  1.00  0.00            
-ATOM    868  C5'  DC A  28      32.510  63.020  67.720  1.00  0.00            
-ATOM    869 1H5'  DC A  28      32.700  62.940  68.790  1.00  0.00            
-ATOM    870 2H5'  DC A  28      33.310  63.640  67.310  1.00  0.00            
-ATOM    871  C4'  DC A  28      32.690  61.550  67.160  1.00  0.00            
-ATOM    872  H4'  DC A  28      33.530  61.110  67.690  1.00  0.00            
-ATOM    873  O4'  DC A  28      31.530  60.810  67.530  1.00  0.00            
-ATOM    874  C1'  DC A  28      30.960  60.250  66.350  1.00  0.00            
-ATOM    875  H1'  DC A  28      31.280  59.210  66.250  1.00  0.00            
-ATOM    876  N1   DC A  28      29.480  60.350  66.470  1.00  0.00            
-ATOM    877  C6   DC A  28      28.880  61.560  66.710  1.00  0.00            
-ATOM    878  H6   DC A  28      29.500  62.450  66.710  1.00  0.00            
-ATOM    879  C5   DC A  28      27.560  61.630  66.990  1.00  0.00            
-ATOM    880  H5   DC A  28      27.100  62.570  67.210  1.00  0.00            
-ATOM    881  C4   DC A  28      26.870  60.390  67.030  1.00  0.00            
-ATOM    882  N4   DC A  28      25.630  60.340  67.430  1.00  0.00            
-ATOM    883  H41  DC A  28      25.270  59.390  67.500  1.00  0.00            
-ATOM    884  H42  DC A  28      25.200  61.130  67.840  1.00  0.00            
-ATOM    885  N3   DC A  28      27.410  59.230  66.780  1.00  0.00            
-ATOM    886  C2   DC A  28      28.720  59.180  66.490  1.00  0.00            
-ATOM    887  O2   DC A  28      29.200  58.070  66.270  1.00  0.00            
-ATOM    888  C3'  DC A  28      32.940  61.220  65.650  1.00  0.00            
-ATOM    889  H3'  DC A  28      33.450  62.030  65.140  1.00  0.00            
-ATOM    890  C2'  DC A  28      31.510  61.040  65.170  1.00  0.00            
-ATOM    891 1H2'  DC A  28      31.040  62.020  65.070  1.00  0.00            
-ATOM    892 2H2'  DC A  28      31.450  60.480  64.250  1.00  0.00            
-ATOM    893  O3'  DC A  28      33.670  59.970  65.480  1.00  0.00            
-ATOM    894  P    DA A  29      34.170  59.360  64.030  1.00  0.00            
-ATOM    895  O1P  DA A  29      35.640  59.160  64.100  1.00  0.00            
-ATOM    896  O2P  DA A  29      33.650  60.270  62.990  1.00  0.00            
-ATOM    897  O5'  DA A  29      33.490  57.880  63.770  1.00  0.00            
-ATOM    898  C5'  DA A  29      33.970  56.660  64.380  1.00  0.00            
-ATOM    899 1H5'  DA A  29      34.010  56.870  65.440  1.00  0.00            
-ATOM    900 2H5'  DA A  29      34.990  56.490  64.050  1.00  0.00            
-ATOM    901  C4'  DA A  29      33.140  55.330  64.230  1.00  0.00            
-ATOM    902  H4'  DA A  29      33.530  54.640  64.970  1.00  0.00            
-ATOM    903  O4'  DA A  29      31.800  55.630  64.550  1.00  0.00            
-ATOM    904  C1'  DA A  29      31.040  55.530  63.360  1.00  0.00            
-ATOM    905  H1'  DA A  29      30.430  54.630  63.440  1.00  0.00            
-ATOM    906  N9   DA A  29      30.150  56.700  63.210  1.00  0.00            
-ATOM    907  C8   DA A  29      30.440  58.030  63.030  1.00  0.00            
-ATOM    908  H8   DA A  29      31.450  58.400  62.870  1.00  0.00            
-ATOM    909  N7   DA A  29      29.400  58.830  63.080  1.00  0.00            
-ATOM    910  C5   DA A  29      28.360  57.920  63.300  1.00  0.00            
-ATOM    911  C6   DA A  29      26.970  58.040  63.520  1.00  0.00            
-ATOM    912  N6   DA A  29      26.340  59.190  63.590  1.00  0.00            
-ATOM    913  H61  DA A  29      25.360  59.210  63.820  1.00  0.00            
-ATOM    914  H62  DA A  29      26.910  60.010  63.470  1.00  0.00            
-ATOM    915  N1   DA A  29      26.200  56.970  63.700  1.00  0.00            
-ATOM    916  C2   DA A  29      26.770  55.770  63.660  1.00  0.00            
-ATOM    917  H2   DA A  29      26.120  54.920  63.800  1.00  0.00            
-ATOM    918  N3   DA A  29      28.050  55.490  63.480  1.00  0.00            
-ATOM    919  C4   DA A  29      28.800  56.630  63.330  1.00  0.00            
-ATOM    920  C3'  DA A  29      33.060  54.510  62.900  1.00  0.00            
-ATOM    921  H3'  DA A  29      34.010  54.530  62.350  1.00  0.00            
-ATOM    922  C2'  DA A  29      32.000  55.330  62.200  1.00  0.00            
-ATOM    923 1H2'  DA A  29      32.420  56.280  61.860  1.00  0.00            
-ATOM    924 2H2'  DA A  29      31.540  54.770  61.400  1.00  0.00            
-ATOM    925  O3'  DA A  29      32.590  53.140  63.080  1.00  0.00            
-ATOM    926  P    DT A  30      32.360  52.030  61.870  1.00  0.00            
-ATOM    927  O1P  DT A  30      32.920  50.730  62.320  1.00  0.00            
-ATOM    928  O2P  DT A  30      32.880  52.600  60.620  1.00  0.00            
-ATOM    929  O5'  DT A  30      30.750  51.740  61.610  1.00  0.00            
-ATOM    930  C5'  DT A  30      30.030  50.700  62.300  1.00  0.00            
-ATOM    931 1H5'  DT A  30      30.110  50.930  63.370  1.00  0.00            
-ATOM    932 2H5'  DT A  30      30.540  49.760  62.140  1.00  0.00            
-ATOM    933  C4'  DT A  30      28.500  50.490  62.000  1.00  0.00            
-ATOM    934  H4'  DT A  30      28.110  49.890  62.820  1.00  0.00            
-ATOM    935  O4'  DT A  30      27.890  51.770  62.070  1.00  0.00            
-ATOM    936  C1'  DT A  30      27.400  52.100  60.790  1.00  0.00            
-ATOM    937  H1'  DT A  30      26.320  51.910  60.820  1.00  0.00            
-ATOM    938  N1   DT A  30      27.640  53.530  60.470  1.00  0.00            
-ATOM    939  C6   DT A  30      28.880  54.040  60.110  1.00  0.00            
-ATOM    940  H6   DT A  30      29.740  53.390  60.050  1.00  0.00            
-ATOM    941  C5   DT A  30      29.030  55.380  59.860  1.00  0.00            
-ATOM    942  C7   DT A  30      30.360  55.930  59.370  1.00  0.00            
-ATOM    943  H71  DT A  30      31.100  55.150  59.230  1.00  0.00            
-ATOM    944  H72  DT A  30      30.200  56.450  58.430  1.00  0.00            
-ATOM    945  H73  DT A  30      30.720  56.670  60.090  1.00  0.00            
-ATOM    946  C4   DT A  30      27.920  56.300  60.030  1.00  0.00            
-ATOM    947  O4   DT A  30      27.940  57.520  59.940  1.00  0.00            
-ATOM    948  N3   DT A  30      26.730  55.700  60.340  1.00  0.00            
-ATOM    949  H3   DT A  30      25.930  56.300  60.450  1.00  0.00            
-ATOM    950  C2   DT A  30      26.510  54.360  60.510  1.00  0.00            
-ATOM    951  O2   DT A  30      25.360  53.950  60.640  1.00  0.00            
-ATOM    952  C3'  DT A  30      28.000  49.840  60.670  1.00  0.00            
-ATOM    953  H3'  DT A  30      28.730  49.120  60.290  1.00  0.00            
-ATOM    954  C2'  DT A  30      27.980  51.080  59.800  1.00  0.00            
-ATOM    955 1H2'  DT A  30      29.000  51.350  59.510  1.00  0.00            
-ATOM    956 2H2'  DT A  30      27.340  50.950  58.940  1.00  0.00            
-ATOM    957  O3'  DT A  30      26.670  49.240  60.760  1.00  0.00            
-ATOM    958  P    DT A  31      25.880  48.410  59.560  1.00  0.00            
-ATOM    959  O1P  DT A  31      25.210  47.240  60.190  1.00  0.00            
-ATOM    960  O2P  DT A  31      26.860  48.100  58.490  1.00  0.00            
-ATOM    961  O5'  DT A  31      24.670  49.300  58.860  1.00  0.00            
-ATOM    962  C5'  DT A  31      23.310  49.250  59.340  1.00  0.00            
-ATOM    963 1H5'  DT A  31      23.360  49.470  60.410  1.00  0.00            
-ATOM    964 2H5'  DT A  31      22.950  48.220  59.250  1.00  0.00            
-ATOM    965  C4'  DT A  31      22.200  50.200  58.760  1.00  0.00            
-ATOM    966  H4'  DT A  31      21.350  50.130  59.440  1.00  0.00            
-ATOM    967  O4'  DT A  31      22.710  51.510  58.860  1.00  0.00            
-ATOM    968  C1'  DT A  31      22.760  52.090  57.580  1.00  0.00            
-ATOM    969  H1'  DT A  31      21.900  52.750  57.490  1.00  0.00            
-ATOM    970  N1   DT A  31      24.010  52.870  57.420  1.00  0.00            
-ATOM    971  C6   DT A  31      25.250  52.280  57.230  1.00  0.00            
-ATOM    972  H6   DT A  31      25.350  51.210  57.250  1.00  0.00            
-ATOM    973  C5   DT A  31      26.370  53.050  57.040  1.00  0.00            
-ATOM    974  C7   DT A  31      27.710  52.410  56.740  1.00  0.00            
-ATOM    975  H71  DT A  31      27.630  51.320  56.690  1.00  0.00            
-ATOM    976  H72  DT A  31      28.070  52.790  55.780  1.00  0.00            
-ATOM    977  H73  DT A  31      28.430  52.710  57.500  1.00  0.00            
-ATOM    978  C4   DT A  31      26.280  54.500  57.120  1.00  0.00            
-ATOM    979  O4   DT A  31      27.220  55.290  57.040  1.00  0.00            
-ATOM    980  N3   DT A  31      25.020  55.000  57.320  1.00  0.00            
-ATOM    981  H3   DT A  31      24.930  56.000  57.340  1.00  0.00            
-ATOM    982  C2   DT A  31      23.870  54.270  57.400  1.00  0.00            
-ATOM    983  O2   DT A  31      22.780  54.840  57.400  1.00  0.00            
-ATOM    984  C3'  DT A  31      21.600  50.060  57.310  1.00  0.00            
-ATOM    985  H3'  DT A  31      21.670  49.030  56.960  1.00  0.00            
-ATOM    986  C2'  DT A  31      22.560  50.960  56.570  1.00  0.00            
-ATOM    987 1H2'  DT A  31      23.490  50.420  56.380  1.00  0.00            
-ATOM    988 2H2'  DT A  31      22.120  51.330  55.650  1.00  0.00            
-ATOM    989  O3'  DT A  31      20.220  50.550  57.180  1.00  0.00            
-ATOM    990  P    DT A  32      19.290  50.480  55.810  1.00  0.00            
-ATOM    991  O1P  DT A  32      17.910  50.130  56.260  1.00  0.00            
-ATOM    992  O2P  DT A  32      19.930  49.530  54.880  1.00  0.00            
-ATOM    993  O5'  DT A  32      19.150  51.940  55.020  1.00  0.00            
-ATOM    994  C5'  DT A  32      18.080  52.880  55.270  1.00  0.00            
-ATOM    995 1H5'  DT A  32      18.050  53.010  56.360  1.00  0.00            
-ATOM    996 2H5'  DT A  32      17.140  52.410  55.000  1.00  0.00            
-ATOM    997  C4'  DT A  32      18.100  54.340  54.670  1.00  0.00            
-ATOM    998  H4'  DT A  32      17.410  54.930  55.290  1.00  0.00            
-ATOM    999  O4'  DT A  32      19.390  54.840  54.910  1.00  0.00            
-ATOM   1000  C1'  DT A  32      19.960  55.250  53.690  1.00  0.00            
-ATOM   1001  H1'  DT A  32      19.860  56.340  53.620  1.00  0.00            
-ATOM   1002  N1   DT A  32      21.400  54.880  53.690  1.00  0.00            
-ATOM   1003  C6   DT A  32      21.820  53.560  53.610  1.00  0.00            
-ATOM   1004  H6   DT A  32      21.090  52.770  53.530  1.00  0.00            
-ATOM   1005  C5   DT A  32      23.140  53.260  53.650  1.00  0.00            
-ATOM   1006  C7   DT A  32      23.610  51.820  53.470  1.00  0.00            
-ATOM   1007  H71  DT A  32      22.770  51.140  53.350  1.00  0.00            
-ATOM   1008  H72  DT A  32      24.260  51.780  52.600  1.00  0.00            
-ATOM   1009  H73  DT A  32      24.210  51.540  54.340  1.00  0.00            
-ATOM   1010  C4   DT A  32      24.140  54.300  53.880  1.00  0.00            
-ATOM   1011  O4   DT A  32      25.340  54.120  54.020  1.00  0.00            
-ATOM   1012  N3   DT A  32      23.620  55.570  53.960  1.00  0.00            
-ATOM   1013  H3   DT A  32      24.290  56.320  54.060  1.00  0.00            
-ATOM   1014  C2   DT A  32      22.310  55.920  53.810  1.00  0.00            
-ATOM   1015  O2   DT A  32      21.990  57.110  53.730  1.00  0.00            
-ATOM   1016  C3'  DT A  32      17.740  54.700  53.190  1.00  0.00            
-ATOM   1017  H3'  DT A  32      17.070  53.960  52.750  1.00  0.00            
-ATOM   1018  C2'  DT A  32      19.120  54.630  52.570  1.00  0.00            
-ATOM   1019 1H2'  DT A  32      19.390  53.590  52.390  1.00  0.00            
-ATOM   1020 2H2'  DT A  32      19.180  55.210  51.650  1.00  0.00            
-ATOM   1021  O3'  DT A  32      17.170  56.040  53.030  1.00  0.00            
-ATOM   1022  P    DC A  33      16.590  56.700  51.620  1.00  0.00            
-ATOM   1023  O1P  DC A  33      15.290  57.340  51.940  1.00  0.00            
-ATOM   1024  O2P  DC A  33      16.560  55.600  50.630  1.00  0.00            
-ATOM   1025  O5'  DC A  33      17.570  57.890  51.000  1.00  0.00            
-ATOM   1026  C5'  DC A  33      17.500  59.290  51.380  1.00  0.00            
-ATOM   1027 1H5'  DC A  33      17.500  59.300  52.470  1.00  0.00            
-ATOM   1028 2H5'  DC A  33      16.540  59.690  51.060  1.00  0.00            
-ATOM   1029  C4'  DC A  33      18.630  60.310  50.950  1.00  0.00            
-ATOM   1030  H4'  DC A  33      18.560  61.140  51.650  1.00  0.00            
-ATOM   1031  O4'  DC A  33      19.860  59.670  51.220  1.00  0.00            
-ATOM   1032  C1'  DC A  33      20.680  59.700  50.070  1.00  0.00            
-ATOM   1033  H1'  DC A  33      21.420  60.510  50.190  1.00  0.00            
-ATOM   1034  N1   DC A  33      21.360  58.390  49.930  1.00  0.00            
-ATOM   1035  C6   DC A  33      20.660  57.210  50.000  1.00  0.00            
-ATOM   1036  H6   DC A  33      19.590  57.250  50.110  1.00  0.00            
-ATOM   1037  C5   DC A  33      21.310  56.020  49.970  1.00  0.00            
-ATOM   1038  H5   DC A  33      20.780  55.100  50.050  1.00  0.00            
-ATOM   1039  C4   DC A  33      22.730  56.080  49.890  1.00  0.00            
-ATOM   1040  N4   DC A  33      23.420  54.990  49.980  1.00  0.00            
-ATOM   1041  H41  DC A  33      24.440  55.140  50.050  1.00  0.00            
-ATOM   1042  H42  DC A  33      23.020  54.140  50.300  1.00  0.00            
-ATOM   1043  N3   DC A  33      23.400  57.190  49.740  1.00  0.00            
-ATOM   1044  C2   DC A  33      22.740  58.370  49.760  1.00  0.00            
-ATOM   1045  O2   DC A  33      23.370  59.410  49.580  1.00  0.00            
-ATOM   1046  C3'  DC A  33      18.760  60.960  49.530  1.00  0.00            
-ATOM   1047  H3'  DC A  33      17.810  60.930  48.990  1.00  0.00            
-ATOM   1048  C2'  DC A  33      19.770  60.020  48.890  1.00  0.00            
-ATOM   1049 1H2'  DC A  33      19.270  59.130  48.520  1.00  0.00            
-ATOM   1050 2H2'  DC A  33      20.330  60.510  48.090  1.00  0.00            
-ATOM   1051  O3'  DC A  33      19.270  62.320  49.560  1.00  0.00            
-ATOM   1052  P    DT A  34      19.550  63.290  48.250  1.00  0.00            
-ATOM   1053  O1P  DT A  34      19.070  64.650  48.600  1.00  0.00            
-ATOM   1054  O2P  DT A  34      18.880  62.650  47.090  1.00  0.00            
-ATOM   1055  O5'  DT A  34      21.160  63.420  47.890  1.00  0.00            
-ATOM   1056  C5'  DT A  34      22.060  64.340  48.560  1.00  0.00            
-ATOM   1057 1H5'  DT A  34      21.870  64.220  49.630  1.00  0.00            
-ATOM   1058 2H5'  DT A  34      21.780  65.360  48.310  1.00  0.00            
-ATOM   1059  C4'  DT A  34      23.630  64.210  48.400  1.00  0.00            
-ATOM   1060  H4'  DT A  34      24.060  64.680  49.290  1.00  0.00            
-ATOM   1061  O4'  DT A  34      23.930  62.840  48.480  1.00  0.00            
-ATOM   1062  C1'  DT A  34      24.840  62.490  47.450  1.00  0.00            
-ATOM   1063  H1'  DT A  34      25.870  62.510  47.840  1.00  0.00            
-ATOM   1064  N1   DT A  34      24.470  61.140  46.970  1.00  0.00            
-ATOM   1065  C6   DT A  34      23.190  60.880  46.530  1.00  0.00            
-ATOM   1066  H6   DT A  34      22.480  61.690  46.520  1.00  0.00            
-ATOM   1067  C5   DT A  34      22.820  59.610  46.200  1.00  0.00            
-ATOM   1068  C7   DT A  34      21.420  59.360  45.680  1.00  0.00            
-ATOM   1069  H71  DT A  34      20.910  60.290  45.460  1.00  0.00            
-ATOM   1070  H72  DT A  34      21.490  58.750  44.780  1.00  0.00            
-ATOM   1071  H73  DT A  34      20.860  58.790  46.430  1.00  0.00            
-ATOM   1072  C4   DT A  34      23.760  58.500  46.330  1.00  0.00            
-ATOM   1073  O4   DT A  34      23.480  57.320  46.130  1.00  0.00            
-ATOM   1074  N3   DT A  34      25.030  58.870  46.710  1.00  0.00            
-ATOM   1075  H3   DT A  34      25.720  58.150  46.850  1.00  0.00            
-ATOM   1076  C2   DT A  34      25.440  60.140  47.020  1.00  0.00            
-ATOM   1077  O2   DT A  34      26.620  60.360  47.280  1.00  0.00            
-ATOM   1078  C3'  DT A  34      24.430  64.810  47.200  1.00  0.00            
-ATOM   1079  H3'  DT A  34      23.840  65.530  46.640  1.00  0.00            
-ATOM   1080  C2'  DT A  34      24.700  63.560  46.370  1.00  0.00            
-ATOM   1081 1H2'  DT A  34      23.840  63.360  45.720  1.00  0.00            
-ATOM   1082 2H2'  DT A  34      25.600  63.630  45.770  1.00  0.00            
-ATOM   1083  O3'  DT A  34      25.680  65.420  47.620  1.00  0.00            
-ATOM   1084  P    DA A  35      26.790  66.110  46.610  1.00  0.00            
-ATOM   1085  O1P  DA A  35      27.240  67.370  47.250  1.00  0.00            
-ATOM   1086  O2P  DA A  35      26.140  66.240  45.290  1.00  0.00            
-ATOM   1087  O5'  DA A  35      28.110  65.110  46.450  1.00  0.00            
-ATOM   1088  C5'  DA A  35      29.150  64.980  47.460  1.00  0.00            
-ATOM   1089 1H5'  DA A  35      28.630  64.850  48.410  1.00  0.00            
-ATOM   1090 2H5'  DA A  35      29.700  65.920  47.530  1.00  0.00            
-ATOM   1091  C4'  DA A  35      30.190  63.800  47.390  1.00  0.00            
-ATOM   1092  H4'  DA A  35      30.620  63.680  48.390  1.00  0.00            
-ATOM   1093  O4'  DA A  35      29.440  62.640  47.120  1.00  0.00            
-ATOM   1094  C1'  DA A  35      30.010  61.970  46.020  1.00  0.00            
-ATOM   1095  H1'  DA A  35      30.670  61.160  46.360  1.00  0.00            
-ATOM   1096  N9   DA A  35      28.920  61.440  45.190  1.00  0.00            
-ATOM   1097  C8   DA A  35      27.820  62.110  44.710  1.00  0.00            
-ATOM   1098  H8   DA A  35      27.690  63.170  44.880  1.00  0.00            
-ATOM   1099  N7   DA A  35      26.970  61.360  44.050  1.00  0.00            
-ATOM   1100  C5   DA A  35      27.570  60.090  44.150  1.00  0.00            
-ATOM   1101  C6   DA A  35      27.210  58.780  43.780  1.00  0.00            
-ATOM   1102  N6   DA A  35      26.060  58.480  43.200  1.00  0.00            
-ATOM   1103  H61  DA A  35      25.870  57.500  43.030  1.00  0.00            
-ATOM   1104  H62  DA A  35      25.460  59.230  42.950  1.00  0.00            
-ATOM   1105  N1   DA A  35      27.980  57.730  44.030  1.00  0.00            
-ATOM   1106  C2   DA A  35      29.140  57.940  44.650  1.00  0.00            
-ATOM   1107  H2   DA A  35      29.760  57.070  44.840  1.00  0.00            
-ATOM   1108  N3   DA A  35      29.610  59.100  45.070  1.00  0.00            
-ATOM   1109  C4   DA A  35      28.760  60.130  44.820  1.00  0.00            
-ATOM   1110  C3'  DA A  35      31.410  63.790  46.410  1.00  0.00            
-ATOM   1111  H3'  DA A  35      31.690  64.790  46.110  1.00  0.00            
-ATOM   1112  C2'  DA A  35      30.810  63.010  45.250  1.00  0.00            
-ATOM   1113 1H2'  DA A  35      30.160  63.660  44.660  1.00  0.00            
-ATOM   1114 2H2'  DA A  35      31.570  62.540  44.620  1.00  0.00            
-ATOM   1115  O3'  DA A  35      32.560  63.080  46.930  1.00  0.00            
-ATOM   1116  P    DC A  36      33.990  62.890  46.140  1.00  0.00            
-ATOM   1117  O1P  DC A  36      35.070  63.320  47.060  1.00  0.00            
-ATOM   1118  O2P  DC A  36      33.860  63.650  44.870  1.00  0.00            
-ATOM   1119  O5'  DC A  36      34.240  61.310  45.740  1.00  0.00            
-ATOM   1120  C5'  DC A  36      34.600  60.260  46.680  1.00  0.00            
-ATOM   1121 1H5'  DC A  36      33.890  60.340  47.510  1.00  0.00            
-ATOM   1122 2H5'  DC A  36      35.590  60.480  47.080  1.00  0.00            
-ATOM   1123  C4'  DC A  36      34.550  58.750  46.220  1.00  0.00            
-ATOM   1124  H4'  DC A  36      34.510  58.140  47.120  1.00  0.00            
-ATOM   1125  O4'  DC A  36      33.330  58.580  45.530  1.00  0.00            
-ATOM   1126  C1'  DC A  36      33.610  58.120  44.220  1.00  0.00            
-ATOM   1127  H1'  DC A  36      33.490  57.030  44.210  1.00  0.00            
-ATOM   1128  N1   DC A  36      32.670  58.770  43.280  1.00  0.00            
-ATOM   1129  C6   DC A  36      32.620  60.140  43.160  1.00  0.00            
-ATOM   1130  H6   DC A  36      33.340  60.740  43.710  1.00  0.00            
-ATOM   1131  C5   DC A  36      31.640  60.730  42.420  1.00  0.00            
-ATOM   1132  H5   DC A  36      31.590  61.800  42.370  1.00  0.00            
-ATOM   1133  C4   DC A  36      30.700  59.860  41.810  1.00  0.00            
-ATOM   1134  N4   DC A  36      29.670  60.340  41.190  1.00  0.00            
-ATOM   1135  H41  DC A  36      29.040  59.630  40.820  1.00  0.00            
-ATOM   1136  H42  DC A  36      29.510  61.310  41.160  1.00  0.00            
-ATOM   1137  N3   DC A  36      30.760  58.560  41.870  1.00  0.00            
-ATOM   1138  C2   DC A  36      31.750  57.980  42.600  1.00  0.00            
-ATOM   1139  O2   DC A  36      31.780  56.760  42.620  1.00  0.00            
-ATOM   1140  C3'  DC A  36      35.650  58.080  45.320  1.00  0.00            
-ATOM   1141  H3'  DC A  36      36.630  58.530  45.480  1.00  0.00            
-ATOM   1142  C2'  DC A  36      35.080  58.440  43.960  1.00  0.00            
-ATOM   1143 1H2'  DC A  36      35.250  59.490  43.750  1.00  0.00            
-ATOM   1144 2H2'  DC A  36      35.500  57.810  43.180  1.00  0.00            
-ATOM   1145  O3'  DC A  36      35.710  56.630  45.460  1.00  0.00            
-ATOM   1146  P    DC A  37      36.760  55.640  44.650  1.00  0.00            
-ATOM   1147  O1P  DC A  37      37.440  54.760  45.630  1.00  0.00            
-ATOM   1148  O2P  DC A  37      37.610  56.510  43.810  1.00  0.00            
-ATOM   1149  O5'  DC A  37      35.960  54.640  43.610  1.00  0.00            
-ATOM   1150  C5'  DC A  37      35.400  53.370  43.990  1.00  0.00            
-ATOM   1151 1H5'  DC A  37      34.690  53.580  44.790  1.00  0.00            
-ATOM   1152 2H5'  DC A  37      36.200  52.760  44.420  1.00  0.00            
-ATOM   1153  C4'  DC A  37      34.640  52.520  42.900  1.00  0.00            
-ATOM   1154  H4'  DC A  37      34.030  51.800  43.450  1.00  0.00            
-ATOM   1155  O4'  DC A  37      33.760  53.400  42.220  1.00  0.00            
-ATOM   1156  C1'  DC A  37      34.250  53.570  40.910  1.00  0.00            
-ATOM   1157  H1'  DC A  37      33.590  52.990  40.250  1.00  0.00            
-ATOM   1158  N1   DC A  37      34.160  55.010  40.520  1.00  0.00            
-ATOM   1159  C6   DC A  37      35.060  55.970  40.930  1.00  0.00            
-ATOM   1160  H6   DC A  37      35.910  55.690  41.530  1.00  0.00            
-ATOM   1161  C5   DC A  37      34.850  57.270  40.600  1.00  0.00            
-ATOM   1162  H5   DC A  37      35.550  58.020  40.930  1.00  0.00            
-ATOM   1163  C4   DC A  37      33.690  57.570  39.840  1.00  0.00            
-ATOM   1164  N4   DC A  37      33.370  58.810  39.580  1.00  0.00            
-ATOM   1165  H41  DC A  37      32.510  58.950  39.070  1.00  0.00            
-ATOM   1166  H42  DC A  37      33.950  59.540  39.920  1.00  0.00            
-ATOM   1167  N3   DC A  37      32.830  56.670  39.420  1.00  0.00            
-ATOM   1168  C2   DC A  37      33.070  55.380  39.740  1.00  0.00            
-ATOM   1169  O2   DC A  37      32.290  54.540  39.290  1.00  0.00            
-ATOM   1170  C3'  DC A  37      35.370  51.730  41.760  1.00  0.00            
-ATOM   1171  H3'  DC A  37      36.310  51.300  42.120  1.00  0.00            
-ATOM   1172  C2'  DC A  37      35.620  52.900  40.820  1.00  0.00            
-ATOM   1173 1H2'  DC A  37      36.410  53.540  41.210  1.00  0.00            
-ATOM   1174 2H2'  DC A  37      35.860  52.570  39.810  1.00  0.00            
-ATOM   1175  O3'  DC A  37      34.520  50.700  41.150  1.00  0.00            
-ATOM   1176  P    DG A  38      34.960  49.590  40.010  1.00  0.00            
-ATOM   1177  O1P  DG A  38      34.500  48.250  40.460  1.00  0.00            
-ATOM   1178  O2P  DG A  38      36.400  49.740  39.740  1.00  0.00            
-ATOM   1179  O5'  DG A  38      34.180  49.850  38.570  1.00  0.00            
-ATOM   1180  C5'  DG A  38      32.900  49.260  38.270  1.00  0.00            
-ATOM   1181 1H5'  DG A  38      32.230  49.610  39.060  1.00  0.00            
-ATOM   1182 2H5'  DG A  38      32.990  48.190  38.380  1.00  0.00            
-ATOM   1183  C4'  DG A  38      32.180  49.560  36.900  1.00  0.00            
-ATOM   1184  H4'  DG A  38      31.190  49.120  36.980  1.00  0.00            
-ATOM   1185  O4'  DG A  38      32.000  50.960  36.830  1.00  0.00            
-ATOM   1186  C1'  DG A  38      32.870  51.450  35.840  1.00  0.00            
-ATOM   1187  H1'  DG A  38      32.250  51.790  35.010  1.00  0.00            
-ATOM   1188  N9   DG A  38      33.640  52.610  36.320  1.00  0.00            
-ATOM   1189  C8   DG A  38      34.670  52.730  37.230  1.00  0.00            
-ATOM   1190  H8   DG A  38      35.090  51.880  37.750  1.00  0.00            
-ATOM   1191  N7   DG A  38      35.080  53.950  37.410  1.00  0.00            
-ATOM   1192  C5   DG A  38      34.250  54.710  36.570  1.00  0.00            
-ATOM   1193  C6   DG A  38      34.150  56.130  36.320  1.00  0.00            
-ATOM   1194  O6   DG A  38      34.760  57.070  36.800  1.00  0.00            
-ATOM   1195  N1   DG A  38      33.180  56.430  35.380  1.00  0.00            
-ATOM   1196  H1   DG A  38      33.030  57.410  35.200  1.00  0.00            
-ATOM   1197  C2   DG A  38      32.410  55.520  34.750  1.00  0.00            
-ATOM   1198  N2   DG A  38      31.520  55.920  33.890  1.00  0.00            
-ATOM   1199  H21  DG A  38      31.360  56.910  33.770  1.00  0.00            
-ATOM   1200  H22  DG A  38      30.940  55.210  33.500  1.00  0.00            
-ATOM   1201  N3   DG A  38      32.480  54.210  34.930  1.00  0.00            
-ATOM   1202  C4   DG A  38      33.410  53.880  35.880  1.00  0.00            
-ATOM   1203  C3'  DG A  38      32.760  49.150  35.510  1.00  0.00            
-ATOM   1204  H3'  DG A  38      33.290  48.200  35.570  1.00  0.00            
-ATOM   1205  C2'  DG A  38      33.720  50.300  35.320  1.00  0.00            
-ATOM   1206 1H2'  DG A  38      34.610  50.160  35.930  1.00  0.00            
-ATOM   1207 2H2'  DG A  38      33.980  50.430  34.270  1.00  0.00            
-ATOM   1208  O3'  DG A  38      31.750  49.110  34.440  1.00  0.00            
-ATOM   1209  P    DT A  39      31.980  48.700  32.850  1.00  0.00            
-ATOM   1210  O1P  DT A  39      30.770  47.950  32.420  1.00  0.00            
-ATOM   1211  O2P  DT A  39      33.260  47.960  32.760  1.00  0.00            
-ATOM   1212  O5'  DT A  39      32.090  50.000  31.820  1.00  0.00            
-ATOM   1213  C5'  DT A  39      30.940  50.520  31.110  1.00  0.00            
-ATOM   1214 1H5'  DT A  39      30.180  50.710  31.870  1.00  0.00            
-ATOM   1215 2H5'  DT A  39      30.560  49.730  30.470  1.00  0.00            
-ATOM   1216  C4'  DT A  39      31.010  51.850  30.250  1.00  0.00            
-ATOM   1217  H4'  DT A  39      29.970  52.150  30.100  1.00  0.00            
-ATOM   1218  O4'  DT A  39      31.580  52.830  31.080  1.00  0.00            
-ATOM   1219  C1'  DT A  39      32.710  53.380  30.420  1.00  0.00            
-ATOM   1220  H1'  DT A  39      32.400  54.330  29.970  1.00  0.00            
-ATOM   1221  N1   DT A  39      33.790  53.620  31.410  1.00  0.00            
-ATOM   1222  C6   DT A  39      34.460  52.590  32.040  1.00  0.00            
-ATOM   1223  H6   DT A  39      34.170  51.570  31.850  1.00  0.00            
-ATOM   1224  C5   DT A  39      35.450  52.850  32.930  1.00  0.00            
-ATOM   1225  C7   DT A  39      36.240  51.720  33.560  1.00  0.00            
-ATOM   1226  H71  DT A  39      35.940  50.750  33.170  1.00  0.00            
-ATOM   1227  H72  DT A  39      37.300  51.880  33.370  1.00  0.00            
-ATOM   1228  H73  DT A  39      36.110  51.760  34.650  1.00  0.00            
-ATOM   1229  C4   DT A  39      35.790  54.230  33.280  1.00  0.00            
-ATOM   1230  O4   DT A  39      36.630  54.590  34.090  1.00  0.00            
-ATOM   1231  N3   DT A  39      35.080  55.180  32.600  1.00  0.00            
-ATOM   1232  H3   DT A  39      35.310  56.140  32.810  1.00  0.00            
-ATOM   1233  C2   DT A  39      34.120  54.960  31.660  1.00  0.00            
-ATOM   1234  O2   DT A  39      33.610  55.900  31.050  1.00  0.00            
-ATOM   1235  C3'  DT A  39      31.690  51.990  28.850  1.00  0.00            
-ATOM   1236  H3'  DT A  39      31.730  51.020  28.340  1.00  0.00            
-ATOM   1237  C2'  DT A  39      33.070  52.430  29.290  1.00  0.00            
-ATOM   1238 1H2'  DT A  39      33.640  51.580  29.650  1.00  0.00            
-ATOM   1239 2H2'  DT A  39      33.620  52.950  28.490  1.00  0.00            
-ATOM   1240  O3'  DT A  39      31.050  52.990  27.990  1.00  0.00            
-ATOM   1241  P    DA A  40      31.400  53.310  26.400  1.00  0.00            
-ATOM   1242  O1P  DA A  40      30.090  53.510  25.710  1.00  0.00            
-ATOM   1243  O2P  DA A  40      32.220  52.190  25.900  1.00  0.00            
-ATOM   1244  O5'  DA A  40      32.260  54.720  26.160  1.00  0.00            
-ATOM   1245  C5'  DA A  40      31.630  56.000  25.870  1.00  0.00            
-ATOM   1246 1H5'  DA A  40      30.850  56.110  26.630  1.00  0.00            
-ATOM   1247 2H5'  DA A  40      31.120  55.910  24.910  1.00  0.00            
-ATOM   1248  C4'  DA A  40      32.410  57.370  25.870  1.00  0.00            
-ATOM   1249  H4'  DA A  40      31.640  58.140  25.930  1.00  0.00            
-ATOM   1250  O4'  DA A  40      33.110  57.450  27.090  1.00  0.00            
-ATOM   1251  C1'  DA A  40      34.490  57.590  26.830  1.00  0.00            
-ATOM   1252  H1'  DA A  40      34.810  58.600  27.100  1.00  0.00            
-ATOM   1253  N9   DA A  40      35.220  56.620  27.660  1.00  0.00            
-ATOM   1254  C8   DA A  40      35.160  55.250  27.670  1.00  0.00            
-ATOM   1255  H8   DA A  40      34.500  54.690  27.020  1.00  0.00            
-ATOM   1256  N7   DA A  40      35.950  54.670  28.540  1.00  0.00            
-ATOM   1257  C5   DA A  40      36.560  55.780  29.160  1.00  0.00            
-ATOM   1258  C6   DA A  40      37.490  55.980  30.200  1.00  0.00            
-ATOM   1259  N6   DA A  40      38.040  55.010  30.900  1.00  0.00            
-ATOM   1260  H61  DA A  40      38.670  55.280  31.670  1.00  0.00            
-ATOM   1261  H62  DA A  40      37.840  54.060  30.700  1.00  0.00            
-ATOM   1262  N1   DA A  40      37.870  57.200  30.550  1.00  0.00            
-ATOM   1263  C2   DA A  40      37.370  58.250  29.920  1.00  0.00            
-ATOM   1264  H2   DA A  40      37.720  59.220  30.250  1.00  0.00            
-ATOM   1265  N3   DA A  40      36.500  58.230  28.930  1.00  0.00            
-ATOM   1266  C4   DA A  40      36.130  56.960  28.610  1.00  0.00            
-ATOM   1267  C3'  DA A  40      33.400  57.880  24.770  1.00  0.00            
-ATOM   1268  H3'  DA A  40      33.190  57.430  23.800  1.00  0.00            
-ATOM   1269  C2'  DA A  40      34.710  57.360  25.330  1.00  0.00            
-ATOM   1270 1H2'  DA A  40      34.820  56.300  25.110  1.00  0.00            
-ATOM   1271 2H2'  DA A  40      35.580  57.920  24.970  1.00  0.00            
-ATOM   1272  O3'  DA A  40      33.410  59.340  24.660  1.00  0.00            
-ATOM   1273  P    DA A  41      34.300  60.240  23.580  1.00  0.00            
-ATOM   1274  O1P  DA A  41      33.410  61.350  23.140  1.00  0.00            
-ATOM   1275  O2P  DA A  41      34.740  59.310  22.520  1.00  0.00            
-ATOM   1276  O5'  DA A  41      35.640  60.950  24.260  1.00  0.00            
-ATOM   1277  C5'  DA A  41      35.620  62.250  24.910  1.00  0.00            
-ATOM   1278 1H5'  DA A  41      34.780  62.210  25.610  1.00  0.00            
-ATOM   1279 2H5'  DA A  41      35.370  63.000  24.170  1.00  0.00            
-ATOM   1280  C4'  DA A  41      36.830  62.800  25.770  1.00  0.00            
-ATOM   1281  H4'  DA A  41      36.410  63.560  26.420  1.00  0.00            
-ATOM   1282  O4'  DA A  41      37.240  61.750  26.620  1.00  0.00            
-ATOM   1283  C1'  DA A  41      38.630  61.560  26.500  1.00  0.00            
-ATOM   1284  H1'  DA A  41      39.150  61.990  27.370  1.00  0.00            
-ATOM   1285  N9   DA A  41      38.860  60.110  26.440  1.00  0.00            
-ATOM   1286  C8   DA A  41      38.330  59.190  25.570  1.00  0.00            
-ATOM   1287  H8   DA A  41      37.660  59.480  24.780  1.00  0.00            
-ATOM   1288  N7   DA A  41      38.690  57.950  25.810  1.00  0.00            
-ATOM   1289  C5   DA A  41      39.490  58.100  26.960  1.00  0.00            
-ATOM   1290  C6   DA A  41      40.150  57.230  27.850  1.00  0.00            
-ATOM   1291  N6   DA A  41      40.150  55.910  27.740  1.00  0.00            
-ATOM   1292  H61  DA A  41      40.620  55.390  28.480  1.00  0.00            
-ATOM   1293  H62  DA A  41      39.650  55.490  27.000  1.00  0.00            
-ATOM   1294  N1   DA A  41      40.820  57.680  28.900  1.00  0.00            
-ATOM   1295  C2   DA A  41      40.870  58.990  29.120  1.00  0.00            
-ATOM   1296  H2   DA A  41      41.430  59.320  29.980  1.00  0.00            
-ATOM   1297  N3   DA A  41      40.300  59.930  28.380  1.00  0.00            
-ATOM   1298  C4   DA A  41      39.610  59.410  27.330  1.00  0.00            
-ATOM   1299  C3'  DA A  41      38.130  63.450  25.180  1.00  0.00            
-ATOM   1300  H3'  DA A  41      37.990  63.790  24.160  1.00  0.00            
-ATOM   1301  C2'  DA A  41      39.090  62.270  25.230  1.00  0.00            
-ATOM   1302 1H2'  DA A  41      38.940  61.640  24.350  1.00  0.00            
-ATOM   1303 2H2'  DA A  41      40.140  62.570  25.300  1.00  0.00            
-ATOM   1304  O3'  DA A  41      38.610  64.540  26.010  1.00  0.00            
-ATOM   1305  P    DA A  42      39.970  65.450  25.730  1.00  0.00            
-ATOM   1306  O1P  DA A  42      39.620  66.850  26.080  1.00  0.00            
-ATOM   1307  O2P  DA A  42      40.330  65.220  24.310  1.00  0.00            
-ATOM   1308  O5'  DA A  42      41.240  64.980  26.690  1.00  0.00            
-ATOM   1309  C5'  DA A  42      41.400  65.390  28.080  1.00  0.00            
-ATOM   1310 1H5'  DA A  42      40.430  65.230  28.550  1.00  0.00            
-ATOM   1311 2H5'  DA A  42      41.590  66.460  28.100  1.00  0.00            
-ATOM   1312  C4'  DA A  42      42.430  64.690  29.040  1.00  0.00            
-ATOM   1313  H4'  DA A  42      42.100  64.890  30.060  1.00  0.00            
-ATOM   1314  O4'  DA A  42      42.290  63.310  28.830  1.00  0.00            
-ATOM   1315  C1'  DA A  42      43.570  62.720  28.680  1.00  0.00            
-ATOM   1316  H1'  DA A  42      43.920  62.290  29.630  1.00  0.00            
-ATOM   1317  N9   DA A  42      43.440  61.680  27.660  1.00  0.00            
-ATOM   1318  C8   DA A  42      42.910  61.780  26.400  1.00  0.00            
-ATOM   1319  H8   DA A  42      42.540  62.730  26.020  1.00  0.00            
-ATOM   1320  N7   DA A  42      42.850  60.660  25.730  1.00  0.00            
-ATOM   1321  C5   DA A  42      43.390  59.750  26.660  1.00  0.00            
-ATOM   1322  C6   DA A  42      43.590  58.350  26.700  1.00  0.00            
-ATOM   1323  N6   DA A  42      43.250  57.540  25.720  1.00  0.00            
-ATOM   1324  H61  DA A  42      43.370  56.540  25.880  1.00  0.00            
-ATOM   1325  H62  DA A  42      42.840  57.940  24.910  1.00  0.00            
-ATOM   1326  N1   DA A  42      44.080  57.730  27.770  1.00  0.00            
-ATOM   1327  C2   DA A  42      44.410  58.470  28.830  1.00  0.00            
-ATOM   1328  H2   DA A  42      44.820  57.960  29.680  1.00  0.00            
-ATOM   1329  N3   DA A  42      44.280  59.790  28.940  1.00  0.00            
-ATOM   1330  C4   DA A  42      43.760  60.360  27.830  1.00  0.00            
-ATOM   1331  C3'  DA A  42      43.970  65.000  29.050  1.00  0.00            
-ATOM   1332  H3'  DA A  42      44.200  65.950  28.580  1.00  0.00            
-ATOM   1333  C2'  DA A  42      44.510  63.830  28.230  1.00  0.00            
-ATOM   1334 1H2'  DA A  42      44.390  64.050  27.170  1.00  0.00            
-ATOM   1335 2H2'  DA A  42      45.550  63.600  28.460  1.00  0.00            
-ATOM   1336  O3'  DA A  42      44.520  64.970  30.390  1.00  0.00            
-ATOM   1337  P    DG A  43      46.110  65.230  30.780  1.00  0.00            
-ATOM   1338  O1P  DG A  43      46.120  66.130  31.950  1.00  0.00            
-ATOM   1339  O2P  DG A  43      46.740  65.750  29.540  1.00  0.00            
-ATOM   1340  O5'  DG A  43      46.860  63.800  31.190  1.00  0.00            
-ATOM   1341  C5'  DG A  43      46.720  63.170  32.500  1.00  0.00            
-ATOM   1342 1H5'  DG A  43      45.650  63.130  32.710  1.00  0.00            
-ATOM   1343 2H5'  DG A  43      47.160  63.820  33.260  1.00  0.00            
-ATOM   1344  C4'  DG A  43      47.250  61.700  32.740  1.00  0.00            
-ATOM   1345  H4'  DG A  43      46.740  61.310  33.630  1.00  0.00            
-ATOM   1346  O4'  DG A  43      46.810  60.950  31.630  1.00  0.00            
-ATOM   1347  C1'  DG A  43      47.940  60.350  31.030  1.00  0.00            
-ATOM   1348  H1'  DG A  43      48.030  59.320  31.390  1.00  0.00            
-ATOM   1349  N9   DG A  43      47.770  60.360  29.580  1.00  0.00            
-ATOM   1350  C8   DG A  43      47.590  61.420  28.730  1.00  0.00            
-ATOM   1351  H8   DG A  43      47.590  62.440  29.100  1.00  0.00            
-ATOM   1352  N7   DG A  43      47.400  61.090  27.470  1.00  0.00            
-ATOM   1353  C5   DG A  43      47.440  59.680  27.520  1.00  0.00            
-ATOM   1354  C6   DG A  43      47.240  58.670  26.510  1.00  0.00            
-ATOM   1355  O6   DG A  43      46.960  58.810  25.320  1.00  0.00            
-ATOM   1356  N1   DG A  43      47.380  57.380  26.990  1.00  0.00            
-ATOM   1357  H1   DG A  43      47.230  56.620  26.350  1.00  0.00            
-ATOM   1358  C2   DG A  43      47.640  57.070  28.280  1.00  0.00            
-ATOM   1359  N2   DG A  43      47.790  55.820  28.610  1.00  0.00            
-ATOM   1360  H21  DG A  43      47.700  55.070  27.930  1.00  0.00            
-ATOM   1361  H22  DG A  43      47.990  55.650  29.580  1.00  0.00            
-ATOM   1362  N3   DG A  43      47.810  57.960  29.240  1.00  0.00            
-ATOM   1363  C4   DG A  43      47.690  59.240  28.800  1.00  0.00            
-ATOM   1364  C3'  DG A  43      48.760  61.330  32.940  1.00  0.00            
-ATOM   1365  H3'  DG A  43      49.320  62.140  33.410  1.00  0.00            
-ATOM   1366  C2'  DG A  43      49.160  61.140  31.490  1.00  0.00            
-ATOM   1367 1H2'  DG A  43      49.230  62.100  30.980  1.00  0.00            
-ATOM   1368 2H2'  DG A  43      50.080  60.560  31.380  1.00  0.00            
-ATOM   1369  O3'  DG A  43      48.950  60.090  33.670  1.00  0.00            
-ATOM   1370  P    DA A  44      50.420  59.460  34.110  1.00  0.00            
-ATOM   1371  O1P  DA A  44      50.400  59.250  35.570  1.00  0.00            
-ATOM   1372  O2P  DA A  44      51.440  60.370  33.560  1.00  0.00            
-ATOM   1373  O5'  DA A  44      50.670  57.980  33.410  1.00  0.00            
-ATOM   1374  C5'  DA A  44      50.050  56.760  33.870  1.00  0.00            
-ATOM   1375 1H5'  DA A  44      48.990  56.970  33.870  1.00  0.00            
-ATOM   1376 2H5'  DA A  44      50.340  56.590  34.910  1.00  0.00            
-ATOM   1377  C4'  DA A  44      50.230  55.410  33.070  1.00  0.00            
-ATOM   1378  H4'  DA A  44      49.490  54.720  33.470  1.00  0.00            
-ATOM   1379  O4'  DA A  44      49.890  55.680  31.720  1.00  0.00            
-ATOM   1380  C1'  DA A  44      51.070  55.570  30.950  1.00  0.00            
-ATOM   1381  H1'  DA A  44      51.000  54.660  30.350  1.00  0.00            
-ATOM   1382  N9   DA A  44      51.190  56.740  30.060  1.00  0.00            
-ATOM   1383  C8   DA A  44      51.340  58.080  30.350  1.00  0.00            
-ATOM   1384  H8   DA A  44      51.490  58.450  31.350  1.00  0.00            
-ATOM   1385  N7   DA A  44      51.260  58.870  29.300  1.00  0.00            
-ATOM   1386  C5   DA A  44      51.050  57.950  28.260  1.00  0.00            
-ATOM   1387  C6   DA A  44      50.790  58.070  26.890  1.00  0.00            
-ATOM   1388  N6   DA A  44      50.630  59.220  26.270  1.00  0.00            
-ATOM   1389  H61  DA A  44      50.380  59.240  25.290  1.00  0.00            
-ATOM   1390  H62  DA A  44      50.670  60.040  26.850  1.00  0.00            
-ATOM   1391  N1   DA A  44      50.620  56.990  26.120  1.00  0.00            
-ATOM   1392  C2   DA A  44      50.710  55.800  26.680  1.00  0.00            
-ATOM   1393  H2   DA A  44      50.590  54.940  26.030  1.00  0.00            
-ATOM   1394  N3   DA A  44      50.920  55.530  27.960  1.00  0.00            
-ATOM   1395  C4   DA A  44      51.060  56.660  28.700  1.00  0.00            
-ATOM   1396  C3'  DA A  44      51.570  54.600  32.990  1.00  0.00            
-ATOM   1397  H3'  DA A  44      52.120  54.650  33.930  1.00  0.00            
-ATOM   1398  C2'  DA A  44      52.240  55.410  31.910  1.00  0.00            
-ATOM   1399 1H2'  DA A  44      52.580  56.370  32.300  1.00  0.00            
-ATOM   1400 2H2'  DA A  44      53.050  54.840  31.450  1.00  0.00            
-ATOM   1401  O3'  DA A  44      51.400  53.220  32.560  1.00  0.00            
-ATOM   1402  P    DT A  45      52.610  52.120  32.340  1.00  0.00            
-ATOM   1403  O1P  DT A  45      52.160  50.810  32.880  1.00  0.00            
-ATOM   1404  O2P  DT A  45      53.850  52.700  32.900  1.00  0.00            
-ATOM   1405  O5'  DT A  45      52.920  51.840  30.730  1.00  0.00            
-ATOM   1406  C5'  DT A  45      52.280  50.780  30.000  1.00  0.00            
-ATOM   1407 1H5'  DT A  45      51.210  50.960  30.070  1.00  0.00            
-ATOM   1408 2H5'  DT A  45      52.470  49.840  30.520  1.00  0.00            
-ATOM   1409  C4'  DT A  45      52.610  50.560  28.480  1.00  0.00            
-ATOM   1410  H4'  DT A  45      51.820  49.930  28.080  1.00  0.00            
-ATOM   1411  O4'  DT A  45      52.510  51.820  27.840  1.00  0.00            
-ATOM   1412  C1'  DT A  45      53.790  52.190  27.380  1.00  0.00            
-ATOM   1413  H1'  DT A  45      53.810  52.010  26.300  1.00  0.00            
-ATOM   1414  N1   DT A  45      54.030  53.640  27.620  1.00  0.00            
-ATOM   1415  C6   DT A  45      54.410  54.160  28.850  1.00  0.00            
-ATOM   1416  H6   DT A  45      54.540  53.500  29.700  1.00  0.00            
-ATOM   1417  C5   DT A  45      54.610  55.500  29.010  1.00  0.00            
-ATOM   1418  C7   DT A  45      55.100  56.070  30.330  1.00  0.00            
-ATOM   1419  H71  DT A  45      55.250  55.280  31.070  1.00  0.00            
-ATOM   1420  H72  DT A  45      56.040  56.590  30.160  1.00  0.00            
-ATOM   1421  H73  DT A  45      54.370  56.800  30.690  1.00  0.00            
-ATOM   1422  C4   DT A  45      54.360  56.420  27.900  1.00  0.00            
-ATOM   1423  O4   DT A  45      54.420  57.650  27.930  1.00  0.00            
-ATOM   1424  N3   DT A  45      54.000  55.820  26.730  1.00  0.00            
-ATOM   1425  H3   DT A  45      53.840  56.420  25.940  1.00  0.00            
-ATOM   1426  C2   DT A  45      53.850  54.480  26.520  1.00  0.00            
-ATOM   1427  O2   DT A  45      53.580  54.090  25.380  1.00  0.00            
-ATOM   1428  C3'  DT A  45      53.960  49.940  27.980  1.00  0.00            
-ATOM   1429  H3'  DT A  45      54.340  49.210  28.700  1.00  0.00            
-ATOM   1430  C2'  DT A  45      54.800  51.210  28.000  1.00  0.00            
-ATOM   1431 1H2'  DT A  45      55.050  51.480  29.020  1.00  0.00            
-ATOM   1432 2H2'  DT A  45      55.700  51.110  27.400  1.00  0.00            
-ATOM   1433  O3'  DT A  45      53.850  49.350  26.650  1.00  0.00            
-ATOM   1434  P    DG A  46      54.990  48.440  25.860  1.00  0.00            
-ATOM   1435  O1P  DG A  46      54.280  47.300  25.230  1.00  0.00            
-ATOM   1436  O2P  DG A  46      56.060  48.100  26.820  1.00  0.00            
-ATOM   1437  O5'  DG A  46      55.700  49.260  24.600  1.00  0.00            
-ATOM   1438  C5'  DG A  46      55.170  49.210  23.260  1.00  0.00            
-ATOM   1439 1H5'  DG A  46      54.130  49.520  23.340  1.00  0.00            
-ATOM   1440 2H5'  DG A  46      55.170  48.170  22.940  1.00  0.00            
-ATOM   1441  C4'  DG A  46      55.770  50.070  22.080  1.00  0.00            
-ATOM   1442  H4'  DG A  46      55.110  49.900  21.230  1.00  0.00            
-ATOM   1443  O4'  DG A  46      55.620  51.420  22.440  1.00  0.00            
-ATOM   1444  C1'  DG A  46      56.910  51.970  22.630  1.00  0.00            
-ATOM   1445  H1'  DG A  46      57.100  52.670  21.810  1.00  0.00            
-ATOM   1446  N9   DG A  46      56.970  52.710  23.890  1.00  0.00            
-ATOM   1447  C8   DG A  46      56.930  52.290  25.200  1.00  0.00            
-ATOM   1448  H8   DG A  46      56.820  51.250  25.470  1.00  0.00            
-ATOM   1449  N7   DG A  46      57.000  53.260  26.070  1.00  0.00            
-ATOM   1450  C5   DG A  46      57.110  54.410  25.280  1.00  0.00            
-ATOM   1451  C6   DG A  46      57.210  55.820  25.590  1.00  0.00            
-ATOM   1452  O6   DG A  46      57.210  56.390  26.670  1.00  0.00            
-ATOM   1453  N1   DG A  46      57.280  56.620  24.470  1.00  0.00            
-ATOM   1454  H1   DG A  46      57.330  57.610  24.630  1.00  0.00            
-ATOM   1455  C2   DG A  46      57.260  56.150  23.200  1.00  0.00            
-ATOM   1456  N2   DG A  46      57.350  56.990  22.210  1.00  0.00            
-ATOM   1457  H21  DG A  46      57.390  57.990  22.400  1.00  0.00            
-ATOM   1458  H22  DG A  46      57.330  56.600  21.290  1.00  0.00            
-ATOM   1459  N3   DG A  46      57.180  54.880  22.850  1.00  0.00            
-ATOM   1460  C4   DG A  46      57.100  54.070  23.940  1.00  0.00            
-ATOM   1461  C3'  DG A  46      57.230  49.950  21.510  1.00  0.00            
-ATOM   1462  H3'  DG A  46      57.590  48.930  21.570  1.00  0.00            
-ATOM   1463  C2'  DG A  46      57.940  50.840  22.520  1.00  0.00            
-ATOM   1464 1H2'  DG A  46      58.050  50.330  23.480  1.00  0.00            
-ATOM   1465 2H2'  DG A  46      58.900  51.200  22.160  1.00  0.00            
-ATOM   1466  O3'  DG A  46      57.330  50.470  20.140  1.00  0.00            
-ATOM   1467  P    DG A  47      58.660  50.440  19.160  1.00  0.00            
-ATOM   1468  O1P  DG A  47      58.160  50.080  17.800  1.00  0.00            
-ATOM   1469  O2P  DG A  47      59.630  49.490  19.750  1.00  0.00            
-ATOM   1470  O5'  DG A  47      59.420  51.910  18.990  1.00  0.00            
-ATOM   1471  C5'  DG A  47      59.080  52.850  17.930  1.00  0.00            
-ATOM   1472 1H5'  DG A  47      58.000  53.000  18.010  1.00  0.00            
-ATOM   1473 2H5'  DG A  47      59.260  52.360  16.980  1.00  0.00            
-ATOM   1474  C4'  DG A  47      59.690  54.310  17.850  1.00  0.00            
-ATOM   1475  H4'  DG A  47      59.090  54.840  17.120  1.00  0.00            
-ATOM   1476  O4'  DG A  47      59.430  54.920  19.090  1.00  0.00            
-ATOM   1477  C1'  DG A  47      60.670  55.230  19.690  1.00  0.00            
-ATOM   1478  H1'  DG A  47      60.820  56.320  19.640  1.00  0.00            
-ATOM   1479  N9   DG A  47      60.670  54.830  21.110  1.00  0.00            
-ATOM   1480  C8   DG A  47      60.560  53.590  21.680  1.00  0.00            
-ATOM   1481  H8   DG A  47      60.440  52.690  21.100  1.00  0.00            
-ATOM   1482  N7   DG A  47      60.610  53.610  22.980  1.00  0.00            
-ATOM   1483  C5   DG A  47      60.700  54.980  23.290  1.00  0.00            
-ATOM   1484  C6   DG A  47      60.710  55.710  24.530  1.00  0.00            
-ATOM   1485  O6   DG A  47      60.620  55.290  25.680  1.00  0.00            
-ATOM   1486  N1   DG A  47      60.830  57.080  24.360  1.00  0.00            
-ATOM   1487  H1   DG A  47      60.760  57.640  25.190  1.00  0.00            
-ATOM   1488  C2   DG A  47      60.910  57.690  23.160  1.00  0.00            
-ATOM   1489  N2   DG A  47      61.000  58.980  23.110  1.00  0.00            
-ATOM   1490  H21  DG A  47      60.900  59.520  23.970  1.00  0.00            
-ATOM   1491  H22  DG A  47      60.960  59.420  22.210  1.00  0.00            
-ATOM   1492  N3   DG A  47      60.910  57.070  21.990  1.00  0.00            
-ATOM   1493  C4   DG A  47      60.780  55.720  22.130  1.00  0.00            
-ATOM   1494  C3'  DG A  47      61.180  54.650  17.510  1.00  0.00            
-ATOM   1495  H3'  DG A  47      61.620  53.910  16.840  1.00  0.00            
-ATOM   1496  C2'  DG A  47      61.780  54.550  18.900  1.00  0.00            
-ATOM   1497 1H2'  DG A  47      61.880  53.500  19.190  1.00  0.00            
-ATOM   1498 2H2'  DG A  47      62.720  55.080  18.980  1.00  0.00            
-ATOM   1499  O3'  DG A  47      61.350  56.000  16.970  1.00  0.00            
-ATOM   1500  P    DC A  48      62.780  56.690  16.460  1.00  0.00            
-ATOM   1501  O1P  DC A  48      62.480  57.390  15.190  1.00  0.00            
-ATOM   1502  O2P  DC A  48      63.770  55.590  16.390  1.00  0.00            
-ATOM   1503  O5'  DC A  48      63.380  57.840  17.510  1.00  0.00            
-ATOM   1504  C5'  DC A  48      63.040  59.250  17.440  1.00  0.00            
-ATOM   1505 1H5'  DC A  48      61.950  59.290  17.400  1.00  0.00            
-ATOM   1506 2H5'  DC A  48      63.400  59.640  16.490  1.00  0.00            
-ATOM   1507  C4'  DC A  48      63.470  60.260  18.580  1.00  0.00            
-ATOM   1508  H4'  DC A  48      62.790  61.110  18.480  1.00  0.00            
-ATOM   1509  O4'  DC A  48      63.160  59.660  19.820  1.00  0.00            
-ATOM   1510  C1'  DC A  48      64.310  59.670  20.650  1.00  0.00            
-ATOM   1511  H1'  DC A  48      64.210  60.480  21.390  1.00  0.00            
-ATOM   1512  N1   DC A  48      64.410  58.360  21.330  1.00  0.00            
-ATOM   1513  C6   DC A  48      64.340  57.180  20.630  1.00  0.00            
-ATOM   1514  H6   DC A  48      64.260  57.220  19.560  1.00  0.00            
-ATOM   1515  C5   DC A  48      64.310  55.990  21.280  1.00  0.00            
-ATOM   1516  H5   DC A  48      64.230  55.060  20.750  1.00  0.00            
-ATOM   1517  C4   DC A  48      64.360  56.040  22.700  1.00  0.00            
-ATOM   1518  N4   DC A  48      64.240  54.960  23.400  1.00  0.00            
-ATOM   1519  H41  DC A  48      64.220  55.100  24.410  1.00  0.00            
-ATOM   1520  H42  DC A  48      63.860  54.130  23.010  1.00  0.00            
-ATOM   1521  N3   DC A  48      64.490  57.160  23.380  1.00  0.00            
-ATOM   1522  C2   DC A  48      64.500  58.340  22.720  1.00  0.00            
-ATOM   1523  O2   DC A  48      64.590  59.370  23.370  1.00  0.00            
-ATOM   1524  C3'  DC A  48      64.890  60.910  18.730  1.00  0.00            
-ATOM   1525  H3'  DC A  48      65.440  60.880  17.800  1.00  0.00            
-ATOM   1526  C2'  DC A  48      65.510  59.970  19.750  1.00  0.00            
-ATOM   1527 1H2'  DC A  48      65.860  59.060  19.260  1.00  0.00            
-ATOM   1528 2H2'  DC A  48      66.320  60.430  20.320  1.00  0.00            
-ATOM   1529  O3'  DC A  48      64.820  62.270  19.240  1.00  0.00            
-ATOM   1530  P    DA A  49      66.110  63.280  19.520  1.00  0.00            
-ATOM   1531  O1P  DA A  49      65.730  64.620  18.990  1.00  0.00            
-ATOM   1532  O2P  DA A  49      67.300  62.650  18.890  1.00  0.00            
-ATOM   1533  O5'  DA A  49      66.420  63.460  21.140  1.00  0.00            
-ATOM   1534  C5'  DA A  49      65.700  64.400  21.980  1.00  0.00            
-ATOM   1535 1H5'  DA A  49      64.640  64.240  21.770  1.00  0.00            
-ATOM   1536 2H5'  DA A  49      65.930  65.410  21.660  1.00  0.00            
-ATOM   1537  C4'  DA A  49      65.820  64.350  23.550  1.00  0.00            
-ATOM   1538  H4'  DA A  49      64.940  64.870  23.940  1.00  0.00            
-ATOM   1539  O4'  DA A  49      65.680  63.000  23.940  1.00  0.00            
-ATOM   1540  C1'  DA A  49      66.770  62.620  24.760  1.00  0.00            
-ATOM   1541  H1'  DA A  49      66.460  62.590  25.810  1.00  0.00            
-ATOM   1542  N9   DA A  49      67.230  61.290  24.330  1.00  0.00            
-ATOM   1543  C8   DA A  49      67.560  60.870  23.060  1.00  0.00            
-ATOM   1544  H8   DA A  49      67.560  61.540  22.220  1.00  0.00            
-ATOM   1545  N7   DA A  49      67.860  59.600  22.970  1.00  0.00            
-ATOM   1546  C5   DA A  49      67.650  59.160  24.300  1.00  0.00            
-ATOM   1547  C6   DA A  49      67.660  57.920  24.960  1.00  0.00            
-ATOM   1548  N6   DA A  49      67.880  56.760  24.370  1.00  0.00            
-ATOM   1549  H61  DA A  49      67.740  55.930  24.940  1.00  0.00            
-ATOM   1550  H62  DA A  49      67.910  56.740  23.380  1.00  0.00            
-ATOM   1551  N1   DA A  49      67.400  57.820  26.260  1.00  0.00            
-ATOM   1552  C2   DA A  49      67.120  58.920  26.950  1.00  0.00            
-ATOM   1553  H2   DA A  49      66.910  58.800  28.000  1.00  0.00            
-ATOM   1554  N3   DA A  49      67.070  60.160  26.460  1.00  0.00            
-ATOM   1555  C4   DA A  49      67.310  60.200  25.130  1.00  0.00            
-ATOM   1556  C3'  DA A  49      67.030  64.930  24.360  1.00  0.00            
-ATOM   1557  H3'  DA A  49      67.580  65.660  23.770  1.00  0.00            
-ATOM   1558  C2'  DA A  49      67.860  63.670  24.570  1.00  0.00            
-ATOM   1559 1H2'  DA A  49      68.460  63.470  23.690  1.00  0.00            
-ATOM   1560 2H2'  DA A  49      68.490  63.740  25.460  1.00  0.00            
-ATOM   1561  O3'  DA A  49      66.620  65.510  25.620  1.00  0.00            
-ATOM   1562  P    DT A  50      67.640  66.150  26.750  1.00  0.00            
-ATOM   1563  O1P  DT A  50      67.020  67.400  27.240  1.00  0.00            
-ATOM   1564  O2P  DT A  50      68.960  66.280  26.090  1.00  0.00            
-ATOM   1565  O5'  DT A  50      67.800  65.100  28.030  1.00  0.00            
-ATOM   1566  C5'  DT A  50      66.770  64.920  29.050  1.00  0.00            
-ATOM   1567 1H5'  DT A  50      65.830  64.780  28.520  1.00  0.00            
-ATOM   1568 2H5'  DT A  50      66.680  65.830  29.630  1.00  0.00            
-ATOM   1569  C4'  DT A  50      66.870  63.710  30.060  1.00  0.00            
-ATOM   1570  H4'  DT A  50      65.870  63.530  30.460  1.00  0.00            
-ATOM   1571  O4'  DT A  50      67.220  62.580  29.280  1.00  0.00            
-ATOM   1572  C1'  DT A  50      68.270  61.880  29.910  1.00  0.00            
-ATOM   1573  H1'  DT A  50      67.870  61.100  30.560  1.00  0.00            
-ATOM   1574  N1   DT A  50      69.170  61.320  28.880  1.00  0.00            
-ATOM   1575  C6   DT A  50      69.690  62.140  27.890  1.00  0.00            
-ATOM   1576  H6   DT A  50      69.420  63.180  27.910  1.00  0.00            
-ATOM   1577  C5   DT A  50      70.460  61.620  26.900  1.00  0.00            
-ATOM   1578  C7   DT A  50      71.030  62.540  25.840  1.00  0.00            
-ATOM   1579  H71  DT A  50      70.830  63.580  26.090  1.00  0.00            
-ATOM   1580  H72  DT A  50      72.100  62.380  25.780  1.00  0.00            
-ATOM   1581  H73  DT A  50      70.580  62.290  24.880  1.00  0.00            
-ATOM   1582  C4   DT A  50      70.740  60.190  26.850  1.00  0.00            
-ATOM   1583  O4   DT A  50      71.370  59.620  25.950  1.00  0.00            
-ATOM   1584  N3   DT A  50      70.240  59.460  27.900  1.00  0.00            
-ATOM   1585  H3   DT A  50      70.360  58.460  27.920  1.00  0.00            
-ATOM   1586  C2   DT A  50      69.490  59.970  28.940  1.00  0.00            
-ATOM   1587  O2   DT A  50      69.170  59.230  29.850  1.00  0.00            
-ATOM   1588  C3'  DT A  50      67.820  63.710  31.310  1.00  0.00            
-ATOM   1589  H3'  DT A  50      68.110  64.720  31.580  1.00  0.00            
-ATOM   1590  C2'  DT A  50      68.990  62.920  30.770  1.00  0.00            
-ATOM   1591 1H2'  DT A  50      69.630  63.570  30.170  1.00  0.00            
-ATOM   1592 2H2'  DT A  50      69.560  62.430  31.550  1.00  0.00            
-ATOM   1593  O3'  DT A  50      67.280  63.020  32.460  1.00  0.00            
-ATOM   1594  P    DT A  51      68.070  62.870  33.910  1.00  0.00            
-ATOM   1595  O1P  DT A  51      67.130  63.260  34.980  1.00  0.00            
-ATOM   1596  O2P  DT A  51      69.310  63.670  33.780  1.00  0.00            
-ATOM   1597  O5'  DT A  51      68.520  61.290  34.160  1.00  0.00            
-ATOM   1598  C5'  DT A  51      67.600  60.250  34.590  1.00  0.00            
-ATOM   1599 1H5'  DT A  51      66.750  60.330  33.910  1.00  0.00            
-ATOM   1600 2H5'  DT A  51      67.220  60.490  35.590  1.00  0.00            
-ATOM   1601  C4'  DT A  51      68.030  58.730  34.560  1.00  0.00            
-ATOM   1602  H4'  DT A  51      67.110  58.150  34.580  1.00  0.00            
-ATOM   1603  O4'  DT A  51      68.640  58.540  33.300  1.00  0.00            
-ATOM   1604  C1'  DT A  51      69.950  58.060  33.510  1.00  0.00            
-ATOM   1605  H1'  DT A  51      69.940  56.970  33.380  1.00  0.00            
-ATOM   1606  N1   DT A  51      70.880  58.690  32.550  1.00  0.00            
-ATOM   1607  C6   DT A  51      71.130  60.050  32.570  1.00  0.00            
-ATOM   1608  H6   DT A  51      70.650  60.650  33.330  1.00  0.00            
-ATOM   1609  C5   DT A  51      71.930  60.630  31.640  1.00  0.00            
-ATOM   1610  C7   DT A  51      72.230  62.110  31.720  1.00  0.00            
-ATOM   1611  H71  DT A  51      71.720  62.570  32.570  1.00  0.00            
-ATOM   1612  H72  DT A  51      73.300  62.250  31.820  1.00  0.00            
-ATOM   1613  H73  DT A  51      71.900  62.590  30.800  1.00  0.00            
-ATOM   1614  C4   DT A  51      72.500  59.830  30.570  1.00  0.00            
-ATOM   1615  O4   DT A  51      73.160  60.270  29.620  1.00  0.00            
-ATOM   1616  N3   DT A  51      72.240  58.490  30.640  1.00  0.00            
-ATOM   1617  H3   DT A  51      72.660  57.870  29.980  1.00  0.00            
-ATOM   1618  C2   DT A  51      71.500  57.870  31.610  1.00  0.00            
-ATOM   1619  O2   DT A  51      71.470  56.640  31.620  1.00  0.00            
-ATOM   1620  C3'  DT A  51      68.970  58.060  35.620  1.00  0.00            
-ATOM   1621  H3'  DT A  51      68.880  58.540  36.590  1.00  0.00            
-ATOM   1622  C2'  DT A  51      70.290  58.360  34.960  1.00  0.00            
-ATOM   1623 1H2'  DT A  51      70.550  59.400  35.130  1.00  0.00            
-ATOM   1624 2H2'  DT A  51      71.070  57.690  35.320  1.00  0.00            
-ATOM   1625  O3'  DT A  51      68.820  56.620  35.740  1.00  0.00            
-ATOM   1626  P    DT A  52      69.720  55.650  36.750  1.00  0.00            
-ATOM   1627  O1P  DT A  52      68.800  54.760  37.480  1.00  0.00            
-ATOM   1628  O2P  DT A  52      70.600  56.550  37.540  1.00  0.00            
-ATOM   1629  O5'  DT A  52      70.740  54.670  35.900  1.00  0.00            
-ATOM   1630  C5'  DT A  52      70.350  53.370  35.400  1.00  0.00            
-ATOM   1631 1H5'  DT A  52      69.510  53.540  34.730  1.00  0.00            
-ATOM   1632 2H5'  DT A  52      69.980  52.770  36.230  1.00  0.00            
-ATOM   1633  C4'  DT A  52      71.400  52.510  34.600  1.00  0.00            
-ATOM   1634  H4'  DT A  52      70.830  51.780  34.030  1.00  0.00            
-ATOM   1635  O4'  DT A  52      72.040  53.380  33.690  1.00  0.00            
-ATOM   1636  C1'  DT A  52      73.380  53.550  34.100  1.00  0.00            
-ATOM   1637  H1'  DT A  52      73.990  52.940  33.410  1.00  0.00            
-ATOM   1638  N1   DT A  52      73.770  54.980  33.950  1.00  0.00            
-ATOM   1639  C6   DT A  52      73.480  55.960  34.890  1.00  0.00            
-ATOM   1640  H6   DT A  52      72.950  55.690  35.800  1.00  0.00            
-ATOM   1641  C5   DT A  52      73.800  57.260  34.670  1.00  0.00            
-ATOM   1642  C7   DT A  52      73.560  58.320  35.730  1.00  0.00            
-ATOM   1643  H71  DT A  52      73.030  57.900  36.590  1.00  0.00            
-ATOM   1644  H72  DT A  52      74.510  58.740  36.040  1.00  0.00            
-ATOM   1645  H73  DT A  52      72.970  59.130  35.300  1.00  0.00            
-ATOM   1646  C4   DT A  52      74.390  57.670  33.390  1.00  0.00            
-ATOM   1647  O4   DT A  52      74.630  58.810  33.030  1.00  0.00            
-ATOM   1648  N3   DT A  52      74.680  56.630  32.540  1.00  0.00            
-ATOM   1649  H3   DT A  52      75.180  56.850  31.700  1.00  0.00            
-ATOM   1650  C2   DT A  52      74.470  55.300  32.790  1.00  0.00            
-ATOM   1651  O2   DT A  52      74.950  54.480  32.010  1.00  0.00            
-ATOM   1652  C3'  DT A  52      72.560  51.740  35.310  1.00  0.00            
-ATOM   1653  H3'  DT A  52      72.240  51.350  36.280  1.00  0.00            
-ATOM   1654  C2'  DT A  52      73.520  52.900  35.480  1.00  0.00            
-ATOM   1655 1H2'  DT A  52      73.170  53.560  36.280  1.00  0.00            
-ATOM   1656 2H2'  DT A  52      74.520  52.540  35.670  1.00  0.00            
-ATOM   1657  O3'  DT A  52      73.150  50.680  34.490  1.00  0.00            
-ATOM   1658  P    DC A  53      74.330  49.610  34.960  1.00  0.00            
-ATOM   1659  O1P  DC A  53      73.920  48.250  34.540  1.00  0.00            
-ATOM   1660  O2P  DC A  53      74.600  49.830  36.390  1.00  0.00            
-ATOM   1661  O5'  DC A  53      75.760  49.890  34.180  1.00  0.00            
-ATOM   1662  C5'  DC A  53      76.080  49.320  32.890  1.00  0.00            
-ATOM   1663 1H5'  DC A  53      75.280  49.630  32.220  1.00  0.00            
-ATOM   1664 2H5'  DC A  53      76.010  48.240  32.980  1.00  0.00            
-ATOM   1665  C4'  DC A  53      77.440  49.680  32.190  1.00  0.00            
-ATOM   1666  H4'  DC A  53      77.360  49.300  31.170  1.00  0.00            
-ATOM   1667  O4'  DC A  53      77.460  51.090  32.100  1.00  0.00            
-ATOM   1668  C1'  DC A  53      78.520  51.570  32.910  1.00  0.00            
-ATOM   1669  H1'  DC A  53      79.320  51.850  32.230  1.00  0.00            
-ATOM   1670  N1   DC A  53      78.080  52.770  33.680  1.00  0.00            
-ATOM   1671  C6   DC A  53      77.230  52.730  34.760  1.00  0.00            
-ATOM   1672  H6   DC A  53      76.840  51.780  35.110  1.00  0.00            
-ATOM   1673  C5   DC A  53      76.850  53.880  35.370  1.00  0.00            
-ATOM   1674  H5   DC A  53      76.180  53.860  36.220  1.00  0.00            
-ATOM   1675  C4   DC A  53      77.330  55.100  34.830  1.00  0.00            
-ATOM   1676  N4   DC A  53      76.930  56.240  35.310  1.00  0.00            
-ATOM   1677  H41  DC A  53      77.300  57.090  34.900  1.00  0.00            
-ATOM   1678  H42  DC A  53      76.250  56.260  36.050  1.00  0.00            
-ATOM   1679  N3   DC A  53      78.180  55.160  33.830  1.00  0.00            
-ATOM   1680  C2   DC A  53      78.580  54.000  33.260  1.00  0.00            
-ATOM   1681  O2   DC A  53      79.450  54.060  32.390  1.00  0.00            
-ATOM   1682  C3'  DC A  53      78.840  49.260  32.740  1.00  0.00            
-ATOM   1683  H3'  DC A  53      78.770  48.300  33.260  1.00  0.00            
-ATOM   1684  C2'  DC A  53      79.050  50.390  33.730  1.00  0.00            
-ATOM   1685 1H2'  DC A  53      78.450  50.230  34.630  1.00  0.00            
-ATOM   1686 2H2'  DC A  53      80.100  50.520  33.960  1.00  0.00            
-ATOM   1687  O3'  DC A  53      79.900  49.230  31.730  1.00  0.00            
-ATOM   1688  P    DT A  54      81.480  48.760  31.950  1.00  0.00            
-ATOM   1689  O1P  DT A  54      81.880  48.000  30.730  1.00  0.00            
-ATOM   1690  O2P  DT A  54      81.560  48.020  33.230  1.00  0.00            
-ATOM   1691  O5'  DT A  54      82.540  50.040  32.050  1.00  0.00            
-ATOM   1692  C5'  DT A  54      83.250  50.540  30.890  1.00  0.00            
-ATOM   1693 1H5'  DT A  54      82.480  50.740  30.140  1.00  0.00            
-ATOM   1694 2H5'  DT A  54      83.870  49.740  30.500  1.00  0.00            
-ATOM   1695  C4'  DT A  54      84.130  51.850  30.940  1.00  0.00            
-ATOM   1696  H4'  DT A  54      84.290  52.140  29.910  1.00  0.00            
-ATOM   1697  O4'  DT A  54      83.320  52.850  31.510  1.00  0.00            
-ATOM   1698  C1'  DT A  54      83.970  53.370  32.660  1.00  0.00            
-ATOM   1699  H1'  DT A  54      84.430  54.320  32.380  1.00  0.00            
-ATOM   1700  N1   DT A  54      82.960  53.600  33.730  1.00  0.00            
-ATOM   1701  C6   DT A  54      82.370  52.560  34.430  1.00  0.00            
-ATOM   1702  H6   DT A  54      82.630  51.540  34.200  1.00  0.00            
-ATOM   1703  C5   DT A  54      81.440  52.820  35.400  1.00  0.00            
-ATOM   1704  C7   DT A  54      80.860  51.700  36.230  1.00  0.00            
-ATOM   1705  H71  DT A  54      81.270  50.730  35.950  1.00  0.00            
-ATOM   1706  H72  DT A  54      81.080  51.890  37.290  1.00  0.00            
-ATOM   1707  H73  DT A  54      79.770  51.710  36.130  1.00  0.00            
-ATOM   1708  C4   DT A  54      81.000  54.190  35.650  1.00  0.00            
-ATOM   1709  O4   DT A  54      80.130  54.540  36.430  1.00  0.00            
-ATOM   1710  N3   DT A  54      81.640  55.140  34.900  1.00  0.00            
-ATOM   1711  H3   DT A  54      81.380  56.100  35.080  1.00  0.00            
-ATOM   1712  C2   DT A  54      82.630  54.930  33.990  1.00  0.00            
-ATOM   1713  O2   DT A  54      83.210  55.880  33.460  1.00  0.00            
-ATOM   1714  C3'  DT A  54      85.540  51.970  31.620  1.00  0.00            
-ATOM   1715  H3'  DT A  54      86.040  51.000  31.660  1.00  0.00            
-ATOM   1716  C2'  DT A  54      85.100  52.400  33.020  1.00  0.00            
-ATOM   1717 1H2'  DT A  54      84.740  51.540  33.570  1.00  0.00            
-ATOM   1718 2H2'  DT A  54      85.900  52.900  33.560  1.00  0.00            
-ATOM   1719  O3'  DT A  54      86.400  52.970  30.980  1.00  0.00            
-ATOM   1720  P    DA A  55      87.990  53.280  31.320  1.00  0.00            
-ATOM   1721  O1P  DA A  55      88.680  53.460  30.010  1.00  0.00            
-ATOM   1722  O2P  DA A  55      88.490  52.160  32.160  1.00  0.00            
-ATOM   1723  O5'  DA A  55      88.240  54.690  32.170  1.00  0.00            
-ATOM   1724  C5'  DA A  55      88.490  55.970  31.520  1.00  0.00            
-ATOM   1725 1H5'  DA A  55      87.710  56.070  30.760  1.00  0.00            
-ATOM   1726 2H5'  DA A  55      89.440  55.890  30.990  1.00  0.00            
-ATOM   1727  C4'  DA A  55      88.480  57.340  32.300  1.00  0.00            
-ATOM   1728  H4'  DA A  55      88.410  58.110  31.540  1.00  0.00            
-ATOM   1729  O4'  DA A  55      87.280  57.390  33.020  1.00  0.00            
-ATOM   1730  C1'  DA A  55      87.560  57.540  34.400  1.00  0.00            
-ATOM   1731  H1'  DA A  55      87.300  58.560  34.720  1.00  0.00            
-ATOM   1732  N9   DA A  55      86.760  56.580  35.160  1.00  0.00            
-ATOM   1733  C8   DA A  55      86.700  55.210  35.060  1.00  0.00            
-ATOM   1734  H8   DA A  55      87.310  54.660  34.370  1.00  0.00            
-ATOM   1735  N7   DA A  55      85.850  54.640  35.870  1.00  0.00            
-ATOM   1736  C5   DA A  55      85.280  55.750  36.530  1.00  0.00            
-ATOM   1737  C6   DA A  55      84.250  55.950  37.470  1.00  0.00            
-ATOM   1738  N6   DA A  55      83.500  55.000  37.980  1.00  0.00            
-ATOM   1739  H61  DA A  55      82.740  55.260  38.610  1.00  0.00            
-ATOM   1740  H62  DA A  55      83.690  54.040  37.780  1.00  0.00            
-ATOM   1741  N1   DA A  55      83.940  57.170  37.890  1.00  0.00            
-ATOM   1742  C2   DA A  55      84.600  58.220  37.410  1.00  0.00            
-ATOM   1743  H2   DA A  55      84.310  59.190  37.790  1.00  0.00            
-ATOM   1744  N3   DA A  55      85.590  58.200  36.530  1.00  0.00            
-ATOM   1745  C4   DA A  55      85.850  56.930  36.110  1.00  0.00            
-ATOM   1746  C3'  DA A  55      89.600  57.850  33.280  1.00  0.00            
-ATOM   1747  H3'  DA A  55      90.560  57.400  33.050  1.00  0.00            
-ATOM   1748  C2'  DA A  55      89.060  57.320  34.600  1.00  0.00            
-ATOM   1749 1H2'  DA A  55      89.280  56.260  34.690  1.00  0.00            
-ATOM   1750 2H2'  DA A  55      89.440  57.880  35.450  1.00  0.00            
-ATOM   1751  O3'  DA A  55      89.710  59.300  33.300  1.00  0.00            
-ATOM   1752  P    DC A  56      90.780  60.190  34.190  1.00  0.00            
-ATOM   1753  O1P  DC A  56      91.240  61.300  33.310  1.00  0.00            
-ATOM   1754  O2P  DC A  56      91.830  59.250  34.640  1.00  0.00            
-ATOM   1755  O5'  DC A  56      90.100  60.880  35.540  1.00  0.00            
-ATOM   1756  C5'  DC A  56      89.370  62.140  35.510  1.00  0.00            
-ATOM   1757 1H5'  DC A  56      88.650  62.060  34.700  1.00  0.00            
-ATOM   1758 2H5'  DC A  56      90.060  62.940  35.240  1.00  0.00            
-ATOM   1759  C4'  DC A  56      88.520  62.640  36.750  1.00  0.00            
-ATOM   1760  H4'  DC A  56      87.820  63.370  36.360  1.00  0.00            
-ATOM   1761  O4'  DC A  56      87.740  61.550  37.180  1.00  0.00            
-ATOM   1762  C1'  DC A  56      87.830  61.400  38.590  1.00  0.00            
-ATOM   1763  H1'  DC A  56      86.960  61.860  39.070  1.00  0.00            
-ATOM   1764  N1   DC A  56      87.900  59.950  38.880  1.00  0.00            
-ATOM   1765  C6   DC A  56      88.740  59.130  38.170  1.00  0.00            
-ATOM   1766  H6   DC A  56      89.370  59.580  37.420  1.00  0.00            
-ATOM   1767  C5   DC A  56      88.730  57.790  38.370  1.00  0.00            
-ATOM   1768  H5   DC A  56      89.360  57.140  37.800  1.00  0.00            
-ATOM   1769  C4   DC A  56      87.800  57.300  39.330  1.00  0.00            
-ATOM   1770  N4   DC A  56      87.660  56.030  39.510  1.00  0.00            
-ATOM   1771  H41  DC A  56      86.900  55.780  40.140  1.00  0.00            
-ATOM   1772  H42  DC A  56      88.030  55.370  38.870  1.00  0.00            
-ATOM   1773  N3   DC A  56      87.030  58.080  40.050  1.00  0.00            
-ATOM   1774  C2   DC A  56      87.040  59.410  39.850  1.00  0.00            
-ATOM   1775  O2   DC A  56      86.320  60.130  40.520  1.00  0.00            
-ATOM   1776  C3'  DC A  56      89.120  63.310  38.030  1.00  0.00            
-ATOM   1777  H3'  DC A  56      90.140  63.650  37.870  1.00  0.00            
-ATOM   1778  C2'  DC A  56      89.100  62.140  39.020  1.00  0.00            
-ATOM   1779 1H2'  DC A  56      89.980  61.520  38.870  1.00  0.00            
-ATOM   1780 2H2'  DC A  56      89.030  62.470  40.050  1.00  0.00            
-ATOM   1781  O3'  DC A  56      88.300  64.410  38.510  1.00  0.00            
-ATOM   1782  P    DC A  57      88.600  65.330  39.850  1.00  0.00            
-ATOM   1783  O1P  DC A  57      88.260  66.730  39.490  1.00  0.00            
-ATOM   1784  O2P  DC A  57      90.010  65.070  40.210  1.00  0.00            
-ATOM   1785  O5'  DC A  57      87.640  64.870  41.120  1.00  0.00            
-ATOM   1786  C5'  DC A  57      86.230  65.240  41.250  1.00  0.00            
-ATOM   1787 1H5'  DC A  57      85.780  65.020  40.280  1.00  0.00            
-ATOM   1788 2H5'  DC A  57      86.160  66.310  41.400  1.00  0.00            
-ATOM   1789  C4'  DC A  57      85.300  64.530  42.300  1.00  0.00            
-ATOM   1790  H4'  DC A  57      84.270  64.690  41.960  1.00  0.00            
-ATOM   1791  O4'  DC A  57      85.540  63.140  42.220  1.00  0.00            
-ATOM   1792  C1'  DC A  57      85.730  62.610  43.520  1.00  0.00            
-ATOM   1793  H1'  DC A  57      84.790  62.170  43.880  1.00  0.00            
-ATOM   1794  N1   DC A  57      86.800  61.590  43.430  1.00  0.00            
-ATOM   1795  C6   DC A  57      87.990  61.890  42.820  1.00  0.00            
-ATOM   1796  H6   DC A  57      88.130  62.900  42.450  1.00  0.00            
-ATOM   1797  C5   DC A  57      88.930  60.940  42.630  1.00  0.00            
-ATOM   1798  H5   DC A  57      89.850  61.160  42.120  1.00  0.00            
-ATOM   1799  C4   DC A  57      88.600  59.640  43.100  1.00  0.00            
-ATOM   1800  N4   DC A  57      89.390  58.640  42.850  1.00  0.00            
-ATOM   1801  H41  DC A  57      88.980  57.730  43.110  1.00  0.00            
-ATOM   1802  H42  DC A  57      90.130  58.720  42.210  1.00  0.00            
-ATOM   1803  N3   DC A  57      87.490  59.330  43.700  1.00  0.00            
-ATOM   1804  C2   DC A  57      86.550  60.290  43.880  1.00  0.00            
-ATOM   1805  O2   DC A  57      85.500  59.980  44.430  1.00  0.00            
-ATOM   1806  C3'  DC A  57      85.270  64.900  43.820  1.00  0.00            
-ATOM   1807  H3'  DC A  57      85.710  65.870  44.010  1.00  0.00            
-ATOM   1808  C2'  DC A  57      86.120  63.780  44.410  1.00  0.00            
-ATOM   1809 1H2'  DC A  57      87.170  64.030  44.310  1.00  0.00            
-ATOM   1810 2H2'  DC A  57      85.880  63.580  45.460  1.00  0.00            
-ATOM   1811  O3'  DC A  57      83.920  64.860  44.360  1.00  0.00            
-ATOM   1812  P    DG A  58      83.520  65.170  45.920  1.00  0.00            
-ATOM   1813  O1P  DG A  58      82.350  66.090  45.900  1.00  0.00            
-ATOM   1814  O2P  DG A  58      84.750  65.700  46.570  1.00  0.00            
-ATOM   1815  O5'  DG A  58      83.080  63.770  46.690  1.00  0.00            
-ATOM   1816  C5'  DG A  58      81.780  63.130  46.510  1.00  0.00            
-ATOM   1817 1H5'  DG A  58      81.620  63.070  45.430  1.00  0.00            
-ATOM   1818 2H5'  DG A  58      81.000  63.780  46.900  1.00  0.00            
-ATOM   1819  C4'  DG A  58      81.540  61.670  47.050  1.00  0.00            
-ATOM   1820  H4'  DG A  58      80.660  61.270  46.550  1.00  0.00            
-ATOM   1821  O4'  DG A  58      82.660  60.920  46.640  1.00  0.00            
-ATOM   1822  C1'  DG A  58      83.270  60.390  47.800  1.00  0.00            
-ATOM   1823  H1'  DG A  58      82.950  59.350  47.930  1.00  0.00            
-ATOM   1824  N9   DG A  58      84.730  60.440  47.680  1.00  0.00            
-ATOM   1825  C8   DG A  58      85.550  61.510  47.430  1.00  0.00            
-ATOM   1826  H8   DG A  58      85.150  62.510  47.350  1.00  0.00            
-ATOM   1827  N7   DG A  58      86.810  61.200  47.260  1.00  0.00            
-ATOM   1828  C5   DG A  58      86.810  59.790  47.410  1.00  0.00            
-ATOM   1829  C6   DG A  58      87.840  58.800  47.280  1.00  0.00            
-ATOM   1830  O6   DG A  58      89.030  58.960  46.990  1.00  0.00            
-ATOM   1831  N1   DG A  58      87.390  57.510  47.500  1.00  0.00            
-ATOM   1832  H1   DG A  58      88.040  56.750  47.370  1.00  0.00            
-ATOM   1833  C2   DG A  58      86.120  57.190  47.850  1.00  0.00            
-ATOM   1834  N2   DG A  58      85.810  55.940  48.010  1.00  0.00            
-ATOM   1835  H21  DG A  58      86.470  55.190  47.840  1.00  0.00            
-ATOM   1836  H22  DG A  58      84.850  55.740  48.240  1.00  0.00            
-ATOM   1837  N3   DG A  58      85.150  58.070  48.010  1.00  0.00            
-ATOM   1838  C4   DG A  58      85.550  59.350  47.740  1.00  0.00            
-ATOM   1839  C3'  DG A  58      81.330  61.350  48.570  1.00  0.00            
-ATOM   1840  H3'  DG A  58      80.840  62.170  49.090  1.00  0.00            
-ATOM   1841  C2'  DG A  58      82.780  61.200  48.980  1.00  0.00            
-ATOM   1842 1H2'  DG A  58      83.260  62.170  49.040  1.00  0.00            
-ATOM   1843 2H2'  DG A  58      82.870  60.640  49.900  1.00  0.00            
-ATOM   1844  O3'  DG A  58      80.630  60.100  48.820  1.00  0.00            
-ATOM   1845  P    DT A  59      80.280  59.490  50.320  1.00  0.00            
-ATOM   1846  O1P  DT A  59      78.840  59.180  50.350  1.00  0.00            
-ATOM   1847  O2P  DT A  59      80.780  60.480  51.300  1.00  0.00            
-ATOM   1848  O5'  DT A  59      81.100  58.080  50.610  1.00  0.00            
-ATOM   1849  C5'  DT A  59      80.680  56.800  50.080  1.00  0.00            
-ATOM   1850 1H5'  DT A  59      80.640  56.940  49.000  1.00  0.00            
-ATOM   1851 2H5'  DT A  59      79.660  56.600  50.410  1.00  0.00            
-ATOM   1852  C4'  DT A  59      81.550  55.500  50.310  1.00  0.00            
-ATOM   1853  H4'  DT A  59      81.230  54.780  49.550  1.00  0.00            
-ATOM   1854  O4'  DT A  59      82.900  55.840  50.030  1.00  0.00            
-ATOM   1855  C1'  DT A  59      83.640  55.700  51.220  1.00  0.00            
-ATOM   1856  H1'  DT A  59      84.190  54.760  51.160  1.00  0.00            
-ATOM   1857  N1   DT A  59      84.590  56.830  51.350  1.00  0.00            
-ATOM   1858  C6   DT A  59      84.170  58.120  51.610  1.00  0.00            
-ATOM   1859  H6   DT A  59      83.120  58.310  51.800  1.00  0.00            
-ATOM   1860  C5   DT A  59      85.050  59.160  51.570  1.00  0.00            
-ATOM   1861  C7   DT A  59      84.590  60.570  51.890  1.00  0.00            
-ATOM   1862  H71  DT A  59      83.520  60.590  52.120  1.00  0.00            
-ATOM   1863  H72  DT A  59      85.150  60.940  52.750  1.00  0.00            
-ATOM   1864  H73  DT A  59      84.800  61.220  51.040  1.00  0.00            
-ATOM   1865  C4   DT A  59      86.440  58.940  51.200  1.00  0.00            
-ATOM   1866  O4   DT A  59      87.310  59.800  51.050  1.00  0.00            
-ATOM   1867  N3   DT A  59      86.780  57.620  51.030  1.00  0.00            
-ATOM   1868  H3   DT A  59      87.730  57.400  50.810  1.00  0.00            
-ATOM   1869  C2   DT A  59      85.930  56.550  51.110  1.00  0.00            
-ATOM   1870  O2   DT A  59      86.410  55.420  51.000  1.00  0.00            
-ATOM   1871  C3'  DT A  59      81.600  54.710  51.660  1.00  0.00            
-ATOM   1872  H3'  DT A  59      80.640  54.740  52.170  1.00  0.00            
-ATOM   1873  C2'  DT A  59      82.640  55.550  52.370  1.00  0.00            
-ATOM   1874 1H2'  DT A  59      82.210  56.500  52.670  1.00  0.00            
-ATOM   1875 2H2'  DT A  59      83.070  55.030  53.230  1.00  0.00            
-ATOM   1876  O3'  DT A  59      82.070  53.330  51.490  1.00  0.00            
-ATOM   1877  P    DA A  60      82.200  52.200  52.690  1.00  0.00            
-ATOM   1878  O1P  DA A  60      81.540  50.950  52.220  1.00  0.00            
-ATOM   1879  O2P  DA A  60      81.700  52.800  53.930  1.00  0.00            
-ATOM   1880  O5'  DA A  60      83.780  51.790  52.970  1.00  0.00            
-ATOM   1881  C5'  DA A  60      84.430  50.690  52.310  1.00  0.00            
-ATOM   1882 1H5'  DA A  60      84.370  50.900  51.240  1.00  0.00            
-ATOM   1883 2H5'  DA A  60      83.840  49.790  52.480  1.00  0.00            
-ATOM   1884  C4'  DA A  60      85.940  50.360  52.610  1.00  0.00            
-ATOM   1885  H4'  DA A  60      86.260  49.680  51.830  1.00  0.00            
-ATOM   1886  O4'  DA A  60      86.670  51.560  52.450  1.00  0.00            
-ATOM   1887  C1'  DA A  60      87.080  52.000  53.730  1.00  0.00            
-ATOM   1888  H1'  DA A  60      88.170  51.900  53.780  1.00  0.00            
-ATOM   1889  N9   DA A  60      86.750  53.420  53.920  1.00  0.00            
-ATOM   1890  C8   DA A  60      85.560  54.040  54.240  1.00  0.00            
-ATOM   1891  H8   DA A  60      84.630  53.500  54.380  1.00  0.00            
-ATOM   1892  N7   DA A  60      85.650  55.340  54.370  1.00  0.00            
-ATOM   1893  C5   DA A  60      87.000  55.580  54.070  1.00  0.00            
-ATOM   1894  C6   DA A  60      87.800  56.730  53.970  1.00  0.00            
-ATOM   1895  N6   DA A  60      87.370  57.960  54.170  1.00  0.00            
-ATOM   1896  H61  DA A  60      88.010  58.740  54.080  1.00  0.00            
-ATOM   1897  H62  DA A  60      86.430  58.080  54.490  1.00  0.00            
-ATOM   1898  N1   DA A  60      89.090  56.650  53.660  1.00  0.00            
-ATOM   1899  C2   DA A  60      89.620  55.440  53.470  1.00  0.00            
-ATOM   1900  H2   DA A  60      90.670  55.410  53.250  1.00  0.00            
-ATOM   1901  N3   DA A  60      89.010  54.270  53.540  1.00  0.00            
-ATOM   1902  C4   DA A  60      87.680  54.420  53.820  1.00  0.00            
-ATOM   1903  C3'  DA A  60      86.440  49.770  53.970  1.00  0.00            
-ATOM   1904  H3'  DA A  60      85.710  49.070  54.390  1.00  0.00            
-ATOM   1905  C2'  DA A  60      86.470  51.060  54.770  1.00  0.00            
-ATOM   1906 1H2'  DA A  60      85.460  51.370  55.040  1.00  0.00            
-ATOM   1907 2H2'  DA A  60      87.090  50.980  55.660  1.00  0.00            
-ATOM   1908  O3'  DA A  60      87.760  49.150  53.870  1.00  0.00            
-ATOM   1909  P    DT B   1      95.150  63.890  55.830  1.00  0.00            
-ATOM   1910  O1P  DT B   1      96.530  64.220  56.280  1.00  0.00            
-ATOM   1911  O2P  DT B   1      94.520  64.870  54.910  1.00  0.00            
-ATOM   1912  O5'  DT B   1      95.270  62.440  55.000  1.00  0.00            
-ATOM   1913  C5'  DT B   1      96.380  61.510  55.190  1.00  0.00            
-ATOM   1914 1H5'  DT B   1      96.450  61.370  56.260  1.00  0.00            
-ATOM   1915 2H5'  DT B   1      97.290  62.010  54.870  1.00  0.00            
-ATOM   1916  C4'  DT B   1      96.370  60.060  54.570  1.00  0.00            
-ATOM   1917  H4'  DT B   1      97.080  59.480  55.160  1.00  0.00            
-ATOM   1918  O4'  DT B   1      95.100  59.520  54.840  1.00  0.00            
-ATOM   1919  C1'  DT B   1      94.500  59.120  53.630  1.00  0.00            
-ATOM   1920  H1'  DT B   1      94.600  58.030  53.550  1.00  0.00            
-ATOM   1921  N1   DT B   1      93.060  59.480  53.670  1.00  0.00            
-ATOM   1922  C6   DT B   1      92.630  60.800  53.600  1.00  0.00            
-ATOM   1923  H6   DT B   1      93.360  61.590  53.500  1.00  0.00            
-ATOM   1924  C5   DT B   1      91.310  61.100  53.670  1.00  0.00            
-ATOM   1925  C7   DT B   1      90.840  62.540  53.490  1.00  0.00            
-ATOM   1926  H71  DT B   1      91.680  63.220  53.370  1.00  0.00            
-ATOM   1927  H72  DT B   1      90.200  62.580  52.610  1.00  0.00            
-ATOM   1928  H73  DT B   1      90.240  62.820  54.360  1.00  0.00            
-ATOM   1929  C4   DT B   1      90.320  60.060  53.920  1.00  0.00            
-ATOM   1930  O4   DT B   1      89.120  60.230  54.070  1.00  0.00            
-ATOM   1931  N3   DT B   1      90.840  58.790  53.990  1.00  0.00            
-ATOM   1932  H3   DT B   1      90.180  58.030  54.090  1.00  0.00            
-ATOM   1933  C2   DT B   1      92.150  58.430  53.820  1.00  0.00            
-ATOM   1934  O2   DT B   1      92.470  57.250  53.770  1.00  0.00            
-ATOM   1935  C3'  DT B   1      96.690  59.700  53.070  1.00  0.00            
-ATOM   1936  H3'  DT B   1      97.330  60.460  52.620  1.00  0.00            
-ATOM   1937  C2'  DT B   1      95.290  59.750  52.480  1.00  0.00            
-ATOM   1938 1H2'  DT B   1      95.000  60.780  52.310  1.00  0.00            
-ATOM   1939 2H2'  DT B   1      95.210  59.160  51.570  1.00  0.00            
-ATOM   1940  O3'  DT B   1      97.280  58.370  52.910  1.00  0.00            
-ATOM   1941  P    DA B   2      97.840  57.710  51.490  1.00  0.00            
-ATOM   1942  O1P  DA B   2      99.150  57.070  51.800  1.00  0.00            
-ATOM   1943  O2P  DA B   2      97.880  58.810  50.490  1.00  0.00            
-ATOM   1944  O5'  DA B   2      96.860  56.520  50.880  1.00  0.00            
-ATOM   1945  C5'  DA B   2      97.020  55.110  51.210  1.00  0.00            
-ATOM   1946 1H5'  DA B   2      97.070  55.070  52.300  1.00  0.00            
-ATOM   1947 2H5'  DA B   2      97.980  54.770  50.840  1.00  0.00            
-ATOM   1948  C4'  DA B   2      95.930  54.030  50.810  1.00  0.00            
-ATOM   1949  H4'  DA B   2      96.110  53.170  51.460  1.00  0.00            
-ATOM   1950  O4'  DA B   2      94.680  54.550  51.180  1.00  0.00            
-ATOM   1951  C1'  DA B   2      93.840  54.610  50.050  1.00  0.00            
-ATOM   1952  H1'  DA B   2      93.070  53.820  50.120  1.00  0.00            
-ATOM   1953  N9   DA B   2      93.190  55.920  50.020  1.00  0.00            
-ATOM   1954  C8   DA B   2      93.760  57.170  50.010  1.00  0.00            
-ATOM   1955  H8   DA B   2      94.830  57.320  50.030  1.00  0.00            
-ATOM   1956  N7   DA B   2      92.910  58.160  49.990  1.00  0.00            
-ATOM   1957  C5   DA B   2      91.670  57.480  50.030  1.00  0.00            
-ATOM   1958  C6   DA B   2      90.310  57.860  50.110  1.00  0.00            
-ATOM   1959  N6   DA B   2      89.890  59.100  50.210  1.00  0.00            
-ATOM   1960  H61  DA B   2      88.890  59.250  50.340  1.00  0.00            
-ATOM   1961  H62  DA B   2      90.550  59.850  50.220  1.00  0.00            
-ATOM   1962  N1   DA B   2      89.350  56.950  50.110  1.00  0.00            
-ATOM   1963  C2   DA B   2      89.670  55.660  50.070  1.00  0.00            
-ATOM   1964  H2   DA B   2      88.850  54.950  50.080  1.00  0.00            
-ATOM   1965  N3   DA B   2      90.890  55.150  50.000  1.00  0.00            
-ATOM   1966  C4   DA B   2      91.840  56.120  50.020  1.00  0.00            
-ATOM   1967  C3'  DA B   2      95.750  53.430  49.370  1.00  0.00            
-ATOM   1968  H3'  DA B   2      96.670  53.490  48.800  1.00  0.00            
-ATOM   1969  C2'  DA B   2      94.700  54.370  48.810  1.00  0.00            
-ATOM   1970 1H2'  DA B   2      95.170  55.290  48.490  1.00  0.00            
-ATOM   1971 2H2'  DA B   2      94.120  53.920  48.000  1.00  0.00            
-ATOM   1972  O3'  DA B   2      95.260  52.050  49.400  1.00  0.00            
-ATOM   1973  P    DC B   3      94.930  51.110  48.080  1.00  0.00            
-ATOM   1974  O1P  DC B   3      95.420  49.740  48.390  1.00  0.00            
-ATOM   1975  O2P  DC B   3      95.570  51.780  46.920  1.00  0.00            
-ATOM   1976  O5'  DC B   3      93.300  51.000  47.780  1.00  0.00            
-ATOM   1977  C5'  DC B   3      92.410  50.120  48.530  1.00  0.00            
-ATOM   1978 1H5'  DC B   3      92.610  50.320  49.580  1.00  0.00            
-ATOM   1979 2H5'  DC B   3      92.700  49.090  48.340  1.00  0.00            
-ATOM   1980  C4'  DC B   3      90.840  50.230  48.370  1.00  0.00            
-ATOM   1981  H4'  DC B   3      90.420  49.730  49.250  1.00  0.00            
-ATOM   1982  O4'  DC B   3      90.500  51.590  48.490  1.00  0.00            
-ATOM   1983  C1'  DC B   3      89.590  51.960  47.470  1.00  0.00            
-ATOM   1984  H1'  DC B   3      88.560  51.950  47.850  1.00  0.00            
-ATOM   1985  N1   DC B   3      89.980  53.320  47.010  1.00  0.00            
-ATOM   1986  C6   DC B   3      91.300  53.600  46.740  1.00  0.00            
-ATOM   1987  H6   DC B   3      92.020  52.800  46.830  1.00  0.00            
-ATOM   1988  C5   DC B   3      91.690  54.870  46.450  1.00  0.00            
-ATOM   1989  H5   DC B   3      92.720  55.100  46.280  1.00  0.00            
-ATOM   1990  C4   DC B   3      90.660  55.850  46.430  1.00  0.00            
-ATOM   1991  N4   DC B   3      90.960  57.100  46.280  1.00  0.00            
-ATOM   1992  H41  DC B   3      90.160  57.720  46.430  1.00  0.00            
-ATOM   1993  H42  DC B   3      91.890  57.410  46.440  1.00  0.00            
-ATOM   1994  N3   DC B   3      89.400  55.600  46.660  1.00  0.00            
-ATOM   1995  C2   DC B   3      89.020  54.340  46.970  1.00  0.00            
-ATOM   1996  O2   DC B   3      87.850  54.130  47.230  1.00  0.00            
-ATOM   1997  C3'  DC B   3      90.040  49.650  47.160  1.00  0.00            
-ATOM   1998  H3'  DC B   3      90.640  48.960  46.580  1.00  0.00            
-ATOM   1999  C2'  DC B   3      89.740  50.910  46.370  1.00  0.00            
-ATOM   2000 1H2'  DC B   3      90.580  51.140  45.720  1.00  0.00            
-ATOM   2001 2H2'  DC B   3      88.830  50.830  45.780  1.00  0.00            
-ATOM   2002  O3'  DC B   3      88.820  48.990  47.590  1.00  0.00            
-ATOM   2003  P    DG B   4      87.700  48.300  46.600  1.00  0.00            
-ATOM   2004  O1P  DG B   4      87.250  47.050  47.250  1.00  0.00            
-ATOM   2005  O2P  DG B   4      88.350  48.150  45.270  1.00  0.00            
-ATOM   2006  O5'  DG B   4      86.380  49.300  46.430  1.00  0.00            
-ATOM   2007  C5'  DG B   4      85.370  49.470  47.460  1.00  0.00            
-ATOM   2008 1H5'  DG B   4      85.920  49.640  48.390  1.00  0.00            
-ATOM   2009 2H5'  DG B   4      84.830  48.530  47.580  1.00  0.00            
-ATOM   2010  C4'  DG B   4      84.320  50.640  47.380  1.00  0.00            
-ATOM   2011  H4'  DG B   4      83.910  50.780  48.380  1.00  0.00            
-ATOM   2012  O4'  DG B   4      85.070  51.800  47.060  1.00  0.00            
-ATOM   2013  C1'  DG B   4      84.480  52.410  45.930  1.00  0.00            
-ATOM   2014  H1'  DG B   4      83.800  53.210  46.250  1.00  0.00            
-ATOM   2015  N9   DG B   4      85.550  52.970  45.090  1.00  0.00            
-ATOM   2016  C8   DG B   4      86.650  52.350  44.570  1.00  0.00            
-ATOM   2017  H8   DG B   4      86.800  51.280  44.700  1.00  0.00            
-ATOM   2018  N7   DG B   4      87.480  53.140  43.940  1.00  0.00            
-ATOM   2019  C5   DG B   4      86.860  54.400  44.090  1.00  0.00            
-ATOM   2020  C6   DG B   4      87.270  55.730  43.710  1.00  0.00            
-ATOM   2021  O6   DG B   4      88.290  56.080  43.110  1.00  0.00            
-ATOM   2022  N1   DG B   4      86.360  56.710  44.080  1.00  0.00            
-ATOM   2023  H1   DG B   4      86.600  57.680  43.900  1.00  0.00            
-ATOM   2024  C2   DG B   4      85.200  56.470  44.730  1.00  0.00            
-ATOM   2025  N2   DG B   4      84.430  57.470  45.040  1.00  0.00            
-ATOM   2026  H21  DG B   4      84.680  58.430  44.820  1.00  0.00            
-ATOM   2027  H22  DG B   4      83.580  57.250  45.530  1.00  0.00            
-ATOM   2028  N3   DG B   4      84.790  55.270  45.090  1.00  0.00            
-ATOM   2029  C4   DG B   4      85.670  54.290  44.760  1.00  0.00            
-ATOM   2030  C3'  DG B   4      83.090  50.630  46.420  1.00  0.00            
-ATOM   2031  H3'  DG B   4      82.780  49.620  46.170  1.00  0.00            
-ATOM   2032  C2'  DG B   4      83.680  51.340  45.210  1.00  0.00            
-ATOM   2033 1H2'  DG B   4      84.340  50.660  44.660  1.00  0.00            
-ATOM   2034 2H2'  DG B   4      82.930  51.770  44.560  1.00  0.00            
-ATOM   2035  O3'  DG B   4      81.970  51.390  46.950  1.00  0.00            
-ATOM   2036  P    DG B   5      80.510  51.570  46.210  1.00  0.00            
-ATOM   2037  O1P  DG B   5      79.470  51.160  47.180  1.00  0.00            
-ATOM   2038  O2P  DG B   5      80.590  50.790  44.940  1.00  0.00            
-ATOM   2039  O5'  DG B   5      80.260  53.160  45.820  1.00  0.00            
-ATOM   2040  C5'  DG B   5      79.840  54.160  46.780  1.00  0.00            
-ATOM   2041 1H5'  DG B   5      80.540  54.090  47.610  1.00  0.00            
-ATOM   2042 2H5'  DG B   5      78.860  53.900  47.160  1.00  0.00            
-ATOM   2043  C4'  DG B   5      79.820  55.690  46.370  1.00  0.00            
-ATOM   2044  H4'  DG B   5      79.810  56.270  47.290  1.00  0.00            
-ATOM   2045  O4'  DG B   5      81.050  55.940  45.710  1.00  0.00            
-ATOM   2046  C1'  DG B   5      80.740  56.290  44.370  1.00  0.00            
-ATOM   2047  H1'  DG B   5      80.830  57.380  44.280  1.00  0.00            
-ATOM   2048  N9   DG B   5      81.650  55.640  43.430  1.00  0.00            
-ATOM   2049  C8   DG B   5      81.900  54.310  43.200  1.00  0.00            
-ATOM   2050  H8   DG B   5      81.340  53.530  43.700  1.00  0.00            
-ATOM   2051  N7   DG B   5      82.890  54.090  42.370  1.00  0.00            
-ATOM   2052  C5   DG B   5      83.320  55.380  42.040  1.00  0.00            
-ATOM   2053  C6   DG B   5      84.430  55.860  41.270  1.00  0.00            
-ATOM   2054  O6   DG B   5      85.310  55.220  40.680  1.00  0.00            
-ATOM   2055  N1   DG B   5      84.530  57.240  41.230  1.00  0.00            
-ATOM   2056  H1   DG B   5      85.320  57.640  40.770  1.00  0.00            
-ATOM   2057  C2   DG B   5      83.660  58.080  41.840  1.00  0.00            
-ATOM   2058  N2   DG B   5      83.850  59.360  41.760  1.00  0.00            
-ATOM   2059  H21  DG B   5      84.660  59.750  41.280  1.00  0.00            
-ATOM   2060  H22  DG B   5      83.170  59.940  42.230  1.00  0.00            
-ATOM   2061  N3   DG B   5      82.610  57.690  42.540  1.00  0.00            
-ATOM   2062  C4   DG B   5      82.520  56.330  42.630  1.00  0.00            
-ATOM   2063  C3'  DG B   5      78.720  56.330  45.470  1.00  0.00            
-ATOM   2064  H3'  DG B   5      77.740  55.890  45.640  1.00  0.00            
-ATOM   2065  C2'  DG B   5      79.280  55.930  44.130  1.00  0.00            
-ATOM   2066 1H2'  DG B   5      79.150  54.860  43.950  1.00  0.00            
-ATOM   2067 2H2'  DG B   5      78.860  56.530  43.330  1.00  0.00            
-ATOM   2068  O3'  DG B   5      78.650  57.790  45.540  1.00  0.00            
-ATOM   2069  P    DT B   6      77.630  58.750  44.670  1.00  0.00            
-ATOM   2070  O1P  DT B   6      76.960  59.690  45.600  1.00  0.00            
-ATOM   2071  O2P  DT B   6      76.780  57.860  43.850  1.00  0.00            
-ATOM   2072  O5'  DT B   6      78.450  59.700  43.580  1.00  0.00            
-ATOM   2073  C5'  DT B   6      79.000  60.990  43.920  1.00  0.00            
-ATOM   2074 1H5'  DT B   6      79.710  60.800  44.720  1.00  0.00            
-ATOM   2075 2H5'  DT B   6      78.200  61.600  44.350  1.00  0.00            
-ATOM   2076  C4'  DT B   6      79.760  61.840  42.830  1.00  0.00            
-ATOM   2077  H4'  DT B   6      80.350  62.570  43.380  1.00  0.00            
-ATOM   2078  O4'  DT B   6      80.650  60.970  42.160  1.00  0.00            
-ATOM   2079  C1'  DT B   6      80.200  60.820  40.830  1.00  0.00            
-ATOM   2080  H1'  DT B   6      80.850  61.430  40.200  1.00  0.00            
-ATOM   2081  N1   DT B   6      80.310  59.400  40.410  1.00  0.00            
-ATOM   2082  C6   DT B   6      79.400  58.420  40.790  1.00  0.00            
-ATOM   2083  H6   DT B   6      78.550  58.680  41.410  1.00  0.00            
-ATOM   2084  C5   DT B   6      79.600  57.120  40.440  1.00  0.00            
-ATOM   2085  C7   DT B   6      78.580  56.050  40.800  1.00  0.00            
-ATOM   2086  H71  DT B   6      77.740  56.480  41.350  1.00  0.00            
-ATOM   2087  H72  DT B   6      78.210  55.590  39.880  1.00  0.00            
-ATOM   2088  H73  DT B   6      79.070  55.280  41.390  1.00  0.00            
-ATOM   2089  C4   DT B   6      80.800  56.720  39.700  1.00  0.00            
-ATOM   2090  O4   DT B   6      81.140  55.590  39.390  1.00  0.00            
-ATOM   2091  N3   DT B   6      81.590  57.770  39.320  1.00  0.00            
-ATOM   2092  H3   DT B   6      82.410  57.550  38.780  1.00  0.00            
-ATOM   2093  C2   DT B   6      81.400  59.090  39.600  1.00  0.00            
-ATOM   2094  O2   DT B   6      82.180  59.910  39.120  1.00  0.00            
-ATOM   2095  C3'  DT B   6      79.010  62.620  41.690  1.00  0.00            
-ATOM   2096  H3'  DT B   6      78.060  63.020  42.050  1.00  0.00            
-ATOM   2097  C2'  DT B   6      78.810  61.460  40.740  1.00  0.00            
-ATOM   2098 1H2'  DT B   6      78.030  60.790  41.120  1.00  0.00            
-ATOM   2099 2H2'  DT B   6      78.570  61.790  39.730  1.00  0.00            
-ATOM   2100  O3'  DT B   6      79.840  63.670  41.100  1.00  0.00            
-ATOM   2101  P    DA B   7      79.360  64.770  39.950  1.00  0.00            
-ATOM   2102  O1P  DA B   7      79.840  66.120  40.380  1.00  0.00            
-ATOM   2103  O2P  DA B   7      77.910  64.620  39.740  1.00  0.00            
-ATOM   2104  O5'  DA B   7      80.090  64.510  38.490  1.00  0.00            
-ATOM   2105  C5'  DA B   7      81.320  65.150  38.110  1.00  0.00            
-ATOM   2106 1H5'  DA B   7      82.040  64.900  38.900  1.00  0.00            
-ATOM   2107 2H5'  DA B   7      81.160  66.230  38.160  1.00  0.00            
-ATOM   2108  C4'  DA B   7      82.040  64.830  36.750  1.00  0.00            
-ATOM   2109  H4'  DA B   7      83.010  65.320  36.810  1.00  0.00            
-ATOM   2110  O4'  DA B   7      82.280  63.440  36.710  1.00  0.00            
-ATOM   2111  C1'  DA B   7      81.450  62.870  35.720  1.00  0.00            
-ATOM   2112  H1'  DA B   7      82.090  62.520  34.910  1.00  0.00            
-ATOM   2113  N9   DA B   7      80.720  61.710  36.260  1.00  0.00            
-ATOM   2114  C8   DA B   7      79.650  61.640  37.130  1.00  0.00            
-ATOM   2115  H8   DA B   7      79.200  62.510  37.590  1.00  0.00            
-ATOM   2116  N7   DA B   7      79.230  60.420  37.350  1.00  0.00            
-ATOM   2117  C5   DA B   7      80.100  59.650  36.570  1.00  0.00            
-ATOM   2118  C6   DA B   7      80.260  58.270  36.330  1.00  0.00            
-ATOM   2119  N6   DA B   7      79.520  57.320  36.870  1.00  0.00            
-ATOM   2120  H61  DA B   7      79.740  56.350  36.680  1.00  0.00            
-ATOM   2121  H62  DA B   7      78.770  57.600  37.460  1.00  0.00            
-ATOM   2122  N1   DA B   7      81.230  57.830  35.530  1.00  0.00            
-ATOM   2123  C2   DA B   7      82.030  58.710  34.950  1.00  0.00            
-ATOM   2124  H2   DA B   7      82.790  58.310  34.300  1.00  0.00            
-ATOM   2125  N3   DA B   7      82.000  60.020  35.060  1.00  0.00            
-ATOM   2126  C4   DA B   7      81.010  60.420  35.910  1.00  0.00            
-ATOM   2127  C3'  DA B   7      81.450  65.180  35.340  1.00  0.00            
-ATOM   2128  H3'  DA B   7      80.880  66.100  35.370  1.00  0.00            
-ATOM   2129  C2'  DA B   7      80.540  63.970  35.170  1.00  0.00            
-ATOM   2130 1H2'  DA B   7      79.650  64.090  35.790  1.00  0.00            
-ATOM   2131 2H2'  DA B   7      80.280  63.800  34.130  1.00  0.00            
-ATOM   2132  O3'  DA B   7      82.500  65.240  34.310  1.00  0.00            
-ATOM   2133  P    DG B   8      82.320  65.700  32.720  1.00  0.00            
-ATOM   2134  O1P  DG B   8      83.540  66.480  32.370  1.00  0.00            
-ATOM   2135  O2P  DG B   8      81.030  66.420  32.590  1.00  0.00            
-ATOM   2136  O5'  DG B   8      82.290  64.420  31.660  1.00  0.00            
-ATOM   2137  C5'  DG B   8      83.500  63.900  31.040  1.00  0.00            
-ATOM   2138 1H5'  DG B   8      84.170  63.660  31.880  1.00  0.00            
-ATOM   2139 2H5'  DG B   8      83.970  64.720  30.500  1.00  0.00            
-ATOM   2140  C4'  DG B   8      83.520  62.630  30.120  1.00  0.00            
-ATOM   2141  H4'  DG B   8      84.580  62.420  29.930  1.00  0.00            
-ATOM   2142  O4'  DG B   8      83.050  61.550  30.890  1.00  0.00            
-ATOM   2143  C1'  DG B   8      81.850  61.080  30.310  1.00  0.00            
-ATOM   2144  H1'  DG B   8      82.050  60.110  29.860  1.00  0.00            
-ATOM   2145  N9   DG B   8      80.830  60.900  31.350  1.00  0.00            
-ATOM   2146  C8   DG B   8      80.140  61.820  32.100  1.00  0.00            
-ATOM   2147  H8   DG B   8      80.310  62.880  32.040  1.00  0.00            
-ATOM   2148  N7   DG B   8      79.260  61.280  32.910  1.00  0.00            
-ATOM   2149  C5   DG B   8      79.400  59.900  32.690  1.00  0.00            
-ATOM   2150  C6   DG B   8      78.770  58.730  33.250  1.00  0.00            
-ATOM   2151  O6   DG B   8      77.900  58.650  34.120  1.00  0.00            
-ATOM   2152  N1   DG B   8      79.230  57.550  32.710  1.00  0.00            
-ATOM   2153  H1   DG B   8      78.810  56.700  33.060  1.00  0.00            
-ATOM   2154  C2   DG B   8      80.170  57.470  31.750  1.00  0.00            
-ATOM   2155  N2   DG B   8      80.500  56.310  31.280  1.00  0.00            
-ATOM   2156  H21  DG B   8      80.060  55.470  31.650  1.00  0.00            
-ATOM   2157  H22  DG B   8      81.210  56.280  30.570  1.00  0.00            
-ATOM   2158  N3   DG B   8      80.780  58.500  31.190  1.00  0.00            
-ATOM   2159  C4   DG B   8      80.360  59.680  31.720  1.00  0.00            
-ATOM   2160  C3'  DG B   8      82.820  62.490  28.720  1.00  0.00            
-ATOM   2161  H3'  DG B   8      82.760  63.450  28.210  1.00  0.00            
-ATOM   2162  C2'  DG B   8      81.440  62.040  29.200  1.00  0.00            
-ATOM   2163 1H2'  DG B   8      80.890  62.890  29.600  1.00  0.00            
-ATOM   2164 2H2'  DG B   8      80.870  61.540  28.420  1.00  0.00            
-ATOM   2165  O3'  DG B   8      83.460  61.480  27.870  1.00  0.00            
-ATOM   2166  P    DA B   9      83.080  61.100  26.300  1.00  0.00            
-ATOM   2167  O1P  DA B   9      84.370  60.870  25.600  1.00  0.00            
-ATOM   2168  O2P  DA B   9      82.250  62.220  25.770  1.00  0.00            
-ATOM   2169  O5'  DA B   9      82.200  59.690  26.120  1.00  0.00            
-ATOM   2170  C5'  DA B   9      82.830  58.400  25.870  1.00  0.00            
-ATOM   2171 1H5'  DA B   9      83.590  58.300  26.650  1.00  0.00            
-ATOM   2172 2H5'  DA B   9      83.360  58.460  24.920  1.00  0.00            
-ATOM   2173  C4'  DA B   9      82.040  57.030  25.890  1.00  0.00            
-ATOM   2174  H4'  DA B   9      82.810  56.260  25.960  1.00  0.00            
-ATOM   2175  O4'  DA B   9      81.330  56.960  27.110  1.00  0.00            
-ATOM   2176  C1'  DA B   9      79.950  56.820  26.830  1.00  0.00            
-ATOM   2177  H1'  DA B   9      79.620  55.810  27.090  1.00  0.00            
-ATOM   2178  N9   DA B   9      79.210  57.790  27.640  1.00  0.00            
-ATOM   2179  C8   DA B   9      79.280  59.160  27.660  1.00  0.00            
-ATOM   2180  H8   DA B   9      79.930  59.720  27.010  1.00  0.00            
-ATOM   2181  N7   DA B   9      78.490  59.730  28.520  1.00  0.00            
-ATOM   2182  C5   DA B   9      77.880  58.620  29.150  1.00  0.00            
-ATOM   2183  C6   DA B   9      76.980  58.430  30.220  1.00  0.00            
-ATOM   2184  N6   DA B   9      76.460  59.390  30.960  1.00  0.00            
-ATOM   2185  H61  DA B   9      75.860  59.120  31.730  1.00  0.00            
-ATOM   2186  H62  DA B   9      76.740  60.340  30.830  1.00  0.00            
-ATOM   2187  N1   DA B   9      76.610  57.210  30.580  1.00  0.00            
-ATOM   2188  C2   DA B   9      77.090  56.160  29.940  1.00  0.00            
-ATOM   2189  H2   DA B   9      76.750  55.190  30.270  1.00  0.00            
-ATOM   2190  N3   DA B   9      77.940  56.180  28.920  1.00  0.00            
-ATOM   2191  C4   DA B   9      78.300  57.450  28.600  1.00  0.00            
-ATOM   2192  C3'  DA B   9      81.060  56.510  24.780  1.00  0.00            
-ATOM   2193  H3'  DA B   9      81.280  56.950  23.820  1.00  0.00            
-ATOM   2194  C2'  DA B   9      79.740  57.040  25.330  1.00  0.00            
-ATOM   2195 1H2'  DA B   9      79.640  58.100  25.100  1.00  0.00            
-ATOM   2196 2H2'  DA B   9      78.880  56.480  24.960  1.00  0.00            
-ATOM   2197  O3'  DA B   9      81.050  55.050  24.690  1.00  0.00            
-ATOM   2198  P    DA B  10      80.170  54.140  23.610  1.00  0.00            
-ATOM   2199  O1P  DA B  10      81.070  53.030  23.180  1.00  0.00            
-ATOM   2200  O2P  DA B  10      79.730  55.070  22.540  1.00  0.00            
-ATOM   2201  O5'  DA B  10      78.820  53.440  24.290  1.00  0.00            
-ATOM   2202  C5'  DA B  10      78.840  52.140  24.940  1.00  0.00            
-ATOM   2203 1H5'  DA B  10      79.680  52.180  25.640  1.00  0.00            
-ATOM   2204 2H5'  DA B  10      79.080  51.390  24.200  1.00  0.00            
-ATOM   2205  C4'  DA B  10      77.630  51.600  25.810  1.00  0.00            
-ATOM   2206  H4'  DA B  10      78.060  50.850  26.470  1.00  0.00            
-ATOM   2207  O4'  DA B  10      77.220  52.660  26.640  1.00  0.00            
-ATOM   2208  C1'  DA B  10      75.820  52.840  26.530  1.00  0.00            
-ATOM   2209  H1'  DA B  10      75.310  52.420  27.400  1.00  0.00            
-ATOM   2210  N9   DA B  10      75.590  54.290  26.460  1.00  0.00            
-ATOM   2211  C8   DA B  10      76.120  55.210  25.600  1.00  0.00            
-ATOM   2212  H8   DA B  10      76.790  54.920  24.800  1.00  0.00            
-ATOM   2213  N7   DA B  10      75.770  56.450  25.830  1.00  0.00            
-ATOM   2214  C5   DA B  10      74.970  56.300  26.990  1.00  0.00            
-ATOM   2215  C6   DA B  10      74.310  57.180  27.870  1.00  0.00            
-ATOM   2216  N6   DA B  10      74.330  58.490  27.770  1.00  0.00            
-ATOM   2217  H61  DA B  10      73.860  59.020  28.500  1.00  0.00            
-ATOM   2218  H62  DA B  10      74.840  58.920  27.030  1.00  0.00            
-ATOM   2219  N1   DA B  10      73.630  56.730  28.920  1.00  0.00            
-ATOM   2220  C2   DA B  10      73.580  55.420  29.140  1.00  0.00            
-ATOM   2221  H2   DA B  10      73.010  55.090  30.000  1.00  0.00            
-ATOM   2222  N3   DA B  10      74.150  54.470  28.400  1.00  0.00            
-ATOM   2223  C4   DA B  10      74.840  54.990  27.350  1.00  0.00            
-ATOM   2224  C3'  DA B  10      76.330  50.940  25.230  1.00  0.00            
-ATOM   2225  H3'  DA B  10      76.480  50.590  24.210  1.00  0.00            
-ATOM   2226  C2'  DA B  10      75.370  52.120  25.260  1.00  0.00            
-ATOM   2227 1H2'  DA B  10      75.530  52.750  24.380  1.00  0.00            
-ATOM   2228 2H2'  DA B  10      74.330  51.820  25.330  1.00  0.00            
-ATOM   2229  O3'  DA B  10      75.860  49.850  26.070  1.00  0.00            
-ATOM   2230  P    DA B  11      74.510  48.940  25.810  1.00  0.00            
-ATOM   2231  O1P  DA B  11      74.870  47.540  26.160  1.00  0.00            
-ATOM   2232  O2P  DA B  11      74.120  49.170  24.400  1.00  0.00            
-ATOM   2233  O5'  DA B  11      73.260  49.400  26.800  1.00  0.00            
-ATOM   2234  C5'  DA B  11      73.150  49.010  28.200  1.00  0.00            
-ATOM   2235 1H5'  DA B  11      74.120  49.200  28.640  1.00  0.00            
-ATOM   2236 2H5'  DA B  11      72.990  47.930  28.240  1.00  0.00            
-ATOM   2237  C4'  DA B  11      72.110  49.700  29.160  1.00  0.00            
-ATOM   2238  H4'  DA B  11      72.450  49.510  30.180  1.00  0.00            
-ATOM   2239  O4'  DA B  11      72.230  51.090  28.940  1.00  0.00            
-ATOM   2240  C1'  DA B  11      70.950  51.650  28.770  1.00  0.00            
-ATOM   2241  H1'  DA B  11      70.580  52.090  29.710  1.00  0.00            
-ATOM   2242  N9   DA B  11      71.050  52.670  27.720  1.00  0.00            
-ATOM   2243  C8   DA B  11      71.610  52.550  26.470  1.00  0.00            
-ATOM   2244  H8   DA B  11      71.990  51.610  26.120  1.00  0.00            
-ATOM   2245  N7   DA B  11      71.660  53.670  25.780  1.00  0.00            
-ATOM   2246  C5   DA B  11      71.100  54.590  26.700  1.00  0.00            
-ATOM   2247  C6   DA B  11      70.890  55.980  26.720  1.00  0.00            
-ATOM   2248  N6   DA B  11      71.260  56.790  25.750  1.00  0.00            
-ATOM   2249  H61  DA B  11      71.150  57.780  25.910  1.00  0.00            
-ATOM   2250  H62  DA B  11      71.720  56.400  24.960  1.00  0.00            
-ATOM   2251  N1   DA B  11      70.360  56.600  27.760  1.00  0.00            
-ATOM   2252  C2   DA B  11      70.000  55.870  28.820  1.00  0.00            
-ATOM   2253  H2   DA B  11      69.560  56.400  29.650  1.00  0.00            
-ATOM   2254  N3   DA B  11      70.120  54.560  28.940  1.00  0.00            
-ATOM   2255  C4   DA B  11      70.700  53.980  27.860  1.00  0.00            
-ATOM   2256  C3'  DA B  11      70.580  49.370  29.180  1.00  0.00            
-ATOM   2257  H3'  DA B  11      70.370  48.410  28.720  1.00  0.00            
-ATOM   2258  C2'  DA B  11      70.030  50.510  28.340  1.00  0.00            
-ATOM   2259 1H2'  DA B  11      70.150  50.280  27.280  1.00  0.00            
-ATOM   2260 2H2'  DA B  11      68.990  50.740  28.570  1.00  0.00            
-ATOM   2261  O3'  DA B  11      70.000  49.420  30.510  1.00  0.00            
-ATOM   2262  P    DT B  12      68.400  49.160  30.850  1.00  0.00            
-ATOM   2263  O1P  DT B  12      68.350  48.290  32.050  1.00  0.00            
-ATOM   2264  O2P  DT B  12      67.810  48.610  29.600  1.00  0.00            
-ATOM   2265  O5'  DT B  12      67.630  50.600  31.200  1.00  0.00            
-ATOM   2266  C5'  DT B  12      67.710  51.270  32.480  1.00  0.00            
-ATOM   2267 1H5'  DT B  12      68.780  51.320  32.730  1.00  0.00            
-ATOM   2268 2H5'  DT B  12      67.250  50.650  33.240  1.00  0.00            
-ATOM   2269  C4'  DT B  12      67.170  52.750  32.650  1.00  0.00            
-ATOM   2270  H4'  DT B  12      67.690  53.180  33.520  1.00  0.00            
-ATOM   2271  O4'  DT B  12      67.600  53.470  31.510  1.00  0.00            
-ATOM   2272  C1'  DT B  12      66.470  54.120  30.940  1.00  0.00            
-ATOM   2273  H1'  DT B  12      66.420  55.150  31.330  1.00  0.00            
-ATOM   2274  N1   DT B  12      66.630  54.110  29.470  1.00  0.00            
-ATOM   2275  C6   DT B  12      66.740  52.910  28.800  1.00  0.00            
-ATOM   2276  H6   DT B  12      66.670  51.990  29.370  1.00  0.00            
-ATOM   2277  C5   DT B  12      66.970  52.880  27.460  1.00  0.00            
-ATOM   2278  C7   DT B  12      67.070  51.550  26.740  1.00  0.00            
-ATOM   2279  H71  DT B  12      66.880  50.730  27.430  1.00  0.00            
-ATOM   2280  H72  DT B  12      66.330  51.540  25.940  1.00  0.00            
-ATOM   2281  H73  DT B  12      68.060  51.460  26.310  1.00  0.00            
-ATOM   2282  C4   DT B  12      67.150  54.130  26.710  1.00  0.00            
-ATOM   2283  O4   DT B  12      67.440  54.220  25.520  1.00  0.00            
-ATOM   2284  N3   DT B  12      66.990  55.270  27.460  1.00  0.00            
-ATOM   2285  H3   DT B  12      67.090  56.170  27.020  1.00  0.00            
-ATOM   2286  C2   DT B  12      66.730  55.330  28.810  1.00  0.00            
-ATOM   2287  O2   DT B  12      66.620  56.430  29.330  1.00  0.00            
-ATOM   2288  C3'  DT B  12      65.660  53.100  32.860  1.00  0.00            
-ATOM   2289  H3'  DT B  12      65.110  52.280  33.310  1.00  0.00            
-ATOM   2290  C2'  DT B  12      65.250  53.350  31.430  1.00  0.00            
-ATOM   2291 1H2'  DT B  12      65.120  52.400  30.910  1.00  0.00            
-ATOM   2292 2H2'  DT B  12      64.340  53.950  31.350  1.00  0.00            
-ATOM   2293  O3'  DT B  12      65.460  54.320  33.640  1.00  0.00            
-ATOM   2294  P    DG B  13      63.990  54.910  34.100  1.00  0.00            
-ATOM   2295  O1P  DG B  13      64.010  55.100  35.560  1.00  0.00            
-ATOM   2296  O2P  DG B  13      62.980  53.980  33.550  1.00  0.00            
-ATOM   2297  O5'  DG B  13      63.700  56.390  33.410  1.00  0.00            
-ATOM   2298  C5'  DG B  13      64.290  57.610  33.900  1.00  0.00            
-ATOM   2299 1H5'  DG B  13      65.360  57.410  33.910  1.00  0.00            
-ATOM   2300 2H5'  DG B  13      63.990  57.760  34.940  1.00  0.00            
-ATOM   2301  C4'  DG B  13      64.110  58.960  33.110  1.00  0.00            
-ATOM   2302  H4'  DG B  13      64.820  59.670  33.530  1.00  0.00            
-ATOM   2303  O4'  DG B  13      64.490  58.700  31.780  1.00  0.00            
-ATOM   2304  C1'  DG B  13      63.320  58.790  30.980  1.00  0.00            
-ATOM   2305  H1'  DG B  13      63.390  59.710  30.400  1.00  0.00            
-ATOM   2306  N9   DG B  13      63.280  57.650  30.050  1.00  0.00            
-ATOM   2307  C8   DG B  13      63.180  56.300  30.280  1.00  0.00            
-ATOM   2308  H8   DG B  13      63.030  55.880  31.270  1.00  0.00            
-ATOM   2309  N7   DG B  13      63.320  55.560  29.210  1.00  0.00            
-ATOM   2310  C5   DG B  13      63.520  56.510  28.190  1.00  0.00            
-ATOM   2311  C6   DG B  13      63.790  56.380  26.790  1.00  0.00            
-ATOM   2312  O6   DG B  13      63.980  55.370  26.120  1.00  0.00            
-ATOM   2313  N1   DG B  13      63.870  57.590  26.130  1.00  0.00            
-ATOM   2314  H1   DG B  13      64.090  57.570  25.150  1.00  0.00            
-ATOM   2315  C2   DG B  13      63.730  58.790  26.740  1.00  0.00            
-ATOM   2316  N2   DG B  13      63.810  59.880  26.020  1.00  0.00            
-ATOM   2317  H21  DG B  13      64.040  59.820  25.030  1.00  0.00            
-ATOM   2318  H22  DG B  13      63.720  60.740  26.530  1.00  0.00            
-ATOM   2319  N3   DG B  13      63.520  58.970  28.030  1.00  0.00            
-ATOM   2320  C4   DG B  13      63.430  57.790  28.700  1.00  0.00            
-ATOM   2321  C3'  DG B  13      62.760  59.740  33.000  1.00  0.00            
-ATOM   2322  H3'  DG B  13      62.190  59.700  33.930  1.00  0.00            
-ATOM   2323  C2'  DG B  13      62.120  58.900  31.910  1.00  0.00            
-ATOM   2324 1H2'  DG B  13      61.810  57.930  32.300  1.00  0.00            
-ATOM   2325 2H2'  DG B  13      61.290  59.430  31.450  1.00  0.00            
-ATOM   2326  O3'  DG B  13      62.940  61.130  32.550  1.00  0.00            
-ATOM   2327  P    DC B  14      61.740  62.240  32.290  1.00  0.00            
-ATOM   2328  O1P  DC B  14      62.150  63.530  32.900  1.00  0.00            
-ATOM   2329  O2P  DC B  14      60.470  61.640  32.740  1.00  0.00            
-ATOM   2330  O5'  DC B  14      61.540  62.560  30.680  1.00  0.00            
-ATOM   2331  C5'  DC B  14      62.270  63.590  29.980  1.00  0.00            
-ATOM   2332 1H5'  DC B  14      63.320  63.320  30.050  1.00  0.00            
-ATOM   2333 2H5'  DC B  14      62.140  64.530  30.520  1.00  0.00            
-ATOM   2334  C4'  DC B  14      61.950  63.830  28.460  1.00  0.00            
-ATOM   2335  H4'  DC B  14      62.760  64.440  28.070  1.00  0.00            
-ATOM   2336  O4'  DC B  14      62.000  62.580  27.810  1.00  0.00            
-ATOM   2337  C1'  DC B  14      60.690  62.240  27.380  1.00  0.00            
-ATOM   2338  H1'  DC B  14      60.660  62.420  26.310  1.00  0.00            
-ATOM   2339  N1   DC B  14      60.420  60.800  27.650  1.00  0.00            
-ATOM   2340  C6   DC B  14      60.180  60.290  28.910  1.00  0.00            
-ATOM   2341  H6   DC B  14      60.140  60.950  29.770  1.00  0.00            
-ATOM   2342  C5   DC B  14      60.020  58.950  29.070  1.00  0.00            
-ATOM   2343  H5   DC B  14      59.850  58.540  30.050  1.00  0.00            
-ATOM   2344  C4   DC B  14      60.170  58.130  27.930  1.00  0.00            
-ATOM   2345  N4   DC B  14      60.160  56.830  28.040  1.00  0.00            
-ATOM   2346  H41  DC B  14      60.250  56.280  27.200  1.00  0.00            
-ATOM   2347  H42  DC B  14      60.090  56.400  28.940  1.00  0.00            
-ATOM   2348  N3   DC B  14      60.350  58.600  26.710  1.00  0.00            
-ATOM   2349  C2   DC B  14      60.450  59.940  26.560  1.00  0.00            
-ATOM   2350  O2   DC B  14      60.540  60.370  25.410  1.00  0.00            
-ATOM   2351  C3'  DC B  14      60.610  64.490  27.980  1.00  0.00            
-ATOM   2352  H3'  DC B  14      60.260  65.230  28.700  1.00  0.00            
-ATOM   2353  C2'  DC B  14      59.730  63.260  28.000  1.00  0.00            
-ATOM   2354 1H2'  DC B  14      59.470  62.990  29.030  1.00  0.00            
-ATOM   2355 2H2'  DC B  14      58.840  63.400  27.400  1.00  0.00            
-ATOM   2356  O3'  DC B  14      60.710  65.080  26.640  1.00  0.00            
-ATOM   2357  P    DC B  15      59.530  65.940  25.850  1.00  0.00            
-ATOM   2358  O1P  DC B  15      60.200  67.100  25.200  1.00  0.00            
-ATOM   2359  O2P  DC B  15      58.470  66.260  26.820  1.00  0.00            
-ATOM   2360  O5'  DC B  15      58.830  65.080  24.620  1.00  0.00            
-ATOM   2361  C5'  DC B  15      59.330  65.130  23.270  1.00  0.00            
-ATOM   2362 1H5'  DC B  15      60.390  64.880  23.330  1.00  0.00            
-ATOM   2363 2H5'  DC B  15      59.270  66.150  22.920  1.00  0.00            
-ATOM   2364  C4'  DC B  15      58.730  64.190  22.150  1.00  0.00            
-ATOM   2365  H4'  DC B  15      59.420  64.250  21.310  1.00  0.00            
-ATOM   2366  O4'  DC B  15      58.820  62.880  22.650  1.00  0.00            
-ATOM   2367  C1'  DC B  15      57.510  62.350  22.750  1.00  0.00            
-ATOM   2368  H1'  DC B  15      57.360  61.690  21.900  1.00  0.00            
-ATOM   2369  N1   DC B  15      57.370  61.580  24.020  1.00  0.00            
-ATOM   2370  C6   DC B  15      57.330  62.160  25.260  1.00  0.00            
-ATOM   2371  H6   DC B  15      57.420  63.240  25.350  1.00  0.00            
-ATOM   2372  C5   DC B  15      57.200  61.390  26.370  1.00  0.00            
-ATOM   2373  H5   DC B  15      57.160  61.830  27.350  1.00  0.00            
-ATOM   2374  C4   DC B  15      57.150  59.980  26.180  1.00  0.00            
-ATOM   2375  N4   DC B  15      57.060  59.180  27.200  1.00  0.00            
-ATOM   2376  H41  DC B  15      57.040  58.180  27.010  1.00  0.00            
-ATOM   2377  H42  DC B  15      56.990  59.520  28.130  1.00  0.00            
-ATOM   2378  N3   DC B  15      57.190  59.410  25.000  1.00  0.00            
-ATOM   2379  C2   DC B  15      57.310  60.190  23.900  1.00  0.00            
-ATOM   2380  O2   DC B  15      57.330  59.650  22.800  1.00  0.00            
-ATOM   2381  C3'  DC B  15      57.290  64.340  21.540  1.00  0.00            
-ATOM   2382  H3'  DC B  15      56.970  65.380  21.550  1.00  0.00            
-ATOM   2383  C2'  DC B  15      56.530  63.510  22.570  1.00  0.00            
-ATOM   2384 1H2'  DC B  15      56.410  64.080  23.490  1.00  0.00            
-ATOM   2385 2H2'  DC B  15      55.570  63.180  22.190  1.00  0.00            
-ATOM   2386  O3'  DC B  15      57.200  63.770  20.190  1.00  0.00            
-ATOM   2387  P    DA B  16      55.910  63.880  19.160  1.00  0.00            
-ATOM   2388  O1P  DA B  16      56.460  64.240  17.820  1.00  0.00            
-ATOM   2389  O2P  DA B  16      54.940  64.840  19.740  1.00  0.00            
-ATOM   2390  O5'  DA B  16      55.110  62.430  18.950  1.00  0.00            
-ATOM   2391  C5'  DA B  16      55.400  61.510  17.870  1.00  0.00            
-ATOM   2392 1H5'  DA B  16      56.480  61.380  17.880  1.00  0.00            
-ATOM   2393 2H5'  DA B  16      55.160  62.010  16.930  1.00  0.00            
-ATOM   2394  C4'  DA B  16      54.800  60.050  17.810  1.00  0.00            
-ATOM   2395  H4'  DA B  16      55.360  59.530  17.040  1.00  0.00            
-ATOM   2396  O4'  DA B  16      55.130  59.430  19.030  1.00  0.00            
-ATOM   2397  C1'  DA B  16      53.940  59.080  19.700  1.00  0.00            
-ATOM   2398  H1'  DA B  16      53.830  57.980  19.680  1.00  0.00            
-ATOM   2399  N9   DA B  16      53.990  59.520  21.100  1.00  0.00            
-ATOM   2400  C8   DA B  16      54.130  60.790  21.620  1.00  0.00            
-ATOM   2401  H8   DA B  16      54.260  61.660  21.000  1.00  0.00            
-ATOM   2402  N7   DA B  16      54.100  60.850  22.920  1.00  0.00            
-ATOM   2403  C5   DA B  16      53.930  59.490  23.270  1.00  0.00            
-ATOM   2404  C6   DA B  16      53.840  58.770  24.480  1.00  0.00            
-ATOM   2405  N6   DA B  16      53.930  59.290  25.680  1.00  0.00            
-ATOM   2406  H61  DA B  16      53.980  58.660  26.480  1.00  0.00            
-ATOM   2407  H62  DA B  16      54.110  60.270  25.790  1.00  0.00            
-ATOM   2408  N1   DA B  16      53.670  57.450  24.470  1.00  0.00            
-ATOM   2409  C2   DA B  16      53.580  56.810  23.310  1.00  0.00            
-ATOM   2410  H2   DA B  16      53.440  55.740  23.360  1.00  0.00            
-ATOM   2411  N3   DA B  16      53.630  57.350  22.100  1.00  0.00            
-ATOM   2412  C4   DA B  16      53.840  58.690  22.170  1.00  0.00            
-ATOM   2413  C3'  DA B  16      53.290  59.700  17.530  1.00  0.00            
-ATOM   2414  H3'  DA B  16      52.810  60.470  16.930  1.00  0.00            
-ATOM   2415  C2'  DA B  16      52.770  59.700  18.950  1.00  0.00            
-ATOM   2416 1H2'  DA B  16      52.590  60.730  19.280  1.00  0.00            
-ATOM   2417 2H2'  DA B  16      51.870  59.090  19.060  1.00  0.00            
-ATOM   2418  O3'  DA B  16      53.100  58.380  16.920  1.00  0.00            
-ATOM   2419  P    DT B  17      51.650  57.730  16.460  1.00  0.00            
-ATOM   2420  O1P  DT B  17      51.890  57.020  15.170  1.00  0.00            
-ATOM   2421  O2P  DT B  17      50.670  58.840  16.410  1.00  0.00            
-ATOM   2422  O5'  DT B  17      51.050  56.590  17.520  1.00  0.00            
-ATOM   2423  C5'  DT B  17      51.340  55.170  17.410  1.00  0.00            
-ATOM   2424 1H5'  DT B  17      52.420  55.090  17.300  1.00  0.00            
-ATOM   2425 2H5'  DT B  17      50.910  54.800  16.480  1.00  0.00            
-ATOM   2426  C4'  DT B  17      50.960  54.170  18.570  1.00  0.00            
-ATOM   2427  H4'  DT B  17      51.660  53.340  18.500  1.00  0.00            
-ATOM   2428  O4'  DT B  17      51.250  54.840  19.780  1.00  0.00            
-ATOM   2429  C1'  DT B  17      50.140  54.750  20.650  1.00  0.00            
-ATOM   2430  H1'  DT B  17      50.300  53.930  21.350  1.00  0.00            
-ATOM   2431  N1   DT B  17      50.000  56.040  21.360  1.00  0.00            
-ATOM   2432  C6   DT B  17      49.840  57.220  20.680  1.00  0.00            
-ATOM   2433  H6   DT B  17      49.820  57.210  19.600  1.00  0.00            
-ATOM   2434  C5   DT B  17      49.720  58.400  21.350  1.00  0.00            
-ATOM   2435  C7   DT B  17      49.460  59.680  20.580  1.00  0.00            
-ATOM   2436  H71  DT B  17      48.400  59.930  20.680  1.00  0.00            
-ATOM   2437  H72  DT B  17      50.040  60.490  21.030  1.00  0.00            
-ATOM   2438  H73  DT B  17      49.720  59.570  19.530  1.00  0.00            
-ATOM   2439  C4   DT B  17      49.860  58.440  22.800  1.00  0.00            
-ATOM   2440  O4   DT B  17      49.870  59.450  23.490  1.00  0.00            
-ATOM   2441  N3   DT B  17      49.970  57.210  23.400  1.00  0.00            
-ATOM   2442  H3   DT B  17      50.110  57.170  24.400  1.00  0.00            
-ATOM   2443  C2   DT B  17      49.990  56.000  22.760  1.00  0.00            
-ATOM   2444  O2   DT B  17      49.930  54.950  23.390  1.00  0.00            
-ATOM   2445  C3'  DT B  17      49.550  53.510  18.730  1.00  0.00            
-ATOM   2446  H3'  DT B  17      48.980  53.540  17.800  1.00  0.00            
-ATOM   2447  C2'  DT B  17      48.920  54.420  19.780  1.00  0.00            
-ATOM   2448 1H2'  DT B  17      48.530  55.310  19.290  1.00  0.00            
-ATOM   2449 2H2'  DT B  17      48.150  53.920  20.360  1.00  0.00            
-ATOM   2450  O3'  DT B  17      49.610  52.130  19.220  1.00  0.00            
-ATOM   2451  P    DC B  18      48.320  51.140  19.500  1.00  0.00            
-ATOM   2452  O1P  DC B  18      48.670  49.800  18.950  1.00  0.00            
-ATOM   2453  O2P  DC B  18      47.140  51.800  18.890  1.00  0.00            
-ATOM   2454  O5'  DC B  18      48.010  50.950  21.110  1.00  0.00            
-ATOM   2455  C5'  DC B  18      48.770  50.070  21.990  1.00  0.00            
-ATOM   2456 1H5'  DC B  18      49.820  50.280  21.780  1.00  0.00            
-ATOM   2457 2H5'  DC B  18      48.590  49.040  21.690  1.00  0.00            
-ATOM   2458  C4'  DC B  18      48.630  50.170  23.550  1.00  0.00            
-ATOM   2459  H4'  DC B  18      49.520  49.700  23.980  1.00  0.00            
-ATOM   2460  O4'  DC B  18      48.720  51.540  23.880  1.00  0.00            
-ATOM   2461  C1'  DC B  18      47.670  51.900  24.760  1.00  0.00            
-ATOM   2462  H1'  DC B  18      48.050  51.920  25.800  1.00  0.00            
-ATOM   2463  N1   DC B  18      47.170  53.240  24.360  1.00  0.00            
-ATOM   2464  C6   DC B  18      46.900  53.510  23.040  1.00  0.00            
-ATOM   2465  H6   DC B  18      47.040  52.720  22.320  1.00  0.00            
-ATOM   2466  C5   DC B  18      46.540  54.760  22.650  1.00  0.00            
-ATOM   2467  H5   DC B  18      46.360  54.980  21.620  1.00  0.00            
-ATOM   2468  C4   DC B  18      46.460  55.740  23.680  1.00  0.00            
-ATOM   2469  N4   DC B  18      46.240  56.980  23.380  1.00  0.00            
-ATOM   2470  H41  DC B  18      46.370  57.610  24.170  1.00  0.00            
-ATOM   2471  H42  DC B  18      46.350  57.300  22.450  1.00  0.00            
-ATOM   2472  N3   DC B  18      46.650  55.480  24.940  1.00  0.00            
-ATOM   2473  C2   DC B  18      47.020  54.240  25.320  1.00  0.00            
-ATOM   2474  O2   DC B  18      47.160  54.010  26.510  1.00  0.00            
-ATOM   2475  C3'  DC B  18      47.430  49.580  24.370  1.00  0.00            
-ATOM   2476  H3'  DC B  18      46.870  48.860  23.770  1.00  0.00            
-ATOM   2477  C2'  DC B  18      46.600  50.830  24.630  1.00  0.00            
-ATOM   2478 1H2'  DC B  18      45.960  51.020  23.770  1.00  0.00            
-ATOM   2479 2H2'  DC B  18      46.020  50.750  25.540  1.00  0.00            
-ATOM   2480  O3'  DC B  18      47.840  48.960  25.610  1.00  0.00            
-ATOM   2481  P    DT B  19      46.830  48.310  26.740  1.00  0.00            
-ATOM   2482  O1P  DT B  19      47.450  47.040  27.200  1.00  0.00            
-ATOM   2483  O2P  DT B  19      45.500  48.180  26.080  1.00  0.00            
-ATOM   2484  O5'  DT B  19      46.670  49.320  28.040  1.00  0.00            
-ATOM   2485  C5'  DT B  19      47.700  49.510  29.060  1.00  0.00            
-ATOM   2486 1H5'  DT B  19      48.630  49.670  28.520  1.00  0.00            
-ATOM   2487 2H5'  DT B  19      47.810  48.580  29.620  1.00  0.00            
-ATOM   2488  C4'  DT B  19      47.590  50.700  30.080  1.00  0.00            
-ATOM   2489  H4'  DT B  19      48.590  50.880  30.490  1.00  0.00            
-ATOM   2490  O4'  DT B  19      47.230  51.840  29.320  1.00  0.00            
-ATOM   2491  C1'  DT B  19      46.130  52.480  29.930  1.00  0.00            
-ATOM   2492  H1'  DT B  19      46.490  53.270  30.600  1.00  0.00            
-ATOM   2493  N1   DT B  19      45.240  53.030  28.880  1.00  0.00            
-ATOM   2494  C6   DT B  19      44.750  52.210  27.880  1.00  0.00            
-ATOM   2495  H6   DT B  19      45.030  51.170  27.900  1.00  0.00            
-ATOM   2496  C5   DT B  19      43.990  52.720  26.880  1.00  0.00            
-ATOM   2497  C7   DT B  19      43.440  51.800  25.820  1.00  0.00            
-ATOM   2498  H71  DT B  19      43.660  50.760  26.060  1.00  0.00            
-ATOM   2499  H72  DT B  19      42.360  51.940  25.760  1.00  0.00            
-ATOM   2500  H73  DT B  19      43.880  52.070  24.860  1.00  0.00            
-ATOM   2501  C4   DT B  19      43.700  54.150  26.830  1.00  0.00            
-ATOM   2502  O4   DT B  19      43.080  54.710  25.920  1.00  0.00            
-ATOM   2503  N3   DT B  19      44.180  54.880  27.890  1.00  0.00            
-ATOM   2504  H3   DT B  19      44.040  55.880  27.910  1.00  0.00            
-ATOM   2505  C2   DT B  19      44.890  54.380  28.950  1.00  0.00            
-ATOM   2506  O2   DT B  19      45.150  55.100  29.900  1.00  0.00            
-ATOM   2507  C3'  DT B  19      46.630  50.670  31.320  1.00  0.00            
-ATOM   2508  H3'  DT B  19      46.370  49.650  31.600  1.00  0.00            
-ATOM   2509  C2'  DT B  19      45.430  51.410  30.750  1.00  0.00            
-ATOM   2510 1H2'  DT B  19      44.840  50.730  30.140  1.00  0.00            
-ATOM   2511 2H2'  DT B  19      44.830  51.870  31.530  1.00  0.00            
-ATOM   2512  O3'  DT B  19      47.120  51.380  32.480  1.00  0.00            
-ATOM   2513  P    DT B  20      46.310  51.520  33.910  1.00  0.00            
-ATOM   2514  O1P  DT B  20      47.240  51.110  34.990  1.00  0.00            
-ATOM   2515  O2P  DT B  20      45.070  50.720  33.760  1.00  0.00            
-ATOM   2516  O5'  DT B  20      45.860  53.090  34.180  1.00  0.00            
-ATOM   2517  C5'  DT B  20      46.780  54.120  34.630  1.00  0.00            
-ATOM   2518 1H5'  DT B  20      47.630  54.040  33.960  1.00  0.00            
-ATOM   2519 2H5'  DT B  20      47.140  53.880  35.620  1.00  0.00            
-ATOM   2520  C4'  DT B  20      46.360  55.640  34.590  1.00  0.00            
-ATOM   2521  H4'  DT B  20      47.280  56.220  34.620  1.00  0.00            
-ATOM   2522  O4'  DT B  20      45.770  55.850  33.320  1.00  0.00            
-ATOM   2523  C1'  DT B  20      44.460  56.340  33.530  1.00  0.00            
-ATOM   2524  H1'  DT B  20      44.480  57.430  33.400  1.00  0.00            
-ATOM   2525  N1   DT B  20      43.530  55.710  32.560  1.00  0.00            
-ATOM   2526  C6   DT B  20      43.280  54.350  32.590  1.00  0.00            
-ATOM   2527  H6   DT B  20      43.750  53.750  33.350  1.00  0.00            
-ATOM   2528  C5   DT B  20      42.470  53.770  31.660  1.00  0.00            
-ATOM   2529  C7   DT B  20      42.190  52.280  31.730  1.00  0.00            
-ATOM   2530  H71  DT B  20      42.700  51.830  32.580  1.00  0.00            
-ATOM   2531  H72  DT B  20      41.110  52.140  31.830  1.00  0.00            
-ATOM   2532  H73  DT B  20      42.520  51.820  30.800  1.00  0.00            
-ATOM   2533  C4   DT B  20      41.900  54.570  30.580  1.00  0.00            
-ATOM   2534  O4   DT B  20      41.230  54.130  29.640  1.00  0.00            
-ATOM   2535  N3   DT B  20      42.160  55.910  30.660  1.00  0.00            
-ATOM   2536  H3   DT B  20      41.750  56.540  29.990  1.00  0.00            
-ATOM   2537  C2   DT B  20      42.910  56.530  31.620  1.00  0.00            
-ATOM   2538  O2   DT B  20      42.950  57.760  31.630  1.00  0.00            
-ATOM   2539  C3'  DT B  20      45.420  56.330  35.640  1.00  0.00            
-ATOM   2540  H3'  DT B  20      45.500  55.860  36.620  1.00  0.00            
-ATOM   2541  C2'  DT B  20      44.100  56.050  34.980  1.00  0.00            
-ATOM   2542 1H2'  DT B  20      43.820  55.010  35.150  1.00  0.00            
-ATOM   2543 2H2'  DT B  20      43.330  56.730  35.330  1.00  0.00            
-ATOM   2544  O3'  DT B  20      45.580  57.770  35.760  1.00  0.00            
-ATOM   2545  P    DT B  21      44.700  58.750  36.770  1.00  0.00            
-ATOM   2546  O1P  DT B  21      45.630  59.650  37.470  1.00  0.00            
-ATOM   2547  O2P  DT B  21      43.860  57.850  37.590  1.00  0.00            
-ATOM   2548  O5'  DT B  21      43.650  59.720  35.940  1.00  0.00            
-ATOM   2549  C5'  DT B  21      44.000  61.030  35.450  1.00  0.00            
-ATOM   2550 1H5'  DT B  21      44.840  60.880  34.760  1.00  0.00            
-ATOM   2551 2H5'  DT B  21      44.380  61.620  36.280  1.00  0.00            
-ATOM   2552  C4'  DT B  21      42.930  61.890  34.680  1.00  0.00            
-ATOM   2553  H4'  DT B  21      43.490  62.650  34.120  1.00  0.00            
-ATOM   2554  O4'  DT B  21      42.310  61.040  33.740  1.00  0.00            
-ATOM   2555  C1'  DT B  21      40.970  60.830  34.160  1.00  0.00            
-ATOM   2556  H1'  DT B  21      40.340  61.430  33.490  1.00  0.00            
-ATOM   2557  N1   DT B  21      40.620  59.390  33.990  1.00  0.00            
-ATOM   2558  C6   DT B  21      40.900  58.410  34.920  1.00  0.00            
-ATOM   2559  H6   DT B  21      41.400  58.680  35.850  1.00  0.00            
-ATOM   2560  C5   DT B  21      40.600  57.110  34.680  1.00  0.00            
-ATOM   2561  C7   DT B  21      40.840  56.050  35.750  1.00  0.00            
-ATOM   2562  H71  DT B  21      41.350  56.470  36.610  1.00  0.00            
-ATOM   2563  H72  DT B  21      39.880  55.630  36.050  1.00  0.00            
-ATOM   2564  H73  DT B  21      41.430  55.240  35.320  1.00  0.00            
-ATOM   2565  C4   DT B  21      40.050  56.700  33.390  1.00  0.00            
-ATOM   2566  O4   DT B  21      39.810  55.550  33.020  1.00  0.00            
-ATOM   2567  N3   DT B  21      39.780  57.740  32.540  1.00  0.00            
-ATOM   2568  H3   DT B  21      39.300  57.520  31.680  1.00  0.00            
-ATOM   2569  C2   DT B  21      39.970  59.070  32.790  1.00  0.00            
-ATOM   2570  O2   DT B  21      39.510  59.880  32.000  1.00  0.00            
-ATOM   2571  C3'  DT B  21      41.750  62.630  35.400  1.00  0.00            
-ATOM   2572  H3'  DT B  21      42.070  63.010  36.370  1.00  0.00            
-ATOM   2573  C2'  DT B  21      40.820  61.440  35.550  1.00  0.00            
-ATOM   2574 1H2'  DT B  21      41.190  60.770  36.330  1.00  0.00            
-ATOM   2575 2H2'  DT B  21      39.800  61.750  35.770  1.00  0.00            
-ATOM   2576  O3'  DT B  21      41.160  63.700  34.590  1.00  0.00            
-ATOM   2577  P    DA B  22      39.990  64.770  35.070  1.00  0.00            
-ATOM   2578  O1P  DA B  22      40.430  66.140  34.670  1.00  0.00            
-ATOM   2579  O2P  DA B  22      39.720  64.560  36.500  1.00  0.00            
-ATOM   2580  O5'  DA B  22      38.550  64.540  34.290  1.00  0.00            
-ATOM   2581  C5'  DA B  22      38.240  65.160  33.030  1.00  0.00            
-ATOM   2582 1H5'  DA B  22      39.040  64.860  32.340  1.00  0.00            
-ATOM   2583 2H5'  DA B  22      38.330  66.240  33.160  1.00  0.00            
-ATOM   2584  C4'  DA B  22      36.880  64.860  32.300  1.00  0.00            
-ATOM   2585  H4'  DA B  22      36.960  65.340  31.320  1.00  0.00            
-ATOM   2586  O4'  DA B  22      36.830  63.470  32.060  1.00  0.00            
-ATOM   2587  C1'  DA B  22      35.820  62.910  32.890  1.00  0.00            
-ATOM   2588  H1'  DA B  22      35.020  62.560  32.240  1.00  0.00            
-ATOM   2589  N9   DA B  22      36.360  61.750  33.630  1.00  0.00            
-ATOM   2590  C8   DA B  22      37.250  61.680  34.670  1.00  0.00            
-ATOM   2591  H8   DA B  22      37.710  62.550  35.120  1.00  0.00            
-ATOM   2592  N7   DA B  22      37.480  60.470  35.090  1.00  0.00            
-ATOM   2593  C5   DA B  22      36.710  59.680  34.220  1.00  0.00            
-ATOM   2594  C6   DA B  22      36.500  58.300  34.050  1.00  0.00            
-ATOM   2595  N6   DA B  22      37.100  57.350  34.740  1.00  0.00            
-ATOM   2596  H61  DA B  22      36.880  56.380  34.550  1.00  0.00            
-ATOM   2597  H62  DA B  22      37.700  57.610  35.500  1.00  0.00            
-ATOM   2598  N1   DA B  22      35.630  57.860  33.130  1.00  0.00            
-ATOM   2599  C2   DA B  22      34.990  58.750  32.390  1.00  0.00            
-ATOM   2600  H2   DA B  22      34.290  58.340  31.660  1.00  0.00            
-ATOM   2601  N3   DA B  22      35.090  60.060  32.410  1.00  0.00            
-ATOM   2602  C4   DA B  22      36.000  60.460  33.350  1.00  0.00            
-ATOM   2603  C3'  DA B  22      35.480  65.230  32.870  1.00  0.00            
-ATOM   2604  H3'  DA B  22      35.530  66.150  33.450  1.00  0.00            
-ATOM   2605  C2'  DA B  22      35.280  64.030  33.780  1.00  0.00            
-ATOM   2606 1H2'  DA B  22      35.880  64.140  34.680  1.00  0.00            
-ATOM   2607 2H2'  DA B  22      34.230  63.890  34.020  1.00  0.00            
-ATOM   2608  O3'  DA B  22      34.450  65.320  31.840  1.00  0.00            
-ATOM   2609  P    DC B  23      32.860  65.760  32.050  1.00  0.00            
-ATOM   2610  O1P  DC B  23      32.470  66.540  30.840  1.00  0.00            
-ATOM   2611  O2P  DC B  23      32.760  66.480  33.330  1.00  0.00            
-ATOM   2612  O5'  DC B  23      31.820  64.470  32.110  1.00  0.00            
-ATOM   2613  C5'  DC B  23      31.210  63.900  30.930  1.00  0.00            
-ATOM   2614 1H5'  DC B  23      32.040  63.680  30.250  1.00  0.00            
-ATOM   2615 2H5'  DC B  23      30.620  64.680  30.450  1.00  0.00            
-ATOM   2616  C4'  DC B  23      30.340  62.590  30.980  1.00  0.00            
-ATOM   2617  H4'  DC B  23      30.200  62.290  29.940  1.00  0.00            
-ATOM   2618  O4'  DC B  23      31.150  61.600  31.570  1.00  0.00            
-ATOM   2619  C1'  DC B  23      30.480  61.070  32.690  1.00  0.00            
-ATOM   2620  H1'  DC B  23      30.020  60.120  32.390  1.00  0.00            
-ATOM   2621  N1   DC B  23      31.460  60.830  33.780  1.00  0.00            
-ATOM   2622  C6   DC B  23      32.230  61.840  34.310  1.00  0.00            
-ATOM   2623  H6   DC B  23      32.090  62.850  33.960  1.00  0.00            
-ATOM   2624  C5   DC B  23      33.180  61.550  35.240  1.00  0.00            
-ATOM   2625  H5   DC B  23      33.800  62.320  35.660  1.00  0.00            
-ATOM   2626  C4   DC B  23      33.330  60.180  35.610  1.00  0.00            
-ATOM   2627  N4   DC B  23      34.290  59.820  36.410  1.00  0.00            
-ATOM   2628  H41  DC B  23      34.390  58.830  36.620  1.00  0.00            
-ATOM   2629  H42  DC B  23      35.000  60.460  36.700  1.00  0.00            
-ATOM   2630  N3   DC B  23      32.610  59.210  35.110  1.00  0.00            
-ATOM   2631  C2   DC B  23      31.660  59.510  34.200  1.00  0.00            
-ATOM   2632  O2   DC B  23      30.980  58.600  33.730  1.00  0.00            
-ATOM   2633  C3'  DC B  23      28.920  62.470  31.650  1.00  0.00            
-ATOM   2634  H3'  DC B  23      28.420  63.440  31.680  1.00  0.00            
-ATOM   2635  C2'  DC B  23      29.350  62.030  33.040  1.00  0.00            
-ATOM   2636 1H2'  DC B  23      29.720  62.880  33.610  1.00  0.00            
-ATOM   2637 2H2'  DC B  23      28.540  61.530  33.580  1.00  0.00            
-ATOM   2638  O3'  DC B  23      28.080  61.470  30.990  1.00  0.00            
-ATOM   2639  P    DG B  24      26.480  61.140  31.300  1.00  0.00            
-ATOM   2640  O1P  DG B  24      25.830  60.950  29.980  1.00  0.00            
-ATOM   2641  O2P  DG B  24      25.950  62.260  32.110  1.00  0.00            
-ATOM   2642  O5'  DG B  24      26.240  59.730  32.150  1.00  0.00            
-ATOM   2643  C5'  DG B  24      26.020  58.450  31.500  1.00  0.00            
-ATOM   2644 1H5'  DG B  24      26.830  58.360  30.770  1.00  0.00            
-ATOM   2645 2H5'  DG B  24      25.090  58.520  30.930  1.00  0.00            
-ATOM   2646  C4'  DG B  24      26.010  57.070  32.270  1.00  0.00            
-ATOM   2647  H4'  DG B  24      26.090  56.310  31.500  1.00  0.00            
-ATOM   2648  O4'  DG B  24      27.210  57.010  33.000  1.00  0.00            
-ATOM   2649  C1'  DG B  24      26.900  56.900  34.370  1.00  0.00            
-ATOM   2650  H1'  DG B  24      27.140  55.880  34.700  1.00  0.00            
-ATOM   2651  N9   DG B  24      27.720  57.840  35.140  1.00  0.00            
-ATOM   2652  C8   DG B  24      27.780  59.210  35.110  1.00  0.00            
-ATOM   2653  H8   DG B  24      27.170  59.800  34.450  1.00  0.00            
-ATOM   2654  N7   DG B  24      28.640  59.730  35.950  1.00  0.00            
-ATOM   2655  C5   DG B  24      29.220  58.590  36.560  1.00  0.00            
-ATOM   2656  C6   DG B  24      30.260  58.430  37.540  1.00  0.00            
-ATOM   2657  O6   DG B  24      30.930  59.290  38.110  1.00  0.00            
-ATOM   2658  N1   DG B  24      30.510  57.100  37.850  1.00  0.00            
-ATOM   2659  H1   DG B  24      31.260  56.910  38.500  1.00  0.00            
-ATOM   2660  C2   DG B  24      29.860  56.050  37.280  1.00  0.00            
-ATOM   2661  N2   DG B  24      30.180  54.840  37.620  1.00  0.00            
-ATOM   2662  H21  DG B  24      30.930  54.690  38.290  1.00  0.00            
-ATOM   2663  H22  DG B  24      29.710  54.080  37.180  1.00  0.00            
-ATOM   2664  N3   DG B  24      28.900  56.150  36.380  1.00  0.00            
-ATOM   2665  C4   DG B  24      28.640  57.450  36.060  1.00  0.00            
-ATOM   2666  C3'  DG B  24      24.890  56.560  33.240  1.00  0.00            
-ATOM   2667  H3'  DG B  24      23.920  56.980  32.990  1.00  0.00            
-ATOM   2668  C2'  DG B  24      25.400  57.120  34.550  1.00  0.00            
-ATOM   2669 1H2'  DG B  24      25.180  58.190  34.620  1.00  0.00            
-ATOM   2670 2H2'  DG B  24      25.020  56.590  35.420  1.00  0.00            
-ATOM   2671  O3'  DG B  24      24.820  55.100  33.260  1.00  0.00            
-ATOM   2672  P    DG B  25      23.750  54.170  34.130  1.00  0.00            
-ATOM   2673  O1P  DG B  25      23.330  53.070  33.220  1.00  0.00            
-ATOM   2674  O2P  DG B  25      22.670  55.070  34.580  1.00  0.00            
-ATOM   2675  O5'  DG B  25      24.430  53.450  35.470  1.00  0.00            
-ATOM   2676  C5'  DG B  25      25.150  52.180  35.420  1.00  0.00            
-ATOM   2677 1H5'  DG B  25      25.870  52.290  34.610  1.00  0.00            
-ATOM   2678 2H5'  DG B  25      24.450  51.410  35.110  1.00  0.00            
-ATOM   2679  C4'  DG B  25      25.980  51.630  36.640  1.00  0.00            
-ATOM   2680  H4'  DG B  25      26.660  50.890  36.220  1.00  0.00            
-ATOM   2681  O4'  DG B  25      26.790  52.690  37.090  1.00  0.00            
-ATOM   2682  C1'  DG B  25      26.600  52.850  38.490  1.00  0.00            
-ATOM   2683  H1'  DG B  25      27.440  52.400  39.030  1.00  0.00            
-ATOM   2684  N9   DG B  25      26.520  54.280  38.780  1.00  0.00            
-ATOM   2685  C8   DG B  25      25.690  55.240  38.270  1.00  0.00            
-ATOM   2686  H8   DG B  25      24.930  55.000  37.540  1.00  0.00            
-ATOM   2687  N7   DG B  25      25.920  56.450  38.710  1.00  0.00            
-ATOM   2688  C5   DG B  25      27.030  56.270  39.560  1.00  0.00            
-ATOM   2689  C6   DG B  25      27.850  57.190  40.300  1.00  0.00            
-ATOM   2690  O6   DG B  25      27.740  58.420  40.360  1.00  0.00            
-ATOM   2691  N1   DG B  25      28.890  56.580  40.980  1.00  0.00            
-ATOM   2692  H1   DG B  25      29.550  57.170  41.470  1.00  0.00            
-ATOM   2693  C2   DG B  25      29.130  55.240  40.970  1.00  0.00            
-ATOM   2694  N2   DG B  25      30.160  54.780  41.620  1.00  0.00            
-ATOM   2695  H21  DG B  25      30.790  55.420  42.100  1.00  0.00            
-ATOM   2696  H22  DG B  25      30.390  53.810  41.540  1.00  0.00            
-ATOM   2697  N3   DG B  25      28.370  54.350  40.330  1.00  0.00            
-ATOM   2698  C4   DG B  25      27.370  54.940  39.630  1.00  0.00            
-ATOM   2699  C3'  DG B  25      25.370  50.950  37.910  1.00  0.00            
-ATOM   2700  H3'  DG B  25      24.370  50.560  37.710  1.00  0.00            
-ATOM   2701  C2'  DG B  25      25.310  52.130  38.860  1.00  0.00            
-ATOM   2702 1H2'  DG B  25      24.440  52.740  38.640  1.00  0.00            
-ATOM   2703 2H2'  DG B  25      25.320  51.820  39.910  1.00  0.00            
-ATOM   2704  O3'  DG B  25      26.210  49.890  38.440  1.00  0.00            
-ATOM   2705  P    DT B  26      25.910  49.010  39.810  1.00  0.00            
-ATOM   2706  O1P  DT B  26      26.290  47.600  39.500  1.00  0.00            
-ATOM   2707  O2P  DT B  26      24.490  49.240  40.150  1.00  0.00            
-ATOM   2708  O5'  DT B  26      26.840  49.520  41.090  1.00  0.00            
-ATOM   2709  C5'  DT B  26      28.230  49.130  41.290  1.00  0.00            
-ATOM   2710 1H5'  DT B  26      28.730  49.290  40.330  1.00  0.00            
-ATOM   2711 2H5'  DT B  26      28.280  48.060  41.480  1.00  0.00            
-ATOM   2712  C4'  DT B  26      29.150  49.850  42.350  1.00  0.00            
-ATOM   2713  H4'  DT B  26      30.180  49.710  42.020  1.00  0.00            
-ATOM   2714  O4'  DT B  26      28.890  51.240  42.260  1.00  0.00            
-ATOM   2715  C1'  DT B  26      28.740  51.780  43.570  1.00  0.00            
-ATOM   2716  H1'  DT B  26      29.690  52.200  43.920  1.00  0.00            
-ATOM   2717  N1   DT B  26      27.690  52.820  43.500  1.00  0.00            
-ATOM   2718  C6   DT B  26      26.460  52.520  42.950  1.00  0.00            
-ATOM   2719  H6   DT B  26      26.280  51.510  42.610  1.00  0.00            
-ATOM   2720  C5   DT B  26      25.520  53.490  42.780  1.00  0.00            
-ATOM   2721  C7   DT B  26      24.170  53.130  42.190  1.00  0.00            
-ATOM   2722  H71  DT B  26      24.070  52.050  42.090  1.00  0.00            
-ATOM   2723  H72  DT B  26      23.400  53.520  42.850  1.00  0.00            
-ATOM   2724  H73  DT B  26      24.080  53.620  41.220  1.00  0.00            
-ATOM   2725  C4   DT B  26      25.810  54.870  43.160  1.00  0.00            
-ATOM   2726  O4   DT B  26      25.050  55.820  42.970  1.00  0.00            
-ATOM   2727  N3   DT B  26      27.040  55.070  43.750  1.00  0.00            
-ATOM   2728  H3   DT B  26      27.320  56.000  44.000  1.00  0.00            
-ATOM   2729  C2   DT B  26      27.990  54.100  43.950  1.00  0.00            
-ATOM   2730  O2   DT B  26      29.040  54.400  44.510  1.00  0.00            
-ATOM   2731  C3'  DT B  26      29.170  49.490  43.880  1.00  0.00            
-ATOM   2732  H3'  DT B  26      28.710  48.520  44.060  1.00  0.00            
-ATOM   2733  C2'  DT B  26      28.330  50.620  44.470  1.00  0.00            
-ATOM   2734 1H2'  DT B  26      27.280  50.380  44.370  1.00  0.00            
-ATOM   2735 2H2'  DT B  26      28.580  50.820  45.510  1.00  0.00            
-ATOM   2736  O3'  DT B  26      30.500  49.510  44.430  1.00  0.00            
-ATOM   2737  P    DA B  27      30.880  49.200  46.010  1.00  0.00            
-ATOM   2738  O1P  DA B  27      32.040  48.280  46.010  1.00  0.00            
-ATOM   2739  O2P  DA B  27      29.630  48.660  46.620  1.00  0.00            
-ATOM   2740  O5'  DA B  27      31.290  50.600  46.800  1.00  0.00            
-ATOM   2741  C5'  DA B  27      32.610  51.220  46.700  1.00  0.00            
-ATOM   2742 1H5'  DA B  27      32.850  51.250  45.640  1.00  0.00            
-ATOM   2743 2H5'  DA B  27      33.340  50.570  47.170  1.00  0.00            
-ATOM   2744  C4'  DA B  27      32.840  52.690  47.230  1.00  0.00            
-ATOM   2745  H4'  DA B  27      33.740  53.070  46.740  1.00  0.00            
-ATOM   2746  O4'  DA B  27      31.750  53.450  46.760  1.00  0.00            
-ATOM   2747  C1'  DA B  27      31.120  54.060  47.880  1.00  0.00            
-ATOM   2748  H1'  DA B  27      31.450  55.100  47.970  1.00  0.00            
-ATOM   2749  N9   DA B  27      29.670  53.990  47.690  1.00  0.00            
-ATOM   2750  C8   DA B  27      28.870  52.890  47.500  1.00  0.00            
-ATOM   2751  H8   DA B  27      29.290  51.900  47.490  1.00  0.00            
-ATOM   2752  N7   DA B  27      27.600  53.160  47.300  1.00  0.00            
-ATOM   2753  C5   DA B  27      27.600  54.560  47.380  1.00  0.00            
-ATOM   2754  C6   DA B  27      26.630  55.570  47.210  1.00  0.00            
-ATOM   2755  N6   DA B  27      25.370  55.320  46.920  1.00  0.00            
-ATOM   2756  H61  DA B  27      24.750  56.100  46.780  1.00  0.00            
-ATOM   2757  H62  DA B  27      25.100  54.360  46.860  1.00  0.00            
-ATOM   2758  N1   DA B  27      26.910  56.860  47.310  1.00  0.00            
-ATOM   2759  C2   DA B  27      28.170  57.200  47.580  1.00  0.00            
-ATOM   2760  H2   DA B  27      28.380  58.260  47.670  1.00  0.00            
-ATOM   2761  N3   DA B  27      29.190  56.380  47.750  1.00  0.00            
-ATOM   2762  C4   DA B  27      28.840  55.080  47.620  1.00  0.00            
-ATOM   2763  C3'  DA B  27      33.010  53.060  48.740  1.00  0.00            
-ATOM   2764  H3'  DA B  27      33.460  52.250  49.310  1.00  0.00            
-ATOM   2765  C2'  DA B  27      31.560  53.280  49.120  1.00  0.00            
-ATOM   2766 1H2'  DA B  27      31.040  52.330  49.200  1.00  0.00            
-ATOM   2767 2H2'  DA B  27      31.440  53.880  50.020  1.00  0.00            
-ATOM   2768  O3'  DA B  27      33.760  54.290  48.950  1.00  0.00            
-ATOM   2769  P    DG B  28      34.150  54.930  50.420  1.00  0.00            
-ATOM   2770  O1P  DG B  28      35.610  55.170  50.430  1.00  0.00            
-ATOM   2771  O2P  DG B  28      33.610  53.990  51.430  1.00  0.00            
-ATOM   2772  O5'  DG B  28      33.410  56.390  50.660  1.00  0.00            
-ATOM   2773  C5'  DG B  28      33.920  57.640  50.130  1.00  0.00            
-ATOM   2774 1H5'  DG B  28      34.020  57.480  49.060  1.00  0.00            
-ATOM   2775 2H5'  DG B  28      34.930  57.790  50.520  1.00  0.00            
-ATOM   2776  C4'  DG B  28      33.100  58.970  50.300  1.00  0.00            
-ATOM   2777  H4'  DG B  28      33.500  59.680  49.580  1.00  0.00            
-ATOM   2778  O4'  DG B  28      31.770  58.670  49.930  1.00  0.00            
-ATOM   2779  C1'  DG B  28      30.980  58.750  51.100  1.00  0.00            
-ATOM   2780  H1'  DG B  28      30.390  59.670  51.030  1.00  0.00            
-ATOM   2781  N9   DG B  28      30.050  57.610  51.160  1.00  0.00            
-ATOM   2782  C8   DG B  28      30.270  56.270  51.350  1.00  0.00            
-ATOM   2783  H8   DG B  28      31.260  55.860  51.540  1.00  0.00            
-ATOM   2784  N7   DG B  28      29.190  55.530  51.240  1.00  0.00            
-ATOM   2785  C5   DG B  28      28.190  56.460  50.960  1.00  0.00            
-ATOM   2786  C6   DG B  28      26.790  56.330  50.680  1.00  0.00            
-ATOM   2787  O6   DG B  28      26.090  55.310  50.600  1.00  0.00            
-ATOM   2788  N1   DG B  28      26.150  57.530  50.460  1.00  0.00            
-ATOM   2789  H1   DG B  28      25.170  57.510  50.240  1.00  0.00            
-ATOM   2790  C2   DG B  28      26.770  58.740  50.500  1.00  0.00            
-ATOM   2791  N2   DG B  28      26.060  59.810  50.340  1.00  0.00            
-ATOM   2792  H21  DG B  28      25.070  59.770  50.140  1.00  0.00            
-ATOM   2793  H22  DG B  28      26.580  60.670  50.410  1.00  0.00            
-ATOM   2794  N3   DG B  28      28.050  58.910  50.730  1.00  0.00            
-ATOM   2795  C4   DG B  28      28.710  57.740  50.940  1.00  0.00            
-ATOM   2796  C3'  DG B  28      32.960  59.760  51.650  1.00  0.00            
-ATOM   2797  H3'  DG B  28      33.900  59.740  52.220  1.00  0.00            
-ATOM   2798  C2'  DG B  28      31.900  58.890  52.300  1.00  0.00            
-ATOM   2799 1H2'  DG B  28      32.320  57.930  52.600  1.00  0.00            
-ATOM   2800 2H2'  DG B  28      31.420  59.390  53.140  1.00  0.00            
-ATOM   2801  O3'  DG B  28      32.480  61.130  51.470  1.00  0.00            
-ATOM   2802  P    DA B  29      32.270  62.270  52.650  1.00  0.00            
-ATOM   2803  O1P  DA B  29      32.880  63.540  52.180  1.00  0.00            
-ATOM   2804  O2P  DA B  29      32.780  61.700  53.910  1.00  0.00            
-ATOM   2805  O5'  DA B  29      30.670  62.620  52.920  1.00  0.00            
-ATOM   2806  C5'  DA B  29      29.990  63.700  52.250  1.00  0.00            
-ATOM   2807 1H5'  DA B  29      30.050  63.490  51.180  1.00  0.00            
-ATOM   2808 2H5'  DA B  29      30.560  64.610  52.420  1.00  0.00            
-ATOM   2809  C4'  DA B  29      28.480  64.010  52.570  1.00  0.00            
-ATOM   2810  H4'  DA B  29      28.140  64.690  51.790  1.00  0.00            
-ATOM   2811  O4'  DA B  29      27.740  62.810  52.430  1.00  0.00            
-ATOM   2812  C1'  DA B  29      27.350  62.380  53.720  1.00  0.00            
-ATOM   2813  H1'  DA B  29      26.270  62.480  53.790  1.00  0.00            
-ATOM   2814  N9   DA B  29      27.690  60.960  53.910  1.00  0.00            
-ATOM   2815  C8   DA B  29      28.900  60.340  54.170  1.00  0.00            
-ATOM   2816  H8   DA B  29      29.830  60.880  54.280  1.00  0.00            
-ATOM   2817  N7   DA B  29      28.820  59.040  54.260  1.00  0.00            
-ATOM   2818  C5   DA B  29      27.470  58.790  54.010  1.00  0.00            
-ATOM   2819  C6   DA B  29      26.660  57.640  53.900  1.00  0.00            
-ATOM   2820  N6   DA B  29      27.110  56.410  54.000  1.00  0.00            
-ATOM   2821  H61  DA B  29      26.480  55.620  53.900  1.00  0.00            
-ATOM   2822  H62  DA B  29      28.100  56.270  54.150  1.00  0.00            
-ATOM   2823  N1   DA B  29      25.350  57.730  53.670  1.00  0.00            
-ATOM   2824  C2   DA B  29      24.820  58.940  53.560  1.00  0.00            
-ATOM   2825  H2   DA B  29      23.750  58.970  53.380  1.00  0.00            
-ATOM   2826  N3   DA B  29      25.430  60.110  53.630  1.00  0.00            
-ATOM   2827  C4   DA B  29      26.770  59.960  53.840  1.00  0.00            
-ATOM   2828  C3'  DA B  29      27.990  64.610  53.930  1.00  0.00            
-ATOM   2829  H3'  DA B  29      28.710  65.320  54.330  1.00  0.00            
-ATOM   2830  C2'  DA B  29      27.970  63.330  54.750  1.00  0.00            
-ATOM   2831 1H2'  DA B  29      28.990  63.030  55.000  1.00  0.00            
-ATOM   2832 2H2'  DA B  29      27.370  63.420  55.640  1.00  0.00            
-ATOM   2833  O3'  DA B  29      26.660  65.220  53.830  1.00  0.00            
-ATOM   2834  P    DA B  30      25.840  66.040  55.010  1.00  0.00            
-ATOM   2835  O1P  DA B  30      25.170  67.200  54.350  1.00  0.00            
-ATOM   2836  O2P  DA B  30      26.790  66.370  56.090  1.00  0.00            
-ATOM   2837  O5'  DA B  30      24.610  65.150  55.680  1.00  0.00            
-ATOM   2838  C5'  DA B  30      23.250  65.220  55.180  1.00  0.00            
-ATOM   2839 1H5'  DA B  30      23.330  64.970  54.120  1.00  0.00            
-ATOM   2840 2H5'  DA B  30      22.930  66.250  55.240  1.00  0.00            
-ATOM   2841  C4'  DA B  30      22.090  64.310  55.750  1.00  0.00            
-ATOM   2842  H4'  DA B  30      21.250  64.460  55.070  1.00  0.00            
-ATOM   2843  O4'  DA B  30      22.490  62.970  55.590  1.00  0.00            
-ATOM   2844  C1'  DA B  30      22.640  62.390  56.870  1.00  0.00            
-ATOM   2845  H1'  DA B  30      21.830  61.660  57.020  1.00  0.00            
-ATOM   2846  N9   DA B  30      23.920  61.670  56.940  1.00  0.00            
-ATOM   2847  C8   DA B  30      25.210  62.160  56.990  1.00  0.00            
-ATOM   2848  H8   DA B  30      25.440  63.210  56.940  1.00  0.00            
-ATOM   2849  N7   DA B  30      26.120  61.230  57.080  1.00  0.00            
-ATOM   2850  C5   DA B  30      25.370  60.040  57.060  1.00  0.00            
-ATOM   2851  C6   DA B  30      25.660  58.660  57.070  1.00  0.00            
-ATOM   2852  N6   DA B  30      26.860  58.140  57.100  1.00  0.00            
-ATOM   2853  H61  DA B  30      26.970  57.130  57.090  1.00  0.00            
-ATOM   2854  H62  DA B  30      27.670  58.740  57.120  1.00  0.00            
-ATOM   2855  N1   DA B  30      24.670  57.760  57.040  1.00  0.00            
-ATOM   2856  C2   DA B  30      23.420  58.180  56.990  1.00  0.00            
-ATOM   2857  H2   DA B  30      22.660  57.410  56.970  1.00  0.00            
-ATOM   2858  N3   DA B  30      22.990  59.430  56.970  1.00  0.00            
-ATOM   2859  C4   DA B  30      24.030  60.310  56.990  1.00  0.00            
-ATOM   2860  C3'  DA B  30      21.510  64.410  57.190  1.00  0.00            
-ATOM   2861  H3'  DA B  30      21.570  65.430  57.570  1.00  0.00            
-ATOM   2862  C2'  DA B  30      22.500  63.500  57.900  1.00  0.00            
-ATOM   2863 1H2'  DA B  30      23.450  64.020  58.050  1.00  0.00            
-ATOM   2864 2H2'  DA B  30      22.110  63.130  58.850  1.00  0.00            
-ATOM   2865  O3'  DA B  30      20.140  63.900  57.280  1.00  0.00            
-ATOM   2866  P    DA B  31      19.140  63.940  58.600  1.00  0.00            
-ATOM   2867  O1P  DA B  31      17.780  64.290  58.090  1.00  0.00            
-ATOM   2868  O2P  DA B  31      19.730  64.890  59.570  1.00  0.00            
-ATOM   2869  O5'  DA B  31      18.980  62.470  59.360  1.00  0.00            
-ATOM   2870  C5'  DA B  31      17.920  61.520  59.050  1.00  0.00            
-ATOM   2871 1H5'  DA B  31      17.960  61.400  57.960  1.00  0.00            
-ATOM   2872 2H5'  DA B  31      16.970  62.000  59.270  1.00  0.00            
-ATOM   2873  C4'  DA B  31      17.880  60.060  59.630  1.00  0.00            
-ATOM   2874  H4'  DA B  31      17.110  59.540  59.050  1.00  0.00            
-ATOM   2875  O4'  DA B  31      19.100  59.450  59.310  1.00  0.00            
-ATOM   2876  C1'  DA B  31      19.760  59.070  60.500  1.00  0.00            
-ATOM   2877  H1'  DA B  31      19.740  57.970  60.580  1.00  0.00            
-ATOM   2878  N9   DA B  31      21.160  59.520  60.460  1.00  0.00            
-ATOM   2879  C8   DA B  31      21.670  60.780  60.320  1.00  0.00            
-ATOM   2880  H8   DA B  31      21.040  61.650  60.200  1.00  0.00            
-ATOM   2881  N7   DA B  31      22.970  60.840  60.320  1.00  0.00            
-ATOM   2882  C5   DA B  31      23.340  59.490  60.460  1.00  0.00            
-ATOM   2883  C6   DA B  31      24.550  58.760  60.490  1.00  0.00            
-ATOM   2884  N6   DA B  31      25.750  59.270  60.330  1.00  0.00            
-ATOM   2885  H61  DA B  31      26.540  58.630  60.290  1.00  0.00            
-ATOM   2886  H62  DA B  31      25.850  60.240  60.100  1.00  0.00            
-ATOM   2887  N1   DA B  31      24.530  57.440  60.660  1.00  0.00            
-ATOM   2888  C2   DA B  31      23.380  56.810  60.790  1.00  0.00            
-ATOM   2889  H2   DA B  31      23.430  55.730  60.920  1.00  0.00            
-ATOM   2890  N3   DA B  31      22.170  57.340  60.780  1.00  0.00            
-ATOM   2891  C4   DA B  31      22.230  58.690  60.590  1.00  0.00            
-ATOM   2892  C3'  DA B  31      17.580  59.690  61.130  1.00  0.00            
-ATOM   2893  H3'  DA B  31      16.990  60.460  61.620  1.00  0.00            
-ATOM   2894  C2'  DA B  31      19.000  59.670  61.670  1.00  0.00            
-ATOM   2895 1H2'  DA B  31      19.330  60.690  61.870  1.00  0.00            
-ATOM   2896 2H2'  DA B  31      19.090  59.050  62.560  1.00  0.00            
-ATOM   2897  O3'  DA B  31      16.960  58.370  61.310  1.00  0.00            
-ATOM   2898  P    DT B  32      16.490  57.710  62.750  1.00  0.00            
-ATOM   2899  O1P  DT B  32      15.220  56.970  62.480  1.00  0.00            
-ATOM   2900  O2P  DT B  32      16.390  58.820  63.720  1.00  0.00            
-ATOM   2901  O5'  DT B  32      17.560  56.600  63.370  1.00  0.00            
-ATOM   2902  C5'  DT B  32      17.480  55.170  63.090  1.00  0.00            
-ATOM   2903 1H5'  DT B  32      17.390  55.080  62.010  1.00  0.00            
-ATOM   2904 2H5'  DT B  32      16.540  54.790  63.510  1.00  0.00            
-ATOM   2905  C4'  DT B  32      18.640  54.180  63.500  1.00  0.00            
-ATOM   2906  H4'  DT B  32      18.570  53.340  62.810  1.00  0.00            
-ATOM   2907  O4'  DT B  32      19.850  54.840  63.200  1.00  0.00            
-ATOM   2908  C1'  DT B  32      20.720  54.760  64.310  1.00  0.00            
-ATOM   2909  H1'  DT B  32      21.420  53.930  64.150  1.00  0.00            
-ATOM   2910  N1   DT B  32      21.450  56.050  64.420  1.00  0.00            
-ATOM   2911  C6   DT B  32      20.780  57.240  64.640  1.00  0.00            
-ATOM   2912  H6   DT B  32      19.710  57.220  64.750  1.00  0.00            
-ATOM   2913  C5   DT B  32      21.450  58.420  64.670  1.00  0.00            
-ATOM   2914  C7   DT B  32      20.710  59.690  65.010  1.00  0.00            
-ATOM   2915  H71  DT B  32      19.880  59.480  65.680  1.00  0.00            
-ATOM   2916  H72  DT B  32      21.400  60.380  65.500  1.00  0.00            
-ATOM   2917  H73  DT B  32      20.360  60.170  64.090  1.00  0.00            
-ATOM   2918  C4   DT B  32      22.890  58.450  64.420  1.00  0.00            
-ATOM   2919  O4   DT B  32      23.580  59.470  64.360  1.00  0.00            
-ATOM   2920  N3   DT B  32      23.470  57.220  64.250  1.00  0.00            
-ATOM   2921  H3   DT B  32      24.460  57.190  64.070  1.00  0.00            
-ATOM   2922  C2   DT B  32      22.830  56.010  64.270  1.00  0.00            
-ATOM   2923  O2   DT B  32      23.470  54.970  64.180  1.00  0.00            
-ATOM   2924  C3'  DT B  32      18.800  53.530  64.920  1.00  0.00            
-ATOM   2925  H3'  DT B  32      17.880  53.580  65.490  1.00  0.00            
-ATOM   2926  C2'  DT B  32      19.860  54.440  65.530  1.00  0.00            
-ATOM   2927 1H2'  DT B  32      19.380  55.330  65.930  1.00  0.00            
-ATOM   2928 2H2'  DT B  32      20.440  53.940  66.310  1.00  0.00            
-ATOM   2929  O3'  DT B  32      19.270  52.150  64.860  1.00  0.00            
-ATOM   2930  P    DG B  33      19.550  51.160  66.150  1.00  0.00            
-ATOM   2931  O1P  DG B  33      19.020  49.820  65.790  1.00  0.00            
-ATOM   2932  O2P  DG B  33      18.920  51.800  67.330  1.00  0.00            
-ATOM   2933  O5'  DG B  33      21.160  50.970  66.470  1.00  0.00            
-ATOM   2934  C5'  DG B  33      22.010  50.050  65.730  1.00  0.00            
-ATOM   2935 1H5'  DG B  33      21.810  50.240  64.670  1.00  0.00            
-ATOM   2936 2H5'  DG B  33      21.680  49.030  65.930  1.00  0.00            
-ATOM   2937  C4'  DG B  33      23.580  50.090  65.860  1.00  0.00            
-ATOM   2938  H4'  DG B  33      23.980  49.570  64.990  1.00  0.00            
-ATOM   2939  O4'  DG B  33      23.940  51.440  65.720  1.00  0.00            
-ATOM   2940  C1'  DG B  33      24.790  51.820  66.790  1.00  0.00            
-ATOM   2941  H1'  DG B  33      25.840  51.800  66.460  1.00  0.00            
-ATOM   2942  N9   DG B  33      24.420  53.180  67.200  1.00  0.00            
-ATOM   2943  C8   DG B  33      23.190  53.660  67.550  1.00  0.00            
-ATOM   2944  H8   DG B  33      22.310  53.030  67.580  1.00  0.00            
-ATOM   2945  N7   DG B  33      23.170  54.940  67.820  1.00  0.00            
-ATOM   2946  C5   DG B  33      24.500  55.330  67.570  1.00  0.00            
-ATOM   2947  C6   DG B  33      25.160  56.610  67.570  1.00  0.00            
-ATOM   2948  O6   DG B  33      24.660  57.720  67.790  1.00  0.00            
-ATOM   2949  N1   DG B  33      26.510  56.540  67.250  1.00  0.00            
-ATOM   2950  H1   DG B  33      27.010  57.410  67.130  1.00  0.00            
-ATOM   2951  C2   DG B  33      27.160  55.390  66.960  1.00  0.00            
-ATOM   2952  N2   DG B  33      28.420  55.450  66.650  1.00  0.00            
-ATOM   2953  H21  DG B  33      28.890  56.350  66.540  1.00  0.00            
-ATOM   2954  H22  DG B  33      28.870  54.610  66.320  1.00  0.00            
-ATOM   2955  N3   DG B  33      26.600  54.190  66.950  1.00  0.00            
-ATOM   2956  C4   DG B  33      25.270  54.240  67.230  1.00  0.00            
-ATOM   2957  C3'  DG B  33      24.380  49.530  67.080  1.00  0.00            
-ATOM   2958  H3'  DG B  33      23.800  48.790  67.630  1.00  0.00            
-ATOM   2959  C2'  DG B  33      24.570  50.800  67.900  1.00  0.00            
-ATOM   2960 1H2'  DG B  33      23.660  51.020  68.460  1.00  0.00            
-ATOM   2961 2H2'  DG B  33      25.430  50.740  68.560  1.00  0.00            
-ATOM   2962  O3'  DG B  33      25.660  48.970  66.680  1.00  0.00            
-ATOM   2963  P    DC B  34      26.790  48.340  67.700  1.00  0.00            
-ATOM   2964  O1P  DC B  34      27.270  47.080  67.090  1.00  0.00            
-ATOM   2965  O2P  DC B  34      26.130  48.220  69.020  1.00  0.00            
-ATOM   2966  O5'  DC B  34      28.080  49.370  67.860  1.00  0.00            
-ATOM   2967  C5'  DC B  34      29.080  49.600  66.830  1.00  0.00            
-ATOM   2968 1H5'  DC B  34      28.540  49.800  65.900  1.00  0.00            
-ATOM   2969 2H5'  DC B  34      29.640  48.670  66.670  1.00  0.00            
-ATOM   2970  C4'  DC B  34      30.130  50.780  66.960  1.00  0.00            
-ATOM   2971  H4'  DC B  34      30.560  50.930  65.960  1.00  0.00            
-ATOM   2972  O4'  DC B  34      29.400  51.950  67.280  1.00  0.00            
-ATOM   2973  C1'  DC B  34      29.980  52.560  68.430  1.00  0.00            
-ATOM   2974  H1'  DC B  34      30.660  53.370  68.120  1.00  0.00            
-ATOM   2975  N1   DC B  34      28.880  53.070  69.280  1.00  0.00            
-ATOM   2976  C6   DC B  34      27.820  52.260  69.600  1.00  0.00            
-ATOM   2977  H6   DC B  34      27.850  51.230  69.260  1.00  0.00            
-ATOM   2978  C5   DC B  34      26.750  52.750  70.260  1.00  0.00            
-ATOM   2979  H5   DC B  34      25.910  52.120  70.480  1.00  0.00            
-ATOM   2980  C4   DC B  34      26.800  54.130  70.590  1.00  0.00            
-ATOM   2981  N4   DC B  34      25.750  54.710  71.090  1.00  0.00            
-ATOM   2982  H41  DC B  34      25.870  55.720  71.160  1.00  0.00            
-ATOM   2983  H42  DC B  34      24.870  54.280  71.010  1.00  0.00            
-ATOM   2984  N3   DC B  34      27.810  54.920  70.330  1.00  0.00            
-ATOM   2985  C2   DC B  34      28.880  54.410  69.680  1.00  0.00            
-ATOM   2986  O2   DC B  34      29.820  55.160  69.460  1.00  0.00            
-ATOM   2987  C3'  DC B  34      31.350  50.740  67.930  1.00  0.00            
-ATOM   2988  H3'  DC B  34      31.630  49.710  68.180  1.00  0.00            
-ATOM   2989  C2'  DC B  34      30.780  51.470  69.130  1.00  0.00            
-ATOM   2990 1H2'  DC B  34      30.140  50.800  69.700  1.00  0.00            
-ATOM   2991 2H2'  DC B  34      31.550  51.900  69.760  1.00  0.00            
-ATOM   2992  O3'  DC B  34      32.500  51.460  67.430  1.00  0.00            
-ATOM   2993  P    DC B  35      33.950  51.570  68.200  1.00  0.00            
-ATOM   2994  O1P  DC B  35      35.000  51.160  67.250  1.00  0.00            
-ATOM   2995  O2P  DC B  35      33.810  50.770  69.440  1.00  0.00            
-ATOM   2996  O5'  DC B  35      34.230  53.140  68.660  1.00  0.00            
-ATOM   2997  C5'  DC B  35      34.620  54.190  67.740  1.00  0.00            
-ATOM   2998 1H5'  DC B  35      33.920  54.120  66.910  1.00  0.00            
-ATOM   2999 2H5'  DC B  35      35.610  53.970  67.340  1.00  0.00            
-ATOM   3000  C4'  DC B  35      34.590  55.700  68.200  1.00  0.00            
-ATOM   3001  H4'  DC B  35      34.560  56.300  67.290  1.00  0.00            
-ATOM   3002  O4'  DC B  35      33.370  55.900  68.880  1.00  0.00            
-ATOM   3003  C1'  DC B  35      33.660  56.300  70.200  1.00  0.00            
-ATOM   3004  H1'  DC B  35      33.540  57.390  70.260  1.00  0.00            
-ATOM   3005  N1   DC B  35      32.710  55.620  71.120  1.00  0.00            
-ATOM   3006  C6   DC B  35      32.710  54.260  71.260  1.00  0.00            
-ATOM   3007  H6   DC B  35      33.470  53.680  70.760  1.00  0.00            
-ATOM   3008  C5   DC B  35      31.730  53.650  71.980  1.00  0.00            
-ATOM   3009  H5   DC B  35      31.720  52.580  72.070  1.00  0.00            
-ATOM   3010  C4   DC B  35      30.750  54.500  72.550  1.00  0.00            
-ATOM   3011  N4   DC B  35      29.740  54.000  73.200  1.00  0.00            
-ATOM   3012  H41  DC B  35      29.080  54.690  73.550  1.00  0.00            
-ATOM   3013  H42  DC B  35      29.670  53.020  73.340  1.00  0.00            
-ATOM   3014  N3   DC B  35      30.750  55.800  72.460  1.00  0.00            
-ATOM   3015  C2   DC B  35      31.740  56.390  71.750  1.00  0.00            
-ATOM   3016  O2   DC B  35      31.730  57.620  71.700  1.00  0.00            
-ATOM   3017  C3'  DC B  35      35.680  56.390  69.090  1.00  0.00            
-ATOM   3018  H3'  DC B  35      36.670  55.970  68.910  1.00  0.00            
-ATOM   3019  C2'  DC B  35      35.130  55.990  70.450  1.00  0.00            
-ATOM   3020 1H2'  DC B  35      35.310  54.940  70.640  1.00  0.00            
-ATOM   3021 2H2'  DC B  35      35.560  56.600  71.250  1.00  0.00            
-ATOM   3022  O3'  DC B  35      35.690  57.840  68.940  1.00  0.00            
-ATOM   3023  P    DA B  36      36.750  58.870  69.680  1.00  0.00            
-ATOM   3024  O1P  DA B  36      37.410  59.690  68.640  1.00  0.00            
-ATOM   3025  O2P  DA B  36      37.610  58.050  70.560  1.00  0.00            
-ATOM   3026  O5'  DA B  36      35.960  59.930  70.670  1.00  0.00            
-ATOM   3027  C5'  DA B  36      35.410  61.180  70.220  1.00  0.00            
-ATOM   3028 1H5'  DA B  36      34.710  60.930  69.430  1.00  0.00            
-ATOM   3029 2H5'  DA B  36      36.210  61.770  69.770  1.00  0.00            
-ATOM   3030  C4'  DA B  36      34.640  62.090  71.250  1.00  0.00            
-ATOM   3031  H4'  DA B  36      34.100  62.830  70.670  1.00  0.00            
-ATOM   3032  O4'  DA B  36      33.690  61.270  71.910  1.00  0.00            
-ATOM   3033  C1'  DA B  36      34.140  61.060  73.230  1.00  0.00            
-ATOM   3034  H1'  DA B  36      33.450  61.600  73.890  1.00  0.00            
-ATOM   3035  N9   DA B  36      34.080  59.630  73.600  1.00  0.00            
-ATOM   3036  C8   DA B  36      34.830  58.550  73.180  1.00  0.00            
-ATOM   3037  H8   DA B  36      35.680  58.640  72.510  1.00  0.00            
-ATOM   3038  N7   DA B  36      34.420  57.400  73.640  1.00  0.00            
-ATOM   3039  C5   DA B  36      33.340  57.760  74.440  1.00  0.00            
-ATOM   3040  C6   DA B  36      32.410  57.060  75.220  1.00  0.00            
-ATOM   3041  N6   DA B  36      32.370  55.750  75.320  1.00  0.00            
-ATOM   3042  H61  DA B  36      31.640  55.300  75.850  1.00  0.00            
-ATOM   3043  H62  DA B  36      33.080  55.240  74.820  1.00  0.00            
-ATOM   3044  N1   DA B  36      31.470  57.700  75.920  1.00  0.00            
-ATOM   3045  C2   DA B  36      31.440  59.030  75.870  1.00  0.00            
-ATOM   3046  H2   DA B  36      30.670  59.510  76.450  1.00  0.00            
-ATOM   3047  N3   DA B  36      32.240  59.830  75.190  1.00  0.00            
-ATOM   3048  C4   DA B  36      33.160  59.120  74.470  1.00  0.00            
-ATOM   3049  C3'  DA B  36      35.370  62.850  72.410  1.00  0.00            
-ATOM   3050  H3'  DA B  36      36.340  63.220  72.080  1.00  0.00            
-ATOM   3051  C2'  DA B  36      35.510  61.700  73.380  1.00  0.00            
-ATOM   3052 1H2'  DA B  36      36.300  61.020  73.050  1.00  0.00            
-ATOM   3053 2H2'  DA B  36      35.680  62.060  74.390  1.00  0.00            
-ATOM   3054  O3'  DA B  36      34.570  63.930  73.000  1.00  0.00            
-ATOM   3055  P    DT B  37      35.040  64.930  74.240  1.00  0.00            
-ATOM   3056  O1P  DT B  37      34.560  66.300  73.930  1.00  0.00            
-ATOM   3057  O2P  DT B  37      36.490  64.760  74.450  1.00  0.00            
-ATOM   3058  O5'  DT B  37      34.320  64.520  75.670  1.00  0.00            
-ATOM   3059  C5'  DT B  37      33.050  65.100  76.070  1.00  0.00            
-ATOM   3060 1H5'  DT B  37      32.350  64.860  75.270  1.00  0.00            
-ATOM   3061 2H5'  DT B  37      33.160  66.180  76.090  1.00  0.00            
-ATOM   3062  C4'  DT B  37      32.370  64.660  77.420  1.00  0.00            
-ATOM   3063  H4'  DT B  37      31.350  65.010  77.360  1.00  0.00            
-ATOM   3064  O4'  DT B  37      32.320  63.250  77.410  1.00  0.00            
-ATOM   3065  C1'  DT B  37      33.060  62.760  78.510  1.00  0.00            
-ATOM   3066  H1'  DT B  37      32.340  62.510  79.290  1.00  0.00            
-ATOM   3067  N1   DT B  37      33.810  61.530  78.130  1.00  0.00            
-ATOM   3068  C6   DT B  37      34.930  61.550  77.310  1.00  0.00            
-ATOM   3069  H6   DT B  37      35.310  62.480  76.930  1.00  0.00            
-ATOM   3070  C5   DT B  37      35.540  60.380  76.950  1.00  0.00            
-ATOM   3071  C7   DT B  37      36.820  60.390  76.130  1.00  0.00            
-ATOM   3072  H71  DT B  37      37.170  61.400  75.940  1.00  0.00            
-ATOM   3073  H72  DT B  37      37.590  59.830  76.670  1.00  0.00            
-ATOM   3074  H73  DT B  37      36.650  59.860  75.200  1.00  0.00            
-ATOM   3075  C4   DT B  37      34.970  59.100  77.350  1.00  0.00            
-ATOM   3076  O4   DT B  37      35.360  57.980  77.020  1.00  0.00            
-ATOM   3077  N3   DT B  37      33.890  59.180  78.180  1.00  0.00            
-ATOM   3078  H3   DT B  37      33.500  58.310  78.480  1.00  0.00            
-ATOM   3079  C2   DT B  37      33.310  60.330  78.640  1.00  0.00            
-ATOM   3080  O2   DT B  37      32.420  60.260  79.490  1.00  0.00            
-ATOM   3081  C3'  DT B  37      32.920  65.080  78.820  1.00  0.00            
-ATOM   3082  H3'  DT B  37      33.440  66.030  78.770  1.00  0.00            
-ATOM   3083  C2'  DT B  37      33.900  63.930  79.040  1.00  0.00            
-ATOM   3084 1H2'  DT B  37      34.790  64.080  78.430  1.00  0.00            
-ATOM   3085 2H2'  DT B  37      34.150  63.820  80.090  1.00  0.00            
-ATOM   3086  O3'  DT B  37      31.880  65.110  79.860  1.00  0.00            
-ATOM   3087  P    DC B  38      32.050  65.630  81.420  1.00  0.00            
-ATOM   3088  O1P  DC B  38      30.850  66.450  81.750  1.00  0.00            
-ATOM   3089  O2P  DC B  38      33.350  66.320  81.540  1.00  0.00            
-ATOM   3090  O5'  DC B  38      32.050  64.390  82.520  1.00  0.00            
-ATOM   3091  C5'  DC B  38      30.840  63.860  83.100  1.00  0.00            
-ATOM   3092 1H5'  DC B  38      30.180  63.640  82.260  1.00  0.00            
-ATOM   3093 2H5'  DC B  38      30.370  64.650  83.680  1.00  0.00            
-ATOM   3094  C4'  DC B  38      30.860  62.550  83.980  1.00  0.00            
-ATOM   3095  H4'  DC B  38      29.820  62.250  84.090  1.00  0.00            
-ATOM   3096  O4'  DC B  38      31.480  61.560  83.180  1.00  0.00            
-ATOM   3097  C1'  DC B  38      32.590  61.050  83.870  1.00  0.00            
-ATOM   3098  H1'  DC B  38      32.290  60.090  84.310  1.00  0.00            
-ATOM   3099  N1   DC B  38      33.730  60.840  82.930  1.00  0.00            
-ATOM   3100  C6   DC B  38      34.280  61.870  82.200  1.00  0.00            
-ATOM   3101  H6   DC B  38      33.890  62.870  82.310  1.00  0.00            
-ATOM   3102  C5   DC B  38      35.280  61.610  81.320  1.00  0.00            
-ATOM   3103  H5   DC B  38      35.720  62.390  80.730  1.00  0.00            
-ATOM   3104  C4   DC B  38      35.690  60.250  81.170  1.00  0.00            
-ATOM   3105  N4   DC B  38      36.550  59.920  80.260  1.00  0.00            
-ATOM   3106  H41  DC B  38      36.750  58.920  80.150  1.00  0.00            
-ATOM   3107  H42  DC B  38      36.940  60.590  79.630  1.00  0.00            
-ATOM   3108  N3   DC B  38      35.190  59.280  81.900  1.00  0.00            
-ATOM   3109  C2   DC B  38      34.230  59.550  82.800  1.00  0.00            
-ATOM   3110  O2   DC B  38      33.830  58.650  83.540  1.00  0.00            
-ATOM   3111  C3'  DC B  38      31.500  62.440  85.410  1.00  0.00            
-ATOM   3112  H3'  DC B  38      31.520  63.410  85.900  1.00  0.00            
-ATOM   3113  C2'  DC B  38      32.900  62.000  85.020  1.00  0.00            
-ATOM   3114 1H2'  DC B  38      33.480  62.860  84.680  1.00  0.00            
-ATOM   3115 2H2'  DC B  38      33.400  61.490  85.840  1.00  0.00            
-ATOM   3116  O3'  DC B  38      30.850  61.440  86.270  1.00  0.00            
-ATOM   3117  P    DT B  39      31.230  61.110  87.850  1.00  0.00            
-ATOM   3118  O1P  DT B  39      29.950  60.880  88.560  1.00  0.00            
-ATOM   3119  O2P  DT B  39      32.060  62.230  88.350  1.00  0.00            
-ATOM   3120  O5'  DT B  39      32.120  59.710  88.040  1.00  0.00            
-ATOM   3121  C5'  DT B  39      31.520  58.410  88.300  1.00  0.00            
-ATOM   3122 1H5'  DT B  39      30.720  58.310  87.560  1.00  0.00            
-ATOM   3123 2H5'  DT B  39      31.030  58.440  89.270  1.00  0.00            
-ATOM   3124  C4'  DT B  39      32.350  57.070  88.200  1.00  0.00            
-ATOM   3125  H4'  DT B  39      31.620  56.280  88.030  1.00  0.00            
-ATOM   3126  O4'  DT B  39      33.110  57.180  87.020  1.00  0.00            
-ATOM   3127  C1'  DT B  39      34.460  56.880  87.300  1.00  0.00            
-ATOM   3128  H1'  DT B  39      34.660  55.850  87.000  1.00  0.00            
-ATOM   3129  N1   DT B  39      35.330  57.810  86.540  1.00  0.00            
-ATOM   3130  C6   DT B  39      35.280  59.180  86.730  1.00  0.00            
-ATOM   3131  H6   DT B  39      34.570  59.580  87.440  1.00  0.00            
-ATOM   3132  C5   DT B  39      36.080  60.010  86.020  1.00  0.00            
-ATOM   3133  C7   DT B  39      36.080  61.500  86.290  1.00  0.00            
-ATOM   3134  H71  DT B  39      35.450  61.750  87.140  1.00  0.00            
-ATOM   3135  H72  DT B  39      37.110  61.810  86.490  1.00  0.00            
-ATOM   3136  H73  DT B  39      35.740  62.020  85.400  1.00  0.00            
-ATOM   3137  C4   DT B  39      36.970  59.480  84.990  1.00  0.00            
-ATOM   3138  O4   DT B  39      37.680  60.150  84.250  1.00  0.00            
-ATOM   3139  N3   DT B  39      36.970  58.110  84.900  1.00  0.00            
-ATOM   3140  H3   DT B  39      37.570  57.700  84.190  1.00  0.00            
-ATOM   3141  C2   DT B  39      36.250  57.240  85.660  1.00  0.00            
-ATOM   3142  O2   DT B  39      36.450  56.030  85.610  1.00  0.00            
-ATOM   3143  C3'  DT B  39      33.300  56.520  89.320  1.00  0.00            
-ATOM   3144  H3'  DT B  39      33.070  56.970  90.290  1.00  0.00            
-ATOM   3145  C2'  DT B  39      34.640  56.990  88.810  1.00  0.00            
-ATOM   3146 1H2'  DT B  39      34.820  58.020  89.120  1.00  0.00            
-ATOM   3147 2H2'  DT B  39      35.460  56.340  89.140  1.00  0.00            
-ATOM   3148  O3'  DT B  39      33.280  55.060  89.440  1.00  0.00            
-ATOM   3149  P    DT B  40      34.140  54.170  90.540  1.00  0.00            
-ATOM   3150  O1P  DT B  40      33.250  53.060  90.980  1.00  0.00            
-ATOM   3151  O2P  DT B  40      34.560  55.110  91.610  1.00  0.00            
-ATOM   3152  O5'  DT B  40      35.510  53.470  89.910  1.00  0.00            
-ATOM   3153  C5'  DT B  40      35.530  52.170  89.260  1.00  0.00            
-ATOM   3154 1H5'  DT B  40      34.690  52.170  88.570  1.00  0.00            
-ATOM   3155 2H5'  DT B  40      35.330  51.400  90.010  1.00  0.00            
-ATOM   3156  C4'  DT B  40      36.770  51.710  88.400  1.00  0.00            
-ATOM   3157  H4'  DT B  40      36.390  51.000  87.660  1.00  0.00            
-ATOM   3158  O4'  DT B  40      37.190  52.840  87.690  1.00  0.00            
-ATOM   3159  C1'  DT B  40      38.590  52.960  87.740  1.00  0.00            
-ATOM   3160  H1'  DT B  40      39.040  52.520  86.840  1.00  0.00            
-ATOM   3161  N1   DT B  40      38.920  54.400  87.840  1.00  0.00            
-ATOM   3162  C6   DT B  40      38.420  55.180  88.860  1.00  0.00            
-ATOM   3163  H6   DT B  40      37.800  54.710  89.610  1.00  0.00            
-ATOM   3164  C5   DT B  40      38.700  56.510  88.920  1.00  0.00            
-ATOM   3165  C7   DT B  40      38.210  57.300  90.120  1.00  0.00            
-ATOM   3166  H71  DT B  40      38.810  57.030  90.990  1.00  0.00            
-ATOM   3167  H72  DT B  40      38.340  58.370  89.930  1.00  0.00            
-ATOM   3168  H73  DT B  40      37.160  57.100  90.310  1.00  0.00            
-ATOM   3169  C4   DT B  40      39.460  57.150  87.850  1.00  0.00            
-ATOM   3170  O4   DT B  40      39.670  58.360  87.770  1.00  0.00            
-ATOM   3171  N3   DT B  40      39.930  56.290  86.900  1.00  0.00            
-ATOM   3172  H3   DT B  40      40.490  56.670  86.140  1.00  0.00            
-ATOM   3173  C2   DT B  40      39.760  54.940  86.870  1.00  0.00            
-ATOM   3174  O2   DT B  40      40.380  54.250  86.070  1.00  0.00            
-ATOM   3175  C3'  DT B  40      38.060  51.020  88.990  1.00  0.00            
-ATOM   3176  H3'  DT B  40      37.890  50.680  90.010  1.00  0.00            
-ATOM   3177  C2'  DT B  40      39.050  52.170  88.970  1.00  0.00            
-ATOM   3178 1H2'  DT B  40      38.950  52.750  89.880  1.00  0.00            
-ATOM   3179 2H2'  DT B  40      40.080  51.830  88.840  1.00  0.00            
-ATOM   3180  O3'  DT B  40      38.550  49.920  88.170  1.00  0.00            
-ATOM   3181  P    DT B  41      39.890  49.010  88.500  1.00  0.00            
-ATOM   3182  O1P  DT B  41      39.550  47.600  88.150  1.00  0.00            
-ATOM   3183  O2P  DT B  41      40.220  49.260  89.930  1.00  0.00            
-ATOM   3184  O5'  DT B  41      41.190  49.470  87.570  1.00  0.00            
-ATOM   3185  C5'  DT B  41      41.380  49.070  86.190  1.00  0.00            
-ATOM   3186 1H5'  DT B  41      40.420  49.220  85.690  1.00  0.00            
-ATOM   3187 2H5'  DT B  41      41.580  48.000  86.150  1.00  0.00            
-ATOM   3188  C4'  DT B  41      42.430  49.800  85.270  1.00  0.00            
-ATOM   3189  H4'  DT B  41      42.100  49.660  84.230  1.00  0.00            
-ATOM   3190  O4'  DT B  41      42.310  51.170  85.550  1.00  0.00            
-ATOM   3191  C1'  DT B  41      43.600  51.750  85.660  1.00  0.00            
-ATOM   3192  H1'  DT B  41      43.910  52.170  84.690  1.00  0.00            
-ATOM   3193  N1   DT B  41      43.500  52.810  86.690  1.00  0.00            
-ATOM   3194  C6   DT B  41      43.030  52.500  87.950  1.00  0.00            
-ATOM   3195  H6   DT B  41      42.820  51.470  88.180  1.00  0.00            
-ATOM   3196  C5   DT B  41      42.780  53.480  88.860  1.00  0.00            
-ATOM   3197  C7   DT B  41      42.290  53.110  90.240  1.00  0.00            
-ATOM   3198  H71  DT B  41      42.270  52.030  90.370  1.00  0.00            
-ATOM   3199  H72  DT B  41      42.970  53.560  90.970  1.00  0.00            
-ATOM   3200  H73  DT B  41      41.300  53.530  90.390  1.00  0.00            
-ATOM   3201  C4   DT B  41      42.960  54.880  88.500  1.00  0.00            
-ATOM   3202  O4   DT B  41      42.670  55.840  89.220  1.00  0.00            
-ATOM   3203  N3   DT B  41      43.490  55.090  87.240  1.00  0.00            
-ATOM   3204  H3   DT B  41      43.680  56.030  86.930  1.00  0.00            
-ATOM   3205  C2   DT B  41      43.800  54.120  86.330  1.00  0.00            
-ATOM   3206  O2   DT B  41      44.320  54.430  85.270  1.00  0.00            
-ATOM   3207  C3'  DT B  41      43.960  49.470  85.240  1.00  0.00            
-ATOM   3208  H3'  DT B  41      44.170  48.510  85.720  1.00  0.00            
-ATOM   3209  C2'  DT B  41      44.540  50.620  86.050  1.00  0.00            
-ATOM   3210 1H2'  DT B  41      44.480  50.390  87.110  1.00  0.00            
-ATOM   3211 2H2'  DT B  41      45.570  50.850  85.780  1.00  0.00            
-ATOM   3212  O3'  DT B  41      44.510  49.470  83.900  1.00  0.00            
-ATOM   3213  P    DA B  42      46.090  49.180  83.520  1.00  0.00            
-ATOM   3214  O1P  DA B  42      46.100  48.250  82.370  1.00  0.00            
-ATOM   3215  O2P  DA B  42      46.720  48.690  84.770  1.00  0.00            
-ATOM   3216  O5'  DA B  42      46.850  50.590  83.070  1.00  0.00            
-ATOM   3217  C5'  DA B  42      46.690  51.210  81.770  1.00  0.00            
-ATOM   3218 1H5'  DA B  42      45.620  51.250  81.570  1.00  0.00            
-ATOM   3219 2H5'  DA B  42      47.130  50.570  81.010  1.00  0.00            
-ATOM   3220  C4'  DA B  42      47.210  52.690  81.520  1.00  0.00            
-ATOM   3221  H4'  DA B  42      46.700  53.060  80.630  1.00  0.00            
-ATOM   3222  O4'  DA B  42      46.760  53.440  82.620  1.00  0.00            
-ATOM   3223  C1'  DA B  42      47.880  54.060  83.230  1.00  0.00            
-ATOM   3224  H1'  DA B  42      47.960  55.100  82.890  1.00  0.00            
-ATOM   3225  N9   DA B  42      47.710  54.000  84.680  1.00  0.00            
-ATOM   3226  C8   DA B  42      47.480  52.890  85.460  1.00  0.00            
-ATOM   3227  H8   DA B  42      47.430  51.900  85.030  1.00  0.00            
-ATOM   3228  N7   DA B  42      47.300  53.150  86.740  1.00  0.00            
-ATOM   3229  C5   DA B  42      47.420  54.550  86.760  1.00  0.00            
-ATOM   3230  C6   DA B  42      47.280  55.550  87.740  1.00  0.00            
-ATOM   3231  N6   DA B  42      46.930  55.300  88.990  1.00  0.00            
-ATOM   3232  H61  DA B  42      46.820  56.080  89.610  1.00  0.00            
-ATOM   3233  H62  DA B  42      46.890  54.340  89.260  1.00  0.00            
-ATOM   3234  N1   DA B  42      47.450  56.840  87.480  1.00  0.00            
-ATOM   3235  C2   DA B  42      47.770  57.180  86.230  1.00  0.00            
-ATOM   3236  H2   DA B  42      47.920  58.230  86.040  1.00  0.00            
-ATOM   3237  N3   DA B  42      47.910  56.370  85.200  1.00  0.00            
-ATOM   3238  C4   DA B  42      47.700  55.070  85.520  1.00  0.00            
-ATOM   3239  C3'  DA B  42      48.720  53.050  81.330  1.00  0.00            
-ATOM   3240  H3'  DA B  42      49.280  52.230  80.880  1.00  0.00            
-ATOM   3241  C2'  DA B  42      49.110  53.280  82.770  1.00  0.00            
-ATOM   3242 1H2'  DA B  42      49.210  52.330  83.290  1.00  0.00            
-ATOM   3243 2H2'  DA B  42      50.020  53.880  82.860  1.00  0.00            
-ATOM   3244  O3'  DA B  42      48.930  54.270  80.570  1.00  0.00            
-ATOM   3245  P    DC B  43      50.400  54.910  80.190  1.00  0.00            
-ATOM   3246  O1P  DC B  43      50.420  55.170  78.730  1.00  0.00            
-ATOM   3247  O2P  DC B  43      51.400  53.960  80.720  1.00  0.00            
-ATOM   3248  O5'  DC B  43      50.650  56.350  80.960  1.00  0.00            
-ATOM   3249  C5'  DC B  43      50.090  57.610  80.520  1.00  0.00            
-ATOM   3250 1H5'  DC B  43      49.010  57.450  80.460  1.00  0.00            
-ATOM   3251 2H5'  DC B  43      50.440  57.830  79.520  1.00  0.00            
-ATOM   3252  C4'  DC B  43      50.290  58.900  81.420  1.00  0.00            
-ATOM   3253  H4'  DC B  43      49.520  59.610  81.110  1.00  0.00            
-ATOM   3254  O4'  DC B  43      50.010  58.520  82.750  1.00  0.00            
-ATOM   3255  C1'  DC B  43      51.200  58.670  83.510  1.00  0.00            
-ATOM   3256  H1'  DC B  43      51.110  59.600  84.080  1.00  0.00            
-ATOM   3257  N1   DC B  43      51.320  57.520  84.440  1.00  0.00            
-ATOM   3258  C6   DC B  43      51.560  56.240  84.000  1.00  0.00            
-ATOM   3259  H6   DC B  43      51.760  56.060  82.960  1.00  0.00            
-ATOM   3260  C5   DC B  43      51.490  55.190  84.870  1.00  0.00            
-ATOM   3261  H5   DC B  43      51.650  54.190  84.510  1.00  0.00            
-ATOM   3262  C4   DC B  43      51.170  55.500  86.220  1.00  0.00            
-ATOM   3263  N4   DC B  43      50.960  54.560  87.090  1.00  0.00            
-ATOM   3264  H41  DC B  43      50.690  54.880  88.010  1.00  0.00            
-ATOM   3265  H42  DC B  43      50.960  53.610  86.790  1.00  0.00            
-ATOM   3266  N3   DC B  43      50.960  56.710  86.670  1.00  0.00            
-ATOM   3267  C2   DC B  43      51.030  57.740  85.790  1.00  0.00            
-ATOM   3268  O2   DC B  43      50.820  58.860  86.240  1.00  0.00            
-ATOM   3269  C3'  DC B  43      51.630  59.710  81.490  1.00  0.00            
-ATOM   3270  H3'  DC B  43      52.150  59.700  80.530  1.00  0.00            
-ATOM   3271  C2'  DC B  43      52.350  58.860  82.530  1.00  0.00            
-ATOM   3272 1H2'  DC B  43      52.670  57.920  82.080  1.00  0.00            
-ATOM   3273 2H2'  DC B  43      53.190  59.380  82.970  1.00  0.00            
-ATOM   3274  O3'  DC B  43      51.450  61.080  81.970  1.00  0.00            
-ATOM   3275  P    DG B  44      52.620  62.230  82.100  1.00  0.00            
-ATOM   3276  O1P  DG B  44      52.120  63.490  81.470  1.00  0.00            
-ATOM   3277  O2P  DG B  44      53.880  61.670  81.560  1.00  0.00            
-ATOM   3278  O5'  DG B  44      52.930  62.630  83.670  1.00  0.00            
-ATOM   3279  C5'  DG B  44      52.230  63.680  84.360  1.00  0.00            
-ATOM   3280 1H5'  DG B  44      51.170  63.410  84.320  1.00  0.00            
-ATOM   3281 2H5'  DG B  44      52.340  64.600  83.780  1.00  0.00            
-ATOM   3282  C4'  DG B  44      52.560  64.010  85.870  1.00  0.00            
-ATOM   3283  H4'  DG B  44      51.770  64.680  86.200  1.00  0.00            
-ATOM   3284  O4'  DG B  44      52.430  62.810  86.600  1.00  0.00            
-ATOM   3285  C1'  DG B  44      53.730  62.390  86.950  1.00  0.00            
-ATOM   3286  H1'  DG B  44      53.820  62.500  88.040  1.00  0.00            
-ATOM   3287  N9   DG B  44      53.920  60.960  86.650  1.00  0.00            
-ATOM   3288  C8   DG B  44      54.120  60.290  85.460  1.00  0.00            
-ATOM   3289  H8   DG B  44      54.180  60.780  84.500  1.00  0.00            
-ATOM   3290  N7   DG B  44      54.200  58.990  85.600  1.00  0.00            
-ATOM   3291  C5   DG B  44      54.060  58.790  86.980  1.00  0.00            
-ATOM   3292  C6   DG B  44      54.040  57.610  87.800  1.00  0.00            
-ATOM   3293  O6   DG B  44      54.130  56.420  87.500  1.00  0.00            
-ATOM   3294  N1   DG B  44      53.890  57.890  89.150  1.00  0.00            
-ATOM   3295  H1   DG B  44      53.850  57.100  89.770  1.00  0.00            
-ATOM   3296  C2   DG B  44      53.770  59.140  89.660  1.00  0.00            
-ATOM   3297  N2   DG B  44      53.680  59.300  90.940  1.00  0.00            
-ATOM   3298  H21  DG B  44      53.620  58.490  91.550  1.00  0.00            
-ATOM   3299  H22  DG B  44      53.600  60.240  91.260  1.00  0.00            
-ATOM   3300  N3   DG B  44      53.770  60.250  88.960  1.00  0.00            
-ATOM   3301  C4   DG B  44      53.910  60.000  87.620  1.00  0.00            
-ATOM   3302  C3'  DG B  44      53.920  64.620  86.350  1.00  0.00            
-ATOM   3303  H3'  DG B  44      54.300  65.350  85.630  1.00  0.00            
-ATOM   3304  C2'  DG B  44      54.740  63.340  86.330  1.00  0.00            
-ATOM   3305 1H2'  DG B  44      54.980  63.050  85.300  1.00  0.00            
-ATOM   3306 2H2'  DG B  44      55.650  63.430  86.920  1.00  0.00            
-ATOM   3307  O3'  DG B  44      53.800  65.200  87.690  1.00  0.00            
-ATOM   3308  P    DG B  45      54.960  66.040  88.530  1.00  0.00            
-ATOM   3309  O1P  DG B  45      54.280  67.200  89.170  1.00  0.00            
-ATOM   3310  O2P  DG B  45      56.070  66.350  87.610  1.00  0.00            
-ATOM   3311  O5'  DG B  45      55.600  65.160  89.800  1.00  0.00            
-ATOM   3312  C5'  DG B  45      55.010  65.180  91.120  1.00  0.00            
-ATOM   3313 1H5'  DG B  45      53.970  64.870  90.990  1.00  0.00            
-ATOM   3314 2H5'  DG B  45      54.980  66.220  91.450  1.00  0.00            
-ATOM   3315  C4'  DG B  45      55.580  64.310  92.300  1.00  0.00            
-ATOM   3316  H4'  DG B  45      54.890  64.440  93.130  1.00  0.00            
-ATOM   3317  O4'  DG B  45      55.480  62.970  91.900  1.00  0.00            
-ATOM   3318  C1'  DG B  45      56.790  62.460  91.760  1.00  0.00            
-ATOM   3319  H1'  DG B  45      56.970  61.750  92.580  1.00  0.00            
-ATOM   3320  N9   DG B  45      56.940  61.730  90.490  1.00  0.00            
-ATOM   3321  C8   DG B  45      56.930  62.170  89.190  1.00  0.00            
-ATOM   3322  H8   DG B  45      56.800  63.210  88.920  1.00  0.00            
-ATOM   3323  N7   DG B  45      57.080  61.220  88.310  1.00  0.00            
-ATOM   3324  C5   DG B  45      57.180  60.050  89.090  1.00  0.00            
-ATOM   3325  C6   DG B  45      57.280  58.650  88.770  1.00  0.00            
-ATOM   3326  O6   DG B  45      57.300  58.100  87.680  1.00  0.00            
-ATOM   3327  N1   DG B  45      57.330  57.840  89.880  1.00  0.00            
-ATOM   3328  H1   DG B  45      57.340  56.850  89.700  1.00  0.00            
-ATOM   3329  C2   DG B  45      57.290  58.280  91.150  1.00  0.00            
-ATOM   3330  N2   DG B  45      57.320  57.420  92.120  1.00  0.00            
-ATOM   3331  H21  DG B  45      57.300  56.430  91.910  1.00  0.00            
-ATOM   3332  H22  DG B  45      57.260  57.780  93.050  1.00  0.00            
-ATOM   3333  N3   DG B  45      57.210  59.550  91.510  1.00  0.00            
-ATOM   3334  C4   DG B  45      57.130  60.380  90.430  1.00  0.00            
-ATOM   3335  C3'  DG B  45      57.020  64.470  92.900  1.00  0.00            
-ATOM   3336  H3'  DG B  45      57.360  65.500  92.860  1.00  0.00            
-ATOM   3337  C2'  DG B  45      57.780  63.610  91.920  1.00  0.00            
-ATOM   3338 1H2'  DG B  45      57.910  64.140  90.970  1.00  0.00            
-ATOM   3339 2H2'  DG B  45      58.720  63.270  92.330  1.00  0.00            
-ATOM   3340  O3'  DG B  45      57.150  63.940  94.260  1.00  0.00            
-ATOM   3341  P    DT B  46      58.520  63.950  95.200  1.00  0.00            
-ATOM   3342  O1P  DT B  46      58.080  64.250  96.590  1.00  0.00            
-ATOM   3343  O2P  DT B  46      59.450  64.940  94.600  1.00  0.00            
-ATOM   3344  O5'  DT B  46      59.320  62.490  95.270  1.00  0.00            
-ATOM   3345  C5'  DT B  46      59.120  61.520  96.330  1.00  0.00            
-ATOM   3346 1H5'  DT B  46      58.040  61.380  96.390  1.00  0.00            
-ATOM   3347 2H5'  DT B  46      59.410  61.990  97.270  1.00  0.00            
-ATOM   3348  C4'  DT B  46      59.740  60.070  96.290  1.00  0.00            
-ATOM   3349  H4'  DT B  46      59.140  59.470  96.980  1.00  0.00            
-ATOM   3350  O4'  DT B  46      59.480  59.560  95.000  1.00  0.00            
-ATOM   3351  C1'  DT B  46      60.690  59.130  94.430  1.00  0.00            
-ATOM   3352  H1'  DT B  46      60.770  58.050  94.540  1.00  0.00            
-ATOM   3353  N1   DT B  46      60.700  59.490  92.990  1.00  0.00            
-ATOM   3354  C6   DT B  46      60.710  60.810  92.560  1.00  0.00            
-ATOM   3355  H6   DT B  46      60.660  61.600  93.300  1.00  0.00            
-ATOM   3356  C5   DT B  46      60.740  61.110  91.240  1.00  0.00            
-ATOM   3357  C7   DT B  46      60.820  62.550  90.780  1.00  0.00            
-ATOM   3358  H71  DT B  46      60.910  63.230  91.620  1.00  0.00            
-ATOM   3359  H72  DT B  46      61.690  62.660  90.120  1.00  0.00            
-ATOM   3360  H73  DT B  46      59.930  62.780  90.180  1.00  0.00            
-ATOM   3361  C4   DT B  46      60.710  60.040  90.240  1.00  0.00            
-ATOM   3362  O4   DT B  46      60.700  60.200  89.030  1.00  0.00            
-ATOM   3363  N3   DT B  46      60.710  58.780  90.750  1.00  0.00            
-ATOM   3364  H3   DT B  46      60.700  58.010  90.090  1.00  0.00            
-ATOM   3365  C2   DT B  46      60.740  58.430  92.080  1.00  0.00            
-ATOM   3366  O2   DT B  46      60.810  57.250  92.420  1.00  0.00            
-ATOM   3367  C3'  DT B  46      61.230  59.710  96.630  1.00  0.00            
-ATOM   3368  H3'  DT B  46      61.680  60.460  97.280  1.00  0.00            
-ATOM   3369  C2'  DT B  46      61.830  59.770  95.230  1.00  0.00            
-ATOM   3370 1H2'  DT B  46      61.990  60.810  94.940  1.00  0.00            
-ATOM   3371 2H2'  DT B  46      62.750  59.200  95.150  1.00  0.00            
-ATOM   3372  O3'  DT B  46      61.390  58.370  97.200  1.00  0.00            
-ATOM   3373  P    DA B  47      62.800  57.720  97.770  1.00  0.00            
-ATOM   3374  O1P  DA B  47      62.470  57.050  99.060  1.00  0.00            
-ATOM   3375  O2P  DA B  47      63.790  58.820  97.840  1.00  0.00            
-ATOM   3376  O5'  DA B  47      63.440  56.530  96.790  1.00  0.00            
-ATOM   3377  C5'  DA B  47      63.150  55.120  96.950  1.00  0.00            
-ATOM   3378 1H5'  DA B  47      62.070  55.050  97.020  1.00  0.00            
-ATOM   3379 2H5'  DA B  47      63.550  54.800  97.910  1.00  0.00            
-ATOM   3380  C4'  DA B  47      63.560  54.040  95.870  1.00  0.00            
-ATOM   3381  H4'  DA B  47      62.930  53.170  96.070  1.00  0.00            
-ATOM   3382  O4'  DA B  47      63.160  54.530  94.610  1.00  0.00            
-ATOM   3383  C1'  DA B  47      64.290  54.620  93.760  1.00  0.00            
-ATOM   3384  H1'  DA B  47      64.230  53.840  92.990  1.00  0.00            
-ATOM   3385  N9   DA B  47      64.290  55.940  93.120  1.00  0.00            
-ATOM   3386  C8   DA B  47      64.310  57.190  93.680  1.00  0.00            
-ATOM   3387  H8   DA B  47      64.320  57.340  94.750  1.00  0.00            
-ATOM   3388  N7   DA B  47      64.310  58.180  92.830  1.00  0.00            
-ATOM   3389  C5   DA B  47      64.260  57.490  91.600  1.00  0.00            
-ATOM   3390  C6   DA B  47      64.200  57.860  90.240  1.00  0.00            
-ATOM   3391  N6   DA B  47      64.140  59.100  89.800  1.00  0.00            
-ATOM   3392  H61  DA B  47      64.010  59.240  88.800  1.00  0.00            
-ATOM   3393  H62  DA B  47      64.070  59.850  90.460  1.00  0.00            
-ATOM   3394  N1   DA B  47      64.170  56.940  89.280  1.00  0.00            
-ATOM   3395  C2   DA B  47      64.170  55.660  89.600  1.00  0.00            
-ATOM   3396  H2   DA B  47      64.140  54.950  88.790  1.00  0.00            
-ATOM   3397  N3   DA B  47      64.230  55.150  90.830  1.00  0.00            
-ATOM   3398  C4   DA B  47      64.260  56.130  91.770  1.00  0.00            
-ATOM   3399  C3'  DA B  47      65.000  53.440  95.670  1.00  0.00            
-ATOM   3400  H3'  DA B  47      65.590  53.510  96.580  1.00  0.00            
-ATOM   3401  C2'  DA B  47      65.540  54.390  94.610  1.00  0.00            
-ATOM   3402 1H2'  DA B  47      65.870  55.320  95.080  1.00  0.00            
-ATOM   3403 2H2'  DA B  47      66.350  53.950  94.020  1.00  0.00            
-ATOM   3404  O3'  DA B  47      64.970  52.070  95.190  1.00  0.00            
-ATOM   3405  P    DG B  48      66.280  51.100  94.870  1.00  0.00            
-ATOM   3406  O1P  DG B  48      65.940  49.750  95.370  1.00  0.00            
-ATOM   3407  O2P  DG B  48      67.450  51.760  95.500  1.00  0.00            
-ATOM   3408  O5'  DG B  48      66.580  50.960  93.240  1.00  0.00            
-ATOM   3409  C5'  DG B  48      65.860  50.040  92.380  1.00  0.00            
-ATOM   3410 1H5'  DG B  48      64.800  50.200  92.590  1.00  0.00            
-ATOM   3411 2H5'  DG B  48      66.080  49.020  92.690  1.00  0.00            
-ATOM   3412  C4'  DG B  48      65.980  50.110  90.810  1.00  0.00            
-ATOM   3413  H4'  DG B  48      65.100  49.600  90.410  1.00  0.00            
-ATOM   3414  O4'  DG B  48      65.830  51.470  90.470  1.00  0.00            
-ATOM   3415  C1'  DG B  48      66.870  51.840  89.600  1.00  0.00            
-ATOM   3416  H1'  DG B  48      66.510  51.830  88.560  1.00  0.00            
-ATOM   3417  N9   DG B  48      67.290  53.200  89.960  1.00  0.00            
-ATOM   3418  C8   DG B  48      67.740  53.690  91.160  1.00  0.00            
-ATOM   3419  H8   DG B  48      67.830  53.050  92.020  1.00  0.00            
-ATOM   3420  N7   DG B  48      68.020  54.960  91.160  1.00  0.00            
-ATOM   3421  C5   DG B  48      67.680  55.360  89.850  1.00  0.00            
-ATOM   3422  C6   DG B  48      67.680  56.640  89.190  1.00  0.00            
-ATOM   3423  O6   DG B  48      68.000  57.740  89.650  1.00  0.00            
-ATOM   3424  N1   DG B  48      67.250  56.570  87.870  1.00  0.00            
-ATOM   3425  H1   DG B  48      67.210  57.430  87.340  1.00  0.00            
-ATOM   3426  C2   DG B  48      66.850  55.430  87.250  1.00  0.00            
-ATOM   3427  N2   DG B  48      66.490  55.500  86.000  1.00  0.00            
-ATOM   3428  H21  DG B  48      66.540  56.370  85.480  1.00  0.00            
-ATOM   3429  H22  DG B  48      66.150  54.660  85.570  1.00  0.00            
-ATOM   3430  N3   DG B  48      66.840  54.240  87.820  1.00  0.00            
-ATOM   3431  C4   DG B  48      67.250  54.270  89.120  1.00  0.00            
-ATOM   3432  C3'  DG B  48      67.190  49.560  89.980  1.00  0.00            
-ATOM   3433  H3'  DG B  48      67.760  48.830  90.550  1.00  0.00            
-ATOM   3434  C2'  DG B  48      67.990  50.830  89.770  1.00  0.00            
-ATOM   3435 1H2'  DG B  48      68.580  51.050  90.660  1.00  0.00            
-ATOM   3436 2H2'  DG B  48      68.630  50.790  88.890  1.00  0.00            
-ATOM   3437  O3'  DG B  48      66.780  48.980  88.710  1.00  0.00            
-ATOM   3438  P    DA B  49      67.780  48.340  87.570  1.00  0.00            
-ATOM   3439  O1P  DA B  49      67.150  47.090  87.090  1.00  0.00            
-ATOM   3440  O2P  DA B  49      69.110  48.190  88.220  1.00  0.00            
-ATOM   3441  O5'  DA B  49      67.950  49.360  86.270  1.00  0.00            
-ATOM   3442  C5'  DA B  49      66.950  49.510  85.220  1.00  0.00            
-ATOM   3443 1H5'  DA B  49      66.000  49.660  85.730  1.00  0.00            
-ATOM   3444 2H5'  DA B  49      66.870  48.560  84.680  1.00  0.00            
-ATOM   3445  C4'  DA B  49      67.040  50.670  84.150  1.00  0.00            
-ATOM   3446  H4'  DA B  49      66.040  50.790  83.730  1.00  0.00            
-ATOM   3447  O4'  DA B  49      67.320  51.850  84.870  1.00  0.00            
-ATOM   3448  C1'  DA B  49      68.470  52.460  84.300  1.00  0.00            
-ATOM   3449  H1'  DA B  49      68.180  53.270  83.620  1.00  0.00            
-ATOM   3450  N9   DA B  49      69.290  52.970  85.400  1.00  0.00            
-ATOM   3451  C8   DA B  49      69.770  52.300  86.490  1.00  0.00            
-ATOM   3452  H8   DA B  49      69.630  51.230  86.600  1.00  0.00            
-ATOM   3453  N7   DA B  49      70.370  53.050  87.380  1.00  0.00            
-ATOM   3454  C5   DA B  49      70.220  54.330  86.810  1.00  0.00            
-ATOM   3455  C6   DA B  49      70.510  55.640  87.220  1.00  0.00            
-ATOM   3456  N6   DA B  49      71.030  55.950  88.390  1.00  0.00            
-ATOM   3457  H61  DA B  49      71.140  56.930  88.620  1.00  0.00            
-ATOM   3458  H62  DA B  49      71.180  55.200  89.040  1.00  0.00            
-ATOM   3459  N1   DA B  49      70.210  56.700  86.480  1.00  0.00            
-ATOM   3460  C2   DA B  49      69.630  56.490  85.290  1.00  0.00            
-ATOM   3461  H2   DA B  49      69.400  57.370  84.700  1.00  0.00            
-ATOM   3462  N3   DA B  49      69.320  55.320  84.770  1.00  0.00            
-ATOM   3463  C4   DA B  49      69.610  54.280  85.590  1.00  0.00            
-ATOM   3464  C3'  DA B  49      68.010  50.660  82.920  1.00  0.00            
-ATOM   3465  H3'  DA B  49      68.260  49.640  82.620  1.00  0.00            
-ATOM   3466  C2'  DA B  49      69.200  51.380  83.520  1.00  0.00            
-ATOM   3467 1H2'  DA B  49      69.760  50.710  84.170  1.00  0.00            
-ATOM   3468 2H2'  DA B  49      69.860  51.810  82.760  1.00  0.00            
-ATOM   3469  O3'  DA B  49      67.490  51.400  81.790  1.00  0.00            
-ATOM   3470  P    DA B  50      68.260  51.590  80.350  1.00  0.00            
-ATOM   3471  O1P  DA B  50      67.310  51.190  79.290  1.00  0.00            
-ATOM   3472  O2P  DA B  50      69.510  50.790  80.450  1.00  0.00            
-ATOM   3473  O5'  DA B  50      68.680  53.180  80.100  1.00  0.00            
-ATOM   3474  C5'  DA B  50      67.770  54.190  79.600  1.00  0.00            
-ATOM   3475 1H5'  DA B  50      66.870  54.110  80.210  1.00  0.00            
-ATOM   3476 2H5'  DA B  50      67.480  53.920  78.580  1.00  0.00            
-ATOM   3477  C4'  DA B  50      68.170  55.720  79.620  1.00  0.00            
-ATOM   3478  H4'  DA B  50      67.240  56.290  79.580  1.00  0.00            
-ATOM   3479  O4'  DA B  50      68.770  55.950  80.870  1.00  0.00            
-ATOM   3480  C1'  DA B  50      70.110  56.350  80.640  1.00  0.00            
-ATOM   3481  H1'  DA B  50      70.180  57.430  80.770  1.00  0.00            
-ATOM   3482  N9   DA B  50      70.980  55.680  81.610  1.00  0.00            
-ATOM   3483  C8   DA B  50      71.250  54.340  81.760  1.00  0.00            
-ATOM   3484  H8   DA B  50      70.830  53.590  81.110  1.00  0.00            
-ATOM   3485  N7   DA B  50      72.040  54.050  82.770  1.00  0.00            
-ATOM   3486  C5   DA B  50      72.260  55.330  83.330  1.00  0.00            
-ATOM   3487  C6   DA B  50      72.940  55.820  84.460  1.00  0.00            
-ATOM   3488  N6   DA B  50      73.570  55.040  85.330  1.00  0.00            
-ATOM   3489  H61  DA B  50      74.000  55.470  86.130  1.00  0.00            
-ATOM   3490  H62  DA B  50      73.570  54.060  85.120  1.00  0.00            
-ATOM   3491  N1   DA B  50      72.990  57.110  84.760  1.00  0.00            
-ATOM   3492  C2   DA B  50      72.360  57.960  83.940  1.00  0.00            
-ATOM   3493  H2   DA B  50      72.410  59.010  84.190  1.00  0.00            
-ATOM   3494  N3   DA B  50      71.670  57.660  82.860  1.00  0.00            
-ATOM   3495  C4   DA B  50      71.650  56.320  82.610  1.00  0.00            
-ATOM   3496  C3'  DA B  50      69.120  56.390  78.570  1.00  0.00            
-ATOM   3497  H3'  DA B  50      69.000  55.960  77.580  1.00  0.00            
-ATOM   3498  C2'  DA B  50      70.450  56.010  79.190  1.00  0.00            
-ATOM   3499 1H2'  DA B  50      70.640  54.950  79.060  1.00  0.00            
-ATOM   3500 2H2'  DA B  50      71.270  56.610  78.810  1.00  0.00            
-ATOM   3501  O3'  DA B  50      68.980  57.840  78.530  1.00  0.00            
-ATOM   3502  P    DA B  51      69.780  58.850  77.490  1.00  0.00            
-ATOM   3503  O1P  DA B  51      68.780  59.690  76.790  1.00  0.00            
-ATOM   3504  O2P  DA B  51      70.670  58.010  76.670  1.00  0.00            
-ATOM   3505  O5'  DA B  51      70.770  59.910  78.290  1.00  0.00            
-ATOM   3506  C5'  DA B  51      70.310  61.130  78.890  1.00  0.00            
-ATOM   3507 1H5'  DA B  51      69.560  60.830  79.620  1.00  0.00            
-ATOM   3508 2H5'  DA B  51      69.800  61.730  78.130  1.00  0.00            
-ATOM   3509  C4'  DA B  51      71.330  62.060  79.660  1.00  0.00            
-ATOM   3510  H4'  DA B  51      70.730  62.800  80.180  1.00  0.00            
-ATOM   3511  O4'  DA B  51      71.960  61.260  80.640  1.00  0.00            
-ATOM   3512  C1'  DA B  51      73.300  61.050  80.230  1.00  0.00            
-ATOM   3513  H1'  DA B  51      73.930  61.590  80.940  1.00  0.00            
-ATOM   3514  N9   DA B  51      73.650  59.620  80.300  1.00  0.00            
-ATOM   3515  C8   DA B  51      73.250  58.540  79.540  1.00  0.00            
-ATOM   3516  H8   DA B  51      72.610  58.630  78.670  1.00  0.00            
-ATOM   3517  N7   DA B  51      73.700  57.380  79.950  1.00  0.00            
-ATOM   3518  C5   DA B  51      74.470  57.750  81.070  1.00  0.00            
-ATOM   3519  C6   DA B  51      75.210  57.040  82.030  1.00  0.00            
-ATOM   3520  N6   DA B  51      75.290  55.720  82.080  1.00  0.00            
-ATOM   3521  H61  DA B  51      75.810  55.280  82.820  1.00  0.00            
-ATOM   3522  H62  DA B  51      74.750  55.210  81.400  1.00  0.00            
-ATOM   3523  N1   DA B  51      75.880  57.670  82.990  1.00  0.00            
-ATOM   3524  C2   DA B  51      75.810  59.000  83.030  1.00  0.00            
-ATOM   3525  H2   DA B  51      76.360  59.480  83.820  1.00  0.00            
-ATOM   3526  N3   DA B  51      75.150  59.800  82.220  1.00  0.00            
-ATOM   3527  C4   DA B  51      74.470  59.100  81.260  1.00  0.00            
-ATOM   3528  C3'  DA B  51      72.500  62.830  78.960  1.00  0.00            
-ATOM   3529  H3'  DA B  51      72.200  63.190  77.980  1.00  0.00            
-ATOM   3530  C2'  DA B  51      73.480  61.690  78.860  1.00  0.00            
-ATOM   3531 1H2'  DA B  51      73.190  61.000  78.060  1.00  0.00            
-ATOM   3532 2H2'  DA B  51      74.490  62.050  78.720  1.00  0.00            
-ATOM   3533  O3'  DA B  51      73.060  63.920  79.770  1.00  0.00            
-ATOM   3534  P    DT B  52      74.290  64.940  79.330  1.00  0.00            
-ATOM   3535  O1P  DT B  52      73.980  66.290  79.870  1.00  0.00            
-ATOM   3536  O2P  DT B  52      74.470  64.840  77.860  1.00  0.00            
-ATOM   3537  O5'  DT B  52      75.740  64.520  80.010  1.00  0.00            
-ATOM   3538  C5'  DT B  52      76.180  65.090  81.270  1.00  0.00            
-ATOM   3539 1H5'  DT B  52      75.400  64.850  81.990  1.00  0.00            
-ATOM   3540 2H5'  DT B  52      76.190  66.170  81.160  1.00  0.00            
-ATOM   3541  C4'  DT B  52      77.540  64.660  81.930  1.00  0.00            
-ATOM   3542  H4'  DT B  52      77.510  65.040  82.940  1.00  0.00            
-ATOM   3543  O4'  DT B  52      77.530  63.250  82.030  1.00  0.00            
-ATOM   3544  C1'  DT B  52      78.590  62.730  81.260  1.00  0.00            
-ATOM   3545  H1'  DT B  52      79.390  62.470  81.950  1.00  0.00            
-ATOM   3546  N1   DT B  52      78.150  61.500  80.550  1.00  0.00            
-ATOM   3547  C6   DT B  52      77.370  61.510  79.400  1.00  0.00            
-ATOM   3548  H6   DT B  52      77.030  62.460  78.990  1.00  0.00            
-ATOM   3549  C5   DT B  52      77.000  60.350  78.800  1.00  0.00            
-ATOM   3550  C7   DT B  52      76.210  60.360  77.500  1.00  0.00            
-ATOM   3551  H71  DT B  52      76.020  61.380  77.160  1.00  0.00            
-ATOM   3552  H72  DT B  52      76.780  59.830  76.740  1.00  0.00            
-ATOM   3553  H73  DT B  52      75.270  59.830  77.640  1.00  0.00            
-ATOM   3554  C4   DT B  52      77.360  59.060  79.380  1.00  0.00            
-ATOM   3555  O4   DT B  52      77.040  57.950  78.990  1.00  0.00            
-ATOM   3556  N3   DT B  52      78.120  59.150  80.510  1.00  0.00            
-ATOM   3557  H3   DT B  52      78.400  58.280  80.920  1.00  0.00            
-ATOM   3558  C2   DT B  52      78.580  60.290  81.100  1.00  0.00            
-ATOM   3559  O2   DT B  52      79.360  60.200  82.060  1.00  0.00            
-ATOM   3560  C3'  DT B  52      78.950  65.040  81.360  1.00  0.00            
-ATOM   3561  H3'  DT B  52      78.900  65.990  80.830  1.00  0.00            
-ATOM   3562  C2'  DT B  52      79.120  63.880  80.390  1.00  0.00            
-ATOM   3563 1H2'  DT B  52      78.490  64.030  79.510  1.00  0.00            
-ATOM   3564 2H2'  DT B  52      80.150  63.730  80.100  1.00  0.00            
-ATOM   3565  O3'  DT B  52      79.980  65.070  82.400  1.00  0.00            
-ATOM   3566  P    DG B  53      81.540  65.610  82.260  1.00  0.00            
-ATOM   3567  O1P  DG B  53      81.840  66.420  83.470  1.00  0.00            
-ATOM   3568  O2P  DG B  53      81.680  66.310  80.960  1.00  0.00            
-ATOM   3569  O5'  DG B  53      82.660  64.380  82.270  1.00  0.00            
-ATOM   3570  C5'  DG B  53      83.250  63.880  83.500  1.00  0.00            
-ATOM   3571 1H5'  DG B  53      82.400  63.620  84.140  1.00  0.00            
-ATOM   3572 2H5'  DG B  53      83.760  64.710  83.970  1.00  0.00            
-ATOM   3573  C4'  DG B  53      84.210  62.630  83.540  1.00  0.00            
-ATOM   3574  H4'  DG B  53      84.380  62.430  84.590  1.00  0.00            
-ATOM   3575  O4'  DG B  53      83.480  61.540  83.050  1.00  0.00            
-ATOM   3576  C1'  DG B  53      84.080  61.110  81.840  1.00  0.00            
-ATOM   3577  H1'  DG B  53      84.550  60.130  82.020  1.00  0.00            
-ATOM   3578  N9   DG B  53      83.060  60.930  80.800  1.00  0.00            
-ATOM   3579  C8   DG B  53      82.240  61.840  80.180  1.00  0.00            
-ATOM   3580  H8   DG B  53      82.270  62.900  80.400  1.00  0.00            
-ATOM   3581  N7   DG B  53      81.420  61.320  79.320  1.00  0.00            
-ATOM   3582  C5   DG B  53      81.700  59.940  79.390  1.00  0.00            
-ATOM   3583  C6   DG B  53      81.110  58.780  78.760  1.00  0.00            
-ATOM   3584  O6   DG B  53      80.160  58.710  78.000  1.00  0.00            
-ATOM   3585  N1   DG B  53      81.730  57.600  79.120  1.00  0.00            
-ATOM   3586  H1   DG B  53      81.320  56.760  78.750  1.00  0.00            
-ATOM   3587  C2   DG B  53      82.760  57.520  79.990  1.00  0.00            
-ATOM   3588  N2   DG B  53      83.260  56.350  80.280  1.00  0.00            
-ATOM   3589  H21  DG B  53      82.800  55.520  79.900  1.00  0.00            
-ATOM   3590  H22  DG B  53      83.950  56.310  80.990  1.00  0.00            
-ATOM   3591  N3   DG B  53      83.330  58.540  80.610  1.00  0.00            
-ATOM   3592  C4   DG B  53      82.730  59.720  80.270  1.00  0.00            
-ATOM   3593  C3'  DG B  53      85.620  62.540  82.850  1.00  0.00            
-ATOM   3594  H3'  DG B  53      86.100  63.510  82.820  1.00  0.00            
-ATOM   3595  C2'  DG B  53      85.170  62.110  81.470  1.00  0.00            
-ATOM   3596 1H2'  DG B  53      84.750  62.950  80.920  1.00  0.00            
-ATOM   3597 2H2'  DG B  53      85.980  61.640  80.910  1.00  0.00            
-ATOM   3598  O3'  DG B  53      86.480  61.540  83.480  1.00  0.00            
-ATOM   3599  P    DC B  54      88.050  61.180  83.080  1.00  0.00            
-ATOM   3600  O1P  DC B  54      88.770  60.960  84.360  1.00  0.00            
-ATOM   3601  O2P  DC B  54      88.540  62.290  82.240  1.00  0.00            
-ATOM   3602  O5'  DC B  54      88.200  59.770  82.200  1.00  0.00            
-ATOM   3603  C5'  DC B  54      88.380  58.470  82.810  1.00  0.00            
-ATOM   3604 1H5'  DC B  54      87.580  58.380  83.550  1.00  0.00            
-ATOM   3605 2H5'  DC B  54      89.320  58.470  83.360  1.00  0.00            
-ATOM   3606  C4'  DC B  54      88.310  57.130  81.970  1.00  0.00            
-ATOM   3607  H4'  DC B  54      88.150  56.330  82.700  1.00  0.00            
-ATOM   3608  O4'  DC B  54      87.130  57.190  81.200  1.00  0.00            
-ATOM   3609  C1'  DC B  54      87.440  56.950  79.840  1.00  0.00            
-ATOM   3610  H1'  DC B  54      87.200  55.910  79.600  1.00  0.00            
-ATOM   3611  N1   DC B  54      86.650  57.870  78.990  1.00  0.00            
-ATOM   3612  C6   DC B  54      86.620  59.220  79.240  1.00  0.00            
-ATOM   3613  H6   DC B  54      87.210  59.620  80.050  1.00  0.00            
-ATOM   3614  C5   DC B  54      85.810  60.030  78.500  1.00  0.00            
-ATOM   3615  H5   DC B  54      85.750  61.080  78.700  1.00  0.00            
-ATOM   3616  C4   DC B  54      85.010  59.400  77.510  1.00  0.00            
-ATOM   3617  N4   DC B  54      84.140  60.100  76.850  1.00  0.00            
-ATOM   3618  H41  DC B  54      83.540  59.570  76.200  1.00  0.00            
-ATOM   3619  H42  DC B  54      83.870  61.020  77.110  1.00  0.00            
-ATOM   3620  N3   DC B  54      85.080  58.120  77.240  1.00  0.00            
-ATOM   3621  C2   DC B  54      85.890  57.330  77.960  1.00  0.00            
-ATOM   3622  O2   DC B  54      85.970  56.130  77.680  1.00  0.00            
-ATOM   3623  C3'  DC B  54      89.440  56.590  81.030  1.00  0.00            
-ATOM   3624  H3'  DC B  54      90.410  57.020  81.290  1.00  0.00            
-ATOM   3625  C2'  DC B  54      88.950  57.140  79.690  1.00  0.00            
-ATOM   3626 1H2'  DC B  54      89.210  58.190  79.610  1.00  0.00            
-ATOM   3627 2H2'  DC B  54      89.340  56.570  78.850  1.00  0.00            
-ATOM   3628  O3'  DC B  54      89.510  55.130  81.010  1.00  0.00            
-ATOM   3629  P    DC B  55      90.620  54.220  80.180  1.00  0.00            
-ATOM   3630  O1P  DC B  55      91.050  53.130  81.100  1.00  0.00            
-ATOM   3631  O2P  DC B  55      91.690  55.150  79.740  1.00  0.00            
-ATOM   3632  O5'  DC B  55      89.990  53.500  78.820  1.00  0.00            
-ATOM   3633  C5'  DC B  55      89.300  52.220  78.840  1.00  0.00            
-ATOM   3634 1H5'  DC B  55      88.580  52.270  79.660  1.00  0.00            
-ATOM   3635 2H5'  DC B  55      90.020  51.440  79.090  1.00  0.00            
-ATOM   3636  C4'  DC B  55      88.460  51.710  77.600  1.00  0.00            
-ATOM   3637  H4'  DC B  55      87.750  50.990  78.000  1.00  0.00            
-ATOM   3638  O4'  DC B  55      87.680  52.800  77.150  1.00  0.00            
-ATOM   3639  C1'  DC B  55      87.830  52.950  75.750  1.00  0.00            
-ATOM   3640  H1'  DC B  55      86.960  52.520  75.240  1.00  0.00            
-ATOM   3641  N1   DC B  55      87.930  54.400  75.460  1.00  0.00            
-ATOM   3642  C6   DC B  55      88.820  55.190  76.140  1.00  0.00            
-ATOM   3643  H6   DC B  55      89.470  54.730  76.870  1.00  0.00            
-ATOM   3644  C5   DC B  55      88.850  56.540  75.940  1.00  0.00            
-ATOM   3645  H5   DC B  55      89.520  57.160  76.480  1.00  0.00            
-ATOM   3646  C4   DC B  55      87.910  57.050  75.000  1.00  0.00            
-ATOM   3647  N4   DC B  55      87.810  58.320  74.810  1.00  0.00            
-ATOM   3648  H41  DC B  55      87.030  58.590  74.200  1.00  0.00            
-ATOM   3649  H42  DC B  55      88.240  58.980  75.410  1.00  0.00            
-ATOM   3650  N3   DC B  55      87.090  56.300  74.310  1.00  0.00            
-ATOM   3651  C2   DC B  55      87.060  54.970  74.530  1.00  0.00            
-ATOM   3652  O2   DC B  55      86.260  54.280  73.910  1.00  0.00            
-ATOM   3653  C3'  DC B  55      89.050  51.020  76.320  1.00  0.00            
-ATOM   3654  H3'  DC B  55      90.060  50.640  76.510  1.00  0.00            
-ATOM   3655  C2'  DC B  55      89.080  52.180  75.340  1.00  0.00            
-ATOM   3656 1H2'  DC B  55      89.980  52.780  75.500  1.00  0.00            
-ATOM   3657 2H2'  DC B  55      89.020  51.860  74.300  1.00  0.00            
-ATOM   3658  O3'  DC B  55      88.200  49.940  75.850  1.00  0.00            
-ATOM   3659  P    DA B  56      88.490  48.990  74.530  1.00  0.00            
-ATOM   3660  O1P  DA B  56      88.130  47.600  74.910  1.00  0.00            
-ATOM   3661  O2P  DA B  56      89.900  49.220  74.150  1.00  0.00            
-ATOM   3662  O5'  DA B  56      87.520  49.430  73.250  1.00  0.00            
-ATOM   3663  C5'  DA B  56      86.130  49.030  73.120  1.00  0.00            
-ATOM   3664 1H5'  DA B  56      85.670  49.230  74.090  1.00  0.00            
-ATOM   3665 2H5'  DA B  56      86.090  47.950  72.960  1.00  0.00            
-ATOM   3666  C4'  DA B  56      85.170  49.710  72.060  1.00  0.00            
-ATOM   3667  H4'  DA B  56      84.150  49.530  72.400  1.00  0.00            
-ATOM   3668  O4'  DA B  56      85.390  51.100  72.160  1.00  0.00            
-ATOM   3669  C1'  DA B  56      85.630  51.630  70.870  1.00  0.00            
-ATOM   3670  H1'  DA B  56      84.710  52.090  70.470  1.00  0.00            
-ATOM   3671  N9   DA B  56      86.690  52.640  70.990  1.00  0.00            
-ATOM   3672  C8   DA B  56      87.910  52.510  71.600  1.00  0.00            
-ATOM   3673  H8   DA B  56      88.230  51.570  72.030  1.00  0.00            
-ATOM   3674  N7   DA B  56      88.620  53.610  71.660  1.00  0.00            
-ATOM   3675  C5   DA B  56      87.750  54.530  71.030  1.00  0.00            
-ATOM   3676  C6   DA B  56      87.760  55.920  70.790  1.00  0.00            
-ATOM   3677  N6   DA B  56      88.720  56.730  71.190  1.00  0.00            
-ATOM   3678  H61  DA B  56      88.560  57.720  71.070  1.00  0.00            
-ATOM   3679  H62  DA B  56      89.450  56.340  71.740  1.00  0.00            
-ATOM   3680  N1   DA B  56      86.750  56.540  70.190  1.00  0.00            
-ATOM   3681  C2   DA B  56      85.720  55.820  69.780  1.00  0.00            
-ATOM   3682  H2   DA B  56      84.910  56.350  69.280  1.00  0.00            
-ATOM   3683  N3   DA B  56      85.570  54.510  69.910  1.00  0.00            
-ATOM   3684  C4   DA B  56      86.610  53.940  70.580  1.00  0.00            
-ATOM   3685  C3'  DA B  56      85.180  49.360  70.540  1.00  0.00            
-ATOM   3686  H3'  DA B  56      85.620  48.380  70.360  1.00  0.00            
-ATOM   3687  C2'  DA B  56      86.050  50.470  69.990  1.00  0.00            
-ATOM   3688 1H2'  DA B  56      87.100  50.220  70.140  1.00  0.00            
-ATOM   3689 2H2'  DA B  56      85.850  50.680  68.950  1.00  0.00            
-ATOM   3690  O3'  DA B  56      83.860  49.420  69.940  1.00  0.00            
-ATOM   3691  P    DT B  57      83.530  49.160  68.350  1.00  0.00            
-ATOM   3692  O1P  DT B  57      82.340  48.270  68.290  1.00  0.00            
-ATOM   3693  O2P  DT B  57      84.780  48.630  67.750  1.00  0.00            
-ATOM   3694  O5'  DT B  57      83.150  50.590  67.600  1.00  0.00            
-ATOM   3695  C5'  DT B  57      81.870  51.260  67.710  1.00  0.00            
-ATOM   3696 1H5'  DT B  57      81.640  51.290  68.780  1.00  0.00            
-ATOM   3697 2H5'  DT B  57      81.100  50.650  67.250  1.00  0.00            
-ATOM   3698  C4'  DT B  57      81.700  52.750  67.200  1.00  0.00            
-ATOM   3699  H4'  DT B  57      80.860  53.180  67.750  1.00  0.00            
-ATOM   3700  O4'  DT B  57      82.870  53.440  67.590  1.00  0.00            
-ATOM   3701  C1'  DT B  57      83.400  54.110  66.460  1.00  0.00            
-ATOM   3702  H1'  DT B  57      83.010  55.130  66.430  1.00  0.00            
-ATOM   3703  N1   DT B  57      84.870  54.090  66.550  1.00  0.00            
-ATOM   3704  C6   DT B  57      85.550  52.890  66.680  1.00  0.00            
-ATOM   3705  H6   DT B  57      84.980  51.980  66.670  1.00  0.00            
-ATOM   3706  C5   DT B  57      86.890  52.880  66.900  1.00  0.00            
-ATOM   3707  C7   DT B  57      87.620  51.550  67.030  1.00  0.00            
-ATOM   3708  H71  DT B  57      86.930  50.720  66.850  1.00  0.00            
-ATOM   3709  H72  DT B  57      88.430  51.530  66.300  1.00  0.00            
-ATOM   3710  H73  DT B  57      88.040  51.490  68.030  1.00  0.00            
-ATOM   3711  C4   DT B  57      87.640  54.130  67.030  1.00  0.00            
-ATOM   3712  O4   DT B  57      88.820  54.220  67.340  1.00  0.00            
-ATOM   3713  N3   DT B  57      86.900  55.260  66.790  1.00  0.00            
-ATOM   3714  H3   DT B  57      87.340  56.160  66.860  1.00  0.00            
-ATOM   3715  C2   DT B  57      85.550  55.310  66.550  1.00  0.00            
-ATOM   3716  O2   DT B  57      85.020  56.390  66.350  1.00  0.00            
-ATOM   3717  C3'  DT B  57      81.450  53.110  65.700  1.00  0.00            
-ATOM   3718  H3'  DT B  57      80.980  52.300  65.160  1.00  0.00            
-ATOM   3719  C2'  DT B  57      82.880  53.350  65.250  1.00  0.00            
-ATOM   3720 1H2'  DT B  57      83.380  52.390  65.110  1.00  0.00            
-ATOM   3721 2H2'  DT B  57      82.930  53.950  64.350  1.00  0.00            
-ATOM   3722  O3'  DT B  57      80.690  54.340  65.530  1.00  0.00            
-ATOM   3723  P    DC B  58      80.230  54.970  64.070  1.00  0.00            
-ATOM   3724  O1P  DC B  58      78.760  55.150  64.090  1.00  0.00            
-ATOM   3725  O2P  DC B  58      80.790  54.060  63.040  1.00  0.00            
-ATOM   3726  O5'  DC B  58      80.920  56.450  63.820  1.00  0.00            
-ATOM   3727  C5'  DC B  58      80.480  57.670  64.450  1.00  0.00            
-ATOM   3728 1H5'  DC B  58      80.460  57.440  65.520  1.00  0.00            
-ATOM   3729 2H5'  DC B  58      79.450  57.870  64.150  1.00  0.00            
-ATOM   3730  C4'  DC B  58      81.340  58.980  64.300  1.00  0.00            
-ATOM   3731  H4'  DC B  58      81.000  59.670  65.060  1.00  0.00            
-ATOM   3732  O4'  DC B  58      82.670  58.600  64.600  1.00  0.00            
-ATOM   3733  C1'  DC B  58      83.460  58.770  63.450  1.00  0.00            
-ATOM   3734  H1'  DC B  58      84.030  59.700  63.590  1.00  0.00            
-ATOM   3735  N1   DC B  58      84.390  57.620  63.290  1.00  0.00            
-ATOM   3736  C6   DC B  58      83.950  56.360  62.950  1.00  0.00            
-ATOM   3737  H6   DC B  58      82.900  56.190  62.740  1.00  0.00            
-ATOM   3738  C5   DC B  58      84.820  55.320  62.910  1.00  0.00            
-ATOM   3739  H5   DC B  58      84.470  54.340  62.670  1.00  0.00            
-ATOM   3740  C4   DC B  58      86.170  55.610  63.240  1.00  0.00            
-ATOM   3741  N4   DC B  58      87.050  54.660  63.330  1.00  0.00            
-ATOM   3742  H41  DC B  58      87.990  54.950  63.580  1.00  0.00            
-ATOM   3743  H42  DC B  58      86.780  53.720  63.130  1.00  0.00            
-ATOM   3744  N3   DC B  58      86.620  56.810  63.510  1.00  0.00            
-ATOM   3745  C2   DC B  58      85.740  57.830  63.530  1.00  0.00            
-ATOM   3746  O2   DC B  58      86.200  58.960  63.700  1.00  0.00            
-ATOM   3747  C3'  DC B  58      81.430  59.810  62.970  1.00  0.00            
-ATOM   3748  H3'  DC B  58      80.490  59.780  62.420  1.00  0.00            
-ATOM   3749  C2'  DC B  58      82.510  59.000  62.280  1.00  0.00            
-ATOM   3750 1H2'  DC B  58      82.090  58.080  61.890  1.00  0.00            
-ATOM   3751 2H2'  DC B  58      82.980  59.590  61.500  1.00  0.00            
-ATOM   3752  O3'  DC B  58      81.890  61.190  63.140  1.00  0.00            
-ATOM   3753  P    DT B  59      82.110  62.290  61.920  1.00  0.00            
-ATOM   3754  O1P  DT B  59      81.510  63.590  62.340  1.00  0.00            
-ATOM   3755  O2P  DT B  59      81.620  61.690  60.670  1.00  0.00            
-ATOM   3756  O5'  DT B  59      83.710  62.610  61.670  1.00  0.00            
-ATOM   3757  C5'  DT B  59      84.420  63.660  62.360  1.00  0.00            
-ATOM   3758 1H5'  DT B  59      84.340  63.430  63.430  1.00  0.00            
-ATOM   3759 2H5'  DT B  59      83.880  64.590  62.200  1.00  0.00            
-ATOM   3760  C4'  DT B  59      85.940  63.900  62.050  1.00  0.00            
-ATOM   3761  H4'  DT B  59      86.320  64.510  62.870  1.00  0.00            
-ATOM   3762  O4'  DT B  59      86.580  62.640  62.120  1.00  0.00            
-ATOM   3763  C1'  DT B  59      87.020  62.300  60.820  1.00  0.00            
-ATOM   3764  H1'  DT B  59      88.100  62.480  60.810  1.00  0.00            
-ATOM   3765  N1   DT B  59      86.770  60.860  60.530  1.00  0.00            
-ATOM   3766  C6   DT B  59      85.530  60.360  60.150  1.00  0.00            
-ATOM   3767  H6   DT B  59      84.680  61.020  60.060  1.00  0.00            
-ATOM   3768  C5   DT B  59      85.370  59.030  59.910  1.00  0.00            
-ATOM   3769  C7   DT B  59      84.050  58.480  59.390  1.00  0.00            
-ATOM   3770  H71  DT B  59      83.310  59.270  59.270  1.00  0.00            
-ATOM   3771  H72  DT B  59      84.220  58.000  58.430  1.00  0.00            
-ATOM   3772  H73  DT B  59      83.680  57.720  60.080  1.00  0.00            
-ATOM   3773  C4   DT B  59      86.460  58.090  60.130  1.00  0.00            
-ATOM   3774  O4   DT B  59      86.420  56.870  60.040  1.00  0.00            
-ATOM   3775  N3   DT B  59      87.650  58.680  60.470  1.00  0.00            
-ATOM   3776  H3   DT B  59      88.440  58.080  60.590  1.00  0.00            
-ATOM   3777  C2   DT B  59      87.880  60.020  60.600  1.00  0.00            
-ATOM   3778  O2   DT B  59      89.040  60.420  60.720  1.00  0.00            
-ATOM   3779  C3'  DT B  59      86.420  64.560  60.720  1.00  0.00            
-ATOM   3780  H3'  DT B  59      85.690  65.290  60.360  1.00  0.00            
-ATOM   3781  C2'  DT B  59      86.420  63.320  59.850  1.00  0.00            
-ATOM   3782 1H2'  DT B  59      85.400  63.060  59.570  1.00  0.00            
-ATOM   3783 2H2'  DT B  59      87.050  63.450  58.980  1.00  0.00            
-ATOM   3784  O3'  DT B  59      87.760  65.150  60.790  1.00  0.00            
-ATOM   3785  P    DT B  60      88.540  65.970  59.580  1.00  0.00            
-ATOM   3786  O1P  DT B  60      89.210  67.150  60.200  1.00  0.00            
-ATOM   3787  O2P  DT B  60      87.560  66.260  58.510  1.00  0.00            
-ATOM   3788  O5'  DT B  60      89.760  65.090  58.880  1.00  0.00            
-ATOM   3789  C5'  DT B  60      91.130  65.150  59.350  1.00  0.00            
-ATOM   3790 1H5'  DT B  60      91.080  64.940  60.420  1.00  0.00            
-ATOM   3791 2H5'  DT B  60      91.470  66.180  59.250  1.00  0.00            
-ATOM   3792  C4'  DT B  60      92.240  64.200  58.770  1.00  0.00            
-ATOM   3793  H4'  DT B  60      93.080  64.270  59.460  1.00  0.00            
-ATOM   3794  O4'  DT B  60      91.720  62.890  58.880  1.00  0.00            
-ATOM   3795  C1'  DT B  60      91.670  62.320  57.600  1.00  0.00            
-ATOM   3796  H1'  DT B  60      92.530  61.650  57.510  1.00  0.00            
-ATOM   3797  N1   DT B  60      90.420  61.530  57.440  1.00  0.00            
-ATOM   3798  C6   DT B  60      89.180  62.120  57.260  1.00  0.00            
-ATOM   3799  H6   DT B  60      89.080  63.190  57.270  1.00  0.00            
-ATOM   3800  C5   DT B  60      88.060  61.350  57.080  1.00  0.00            
-ATOM   3801  C7   DT B  60      86.720  61.990  56.780  1.00  0.00            
-ATOM   3802  H71  DT B  60      86.790  63.070  56.730  1.00  0.00            
-ATOM   3803  H72  DT B  60      86.360  61.600  55.830  1.00  0.00            
-ATOM   3804  H73  DT B  60      86.000  61.690  57.550  1.00  0.00            
-ATOM   3805  C4   DT B  60      88.150  59.890  57.160  1.00  0.00            
-ATOM   3806  O4   DT B  60      87.210  59.110  57.090  1.00  0.00            
-ATOM   3807  N3   DT B  60      89.410  59.410  57.360  1.00  0.00            
-ATOM   3808  H3   DT B  60      89.510  58.400  57.370  1.00  0.00            
-ATOM   3809  C2   DT B  60      90.560  60.140  57.420  1.00  0.00            
-ATOM   3810  O2   DT B  60      91.650  59.570  57.410  1.00  0.00            
-ATOM   3811  C3'  DT B  60      92.840  64.330  57.330  1.00  0.00            
-ATOM   3812  H3'  DT B  60      92.780  65.360  56.980  1.00  0.00            
-ATOM   3813  C2'  DT B  60      91.870  63.450  56.590  1.00  0.00            
-ATOM   3814 1H2'  DT B  60      90.940  63.990  56.400  1.00  0.00            
-ATOM   3815 2H2'  DT B  60      92.300  63.070  55.660  1.00  0.00            
-ATOM   3816  O3'  DT B  60      94.210  63.820  57.200  1.00  0.00            
-TER                  
-ENDMDL
index 292e20222223c53041435b242a4c13fbc6011636..af63fc601edb6c7e4e500e90c116909111459c07 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -94,7 +94,7 @@ public:
         ASSERT_EQ(0, gmx_editconf(cmdline.argc(), cmdline.argv()));
 
         // Check the output
-        auto                 extension = ftp2ext(std::get<1>(GetParam()));
+        const auto*          extension = ftp2ext(std::get<1>(GetParam()));
         TestReferenceChecker rootChecker(this->rootChecker());
         rootChecker.checkString(extension, testName);
         checkOutputFiles();
index 1c1f1a909cde64d7b80e340768259debd0d1b1eb..99c7b888b63e214fcbbc8136e8b8be1ed9b2807c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,20 +124,20 @@ TEST_F(PreprocessingAtomTypesTest, CorrectNameFound)
 TEST_F(PreprocessingAtomTypesTest, WrongNameNotFound)
 {
     EXPECT_EQ(addType("Foo", 1, 2), 0);
-    EXPECT_EQ(atypes_.atomTypeFromName("Bar"), NOTSET);
+    EXPECT_FALSE(atypes_.atomTypeFromName("Bar").has_value());
 }
 
 TEST_F(PreprocessingAtomTypesTest, CorrectNameFromTypeNumber)
 {
     EXPECT_EQ(addType("Foo", 1, 2), 0);
     EXPECT_EQ(addType("Bar", 3, 4), 1);
-    EXPECT_STREQ(atypes_.atomNameFromAtomType(0), "Foo");
-    EXPECT_STREQ(atypes_.atomNameFromAtomType(1), "Bar");
+    EXPECT_STREQ(*atypes_.atomNameFromAtomType(0), "Foo");
+    EXPECT_STREQ(*atypes_.atomNameFromAtomType(1), "Bar");
 }
 
 TEST_F(PreprocessingAtomTypesTest, NoNameFromIncorrectTypeNumber)
 {
-    EXPECT_EQ(atypes_.atomNameFromAtomType(-1), nullptr);
+    EXPECT_FALSE(atypes_.atomNameFromAtomType(-1).has_value());
 }
 
 } // namespace
index 1f15b41d7dd03371fda2eed6e63c167ac236463e..3ed0452f560a9a6ac2371a478c03b0e35400ca2f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -135,18 +135,18 @@ TEST_F(PreprocessingBondAtomTypeTest, CorrectNameFound)
 TEST_F(PreprocessingBondAtomTypeTest, WrongNameNotFound)
 {
     EXPECT_EQ(addType("Foo"), 0);
-    EXPECT_EQ(bat_.bondAtomTypeFromName("Bar"), NOTSET);
+    EXPECT_FALSE(bat_.bondAtomTypeFromName("Bar").has_value());
 }
 
 TEST_F(PreprocessingBondAtomTypeTest, CorrectNameFromTypeNumber)
 {
     EXPECT_EQ(addType("Foo"), 0);
     EXPECT_EQ(addType("Bar"), 1);
-    EXPECT_STREQ(bat_.atomNameFromBondAtomType(0), "Foo");
-    EXPECT_STREQ(bat_.atomNameFromBondAtomType(1), "Bar");
+    EXPECT_STREQ(*bat_.atomNameFromBondAtomType(0), "Foo");
+    EXPECT_STREQ(*bat_.atomNameFromBondAtomType(1), "Bar");
 }
 
 TEST_F(PreprocessingBondAtomTypeTest, NoNameFromIncorrectTypeNumber)
 {
-    EXPECT_EQ(bat_.atomNameFromBondAtomType(-1), nullptr);
+    EXPECT_FALSE(bat_.atomNameFromBondAtomType(-1).has_value());
 }
index 53cf3080eae7c6dc991f9d3ae07e486bef3e20b3..97909b736f2e3c867485774e4c0aa7d08199930d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015,2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +66,9 @@ public:
         gmx::test::TestReferenceChecker rootChecker(this->rootChecker());
         rootChecker.checkString(args.toString(), "CommandLine");
 
-        ASSERT_EQ(0, gmx::test::CommandLineTestHelper::runModuleFactory(
-                             &gmx::InsertMoleculesInfo::create, &cmdline));
+        ASSERT_EQ(0,
+                  gmx::test::CommandLineTestHelper::runModuleFactory(
+                          &gmx::InsertMoleculesInfo::create, &cmdline));
 
         checkOutputFiles();
     }
@@ -109,8 +110,9 @@ TEST_F(InsertMoleculesTest, InsertsMoleculesWithReplacement)
 TEST_F(InsertMoleculesTest, InsertsMoleculesIntoFixedPositions)
 {
     const char* const cmdline[]   = { "insert-molecules", "-box", "4", "-seed", "1997" };
-    const char* const positions[] = { "0.0  0.0  0.0", "1.0  2.0  3.0", "0.99 2.01 3.0",
-                                      "2.0  1.0  2.0" };
+    const char* const positions[] = {
+        "0.0  0.0  0.0", "1.0  2.0  3.0", "0.99 2.01 3.0", "2.0  1.0  2.0"
+    };
     setInputFile("-ci", "x0.gro");
     setInputFileContents("-ip", "dat", positions);
     runTest(CommandLine(cmdline));
index e2591c7392a193e6b3e28a3671d477882fda26da..af1b9b967a6a5b0230afd5b6112c42be6d777075 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -94,10 +94,9 @@ public:
 
         TextWriter::writeFileFromString(inputMdpFilename, inputMdpFileContents);
 
-        get_ir(inputMdpFilename.c_str(), outputMdpFilename.c_str(), &mdModules_, &ir_, &opts_,
-               WriteMdpHeader::no, wi_);
+        get_ir(inputMdpFilename.c_str(), outputMdpFilename.c_str(), &mdModules_, &ir_, &opts_, WriteMdpHeader::no, wi_);
 
-        check_ir(inputMdpFilename.c_str(), mdModules_.notifier(), &ir_, &opts_, wi_);
+        check_ir(inputMdpFilename.c_str(), mdModules_.notifiers(), &ir_, &opts_, wi_);
         // Now check
         bool                 failure = warning_errors_exist(wi_);
         TestReferenceData    data;
index 62ebe479c89637c1b128b6a320409c471755a7fe..58d37a7ef6f119eb138a5f35959dbfe07819727e 100644 (file)
@@ -260,8 +260,6 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
-acc-grps                 = 
-accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index 773cc6ea53208a523a5b69aec4247d4759db2f76..8dd09198038c2c3f2e7e52e9678a9af7617dfd64 100644 (file)
@@ -260,8 +260,6 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
-acc-grps                 = 
-accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index 569e772e5555c8e4f85d96807c6bde033602cff6..bbefcc9748f75a82ba1dd2220588a9852dcc8862 100644 (file)
@@ -260,8 +260,6 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
-acc-grps                 = 
-accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index 021975538da9f1f2fbe3f7c584e233ffba959548..8b21cdf5efd01f4a5fa5450a906bc491529b05f3 100644 (file)
@@ -260,8 +260,6 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
-acc-grps                 = 
-accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index 216f7dcd692be0738678090b75862b09f11d974a..72c39c0c0e3ea041031f2ce4b466e8babfc3c0db 100644 (file)
@@ -260,8 +260,6 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
-acc-grps                 = 
-accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index 216f7dcd692be0738678090b75862b09f11d974a..72c39c0c0e3ea041031f2ce4b466e8babfc3c0db 100644 (file)
@@ -260,8 +260,6 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
-acc-grps                 = 
-accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index 216f7dcd692be0738678090b75862b09f11d974a..72c39c0c0e3ea041031f2ce4b466e8babfc3c0db 100644 (file)
@@ -260,8 +260,6 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
-acc-grps                 = 
-accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index 3aa77677fdf067d952583e929602d1c11975583a..40e229819f3e95b7b1ad04337abfcdd1b7e5ff25 100644 (file)
@@ -260,8 +260,6 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
-acc-grps                 = 
-accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index 52c2a1f4f71d6c2eb55efe93b31f93828744a47e..ed1446672ab540bf08685327b1144f900e675920 100644 (file)
@@ -260,8 +260,6 @@ dh_hist_size             = 0
 dh_hist_spacing          = 0.1
 
 ; Non-equilibrium MD stuff
-acc-grps                 = 
-accelerate               = 
 freezegrps               = 
 freezedim                = 
 cos-acceleration         = 0
index cd1fa35119ba87e165bb665bbe115c6ab7d63058..281b3e37661e872929baf42db5ba74b1d800a309 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ TEST(TopDirTests, NamesArrayHasCorrectSize)
         // If the enumeration is extended, but there is no matching
         // name, then at least one element will be value initialized,
         // ie. to nullptr, which this test will catch.
-        auto name = dir2str(d);
+        const auto* name = enumValueToString(d);
         EXPECT_NE(name, nullptr);
     }
 }
index f49f44ec20e132beb34434613fb69fb173a972aa..ed1059196635dc72f585c5bdc3d1a593f11812ee 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -218,9 +218,10 @@ void convert_harmonics(gmx::ArrayRef<MoleculeInformation> mols, PreprocessingAto
                 {
                     int  ni   = harmonic->ai();
                     int  nj   = harmonic->aj();
-                    real edis = search_e_diss(n2m, t2m,
-                                              atype->atomNameFromAtomType(mol.atoms.atom[ni].type),
-                                              atype->atomNameFromAtomType(mol.atoms.atom[nj].type));
+                    real edis = search_e_diss(n2m,
+                                              t2m,
+                                              *atype->atomNameFromAtomType(mol.atoms.atom[ni].type),
+                                              *atype->atomNameFromAtomType(mol.atoms.atom[nj].type));
                     if (edis != 0)
                     {
                         real              b0         = harmonic->c0();
@@ -239,8 +240,12 @@ void convert_harmonics(gmx::ArrayRef<MoleculeInformation> mols, PreprocessingAto
                 }
 
                 int newHarmonics = mol.interactions[bb].size();
-                fprintf(stderr, "Converted %d out of %d %s to morse bonds for mol %d\n",
-                        nrharm - newHarmonics, nrharm, interaction_function[bb].name, i);
+                fprintf(stderr,
+                        "Converted %d out of %d %s to morse bonds for mol %d\n",
+                        nrharm - newHarmonics,
+                        nrharm,
+                        interaction_function[bb].name,
+                        i);
             }
         }
         i++;
index 36c27ceb647fe620ae0f536b2984db8cfdc67aaa..4d1a3292edc417719b48133be3d7e12914fd27c9 100644 (file)
 #include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringtoenumvalueconverter.h"
 
-/* Must correspond to the Directive enum in grompp_impl.h */
-static gmx::EnumerationArray<Directive, const char*> directive_names = {
-    { "defaults", "atomtypes", "bondtypes", "constrainttypes", "pairtypes", "angletypes",
-      "dihedraltypes", "nonbond_params", "implicit_genborn_params", "implicit_surface_params",
-      "cmaptypes",
-      /* All the directives above can not appear after moleculetype */
-      "moleculetype", "atoms", "virtual_sites1", "virtual_sites2", "virtual_sites3",
-      "virtual_sites4", "virtual_sitesn", "bonds", "exclusions", "pairs", "pairs_nb", "angles",
-      "dihedrals", "constraints", "settles", "polarization", "water_polarization",
-      "thole_polarization", "system", "molecules", "position_restraints", "angle_restraints",
-      "angle_restraints_z", "distance_restraints", "orientation_restraints", "dihedral_restraints",
-      "cmap", "intermolecular_interactions", "maxdirs", "invalid", "none" }
-};
+const char* enumValueToString(Directive d)
+{
+    /* Must correspond to the Directive enum in topdirs.h */
+    static constexpr gmx::EnumerationArray<Directive, const char*> directiveNames = {
+        "defaults",
+        "atomtypes",
+        "bondtypes",
+        "constrainttypes",
+        "pairtypes",
+        "angletypes",
+        "dihedraltypes",
+        "nonbond_params",
+        "implicit_genborn_params",
+        "implicit_surface_params",
+        "cmaptypes",
+        /* All the directives above can not appear after moleculetype */
+        "moleculetype",
+        "atoms",
+        "virtual_sites1",
+        "virtual_sites2",
+        "virtual_sites3",
+        "virtual_sites4",
+        "virtual_sitesn",
+        "bonds",
+        "exclusions",
+        "pairs",
+        "pairs_nb",
+        "angles",
+        "dihedrals",
+        "constraints",
+        "settles",
+        "polarization",
+        "water_polarization",
+        "thole_polarization",
+        "system",
+        "molecules",
+        "position_restraints",
+        "angle_restraints",
+        "angle_restraints_z",
+        "distance_restraints",
+        "orientation_restraints",
+        "dihedral_restraints",
+        "cmap",
+        "intermolecular_interactions",
+        "maxdirs",
+        "invalid",
+        "none"
+    };
+    return directiveNames[d];
+}
 
 int ifunc_index(Directive d, int type)
 {
@@ -206,42 +244,54 @@ int ifunc_index(Directive d, int type)
         case Directive::d_orientation_restraints: return F_ORIRES;
         case Directive::d_dihedral_restraints: return F_DIHRES;
         default:
-            gmx_fatal(FARGS, "invalid directive %s in ifunc_index (%s:%d)", dir2str(d), __FILE__, __LINE__);
+            gmx_fatal(FARGS, "invalid directive %s in ifunc_index (%s:%d)", enumValueToString(d), __FILE__, __LINE__);
     }
 }
 
-const char* dir2str(Directive d)
+enum class DeprecatedDirectives : int
+{
+    d_dummies1,
+    d_dummies2,
+    d_dummies3,
+    d_dummies4,
+    d_dummiesn,
+    Count
+};
+
+static const char* enumValueToString(DeprecatedDirectives d)
 {
-    int index = static_cast<int>(d);
-    return directive_names[index];
+    static constexpr gmx::EnumerationArray<DeprecatedDirectives, const char*> directiveNames = {
+        "dummies1", "dummies2", "dummies3", "dummies4", "dummiesn"
+    };
+    return directiveNames[d];
 }
 
 Directive str2dir(char* dstr)
 {
-    char buf[STRLEN], *ptr;
+    static const gmx::StringToEnumValueConverter<Directive, enumValueToString, gmx::StringCompareType::CaseAndDashInsensitive> s_converter;
 
-    /* Hack to be able to read old topologies */
-    if (gmx_strncasecmp_min(dstr, "dummies", 7) == 0)
+    if (std::optional<Directive> d = s_converter.valueFrom(dstr); d.has_value())
     {
-        sprintf(buf, "virtual_sites%s", dstr + 7);
-        ptr = buf;
-    }
-    else
-    {
-        ptr = dstr;
+        return d.value();
     }
+    // Also handle deprecated directives that have modern replacements, like
+    // "dummies*" -> "virtual_sites*"
+
+    static const gmx::StringToEnumValueConverter<DeprecatedDirectives, enumValueToString, gmx::StringCompareType::CaseAndDashInsensitive>
+            s_converterForDeprecated;
 
-    for (auto d : gmx::EnumerationWrapper<Directive>())
+    if (std::optional<DeprecatedDirectives> d = s_converterForDeprecated.valueFrom(dstr); d.has_value())
     {
-        if (gmx_strcasecmp_min(ptr, dir2str(static_cast<Directive>(d))) == 0)
-        {
-            return static_cast<Directive>(d);
-        }
+        static constexpr gmx::EnumerationArray<DeprecatedDirectives, Directive> s_deprecatedDirectiveToDirective = {
+            Directive::d_vsites1, Directive::d_vsites2, Directive::d_vsites3,
+            Directive::d_vsites4, Directive::d_vsitesn,
+        };
+        return s_deprecatedDirectiveToDirective[d.value()];
     }
-
     return Directive::d_invalid;
 }
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static gmx::EnumerationArray<Directive, Directive*> necessary = { { nullptr } };
 
 static void set_nec(Directive** n, ...)
@@ -280,10 +330,8 @@ void DS_Init(DirStack** DS)
         // be in the same place that was valid in old versions (ie. child
         // directive of [atomtypes]) but any relevant case will
         // satisfy that.
-        set_nec(&(necessary[Directive::d_implicit_genborn_params]), Directive::d_atomtypes,
-                Directive::d_none);
-        set_nec(&(necessary[Directive::d_implicit_surface_params]), Directive::d_atomtypes,
-                Directive::d_none);
+        set_nec(&(necessary[Directive::d_implicit_genborn_params]), Directive::d_atomtypes, Directive::d_none);
+        set_nec(&(necessary[Directive::d_implicit_surface_params]), Directive::d_atomtypes, Directive::d_none);
         set_nec(&(necessary[Directive::d_cmaptypes]), Directive::d_atomtypes, Directive::d_none);
         set_nec(&(necessary[Directive::d_moleculetype]), Directive::d_atomtypes, Directive::d_none);
         set_nec(&(necessary[Directive::d_atoms]), Directive::d_moleculetype, Directive::d_none);
@@ -293,8 +341,11 @@ void DS_Init(DirStack** DS)
         set_nec(&(necessary[Directive::d_vsites4]), Directive::d_atoms, Directive::d_none);
         set_nec(&(necessary[Directive::d_vsitesn]), Directive::d_atoms, Directive::d_none);
         set_nec(&(necessary[Directive::d_bonds]), Directive::d_atoms, Directive::d_none);
-        set_nec(&(necessary[Directive::d_exclusions]), Directive::d_bonds, Directive::d_constraints,
-                Directive::d_settles, Directive::d_none);
+        set_nec(&(necessary[Directive::d_exclusions]),
+                Directive::d_bonds,
+                Directive::d_constraints,
+                Directive::d_settles,
+                Directive::d_none);
         set_nec(&(necessary[Directive::d_pairs]), Directive::d_atoms, Directive::d_none);
         set_nec(&(necessary[Directive::d_pairs_nb]), Directive::d_atoms, Directive::d_none);
         set_nec(&(necessary[Directive::d_angles]), Directive::d_atoms, Directive::d_none);
@@ -313,7 +364,8 @@ void DS_Init(DirStack** DS)
         set_nec(&(necessary[Directive::d_orientation_restraints]), Directive::d_atoms, Directive::d_none);
         set_nec(&(necessary[Directive::d_dihedral_restraints]), Directive::d_atoms, Directive::d_none);
         set_nec(&(necessary[Directive::d_cmap]), Directive::d_atoms, Directive::d_none);
-        set_nec(&(necessary[Directive::d_intermolecular_interactions]), Directive::d_molecules,
+        set_nec(&(necessary[Directive::d_intermolecular_interactions]),
+                Directive::d_molecules,
                 Directive::d_none);
     }
     *DS = nullptr;
index 202cd23b11ef3d5b2ff5526f54c7c28294b6fec2..d904e6fcd1b4f005c636702b7420fc020c995952 100644 (file)
@@ -86,6 +86,8 @@ enum class Directive : int
     Count
 };
 
+const char* enumValueToString(Directive d);
+
 struct DirStack
 {
     Directive d;
@@ -94,8 +96,6 @@ struct DirStack
 
 int ifunc_index(Directive d, int type);
 
-const char* dir2str(Directive d);
-
 Directive str2dir(char* dstr);
 
 void DS_Init(DirStack** DS);
index 7c7343a7018df5fc023e34d340a0f94761d61bad..42cfc075836347fa21d5c110ccd1d7fd1822d5b5 100644 (file)
@@ -37,6 +37,8 @@
  */
 #include "gmxpre.h"
 
+#include "gromacs/utility/enumerationhelpers.h"
+#include "gromacs/utility/stringutil.h"
 #include "topio.h"
 
 #include <cassert>
@@ -87,7 +89,7 @@
 #define OPENDIR '['  /* starting sign for directive */
 #define CLOSEDIR ']' /* ending sign for directive   */
 
-static void gen_pairs(const InteractionsOfType& nbs, InteractionsOfType* pairs, real fudge, int comb)
+static void gen_pairs(const InteractionsOfType& nbs, InteractionsOfType* pairs, real fudge, CombinationRule comb)
 {
     real scaling;
     int  ntp = nbs.size();
@@ -122,7 +124,8 @@ static void gen_pairs(const InteractionsOfType& nbs, InteractionsOfType* pairs,
              * should be scaled, but not sigma.
              * The sigma values have even indices 0,2, etc.
              */
-            if ((comb == eCOMB_ARITHMETIC || comb == eCOMB_GEOM_SIG_EPS) && (j % 2 == 0))
+            if ((comb == CombinationRule::Arithmetic || comb == CombinationRule::GeomSigEps)
+                && (j % 2 == 0))
             {
                 scaling = 1.0;
             }
@@ -142,7 +145,7 @@ static void gen_pairs(const InteractionsOfType& nbs, InteractionsOfType* pairs,
 double check_mol(const gmx_mtop_t* mtop, warninp* wi)
 {
     char   buf[256];
-    int    i, ri, pt;
+    int    i, ri;
     double q;
     real   m, mB;
 
@@ -155,27 +158,36 @@ double check_mol(const gmx_mtop_t* mtop, warninp* wi)
         for (i = 0; (i < atoms->nr); i++)
         {
             q += molb.nmol * atoms->atom[i].q;
-            m  = atoms->atom[i].m;
-            mB = atoms->atom[i].mB;
-            pt = atoms->atom[i].ptype;
+            m               = atoms->atom[i].m;
+            mB              = atoms->atom[i].mB;
+            ParticleType pt = atoms->atom[i].ptype;
             /* If the particle is an atom or a nucleus it must have a mass,
              * else, if it is a shell, a vsite or a bondshell it can have mass zero
              */
-            if (((m <= 0.0) || (mB <= 0.0)) && ((pt == eptAtom) || (pt == eptNucleus)))
+            if (((m <= 0.0) || (mB <= 0.0)) && ((pt == ParticleType::Atom) || (pt == ParticleType::Nucleus)))
             {
                 ri = atoms->atom[i].resind;
-                sprintf(buf, "atom %s (Res %s-%d) has mass %g (state A) / %g (state B)\n",
-                        *(atoms->atomname[i]), *(atoms->resinfo[ri].name), atoms->resinfo[ri].nr, m, mB);
+                sprintf(buf,
+                        "atom %s (Res %s-%d) has mass %g (state A) / %g (state B)\n",
+                        *(atoms->atomname[i]),
+                        *(atoms->resinfo[ri].name),
+                        atoms->resinfo[ri].nr,
+                        m,
+                        mB);
                 warning_error(wi, buf);
             }
-            else if (((m != 0) || (mB != 0)) && (pt == eptVSite))
+            else if (((m != 0) || (mB != 0)) && (pt == ParticleType::VSite))
             {
                 ri = atoms->atom[i].resind;
                 sprintf(buf,
                         "virtual site %s (Res %s-%d) has non-zero mass %g (state A) / %g (state "
                         "B)\n"
                         "     Check your topology.\n",
-                        *(atoms->atomname[i]), *(atoms->resinfo[ri].name), atoms->resinfo[ri].nr, m, mB);
+                        *(atoms->atomname[i]),
+                        *(atoms->resinfo[ri].name),
+                        atoms->resinfo[ri].nr,
+                        m,
+                        mB);
                 warning_error(wi, buf);
                 /* The following statements make LINCS break! */
                 /* atoms->atom[i].m=0; */
@@ -238,55 +250,69 @@ static void sum_q(const t_atoms* atoms, int numMols, double* qTotA, double* qTot
     *qTotB += numMols * roundedMoleculeCharge(qmolB, sumAbsQB);
 }
 
-static void get_nbparm(char* nb_str, char* comb_str, int* nb, int* comb, warninp* wi)
+static void get_nbparm(char* nb_str, char* comb_str, VanDerWaalsPotential* nb, CombinationRule* comb, warninp* wi)
 {
-    int  i;
-    char warn_buf[STRLEN];
-
-    *nb = -1;
-    for (i = 1; (i < eNBF_NR); i++)
+    *nb = VanDerWaalsPotential::Count;
+    for (auto i : gmx::EnumerationArray<VanDerWaalsPotential, bool>::keys())
     {
-        if (gmx_strcasecmp(nb_str, enbf_names[i]) == 0)
+        if (gmx_strcasecmp(nb_str, enumValueToString(i)) == 0)
         {
             *nb = i;
         }
     }
-    if (*nb == -1)
+    if (*nb == VanDerWaalsPotential::Count)
     {
-        *nb = strtol(nb_str, nullptr, 10);
-    }
-    if ((*nb < 1) || (*nb >= eNBF_NR))
-    {
-        sprintf(warn_buf, "Invalid nonbond function selector '%s' using %s", nb_str, enbf_names[1]);
-        warning_error(wi, warn_buf);
-        *nb = 1;
+        int integerValue = strtol(nb_str, nullptr, 10);
+        if ((integerValue < 1) || (integerValue >= static_cast<int>(VanDerWaalsPotential::Count)))
+        {
+            std::string message =
+                    gmx::formatString("Invalid nonbond function selector '%s' using %s",
+                                      nb_str,
+                                      enumValueToString(VanDerWaalsPotential::LJ));
+            warning_error(wi, message);
+            *nb = VanDerWaalsPotential::LJ;
+        }
+        else
+        {
+            *nb = static_cast<VanDerWaalsPotential>(integerValue);
+        }
     }
-    *comb = -1;
-    for (i = 1; (i < eCOMB_NR); i++)
+    *comb = CombinationRule::Count;
+    for (auto i : gmx::EnumerationArray<CombinationRule, bool>::keys())
     {
-        if (gmx_strcasecmp(comb_str, ecomb_names[i]) == 0)
+        if (gmx_strcasecmp(comb_str, enumValueToString(i)) == 0)
         {
             *comb = i;
         }
     }
-    if (*comb == -1)
-    {
-        *comb = strtol(comb_str, nullptr, 10);
-    }
-    if ((*comb < 1) || (*comb >= eCOMB_NR))
+    if (*comb == CombinationRule::Count)
     {
-        sprintf(warn_buf, "Invalid combination rule selector '%s' using %s", comb_str, ecomb_names[1]);
-        warning_error(wi, warn_buf);
-        *comb = 1;
+        int integerValue = strtol(comb_str, nullptr, 10);
+        if ((integerValue < 1) || (integerValue >= static_cast<int>(CombinationRule::Count)))
+        {
+            std::string message =
+                    gmx::formatString("Invalid combination rule selector '%s' using %s",
+                                      comb_str,
+                                      enumValueToString(CombinationRule::Geometric));
+            warning_error(wi, message);
+            *comb = CombinationRule::Geometric;
+        }
+        else
+        {
+            *comb = static_cast<CombinationRule>(integerValue);
+        }
     }
 }
 
-static char** cpp_opts(const char* define, const char* include, warninp* wi)
+/*! \brief Parses define and include flags.
+ *
+ * Returns a vector of parsed include/define flags, with an extra nullptr entry at the back
+ * for consumers that expect null-terminated char** structures.
+ */
+static std::vector<char*> cpp_opts(const char* define, const char* include, warninp* wi)
 {
     int         n, len;
-    int         ncppopts = 0;
     const char* cppadds[2];
-    char**      cppopts   = nullptr;
     const char* option[2] = { "-D", "-I" };
     const char* nopt[2]   = { "define", "include" };
     const char* ptr;
@@ -296,6 +322,7 @@ static char** cpp_opts(const char* define, const char* include, warninp* wi)
 
     cppadds[0] = define;
     cppadds[1] = include;
+    std::vector<char*> cppOptions;
     for (n = 0; (n < 2); n++)
     {
         if (cppadds[n])
@@ -325,8 +352,7 @@ static char** cpp_opts(const char* define, const char* include, warninp* wi)
                     }
                     else
                     {
-                        srenew(cppopts, ++ncppopts);
-                        cppopts[ncppopts - 1] = gmx_strdup(buf);
+                        cppOptions.emplace_back(gmx_strdup(buf));
                     }
                     sfree(buf);
                     ptr = rptr;
@@ -334,10 +360,9 @@ static char** cpp_opts(const char* define, const char* include, warninp* wi)
             }
         }
     }
-    srenew(cppopts, ++ncppopts);
-    cppopts[ncppopts - 1] = nullptr;
-
-    return cppopts;
+    // Users of cppOptions expect a null last element.
+    cppOptions.emplace_back(nullptr);
+    return cppOptions;
 }
 
 
@@ -374,7 +399,7 @@ static char** read_topol(const char*                           infile,
                          std::vector<MoleculeInformation>*     molinfo,
                          std::unique_ptr<MoleculeInformation>* intermolecular_interactions,
                          gmx::ArrayRef<InteractionsOfType>     interactions,
-                         int*                                  combination_rule,
+                         CombinationRule*                      combination_rule,
                          double*                               reppow,
                          t_gromppopts*                         opts,
                          real*                                 fudgeQQ,
@@ -387,7 +412,7 @@ static char** read_topol(const char*                           infile,
                          const gmx::MDLogger&                  logger)
 {
     FILE*                out;
-    int                  sl, nb_funct;
+    int                  sl;
     char *               pline = nullptr, **title = nullptr;
     char                 line[STRLEN], errbuf[256], comb_str[256], nb_str[256];
     char                 genpairs[32];
@@ -426,7 +451,7 @@ static char** read_topol(const char*                           infile,
 
     /* open input file */
     auto cpp_opts_return = cpp_opts(define, include, wi);
-    status               = cpp_open_file(infile, &handle, cpp_opts_return);
+    status               = cpp_open_file(infile, &handle, cpp_opts_return.data());
     if (status != 0)
     {
         gmx_fatal(FARGS, "%s", cpp_error(&handle, status));
@@ -438,7 +463,7 @@ static char** read_topol(const char*                           infile,
     nbparam = nullptr;              /* The temporary non-bonded matrix */
     pair    = nullptr;              /* The temporary pair interaction matrix */
     std::vector<std::vector<gmx::ExclusionBlock>> exclusionBlocks;
-    nb_funct = F_LJ;
+    VanDerWaalsPotential                          nb_funct = VanDerWaalsPotential::LJ;
 
     *reppow = 12.0; /* Default value for repulsion power     */
 
@@ -553,8 +578,10 @@ static char** read_topol(const char*                           infile,
                         {
                             /* we should print here which directives should have
                                been present, and which actually are */
-                            gmx_fatal(FARGS, "%s\nInvalid order for directive %s",
-                                      cpp_error(&handle, eCPP_SYNTAX), dir2str(newd));
+                            gmx_fatal(FARGS,
+                                      "%s\nInvalid order for directive %s",
+                                      cpp_error(&handle, eCPP_SYNTAX),
+                                      enumValueToString(newd));
                             /* d = Directive::d_invalid; */
                         }
 
@@ -586,12 +613,13 @@ static char** read_topol(const char*                           infile,
                         case Directive::d_defaults:
                             if (bReadDefaults)
                             {
-                                gmx_fatal(FARGS, "%s\nFound a second defaults directive.\n",
+                                gmx_fatal(FARGS,
+                                          "%s\nFound a second defaults directive.\n",
                                           cpp_error(&handle, eCPP_SYNTAX));
                             }
                             bReadDefaults = TRUE;
-                            nscan = sscanf(pline, "%s%s%s%lf%lf%lf", nb_str, comb_str, genpairs,
-                                           &fLJ, &fQQ, &fPOW);
+                            nscan         = sscanf(
+                                    pline, "%s%s%s%lf%lf%lf", nb_str, comb_str, genpairs, &fLJ, &fQQ, &fPOW);
                             if (nscan < 2)
                             {
                                 too_few(wi);
@@ -606,7 +634,7 @@ static char** read_topol(const char*                           infile,
                                 if (nscan >= 3)
                                 {
                                     bGenPairs = (gmx::equalCaseInsensitive(genpairs, "Y", 1));
-                                    if (nb_funct != eNBF_LJ && bGenPairs)
+                                    if (nb_funct != VanDerWaalsPotential::LJ && bGenPairs)
                                     {
                                         gmx_fatal(FARGS,
                                                   "Generating pair parameters is only supported "
@@ -626,12 +654,19 @@ static char** read_topol(const char*                           infile,
                                     *reppow = fPOW;
                                 }
                             }
-                            nb_funct = ifunc_index(Directive::d_nonbond_params, nb_funct);
+                            nb_funct = static_cast<VanDerWaalsPotential>(ifunc_index(
+                                    Directive::d_nonbond_params, static_cast<int>(nb_funct)));
 
                             break;
                         case Directive::d_atomtypes:
-                            push_at(symtab, atypes, &bondAtomType, pline, nb_funct, &nbparam,
-                                    bGenPairs ? &pair : nullptr, wi);
+                            push_at(symtab,
+                                    atypes,
+                                    &bondAtomType,
+                                    pline,
+                                    static_cast<int>(nb_funct),
+                                    &nbparam,
+                                    bGenPairs ? &pair : nullptr,
+                                    wi);
                             break;
 
                         case Directive::d_bondtypes: // Intended to fall through
@@ -657,7 +692,7 @@ static char** read_topol(const char*                           infile,
                             break;
 
                         case Directive::d_nonbond_params:
-                            push_nbt(d, nbparam, atypes, pline, nb_funct, wi);
+                            push_nbt(d, nbparam, atypes, pline, static_cast<int>(nb_funct), wi);
                             break;
 
                         case Directive::d_implicit_genborn_params: // NOLINT bugprone-branch-clone
@@ -686,32 +721,43 @@ static char** read_topol(const char*                           infile,
                                         || opts->couple_lam1 == ecouplamNONE
                                         || opts->couple_lam1 == ecouplamQ))
                                 {
-                                    dcatt = add_atomtype_decoupled(symtab, atypes, &nbparam,
-                                                                   bGenPairs ? &pair : nullptr);
+                                    dcatt = add_atomtype_decoupled(
+                                            symtab, atypes, &nbparam, bGenPairs ? &pair : nullptr);
                                 }
                                 ntype  = atypes->size();
                                 ncombs = (ntype * (ntype + 1)) / 2;
-                                generate_nbparams(*combination_rule, nb_funct,
-                                                  &(interactions[nb_funct]), atypes, wi);
-                                ncopy = copy_nbparams(nbparam, nb_funct, &(interactions[nb_funct]), ntype);
+                                generate_nbparams(*combination_rule,
+                                                  static_cast<int>(nb_funct),
+                                                  &(interactions[static_cast<int>(nb_funct)]),
+                                                  atypes,
+                                                  wi);
+                                ncopy = copy_nbparams(nbparam,
+                                                      static_cast<int>(nb_funct),
+                                                      &(interactions[static_cast<int>(nb_funct)]),
+                                                      ntype);
                                 GMX_LOG(logger.info)
                                         .asParagraph()
                                         .appendTextFormatted(
                                                 "Generated %d of the %d non-bonded parameter "
                                                 "combinations",
-                                                ncombs - ncopy, ncombs);
+                                                ncombs - ncopy,
+                                                ncombs);
                                 free_nbparam(nbparam, ntype);
                                 if (bGenPairs)
                                 {
-                                    gen_pairs((interactions[nb_funct]), &(interactions[F_LJ14]),
-                                              fudgeLJ, *combination_rule);
-                                    ncopy = copy_nbparams(pair, nb_funct, &(interactions[F_LJ14]), ntype);
+                                    gen_pairs((interactions[static_cast<int>(nb_funct)]),
+                                              &(interactions[F_LJ14]),
+                                              fudgeLJ,
+                                              *combination_rule);
+                                    ncopy = copy_nbparams(
+                                            pair, static_cast<int>(nb_funct), &(interactions[F_LJ14]), ntype);
                                     GMX_LOG(logger.info)
                                             .asParagraph()
                                             .appendTextFormatted(
                                                     "Generated %d of the %d 1-4 parameter "
                                                     "combinations",
-                                                    ncombs - ncopy, ncombs);
+                                                    ncombs - ncopy,
+                                                    ncombs);
                                     free_nbparam(pair, ntype);
                                 }
                                 /* Copy GBSA parameters to atomtype array? */
@@ -737,15 +783,35 @@ static char** read_topol(const char*                           infile,
                             GMX_RELEASE_ASSERT(
                                     mi0,
                                     "Need to have a valid MoleculeInformation object to work on");
-                            push_bond(d, interactions, mi0->interactions, &(mi0->atoms), atypes,
-                                      pline, FALSE, bGenPairs, *fudgeQQ, bZero, &bWarn_copy_A_B, wi);
+                            push_bond(d,
+                                      interactions,
+                                      mi0->interactions,
+                                      &(mi0->atoms),
+                                      atypes,
+                                      pline,
+                                      FALSE,
+                                      bGenPairs,
+                                      *fudgeQQ,
+                                      bZero,
+                                      &bWarn_copy_A_B,
+                                      wi);
                             break;
                         case Directive::d_pairs_nb:
                             GMX_RELEASE_ASSERT(
                                     mi0,
                                     "Need to have a valid MoleculeInformation object to work on");
-                            push_bond(d, interactions, mi0->interactions, &(mi0->atoms), atypes,
-                                      pline, FALSE, FALSE, 1.0, bZero, &bWarn_copy_A_B, wi);
+                            push_bond(d,
+                                      interactions,
+                                      mi0->interactions,
+                                      &(mi0->atoms),
+                                      atypes,
+                                      pline,
+                                      FALSE,
+                                      FALSE,
+                                      1.0,
+                                      bZero,
+                                      &bWarn_copy_A_B,
+                                      wi);
                             break;
 
                         case Directive::d_vsites1:
@@ -769,8 +835,18 @@ static char** read_topol(const char*                           infile,
                             GMX_RELEASE_ASSERT(
                                     mi0,
                                     "Need to have a valid MoleculeInformation object to work on");
-                            push_bond(d, interactions, mi0->interactions, &(mi0->atoms), atypes,
-                                      pline, TRUE, bGenPairs, *fudgeQQ, bZero, &bWarn_copy_A_B, wi);
+                            push_bond(d,
+                                      interactions,
+                                      mi0->interactions,
+                                      &(mi0->atoms),
+                                      atypes,
+                                      pline,
+                                      TRUE,
+                                      bGenPairs,
+                                      *fudgeQQ,
+                                      bZero,
+                                      &bWarn_copy_A_B,
+                                      wi);
                             break;
                         case Directive::d_cmap:
                             GMX_RELEASE_ASSERT(
@@ -829,7 +905,8 @@ static char** read_topol(const char*                           infile,
                                     .asParagraph()
                                     .appendTextFormatted(
                                             "Excluding %d bonded neighbours molecule type '%s'",
-                                            mi0->nrexcl, *mi0->name);
+                                            mi0->nrexcl,
+                                            *mi0->name);
                             sum_q(&mi0->atoms, nrcopies, &qt, &qBt);
                             if (!mi0->bProcessed)
                             {
@@ -839,9 +916,15 @@ static char** read_topol(const char*                           infile,
 
                                 if (bCouple)
                                 {
-                                    convert_moltype_couple(mi0, dcatt, *fudgeQQ, opts->couple_lam0,
-                                                           opts->couple_lam1, opts->bCoupleIntra,
-                                                           nb_funct, &(interactions[nb_funct]), wi);
+                                    convert_moltype_couple(mi0,
+                                                           dcatt,
+                                                           *fudgeQQ,
+                                                           opts->couple_lam0,
+                                                           opts->couple_lam1,
+                                                           opts->bCoupleIntra,
+                                                           static_cast<int>(nb_funct),
+                                                           &(interactions[static_cast<int>(nb_funct)]),
+                                                           wi);
                                 }
                                 stupid_fill_block(&mi0->mols, mi0->atoms.nr, TRUE);
                                 mi0->bProcessed = TRUE;
@@ -868,7 +951,10 @@ static char** read_topol(const char*                           infile,
         warning(wi, unusedDefineWarning);
     }
 
-    sfree(cpp_opts_return);
+    for (char* element : cpp_opts_return)
+    {
+        sfree(element);
+    }
 
     if (out)
     {
@@ -919,8 +1005,8 @@ static char** read_topol(const char*                           infile,
         }
         GMX_LOG(logger.info)
                 .asParagraph()
-                .appendTextFormatted("Coupling %d copies of molecule type '%s'", nmol_couple,
-                                     opts->couple_moltype);
+                .appendTextFormatted(
+                        "Coupling %d copies of molecule type '%s'", nmol_couple, opts->couple_moltype);
     }
 
     /* this is not very clean, but fixes core dump on empty system name */
@@ -936,8 +1022,7 @@ static char** read_topol(const char*                           infile,
     }
     if (fabs(qBt) > 1e-4 && !gmx_within_tol(qBt, qt, 1e-6))
     {
-        sprintf(warn_buf, "State B has non-zero total charge: %.6f\n%s\n", qBt,
-                floating_point_arithmetic_tip);
+        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))
@@ -967,7 +1052,7 @@ char** do_top(bool                                  bVerbose,
               bool                                  bZero,
               t_symtab*                             symtab,
               gmx::ArrayRef<InteractionsOfType>     interactions,
-              int*                                  combination_rule,
+              CombinationRule*                      combination_rule,
               double*                               repulsion_power,
               real*                                 fudgeQQ,
               PreprocessingAtomTypes*               atypes,
@@ -996,12 +1081,28 @@ char** do_top(bool                                  bVerbose,
     {
         GMX_LOG(logger.info).asParagraph().appendTextFormatted("processing topology...");
     }
-    title = read_topol(topfile, tmpfile, opts->define, opts->include, symtab, atypes, molinfo,
-                       intermolecular_interactions, interactions, combination_rule, repulsion_power,
-                       opts, fudgeQQ, molblock, ffParametrizedWithHBondConstraints,
-                       ir->efep != efepNO, bZero, EEL_FULL(ir->coulombtype), wi, logger);
-
-    if ((*combination_rule != eCOMB_GEOMETRIC) && (ir->vdwtype == evdwUSER))
+    title = read_topol(topfile,
+                       tmpfile,
+                       opts->define,
+                       opts->include,
+                       symtab,
+                       atypes,
+                       molinfo,
+                       intermolecular_interactions,
+                       interactions,
+                       combination_rule,
+                       repulsion_power,
+                       opts,
+                       fudgeQQ,
+                       molblock,
+                       ffParametrizedWithHBondConstraints,
+                       ir->efep != FreeEnergyPerturbationType::No,
+                       bZero,
+                       EEL_FULL(ir->coulombtype),
+                       wi,
+                       logger);
+
+    if ((*combination_rule != CombinationRule::Geometric) && (ir->vdwtype == VanDerWaalsType::User))
     {
         warning(wi,
                 "Using sigma/epsilon based combination rules with"
index f39c8ec2f0fe17a100ac8deef983120655ca5dd6..96ee43e1e3c9c6dcfa9e3dc6ffdf1d7fa4bcb836 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ struct InteractionsOfType;
 struct t_symtab;
 struct warninp;
 typedef warninp* warninp_t;
+enum class CombinationRule : int;
 
 namespace gmx
 {
@@ -72,7 +73,7 @@ char** do_top(bool                                  bVerbose,
               bool                                  bZero,
               t_symtab*                             symtab,
               gmx::ArrayRef<InteractionsOfType>     plist,
-              int*                                  combination_rule,
+              CombinationRule*                      combination_rule,
               double*                               repulsion_power,
               real*                                 fudgeQQ,
               PreprocessingAtomTypes*               atype,
index 1c61976460dc08f5f04a9d49887aeac3d7511bb6..59b8d799881491626c9bd4db5e58eda9f58e435c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/symtab.h"
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringtoenumvalueconverter.h"
 #include "gromacs/utility/stringutil.h"
 
-void generate_nbparams(int                     comb,
+void generate_nbparams(CombinationRule         comb,
                        int                     ftype,
                        InteractionsOfType*     interactions,
                        PreprocessingAtomTypes* atypes,
@@ -88,7 +90,7 @@ void generate_nbparams(int                     comb,
         case F_LJ:
             switch (comb)
             {
-                case eCOMB_GEOMETRIC:
+                case CombinationRule::Geometric:
                     /* Gromos rules */
                     for (int i = 0; (i < nr); i++)
                     {
@@ -96,8 +98,8 @@ void generate_nbparams(int                     comb,
                         {
                             for (int nf = 0; (nf < nrfp); nf++)
                             {
-                                ci             = atypes->atomNonBondedParamFromAtomType(i, nf);
-                                cj             = atypes->atomNonBondedParamFromAtomType(j, nf);
+                                ci             = *atypes->atomNonBondedParamFromAtomType(i, nf);
+                                cj             = *atypes->atomNonBondedParamFromAtomType(j, nf);
                                 c              = std::sqrt(ci * cj);
                                 forceParam[nf] = c;
                             }
@@ -106,16 +108,16 @@ void generate_nbparams(int                     comb,
                     }
                     break;
 
-                case eCOMB_ARITHMETIC:
+                case CombinationRule::Arithmetic:
                     /* c0 and c1 are sigma and epsilon */
                     for (int i = 0; (i < nr); i++)
                     {
                         for (int j = 0; (j < nr); j++)
                         {
-                            ci0           = atypes->atomNonBondedParamFromAtomType(i, 0);
-                            cj0           = atypes->atomNonBondedParamFromAtomType(j, 0);
-                            ci1           = atypes->atomNonBondedParamFromAtomType(i, 1);
-                            cj1           = atypes->atomNonBondedParamFromAtomType(j, 1);
+                            ci0           = *atypes->atomNonBondedParamFromAtomType(i, 0);
+                            cj0           = *atypes->atomNonBondedParamFromAtomType(j, 0);
+                            ci1           = *atypes->atomNonBondedParamFromAtomType(i, 1);
+                            cj1           = *atypes->atomNonBondedParamFromAtomType(j, 1);
                             forceParam[0] = (fabs(ci0) + fabs(cj0)) * 0.5;
                             /* Negative sigma signals that c6 should be set to zero later,
                              * so we need to propagate that through the combination rules.
@@ -130,16 +132,16 @@ void generate_nbparams(int                     comb,
                     }
 
                     break;
-                case eCOMB_GEOM_SIG_EPS:
+                case CombinationRule::GeomSigEps:
                     /* c0 and c1 are sigma and epsilon */
                     for (int i = 0; (i < nr); i++)
                     {
                         for (int j = 0; (j < nr); j++)
                         {
-                            ci0           = atypes->atomNonBondedParamFromAtomType(i, 0);
-                            cj0           = atypes->atomNonBondedParamFromAtomType(j, 0);
-                            ci1           = atypes->atomNonBondedParamFromAtomType(i, 1);
-                            cj1           = atypes->atomNonBondedParamFromAtomType(j, 1);
+                            ci0           = *atypes->atomNonBondedParamFromAtomType(i, 0);
+                            cj0           = *atypes->atomNonBondedParamFromAtomType(j, 0);
+                            ci1           = *atypes->atomNonBondedParamFromAtomType(i, 1);
+                            cj1           = *atypes->atomNonBondedParamFromAtomType(j, 1);
                             forceParam[0] = std::sqrt(std::fabs(ci0 * cj0));
                             /* Negative sigma signals that c6 should be set to zero later,
                              * so we need to propagate that through the combination rules.
@@ -155,7 +157,8 @@ void generate_nbparams(int                     comb,
 
                     break;
                 default:
-                    auto message = gmx::formatString("No such combination rule %d", comb);
+                    auto message =
+                            gmx::formatString("No such combination rule %s", enumValueToString(comb));
                     warning_error_and_exit(wi, message, FARGS);
             }
             break;
@@ -166,12 +169,12 @@ void generate_nbparams(int                     comb,
             {
                 for (int j = 0; (j < nr); j++)
                 {
-                    ci0           = atypes->atomNonBondedParamFromAtomType(i, 0);
-                    cj0           = atypes->atomNonBondedParamFromAtomType(j, 0);
-                    ci2           = atypes->atomNonBondedParamFromAtomType(i, 2);
-                    cj2           = atypes->atomNonBondedParamFromAtomType(j, 2);
-                    bi            = atypes->atomNonBondedParamFromAtomType(i, 1);
-                    bj            = atypes->atomNonBondedParamFromAtomType(j, 1);
+                    ci0           = *atypes->atomNonBondedParamFromAtomType(i, 0);
+                    cj0           = *atypes->atomNonBondedParamFromAtomType(j, 0);
+                    ci2           = *atypes->atomNonBondedParamFromAtomType(i, 2);
+                    cj2           = *atypes->atomNonBondedParamFromAtomType(j, 2);
+                    bi            = *atypes->atomNonBondedParamFromAtomType(i, 1);
+                    bj            = *atypes->atomNonBondedParamFromAtomType(j, 1);
                     forceParam[0] = std::sqrt(ci0 * cj0);
                     if ((bi == 0) || (bj == 0))
                     {
@@ -271,6 +274,15 @@ static void copy_B_from_A(int ftype, double* c)
     }
 }
 
+//! Local definition that supersedes the central one, as we only want the leading letter
+static const char* enumValueToLetterAsString(ParticleType enumValue)
+{
+    static constexpr gmx::EnumerationArray<ParticleType, const char*> particleTypeLetters = {
+        "A", "N", "S", "B", "V"
+    };
+    return particleTypeLetters[enumValue];
+}
+
 void push_at(t_symtab*                  symtab,
              PreprocessingAtomTypes*    at,
              PreprocessingBondAtomType* bondAtomType,
@@ -280,18 +292,8 @@ void push_at(t_symtab*                  symtab,
              t_nbparam***               pair,
              warninp*                   wi)
 {
-    typedef struct
-    {
-        const char* entry;
-        int         ptype;
-    } t_xlate;
-    t_xlate xl[eptNR] = {
-        { "A", eptAtom }, { "N", eptNucleus }, { "S", eptShell },
-        { "B", eptBond }, { "V", eptVSite },
-    };
-
-    int     nr, nfields, j, pt, nfp0 = -1;
-    int     batype_nr, nread;
+    int     nfields, nfp0 = -1;
+    int     nread;
     char    type[STRLEN], btype[STRLEN], ptype[STRLEN];
     double  m, q;
     double  c[MAXFORCEPARAM];
@@ -304,9 +306,20 @@ void push_at(t_symtab*                  symtab,
     snew(atom, 1);
 
     /* First assign input line to temporary array */
-    nfields = sscanf(line, "%s%s%s%s%s%s%s%s%s%s%s%s", tmpfield[0], tmpfield[1], tmpfield[2],
-                     tmpfield[3], tmpfield[4], tmpfield[5], tmpfield[6], tmpfield[7], tmpfield[8],
-                     tmpfield[9], tmpfield[10], tmpfield[11]);
+    nfields = sscanf(line,
+                     "%s%s%s%s%s%s%s%s%s%s%s%s",
+                     tmpfield[0],
+                     tmpfield[1],
+                     tmpfield[2],
+                     tmpfield[3],
+                     tmpfield[4],
+                     tmpfield[5],
+                     tmpfield[6],
+                     tmpfield[7],
+                     tmpfield[8],
+                     tmpfield[9],
+                     tmpfield[10],
+                     tmpfield[11]);
 
     /* Comments on optional fields in the atomtypes section:
      *
@@ -373,8 +386,8 @@ void push_at(t_symtab*                  symtab,
             {
                 if (have_bonded_type)
                 {
-                    nread = sscanf(line, "%s%s%d%lf%lf%s%lf%lf", type, btype, &atomnr, &m, &q,
-                                   ptype, &c[0], &c[1]);
+                    nread = sscanf(
+                            line, "%s%s%d%lf%lf%s%lf%lf", type, btype, &atomnr, &m, &q, ptype, &c[0], &c[1]);
                     if (nread < 8)
                     {
                         too_few(wi);
@@ -435,8 +448,8 @@ void push_at(t_symtab*                  symtab,
             {
                 if (have_bonded_type)
                 {
-                    nread = sscanf(line, "%s%s%d%lf%lf%s%lf%lf%lf", type, btype, &atomnr, &m, &q,
-                                   ptype, &c[0], &c[1], &c[2]);
+                    nread = sscanf(
+                            line, "%s%s%d%lf%lf%s%lf%lf%lf", type, btype, &atomnr, &m, &q, ptype, &c[0], &c[1], &c[2]);
                     if (nread < 9)
                     {
                         too_few(wi);
@@ -446,8 +459,8 @@ void push_at(t_symtab*                  symtab,
                 else
                 {
                     /* have_atomic_number && !have_bonded_type */
-                    nread = sscanf(line, "%s%d%lf%lf%s%lf%lf%lf", type, &atomnr, &m, &q, ptype,
-                                   &c[0], &c[1], &c[2]);
+                    nread = sscanf(
+                            line, "%s%d%lf%lf%s%lf%lf%lf", type, &atomnr, &m, &q, ptype, &c[0], &c[1], &c[2]);
                     if (nread < 8)
                     {
                         too_few(wi);
@@ -460,8 +473,8 @@ void push_at(t_symtab*                  symtab,
                 if (have_bonded_type)
                 {
                     /* !have_atomic_number && have_bonded_type */
-                    nread = sscanf(line, "%s%s%lf%lf%s%lf%lf%lf", type, btype, &m, &q, ptype, &c[0],
-                                   &c[1], &c[2]);
+                    nread = sscanf(
+                            line, "%s%s%lf%lf%s%lf%lf%lf", type, btype, &m, &q, ptype, &c[0], &c[1], &c[2]);
                     if (nread < 8)
                     {
                         too_few(wi);
@@ -517,23 +530,18 @@ void push_at(t_symtab*                  symtab,
     {
         sprintf(ptype, "V");
     }
-    for (j = 0; (j < eptNR); j++)
-    {
-        if (gmx_strcasecmp(ptype, xl[j].entry) == 0)
-        {
-            break;
-        }
-    }
-    if (j == eptNR)
+    static const gmx::StringToEnumValueConverter<ParticleType, enumValueToLetterAsString, gmx::StringCompareType::CaseInsensitive, gmx::StripStrings::No>
+                                s_stringToParticleType;
+    std::optional<ParticleType> pt = s_stringToParticleType.valueFrom(ptype);
+    if (!pt)
     {
         auto message = gmx::formatString("Invalid particle type %s", ptype);
         warning_error_and_exit(wi, message, FARGS);
     }
-    pt = xl[j].ptype;
 
     atom->q     = q;
     atom->m     = m;
-    atom->ptype = pt;
+    atom->ptype = pt.value();
     for (int i = 0; i < MAXFORCEPARAM; i++)
     {
         forceParam[i] = c[i];
@@ -541,9 +549,10 @@ void push_at(t_symtab*                  symtab,
 
     InteractionOfType interactionType({}, forceParam, "");
 
-    batype_nr = bondAtomType->addBondAtomType(symtab, btype);
+    auto batype_nr = bondAtomType->addBondAtomType(symtab, btype);
 
-    if ((nr = at->atomTypeFromName(type)) != NOTSET)
+    auto atomType = at->atomTypeFromName(type);
+    if (atomType.has_value())
     {
         auto message = gmx::formatString(
                 "Atomtype %s was defined previously (e.g. in the forcefield files), "
@@ -555,19 +564,16 @@ void push_at(t_symtab*                  symtab,
                 "to suppress this warning with -maxwarn.",
                 type);
         warning(wi, message);
-        if ((nr = at->setType(nr, symtab, *atom, type, interactionType, batype_nr, atomnr)) == NOTSET)
+        auto newAtomType = at->setType(*atomType, symtab, *atom, type, interactionType, batype_nr, atomnr);
+        if (!newAtomType.has_value())
         {
             auto message = gmx::formatString("Replacing atomtype %s failed", type);
             warning_error_and_exit(wi, message, FARGS);
         }
     }
-    else if ((at->addType(symtab, *atom, type, interactionType, batype_nr, atomnr)) == NOTSET)
-    {
-        auto message = gmx::formatString("Adding atomtype %s failed", type);
-        warning_error_and_exit(wi, message, FARGS);
-    }
     else
     {
+        at->addType(symtab, *atom, type, interactionType, batype_nr, atomnr);
         /* Add space in the non-bonded parameters matrix */
         realloc_nb_params(at, nbparam, pair);
     }
@@ -634,9 +640,9 @@ static void push_bondtype(InteractionsOfType*      bt,
             GMX_ASSERT(nrfp <= MAXFORCEPARAM,
                        "This is ensured in other places, but we need this assert to keep the clang "
                        "analyzer happy");
-            const bool identicalParameters = std::equal(
-                    bt->interactionTypes[i].forceParam().begin(),
-                    bt->interactionTypes[i].forceParam().begin() + nrfp, b.forceParam().begin());
+            const bool identicalParameters = std::equal(bt->interactionTypes[i].forceParam().begin(),
+                                                        bt->interactionTypes[i].forceParam().begin() + nrfp,
+                                                        b.forceParam().begin());
 
             if (!bAllowRepeat || identicalParameters)
             {
@@ -746,23 +752,23 @@ static std::vector<int> atomTypesFromAtomNames(const PreprocessingAtomTypes*
     {
         if (atomTypes != nullptr)
         {
-            int atomType = atomTypes->atomTypeFromName(name);
-            if (atomType == NOTSET)
+            auto atomType = atomTypes->atomTypeFromName(name);
+            if (!atomType.has_value())
             {
                 auto message = gmx::formatString("Unknown atomtype %s\n", name);
                 warning_error_and_exit(wi, message, FARGS);
             }
-            atomTypesFromAtomNames.emplace_back(atomType);
+            atomTypesFromAtomNames.emplace_back(*atomType);
         }
         else if (bondAtomTypes != nullptr)
         {
-            int atomType = bondAtomTypes->bondAtomTypeFromName(name);
-            if (atomType == NOTSET)
+            auto bondAtomType = bondAtomTypes->bondAtomTypeFromName(name);
+            if (!bondAtomType.has_value())
             {
                 auto message = gmx::formatString("Unknown bond_atomtype %s\n", name);
                 warning_error_and_exit(wi, message, FARGS);
             }
-            atomTypesFromAtomNames.emplace_back(atomType);
+            atomTypesFromAtomNames.emplace_back(*bondAtomType);
         }
     }
     return atomTypesFromAtomNames;
@@ -813,8 +819,8 @@ void push_bt(Directive                         d,
     nrfpA = interaction_function[ftype].nrfpA;
     strcpy(f1, formnl[nral]);
     strcat(f1, formlf);
-    if ((nn = sscanf(line, f1, &c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6], &c[7], &c[8], &c[9],
-                     &c[10], &c[11], &c[12]))
+    if ((nn = sscanf(
+                 line, f1, &c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6], &c[7], &c[8], &c[9], &c[10], &c[11], &c[12]))
         != nrfp)
     {
         if (nn == nrfpA)
@@ -961,8 +967,8 @@ void push_dihedraltype(Directive                         d,
     strcat(f1, formlf[nrfp - 1]);
 
     /* Check number of parameters given */
-    if ((nn = sscanf(line, f1, &c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6], &c[7], &c[8], &c[9],
-                     &c[10], &c[11]))
+    if ((nn = sscanf(
+                 line, f1, &c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6], &c[7], &c[8], &c[9], &c[10], &c[11]))
         != nrfp)
     {
         if (nn == nrfpA)
@@ -1001,13 +1007,13 @@ void push_dihedraltype(Directive                         d,
         }
         else
         {
-            int atomNumber;
-            if ((atomNumber = bondAtomType->bondAtomTypeFromName(alc[i])) == NOTSET)
+            auto atomNumber = bondAtomType->bondAtomTypeFromName(alc[i]);
+            if (!atomNumber.has_value())
             {
                 auto message = gmx::formatString("Unknown bond_atomtype %s", alc[i]);
                 warning_error_and_exit(wi, message, FARGS);
             }
-            atoms.emplace_back(atomNumber);
+            atoms.emplace_back(*atomNumber);
         }
     }
     for (int i = 0; (i < nrfp); i++)
@@ -1031,7 +1037,6 @@ void push_nbt(Directive d, t_nbparam** nbt, PreprocessingAtomTypes* atypes, char
     int         i, f, n, ftype, nrfp;
     double      c[4], dum;
     real        cr[4];
-    int         ai, aj;
     t_nbparam*  nbp;
     bool        bId;
 
@@ -1108,17 +1113,19 @@ void push_nbt(Directive d, t_nbparam** nbt, PreprocessingAtomTypes* atypes, char
     }
 
     /* Put the parameters in the matrix */
-    if ((ai = atypes->atomTypeFromName(a0)) == NOTSET)
+    auto ai = atypes->atomTypeFromName(a0);
+    if (!ai.has_value())
     {
         auto message = gmx::formatString("Atomtype %s not found", a0);
         warning_error_and_exit(wi, message, FARGS);
     }
-    if ((aj = atypes->atomTypeFromName(a1)) == NOTSET)
+    auto aj = atypes->atomTypeFromName(a1);
+    if (!aj.has_value())
     {
         auto message = gmx::formatString("Atomtype %s not found", a1);
         warning_error_and_exit(wi, message, FARGS);
     }
-    nbp = &(nbt[std::max(ai, aj)][std::min(ai, aj)]);
+    nbp = &(nbt[std::max(*ai, *aj)][std::min(*ai, *aj)]);
 
     if (nbp->bSet)
     {
@@ -1223,7 +1230,11 @@ void push_cmaptype(Directive                         d,
         {
             auto message =
                     gmx::formatString("Error in reading cmap parameter for angle %s %s %s %s %s",
-                                      alc[0], alc[1], alc[2], alc[3], alc[4]);
+                                      alc[0],
+                                      alc[1],
+                                      alc[2],
+                                      alc[3],
+                                      alc[4]);
             warning_error(wi, message);
         }
     }
@@ -1264,7 +1275,7 @@ void push_cmaptype(Directive                         d,
     {
         /* Assign a grid number to each cmap_type */
         GMX_RELEASE_ASSERT(bondAtomType != nullptr, "Need valid PreprocessingBondAtomType object");
-        bt[F_CMAP].cmapAtomTypes.emplace_back(bondAtomType->bondAtomTypeFromName(alc[i]));
+        bt[F_CMAP].cmapAtomTypes.emplace_back(*bondAtomType->bondAtomTypeFromName(alc[i]));
     }
 
     /* Assign a type number to this cmap */
@@ -1275,8 +1286,8 @@ void push_cmaptype(Directive                         d,
     /* Check for the correct number of atoms (again) */
     if (bt[F_CMAP].nct() != nct)
     {
-        auto message = gmx::formatString("Incorrect number of atom types (%d) in cmap type %d\n",
-                                         nct, bt[F_CMAP].cmapAngles);
+        auto message = gmx::formatString(
+                "Incorrect number of atom types (%d) in cmap type %d\n", nct, bt[F_CMAP].cmapAngles);
         warning_error(wi, message);
     }
     std::vector<int> atomTypes =
@@ -1288,23 +1299,23 @@ void push_cmaptype(Directive                         d,
 }
 
 
-static void push_atom_now(t_symtab* symtab,
-                          t_atoms*  at,
-                          int       atomnr,
-                          int       atomicnumber,
-                          int       type,
-                          char*     ctype,
-                          int       ptype,
-                          char*     resnumberic,
-                          char*     resname,
-                          char*     name,
-                          real      m0,
-                          real      q0,
-                          int       typeB,
-                          char*     ctypeB,
-                          real      mB,
-                          real      qB,
-                          warninp*  wi)
+static void push_atom_now(t_symtab*    symtab,
+                          t_atoms*     at,
+                          int          atomnr,
+                          int          atomicnumber,
+                          int          type,
+                          char*        ctype,
+                          ParticleType ptype,
+                          char*        resnumberic,
+                          char*        resname,
+                          char*        name,
+                          real         m0,
+                          real         q0,
+                          int          typeB,
+                          char*        ctypeB,
+                          real         mB,
+                          real         qB,
+                          warninp*     wi)
 {
     int           j, resind = 0, resnr;
     unsigned char ric;
@@ -1315,7 +1326,8 @@ static void push_atom_now(t_symtab* symtab,
         auto message = gmx::formatString(
                 "Atoms in the .top are not numbered consecutively from 1 (rather, "
                 "atomnr = %d, while at->nr = %d)",
-                atomnr, at->nr);
+                atomnr,
+                at->nr);
         warning_error_and_exit(wi, message, FARGS);
     }
 
@@ -1389,8 +1401,7 @@ static void push_atom_now(t_symtab* symtab,
 
 void push_atom(t_symtab* symtab, t_atoms* at, PreprocessingAtomTypes* atypes, char* line, warninp* wi)
 {
-    int  ptype;
-    int  cgnumber, atomnr, type, typeB, nscan;
+    int  cgnumber, atomnr, nscan;
     char id[STRLEN], ctype[STRLEN], ctypeB[STRLEN], resnumberic[STRLEN], resname[STRLEN],
             name[STRLEN], check[STRLEN];
     double m, q, mb, qb;
@@ -1403,19 +1414,20 @@ void push_atom(t_symtab* symtab, t_atoms* at, PreprocessingAtomTypes* atypes, ch
         return;
     }
     sscanf(id, "%d", &atomnr);
-    if ((type = atypes->atomTypeFromName(ctype)) == NOTSET)
+    auto type = atypes->atomTypeFromName(ctype);
+    if (!type.has_value())
     {
         auto message = gmx::formatString("Atomtype %s not found", ctype);
         warning_error_and_exit(wi, message, FARGS);
     }
-    ptype = atypes->atomParticleTypeFromAtomType(type);
+    ParticleType ptype = *atypes->atomParticleTypeFromAtomType(*type);
 
     /* Set default from type */
-    q0    = atypes->atomChargeFromAtomType(type);
-    m0    = atypes->atomMassFromAtomType(type);
-    typeB = type;
-    qB    = q0;
-    mB    = m0;
+    q0         = *atypes->atomChargeFromAtomType(*type);
+    m0         = *atypes->atomMassFromAtomType(*type);
+    auto typeB = type;
+    qB         = q0;
+    mB         = m0;
 
     /* Optional parameters */
     nscan = sscanf(line, "%*s%*s%*s%*s%*s%*s%lf%lf%s%lf%lf%s", &q, &m, ctypeB, &qb, &mb, check);
@@ -1429,13 +1441,14 @@ void push_atom(t_symtab* symtab, t_atoms* at, PreprocessingAtomTypes* atypes, ch
             m0 = mB = m;
             if (nscan > 2)
             {
-                if ((typeB = atypes->atomTypeFromName(ctypeB)) == NOTSET)
+                typeB = atypes->atomTypeFromName(ctypeB);
+                if (!typeB.has_value())
                 {
                     auto message = gmx::formatString("Atomtype %s not found", ctypeB);
                     warning_error_and_exit(wi, message, FARGS);
                 }
-                qB = atypes->atomChargeFromAtomType(typeB);
-                mB = atypes->atomMassFromAtomType(typeB);
+                qB = *atypes->atomChargeFromAtomType(*typeB);
+                mB = *atypes->atomMassFromAtomType(*typeB);
                 if (nscan > 3)
                 {
                     qB = qb;
@@ -1452,8 +1465,23 @@ void push_atom(t_symtab* symtab, t_atoms* at, PreprocessingAtomTypes* atypes, ch
         }
     }
 
-    push_atom_now(symtab, at, atomnr, atypes->atomNumberFromAtomType(type), type, ctype, ptype,
-                  resnumberic, resname, name, m0, q0, typeB, typeB == type ? ctype : ctypeB, mB, qB, wi);
+    push_atom_now(symtab,
+                  at,
+                  atomnr,
+                  *atypes->atomNumberFromAtomType(*type),
+                  *type,
+                  ctype,
+                  ptype,
+                  resnumberic,
+                  resname,
+                  name,
+                  m0,
+                  q0,
+                  *typeB,
+                  typeB == type ? ctype : ctypeB,
+                  mB,
+                  qB,
+                  wi);
 }
 
 void push_molt(t_symtab* symtab, std::vector<MoleculeInformation>* mol, char* line, warninp* wi)
@@ -1467,8 +1495,8 @@ void push_molt(t_symtab* symtab, std::vector<MoleculeInformation>* mol, char* li
     }
 
     /* Test if this moleculetype overwrites another */
-    const auto found = std::find_if(mol->begin(), mol->end(),
-                                    [&type](const auto& m) { return strcmp(*(m.name), type) == 0; });
+    const auto found = std::find_if(
+            mol->begin(), mol->end(), [&type](const auto& m) { return strcmp(*(m.name), type) == 0; });
     if (found != mol->end())
     {
         auto message = gmx::formatString("moleculetype %s is redefined", type);
@@ -1574,7 +1602,8 @@ static bool default_nb_params(int                               ftype,
     if (!bFound)
     {
         auto foundParameter =
-                std::find_if(bt[ftype].interactionTypes.begin(), bt[ftype].interactionTypes.end(),
+                std::find_if(bt[ftype].interactionTypes.begin(),
+                             bt[ftype].interactionTypes.end(),
                              [&paramAtoms, &at, &bB](const auto& param) {
                                  return findIfAllNBAtomsMatch(param.atoms(), paramAtoms, at, bB);
                              });
@@ -1661,8 +1690,12 @@ static bool default_cmap_params(gmx::ArrayRef<InteractionsOfType> bondtype,
     /* If we did not find a matching type for this cmap torsion */
     if (!bFound)
     {
-        auto message = gmx::formatString("Unknown cmap torsion between atoms %d %d %d %d %d", p->ai() + 1,
-                                         p->aj() + 1, p->ak() + 1, p->al() + 1, p->am() + 1);
+        auto message = gmx::formatString("Unknown cmap torsion between atoms %d %d %d %d %d",
+                                         p->ai() + 1,
+                                         p->aj() + 1,
+                                         p->ak() + 1,
+                                         p->al() + 1,
+                                         p->am() + 1);
         warning_error_and_exit(wi, message, FARGS);
     }
 
@@ -1704,15 +1737,21 @@ static int findNumberOfDihedralAtomMatches(const InteractionOfType& currentParam
 {
     if (bB)
     {
-        return natom_match(currentParamFromParameterArray, at->atom[parameterToAdd.ai()].typeB,
-                           at->atom[parameterToAdd.aj()].typeB, at->atom[parameterToAdd.ak()].typeB,
-                           at->atom[parameterToAdd.al()].typeB, atypes);
+        return natom_match(currentParamFromParameterArray,
+                           at->atom[parameterToAdd.ai()].typeB,
+                           at->atom[parameterToAdd.aj()].typeB,
+                           at->atom[parameterToAdd.ak()].typeB,
+                           at->atom[parameterToAdd.al()].typeB,
+                           atypes);
     }
     else
     {
-        return natom_match(currentParamFromParameterArray, at->atom[parameterToAdd.ai()].type,
-                           at->atom[parameterToAdd.aj()].type, at->atom[parameterToAdd.ak()].type,
-                           at->atom[parameterToAdd.al()].type, atypes);
+        return natom_match(currentParamFromParameterArray,
+                           at->atom[parameterToAdd.ai()].type,
+                           at->atom[parameterToAdd.aj()].type,
+                           at->atom[parameterToAdd.ak()].type,
+                           at->atom[parameterToAdd.al()].type,
+                           atypes);
     }
 }
 
@@ -1782,7 +1821,8 @@ static std::vector<InteractionOfType>::iterator defaultInteractionsOfType(int ft
         auto pos     = bt[ftype].interactionTypes.begin();
         while (pos != bt[ftype].interactionTypes.end() && nmatch_max < 4)
         {
-            pos = std::find_if(bt[ftype].interactionTypes.begin(), bt[ftype].interactionTypes.end(),
+            pos = std::find_if(bt[ftype].interactionTypes.begin(),
+                               bt[ftype].interactionTypes.end(),
                                [&p, &at, &atypes, &bB, &nmatch_max](const auto& param) {
                                    return (findNumberOfDihedralAtomMatches(param, p, at, atypes, bB)
                                            > nmatch_max);
@@ -1829,11 +1869,12 @@ static std::vector<InteractionOfType>::iterator defaultInteractionsOfType(int ft
     else /* Not a dihedral */
     {
         gmx::ArrayRef<const int> atomParam = p.atoms();
-        auto                     found     = std::find_if(
-                bt[ftype].interactionTypes.begin(), bt[ftype].interactionTypes.end(),
-                [&atomParam, &at, &atypes, &bB](const auto& param) {
-                    return findIfAllParameterAtomsMatch(param.atoms(), atomParam, at, atypes, bB);
-                });
+        auto                     found     = std::find_if(bt[ftype].interactionTypes.begin(),
+                                  bt[ftype].interactionTypes.end(),
+                                  [&atomParam, &at, &atypes, &bB](const auto& param) {
+                                      return findIfAllParameterAtomsMatch(
+                                              param.atoms(), atomParam, at, atypes, bB);
+                                  });
         if (found != bt[ftype].interactionTypes.end())
         {
             nparam_found = 1;
@@ -1944,7 +1985,11 @@ void push_bond(Directive                         d,
                     "This probably means that you have inserted topology section \"%s\"\n"
                     "in a part belonging to a different molecule than you intended to.\n"
                     "In that case move the \"%s\" section to the right molecule.",
-                    aa[i], dir2str(d), at->nr, dir2str(d), dir2str(d));
+                    aa[i],
+                    enumValueToString(d),
+                    at->nr,
+                    enumValueToString(d),
+                    enumValueToString(d));
             warning_error_and_exit(wi, message, FARGS);
         }
         for (int j = i + 1; (j < nral); j++)
@@ -1953,7 +1998,8 @@ void push_bond(Directive                         d,
                        "Values from nral=NRAL() will satisfy this, we assert to keep gcc 4 happy");
             if (aa[i] == aa[j])
             {
-                auto message = gmx::formatString("Duplicate atom index (%d) in %s", aa[i], dir2str(d));
+                auto message = gmx::formatString(
+                        "Duplicate atom index (%d) in %s", aa[i], enumValueToString(d));
                 if (ftype == F_ANGRES)
                 {
                     /* Since the angle restraints uses 2 pairs of atoms to
@@ -2056,8 +2102,21 @@ void push_bond(Directive                         d,
         strcpy(format, asformat[nral_fmt - 1]);
         strcat(format, ccformat);
 
-        nread = sscanf(line, format, &cc[0], &cc[1], &cc[2], &cc[3], &cc[4], &cc[5], &cc[6], &cc[7],
-                       &cc[8], &cc[9], &cc[10], &cc[11], &cc[12]);
+        nread = sscanf(line,
+                       format,
+                       &cc[0],
+                       &cc[1],
+                       &cc[2],
+                       &cc[3],
+                       &cc[4],
+                       &cc[5],
+                       &cc[6],
+                       &cc[7],
+                       &cc[8],
+                       &cc[9],
+                       &cc[10],
+                       &cc[11],
+                       &cc[12]);
 
         if ((nread == NRFPA(ftype)) && (NRFPB(ftype) != 0))
         {
@@ -2100,7 +2159,10 @@ void push_bond(Directive                         d,
             auto message = gmx::formatString(
                     "Incorrect number of parameters - found %d, expected %d "
                     "or %d for %s (after the function type).",
-                    nread, NRFPA(ftype), NRFP(ftype), interaction_function[ftype].longname);
+                    nread,
+                    NRFPA(ftype),
+                    NRFP(ftype),
+                    interaction_function[ftype].longname);
             warning_error_and_exit(wi, message, FARGS);
         }
 
@@ -2166,7 +2228,8 @@ void push_bond(Directive                         d,
                 {
                     if (bZero)
                     {
-                        fprintf(stderr, "NOTE: No default %s types, using zeroes\n",
+                        fprintf(stderr,
+                                "NOTE: No default %s types, using zeroes\n",
                                 interaction_function[ftype].longname);
                     }
                     else
@@ -2214,7 +2277,8 @@ void push_bond(Directive                         d,
     if ((ftype == F_PDIHS || ftype == F_ANGRES || ftype == F_ANGRESZ) && paramValue[5] != paramValue[2])
     {
         auto message = gmx::formatString("%s multiplicity can not be perturbed %f!=%f",
-                                         interaction_function[ftype].longname, paramValue[2],
+                                         interaction_function[ftype].longname,
+                                         paramValue[2],
                                          paramValue[5]);
         warning_error_and_exit(wi, message, FARGS);
     }
@@ -2223,7 +2287,8 @@ void push_bond(Directive                         d,
     {
         auto message = gmx::formatString("%s table number can not be perturbed %d!=%d",
                                          interaction_function[ftype].longname,
-                                         gmx::roundToInt(param.c0()), gmx::roundToInt(param.c0()));
+                                         gmx::roundToInt(param.c0()),
+                                         gmx::roundToInt(param.c0()));
         warning_error_and_exit(wi, message, FARGS);
     }
 
@@ -2313,7 +2378,11 @@ void push_cmap(Directive                         d,
                     "This probably means that you have inserted topology section \"%s\"\n"
                     "in a part belonging to a different molecule than you intended to.\n"
                     "In that case move the \"%s\" section to the right molecule.",
-                    aa[i], dir2str(d), at->nr, dir2str(d), dir2str(d));
+                    aa[i],
+                    enumValueToString(d),
+                    at->nr,
+                    enumValueToString(d),
+                    enumValueToString(d));
             warning_error_and_exit(wi, message, FARGS);
         }
 
@@ -2321,7 +2390,8 @@ void push_cmap(Directive                         d,
         {
             if (aa[i] == aa[j])
             {
-                auto message = gmx::formatString("Duplicate atom index (%d) in %s", aa[i], dir2str(d));
+                auto message = gmx::formatString(
+                        "Duplicate atom index (%d) in %s", aa[i], enumValueToString(d));
                 warning_error(wi, message);
             }
         }
@@ -2348,9 +2418,13 @@ void push_cmap(Directive                         d,
     else
     {
         /* This is essentially the same check as in default_cmap_params() done one more time */
-        auto message = gmx::formatString(
-                "Unable to assign a cmap type to torsion %d %d %d %d and %d\n", param.ai() + 1,
-                param.aj() + 1, param.ak() + 1, param.al() + 1, param.am() + 1);
+        auto message =
+                gmx::formatString("Unable to assign a cmap type to torsion %d %d %d %d and %d\n",
+                                  param.ai() + 1,
+                                  param.aj() + 1,
+                                  param.ak() + 1,
+                                  param.al() + 1,
+                                  param.am() + 1);
         warning_error_and_exit(wi, message, FARGS);
     }
 }
@@ -2369,7 +2443,8 @@ void push_vsitesn(Directive d, gmx::ArrayRef<InteractionsOfType> bond, t_atoms*
     ptr += n;
     if (ret == 0)
     {
-        auto message = gmx::formatString("Expected an atom index in section \"%s\"", dir2str(d));
+        auto message =
+                gmx::formatString("Expected an atom index in section \"%s\"", enumValueToString(d));
         warning_error_and_exit(wi, message, FARGS);
     }
 
@@ -2410,7 +2485,8 @@ void push_vsitesn(Directive d, gmx::ArrayRef<InteractionsOfType> bond, t_atoms*
                         auto message = gmx::formatString(
                                 "No weight or negative weight found for vsiten "
                                 "constructing atom %d (atom index %d)",
-                                nj + 1, atc[nj] + 1);
+                                nj + 1,
+                                atc[nj] + 1);
                         warning_error_and_exit(wi, message, FARGS);
                     }
                     break;
@@ -2425,8 +2501,8 @@ void push_vsitesn(Directive d, gmx::ArrayRef<InteractionsOfType> bond, t_atoms*
 
     if (nj == 0)
     {
-        auto message =
-                gmx::formatString("Expected more than one atom index in section \"%s\"", dir2str(d));
+        auto message = gmx::formatString("Expected more than one atom index in section \"%s\"",
+                                         enumValueToString(d));
         warning_error_and_exit(wi, message, FARGS);
     }
 
@@ -2498,7 +2574,9 @@ void push_mol(gmx::ArrayRef<MoleculeInformation> mols, char* pline, int* whichmo
                     "For moleculetype '%s' in [ system ] %d case insensitive "
                     "matches, but %d case sensitive matches were found. Check "
                     "the case of the characters in the moleculetypes.",
-                    type, nrci, nrcs);
+                    type,
+                    nrci,
+                    nrcs);
             warning_error_and_exit(wi, message, FARGS);
         }
         if (nrci == 1)
@@ -2569,7 +2647,7 @@ int add_atomtype_decoupled(t_symtab* symtab, PreprocessingAtomTypes* at, t_nbpar
     /* Type for decoupled atoms could be anything,
      * this should be changed automatically later when required.
      */
-    atom.ptype = eptAtom;
+    atom.ptype = ParticleType::Atom;
 
     std::array<real, MAXFORCEPARAM> forceParam = { 0.0 };
     nr = at->addType(symtab, atom, "decoupled", InteractionOfType({}, forceParam, ""), -1, 0);
@@ -2602,8 +2680,9 @@ static void convert_pairs_to_pairsQ(gmx::ArrayRef<InteractionsOfType> interactio
 
     for (const auto& param : paramp1)
     {
-        std::vector<real> forceParam = { fudgeQQ, atoms->atom[param.ai()].q,
-                                         atoms->atom[param.aj()].q, param.c0(), param.c1() };
+        std::vector<real> forceParam = {
+            fudgeQQ, atoms->atom[param.ai()].q, atoms->atom[param.aj()].q, param.c0(), param.c1()
+        };
         paramnew.emplace_back(InteractionOfType(param.atoms(), forceParam, ""));
     }
 
@@ -2651,7 +2730,9 @@ static void generate_LJCpairsNB(MoleculeInformation* mol, int nb_funct, Interact
                 }
                 std::vector<int>  atoms      = { i, j };
                 std::vector<real> forceParam = {
-                    atom[i].q, atom[j].q, nbp->interactionTypes[ntype * atom[i].type + atom[j].type].c0(),
+                    atom[i].q,
+                    atom[j].q,
+                    nbp->interactionTypes[ntype * atom[i].type + atom[j].type].c0(),
                     nbp->interactionTypes[ntype * atom[i].type + atom[j].type].c1()
                 };
                 add_param_to_list(&mol->interactions[F_LJC_PAIRS_NB], InteractionOfType(atoms, forceParam));
@@ -2698,7 +2779,9 @@ static void decouple_atoms(t_atoms*    atoms,
                     "charges and/or atom types set in the topology file as well "
                     "as through the mdp option '%s'. You can not use both "
                     "these methods simultaneously.",
-                    i + 1, mol_name, "couple-moltype");
+                    i + 1,
+                    mol_name,
+                    "couple-moltype");
             warning_error_and_exit(wi, message, FARGS);
         }
 
index 66df62b9d303446f36f023f708b54d2063a07cb3..302af131afab39db3b965a760e684da94c8d85d1 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ class InteractionOfType;
 struct InteractionsOfType;
 struct PreprocessResidue;
 struct warninp;
-
+enum class CombinationRule : int;
 namespace gmx
 {
 template<typename>
@@ -62,7 +62,11 @@ class ArrayRef;
 struct ExclusionBlock;
 } // namespace gmx
 
-void generate_nbparams(int comb, int funct, InteractionsOfType* plist, PreprocessingAtomTypes* atype, warninp* wi);
+void generate_nbparams(CombinationRule         comb,
+                       int                     funct,
+                       InteractionsOfType*     plist,
+                       PreprocessingAtomTypes* atype,
+                       warninp*                wi);
 
 void push_at(struct t_symtab*           symtab,
              PreprocessingAtomTypes*    at,
index d1c8abba6723a967c5a8c39b6a4d903e91c96521..66a5ca31e53ac3a5a6904ba31e17fde2da1f80e5 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,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gmxpreprocess/toppush.h"
 #include "gromacs/gmxpreprocess/toputil.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/topology/ifunc.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/logger.h"
@@ -130,8 +131,8 @@ void make_shake(gmx::ArrayRef<InteractionsOfType> plist, t_atoms* atoms, int nsh
 #ifdef DEBUG
                                 GMX_LOG(logger.info)
                                         .asParagraph()
-                                        .appendTextFormatted("Angle: %d-%d-%d", ang->ai(),
-                                                             ang->aj(), ang->ak());
+                                        .appendTextFormatted(
+                                                "Angle: %d-%d-%d", ang->ai(), ang->aj(), ang->ak());
 #endif
                                 int numhydrogens = count_hydrogens(info, 3, ang->atoms());
                                 if ((nshake == eshALLANGLES) || (numhydrogens > 1)
@@ -162,9 +163,9 @@ void make_shake(gmx::ArrayRef<InteractionsOfType> plist, t_atoms* atoms, int nsh
                                     }
                                     if (bFound)
                                     {
-                                        real param = std::sqrt(b_ij * b_ij + b_jk * b_jk
-                                                               - 2.0 * b_ij * b_jk
-                                                                         * cos(DEG2RAD * ang->c0()));
+                                        real param = std::sqrt(
+                                                b_ij * b_ij + b_jk * b_jk
+                                                - 2.0 * b_ij * b_jk * cos(gmx::c_deg2Rad * ang->c0()));
                                         std::vector<real> forceParm = { param, param };
                                         if (ftype == F_CONNBONDS || ftype_a == F_CONNBONDS)
                                         {
@@ -178,7 +179,8 @@ void make_shake(gmx::ArrayRef<InteractionsOfType> plist, t_atoms* atoms, int nsh
                                         GMX_LOG(logger.info)
                                                 .asParagraph()
                                                 .appendTextFormatted("p: %d, q: %d, dist: %12.5e",
-                                                                     atomNumbers[0], atomNumbers[1],
+                                                                     atomNumbers[0],
+                                                                     atomNumbers[1],
                                                                      forceParm[0]);
 #endif
                                         add_param_to_list(&(plist[F_CONSTR]),
index 10ebbfce3e417c6d23309bca8db42c32dc63d2c6..88dfc9c112ce19be900d6db6c772e7db25954f2d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +37,7 @@
  */
 #include "gmxpre.h"
 
+#include "gromacs/utility/strconvert.h"
 #include "toputil.h"
 
 #include <climits>
@@ -55,6 +56,7 @@
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringutil.h"
 
 /* UTILITIES */
 
@@ -128,7 +130,7 @@ static void print_bt(FILE*                                   out,
     nrfp = NRFP(ftype);
 
     /* header */
-    fprintf(out, "[ %s ]\n", dir2str(d));
+    fprintf(out, "[ %s ]\n", enumValueToString(d));
     fprintf(out, "; ");
     if (!bDih)
     {
@@ -162,14 +164,14 @@ static void print_bt(FILE*                                   out,
         {
             for (int j = 0; (j < nral); j++)
             {
-                fprintf(out, "%5s ", at->atomNameFromAtomType(atoms[j]));
+                fprintf(out, "%5s ", *at->atomNameFromAtomType(atoms[j]));
             }
         }
         else
         {
             for (int j = 0; (j < 2); j++)
             {
-                fprintf(out, "%5s ", at->atomNameFromAtomType(atoms[dihp[f][j]]));
+                fprintf(out, "%5s ", *at->atomNameFromAtomType(atoms[dihp[f][j]]));
             }
         }
         fprintf(out, "%5d ", bSwapParity ? -f - 1 : f + 1);
@@ -207,7 +209,7 @@ void print_excl(FILE* out, int natoms, t_excls excls[])
 
     if (have_excl)
     {
-        fprintf(out, "[ %s ]\n", dir2str(Directive::d_exclusions));
+        fprintf(out, "[ %s ]\n", enumValueToString(Directive::d_exclusions));
         fprintf(out, "; %4s    %s\n", "i", "excluded from i");
         for (i = 0; i < natoms; i++)
         {
@@ -247,13 +249,23 @@ void print_atoms(FILE* out, PreprocessingAtomTypes* atype, t_atoms* at, int* cgn
     int         i, ri;
     int         tpA, tpB;
     const char* as;
-    const char *tpnmA, *tpnmB;
     double      qres, qtot;
 
-    as = dir2str(Directive::d_atoms);
+    as = enumValueToString(Directive::d_atoms);
     fprintf(out, "[ %s ]\n", as);
-    fprintf(out, "; %4s %10s %6s %7s%6s %6s %10s %10s %6s %10s %10s\n", "nr", "type", "resnr",
-            "residue", "atom", "cgnr", "charge", "mass", "typeB", "chargeB", "massB");
+    fprintf(out,
+            "; %4s %10s %6s %7s%6s %6s %10s %10s %6s %10s %10s\n",
+            "nr",
+            "type",
+            "resnr",
+            "residue",
+            "atom",
+            "cgnr",
+            "charge",
+            "mass",
+            "typeB",
+            "chargeB",
+            "massB");
 
     qtot = 0;
 
@@ -266,8 +278,11 @@ void print_atoms(FILE* out, PreprocessingAtomTypes* atype, t_atoms* at, int* cgn
             if ((i == 0 || ri != at->atom[i - 1].resind) && at->resinfo[ri].rtp != nullptr)
             {
                 qres = get_residue_charge(at, i);
-                fprintf(out, "; residue %3d %-3s rtp %-4s q ", at->resinfo[ri].nr,
-                        *at->resinfo[ri].name, *at->resinfo[ri].rtp);
+                fprintf(out,
+                        "; residue %3d %-3s rtp %-4s q ",
+                        at->resinfo[ri].nr,
+                        *at->resinfo[ri].name,
+                        *at->resinfo[ri].rtp);
                 if (fabs(qres) < 0.001)
                 {
                     fprintf(out, " %s", "0.0");
@@ -278,8 +293,9 @@ void print_atoms(FILE* out, PreprocessingAtomTypes* atype, t_atoms* at, int* cgn
                 }
                 fprintf(out, "\n");
             }
-            tpA = at->atom[i].type;
-            if ((tpnmA = atype->atomNameFromAtomType(tpA)) == nullptr)
+            tpA        = at->atom[i].type;
+            auto tpnmA = atype->atomNameFromAtomType(tpA);
+            if (!tpnmA.has_value())
             {
                 gmx_fatal(FARGS, "tpA = %d, i= %d in print_atoms", tpA, i);
             }
@@ -287,19 +303,27 @@ void print_atoms(FILE* out, PreprocessingAtomTypes* atype, t_atoms* at, int* cgn
             /* This is true by construction, but static analysers don't know */
             GMX_ASSERT(!bRTPresname || at->resinfo[at->atom[i].resind].rtp,
                        "-rtpres did not have residue name available");
-            fprintf(out, "%6d %10s %6d%c %5s %6s %6d %10g %10g", i + 1, tpnmA, at->resinfo[ri].nr,
+            fprintf(out,
+                    "%6d %10s %6d%c %5s %6s %6d %10g %10g",
+                    i + 1,
+                    *tpnmA,
+                    at->resinfo[ri].nr,
                     at->resinfo[ri].ic,
                     bRTPresname ? *(at->resinfo[at->atom[i].resind].rtp)
                                 : *(at->resinfo[at->atom[i].resind].name),
-                    *(at->atomname[i]), cgnr[i], at->atom[i].q, at->atom[i].m);
+                    *(at->atomname[i]),
+                    cgnr[i],
+                    at->atom[i].q,
+                    at->atom[i].m);
             if (PERTURBED(at->atom[i]))
             {
-                tpB = at->atom[i].typeB;
-                if ((tpnmB = atype->atomNameFromAtomType(tpB)) == nullptr)
+                tpB        = at->atom[i].typeB;
+                auto tpnmB = atype->atomNameFromAtomType(tpB);
+                if (!tpnmB.has_value())
                 {
                     gmx_fatal(FARGS, "tpB = %d, i= %d in print_atoms", tpB, i);
                 }
-                fprintf(out, " %6s %10g %10g", tpnmB, at->atom[i].qB, at->atom[i].mB);
+                fprintf(out, " %6s %10g %10g", *tpnmB, at->atom[i].qB, at->atom[i].mB);
             }
             // Accumulate the total charge to help troubleshoot issues.
             qtot += static_cast<double>(at->atom[i].q);
@@ -336,9 +360,8 @@ void print_bondeds(FILE* out, int natoms, Directive d, int ftype, int fsubtype,
     open_symtab(&stab);
     for (int i = 0; (i < natoms); i++)
     {
-        char buf[12];
-        sprintf(buf, "%4d", (i + 1));
-        atype.addType(&stab, *a, buf, InteractionOfType({}, {}), 0, 0);
+        std::string name = gmx::toString(i + 1);
+        atype.addType(&stab, *a, name, InteractionOfType({}, {}), 0, 0);
     }
     print_bt(out, d, &atype, ftype, fsubtype, plist, TRUE);
 
index 8d4669f7345585078483274cccc8e0e3fa95f9af..82051635a1804a73a7d1147831e10294af67ce6a 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -39,6 +39,7 @@
 
 #include "vsite_parm.h"
 
+#include <array>
 #include <cmath>
 #include <cstdio>
 #include <cstring>
@@ -52,6 +53,7 @@
 #include "gromacs/gmxpreprocess/toputil.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/topology/ifunc.h"
@@ -79,7 +81,7 @@ public:
     {
         GMX_RELEASE_ASSERT(atomIndex.size() <= atomIndex_.size(),
                            "Cannot add more atom indices than maximum number");
-        auto atomIndexIt = atomIndex_.begin();
+        std::array<int, 4>::iterator atomIndexIt = atomIndex_.begin();
         for (const auto index : atomIndex)
         {
             *atomIndexIt++ = index;
@@ -181,7 +183,7 @@ static AllVsiteBondedInteractions createVsiteBondedInformation(int
     AllVsiteBondedInteractions allVsiteBondeds;
     for (int k = 0; k < nrat; k++)
     {
-        for (auto& vsite : at2vb[atoms[k]].vSiteBondedParameters)
+        for (const auto& vsite : at2vb[atoms[k]].vSiteBondedParameters)
         {
             int                      ftype   = vsite.ftype_;
             const InteractionOfType& type    = vsite.vsiteInteraction_;
@@ -305,8 +307,7 @@ static void print_bad(FILE*                                       fp,
         fprintf(fp, "angles:");
         for (const auto& angle : angles)
         {
-            fprintf(fp, " %d-%d-%d (%g)", angle.ai() + 1, angle.aj() + 1, angle.ak() + 1,
-                    angle.parameterValue());
+            fprintf(fp, " %d-%d-%d (%g)", angle.ai() + 1, angle.aj() + 1, angle.ak() + 1, angle.parameterValue());
         }
         fprintf(fp, "\n");
     }
@@ -315,8 +316,13 @@ static void print_bad(FILE*                                       fp,
         fprintf(fp, "idihs:");
         for (const auto& idih : idihs)
         {
-            fprintf(fp, " %d-%d-%d-%d (%g)", idih.ai() + 1, idih.aj() + 1, idih.ak() + 1,
-                    idih.al() + 1, idih.parameterValue());
+            fprintf(fp,
+                    " %d-%d-%d-%d (%g)",
+                    idih.ai() + 1,
+                    idih.aj() + 1,
+                    idih.ak() + 1,
+                    idih.al() + 1,
+                    idih.parameterValue());
         }
         fprintf(fp, "\n");
     }
@@ -372,7 +378,7 @@ static real get_angle(gmx::ArrayRef<const VsiteBondedInteraction> angles, t_iato
         if (((ai == ang.ai()) && (aj == ang.aj()) && (ak == ang.ak()))
             || ((ai == ang.ak()) && (aj == ang.aj()) && (ak == ang.ai())))
         {
-            angle = DEG2RAD * ang.parameterValue();
+            angle = gmx::c_deg2Rad * ang.parameterValue();
             break;
         }
     }
@@ -381,7 +387,7 @@ static real get_angle(gmx::ArrayRef<const VsiteBondedInteraction> angles, t_iato
 
 static const char* get_atomtype_name_AB(t_atom* atom, PreprocessingAtomTypes* atypes)
 {
-    const char* name = atypes->atomNameFromAtomType(atom->type);
+    const char* name = *atypes->atomNameFromAtomType(atom->type);
 
     /* When using the decoupling option, atom types are changed
      * to decoupled for the non-bonded interactions, but the virtual
@@ -395,7 +401,7 @@ static const char* get_atomtype_name_AB(t_atom* atom, PreprocessingAtomTypes* at
      */
     if (strcmp(name, "decoupled") == 0)
     {
-        name = atypes->atomNameFromAtomType(atom->typeB);
+        name = *atypes->atomNameFromAtomType(atom->typeB);
     }
 
     return name;
@@ -417,12 +423,12 @@ static bool calc_vsite3_param(PreprocessingAtomTypes*                     atypes
     /* check if this is part of a NH3 , NH2-umbrella or CH3 group,
      * i.e. if atom k and l are dummy masses (MNH* or MCH3*) */
     bXH3 = ((gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[vsite->ak()], atypes), "MNH", 3))
-            && (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[vsite->al()], atypes),
-                                          "MNH", 3)))
-           || ((gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[vsite->ak()], atypes),
-                                          "MCH3", 4))
-               && (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[vsite->al()], atypes),
-                                             "MCH3", 4)));
+            && (gmx::equalCaseInsensitive(
+                       get_atomtype_name_AB(&at->atom[vsite->al()], atypes), "MNH", 3)))
+           || ((gmx::equalCaseInsensitive(
+                       get_atomtype_name_AB(&at->atom[vsite->ak()], atypes), "MCH3", 4))
+               && (gmx::equalCaseInsensitive(
+                          get_atomtype_name_AB(&at->atom[vsite->al()], atypes), "MCH3", 4)));
 
     bjk    = get_bond_length(bonds, vsite->aj(), vsite->ak());
     bjl    = get_bond_length(bonds, vsite->aj(), vsite->al());
@@ -531,7 +537,7 @@ static bool calc_vsite3fad_param(InteractionOfType*                          vsi
     bError = (bij == NOTSET) || (aijk == NOTSET);
 
     vsite->setForceParameter(1, bij);
-    vsite->setForceParameter(0, RAD2DEG * aijk);
+    vsite->setForceParameter(0, gmx::c_rad2Deg * aijk);
 
     if (bSwapParity)
     {
@@ -559,12 +565,12 @@ static bool calc_vsite3out_param(PreprocessingAtomTypes*                     aty
     /* check if this is part of a NH2-umbrella, NH3 or CH3 group,
      * i.e. if atom k and l are dummy masses (MNH* or MCH3*) */
     bXH3 = ((gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[vsite->ak()], atypes), "MNH", 3))
-            && (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[vsite->al()], atypes),
-                                          "MNH", 3)))
-           || ((gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[vsite->ak()], atypes),
-                                          "MCH3", 4))
-               && (gmx::equalCaseInsensitive(get_atomtype_name_AB(&at->atom[vsite->al()], atypes),
-                                             "MCH3", 4)));
+            && (gmx::equalCaseInsensitive(
+                       get_atomtype_name_AB(&at->atom[vsite->al()], atypes), "MNH", 3)))
+           || ((gmx::equalCaseInsensitive(
+                       get_atomtype_name_AB(&at->atom[vsite->ak()], atypes), "MCH3", 4))
+               && (gmx::equalCaseInsensitive(
+                          get_atomtype_name_AB(&at->atom[vsite->al()], atypes), "MCH3", 4)));
 
     /* check if construction parity must be swapped */
     bSwapParity = (vsite->c1() == -1);
@@ -597,8 +603,8 @@ static bool calc_vsite3out_param(PreprocessingAtomTypes*                     aty
         dH = bCN - bNH * std::cos(aCNH);
         rH = bNH * std::sin(aCNH);
         /* we assume the H's are symmetrically distributed */
-        rHx = rH * std::cos(DEG2RAD * 30);
-        rHy = rH * std::sin(DEG2RAD * 30);
+        rHx = rH * std::cos(gmx::c_deg2Rad * 30);
+        rHy = rH * std::sin(gmx::c_deg2Rad * 30);
         rM  = 0.5 * bMM;
         dM  = std::sqrt(gmx::square(bCM) - gmx::square(rM));
         a   = 0.5 * ((dH / dM) - (rHy / rM));
@@ -677,11 +683,16 @@ static bool calc_vsite4fd_param(InteractionOfType*                          vsit
                     .asParagraph()
                     .appendTextFormatted(
                             "virtual site %d: angle ijk = %f, angle ijl = %f, angle ijm = %f",
-                            vsite->ai() + 1, RAD2DEG * aijk, RAD2DEG * aijl, RAD2DEG * aijm);
+                            vsite->ai() + 1,
+                            gmx::c_rad2Deg * aijk,
+                            gmx::c_rad2Deg * aijl,
+                            gmx::c_rad2Deg * aijm);
             gmx_fatal(FARGS,
                       "invalid construction in calc_vsite4fd for atom %d: "
                       "cosakl=%f, cosakm=%f\n",
-                      vsite->ai() + 1, cosakl, cosakm);
+                      vsite->ai() + 1,
+                      cosakl,
+                      cosakm);
         }
         sinakl = std::sqrt(1 - gmx::square(cosakl));
         sinakm = std::sqrt(1 - gmx::square(cosakm));
@@ -742,11 +753,16 @@ static bool calc_vsite4fdn_param(InteractionOfType*                          vsi
                     .asParagraph()
                     .appendTextFormatted(
                             "virtual site %d: angle ijk = %f, angle ijl = %f, angle ijm = %f",
-                            vsite->ai() + 1, RAD2DEG * aijk, RAD2DEG * aijl, RAD2DEG * aijm);
+                            vsite->ai() + 1,
+                            gmx::c_rad2Deg * aijk,
+                            gmx::c_rad2Deg * aijl,
+                            gmx::c_rad2Deg * aijm);
             gmx_fatal(FARGS,
                       "invalid construction in calc_vsite4fdn for atom %d: "
                       "pl=%f, pm=%f\n",
-                      vsite->ai() + 1, pl, pm);
+                      vsite->ai() + 1,
+                      pl,
+                      pm);
         }
 
         a = pk / pl;
@@ -825,43 +841,48 @@ int set_vsites(bool                              bVerbose,
                         fprintf(debug,
                                 "Found %zu bonds, %zu angles and %zu idihs "
                                 "for virtual site %d (%s)\n",
-                                allVsiteBondeds.bonds.size(), allVsiteBondeds.angles.size(),
-                                allVsiteBondeds.dihedrals.size(), param.ai() + 1,
+                                allVsiteBondeds.bonds.size(),
+                                allVsiteBondeds.angles.size(),
+                                allVsiteBondeds.dihedrals.size(),
+                                param.ai() + 1,
                                 interaction_function[ftype].longname);
-                        print_bad(debug, allVsiteBondeds.bonds, allVsiteBondeds.angles,
+                        print_bad(debug,
+                                  allVsiteBondeds.bonds,
+                                  allVsiteBondeds.angles,
                                   allVsiteBondeds.dihedrals);
                     } /* debug */
                     switch (ftype)
                     {
                         case F_VSITE3:
-                            bERROR = calc_vsite3_param(atypes, &param, atoms, allVsiteBondeds.bonds,
-                                                       allVsiteBondeds.angles);
+                            bERROR = calc_vsite3_param(
+                                    atypes, &param, atoms, allVsiteBondeds.bonds, allVsiteBondeds.angles);
                             break;
                         case F_VSITE3FD:
-                            bERROR = calc_vsite3fd_param(&param, allVsiteBondeds.bonds,
-                                                         allVsiteBondeds.angles);
+                            bERROR = calc_vsite3fd_param(
+                                    &param, allVsiteBondeds.bonds, allVsiteBondeds.angles);
                             break;
                         case F_VSITE3FAD:
-                            bERROR = calc_vsite3fad_param(&param, allVsiteBondeds.bonds,
-                                                          allVsiteBondeds.angles);
+                            bERROR = calc_vsite3fad_param(
+                                    &param, allVsiteBondeds.bonds, allVsiteBondeds.angles);
                             break;
                         case F_VSITE3OUT:
-                            bERROR = calc_vsite3out_param(atypes, &param, atoms, allVsiteBondeds.bonds,
-                                                          allVsiteBondeds.angles);
+                            bERROR = calc_vsite3out_param(
+                                    atypes, &param, atoms, allVsiteBondeds.bonds, allVsiteBondeds.angles);
                             break;
                         case F_VSITE4FD:
-                            bERROR = calc_vsite4fd_param(&param, allVsiteBondeds.bonds,
-                                                         allVsiteBondeds.angles, logger);
+                            bERROR = calc_vsite4fd_param(
+                                    &param, allVsiteBondeds.bonds, allVsiteBondeds.angles, logger);
                             break;
                         case F_VSITE4FDN:
-                            bERROR = calc_vsite4fdn_param(&param, allVsiteBondeds.bonds,
-                                                          allVsiteBondeds.angles, logger);
+                            bERROR = calc_vsite4fdn_param(
+                                    &param, allVsiteBondeds.bonds, allVsiteBondeds.angles, logger);
                             break;
                         default:
                             gmx_fatal(FARGS,
                                       "Automatic parameter generation not supported "
                                       "for %s atom %d",
-                                      interaction_function[ftype].longname, param.ai() + 1);
+                                      interaction_function[ftype].longname,
+                                      param.ai() + 1);
                             bERROR = TRUE;
                     } /* switch */
                     if (bERROR)
@@ -869,7 +890,8 @@ int set_vsites(bool                              bVerbose,
                         gmx_fatal(FARGS,
                                   "Automatic parameter generation not supported "
                                   "for %s atom %d for this bonding configuration",
-                                  interaction_function[ftype].longname, param.ai() + 1);
+                                  interaction_function[ftype].longname,
+                                  param.ai() + 1);
                     }
                 } /* if bSet */
                 i++;
@@ -902,7 +924,8 @@ void set_vsites_ptype(bool bVerbose, gmx_moltype_t* molt, const gmx::MDLogger& l
             {
                 GMX_LOG(logger.info)
                         .asParagraph()
-                        .appendTextFormatted("doing %d %s virtual sites", (nrd / (nra + 1)),
+                        .appendTextFormatted("doing %d %s virtual sites",
+                                             (nrd / (nra + 1)),
                                              interaction_function[ftype].longname);
             }
 
@@ -910,7 +933,7 @@ void set_vsites_ptype(bool bVerbose, gmx_moltype_t* molt, const gmx::MDLogger& l
             {
                 /* The virtual site */
                 int avsite                     = ia[i + 1];
-                molt->atoms.atom[avsite].ptype = eptVSite;
+                molt->atoms.atom[avsite].ptype = ParticleType::VSite;
 
                 i += nra + 1;
             }
@@ -965,7 +988,9 @@ static void check_vsite_constraints(gmx::ArrayRef<InteractionsOfType> plist,
                         .asParagraph()
                         .appendTextFormatted(
                                 "ERROR: Cannot have constraint (%d-%d) with virtual site (%d)",
-                                param.ai() + 1, param.aj() + 1, atom + 1);
+                                param.ai() + 1,
+                                param.aj() + 1,
+                                atom + 1);
                 n++;
             }
         }
@@ -1158,7 +1183,8 @@ static void clean_vsite_bonds(gmx::ArrayRef<InteractionsOfType>     plist,
                         if (interaction_function[ftype].flags & IF_CONSTRAINT)
                         {
                             for (auto entry = plist[ftype].interactionTypes.begin();
-                                 (entry != plist[ftype].interactionTypes.end()) && !bPresent; entry++)
+                                 (entry != plist[ftype].interactionTypes.end()) && !bPresent;
+                                 entry++)
                             {
                                 /* all constraints until one matches */
                                 bPresent = (((entry->ai() == at1) && (entry->aj() == at2))
@@ -1195,8 +1221,10 @@ static void clean_vsite_bonds(gmx::ArrayRef<InteractionsOfType>     plist,
     {
         GMX_LOG(logger.info)
                 .asParagraph()
-                .appendTextFormatted("Removed   %4d %15ss with virtual sites, %zu left", nremoved,
-                                     interaction_function[cftype].longname, ps->size());
+                .appendTextFormatted("Removed   %4d %15ss with virtual sites, %zu left",
+                                     nremoved,
+                                     interaction_function[cftype].longname,
+                                     ps->size());
     }
     if (nconverted)
     {
@@ -1204,7 +1232,9 @@ static void clean_vsite_bonds(gmx::ArrayRef<InteractionsOfType>     plist,
                 .asParagraph()
                 .appendTextFormatted(
                         "Converted %4d %15ss with virtual sites to connections, %zu left",
-                        nconverted, interaction_function[cftype].longname, ps->size());
+                        nconverted,
+                        interaction_function[cftype].longname,
+                        ps->size());
     }
     if (nOut)
     {
@@ -1216,7 +1246,8 @@ static void clean_vsite_bonds(gmx::ArrayRef<InteractionsOfType>     plist,
                         "bond-length\n"
                         "         If the constructions were generated by pdb2gmx ignore "
                         "this warning",
-                        nOut, interaction_function[cftype].longname,
+                        nOut,
+                        interaction_function[cftype].longname,
                         interaction_function[F_VSITE3OUT].longname);
     }
 }
@@ -1371,7 +1402,8 @@ static void clean_vsite_angles(gmx::ArrayRef<InteractionsOfType>         plist,
         GMX_LOG(logger.info)
                 .asParagraph()
                 .appendTextFormatted("Removed   %4zu %15ss with virtual sites, %zu left",
-                                     oldSize - ps->size(), interaction_function[cftype].longname,
+                                     oldSize - ps->size(),
+                                     interaction_function[cftype].longname,
                                      ps->size());
     }
 }
@@ -1502,7 +1534,8 @@ static void clean_vsite_dihs(gmx::ArrayRef<InteractionsOfType>     plist,
         GMX_LOG(logger.info)
                 .asParagraph()
                 .appendTextFormatted("Removed   %4zu %15ss with virtual sites, %zu left",
-                                     oldSize - ps->size(), interaction_function[cftype].longname,
+                                     oldSize - ps->size(),
+                                     interaction_function[cftype].longname,
                                      ps->size());
     }
 }
index 17410a6408eedd5202329e587e4dc059d05c33d2..876afdef94c6241d2b86adc6b32d52b9d1dac2ae 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -270,7 +270,7 @@ static void calc_angles_dihs(InteractionsOfType* ang, InteractionsOfType* dih, c
         int  ai = angle.ai();
         int  aj = angle.aj();
         int  ak = angle.ak();
-        real th = RAD2DEG
+        real th = gmx::c_rad2Deg
                   * bond_angle(x[ai], x[aj], x[ak], bPBC ? &pbc : nullptr, r_ij, r_kj, &costh, &t1, &t2);
         angle.setForceParameter(0, th);
     }
@@ -280,9 +280,9 @@ static void calc_angles_dihs(InteractionsOfType* ang, InteractionsOfType* dih, c
         int  aj = dihedral.aj();
         int  ak = dihedral.ak();
         int  al = dihedral.al();
-        real ph = RAD2DEG
-                  * dih_angle(x[ai], x[aj], x[ak], x[al], bPBC ? &pbc : nullptr, r_ij, r_kj, r_kl,
-                              m, n, &t1, &t2, &t3);
+        real ph =
+                gmx::c_rad2Deg
+                * dih_angle(x[ai], x[aj], x[ak], x[al], bPBC ? &pbc : nullptr, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3);
         dihedral.setForceParameter(0, ph);
     }
 }
@@ -330,9 +330,8 @@ static void print_rtp(const char*                             filenm,
                       PreprocessingAtomTypes*                 atypes,
                       int                                     cgnr[])
 {
-    FILE*       fp;
-    int         i, tp;
-    const char* tpnm;
+    FILE* fp;
+    int   i, tp;
 
     fp = gmx_fio_fopen(filenm, "w");
     fprintf(fp, "; %s\n", title);
@@ -342,12 +341,13 @@ static void print_rtp(const char*                             filenm,
     fprintf(fp, "[ atoms ]\n");
     for (i = 0; (i < atoms->nr); i++)
     {
-        tp = atoms->atom[i].type;
-        if ((tpnm = atypes->atomNameFromAtomType(tp)) == nullptr)
+        tp        = atoms->atom[i].type;
+        auto tpnm = atypes->atomNameFromAtomType(tp);
+        if (!tpnm.has_value())
         {
             gmx_fatal(FARGS, "tp = %d, i = %d in print_rtp", tp, i);
         }
-        fprintf(fp, "%-8s  %12s  %8.4f  %5d\n", *atoms->atomname[i], tpnm, atoms->atom[i].q, cgnr[i]);
+        fprintf(fp, "%-8s  %12s  %8.4f  %5d\n", *atoms->atomname[i], *tpnm, atoms->atom[i].q, cgnr[i]);
     }
     print_pl(fp, plist, F_BONDS, "bonds", atoms->atomname);
     print_pl(fp, plist, F_ANGLES, "angles", atoms->atomname);
@@ -382,7 +382,8 @@ int gmx_x2top(int argc, char* argv[])
     };
     const char* bugs[] = {
         "The atom type selection is primitive. Virtually no chemical knowledge is used",
-        "Periodic boundary conditions screw up the bonding", "No improper dihedrals are generated",
+        "Periodic boundary conditions screw up the bonding",
+        "No improper dihedrals are generated",
         "The atoms to atomtype translation table is incomplete ([TT]atomname2type.n2t[tt] file in",
         "the data directory). Please extend it and send the results back to the GROMACS crew."
     };
@@ -458,8 +459,8 @@ int gmx_x2top(int argc, char* argv[])
         { "-kp", FALSE, etREAL, { &kp }, "Dihedral angle force constant (kJ/mol/rad^2)" }
     };
 
-    if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc,
-                           asize(bugs), bugs, &oenv))
+    if (!parse_common_args(
+                &argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
         return 0;
     }
@@ -485,8 +486,7 @@ int gmx_x2top(int argc, char* argv[])
 
 
     /* Force field selection, interactive or direct */
-    choose_ff(strcmp(ff, "select") == 0 ? nullptr : ff, forcefield, sizeof(forcefield), ffdir,
-              sizeof(ffdir), logger);
+    choose_ff(strcmp(ff, "select") == 0 ? nullptr : ff, forcefield, sizeof(forcefield), ffdir, sizeof(ffdir), logger);
 
     bOPLS = (strcmp(forcefield, "oplsaa") == 0);
 
@@ -545,8 +545,13 @@ int gmx_x2top(int argc, char* argv[])
             .appendTextFormatted(
                     "There are %4zu %s dihedrals, %4zu impropers, %4zu angles\n"
                     "          %4zu pairs,     %4zu bonds and  %4d atoms\n",
-                    plist[F_PDIHS].size(), bOPLS ? "Ryckaert-Bellemans" : "proper", plist[F_IDIHS].size(),
-                    plist[F_ANGLES].size(), plist[F_LJ14].size(), plist[F_BONDS].size(), atoms->nr);
+                    plist[F_PDIHS].size(),
+                    bOPLS ? "Ryckaert-Bellemans" : "proper",
+                    plist[F_IDIHS].size(),
+                    plist[F_ANGLES].size(),
+                    plist[F_LJ14].size(),
+                    plist[F_BONDS].size(),
+                    atoms->nr);
 
     calc_angles_dihs(&plist[F_ANGLES], &plist[F_PDIHS], x, bPBC, box);
 
@@ -565,7 +570,16 @@ int gmx_x2top(int argc, char* argv[])
         fp = ftp2FILE(efTOP, NFILE, fnm, "w");
         print_top_header(fp, ftp2fn(efTOP, NFILE, fnm), TRUE, ffdir, 1.0);
 
-        write_top(fp, nullptr, mymol.name.c_str(), atoms, FALSE, bts, plist, excls, &atypes, cgnr,
+        write_top(fp,
+                  nullptr,
+                  mymol.name.c_str(),
+                  atoms,
+                  FALSE,
+                  bts,
+                  plist,
+                  excls,
+                  &atypes,
+                  cgnr,
                   rtp_header_settings.nrexcl);
         print_top_mols(fp, mymol.name.c_str(), ffdir, nullptr, {}, gmx::arrayRefFromArray(&mymol, 1));
 
index 4166698511a6bad72f85c17784e1d551a060e665..0cb0529620ced88ce6deec5ac93ee46402f880bc 100644 (file)
@@ -91,8 +91,10 @@ static void get_xlatoms(const std::string& filename, FILE* fp, int* nptr, t_xlat
         }
         if (na != 3)
         {
-            gmx_fatal(FARGS, "Expected a residue name and two atom names in file '%s', not '%s'",
-                      filename.c_str(), line);
+            gmx_fatal(FARGS,
+                      "Expected a residue name and two atom names in file '%s', not '%s'",
+                      filename.c_str(),
+                      line);
         }
 
         srenew(xl, n + 1);
@@ -245,8 +247,11 @@ void rename_atoms(const char*                            xlfile,
                     const char* ptr0 = xlatom[i].replace;
                     if (bVerbose)
                     {
-                        printf("Renaming atom '%s' in residue %d %s to '%s'\n", *atoms->atomname[a],
-                               atoms->resinfo[resind].nr, *atoms->resinfo[resind].name, ptr0);
+                        printf("Renaming atom '%s' in residue %d %s to '%s'\n",
+                               *atoms->atomname[a],
+                               atoms->resinfo[resind].nr,
+                               *atoms->resinfo[resind].name,
+                               ptr0);
                     }
                     atoms->atomname[a] = put_symtab(symtab, ptr0);
                     bRenamed           = TRUE;
index ca34184f832a664253cb9cdcdd5be93df83fdf00..7791042ae4c64f09132657423a280ee1b2137d4b 100644 (file)
@@ -1,7 +1,8 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team.
+# Copyright (c) 2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +37,8 @@
 # the incidence of textual clashes when adding/moving files that
 # otherwise make the end of the list a hotspot.
 
+add_library(gpu_utils INTERFACE)
+
 gmx_add_libgromacs_sources(
         clfftinitializer.cpp
         device_stream_manager.cpp
@@ -46,6 +49,7 @@ if(GMX_GPU_OPENCL)
     gmx_add_libgromacs_sources(
         device_context_ocl.cpp
         device_stream_ocl.cpp
+        pmalloc_ocl.cpp
         ocl_compiler.cpp
         ocl_caching.cpp
         oclutils.cpp
@@ -56,16 +60,17 @@ elseif(GMX_GPU_CUDA)
         device_stream.cu
         gpu_utils.cu
         pinning.cu
-        pmalloc_cuda.cu
+        pmalloc.cu
         )
     _gmx_add_files_to_property(CUDA_SOURCES
         device_stream_manager.cpp
-       )
+        )
 elseif(GMX_GPU_SYCL)
     gmx_add_libgromacs_sources(
         devicebuffer_sycl.cpp
         device_context_sycl.cpp
         device_stream_sycl.cpp
+        pmalloc_sycl.cpp
         )
     _gmx_add_files_to_property(SYCL_SOURCES
         devicebuffer_sycl.cpp
@@ -73,6 +78,7 @@ elseif(GMX_GPU_SYCL)
         device_context_sycl.cpp
         device_stream_manager.cpp
         device_stream_sycl.cpp
+        pmalloc_sycl.cpp
         )
 else()
     gmx_add_libgromacs_sources(
@@ -81,6 +87,38 @@ else()
     )
 endif()
 
+# Source files have the following private module dependencies.
+target_link_libraries(gpu_utils PRIVATE
+#                      gmxlib
+#                      math
+#                      mdtypes
+#                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(gpu_utils PUBLIC
+target_include_directories(gpu_utils INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(gpu_utils PUBLIC
+target_link_libraries(gpu_utils INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when gpu_utils is an OBJECT target
+#target_link_libraries(gpu_utils PUBLIC legacy_api)
+#target_link_libraries(gpu_utils PRIVATE common)
+
+# Module dependencies
+# gpu_utils interfaces convey transitive dependence on these modules.
+#target_link_libraries(gpu_utils PUBLIC
+target_link_libraries(gpu_utils INTERFACE
+#                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(gpu_utils PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(gpu_utils PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index 5097649d478cfd8608375da038479712e52f8cb2..2734f2a9a2ae3fe49372ebff21272d62ef7f8f72 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "config.h"
 
+#include <mutex>
+
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/exceptions.h"
-#include "gromacs/utility/mutex.h"
 #include "gromacs/utility/stringutil.h"
 
 #if GMX_GPU_OPENCL
@@ -68,7 +69,7 @@ namespace
  * initialize it more than once. */
 //! @{
 bool       g_clfftInitialized = false;
-gmx::Mutex g_clfftMutex;
+std::mutex g_clfftMutex;
 //! @}
 #endif
 
@@ -77,7 +78,7 @@ gmx::Mutex g_clfftMutex;
 ClfftInitializer::ClfftInitializer()
 {
 #if GMX_GPU_OPENCL
-    gmx::lock_guard<gmx::Mutex> guard(g_clfftMutex);
+    std::lock_guard<std::mutex> guard(g_clfftMutex);
     clfftSetupData              fftSetup;
     int                         initErrorCode = clfftInitSetupData(&fftSetup);
     if (initErrorCode != 0)
@@ -98,7 +99,7 @@ ClfftInitializer::ClfftInitializer()
 ClfftInitializer::~ClfftInitializer()
 {
 #if GMX_GPU_OPENCL
-    gmx::lock_guard<gmx::Mutex> guard(g_clfftMutex);
+    std::lock_guard<std::mutex> guard(g_clfftMutex);
     if (g_clfftInitialized)
     {
         clfftTeardown();
index 9a69fe9ef0b5b6da6fb8e8ddfb36b9600835fd7c..e5d3c3aad64d9b5d31386a1e17fd436536406d12 100644 (file)
@@ -63,7 +63,9 @@ namespace
  */
 static inline std::string getDeviceErrorString(const cudaError_t deviceError)
 {
-    return formatString("CUDA error #%d (%s): %s.", deviceError, cudaGetErrorName(deviceError),
+    return formatString("CUDA error #%d (%s): %s.",
+                        deviceError,
+                        cudaGetErrorName(deviceError),
                         cudaGetErrorString(deviceError));
 }
 
@@ -281,8 +283,12 @@ void launchGpuKernel(void (*kernel)(Args...),
 {
     dim3 blockSize(config.blockSize[0], config.blockSize[1], config.blockSize[2]);
     dim3 gridSize(config.gridSize[0], config.gridSize[1], config.gridSize[2]);
-    cudaLaunchKernel((void*)kernel, gridSize, blockSize, const_cast<void**>(kernelArgs.data()),
-                     config.sharedMemorySize, deviceStream.stream());
+    cudaLaunchKernel((void*)kernel,
+                     gridSize,
+                     blockSize,
+                     const_cast<void**>(kernelArgs.data()),
+                     config.sharedMemorySize,
+                     deviceStream.stream());
 
     gmx::ensureNoPendingDeviceError("GPU kernel (" + std::string(kernelName)
                                     + ") failed to launch.");
index c4ab967b8f2e72934b553e3c63cd3fdbfee949fb..ee201f4771326f1a486615966c5d31facecc3c17 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "config.h"
 
+#include <memory>
+
 #if GMX_GPU_OPENCL
 #    include "gromacs/gpu_utils/gmxopencl.h"
 #endif
 #if GMX_GPU_SYCL
 #    include "gromacs/gpu_utils/gmxsycl.h"
 #endif
+
 #include "gromacs/gpu_utils/gpu_utils.h"
 #include "gromacs/hardware/device_management.h"
 #include "gromacs/utility/classhelpers.h"
@@ -69,6 +72,7 @@ public:
     //! Constructor.
     DeviceContext(const DeviceInformation& deviceInfo);
     //! Destructor
+    // NOLINTNEXTLINE(performance-trivially-destructible)
     ~DeviceContext();
 
     //! Get the associated device information
index c7fa8af86076fb66727db920fdce5049a17038c6..0ecf83daf5e53671d4076e7003368cbcb33cc470 100644 (file)
@@ -84,7 +84,8 @@ DeviceContext::DeviceContext(const DeviceInformation& deviceInfo) : deviceInfo_(
     {
         GMX_THROW(gmx::InternalError(gmx::formatString(
                 "Failed to create OpenCL context on device %s (OpenCL error ID %d).",
-                deviceInfo.device_name, clError)));
+                deviceInfo.device_name,
+                clError)));
     }
 }
 
index d1aca30236af675016bfef30ea6e4163d957c094..e9794e087ebcc4350ba84a26660eaaac0edb048a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
 
 #include "config.h"
 
+#include <memory>
+
 #if GMX_GPU_CUDA
 #    include <cuda_runtime.h>
 
@@ -56,6 +58,7 @@
 #elif GMX_GPU_SYCL
 #    include "gromacs/gpu_utils/gmxsycl.h"
 #endif
+
 #include "gromacs/utility/classhelpers.h"
 
 struct DeviceInformation;
@@ -98,6 +101,7 @@ public:
     DeviceStream(const DeviceContext& deviceContext, DeviceStreamPriority priority, bool useTiming);
 
     //! Destructor
+    // NOLINTNEXTLINE(performance-trivially-destructible)
     ~DeviceStream();
 
     /*! \brief Check if the underlying stream is valid.
index 1f8366e743fc7336855973af53fc8f4caa732362..036822d4e531d71132faaf933bc730b2f4ea14de 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_GPU_UTILS_GPUSTREAMMANAGER_H
 #define GMX_GPU_UTILS_GPUSTREAMMANAGER_H
 
+#include <memory>
 #include <string>
 
-#include "gromacs/utility/classhelpers.h"
-
 class DeviceContext;
 struct DeviceInformation;
 class DeviceStream;
@@ -140,7 +139,7 @@ public:
 
 private:
     class Impl;
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 914061627116a4387c274a63d852a6e78d10f35b..1aeb807d13c0fd0955712986e3e95d7cac1b054c 100644 (file)
@@ -63,7 +63,8 @@ DeviceStream::DeviceStream(const DeviceContext& deviceContext,
     {
         GMX_THROW(gmx::InternalError(gmx::formatString(
                 "Failed to create OpenCL command queue on GPU %s (OpenCL error ID %d).",
-                deviceInfo.device_name, clError)));
+                deviceInfo.device_name,
+                clError)));
     }
 }
 
index 72a431e121b920b55f4642a46c4e9bb13c6dcd2c..48c6217ab74149d48e277108ba18857759286e2a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,12 @@ DeviceStream::DeviceStream(const DeviceContext& deviceContext,
         const bool deviceSupportsTiming = device.get_info<cl::sycl::info::device::queue_profiling>();
         if (deviceSupportsTiming)
         {
+#if (!GMX_SYCL_HIPSYCL)
+            /* Support for profiling and even the `::enable_profile` property is added in
+             * https://github.com/illuhad/hipSYCL/pull/428, which is not merged at the
+             * time of writing */
             propertyList = cl::sycl::property::queue::enable_profiling();
+#endif
         }
     }
     stream_ = cl::sycl::queue(deviceContext.context(), device, propertyList);
index ec544aa3c2a58cdc693a9d117f7d79dd9f900957..2b83752c2ae2954b9bc533a8f19f62b3daf01397 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,18 +129,20 @@ void copyToDeviceBuffer(DeviceBuffer<ValueType>* buffer,
     switch (transferKind)
     {
         case GpuApiCallBehavior::Async:
-            GMX_ASSERT(isHostMemoryPinned(hostBuffer),
-                       "Source host buffer was not pinned for CUDA");
-            stat = cudaMemcpyAsync(*((ValueType**)buffer) + startingOffset, hostBuffer, bytes,
-                                   cudaMemcpyHostToDevice, deviceStream.stream());
+            GMX_ASSERT(isHostMemoryPinned(hostBuffer), "Source host buffer was not pinned for CUDA");
+            stat = cudaMemcpyAsync(*((ValueType**)buffer) + startingOffset,
+                                   hostBuffer,
+                                   bytes,
+                                   cudaMemcpyHostToDevice,
+                                   deviceStream.stream());
             GMX_RELEASE_ASSERT(
                     stat == cudaSuccess,
                     ("Asynchronous H2D copy failed. " + gmx::getDeviceErrorString(stat)).c_str());
             break;
 
         case GpuApiCallBehavior::Sync:
-            stat = cudaMemcpy(*((ValueType**)buffer) + startingOffset, hostBuffer, bytes,
-                              cudaMemcpyHostToDevice);
+            stat = cudaMemcpy(
+                    *((ValueType**)buffer) + startingOffset, hostBuffer, bytes, cudaMemcpyHostToDevice);
             GMX_RELEASE_ASSERT(
                     stat == cudaSuccess,
                     ("Synchronous H2D copy failed. " + gmx::getDeviceErrorString(stat)).c_str());
@@ -186,16 +188,19 @@ void copyFromDeviceBuffer(ValueType*               hostBuffer,
         case GpuApiCallBehavior::Async:
             GMX_ASSERT(isHostMemoryPinned(hostBuffer),
                        "Destination host buffer was not pinned for CUDA");
-            stat = cudaMemcpyAsync(hostBuffer, *((ValueType**)buffer) + startingOffset, bytes,
-                                   cudaMemcpyDeviceToHost, deviceStream.stream());
+            stat = cudaMemcpyAsync(hostBuffer,
+                                   *((ValueType**)buffer) + startingOffset,
+                                   bytes,
+                                   cudaMemcpyDeviceToHost,
+                                   deviceStream.stream());
             GMX_RELEASE_ASSERT(
                     stat == cudaSuccess,
                     ("Asynchronous D2H copy failed. " + gmx::getDeviceErrorString(stat)).c_str());
             break;
 
         case GpuApiCallBehavior::Sync:
-            stat = cudaMemcpy(hostBuffer, *((ValueType**)buffer) + startingOffset, bytes,
-                              cudaMemcpyDeviceToHost);
+            stat = cudaMemcpy(
+                    hostBuffer, *((ValueType**)buffer) + startingOffset, bytes, cudaMemcpyDeviceToHost);
             GMX_RELEASE_ASSERT(
                     stat == cudaSuccess,
                     ("Synchronous D2H copy failed. " + gmx::getDeviceErrorString(stat)).c_str());
@@ -205,6 +210,59 @@ void copyFromDeviceBuffer(ValueType*               hostBuffer,
     }
 }
 
+/*! \brief
+ * Performs the device-to-device data copy, synchronous or asynchronously on request.
+ *
+ * \tparam        ValueType                Raw value type of the \p buffer.
+ * \param[in,out] destinationDeviceBuffer  Device-side buffer to copy to
+ * \param[in]     sourceDeviceBuffer       Device-side buffer to copy from
+ * \param[in]     numValues                Number of values to copy.
+ * \param[in]     deviceStream             GPU stream to perform asynchronous copy in.
+ * \param[in]     transferKind             Copy type: synchronous or asynchronous.
+ * \param[out]    timingEvent              A dummy pointer to the D2D copy timing event to be filled
+ * in. Not used in CUDA implementation.
+ */
+template<typename ValueType>
+void copyBetweenDeviceBuffers(DeviceBuffer<ValueType>* destinationDeviceBuffer,
+                              DeviceBuffer<ValueType>* sourceDeviceBuffer,
+                              size_t                   numValues,
+                              const DeviceStream&      deviceStream,
+                              GpuApiCallBehavior       transferKind,
+                              CommandEvent* /*timingEvent*/)
+{
+    if (numValues == 0)
+    {
+        return;
+    }
+    GMX_ASSERT(destinationDeviceBuffer, "needs a destination buffer pointer");
+    GMX_ASSERT(sourceDeviceBuffer, "needs a source buffer pointer");
+
+    cudaError_t  stat;
+    const size_t bytes = numValues * sizeof(ValueType);
+    switch (transferKind)
+    {
+        case GpuApiCallBehavior::Async:
+            stat = cudaMemcpyAsync(*destinationDeviceBuffer,
+                                   *sourceDeviceBuffer,
+                                   bytes,
+                                   cudaMemcpyDeviceToDevice,
+                                   deviceStream.stream());
+            GMX_RELEASE_ASSERT(
+                    stat == cudaSuccess,
+                    ("Asynchronous D2D copy failed. " + gmx::getDeviceErrorString(stat)).c_str());
+            break;
+
+        case GpuApiCallBehavior::Sync:
+            stat = cudaMemcpy(*destinationDeviceBuffer, *sourceDeviceBuffer, bytes, cudaMemcpyDeviceToDevice);
+            GMX_RELEASE_ASSERT(
+                    stat == cudaSuccess,
+                    ("Synchronous D2D copy failed. " + gmx::getDeviceErrorString(stat)).c_str());
+            break;
+
+        default: throw;
+    }
+}
+
 /*! \brief
  * Clears the device buffer asynchronously.
  *
@@ -220,12 +278,16 @@ void clearDeviceBufferAsync(DeviceBuffer<ValueType>* buffer,
                             size_t                   numValues,
                             const DeviceStream&      deviceStream)
 {
+    if (numValues == 0)
+    {
+        return;
+    }
     GMX_ASSERT(buffer, "needs a buffer pointer");
     const size_t bytes   = numValues * sizeof(ValueType);
     const char   pattern = 0;
 
-    cudaError_t stat = cudaMemsetAsync(*((ValueType**)buffer) + startingOffset, pattern, bytes,
-                                       deviceStream.stream());
+    cudaError_t stat = cudaMemsetAsync(
+            *((ValueType**)buffer) + startingOffset, pattern, bytes, deviceStream.stream());
     GMX_RELEASE_ASSERT(stat == cudaSuccess,
                        ("Couldn't clear the device buffer. " + gmx::getDeviceErrorString(stat)).c_str());
 }
index a13f0c62625315e7979c71e931e93b00924ea382..d3fc1c97d966230a1eafd426e3049e94fd43b2a2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_GPU_UTILS_DEVICEBUFFER_H
 
 /*! \libinternal \file
- *  \brief Implements the logic for handling of DeviceBuffer types in OpenCL/CUDA.
+ *  \brief Implements the logic for handling of DeviceBuffer types in OpenCL, CUDA and SYCL.
+ *
  *  Can only be included on GPU build paths.
  *
+ *  Note that most of the buffer operations have an early return, if the requested operation
+ *  size is zero. This allows for calling these functions with zero operation size even when
+ *  the underlying buffers were not properly intialized.
+ *
  *  \author Aleksei Iupinov <a.yupinov@gmail.com>
  *
  *  \inlibraryapi
index 81501a2b0862d9c65bc09af357d403574670498e..a6d9e6813461f9d01287ab252424017c29cf5a51 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -69,10 +69,11 @@ void allocateDeviceBuffer(DeviceBuffer<ValueType>* buffer, size_t numValues, con
     GMX_ASSERT(buffer, "needs a buffer pointer");
     void*  hostPtr = nullptr;
     cl_int clError;
-    *buffer = clCreateBuffer(deviceContext.context(), CL_MEM_READ_WRITE,
-                             numValues * sizeof(ValueType), hostPtr, &clError);
+    *buffer = clCreateBuffer(
+            deviceContext.context(), CL_MEM_READ_WRITE, numValues * sizeof(ValueType), hostPtr, &clError);
     GMX_RELEASE_ASSERT(clError == CL_SUCCESS,
-                       gmx::formatString("clCreateBuffer failure (OpenCL error %d: %s)", clError,
+                       gmx::formatString("clCreateBuffer failure (OpenCL error %d: %s)",
+                                         clError,
                                          ocl_get_error_string(clError).c_str())
                                .c_str());
 }
@@ -94,7 +95,8 @@ void freeDeviceBuffer(DeviceBuffer* buffer)
         cl_int clError = clReleaseMemObject(*buffer);
         GMX_RELEASE_ASSERT(clError == CL_SUCCESS,
                            gmx::formatString("clReleaseMemObject failed (OpenCL error %d: %s)",
-                                             clError, ocl_get_error_string(clError).c_str())
+                                             clError,
+                                             ocl_get_error_string(clError).c_str())
                                    .c_str());
     }
 }
@@ -137,21 +139,23 @@ void copyToDeviceBuffer(DeviceBuffer<ValueType>* buffer,
     switch (transferKind)
     {
         case GpuApiCallBehavior::Async:
-            clError = clEnqueueWriteBuffer(deviceStream.stream(), *buffer, CL_FALSE, offset, bytes,
-                                           hostBuffer, 0, nullptr, timingEvent);
+            clError = clEnqueueWriteBuffer(
+                    deviceStream.stream(), *buffer, CL_FALSE, offset, bytes, hostBuffer, 0, nullptr, timingEvent);
             GMX_RELEASE_ASSERT(
                     clError == CL_SUCCESS,
-                    gmx::formatString("Asynchronous H2D copy failed (OpenCL error %d: %s)", clError,
+                    gmx::formatString("Asynchronous H2D copy failed (OpenCL error %d: %s)",
+                                      clError,
                                       ocl_get_error_string(clError).c_str())
                             .c_str());
             break;
 
         case GpuApiCallBehavior::Sync:
-            clError = clEnqueueWriteBuffer(deviceStream.stream(), *buffer, CL_TRUE, offset, bytes,
-                                           hostBuffer, 0, nullptr, timingEvent);
+            clError = clEnqueueWriteBuffer(
+                    deviceStream.stream(), *buffer, CL_TRUE, offset, bytes, hostBuffer, 0, nullptr, timingEvent);
             GMX_RELEASE_ASSERT(
                     clError == CL_SUCCESS,
-                    gmx::formatString("Synchronous H2D copy failed (OpenCL error %d: %s)", clError,
+                    gmx::formatString("Synchronous H2D copy failed (OpenCL error %d: %s)",
+                                      clError,
                                       ocl_get_error_string(clError).c_str())
                             .c_str());
             break;
@@ -198,21 +202,23 @@ void copyFromDeviceBuffer(ValueType*               hostBuffer,
     switch (transferKind)
     {
         case GpuApiCallBehavior::Async:
-            clError = clEnqueueReadBuffer(deviceStream.stream(), *buffer, CL_FALSE, offset, bytes,
-                                          hostBuffer, 0, nullptr, timingEvent);
+            clError = clEnqueueReadBuffer(
+                    deviceStream.stream(), *buffer, CL_FALSE, offset, bytes, hostBuffer, 0, nullptr, timingEvent);
             GMX_RELEASE_ASSERT(
                     clError == CL_SUCCESS,
-                    gmx::formatString("Asynchronous D2H copy failed (OpenCL error %d: %s)", clError,
+                    gmx::formatString("Asynchronous D2H copy failed (OpenCL error %d: %s)",
+                                      clError,
                                       ocl_get_error_string(clError).c_str())
                             .c_str());
             break;
 
         case GpuApiCallBehavior::Sync:
-            clError = clEnqueueReadBuffer(deviceStream.stream(), *buffer, CL_TRUE, offset, bytes,
-                                          hostBuffer, 0, nullptr, timingEvent);
+            clError = clEnqueueReadBuffer(
+                    deviceStream.stream(), *buffer, CL_TRUE, offset, bytes, hostBuffer, 0, nullptr, timingEvent);
             GMX_RELEASE_ASSERT(
                     clError == CL_SUCCESS,
-                    gmx::formatString("Synchronous D2H copy failed (OpenCL error %d: %s)", clError,
+                    gmx::formatString("Synchronous D2H copy failed (OpenCL error %d: %s)",
+                                      clError,
                                       ocl_get_error_string(clError).c_str())
                             .c_str());
             break;
@@ -221,6 +227,23 @@ void copyFromDeviceBuffer(ValueType*               hostBuffer,
     }
 }
 
+/*! \brief
+ * Performs the device-to-device data copy, synchronous or asynchronously on request.
+ *
+ * \tparam        ValueType                Raw value type of the \p buffer.
+ */
+template<typename ValueType>
+void copyBetweenDeviceBuffers(DeviceBuffer<ValueType>* /* destinationDeviceBuffer */,
+                              DeviceBuffer<ValueType>* /* sourceDeviceBuffer */,
+                              size_t /* numValues */,
+                              const DeviceStream& /* deviceStream */,
+                              GpuApiCallBehavior /* transferKind */,
+                              CommandEvent* /*timingEvent*/)
+{
+    // OpenCL-TODO
+    gmx_fatal(FARGS, "D2D copy stub was called. Not yet implemented in OpenCL.");
+}
+
 /*! \brief
  * Clears the device buffer asynchronously.
  *
@@ -236,6 +259,10 @@ void clearDeviceBufferAsync(DeviceBuffer<ValueType>* buffer,
                             size_t                   numValues,
                             const DeviceStream&      deviceStream)
 {
+    if (numValues == 0)
+    {
+        return;
+    }
     GMX_ASSERT(buffer, "needs a buffer pointer");
     const size_t    offset        = startingOffset * sizeof(ValueType);
     const size_t    bytes         = numValues * sizeof(ValueType);
@@ -243,11 +270,12 @@ void clearDeviceBufferAsync(DeviceBuffer<ValueType>* buffer,
     const cl_uint   numWaitEvents = 0;
     const cl_event* waitEvents    = nullptr;
     cl_event        commandEvent;
-    cl_int clError = clEnqueueFillBuffer(deviceStream.stream(), *buffer, &pattern, sizeof(pattern),
-                                         offset, bytes, numWaitEvents, waitEvents, &commandEvent);
+    cl_int          clError = clEnqueueFillBuffer(
+            deviceStream.stream(), *buffer, &pattern, sizeof(pattern), offset, bytes, numWaitEvents, waitEvents, &commandEvent);
     GMX_RELEASE_ASSERT(clError == CL_SUCCESS,
                        gmx::formatString("Couldn't clear the device buffer (OpenCL error %d: %s)",
-                                         clError, ocl_get_error_string(clError).c_str())
+                                         clError,
+                                         ocl_get_error_string(clError).c_str())
                                .c_str());
 }
 
@@ -306,11 +334,14 @@ void initParamLookupTable(DeviceBuffer<ValueType>* deviceBuffer,
     cl_int       clError;
     *deviceBuffer = clCreateBuffer(deviceContext.context(),
                                    CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY | CL_MEM_COPY_HOST_PTR,
-                                   bytes, const_cast<ValueType*>(hostBuffer), &clError);
+                                   bytes,
+                                   const_cast<ValueType*>(hostBuffer),
+                                   &clError);
 
     GMX_RELEASE_ASSERT(clError == CL_SUCCESS,
                        gmx::formatString("Constant memory allocation failed (OpenCL error %d: %s)",
-                                         clError, ocl_get_error_string(clError).c_str())
+                                         clError,
+                                         ocl_get_error_string(clError).c_str())
                                .c_str());
 }
 
index 5efc4dd963b48aff96ce74d500a48dcea99dc391..68d245337fb6d643865850680f4d455aab6ba527 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  *  \inlibraryapi
  */
 
+#include <utility>
+
 #include "gromacs/gpu_utils/device_context.h"
 #include "gromacs/gpu_utils/device_stream.h"
 #include "gromacs/gpu_utils/devicebuffer_datatype.h"
 #include "gromacs/gpu_utils/gmxsycl.h"
 #include "gromacs/gpu_utils/gpu_utils.h" //only for GpuApiCallBehavior
 #include "gromacs/gpu_utils/gputraits_sycl.h"
+#include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/stringutil.h"
 
@@ -120,7 +123,7 @@ DeviceBuffer<T>& DeviceBuffer<T>::operator=(std::nullptr_t nullPtr)
 namespace gmx::internal
 {
 //! Shorthand alias to create a placeholder SYCL accessor with chosen data type and access mode.
-template<class T, enum cl::sycl::access::mode mode>
+template<class T, cl::sycl::access::mode mode>
 using PlaceholderAccessor =
         cl::sycl::accessor<T, 1, mode, cl::sycl::access::target::global_buffer, cl::sycl::access::placeholder::true_t>;
 } // namespace gmx::internal
@@ -136,7 +139,7 @@ using PlaceholderAccessor =
  * \tparam T Type of buffer content.
  * \tparam mode Access mode.
  */
-template<class T, enum cl::sycl::access::mode mode>
+template<class T, cl::sycl::access::mode mode>
 class DeviceAccessor : public gmx::internal::PlaceholderAccessor<T, mode>
 {
 public:
@@ -147,6 +150,18 @@ public:
         gmx::internal::PlaceholderAccessor<T, mode>(getSyclBuffer(buffer))
     {
     }
+    //! Construct read-only Accessor from a const DeviceBuffer (must be initialized)
+    DeviceAccessor(const DeviceBuffer<T>& buffer) :
+        gmx::internal::PlaceholderAccessor<T, mode>(getSyclBuffer(const_cast<DeviceBuffer<T>&>(buffer)))
+    {
+        /* There were some discussions about making it possible to create read-only sycl::accessor
+         * from a const sycl::buffer (https://github.com/KhronosGroup/SYCL-Docs/issues/10), but
+         * it did not make it into the SYCL2020 standard. So, we have to use const_cast above */
+        /* Using static_assert to ensure that only mode::read accessors can be created from a
+         * const DeviceBuffer. static_assert provides better error messages than std::enable_if. */
+        static_assert(mode == cl::sycl::access::mode::read,
+                      "Can not create non-read-only accessor from a const DeviceBuffer");
+    }
 
 private:
     //! Helper function to get sycl:buffer object from DeviceBuffer wrapper, with a sanity check.
@@ -197,7 +212,7 @@ struct EmptyClassThatIgnoresConstructorArguments
  * \tparam mode Access mode of the accessor
  * \tparam enabled Compile-time flag indicating whether we want to actually create an accessor.
  */
-template<class T, enum cl::sycl::access::mode mode, bool enabled>
+template<class T, cl::sycl::access::mode mode, bool enabled>
 using OptionalAccessor =
         std::conditional_t<enabled, DeviceAccessor<T, mode>, gmx::internal::EmptyClassThatIgnoresConstructorArguments>;
 
@@ -353,6 +368,62 @@ void copyFromDeviceBuffer(ValueType*               hostBuffer,
     }
 }
 
+/*! \brief
+ * Performs the device-to-device data copy, synchronous or asynchronously on request.
+ *
+ * \tparam        ValueType                Raw value type of the \p buffer.
+ */
+template<typename ValueType>
+void copyBetweenDeviceBuffers(DeviceBuffer<ValueType>* /* destinationDeviceBuffer */,
+                              DeviceBuffer<ValueType>* /* sourceDeviceBuffer */,
+                              size_t /* numValues */,
+                              const DeviceStream& /* deviceStream */,
+                              GpuApiCallBehavior /* transferKind */,
+                              CommandEvent* /*timingEvent*/)
+{
+    // SYCL-TODO
+    gmx_fatal(FARGS, "D2D copy stub was called. Not yet implemented in SYCL.");
+}
+
+
+namespace gmx::internal
+{
+/*! \brief Helper function to clear device buffer.
+ *
+ * Not applicable to GROMACS's float3 (a.k.a. gmx::RVec) and other custom types.
+ * From SYCL specs: "T must be a scalar value or a SYCL vector type."
+ */
+template<typename ValueType>
+cl::sycl::event fillSyclBufferWithNull(cl::sycl::buffer<ValueType, 1>& buffer,
+                                       size_t                          startingOffset,
+                                       size_t                          numValues,
+                                       cl::sycl::queue                 queue)
+{
+    using cl::sycl::access::mode;
+    const cl::sycl::range<1> range(numValues);
+    const cl::sycl::id<1>    offset(startingOffset);
+    const ValueType pattern = ValueType(0); // SYCL vectors support initialization by scalar
+
+    return queue.submit([&](cl::sycl::handler& cgh) {
+        auto d_bufferAccessor =
+                cl::sycl::accessor<ValueType, 1, mode::discard_write>{ buffer, cgh, range, offset };
+        cgh.fill(d_bufferAccessor, pattern);
+    });
+}
+
+//! \brief Helper function to clear device buffer of type float3.
+template<>
+inline cl::sycl::event fillSyclBufferWithNull(cl::sycl::buffer<Float3, 1>& buffer,
+                                              size_t                       startingOffset,
+                                              size_t                       numValues,
+                                              cl::sycl::queue              queue)
+{
+    cl::sycl::buffer<float, 1> bufferAsFloat = buffer.reinterpret<float, 1>(buffer.get_count() * DIM);
+    return fillSyclBufferWithNull<float>(
+            bufferAsFloat, startingOffset * DIM, numValues * DIM, std::move(queue));
+}
+} // namespace gmx::internal
+
 /*! \brief
  * Clears the device buffer asynchronously.
  *
@@ -377,15 +448,10 @@ void clearDeviceBufferAsync(DeviceBuffer<ValueType>* buffer,
     GMX_ASSERT(checkDeviceBuffer(*buffer, startingOffset + numValues),
                "buffer too small or not initialized");
 
-    const ValueType              pattern{};
     cl::sycl::buffer<ValueType>& syclBuffer = *(buffer->buffer_);
 
-    cl::sycl::event ev = deviceStream.stream().submit([&](cl::sycl::handler& cgh) {
-        auto d_bufferAccessor = cl::sycl::accessor<ValueType, 1, cl::sycl::access::mode::discard_write>{
-            syclBuffer, cgh, cl::sycl::range(numValues), cl::sycl::id(startingOffset)
-        };
-        cgh.fill(d_bufferAccessor, pattern);
-    });
+    gmx::internal::fillSyclBufferWithNull<ValueType>(
+            syclBuffer, startingOffset, numValues, deviceStream.stream());
 }
 
 /*! \brief Create a texture object for an array of type ValueType.
index 6c1b63573292f37f5b94d0990cf464f4ec855950..77891f937dc1b208e3c5af4627653eb7cddddd88 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * \brief
  * Wraps the complexity of including SYCL in GROMACS.
  *
- * SYCL headers use symbol DIM as a template parameter, which gets broken by macro DIM defined
+ * The __SYCL_COMPILER_VERSION macro is used to identify Intel DPCPP compiler.
+ * See https://github.com/intel/llvm/pull/2998 for better proposal.
+ *
+ * Intel SYCL headers use symbol DIM as a template parameter, which gets broken by macro DIM defined
  * in gromacs/math/vectypes.h. Here, we include the SYCL header while temporary undefining this macro.
+ * See https://github.com/intel/llvm/issues/2981.
+ *
+ * Different compilers, at the time of writing, have different names for some of the proposed features
+ * of the SYCL2020 standard. For uniformity, they are all aliased in our custom sycl_2020 namespace.
  *
  * \inlibraryapi
  */
 #ifndef GMX_GPU_UTILS_GMXSYCL_H
 #define GMX_GPU_UTILS_GMXSYCL_H
 
+#include "config.h"
+
+/* Some versions of Intel ICPX compiler (at least 2021.1.1 and 2021.1.2) fail to unroll a loop
+ * in sycl::accessor::__init, and emit -Wpass-failed=transform-warning. This is a useful
+ * warning, but mostly noise right now. Probably related to using shared memory accessors.
+ * The unroll directive was introduced in https://github.com/intel/llvm/pull/2449. */
+#if GMX_SYCL_DPCPP
+#    include <CL/sycl/version.hpp>
+#    define DISABLE_UNROLL_WARNINGS \
+        ((__SYCL_COMPILER_VERSION >= 20201113) && (__SYCL_COMPILER_VERSION <= 20201214))
+#else
+#    define DISABLE_UNROLL_WARNINGS 0
+#endif
+
+#if DISABLE_UNROLL_WARNINGS
+#    pragma clang diagnostic push
+#    pragma clang diagnostic ignored "-Wpass-failed"
+#endif
+
+// For hipSYCL, we need to activate floating-point atomics
+#if GMX_SYCL_HIPSYCL
+#    define HIPSYCL_EXT_FP_ATOMICS
+#    pragma clang diagnostic push
+#    pragma clang diagnostic ignored "-Wunused-variable"
+#    pragma clang diagnostic ignored "-Wunused-parameter"
+#    pragma clang diagnostic ignored "-Wmissing-noreturn"
+#    pragma clang diagnostic ignored "-Wshadow-field"
+#    pragma clang diagnostic ignored "-Wctad-maybe-unsupported"
+#    pragma clang diagnostic ignored "-Wdeprecated-copy-dtor"
+#    pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
+#    pragma clang diagnostic ignored "-Wunused-template"
+#    pragma clang diagnostic ignored "-Wsign-compare"
+#    pragma clang diagnostic ignored "-Wundefined-reinterpret-cast"
+#    pragma clang diagnostic ignored "-Wdeprecated-copy"
+#    pragma clang diagnostic ignored "-Wnewline-eof"
+#    pragma clang diagnostic ignored "-Wextra-semi"
+#    pragma clang diagnostic ignored "-Wsuggest-override"
+#    pragma clang diagnostic ignored "-Wsuggest-destructor-override"
+#    pragma clang diagnostic ignored "-Wgcc-compat"
+#endif
+
 
 #ifdef DIM
 #    if DIM != 3
 #    include <CL/sycl.hpp>
 #endif
 
+#if DISABLE_UNROLL_WARNINGS
+#    pragma clang diagnostic pop
+#endif
+
+#if GMX_SYCL_HIPSYCL
+#    pragma clang diagnostic pop
+#endif
+
+#undef DISABLE_UNROLL_WARNINGS
+
+/* Exposing Intel-specific extensions in a manner compatible with SYCL2020 provisional spec.
+ * Despite ICPX (up to 2021.1.2 at the least) having SYCL_LANGUAGE_VERSION=202001,
+ * some parts of the spec are still in custom sycl::ONEAPI namespace (sycl::intel in beta versions),
+ * and some functions have different names. To make things easier to upgrade
+ * in the future, this thin layer is added.
+ * */
+namespace sycl_2020
+{
+namespace detail
+{
+#if GMX_SYCL_DPCPP
+// Confirmed to work for 2021.1-beta10 (20201005), 2021.1.1 (20201113), 2021.1.2 (20201214).
+namespace origin = cl::sycl::ONEAPI;
+#elif GMX_SYCL_HIPSYCL
+namespace origin = cl::sycl;
+#else
+#    error "Unsupported version of SYCL compiler"
+#endif
+} // namespace detail
+
+using detail::origin::memory_order;
+using detail::origin::memory_scope;
+using detail::origin::plus;
+using detail::origin::sub_group;
+
+#if GMX_SYCL_DPCPP
+using detail::origin::atomic_ref;
+template<typename... Args>
+bool group_any_of(Args&&... args)
+{
+    return detail::origin::any_of(std::forward<Args>(args)...);
+}
+template<typename... Args>
+auto group_reduce(Args&&... args) -> decltype(detail::origin::reduce(std::forward<Args>(args)...))
+{
+    return detail::origin::reduce(std::forward<Args>(args)...);
+}
+#elif GMX_SYCL_HIPSYCL
+// No atomic_ref in hipSYCL yet (2021-02-22)
+using detail::origin::group_any_of;
+using detail::origin::group_reduce;
+#else
+#    error "Unsupported SYCL compiler"
+#endif
+
+} // namespace sycl_2020
+
 #endif
index 1bfbefd0a75735bc77ab622215338eb9c790ac60..bf57d57d3b26e3fc25c35e114b01e04320b6b2fa 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2017,2018,2019, by the GROMACS development team.
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 OPENCL_FUNC_ARGUMENT REAL_FUNC_ARGUMENT
 #    define OPENCL_FUNC_TERM REAL_FUNC_TERM
 #    define OPENCL_FUNC_TERM_WITH_RETURN(arg) REAL_FUNC_TERM_WITH_RETURN(arg)
+#    define SYCL_FUNC_QUALIFIER REAL_FUNC_QUALIFIER
+#    define SYCL_FUNC_ARGUMENT REAL_FUNC_ARGUMENT
+#    define SYCL_FUNC_TERM REAL_FUNC_TERM
+#    define SYCL_FUNC_TERM_WITH_RETURN(arg) REAL_FUNC_TERM_WITH_RETURN(arg)
 
 #else // Not DOXYGEN
 
 /* GPU support is enabled, so these functions will have real code defined somewhere */
-#    if GMX_GPU && !GMX_GPU_SYCL
+#    if GMX_GPU
 #        define GPU_FUNC_QUALIFIER REAL_FUNC_QUALIFIER
 #        define GPU_FUNC_ARGUMENT REAL_FUNC_ARGUMENT
 #        define GPU_FUNC_TERM REAL_FUNC_TERM
@@ -87,7 +92,6 @@
 #        define GPU_FUNC_ARGUMENT NULL_FUNC_ARGUMENT
 #        define GPU_FUNC_TERM NULL_FUNC_TERM
 #        define GPU_FUNC_TERM_WITH_RETURN(arg) NULL_FUNC_TERM_WITH_RETURN(arg)
-#
 #    endif
 
 /* Enable and disable platform-specific function implementations */
 #        define CUDA_FUNC_TERM_WITH_RETURN(arg) NULL_FUNC_TERM_WITH_RETURN(arg)
 #    endif
 
+#    if GMX_GPU_SYCL
+#        define SYCL_FUNC_QUALIFIER REAL_FUNC_QUALIFIER
+#        define SYCL_FUNC_ARGUMENT REAL_FUNC_ARGUMENT
+#        define SYCL_FUNC_TERM REAL_FUNC_TERM
+#        define SYCL_FUNC_TERM_WITH_RETURN(arg) REAL_FUNC_TERM_WITH_RETURN(arg)
+#    else
+#        define SYCL_FUNC_QUALIFIER NULL_FUNC_QUALIFIER
+#        define SYCL_FUNC_ARGUMENT NULL_FUNC_ARGUMENT
+#        define SYCL_FUNC_TERM NULL_FUNC_TERM
+#        define SYCL_FUNC_TERM_WITH_RETURN(arg) NULL_FUNC_TERM_WITH_RETURN(arg)
+#    endif
+
 #endif // ifdef DOXYGEN
 
 #endif // GMX_GPU_UTILS_MACROS_H
index eb26ce0a8e16a5e381363add1747f7f2c5169c39..5fab6b73795b5d496d6b35e163695673ea4960d6 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2017,2018,2019, by the GROMACS development team.
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "config.h"
 
-#include <cassert>
-
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/stringutil.h"
 
 #ifdef _MSC_VER
 #    pragma warning(disable : 6237)
 #endif
 
+const char* enumValueToString(GpuApiCallBehavior enumValue)
+{
+    static constexpr gmx::EnumerationArray<GpuApiCallBehavior, const char*> s_gpuApiCallBehaviorNames = {
+        "Synchronous", "Asynchronous"
+    };
+    return s_gpuApiCallBehaviorNames[enumValue];
+}
+
 /*! \brief Help build a descriptive message in \c error if there are
  * \c errorReasons why nonbondeds on a GPU are not supported.
  *
@@ -79,9 +86,5 @@ bool buildSupportsNonbondedOnGpu(std::string* error)
     {
         errorReasons.emplace_back("non-GPU build of GROMACS");
     }
-    if (GMX_GPU_SYCL)
-    {
-        errorReasons.emplace_back("SYCL build of GROMACS");
-    }
     return addMessageIfNotSupported(errorReasons, error);
 }
index 8df9282b6bc708d5bc77ffb37ce876d8644d2e72..b35fcabd4ab2d357378c33a65eb79a97e2692cca 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014,2015,2016, The GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@
 #include "gromacs/gpu_utils/cudautils.cuh"
 #include "gromacs/gpu_utils/device_context.h"
 #include "gromacs/gpu_utils/device_stream.h"
-#include "gromacs/gpu_utils/pmalloc_cuda.h"
 #include "gromacs/hardware/device_information.h"
 #include "gromacs/hardware/device_management.h"
 #include "gromacs/utility/basedefinitions.h"
@@ -146,7 +145,17 @@ void resetGpuProfiler(void)
     }
 }
 
-/*! \brief Check status returned from peer access CUDA call, and error out or warn appropriately
+/*! \brief Check and act on status returned from peer access CUDA call
+ *
+ * If status is "cudaSuccess", we continue. If
+ * "cudaErrorPeerAccessAlreadyEnabled", then peer access has already
+ * been enabled so we ignore. If "cudaErrorInvalidDevice" then the
+ * run is trying to access an invalid GPU, so we throw an error. If
+ * "cudaErrorInvalidValue" then there is a problem with the arguments
+ * to the CUDA call, and we throw an error. These cover all expected
+ * statuses, but if any other is returned we issue a warning and
+ * continue.
+ *
  * \param[in] stat           CUDA call return status
  * \param[in] gpuA           ID for GPU initiating peer access call
  * \param[in] gpuB           ID for remote GPU
@@ -159,6 +168,14 @@ static void peerAccessCheckStat(const cudaError_t    stat,
                                 const gmx::MDLogger& mdlog,
                                 const char*          cudaCallName)
 {
+
+    if (stat == cudaErrorPeerAccessAlreadyEnabled)
+    {
+        // Since peer access has already been enabled, this error can safely be ignored.
+        // Now clear the error internally within CUDA:
+        cudaGetLastError();
+        return;
+    }
     if ((stat == cudaErrorInvalidDevice) || (stat == cudaErrorInvalidValue))
     {
         std::string errorString =
@@ -172,7 +189,12 @@ static void peerAccessCheckStat(const cudaError_t    stat,
                 .appendTextFormatted(
                         "GPU peer access not enabled between GPUs %d and %d due to unexpected "
                         "return value from %s. %s",
-                        gpuA, gpuB, cudaCallName, gmx::getDeviceErrorString(stat).c_str());
+                        gpuA,
+                        gpuB,
+                        cudaCallName,
+                        gmx::getDeviceErrorString(stat).c_str());
+        // Clear the error internally within CUDA
+        cudaGetLastError();
     }
 }
 
@@ -200,7 +222,8 @@ void setupGpuDevicePeerAccess(const std::vector<int>& gpuIdsToUse, const gmx::MD
                     .appendTextFormatted(
                             "GPU peer access not enabled due to unexpected return value from "
                             "cudaSetDevice(%d). %s",
-                            gpuA, gmx::getDeviceErrorString(stat).c_str());
+                            gpuA,
+                            gmx::getDeviceErrorString(stat).c_str());
             return;
         }
         for (unsigned int j = 0; j < gpuIdsToUse.size(); j++)
index fce1e995802450f160f91f91f9fdf38cbb9fdd6d..378015fb309729f3c1ef5886de03cffdf1b358f5 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2010, The GROMACS development team.
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,12 +60,19 @@ class MDLogger;
 }
 
 //! Enum which is only used to describe transfer calls at the moment
-enum class GpuApiCallBehavior
+enum class GpuApiCallBehavior : int
 {
+    //! Synchronous
     Sync,
-    Async
+    //! Asynchronous
+    Async,
+    //! Size of the enumeration
+    Count
 };
 
+//! String corresponding to GPU API call behavior
+const char* enumValueToString(GpuApiCallBehavior enumValue);
+
 //! Types of actions associated to waiting or checking the completion of GPU tasks
 enum class GpuTaskCompletion
 {
index fee73cdb04b9c77dc503b97cac777afdeef4d822..f40c7d446ff45729b452a04d40662af0e6822b75 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -99,6 +99,14 @@ public:
         GMX_ASSERT(stat == cudaSuccess,
                    ("cudaEventSynchronize failed. " + gmx::getDeviceErrorString(stat)).c_str());
     }
+    /*! \brief Checks the completion of the underlying event and resets the object if it was. */
+    inline bool isReady()
+    {
+        cudaError_t gmx_used_in_debug stat = cudaEventQuery(event_);
+        GMX_ASSERT((stat == cudaSuccess) || (stat == cudaErrorNotReady),
+                   ("cudaEventQuery failed. " + gmx::getDeviceErrorString(stat)).c_str());
+        return (stat == cudaSuccess);
+    }
     /*! \brief Enqueues a wait for the recorded event in stream \p stream */
     inline void enqueueWaitEvent(const DeviceStream& deviceStream)
     {
@@ -106,6 +114,8 @@ public:
         GMX_ASSERT(stat == cudaSuccess,
                    ("cudaStreamWaitEvent failed. " + gmx::getDeviceErrorString(stat)).c_str());
     }
+    //! Reset the event (not needed in CUDA)
+    inline void reset() {}
 
 private:
     cudaEvent_t event_;
index 128e0564ddbfdaf6e4624f0e3f75cbdbb13b0ea7..0b9905450fd4014e1d70827621c96e63395d55ce 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -106,7 +106,24 @@ public:
                                          + ocl_get_error_string(clError)));
         }
 
-        releaseEvent();
+        reset();
+    }
+    /*! \brief Checks the completion of the underlying event and resets the object if it was. */
+    inline bool isReady()
+    {
+        cl_int result;
+        cl_int clError = clGetEventInfo(
+                event_, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(cl_int), &result, nullptr);
+        if (CL_SUCCESS != clError)
+        {
+            GMX_THROW(gmx::InternalError("Failed to retrieve event info: " + ocl_get_error_string(clError)));
+        }
+        bool hasTriggered = (result == CL_COMPLETE);
+        if (hasTriggered)
+        {
+            reset();
+        }
+        return hasTriggered;
     }
     /*! \brief Enqueues a wait for the recorded event in stream \p stream
      *
@@ -122,11 +139,11 @@ public:
                                          + ocl_get_error_string(clError)));
         }
 
-        releaseEvent();
+        reset();
     }
 
-private:
-    inline void releaseEvent()
+    //! Reset (release) the event to unmarked state.
+    inline void reset()
     {
         cl_int clError = clReleaseEvent(event_);
         if (CL_SUCCESS != clError)
@@ -137,6 +154,7 @@ private:
         event_ = nullptr;
     }
 
+private:
     cl_event event_;
 };
 
index 1daa5b9f32db44c215efa5df3b60c36b2fd4808b..470c89aac7e915ae00bf0a5ed764deb918076d68 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +81,10 @@ class GpuEventSynchronizer
 {
 public:
     //! A constructor.
-    GpuEventSynchronizer() = default;
+    GpuEventSynchronizer()
+    {
+        doNotSynchronizeBetweenStreams_ = (std::getenv("GMX_GPU_SYCL_NO_SYNCHRONIZE") != nullptr);
+    }
     //! A constructor from an existing event.
     GpuEventSynchronizer(const cl::sycl::event& event) : event_(event) {}
     //! A destructor.
@@ -98,31 +101,70 @@ public:
      */
     inline void markEvent(const DeviceStream& deviceStream)
     {
+#    if GMX_SYCL_HIPSYCL
+        deviceStream.stream().wait_and_throw(); // SYCL-TODO: Use CUDA/HIP-specific solutions
+#    else
         GMX_ASSERT(!event_.has_value(), "Do not call markEvent more than once!");
         // Relies on SYCL_INTEL_enqueue_barrier
         event_ = deviceStream.stream().submit_barrier();
+#    endif
     }
     /*! \brief Synchronizes the host thread on the marked event.
      * As in the OpenCL implementation, the event is released.
      */
     inline void waitForEvent()
     {
+#    if (!GMX_SYCL_HIPSYCL)
         event_->wait_and_throw();
+#    endif
         event_.reset();
     }
+    /*! \brief Checks the completion of the underlying event and resets the object if it was. */
+    inline bool isReady()
+    {
+        auto info         = event_->get_info<cl::sycl::info::event::command_execution_status>();
+        bool hasTriggered = (info == cl::sycl::info::event_command_status::complete);
+        if (hasTriggered)
+        {
+            event_.reset();
+        }
+        return hasTriggered;
+    }
     /*! \brief Enqueues a wait for the recorded event in stream \p deviceStream.
      * As in the OpenCL implementation, the event is released.
      */
     inline void enqueueWaitEvent(const DeviceStream& deviceStream)
     {
+        if (doNotSynchronizeBetweenStreams_)
+        {
+            event_.reset();
+            return;
+        }
+#    if GMX_SYCL_HIPSYCL
+        deviceStream.stream().wait_and_throw(); // SYCL-TODO: Use CUDA/HIP-specific solutions
+#    else
         // Relies on SYCL_INTEL_enqueue_barrier
         const std::vector<cl::sycl::event> waitlist{ event_.value() };
         deviceStream.stream().submit_barrier(waitlist);
         event_.reset();
+#    endif
     }
+    //! Reset the event to unmarked state.
+    inline void reset() { event_.reset(); }
+    //! Check if the event is marked. Needed for some workarounds for #3988
+    inline bool isMarked() const { return event_.has_value(); }
 
 private:
     std::optional<cl::sycl::event> event_ = std::nullopt;
+    /*! \brief Dev. setting to no-op enqueueWaitEvent
+     *
+     * In SYCL, dependencies between the GPU tasks are managed by the runtime, so manual
+     * synchronization between GPU streams should be redundant, but we keep it on by default.
+     *
+     * Setting this to \c true via \c GMX_GPU_SYCL_NO_SYNCHRONIZE environment variable will
+     * immediately return from \ref enqueueWaitEvent, without placing a barrier into the stream.
+     */
+    bool doNotSynchronizeBetweenStreams_;
 };
 
 #endif // !defined DOXYGEN
index 3434a451e477fb3442d94bf59ff6d36ecd7f8b43..8adaf08eefef775c53f83c97c5f12c5b4c6bef28 100644 (file)
@@ -97,17 +97,19 @@ public:
                 cl_ulong start_ns, end_ns;
                 cl_int gmx_unused cl_error;
 
-                cl_error = clGetEventProfilingInfo(events_[i], CL_PROFILING_COMMAND_START,
-                                                   sizeof(cl_ulong), &start_ns, nullptr);
+                cl_error = clGetEventProfilingInfo(
+                        events_[i], CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start_ns, nullptr);
                 GMX_ASSERT(CL_SUCCESS == cl_error,
                            gmx::formatString("GPU timing update failure (OpenCL error %d: %s).",
-                                             cl_error, ocl_get_error_string(cl_error).c_str())
+                                             cl_error,
+                                             ocl_get_error_string(cl_error).c_str())
                                    .c_str());
-                cl_error = clGetEventProfilingInfo(events_[i], CL_PROFILING_COMMAND_END,
-                                                   sizeof(cl_ulong), &end_ns, nullptr);
+                cl_error = clGetEventProfilingInfo(
+                        events_[i], CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &end_ns, nullptr);
                 GMX_ASSERT(CL_SUCCESS == cl_error,
                            gmx::formatString("GPU timing update failure (OpenCL error %d: %s).",
-                                             cl_error, ocl_get_error_string(cl_error).c_str())
+                                             cl_error,
+                                             ocl_get_error_string(cl_error).c_str())
                                    .c_str());
                 milliseconds += (end_ns - start_ns) / 1000000.0;
             }
index fec113b4b4c1f4bcd1414e1ee8cfd4d4478b687f..656e8a231969a5bc85da806e01ab120b04504799 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
  * \ingroup module_gpu_utils
  */
 #include <cuda_runtime.h>
+#include "gromacs/math/vectypes.h"
 
 //! Device texture for fast read-only data fetching
 using DeviceTexture = cudaTextureObject_t;
@@ -52,6 +53,15 @@ using DeviceTexture = cudaTextureObject_t;
 //! \brief Single GPU call timing event - meaningless in CUDA
 using CommandEvent = void;
 
+//! Convenience alias for 2-wide float
+using Float2 = float2;
+
+//! Convenience alias for 3-wide float
+using Float3 = gmx::RVec;
+
+//! Convenience alias for 4-wide float.
+using Float4 = float4;
+
 /*! \internal \brief
  * GPU kernels scheduling description. This is same in OpenCL/CUDA.
  * Provides reasonable defaults, one typically only needs to set the GPU stream
index 38c5edf8a90d0b87bcaf6a2fd48065bd4c4a26b6..344b0427c1ae335fd03a69e890e1dd974e9d3ec8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +66,56 @@ using DeviceTexture = void*;
 //! \brief Single GPU call timing event
 using CommandEvent = void*;
 
+// Stubs for CPU-only build. Might be changed in #3312.
+struct Float2
+{
+};
+struct Float3
+{
+};
+struct Float4
+{
+};
+
 #endif // GMX_GPU
 
+namespace gmx
+{
+template<typename T>
+static inline Float3* asGenericFloat3Pointer(T* in)
+{
+    static_assert(sizeof(T) == sizeof(Float3),
+                  "Size of the host-side data-type is different from the size of the generic "
+                  "device-side counterpart.");
+    return reinterpret_cast<Float3*>(in);
+}
+
+template<typename T>
+static inline const Float3* asGenericFloat3Pointer(const T* in)
+{
+    static_assert(sizeof(T) == sizeof(Float3),
+                  "Size of the host-side data-type is different from the size of the generic "
+                  "device-side counterpart.");
+    return reinterpret_cast<const Float3*>(in);
+}
+
+template<typename C>
+static inline Float3* asGenericFloat3Pointer(C& in)
+{
+    static_assert(sizeof(*in.data()) == sizeof(Float3),
+                  "Size of the host-side data-type is different from the size of the device-side "
+                  "counterpart.");
+    return reinterpret_cast<Float3*>(in.data());
+}
+
+template<typename C>
+static inline const Float3* asGenericFloat3Pointer(const C& in)
+{
+    static_assert(sizeof(*in.data()) == sizeof(Float3),
+                  "Size of the host-side data-type is different from the size of the device-side "
+                  "counterpart.");
+    return reinterpret_cast<const Float3*>(in.data());
+}
+} // namespace gmx
+
 #endif // GMX_GPU_UTILS_GPUTRAITS_H
index 489bb0527c0b34a016d7e7462db236722336d9aa..a8a3c2681816c214cc7976b97c3625c367cbf84d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gpu_utils/gmxopencl.h"
+#include "gromacs/math/vectypes.h"
 
 using DeviceTexture = void*;
 
 //! \brief Single GPU call timing event
 using CommandEvent = cl_event;
 
+//! Convenience alias for 2-wide float
+using Float2 = cl_float2;
+
+//! Convenience alias for 3-wide float. Not using cl_float3 due to alignment issues.
+using Float3 = gmx::RVec;
+
+//! Convenience alias for 4-wide float.
+using Float4 = cl_float4;
+
 /*! \internal \brief
  * GPU kernels scheduling description. This is same in OpenCL/CUDA.
  * Provides reasonable defaults, one typically only needs to set the GPU stream
index 52e40bb8369257d90666e8c4470fcc4d7670ed8c..9c64d3f303ba2b875c7708c5fca4d7e1952cf874 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstddef>
 
 #include "gromacs/gpu_utils/gmxsycl.h"
+#include "gromacs/math/vectypes.h"
 
 using DeviceTexture = void*;
 
 //! \brief Single GPU call timing event, not used with SYCL
 using CommandEvent = void*;
 
+// TODO: Issue #3312
 //! Convenience alias.
-using float4 = cl::sycl::float4;
-
+using Float4 = cl::sycl::float4;
 //! Convenience alias. Not using cl::sycl::float3 due to alignment issues.
-using float3 = gmx::RVec;
-
+using Float3 = gmx::RVec;
 //! Convenience alias for cl::sycl::float2
-using float2 = cl::sycl::float2;
+using Float2 = cl::sycl::float2;
 
 /*! \internal \brief
  * GPU kernels scheduling description. This is same in OpenCL/CUDA.
index e8894aaad00b87eabd966f53695e9601ddb71b8a..bdc71c69bcc1b42fe3c5a246b7aea15313d1819a 100644 (file)
@@ -75,8 +75,8 @@ std::string makeBinaryCacheFilename(const std::string& kernelFilename, cl_device
     // assume that sizeof(char) is one byte.
     std::array<char, 1024> deviceName;
     size_t                 deviceNameLength;
-    cl_int                 cl_error = clGetDeviceInfo(deviceId, CL_DEVICE_NAME, deviceName.size(),
-                                      deviceName.data(), &deviceNameLength);
+    cl_int                 cl_error = clGetDeviceInfo(
+            deviceId, CL_DEVICE_NAME, deviceName.size(), deviceName.data(), &deviceNameLength);
     if (cl_error != CL_SUCCESS)
     {
         GMX_THROW(InternalError(formatString("Could not get OpenCL device name, error was %s",
@@ -94,8 +94,10 @@ std::string makeBinaryCacheFilename(const std::string& kernelFilename, cl_device
        (symbols), by permitting only alphanumeric characters from the
        current locale. We assume these work well enough in a
        filename. */
-    std::copy_if(deviceName.begin(), deviceName.begin() + deviceNameLength,
-                 std::back_inserter(cacheFilename), isalnum);
+    std::copy_if(deviceName.begin(),
+                 deviceName.begin() + deviceNameLength,
+                 std::back_inserter(cacheFilename),
+                 isalnum);
     cacheFilename += ".bin";
 
     return cacheFilename;
@@ -134,9 +136,8 @@ cl_program makeProgramFromCache(const std::string& filename, cl_context context,
 
     /* Create program from pre-built binary */
     cl_int     cl_error;
-    cl_program program = clCreateProgramWithBinary(context, 1, &deviceId, &fileSize,
-                                                   const_cast<const unsigned char**>(&binary),
-                                                   nullptr, &cl_error);
+    cl_program program = clCreateProgramWithBinary(
+            context, 1, &deviceId, &fileSize, const_cast<const unsigned char**>(&binary), nullptr, &cl_error);
     if (cl_error != CL_SUCCESS)
     {
         GMX_THROW(InternalError("Could not create OpenCL program from the cache file " + filename
index 1f670e8b910e26d6d4624ded3bf8b451ed76b9c8..c8ed6f19c54a00b76cd53b12fbd619c145ef187f 100644 (file)
@@ -126,8 +126,8 @@ static void writeOclBuildLog(FILE*              fplog,
         buildLogGuard.reset(buildLog);
 
         /* Get the actual compilation log */
-        cl_error = clGetProgramBuildInfo(program, deviceId, CL_PROGRAM_BUILD_LOG, buildLogSize,
-                                         buildLog, nullptr);
+        cl_error = clGetProgramBuildInfo(
+                program, deviceId, CL_PROGRAM_BUILD_LOG, buildLogSize, buildLog, nullptr);
         if (cl_error != CL_SUCCESS)
         {
             GMX_THROW(InternalError("Could not get OpenCL program build log, error was "
@@ -248,9 +248,8 @@ static std::string getSourceRootPath(const std::string& sourceRelativePath)
 size_t getKernelWarpSize(cl_kernel kernel, cl_device_id deviceId)
 {
     size_t warpSize = 0;
-    cl_int cl_error =
-            clGetKernelWorkGroupInfo(kernel, deviceId, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE,
-                                     sizeof(warpSize), &warpSize, nullptr);
+    cl_int cl_error = clGetKernelWorkGroupInfo(
+            kernel, deviceId, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, sizeof(warpSize), &warpSize, nullptr);
     if (cl_error != CL_SUCCESS)
     {
         GMX_THROW(InternalError("Could not query OpenCL preferred workgroup size, error was "
@@ -450,7 +449,8 @@ cl_program compileProgram(FILE*              fplog,
                 // Failing to read from the cache is not a critical error
                 formatExceptionMessageToFile(fplog, e);
             }
-            fprintf(fplog, "OpenCL binary cache file %s is present, will load kernels.\n",
+            fprintf(fplog,
+                    "OpenCL binary cache file %s is present, will load kernels.\n",
                     cacheFilename.c_str());
         }
         else
@@ -487,8 +487,7 @@ cl_program compileProgram(FILE*              fplog,
 
     /* Write log first, and then throw exception that the user know what is
        the issue even if the build fails. */
-    writeOclBuildLog(fplog, program, deviceId, kernelFilename, preprocessorOptions,
-                     buildStatus != CL_SUCCESS);
+    writeOclBuildLog(fplog, program, deviceId, kernelFilename, preprocessorOptions, buildStatus != CL_SUCCESS);
 
     if (buildStatus != CL_SUCCESS)
     {
index 726e4f2cff47fdfd65afc75b5b80dacc20823700..d5ee96fd55b5d16e3d2b774ba71e010bd79e491e 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gpu_utils/gpu_utils.h"
-#include "gromacs/utility/fatalerror.h"
-#include "gromacs/utility/smalloc.h"
 
-/*! \brief \brief Allocates nbytes of host memory. Use ocl_free to free memory allocated with this function.
- *
- *  \todo
- *  This function should allocate page-locked memory to help reduce D2H and H2D
- *  transfer times, similar with pmalloc from pmalloc_cuda.cu.
- *
- * \param[in,out]    h_ptr   Pointer where to store the address of the newly allocated buffer.
- * \param[in]        nbytes  Size in bytes of the buffer to be allocated.
- */
-void pmalloc(void** h_ptr, size_t nbytes)
-{
-    /* Need a temporary type whose size is 1 byte, so that the
-     * implementation of snew_aligned can cope without issuing
-     * warnings. */
-    char** temporary = reinterpret_cast<char**>(h_ptr);
-
-    /* 16-byte alignment is required by the neighbour-searching code,
-     * because it uses four-wide SIMD for bounding-box calculation.
-     * However, when we organize using page-locked memory for
-     * device-host transfers, it will probably need to be aligned to a
-     * 4kb page, like CUDA does. */
-    snew_aligned(*temporary, nbytes, 16);
-}
-
-/*! \brief Frees memory allocated with pmalloc.
- *
- * \param[in]    h_ptr   Buffer allocated with pmalloc that needs to be freed.
- */
-void pfree(void* h_ptr)
-{
-
-    if (h_ptr)
-    {
-        sfree_aligned(h_ptr);
-    }
-}
 
 /*! \brief Convert error code to diagnostic string */
 std::string ocl_get_error_string(cl_int error)
index e5d4f6da3362320f5b9227c00a77380f609d64f8..5f881c33c4fc7921693e11da06c7049c043767ef 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,12 +71,6 @@ struct gmx_device_runtime_data_t
     cl_program program;
 };
 
-/*! \brief Allocate host memory in malloc style */
-void pmalloc(void** h_ptr, size_t nbytes);
-
-/*! \brief Free host memory in malloc style */
-void pfree(void* h_ptr);
-
 /*! \brief Convert error code to diagnostic string */
 std::string ocl_get_error_string(cl_int error);
 
@@ -189,9 +183,15 @@ inline void launchGpuKernel(cl_kernel                 kernel,
     {
         globalWorkSize[i] = config.gridSize[i] * config.blockSize[i];
     }
-    cl_int clError = clEnqueueNDRangeKernel(deviceStream.stream(), kernel, workDimensions,
-                                            globalWorkOffset, globalWorkSize, config.blockSize,
-                                            waitListSize, waitList, timingEvent);
+    cl_int clError = clEnqueueNDRangeKernel(deviceStream.stream(),
+                                            kernel,
+                                            workDimensions,
+                                            globalWorkOffset,
+                                            globalWorkSize,
+                                            config.blockSize,
+                                            waitListSize,
+                                            waitList,
+                                            timingEvent);
     if (CL_SUCCESS != clError)
     {
         const std::string errorMessage = "GPU kernel (" + std::string(kernelName)
similarity index 78%
rename from src/gromacs/gpu_utils/pmalloc_cuda.cu
rename to src/gromacs/gpu_utils/pmalloc.cu
index 2d5e1220529a245011656c69e6c66d40b9ab3b5c..3a8f1058fe992c19a1822f90df4c6ae9461688cc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2014,2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -40,7 +40,7 @@
 
 #include "gmxpre.h"
 
-#include "pmalloc_cuda.h"
+#include "pmalloc.h"
 
 #include <stdlib.h>
 
@@ -70,29 +70,6 @@ void pmalloc(void** h_ptr, size_t nbytes)
     CU_RET_ERR(stat, strbuf);
 }
 
-/*! Allocates nbytes of page-locked memory with write-combining.
- *  This memory should always be freed using pfree (or with the page-locked
- *  free functions provied by the CUDA library).
- */
-void pmalloc_wc(void** h_ptr, size_t nbytes)
-{
-    cudaError_t stat;
-    char        strbuf[STRLEN];
-    int         flag = cudaHostAllocDefault | cudaHostAllocWriteCombined;
-
-    if (nbytes == 0)
-    {
-        *h_ptr = nullptr;
-        return;
-    }
-
-    gmx::ensureNoPendingDeviceError("Could not allocate page-locked memory with write-combining.");
-
-    stat = cudaMallocHost(h_ptr, nbytes, flag);
-    sprintf(strbuf, "cudaMallocHost of size %d bytes failed", (int)nbytes);
-    CU_RET_ERR(stat, strbuf);
-}
-
 /*! Frees page locked memory allocated with pmalloc.
  *  This function can safely be called also with a pointer to a page-locked
  *  memory allocated directly with CUDA API calls.
similarity index 85%
rename from src/gromacs/gpu_utils/pmalloc_cuda.h
rename to src/gromacs/gpu_utils/pmalloc.h
index d9ab9e088d21526db95dd5064d68a1f1321df884..d6b2707556b21accf5600396f59b3fb06b890382 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 /*! \libinternal \file
- *  \brief Declare functions for host-side memory handling when using CUDA devices.
+ *  \brief Declare functions for host-side memory handling.
  *
  *  \author Szilard Pall <pall.szilard@gmail.com>
  *  \inlibraryapi
  */
-#ifndef GMX_GPU_UTILS_PMALLOC_CUDA_H
-#define GMX_GPU_UTILS_PMALLOC_CUDA_H
+#ifndef GMX_GPU_UTILS_PMALLOC_H
+#define GMX_GPU_UTILS_PMALLOC_H
 
 #include <stdlib.h>
 
@@ -51,9 +51,6 @@
 /*! \brief Allocates nbytes of page-locked memory. */
 void pmalloc(void** h_ptr, size_t nbytes);
 
-/*! \brief Allocates nbytes of page-locked memory with write-combining. */
-void pmalloc_wc(void** h_ptr, size_t nbytes);
-
 /*! \brief Frees page locked memory allocated with pmalloc. */
 void pfree(void* h_ptr);
 
diff --git a/src/gromacs/gpu_utils/pmalloc_ocl.cpp b/src/gromacs/gpu_utils/pmalloc_ocl.cpp
new file mode 100644 (file)
index 0000000..9ac9d77
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2012,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 Define functions for host-side memory handling when using OpenCL devices.
+ *
+ *  \author Anca Hamuraru <anca@streamcomputing.eu>
+ */
+
+#include "gmxpre.h"
+
+#include "pmalloc.h"
+
+#include "gromacs/utility/smalloc.h"
+
+/*! \brief \brief Allocates nbytes of host memory. Use pfree to free memory allocated with this function.
+ *
+ *  \todo
+ *  This function should allocate page-locked memory to help reduce D2H and H2D
+ *  transfer times, similar with pmalloc from pmalloc.cu.
+ *
+ * \param[in,out]    h_ptr   Pointer where to store the address of the newly allocated buffer.
+ * \param[in]        nbytes  Size in bytes of the buffer to be allocated.
+ */
+void pmalloc(void** h_ptr, size_t nbytes)
+{
+    /* Need a temporary type whose size is 1 byte, so that the
+     * implementation of snew_aligned can cope without issuing
+     * warnings. */
+    char** temporary = reinterpret_cast<char**>(h_ptr);
+
+    /* 16-byte alignment is required by the neighbour-searching code,
+     * because it uses four-wide SIMD for bounding-box calculation.
+     * However, when we organize using page-locked memory for
+     * device-host transfers, it will probably need to be aligned to a
+     * 4kb page, like CUDA does. */
+    snew_aligned(*temporary, nbytes, 16);
+}
+
+/*! \brief Frees memory allocated with pmalloc.
+ *
+ * \param[in]    h_ptr   Buffer allocated with pmalloc that needs to be freed.
+ */
+void pfree(void* h_ptr)
+{
+
+    if (h_ptr)
+    {
+        sfree_aligned(h_ptr);
+    }
+}
diff --git a/src/gromacs/gpu_utils/pmalloc_sycl.cpp b/src/gromacs/gpu_utils/pmalloc_sycl.cpp
new file mode 100644 (file)
index 0000000..839409b
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2012,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 Define utility routines for SYCL
+ *
+ *  \author Andrey Alekseenko <al42and@gmail.com>
+ */
+#include "gmxpre.h"
+
+#include "pmalloc.h"
+
+#include "gromacs/utility/smalloc.h"
+
+/*! \brief Allocates \p nbytes of host memory. Use \c pfree to free memory allocated with this function.
+ *
+ *  \todo
+ *  This function was copied from OpenCL implementation, not tuned for SYCL at all.
+ *  Once SYCL2020 is out, might be worthwhile to look into USM and sycl::malloc_host / sycl::aligned_alloc_host.
+ *  Overall, it is better to directly use sycl::buffer instead of pinned arrays. But this function
+ *  is needed to compile some PME code with SYCL enabled, even if it is never used.
+ *
+ * \param[in,out]    h_ptr   Pointer where to store the address of the newly allocated buffer.
+ * \param[in]        nbytes  Size in bytes of the buffer to be allocated.
+ */
+void pmalloc(void** h_ptr, size_t nbytes)
+{
+    /* Need a temporary type whose size is 1 byte, so that the
+     * implementation of snew_aligned can cope without issuing
+     * warnings. */
+    auto** temporary = reinterpret_cast<std::byte**>(h_ptr);
+
+    /* 16-byte alignment inherited from OpenCL and does not sound unreasonable */
+    snew_aligned(*temporary, nbytes, 16);
+}
+
+/*! \brief Frees memory allocated with pmalloc.
+ *
+ * \param[in]    h_ptr   Buffer allocated with pmalloc that needs to be freed.
+ */
+void pfree(void* h_ptr)
+{
+    if (h_ptr)
+    {
+        sfree_aligned(h_ptr);
+    }
+}
diff --git a/src/gromacs/gpu_utils/sycl_kernel_utils.h b/src/gromacs/gpu_utils/sycl_kernel_utils.h
new file mode 100644 (file)
index 0000000..b261d9d
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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_GPU_UTILS_SYCL_KERNEL_UTILS_H
+#define GMX_GPU_UTILS_SYCL_KERNEL_UTILS_H
+
+#include "gmxsycl.h"
+
+/*! \file
+ *  \brief SYCL kernel helper functions.
+ *
+ *  \author Andrey Alekseenko <al42and@gmail.com>
+ */
+
+/*! \brief Access mode to use for atomic accessors.
+ *
+ * Intel DPCPP compiler has \c sycl::atomic_ref, but has no \c sycl::atomic_fetch_add for floats.
+ * However, \c atomic_ref can not be constructed from \c sycl::atomic, so we can not use
+ * atomic accessors. Thus, we use \c mode::read_write accessors and \c atomic_ref.
+ *
+ * hipSYCL does not have \c sycl::atomic_ref, but has \c sycl::atomic_fetch_add for floats, which
+ * requires using atomic accessors. Thus, we use \c mode::atomic accessors.
+ *
+ * The \ref atomicFetchAdd function could be used for doing operations on such accessors.
+ */
+static constexpr auto mode_atomic = GMX_SYCL_DPCPP ? cl::sycl::access::mode::read_write :
+                                                   /* GMX_SYCL_HIPSYCL */ cl::sycl::access::mode::atomic;
+
+/*! \brief Convenience wrapper to do atomic addition to a global buffer.
+ *
+ * The implementation differences between DPCPP and hipSYCL are explained in \ref mode_atomic.
+ */
+template<class IndexType>
+static inline void atomicFetchAdd(DeviceAccessor<float, mode_atomic> acc, const IndexType idx, const float val)
+{
+#if GMX_SYCL_DPCPP
+    sycl_2020::atomic_ref<float, sycl_2020::memory_order::relaxed, sycl_2020::memory_scope::device, cl::sycl::access::address_space::global_space>
+            fout_atomic(acc[idx]);
+    fout_atomic.fetch_add(val);
+#elif GMX_SYCL_HIPSYCL
+#    ifdef SYCL_DEVICE_ONLY
+    /* While there is support for float atomics on device, the host implementation uses
+     * Clang's __atomic_fetch_add intrinsic, that, at least in Clang 11, does not support
+     * floats. Luckily, we don't want to run on host. */
+    acc[idx].fetch_add(val);
+#    else
+    GMX_ASSERT(false, "hipSYCL host codepath not supported");
+    GMX_UNUSED_VALUE(val);
+    GMX_UNUSED_VALUE(acc);
+    GMX_UNUSED_VALUE(idx);
+#    endif
+#endif
+}
+
+namespace sycl_2020
+{
+#if GMX_SYCL_HIPSYCL
+__device__ static inline float shift_left(sycl_2020::sub_group, float var, sycl_2020::sub_group::linear_id_type delta)
+{
+    // No sycl::sub_group::shift_left / shuffle_down in hipSYCL yet
+#    ifdef SYCL_DEVICE_ONLY
+#        if defined(HIPSYCL_PLATFORM_CUDA) && defined(__HIPSYCL_ENABLE_CUDA_TARGET__)
+    static const unsigned int sc_cudaFullWarpMask = 0xffffffff;
+    return __shfl_down_sync(sc_cudaFullWarpMask, var, delta);
+#        elif defined(HIPSYCL_PLATFORM_ROCM) && defined(__HIPSYCL_ENABLE_HIP_TARGET__)
+    // Do we need more ifdefs? https://github.com/ROCm-Developer-Tools/HIP/issues/1491
+    return __shfl_down(var, delta);
+#        else
+#            error "Unsupported hipSYCL target"
+#        endif
+#    else
+    // Should never be called
+    GMX_UNUSED_VALUE(var);
+    GMX_UNUSED_VALUE(delta);
+    assert(false);
+    return NAN;
+#    endif
+}
+__host__ static inline float shift_left(sycl_2020::sub_group, float, sycl_2020::sub_group::linear_id_type)
+{
+    // Should never be called
+    assert(false);
+    return NAN;
+}
+#elif GMX_SYCL_DPCPP
+static inline float shift_left(sycl_2020::sub_group sg, float var, sycl_2020::sub_group::linear_id_type delta)
+{
+    return sg.shuffle_down(var, delta);
+}
+#endif
+
+#if GMX_SYCL_HIPSYCL
+__device__ static inline float shift_right(sycl_2020::sub_group,
+                                           float                                var,
+                                           sycl_2020::sub_group::linear_id_type delta)
+{
+    // No sycl::sub_group::shift_right / shuffle_up in hipSYCL yet
+#    ifdef SYCL_DEVICE_ONLY
+#        if defined(HIPSYCL_PLATFORM_CUDA) && defined(__HIPSYCL_ENABLE_CUDA_TARGET__)
+    static const unsigned int sc_cudaFullWarpMask = 0xffffffff;
+    return __shfl_up_sync(sc_cudaFullWarpMask, var, delta);
+#        elif defined(HIPSYCL_PLATFORM_ROCM) && defined(__HIPSYCL_ENABLE_HIP_TARGET__)
+    // Do we need more ifdefs? https://github.com/ROCm-Developer-Tools/HIP/issues/1491
+    return __shfl_up(var, delta);
+#        else
+#            error "Unsupported hipSYCL target"
+#        endif
+#    else
+    // Should never be called
+    assert(false);
+    GMX_UNUSED_VALUE(var);
+    GMX_UNUSED_VALUE(delta);
+    return NAN;
+#    endif
+}
+__host__ static inline float shift_right(sycl_2020::sub_group, float, sycl_2020::sub_group::linear_id_type)
+{
+    // Should never be called
+    assert(false);
+    return NAN;
+}
+#elif GMX_SYCL_DPCPP
+static inline float shift_right(sycl_2020::sub_group sg, float var, sycl_2020::sub_group::linear_id_type delta)
+{
+    return sg.shuffle_up(var, delta);
+}
+#endif
+} // namespace sycl_2020
+
+#endif /* GMX_GPU_UTILS_SYCL_KERNEL_UTILS_H */
diff --git a/src/gromacs/gpu_utils/syclutils.h b/src/gromacs/gpu_utils/syclutils.h
new file mode 100644 (file)
index 0000000..ffa4be2
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 Declare utility routines for SYCL
+ *
+ *  \author Andrey Alekseenko <al42and@gmail.com>
+ *  \inlibraryapi
+ */
+#ifndef GMX_GPU_UTILS_SYCLUTILS_H
+#define GMX_GPU_UTILS_SYCLUTILS_H
+
+#include <string>
+
+#include "gromacs/gpu_utils/gmxsycl.h"
+#include "gromacs/gpu_utils/gputraits.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/stringutil.h"
+
+class DeviceStream;
+enum class GpuApiCallBehavior;
+
+/*! \internal
+ * \brief SYCL GPU runtime data
+ *
+ * The device runtime data is meant to hold objects associated with a GROMACS rank's
+ * (thread or process) use of a single device (multiple devices per rank is not
+ * implemented). These objects should be constructed at the point where a device
+ * gets assigned to a rank and released at when this assignment is no longer valid
+ * (i.e. at cleanup in the current implementation).
+ */
+struct gmx_device_runtime_data_t
+{
+};
+
+#ifndef DOXYGEN
+
+/* To properly mark function as [[noreturn]], we must do it everywhere it is declared, which
+ * will pollute common headers.*/
+#    pragma clang diagnostic push
+#    pragma clang diagnostic ignored "-Wmissing-noreturn"
+
+/*! \brief
+ * A wrapper function for setting up all the SYCL kernel arguments.
+ * Calls the recursive functions above.
+ *
+ * \tparam    Args            Types of all the kernel arguments
+ * \param[in] kernel          Kernel function handle
+ * \param[in] config          Kernel configuration for launching
+ * \param[in] argsPtrs        Pointers to all the kernel arguments
+ * \returns A handle for the prepared parameter pack to be used with launchGpuKernel() as the last argument.
+ */
+template<typename... Args>
+void* prepareGpuKernelArguments(void* /*kernel*/, const KernelLaunchConfig& /*config*/, const Args*... /*argsPtrs*/)
+{
+    GMX_THROW(gmx::NotImplementedError("Not implemented on SYCL yet"));
+}
+
+/*! \brief Launches the SYCL kernel and handles the errors.
+ *
+ * \param[in] kernel          Kernel function handle
+ * \param[in] config          Kernel configuration for launching
+ * \param[in] deviceStream    GPU stream to launch kernel in
+ * \param[in] timingEvent     Timing event, fetched from GpuRegionTimer
+ * \param[in] kernelName      Human readable kernel description, for error handling only
+ * \throws gmx::InternalError on kernel launch failure
+ */
+inline void launchGpuKernel(void* /*kernel*/,
+                            const KernelLaunchConfig& /*config*/,
+                            const DeviceStream& /*deviceStream*/,
+                            CommandEvent* /*timingEvent*/,
+                            const char* /*kernelName*/,
+                            const void* /*kernelArgs*/)
+{
+    GMX_THROW(gmx::NotImplementedError("Not implemented on SYCL yet"));
+}
+
+/*! \brief Pretend to check a SYCL stream for unfinished work (dummy implementation).
+ *
+ *  \returns  Not implemented in SYCL.
+ */
+static inline bool haveStreamTasksCompleted(const DeviceStream& /* deviceStream */)
+{
+    GMX_THROW(gmx::NotImplementedError("Not implemented on SYCL yet"));
+}
+
+#    pragma clang diagnostic pop
+
+#endif // !DOXYGEN
+
+#endif
diff --git a/src/gromacs/gpu_utils/tests/.clang-tidy b/src/gromacs/gpu_utils/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 3acfee02045a962f0b9e37c86fbed542ecb21036..8cddef033da962e11e12f07fadd4d74ccad09ec7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +52,7 @@
 #    include "gromacs/gpu_utils/device_context.h"
 #    include "gromacs/gpu_utils/device_stream.h"
 #    include "gromacs/gpu_utils/devicebuffer.h"
+#    include "gromacs/gpu_utils/hostallocator.h"
 
 #    include "testutils/test_hardware_environment.h"
 #    include "testutils/testasserts.h"
@@ -142,72 +143,157 @@ const gmx::RVec c_initialValue<gmx::RVec> = { 1, -2, 3 };
 
 TYPED_TEST(DeviceBufferTest, CanCopyToAndFromDevice)
 {
-    for (const auto& testDevice : getTestHardwareEnvironment()->getTestDeviceList())
+    for (auto transferKind : { GpuApiCallBehavior::Sync, GpuApiCallBehavior::Async })
     {
-        const DeviceContext& deviceContext = testDevice->deviceContext();
-        const DeviceStream&  deviceStream  = testDevice->deviceStream();
-        setActiveDevice(testDevice->deviceInfo());
-
-        DeviceBuffer<TypeParam> buffer;
-        int                     numValues = 123;
-        allocateDeviceBuffer(&buffer, numValues, deviceContext);
-        std::vector<TypeParam> valuesIn(numValues);
-        std::vector<TypeParam> valuesOut(numValues);
-
-        std::iota(valuesIn.begin(), valuesIn.end(), c_initialValue<TypeParam>);
-
-        copyToDeviceBuffer(&buffer, valuesIn.data(), 0, numValues, deviceStream,
-                           GpuApiCallBehavior::Sync, nullptr);
-        copyFromDeviceBuffer(valuesOut.data(), &buffer, 0, numValues, deviceStream,
-                             GpuApiCallBehavior::Sync, nullptr);
-        EXPECT_THAT(valuesOut, Pointwise(Eq(), valuesIn)) << "Changed after H2D and D2H copy.";
-        freeDeviceBuffer(&buffer);
+        PinningPolicy pinningPolicy = (transferKind == GpuApiCallBehavior::Async)
+                                              ? PinningPolicy::PinnedIfSupported
+                                              : PinningPolicy::CannotBePinned;
+        for (const auto& testDevice : getTestHardwareEnvironment()->getTestDeviceList())
+        {
+            const DeviceContext& deviceContext = testDevice->deviceContext();
+            const DeviceStream&  deviceStream  = testDevice->deviceStream();
+            setActiveDevice(testDevice->deviceInfo());
+
+            DeviceBuffer<TypeParam> buffer;
+            int                     numValues = 123;
+            allocateDeviceBuffer(&buffer, numValues, deviceContext);
+            HostVector<TypeParam> valuesIn(numValues, { pinningPolicy });
+            HostVector<TypeParam> valuesOut(numValues, { pinningPolicy });
+
+            std::iota(valuesIn.begin(), valuesIn.end(), c_initialValue<TypeParam>);
+
+            copyToDeviceBuffer(&buffer, valuesIn.data(), 0, numValues, deviceStream, transferKind, nullptr);
+            copyFromDeviceBuffer(
+                    valuesOut.data(), &buffer, 0, numValues, deviceStream, transferKind, nullptr);
+            if (transferKind == GpuApiCallBehavior::Async)
+            {
+                deviceStream.synchronize();
+            }
+            EXPECT_THAT(valuesOut, Pointwise(Eq(), valuesIn))
+                    << "Changed after H2D and D2H " << enumValueToString(transferKind) << " copy.";
+            freeDeviceBuffer(&buffer);
+        }
     }
 }
 
 TYPED_TEST(DeviceBufferTest, CanCopyToAndFromDeviceWithOffset)
 {
-    for (const auto& testDevice : getTestHardwareEnvironment()->getTestDeviceList())
+    for (auto transferKind : { GpuApiCallBehavior::Sync, GpuApiCallBehavior::Async })
     {
-        const DeviceContext& deviceContext = testDevice->deviceContext();
-        const DeviceStream&  deviceStream  = testDevice->deviceStream();
-        setActiveDevice(testDevice->deviceInfo());
+        PinningPolicy pinningPolicy = (transferKind == GpuApiCallBehavior::Async)
+                                              ? PinningPolicy::PinnedIfSupported
+                                              : PinningPolicy::CannotBePinned;
+        for (const auto& testDevice : getTestHardwareEnvironment()->getTestDeviceList())
+        {
+            const DeviceContext& deviceContext = testDevice->deviceContext();
+            const DeviceStream&  deviceStream  = testDevice->deviceStream();
+            setActiveDevice(testDevice->deviceInfo());
+
+            DeviceBuffer<TypeParam> buffer;
+            int                     numValues = 123;
+            allocateDeviceBuffer(&buffer, 2 * numValues, deviceContext);
+            HostVector<TypeParam> valuesIn(numValues, { pinningPolicy });
+            HostVector<TypeParam> valuesOut(2 * numValues, { pinningPolicy });
+
+            std::iota(valuesIn.begin(), valuesIn.end(), c_initialValue<TypeParam>);
+
+            // Fill the buffer with two copies of valuesIn, one after the other.
+            copyToDeviceBuffer(&buffer, valuesIn.data(), 0, numValues, deviceStream, transferKind, nullptr);
+            copyToDeviceBuffer(
+                    &buffer, valuesIn.data(), numValues, numValues, deviceStream, transferKind, nullptr);
+            // Wait until GPU is done andd o the same copying on the CPU, so we can test it works correctly.
+            if (transferKind == GpuApiCallBehavior::Async)
+            {
+                deviceStream.synchronize();
+            }
+            valuesIn.insert(valuesIn.end(), valuesIn.begin(), valuesIn.end());
+
+            copyFromDeviceBuffer(
+                    valuesOut.data(), &buffer, 0, 2 * numValues, deviceStream, transferKind, nullptr);
+            if (transferKind == GpuApiCallBehavior::Async)
+            {
+                deviceStream.synchronize();
+            }
+            EXPECT_THAT(valuesOut, Pointwise(Eq(), valuesIn))
+                    << "Changed after H2D and D2H " << enumValueToString(transferKind) << " copy.";
+
+            SCOPED_TRACE("Checking the copy respects the output range");
+
+            // Remove the first element, and push another copy of the last
+            // element, so we can check that a copy of all of the data
+            // skipping the first element correctly over-writes exactly
+            // all but one of the old values.
+            valuesIn.erase(valuesIn.begin());
+            valuesIn.push_back(valuesIn.back());
+            copyFromDeviceBuffer(
+                    valuesOut.data(), &buffer, 1, 2 * numValues - 1, deviceStream, transferKind, nullptr);
+            if (transferKind == GpuApiCallBehavior::Async)
+            {
+                deviceStream.synchronize();
+            }
+            EXPECT_THAT(valuesOut, Pointwise(Eq(), valuesIn))
+                    << "Changed after H2D and D2H " << enumValueToString(transferKind) << " copy.";
+        }
+    }
+}
 
-        DeviceBuffer<TypeParam> buffer;
-        int                     numValues = 123;
-        allocateDeviceBuffer(&buffer, 2 * numValues, deviceContext);
-        std::vector<TypeParam> valuesIn(numValues);
-        std::vector<TypeParam> valuesOut(2 * numValues);
-
-        std::iota(valuesIn.begin(), valuesIn.end(), c_initialValue<TypeParam>);
-
-        // Fill the buffer with two copies of valuesIn, one after the other.
-        copyToDeviceBuffer(&buffer, valuesIn.data(), 0, numValues, deviceStream,
-                           GpuApiCallBehavior::Sync, nullptr);
-        copyToDeviceBuffer(&buffer, valuesIn.data(), numValues, numValues, deviceStream,
-                           GpuApiCallBehavior::Sync, nullptr);
-        // Do the same copying on the CPU, so we can test it works
-        // correctly.
-        valuesIn.insert(valuesIn.end(), valuesIn.begin(), valuesIn.end());
-
-        copyFromDeviceBuffer(valuesOut.data(), &buffer, 0, 2 * numValues, deviceStream,
-                             GpuApiCallBehavior::Sync, nullptr);
-        EXPECT_THAT(valuesOut, Pointwise(Eq(), valuesIn)) << "Changed after H2D and D2H copy.";
-
-        SCOPED_TRACE("Checking the copy respects the output range");
-
-        // Remove the first element, and push another copy of the last
-        // element, so we can check that a copy of all of the data
-        // skipping the first element correctly over-writes exactly
-        // all but one of the old values.
-        valuesIn.erase(valuesIn.begin());
-        valuesIn.push_back(valuesIn.back());
-        copyFromDeviceBuffer(valuesOut.data(), &buffer, 1, 2 * numValues - 1, deviceStream,
-                             GpuApiCallBehavior::Sync, nullptr);
-        EXPECT_THAT(valuesOut, Pointwise(Eq(), valuesIn)) << "Changed after H2D and D2H copy.";
+#    if GMX_GPU_CUDA
+
+TYPED_TEST(DeviceBufferTest, CanCopyBetweenDeviceBuffers)
+{
+    for (auto transferKind : { GpuApiCallBehavior::Sync, GpuApiCallBehavior::Async })
+    {
+        PinningPolicy pinningPolicy = (transferKind == GpuApiCallBehavior::Async)
+                                              ? PinningPolicy::PinnedIfSupported
+                                              : PinningPolicy::CannotBePinned;
+        for (const auto& testDeviceIn : getTestHardwareEnvironment()->getTestDeviceList())
+        {
+            for (const auto& testDeviceOut : getTestHardwareEnvironment()->getTestDeviceList())
+            {
+                int                   numValues = 321;
+                HostVector<TypeParam> valuesIn(numValues, { pinningPolicy });
+                HostVector<TypeParam> valuesOut(numValues, { pinningPolicy });
+
+                std::iota(valuesIn.begin(), valuesIn.end(), c_initialValue<TypeParam>);
+
+                const DeviceContext& deviceContextIn = testDeviceIn->deviceContext();
+                const DeviceStream&  deviceStreamIn  = testDeviceIn->deviceStream();
+                setActiveDevice(testDeviceIn->deviceInfo());
+                DeviceBuffer<TypeParam> bufferIn;
+                allocateDeviceBuffer(&bufferIn, numValues, deviceContextIn);
+
+                const DeviceContext& deviceContextOut = testDeviceOut->deviceContext();
+                const DeviceStream&  deviceStreamOut  = testDeviceOut->deviceStream();
+                setActiveDevice(testDeviceOut->deviceInfo());
+                DeviceBuffer<TypeParam> bufferOut;
+                allocateDeviceBuffer(&bufferOut, numValues, deviceContextOut);
+
+                copyToDeviceBuffer(
+                        &bufferIn, valuesIn.data(), 0, numValues, deviceStreamIn, transferKind, nullptr);
+                copyBetweenDeviceBuffers(
+                        &bufferOut, &bufferIn, numValues, deviceStreamIn, transferKind, nullptr);
+                if (transferKind == GpuApiCallBehavior::Async)
+                {
+                    deviceStreamIn.synchronize();
+                }
+                copyFromDeviceBuffer(
+                        valuesOut.data(), &bufferOut, 0, numValues, deviceStreamOut, transferKind, nullptr);
+                if (transferKind == GpuApiCallBehavior::Async)
+                {
+                    deviceStreamOut.synchronize();
+                }
+                EXPECT_THAT(valuesOut, Pointwise(Eq(), valuesIn))
+                        << "Changed after H2D, D2D and D2H " << enumValueToString(transferKind)
+                        << " copy.";
+                freeDeviceBuffer(&bufferIn);
+                freeDeviceBuffer(&bufferOut);
+            }
+        }
     }
 }
 
+#    endif // GMX_GPU_CUDA
+
 
 } // namespace
 } // namespace test
index d01aff20ead9771860aa31cdf0f19893cafe2eea..8166eaa7710029855fbddd180366ab6ba21a3445 100644 (file)
@@ -126,9 +126,11 @@ TEST_F(DeviceStreamManagerTest, CorrectStreamsAreReturnedOnNonbondedDevice)
             DeviceStreamManager manager(deviceInfo, havePpDomainDecomposition, simulationWork, useTiming);
 
             expectValidStreams(&manager, { DeviceStreamType::NonBondedLocal });
-            expectInvalidStreams(&manager, { DeviceStreamType::NonBondedNonLocal,
-                                             DeviceStreamType::Pme, DeviceStreamType::PmePpTransfer,
-                                             DeviceStreamType::UpdateAndConstraints });
+            expectInvalidStreams(&manager,
+                                 { DeviceStreamType::NonBondedNonLocal,
+                                   DeviceStreamType::Pme,
+                                   DeviceStreamType::PmePpTransfer,
+                                   DeviceStreamType::UpdateAndConstraints });
         }
 
         {
@@ -140,10 +142,12 @@ TEST_F(DeviceStreamManagerTest, CorrectStreamsAreReturnedOnNonbondedDevice)
             bool                havePpDomainDecomposition = true;
             DeviceStreamManager manager(deviceInfo, havePpDomainDecomposition, simulationWork, useTiming);
 
-            expectValidStreams(&manager, { DeviceStreamType::NonBondedLocal,
-                                           DeviceStreamType::NonBondedNonLocal });
-            expectInvalidStreams(&manager, { DeviceStreamType::Pme, DeviceStreamType::PmePpTransfer,
-                                             DeviceStreamType::UpdateAndConstraints });
+            expectValidStreams(
+                    &manager, { DeviceStreamType::NonBondedLocal, DeviceStreamType::NonBondedNonLocal });
+            expectInvalidStreams(&manager,
+                                 { DeviceStreamType::Pme,
+                                   DeviceStreamType::PmePpTransfer,
+                                   DeviceStreamType::UpdateAndConstraints });
         }
 
         {
@@ -155,9 +159,11 @@ TEST_F(DeviceStreamManagerTest, CorrectStreamsAreReturnedOnNonbondedDevice)
             bool                havePpDomainDecomposition = false;
             DeviceStreamManager manager(deviceInfo, havePpDomainDecomposition, simulationWork, useTiming);
 
-            expectValidStreams(&manager, { DeviceStreamType::Pme, DeviceStreamType::NonBondedLocal,
-                                           DeviceStreamType::PmePpTransfer,
-                                           DeviceStreamType::UpdateAndConstraints });
+            expectValidStreams(&manager,
+                               { DeviceStreamType::Pme,
+                                 DeviceStreamType::NonBondedLocal,
+                                 DeviceStreamType::PmePpTransfer,
+                                 DeviceStreamType::UpdateAndConstraints });
             expectInvalidStreams(&manager, { DeviceStreamType::NonBondedNonLocal });
         }
 
@@ -170,9 +176,12 @@ TEST_F(DeviceStreamManagerTest, CorrectStreamsAreReturnedOnNonbondedDevice)
             bool                havePpDomainDecomposition = true;
             DeviceStreamManager manager(deviceInfo, havePpDomainDecomposition, simulationWork, useTiming);
 
-            expectValidStreams(&manager, { DeviceStreamType::Pme, DeviceStreamType::NonBondedLocal,
-                                           DeviceStreamType::NonBondedNonLocal, DeviceStreamType::PmePpTransfer,
-                                           DeviceStreamType::UpdateAndConstraints });
+            expectValidStreams(&manager,
+                               { DeviceStreamType::Pme,
+                                 DeviceStreamType::NonBondedLocal,
+                                 DeviceStreamType::NonBondedNonLocal,
+                                 DeviceStreamType::PmePpTransfer,
+                                 DeviceStreamType::UpdateAndConstraints });
         }
 
         {
@@ -184,10 +193,12 @@ TEST_F(DeviceStreamManagerTest, CorrectStreamsAreReturnedOnNonbondedDevice)
             bool                havePpDomainDecomposition = false;
             DeviceStreamManager manager(deviceInfo, havePpDomainDecomposition, simulationWork, useTiming);
 
-            expectValidStreams(&manager, { DeviceStreamType::NonBondedLocal,
-                                           DeviceStreamType::UpdateAndConstraints });
-            expectInvalidStreams(&manager, { DeviceStreamType::NonBondedNonLocal,
-                                             DeviceStreamType::Pme, DeviceStreamType::PmePpTransfer });
+            expectValidStreams(
+                    &manager, { DeviceStreamType::NonBondedLocal, DeviceStreamType::UpdateAndConstraints });
+            expectInvalidStreams(&manager,
+                                 { DeviceStreamType::NonBondedNonLocal,
+                                   DeviceStreamType::Pme,
+                                   DeviceStreamType::PmePpTransfer });
         }
 
         {
@@ -199,8 +210,10 @@ TEST_F(DeviceStreamManagerTest, CorrectStreamsAreReturnedOnNonbondedDevice)
             bool                havePpDomainDecomposition = true;
             DeviceStreamManager manager(deviceInfo, havePpDomainDecomposition, simulationWork, useTiming);
 
-            expectValidStreams(&manager, { DeviceStreamType::NonBondedLocal, DeviceStreamType::NonBondedNonLocal,
-                                           DeviceStreamType::UpdateAndConstraints });
+            expectValidStreams(&manager,
+                               { DeviceStreamType::NonBondedLocal,
+                                 DeviceStreamType::NonBondedNonLocal,
+                                 DeviceStreamType::UpdateAndConstraints });
             expectInvalidStreams(&manager, { DeviceStreamType::Pme, DeviceStreamType::PmePpTransfer });
         }
 
@@ -213,9 +226,11 @@ TEST_F(DeviceStreamManagerTest, CorrectStreamsAreReturnedOnNonbondedDevice)
             bool                havePpDomainDecomposition = false;
             DeviceStreamManager manager(deviceInfo, havePpDomainDecomposition, simulationWork, useTiming);
 
-            expectValidStreams(&manager, { DeviceStreamType::Pme, DeviceStreamType::NonBondedLocal,
-                                           DeviceStreamType::PmePpTransfer,
-                                           DeviceStreamType::UpdateAndConstraints });
+            expectValidStreams(&manager,
+                               { DeviceStreamType::Pme,
+                                 DeviceStreamType::NonBondedLocal,
+                                 DeviceStreamType::PmePpTransfer,
+                                 DeviceStreamType::UpdateAndConstraints });
             expectInvalidStreams(&manager, { DeviceStreamType::NonBondedNonLocal });
         }
 
@@ -228,9 +243,12 @@ TEST_F(DeviceStreamManagerTest, CorrectStreamsAreReturnedOnNonbondedDevice)
             bool                havePpDomainDecomposition = true;
             DeviceStreamManager manager(deviceInfo, havePpDomainDecomposition, simulationWork, useTiming);
 
-            expectValidStreams(&manager, { DeviceStreamType::Pme, DeviceStreamType::NonBondedLocal,
-                                           DeviceStreamType::NonBondedNonLocal, DeviceStreamType::PmePpTransfer,
-                                           DeviceStreamType::UpdateAndConstraints });
+            expectValidStreams(&manager,
+                               { DeviceStreamType::Pme,
+                                 DeviceStreamType::NonBondedLocal,
+                                 DeviceStreamType::NonBondedNonLocal,
+                                 DeviceStreamType::PmePpTransfer,
+                                 DeviceStreamType::UpdateAndConstraints });
         }
     }
 }
index 1888a35729ee197f8ad9e18c18246a3079a4f55c..c01232fc1367c81965423f1c32f9bdb90c997de6 100644 (file)
@@ -64,8 +64,8 @@ void throwUponFailure(cl_int status, const char* message)
 {
     if (status != CL_SUCCESS)
     {
-        GMX_THROW(InternalError(formatString("Failure while %s, error was %s", message,
-                                             ocl_get_error_string(status).c_str())));
+        GMX_THROW(InternalError(formatString(
+                "Failure while %s, error was %s", message, ocl_get_error_string(status).c_str())));
     }
 }
 
@@ -90,11 +90,11 @@ void doDeviceTransfers(const DeviceInformation& deviceInfo, ArrayRef<const char>
     auto devicePointer = clCreateBuffer(context, CL_MEM_READ_WRITE, input.size(), nullptr, &status);
     throwUponFailure(status, "creating buffer");
 
-    status = clEnqueueWriteBuffer(commandQueue, devicePointer, CL_TRUE, 0, input.size(),
-                                  input.data(), 0, nullptr, nullptr);
+    status = clEnqueueWriteBuffer(
+            commandQueue, devicePointer, CL_TRUE, 0, input.size(), input.data(), 0, nullptr, nullptr);
     throwUponFailure(status, "transferring host to device");
-    status = clEnqueueReadBuffer(commandQueue, devicePointer, CL_TRUE, 0, output.size(),
-                                 output.data(), 0, nullptr, nullptr);
+    status = clEnqueueReadBuffer(
+            commandQueue, devicePointer, CL_TRUE, 0, output.size(), output.data(), 0, nullptr, nullptr);
     throwUponFailure(status, "transferring device to host");
 
     status = clReleaseMemObject(devicePointer);
index b4493e961e460bbe5da26aef9190a53abcb20a0a..699dff0613e97c1f9475a0283e4c2863b397324d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -50,7 +50,7 @@
 
 #    include "gromacs/gpu_utils/gpu_utils.h"
 #    include "gromacs/gpu_utils/hostallocator.h"
-#    include "gromacs/gpu_utils/pmalloc_cuda.h"
+#    include "gromacs/gpu_utils/pmalloc.h"
 #    include "gromacs/utility/real.h"
 #    include "gromacs/utility/smalloc.h"
 
index 7d88601d9f35fe09b55c1c7c87a7fb309a5e0f88..dde856d93fc58718f2ab0be155ab6493bc3dba9a 100644 (file)
@@ -118,8 +118,8 @@ void convertRVecToFloat3OnDevice(std::vector<gmx::RVec>&       h_rVecOutput,
 
     DeviceBuffer<RVec> d_rVecInput;
     allocateDeviceBuffer(&d_rVecInput, numElements, deviceContext);
-    copyToDeviceBuffer(&d_rVecInput, h_rVecInput.data(), 0, numElements, deviceStream,
-                       GpuApiCallBehavior::Sync, nullptr);
+    copyToDeviceBuffer(
+            &d_rVecInput, h_rVecInput.data(), 0, numElements, deviceStream, GpuApiCallBehavior::Sync, nullptr);
 
     DeviceBuffer<float3> d_float3Output;
     allocateDeviceBuffer(&d_float3Output, numElements * DIM, deviceContext);
@@ -134,13 +134,17 @@ void convertRVecToFloat3OnDevice(std::vector<gmx::RVec>&       h_rVecOutput,
     kernelLaunchConfig.sharedMemorySize = 0;
 
     auto       kernelPtr  = convertRVecToFloat3OnDevice_kernel;
-    const auto kernelArgs = prepareGpuKernelArguments(kernelPtr, kernelLaunchConfig,
-                                                      &d_float3Output, &d_rVecInput, &numElements);
-    launchGpuKernel(kernelPtr, kernelLaunchConfig, deviceStream, nullptr,
-                    "convertRVecToFloat3OnDevice_kernel", kernelArgs);
-
-    copyFromDeviceBuffer(h_float3Output.data(), &d_float3Output, 0, numElements, deviceStream,
-                         GpuApiCallBehavior::Sync, nullptr);
+    const auto kernelArgs = prepareGpuKernelArguments(
+            kernelPtr, kernelLaunchConfig, &d_float3Output, &d_rVecInput, &numElements);
+    launchGpuKernel(kernelPtr,
+                    kernelLaunchConfig,
+                    deviceStream,
+                    nullptr,
+                    "convertRVecToFloat3OnDevice_kernel",
+                    kernelArgs);
+
+    copyFromDeviceBuffer(
+            h_float3Output.data(), &d_float3Output, 0, numElements, deviceStream, GpuApiCallBehavior::Sync, nullptr);
 
     saveFloat3InRVecFormat(h_rVecOutput, h_float3Output.data(), numElements);
 
index 1dd63b719313c673246366c3b66b62e937b0f2ef..d98c5877037391d248f7d80ecc5ac444d6c4674b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,4 +60,25 @@ static inline __host__ __device__ float3* asFloat3(gmx::RVec* in)
     return reinterpret_cast<float3*>(in);
 }
 
+/*! \brief Cast pointer RVec buffer to a pointer to float3 buffer.
+ *
+ * \param[in] in The Pointer to RVec buffer to cast.
+ *
+ * \returns Buffer pointer, casted to float3*.
+ */
+static inline __host__ __device__ float3** asFloat3Pointer(gmx::RVec** in)
+{
+    static_assert(sizeof((*in)[0]) == sizeof(float3),
+                  "Size of the host-side data-type is different from the size of the device-side "
+                  "counterpart.");
+    return reinterpret_cast<float3**>(in);
+}
+static inline __host__ __device__ const float3* const* asFloat3Pointer(const gmx::RVec* const* in)
+{
+    static_assert(sizeof((*in)[0]) == sizeof(float3),
+                  "Size of the host-side data-type is different from the size of the device-side "
+                  "counterpart.");
+    return reinterpret_cast<const float3* const*>(in);
+}
+
 #endif // GMX_GPU_UTILS_TYPECASTS_CUH
index 668e6ab1867766ba4c3e9694cec5d09e89686ead..da2653807048bba4c78a84d931a786046d1c977b 100644 (file)
@@ -32,6 +32,7 @@
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
+add_library(hardware INTERFACE)
 gmx_add_libgromacs_sources(
     cpuinfo.cpp
     detecthardware.cpp
@@ -72,6 +73,34 @@ else()
     )
 endif()
 
+# Source files have the following private module dependencies.
+target_link_libraries(hardware PRIVATE
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(hardware PUBLIC
+target_include_directories(hardware INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(hardware PUBLIC
+target_link_libraries(hardware INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when hardware is an OBJECT target
+#target_link_libraries(hardware PUBLIC legacy_api)
+#target_link_libraries(hardware PRIVATE common)
+
+# Module dependencies
+# hardware interfaces convey transitive dependence on these modules.
+#target_link_libraries(hardware PUBLIC
+target_link_libraries(hardware INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(hardware PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(hardware PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index f81a6f027998424c6aef3bcfb62f916552ad9eb8..82c50f0e19d6025efa9e23a4895cbbbc48c97cb9 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -548,7 +548,9 @@ void renumberIndex(std::vector<unsigned int>* v)
     for (std::size_t i = 0; i < uniqueSortedV.size(); i++)
     {
         unsigned int val = uniqueSortedV[i];
-        std::replace_if(v->begin(), v->end(), [val](unsigned int& c) -> bool { return c == val; },
+        std::replace_if(v->begin(),
+                        v->end(),
+                        [val](unsigned int& c) -> bool { return c == val; },
                         static_cast<unsigned int>(i));
     }
 }
@@ -808,14 +810,14 @@ CpuInfo::Vendor detectProcCpuInfoVendor(const std::map<std::string, std::string>
 
     // For each label in /proc/cpuinfo, compare the value to the name in the
     // testNames map above, and if it's a match return the vendor.
-    for (auto& l : { "vendor_id", "vendor", "manufacture", "model", "processor", "cpu" })
+    for (const auto& l : { "vendor_id", "vendor", "manufacture", "model", "processor", "cpu" })
     {
         if (cpuInfo.count(l) != 0U)
         {
             // there was a line with this left-hand side in /proc/cpuinfo
             const std::string& s1 = cpuInfo.at(l);
 
-            for (auto& t : testVendors)
+            for (const auto& t : testVendors)
             {
                 const std::string& s2 = t.first;
 
@@ -863,7 +865,7 @@ void detectProcCpuInfoIbm(const std::map<std::string, std::string>& cpuInfo,
         features->insert(CpuInfo::Feature::Ibm_Qpx);
     }
 
-    for (auto& l : { "model name", "model", "Processor", "cpu" })
+    for (const auto& l : { "model name", "model", "Processor", "cpu" })
     {
         if (cpuInfo.count(l) != 0U)
         {
@@ -1027,8 +1029,8 @@ CpuInfo CpuInfo::detect()
         {
             result.features_.insert(CpuInfo::Feature::X86_Hygon);
         }
-        detectX86Features(&result.brandString_, &result.family_, &result.model_, &result.stepping_,
-                          &result.features_);
+        detectX86Features(
+                &result.brandString_, &result.family_, &result.model_, &result.stepping_, &result.features_);
         result.logicalProcessors_ = detectX86LogicalProcessors();
     }
     else
@@ -1057,8 +1059,12 @@ CpuInfo CpuInfo::detect()
 
         // On Linux we might be able to find information in /proc/cpuinfo. If vendor or brand
         // is set to a known value this routine will not overwrite it.
-        detectProcCpuInfo(&result.vendor_, &result.brandString_, &result.family_, &result.model_,
-                          &result.stepping_, &result.features_);
+        detectProcCpuInfo(&result.vendor_,
+                          &result.brandString_,
+                          &result.family_,
+                          &result.model_,
+                          &result.stepping_,
+                          &result.features_);
     }
 
     if (!result.logicalProcessors_.empty())
@@ -1168,11 +1174,28 @@ const std::string& CpuInfo::featureString(Feature f)
 
 bool cpuIsX86Nehalem(const CpuInfo& cpuInfo)
 {
-    return (cpuInfo.vendor() == gmx::CpuInfo::Vendor::Intel && cpuInfo.family() == 6
+    return (cpuInfo.vendor() == CpuInfo::Vendor::Intel && cpuInfo.family() == 6
             && (cpuInfo.model() == 0x2E || cpuInfo.model() == 0x1A || cpuInfo.model() == 0x1E
                 || cpuInfo.model() == 0x2F || cpuInfo.model() == 0x2C || cpuInfo.model() == 0x25));
 }
 
+bool cpuIsAmdZen1(const CpuInfo& cpuInfo)
+{
+    /* Both Zen/Zen+/Zen2 have family==23
+     * Model numbers for Zen:
+     * 1)  Naples, Whitehaven, Summit Ridge, and Snowy Owl;
+     * 17) Raven Ridge.
+     * Model numbers for Zen+:
+     * 8)  Pinnacle Ridge;
+     * 24) Picasso.
+     * Hygon got license for Zen1, but not Zen2 (https://www.tomshardware.com/news/amd-zen-china-x86-ip-license,39573.html)
+     */
+    return (cpuInfo.vendor() == CpuInfo::Vendor::Amd && cpuInfo.family() == 23
+            && (cpuInfo.model() == 1 || cpuInfo.model() == 17 || cpuInfo.model() == 8
+                || cpuInfo.model() == 24))
+           || (cpuInfo.vendor() == CpuInfo::Vendor::Hygon);
+}
+
 } // namespace gmx
 
 #ifdef GMX_CPUINFO_STANDALONE
index fe09e27807a74b899ee1d321f3ff5a9aa7a2305c..a6b9041f36f8a328b9f561973bcc4f0c2617c8f3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -162,7 +162,6 @@ public:
         int hwThreadRankInCore;  //!< Relative rank of logical processor in its core
     };
 
-public:
     /*! \brief Perform detection and construct a CpuInfo class from the results.
      *
      *  \note The detection should generally be performed again in different
@@ -273,6 +272,14 @@ private:
  */
 bool cpuIsX86Nehalem(const CpuInfo& cpuInfo);
 
+/*! \brief Return true if the CPU is a first generation AMD Zen (produced by AMD or Hygon)
+ *
+ * \param cpuInfo  Object with cpu information
+ *
+ * \returns  True if running on a first generation AMD Zen
+ */
+bool cpuIsAmdZen1(const CpuInfo& cpuInfo);
+
 } // namespace gmx
 
 #endif // GMX_HARDWARE_CPUINFO_H
index d808249678abdb704be7cdbb13562ce846b41ae7..2325c71bd1826cffa156cb373e56620109899653 100644 (file)
@@ -209,10 +209,7 @@ static void gmx_collect_hardware_mpi(const gmx::CpuInfo&             cpuInfo,
      * - family=23 with the below listed models;
      * - Hygon as vendor.
      */
-    const bool cpuIsAmdZen1 = ((cpuInfo.vendor() == CpuInfo::Vendor::Amd && cpuInfo.family() == 23
-                                && (cpuInfo.model() == 1 || cpuInfo.model() == 17
-                                    || cpuInfo.model() == 8 || cpuInfo.model() == 24))
-                               || cpuInfo.vendor() == CpuInfo::Vendor::Hygon);
+    const bool cpuIsAmdZen1 = gmx::cpuIsAmdZen1(cpuInfo);
 
     int numCompatibleDevices = getCompatibleDevices(hardwareInfo->deviceInfoList).size();
 #if GMX_LIB_MPI
@@ -251,8 +248,7 @@ static void gmx_collect_hardware_mpi(const gmx::CpuInfo&             cpuInfo,
             countsLocal[3] = numCompatibleDevices;
         }
 
-        MPI_Allreduce(countsLocal.data(), countsReduced.data(), countsLocal.size(), MPI_INT,
-                      MPI_SUM, MPI_COMM_WORLD);
+        MPI_Allreduce(countsLocal.data(), countsReduced.data(), countsLocal.size(), MPI_INT, MPI_SUM, MPI_COMM_WORLD);
     }
 
     constexpr int                   numElementsMax = 11;
@@ -274,8 +270,7 @@ static void gmx_collect_hardware_mpi(const gmx::CpuInfo&             cpuInfo,
         maxMinLocal[9]  = -maxMinLocal[4];
         maxMinLocal[10] = (cpuIsAmdZen1 ? 1 : 0);
 
-        MPI_Allreduce(maxMinLocal.data(), maxMinReduced.data(), maxMinLocal.size(), MPI_INT,
-                      MPI_MAX, MPI_COMM_WORLD);
+        MPI_Allreduce(maxMinLocal.data(), maxMinReduced.data(), maxMinLocal.size(), MPI_INT, MPI_MAX, MPI_COMM_WORLD);
     }
 
     hardwareInfo->nphysicalnode       = countsReduced[0];
@@ -333,7 +328,8 @@ void hardwareTopologyDoubleCheckDetection(const gmx::MDLogger gmx_unused& mdlog,
         GMX_LOG(mdlog.info)
                 .appendTextFormatted(
                         "Note: %d CPUs configured, but only %d were detected to be online.\n",
-                        countConfigured, countFromDetection);
+                        countConfigured,
+                        countFromDetection);
 
         if (c_architecture == Architecture::X86 && countConfigured == 2 * countFromDetection)
         {
index 54915dc52ec5f4dc05e320cb62075fa2c4ceee6f..d23279e436a3f3aec5924829b664943913e4104d 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -78,18 +78,22 @@ enum class DeviceStatus : int
     Incompatible = 2,
     //! OpenCL device has incompatible cluster size for non-bonded kernels.
     IncompatibleClusterSize = 3,
-    //! There are known issues with NVIDIA Volta and newer.
+    //! There are known issues with OpenCL on NVIDIA Volta and newer.
     IncompatibleNvidiaVolta = 4,
+    /* \brief The device originates from non-recommended SYCL backend.
+     * The device might work by itself, but to simplify device allocation, it is marked as incompatible.
+     * */
+    NotPreferredBackend = 5,
     /*! \brief An error occurred during the functionality checks.
      * That indicates malfunctioning of the device, driver, or incompatible driver/runtime.
      */
-    NonFunctional = 5,
+    NonFunctional = 6,
     /*! \brief CUDA devices are busy or unavailable.
      * typically due to use of \p cudaComputeModeExclusive, \p cudaComputeModeProhibited modes.
      */
-    Unavailable = 6,
+    Unavailable = 7,
     //! Enumeration size
-    Count = 7
+    Count = 8
 };
 
 /*! \brief Names of the GPU detection/check results
@@ -102,12 +106,16 @@ enum class DeviceStatus : int
  * missing, so that is suppressed.
  */
 static const gmx::EnumerationArray<DeviceStatus, const char*> c_deviceStateString = {
-    "compatible", "nonexistent", "incompatible",
+    "compatible",
+    "nonexistent",
+    "incompatible",
     // clang-format off
     // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
-    "incompatible (please recompile with correct GMX" "_OPENCL_NB_CLUSTER_SIZE of 4)",
+    "incompatible (please recompile with correct GMX" "_GPU_NB_CLUSTER_SIZE of 4)",
     // clang-format on
-    "incompatible (please use CUDA build for NVIDIA Volta GPUs or newer)", "non-functional",
+    "incompatible (please use CUDA build for NVIDIA Volta GPUs or newer)",
+    "not recommended (please use SYCL_DEVICE_FILTER to limit visibility to a single backend)",
+    "non-functional",
     "unavailable"
 };
 
index 0e77621a5bdf61ba82aadcea9cd882eae77b8759..3df63f81310f383c7fa5e8096ad197b1bfa8ab53 100644 (file)
@@ -86,7 +86,10 @@ static cudaError_t checkCompiledTargetCompatibility(int deviceId, const cudaDevi
                 "might be rare, or some architectures were disabled in the build. \n"
                 "Consult the install guide for how to use the GMX_CUDA_TARGET_SM and "
                 "GMX_CUDA_TARGET_COMPUTE CMake variables to add this architecture. \n",
-                gmx::getProgramContext().displayName(), deviceId, deviceProp.major, deviceProp.minor);
+                gmx::getProgramContext().displayName(),
+                deviceId,
+                deviceProp.major,
+                deviceProp.minor);
     }
 
     return stat;
@@ -127,7 +130,9 @@ static DeviceStatus isDeviceFunctional(const DeviceInformation& deviceInfo)
     cu_err = cudaSetDevice(deviceInfo.id);
     if (cu_err != cudaSuccess)
     {
-        fprintf(stderr, "Error while switching to device #%d. %s\n", deviceInfo.id,
+        fprintf(stderr,
+                "Error while switching to device #%d. %s\n",
+                deviceInfo.id,
                 gmx::getDeviceErrorString(cu_err).c_str());
         return DeviceStatus::NonFunctional;
     }
@@ -160,7 +165,8 @@ static DeviceStatus isDeviceFunctional(const DeviceInformation& deviceInfo)
         // launchGpuKernel error is not fatal and should continue with marking the device bad
         fprintf(stderr,
                 "Error occurred while running dummy kernel sanity check on device #%d:\n %s\n",
-                deviceInfo.id, formatExceptionMessageToString(ex).c_str());
+                deviceInfo.id,
+                formatExceptionMessageToString(ex).c_str());
         return DeviceStatus::NonFunctional;
     }
 
@@ -373,14 +379,17 @@ std::string getDeviceInformationString(const DeviceInformation& deviceInfo)
 
     if (!gpuExists)
     {
-        return gmx::formatString("#%d: %s, stat: %s", deviceInfo.id, "N/A",
-                                 c_deviceStateString[deviceInfo.status]);
+        return gmx::formatString(
+                "#%d: %s, stat: %s", deviceInfo.id, "N/A", c_deviceStateString[deviceInfo.status]);
     }
     else
     {
         return gmx::formatString("#%d: NVIDIA %s, compute cap.: %d.%d, ECC: %3s, stat: %s",
-                                 deviceInfo.id, deviceInfo.prop.name, deviceInfo.prop.major,
-                                 deviceInfo.prop.minor, deviceInfo.prop.ECCEnabled ? "yes" : " no",
+                                 deviceInfo.id,
+                                 deviceInfo.prop.name,
+                                 deviceInfo.prop.major,
+                                 deviceInfo.prop.minor,
+                                 deviceInfo.prop.ECCEnabled ? "yes" : " no",
                                  c_deviceStateString[deviceInfo.status]);
     }
 }
index 60cb54aacc4f8ce7bf29d6cf3b5610751a0ceba8..138b6f7485c9d8a2129f2e696952bac8ea99d7b1 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <string>
 #include <vector>
 
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/iserializer.h"
 
@@ -153,7 +154,7 @@ getCompatibleDevices(const std::vector<std::unique_ptr<DeviceInformation>>& devi
  *
  * \return  Vector of compatible GPU ids.
  */
-std::vector<int> getCompatibleDeviceIds(const std::vector<std::unique_ptr<DeviceInformation>>& deviceInfoList);
+std::vector<int> getCompatibleDeviceIds(gmx::ArrayRef<const std::unique_ptr<DeviceInformation>> deviceInfoList);
 
 /*! \brief Return whether \p deviceId is found in \p deviceInfoList and is compatible
  *
@@ -167,8 +168,8 @@ std::vector<int> getCompatibleDeviceIds(const std::vector<std::unique_ptr<Device
  *
  * \return  Whether \c deviceId is compatible.
  */
-bool deviceIdIsCompatible(const std::vector<std::unique_ptr<DeviceInformation>>& deviceInfoList,
-                          int                                                    deviceId);
+bool deviceIdIsCompatible(gmx::ArrayRef<const std::unique_ptr<DeviceInformation>> deviceInfoList,
+                          int                                                     deviceId);
 
 /*! \brief Set the active GPU.
  *
@@ -219,7 +220,7 @@ std::string getDeviceInformationString(const DeviceInformation& deviceInfo);
  * \param[in] deviceId       An index of the device to check
  * \returns                  A string describing the compatibility status, useful for error messages.
  */
-std::string getDeviceCompatibilityDescription(const std::vector<std::unique_ptr<DeviceInformation>>& deviceInfoList,
+std::string getDeviceCompatibilityDescription(gmx::ArrayRef<const std::unique_ptr<DeviceInformation>> deviceInfoList,
                                               int deviceId);
 
 /*! \brief Serialization of information on devices for MPI broadcasting.
index 1392020ce02b8660a382a2e75ea548aee14f196b..8c7485d1df03179bf1480dd1aa87ce859323b68c 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ getCompatibleDevices(const std::vector<std::unique_ptr<DeviceInformation>>& devi
     return compatibleDeviceInfoList;
 }
 
-std::vector<int> getCompatibleDeviceIds(const std::vector<std::unique_ptr<DeviceInformation>>& deviceInfoList)
+std::vector<int> getCompatibleDeviceIds(gmx::ArrayRef<const std::unique_ptr<DeviceInformation>> deviceInfoList)
 {
     // Possible minor over-allocation here, but not important for anything
     std::vector<int> compatibleDeviceIds;
@@ -125,21 +125,23 @@ std::vector<int> getCompatibleDeviceIds(const std::vector<std::unique_ptr<Device
     return compatibleDeviceIds;
 }
 
-bool deviceIdIsCompatible(const std::vector<std::unique_ptr<DeviceInformation>>& deviceInfoList,
-                          const int                                              deviceId)
+bool deviceIdIsCompatible(gmx::ArrayRef<const std::unique_ptr<DeviceInformation>> deviceInfoList,
+                          const int                                               deviceId)
 {
-    auto foundIt = std::find_if(deviceInfoList.begin(), deviceInfoList.end(),
+    auto foundIt = std::find_if(deviceInfoList.begin(),
+                                deviceInfoList.end(),
                                 [deviceId](auto& deviceInfo) { return deviceInfo->id == deviceId; });
     if (foundIt == deviceInfoList.end())
     {
         GMX_THROW(gmx::RangeError(gmx::formatString(
-                "Device ID %d did not correspond to any of the %zu detected device(s)", deviceId,
+                "Device ID %d did not correspond to any of the %zu detected device(s)",
+                deviceId,
                 deviceInfoList.size())));
     }
     return (*foundIt)->status == DeviceStatus::Compatible;
 }
 
-std::string getDeviceCompatibilityDescription(const std::vector<std::unique_ptr<DeviceInformation>>& deviceInfoList,
+std::string getDeviceCompatibilityDescription(const gmx::ArrayRef<const std::unique_ptr<DeviceInformation>> deviceInfoList,
                                               int deviceId)
 {
     return (deviceId >= static_cast<int>(deviceInfoList.size())
@@ -154,7 +156,7 @@ void serializeDeviceInformations(const std::vector<std::unique_ptr<DeviceInforma
                        "DeviceInformation for OpenCL/SYCL can not be serialized");
     int numDevices = deviceInfoList.size();
     serializer->doInt(&numDevices);
-    for (auto& deviceInfo : deviceInfoList)
+    for (const auto& deviceInfo : deviceInfoList)
     {
         serializer->doOpaque(reinterpret_cast<char*>(deviceInfo.get()), sizeof(DeviceInformation));
     }
index 8f45aad13285a4dfd9a493cad41950831fdda55a..9687e042a0fa9a9e31c769e1d0cc2cf42f6a74e4 100644 (file)
@@ -120,8 +120,8 @@ static bool runningOnCompatibleHWForNvidia(const DeviceInformation& deviceInfo)
     static const unsigned int ccMajorBad = 7; // Volta and Turing
     unsigned int              ccMajor;
     cl_device_id              devId = deviceInfo.oclDeviceId;
-    const cl_int              err   = clGetDeviceInfo(devId, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV,
-                                       sizeof(ccMajor), &ccMajor, nullptr);
+    const cl_int              err   = clGetDeviceInfo(
+            devId, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, sizeof(ccMajor), &ccMajor, nullptr);
     if (err != CL_SUCCESS)
     {
         return true; // Err on a side of trusting the user to know what they are doing.
@@ -163,9 +163,9 @@ static DeviceStatus isDeviceFunctional(const DeviceInformation& deviceInfo)
     // the device which has the following format:
     //      OpenCL<space><major_version.minor_version><space><vendor-specific information>
     unsigned int deviceVersionMinor, deviceVersionMajor;
-    const int    valuesScanned = std::sscanf(deviceInfo.device_version, "OpenCL %u.%u",
-                                          &deviceVersionMajor, &deviceVersionMinor);
-    const bool   versionLargeEnough =
+    const int    valuesScanned = std::sscanf(
+            deviceInfo.device_version, "OpenCL %u.%u", &deviceVersionMajor, &deviceVersionMinor);
+    const bool versionLargeEnough =
             ((valuesScanned == 2)
              && ((deviceVersionMajor > minVersionMajor)
                  || (deviceVersionMajor == minVersionMajor && deviceVersionMinor >= minVersionMinor)));
@@ -183,8 +183,8 @@ static DeviceStatus isDeviceFunctional(const DeviceInformation& deviceInfo)
         case DeviceVendor::Amd:
             return runningOnCompatibleOSForAmd() ? DeviceStatus::Compatible : DeviceStatus::Incompatible;
         case DeviceVendor::Intel:
-            return GMX_OPENCL_NB_CLUSTER_SIZE == 4 ? DeviceStatus::Compatible
-                                                   : DeviceStatus::IncompatibleClusterSize;
+            return GMX_GPU_NB_CLUSTER_SIZE == 4 ? DeviceStatus::Compatible
+                                                : DeviceStatus::IncompatibleClusterSize;
         default: return DeviceStatus::Incompatible;
     }
 }
@@ -204,14 +204,17 @@ inline std::string makeOpenClInternalErrorString(const char* message, cl_int sta
 {
     if (message != nullptr)
     {
-        return gmx::formatString("%s did %ssucceed %d: %s", message,
-                                 ((status != CL_SUCCESS) ? "not " : ""), status,
+        return gmx::formatString("%s did %ssucceed %d: %s",
+                                 message,
+                                 ((status != CL_SUCCESS) ? "not " : ""),
+                                 status,
                                  ocl_get_error_string(status).c_str());
     }
     else
     {
         return gmx::formatString("%sOpenCL error encountered %d: %s",
-                                 ((status != CL_SUCCESS) ? "" : "No "), status,
+                                 ((status != CL_SUCCESS) ? "" : "No "),
+                                 status,
                                  ocl_get_error_string(status).c_str());
     }
 }
@@ -275,8 +278,8 @@ static bool isDeviceFunctional(const DeviceInformation& deviceInfo, std::string*
     clSetKernelArg(kernel, 0, sizeof(void*), nullptr);
 
     const size_t localWorkSize = 1, globalWorkSize = 1;
-    if ((status = clEnqueueNDRangeKernel(commandQueue, kernel, 1, nullptr, &globalWorkSize,
-                                         &localWorkSize, 0, nullptr, nullptr))
+    if ((status = clEnqueueNDRangeKernel(
+                 commandQueue, kernel, 1, nullptr, &globalWorkSize, &localWorkSize, 0, nullptr, nullptr))
         != CL_SUCCESS)
     {
         errorMessage->assign(makeOpenClInternalErrorString("clEnqueueNDRangeKernel", status));
@@ -337,7 +340,8 @@ bool isDeviceDetectionFunctional(std::string* errorMessage)
     GMX_RELEASE_ASSERT(
             status == CL_SUCCESS,
             gmx::formatString("An unexpected value was returned from clGetPlatformIDs %d: %s",
-                              status, ocl_get_error_string(status).c_str())
+                              status,
+                              ocl_get_error_string(status).c_str())
                     .c_str());
     bool foundPlatform = (numPlatforms > 0);
     if (!foundPlatform && errorMessage != nullptr)
@@ -425,8 +429,7 @@ std::vector<std::unique_ptr<DeviceInformation>> findDevices()
 
                 /* If requesting req_dev_type devices fails, just go to the next platform */
                 if (CL_SUCCESS
-                    != clGetDeviceIDs(ocl_platform_ids[i], req_dev_type, numDevices, ocl_device_ids,
-                                      &ocl_device_count))
+                    != clGetDeviceIDs(ocl_platform_ids[i], req_dev_type, numDevices, ocl_device_ids, &ocl_device_count))
                 {
                     continue;
                 }
@@ -446,38 +449,54 @@ std::vector<std::unique_ptr<DeviceInformation>> findDevices()
                     deviceInfoList[device_index]->oclDeviceId   = ocl_device_ids[j];
 
                     deviceInfoList[device_index]->device_name[0] = 0;
-                    clGetDeviceInfo(ocl_device_ids[j], CL_DEVICE_NAME,
+                    clGetDeviceInfo(ocl_device_ids[j],
+                                    CL_DEVICE_NAME,
                                     sizeof(deviceInfoList[device_index]->device_name),
-                                    deviceInfoList[device_index]->device_name, nullptr);
+                                    deviceInfoList[device_index]->device_name,
+                                    nullptr);
 
                     deviceInfoList[device_index]->device_version[0] = 0;
-                    clGetDeviceInfo(ocl_device_ids[j], CL_DEVICE_VERSION,
+                    clGetDeviceInfo(ocl_device_ids[j],
+                                    CL_DEVICE_VERSION,
                                     sizeof(deviceInfoList[device_index]->device_version),
-                                    deviceInfoList[device_index]->device_version, nullptr);
+                                    deviceInfoList[device_index]->device_version,
+                                    nullptr);
 
                     deviceInfoList[device_index]->vendorName[0] = 0;
-                    clGetDeviceInfo(ocl_device_ids[j], CL_DEVICE_VENDOR,
+                    clGetDeviceInfo(ocl_device_ids[j],
+                                    CL_DEVICE_VENDOR,
                                     sizeof(deviceInfoList[device_index]->vendorName),
-                                    deviceInfoList[device_index]->vendorName, nullptr);
+                                    deviceInfoList[device_index]->vendorName,
+                                    nullptr);
 
                     deviceInfoList[device_index]->compute_units = 0;
-                    clGetDeviceInfo(ocl_device_ids[j], CL_DEVICE_MAX_COMPUTE_UNITS,
+                    clGetDeviceInfo(ocl_device_ids[j],
+                                    CL_DEVICE_MAX_COMPUTE_UNITS,
                                     sizeof(deviceInfoList[device_index]->compute_units),
-                                    &(deviceInfoList[device_index]->compute_units), nullptr);
+                                    &(deviceInfoList[device_index]->compute_units),
+                                    nullptr);
 
                     deviceInfoList[device_index]->adress_bits = 0;
-                    clGetDeviceInfo(ocl_device_ids[j], CL_DEVICE_ADDRESS_BITS,
+                    clGetDeviceInfo(ocl_device_ids[j],
+                                    CL_DEVICE_ADDRESS_BITS,
                                     sizeof(deviceInfoList[device_index]->adress_bits),
-                                    &(deviceInfoList[device_index]->adress_bits), nullptr);
+                                    &(deviceInfoList[device_index]->adress_bits),
+                                    nullptr);
 
                     deviceInfoList[device_index]->deviceVendor =
                             getDeviceVendor(deviceInfoList[device_index]->vendorName);
 
-                    clGetDeviceInfo(ocl_device_ids[j], CL_DEVICE_MAX_WORK_ITEM_SIZES, 3 * sizeof(size_t),
-                                    &deviceInfoList[device_index]->maxWorkItemSizes, nullptr);
+                    clGetDeviceInfo(ocl_device_ids[j],
+                                    CL_DEVICE_MAX_WORK_ITEM_SIZES,
+                                    3 * sizeof(size_t),
+                                    &deviceInfoList[device_index]->maxWorkItemSizes,
+                                    nullptr);
 
-                    clGetDeviceInfo(ocl_device_ids[j], CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(size_t),
-                                    &deviceInfoList[device_index]->maxWorkGroupSize, nullptr);
+                    clGetDeviceInfo(ocl_device_ids[j],
+                                    CL_DEVICE_MAX_WORK_GROUP_SIZE,
+                                    sizeof(size_t),
+                                    &deviceInfoList[device_index]->maxWorkGroupSize,
+                                    nullptr);
 
                     deviceInfoList[device_index]->status =
                             gmx::checkGpu(device_index, *deviceInfoList[device_index]);
@@ -563,13 +582,16 @@ std::string getDeviceInformationString(const DeviceInformation& deviceInfo)
 
     if (!gpuExists)
     {
-        return gmx::formatString("#%d: %s, status: %s", deviceInfo.id, "N/A",
-                                 c_deviceStateString[deviceInfo.status]);
+        return gmx::formatString(
+                "#%d: %s, status: %s", deviceInfo.id, "N/A", c_deviceStateString[deviceInfo.status]);
     }
     else
     {
         return gmx::formatString("#%d: name: %s, vendor: %s, device version: %s, status: %s",
-                                 deviceInfo.id, deviceInfo.device_name, deviceInfo.vendorName,
-                                 deviceInfo.device_version, c_deviceStateString[deviceInfo.status]);
+                                 deviceInfo.id,
+                                 deviceInfo.device_name,
+                                 deviceInfo.vendorName,
+                                 deviceInfo.device_version,
+                                 c_deviceStateString[deviceInfo.status]);
     }
 }
index fb84d41f2b14a937e56c3c3118b0e792ffd69a1e..04d8ab543c5c2b4d3cbb6fe18193f902125a0a99 100644 (file)
@@ -44,6 +44,8 @@
  */
 #include "gmxpre.h"
 
+#include <map>
+
 #include "gromacs/gpu_utils/gmxsycl.h"
 #include "gromacs/hardware/device_management.h"
 #include "gromacs/utility/fatalerror.h"
@@ -92,14 +94,55 @@ static DeviceStatus isDeviceCompatible(const cl::sycl::device& syclDevice)
         return DeviceStatus::Compatible;
     }
 
-    if (syclDevice.is_accelerator()) // FPGAs and FPGA emulators
+    if (syclDevice.get_info<cl::sycl::info::device::local_mem_type>() == cl::sycl::info::local_mem_type::none)
     {
+        // While some kernels (leapfrog) can run without shared/local memory, this is a bad sign
         return DeviceStatus::Incompatible;
     }
-    else
+
+    if (syclDevice.is_host())
+    {
+        // Host device does not support subgroups or even querying for sub_group_sizes
+        return DeviceStatus::Incompatible;
+    }
+
+#if GMX_SYCL_HIPSYCL
+    /* At the time of writing:
+     * 1. SYCL NB kernels currently don't support sub_group size of 32 or 64, which are the only
+     * ones available on NVIDIA and AMD hardware, respectively. That's not a fundamental limitation,
+     * but requires porting more OpenCL code, see #3934.
+     * 2. hipSYCL does not support cl::sycl::info::device::sub_group_sizes,
+     * see https://github.com/illuhad/hipSYCL/pull/449
+     */
+    const std::vector<size_t> supportedSubGroupSizes{ warpSize };
+#else
+    const std::vector<size_t> supportedSubGroupSizes =
+            syclDevice.get_info<cl::sycl::info::device::sub_group_sizes>();
+#endif
+    const size_t requiredSubGroupSizeForNBNXM = 8;
+    if (std::find(supportedSubGroupSizes.begin(), supportedSubGroupSizes.end(), requiredSubGroupSizeForNBNXM)
+        == supportedSubGroupSizes.end())
+    {
+        return DeviceStatus::IncompatibleClusterSize;
+    }
+
+    /* Host device can not be used, because NBNXM requires sub-groups, which are not supported.
+     * Accelerators (FPGAs and their emulators) are not supported.
+     * So, the only viable options are CPUs and GPUs. */
+    const bool forceCpu = (getenv("GMX_SYCL_FORCE_CPU") != nullptr);
+
+    if (forceCpu && syclDevice.is_cpu())
     {
         return DeviceStatus::Compatible;
     }
+    else if (!forceCpu && syclDevice.is_gpu())
+    {
+        return DeviceStatus::Compatible;
+    }
+    else
+    {
+        return DeviceStatus::Incompatible;
+    }
 }
 
 
@@ -147,9 +190,10 @@ static bool isDeviceFunctional(const cl::sycl::device& syclDevice, std::string*
     {
         if (errorMessage != nullptr)
         {
-            errorMessage->assign(gmx::formatString(
-                    "Unable to run dummy kernel on device %s: %s",
-                    syclDevice.get_info<cl::sycl::info::device::name>().c_str(), e.what()));
+            errorMessage->assign(
+                    gmx::formatString("Unable to run dummy kernel on device %s: %s",
+                                      syclDevice.get_info<cl::sycl::info::device::name>().c_str(),
+                                      e.what()));
         }
         return false;
     }
@@ -187,6 +231,65 @@ static DeviceStatus checkDevice(size_t deviceId, const DeviceInformation& device
     return DeviceStatus::Compatible;
 }
 
+/* In DPCPP, the same physical device can appear as different virtual devices provided
+ * by different backends (e.g., the same GPU can be accessible via both OpenCL and L0).
+ * Thus, using devices from two backends is more likely to be a user error than the
+ * desired behavior. In this function, we choose the backend with the most compatible
+ * devices. In case of a tie, we choose OpenCL (if present), or some arbitrary backend
+ * among those with the most devices.
+ *
+ * In hipSYCL, this problem is unlikely to manifest. It has (as of 2021-03-03) another
+ * issues: D2D copy between different backends is not allowed. We don't use D2D in
+ * SYCL yet. Additionally, hipSYCL does not implement the `sycl::platform::get_backend()`
+ * function.
+ * Thus, we only do the backend filtering with DPCPP.
+ * */
+#if GMX_SYCL_DPCPP
+static std::optional<cl::sycl::backend>
+chooseBestBackend(const std::vector<std::unique_ptr<DeviceInformation>>& deviceInfos)
+{
+    // Count the number of compatible devices per backend
+    std::map<cl::sycl::backend, int> countDevicesByBackend; // Default initialized with zeros
+    for (const auto& deviceInfo : deviceInfos)
+    {
+        if (deviceInfo->status == DeviceStatus::Compatible)
+        {
+            const cl::sycl::backend backend = deviceInfo->syclDevice.get_platform().get_backend();
+            ++countDevicesByBackend[backend];
+        }
+    }
+    // If we have devices from more than one backend...
+    if (countDevicesByBackend.size() > 1)
+    {
+        // Find backend with most devices
+        const auto backendWithMostDevices = std::max_element(
+                countDevicesByBackend.cbegin(),
+                countDevicesByBackend.cend(),
+                [](const auto& kv1, const auto& kv2) { return kv1.second < kv2.second; });
+        // Count devices provided by OpenCL. Will be zero if no OpenCL devices found.
+        const int devicesInOpenCL = countDevicesByBackend[cl::sycl::backend::opencl];
+        if (devicesInOpenCL == backendWithMostDevices->second)
+        {
+            // Prefer OpenCL backend as more stable, if it has as many devices as others
+            return cl::sycl::backend::opencl;
+        }
+        else
+        {
+            // Otherwise, just return max
+            return backendWithMostDevices->first;
+        }
+    }
+    else if (countDevicesByBackend.size() == 1)
+    {
+        return countDevicesByBackend.cbegin()->first;
+    }
+    else // No devices found
+    {
+        return std::nullopt;
+    }
+}
+#endif
+
 std::vector<std::unique_ptr<DeviceInformation>> findDevices()
 {
     std::vector<std::unique_ptr<DeviceInformation>> deviceInfos(0);
@@ -204,6 +307,23 @@ std::vector<std::unique_ptr<DeviceInformation>> findDevices()
         deviceInfos[i]->deviceVendor =
                 getDeviceVendor(syclDevice.get_info<cl::sycl::info::device::vendor>().c_str());
     }
+#if GMX_SYCL_DPCPP
+    // Now, filter by the backend if we did not disable compatibility check
+    if (getenv("GMX_GPU_DISABLE_COMPATIBILITY_CHECK") == nullptr)
+    {
+        std::optional<cl::sycl::backend> preferredBackend = chooseBestBackend(deviceInfos);
+        if (preferredBackend.has_value())
+        {
+            for (auto& deviceInfo : deviceInfos)
+            {
+                if (deviceInfo->syclDevice.get_platform().get_backend() != *preferredBackend)
+                {
+                    deviceInfo->status = DeviceStatus::NotPreferredBackend;
+                }
+            }
+        }
+    }
+#endif
     return deviceInfos;
 }
 
@@ -218,13 +338,14 @@ std::string getDeviceInformationString(const DeviceInformation& deviceInfo)
 
     if (!deviceExists)
     {
-        return gmx::formatString("#%d: %s, status: %s", deviceInfo.id, "N/A",
-                                 c_deviceStateString[deviceInfo.status]);
+        return gmx::formatString(
+                "#%d: %s, status: %s", deviceInfo.id, "N/A", c_deviceStateString[deviceInfo.status]);
     }
     else
     {
         return gmx::formatString(
-                "#%d: name: %s, vendor: %s, device version: %s, status: %s", deviceInfo.id,
+                "#%d: name: %s, vendor: %s, device version: %s, status: %s",
+                deviceInfo.id,
                 deviceInfo.syclDevice.get_info<cl::sycl::info::device::name>().c_str(),
                 deviceInfo.syclDevice.get_info<cl::sycl::info::device::vendor>().c_str(),
                 deviceInfo.syclDevice.get_info<cl::sycl::info::device::version>().c_str(),
index 1e9d785ce4317267a67a2597b7822905607c518a..25330ef66311bd017d1691a5492d670b2a733c79 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -106,7 +106,7 @@ void parseCpuInfo(HardwareTopology::Machine* machine, HardwareTopology::SupportL
         int nHwThreads = 0;
 
         // Copy the logical processor information from cpuinfo
-        for (auto& l : cpuInfo.logicalProcessors())
+        for (const auto& l : cpuInfo.logicalProcessors())
         {
             machine->logicalProcessors.push_back(
                     { l.socketRankInMachine, l.coreRankInSocket, l.hwThreadRankInCore, -1 });
@@ -218,8 +218,8 @@ std::vector<const hwloc_obj*> getHwLocDescendantsByType(const hwloc_topology*  t
     // Go through children; if this object has no children obj->arity is 0,
     // and we'll return an empty vector.
     hwloc_obj_t tempNode = nullptr;
-    while ((tempNode = hwloc_get_next_child(const_cast<hwloc_topology_t>(topo),
-                                            const_cast<hwloc_obj_t>(obj), tempNode))
+    while ((tempNode = hwloc_get_next_child(
+                    const_cast<hwloc_topology_t>(topo), const_cast<hwloc_obj_t>(obj), tempNode))
            != nullptr)
     {
         std::vector<const hwloc_obj*> v2 = getHwLocDescendantsByType(topo, tempNode, type);
@@ -342,7 +342,6 @@ bool parseHwLocCache(hwloc_topology_t topo, HardwareTopology::Machine* machine)
     return !machine->caches.empty();
 }
 
-
 /*! \brief Read numa information from hwloc topology
  *
  *  \param topo    hwloc topology handle that has been initialized and loaded
@@ -463,8 +462,11 @@ bool parseHwLocNuma(hwloc_topology_t topo, HardwareTopology::Machine* machine)
         // assign stuff
         for (auto& v : machine->numa.relativeLatency)
         {
-            std::transform(v.begin(), v.end(), v.begin(),
-                           std::bind(std::multiplies<float>(), std::placeholders::_1, 1.0 / minLatency));
+            // Rescale the latencies to a relative float-point value
+            for (float& value : v)
+            {
+                value /= minLatency;
+            }
         }
         machine->numa.baseLatency = 1.0; // latencies still do not have any units in hwloc-2.x
         machine->numa.maxRelativeLatency = maxLatency / minLatency;
@@ -589,9 +591,13 @@ bool parseHwLocDevices(hwloc_topology_t topo, HardwareTopology::Machine* machine
 
         GMX_RELEASE_ASSERT(p->attr, "Attributes should not be NULL for hwloc PCI object");
 
-        machine->devices.push_back({ p->attr->pcidev.vendor_id, p->attr->pcidev.device_id,
-                                     p->attr->pcidev.class_id, p->attr->pcidev.domain,
-                                     p->attr->pcidev.bus, p->attr->pcidev.dev, p->attr->pcidev.func,
+        machine->devices.push_back({ p->attr->pcidev.vendor_id,
+                                     p->attr->pcidev.device_id,
+                                     p->attr->pcidev.class_id,
+                                     p->attr->pcidev.domain,
+                                     p->attr->pcidev.bus,
+                                     p->attr->pcidev.dev,
+                                     p->attr->pcidev.func,
                                      numaId });
     }
     return !pcidevs.empty();
index b52ad0a3b06887fcb4ab2ab3ce2947536c5482f4..065cb1d42bc76acc381b5d8af395bb4d61914811 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -186,7 +186,6 @@ public:
         std::vector<Device>           devices;           //!< Devices on PCI bus
     };
 
-public:
     /*! \brief Detects the hardware topology. */
     static HardwareTopology detect();
 
index 4d51d955adef28c88cd822041b06d4bd1e1183e1..044c8dd86b47e28eabe4ae4bb9b1cc09f38078b3 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -134,9 +134,9 @@ struct gmx_hw_opt_t
     //! Logical core pinning offset.
     int core_pinning_offset = 0;
     //! Empty, or a string provided by the user declaring (unique) GPU IDs available for mdrun to use.
-    std::string gpuIdsAvailable = "";
+    std::string devicesSelectedByUser;
     //! Empty, or a string provided by the user mapping GPU tasks to devices.
-    std::string userGpuTaskAssignment = "";
+    std::string userGpuTaskAssignment;
     //! Tells whether mdrun is free to choose the total number of threads (by choosing the number of OpenMP and/or thread-MPI threads).
     bool totNumThreadsIsAuto;
 };
index 3ee4686533482d25c781336ba68c3083b0177125..b7ae52707c3ce0457c91c216ced8de92fbf0689c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -152,9 +152,35 @@ uint64_t timeFmaAndShuffleLoop(uint64_t loopCount)
             "\tmovq %%rdx, %0\n"
             : "=r"(cycles)
             : "r"(loopCount)
-            : "rax", "rbx", "rcx", "rdx", "zmm0", "zmm1", "zmm2", "zmm3", "zmm4", "zmm5", "zmm6",
-              "zmm7", "zmm8", "zmm9", "zmm10", "zmm11", "zmm12", "zmm13", "zmm14", "zmm15", "zmm16",
-              "zmm17", "zmm18", "zmm19", "zmm20", "zmm21", "zmm22", "zmm23", "zmm30");
+            : "rax",
+              "rbx",
+              "rcx",
+              "rdx",
+              "zmm0",
+              "zmm1",
+              "zmm2",
+              "zmm3",
+              "zmm4",
+              "zmm5",
+              "zmm6",
+              "zmm7",
+              "zmm8",
+              "zmm9",
+              "zmm10",
+              "zmm11",
+              "zmm12",
+              "zmm13",
+              "zmm14",
+              "zmm15",
+              "zmm16",
+              "zmm17",
+              "zmm18",
+              "zmm19",
+              "zmm20",
+              "zmm21",
+              "zmm22",
+              "zmm23",
+              "zmm30");
 
     return cycles;
 }
@@ -219,8 +245,22 @@ uint64_t timeFmaOnlyLoop(uint64_t loopCount)
             "\tmovq %%rdx, %0\n"
             : "=r"(cycles)
             : "r"(loopCount)
-            : "rax", "rbx", "rcx", "rdx", "zmm0", "zmm1", "zmm2", "zmm3", "zmm4", "zmm5", "zmm6",
-              "zmm7", "zmm8", "zmm9", "zmm10", "zmm11");
+            : "rax",
+              "rbx",
+              "rcx",
+              "rdx",
+              "zmm0",
+              "zmm1",
+              "zmm2",
+              "zmm3",
+              "zmm4",
+              "zmm5",
+              "zmm6",
+              "zmm7",
+              "zmm8",
+              "zmm9",
+              "zmm10",
+              "zmm11");
 
     return cycles;
 }
@@ -252,6 +292,7 @@ bool checkDualAvx512FmaUnits()
  * We only execute the test once, and return the saved result
  * on subsequent calls.
  */
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 std::mutex initMutex;
 
 } // namespace
index 853192f52a70c810c54d8f5ee6ab502fedc727b1..296b4844fc0229542c0da7f2909f9c7860c34866 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -73,18 +73,8 @@ namespace gmx
  *  (using sysconf), and the spins doing dummy compute operations for up to
  *  2 seconds, or until all cores have come online. This can be used prior to
  *  hardware detection for platforms that take unused processors offline.
- *
- *  This routine will not throw exceptions. In principle it should be
- *  declared noexcept, but at least icc 19.1 and 21-beta08 with the
- *  libstdc++-7.5 has difficulty implementing a std::vector of
- *  std::thread started with this function when declared noexcept. It
- *  is a known compiler bug that should be fixed after 19.1.
- *  Fortunately, this function is not performance sensitive,
- *  and only runs on platforms other than x86 and POWER (ie ARM),
- *  so the possible overhead introduced by omitting noexcept is not
- *  important.
  */
-static void spinUpCore()
+static void spinUpCore() noexcept
 {
 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF) && defined(_SC_NPROCESSORS_ONLN)
     float dummy           = 0.1;
index 0720a12bbe9398a344acffd7eb8f6d24ad491268..32a5eedda6e15d545dc5ab0f8da93e34ea0dc364 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016, The GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -125,7 +125,8 @@ static void check_use_of_rdtscp_on_this_cpu(const gmx::MDLogger& mdlog, const gm
                             "speed as accurate timings are needed for load-balancing.\n"
                             "Please consider rebuilding %s with the GMX_USE_RDTSCP=ON CMake "
                             "option.",
-                            programName, programName);
+                            programName,
+                            programName);
         }
     }
 }
@@ -138,7 +139,8 @@ static std::string detected_hardware_string(const gmx_hw_info_t* hwinfo, bool bF
     const gmx::HardwareTopology& hwTop   = *hwinfo->hardwareTopology;
 
     s = gmx::formatString("\n");
-    s += gmx::formatString("Running on %d node%s with total", hwinfo->nphysicalnode,
+    s += gmx::formatString("Running on %d node%s with total",
+                           hwinfo->nphysicalnode,
                            hwinfo->nphysicalnode == 1 ? "" : "s");
     if (hwinfo->ncore_tot > 0)
     {
@@ -147,7 +149,8 @@ static std::string detected_hardware_string(const gmx_hw_info_t* hwinfo, bool bF
     s += gmx::formatString(" %d logical cores", hwinfo->nhwthread_tot);
     if (canPerformDeviceDetection(nullptr))
     {
-        s += gmx::formatString(", %d compatible GPU%s", hwinfo->ngpu_compatible_tot,
+        s += gmx::formatString(", %d compatible GPU%s",
+                               hwinfo->ngpu_compatible_tot,
                                hwinfo->ngpu_compatible_tot == 1 ? "" : "s");
     }
     else if (bGPUBinary)
@@ -228,11 +231,13 @@ static std::string detected_hardware_string(const gmx_hw_info_t* hwinfo, bool bF
 
     if (bFullCpuInfo)
     {
-        s += gmx::formatString("    Family: %d   Model: %d   Stepping: %d\n", cpuInfo.family(),
-                               cpuInfo.model(), cpuInfo.stepping());
+        s += gmx::formatString("    Family: %d   Model: %d   Stepping: %d\n",
+                               cpuInfo.family(),
+                               cpuInfo.model(),
+                               cpuInfo.stepping());
 
         s += gmx::formatString("    Features:");
-        for (auto& f : cpuInfo.featureSet())
+        for (const auto& f : cpuInfo.featureSet())
         {
             s += gmx::formatString(" %s", gmx::CpuInfo::featureString(f).c_str());
         }
@@ -287,13 +292,13 @@ static std::string detected_hardware_string(const gmx_hw_info_t* hwinfo, bool bF
         {
             s += gmx::formatString("    Sockets, cores, and logical processors:\n");
 
-            for (auto& socket : hwTop.machine().sockets)
+            for (const auto& socket : hwTop.machine().sockets)
             {
                 s += gmx::formatString("      Socket %2d:", socket.id);
-                for (auto& c : socket.cores)
+                for (const auto& c : socket.cores)
                 {
                     s += gmx::formatString(" [");
-                    for (auto& t : c.hwThreads)
+                    for (const auto& t : c.hwThreads)
                     {
                         s += gmx::formatString(" %3d", t.logicalProcessorId);
                     }
@@ -305,10 +310,10 @@ static std::string detected_hardware_string(const gmx_hw_info_t* hwinfo, bool bF
         if (hwTop.supportLevel() >= gmx::HardwareTopology::SupportLevel::Full)
         {
             s += gmx::formatString("    Numa nodes:\n");
-            for (auto& n : hwTop.machine().numa.nodes)
+            for (const auto& n : hwTop.machine().numa.nodes)
             {
                 s += gmx::formatString("      Node %2d (%zu bytes mem):", n.id, n.memory);
-                for (auto& l : n.logicalProcessorId)
+                for (const auto& l : n.logicalProcessorId)
                 {
                     s += gmx::formatString(" %3d", l);
                 }
@@ -332,21 +337,32 @@ static std::string detected_hardware_string(const gmx_hw_info_t* hwinfo, bool bF
 
 
             s += gmx::formatString("    Caches:\n");
-            for (auto& c : hwTop.machine().caches)
+            for (const auto& c : hwTop.machine().caches)
             {
                 s += gmx::formatString(
                         "      L%d: %zu bytes, linesize %d bytes, assoc. %d, shared %d ways\n",
-                        c.level, c.size, c.linesize, c.associativity, c.shared);
+                        c.level,
+                        c.size,
+                        c.linesize,
+                        c.associativity,
+                        c.shared);
             }
         }
         if (hwTop.supportLevel() >= gmx::HardwareTopology::SupportLevel::FullWithDevices)
         {
             s += gmx::formatString("    PCI devices:\n");
-            for (auto& d : hwTop.machine().devices)
+            for (const auto& d : hwTop.machine().devices)
             {
                 s += gmx::formatString(
-                        "      %04x:%02x:%02x.%1x  Id: %04x:%04x  Class: 0x%04x  Numa: %d\n", d.domain,
-                        d.bus, d.dev, d.func, d.vendorId, d.deviceId, d.classId, d.numaNodeId);
+                        "      %04x:%02x:%02x.%1x  Id: %04x:%04x  Class: 0x%04x  Numa: %d\n",
+                        d.domain,
+                        d.bus,
+                        d.dev,
+                        d.func,
+                        d.vendorId,
+                        d.deviceId,
+                        d.classId,
+                        d.numaNodeId);
             }
         }
     }
diff --git a/src/gromacs/hardware/tests/.clang-tidy b/src/gromacs/hardware/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 53937307d614a75ae9d80386b795f25ef15a71b5..d0ea6a73b663d472c45d4285cabb38224788cd1d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +76,7 @@ TEST(CpuInfoTest, SupportLevel)
     if (c.supportLevel() >= gmx::CpuInfo::SupportLevel::LogicalProcessorInfo)
     {
         // Make sure assigned numbers are reasonable if we have them
-        for (auto& l : c.logicalProcessors())
+        for (const auto& l : c.logicalProcessors())
         {
             EXPECT_GE(l.socketRankInMachine, 0)
                     << "Impossible socket index for logical processor. " << commonMsg << std::endl;
index 537807bd65180a139c4040f00d95754cad318349..92a18641dd6c2fddabdc76545a1f0b109527f91b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@ TEST(HardwareTopologyTest, ProcessorSelfconsistency)
 
         auto logicalProcessors = hwTop.machine().logicalProcessors;
         for (auto logicalProcessorIt = logicalProcessors.begin();
-             logicalProcessorIt != logicalProcessors.end(); ++logicalProcessorIt)
+             logicalProcessorIt != logicalProcessors.end();
+             ++logicalProcessorIt)
         {
             // Check that logical processor information contains
             // reasonable values.
@@ -128,7 +129,8 @@ TEST(HardwareTopologyTest, ProcessorSelfconsistency)
             // for each logical processor.
 
             for (auto remainingLogicalProcessorIt = logicalProcessorIt + 1;
-                 remainingLogicalProcessorIt != logicalProcessors.end(); ++remainingLogicalProcessorIt)
+                 remainingLogicalProcessorIt != logicalProcessors.end();
+                 ++remainingLogicalProcessorIt)
             {
                 SCOPED_TRACE(gmx::formatString("Other socket rank in machine: %d",
                                                remainingLogicalProcessorIt->socketRankInMachine));
@@ -161,7 +163,7 @@ TEST(HardwareTopologyTest, NumaCacheSelfconsistency)
 
         // Check that the sum of numa domains is the total processor count
         int processorsinNumaNudes = 0;
-        for (auto& n : hwTop.machine().numa.nodes)
+        for (const auto& n : hwTop.machine().numa.nodes)
         {
             processorsinNumaNudes += n.logicalProcessorId.size();
         }
@@ -173,9 +175,9 @@ TEST(HardwareTopologyTest, NumaCacheSelfconsistency)
         {
             elem = 0;
         }
-        for (auto& n : hwTop.machine().numa.nodes)
+        for (const auto& n : hwTop.machine().numa.nodes)
         {
-            for (auto& idx : n.logicalProcessorId)
+            for (const auto& idx : n.logicalProcessorId)
             {
                 v[idx] = 1;
             }
@@ -184,7 +186,7 @@ TEST(HardwareTopologyTest, NumaCacheSelfconsistency)
         EXPECT_EQ(uniqueProcessorsinNumaNudes, hwTop.machine().logicalProcessorCount);
 
         // We must have some memory in a numa node
-        for (auto& n : hwTop.machine().numa.nodes)
+        for (const auto& n : hwTop.machine().numa.nodes)
         {
             EXPECT_GT(n.memory, 0);
         }
@@ -194,11 +196,11 @@ TEST(HardwareTopologyTest, NumaCacheSelfconsistency)
         EXPECT_GT(hwTop.machine().numa.maxRelativeLatency, 0);
         // Check number of rows matches # numa nodes
         EXPECT_EQ(hwTop.machine().numa.relativeLatency.size(), hwTop.machine().numa.nodes.size());
-        for (auto& v2 : hwTop.machine().numa.relativeLatency)
+        for (const auto& v2 : hwTop.machine().numa.relativeLatency)
         {
             // Check that size of each row matches # numa nodes
             EXPECT_EQ(v2.size(), hwTop.machine().numa.nodes.size());
-            for (auto& latency : v2)
+            for (const auto& latency : v2)
             {
                 // Latency values should be positive
                 EXPECT_GT(latency, 0);
index 0b47f378724845a9cd171351ca54eb332c6fae50..e48c21f9a06a855e7ca76e88f94e34b3634a6c92 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,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+add_library(imd INTERFACE)
 file(GLOB IMD_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${IMD_SOURCES} PARENT_SCOPE)
+
+# Source files have the following private module dependencies.
+target_link_libraries(imd PRIVATE
+#                      gmxlib
+#                      math
+#                      mdtypes
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(imd PUBLIC
+target_include_directories(imd INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(imd PUBLIC
+target_link_libraries(imd INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when imd is an OBJECT target
+#target_link_libraries(imd PUBLIC legacy_api)
+#target_link_libraries(imd PRIVATE common)
+
+# Module dependencies
+# imd interfaces convey transitive dependence on these modules.
+#target_link_libraries(imd PUBLIC
+target_link_libraries(imd INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(imd PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(imd PRIVATE legacy_modules)
index 6b5d3d28f4443d9cb9669b039dc264b81daf27df..7050b67956f87a67b0a987c5667cb64cf063452d 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
  */
 #include "gmxpre.h"
 
+#include "gromacs/utility/enumerationhelpers.h"
 #include "imd.h"
 
 #include "config.h"
@@ -82,6 +83,7 @@
 #include "gromacs/timing/wallcycle.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/logger.h"
 #include "gromacs/utility/smalloc.h"
@@ -102,6 +104,8 @@ constexpr int c_headerSize = 8;
 /*! \brief IMD Protocol Version. */
 constexpr int c_protocolVersion = 2;
 
+enum class IMDMessageType : int;
+
 /*! \internal
  * \brief
  * IMD (interactive molecular dynamics) energy record.
@@ -179,7 +183,7 @@ public:
      * Do conversion from Cal->Joule and from
      * Angstrom -> nm and from a pointer array to arrays to 3*N array.
      */
-    void copyToMDForces();
+    void copyToMDForces() const;
     /*! \brief Return true if any of the forces or indices changed. */
     bool bForcesChanged() const;
     /*! \brief Update the old_f_ind and old_forces arrays to contain the current values. */
@@ -199,13 +203,13 @@ public:
      */
     void openOutputFile(const char* fn, int nat_total, const gmx_output_env_t* oenv, StartingBehavior startingBehavior);
     /*! \brief Creates the molecule start-end position array of molecules in the IMD group. */
-    void prepareMoleculesInImdGroup(const gmx_mtop_t* top_global);
+    void prepareMoleculesInImdGroup(const gmx_mtop_t& top_global);
     /*! \brief Removes shifts of molecules diffused outside of the box. */
-    void removeMolecularShifts(const matrix box);
+    void removeMolecularShifts(const matrix box) const;
     /*! \brief Initialize arrays used to assemble the positions from the other nodes. */
-    void prepareForPositionAssembly(const t_commrec* cr, const rvec x[]);
+    void prepareForPositionAssembly(const t_commrec* cr, gmx::ArrayRef<const gmx::RVec> coords);
     /*! \brief Interact with any connected VMD session */
-    bool run(int64_t step, bool bNS, const matrix box, const rvec x[], double t);
+    bool run(int64_t step, bool bNS, const matrix box, gmx::ArrayRef<const gmx::RVec> coords, double t);
 
     // TODO rename all the data members to have underscore suffixes
 
@@ -326,8 +330,8 @@ class InteractiveMolecularDynamics final : public IMDModule
     IMdpOptionProvider* mdpOptionProvider() override { return nullptr; }
     IMDOutputProvider*  outputProvider() override { return nullptr; }
     void                initForceProviders(ForceProviders* /* forceProviders */) override {}
-    void subscribeToSimulationSetupNotifications(MdModulesNotifier* /* notifier */) override {}
-    void subscribeToPreProcessingNotifications(MdModulesNotifier* /* notifier */) override {}
+    void subscribeToSimulationSetupNotifications(MDModulesNotifiers* /* notifiers */) override {}
+    void subscribeToPreProcessingNotifications(MDModulesNotifiers* /* notifiers */) override {}
 };
 
 std::unique_ptr<IMDModule> createInteractiveMolecularDynamicsModule()
@@ -339,35 +343,39 @@ std::unique_ptr<IMDModule> createInteractiveMolecularDynamicsModule()
  *
  * We use the same records as the NAMD/VMD IMD implementation.
  */
-typedef enum IMDType_t
+enum class IMDMessageType : int
 {
-    IMD_DISCONNECT, /**< client disconnect                               */
-    IMD_ENERGIES,   /**< energy data                                     */
-    IMD_FCOORDS,    /**< atomic coordinates                              */
-    IMD_GO,         /**< start command for the simulation                */
-    IMD_HANDSHAKE,  /**< handshake to determine little/big endianness    */
-    IMD_KILL,       /**< terminates the simulation                       */
-    IMD_MDCOMM,     /**< force data                                      */
-    IMD_PAUSE,      /**< pauses the simulation                           */
-    IMD_TRATE,      /**< sets the IMD transmission and processing rate   */
-    IMD_IOERROR,    /**< I/O error                                       */
-    IMD_NR          /**< number of entries                               */
-} IMDMessageType;
+    Disconnect, /**< client disconnect                               */
+    Energies,   /**< energy data                                     */
+    FCoords,    /**< atomic coordinates                              */
+    Go,         /**< start command for the simulation                */
+    Handshake,  /**< handshake to determine little/big endianness    */
+    Kill,       /**< terminates the simulation                       */
+    Mdcomm,     /**< force data                                      */
+    Pause,      /**< pauses the simulation                           */
+    TRate,      /**< sets the IMD transmission and processing rate   */
+    IOerror,    /**< I/O error                                       */
+    Count       /**< number of entries                               */
+};
 
 
 /*! \brief Names of the IMDType for error messages.
  */
-static const char* eIMDType_names[IMD_NR + 1] = { "IMD_DISCONNECT", "IMD_ENERGIES",  "IMD_FCOORDS",
-                                                  "IMD_GO",         "IMD_HANDSHAKE", "IMD_KILL",
-                                                  "IMD_MDCOMM",     "IMD_PAUSE",     "IMD_TRATE",
-                                                  "IMD_IOERROR",    nullptr };
+static const char* enumValueToString(IMDMessageType enumValue)
+{
+    constexpr gmx::EnumerationArray<IMDMessageType, const char*> imdMessageTypeNames = {
+        "IMD_DISCONNECT", "IMD_ENERGIES", "IMD_FCOORDS", "IMD_GO",    "IMD_HANDSHAKE",
+        "IMD_KILL",       "IMD_MDCOMM",   "IMD_PAUSE",   "IMD_TRATE", "IMD_IOERROR"
+    };
+    return imdMessageTypeNames[enumValue];
+}
 
 
 /*! \brief Fills the header with message and the length argument. */
 static void fill_header(IMDHeader* header, IMDMessageType type, int32_t length)
 {
     /* We (ab-)use htonl network function for the correct endianness */
-    header->type   = imd_htonl(static_cast<int32_t>(type));
+    header->type   = imd_htonl(static_cast<int>(type));
     header->length = imd_htonl(length);
 }
 
@@ -376,7 +384,7 @@ static void fill_header(IMDHeader* header, IMDMessageType type, int32_t length)
 static void swap_header(IMDHeader* header)
 {
     /* and vice versa... */
-    header->type   = imd_ntohl(header->type);
+    header->type   = imd_ntohl(static_cast<int>(header->type));
     header->length = imd_ntohl(header->length);
 }
 
@@ -453,7 +461,7 @@ static int imd_handshake(IMDSocket* socket)
     IMDHeader header;
 
 
-    fill_header(&header, IMD_HANDSHAKE, 1);
+    fill_header(&header, IMDMessageType::Handshake, 1);
     header.length = c_protocolVersion; /* client wants unswapped version */
 
     return static_cast<int>(imd_write_multiple(socket, reinterpret_cast<char*>(&header), c_headerSize)
@@ -468,7 +476,7 @@ static int imd_send_energies(IMDSocket* socket, const IMDEnergyBlock* energies,
 
 
     recsize = c_headerSize + sizeof(IMDEnergyBlock);
-    fill_header(reinterpret_cast<IMDHeader*>(buffer), IMD_ENERGIES, 1);
+    fill_header(reinterpret_cast<IMDHeader*>(buffer), IMDMessageType::Energies, 1);
     memcpy(buffer + c_headerSize, energies, sizeof(IMDEnergyBlock));
 
     return static_cast<int>(imd_write_multiple(socket, buffer, recsize) != recsize);
@@ -483,7 +491,7 @@ static IMDMessageType imd_recv_header(IMDSocket* socket, int32_t* length)
 
     if (imd_read_multiple(socket, reinterpret_cast<char*>(&header), c_headerSize) != c_headerSize)
     {
-        return IMD_IOERROR;
+        return IMDMessageType::IOerror;
     }
     swap_header(&header);
     *length = header.length;
@@ -516,7 +524,7 @@ static bool imd_recv_mdcomm(IMDSocket* socket, int32_t nforces, int32_t* forcend
 void write_IMDgroup_to_file(bool              bIMD,
                             t_inputrec*       ir,
                             const t_state*    state,
-                            const gmx_mtop_t* sys,
+                            const gmx_mtop_t& sys,
                             int               nfile,
                             const t_filenm    fnm[])
 {
@@ -526,9 +534,15 @@ void write_IMDgroup_to_file(bool              bIMD,
     if (bIMD)
     {
         IMDatoms = gmx_mtop_global_atoms(sys);
-        write_sto_conf_indexed(opt2fn("-imd", nfile, fnm), "IMDgroup", &IMDatoms,
-                               state->x.rvec_array(), state->v.rvec_array(), ir->pbcType,
-                               state->box, ir->imd->nat, ir->imd->ind);
+        write_sto_conf_indexed(opt2fn("-imd", nfile, fnm),
+                               "IMDgroup",
+                               &IMDatoms,
+                               state->x.rvec_array(),
+                               state->v.rvec_array(),
+                               ir->pbcType,
+                               state->box,
+                               ir->imd->nat,
+                               ir->imd->ind);
     }
 }
 
@@ -540,8 +554,8 @@ void ImdSession::dd_make_local_IMD_atoms(const gmx_domdec_t* dd)
         return;
     }
 
-    dd_make_local_group_indices(dd->ga2la, impl_->nat, impl_->ind, &impl_->nat_loc, &impl_->ind_loc,
-                                &impl_->nalloc_loc, impl_->xa_ind);
+    dd_make_local_group_indices(
+            dd->ga2la, impl_->nat, impl_->ind, &impl_->nat_loc, &impl_->ind_loc, &impl_->nalloc_loc, impl_->xa_ind);
 }
 
 
@@ -561,12 +575,12 @@ static int imd_send_rvecs(IMDSocket* socket, int nat, rvec* x, char* buffer)
     size = c_headerSize + 3 * sizeof(float) * nat;
 
     /* Prepare header */
-    fill_header(reinterpret_cast<IMDHeader*>(buffer), IMD_FCOORDS, static_cast<int32_t>(nat));
+    fill_header(reinterpret_cast<IMDHeader*>(buffer), IMDMessageType::FCoords, static_cast<int32_t>(nat));
     for (i = 0; i < nat; i++)
     {
-        sendx[0] = static_cast<float>(x[i][0]) * NM2A;
-        sendx[1] = static_cast<float>(x[i][1]) * NM2A;
-        sendx[2] = static_cast<float>(x[i][2]) * NM2A;
+        sendx[0] = static_cast<float>(x[i][0]) * gmx::c_nm2A;
+        sendx[1] = static_cast<float>(x[i][1]) * gmx::c_nm2A;
+        sendx[2] = static_cast<float>(x[i][2]) * gmx::c_nm2A;
         memcpy(buffer + c_headerSize + i * tuplesize, sendx, tuplesize);
     }
 
@@ -662,7 +676,7 @@ bool ImdSession::Impl::tryConnect()
 
         /* Check if we get the proper "GO" command from client. */
         if (imdsock_tryread(clientsocket, c_connectWait, 0) != 1
-            || imd_recv_header(clientsocket, &(length)) != IMD_GO)
+            || imd_recv_header(clientsocket, &(length)) != IMDMessageType::Go)
         {
             issueFatalError("No IMD_GO order received. IMD connection failed.");
         }
@@ -680,7 +694,7 @@ bool ImdSession::Impl::tryConnect()
 void ImdSession::Impl::blockConnect()
 {
     /* do not wait for connection, when e.g. ctrl+c is pressed and we will terminate anyways. */
-    if (!(static_cast<int>(gmx_get_stop_condition()) == gmx_stop_cond_none))
+    if (!(gmx_get_stop_condition() == StopCondition::None))
     {
         return;
     }
@@ -689,7 +703,7 @@ void ImdSession::Impl::blockConnect()
             .appendTextFormatted("%s Will wait until I have a connection and IMD_GO orders.", IMDstr);
 
     /* while we have no clientsocket... 2nd part: we should still react on ctrl+c */
-    while ((!clientsocket) && (static_cast<int>(gmx_get_stop_condition()) == gmx_stop_cond_none))
+    while ((!clientsocket) && (gmx_get_stop_condition() == StopCondition::None))
     {
         tryConnect();
         imd_sleep(c_loopWait);
@@ -725,10 +739,10 @@ void ImdSession::Impl::prepareMDForces()
 }
 
 
-void ImdSession::Impl::copyToMDForces()
+void ImdSession::Impl::copyToMDForces() const
 {
     int  i;
-    real conversion = CAL2JOULE * NM2A;
+    real conversion = gmx::c_cal2Joule * gmx::c_nm2A;
 
 
     for (i = 0; i < nforces; i++)
@@ -930,7 +944,7 @@ void ImdSession::Impl::readCommand()
         switch (itype)
         {
             /* IMD asks us to terminate the simulation, check if the user allowed this */
-            case IMD_KILL:
+            case IMDMessageType::Kill:
                 if (bTerminatable)
                 {
                     GMX_LOG(mdlog.warning)
@@ -940,7 +954,7 @@ void ImdSession::Impl::readCommand()
                                     IMDstr);
                     bTerminated = true;
                     bWConnect   = false;
-                    gmx_set_stop_condition(gmx_stop_cond_next);
+                    gmx_set_stop_condition(StopCondition::Next);
                 }
                 else
                 {
@@ -954,19 +968,19 @@ void ImdSession::Impl::readCommand()
                 break;
 
             /* the client doen't want to talk to us anymore */
-            case IMD_DISCONNECT:
+            case IMDMessageType::Disconnect:
                 GMX_LOG(mdlog.warning).appendTextFormatted(" %s Disconnecting client.", IMDstr);
                 disconnectClient();
                 break;
 
             /* we got new forces, read them and set bNewForces flag */
-            case IMD_MDCOMM:
+            case IMDMessageType::Mdcomm:
                 readVmdForces();
                 bNewForces = true;
                 break;
 
             /* the client asks us to (un)pause the simulation. So we toggle the IMDpaused state */
-            case IMD_PAUSE:
+            case IMDMessageType::Pause:
                 if (IMDpaused)
                 {
                     GMX_LOG(mdlog.warning).appendTextFormatted(" %s Un-pause command received.", IMDstr);
@@ -982,7 +996,7 @@ void ImdSession::Impl::readCommand()
 
             /* the client sets a new transfer rate, if we get 0, we reset the rate
              * to the default. VMD filters 0 however */
-            case IMD_TRATE:
+            case IMDMessageType::TRate:
                 nstimd_new = (length > 0) ? length : defaultNstImd;
                 GMX_LOG(mdlog.warning)
                         .appendTextFormatted(" %s Update frequency will be set to %d.", IMDstr, nstimd_new);
@@ -991,8 +1005,8 @@ void ImdSession::Impl::readCommand()
             /* Catch all rule for the remaining IMD types which we don't expect */
             default:
                 GMX_LOG(mdlog.warning)
-                        .appendTextFormatted(" %s Received unexpected %s.", IMDstr,
-                                             enum_name(static_cast<int>(itype), IMD_NR, eIMDType_names));
+                        .appendTextFormatted(
+                                " %s Received unexpected %s.", IMDstr, enumValueToString(itype));
                 issueFatalError("Terminating connection");
                 break;
         } /* end switch */
@@ -1012,7 +1026,8 @@ void ImdSession::Impl::openOutputFile(const char*                 fn,
                 "%s For a log of the IMD pull forces explicitly specify '-if' on the command "
                 "line.\n"
                 "%s (Not possible with energy minimization.)\n",
-                IMDstr, IMDstr);
+                IMDstr,
+                IMDstr);
         return;
     }
 
@@ -1031,8 +1046,7 @@ void ImdSession::Impl::openOutputFile(const char*                 fn,
                     "the atoms suffices.\n");
         }
 
-        xvgr_header(outf, "IMD Pull Forces", "Time (ps)",
-                    "# of Forces / Atom IDs / Forces (kJ/mol)", exvggtNONE, oenv);
+        xvgr_header(outf, "IMD Pull Forces", "Time (ps)", "# of Forces / Atom IDs / Forces (kJ/mol)", exvggtNONE, oenv);
 
         fprintf(outf, "# Can display and manipulate %d (of a total of %d) atoms via IMD.\n", nat, nat_total);
         fprintf(outf, "# column 1    : time (ps)\n");
@@ -1073,7 +1087,7 @@ ImdSession::Impl::~Impl()
 }
 
 
-void ImdSession::Impl::prepareMoleculesInImdGroup(const gmx_mtop_t* top_global)
+void ImdSession::Impl::prepareMoleculesInImdGroup(const gmx_mtop_t& top_global)
 {
     /* check whether index is sorted */
     for (int i = 0; i < nat - 1; i++)
@@ -1084,7 +1098,7 @@ void ImdSession::Impl::prepareMoleculesInImdGroup(const gmx_mtop_t* top_global)
         }
     }
 
-    RangePartitioning gmols = gmx_mtop_molecules(*top_global);
+    RangePartitioning gmols = gmx_mtop_molecules(top_global);
     t_block           lmols;
     lmols.nr = 0;
     snew(lmols.index, gmols.numBlocks() + 1);
@@ -1151,7 +1165,7 @@ static void shift_positions(const matrix box,
 }
 
 
-void ImdSession::Impl::removeMolecularShifts(const matrix box)
+void ImdSession::Impl::removeMolecularShifts(const matrix box) const
 {
     /* for each molecule also present in IMD group */
     for (int i = 0; i < mols.nr; i++)
@@ -1235,7 +1249,7 @@ void ImdSession::Impl::removeMolecularShifts(const matrix box)
 }
 
 
-void ImdSession::Impl::prepareForPositionAssembly(const t_commrec* cr, const rvec x[])
+void ImdSession::Impl::prepareForPositionAssembly(const t_commrec* cr, gmx::ArrayRef<const gmx::RVec> coords)
 {
     snew(xa, nat);
     snew(xa_ind, nat);
@@ -1250,7 +1264,7 @@ void ImdSession::Impl::prepareForPositionAssembly(const t_commrec* cr, const rve
         for (int i = 0; i < nat; i++)
         {
             int ii = ind[i];
-            copy_rvec(x[ii], xa_old[i]);
+            copy_rvec(coords[ii], xa_old[i]);
         }
     }
 
@@ -1279,7 +1293,8 @@ static void imd_check_integrator_parallel(const t_inputrec* ir, const t_commrec*
 {
     if (PAR(cr))
     {
-        if (((ir->eI) == eiSteep) || ((ir->eI) == eiCG) || ((ir->eI) == eiLBFGS) || ((ir->eI) == eiNM))
+        if (((ir->eI) == IntegrationAlgorithm::Steep) || ((ir->eI) == IntegrationAlgorithm::CG)
+            || ((ir->eI) == IntegrationAlgorithm::LBFGS) || ((ir->eI) == IntegrationAlgorithm::NM))
         {
             gmx_fatal(FARGS,
                       "%s Energy minimization via steep, CG, lbfgs and nm in parallel is currently "
@@ -1289,22 +1304,22 @@ static void imd_check_integrator_parallel(const t_inputrec* ir, const t_commrec*
     }
 }
 
-std::unique_ptr<ImdSession> makeImdSession(const t_inputrec*           ir,
-                                           const t_commrec*            cr,
-                                           gmx_wallcycle*              wcycle,
-                                           gmx_enerdata_t*             enerd,
-                                           const gmx_multisim_t*       ms,
-                                           const gmx_mtop_t*           top_global,
-                                           const MDLogger&             mdlog,
-                                           const rvec                  x[],
-                                           int                         nfile,
-                                           const t_filenm              fnm[],
-                                           const gmx_output_env_t*     oenv,
-                                           const ImdOptions&           options,
-                                           const gmx::StartingBehavior startingBehavior)
+std::unique_ptr<ImdSession> makeImdSession(const t_inputrec*              ir,
+                                           const t_commrec*               cr,
+                                           gmx_wallcycle*                 wcycle,
+                                           gmx_enerdata_t*                enerd,
+                                           const gmx_multisim_t*          ms,
+                                           const gmx_mtop_t&              top_global,
+                                           const MDLogger&                mdlog,
+                                           gmx::ArrayRef<const gmx::RVec> coords,
+                                           int                            nfile,
+                                           const t_filenm                 fnm[],
+                                           const gmx_output_env_t*        oenv,
+                                           const ImdOptions&              options,
+                                           const gmx::StartingBehavior    startingBehavior)
 {
     std::unique_ptr<ImdSession> session(new ImdSession(mdlog));
-    auto                        impl = session->impl_.get();
+    auto*                       impl = session->impl_.get();
 
     /* We will allow IMD sessions only if supported by the binary and
        explicitly enabled in the .tpr file */
@@ -1335,7 +1350,8 @@ std::unique_ptr<ImdSession> makeImdSession(const t_inputrec*           ir,
                 .appendTextFormatted(
                         "%s Integrator '%s' is not supported for Interactive Molecular Dynamics, "
                         "running normally instead",
-                        IMDstr, ei_names[ir->eI]);
+                        IMDstr,
+                        enumValueToString(ir->eI));
         return session;
     }
     if (isMultiSim(ms))
@@ -1367,7 +1383,8 @@ std::unique_ptr<ImdSession> makeImdSession(const t_inputrec*           ir,
                     .appendTextFormatted(
                             "%s None of the -imd switches was used.\n"
                             "%s This run will not accept incoming IMD connections",
-                            IMDstr, IMDstr);
+                            IMDstr,
+                            IMDstr);
         }
     } /* end master only */
 
@@ -1394,7 +1411,7 @@ std::unique_ptr<ImdSession> makeImdSession(const t_inputrec*           ir,
      *****************************************************
      */
 
-    int nat_total = top_global->natoms;
+    int nat_total = top_global.natoms;
 
     /* Initialize IMD session. If we read in a pre-IMD .tpr file, ir->imd->nat
      * will be zero. For those cases we transfer _all_ atomic positions */
@@ -1495,7 +1512,7 @@ std::unique_ptr<ImdSession> makeImdSession(const t_inputrec*           ir,
     impl->syncNodes(cr, 0);
 
     /* Initialize arrays used to assemble the positions from the other nodes */
-    impl->prepareForPositionAssembly(cr, x);
+    impl->prepareForPositionAssembly(cr, coords);
 
     /* Initialize molecule blocks to make them whole later...*/
     if (MASTER(cr))
@@ -1507,7 +1524,7 @@ std::unique_ptr<ImdSession> makeImdSession(const t_inputrec*           ir,
 }
 
 
-bool ImdSession::Impl::run(int64_t step, bool bNS, const matrix box, const rvec x[], double t)
+bool ImdSession::Impl::run(int64_t step, bool bNS, const matrix box, gmx::ArrayRef<const gmx::RVec> coords, double t)
 {
     /* IMD at all? */
     if (!sessionPossible)
@@ -1515,7 +1532,7 @@ bool ImdSession::Impl::run(int64_t step, bool bNS, const matrix box, const rvec
         return false;
     }
 
-    wallcycle_start(wcycle, ewcIMD);
+    wallcycle_start(wcycle, WallCycleCounter::Imd);
 
     /* read command from client and check if new incoming connection */
     if (MASTER(cr))
@@ -1556,8 +1573,8 @@ bool ImdSession::Impl::run(int64_t step, bool bNS, const matrix box, const rvec
     {
         /* Transfer the IMD positions to the master node. Every node contributes
          * its local positions x and stores them in the assembled xa array. */
-        communicate_group_positions(cr, xa, xa_shifts, xa_eshifts, true, x, nat, nat_loc, ind_loc,
-                                    xa_ind, xa_old, box);
+        communicate_group_positions(
+                cr, xa, xa_shifts, xa_eshifts, true, as_rvec_array(coords.data()), nat, nat_loc, ind_loc, xa_ind, xa_old, box);
 
         /* If connected and master -> remove shifts */
         if ((imdstep && bConnected) && MASTER(cr))
@@ -1566,14 +1583,14 @@ bool ImdSession::Impl::run(int64_t step, bool bNS, const matrix box, const rvec
         }
     }
 
-    wallcycle_stop(wcycle, ewcIMD);
+    wallcycle_stop(wcycle, WallCycleCounter::Imd);
 
     return imdstep;
 }
 
-bool ImdSession::run(int64_t step, bool bNS, const matrix box, const rvec x[], double t)
+bool ImdSession::run(int64_t step, bool bNS, const matrix box, gmx::ArrayRef<const gmx::RVec> coords, double t)
 {
-    return impl_->run(step, bNS, box, x, t);
+    return impl_->run(step, bNS, box, coords, t);
 }
 
 void ImdSession::fillEnergyRecord(int64_t step, bool bHaveNewEnergies)
@@ -1631,7 +1648,7 @@ void ImdSession::updateEnergyRecordAndSendPositionsAndEnergies(bool bIMDstep, in
         return;
     }
 
-    wallcycle_start(impl_->wcycle, ewcIMD);
+    wallcycle_start(impl_->wcycle, WallCycleCounter::Imd);
 
     /* Update time step for IMD and prepare IMD energy record if we have new energies. */
     fillEnergyRecord(step, bHaveNewEnergies);
@@ -1642,17 +1659,17 @@ void ImdSession::updateEnergyRecordAndSendPositionsAndEnergies(bool bIMDstep, in
         sendPositionsAndEnergies();
     }
 
-    wallcycle_stop(impl_->wcycle, ewcIMD);
+    wallcycle_stop(impl_->wcycle, WallCycleCounter::Imd);
 }
 
-void ImdSession::applyForces(rvec* f)
+void ImdSession::applyForces(gmx::ArrayRef<gmx::RVec> force)
 {
     if (!impl_->sessionPossible || !impl_->bForceActivated)
     {
         return;
     }
 
-    wallcycle_start(impl_->wcycle, ewcIMD);
+    wallcycle_start(impl_->wcycle, WallCycleCounter::Imd);
 
     for (int i = 0; i < impl_->nforces; i++)
     {
@@ -1667,10 +1684,10 @@ void ImdSession::applyForces(rvec* f)
             j = *locndx;
         }
 
-        rvec_inc(f[j], impl_->f[i]);
+        rvec_inc(force[j], impl_->f[i]);
     }
 
-    wallcycle_stop(impl_->wcycle, ewcIMD);
+    wallcycle_stop(impl_->wcycle, WallCycleCounter::Imd);
 }
 
 ImdSession::ImdSession(const MDLogger& mdlog) : impl_(new Impl(mdlog)) {}
index 0ef075ae60bef98a04deb1a3b26415cbbcd0864d..1d5c4fa56d60bb5e62d3a1574bec68ecf6c113f3 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +67,6 @@
 #include <memory>
 
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/classhelpers.h"
 
 struct gmx_domdec_t;
 struct gmx_enerdata_t;
@@ -91,6 +89,8 @@ class InteractiveMolecularDynamics;
 class MDLogger;
 struct ImdOptions;
 struct MdrunOptions;
+template<typename>
+class ArrayRef;
 
 /*! \brief
  * Creates a module for interactive molecular dynamics.
@@ -115,7 +115,7 @@ static const char IMDstr[] = "IMD:"; /**< Tag output from the IMD module with th
 void write_IMDgroup_to_file(bool              bIMD,
                             t_inputrec*       ir,
                             const t_state*    state,
-                            const gmx_mtop_t* sys,
+                            const gmx_mtop_t& sys,
                             int               nfile,
                             const t_filenm    fnm[]);
 
@@ -131,26 +131,26 @@ void write_IMDgroup_to_file(bool              bIMD,
  * \param ms           Handler for multi-simulations.
  * \param top_global   The topology of the whole system.
  * \param mdlog        Logger
- * \param x            The starting positions of the atoms.
+ * \param coords       The starting positions of the atoms.
  * \param nfile        Number of files.
  * \param fnm          Struct containing file names etc.
  * \param oenv         Output options.
  * \param options      Options for interactive MD.
  * \param startingBehavior  Describes whether this is a restart appending to output files
  */
-std::unique_ptr<ImdSession> makeImdSession(const t_inputrec*       ir,
-                                           const t_commrec*        cr,
-                                           gmx_wallcycle*          wcycle,
-                                           gmx_enerdata_t*         enerd,
-                                           const gmx_multisim_t*   ms,
-                                           const gmx_mtop_t*       top_global,
-                                           const MDLogger&         mdlog,
-                                           const rvec              x[],
-                                           int                     nfile,
-                                           const t_filenm          fnm[],
-                                           const gmx_output_env_t* oenv,
-                                           const ImdOptions&       options,
-                                           StartingBehavior        startingBehavior);
+std::unique_ptr<ImdSession> makeImdSession(const t_inputrec*              ir,
+                                           const t_commrec*               cr,
+                                           gmx_wallcycle*                 wcycle,
+                                           gmx_enerdata_t*                enerd,
+                                           const gmx_multisim_t*          ms,
+                                           const gmx_mtop_t&              top_global,
+                                           const MDLogger&                mdlog,
+                                           gmx::ArrayRef<const gmx::RVec> coords,
+                                           int                            nfile,
+                                           const t_filenm                 fnm[],
+                                           const gmx_output_env_t*        oenv,
+                                           const ImdOptions&              options,
+                                           StartingBehavior               startingBehavior);
 
 class ImdSession
 {
@@ -180,18 +180,18 @@ public:
      * \param step         The time step.
      * \param bNS          Is this a neighbor searching step?
      * \param box          The simulation box.
-     * \param x            The local atomic positions on this node.
+     * \param coords       The local atomic positions on this node.
      * \param t            The time.
      *
      * \returns            Whether or not we have to do IMD communication at this step.
      */
-    bool run(int64_t step, bool bNS, const matrix box, const rvec x[], double t);
+    bool run(int64_t step, bool bNS, const matrix box, gmx::ArrayRef<const gmx::RVec> coords, double t);
 
     /*! \brief Add external forces from a running interactive molecular dynamics session.
      *
-     * \param f            The forces.
+     * \param force The forces.
      */
-    void applyForces(rvec* f);
+    void applyForces(gmx::ArrayRef<gmx::RVec> force);
 
     /*! \brief Copy energies and convert to float from enerdata to the IMD energy record.
      *
@@ -217,23 +217,23 @@ private:
     //! Implementation type.
     class Impl;
     //! Implementation object.
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
 public:
     // Befriend the factory function.
-    friend std::unique_ptr<ImdSession> makeImdSession(const t_inputrec*       ir,
-                                                      const t_commrec*        cr,
-                                                      gmx_wallcycle*          wcycle,
-                                                      gmx_enerdata_t*         enerd,
-                                                      const gmx_multisim_t*   ms,
-                                                      const gmx_mtop_t*       top_global,
-                                                      const MDLogger&         mdlog,
-                                                      const rvec              x[],
-                                                      int                     nfile,
-                                                      const t_filenm          fnm[],
-                                                      const gmx_output_env_t* oenv,
-                                                      const ImdOptions&       options,
-                                                      StartingBehavior        startingBehavior);
+    friend std::unique_ptr<ImdSession> makeImdSession(const t_inputrec*              ir,
+                                                      const t_commrec*               cr,
+                                                      gmx_wallcycle*                 wcycle,
+                                                      gmx_enerdata_t*                enerd,
+                                                      const gmx_multisim_t*          ms,
+                                                      const gmx_mtop_t&              top_global,
+                                                      const MDLogger&                mdlog,
+                                                      gmx::ArrayRef<const gmx::RVec> coords,
+                                                      int                            nfile,
+                                                      const t_filenm                 fnm[],
+                                                      const gmx_output_env_t*        oenv,
+                                                      const ImdOptions&              options,
+                                                      StartingBehavior startingBehavior);
 };
 
 } // namespace gmx
index 4c0ab0c09ca8794ec055ab1fc288bac34be96f64..f908f019822483f1d400889fb896862dd06f05c1 100644 (file)
@@ -47,6 +47,11 @@ set(LINEARALGEBRA_SOURCES
     ${LINEARALGEBRA_SOURCES} ${BLAS_SOURCES} ${LAPACK_SOURCES})
 
 add_library(linearalgebra OBJECT ${LINEARALGEBRA_SOURCES})
+# TODO: Only expose the module's public headers.
+target_include_directories(linearalgebra INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+target_include_directories(linearalgebra PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+
 gmx_target_compile_options(linearalgebra)
 target_compile_definitions(linearalgebra PRIVATE HAVE_CONFIG_H)
 # The linearalgebra code is all considered external, and we will
@@ -62,5 +67,9 @@ else()
     # not expect null termination of C strings.
     gmx_target_warning_suppression(linearalgebra -Wno-stringop-truncation HAS_NO_STRINGOP_TRUNCATION)
 endif()
+target_link_libraries(linearalgebra PRIVATE legacy_api)
+target_link_libraries(linearalgebra PRIVATE common)
+# TODO: Link specific modules.
+target_link_libraries(linearalgebra PRIVATE legacy_modules)
 list(APPEND libgromacs_object_library_dependencies linearalgebra)
 set(libgromacs_object_library_dependencies ${libgromacs_object_library_dependencies} PARENT_SCOPE)
index f0643b413bba54f1ea79ce05226b44987aaee720..e365d9b1d06afaca8d41e2bcd8c1ac1ed2c0ebaa 100644 (file)
@@ -91,12 +91,50 @@ void eigensolver(real* a, int n, int index_lower, int index_upper, real* eigenva
      */
 #if GMX_DOUBLE
     F77_FUNC(dsyevr, DSYEVR)
-    (jobz, "I", "L", &n, a, &n, &vl, &vu, &index_lower, &index_upper, &abstol, &m, eigenvalues,
-     eigenvectors, &n, isuppz, &w0, &lwork, &iw0, &liwork, &info);
+    (jobz,
+     "I",
+     "L",
+     &n,
+     a,
+     &n,
+     &vl,
+     &vu,
+     &index_lower,
+     &index_upper,
+     &abstol,
+     &m,
+     eigenvalues,
+     eigenvectors,
+     &n,
+     isuppz,
+     &w0,
+     &lwork,
+     &iw0,
+     &liwork,
+     &info);
 #else
     F77_FUNC(ssyevr, SSYEVR)
-    (jobz, "I", "L", &n, a, &n, &vl, &vu, &index_lower, &index_upper, &abstol, &m, eigenvalues,
-     eigenvectors, &n, isuppz, &w0, &lwork, &iw0, &liwork, &info);
+    (jobz,
+     "I",
+     "L",
+     &n,
+     a,
+     &n,
+     &vl,
+     &vu,
+     &index_lower,
+     &index_upper,
+     &abstol,
+     &m,
+     eigenvalues,
+     eigenvectors,
+     &n,
+     isuppz,
+     &w0,
+     &lwork,
+     &iw0,
+     &liwork,
+     &info);
 #endif
 
     if (info != 0)
@@ -115,12 +153,50 @@ void eigensolver(real* a, int n, int index_lower, int index_upper, real* eigenva
 
 #if GMX_DOUBLE
     F77_FUNC(dsyevr, DSYEVR)
-    (jobz, "I", "L", &n, a, &n, &vl, &vu, &index_lower, &index_upper, &abstol, &m, eigenvalues,
-     eigenvectors, &n, isuppz, work, &lwork, iwork, &liwork, &info);
+    (jobz,
+     "I",
+     "L",
+     &n,
+     a,
+     &n,
+     &vl,
+     &vu,
+     &index_lower,
+     &index_upper,
+     &abstol,
+     &m,
+     eigenvalues,
+     eigenvectors,
+     &n,
+     isuppz,
+     work,
+     &lwork,
+     iwork,
+     &liwork,
+     &info);
 #else
     F77_FUNC(ssyevr, SSYEVR)
-    (jobz, "I", "L", &n, a, &n, &vl, &vu, &index_lower, &index_upper, &abstol, &m, eigenvalues,
-     eigenvectors, &n, isuppz, work, &lwork, iwork, &liwork, &info);
+    (jobz,
+     "I",
+     "L",
+     &n,
+     a,
+     &n,
+     &vl,
+     &vu,
+     &index_lower,
+     &index_upper,
+     &abstol,
+     &m,
+     eigenvalues,
+     eigenvectors,
+     &n,
+     isuppz,
+     work,
+     &lwork,
+     iwork,
+     &liwork,
+     &info);
 #endif
 
     sfree(isuppz);
@@ -198,12 +274,10 @@ void sparse_parallel_eigensolver(gmx_sparsematrix_t* A, int neig, real* eigenval
     {
 #    if GMX_DOUBLE
         F77_FUNC(pdsaupd, PDSAUPD)
-        (&ido, "I", &n, "SA", &neig, &abstol, resid, &ncv, v, &n, iparam, ipntr, workd, iwork,
-         workl, &lworkl, &info);
+        (&ido, "I", &n, "SA", &neig, &abstol, resid, &ncv, v, &n, iparam, ipntr, workd, iwork, workl, &lworkl, &info);
 #    else
         F77_FUNC(pssaupd, PSSAUPD)
-        (&ido, "I", &n, "SA", &neig, &abstol, resid, &ncv, v, &n, iparam, ipntr, workd, iwork,
-         workl, &lworkl, &info);
+        (&ido, "I", &n, "SA", &neig, &abstol, resid, &ncv, v, &n, iparam, ipntr, workd, iwork, workl, &lworkl, &info);
 #    endif
         if (ido == -1 || ido == 1)
         {
@@ -220,7 +294,9 @@ void sparse_parallel_eigensolver(gmx_sparsematrix_t* A, int neig, real* eigenval
         gmx_fatal(FARGS,
                   "Maximum number of iterations (%d) reached in Arnoldi\n"
                   "diagonalization, but only %d of %d eigenvectors converged.\n",
-                  maxiter, iparam[4], neig);
+                  maxiter,
+                  iparam[4],
+                  neig);
     }
     else if (info != 0)
     {
@@ -233,12 +309,52 @@ void sparse_parallel_eigensolver(gmx_sparsematrix_t* A, int neig, real* eigenval
 
 #    if GMX_DOUBLE
     F77_FUNC(pdseupd, PDSEUPD)
-    (&dovec, "A", select, eigenvalues, eigenvectors, &n, NULL, "I", &n, "SA", &neig, &abstol, resid,
-     &ncv, v, &n, iparam, ipntr, workd, workl, &lworkl, &info);
+    (&dovec,
+     "A",
+     select,
+     eigenvalues,
+     eigenvectors,
+     &n,
+     NULL,
+     "I",
+     &n,
+     "SA",
+     &neig,
+     &abstol,
+     resid,
+     &ncv,
+     v,
+     &n,
+     iparam,
+     ipntr,
+     workd,
+     workl,
+     &lworkl,
+     &info);
 #    else
     F77_FUNC(psseupd, PSSEUPD)
-    (&dovec, "A", select, eigenvalues, eigenvectors, &n, NULL, "I", &n, "SA", &neig, &abstol, resid,
-     &ncv, v, &n, iparam, ipntr, workd, workl, &lworkl, &info);
+    (&dovec,
+     "A",
+     select,
+     eigenvalues,
+     eigenvectors,
+     &n,
+     NULL,
+     "I",
+     &n,
+     "SA",
+     &neig,
+     &abstol,
+     resid,
+     &ncv,
+     v,
+     &n,
+     iparam,
+     ipntr,
+     workd,
+     workl,
+     &lworkl,
+     &info);
 #    endif
 
     sfree(v);
@@ -318,12 +434,10 @@ void sparse_eigensolver(gmx_sparsematrix_t* A, int neig, real* eigenvalues, real
     {
 #if GMX_DOUBLE
         F77_FUNC(dsaupd, DSAUPD)
-        (&ido, "I", &n, "SA", &neig, &abstol, resid, &ncv, v, &n, iparam, ipntr, workd, iwork,
-         workl, &lworkl, &info);
+        (&ido, "I", &n, "SA", &neig, &abstol, resid, &ncv, v, &n, iparam, ipntr, workd, iwork, workl, &lworkl, &info);
 #else
         F77_FUNC(ssaupd, SSAUPD)
-        (&ido, "I", &n, "SA", &neig, &abstol, resid, &ncv, v, &n, iparam, ipntr, workd, iwork,
-         workl, &lworkl, &info);
+        (&ido, "I", &n, "SA", &neig, &abstol, resid, &ncv, v, &n, iparam, ipntr, workd, iwork, workl, &lworkl, &info);
 #endif
         if (ido == -1 || ido == 1)
         {
@@ -340,7 +454,9 @@ void sparse_eigensolver(gmx_sparsematrix_t* A, int neig, real* eigenvalues, real
         gmx_fatal(FARGS,
                   "Maximum number of iterations (%d) reached in Arnoldi\n"
                   "diagonalization, but only %d of %d eigenvectors converged.\n",
-                  maxiter, iparam[4], neig);
+                  maxiter,
+                  iparam[4],
+                  neig);
     }
     else if (info != 0)
     {
@@ -353,12 +469,52 @@ void sparse_eigensolver(gmx_sparsematrix_t* A, int neig, real* eigenvalues, real
 
 #if GMX_DOUBLE
     F77_FUNC(dseupd, DSEUPD)
-    (&dovec, "A", select, eigenvalues, eigenvectors, &n, nullptr, "I", &n, "SA", &neig, &abstol,
-     resid, &ncv, v, &n, iparam, ipntr, workd, workl, &lworkl, &info);
+    (&dovec,
+     "A",
+     select,
+     eigenvalues,
+     eigenvectors,
+     &n,
+     nullptr,
+     "I",
+     &n,
+     "SA",
+     &neig,
+     &abstol,
+     resid,
+     &ncv,
+     v,
+     &n,
+     iparam,
+     ipntr,
+     workd,
+     workl,
+     &lworkl,
+     &info);
 #else
     F77_FUNC(sseupd, SSEUPD)
-    (&dovec, "A", select, eigenvalues, eigenvectors, &n, nullptr, "I", &n, "SA", &neig, &abstol,
-     resid, &ncv, v, &n, iparam, ipntr, workd, workl, &lworkl, &info);
+    (&dovec,
+     "A",
+     select,
+     eigenvalues,
+     eigenvectors,
+     &n,
+     nullptr,
+     "I",
+     &n,
+     "SA",
+     &neig,
+     &abstol,
+     resid,
+     &ncv,
+     v,
+     &n,
+     iparam,
+     ipntr,
+     workd,
+     workl,
+     &lworkl,
+     &info);
 #endif
 
     sfree(v);
index 4ee3114cb0b6db93eebef727a6a0c2f984dc88de..8009a46988683ff04649aec284ecef9dd35040b3 100644 (file)
@@ -841,8 +841,7 @@ static void F77_FUNC(dsapps, DSAPPS)(int*    n,
     if (h__[*kev + 1 + h_dim1] > 0.)
     {
         F77_FUNC(dgemv, DGEMV)
-        ("N", n, &kplusp, &c_b5, &v[v_offset], ldv, &q[(*kev + 1) * q_dim1 + 1], &c__1, &c_b4,
-         &workd[*n + 1], &c__1);
+        ("N", n, &kplusp, &c_b5, &v[v_offset], ldv, &q[(*kev + 1) * q_dim1 + 1], &c__1, &c_b4, &workd[*n + 1], &c__1);
     }
 
     i__1 = *kev;
@@ -850,8 +849,7 @@ static void F77_FUNC(dsapps, DSAPPS)(int*    n,
     {
         i__2 = kplusp - i__ + 1;
         F77_FUNC(dgemv, DGEMV)
-        ("N", n, &i__2, &c_b5, &v[v_offset], ldv, &q[(*kev - i__ + 1) * q_dim1 + 1], &c__1, &c_b4,
-         &workd[1], &c__1);
+        ("N", n, &i__2, &c_b5, &v[v_offset], ldv, &q[(*kev - i__ + 1) * q_dim1 + 1], &c__1, &c_b4, &workd[1], &c__1);
         F77_FUNC(dcopy, DCOPY)(n, &workd[1], &c__1, &v[(kplusp - i__ + 1) * v_dim1 + 1], &c__1);
     }
 
@@ -1461,8 +1459,20 @@ L20:
 L30:
 
     F77_FUNC(dgetv0, DGETV0)
-    (ido, bmat, &iwork[11], &c__0, n, &iwork[12], &v[v_offset], ldv, &resid[1], rnorm, &ipntr[1],
-     &workd[1], &iwork[21], &iwork[7]);
+    (ido,
+     bmat,
+     &iwork[11],
+     &c__0,
+     n,
+     &iwork[12],
+     &v[v_offset],
+     ldv,
+     &resid[1],
+     rnorm,
+     &ipntr[1],
+     &workd[1],
+     &iwork[21],
+     &iwork[7]);
     if (*ido != 99)
     {
         goto L9000;
@@ -1554,14 +1564,12 @@ L65:
     if (*mode != 2)
     {
         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);
+        ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[8]], &c__1, &c_b42, &workd[iwork[9]], &c__1);
     }
     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);
+        ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[10]], &c__1, &c_b42, &workd[iwork[9]], &c__1);
     }
 
     F77_FUNC(dgemv, DGEMV)
@@ -1615,8 +1623,7 @@ L70:
 L80:
 
     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);
+    ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[8]], &c__1, &c_b42, &workd[iwork[9]], &c__1);
 
     F77_FUNC(dgemv, DGEMV)
     ("N", n, &iwork[12], &c_b50, &v[v_offset], ldv, &workd[iwork[9]], &c__1, &c_b18, &resid[1], &c__1);
@@ -1808,8 +1815,20 @@ static void F77_FUNC(dsaup2, DSAUP2)(int*        ido,
     if (iwork[2] == 1)
     {
         F77_FUNC(dgetv0, DGETV0)
-        (ido, bmat, &c__1, &iwork[3], n, &c__1, &v[v_offset], ldv, &resid[1], &workd[*n * 3 + 1],
-         &ipntr[1], &workd[1], &iwork[41], info);
+        (ido,
+         bmat,
+         &c__1,
+         &iwork[3],
+         n,
+         &c__1,
+         &v[v_offset],
+         ldv,
+         &resid[1],
+         &workd[*n * 3 + 1],
+         &ipntr[1],
+         &workd[1],
+         &iwork[41],
+         info);
 
         if (*ido != 99)
         {
@@ -1842,8 +1861,22 @@ static void F77_FUNC(dsaup2, DSAUP2)(int*        ido,
     }
 
     F77_FUNC(dsaitr, DSAITR)
-    (ido, bmat, n, &c__0, &iwork[9], mode, &resid[1], &workd[*n * 3 + 1], &v[v_offset], ldv,
-     &h__[h_offset], ldh, &ipntr[1], &workd[1], &iwork[21], info);
+    (ido,
+     bmat,
+     n,
+     &c__0,
+     &iwork[9],
+     mode,
+     &resid[1],
+     &workd[*n * 3 + 1],
+     &v[v_offset],
+     ldv,
+     &h__[h_offset],
+     ldh,
+     &ipntr[1],
+     &workd[1],
+     &iwork[21],
+     info);
 
     if (*ido != 99)
     {
@@ -1869,8 +1902,22 @@ L20:
     iwork[4] = 1;
 
     F77_FUNC(dsaitr, DSAITR)
-    (ido, bmat, n, nev, np, mode, &resid[1], &workd[*n * 3 + 1], &v[v_offset], ldv, &h__[h_offset],
-     ldh, &ipntr[1], &workd[1], &iwork[21], info);
+    (ido,
+     bmat,
+     n,
+     nev,
+     np,
+     mode,
+     &resid[1],
+     &workd[*n * 3 + 1],
+     &v[v_offset],
+     ldv,
+     &h__[h_offset],
+     ldh,
+     &ipntr[1],
+     &workd[1],
+     &iwork[21],
+     info);
 
     if (*ido != 99)
     {
@@ -2050,8 +2097,7 @@ L50:
     }
 
     F77_FUNC(dsapps, DSAPPS)
-    (n, nev, np, &ritz[1], &v[v_offset], ldv, &h__[h_offset], ldh, &resid[1], &q[q_offset], ldq,
-     &workd[1]);
+    (n, nev, np, &ritz[1], &v[v_offset], ldv, &h__[h_offset], ldh, &resid[1], &q[q_offset], ldq, &workd[1]);
 
     iwork[1] = 1;
     if (*bmat == 'G')
@@ -2235,9 +2281,31 @@ void F77_FUNC(dsaupd, DSAUPD)(int*        ido,
     }
 
     F77_FUNC(dsaup2, DSAUP2)
-    (ido, bmat, n, which, &iwork[13], &iwork[15], tol, &resid[1], &iwork[11], &iwork[6], &iwork[5],
-     &iwork[10], &v[v_offset], ldv, &workl[iwork[3]], &iwork[8], &workl[iwork[16]], &workl[iwork[1]],
-     &workl[iwork[4]], &iwork[9], &workl[iwork[7]], &ipntr[1], &workd[1], &iwork[21], info);
+    (ido,
+     bmat,
+     n,
+     which,
+     &iwork[13],
+     &iwork[15],
+     tol,
+     &resid[1],
+     &iwork[11],
+     &iwork[6],
+     &iwork[5],
+     &iwork[10],
+     &v[v_offset],
+     ldv,
+     &workl[iwork[3]],
+     &iwork[8],
+     &workl[iwork[16]],
+     &workl[iwork[1]],
+     &workl[iwork[4]],
+     &iwork[9],
+     &workl[iwork[7]],
+     &ipntr[1],
+     &workd[1],
+     &iwork[21],
+     info);
 
     if (*ido == 3)
     {
@@ -2673,8 +2741,18 @@ void F77_FUNC(dseupd, DSEUPD)(int*        rvec,
         (ncv, &nconv, &workl[iq], &ldq, &workl[iw + *ncv], &workl[ihb], &ierr);
 
         F77_FUNC(dorm2r, DORM2R)
-        ("Right", "Notranspose", n, ncv, &nconv, &workl[iq], &ldq, &workl[iw + *ncv], &v[v_offset],
-         ldv, &workd[*n + 1], &ierr);
+        ("Right",
+         "Notranspose",
+         n,
+         ncv,
+         &nconv,
+         &workl[iq],
+         &ldq,
+         &workl[iw + *ncv],
+         &v[v_offset],
+         ldv,
+         &workd[*n + 1],
+         &ierr);
         F77_FUNC(dlacpy, DLACPY)("All", n, &nconv, &v[v_offset], ldv, &z__[z_offset], ldz);
 
         i__1 = *ncv - 1;
@@ -2684,8 +2762,7 @@ void F77_FUNC(dseupd, DSEUPD)(int*        rvec,
         }
         workl[ihb + *ncv - 1] = 1.;
         F77_FUNC(dorm2r, DORM2R)
-        ("Left", "Transpose", ncv, &c__1, &nconv, &workl[iq], &ldq, &workl[iw + *ncv], &workl[ihb],
-         ncv, &temp, &ierr);
+        ("Left", "Transpose", ncv, &c__1, &nconv, &workl[iq], &ldq, &workl[iw + *ncv], &workl[ihb], ncv, &temp, &ierr);
     }
     else if (*rvec && *howmny == 'S')
     {
@@ -3562,8 +3639,7 @@ static void F77_FUNC(ssapps, SSAPPS)(int*   n,
     if (h__[*kev + 1 + h_dim1] > 0.)
     {
         F77_FUNC(sgemv, SGEMV)
-        ("N", n, &kplusp, &c_b5, &v[v_offset], ldv, &q[(*kev + 1) * q_dim1 + 1], &c__1, &c_b4,
-         &workd[*n + 1], &c__1);
+        ("N", n, &kplusp, &c_b5, &v[v_offset], ldv, &q[(*kev + 1) * q_dim1 + 1], &c__1, &c_b4, &workd[*n + 1], &c__1);
     }
 
     i__1 = *kev;
@@ -3571,8 +3647,7 @@ static void F77_FUNC(ssapps, SSAPPS)(int*   n,
     {
         i__2 = kplusp - i__ + 1;
         F77_FUNC(sgemv, SGEMV)
-        ("N", n, &i__2, &c_b5, &v[v_offset], ldv, &q[(*kev - i__ + 1) * q_dim1 + 1], &c__1, &c_b4,
-         &workd[1], &c__1);
+        ("N", n, &i__2, &c_b5, &v[v_offset], ldv, &q[(*kev - i__ + 1) * q_dim1 + 1], &c__1, &c_b4, &workd[1], &c__1);
         F77_FUNC(scopy, SCOPY)(n, &workd[1], &c__1, &v[(kplusp - i__ + 1) * v_dim1 + 1], &c__1);
     }
 
@@ -4177,8 +4252,20 @@ L20:
 L30:
 
     F77_FUNC(sgetv0, sgetv0)
-    (ido, bmat, &iwork[11], &c__0, n, &iwork[12], &v[v_offset], ldv, &resid[1], rnorm, &ipntr[1],
-     &workd[1], &iwork[21], &iwork[7]);
+    (ido,
+     bmat,
+     &iwork[11],
+     &c__0,
+     n,
+     &iwork[12],
+     &v[v_offset],
+     ldv,
+     &resid[1],
+     rnorm,
+     &ipntr[1],
+     &workd[1],
+     &iwork[21],
+     &iwork[7]);
     if (*ido != 99)
     {
         goto L9000;
@@ -4270,14 +4357,12 @@ L65:
     if (*mode != 2)
     {
         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);
+        ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[8]], &c__1, &c_b42, &workd[iwork[9]], &c__1);
     }
     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);
+        ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[10]], &c__1, &c_b42, &workd[iwork[9]], &c__1);
     }
 
     F77_FUNC(sgemv, SGEMV)
@@ -4331,8 +4416,7 @@ L70:
 L80:
 
     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);
+    ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[8]], &c__1, &c_b42, &workd[iwork[9]], &c__1);
 
     F77_FUNC(sgemv, SGEMV)
     ("N", n, &iwork[12], &c_b50, &v[v_offset], ldv, &workd[iwork[9]], &c__1, &c_b18, &resid[1], &c__1);
@@ -4524,8 +4608,20 @@ static void F77_FUNC(ssaup2, SSAUP2)(int*        ido,
     if (iwork[2] == 1)
     {
         F77_FUNC(sgetv0, SGETV0)
-        (ido, bmat, &c__1, &iwork[3], n, &c__1, &v[v_offset], ldv, &resid[1], &workd[*n * 3 + 1],
-         &ipntr[1], &workd[1], &iwork[41], info);
+        (ido,
+         bmat,
+         &c__1,
+         &iwork[3],
+         n,
+         &c__1,
+         &v[v_offset],
+         ldv,
+         &resid[1],
+         &workd[*n * 3 + 1],
+         &ipntr[1],
+         &workd[1],
+         &iwork[41],
+         info);
 
         if (*ido != 99)
         {
@@ -4558,8 +4654,22 @@ static void F77_FUNC(ssaup2, SSAUP2)(int*        ido,
     }
 
     F77_FUNC(ssaitr, SSAITR)
-    (ido, bmat, n, &c__0, &iwork[9], mode, &resid[1], &workd[*n * 3 + 1], &v[v_offset], ldv,
-     &h__[h_offset], ldh, &ipntr[1], &workd[1], &iwork[21], info);
+    (ido,
+     bmat,
+     n,
+     &c__0,
+     &iwork[9],
+     mode,
+     &resid[1],
+     &workd[*n * 3 + 1],
+     &v[v_offset],
+     ldv,
+     &h__[h_offset],
+     ldh,
+     &ipntr[1],
+     &workd[1],
+     &iwork[21],
+     info);
 
     if (*ido != 99)
     {
@@ -4585,8 +4695,22 @@ L20:
     iwork[4] = 1;
 
     F77_FUNC(ssaitr, SSAITR)
-    (ido, bmat, n, nev, np, mode, &resid[1], &workd[*n * 3 + 1], &v[v_offset], ldv, &h__[h_offset],
-     ldh, &ipntr[1], &workd[1], &iwork[21], info);
+    (ido,
+     bmat,
+     n,
+     nev,
+     np,
+     mode,
+     &resid[1],
+     &workd[*n * 3 + 1],
+     &v[v_offset],
+     ldv,
+     &h__[h_offset],
+     ldh,
+     &ipntr[1],
+     &workd[1],
+     &iwork[21],
+     info);
 
     if (*ido != 99)
     {
@@ -4767,8 +4891,7 @@ L50:
     }
 
     F77_FUNC(ssapps, SSAPPS)
-    (n, nev, np, &ritz[1], &v[v_offset], ldv, &h__[h_offset], ldh, &resid[1], &q[q_offset], ldq,
-     &workd[1]);
+    (n, nev, np, &ritz[1], &v[v_offset], ldv, &h__[h_offset], ldh, &resid[1], &q[q_offset], ldq, &workd[1]);
 
     iwork[1] = 1;
     if (*bmat == 'G')
@@ -4952,9 +5075,31 @@ void F77_FUNC(ssaupd, SSAUPD)(int*        ido,
     }
 
     F77_FUNC(ssaup2, SSAUP2)
-    (ido, bmat, n, which, &iwork[13], &iwork[15], tol, &resid[1], &iwork[11], &iwork[6], &iwork[5],
-     &iwork[10], &v[v_offset], ldv, &workl[iwork[3]], &iwork[8], &workl[iwork[16]], &workl[iwork[1]],
-     &workl[iwork[4]], &iwork[9], &workl[iwork[7]], &ipntr[1], &workd[1], &iwork[21], info);
+    (ido,
+     bmat,
+     n,
+     which,
+     &iwork[13],
+     &iwork[15],
+     tol,
+     &resid[1],
+     &iwork[11],
+     &iwork[6],
+     &iwork[5],
+     &iwork[10],
+     &v[v_offset],
+     ldv,
+     &workl[iwork[3]],
+     &iwork[8],
+     &workl[iwork[16]],
+     &workl[iwork[1]],
+     &workl[iwork[4]],
+     &iwork[9],
+     &workl[iwork[7]],
+     &ipntr[1],
+     &workd[1],
+     &iwork[21],
+     info);
 
     if (*ido == 3)
     {
@@ -5390,8 +5535,18 @@ void F77_FUNC(sseupd, SSEUPD)(int*        rvec,
         (ncv, &nconv, &workl[iq], &ldq, &workl[iw + *ncv], &workl[ihb], &ierr);
 
         F77_FUNC(sorm2r, SORM2R)
-        ("Right", "Notranspose", n, ncv, &nconv, &workl[iq], &ldq, &workl[iw + *ncv], &v[v_offset],
-         ldv, &workd[*n + 1], &ierr);
+        ("Right",
+         "Notranspose",
+         n,
+         ncv,
+         &nconv,
+         &workl[iq],
+         &ldq,
+         &workl[iw + *ncv],
+         &v[v_offset],
+         ldv,
+         &workd[*n + 1],
+         &ierr);
         F77_FUNC(slacpy, SLACPY)("All", n, &nconv, &v[v_offset], ldv, &z__[z_offset], ldz);
 
         i__1 = *ncv - 1;
@@ -5401,8 +5556,7 @@ void F77_FUNC(sseupd, SSEUPD)(int*        rvec,
         }
         workl[ihb + *ncv - 1] = 1.;
         F77_FUNC(sorm2r, SORM2R)
-        ("Left", "Transpose", ncv, &c__1, &nconv, &workl[iq], &ldq, &workl[iw + *ncv], &workl[ihb],
-         ncv, &temp, &ierr);
+        ("Left", "Transpose", ncv, &c__1, &nconv, &workl[iq], &ldq, &workl[iw + *ncv], &workl[ihb], ncv, &temp, &ierr);
     }
     else if (*rvec && *howmny == 'S')
     {
index f5cbc5880055a043f8d585c3bbdee56622b703c9..e75c442974902c01a0fcedc52f687d73d26c0f74 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cmath>
 
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
 
-static inline void do_rotate(double** a, int i, int j, int k, int l, double tau, double s)
+template<typename MatrixType>
+static inline void do_rotate(MatrixType a, int i, int j, int k, int l, double tau, double s)
 {
     double g, h;
     g       = a[i][j];
@@ -54,7 +56,8 @@ static inline void do_rotate(double** a, int i, int j, int k, int l, double tau,
     a[k][l] = h + s * (g - h * tau);
 }
 
-void jacobi(double** a, int n, double d[], double** v, int* nrot)
+template<typename MatrixType>
+static int jacobi(MatrixType a, const int n, double d[], MatrixType v)
 {
     int    j, i;
     int    iq, ip;
@@ -75,7 +78,7 @@ void jacobi(double** a, int n, double d[], double** v, int* nrot)
         b[ip] = d[ip] = a[ip][ip];
         z[ip]         = 0.0;
     }
-    *nrot = 0;
+    int nrot = 0;
     for (i = 1; i <= 50; i++)
     {
         sm = 0.0;
@@ -90,7 +93,7 @@ void jacobi(double** a, int n, double d[], double** v, int* nrot)
         {
             sfree(z);
             sfree(b);
-            return;
+            return nrot;
         }
         if (i < 4)
         {
@@ -151,7 +154,7 @@ void jacobi(double** a, int n, double d[], double** v, int* nrot)
                     {
                         do_rotate(v, j, ip, j, iq, tau, s);
                     }
-                    ++(*nrot);
+                    ++nrot;
                 }
             }
         }
@@ -163,6 +166,27 @@ void jacobi(double** a, int n, double d[], double** v, int* nrot)
         }
     }
     gmx_fatal(FARGS, "Error: Too many iterations in routine JACOBI\n");
+
+    return nrot;
+}
+
+void jacobi(double** a, const int numDimensions, double* eigenvalues, double** eigenvectors, int* numRotations)
+{
+    int numRot = jacobi(a, numDimensions, eigenvalues, eigenvectors);
+
+    if (numRotations)
+    {
+        *numRotations = numRot;
+    }
+}
+
+int jacobi(gmx::ArrayRef<gmx::DVec> a, gmx::ArrayRef<double> eigenvalues, gmx::ArrayRef<gmx::DVec> eigenvectors)
+{
+    GMX_RELEASE_ASSERT(gmx::ssize(a) == DIM, "Size should be 3");
+    GMX_RELEASE_ASSERT(gmx::ssize(eigenvalues) == DIM, "Size should be 3");
+    GMX_RELEASE_ASSERT(gmx::ssize(eigenvectors) == DIM, "Size should be 3");
+
+    return jacobi(a, DIM, eigenvalues.data(), eigenvectors);
 }
 
 int m_inv_gen(real* m, int n, real* minv)
index 460c383fc2227957b1c0be024c5e2c08536a2999..82bbb51b12941fefc37f770dbc858961f6bcc737 100644 (file)
@@ -3,7 +3,8 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2010,2014,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2017,2018,2019 by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_LINEARALGEBRA_NRJAC_H
 #define GMX_LINEARALGEBRA_NRJAC_H
 
+#include "gromacs/math/vectypes.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/real.h"
 
-void jacobi(double** a, int n, double d[], double** v, int* nrot);
-/*
- * real   **omega = input matrix a[0..n-1][0..n-1] must be symmetric
- * int     natoms = number of rows and columns
- * real      NULL = d[0]..d[n-1] are the eigenvalues of a[][]
- * real       **v = v[0..n-1][0..n-1] the eigenvectors:
- *                                    v[i][j] is component i of vector j
- * int      *irot = number of jacobi rotations
+/* Diagonalizes a symmetric matrix
+ *
+ * \param[in,out] a           Input matrix a[0..n-1][0..n-1] must be symmetric, gets modified
+ * \param[in]  numDimensions  Number of rows and columns
+ * \param[out] eigenvalues    eigenvalues[0]..eigenvalues[n-1] are the eigenvalues of a
+ * \param[out] eigenvectors   v[0..n-1][0..n-1] the eigenvectors: v[i][j] is component i of vector j
+ * \param[out] numRotations   The number of jacobi rotations, can be nullptr
+ */
+void jacobi(double** a, int numDimensions, double* eigenvalues, double** eigenvectors, int* numRotations);
+
+/* Like jacobi above, but specialized for n=3
+ *
+ * \param[in,out] a  The symmetric matrix to diagonalize, size 3, note that the contents gets modified
+ * \param[out] eigenvalues  The eigenvalues, size 3
+ * \param[out] eigenvectors The eigenvectors, size 3
+
+ * Returns the number of jacobi rotations.
  */
+int jacobi(gmx::ArrayRef<gmx::DVec> a, gmx::ArrayRef<double> eigenvalues, gmx::ArrayRef<gmx::DVec> eigenvectors);
 
 int m_inv_gen(real* m, int n, real* minv);
 /* Produces minv, a generalized inverse of m, both stored as linear arrays.
index fa1fa07902081be0d7027030b1aa0903dd2a58a2..c1de86e14b582b06edfbd3ef6ebb55cf97610291 100644 (file)
@@ -32,6 +32,7 @@
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
+add_library(listed_forces INTERFACE)
 gmx_add_libgromacs_sources(
     bonded.cpp
     disre.cpp
@@ -52,6 +53,37 @@ if(GMX_GPU_CUDA)
        )
 endif()
 
+# Source files have the following private module dependencies.
+target_link_libraries(listed_forces PRIVATE
+#                      gmxlib
+#                      math
+#                      mdtypes
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(listed_forces PUBLIC
+target_include_directories(listed_forces INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(listed_forces PUBLIC
+target_link_libraries(listed_forces INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when listed_forces is an OBJECT target
+#target_link_libraries(listed_forces PUBLIC legacy_api)
+#target_link_libraries(listed_forces PRIVATE common)
+
+# Module dependencies
+# listed_forces interfaces convey transitive dependence on these modules.
+#target_link_libraries(listed_forces PUBLIC
+target_link_libraries(listed_forces INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(listed_forces PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(listed_forces PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
      add_subdirectory(tests)
 endif()
index 4daf42387421e4ebd7167e3c4b6f9cdabdfb2d96..87c06ee74f65b3dc3ec386a196050190f115bc52 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #include "gromacs/simd/simd.h"
 #include "gromacs/simd/simd_math.h"
 #include "gromacs/simd/vector_operations.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 using namespace gmx; // TODO: Remove when this file is moved into gmx namespace
 
 const EnumerationArray<BondedKernelFlavor, std::string> c_bondedKernelFlavorStrings = {
-    "forces, using SIMD when available", "forces, not using SIMD",
-    "forces, virial, and energy (ie. not using SIMD)", "forces and energy (ie. not using SIMD)"
+    "forces, using SIMD when available",
+    "forces, not using SIMD",
+    "forces, virial, and energy (ie. not using SIMD)",
+    "forces and energy (ie. not using SIMD)"
 };
 namespace
 {
 
 //! Type of CPU function to compute a bonded interaction.
-using BondedFunction = real (*)(int              nbonds,
-                                const t_iatom    iatoms[],
-                                const t_iparams  iparams[],
-                                const rvec       x[],
-                                rvec4            f[],
-                                rvec             fshift[],
-                                const t_pbc*     pbc,
-                                real             lambda,
-                                real*            dvdlambda,
-                                const t_mdatoms* md,
-                                t_fcdata*        fcd,
-                                int*             ddgatindex);
+using BondedFunction = real (*)(int                       nbonds,
+                                const t_iatom             iatoms[],
+                                const t_iparams           iparams[],
+                                const rvec                x[],
+                                rvec4                     f[],
+                                rvec                      fshift[],
+                                const t_pbc*              pbc,
+                                real                      lambda,
+                                real*                     dvdlambda,
+                                gmx::ArrayRef<const real> charge,
+                                t_fcdata*                 fcd,
+                                t_disresdata*             disresdata,
+                                t_oriresdata*             oriresdata,
+                                int*                      ddgatindex);
 
 /*! \brief Mysterious CMAP coefficient matrix */
 const int cmap_coeff_matrix[] = {
@@ -130,7 +135,7 @@ int pbc_rvec_sub(const t_pbc* pbc, const rvec xi, const rvec xj, rvec dx)
     else
     {
         rvec_sub(xi, xj, dx);
-        return CENTRAL;
+        return c_centralShiftIndex;
     }
 }
 
@@ -226,7 +231,7 @@ inline void spreadBondForces(const real bondForce,
         if (computeVirial(flavor))
         {
             fshift[shiftIndex][m] += fij;
-            fshift[CENTRAL][m] -= fij;
+            fshift[c_centralShiftIndex][m] -= fij;
         }
     }
 }
@@ -252,8 +257,10 @@ real morse_bonds(int             nbonds,
                  const t_pbc*    pbc,
                  real            lambda,
                  real*           dvdlambda,
-                 const t_mdatoms gmx_unused* md,
+                 gmx::ArrayRef<const real> /*charge*/,
                  t_fcdata gmx_unused* fcd,
+                 t_disresdata gmx_unused* disresdata,
+                 t_oriresdata gmx_unused* oriresdata,
                  int gmx_unused* global_atom_index)
 {
     const real one = 1.0;
@@ -320,8 +327,10 @@ real cubic_bonds(int             nbonds,
                  const t_pbc*    pbc,
                  real gmx_unused lambda,
                  real gmx_unused* dvdlambda,
-                 const t_mdatoms gmx_unused* md,
+                 gmx::ArrayRef<const real> /*charge*/,
                  t_fcdata gmx_unused* fcd,
+                 t_disresdata gmx_unused* disresdata,
+                 t_oriresdata gmx_unused* oriresdata,
                  int gmx_unused* global_atom_index)
 {
     const real three = 3.0;
@@ -375,9 +384,11 @@ real FENE_bonds(int             nbonds,
                 const t_pbc*    pbc,
                 real gmx_unused lambda,
                 real gmx_unused* dvdlambda,
-                const t_mdatoms gmx_unused* md,
+                gmx::ArrayRef<const real> /*charge*/,
                 t_fcdata gmx_unused* fcd,
-                int*                 global_atom_index)
+                t_disresdata gmx_unused* disresdata,
+                t_oriresdata gmx_unused* oriresdata,
+                int*                     global_atom_index)
 {
     const real half = 0.5;
     const real one  = 1.0;
@@ -408,8 +419,12 @@ real FENE_bonds(int             nbonds,
 
         if (dr2 >= bm2)
         {
-            gmx_fatal(FARGS, "r^2 (%f) >= bm^2 (%f) in FENE bond between atoms %d and %d", dr2, bm2,
-                      glatnr(global_atom_index, ai), glatnr(global_atom_index, aj));
+            gmx_fatal(FARGS,
+                      "r^2 (%f) >= bm^2 (%f) in FENE bond between atoms %d and %d",
+                      dr2,
+                      bm2,
+                      glatnr(global_atom_index, ai),
+                      glatnr(global_atom_index, aj));
         }
 
         omdr2obm2 = one - dr2 / bm2;
@@ -460,8 +475,10 @@ bonds(int             nbonds,
       const t_pbc*    pbc,
       real            lambda,
       real*           dvdlambda,
-      const t_mdatoms gmx_unused* md,
+      gmx::ArrayRef<const real> /*charge*/,
       t_fcdata gmx_unused* fcd,
+      t_disresdata gmx_unused* disresdata,
+      t_oriresdata gmx_unused* oriresdata,
       int gmx_unused* global_atom_index)
 {
     int  i, ki, ai, aj, type;
@@ -479,9 +496,14 @@ bonds(int             nbonds,
         dr2 = iprod(dx, dx);                       /*   5              */
         dr  = std::sqrt(dr2);                      /*  10              */
 
-        *dvdlambda += harmonic(forceparams[type].harmonic.krA, forceparams[type].harmonic.krB,
-                               forceparams[type].harmonic.rA, forceparams[type].harmonic.rB, dr,
-                               lambda, &vbond, &fbond); /*  19  */
+        *dvdlambda += harmonic(forceparams[type].harmonic.krA,
+                               forceparams[type].harmonic.krB,
+                               forceparams[type].harmonic.rA,
+                               forceparams[type].harmonic.rB,
+                               dr,
+                               lambda,
+                               &vbond,
+                               &fbond); /*  19  */
 
         if (dr2 == 0.0)
         {
@@ -515,8 +537,10 @@ bonds(int             nbonds,
       const t_pbc*    pbc,
       real gmx_unused lambda,
       real gmx_unused* dvdlambda,
-      const t_mdatoms gmx_unused* md,
+      gmx::ArrayRef<const real> /*charge*/,
       t_fcdata gmx_unused* fcd,
+      t_disresdata gmx_unused* disresdata,
+      t_oriresdata gmx_unused* oriresdata,
       int gmx_unused* global_atom_index)
 {
     constexpr int                            nfa1 = 3;
@@ -605,8 +629,10 @@ real restraint_bonds(int             nbonds,
                      const t_pbc*    pbc,
                      real            lambda,
                      real*           dvdlambda,
-                     const t_mdatoms gmx_unused* md,
+                     gmx::ArrayRef<const real> /*charge*/,
                      t_fcdata gmx_unused* fcd,
+                     t_disresdata gmx_unused* disresdata,
+                     t_oriresdata gmx_unused* oriresdata,
                      int gmx_unused* global_atom_index)
 {
     int  i, ki, ai, aj, type;
@@ -684,17 +710,19 @@ real restraint_bonds(int             nbonds,
 }
 
 template<BondedKernelFlavor flavor>
-real polarize(int              nbonds,
-              const t_iatom    forceatoms[],
-              const t_iparams  forceparams[],
-              const rvec       x[],
-              rvec4            f[],
-              rvec             fshift[],
-              const t_pbc*     pbc,
-              real             lambda,
-              real*            dvdlambda,
-              const t_mdatoms* md,
+real polarize(int                       nbonds,
+              const t_iatom             forceatoms[],
+              const t_iparams           forceparams[],
+              const rvec                x[],
+              rvec4                     f[],
+              rvec                      fshift[],
+              const t_pbc*              pbc,
+              real                      lambda,
+              real*                     dvdlambda,
+              gmx::ArrayRef<const real> charge,
               t_fcdata gmx_unused* fcd,
+              t_disresdata gmx_unused* disresdata,
+              t_oriresdata gmx_unused* oriresdata,
               int gmx_unused* global_atom_index)
 {
     int  i, ki, ai, aj, type;
@@ -707,7 +735,7 @@ real polarize(int              nbonds,
         type = forceatoms[i++];
         ai   = forceatoms[i++];
         aj   = forceatoms[i++];
-        ksh  = gmx::square(md->chargeA[aj]) * ONE_4PI_EPS0 / forceparams[type].polarize.alpha;
+        ksh  = gmx::square(charge[aj]) * gmx::c_one4PiEps0 / forceparams[type].polarize.alpha;
 
         ki  = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /*   3      */
         dr2 = iprod(dx, dx);                       /*   5              */
@@ -729,17 +757,19 @@ real polarize(int              nbonds,
 }
 
 template<BondedKernelFlavor flavor>
-real anharm_polarize(int              nbonds,
-                     const t_iatom    forceatoms[],
-                     const t_iparams  forceparams[],
-                     const rvec       x[],
-                     rvec4            f[],
-                     rvec             fshift[],
-                     const t_pbc*     pbc,
-                     real             lambda,
-                     real*            dvdlambda,
-                     const t_mdatoms* md,
+real anharm_polarize(int                       nbonds,
+                     const t_iatom             forceatoms[],
+                     const t_iparams           forceparams[],
+                     const rvec                x[],
+                     rvec4                     f[],
+                     rvec                      fshift[],
+                     const t_pbc*              pbc,
+                     real                      lambda,
+                     real*                     dvdlambda,
+                     gmx::ArrayRef<const real> charge,
                      t_fcdata gmx_unused* fcd,
+                     t_disresdata gmx_unused* disresdata,
+                     t_oriresdata gmx_unused* oriresdata,
                      int gmx_unused* global_atom_index)
 {
     int  i, ki, ai, aj, type;
@@ -752,7 +782,7 @@ real anharm_polarize(int              nbonds,
         type = forceatoms[i++];
         ai   = forceatoms[i++];
         aj   = forceatoms[i++];
-        ksh = gmx::square(md->chargeA[aj]) * ONE_4PI_EPS0 / forceparams[type].anharm_polarize.alpha; /* 7*/
+        ksh = gmx::square(charge[aj]) * gmx::c_one4PiEps0 / forceparams[type].anharm_polarize.alpha; /* 7*/
         khyp  = forceparams[type].anharm_polarize.khyp;
         drcut = forceparams[type].anharm_polarize.drcut;
 
@@ -791,9 +821,11 @@ real water_pol(int             nbonds,
                rvec gmx_unused fshift[],
                const t_pbc gmx_unused* pbc,
                real gmx_unused lambda,
-               real gmx_unused* dvdlambda,
-               const t_mdatoms gmx_unused* md,
+               real gmx_unused*          dvdlambda,
+               gmx::ArrayRef<const real> charge,
                t_fcdata gmx_unused* fcd,
+               t_disresdata gmx_unused* disresdata,
+               t_oriresdata gmx_unused* oriresdata,
                int gmx_unused* global_atom_index)
 {
     /* This routine implements anisotropic polarizibility for water, through
@@ -809,18 +841,17 @@ real water_pol(int             nbonds,
     {
         type0  = forceatoms[0];
         aS     = forceatoms[5];
-        qS     = md->chargeA[aS];
-        kk[XX] = gmx::square(qS) * ONE_4PI_EPS0 / forceparams[type0].wpol.al_x;
-        kk[YY] = gmx::square(qS) * ONE_4PI_EPS0 / forceparams[type0].wpol.al_y;
-        kk[ZZ] = gmx::square(qS) * ONE_4PI_EPS0 / forceparams[type0].wpol.al_z;
+        qS     = charge[aS];
+        kk[XX] = gmx::square(qS) * gmx::c_one4PiEps0 / forceparams[type0].wpol.al_x;
+        kk[YY] = gmx::square(qS) * gmx::c_one4PiEps0 / forceparams[type0].wpol.al_y;
+        kk[ZZ] = gmx::square(qS) * gmx::c_one4PiEps0 / forceparams[type0].wpol.al_z;
         r_HH   = 1.0 / forceparams[type0].wpol.rHH;
         for (i = 0; (i < nbonds); i += 6)
         {
             type = forceatoms[i];
             if (type != type0)
             {
-                gmx_fatal(FARGS, "Sorry, type = %d, type0 = %d, file = %s, line = %d", type, type0,
-                          __FILE__, __LINE__);
+                gmx_fatal(FARGS, "Sorry, type = %d, type0 = %d, file = %s, line = %d", type, type0, __FILE__, __LINE__);
             }
             aO  = forceatoms[i + 1];
             aH1 = forceatoms[i + 2];
@@ -884,7 +915,7 @@ real water_pol(int             nbonds,
                 if (computeVirial(flavor))
                 {
                     fshift[ki][m] += fij;
-                    fshift[CENTRAL][m] -= fij;
+                    fshift[c_centralShiftIndex][m] -= fij;
                 }
             }
         }
@@ -905,7 +936,7 @@ do_1_thole(const rvec xi, const rvec xj, rvec fi, rvec fj, const t_pbc* pbc, rea
     r12sq  = iprod(r12, r12);                                                     /*  5 */
     r12_1  = gmx::invsqrt(r12sq);                                                 /*  5 */
     r12bar = afac / r12_1;                                                        /*  5 */
-    v0     = qq * ONE_4PI_EPS0 * r12_1;                                           /*  2 */
+    v0     = qq * gmx::c_one4PiEps0 * r12_1;                                      /*  2 */
     ebar   = std::exp(-r12bar);                                                   /*  5 */
     v1     = (1 - (1 + 0.5 * r12bar) * ebar);                                     /*  4 */
     fscal  = ((v0 * r12_1) * v1 - v0 * 0.5 * afac * ebar * (r12bar + 1)) * r12_1; /* 9 */
@@ -918,7 +949,7 @@ do_1_thole(const rvec xi, const rvec xj, rvec fi, rvec fj, const t_pbc* pbc, rea
         if (computeVirial(flavor))
         {
             fshift[t][m] += fff;
-            fshift[CENTRAL][m] -= fff;
+            fshift[c_centralShiftIndex][m] -= fff;
         }
     } /* 15 */
 
@@ -935,9 +966,11 @@ real thole_pol(int             nbonds,
                rvec            fshift[],
                const t_pbc*    pbc,
                real gmx_unused lambda,
-               real gmx_unused* dvdlambda,
-               const t_mdatoms* md,
+               real gmx_unused*          dvdlambda,
+               gmx::ArrayRef<const real> charge,
                t_fcdata gmx_unused* fcd,
+               t_disresdata gmx_unused* disresdata,
+               t_oriresdata gmx_unused* oriresdata,
                int gmx_unused* global_atom_index)
 {
     /* Interaction between two pairs of particles with opposite charge */
@@ -952,8 +985,8 @@ real thole_pol(int             nbonds,
         da1  = forceatoms[i++];
         a2   = forceatoms[i++];
         da2  = forceatoms[i++];
-        q1   = md->chargeA[da1];
-        q2   = md->chargeA[da2];
+        q1   = charge[da1];
+        q2   = charge[da2];
         a    = forceparams[type].thole.a;
         al1  = forceparams[type].thole.alpha1;
         al2  = forceparams[type].thole.alpha2;
@@ -987,8 +1020,10 @@ angles(int             nbonds,
        const t_pbc*    pbc,
        real            lambda,
        real*           dvdlambda,
-       const t_mdatoms gmx_unused* md,
+       gmx::ArrayRef<const real> /*charge*/,
        t_fcdata gmx_unused* fcd,
+       t_disresdata gmx_unused* disresdata,
+       t_oriresdata gmx_unused* oriresdata,
        int gmx_unused* global_atom_index)
 {
     int  i, ai, aj, ak, t1, t2, type;
@@ -1005,9 +1040,14 @@ angles(int             nbonds,
 
         theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /*  41 */
 
-        *dvdlambda += harmonic(forceparams[type].harmonic.krA, forceparams[type].harmonic.krB,
-                               forceparams[type].harmonic.rA * DEG2RAD,
-                               forceparams[type].harmonic.rB * DEG2RAD, theta, lambda, &va, &dVdt); /*  21  */
+        *dvdlambda += harmonic(forceparams[type].harmonic.krA,
+                               forceparams[type].harmonic.krB,
+                               forceparams[type].harmonic.rA * gmx::c_deg2Rad,
+                               forceparams[type].harmonic.rB * gmx::c_deg2Rad,
+                               theta,
+                               lambda,
+                               &va,
+                               &dVdt); /*  21  */
         vtot += va;
 
         cos_theta2 = gmx::square(cos_theta);
@@ -1044,7 +1084,7 @@ angles(int             nbonds,
             if (computeVirial(flavor))
             {
                 rvec_inc(fshift[t1], f_i);
-                rvec_inc(fshift[CENTRAL], f_j);
+                rvec_inc(fshift[c_centralShiftIndex], f_j);
                 rvec_inc(fshift[t2], f_k);
             }
         } /* 161 TOTAL */
@@ -1074,8 +1114,10 @@ angles(int             nbonds,
        const t_pbc*    pbc,
        real gmx_unused lambda,
        real gmx_unused* dvdlambda,
-       const t_mdatoms gmx_unused* md,
+       gmx::ArrayRef<const real> /*charge*/,
        t_fcdata gmx_unused* fcd,
+       t_disresdata gmx_unused* disresdata,
+       t_oriresdata gmx_unused* oriresdata,
        int gmx_unused* global_atom_index)
 {
     const int                                nfa1 = 4;
@@ -1085,7 +1127,7 @@ angles(int             nbonds,
     alignas(GMX_SIMD_ALIGNMENT) std::int32_t aj[GMX_SIMD_REAL_WIDTH];
     alignas(GMX_SIMD_ALIGNMENT) std::int32_t ak[GMX_SIMD_REAL_WIDTH];
     alignas(GMX_SIMD_ALIGNMENT) real         coeff[2 * GMX_SIMD_REAL_WIDTH];
-    SimdReal                                 deg2rad_S(DEG2RAD);
+    SimdReal                                 deg2rad_S(gmx::c_deg2Rad);
     SimdReal                                 xi_S, yi_S, zi_S;
     SimdReal                                 xj_S, yj_S, zj_S;
     SimdReal                                 xk_S, yk_S, zk_S;
@@ -1212,8 +1254,8 @@ angles(int             nbonds,
         f_kz_S = fnma(cik_S, rijz_S, f_kz_S);
 
         transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_ix_S, f_iy_S, f_iz_S);
-        transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S,
-                                 f_iz_S + f_kz_S);
+        transposeScatterDecrU<4>(
+                reinterpret_cast<real*>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S, f_iz_S + f_kz_S);
         transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_kx_S, f_ky_S, f_kz_S);
     }
 
@@ -1232,8 +1274,10 @@ real linear_angles(int             nbonds,
                    const t_pbc*    pbc,
                    real            lambda,
                    real*           dvdlambda,
-                   const t_mdatoms gmx_unused* md,
+                   gmx::ArrayRef<const real> /*charge*/,
                    t_fcdata gmx_unused* fcd,
+                   t_disresdata gmx_unused* disresdata,
+                   t_oriresdata gmx_unused* oriresdata,
                    int gmx_unused* global_atom_index)
 {
     int  i, m, ai, aj, ak, t1, t2, type;
@@ -1284,7 +1328,7 @@ real linear_angles(int             nbonds,
         if (computeVirial(flavor))
         {
             rvec_inc(fshift[t1], f_i);
-            rvec_inc(fshift[CENTRAL], f_j);
+            rvec_inc(fshift[c_centralShiftIndex], f_j);
             rvec_inc(fshift[t2], f_k);
         }
     } /* 57 TOTAL      */
@@ -1302,8 +1346,10 @@ urey_bradley(int             nbonds,
              const t_pbc*    pbc,
              real            lambda,
              real*           dvdlambda,
-             const t_mdatoms gmx_unused* md,
+             gmx::ArrayRef<const real> /*charge*/,
              t_fcdata gmx_unused* fcd,
+             t_disresdata gmx_unused* disresdata,
+             t_oriresdata gmx_unused* oriresdata,
              int gmx_unused* global_atom_index)
 {
     int  i, m, ai, aj, ak, t1, t2, type, ki;
@@ -1319,11 +1365,11 @@ urey_bradley(int             nbonds,
         ai   = forceatoms[i++];
         aj   = forceatoms[i++];
         ak   = forceatoms[i++];
-        th0A = forceparams[type].u_b.thetaA * DEG2RAD;
+        th0A = forceparams[type].u_b.thetaA * gmx::c_deg2Rad;
         kthA = forceparams[type].u_b.kthetaA;
         r13A = forceparams[type].u_b.r13A;
         kUBA = forceparams[type].u_b.kUBA;
-        th0B = forceparams[type].u_b.thetaB * DEG2RAD;
+        th0B = forceparams[type].u_b.thetaB * gmx::c_deg2Rad;
         kthB = forceparams[type].u_b.kthetaB;
         r13B = forceparams[type].u_b.r13B;
         kUBB = forceparams[type].u_b.kUBB;
@@ -1368,7 +1414,7 @@ urey_bradley(int             nbonds,
             if (computeVirial(flavor))
             {
                 rvec_inc(fshift[t1], f_i);
-                rvec_inc(fshift[CENTRAL], f_j);
+                rvec_inc(fshift[c_centralShiftIndex], f_j);
                 rvec_inc(fshift[t2], f_k);
             }
         } /* 161 TOTAL */
@@ -1389,7 +1435,7 @@ urey_bradley(int             nbonds,
             if (computeVirial(flavor))
             {
                 fshift[ki][m] += fik;
-                fshift[CENTRAL][m] -= fik;
+                fshift[c_centralShiftIndex][m] -= fik;
             }
         }
     }
@@ -1412,8 +1458,10 @@ urey_bradley(int             nbonds,
              const t_pbc*    pbc,
              real gmx_unused lambda,
              real gmx_unused* dvdlambda,
-             const t_mdatoms gmx_unused* md,
+             gmx::ArrayRef<const real> /*charge*/,
              t_fcdata gmx_unused* fcd,
+             t_disresdata gmx_unused* disresdata,
+             t_oriresdata gmx_unused* oriresdata,
              int gmx_unused* global_atom_index)
 {
     constexpr int                            nfa1 = 4;
@@ -1480,7 +1528,7 @@ urey_bradley(int             nbonds,
         SimdReal rikz_S = zi_S - zk_S;
 
         const SimdReal ktheta_S = load<SimdReal>(coeff);
-        const SimdReal theta0_S = load<SimdReal>(coeff + GMX_SIMD_REAL_WIDTH) * DEG2RAD;
+        const SimdReal theta0_S = load<SimdReal>(coeff + GMX_SIMD_REAL_WIDTH) * gmx::c_deg2Rad;
         const SimdReal kUB_S    = load<SimdReal>(coeff + 2 * GMX_SIMD_REAL_WIDTH);
         const SimdReal r13_S    = load<SimdReal>(coeff + 3 * GMX_SIMD_REAL_WIDTH);
 
@@ -1534,8 +1582,8 @@ urey_bradley(int             nbonds,
         const SimdReal f_kz_S = fnma(cik_S, rijz_S, ckk_S * rkjz_S) - f_ikz_S;
 
         transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ai, f_ix_S, f_iy_S, f_iz_S);
-        transposeScatterDecrU<4>(reinterpret_cast<real*>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S,
-                                 f_iz_S + f_kz_S);
+        transposeScatterDecrU<4>(
+                reinterpret_cast<real*>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S, f_iz_S + f_kz_S);
         transposeScatterIncrU<4>(reinterpret_cast<real*>(f), ak, f_kx_S, f_ky_S, f_kz_S);
     }
 
@@ -1554,8 +1602,10 @@ real quartic_angles(int             nbonds,
                     const t_pbc*    pbc,
                     real gmx_unused lambda,
                     real gmx_unused* dvdlambda,
-                    const t_mdatoms gmx_unused* md,
+                    gmx::ArrayRef<const real> /*charge*/,
                     t_fcdata gmx_unused* fcd,
+                    t_disresdata gmx_unused* disresdata,
+                    t_oriresdata gmx_unused* oriresdata,
                     int gmx_unused* global_atom_index)
 {
     int  i, j, ai, aj, ak, t1, t2, type;
@@ -1572,7 +1622,7 @@ real quartic_angles(int             nbonds,
 
         theta = bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &cos_theta, &t1, &t2); /*  41 */
 
-        dt = theta - forceparams[type].qangle.theta * DEG2RAD; /* 2          */
+        dt = theta - forceparams[type].qangle.theta * gmx::c_deg2Rad; /* 2          */
 
         dVdt = 0;
         va   = forceparams[type].qangle.c[0];
@@ -1619,7 +1669,7 @@ real quartic_angles(int             nbonds,
             if (computeVirial(flavor))
             {
                 rvec_inc(fshift[t1], f_i);
-                rvec_inc(fshift[CENTRAL], f_j);
+                rvec_inc(fshift[c_centralShiftIndex], f_j);
                 rvec_inc(fshift[t2], f_k);
             }
         } /* 153 TOTAL */
@@ -1808,11 +1858,11 @@ void do_dih_fup(int          i,
             }
             else
             {
-                t3 = CENTRAL;
+                t3 = c_centralShiftIndex;
             }
 
             rvec_inc(fshift[t1], f_i);
-            rvec_dec(fshift[CENTRAL], f_j);
+            rvec_dec(fshift[c_centralShiftIndex], f_j);
             rvec_dec(fshift[t2], f_k);
             rvec_inc(fshift[t3], f_l);
         }
@@ -1864,8 +1914,8 @@ template<BondedKernelFlavor flavor>
 real dopdihs(real cpA, real cpB, real phiA, real phiB, int mult, real phi, real lambda, real* V, real* dvdlambda)
 {
     const real L1   = 1.0 - lambda;
-    const real ph0  = (L1 * phiA + lambda * phiB) * DEG2RAD;
-    const real dph0 = (phiB - phiA) * DEG2RAD;
+    const real ph0  = (L1 * phiA + lambda * phiB) * gmx::c_deg2Rad;
+    const real dph0 = (phiB - phiA) * gmx::c_deg2Rad;
     const real cp   = L1 * cpA + lambda * cpB;
 
     const real mdphi = mult * phi - ph0;
@@ -1888,8 +1938,8 @@ real dopdihs_min(real cpA, real cpB, real phiA, real phiB, int mult, real phi, r
 {
     real v, dvdlambda, mdphi, v1, sdphi, ddphi;
     real L1   = 1.0 - lambda;
-    real ph0  = (L1 * phiA + lambda * phiB) * DEG2RAD;
-    real dph0 = (phiB - phiA) * DEG2RAD;
+    real ph0  = (L1 * phiA + lambda * phiB) * gmx::c_deg2Rad;
+    real dph0 = (phiB - phiA) * gmx::c_deg2Rad;
     real cp   = L1 * cpA + lambda * cpB;
 
     mdphi = mult * (phi - ph0);
@@ -1919,8 +1969,10 @@ pdihs(int             nbonds,
       const t_pbc*    pbc,
       real            lambda,
       real*           dvdlambda,
-      const t_mdatoms gmx_unused* md,
+      gmx::ArrayRef<const real> /*charge*/,
       t_fcdata gmx_unused* fcd,
+      t_disresdata gmx_unused* disresdata,
+      t_oriresdata gmx_unused* oriresdata,
       int gmx_unused* global_atom_index)
 {
     int  t1, t2, t3;
@@ -1935,8 +1987,8 @@ pdihs(int             nbonds,
         const int ak = forceatoms[i + 3];
         const int al = forceatoms[i + 4];
 
-        const real phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1,
-                                   &t2, &t3); /*  84      */
+        const real phi =
+                dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n, &t1, &t2, &t3); /*  84 */
 
         /* Loop over dihedrals working on the same atoms,
          * so we avoid recalculating angles and distributing forces.
@@ -1945,17 +1997,23 @@ pdihs(int             nbonds,
         do
         {
             const int type = forceatoms[i];
-            ddphi_tot += dopdihs<flavor>(forceparams[type].pdihs.cpA, forceparams[type].pdihs.cpB,
-                                         forceparams[type].pdihs.phiA, forceparams[type].pdihs.phiB,
-                                         forceparams[type].pdihs.mult, phi, lambda, &vtot, dvdlambda);
+            ddphi_tot += dopdihs<flavor>(forceparams[type].pdihs.cpA,
+                                         forceparams[type].pdihs.cpB,
+                                         forceparams[type].pdihs.phiA,
+                                         forceparams[type].pdihs.phiB,
+                                         forceparams[type].pdihs.mult,
+                                         phi,
+                                         lambda,
+                                         &vtot,
+                                         dvdlambda);
 
             i += 5;
         } while (i < nbonds && forceatoms[i + 1] == ai && forceatoms[i + 2] == aj
                  && forceatoms[i + 3] == ak && forceatoms[i + 4] == al);
 
-        do_dih_fup<flavor>(ai, aj, ak, al, ddphi_tot, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
-                           t2, t3); /* 112             */
-    }                               /* 223 TOTAL  */
+        do_dih_fup<flavor>(
+                ai, aj, ak, al, ddphi_tot, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2, t3); /* 112              */
+    } /* 223 TOTAL  */
 
     return vtot;
 }
@@ -1974,8 +2032,10 @@ pdihs(int             nbonds,
       const t_pbc*    pbc,
       real gmx_unused lambda,
       real gmx_unused* dvdlambda,
-      const t_mdatoms gmx_unused* md,
+      gmx::ArrayRef<const real> /*charge*/,
       t_fcdata gmx_unused* fcd,
+      t_disresdata gmx_unused* disresdata,
+      t_oriresdata gmx_unused* oriresdata,
       int gmx_unused* global_atom_index)
 {
     const int                                nfa1 = 5;
@@ -1987,7 +2047,7 @@ pdihs(int             nbonds,
     alignas(GMX_SIMD_ALIGNMENT) std::int32_t al[GMX_SIMD_REAL_WIDTH];
     alignas(GMX_SIMD_ALIGNMENT) real         buf[3 * GMX_SIMD_REAL_WIDTH];
     real *                                   cp, *phi0, *mult;
-    SimdReal                                 deg2rad_S(DEG2RAD);
+    SimdReal                                 deg2rad_S(gmx::c_deg2Rad);
     SimdReal                                 p_S, q_S;
     SimdReal                                 phi0_S, phi_S;
     SimdReal                                 mx_S, my_S, mz_S;
@@ -2042,8 +2102,8 @@ pdihs(int             nbonds,
         }
 
         /* Calculate GMX_SIMD_REAL_WIDTH dihedral angles at once */
-        dih_angle_simd(x, ai, aj, ak, al, pbc_simd, &phi_S, &mx_S, &my_S, &mz_S, &nx_S, &ny_S,
-                       &nz_S, &nrkj_m2_S, &nrkj_n2_S, &p_S, &q_S);
+        dih_angle_simd(
+                x, ai, aj, ak, al, pbc_simd, &phi_S, &mx_S, &my_S, &mz_S, &nx_S, &ny_S, &nz_S, &nrkj_m2_S, &nrkj_n2_S, &p_S, &q_S);
 
         cp_S   = load<SimdReal>(cp);
         phi0_S = load<SimdReal>(phi0) * deg2rad_S;
@@ -2088,8 +2148,10 @@ rbdihs(int             nbonds,
        const t_pbc*    pbc,
        real gmx_unused lambda,
        real gmx_unused* dvdlambda,
-       const t_mdatoms gmx_unused* md,
+       gmx::ArrayRef<const real> /*charge*/,
        t_fcdata gmx_unused* fcd,
+       t_disresdata gmx_unused* disresdata,
+       t_oriresdata gmx_unused* oriresdata,
        int gmx_unused* global_atom_index)
 {
     const int                                nfa1 = 5;
@@ -2158,8 +2220,8 @@ rbdihs(int             nbonds,
         }
 
         /* Calculate GMX_SIMD_REAL_WIDTH dihedral angles at once */
-        dih_angle_simd(x, ai, aj, ak, al, pbc_simd, &phi_S, &mx_S, &my_S, &mz_S, &nx_S, &ny_S,
-                       &nz_S, &nrkj_m2_S, &nrkj_n2_S, &p_S, &q_S);
+        dih_angle_simd(
+                x, ai, aj, ak, al, pbc_simd, &phi_S, &mx_S, &my_S, &mz_S, &nx_S, &ny_S, &nz_S, &nrkj_m2_S, &nrkj_n2_S, &p_S, &q_S);
 
         /* Change to polymer convention */
         phi_S = phi_S - pi_S;
@@ -2214,8 +2276,10 @@ real idihs(int             nbonds,
            const t_pbc*    pbc,
            real            lambda,
            real*           dvdlambda,
-           const t_mdatoms gmx_unused* md,
+           gmx::ArrayRef<const real> /*charge*/,
            t_fcdata gmx_unused* fcd,
+           t_disresdata gmx_unused* disresdata,
+           t_oriresdata gmx_unused* oriresdata,
            int gmx_unused* global_atom_index)
 {
     int  i, type, ai, aj, ak, al;
@@ -2250,8 +2314,8 @@ real idihs(int             nbonds,
         pB = forceparams[type].harmonic.rB;
 
         kk    = L1 * kA + lambda * kB;
-        phi0  = (L1 * pA + lambda * pB) * DEG2RAD;
-        dphi0 = (pB - pA) * DEG2RAD;
+        phi0  = (L1 * pA + lambda * pB) * gmx::c_deg2Rad;
+        dphi0 = (pB - pA) * gmx::c_deg2Rad;
 
         dp = phi - phi0;
 
@@ -2264,8 +2328,7 @@ real idihs(int             nbonds,
 
         dvdl_term += 0.5 * (kB - kA) * dp2 - kk * dphi0 * dp;
 
-        do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
-                           t2, t3); /* 112             */
+        do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2, t3); /* 112              */
         /* 218 TOTAL   */
     }
 
@@ -2318,9 +2381,15 @@ real low_angres(int             nbonds,
         cos_phi = cos_angle(r_ij, r_kl); /* 25         */
         phi     = std::acos(cos_phi);    /* 10           */
 
-        *dvdlambda += dopdihs_min(forceparams[type].pdihs.cpA, forceparams[type].pdihs.cpB,
-                                  forceparams[type].pdihs.phiA, forceparams[type].pdihs.phiB,
-                                  forceparams[type].pdihs.mult, phi, lambda, &vid, &dVdphi); /*  40 */
+        *dvdlambda += dopdihs_min(forceparams[type].pdihs.cpA,
+                                  forceparams[type].pdihs.cpB,
+                                  forceparams[type].pdihs.phiA,
+                                  forceparams[type].pdihs.phiB,
+                                  forceparams[type].pdihs.mult,
+                                  phi,
+                                  lambda,
+                                  &vid,
+                                  &dVdphi); /*  40 */
 
         vtot += vid;
 
@@ -2352,11 +2421,11 @@ real low_angres(int             nbonds,
             if (computeVirial(flavor))
             {
                 rvec_inc(fshift[t1], f_i);
-                rvec_dec(fshift[CENTRAL], f_i);
+                rvec_dec(fshift[c_centralShiftIndex], f_i);
                 if (!bZAxis)
                 {
                     rvec_inc(fshift[t2], f_k);
-                    rvec_dec(fshift[CENTRAL], f_k);
+                    rvec_dec(fshift[c_centralShiftIndex], f_k);
                 }
             }
         }
@@ -2375,8 +2444,10 @@ real angres(int             nbonds,
             const t_pbc*    pbc,
             real            lambda,
             real*           dvdlambda,
-            const t_mdatoms gmx_unused* md,
+            gmx::ArrayRef<const real> /*charge*/,
             t_fcdata gmx_unused* fcd,
+            t_disresdata gmx_unused* disresdata,
+            t_oriresdata gmx_unused* oriresdata,
             int gmx_unused* global_atom_index)
 {
     return low_angres<flavor>(nbonds, forceatoms, forceparams, x, f, fshift, pbc, lambda, dvdlambda, FALSE);
@@ -2392,8 +2463,10 @@ real angresz(int             nbonds,
              const t_pbc*    pbc,
              real            lambda,
              real*           dvdlambda,
-             const t_mdatoms gmx_unused* md,
+             gmx::ArrayRef<const real> /*charge*/,
              t_fcdata gmx_unused* fcd,
+             t_disresdata gmx_unused* disresdata,
+             t_oriresdata gmx_unused* oriresdata,
              int gmx_unused* global_atom_index)
 {
     return low_angres<flavor>(nbonds, forceatoms, forceparams, x, f, fshift, pbc, lambda, dvdlambda, TRUE);
@@ -2409,8 +2482,10 @@ real dihres(int             nbonds,
             const t_pbc*    pbc,
             real            lambda,
             real*           dvdlambda,
-            const t_mdatoms gmx_unused* md,
+            gmx::ArrayRef<const real> /*charge*/,
             t_fcdata gmx_unused* fcd,
+            t_disresdata gmx_unused* disresdata,
+            t_oriresdata gmx_unused* oriresdata,
             int gmx_unused* global_atom_index)
 {
     real vtot = 0;
@@ -2421,7 +2496,7 @@ real dihres(int             nbonds,
 
     L1 = 1.0 - lambda;
 
-    d2r = DEG2RAD;
+    d2r = gmx::c_deg2Rad;
 
     for (i = 0; (i < nbonds);)
     {
@@ -2485,8 +2560,8 @@ real dihres(int             nbonds,
             {
                 *dvdlambda += kfac * ddp * ((dphiB - dphiA) - (phi0B - phi0A));
             }
-            do_dih_fup<flavor>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
-                               t2, t3); /* 112         */
+            do_dih_fup<flavor>(
+                    ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2, t3); /* 112              */
         }
     }
     return vtot;
@@ -2502,8 +2577,10 @@ real unimplemented(int gmx_unused nbonds,
                    const t_pbc gmx_unused* pbc,
                    real gmx_unused lambda,
                    real gmx_unused* dvdlambda,
-                   const t_mdatoms gmx_unused* md,
+                   gmx::ArrayRef<const real> /*charge*/,
                    t_fcdata gmx_unused* fcd,
+                   t_disresdata gmx_unused* disresdata,
+                   t_oriresdata gmx_unused* oriresdata,
                    int gmx_unused* global_atom_index)
 {
     gmx_impl("*** you are using a not implemented function");
@@ -2519,8 +2596,10 @@ real restrangles(int             nbonds,
                  const t_pbc*    pbc,
                  real gmx_unused lambda,
                  real gmx_unused* dvdlambda,
-                 const t_mdatoms gmx_unused* md,
+                 gmx::ArrayRef<const real> /*charge*/,
                  t_fcdata gmx_unused* fcd,
+                 t_disresdata gmx_unused* disresdata,
+                 t_oriresdata gmx_unused* oriresdata,
                  int gmx_unused* global_atom_index)
 {
     int    i, d, ai, aj, ak, type, m;
@@ -2575,8 +2654,8 @@ real restrangles(int             nbonds,
          * {\sin^2\theta_i}\f] ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
          * For more explanations see comments file "restcbt.h". */
 
-        compute_factors_restangles(type, forceparams, delta_ante, delta_post, &prefactor,
-                                   &ratio_ante, &ratio_post, &v);
+        compute_factors_restangles(
+                type, forceparams, delta_ante, delta_post, &prefactor, &ratio_ante, &ratio_post, &v);
 
         /*   Forces are computed per component */
         for (d = 0; d < DIM; d++)
@@ -2603,7 +2682,7 @@ real restrangles(int             nbonds,
         if (computeVirial(flavor))
         {
             rvec_inc(fshift[t1], f_i);
-            rvec_inc(fshift[CENTRAL], f_j);
+            rvec_inc(fshift[c_centralShiftIndex], f_j);
             rvec_inc(fshift[t2], f_k);
         }
     }
@@ -2621,8 +2700,10 @@ real restrdihs(int             nbonds,
                const t_pbc*    pbc,
                real gmx_unused lambda,
                real gmx_unused* dvlambda,
-               const t_mdatoms gmx_unused* md,
+               gmx::ArrayRef<const real> /*charge*/,
                t_fcdata gmx_unused* fcd,
+               t_disresdata gmx_unused* disresdata,
+               t_oriresdata gmx_unused* oriresdata,
                int gmx_unused* global_atom_index)
 {
     int  i, d, type, ai, aj, ak, al;
@@ -2662,11 +2743,25 @@ real restrdihs(int             nbonds,
          * ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
          * For more explanations see comments file "restcbt.h" */
 
-        compute_factors_restrdihs(
-                type, forceparams, delta_ante, delta_crnt, delta_post, &factor_phi_ai_ante,
-                &factor_phi_ai_crnt, &factor_phi_ai_post, &factor_phi_aj_ante, &factor_phi_aj_crnt,
-                &factor_phi_aj_post, &factor_phi_ak_ante, &factor_phi_ak_crnt, &factor_phi_ak_post,
-                &factor_phi_al_ante, &factor_phi_al_crnt, &factor_phi_al_post, &prefactor_phi, &v);
+        compute_factors_restrdihs(type,
+                                  forceparams,
+                                  delta_ante,
+                                  delta_crnt,
+                                  delta_post,
+                                  &factor_phi_ai_ante,
+                                  &factor_phi_ai_crnt,
+                                  &factor_phi_ai_post,
+                                  &factor_phi_aj_ante,
+                                  &factor_phi_aj_crnt,
+                                  &factor_phi_aj_post,
+                                  &factor_phi_ak_ante,
+                                  &factor_phi_ak_crnt,
+                                  &factor_phi_ak_post,
+                                  &factor_phi_al_ante,
+                                  &factor_phi_al_crnt,
+                                  &factor_phi_al_post,
+                                  &prefactor_phi,
+                                  &v);
 
 
         /*      Computation of forces per component */
@@ -2705,11 +2800,11 @@ real restrdihs(int             nbonds,
             }
             else
             {
-                t3 = CENTRAL;
+                t3 = c_centralShiftIndex;
             }
 
             rvec_inc(fshift[t1], f_i);
-            rvec_inc(fshift[CENTRAL], f_j);
+            rvec_inc(fshift[c_centralShiftIndex], f_j);
             rvec_inc(fshift[t2], f_k);
             rvec_inc(fshift[t3], f_l);
         }
@@ -2729,8 +2824,10 @@ real cbtdihs(int             nbonds,
              const t_pbc*    pbc,
              real gmx_unused lambda,
              real gmx_unused* dvdlambda,
-             const t_mdatoms gmx_unused* md,
+             gmx::ArrayRef<const real> /*charge*/,
              t_fcdata gmx_unused* fcd,
+             t_disresdata gmx_unused* disresdata,
+             t_oriresdata gmx_unused* oriresdata,
              int gmx_unused* global_atom_index)
 {
     int  type, ai, aj, ak, al, i, d;
@@ -2773,9 +2870,22 @@ real cbtdihs(int             nbonds,
          * --- the adjacent bending angles.
          * For more explanations see comments file "restcbt.h". */
 
-        compute_factors_cbtdihs(type, forceparams, delta_ante, delta_crnt, delta_post, f_phi_ai,
-                                f_phi_aj, f_phi_ak, f_phi_al, f_theta_ante_ai, f_theta_ante_aj,
-                                f_theta_ante_ak, f_theta_post_aj, f_theta_post_ak, f_theta_post_al, &v);
+        compute_factors_cbtdihs(type,
+                                forceparams,
+                                delta_ante,
+                                delta_crnt,
+                                delta_post,
+                                f_phi_ai,
+                                f_phi_aj,
+                                f_phi_ak,
+                                f_phi_al,
+                                f_theta_ante_ai,
+                                f_theta_ante_aj,
+                                f_theta_ante_ak,
+                                f_theta_post_aj,
+                                f_theta_post_ak,
+                                f_theta_post_al,
+                                &v);
 
 
         /*      Acumulate the resuts per beads */
@@ -2807,11 +2917,11 @@ real cbtdihs(int             nbonds,
             }
             else
             {
-                t3 = CENTRAL;
+                t3 = c_centralShiftIndex;
             }
 
             rvec_inc(fshift[t1], f_i);
-            rvec_inc(fshift[CENTRAL], f_j);
+            rvec_inc(fshift[c_centralShiftIndex], f_j);
             rvec_inc(fshift[t2], f_k);
             rvec_inc(fshift[t3], f_l);
         }
@@ -2831,8 +2941,10 @@ rbdihs(int             nbonds,
        const t_pbc*    pbc,
        real            lambda,
        real*           dvdlambda,
-       const t_mdatoms gmx_unused* md,
+       gmx::ArrayRef<const real> /*charge*/,
        t_fcdata gmx_unused* fcd,
+       t_disresdata gmx_unused* disresdata,
+       t_oriresdata gmx_unused* oriresdata,
        int gmx_unused* global_atom_index)
 {
     const real c0 = 0.0, c1 = 1.0, c2 = 2.0, c3 = 3.0, c4 = 4.0, c5 = 5.0;
@@ -2920,8 +3032,7 @@ rbdihs(int             nbonds,
 
         ddphi = -ddphi * sin_phi; /*  11               */
 
-        do_dih_fup<flavor>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2,
-                           t3); /* 112         */
+        do_dih_fup<flavor>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2, t3); /* 112               */
         vtot += v;
     }
     *dvdlambda += dvdl_term;
@@ -2982,8 +3093,10 @@ real cmap_dihs(int                 nbonds,
                const struct t_pbc* pbc,
                real gmx_unused lambda,
                real gmx_unused* dvdlambda,
-               const t_mdatoms gmx_unused* md,
+               gmx::ArrayRef<const real> /*charge*/,
                t_fcdata gmx_unused* fcd,
+               t_disresdata gmx_unused* disresdata,
+               t_oriresdata gmx_unused* oriresdata,
                int gmx_unused* global_atom_index)
 {
     int i, n;
@@ -3039,8 +3152,8 @@ real cmap_dihs(int                 nbonds,
         a1k = ak;
         a1l = al;
 
-        phi1 = dih_angle(x[a1i], x[a1j], x[a1k], x[a1l], pbc, r1_ij, r1_kj, r1_kl, m1, n1, &t11,
-                         &t21, &t31); /* 84 */
+        phi1 = dih_angle(
+                x[a1i], x[a1j], x[a1k], x[a1l], pbc, r1_ij, r1_kj, r1_kl, m1, n1, &t11, &t21, &t31); /* 84 */
 
         cos_phi1 = std::cos(phi1);
 
@@ -3100,8 +3213,8 @@ real cmap_dihs(int                 nbonds,
         a2k = al;
         a2l = am;
 
-        phi2 = dih_angle(x[a2i], x[a2j], x[a2k], x[a2l], pbc, r2_ij, r2_kj, r2_kl, m2, n2, &t12,
-                         &t22, &t32); /* 84 */
+        phi2 = dih_angle(
+                x[a2i], x[a2j], x[a2k], x[a2l], pbc, r2_ij, r2_kj, r2_kl, m2, n2, &t12, &t22, &t32); /* 84 */
 
         cos_phi2 = std::cos(phi2);
 
@@ -3211,8 +3324,8 @@ real cmap_dihs(int                 nbonds,
 
         /* Switch to degrees */
         dx    = 360.0 / cmap_grid->grid_spacing;
-        xphi1 = xphi1 * RAD2DEG;
-        xphi2 = xphi2 * RAD2DEG;
+        xphi1 = xphi1 * gmx::c_rad2Deg;
+        xphi2 = xphi2 * gmx::c_rad2Deg;
 
         for (i = 0; i < 4; i++) /* 16 */
         {
@@ -3249,7 +3362,7 @@ real cmap_dihs(int                 nbonds,
             df2 = tt * df2 + (3.0 * tc[i * 4 + 3] * tu + 2.0 * tc[i * 4 + 2]) * tu + tc[i * 4 + 1];
         }
 
-        fac = RAD2DEG / dx;
+        fac = gmx::c_rad2Deg / dx;
         df1 = df1 * fac;
         df2 = df2 * fac;
 
@@ -3324,17 +3437,17 @@ real cmap_dihs(int                 nbonds,
             }
             else
             {
-                t31 = CENTRAL;
-                t32 = CENTRAL;
+                t31 = c_centralShiftIndex;
+                t32 = c_centralShiftIndex;
             }
 
             rvec_inc(fshift[t11], f1_i);
-            rvec_inc(fshift[CENTRAL], f1_j);
+            rvec_inc(fshift[c_centralShiftIndex], f1_j);
             rvec_inc(fshift[t21], f1_k);
             rvec_inc(fshift[t31], f1_l);
 
             rvec_inc(fshift[t12], f2_i);
-            rvec_inc(fshift[CENTRAL], f2_j);
+            rvec_inc(fshift[c_centralShiftIndex], f2_j);
             rvec_inc(fshift[t22], f2_k);
             rvec_inc(fshift[t32], f2_l);
         }
@@ -3386,8 +3499,10 @@ real g96bonds(int             nbonds,
               const t_pbc*    pbc,
               real            lambda,
               real*           dvdlambda,
-              const t_mdatoms gmx_unused* md,
+              gmx::ArrayRef<const real> /*charge*/,
               t_fcdata gmx_unused* fcd,
+              t_disresdata gmx_unused* disresdata,
+              t_oriresdata gmx_unused* oriresdata,
               int gmx_unused* global_atom_index)
 {
     int  i, ki, ai, aj, type;
@@ -3404,9 +3519,14 @@ real g96bonds(int             nbonds,
         ki  = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /*   3      */
         dr2 = iprod(dx, dx);                       /*   5              */
 
-        *dvdlambda += g96harmonic(forceparams[type].harmonic.krA, forceparams[type].harmonic.krB,
-                                  forceparams[type].harmonic.rA, forceparams[type].harmonic.rB, dr2,
-                                  lambda, &vbond, &fbond);
+        *dvdlambda += g96harmonic(forceparams[type].harmonic.krA,
+                                  forceparams[type].harmonic.krB,
+                                  forceparams[type].harmonic.rA,
+                                  forceparams[type].harmonic.rB,
+                                  dr2,
+                                  lambda,
+                                  &vbond,
+                                  &fbond);
 
         vtot += 0.5 * vbond; /* 1*/
 
@@ -3438,8 +3558,10 @@ real g96angles(int             nbonds,
                const t_pbc*    pbc,
                real            lambda,
                real*           dvdlambda,
-               const t_mdatoms gmx_unused* md,
+               gmx::ArrayRef<const real> /*charge*/,
                t_fcdata gmx_unused* fcd,
+               t_disresdata gmx_unused* disresdata,
+               t_oriresdata gmx_unused* oriresdata,
                int gmx_unused* global_atom_index)
 {
     int  i, ai, aj, ak, type, m, t1, t2;
@@ -3458,9 +3580,14 @@ real g96angles(int             nbonds,
 
         cos_theta = g96bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &t1, &t2);
 
-        *dvdlambda += g96harmonic(forceparams[type].harmonic.krA, forceparams[type].harmonic.krB,
-                                  forceparams[type].harmonic.rA, forceparams[type].harmonic.rB,
-                                  cos_theta, lambda, &va, &dVdt);
+        *dvdlambda += g96harmonic(forceparams[type].harmonic.krA,
+                                  forceparams[type].harmonic.krB,
+                                  forceparams[type].harmonic.rA,
+                                  forceparams[type].harmonic.rB,
+                                  cos_theta,
+                                  lambda,
+                                  &va,
+                                  &dVdt);
         vtot += va;
 
         rij_1    = gmx::invsqrt(iprod(r_ij, r_ij));
@@ -3482,7 +3609,7 @@ real g96angles(int             nbonds,
         if (computeVirial(flavor))
         {
             rvec_inc(fshift[t1], f_i);
-            rvec_inc(fshift[CENTRAL], f_j);
+            rvec_inc(fshift[c_centralShiftIndex], f_j);
             rvec_inc(fshift[t2], f_k); /* 9 */
         }
         /* 163 TOTAL   */
@@ -3500,8 +3627,10 @@ real cross_bond_bond(int             nbonds,
                      const t_pbc*    pbc,
                      real gmx_unused lambda,
                      real gmx_unused* dvdlambda,
-                     const t_mdatoms gmx_unused* md,
+                     gmx::ArrayRef<const real> /*charge*/,
                      t_fcdata gmx_unused* fcd,
+                     t_disresdata gmx_unused* disresdata,
+                     t_oriresdata gmx_unused* oriresdata,
                      int gmx_unused* global_atom_index)
 {
     /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
@@ -3554,7 +3683,7 @@ real cross_bond_bond(int             nbonds,
         if (computeVirial(flavor))
         {
             rvec_inc(fshift[t1], f_i);
-            rvec_inc(fshift[CENTRAL], f_j);
+            rvec_inc(fshift[c_centralShiftIndex], f_j);
             rvec_inc(fshift[t2], f_k); /* 9 */
         }
         /* 163 TOTAL   */
@@ -3572,8 +3701,10 @@ real cross_bond_angle(int             nbonds,
                       const t_pbc*    pbc,
                       real gmx_unused lambda,
                       real gmx_unused* dvdlambda,
-                      const t_mdatoms gmx_unused* md,
+                      gmx::ArrayRef<const real> /*charge*/,
                       t_fcdata gmx_unused* fcd,
+                      t_disresdata gmx_unused* disresdata,
+                      t_oriresdata gmx_unused* oriresdata,
                       int gmx_unused* global_atom_index)
 {
     /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
@@ -3636,7 +3767,7 @@ real cross_bond_angle(int             nbonds,
         if (computeVirial(flavor))
         {
             rvec_inc(fshift[t1], f_i);
-            rvec_inc(fshift[CENTRAL], f_j);
+            rvec_inc(fshift[c_centralShiftIndex], f_j);
             rvec_inc(fshift[t2], f_k); /* 9 */
         }
         /* 163 TOTAL   */
@@ -3671,7 +3802,12 @@ real bonded_tab(const char*          type,
         gmx_fatal(FARGS,
                   "A tabulated %s interaction table number %d is out of the table range: r %f, "
                   "between table indices %d and %d, table length %d",
-                  type, table_nr, r, n0, n0 + 1, table->n);
+                  type,
+                  table_nr,
+                  r,
+                  n0,
+                  n0 + 1,
+                  table->n);
     }
     eps   = rt - n0;
     eps2  = eps * eps;
@@ -3703,8 +3839,10 @@ real tab_bonds(int             nbonds,
                const t_pbc*    pbc,
                real            lambda,
                real*           dvdlambda,
-               const t_mdatoms gmx_unused* md,
-               t_fcdata*                   fcd,
+               gmx::ArrayRef<const real> /*charge*/,
+               t_fcdata*    fcd,
+               t_disresdata gmx_unused* disresdata,
+               t_oriresdata gmx_unused* oriresdata,
                int gmx_unused* global_atom_index)
 {
     int  i, ki, ai, aj, type, table;
@@ -3724,8 +3862,15 @@ real tab_bonds(int             nbonds,
 
         table = forceparams[type].tab.table;
 
-        *dvdlambda += bonded_tab("bond", table, &fcd->bondtab[table], forceparams[type].tab.kA,
-                                 forceparams[type].tab.kB, dr, lambda, &vbond, &fbond); /*  22 */
+        *dvdlambda += bonded_tab("bond",
+                                 table,
+                                 &fcd->bondtab[table],
+                                 forceparams[type].tab.kA,
+                                 forceparams[type].tab.kB,
+                                 dr,
+                                 lambda,
+                                 &vbond,
+                                 &fbond); /*  22 */
 
         if (dr2 == 0.0)
         {
@@ -3751,8 +3896,10 @@ real tab_angles(int             nbonds,
                 const t_pbc*    pbc,
                 real            lambda,
                 real*           dvdlambda,
-                const t_mdatoms gmx_unused* md,
-                t_fcdata*                   fcd,
+                gmx::ArrayRef<const real> /*charge*/,
+                t_fcdata*    fcd,
+                t_disresdata gmx_unused* disresdata,
+                t_oriresdata gmx_unused* oriresdata,
                 int gmx_unused* global_atom_index)
 {
     int  i, ai, aj, ak, t1, t2, type, table;
@@ -3771,8 +3918,15 @@ real tab_angles(int             nbonds,
 
         table = forceparams[type].tab.table;
 
-        *dvdlambda += bonded_tab("angle", table, &fcd->angletab[table], forceparams[type].tab.kA,
-                                 forceparams[type].tab.kB, theta, lambda, &va, &dVdt); /*  22  */
+        *dvdlambda += bonded_tab("angle",
+                                 table,
+                                 &fcd->angletab[table],
+                                 forceparams[type].tab.kA,
+                                 forceparams[type].tab.kB,
+                                 theta,
+                                 lambda,
+                                 &va,
+                                 &dVdt); /*  22  */
         vtot += va;
 
         cos_theta2 = gmx::square(cos_theta); /*   1            */
@@ -3806,7 +3960,7 @@ real tab_angles(int             nbonds,
             if (computeVirial(flavor))
             {
                 rvec_inc(fshift[t1], f_i);
-                rvec_inc(fshift[CENTRAL], f_j);
+                rvec_inc(fshift[c_centralShiftIndex], f_j);
                 rvec_inc(fshift[t2], f_k);
             }
         } /* 169 TOTAL */
@@ -3824,8 +3978,10 @@ real tab_dihs(int             nbonds,
               const t_pbc*    pbc,
               real            lambda,
               real*           dvdlambda,
-              const t_mdatoms gmx_unused* md,
-              t_fcdata*                   fcd,
+              gmx::ArrayRef<const real> /*charge*/,
+              t_fcdata*    fcd,
+              t_disresdata gmx_unused* disresdata,
+              t_oriresdata gmx_unused* oriresdata,
               int gmx_unused* global_atom_index)
 {
     int  i, type, ai, aj, ak, al, table;
@@ -3847,12 +4003,18 @@ real tab_dihs(int             nbonds,
         table = forceparams[type].tab.table;
 
         /* Hopefully phi+M_PI never results in values < 0 */
-        *dvdlambda += bonded_tab("dihedral", table, &fcd->dihtab[table], forceparams[type].tab.kA,
-                                 forceparams[type].tab.kB, phi + M_PI, lambda, &vpd, &ddphi);
+        *dvdlambda += bonded_tab("dihedral",
+                                 table,
+                                 &fcd->dihtab[table],
+                                 forceparams[type].tab.kA,
+                                 forceparams[type].tab.kB,
+                                 phi + M_PI,
+                                 lambda,
+                                 &vpd,
+                                 &ddphi);
 
         vtot += vpd;
-        do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1,
-                           t2, t3); /* 112     */
+        do_dih_fup<flavor>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, f, fshift, pbc, x, t1, t2, t3); /* 112      */
 
     } /* 227 TOTAL  */
 
@@ -3984,25 +4146,27 @@ gmx::EnumerationArray<BondedKernelFlavor, std::array<BondedInteractions, F_NRE>>
 
 } // namespace
 
-real calculateSimpleBond(const int           ftype,
-                         const int           numForceatoms,
-                         const t_iatom       forceatoms[],
-                         const t_iparams     forceparams[],
-                         const rvec          x[],
-                         rvec4               f[],
-                         rvec                fshift[],
-                         const struct t_pbc* pbc,
-                         const real          lambda,
-                         real*               dvdlambda,
-                         const t_mdatoms*    md,
-                         t_fcdata*           fcd,
+real calculateSimpleBond(const int                 ftype,
+                         const int                 numForceatoms,
+                         const t_iatom             forceatoms[],
+                         const t_iparams           forceparams[],
+                         const rvec                x[],
+                         rvec4                     f[],
+                         rvec                      fshift[],
+                         const struct t_pbc*       pbc,
+                         const real                lambda,
+                         real*                     dvdlambda,
+                         gmx::ArrayRef<const real> charge,
+                         t_fcdata*                 fcd,
+                         t_disresdata*             disresdata,
+                         t_oriresdata*             oriresdata,
                          int gmx_unused*          global_atom_index,
                          const BondedKernelFlavor bondedKernelFlavor)
 {
     const BondedInteractions& bonded = c_bondedInteractionFunctionsPerFlavor[bondedKernelFlavor][ftype];
 
-    real v = bonded.function(numForceatoms, forceatoms, forceparams, x, f, fshift, pbc, lambda,
-                             dvdlambda, md, fcd, global_atom_index);
+    real v = bonded.function(
+            numForceatoms, forceatoms, forceparams, x, f, fshift, pbc, lambda, dvdlambda, charge, fcd, disresdata, oriresdata, global_atom_index);
 
     return v;
 }
index beb95b55289bc9d108008e7985c4b7ff42ac406a..7a2b6282b91b064588fbe2441aae6f73ea89cc48 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 gmx_cmap_t;
 struct t_fcdata;
-struct t_mdatom;
 struct t_nrnb;
 struct t_pbc;
+struct t_disresdata;
+struct t_oriresdata;
 
 namespace gmx
 {
 template<typename EnumType, typename DataType, EnumType ArraySize>
 struct EnumerationArray;
+template<typename>
+class ArrayRef;
 } // namespace gmx
 
 /*! \brief Calculate bond-angle. No PBC is taken into account (use mol-shift) */
@@ -125,8 +128,10 @@ real cmap_dihs(int                 nbonds,
                const struct t_pbc* pbc,
                real gmx_unused lambda,
                real gmx_unused* dvdlambda,
-               const t_mdatoms gmx_unused* md,
+               gmx::ArrayRef<const real> /*charge*/,
                t_fcdata gmx_unused* fcd,
+               t_disresdata gmx_unused* disresdata,
+               t_oriresdata gmx_unused* oriresdata,
                int gmx_unused* global_atom_index);
 
 /*! \brief For selecting which flavor of bonded kernel is used for simple bonded types */
@@ -168,18 +173,20 @@ static constexpr inline bool computeEnergyOrVirial(const BondedKernelFlavor flav
  * All pointers should be non-null, except for pbc and g which can be nullptr.
  * \returns the energy or 0 when \p bondedKernelFlavor did not request the energy.
  */
-real calculateSimpleBond(int                 ftype,
-                         int                 numForceatoms,
-                         const t_iatom       forceatoms[],
-                         const t_iparams     forceparams[],
-                         const rvec          x[],
-                         rvec4               f[],
-                         rvec                fshift[],
-                         const struct t_pbc* pbc,
-                         real                lambda,
-                         real*               dvdlambda,
-                         const t_mdatoms*    md,
-                         t_fcdata*           fcd,
+real calculateSimpleBond(int                       ftype,
+                         int                       numForceatoms,
+                         const t_iatom             forceatoms[],
+                         const t_iparams           forceparams[],
+                         const rvec                x[],
+                         rvec4                     f[],
+                         rvec                      fshift[],
+                         const struct t_pbc*       pbc,
+                         real                      lambda,
+                         real*                     dvdlambda,
+                         gmx::ArrayRef<const real> charge,
+                         t_fcdata*                 fcd,
+                         t_disresdata*             disresdata,
+                         t_oriresdata*             oriresdata,
                          int gmx_unused*    global_atom_index,
                          BondedKernelFlavor bondedKernelFlavor);
 
index d95867cf7d2cdf7dceba975f07782c7100d6df28..e22a49ba95bc847dfe3326525b8ea134f5cbbf62 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/mdtypes/commrec.h"
 #include "gromacs/mdtypes/fcdata.h"
 #include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/state.h"
 #include "gromacs/pbcutil/ishift.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/gmxassert.h"
@@ -68,7 +70,7 @@
 #include "gromacs/utility/smalloc.h"
 
 void init_disres(FILE*                 fplog,
-                 const gmx_mtop_t*     mtop,
+                 const gmx_mtop_t&     mtop,
                  t_inputrec*           ir,
                  DisResRunMode         disResRunMode,
                  DDRole                ddRole,
@@ -79,11 +81,9 @@ void init_disres(FILE*                 fplog,
                  t_state*              state,
                  gmx_bool              bIsREMD)
 {
-    int                  fa, nmol, npair, np;
-    history_t*           hist;
-    gmx_mtop_ilistloop_t iloop;
-    char*                ptr;
-    int                  type_min, type_max;
+    history_t* hist;
+    char*      ptr;
+    int        type_min, type_max;
 
     if (gmx_mtop_ftype_count(mtop, F_DISRES) == 0)
     {
@@ -135,10 +135,10 @@ void init_disres(FILE*                 fplog,
     dd->npair = 0;
     type_min  = INT_MAX;
     type_max  = 0;
-    iloop     = gmx_mtop_ilistloop_init(mtop);
-    while (const InteractionLists* il = gmx_mtop_ilistloop_next(iloop, &nmol))
+    for (const auto il : IListRange(mtop))
     {
-        if (nmol > 1 && !(*il)[F_DISRES].empty() && ir->eDisre != edrEnsemble)
+        if (il.nmol() > 1 && !il.list()[F_DISRES].empty()
+            && ir->eDisre != DistanceRestraintRefinement::Ensemble)
         {
             gmx_fatal(FARGS,
                       "NMR distance restraints with multiple copies of the same molecule are "
@@ -147,19 +147,17 @@ void init_disres(FILE*                 fplog,
                       "a restraint potential (bonds type 10) instead.");
         }
 
-        np = 0;
-        for (fa = 0; fa < (*il)[F_DISRES].size(); fa += 3)
+        int np = 0;
+        for (int fa = 0; fa < il.list()[F_DISRES].size(); fa += 3)
         {
-            int type;
-
-            type = (*il)[F_DISRES].iatoms[fa];
+            int type = il.list()[F_DISRES].iatoms[fa];
 
             np++;
-            npair = mtop->ffparams.iparams[type].disres.npair;
+            int npair = mtop.ffparams.iparams[type].disres.npair;
             if (np == npair)
             {
-                dd->nres += (ir->eDisre == edrEnsemble ? 1 : nmol);
-                dd->npair += nmol * npair;
+                dd->nres += (ir->eDisre == DistanceRestraintRefinement::Ensemble ? 1 : il.nmol());
+                dd->npair += il.nmol() * npair;
                 np = 0;
 
                 type_min = std::min(type_min, type);
@@ -199,12 +197,11 @@ void init_disres(FILE*                 fplog,
 
         hist = &state->hist;
         /* Set the "history lack" factor to 1 */
-        state->flags |= (1 << estDISRE_INITF);
+        state->flags |= enumValueToBitMask(StateEntry::DisreInitF);
         hist->disre_initf = 1.0;
         /* Allocate space for the r^-3 time averages */
-        state->flags |= (1 << estDISRE_RM3TAV);
-        hist->ndisrepairs = dd->npair;
-        snew(hist->disre_rm3tav, hist->ndisrepairs);
+        state->flags |= enumValueToBitMask(StateEntry::DisreRm3Tav);
+        hist->disre_rm3tav.resize(dd->npair);
     }
     /* Allocate space for a copy of rm3tav,
      * so we can call do_force without modifying the state.
@@ -245,7 +242,8 @@ void init_disres(FILE*                 fplog,
             gmx_fatal(FARGS,
                       "GMX_DISRE_ENSEMBLE_SIZE (%d) is not equal to 1 or the number of systems "
                       "(option -multidir) %d",
-                      dd->nsystems, ms->numSimulations_);
+                      dd->nsystems,
+                      ms->numSimulations_);
         }
         if (fplog)
         {
@@ -278,8 +276,7 @@ void init_disres(FILE*                 fplog,
     {
         if (fplog)
         {
-            fprintf(fplog, "There are %d distance restraints involving %d atom pairs\n", dd->nres,
-                    dd->npair);
+            fprintf(fplog, "There are %d distance restraints involving %d atom pairs\n", dd->nres, dd->npair);
         }
         /* Have to avoid g_disre de-referencing cr blindly, mdrun not
          * doing consistency checks for ensemble-averaged distance
@@ -303,7 +300,7 @@ void calc_disres_R_6(const t_commrec*      cr,
                      const rvec            x[],
                      const t_pbc*          pbc,
                      t_disresdata*         dd,
-                     history_t*            hist)
+                     const history_t*      hist)
 {
     rvec     dx;
     real *   rt, *rm3tav, *Rtl_6, *Rt_6, *Rtav_6;
@@ -415,48 +412,47 @@ void calc_disres_R_6(const t_commrec*      cr,
     dd->sumviol = 0;
 }
 
-real ta_disres(int             nfa,
-               const t_iatom   forceatoms[],
-               const t_iparams ip[],
-               const rvec      x[],
-               rvec4           f[],
-               rvec            fshift[],
-               const t_pbc*    pbc,
+real ta_disres(int              nfa,
+               const t_iatom*   forceatoms,
+               const t_iparams* ip,
+               const rvec*      x,
+               rvec4*           f,
+               rvec*            fshift,
+               const t_pbc*     pbc,
                real gmx_unused lambda,
                real gmx_unused* dvdlambda,
-               const t_mdatoms gmx_unused* md,
-               t_fcdata*                   fcd,
+               gmx::ArrayRef<const real> /*charge*/,
+               t_fcdata gmx_unused* fcd,
+               t_disresdata*        disresdata,
+               t_oriresdata gmx_unused* oriresdata,
                int gmx_unused* global_atom_index)
 {
     const real seven_three = 7.0 / 3.0;
 
-    rvec          dx;
-    real          weight_rt_1;
-    real          smooth_fc, Rt, Rtav, rt2, *Rtl_6, *Rt_6, *Rtav_6;
-    real          k0, f_scal = 0, fmax_scal, fk_scal, fij;
-    real          tav_viol, instant_viol, mixed_viol, violtot, vtot;
-    real          tav_viol_Rtav7, instant_viol_Rtav7;
-    real          up1, up2, low;
-    gmx_bool      bConservative, bMixed, bViolation;
-    t_disresdata* dd;
-    int           dr_weighting;
-    gmx_bool      dr_bMixed;
-
-    dd           = fcd->disres;
-    dr_weighting = dd->dr_weighting;
-    dr_bMixed    = dd->dr_bMixed;
-    Rtl_6        = dd->Rtl_6;
-    Rt_6         = dd->Rt_6;
-    Rtav_6       = dd->Rtav_6;
+    rvec     dx;
+    real     weight_rt_1;
+    real     smooth_fc, Rt, Rtav, rt2, *Rtl_6, *Rt_6, *Rtav_6;
+    real     k0, f_scal = 0, fmax_scal, fk_scal, fij;
+    real     tav_viol, instant_viol, mixed_viol, violtot, vtot;
+    real     tav_viol_Rtav7, instant_viol_Rtav7;
+    real     up1, up2, low;
+    gmx_bool bConservative, bMixed, bViolation;
+    gmx_bool dr_bMixed;
+
+    DistanceRestraintWeighting dr_weighting = disresdata->dr_weighting;
+    dr_bMixed                               = disresdata->dr_bMixed;
+    Rtl_6                                   = disresdata->Rtl_6;
+    Rt_6                                    = disresdata->Rt_6;
+    Rtav_6                                  = disresdata->Rtav_6;
 
     tav_viol = instant_viol = mixed_viol = tav_viol_Rtav7 = instant_viol_Rtav7 = 0;
 
-    smooth_fc = dd->dr_fc;
-    if (dd->dr_tau != 0)
+    smooth_fc = disresdata->dr_fc;
+    if (disresdata->dr_tau != 0)
     {
         /* scaling factor to smoothly turn on the restraint forces *
          * when using time averaging                               */
-        smooth_fc *= (1.0 - dd->exp_min_t_tau);
+        smooth_fc *= (1.0 - disresdata->exp_min_t_tau);
     }
 
     violtot = 0;
@@ -464,7 +460,7 @@ real ta_disres(int             nfa,
 
     /* 'loop' over all atom pairs (pair_nr=fa/3) involved in restraints, *
      * the total number of atoms pairs is nfa/3                          */
-    int faOffset = static_cast<int>(forceatoms - dd->forceatomsStart);
+    int faOffset = static_cast<int>(forceatoms - disresdata->forceatomsStart);
     for (int fa = 0; fa < nfa; fa += 3)
     {
         int type  = forceatoms[fa];
@@ -474,12 +470,12 @@ real ta_disres(int             nfa,
         low       = ip[type].disres.low;
         k0        = smooth_fc * ip[type].disres.kfac;
 
-        int res = type - dd->type_min;
+        int res = type - disresdata->type_min;
 
         /* save some flops when there is only one pair */
         if (ip[type].disres.type != 2)
         {
-            bConservative = (dr_weighting == edrwConservative) && (npair > 1);
+            bConservative = (dr_weighting == DistanceRestraintWeighting::Conservative) && (npair > 1);
             bMixed        = dr_bMixed;
             Rt            = gmx::invsixthroot(Rt_6[res]);
             Rtav          = gmx::invsixthroot(Rtav_6[res]);
@@ -588,7 +584,7 @@ real ta_disres(int             nfa,
             int pair = (faOffset + fa) / 3;
             int ai   = forceatoms[fa + 1];
             int aj   = forceatoms[fa + 2];
-            int ki   = CENTRAL;
+            int ki   = gmx::c_centralShiftIndex;
             if (pbc)
             {
                 ki = pbc_dx_aiuc(pbc, x[ai], x[aj], dx);
@@ -605,12 +601,14 @@ real ta_disres(int             nfa,
             {
                 if (!dr_bMixed)
                 {
-                    weight_rt_1 *= std::pow(dd->rm3tav[pair], seven_three);
+                    weight_rt_1 *= std::pow(disresdata->rm3tav[pair], seven_three);
                 }
                 else
                 {
-                    weight_rt_1 *= tav_viol_Rtav7 * std::pow(dd->rm3tav[pair], seven_three)
-                                   + instant_viol_Rtav7 / (dd->rt[pair] * gmx::power6(dd->rt[pair]));
+                    weight_rt_1 *=
+                            tav_viol_Rtav7 * std::pow(disresdata->rm3tav[pair], seven_three)
+                            + instant_viol_Rtav7
+                                      / (disresdata->rt[pair] * gmx::power6(disresdata->rt[pair]));
                 }
             }
 
@@ -625,14 +623,14 @@ real ta_disres(int             nfa,
                 if (fshift)
                 {
                     fshift[ki][m] += fij;
-                    fshift[CENTRAL][m] -= fij;
+                    fshift[gmx::c_centralShiftIndex][m] -= fij;
                 }
             }
         }
     }
 
 #pragma omp atomic
-    dd->sumviol += violtot;
+    disresdata->sumviol += violtot;
 
     /* Return energy */
     return vtot;
index 7144dd0f125d71e60fd6f5501d1d97f64150c698..34aaba06b7690af53cfeb70b520aa92f713fc174 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ struct gmx_multisim_t;
 class history_t;
 struct t_commrec;
 struct t_disresdata;
+struct t_oriresdata;
 struct t_fcdata;
 struct t_inputrec;
 struct t_pbc;
@@ -63,6 +64,12 @@ class t_state;
 enum class DDRole;
 enum class NumRanks;
 
+namespace gmx
+{
+template<typename>
+class ArrayRef;
+} // namespace gmx
+
 //! Whether distance restraints are called from mdrun or from an analysis tool
 enum class DisResRunMode
 {
@@ -81,7 +88,7 @@ enum class DisResRunMode
  * must differ according to whether REMD is active.
  */
 void init_disres(FILE*                 fplog,
-                 const gmx_mtop_t*     mtop,
+                 const gmx_mtop_t&     mtop,
                  t_inputrec*           ir,
                  DisResRunMode         disResRunMode,
                  DDRole                ddRole,
@@ -103,21 +110,23 @@ void calc_disres_R_6(const t_commrec*      cr,
                      const rvec*           x,
                      const t_pbc*          pbc,
                      t_disresdata*         disresdata,
-                     history_t*            hist);
+                     const history_t*      hist);
 
 //! Calculates the distance restraint forces, return the potential.
-real ta_disres(int              nfa,
-               const t_iatom    forceatoms[],
-               const t_iparams  ip[],
-               const rvec       x[],
-               rvec4            f[],
-               rvec             fshift[],
-               const t_pbc*     pbc,
-               real             lambda,
-               real*            dvdlambda,
-               const t_mdatoms* md,
-               t_fcdata*        fcdata,
-               int*             global_atom_index);
+real ta_disres(int                       nfa,
+               const t_iatom*            forceatoms,
+               const t_iparams*          ip,
+               const rvec*               x,
+               rvec4*                    f,
+               rvec*                     fshift,
+               const t_pbc*              pbc,
+               real                      lambda,
+               real*                     dvdlambda,
+               gmx::ArrayRef<const real> charge,
+               t_fcdata gmx_unused* fcd,
+               t_disresdata*        disresdata,
+               t_oriresdata gmx_unused* oriresdata,
+               int*                     global_atom_index);
 
 //! Copies the new time averages that have been calculated in calc_disres_R_6.
 void update_disres_history(const t_disresdata& disresdata, history_t* hist);
index 1cfeed429d2e92e84a4019d9366ab9361cc81fd7..41ad20d42a58b04a1c754015da0fef7a1dc80117 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_LISTED_FORCES_GPUBONDED_H
 #define GMX_LISTED_FORCES_GPUBONDED_H
 
+#include <memory>
+
 #include "gromacs/gpu_utils/devicebuffer_datatype.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/idef.h"
-#include "gromacs/utility/classhelpers.h"
 
 class DeviceContext;
 class DeviceStream;
@@ -198,7 +199,7 @@ public:
 
 private:
     class Impl;
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index ff6232572373ab96a699cf5bd32acb599e548dbf..0e3f2cb54cadc06ffeaf4fb0c53a5a6d8ad2f61c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "config.h"
 
+#include <algorithm>
 #include <string>
 
 #include "gromacs/listed_forces/gpubonded.h"
@@ -58,21 +59,16 @@ namespace gmx
 //! Returns whether there are any interactions in ilists suitable for a GPU.
 static bool someInteractionsCanRunOnGpu(const InteractionLists& ilists)
 {
-    for (int fType : fTypesOnGpu)
-    {
-        if (!ilists[fType].iatoms.empty())
-        {
-            // Perturbation is not implemented in the GPU bonded
-            // kernels. If all the interactions were actually
-            // perturbed, then that will be detected later on each
-            // domain, and work will never run on the GPU. This is
-            // very unlikely to occur, and has little run-time cost,
-            // so we don't complicate the code by catering for it
-            // here.
-            return true;
-        }
-    }
-    return false;
+    // Perturbation is not implemented in the GPU bonded
+    // kernels. If all the interactions were actually
+    // perturbed, then that will be detected later on each
+    // domain, and work will never run on the GPU. This is
+    // very unlikely to occur, and has little run-time cost,
+    // so we don't complicate the code by catering for it
+    // here.
+    return std::any_of(fTypesOnGpu.begin(), fTypesOnGpu.end(), [ilists](int fType) {
+        return !ilists[fType].iatoms.empty();
+    });
 }
 
 //! Returns whether there are any bonded interactions in the global topology suitable for a GPU.
@@ -124,6 +120,10 @@ bool buildSupportsGpuBondeds(std::string* error)
     {
         errorReasons.emplace_back("not supported with OpenCL build of GROMACS");
     }
+    if (GMX_GPU_SYCL)
+    {
+        errorReasons.emplace_back("not supported with SYCL build of GROMACS");
+    }
     else if (!GMX_GPU)
     {
         errorReasons.emplace_back("not supported with CPU-only build of GROMACS");
index 19c8762ee76d017e23e826e6ec01bddaea13a0df..c5fbd00e4669d0b46f918bb250fdd3236e4d4c73 100644 (file)
@@ -78,9 +78,10 @@ GpuBonded::Impl::Impl(const gmx_ffparams_t& ffparams,
     GMX_RELEASE_ASSERT(deviceStream.isValid(),
                        "Can't run GPU version of bonded forces in stream that is not valid.");
 
-    static_assert(c_threadsPerBlock >= SHIFTS,
-                  "Threads per block in GPU bonded must be >= SHIFTS for the virial kernel "
-                  "(calcVir=true)");
+    static_assert(
+            c_threadsPerBlock >= c_numShiftVectors,
+            "Threads per block in GPU bonded must be >= c_numShiftVectors for the virial kernel "
+            "(calcVir=true)");
 
     wcycle_ = wcycle;
 
@@ -88,8 +89,13 @@ GpuBonded::Impl::Impl(const gmx_ffparams_t& ffparams,
     // This could be an async transfer (if the source is pinned), so
     // long as it uses the same stream as the kernels and we are happy
     // to consume additional pinned pages.
-    copyToDeviceBuffer(&d_forceParams_, ffparams.iparams.data(), 0, ffparams.numTypes(),
-                       deviceStream_, GpuApiCallBehavior::Sync, nullptr);
+    copyToDeviceBuffer(&d_forceParams_,
+                       ffparams.iparams.data(),
+                       0,
+                       ffparams.numTypes(),
+                       deviceStream_,
+                       GpuApiCallBehavior::Sync,
+                       nullptr);
     vTot_.resize(F_NRE);
     allocateDeviceBuffer(&d_vTot_, F_NRE, deviceContext_);
     clearDeviceBufferAsync(&d_vTot_, 0, F_NRE, deviceStream_);
@@ -116,7 +122,7 @@ GpuBonded::Impl::Impl(const gmx_ffparams_t& ffparams,
     kernelLaunchConfig_.gridSize[1]  = 1;
     kernelLaunchConfig_.gridSize[2]  = 1;
     kernelLaunchConfig_.sharedMemorySize =
-            SHIFTS * sizeof(float3) + (c_threadsPerBlock / warp_size) * 3 * sizeof(float);
+            c_numShiftVectors * sizeof(float3) + (c_threadsPerBlock / warp_size) * 3 * sizeof(float);
 }
 
 GpuBonded::Impl::~Impl()
@@ -232,11 +238,16 @@ void GpuBonded::Impl::updateInteractionListsAndDeviceBuffers(ArrayRef<const int>
         {
             t_ilist& d_iList = d_iLists_[fType];
 
-            reallocateDeviceBuffer(&d_iList.iatoms, iList.size(), &d_iList.nr, &d_iList.nalloc,
-                                   deviceContext_);
+            reallocateDeviceBuffer(
+                    &d_iList.iatoms, iList.size(), &d_iList.nr, &d_iList.nalloc, deviceContext_);
 
-            copyToDeviceBuffer(&d_iList.iatoms, iList.iatoms.data(), 0, iList.size(), deviceStream_,
-                               GpuApiCallBehavior::Async, nullptr);
+            copyToDeviceBuffer(&d_iList.iatoms,
+                               iList.iatoms.data(),
+                               0,
+                               iList.size(),
+                               deviceStream_,
+                               GpuApiCallBehavior::Async,
+                               nullptr);
         }
         kernelParams_.fTypesOnGpu[fTypesCounter]    = fType;
         kernelParams_.numFTypeIAtoms[fTypesCounter] = iList.size();
@@ -300,11 +311,11 @@ void GpuBonded::Impl::launchEnergyTransfer()
     GMX_ASSERT(haveInteractions_,
                "No GPU bonded interactions, so no energies will be computed, so transfer should "
                "not be called");
-    wallcycle_sub_start_nocount(wcycle_, ewcsLAUNCH_GPU_BONDED);
+    wallcycle_sub_start_nocount(wcycle_, WallCycleSubCounter::LaunchGpuBonded);
     // TODO add conditional on whether there has been any compute (and make sure host buffer doesn't contain garbage)
     float* h_vTot = vTot_.data();
     copyFromDeviceBuffer(h_vTot, &d_vTot_, 0, F_NRE, deviceStream_, GpuApiCallBehavior::Async, nullptr);
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_GPU_BONDED);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchGpuBonded);
 }
 
 void GpuBonded::Impl::waitAccumulateEnergyTerms(gmx_enerdata_t* enerd)
@@ -313,10 +324,10 @@ void GpuBonded::Impl::waitAccumulateEnergyTerms(gmx_enerdata_t* enerd)
                "No GPU bonded interactions, so no energies will be computed or transferred, so "
                "accumulation should not occur");
 
-    wallcycle_start(wcycle_, ewcWAIT_GPU_BONDED);
+    wallcycle_start(wcycle_, WallCycleCounter::WaitGpuBonded);
     cudaError_t stat = cudaStreamSynchronize(deviceStream_.stream());
     CU_RET_ERR(stat, "D2H transfer of bonded energies failed");
-    wallcycle_stop(wcycle_, ewcWAIT_GPU_BONDED);
+    wallcycle_stop(wcycle_, WallCycleCounter::WaitGpuBonded);
 
     for (int fType : fTypesOnGpu)
     {
@@ -329,17 +340,17 @@ void GpuBonded::Impl::waitAccumulateEnergyTerms(gmx_enerdata_t* enerd)
     // Note: We do not support energy groups here
     gmx_grppairener_t* grppener = &enerd->grpp;
     GMX_RELEASE_ASSERT(grppener->nener == 1, "No energy group support for bondeds on the GPU");
-    grppener->ener[egLJ14][0] += vTot_[F_LJ14];
-    grppener->ener[egCOUL14][0] += vTot_[F_COUL14];
+    grppener->energyGroupPairTerms[NonBondedEnergyTerms::LJ14][0] += vTot_[F_LJ14];
+    grppener->energyGroupPairTerms[NonBondedEnergyTerms::Coulomb14][0] += vTot_[F_COUL14];
 }
 
 void GpuBonded::Impl::clearEnergies()
 {
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start_nocount(wcycle_, ewcsLAUNCH_GPU_BONDED);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start_nocount(wcycle_, WallCycleSubCounter::LaunchGpuBonded);
     clearDeviceBufferAsync(&d_vTot_, 0, F_NRE, deviceStream_);
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_GPU_BONDED);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchGpuBonded);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
 // ---- GpuBonded
index 0253a9b9e6e04fa4f4580a666e8ad29f5a071e0b..1537c58d58b653252441cfe63547f3c06f527ade 100644 (file)
@@ -132,10 +132,10 @@ __device__ void bonds_gpu(const int       i,
             float3 fij = fbond * dx;
             atomicAdd(&gm_f[ai], fij);
             atomicAdd(&gm_f[aj], -fij);
-            if (calcVir && ki != CENTRAL)
+            if (calcVir && ki != gmx::c_centralShiftIndex)
             {
                 atomicAdd(&sm_fShiftLoc[ki], fij);
-                atomicAdd(&sm_fShiftLoc[CENTRAL], -fij);
+                atomicAdd(&sm_fShiftLoc[gmx::c_centralShiftIndex], -fij);
             }
         }
     }
@@ -186,13 +186,16 @@ __device__ void angles_gpu(const int       i,
         float  cos_theta;
         int    t1;
         int    t2;
-        float  theta = bond_angle_gpu<calcVir>(gm_xq[ai], gm_xq[aj], gm_xq[ak], pbcAiuc, &r_ij,
-                                              &r_kj, &cos_theta, &t1, &t2);
+        float  theta = bond_angle_gpu<calcVir>(
+                gm_xq[ai], gm_xq[aj], gm_xq[ak], pbcAiuc, &r_ij, &r_kj, &cos_theta, &t1, &t2);
 
         float va;
         float dVdt;
         harmonic_gpu(d_forceparams[type].harmonic.krA,
-                     d_forceparams[type].harmonic.rA * CUDA_DEG2RAD_F, theta, &va, &dVdt);
+                     d_forceparams[type].harmonic.rA * CUDA_DEG2RAD_F,
+                     theta,
+                     &va,
+                     &dVdt);
 
         if (calcEner)
         {
@@ -225,7 +228,7 @@ __device__ void angles_gpu(const int       i,
             if (calcVir)
             {
                 atomicAdd(&sm_fShiftLoc[t1], f_i);
-                atomicAdd(&sm_fShiftLoc[CENTRAL], f_j);
+                atomicAdd(&sm_fShiftLoc[gmx::c_centralShiftIndex], f_j);
                 atomicAdd(&sm_fShiftLoc[t2], f_k);
             }
         }
@@ -261,8 +264,8 @@ __device__ void urey_bradley_gpu(const int       i,
         float  cos_theta;
         int    t1;
         int    t2;
-        float  theta = bond_angle_gpu<calcVir>(gm_xq[ai], gm_xq[aj], gm_xq[ak], pbcAiuc, &r_ij,
-                                              &r_kj, &cos_theta, &t1, &t2);
+        float  theta = bond_angle_gpu<calcVir>(
+                gm_xq[ai], gm_xq[aj], gm_xq[ak], pbcAiuc, &r_ij, &r_kj, &cos_theta, &t1, &t2);
 
         float va;
         float dVdt;
@@ -307,7 +310,7 @@ __device__ void urey_bradley_gpu(const int       i,
             if (calcVir)
             {
                 atomicAdd(&sm_fShiftLoc[t1], f_i);
-                atomicAdd(&sm_fShiftLoc[CENTRAL], f_j);
+                atomicAdd(&sm_fShiftLoc[gmx::c_centralShiftIndex], f_j);
                 atomicAdd(&sm_fShiftLoc[t2], f_k);
             }
         }
@@ -326,10 +329,10 @@ __device__ void urey_bradley_gpu(const int       i,
             atomicAdd(&gm_f[ai], fik);
             atomicAdd(&gm_f[ak], -fik);
 
-            if (calcVir && ki != CENTRAL)
+            if (calcVir && ki != gmx::c_centralShiftIndex)
             {
                 atomicAdd(&sm_fShiftLoc[ki], fik);
-                atomicAdd(&sm_fShiftLoc[CENTRAL], -fik);
+                atomicAdd(&sm_fShiftLoc[gmx::c_centralShiftIndex], -fik);
             }
         }
     }
@@ -429,7 +432,7 @@ __device__ static void do_dih_fup_gpu(const int      i,
             int    t3 = pbcDxAiuc<calcVir>(pbcAiuc, gm_xq[l], gm_xq[j], dx_jl);
 
             atomicAdd(&sm_fShiftLoc[t1], f_i);
-            atomicAdd(&sm_fShiftLoc[CENTRAL], -f_j);
+            atomicAdd(&sm_fShiftLoc[gmx::c_centralShiftIndex], -f_j);
             atomicAdd(&sm_fShiftLoc[t2], -f_k);
             atomicAdd(&sm_fShiftLoc[t3], f_l);
         }
@@ -463,21 +466,25 @@ __device__ void pdihs_gpu(const int       i,
         int    t1;
         int    t2;
         int    t3;
-        float  phi = dih_angle_gpu<calcVir>(gm_xq[ai], gm_xq[aj], gm_xq[ak], gm_xq[al], pbcAiuc,
-                                           &r_ij, &r_kj, &r_kl, &m, &n, &t1, &t2, &t3);
+        float  phi = dih_angle_gpu<calcVir>(
+                gm_xq[ai], gm_xq[aj], gm_xq[ak], gm_xq[al], pbcAiuc, &r_ij, &r_kj, &r_kl, &m, &n, &t1, &t2, &t3);
 
         float vpd;
         float ddphi;
-        dopdihs_gpu(d_forceparams[type].pdihs.cpA, d_forceparams[type].pdihs.phiA,
-                    d_forceparams[type].pdihs.mult, phi, &vpd, &ddphi);
+        dopdihs_gpu(d_forceparams[type].pdihs.cpA,
+                    d_forceparams[type].pdihs.phiA,
+                    d_forceparams[type].pdihs.mult,
+                    phi,
+                    &vpd,
+                    &ddphi);
 
         if (calcEner)
         {
             *vtot_loc += vpd;
         }
 
-        do_dih_fup_gpu<calcVir>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, gm_f, sm_fShiftLoc,
-                                pbcAiuc, gm_xq, t1, t2, t3);
+        do_dih_fup_gpu<calcVir>(
+                ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, gm_f, sm_fShiftLoc, pbcAiuc, gm_xq, t1, t2, t3);
     }
 }
 
@@ -510,8 +517,8 @@ __device__ void rbdihs_gpu(const int       i,
         int    t1;
         int    t2;
         int    t3;
-        float  phi = dih_angle_gpu<calcVir>(gm_xq[ai], gm_xq[aj], gm_xq[ak], gm_xq[al], pbcAiuc,
-                                           &r_ij, &r_kj, &r_kl, &m, &n, &t1, &t2, &t3);
+        float  phi = dih_angle_gpu<calcVir>(
+                gm_xq[ai], gm_xq[aj], gm_xq[ak], gm_xq[al], pbcAiuc, &r_ij, &r_kj, &r_kl, &m, &n, &t1, &t2, &t3);
 
         /* Change to polymer convention */
         if (phi < c0)
@@ -576,8 +583,8 @@ __device__ void rbdihs_gpu(const int       i,
 
         ddphi = -ddphi * sin_phi;
 
-        do_dih_fup_gpu<calcVir>(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, gm_f, sm_fShiftLoc,
-                                pbcAiuc, gm_xq, t1, t2, t3);
+        do_dih_fup_gpu<calcVir>(
+                ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n, gm_f, sm_fShiftLoc, pbcAiuc, gm_xq, t1, t2, t3);
         if (calcEner)
         {
             *vtot_loc += v;
@@ -625,8 +632,8 @@ __device__ void idihs_gpu(const int       i,
         int    t1;
         int    t2;
         int    t3;
-        float  phi = dih_angle_gpu<calcVir>(gm_xq[ai], gm_xq[aj], gm_xq[ak], gm_xq[al], pbcAiuc,
-                                           &r_ij, &r_kj, &r_kl, &m, &n, &t1, &t2, &t3);
+        float  phi = dih_angle_gpu<calcVir>(
+                gm_xq[ai], gm_xq[aj], gm_xq[ak], gm_xq[al], pbcAiuc, &r_ij, &r_kj, &r_kl, &m, &n, &t1, &t2, &t3);
 
         /* phi can jump if phi0 is close to Pi/-Pi, which will cause huge
          * force changes if we just apply a normal harmonic.
@@ -646,8 +653,8 @@ __device__ void idihs_gpu(const int       i,
 
         float ddphi = -kA * dp;
 
-        do_dih_fup_gpu<calcVir>(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, gm_f, sm_fShiftLoc,
-                                pbcAiuc, gm_xq, t1, t2, t3);
+        do_dih_fup_gpu<calcVir>(
+                ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n, gm_f, sm_fShiftLoc, pbcAiuc, gm_xq, t1, t2, t3);
 
         if (calcEner)
         {
@@ -702,10 +709,10 @@ __device__ void pairs_gpu(const int       i,
         /* Add the forces */
         atomicAdd(&gm_f[ai], f);
         atomicAdd(&gm_f[aj], -f);
-        if (calcVir && fshift_index != CENTRAL)
+        if (calcVir && fshift_index != gmx::c_centralShiftIndex)
         {
             atomicAdd(&sm_fShiftLoc[fshift_index], f);
-            atomicAdd(&sm_fShiftLoc[CENTRAL], -f);
+            atomicAdd(&sm_fShiftLoc[gmx::c_centralShiftIndex], -f);
         }
 
         if (calcEner)
@@ -731,11 +738,11 @@ __global__ void exec_kernel_gpu(BondedCudaKernelParameters kernelParams)
     extern __shared__ char sm_dynamicShmem[];
     char*                  sm_nextSlotPtr = sm_dynamicShmem;
     float3*                sm_fShiftLoc   = (float3*)sm_nextSlotPtr;
-    sm_nextSlotPtr += SHIFTS * sizeof(float3);
+    sm_nextSlotPtr += c_numShiftVectors * sizeof(float3);
 
     if (calcVir)
     {
-        if (threadIdx.x < SHIFTS)
+        if (threadIdx.x < c_numShiftVectors)
         {
             sm_fShiftLoc[threadIdx.x] = make_float3(0.0f, 0.0f, 0.0f);
         }
@@ -761,41 +768,84 @@ __global__ void exec_kernel_gpu(BondedCudaKernelParameters kernelParams)
             switch (fType)
             {
                 case F_BONDS:
-                    bonds_gpu<calcVir, calcEner>(fTypeTid, &vtot_loc, numBonds, iatoms,
-                                                 kernelParams.d_forceParams, kernelParams.d_xq,
-                                                 kernelParams.d_f, sm_fShiftLoc, kernelParams.pbcAiuc);
+                    bonds_gpu<calcVir, calcEner>(fTypeTid,
+                                                 &vtot_loc,
+                                                 numBonds,
+                                                 iatoms,
+                                                 kernelParams.d_forceParams,
+                                                 kernelParams.d_xq,
+                                                 kernelParams.d_f,
+                                                 sm_fShiftLoc,
+                                                 kernelParams.pbcAiuc);
                     break;
                 case F_ANGLES:
-                    angles_gpu<calcVir, calcEner>(
-                            fTypeTid, &vtot_loc, numBonds, iatoms, kernelParams.d_forceParams,
-                            kernelParams.d_xq, kernelParams.d_f, sm_fShiftLoc, kernelParams.pbcAiuc);
+                    angles_gpu<calcVir, calcEner>(fTypeTid,
+                                                  &vtot_loc,
+                                                  numBonds,
+                                                  iatoms,
+                                                  kernelParams.d_forceParams,
+                                                  kernelParams.d_xq,
+                                                  kernelParams.d_f,
+                                                  sm_fShiftLoc,
+                                                  kernelParams.pbcAiuc);
                     break;
                 case F_UREY_BRADLEY:
-                    urey_bradley_gpu<calcVir, calcEner>(
-                            fTypeTid, &vtot_loc, numBonds, iatoms, kernelParams.d_forceParams,
-                            kernelParams.d_xq, kernelParams.d_f, sm_fShiftLoc, kernelParams.pbcAiuc);
+                    urey_bradley_gpu<calcVir, calcEner>(fTypeTid,
+                                                        &vtot_loc,
+                                                        numBonds,
+                                                        iatoms,
+                                                        kernelParams.d_forceParams,
+                                                        kernelParams.d_xq,
+                                                        kernelParams.d_f,
+                                                        sm_fShiftLoc,
+                                                        kernelParams.pbcAiuc);
                     break;
                 case F_PDIHS:
                 case F_PIDIHS:
-                    pdihs_gpu<calcVir, calcEner>(fTypeTid, &vtot_loc, numBonds, iatoms,
-                                                 kernelParams.d_forceParams, kernelParams.d_xq,
-                                                 kernelParams.d_f, sm_fShiftLoc, kernelParams.pbcAiuc);
+                    pdihs_gpu<calcVir, calcEner>(fTypeTid,
+                                                 &vtot_loc,
+                                                 numBonds,
+                                                 iatoms,
+                                                 kernelParams.d_forceParams,
+                                                 kernelParams.d_xq,
+                                                 kernelParams.d_f,
+                                                 sm_fShiftLoc,
+                                                 kernelParams.pbcAiuc);
                     break;
                 case F_RBDIHS:
-                    rbdihs_gpu<calcVir, calcEner>(
-                            fTypeTid, &vtot_loc, numBonds, iatoms, kernelParams.d_forceParams,
-                            kernelParams.d_xq, kernelParams.d_f, sm_fShiftLoc, kernelParams.pbcAiuc);
+                    rbdihs_gpu<calcVir, calcEner>(fTypeTid,
+                                                  &vtot_loc,
+                                                  numBonds,
+                                                  iatoms,
+                                                  kernelParams.d_forceParams,
+                                                  kernelParams.d_xq,
+                                                  kernelParams.d_f,
+                                                  sm_fShiftLoc,
+                                                  kernelParams.pbcAiuc);
                     break;
                 case F_IDIHS:
-                    idihs_gpu<calcVir, calcEner>(fTypeTid, &vtot_loc, numBonds, iatoms,
-                                                 kernelParams.d_forceParams, kernelParams.d_xq,
-                                                 kernelParams.d_f, sm_fShiftLoc, kernelParams.pbcAiuc);
+                    idihs_gpu<calcVir, calcEner>(fTypeTid,
+                                                 &vtot_loc,
+                                                 numBonds,
+                                                 iatoms,
+                                                 kernelParams.d_forceParams,
+                                                 kernelParams.d_xq,
+                                                 kernelParams.d_f,
+                                                 sm_fShiftLoc,
+                                                 kernelParams.pbcAiuc);
                     break;
                 case F_LJ14:
-                    pairs_gpu<calcVir, calcEner>(
-                            fTypeTid, numBonds, iatoms, kernelParams.d_forceParams,
-                            kernelParams.d_xq, kernelParams.d_f, sm_fShiftLoc, kernelParams.pbcAiuc,
-                            kernelParams.electrostaticsScaleFactor, &vtotVdw_loc, &vtotElec_loc);
+                    pairs_gpu<calcVir, calcEner>(fTypeTid,
+                                                 numBonds,
+                                                 iatoms,
+                                                 kernelParams.d_forceParams,
+                                                 kernelParams.d_xq,
+                                                 kernelParams.d_f,
+                                                 sm_fShiftLoc,
+                                                 kernelParams.pbcAiuc,
+                                                 kernelParams.electrostaticsScaleFactor,
+                                                 &vtotVdw_loc,
+                                                 &vtotElec_loc);
                     break;
             }
             break;
@@ -843,11 +893,11 @@ __global__ void exec_kernel_gpu(BondedCudaKernelParameters kernelParams)
             atomicAdd(vtotElec, sm_vTotElec[warpId]);
         }
     }
-    /* Accumulate shift vectors from shared memory to global memory on the first SHIFTS threads of the block. */
+    /* Accumulate shift vectors from shared memory to global memory on the first c_numShiftVectors threads of the block. */
     if (calcVir)
     {
         __syncthreads();
-        if (threadIdx.x < SHIFTS)
+        if (threadIdx.x < c_numShiftVectors)
         {
             atomicAdd(kernelParams.d_fShift[threadIdx.x], sm_fShiftLoc[threadIdx.x]);
         }
@@ -864,8 +914,8 @@ void GpuBonded::Impl::launchKernel()
     GMX_ASSERT(haveInteractions_,
                "Cannot launch bonded GPU kernels unless bonded GPU work was scheduled");
 
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_GPU_BONDED);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchGpuBonded);
 
     int fTypeRangeEnd = kernelParams_.fTypeRangeEnd[numFTypesOnGpu - 1];
 
@@ -878,11 +928,15 @@ void GpuBonded::Impl::launchKernel()
 
     const auto kernelArgs = prepareGpuKernelArguments(kernelPtr, kernelLaunchConfig_, &kernelParams_);
 
-    launchGpuKernel(kernelPtr, kernelLaunchConfig_, deviceStream_, nullptr,
-                    "exec_kernel_gpu<calcVir, calcEner>", kernelArgs);
+    launchGpuKernel(kernelPtr,
+                    kernelLaunchConfig_,
+                    deviceStream_,
+                    nullptr,
+                    "exec_kernel_gpu<calcVir, calcEner>",
+                    kernelArgs);
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_GPU_BONDED);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchGpuBonded);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
 void GpuBonded::launchKernel(const gmx::StepWorkload& stepWork)
index ee298f5a519c066cec1ff02ded467c2c550c5f3c..85967f1b7f45caa70472ca266741b086630fc894 100644 (file)
@@ -44,6 +44,8 @@
  */
 #include "gmxpre.h"
 
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "listed_forces.h"
 
 #include <cassert>
@@ -64,6 +66,7 @@
 #include "gromacs/mdlib/force.h"
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
 #include "gromacs/mdtypes/commrec.h"
+#include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/mdtypes/fcdata.h"
 #include "gromacs/mdtypes/forceoutput.h"
 #include "gromacs/mdtypes/forcerec.h"
@@ -176,7 +179,7 @@ void ListedForces::setup(const InteractionDefinitions& domainIdef, const int num
     if (idef_->ilsort == ilsortFE_SORTED)
     {
         forceBufferLambda_.resize(numAtomsForce * sizeof(rvec4) / sizeof(real));
-        shiftForceBufferLambda_.resize(SHIFTS);
+        shiftForceBufferLambda_.resize(gmx::c_numShiftVectors);
     }
 }
 
@@ -211,7 +214,7 @@ void zero_thread_output(f_thread_t* f_t)
         }
     }
 
-    for (int i = 0; i < SHIFTS; i++)
+    for (int i = 0; i < gmx::c_numShiftVectors; i++)
     {
         clear_rvec(f_t->fshift[i]);
     }
@@ -219,14 +222,14 @@ void zero_thread_output(f_thread_t* f_t)
     {
         f_t->ener[i] = 0;
     }
-    for (int i = 0; i < egNR; i++)
+    for (int i = 0; i < static_cast<int>(NonBondedEnergyTerms::Count); i++)
     {
         for (int j = 0; j < f_t->grpp.nener; j++)
         {
-            f_t->grpp.ener[i][j] = 0;
+            f_t->grpp.energyGroupPairTerms[i][j] = 0;
         }
     }
-    for (int i = 0; i < efptNR; i++)
+    for (auto i : keysOf(f_t->dvdl))
     {
         f_t->dvdl[i] = 0;
     }
@@ -298,7 +301,7 @@ void reduce_thread_forces(gmx::ArrayRef<gmx::RVec> force, const bonded_threading
 void reduce_thread_output(gmx::ForceWithShiftForces* forceWithShiftForces,
                           real*                      ener,
                           gmx_grppairener_t*         grpp,
-                          real*                      dvdl,
+                          gmx::ArrayRef<real>        dvdl,
                           const bonded_threading_t*  bt,
                           const gmx::StepWorkload&   stepWork)
 {
@@ -319,7 +322,7 @@ void reduce_thread_output(gmx::ForceWithShiftForces* forceWithShiftForces,
 
         if (stepWork.computeVirial)
         {
-            for (int i = 0; i < SHIFTS; i++)
+            for (int i = 0; i < gmx::c_numShiftVectors; i++)
             {
                 for (int t = 1; t < bt->nthreads; t++)
                 {
@@ -336,25 +339,25 @@ void reduce_thread_output(gmx::ForceWithShiftForces* forceWithShiftForces,
                     ener[i] += f_t[t]->ener[i];
                 }
             }
-            for (int i = 0; i < egNR; i++)
+            for (int i = 0; i < static_cast<int>(NonBondedEnergyTerms::Count); i++)
             {
                 for (int j = 0; j < f_t[1]->grpp.nener; j++)
                 {
                     for (int t = 1; t < bt->nthreads; t++)
                     {
-                        grpp->ener[i][j] += f_t[t]->grpp.ener[i][j];
+                        grpp->energyGroupPairTerms[i][j] += f_t[t]->grpp.energyGroupPairTerms[i][j];
                     }
                 }
             }
         }
         if (stepWork.computeDhdl)
         {
-            for (int i = 0; i < efptNR; i++)
+            for (auto i : keysOf(f_t[1]->dvdl))
             {
 
                 for (int t = 1; t < bt->nthreads; t++)
                 {
-                    dvdl[i] += f_t[t]->dvdl[i];
+                    dvdl[static_cast<int>(i)] += f_t[t]->dvdl[i];
                 }
             }
         }
@@ -414,8 +417,8 @@ real calc_one_bond(int                           thread,
                    const t_pbc*                  pbc,
                    gmx_grppairener_t*            grpp,
                    t_nrnb*                       nrnb,
-                   const real*                   lambda,
-                   real*                         dvdl,
+                   gmx::ArrayRef<const real>     lambda,
+                   gmx::ArrayRef<real>           dvdl,
                    const t_mdatoms*              md,
                    t_fcdata*                     fcd,
                    const gmx::StepWorkload&      stepWork,
@@ -428,14 +431,14 @@ real calc_one_bond(int                           thread,
             (idef.ilsort == ilsortFE_SORTED && numNonperturbedInteractions < iatoms.ssize());
     BondedKernelFlavor flavor =
             selectBondedKernelFlavor(stepWork, fr->use_simd_kernels, havePerturbedInteractions);
-    int efptFTYPE;
+    FreeEnergyPerturbationCouplingType efptFTYPE;
     if (IS_RESTRAINT_TYPE(ftype))
     {
-        efptFTYPE = efptRESTRAINT;
+        efptFTYPE = FreeEnergyPerturbationCouplingType::Restraint;
     }
     else
     {
-        efptFTYPE = efptBONDED;
+        efptFTYPE = FreeEnergyPerturbationCouplingType::Bonded;
     }
 
     const int nat1   = interaction_function[ftype].nratoms + 1;
@@ -458,14 +461,40 @@ real calc_one_bond(int                           thread,
                nice to account to its own subtimer, but first
                wallcycle needs to be extended to support calling from
                multiple threads. */
-            v = cmap_dihs(nbn, iatoms.data() + nb0, iparams.data(), &idef.cmap_grid, x, f, fshift,
-                          pbc, lambda[efptFTYPE], &(dvdl[efptFTYPE]), md, fcd, global_atom_index);
+            v = cmap_dihs(nbn,
+                          iatoms.data() + nb0,
+                          iparams.data(),
+                          &idef.cmap_grid,
+                          x,
+                          f,
+                          fshift,
+                          pbc,
+                          lambda[static_cast<int>(efptFTYPE)],
+                          &(dvdl[static_cast<int>(efptFTYPE)]),
+                          gmx::arrayRefFromArray(md->chargeA, md->nr),
+                          fcd,
+                          nullptr,
+                          nullptr,
+                          global_atom_index);
         }
         else
         {
-            v = calculateSimpleBond(ftype, nbn, iatoms.data() + nb0, iparams.data(), x, f, fshift,
-                                    pbc, lambda[efptFTYPE], &(dvdl[efptFTYPE]), md, fcd,
-                                    global_atom_index, flavor);
+            v = calculateSimpleBond(ftype,
+                                    nbn,
+                                    iatoms.data() + nb0,
+                                    iparams.data(),
+                                    x,
+                                    f,
+                                    fshift,
+                                    pbc,
+                                    lambda[static_cast<int>(efptFTYPE)],
+                                    &(dvdl[static_cast<int>(efptFTYPE)]),
+                                    gmx::arrayRefFromArray(md->chargeA, md->nr),
+                                    fcd,
+                                    fcd->disres,
+                                    fcd->orires.get(),
+                                    global_atom_index,
+                                    flavor);
         }
     }
     else
@@ -473,8 +502,26 @@ real calc_one_bond(int                           thread,
         /* TODO The execution time for pairs might be nice to account
            to its own subtimer, but first wallcycle needs to be
            extended to support calling from multiple threads. */
-        do_pairs(ftype, nbn, iatoms.data() + nb0, iparams.data(), x, f, fshift, pbc, lambda, dvdl,
-                 md, fr, havePerturbedInteractions, stepWork, grpp, global_atom_index);
+        do_pairs(ftype,
+                 nbn,
+                 iatoms.data() + nb0,
+                 iparams.data(),
+                 x,
+                 f,
+                 fshift,
+                 pbc,
+                 lambda.data(),
+                 dvdl.data(),
+                 md->chargeA ? gmx::arrayRefFromArray(md->chargeA, md->nr) : gmx::ArrayRef<real>{},
+                 md->chargeB ? gmx::arrayRefFromArray(md->chargeB, md->nr) : gmx::ArrayRef<real>{},
+                 md->bPerturbed ? gmx::arrayRefFromArray(md->bPerturbed, md->nr) : gmx::ArrayRef<bool>(),
+                 gmx::arrayRefFromArray(md->cENER, md->nr),
+                 md->nPerturbed,
+                 fr,
+                 havePerturbedInteractions,
+                 stepWork,
+                 grpp,
+                 global_atom_index);
     }
 
     if (thread == 0)
@@ -497,8 +544,8 @@ static void calcBondedForces(const InteractionDefinitions& idef,
                              rvec*                         fshiftMasterBuffer,
                              gmx_enerdata_t*               enerd,
                              t_nrnb*                       nrnb,
-                             const real*                   lambda,
-                             real*                         dvdl,
+                             gmx::ArrayRef<const real>     lambda,
+                             gmx::ArrayRef<real>           dvdl,
                              const t_mdatoms*              md,
                              t_fcdata*                     fcd,
                              const gmx::StepWorkload&      stepWork,
@@ -511,11 +558,12 @@ static void calcBondedForces(const InteractionDefinitions& idef,
         {
             f_thread_t& threadBuffers = *bt->f_t[thread];
             int         ftype;
-            real *      epot, v;
+            real        v;
             /* thread stuff */
-            rvec*              fshift;
-            real*              dvdlt;
-            gmx_grppairener_t* grpp;
+            rvec*               fshift;
+            gmx::ArrayRef<real> dvdlt;
+            gmx::ArrayRef<real> epot;
+            gmx_grppairener_t*  grpp;
 
             zero_thread_output(&threadBuffers);
 
@@ -545,9 +593,25 @@ static void calcBondedForces(const InteractionDefinitions& idef,
                 if (!ilist.empty() && ftype_is_bonded_potential(ftype))
                 {
                     ArrayRef<const int> iatoms = gmx::makeConstArrayRef(ilist.iatoms);
-                    v = calc_one_bond(thread, ftype, idef, iatoms, idef.numNonperturbedInteractions[ftype],
-                                      bt->workDivision, x, ft, fshift, fr, pbc_null, grpp, nrnb,
-                                      lambda, dvdlt, md, fcd, stepWork, global_atom_index);
+                    v                          = calc_one_bond(thread,
+                                      ftype,
+                                      idef,
+                                      iatoms,
+                                      idef.numNonperturbedInteractions[ftype],
+                                      bt->workDivision,
+                                      x,
+                                      ft,
+                                      fshift,
+                                      fr,
+                                      pbc_null,
+                                      grpp,
+                                      nrnb,
+                                      lambda,
+                                      dvdlt,
+                                      md,
+                                      fcd,
+                                      stepWork,
+                                      global_atom_index);
                     epot[ftype] += v;
                 }
             }
@@ -558,9 +622,9 @@ static void calcBondedForces(const InteractionDefinitions& idef,
 
 bool ListedForces::haveRestraints(const t_fcdata& fcdata) const
 {
-    GMX_ASSERT(fcdata.orires && fcdata.disres, "NMR restraints objects should be set up");
+    GMX_ASSERT(fcdata.disres, "NMR distance restraint object should be set up");
 
-    return (!idef_->il[F_POSRES].empty() || !idef_->il[F_FBPOSRES].empty() || fcdata.orires->nr > 0
+    return (!idef_->il[F_POSRES].empty() || !idef_->il[F_FBPOSRES].empty() || fcdata.orires
             || fcdata.disres->nres > 0);
 }
 
@@ -587,7 +651,7 @@ void calc_listed(struct gmx_wallcycle*         wcycle,
                  const t_pbc*                  pbc,
                  gmx_enerdata_t*               enerd,
                  t_nrnb*                       nrnb,
-                 const real*                   lambda,
+                 gmx::ArrayRef<const real>     lambda,
                  const t_mdatoms*              md,
                  t_fcdata*                     fcd,
                  int*                          global_atom_index,
@@ -597,26 +661,37 @@ void calc_listed(struct gmx_wallcycle*         wcycle,
     {
         gmx::ForceWithShiftForces& forceWithShiftForces = forceOutputs->forceWithShiftForces();
 
-        wallcycle_sub_start(wcycle, ewcsLISTED);
+        wallcycle_sub_start(wcycle, WallCycleSubCounter::Listed);
         /* The dummy array is to have a place to store the dhdl at other values
            of lambda, which will be thrown away in the end */
-        real dvdl[efptNR] = { 0 };
-        calcBondedForces(idef, bt, x, fr, fr->bMolPBC ? pbc : nullptr,
-                         as_rvec_array(forceWithShiftForces.shiftForces().data()), enerd, nrnb,
-                         lambda, dvdl, md, fcd, stepWork, global_atom_index);
-        wallcycle_sub_stop(wcycle, ewcsLISTED);
-
-        wallcycle_sub_start(wcycle, ewcsLISTED_BUF_OPS);
-        reduce_thread_output(&forceWithShiftForces, enerd->term, &enerd->grpp, dvdl, bt, stepWork);
+        gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> dvdl = { 0 };
+        calcBondedForces(idef,
+                         bt,
+                         x,
+                         fr,
+                         fr->bMolPBC ? pbc : nullptr,
+                         as_rvec_array(forceWithShiftForces.shiftForces().data()),
+                         enerd,
+                         nrnb,
+                         lambda,
+                         dvdl,
+                         md,
+                         fcd,
+                         stepWork,
+                         global_atom_index);
+        wallcycle_sub_stop(wcycle, WallCycleSubCounter::Listed);
+
+        wallcycle_sub_start(wcycle, WallCycleSubCounter::ListedBufOps);
+        reduce_thread_output(&forceWithShiftForces, enerd->term.data(), &enerd->grpp, dvdl, bt, stepWork);
 
         if (stepWork.computeDhdl)
         {
-            for (int i = 0; i < efptNR; i++)
+            for (auto i : keysOf(enerd->dvdl_lin))
             {
                 enerd->dvdl_nonlin[i] += dvdl[i];
             }
         }
-        wallcycle_sub_stop(wcycle, ewcsLISTED_BUF_OPS);
+        wallcycle_sub_stop(wcycle, WallCycleSubCounter::ListedBufOps);
     }
 
     /* Copy the sum of violations for the distance restraints from fcd */
@@ -642,7 +717,7 @@ void calc_listed_lambda(const InteractionDefinitions& idef,
                         real*                         epot,
                         gmx::ArrayRef<real>           dvdl,
                         t_nrnb*                       nrnb,
-                        const real*                   lambda,
+                        gmx::ArrayRef<const real>     lambda,
                         const t_mdatoms*              md,
                         t_fcdata*                     fcd,
                         int*                          global_atom_index)
@@ -661,7 +736,8 @@ void calc_listed_lambda(const InteractionDefinitions& idef,
 
     /* We already have the forces, so we use temp buffers here */
     std::fill(forceBufferLambda.begin(), forceBufferLambda.end(), 0.0_real);
-    std::fill(shiftForceBufferLambda.begin(), shiftForceBufferLambda.end(),
+    std::fill(shiftForceBufferLambda.begin(),
+              shiftForceBufferLambda.end(),
               gmx::RVec{ 0.0_real, 0.0_real, 0.0_real });
     rvec4* f      = reinterpret_cast<rvec4*>(forceBufferLambda.data());
     rvec*  fshift = as_rvec_array(shiftForceBufferLambda.data());
@@ -684,9 +760,25 @@ void calc_listed_lambda(const InteractionDefinitions& idef,
 
                 gmx::StepWorkload tempFlags;
                 tempFlags.computeEnergy = true;
-                real v = calc_one_bond(0, ftype, idef, iatomsPerturbed, iatomsPerturbed.ssize(),
-                                       workDivision, x, f, fshift, fr, pbc_null, grpp, nrnb, lambda,
-                                       dvdl.data(), md, fcd, tempFlags, global_atom_index);
+                real v                  = calc_one_bond(0,
+                                       ftype,
+                                       idef,
+                                       iatomsPerturbed,
+                                       iatomsPerturbed.ssize(),
+                                       workDivision,
+                                       x,
+                                       f,
+                                       fshift,
+                                       fr,
+                                       pbc_null,
+                                       grpp,
+                                       nrnb,
+                                       lambda,
+                                       dvdl,
+                                       md,
+                                       fcd,
+                                       tempFlags,
+                                       global_atom_index);
                 epot[ftype] += v;
             }
         }
@@ -703,13 +795,13 @@ void ListedForces::calculate(struct gmx_wallcycle*                     wcycle,
                              gmx::ArrayRefWithPadding<const gmx::RVec> coordinates,
                              gmx::ArrayRef<const gmx::RVec>            xWholeMolecules,
                              t_fcdata*                                 fcdata,
-                             history_t*                                hist,
+                             const history_t*                          hist,
                              gmx::ForceOutputs*                        forceOutputs,
                              const t_forcerec*                         fr,
                              const struct t_pbc*                       pbc,
                              gmx_enerdata_t*                           enerd,
                              t_nrnb*                                   nrnb,
-                             const real*                               lambda,
+                             gmx::ArrayRef<const real>                 lambda,
                              const t_mdatoms*                          md,
                              int*                                      global_atom_index,
                              const gmx::StepWorkload&                  stepWork)
@@ -741,7 +833,7 @@ void ListedForces::calculate(struct gmx_wallcycle*                     wcycle,
            awkward to account to this subtimer properly in the present
            code. We don't test / care much about performance with
            restraints, anyway. */
-        wallcycle_sub_start(wcycle, ewcsRESTRAINTS);
+        wallcycle_sub_start(wcycle, WallCycleSubCounter::Restraints);
 
         if (!idef.il[F_POSRES].empty())
         {
@@ -754,60 +846,84 @@ void ListedForces::calculate(struct gmx_wallcycle*                     wcycle,
         }
 
         /* Do pre force calculation stuff which might require communication */
-        if (fcdata->orires->nr > 0)
+        if (fcdata->orires)
         {
             GMX_ASSERT(!xWholeMolecules.empty(), "Need whole molecules for orienation restraints");
-            enerd->term[F_ORIRESDEV] = calc_orires_dev(
-                    ms, idef.il[F_ORIRES].size(), idef.il[F_ORIRES].iatoms.data(), idef.iparams.data(),
-                    md, xWholeMolecules, x, fr->bMolPBC ? pbc : nullptr, fcdata->orires, hist);
+            enerd->term[F_ORIRESDEV] = calc_orires_dev(ms,
+                                                       idef.il[F_ORIRES].size(),
+                                                       idef.il[F_ORIRES].iatoms.data(),
+                                                       idef.iparams.data(),
+                                                       md,
+                                                       xWholeMolecules,
+                                                       x,
+                                                       fr->bMolPBC ? pbc : nullptr,
+                                                       fcdata->orires.get(),
+                                                       hist);
         }
         if (fcdata->disres->nres > 0)
         {
-            calc_disres_R_6(cr, ms, idef.il[F_DISRES].size(), idef.il[F_DISRES].iatoms.data(), x,
-                            fr->bMolPBC ? pbc : nullptr, fcdata->disres, hist);
+            calc_disres_R_6(cr,
+                            ms,
+                            idef.il[F_DISRES].size(),
+                            idef.il[F_DISRES].iatoms.data(),
+                            x,
+                            fr->bMolPBC ? pbc : nullptr,
+                            fcdata->disres,
+                            hist);
         }
 
-        wallcycle_sub_stop(wcycle, ewcsRESTRAINTS);
+        wallcycle_sub_stop(wcycle, WallCycleSubCounter::Restraints);
     }
 
-    calc_listed(wcycle, idef, threading_.get(), x, forceOutputs, fr, pbc, enerd, nrnb, lambda, md,
-                fcdata, global_atom_index, stepWork);
+    calc_listed(wcycle, idef, threading_.get(), x, forceOutputs, fr, pbc, enerd, nrnb, lambda, md, fcdata, global_atom_index, stepWork);
 
     /* Check if we have to determine energy differences
      * at foreign lambda's.
      */
     if (fepvals->n_lambda > 0 && stepWork.computeDhdl)
     {
-        real dvdl[efptNR] = { 0 };
+        gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> dvdl = { 0 };
         if (!idef.il[F_POSRES].empty())
         {
             posres_wrapper_lambda(wcycle, fepvals, idef, &pbc_full, x, enerd, lambda, fr);
         }
         if (idef.ilsort != ilsortNO_FE)
         {
-            wallcycle_sub_start(wcycle, ewcsLISTED_FEP);
+            wallcycle_sub_start(wcycle, WallCycleSubCounter::ListedFep);
             if (idef.ilsort != ilsortFE_SORTED)
             {
                 gmx_incons("The bonded interactions are not sorted for free energy");
             }
             for (int i = 0; i < 1 + enerd->foreignLambdaTerms.numLambdas(); i++)
             {
-                real lam_i[efptNR];
+                gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> lam_i;
 
                 reset_foreign_enerdata(enerd);
-                for (int j = 0; j < efptNR; j++)
+                for (auto j : keysOf(lam_i))
                 {
-                    lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i - 1]);
+                    lam_i[j] = (i == 0 ? lambda[static_cast<int>(j)] : fepvals->all_lambda[j][i - 1]);
                 }
-                calc_listed_lambda(idef, threading_.get(), x, fr, pbc, forceBufferLambda_,
-                                   shiftForceBufferLambda_, &(enerd->foreign_grpp), enerd->foreign_term,
-                                   dvdl, nrnb, lam_i, md, fcdata, global_atom_index);
-                sum_epot(enerd->foreign_grpp, enerd->foreign_term);
+                calc_listed_lambda(idef,
+                                   threading_.get(),
+                                   x,
+                                   fr,
+                                   pbc,
+                                   forceBufferLambda_,
+                                   shiftForceBufferLambda_,
+                                   &(enerd->foreign_grpp),
+                                   enerd->foreign_term.data(),
+                                   dvdl,
+                                   nrnb,
+                                   lam_i,
+                                   md,
+                                   fcdata,
+                                   global_atom_index);
+                sum_epot(enerd->foreign_grpp, enerd->foreign_term.data());
                 const double dvdlSum = std::accumulate(std::begin(dvdl), std::end(dvdl), 0.);
                 std::fill(std::begin(dvdl), std::end(dvdl), 0.0);
                 enerd->foreignLambdaTerms.accumulate(i, enerd->foreign_term[F_EPOT], dvdlSum);
             }
-            wallcycle_sub_stop(wcycle, ewcsLISTED_FEP);
+            wallcycle_sub_stop(wcycle, WallCycleSubCounter::ListedFep);
         }
     }
 }
index c044baf11730375ab30db3a15b08b902bdfadfb8..34e297b36d5b72a2f1a3ce3585e34d54404f1bbe 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +77,6 @@
 #include "gromacs/math/vectypes.h"
 #include "gromacs/topology/idef.h"
 #include "gromacs/topology/ifunc.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/classhelpers.h"
 
 struct bonded_threading_t;
@@ -94,6 +93,8 @@ struct t_lambda;
 struct t_mdatoms;
 struct t_nrnb;
 class t_state;
+struct t_disresdata;
+struct t_oriresdata;
 
 namespace gmx
 {
@@ -106,18 +107,20 @@ class ArrayRefWithPadding;
 } // namespace gmx
 
 //! Type of CPU function to compute a bonded interaction.
-using BondedFunction = real (*)(int              nbonds,
-                                const t_iatom    iatoms[],
-                                const t_iparams  iparams[],
-                                const rvec       x[],
-                                rvec4            f[],
-                                rvec             fshift[],
-                                const t_pbc*     pbc,
-                                real             lambda,
-                                real*            dvdlambda,
-                                const t_mdatoms* md,
-                                t_fcdata*        fcd,
-                                int*             ddgatindex);
+using BondedFunction = real (*)(int                 nbonds,
+                                const t_iatom       iatoms[],
+                                const t_iparams     iparams[],
+                                const rvec          x[],
+                                rvec4               f[],
+                                rvec                fshift[],
+                                const t_pbc*        pbc,
+                                real                lambda,
+                                gmx::ArrayRef<real> dvdlambda,
+                                const t_mdatoms*    md,
+                                t_fcdata*           fcd,
+                                t_disresdata*       disresdata,
+                                t_oriresdata*       oriresdata,
+                                int*                ddgatindex);
 
 //! Getter for finding a callable CPU function to compute an \c ftype interaction.
 BondedFunction bondedFunction(int ftype);
@@ -193,13 +196,13 @@ public:
                    gmx::ArrayRefWithPadding<const gmx::RVec> coordinates,
                    gmx::ArrayRef<const gmx::RVec>            xWholeMolecules,
                    t_fcdata*                                 fcdata,
-                   history_t*                                hist,
+                   const history_t*                          hist,
                    gmx::ForceOutputs*                        forceOutputs,
                    const t_forcerec*                         fr,
                    const struct t_pbc*                       pbc,
                    gmx_enerdata_t*                           enerd,
                    t_nrnb*                                   nrnb,
-                   const real*                               lambda,
+                   gmx::ArrayRef<const real>                 lambda,
                    const t_mdatoms*                          md,
                    int*                                      global_atom_index,
                    const gmx::StepWorkload&                  stepWork);
index 2e130dcb835930729d9623cb47413bd9a98721eb..9366efcce139683271ec59368361f56457f8a39c 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/alignedallocator.h"
 #include "gromacs/utility/bitmask.h"
 #include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/enumerationhelpers.h"
 
 /* We reduce the force array in blocks of 32 atoms. This is large enough
  * to not cause overhead and 32*sizeof(rvec) is a multiple of the cache-line
@@ -110,14 +111,14 @@ struct f_thread_t
     //! Index to touched blocks
     std::vector<int> block_index;
 
-    //! Shift force array, size SHIFTS
+    //! Shift force array, size c_numShiftVectors
     std::vector<gmx::RVec> fshift;
     //! Energy array
     real ener[F_NRE];
     //! Group pair energy data for pairs
     gmx_grppairener_t grpp;
     //! Free-energy dV/dl output
-    real dvdl[efptNR];
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> dvdl;
 
     GMX_DISALLOW_COPY_MOVE_AND_ASSIGN(f_thread_t);
 };
index f666b5a012ecdb5499348fa29fa67533b631caa9..0eeac68641bfb4e790c32e29c2a67ee40763ca9b 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -316,7 +316,8 @@ static void divide_bondeds_over_threads(bonded_threading_t*           bt,
                 fprintf(debug, "%16s", interaction_function[f].name);
                 for (t = 0; t < numThreads; t++)
                 {
-                    fprintf(debug, " %4d",
+                    fprintf(debug,
+                            " %4d",
                             (bt->workDivision.bound(f, t + 1) - bt->workDivision.bound(f, t))
                                     / (1 + NRAL(f)));
                 }
@@ -342,7 +343,8 @@ static void calc_bonded_reduction_mask(int                           natoms,
                   "You are using %d OpenMP threads, which is larger than GMX_OPENMP_MAX_THREADS "
                   "(%d). Decrease the number of OpenMP threads or rebuild GROMACS with a larger "
                   "value for GMX_OPENMP_MAX_THREADS passed to CMake.",
-                  bondedThreading.nthreads, GMX_OPENMP_MAX_THREADS);
+                  bondedThreading.nthreads,
+                  GMX_OPENMP_MAX_THREADS);
     }
     GMX_ASSERT(bondedThreading.nthreads <= BITMASK_SIZE,
                "We need at least nthreads bits in the mask");
@@ -481,13 +483,16 @@ void setup_bonded_threading(bonded_threading_t*           bt,
     if (debug)
     {
         fprintf(debug, "Number of %d atom blocks to reduce: %d\n", reduction_block_size, bt->nblock_used);
-        fprintf(debug, "Reduction density %.2f for touched blocks only %.2f\n",
+        fprintf(debug,
+                "Reduction density %.2f for touched blocks only %.2f\n",
                 ctot * reduction_block_size / static_cast<double>(numAtomsForce),
                 ctot / static_cast<double>(bt->nblock_used));
     }
 }
 
-f_thread_t::f_thread_t(int numEnergyGroups) : fshift(SHIFTS), grpp(numEnergyGroups) {}
+f_thread_t::f_thread_t(int numEnergyGroups) : fshift(gmx::c_numShiftVectors), grpp(numEnergyGroups)
+{
+}
 
 bonded_threading_t::bonded_threading_t(const int numThreads, const int numEnergyGroups, FILE* fplog) :
     nthreads(numThreads),
@@ -531,7 +536,8 @@ bonded_threading_t::bonded_threading_t(const int numThreads, const int numEnergy
         sscanf(ptr, "%d", &max_nthread_uniform);
         if (fplog != nullptr)
         {
-            fprintf(fplog, "\nMax threads for uniform bonded distribution set to %d by env.var.\n",
+            fprintf(fplog,
+                    "\nMax threads for uniform bonded distribution set to %d by env.var.\n",
                     max_nthread_uniform);
         }
     }
index aab79ed9727067f8eed0cdd93f6da3450e5435b4..626d3996e7e0d57b371d24cee49b7df90ce09190 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 The GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/smalloc.h"
 
@@ -69,87 +69,76 @@ using gmx::RVec;
 // TODO This implementation of ensemble orientation restraints is nasty because
 // a user can't just do multi-sim with single-sim orientation restraints.
 
-void init_orires(FILE*                 fplog,
-                 const gmx_mtop_t*     mtop,
-                 const t_inputrec*     ir,
-                 const t_commrec*      cr,
-                 const gmx_multisim_t* ms,
-                 t_state*              globalState,
-                 t_oriresdata*         od)
+t_oriresdata::t_oriresdata(FILE*                 fplog,
+                           const gmx_mtop_t&     mtop,
+                           const t_inputrec&     ir,
+                           const t_commrec*      cr,
+                           const gmx_multisim_t* ms,
+                           t_state*              globalState) :
+    numRestraints(gmx_mtop_ftype_count(mtop, F_ORIRES))
 {
-    od->nr = gmx_mtop_ftype_count(mtop, F_ORIRES);
-    if (0 == od->nr)
-    {
-        /* Not doing orientation restraints */
-        return;
-    }
+    GMX_RELEASE_ASSERT(numRestraints > 0,
+                       "orires() should only be called with orientation restraints present");
 
     const int numFitParams = 5;
-    if (od->nr <= numFitParams)
+    if (numRestraints <= numFitParams)
     {
-        gmx_fatal(FARGS,
-                  "The system has %d orientation restraints, but at least %d are required, since "
-                  "there are %d fitting parameters.",
-                  od->nr, numFitParams + 1, numFitParams);
+        const std::string mesg = gmx::formatString(
+                "The system has %d orientation restraints, but at least %d are required, since "
+                "there are %d fitting parameters.",
+                numRestraints,
+                numFitParams + 1,
+                numFitParams);
+        GMX_THROW(gmx::InvalidInputError(mesg));
     }
 
-    if (ir->bPeriodicMols)
+    if (ir.bPeriodicMols)
     {
         /* Since we apply fitting, we need to make molecules whole and this
          * can not be done when periodic molecules are present.
          */
-        gmx_fatal(FARGS,
-                  "Orientation restraints can not be applied when periodic molecules are present "
-                  "in the system");
+        GMX_THROW(gmx::InvalidInputError(
+                "Orientation restraints can not be applied when periodic molecules are present "
+                "in the system"));
     }
 
-    if (PAR(cr))
+    if (cr && PAR(cr))
     {
-        gmx_fatal(FARGS,
-                  "Orientation restraints do not work with MPI parallelization. Choose 1 MPI rank, "
-                  "if possible.");
+        GMX_THROW(gmx::InvalidInputError(
+                "Orientation restraints do not work with MPI parallelization. Choose 1 MPI rank, "
+                "if possible."));
     }
 
-    GMX_RELEASE_ASSERT(globalState != nullptr, "We need a valid global state in init_orires");
+    GMX_RELEASE_ASSERT(globalState != nullptr, "We need a valid global state in t_oriresdata()");
 
-    od->fc  = ir->orires_fc;
-    od->nex = 0;
-    od->S   = nullptr;
-    od->M   = nullptr;
-    od->eig = nullptr;
-    od->v   = nullptr;
+    fc             = ir.orires_fc;
+    numExperiments = 0;
 
-    int*                 nr_ex   = nullptr;
-    int                  typeMin = INT_MAX;
-    int                  typeMax = 0;
-    gmx_mtop_ilistloop_t iloop   = gmx_mtop_ilistloop_init(mtop);
-    int                  nmol;
-    while (const InteractionLists* il = gmx_mtop_ilistloop_next(iloop, &nmol))
+    std::vector<int> nr_ex;
+    typeMin     = INT_MAX;
+    int typeMax = 0;
+    for (const auto il : IListRange(mtop))
     {
-        const int numOrires = (*il)[F_ORIRES].size();
-        if (nmol > 1 && numOrires > 0)
+        const int numOrires = il.list()[F_ORIRES].size();
+        if (il.nmol() > 1 && numOrires > 0)
         {
-            gmx_fatal(FARGS,
-                      "Found %d copies of a molecule with orientation restrains while the current "
-                      "code only supports a single copy. If you want to ensemble average, run "
-                      "multiple copies of the system using the multi-sim feature of mdrun.",
-                      nmol);
+            const std::string mesg = gmx::formatString(
+                    "Found %d copies of a molecule with orientation restrains while the current "
+                    "code only supports a single copy. If you want to ensemble average, run "
+                    "multiple copies of the system using the multi-sim feature of mdrun.",
+                    il.nmol());
+            GMX_THROW(gmx::InvalidInputError(mesg));
         }
 
         for (int i = 0; i < numOrires; i += 3)
         {
-            int type = (*il)[F_ORIRES].iatoms[i];
-            int ex   = mtop->ffparams.iparams[type].orires.ex;
-            if (ex >= od->nex)
+            int type = il.list()[F_ORIRES].iatoms[i];
+            int ex   = mtop.ffparams.iparams[type].orires.ex;
+            if (ex >= numExperiments)
             {
-                srenew(nr_ex, ex + 1);
-                for (int j = od->nex; j < ex + 1; j++)
-                {
-                    nr_ex[j] = 0;
-                }
-                od->nex = ex + 1;
+                nr_ex.resize(ex + 1, 0);
+                numExperiments = ex + 1;
             }
-            GMX_ASSERT(nr_ex, "Check for allocated nr_ex to keep the static analyzer happy");
             nr_ex[ex]++;
 
             typeMin = std::min(typeMin, type);
@@ -158,78 +147,77 @@ void init_orires(FILE*                 fplog,
     }
     /* With domain decomposition we use the type index for indexing in global arrays */
     GMX_RELEASE_ASSERT(
-            typeMax - typeMin + 1 == od->nr,
+            typeMax - typeMin + 1 == numRestraints,
             "All orientation restraint parameter entries in the topology should be consecutive");
-    /* Store typeMin so we can index array with the type offset */
-    od->typeMin = typeMin;
 
-    snew(od->S, od->nex);
+    snew(orderTensors, numExperiments);
     /* When not doing time averaging, the instaneous and time averaged data
      * are indentical and the pointers can point to the same memory.
      */
-    snew(od->Dinsl, od->nr);
+    snew(DTensors, numRestraints);
 
     if (ms)
     {
-        snew(od->Dins, od->nr);
+        snew(DTensorsEnsembleAv, numRestraints);
     }
     else
     {
-        od->Dins = od->Dinsl;
+        DTensorsEnsembleAv = DTensors;
     }
 
-    if (ir->orires_tau == 0)
+    if (ir.orires_tau == 0)
     {
-        od->Dtav  = od->Dins;
-        od->edt   = 0.0;
-        od->edt_1 = 1.0;
+        DTensorsTimeAndEnsembleAv = DTensorsEnsembleAv;
+        edt                       = 0.0;
+        edt_1                     = 1.0;
     }
     else
     {
-        snew(od->Dtav, od->nr);
-        od->edt   = std::exp(-ir->delta_t / ir->orires_tau);
-        od->edt_1 = 1.0 - od->edt;
+        snew(DTensorsTimeAndEnsembleAv, numRestraints);
+        edt   = std::exp(-ir.delta_t / ir.orires_tau);
+        edt_1 = 1.0 - edt;
 
         /* Extend the state with the orires history */
-        globalState->flags |= (1 << estORIRE_INITF);
+        globalState->flags |= enumValueToBitMask(StateEntry::OrireInitF);
         globalState->hist.orire_initf = 1;
-        globalState->flags |= (1 << estORIRE_DTAV);
-        globalState->hist.norire_Dtav = od->nr * 5;
-        snew(globalState->hist.orire_Dtav, globalState->hist.norire_Dtav);
+        globalState->flags |= enumValueToBitMask(StateEntry::OrireDtav);
+        globalState->hist.orire_Dtav.resize(numRestraints * 5);
     }
 
-    snew(od->oinsl, od->nr);
+    orientations.resize(numRestraints);
     if (ms)
     {
-        snew(od->oins, od->nr);
+        orientationsEnsembleAvBuffer.resize(numRestraints);
+        orientationsEnsembleAv = orientationsEnsembleAvBuffer;
     }
     else
     {
-        od->oins = od->oinsl;
+        orientationsEnsembleAv = orientations;
     }
-    if (ir->orires_tau == 0)
+    if (ir.orires_tau == 0)
     {
-        od->otav = od->oins;
+        orientationsTimeAndEnsembleAv = orientationsEnsembleAv;
     }
     else
     {
-        snew(od->otav, od->nr);
+        orientationsTimeAndEnsembleAvBuffer.resize(numRestraints);
+        orientationsTimeAndEnsembleAv = orientationsTimeAndEnsembleAvBuffer;
     }
-    snew(od->tmpEq, od->nex);
+    tmpEq.resize(numExperiments);
 
-    od->nref = 0;
-    for (int i = 0; i < mtop->natoms; i++)
+    numReferenceAtoms = 0;
+    for (int i = 0; i < mtop.natoms; i++)
     {
-        if (getGroupType(mtop->groups, SimulationAtomGroupType::OrientationRestraintsFit, i) == 0)
+        if (getGroupType(mtop.groups, SimulationAtomGroupType::OrientationRestraintsFit, i) == 0)
         {
-            od->nref++;
+            numReferenceAtoms++;
         }
     }
-    snew(od->mref, od->nref);
-    snew(od->xref, od->nref);
-    snew(od->xtmp, od->nref);
+    mref.resize(numReferenceAtoms);
+    xref.resize(numReferenceAtoms);
+    xtmp.resize(numReferenceAtoms);
 
-    snew(od->eig, od->nex * 12);
+    eigenOutput.resize(numExperiments * c_numEigenRealsPerExperiment);
 
     /* Determine the reference structure on the master node.
      * Copy it to the other nodes after checking multi compatibility,
@@ -239,85 +227,90 @@ void init_orires(FILE*                 fplog,
     rvec   com  = { 0, 0, 0 };
     double mtot = 0.0;
     int    j    = 0;
-    for (const AtomProxy atomP : AtomRange(*mtop))
+    for (const AtomProxy atomP : AtomRange(mtop))
     {
         const t_atom& local = atomP.atom();
         int           i     = atomP.globalAtomNumber();
-        if (mtop->groups.groupNumbers[SimulationAtomGroupType::OrientationRestraintsFit].empty()
-            || mtop->groups.groupNumbers[SimulationAtomGroupType::OrientationRestraintsFit][i] == 0)
+        if (mtop.groups.groupNumbers[SimulationAtomGroupType::OrientationRestraintsFit].empty()
+            || mtop.groups.groupNumbers[SimulationAtomGroupType::OrientationRestraintsFit][i] == 0)
         {
             /* Not correct for free-energy with changing masses */
-            od->mref[j] = local.m;
+            mref[j] = local.m;
             // Note that only one rank per sim is supported.
             if (isMasterSim(ms))
             {
-                copy_rvec(x[i], od->xref[j]);
+                copy_rvec(x[i], xref[j]);
                 for (int d = 0; d < DIM; d++)
                 {
-                    com[d] += od->mref[j] * x[i][d];
+                    com[d] += mref[j] * x[i][d];
                 }
             }
-            mtot += od->mref[j];
+            mtot += mref[j];
             j++;
         }
     }
     svmul(1.0 / mtot, com, com);
     if (isMasterSim(ms))
     {
-        for (int j = 0; j < od->nref; j++)
+        for (int j = 0; j < numReferenceAtoms; j++)
         {
-            rvec_dec(od->xref[j], com);
+            rvec_dec(xref[j], com);
         }
     }
 
-    fprintf(fplog, "Found %d orientation experiments\n", od->nex);
-    for (int i = 0; i < od->nex; i++)
+    if (fplog)
     {
-        fprintf(fplog, "  experiment %d has %d restraints\n", i + 1, nr_ex[i]);
-    }
-
-    sfree(nr_ex);
+        fprintf(fplog, "Found %d orientation experiments\n", numExperiments);
+        for (int i = 0; i < numExperiments; i++)
+        {
+            fprintf(fplog, "  experiment %d has %d restraints\n", i + 1, nr_ex[i]);
+        }
 
-    fprintf(fplog, "  the fit group consists of %d atoms and has total mass %g\n", od->nref, mtot);
+        fprintf(fplog, "  the fit group consists of %d atoms and has total mass %g\n", numReferenceAtoms, mtot);
+    }
 
     if (ms)
     {
-        fprintf(fplog, "  the orientation restraints are ensemble averaged over %d systems\n",
-                ms->numSimulations_);
+        if (fplog)
+        {
+            fprintf(fplog,
+                    "  the orientation restraints are ensemble averaged over %d systems\n",
+                    ms->numSimulations_);
+        }
 
-        check_multi_int(fplog, ms, od->nr, "the number of orientation restraints", FALSE);
-        check_multi_int(fplog, ms, od->nref, "the number of fit atoms for orientation restraining", FALSE);
-        check_multi_int(fplog, ms, ir->nsteps, "nsteps", FALSE);
+        check_multi_int(fplog, ms, numRestraints, "the number of orientation restraints", FALSE);
+        check_multi_int(
+                fplog, ms, numReferenceAtoms, "the number of fit atoms for orientation restraining", FALSE);
+        check_multi_int(fplog, ms, ir.nsteps, "nsteps", FALSE);
         /* Copy the reference coordinates from the master to the other nodes */
-        gmx_sum_sim(DIM * od->nref, od->xref[0], ms);
+        gmx_sum_sim(DIM * numReferenceAtoms, xref[0], ms);
     }
 
     please_cite(fplog, "Hess2003");
 }
 
-void diagonalize_orires_tensors(t_oriresdata* od)
+t_oriresdata::~t_oriresdata()
 {
-    if (od->M == nullptr)
+    sfree(orderTensors);
+    if (DTensorsTimeAndEnsembleAv != DTensorsEnsembleAv)
     {
-        snew(od->M, DIM);
-        for (int i = 0; i < DIM; i++)
-        {
-            snew(od->M[i], DIM);
-        }
-        snew(od->eig_diag, DIM);
-        snew(od->v, DIM);
-        for (int i = 0; i < DIM; i++)
-        {
-            snew(od->v[i], DIM);
-        }
+        sfree(DTensorsTimeAndEnsembleAv);
     }
+    if (DTensorsEnsembleAv != DTensors)
+    {
+        sfree(DTensorsEnsembleAv);
+    }
+    sfree(DTensors);
+}
 
-    for (int ex = 0; ex < od->nex; ex++)
+void diagonalize_orires_tensors(t_oriresdata* od)
+{
+    for (int ex = 0; ex < od->numExperiments; ex++)
     {
         /* Rotate the S tensor back to the reference frame */
         matrix S, TMP;
-        mmul(od->R, od->S[ex], TMP);
-        mtmul(TMP, od->R, S);
+        mmul(od->rotationMatrix, od->orderTensors[ex], TMP);
+        mtmul(TMP, od->rotationMatrix, S);
         for (int i = 0; i < DIM; i++)
         {
             for (int j = 0; j < DIM; j++)
@@ -326,8 +319,7 @@ void diagonalize_orires_tensors(t_oriresdata* od)
             }
         }
 
-        int nrot;
-        jacobi(od->M, DIM, od->eig_diag, od->v, &nrot);
+        jacobi(od->M, od->eig_diag, od->v);
 
         int ord[DIM];
         for (int i = 0; i < DIM; i++)
@@ -349,13 +341,14 @@ void diagonalize_orires_tensors(t_oriresdata* od)
 
         for (int i = 0; i < DIM; i++)
         {
-            od->eig[ex * 12 + i] = od->eig_diag[ord[i]];
+            od->eigenOutput[ex * t_oriresdata::c_numEigenRealsPerExperiment + i] = od->eig_diag[ord[i]];
         }
         for (int i = 0; i < DIM; i++)
         {
             for (int j = 0; j < DIM; j++)
             {
-                od->eig[ex * 12 + 3 + 3 * i + j] = od->v[j][ord[i]];
+                od->eigenOutput[ex * t_oriresdata::c_numEigenRealsPerExperiment + 3 + 3 * i + j] =
+                        od->v[j][ord[i]];
             }
         }
     }
@@ -363,19 +356,21 @@ void diagonalize_orires_tensors(t_oriresdata* od)
 
 void print_orires_log(FILE* log, t_oriresdata* od)
 {
-    real* eig;
-
     diagonalize_orires_tensors(od);
 
-    for (int ex = 0; ex < od->nex; ex++)
+    for (int ex = 0; ex < od->numExperiments; ex++)
     {
-        eig = od->eig + ex * 12;
+        const real* eig = od->eigenOutput.data() + ex * t_oriresdata::c_numEigenRealsPerExperiment;
         fprintf(log, "  Orientation experiment %d:\n", ex + 1);
         fprintf(log, "    order parameter: %g\n", eig[0]);
         for (int i = 0; i < DIM; i++)
         {
-            fprintf(log, "    eig: %6.3f   %6.3f %6.3f %6.3f\n", (eig[0] != 0) ? eig[i] / eig[0] : eig[i],
-                    eig[DIM + i * DIM + XX], eig[DIM + i * DIM + YY], eig[DIM + i * DIM + ZZ]);
+            fprintf(log,
+                    "    eig: %6.3f   %6.3f %6.3f %6.3f\n",
+                    (eig[0] != 0) ? eig[i] / eig[0] : eig[i],
+                    eig[DIM + i * DIM + XX],
+                    eig[DIM + i * DIM + YY],
+                    eig[DIM + i * DIM + ZZ]);
         }
         fprintf(log, "\n");
     }
@@ -390,32 +385,21 @@ real calc_orires_dev(const gmx_multisim_t* ms,
                      const rvec            x[],
                      const t_pbc*          pbc,
                      t_oriresdata*         od,
-                     history_t*            hist)
+                     const history_t*      hist)
 {
-    int          nref;
-    real         edt, edt_1, invn, pfac, r2, invr, corrfac, wsv2, sw, dev;
-    OriresMatEq* matEq;
-    real*        mref;
-    double       mtot;
-    rvec *       xref, *xtmp, com, r_unrot, r;
-    gmx_bool     bTAV;
-    const real   two_thr = 2.0 / 3.0;
-
-    if (od->nr == 0)
-    {
-        /* This means that this is not the master node */
-        gmx_fatal(FARGS,
-                  "Orientation restraints are only supported on the master rank, use fewer ranks");
-    }
-
-    bTAV  = (od->edt != 0);
-    edt   = od->edt;
-    edt_1 = od->edt_1;
-    matEq = od->tmpEq;
-    nref  = od->nref;
-    mref  = od->mref;
-    xref  = od->xref;
-    xtmp  = od->xtmp;
+    real       invn, pfac, r2, invr, corrfac, wsv2, sw, dev;
+    double     mtot;
+    rvec       com, r_unrot, r;
+    const real two_thr = 2.0 / 3.0;
+
+    const bool                     bTAV  = (od->edt != 0);
+    const real                     edt   = od->edt;
+    const real                     edt_1 = od->edt_1;
+    gmx::ArrayRef<OriresMatEq>     matEq = od->tmpEq;
+    const int                      nref  = od->numReferenceAtoms;
+    gmx::ArrayRef<real>            mref  = od->mref;
+    gmx::ArrayRef<const gmx::RVec> xref  = od->xref;
+    gmx::ArrayRef<gmx::RVec>       xtmp  = od->xtmp;
 
     if (bTAV)
     {
@@ -441,14 +425,16 @@ real calc_orires_dev(const gmx_multisim_t* ms,
     }
 
     clear_rvec(com);
-    mtot  = 0;
-    int j = 0;
+    mtot        = 0;
+    int   j     = 0;
+    auto* massT = md->massT;
+    auto* cORF  = md->cORF;
     for (int i = 0; i < md->nr; i++)
     {
-        if (md->cORF[i] == 0)
+        if (cORF[i] == 0)
         {
             copy_rvec(xWholeMolecules[i], xtmp[j]);
-            mref[j] = md->massT[i];
+            mref[j] = massT[i];
             for (int d = 0; d < DIM; d++)
             {
                 com[d] += mref[j] * xtmp[j][d];
@@ -463,7 +449,7 @@ real calc_orires_dev(const gmx_multisim_t* ms,
         rvec_dec(xtmp[j], com);
     }
     /* Calculate the rotation matrix to rotate x to the reference orientation */
-    calc_fit_R(DIM, nref, mref, xref, xtmp, od->R);
+    calc_fit_R(DIM, nref, mref.data(), as_rvec_array(xref.data()), as_rvec_array(xtmp.data()), od->rotationMatrix);
 
     for (int fa = 0; fa < nfa; fa += 3)
     {
@@ -477,7 +463,7 @@ real calc_orires_dev(const gmx_multisim_t* ms,
         {
             rvec_sub(x[forceatoms[fa + 1]], x[forceatoms[fa + 2]], r_unrot);
         }
-        mvmul(od->R, r_unrot, r);
+        mvmul(od->rotationMatrix, r_unrot, r);
         r2   = norm2(r);
         invr = gmx::invsqrt(r2);
         /* Calculate the prefactor for the D tensor, this includes the factor 3! */
@@ -486,7 +472,7 @@ real calc_orires_dev(const gmx_multisim_t* ms,
         {
             pfac *= invr;
         }
-        rvec5& Dinsl = od->Dinsl[restraintIndex];
+        rvec5& Dinsl = od->DTensors[restraintIndex];
         Dinsl[0]     = pfac * (2 * r[0] * r[0] + r[1] * r[1] - r2);
         Dinsl[1]     = pfac * (2 * r[0] * r[1]);
         Dinsl[2]     = pfac * (2 * r[0] * r[2]);
@@ -497,18 +483,18 @@ real calc_orires_dev(const gmx_multisim_t* ms,
         {
             for (int i = 0; i < 5; i++)
             {
-                od->Dins[restraintIndex][i] = Dinsl[i] * invn;
+                od->DTensorsEnsembleAv[restraintIndex][i] = Dinsl[i] * invn;
             }
         }
     }
 
     if (ms)
     {
-        gmx_sum_sim(5 * od->nr, od->Dins[0], ms);
+        gmx_sum_sim(5 * od->numRestraints, od->DTensorsEnsembleAv[0], ms);
     }
 
     /* Calculate the order tensor S for each experiment via optimization */
-    for (int ex = 0; ex < od->nex; ex++)
+    for (int ex = 0; ex < od->numExperiments; ex++)
     {
         for (int i = 0; i < 5; i++)
         {
@@ -524,17 +510,17 @@ real calc_orires_dev(const gmx_multisim_t* ms,
     {
         const int type           = forceatoms[fa];
         const int restraintIndex = type - od->typeMin;
-        rvec5&    Dtav           = od->Dtav[restraintIndex];
+        rvec5&    Dtav           = od->DTensorsTimeAndEnsembleAv[restraintIndex];
         if (bTAV)
         {
-            /* Here we update Dtav in t_fcdata using the data in history_t.
+            /* Here we update DTensorsTimeAndEnsembleAv in t_fcdata using the data in history_t.
              * Thus the results stay correct when this routine
              * is called multiple times.
              */
             for (int i = 0; i < 5; i++)
             {
                 Dtav[i] = edt * hist->orire_Dtav[restraintIndex * 5 + i]
-                          + edt_1 * od->Dins[restraintIndex][i];
+                          + edt_1 * od->DTensorsEnsembleAv[restraintIndex][i];
             }
         }
 
@@ -551,7 +537,7 @@ real calc_orires_dev(const gmx_multisim_t* ms,
         }
     }
     /* Now we have all the data we can calculate S */
-    for (int ex = 0; ex < od->nex; ex++)
+    for (int ex = 0; ex < od->numExperiments; ex++)
     {
         OriresMatEq& eq = matEq[ex];
         /* Correct corrfac and copy one half of T to the other half */
@@ -567,7 +553,7 @@ real calc_orires_dev(const gmx_multisim_t* ms,
         }
         m_inv_gen(&eq.mat[0][0], 5, &eq.mat[0][0]);
         /* Calculate the orientation tensor S for this experiment */
-        matrix& S = od->S[ex];
+        matrix& S = od->orderTensors[ex];
         S[0][0]   = 0;
         S[0][1]   = 0;
         S[0][2]   = 0;
@@ -587,7 +573,7 @@ real calc_orires_dev(const gmx_multisim_t* ms,
         S[2][2] = -S[0][0] - S[1][1];
     }
 
-    const matrix* S = od->S;
+    const matrix* S = od->orderTensors;
 
     wsv2 = 0;
     sw   = 0;
@@ -598,15 +584,15 @@ real calc_orires_dev(const gmx_multisim_t* ms,
         const int restraintIndex = type - od->typeMin;
         const int ex             = ip[type].orires.ex;
 
-        const rvec5& Dtav = od->Dtav[restraintIndex];
-        od->otav[restraintIndex] =
+        const rvec5& Dtav = od->DTensorsTimeAndEnsembleAv[restraintIndex];
+        od->orientationsTimeAndEnsembleAv[restraintIndex] =
                 two_thr * corrfac
                 * (S[ex][0][0] * Dtav[0] + S[ex][0][1] * Dtav[1] + S[ex][0][2] * Dtav[2]
                    + S[ex][1][1] * Dtav[3] + S[ex][1][2] * Dtav[4]);
         if (bTAV)
         {
-            const rvec5& Dins = od->Dins[restraintIndex];
-            od->oins[restraintIndex] =
+            const rvec5& Dins = od->DTensorsEnsembleAv[restraintIndex];
+            od->orientationsEnsembleAv[restraintIndex] =
                     two_thr
                     * (S[ex][0][0] * Dins[0] + S[ex][0][1] * Dins[1] + S[ex][0][2] * Dins[2]
                        + S[ex][1][1] * Dins[3] + S[ex][1][2] * Dins[4]);
@@ -616,14 +602,14 @@ real calc_orires_dev(const gmx_multisim_t* ms,
             /* When ensemble averaging is used recalculate the local orientation
              * for output to the energy file.
              */
-            const rvec5& Dinsl = od->Dinsl[restraintIndex];
-            od->oinsl[restraintIndex] =
+            const rvec5& Dinsl = od->DTensors[restraintIndex];
+            od->orientations[restraintIndex] =
                     two_thr
                     * (S[ex][0][0] * Dinsl[0] + S[ex][0][1] * Dinsl[1] + S[ex][0][2] * Dinsl[2]
                        + S[ex][1][1] * Dinsl[3] + S[ex][1][2] * Dinsl[4]);
         }
 
-        dev = od->otav[restraintIndex] - ip[type].orires.obs;
+        dev = od->orientationsTimeAndEnsembleAv[restraintIndex] - ip[type].orires.obs;
 
         wsv2 += ip[type].orires.kfac * gmx::square(dev);
         sw += ip[type].orires.kfac;
@@ -631,11 +617,11 @@ real calc_orires_dev(const gmx_multisim_t* ms,
     od->rmsdev = std::sqrt(wsv2 / sw);
 
     /* Rotate the S matrices back, so we get the correct grad(tr(S D)) */
-    for (int ex = 0; ex < od->nex; ex++)
+    for (int ex = 0; ex < od->numExperiments; ex++)
     {
         matrix RS;
-        tmmul(od->R, od->S[ex], RS);
-        mmul(RS, od->R, od->S[ex]);
+        tmmul(od->rotationMatrix, od->orderTensors[ex], RS);
+        mmul(RS, od->rotationMatrix, od->orderTensors[ex]);
     }
 
     return od->rmsdev;
@@ -652,29 +638,29 @@ real orires(int             nfa,
             const t_pbc*    pbc,
             real gmx_unused lambda,
             real gmx_unused* dvdlambda,
-            const t_mdatoms gmx_unused* md,
-            t_fcdata*                   fcd,
+            gmx::ArrayRef<const real> /*charge*/,
+            t_fcdata gmx_unused* fcd,
+            t_disresdata gmx_unused* disresdata,
+            t_oriresdata*            oriresdata,
             int gmx_unused* global_atom_index)
 {
-    int                 ex, power, ki = CENTRAL;
-    real                r2, invr, invr2, fc, smooth_fc, dev, devins, pfac;
-    rvec                r, Sr, fij;
-    real                vtot;
-    const t_oriresdata* od;
-    gmx_bool            bTAV;
+    int      ex, power, ki = gmx::c_centralShiftIndex;
+    real     r2, invr, invr2, fc, smooth_fc, dev, devins, pfac;
+    rvec     r, Sr, fij;
+    real     vtot;
+    gmx_bool bTAV;
 
     vtot = 0;
-    od   = fcd->orires;
 
-    if (od->fc != 0)
+    if (oriresdata->fc != 0)
     {
-        bTAV = (od->edt != 0);
+        bTAV = (oriresdata->edt != 0);
 
-        smooth_fc = od->fc;
+        smooth_fc = oriresdata->fc;
         if (bTAV)
         {
             /* Smoothly switch on the restraining when time averaging is used */
-            smooth_fc *= (1.0 - od->exp_min_t_tau);
+            smooth_fc *= (1.0 - oriresdata->exp_min_t_tau);
         }
 
         for (int fa = 0; fa < nfa; fa += 3)
@@ -682,7 +668,7 @@ real orires(int             nfa,
             const int type           = forceatoms[fa];
             const int ai             = forceatoms[fa + 1];
             const int aj             = forceatoms[fa + 2];
-            const int restraintIndex = type - od->typeMin;
+            const int restraintIndex = type - oriresdata->typeMin;
             if (pbc)
             {
                 ki = pbc_dx_aiuc(pbc, x[ai], x[aj], r);
@@ -697,7 +683,7 @@ real orires(int             nfa,
             ex    = ip[type].orires.ex;
             power = ip[type].orires.power;
             fc    = smooth_fc * ip[type].orires.kfac;
-            dev   = od->otav[restraintIndex] - ip[type].orires.obs;
+            dev   = oriresdata->orientationsTimeAndEnsembleAv[restraintIndex] - ip[type].orires.obs;
 
             /* NOTE:
              * there is no real potential when time averaging is applied
@@ -707,7 +693,7 @@ real orires(int             nfa,
             if (bTAV)
             {
                 /* Calculate the force as the sqrt of tav times instantaneous */
-                devins = od->oins[restraintIndex] - ip[type].orires.obs;
+                devins = oriresdata->orientationsEnsembleAv[restraintIndex] - ip[type].orires.obs;
                 if (dev * devins <= 0)
                 {
                     dev = 0;
@@ -727,7 +713,7 @@ real orires(int             nfa,
             {
                 pfac *= invr;
             }
-            mvmul(od->S[ex], r, Sr);
+            mvmul(oriresdata->orderTensors[ex], r, Sr);
             for (int i = 0; i < DIM; i++)
             {
                 fij[i] = -pfac * dev * (4 * Sr[i] - 2 * (2 + power) * invr2 * iprod(Sr, r) * r[i]);
@@ -740,7 +726,7 @@ real orires(int             nfa,
                 if (fshift)
                 {
                     fshift[ki][i] += fij[i];
-                    fshift[CENTRAL][i] -= fij[i];
+                    fshift[gmx::c_centralShiftIndex][i] -= fij[i];
                 }
             }
         }
@@ -759,11 +745,11 @@ void update_orires_history(const t_oriresdata& od, history_t* hist)
          *  in calc_orires_dev.
          */
         hist->orire_initf = od.exp_min_t_tau;
-        for (int pair = 0; pair < od.nr; pair++)
+        for (int pair = 0; pair < od.numRestraints; pair++)
         {
             for (int i = 0; i < 5; i++)
             {
-                hist->orire_Dtav[pair * 5 + i] = od.Dtav[pair][i];
+                hist->orire_Dtav[pair * 5 + i] = od.DTensorsTimeAndEnsembleAv[pair][i];
             }
         }
     }
index 37065e8be559164e7f12ac6204bc5e3322edde0e..3a298220d67efa4f7f445a6d932cec5b97373f74 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2010,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +56,10 @@ struct t_inputrec;
 struct t_pbc;
 struct t_commrec;
 struct t_oriresdata;
+struct t_disresdata;
+struct t_fcdata;
 class t_state;
+struct t_mdatoms;
 
 namespace gmx
 {
@@ -64,22 +67,6 @@ template<typename>
 class ArrayRef;
 } // namespace gmx
 
-/*! \brief
- * Decides whether orientation restraints can work, and initializes
- * all the orientation restraint stuff in *od (and assumes *od is
- * already allocated.
- * If orientation restraint are used, globalState is read and modified
- * on the master rank (which is the only rank, since orientation
- * restraints can not run in parallel).
- */
-void init_orires(FILE*                 fplog,
-                 const gmx_mtop_t*     mtop,
-                 const t_inputrec*     ir,
-                 const t_commrec*      cr,
-                 const gmx_multisim_t* ms,
-                 t_state*              globalState,
-                 t_oriresdata*         od);
-
 /*! \brief
  * Calculates the time averaged D matrices, the S matrix for each experiment.
  *
@@ -94,7 +81,7 @@ real calc_orires_dev(const gmx_multisim_t*          ms,
                      const rvec                     x[],
                      const t_pbc*                   pbc,
                      t_oriresdata*                  oriresdata,
-                     history_t*                     hist);
+                     const history_t*               hist);
 
 /*! \brief
  * Diagonalizes the order tensor(s) of the orienation restraints.
@@ -108,18 +95,20 @@ void diagonalize_orires_tensors(t_oriresdata* od);
 void print_orires_log(FILE* log, t_oriresdata* od);
 
 //! Calculates the orientation restraint forces.
-real orires(int              nfa,
-            const t_iatom    forceatoms[],
-            const t_iparams  ip[],
-            const rvec       x[],
-            rvec4            f[],
-            rvec             fshift[],
-            const t_pbc*     pbc,
-            real             lambda,
-            real*            dvdlambda,
-            const t_mdatoms* md,
-            t_fcdata*        fcd,
-            int*             global_atom_index);
+real orires(int                       nfa,
+            const t_iatom             forceatoms[],
+            const t_iparams           ip[],
+            const rvec                x[],
+            rvec4                     f[],
+            rvec                      fshift[],
+            const t_pbc*              pbc,
+            real                      lambda,
+            real*                     dvdlambda,
+            gmx::ArrayRef<const real> charge,
+            t_fcdata*                 fcd,
+            t_disresdata*             disresdata,
+            t_oriresdata*             oriresdata,
+            int*                      global_atom_index);
 
 //! Copies the new time averages that have been calculated in calc_orires_dev.
 void update_orires_history(const t_oriresdata& oriresdata, history_t* hist);
index 1d0393fb71147a6b1fbd779208e8580af4414d9c..a7b18375713f2c1593c5b2c7d4cd0c4adec5dc44 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +55,6 @@
 #include "gromacs/mdtypes/group.h"
 #include "gromacs/mdtypes/interaction_const.h"
 #include "gromacs/mdtypes/md_enums.h"
-#include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/mdtypes/nblist.h"
 #include "gromacs/mdtypes/simulation_workload.h"
 #include "gromacs/pbcutil/ishift.h"
@@ -87,15 +86,25 @@ static void warning_rlimit(const rvec* x, int ai, int aj, int* global_atom_index
             "IMPORTANT: This should not happen in a stable simulation, so there is\n"
             "probably something wrong with your system. Only change the table-extension\n"
             "distance in the mdp file if you are really sure that is the reason.\n",
-            glatnr(global_atom_index, ai), glatnr(global_atom_index, aj), r, rlimit);
+            glatnr(global_atom_index, ai),
+            glatnr(global_atom_index, aj),
+            r,
+            rlimit);
 
     if (debug)
     {
         fprintf(debug,
                 "%8f %8f %8f\n%8f %8f %8f\n1-4 (%d,%d) interaction not within cut-off! r=%g. "
                 "Ignored\n",
-                x[ai][XX], x[ai][YY], x[ai][ZZ], x[aj][XX], x[aj][YY], x[aj][ZZ],
-                glatnr(global_atom_index, ai), glatnr(global_atom_index, aj), r);
+                x[ai][XX],
+                x[ai][YY],
+                x[ai][ZZ],
+                x[aj][XX],
+                x[aj][YY],
+                x[aj][ZZ],
+                glatnr(global_atom_index, ai),
+                glatnr(global_atom_index, aj),
+                r);
     }
 }
 
@@ -321,8 +330,8 @@ static real free_energy_evaluate_single(real
                     + LFV[i] * alpha_vdw_eff * dlfac_vdw[i] * fscal_vdw[i] * sigma_pow[i];
     }
 
-    dvdl[efptCOUL] += dvdl_coul;
-    dvdl[efptVDW] += dvdl_vdw;
+    dvdl[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)] += dvdl_coul;
+    dvdl[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)] += dvdl_vdw;
 
     *velectot = velecsum;
     *vvdwtot  = vvdwsum;
@@ -332,20 +341,24 @@ static real free_energy_evaluate_single(real
 
 /*! \brief Calculate pair interactions, supports all types and conditions. */
 template<BondedKernelFlavor flavor>
-static real do_pairs_general(int                 ftype,
-                             int                 nbonds,
-                             const t_iatom       iatoms[],
-                             const t_iparams     iparams[],
-                             const rvec          x[],
-                             rvec4               f[],
-                             rvec                fshift[],
-                             const struct t_pbc* pbc,
-                             const real*         lambda,
-                             real*               dvdl,
-                             const t_mdatoms*    md,
-                             const t_forcerec*   fr,
-                             gmx_grppairener_t*  grppener,
-                             int*                global_atom_index)
+static real do_pairs_general(int                           ftype,
+                             int                           nbonds,
+                             const t_iatom                 iatoms[],
+                             const t_iparams               iparams[],
+                             const rvec                    x[],
+                             rvec4                         f[],
+                             rvec                          fshift[],
+                             const struct t_pbc*           pbc,
+                             const real*                   lambda,
+                             real*                         dvdl,
+                             gmx::ArrayRef<real>           chargeA,
+                             gmx::ArrayRef<real>           chargeB,
+                             gmx::ArrayRef<bool>           atomIsPerturbed,
+                             gmx::ArrayRef<unsigned short> cENER,
+                             int                           numEnergyGroups,
+                             const t_forcerec*             fr,
+                             gmx_grppairener_t*            grppener,
+                             int*                          global_atom_index)
 {
     real            qq, c6, c12;
     rvec            dx;
@@ -366,12 +379,12 @@ static real do_pairs_general(int                 ftype,
     {
         case F_LJ14:
         case F_LJC14_Q:
-            energygrp_elec = grppener->ener[egCOUL14].data();
-            energygrp_vdw  = grppener->ener[egLJ14].data();
+            energygrp_elec = grppener->energyGroupPairTerms[NonBondedEnergyTerms::Coulomb14].data();
+            energygrp_vdw  = grppener->energyGroupPairTerms[NonBondedEnergyTerms::LJ14].data();
             break;
         case F_LJC_PAIRS_NB:
-            energygrp_elec = grppener->ener[egCOULSR].data();
-            energygrp_vdw  = grppener->ener[egLJSR].data();
+            energygrp_elec = grppener->energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR].data();
+            energygrp_vdw  = grppener->energyGroupPairTerms[NonBondedEnergyTerms::LJSR].data();
             break;
         default:
             energygrp_elec = nullptr; /* Keep compiler happy */
@@ -379,13 +392,13 @@ static real do_pairs_general(int                 ftype,
             gmx_fatal(FARGS, "Unknown function type %d in do_nonbonded14", ftype);
     }
 
-    if (fr->efep != efepNO)
+    if (fr->efep != FreeEnergyPerturbationType::No)
     {
         /* Lambda factor for state A=1-lambda and B=lambda */
-        LFC[0] = 1.0 - lambda[efptCOUL];
-        LFV[0] = 1.0 - lambda[efptVDW];
-        LFC[1] = lambda[efptCOUL];
-        LFV[1] = lambda[efptVDW];
+        LFC[0] = 1.0 - lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)];
+        LFV[0] = 1.0 - lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)];
+        LFC[1] = lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)];
+        LFV[1] = lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)];
 
         /*derivative of the lambda factor for state A and B */
         DLF[0] = -1;
@@ -423,19 +436,20 @@ static real do_pairs_general(int                 ftype,
         itype = iatoms[i++];
         ai    = iatoms[i++];
         aj    = iatoms[i++];
-        gid   = GID(md->cENER[ai], md->cENER[aj], md->nenergrp);
+        gid   = GID(cENER[ai], cENER[aj], numEnergyGroups);
 
         /* Get parameters */
         switch (ftype)
         {
             case F_LJ14:
-                bFreeEnergy = (fr->efep != efepNO
-                               && (((md->nPerturbed != 0) && (md->bPerturbed[ai] || md->bPerturbed[aj]))
-                                   || iparams[itype].lj14.c6A != iparams[itype].lj14.c6B
-                                   || iparams[itype].lj14.c12A != iparams[itype].lj14.c12B));
-                qq          = md->chargeA[ai] * md->chargeA[aj] * epsfac * fr->fudgeQQ;
-                c6          = iparams[itype].lj14.c6A;
-                c12         = iparams[itype].lj14.c12A;
+                bFreeEnergy =
+                        (fr->efep != FreeEnergyPerturbationType::No
+                         && ((!atomIsPerturbed.empty() && (atomIsPerturbed[ai] || atomIsPerturbed[aj]))
+                             || iparams[itype].lj14.c6A != iparams[itype].lj14.c6B
+                             || iparams[itype].lj14.c12A != iparams[itype].lj14.c12B));
+                qq  = chargeA[ai] * chargeA[aj] * epsfac * fr->fudgeQQ;
+                c6  = iparams[itype].lj14.c6A;
+                c12 = iparams[itype].lj14.c12A;
                 break;
             case F_LJC14_Q:
                 qq = iparams[itype].ljc14.qi * iparams[itype].ljc14.qj * epsfac
@@ -469,7 +483,7 @@ static real do_pairs_general(int                 ftype,
         }
         else
         {
-            fshift_index = CENTRAL;
+            fshift_index = c_centralShiftIndex;
             rvec_sub(x[ai], x[aj], dx);
         }
         r2 = norm2(dx);
@@ -489,20 +503,44 @@ static real do_pairs_general(int                 ftype,
         if (bFreeEnergy)
         {
             /* Currently free energy is only supported for F_LJ14, so no need to check for that if we got here */
-            qqB  = md->chargeB[ai] * md->chargeB[aj] * epsfac * fr->fudgeQQ;
+            qqB  = chargeB[ai] * chargeB[aj] * epsfac * fr->fudgeQQ;
             c6B  = iparams[itype].lj14.c6B * 6.0;
             c12B = iparams[itype].lj14.c12B * 12.0;
 
-            fscal = free_energy_evaluate_single(
-                    r2, *fr->ic->softCoreParameters, fr->pairsTable->scale,
-                    fr->pairsTable->data.data(), fr->pairsTable->stride, qq, c6, c12, qqB, c6B, c12B,
-                    LFC, LFV, DLF, lfac_coul, lfac_vdw, dlfac_coul, dlfac_vdw, &velec, &vvdw, dvdl);
+            fscal = free_energy_evaluate_single(r2,
+                                                *fr->ic->softCoreParameters,
+                                                fr->pairsTable->scale,
+                                                fr->pairsTable->data.data(),
+                                                fr->pairsTable->stride,
+                                                qq,
+                                                c6,
+                                                c12,
+                                                qqB,
+                                                c6B,
+                                                c12B,
+                                                LFC,
+                                                LFV,
+                                                DLF,
+                                                lfac_coul,
+                                                lfac_vdw,
+                                                dlfac_coul,
+                                                dlfac_vdw,
+                                                &velec,
+                                                &vvdw,
+                                                dvdl);
         }
         else
         {
             /* Evaluate tabulated interaction without free energy */
-            fscal = evaluate_single(r2, fr->pairsTable->scale, fr->pairsTable->data.data(),
-                                    fr->pairsTable->stride, qq, c6, c12, &velec, &vvdw);
+            fscal = evaluate_single(r2,
+                                    fr->pairsTable->scale,
+                                    fr->pairsTable->data.data(),
+                                    fr->pairsTable->stride,
+                                    qq,
+                                    c6,
+                                    c12,
+                                    &velec,
+                                    &vvdw);
         }
 
         energygrp_elec[gid] += velec;
@@ -515,10 +553,10 @@ static real do_pairs_general(int                 ftype,
 
         if (computeVirial(flavor))
         {
-            if (fshift_index != CENTRAL)
+            if (fshift_index != c_centralShiftIndex)
             {
                 rvec_inc(fshift[fshift_index], dx);
-                rvec_dec(fshift[CENTRAL], dx);
+                rvec_dec(fshift[c_centralShiftIndex], dx);
             }
         }
     }
@@ -530,14 +568,14 @@ static real do_pairs_general(int                 ftype,
  * This function is templated for real/SimdReal and for optimization.
  */
 template<typename T, int pack_size, typename pbc_type>
-static void do_pairs_simple(int              nbonds,
-                            const t_iatom    iatoms[],
-                            const t_iparams  iparams[],
-                            const rvec       x[],
-                            rvec4            f[],
-                            const pbc_type   pbc,
-                            const t_mdatoms* md,
-                            const real       scale_factor)
+static void do_pairs_simple(int                 nbonds,
+                            const t_iatom       iatoms[],
+                            const t_iparams     iparams[],
+                            const rvec          x[],
+                            rvec4               f[],
+                            const pbc_type      pbc,
+                            gmx::ArrayRef<real> charge,
+                            const real          scale_factor)
 {
     const int nfa1 = 1 + 2;
 
@@ -572,7 +610,7 @@ static void do_pairs_simple(int              nbonds,
             {
                 coeff[0 * pack_size + s] = iparams[itype].lj14.c6A;
                 coeff[1 * pack_size + s] = iparams[itype].lj14.c12A;
-                coeff[2 * pack_size + s] = md->chargeA[ai[s]] * md->chargeA[aj[s]];
+                coeff[2 * pack_size + s] = charge[ai[s]] * charge[aj[s]];
 
                 /* Avoid indexing the iatoms array out of bounds.
                  * We pad the coordinate indices with the last atom pair.
@@ -633,24 +671,28 @@ static void do_pairs_simple(int              nbonds,
 }
 
 /*! \brief Calculate all listed pair interactions */
-void do_pairs(int                      ftype,
-              int                      nbonds,
-              const t_iatom            iatoms[],
-              const t_iparams          iparams[],
-              const rvec               x[],
-              rvec4                    f[],
-              rvec                     fshift[],
-              const struct t_pbc*      pbc,
-              const real*              lambda,
-              real*                    dvdl,
-              const t_mdatoms*         md,
-              const t_forcerec*        fr,
-              const bool               havePerturbedInteractions,
-              const gmx::StepWorkload& stepWork,
-              gmx_grppairener_t*       grppener,
-              int*                     global_atom_index)
+void do_pairs(int                           ftype,
+              int                           nbonds,
+              const t_iatom                 iatoms[],
+              const t_iparams               iparams[],
+              const rvec                    x[],
+              rvec4                         f[],
+              rvec                          fshift[],
+              const struct t_pbc*           pbc,
+              const real*                   lambda,
+              real*                         dvdl,
+              gmx::ArrayRef<real>           chargeA,
+              gmx::ArrayRef<real>           chargeB,
+              gmx::ArrayRef<bool>           atomIsPerturbed,
+              gmx::ArrayRef<unsigned short> cENER,
+              const int                     numEnergyGroups,
+              const t_forcerec*             fr,
+              const bool                    havePerturbedInteractions,
+              const gmx::StepWorkload&      stepWork,
+              gmx_grppairener_t*            grppener,
+              int*                          global_atom_index)
 {
-    if (ftype == F_LJ14 && fr->ic->vdwtype != evdwUSER && !EEL_USER(fr->ic->eeltype)
+    if (ftype == F_LJ14 && fr->ic->vdwtype != VanDerWaalsType::User && !EEL_USER(fr->ic->eeltype)
         && !havePerturbedInteractions && (!stepWork.computeVirial && !stepWork.computeEnergy))
     {
         /* We use a fast code-path for plain LJ 1-4 without FEP.
@@ -668,7 +710,7 @@ void do_pairs(int                      ftype,
             set_pbc_simd(pbc, pbc_simd);
 
             do_pairs_simple<SimdReal, GMX_SIMD_REAL_WIDTH, const real*>(
-                    nbonds, iatoms, iparams, x, f, pbc_simd, md, fr->ic->epsfac * fr->fudgeQQ);
+                    nbonds, iatoms, iparams, x, f, pbc_simd, chargeA, fr->ic->epsfac * fr->fudgeQQ);
         }
         else
 #endif
@@ -687,20 +729,50 @@ void do_pairs(int                      ftype,
                 pbc_nonnull = &pbc_no;
             }
 
-            do_pairs_simple<real, 1, const t_pbc*>(nbonds, iatoms, iparams, x, f, pbc_nonnull, md,
-                                                   fr->ic->epsfac * fr->fudgeQQ);
+            do_pairs_simple<real, 1, const t_pbc*>(
+                    nbonds, iatoms, iparams, x, f, pbc_nonnull, chargeA, fr->ic->epsfac * fr->fudgeQQ);
         }
     }
     else if (stepWork.computeVirial)
     {
-        do_pairs_general<BondedKernelFlavor::ForcesAndVirialAndEnergy>(
-                ftype, nbonds, iatoms, iparams, x, f, fshift, pbc, lambda, dvdl, md, fr, grppener,
-                global_atom_index);
+        do_pairs_general<BondedKernelFlavor::ForcesAndVirialAndEnergy>(ftype,
+                                                                       nbonds,
+                                                                       iatoms,
+                                                                       iparams,
+                                                                       x,
+                                                                       f,
+                                                                       fshift,
+                                                                       pbc,
+                                                                       lambda,
+                                                                       dvdl,
+                                                                       chargeA,
+                                                                       chargeB,
+                                                                       atomIsPerturbed,
+                                                                       cENER,
+                                                                       numEnergyGroups,
+                                                                       fr,
+                                                                       grppener,
+                                                                       global_atom_index);
     }
     else
     {
-        do_pairs_general<BondedKernelFlavor::ForcesAndEnergy>(ftype, nbonds, iatoms, iparams, x, f,
-                                                              fshift, pbc, lambda, dvdl, md, fr,
-                                                              grppener, global_atom_index);
+        do_pairs_general<BondedKernelFlavor::ForcesAndEnergy>(ftype,
+                                                              nbonds,
+                                                              iatoms,
+                                                              iparams,
+                                                              x,
+                                                              f,
+                                                              fshift,
+                                                              pbc,
+                                                              lambda,
+                                                              dvdl,
+                                                              chargeA,
+                                                              chargeB,
+                                                              atomIsPerturbed,
+                                                              cENER,
+                                                              numEnergyGroups,
+                                                              fr,
+                                                              grppener,
+                                                              global_atom_index);
     }
 }
index af9320e014af230b454861088594b11455fe788a..57c0c42aba3374239b3ebf339322fbe98b8dc242 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "gromacs/math/vec.h"
 #include "gromacs/topology/ifunc.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
 struct gmx_grppairener_t;
@@ -57,28 +56,34 @@ struct t_pbc;
 namespace gmx
 {
 class StepWorkload;
-}
+template<typename>
+class ArrayRef;
+} // namespace gmx
 
 /*! \brief Calculate VdW/charge listed pair interactions (usually 1-4
  * interactions).
  *
  * global_atom_index is only passed for printing error messages.
  */
-void do_pairs(int                      ftype,
-              int                      nbonds,
-              const t_iatom            iatoms[],
-              const t_iparams          iparams[],
-              const rvec               x[],
-              rvec4                    f[],
-              rvec                     fshift[],
-              const struct t_pbc*      pbc,
-              const real*              lambda,
-              real*                    dvdl,
-              const t_mdatoms*         md,
-              const t_forcerec*        fr,
-              bool                     havePerturbedPairs,
-              const gmx::StepWorkload& stepWork,
-              gmx_grppairener_t*       grppener,
-              int*                     global_atom_index);
+void do_pairs(int                           ftype,
+              int                           nbonds,
+              const t_iatom                 iatoms[],
+              const t_iparams               iparams[],
+              const rvec                    x[],
+              rvec4                         f[],
+              rvec                          fshift[],
+              const struct t_pbc*           pbc,
+              const real*                   lambda,
+              real*                         dvdl,
+              gmx::ArrayRef<real>           chargeA,
+              gmx::ArrayRef<real>           chargeB,
+              gmx::ArrayRef<bool>           atomIsPerturbed,
+              gmx::ArrayRef<unsigned short> cENER,
+              int                           numEnergyGroups,
+              const t_forcerec*             fr,
+              bool                          havePerturbedPairs,
+              const gmx::StepWorkload&      stepWork,
+              gmx_grppairener_t*            grppener,
+              int*                          global_atom_index);
 
 #endif
index 5b12681b79b5215dd664f9b63361be6fa16d8047..165b8932083fe8952b2ad79db54e1d505610874a 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "gmxpre.h"
 
+#include "gromacs/utility/arrayref.h"
 #include "position_restraints.h"
 
 #include <cassert>
@@ -71,18 +72,18 @@ namespace
 
 /*! \brief returns dx, rdist, and dpdl for functions posres() and fbposres()
  */
-void posres_dx(const rvec   x,
-               const rvec   pos0A,
-               const rvec   pos0B,
-               const rvec   comA_sc,
-               const rvec   comB_sc,
-               real         lambda,
-               const t_pbc* pbc,
-               int          refcoord_scaling,
-               int          npbcdim,
-               rvec         dx,
-               rvec         rdist,
-               rvec         dpdl)
+void posres_dx(const rvec      x,
+               const rvec      pos0A,
+               const rvec      pos0B,
+               const rvec      comA_sc,
+               const rvec      comB_sc,
+               real            lambda,
+               const t_pbc*    pbc,
+               RefCoordScaling refcoord_scaling,
+               int             npbcdim,
+               rvec            dx,
+               rvec            rdist,
+               rvec            dpdl)
 {
     int  m, d;
     real posA, posB, L1, ref = 0.;
@@ -98,12 +99,12 @@ void posres_dx(const rvec   x,
         {
             switch (refcoord_scaling)
             {
-                case erscNO:
+                case RefCoordScaling::No:
                     ref      = 0;
                     rdist[m] = L1 * posA + lambda * posB;
                     dpdl[m]  = posB - posA;
                     break;
-                case erscALL:
+                case RefCoordScaling::All:
                     /* Box relative coordinates are stored for dimensions with pbc */
                     posA *= pbc->box[m][m];
                     posB *= pbc->box[m][m];
@@ -117,7 +118,7 @@ void posres_dx(const rvec   x,
                     rdist[m] = 0;
                     dpdl[m]  = posB - posA;
                     break;
-                case erscCOM:
+                case RefCoordScaling::Com:
                     ref      = L1 * comA_sc[m] + lambda * comB_sc[m];
                     rdist[m] = L1 * posA + lambda * posB;
                     dpdl[m]  = comB_sc[m] - comA_sc[m] + posB - posA;
@@ -194,7 +195,7 @@ real fbposres(int                   nbonds,
               const rvec            x[],
               gmx::ForceWithVirial* forceWithVirial,
               const t_pbc*          pbc,
-              int                   refcoord_scaling,
+              RefCoordScaling       refcoord_scaling,
               PbcType               pbcType,
               const rvec            com)
 /* compute flat-bottomed positions restraints */
@@ -208,7 +209,7 @@ real fbposres(int                   nbonds,
 
     npbcdim = numPbcDimensions(pbcType);
     GMX_ASSERT((pbcType == PbcType::No) == (npbcdim == 0), "");
-    if (refcoord_scaling == erscCOM)
+    if (refcoord_scaling == RefCoordScaling::Com)
     {
         clear_rvec(com_sc);
         for (m = 0; m < npbcdim; m++)
@@ -231,8 +232,18 @@ real fbposres(int                   nbonds,
         pr   = &forceparams[type];
 
         /* same calculation as for normal posres, but with identical A and B states, and lambda==0 */
-        posres_dx(x[ai], forceparams[type].fbposres.pos0, forceparams[type].fbposres.pos0, com_sc,
-                  com_sc, 0.0, pbc, refcoord_scaling, npbcdim, dx, rdist, dpdl);
+        posres_dx(x[ai],
+                  forceparams[type].fbposres.pos0,
+                  forceparams[type].fbposres.pos0,
+                  com_sc,
+                  com_sc,
+                  0.0,
+                  pbc,
+                  refcoord_scaling,
+                  npbcdim,
+                  dx,
+                  rdist,
+                  dpdl);
 
         clear_rvec(fm);
         v = 0.0;
@@ -327,7 +338,7 @@ real posres(int                   nbonds,
             const struct t_pbc*   pbc,
             real                  lambda,
             real*                 dvdlambda,
-            int                   refcoord_scaling,
+            RefCoordScaling       refcoord_scaling,
             PbcType               pbcType,
             const rvec            comA,
             const rvec            comB)
@@ -339,7 +350,7 @@ real posres(int                   nbonds,
 
     npbcdim = numPbcDimensions(pbcType);
     GMX_ASSERT((pbcType == PbcType::No) == (npbcdim == 0), "");
-    if (refcoord_scaling == erscCOM)
+    if (refcoord_scaling == RefCoordScaling::Com)
     {
         clear_rvec(comA_sc);
         clear_rvec(comB_sc);
@@ -372,8 +383,18 @@ real posres(int                   nbonds,
         pr   = &forceparams[type];
 
         /* return dx, rdist, and dpdl */
-        posres_dx(x[ai], forceparams[type].posres.pos0A, forceparams[type].posres.pos0B, comA_sc,
-                  comB_sc, lambda, pbc, refcoord_scaling, npbcdim, dx, rdist, dpdl);
+        posres_dx(x[ai],
+                  forceparams[type].posres.pos0A,
+                  forceparams[type].posres.pos0B,
+                  comA_sc,
+                  comB_sc,
+                  lambda,
+                  pbc,
+                  refcoord_scaling,
+                  npbcdim,
+                  dx,
+                  rdist,
+                  dpdl);
 
         for (m = 0; (m < DIM); m++)
         {
@@ -406,22 +427,30 @@ void posres_wrapper(t_nrnb*                       nrnb,
                     const struct t_pbc*           pbc,
                     const rvec*                   x,
                     gmx_enerdata_t*               enerd,
-                    const real*                   lambda,
+                    gmx::ArrayRef<const real>     lambda,
                     const t_forcerec*             fr,
                     gmx::ForceWithVirial*         forceWithVirial)
 {
     real v, dvdl;
 
     dvdl = 0;
-    v    = posres<true>(idef.il[F_POSRES].size(), idef.il[F_POSRES].iatoms.data(),
-                     idef.iparams_posres.data(), x, forceWithVirial,
-                     fr->pbcType == PbcType::No ? nullptr : pbc, lambda[efptRESTRAINT], &dvdl,
-                     fr->rc_scaling, fr->pbcType, fr->posres_com, fr->posres_comB);
+    v    = posres<true>(idef.il[F_POSRES].size(),
+                     idef.il[F_POSRES].iatoms.data(),
+                     idef.iparams_posres.data(),
+                     x,
+                     forceWithVirial,
+                     fr->pbcType == PbcType::No ? nullptr : pbc,
+                     lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Restraint)],
+                     &dvdl,
+                     fr->rc_scaling,
+                     fr->pbcType,
+                     fr->posres_com,
+                     fr->posres_comB);
     enerd->term[F_POSRES] += v;
     /* If just the force constant changes, the FEP term is linear,
      * but if k changes, it is not.
      */
-    enerd->dvdl_nonlin[efptRESTRAINT] += dvdl;
+    enerd->dvdl_nonlin[FreeEnergyPerturbationCouplingType::Restraint] += dvdl;
     inc_nrnb(nrnb, eNR_POSRES, gmx::exactDiv(idef.il[F_POSRES].size(), 2));
 }
 
@@ -431,10 +460,10 @@ void posres_wrapper_lambda(struct gmx_wallcycle*         wcycle,
                            const struct t_pbc*           pbc,
                            const rvec                    x[],
                            gmx_enerdata_t*               enerd,
-                           const real*                   lambda,
+                           gmx::ArrayRef<const real>     lambda,
                            const t_forcerec*             fr)
 {
-    wallcycle_sub_start_nocount(wcycle, ewcsRESTRAINTS);
+    wallcycle_sub_start_nocount(wcycle, WallCycleSubCounter::Restraints);
 
     auto& foreignTerms = enerd->foreignLambdaTerms;
     for (int i = 0; i < 1 + foreignTerms.numLambdas(); i++)
@@ -442,14 +471,23 @@ void posres_wrapper_lambda(struct gmx_wallcycle*         wcycle,
         real dvdl = 0;
 
         const real lambda_dum =
-                (i == 0 ? lambda[efptRESTRAINT] : fepvals->all_lambda[efptRESTRAINT][i - 1]);
-        const real v = posres<false>(idef.il[F_POSRES].size(), idef.il[F_POSRES].iatoms.data(),
-                                     idef.iparams_posres.data(), x, nullptr,
-                                     fr->pbcType == PbcType::No ? nullptr : pbc, lambda_dum, &dvdl,
-                                     fr->rc_scaling, fr->pbcType, fr->posres_com, fr->posres_comB);
+                (i == 0 ? lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Restraint)]
+                        : fepvals->all_lambda[FreeEnergyPerturbationCouplingType::Restraint][i - 1]);
+        const real v = posres<false>(idef.il[F_POSRES].size(),
+                                     idef.il[F_POSRES].iatoms.data(),
+                                     idef.iparams_posres.data(),
+                                     x,
+                                     nullptr,
+                                     fr->pbcType == PbcType::No ? nullptr : pbc,
+                                     lambda_dum,
+                                     &dvdl,
+                                     fr->rc_scaling,
+                                     fr->pbcType,
+                                     fr->posres_com,
+                                     fr->posres_comB);
         foreignTerms.accumulate(i, v, dvdl);
     }
-    wallcycle_sub_stop(wcycle, ewcsRESTRAINTS);
+    wallcycle_sub_stop(wcycle, WallCycleSubCounter::Restraints);
 }
 
 /*! \brief Helper function that wraps calls to fbposres for
@@ -464,9 +502,15 @@ void fbposres_wrapper(t_nrnb*                       nrnb,
 {
     real v;
 
-    v = fbposres(idef.il[F_FBPOSRES].size(), idef.il[F_FBPOSRES].iatoms.data(),
-                 idef.iparams_fbposres.data(), x, forceWithVirial,
-                 fr->pbcType == PbcType::No ? nullptr : pbc, fr->rc_scaling, fr->pbcType, fr->posres_com);
+    v = fbposres(idef.il[F_FBPOSRES].size(),
+                 idef.il[F_FBPOSRES].iatoms.data(),
+                 idef.iparams_fbposres.data(),
+                 x,
+                 forceWithVirial,
+                 fr->pbcType == PbcType::No ? nullptr : pbc,
+                 fr->rc_scaling,
+                 fr->pbcType,
+                 fr->posres_com);
     enerd->term[F_FBPOSRES] += v;
     inc_nrnb(nrnb, eNR_FBPOSRES, gmx::exactDiv(idef.il[F_FBPOSRES].size(), 2));
 }
index 5d3148fb33aac3e5c986661c9dd188745c629f72..3fc8d0020c76421e0c09f8696f26c207376800b6 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,2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,7 @@
 #include <stdio.h>
 
 #include "gromacs/math/vectypes.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/real.h"
 
 struct gmx_enerdata_t;
@@ -72,7 +73,7 @@ void posres_wrapper(t_nrnb*                       nrnb,
                     const struct t_pbc*           pbc,
                     const rvec*                   x,
                     gmx_enerdata_t*               enerd,
-                    const real*                   lambda,
+                    gmx::ArrayRef<const real>     lambda,
                     const t_forcerec*             fr,
                     gmx::ForceWithVirial*         forceWithVirial);
 
@@ -84,7 +85,7 @@ void posres_wrapper_lambda(struct gmx_wallcycle*         wcycle,
                            const struct t_pbc*           pbc,
                            const rvec                    x[],
                            gmx_enerdata_t*               enerd,
-                           const real*                   lambda,
+                           gmx::ArrayRef<const real>     lambda,
                            const t_forcerec*             fr);
 
 /*! \brief Helper function that wraps calls to fbposres for
index 2da9dcf8fec015aec0d135b40ab8c274beb77d79..68326ebca3929eff65dd0a1d0766fc87e38c0719 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2017,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -78,7 +78,7 @@ void compute_factors_restangles(int             type,
     double term_theta_theta_equil;
 
     k_bending          = forceparams[type].harmonic.krA;
-    theta_equil        = forceparams[type].harmonic.rA * DEG2RAD;
+    theta_equil        = forceparams[type].harmonic.rA * gmx::c_deg2Rad;
     theta_equil        = M_PI - theta_equil;
     cosine_theta_equil = cos(theta_equil);
 
@@ -135,7 +135,7 @@ void compute_factors_restrdihs(int             type,
     real norm_phi;
 
     /* Read parameters phi0 and k_torsion */
-    phi0        = forceparams[type].pdihs.phiA * DEG2RAD;
+    phi0        = forceparams[type].pdihs.phiA * gmx::c_deg2Rad;
     cosine_phi0 = cos(phi0);
     k_torsion   = forceparams[type].pdihs.cpA;
 
diff --git a/src/gromacs/listed_forces/tests/.clang-tidy b/src/gromacs/listed_forces/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index ffe786b4b24c6bdfca4012a73d6a37d1b30bec86..d253053eacbfd3d4908dbdaeb4bd24289a93a67c 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2016,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2016,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,5 +35,7 @@
 gmx_add_unit_test(ListedForcesTest listed_forces-test
     CPP_SOURCE_FILES
         bonded.cpp
+        pairs.cpp
+        position_restraints.cpp
         )
 
index 41c74f9294a23e40c02ce3fa6b5821afc4f4c1df..76aa9e97c7478cc55c9d1c1cc0244faa895fbd0e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -92,7 +92,7 @@ struct OutputQuantities
     //! Derivative with respect to lambda
     real dvdlambda = 0;
     //! Shift vectors
-    rvec fshift[N_IVEC] = { { 0 } };
+    rvec fshift[c_numShiftVectors] = { { 0 } };
     //! Forces
     alignas(GMX_REAL_MAX_SIMD_WIDTH * sizeof(real)) rvec4 f[c_numAtoms] = { { 0 } };
 };
@@ -565,17 +565,19 @@ protected:
         // have an implementation for uint64_t(!) but this is likely to
         // work because that type is likely to be a typedef for one of
         // the other numerical types that happens to be 64-bits wide.
-        shiftForcesTolerance_ = FloatingPointTolerance(singleShiftForcesAbsoluteTolerance, 1e-8, 1e-6,
-                                                       1e-12, std::numeric_limits<uint64_t>::max(),
-                                                       std::numeric_limits<uint64_t>::max(), false);
+        shiftForcesTolerance_ = FloatingPointTolerance(singleShiftForcesAbsoluteTolerance,
+                                                       1e-8,
+                                                       1e-6,
+                                                       1e-12,
+                                                       std::numeric_limits<uint64_t>::max(),
+                                                       std::numeric_limits<uint64_t>::max(),
+                                                       false);
     }
     void testOneIfunc(TestReferenceChecker* checker, const std::vector<t_iatom>& iatoms, const real lambda)
     {
         SCOPED_TRACE(std::string("Testing PBC type: ") + c_pbcTypeNames[pbcType_]);
         std::vector<int>  ddgatindex = { 0, 1, 2, 3 };
-        std::vector<real> chargeA    = { 1.5, -2.0, 1.5, -1.0 };
-        t_mdatoms         mdatoms    = { 0 };
-        mdatoms.chargeA              = chargeA.data();
+        std::vector<real> charge     = { 1.5, -2.0, 1.5, -1.0 };
         /* Here we run both the standard, plain-C force+shift-forces+energy+free-energy
          * kernel flavor and the potentially optimized, with SIMD and less output,
          * force only kernels. Note that we also run the optimized kernel for free-energy
@@ -590,11 +592,22 @@ protected:
         {
             SCOPED_TRACE("Testing bonded kernel flavor: " + c_bondedKernelFlavorStrings[flavor]);
             OutputQuantities output;
-            output.energy =
-                    calculateSimpleBond(input_.ftype, iatoms.size(), iatoms.data(), &input_.iparams,
-                                        as_rvec_array(x_.data()), output.f, output.fshift, &pbc_,
-                                        lambda, &output.dvdlambda, &mdatoms,
-                                        /* struct t_fcdata * */ nullptr, ddgatindex.data(), flavor);
+            output.energy = calculateSimpleBond(input_.ftype,
+                                                iatoms.size(),
+                                                iatoms.data(),
+                                                &input_.iparams,
+                                                as_rvec_array(x_.data()),
+                                                output.f,
+                                                output.fshift,
+                                                &pbc_,
+                                                lambda,
+                                                &output.dvdlambda,
+                                                charge,
+                                                /* struct t_fcdata * */ nullptr,
+                                                nullptr,
+                                                nullptr,
+                                                ddgatindex.data(),
+                                                flavor);
             // Internal consistency test of both test input
             // and bonded functions.
             EXPECT_TRUE((input_.fep || (output.dvdlambda == 0.0))) << "dvdlambda was " << output.dvdlambda;
@@ -603,7 +616,7 @@ protected:
             if (computeVirial(flavor))
             {
                 shiftForcesChecker.setDefaultTolerance(shiftForcesTolerance_);
-                shiftForcesChecker.checkVector(output.fshift[CENTRAL], "Central");
+                shiftForcesChecker.checkVector(output.fshift[c_centralShiftIndex], "Central");
             }
             else
             {
@@ -770,8 +783,6 @@ std::vector<PaddedVector<RVec>> c_coordinatesForTestsZeroAngle = {
 //! PBC values for testing
 std::vector<PbcType> c_pbcForTests = { PbcType::No, PbcType::XY, PbcType::Xyz };
 
-// Those tests give errors with the intel compiler and nothing else, so we disable them only there.
-#ifndef __INTEL_COMPILER
 INSTANTIATE_TEST_CASE_P(Bond,
                         ListedForcesTest,
                         ::testing::Combine(::testing::ValuesIn(c_InputBonds),
@@ -813,7 +824,6 @@ INSTANTIATE_TEST_CASE_P(AngleZero,
                         ::testing::Combine(::testing::ValuesIn(c_InputAnglesZeroAngle),
                                            ::testing::ValuesIn(c_coordinatesForTestsZeroAngle),
                                            ::testing::ValuesIn(c_pbcForTests)));
-#endif
 
 } // namespace
 
diff --git a/src/gromacs/listed_forces/tests/pairs.cpp b/src/gromacs/listed_forces/tests/pairs.cpp
new file mode 100644 (file)
index 0000000..1a734aa
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 1-4 interactions
+ *
+ * This test is copied from the bonded interactions test and slightly
+ * modified since 'do_pairs' takes a different set of arguments than
+ * 'calculateSimpleBond'. To keep the test setup uncluttered this test is
+ * therefore not merged into the bonded test but implemented standalone.
+ *
+ * The test setup consists of 2 atom pairs that are tested in an fep setting
+ * (vanishing charge and lennard-jones parameters of one atom) and without
+ * fep. Placement of the atoms in the box is such that shift-forces and pbc
+ * paths in do_pairs are covered.
+ *
+ * \author Sebastian Kehl <sebastian.kehl@mpcdf.mpg.de>
+ * \ingroup module_listed_forces
+ */
+#include "gmxpre.h"
+
+#include "gromacs/listed_forces/bonded.h"
+
+#include <cmath>
+
+#include <memory>
+#include <unordered_map>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/listed_forces/listed_forces.h"
+#include "gromacs/listed_forces/pairs.h"
+#include "gromacs/math/paddedvector.h"
+#include "gromacs/math/units.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/math/vectypes.h"
+#include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/mdtypes/simulation_workload.h"
+#include "gromacs/mdtypes/enerdata.h"
+#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/interaction_const.h"
+#include "gromacs/mdtypes/nblist.h"
+#include "gromacs/tables/forcetable.h"
+#include "gromacs/pbcutil/ishift.h"
+#include "gromacs/pbcutil/pbc.h"
+#include "gromacs/topology/idef.h"
+#include "gromacs/utility/enumerationhelpers.h"
+#include "gromacs/utility/strconvert.h"
+#include "gromacs/utility/stringstream.h"
+#include "gromacs/utility/textwriter.h"
+#include "gromacs/utility/fatalerror.h"
+
+#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
+
+namespace gmx
+{
+namespace test
+{
+namespace
+{
+
+//! Number of atoms used in these tests.
+constexpr int c_numAtoms = 3;
+
+/*! \brief Output from pairs kernels
+ *
+ */
+struct OutputQuantities
+{
+    OutputQuantities(int energyGroup) :
+        energy(energyGroup),
+        dvdLambda(static_cast<int>(FreeEnergyPerturbationCouplingType::Count), 0.0)
+    {
+    }
+
+    //! Energy of this interaction
+    gmx_grppairener_t energy;
+    //! Derivative with respect to lambda
+    std::vector<real> dvdLambda;
+    //! Shift vectors
+    rvec fShift[gmx::detail::c_numIvecs] = { { 0 } };
+    //! Forces
+    alignas(GMX_REAL_MAX_SIMD_WIDTH * sizeof(real)) rvec4 f[c_numAtoms] = { { 0 } };
+};
+
+/*! \brief Utility to check the output from pairs tests
+ *
+ * \param[in] checker Reference checker
+ * \param[in] output  The output from the test to check
+ * \param[in] bondedKernelFlavor  Flavor for determining what output to check
+ * \param[in] functionType type of the interaction
+ */
+void checkOutput(TestReferenceChecker*    checker,
+                 const OutputQuantities&  output,
+                 const BondedKernelFlavor bondedKernelFlavor,
+                 const int                functionType)
+{
+    if (computeEnergy(bondedKernelFlavor))
+    {
+        switch (functionType)
+        {
+            case F_LJ14:
+            case F_LJC14_Q:
+                checker->checkReal(output.energy.energyGroupPairTerms[NonBondedEnergyTerms::Coulomb14][0],
+                                   "Epot Coulomb14");
+                checker->checkReal(output.energy.energyGroupPairTerms[NonBondedEnergyTerms::LJ14][0],
+                                   "Epot LJ14");
+                break;
+            case F_LJC_PAIRS_NB:
+                checker->checkReal(output.energy.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR][0],
+                                   "Epot Coulomb14");
+                checker->checkReal(output.energy.energyGroupPairTerms[NonBondedEnergyTerms::LJSR][0],
+                                   "Epot LJ14");
+                break;
+            default: gmx_fatal(FARGS, "Unknown function type %d in do_nonbonded14", functionType);
+        }
+        checker->checkReal(output.dvdLambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)],
+                           "dVdlCoul ");
+        checker->checkReal(output.dvdLambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)],
+                           "dVdlVdw ");
+    }
+    checker->checkSequence(std::begin(output.f), std::end(output.f), "Forces");
+}
+
+/* \brief Utility class to setup forcerec and interaction parameters
+ *
+ * Data is only initialized as necessary for the 1-4 interactions to work!
+ */
+class ForcerecHelper
+{
+public:
+    ForcerecHelper()
+    {
+        fepVals_.sc_alpha     = 0.3;
+        fepVals_.sc_power     = 1;
+        fepVals_.sc_r_power   = 6.0;
+        fepVals_.sc_sigma     = 0.3;
+        fepVals_.sc_sigma_min = 0.3;
+        fepVals_.bScCoul      = true;
+
+        fr_.ic = std::make_unique<interaction_const_t>();
+        // set data in ic
+        fr_.ic->softCoreParameters = std::make_unique<interaction_const_t::SoftCoreParameters>(fepVals_);
+
+        // set data in fr
+        real tableRange = 2.9;
+        fr_.pairsTable = make_tables(nullptr, fr_.ic.get(), nullptr, tableRange, GMX_MAKETABLES_14ONLY);
+        fr_.efep       = haveFep_;
+        fr_.fudgeQQ          = 0.5;
+        fr_.use_simd_kernels = useSimd_;
+        fr_.bMolPBC          = haveMolPBC_;
+    }
+
+    t_forcerec* get() { return &fr_; }
+
+private:
+    FreeEnergyPerturbationType haveFep_    = FreeEnergyPerturbationType::No;
+    bool                       useSimd_    = false;
+    bool                       haveMolPBC_ = false;
+
+    t_lambda   fepVals_;
+    t_forcerec fr_;
+};
+
+ForcerecHelper frHelper;
+
+
+/*! \brief Input structure for listed forces tests
+ */
+struct ListInput
+{
+public:
+    //! Function type
+    int fType = -1;
+    //! do fep
+    bool fep = false;
+    //! Tolerance for float evaluation
+    float floatToler = 1e-6;
+    //! Tolerance for double evaluation
+    double doubleToler = 1e-8;
+    //! Interaction parameters
+    t_iparams iparams = { { 0 } };
+
+    //! Constructor
+    ListInput() {}
+
+    /*! \brief Constructor with tolerance
+     *
+     * \param[in] ftol Single precision tolerance
+     * \param[in] dtol Double precision tolerance
+     */
+    ListInput(float ftol, double dtol)
+    {
+        floatToler  = ftol;
+        doubleToler = dtol;
+    }
+
+    /*! \brief Set parameters for lj14 interaction
+     *
+     * Fep is used if either c6A != c6B or c12A != c12B.
+     *
+     * \param[in] c6A  lj-c6 of state A
+     * \param[in] c12A lj-c12 of state A
+     * \param[in] c6B  lj-c6 of state B
+     * \param[in] c12B lj-c12 of state B
+     */
+    ListInput setLj14Interaction(real c6A, real c12A, real c6B, real c12B)
+    {
+        fType             = F_LJ14;
+        fep               = (c6A != c6B || c12A != c12B);
+        iparams.lj14.c6A  = c6A;
+        iparams.lj14.c12A = c12A;
+        iparams.lj14.c6B  = c6B;
+        iparams.lj14.c12B = c12B;
+
+        return *this;
+    }
+
+    /*! \brief Set parameters for ljc14 interaction
+     *
+     * \param[in] qi     charge i
+     * \param[in] qj     charge j
+     * \param[in] c6     lj-c6
+     * \param[in] c12    lj-c12
+     * \param[in] fudgeQ fudge factor
+     */
+    ListInput setLjc14Interaction(real qi, real qj, real c6, real c12, real fudgeQ)
+    {
+        fType             = F_LJC14_Q;
+        iparams.ljc14.qi  = qi;
+        iparams.ljc14.qj  = qj;
+        iparams.ljc14.c6  = c6;
+        iparams.ljc14.c12 = c12;
+        iparams.ljc14.fqq = fudgeQ;
+
+        return *this;
+    }
+
+    /*! \brief Set parameters for ljcnb interaction
+     *
+     * \param[in] qi  charge i
+     * \param[in] qj  charge j
+     * \param[in] c6  lj-c6
+     * \param[in] c12 lj-c12
+     */
+    ListInput setLjcnbInteraction(real qi, real qj, real c6, real c12)
+    {
+        fType             = F_LJC_PAIRS_NB;
+        iparams.ljcnb.qi  = qi;
+        iparams.ljcnb.qj  = qj;
+        iparams.ljcnb.c6  = c6;
+        iparams.ljcnb.c12 = c12;
+
+        return *this;
+    }
+};
+
+class ListedForcesPairsTest :
+    public ::testing::TestWithParam<std::tuple<ListInput, PaddedVector<RVec>, PbcType>>
+{
+protected:
+    matrix               box_;
+    t_pbc                pbc_;
+    PaddedVector<RVec>   x_;
+    PbcType              pbcType_;
+    ListInput            input_;
+    TestReferenceData    refData_;
+    TestReferenceChecker checker_;
+
+    ListedForcesPairsTest() : checker_(refData_.rootChecker())
+    {
+        input_   = std::get<0>(GetParam());
+        x_       = std::get<1>(GetParam());
+        pbcType_ = std::get<2>(GetParam());
+        clear_mat(box_);
+        box_[0][0] = box_[1][1] = box_[2][2] = 1.0;
+        set_pbc(&pbc_, pbcType_, box_);
+
+        FloatingPointTolerance tolerance = relativeToleranceAsPrecisionDependentFloatingPoint(
+                1.0, input_.floatToler, input_.doubleToler);
+
+        checker_.setDefaultTolerance(tolerance);
+    }
+
+    void testOneIfunc(TestReferenceChecker* checker, const real lambda)
+    {
+        SCOPED_TRACE(std::string("Testing PBC type: ") + c_pbcTypeNames[pbcType_]);
+
+        // 'definition of pairs' is a concatenation of #npairs (here 2)
+        // 'nAtomsPerPair+1'-tuples (fType a_0 a_i ... a_nAtomsPerPair)
+        std::vector<t_iatom> iatoms = { 0, 1, 2, 0, 0, 2 };
+
+        std::vector<int>            ddgatindex = { 0, 1, 2 };
+        std::vector<real>           chargeA    = { 1.0, -0.5, -0.5 };
+        std::vector<real>           chargeB    = { 0.0, 0.0, 0.0 };
+        std::vector<unsigned short> egrp       = { 0, 0, 0 };
+        t_mdatoms                   mdatoms    = { 0 };
+
+        mdatoms.chargeA = chargeA.data();
+        mdatoms.chargeB = chargeB.data();
+        mdatoms.cENER   = egrp.data();
+        // nPerturbed is not decisive for fep to be used; it is overruled by
+        // other conditions in do_pairs_general; just here to not segfault
+        // upon query
+        mdatoms.nPerturbed = 0;
+
+        t_forcerec* fr = frHelper.get();
+        fr->efep = input_.fep ? FreeEnergyPerturbationType::Yes : FreeEnergyPerturbationType::No;
+        if (pbcType_ != PbcType::No)
+        {
+            fr->bMolPBC = true;
+        }
+
+        std::vector<BondedKernelFlavor> flavors = { BondedKernelFlavor::ForcesAndVirialAndEnergy };
+
+        if (!input_.fep || lambda == 0)
+        {
+            fr->use_simd_kernels = true;
+            flavors.push_back(BondedKernelFlavor::ForcesSimdWhenAvailable);
+        }
+
+        for (const auto flavor : flavors)
+        {
+            SCOPED_TRACE("Testing bonded kernel flavor: " + c_bondedKernelFlavorStrings[flavor]);
+
+            StepWorkload stepWork;
+            stepWork.computeVirial = computeVirial(flavor);
+            stepWork.computeEnergy = computeEnergy(flavor);
+
+            bool havePerturbedInteractions = input_.fep;
+            if (flavor == BondedKernelFlavor::ForcesSimdWhenAvailable)
+            {
+                havePerturbedInteractions = false;
+            }
+
+            int numEnergyTerms      = static_cast<int>(NonBondedEnergyTerms::Count);
+            int numFepCouplingTerms = static_cast<int>(FreeEnergyPerturbationCouplingType::Count);
+            OutputQuantities  output(numEnergyTerms);
+            std::vector<real> lambdas(numFepCouplingTerms, lambda);
+
+            do_pairs(input_.fType,
+                     iatoms.size(),
+                     iatoms.data(),
+                     &input_.iparams,
+                     as_rvec_array(x_.data()),
+                     output.f,
+                     output.fShift,
+                     &pbc_,
+                     lambdas.data(),
+                     output.dvdLambda.data(),
+                     gmx::arrayRefFromArray(mdatoms.chargeA, mdatoms.nr),
+                     gmx::arrayRefFromArray(mdatoms.chargeB, mdatoms.nr),
+                     gmx::arrayRefFromArray(mdatoms.bPerturbed, mdatoms.nr),
+                     gmx::arrayRefFromArray(mdatoms.cENER, mdatoms.nr),
+                     mdatoms.nPerturbed,
+                     fr,
+                     havePerturbedInteractions,
+                     stepWork,
+                     &output.energy,
+                     ddgatindex.data());
+
+            checkOutput(checker, output, flavor, input_.fType);
+            auto shiftForcesChecker = checker->checkCompound("Shift-Forces", "Shift-forces");
+
+            if (computeVirial(flavor))
+            {
+                shiftForcesChecker.checkVector(output.fShift[gmx::c_centralShiftIndex], "Central");
+            }
+            else
+            {
+                // Permit omitting to compare shift forces with
+                // reference data when that is useless.
+                shiftForcesChecker.disableUnusedEntriesCheck();
+            }
+        }
+    }
+
+    void testIfunc()
+    {
+        TestReferenceChecker thisChecker =
+                checker_.checkCompound("FunctionType", interaction_function[input_.fType].name)
+                        .checkCompound("FEP", (input_.fep ? "Yes" : "No"));
+
+        if (input_.fep)
+        {
+            const int numLambdas = 3;
+            for (int i = 0; i < numLambdas; ++i)
+            {
+                const real lambda        = i / (numLambdas - 1.0);
+                auto       lambdaChecker = thisChecker.checkCompound("Lambda", toString(lambda));
+                testOneIfunc(&lambdaChecker, lambda);
+            }
+        }
+        else
+        {
+            testOneIfunc(&thisChecker, 0.0);
+        }
+    }
+};
+
+TEST_P(ListedForcesPairsTest, Ifunc)
+{
+    testIfunc();
+}
+
+//! Function types for testing 1-4 interaction. Add new terms at the end.
+std::vector<ListInput> c_14Interaction = {
+    { ListInput(1e-5, 1e-7).setLj14Interaction(0.001458, 1.0062882e-6, 0.0, 0.0) },
+    { ListInput(1e-5, 1e-7).setLj14Interaction(0.001458, 1.0062882e-6, 0.001458, 1.0062882e-6) },
+    { ListInput(1e-5, 1e-7).setLjc14Interaction(1.0, -1.0, 0.001458, 1.0062882e-6, 0.5) },
+    { ListInput(1e-5, 1e-7).setLjcnbInteraction(1.0, -1.0, 0.001458, 1.0062882e-6) }
+};
+
+//! PBC values for testing
+std::vector<PbcType> c_pbcForTests = { PbcType::No, PbcType::XY, PbcType::Xyz };
+
+/*! \brief Coordinates for testing 1-4 interaction
+ *
+ * Define coordinates for 3 atoms here, which will be used in 2 interactions.
+ */
+std::vector<PaddedVector<RVec>> c_coordinatesFor14Interaction = {
+    { { 0.0, 0.0, 0.0 }, { 1.0, 1.0, 1.0 }, { 1.1, 1.2, 1.3 } }
+};
+
+INSTANTIATE_TEST_CASE_P(14Interaction,
+                        ListedForcesPairsTest,
+                        ::testing::Combine(::testing::ValuesIn(c_14Interaction),
+                                           ::testing::ValuesIn(c_coordinatesFor14Interaction),
+                                           ::testing::ValuesIn(c_pbcForTests)));
+
+} // namespace
+
+} // namespace test
+
+} // namespace gmx
diff --git a/src/gromacs/listed_forces/tests/position_restraints.cpp b/src/gromacs/listed_forces/tests/position_restraints.cpp
new file mode 100644 (file)
index 0000000..23dee62
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 position restraint tests.
+ *
+ * \author Kevin Boyd <kevin44boyd@gmail.com>
+ * \ingroup module_listed_forces
+ */
+#include "gmxpre.h"
+
+#include "gromacs/listed_forces/position_restraints.h"
+
+#include <cmath>
+
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/gmxlib/nrnb.h"
+#include "gromacs/listed_forces/listed_forces.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/math/vectypes.h"
+#include "gromacs/mdtypes/enerdata.h"
+#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/forceoutput.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/interaction_const.h"
+#include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/mdtypes/nblist.h"
+#include "gromacs/mdtypes/simulation_workload.h"
+#include "gromacs/pbcutil/pbc.h"
+#include "gromacs/tables/forcetable.h"
+#include "gromacs/topology/forcefieldparameters.h"
+#include "gromacs/topology/idef.h"
+#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/stringstream.h"
+
+#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
+
+namespace gmx
+{
+namespace test
+{
+namespace
+{
+
+//! Tolerance for float evaluation
+constexpr float c_precisionTolerance = 1e-6;
+
+
+class PositionRestraintsTest : public ::testing::TestWithParam<std::tuple<RefCoordScaling, PbcType>>
+{
+protected:
+    std::vector<RVec> x_;
+    std::vector<RVec> f_;
+
+    matrix  box_;
+    t_pbc   pbc_;
+    PbcType pbcType_;
+
+    t_nrnb                           nrnb_;
+    t_forcerec                       fr_;
+    InteractionDefinitions           idef_;
+    gmx_enerdata_t                   enerd_;
+    std::unique_ptr<ForceWithVirial> forceWithVirial_;
+    RefCoordScaling                  refCoordScaling_;
+
+    TestReferenceData    refData_;
+    TestReferenceChecker checker_;
+
+    PositionRestraintsTest() : idef_({}), enerd_(1, 0), checker_(refData_.rootChecker())
+    {
+        refCoordScaling_ = std::get<0>(GetParam());
+        pbcType_         = std::get<1>(GetParam());
+
+        clear_mat(box_);
+        box_[0][0] = 0.9;
+        box_[1][1] = 1.0;
+        box_[2][2] = 1.1;
+        set_pbc(&pbc_, pbcType_, box_);
+
+        FloatingPointTolerance tolerance = relativeToleranceAsFloatingPoint(1.0, c_precisionTolerance);
+        checker_.setDefaultTolerance(tolerance);
+
+        fr_.rc_scaling    = refCoordScaling_;
+        fr_.pbcType       = pbcType_;
+        fr_.posres_com[1] = 0.5;
+    }
+
+    //! Prepares the test with the coordinate and force constant input.
+    void setValues(gmx::ArrayRef<const RVec> positions,
+                   gmx::ArrayRef<const RVec> referencePositions,
+                   gmx::ArrayRef<const RVec> forceConstants)
+    {
+        x_.resize(positions.size());
+        std::copy(positions.begin(), positions.end(), x_.begin());
+
+        for (size_t i = 0; i < positions.size(); i++)
+        {
+            // First item is "type" - each atom will have a different forceparam type
+            // Second item is index - we'll just go from 0.
+            idef_.il[F_POSRES].iatoms.push_back(i);
+            idef_.il[F_POSRES].iatoms.push_back(i);
+
+            auto& entry = idef_.iparams_posres.emplace_back();
+            copy_rvec(referencePositions[i], entry.posres.pos0A);
+            copy_rvec(forceConstants[i], entry.posres.fcA);
+            clear_rvec(entry.posres.pos0B);
+            clear_rvec(entry.posres.fcB);
+        }
+        f_.resize(x_.size(), { 0, 0, 0 });
+        forceWithVirial_ = std::make_unique<ForceWithVirial>(f_, /*computeVirial=*/true);
+    }
+};
+
+std::array<real, static_cast<size_t>(FreeEnergyPerturbationCouplingType::Count)> c_emptyLambdas = { { 0 } };
+
+TEST_P(PositionRestraintsTest, BasicPosResNoFreeEnergy)
+{
+    SCOPED_TRACE(formatString("Testing PBC type: %s, refcoord type: %s",
+                              c_pbcTypeNames[pbcType_].c_str(),
+                              enumValueToString(refCoordScaling_)));
+    const std::vector<RVec> positions          = { { 0.0, 0.0, 0.0 }, { 0.4, 0.5, 0.6 } };
+    const std::vector<RVec> referencePositions = { { 0.0, 0.0, 0.0 }, { 0.5, 0.6, 0.0 } };
+    const std::vector<RVec> forceConstants     = { { 1000, 500, 250 }, { 0, 200, 400 } };
+    setValues(positions, referencePositions, forceConstants);
+    posres_wrapper(&nrnb_,
+                   idef_,
+                   &pbc_,
+                   as_rvec_array(x_.data()),
+                   &enerd_,
+                   c_emptyLambdas,
+                   &fr_,
+                   forceWithVirial_.get());
+    checker_.checkSequence(
+            std::begin(forceWithVirial_->force_), std::end(forceWithVirial_->force_), "Forces");
+    checker_.checkSequenceArray(3, forceWithVirial_->getVirial(), "Virial contribution");
+    checker_.checkReal(enerd_.term[F_POSRES], "Potential energy");
+}
+
+//! PBC values for testing
+std::vector<PbcType> c_pbcForTests = { PbcType::No, PbcType::XY, PbcType::Xyz };
+//! Reference Coordinate Scaling values for testing
+std::vector<RefCoordScaling> c_refCoordScalingForTests = { RefCoordScaling::No,
+                                                           RefCoordScaling::Com,
+                                                           RefCoordScaling::All };
+
+INSTANTIATE_TEST_CASE_P(PosResBasicTest,
+                        PositionRestraintsTest,
+                        ::testing::Combine(::testing::ValuesIn(c_refCoordScalingForTests),
+                                           ::testing::ValuesIn(c_pbcForTests)));
+
+} // namespace
+
+} // namespace test
+
+} // namespace gmx
diff --git a/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_0.xml b/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_0.xml
new file mode 100644 (file)
index 0000000..9e4ad67
--- /dev/null
@@ -0,0 +1,101 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <FunctionType Name="LJ14">
+    <FEP Name="Yes">
+      <Lambda Name="0">
+        <Real Name="Epot Coulomb14">0.21407271220614837</Real>
+        <Real Name="Epot LJ14">-0.39771349695163671</Real>
+        <Real Name="dVdlCoul ">-0.21851037383566912</Real>
+        <Real Name="dVdlVdw ">0.41875860652489377</Real>
+        <Sequence Name="Forces">
+          <Int Name="Length">3</Int>
+          <Vector>
+            <Real Name="X">0.030442842705220918</Real>
+            <Real Name="Y">0.033210373860240998</Real>
+            <Real Name="Z">0.035977905015261082</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">0.89301764058624677</Real>
+            <Real Name="Y">1.7860352811724916</Real>
+            <Real Name="Z">2.6790529217587382</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">-0.92346048329146768</Real>
+            <Real Name="Y">-1.8192456550327325</Real>
+            <Real Name="Z">-2.7150308267739991</Real>
+          </Vector>
+        </Sequence>
+        <Shift-Forces Name="Shift-forces">
+          <Vector Name="Central">
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Shift-Forces>
+      </Lambda>
+      <Lambda Name="0.5">
+        <Real Name="Epot Coulomb14">0.10595201107466379</Real>
+        <Real Name="Epot LJ14">-0.19369895958475428</Real>
+        <Real Name="dVdlCoul ">-0.21402396676422034</Real>
+        <Real Name="dVdlVdw ">0.39750692921973912</Real>
+        <Sequence Name="Forces">
+          <Int Name="Length">3</Int>
+          <Vector>
+            <Real Name="X">0.015221397582715825</Real>
+            <Real Name="Y">0.016605160999326352</Real>
+            <Real Name="Z">0.017988924415936882</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">0.42958890996342458</Real>
+            <Real Name="Y">0.85917781992684816</Real>
+            <Real Name="Z">1.2887667298902727</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">-0.44481030754614043</Real>
+            <Real Name="Y">-0.87578298092617457</Real>
+            <Real Name="Z">-1.3067556543062095</Real>
+          </Vector>
+        </Sequence>
+        <Shift-Forces Name="Shift-forces">
+          <Vector Name="Central">
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Shift-Forces>
+      </Lambda>
+      <Lambda Name="1">
+        <Real Name="Epot Coulomb14">0</Real>
+        <Real Name="Epot LJ14">0</Real>
+        <Real Name="dVdlCoul ">-0.20983019696952224</Real>
+        <Real Name="dVdlVdw ">0.37749364747323017</Real>
+        <Sequence Name="Forces">
+          <Int Name="Length">3</Int>
+          <Vector>
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Sequence>
+        <Shift-Forces Name="Shift-forces">
+          <Vector Name="Central">
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Shift-Forces>
+      </Lambda>
+    </FEP>
+  </FunctionType>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_1.xml b/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_1.xml
new file mode 100644 (file)
index 0000000..1af2924
--- /dev/null
@@ -0,0 +1,101 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <FunctionType Name="LJ14">
+    <FEP Name="Yes">
+      <Lambda Name="0">
+        <Real Name="Epot Coulomb14">0.1445520414957524</Real>
+        <Real Name="Epot LJ14">-0.3979723893321509</Real>
+        <Real Name="dVdlCoul ">-0.14898844529427274</Real>
+        <Real Name="dVdlVdw ">0.41901751034443802</Real>
+        <Sequence Name="Forces">
+          <Int Name="Length">3</Int>
+          <Vector>
+            <Real Name="X">0.010987624164811038</Real>
+            <Real Name="Y">0.021975248329622051</Real>
+            <Real Name="Z">0.14283911414254338</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">0.89301764058624677</Real>
+            <Real Name="Y">1.7860352811724916</Real>
+            <Real Name="Z">2.6790529217587382</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">-0.9040052647510578</Real>
+            <Real Name="Y">-1.8080105295021136</Real>
+            <Real Name="Z">-2.8218920359012816</Real>
+          </Vector>
+        </Sequence>
+        <Shift-Forces Name="Shift-forces">
+          <Vector Name="Central">
+            <Real Name="X">-0.010987624164811038</Real>
+            <Real Name="Y">-0.021975248329622051</Real>
+            <Real Name="Z">-0.14283911414254338</Real>
+          </Vector>
+        </Shift-Forces>
+      </Lambda>
+      <Lambda Name="0.5">
+        <Real Name="Epot Coulomb14">0.071191990173256878</Real>
+        <Real Name="Epot LJ14">-0.19382840291531345</Real>
+        <Real Name="dVdlCoul ">-0.14450329606174245</Real>
+        <Real Name="dVdlVdw ">0.39776582160013413</Real>
+        <Sequence Name="Forces">
+          <Int Name="Length">3</Int>
+          <Vector>
+            <Real Name="X">0.0054936782176173184</Real>
+            <Real Name="Y">0.010987356435234625</Real>
+            <Real Name="Z">0.07141781682902508</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">0.42958890996342458</Real>
+            <Real Name="Y">0.85917781992684816</Real>
+            <Real Name="Z">1.2887667298902727</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">-0.4350825881810419</Real>
+            <Real Name="Y">-0.87016517636208279</Real>
+            <Real Name="Z">-1.3601845467192979</Real>
+          </Vector>
+        </Sequence>
+        <Shift-Forces Name="Shift-forces">
+          <Vector Name="Central">
+            <Real Name="X">-0.0054936782176173184</Real>
+            <Real Name="Y">-0.010987356435234625</Real>
+            <Real Name="Z">-0.07141781682902508</Real>
+          </Vector>
+        </Shift-Forces>
+      </Lambda>
+      <Lambda Name="1">
+        <Real Name="Epot Coulomb14">0</Real>
+        <Real Name="Epot LJ14">0</Real>
+        <Real Name="dVdlCoul ">-0.14031078405845462</Real>
+        <Real Name="dVdlVdw ">0.37775252841519097</Real>
+        <Sequence Name="Forces">
+          <Int Name="Length">3</Int>
+          <Vector>
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Sequence>
+        <Shift-Forces Name="Shift-forces">
+          <Vector Name="Central">
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Shift-Forces>
+      </Lambda>
+    </FEP>
+  </FunctionType>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_10.xml b/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_10.xml
new file mode 100644 (file)
index 0000000..1f21e7d
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <FunctionType Name="LJC_NB">
+    <FEP Name="No">
+      <Real Name="Epot Coulomb14">-3.4307104627027285</Real>
+      <Real Name="Epot LJ14">-0.3979723893321509</Real>
+      <Real Name="dVdlCoul ">0</Real>
+      <Real Name="dVdlVdw ">0</Real>
+      <Sequence Name="Forces">
+        <Int Name="Length">3</Int>
+        <Vector>
+          <Real Name="X">0.043664263974573722</Real>
+          <Real Name="Y">0.087328527949147347</Real>
+          <Real Name="Z">0.56763543166945785</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">3.0406526210041607</Real>
+          <Real Name="Y">6.0813052420083142</Real>
+          <Real Name="Z">9.1219578630124758</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">-3.0843168849787346</Real>
+          <Real Name="Y">-6.1686337699574612</Real>
+          <Real Name="Z">-9.6895932946819343</Real>
+        </Vector>
+      </Sequence>
+      <Shift-Forces Name="Shift-forces">
+        <Vector Name="Central">
+          <Real Name="X">-0.043664263974573722</Real>
+          <Real Name="Y">-0.087328527949147347</Real>
+          <Real Name="Z">-0.56763543166945785</Real>
+        </Vector>
+      </Shift-Forces>
+    </FEP>
+  </FunctionType>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_11.xml b/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_11.xml
new file mode 100644 (file)
index 0000000..3a85c07
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <FunctionType Name="LJC_NB">
+    <FEP Name="No">
+      <Real Name="Epot Coulomb14">-5.3452248382476508</Real>
+      <Real Name="Epot LJ14">-0.79539132295421022</Real>
+      <Real Name="dVdlCoul ">0</Real>
+      <Real Name="dVdlVdw ">0</Real>
+      <Sequence Name="Forces">
+        <Int Name="Length">3</Int>
+        <Vector>
+          <Real Name="X">3.0406526210041607</Real>
+          <Real Name="Y">6.0813052420083142</Real>
+          <Real Name="Z">9.1219578630124758</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">3.0406526210041607</Real>
+          <Real Name="Y">6.0813052420083142</Real>
+          <Real Name="Z">9.1219578630124758</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">-6.0813052420083213</Real>
+          <Real Name="Y">-12.162610484016628</Real>
+          <Real Name="Z">-18.243915726024952</Real>
+        </Vector>
+      </Sequence>
+      <Shift-Forces Name="Shift-forces">
+        <Vector Name="Central">
+          <Real Name="X">-3.0406526210041607</Real>
+          <Real Name="Y">-6.0813052420083142</Real>
+          <Real Name="Z">-9.1219578630124758</Real>
+        </Vector>
+      </Shift-Forces>
+    </FEP>
+  </FunctionType>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_2.xml b/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_2.xml
new file mode 100644 (file)
index 0000000..c55987f
--- /dev/null
@@ -0,0 +1,101 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <FunctionType Name="LJ14">
+    <FEP Name="Yes">
+      <Lambda Name="0">
+        <Real Name="Epot Coulomb14">-0.33407655239047818</Real>
+        <Real Name="Epot LJ14">-0.79539132295421022</Real>
+        <Real Name="dVdlCoul ">0.3385142675285866</Real>
+        <Real Name="dVdlVdw ">0.83748154200529312</Real>
+        <Sequence Name="Forces">
+          <Int Name="Length">3</Int>
+          <Vector>
+            <Real Name="X">1.6088959673922179</Real>
+            <Real Name="Y">3.2177919347844322</Real>
+            <Real Name="Z">4.8266879021766504</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">0.89301764058624677</Real>
+            <Real Name="Y">1.7860352811724916</Real>
+            <Real Name="Z">2.6790529217587382</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">-2.5019136079784645</Real>
+            <Real Name="Y">-5.0038272159569237</Real>
+            <Real Name="Z">-7.5057408239353887</Real>
+          </Vector>
+        </Sequence>
+        <Shift-Forces Name="Shift-forces">
+          <Vector Name="Central">
+            <Real Name="X">-1.6088959673922179</Real>
+            <Real Name="Y">-3.2177919347844322</Real>
+            <Real Name="Z">-4.8266879021766504</Real>
+          </Vector>
+        </Shift-Forces>
+      </Lambda>
+      <Lambda Name="0.5">
+        <Real Name="Epot Coulomb14">-0.16595391778969223</Real>
+        <Real Name="Epot LJ14">-0.38738008371883476</Real>
+        <Real Name="dVdlCoul ">0.33402780694852929</Real>
+        <Real Name="dVdlVdw ">0.79497818749041516</Real>
+        <Sequence Name="Forces">
+          <Int Name="Length">3</Int>
+          <Vector>
+            <Real Name="X">0.77157606087074149</Real>
+            <Real Name="Y">1.5431521217414814</Real>
+            <Real Name="Z">2.3147281826122228</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">0.42958890996342458</Real>
+            <Real Name="Y">0.85917781992684816</Real>
+            <Real Name="Z">1.2887667298902727</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">-1.2011649708341661</Real>
+            <Real Name="Y">-2.4023299416683295</Real>
+            <Real Name="Z">-3.6034949125024953</Real>
+          </Vector>
+        </Sequence>
+        <Shift-Forces Name="Shift-forces">
+          <Vector Name="Central">
+            <Real Name="X">-0.77157606087074149</Real>
+            <Real Name="Y">-1.5431521217414814</Real>
+            <Real Name="Z">-2.3147281826122228</Real>
+          </Vector>
+        </Shift-Forces>
+      </Lambda>
+      <Lambda Name="1">
+        <Real Name="Epot Coulomb14">0</Real>
+        <Real Name="Epot LJ14">0</Real>
+        <Real Name="dVdlCoul ">0.32983398364534788</Real>
+        <Real Name="dVdlVdw ">0.75495162409282812</Real>
+        <Sequence Name="Forces">
+          <Int Name="Length">3</Int>
+          <Vector>
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+          <Vector>
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Sequence>
+        <Shift-Forces Name="Shift-forces">
+          <Vector Name="Central">
+            <Real Name="X">0</Real>
+            <Real Name="Y">0</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Shift-Forces>
+      </Lambda>
+    </FEP>
+  </FunctionType>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_3.xml b/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_3.xml
new file mode 100644 (file)
index 0000000..0ee6004
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <FunctionType Name="LJ14">
+    <FEP Name="No">
+      <Real Name="Epot Coulomb14">0.2140727122061484</Real>
+      <Real Name="Epot LJ14">-0.39771349695163671</Real>
+      <Real Name="dVdlCoul ">0</Real>
+      <Real Name="dVdlVdw ">0</Real>
+      <Sequence Name="Forces">
+        <Int Name="Length">3</Int>
+        <Vector>
+          <Real Name="X">0.030442842705220907</Real>
+          <Real Name="Y">0.033210373860240984</Real>
+          <Real Name="Z">0.035977905015261075</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">0.89301764058624677</Real>
+          <Real Name="Y">1.7860352811724916</Real>
+          <Real Name="Z">2.6790529217587382</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">-0.92346048329146768</Real>
+          <Real Name="Y">-1.8192456550327325</Real>
+          <Real Name="Z">-2.7150308267739991</Real>
+        </Vector>
+      </Sequence>
+      <Shift-Forces Name="Shift-forces">
+        <Vector Name="Central">
+          <Real Name="X">0</Real>
+          <Real Name="Y">0</Real>
+          <Real Name="Z">0</Real>
+        </Vector>
+      </Shift-Forces>
+    </FEP>
+  </FunctionType>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_4.xml b/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_4.xml
new file mode 100644 (file)
index 0000000..c540567
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <FunctionType Name="LJ14">
+    <FEP Name="No">
+      <Real Name="Epot Coulomb14">0.14455204149575238</Real>
+      <Real Name="Epot LJ14">-0.3979723893321509</Real>
+      <Real Name="dVdlCoul ">0</Real>
+      <Real Name="dVdlVdw ">0</Real>
+      <Sequence Name="Forces">
+        <Int Name="Length">3</Int>
+        <Vector>
+          <Real Name="X">0.010987624164811043</Real>
+          <Real Name="Y">0.021975248329622062</Real>
+          <Real Name="Z">0.14283911414254344</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">0.89301764058624677</Real>
+          <Real Name="Y">1.7860352811724916</Real>
+          <Real Name="Z">2.6790529217587382</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">-0.9040052647510578</Real>
+          <Real Name="Y">-1.8080105295021136</Real>
+          <Real Name="Z">-2.8218920359012816</Real>
+        </Vector>
+      </Sequence>
+      <Shift-Forces Name="Shift-forces">
+        <Vector Name="Central">
+          <Real Name="X">-0.010987624164811043</Real>
+          <Real Name="Y">-0.021975248329622062</Real>
+          <Real Name="Z">-0.14283911414254344</Real>
+        </Vector>
+      </Shift-Forces>
+    </FEP>
+  </FunctionType>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_5.xml b/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_5.xml
new file mode 100644 (file)
index 0000000..3f65bf3
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <FunctionType Name="LJ14">
+    <FEP Name="No">
+      <Real Name="Epot Coulomb14">-0.33407655239047818</Real>
+      <Real Name="Epot LJ14">-0.79539132295421022</Real>
+      <Real Name="dVdlCoul ">0</Real>
+      <Real Name="dVdlVdw ">0</Real>
+      <Sequence Name="Forces">
+        <Int Name="Length">3</Int>
+        <Vector>
+          <Real Name="X">1.6088959673922179</Real>
+          <Real Name="Y">3.2177919347844322</Real>
+          <Real Name="Z">4.8266879021766504</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">0.89301764058624677</Real>
+          <Real Name="Y">1.7860352811724916</Real>
+          <Real Name="Z">2.6790529217587382</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">-2.5019136079784645</Real>
+          <Real Name="Y">-5.0038272159569237</Real>
+          <Real Name="Z">-7.5057408239353887</Real>
+        </Vector>
+      </Sequence>
+      <Shift-Forces Name="Shift-forces">
+        <Vector Name="Central">
+          <Real Name="X">-1.6088959673922179</Real>
+          <Real Name="Y">-3.2177919347844322</Real>
+          <Real Name="Z">-4.8266879021766504</Real>
+        </Vector>
+      </Shift-Forces>
+    </FEP>
+  </FunctionType>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_6.xml b/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_6.xml
new file mode 100644 (file)
index 0000000..5104d00
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <FunctionType Name="LJC14_Q">
+    <FEP Name="No">
+      <Real Name="Epot Coulomb14">-1.5763138899305722</Real>
+      <Real Name="Epot LJ14">-0.39771349695163671</Real>
+      <Real Name="dVdlCoul ">0</Real>
+      <Real Name="dVdlVdw ">0</Real>
+      <Sequence Name="Forces">
+        <Int Name="Length">3</Int>
+        <Vector>
+          <Real Name="X">0.060858562567575235</Real>
+          <Real Name="Y">0.066391159164627525</Real>
+          <Real Name="Z">0.071923755761679822</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">2.0861481852628656</Real>
+          <Real Name="Y">4.1722963705257259</Real>
+          <Real Name="Z">6.2584445557885919</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">-2.1470067478304409</Real>
+          <Real Name="Y">-4.2386875296903535</Real>
+          <Real Name="Z">-6.3303683115502718</Real>
+        </Vector>
+      </Sequence>
+      <Shift-Forces Name="Shift-forces">
+        <Vector Name="Central">
+          <Real Name="X">0</Real>
+          <Real Name="Y">0</Real>
+          <Real Name="Z">0</Real>
+        </Vector>
+      </Shift-Forces>
+    </FEP>
+  </FunctionType>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_7.xml b/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_7.xml
new file mode 100644 (file)
index 0000000..4efb547
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <FunctionType Name="LJC14_Q">
+    <FEP Name="No">
+      <Real Name="Epot Coulomb14">-1.7153552313513643</Real>
+      <Real Name="Epot LJ14">-0.3979723893321509</Real>
+      <Real Name="dVdlCoul ">0</Real>
+      <Real Name="dVdlVdw ">0</Real>
+      <Sequence Name="Forces">
+        <Int Name="Length">3</Int>
+        <Vector>
+          <Real Name="X">0.021879837434731937</Real>
+          <Real Name="Y">0.043759674869463826</Real>
+          <Real Name="Z">0.28443788665151498</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">2.0861481852628656</Real>
+          <Real Name="Y">4.1722963705257259</Real>
+          <Real Name="Z">6.2584445557885919</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">-2.1080280226975976</Real>
+          <Real Name="Y">-4.2160560453951899</Real>
+          <Real Name="Z">-6.5428824424401073</Real>
+        </Vector>
+      </Sequence>
+      <Shift-Forces Name="Shift-forces">
+        <Vector Name="Central">
+          <Real Name="X">-0.021879837434731937</Real>
+          <Real Name="Y">-0.043759674869463826</Real>
+          <Real Name="Z">-0.28443788665151498</Real>
+        </Vector>
+      </Shift-Forces>
+    </FEP>
+  </FunctionType>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_8.xml b/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_8.xml
new file mode 100644 (file)
index 0000000..9c72eaa
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <FunctionType Name="LJC14_Q">
+    <FEP Name="No">
+      <Real Name="Epot Coulomb14">-2.6726124191238254</Real>
+      <Real Name="Epot LJ14">-0.79539132295421022</Real>
+      <Real Name="dVdlCoul ">0</Real>
+      <Real Name="dVdlVdw ">0</Real>
+      <Sequence Name="Forces">
+        <Int Name="Length">3</Int>
+        <Vector>
+          <Real Name="X">2.0861481852628656</Real>
+          <Real Name="Y">4.1722963705257259</Real>
+          <Real Name="Z">6.2584445557885919</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">2.0861481852628656</Real>
+          <Real Name="Y">4.1722963705257259</Real>
+          <Real Name="Z">6.2584445557885919</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">-4.1722963705257312</Real>
+          <Real Name="Y">-8.3445927410514518</Real>
+          <Real Name="Z">-12.516889111577184</Real>
+        </Vector>
+      </Sequence>
+      <Shift-Forces Name="Shift-forces">
+        <Vector Name="Central">
+          <Real Name="X">-2.0861481852628656</Real>
+          <Real Name="Y">-4.1722963705257259</Real>
+          <Real Name="Z">-6.2584445557885919</Real>
+        </Vector>
+      </Shift-Forces>
+    </FEP>
+  </FunctionType>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_9.xml b/src/gromacs/listed_forces/tests/refdata/14Interaction_ListedForcesPairsTest_Ifunc_9.xml
new file mode 100644 (file)
index 0000000..23f2d94
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <FunctionType Name="LJC_NB">
+    <FEP Name="No">
+      <Real Name="Epot Coulomb14">-3.1526277798611444</Real>
+      <Real Name="Epot LJ14">-0.39771349695163671</Real>
+      <Real Name="dVdlCoul ">0</Real>
+      <Real Name="dVdlVdw ">0</Real>
+      <Sequence Name="Forces">
+        <Int Name="Length">3</Int>
+        <Vector>
+          <Real Name="X">0.1216900022922839</Real>
+          <Real Name="Y">0.13275272977340061</Real>
+          <Real Name="Z">0.14381545725451733</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">3.0406526210041607</Real>
+          <Real Name="Y">6.0813052420083142</Real>
+          <Real Name="Z">9.1219578630124758</Real>
+        </Vector>
+        <Vector>
+          <Real Name="X">-3.1623426232964444</Real>
+          <Real Name="Y">-6.214057971781715</Real>
+          <Real Name="Z">-9.2657733202669927</Real>
+        </Vector>
+      </Sequence>
+      <Shift-Forces Name="Shift-forces">
+        <Vector Name="Central">
+          <Real Name="X">0</Real>
+          <Real Name="Y">0</Real>
+          <Real Name="Z">0</Real>
+        </Vector>
+      </Shift-Forces>
+    </FEP>
+  </FunctionType>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_0.xml b/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_0.xml
new file mode 100644 (file)
index 0000000..e6e1dce
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Sequence Name="Forces">
+    <Int Name="Length">2</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">20</Real>
+      <Real Name="Z">-240</Real>
+    </Vector>
+  </Sequence>
+  <Sequence Name="Virial contribution">
+    <Int Name="Length">3</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">1</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">72</Real>
+    </Vector>
+  </Sequence>
+  <Real Name="Potential energy">73</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_1.xml b/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_1.xml
new file mode 100644 (file)
index 0000000..2d006b5
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Sequence Name="Forces">
+    <Int Name="Length">2</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">20</Real>
+      <Real Name="Z">-240</Real>
+    </Vector>
+  </Sequence>
+  <Sequence Name="Virial contribution">
+    <Int Name="Length">3</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">-5</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">72</Real>
+    </Vector>
+  </Sequence>
+  <Real Name="Potential energy">73</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_2.xml b/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_2.xml
new file mode 100644 (file)
index 0000000..0c43ced
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Sequence Name="Forces">
+    <Int Name="Length">2</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">20</Real>
+      <Real Name="Z">200</Real>
+    </Vector>
+  </Sequence>
+  <Sequence Name="Virial contribution">
+    <Int Name="Length">3</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">-5</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">50</Real>
+    </Vector>
+  </Sequence>
+  <Real Name="Potential energy">51</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_3.xml b/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_3.xml
new file mode 100644 (file)
index 0000000..e6e1dce
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Sequence Name="Forces">
+    <Int Name="Length">2</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">20</Real>
+      <Real Name="Z">-240</Real>
+    </Vector>
+  </Sequence>
+  <Sequence Name="Virial contribution">
+    <Int Name="Length">3</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">1</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">72</Real>
+    </Vector>
+  </Sequence>
+  <Real Name="Potential energy">73</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_4.xml b/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_4.xml
new file mode 100644 (file)
index 0000000..6353463
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Sequence Name="Forces">
+    <Int Name="Length">2</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">-250</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">-80</Real>
+      <Real Name="Z">-240</Real>
+    </Vector>
+  </Sequence>
+  <Sequence Name="Virial contribution">
+    <Int Name="Length">3</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">102.5</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">72</Real>
+    </Vector>
+  </Sequence>
+  <Real Name="Potential energy">150.5</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_5.xml b/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_5.xml
new file mode 100644 (file)
index 0000000..613bbaf
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Sequence Name="Forces">
+    <Int Name="Length">2</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">-250</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">-80</Real>
+      <Real Name="Z">200</Real>
+    </Vector>
+  </Sequence>
+  <Sequence Name="Virial contribution">
+    <Int Name="Length">3</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">102.5</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">50</Real>
+    </Vector>
+  </Sequence>
+  <Real Name="Potential energy">128.5</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_6.xml b/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_6.xml
new file mode 100644 (file)
index 0000000..e6e1dce
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Sequence Name="Forces">
+    <Int Name="Length">2</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">20</Real>
+      <Real Name="Z">-240</Real>
+    </Vector>
+  </Sequence>
+  <Sequence Name="Virial contribution">
+    <Int Name="Length">3</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">1</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">72</Real>
+    </Vector>
+  </Sequence>
+  <Real Name="Potential energy">73</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_7.xml b/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_7.xml
new file mode 100644 (file)
index 0000000..e6e1dce
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Sequence Name="Forces">
+    <Int Name="Length">2</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">20</Real>
+      <Real Name="Z">-240</Real>
+    </Vector>
+  </Sequence>
+  <Sequence Name="Virial contribution">
+    <Int Name="Length">3</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">1</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">72</Real>
+    </Vector>
+  </Sequence>
+  <Real Name="Potential energy">73</Real>
+</ReferenceData>
diff --git a/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_8.xml b/src/gromacs/listed_forces/tests/refdata/PosResBasicTest_PositionRestraintsTest_BasicPosResNoFreeEnergy_8.xml
new file mode 100644 (file)
index 0000000..128436a
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Sequence Name="Forces">
+    <Int Name="Length">2</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">20</Real>
+      <Real Name="Z">200</Real>
+    </Vector>
+  </Sequence>
+  <Sequence Name="Virial contribution">
+    <Int Name="Length">3</Int>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">1</Real>
+      <Real Name="Z">0</Real>
+    </Vector>
+    <Vector>
+      <Real Name="X">0</Real>
+      <Real Name="Y">0</Real>
+      <Real Name="Z">50</Real>
+    </Vector>
+  </Sequence>
+  <Real Name="Potential energy">51</Real>
+</ReferenceData>
index 16d6ccd7408227be68d04e515f169c1a4d290314..4323f44e6cb1d28e275210a799ba15169f5d9e16 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 up the module library
+add_library(math INTERFACE)
+
 file(GLOB MATH_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${MATH_SOURCES} PARENT_SCOPE)
 
-# TODO: (https://gitlab.com/gromacs/gromacs/-/issues/988) Find a new convention for defining public API.
-install(FILES
-       do_fit.h
-       functions.h
-       units.h
-       utilities.h
-       vec.h
-        vectypes.h
-        DESTINATION include/gromacs/math)
-
-if(GMX_INSTALL_LEGACY_API)
-  install(FILES
-         do_fit.h
-         units.h
-         utilities.h
-          DESTINATION include/gromacs/math)
-endif()
+# Source files have the following private module dependencies.
+target_link_libraries(math PRIVATE
+                      #                      gmxlib
+                      #                      math
+                      #                      mdtypes
+                      #                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(math PUBLIC
+target_include_directories(math INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(math PUBLIC
+target_link_libraries(math INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when fileio is an OBJECT target
+#target_link_libraries(math PUBLIC legacy_api)
+#target_link_libraries(math PRIVATE common)
+
+# Module dependencies
+# fileio interfaces convey transitive dependence on these modules.
+#target_link_libraries(math PUBLIC
+target_link_libraries(math INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(math PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(math PRIVATE legacy_modules)
 
 
 if (BUILD_TESTING)
index 2451283b1f232a1e3ef9eb7551872e0c47508546..0312878d5e3a224715a8518491f790e4211ce34a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +43,9 @@
 #ifndef GMX_MATH_COORDINATETRANSFORMATION_H
 #define GMX_MATH_COORDINATETRANSFORMATION_H
 
+#include <memory>
+
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/classhelpers.h"
 
 #include "matrix.h"
 
@@ -91,7 +92,7 @@ public:
 
 private:
     class Impl;
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \libinternal \brief Transform coordinates in three dimensions by first
@@ -134,7 +135,7 @@ public:
 
 private:
     class Impl;
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \libinternal
index 2d14fd6fc6280adfc5646ddfab8c1e1bf6d13955..6cfcc15305d1afddeb78621d299067890a059e4e 100644 (file)
@@ -104,8 +104,9 @@ DensitySimilarityInnerProduct::DensitySimilarityInnerProduct(density referenceDe
     const auto numVoxels = gradient_.asConstView().mapping().required_span_size();
     /* the gradient for the inner product measure of fit is constant and does not
      * depend on the compared density, so it is pre-computed here */
-    std::transform(begin(referenceDensity_), end(referenceDensity_), begin(gradient_),
-                   [numVoxels](float x) { return x / numVoxels; });
+    std::transform(begin(referenceDensity_), end(referenceDensity_), begin(gradient_), [numVoxels](float x) {
+        return x / numVoxels;
+    });
 }
 
 real DensitySimilarityInnerProduct::similarity(density comparedDensity)
@@ -194,8 +195,12 @@ real DensitySimilarityRelativeEntropy::similarity(density comparedDensity)
     {
         GMX_THROW(RangeError("Reference density and compared density need to have same extents."));
     }
-    return std::inner_product(begin(referenceDensity_), end(referenceDensity_),
-                              begin(comparedDensity), 0., std::plus<>(), relativeEntropyAtVoxel);
+    return std::inner_product(begin(referenceDensity_),
+                              end(referenceDensity_),
+                              begin(comparedDensity),
+                              0.,
+                              std::plus<>(),
+                              relativeEntropyAtVoxel);
 }
 
 DensitySimilarityMeasure::density DensitySimilarityRelativeEntropy::gradient(density comparedDensity)
@@ -204,8 +209,11 @@ DensitySimilarityMeasure::density DensitySimilarityRelativeEntropy::gradient(den
     {
         GMX_THROW(RangeError("Reference density and compared density need to have same extents."));
     }
-    std::transform(begin(referenceDensity_), end(referenceDensity_), begin(comparedDensity),
-                   begin(gradient_), relativeEntropyGradientAtVoxel);
+    std::transform(begin(referenceDensity_),
+                   end(referenceDensity_),
+                   begin(comparedDensity),
+                   begin(gradient_),
+                   relativeEntropyGradientAtVoxel);
     return gradient_.asConstView();
 }
 
@@ -245,7 +253,7 @@ CrossCorrelationEvaluationHelperValues evaluateHelperValues(DensitySimilarityMea
 
     index i = 0;
 
-    auto referenceIterator = begin(reference);
+    const auto* referenceIterator = begin(reference);
     for (const real comp : compared)
     {
         const real refHelper        = *referenceIterator - helperValues.meanReference;
@@ -276,7 +284,7 @@ public:
     {
     }
     //! Evaluate the cross correlation gradient at a voxel
-    real operator()(real reference, real comparison)
+    real operator()(real reference, real comparison) const
     {
         return prefactor_
                * (reference - meanReference_ - comparisonPrefactor_ * (comparison - meanComparison_));
@@ -361,8 +369,11 @@ DensitySimilarityMeasure::density DensitySimilarityCrossCorrelation::gradient(de
     CrossCorrelationEvaluationHelperValues helperValues =
             evaluateHelperValues(referenceDensity_, comparedDensity);
 
-    std::transform(begin(referenceDensity_), end(referenceDensity_), begin(comparedDensity),
-                   begin(gradient_), CrossCorrelationGradientAtVoxel(helperValues));
+    std::transform(begin(referenceDensity_),
+                   end(referenceDensity_),
+                   begin(comparedDensity),
+                   begin(gradient_),
+                   CrossCorrelationGradientAtVoxel(helperValues));
 
     return gradient_.asConstView();
 }
index 246d6610b0e4404ef02475c408f4d7820ac818fd..0f33d62a01cec035e33c14325560ab29518f7970 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +43,9 @@
 #ifndef GMX_MATH_DENSITYFIT_H
 #define GMX_MATH_DENSITYFIT_H
 
+#include <memory>
+
 #include "gromacs/mdspan/extensions.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/real.h"
 
 namespace gmx
index b3c869463934222e3be7052656cbce593132d70a..a389054fbab95737178aedfa4c3056314949e018 100644 (file)
@@ -107,8 +107,8 @@ RVec DensityFittingForce::Impl::evaluateForce(const GaussianSpreadKernelParamete
     {
         // multiply with amplitude so that Gauss3D = (amplitude * Gauss_x) * Gauss_y * Gauss_z
         const float gauss1DAmplitude = dimension > XX ? 1.0 : localParameters.amplitude_;
-        gauss1d_[dimension].spread(gauss1DAmplitude, localParameters.coordinate_[dimension]
-                                                             - closestLatticePoint[dimension]);
+        gauss1d_[dimension].spread(
+                gauss1DAmplitude, localParameters.coordinate_[dimension] - closestLatticePoint[dimension]);
     }
 
     const auto spreadZY = outerProductZY_(gauss1d_[ZZ].view(), gauss1d_[YY].view());
@@ -117,7 +117,8 @@ RVec DensityFittingForce::Impl::evaluateForce(const GaussianSpreadKernelParamete
                                 latticeSpreadRange_[YY] - closestLatticePoint[YY],
                                 latticeSpreadRange_[ZZ] - closestLatticePoint[ZZ]);
 
-    const DVec differenceVectorScale  = { 1. / (square(sigma_[XX])), 1. / (square(sigma_[YY])),
+    const DVec differenceVectorScale  = { 1. / (square(sigma_[XX])),
+                                         1. / (square(sigma_[YY])),
                                          1. / (square(sigma_[ZZ])) };
     const DVec differenceVectorOffset = scaleByVector(
             spreadRange.begin().toDVec() - localParameters.coordinate_.toDVec(), differenceVectorScale);
index 5c16dadc77c70e2a1c9440dbba99b6fb56e5aed2..904ddea75f6cc572a31f613d7cfe1a0444995982 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * \ingroup module_math
  */
 
+#include <memory>
+
 #include "gromacs/math/gausstransform.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/mdspan/extensions.h"
 #include "gromacs/mdspan/mdspan.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
@@ -105,7 +106,7 @@ public:
 
 private:
     class Impl;
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index b8be02f06dbc903616c8643ef6e2a9209a7bcc7a..dd3559438a25e61af7f04a010c2c19ebe81b413e 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "do_fit.h"
+#include "gromacs/math/do_fit.h"
 
 #include <cmath>
 #include <cstdio>
 
 #include "gromacs/linearalgebra/nrjac.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/utility/fatalerror.h"
index 2cd3e3280a82a23ff8371ade0c91b0aaa7e55ba8..7269a47b0a64d4e0900af6f2c4a0a66224ed4cbe 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,2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 @@
 
 #include "gmxpre.h"
 
-#include "functions.h"
+#include "gromacs/math/functions.h"
 
 #include "config.h"
 
@@ -57,6 +57,7 @@
 #    include <intrin.h> // _BitScanReverse, _BitScanReverse64
 #endif
 
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/utility/gmxassert.h"
 
index 111e2c7ccd0510f14459a4eae22dc820a1d51c3b..a539062ac770db943f504285eb952e29a13ff62b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,7 +51,9 @@
 
 #include "gromacs/math/functions.h"
 #include "gromacs/math/multidimarray.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
+#include "gromacs/utility/basedefinitions.h"
 
 namespace gmx
 {
@@ -115,10 +117,10 @@ GaussianOn1DLattice::Impl::Impl(int numGridPointsForSpreadingHalfWidth, real sig
             std::min(maxEvaluatedSpreadDistance_,
                      static_cast<int>(std::floor(sigma * sqrt(-2.0 * c_logMinFloat))) - 1);
 
-    std::generate_n(std::back_inserter(e3_), maxEvaluatedSpreadDistance_ + 1,
-                    [sigma, latticeIndex = 0]() mutable {
-                        return std::exp(-0.5 * square(latticeIndex++ / sigma));
-                    });
+    std::generate_n(
+            std::back_inserter(e3_), maxEvaluatedSpreadDistance_ + 1, [sigma, latticeIndex = 0]() mutable {
+                return std::exp(-0.5 * square(latticeIndex++ / sigma));
+            });
 
     std::fill(std::begin(spreadingResult_), std::end(spreadingResult_), 0.);
 };
@@ -235,7 +237,8 @@ IVec rangeBeginWithinLattice(const IVec& index, const IVec& range)
  */
 IVec rangeEndWithinLattice(const IVec& index, const dynamicExtents3D& extents, const IVec& range)
 {
-    IVec extentAsIvec(static_cast<int>(extents.extent(ZZ)), static_cast<int>(extents.extent(YY)),
+    IVec extentAsIvec(static_cast<int>(extents.extent(ZZ)),
+                      static_cast<int>(extents.extent(YY)),
                       static_cast<int>(extents.extent(XX)));
     return elementWiseMin(extentAsIvec, index + range);
 }
@@ -254,8 +257,9 @@ mdspan<const float, dynamic_extent, dynamic_extent> OuterProductEvaluator::
     for (gmx::index xIndex = 0; xIndex < ssize(x); ++xIndex)
     {
         const auto xValue = x[xIndex];
-        std::transform(std::begin(y), std::end(y), begin(data_.asView()[xIndex]),
-                       [xValue](float yValue) { return xValue * yValue; });
+        std::transform(std::begin(y), std::end(y), begin(data_.asView()[xIndex]), [xValue](float yValue) {
+            return xValue * yValue;
+        });
     }
     return data_.asConstView();
 }
@@ -356,8 +360,8 @@ void GaussTransform3D::Impl::add(const GaussianSpreadKernelParameters::PositionA
     {
         // multiply with amplitude so that Gauss3D = (amplitude * Gauss_x) * Gauss_y * Gauss_z
         const float gauss1DAmplitude = dimension > XX ? 1.0 : localParameters.amplitude_;
-        gauss1d_[dimension].spread(gauss1DAmplitude, localParameters.coordinate_[dimension]
-                                                             - closestLatticePoint[dimension]);
+        gauss1d_[dimension].spread(
+                gauss1DAmplitude, localParameters.coordinate_[dimension] - closestLatticePoint[dimension]);
     }
 
     const auto spreadZY         = outerProductZY_(gauss1d_[ZZ].view(), gauss1d_[YY].view());
index 40ef38d79024a835d010ec7e9dae2c5fd4d136ea..f00e43fd3031779d2706bcbd1fa614e03a67ed0b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_MATH_GAUSSTRANSFORM_H
 #define GMX_MATH_GAUSSTRANSFORM_H
 
+#include <memory>
 #include <vector>
 
 #include "gromacs/math/multidimarray.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/mdspan/extensions.h"
 #include "gromacs/mdspan/mdspan.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/real.h"
 
 namespace gmx
@@ -121,7 +121,7 @@ public:
 
 private:
     class Impl;
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \libinternal \brief Parameters for density spreading kernels.
@@ -204,7 +204,7 @@ public:
 
 private:
     class Impl;
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \internal \brief A 3-orthotope over integer intervals.
index b329647bf1d5af2f5e90a28e838d1e1f8000ee43..87069cf7ec574a65a1164a36b4e3f557c21def1e 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,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +47,6 @@ struct t_complex
     real re, im;
 };
 
-typedef t_complex cvec[DIM];
-
 static t_complex rcmul(real r, t_complex c)
 {
     t_complex d;
index 662d6cf791323f646bee65789a3642673afb783f..fffbce5fc56658663e262cef0850ec09a7ebc5fd 100644 (file)
@@ -50,8 +50,14 @@ namespace gmx
 Matrix3x3 transpose(Matrix3x3ConstSpan matrixView)
 {
 
-    return Matrix3x3({ matrixView(0, 0), matrixView(1, 0), matrixView(2, 0), matrixView(0, 1),
-                       matrixView(1, 1), matrixView(2, 1), matrixView(0, 2), matrixView(1, 2),
+    return Matrix3x3({ matrixView(0, 0),
+                       matrixView(1, 0),
+                       matrixView(2, 0),
+                       matrixView(0, 1),
+                       matrixView(1, 1),
+                       matrixView(2, 1),
+                       matrixView(0, 2),
+                       matrixView(1, 2),
                        matrixView(2, 2) });
 }
 
index 9bb1df25af43ca1424af78e4bec542c3922febbb..d0d348a1ab386ffef08a41ca88658434367f27ec 100644 (file)
@@ -72,8 +72,10 @@ std::vector<real> linearCombination(real alpha, ArrayRef<const real> a, real bet
     GMX_ASSERT(a.size() == b.size(),
                "Input vectors have to have the same size to evaluate their linear combination.");
     std::vector<real> result(a.size());
-    std::transform(std::begin(a), std::end(a), std::begin(b), std::begin(result),
-                   [alpha, beta](auto a, auto b) { return alpha * a + beta * b; });
+    std::transform(
+            std::begin(a), std::end(a), std::begin(b), std::begin(result), [alpha, beta](auto a, auto b) {
+                return alpha * a + beta * b;
+            });
     return result;
 };
 
@@ -151,17 +153,20 @@ RealFunctionvalueAtCoordinate
 NelderMeadSimplex::evaluateExpansionPoint(const std::function<real(ArrayRef<const real>)>& f) const
 {
     const std::vector<real> expansionPointCoordinate =
-            linearCombination(1 - defaultNelderMeadParameters.gamma_, centroidWithoutWorstPoint_,
-                              defaultNelderMeadParameters.gamma_, reflectionPointCoordinates_);
+            linearCombination(1 - defaultNelderMeadParameters.gamma_,
+                              centroidWithoutWorstPoint_,
+                              defaultNelderMeadParameters.gamma_,
+                              reflectionPointCoordinates_);
     return { expansionPointCoordinate, f(expansionPointCoordinate) };
 }
 
 RealFunctionvalueAtCoordinate
 NelderMeadSimplex::evaluateContractionPoint(const std::function<real(ArrayRef<const real>)>& f) const
 {
-    std::vector<real> contractionPoint =
-            linearCombination(1 - defaultNelderMeadParameters.rho_, centroidWithoutWorstPoint_,
-                              defaultNelderMeadParameters.rho_, worstVertex().coordinate_);
+    std::vector<real> contractionPoint = linearCombination(1 - defaultNelderMeadParameters.rho_,
+                                                           centroidWithoutWorstPoint_,
+                                                           defaultNelderMeadParameters.rho_,
+                                                           worstVertex().coordinate_);
     return { contractionPoint, f(contractionPoint) };
 }
 
@@ -173,7 +178,9 @@ void NelderMeadSimplex::swapOutWorst(const RealFunctionvalueAtCoordinate& newVer
     // find the point to insert the new vertex, so that the simplex vertices
     // keep being sorted according to function value
     const auto insertionPoint = std::lower_bound(
-            std::begin(simplex_), std::end(simplex_), newVertex.value_,
+            std::begin(simplex_),
+            std::end(simplex_),
+            newVertex.value_,
             [](const RealFunctionvalueAtCoordinate& lhs, real value) { return lhs.value_ < value; });
     simplex_.insert(insertionPoint, newVertex);
     // now that the simplex has changed, it has a new centroid and reflection point
@@ -185,11 +192,15 @@ void NelderMeadSimplex::shrinkSimplexPointsExceptBest(const std::function<real(A
     std::vector<real> bestPointCoordinate = simplex_.front().coordinate_;
     // skipping over the first simplex vertex, pull points closer to the best
     // vertex
-    std::transform(std::next(std::begin(simplex_)), std::end(simplex_), std::next(std::begin(simplex_)),
+    std::transform(std::next(std::begin(simplex_)),
+                   std::end(simplex_),
+                   std::next(std::begin(simplex_)),
                    [bestPointCoordinate, f](const RealFunctionvalueAtCoordinate& d) -> RealFunctionvalueAtCoordinate {
-                       const std::vector<real> shrinkPoint = linearCombination(
-                               defaultNelderMeadParameters.sigma_, d.coordinate_,
-                               1 - defaultNelderMeadParameters.sigma_, bestPointCoordinate);
+                       const std::vector<real> shrinkPoint =
+                               linearCombination(defaultNelderMeadParameters.sigma_,
+                                                 d.coordinate_,
+                                                 1 - defaultNelderMeadParameters.sigma_,
+                                                 bestPointCoordinate);
                        return { shrinkPoint, f(shrinkPoint) };
                    });
 
@@ -209,9 +220,10 @@ real NelderMeadSimplex::orientedLength() const
     {
         const std::vector<real> differenceVector =
                 linearCombination(1, firstSimplexVertexCoordinate, -1, simplexVertex.coordinate_);
-        const real thisLength =
-                std::accumulate(std::begin(differenceVector), std::end(differenceVector), 0.,
-                                [](real sum, real value) { return sum + value * value; });
+        const real thisLength = std::accumulate(
+                std::begin(differenceVector), std::end(differenceVector), 0., [](real sum, real value) {
+                    return sum + value * value;
+                });
         result = std::max(result, thisLength);
     }
     return sqrt(result);
@@ -221,23 +233,28 @@ void NelderMeadSimplex::updateCentroidAndReflectionPoint()
 {
     // intialize with first vertex, then add up all other vertex coordinates
     // expect last one
-    centroidWithoutWorstPoint_ = std::accumulate(
-            std::next(std::begin(simplex_)), std::prev(std::end(simplex_)), simplex_.front().coordinate_,
-            [](std::vector<real> sum, const RealFunctionvalueAtCoordinate& x) {
-                std::transform(std::begin(sum), std::end(sum), std::begin(x.coordinate_),
-                               std::begin(sum), std::plus<>());
-                return sum;
-            });
+    centroidWithoutWorstPoint_ =
+            std::accumulate(std::next(std::begin(simplex_)),
+                            std::prev(std::end(simplex_)),
+                            simplex_.front().coordinate_,
+                            [](std::vector<real> sum, const RealFunctionvalueAtCoordinate& x) {
+                                std::transform(std::begin(sum),
+                                               std::end(sum),
+                                               std::begin(x.coordinate_),
+                                               std::begin(sum),
+                                               std::plus<>());
+                                return sum;
+                            });
 
     // divide the summed up coordinates by N (the simplex has N+1 vertices)
-    std::transform(std::begin(centroidWithoutWorstPoint_), std::end(centroidWithoutWorstPoint_),
+    std::transform(std::begin(centroidWithoutWorstPoint_),
+                   std::end(centroidWithoutWorstPoint_),
                    std::begin(centroidWithoutWorstPoint_),
                    [n = simplex_.size() - 1](const auto& x) { return x / n; });
 
     // now, that we have evaluated the centroid, update the reflection points
-    reflectionPointCoordinates_ =
-            linearCombination(defaultNelderMeadParameters.alpha_ + 1, centroidWithoutWorstPoint_,
-                              -1, worstVertex().coordinate_);
+    reflectionPointCoordinates_ = linearCombination(
+            defaultNelderMeadParameters.alpha_ + 1, centroidWithoutWorstPoint_, -1, worstVertex().coordinate_);
 }
 
 } // namespace gmx
index 4535fd86b47c42be7fe7d22ea81dfc0777818fac..7cf3b0c0baa62961ad326007baa32129762cae7b 100644 (file)
@@ -60,7 +60,8 @@ OptimisationResult nelderMead(const std::function<real(ArrayRef<const real>)>& f
     // the oriented simplex length is smaller or equal a given number.
     const real minimumSimplexLength = minimumRelativeSimplexLength * nelderMeadSimplex.orientedLength();
     for (int currentStep = 0;
-         nelderMeadSimplex.orientedLength() > minimumSimplexLength && currentStep < maxSteps; ++currentStep)
+         nelderMeadSimplex.orientedLength() > minimumSimplexLength && currentStep < maxSteps;
+         ++currentStep)
     {
 
         // see if simplex can by improved by reflecing the worst vertex at the centroid
diff --git a/src/gromacs/math/tests/.clang-tidy b/src/gromacs/math/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 199ecbf89131e6b881a5501e9d58dcbe0489cf3b..447ff526e107d17c3896b0d49a418eef0ca01fb3 100644 (file)
@@ -1,7 +1,8 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2014,2015,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2014,2015,2018,2019, The GROMACS development team.
+# Copyright (c) 2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
index a06f144236454fe2e2049616269dbb23e5cc1eb2..3990584c16e5581df9e8c67d2b908026e005a204 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -170,8 +170,8 @@ TYPED_TEST(ArrayRefWithPaddingTest, AssignFromPaddedVectorWorks)
 
 TYPED_TEST(ArrayRefWithPaddingTest, ConstructFromPointersWorks)
 {
-    typename TestFixture::ArrayRefType arrayRef(this->v.data(), this->v.data() + this->v.size(),
-                                                this->v.data() + this->v.paddedSize());
+    typename TestFixture::ArrayRefType arrayRef(
+            this->v.data(), this->v.data() + this->v.size(), this->v.data() + this->v.paddedSize());
     this->runTests(arrayRef);
 }
 
index 19472d019afe21360bfcb83b583af322eef3e6ca..7fdf5561db1ab028cb98fa5116fed60649cecd11 100644 (file)
@@ -226,11 +226,14 @@ TEST_F(AffineTransformationTest, applyTransformationToVectors)
         RVec vectorTransformed = vector;
         affineTransformation(&vectorTransformed);
         // need relaxed tolerance here, due to the number of operations involved
-        EXPECT_REAL_EQ_TOL((*expected)[XX], vectorTransformed[XX],
+        EXPECT_REAL_EQ_TOL((*expected)[XX],
+                           vectorTransformed[XX],
                            relativeToleranceAsFloatingPoint((*expected)[XX], 1e-5));
-        EXPECT_REAL_EQ_TOL((*expected)[YY], vectorTransformed[YY],
+        EXPECT_REAL_EQ_TOL((*expected)[YY],
+                           vectorTransformed[YY],
                            relativeToleranceAsFloatingPoint((*expected)[YY], 1e-5));
-        EXPECT_REAL_EQ_TOL((*expected)[ZZ], vectorTransformed[ZZ],
+        EXPECT_REAL_EQ_TOL((*expected)[ZZ],
+                           vectorTransformed[ZZ],
                            relativeToleranceAsFloatingPoint((*expected)[ZZ], 1e-5));
         ++expected;
     }
index 1ebda302a7b0d7a228b041ca7e4b181048b91cad..fc6ad029e56b034609537e189ae54ec084103fcc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +88,7 @@ TEST(DensitySimilarityTest, InnerProductGradientIsCorrect)
     std::iota(begin(comparedDensity), end(comparedDensity), -18);
 
     std::vector<float> expectedSimilarityGradient;
-    std::copy(begin(referenceDensity), end(referenceDensity),
-              std::back_inserter(expectedSimilarityGradient));
+    std::copy(begin(referenceDensity), end(referenceDensity), std::back_inserter(expectedSimilarityGradient));
     for (auto& x : expectedSimilarityGradient)
     {
         x /= comparedDensity.asConstView().mapping().required_span_size();
index b3d69670a42f8923e301f05914a8c42993d2a9bd..f2fa71d3bbbf887f900c740c413f77d8ecc67ec8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
 
 #include "gromacs/math/multidimarray.h"
 #include "gromacs/math/utilities.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdspan/extensions.h"
 
index 2976200e984d926cb26dcce68edeac245df89d2f..a797f2a399d23da2b044ec9ac0a628087b832bfa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +90,8 @@ TEST_F(StructureSimilarityTest, YieldsCorrectRho)
 
 TEST_F(StructureSimilarityTest, YieldsCorrectRMSDWithIndex)
 {
-    EXPECT_REAL_EQ_TOL(sqrt(2.0), rmsdev_ind(index_.size(), index_.data(), m_, x1_, x2_),
-                       defaultRealTolerance());
+    EXPECT_REAL_EQ_TOL(
+            sqrt(2.0), rmsdev_ind(index_.size(), index_.data(), m_, x1_, x2_), defaultRealTolerance());
 }
 
 TEST_F(StructureSimilarityTest, YieldsCorrectRhoWidthIndex)
index b444ee78412448af973b9f75c279a9002f4314c0..939a08da2eb5f5c8fee3575e1c6161cc7cd0466b 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019 by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -356,4 +357,37 @@ TEST(FunctionTest, ErfAndErfInvAreInversesDouble)
     }
 }
 
+template<typename T>
+class FunctionTestIntegerTypes : public ::testing::Test
+{
+};
+
+typedef ::testing::Types<char, unsigned char, int, unsigned int, long, unsigned long> IntegerTypes;
+TYPED_TEST_CASE(FunctionTestIntegerTypes, IntegerTypes);
+
+TYPED_TEST(FunctionTestIntegerTypes, IsPowerOfTwo)
+{
+    if (std::is_signed_v<TypeParam>)
+    {
+        EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(std::numeric_limits<TypeParam>::min()));
+        EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(-16));
+        EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(-3));
+        EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(-2));
+        EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(-1));
+    }
+    EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(0));
+    EXPECT_EQ(true, gmx::isPowerOfTwo<TypeParam>(1));
+    EXPECT_EQ(true, gmx::isPowerOfTwo<TypeParam>(2));
+    EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(3));
+    EXPECT_EQ(true, gmx::isPowerOfTwo<TypeParam>(4));
+    EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(5));
+    EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(6));
+    EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(24));
+    EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(63));
+    EXPECT_EQ(true, gmx::isPowerOfTwo<TypeParam>(64));
+    EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(66));
+    // Max for any type is always 2^x - 1
+    EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(std::numeric_limits<TypeParam>::max()));
+}
+
 } // namespace
index a0f35646ac435ba7357a86c5e447831e072a60fc..06faafb4dfaa7e5490eb248deb0384645780931a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,11 @@ TEST(GaussianOn1DLattice, isCorrect)
     FloatingPointTolerance tolerance(defaultFloatTolerance());
     const real             amplitude = 1.0;
     gauss1d.spread(amplitude, shift);
-    std::array<float, 2 * spreadWidth + 1> expected = {
-        0.0047816522419452667236328125, 0.2613909542560577392578125, 0.65811407566070556640625,
-        0.07631497085094451904296875, 0.000407583254855126142501831054688
-    };
+    std::array<float, 2 * spreadWidth + 1> expected = { 0.0047816522419452667236328125,
+                                                        0.2613909542560577392578125,
+                                                        0.65811407566070556640625,
+                                                        0.07631497085094451904296875,
+                                                        0.000407583254855126142501831054688 };
     EXPECT_THAT(expected, Pointwise(FloatEq(tolerance), viewOnResult));
 }
 
@@ -109,13 +110,14 @@ TEST(GaussianOn1DLattice, complementaryAmplitudesSumToZero)
     gauss1d.spread(amplitude, shift);
     std::vector<float> sumOfComplementaryGaussians;
     // keep a copy of the first Gaussian
-    std::copy(std::begin(viewOnResult), std::end(viewOnResult),
-              std::back_inserter(sumOfComplementaryGaussians));
+    std::copy(std::begin(viewOnResult), std::end(viewOnResult), std::back_inserter(sumOfComplementaryGaussians));
 
     gauss1d.spread(-amplitude, shift);
     // add the two spread Gaussians
-    std::transform(std::begin(viewOnResult), std::end(viewOnResult),
-                   std::begin(sumOfComplementaryGaussians), std::begin(sumOfComplementaryGaussians),
+    std::transform(std::begin(viewOnResult),
+                   std::end(viewOnResult),
+                   std::begin(sumOfComplementaryGaussians),
+                   std::begin(sumOfComplementaryGaussians),
                    std::plus<>());
     // Expect all zeros
     std::array<float, 2 * spreadWidth + 1> expected = {};
index b82f51454157d1cf93054614d3ef9fa41ee0d7b7..7e4136ecb064110b8b791eddad3ffaa97093d620 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -291,7 +291,7 @@ TEST_F(MultiDimArrayTest, viewBegin)
 TEST_F(MultiDimArrayTest, viewEnd)
 {
     static_array_type::view_type view = staticArray_.asView();
-    auto                         x    = end(view);
+    auto*                        x    = end(view);
     --x;
     view(2, 2) = testNumber_;
     EXPECT_EQ(*x, testNumber_);
@@ -308,8 +308,8 @@ TEST_F(MultiDimArrayTest, constViewConstBegin)
 TEST_F(MultiDimArrayTest, constViewConstEnd)
 {
     staticArray_(2, 2) = testNumber_;
-    const auto view    = staticArray_.asConstView();
-    auto       x       = end(view);
+    const auto  view   = staticArray_.asConstView();
+    const auto* x      = end(view);
     --x;
     EXPECT_EQ(*x, testNumber_);
 }
index 3cbaab7b72c75fa4cb919bf4cb5cf64b13354b3a..7049e97433da18558145017b15125ed69c86f4d4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -118,6 +118,24 @@ TEST(RVecTest, WorksAs_rvec_Array)
     EXPECT_EQ(4, r[1][ZZ]);
 }
 
+TEST(RVecTest, ComparesEqual)
+{
+    RVec a(1, 2, 3);
+    RVec b(1, 2, 3);
+    RVec c(1, 2, 2);
+    EXPECT_EQ(a == b, true);
+    EXPECT_EQ(a == c, false);
+}
+
+TEST(RVecTest, ComparesUnequal)
+{
+    RVec a(1, 2, 3);
+    RVec b(1, 2, 3);
+    RVec c(1, 2, 2);
+    EXPECT_EQ(a != b, false);
+    EXPECT_EQ(a != c, true);
+}
+
 /*! \brief
  * Test overloaded math operations
  */
diff --git a/src/gromacs/math/units.cpp b/src/gromacs/math/units.cpp
deleted file mode 100644 (file)
index 6881111..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2010,2011,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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 "units.h"
-
-#include <cstdio>
-
-#include "gromacs/utility/cstringutil.h"
-
-double convert2gmx(double x, int unit)
-{
-    switch (unit)
-    {
-        case eg2cAngstrom: return x * A2NM;
-        case eg2cNm: return x;
-        case eg2cBohr: return x * BOHR2NM;
-        case eg2cKcal_Mole: return x / CAL2JOULE;
-        case eg2cHartree: return x * ONE_4PI_EPS0 / BOHR2NM; // NOLINT bugprone-branch-clone
-        case eg2cHartree_e: return x * ONE_4PI_EPS0 / BOHR2NM;
-        case eg2cAngstrom3: return x * A2NM * A2NM * A2NM;
-        case eg2cCoulomb: return x / E_CHARGE;
-        case eg2cDebye: return x * DEBYE2ENM;
-        case eg2cElectron: return x;
-        case eg2cBuckingham: return x * A2NM * DEBYE2ENM;
-        default: fprintf(stderr, "Unknown unit %d, not converting.\n", unit);
-    }
-    return x;
-}
-
-double gmx2convert(double x, int unit)
-{
-    switch (unit)
-    {
-        case eg2cAngstrom: return x / A2NM;
-        case eg2cNm: return x;
-        case eg2cBohr: return x / BOHR2NM;
-        case eg2cKcal_Mole: return x * CAL2JOULE;
-        case eg2cHartree: return x / (ONE_4PI_EPS0 / BOHR2NM); // NOLINT bugprone-branch-clone
-        case eg2cHartree_e: return x / (ONE_4PI_EPS0 / BOHR2NM);
-        case eg2cAngstrom3: return x / (A2NM * A2NM * A2NM);
-        case eg2cCoulomb: return x * E_CHARGE;
-        case eg2cDebye: return x / DEBYE2ENM;
-        case eg2cElectron: return x;
-        case eg2cBuckingham: return x / (A2NM * DEBYE2ENM);
-        default: fprintf(stderr, "Unknown unit %d, not converting.\n", unit);
-    }
-    return x;
-}
-
-/* This has to have the same order as the enums. */
-static const char* eg2c_names[eg2cNR] = { "Angstrom", "Nm",        "Bohr",      "Kcal_Mole",
-                                          "Hartree",  "Hartree_e", "Angstrom3", "Coulomb",
-                                          "Debye",    "Electron",  "Buckingham" };
-
-int string2unit(char* string)
-{
-    int i;
-
-    for (i = 0; (i < eg2cNR); i++)
-    {
-        if (gmx_strcasecmp(string, eg2c_names[i]) == 0)
-        {
-            return i;
-        }
-    }
-    return -1;
-}
-
-const char* unit2string(int unit)
-{
-    if ((unit >= 0) && (unit < eg2cNR))
-    {
-        return eg2c_names[unit];
-    }
-
-    return nullptr;
-}
diff --git a/src/gromacs/math/units.h b/src/gromacs/math/units.h
deleted file mode 100644 (file)
index 865fd31..0000000
+++ /dev/null
@@ -1,171 +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) 2012,2014,2015,2018,2019, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_MATH_UNITS_H
-#define GMX_MATH_UNITS_H
-
-/*
- * Physical constants to be used in Gromacs.
- * No constants (apart from 0, 1 or 2) should
- * be anywhere else in the code.
- */
-
-#include "gromacs/math/utilities.h"
-
-#define ANGSTROM (1e-10)           /* Old...   */
-#define KILO (1e3)                 /* Thousand */
-#define NANO (1e-9)                /* A Number */
-#define PICO (1e-12)               /* A Number */
-#define A2NM (ANGSTROM / NANO)     /* NANO             */
-#define NM2A (NANO / ANGSTROM)     /* 10.0             */
-#define RAD2DEG (180.0 / M_PI)     /* Conversion       */
-#define DEG2RAD (M_PI / 180.0)     /* id               */
-#define CAL2JOULE (4.184)          /* Exact definition of the calorie */
-#define E_CHARGE (1.602176634e-19) /* Exact definition, Coulomb NIST 2018 CODATA */
-
-#define AMU (1.66053906660e-27)                     /* kg, NIST 2018 CODATA  */
-#define BOLTZMANN (1.380649e-23)                    /* (J/K, Exact definition, NIST 2018 CODATA */
-#define AVOGADRO (6.02214076e23)                    /* 1/mol, Exact definition, NIST 2018 CODATA */
-#define RGAS (BOLTZMANN * AVOGADRO)                 /* (J/(mol K))  */
-#define BOLTZ (RGAS / KILO)                         /* (kJ/(mol K)) */
-#define FARADAY (E_CHARGE * AVOGADRO)               /* (C/mol)      */
-#define ELECTRONVOLT (E_CHARGE * AVOGADRO / KILO)   /* (kJ/mol)   */
-#define PLANCK1 (6.62607015e-34)                    /* J/Hz, Exact definition, NIST 2018 CODATA */
-#define PLANCK (PLANCK1 * AVOGADRO / (PICO * KILO)) /* (kJ/mol) ps */
-
-#define EPSILON0_SI (8.8541878128e-12) /* F/m,  NIST 2018 CODATA */
-/* Epsilon in our MD units: (e^2 / Na (kJ nm)) == (e^2 mol/(kJ nm)) */
-#define EPSILON0 ((EPSILON0_SI * NANO * KILO) / (E_CHARGE * E_CHARGE * AVOGADRO))
-
-#define SPEED_OF_LIGHT (2.99792458e05)  /* units of nm/ps, Exact definition, NIST 2018 CODATA */
-#define ATOMICMASS_keV (931494.10242)   /* Atomic mass in keV, NIST 2018 CODATA   */
-#define ELECTRONMASS_keV (510.99895000) /* Electron mas in keV, NIST 2018 CODATA  */
-
-#define RYDBERG (1.0973731568160e-02) /* nm^-1, NIST 2018 CODATA */
-
-#define ONE_4PI_EPS0 (1.0 / (4.0 * M_PI * EPSILON0))
-#define FACEL (10.0 * ONE_4PI_EPS0)
-
-/* Pressure in MD units is:
- * 1 bar = 1e5 Pa = 1e5 kg m^-1 s^-2 = 1e-28 kg nm^-1 ps^-2 = 1e-28 / AMU amu nm^1 ps ^2
- */
-#define BAR_MDUNITS (1e5 * NANO * PICO * PICO / AMU)
-#define PRESFAC (1.0 / BAR_MDUNITS)
-
-/* DEBYE2ENM should be (1e-21*PICO)/(SPEED_OF_LIGHT*E_CHARGE*NANO*NANO),
- * but we need to factor out some of the exponents to avoid single-precision overflows.
- */
-#define DEBYE2ENM (1e-15 / (SPEED_OF_LIGHT * E_CHARGE))
-#define ENM2DEBYE (1.0 / DEBYE2ENM)
-
-/* to convert from a acceleration in (e V)/(amu nm) */
-/* FIELDFAC is also Faraday's constant and E_CHARGE/(1e6 AMU) */
-#define FIELDFAC (FARADAY / KILO)
-
-/* to convert AU to MD units: */
-#define HARTREE2KJ ((2.0 * RYDBERG * PLANCK * SPEED_OF_LIGHT) / AVOGADRO)
-#define BOHR2NM (0.0529177210903) /* nm^-1, NIST 2018 CODATA */
-#define HARTREE_BOHR2MD (HARTREE2KJ * AVOGADRO / BOHR2NM)
-
-
-/* The four basic units */
-#define unit_length "nm"
-#define unit_time "ps"
-#define unit_mass "u"
-#define unit_energy "kJ/mol"
-
-/* Temperature unit, T in this unit times BOLTZ give energy in unit_energy */
-#define unit_temp_K "K"
-
-/* Charge unit, electron charge, involves ONE_4PI_EPS0 */
-#define unit_charge_e "e"
-
-/* Pressure unit, pressure in basic units times PRESFAC gives this unit */
-#define unit_pres_bar "bar"
-
-/* Dipole unit, debye, conversion from the unit_charge_e involves ENM2DEBYE */
-#define unit_dipole_D "D"
-
-/* Derived units from basic units only */
-#define unit_vel unit_length "/" unit_time
-#define unit_volume unit_length "^3"
-#define unit_invtime "1/" unit_time
-
-/* Other derived units */
-#define unit_surft_bar unit_pres_bar " " unit_length
-
-/* SI units, conversion from basic units involves NANO, PICO and AMU */
-#define unit_length_SI "m"
-#define unit_time_SI "s"
-#define unit_mass_SI "kg"
-
-#define unit_density_SI unit_mass_SI "/" unit_length_SI "^3"
-#define unit_invvisc_SI unit_length_SI " " unit_time_SI "/" unit_mass_SI
-
-/* The routines below can be used for converting units from or to GROMACS
-   internal units. */
-enum
-{
-    eg2cAngstrom,
-    eg2cNm,
-    eg2cBohr,
-    eg2cKcal_Mole,
-    eg2cHartree,
-    eg2cHartree_e,
-    eg2cAngstrom3,
-    eg2cCoulomb,
-    eg2cDebye,
-    eg2cElectron,
-    eg2cBuckingham,
-    eg2cNR
-};
-
-/* Convert value x to GROMACS units. Energy -> Energy, Length -> Length etc.
-   The type of x is deduced from unit,
-   which should be taken from the enum above. */
-extern double convert2gmx(double x, int unit);
-
-/* Convert value x from GROMACS units to the desired one.
-   The type of return value is deduced from unit, see above */
-extern double gmx2convert(double x, int unit);
-
-/* Convert the string to one of the units supported. Returns -1 if not found. */
-extern int string2unit(char* string);
-
-/* Convert the unit to a string. Return NULL when unit is out of range. */
-extern const char* unit2string(int unit);
-
-#endif
index 3412f2c47208c4a6d591875ff40de9dab8e75e53..14b7dd38aa52cad73c3050ab2f38534ba363c73a 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "utilities.h"
+#include "gromacs/math/utilities.h"
+#include "gromacs/utility/real.h"
 
 #include "config.h"
 
-#include <cassert>
-#include <climits>
+#include <cstdint>
 #include <cmath>
 
-#include <algorithm>
 #include <cfenv>
 
 //! Floating point exception set that we use and care about
@@ -63,13 +62,13 @@ bool gmx_numzero(double a)
 }
 
 
-gmx_bool check_int_multiply_for_overflow(int64_t a, int64_t b, int64_t* result)
+bool check_int_multiply_for_overflow(int64_t a, int64_t b, int64_t* result)
 {
     int64_t sign = 1;
     if ((0 == a) || (0 == b))
     {
         *result = 0;
-        return TRUE;
+        return true;
     }
     if (a < 0)
     {
@@ -84,10 +83,10 @@ gmx_bool check_int_multiply_for_overflow(int64_t a, int64_t b, int64_t* result)
     if (INT64_MAX / b < a)
     {
         *result = (sign > 0) ? INT64_MAX : INT64_MIN;
-        return FALSE;
+        return false;
     }
     *result = sign * a * b;
-    return TRUE;
+    return true;
 }
 
 int gmx_feenableexcept()
@@ -140,3 +139,16 @@ int gmx_fedisableexcept()
     return -1;
 #endif
 }
+
+bool gmxShouldEnableFPExceptions()
+{
+#if defined(NDEBUG)
+    return false; // Release build
+#elif ((defined __clang__ || (defined(__GNUC__) && __GNUC__ == 7)) && defined __OPTIMIZE__)
+    return false; // Buggy compiler
+#elif GMX_GPU_SYCL
+    return false; // avoid spurious FPE during SYCL JIT
+#else
+    return true;
+#endif
+}
index 22c75d49f76cc18409604d8a26c11c7756561c5f..1914b9d18e9509186e56dd87a49f3376427b9616 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,2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,13 +50,28 @@ void cmp_rvec(FILE* fp, const char* s, int index, const rvec i1, const rvec i2,
     {
         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]);
+            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]);
+            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]);
         }
     }
 }
@@ -67,13 +82,20 @@ void cmp_ivec(FILE* fp, const char* s, int index, const ivec i1, const ivec i2)
     {
         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]);
+            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]);
+            fprintf(fp, "%s (%8d,%8d,%8d - %8d,%8d,%8d)\n", s, i1[XX], i1[YY], i1[ZZ], i2[XX], i2[YY], i2[ZZ]);
         }
     }
 }
index 6e640d69ce6bf817197c6d03157692e4e0d22f2e..4fde70e8bdb301aa2d6c19cb33810c63ca71524b 100644 (file)
@@ -89,8 +89,13 @@ void pr_ivec_block(FILE* fp, int indent, const char* title, const int vec[], int
             else
             {
                 pr_indent(fp, indent);
-                fprintf(fp, "%s[%d,...,%d] = {%d,...,%d}\n", title, bShowNumbers ? i : -1,
-                        bShowNumbers ? j - 1 : -1, vec[i], vec[j - 1]);
+                fprintf(fp,
+                        "%s[%d,...,%d] = {%d,...,%d}\n",
+                        title,
+                        bShowNumbers ? i : -1,
+                        bShowNumbers ? j - 1 : -1,
+                        vec[i],
+                        vec[j - 1]);
                 i = j;
             }
         }
index 949a3057972b5275f3aab35af1667cb72af66f78..060f6160d7ba9dea6d9de1bdb53eb6beb001b449 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2010,2012,2013,2014,2015 by the GROMACS development team.
-# Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+add_library(mdlib INTERFACE)
+
 file(GLOB MDLIB_SOURCES *.cpp)
-# To avoid listing all the necessary files manually, we will remove SYCL-specfific one here:
-list(REMOVE_ITEM MDLIB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/leapfrog_gpu_sycl.cpp)
+# To avoid listing all the necessary files manually, we will remove SYCL-specific files here:
+list(REMOVE_ITEM MDLIB_SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/gpuforcereduction_impl.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/leapfrog_gpu_sycl.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/lincs_gpu.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/lincs_gpu_internal_sycl.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/settle_gpu.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/settle_gpu_internal_sycl.cpp)
 
 set(MDLIB_SOURCES ${MDLIB_SOURCES} PARENT_SCOPE)
-if (BUILD_TESTING)
-    add_subdirectory(tests)
-endif()
 if(GMX_GPU_CUDA)
     gmx_add_libgromacs_sources(
        leapfrog_gpu.cu
-       lincs_gpu.cu
-       settle_gpu.cu
+       gpuforcereduction_impl.cpp
+       gpuforcereduction_impl_internal.cu
+       lincs_gpu.cpp
+       lincs_gpu_internal.cu
+       settle_gpu.cpp
+       settle_gpu_internal.cu
        update_constrain_gpu_impl.cu
-       gpuforcereduction_impl.cu
+       )
+    _gmx_add_files_to_property(CUDA_SOURCES
+       gpuforcereduction_impl.cpp
+       lincs_gpu.cpp
+       settle_gpu.cpp
        )
 endif()
+
 if(GMX_GPU_SYCL)
     gmx_add_libgromacs_sources(
         leapfrog_gpu_sycl.cpp
+        lincs_gpu.cpp
+        lincs_gpu_internal_sycl.cpp
+        settle_gpu.cpp
+        settle_gpu_internal_sycl.cpp
     )
+
     _gmx_add_files_to_property(SYCL_SOURCES
         leapfrog_gpu_sycl.cpp
+        lincs_gpu.cpp
+        lincs_gpu_internal_sycl.cpp
+        settle_gpu.cpp
+        settle_gpu_internal_sycl.cpp
     )
 endif()
+
+# Source files have the following private module dependencies.
+target_link_libraries(mdlib PRIVATE
+#                      gmxlib
+#                      math
+#                      mdtypes
+#                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(mdlib PUBLIC
+target_include_directories(mdlib INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(mdlib PUBLIC
+target_link_libraries(mdlib INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when mdlib is an OBJECT target
+#target_link_libraries(mdlib PUBLIC legacy_api)
+#target_link_libraries(mdlib PRIVATE common)
+
+# Module dependencies
+# mdlib interfaces convey transitive dependence on these modules.
+#target_link_libraries(mdlib PUBLIC
+target_link_libraries(mdlib INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(mdlib PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(mdlib PRIVATE legacy_modules)
+
+if (BUILD_TESTING)
+    add_subdirectory(tests)
+endif()
index 4ab660a823ae573eabdb965cd87143a319bad844..ad751dff21871eab5b6b82a0fc69aa68ab17d99b 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/fileio/tpxio.h"
 #include "gromacs/mdtypes/state.h"
+#include "gromacs/utility/enumerationhelpers.h"
 
 template<typename AllocatorType>
 static void bcastPaddedRVecVector(MPI_Comm                                     communicator,
@@ -72,16 +73,22 @@ void broadcastStateWithoutDynamics(MPI_Comm communicator,
     block_bc(communicator, state->natoms);
     block_bc(communicator, state->flags);
 
-    for (int i = 0; i < estNR; i++)
+    for (auto i : gmx::EnumerationArray<StateEntry, bool>::keys())
     {
-        if (state->flags & (1 << i))
+        if (state->flags & enumValueToBitMask(i))
         {
             switch (i)
             {
-                case estLAMBDA: nblock_bc(communicator, efptNR, state->lambda.data()); break;
-                case estFEPSTATE: block_bc(communicator, state->fep_state); break;
-                case estBOX: block_bc(communicator, state->box); break;
-                case estX: bcastPaddedRVecVector(communicator, &state->x, state->natoms); break;
+                case StateEntry::Lambda:
+                    nblock_bc(communicator,
+                              static_cast<int>(FreeEnergyPerturbationCouplingType::Count),
+                              state->lambda.data());
+                    break;
+                case StateEntry::FepState: block_bc(communicator, state->fep_state); break;
+                case StateEntry::Box: block_bc(communicator, state->box); break;
+                case StateEntry::X:
+                    bcastPaddedRVecVector(communicator, &state->x, state->natoms);
+                    break;
                 default:
                     GMX_RELEASE_ASSERT(false,
                                        "The state has a dynamic entry, while no dynamic entries "
index 90e9acf9275df0eb14a4ba6a3f2791c304240a50..f29ff7303b793d2c7159a0874ea322f8944e7281 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -291,7 +291,7 @@ static void get_vsite_masses(const gmx_moltype_t&  moltype,
                     int  aj    = ilist.iatoms[i + j + 2];
                     real coeff = ffparams.iparams[ilist.iatoms[i + j]].vsiten.a;
                     real m_aj;
-                    if (moltype.atoms.atom[aj].ptype == eptVSite)
+                    if (moltype.atoms.atom[aj].ptype == ParticleType::VSite)
                     {
                         m_aj = vsite_m[aj];
                     }
@@ -311,8 +311,11 @@ static void get_vsite_masses(const gmx_moltype_t&  moltype,
             }
             if (gmx_debug_at)
             {
-                fprintf(debug, "atom %4d %-20s mass %6.3f\n", a1,
-                        interaction_function[ilist.functionType].longname, vsite_m[a1]);
+                fprintf(debug,
+                        "atom %4d %-20s mass %6.3f\n",
+                        a1,
+                        interaction_function[ilist.functionType].longname,
+                        vsite_m[a1]);
             }
         }
     }
@@ -394,7 +397,7 @@ static std::vector<VerletbufAtomtype> getVerletBufferAtomtypes(const gmx_mtop_t&
 
         for (a = 0; a < atoms->nr; a++)
         {
-            if (atoms->atom[a].ptype == eptVSite)
+            if (atoms->atom[a].ptype == ParticleType::VSite)
             {
                 prop[a].mass = vsite_m[a];
             }
@@ -421,10 +424,16 @@ static std::vector<VerletbufAtomtype> getVerletBufferAtomtypes(const gmx_mtop_t&
     {
         for (size_t a = 0; a < att.size(); a++)
         {
-            fprintf(debug, "type %zu: m %5.2f t %d q %6.3f con %s con_m %5.3f con_l %5.3f n %d\n",
-                    a, att[a].prop.mass, att[a].prop.type, att[a].prop.q,
-                    gmx::boolToString(att[a].prop.bConstr), att[a].prop.con_mass,
-                    att[a].prop.con_len, att[a].n);
+            fprintf(debug,
+                    "type %zu: m %5.2f t %d q %6.3f con %s con_m %5.3f con_l %5.3f n %d\n",
+                    a,
+                    att[a].prop.mass,
+                    att[a].prop.type,
+                    att[a].prop.q,
+                    gmx::boolToString(att[a].prop.bConstr),
+                    att[a].prop.con_mass,
+                    att[a].prop.con_len,
+                    att[a].n);
         }
     }
 
@@ -657,8 +666,8 @@ static real energyDrift(gmx::ArrayRef<const VerletbufAtomtype> att,
             lj.d2  = c6 * ljDisp->d2 + c12 * ljRep->d2;
             lj.md3 = c6 * ljDisp->md3 + c12 * ljRep->md3;
 
-            real pot_lj = energyDriftAtomPair(prop_i->bConstr, prop_j->bConstr, s2, s2i_2d, s2j_2d,
-                                              rlist - rlj, &lj);
+            real pot_lj = energyDriftAtomPair(
+                    prop_i->bConstr, prop_j->bConstr, s2, s2i_2d, s2j_2d, rlist - rlj, &lj);
 
             // Set -V' and V'' at the cut-off for Coulomb
             pot_derivatives_t elec_qq;
@@ -666,8 +675,8 @@ static real energyDrift(gmx::ArrayRef<const VerletbufAtomtype> att,
             elec_qq.d2  = elec->d2 * prop_i->q * prop_j->q;
             elec_qq.md3 = 0;
 
-            real pot_q = energyDriftAtomPair(prop_i->bConstr, prop_j->bConstr, s2, s2i_2d, s2j_2d,
-                                             rlist - rcoulomb, &elec_qq);
+            real pot_q = energyDriftAtomPair(
+                    prop_i->bConstr, prop_j->bConstr, s2, s2i_2d, s2j_2d, rlist - rcoulomb, &elec_qq);
 
             // Note that attractive and repulsive potentials for individual
             // pairs can partially cancel.
@@ -776,14 +785,14 @@ static real displacementVariance(const t_inputrec& ir, real temperature, real ti
 {
     real kT_fac;
 
-    if (ir.eI == eiBD)
+    if (ir.eI == IntegrationAlgorithm::BD)
     {
         /* Get the displacement distribution from the random component only.
          * With accurate integration the systematic (force) displacement
          * should be negligible (unless nstlist is extremely large, which
          * you wouldn't do anyhow).
          */
-        kT_fac = 2 * BOLTZ * temperature * timePeriod;
+        kT_fac = 2 * gmx::c_boltz * temperature * timePeriod;
         if (ir.bd_fric > 0)
         {
             /* This is directly sigma^2 of the displacement */
@@ -804,7 +813,7 @@ static real displacementVariance(const t_inputrec& ir, real temperature, real ti
     }
     else
     {
-        kT_fac = BOLTZ * temperature * gmx::square(timePeriod);
+        kT_fac = gmx::c_boltz * temperature * gmx::square(timePeriod);
     }
 
     return kT_fac;
@@ -905,7 +914,7 @@ real calcVerletBufferSize(const gmx_mtop_t&         mtop,
     /* TODO: Obtain masses through (future) integrator functionality
      *       to avoid scattering the code with (or forgetting) checks.
      */
-    const bool setMassesToOne = (ir.eI == eiBD && ir.bd_fric > 0);
+    const bool setMassesToOne = (ir.eI == IntegrationAlgorithm::BD && ir.bd_fric > 0);
     const auto att            = getVerletBufferAtomtypes(mtop, setMassesToOne);
     GMX_ASSERT(!att.empty(), "We expect at least one type");
 
@@ -919,25 +928,25 @@ real calcVerletBufferSize(const gmx_mtop_t&         mtop,
     pot_derivatives_t ljRep  = { 0, 0, 0 };
     real              repPow = mtop.ffparams.reppow;
 
-    if (ir.vdwtype == evdwCUT)
+    if (ir.vdwtype == VanDerWaalsType::Cut)
     {
         real sw_range, md3_pswf;
 
         switch (ir.vdw_modifier)
         {
-            case eintmodNONE:
-            case eintmodPOTSHIFT:
+            case InteractionModifiers::None:
+            case InteractionModifiers::PotShift:
                 /* -dV/dr of -r^-6 and r^-reppow */
                 ljDisp.md1 = -6 * std::pow(ir.rvdw, -7.0);
                 ljRep.md1  = repPow * std::pow(ir.rvdw, -(repPow + 1));
                 /* The contribution of the higher derivatives is negligible */
                 break;
-            case eintmodFORCESWITCH:
+            case InteractionModifiers::ForceSwitch:
                 /* At the cut-off: V=V'=V''=0, so we use only V''' */
                 ljDisp.md3 = -md3_force_switch(6.0, ir.rvdw_switch, ir.rvdw);
                 ljRep.md3  = md3_force_switch(repPow, ir.rvdw_switch, ir.rvdw);
                 break;
-            case eintmodPOTSWITCH:
+            case InteractionModifiers::PotSwitch:
                 /* At the cut-off: V=V'=V''=0.
                  * V''' is given by the original potential times
                  * the third derivative of the switch function.
@@ -972,16 +981,16 @@ real calcVerletBufferSize(const gmx_mtop_t&         mtop,
                   "interactions");
     }
 
-    elfac = ONE_4PI_EPS0 / ir.epsilon_r;
+    elfac = gmx::c_one4PiEps0 / ir.epsilon_r;
 
     // Determine the 1st and 2nd derivative for the electostatics
     pot_derivatives_t elec = { 0, 0, 0 };
 
-    if (ir.coulombtype == eelCUT || EEL_RF(ir.coulombtype))
+    if (ir.coulombtype == CoulombInteractionType::Cut || EEL_RF(ir.coulombtype))
     {
         real eps_rf, k_rf;
 
-        if (ir.coulombtype == eelCUT)
+        if (ir.coulombtype == CoulombInteractionType::Cut)
         {
             eps_rf = 1;
             k_rf   = 0;
@@ -995,7 +1004,7 @@ real calcVerletBufferSize(const gmx_mtop_t&         mtop,
             }
             else
             {
-                /* epsilon_rf = infinity */
+                /* reactionFieldPermitivity = infinity */
                 k_rf = 0.5 / gmx::power3(ir.rcoulomb);
             }
         }
@@ -1006,7 +1015,7 @@ real calcVerletBufferSize(const gmx_mtop_t&         mtop,
         }
         elec.d2 = elfac * (2.0 / gmx::power3(ir.rcoulomb) + 2 * k_rf);
     }
-    else if (EEL_PME(ir.coulombtype) || ir.coulombtype == eelEWALD)
+    else if (EEL_PME(ir.coulombtype) || ir.coulombtype == CoulombInteractionType::Ewald)
     {
         real b, rc, br;
 
@@ -1053,8 +1062,8 @@ real calcVerletBufferSize(const gmx_mtop_t&         mtop,
         /* Calculate the average energy drift at the last step
          * of the nstlist steps at which the pair-list is used.
          */
-        drift = energyDrift(att, &mtop.ffparams, kT_fac, &ljDisp, &ljRep, &elec, ir.rvdw,
-                            ir.rcoulomb, rl, boxVolume);
+        drift = energyDrift(
+                att, &mtop.ffparams, kT_fac, &ljDisp, &ljRep, &elec, ir.rvdw, ir.rcoulomb, rl, boxVolume);
 
         /* Correct for the fact that we are using a Ni x Nj particle pair list
          * and not a 1 x 1 particle pair list. This reduces the drift.
@@ -1070,9 +1079,16 @@ real calcVerletBufferSize(const gmx_mtop_t&         mtop,
 
         if (debug)
         {
-            fprintf(debug, "ib %3d %3d %3d rb %.3f %dx%d fac %.3f drift %.1e\n", ib0, ib, ib1, rb,
-                    listSetup.cluster_size_i, listSetup.cluster_size_j,
-                    nb_clust_frac_pairs_not_in_list_at_cutoff, drift);
+            fprintf(debug,
+                    "ib %3d %3d %3d rb %.3f %dx%d fac %.3f drift %.1e\n",
+                    ib0,
+                    ib,
+                    ib1,
+                    rb,
+                    listSetup.cluster_size_i,
+                    listSetup.cluster_size_j,
+                    nb_clust_frac_pairs_not_in_list_at_cutoff,
+                    drift);
         }
 
         if (std::abs(drift) > ir.verletbuf_tol)
@@ -1120,8 +1136,8 @@ static real chanceOfAtomCrossingCell(gmx::ArrayRef<const VerletbufAtomtype> atom
         real                                 s2_3d;
         get_atom_sigma2(kT_fac, &propAtom, &s2_2d, &s2_3d);
 
-        real chancePerAtom = energyDriftAtomPair(propAtom.bConstr, false, s2_2d + s2_3d, s2_2d, 0,
-                                                 cellSize, &boundaryInteraction);
+        real chancePerAtom = energyDriftAtomPair(
+                propAtom.bConstr, false, s2_2d + s2_3d, s2_2d, 0, cellSize, &boundaryInteraction);
 
         if (propAtom.bConstr)
         {
@@ -1273,8 +1289,8 @@ static real chanceOfUpdateGroupCrossingCell(const gmx_moltype_t&          moltyp
             }
         }
         real s2_3d = kT_fac / massSum;
-        chance += energyDriftAtomPair(false, false, s2_3d, 0, 0, cellSize - 2 * maxComCogDistance,
-                                      &boundaryInteraction);
+        chance += energyDriftAtomPair(
+                false, false, s2_3d, 0, 0, cellSize - 2 * maxComCogDistance, &boundaryInteraction);
     }
 
     return chance;
@@ -1294,8 +1310,8 @@ static real chanceOfUpdateGroupCrossingCell(const gmx_mtop_t&      mtop,
     {
         const gmx_moltype_t& moltype = mtop.moltype[molblock.type];
         chance += molblock.nmol
-                  * chanceOfUpdateGroupCrossingCell(moltype, mtop.ffparams,
-                                                    updateGrouping[molblock.type], kT_fac, cellSize);
+                  * chanceOfUpdateGroupCrossingCell(
+                            moltype, mtop.ffparams, updateGrouping[molblock.type], kT_fac, cellSize);
     }
 
     return chance;
@@ -1306,7 +1322,7 @@ real minCellSizeForAtomDisplacement(const gmx_mtop_t&      mtop,
                                     PartitioningPerMoltype updateGrouping,
                                     real                   chanceRequested)
 {
-    if (!EI_DYNAMICS(ir.eI) || (EI_MD(ir.eI) && ir.etc == etcNO))
+    if (!EI_DYNAMICS(ir.eI) || (EI_MD(ir.eI) && ir.etc == TemperatureCoupling::No))
     {
         return minCellSizeFromPairlistBuffer(ir);
     }
@@ -1317,7 +1333,7 @@ real minCellSizeForAtomDisplacement(const gmx_mtop_t&      mtop,
      */
     const real temperature = maxReferenceTemperature(ir);
 
-    const bool setMassesToOne = (ir.eI == eiBD && ir.bd_fric > 0);
+    const bool setMassesToOne = (ir.eI == IntegrationAlgorithm::BD && ir.bd_fric > 0);
 
     const auto atomtypes = getVerletBufferAtomtypes(mtop, setMassesToOne);
 
index 83a61bed785e557cc689eb8f72a3a03910ad0389..8d7b897d34696ec37eaed4f65dd916617209d261 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 void calc_mu(int                            start,
              int                            homenr,
              gmx::ArrayRef<const gmx::RVec> x,
-             const real                     q[],
-             const real                     qB[],
-             int                            nChargePerturbed,
+             gmx::ArrayRef<const real>      q,
+             gmx::ArrayRef<const real>      qB,
+             bool                           havePerturbedCharges,
              dvec                           mu,
              dvec                           mu_B)
 {
@@ -65,7 +65,7 @@ void calc_mu(int                            start,
 
     mu_x = mu_y = mu_z = 0.0;
 #pragma omp parallel for reduction(+: mu_x, mu_y, mu_z) schedule(static) \
-    num_threads(gmx_omp_nthreads_get(emntDefault))
+    num_threads(gmx_omp_nthreads_get(ModuleMultiThread::Default))
     for (int i = start; i < end; i++)
     {
         // Trivial OpenMP region that cannot throw
@@ -79,14 +79,14 @@ void calc_mu(int                            start,
 
     for (m = 0; (m < DIM); m++)
     {
-        mu[m] *= ENM2DEBYE;
+        mu[m] *= gmx::c_enm2Debye;
     }
 
-    if (nChargePerturbed)
+    if (havePerturbedCharges)
     {
         mu_x = mu_y = mu_z = 0.0;
 #pragma omp parallel for reduction(+: mu_x, mu_y, mu_z) schedule(static) \
-        num_threads(gmx_omp_nthreads_get(emntDefault))
+        num_threads(gmx_omp_nthreads_get(ModuleMultiThread::Default))
         for (int i = start; i < end; i++)
         {
             // Trivial OpenMP region that cannot throw
@@ -94,9 +94,9 @@ void calc_mu(int                            start,
             mu_y += qB[i] * x[i][YY];
             mu_z += qB[i] * x[i][ZZ];
         }
-        mu_B[XX] = mu_x * ENM2DEBYE;
-        mu_B[YY] = mu_y * ENM2DEBYE;
-        mu_B[ZZ] = mu_z * ENM2DEBYE;
+        mu_B[XX] = mu_x * gmx::c_enm2Debye;
+        mu_B[YY] = mu_y * gmx::c_enm2Debye;
+        mu_B[ZZ] = mu_z * gmx::c_enm2Debye;
     }
     else
     {
index 4081afc4efe16a84106468f45035c9a20ced6c20..23a4fd2907d575847b9604e508f7c7c9498834c4 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2010,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ class ArrayRef;
 void calc_mu(int                            start,
              int                            homenr,
              gmx::ArrayRef<const gmx::RVec> x,
-             const real                     q[],
-             const real                     qB[],
-             int                            nChargePerturbed,
+             gmx::ArrayRef<const real>      q,
+             gmx::ArrayRef<const real>      qB,
+             bool                           havePerturbedCharges,
              dvec                           mu,
              dvec                           mu_B);
 
index 99398cff8404d42cc266860e9a01bd3c8157405a..6a9f1903fbad3215524837144d82752f60b1f547 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +84,7 @@ static void calc_x_times_f(int nxf, const rvec x[], const rvec f[], gmx_bool bSc
 
         if (bScrewPBC)
         {
-            int isx = IS2X(i);
+            int isx = gmx::shiftIndexToXDim(i);
             /* We should correct all odd x-shifts, but the range of isx is -2 to 2 */
             if (isx == 1 || isx == -1)
             {
@@ -104,7 +104,7 @@ void calc_vir(int nxf, const rvec x[], const rvec f[], tensor vir, bool bScrewPB
 {
     matrix x_times_f;
 
-    int nthreads = gmx_omp_nthreads_get_simple_rvec_task(emntDefault, nxf * 9);
+    int nthreads = gmx_omp_nthreads_get_simple_rvec_task(ModuleMultiThread::Default, nxf * 9);
 
     GMX_ASSERT(nthreads >= 1, "Avoids uninitialized x_times_f (warning)");
 
@@ -126,7 +126,11 @@ void calc_vir(int nxf, const rvec x[], const rvec f[], tensor vir, bool bScrewPB
             int start = (nxf * thread) / nthreads;
             int end   = std::min(nxf * (thread + 1) / nthreads, nxf);
 
-            calc_x_times_f(end - start, x + start, f + start, bScrewPBC, box,
+            calc_x_times_f(end - start,
+                           x + start,
+                           f + start,
+                           bScrewPBC,
+                           box,
                            thread == 0 ? x_times_f : xf_buf[thread * 3]);
         }
 
index 0819f82ef7918b9bab13159848d815509974381d..1c90a9b23dcdf969a1efc5f39b9484f275a396d1 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -62,8 +62,8 @@ static int div_nsteps(int nsteps, int nst)
 double compute_io(const t_inputrec* ir, int natoms, const SimulationGroups& groups, int nrener, int nrepl)
 {
 
-    int    nsteps = ir->nsteps;
-    int    i, nxtcatoms = 0;
+    int    nsteps    = ir->nsteps;
+    int    nxtcatoms = 0;
     int    nstx, nstv, nstf, nste, nstlog, nstxtc;
     double cio;
 
@@ -93,13 +93,13 @@ double compute_io(const t_inputrec* ir, int natoms, const SimulationGroups& grou
     /* t_energy contains doubles, but real is written to edr */
     cio += (1.0 * nste) * nrener * 3 * sizeof(real);
 
-    if ((ir->efep != efepNO || ir->bSimTemp) && (ir->fepvals->nstdhdl > 0))
+    if ((ir->efep != FreeEnergyPerturbationType::No || ir->bSimTemp) && (ir->fepvals->nstdhdl > 0))
     {
         int ndh    = ir->fepvals->n_lambda;
         int ndhdl  = 0;
         int nchars = 0;
 
-        for (i = 0; i < efptNR; i++)
+        for (auto i : keysOf(ir->fepvals->separate_dvdl))
         {
             if (ir->fepvals->separate_dvdl[i])
             {
@@ -107,15 +107,15 @@ double compute_io(const t_inputrec* ir, int natoms, const SimulationGroups& grou
             }
         }
 
-        if (ir->fepvals->separate_dhdl_file == esepdhdlfileYES)
+        if (ir->fepvals->separate_dhdl_file == SeparateDhdlFile::Yes)
         {
             nchars = 8 + ndhdl * 8 + ndh * 10; /* time data ~8 chars/entry, dH data ~10 chars/entry */
-            if (ir->expandedvals->elmcmove > elmcmoveNO)
+            if (ir->expandedvals->elmcmove > LambdaMoveCalculation::No)
             {
                 nchars += 5; /* alchemical state */
             }
 
-            if (ir->fepvals->edHdLPrintEnergy != edHdLPrintEnergyNO)
+            if (ir->fepvals->edHdLPrintEnergy != FreeEnergyPrintEnergy::No)
             {
                 nchars += 12; /* energy for dhdl */
             }
@@ -127,11 +127,11 @@ double compute_io(const t_inputrec* ir, int natoms, const SimulationGroups& grou
             if (ir->fepvals->dh_hist_size <= 0)
             {
                 int ndh_tot = ndh + ndhdl;
-                if (ir->expandedvals->elmcmove > elmcmoveNO)
+                if (ir->expandedvals->elmcmove > LambdaMoveCalculation::No)
                 {
                     ndh_tot += 1;
                 }
-                if (ir->fepvals->edHdLPrintEnergy != edHdLPrintEnergyNO)
+                if (ir->fepvals->edHdLPrintEnergy != FreeEnergyPrintEnergy::No)
                 {
                     ndh_tot += 1;
                 }
index 32a12e0c88d0b2db90266d1361aa36a0c15631d6..0b8d94234c739dd2a2e79a5bbab263b2a21b22d0 100644 (file)
@@ -59,6 +59,7 @@
 #include "gromacs/fileio/gmxfio.h"
 #include "gromacs/fileio/pdbio.h"
 #include "gromacs/gmxlib/nrnb.h"
+#include "gromacs/math/arrayrefwithpadding.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
@@ -75,6 +76,7 @@
 #include "gromacs/topology/ifunc.h"
 #include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/mtop_util.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
@@ -102,6 +104,7 @@ public:
          pull_t*               pull_work,
          FILE*                 log_p,
          const t_commrec*      cr_p,
+         bool                  useUpdateGroups,
          const gmx_multisim_t* ms,
          t_nrnb*               nrnb,
          gmx_wallcycle*        wcycle_p,
@@ -109,14 +112,14 @@ public:
          int                   numConstraints,
          int                   numSettles);
     ~Impl();
-    void setConstraints(gmx_localtop_t* top,
-                        int             numAtoms,
-                        int             numHomeAtoms,
-                        real*           masses,
-                        real*           inverseMasses,
-                        bool            hasMassPerturbedAtoms,
-                        real            lambda,
-                        unsigned short* cFREEZE);
+    void setConstraints(gmx_localtop_t*                     top,
+                        int                                 numAtoms,
+                        int                                 numHomeAtoms,
+                        gmx::ArrayRef<const real>           masses,
+                        gmx::ArrayRef<const real>           inverseMasses,
+                        bool                                hasMassPerturbedAtoms,
+                        real                                lambda,
+                        gmx::ArrayRef<const unsigned short> cFREEZE);
     bool apply(bool                      bLog,
                bool                      bEner,
                int64_t                   step,
@@ -169,15 +172,15 @@ public:
     //! Number of local atoms.
     int numHomeAtoms_ = 0;
     //! Atoms masses.
-    real* masses_;
+    gmx::ArrayRef<const real> masses_;
     //! Inverse masses.
-    real* inverseMasses_;
+    gmx::ArrayRef<const real> inverseMasses_;
     //! If there are atoms with perturbed mass (for FEP).
     bool hasMassPerturbedAtoms_;
     //! FEP lambda value.
     real lambda_;
     //! Freeze groups data
-    unsigned short* cFREEZE_;
+    gmx::ArrayRef<const unsigned short> cFREEZE_;
     //! Whether we need to do pbc for handling bonds.
     bool pbcHandlingRequired_ = false;
 
@@ -223,28 +226,30 @@ bool Constraints::havePerturbedConstraints() const
 }
 
 //! Clears constraint quantities for atoms in nonlocal region.
-static void clear_constraint_quantity_nonlocal(gmx_domdec_t* dd, ArrayRef<RVec> q)
+static void clear_constraint_quantity_nonlocal(const gmx_domdec_t& dd, ArrayRef<RVec> q)
 {
-    int nonlocal_at_start, nonlocal_at_end, at;
+    int nonlocal_at_start, nonlocal_at_end;
 
     dd_get_constraint_range(dd, &nonlocal_at_start, &nonlocal_at_end);
 
-    for (at = nonlocal_at_start; at < nonlocal_at_end; at++)
+    for (int at = nonlocal_at_start; at < nonlocal_at_end; at++)
     {
         clear_rvec(q[at]);
     }
 }
 
-void too_many_constraint_warnings(int eConstrAlg, int warncount)
+void too_many_constraint_warnings(ConstraintAlgorithm eConstrAlg, int warncount)
 {
-    gmx_fatal(
-            FARGS,
-            "Too many %s warnings (%d)\n"
-            "If you know what you are doing you can %s"
-            "set the environment variable GMX_MAXCONSTRWARN to -1,\n"
-            "but normally it is better to fix the problem",
-            (eConstrAlg == econtLINCS) ? "LINCS" : "SETTLE", warncount,
-            (eConstrAlg == econtLINCS) ? "adjust the lincs warning threshold in your mdp file\nor " : "\n");
+    gmx_fatal(FARGS,
+              "Too many %s warnings (%d)\n"
+              "If you know what you are doing you can %s"
+              "set the environment variable GMX_MAXCONSTRWARN to -1,\n"
+              "but normally it is better to fix the problem",
+              (eConstrAlg == ConstraintAlgorithm::Lincs) ? "LINCS" : "SETTLE",
+              warncount,
+              (eConstrAlg == ConstraintAlgorithm::Lincs)
+                      ? "adjust the lincs warning threshold in your mdp file\nor "
+                      : "\n");
 }
 
 //! Writes out coordinates.
@@ -267,7 +272,7 @@ static void write_constr_pdb(const char*          fn,
     if (DOMAINDECOMP(cr))
     {
         dd = cr->dd;
-        dd_get_constraint_range(dd, &dd_ac0, &dd_ac1);
+        dd_get_constraint_range(*dd, &dd_ac0, &dd_ac1);
         start  = 0;
         homenr = dd_ac1;
     }
@@ -301,8 +306,21 @@ static void write_constr_pdb(const char*          fn,
             ii = i;
         }
         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, "");
+        gmx_fprintf_pdb_atomline(out,
+                                 PdbRecordType::Atom,
+                                 ii + 1,
+                                 anm,
+                                 ' ',
+                                 resnm,
+                                 ' ',
+                                 resnr,
+                                 ' ',
+                                 10 * x[i][XX],
+                                 10 * x[i][YY],
+                                 10 * x[i][ZZ],
+                                 1.0,
+                                 0.0,
+                                 "");
     }
     fprintf(out, "TER\n");
 
@@ -355,9 +373,21 @@ bool Constraints::apply(bool                      bLog,
                         tensor                    constraintsVirial,
                         ConstraintVariable        econq)
 {
-    return impl_->apply(bLog, bEner, step, delta_step, step_scaling, std::move(x),
-                        std::move(xprime), min_proj, box, lambda, dvdlambda, std::move(v),
-                        computeVirial, constraintsVirial, econq);
+    return impl_->apply(bLog,
+                        bEner,
+                        step,
+                        delta_step,
+                        step_scaling,
+                        std::move(x),
+                        std::move(xprime),
+                        min_proj,
+                        box,
+                        lambda,
+                        dvdlambda,
+                        std::move(v),
+                        computeVirial,
+                        constraintsVirial,
+                        econq);
 }
 
 bool Constraints::Impl::apply(bool                      bLog,
@@ -385,7 +415,7 @@ bool Constraints::Impl::apply(bool                      bLog,
     char  buf[22];
     int   nth;
 
-    wallcycle_start(wcycle, ewcCONSTR);
+    wallcycle_start(wcycle, WallCycleCounter::Constr);
 
     if (econq == ConstraintVariable::ForceDispl && !EI_ENERGY_MINIMIZATION(ir.eI))
     {
@@ -413,7 +443,7 @@ bool Constraints::Impl::apply(bool                      bLog,
         invdt = 1.0 / scaled_delta_t;
     }
 
-    if (ir.efep != efepNO && EI_DYNAMICS(ir.eI))
+    if (ir.efep != FreeEnergyPerturbationType::No && EI_DYNAMICS(ir.eI))
     {
         /* Set the constraint lengths for the step at which this configuration
          * is meant to be. The invmasses should not be changed.
@@ -430,7 +460,7 @@ bool Constraints::Impl::apply(bool                      bLog,
 
     if (nsettle > 0)
     {
-        nth = gmx_omp_nthreads_get(emntSETTLE);
+        nth = gmx_omp_nthreads_get(ModuleMultiThread::Settle);
     }
     else
     {
@@ -461,7 +491,10 @@ bool Constraints::Impl::apply(bool                      bLog,
      */
     if (cr->dd)
     {
-        dd_move_x_constraints(cr->dd, box, x.unpaddedArrayRef(), xprime.unpaddedArrayRef(),
+        dd_move_x_constraints(cr->dd,
+                              box,
+                              x.unpaddedArrayRef(),
+                              xprime.unpaddedArrayRef(),
                               econq == ConstraintVariable::Positions);
 
         if (!v.empty())
@@ -470,22 +503,43 @@ bool Constraints::Impl::apply(bool                      bLog,
              * We never actually use these values, but we do increment them,
              * so we should avoid uninitialized variables and overflows.
              */
-            clear_constraint_quantity_nonlocal(cr->dd, v.unpaddedArrayRef());
+            clear_constraint_quantity_nonlocal(*cr->dd, v.unpaddedArrayRef());
         }
     }
 
     if (lincsd != nullptr)
     {
-        bOK = constrain_lincs(bLog || bEner, ir, step, lincsd, inverseMasses_, cr, ms, x, xprime,
-                              min_proj, box, pbc_null, hasMassPerturbedAtoms_, lambda, dvdlambda,
-                              invdt, v.unpaddedArrayRef(), computeVirial, constraintsVirial, econq,
-                              nrnb, maxwarn, &warncount_lincs);
+        bOK = constrain_lincs(bLog || bEner,
+                              ir,
+                              step,
+                              lincsd,
+                              inverseMasses_,
+                              cr,
+                              ms,
+                              x,
+                              xprime,
+                              min_proj,
+                              box,
+                              pbc_null,
+                              hasMassPerturbedAtoms_,
+                              lambda,
+                              dvdlambda,
+                              invdt,
+                              v.unpaddedArrayRef(),
+                              computeVirial,
+                              constraintsVirial,
+                              econq,
+                              nrnb,
+                              maxwarn,
+                              &warncount_lincs);
         if (!bOK && maxwarn < INT_MAX)
         {
             if (log != nullptr)
             {
-                fprintf(log, "Constraint error in algorithm %s at step %s\n",
-                        econstr_names[econtLINCS], gmx_step_str(step, buf));
+                fprintf(log,
+                        "Constraint error in algorithm %s at step %s\n",
+                        enumValueToString(ConstraintAlgorithm::Lincs),
+                        gmx_step_str(step, buf));
             }
             bDump = TRUE;
         }
@@ -493,17 +547,33 @@ bool Constraints::Impl::apply(bool                      bLog,
 
     if (shaked != nullptr)
     {
-        bOK = constrain_shake(log, shaked.get(), inverseMasses_, *idef, ir, x.unpaddedArrayRef(),
-                              xprime.unpaddedArrayRef(), min_proj, pbc_null, nrnb, lambda,
-                              dvdlambda, invdt, v.unpaddedArrayRef(), computeVirial,
-                              constraintsVirial, maxwarn < INT_MAX, econq);
+        bOK = constrain_shake(log,
+                              shaked.get(),
+                              inverseMasses_,
+                              *idef,
+                              ir,
+                              x.unpaddedArrayRef(),
+                              xprime.unpaddedArrayRef(),
+                              min_proj,
+                              pbc_null,
+                              nrnb,
+                              lambda,
+                              dvdlambda,
+                              invdt,
+                              v.unpaddedArrayRef(),
+                              computeVirial,
+                              constraintsVirial,
+                              maxwarn < INT_MAX,
+                              econq);
 
         if (!bOK && maxwarn < INT_MAX)
         {
             if (log != nullptr)
             {
-                fprintf(log, "Constraint error in algorithm %s at step %s\n",
-                        econstr_names[econtSHAKE], gmx_step_str(step, buf));
+                fprintf(log,
+                        "Constraint error in algorithm %s at step %s\n",
+                        enumValueToString(ConstraintAlgorithm::Shake),
+                        gmx_step_str(step, buf));
             }
             bDump = TRUE;
         }
@@ -526,7 +596,15 @@ bool Constraints::Impl::apply(bool                      bLog,
                             clear_mat(threadConstraintsVirial[th]);
                         }
 
-                        csettle(*settled, nth, th, pbc_null, x, xprime, invdt, v, computeVirial,
+                        csettle(*settled,
+                                nth,
+                                th,
+                                pbc_null,
+                                x,
+                                xprime,
+                                invdt,
+                                v,
+                                computeVirial,
                                 th == 0 ? constraintsVirial : threadConstraintsVirial[th],
                                 th == 0 ? &bSettleErrorHasOccurred0 : &bSettleErrorHasOccurred[th]);
                     }
@@ -572,10 +650,15 @@ bool Constraints::Impl::apply(bool                      bLog,
 
                         if (start_th >= 0 && end_th - start_th > 0)
                         {
-                            settle_proj(*settled, econq, end_th - start_th,
+                            settle_proj(*settled,
+                                        econq,
+                                        end_th - start_th,
                                         settle.iatoms.data() + start_th * (1 + NRAL(F_SETTLE)),
-                                        pbc_null, x.unpaddedArrayRef(), xprime.unpaddedArrayRef(),
-                                        min_proj, calcvir_atom_end,
+                                        pbc_null,
+                                        x.unpaddedArrayRef(),
+                                        xprime.unpaddedArrayRef(),
+                                        min_proj,
+                                        calcvir_atom_end,
                                         th == 0 ? constraintsVirial : threadConstraintsVirial[th]);
                         }
                     }
@@ -623,7 +706,7 @@ bool Constraints::Impl::apply(bool                      bLog,
                 warncount_settle++;
                 if (warncount_settle > maxwarn)
                 {
-                    too_many_constraint_warnings(-1, warncount_settle);
+                    too_many_constraint_warnings(ConstraintAlgorithm::Count, warncount_settle);
                 }
                 bDump = TRUE;
 
@@ -666,8 +749,7 @@ bool Constraints::Impl::apply(bool                      bLog,
 
     if (bDump)
     {
-        dump_confs(log, step, mtop, start, numHomeAtoms_, cr, x.unpaddedArrayRef(),
-                   xprime.unpaddedArrayRef(), box);
+        dump_confs(log, step, mtop, start, numHomeAtoms_, cr, x.unpaddedArrayRef(), xprime.unpaddedArrayRef(), box);
     }
 
     if (econq == ConstraintVariable::Positions)
@@ -683,22 +765,27 @@ bool Constraints::Impl::apply(bool                      bLog,
                 t = ir.init_t;
             }
             set_pbc(&pbc, ir.pbcType, box);
-            pull_constraint(pull_work, masses_, &pbc, cr, ir.delta_t, t,
-                            as_rvec_array(x.unpaddedArrayRef().data()),
-                            as_rvec_array(xprime.unpaddedArrayRef().data()),
-                            as_rvec_array(v.unpaddedArrayRef().data()), constraintsVirial);
+            pull_constraint(pull_work,
+                            masses_,
+                            &pbc,
+                            cr,
+                            ir.delta_t,
+                            t,
+                            x.unpaddedArrayRef(),
+                            xprime.unpaddedArrayRef(),
+                            v.unpaddedArrayRef(),
+                            constraintsVirial);
         }
         if (ed && delta_step > 0)
         {
             /* apply the essential dynamics constraints here */
-            do_edsam(&ir, step, cr, as_rvec_array(xprime.unpaddedArrayRef().data()),
-                     as_rvec_array(v.unpaddedArrayRef().data()), box, ed);
+            do_edsam(&ir, step, cr, xprime.unpaddedArrayRef(), v.unpaddedArrayRef(), box, ed);
         }
     }
-    wallcycle_stop(wcycle, ewcCONSTR);
+    wallcycle_stop(wcycle, WallCycleCounter::Constr);
 
     const bool haveVelocities = (!v.empty() || econq == ConstraintVariable::Velocities);
-    if (haveVelocities && cFREEZE_)
+    if (haveVelocities && !cFREEZE_.empty())
     {
         /* Set the velocities of frozen dimensions to zero */
         ArrayRef<RVec> vRef;
@@ -711,7 +798,7 @@ bool Constraints::Impl::apply(bool                      bLog,
             vRef = v.unpaddedArrayRef();
         }
 
-        int gmx_unused numThreads = gmx_omp_nthreads_get(emntUpdate);
+        int gmx_unused numThreads = gmx_omp_nthreads_get(ModuleMultiThread::Update);
 
 #pragma omp parallel for num_threads(numThreads) schedule(static)
         for (int i = 0; i < numHomeAtoms_; i++)
@@ -861,8 +948,8 @@ ListOfLists<int> make_at2con(const gmx_moltype_t&           moltype,
                              gmx::ArrayRef<const t_iparams> iparams,
                              FlexibleConstraintTreatment    flexibleConstraintTreatment)
 {
-    return makeAtomsToConstraintsList(moltype.atoms.nr, makeConstArrayRef(moltype.ilist), iparams,
-                                      flexibleConstraintTreatment);
+    return makeAtomsToConstraintsList(
+            moltype.atoms.nr, makeConstArrayRef(moltype.ilist), iparams, flexibleConstraintTreatment);
 }
 
 //! Return the number of flexible constraints in the \c ilist and \c iparams.
@@ -903,14 +990,14 @@ static std::vector<int> make_at2settle(int natoms, const InteractionList& ilist)
     return at2s;
 }
 
-void Constraints::Impl::setConstraints(gmx_localtop_t* top,
-                                       int             numAtoms,
-                                       int             numHomeAtoms,
-                                       real*           masses,
-                                       real*           inverseMasses,
-                                       const bool      hasMassPerturbedAtoms,
-                                       const real      lambda,
-                                       unsigned short* cFREEZE)
+void Constraints::Impl::setConstraints(gmx_localtop_t*                     top,
+                                       int                                 numAtoms,
+                                       int                                 numHomeAtoms,
+                                       gmx::ArrayRef<const real>           masses,
+                                       gmx::ArrayRef<const real>           inverseMasses,
+                                       const bool                          hasMassPerturbedAtoms,
+                                       const real                          lambda,
+                                       gmx::ArrayRef<const unsigned short> cFREEZE)
 {
     numAtoms_              = numAtoms;
     numHomeAtoms_          = numHomeAtoms;
@@ -927,11 +1014,11 @@ void Constraints::Impl::setConstraints(gmx_localtop_t* top,
         /* With DD we might also need to call LINCS on a domain no constraints for
          * communicating coordinates to other nodes that do have constraints.
          */
-        if (ir.eConstrAlg == econtLINCS)
+        if (ir.eConstrAlg == ConstraintAlgorithm::Lincs)
         {
             set_lincs(*idef, numAtoms_, inverseMasses_, lambda_, EI_DYNAMICS(ir.eI), cr, lincsd);
         }
-        if (ir.eConstrAlg == econtSHAKE)
+        if (ir.eConstrAlg == ConstraintAlgorithm::Shake)
         {
             if (cr->dd)
             {
@@ -960,17 +1047,17 @@ void Constraints::Impl::setConstraints(gmx_localtop_t* top,
     }
 }
 
-void Constraints::setConstraints(gmx_localtop_t* top,
-                                 const int       numAtoms,
-                                 const int       numHomeAtoms,
-                                 real*           masses,
-                                 real*           inverseMasses,
-                                 const bool      hasMassPerturbedAtoms,
-                                 const real      lambda,
-                                 unsigned short* cFREEZE)
+void Constraints::setConstraints(gmx_localtop_t*                     top,
+                                 const int                           numAtoms,
+                                 const int                           numHomeAtoms,
+                                 gmx::ArrayRef<const real>           masses,
+                                 gmx::ArrayRef<const real>           inverseMasses,
+                                 const bool                          hasMassPerturbedAtoms,
+                                 const real                          lambda,
+                                 gmx::ArrayRef<const unsigned short> cFREEZE)
 {
-    impl_->setConstraints(top, numAtoms, numHomeAtoms, masses, inverseMasses, hasMassPerturbedAtoms,
-                          lambda, cFREEZE);
+    impl_->setConstraints(
+            top, numAtoms, numHomeAtoms, masses, inverseMasses, hasMassPerturbedAtoms, lambda, cFREEZE);
 }
 
 /*! \brief Makes a per-moleculetype container of mappings from atom
@@ -994,13 +1081,14 @@ Constraints::Constraints(const gmx_mtop_t&     mtop,
                          pull_t*               pull_work,
                          FILE*                 log,
                          const t_commrec*      cr,
+                         const bool            useUpdateGroups,
                          const gmx_multisim_t* ms,
                          t_nrnb*               nrnb,
                          gmx_wallcycle*        wcycle,
                          bool                  pbcHandlingRequired,
                          int                   numConstraints,
                          int                   numSettles) :
-    impl_(new Impl(mtop, ir, pull_work, log, cr, ms, nrnb, wcycle, pbcHandlingRequired, numConstraints, numSettles))
+    impl_(new Impl(mtop, ir, pull_work, log, cr, useUpdateGroups, ms, nrnb, wcycle, pbcHandlingRequired, numConstraints, numSettles))
 {
 }
 
@@ -1009,6 +1097,7 @@ Constraints::Impl::Impl(const gmx_mtop_t&     mtop_p,
                         pull_t*               pull_work,
                         FILE*                 log_p,
                         const t_commrec*      cr_p,
+                        const bool            mayHaveSplitConstraints,
                         const gmx_multisim_t* ms_p,
                         t_nrnb*               nrnb_p,
                         gmx_wallcycle*        wcycle_p,
@@ -1026,7 +1115,7 @@ Constraints::Impl::Impl(const gmx_mtop_t&     mtop_p,
     nrnb(nrnb_p),
     wcycle(wcycle_p)
 {
-    if (numConstraints + numSettles > 0 && ir.epc == epcMTTK)
+    if (numConstraints + numSettles > 0 && ir.epc == PressureCoupling::Mttk)
     {
         gmx_fatal(FARGS, "Constraints are not implemented with MTTK pressure control.");
     }
@@ -1065,19 +1154,20 @@ Constraints::Impl::Impl(const gmx_mtop_t&     mtop_p,
             }
         }
 
-        if (ir.eConstrAlg == econtLINCS)
+        // When there are multiple PP domains and update groups are not in use,
+        // the constraints might be split across them.
+        if (ir.eConstrAlg == ConstraintAlgorithm::Lincs)
         {
-            lincsd = init_lincs(log, mtop, nflexcon, at2con_mt,
-                                DOMAINDECOMP(cr) && ddHaveSplitConstraints(*cr->dd), ir.nLincsIter,
-                                ir.nProjOrder);
+            lincsd = init_lincs(
+                    log, mtop, nflexcon, at2con_mt, mayHaveSplitConstraints, ir.nLincsIter, ir.nProjOrder);
         }
 
-        if (ir.eConstrAlg == econtSHAKE)
+        if (ir.eConstrAlg == ConstraintAlgorithm::Shake)
         {
-            if (DOMAINDECOMP(cr) && ddHaveSplitConstraints(*cr->dd))
+            if (mayHaveSplitConstraints)
             {
                 gmx_fatal(FARGS,
-                          "SHAKE is not supported with domain decomposition and constraint that "
+                          "SHAKE is not supported with domain decomposition and constraints that "
                           "cross domain boundaries, use LINCS");
             }
             if (nflexcon)
@@ -1119,7 +1209,7 @@ Constraints::Impl::Impl(const gmx_mtop_t&     mtop_p,
         }
 
         /* Allocate thread-local work arrays */
-        int nthreads = gmx_omp_nthreads_get(emntSETTLE);
+        int nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Settle);
         if (nthreads > 1 && threadConstraintsVirial == nullptr)
         {
             snew(threadConstraintsVirial, nthreads);
@@ -1215,17 +1305,43 @@ void do_constrain_first(FILE*                     fplog,
     bool computeEnergy = false;
     bool computeVirial = false;
     /* constrain the current position */
-    constr->apply(needsLogging, computeEnergy, step, 0, 1.0, x, x, {}, box, lambda, &dvdl_dum, {},
-                  computeVirial, nullptr, gmx::ConstraintVariable::Positions);
+    constr->apply(needsLogging,
+                  computeEnergy,
+                  step,
+                  0,
+                  1.0,
+                  x,
+                  x,
+                  {},
+                  box,
+                  lambda,
+                  &dvdl_dum,
+                  {},
+                  computeVirial,
+                  nullptr,
+                  gmx::ConstraintVariable::Positions);
     if (EI_VV(ir->eI))
     {
         /* constrain the inital velocity, and save it */
         /* also may be useful if we need the ekin from the halfstep for velocity verlet */
-        constr->apply(needsLogging, computeEnergy, step, 0, 1.0, x, v, v.unpaddedArrayRef(), box, lambda,
-                      &dvdl_dum, {}, computeVirial, nullptr, gmx::ConstraintVariable::Velocities);
+        constr->apply(needsLogging,
+                      computeEnergy,
+                      step,
+                      0,
+                      1.0,
+                      x,
+                      v,
+                      v.unpaddedArrayRef(),
+                      box,
+                      lambda,
+                      &dvdl_dum,
+                      {},
+                      computeVirial,
+                      nullptr,
+                      gmx::ConstraintVariable::Velocities);
     }
     /* constrain the inital velocities at t-dt/2 */
-    if (EI_STATE_VELOCITY(ir->eI) && ir->eI != eiVV)
+    if (EI_STATE_VELOCITY(ir->eI) && ir->eI != IntegrationAlgorithm::VV)
     {
         auto subX = x.paddedArrayRef().subArray(start, end);
         auto subV = v.paddedArrayRef().subArray(start, end);
@@ -1248,8 +1364,20 @@ void do_constrain_first(FILE*                     fplog,
             fprintf(fplog, "\nConstraining the coordinates at t0-dt (step %s)\n", gmx_step_str(step, buf));
         }
         dvdl_dum = 0;
-        constr->apply(needsLogging, computeEnergy, step, -1, 1.0, x, savex.arrayRefWithPadding(),
-                      {}, box, lambda, &dvdl_dum, v, computeVirial, nullptr,
+        constr->apply(needsLogging,
+                      computeEnergy,
+                      step,
+                      -1,
+                      1.0,
+                      x,
+                      savex.arrayRefWithPadding(),
+                      {},
+                      box,
+                      lambda,
+                      &dvdl_dum,
+                      v,
+                      computeVirial,
+                      nullptr,
                       gmx::ConstraintVariable::Positions);
 
         for (i = start; i < end; i++)
@@ -1274,10 +1402,21 @@ void constrain_velocities(gmx::Constraints* constr,
 {
     if (constr != nullptr)
     {
-        constr->apply(do_log, do_ene, step, 1, 1.0, state->x.arrayRefWithPadding(),
-                      state->v.arrayRefWithPadding(), state->v.arrayRefWithPadding().unpaddedArrayRef(),
-                      state->box, state->lambda[efptBONDED], dvdlambda, ArrayRefWithPadding<RVec>(),
-                      computeVirial, constraintsVirial, ConstraintVariable::Velocities);
+        constr->apply(do_log,
+                      do_ene,
+                      step,
+                      1,
+                      1.0,
+                      state->x.arrayRefWithPadding(),
+                      state->v.arrayRefWithPadding(),
+                      state->v.arrayRefWithPadding().unpaddedArrayRef(),
+                      state->box,
+                      state->lambda[FreeEnergyPerturbationCouplingType::Bonded],
+                      dvdlambda,
+                      ArrayRefWithPadding<RVec>(),
+                      computeVirial,
+                      constraintsVirial,
+                      ConstraintVariable::Velocities);
     }
 }
 
@@ -1293,9 +1432,20 @@ void constrain_coordinates(gmx::Constraints*         constr,
 {
     if (constr != nullptr)
     {
-        constr->apply(do_log, do_ene, step, 1, 1.0, state->x.arrayRefWithPadding(), std::move(xp),
-                      ArrayRef<RVec>(), state->box, state->lambda[efptBONDED], dvdlambda,
-                      state->v.arrayRefWithPadding(), computeVirial, constraintsVirial,
+        constr->apply(do_log,
+                      do_ene,
+                      step,
+                      1,
+                      1.0,
+                      state->x.arrayRefWithPadding(),
+                      std::move(xp),
+                      ArrayRef<RVec>(),
+                      state->box,
+                      state->lambda[FreeEnergyPerturbationCouplingType::Bonded],
+                      dvdlambda,
+                      state->v.arrayRefWithPadding(),
+                      computeVirial,
+                      constraintsVirial,
                       ConstraintVariable::Positions);
     }
 }
index 1c9f41bd34afb84875fa44d00b849fdaec95305a..f5bc84ea2ce427aa9f4f51ef734cf0e69d77ac3d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <memory>
+
 #include "gromacs/math/vectypes.h"
 #include "gromacs/topology/idef.h"
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/real.h"
 
@@ -70,7 +70,7 @@ struct t_inputrec;
 struct t_nrnb;
 struct t_pbc;
 class t_state;
-
+enum class ConstraintAlgorithm : int;
 namespace gmx
 {
 template<typename T>
@@ -107,6 +107,7 @@ private:
                 pull_t*               pull_work,
                 FILE*                 log,
                 const t_commrec*      cr,
+                bool                  haveHaveSplitConstraints,
                 const gmx_multisim_t* ms,
                 t_nrnb*               nrnb,
                 gmx_wallcycle*        wcycle,
@@ -132,14 +133,14 @@ public:
      *
      * \todo Make this a callback that is called automatically
      * once a new domain has been made. */
-    void setConstraints(gmx_localtop_t* top,
-                        int             numAtoms,
-                        int             numHomeAtoms,
-                        real*           masses,
-                        real*           inverseMasses,
-                        bool            hasMassPerturbedAtoms,
-                        real            lambda,
-                        unsigned short* cFREEZE);
+    void setConstraints(gmx_localtop_t*                     top,
+                        int                                 numAtoms,
+                        int                                 numHomeAtoms,
+                        gmx::ArrayRef<const real>           masses,
+                        gmx::ArrayRef<const real>           inverseMasses,
+                        bool                                hasMassPerturbedAtoms,
+                        real                                lambda,
+                        gmx::ArrayRef<const unsigned short> cFREEZE);
 
     /*! \brief Applies constraints to coordinates.
      *
@@ -214,11 +215,11 @@ private:
     //! Implementation type.
     class Impl;
     //! Implementation object.
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \brief Generate a fatal error because of too many LINCS/SETTLE warnings. */
-[[noreturn]] void too_many_constraint_warnings(int eConstrAlg, int warncount);
+[[noreturn]] void too_many_constraint_warnings(ConstraintAlgorithm eConstrAlg, int warncount);
 
 /*! \brief Returns whether constraint with parameter \p iparamsIndex is a flexible constraint */
 static inline bool isConstraintFlexible(ArrayRef<const t_iparams> iparams, int iparamsIndex)
@@ -327,7 +328,7 @@ void constrain_velocities(gmx::Constraints* constr,
                           int64_t           step,
                           t_state*          state,
                           real*             dvdlambda,
-                          gmx_bool          computeVirial,
+                          bool              computeVirial,
                           tensor            constraintsVirial);
 
 /*! \brief Constraint coordinates.
@@ -341,7 +342,7 @@ void constrain_coordinates(gmx::Constraints*         constr,
                            t_state*                  state,
                            ArrayRefWithPadding<RVec> xp,
                            real*                     dvdlambda,
-                           gmx_bool                  computeVirial,
+                           bool                      computeVirial,
                            tensor                    constraintsVirial);
 
 } // namespace gmx
index 90d16294d0be06788fd6facb61d06b86a29d3d71..308ade02f59bc0f68df0caaf5dad51777f96376b 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -120,11 +120,15 @@ static void constr_recur(const ListOfLists<int>&        at2con,
                 if (debug)
                 {
                     fprintf(debug,
-                            "Found longer constraint distance: r0 %5.3f r1 %5.3f rmax %5.3f\n", rn0,
-                            rn1, sqrt(*r2max));
+                            "Found longer constraint distance: r0 %5.3f r1 %5.3f rmax %5.3f\n",
+                            rn0,
+                            rn1,
+                            sqrt(*r2max));
                     for (int a1 = 0; a1 < depth; a1++)
                     {
-                        fprintf(debug, " %d %5.3f", path[a1],
+                        fprintf(debug,
+                                " %d %5.3f",
+                                path[a1],
                                 iparams[constr_iatomptr(ia1, ia2, con)[0]].constr.dA);
                     }
                     fprintf(debug, " %d %5.3f\n", con, len);
@@ -185,10 +189,10 @@ static real constr_r_max_moltype(const gmx_moltype_t*           molt,
         r1 = 0;
 
         count = 0;
-        constr_recur(at2con, molt->ilist, iparams, FALSE, at, 0, 1 + ir->nProjOrder, path, r0, r1,
-                     &r2maxA, &count);
+        constr_recur(
+                at2con, molt->ilist, iparams, FALSE, at, 0, 1 + ir->nProjOrder, path, r0, r1, &r2maxA, &count);
     }
-    if (ir->efep == efepNO)
+    if (ir->efep == FreeEnergyPerturbationType::No)
     {
         rmax = sqrt(r2maxA);
     }
@@ -200,8 +204,8 @@ static real constr_r_max_moltype(const gmx_moltype_t*           molt,
             r0    = 0;
             r1    = 0;
             count = 0;
-            constr_recur(at2con, molt->ilist, iparams, TRUE, at, 0, 1 + ir->nProjOrder, path, r0,
-                         r1, &r2maxB, &count);
+            constr_recur(
+                    at2con, molt->ilist, iparams, TRUE, at, 0, 1 + ir->nProjOrder, path, r0, r1, &r2maxB, &count);
         }
         lam0 = ir->fepvals->init_lambda;
         if (EI_DYNAMICS(ir->eI))
@@ -230,7 +234,8 @@ real constr_r_max(const MDLogger& mdlog, const gmx_mtop_t* mtop, const t_inputre
     GMX_LOG(mdlog.info)
             .appendTextFormatted(
                     "Maximum distance for %d constraints, at 120 deg. angles, all-trans: %.3f nm",
-                    1 + ir->nProjOrder, rmax);
+                    1 + ir->nProjOrder,
+                    rmax);
 
     return rmax;
 }
index 504ff512ed643c4bddced38abe476fe4c547d329..e6c3613f49e112f97e614f10a753253d921a53d5 100644 (file)
@@ -61,7 +61,6 @@
 #include "gromacs/mdtypes/group.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
-#include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/mdtypes/state.h"
 #include "gromacs/pbcutil/boxutilities.h"
 #include "gromacs/pbcutil/pbc.h"
 
 static const double sy_const_1[] = { 1. };
 static const double sy_const_3[] = { 0.828981543588751, -0.657963087177502, 0.828981543588751 };
-static const double sy_const_5[] = { 0.2967324292201065, 0.2967324292201065, -0.186929716880426,
-                                     0.2967324292201065, 0.2967324292201065 };
+static const double sy_const_5[] = { 0.2967324292201065,
+                                     0.2967324292201065,
+                                     -0.186929716880426,
+                                     0.2967324292201065,
+                                     0.2967324292201065 };
 
-static const double* sy_const[] = { nullptr, sy_const_1, nullptr, sy_const_3, nullptr, sy_const_5 };
+static constexpr std::array<const double*, 6> sy_const = { nullptr,    sy_const_1, nullptr,
+                                                           sy_const_3, nullptr,    sy_const_5 };
 
 
-void update_tcouple(int64_t           step,
-                    const t_inputrec* inputrec,
-                    t_state*          state,
-                    gmx_ekindata_t*   ekind,
-                    const t_extmass*  MassQ,
-                    const t_mdatoms*  md)
+void update_tcouple(int64_t                             step,
+                    const t_inputrec*                   inputrec,
+                    t_state*                            state,
+                    gmx_ekindata_t*                     ekind,
+                    const t_extmass*                    MassQ,
+                    int                                 homenr,
+                    gmx::ArrayRef<const unsigned short> cTC)
 
 {
     // This condition was explicitly checked in previous version, but should have never been satisfied
@@ -111,7 +115,7 @@ void update_tcouple(int64_t           step,
 
     // For VV temperature coupling parameters are updated on the current
     // step, for the others - one step before.
-    if (inputrec->etc == etcNO)
+    if (inputrec->etc == TemperatureCoupling::No)
     {
         doTemperatureCoupling = false;
     }
@@ -133,22 +137,25 @@ void update_tcouple(int64_t           step,
         //      subroutines
         switch (inputrec->etc)
         {
-            case etcNO: break;
-            case etcBERENDSEN:
+            case TemperatureCoupling::No:
+            case TemperatureCoupling::Andersen:
+            case TemperatureCoupling::AndersenMassive: break;
+            case TemperatureCoupling::Berendsen:
                 berendsen_tcoupl(inputrec, ekind, dttc, state->therm_integral);
                 break;
-            case etcNOSEHOOVER:
-                nosehoover_tcoupl(&(inputrec->opts), ekind, dttc, state->nosehoover_xi.data(),
-                                  state->nosehoover_vxi.data(), MassQ);
+            case TemperatureCoupling::NoseHoover:
+                nosehoover_tcoupl(
+                        &(inputrec->opts), ekind, dttc, state->nosehoover_xi, state->nosehoover_vxi, MassQ);
                 break;
-            case etcVRESCALE:
-                vrescale_tcoupl(inputrec, step, ekind, dttc, state->therm_integral.data());
+            case TemperatureCoupling::VRescale:
+                vrescale_tcoupl(inputrec, step, ekind, dttc, state->therm_integral);
                 break;
+            default: gmx_fatal(FARGS, "Unknown temperature coupling algorithm");
         }
         /* rescale in place here */
         if (EI_VV(inputrec->eI))
         {
-            rescale_velocities(ekind, md, 0, md->homenr, state->v.rvec_array());
+            rescale_velocities(ekind, cTC, 0, homenr, state->v);
         }
     }
     else
@@ -168,36 +175,36 @@ void update_pcouple_before_coordinates(FILE*             fplog,
                                        t_state*          state,
                                        matrix            parrinellorahmanMu,
                                        matrix            M,
-                                       gmx_bool          bInitStep)
+                                       bool              bInitStep)
 {
     /* 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
+    if (inputrec->epc == PressureCoupling::ParrinelloRahman
         && do_per_step(step + inputrec->nstpcouple - 1, inputrec->nstpcouple))
     {
         real dtpc = inputrec->nstpcouple * inputrec->delta_t;
 
-        parrinellorahman_pcoupl(fplog, step, inputrec, dtpc, state->pres_prev, state->box,
-                                state->box_rel, state->boxv, M, parrinellorahmanMu, bInitStep);
+        parrinellorahman_pcoupl(
+                fplog, step, inputrec, dtpc, state->pres_prev, state->box, state->box_rel, state->boxv, M, parrinellorahmanMu, bInitStep);
     }
 }
 
-void update_pcouple_after_coordinates(FILE*                fplog,
-                                      int64_t              step,
-                                      const t_inputrec*    inputrec,
-                                      const t_mdatoms*     md,
-                                      const matrix         pressure,
-                                      const matrix         forceVirial,
-                                      const matrix         constraintVirial,
-                                      matrix               pressureCouplingMu,
-                                      t_state*             state,
-                                      t_nrnb*              nrnb,
-                                      gmx::BoxDeformation* boxDeformation,
-                                      const bool           scaleCoordinates)
+void update_pcouple_after_coordinates(FILE*                               fplog,
+                                      int64_t                             step,
+                                      const t_inputrec*                   inputrec,
+                                      const int                           homenr,
+                                      gmx::ArrayRef<const unsigned short> cFREEZE,
+                                      const matrix                        pressure,
+                                      const matrix                        forceVirial,
+                                      const matrix                        constraintVirial,
+                                      matrix                              pressureCouplingMu,
+                                      t_state*                            state,
+                                      t_nrnb*                             nrnb,
+                                      gmx::BoxDeformation*                boxDeformation,
+                                      const bool                          scaleCoordinates)
 {
-    int start  = 0;
-    int homenr = md->homenr;
+    int start = 0;
 
     /* Cast to real for faster code, no loss in precision (see comment above) */
     real dt = inputrec->delta_t;
@@ -206,29 +213,63 @@ void update_pcouple_after_coordinates(FILE*                fplog,
     /* now update boxes */
     switch (inputrec->epc)
     {
-        case (epcNO): break;
-        case (epcBERENDSEN):
+        case (PressureCoupling::No): break;
+        case (PressureCoupling::Berendsen):
             if (do_per_step(step, inputrec->nstpcouple))
             {
                 real dtpc = inputrec->nstpcouple * dt;
-                berendsen_pcoupl(fplog, step, inputrec, dtpc, pressure, state->box, forceVirial,
-                                 constraintVirial, pressureCouplingMu, &state->baros_integral);
-                berendsen_pscale(inputrec, pressureCouplingMu, state->box, state->box_rel, start,
-                                 homenr, state->x.rvec_array(), md->cFREEZE, nrnb, scaleCoordinates);
+                pressureCouplingCalculateScalingMatrix<PressureCoupling::Berendsen>(fplog,
+                                                                                    step,
+                                                                                    inputrec,
+                                                                                    dtpc,
+                                                                                    pressure,
+                                                                                    state->box,
+                                                                                    forceVirial,
+                                                                                    constraintVirial,
+                                                                                    pressureCouplingMu,
+                                                                                    &state->baros_integral);
+                pressureCouplingScaleBoxAndCoordinates<PressureCoupling::Berendsen>(
+                        inputrec,
+                        pressureCouplingMu,
+                        state->box,
+                        state->box_rel,
+                        start,
+                        homenr,
+                        state->x,
+                        gmx::ArrayRef<gmx::RVec>(),
+                        cFREEZE,
+                        nrnb,
+                        scaleCoordinates);
             }
             break;
-        case (epcCRESCALE):
+        case (PressureCoupling::CRescale):
             if (do_per_step(step, inputrec->nstpcouple))
             {
                 real dtpc = inputrec->nstpcouple * dt;
-                crescale_pcoupl(fplog, step, inputrec, dtpc, pressure, state->box, forceVirial,
-                                constraintVirial, pressureCouplingMu, &state->baros_integral);
-                crescale_pscale(inputrec, pressureCouplingMu, state->box, state->box_rel, start,
-                                homenr, state->x.rvec_array(), state->v.rvec_array(), md->cFREEZE,
-                                nrnb, scaleCoordinates);
+                pressureCouplingCalculateScalingMatrix<PressureCoupling::CRescale>(fplog,
+                                                                                   step,
+                                                                                   inputrec,
+                                                                                   dtpc,
+                                                                                   pressure,
+                                                                                   state->box,
+                                                                                   forceVirial,
+                                                                                   constraintVirial,
+                                                                                   pressureCouplingMu,
+                                                                                   &state->baros_integral);
+                pressureCouplingScaleBoxAndCoordinates<PressureCoupling::CRescale>(inputrec,
+                                                                                   pressureCouplingMu,
+                                                                                   state->box,
+                                                                                   state->box_rel,
+                                                                                   start,
+                                                                                   homenr,
+                                                                                   state->x,
+                                                                                   state->v,
+                                                                                   cFREEZE,
+                                                                                   nrnb,
+                                                                                   scaleCoordinates);
             }
             break;
-        case (epcPARRINELLORAHMAN):
+        case (PressureCoupling::ParrinelloRahman):
             if (do_per_step(step + inputrec->nstpcouple - 1, inputrec->nstpcouple))
             {
                 /* The box velocities were updated in do_pr_pcoupl,
@@ -248,7 +289,7 @@ void update_pcouple_after_coordinates(FILE*                fplog,
                 /* Scale the coordinates */
                 if (scaleCoordinates)
                 {
-                    auto x = state->x.rvec_array();
+                    auto* x = state->x.rvec_array();
                     for (int n = start; n < start + homenr; n++)
                     {
                         tmvmul_ur0(pressureCouplingMu, x[n], x[n]);
@@ -256,10 +297,10 @@ void update_pcouple_after_coordinates(FILE*                fplog,
                 }
             }
             break;
-        case (epcMTTK):
+        case (PressureCoupling::Mttk):
             switch (inputrec->epct)
             {
-                case (epctISOTROPIC):
+                case (PressureCouplingType::Isotropic):
                     /* DIM * eta = ln V.  so DIM*eta_new = DIM*eta_old + DIM*dt*veta =>
                        ln V_new = ln V_old + 3*dt*veta => V_new = V_old*exp(3*dt*veta) =>
                        Side length scales as exp(veta*dt) */
@@ -290,18 +331,20 @@ void update_pcouple_after_coordinates(FILE*                fplog,
     }
 }
 
-extern gmx_bool update_randomize_velocities(const t_inputrec*        ir,
-                                            int64_t                  step,
-                                            const t_commrec*         cr,
-                                            const t_mdatoms*         md,
-                                            gmx::ArrayRef<gmx::RVec> v,
-                                            const gmx::Update*       upd,
-                                            const gmx::Constraints*  constr)
+extern bool update_randomize_velocities(const t_inputrec*                   ir,
+                                        int64_t                             step,
+                                        const t_commrec*                    cr,
+                                        int                                 homenr,
+                                        gmx::ArrayRef<const unsigned short> cTC,
+                                        gmx::ArrayRef<const real>           invMass,
+                                        gmx::ArrayRef<gmx::RVec>            v,
+                                        const gmx::Update*                  upd,
+                                        const gmx::Constraints*             constr)
 {
 
     real rate = (ir->delta_t) / ir->opts.tau_t[0];
 
-    if (ir->etc == etcANDERSEN && constr != nullptr)
+    if (ir->etc == TemperatureCoupling::Andersen && constr != nullptr)
     {
         /* Currently, Andersen thermostat does not support constrained
            systems. Functionality exists in the andersen_tcoupl
@@ -316,25 +359,15 @@ extern gmx_bool update_randomize_velocities(const t_inputrec*        ir,
 
     /* proceed with andersen if 1) it's fixed probability per
        particle andersen or 2) it's massive andersen and it's tau_t/dt */
-    if ((ir->etc == etcANDERSEN) || do_per_step(step, gmx::roundToInt(1.0 / rate)))
+    if ((ir->etc == TemperatureCoupling::Andersen) || do_per_step(step, gmx::roundToInt(1.0 / rate)))
     {
-        andersen_tcoupl(ir, step, cr, md, v, rate, upd->getAndersenRandomizeGroup(),
-                        upd->getBoltzmanFactor());
+        andersen_tcoupl(
+                ir, step, cr, homenr, cTC, invMass, v, rate, upd->getAndersenRandomizeGroup(), upd->getBoltzmanFactor());
         return TRUE;
     }
     return FALSE;
 }
 
-/*
-   static const double sy_const[MAX_SUZUKI_YOSHIDA_NUM+1][MAX_SUZUKI_YOSHIDA_NUM+1] = {
-    {},
-    {1},
-    {},
-    {0.828981543588751,-0.657963087177502,0.828981543588751},
-    {},
-    {0.2967324292201065,0.2967324292201065,-0.186929716880426,0.2967324292201065,0.2967324292201065}
-   };*/
-
 /* these integration routines are only referenced inside this file */
 static void NHC_trotter(const t_grpopts*      opts,
                         int                   nvar,
@@ -345,20 +378,20 @@ static void NHC_trotter(const t_grpopts*      opts,
                         double                scalefac[],
                         real*                 veta,
                         const t_extmass*      MassQ,
-                        gmx_bool              bEkinAveVel)
+                        bool                  bEkinAveVel)
 
 {
     /* general routine for both barostat and thermostat nose hoover chains */
 
-    int      i, j, mi, mj;
-    double   Ekin, Efac, reft, kT, nd;
-    double   dt;
-    double * ivxi, *ixi;
-    double*  GQ;
-    gmx_bool bBarostat;
-    int      mstepsi, mstepsj;
-    int      ns = SUZUKI_YOSHIDA_NUM; /* set the degree of integration in the types/state.h file */
-    int      nh = opts->nhchainlength;
+    int     i, j, mi, mj;
+    double  Ekin, Efac, reft, kT, nd;
+    double  dt;
+    double *ivxi, *ixi;
+    double* GQ;
+    bool    bBarostat;
+    int     mstepsi, mstepsj;
+    int     ns = SUZUKI_YOSHIDA_NUM; /* set the degree of integration in the types/state.h file */
+    int     nh = opts->nhchainlength;
 
     snew(GQ, nh);
     mstepsi = mstepsj = ns;
@@ -402,7 +435,7 @@ static void NHC_trotter(const t_grpopts*      opts,
                 Ekin = 2 * trace(tcstat->ekinh) * tcstat->ekinscaleh_nhc;
             }
         }
-        kT = BOLTZ * reft;
+        kT = gmx::c_boltz * reft;
 
         for (mi = 0; mi < mstepsi; mi++)
         {
@@ -498,7 +531,7 @@ static void boxv_trotter(const t_inputrec*     ir,
        2006 Tuckerman et al paper., the order is iL_{T_baro} iL {T_part}
      */
 
-    if (ir->epct == epctSEMIISOTROPIC)
+    if (ir->epct == PressureCouplingType::SemiIsotropic)
     {
         nwall = 2;
     }
@@ -528,7 +561,8 @@ static void boxv_trotter(const t_inputrec*     ir,
     pscal = calc_pres(ir->pbcType, nwall, box, ekinmod, vir, localpres) + pcorr;
 
     vol = det(box);
-    GW  = (vol * (MassQ->Winv / PRESFAC)) * (DIM * pscal - trace(ir->ref_p)); /* W is in ps^2 * bar * nm^3 */
+    GW  = (vol * (MassQ->Winv / gmx::c_presfac))
+         * (DIM * pscal - trace(ir->ref_p)); /* W is in ps^2 * bar * nm^3 */
 
     *veta += 0.5 * dt * GW;
 }
@@ -557,7 +591,7 @@ real calc_pres(PbcType pbcType, int nwall, const matrix box, const tensor ekin,
          * het systeem...
          */
 
-        fac = PRESFAC * 2.0 / det(box);
+        fac = gmx::c_presfac * 2.0 / det(box);
         for (n = 0; (n < DIM); n++)
         {
             for (m = 0; (m < DIM); m++)
@@ -581,7 +615,7 @@ real calc_temp(real ekin, real nrdf)
 {
     if (nrdf > 0)
     {
-        return (2.0 * ekin) / (nrdf * BOLTZ);
+        return (2.0 * ekin) / (nrdf * gmx::c_boltz);
     }
     else
     {
@@ -589,7 +623,7 @@ real calc_temp(real ekin, real nrdf)
     }
 }
 
-/*! \brief Sets 1/mass for Parrinello-Rahman in wInv; NOTE: PRESFAC is not included, so not in GROMACS units! */
+/*! \brief Sets 1/mass for Parrinello-Rahman in wInv; NOTE: c_presfac is not included, so not in GROMACS units! */
 static void calcParrinelloRahmanInvMass(const t_inputrec* ir, const matrix box, tensor wInv)
 {
     real maxBoxLength;
@@ -617,7 +651,7 @@ void parrinellorahman_pcoupl(FILE*             fplog,
                              tensor            boxv,
                              tensor            M,
                              matrix            mu,
-                             gmx_bool          bFirstStep)
+                             bool              bFirstStep)
 {
     /* This doesn't do any coordinate updating. It just
      * integrates the box vector equations from the calculated
@@ -652,7 +686,7 @@ void parrinellorahman_pcoupl(FILE*             fplog,
 
     if (!bFirstStep)
     {
-        /* Note that PRESFAC does not occur here.
+        /* Note that c_presfac does not occur here.
          * The pressure and compressibility always occur as a product,
          * therefore the pressure unit drops out.
          */
@@ -661,7 +695,7 @@ void parrinellorahman_pcoupl(FILE*             fplog,
 
         m_sub(pres, ir->ref_p, pdiff);
 
-        if (ir->epct == epctSURFACETENSION)
+        if (ir->epct == PressureCouplingType::SurfaceTension)
         {
             /* Unlike Berendsen coupling it might not be trivial to include a z
              * pressure correction here? On the other hand we don't scale the
@@ -689,7 +723,7 @@ void parrinellorahman_pcoupl(FILE*             fplog,
 
         switch (ir->epct)
         {
-            case epctANISOTROPIC:
+            case PressureCouplingType::Anisotropic:
                 for (int d = 0; d < DIM; d++)
                 {
                     for (int n = 0; n <= d; n++)
@@ -698,7 +732,7 @@ void parrinellorahman_pcoupl(FILE*             fplog,
                     }
                 }
                 break;
-            case epctISOTROPIC:
+            case PressureCouplingType::Isotropic:
                 /* calculate total volume acceleration */
                 atot = box[XX][XX] * box[YY][YY] * t1[ZZ][ZZ] + box[XX][XX] * t1[YY][YY] * box[ZZ][ZZ]
                        + t1[XX][XX] * box[YY][YY] * box[ZZ][ZZ];
@@ -713,8 +747,8 @@ void parrinellorahman_pcoupl(FILE*             fplog,
                     }
                 }
                 break;
-            case epctSEMIISOTROPIC:
-            case epctSURFACETENSION:
+            case PressureCouplingType::SemiIsotropic:
+            case PressureCouplingType::SurfaceTension:
                 /* Note the correction to pdiff above for surftens. coupling  */
 
                 /* calculate total XY volume acceleration */
@@ -738,7 +772,7 @@ void parrinellorahman_pcoupl(FILE*             fplog,
                 gmx_fatal(FARGS,
                           "Parrinello-Rahman pressure coupling type %s "
                           "not supported yet\n",
-                          EPCOUPLTYPETYPE(ir->epct));
+                          enumValueToString(ir->epct));
         }
 
         real maxchange = 0;
@@ -800,25 +834,34 @@ void parrinellorahman_pcoupl(FILE*             fplog,
     mmul_ur0(invbox, t1, mu);
 }
 
-void berendsen_pcoupl(FILE*             fplog,
-                      int64_t           step,
-                      const t_inputrec* ir,
-                      real              dt,
-                      const tensor      pres,
-                      const matrix      box,
-                      const matrix      force_vir,
-                      const matrix      constraint_vir,
-                      matrix            mu,
-                      double*           baros_integral)
+//! Return compressibility factor for entry (i,j) of Berendsen / C-rescale scaling matrix
+static inline real compressibilityFactor(int i, int j, const t_inputrec* ir, real dt)
 {
-    real scalar_pressure, xy_pressure, p_corr_z;
-    char buf[STRLEN];
+    return ir->compress[i][j] * dt / ir->tau_p;
+}
 
-    /*
-     *  Calculate the scaling matrix mu
-     */
-    scalar_pressure = 0;
-    xy_pressure     = 0;
+//! Details of Berendsen / C-rescale scaling matrix calculation
+template<PressureCoupling pressureCouplingType>
+static void calculateScalingMatrixImplDetail(const t_inputrec* ir,
+                                             matrix            mu,
+                                             real              dt,
+                                             const matrix      pres,
+                                             const matrix      box,
+                                             real              scalar_pressure,
+                                             real              xy_pressure,
+                                             int64_t           step);
+
+//! Calculate Berendsen / C-rescale scaling matrix
+template<PressureCoupling pressureCouplingType>
+static void calculateScalingMatrixImpl(const t_inputrec* ir,
+                                       matrix            mu,
+                                       real              dt,
+                                       const matrix      pres,
+                                       const matrix      box,
+                                       int64_t           step)
+{
+    real scalar_pressure = 0;
+    real xy_pressure     = 0;
     for (int d = 0; d < DIM; d++)
     {
         scalar_pressure += pres[d][d] / DIM;
@@ -827,38 +870,49 @@ void berendsen_pcoupl(FILE*             fplog,
             xy_pressure += pres[d][d] / (DIM - 1);
         }
     }
-    /* Pressure is now in bar, everywhere. */
-#define factor(d, m) (ir->compress[d][m] * dt / ir->tau_p)
-
-    /* mu has been changed from pow(1+...,1/3) to 1+.../3, since this is
-     * necessary for triclinic scaling
-     */
     clear_mat(mu);
+    calculateScalingMatrixImplDetail<pressureCouplingType>(
+            ir, mu, dt, pres, box, scalar_pressure, xy_pressure, step);
+}
+
+template<>
+void calculateScalingMatrixImplDetail<PressureCoupling::Berendsen>(const t_inputrec* ir,
+                                                                   matrix            mu,
+                                                                   real              dt,
+                                                                   const matrix      pres,
+                                                                   const matrix      box,
+                                                                   real    scalar_pressure,
+                                                                   real    xy_pressure,
+                                                                   int64_t gmx_unused step)
+{
+    real p_corr_z = 0;
     switch (ir->epct)
     {
-        case epctISOTROPIC:
+        case PressureCouplingType::Isotropic:
             for (int d = 0; d < DIM; d++)
             {
-                mu[d][d] = 1.0 - factor(d, d) * (ir->ref_p[d][d] - scalar_pressure) / DIM;
+                mu[d][d] = 1.0 - compressibilityFactor(d, d, ir, dt) * (ir->ref_p[d][d] - scalar_pressure) / DIM;
             }
             break;
-        case epctSEMIISOTROPIC:
+        case PressureCouplingType::SemiIsotropic:
             for (int d = 0; d < ZZ; d++)
             {
-                mu[d][d] = 1.0 - factor(d, d) * (ir->ref_p[d][d] - xy_pressure) / DIM;
+                mu[d][d] = 1.0 - compressibilityFactor(d, d, ir, dt) * (ir->ref_p[d][d] - xy_pressure) / DIM;
             }
-            mu[ZZ][ZZ] = 1.0 - factor(ZZ, ZZ) * (ir->ref_p[ZZ][ZZ] - pres[ZZ][ZZ]) / DIM;
+            mu[ZZ][ZZ] =
+                    1.0 - compressibilityFactor(ZZ, ZZ, ir, dt) * (ir->ref_p[ZZ][ZZ] - pres[ZZ][ZZ]) / DIM;
             break;
-        case epctANISOTROPIC:
+        case PressureCouplingType::Anisotropic:
             for (int d = 0; d < DIM; d++)
             {
                 for (int n = 0; n < DIM; n++)
                 {
-                    mu[d][n] = (d == n ? 1.0 : 0.0) - factor(d, n) * (ir->ref_p[d][n] - pres[d][n]) / DIM;
+                    mu[d][n] = (d == n ? 1.0 : 0.0)
+                               - compressibilityFactor(d, n, ir, dt) * (ir->ref_p[d][n] - pres[d][n]) / DIM;
                 }
             }
             break;
-        case epctSURFACETENSION:
+        case PressureCouplingType::SurfaceTension:
             /* ir->ref_p[0/1] is the reference surface-tension times *
              * the number of surfaces                                */
             if (ir->compress[ZZ][ZZ] != 0.0F)
@@ -875,93 +929,29 @@ void berendsen_pcoupl(FILE*             fplog,
             for (int d = 0; d < DIM - 1; d++)
             {
                 mu[d][d] = 1.0
-                           + factor(d, d)
+                           + compressibilityFactor(d, d, ir, dt)
                                      * (ir->ref_p[d][d] / (mu[ZZ][ZZ] * box[ZZ][ZZ])
                                         - (pres[ZZ][ZZ] + p_corr_z - xy_pressure))
                                      / (DIM - 1);
             }
             break;
         default:
-            gmx_fatal(FARGS, "Berendsen pressure coupling type %s not supported yet\n",
-                      EPCOUPLTYPETYPE(ir->epct));
-    }
-    /* To fullfill the orientation restrictions on triclinic boxes
-     * we will set mu_yx, mu_zx and mu_zy to 0 and correct
-     * the other elements of mu to first order.
-     */
-    mu[YY][XX] += mu[XX][YY];
-    mu[ZZ][XX] += mu[XX][ZZ];
-    mu[ZZ][YY] += mu[YY][ZZ];
-    mu[XX][YY] = 0;
-    mu[XX][ZZ] = 0;
-    mu[YY][ZZ] = 0;
-
-    /* Keep track of the work the barostat applies on the system.
-     * Without constraints force_vir tells us how Epot changes when scaling.
-     * With constraints constraint_vir gives us the constraint contribution
-     * to both Epot and Ekin. Although we are not scaling velocities, scaling
-     * the coordinates leads to scaling of distances involved in constraints.
-     * This in turn changes the angular momentum (even if the constrained
-     * distances are corrected at the next step). The kinetic component
-     * of the constraint virial captures the angular momentum change.
-     */
-    for (int d = 0; d < DIM; d++)
-    {
-        for (int n = 0; n <= d; n++)
-        {
-            *baros_integral -=
-                    2 * (mu[d][n] - (n == d ? 1 : 0)) * (force_vir[d][n] + constraint_vir[d][n]);
-        }
-    }
-
-    if (debug)
-    {
-        pr_rvecs(debug, 0, "PC: pres ", pres, 3);
-        pr_rvecs(debug, 0, "PC: mu   ", mu, 3);
-    }
-
-    if (mu[XX][XX] < 0.99 || mu[XX][XX] > 1.01 || mu[YY][YY] < 0.99 || mu[YY][YY] > 1.01
-        || mu[ZZ][ZZ] < 0.99 || mu[ZZ][ZZ] > 1.01)
-    {
-        char buf2[22];
-        sprintf(buf,
-                "\nStep %s  Warning: pressure scaling more than 1%%, "
-                "mu: %g %g %g\n",
-                gmx_step_str(step, buf2), mu[XX][XX], mu[YY][YY], mu[ZZ][ZZ]);
-        if (fplog)
-        {
-            fprintf(fplog, "%s", buf);
-        }
-        fprintf(stderr, "%s", buf);
+            gmx_fatal(FARGS,
+                      "Berendsen pressure coupling type %s not supported yet\n",
+                      enumValueToString(ir->epct));
     }
 }
 
-void crescale_pcoupl(FILE*             fplog,
-                     int64_t           step,
-                     const t_inputrec* ir,
-                     real              dt,
-                     const tensor      pres,
-                     const matrix      box,
-                     const matrix      force_vir,
-                     const matrix      constraint_vir,
-                     matrix            mu,
-                     double*           baros_integral)
+template<>
+void calculateScalingMatrixImplDetail<PressureCoupling::CRescale>(const t_inputrec* ir,
+                                                                  matrix            mu,
+                                                                  real              dt,
+                                                                  const matrix      pres,
+                                                                  const matrix      box,
+                                                                  real              scalar_pressure,
+                                                                  real              xy_pressure,
+                                                                  int64_t           step)
 {
-    /*
-     *  Calculate the scaling matrix mu
-     */
-    real scalar_pressure = 0;
-    real xy_pressure     = 0;
-    for (int d = 0; d < DIM; d++)
-    {
-        scalar_pressure += pres[d][d] / DIM;
-        if (d != ZZ)
-        {
-            xy_pressure += pres[d][d] / (DIM - 1);
-        }
-    }
-    clear_mat(mu);
-
     gmx::ThreeFry2x64<64>         rng(ir->ld_seed, gmx::RandomDomain::Barostat);
     gmx::NormalDistribution<real> normalDist;
     rng.restart(step, 0);
@@ -970,9 +960,9 @@ void crescale_pcoupl(FILE*             fplog,
     {
         vol *= box[d][d];
     }
-    real gauss;
-    real gauss2;
-    real kt = ir->opts.ref_t[0] * BOLTZ;
+    real gauss  = 0;
+    real gauss2 = 0;
+    real kt     = ir->opts.ref_t[0] * gmx::c_boltz;
     if (kt < 0.0)
     {
         kt = 0.0;
@@ -980,59 +970,75 @@ void crescale_pcoupl(FILE*             fplog,
 
     switch (ir->epct)
     {
-        case epctISOTROPIC:
+        case PressureCouplingType::Isotropic:
             gauss = normalDist(rng);
             for (int d = 0; d < DIM; d++)
             {
-                const real compressibilityFactor = ir->compress[d][d] * dt / ir->tau_p;
-                mu[d][d] = std::exp(-compressibilityFactor * (ir->ref_p[d][d] - scalar_pressure) / DIM
-                                    + std::sqrt(2.0 * kt * compressibilityFactor * PRESFAC / vol)
-                                              * gauss / DIM);
+                const real factor = compressibilityFactor(d, d, ir, dt);
+                mu[d][d]          = std::exp(-factor * (ir->ref_p[d][d] - scalar_pressure) / DIM
+                                    + std::sqrt(2.0 * kt * factor * gmx::c_presfac / vol) * gauss / DIM);
             }
             break;
-        case epctSEMIISOTROPIC:
+        case PressureCouplingType::SemiIsotropic:
             gauss  = normalDist(rng);
             gauss2 = normalDist(rng);
             for (int d = 0; d < ZZ; d++)
             {
-                const real compressibilityFactor = ir->compress[d][d] * dt / ir->tau_p;
-                mu[d][d]                         = std::exp(
-                        -compressibilityFactor * (ir->ref_p[d][d] - xy_pressure) / DIM
-                        + std::sqrt((DIM - 1) * 2.0 * kt * compressibilityFactor * PRESFAC / vol / DIM)
-                                  / (DIM - 1) * gauss);
+                const real factor = compressibilityFactor(d, d, ir, dt);
+                mu[d][d]          = std::exp(-factor * (ir->ref_p[d][d] - xy_pressure) / DIM
+                                    + std::sqrt((DIM - 1) * 2.0 * kt * factor * gmx::c_presfac / vol / DIM)
+                                              / (DIM - 1) * gauss);
             }
             {
-                const real compressibilityFactor = ir->compress[ZZ][ZZ] * dt / ir->tau_p;
-                mu[ZZ][ZZ]                       = std::exp(
-                        -compressibilityFactor * (ir->ref_p[ZZ][ZZ] - pres[ZZ][ZZ]) / DIM
-                        + std::sqrt(2.0 * kt * compressibilityFactor * PRESFAC / vol / DIM) * gauss2);
+                const real factor = compressibilityFactor(ZZ, ZZ, ir, dt);
+                mu[ZZ][ZZ]        = std::exp(-factor * (ir->ref_p[ZZ][ZZ] - pres[ZZ][ZZ]) / DIM
+                                      + std::sqrt(2.0 * kt * factor * gmx::c_presfac / vol / DIM) * gauss2);
             }
             break;
-        case epctSURFACETENSION:
+        case PressureCouplingType::SurfaceTension:
             gauss  = normalDist(rng);
             gauss2 = normalDist(rng);
             for (int d = 0; d < ZZ; d++)
             {
-                const real compressibilityFactor = ir->compress[d][d] * dt / ir->tau_p;
+                const real factor = compressibilityFactor(d, d, ir, dt);
                 /* Notice: we here use ref_p[ZZ][ZZ] as isotropic pressure and ir->ref_p[d][d] as surface tension */
                 mu[d][d] = std::exp(
-                        -compressibilityFactor
-                                * (ir->ref_p[ZZ][ZZ] - ir->ref_p[d][d] / box[ZZ][ZZ] - xy_pressure) / DIM
-                        + std::sqrt(4.0 / 3.0 * kt * compressibilityFactor * PRESFAC / vol)
-                                  / (DIM - 1) * gauss);
+                        -factor * (ir->ref_p[ZZ][ZZ] - ir->ref_p[d][d] / box[ZZ][ZZ] - xy_pressure) / DIM
+                        + std::sqrt(4.0 / 3.0 * kt * factor * gmx::c_presfac / vol) / (DIM - 1) * gauss);
             }
             {
-                const real compressibilityFactor = ir->compress[ZZ][ZZ] * dt / ir->tau_p;
-                mu[ZZ][ZZ]                       = std::exp(
-                        -compressibilityFactor * (ir->ref_p[ZZ][ZZ] - pres[ZZ][ZZ]) / DIM
-                        + std::sqrt(2.0 / 3.0 * kt * compressibilityFactor * PRESFAC / vol) * gauss2);
+                const real factor = compressibilityFactor(ZZ, ZZ, ir, dt);
+                mu[ZZ][ZZ]        = std::exp(-factor * (ir->ref_p[ZZ][ZZ] - pres[ZZ][ZZ]) / DIM
+                                      + std::sqrt(2.0 / 3.0 * kt * factor * gmx::c_presfac / vol) * gauss2);
             }
             break;
         default:
-            gmx_fatal(FARGS, "C-rescale pressure coupling type %s not supported yet\n",
-                      EPCOUPLTYPETYPE(ir->epct));
+            gmx_fatal(FARGS,
+                      "C-rescale pressure coupling type %s not supported yet\n",
+                      enumValueToString(ir->epct));
     }
-    /* To fullfill the orientation restrictions on triclinic boxes
+}
+
+template<PressureCoupling pressureCouplingType>
+void pressureCouplingCalculateScalingMatrix(FILE*             fplog,
+                                            int64_t           step,
+                                            const t_inputrec* ir,
+                                            real              dt,
+                                            const tensor      pres,
+                                            const matrix      box,
+                                            const matrix      force_vir,
+                                            const matrix      constraint_vir,
+                                            matrix            mu,
+                                            double*           baros_integral)
+{
+    static_assert(pressureCouplingType == PressureCoupling::Berendsen
+                          || pressureCouplingType == PressureCoupling::CRescale,
+                  "pressureCouplingCalculateScalingMatrix is only implemented for Berendsen and "
+                  "C-rescale pressure coupling");
+
+    calculateScalingMatrixImpl<pressureCouplingType>(ir, mu, dt, pres, box, step);
+
+    /* To fulfill the orientation restrictions on triclinic boxes
      * we will set mu_yx, mu_zx and mu_zy to 0 and correct
      * the other elements of mu to first order.
      */
@@ -1075,7 +1081,10 @@ void crescale_pcoupl(FILE*             fplog,
         sprintf(buf,
                 "\nStep %s  Warning: pressure scaling more than 1%%, "
                 "mu: %g %g %g\n",
-                gmx_step_str(step, buf2), mu[XX][XX], mu[YY][YY], mu[ZZ][ZZ]);
+                gmx_step_str(step, buf2),
+                mu[XX][XX],
+                mu[YY][YY],
+                mu[ZZ][ZZ]);
         if (fplog)
         {
             fprintf(fplog, "%s", buf);
@@ -1084,113 +1093,41 @@ void crescale_pcoupl(FILE*             fplog,
     }
 }
 
-void crescale_pscale(const t_inputrec*    ir,
-                     const matrix         mu,
-                     matrix               box,
-                     matrix               box_rel,
-                     int                  start,
-                     int                  nr_atoms,
-                     rvec                 x[],
-                     rvec                 v[],
-                     const unsigned short cFREEZE[],
-                     t_nrnb*              nrnb,
-                     const bool           scaleCoordinates)
+template<PressureCoupling pressureCouplingType>
+void pressureCouplingScaleBoxAndCoordinates(const t_inputrec*                   ir,
+                                            const matrix                        mu,
+                                            matrix                              box,
+                                            matrix                              box_rel,
+                                            int                                 start,
+                                            int                                 nr_atoms,
+                                            gmx::ArrayRef<gmx::RVec>            x,
+                                            gmx::ArrayRef<gmx::RVec>            v,
+                                            gmx::ArrayRef<const unsigned short> cFREEZE,
+                                            t_nrnb*                             nrnb,
+                                            const bool                          scaleCoordinates)
 {
-    ivec* nFreeze = ir->opts.nFreeze;
-    int nthreads gmx_unused;
-    matrix       inv_mu;
-
-#ifndef __clang_analyzer__
-    nthreads = gmx_omp_nthreads_get(emntUpdate);
-#endif
-
-    gmx::invertBoxMatrix(mu, inv_mu);
-
-    /* Scale the positions and the velocities */
-    if (scaleCoordinates)
-    {
-#pragma omp parallel for num_threads(nthreads) schedule(static)
-        for (int n = start; n < start + nr_atoms; n++)
-        {
-            // Trivial OpenMP region that does not throw
-            int g;
+    static_assert(pressureCouplingType == PressureCoupling::Berendsen
+                          || pressureCouplingType == PressureCoupling::CRescale,
+                  "pressureCouplingScaleBoxAndCoordinates is only implemented for Berendsen and "
+                  "C-rescale pressure coupling");
 
-            if (cFREEZE == nullptr)
-            {
-                g = 0;
-            }
-            else
-            {
-                g = cFREEZE[n];
-            }
-
-            if (!nFreeze[g][XX])
-            {
-                x[n][XX] = mu[XX][XX] * x[n][XX] + mu[YY][XX] * x[n][YY] + mu[ZZ][XX] * x[n][ZZ];
-                v[n][XX] = inv_mu[XX][XX] * v[n][XX] + inv_mu[YY][XX] * v[n][YY]
-                           + inv_mu[ZZ][XX] * v[n][ZZ];
-            }
-            if (!nFreeze[g][YY])
-            {
-                x[n][YY] = mu[YY][YY] * x[n][YY] + mu[ZZ][YY] * x[n][ZZ];
-                v[n][YY] = inv_mu[YY][YY] * v[n][YY] + inv_mu[ZZ][YY] * v[n][ZZ];
-            }
-            if (!nFreeze[g][ZZ])
-            {
-                x[n][ZZ] = mu[ZZ][ZZ] * x[n][ZZ];
-                v[n][ZZ] = inv_mu[ZZ][ZZ] * v[n][ZZ];
-            }
-        }
-    }
-    /* compute final boxlengths */
-    for (int d = 0; d < DIM; d++)
+    ivec*  nFreeze = ir->opts.nFreeze;
+    matrix inv_mu;
+    if (pressureCouplingType == PressureCoupling::CRescale)
     {
-        box[d][XX] = mu[XX][XX] * box[d][XX] + mu[YY][XX] * box[d][YY] + mu[ZZ][XX] * box[d][ZZ];
-        box[d][YY] = mu[YY][YY] * box[d][YY] + mu[ZZ][YY] * box[d][ZZ];
-        box[d][ZZ] = mu[ZZ][ZZ] * box[d][ZZ];
+        gmx::invertBoxMatrix(mu, inv_mu);
     }
 
-    preserve_box_shape(ir, box_rel, box);
-
-    /* (un)shifting should NOT be done after this,
-     * since the box vectors might have changed
-     */
-    inc_nrnb(nrnb, eNR_PCOUPL, nr_atoms);
-}
-
-void berendsen_pscale(const t_inputrec*    ir,
-                      const matrix         mu,
-                      matrix               box,
-                      matrix               box_rel,
-                      int                  start,
-                      int                  nr_atoms,
-                      rvec                 x[],
-                      const unsigned short cFREEZE[],
-                      t_nrnb*              nrnb,
-                      const bool           scaleCoordinates)
-{
-    ivec* nFreeze = ir->opts.nFreeze;
-    int   d;
-    int nthreads gmx_unused;
-
-#ifndef __clang_analyzer__
-    nthreads = gmx_omp_nthreads_get(emntUpdate);
-#endif
-
-    /* Scale the positions */
+    /* Scale the positions and the velocities */
     if (scaleCoordinates)
     {
-#pragma omp parallel for num_threads(nthreads) schedule(static)
+        const int gmx_unused numThreads = gmx_omp_nthreads_get(ModuleMultiThread::Update);
+#pragma omp parallel for num_threads(numThreads) schedule(static)
         for (int n = start; n < start + nr_atoms; n++)
         {
             // Trivial OpenMP region that does not throw
-            int g;
-
-            if (cFREEZE == nullptr)
-            {
-                g = 0;
-            }
-            else
+            int g = 0;
+            if (!cFREEZE.empty())
             {
                 g = cFREEZE[n];
             }
@@ -1198,19 +1135,32 @@ void berendsen_pscale(const t_inputrec*    ir,
             if (!nFreeze[g][XX])
             {
                 x[n][XX] = mu[XX][XX] * x[n][XX] + mu[YY][XX] * x[n][YY] + mu[ZZ][XX] * x[n][ZZ];
+                if (pressureCouplingType == PressureCoupling::CRescale)
+                {
+                    v[n][XX] = inv_mu[XX][XX] * v[n][XX] + inv_mu[YY][XX] * v[n][YY]
+                               + inv_mu[ZZ][XX] * v[n][ZZ];
+                }
             }
             if (!nFreeze[g][YY])
             {
                 x[n][YY] = mu[YY][YY] * x[n][YY] + mu[ZZ][YY] * x[n][ZZ];
+                if (pressureCouplingType == PressureCoupling::CRescale)
+                {
+                    v[n][YY] = inv_mu[YY][YY] * v[n][YY] + inv_mu[ZZ][YY] * v[n][ZZ];
+                }
             }
             if (!nFreeze[g][ZZ])
             {
                 x[n][ZZ] = mu[ZZ][ZZ] * x[n][ZZ];
+                if (pressureCouplingType == PressureCoupling::CRescale)
+                {
+                    v[n][ZZ] = inv_mu[ZZ][ZZ] * v[n][ZZ];
+                }
             }
         }
     }
     /* compute final boxlengths */
-    for (d = 0; d < DIM; d++)
+    for (int d = 0; d < DIM; d++)
     {
         box[d][XX] = mu[XX][XX] * box[d][XX] + mu[YY][XX] * box[d][YY] + mu[ZZ][XX] * box[d][ZZ];
         box[d][YY] = mu[YY][YY] * box[d][YY] + mu[ZZ][YY] * box[d][ZZ];
@@ -1233,7 +1183,7 @@ void berendsen_tcoupl(const t_inputrec* ir, gmx_ekindata_t* ekind, real dt, std:
     {
         real Ek, T;
 
-        if (ir->eI == eiVV)
+        if (ir->eI == IntegrationAlgorithm::VV)
         {
             Ek = trace(ekind->tcstat[i].ekinf);
             T  = ekind->tcstat[i].T;
@@ -1265,14 +1215,16 @@ void berendsen_tcoupl(const t_inputrec* ir, gmx_ekindata_t* ekind, real dt, std:
     }
 }
 
-void andersen_tcoupl(const t_inputrec*         ir,
-                     int64_t                   step,
-                     const t_commrec*          cr,
-                     const t_mdatoms*          md,
-                     gmx::ArrayRef<gmx::RVec>  v,
-                     real                      rate,
-                     const std::vector<bool>&  randomize,
-                     gmx::ArrayRef<const real> boltzfac)
+void andersen_tcoupl(const t_inputrec*                   ir,
+                     int64_t                             step,
+                     const t_commrec*                    cr,
+                     const int                           homenr,
+                     gmx::ArrayRef<const unsigned short> cTC,
+                     gmx::ArrayRef<const real>           invMass,
+                     gmx::ArrayRef<gmx::RVec>            v,
+                     real                                rate,
+                     const std::vector<bool>&            randomize,
+                     gmx::ArrayRef<const real>           boltzfac)
 {
     const int*           gatindex = (DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
     int                  i;
@@ -1283,20 +1235,20 @@ void andersen_tcoupl(const t_inputrec*         ir,
 
     /* randomize the velocities of the selected particles */
 
-    for (i = 0; i < md->homenr; i++) /* now loop over the list of atoms */
+    for (i = 0; i < homenr; i++) /* now loop over the list of atoms */
     {
-        int      ng = gatindex ? gatindex[i] : i;
-        gmx_bool bRandomize;
+        int  ng = gatindex ? gatindex[i] : i;
+        bool bRandomize;
 
         rng.restart(step, ng);
 
-        if (md->cTC)
+        if (!cTC.empty())
         {
-            gc = md->cTC[i]; /* assign the atom to a temperature group if there are more than one */
+            gc = cTC[i]; /* assign the atom to a temperature group if there are more than one */
         }
         if (randomize[gc])
         {
-            if (ir->etc == etcANDERSENMASSIVE)
+            if (ir->etc == TemperatureCoupling::AndersenMassive)
             {
                 /* Randomize particle always */
                 bRandomize = TRUE;
@@ -1312,7 +1264,7 @@ void andersen_tcoupl(const t_inputrec*         ir,
                 real scal;
                 int  d;
 
-                scal = std::sqrt(boltzfac[gc] * md->invmass[i]);
+                scal = std::sqrt(boltzfac[gc] * invMass[i]);
 
                 normalDist.reset();
 
@@ -1329,8 +1281,8 @@ void andersen_tcoupl(const t_inputrec*         ir,
 void nosehoover_tcoupl(const t_grpopts*      opts,
                        const gmx_ekindata_t* ekind,
                        real                  dt,
-                       double                xi[],
-                       double                vxi[],
+                       gmx::ArrayRef<double> xi,
+                       gmx::ArrayRef<double> vxi,
                        const t_extmass*      MassQ)
 {
     int  i;
@@ -1347,16 +1299,18 @@ void nosehoover_tcoupl(const t_grpopts*      opts,
     }
 }
 
-void trotter_update(const t_inputrec*               ir,
-                    int64_t                         step,
-                    gmx_ekindata_t*                 ekind,
-                    const gmx_enerdata_t*           enerd,
-                    t_state*                        state,
-                    const tensor                    vir,
-                    const t_mdatoms*                md,
-                    const t_extmass*                MassQ,
-                    gmx::ArrayRef<std::vector<int>> trotter_seqlist,
-                    int                             trotter_seqno)
+void trotter_update(const t_inputrec*                   ir,
+                    int64_t                             step,
+                    gmx_ekindata_t*                     ekind,
+                    const gmx_enerdata_t*               enerd,
+                    t_state*                            state,
+                    const tensor                        vir,
+                    int                                 homenr,
+                    gmx::ArrayRef<const unsigned short> cTC,
+                    gmx::ArrayRef<const real>           invMass,
+                    const t_extmass*                    MassQ,
+                    gmx::ArrayRef<std::vector<int>>     trotter_seqlist,
+                    int                                 trotter_seqno)
 {
 
     int              n, i, d, ngtc, gc = 0, t;
@@ -1366,7 +1320,7 @@ void trotter_update(const t_inputrec*               ir,
     real             dt;
     double *         scalefac, dtc;
     rvec             sumv = { 0, 0, 0 };
-    gmx_bool         bCouple;
+    bool             bCouple;
 
     if (trotter_seqno <= ettTSEQ2)
     {
@@ -1416,18 +1370,33 @@ void trotter_update(const t_inputrec*               ir,
         {
             case etrtBAROV:
             case etrtBAROV2:
-                boxv_trotter(ir, &(state->veta), dt, state->box, ekind, vir,
-                             enerd->term[F_PDISPCORR], MassQ);
+                boxv_trotter(ir, &(state->veta), dt, state->box, ekind, vir, enerd->term[F_PDISPCORR], MassQ);
                 break;
             case etrtBARONHC:
             case etrtBARONHC2:
-                NHC_trotter(opts, state->nnhpres, ekind, dt, state->nhpres_xi.data(),
-                            state->nhpres_vxi.data(), nullptr, &(state->veta), MassQ, FALSE);
+                NHC_trotter(opts,
+                            state->nnhpres,
+                            ekind,
+                            dt,
+                            state->nhpres_xi.data(),
+                            state->nhpres_vxi.data(),
+                            nullptr,
+                            &(state->veta),
+                            MassQ,
+                            FALSE);
                 break;
             case etrtNHC:
             case etrtNHC2:
-                NHC_trotter(opts, opts->ngtc, ekind, dt, state->nosehoover_xi.data(),
-                            state->nosehoover_vxi.data(), scalefac, nullptr, MassQ, (ir->eI == eiVV));
+                NHC_trotter(opts,
+                            opts->ngtc,
+                            ekind,
+                            dt,
+                            state->nosehoover_xi.data(),
+                            state->nosehoover_vxi.data(),
+                            scalefac,
+                            nullptr,
+                            MassQ,
+                            (ir->eI == IntegrationAlgorithm::VV));
                 /* 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. */
@@ -1443,11 +1412,11 @@ void trotter_update(const t_inputrec*               ir,
                 /* but do we actually need the total? */
 
                 /* modify the velocities as well */
-                for (n = 0; n < md->homenr; n++)
+                for (n = 0; n < homenr; n++)
                 {
-                    if (md->cTC) /* does this conditional need to be here? is this always true?*/
+                    if (!cTC.empty()) /* does this conditional need to be here? is this always true?*/
                     {
-                        gc = md->cTC[n];
+                        gc = cTC[n];
                     }
                     for (d = 0; d < DIM; d++)
                     {
@@ -1458,7 +1427,7 @@ void trotter_update(const t_inputrec*               ir,
                     {
                         for (d = 0; d < DIM; d++)
                         {
-                            sumv[d] += (v[n][d]) / md->invmass[n];
+                            sumv[d] += (v[n][d]) / invMass[n];
                         }
                     }
                 }
@@ -1471,7 +1440,7 @@ void trotter_update(const t_inputrec*               ir,
 }
 
 
-extern void init_npt_masses(const t_inputrec* ir, t_state* state, t_extmass* MassQ, gmx_bool bInit)
+extern void init_npt_masses(const t_inputrec* ir, t_state* state, t_extmass* MassQ, bool bInit)
 {
     int              n, i, j, d, ngtc, nh;
     const t_grpopts* opts;
@@ -1481,7 +1450,7 @@ extern void init_npt_masses(const t_inputrec* ir, t_state* state, t_extmass* Mas
     ngtc = ir->opts.ngtc;
     nh   = state->nhchainlength;
 
-    if (ir->eI == eiMD)
+    if (ir->eI == IntegrationAlgorithm::MD)
     {
         if (bInit)
         {
@@ -1516,16 +1485,16 @@ extern void init_npt_masses(const t_inputrec* ir, t_state* state, t_extmass* Mas
 
         /* units are nm^3 * ns^2 / (nm^3 * bar / kJ/mol) = kJ/mol  */
         /* Consider evaluating eventually if this the right mass to use.  All are correct, some might be more stable  */
-        MassQ->Winv = (PRESFAC * trace(ir->compress) * BOLTZ * opts->ref_t[0])
+        MassQ->Winv = (gmx::c_presfac * trace(ir->compress) * gmx::c_boltz * opts->ref_t[0])
                       / (DIM * state->vol0 * gmx::square(ir->tau_p / M_2PI));
         /* An alternate mass definition, from Tuckerman et al. */
-        /* MassQ->Winv = 1.0/(gmx::square(ir->tau_p/M_2PI)*(opts->nrdf[0]+DIM)*BOLTZ*opts->ref_t[0]); */
+        /* MassQ->Winv = 1.0/(gmx::square(ir->tau_p/M_2PI)*(opts->nrdf[0]+DIM)*c_boltz*opts->ref_t[0]); */
         for (d = 0; d < DIM; d++)
         {
             for (n = 0; n < DIM; n++)
             {
-                MassQ->Winvm[d][n] =
-                        PRESFAC * ir->compress[d][n] / (state->vol0 * gmx::square(ir->tau_p / M_2PI));
+                MassQ->Winvm[d][n] = gmx::c_presfac * ir->compress[d][n]
+                                     / (state->vol0 * gmx::square(ir->tau_p / M_2PI));
                 /* not clear this is correct yet for the anisotropic case. Will need to reevaluate
                    before using MTTK for anisotropic states.*/
             }
@@ -1543,7 +1512,7 @@ extern void init_npt_masses(const t_inputrec* ir, t_state* state, t_extmass* Mas
             {
                 reft = std::max<real>(0, opts->ref_t[i]);
                 nd   = opts->nrdf[i];
-                kT   = BOLTZ * reft;
+                kT   = gmx::c_boltz * reft;
                 for (j = 0; j < nh; j++)
                 {
                     if (j == 0)
@@ -1569,7 +1538,7 @@ extern void init_npt_masses(const t_inputrec* ir, t_state* state, t_extmass* Mas
 }
 
 std::array<std::vector<int>, ettTSEQMAX>
-init_npt_vars(const t_inputrec* ir, t_state* state, t_extmass* MassQ, gmx_bool bTrotter)
+init_npt_vars(const t_inputrec* ir, t_state* state, t_extmass* MassQ, bool bTrotter)
 {
     int              i, j, nnhpres, nh;
     const t_grpopts* opts;
@@ -1579,10 +1548,9 @@ init_npt_vars(const t_inputrec* ir, t_state* state, t_extmass* MassQ, gmx_bool b
     nnhpres = state->nnhpres;
     nh      = state->nhchainlength;
 
-    if (EI_VV(ir->eI) && (ir->epc == epcMTTK) && (ir->etc != etcNOSEHOOVER))
+    if (EI_VV(ir->eI) && (ir->epc == PressureCoupling::Mttk) && (ir->etc != TemperatureCoupling::NoseHoover))
     {
-        gmx_fatal(FARGS,
-                  "Cannot do MTTK pressure coupling without Nose-Hoover temperature control");
+        gmx_fatal(FARGS, "Cannot do MTTK pressure coupling without Nose-Hoover temperature control");
     }
 
     init_npt_masses(ir, state, MassQ, TRUE);
@@ -1607,7 +1575,7 @@ init_npt_vars(const t_inputrec* ir, t_state* state, t_extmass* MassQ, gmx_bool b
     /* compute the kinetic energy by using the half step velocities or
      * the kinetic energies, depending on the order of the trotter calls */
 
-    if (ir->eI == eiVV)
+    if (ir->eI == IntegrationAlgorithm::VV)
     {
         if (inputrecNptTrotter(ir))
         {
@@ -1657,7 +1625,7 @@ init_npt_vars(const t_inputrec* ir, t_state* state, t_extmass* MassQ, gmx_bool b
             /* trotter_seq[4] is etrtNHC for second 1/2 step velocities - leave zero */
         }
     }
-    else if (ir->eI == eiVVAK)
+    else if (ir->eI == IntegrationAlgorithm::VVAK)
     {
         if (inputrecNptTrotter(ir))
         {
@@ -1711,7 +1679,7 @@ init_npt_vars(const t_inputrec* ir, t_state* state, t_extmass* MassQ, gmx_bool b
 
     switch (ir->epct)
     {
-        case epctISOTROPIC:
+        case PressureCouplingType::Isotropic:
         default: bmass = DIM * DIM; /* recommended mass parameters for isotropic barostat */
     }
 
@@ -1721,7 +1689,7 @@ init_npt_vars(const t_inputrec* ir, t_state* state, t_extmass* MassQ, gmx_bool b
     if ((ir->tau_p > 0) && (opts->ref_t[0] > 0))
     {
         reft = std::max<real>(0, opts->ref_t[0]);
-        kT   = BOLTZ * reft;
+        kT   = gmx::c_boltz * reft;
         for (i = 0; i < nnhpres; i++)
         {
             for (j = 0; j < nh; j++)
@@ -1766,7 +1734,7 @@ static real energyNoseHoover(const t_inputrec* ir, const t_state* state, const t
 
         real nd   = ir->opts.nrdf[i];
         real reft = std::max<real>(ir->opts.ref_t[i], 0);
-        real kT   = BOLTZ * reft;
+        real kT   = gmx::c_boltz * reft;
 
         if (nd > 0.0)
         {
@@ -1794,7 +1762,7 @@ static real energyNoseHoover(const t_inputrec* ir, const t_state* state, const t
             }
             else /* Other non Trotter temperature NH control  -- no chains yet. */
             {
-                energy += 0.5 * BOLTZ * nd * gmx::square(ivxi[0]) / iQinv[0];
+                energy += 0.5 * gmx::c_boltz * nd * gmx::square(ivxi[0]) / iQinv[0];
                 energy += nd * ixi[0] * kT;
             }
         }
@@ -1814,7 +1782,7 @@ static real energyPressureMTTK(const t_inputrec* ir, const t_state* state, const
     {
         /* 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;
+        real kT   = gmx::c_boltz * reft;
 
         for (int j = 0; j < nh; j++)
         {
@@ -1827,8 +1795,12 @@ static real energyPressureMTTK(const t_inputrec* ir, const t_state* state, const
             }
             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]);
+                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]);
             }
         }
     }
@@ -1852,7 +1824,7 @@ real NPT_energy(const t_inputrec* ir, const t_state* state, const t_extmass* Mas
 {
     real energyNPT = 0;
 
-    if (ir->epc != epcNO)
+    if (ir->epc != PressureCoupling::No)
     {
         /* Compute the contribution of the pressure to the conserved quantity*/
 
@@ -1860,7 +1832,7 @@ real NPT_energy(const t_inputrec* ir, const t_state* state, const t_extmass* Mas
 
         switch (ir->epc)
         {
-            case epcPARRINELLORAHMAN:
+            case PressureCoupling::ParrinelloRahman:
             {
                 /* contribution from the pressure momenta */
                 tensor invMass;
@@ -1871,7 +1843,8 @@ real NPT_energy(const t_inputrec* ir, const t_state* state, const t_extmass* Mas
                     {
                         if (invMass[d][n] > 0)
                         {
-                            energyNPT += 0.5 * gmx::square(state->boxv[d][n]) / (invMass[d][n] * PRESFAC);
+                            energyNPT += 0.5 * gmx::square(state->boxv[d][n])
+                                         / (invMass[d][n] * gmx::c_presfac);
                         }
                     }
                 }
@@ -1883,24 +1856,24 @@ real NPT_energy(const t_inputrec* ir, const t_state* state, const t_extmass* Mas
                  * track of unwrapped box diagonal elements. This case is
                  * excluded in integratorHasConservedEnergyQuantity().
                  */
-                energyNPT += vol * trace(ir->ref_p) / (DIM * PRESFAC);
+                energyNPT += vol * trace(ir->ref_p) / (DIM * gmx::c_presfac);
                 break;
             }
-            case epcMTTK:
+            case PressureCoupling::Mttk:
                 /* contribution from the pressure momenta */
                 energyNPT += 0.5 * gmx::square(state->veta) / MassQ->Winv;
 
                 /* contribution from the PV term */
-                energyNPT += vol * trace(ir->ref_p) / (DIM * PRESFAC);
+                energyNPT += vol * trace(ir->ref_p) / (DIM * gmx::c_presfac);
 
-                if (ir->epc == epcMTTK)
+                if (ir->epc == PressureCoupling::Mttk)
                 {
                     /* contribution from the MTTK chain */
                     energyNPT += energyPressureMTTK(ir, state, MassQ);
                 }
                 break;
-            case epcBERENDSEN:
-            case epcCRESCALE: energyNPT += state->baros_integral; break;
+            case PressureCoupling::Berendsen:
+            case PressureCoupling::CRescale: energyNPT += state->baros_integral; break;
             default:
                 GMX_RELEASE_ASSERT(
                         false,
@@ -1912,12 +1885,14 @@ real NPT_energy(const t_inputrec* ir, const t_state* state, const t_extmass* Mas
 
     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:
+        case TemperatureCoupling::No: break;
+        case TemperatureCoupling::VRescale:
+        case TemperatureCoupling::Berendsen: energyNPT += energyVrescale(ir, state); break;
+        case TemperatureCoupling::NoseHoover:
+            energyNPT += energyNoseHoover(ir, state, MassQ);
+            break;
+        case TemperatureCoupling::Andersen:
+        case TemperatureCoupling::AndersenMassive:
             // Not supported, excluded in integratorHasConservedEnergyQuantity()
             break;
         default:
@@ -2009,7 +1984,7 @@ real vrescale_resamplekin(real kk, real sigma, real ndeg, real taut, int64_t ste
     return ekin_new;
 }
 
-void vrescale_tcoupl(const t_inputrec* ir, int64_t step, gmx_ekindata_t* ekind, real dt, double therm_integral[])
+void vrescale_tcoupl(const t_inputrec* ir, int64_t step, gmx_ekindata_t* ekind, real dt, gmx::ArrayRef<double> therm_integral)
 {
     const t_grpopts* opts;
     int              i;
@@ -2019,7 +1994,7 @@ void vrescale_tcoupl(const t_inputrec* ir, int64_t step, gmx_ekindata_t* ekind,
 
     for (i = 0; (i < opts->ngtc); i++)
     {
-        if (ir->eI == eiVV)
+        if (ir->eI == IntegrationAlgorithm::VV)
         {
             Ek = trace(ekind->tcstat[i].ekinf);
         }
@@ -2030,7 +2005,7 @@ void vrescale_tcoupl(const t_inputrec* ir, int64_t step, gmx_ekindata_t* ekind,
 
         if (opts->tau_t[i] >= 0 && opts->nrdf[i] > 0 && Ek > 0)
         {
-            Ek_ref1 = 0.5 * opts->ref_t[i] * BOLTZ;
+            Ek_ref1 = 0.5 * opts->ref_t[i] * gmx::c_boltz;
             Ek_ref  = Ek_ref1 * opts->nrdf[i];
 
             Ek_new = vrescale_resamplekin(Ek, Ek_ref, opts->nrdf[i], opts->tau_t[i] / dt, step, ir->ld_seed);
@@ -2049,8 +2024,13 @@ void vrescale_tcoupl(const t_inputrec* ir, int64_t step, gmx_ekindata_t* ekind,
 
             if (debug)
             {
-                fprintf(debug, "TC: group %d: Ekr %g, Ek %g, Ek_new %g, Lambda: %g\n", i, Ek_ref,
-                        Ek, Ek_new, ekind->tcstat[i].lambda);
+                fprintf(debug,
+                        "TC: group %d: Ekr %g, Ek %g, Ek_new %g, Lambda: %g\n",
+                        i,
+                        Ek_ref,
+                        Ek,
+                        Ek_new,
+                        ekind->tcstat[i].lambda);
             }
         }
         else
@@ -2060,57 +2040,25 @@ void vrescale_tcoupl(const t_inputrec* ir, int64_t step, gmx_ekindata_t* ekind,
     }
 }
 
-void rescale_velocities(const gmx_ekindata_t* ekind, const t_mdatoms* mdatoms, int start, int end, rvec v[])
+void rescale_velocities(const gmx_ekindata_t*               ekind,
+                        gmx::ArrayRef<const unsigned short> cTC,
+                        int                                 start,
+                        int                                 end,
+                        gmx::ArrayRef<gmx::RVec>            v)
 {
-    unsigned short *cACC, *cTC;
-    int             ga, gt, n, d;
-    real            lg;
-    rvec            vrel;
-
-    cTC = mdatoms->cTC;
-
     gmx::ArrayRef<const t_grp_tcstat> tcstat = ekind->tcstat;
 
-    if (ekind->bNEMD)
+    for (int n = start; n < end; n++)
     {
-        gmx::ArrayRef<const t_grp_acc> gstat = ekind->grpstat;
-        cACC                                 = mdatoms->cACC;
-
-        ga = 0;
-        gt = 0;
-        for (n = start; n < end; n++)
+        int gt = 0;
+        if (!cTC.empty())
         {
-            if (cACC)
-            {
-                ga = cACC[n];
-            }
-            if (cTC)
-            {
-                gt = cTC[n];
-            }
-            /* Only scale the velocity component relative to the COM velocity */
-            rvec_sub(v[n], gstat[ga].u, vrel);
-            lg = tcstat[gt].lambda;
-            for (d = 0; d < DIM; d++)
-            {
-                v[n][d] = gstat[ga].u[d] + lg * vrel[d];
-            }
+            gt = cTC[n];
         }
-    }
-    else
-    {
-        gt = 0;
-        for (n = start; n < end; n++)
+        const real lg = tcstat[gt].lambda;
+        for (int d = 0; d < DIM; d++)
         {
-            if (cTC)
-            {
-                gt = cTC[n];
-            }
-            lg = tcstat[gt].lambda;
-            for (d = 0; d < DIM; d++)
-            {
-                v[n][d] *= lg;
-            }
+            v[n][d] *= lg;
         }
     }
 }
@@ -2121,7 +2069,7 @@ bool doSimulatedAnnealing(const t_inputrec* ir)
     for (int i = 0; i < ir->opts.ngtc; i++)
     {
         /* set bSimAnn if any group is being annealed */
-        if (ir->opts.annealing[i] != eannNO)
+        if (ir->opts.annealing[i] != SimulatedAnnealing::No)
         {
             return true;
         }
@@ -2152,8 +2100,8 @@ void update_annealing_target_temp(t_inputrec* ir, real t, gmx::Update* upd)
         npoints = ir->opts.anneal_npoints[i];
         switch (ir->opts.annealing[i])
         {
-            case eannNO: continue;
-            case eannPERIODIC:
+            case SimulatedAnnealing::No: continue;
+            case SimulatedAnnealing::Periodic:
                 /* calculate time modulo the period */
                 pert  = ir->opts.anneal_time[i][npoints - 1];
                 n     = static_cast<int>(t / pert);
@@ -2164,10 +2112,13 @@ void update_annealing_target_temp(t_inputrec* ir, real t, gmx::Update* upd)
                     thist = 0;
                 }
                 break;
-            case eannSINGLE: thist = t; break;
+            case SimulatedAnnealing::Single: thist = t; break;
             default:
-                gmx_fatal(FARGS, "Death horror in update_annealing_target_temp (i=%d/%d npoints=%d)",
-                          i, ir->opts.ngtc, npoints);
+                gmx_fatal(FARGS,
+                          "Death horror in update_annealing_target_temp (i=%d/%d npoints=%d)",
+                          i,
+                          ir->opts.ngtc,
+                          npoints);
         }
         /* We are doing annealing for this group if we got here,
          * and we have the (relative) time as thist.
@@ -2208,20 +2159,20 @@ void pleaseCiteCouplingAlgorithms(FILE* fplog, const t_inputrec& ir)
 {
     if (EI_DYNAMICS(ir.eI))
     {
-        if (ir.etc == etcBERENDSEN)
+        if (ir.etc == TemperatureCoupling::Berendsen)
         {
             please_cite(fplog, "Berendsen84a");
         }
-        if (ir.etc == etcVRESCALE)
+        if (ir.etc == TemperatureCoupling::VRescale)
         {
             please_cite(fplog, "Bussi2007a");
         }
-        if (ir.epc == epcCRESCALE)
+        if (ir.epc == PressureCoupling::CRescale)
         {
             please_cite(fplog, "Bernetti2020");
         }
         // TODO this is actually an integrator, not a coupling algorithm
-        if (ir.eI == eiSD1)
+        if (ir.eI == IntegrationAlgorithm::SD1)
         {
             please_cite(fplog, "Goga2012");
         }
index 1d95925b8153f6dbdda1dffad3a0192dfa41e040..92333c5cca85786e228f5e76c8c5b3b3007f0c95 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_MDLIB_COUPLING_H
 #define GMX_MDLIB_COUPLING_H
 
-#include "gromacs/math/paddedvector.h"
+#include <cstdio>
+
+#include <array>
+#include <vector>
+
 #include "gromacs/math/vectypes.h"
 #include "gromacs/mdtypes/md_enums.h"
-#include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
-struct gmx_ekindata_t;
+class gmx_ekindata_t;
 struct gmx_enerdata_t;
 struct t_commrec;
 struct t_extmass;
 struct t_grpopts;
 struct t_inputrec;
-struct t_mdatoms;
 struct t_nrnb;
 class t_state;
 
@@ -62,17 +63,20 @@ namespace gmx
 class BoxDeformation;
 class Constraints;
 class Update;
+template<typename>
+class ArrayRef;
 }; // namespace gmx
 
 /* Update the size of per-atom arrays (e.g. after DD re-partitioning,
    which might increase the number of home atoms). */
 
-void update_tcouple(int64_t           step,
-                    const t_inputrec* inputrec,
-                    t_state*          state,
-                    gmx_ekindata_t*   ekind,
-                    const t_extmass*  MassQ,
-                    const t_mdatoms*  md);
+void update_tcouple(int64_t                             step,
+                    const t_inputrec*                   inputrec,
+                    t_state*                            state,
+                    gmx_ekindata_t*                     ekind,
+                    const t_extmass*                    MassQ,
+                    int                                 homenr,
+                    gmx::ArrayRef<const unsigned short> cTC);
 
 /* Update Parrinello-Rahman, to be called before the coordinate update */
 void update_pcouple_before_coordinates(FILE*             fplog,
@@ -81,78 +85,93 @@ void update_pcouple_before_coordinates(FILE*             fplog,
                                        t_state*          state,
                                        matrix            parrinellorahmanMu,
                                        matrix            M,
-                                       gmx_bool          bInitStep);
+                                       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,
-                                      int64_t              step,
-                                      const t_inputrec*    inputrec,
-                                      const t_mdatoms*     md,
-                                      const matrix         pressure,
-                                      const matrix         forceVirial,
-                                      const matrix         constraintVirial,
-                                      matrix               pressureCouplingMu,
-                                      t_state*             state,
-                                      t_nrnb*              nrnb,
-                                      gmx::BoxDeformation* boxDeformation,
-                                      bool                 scaleCoordinates);
+void update_pcouple_after_coordinates(FILE*                               fplog,
+                                      int64_t                             step,
+                                      const t_inputrec*                   inputrec,
+                                      int                                 homenr,
+                                      gmx::ArrayRef<const unsigned short> cFREEZE,
+                                      const matrix                        pressure,
+                                      const matrix                        forceVirial,
+                                      const matrix                        constraintVirial,
+                                      matrix                              pressureCouplingMu,
+                                      t_state*                            state,
+                                      t_nrnb*                             nrnb,
+                                      gmx::BoxDeformation*                boxDeformation,
+                                      bool                                scaleCoordinates);
 
 /* Return TRUE if OK, FALSE in case of Shake Error */
 
-extern gmx_bool update_randomize_velocities(const t_inputrec*        ir,
-                                            int64_t                  step,
-                                            const t_commrec*         cr,
-                                            const t_mdatoms*         md,
-                                            gmx::ArrayRef<gmx::RVec> v,
-                                            const gmx::Update*       upd,
-                                            const gmx::Constraints*  constr);
+extern bool update_randomize_velocities(const t_inputrec*                   ir,
+                                        int64_t                             step,
+                                        const t_commrec*                    cr,
+                                        int                                 homenr,
+                                        gmx::ArrayRef<const unsigned short> cTC,
+                                        gmx::ArrayRef<const real>           invMass,
+                                        gmx::ArrayRef<gmx::RVec>            v,
+                                        const gmx::Update*                  upd,
+                                        const gmx::Constraints*             constr);
 
 void berendsen_tcoupl(const t_inputrec*    ir,
                       gmx_ekindata_t*      ekind,
                       real                 dt,
                       std::vector<double>& therm_integral); //NOLINT(google-runtime-references)
 
-void andersen_tcoupl(const t_inputrec*         ir,
-                     int64_t                   step,
-                     const t_commrec*          cr,
-                     const t_mdatoms*          md,
-                     gmx::ArrayRef<gmx::RVec>  v,
-                     real                      rate,
-                     const std::vector<bool>&  randomize,
-                     gmx::ArrayRef<const real> boltzfac);
+void andersen_tcoupl(const t_inputrec*                   ir,
+                     int64_t                             step,
+                     const t_commrec*                    cr,
+                     int                                 homenr,
+                     gmx::ArrayRef<const unsigned short> cTC,
+                     gmx::ArrayRef<const real>           invMass,
+                     gmx::ArrayRef<gmx::RVec>            v,
+                     real                                rate,
+                     const std::vector<bool>&            randomize,
+                     gmx::ArrayRef<const real>           boltzfac);
 
 void nosehoover_tcoupl(const t_grpopts*      opts,
                        const gmx_ekindata_t* ekind,
                        real                  dt,
-                       double                xi[],
-                       double                vxi[],
+                       gmx::ArrayRef<double> xi,
+                       gmx::ArrayRef<double> vxi,
                        const t_extmass*      MassQ);
 
-void trotter_update(const t_inputrec*               ir,
-                    int64_t                         step,
-                    gmx_ekindata_t*                 ekind,
-                    const gmx_enerdata_t*           enerd,
-                    t_state*                        state,
-                    const tensor                    vir,
-                    const t_mdatoms*                md,
-                    const t_extmass*                MassQ,
-                    gmx::ArrayRef<std::vector<int>> trotter_seqlist,
-                    int                             trotter_seqno);
+void trotter_update(const t_inputrec*                   ir,
+                    int64_t                             step,
+                    gmx_ekindata_t*                     ekind,
+                    const gmx_enerdata_t*               enerd,
+                    t_state*                            state,
+                    const tensor                        vir,
+                    int                                 homenr,
+                    gmx::ArrayRef<const unsigned short> cTC,
+                    gmx::ArrayRef<const real>           invMass,
+                    const t_extmass*                    MassQ,
+                    gmx::ArrayRef<std::vector<int>>     trotter_seqlist,
+                    int                                 trotter_seqno);
 
 std::array<std::vector<int>, ettTSEQMAX>
-init_npt_vars(const t_inputrec* ir, t_state* state, t_extmass* Mass, gmx_bool bTrotter);
+init_npt_vars(const t_inputrec* ir, t_state* state, t_extmass* Mass, bool bTrotter);
 
 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 vrescale_tcoupl(const t_inputrec* ir, int64_t step, gmx_ekindata_t* ekind, real dt, double therm_integral[]);
+void vrescale_tcoupl(const t_inputrec*     ir,
+                     int64_t               step,
+                     gmx_ekindata_t*       ekind,
+                     real                  dt,
+                     gmx::ArrayRef<double> therm_integral);
 /* Compute temperature scaling. For V-rescale it is done in update. */
 
-void rescale_velocities(const gmx_ekindata_t* ekind, const t_mdatoms* mdatoms, int start, int end, rvec v[]);
+void rescale_velocities(const gmx_ekindata_t*               ekind,
+                        gmx::ArrayRef<const unsigned short> cTC,
+                        int                                 start,
+                        int                                 end,
+                        gmx::ArrayRef<gmx::RVec>            v);
 /* Rescale the velocities with the scaling factor in ekind */
 
 //! Check whether we do simulated annealing.
@@ -183,51 +202,45 @@ void parrinellorahman_pcoupl(FILE*             fplog,
                              tensor            boxv,
                              tensor            M,
                              matrix            mu,
-                             gmx_bool          bFirstStep);
-
-void berendsen_pcoupl(FILE*             fplog,
-                      int64_t           step,
-                      const t_inputrec* ir,
-                      real              dt,
-                      const tensor      pres,
-                      const matrix      box,
-                      const matrix      force_vir,
-                      const matrix      constraint_vir,
-                      matrix            mu,
-                      double*           baros_integral);
-
-void berendsen_pscale(const t_inputrec*    ir,
-                      const matrix         mu,
-                      matrix               box,
-                      matrix               box_rel,
-                      int                  start,
-                      int                  nr_atoms,
-                      rvec                 x[],
-                      const unsigned short cFREEZE[],
-                      t_nrnb*              nrnb,
-                      bool                 scaleCoordinates);
-void crescale_pcoupl(FILE*             fplog,
-                     int64_t           step,
-                     const t_inputrec* ir,
-                     real              dt,
-                     const tensor      pres,
-                     const matrix      box,
-                     const matrix      force_vir,
-                     const matrix      constraint_vir,
-                     matrix            mu,
-                     double*           baros_integral);
-
-void crescale_pscale(const t_inputrec*    ir,
-                     const matrix         mu,
-                     matrix               box,
-                     matrix               box_rel,
-                     int                  start,
-                     int                  nr_atoms,
-                     rvec                 x[],
-                     rvec                 v[],
-                     const unsigned short cFREEZE[],
-                     t_nrnb*              nrnb,
-                     bool                 scaleCoordinates);
+                             bool              bFirstStep);
+
+/*! \brief Calculate the pressure coupling scaling matrix
+ *
+ * Used by Berendsen and C-Rescale pressure coupling, this function
+ * computes the current value of the scaling matrix. The template
+ * parameter determines the pressure coupling algorithm.
+ */
+template<PressureCoupling pressureCouplingType>
+void pressureCouplingCalculateScalingMatrix(FILE*             fplog,
+                                            int64_t           step,
+                                            const t_inputrec* ir,
+                                            real              dt,
+                                            const tensor      pres,
+                                            const matrix      box,
+                                            const matrix      force_vir,
+                                            const matrix      constraint_vir,
+                                            matrix            mu,
+                                            double*           baros_integral);
+
+/*! \brief Scale the box and coordinates
+ *
+ * Used by Berendsen and C-Rescale pressure coupling, this function scales
+ * the box, the positions, and the velocities (C-Rescale only) according to
+ * the scaling matrix mu. The template parameter determines the pressure
+ * coupling algorithm.
+ */
+template<PressureCoupling pressureCouplingType>
+void pressureCouplingScaleBoxAndCoordinates(const t_inputrec*                   ir,
+                                            const matrix                        mu,
+                                            matrix                              box,
+                                            matrix                              box_rel,
+                                            int                                 start,
+                                            int                                 nr_atoms,
+                                            gmx::ArrayRef<gmx::RVec>            x,
+                                            gmx::ArrayRef<gmx::RVec>            v,
+                                            gmx::ArrayRef<const unsigned short> cFREEZE,
+                                            t_nrnb*                             nrnb,
+                                            bool                                scaleCoordinates);
 
 void pleaseCiteCouplingAlgorithms(FILE* fplog, const t_inputrec& ir);
 
index b4871765ced15e39c3909915758cb70f15cafe28..4494d09f68c457081a3943ca58d5bea02f7a3ffb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +57,8 @@
 DispersionCorrection::InteractionParams::~InteractionParams() = default;
 
 /* Returns a matrix, as flat list, of combination rule combined LJ parameters */
-static std::vector<real> mk_nbfp_combination_rule(const gmx_ffparams_t& ffparams, const int comb_rule)
+static std::vector<real> mk_nbfp_combination_rule(const gmx_ffparams_t& ffparams,
+                                                  const CombinationRule comb_rule)
 {
     const int atnr = ffparams.atnr;
 
@@ -73,7 +74,7 @@ static std::vector<real> mk_nbfp_combination_rule(const gmx_ffparams_t& ffparams
             const real c12j = ffparams.iparams[j * (atnr + 1)].lj.c12;
             real       c6   = std::sqrt(c6i * c6j);
             real       c12  = std::sqrt(c12i * c12j);
-            if (comb_rule == eCOMB_ARITHMETIC && !gmx_numzero(c6) && !gmx_numzero(c12))
+            if (comb_rule == CombinationRule::Arithmetic && !gmx_numzero(c6) && !gmx_numzero(c12))
             {
                 const real sigmai = gmx::sixthroot(c12i / c6i);
                 const real sigmaj = gmx::sixthroot(c12j / c6j);
@@ -121,9 +122,10 @@ DispersionCorrection::TopologyParams::TopologyParams(const gmx_mtop_t&         m
      * combination rules. */
     if (EVDW_PME(inputrec.vdwtype))
     {
-        nbfp_comb = mk_nbfp_combination_rule(
-                mtop.ffparams,
-                (inputrec.ljpme_combination_rule == eljpmeLB) ? eCOMB_ARITHMETIC : eCOMB_GEOMETRIC);
+        nbfp_comb = mk_nbfp_combination_rule(mtop.ffparams,
+                                             (inputrec.ljpme_combination_rule == LongRangeVdW::LB)
+                                                     ? CombinationRule::Arithmetic
+                                                     : CombinationRule::Geometric);
         for (int tpi = 0; tpi < ntp; ++tpi)
         {
             for (int tpj = 0; tpj < ntp; ++tpj)
@@ -135,7 +137,7 @@ DispersionCorrection::TopologyParams::TopologyParams(const gmx_mtop_t&         m
         nbfp = nbfp_comb;
     }
 
-    for (int q = 0; q < (inputrec.efep == efepNO ? 1 : 2); q++)
+    for (int q = 0; q < (inputrec.efep == FreeEnergyPerturbationType::No ? 1 : 2); q++)
     {
         double  csix    = 0;
         double  ctwelve = 0;
@@ -148,7 +150,7 @@ DispersionCorrection::TopologyParams::TopologyParams(const gmx_mtop_t&         m
 
             /* Count the types so we avoid natoms^2 operations */
             std::vector<int> typecount(ntp);
-            gmx_mtop_count_atomtypes(&mtop, q, typecount.data());
+            gmx_mtop_count_atomtypes(mtop, q, typecount.data());
 
             for (int tpi = 0; tpi < ntp; tpi++)
             {
@@ -384,18 +386,20 @@ void DispersionCorrection::setInteractionParameters(InteractionParams*         i
     InteractionCorrection energy;
     InteractionCorrection virial;
 
-    if ((ic.vdw_modifier == eintmodPOTSHIFT) || (ic.vdw_modifier == eintmodPOTSWITCH)
-        || (ic.vdw_modifier == eintmodFORCESWITCH) || (ic.vdwtype == evdwSHIFT)
-        || (ic.vdwtype == evdwSWITCH))
+    if ((ic.vdw_modifier == InteractionModifiers::PotShift)
+        || (ic.vdw_modifier == InteractionModifiers::PotSwitch)
+        || (ic.vdw_modifier == InteractionModifiers::ForceSwitch)
+        || (ic.vdwtype == VanDerWaalsType::Shift) || (ic.vdwtype == VanDerWaalsType::Switch))
     {
-        if (((ic.vdw_modifier == eintmodPOTSWITCH) || (ic.vdw_modifier == eintmodFORCESWITCH)
-             || (ic.vdwtype == evdwSWITCH))
+        if (((ic.vdw_modifier == InteractionModifiers::PotSwitch)
+             || (ic.vdw_modifier == InteractionModifiers::ForceSwitch)
+             || (ic.vdwtype == VanDerWaalsType::Switch))
             && ic.rvdw_switch == 0)
         {
             gmx_fatal(FARGS,
                       "With dispersion correction rvdw-switch can not be zero "
                       "for vdw-type = %s",
-                      evdw_names[ic.vdwtype]);
+                      enumValueToString(ic.vdwtype));
         }
 
         GMX_ASSERT(iParams->dispersionCorrectionTable_, "We need an initialized table");
@@ -429,13 +433,13 @@ void DispersionCorrection::setInteractionParameters(InteractionParams*         i
          * we need to calculate the constant shift up to the point where we
          * start modifying the potential.
          */
-        ri0 = (ic.vdw_modifier == eintmodPOTSHIFT) ? ri1 : ri0;
+        ri0 = (ic.vdw_modifier == InteractionModifiers::PotShift) ? ri1 : ri0;
 
         const double r0  = ri0 / scale;
         const double rc3 = r0 * r0 * r0;
         const double rc9 = rc3 * rc3 * rc3;
 
-        if ((ic.vdw_modifier == eintmodFORCESWITCH) || (ic.vdwtype == evdwSHIFT))
+        if ((ic.vdw_modifier == InteractionModifiers::ForceSwitch) || (ic.vdwtype == VanDerWaalsType::Shift))
         {
             /* Determine the constant energy shift below rvdw_switch.
              * Table has a scale factor since we have scaled it down to compensate
@@ -444,7 +448,7 @@ void DispersionCorrection::setInteractionParameters(InteractionParams*         i
             iParams->enershiftsix_ = static_cast<real>(-1.0 / (rc3 * rc3)) - 6.0 * vdwtab[8 * ri0];
             iParams->enershifttwelve_ = static_cast<real>(1.0 / (rc9 * rc3)) - 12.0 * vdwtab[8 * ri0 + 4];
         }
-        else if (ic.vdw_modifier == eintmodPOTSHIFT)
+        else if (ic.vdw_modifier == InteractionModifiers::PotShift)
         {
             iParams->enershiftsix_    = static_cast<real>(-1.0 / (rc3 * rc3));
             iParams->enershifttwelve_ = static_cast<real>(1.0 / (rc9 * rc3));
@@ -482,7 +486,8 @@ void DispersionCorrection::setInteractionParameters(InteractionParams*         i
          */
         addCorrectionBeyondCutoff(&energy, &virial, r0);
     }
-    else if (ic.vdwtype == evdwCUT || EVDW_PME(ic.vdwtype) || ic.vdwtype == evdwUSER)
+    else if (ic.vdwtype == VanDerWaalsType::Cut || EVDW_PME(ic.vdwtype)
+             || ic.vdwtype == VanDerWaalsType::User)
     {
         /* Note that with LJ-PME, the dispersion correction is multiplied
          * by the difference between the actual C6 and the value of C6
@@ -493,7 +498,7 @@ void DispersionCorrection::setInteractionParameters(InteractionParams*         i
 
         const double rc3 = ic.rvdw * ic.rvdw * ic.rvdw;
         const double rc9 = rc3 * rc3 * rc3;
-        if (ic.vdw_modifier == eintmodPOTSHIFT)
+        if (ic.vdw_modifier == InteractionModifiers::PotShift)
         {
             /* Contribution within the cut-off */
             energy.dispersion += -4.0 * M_PI / (3.0 * rc3);
@@ -504,8 +509,9 @@ void DispersionCorrection::setInteractionParameters(InteractionParams*         i
     }
     else
     {
-        gmx_fatal(FARGS, "Dispersion correction is not implemented for vdw-type = %s",
-                  evdw_names[ic.vdwtype]);
+        gmx_fatal(FARGS,
+                  "Dispersion correction is not implemented for vdw-type = %s",
+                  enumValueToString(ic.vdwtype));
     }
 
     iParams->enerdiffsix_    = energy.dispersion;
@@ -527,7 +533,7 @@ DispersionCorrection::DispersionCorrection(const gmx_mtop_t&          mtop,
     eFep_(inputrec.efep),
     topParams_(mtop, inputrec, useBuckingham, numAtomTypes, nonbondedForceParameters)
 {
-    if (eDispCorr_ != edispcNO)
+    if (eDispCorr_ != DispersionCorrectionType::No)
     {
         GMX_RELEASE_ASSERT(tableFileName, "Need a table file name");
 
@@ -537,7 +543,8 @@ DispersionCorrection::DispersionCorrection(const gmx_mtop_t&          mtop,
 
 bool DispersionCorrection::correctFullInteraction() const
 {
-    return (eDispCorr_ == edispcAllEner || eDispCorr_ == edispcAllEnerPres);
+    return (eDispCorr_ == DispersionCorrectionType::AllEner
+            || eDispCorr_ == DispersionCorrectionType::AllEnerPres);
 }
 
 void DispersionCorrection::print(const gmx::MDLogger& mdlog) const
@@ -548,7 +555,7 @@ void DispersionCorrection::print(const gmx::MDLogger& mdlog) const
                 .asParagraph()
                 .appendText("WARNING: There are no atom pairs for dispersion correction");
     }
-    else if (vdwType_ == evdwUSER)
+    else if (vdwType_ == VanDerWaalsType::User)
     {
         GMX_LOG(mdlog.warning)
                 .asParagraph()
@@ -565,7 +572,7 @@ void DispersionCorrection::print(const gmx::MDLogger& mdlog) const
 
 void DispersionCorrection::setParameters(const interaction_const_t& ic)
 {
-    if (eDispCorr_ != edispcNO)
+    if (eDispCorr_ != DispersionCorrectionType::No)
     {
         setInteractionParameters(&iParams_, ic, nullptr);
     }
@@ -576,13 +583,14 @@ DispersionCorrection::Correction DispersionCorrection::calculate(const matrix bo
 {
     Correction corr;
 
-    if (eDispCorr_ == edispcNO)
+    if (eDispCorr_ == DispersionCorrectionType::No)
     {
         return corr;
     }
 
     const bool bCorrAll  = correctFullInteraction();
-    const bool bCorrPres = (eDispCorr_ == edispcEnerPres || eDispCorr_ == edispcAllEnerPres);
+    const bool bCorrPres = (eDispCorr_ == DispersionCorrectionType::EnerPres
+                            || eDispCorr_ == DispersionCorrectionType::AllEnerPres);
 
     const real invvol  = 1 / det(box);
     const real density = topParams_.numAtomsForDensity_ * invvol;
@@ -590,7 +598,7 @@ DispersionCorrection::Correction DispersionCorrection::calculate(const matrix bo
 
     real avcsix;
     real avctwelve;
-    if (eFep_ == efepNO)
+    if (eFep_ == FreeEnergyPerturbationType::No)
     {
         avcsix    = topParams_.avcsix_[0];
         avctwelve = topParams_.avctwelve_[0];
@@ -604,7 +612,7 @@ DispersionCorrection::Correction DispersionCorrection::calculate(const matrix bo
     const real enerdiff = numCorr * (density * iParams_.enerdiffsix_ - iParams_.enershiftsix_);
     corr.energy += avcsix * enerdiff;
     real dvdlambda = 0;
-    if (eFep_ != efepNO)
+    if (eFep_ != FreeEnergyPerturbationType::No)
     {
         dvdlambda += (topParams_.avcsix_[1] - topParams_.avcsix_[0]) * enerdiff;
     }
@@ -612,7 +620,7 @@ DispersionCorrection::Correction DispersionCorrection::calculate(const matrix bo
     {
         const real enerdiff = numCorr * (density * iParams_.enerdifftwelve_ - iParams_.enershifttwelve_);
         corr.energy += avctwelve * enerdiff;
-        if (eFep_ != efepNO)
+        if (eFep_ != FreeEnergyPerturbationType::No)
         {
             dvdlambda += (topParams_.avctwelve_[1] - topParams_.avctwelve_[0]) * enerdiff;
         }
@@ -621,15 +629,15 @@ DispersionCorrection::Correction DispersionCorrection::calculate(const matrix bo
     if (bCorrPres)
     {
         corr.virial = numCorr * density * avcsix * iParams_.virdiffsix_ / 3.0;
-        if (eDispCorr_ == edispcAllEnerPres)
+        if (eDispCorr_ == DispersionCorrectionType::AllEnerPres)
         {
             corr.virial += numCorr * density * avctwelve * iParams_.virdifftwelve_ / 3.0;
         }
         /* The factor 2 is because of the Gromacs virial definition */
-        corr.pressure = -2.0 * invvol * corr.virial * PRESFAC;
+        corr.pressure = -2.0 * invvol * corr.virial * gmx::c_presfac;
     }
 
-    if (eFep_ != efepNO)
+    if (eFep_ != FreeEnergyPerturbationType::No)
     {
         corr.dvdl += dvdlambda;
     }
index be656e2130c4769ff0963a28d5a3127acf8ce959..62e7cbc021d7b8873f7ed3b1c5049a907ac41b32 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 @@ struct interaction_const_t;
 struct t_forcerec;
 struct t_forcetable;
 struct t_inputrec;
-
+enum class DispersionCorrectionType : int;
+enum class VanDerWaalsType : int;
+enum class FreeEnergyPerturbationType : int;
 namespace gmx
 {
 template<typename>
@@ -177,11 +179,11 @@ private:
     bool correctFullInteraction() const;
 
     //! Type of dispersion correction
-    int eDispCorr_;
+    DispersionCorrectionType eDispCorr_;
     //! Type of Van der Waals interaction
-    int vdwType_;
+    VanDerWaalsType vdwType_;
     //! Free-energy perturbation
-    int eFep_;
+    FreeEnergyPerturbationType eFep_;
     //! Topology parameters
     TopologyParams topParams_;
     //! Interaction parameters
index 6c830526bea1576778b38cc026603480c4ccdb44..4a2763d8c8a798f03e59b49aee660f6f95898685 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -134,11 +134,6 @@ int get_ebin_space(t_ebin* eb, int nener, const char* const enm[], const char* u
     return index;
 }
 
-// ICC 19 -O3 -msse2 generates wrong code. Lower optimization levels
-// and other SIMD levels seem fine, however.
-#if defined __ICC
-#    pragma intel optimization_level 2
-#endif
 void add_ebin(t_ebin* eb, int entryIndex, int nener, const real ener[], gmx_bool bSum)
 {
     int       i, m;
@@ -147,8 +142,13 @@ void add_ebin(t_ebin* eb, int entryIndex, int nener, const real ener[], gmx_bool
 
     if ((entryIndex + nener > eb->nener) || (entryIndex < 0))
     {
-        gmx_fatal(FARGS, "%s-%d: Energies out of range: entryIndex=%d nener=%d maxener=%d",
-                  __FILE__, __LINE__, entryIndex, nener, eb->nener);
+        gmx_fatal(FARGS,
+                  "%s-%d: Energies out of range: entryIndex=%d nener=%d maxener=%d",
+                  __FILE__,
+                  __LINE__,
+                  entryIndex,
+                  nener,
+                  eb->nener);
     }
 
     eg = &(eb->e[entryIndex]);
@@ -205,8 +205,10 @@ void add_ebin_indexed(t_ebin*                   eb,
 
     GMX_ASSERT(shouldUse.size() == ener.size(), "View sizes must match");
     GMX_ASSERT(entryIndex + std::count(shouldUse.begin(), shouldUse.end(), true) <= eb->nener,
-               gmx::formatString("Energies out of range: entryIndex=%d nener=%td maxener=%d", entryIndex,
-                                 std::count(shouldUse.begin(), shouldUse.end(), true), eb->nener)
+               gmx::formatString("Energies out of range: entryIndex=%d nener=%td maxener=%d",
+                                 entryIndex,
+                                 std::count(shouldUse.begin(), shouldUse.end(), true),
+                                 eb->nener)
                        .c_str());
     GMX_ASSERT(entryIndex >= 0, "Must have non-negative entry");
 
index 0ebef33d1e74741c0de981adab7041fe84cc41aa..f76dca56a1e3fafd5398f69f6b992b750f26d014 100644 (file)
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/enerdata.h"
 #include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
 
 ForeignLambdaTerms::ForeignLambdaTerms(int numLambdas) :
-    numLambdas_(numLambdas),
-    energies_(1 + numLambdas),
-    dhdl_(1 + numLambdas)
+    numLambdas_(numLambdas), energies_(1 + numLambdas), dhdl_(1 + numLambdas)
 {
 }
 
@@ -81,9 +80,7 @@ void ForeignLambdaTerms::zeroAllTerms()
 }
 
 gmx_enerdata_t::gmx_enerdata_t(int numEnergyGroups, int numFepLambdas) :
-    grpp(numEnergyGroups),
-    foreignLambdaTerms(numFepLambdas),
-    foreign_grpp(numEnergyGroups)
+    grpp(numEnergyGroups), foreignLambdaTerms(numFepLambdas), foreign_grpp(numEnergyGroups)
 {
 }
 
@@ -106,15 +103,15 @@ void sum_epot(const gmx_grppairener_t& grpp, real* epot)
     int i;
 
     /* Accumulate energies */
-    epot[F_COUL_SR] = sum_v(grpp.nener, grpp.ener[egCOULSR]);
-    epot[F_LJ]      = sum_v(grpp.nener, grpp.ener[egLJSR]);
-    epot[F_LJ14]    = sum_v(grpp.nener, grpp.ener[egLJ14]);
-    epot[F_COUL14]  = sum_v(grpp.nener, grpp.ener[egCOUL14]);
+    epot[F_COUL_SR] = sum_v(grpp.nener, grpp.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR]);
+    epot[F_LJ]      = sum_v(grpp.nener, grpp.energyGroupPairTerms[NonBondedEnergyTerms::LJSR]);
+    epot[F_LJ14]    = sum_v(grpp.nener, grpp.energyGroupPairTerms[NonBondedEnergyTerms::LJ14]);
+    epot[F_COUL14]  = sum_v(grpp.nener, grpp.energyGroupPairTerms[NonBondedEnergyTerms::Coulomb14]);
 
     /* lattice part of LR doesnt belong to any group
      * and has been added earlier
      */
-    epot[F_BHAM] = sum_v(grpp.nener, grpp.ener[egBHAMSR]);
+    epot[F_BHAM] = sum_v(grpp.nener, grpp.energyGroupPairTerms[NonBondedEnergyTerms::BuckinghamSR]);
 
     epot[F_EPOT] = 0;
     for (i = 0; (i < F_EPOT); i++)
@@ -127,7 +124,7 @@ void sum_epot(const gmx_grppairener_t& grpp, real* epot)
 }
 
 // Adds computed dH/dlambda contribution i to the requested output
-static void set_dhdl_output(gmx_enerdata_t* enerd, int i, const t_lambda& fepvals)
+static void set_dhdl_output(gmx_enerdata_t* enerd, FreeEnergyPerturbationCouplingType i, const t_lambda& fepvals)
 {
     if (fepvals.separate_dvdl[i])
     {
@@ -137,18 +134,23 @@ static void set_dhdl_output(gmx_enerdata_t* enerd, int i, const t_lambda& fepval
         int index;
         switch (i)
         {
-            case (efptMASS): index = F_DKDL; break;
-            case (efptCOUL): index = F_DVDL_COUL; break;
-            case (efptVDW): index = F_DVDL_VDW; break;
-            case (efptBONDED): index = F_DVDL_BONDED; break;
-            case (efptRESTRAINT): index = F_DVDL_RESTRAINT; break;
+            case (FreeEnergyPerturbationCouplingType::Mass): index = F_DKDL; break;
+            case (FreeEnergyPerturbationCouplingType::Coul): index = F_DVDL_COUL; break;
+            case (FreeEnergyPerturbationCouplingType::Vdw): index = F_DVDL_VDW; break;
+            case (FreeEnergyPerturbationCouplingType::Bonded): index = F_DVDL_BONDED; break;
+            case (FreeEnergyPerturbationCouplingType::Restraint): index = F_DVDL_RESTRAINT; break;
             default: index = F_DVDL; break;
         }
         enerd->term[index] = enerd->dvdl_lin[i] + enerd->dvdl_nonlin[i];
         if (debug)
         {
-            fprintf(debug, "dvdl-%s[%2d]: %f: non-linear %f + linear %f\n", efpt_names[i], i,
-                    enerd->term[index], enerd->dvdl_nonlin[i], enerd->dvdl_lin[i]);
+            fprintf(debug,
+                    "dvdl-%s[%2d]: %f: non-linear %f + linear %f\n",
+                    enumValueToString(i),
+                    static_cast<int>(i),
+                    enerd->term[index],
+                    enerd->dvdl_nonlin[i],
+                    enerd->dvdl_lin[i]);
         }
     }
     else
@@ -156,8 +158,13 @@ static void set_dhdl_output(gmx_enerdata_t* enerd, int i, const t_lambda& fepval
         enerd->term[F_DVDL] += enerd->dvdl_lin[i] + enerd->dvdl_nonlin[i];
         if (debug)
         {
-            fprintf(debug, "dvd-%sl[%2d]: %f: non-linear %f + linear %f\n", efpt_names[0], i,
-                    enerd->term[F_DVDL], enerd->dvdl_nonlin[i], enerd->dvdl_lin[i]);
+            fprintf(debug,
+                    "dvd-%sl[%2d]: %f: non-linear %f + linear %f\n",
+                    enumValueToString(FreeEnergyPerturbationCouplingType::Fep),
+                    static_cast<int>(i),
+                    enerd->term[F_DVDL],
+                    enerd->dvdl_nonlin[i],
+                    enerd->dvdl_lin[i]);
         }
     }
 }
@@ -180,7 +187,7 @@ void ForeignLambdaTerms::finalizePotentialContributions(gmx::ArrayRef<const doub
     }
 
     double dvdl_lin = 0;
-    for (int i = 0; i < efptNR; i++)
+    for (int i = 0; i < static_cast<int>(FreeEnergyPerturbationCouplingType::Count); i++)
     {
         dvdl_lin += dvdlLinear[i];
     }
@@ -218,15 +225,15 @@ void ForeignLambdaTerms::finalizePotentialContributions(gmx::ArrayRef<const doub
 
 void accumulatePotentialEnergies(gmx_enerdata_t* enerd, gmx::ArrayRef<const real> lambda, const t_lambda* fepvals)
 {
-    sum_epot(enerd->grpp, enerd->term);
+    sum_epot(enerd->grpp, enerd->term.data());
 
     if (fepvals)
     {
         enerd->term[F_DVDL] = 0.0;
-        for (int i = 0; i < efptNR; i++)
+        for (auto i : gmx::EnumerationWrapper<FreeEnergyPerturbationCouplingType>{})
         {
             // Skip kinetic terms here, as those are not available here yet
-            if (i != efptMASS)
+            if (i != FreeEnergyPerturbationCouplingType::Mass)
             {
                 set_dhdl_output(enerd, i, *fepvals);
             }
@@ -252,7 +259,7 @@ void ForeignLambdaTerms::finalizeKineticContributions(gmx::ArrayRef<const real>
 
     // Treat current lambda, the deltaH contribution is 0 as delta-lambda=0 for the current lambda
     accumulateKinetic(0, 0.0, energyTerms[F_DVDL_CONSTR]);
-    if (!fepvals.separate_dvdl[efptMASS])
+    if (!fepvals.separate_dvdl[FreeEnergyPerturbationCouplingType::Mass])
     {
         accumulateKinetic(0, 0.0, energyTerms[F_DKDL]);
     }
@@ -265,13 +272,17 @@ void ForeignLambdaTerms::finalizeKineticContributions(gmx::ArrayRef<const real>
          * a linear extrapolation. This is an approximation, but usually
          * quite accurate since constraints change little between lambdas.
          */
-        const int    lambdaIndex = (fepvals.separate_dvdl[efptBONDED] ? efptBONDED : efptFEP);
-        const double dlam        = fepvals.all_lambda[lambdaIndex][i] - lambda[lambdaIndex];
+        const FreeEnergyPerturbationCouplingType lambdaIndex =
+                (fepvals.separate_dvdl[FreeEnergyPerturbationCouplingType::Bonded]
+                         ? FreeEnergyPerturbationCouplingType::Bonded
+                         : FreeEnergyPerturbationCouplingType::Fep);
+        const double dlam = fepvals.all_lambda[lambdaIndex][i] - lambda[static_cast<int>(lambdaIndex)];
         accumulateKinetic(1 + i, dlam * energyTerms[F_DVDL_CONSTR], energyTerms[F_DVDL_CONSTR]);
 
-        if (!fepvals.separate_dvdl[efptMASS])
+        if (!fepvals.separate_dvdl[FreeEnergyPerturbationCouplingType::Mass])
         {
-            const double dlam = fepvals.all_lambda[efptMASS][i] - lambda[efptMASS];
+            const double dlam = fepvals.all_lambda[FreeEnergyPerturbationCouplingType::Mass][i]
+                                - lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Mass)];
             accumulateKinetic(1 + i, dlam * energyTerms[F_DKDL], energyTerms[F_DKDL]);
         }
     }
@@ -281,7 +292,7 @@ void accumulateKineticLambdaComponents(gmx_enerdata_t*           enerd,
                                        gmx::ArrayRef<const real> lambda,
                                        const t_lambda&           fepvals)
 {
-    if (fepvals.separate_dvdl[efptBONDED])
+    if (fepvals.separate_dvdl[FreeEnergyPerturbationCouplingType::Bonded])
     {
         enerd->term[F_DVDL_BONDED] += enerd->term[F_DVDL_CONSTR];
     }
@@ -291,10 +302,10 @@ void accumulateKineticLambdaComponents(gmx_enerdata_t*           enerd,
     }
 
     // Add computed mass dH/dlambda contribution to the requested output
-    set_dhdl_output(enerd, efptMASS, fepvals);
+    set_dhdl_output(enerd, FreeEnergyPerturbationCouplingType::Mass, fepvals);
 
-    enerd->foreignLambdaTerms.finalizeKineticContributions(enerd->term, enerd->dvdl_lin[efptMASS],
-                                                           lambda, fepvals);
+    enerd->foreignLambdaTerms.finalizeKineticContributions(
+            enerd->term, enerd->dvdl_lin[FreeEnergyPerturbationCouplingType::Mass], lambda, fepvals);
 
     /* The constrain contribution is now included in other terms, so clear it */
     enerd->term[F_DVDL_CONSTR] = 0;
@@ -306,11 +317,11 @@ void reset_foreign_enerdata(gmx_enerdata_t* enerd)
 
     /* First reset all foreign energy components.  Foreign energies always called on
        neighbor search steps */
-    for (i = 0; (i < egNR); i++)
+    for (i = 0; (i < static_cast<int>(NonBondedEnergyTerms::Count)); i++)
     {
         for (j = 0; (j < enerd->grpp.nener); j++)
         {
-            enerd->foreign_grpp.ener[i][j] = 0.0;
+            enerd->foreign_grpp.energyGroupPairTerms[i][j] = 0.0;
         }
     }
 
@@ -323,7 +334,7 @@ void reset_foreign_enerdata(gmx_enerdata_t* enerd)
 
 void reset_dvdl_enerdata(gmx_enerdata_t* enerd)
 {
-    for (int i = 0; i < efptNR; i++)
+    for (auto i : keysOf(enerd->dvdl_lin))
     {
         enerd->dvdl_lin[i]    = 0.0;
         enerd->dvdl_nonlin[i] = 0.0;
@@ -335,11 +346,11 @@ void reset_enerdata(gmx_enerdata_t* enerd)
     int i, j;
 
     /* First reset all energy components. */
-    for (i = 0; (i < egNR); i++)
+    for (i = 0; (i < static_cast<int>(NonBondedEnergyTerms::Count)); i++)
     {
         for (j = 0; (j < enerd->grpp.nener); j++)
         {
-            enerd->grpp.ener[i][j] = 0.0_real;
+            enerd->grpp.energyGroupPairTerms[i][j] = 0.0_real;
         }
     }
 
index 1d5f2b13ddbdff130360f8216e2ad3adba5fbc6d..ddbd078fe21fbd5b5f0871397a6ece3cb2f59d41 100644 (file)
@@ -87,14 +87,18 @@ std::string EnergyDriftTracker::energyDriftString(const std::string& partName) c
     if (timeInterval() > 0)
     {
         mesg = formatString("Energy conservation over %s of length %g ns, time %g to %g ns\n",
-                            partName.c_str(), timeInterval(), firstTime_, lastTime_);
+                            partName.c_str(),
+                            timeInterval(),
+                            firstTime_,
+                            lastTime_);
         mesg += formatString("  Conserved energy drift: %.2e kJ/mol/ps per atom\n", energyDrift());
     }
     else
     {
         mesg = formatString(
                 "Time interval for measuring conserved energy has length 0, time %g to %g\n",
-                firstTime_, lastTime_);
+                firstTime_,
+                lastTime_);
     }
 
     return mesg;
index 0b72fc4e0cce0e1eaa038941b35cdaf2c71afeb7..631e7b1dade7cb1a4a6a4064402aa5e87e26b8f5 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -80,8 +80,9 @@
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/trajectory/energyframe.h"
 #include "gromacs/utility/arraysize.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
-#include "gromacs/utility/mdmodulenotification.h"
+#include "gromacs/utility/mdmodulesnotifiers.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringutil.h"
 
 
 //! Labels for energy file quantities
 //! \{
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static const char* conrmsd_nm[] = { "Constr. rmsd", "Constr.2 rmsd" };
 
-static std::array<const char*, 3> boxs_nm = { "Box-X", "Box-Y", "Box-Z" };
+static constexpr std::array<const char*, 3> boxs_nm = { "Box-X", "Box-Y", "Box-Z" };
 
-static std::array<const char*, 6> tricl_boxs_nm = { "Box-XX", "Box-YY", "Box-ZZ",
-                                                    "Box-YX", "Box-ZX", "Box-ZY" };
+static constexpr std::array<const char*, 6> tricl_boxs_nm = { "Box-XX", "Box-YY", "Box-ZZ",
+                                                              "Box-YX", "Box-ZX", "Box-ZY" };
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static const char* vol_nm[] = { "Volume" };
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static const char* dens_nm[] = { "Density" };
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static const char* pv_nm[] = { "pV" };
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static const char* enthalpy_nm[] = { "Enthalpy" };
 
-static std::array<const char*, 6> boxvel_nm = { "Box-Vel-XX", "Box-Vel-YY", "Box-Vel-ZZ",
-                                                "Box-Vel-YX", "Box-Vel-ZX", "Box-Vel-ZY" };
+static constexpr std::array<const char*, 6> boxvel_nm = { "Box-Vel-XX", "Box-Vel-YY", "Box-Vel-ZZ",
+                                                          "Box-Vel-YX", "Box-Vel-ZX", "Box-Vel-ZY" };
+
+const char* enumValueToString(NonBondedEnergyTerms enumValue)
+{
+    static constexpr gmx::EnumerationArray<NonBondedEnergyTerms, const char*> nonBondedEnergyTermTypeNames = {
+        "Coul-SR", "LJ-SR", "Buck-SR", "Coul-14", "LJ-14"
+    };
+    return nonBondedEnergyTermTypeNames[enumValue];
+}
 
-const char* egrp_nm[egNR + 1] = { "Coul-SR", "LJ-SR", "Buck-SR", "Coul-14", "LJ-14", nullptr };
 //! \}
 
 namespace gmx
@@ -122,15 +135,15 @@ namespace gmx
  * \todo Remove GMX_CONSTRAINTVIR
  * \todo Write free-energy output also to energy file (after adding more tests)
  */
-EnergyOutput::EnergyOutput(ener_file*               fp_ene,
-                           const gmx_mtop_t*        mtop,
-                           const t_inputrec*        ir,
-                           const pull_t*            pull_work,
-                           FILE*                    fp_dhdl,
-                           bool                     isRerun,
-                           const StartingBehavior   startingBehavior,
-                           const bool               simulationsShareState,
-                           const MdModulesNotifier& mdModulesNotifier)
+EnergyOutput::EnergyOutput(ener_file*                fp_ene,
+                           const gmx_mtop_t        mtop,
+                           const t_inputrec&         inputrec,
+                           const pull_t*             pull_work,
+                           FILE*                     fp_dhdl,
+                           bool                      isRerun,
+                           const StartingBehavior    startingBehavior,
+                           const bool                simulationsShareState,
+                           const MDModulesNotifiers& mdModulesNotifiers)
 {
     const char*        ener_nm[F_NRE];
     static const char* vir_nm[]   = { "Vir-XX", "Vir-XY", "Vir-XZ", "Vir-YX", "Vir-YY",
@@ -153,21 +166,21 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
     char**                  gnm;
     char                    buf[256];
     const char*             bufi;
-    int                     i, j, ni, nj, n, k, kk, ncon, nset;
+    int                     i, j, ni, nj, n, ncon, nset;
     bool                    bBHAM, b14;
 
-    if (EI_DYNAMICS(ir->eI))
+    if (EI_DYNAMICS(inputrec.eI))
     {
-        delta_t_ = ir->delta_t;
+        delta_t_ = inputrec.delta_t;
     }
     else
     {
         delta_t_ = 0;
     }
 
-    groups = &mtop->groups;
+    groups = &mtop.groups;
 
-    bBHAM = (mtop->ffparams.numTypes() > 0) && (mtop->ffparams.functype[0] == F_BHAM);
+    bBHAM = (mtop.ffparams.numTypes() > 0) && (mtop.ffparams.functype[0] == F_BHAM);
     b14   = (gmx_mtop_ftype_count(mtop, F_LJ14) > 0 || gmx_mtop_ftype_count(mtop, F_LJC14_Q) > 0);
 
     ncon         = gmx_mtop_ftype_count(mtop, F_CONSTR);
@@ -177,7 +190,7 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
     nCrmsd_      = 0;
     if (bConstr)
     {
-        if (ncon > 0 && ir->eConstrAlg == econtLINCS)
+        if (ncon > 0 && inputrec.eConstrAlg == ConstraintAlgorithm::Lincs)
         {
             nCrmsd_ = 1;
         }
@@ -189,9 +202,9 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
     }
 
     /* Energy monitoring */
-    for (i = 0; i < egNR; i++)
+    for (auto& term : bEInd_)
     {
-        bEInd_[i] = false;
+        term = false;
     }
 
     // Setting true only to those energy terms, that have active interactions and
@@ -204,33 +217,40 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
 
     if (!isRerun)
     {
-        bEner_[F_EKIN] = EI_DYNAMICS(ir->eI);
-        bEner_[F_ETOT] = EI_DYNAMICS(ir->eI);
-        bEner_[F_TEMP] = EI_DYNAMICS(ir->eI);
+        bEner_[F_EKIN] = EI_DYNAMICS(inputrec.eI);
+        bEner_[F_ETOT] = EI_DYNAMICS(inputrec.eI);
+        bEner_[F_TEMP] = EI_DYNAMICS(inputrec.eI);
 
-        bEner_[F_ECONSERVED] = integratorHasConservedEnergyQuantity(ir);
-        bEner_[F_PDISPCORR]  = (ir->eDispCorr != edispcNO);
+        bEner_[F_ECONSERVED] = integratorHasConservedEnergyQuantity(&inputrec);
+        bEner_[F_PDISPCORR]  = (inputrec.eDispCorr != DispersionCorrectionType::No);
         bEner_[F_PRES]       = true;
     }
 
-    bEner_[F_LJ]           = !bBHAM;
-    bEner_[F_BHAM]         = bBHAM;
-    bEner_[F_EQM]          = ir->bQMMM;
-    bEner_[F_RF_EXCL]      = (EEL_RF(ir->coulombtype) && ir->cutoff_scheme == ecutsGROUP);
-    bEner_[F_COUL_RECIP]   = EEL_FULL(ir->coulombtype);
-    bEner_[F_LJ_RECIP]     = EVDW_PME(ir->vdwtype);
+    bEner_[F_LJ]   = !bBHAM;
+    bEner_[F_BHAM] = bBHAM;
+    bEner_[F_EQM]  = inputrec.bQMMM;
+    bEner_[F_RF_EXCL] = (EEL_RF(inputrec.coulombtype) && inputrec.cutoff_scheme == CutoffScheme::Group);
+    bEner_[F_COUL_RECIP]   = EEL_FULL(inputrec.coulombtype);
+    bEner_[F_LJ_RECIP]     = EVDW_PME(inputrec.vdwtype);
     bEner_[F_LJ14]         = b14;
     bEner_[F_COUL14]       = b14;
     bEner_[F_LJC14_Q]      = false;
     bEner_[F_LJC_PAIRS_NB] = false;
 
 
-    bEner_[F_DVDL_COUL]      = (ir->efep != efepNO) && ir->fepvals->separate_dvdl[efptCOUL];
-    bEner_[F_DVDL_VDW]       = (ir->efep != efepNO) && ir->fepvals->separate_dvdl[efptVDW];
-    bEner_[F_DVDL_BONDED]    = (ir->efep != efepNO) && ir->fepvals->separate_dvdl[efptBONDED];
-    bEner_[F_DVDL_RESTRAINT] = (ir->efep != efepNO) && ir->fepvals->separate_dvdl[efptRESTRAINT];
-    bEner_[F_DKDL]           = (ir->efep != efepNO) && ir->fepvals->separate_dvdl[efptMASS];
-    bEner_[F_DVDL]           = (ir->efep != efepNO) && ir->fepvals->separate_dvdl[efptFEP];
+    bEner_[F_DVDL_COUL] = (inputrec.efep != FreeEnergyPerturbationType::No)
+                          && inputrec.fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Coul];
+    bEner_[F_DVDL_VDW] = (inputrec.efep != FreeEnergyPerturbationType::No)
+                         && inputrec.fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Vdw];
+    bEner_[F_DVDL_BONDED] = (inputrec.efep != FreeEnergyPerturbationType::No)
+                            && inputrec.fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Bonded];
+    bEner_[F_DVDL_RESTRAINT] =
+            (inputrec.efep != FreeEnergyPerturbationType::No)
+            && inputrec.fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Restraint];
+    bEner_[F_DKDL] = (inputrec.efep != FreeEnergyPerturbationType::No)
+                     && inputrec.fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Mass];
+    bEner_[F_DVDL] = (inputrec.efep != FreeEnergyPerturbationType::No)
+                     && inputrec.fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Fep];
 
     bEner_[F_CONSTR]   = false;
     bEner_[F_CONSTRNC] = false;
@@ -239,13 +259,13 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
     bEner_[F_COUL_SR] = true;
     bEner_[F_EPOT]    = true;
 
-    bEner_[F_DISPCORR]   = (ir->eDispCorr != edispcNO);
+    bEner_[F_DISPCORR]   = (inputrec.eDispCorr != DispersionCorrectionType::No);
     bEner_[F_DISRESVIOL] = (gmx_mtop_ftype_count(mtop, F_DISRES) > 0);
     bEner_[F_ORIRESDEV]  = (gmx_mtop_ftype_count(mtop, F_ORIRES) > 0);
-    bEner_[F_COM_PULL]   = ((ir->bPull && pull_have_potential(*pull_work)) || ir->bRot);
+    bEner_[F_COM_PULL]   = ((inputrec.bPull && pull_have_potential(*pull_work)) || inputrec.bRot);
 
-    MdModulesEnergyOutputToDensityFittingRequestChecker mdModulesAddOutputToDensityFittingFieldRequest;
-    mdModulesNotifier.simulationSetupNotifications_.notify(&mdModulesAddOutputToDensityFittingFieldRequest);
+    MDModulesEnergyOutputToDensityFittingRequestChecker mdModulesAddOutputToDensityFittingFieldRequest;
+    mdModulesNotifiers.simulationSetupNotifier_.notify(&mdModulesAddOutputToDensityFittingFieldRequest);
 
     bEner_[F_DENSITYFITTING] = mdModulesAddOutputToDensityFittingFieldRequest.energyOutputToDensityFitting_;
 
@@ -261,16 +281,16 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
         }
     }
 
-    epc_            = isRerun ? epcNO : ir->epc;
-    bDiagPres_      = !TRICLINIC(ir->ref_p) && !isRerun;
-    ref_p_          = (ir->ref_p[XX][XX] + ir->ref_p[YY][YY] + ir->ref_p[ZZ][ZZ]) / DIM;
-    bTricl_         = TRICLINIC(ir->compress) || TRICLINIC(ir->deform);
-    bDynBox_        = inputrecDynamicBox(ir);
-    etc_            = isRerun ? etcNO : ir->etc;
-    bNHC_trotter_   = inputrecNvtTrotter(ir) && !isRerun;
-    bPrintNHChains_ = ir->bPrintNHChains && !isRerun;
-    bMTTK_          = (inputrecNptTrotter(ir) || inputrecNphTrotter(ir)) && !isRerun;
-    bMu_            = inputrecNeedMutot(ir);
+    epc_       = isRerun ? PressureCoupling::No : inputrec.epc;
+    bDiagPres_ = !TRICLINIC(inputrec.ref_p) && !isRerun;
+    ref_p_     = (inputrec.ref_p[XX][XX] + inputrec.ref_p[YY][YY] + inputrec.ref_p[ZZ][ZZ]) / DIM;
+    bTricl_    = TRICLINIC(inputrec.compress) || TRICLINIC(inputrec.deform);
+    bDynBox_   = inputrecDynamicBox(&inputrec);
+    etc_       = isRerun ? TemperatureCoupling::No : inputrec.etc;
+    bNHC_trotter_   = inputrecNvtTrotter(&inputrec) && !isRerun;
+    bPrintNHChains_ = inputrec.bPrintNHChains && !isRerun;
+    bMTTK_          = (inputrecNptTrotter(&inputrec) || inputrecNphTrotter(&inputrec)) && !isRerun;
+    bMu_            = inputrecNeedMutot(&inputrec);
     bPres_          = !isRerun;
 
     ebin_ = mk_ebin();
@@ -287,8 +307,10 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
     }
     if (bDynBox_)
     {
-        ib_    = get_ebin_space(ebin_, bTricl_ ? tricl_boxs_nm.size() : boxs_nm.size(),
-                             bTricl_ ? tricl_boxs_nm.data() : boxs_nm.data(), unit_length);
+        ib_    = get_ebin_space(ebin_,
+                             bTricl_ ? tricl_boxs_nm.size() : boxs_nm.size(),
+                             bTricl_ ? tricl_boxs_nm.data() : boxs_nm.data(),
+                             unit_length);
         ivol_  = get_ebin_space(ebin_, 1, vol_nm, unit_volume);
         idens_ = get_ebin_space(ebin_, 1, dens_nm, unit_density_SI);
         if (bDiagPres_)
@@ -308,7 +330,7 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
         ipres_  = get_ebin_space(ebin_, asize(pres_nm), pres_nm, unit_pres_bar);
         isurft_ = get_ebin_space(ebin_, asize(surft_nm), surft_nm, unit_surft_bar);
     }
-    if (epc_ == epcPARRINELLORAHMAN || epc_ == epcMTTK)
+    if (epc_ == PressureCoupling::ParrinelloRahman || epc_ == PressureCoupling::Mttk)
     {
         ipc_ = get_ebin_space(ebin_, bTricl_ ? boxvel_nm.size() : DIM, boxvel_nm.data(), unit_vel);
     }
@@ -316,34 +338,34 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
     {
         imu_ = get_ebin_space(ebin_, asize(mu_nm), mu_nm, unit_dipole_D);
     }
-    if (ir->cos_accel != 0)
+    if (inputrec.cos_accel != 0)
     {
         ivcos_ = get_ebin_space(ebin_, asize(vcos_nm), vcos_nm, unit_vel);
         ivisc_ = get_ebin_space(ebin_, asize(visc_nm), visc_nm, unit_invvisc_SI);
     }
 
     /* Energy monitoring */
-    for (i = 0; i < egNR; i++)
+    for (auto& term : bEInd_)
     {
-        bEInd_[i] = false;
+        term = false;
     }
-    bEInd_[egCOULSR] = true;
-    bEInd_[egLJSR]   = true;
+    bEInd_[NonBondedEnergyTerms::CoulombSR] = true;
+    bEInd_[NonBondedEnergyTerms::LJSR]      = true;
 
     if (bBHAM)
     {
-        bEInd_[egLJSR]   = false;
-        bEInd_[egBHAMSR] = true;
+        bEInd_[NonBondedEnergyTerms::LJSR]         = false;
+        bEInd_[NonBondedEnergyTerms::BuckinghamSR] = true;
     }
     if (b14)
     {
-        bEInd_[egLJ14]   = true;
-        bEInd_[egCOUL14] = true;
+        bEInd_[NonBondedEnergyTerms::LJ14]      = true;
+        bEInd_[NonBondedEnergyTerms::Coulomb14] = true;
     }
     nEc_ = 0;
-    for (i = 0; (i < egNR); i++)
+    for (auto term : bEInd_)
     {
-        if (bEInd_[i])
+        if (term)
         {
             nEc_++;
         }
@@ -352,12 +374,12 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
     nEg_ = n;
     nE_  = (n * (n + 1)) / 2;
 
-    snew(igrp_, nE_);
+    igrp_.resize(nE_);
     if (nE_ > 1)
     {
         n = 0;
         snew(gnm, nEc_);
-        for (k = 0; (k < nEc_); k++)
+        for (int k = 0; (k < nEc_); k++)
         {
             snew(gnm[k], STRLEN);
         }
@@ -366,21 +388,25 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
             ni = groups->groups[SimulationAtomGroupType::EnergyOutput][i];
             for (j = i; (j < gmx::ssize(groups->groups[SimulationAtomGroupType::EnergyOutput])); j++)
             {
-                nj = groups->groups[SimulationAtomGroupType::EnergyOutput][j];
-                for (k = kk = 0; (k < egNR); k++)
+                nj    = groups->groups[SimulationAtomGroupType::EnergyOutput][j];
+                int k = 0;
+                for (auto key : keysOf(bEInd_))
                 {
-                    if (bEInd_[k])
+                    if (bEInd_[key])
                     {
-                        sprintf(gnm[kk], "%s:%s-%s", egrp_nm[k], *(groups->groupNames[ni]),
+                        sprintf(gnm[k],
+                                "%s:%s-%s",
+                                enumValueToString(key),
+                                *(groups->groupNames[ni]),
                                 *(groups->groupNames[nj]));
-                        kk++;
+                        k++;
                     }
                 }
                 igrp_[n] = get_ebin_space(ebin_, nEc_, gnm, unit_energy);
                 n++;
             }
         }
-        for (k = 0; (k < nEc_); k++)
+        for (int k = 0; (k < nEc_); k++)
         {
             sfree(gnm[k]);
         }
@@ -393,7 +419,7 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
     }
 
     nTC_  = isRerun ? 0 : groups->groups[SimulationAtomGroupType::TemperatureCoupling].size();
-    nNHC_ = ir->opts.nhchainlength; /* shorthand for number of NH chains */
+    nNHC_ = inputrec.opts.nhchainlength; /* shorthand for number of NH chains */
     if (bMTTK_)
     {
         nTCP_ = 1; /* assume only one possible coupling system for barostat
@@ -403,7 +429,7 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
     {
         nTCP_ = 0;
     }
-    if (etc_ == etcNOSEHOOVER)
+    if (etc_ == TemperatureCoupling::NoseHoover)
     {
         if (bNHC_trotter_)
         {
@@ -413,7 +439,7 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
         {
             mde_n_ = 2 * nTC_;
         }
-        if (epc_ == epcMTTK)
+        if (epc_ == PressureCoupling::Mttk)
         {
             mdeb_n_ = 2 * nNHC_ * nTCP_;
         }
@@ -424,7 +450,7 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
         mdeb_n_ = 0;
     }
 
-    snew(tmp_r_, mde_n_);
+    tmp_r_.resize(mde_n_);
     // TODO redo the group name memory management to make it more clear
     char** grpnms;
     snew(grpnms, std::max(mde_n_, mdeb_n_)); // Just in case mdeb_n_ > mde_n_
@@ -442,7 +468,7 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
     }
 
     int allocated = 0;
-    if (etc_ == etcNOSEHOOVER)
+    if (etc_ == TemperatureCoupling::NoseHoover)
     {
         if (bPrintNHChains_)
         {
@@ -495,7 +521,8 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
             }
         }
     }
-    else if (etc_ == etcBERENDSEN || etc_ == etcYES || etc_ == etcVRESCALE)
+    else if (etc_ == TemperatureCoupling::Berendsen || etc_ == TemperatureCoupling::Yes
+             || etc_ == TemperatureCoupling::VRescale)
     {
         for (i = 0; (i < nTC_); i++)
         {
@@ -513,29 +540,6 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
     }
     sfree(grpnms);
 
-    nU_ = groups->groups[SimulationAtomGroupType::Acceleration].size();
-    snew(tmp_v_, nU_);
-    if (nU_ > 1)
-    {
-        snew(grpnms, 3 * nU_);
-        for (i = 0; (i < nU_); i++)
-        {
-            ni = groups->groups[SimulationAtomGroupType::Acceleration][i];
-            sprintf(buf, "Ux-%s", *(groups->groupNames[ni]));
-            grpnms[3 * i + XX] = gmx_strdup(buf);
-            sprintf(buf, "Uy-%s", *(groups->groupNames[ni]));
-            grpnms[3 * i + YY] = gmx_strdup(buf);
-            sprintf(buf, "Uz-%s", *(groups->groupNames[ni]));
-            grpnms[3 * i + ZZ] = gmx_strdup(buf);
-        }
-        iu_ = get_ebin_space(ebin_, 3 * nU_, grpnms, unit_vel);
-        for (i = 0; i < 3 * nU_; i++)
-        {
-            sfree(grpnms[i]);
-        }
-        sfree(grpnms);
-    }
-
     /* Note that fp_ene should be valid on the master rank and null otherwise */
     if (fp_ene != nullptr && startingBehavior != StartingBehavior::RestartWithAppending)
     {
@@ -544,56 +548,35 @@ EnergyOutput::EnergyOutput(ener_file*               fp_ene,
 
     /* check whether we're going to write dh histograms */
     dhc_ = nullptr;
-    if (ir->fepvals->separate_dhdl_file == esepdhdlfileNO)
+    if (inputrec.fepvals->separate_dhdl_file == SeparateDhdlFile::No)
     {
         /* Currently dh histograms are only written with dynamics */
-        if (EI_DYNAMICS(ir->eI))
+        if (EI_DYNAMICS(inputrec.eI))
         {
-            snew(dhc_, 1);
-
-            mde_delta_h_coll_init(dhc_, ir);
+            dhc_ = std::make_unique<t_mde_delta_h_coll>(inputrec);
         }
         fp_dhdl_ = nullptr;
-        snew(dE_, ir->fepvals->n_lambda);
+        dE_.resize(inputrec.fepvals->n_lambda);
     }
     else
     {
         fp_dhdl_ = fp_dhdl;
-        snew(dE_, ir->fepvals->n_lambda);
+        dE_.resize(inputrec.fepvals->n_lambda);
     }
-    if (ir->bSimTemp)
+    if (inputrec.bSimTemp)
     {
-        int i;
-        snew(temperatures_, ir->fepvals->n_lambda);
-        numTemperatures_ = ir->fepvals->n_lambda;
-        for (i = 0; i < ir->fepvals->n_lambda; i++)
-        {
-            temperatures_[i] = ir->simtempvals->temperatures[i];
-        }
-    }
-    else
-    {
-        numTemperatures_ = 0;
+        temperatures_ = inputrec.simtempvals->temperatures;
     }
 
-    if (EI_MD(ir->eI) && !simulationsShareState)
+    if (EI_MD(inputrec.eI) && !simulationsShareState)
     {
-        conservedEnergyTracker_ = std::make_unique<EnergyDriftTracker>(mtop->natoms);
+        conservedEnergyTracker_ = std::make_unique<EnergyDriftTracker>(mtop.natoms);
     }
 }
 
 EnergyOutput::~EnergyOutput()
 {
-    sfree(igrp_);
-    sfree(tmp_r_);
-    sfree(tmp_v_);
     done_ebin(ebin_);
-    done_mde_delta_h_coll(dhc_);
-    sfree(dE_);
-    if (numTemperatures_ > 0)
-    {
-        sfree(temperatures_);
-    }
 }
 
 } // namespace gmx
@@ -608,10 +591,10 @@ EnergyOutput::~EnergyOutput()
  */
 static void print_lambda_vector(t_lambda* fep, int i, bool get_native_lambda, bool get_names, char* str)
 {
-    int j, k = 0;
+    int k    = 0;
     int Nsep = 0;
 
-    for (j = 0; j < efptNR; j++)
+    for (auto j : keysOf(fep->separate_dvdl))
     {
         if (fep->separate_dvdl[j])
         {
@@ -623,7 +606,7 @@ static void print_lambda_vector(t_lambda* fep, int i, bool get_native_lambda, bo
     {
         str += sprintf(str, "("); /* set the opening parenthesis*/
     }
-    for (j = 0; j < efptNR; j++)
+    for (auto j : keysOf(fep->separate_dvdl))
     {
         if (fep->separate_dvdl[j])
         {
@@ -640,7 +623,7 @@ static void print_lambda_vector(t_lambda* fep, int i, bool get_native_lambda, bo
             }
             else
             {
-                str += sprintf(str, "%s", efpt_singular_names[j]);
+                str += sprintf(str, "%s", enumValueToStringSingular(j));
             }
             /* print comma for the next item */
             if (k < Nsep - 1)
@@ -664,8 +647,8 @@ FILE* open_dhdl(const char* filename, const t_inputrec* ir, const gmx_output_env
                *lambdastate = "\\lambda state";
     int         i, nsets, nsets_de, nsetsbegin;
     int         n_lambda_terms = 0;
-    t_lambda*   fep            = ir->fepvals; /* for simplicity */
-    t_expanded* expand         = ir->expandedvals;
+    t_lambda*   fep            = ir->fepvals.get(); /* for simplicity */
+    t_expanded* expand         = ir->expandedvals.get();
     char        lambda_vec_str[STRLEN], lambda_name_str[STRLEN];
 
     int  nsets_dhdl = 0;
@@ -674,7 +657,7 @@ FILE* open_dhdl(const char* filename, const t_inputrec* ir, const gmx_output_env
     bool write_pV = false;
 
     /* count the number of different lambda terms */
-    for (i = 0; i < efptNR; i++)
+    for (auto i : keysOf(fep->separate_dvdl))
     {
         if (fep->separate_dvdl[i])
         {
@@ -693,8 +676,8 @@ FILE* open_dhdl(const char* filename, const t_inputrec* ir, const gmx_output_env
     {
         title   = gmx::formatString("%s and %s", dhdl, deltag);
         label_x = gmx::formatString("Time (ps)");
-        label_y = gmx::formatString("%s and %s (%s %s)", dhdl, deltag, unit_energy,
-                                    "[\\8l\\4]\\S-1\\N");
+        label_y = gmx::formatString(
+                "%s and %s (%s %s)", dhdl, deltag, unit_energy, "[\\8l\\4]\\S-1\\N");
     }
     fp = gmx_fio_fopen(filename, "w+");
     xvgr_header(fp, title.c_str(), label_x, label_y, exvggtXNY, oenv);
@@ -704,7 +687,8 @@ FILE* open_dhdl(const char* filename, const t_inputrec* ir, const gmx_output_env
     {
         buf = gmx::formatString("T = %g (K) ", ir->opts.ref_t[0]);
     }
-    if ((ir->efep != efepSLOWGROWTH) && (ir->efep != efepEXPANDED))
+    if ((ir->efep != FreeEnergyPerturbationType::SlowGrowth)
+        && (ir->efep != FreeEnergyPerturbationType::Expanded))
     {
         if ((fep->init_lambda >= 0) && (n_lambda_terms == 1))
         {
@@ -715,15 +699,15 @@ FILE* open_dhdl(const char* filename, const t_inputrec* ir, const gmx_output_env
         {
             print_lambda_vector(fep, fep->init_fep_state, true, false, lambda_vec_str);
             print_lambda_vector(fep, fep->init_fep_state, true, true, lambda_name_str);
-            buf += gmx::formatString("%s %d: %s = %s", lambdastate, fep->init_fep_state,
-                                     lambda_name_str, lambda_vec_str);
+            buf += gmx::formatString(
+                    "%s %d: %s = %s", lambdastate, fep->init_fep_state, lambda_name_str, lambda_vec_str);
         }
     }
     xvgr_subtitle(fp, buf.c_str(), oenv);
 
 
     nsets_dhdl = 0;
-    if (fep->dhdl_derivatives == edhdlderivativesYES)
+    if (fep->dhdl_derivatives == DhDlDerivativeCalculation::Yes)
     {
         nsets_dhdl = n_lambda_terms;
     }
@@ -732,18 +716,18 @@ FILE* open_dhdl(const char* filename, const t_inputrec* ir, const gmx_output_env
 
     nsets = nsets_dhdl + nsets_de; /* dhdl + fep differences */
 
-    if (fep->n_lambda > 0 && (expand->elmcmove > elmcmoveNO))
+    if (fep->n_lambda > 0 && (expand->elmcmove > LambdaMoveCalculation::No))
     {
         nsets += 1; /*add fep state for expanded ensemble */
     }
 
-    if (fep->edHdLPrintEnergy != edHdLPrintEnergyNO)
+    if (fep->edHdLPrintEnergy != FreeEnergyPrintEnergy::No)
     {
         nsets += 1; /* add energy to the dhdl as well */
     }
 
     nsetsextend = nsets;
-    if ((ir->epc != epcNO) && (fep->n_lambda > 0) && (fep->init_lambda < 0))
+    if ((ir->epc != PressureCoupling::No) && (fep->n_lambda > 0) && (fep->init_lambda < 0))
     {
         nsetsextend += 1; /* for PV term, other terms possible if required for
                              the reduced potential (only needed with foreign
@@ -754,30 +738,30 @@ FILE* open_dhdl(const char* filename, const t_inputrec* ir, const gmx_output_env
     }
     std::vector<std::string> setname(nsetsextend);
 
-    if (expand->elmcmove > elmcmoveNO)
+    if (expand->elmcmove > LambdaMoveCalculation::No)
     {
         /* state for the fep_vals, if we have alchemical sampling */
         setname[s++] = "Thermodynamic state";
     }
 
-    if (fep->edHdLPrintEnergy != edHdLPrintEnergyNO)
+    if (fep->edHdLPrintEnergy != FreeEnergyPrintEnergy::No)
     {
         std::string energy;
         switch (fep->edHdLPrintEnergy)
         {
-            case edHdLPrintEnergyPOTENTIAL:
+            case FreeEnergyPrintEnergy::Potential:
                 energy = gmx::formatString("%s (%s)", "Potential Energy", unit_energy);
                 break;
-            case edHdLPrintEnergyTOTAL:
-            case edHdLPrintEnergyYES:
+            case FreeEnergyPrintEnergy::Total:
+            case FreeEnergyPrintEnergy::Yes:
             default: energy = gmx::formatString("%s (%s)", "Total Energy", unit_energy);
         }
         setname[s++] = energy;
     }
 
-    if (fep->dhdl_derivatives == edhdlderivativesYES)
+    if (fep->dhdl_derivatives == DhDlDerivativeCalculation::Yes)
     {
-        for (i = 0; i < efptNR; i++)
+        for (auto i : keysOf(fep->separate_dvdl))
         {
             if (fep->separate_dvdl[i])
             {
@@ -794,7 +778,7 @@ FILE* open_dhdl(const char* filename, const t_inputrec* ir, const gmx_output_env
                     {
                         lam = fep->all_lambda[i][fep->init_fep_state];
                     }
-                    derivative = gmx::formatString("%s %s = %.4f", dhdl, efpt_singular_names[i], lam);
+                    derivative = gmx::formatString("%s %s = %.4f", dhdl, enumValueToStringSingular(i), lam);
                 }
                 setname[s++] = derivative;
             }
@@ -807,7 +791,7 @@ FILE* open_dhdl(const char* filename, const t_inputrec* ir, const gmx_output_env
          * from this xvg legend.
          */
 
-        if (expand->elmcmove > elmcmoveNO)
+        if (expand->elmcmove > LambdaMoveCalculation::No)
         {
             nsetsbegin = 1; /* for including the expanded ensemble */
         }
@@ -816,7 +800,7 @@ FILE* open_dhdl(const char* filename, const t_inputrec* ir, const gmx_output_env
             nsetsbegin = 0;
         }
 
-        if (fep->edHdLPrintEnergy != edHdLPrintEnergyNO)
+        if (fep->edHdLPrintEnergy != FreeEnergyPrintEnergy::No)
         {
             nsetsbegin += 1;
         }
@@ -876,13 +860,14 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
                                        const rvec              mu_tot,
                                        const gmx::Constraints* constr)
 {
-    int    j, k, kk, n, gid;
-    real   crmsd[2], tmp6[6];
-    real   bs[tricl_boxs_nm.size()], vol, dens, pv, enthalpy;
-    real   eee[egNR];
-    double store_dhdl[efptNR];
-    real   store_energy = 0;
-    real   tmp;
+    int  j, k, kk, n, gid;
+    real crmsd[2], tmp6[6];
+    real bs[tricl_boxs_nm.size()], vol, dens, enthalpy;
+    real eee[static_cast<int>(NonBondedEnergyTerms::Count)];
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, double> store_dhdl;
+    real                                                              store_energy = 0;
+    real                                                              tmp;
+    real pv = 0.0; // static analyzer warns about uninitialized variable warnings here.
 
     /* Do NOT use the box in the state variable, but the separate box provided
      * as an argument. This is because we sometimes need to write the box from
@@ -915,7 +900,7 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
             nboxs = boxs_nm.size();
         }
         vol  = box[XX][XX] * box[YY][YY] * box[ZZ][ZZ];
-        dens = (tmass * AMU) / (vol * NANO * NANO * NANO);
+        dens = (tmass * gmx::c_amu) / (vol * gmx::c_nano * gmx::c_nano * gmx::c_nano);
         add_ebin(ebin_, ib_, nboxs, bs, bSum);
         add_ebin(ebin_, ivol_, 1, &vol, bSum);
         add_ebin(ebin_, idens_, 1, &dens, bSum);
@@ -924,7 +909,7 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
         {
             /* This is pV (in kJ/mol).  The pressure is the reference pressure,
                not the instantaneous pressure */
-            pv = vol * ref_p_ / PRESFAC;
+            pv = vol * ref_p_ / gmx::c_presfac;
 
             add_ebin(ebin_, ipv_, 1, &pv, bSum);
             enthalpy = pv + enerd->term[F_ETOT];
@@ -943,7 +928,7 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
         tmp = (pres[ZZ][ZZ] - (pres[XX][XX] + pres[YY][YY]) * 0.5) * box[ZZ][ZZ];
         add_ebin(ebin_, isurft_, 1, &tmp, bSum);
     }
-    if (epc_ == epcPARRINELLORAHMAN || epc_ == epcMTTK)
+    if (epc_ == PressureCoupling::ParrinelloRahman || epc_ == PressureCoupling::Mttk)
     {
         tmp6[0] = ptCouplingArrays.boxv[XX][XX];
         tmp6[1] = ptCouplingArrays.boxv[YY][YY];
@@ -960,12 +945,12 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
     if (ekind && ekind->cosacc.cos_accel != 0)
     {
         vol  = box[XX][XX] * box[YY][YY] * box[ZZ][ZZ];
-        dens = (tmass * AMU) / (vol * NANO * NANO * NANO);
+        dens = (tmass * gmx::c_amu) / (vol * gmx::c_nano * gmx::c_nano * gmx::c_nano);
         add_ebin(ebin_, ivcos_, 1, &(ekind->cosacc.vcos), bSum);
         /* 1/viscosity, unit 1/(kg m^-1 s^-1) */
         tmp = 1
-              / (ekind->cosacc.cos_accel / (ekind->cosacc.vcos * PICO) * dens
-                 * gmx::square(box[ZZ][ZZ] * NANO / (2 * M_PI)));
+              / (ekind->cosacc.cos_accel / (ekind->cosacc.vcos * gmx::c_pico) * dens
+                 * gmx::square(box[ZZ][ZZ] * gmx::c_nano / (2 * M_PI)));
         add_ebin(ebin_, ivisc_, 1, &tmp, bSum);
     }
     if (nE_ > 1)
@@ -976,11 +961,11 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
             for (j = i; (j < nEg_); j++)
             {
                 gid = GID(i, j, nEg_);
-                for (k = kk = 0; (k < egNR); k++)
+                for (k = kk = 0; (k < static_cast<int>(NonBondedEnergyTerms::Count)); k++)
                 {
                     if (bEInd_[k])
                     {
-                        eee[kk++] = enerd->grpp.ener[k][gid];
+                        eee[kk++] = enerd->grpp.energyGroupPairTerms[k][gid];
                     }
                 }
                 add_ebin(ebin_, igrp_[n], nEc_, eee, bSum);
@@ -995,9 +980,9 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
         {
             tmp_r_[i] = ekind->tcstat[i].T;
         }
-        add_ebin(ebin_, itemp_, nTC_, tmp_r_, bSum);
+        add_ebin(ebin_, itemp_, nTC_, tmp_r_.data(), bSum);
 
-        if (etc_ == etcNOSEHOOVER)
+        if (etc_ == TemperatureCoupling::NoseHoover)
         {
             /* whether to print Nose-Hoover chains: */
             if (bPrintNHChains_)
@@ -1013,7 +998,7 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
                             tmp_r_[2 * k + 1] = ptCouplingArrays.nosehoover_vxi[k];
                         }
                     }
-                    add_ebin(ebin_, itc_, mde_n_, tmp_r_, bSum);
+                    add_ebin(ebin_, itc_, mde_n_, tmp_r_.data(), bSum);
 
                     if (bMTTK_)
                     {
@@ -1026,7 +1011,7 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
                                 tmp_r_[2 * k + 1] = ptCouplingArrays.nhpres_vxi[k];
                             }
                         }
-                        add_ebin(ebin_, itcb_, mdeb_n_, tmp_r_, bSum);
+                        add_ebin(ebin_, itcb_, mdeb_n_, tmp_r_.data(), bSum);
                     }
                 }
                 else
@@ -1036,27 +1021,19 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
                         tmp_r_[2 * i]     = ptCouplingArrays.nosehoover_xi[i];
                         tmp_r_[2 * i + 1] = ptCouplingArrays.nosehoover_vxi[i];
                     }
-                    add_ebin(ebin_, itc_, mde_n_, tmp_r_, bSum);
+                    add_ebin(ebin_, itc_, mde_n_, tmp_r_.data(), bSum);
                 }
             }
         }
-        else if (etc_ == etcBERENDSEN || etc_ == etcYES || etc_ == etcVRESCALE)
+        else if (etc_ == TemperatureCoupling::Berendsen || etc_ == TemperatureCoupling::Yes
+                 || etc_ == TemperatureCoupling::VRescale)
         {
             for (int i = 0; (i < nTC_); i++)
             {
                 tmp_r_[i] = ekind->tcstat[i].lambda;
             }
-            add_ebin(ebin_, itc_, nTC_, tmp_r_, bSum);
-        }
-    }
-
-    if (ekind && nU_ > 1)
-    {
-        for (int i = 0; (i < nU_); i++)
-        {
-            copy_rvec(ekind->grpstat[i].u, tmp_v_[i]);
+            add_ebin(ebin_, itc_, nTC_, tmp_r_.data(), bSum);
         }
-        add_ebin(ebin_, iu_, 3 * nU_, tmp_v_[0], bSum);
     }
 
     ebin_increase_count(1, ebin_, bSum);
@@ -1069,12 +1046,12 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
         {
             /* zero for simulated tempering */
             dE_[i] = foreignTerms.deltaH(i);
-            if (numTemperatures_ > 0)
+            if (!temperatures_.empty())
             {
-                GMX_RELEASE_ASSERT(numTemperatures_ > fep_state,
+                GMX_RELEASE_ASSERT(gmx::ssize(temperatures_) > fep_state,
                                    "Number of lambdas in state is bigger then in input record");
                 GMX_RELEASE_ASSERT(
-                        numTemperatures_ >= foreignTerms.numLambdas(),
+                        gmx::ssize(temperatures_) >= foreignTerms.numLambdas(),
                         "Number of lambdas in energy data is bigger then in input record");
                 /* MRS: is this right, given the way we have defined the exchange probabilities? */
                 /* is this even useful to have at all? */
@@ -1088,32 +1065,34 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
             /* the current free energy state */
 
             /* print the current state if we are doing expanded ensemble */
-            if (expand->elmcmove > elmcmoveNO)
+            if (expand->elmcmove > LambdaMoveCalculation::No)
             {
                 fprintf(fp_dhdl_, " %4d", fep_state);
             }
             /* total energy (for if the temperature changes */
 
-            if (fep->edHdLPrintEnergy != edHdLPrintEnergyNO)
+            if (fep->edHdLPrintEnergy != FreeEnergyPrintEnergy::No)
             {
                 switch (fep->edHdLPrintEnergy)
                 {
-                    case edHdLPrintEnergyPOTENTIAL: store_energy = enerd->term[F_EPOT]; break;
-                    case edHdLPrintEnergyTOTAL:
-                    case edHdLPrintEnergyYES:
+                    case FreeEnergyPrintEnergy::Potential:
+                        store_energy = enerd->term[F_EPOT];
+                        break;
+                    case FreeEnergyPrintEnergy::Total:
+                    case FreeEnergyPrintEnergy::Yes:
                     default: store_energy = enerd->term[F_ETOT];
                 }
                 fprintf(fp_dhdl_, " %#.8g", store_energy);
             }
 
-            if (fep->dhdl_derivatives == edhdlderivativesYES)
+            if (fep->dhdl_derivatives == DhDlDerivativeCalculation::Yes)
             {
-                for (int i = 0; i < efptNR; i++)
+                for (auto i : keysOf(fep->separate_dvdl))
                 {
                     if (fep->separate_dvdl[i])
                     {
                         /* assumes F_DVDL is first */
-                        fprintf(fp_dhdl_, " %#.8g", enerd->term[F_DVDL + i]);
+                        fprintf(fp_dhdl_, " %#.8g", enerd->term[F_DVDL + static_cast<int>(i)]);
                     }
                 }
             }
@@ -1121,8 +1100,8 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
             {
                 fprintf(fp_dhdl_, " %#.8g", dE_[i]);
             }
-            if (bDynBox_ && bDiagPres_ && (epc_ != epcNO) && foreignTerms.numLambdas() > 0
-                && (fep->init_lambda < 0))
+            if (bDynBox_ && bDiagPres_ && (epc_ != PressureCoupling::No)
+                && foreignTerms.numLambdas() > 0 && (fep->init_lambda < 0))
             {
                 fprintf(fp_dhdl_, " %#.8g", pv); /* PV term only needed when
                                                          there are alternate state
@@ -1135,19 +1114,24 @@ void EnergyOutput::addDataAtEnergyStep(bool                    bDoDHDL,
         if (dhc_ && bDoDHDL)
         {
             int idhdl = 0;
-            for (int i = 0; i < efptNR; i++)
+            for (auto i : keysOf(fep->separate_dvdl))
             {
                 if (fep->separate_dvdl[i])
                 {
                     /* assumes F_DVDL is first */
-                    store_dhdl[idhdl] = enerd->term[F_DVDL + i];
+                    store_dhdl[idhdl] = enerd->term[F_DVDL + static_cast<int>(i)];
                     idhdl += 1;
                 }
             }
             store_energy = enerd->term[F_ETOT];
             /* store_dh is dE */
-            mde_delta_h_coll_add_dh(dhc_, static_cast<double>(fep_state), store_energy, pv,
-                                    store_dhdl, dE_ + fep->lambda_start_n, time);
+            mde_delta_h_coll_add_dh(dhc_.get(),
+                                    static_cast<double>(fep_state),
+                                    store_energy,
+                                    pv,
+                                    store_dhdl,
+                                    dE_.data() + fep->lambda_start_n,
+                                    time);
         }
     }
 
@@ -1170,7 +1154,10 @@ void EnergyOutput::printHeader(FILE* log, int64_t steps, double time)
     fprintf(log,
             "   %12s   %12s\n"
             "   %12s   %12.5f\n\n",
-            "Step", "Time", gmx_step_str(steps, buf), time);
+            "Step",
+            "Time",
+            gmx_step_str(steps, buf),
+            time);
 }
 
 void EnergyOutput::printStepToEnergyFile(ener_file* fp_ene,
@@ -1204,18 +1191,20 @@ void EnergyOutput::printStepToEnergyFile(ener_file* fp_ene,
         nr[i] = 0;
     }
 
-    if (bOR && fcd->orires->nr > 0)
+    if (bOR && fcd->orires)
     {
         t_oriresdata& orires = *fcd->orires;
         diagonalize_orires_tensors(&orires);
-        nr[enxOR]     = orires.nr;
-        block[enxOR]  = orires.otav;
-        id[enxOR]     = enxOR;
-        nr[enxORI]    = (orires.oinsl != orires.otav) ? orires.nr : 0;
-        block[enxORI] = orires.oinsl;
+        nr[enxOR]    = orires.numRestraints;
+        block[enxOR] = orires.orientationsTimeAndEnsembleAv.data();
+        id[enxOR]    = enxOR;
+        nr[enxORI]   = (orires.orientations.data() != orires.orientationsTimeAndEnsembleAv.data())
+                             ? orires.numRestraints
+                             : 0;
+        block[enxORI] = orires.orientations.data();
         id[enxORI]    = enxORI;
-        nr[enxORT]    = orires.nex * 12;
-        block[enxORT] = orires.eig;
+        nr[enxORT]    = ssize(orires.eigenOutput);
+        block[enxORT] = orires.eigenOutput.data();
         id[enxORT]    = enxORT;
     }
 
@@ -1238,10 +1227,10 @@ void EnergyOutput::printStepToEnergyFile(ener_file* fp_ene,
             fr.block[b].id        = id[b];
             fr.block[b].sub[0].nr = nr[b];
 #if !GMX_DOUBLE
-            fr.block[b].sub[0].type = xdr_datatype_float;
+            fr.block[b].sub[0].type = XdrDataType::Float;
             fr.block[b].sub[0].fval = block[b];
 #else
-            fr.block[b].sub[0].type  = xdr_datatype_double;
+            fr.block[b].sub[0].type  = XdrDataType::Double;
             fr.block[b].sub[0].dval  = block[b];
 #endif
         }
@@ -1259,13 +1248,13 @@ void EnergyOutput::printStepToEnergyFile(ener_file* fp_ene,
             fr.block[db].sub[0].nr     = ndisre;
             fr.block[db].sub[1].nr     = ndisre;
 #if !GMX_DOUBLE
-            fr.block[db].sub[0].type = xdr_datatype_float;
-            fr.block[db].sub[1].type = xdr_datatype_float;
+            fr.block[db].sub[0].type = XdrDataType::Float;
+            fr.block[db].sub[1].type = XdrDataType::Float;
             fr.block[db].sub[0].fval = disres.rt;
             fr.block[db].sub[1].fval = disres.rm3tav;
 #else
-            fr.block[db].sub[0].type = xdr_datatype_double;
-            fr.block[db].sub[1].type = xdr_datatype_double;
+            fr.block[db].sub[0].type = XdrDataType::Double;
+            fr.block[db].sub[1].type = XdrDataType::Double;
             fr.block[db].sub[0].dval = disres.rt;
             fr.block[db].sub[1].dval = disres.rm3tav;
 #endif
@@ -1275,13 +1264,13 @@ void EnergyOutput::printStepToEnergyFile(ener_file* fp_ene,
         /* Free energy perturbation blocks */
         if (dhc_)
         {
-            mde_delta_h_coll_handle_block(dhc_, &fr, fr.nblock);
+            mde_delta_h_coll_handle_block(dhc_.get(), &fr, fr.nblock);
         }
 
         /* we can now free & reset the data in the blocks */
         if (dhc_)
         {
-            mde_delta_h_coll_reset(dhc_);
+            mde_delta_h_coll_reset(dhc_.get());
         }
 
         /* AWH bias blocks. */
@@ -1301,9 +1290,9 @@ void EnergyOutput::printStepToEnergyFile(ener_file* fp_ene,
     free_enxframe(&fr);
     if (log)
     {
-        if (bOR && fcd->orires->nr > 0)
+        if (bOR && fcd->orires)
         {
-            print_orires_log(log, fcd->orires);
+            print_orires_log(log, fcd->orires.get());
         }
 
         fprintf(log, "   Energies (%s)\n", unit_energy);
@@ -1312,7 +1301,7 @@ void EnergyOutput::printStepToEnergyFile(ener_file* fp_ene,
     }
 }
 
-void EnergyOutput::printAnnealingTemperatures(FILE* log, const SimulationGroups* groups, t_grpopts* opts)
+void EnergyOutput::printAnnealingTemperatures(FILE* log, const SimulationGroups* groups, const t_grpopts* opts)
 {
     if (log)
     {
@@ -1320,9 +1309,10 @@ void EnergyOutput::printAnnealingTemperatures(FILE* log, const SimulationGroups*
         {
             for (int i = 0; i < opts->ngtc; i++)
             {
-                if (opts->annealing[i] != eannNO)
+                if (opts->annealing[i] != SimulatedAnnealing::No)
                 {
-                    fprintf(log, "Current ref_t for group %s: %8.1f\n",
+                    fprintf(log,
+                            "Current ref_t for group %s: %8.1f\n",
                             *(groups->groupNames[groups->groups[SimulationAtomGroupType::TemperatureCoupling][i]]),
                             opts->ref_t[i]);
                 }
@@ -1351,8 +1341,10 @@ void EnergyOutput::printAverages(FILE* log, const SimulationGroups* groups)
         fprintf(log, "\t<====  A V E R A G E S  ====>\n");
         fprintf(log, "\t<==  ###############  ======>\n\n");
 
-        fprintf(log, "\tStatistics over %s steps using %s frames\n",
-                gmx_step_str(ebin_->nsteps_sim, buf1), gmx_step_str(ebin_->nsum_sim, buf2));
+        fprintf(log,
+                "\tStatistics over %s steps using %s frames\n",
+                gmx_step_str(ebin_->nsteps_sim, buf1),
+                gmx_step_str(ebin_->nsum_sim, buf2));
         fprintf(log, "\n");
 
         fprintf(log, "   Energies (%s)\n", unit_energy);
@@ -1393,11 +1385,11 @@ void EnergyOutput::printAverages(FILE* log, const SimulationGroups* groups)
         {
             int padding = 8 - strlen(unit_energy);
             fprintf(log, "%*sEpot (%s)   ", padding, "", unit_energy);
-            for (int i = 0; (i < egNR); i++)
+            for (auto key : keysOf(bEInd_))
             {
-                if (bEInd_[i])
+                if (bEInd_[key])
                 {
-                    fprintf(log, "%12s   ", egrp_nm[i]);
+                    fprintf(log, "%12s   ", enumValueToString(key));
                 }
             }
             fprintf(log, "\n");
@@ -1411,8 +1403,7 @@ void EnergyOutput::printAverages(FILE* log, const SimulationGroups* groups)
                     int nj = groups->groups[SimulationAtomGroupType::EnergyOutput][j];
                     int padding =
                             14 - (strlen(*(groups->groupNames[ni])) + strlen(*(groups->groupNames[nj])));
-                    fprintf(log, "%*s%s-%s", padding, "", *(groups->groupNames[ni]),
-                            *(groups->groupNames[nj]));
+                    fprintf(log, "%*s%s-%s", padding, "", *(groups->groupNames[ni]), *(groups->groupNames[nj]));
                     pr_ebin(log, ebin_, igrp_[n], nEc_, nEc_, eprAVER, false);
                     n++;
                 }
@@ -1424,17 +1415,6 @@ void EnergyOutput::printAverages(FILE* log, const SimulationGroups* groups)
             pr_ebin(log, ebin_, itemp_, nTC_, 4, eprAVER, true);
             fprintf(log, "\n");
         }
-        if (nU_ > 1)
-        {
-            fprintf(log, "%15s   %12s   %12s   %12s\n", "Group", "Ux", "Uy", "Uz");
-            for (int i = 0; (i < nU_); i++)
-            {
-                int ni = groups->groups[SimulationAtomGroupType::Acceleration][i];
-                fprintf(log, "%15s", *groups->groupNames[ni]);
-                pr_ebin(log, ebin_, iu_ + 3 * i, 3, 3, eprAVER, false);
-            }
-            fprintf(log, "\n");
-        }
     }
 }
 
@@ -1472,7 +1452,7 @@ void EnergyOutput::fillEnergyHistory(energyhistory_t* enerhist) const
     }
     if (dhc_)
     {
-        mde_delta_h_coll_update_energyhistory(dhc_, enerhist);
+        mde_delta_h_coll_update_energyhistory(dhc_.get(), enerhist);
     }
 }
 
@@ -1486,7 +1466,9 @@ void EnergyOutput::restoreFromEnergyHistory(const energyhistory_t& enerhist)
         gmx_fatal(FARGS,
                   "Mismatch between number of energies in run input (%u) and checkpoint file (%zu "
                   "or %zu).",
-                  nener, enerhist.ener_sum.size(), enerhist.ener_sum_sim.size());
+                  nener,
+                  enerhist.ener_sum.size(),
+                  enerhist.ener_sum_sim.size());
     }
 
     ebin_->nsteps     = enerhist.nsteps;
@@ -1502,7 +1484,7 @@ void EnergyOutput::restoreFromEnergyHistory(const energyhistory_t& enerhist)
     }
     if (dhc_)
     {
-        mde_delta_h_coll_restore_energyhistory(dhc_, enerhist.deltaHForeignLambdas.get());
+        mde_delta_h_coll_restore_energyhistory(dhc_.get(), enerhist.deltaHForeignLambdas.get());
     }
 }
 
index aa3ee609fcff82103bd1817405f4b0036d9c49ba..e7a91dec5dc2e18d896bf7b01118d014e5f05d90 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +53,7 @@
 
 class energyhistory_t;
 struct ener_file;
-struct gmx_ekindata_t;
+class gmx_ekindata_t;
 struct gmx_enerdata_t;
 struct SimulationGroups;
 struct gmx_mtop_t;
@@ -73,12 +73,12 @@ namespace gmx
 {
 class Awh;
 class Constraints;
-struct MdModulesNotifier;
+struct MDModulesNotifiers;
 enum class StartingBehavior;
 } // namespace gmx
 
 //! \brief Printed names for intergroup energies
-extern const char* egrp_nm[egNR + 1];
+const char* enumValueToString(NonBondedEnergyTerms enumValue);
 
 /* \brief delta_h block type enum: the kinds of energies written out. */
 enum
@@ -134,23 +134,23 @@ public:
      *
      * \param[in] fp_ene     Energy output file.
      * \param[in] mtop       Topology.
-     * \param[in] ir         Input parameters.
+     * \param[in] inputrec   Input parameters.
      * \param[in] pull_work  Pulling simulations data
      * \param[in] fp_dhdl    FEP file.
      * \param[in] isRerun    Is this is a rerun instead of the simulations.
      * \param[in] startingBehavior  Run starting behavior.
      * \param[in] simulationsShareState  Tells whether the physical state is shared over simulations
-     * \param[in] mdModulesNotifier Notifications to MD modules.
+     * \param[in] mdModulesNotifiers Notifications to MD modules.
      */
-    EnergyOutput(ener_file*               fp_ene,
-                 const gmx_mtop_t*        mtop,
-                 const t_inputrec*        ir,
-                 const pull_t*            pull_work,
-                 FILE*                    fp_dhdl,
-                 bool                     isRerun,
-                 StartingBehavior         startingBehavior,
-                 bool                     simulationsShareState,
-                 const MdModulesNotifier& mdModulesNotifier);
+    EnergyOutput(ener_file*                fp_ene,
+                 const gmx_mtop_t        mtop,
+                 const t_inputrec&         inputrec,
+                 const pull_t*             pull_work,
+                 FILE*                     fp_dhdl,
+                 bool                      isRerun,
+                 StartingBehavior          startingBehavior,
+                 bool                      simulationsShareState,
+                 const MDModulesNotifiers& mdModulesNotifiers);
 
     ~EnergyOutput();
 
@@ -240,7 +240,7 @@ public:
      * \param[in] opts    Atom temperature coupling groups options
      *                    (annealing is done by groups).
      */
-    static void printAnnealingTemperatures(FILE* log, const SimulationGroups* groups, t_grpopts* opts);
+    static void printAnnealingTemperatures(FILE* log, const SimulationGroups* groups, const t_grpopts* opts);
 
     /*! \brief Prints average values to log file.
      *
@@ -308,7 +308,7 @@ private:
     bool bMTTK_ = false;
 
     //! Temperature control scheme
-    int etc_ = 0;
+    TemperatureCoupling etc_ = TemperatureCoupling::No;
 
     //! Which of the main energy terms should be printed
     bool bEner_[F_NRE] = { false };
@@ -361,7 +361,7 @@ private:
     int isurft_ = 0;
 
     //! Pressure control scheme
-    int epc_ = 0;
+    PressureCoupling epc_ = PressureCoupling::No;
     //! Index for velocity of the box borders
     int ipc_ = 0;
 
@@ -375,8 +375,8 @@ private:
     //! Index for viscocity
     int ivisc_ = 0;
 
-    //! Which energy terms from egNR list should be printed in group-to-group block
-    bool bEInd_[egNR] = { false };
+    //! Which energy terms from NonBondedEnergyTerms list should be printed in group-to-group block
+    gmx::EnumerationArray<NonBondedEnergyTerms, bool> bEInd_;
     //! Number of energy terms to be printed (these, for which bEInd[] == true)
     int nEc_ = 0;
     //! Number of energy output groups
@@ -384,7 +384,7 @@ private:
     //! Number of intergroup energy sets to be printed for each energy term (nE = (nEg*(nEg+1))/2)
     int nE_ = 0;
     //! Indexes for integroup energy sets (each set with nEc energies)
-    int* igrp_ = nullptr;
+    std::vector<int> igrp_;
 
     //! Number of temperature coupling groups
     int nTC_ = 0;
@@ -405,26 +405,17 @@ private:
     //! Index for scalling factor of MTTK
     int itcb_ = 0;
 
-    //! Number of acceleration groups
-    int nU_ = 0;
-    //! Index for group velocities
-    int iu_ = 0;
-
-    //! Array to accumulate values during update
-    real* tmp_r_ = nullptr;
     //! Array to accumulate values during update
-    rvec* tmp_v_ = nullptr;
+    std::vector<real> tmp_r_;
 
     //! The dhdl.xvg output file
     FILE* fp_dhdl_ = nullptr;
     //! Energy components for dhdl.xvg output
-    double* dE_ = nullptr;
+    std::vector<double> dE_;
     //! The delta U components (raw data + histogram)
-    t_mde_delta_h_coll* dhc_ = nullptr;
+    std::unique_ptr<t_mde_delta_h_coll> dhc_;
     //! Temperatures for simulated tempering groups
-    real* temperatures_ = nullptr;
-    //! Number of temperatures actually saved
-    int numTemperatures_ = 0;
+    std::vector<real> temperatures_;
 
     //! For tracking the conserved or total energy
     std::unique_ptr<EnergyDriftTracker> conservedEnergyTracker_;
index d48016a4d64c05e82f6d380942c5dca4758d53a3..025cdac6573216f416f977d3c0cf022259a703ff 100644 (file)
 #include <cmath>
 #include <cstdio>
 
-#include <algorithm>
-
-#include "gromacs/domdec/domdec.h"
-#include "gromacs/fileio/confio.h"
-#include "gromacs/fileio/gmxfio.h"
-#include "gromacs/fileio/xtcio.h"
-#include "gromacs/gmxlib/network.h"
-#include "gromacs/gmxlib/nrnb.h"
-#include "gromacs/listed_forces/disre.h"
-#include "gromacs/listed_forces/orires.h"
-#include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
-#include "gromacs/math/vec.h"
-#include "gromacs/mdlib/calcmu.h"
-#include "gromacs/mdlib/constr.h"
-#include "gromacs/mdlib/force.h"
-#include "gromacs/mdlib/update.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/mdtypes/enerdata.h"
 #include "gromacs/mdtypes/forcerec.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
-#include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/mdtypes/state.h"
 #include "gromacs/random/threefry.h"
 #include "gromacs/random/uniformrealdistribution.h"
-#include "gromacs/timing/wallcycle.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
-#include "gromacs/utility/gmxmpi.h"
 #include "gromacs/utility/smalloc.h"
 
 #include "expanded_internal.h"
@@ -89,7 +72,7 @@ void init_expanded_ensemble(gmx_bool bStateFromCP, const t_inputrec* ir, df_hist
 {
     if (!bStateFromCP)
     {
-        init_df_history_weights(dfhist, ir->expandedvals, ir->fepvals->n_lambda);
+        init_df_history_weights(dfhist, ir->expandedvals.get(), ir->fepvals->n_lambda);
     }
 }
 
@@ -258,22 +241,22 @@ static gmx_bool CheckIfDoneEquilibrating(int nlim, const t_expanded* expand, con
         /* calculate the total number of samples */
         switch (expand->elmceq)
         {
-            case elmceqNO:
+            case LambdaWeightWillReachEquilibrium::No:
                 /* We have not equilibrated, and won't, ever. */
                 bDoneEquilibrating = FALSE;
                 break;
-            case elmceqYES:
+            case LambdaWeightWillReachEquilibrium::Yes:
                 /* we have equilibrated -- we're done */
                 bDoneEquilibrating = TRUE;
                 break;
-            case elmceqSTEPS:
+            case LambdaWeightWillReachEquilibrium::Steps:
                 /* first, check if we are equilibrating by steps, if we're still under */
                 if (step < expand->equil_steps)
                 {
                     bDoneEquilibrating = FALSE;
                 }
                 break;
-            case elmceqSAMPLES:
+            case LambdaWeightWillReachEquilibrium::Samples:
                 totalsamples = 0;
                 for (i = 0; i < nlim; i++)
                 {
@@ -284,7 +267,7 @@ static gmx_bool CheckIfDoneEquilibrating(int nlim, const t_expanded* expand, con
                     bDoneEquilibrating = FALSE;
                 }
                 break;
-            case elmceqNUMATLAM:
+            case LambdaWeightWillReachEquilibrium::NumAtLambda:
                 for (i = 0; i < nlim; i++)
                 {
                     if (dfhist->n_at_lam[i]
@@ -296,7 +279,7 @@ static gmx_bool CheckIfDoneEquilibrating(int nlim, const t_expanded* expand, con
                     }
                 }
                 break;
-            case elmceqWLDELTA:
+            case LambdaWeightWillReachEquilibrium::WLDelta:
                 if (EWL(expand->elamstats)) /* This check is in readir as well, but
                                                just to be sure */
                 {
@@ -306,13 +289,13 @@ static gmx_bool CheckIfDoneEquilibrating(int nlim, const t_expanded* expand, con
                     }
                 }
                 break;
-            case elmceqRATIO:
+            case LambdaWeightWillReachEquilibrium::Ratio:
                 /* we can use the flatness as a judge of good weights, as long as
                    we're not doing minvar, or Wang-Landau.
                    But turn off for now until we figure out exactly how we do this.
                  */
 
-                if (!(EWL(expand->elamstats) || expand->elamstats == elamstatsMINVAR))
+                if (!(EWL(expand->elamstats) || expand->elamstats == LambdaWeightCalculation::Minvar))
                 {
                     /* we want to use flatness -avoiding- the forced-through samples.  Plus, we need
                        to convert to floats for this histogram function. */
@@ -387,12 +370,13 @@ static gmx_bool UpdateWeights(int           nlim,
 
     if (EWL(expand->elamstats))
     {
-        if (expand->elamstats == elamstatsWL) /* Using standard Wang-Landau for weight updates */
+        if (expand->elamstats
+            == LambdaWeightCalculation::WL) /* Using standard Wang-Landau for weight updates */
         {
             dfhist->sum_weights[fep_state] -= dfhist->wl_delta;
             dfhist->wl_histo[fep_state] += 1.0;
         }
-        else if (expand->elamstats == elamstatsWWL)
+        else if (expand->elamstats == LambdaWeightCalculation::WWL)
         /* Using weighted Wang-Landau for weight updates.
          * Very closly equivalent to accelerated weight histogram approach
          * applied to expanded ensemble. */
@@ -408,8 +392,8 @@ static gmx_bool UpdateWeights(int           nlim,
 
             /* then increment weights (uses count) */
             pks = 0.0;
-            GenerateWeightedGibbsProbabilities(weighted_lamee, p_k, &pks, nlim, dfhist->wl_histo,
-                                               dfhist->wl_delta);
+            GenerateWeightedGibbsProbabilities(
+                    weighted_lamee, p_k, &pks, nlim, dfhist->wl_histo, dfhist->wl_delta);
 
             for (i = 0; i < nlim; i++)
             {
@@ -434,8 +418,9 @@ static gmx_bool UpdateWeights(int           nlim,
         }
     }
 
-    if (expand->elamstats == elamstatsBARKER || expand->elamstats == elamstatsMETROPOLIS
-        || expand->elamstats == elamstatsMINVAR)
+    if (expand->elamstats == LambdaWeightCalculation::Barker
+        || expand->elamstats == LambdaWeightCalculation::Metropolis
+        || expand->elamstats == LambdaWeightCalculation::Minvar)
     {
         maxc = 2 * expand->c_range + 1;
 
@@ -786,7 +771,7 @@ static gmx_bool UpdateWeights(int           nlim,
             lam_variance[fep_state] = clam_varp;
         }
 
-        if (expand->elamstats == elamstatsMINVAR)
+        if (expand->elamstats == LambdaWeightCalculation::Minvar)
         {
             bSufficientSamples = TRUE;
             /* make sure the number of samples in each state are all
@@ -910,7 +895,8 @@ static int ChooseNewLambda(int               nlim,
             accept[ifep]  = 0;
         }
 
-        if ((expand->elmcmove == elmcmoveGIBBS) || (expand->elmcmove == elmcmoveMETGIBBS))
+        if ((expand->elmcmove == LambdaMoveCalculation::Gibbs)
+            || (expand->elmcmove == LambdaMoveCalculation::MetropolisGibbs))
         {
             /* use the Gibbs sampler, with restricted range */
             if (expand->gibbsdeltalam < 0)
@@ -934,7 +920,7 @@ static int ChooseNewLambda(int               nlim,
 
             GenerateGibbsProbabilities(weighted_lamee, p_k, &pks, minfep, maxfep);
 
-            if (expand->elmcmove == elmcmoveGIBBS)
+            if (expand->elmcmove == LambdaMoveCalculation::Gibbs)
             {
                 for (ifep = minfep; ifep <= maxfep; ifep++)
                 {
@@ -952,7 +938,7 @@ static int ChooseNewLambda(int               nlim,
                     r1 -= p_k[lamnew];
                 }
             }
-            else if (expand->elmcmove == elmcmoveMETGIBBS)
+            else if (expand->elmcmove == LambdaMoveCalculation::MetropolisGibbs)
             {
 
                 /* Metropolized Gibbs sampling */
@@ -1059,17 +1045,23 @@ static int ChooseNewLambda(int               nlim,
                             "Something wrong in choosing new lambda state with a Gibbs move -- "
                             "probably underflow in weight determination.\nDenominator is: "
                             "%3d%17.10e\n  i                dE        numerator          weights\n",
-                            0, pks);
+                            0,
+                            pks);
                     for (ifep = minfep; ifep <= maxfep; ifep++)
                     {
-                        loc += sprintf(&errorstr[loc], "%3d %17.10e%17.10e%17.10e\n", ifep,
-                                       weighted_lamee[ifep], p_k[ifep], dfhist->sum_weights[ifep]);
+                        loc += sprintf(&errorstr[loc],
+                                       "%3d %17.10e%17.10e%17.10e\n",
+                                       ifep,
+                                       weighted_lamee[ifep],
+                                       p_k[ifep],
+                                       dfhist->sum_weights[ifep]);
                     }
                     gmx_fatal(FARGS, "%s", errorstr);
                 }
             }
         }
-        else if ((expand->elmcmove == elmcmoveMETROPOLIS) || (expand->elmcmove == elmcmoveBARKER))
+        else if ((expand->elmcmove == LambdaMoveCalculation::Metropolis)
+                 || (expand->elmcmove == LambdaMoveCalculation::Barker))
         {
             /* use the metropolis sampler with trial +/- 1 */
             r1 = dist(rng);
@@ -1097,7 +1089,7 @@ static int ChooseNewLambda(int               nlim,
             }
 
             de = weighted_lamee[lamtrial] - weighted_lamee[fep_state];
-            if (expand->elmcmove == elmcmoveMETROPOLIS)
+            if (expand->elmcmove == LambdaMoveCalculation::Metropolis)
             {
                 tprob = 1.0;
                 if (de < 0)
@@ -1110,7 +1102,7 @@ static int ChooseNewLambda(int               nlim,
                         1.0; /* doesn't actually matter, never proposed unless fep_state = ntrial, in which case it's 1.0 anyway */
                 accept[lamtrial] = tprob;
             }
-            else if (expand->elmcmove == elmcmoveBARKER)
+            else if (expand->elmcmove == LambdaMoveCalculation::Barker)
             {
                 if (de > 0) /* Numerically stable version */
                 {
@@ -1165,11 +1157,9 @@ void PrintFreeEnergyInfoToFile(FILE*               outfile,
                                int                 frequency,
                                int64_t             step)
 {
-    int         nlim, i, ifep, jfep;
-    real        dw, dg, dv, Tprint;
-    const char* print_names[efptNR] = { " FEPL", "MassL", "CoulL",   " VdwL",
-                                        "BondL", "RestT", "Temp.(K)" };
-    gmx_bool    bSimTemp            = FALSE;
+    int      nlim, ifep, jfep;
+    real     dw, dg, dv, Tprint;
+    gmx_bool bSimTemp = FALSE;
 
     nlim = fep->n_lambda;
     if (simtemp != nullptr)
@@ -1185,19 +1175,19 @@ void PrintFreeEnergyInfoToFile(FILE*               outfile,
             fprintf(outfile, "  Wang-Landau incrementor is: %11.5g\n", dfhist->wl_delta);
         }
         fprintf(outfile, "  N");
-        for (i = 0; i < efptNR; i++)
+        for (auto i : keysOf(fep->separate_dvdl))
         {
             if (fep->separate_dvdl[i])
             {
-                fprintf(outfile, "%7s", print_names[i]);
+                fprintf(outfile, "%7s", enumValueToString(i));
             }
-            else if ((i == efptTEMPERATURE) && bSimTemp)
+            else if ((i == FreeEnergyPerturbationCouplingType::Temperature) && bSimTemp)
             {
-                fprintf(outfile, "%10s", print_names[i]); /* more space for temperature formats */
+                fprintf(outfile, "%10s", enumValueToString(i)); /* more space for temperature formats */
             }
         }
         fprintf(outfile, "    Count   ");
-        if (expand->elamstats == elamstatsMINVAR)
+        if (expand->elamstats == LambdaWeightCalculation::Minvar)
         {
             fprintf(outfile, "W(in kT)   G(in kT)  dG(in kT)  dV(in kT)\n");
         }
@@ -1221,13 +1211,13 @@ void PrintFreeEnergyInfoToFile(FILE*               outfile,
                                - gmx::square(dfhist->sum_variance[ifep]));
             }
             fprintf(outfile, "%3d", (ifep + 1));
-            for (i = 0; i < efptNR; i++)
+            for (auto i : keysOf(fep->separate_dvdl))
             {
                 if (fep->separate_dvdl[i])
                 {
                     fprintf(outfile, "%7.3f", fep->all_lambda[i][ifep]);
                 }
-                else if (i == efptTEMPERATURE && bSimTemp)
+                else if (i == FreeEnergyPerturbationCouplingType::Temperature && bSimTemp)
                 {
                     fprintf(outfile, "%9.3f", simtemp->temperatures[ifep]);
                 }
@@ -1235,7 +1225,7 @@ void PrintFreeEnergyInfoToFile(FILE*               outfile,
             if (EWL(expand->elamstats)
                 && (!(dfhist->bEquil))) /* if performing WL and still haven't equilibrated */
             {
-                if (expand->elamstats == elamstatsWL)
+                if (expand->elamstats == LambdaWeightCalculation::WL)
                 {
                     fprintf(outfile, " %8d", static_cast<int>(dfhist->wl_histo[ifep]));
                 }
@@ -1248,10 +1238,14 @@ void PrintFreeEnergyInfoToFile(FILE*               outfile,
             {
                 fprintf(outfile, " %8d", dfhist->n_at_lam[ifep]);
             }
-            if (expand->elamstats == elamstatsMINVAR)
+            if (expand->elamstats == LambdaWeightCalculation::Minvar)
             {
-                fprintf(outfile, " %10.5f %10.5f %10.5f %10.5f", dfhist->sum_weights[ifep],
-                        dfhist->sum_dg[ifep], dg, dv);
+                fprintf(outfile,
+                        " %10.5f %10.5f %10.5f %10.5f",
+                        dfhist->sum_weights[ifep],
+                        dfhist->sum_dg[ifep],
+                        dg,
+                        dv);
             }
             else
             {
@@ -1335,16 +1329,17 @@ void PrintFreeEnergyInfoToFile(FILE*               outfile,
     }
 }
 
-int ExpandedEnsembleDynamics(FILE*                 log,
-                             const t_inputrec*     ir,
-                             const gmx_enerdata_t* enerd,
-                             t_state*              state,
-                             t_extmass*            MassQ,
-                             int                   fep_state,
-                             df_history_t*         dfhist,
-                             int64_t               step,
-                             rvec*                 v,
-                             const t_mdatoms*      mdatoms)
+int ExpandedEnsembleDynamics(FILE*                               log,
+                             t_inputrec*                         ir,
+                             const gmx_enerdata_t*               enerd,
+                             t_state*                            state,
+                             t_extmass*                          MassQ,
+                             int                                 fep_state,
+                             df_history_t*                       dfhist,
+                             int64_t                             step,
+                             rvec*                               v,
+                             const int                           homenr,
+                             gmx::ArrayRef<const unsigned short> cTC)
 /* Note that the state variable is only needed for simulated tempering, not
    Hamiltonian expanded ensemble.  May be able to remove it after integrator refactoring. */
 {
@@ -1356,8 +1351,8 @@ int ExpandedEnsembleDynamics(FILE*                 log,
     t_simtemp*  simtemp;
     gmx_bool    bIfReset, bSwitchtoOneOverT, bDoneEquilibrating = FALSE;
 
-    expand  = ir->expandedvals;
-    simtemp = ir->simtempvals;
+    expand  = ir->expandedvals.get();
+    simtemp = ir->simtempvals.get();
     nlim    = ir->fepvals->n_lambda;
 
     snew(scaled_lamee, nlim);
@@ -1383,22 +1378,23 @@ int ExpandedEnsembleDynamics(FILE*                 log,
     /* we don't need to include the pressure term, since the volume is the same between the two.
        is there some term we are neglecting, however? */
 
-    if (ir->efep != efepNO)
+    if (ir->efep != FreeEnergyPerturbationType::No)
     {
         for (i = 0; i < nlim; i++)
         {
             if (ir->bSimTemp)
             {
                 /* Note -- this assumes no mass changes, since kinetic energy is not added  . . . */
-                scaled_lamee[i] = enerd->foreignLambdaTerms.deltaH(i) / (simtemp->temperatures[i] * BOLTZ)
-                                  + enerd->term[F_EPOT]
-                                            * (1.0 / (simtemp->temperatures[i])
-                                               - 1.0 / (simtemp->temperatures[fep_state]))
-                                            / BOLTZ;
+                scaled_lamee[i] =
+                        enerd->foreignLambdaTerms.deltaH(i) / (simtemp->temperatures[i] * gmx::c_boltz)
+                        + enerd->term[F_EPOT]
+                                  * (1.0 / (simtemp->temperatures[i])
+                                     - 1.0 / (simtemp->temperatures[fep_state]))
+                                  / gmx::c_boltz;
             }
             else
             {
-                scaled_lamee[i] = enerd->foreignLambdaTerms.deltaH(i) / (expand->mc_temp * BOLTZ);
+                scaled_lamee[i] = enerd->foreignLambdaTerms.deltaH(i) / (expand->mc_temp * gmx::c_boltz);
                 /* mc_temp is currently set to the system reft unless otherwise defined */
             }
 
@@ -1415,7 +1411,8 @@ int ExpandedEnsembleDynamics(FILE*                 log,
             {
                 scaled_lamee[i] =
                         enerd->term[F_EPOT]
-                        * (1.0 / simtemp->temperatures[i] - 1.0 / simtemp->temperatures[fep_state]) / BOLTZ;
+                        * (1.0 / simtemp->temperatures[i] - 1.0 / simtemp->temperatures[fep_state])
+                        / gmx::c_boltz;
             }
         }
     }
@@ -1457,13 +1454,15 @@ int ExpandedEnsembleDynamics(FILE*                 log,
     {
         if (log)
         {
-            fprintf(log, "\nStep %" PRId64 ": Weights have equilibrated, using criteria: %s\n",
-                    step, elmceq_names[expand->elmceq]);
+            fprintf(log,
+                    "\nStep %" PRId64 ": Weights have equilibrated, using criteria: %s\n",
+                    step,
+                    enumValueToString(expand->elmceq));
         }
     }
 
-    lamnew = ChooseNewLambda(nlim, expand, dfhist, fep_state, weighted_lamee, p_k,
-                             ir->expandedvals->lmc_seed, step);
+    lamnew = ChooseNewLambda(
+            nlim, expand, dfhist, fep_state, weighted_lamee, p_k, ir->expandedvals->lmc_seed, step);
     /* if using simulated tempering, we need to adjust the temperatures */
     if (ir->bSimTemp && (lamnew != fep_state)) /* only need to change the temperatures if we change the state */
     {
@@ -1487,13 +1486,13 @@ int ExpandedEnsembleDynamics(FILE*                 log,
         /* we don't need to manipulate the ekind information, as it isn't due to be reset until the next step anyway */
 
         nstart = 0;
-        nend   = mdatoms->homenr;
+        nend   = homenr;
         for (n = nstart; n < nend; n++)
         {
             gt = 0;
-            if (mdatoms->cTC)
+            if (!cTC.empty())
             {
-                gt = mdatoms->cTC[n];
+                gt = cTC[n];
             }
             for (d = 0; d < DIM; d++)
             {
index 6f6bec9804e6b71c5d4d6e872c0c7dc540b5e8c8..1c227e0ea3ef1496c2666487868fead9470f9595 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +38,6 @@
 #include <stdio.h>
 
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/basedefinitions.h"
 
 struct df_history_t;
 struct gmx_enerdata_t;
@@ -46,24 +45,30 @@ struct t_expanded;
 struct t_extmass;
 struct t_inputrec;
 struct t_lambda;
-struct t_mdatoms;
 struct t_simtemp;
 class t_state;
 
-void init_npt_masses(const t_inputrec* ir, t_state* state, t_extmass* MassQ, gmx_bool bInit);
+namespace gmx
+{
+template<typename>
+class ArrayRef;
+}
 
-void init_expanded_ensemble(gmx_bool bStateFromCP, const t_inputrec* ir, df_history_t* dfhist);
+void init_npt_masses(const t_inputrec* ir, t_state* state, t_extmass* MassQ, bool bInit);
 
-int ExpandedEnsembleDynamics(FILE*                 log,
-                             const t_inputrec*     ir,
-                             const gmx_enerdata_t* enerd,
-                             t_state*              state,
-                             t_extmass*            MassQ,
-                             int                   fep_state,
-                             df_history_t*         dfhist,
-                             int64_t               step,
-                             rvec*                 v,
-                             const t_mdatoms*      mdatoms);
+void init_expanded_ensemble(bool bStateFromCP, const t_inputrec* ir, df_history_t* dfhist);
+
+int ExpandedEnsembleDynamics(FILE*                               log,
+                             t_inputrec*                         ir,
+                             const gmx_enerdata_t*               enerd,
+                             t_state*                            state,
+                             t_extmass*                          MassQ,
+                             int                                 fep_state,
+                             df_history_t*                       dfhist,
+                             int64_t                             step,
+                             rvec*                               v,
+                             int                                 homenr,
+                             gmx::ArrayRef<const unsigned short> cTC);
 
 void PrintFreeEnergyInfoToFile(FILE*               outfile,
                                const t_lambda*     fep,
index a46f02e1e8f9f073024cfecd170ca9cd7d45f265..cc63b5e5ad366a9d82e069c5061f398b57092c95 100644 (file)
 
 namespace gmx
 {
-real calculateAcceptanceWeight(int calculationMode, real lambdaEnergyDifference)
+real calculateAcceptanceWeight(LambdaWeightCalculation calculationMode, real lambdaEnergyDifference)
 {
-    if (calculationMode == elamstatsBARKER || calculationMode == elamstatsMINVAR)
+    if (calculationMode == LambdaWeightCalculation::Barker
+        || calculationMode == LambdaWeightCalculation::Minvar)
     {
         /* Barker acceptance rule forumula is used for accumulation of probability for
          * both the Barker variant of the weight accumulation algorithm and the
@@ -77,7 +78,7 @@ real calculateAcceptanceWeight(int calculationMode, real lambdaEnergyDifference)
             return std::exp(-lambdaEnergyDifference) / (1.0 + std::exp(-lambdaEnergyDifference));
         }
     }
-    else if (calculationMode == elamstatsMETROPOLIS)
+    else if (calculationMode == LambdaWeightCalculation::Metropolis)
     {
         /* Metropolis acceptance rule for a jump from state i -> j is defined as
          *     1            (if dE_ij < 0)
index be3c7c81f0ecb63896d41e089e992dbf482932e9..f2f70b7145ea39f8010452cf090bebf68266e4fa 100644 (file)
@@ -46,6 +46,8 @@
 
 #include "gromacs/utility/real.h"
 
+enum class LambdaWeightCalculation : int;
+
 namespace gmx
 {
 /*! \brief Calculates the acceptance weight for a lambda state transition
@@ -54,7 +56,7 @@ namespace gmx
  * \param[in] lambdaEnergyDifference  The difference in energy between the two states
  * \return  The acceptance weight
  */
-real calculateAcceptanceWeight(int calculationMode, real lambdaEnergyDifference);
+real calculateAcceptanceWeight(LambdaWeightCalculation calculationMode, real lambdaEnergyDifference);
 } // namespace gmx
 
 #endif // GMX_MDLIB_EXPANDEDINTERNAL_H
index 2bd8088a6a95ad3ace559280359d8f861e7381e7..a939841283a504e4231d7bf914b51128adb81464 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -75,15 +75,15 @@ using gmx::RVec;
 
 static void clearEwaldThreadOutput(ewald_corr_thread_t* ewc_t)
 {
-    ewc_t->Vcorr_q        = 0;
-    ewc_t->Vcorr_lj       = 0;
-    ewc_t->dvdl[efptCOUL] = 0;
-    ewc_t->dvdl[efptVDW]  = 0;
+    ewc_t->Vcorr_q                                        = 0;
+    ewc_t->Vcorr_lj                                       = 0;
+    ewc_t->dvdl[FreeEnergyPerturbationCouplingType::Coul] = 0;
+    ewc_t->dvdl[FreeEnergyPerturbationCouplingType::Vdw]  = 0;
     clear_mat(ewc_t->vir_q);
     clear_mat(ewc_t->vir_lj);
 }
 
-static void reduceEwaldThreadOuput(int nthreads, ewald_corr_thread_t* ewc_t)
+static void reduceEwaldThreadOuput(int nthreads, gmx::ArrayRef<ewald_corr_thread_t> ewc_t)
 {
     ewald_corr_thread_t& dest = ewc_t[0];
 
@@ -91,38 +91,40 @@ static void reduceEwaldThreadOuput(int nthreads, ewald_corr_thread_t* ewc_t)
     {
         dest.Vcorr_q += ewc_t[t].Vcorr_q;
         dest.Vcorr_lj += ewc_t[t].Vcorr_lj;
-        dest.dvdl[efptCOUL] += ewc_t[t].dvdl[efptCOUL];
-        dest.dvdl[efptVDW] += ewc_t[t].dvdl[efptVDW];
+        dest.dvdl[FreeEnergyPerturbationCouplingType::Coul] +=
+                ewc_t[t].dvdl[FreeEnergyPerturbationCouplingType::Coul];
+        dest.dvdl[FreeEnergyPerturbationCouplingType::Vdw] +=
+                ewc_t[t].dvdl[FreeEnergyPerturbationCouplingType::Vdw];
         m_add(dest.vir_q, ewc_t[t].vir_q, dest.vir_q);
         m_add(dest.vir_lj, ewc_t[t].vir_lj, dest.vir_lj);
     }
 }
 
-void calculateLongRangeNonbondeds(t_forcerec*                   fr,
-                                  const t_inputrec*             ir,
-                                  const t_commrec*              cr,
-                                  t_nrnb*                       nrnb,
-                                  gmx_wallcycle_t               wcycle,
-                                  const t_mdatoms*              md,
-                                  gmx::ArrayRef<const RVec>     coordinates,
-                                  gmx::ForceWithVirial*         forceWithVirial,
-                                  gmx_enerdata_t*               enerd,
-                                  const matrix                  box,
-                                  const real*                   lambda,
-                                  const rvec*                   mu_tot,
-                                  const gmx::StepWorkload&      stepWork,
-                                  const DDBalanceRegionHandler& ddBalanceRegionHandler)
+void calculateLongRangeNonbondeds(t_forcerec*                    fr,
+                                  const t_inputrec             ir,
+                                  const t_commrec*               cr,
+                                  t_nrnb*                        nrnb,
+                                  gmx_wallcycle*                 wcycle,
+                                  const t_mdatoms*               md,
+                                  gmx::ArrayRef<const RVec>      coordinates,
+                                  gmx::ForceWithVirial*          forceWithVirial,
+                                  gmx_enerdata_t*                enerd,
+                                  const matrix                   box,
+                                  gmx::ArrayRef<const real>      lambda,
+                                  gmx::ArrayRef<const gmx::RVec> mu_tot,
+                                  const gmx::StepWorkload&       stepWork,
+                                  const DDBalanceRegionHandler&  ddBalanceRegionHandler)
 {
     const bool computePmeOnCpu = (EEL_PME(fr->ic->eeltype) || EVDW_PME(fr->ic->vdwtype))
                                  && thisRankHasDuty(cr, DUTY_PME)
                                  && (pme_run_mode(fr->pmedata) == PmeRunMode::CPU);
 
-    const bool haveEwaldSurfaceTerm = haveEwaldSurfaceContribution(*ir);
+    const bool haveEwaldSurfaceTerm = haveEwaldSurfaceContribution(ir);
 
     /* Do long-range electrostatics and/or LJ-PME
      * and compute PME surface terms when necessary.
      */
-    if ((computePmeOnCpu || fr->ic->eeltype == eelEWALD || haveEwaldSurfaceTerm)
+    if ((computePmeOnCpu || fr->ic->eeltype == CoulombInteractionType::Ewald || haveEwaldSurfaceTerm)
         && stepWork.computeNonbondedForces)
     {
         int  status = 0;
@@ -139,7 +141,7 @@ void calculateLongRangeNonbondeds(t_forcerec*                   fr,
             /* Calculate the Ewald surface force and energy contributions, when necessary */
             if (haveEwaldSurfaceTerm)
             {
-                wallcycle_sub_start(wcycle, ewcsEWALD_CORRECTION);
+                wallcycle_sub_start(wcycle, WallCycleSubCounter::EwaldCorrection);
 
                 int nthreads = fr->nthread_ewc;
 #pragma omp parallel for num_threads(nthreads) schedule(static)
@@ -158,11 +160,25 @@ void calculateLongRangeNonbondeds(t_forcerec*                   fr,
                          * exclusion forces) are calculated, so we can store
                          * the forces in the normal, single forceWithVirial->force_ array.
                          */
-                        const rvec* x = as_rvec_array(coordinates.data());
-                        ewald_LRcorrection(md->homenr, cr, nthreads, t, *fr, *ir, md->chargeA,
-                                           md->chargeB, (md->nChargePerturbed != 0), x, box, mu_tot,
-                                           as_rvec_array(forceWithVirial->force_.data()),
-                                           &ewc_t.Vcorr_q, lambda[efptCOUL], &ewc_t.dvdl[efptCOUL]);
+                        ewald_LRcorrection(
+                                md->homenr,
+                                cr,
+                                nthreads,
+                                t,
+                                *fr,
+                                ir,
+                                md->chargeA ? gmx::constArrayRefFromArray(md->chargeA, md->nr)
+                                            : gmx::ArrayRef<const real>{},
+                                md->chargeB ? gmx::constArrayRefFromArray(md->chargeB, md->nr)
+                                            : gmx::ArrayRef<const real>{},
+                                (md->nChargePerturbed != 0),
+                                coordinates,
+                                box,
+                                mu_tot,
+                                forceWithVirial->force_,
+                                &ewc_t.Vcorr_q,
+                                lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)],
+                                &ewc_t.dvdl[FreeEnergyPerturbationCouplingType::Coul]);
                     }
                     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
                 }
@@ -170,7 +186,7 @@ void calculateLongRangeNonbondeds(t_forcerec*                   fr,
                 {
                     reduceEwaldThreadOuput(nthreads, fr->ewc_t);
                 }
-                wallcycle_sub_stop(wcycle, ewcsEWALD_CORRECTION);
+                wallcycle_sub_stop(wcycle, WallCycleSubCounter::EwaldCorrection);
             }
 
             if (EEL_PME_EWALD(fr->ic->eeltype) && fr->n_tpi == 0)
@@ -178,7 +194,12 @@ void calculateLongRangeNonbondeds(t_forcerec*                   fr,
                 /* This is not in a subcounter because it takes a
                    negligible and constant-sized amount of time */
                 ewaldOutput.Vcorr_q += ewald_charge_correction(
-                        cr, fr, lambda[efptCOUL], box, &ewaldOutput.dvdl[efptCOUL], ewaldOutput.vir_q);
+                        cr,
+                        fr,
+                        lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)],
+                        box,
+                        &ewaldOutput.dvdl[FreeEnergyPerturbationCouplingType::Coul],
+                        ewaldOutput.vir_q);
             }
 
             if (computePmeOnCpu)
@@ -193,18 +214,39 @@ void calculateLongRangeNonbondeds(t_forcerec*                   fr,
                      */
                     ddBalanceRegionHandler.closeAfterForceComputationCpu();
 
-                    wallcycle_start(wcycle, ewcPMEMESH);
+                    wallcycle_start(wcycle, WallCycleCounter::PmeMesh);
                     status = gmx_pme_do(
                             fr->pmedata,
                             gmx::constArrayRefFromArray(coordinates.data(), md->homenr - fr->n_tpi),
-                            forceWithVirial->force_, md->chargeA, md->chargeB, md->sqrt_c6A,
-                            md->sqrt_c6B, md->sigmaA, md->sigmaB, box, cr,
-                            DOMAINDECOMP(cr) ? dd_pme_maxshift_x(cr->dd) : 0,
-                            DOMAINDECOMP(cr) ? dd_pme_maxshift_y(cr->dd) : 0, nrnb, wcycle,
-                            ewaldOutput.vir_q, ewaldOutput.vir_lj, &Vlr_q, &Vlr_lj,
-                            lambda[efptCOUL], lambda[efptVDW], &ewaldOutput.dvdl[efptCOUL],
-                            &ewaldOutput.dvdl[efptVDW], stepWork);
-                    wallcycle_stop(wcycle, ewcPMEMESH);
+                            forceWithVirial->force_,
+                            md->chargeA ? gmx::constArrayRefFromArray(md->chargeA, md->nr)
+                                        : gmx::ArrayRef<const real>{},
+                            md->chargeB ? gmx::constArrayRefFromArray(md->chargeB, md->nr)
+                                        : gmx::ArrayRef<const real>{},
+                            md->sqrt_c6A ? gmx::constArrayRefFromArray(md->sqrt_c6A, md->nr)
+                                         : gmx::ArrayRef<const real>{},
+                            md->sqrt_c6B ? gmx::constArrayRefFromArray(md->sqrt_c6B, md->nr)
+                                         : gmx::ArrayRef<const real>{},
+                            md->sigmaA ? gmx::constArrayRefFromArray(md->sigmaA, md->nr)
+                                       : gmx::ArrayRef<const real>{},
+                            md->sigmaB ? gmx::constArrayRefFromArray(md->sigmaB, md->nr)
+                                       : gmx::ArrayRef<const real>{},
+                            box,
+                            cr,
+                            DOMAINDECOMP(cr) ? dd_pme_maxshift_x(*cr->dd) : 0,
+                            DOMAINDECOMP(cr) ? dd_pme_maxshift_y(*cr->dd) : 0,
+                            nrnb,
+                            wcycle,
+                            ewaldOutput.vir_q,
+                            ewaldOutput.vir_lj,
+                            &Vlr_q,
+                            &Vlr_lj,
+                            lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)],
+                            lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)],
+                            &ewaldOutput.dvdl[FreeEnergyPerturbationCouplingType::Coul],
+                            &ewaldOutput.dvdl[FreeEnergyPerturbationCouplingType::Vdw],
+                            stepWork);
+                    wallcycle_stop(wcycle, WallCycleCounter::PmeMesh);
                     if (status != 0)
                     {
                         gmx_fatal(FARGS, "Error %d in reciprocal PME routine", status);
@@ -223,20 +265,29 @@ void calculateLongRangeNonbondeds(t_forcerec*                   fr,
                     /* Determine the PME grid energy of the test molecule
                      * with the PME grid potential of the other charges.
                      */
-                    gmx_pme_calc_energy(
-                            fr->pmedata, coordinates.subArray(md->homenr - fr->n_tpi, fr->n_tpi),
-                            gmx::arrayRefFromArray(md->chargeA + md->homenr - fr->n_tpi, fr->n_tpi),
-                            &Vlr_q);
+                    Vlr_q = gmx_pme_calc_energy(
+                            fr->pmedata,
+                            coordinates.subArray(md->homenr - fr->n_tpi, fr->n_tpi),
+                            gmx::arrayRefFromArray(md->chargeA + md->homenr - fr->n_tpi, fr->n_tpi));
                 }
             }
         }
 
-        if (fr->ic->eeltype == eelEWALD)
+        if (fr->ic->eeltype == CoulombInteractionType::Ewald)
         {
-            const rvec* x = as_rvec_array(coordinates.data());
-            Vlr_q = do_ewald(ir, x, as_rvec_array(forceWithVirial->force_.data()), md->chargeA,
-                             md->chargeB, box, cr, md->homenr, ewaldOutput.vir_q, fr->ic->ewaldcoeff_q,
-                             lambda[efptCOUL], &ewaldOutput.dvdl[efptCOUL], fr->ewald_table);
+            Vlr_q = do_ewald(ir,
+                             coordinates,
+                             forceWithVirial->force_,
+                             gmx::arrayRefFromArray(md->chargeA, md->nr),
+                             gmx::arrayRefFromArray(md->chargeB, md->nr),
+                             box,
+                             cr,
+                             md->homenr,
+                             ewaldOutput.vir_q,
+                             fr->ic->ewaldcoeff_q,
+                             lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)],
+                             &ewaldOutput.dvdl[FreeEnergyPerturbationCouplingType::Coul],
+                             fr->ewald_table.get());
         }
 
         /* Note that with separate PME nodes we get the real energies later */
@@ -244,18 +295,26 @@ void calculateLongRangeNonbondeds(t_forcerec*                   fr,
         // long-range virial contribution.
         forceWithVirial->addVirialContribution(ewaldOutput.vir_q);
         forceWithVirial->addVirialContribution(ewaldOutput.vir_lj);
-        enerd->dvdl_lin[efptCOUL] += ewaldOutput.dvdl[efptCOUL];
-        enerd->dvdl_lin[efptVDW] += ewaldOutput.dvdl[efptVDW];
+        enerd->dvdl_lin[FreeEnergyPerturbationCouplingType::Coul] +=
+                ewaldOutput.dvdl[FreeEnergyPerturbationCouplingType::Coul];
+        enerd->dvdl_lin[FreeEnergyPerturbationCouplingType::Vdw] +=
+                ewaldOutput.dvdl[FreeEnergyPerturbationCouplingType::Vdw];
         enerd->term[F_COUL_RECIP] = Vlr_q + ewaldOutput.Vcorr_q;
         enerd->term[F_LJ_RECIP]   = Vlr_lj + ewaldOutput.Vcorr_lj;
 
         if (debug)
         {
-            fprintf(debug, "Vlr_q = %g, Vcorr_q = %g, Vlr_corr_q = %g\n", Vlr_q,
-                    ewaldOutput.Vcorr_q, enerd->term[F_COUL_RECIP]);
+            fprintf(debug,
+                    "Vlr_q = %g, Vcorr_q = %g, Vlr_corr_q = %g\n",
+                    Vlr_q,
+                    ewaldOutput.Vcorr_q,
+                    enerd->term[F_COUL_RECIP]);
             pr_rvecs(debug, 0, "vir_el_recip after corr", ewaldOutput.vir_q, DIM);
-            fprintf(debug, "Vlr_lj: %g, Vcorr_lj = %g, Vlr_corr_lj = %g\n", Vlr_lj,
-                    ewaldOutput.Vcorr_lj, enerd->term[F_LJ_RECIP]);
+            fprintf(debug,
+                    "Vlr_lj: %g, Vcorr_lj = %g, Vlr_corr_lj = %g\n",
+                    Vlr_lj,
+                    ewaldOutput.Vcorr_lj,
+                    enerd->term[F_LJ_RECIP]);
             pr_rvecs(debug, 0, "vir_lj_recip after corr", ewaldOutput.vir_lj, DIM);
         }
     }
index 63f80e88394acbfc85503b10c56c55207104f7a5..a25a42d6c23973760f344db4fb4efe8a1e61e02e 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -92,7 +92,7 @@ class VirtualSitesHandler;
 void do_force(FILE*                               log,
               const t_commrec*                    cr,
               const gmx_multisim_t*               ms,
-              const t_inputrec*                   inputrec,
+              const t_inputrec&                   inputrec,
               gmx::Awh*                           awh,
               gmx_enfrot*                         enforcedRotation,
               gmx::ImdSession*                    imdSession,
@@ -103,7 +103,7 @@ void do_force(FILE*                               log,
               const gmx_localtop_t*               top,
               const matrix                        box,
               gmx::ArrayRefWithPadding<gmx::RVec> coordinates,
-              history_t*                          hist,
+              const history_t*                    hist,
               gmx::ForceBuffersView*              force,
               tensor                              vir_force,
               const t_mdatoms*                    mdatoms,
@@ -134,7 +134,7 @@ void do_force(FILE*                               log,
  * on whether the PME-mesh contribution is computed on a separate PME rank or on a GPU.
  */
 void calculateLongRangeNonbondeds(t_forcerec*                    fr,
-                                  const t_inputrec*              ir,
+                                  const t_inputrec&              ir,
                                   const t_commrec*               cr,
                                   t_nrnb*                        nrnb,
                                   gmx_wallcycle*                 wcycle,
@@ -143,8 +143,8 @@ void calculateLongRangeNonbondeds(t_forcerec*                    fr,
                                   gmx::ForceWithVirial*          forceWithVirial,
                                   gmx_enerdata_t*                enerd,
                                   const matrix                   box,
-                                  const real*                    lambda,
-                                  const rvec*                    mu_tot,
+                                  gmx::ArrayRef<const real>      lambda,
+                                  gmx::ArrayRef<const gmx::RVec> mu_tot,
                                   const gmx::StepWorkload&       stepWork,
                                   const DDBalanceRegionHandler&  ddBalanceRegionHandler);
 
index 8d7eb271086c8cf129c422602cb7d6263aecdb47..871e7cdc338ee523803c6626be63891072c43f94 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-2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013-2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -40,7 +40,6 @@
 
 #include "config.h"
 
-#include <cassert>
 #include <cmath>
 #include <cstdlib>
 #include <cstring>
@@ -52,7 +51,6 @@
 #include "gromacs/domdec/domdec.h"
 #include "gromacs/domdec/domdec_struct.h"
 #include "gromacs/ewald/ewald.h"
-#include "gromacs/ewald/ewald_utils.h"
 #include "gromacs/ewald/pme_pp_comm_gpu.h"
 #include "gromacs/fileio/filetypes.h"
 #include "gromacs/gmxlib/network.h"
@@ -63,7 +61,6 @@
 #include "gromacs/listed_forces/listed_forces.h"
 #include "gromacs/listed_forces/pairs.h"
 #include "gromacs/math/functions.h"
-#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/dispersioncorrection.h"
@@ -71,7 +68,6 @@
 #include "gromacs/mdlib/forcerec_threading.h"
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
 #include "gromacs/mdlib/md_support.h"
-#include "gromacs/mdlib/rf_util.h"
 #include "gromacs/mdlib/wall.h"
 #include "gromacs/mdlib/wholemoleculetransform.h"
 #include "gromacs/mdtypes/commrec.h"
@@ -83,6 +79,7 @@
 #include "gromacs/mdtypes/interaction_const.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/multipletimestepping.h"
+#include "gromacs/mdtypes/nblist.h"
 #include "gromacs/nbnxm/nbnxm.h"
 #include "gromacs/pbcutil/ishift.h"
 #include "gromacs/pbcutil/pbc.h"
 ForceHelperBuffers::ForceHelperBuffers(bool haveDirectVirialContributions) :
     haveDirectVirialContributions_(haveDirectVirialContributions)
 {
-    shiftForces_.resize(SHIFTS);
+    shiftForces_.resize(gmx::c_numShiftVectors);
 }
 
 void ForceHelperBuffers::resize(int numAtoms)
@@ -115,13 +112,13 @@ void ForceHelperBuffers::resize(int numAtoms)
     }
 }
 
-static std::vector<real> mk_nbfp(const gmx_ffparams_t* idef, gmx_bool bBHAM)
+std::vector<real> makeNonBondedParameterLists(const gmx_ffparams_t& forceFieldParams, bool useBuckinghamPotential)
 {
     std::vector<real> nbfp;
     int               atnr;
 
-    atnr = idef->atnr;
-    if (bBHAM)
+    atnr = forceFieldParams.atnr;
+    if (useBuckinghamPotential)
     {
         nbfp.resize(3 * atnr * atnr);
         int k = 0;
@@ -129,10 +126,10 @@ static std::vector<real> mk_nbfp(const gmx_ffparams_t* idef, gmx_bool bBHAM)
         {
             for (int j = 0; (j < atnr); j++, k++)
             {
-                BHAMA(nbfp, atnr, i, j) = idef->iparams[k].bham.a;
-                BHAMB(nbfp, atnr, i, j) = idef->iparams[k].bham.b;
+                BHAMA(nbfp, atnr, i, j) = forceFieldParams.iparams[k].bham.a;
+                BHAMB(nbfp, atnr, i, j) = forceFieldParams.iparams[k].bham.b;
                 /* nbfp now includes the 6.0 derivative prefactor */
-                BHAMC(nbfp, atnr, i, j) = idef->iparams[k].bham.c * 6.0;
+                BHAMC(nbfp, atnr, i, j) = forceFieldParams.iparams[k].bham.c * 6.0;
             }
         }
     }
@@ -145,8 +142,8 @@ static std::vector<real> mk_nbfp(const gmx_ffparams_t* idef, gmx_bool bBHAM)
             for (int j = 0; (j < atnr); j++, k++)
             {
                 /* nbfp now includes the 6.0/12.0 derivative prefactors */
-                C6(nbfp, atnr, i, j)  = idef->iparams[k].lj.c6 * 6.0;
-                C12(nbfp, atnr, i, j) = idef->iparams[k].lj.c12 * 12.0;
+                C6(nbfp, atnr, i, j)  = forceFieldParams.iparams[k].lj.c6 * 6.0;
+                C12(nbfp, atnr, i, j) = forceFieldParams.iparams[k].lj.c12 * 12.0;
             }
         }
     }
@@ -154,30 +151,30 @@ static std::vector<real> mk_nbfp(const gmx_ffparams_t* idef, gmx_bool bBHAM)
     return nbfp;
 }
 
-static real* make_ljpme_c6grid(const gmx_ffparams_t* idef, t_forcerec* fr)
+std::vector<real> makeLJPmeC6GridCorrectionParameters(const gmx_ffparams_t& forceFieldParams,
+                                                      const t_forcerec&     forceRec)
 {
-    int   i, j, k, atnr;
-    real  c6, c6i, c6j, c12i, c12j, epsi, epsj, sigmai, sigmaj;
-    real* grid;
+    int  i, j, k, atnr;
+    real c6, c6i, c6j, c12i, c12j, epsi, epsj, sigmai, sigmaj;
 
     /* For LJ-PME simulations, we correct the energies with the reciprocal space
      * inside of the cut-off. To do this the non-bonded kernels needs to have
      * access to the C6-values used on the reciprocal grid in pme.c
      */
 
-    atnr = idef->atnr;
-    snew(grid, 2 * atnr * atnr);
+    atnr = forceFieldParams.atnr;
+    std::vector<real> grid(2 * atnr * atnr, 0.0);
     for (i = k = 0; (i < atnr); i++)
     {
         for (j = 0; (j < atnr); j++, k++)
         {
-            c6i  = idef->iparams[i * (atnr + 1)].lj.c6;
-            c12i = idef->iparams[i * (atnr + 1)].lj.c12;
-            c6j  = idef->iparams[j * (atnr + 1)].lj.c6;
-            c12j = idef->iparams[j * (atnr + 1)].lj.c12;
+            c6i  = forceFieldParams.iparams[i * (atnr + 1)].lj.c6;
+            c12i = forceFieldParams.iparams[i * (atnr + 1)].lj.c12;
+            c6j  = forceFieldParams.iparams[j * (atnr + 1)].lj.c6;
+            c12j = forceFieldParams.iparams[j * (atnr + 1)].lj.c12;
             c6   = std::sqrt(c6i * c6j);
-            if (fr->ljpme_combination_rule == eljpmeLB && !gmx_numzero(c6) && !gmx_numzero(c12i)
-                && !gmx_numzero(c12j))
+            if (forceRec.ljpme_combination_rule == LongRangeVdW::LB && !gmx_numzero(c6)
+                && !gmx_numzero(c12i) && !gmx_numzero(c12j))
             {
                 sigmai = gmx::sixthroot(c12i / c6i);
                 sigmaj = gmx::sixthroot(c12j / c6j);
@@ -201,7 +198,7 @@ enum
     acSETTLE
 };
 
-static std::vector<cginfo_mb_t> init_cginfo_mb(const gmx_mtop_t* mtop, const t_forcerec* fr)
+static std::vector<cginfo_mb_t> init_cginfo_mb(const gmx_mtop_t& mtop, const t_forcerec* fr)
 {
     gmx_bool* type_VDW;
     int*      a_con;
@@ -212,17 +209,17 @@ static std::vector<cginfo_mb_t> init_cginfo_mb(const gmx_mtop_t* mtop, const t_f
         type_VDW[ai] = FALSE;
         for (int j = 0; j < fr->ntype; j++)
         {
-            type_VDW[ai] = type_VDW[ai] || fr->bBHAM || C6(fr->nbfp, fr->ntype, ai, j) != 0
+            type_VDW[ai] = type_VDW[ai] || fr->haveBuckingham || C6(fr->nbfp, fr->ntype, ai, j) != 0
                            || C12(fr->nbfp, fr->ntype, ai, j) != 0;
         }
     }
 
     std::vector<cginfo_mb_t> cginfoPerMolblock;
     int                      a_offset = 0;
-    for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
+    for (size_t mb = 0; mb < mtop.molblock.size(); mb++)
     {
-        const gmx_molblock_t& molb = mtop->molblock[mb];
-        const gmx_moltype_t&  molt = mtop->moltype[molb.type];
+        const gmx_molblock_t& molb = mtop.molblock[mb];
+        const gmx_moltype_t&  molt = mtop.moltype[molb.type];
         const auto&           excl = molt.excls;
 
         /* Check if the cginfo is identical for all molecules in this block.
@@ -235,15 +232,15 @@ static std::vector<cginfo_mb_t> init_cginfo_mb(const gmx_mtop_t* mtop, const t_f
             const int am = m * molt.atoms.nr;
             for (int a = 0; a < molt.atoms.nr; a++)
             {
-                if (getGroupType(mtop->groups, SimulationAtomGroupType::QuantumMechanics, a_offset + am + a)
-                    != getGroupType(mtop->groups, SimulationAtomGroupType::QuantumMechanics, a_offset + a))
+                if (getGroupType(mtop.groups, SimulationAtomGroupType::QuantumMechanics, a_offset + am + a)
+                    != getGroupType(mtop.groups, SimulationAtomGroupType::QuantumMechanics, a_offset + a))
                 {
                     bId = FALSE;
                 }
-                if (!mtop->groups.groupNumbers[SimulationAtomGroupType::QuantumMechanics].empty())
+                if (!mtop.groups.groupNumbers[SimulationAtomGroupType::QuantumMechanics].empty())
                 {
-                    if (mtop->groups.groupNumbers[SimulationAtomGroupType::QuantumMechanics][a_offset + am + a]
-                        != mtop->groups.groupNumbers[SimulationAtomGroupType::QuantumMechanics][a_offset + a])
+                    if (mtop.groups.groupNumbers[SimulationAtomGroupType::QuantumMechanics][a_offset + am + a]
+                        != mtop.groups.groupNumbers[SimulationAtomGroupType::QuantumMechanics][a_offset + a])
                     {
                         bId = FALSE;
                     }
@@ -287,7 +284,8 @@ static std::vector<cginfo_mb_t> init_cginfo_mb(const gmx_mtop_t* mtop, const t_f
                 int&          atomInfo = cginfo[molculeOffsetInBlock + a];
 
                 /* Store the energy group in cginfo */
-                int gid = getGroupType(mtop->groups, SimulationAtomGroupType::EnergyOutput,
+                int gid = getGroupType(mtop.groups,
+                                       SimulationAtomGroupType::EnergyOutput,
                                        a_offset + molculeOffsetInBlock + a);
                 SET_CGINFO_GID(atomInfo, gid);
 
@@ -323,7 +321,7 @@ static std::vector<cginfo_mb_t> init_cginfo_mb(const gmx_mtop_t* mtop, const t_f
                 {
                     SET_CGINFO_HAS_Q(atomInfo);
                 }
-                if (fr->efep != efepNO && PERTURBED(atom))
+                if (fr->efep != FreeEnergyPerturbationType::No && PERTURBED(atom))
                 {
                     SET_CGINFO_FEP(atomInfo);
                 }
@@ -363,7 +361,7 @@ static std::vector<int> cginfo_expand(const int nmb, gmx::ArrayRef<const cginfo_
 /* Sets the sum of charges (squared) and C6 in the system in fr.
  * Returns whether the system has a net charge.
  */
-static bool set_chargesum(FILE* log, t_forcerec* fr, const gmx_mtop_t* mtop)
+static bool set_chargesum(FILE* log, t_forcerec* fr, const gmx_mtop_t& mtop)
 {
     /*This now calculates sum for q and c6*/
     double qsum, q2sum, q, c6sum, c6;
@@ -371,16 +369,16 @@ static bool set_chargesum(FILE* log, t_forcerec* fr, const gmx_mtop_t* mtop)
     qsum  = 0;
     q2sum = 0;
     c6sum = 0;
-    for (const gmx_molblock_t& molb : mtop->molblock)
+    for (const gmx_molblock_t& molb : mtop.molblock)
     {
         int            nmol  = molb.nmol;
-        const t_atoms* atoms = &mtop->moltype[molb.type].atoms;
+        const t_atoms* atoms = &mtop.moltype[molb.type].atoms;
         for (int i = 0; i < atoms->nr; i++)
         {
             q = atoms->atom[i].q;
             qsum += nmol * q;
             q2sum += nmol * q * q;
-            c6 = mtop->ffparams.iparams[atoms->atom[i].type * (mtop->ffparams.atnr + 1)].lj.c6;
+            c6 = mtop.ffparams.iparams[atoms->atom[i].type * (mtop.ffparams.atnr + 1)].lj.c6;
             c6sum += nmol * c6;
         }
     }
@@ -388,21 +386,21 @@ static bool set_chargesum(FILE* log, t_forcerec* fr, const gmx_mtop_t* mtop)
     fr->q2sum[0] = q2sum;
     fr->c6sum[0] = c6sum;
 
-    if (fr->efep != efepNO)
+    if (fr->efep != FreeEnergyPerturbationType::No)
     {
         qsum  = 0;
         q2sum = 0;
         c6sum = 0;
-        for (const gmx_molblock_t& molb : mtop->molblock)
+        for (const gmx_molblock_t& molb : mtop.molblock)
         {
             int            nmol  = molb.nmol;
-            const t_atoms* atoms = &mtop->moltype[molb.type].atoms;
+            const t_atoms* atoms = &mtop.moltype[molb.type].atoms;
             for (int i = 0; i < atoms->nr; i++)
             {
                 q = atoms->atom[i].qB;
                 qsum += nmol * q;
                 q2sum += nmol * q * q;
-                c6 = mtop->ffparams.iparams[atoms->atom[i].typeB * (mtop->ffparams.atnr + 1)].lj.c6;
+                c6 = mtop.ffparams.iparams[atoms->atom[i].typeB * (mtop.ffparams.atnr + 1)].lj.c6;
                 c6sum += nmol * c6;
             }
             fr->qsum[1]  = qsum;
@@ -418,7 +416,7 @@ static bool set_chargesum(FILE* log, t_forcerec* fr, const gmx_mtop_t* mtop)
     }
     if (log)
     {
-        if (fr->efep == efepNO)
+        if (fr->efep == FreeEnergyPerturbationType::No)
         {
             fprintf(log, "System total charge: %.3f\n", fr->qsum[0]);
         }
@@ -432,62 +430,6 @@ static bool set_chargesum(FILE* log, t_forcerec* fr, const gmx_mtop_t* mtop)
     return (std::abs(fr->qsum[0]) > 1e-4 || std::abs(fr->qsum[1]) > 1e-4);
 }
 
-static real calcBuckinghamBMax(FILE* fplog, const gmx_mtop_t* mtop)
-{
-    const t_atoms *at1, *at2;
-    int            i, j, tpi, tpj, ntypes;
-    real           b, bmin;
-
-    if (fplog)
-    {
-        fprintf(fplog, "Determining largest Buckingham b parameter for table\n");
-    }
-    ntypes = mtop->ffparams.atnr;
-
-    bmin            = -1;
-    real bham_b_max = 0;
-    for (size_t mt1 = 0; mt1 < mtop->moltype.size(); mt1++)
-    {
-        at1 = &mtop->moltype[mt1].atoms;
-        for (i = 0; (i < at1->nr); i++)
-        {
-            tpi = at1->atom[i].type;
-            if (tpi >= ntypes)
-            {
-                gmx_fatal(FARGS, "Atomtype[%d] = %d, maximum = %d", i, tpi, ntypes);
-            }
-
-            for (size_t mt2 = mt1; mt2 < mtop->moltype.size(); mt2++)
-            {
-                at2 = &mtop->moltype[mt2].atoms;
-                for (j = 0; (j < at2->nr); j++)
-                {
-                    tpj = at2->atom[j].type;
-                    if (tpj >= ntypes)
-                    {
-                        gmx_fatal(FARGS, "Atomtype[%d] = %d, maximum = %d", j, tpj, ntypes);
-                    }
-                    b = mtop->ffparams.iparams[tpi * ntypes + tpj].bham.b;
-                    if (b > bham_b_max)
-                    {
-                        bham_b_max = b;
-                    }
-                    if ((b < bmin) || (bmin == -1))
-                    {
-                        bmin = b;
-                    }
-                }
-            }
-        }
-    }
-    if (fplog)
-    {
-        fprintf(fplog, "Buckingham b parameters, min: %g, max: %g\n", bmin, bham_b_max);
-    }
-
-    return bham_b_max;
-}
-
 /*!\brief If there's bonded interactions of type \c ftype1 or \c
  * ftype2 present in the topology, build an array of the number of
  * interactions present for each bonded interaction index found in the
@@ -501,12 +443,12 @@ static real calcBuckinghamBMax(FILE* fplog, const gmx_mtop_t* mtop)
  * \c ncount. It will contain zero for every bonded interaction index
  * for which no interactions are present in the topology.
  */
-static void count_tables(int ftype1, int ftype2, const gmx_mtop_t* mtop, int* ncount, int** count)
+static void count_tables(int ftype1, int ftype2, const gmx_mtop_t& mtop, int* ncount, int** count)
 {
     int ftype, i, j, tabnr;
 
     // Loop over all moleculetypes
-    for (const gmx_moltype_t& molt : mtop->moltype)
+    for (const gmx_moltype_t& molt : mtop.moltype)
     {
         // Loop over all interaction types
         for (ftype = 0; ftype < F_NRE; ftype++)
@@ -520,7 +462,7 @@ static void count_tables(int ftype1, int ftype2, const gmx_mtop_t* mtop, int* nc
                 for (i = 0; i < il.size(); i += stride)
                 {
                     // Find out which table index the user wanted
-                    tabnr = mtop->ffparams.iparams[il.iatoms[i]].tab.table;
+                    tabnr = mtop.ffparams.iparams[il.iatoms[i]].tab.table;
                     if (tabnr < 0)
                     {
                         gmx_fatal(FARGS, "A bonded table number is smaller than 0: %d\n", tabnr);
@@ -556,7 +498,7 @@ static void count_tables(int ftype1, int ftype2, const gmx_mtop_t* mtop, int* nc
 static std::vector<bondedtable_t> make_bonded_tables(FILE*                            fplog,
                                                      int                              ftype1,
                                                      int                              ftype2,
-                                                     const gmx_mtop_t*                mtop,
+                                                     const gmx_mtop_t&                mtop,
                                                      gmx::ArrayRef<const std::string> tabbfnm,
                                                      const char*                      tabext)
 {
@@ -597,8 +539,10 @@ static std::vector<bondedtable_t> make_bonded_tables(FILE*
                               "Tabulated interaction of type '%s%s%s' with index %d cannot be used "
                               "because no table file whose name matched '%s' was passed via the "
                               "gmx mdrun -tableb command-line option.",
-                              interaction_function[ftype1].longname, isPlural ? "' or '" : "",
-                              isPlural ? interaction_function[ftype2].longname : "", i,
+                              interaction_function[ftype1].longname,
+                              isPlural ? "' or '" : "",
+                              isPlural ? interaction_function[ftype2].longname : "",
+                              i,
                               patternToFind.c_str());
                 }
             }
@@ -620,103 +564,6 @@ void forcerec_set_ranges(t_forcerec* fr, int natoms_force, int natoms_force_cons
     }
 }
 
-static real cutoff_inf(real cutoff)
-{
-    if (cutoff == 0)
-    {
-        cutoff = GMX_CUTOFF_INF;
-    }
-
-    return cutoff;
-}
-
-/*! \brief Print Coulomb Ewald citations and set ewald coefficients */
-static void initCoulombEwaldParameters(FILE*                fp,
-                                       const t_inputrec*    ir,
-                                       bool                 systemHasNetCharge,
-                                       interaction_const_t* ic)
-{
-    if (!EEL_PME_EWALD(ir->coulombtype))
-    {
-        return;
-    }
-
-    if (fp)
-    {
-        fprintf(fp, "Will do PME sum in reciprocal space for electrostatic interactions.\n");
-
-        if (ir->coulombtype == eelP3M_AD)
-        {
-            please_cite(fp, "Hockney1988");
-            please_cite(fp, "Ballenegger2012");
-        }
-        else
-        {
-            please_cite(fp, "Essmann95a");
-        }
-
-        if (ir->ewald_geometry == eewg3DC)
-        {
-            if (fp)
-            {
-                fprintf(fp, "Using the Ewald3DC correction for systems with a slab geometry%s.\n",
-                        systemHasNetCharge ? " and net charge" : "");
-            }
-            please_cite(fp, "In-Chul99a");
-            if (systemHasNetCharge)
-            {
-                please_cite(fp, "Ballenegger2009");
-            }
-        }
-    }
-
-    ic->ewaldcoeff_q = calc_ewaldcoeff_q(ir->rcoulomb, ir->ewald_rtol);
-    if (fp)
-    {
-        fprintf(fp, "Using a Gaussian width (1/beta) of %g nm for Ewald\n", 1 / ic->ewaldcoeff_q);
-    }
-
-    if (ic->coulomb_modifier == eintmodPOTSHIFT)
-    {
-        GMX_RELEASE_ASSERT(ic->rcoulomb != 0, "Cutoff radius cannot be zero");
-        ic->sh_ewald = std::erfc(ic->ewaldcoeff_q * ic->rcoulomb) / ic->rcoulomb;
-    }
-    else
-    {
-        ic->sh_ewald = 0;
-    }
-}
-
-/*! \brief Print Van der Waals Ewald citations and set ewald coefficients */
-static void initVdwEwaldParameters(FILE* fp, const t_inputrec* ir, interaction_const_t* ic)
-{
-    if (!EVDW_PME(ir->vdwtype))
-    {
-        return;
-    }
-
-    if (fp)
-    {
-        fprintf(fp, "Will do PME sum in reciprocal space for LJ dispersion interactions.\n");
-        please_cite(fp, "Essmann95a");
-    }
-    ic->ewaldcoeff_lj = calc_ewaldcoeff_lj(ir->rvdw, ir->ewald_rtol_lj);
-    if (fp)
-    {
-        fprintf(fp, "Using a Gaussian width (1/beta) of %g nm for LJ Ewald\n", 1 / ic->ewaldcoeff_lj);
-    }
-
-    if (ic->vdw_modifier == eintmodPOTSHIFT)
-    {
-        real crc2       = gmx::square(ic->ewaldcoeff_lj * ic->rvdw);
-        ic->sh_lj_ewald = (std::exp(-crc2) * (1 + crc2 + 0.5 * crc2 * crc2) - 1) / gmx::power6(ic->rvdw);
-    }
-    else
-    {
-        ic->sh_lj_ewald = 0;
-    }
-}
-
 /* Generate Coulomb and/or Van der Waals Ewald long-range correction tables
  *
  * Tables are generated for one or both, depending on if the pointers
@@ -768,192 +615,34 @@ void init_interaction_const_tables(FILE* fp, interaction_const_t* ic, const real
 {
     if (EEL_PME_EWALD(ic->eeltype) || EVDW_PME(ic->vdwtype))
     {
-        init_ewald_f_table(*ic, rlist, tableExtensionLength, ic->coulombEwaldTables.get(),
-                           ic->vdwEwaldTables.get());
+        init_ewald_f_table(
+                *ic, rlist, tableExtensionLength, ic->coulombEwaldTables.get(), ic->vdwEwaldTables.get());
         if (fp != nullptr)
         {
-            fprintf(fp, "Initialized non-bonded Ewald tables, spacing: %.2e size: %zu\n\n",
-                    1 / ic->coulombEwaldTables->scale, ic->coulombEwaldTables->tableF.size());
+            fprintf(fp,
+                    "Initialized non-bonded Ewald tables, spacing: %.2e size: %zu\n\n",
+                    1 / ic->coulombEwaldTables->scale,
+                    ic->coulombEwaldTables->tableF.size());
         }
     }
 }
 
-static void clear_force_switch_constants(shift_consts_t* sc)
-{
-    sc->c2   = 0;
-    sc->c3   = 0;
-    sc->cpot = 0;
-}
-
-static void force_switch_constants(real p, real rsw, real rc, shift_consts_t* sc)
-{
-    /* Here we determine the coefficient for shifting the force to zero
-     * between distance rsw and the cut-off rc.
-     * For a potential of r^-p, we have force p*r^-(p+1).
-     * But to save flops we absorb p in the coefficient.
-     * Thus we get:
-     * force/p   = r^-(p+1) + c2*r^2 + c3*r^3
-     * potential = r^-p + c2/3*r^3 + c3/4*r^4 + cpot
-     */
-    sc->c2   = ((p + 1) * rsw - (p + 4) * rc) / (pow(rc, p + 2) * gmx::square(rc - rsw));
-    sc->c3   = -((p + 1) * rsw - (p + 3) * rc) / (pow(rc, p + 2) * gmx::power3(rc - rsw));
-    sc->cpot = -pow(rc, -p) + p * sc->c2 / 3 * gmx::power3(rc - rsw)
-               + p * sc->c3 / 4 * gmx::power4(rc - rsw);
-}
-
-static void potential_switch_constants(real rsw, real rc, switch_consts_t* sc)
-{
-    /* The switch function is 1 at rsw and 0 at rc.
-     * The derivative and second derivate are zero at both ends.
-     * rsw        = max(r - r_switch, 0)
-     * sw         = 1 + c3*rsw^3 + c4*rsw^4 + c5*rsw^5
-     * dsw        = 3*c3*rsw^2 + 4*c4*rsw^3 + 5*c5*rsw^4
-     * force      = force*dsw - potential*sw
-     * potential *= sw
-     */
-    sc->c3 = -10 / gmx::power3(rc - rsw);
-    sc->c4 = 15 / gmx::power4(rc - rsw);
-    sc->c5 = -6 / gmx::power5(rc - rsw);
-}
-
-/*! \brief Construct interaction constants
- *
- * This data is used (particularly) by search and force code for
- * short-range interactions. Many of these are constant for the whole
- * simulation; some are constant only after PME tuning completes.
- */
-static void init_interaction_const(FILE*                 fp,
-                                   interaction_const_t** interaction_const,
-                                   const t_inputrec*     ir,
-                                   const gmx_mtop_t*     mtop,
-                                   bool                  systemHasNetCharge)
+real cutoff_inf(real cutoff)
 {
-    interaction_const_t* ic = new interaction_const_t;
-
-    ic->coulombEwaldTables = std::make_unique<EwaldCorrectionTables>();
-    ic->vdwEwaldTables     = std::make_unique<EwaldCorrectionTables>();
-
-    /* Lennard-Jones */
-    ic->vdwtype         = ir->vdwtype;
-    ic->vdw_modifier    = ir->vdw_modifier;
-    ic->reppow          = mtop->ffparams.reppow;
-    ic->rvdw            = cutoff_inf(ir->rvdw);
-    ic->rvdw_switch     = ir->rvdw_switch;
-    ic->ljpme_comb_rule = ir->ljpme_combination_rule;
-    ic->useBuckingham   = (mtop->ffparams.functype[0] == F_BHAM);
-    if (ic->useBuckingham)
-    {
-        ic->buckinghamBMax = calcBuckinghamBMax(fp, mtop);
-    }
-
-    initVdwEwaldParameters(fp, ir, ic);
-
-    clear_force_switch_constants(&ic->dispersion_shift);
-    clear_force_switch_constants(&ic->repulsion_shift);
-
-    switch (ic->vdw_modifier)
-    {
-        case eintmodPOTSHIFT:
-            /* Only shift the potential, don't touch the force */
-            ic->dispersion_shift.cpot = -1.0 / gmx::power6(ic->rvdw);
-            ic->repulsion_shift.cpot  = -1.0 / gmx::power12(ic->rvdw);
-            break;
-        case eintmodFORCESWITCH:
-            /* Switch the force, switch and shift the potential */
-            force_switch_constants(6.0, ic->rvdw_switch, ic->rvdw, &ic->dispersion_shift);
-            force_switch_constants(12.0, ic->rvdw_switch, ic->rvdw, &ic->repulsion_shift);
-            break;
-        case eintmodPOTSWITCH:
-            /* Switch the potential and force */
-            potential_switch_constants(ic->rvdw_switch, ic->rvdw, &ic->vdw_switch);
-            break;
-        case eintmodNONE:
-        case eintmodEXACTCUTOFF:
-            /* Nothing to do here */
-            break;
-        default: gmx_incons("unimplemented potential modifier");
-    }
-
-    /* Electrostatics */
-    ic->eeltype          = ir->coulombtype;
-    ic->coulomb_modifier = ir->coulomb_modifier;
-    ic->rcoulomb         = cutoff_inf(ir->rcoulomb);
-    ic->rcoulomb_switch  = ir->rcoulomb_switch;
-    ic->epsilon_r        = ir->epsilon_r;
-
-    /* Set the Coulomb energy conversion factor */
-    if (ic->epsilon_r != 0)
-    {
-        ic->epsfac = ONE_4PI_EPS0 / ic->epsilon_r;
-    }
-    else
-    {
-        /* eps = 0 is infinite dieletric: no Coulomb interactions */
-        ic->epsfac = 0;
-    }
-
-    /* Reaction-field */
-    if (EEL_RF(ic->eeltype))
-    {
-        GMX_RELEASE_ASSERT(ic->eeltype != eelGRF_NOTUSED, "GRF is no longer supported");
-        ic->epsilon_rf = ir->epsilon_rf;
-
-        calc_rffac(fp, ic->epsilon_r, ic->epsilon_rf, ic->rcoulomb, &ic->k_rf, &ic->c_rf);
-    }
-    else
-    {
-        /* For plain cut-off we might use the reaction-field kernels */
-        ic->epsilon_rf = ic->epsilon_r;
-        ic->k_rf       = 0;
-        if (ir->coulomb_modifier == eintmodPOTSHIFT)
-        {
-            ic->c_rf = 1 / ic->rcoulomb;
-        }
-        else
-        {
-            ic->c_rf = 0;
-        }
-    }
-
-    initCoulombEwaldParameters(fp, ir, systemHasNetCharge, ic);
-
-    if (fp != nullptr)
-    {
-        real dispersion_shift;
-
-        dispersion_shift = ic->dispersion_shift.cpot;
-        if (EVDW_PME(ic->vdwtype))
-        {
-            dispersion_shift -= ic->sh_lj_ewald;
-        }
-        fprintf(fp, "Potential shift: LJ r^-12: %.3e r^-6: %.3e", ic->repulsion_shift.cpot, dispersion_shift);
-
-        if (ic->eeltype == eelCUT)
-        {
-            fprintf(fp, ", Coulomb %.e", -ic->c_rf);
-        }
-        else if (EEL_PME(ic->eeltype))
-        {
-            fprintf(fp, ", Ewald %.3e", -ic->sh_ewald);
-        }
-        fprintf(fp, "\n");
-    }
-
-    if (ir->efep != efepNO)
+    if (cutoff == 0)
     {
-        GMX_RELEASE_ASSERT(ir->fepvals, "ir->fepvals should be set wth free-energy");
-        ic->softCoreParameters = std::make_unique<interaction_const_t::SoftCoreParameters>(*ir->fepvals);
+        cutoff = GMX_CUTOFF_INF;
     }
 
-    *interaction_const = ic;
+    return cutoff;
 }
 
-void init_forcerec(FILE*                            fp,
+void init_forcerec(FILE*                            fplog,
                    const gmx::MDLogger&             mdlog,
-                   t_forcerec*                      fr,
-                   const t_inputrec*                ir,
-                   const gmx_mtop_t*                mtop,
-                   const t_commrec*                 cr,
+                   t_forcerec*                      forcerec,
+                   const t_inputrec&                inputrec,
+                   const gmx_mtop_t&                mtop,
+                   const t_commrec*                 commrec,
                    matrix                           box,
                    const char*                      tabfn,
                    const char*                      tabpfn,
@@ -961,100 +650,102 @@ void init_forcerec(FILE*                            fp,
                    real                             print_force)
 {
     /* The CMake default turns SIMD kernels on, but it might be turned off further down... */
-    fr->use_simd_kernels = GMX_USE_SIMD_KERNELS;
+    forcerec->use_simd_kernels = GMX_USE_SIMD_KERNELS;
 
-    if (check_box(ir->pbcType, box))
+    if (check_box(inputrec.pbcType, box))
     {
-        gmx_fatal(FARGS, "%s", check_box(ir->pbcType, box));
+        gmx_fatal(FARGS, "%s", check_box(inputrec.pbcType, box));
     }
 
     /* Test particle insertion ? */
-    if (EI_TPI(ir->eI))
+    if (EI_TPI(inputrec.eI))
     {
         /* Set to the size of the molecule to be inserted (the last one) */
-        gmx::RangePartitioning molecules = gmx_mtop_molecules(*mtop);
-        fr->n_tpi                        = molecules.block(molecules.numBlocks() - 1).size();
+        gmx::RangePartitioning molecules = gmx_mtop_molecules(mtop);
+        forcerec->n_tpi                  = molecules.block(molecules.numBlocks() - 1).size();
     }
     else
     {
-        fr->n_tpi = 0;
+        forcerec->n_tpi = 0;
     }
 
-    if (ir->coulombtype == eelRF_NEC_UNSUPPORTED || ir->coulombtype == eelGRF_NOTUSED)
+    if (inputrec.coulombtype == CoulombInteractionType::RFNecUnsupported
+        || inputrec.coulombtype == CoulombInteractionType::GRFNotused)
     {
-        gmx_fatal(FARGS, "%s electrostatics is no longer supported", eel_names[ir->coulombtype]);
+        gmx_fatal(FARGS, "%s electrostatics is no longer supported", enumValueToString(inputrec.coulombtype));
     }
 
-    if (ir->bAdress)
+    if (inputrec.bAdress)
     {
         gmx_fatal(FARGS, "AdResS simulations are no longer supported");
     }
-    if (ir->useTwinRange)
+    if (inputrec.useTwinRange)
     {
         gmx_fatal(FARGS, "Twin-range simulations are no longer supported");
     }
     /* Copy the user determined parameters */
-    fr->userint1  = ir->userint1;
-    fr->userint2  = ir->userint2;
-    fr->userint3  = ir->userint3;
-    fr->userint4  = ir->userint4;
-    fr->userreal1 = ir->userreal1;
-    fr->userreal2 = ir->userreal2;
-    fr->userreal3 = ir->userreal3;
-    fr->userreal4 = ir->userreal4;
+    forcerec->userint1  = inputrec.userint1;
+    forcerec->userint2  = inputrec.userint2;
+    forcerec->userint3  = inputrec.userint3;
+    forcerec->userint4  = inputrec.userint4;
+    forcerec->userreal1 = inputrec.userreal1;
+    forcerec->userreal2 = inputrec.userreal2;
+    forcerec->userreal3 = inputrec.userreal3;
+    forcerec->userreal4 = inputrec.userreal4;
 
     /* Shell stuff */
-    fr->fc_stepsize = ir->fc_stepsize;
+    forcerec->fc_stepsize = inputrec.fc_stepsize;
 
     /* Free energy */
-    fr->efep = ir->efep;
+    forcerec->efep = inputrec.efep;
 
     if ((getenv("GMX_DISABLE_SIMD_KERNELS") != nullptr) || (getenv("GMX_NOOPTIMIZEDKERNELS") != nullptr))
     {
-        fr->use_simd_kernels = FALSE;
-        if (fp != nullptr)
+        forcerec->use_simd_kernels = FALSE;
+        if (fplog != nullptr)
         {
-            fprintf(fp,
+            fprintf(fplog,
                     "\nFound environment variable GMX_DISABLE_SIMD_KERNELS.\n"
                     "Disabling the usage of any SIMD-specific non-bonded & bonded kernel routines\n"
                     "(e.g. SSE2/SSE4.1/AVX).\n\n");
         }
     }
 
-    fr->bBHAM = (mtop->ffparams.functype[0] == F_BHAM);
+    forcerec->haveBuckingham = (mtop.ffparams.functype[0] == F_BHAM);
 
     /* Neighbour searching stuff */
-    fr->pbcType = ir->pbcType;
+    forcerec->pbcType = inputrec.pbcType;
 
     /* Determine if we will do PBC for distances in bonded interactions */
-    if (fr->pbcType == PbcType::No)
+    if (forcerec->pbcType == PbcType::No)
     {
-        fr->bMolPBC = FALSE;
+        forcerec->bMolPBC = FALSE;
     }
     else
     {
         const bool useEwaldSurfaceCorrection =
-                (EEL_PME_EWALD(ir->coulombtype) && ir->epsilon_surface != 0);
+                (EEL_PME_EWALD(inputrec.coulombtype) && inputrec.epsilon_surface != 0);
         const bool haveOrientationRestraints = (gmx_mtop_ftype_count(mtop, F_ORIRES) > 0);
-        if (!DOMAINDECOMP(cr))
+        if (!DOMAINDECOMP(commrec))
         {
-            fr->bMolPBC = true;
+            forcerec->bMolPBC = true;
 
             if (useEwaldSurfaceCorrection || haveOrientationRestraints)
             {
-                fr->wholeMoleculeTransform =
-                        std::make_unique<gmx::WholeMoleculeTransform>(*mtop, ir->pbcType);
+                forcerec->wholeMoleculeTransform =
+                        std::make_unique<gmx::WholeMoleculeTransform>(mtop, inputrec.pbcType);
             }
         }
         else
         {
-            fr->bMolPBC = dd_bonded_molpbc(cr->dd, fr->pbcType);
+            forcerec->bMolPBC = dd_bonded_molpbc(*commrec->dd, forcerec->pbcType);
 
             /* With Ewald surface correction it is useful to support e.g. running water
              * in parallel with update groups.
              * With orientation restraints there is no sensible use case supported with DD.
              */
-            if ((useEwaldSurfaceCorrection && !dd_moleculesAreAlwaysWhole(*cr->dd)) || haveOrientationRestraints)
+            if ((useEwaldSurfaceCorrection && !dd_moleculesAreAlwaysWhole(*commrec->dd))
+                || haveOrientationRestraints)
             {
                 gmx_fatal(FARGS,
                           "You requested Ewald surface correction or orientation restraints, "
@@ -1066,168 +757,192 @@ void init_forcerec(FILE*                            fp,
 
         if (useEwaldSurfaceCorrection)
         {
-            GMX_RELEASE_ASSERT(!DOMAINDECOMP(cr) || dd_moleculesAreAlwaysWhole(*cr->dd),
+            GMX_RELEASE_ASSERT(!DOMAINDECOMP(commrec) || dd_moleculesAreAlwaysWhole(*commrec->dd),
                                "Molecules can not be broken by PBC with epsilon_surface > 0");
         }
     }
 
-    fr->rc_scaling = ir->refcoord_scaling;
-    copy_rvec(ir->posres_com, fr->posres_com);
-    copy_rvec(ir->posres_comB, fr->posres_comB);
-    fr->rlist                  = cutoff_inf(ir->rlist);
-    fr->ljpme_combination_rule = ir->ljpme_combination_rule;
+    forcerec->rc_scaling = inputrec.refcoord_scaling;
+    copy_rvec(inputrec.posres_com, forcerec->posres_com);
+    copy_rvec(inputrec.posres_comB, forcerec->posres_comB);
+    forcerec->rlist                  = cutoff_inf(inputrec.rlist);
+    forcerec->ljpme_combination_rule = inputrec.ljpme_combination_rule;
 
     /* This now calculates sum for q and c6*/
-    bool systemHasNetCharge = set_chargesum(fp, fr, mtop);
+    bool systemHasNetCharge = set_chargesum(fplog, forcerec, mtop);
 
-    /* fr->ic is used both by verlet and group kernels (to some extent) now */
-    init_interaction_const(fp, &fr->ic, ir, mtop, systemHasNetCharge);
-    init_interaction_const_tables(fp, fr->ic, fr->rlist, ir->tabext);
+    /* Make data structure used by kernels */
+    forcerec->ic = std::make_unique<interaction_const_t>(
+            init_interaction_const(fplog, inputrec, mtop, systemHasNetCharge));
+    init_interaction_const_tables(fplog, forcerec->ic.get(), forcerec->rlist, inputrec.tabext);
 
-    const interaction_const_t* ic = fr->ic;
+    const interaction_const_t* interactionConst = forcerec->ic.get();
 
     /* TODO: Replace this Ewald table or move it into interaction_const_t */
-    if (ir->coulombtype == eelEWALD)
+    if (inputrec.coulombtype == CoulombInteractionType::Ewald)
     {
-        init_ewald_tab(&(fr->ewald_table), ir, fp);
+        forcerec->ewald_table = std::make_unique<gmx_ewald_tab_t>(inputrec, fplog);
     }
 
     /* Electrostatics: Translate from interaction-setting-in-mdp-file to kernel interaction format */
-    switch (ic->eeltype)
+    switch (interactionConst->eeltype)
     {
-        case eelCUT: fr->nbkernel_elec_interaction = GMX_NBKERNEL_ELEC_COULOMB; break;
-
-        case eelRF:
-        case eelRF_ZERO: fr->nbkernel_elec_interaction = GMX_NBKERNEL_ELEC_REACTIONFIELD; break;
-
-        case eelSWITCH:
-        case eelSHIFT:
-        case eelUSER:
-        case eelPMESWITCH:
-        case eelPMEUSER:
-        case eelPMEUSERSWITCH:
-            fr->nbkernel_elec_interaction = GMX_NBKERNEL_ELEC_CUBICSPLINETABLE;
+        case CoulombInteractionType::Cut:
+            forcerec->nbkernel_elec_interaction = NbkernelElecType::Coulomb;
             break;
 
-        case eelPME:
-        case eelP3M_AD:
-        case eelEWALD: fr->nbkernel_elec_interaction = GMX_NBKERNEL_ELEC_EWALD; break;
+        case CoulombInteractionType::RF:
+        case CoulombInteractionType::RFZero:
+            forcerec->nbkernel_elec_interaction = NbkernelElecType::ReactionField;
+            break;
+
+        case CoulombInteractionType::Switch:
+        case CoulombInteractionType::Shift:
+        case CoulombInteractionType::User:
+        case CoulombInteractionType::PmeSwitch:
+        case CoulombInteractionType::PmeUser:
+        case CoulombInteractionType::PmeUserSwitch:
+            forcerec->nbkernel_elec_interaction = NbkernelElecType::CubicSplineTable;
+            break;
+
+        case CoulombInteractionType::Pme:
+        case CoulombInteractionType::P3mAD:
+        case CoulombInteractionType::Ewald:
+            forcerec->nbkernel_elec_interaction = NbkernelElecType::Ewald;
+            break;
 
         default:
-            gmx_fatal(FARGS, "Unsupported electrostatic interaction: %s", eel_names[ic->eeltype]);
+            gmx_fatal(FARGS,
+                      "Unsupported electrostatic interaction: %s",
+                      enumValueToString(interactionConst->eeltype));
     }
-    fr->nbkernel_elec_modifier = ic->coulomb_modifier;
+    forcerec->nbkernel_elec_modifier = interactionConst->coulomb_modifier;
 
     /* Vdw: Translate from mdp settings to kernel format */
-    switch (ic->vdwtype)
+    switch (interactionConst->vdwtype)
     {
-        case evdwCUT:
-            if (fr->bBHAM)
+        case VanDerWaalsType::Cut:
+            if (forcerec->haveBuckingham)
             {
-                fr->nbkernel_vdw_interaction = GMX_NBKERNEL_VDW_BUCKINGHAM;
+                forcerec->nbkernel_vdw_interaction = NbkernelVdwType::Buckingham;
             }
             else
             {
-                fr->nbkernel_vdw_interaction = GMX_NBKERNEL_VDW_LENNARDJONES;
+                forcerec->nbkernel_vdw_interaction = NbkernelVdwType::LennardJones;
             }
             break;
-        case evdwPME: fr->nbkernel_vdw_interaction = GMX_NBKERNEL_VDW_LJEWALD; break;
+        case VanDerWaalsType::Pme:
+            forcerec->nbkernel_vdw_interaction = NbkernelVdwType::LJEwald;
+            break;
 
-        case evdwSWITCH:
-        case evdwSHIFT:
-        case evdwUSER: fr->nbkernel_vdw_interaction = GMX_NBKERNEL_VDW_CUBICSPLINETABLE; break;
+        case VanDerWaalsType::Switch:
+        case VanDerWaalsType::Shift:
+        case VanDerWaalsType::User:
+            forcerec->nbkernel_vdw_interaction = NbkernelVdwType::CubicSplineTable;
+            break;
 
-        default: gmx_fatal(FARGS, "Unsupported vdw interaction: %s", evdw_names[ic->vdwtype]);
+        default:
+            gmx_fatal(FARGS, "Unsupported vdw interaction: %s", enumValueToString(interactionConst->vdwtype));
     }
-    fr->nbkernel_vdw_modifier = ic->vdw_modifier;
+    forcerec->nbkernel_vdw_modifier = interactionConst->vdw_modifier;
 
-    if (!gmx_within_tol(ic->reppow, 12.0, 10 * GMX_DOUBLE_EPS))
+    if (!gmx_within_tol(interactionConst->reppow, 12.0, 10 * GMX_DOUBLE_EPS))
     {
         gmx_fatal(FARGS, "Only LJ repulsion power 12 is supported");
     }
     /* Older tpr files can contain Coulomb user tables with the Verlet cutoff-scheme,
      * while mdrun does not (and never did) support this.
      */
-    if (EEL_USER(fr->ic->eeltype))
+    if (EEL_USER(forcerec->ic->eeltype))
     {
-        gmx_fatal(FARGS, "Electrostatics type %s is currently not supported", eel_names[ir->coulombtype]);
+        gmx_fatal(FARGS,
+                  "Electrostatics type %s is currently not supported",
+                  enumValueToString(inputrec.coulombtype));
     }
 
-    fr->bvdwtab  = FALSE;
-    fr->bcoultab = FALSE;
-
     /* 1-4 interaction electrostatics */
-    fr->fudgeQQ = mtop->ffparams.fudgeQQ;
+    forcerec->fudgeQQ = mtop.ffparams.fudgeQQ;
 
     // Multiple time stepping
-    fr->useMts = ir->useMts;
+    forcerec->useMts = inputrec.useMts;
 
-    if (fr->useMts)
+    if (forcerec->useMts)
     {
-        gmx::assertMtsRequirements(*ir);
+        GMX_ASSERT(gmx::checkMtsRequirements(inputrec).empty(),
+                   "All MTS requirements should be met here");
     }
 
     const bool haveDirectVirialContributionsFast =
-            fr->forceProviders->hasForceProvider() || gmx_mtop_ftype_count(mtop, F_POSRES) > 0
-            || gmx_mtop_ftype_count(mtop, F_FBPOSRES) > 0 || ir->nwall > 0 || ir->bPull || ir->bRot
-            || ir->bIMD;
-    const bool haveDirectVirialContributionsSlow = EEL_FULL(ic->eeltype) || EVDW_PME(ic->vdwtype);
-    for (int i = 0; i < (fr->useMts ? 2 : 1); i++)
+            forcerec->forceProviders->hasForceProvider() || gmx_mtop_ftype_count(mtop, F_POSRES) > 0
+            || gmx_mtop_ftype_count(mtop, F_FBPOSRES) > 0 || inputrec.nwall > 0 || inputrec.bPull
+            || inputrec.bRot || inputrec.bIMD;
+    const bool haveDirectVirialContributionsSlow =
+            EEL_FULL(interactionConst->eeltype) || EVDW_PME(interactionConst->vdwtype);
+    for (int i = 0; i < (forcerec->useMts ? 2 : 1); i++)
     {
         bool haveDirectVirialContributions =
-                (((!fr->useMts || i == 0) && haveDirectVirialContributionsFast)
-                 || ((!fr->useMts || i == 1) && haveDirectVirialContributionsSlow));
-        fr->forceHelperBuffers.emplace_back(haveDirectVirialContributions);
+                (((!forcerec->useMts || i == 0) && haveDirectVirialContributionsFast)
+                 || ((!forcerec->useMts || i == 1) && haveDirectVirialContributionsSlow));
+        forcerec->forceHelperBuffers.emplace_back(haveDirectVirialContributions);
     }
 
-    if (fr->shift_vec == nullptr)
+    if (forcerec->shift_vec.empty())
     {
-        snew(fr->shift_vec, SHIFTS);
+        forcerec->shift_vec.resize(gmx::c_numShiftVectors);
     }
 
-    if (fr->nbfp.empty())
+    if (forcerec->nbfp.empty())
     {
-        fr->ntype = mtop->ffparams.atnr;
-        fr->nbfp  = mk_nbfp(&mtop->ffparams, fr->bBHAM);
-        if (EVDW_PME(ic->vdwtype))
+        forcerec->ntype = mtop.ffparams.atnr;
+        forcerec->nbfp  = makeNonBondedParameterLists(mtop.ffparams, forcerec->haveBuckingham);
+        if (EVDW_PME(interactionConst->vdwtype))
         {
-            fr->ljpme_c6grid = make_ljpme_c6grid(&mtop->ffparams, fr);
+            forcerec->ljpme_c6grid = makeLJPmeC6GridCorrectionParameters(mtop.ffparams, *forcerec);
         }
     }
 
     /* Copy the energy group exclusions */
-    fr->egp_flags = ir->opts.egp_flags;
+    forcerec->egp_flags = inputrec.opts.egp_flags;
 
     /* Van der Waals stuff */
-    if ((ic->vdwtype != evdwCUT) && (ic->vdwtype != evdwUSER) && !fr->bBHAM)
+    if ((interactionConst->vdwtype != VanDerWaalsType::Cut)
+        && (interactionConst->vdwtype != VanDerWaalsType::User) && !forcerec->haveBuckingham)
     {
-        if (ic->rvdw_switch >= ic->rvdw)
+        if (interactionConst->rvdw_switch >= interactionConst->rvdw)
         {
-            gmx_fatal(FARGS, "rvdw_switch (%f) must be < rvdw (%f)", ic->rvdw_switch, ic->rvdw);
+            gmx_fatal(FARGS,
+                      "rvdw_switch (%f) must be < rvdw (%f)",
+                      interactionConst->rvdw_switch,
+                      interactionConst->rvdw);
         }
-        if (fp)
+        if (fplog)
         {
-            fprintf(fp, "Using %s Lennard-Jones, switch between %g and %g nm\n",
-                    (ic->eeltype == eelSWITCH) ? "switched" : "shifted", ic->rvdw_switch, ic->rvdw);
+            fprintf(fplog,
+                    "Using %s Lennard-Jones, switch between %g and %g nm\n",
+                    (interactionConst->eeltype == CoulombInteractionType::Switch) ? "switched" : "shifted",
+                    interactionConst->rvdw_switch,
+                    interactionConst->rvdw);
         }
     }
 
-    if (fr->bBHAM && EVDW_PME(ic->vdwtype))
+    if (forcerec->haveBuckingham && EVDW_PME(interactionConst->vdwtype))
     {
         gmx_fatal(FARGS, "LJ PME not supported with Buckingham");
     }
 
-    if (fr->bBHAM && (ic->vdwtype == evdwSHIFT || ic->vdwtype == evdwSWITCH))
+    if (forcerec->haveBuckingham
+        && (interactionConst->vdwtype == VanDerWaalsType::Shift
+            || interactionConst->vdwtype == VanDerWaalsType::Switch))
     {
         gmx_fatal(FARGS, "Switch/shift interaction not supported with Buckingham");
     }
 
-    if (fr->bBHAM)
+    if (forcerec->haveBuckingham)
     {
         gmx_fatal(FARGS, "The Verlet cutoff-scheme does not (yet) support Buckingham");
     }
 
-    if (ir->implicit_solvent)
+    if (inputrec.implicit_solvent)
     {
         gmx_fatal(FARGS, "Implict solvation is no longer supported.");
     }
@@ -1237,7 +952,7 @@ void init_forcerec(FILE*                            fp,
      * in that case grompp should already have checked that we do not need
      * normal tables and we only generate tables for 1-4 interactions.
      */
-    real rtab = ir->rlist + ir->tabext;
+    real rtab = inputrec.rlist + inputrec.tabext;
 
     /* We want to use unmodified tables for 1-4 coulombic
      * interactions, so we must in general have an extra set of
@@ -1245,29 +960,29 @@ void init_forcerec(FILE*                            fp,
     if (gmx_mtop_ftype_count(mtop, F_LJ14) > 0 || gmx_mtop_ftype_count(mtop, F_LJC14_Q) > 0
         || gmx_mtop_ftype_count(mtop, F_LJC_PAIRS_NB) > 0)
     {
-        fr->pairsTable = make_tables(fp, ic, tabpfn, rtab, GMX_MAKETABLES_14ONLY);
+        forcerec->pairsTable = make_tables(fplog, interactionConst, tabpfn, rtab, GMX_MAKETABLES_14ONLY);
     }
 
     /* Wall stuff */
-    fr->nwall = ir->nwall;
-    if (ir->nwall && ir->wall_type == ewtTABLE)
+    forcerec->nwall = inputrec.nwall;
+    if (inputrec.nwall && inputrec.wall_type == WallType::Table)
     {
-        make_wall_tables(fp, ir, tabfn, &mtop->groups, fr);
+        make_wall_tables(fplog, inputrec, tabfn, &mtop.groups, forcerec);
     }
 
-    fr->fcdata = std::make_unique<t_fcdata>();
+    forcerec->fcdata = std::make_unique<t_fcdata>();
 
     if (!tabbfnm.empty())
     {
-        t_fcdata& fcdata = *fr->fcdata;
+        t_fcdata& fcdata = *forcerec->fcdata;
         // Need to catch std::bad_alloc
         // TODO Don't need to catch this here, when merging with master branch
         try
         {
             // TODO move these tables into a separate struct and store reference in ListedForces
-            fcdata.bondtab  = make_bonded_tables(fp, F_TABBONDS, F_TABBONDSNC, mtop, tabbfnm, "b");
-            fcdata.angletab = make_bonded_tables(fp, F_TABANGLES, -1, mtop, tabbfnm, "a");
-            fcdata.dihtab   = make_bonded_tables(fp, F_TABDIHS, -1, mtop, tabbfnm, "d");
+            fcdata.bondtab = make_bonded_tables(fplog, F_TABBONDS, F_TABBONDSNC, mtop, tabbfnm, "b");
+            fcdata.angletab = make_bonded_tables(fplog, F_TABANGLES, -1, mtop, tabbfnm, "a");
+            fcdata.dihtab   = make_bonded_tables(fplog, F_TABDIHS, -1, mtop, tabbfnm, "d");
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
     }
@@ -1282,11 +997,11 @@ void init_forcerec(FILE*                            fp,
     }
 
     /* Initialize the thread working data for bonded interactions */
-    if (fr->useMts)
+    if (forcerec->useMts)
     {
         // Add one ListedForces object for each MTS level
         bool isFirstLevel = true;
-        for (const auto& mtsLevel : ir->mtsLevels)
+        for (const auto& mtsLevel : inputrec.mtsLevels)
         {
             ListedForces::InteractionSelection interactionSelection;
             const auto&                        forceGroups = mtsLevel.forceGroups;
@@ -1307,64 +1022,65 @@ void init_forcerec(FILE*                            fp,
                 interactionSelection.set(static_cast<int>(ListedForces::InteractionGroup::Rest));
                 isFirstLevel = false;
             }
-            fr->listedForces.emplace_back(
-                    mtop->ffparams, mtop->groups.groups[SimulationAtomGroupType::EnergyOutput].size(),
-                    gmx_omp_nthreads_get(emntBonded), interactionSelection, fp);
+            forcerec->listedForces.emplace_back(
+                    mtop.ffparams,
+                    mtop.groups.groups[SimulationAtomGroupType::EnergyOutput].size(),
+                    gmx_omp_nthreads_get(ModuleMultiThread::Bonded),
+                    interactionSelection,
+                    fplog);
         }
     }
     else
     {
         // Add one ListedForces object with all listed interactions
-        fr->listedForces.emplace_back(
-                mtop->ffparams, mtop->groups.groups[SimulationAtomGroupType::EnergyOutput].size(),
-                gmx_omp_nthreads_get(emntBonded), ListedForces::interactionSelectionAll(), fp);
+        forcerec->listedForces.emplace_back(
+                mtop.ffparams,
+                mtop.groups.groups[SimulationAtomGroupType::EnergyOutput].size(),
+                gmx_omp_nthreads_get(ModuleMultiThread::Bonded),
+                ListedForces::interactionSelectionAll(),
+                fplog);
     }
 
     // QM/MM initialization if requested
-    if (ir->bQMMM)
+    if (inputrec.bQMMM)
     {
         gmx_incons("QM/MM was requested, but is no longer available in GROMACS");
     }
 
     /* Set all the static charge group info */
-    fr->cginfo_mb = init_cginfo_mb(mtop, fr);
-    if (!DOMAINDECOMP(cr))
+    forcerec->cginfo_mb = init_cginfo_mb(mtop, forcerec);
+    if (!DOMAINDECOMP(commrec))
     {
-        fr->cginfo = cginfo_expand(mtop->molblock.size(), fr->cginfo_mb);
+        forcerec->cginfo = cginfo_expand(mtop.molblock.size(), forcerec->cginfo_mb);
     }
 
-    if (!DOMAINDECOMP(cr))
+    if (!DOMAINDECOMP(commrec))
     {
-        forcerec_set_ranges(fr, mtop->natoms, mtop->natoms, mtop->natoms);
+        forcerec_set_ranges(forcerec, mtop.natoms, mtop.natoms, mtop.natoms);
     }
 
-    fr->print_force = print_force;
+    forcerec->print_force = print_force;
 
-    fr->nthread_ewc = gmx_omp_nthreads_get(emntBonded);
-    snew(fr->ewc_t, fr->nthread_ewc);
+    forcerec->nthread_ewc = gmx_omp_nthreads_get(ModuleMultiThread::Bonded);
+    forcerec->ewc_t.resize(forcerec->nthread_ewc);
 
-    if (ir->eDispCorr != edispcNO)
+    if (inputrec.eDispCorr != DispersionCorrectionType::No)
     {
-        fr->dispersionCorrection = std::make_unique<DispersionCorrection>(
-                *mtop, *ir, fr->bBHAM, fr->ntype, fr->nbfp, *fr->ic, tabfn);
-        fr->dispersionCorrection->print(mdlog);
+        forcerec->dispersionCorrection = std::make_unique<DispersionCorrection>(
+                mtop, inputrec, forcerec->haveBuckingham, forcerec->ntype, forcerec->nbfp, *forcerec->ic, tabfn);
+        forcerec->dispersionCorrection->print(mdlog);
     }
 
-    if (fp != nullptr)
+    if (fplog != nullptr)
     {
         /* Here we switch from using mdlog, which prints the newline before
          * the paragraph, to our old fprintf logging, which prints the newline
          * after the paragraph, so we should add a newline here.
          */
-        fprintf(fp, "\n");
+        fprintf(fplog, "\n");
     }
 }
 
 t_forcerec::t_forcerec() = default;
 
-t_forcerec::~t_forcerec()
-{
-    /* Note: This code will disappear when types are converted to C++ */
-    sfree(shift_vec);
-    sfree(ewc_t);
-}
+t_forcerec::~t_forcerec() = default;
index 1a01ff141330ba927ce925138fa8a53c39e7d0fa..5d8f66d3908515ba6f86fe2598707089b0e9321c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 The GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,7 @@ struct gmx_localtop_t;
 struct gmx_mtop_t;
 struct gmx_wallcycle;
 struct interaction_const_t;
+struct gmx_ffparams_t;
 
 namespace gmx
 {
@@ -58,12 +59,21 @@ class MDLogger;
 class PhysicalNodeCommunicator;
 } // namespace gmx
 
-/*! \brief Print the contents of the forcerec to a file
+/*! \brief Create nonbonded parameter lists
  *
- * \param[in] fplog The log file to print to
- * \param[in] fr    The forcerec structure
+ * \param[in] forceFieldParams       The forcefield parameters
+ * \param[in] useBuckinghamPotential Use Buckingham potential
  */
-void pr_forcerec(FILE* fplog, t_forcerec* fr);
+std::vector<real> makeNonBondedParameterLists(const gmx_ffparams_t& forceFieldParams,
+                                              bool                  useBuckinghamPotential);
+
+/*! \brief Calculate c6 parameters for grid correction
+ *
+ * \param[in] forceFieldParams The forcefield parameters
+ * \param[in] forceRec         The forcerec
+ */
+std::vector<real> makeLJPmeC6GridCorrectionParameters(const gmx_ffparams_t& forceFieldParams,
+                                                      const t_forcerec&     forceRec);
 
 /*! \brief Set the number of charge groups and atoms.
  *
@@ -91,10 +101,10 @@ void init_interaction_const_tables(FILE* fp, interaction_const_t* ic, real rlist
  *
  * \param[in]  fplog              File for printing
  * \param[in]  mdlog              File for printing
- * \param[out] fr                 The forcerec
- * \param[in]  ir                 Inputrec structure
+ * \param[out] forcerec                 The forcerec
+ * \param[in]  inputrec                 Inputrec structure
  * \param[in]  mtop               Molecular topology
- * \param[in]  cr                 Communication structures
+ * \param[in]  commrec                 Communication structures
  * \param[in]  box                Simulation box
  * \param[in]  tabfn              Table potential file for non-bonded interactions
  * \param[in]  tabpfn             Table potential file for pair interactions
@@ -103,33 +113,14 @@ void init_interaction_const_tables(FILE* fp, interaction_const_t* ic, real rlist
  */
 void init_forcerec(FILE*                            fplog,
                    const gmx::MDLogger&             mdlog,
-                   t_forcerec*                      fr,
-                   const t_inputrec*                ir,
-                   const gmx_mtop_t*                mtop,
-                   const t_commrec*                 cr,
+                   t_forcerec*                      forcerec,
+                   const t_inputrec&                inputrec,
+                   const gmx_mtop_t&                mtop,
+                   const t_commrec*                 commrec,
                    matrix                           box,
                    const char*                      tabfn,
                    const char*                      tabpfn,
                    gmx::ArrayRef<const std::string> tabbfnm,
                    real                             print_force);
 
-/*! \brief Check whether molecules are ever distributed over PBC boundaries
- *
- * Note: This covers only the non-DD case. For DD runs, domdec.h offers an
- *       equivalent dd_bonded_molpbc(...) function.
- *
- * \param[in]  ir                 Inputrec structure
- * \param[in]  mtop               Molecular topology
- * \param[in]  mdlog              File for printing
- */
-bool areMoleculesDistributedOverPbc(const t_inputrec& ir, const gmx_mtop_t& mtop, const gmx::MDLogger& mdlog);
-
-/*! \brief Divide exclusions over threads
- *
- * Set the exclusion load for the local exclusions and possibly threads
- * \param[out] fr  The force record
- * \param[in]  top The topology
- */
-void forcerec_set_excl_load(t_forcerec* fr, const gmx_localtop_t* top);
-
 #endif
index 15bca48990a80bdf36319cc6c9cd6e035d9e323f..8a0e3416484d6ff4b8f879d8fcab8a61f8586506 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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"
 #include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/utility/enumerationhelpers.h"
 
 struct ewald_corr_thread_t
 {
-    real   Vcorr_q;
-    real   Vcorr_lj;
-    real   dvdl[efptNR];
-    tensor vir_q;
-    tensor vir_lj;
+    real                                                            Vcorr_q;
+    real                                                            Vcorr_lj;
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> dvdl;
+    tensor                                                          vir_q;
+    tensor                                                          vir_lj;
 };
 
 #endif
index ff47b98b1d5c37f9f1c27767d379f6bc10fe2953..1dcbf1a22cd591e1a4ac25f903adc50e1cd6dad0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * \author Christian Blau <blau@kth.se>
  */
 
+#include <vector>
 #include "gmxpre.h"
 
 #include "freeenergyparameters.h"
 
 #include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/enumerationhelpers.h"
 
 namespace gmx
 {
@@ -51,13 +54,14 @@ namespace gmx
 namespace
 {
 
-std::array<real, efptNR> lambdasAtState(const int stateIndex, double** const lambdaArray, const int lambdaArrayExtent)
+gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real>
+lambdasAtState(const int stateIndex, gmx::ArrayRef<const std::vector<double>> lambdaArray, const int lambdaArrayExtent)
 {
-    std::array<real, efptNR> lambda;
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> lambda;
     // set lambda from an fep state index from stateIndex, if stateIndex was defined (> -1)
     if (stateIndex >= 0 && stateIndex < lambdaArrayExtent)
     {
-        for (int i = 0; i < efptNR; i++)
+        for (int i = 0; i < static_cast<int>(FreeEnergyPerturbationCouplingType::Count); i++)
         {
             lambda[i] = lambdaArray[i][stateIndex];
         }
@@ -112,11 +116,12 @@ double currentGlobalLambda(const int64_t step,
  * \param[in] lambdaArray array of lambda values
  * \param[in] lambdaArrayExtent number of lambda values
  */
-std::array<real, efptNR> interpolatedLambdas(const double   currentGlobalLambda,
-                                             double** const lambdaArray,
-                                             const int      lambdaArrayExtent)
+gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real>
+interpolatedLambdas(const double                             currentGlobalLambda,
+                    gmx::ArrayRef<const std::vector<double>> lambdaArray,
+                    const int                                lambdaArrayExtent)
 {
-    std::array<real, efptNR> lambda;
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> lambda;
     // when there is no lambda value array, set all lambdas to steps * deltaLambdaPerStep
     if (lambdaArrayExtent <= 0)
     {
@@ -127,7 +132,7 @@ std::array<real, efptNR> interpolatedLambdas(const double   currentGlobalLambda,
     // if we run over the boundary of the lambda array, return the boundary array values
     if (currentGlobalLambda <= 0)
     {
-        for (int i = 0; i < efptNR; i++)
+        for (int i = 0; i < static_cast<int>(FreeEnergyPerturbationCouplingType::Count); i++)
         {
             lambda[i] = lambdaArray[i][0];
         }
@@ -135,7 +140,7 @@ std::array<real, efptNR> interpolatedLambdas(const double   currentGlobalLambda,
     }
     if (currentGlobalLambda >= 1)
     {
-        for (int i = 0; i < efptNR; i++)
+        for (int i = 0; i < static_cast<int>(FreeEnergyPerturbationCouplingType::Count); i++)
         {
             lambda[i] = lambdaArray[i][lambdaArrayExtent - 1];
         }
@@ -147,7 +152,7 @@ std::array<real, efptNR> interpolatedLambdas(const double   currentGlobalLambda,
     const int fepStateRight = fepStateLeft + 1;
     // interpolate between this state and the next
     const double fracBetween = currentGlobalLambda * (lambdaArrayExtent - 1) - fepStateLeft;
-    for (int i = 0; i < efptNR; i++)
+    for (int i = 0; i < static_cast<int>(FreeEnergyPerturbationCouplingType::Count); i++)
     {
         lambda[i] = lambdaArray[i][fepStateLeft]
                     + fracBetween * (lambdaArray[i][fepStateRight] - lambdaArray[i][fepStateLeft]);
@@ -157,7 +162,8 @@ std::array<real, efptNR> interpolatedLambdas(const double   currentGlobalLambda,
 
 } // namespace
 
-std::array<real, efptNR> currentLambdas(const int64_t step, const t_lambda& fepvals, const int currentLambdaState)
+gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real>
+currentLambdas(const int64_t step, const t_lambda& fepvals, const int currentLambdaState)
 {
     if (fepvals.delta_lambda == 0)
     {
@@ -171,12 +177,12 @@ std::array<real, efptNR> currentLambdas(const int64_t step, const t_lambda& fepv
             return lambdasAtState(fepvals.init_fep_state, fepvals.all_lambda, fepvals.n_lambda);
         }
 
-        std::array<real, efptNR> lambdas;
+        gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> lambdas;
         std::fill(std::begin(lambdas), std::end(lambdas), fepvals.init_lambda);
         return lambdas;
     }
-    const double globalLambda = currentGlobalLambda(step, fepvals.delta_lambda, fepvals.init_fep_state,
-                                                    fepvals.init_lambda, fepvals.n_lambda);
+    const double globalLambda = currentGlobalLambda(
+            step, fepvals.delta_lambda, fepvals.init_fep_state, fepvals.init_lambda, fepvals.n_lambda);
     return interpolatedLambdas(globalLambda, fepvals.all_lambda, fepvals.n_lambda);
 }
 
index 0814bc6c8855c90d9facc981935260e6a53430de..aaa8307166c895f08e44a47ccf64d0bcf9a44482 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <array>
 
 #include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/real.h"
 
 struct t_lambda;
@@ -60,7 +61,9 @@ namespace gmx
  * \param[in] currentLambdaState the lambda state to use to set the lambdas, -1 if not set
  * \returns the current lambda-value array
  */
-std::array<real, efptNR> currentLambdas(int64_t step, const t_lambda& fepvals, int currentLambdaState);
+gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> currentLambdas(int64_t         step,
+                                                                               const t_lambda& fepvals,
+                                                                               int currentLambdaState);
 
 } // namespace gmx
 
index aa3327c8221a9703360160b55b42cdc1731ba4c4..6d94b641cf5295cb3df9f24051e7f7161370456c 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gmxlib/network.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/gmxomp.h"
@@ -60,31 +61,43 @@ typedef struct
     int gnth;     /**< Global num. of threads per PP or PP+PME process/tMPI thread. */
     int gnth_pme; /**< Global num. of threads per PME only process/tMPI thread. */
 
-    int      nth[emntNR]; /**< Number of threads for each module, indexed with module_nth_t */
-    gmx_bool initialized; /**< TRUE if the module as been initialized. */
+    gmx::EnumerationArray<ModuleMultiThread, int> nth; /**< Number of threads for each module, indexed with module_nth_t */
+    bool initialized; /**< TRUE if the module as been initialized. */
 } omp_module_nthreads_t;
 
 /** Names of environment variables to set the per module number of threads.
  *
  *  Indexed with the values of module_nth_t.
  * */
-static const char* modth_env_var[emntNR] = { "GMX_DEFAULT_NUM_THREADS should never be set",
-                                             "GMX_DOMDEC_NUM_THREADS",
-                                             "GMX_PAIRSEARCH_NUM_THREADS",
-                                             "GMX_NONBONDED_NUM_THREADS",
-                                             "GMX_LISTED_FORCES_NUM_THREADS",
-                                             "GMX_PME_NUM_THREADS",
-                                             "GMX_UPDATE_NUM_THREADS",
-                                             "GMX_VSITE_NUM_THREADS",
-                                             "GMX_LINCS_NUM_THREADS",
-                                             "GMX_SETTLE_NUM_THREADS" };
+static const char* enumValueToEnvVariableString(ModuleMultiThread enumValue)
+{
+    constexpr gmx::EnumerationArray<ModuleMultiThread, const char*> moduleMultiThreadEnvVariableNames = {
+        "GMX_DEFAULT_NUM_THREADS should never be set",
+        "GMX_DOMDEC_NUM_THREADS",
+        "GMX_PAIRSEARCH_NUM_THREADS",
+        "GMX_NONBONDED_NUM_THREADS",
+        "GMX_LISTED_FORCES_NUM_THREADS",
+        "GMX_PME_NUM_THREADS",
+        "GMX_UPDATE_NUM_THREADS",
+        "GMX_VSITE_NUM_THREADS",
+        "GMX_LINCS_NUM_THREADS",
+        "GMX_SETTLE_NUM_THREADS"
+    };
+    return moduleMultiThreadEnvVariableNames[enumValue];
+}
 
 /** Names of the modules. */
-static const char* mod_name[emntNR] = { "default",     "domain decomposition",
-                                        "pair search", "non-bonded",
-                                        "bonded",      "PME",
-                                        "update",      "LINCS",
-                                        "SETTLE" };
+static const char* enumValueToString(ModuleMultiThread enumValue)
+{
+    constexpr gmx::EnumerationArray<ModuleMultiThread, const char*> moduleMultiThreadNames = {
+        "default",     "domain decomposition",
+        "pair search", "non-bonded",
+        "bonded",      "PME",
+        "update",      "LINCS",
+        "SETTLE"
+    };
+    return moduleMultiThreadNames[enumValue];
+}
 
 /** Number of threads for each algorithmic module.
  *
@@ -94,6 +107,7 @@ static const char* mod_name[emntNR] = { "default",     "domain decomposition",
  *  All fields are initialized to 0 which should result in errors if
  *  the init call is omitted.
  * */
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static omp_module_nthreads_t modth = { 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, FALSE };
 
 
@@ -106,7 +120,7 @@ static omp_module_nthreads_t modth = { 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, FALS
  *  GMX_*_NUM_THERADS env var is set, case in which its value overrides
  *  the default.
  */
-static void pick_module_nthreads(const gmx::MDLogger& mdlog, int m, gmx_bool bSepPME)
+static void pick_module_nthreads(const gmx::MDLogger& mdlog, ModuleMultiThread m, gmx_bool bSepPME)
 {
     char* env;
     int   nth;
@@ -115,19 +129,21 @@ static void pick_module_nthreads(const gmx::MDLogger& mdlog, int m, gmx_bool bSe
 
     /* The default should never be set through a GMX_*_NUM_THREADS env var
      * as it's always equal with gnth. */
-    if (m == emntDefault)
+    if (m == ModuleMultiThread::Default)
     {
         return;
     }
 
     /* check the environment variable */
-    if ((env = getenv(modth_env_var[m])) != nullptr)
+    if ((env = getenv(enumValueToEnvVariableString(m))) != nullptr)
     {
         sscanf(env, "%d", &nth);
 
         if (!bOMP)
         {
-            gmx_warning("%s=%d is set, but %s is compiled without OpenMP!", modth_env_var[m], nth,
+            gmx_warning("%s=%d is set, but %s is compiled without OpenMP!",
+                        enumValueToEnvVariableString(m),
+                        nth,
                         gmx::getProgramContext().displayName());
         }
 
@@ -138,23 +154,26 @@ static void pick_module_nthreads(const gmx::MDLogger& mdlog, int m, gmx_bool bSe
             gmx_warning(
                     "%s=%d is set, the default number of threads also "
                     "needs to be set with OMP_NUM_THREADS!",
-                    modth_env_var[m], nth);
+                    enumValueToEnvVariableString(m),
+                    nth);
         }
 
         /* only babble if we are really overriding with a different value */
-        if ((bSepPME && m == emntPME && nth != modth.gnth_pme) || (nth != modth.gnth))
+        if ((bSepPME && m == ModuleMultiThread::Pme && nth != modth.gnth_pme) || (nth != modth.gnth))
         {
             GMX_LOG(mdlog.warning)
                     .asParagraph()
                     .appendTextFormatted("%s=%d set, overriding the default number of %s threads",
-                                         modth_env_var[m], nth, mod_name[m]);
+                                         enumValueToString(m),
+                                         nth,
+                                         enumValueToEnvVariableString(m));
         }
     }
     else
     {
         /* pick the global PME node nthreads if we are setting the number
          * of threads in separate PME nodes  */
-        nth = (bSepPME && m == emntPME) ? modth.gnth_pme : modth.gnth;
+        nth = (bSepPME && m == ModuleMultiThread::Pme) ? modth.gnth_pme : modth.gnth;
     }
 
     gmx_omp_nthreads_set(m, nth);
@@ -184,7 +203,8 @@ void gmx_omp_nthreads_read_env(const gmx::MDLogger& mdlog, int* nthreads_omp)
                       "Environment variable OMP_NUM_THREADS (%d) and the number of threads "
                       "requested on the command line (%d) have different values. Either omit one, "
                       "or set them both to the same value.",
-                      nt_omp, *nthreads_omp);
+                      nt_omp,
+                      *nthreads_omp);
         }
 
         /* Setting the number of OpenMP threads. */
@@ -329,16 +349,16 @@ static void manage_number_of_openmp_threads(const gmx::MDLogger& mdlog,
     }
 
     /* now set the per-module values */
-    modth.nth[emntDefault] = modth.gnth;
-    pick_module_nthreads(mdlog, emntDomdec, bSepPME);
-    pick_module_nthreads(mdlog, emntPairsearch, bSepPME);
-    pick_module_nthreads(mdlog, emntNonbonded, bSepPME);
-    pick_module_nthreads(mdlog, emntBonded, bSepPME);
-    pick_module_nthreads(mdlog, emntPME, bSepPME);
-    pick_module_nthreads(mdlog, emntUpdate, bSepPME);
-    pick_module_nthreads(mdlog, emntVSITE, bSepPME);
-    pick_module_nthreads(mdlog, emntLINCS, bSepPME);
-    pick_module_nthreads(mdlog, emntSETTLE, bSepPME);
+    modth.nth[ModuleMultiThread::Default] = modth.gnth;
+    pick_module_nthreads(mdlog, ModuleMultiThread::Domdec, bSepPME);
+    pick_module_nthreads(mdlog, ModuleMultiThread::Pairsearch, bSepPME);
+    pick_module_nthreads(mdlog, ModuleMultiThread::Nonbonded, bSepPME);
+    pick_module_nthreads(mdlog, ModuleMultiThread::Bonded, bSepPME);
+    pick_module_nthreads(mdlog, ModuleMultiThread::Pme, bSepPME);
+    pick_module_nthreads(mdlog, ModuleMultiThread::Update, bSepPME);
+    pick_module_nthreads(mdlog, ModuleMultiThread::VirtualSite, bSepPME);
+    pick_module_nthreads(mdlog, ModuleMultiThread::Lincs, bSepPME);
+    pick_module_nthreads(mdlog, ModuleMultiThread::Settle, bSepPME);
 
     /* set the number of threads globally */
     if (bOMP)
@@ -405,7 +425,9 @@ static void reportOpenmpSettings(const gmx::MDLogger& mdlog, const t_commrec* cr
     if (nth_max == nth_min)
     {
         GMX_LOG(mdlog.warning)
-                .appendTextFormatted("Using %d OpenMP thread%s %s", nth_min, nth_min > 1 ? "s" : "",
+                .appendTextFormatted("Using %d OpenMP thread%s %s",
+                                     nth_min,
+                                     nth_min > 1 ? "s" : "",
                                      cr->nnodes > 1 ? mpi_str : "");
     }
     else
@@ -418,14 +440,16 @@ static void reportOpenmpSettings(const gmx::MDLogger& mdlog, const t_commrec* cr
         if (nth_pme_max == nth_pme_min)
         {
             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 : "");
+                    .appendTextFormatted("Using %d OpenMP thread%s %s for PME",
+                                         nth_pme_min,
+                                         nth_pme_min > 1 ? "s" : "",
+                                         cr->nnodes > 1 ? mpi_str : "");
         }
         else
         {
             GMX_LOG(mdlog.warning)
-                    .appendTextFormatted("Using %d - %d OpenMP threads %s for PME", nth_pme_min,
-                                         nth_pme_max, mpi_str);
+                    .appendTextFormatted(
+                            "Using %d - %d OpenMP threads %s for PME", nth_pme_min, nth_pme_max, mpi_str);
         }
     }
     GMX_LOG(mdlog.warning);
@@ -445,8 +469,15 @@ void gmx_omp_nthreads_init(const gmx::MDLogger& mdlog,
 
     bSepPME = (thisRankHasDuty(cr, DUTY_PP) != thisRankHasDuty(cr, DUTY_PME));
 
-    manage_number_of_openmp_threads(mdlog, cr, bOMP, nthreads_hw_avail, omp_nthreads_req,
-                                    omp_nthreads_pme_req, bThisNodePMEOnly, numRanksOnThisNode, bSepPME);
+    manage_number_of_openmp_threads(mdlog,
+                                    cr,
+                                    bOMP,
+                                    nthreads_hw_avail,
+                                    omp_nthreads_req,
+                                    omp_nthreads_pme_req,
+                                    bThisNodePMEOnly,
+                                    numRanksOnThisNode,
+                                    bSepPME);
 #if GMX_THREAD_MPI
     /* Non-master threads have to wait for the OpenMP management to be
      * done, so that code elsewhere that uses OpenMP can be certain
@@ -460,9 +491,9 @@ void gmx_omp_nthreads_init(const gmx::MDLogger& mdlog,
     reportOpenmpSettings(mdlog, cr, bOMP, bSepPME);
 }
 
-int gmx_omp_nthreads_get(int mod)
+int gmx_omp_nthreads_get(ModuleMultiThread mod)
 {
-    if (mod < 0 || mod >= emntNR)
+    if (mod < ModuleMultiThread::Default || mod >= ModuleMultiThread::Count)
     {
         /* invalid module queried */
         return -1;
@@ -473,11 +504,12 @@ int gmx_omp_nthreads_get(int mod)
     }
 }
 
-void gmx_omp_nthreads_set(int mod, int nthreads)
+void gmx_omp_nthreads_set(ModuleMultiThread mod, int nthreads)
 {
     /* Catch an attempt to set the number of threads on an invalid
      * OpenMP module. */
-    GMX_RELEASE_ASSERT(mod >= 0 && mod < emntNR, "Trying to set nthreads on invalid OpenMP module");
+    GMX_RELEASE_ASSERT(mod >= ModuleMultiThread::Default && mod < ModuleMultiThread::Count,
+                       "Trying to set nthreads on invalid OpenMP module");
 
     modth.nth[mod] = nthreads;
 }
index 11b77a681bf1600f099d102ec6c7fc6b33033832..1b87c113b65e72d4956288807bed00c039074895 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,22 +49,22 @@ class MDLogger;
 }
 
 /** Enum values corresponding to multithreaded algorithmic modules. */
-typedef enum module_nth
+enum class ModuleMultiThread : int
 {
     /* Default is meant to be used in OMP regions outside the named
      * algorithmic modules listed below. */
-    emntDefault,
-    emntDomdec,
-    emntPairsearch,
-    emntNonbonded,
-    emntBonded,
-    emntPME,
-    emntUpdate,
-    emntVSITE,
-    emntLINCS,
-    emntSETTLE,
-    emntNR
-} module_nth_t;
+    Default,
+    Domdec,
+    Pairsearch,
+    Nonbonded,
+    Bonded,
+    Pme,
+    Update,
+    VirtualSite,
+    Lincs,
+    Settle,
+    Count
+};
 
 /*! \brief
  * Initializes the per-module thread count.
@@ -82,7 +82,7 @@ void gmx_omp_nthreads_init(const gmx::MDLogger& fplog,
 
 /*! \brief
  * Returns the number of threads to be used in the given module \p mod. */
-int gmx_omp_nthreads_get(int mod);
+int gmx_omp_nthreads_get(ModuleMultiThread mod);
 
 /*! \brief
  * Returns the number of threads to be used in the given module \p mod for simple rvec operations.
@@ -92,7 +92,7 @@ int gmx_omp_nthreads_get(int mod);
  * the reduction in computional cost due to parallelization. This routine
  * returns 1 when the overhead is expected to be higher than the gain.
  */
-static inline int gmx_omp_nthreads_get_simple_rvec_task(int mod, int nrvec)
+static inline int gmx_omp_nthreads_get_simple_rvec_task(ModuleMultiThread mod, int nrvec)
 {
     /* There can be a relatively large overhead to an OpenMP parallel for loop.
      * This overhead increases, slowly, with the numbe of threads used.
@@ -121,7 +121,7 @@ static inline int gmx_omp_nthreads_get_simple_rvec_task(int mod, int nrvec)
 /*! \brief Sets the number of threads to be used in module.
  *
  * Intended for use in testing. */
-void gmx_omp_nthreads_set(int mod, int nthreads);
+void gmx_omp_nthreads_set(ModuleMultiThread mod, int nthreads);
 
 /*! \brief
  * Read the OMP_NUM_THREADS env. var. and check against the value set on the
index 8aad5efaf35fe4eb82764767e2272afc6305af4e..e015d7ef5e03c70b4782ee74f7e8b13e622bbaea 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_MDLIB_GPUFORCEREDUCTION_H
 #define GMX_MDLIB_GPUFORCEREDUCTION_H
 
+#include <memory>
+
+#include "config.h"
+
 #include "gromacs/gpu_utils/devicebuffer_datatype.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/timing/wallcycle.h"
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/fixedcapacityvector.h"
 
 class GpuEventSynchronizer;
@@ -57,6 +60,8 @@ class DeviceContext;
 namespace gmx
 {
 
+#define HAVE_GPU_FORCE_REDUCTION (GMX_GPU_CUDA)
+
 /*! \internal
  * \brief Manages the force reduction directly in GPU memory
  *
@@ -85,13 +90,13 @@ public:
      *
      * \param [in] forcePtr  Pointer to force to be reduced
      */
-    void registerNbnxmForce(void* forcePtr);
+    void registerNbnxmForce(DeviceBuffer<RVec> forcePtr);
 
     /*! \brief Register a rvec-format force to be reduced
      *
      * \param [in] forcePtr  Pointer to force to be reduced
      */
-    void registerRvecForce(void* forcePtr);
+    void registerRvecForce(DeviceBuffer<RVec> forcePtr);
 
     /*! \brief Add a dependency for this force reduction
      *
@@ -120,7 +125,7 @@ public:
 
 private:
     class Impl;
-    gmx::PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 69876c7d15711ad318c4c193cfd09d25e66639c1..fb58c5c9437ef48cbadfb5ac4c9592d9b4f006ea 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +34,7 @@
  */
 /*! \internal \file
  *
- * \brief May be used to implement force reduction interfaces for non-GPU builds.
+ * \brief Implements backend-agnostic GPU Force Reduction functions
  *
  * \author Alan Gray <alang@nvidia.com>
  *
 
 #include "gmxpre.h"
 
-#include "config.h"
+#include "gpuforcereduction_impl.h"
 
-#include "gpuforcereduction.h"
-
-#if !GMX_GPU_CUDA
+#include "gromacs/gpu_utils/device_stream.h"
+#include "gromacs/gpu_utils/devicebuffer.h"
+#if GMX_GPU_CUDA
+#    include "gromacs/gpu_utils/gpueventsynchronizer.cuh"
+#elif GMX_GPU_SYCL
+#    include "gromacs/gpu_utils/gpueventsynchronizer_sycl.h"
+#endif
+#include "gromacs/mdlib/gpuforcereduction_impl_internal.h"
+#include "gromacs/utility/gmxassert.h"
 
 namespace gmx
 {
 
-class GpuForceReduction::Impl
+GpuForceReduction::Impl::Impl(const DeviceContext& deviceContext,
+                              const DeviceStream&  deviceStream,
+                              gmx_wallcycle*       wcycle) :
+    baseForce_(),
+    deviceContext_(deviceContext),
+    deviceStream_(deviceStream),
+    nbnxmForceToAdd_(),
+    rvecForceToAdd_(),
+    wcycle_(wcycle)
+{
+}
+
+void GpuForceReduction::Impl::reinit(DeviceBuffer<Float3>  baseForcePtr,
+                                     const int             numAtoms,
+                                     ArrayRef<const int>   cell,
+                                     const int             atomStart,
+                                     const bool            accumulate,
+                                     GpuEventSynchronizer* completionMarker)
+{
+    GMX_ASSERT((baseForcePtr != nullptr), "Input base force for reduction has no data");
+    baseForce_        = baseForcePtr;
+    numAtoms_         = numAtoms;
+    atomStart_        = atomStart;
+    accumulate_       = static_cast<int>(accumulate);
+    completionMarker_ = completionMarker;
+    cellInfo_.cell    = cell.data();
+
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    reallocateDeviceBuffer(
+            &cellInfo_.d_cell, numAtoms_, &cellInfo_.cellSize, &cellInfo_.cellSizeAlloc, deviceContext_);
+    copyToDeviceBuffer(&cellInfo_.d_cell,
+                       &(cellInfo_.cell[atomStart]),
+                       0,
+                       numAtoms_,
+                       deviceStream_,
+                       GpuApiCallBehavior::Async,
+                       nullptr);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
+
+    dependencyList_.clear();
+};
+
+void GpuForceReduction::Impl::registerNbnxmForce(DeviceBuffer<RVec> forcePtr)
 {
+    GMX_ASSERT(forcePtr, "Input force for reduction has no data");
+    nbnxmForceToAdd_ = forcePtr;
 };
 
-GpuForceReduction::GpuForceReduction(const DeviceContext& /* deviceContext */,
-                                     const DeviceStream& /* deviceStream */,
-                                     gmx_wallcycle* /*wcycle*/) :
-    impl_(nullptr)
+void GpuForceReduction::Impl::registerRvecForce(DeviceBuffer<RVec> forcePtr)
+{
+    GMX_ASSERT(forcePtr, "Input force for reduction has no data");
+    rvecForceToAdd_ = forcePtr;
+};
+
+void GpuForceReduction::Impl::addDependency(GpuEventSynchronizer* const dependency)
+{
+    dependencyList_.push_back(dependency);
+}
+
+void GpuForceReduction::Impl::execute()
 {
-    GMX_ASSERT(false, "A CPU stub has been called instead of the correct implementation.");
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchGpuNBFBufOps);
+
+    if (numAtoms_ == 0)
+    {
+        return;
+    }
+
+    GMX_ASSERT(nbnxmForceToAdd_, "Nbnxm force for reduction has no data");
+
+    // Enqueue wait on all dependencies passed
+    for (auto* synchronizer : dependencyList_)
+    {
+        synchronizer->enqueueWaitEvent(deviceStream_);
+    }
+
+    const bool addRvecForce = static_cast<bool>(rvecForceToAdd_); // True iff initialized
+
+    launchForceReductionKernel(numAtoms_,
+                               atomStart_,
+                               addRvecForce,
+                               accumulate_,
+                               nbnxmForceToAdd_,
+                               rvecForceToAdd_,
+                               baseForce_,
+                               cellInfo_.d_cell,
+                               deviceStream_);
+
+    // Mark that kernel has been launched
+    if (completionMarker_ != nullptr)
+    {
+        completionMarker_->markEvent(deviceStream_);
+    }
+
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchGpuNBFBufOps);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
-// NOLINTNEXTLINE readability-convert-member-functions-to-static
-void GpuForceReduction::reinit(DeviceBuffer<RVec> /*baseForcePtr*/,
-                               const int /*numAtoms*/,
-                               ArrayRef<const int> /*cell*/,
-                               const int /*atomStart*/,
-                               const bool /*accumulate*/,
-                               GpuEventSynchronizer* /*completionMarker*/)
+GpuForceReduction::Impl::~Impl() = default;
+
+GpuForceReduction::GpuForceReduction(const DeviceContext& deviceContext,
+                                     const DeviceStream&  deviceStream,
+                                     gmx_wallcycle*       wcycle) :
+    impl_(new Impl(deviceContext, deviceStream, wcycle))
 {
-    GMX_ASSERT(false, "A CPU stub has been called instead of the correct implementation.");
 }
 
-// NOLINTNEXTLINE readability-convert-member-functions-to-static
-void GpuForceReduction::registerNbnxmForce(void* /* forcePtr */)
+void GpuForceReduction::registerNbnxmForce(DeviceBuffer<RVec> forcePtr)
 {
-    GMX_ASSERT(false, "A CPU stub has been called instead of the correct implementation.");
+    impl_->registerNbnxmForce(forcePtr);
 }
 
-// NOLINTNEXTLINE readability-convert-member-functions-to-static
-void GpuForceReduction::registerRvecForce(void* /* forcePtr */)
+void GpuForceReduction::registerRvecForce(DeviceBuffer<RVec> forcePtr)
 {
-    GMX_ASSERT(false, "A CPU stub has been called instead of the correct implementation.");
+    impl_->registerRvecForce(forcePtr);
 }
 
-// NOLINTNEXTLINE readability-convert-member-functions-to-static
-void GpuForceReduction::addDependency(GpuEventSynchronizer* const /* dependency */)
+void GpuForceReduction::addDependency(GpuEventSynchronizer* const dependency)
 {
-    GMX_ASSERT(false, "A CPU stub has been called instead of the correct implementation.");
+    impl_->addDependency(dependency);
 }
 
-// NOLINTNEXTLINE readability-convert-member-functions-to-static
+void GpuForceReduction::reinit(DeviceBuffer<RVec>    baseForcePtr,
+                               const int             numAtoms,
+                               ArrayRef<const int>   cell,
+                               const int             atomStart,
+                               const bool            accumulate,
+                               GpuEventSynchronizer* completionMarker)
+{
+    impl_->reinit(baseForcePtr, numAtoms, cell, atomStart, accumulate, completionMarker);
+}
 void GpuForceReduction::execute()
 {
-    GMX_ASSERT(false, "A CPU stub has been called instead of the correct implementation.");
+    impl_->execute();
 }
 
 GpuForceReduction::~GpuForceReduction() = default;
 
 } // namespace gmx
-
-#endif
diff --git a/src/gromacs/mdlib/gpuforcereduction_impl.cu b/src/gromacs/mdlib/gpuforcereduction_impl.cu
deleted file mode 100644 (file)
index afe7b03..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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 GPU Force Reduction using CUDA
- *
- * \author Alan Gray <alang@nvidia.com>
- *
- * \ingroup module_mdlib
- */
-
-#include "gmxpre.h"
-
-#include "gpuforcereduction_impl.cuh"
-
-#include <stdio.h>
-
-#include "gromacs/gpu_utils/cudautils.cuh"
-#include "gromacs/gpu_utils/device_context.h"
-#include "gromacs/gpu_utils/devicebuffer.h"
-#include "gromacs/gpu_utils/gpu_utils.h"
-#include "gromacs/gpu_utils/gpueventsynchronizer.cuh"
-#include "gromacs/gpu_utils/typecasts.cuh"
-#include "gromacs/gpu_utils/vectype_ops.cuh"
-#include "gromacs/utility/gmxassert.h"
-
-#include "gpuforcereduction.h"
-
-namespace gmx
-{
-
-constexpr static int c_threadsPerBlock = 128;
-
-typedef struct rvecDeviceForceData rvecDeviceForceData_t;
-
-
-template<bool addRvecForce, bool accumulateForce>
-static __global__ void reduceKernel(const float3* __restrict__ gm_nbnxmForce,
-                                    const float3* __restrict__ rvecForceToAdd,
-                                    float3*    gm_fTotal,
-                                    const int* gm_cell,
-                                    const int  numAtoms)
-{
-
-    // map particle-level parallelism to 1D CUDA thread and block index
-    const int threadIndex = blockIdx.x * blockDim.x + threadIdx.x;
-
-    // perform addition for each particle
-    if (threadIndex < numAtoms)
-    {
-
-        float3* gm_fDest = &gm_fTotal[threadIndex];
-        float3  temp;
-
-        // Accumulate or set nbnxm force
-        if (accumulateForce)
-        {
-            temp = *gm_fDest;
-            temp += gm_nbnxmForce[gm_cell[threadIndex]];
-        }
-        else
-        {
-            temp = gm_nbnxmForce[gm_cell[threadIndex]];
-        }
-
-        if (addRvecForce)
-        {
-            temp += rvecForceToAdd[threadIndex];
-        }
-
-        *gm_fDest = temp;
-    }
-    return;
-}
-
-GpuForceReduction::Impl::Impl(const DeviceContext& deviceContext,
-                              const DeviceStream&  deviceStream,
-                              gmx_wallcycle*       wcycle) :
-    deviceContext_(deviceContext),
-    deviceStream_(deviceStream),
-    wcycle_(wcycle){};
-
-void GpuForceReduction::Impl::reinit(float3*               baseForcePtr,
-                                     const int             numAtoms,
-                                     ArrayRef<const int>   cell,
-                                     const int             atomStart,
-                                     const bool            accumulate,
-                                     GpuEventSynchronizer* completionMarker)
-{
-    GMX_ASSERT((baseForcePtr != nullptr), "Input base force for reduction has no data");
-    baseForce_        = &(baseForcePtr[atomStart]);
-    numAtoms_         = numAtoms;
-    atomStart_        = atomStart;
-    accumulate_       = accumulate;
-    completionMarker_ = completionMarker;
-    cellInfo_.cell    = cell.data();
-
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    reallocateDeviceBuffer(&cellInfo_.d_cell, numAtoms_, &cellInfo_.cellSize,
-                           &cellInfo_.cellSizeAlloc, deviceContext_);
-    copyToDeviceBuffer(&cellInfo_.d_cell, &(cellInfo_.cell[atomStart]), 0, numAtoms_, deviceStream_,
-                       GpuApiCallBehavior::Async, nullptr);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
-
-    dependencyList_.clear();
-};
-
-void GpuForceReduction::Impl::registerNbnxmForce(DeviceBuffer<RVec> forcePtr)
-{
-    GMX_ASSERT((forcePtr != nullptr), "Input force for reduction has no data");
-    nbnxmForceToAdd_ = forcePtr;
-};
-
-void GpuForceReduction::Impl::registerRvecForce(DeviceBuffer<RVec> forcePtr)
-{
-    GMX_ASSERT((forcePtr != nullptr), "Input force for reduction has no data");
-    rvecForceToAdd_ = forcePtr;
-};
-
-void GpuForceReduction::Impl::addDependency(GpuEventSynchronizer* const dependency)
-{
-    dependencyList_.push_back(dependency);
-}
-
-void GpuForceReduction::Impl::execute()
-{
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_GPU_NB_F_BUF_OPS);
-
-    if (numAtoms_ == 0)
-    {
-        return;
-    }
-
-    GMX_ASSERT((nbnxmForceToAdd_ != nullptr), "Nbnxm force for reduction has no data");
-
-    // Enqueue wait on all dependencies passed
-    for (auto const synchronizer : dependencyList_)
-    {
-        synchronizer->enqueueWaitEvent(deviceStream_);
-    }
-
-    float3* d_nbnxmForce     = asFloat3(nbnxmForceToAdd_);
-    float3* d_rvecForceToAdd = &(asFloat3(rvecForceToAdd_)[atomStart_]);
-
-    // Configure and launch kernel
-    KernelLaunchConfig config;
-    config.blockSize[0]     = c_threadsPerBlock;
-    config.blockSize[1]     = 1;
-    config.blockSize[2]     = 1;
-    config.gridSize[0]      = ((numAtoms_ + 1) + c_threadsPerBlock - 1) / c_threadsPerBlock;
-    config.gridSize[1]      = 1;
-    config.gridSize[2]      = 1;
-    config.sharedMemorySize = 0;
-
-    auto kernelFn = (rvecForceToAdd_ != nullptr)
-                            ? (accumulate_ ? reduceKernel<true, true> : reduceKernel<true, false>)
-                            : (accumulate_ ? reduceKernel<false, true> : reduceKernel<false, false>);
-
-    const auto kernelArgs = prepareGpuKernelArguments(kernelFn, config, &d_nbnxmForce, &d_rvecForceToAdd,
-                                                      &baseForce_, &cellInfo_.d_cell, &numAtoms_);
-
-    launchGpuKernel(kernelFn, config, deviceStream_, nullptr, "Force Reduction", kernelArgs);
-
-    // Mark that kernel has been launched
-    if (completionMarker_ != nullptr)
-    {
-        completionMarker_->markEvent(deviceStream_);
-    }
-
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_GPU_NB_F_BUF_OPS);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
-}
-
-GpuForceReduction::Impl::~Impl(){};
-
-GpuForceReduction::GpuForceReduction(const DeviceContext& deviceContext,
-                                     const DeviceStream&  deviceStream,
-                                     gmx_wallcycle*       wcycle) :
-    impl_(new Impl(deviceContext, deviceStream, wcycle))
-{
-}
-
-void GpuForceReduction::registerNbnxmForce(void* forcePtr)
-{
-    impl_->registerNbnxmForce(reinterpret_cast<DeviceBuffer<RVec>>(forcePtr));
-}
-
-void GpuForceReduction::registerRvecForce(void* forcePtr)
-{
-    impl_->registerRvecForce(reinterpret_cast<DeviceBuffer<RVec>>(forcePtr));
-}
-
-void GpuForceReduction::addDependency(GpuEventSynchronizer* const dependency)
-{
-    impl_->addDependency(dependency);
-}
-
-void GpuForceReduction::reinit(DeviceBuffer<RVec>    baseForcePtr,
-                               const int             numAtoms,
-                               ArrayRef<const int>   cell,
-                               const int             atomStart,
-                               const bool            accumulate,
-                               GpuEventSynchronizer* completionMarker)
-{
-    impl_->reinit(asFloat3(baseForcePtr), numAtoms, cell, atomStart, accumulate, completionMarker);
-}
-void GpuForceReduction::execute()
-{
-    impl_->execute();
-}
-
-GpuForceReduction::~GpuForceReduction() = default;
-
-} // namespace gmx
similarity index 88%
rename from src/gromacs/mdlib/gpuforcereduction_impl.cuh
rename to src/gromacs/mdlib/gpuforcereduction_impl.h
index 8434a04c712f20ee6181bbc3a8e75ea9e4c053c7..316f4cca317f2d1da0a39a3224b3546767e593f3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gpu_utils/device_stream.h"
 #include "gromacs/gpu_utils/devicebuffer_datatype.h"
+#include "gromacs/gpu_utils/gputraits.h"
 #include "gromacs/math/vectypes.h"
 
 #include "gpuforcereduction.h"
 namespace gmx
 {
 
-//! structure to hold cell information for any nbat-format forces
+//! \internal
+//! \brief structure to hold cell information for any nbat-format forces
 struct cellInfo
 {
     //! cell index mapping for any nbat-format forces
     const int* cell = nullptr;
     //! device copy of cell index mapping for any nbat-format forces
-    int* d_cell = nullptr;
+    DeviceBuffer<int> d_cell;
     //! number of atoms in cell array
     int cellSize = -1;
     //! number of atoms allocated in cell array
@@ -75,20 +77,20 @@ public:
      * \param [in] deviceContext GPU device context
      * \param [in] wcycle        The wallclock counter
      */
-    Impl(const DeviceContext& deviceContext, const DeviceStream& deviceStreami, gmx_wallcycle* wcycle);
+    Impl(const DeviceContext& deviceContext, const DeviceStream& deviceStream, gmx_wallcycle* wcycle);
     ~Impl();
 
     /*! \brief Register a nbnxm-format force to be reduced
      *
      * \param [in] forcePtr  Pointer to force to be reduced
      */
-    void registerNbnxmForce(DeviceBuffer<RVec> forcePtr);
+    void registerNbnxmForce(DeviceBuffer<Float3> forcePtr);
 
     /*! \brief Register a rvec-format force to be reduced
      *
      * \param [in] forcePtr  Pointer to force to be reduced
      */
-    void registerRvecForce(DeviceBuffer<RVec> forcePtr);
+    void registerRvecForce(DeviceBuffer<Float3> forcePtr);
 
     /*! \brief Add a dependency for this force reduction
      *
@@ -105,7 +107,7 @@ public:
      * \param [in] accumulate       Whether reduction should be accumulated
      * \param [in] completionMarker Event to be marked when launch of reduction is complete
      */
-    void reinit(float3*               baseForcePtr,
+    void reinit(DeviceBuffer<Float3>  baseForcePtr,
                 const int             numAtoms,
                 ArrayRef<const int>   cell,
                 const int             atomStart,
@@ -117,7 +119,7 @@ public:
 
 private:
     //! force to be used as a base for this reduction
-    float3* baseForce_ = nullptr;
+    DeviceBuffer<Float3> baseForce_;
     //! starting atom
     int atomStart_ = 0;
     //! number of atoms
@@ -133,10 +135,10 @@ private:
     //! stream to be used for this reduction
     const DeviceStream& deviceStream_;
     //! Nbnxm force to be added in this reduction
-    DeviceBuffer<RVec> nbnxmForceToAdd_ = nullptr;
+    DeviceBuffer<RVec> nbnxmForceToAdd_;
     //! Rvec-format force to be added in this reduction
-    DeviceBuffer<RVec> rvecForceToAdd_ = nullptr;
-    //! event to be marked when redcution launch has been completed
+    DeviceBuffer<RVec> rvecForceToAdd_;
+    //! event to be marked when reduction launch has been completed
     GpuEventSynchronizer* completionMarker_ = nullptr;
     //! The wallclock counter
     gmx_wallcycle* wcycle_ = nullptr;
diff --git a/src/gromacs/mdlib/gpuforcereduction_impl_internal.cu b/src/gromacs/mdlib/gpuforcereduction_impl_internal.cu
new file mode 100644 (file)
index 0000000..4fb187f
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 GPU Force Reduction using CUDA
+ *
+ * \author Alan Gray <alang@nvidia.com>
+ *
+ * \ingroup module_mdlib
+ */
+
+#include "gmxpre.h"
+
+#include "gpuforcereduction_impl_internal.h"
+
+#include "gromacs/gpu_utils/cudautils.cuh"
+#include "gromacs/gpu_utils/devicebuffer.h"
+#include "gromacs/gpu_utils/typecasts.cuh"
+#include "gromacs/gpu_utils/vectype_ops.cuh"
+
+namespace gmx
+{
+
+constexpr static int c_threadsPerBlock = 128;
+
+template<bool addRvecForce, bool accumulateForce>
+static __global__ void reduceKernel(const float3* __restrict__ gm_nbnxmForce,
+                                    const float3* __restrict__ rvecForceToAdd,
+                                    float3*    gm_fTotal,
+                                    const int* gm_cell,
+                                    const int  numAtoms)
+{
+
+    // map particle-level parallelism to 1D CUDA thread and block index
+    const int threadIndex = blockIdx.x * blockDim.x + threadIdx.x;
+
+    // perform addition for each particle
+    if (threadIndex < numAtoms)
+    {
+
+        float3* gm_fDest = &gm_fTotal[threadIndex];
+        float3  temp;
+
+        // Accumulate or set nbnxm force
+        if (accumulateForce)
+        {
+            temp = *gm_fDest;
+            temp += gm_nbnxmForce[gm_cell[threadIndex]];
+        }
+        else
+        {
+            temp = gm_nbnxmForce[gm_cell[threadIndex]];
+        }
+
+        if (addRvecForce)
+        {
+            temp += rvecForceToAdd[threadIndex];
+        }
+
+        *gm_fDest = temp;
+    }
+    return;
+}
+
+void launchForceReductionKernel(int                        numAtoms,
+                                int                        atomStart,
+                                bool                       addRvecForce,
+                                bool                       accumulate,
+                                const DeviceBuffer<Float3> d_nbnxmForceToAdd,
+                                const DeviceBuffer<Float3> d_rvecForceToAdd,
+                                DeviceBuffer<Float3>       d_baseForce,
+                                DeviceBuffer<int>          d_cell,
+                                const DeviceStream&        deviceStream)
+{
+    float3* d_baseForcePtr      = &(asFloat3(d_baseForce)[atomStart]);
+    float3* d_nbnxmForcePtr     = asFloat3(d_nbnxmForceToAdd);
+    float3* d_rvecForceToAddPtr = &(asFloat3(d_rvecForceToAdd)[atomStart]);
+
+    // Configure and launch kernel
+    KernelLaunchConfig config;
+    config.blockSize[0]     = c_threadsPerBlock;
+    config.blockSize[1]     = 1;
+    config.blockSize[2]     = 1;
+    config.gridSize[0]      = ((numAtoms + 1) + c_threadsPerBlock - 1) / c_threadsPerBlock;
+    config.gridSize[1]      = 1;
+    config.gridSize[2]      = 1;
+    config.sharedMemorySize = 0;
+
+    auto kernelFn = addRvecForce
+                            ? (accumulate ? reduceKernel<true, true> : reduceKernel<true, false>)
+                            : (accumulate ? reduceKernel<false, true> : reduceKernel<false, false>);
+
+    const auto kernelArgs = prepareGpuKernelArguments(
+            kernelFn, config, &d_nbnxmForcePtr, &d_rvecForceToAddPtr, &d_baseForcePtr, &d_cell, &numAtoms);
+
+    launchGpuKernel(kernelFn, config, deviceStream, nullptr, "Force Reduction", kernelArgs);
+}
+
+} // namespace gmx
diff --git a/src/gromacs/mdlib/gpuforcereduction_impl_internal.h b/src/gromacs/mdlib/gpuforcereduction_impl_internal.h
new file mode 100644 (file)
index 0000000..23b87a2
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 vendor-specific function to launch force reduction kernel
+ *
+ * \author Andrey Alekseenko <al42and@gmail.com>
+ *
+ * \ingroup module_mdlib
+ */
+
+#include "gromacs/gpu_utils/devicebuffer_datatype.h"
+#include "gromacs/gpu_utils/gputraits.h"
+
+class DeviceStream;
+
+namespace gmx
+{
+
+/*! \brief Backend-specific function to launch GPU Force Reduction kernel.
+ *
+ * In pseudocode:
+ *
+ * \code{.cpp}
+ * for (int i = 0; i < numAtoms; i++) {
+ *     totalForce = d_nbnxmForceToAdd[d_cell[i]]
+ *     if (accumulate)
+ *         totalForce += d_baseForce[atomStart + i]
+ *     if (addRvecForce)
+ *         totalForce += d_rvecForceToAdd[atomStart + i]
+ *     d_baseForce[atomStart + i] = totalForce[i]
+ * }
+ * \endcode
+ *
+ * \param numAtoms Number of atoms subject to reduction.
+ * \param atomStart First atom index (for \p d_rvecForceToAdd and \p d_baseForce).
+ * \param addRvecForce When \c false, \p d_rvecForceToAdd is ignored.
+ * \param accumulate When \c false, the previous values of \p d_baseForce are discarded.
+ * \param d_nbnxmForceToAdd Buffer containing Nbnxm forces in Nbnxm layout.
+ * \param d_rvecForceToAdd Optional buffer containing arbitrary forces in linear layout.
+ * \param d_baseForce Destination buffer for forces in linear layout.
+ * \param d_cell Atom index to Nbnxm cell index.
+ * \param deviceStream Device stream for kernel submission.
+ */
+void launchForceReductionKernel(int                  numAtoms,
+                                int                  atomStart,
+                                bool                 addRvecForce,
+                                bool                 accumulate,
+                                DeviceBuffer<Float3> d_nbnxmForceToAdd,
+                                DeviceBuffer<Float3> d_rvecForceToAdd,
+                                DeviceBuffer<Float3> d_baseForce,
+                                DeviceBuffer<int>    d_cell,
+                                const DeviceStream&  deviceStream);
+
+} // namespace gmx
diff --git a/src/gromacs/mdlib/gpuforcereduction_impl_stubs.cpp b/src/gromacs/mdlib/gpuforcereduction_impl_stubs.cpp
new file mode 100644 (file)
index 0000000..7b1fe88
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 May be used to implement force reduction interfaces for non-GPU builds.
+ *
+ * \author Alan Gray <alang@nvidia.com>
+ *
+ * \ingroup module_mdlib
+ */
+
+#include "gmxpre.h"
+
+#include "config.h"
+
+#include "gpuforcereduction.h"
+
+#if !HAVE_GPU_FORCE_REDUCTION
+
+namespace gmx
+{
+
+class GpuForceReduction::Impl
+{
+};
+
+GpuForceReduction::GpuForceReduction(const DeviceContext& /* deviceContext */,
+                                     const DeviceStream& /* deviceStream */,
+                                     gmx_wallcycle* /*wcycle*/) :
+    impl_(nullptr)
+{
+    GMX_RELEASE_ASSERT(false, "A CPU stub has been called instead of the correct implementation.");
+}
+
+// NOLINTNEXTLINE readability-convert-member-functions-to-static
+void GpuForceReduction::reinit(DeviceBuffer<RVec> /*baseForcePtr*/,
+                               const int /*numAtoms*/,
+                               ArrayRef<const int> /*cell*/,
+                               const int /*atomStart*/,
+                               const bool /*accumulate*/,
+                               GpuEventSynchronizer* /*completionMarker*/)
+{
+    GMX_RELEASE_ASSERT(false, "A CPU stub has been called instead of the correct implementation.");
+}
+
+// NOLINTNEXTLINE readability-convert-member-functions-to-static
+void GpuForceReduction::registerNbnxmForce(DeviceBuffer<RVec> /* forcePtr */)
+{
+    GMX_RELEASE_ASSERT(false, "A CPU stub has been called instead of the correct implementation.");
+}
+
+// NOLINTNEXTLINE readability-convert-member-functions-to-static
+void GpuForceReduction::registerRvecForce(DeviceBuffer<gmx::RVec> /* forcePtr */)
+{
+    GMX_RELEASE_ASSERT(false, "A CPU stub has been called instead of the correct implementation.");
+}
+
+// NOLINTNEXTLINE readability-convert-member-functions-to-static
+void GpuForceReduction::addDependency(GpuEventSynchronizer* const /* dependency */)
+{
+    GMX_RELEASE_ASSERT(false, "A CPU stub has been called instead of the correct implementation.");
+}
+
+// NOLINTNEXTLINE readability-convert-member-functions-to-static
+void GpuForceReduction::execute()
+{
+    GMX_RELEASE_ASSERT(false, "A CPU stub has been called instead of the correct implementation.");
+}
+
+GpuForceReduction::~GpuForceReduction() = default;
+
+} // namespace gmx
+
+#endif /* !HAVE_GPU_FORCE_REDUCTION */
index a5ac290f6f7725390e3dd8d3483cdd87b57e7992..7028e256b85f018d48a7fc58d256851a33ae48c0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 @@
 
 #include "gromacs/gpu_utils/cudautils.cuh"
 #include "gromacs/gpu_utils/devicebuffer.h"
+#include "gromacs/gpu_utils/typecasts.cuh"
 #include "gromacs/gpu_utils/vectype_ops.cuh"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdtypes/group.h"
@@ -237,10 +238,10 @@ inline auto selectLeapFrogKernelPtr(bool                doTemperatureScaling,
     return kernelPtr;
 }
 
-void LeapFrogGpu::integrate(const DeviceBuffer<float3>        d_x,
-                            DeviceBuffer<float3>              d_xp,
-                            DeviceBuffer<float3>              d_v,
-                            const DeviceBuffer<float3>        d_f,
+void LeapFrogGpu::integrate(DeviceBuffer<Float3>              d_x,
+                            DeviceBuffer<Float3>              d_xp,
+                            DeviceBuffer<Float3>              d_v,
+                            const DeviceBuffer<Float3>        d_f,
                             const real                        dt,
                             const bool                        doTemperatureScaling,
                             gmx::ArrayRef<const t_grp_tcstat> tcstat,
@@ -263,8 +264,13 @@ void LeapFrogGpu::integrate(const DeviceBuffer<float3>        d_x,
             {
                 h_lambdas_[i] = tcstat[i].lambda;
             }
-            copyToDeviceBuffer(&d_lambdas_, h_lambdas_.data(), 0, numTempScaleValues_,
-                               deviceStream_, GpuApiCallBehavior::Async, nullptr);
+            copyToDeviceBuffer(&d_lambdas_,
+                               h_lambdas_.data(),
+                               0,
+                               numTempScaleValues_,
+                               deviceStream_,
+                               GpuApiCallBehavior::Async,
+                               nullptr);
         }
         VelocityScalingType prVelocityScalingType = VelocityScalingType::None;
         if (doParrinelloRahman)
@@ -278,24 +284,38 @@ void LeapFrogGpu::integrate(const DeviceBuffer<float3>        d_x,
                        "Fully anisotropic Parrinello-Rahman pressure coupling is not yet supported "
                        "in GPU version of Leap-Frog integrator.");
             prVelocityScalingMatrixDiagonal_ =
-                    make_float3(dtPressureCouple * prVelocityScalingMatrix[XX][XX],
-                                dtPressureCouple * prVelocityScalingMatrix[YY][YY],
-                                dtPressureCouple * prVelocityScalingMatrix[ZZ][ZZ]);
+                    Float3{ dtPressureCouple * prVelocityScalingMatrix[XX][XX],
+                            dtPressureCouple * prVelocityScalingMatrix[YY][YY],
+                            dtPressureCouple * prVelocityScalingMatrix[ZZ][ZZ] };
         }
         kernelPtr = selectLeapFrogKernelPtr(doTemperatureScaling, numTempScaleValues_, prVelocityScalingType);
     }
 
-    const auto kernelArgs = prepareGpuKernelArguments(
-            kernelPtr, kernelLaunchConfig_, &numAtoms_, &d_x, &d_xp, &d_v, &d_f, &d_inverseMasses_,
-            &dt, &d_lambdas_, &d_tempScaleGroups_, &prVelocityScalingMatrixDiagonal_);
+    // Checking the buffer types against the kernel argument types
+    static_assert(sizeof(*d_inverseMasses_) == sizeof(float), "Incompatible types");
+    const auto kernelArgs = prepareGpuKernelArguments(kernelPtr,
+                                                      kernelLaunchConfig_,
+                                                      &numAtoms_,
+                                                      asFloat3Pointer(&d_x),
+                                                      asFloat3Pointer(&d_xp),
+                                                      asFloat3Pointer(&d_v),
+                                                      asFloat3Pointer(&d_f),
+                                                      &d_inverseMasses_,
+                                                      &dt,
+                                                      &d_lambdas_,
+                                                      &d_tempScaleGroups_,
+                                                      &prVelocityScalingMatrixDiagonal_);
     launchGpuKernel(kernelPtr, kernelLaunchConfig_, deviceStream_, nullptr, "leapfrog_kernel", kernelArgs);
 
     return;
 }
 
-LeapFrogGpu::LeapFrogGpu(const DeviceContext& deviceContext, const DeviceStream& deviceStream) :
+LeapFrogGpu::LeapFrogGpu(const DeviceContext& deviceContext,
+                         const DeviceStream&  deviceStream,
+                         const int            numTempScaleValues) :
     deviceContext_(deviceContext),
-    deviceStream_(deviceStream)
+    deviceStream_(deviceStream),
+    numTempScaleValues_(numTempScaleValues)
 {
     numAtoms_ = 0;
 
@@ -305,6 +325,14 @@ LeapFrogGpu::LeapFrogGpu(const DeviceContext& deviceContext, const DeviceStream&
     kernelLaunchConfig_.blockSize[1]     = 1;
     kernelLaunchConfig_.blockSize[2]     = 1;
     kernelLaunchConfig_.sharedMemorySize = 0;
+
+    // If the temperature coupling is enabled, we need to make space for scaling factors
+    if (numTempScaleValues_ > 0)
+    {
+        h_lambdas_.resize(numTempScaleValues_);
+        reallocateDeviceBuffer(
+                &d_lambdas_, numTempScaleValues_, &numLambdas_, &numLambdasAlloc_, deviceContext_);
+    }
 }
 
 LeapFrogGpu::~LeapFrogGpu()
@@ -312,36 +340,23 @@ LeapFrogGpu::~LeapFrogGpu()
     freeDeviceBuffer(&d_inverseMasses_);
 }
 
-void LeapFrogGpu::set(const int             numAtoms,
-                      const real*           inverseMasses,
-                      const int             numTempScaleValues,
-                      const unsigned short* tempScaleGroups)
+void LeapFrogGpu::set(const int numAtoms, const real* inverseMasses, const unsigned short* tempScaleGroups)
 {
     numAtoms_                       = numAtoms;
     kernelLaunchConfig_.gridSize[0] = (numAtoms_ + c_threadsPerBlock - 1) / c_threadsPerBlock;
 
-    numTempScaleValues_ = numTempScaleValues;
-
-    reallocateDeviceBuffer(&d_inverseMasses_, numAtoms_, &numInverseMasses_,
-                           &numInverseMassesAlloc_, deviceContext_);
-    copyToDeviceBuffer(&d_inverseMasses_, (float*)inverseMasses, 0, numAtoms_, deviceStream_,
-                       GpuApiCallBehavior::Sync, nullptr);
+    reallocateDeviceBuffer(
+            &d_inverseMasses_, numAtoms_, &numInverseMasses_, &numInverseMassesAlloc_, deviceContext_);
+    copyToDeviceBuffer(
+            &d_inverseMasses_, inverseMasses, 0, numAtoms_, deviceStream_, GpuApiCallBehavior::Sync, nullptr);
 
     // Temperature scale group map only used if there are more then one group
-    if (numTempScaleValues > 1)
-    {
-        reallocateDeviceBuffer(&d_tempScaleGroups_, numAtoms_, &numTempScaleGroups_,
-                               &numTempScaleGroupsAlloc_, deviceContext_);
-        copyToDeviceBuffer(&d_tempScaleGroups_, tempScaleGroups, 0, numAtoms_, deviceStream_,
-                           GpuApiCallBehavior::Sync, nullptr);
-    }
-
-    // If the temperature coupling is enabled, we need to make space for scaling factors
-    if (numTempScaleValues_ > 0)
+    if (numTempScaleValues_ > 1)
     {
-        h_lambdas_.resize(numTempScaleValues);
-        reallocateDeviceBuffer(&d_lambdas_, numTempScaleValues_, &numLambdas_, &numLambdasAlloc_,
-                               deviceContext_);
+        reallocateDeviceBuffer(
+                &d_tempScaleGroups_, numAtoms_, &numTempScaleGroups_, &numTempScaleGroupsAlloc_, deviceContext_);
+        copyToDeviceBuffer(
+                &d_tempScaleGroups_, tempScaleGroups, 0, numAtoms_, deviceStream_, GpuApiCallBehavior::Sync, nullptr);
     }
 }
 
index 7c76805d09209f130ac29be1810f85dcc985ab89..9102e2a27e9a81ea5ec7c954761c2c149caa8dcd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "config.h"
 
 #if GMX_GPU_CUDA
-#    include "gromacs/gpu_utils/devicebuffer.cuh"
 #    include "gromacs/gpu_utils/gputraits.cuh"
 #endif
 #if GMX_GPU_SYCL
-#    include "gromacs/gpu_utils/devicebuffer_sycl.h"
 #    include "gromacs/gpu_utils/gputraits_sycl.h"
 #endif
 
+#include <memory>
+
+#include "gromacs/gpu_utils/devicebuffer_datatype.h"
 #include "gromacs/gpu_utils/hostallocator.h"
-#include "gromacs/pbcutil/pbc.h"
-#include "gromacs/pbcutil/pbc_aiuc.h"
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/classhelpers.h"
 
 class DeviceContext;
 class DeviceStream;
@@ -100,10 +98,11 @@ class LeapFrogGpu
 public:
     /*! \brief Constructor.
      *
-     * \param[in] deviceContext  Device context (dummy in CUDA).
-     * \param[in] deviceStream   Device stream to use.
+     * \param[in] deviceContext       Device context (dummy in CUDA).
+     * \param[in] deviceStream        Device stream to use.
+     * \param[in] numTempScaleValues  Number of temperature scale groups.
      */
-    LeapFrogGpu(const DeviceContext& deviceContext, const DeviceStream& deviceStream);
+    LeapFrogGpu(const DeviceContext& deviceContext, const DeviceStream& deviceStream, int numTempScaleValues);
     ~LeapFrogGpu();
 
     /*! \brief Integrate
@@ -122,10 +121,10 @@ public:
      * \param[in]     dtPressureCouple         Period between pressure coupling steps
      * \param[in]     prVelocityScalingMatrix  Parrinello-Rahman velocity scaling matrix
      */
-    void integrate(const DeviceBuffer<float3>        d_x,
-                   DeviceBuffer<float3>              d_xp,
-                   DeviceBuffer<float3>              d_v,
-                   const DeviceBuffer<float3>        d_f,
+    void integrate(DeviceBuffer<Float3>              d_x,
+                   DeviceBuffer<Float3>              d_xp,
+                   DeviceBuffer<Float3>              d_v,
+                   const DeviceBuffer<Float3>        d_f,
                    const real                        dt,
                    const bool                        doTemperatureScaling,
                    gmx::ArrayRef<const t_grp_tcstat> tcstat,
@@ -139,15 +138,11 @@ public:
      * and temperature coupling groups. Copies inverse masses and temperature coupling groups
      * to the GPU.
      *
-     * \param[in] numAtoms            Number of atoms in the system.
-     * \param[in] inverseMasses       Inverse masses of atoms.
-     * \param[in] numTempScaleValues  Number of temperature scale groups.
-     * \param[in] tempScaleGroups     Maps the atom index to temperature scale value.
+     * \param[in] numAtoms        Number of atoms in the system.
+     * \param[in] inverseMasses   Inverse masses of atoms.
+     * \param[in] tempScaleGroups Maps the atom index to temperature scale value.
      */
-    void set(const int             numAtoms,
-             const real*           inverseMasses,
-             int                   numTempScaleValues,
-             const unsigned short* tempScaleGroups);
+    void set(const int numAtoms, const real* inverseMasses, const unsigned short* tempScaleGroups);
 
     /*! \brief Class with hardware-specific interfaces and implementations.*/
     class Impl;
@@ -173,7 +168,6 @@ private:
     int numTempScaleValues_ = 0;
     /*! \brief Array with temperature scaling factors.
      * This is temporary solution to remap data from t_grp_tcstat into plain array.
-     * Not used in SYCL.
      * \todo Replace with better solution.
      */
     gmx::HostVector<float> h_lambdas_;
@@ -193,7 +187,7 @@ private:
     int numTempScaleGroupsAlloc_ = -1;
 
     //! Vector with diagonal elements of the Parrinello-Rahman pressure coupling velocity rescale factors
-    float3 prVelocityScalingMatrixDiagonal_;
+    Float3 prVelocityScalingMatrixDiagonal_;
 };
 
 } // namespace gmx
index 61484f8968ec7ef55c3f9e362e5eface1432669d..89997a69ca7c643b37293ae0cf6bfe45fd45b905 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,15 +84,15 @@ using cl::sycl::access::mode;
 template<NumTempScaleValues numTempScaleValues, VelocityScalingType velocityScaling>
 auto leapFrogKernel(
         cl::sycl::handler&                          cgh,
-        DeviceAccessor<float3, mode::read_write>    a_x,
-        DeviceAccessor<float3, mode::discard_write> a_xp,
-        DeviceAccessor<float3, mode::read_write>    a_v,
-        DeviceAccessor<float3, mode::read>          a_f,
+        DeviceAccessor<Float3, mode::read_write>    a_x,
+        DeviceAccessor<Float3, mode::discard_write> a_xp,
+        DeviceAccessor<Float3, mode::read_write>    a_v,
+        DeviceAccessor<Float3, mode::read>          a_f,
         DeviceAccessor<float, mode::read>           a_inverseMasses,
         float                                       dt,
         OptionalAccessor<float, mode::read, numTempScaleValues != NumTempScaleValues::None> a_lambdas,
         OptionalAccessor<unsigned short, mode::read, numTempScaleValues == NumTempScaleValues::Multiple> a_tempScaleGroups,
-        float3 prVelocityScalingMatrixDiagonal)
+        Float3 prVelocityScalingMatrixDiagonal)
 {
     cgh.require(a_x);
     cgh.require(a_xp);
@@ -109,9 +109,9 @@ auto leapFrogKernel(
     }
 
     return [=](cl::sycl::id<1> itemIdx) {
-        const float3 x    = a_x[itemIdx];
-        const float3 v    = a_v[itemIdx];
-        const float3 f    = a_f[itemIdx];
+        const Float3 x    = a_x[itemIdx];
+        const Float3 v    = a_v[itemIdx];
+        const Float3 f    = a_f[itemIdx];
         const float  im   = a_inverseMasses[itemIdx];
         const float  imdt = im * dt;
 
@@ -137,20 +137,20 @@ auto leapFrogKernel(
             }
         }();
 
-        const float3 prVelocityDelta = [=]() {
+        const Float3 prVelocityDelta = [=]() {
             if constexpr (velocityScaling == VelocityScalingType::Diagonal)
             {
-                return float3{ prVelocityScalingMatrixDiagonal[0] * v[0],
+                return Float3{ prVelocityScalingMatrixDiagonal[0] * v[0],
                                prVelocityScalingMatrixDiagonal[1] * v[1],
                                prVelocityScalingMatrixDiagonal[2] * v[2] };
             }
             else if constexpr (velocityScaling == VelocityScalingType::None)
             {
-                return float3{ 0, 0, 0 };
+                return Float3{ 0, 0, 0 };
             }
         }();
 
-        const float3 v_new = v * lambda - prVelocityDelta + f * imdt;
+        const Float3 v_new = v * lambda - prVelocityDelta + f * imdt;
         a_v[itemIdx]       = v_new;
         a_x[itemIdx]       = x + v_new * dt;
     };
@@ -212,13 +212,14 @@ static inline cl::sycl::event launchLeapFrogKernel(NumTempScaleValues  tempScali
             [&](auto tempScalingType_, auto prScalingType_) {
                 return launchLeapFrogKernel<tempScalingType_, prScalingType_>(std::forward<Args>(args)...);
             },
-            tempScalingType, prVelocityScalingType);
+            tempScalingType,
+            prVelocityScalingType);
 }
 
-void LeapFrogGpu::integrate(DeviceBuffer<float3>              d_x,
-                            DeviceBuffer<float3>              d_xp,
-                            DeviceBuffer<float3>              d_v,
-                            DeviceBuffer<float3>              d_f,
+void LeapFrogGpu::integrate(DeviceBuffer<Float3>              d_x,
+                            DeviceBuffer<Float3>              d_xp,
+                            DeviceBuffer<Float3>              d_v,
+                            DeviceBuffer<Float3>              d_f,
                             const real                        dt,
                             const bool                        doTemperatureScaling,
                             gmx::ArrayRef<const t_grp_tcstat> tcstat,
@@ -231,13 +232,25 @@ void LeapFrogGpu::integrate(DeviceBuffer<float3>              d_x,
         GMX_ASSERT(checkDeviceBuffer(d_lambdas_, numTempScaleValues_),
                    "Number of temperature scaling factors changed since it was set for the "
                    "last time.");
-        { // Explicitly limiting the scope of host accessor. Not strictly necessary here.
-            auto ha_lambdas_ = d_lambdas_.buffer_->get_access<mode::discard_write>();
-            for (int i = 0; i < numTempScaleValues_; i++)
-            {
-                ha_lambdas_[i] = tcstat[i].lambda;
-            }
+        GMX_RELEASE_ASSERT(gmx::ssize(h_lambdas_) == numTempScaleValues_,
+                           "Number of temperature scaling factors changed since it was set for the "
+                           "last time.");
+        /* We could use host accessors here, without h_lambdas_.
+         * According to a quick test, host accessor is slightly faster when using DPC++ and
+         * LevelZero compared to using h_lambdas_ + cgh.copy. But with DPC++ and OpenCL, the host
+         * accessor waits for fReadyOnDevice in UpdateConstrainGpu::Impl::integrate. See #4023. */
+
+        for (int i = 0; i < numTempScaleValues_; i++)
+        {
+            h_lambdas_[i] = tcstat[i].lambda;
         }
+        copyToDeviceBuffer(&d_lambdas_,
+                           h_lambdas_.data(),
+                           0,
+                           numTempScaleValues_,
+                           deviceStream_,
+                           GpuApiCallBehavior::Async,
+                           nullptr);
     }
     NumTempScaleValues tempVelocityScalingType =
             getTempScalingType(doTemperatureScaling, numTempScaleValues_);
@@ -251,22 +264,42 @@ void LeapFrogGpu::integrate(DeviceBuffer<float3>              d_x,
                            && prVelocityScalingMatrix[XX][ZZ] == 0 && prVelocityScalingMatrix[YY][ZZ] == 0,
                    "Fully anisotropic Parrinello-Rahman pressure coupling is not yet supported "
                    "in GPU version of Leap-Frog integrator.");
-        prVelocityScalingMatrixDiagonal_ =
-                dtPressureCouple
-                * float3{ prVelocityScalingMatrix[XX][XX], prVelocityScalingMatrix[YY][YY],
-                          prVelocityScalingMatrix[ZZ][ZZ] };
+        prVelocityScalingMatrixDiagonal_ = dtPressureCouple
+                                           * Float3{ prVelocityScalingMatrix[XX][XX],
+                                                     prVelocityScalingMatrix[YY][YY],
+                                                     prVelocityScalingMatrix[ZZ][ZZ] };
     }
 
-    launchLeapFrogKernel(tempVelocityScalingType, prVelocityScalingType, deviceStream_, numAtoms_,
-                         d_x, d_xp, d_v, d_f, d_inverseMasses_, dt, d_lambdas_, d_tempScaleGroups_,
+    launchLeapFrogKernel(tempVelocityScalingType,
+                         prVelocityScalingType,
+                         deviceStream_,
+                         numAtoms_,
+                         d_x,
+                         d_xp,
+                         d_v,
+                         d_f,
+                         d_inverseMasses_,
+                         dt,
+                         d_lambdas_,
+                         d_tempScaleGroups_,
                          prVelocityScalingMatrixDiagonal_);
 }
 
-LeapFrogGpu::LeapFrogGpu(const DeviceContext& deviceContext, const DeviceStream& deviceStream) :
+LeapFrogGpu::LeapFrogGpu(const DeviceContext& deviceContext,
+                         const DeviceStream&  deviceStream,
+                         const int            numTempScaleValues) :
     deviceContext_(deviceContext),
     deviceStream_(deviceStream),
-    numAtoms_(0)
+    numAtoms_(0),
+    numTempScaleValues_(numTempScaleValues)
 {
+    // If the temperature coupling is enabled, we need to make space for scaling factors
+    if (numTempScaleValues_ > 0)
+    {
+        h_lambdas_.resize(numTempScaleValues_);
+        reallocateDeviceBuffer(
+                &d_lambdas_, numTempScaleValues_, &numLambdas_, &numLambdasAlloc_, deviceContext_);
+    }
 }
 
 LeapFrogGpu::~LeapFrogGpu()
@@ -274,33 +307,22 @@ LeapFrogGpu::~LeapFrogGpu()
     freeDeviceBuffer(&d_inverseMasses_);
 }
 
-void LeapFrogGpu::set(const int             numAtoms,
-                      const real*           inverseMasses,
-                      const int             numTempScaleValues,
-                      const unsigned short* tempScaleGroups)
+void LeapFrogGpu::set(const int numAtoms, const real* inverseMasses, const unsigned short* tempScaleGroups)
 {
-    numAtoms_           = numAtoms;
-    numTempScaleValues_ = numTempScaleValues;
+    numAtoms_ = numAtoms;
 
-    reallocateDeviceBuffer(&d_inverseMasses_, numAtoms_, &numInverseMasses_,
-                           &numInverseMassesAlloc_, deviceContext_);
-    copyToDeviceBuffer(&d_inverseMasses_, inverseMasses, 0, numAtoms_, deviceStream_,
-                       GpuApiCallBehavior::Sync, nullptr);
+    reallocateDeviceBuffer(
+            &d_inverseMasses_, numAtoms_, &numInverseMasses_, &numInverseMassesAlloc_, deviceContext_);
+    copyToDeviceBuffer(
+            &d_inverseMasses_, inverseMasses, 0, numAtoms_, deviceStream_, GpuApiCallBehavior::Sync, nullptr);
 
     // Temperature scale group map only used if there are more then one group
     if (numTempScaleValues_ > 1)
     {
-        reallocateDeviceBuffer(&d_tempScaleGroups_, numAtoms_, &numTempScaleGroups_,
-                               &numTempScaleGroupsAlloc_, deviceContext_);
-        copyToDeviceBuffer(&d_tempScaleGroups_, tempScaleGroups, 0, numAtoms_, deviceStream_,
-                           GpuApiCallBehavior::Sync, nullptr);
-    }
-
-    // If the temperature coupling is enabled, we need to make space for scaling factors
-    if (numTempScaleValues_ > 0)
-    {
-        reallocateDeviceBuffer(&d_lambdas_, numTempScaleValues_, &numLambdas_, &numLambdasAlloc_,
-                               deviceContext_);
+        reallocateDeviceBuffer(
+                &d_tempScaleGroups_, numAtoms_, &numTempScaleGroups_, &numTempScaleGroupsAlloc_, deviceContext_);
+        copyToDeviceBuffer(
+                &d_tempScaleGroups_, tempScaleGroups, 0, numAtoms_, deviceStream_, GpuApiCallBehavior::Sync, nullptr);
     }
 }
 
index 2f8119da4ad3d786a6e3e3944ba678f4516e8961..093ff1bec170985b91bd0e6d0f2b5cc173520723 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -349,10 +349,10 @@ static void lincs_update_atoms_noind(int                            ncons,
                                      real                           preFactor,
                                      gmx::ArrayRef<const real>      fac,
                                      gmx::ArrayRef<const gmx::RVec> r,
-                                     const real*                    invmass,
+                                     gmx::ArrayRef<const real>      invmass,
                                      rvec*                          x)
 {
-    if (invmass != nullptr)
+    if (!invmass.empty())
     {
         for (int b = 0; b < ncons; b++)
         {
@@ -398,10 +398,10 @@ static void lincs_update_atoms_ind(gmx::ArrayRef<const int>       ind,
                                    real                           preFactor,
                                    gmx::ArrayRef<const real>      fac,
                                    gmx::ArrayRef<const gmx::RVec> r,
-                                   const real*                    invmass,
+                                   gmx::ArrayRef<const real>      invmass,
                                    rvec*                          x)
 {
-    if (invmass != nullptr)
+    if (!invmass.empty())
     {
         for (int b : ind)
         {
@@ -447,7 +447,7 @@ static void lincs_update_atoms(Lincs*                         li,
                                real                           preFactor,
                                gmx::ArrayRef<const real>      fac,
                                gmx::ArrayRef<const gmx::RVec> r,
-                               const real*                    invmass,
+                               gmx::ArrayRef<const real>      invmass,
                                rvec*                          x)
 {
     if (li->ntask == 1)
@@ -574,7 +574,7 @@ static void do_lincsp(ArrayRefWithPadding<const RVec> xPadded,
                       t_pbc*                          pbc,
                       Lincs*                          lincsd,
                       int                             th,
-                      const real*                     invmass,
+                      ArrayRef<const real>            invmass,
                       ConstraintVariable              econq,
                       bool                            bCalcDHDL,
                       bool                            bCalcVir,
@@ -623,8 +623,8 @@ static void do_lincsp(ArrayRefWithPadding<const RVec> xPadded,
     /* Compute normalized x i-j vectors, store in r.
      * Compute the inner product of r and xp i-j and store in rhs1.
      */
-    calc_dr_x_f_simd(b0, b1, atoms, x, f, blc.data(), pbc_simd, as_rvec_array(r.data()),
-                     rhs1.data(), sol.data());
+    calc_dr_x_f_simd(
+            b0, b1, atoms, x, f, blc.data(), pbc_simd, as_rvec_array(r.data()), rhs1.data(), sol.data());
 
 #else // GMX_SIMD_HAVE_REAL
 
@@ -708,7 +708,12 @@ static void do_lincsp(ArrayRefWithPadding<const RVec> xPadded,
     /* When constraining forces, we should not use mass weighting,
      * so we pass invmass=NULL, which results in the use of 1 for all atoms.
      */
-    lincs_update_atoms(lincsd, th, 1.0, sol, r, (econq != ConstraintVariable::Force) ? invmass : nullptr,
+    lincs_update_atoms(lincsd,
+                       th,
+                       1.0,
+                       sol,
+                       r,
+                       (econq != ConstraintVariable::Force) ? invmass : gmx::ArrayRef<real>(),
                        as_rvec_array(fp.data()));
 
     if (bCalcDHDL)
@@ -953,7 +958,7 @@ static void do_lincs(ArrayRefWithPadding<const RVec> xPadded,
                      t_pbc*                          pbc,
                      Lincs*                          lincsd,
                      int                             th,
-                     const real*                     invmass,
+                     ArrayRef<const real>            invmass,
                      const t_commrec*                cr,
                      bool                            bCalcDHDL,
                      real                            wangle,
@@ -999,8 +1004,8 @@ static void do_lincs(ArrayRefWithPadding<const RVec> xPadded,
     /* Compute normalized x i-j vectors, store in r.
      * Compute the inner product of r and xp i-j and store in rhs1.
      */
-    calc_dr_x_xp_simd(b0, b1, atoms, x, xp, bllen.data(), blc.data(), pbc_simd,
-                      as_rvec_array(r.data()), rhs1.data(), sol.data());
+    calc_dr_x_xp_simd(
+            b0, b1, atoms, x, xp, bllen.data(), blc.data(), pbc_simd, as_rvec_array(r.data()), rhs1.data(), sol.data());
 
 #else // GMX_SIMD_HAVE_REAL
 
@@ -1091,7 +1096,7 @@ static void do_lincs(ArrayRefWithPadding<const RVec> xPadded,
 
     real wfac;
 
-    wfac = std::cos(DEG2RAD * wangle);
+    wfac = std::cos(gmx::c_deg2Rad * wangle);
     wfac = wfac * wfac;
 
     for (int iter = 0; iter < lincsd->nIter; iter++)
@@ -1115,11 +1120,10 @@ static void do_lincs(ArrayRefWithPadding<const RVec> xPadded,
         }
 
 #if GMX_SIMD_HAVE_REAL
-        calc_dist_iter_simd(b0, b1, atoms, xp, bllen.data(), blc.data(), pbc_simd, wfac,
-                            rhs1.data(), sol.data(), bWarn);
+        calc_dist_iter_simd(
+                b0, b1, atoms, xp, bllen.data(), blc.data(), pbc_simd, wfac, rhs1.data(), sol.data(), bWarn);
 #else
-        calc_dist_iter(b0, b1, atoms, xp, bllen.data(), blc.data(), pbc, wfac, rhs1.data(),
-                       sol.data(), bWarn);
+        calc_dist_iter(b0, b1, atoms, xp, bllen.data(), blc.data(), pbc, wfac, rhs1.data(), sol.data(), bWarn);
         /* 20*ncons flops */
 #endif // GMX_SIMD_HAVE_REAL
 
@@ -1213,7 +1217,11 @@ static void do_lincs(ArrayRefWithPadding<const RVec> xPadded,
 }
 
 /*! \brief Sets the elements in the LINCS matrix for task task. */
-static void set_lincs_matrix_task(Lincs* li, Task* li_task, const real* invmass, int* ncc_triangle, int* nCrossTaskTriangles)
+static void set_lincs_matrix_task(Lincs*               li,
+                                  Task*                li_task,
+                                  ArrayRef<const real> invmass,
+                                  int*                 ncc_triangle,
+                                  int*                 nCrossTaskTriangles)
 {
     /* Construct the coupling coefficient matrix blmf */
     li_task->ntriangle   = 0;
@@ -1301,7 +1309,7 @@ static void set_lincs_matrix_task(Lincs* li, Task* li_task, const real* invmass,
 }
 
 /*! \brief Sets the elements in the LINCS matrix. */
-static void set_lincs_matrix(Lincs* li, const real* invmass, real lambda)
+static void set_lincs_matrix(Lincs* li, ArrayRef<const real> invmass, real lambda)
 {
     const real invsqrt2 = 0.7071067811865475244;
 
@@ -1332,8 +1340,7 @@ static void set_lincs_matrix(Lincs* li, const real* invmass, real lambda)
     if (debug)
     {
         fprintf(debug, "The %d constraints participate in %d triangles\n", li->nc, li->ntriangle);
-        fprintf(debug, "There are %d constraint couplings, of which %d in triangles\n", li->ncc,
-                li->ncc_triangle);
+        fprintf(debug, "There are %d constraint couplings, of which %d in triangles\n", li->ncc, li->ncc_triangle);
         if (li->ntriangle > 0 && li->ntask > 1)
         {
             fprintf(debug,
@@ -1498,12 +1505,11 @@ Lincs* init_lincs(FILE*                            fplog,
      * The current constraint to task assignment code can create independent
      * tasks only when not more than two constraints are connected sequentially.
      */
-    li->ntask    = gmx_omp_nthreads_get(emntLINCS);
+    li->ntask    = gmx_omp_nthreads_get(ModuleMultiThread::Lincs);
     li->bTaskDep = (li->ntask > 1 && bMoreThanTwoSeq);
     if (debug)
     {
-        fprintf(debug, "LINCS: using %d threads, tasks are %sdependent\n", li->ntask,
-                li->bTaskDep ? "" : "in");
+        fprintf(debug, "LINCS: using %d threads, tasks are %sdependent\n", li->ntask, li->bTaskDep ? "" : "in");
     }
     if (li->ntask == 1)
     {
@@ -1539,7 +1545,8 @@ Lincs* init_lincs(FILE*                            fplog,
                     "%d constraints are involved in constraint triangles,\n"
                     "will apply an additional matrix expansion of order %d for couplings\n"
                     "between constraints inside triangles\n",
-                    li->ncg_triangle, li->nOrder);
+                    li->ncg_triangle,
+                    li->nOrder);
         }
     }
 
@@ -1851,7 +1858,7 @@ static void set_matrix_indices(Lincs* li, const Task& li_task, const ListOfLists
 
 void set_lincs(const InteractionDefinitions& idef,
                const int                     numAtoms,
-               const real*                   invmass,
+               ArrayRef<const real>          invmass,
                const real                    lambda,
                bool                          bDynamics,
                const t_commrec*              cr,
@@ -1895,7 +1902,7 @@ void set_lincs(const InteractionDefinitions& idef,
         {
             int start;
 
-            dd_get_constraint_range(cr->dd, &start, &natoms);
+            dd_get_constraint_range(*cr->dd, &start, &natoms);
         }
         else
         {
@@ -2122,8 +2129,7 @@ void set_lincs(const InteractionDefinitions& idef,
 
     if (debug)
     {
-        fprintf(debug, "Number of constraints is %d, padded %d, couplings %d\n", li->nc_real,
-                li->nc, li->ncc);
+        fprintf(debug, "Number of constraints is %d, padded %d, couplings %d\n", li->nc_real, li->nc, li->ncc);
     }
 
     if (li->ntask > 1)
@@ -2149,7 +2155,7 @@ static void lincs_warning(gmx_domdec_t*                 dd,
                           int                           maxwarn,
                           int*                          warncount)
 {
-    real wfac = std::cos(DEG2RAD * wangle);
+    real wfac = std::cos(gmx::c_deg2Rad * wangle);
 
     fprintf(stderr,
             "bonds that rotated more than %g degrees:\n"
@@ -2177,8 +2183,14 @@ static void lincs_warning(gmx_domdec_t*                 dd,
         real cosine = ::iprod(v0, v1) / (d0 * d1);
         if (cosine < wfac)
         {
-            fprintf(stderr, " %6d %6d  %5.1f  %8.4f %8.4f    %8.4f\n", ddglatnr(dd, i),
-                    ddglatnr(dd, j), RAD2DEG * std::acos(cosine), d0, d1, bllen[b]);
+            fprintf(stderr,
+                    " %6d %6d  %5.1f  %8.4f %8.4f    %8.4f\n",
+                    ddglatnr(dd, i),
+                    ddglatnr(dd, j),
+                    gmx::c_rad2Deg * std::acos(cosine),
+                    d0,
+                    d1,
+                    bllen[b]);
             if (!std::isfinite(d1))
             {
                 gmx_fatal(FARGS, "Bond length not finite.");
@@ -2189,7 +2201,7 @@ static void lincs_warning(gmx_domdec_t*                 dd,
     }
     if (*warncount > maxwarn)
     {
-        too_many_constraint_warnings(econtLINCS, *warncount);
+        too_many_constraint_warnings(ConstraintAlgorithm::Lincs, *warncount);
     }
 }
 
@@ -2260,7 +2272,7 @@ bool constrain_lincs(bool                            computeRmsd,
                      const t_inputrec&               ir,
                      int64_t                         step,
                      Lincs*                          lincsd,
-                     const real*                     invmass,
+                     ArrayRef<const real>            invmass,
                      const t_commrec*                cr,
                      const gmx_multisim_t*           ms,
                      ArrayRefWithPadding<const RVec> xPadded,
@@ -2286,7 +2298,7 @@ bool constrain_lincs(bool                            computeRmsd,
      * We can also easily check if any constraint length is changed,
      * if not dH/dlambda=0 and we can also set the boolean to FALSE.
      */
-    bool bCalcDHDL = (ir.efep != efepNO && dvdlambda != nullptr);
+    bool bCalcDHDL = (ir.efep != FreeEnergyPerturbationType::No && dvdlambda != nullptr);
 
     if (lincsd->nc == 0 && cr->dd == nullptr)
     {
@@ -2306,7 +2318,7 @@ bool constrain_lincs(bool                            computeRmsd,
         /* We can't use bCalcDHDL here, since NULL can be passed for dvdlambda
          * also with efep!=fepNO.
          */
-        if (ir.efep != efepNO)
+        if (ir.efep != FreeEnergyPerturbationType::No)
         {
             if (hasMassPerturbed && lincsd->matlam != lambda)
             {
@@ -2352,7 +2364,8 @@ bool constrain_lincs(bool                            computeRmsd,
         {
             LincsDeviations deviations = makeLincsDeviations(*lincsd, xprime, pbc);
             fprintf(debug, "   Rel. Constraint Deviation:  RMS         MAX     between atoms\n");
-            fprintf(debug, "       Before LINCS          %.6f    %.6f %6d %6d\n",
+            fprintf(debug,
+                    "       Before LINCS          %.6f    %.6f %6d %6d\n",
                     std::sqrt(deviations.sumSquaredDeviation / deviations.numConstraints),
                     deviations.maxDeviation,
                     ddglatnr(cr->dd, lincsd->atoms[deviations.indexOfMaxDeviation].index1),
@@ -2374,8 +2387,20 @@ bool constrain_lincs(bool                            computeRmsd,
 
                 clear_mat(lincsd->task[th].vir_r_m_dr);
 
-                do_lincs(xPadded, xprimePadded, box, pbc, lincsd, th, invmass, cr, bCalcDHDL,
-                         ir.LincsWarnAngle, &bWarn, invdt, v, bCalcVir,
+                do_lincs(xPadded,
+                         xprimePadded,
+                         box,
+                         pbc,
+                         lincsd,
+                         th,
+                         invmass,
+                         cr,
+                         bCalcDHDL,
+                         ir.LincsWarnAngle,
+                         &bWarn,
+                         invdt,
+                         v,
+                         bCalcVir,
                          th == 0 ? vir_r_m_dr : lincsd->task[th].vir_r_m_dr);
             }
             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
@@ -2399,7 +2424,8 @@ bool constrain_lincs(bool                            computeRmsd,
             }
             if (printDebugOutput)
             {
-                fprintf(debug, "        After LINCS          %.6f    %.6f %6d %6d\n\n",
+                fprintf(debug,
+                        "        After LINCS          %.6f    %.6f %6d %6d\n\n",
                         std::sqrt(deviations.sumSquaredDeviation / deviations.numConstraints),
                         deviations.maxDeviation,
                         ddglatnr(cr->dd, lincsd->atoms[deviations.indexOfMaxDeviation].index1),
@@ -2420,14 +2446,16 @@ bool constrain_lincs(bool                            computeRmsd,
                             ", time %g (ps)  LINCS WARNING%s\n"
                             "relative constraint deviation after LINCS:\n"
                             "rms %.6f, max %.6f (between atoms %d and %d)\n",
-                            step, ir.init_t + step * ir.delta_t, simMesg.c_str(),
+                            step,
+                            ir.init_t + step * ir.delta_t,
+                            simMesg.c_str(),
                             std::sqrt(deviations.sumSquaredDeviation / deviations.numConstraints),
                             deviations.maxDeviation,
                             ddglatnr(cr->dd, lincsd->atoms[deviations.indexOfMaxDeviation].index1),
                             ddglatnr(cr->dd, lincsd->atoms[deviations.indexOfMaxDeviation].index2));
 
-                    lincs_warning(cr->dd, x, xprime, pbc, lincsd->nc, lincsd->atoms, lincsd->bllen,
-                                  ir.LincsWarnAngle, maxwarn, warncount);
+                    lincs_warning(
+                            cr->dd, x, xprime, pbc, lincsd->nc, lincsd->atoms, lincsd->bllen, ir.LincsWarnAngle, maxwarn, warncount);
                 }
                 bOK = (deviations.maxDeviation < 0.5);
             }
@@ -2453,8 +2481,17 @@ bool constrain_lincs(bool                            computeRmsd,
             {
                 int th = gmx_omp_get_thread_num();
 
-                do_lincsp(xPadded, xprimePadded, min_proj, pbc, lincsd, th, invmass, econq,
-                          bCalcDHDL, bCalcVir, th == 0 ? vir_r_m_dr : lincsd->task[th].vir_r_m_dr);
+                do_lincsp(xPadded,
+                          xprimePadded,
+                          min_proj,
+                          pbc,
+                          lincsd,
+                          th,
+                          invmass,
+                          econq,
+                          bCalcDHDL,
+                          bCalcVir,
+                          th == 0 ? vir_r_m_dr : lincsd->task[th].vir_r_m_dr);
             }
             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
         }
index 0b00370c018719e946f92c5f214b8d946579c0c2..fcaf91a9854cf9355dcda3e9d57ceff3f68552ce 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +61,10 @@ struct t_pbc;
 
 namespace gmx
 {
-
 template<typename>
 class ArrayRefWithPadding;
+template<typename>
+class ArrayRef;
 enum class ConstraintVariable : int;
 class Lincs;
 template<typename>
@@ -91,7 +92,7 @@ void done_lincs(Lincs* li);
 /*! \brief Initialize lincs stuff */
 void set_lincs(const InteractionDefinitions& idef,
                int                           numAtoms,
-               const real*                   invmass,
+               ArrayRef<const real>          invmass,
                real                          lambda,
                bool                          bDynamics,
                const t_commrec*              cr,
@@ -104,7 +105,7 @@ bool constrain_lincs(bool                            computeRmsd,
                      const t_inputrec&               ir,
                      int64_t                         step,
                      Lincs*                          lincsd,
-                     const real*                     invmass,
+                     ArrayRef<const real>            invmass,
                      const t_commrec*                cr,
                      const gmx_multisim_t*           ms,
                      ArrayRefWithPadding<const RVec> x,
similarity index 55%
rename from src/gromacs/mdlib/lincs_gpu.cu
rename to src/gromacs/mdlib/lincs_gpu.cpp
index edffc43821a5af85e58132e5707061383759704f..96c0b8fc32823ceaf32cbf07841cd1fe845ffb91 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  */
 /*! \internal \file
  *
- * \brief Implements LINCS using CUDA
+ * \brief Implementations of LINCS GPU class
  *
- * This file contains implementation of LINCS constraints algorithm
- * using CUDA, including class initialization, data-structures management
- * and GPU kernel.
+ * This file contains back-end agnostic implementation of LINCS GPU class.
  *
  * \author Artem Zhmurov <zhmurov@gmail.com>
  * \author Alan Gray <alang@nvidia.com>
@@ -47,7 +45,7 @@
  */
 #include "gmxpre.h"
 
-#include "lincs_gpu.cuh"
+#include "lincs_gpu.h"
 
 #include <assert.h>
 #include <stdio.h>
 
 #include <algorithm>
 
-#include "gromacs/gpu_utils/cuda_arch_utils.cuh"
-#include "gromacs/gpu_utils/cudautils.cuh"
-#include "gromacs/gpu_utils/devicebuffer.cuh"
-#include "gromacs/gpu_utils/gputraits.cuh"
-#include "gromacs/gpu_utils/vectype_ops.cuh"
+#include "gromacs/gpu_utils/devicebuffer.h"
+#include "gromacs/gpu_utils/gputraits.h"
+#include "gromacs/math/functions.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/constr.h"
+#include "gromacs/mdlib/lincs_gpu_internal.h"
 #include "gromacs/pbcutil/pbc.h"
-#include "gromacs/pbcutil/pbc_aiuc_cuda.cuh"
-#include "gromacs/topology/forcefieldparameters.h"
 #include "gromacs/topology/ifunc.h"
 #include "gromacs/topology/topology.h"
 
 namespace gmx
 {
 
-//! Number of CUDA threads in a block
-constexpr static int c_threadsPerBlock = 256;
-//! Maximum number of threads in a block (for __launch_bounds__)
-constexpr static int c_maxThreadsPerBlock = c_threadsPerBlock;
-
-/*! \brief Main kernel for LINCS constraints.
- *
- * See Hess et al., J. Comput. Chem. 18: 1463-1472 (1997) for the description of the algorithm.
- *
- * In CUDA version, one thread is responsible for all computations for one constraint. The blocks are
- * filled in a way that no constraint is coupled to the constraint from the next block. This is achieved
- * by moving active threads to the next block, if the correspondent group of coupled constraints is to big
- * to fit the current thread block. This may leave some 'dummy' threads in the end of the thread block, i.e.
- * threads that are not required to do actual work. Since constraints from different blocks are not coupled,
- * there is no need to synchronize across the device. However, extensive communication in a thread block
- * are still needed.
- *
- * \todo Reduce synchronization overhead. Some ideas are:
- *        1. Consider going to warp-level synchronization for the coupled constraints.
- *        2. Move more data to local/shared memory and try to get rid of atomic operations (at least on
- *           the device level).
- *        3. Use analytical solution for matrix A inversion.
- *        4. Introduce mapping of thread id to both single constraint and single atom, thus designating
- *           Nth threads to deal with Nat <= Nth coupled atoms and Nc <= Nth coupled constraints.
- *       See Issue #2885 for details (https://gitlab.com/gromacs/gromacs/-/issues/2885)
- * \todo The use of __restrict__  for gm_xp and gm_v causes failure, probably because of the atomic
-         operations. Investigate this issue further.
- *
- * \param[in,out] kernelParams  All parameters and pointers for the kernel condensed in single struct.
- * \param[in]     invdt         Inverse timestep (needed to update velocities).
- */
-template<bool updateVelocities, bool computeVirial>
-__launch_bounds__(c_maxThreadsPerBlock) __global__
-        void lincs_kernel(LincsGpuKernelParameters kernelParams,
-                          const float3* __restrict__ gm_x,
-                          float3*     gm_xp,
-                          float3*     gm_v,
-                          const float invdt)
-{
-    const PbcAiuc pbcAiuc                                 = kernelParams.pbcAiuc;
-    const int     numConstraintsThreads                   = kernelParams.numConstraintsThreads;
-    const int     numIterations                           = kernelParams.numIterations;
-    const int     expansionOrder                          = kernelParams.expansionOrder;
-    const int2* __restrict__ gm_constraints               = kernelParams.d_constraints;
-    const float* __restrict__ gm_constraintsTargetLengths = kernelParams.d_constraintsTargetLengths;
-    const int* __restrict__ gm_coupledConstraintsCounts   = kernelParams.d_coupledConstraintsCounts;
-    const int* __restrict__ gm_coupledConstraintsIdxes = kernelParams.d_coupledConstraintsIndices;
-    const float* __restrict__ gm_massFactors           = kernelParams.d_massFactors;
-    float* __restrict__ gm_matrixA                     = kernelParams.d_matrixA;
-    const float* __restrict__ gm_inverseMasses         = kernelParams.d_inverseMasses;
-    float* __restrict__ gm_virialScaled                = kernelParams.d_virialScaled;
-
-    int threadIndex = blockIdx.x * blockDim.x + threadIdx.x;
-
-    // numConstraintsThreads should be a integer multiple of blockSize (numConstraintsThreads = numBlocks*blockSize).
-    // This is to ensure proper synchronizations and reduction. All array are padded to the required size.
-    assert(threadIndex < numConstraintsThreads);
-
-    // Vectors connecting constrained atoms before algorithm was applied.
-    // Needed to construct constrain matrix A
-    extern __shared__ float3 sm_r[];
-
-    int2 pair = gm_constraints[threadIndex];
-    int  i    = pair.x;
-    int  j    = pair.y;
-
-    // Mass-scaled Lagrange multiplier
-    float lagrangeScaled = 0.0f;
-
-    float targetLength;
-    float inverseMassi;
-    float inverseMassj;
-    float sqrtReducedMass;
-
-    float3 xi;
-    float3 xj;
-    float3 rc;
-
-    // i == -1 indicates dummy constraint at the end of the thread block.
-    bool isDummyThread = (i == -1);
-
-    // Everything computed for these dummies will be equal to zero
-    if (isDummyThread)
-    {
-        targetLength    = 0.0f;
-        inverseMassi    = 0.0f;
-        inverseMassj    = 0.0f;
-        sqrtReducedMass = 0.0f;
-
-        xi = make_float3(0.0f, 0.0f, 0.0f);
-        xj = make_float3(0.0f, 0.0f, 0.0f);
-        rc = make_float3(0.0f, 0.0f, 0.0f);
-    }
-    else
-    {
-        // Collecting data
-        targetLength    = gm_constraintsTargetLengths[threadIndex];
-        inverseMassi    = gm_inverseMasses[i];
-        inverseMassj    = gm_inverseMasses[j];
-        sqrtReducedMass = rsqrt(inverseMassi + inverseMassj);
-
-        xi = gm_x[i];
-        xj = gm_x[j];
-
-        float3 dx = pbcDxAiuc(pbcAiuc, xi, xj);
-
-        float rlen = rsqrtf(dx.x * dx.x + dx.y * dx.y + dx.z * dx.z);
-        rc         = rlen * dx;
-    }
-
-    sm_r[threadIdx.x] = rc;
-    // Make sure that all r's are saved into shared memory
-    // before they are accessed in the loop below
-    __syncthreads();
-
-    /*
-     * Constructing LINCS matrix (A)
-     */
-
-    // Only non-zero values are saved (for coupled constraints)
-    int coupledConstraintsCount = gm_coupledConstraintsCounts[threadIndex];
-    for (int n = 0; n < coupledConstraintsCount; n++)
-    {
-        int index = n * numConstraintsThreads + threadIndex;
-        int c1    = gm_coupledConstraintsIdxes[index];
-
-        float3 rc1        = sm_r[c1 - blockIdx.x * blockDim.x];
-        gm_matrixA[index] = gm_massFactors[index] * (rc.x * rc1.x + rc.y * rc1.y + rc.z * rc1.z);
-    }
-
-    // Skipping in dummy threads
-    if (!isDummyThread)
-    {
-        xi = gm_xp[i];
-        xj = gm_xp[j];
-    }
-
-    float3 dx = pbcDxAiuc(pbcAiuc, xi, xj);
-
-    float sol = sqrtReducedMass * ((rc.x * dx.x + rc.y * dx.y + rc.z * dx.z) - targetLength);
-
-    /*
-     *  Inverse matrix using a set of expansionOrder matrix multiplications
-     */
-
-    // This will use the same memory space as sm_r, which is no longer needed.
-    extern __shared__ float sm_rhs[];
-    // Save current right-hand-side vector in the shared memory
-    sm_rhs[threadIdx.x] = sol;
-
-    for (int rec = 0; rec < expansionOrder; rec++)
-    {
-        // Making sure that all sm_rhs are saved before they are accessed in a loop below
-        __syncthreads();
-        float mvb = 0.0f;
-
-        for (int n = 0; n < coupledConstraintsCount; n++)
-        {
-            int index = n * numConstraintsThreads + threadIndex;
-            int c1    = gm_coupledConstraintsIdxes[index];
-            // Convolute current right-hand-side with A
-            // Different, non overlapping parts of sm_rhs[..] are read during odd and even iterations
-            mvb = mvb + gm_matrixA[index] * sm_rhs[c1 - blockIdx.x * blockDim.x + blockDim.x * (rec % 2)];
-        }
-        // 'Switch' rhs vectors, save current result
-        // These values will be accessed in the loop above during the next iteration.
-        sm_rhs[threadIdx.x + blockDim.x * ((rec + 1) % 2)] = mvb;
-        sol                                                = sol + mvb;
-    }
-
-    // Current mass-scaled Lagrange multipliers
-    lagrangeScaled = sqrtReducedMass * sol;
-
-    // Save updated coordinates before correction for the rotational lengthening
-    float3 tmp = rc * lagrangeScaled;
-
-    // Writing for all but dummy constraints
-    if (!isDummyThread)
-    {
-        atomicAdd(&gm_xp[i], -tmp * inverseMassi);
-        atomicAdd(&gm_xp[j], tmp * inverseMassj);
-    }
-
-    /*
-     *  Correction for centripetal effects
-     */
-    for (int iter = 0; iter < numIterations; iter++)
-    {
-        // Make sure that all xp's are saved: atomic operation calls before are
-        // communicating current xp[..] values across thread block.
-        __syncthreads();
-
-        if (!isDummyThread)
-        {
-            xi = gm_xp[i];
-            xj = gm_xp[j];
-        }
-
-        float3 dx = pbcDxAiuc(pbcAiuc, xi, xj);
-
-        float len2  = targetLength * targetLength;
-        float dlen2 = 2.0f * len2 - norm2(dx);
-
-        // TODO A little bit more effective but slightly less readable version of the below would be:
-        //      float proj = sqrtReducedMass*(targetLength - (dlen2 > 0.0f ? 1.0f : 0.0f)*dlen2*rsqrt(dlen2));
-        float proj;
-        if (dlen2 > 0.0f)
-        {
-            proj = sqrtReducedMass * (targetLength - dlen2 * rsqrt(dlen2));
-        }
-        else
-        {
-            proj = sqrtReducedMass * targetLength;
-        }
-
-        sm_rhs[threadIdx.x] = proj;
-        float sol           = proj;
-
-        /*
-         * Same matrix inversion as above is used for updated data
-         */
-        for (int rec = 0; rec < expansionOrder; rec++)
-        {
-            // Make sure that all elements of rhs are saved into shared memory
-            __syncthreads();
-            float mvb = 0;
-
-            for (int n = 0; n < coupledConstraintsCount; n++)
-            {
-                int index = n * numConstraintsThreads + threadIndex;
-                int c1    = gm_coupledConstraintsIdxes[index];
-
-                mvb = mvb + gm_matrixA[index] * sm_rhs[c1 - blockIdx.x * blockDim.x + blockDim.x * (rec % 2)];
-            }
-            sm_rhs[threadIdx.x + blockDim.x * ((rec + 1) % 2)] = mvb;
-            sol                                                = sol + mvb;
-        }
-
-        // Add corrections to Lagrange multipliers
-        float sqrtmu_sol = sqrtReducedMass * sol;
-        lagrangeScaled += sqrtmu_sol;
-
-        // Save updated coordinates for the next iteration
-        // Dummy constraints are skipped
-        if (!isDummyThread)
-        {
-            float3 tmp = rc * sqrtmu_sol;
-            atomicAdd(&gm_xp[i], -tmp * inverseMassi);
-            atomicAdd(&gm_xp[j], tmp * inverseMassj);
-        }
-    }
-
-    // Updating particle velocities for all but dummy threads
-    if (updateVelocities && !isDummyThread)
-    {
-        float3 tmp = rc * invdt * lagrangeScaled;
-        atomicAdd(&gm_v[i], -tmp * inverseMassi);
-        atomicAdd(&gm_v[j], tmp * inverseMassj);
-    }
-
-
-    if (computeVirial)
-    {
-        // Virial is computed from Lagrange multiplier (lagrangeScaled), target constrain length
-        // (targetLength) and the normalized vector connecting constrained atoms before
-        // the algorithm was applied (rc). The evaluation of virial in each thread is
-        // followed by basic reduction for the values inside single thread block.
-        // Then, the values are reduced across grid by atomicAdd(...).
-        //
-        // TODO Shuffle reduction.
-        // TODO Should be unified and/or done once when virial is actually needed.
-        // TODO Recursive version that removes atomicAdd(...)'s entirely is needed. Ideally,
-        //      one that works for any datatype.
-
-        // Save virial for each thread into the shared memory. Tensor is symmetrical, hence only
-        // 6 values are saved. Dummy threads will have zeroes in their virial: targetLength,
-        // lagrangeScaled and rc are all set to zero for them in the beginning of the kernel.
-        // The sm_threadVirial[..] will overlap with the sm_r[..] and sm_rhs[..], but the latter
-        // two are no longer in use.
-        extern __shared__ float sm_threadVirial[];
-        float                   mult                  = targetLength * lagrangeScaled;
-        sm_threadVirial[0 * blockDim.x + threadIdx.x] = mult * rc.x * rc.x;
-        sm_threadVirial[1 * blockDim.x + threadIdx.x] = mult * rc.x * rc.y;
-        sm_threadVirial[2 * blockDim.x + threadIdx.x] = mult * rc.x * rc.z;
-        sm_threadVirial[3 * blockDim.x + threadIdx.x] = mult * rc.y * rc.y;
-        sm_threadVirial[4 * blockDim.x + threadIdx.x] = mult * rc.y * rc.z;
-        sm_threadVirial[5 * blockDim.x + threadIdx.x] = mult * rc.z * rc.z;
-
-        __syncthreads();
-
-        // Reduce up to one virial per thread block. All blocks are divided by half, the first
-        // half of threads sums two virials. Then the first half is divided by two and the first
-        // half of it sums two values. This procedure is repeated until only one thread is left.
-        // Only works if the threads per blocks is a power of two (hence static_assert
-        // in the beginning of the kernel).
-        for (int divideBy = 2; divideBy <= static_cast<int>(blockDim.x); divideBy *= 2)
-        {
-            int dividedAt = blockDim.x / divideBy;
-            if (static_cast<int>(threadIdx.x) < dividedAt)
-            {
-                for (int d = 0; d < 6; d++)
-                {
-                    sm_threadVirial[d * blockDim.x + threadIdx.x] +=
-                            sm_threadVirial[d * blockDim.x + (threadIdx.x + dividedAt)];
-                }
-            }
-            // Syncronize if not within one warp
-            if (dividedAt > warpSize / 2)
-            {
-                __syncthreads();
-            }
-        }
-        // First 6 threads in the block add the results of 6 tensor components to the global memory address.
-        if (threadIdx.x < 6)
-        {
-            atomicAdd(&(gm_virialScaled[threadIdx.x]), sm_threadVirial[threadIdx.x * blockDim.x]);
-        }
-    }
-
-    return;
-}
-
-/*! \brief Select templated kernel.
- *
- * Returns pointer to a CUDA kernel based on provided booleans.
- *
- * \param[in] updateVelocities  If the velocities should be constrained.
- * \param[in] computeVirial     If virial should be updated.
- *
- * \return                      Pointer to CUDA kernel
- */
-inline auto getLincsKernelPtr(const bool updateVelocities, const bool computeVirial)
+void LincsGpu::apply(const DeviceBuffer<Float3> d_x,
+                     DeviceBuffer<Float3>       d_xp,
+                     const bool                 updateVelocities,
+                     DeviceBuffer<Float3>       d_v,
+                     const real                 invdt,
+                     const bool                 computeVirial,
+                     tensor                     virialScaled,
+                     const PbcAiuc              pbcAiuc)
 {
-
-    auto kernelPtr = lincs_kernel<true, true>;
-    if (updateVelocities && computeVirial)
-    {
-        kernelPtr = lincs_kernel<true, true>;
-    }
-    else if (updateVelocities && !computeVirial)
-    {
-        kernelPtr = lincs_kernel<true, false>;
-    }
-    else if (!updateVelocities && computeVirial)
-    {
-        kernelPtr = lincs_kernel<false, true>;
-    }
-    else if (!updateVelocities && !computeVirial)
-    {
-        kernelPtr = lincs_kernel<false, false>;
-    }
-    return kernelPtr;
-}
-
-void LincsGpu::apply(const float3* d_x,
-                     float3*       d_xp,
-                     const bool    updateVelocities,
-                     float3*       d_v,
-                     const real    invdt,
-                     const bool    computeVirial,
-                     tensor        virialScaled,
-                     const PbcAiuc pbcAiuc)
-{
-    ensureNoPendingDeviceError("In CUDA version of LINCS");
+    GMX_ASSERT(GMX_GPU_CUDA, "LINCS GPU is only implemented in CUDA.");
 
     // Early exit if no constraints
     if (kernelParams_.numConstraintsThreads == 0)
@@ -450,45 +91,21 @@ void LincsGpu::apply(const float3* d_x,
         clearDeviceBufferAsync(&kernelParams_.d_virialScaled, 0, 6, deviceStream_);
     }
 
-    auto kernelPtr = getLincsKernelPtr(updateVelocities, computeVirial);
-
-    KernelLaunchConfig config;
-    config.blockSize[0] = c_threadsPerBlock;
-    config.blockSize[1] = 1;
-    config.blockSize[2] = 1;
-    config.gridSize[0] = (kernelParams_.numConstraintsThreads + c_threadsPerBlock - 1) / c_threadsPerBlock;
-    config.gridSize[1] = 1;
-    config.gridSize[2] = 1;
-
-    // Shared memory is used to store:
-    // -- Current coordinates (3 floats per thread)
-    // -- Right-hand-sides for matrix inversion (2 floats per thread)
-    // -- Virial tensor components (6 floats per thread)
-    // Since none of these three are needed simultaneously, they can be saved at the same shared memory address
-    // (i.e. correspondent arrays are intentionally overlapped in address space). Consequently, only
-    // max{3, 2, 6} = 6 floats per thread are needed in case virial is computed, or max{3, 2} = 3 if not.
-    if (computeVirial)
-    {
-        config.sharedMemorySize = c_threadsPerBlock * 6 * sizeof(float);
-    }
-    else
-    {
-        config.sharedMemorySize = c_threadsPerBlock * 3 * sizeof(float);
-    }
-
     kernelParams_.pbcAiuc = pbcAiuc;
 
-    const auto kernelArgs =
-            prepareGpuKernelArguments(kernelPtr, config, &kernelParams_, &d_x, &d_xp, &d_v, &invdt);
-
-    launchGpuKernel(kernelPtr, config, deviceStream_, nullptr,
-                    "lincs_kernel<updateVelocities, computeVirial>", kernelArgs);
+    launchLincsGpuKernel(
+            kernelParams_, d_x, d_xp, updateVelocities, d_v, invdt, computeVirial, deviceStream_);
 
     if (computeVirial)
     {
         // Copy LINCS virial data and add it to the common virial
-        copyFromDeviceBuffer(h_virialScaled_.data(), &kernelParams_.d_virialScaled, 0, 6,
-                             deviceStream_, GpuApiCallBehavior::Sync, nullptr);
+        copyFromDeviceBuffer(h_virialScaled_.data(),
+                             &kernelParams_.d_virialScaled,
+                             0,
+                             6,
+                             deviceStream_,
+                             GpuApiCallBehavior::Sync,
+                             nullptr);
 
         // Mapping [XX, XY, XZ, YY, YZ, ZZ] internal format to a tensor object
         virialScaled[XX][XX] += h_virialScaled_[0];
@@ -514,13 +131,14 @@ LincsGpu::LincsGpu(int                  numIterations,
     deviceContext_(deviceContext),
     deviceStream_(deviceStream)
 {
+    GMX_RELEASE_ASSERT(GMX_GPU_CUDA, "LINCS GPU is only implemented in CUDA.");
     kernelParams_.numIterations  = numIterations;
     kernelParams_.expansionOrder = expansionOrder;
 
     static_assert(sizeof(real) == sizeof(float),
                   "Real numbers should be in single precision in GPU code.");
     static_assert(
-            c_threadsPerBlock > 0 && ((c_threadsPerBlock & (c_threadsPerBlock - 1)) == 0),
+            gmx::isPowerOfTwo(c_threadsPerBlock),
             "Number of threads per block should be a power of two in order for reduction to work.");
 
     allocateDeviceBuffer(&kernelParams_.d_virialScaled, 6, deviceContext_);
@@ -627,7 +245,8 @@ inline int countCoupled(int           a,
             numCoupledConstraints[c2] = 0; // To indicate we've been here
             counted += 1
                        + countCoupled(adjacentAtom.indexOfSecondConstrainedAtom_,
-                                      numCoupledConstraints, atomsAdjacencyList);
+                                      numCoupledConstraints,
+                                      atomsAdjacencyList);
         }
     }
     return counted;
@@ -645,7 +264,7 @@ inline int countCoupled(int           a,
  * \param[in]     iatoms              The list of constraints.
  * \param[in]     stride              Number of elements per constraint in \p iatoms.
  * \param[in]     atomsAdjacencyList  Information about connections between atoms.
- * \param[our]    splitMap            Map of sequential constraint indexes to indexes to be on the device
+ * \param[out]    splitMap            Map of sequential constraint indexes to indexes to be on the device
  * \param[in]     c                   Sequential index for constraint to consider adding.
  * \param[in,out] currentMapIndex     The rolling index for the constraints mapping.
  */
@@ -727,8 +346,9 @@ bool LincsGpu::isNumCoupledConstraintsSupported(const gmx_mtop_t& mtop)
 
 void LincsGpu::set(const InteractionDefinitions& idef, const int numAtoms, const real* invmass)
 {
+    GMX_RELEASE_ASSERT(GMX_GPU_CUDA, "LINCS GPU is only implemented in CUDA.");
     // List of constrained atoms (CPU memory)
-    std::vector<int2> constraintsHost;
+    std::vector<AtomPair> constraintsHost;
     // Equilibrium distances for the constraints (CPU)
     std::vector<float> constraintsTargetLengthsHost;
     // Number of constraints, coupled with the current one (CPU)
@@ -771,7 +391,8 @@ void LincsGpu::set(const InteractionDefinitions& idef, const int numAtoms, const
                       "LINCS with constraints on all-bonds, which is not supported for large "
                       "molecules. When compatible with the force field and integration settings, "
                       "using constraints on H-bonds only.",
-                      numCoupledConstraints.at(c), c_threadsPerBlock);
+                      numCoupledConstraints.at(c),
+                      c_threadsPerBlock);
         }
         if (currentMapIndex / c_threadsPerBlock
             != (currentMapIndex + numCoupledConstraints.at(c)) / c_threadsPerBlock)
@@ -787,9 +408,9 @@ void LincsGpu::set(const InteractionDefinitions& idef, const int numAtoms, const
                        "Number of threads should be a multiple of the block size");
 
     // Initialize constraints and their target indexes taking into account the splits in the data arrays.
-    int2 pair;
-    pair.x = -1;
-    pair.y = -1;
+    AtomPair pair;
+    pair.i = -1;
+    pair.j = -1;
     constraintsHost.resize(kernelParams_.numConstraintsThreads, pair);
     std::fill(constraintsHost.begin(), constraintsHost.end(), pair);
     constraintsTargetLengthsHost.resize(kernelParams_.numConstraintsThreads, 0.0);
@@ -800,9 +421,9 @@ void LincsGpu::set(const InteractionDefinitions& idef, const int numAtoms, const
         int a2   = iatoms[stride * c + 2];
         int type = iatoms[stride * c];
 
-        int2 pair;
-        pair.x                                          = a1;
-        pair.y                                          = a2;
+        AtomPair pair;
+        pair.i                                          = a1;
+        pair.j                                          = a2;
         constraintsHost.at(splitMap.at(c))              = pair;
         constraintsTargetLengthsHost.at(splitMap.at(c)) = idef.iparams[type].constr.dA;
     }
@@ -916,19 +537,24 @@ void LincsGpu::set(const InteractionDefinitions& idef, const int numAtoms, const
 
         numConstraintsThreadsAlloc_ = kernelParams_.numConstraintsThreads;
 
-        allocateDeviceBuffer(&kernelParams_.d_constraints, kernelParams_.numConstraintsThreads,
-                             deviceContext_);
+        allocateDeviceBuffer(
+                &kernelParams_.d_constraints, kernelParams_.numConstraintsThreads, deviceContext_);
         allocateDeviceBuffer(&kernelParams_.d_constraintsTargetLengths,
-                             kernelParams_.numConstraintsThreads, deviceContext_);
+                             kernelParams_.numConstraintsThreads,
+                             deviceContext_);
 
         allocateDeviceBuffer(&kernelParams_.d_coupledConstraintsCounts,
-                             kernelParams_.numConstraintsThreads, deviceContext_);
+                             kernelParams_.numConstraintsThreads,
+                             deviceContext_);
         allocateDeviceBuffer(&kernelParams_.d_coupledConstraintsIndices,
-                             maxCoupledConstraints * kernelParams_.numConstraintsThreads, deviceContext_);
+                             maxCoupledConstraints * kernelParams_.numConstraintsThreads,
+                             deviceContext_);
         allocateDeviceBuffer(&kernelParams_.d_massFactors,
-                             maxCoupledConstraints * kernelParams_.numConstraintsThreads, deviceContext_);
+                             maxCoupledConstraints * kernelParams_.numConstraintsThreads,
+                             deviceContext_);
         allocateDeviceBuffer(&kernelParams_.d_matrixA,
-                             maxCoupledConstraints * kernelParams_.numConstraintsThreads, deviceContext_);
+                             maxCoupledConstraints * kernelParams_.numConstraintsThreads,
+                             deviceContext_);
     }
 
     // (Re)allocate the memory, if the number of atoms has increased.
@@ -943,25 +569,45 @@ void LincsGpu::set(const InteractionDefinitions& idef, const int numAtoms, const
     }
 
     // Copy data to GPU.
-    copyToDeviceBuffer(&kernelParams_.d_constraints, constraintsHost.data(), 0,
-                       kernelParams_.numConstraintsThreads, deviceStream_, GpuApiCallBehavior::Sync,
+    copyToDeviceBuffer(&kernelParams_.d_constraints,
+                       constraintsHost.data(),
+                       0,
+                       kernelParams_.numConstraintsThreads,
+                       deviceStream_,
+                       GpuApiCallBehavior::Sync,
                        nullptr);
     copyToDeviceBuffer(&kernelParams_.d_constraintsTargetLengths,
-                       constraintsTargetLengthsHost.data(), 0, kernelParams_.numConstraintsThreads,
-                       deviceStream_, GpuApiCallBehavior::Sync, nullptr);
+                       constraintsTargetLengthsHost.data(),
+                       0,
+                       kernelParams_.numConstraintsThreads,
+                       deviceStream_,
+                       GpuApiCallBehavior::Sync,
+                       nullptr);
     copyToDeviceBuffer(&kernelParams_.d_coupledConstraintsCounts,
-                       coupledConstraintsCountsHost.data(), 0, kernelParams_.numConstraintsThreads,
-                       deviceStream_, GpuApiCallBehavior::Sync, nullptr);
-    copyToDeviceBuffer(&kernelParams_.d_coupledConstraintsIndices, coupledConstraintsIndicesHost.data(),
-                       0, maxCoupledConstraints * kernelParams_.numConstraintsThreads,
-                       deviceStream_, GpuApiCallBehavior::Sync, nullptr);
-    copyToDeviceBuffer(&kernelParams_.d_massFactors, massFactorsHost.data(), 0,
-                       maxCoupledConstraints * kernelParams_.numConstraintsThreads, deviceStream_,
-                       GpuApiCallBehavior::Sync, nullptr);
+                       coupledConstraintsCountsHost.data(),
+                       0,
+                       kernelParams_.numConstraintsThreads,
+                       deviceStream_,
+                       GpuApiCallBehavior::Sync,
+                       nullptr);
+    copyToDeviceBuffer(&kernelParams_.d_coupledConstraintsIndices,
+                       coupledConstraintsIndicesHost.data(),
+                       0,
+                       maxCoupledConstraints * kernelParams_.numConstraintsThreads,
+                       deviceStream_,
+                       GpuApiCallBehavior::Sync,
+                       nullptr);
+    copyToDeviceBuffer(&kernelParams_.d_massFactors,
+                       massFactorsHost.data(),
+                       0,
+                       maxCoupledConstraints * kernelParams_.numConstraintsThreads,
+                       deviceStream_,
+                       GpuApiCallBehavior::Sync,
+                       nullptr);
 
     GMX_RELEASE_ASSERT(invmass != nullptr, "Masses of atoms should be specified.\n");
-    copyToDeviceBuffer(&kernelParams_.d_inverseMasses, invmass, 0, numAtoms, deviceStream_,
-                       GpuApiCallBehavior::Sync, nullptr);
+    copyToDeviceBuffer(
+            &kernelParams_.d_inverseMasses, invmass, 0, numAtoms, deviceStream_, GpuApiCallBehavior::Sync, nullptr);
 }
 
 } // namespace gmx
similarity index 87%
rename from src/gromacs/mdlib/lincs_gpu.cuh
rename to src/gromacs/mdlib/lincs_gpu.h
index 7dfa2deb82a07c8e21eeb05bb1c6943ec5d066ce..3ed6cd3e59eed7f6df9ae75add2c14624f7420a0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_MDLIB_LINCS_GPU_CUH
 #define GMX_MDLIB_LINCS_GPU_CUH
 
+#include <memory>
+
+#include "gromacs/gpu_utils/devicebuffer_datatype.h"
 #include "gromacs/gpu_utils/device_context.h"
 #include "gromacs/gpu_utils/device_stream.h"
-#include "gromacs/gpu_utils/gputraits.cuh"
+#include "gromacs/gpu_utils/gputraits.h"
 #include "gromacs/mdlib/constr.h"
 #include "gromacs/pbcutil/pbc_aiuc.h"
-#include "gromacs/utility/classhelpers.h"
 
 class InteractionDefinitions;
 
 namespace gmx
 {
 
+//! A pair of atoms indexes
+struct AtomPair
+{
+    //! First atom
+    int i;
+    //! Second atom
+    int j;
+};
+
 /* \brief LINCS parameters and GPU pointers
  *
  * This is used to accumulate all the parameters and pointers so they can be passed
@@ -71,9 +82,9 @@ struct LincsGpuKernelParameters
     //! Number of iterations used to correct the projection
     int numIterations;
     //! 1/mass for all atoms (GPU)
-    float* d_inverseMasses;
+    DeviceBuffer<float> d_inverseMasses;
     //! Scaled virial tensor (6 floats: [XX, XY, XZ, YY, YZ, ZZ], GPU)
-    float* d_virialScaled;
+    DeviceBuffer<float> d_virialScaled;
     /*! \brief Total number of threads.
      *
      *  This covers all constraints and gaps in the ends of the thread blocks
@@ -82,17 +93,17 @@ struct LincsGpuKernelParameters
      */
     int numConstraintsThreads;
     //! List of constrained atoms (GPU memory)
-    int2* d_constraints;
+    DeviceBuffer<AtomPair> d_constraints;
     //! Equilibrium distances for the constraints (GPU)
-    float* d_constraintsTargetLengths;
+    DeviceBuffer<float> d_constraintsTargetLengths;
     //! Number of constraints, coupled with the current one (GPU)
-    int* d_coupledConstraintsCounts;
+    DeviceBuffer<int> d_coupledConstraintsCounts;
     //! List of coupled with the current one (GPU)
-    int* d_coupledConstraintsIndices;
+    DeviceBuffer<int> d_coupledConstraintsIndices;
     //! Elements of the coupling matrix.
-    float* d_matrixA;
+    DeviceBuffer<float> d_matrixA;
     //! Mass factors (GPU)
-    float* d_massFactors;
+    DeviceBuffer<float> d_massFactors;
 };
 
 /*! \internal \brief Class with interfaces and data for GPU version of LINCS. */
@@ -133,14 +144,14 @@ public:
      * \param[in,out] virialScaled      Scaled virial tensor to be updated.
      * \param[in]     pbcAiuc           PBC data.
      */
-    void apply(const float3* d_x,
-               float3*       d_xp,
-               const bool    updateVelocities,
-               float3*       d_v,
-               const real    invdt,
-               const bool    computeVirial,
-               tensor        virialScaled,
-               const PbcAiuc pbcAiuc);
+    void apply(const DeviceBuffer<Float3> d_x,
+               DeviceBuffer<Float3>       d_xp,
+               const bool                 updateVelocities,
+               DeviceBuffer<Float3>       d_v,
+               const real                 invdt,
+               const bool                 computeVirial,
+               tensor                     virialScaled,
+               const PbcAiuc              pbcAiuc);
 
     /*! \brief
      * Update data-structures (e.g. after NB search step).
diff --git a/src/gromacs/mdlib/lincs_gpu_internal.cu b/src/gromacs/mdlib/lincs_gpu_internal.cu
new file mode 100644 (file)
index 0000000..55d4b48
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 LINCS kernels using CUDA
+ *
+ * This file contains CUDA kernels of LINCS constraints algorithm.
+ *
+ * \author Artem Zhmurov <zhmurov@gmail.com>
+ * \author Alan Gray <alang@nvidia.com>
+ *
+ * \ingroup module_mdlib
+ */
+#include "gromacs/gpu_utils/cuda_arch_utils.cuh"
+#include "gromacs/gpu_utils/cudautils.cuh"
+#include "gromacs/gpu_utils/devicebuffer.cuh"
+#include "gromacs/gpu_utils/gputraits.h"
+#include "gromacs/gpu_utils/typecasts.cuh"
+#include "gromacs/gpu_utils/vectype_ops.cuh"
+#include "gromacs/mdlib/lincs_gpu.h"
+#include "gromacs/pbcutil/pbc_aiuc_cuda.cuh"
+
+#include "lincs_gpu_internal.h"
+
+namespace gmx
+{
+
+//! Maximum number of threads in a block (for __launch_bounds__)
+constexpr static int c_maxThreadsPerBlock = c_threadsPerBlock;
+
+/*! \brief Main kernel for LINCS constraints.
+ *
+ * See Hess et al., J. Comput. Chem. 18: 1463-1472 (1997) for the description of the algorithm.
+ *
+ * In CUDA version, one thread is responsible for all computations for one constraint. The blocks are
+ * filled in a way that no constraint is coupled to the constraint from the next block. This is achieved
+ * by moving active threads to the next block, if the correspondent group of coupled constraints is to big
+ * to fit the current thread block. This may leave some 'dummy' threads in the end of the thread block, i.e.
+ * threads that are not required to do actual work. Since constraints from different blocks are not coupled,
+ * there is no need to synchronize across the device. However, extensive communication in a thread block
+ * are still needed.
+ *
+ * \todo Reduce synchronization overhead. Some ideas are:
+ *        1. Consider going to warp-level synchronization for the coupled constraints.
+ *        2. Move more data to local/shared memory and try to get rid of atomic operations (at least on
+ *           the device level).
+ *        3. Use analytical solution for matrix A inversion.
+ *        4. Introduce mapping of thread id to both single constraint and single atom, thus designating
+ *           Nth threads to deal with Nat <= Nth coupled atoms and Nc <= Nth coupled constraints.
+ *       See Issue #2885 for details (https://gitlab.com/gromacs/gromacs/-/issues/2885)
+ * \todo The use of __restrict__  for gm_xp and gm_v causes failure, probably because of the atomic
+         operations. Investigate this issue further.
+ *
+ * \param[in,out] kernelParams  All parameters and pointers for the kernel condensed in single struct.
+ * \param[in]     invdt         Inverse timestep (needed to update velocities).
+ */
+template<bool updateVelocities, bool computeVirial>
+__launch_bounds__(c_maxThreadsPerBlock) __global__
+        void lincs_kernel(LincsGpuKernelParameters kernelParams,
+                          const float3* __restrict__ gm_x,
+                          float3*     gm_xp,
+                          float3*     gm_v,
+                          const float invdt)
+{
+    const PbcAiuc pbcAiuc                                 = kernelParams.pbcAiuc;
+    const int     numConstraintsThreads                   = kernelParams.numConstraintsThreads;
+    const int     numIterations                           = kernelParams.numIterations;
+    const int     expansionOrder                          = kernelParams.expansionOrder;
+    const AtomPair* __restrict__ gm_constraints           = kernelParams.d_constraints;
+    const float* __restrict__ gm_constraintsTargetLengths = kernelParams.d_constraintsTargetLengths;
+    const int* __restrict__ gm_coupledConstraintsCounts   = kernelParams.d_coupledConstraintsCounts;
+    const int* __restrict__ gm_coupledConstraintsIdxes = kernelParams.d_coupledConstraintsIndices;
+    const float* __restrict__ gm_massFactors           = kernelParams.d_massFactors;
+    float* __restrict__ gm_matrixA                     = kernelParams.d_matrixA;
+    const float* __restrict__ gm_inverseMasses         = kernelParams.d_inverseMasses;
+    float* __restrict__ gm_virialScaled                = kernelParams.d_virialScaled;
+
+    int threadIndex = blockIdx.x * blockDim.x + threadIdx.x;
+
+    // numConstraintsThreads should be a integer multiple of blockSize (numConstraintsThreads = numBlocks*blockSize).
+    // This is to ensure proper synchronizations and reduction. All array are padded to the required size.
+    assert(threadIndex < numConstraintsThreads);
+
+    // Vectors connecting constrained atoms before algorithm was applied.
+    // Needed to construct constrain matrix A
+    extern __shared__ float3 sm_r[];
+
+    AtomPair pair = gm_constraints[threadIndex];
+    int      i    = pair.i;
+    int      j    = pair.j;
+
+    // Mass-scaled Lagrange multiplier
+    float lagrangeScaled = 0.0f;
+
+    float targetLength;
+    float inverseMassi;
+    float inverseMassj;
+    float sqrtReducedMass;
+
+    float3 xi;
+    float3 xj;
+    float3 rc;
+
+    // i == -1 indicates dummy constraint at the end of the thread block.
+    bool isDummyThread = (i == -1);
+
+    // Everything computed for these dummies will be equal to zero
+    if (isDummyThread)
+    {
+        targetLength    = 0.0f;
+        inverseMassi    = 0.0f;
+        inverseMassj    = 0.0f;
+        sqrtReducedMass = 0.0f;
+
+        xi = make_float3(0.0f, 0.0f, 0.0f);
+        xj = make_float3(0.0f, 0.0f, 0.0f);
+        rc = make_float3(0.0f, 0.0f, 0.0f);
+    }
+    else
+    {
+        // Collecting data
+        targetLength    = gm_constraintsTargetLengths[threadIndex];
+        inverseMassi    = gm_inverseMasses[i];
+        inverseMassj    = gm_inverseMasses[j];
+        sqrtReducedMass = rsqrt(inverseMassi + inverseMassj);
+
+        xi = gm_x[i];
+        xj = gm_x[j];
+
+        float3 dx = pbcDxAiuc(pbcAiuc, xi, xj);
+
+        float rlen = rsqrtf(dx.x * dx.x + dx.y * dx.y + dx.z * dx.z);
+        rc         = rlen * dx;
+    }
+
+    sm_r[threadIdx.x] = rc;
+    // Make sure that all r's are saved into shared memory
+    // before they are accessed in the loop below
+    __syncthreads();
+
+    /*
+     * Constructing LINCS matrix (A)
+     */
+
+    // Only non-zero values are saved (for coupled constraints)
+    int coupledConstraintsCount = gm_coupledConstraintsCounts[threadIndex];
+    for (int n = 0; n < coupledConstraintsCount; n++)
+    {
+        int index = n * numConstraintsThreads + threadIndex;
+        int c1    = gm_coupledConstraintsIdxes[index];
+
+        float3 rc1        = sm_r[c1 - blockIdx.x * blockDim.x];
+        gm_matrixA[index] = gm_massFactors[index] * (rc.x * rc1.x + rc.y * rc1.y + rc.z * rc1.z);
+    }
+
+    // Skipping in dummy threads
+    if (!isDummyThread)
+    {
+        xi = gm_xp[i];
+        xj = gm_xp[j];
+    }
+
+    float3 dx = pbcDxAiuc(pbcAiuc, xi, xj);
+
+    float sol = sqrtReducedMass * ((rc.x * dx.x + rc.y * dx.y + rc.z * dx.z) - targetLength);
+
+    /*
+     *  Inverse matrix using a set of expansionOrder matrix multiplications
+     */
+
+    // This will use the same memory space as sm_r, which is no longer needed.
+    extern __shared__ float sm_rhs[];
+    // Save current right-hand-side vector in the shared memory
+    sm_rhs[threadIdx.x] = sol;
+
+    for (int rec = 0; rec < expansionOrder; rec++)
+    {
+        // Making sure that all sm_rhs are saved before they are accessed in a loop below
+        __syncthreads();
+        float mvb = 0.0f;
+
+        for (int n = 0; n < coupledConstraintsCount; n++)
+        {
+            int index = n * numConstraintsThreads + threadIndex;
+            int c1    = gm_coupledConstraintsIdxes[index];
+            // Convolute current right-hand-side with A
+            // Different, non overlapping parts of sm_rhs[..] are read during odd and even iterations
+            mvb = mvb + gm_matrixA[index] * sm_rhs[c1 - blockIdx.x * blockDim.x + blockDim.x * (rec % 2)];
+        }
+        // 'Switch' rhs vectors, save current result
+        // These values will be accessed in the loop above during the next iteration.
+        sm_rhs[threadIdx.x + blockDim.x * ((rec + 1) % 2)] = mvb;
+        sol                                                = sol + mvb;
+    }
+
+    // Current mass-scaled Lagrange multipliers
+    lagrangeScaled = sqrtReducedMass * sol;
+
+    // Save updated coordinates before correction for the rotational lengthening
+    float3 tmp = rc * lagrangeScaled;
+
+    // Writing for all but dummy constraints
+    if (!isDummyThread)
+    {
+        atomicAdd(&gm_xp[i], -tmp * inverseMassi);
+        atomicAdd(&gm_xp[j], tmp * inverseMassj);
+    }
+
+    /*
+     *  Correction for centripetal effects
+     */
+    for (int iter = 0; iter < numIterations; iter++)
+    {
+        // Make sure that all xp's are saved: atomic operation calls before are
+        // communicating current xp[..] values across thread block.
+        __syncthreads();
+
+        if (!isDummyThread)
+        {
+            xi = gm_xp[i];
+            xj = gm_xp[j];
+        }
+
+        float3 dx = pbcDxAiuc(pbcAiuc, xi, xj);
+
+        float len2  = targetLength * targetLength;
+        float dlen2 = 2.0f * len2 - norm2(dx);
+
+        // TODO A little bit more effective but slightly less readable version of the below would be:
+        //      float proj = sqrtReducedMass*(targetLength - (dlen2 > 0.0f ? 1.0f : 0.0f)*dlen2*rsqrt(dlen2));
+        float proj;
+        if (dlen2 > 0.0f)
+        {
+            proj = sqrtReducedMass * (targetLength - dlen2 * rsqrt(dlen2));
+        }
+        else
+        {
+            proj = sqrtReducedMass * targetLength;
+        }
+
+        sm_rhs[threadIdx.x] = proj;
+        float sol           = proj;
+
+        /*
+         * Same matrix inversion as above is used for updated data
+         */
+        for (int rec = 0; rec < expansionOrder; rec++)
+        {
+            // Make sure that all elements of rhs are saved into shared memory
+            __syncthreads();
+            float mvb = 0;
+
+            for (int n = 0; n < coupledConstraintsCount; n++)
+            {
+                int index = n * numConstraintsThreads + threadIndex;
+                int c1    = gm_coupledConstraintsIdxes[index];
+
+                mvb = mvb + gm_matrixA[index] * sm_rhs[c1 - blockIdx.x * blockDim.x + blockDim.x * (rec % 2)];
+            }
+            sm_rhs[threadIdx.x + blockDim.x * ((rec + 1) % 2)] = mvb;
+            sol                                                = sol + mvb;
+        }
+
+        // Add corrections to Lagrange multipliers
+        float sqrtmu_sol = sqrtReducedMass * sol;
+        lagrangeScaled += sqrtmu_sol;
+
+        // Save updated coordinates for the next iteration
+        // Dummy constraints are skipped
+        if (!isDummyThread)
+        {
+            float3 tmp = rc * sqrtmu_sol;
+            atomicAdd(&gm_xp[i], -tmp * inverseMassi);
+            atomicAdd(&gm_xp[j], tmp * inverseMassj);
+        }
+    }
+
+    // Updating particle velocities for all but dummy threads
+    if (updateVelocities && !isDummyThread)
+    {
+        float3 tmp = rc * invdt * lagrangeScaled;
+        atomicAdd(&gm_v[i], -tmp * inverseMassi);
+        atomicAdd(&gm_v[j], tmp * inverseMassj);
+    }
+
+
+    if (computeVirial)
+    {
+        // Virial is computed from Lagrange multiplier (lagrangeScaled), target constrain length
+        // (targetLength) and the normalized vector connecting constrained atoms before
+        // the algorithm was applied (rc). The evaluation of virial in each thread is
+        // followed by basic reduction for the values inside single thread block.
+        // Then, the values are reduced across grid by atomicAdd(...).
+        //
+        // TODO Shuffle reduction.
+        // TODO Should be unified and/or done once when virial is actually needed.
+        // TODO Recursive version that removes atomicAdd(...)'s entirely is needed. Ideally,
+        //      one that works for any datatype.
+
+        // Save virial for each thread into the shared memory. Tensor is symmetrical, hence only
+        // 6 values are saved. Dummy threads will have zeroes in their virial: targetLength,
+        // lagrangeScaled and rc are all set to zero for them in the beginning of the kernel.
+        // The sm_threadVirial[..] will overlap with the sm_r[..] and sm_rhs[..], but the latter
+        // two are no longer in use.
+        extern __shared__ float sm_threadVirial[];
+        float                   mult                  = targetLength * lagrangeScaled;
+        sm_threadVirial[0 * blockDim.x + threadIdx.x] = mult * rc.x * rc.x;
+        sm_threadVirial[1 * blockDim.x + threadIdx.x] = mult * rc.x * rc.y;
+        sm_threadVirial[2 * blockDim.x + threadIdx.x] = mult * rc.x * rc.z;
+        sm_threadVirial[3 * blockDim.x + threadIdx.x] = mult * rc.y * rc.y;
+        sm_threadVirial[4 * blockDim.x + threadIdx.x] = mult * rc.y * rc.z;
+        sm_threadVirial[5 * blockDim.x + threadIdx.x] = mult * rc.z * rc.z;
+
+        __syncthreads();
+
+        // Reduce up to one virial per thread block. All blocks are divided by half, the first
+        // half of threads sums two virials. Then the first half is divided by two and the first
+        // half of it sums two values. This procedure is repeated until only one thread is left.
+        // Only works if the threads per blocks is a power of two (hence static_assert
+        // in the beginning of the kernel).
+        for (int divideBy = 2; divideBy <= static_cast<int>(blockDim.x); divideBy *= 2)
+        {
+            int dividedAt = blockDim.x / divideBy;
+            if (static_cast<int>(threadIdx.x) < dividedAt)
+            {
+                for (int d = 0; d < 6; d++)
+                {
+                    sm_threadVirial[d * blockDim.x + threadIdx.x] +=
+                            sm_threadVirial[d * blockDim.x + (threadIdx.x + dividedAt)];
+                }
+            }
+            // Syncronize if not within one warp
+            if (dividedAt > warpSize / 2)
+            {
+                __syncthreads();
+            }
+        }
+        // First 6 threads in the block add the results of 6 tensor components to the global memory address.
+        if (threadIdx.x < 6)
+        {
+            atomicAdd(&(gm_virialScaled[threadIdx.x]), sm_threadVirial[threadIdx.x * blockDim.x]);
+        }
+    }
+
+    return;
+}
+
+/*! \brief Select templated kernel.
+ *
+ * Returns pointer to a CUDA kernel based on provided booleans.
+ *
+ * \param[in] updateVelocities  If the velocities should be constrained.
+ * \param[in] computeVirial     If virial should be updated.
+ *
+ * \return                      Pointer to CUDA kernel
+ */
+inline auto getLincsKernelPtr(const bool updateVelocities, const bool computeVirial)
+{
+
+    auto kernelPtr = lincs_kernel<true, true>;
+    if (updateVelocities && computeVirial)
+    {
+        kernelPtr = lincs_kernel<true, true>;
+    }
+    else if (updateVelocities && !computeVirial)
+    {
+        kernelPtr = lincs_kernel<true, false>;
+    }
+    else if (!updateVelocities && computeVirial)
+    {
+        kernelPtr = lincs_kernel<false, true>;
+    }
+    else if (!updateVelocities && !computeVirial)
+    {
+        kernelPtr = lincs_kernel<false, false>;
+    }
+    return kernelPtr;
+}
+
+void launchLincsGpuKernel(LincsGpuKernelParameters&  kernelParams,
+                          const DeviceBuffer<Float3> d_x,
+                          DeviceBuffer<Float3>       d_xp,
+                          const bool                 updateVelocities,
+                          DeviceBuffer<Float3>       d_v,
+                          const real                 invdt,
+                          const bool                 computeVirial,
+                          const DeviceStream&        deviceStream)
+{
+
+    auto kernelPtr = getLincsKernelPtr(updateVelocities, computeVirial);
+
+    KernelLaunchConfig config;
+    config.blockSize[0] = c_threadsPerBlock;
+    config.blockSize[1] = 1;
+    config.blockSize[2] = 1;
+    config.gridSize[0] = (kernelParams.numConstraintsThreads + c_threadsPerBlock - 1) / c_threadsPerBlock;
+    config.gridSize[1] = 1;
+    config.gridSize[2] = 1;
+
+    // Shared memory is used to store:
+    // -- Current coordinates (3 floats per thread)
+    // -- Right-hand-sides for matrix inversion (2 floats per thread)
+    // -- Virial tensor components (6 floats per thread)
+    // Since none of these three are needed simultaneously, they can be saved at the same shared memory address
+    // (i.e. correspondent arrays are intentionally overlapped in address space). Consequently, only
+    // max{3, 2, 6} = 6 floats per thread are needed in case virial is computed, or max{3, 2} = 3 if not.
+    if (computeVirial)
+    {
+        config.sharedMemorySize = c_threadsPerBlock * 6 * sizeof(float);
+    }
+    else
+    {
+        config.sharedMemorySize = c_threadsPerBlock * 3 * sizeof(float);
+    }
+
+    const auto kernelArgs = prepareGpuKernelArguments(kernelPtr,
+                                                      config,
+                                                      &kernelParams,
+                                                      asFloat3Pointer(&d_x),
+                                                      asFloat3Pointer(&d_xp),
+                                                      asFloat3Pointer(&d_v),
+                                                      &invdt);
+
+    launchGpuKernel(kernelPtr,
+                    config,
+                    deviceStream,
+                    nullptr,
+                    "lincs_kernel<updateVelocities, computeVirial>",
+                    kernelArgs);
+
+    return;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/mdlib/lincs_gpu_internal.h b/src/gromacs/mdlib/lincs_gpu_internal.h
new file mode 100644 (file)
index 0000000..5c42a78
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 Declare backend-specific LINCS GPU functions
+ *
+ * \author Artem Zhmurov <zhmurov@gmail.com>
+ * \author Alan Gray <alang@nvidia.com>
+ *
+ * \ingroup module_mdlib
+ */
+#ifndef GMX_MDLIB_LINCS_GPU_INTERNAL_H
+#define GMX_MDLIB_LINCS_GPU_INTERNAL_H
+
+#include "gromacs/gpu_utils/devicebuffer_datatype.h"
+#include "gromacs/gpu_utils/gputraits.h"
+
+class DeviceStream;
+
+namespace gmx
+{
+
+struct LincsGpuKernelParameters;
+
+//! Number of threads in a GPU block
+constexpr static int c_threadsPerBlock = 256;
+
+void launchLincsGpuKernel(LincsGpuKernelParameters&  kernelParams,
+                          const DeviceBuffer<Float3> d_x,
+                          DeviceBuffer<Float3>       d_xp,
+                          const bool                 updateVelocities,
+                          DeviceBuffer<Float3>       d_v,
+                          const real                 invdt,
+                          const bool                 computeVirial,
+                          const DeviceStream&        deviceStream);
+
+} // namespace gmx
+
+#endif // GMX_MDLIB_LINCS_GPU_INTERNAL_H
diff --git a/src/gromacs/mdlib/lincs_gpu_internal_sycl.cpp b/src/gromacs/mdlib/lincs_gpu_internal_sycl.cpp
new file mode 100644 (file)
index 0000000..b5594c1
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 LINCS kernels using SYCL
+ *
+ * This file contains SYCL kernels of LINCS constraints algorithm.
+ *
+ * \author Artem Zhmurov <zhmurov@gmail.com>
+ *
+ * \ingroup module_mdlib
+ */
+#include "lincs_gpu_internal.h"
+
+#include "gromacs/utility/gmxassert.h"
+
+namespace gmx
+{
+
+void launchLincsGpuKernel(LincsGpuKernelParameters& /* kernelParams */,
+                          const DeviceBuffer<Float3> /* d_x */,
+                          DeviceBuffer<Float3> /* d_xp */,
+                          const bool /* updateVelocities */,
+                          DeviceBuffer<Float3> /* d_v */,
+                          const real /* invdt */,
+                          const bool /* computeVirial */,
+                          const DeviceStream& /* deviceStream */)
+{
+
+    // SYCL_TODO
+    GMX_RELEASE_ASSERT(false, "LINCS is not yet implemented in SYCL.");
+
+    return;
+}
+
+} // namespace gmx
index cecbc3ca0ca216dd06906c2ea992797ea46e04e9..31ba183021bba8eac1d6fa9b5b51f5c76fafe8b1 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 The GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
 #include "gromacs/domdec/domdec.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nrnb.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/coupling.h"
@@ -88,18 +89,14 @@ static void calc_ke_part_normal(gmx::ArrayRef<const gmx::RVec> v,
                                 gmx_bool                       bEkinAveVel)
 {
     int                         g;
-    gmx::ArrayRef<t_grp_tcstat> tcstat  = ekind->tcstat;
-    gmx::ArrayRef<t_grp_acc>    grpstat = ekind->grpstat;
+    gmx::ArrayRef<t_grp_tcstat> tcstat = ekind->tcstat;
 
     /* three main: VV with AveVel, vv with AveEkin, leap with AveEkin.  Leap with AveVel is also
        an option, but not supported now.
        bEkinAveVel: If TRUE, we sum into ekin, if FALSE, into ekinh.
      */
 
-    /* group velocities are calculated in update_ekindata and
-     * accumulated in acumulate_groups.
-     * Now the partial global and groups ekin.
-     */
+    // Now accumulate the partial global and groups ekin.
     for (g = 0; (g < opts->ngtc); g++)
     {
         copy_mat(tcstat[g].ekinh, tcstat[g].ekinh_old);
@@ -114,7 +111,7 @@ static void calc_ke_part_normal(gmx::ArrayRef<const gmx::RVec> v,
         }
     }
     ekind->dekindl_old = ekind->dekindl;
-    int nthread        = gmx_omp_nthreads_get(emntUpdate);
+    int nthread        = gmx_omp_nthreads_get(ModuleMultiThread::Update);
 
 #pragma omp parallel for num_threads(nthread) schedule(static)
     for (int thread = 0; thread < nthread; thread++)
@@ -123,8 +120,7 @@ static void calc_ke_part_normal(gmx::ArrayRef<const gmx::RVec> v,
         // or memory allocation. It should not be able to throw, so for now
         // we do not need a try/catch wrapper.
         int     start_t, end_t, n;
-        int     ga, gt;
-        rvec    v_corrt;
+        int     gt;
         real    hm;
         int     d, m;
         matrix* ekin_sum;
@@ -142,35 +138,26 @@ static void calc_ke_part_normal(gmx::ArrayRef<const gmx::RVec> v,
         }
         *dekindl_sum = 0.0;
 
-        ga = 0;
         gt = 0;
         for (n = start_t; n < end_t; n++)
         {
-            if (md->cACC)
-            {
-                ga = md->cACC[n];
-            }
             if (md->cTC)
             {
                 gt = md->cTC[n];
             }
             hm = 0.5 * md->massT[n];
 
-            for (d = 0; (d < DIM); d++)
-            {
-                v_corrt[d] = v[n][d] - grpstat[ga].u[d];
-            }
             for (d = 0; (d < DIM); d++)
             {
                 for (m = 0; (m < DIM); m++)
                 {
-                    /* if we're computing a full step velocity, v_corrt[d] has v(t).  Otherwise, v(t+dt/2) */
-                    ekin_sum[gt][m][d] += hm * v_corrt[m] * v_corrt[d];
+                    /* if we're computing a full step velocity, v[d] has v(t).  Otherwise, v(t+dt/2) */
+                    ekin_sum[gt][m][d] += hm * v[n][m] * v[n][d];
                 }
             }
             if (md->nMassPerturbed && md->bPerturbed[n])
             {
-                *dekindl_sum += 0.5 * (md->massB[n] - md->massA[n]) * iprod(v_corrt, v_corrt);
+                *dekindl_sum += 0.5 * (md->massB[n] - md->massA[n]) * iprod(v[n], v[n]);
             }
         }
     }
@@ -305,16 +292,15 @@ void compute_globals(gmx_global_stat*               gstat,
                      const t_mdatoms*               mdatoms,
                      t_nrnb*                        nrnb,
                      t_vcm*                         vcm,
-                     gmx_wallcycle_t                wcycle,
+                     gmx_wallcycle                wcycle,
                      gmx_enerdata_t*                enerd,
                      tensor                         force_vir,
                      tensor                         shake_vir,
                      tensor                         total_vir,
                      tensor                         pres,
-                     gmx::Constraints*              constr,
+                     gmx::ArrayRef<real>            constraintsRmsdData,
                      gmx::SimulationSignaller*      signalCoordinator,
                      const matrix                   lastbox,
-                     int*                           totalNumberOfBondedInteractions,
                      gmx_bool*                      bSumEkinhOld,
                      const int                      flags)
 {
@@ -337,7 +323,8 @@ void compute_globals(gmx_global_stat*               gstat,
     /* we calculate a full state kinetic energy either with full-step velocity verlet
        or half step where we need the pressure */
 
-    bEkinAveVel = (ir->eI == eiVV || (ir->eI == eiVVAK && bPres) || bReadEkin);
+    bEkinAveVel = (ir->eI == IntegrationAlgorithm::VV
+                   || (ir->eI == IntegrationAlgorithm::VVAK && bPres) || bReadEkin);
 
     /* in initalization, it sums the shake virial in vv, and to
        sums ekinh_old in leapfrog (or if we are calculating ekinh_old) for other reasons */
@@ -346,14 +333,6 @@ void compute_globals(gmx_global_stat*               gstat,
 
     if (bTemp)
     {
-        /* Non-equilibrium MD: this is parallellized, but only does communication
-         * when there really is NEMD.
-         */
-
-        if (PAR(cr) && (ekind->bNEMD))
-        {
-            accumulate_u(cr, &(ir->opts), ekind);
-        }
         if (!bReadEkin)
         {
             calc_ke_part(x, v, box, &(ir->opts), mdatoms, ekind, nrnb, bEkinAveVel);
@@ -380,11 +359,20 @@ void compute_globals(gmx_global_stat*               gstat,
             gmx::ArrayRef<real> signalBuffer = signalCoordinator->getCommunicationBuffer();
             if (PAR(cr))
             {
-                wallcycle_start(wcycle, ewcMoveE);
-                global_stat(gstat, cr, enerd, force_vir, shake_vir, ir, ekind, constr,
-                            bStopCM ? vcm : nullptr, signalBuffer.size(), signalBuffer.data(),
-                            totalNumberOfBondedInteractions, *bSumEkinhOld, flags);
-                wallcycle_stop(wcycle, ewcMoveE);
+                wallcycle_start(wcycle, WallCycleCounter::MoveE);
+                global_stat(*gstat,
+                            cr,
+                            enerd,
+                            force_vir,
+                            shake_vir,
+                            *ir,
+                            ekind,
+                            constraintsRmsdData,
+                            bStopCM ? vcm : nullptr,
+                            signalBuffer,
+                            *bSumEkinhOld,
+                            flags);
+                wallcycle_stop(wcycle, WallCycleCounter::MoveE);
             }
             signalCoordinator->finalizeSignals();
             *bSumEkinhOld = FALSE;
@@ -407,7 +395,7 @@ void compute_globals(gmx_global_stat*               gstat,
            If FALSE, we average ekinh_old and ekinh*ekinscale_nhc to get an averaged half step kinetic energy.
          */
         enerd->term[F_TEMP] = sum_ekin(&(ir->opts), ekind, &dvdl_ekin, bEkinAveVel, bScaleEkin);
-        enerd->dvdl_lin[efptMASS] = static_cast<double>(dvdl_ekin);
+        enerd->dvdl_lin[FreeEnergyPerturbationCouplingType::Mass] = static_cast<double>(dvdl_ekin);
 
         enerd->term[F_EKIN] = trace(ekind->ekin);
     }
@@ -458,17 +446,17 @@ static int lcd4(int i1, int i2, int i3, int i4)
     return nst;
 }
 
-int computeGlobalCommunicationPeriod(const gmx::MDLogger& mdlog, t_inputrec* ir, const t_commrec* cr)
+int computeGlobalCommunicationPeriod(const t_inputrec* ir)
 {
-    int nstglobalcomm;
+    int nstglobalcomm = 10;
     {
         // Set up the default behaviour
-        if (!(ir->nstcalcenergy > 0 || ir->nstlist > 0 || ir->etc != etcNO || ir->epc != epcNO))
+        if (!(ir->nstcalcenergy > 0 || ir->nstlist > 0 || ir->etc != TemperatureCoupling::No
+              || ir->epc != PressureCoupling::No))
         {
             /* The user didn't choose the period for anything
                important, so we just make sure we can send signals and
                write output suitably. */
-            nstglobalcomm = 10;
             if (ir->nstenergy > 0 && ir->nstenergy < nstglobalcomm)
             {
                 nstglobalcomm = ir->nstenergy;
@@ -485,20 +473,18 @@ int computeGlobalCommunicationPeriod(const gmx::MDLogger& mdlog, t_inputrec* ir,
              * here a leftover of the twin-range scheme? Can we remove
              * nstlist when we remove the group scheme?
              */
-            nstglobalcomm = lcd4(ir->nstcalcenergy, ir->nstlist, ir->etc != etcNO ? ir->nsttcouple : 0,
-                                 ir->epc != epcNO ? ir->nstpcouple : 0);
+            nstglobalcomm = lcd4(ir->nstcalcenergy,
+                                 ir->nstlist,
+                                 ir->etc != TemperatureCoupling::No ? ir->nsttcouple : 0,
+                                 ir->epc != PressureCoupling::No ? ir->nstpcouple : 0);
         }
     }
+    return nstglobalcomm;
+}
 
-    // TODO change this behaviour. Instead grompp should print
-    // a (performance) note and mdrun should not change ir.
-    if (ir->comm_mode != ecmNO && ir->nstcomm < nstglobalcomm)
-    {
-        GMX_LOG(mdlog.warning)
-                .asParagraph()
-                .appendTextFormatted("WARNING: Changing nstcomm from %d to %d", ir->nstcomm, nstglobalcomm);
-        ir->nstcomm = nstglobalcomm;
-    }
+int computeGlobalCommunicationPeriod(const gmx::MDLogger& mdlog, const t_inputrec* ir, const t_commrec* cr)
+{
+    const int nstglobalcomm = computeGlobalCommunicationPeriod(ir);
 
     if (cr->nnodes > 1)
     {
@@ -533,64 +519,63 @@ void set_state_entries(t_state* state, const t_inputrec* ir, bool useModularSimu
      * with what is needed, so we correct this here.
      */
     state->flags = 0;
-    if (ir->efep != efepNO || ir->bExpanded)
+    if (ir->efep != FreeEnergyPerturbationType::No || ir->bExpanded)
     {
-        state->flags |= (1 << estLAMBDA);
-        state->flags |= (1 << estFEPSTATE);
+        state->flags |= enumValueToBitMask(StateEntry::Lambda);
+        state->flags |= enumValueToBitMask(StateEntry::FepState);
     }
-    state->flags |= (1 << estX);
+    state->flags |= enumValueToBitMask(StateEntry::X);
     GMX_RELEASE_ASSERT(state->x.size() == state->natoms,
                        "We should start a run with an initialized state->x");
     if (EI_DYNAMICS(ir->eI))
     {
-        state->flags |= (1 << estV);
+        state->flags |= enumValueToBitMask(StateEntry::V);
     }
 
     state->nnhpres = 0;
     if (ir->pbcType != PbcType::No)
     {
-        state->flags |= (1 << estBOX);
+        state->flags |= enumValueToBitMask(StateEntry::Box);
         if (inputrecPreserveShape(ir))
         {
-            state->flags |= (1 << estBOX_REL);
+            state->flags |= enumValueToBitMask(StateEntry::BoxRel);
         }
-        if ((ir->epc == epcPARRINELLORAHMAN) || (ir->epc == epcMTTK))
+        if ((ir->epc == PressureCoupling::ParrinelloRahman) || (ir->epc == PressureCoupling::Mttk))
         {
-            state->flags |= (1 << estBOXV);
+            state->flags |= enumValueToBitMask(StateEntry::BoxV);
             if (!useModularSimulator)
             {
-                state->flags |= (1 << estPRES_PREV);
+                state->flags |= enumValueToBitMask(StateEntry::PressurePrevious);
             }
         }
         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);
+            state->flags |= enumValueToBitMask(StateEntry::Nhpresxi);
+            state->flags |= enumValueToBitMask(StateEntry::Nhpresvxi);
+            state->flags |= enumValueToBitMask(StateEntry::SVirPrev);
+            state->flags |= enumValueToBitMask(StateEntry::FVirPrev);
+            state->flags |= enumValueToBitMask(StateEntry::Veta);
+            state->flags |= enumValueToBitMask(StateEntry::Vol0);
         }
-        if (ir->epc == epcBERENDSEN || ir->epc == epcCRESCALE)
+        if (ir->epc == PressureCoupling::Berendsen || ir->epc == PressureCoupling::CRescale)
         {
-            state->flags |= (1 << estBAROS_INT);
+            state->flags |= enumValueToBitMask(StateEntry::BarosInt);
         }
     }
 
-    if (ir->etc == etcNOSEHOOVER)
+    if (ir->etc == TemperatureCoupling::NoseHoover)
     {
-        state->flags |= (1 << estNH_XI);
-        state->flags |= (1 << estNH_VXI);
+        state->flags |= enumValueToBitMask(StateEntry::Nhxi);
+        state->flags |= enumValueToBitMask(StateEntry::Nhvxi);
     }
 
-    if (ir->etc == etcVRESCALE || ir->etc == etcBERENDSEN)
+    if (ir->etc == TemperatureCoupling::VRescale || ir->etc == TemperatureCoupling::Berendsen)
     {
-        state->flags |= (1 << estTHERM_INT);
+        state->flags |= enumValueToBitMask(StateEntry::ThermInt);
     }
 
-    init_gtc_state(state, state->ngtc, state->nnhpres,
-                   ir->opts.nhchainlength); /* allocate the space for nose-hoover chains */
+    init_gtc_state(state, state->ngtc, state->nnhpres, ir->opts.nhchainlength); /* allocate the space for nose-hoover chains */
     init_ekinstate(&state->ekinstate, ir);
 
     if (ir->bExpanded)
@@ -601,6 +586,6 @@ void set_state_entries(t_state* state, const t_inputrec* ir, bool useModularSimu
 
     if (ir->pull && ir->pull->bSetPbcRefToPrevStepCOM)
     {
-        state->flags |= (1 << estPULLCOMPREVSTEP);
+        state->flags |= enumValueToBitMask(StateEntry::PullComPrevStep);
     }
 }
index 3544c6f14f68f1fef79e838f4f3eee72291fcb74..da949e10d1165f0e573936a14e59f7f06c28093f 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 The GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +42,7 @@
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/timing/wallcycle.h"
 
-struct gmx_ekindata_t;
+class gmx_ekindata_t;
 struct gmx_enerdata_t;
 struct gmx_global_stat;
 struct gmx_signalling_t;
@@ -90,11 +90,16 @@ class SimulationSignaller;
  * will be computed, to check none are missing. */
 #define CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS (1u << 12u)
 
-
 /*! \brief Return the number of steps that will take place between
  * intra-simulation communications, given the constraints of the
  * inputrec. */
-int computeGlobalCommunicationPeriod(const gmx::MDLogger& mdlog, t_inputrec* ir, const t_commrec* cr);
+int computeGlobalCommunicationPeriod(const t_inputrec* ir);
+
+/*! \brief Return the number of steps that will take place between
+ * intra-simulation communications, given the constraints of the
+ * inputrec, and write information to log.
+ * Calls computeGlobalCommunicationPeriod(ir) internally. */
+int computeGlobalCommunicationPeriod(const gmx::MDLogger& mdlog, const t_inputrec* ir, const t_commrec* cr);
 
 void rerun_parallel_comm(t_commrec* cr, t_trxframe* fr, gmx_bool* bLastStep);
 
@@ -118,16 +123,15 @@ void compute_globals(gmx_global_stat*               gstat,
                      const t_mdatoms*               mdatoms,
                      t_nrnb*                        nrnb,
                      t_vcm*                         vcm,
-                     gmx_wallcycle_t                wcycle,
+                     gmx_wallcycle                wcycle,
                      gmx_enerdata_t*                enerd,
                      tensor                         force_vir,
                      tensor                         shake_vir,
                      tensor                         total_vir,
                      tensor                         pres,
-                     gmx::Constraints*              constr,
+                     gmx::ArrayRef<real>            constraintsRmsdData,
                      gmx::SimulationSignaller*      signalCoordinator,
                      const matrix                   lastbox,
-                     int*                           totalNumberOfBondedInteractions,
                      gmx_bool*                      bSumEkinhOld,
                      int                            flags);
 
index fb538837b19beba733cbfb1eebe84136115c2071..82ecd24b4b0937e50c0d021c4dbf8e26bae06c22 100644 (file)
@@ -87,7 +87,6 @@ MDAtoms::~MDAtoms()
     sfree(mdatoms_->ptype);
     sfree(mdatoms_->cTC);
     sfree(mdatoms_->cENER);
-    sfree(mdatoms_->cACC);
     sfree(mdatoms_->cFREEZE);
     sfree(mdatoms_->cVCM);
     sfree(mdatoms_->cORF);
@@ -148,7 +147,7 @@ std::unique_ptr<MDAtoms> makeMDAtoms(FILE* fp, const gmx_mtop_t& mtop, const t_i
     double totalMassB = 0.0;
 
     md->haveVsites                  = FALSE;
-    gmx_mtop_atomloop_block_t aloop = gmx_mtop_atomloop_block_init(&mtop);
+    gmx_mtop_atomloop_block_t aloop = gmx_mtop_atomloop_block_init(mtop);
     const t_atom*             atom;
     int                       nmol;
     while (gmx_mtop_atomloop_block_next(aloop, &atom, &nmol))
@@ -156,12 +155,12 @@ std::unique_ptr<MDAtoms> makeMDAtoms(FILE* fp, const gmx_mtop_t& mtop, const t_i
         totalMassA += nmol * atom->m;
         totalMassB += nmol * atom->mB;
 
-        if (atom->ptype == eptVSite)
+        if (atom->ptype == ParticleType::VSite)
         {
             md->haveVsites = TRUE;
         }
 
-        if (ir.efep != efepNO && PERTURBED(*atom))
+        if (ir.efep != FreeEnergyPerturbationType::No && PERTURBED(*atom))
         {
             md->nPerturbed++;
             if (atom->mB != atom->m)
@@ -182,10 +181,12 @@ std::unique_ptr<MDAtoms> makeMDAtoms(FILE* fp, const gmx_mtop_t& mtop, const t_i
     md->tmassA = totalMassA;
     md->tmassB = totalMassB;
 
-    if (ir.efep != efepNO && fp)
+    if (ir.efep != FreeEnergyPerturbationType::No && fp)
     {
-        fprintf(fp, "There are %d atoms and %d charges for free energy perturbation\n",
-                md->nPerturbed, md->nChargePerturbed);
+        fprintf(fp,
+                "There are %d atoms and %d charges for free energy perturbation\n",
+                md->nPerturbed,
+                md->nChargePerturbed);
     }
 
     md->havePartiallyFrozenAtoms = FALSE;
@@ -200,15 +201,15 @@ std::unique_ptr<MDAtoms> makeMDAtoms(FILE* fp, const gmx_mtop_t& mtop, const t_i
         }
     }
 
-    md->bOrires = (gmx_mtop_ftype_count(&mtop, F_ORIRES) != 0);
+    md->bOrires = (gmx_mtop_ftype_count(mtop, F_ORIRES) != 0);
 
     return mdAtoms;
 }
 
 } // namespace gmx
 
-void atoms2md(const gmx_mtop_t*  mtop,
-              const t_inputrec*  ir,
+void atoms2md(const gmx_mtop_t&  mtop,
+              const t_inputrec&  inputrec,
               int                nindex,
               gmx::ArrayRef<int> index,
               int                homenr,
@@ -218,13 +219,13 @@ void atoms2md(const gmx_mtop_t*  mtop,
     const t_grpopts* opts;
     int nthreads gmx_unused;
 
-    bLJPME = EVDW_PME(ir->vdwtype);
+    bLJPME = EVDW_PME(inputrec.vdwtype);
 
-    opts = &ir->opts;
+    opts = &inputrec.opts;
 
-    const SimulationGroups& groups = mtop->groups;
+    const SimulationGroups& groups = mtop.groups;
 
-    auto md = mdAtoms->mdatoms();
+    auto* md = mdAtoms->mdatoms();
     /* nindex>=0 indicates DD where we use an index */
     if (nindex >= 0)
     {
@@ -232,7 +233,7 @@ void atoms2md(const gmx_mtop_t*  mtop,
     }
     else
     {
-        md->nr = mtop->natoms;
+        md->nr = mtop.natoms;
     }
 
     if (md->nr > md->nalloc)
@@ -287,11 +288,7 @@ void atoms2md(const gmx_mtop_t*  mtop,
             /* We always copy cTC with domain decomposition */
         }
         srenew(md->cENER, md->nalloc);
-        if (opts->ngacc > 1)
-        {
-            srenew(md->cACC, md->nalloc);
-        }
-        if (inputrecFrozenAtoms(ir))
+        if (inputrecFrozenAtoms(&inputrec))
         {
             srenew(md->cFREEZE, md->nalloc);
         }
@@ -313,11 +310,11 @@ void atoms2md(const gmx_mtop_t*  mtop,
          * Therefore, when adding code, the user should use something like:
          * gprnrU1 = (md->cU1==NULL ? 0 : md->cU1[localatindex])
          */
-        if (!mtop->groups.groupNumbers[SimulationAtomGroupType::User1].empty())
+        if (!mtop.groups.groupNumbers[SimulationAtomGroupType::User1].empty())
         {
             srenew(md->cU1, md->nalloc);
         }
-        if (!mtop->groups.groupNumbers[SimulationAtomGroupType::User2].empty())
+        if (!mtop.groups.groupNumbers[SimulationAtomGroupType::User2].empty())
         {
             srenew(md->cU2, md->nalloc);
         }
@@ -325,7 +322,7 @@ void atoms2md(const gmx_mtop_t*  mtop,
 
     int molb = 0;
 
-    nthreads = gmx_omp_nthreads_get(emntDefault);
+    nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Default);
 #pragma omp parallel for num_threads(nthreads) schedule(static) firstprivate(molb)
     for (int i = 0; i < md->nr; i++)
     {
@@ -349,13 +346,13 @@ void atoms2md(const gmx_mtop_t*  mtop,
             {
                 md->cFREEZE[i] = getGroupType(groups, SimulationAtomGroupType::Freeze, ag);
             }
-            if (EI_ENERGY_MINIMIZATION(ir->eI))
+            if (EI_ENERGY_MINIMIZATION(inputrec.eI))
             {
                 /* Displacement is proportional to F, masses used for constraints */
                 mA = 1.0;
                 mB = 1.0;
             }
-            else if (ir->eI == eiBD)
+            else if (inputrec.eI == IntegrationAlgorithm::BD)
             {
                 /* With BD the physical masses are irrelevant.
                  * To keep the code simple we use most of the normal MD code path
@@ -367,15 +364,15 @@ void atoms2md(const gmx_mtop_t*  mtop,
                  * Thus with BD v*dt will give the displacement and the reported
                  * temperature can signal bad integration (too large time step).
                  */
-                if (ir->bd_fric > 0)
+                if (inputrec.bd_fric > 0)
                 {
-                    mA = 0.5 * ir->bd_fric * ir->delta_t;
-                    mB = 0.5 * ir->bd_fric * ir->delta_t;
+                    mA = 0.5 * inputrec.bd_fric * inputrec.delta_t;
+                    mB = 0.5 * inputrec.bd_fric * inputrec.delta_t;
                 }
                 else
                 {
                     /* The friction coefficient is mass/tau_t */
-                    fac = ir->delta_t
+                    fac = inputrec.delta_t
                           / opts->tau_t[md->cTC ? groups.groupNumbers[SimulationAtomGroupType::TemperatureCoupling][ag] : 0];
                     mA = 0.5 * atom.m * fac;
                     mB = 0.5 * atom.mB * fac;
@@ -403,8 +400,7 @@ void atoms2md(const gmx_mtop_t*  mtop,
             else if (md->cFREEZE)
             {
                 g = md->cFREEZE[i];
-                GMX_ASSERT(opts->nFreeze != nullptr,
-                           "Must have freeze groups to initialize masses");
+                GMX_ASSERT(opts->nFreeze != nullptr, "Must have freeze groups to initialize masses");
                 if (opts->nFreeze[g][XX] && opts->nFreeze[g][YY] && opts->nFreeze[g][ZZ])
                 {
                     /* Set the mass of completely frozen particles to ALMOST_ZERO
@@ -438,9 +434,9 @@ void atoms2md(const gmx_mtop_t*  mtop,
             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;
-                md->sqrt_c6A[i] = sqrt(c6);
+                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] = std::sqrt(c6);
                 if (c6 == 0.0 || c12 == 0)
                 {
                     md->sigmaA[i] = 1.0;
@@ -458,9 +454,9 @@ void atoms2md(const gmx_mtop_t*  mtop,
                 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;
-                    md->sqrt_c6B[i] = sqrt(c6);
+                    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] = std::sqrt(c6);
                     if (c6 == 0.0 || c12 == 0)
                     {
                         md->sigmaB[i] = 1.0;
@@ -478,10 +474,6 @@ void atoms2md(const gmx_mtop_t*  mtop,
                 md->cTC[i] = groups.groupNumbers[SimulationAtomGroupType::TemperatureCoupling][ag];
             }
             md->cENER[i] = getGroupType(groups, SimulationAtomGroupType::EnergyOutput, ag);
-            if (md->cACC)
-            {
-                md->cACC[i] = groups.groupNumbers[SimulationAtomGroupType::Acceleration][ag];
-            }
             if (md->cVCM)
             {
                 md->cVCM[i] = groups.groupNumbers[SimulationAtomGroupType::MassCenterVelocityRemoval][ag];
@@ -527,7 +519,7 @@ void update_mdatoms(t_mdatoms* md, real lambda)
         real L1 = 1 - lambda;
 
         /* Update masses of perturbed atoms for the change in lambda */
-        int gmx_unused nthreads = gmx_omp_nthreads_get(emntDefault);
+        int gmx_unused nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Default);
 #pragma omp parallel for num_threads(nthreads) schedule(static)
         for (int i = 0; i < md->nr; i++)
         {
index 44dbcbba2395ce4dde5b95360a984b828a1ceb12..31af77ad16d715c2e4d0766f406aadc0c2bbeebe 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2010,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@
 #include <vector>
 
 #include "gromacs/gpu_utils/hostallocator.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 #include "gromacs/utility/unique_cptr.h"
 
@@ -110,19 +109,27 @@ std::unique_ptr<MDAtoms> makeMDAtoms(FILE* fp, const gmx_mtop_t& mtop, const t_i
 
 } // namespace gmx
 
-void atoms2md(const gmx_mtop_t*  mtop,
-              const t_inputrec*  ir,
-              int                nindex,
-              gmx::ArrayRef<int> index,
-              int                homenr,
-              gmx::MDAtoms*      mdAtoms);
-/* This routine copies the atoms->atom struct into md.
+/*! \brief This routine copies the atoms->atom struct into md.
+ *
+ * \param[in]    mtop     The molecular topology.
+ * \param[in]    inputrec The input record.
+ * \param[in]    nindex   If nindex>=0 we are doing DD.
+ * \param[in]    index    Lookup table for global atom index.
+ * \param[in]    homenr   Number of atoms on this processor.
+ * \param[inout] mdAtoms  Data set up by this routine.
+ *
  * 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 atoms2md(const gmx_mtop_t&  mtop,
+              const t_inputrec&  inputrec,
+              int                nindex,
+              gmx::ArrayRef<int> index,
+              int                homenr,
+              gmx::MDAtoms*      mdAtoms);
 
 void update_mdatoms(t_mdatoms* md, real lambda);
 /* When necessary, sets all the mass parameters to values corresponding
index bed78d90c1699df9169929577556099483e8e246..c40120c6761f4ee92ea6a3453cb93b2b3c7c071b 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +37,7 @@
  */
 #include "gmxpre.h"
 
+#include "gromacs/utility/arrayref.h"
 #include "mdebin_bar.h"
 
 #include <cassert>
@@ -84,7 +85,7 @@ static void mde_delta_h_init(t_mde_delta_h* dh,
     dh->derivative = derivative;
     dh->nlambda    = nlambda;
 
-    snew(dh->lambda, nlambda);
+    dh->lambda.resize(nlambda);
     for (i = 0; i < nlambda; i++)
     {
         assert(lambda);
@@ -92,16 +93,12 @@ static void mde_delta_h_init(t_mde_delta_h* dh,
     }
 
 
-    snew(dh->subblock_meta_d, dh->nlambda + 1);
+    dh->subblock_meta_d.resize(dh->nlambda + 1);
 
     dh->ndhmax = ndhmax + 2;
-    for (i = 0; i < 2; i++)
-    {
-        dh->bin[i] = nullptr;
-    }
 
-    snew(dh->dh, dh->ndhmax);
-    snew(dh->dhf, dh->ndhmax);
+    dh->dh.resize(dh->ndhmax);
+    dh->dhf.resize(dh->ndhmax);
 
     if (nbins <= 0 || dx < GMX_REAL_EPS * 10)
     {
@@ -116,24 +113,12 @@ static void mde_delta_h_init(t_mde_delta_h* dh,
         dh->nbins = nbins;
         for (i = 0; i < dh->nhist; i++)
         {
-            snew(dh->bin[i], dh->nbins);
+            dh->bin[i].resize(dh->nbins);
         }
     }
     mde_delta_h_reset(dh);
 }
 
-static void done_mde_delta_h(t_mde_delta_h* dh)
-{
-    sfree(dh->lambda);
-    sfree(dh->subblock_meta_d);
-    sfree(dh->dh);
-    sfree(dh->dhf);
-    for (int i = 0; i < dh->nhist; i++)
-    {
-        sfree(dh->bin[i]);
-    }
-}
-
 /* Add a value to the delta_h list */
 static void mde_delta_h_add_dh(t_mde_delta_h* dh, double delta_h)
 {
@@ -254,8 +239,8 @@ static void mde_delta_h_handle_block(t_mde_delta_h* dh, t_enxblock* blk)
                                                     starting from first coord in
                                                     the main delta_h_coll) */
         blk->sub[0].nr   = 2;
-        blk->sub[0].type = xdr_datatype_int;
-        blk->sub[0].ival = dh->subblock_meta_i;
+        blk->sub[0].type = XdrDataType::Int;
+        blk->sub[0].ival = dh->subblock_meta_i.data();
 
         /* subblock 2 */
         for (i = 0; i < dh->nlambda; i++)
@@ -263,8 +248,8 @@ static void mde_delta_h_handle_block(t_mde_delta_h* dh, t_enxblock* blk)
             dh->subblock_meta_d[i] = dh->lambda[i];
         }
         blk->sub[1].nr   = dh->nlambda;
-        blk->sub[1].type = xdr_datatype_double;
-        blk->sub[1].dval = dh->subblock_meta_d;
+        blk->sub[1].type = XdrDataType::Double;
+        blk->sub[1].dval = dh->subblock_meta_d.data();
 
         /* subblock 3 */
         /* check if there's actual data to be written. */
@@ -275,20 +260,20 @@ static void mde_delta_h_handle_block(t_mde_delta_h* dh, t_enxblock* blk)
 
             blk->sub[2].nr = dh->ndh;
             /* Michael commented in 2012 that this use of explicit
-               xdr_datatype_float was good for F@H for now.
+               XdrDataType::Float was good for F@H for now.
                Apparently it's still good enough. */
-            blk->sub[2].type = xdr_datatype_float;
+            blk->sub[2].type = XdrDataType::Float;
             for (i = 0; i < dh->ndh; i++)
             {
                 dh->dhf[i] = static_cast<float>(dh->dh[i]);
             }
-            blk->sub[2].fval = dh->dhf;
+            blk->sub[2].fval = dh->dhf.data();
             dh->written      = TRUE;
         }
         else
         {
             blk->sub[2].nr   = 0;
-            blk->sub[2].type = xdr_datatype_float;
+            blk->sub[2].type = XdrDataType::Float;
             blk->sub[2].fval = nullptr;
         }
     }
@@ -349,8 +334,8 @@ static void mde_delta_h_handle_block(t_mde_delta_h* dh, t_enxblock* blk)
         }
         dh->subblock_meta_d[1] = dh->dx;
         blk->sub[0].nr         = 2 + ((dh->nlambda > 1) ? dh->nlambda : 0);
-        blk->sub[0].type       = xdr_datatype_double;
-        blk->sub[0].dval       = dh->subblock_meta_d;
+        blk->sub[0].type       = XdrDataType::Double;
+        blk->sub[0].dval       = dh->subblock_meta_d.data();
 
         /* subblock 2: the starting point(s) as a long integer */
         dh->subblock_meta_l[0] = nhist_written;
@@ -364,66 +349,66 @@ static void mde_delta_h_handle_block(t_mde_delta_h* dh, t_enxblock* blk)
         dh->subblock_meta_l[k++] = dh->derivative;
 
         blk->sub[1].nr   = nhist_written + 3;
-        blk->sub[1].type = xdr_datatype_int64;
-        blk->sub[1].lval = dh->subblock_meta_l;
+        blk->sub[1].type = XdrDataType::Int64;
+        blk->sub[1].lval = dh->subblock_meta_l.data();
 
         /* subblock 3 + 4 : the histogram data */
         for (i = 0; i < nhist_written; i++)
         {
             blk->sub[i + 2].nr = dh->maxbin[i] + 1; /* it's +1 because size=index+1
                                                        in C */
-            blk->sub[i + 2].type = xdr_datatype_int;
-            blk->sub[i + 2].ival = dh->bin[i];
+            blk->sub[i + 2].type = XdrDataType::Int;
+            blk->sub[i + 2].ival = dh->bin[i].data();
         }
     }
 }
 
 /* initialize the collection*/
-void mde_delta_h_coll_init(t_mde_delta_h_coll* dhc, const t_inputrec* ir)
+t_mde_delta_h_coll::t_mde_delta_h_coll(const t_inputrec& inputrec)
 {
     int       i, j, n;
     double*   lambda_vec;
-    int       ndhmax = ir->nstenergy / ir->nstcalcenergy;
-    t_lambda* fep    = ir->fepvals;
+    int       ndhmax = inputrec.nstenergy / inputrec.nstcalcenergy;
+    t_lambda* fep    = inputrec.fepvals.get();
 
-    dhc->temperature    = ir->opts.ref_t[0]; /* only store system temperature */
-    dhc->start_time     = 0.;
-    dhc->delta_time     = ir->delta_t * ir->fepvals->nstdhdl;
-    dhc->start_time_set = FALSE;
+    temperature    = inputrec.opts.ref_t[0]; /* only store system temperature */
+    start_time     = 0.;
+    delta_time     = inputrec.delta_t * inputrec.fepvals->nstdhdl;
+    start_time_set = FALSE;
 
     /* this is the compatibility lambda value. If it is >=0, it is valid,
        and there is either an old-style lambda or a slow growth simulation. */
-    dhc->start_lambda = ir->fepvals->init_lambda;
+    start_lambda = inputrec.fepvals->init_lambda;
     /* for continuous change of lambda values */
-    dhc->delta_lambda = ir->fepvals->delta_lambda * ir->fepvals->nstdhdl;
+    delta_lambda = inputrec.fepvals->delta_lambda * inputrec.fepvals->nstdhdl;
 
-    if (dhc->start_lambda < 0)
+    if (start_lambda < 0)
     {
         /* create the native lambda vectors */
-        dhc->lambda_index = fep->init_fep_state;
-        dhc->n_lambda_vec = 0;
-        for (i = 0; i < efptNR; i++)
+        lambda_index = fep->init_fep_state;
+        n_lambda_vec = 0;
+        for (auto i : keysOf(fep->separate_dvdl))
         {
             if (fep->separate_dvdl[i])
             {
-                dhc->n_lambda_vec++;
+                n_lambda_vec++;
             }
         }
-        snew(dhc->native_lambda_vec, dhc->n_lambda_vec);
-        snew(dhc->native_lambda_components, dhc->n_lambda_vec);
+        native_lambda_vec.resize(n_lambda_vec);
+        native_lambda_components.resize(n_lambda_vec);
         j = 0;
-        for (i = 0; i < efptNR; i++)
+        for (auto i : keysOf(fep->separate_dvdl))
         {
             if (fep->separate_dvdl[i])
             {
-                dhc->native_lambda_components[j] = i;
+                native_lambda_components[j] = static_cast<int>(i);
                 if (fep->init_fep_state >= 0 && fep->init_fep_state < fep->n_lambda)
                 {
-                    dhc->native_lambda_vec[j] = fep->all_lambda[i][fep->init_fep_state];
+                    native_lambda_vec[j] = fep->all_lambda[i][fep->init_fep_state];
                 }
                 else
                 {
-                    dhc->native_lambda_vec[j] = -1;
+                    native_lambda_vec[j] = -1;
                 }
                 j++;
             }
@@ -432,24 +417,22 @@ void mde_delta_h_coll_init(t_mde_delta_h_coll* dhc, const t_inputrec* ir)
     else
     {
         /* don't allocate the meta-data subblocks for lambda vectors */
-        dhc->native_lambda_vec        = nullptr;
-        dhc->n_lambda_vec             = 0;
-        dhc->native_lambda_components = nullptr;
-        dhc->lambda_index             = -1;
+        n_lambda_vec = 0;
+        lambda_index = -1;
     }
     /* allocate metadata subblocks */
-    snew(dhc->subblock_d, c_subblockDNumPreEntries + dhc->n_lambda_vec);
-    snew(dhc->subblock_i, c_subblockINumPreEntries + dhc->n_lambda_vec);
+    subblock_d.resize(c_subblockDNumPreEntries + n_lambda_vec);
+    subblock_i.resize(c_subblockINumPreEntries + n_lambda_vec);
 
     /* now decide which data to write out */
-    dhc->nlambda     = 0;
-    dhc->ndhdl       = 0;
-    dhc->dh_expanded = nullptr;
-    dhc->dh_energy   = nullptr;
-    dhc->dh_pv       = nullptr;
+    nlambda           = 0;
+    ndhdl             = 0;
+    dh_expanded_index = -1;
+    dh_energy_index   = -1;
+    dh_pv_index       = -1;
 
     /* total number of raw data point collections in the sample */
-    dhc->ndh = 0;
+    ndh = 0;
 
     {
         gmx_bool bExpanded           = FALSE;
@@ -460,44 +443,44 @@ void mde_delta_h_coll_init(t_mde_delta_h_coll* dhc, const t_inputrec* ir)
         /* first count the number of states */
 
         /* add the dhdl's */
-        if (fep->dhdl_derivatives == edhdlderivativesYES)
+        if (fep->dhdl_derivatives == DhDlDerivativeCalculation::Yes)
         {
-            for (i = 0; i < efptNR; i++)
+            for (auto i : keysOf(fep->separate_dvdl))
             {
-                if (ir->fepvals->separate_dvdl[i])
+                if (inputrec.fepvals->separate_dvdl[i])
                 {
-                    dhc->ndh += 1;
-                    dhc->ndhdl += 1;
+                    ndh += 1;
+                    ndhdl += 1;
                 }
             }
         }
         /* add the lambdas */
-        dhc->nlambda = ir->fepvals->lambda_stop_n - ir->fepvals->lambda_start_n;
-        dhc->ndh += dhc->nlambda;
+        nlambda = inputrec.fepvals->lambda_stop_n - inputrec.fepvals->lambda_start_n;
+        ndh += nlambda;
         /* another compatibility check */
-        if (dhc->start_lambda < 0)
+        if (start_lambda < 0)
         {
             /* include one more for the specification of the state, by lambda or
                fep_state*/
-            if (ir->expandedvals->elmcmove > elmcmoveNO)
+            if (inputrec.expandedvals->elmcmove > LambdaMoveCalculation::No)
             {
-                dhc->ndh += 1;
+                ndh += 1;
                 bExpanded = TRUE;
             }
             /* whether to print energies */
-            if (ir->fepvals->edHdLPrintEnergy != edHdLPrintEnergyNO)
+            if (inputrec.fepvals->edHdLPrintEnergy != FreeEnergyPrintEnergy::No)
             {
-                dhc->ndh += 1;
+                ndh += 1;
                 bEnergy = TRUE;
             }
-            if (ir->epc > epcNO)
+            if (inputrec.epc > PressureCoupling::No)
             {
-                dhc->ndh += 1; /* include pressure-volume work */
+                ndh += 1; /* include pressure-volume work */
                 bPV = TRUE;
             }
         }
         /* allocate them */
-        snew(dhc->dh, dhc->ndh);
+        dh.resize(ndh);
 
         /* now initialize them */
         /* the order, for now, must match that of the dhdl.xvg file because of
@@ -505,30 +488,48 @@ void mde_delta_h_coll_init(t_mde_delta_h_coll* dhc, const t_inputrec* ir)
         n = 0;
         if (bExpanded)
         {
-            dhc->dh_expanded = dhc->dh + n;
-            mde_delta_h_init(dhc->dh + n, ir->fepvals->dh_hist_size, ir->fepvals->dh_hist_spacing,
-                             ndhmax, dhbtEXPANDED, 0, 0, nullptr);
+            dh_expanded_index = n;
+            mde_delta_h_init(&dh[n],
+                             inputrec.fepvals->dh_hist_size,
+                             inputrec.fepvals->dh_hist_spacing,
+                             ndhmax,
+                             dhbtEXPANDED,
+                             0,
+                             0,
+                             nullptr);
             n++;
         }
         if (bEnergy)
         {
-            dhc->dh_energy = dhc->dh + n;
-            mde_delta_h_init(dhc->dh + n, ir->fepvals->dh_hist_size, ir->fepvals->dh_hist_spacing,
-                             ndhmax, dhbtEN, 0, 0, nullptr);
+            dh_energy_index = n;
+            mde_delta_h_init(&dh[n],
+                             inputrec.fepvals->dh_hist_size,
+                             inputrec.fepvals->dh_hist_spacing,
+                             ndhmax,
+                             dhbtEN,
+                             0,
+                             0,
+                             nullptr);
             n++;
         }
         /* add the dhdl's */
         n_lambda_components = 0;
-        if (fep->dhdl_derivatives == edhdlderivativesYES)
+        if (fep->dhdl_derivatives == DhDlDerivativeCalculation::Yes)
         {
-            dhc->dh_dhdl = dhc->dh + n;
-            for (i = 0; i < efptNR; i++)
+            dh_dhdl_index = n;
+            for (auto i : keysOf(fep->separate_dvdl))
             {
-                if (ir->fepvals->separate_dvdl[i])
+                if (inputrec.fepvals->separate_dvdl[i])
                 {
                     /* we give it init_lambda for compatibility */
-                    mde_delta_h_init(dhc->dh + n, ir->fepvals->dh_hist_size, ir->fepvals->dh_hist_spacing,
-                                     ndhmax, dhbtDHDL, n_lambda_components, 1, &(fep->init_lambda));
+                    mde_delta_h_init(&dh[n],
+                                     inputrec.fepvals->dh_hist_size,
+                                     inputrec.fepvals->dh_hist_spacing,
+                                     ndhmax,
+                                     dhbtDHDL,
+                                     n_lambda_components,
+                                     1,
+                                     &(fep->init_lambda));
                     n++;
                     n_lambda_components++;
                 }
@@ -536,70 +537,64 @@ void mde_delta_h_coll_init(t_mde_delta_h_coll* dhc, const t_inputrec* ir)
         }
         else
         {
-            for (i = 0; i < efptNR; i++)
+            for (auto i : keysOf(fep->separate_dvdl))
             {
-                if (ir->fepvals->separate_dvdl[i])
+                if (fep->separate_dvdl[i])
                 {
                     n_lambda_components++; /* count the components */
                 }
             }
         }
         /* add the lambdas */
-        dhc->dh_du = dhc->dh + n;
+        dh_du_index = n;
         snew(lambda_vec, n_lambda_components);
-        for (i = ir->fepvals->lambda_start_n; i < ir->fepvals->lambda_stop_n; i++)
+        for (i = inputrec.fepvals->lambda_start_n; i < inputrec.fepvals->lambda_stop_n; i++)
         {
             int k = 0;
 
-            for (j = 0; j < efptNR; j++)
+            for (auto j : keysOf(fep->separate_dvdl))
             {
-                if (ir->fepvals->separate_dvdl[j])
+                if (fep->separate_dvdl[j])
                 {
                     lambda_vec[k++] = fep->all_lambda[j][i];
                 }
             }
 
-            mde_delta_h_init(dhc->dh + n, ir->fepvals->dh_hist_size, ir->fepvals->dh_hist_spacing,
-                             ndhmax, dhbtDH, 0, n_lambda_components, lambda_vec);
+            mde_delta_h_init(&dh[n],
+                             inputrec.fepvals->dh_hist_size,
+                             inputrec.fepvals->dh_hist_spacing,
+                             ndhmax,
+                             dhbtDH,
+                             0,
+                             n_lambda_components,
+                             lambda_vec);
             n++;
         }
         sfree(lambda_vec);
         if (bPV)
         {
-            dhc->dh_pv = dhc->dh + n;
-            mde_delta_h_init(dhc->dh + n, ir->fepvals->dh_hist_size, ir->fepvals->dh_hist_spacing,
-                             ndhmax, dhbtPV, 0, 0, nullptr);
+            dh_pv_index = n;
+            mde_delta_h_init(&dh[n],
+                             inputrec.fepvals->dh_hist_size,
+                             inputrec.fepvals->dh_hist_spacing,
+                             ndhmax,
+                             dhbtPV,
+                             0,
+                             0,
+                             nullptr);
             n++;
         }
     }
 }
 
-void done_mde_delta_h_coll(t_mde_delta_h_coll* dhc)
-{
-    if (dhc == nullptr)
-    {
-        return;
-    }
-    sfree(dhc->native_lambda_vec);
-    sfree(dhc->native_lambda_components);
-    sfree(dhc->subblock_d);
-    sfree(dhc->subblock_i);
-    for (int i = 0; i < dhc->ndh; ++i)
-    {
-        done_mde_delta_h(&dhc->dh[i]);
-    }
-    sfree(dhc->dh);
-    sfree(dhc);
-}
-
 /* add a bunch of samples - note fep_state is double to allow for better data storage */
-void mde_delta_h_coll_add_dh(t_mde_delta_h_coll* dhc,
-                             double              fep_state,
-                             double              energy,
-                             double              pV,
-                             double*             dhdl,
-                             double*             foreign_dU,
-                             double              time)
+void mde_delta_h_coll_add_dh(t_mde_delta_h_coll*   dhc,
+                             double                fep_state,
+                             double                energy,
+                             double                pV,
+                             gmx::ArrayRef<double> dhdl,
+                             double*               foreign_dU,
+                             double                time)
 {
     int i;
 
@@ -611,23 +606,23 @@ void mde_delta_h_coll_add_dh(t_mde_delta_h_coll* dhc,
 
     for (i = 0; i < dhc->ndhdl; i++)
     {
-        mde_delta_h_add_dh(dhc->dh_dhdl + i, dhdl[i]);
+        mde_delta_h_add_dh(&dhc->dh[dhc->dh_dhdl_index + i], dhdl[i]);
     }
     for (i = 0; i < dhc->nlambda; i++)
     {
-        mde_delta_h_add_dh(dhc->dh_du + i, foreign_dU[i]);
+        mde_delta_h_add_dh(&dhc->dh[dhc->dh_du_index + i], foreign_dU[i]);
     }
-    if (dhc->dh_pv != nullptr)
+    if (dhc->dh_pv_index >= 0)
     {
-        mde_delta_h_add_dh(dhc->dh_pv, pV);
+        mde_delta_h_add_dh(&dhc->dh[dhc->dh_pv_index], pV);
     }
-    if (dhc->dh_energy != nullptr)
+    if (dhc->dh_energy_index >= 0)
     {
-        mde_delta_h_add_dh(dhc->dh_energy, energy);
+        mde_delta_h_add_dh(&dhc->dh[dhc->dh_energy_index], energy);
     }
-    if (dhc->dh_expanded != nullptr)
+    if (dhc->dh_expanded_index >= 0)
     {
-        mde_delta_h_add_dh(dhc->dh_expanded, fep_state);
+        mde_delta_h_add_dh(&dhc->dh[dhc->dh_expanded_index], fep_state);
     }
 }
 
@@ -645,7 +640,7 @@ void mde_delta_h_coll_handle_block(t_mde_delta_h_coll* dhc, t_enxframe* fr, int
 
     /* only allocate lambda vector component blocks if they must be written out
        for backward compatibility */
-    if (dhc->native_lambda_components != nullptr)
+    if (!dhc->native_lambda_components.empty())
     {
         add_subblocks_enxblock(blk, 2);
     }
@@ -660,7 +655,7 @@ void mde_delta_h_coll_handle_block(t_mde_delta_h_coll* dhc, t_enxframe* fr, int
     dhc->subblock_d[3] = dhc->start_lambda; /* old-style lambda at starttime */
     dhc->subblock_d[4] = dhc->delta_lambda; /* lambda diff. between samples */
     /* set the lambda vector components if they exist */
-    if (dhc->native_lambda_components != nullptr)
+    if (!dhc->native_lambda_components.empty())
     {
         for (i = 0; i < dhc->n_lambda_vec; i++)
         {
@@ -669,10 +664,10 @@ void mde_delta_h_coll_handle_block(t_mde_delta_h_coll* dhc, t_enxframe* fr, int
     }
     blk->id          = enxDHCOLL;
     blk->sub[0].nr   = c_subblockDNumPreEntries + dhc->n_lambda_vec;
-    blk->sub[0].type = xdr_datatype_double;
-    blk->sub[0].dval = dhc->subblock_d;
+    blk->sub[0].type = XdrDataType::Double;
+    blk->sub[0].dval = dhc->subblock_d.data();
 
-    if (dhc->native_lambda_components != nullptr)
+    if (!dhc->native_lambda_components.empty())
     {
         dhc->subblock_i[0] = dhc->lambda_index;
         /* set the lambda vector component IDs if they exist */
@@ -682,8 +677,8 @@ void mde_delta_h_coll_handle_block(t_mde_delta_h_coll* dhc, t_enxframe* fr, int
             dhc->subblock_i[c_subblockINumPreEntries + i] = dhc->native_lambda_components[i];
         }
         blk->sub[1].nr   = c_subblockINumPreEntries + dhc->n_lambda_vec;
-        blk->sub[1].type = xdr_datatype_int;
-        blk->sub[1].ival = dhc->subblock_i;
+        blk->sub[1].type = XdrDataType::Int;
+        blk->sub[1].ival = dhc->subblock_i.data();
     }
 
     for (i = 0; i < dhc->ndh; i++)
@@ -692,7 +687,7 @@ void mde_delta_h_coll_handle_block(t_mde_delta_h_coll* dhc, t_enxframe* fr, int
         add_blocks_enxframe(fr, nblock);
         blk = fr->block + (nblock - 1);
 
-        mde_delta_h_handle_block(dhc->dh + i, blk);
+        mde_delta_h_handle_block(&dhc->dh[i], blk);
     }
 }
 
@@ -705,7 +700,7 @@ void mde_delta_h_coll_reset(t_mde_delta_h_coll* dhc)
         if (dhc->dh[i].written)
         {
             /* we can now throw away the data */
-            mde_delta_h_reset(dhc->dh + i);
+            mde_delta_h_reset(&dhc->dh[i]);
         }
     }
     dhc->start_time_set = FALSE;
@@ -729,8 +724,10 @@ void mde_delta_h_coll_update_energyhistory(const t_mde_delta_h_coll* dhc, energy
     for (int i = 0; i < dhc->ndh; i++)
     {
         std::vector<real>& dh = deltaH->dh[i];
-        dh.resize(dhc->dh[i].ndh);
-        std::copy(dhc->dh[i].dh, dhc->dh[i].dh + dhc->dh[i].ndh, dh.begin());
+        for (unsigned int j = 0; j < dhc->dh[i].ndh; j++)
+        {
+            dh.emplace_back(dhc->dh[i].dh[j]);
+        }
     }
     deltaH->start_time   = dhc->start_time;
     deltaH->start_lambda = dhc->start_lambda;
index b1dacb29aaa5e321f46809bf974f3492782c2867..5cb6c69776554c228dd538c8f7ac03a0c4d65da8 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
-#ifndef _mdebin_bar_h
-#define _mdebin_bar_h
+#ifndef GMX_MDLIB_MDEBIN_BAR_H
+#define GMX_MDLIB_MDEBIN_BAR_H
 
-#include "gromacs/mdlib/energyoutput.h"
+#include "gromacs/utility/real.h"
 
 /* The functions & data structures here describe writing
    energy differences (or their histogram )for use with g_bar */
 
 class delta_h_history_t;
 struct t_enxframe;
+class energyhistory_t;
+struct t_inputrec;
+
+namespace gmx
+{
+template<typename>
+class ArrayRef;
+}
 
 /* Data for one foreign lambda, or derivative. */
 typedef struct
 {
-    real*        dh;     /* the raw energy data. */
-    float*       dhf;    /* raw difference data -- in floats, for storage. */
-    unsigned int ndh;    /* number of data points */
-    unsigned int ndhmax; /* the maximum number of points */
-
-    int nhist;              /* the number of histograms. There can either be
-                               0 (for no histograms)
-                               1 (for 'foreign lambda' histograms)
-                               2 (for derivative histograms: there's
-                                  a 'forward' and 'backward' histogram
-                                  containing the minimum and maximum
-                                  values, respectively). */
-    int*   bin[2];          /* the histogram(s) */
-    double dx;              /* the histogram spacing in kJ/mol. This is the
-                               same for the two histograms? */
-    unsigned int nbins;     /* the number of bins in the histograms*/
-    int64_t      x0[2];     /* the starting point in units of spacing
-                                       of the histogram */
-    unsigned int maxbin[2]; /* highest bin number with data */
-
-    int type;         /* the block type according to dhbtDH, etc. */
-    int derivative;   /* The derivative direction (as an index in the lambda
-                         vector) if this delta_h contains derivatives */
-    double*  lambda;  /* lambda vector (or NULL if not applicable) */
-    int      nlambda; /* length of the lambda vector */
-    gmx_bool written; /* whether this data has already been written out */
-
-    int64_t subblock_meta_l[5]; /* metadata for an mdebin subblock for
+    std::vector<real>  dh;     /* the raw energy data. */
+    std::vector<float> dhf;    /* raw difference data -- in floats, for storage. */
+    unsigned int       ndh;    /* number of data points */
+    unsigned int       ndhmax; /* the maximum number of points */
+
+    int nhist;                           /* the number of histograms. There can either be
+                                            0 (for no histograms)
+                                            1 (for 'foreign lambda' histograms)
+                                            2 (for derivative histograms: there's
+                                               a 'forward' and 'backward' histogram
+                                               containing the minimum and maximum
+                                               values, respectively). */
+    std::array<std::vector<int>, 2> bin; /* the histogram(s) */
+    double                          dx;  /* the histogram spacing in kJ/mol. This is the
+                                            same for the two histograms? */
+    unsigned int           nbins;        /* the number of bins in the histograms*/
+    std::array<int64_t, 2> x0;           /* the starting point in units of spacing
+                                        of the histogram */
+    std::array<unsigned int, 2> maxbin;  /* highest bin number with data */
+
+    int type;                    /* the block type according to dhbtDH, etc. */
+    int derivative;              /* The derivative direction (as an index in the lambda
+                                    vector) if this delta_h contains derivatives */
+    std::vector<double> lambda;  /* lambda vector (or NULL if not applicable) */
+    int                 nlambda; /* length of the lambda vector */
+    bool                written; /* whether this data has already been written out */
+
+    std::array<int64_t, 5> subblock_meta_l; /* metadata for an mdebin subblock for
                                            I/O: for histogram counts, etc.*/
-    double* subblock_meta_d;    /* metadata subblock for I/O, used for
+    std::vector<double> subblock_meta_d;    /* metadata subblock for I/O, used for
                                    communicating doubles (i.e. the lambda
                                    vector) */
-    int subblock_meta_i[4];     /* metadata subblock for I/O, used for
+    std::array<int, 4> subblock_meta_i;     /* metadata subblock for I/O, used for
                                    communicating ints (i.e. derivative indices,
                                    etc.) */
 } t_mde_delta_h;
@@ -90,52 +98,40 @@ typedef struct
 /* the type definition is in mdebin_bar.h */
 struct t_mde_delta_h_coll
 {
-    t_mde_delta_h* dh;  /* the delta h data */
-    int            ndh; /* the number of delta_h structures */
+    t_mde_delta_h_coll(const t_inputrec& inputrec);
+
+    std::vector<t_mde_delta_h> dh;  /* the delta h data */
+    int                        ndh; /* the number of delta_h structures */
 
-    int            nlambda; /* number of bar dU delta_h structures */
-    t_mde_delta_h* dh_du;   /* the delta h data (pointer into dh) */
+    int nlambda;     /* number of bar dU delta_h structures */
+    int dh_du_index; /* the delta h data (index into dh) */
 
-    int            ndhdl;   /* number of bar dU delta_h structures */
-    t_mde_delta_h* dh_dhdl; /* the dhdl data (pointer into dh) */
+    int ndhdl;         /* number of bar dU delta_h structures */
+    int dh_dhdl_index; /* the dhdl data (index into dh) */
 
-    t_mde_delta_h* dh_energy;   /* energy output block (pointer into dh) */
-    t_mde_delta_h* dh_pv;       /* pV output block (pointer into dh) */
-    t_mde_delta_h* dh_expanded; /* expanded ensemble output block (pointer
-                                   into dh) */
+    int dh_energy_index;   /* energy output block (index into dh) */
+    int dh_pv_index;       /* pV output block (index into dh) */
+    int dh_expanded_index; /* expanded ensemble output block (index into dh) */
 
-    double   start_time;     /* start time of the current dh collection */
-    double   delta_time;     /* time difference between samples */
-    gmx_bool start_time_set; /* whether the start time has been set */
-    double   start_lambda;   /* starting lambda for continuous motion of state*/
-    double   delta_lambda;   /* delta lambda, for continuous motion of state */
-    double   temperature;    /* the temperature of the samples*/
+    double start_time;     /* start time of the current dh collection */
+    double delta_time;     /* time difference between samples */
+    bool   start_time_set; /* whether the start time has been set */
+    double start_lambda;   /* starting lambda for continuous motion of state*/
+    double delta_lambda;   /* delta lambda, for continuous motion of state */
+    double temperature;    /* the temperature of the samples*/
 
-    double* native_lambda_vec;     /* The lambda vector describing the current
+    std::vector<double> native_lambda_vec;     /* The lambda vector describing the current
                                       lambda state if it is set (NULL otherwise) */
-    int  n_lambda_vec;             /* the size of the native lambda vector */
-    int* native_lambda_components; /* the native lambda (and by extension,
+    int              n_lambda_vec;             /* the size of the native lambda vector */
+    std::vector<int> native_lambda_components; /* the native lambda (and by extension,
                                       foreign lambda) components in terms
                                       of efptFEP, efptMASS, etc. */
-    int lambda_index;              /* the lambda_fep_state */
+    int lambda_index;                          /* the lambda_fep_state */
 
-    double* subblock_d; /* for writing a metadata mdebin subblock for I/O */
-    int*    subblock_i; /* for writing a metadata mdebin subblock for I/O */
-
-    double* lambda_vec_subblock; /* native lambda vector data subblock for
-                                    I/O */
-    int* lambda_index_subblock;  /* lambda vector index data subblock for I/O */
+    std::vector<double> subblock_d; /* for writing a metadata mdebin subblock for I/O */
+    std::vector<int>    subblock_i; /* for writing a metadata mdebin subblock for I/O */
 };
 
-
-/* initialize a collection of delta h histograms/sets
-    dhc = the collection
-    ir = the input record */
-
-void mde_delta_h_coll_init(t_mde_delta_h_coll* dhc, const t_inputrec* ir);
-
-void done_mde_delta_h_coll(t_mde_delta_h_coll* dhc);
-
 /* add a bunch of samples to the delta_h collection
     dhc = the collection
     dhdl = the hamiltonian derivatives
@@ -146,13 +142,13 @@ void done_mde_delta_h_coll(t_mde_delta_h_coll* dhc);
  */
 
 /* add a bunch of samples - note fep_state is double to allow for better data storage */
-void mde_delta_h_coll_add_dh(t_mde_delta_h_coll* dhc,
-                             double              fep_state,
-                             double              energy,
-                             double              pV,
-                             double*             dhdl,
-                             double*             foreign_dU,
-                             double              time);
+void mde_delta_h_coll_add_dh(t_mde_delta_h_coll*   dhc,
+                             double                fep_state,
+                             double                energy,
+                             double                pV,
+                             gmx::ArrayRef<double> dhdl,
+                             double*               foreign_dU,
+                             double                time);
 
 /* write the data associated with the du blocks collection as a collection
     of mdebin blocks.
@@ -173,4 +169,4 @@ void mde_delta_h_coll_update_energyhistory(const t_mde_delta_h_coll* dhc, energy
 /* restore the variables from an energyhistory */
 void mde_delta_h_coll_restore_energyhistory(t_mde_delta_h_coll* dhc, const delta_h_history_t* deltaH);
 
-#endif /* _mdebin_bar_h */
+#endif /* GMX_MDLIB_MDEBIN_BAR_H */
index 7e06e4fc9ee5fae2fe646c1b404e309fd8436128..71f911b3dd7803ba76b4bd330fbe5601df89c04c 100644 (file)
 
 struct gmx_mdoutf
 {
-    t_fileio*                     fp_trn;
-    t_fileio*                     fp_xtc;
-    gmx_tng_trajectory_t          tng;
-    gmx_tng_trajectory_t          tng_low_prec;
-    int                           x_compression_precision; /* only used by XTC output */
-    ener_file_t                   fp_ene;
-    const char*                   fn_cpt;
-    gmx_bool                      bKeepAndNumCPT;
-    int                           eIntegrator;
-    gmx_bool                      bExpanded;
-    int                           elamstats;
-    int                           simulation_part;
-    FILE*                         fp_dhdl;
-    int                           natoms_global;
-    int                           natoms_x_compressed;
-    const SimulationGroups*       groups; /* for compressed position writing */
-    gmx_wallcycle_t               wcycle;
-    rvec*                         f_global;
-    gmx::IMDOutputProvider*       outputProvider;
-    const gmx::MdModulesNotifier* mdModulesNotifier;
-    bool                          simulationsShareState;
-    MPI_Comm                      mastersComm;
+    t_fileio*                      fp_trn;
+    t_fileio*                      fp_xtc;
+    gmx_tng_trajectory_t           tng;
+    gmx_tng_trajectory_t           tng_low_prec;
+    int                            x_compression_precision; /* only used by XTC output */
+    ener_file_t                    fp_ene;
+    const char*                    fn_cpt;
+    gmx_bool                       bKeepAndNumCPT;
+    IntegrationAlgorithm           eIntegrator;
+    gmx_bool                       bExpanded;
+    LambdaWeightCalculation        elamstats;
+    int                            simulation_part;
+    FILE*                          fp_dhdl;
+    int                            natoms_global;
+    int                            natoms_x_compressed;
+    const SimulationGroups*        groups; /* for compressed position writing */
+    gmx_wallcycle*                 wcycle;
+    rvec*                          f_global;
+    gmx::IMDOutputProvider*        outputProvider;
+    const gmx::MDModulesNotifiers* mdModulesNotifiers;
+    bool                           simulationsShareState;
+    MPI_Comm                       mastersComm;
 };
 
 
-gmx_mdoutf_t init_mdoutf(FILE*                         fplog,
-                         int                           nfile,
-                         const t_filenm                fnm[],
-                         const gmx::MdrunOptions&      mdrunOptions,
-                         const t_commrec*              cr,
-                         gmx::IMDOutputProvider*       outputProvider,
-                         const gmx::MdModulesNotifier& mdModulesNotifier,
-                         const t_inputrec*             ir,
-                         const gmx_mtop_t*             top_global,
-                         const gmx_output_env_t*       oenv,
-                         gmx_wallcycle_t               wcycle,
-                         const gmx::StartingBehavior   startingBehavior,
-                         bool                          simulationsShareState,
-                         const gmx_multisim_t*         ms)
+gmx_mdoutf_t init_mdoutf(FILE*                          fplog,
+                         int                            nfile,
+                         const t_filenm                 fnm[],
+                         const gmx::MdrunOptions&       mdrunOptions,
+                         const t_commrec*               cr,
+                         gmx::IMDOutputProvider*        outputProvider,
+                         const gmx::MDModulesNotifiers& mdModulesNotifiers,
+                         const t_inputrec*              ir,
+                         const gmx_mtop_t             top_global,
+                         const gmx_output_env_t*        oenv,
+                         gmx_wallcycle*                 wcycle,
+                         const gmx::StartingBehavior    startingBehavior,
+                         bool                           simulationsShareState,
+                         const gmx_multisim_t*          ms)
 {
     gmx_mdoutf_t of;
     const char * appendMode = "a+", *writeMode = "w+", *filemode;
@@ -164,7 +164,7 @@ gmx_mdoutf_t init_mdoutf(FILE*                         fplog,
                     gmx_tng_open(filename, filemode[0], &of->tng_low_prec);
                     if (filemode[0] == 'w')
                     {
-                        gmx_tng_prepare_low_prec_writing(of->tng_low_prec, top_global, ir);
+                        gmx_tng_prepare_low_prec_writing(of->tng_low_prec, &top_global, ir);
                     }
                     bCiteTng = TRUE;
                     break;
@@ -193,7 +193,7 @@ gmx_mdoutf_t init_mdoutf(FILE*                         fplog,
                     gmx_tng_open(filename, filemode[0], &of->tng);
                     if (filemode[0] == 'w')
                     {
-                        gmx_tng_prepare_md_writing(of->tng, top_global, ir);
+                        gmx_tng_prepare_md_writing(of->tng, &top_global, ir);
                     }
                     bCiteTng = TRUE;
                     break;
@@ -206,8 +206,8 @@ gmx_mdoutf_t init_mdoutf(FILE*                         fplog,
         }
         of->fn_cpt = opt2fn("-cpo", nfile, fnm);
 
-        if ((ir->efep != efepNO || ir->bSimTemp) && ir->fepvals->nstdhdl > 0
-            && (ir->fepvals->separate_dhdl_file == esepdhdlfileYES) && EI_DYNAMICS(ir->eI))
+        if ((ir->efep != FreeEnergyPerturbationType::No || ir->bSimTemp) && ir->fepvals->nstdhdl > 0
+            && (ir->fepvals->separate_dhdl_file == SeparateDhdlFile::Yes) && EI_DYNAMICS(ir->eI))
         {
             if (restartWithAppending)
             {
@@ -220,16 +220,16 @@ gmx_mdoutf_t init_mdoutf(FILE*                         fplog,
         }
 
         outputProvider->initOutput(fplog, nfile, fnm, restartWithAppending, oenv);
-        of->mdModulesNotifier = &mdModulesNotifier;
+        of->mdModulesNotifiers = &mdModulesNotifiers;
 
         /* Set up atom counts so they can be passed to actual
            trajectory-writing routines later. Also, XTC writing needs
            to know what (and how many) atoms might be in the XTC
            groups, and how to look up later which ones they are. */
-        of->natoms_global       = top_global->natoms;
-        of->groups              = &top_global->groups;
+        of->natoms_global       = top_global.natoms;
+        of->groups              = &top_global.groups;
         of->natoms_x_compressed = 0;
-        for (i = 0; (i < top_global->natoms); i++)
+        for (i = 0; (i < top_global.natoms); i++)
         {
             if (getGroupType(*of->groups, SimulationAtomGroupType::CompressedPositionOutput, i) == 0)
             {
@@ -239,7 +239,7 @@ gmx_mdoutf_t init_mdoutf(FILE*                         fplog,
 
         if (ir->nstfout && DOMAINDECOMP(cr))
         {
-            snew(of->f_global, top_global->natoms);
+            snew(of->f_global, top_global.natoms);
         }
     }
 
@@ -261,7 +261,7 @@ FILE* mdoutf_get_fp_dhdl(gmx_mdoutf_t of)
     return of->fp_dhdl;
 }
 
-gmx_wallcycle_t mdoutf_get_wcycle(gmx_mdoutf_t of)
+gmx_wallcycle* mdoutf_get_wcycle(gmx_mdoutf_t of)
 {
     return of->wcycle;
 }
@@ -289,15 +289,15 @@ static void write_checkpoint(const char*                     fn,
                              const t_commrec*                cr,
                              ivec                            domdecCells,
                              int                             nppnodes,
-                             int                             eIntegrator,
+                             IntegrationAlgorithm            eIntegrator,
                              int                             simulation_part,
                              gmx_bool                        bExpanded,
-                             int                             elamstats,
+                             LambdaWeightCalculation         elamstats,
                              int64_t                         step,
                              double                          t,
                              t_state*                        state,
                              ObservablesHistory*             observablesHistory,
-                             const gmx::MdModulesNotifier&   mdModulesNotifier,
+                             const gmx::MDModulesNotifiers&  mdModulesNotifiers,
                              gmx::WriteCheckpointDataHolder* modularSimulatorCheckpointData,
                              bool                            applyMpiBarrierBeforeRename,
                              MPI_Comm                        mpiBarrierCommunicator)
@@ -355,7 +355,7 @@ static void write_checkpoint(const char*                     fn,
     int             nED       = (edsamhist ? edsamhist->nED : 0);
 
     swaphistory_t* swaphist    = observablesHistory->swapHistory.get();
-    int            eSwapCoords = (swaphist ? swaphist->eSwapCoords : eswapNO);
+    SwapType       eSwapCoords = (swaphist ? swaphist->eSwapCoords : SwapType::No);
 
     CheckpointHeaderContents headerContents = { 0,
                                                 { 0 },
@@ -394,8 +394,15 @@ static void write_checkpoint(const char*                     fn,
         copy_ivec(domdecCells, headerContents.dd_nc);
     }
 
-    write_checkpoint_data(fp, headerContents, bExpanded, elamstats, state, observablesHistory,
-                          mdModulesNotifier, &outputfiles, modularSimulatorCheckpointData);
+    write_checkpoint_data(fp,
+                          headerContents,
+                          bExpanded,
+                          elamstats,
+                          state,
+                          observablesHistory,
+                          mdModulesNotifiers,
+                          &outputfiles,
+                          modularSimulatorCheckpointData);
 
     /* we really, REALLY, want to make sure to physically write the checkpoint,
        and all the files it depends on, out to disk. Because we've
@@ -428,11 +435,12 @@ static void write_checkpoint(const char*                     fn,
 #if !GMX_NO_RENAME
     if (!bNumberAndKeep && !ret)
     {
+        // Add a barrier before renaming to reduce chance to get out of sync (#2440)
+        // Note: Checkpoint might only exist on some ranks, so put barrier before if clause (#3919)
+        mpiBarrierBeforeRename(applyMpiBarrierBeforeRename, mpiBarrierCommunicator);
         if (gmx_fexist(fn))
         {
             /* Rename the previous checkpoint file */
-            mpiBarrierBeforeRename(applyMpiBarrierBeforeRename, mpiBarrierCommunicator);
-
             std::strcpy(buf, fn);
             buf[std::strlen(fn) - std::strlen(ftp2ext(fn2ftp(fn))) - 1] = '\0';
             std::strcat(buf, "_prev");
@@ -502,12 +510,24 @@ void mdoutf_write_checkpoint(gmx_mdoutf_t                    of,
      * checkpoint files getting out of sync.
      */
     ivec one_ivec = { 1, 1, 1 };
-    write_checkpoint(of->fn_cpt, of->bKeepAndNumCPT, fplog, cr,
+    write_checkpoint(of->fn_cpt,
+                     of->bKeepAndNumCPT,
+                     fplog,
+                     cr,
                      DOMAINDECOMP(cr) ? cr->dd->numCells : one_ivec,
-                     DOMAINDECOMP(cr) ? cr->dd->nnodes : cr->nnodes, of->eIntegrator,
-                     of->simulation_part, of->bExpanded, of->elamstats, step, t, state_global,
-                     observablesHistory, *(of->mdModulesNotifier), modularSimulatorCheckpointData,
-                     of->simulationsShareState, of->mastersComm);
+                     DOMAINDECOMP(cr) ? cr->dd->nnodes : cr->nnodes,
+                     of->eIntegrator,
+                     of->simulation_part,
+                     of->bExpanded,
+                     of->elamstats,
+                     step,
+                     t,
+                     state_global,
+                     observablesHistory,
+                     *(of->mdModulesNotifiers),
+                     modularSimulatorCheckpointData,
+                     of->simulationsShareState,
+                     of->mastersComm);
 }
 
 void mdoutf_write_to_trajectory_files(FILE*                           fplog,
@@ -536,22 +556,36 @@ void mdoutf_write_to_trajectory_files(FILE*                           fplog,
             if (mdof_flags & (MDOF_X | MDOF_X_COMPRESSED))
             {
                 auto globalXRef = MASTER(cr) ? state_global->x : gmx::ArrayRef<gmx::RVec>();
-                dd_collect_vec(cr->dd, state_local->ddp_count, state_local->ddp_count_cg_gl,
-                               state_local->cg_gl, state_local->x, globalXRef);
+                dd_collect_vec(cr->dd,
+                               state_local->ddp_count,
+                               state_local->ddp_count_cg_gl,
+                               state_local->cg_gl,
+                               state_local->x,
+                               globalXRef);
             }
             if (mdof_flags & MDOF_V)
             {
                 auto globalVRef = MASTER(cr) ? state_global->v : gmx::ArrayRef<gmx::RVec>();
-                dd_collect_vec(cr->dd, state_local->ddp_count, state_local->ddp_count_cg_gl,
-                               state_local->cg_gl, state_local->v, globalVRef);
+                dd_collect_vec(cr->dd,
+                               state_local->ddp_count,
+                               state_local->ddp_count_cg_gl,
+                               state_local->cg_gl,
+                               state_local->v,
+                               globalVRef);
             }
         }
         f_global = of->f_global;
         if (mdof_flags & MDOF_F)
         {
-            dd_collect_vec(
-                    cr->dd, state_local->ddp_count, state_local->ddp_count_cg_gl, state_local->cg_gl, f_local,
-                    gmx::arrayRefFromArray(reinterpret_cast<gmx::RVec*>(of->f_global), f_local.size()));
+            auto globalFRef = MASTER(cr) ? gmx::arrayRefFromArray(
+                                      reinterpret_cast<gmx::RVec*>(of->f_global), of->natoms_global)
+                                         : gmx::ArrayRef<gmx::RVec>();
+            dd_collect_vec(cr->dd,
+                           state_local->ddp_count,
+                           state_local->ddp_count_cg_gl,
+                           state_local->cg_gl,
+                           f_local,
+                           globalFRef);
         }
     }
     else
@@ -566,8 +600,8 @@ void mdoutf_write_to_trajectory_files(FILE*                           fplog,
     {
         if (mdof_flags & MDOF_CPT)
         {
-            mdoutf_write_checkpoint(of, fplog, cr, step, t, state_global, observablesHistory,
-                                    modularSimulatorCheckpointData);
+            mdoutf_write_checkpoint(
+                    of, fplog, cr, step, t, state_global, observablesHistory, modularSimulatorCheckpointData);
         }
 
         if (mdof_flags & (MDOF_X | MDOF_V | MDOF_F))
@@ -578,8 +612,15 @@ void mdoutf_write_to_trajectory_files(FILE*                           fplog,
 
             if (of->fp_trn)
             {
-                gmx_trr_write_frame(of->fp_trn, step, t, state_local->lambda[efptFEP],
-                                    state_local->box, natoms, x, v, f);
+                gmx_trr_write_frame(of->fp_trn,
+                                    step,
+                                    t,
+                                    state_local->lambda[FreeEnergyPerturbationCouplingType::Fep],
+                                    state_local->box,
+                                    natoms,
+                                    x,
+                                    v,
+                                    f);
                 if (gmx_fio_flush(of->fp_trn) != 0)
                 {
                     gmx_file("Cannot write trajectory; maybe you are out of disk space?");
@@ -590,15 +631,31 @@ void mdoutf_write_to_trajectory_files(FILE*                           fplog,
                velocities and forces to it. */
             else if (of->tng)
             {
-                gmx_fwrite_tng(of->tng, FALSE, step, t, state_local->lambda[efptFEP],
-                               state_local->box, natoms, x, v, f);
+                gmx_fwrite_tng(of->tng,
+                               FALSE,
+                               step,
+                               t,
+                               state_local->lambda[FreeEnergyPerturbationCouplingType::Fep],
+                               state_local->box,
+                               natoms,
+                               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. */
             else if (of->tng_low_prec)
             {
-                gmx_fwrite_tng(of->tng_low_prec, FALSE, step, t, state_local->lambda[efptFEP],
-                               state_local->box, natoms, x, v, f);
+                gmx_fwrite_tng(of->tng_low_prec,
+                               FALSE,
+                               step,
+                               t,
+                               state_local->lambda[FreeEnergyPerturbationCouplingType::Fep],
+                               state_local->box,
+                               natoms,
+                               x,
+                               v,
+                               f);
             }
         }
         if (mdof_flags & MDOF_X_COMPRESSED)
@@ -628,8 +685,7 @@ void mdoutf_write_to_trajectory_files(FILE*                           fplog,
                     }
                 }
             }
-            if (write_xtc(of->fp_xtc, of->natoms_x_compressed, step, t, state_local->box, xxtc,
-                          of->x_compression_precision)
+            if (write_xtc(of->fp_xtc, of->natoms_x_compressed, step, t, state_local->box, xxtc, of->x_compression_precision)
                 == 0)
             {
                 gmx_fatal(FARGS,
@@ -637,8 +693,16 @@ void mdoutf_write_to_trajectory_files(FILE*                           fplog,
                           "simulation with major instabilities resulting in coordinates "
                           "that are NaN or too large to be represented in the XTC format.\n");
             }
-            gmx_fwrite_tng(of->tng_low_prec, TRUE, step, t, state_local->lambda[efptFEP],
-                           state_local->box, of->natoms_x_compressed, xxtc, nullptr, nullptr);
+            gmx_fwrite_tng(of->tng_low_prec,
+                           TRUE,
+                           step,
+                           t,
+                           state_local->lambda[FreeEnergyPerturbationCouplingType::Fep],
+                           state_local->box,
+                           of->natoms_x_compressed,
+                           xxtc,
+                           nullptr,
+                           nullptr);
             if (of->natoms_x_compressed != of->natoms_global)
             {
                 sfree(xxtc);
@@ -656,7 +720,7 @@ void mdoutf_write_to_trajectory_files(FILE*                           fplog,
                 }
                 if (mdof_flags & MDOF_LAMBDA)
                 {
-                    lambda = state_local->lambda[efptFEP];
+                    lambda = state_local->lambda[FreeEnergyPerturbationCouplingType::Fep];
                 }
                 gmx_fwrite_tng(of->tng, FALSE, step, t, lambda, box, natoms, nullptr, nullptr, nullptr);
             }
@@ -674,10 +738,9 @@ void mdoutf_write_to_trajectory_files(FILE*                           fplog,
                 }
                 if (mdof_flags & MDOF_LAMBDA_COMPRESSED)
                 {
-                    lambda = state_local->lambda[efptFEP];
+                    lambda = state_local->lambda[FreeEnergyPerturbationCouplingType::Fep];
                 }
-                gmx_fwrite_tng(of->tng_low_prec, FALSE, step, t, lambda, box, natoms, nullptr,
-                               nullptr, nullptr);
+                gmx_fwrite_tng(of->tng_low_prec, FALSE, step, t, lambda, box, natoms, nullptr, nullptr, nullptr);
             }
         }
 
@@ -696,10 +759,10 @@ void mdoutf_tng_close(gmx_mdoutf_t of)
 {
     if (of->tng || of->tng_low_prec)
     {
-        wallcycle_start(of->wcycle, ewcTRAJ);
+        wallcycle_start(of->wcycle, WallCycleCounter::Traj);
         gmx_tng_close(&of->tng);
         gmx_tng_close(&of->tng_low_prec);
-        wallcycle_stop(of->wcycle, ewcTRAJ);
+        wallcycle_stop(of->wcycle, WallCycleCounter::Traj);
     }
 }
 
index 88ef9068bf4457ca672759cae6ed4cbf16fef290..308f08cecc898d1b47be9ef1a074ceb720083248 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2017 The GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +57,7 @@ namespace gmx
 {
 enum class StartingBehavior;
 class IMDOutputProvider;
-struct MdModulesNotifier;
+struct MDModulesNotifiers;
 struct MdrunOptions;
 class WriteCheckpointDataHolder;
 } // namespace gmx
@@ -69,20 +69,20 @@ typedef struct gmx_mdoutf* gmx_mdoutf_t;
  * Returns a pointer to a data structure with all output file pointers
  * and names required by mdrun.
  */
-gmx_mdoutf_t init_mdoutf(FILE*                         fplog,
-                         int                           nfile,
-                         const t_filenm                fnm[],
-                         const gmx::MdrunOptions&      mdrunOptions,
-                         const t_commrec*              cr,
-                         gmx::IMDOutputProvider*       outputProvider,
-                         const gmx::MdModulesNotifier& mdModulesNotifier,
-                         const t_inputrec*             ir,
-                         const gmx_mtop_t*             mtop,
-                         const gmx_output_env_t*       oenv,
-                         gmx_wallcycle_t               wcycle,
-                         gmx::StartingBehavior         startingBehavior,
-                         bool                          simulationsShareState,
-                         const gmx_multisim_t*         ms);
+gmx_mdoutf_t init_mdoutf(FILE*                          fplog,
+                         int                            nfile,
+                         const t_filenm                 fnm[],
+                         const gmx::MdrunOptions&       mdrunOptions,
+                         const t_commrec*               cr,
+                         gmx::IMDOutputProvider*        outputProvider,
+                         const gmx::MDModulesNotifiers& mdModulesNotifiers,
+                         const t_inputrec*              ir,
+                         const gmx_mtop_t             mtop,
+                         const gmx_output_env_t*        oenv,
+                         gmx_wallcycle*                 wcycle,
+                         gmx::StartingBehavior          startingBehavior,
+                         bool                           simulationsShareState,
+                         const gmx_multisim_t*          ms);
 
 /*! \brief Getter for file pointer */
 ener_file_t mdoutf_get_fp_ene(gmx_mdoutf_t of);
@@ -91,7 +91,7 @@ ener_file_t mdoutf_get_fp_ene(gmx_mdoutf_t of);
 FILE* mdoutf_get_fp_dhdl(gmx_mdoutf_t of);
 
 /*! \brief Getter for wallcycle timer */
-gmx_wallcycle_t mdoutf_get_wcycle(gmx_mdoutf_t of);
+gmx_wallcycle* mdoutf_get_wcycle(gmx_mdoutf_t of);
 
 /*! \brief Close TNG files if they are open.
  *
index a32c758b39007ef8f5859777cb48878a95bf0a99..1456ae6c9c567eb80e8f4df3eb9d15794223705e 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -109,7 +109,7 @@ typedef struct
 
 /* Get the global molecule id, and the corresponding molecule type and id of the *
  * molblock from the global atom nr. */
-static int get_mol_id(int at, gmx_mtop_t* mtop, int* type, int* block)
+static int get_mol_id(int at, const gmx_mtop_t& mtop, int* type, int* block)
 {
     int mol_id = 0;
     int i;
@@ -119,9 +119,9 @@ static int get_mol_id(int at, gmx_mtop_t* mtop, int* type, int* block)
     mtopGetMolblockIndex(mtop, at, block, &mol_id, &atnr_mol);
     for (i = 0; i < *block; i++)
     {
-        mol_id += mtop->molblock[i].nmol;
+        mol_id += mtop.molblock[i].nmol;
     }
-    *type = mtop->molblock[*block].type;
+    *type = mtop.molblock[*block].type;
 
     return mol_id;
 }
@@ -148,7 +148,7 @@ static int get_molblock(int mol_id, const std::vector<gmx_molblock_t>& mblock)
  * level, if the same molecule type is found in another part of the system, these *
  * would also be affected. Therefore we have to check if the embedded and rest group *
  * share common molecule types. If so, membed will stop with an error. */
-static int get_mtype_list(t_block* at, gmx_mtop_t* mtop, t_block* tlist)
+static int get_mtype_list(t_block* at, const gmx_mtop_t& mtop, t_block* tlist)
 {
     int      i, j, nr;
     int      type = 0, block = 0;
@@ -179,7 +179,7 @@ static int get_mtype_list(t_block* at, gmx_mtop_t* mtop, t_block* tlist)
 }
 
 /* Do the actual check of the molecule types between embedded and rest group */
-static void check_types(t_block* ins_at, t_block* rest_at, gmx_mtop_t* mtop)
+static void check_types(t_block* ins_at, t_block* rest_at, const gmx_mtop_t& mtop)
 {
     t_block *ins_mtype, *rest_mtype;
     int      i, j;
@@ -209,9 +209,9 @@ static void check_types(t_block* ins_at, t_block* rest_at, gmx_mtop_t* mtop)
                         "moleculetype of the molecules %s in the inserted group. Do not forget to "
                         "provide\n"
                         "an appropriate *.itp file",
-                        *(mtop->moltype[rest_mtype->index[j]].name),
-                        *(mtop->moltype[rest_mtype->index[j]].name),
-                        *(mtop->moltype[rest_mtype->index[j]].name));
+                        *(mtop.moltype[rest_mtype->index[j]].name),
+                        *(mtop.moltype[rest_mtype->index[j]].name),
+                        *(mtop.moltype[rest_mtype->index[j]].name));
             }
         }
     }
@@ -381,7 +381,7 @@ static real est_prot_area(pos_ins_t* pos_ins, rvec* r, t_block* ins_at, mem_t* m
     return area;
 }
 
-static int init_mem_at(mem_t* mem_p, gmx_mtop_t* mtop, rvec* r, matrix box, pos_ins_t* pos_ins)
+static int init_mem_at(mem_t* mem_p, const gmx_mtop_t& mtop, rvec* r, matrix box, pos_ins_t* pos_ins)
 {
     int      i, j, at, mol, nmol, nmolbox, count;
     t_block* mem_a;
@@ -446,14 +446,15 @@ static int init_mem_at(mem_t* mem_p, gmx_mtop_t* mtop, rvec* r, matrix box, pos_
                   "so that one membrane is distributed over two periodic box images. Another "
                   "possibility is that\n"
                   "your water layer is not thick enough.\n",
-                  zmax, zmin);
+                  zmax,
+                  zmin);
     }
     mem_p->zmin = zmin;
     mem_p->zmax = zmax;
     mem_p->zmed = (zmax - zmin) / 2 + zmin;
 
     /*number of membrane molecules in protein box*/
-    nmolbox = count / mtop->moltype[mtop->molblock[block].type].atoms.nr;
+    nmolbox = count / mtop.moltype[mtop.molblock[block].type].atoms.nr;
     /*membrane area within the box defined by the min and max coordinates of the embedded molecule*/
     mem_area = (pos_ins->xmax[XX] - pos_ins->xmin[XX]) * (pos_ins->xmax[YY] - pos_ins->xmin[YY]);
     /*rough estimate of area per lipid, assuming there is only one type of lipid in the membrane*/
@@ -515,8 +516,12 @@ static void init_resize(t_block* ins_at, rvec* r_ins, pos_ins_t* pos_ins, mem_t*
             pos_ins->geom_cent[i][ZZ] = mem_p->zmed;
         }
 
-        fprintf(stderr, "Embedding piece %d with center of geometry: %f %f %f\n", i,
-                pos_ins->geom_cent[i][XX], pos_ins->geom_cent[i][YY], pos_ins->geom_cent[i][ZZ]);
+        fprintf(stderr,
+                "Embedding piece %d with center of geometry: %f %f %f\n",
+                i,
+                pos_ins->geom_cent[i][XX],
+                pos_ins->geom_cent[i][YY],
+                pos_ins->geom_cent[i][ZZ]);
     }
     fprintf(stderr, "\n");
 }
@@ -541,17 +546,17 @@ static void resize(rvec* r_ins, rvec* r, pos_ins_t* pos_ins, const rvec fac)
 
 /* generate the list of membrane molecules that overlap with the molecule to be embedded. *
  * The molecule to be embedded is already reduced in size. */
-static int gen_rm_list(rm_t*       rm_p,
-                       t_block*    ins_at,
-                       t_block*    rest_at,
-                       t_pbc*      pbc,
-                       gmx_mtop_t* mtop,
-                       rvec*       r,
-                       mem_t*      mem_p,
-                       pos_ins_t*  pos_ins,
-                       real        probe_rad,
-                       int         low_up_rm,
-                       gmx_bool    bALLOW_ASYMMETRY)
+static int gen_rm_list(rm_t*             rm_p,
+                       t_block*          ins_at,
+                       t_block*          rest_at,
+                       t_pbc*            pbc,
+                       const gmx_mtop_t& mtop,
+                       rvec*             r,
+                       mem_t*            mem_p,
+                       pos_ins_t*        pos_ins,
+                       real              probe_rad,
+                       int               low_up_rm,
+                       gmx_bool          bALLOW_ASYMMETRY)
 {
     int      i, j, k, l, at, at2, mol_id;
     int      type = 0, block = 0;
@@ -563,7 +568,7 @@ static int gen_rm_list(rm_t*       rm_p,
     int*     order;
 
     r_min_rad                        = probe_rad * probe_rad;
-    gmx::RangePartitioning molecules = gmx_mtop_molecules(*mtop);
+    gmx::RangePartitioning molecules = gmx_mtop_molecules(mtop);
     snew(rm_p->block, molecules.numBlocks());
     snew(rm_p->mol, molecules.numBlocks());
     nrm = nupper = 0;
@@ -655,7 +660,7 @@ static int gen_rm_list(rm_t*       rm_p,
         while (nupper != nlower)
         {
             mol_id = mem_p->mol_id[order[i]];
-            block  = get_molblock(mol_id, mtop->molblock);
+            block  = get_molblock(mol_id, mtop.molblock);
             bRM    = TRUE;
             for (l = 0; l < nrm; l++)
             {
@@ -1066,8 +1071,18 @@ gmx_membed_t* init_membed(FILE*          fplog,
         /* get input data out membed file */
         try
         {
-            get_input(opt2fn("-membed", nfile, fnm), &xy_fac, &xy_max, &z_fac, &z_max, &it_xy,
-                      &it_z, &probe_rad, &low_up_rm, &maxwarn, &pieces, &bALLOW_ASYMMETRY);
+            get_input(opt2fn("-membed", nfile, fnm),
+                      &xy_fac,
+                      &xy_max,
+                      &z_fac,
+                      &z_max,
+                      &it_xy,
+                      &it_z,
+                      &probe_rad,
+                      &low_up_rm,
+                      &maxwarn,
+                      &pieces,
+                      &bALLOW_ASYMMETRY);
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
 
@@ -1095,7 +1110,7 @@ gmx_membed_t* init_membed(FILE*          fplog,
             gnames.emplace_back(*groupName);
         }
 
-        atoms = gmx_mtop_global_atoms(mtop);
+        atoms = gmx_mtop_global_atoms(*mtop);
         snew(mem_p, 1);
         fprintf(stderr, "\nSelect a group to embed in the membrane:\n");
         get_index(&atoms, opt2fn_null("-mn", nfile, fnm), 1, &(ins_at->nr), &(ins_at->index), &ins);
@@ -1118,8 +1133,12 @@ gmx_membed_t* init_membed(FILE*          fplog,
             ins_grp_id = std::distance(gnames.begin(), found);
         }
         fprintf(stderr, "\nSelect a group to embed %s into (e.g. the membrane):\n", ins);
-        get_index(&atoms, opt2fn_null("-mn", nfile, fnm), 1, &(mem_p->mem_at.nr),
-                  &(mem_p->mem_at.index), &(mem_p->name));
+        get_index(&atoms,
+                  opt2fn_null("-mn", nfile, fnm),
+                  1,
+                  &(mem_p->mem_at.nr),
+                  &(mem_p->mem_at.index),
+                  &(mem_p->name));
 
         pos_ins->pieces = pieces;
         snew(pos_ins->nidx, pieces);
@@ -1128,8 +1147,7 @@ gmx_membed_t* init_membed(FILE*          fplog,
         if (pieces > 1)
         {
             fprintf(stderr, "\nSelect pieces to embed:\n");
-            get_index(&atoms, opt2fn_null("-mn", nfile, fnm), pieces, pos_ins->nidx,
-                      pos_ins->subindex, piecename);
+            get_index(&atoms, opt2fn_null("-mn", nfile, fnm), pieces, pos_ins->nidx, pos_ins->subindex, piecename);
         }
         else
         {
@@ -1162,7 +1180,9 @@ gmx_membed_t* init_membed(FILE*          fplog,
             fprintf(stderr,
                     "\nWarning %d;\nThe number of steps used to grow the xy-coordinates of %s (%d)"
                     " is probably too small.\nIncrease -nxy or.\n\n",
-                    warn, ins, it_xy);
+                    warn,
+                    ins,
+                    it_xy);
         }
 
         if ((it_z < min_it_z) && (z_fac < 0.99999999 || z_fac > 1.0000001))
@@ -1172,7 +1192,9 @@ gmx_membed_t* init_membed(FILE*          fplog,
                     "\nWarning %d;\nThe number of steps used to grow the z-coordinate of %s (%d)"
                     " is probably too small.\nIncrease -nz or the maxwarn setting in the membed "
                     "input file.\n\n",
-                    warn, ins, it_z);
+                    warn,
+                    ins,
+                    it_z);
         }
 
         if (it_xy + it_z > inputrec->nsteps)
@@ -1254,9 +1276,9 @@ gmx_membed_t* init_membed(FILE*          fplog,
         snew(rest_at, 1);
         init_ins_at(ins_at, rest_at, state, pos_ins, groups, ins_grp_id, xy_max);
         /* Check that moleculetypes in insertion group are not part of the rest of the system */
-        check_types(ins_at, rest_at, mtop);
+        check_types(ins_at, rest_at, *mtop);
 
-        init_mem_at(mem_p, mtop, state->x.rvec_array(), state->box, pos_ins);
+        init_mem_at(mem_p, *mtop, state->x.rvec_array(), state->box, pos_ins);
 
         prot_area = est_prot_area(pos_ins, state->x.rvec_array(), ins_at, mem_p);
         if ((prot_area > prot_vs_box)
@@ -1284,7 +1306,8 @@ gmx_membed_t* init_membed(FILE*          fplog,
         printf("The estimated area of the protein in the membrane is %.3f nm^2\n", prot_area);
         printf("\nThere are %d lipids in the membrane part that overlaps the protein.\n"
                "The area per lipid is %.4f nm^2.\n",
-               mem_p->nmol, mem_p->lip_area);
+               mem_p->nmol,
+               mem_p->lip_area);
 
         /* Maximum number of lipids to be removed*/
         max_lip_rm = static_cast<int>(2 * prot_area / mem_p->lip_area);
@@ -1295,7 +1318,10 @@ gmx_membed_t* init_membed(FILE*          fplog,
                "This resizing will be done with respect to the geometrical center of all protein "
                "atoms\n"
                "that span the membrane region, i.e. z between %.3f and %.3f\n\n",
-               xy_fac, z_fac, mem_p->zmin, mem_p->zmax);
+               xy_fac,
+               z_fac,
+               mem_p->zmin,
+               mem_p->zmax);
 
         /* resize the protein by xy and by z if necessary*/
         snew(r_ins, ins_at->nr);
@@ -1314,8 +1340,8 @@ gmx_membed_t* init_membed(FILE*          fplog,
         set_pbc(pbc, inputrec->pbcType, state->box);
 
         snew(rm_p, 1);
-        lip_rm = gen_rm_list(rm_p, ins_at, rest_at, pbc, mtop, state->x.rvec_array(), mem_p,
-                             pos_ins, probe_rad, low_up_rm, bALLOW_ASYMMETRY);
+        lip_rm = gen_rm_list(
+                rm_p, ins_at, rest_at, pbc, *mtop, state->x.rvec_array(), mem_p, pos_ins, probe_rad, low_up_rm, bALLOW_ASYMMETRY);
         lip_rm -= low_up_rm;
 
         if (fplog)
@@ -1361,7 +1387,8 @@ gmx_membed_t* init_membed(FILE*          fplog,
                     "while %d atoms are embedded. Make sure that the atoms to be embedded are not "
                     "in the same"
                     "molecule type as atoms that are not to be embedded.\n",
-                    rm_bonded_at, ins_at->nr);
+                    rm_bonded_at,
+                    ins_at->nr);
         }
 
         if (warn > maxwarn)
index 656993a85d1ff8f9136639680ffd624015c66f1c..cfab16e2820c445588f4a310b577a6995a1f6aff 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +34,8 @@
  * the research papers on the package. Check out http://www.gromacs.org.
  */
 
-#ifndef _gmx_membed_h
-#define _gmx_membed_h
+#ifndef GMX_MDLIB_MEMBED_H
+#define GMX_MDLIB_MEMBED_H
 
 #include <cstdio>
 
diff --git a/src/gromacs/mdlib/nsgrid.cpp b/src/gromacs/mdlib/nsgrid.cpp
deleted file mode 100644 (file)
index e9f7f0c..0000000
+++ /dev/null
@@ -1,889 +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,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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 "nsgrid.h"
-
-#include <cmath>
-#include <cstdio>
-#include <cstdlib>
-
-#include <algorithm>
-
-#include "gromacs/domdec/dlb.h"
-#include "gromacs/domdec/domdec.h"
-#include "gromacs/domdec/domdec_struct.h"
-#include "gromacs/fileio/pdbio.h"
-#include "gromacs/gmxlib/network.h"
-#include "gromacs/math/vec.h"
-#include "gromacs/mdtypes/forcerec.h"
-#include "gromacs/pbcutil/pbc.h"
-#include "gromacs/utility/fatalerror.h"
-#include "gromacs/utility/futil.h"
-#include "gromacs/utility/smalloc.h"
-
-/***********************************
- *         Grid Routines
- ***********************************/
-
-static const char* range_warn =
-        "Explanation: During neighborsearching, we assign each particle to a grid\n"
-        "based on its coordinates. If your system contains collisions or parameter\n"
-        "errors that give particles very high velocities you might end up with some\n"
-        "coordinates being +-Infinity or NaN (not-a-number). Obviously, we cannot\n"
-        "put these on a grid, so this is usually where we detect those errors.\n"
-        "Make sure your system is properly energy-minimized and that the potential\n"
-        "energy seems reasonable before trying again.";
-
-static void calc_x_av_stddev(int n, rvec* x, rvec av, rvec stddev)
-{
-    dvec s1, s2;
-    int  i, d;
-
-    clear_dvec(s1);
-    clear_dvec(s2);
-
-    for (i = 0; i < n; i++)
-    {
-        for (d = 0; d < DIM; d++)
-        {
-            s1[d] += x[i][d];
-            s2[d] += x[i][d] * x[i][d];
-        }
-    }
-
-    dsvmul(1.0 / n, s1, s1);
-    dsvmul(1.0 / n, s2, s2);
-
-    for (d = 0; d < DIM; d++)
-    {
-        av[d]     = s1[d];
-        stddev[d] = std::sqrt(s2[d] - s1[d] * s1[d]);
-    }
-}
-
-static void get_nsgrid_boundaries_vac(real av, real stddev, real* bound0, real* bound1, real* bdens0, real* bdens1)
-{
-    /* Set the grid to 2 times the standard deviation of
-     * the charge group centers in both directions.
-     * For a uniform bounded distribution the width is sqrt(3)*stddev,
-     * so all charge groups fall within the width.
-     * For a sphere stddev is r/sqrt(5): 99.2% falls within the width.
-     * For a Gaussian distribution 98% fall within the width.
-     */
-    *bound0 = av - NSGRID_STDDEV_FAC * stddev;
-    *bound1 = av + NSGRID_STDDEV_FAC * stddev;
-
-    *bdens0 = av - GRID_STDDEV_FAC * stddev;
-    *bdens1 = av + GRID_STDDEV_FAC * stddev;
-}
-
-static void dd_box_bounds_to_ns_bounds(real box0, real box_size, real* gr0, real* gr1)
-{
-    real av, stddev;
-
-    /* Redetermine av and stddev from the DD box boundaries */
-    av     = box0 + 0.5 * box_size;
-    stddev = 0.5 * box_size / GRID_STDDEV_FAC;
-
-    *gr0 = av - NSGRID_STDDEV_FAC * stddev;
-    *gr1 = av + NSGRID_STDDEV_FAC * stddev;
-}
-
-void get_nsgrid_boundaries(int           nboundeddim,
-                           matrix        box,
-                           gmx_domdec_t* dd,
-                           gmx_ddbox_t*  ddbox,
-                           rvec*         gr0,
-                           rvec*         gr1,
-                           int           ncg,
-                           rvec*         cgcm,
-                           rvec          grid_x0,
-                           rvec          grid_x1,
-                           real*         grid_density)
-{
-    rvec av, stddev;
-    real vol, bdens0, bdens1;
-    int  d;
-
-    if (nboundeddim < DIM)
-    {
-        calc_x_av_stddev(ncg, cgcm, av, stddev);
-    }
-
-    vol = 1;
-    for (d = 0; d < DIM; d++)
-    {
-        if (d < nboundeddim)
-        {
-            grid_x0[d] = (gr0 != nullptr ? (*gr0)[d] : 0);
-            grid_x1[d] = (gr1 != nullptr ? (*gr1)[d] : box[d][d]);
-            vol *= (grid_x1[d] - grid_x0[d]);
-        }
-        else
-        {
-            if (ddbox == nullptr)
-            {
-                get_nsgrid_boundaries_vac(av[d], stddev[d], &grid_x0[d], &grid_x1[d], &bdens0, &bdens1);
-            }
-            else
-            {
-                /* Temporary fix which uses global ddbox boundaries
-                 * for unbounded dimensions.
-                 * Should be replaced by local boundaries, which makes
-                 * the ns grid smaller and does not require global comm.
-                 */
-                dd_box_bounds_to_ns_bounds(ddbox->box0[d], ddbox->box_size[d], &grid_x0[d], &grid_x1[d]);
-                bdens0 = grid_x0[d];
-                bdens1 = grid_x1[d];
-            }
-            /* Check for a DD cell not at a lower edge */
-            if (dd != nullptr && gr0 != nullptr && dd->ci[d] > 0)
-            {
-                grid_x0[d] = (*gr0)[d];
-                bdens0     = (*gr0)[d];
-            }
-            /* Check for a DD cell not at a higher edge */
-            if (dd != nullptr && gr1 != nullptr && dd->ci[d] < dd->numCells[d] - 1)
-            {
-                grid_x1[d] = (*gr1)[d];
-                bdens1     = (*gr1)[d];
-            }
-            vol *= (bdens1 - bdens0);
-        }
-
-        if (debug)
-        {
-            fprintf(debug, "Set grid boundaries dim %d: %f %f\n", d, grid_x0[d], grid_x1[d]);
-        }
-    }
-
-    *grid_density = ncg / vol;
-}
-
-static void set_grid_sizes(matrix              box,
-                           rvec                izones_x0,
-                           rvec                izones_x1,
-                           real                rlist,
-                           const gmx_domdec_t* dd,
-                           const gmx_ddbox_t*  ddbox,
-                           t_grid*             grid,
-                           real                grid_density)
-{
-    int      i, j;
-    gmx_bool bDD, bDDRect;
-    rvec     izones_size;
-    real     inv_r_ideal, size, add_tric, radd;
-
-    for (i = 0; (i < DIM); i++)
-    {
-        if (debug)
-        {
-            fprintf(debug, "set_grid_sizes, i-zone bounds for dim %d: %6.3f %6.3f\n", i,
-                    izones_x0[i], izones_x1[i]);
-        }
-        izones_size[i] = izones_x1[i] - izones_x0[i];
-    }
-
-    /* Use the ideal number of cg's per cell to set the ideal cell size */
-    inv_r_ideal = std::cbrt(grid_density / grid->ncg_ideal);
-    if (rlist > 0 && inv_r_ideal * rlist < 1)
-    {
-        inv_r_ideal = 1 / rlist;
-    }
-    if (debug)
-    {
-        fprintf(debug, "CG density %f ideal ns cell size %f\n", grid_density, 1 / inv_r_ideal);
-    }
-
-    clear_rvec(grid->cell_offset);
-    for (i = 0; (i < DIM); i++)
-    {
-        /* Initial settings, for DD might change below */
-        grid->cell_offset[i] = izones_x0[i];
-        size                 = izones_size[i];
-
-        bDD = (dd != nullptr) && (dd->numCells[i] > 1);
-        if (!bDD)
-        {
-            bDDRect = FALSE;
-        }
-        else
-        {
-            /* With DD grid cell jumps only the first decomposition
-             * direction has uniform DD cell boundaries.
-             */
-            bDDRect = !((ddbox->tric_dir[i] != 0) || (dd_dlb_is_on(dd) && i != dd->dim[0]));
-
-            radd = rlist;
-            if (i >= ddbox->npbcdim
-                && (rlist == 0 || izones_x1[i] + radd > ddbox->box0[i] + ddbox->box_size[i]))
-            {
-                radd = ddbox->box0[i] + ddbox->box_size[i] - izones_x1[i];
-                if (radd < 0)
-                {
-                    radd = 0;
-                }
-            }
-
-            /* With DD we only need a grid of one DD cell size + rlist */
-            if (bDDRect)
-            {
-                size += radd;
-            }
-            else
-            {
-                size += radd / ddbox->skew_fac[i];
-            }
-
-            /* Check if the cell boundary in this direction is
-             * perpendicular to the Cartesian axis.
-             * Since grid->npbcdim isan integer that in principle can take
-             * any value, we help the compiler avoid warnings and potentially
-             * optimize by ensuring that j < DIM here.
-             */
-            for (j = i + 1; j < grid->npbcdim && j < DIM; j++)
-            {
-                if (box[j][i] != 0)
-                {
-                    /* Correct the offset for the home cell location */
-                    grid->cell_offset[i] += izones_x0[j] * box[j][i] / box[j][j];
-
-                    /* Correct the offset and size for the off-diagonal
-                     * displacement of opposing DD cell corners.
-                     */
-                    /* Without rouding we would need to add:
-                     * box[j][i]*rlist/(dd->skew_fac[i]*box[j][j])
-                     */
-                    /* Determine the shift for the corners of the triclinic box */
-                    add_tric = izones_size[j] * box[j][i] / box[j][j];
-                    if (dd->ndim == 1 && j == ZZ)
-                    {
-                        /* With 1D domain decomposition the cg's are not in
-                         * the triclinic box, but trilinic x-y and rectangular y-z.
-                         * Therefore we need to add the shift from the trilinic
-                         * corner to the corner at y=0.
-                         */
-                        add_tric += -box[YY][XX] * box[ZZ][YY] / box[YY][YY];
-                    }
-                    if (box[j][i] < 0)
-                    {
-                        grid->cell_offset[i] += add_tric;
-                        size -= add_tric;
-                    }
-                    else
-                    {
-                        size += add_tric;
-                    }
-                }
-            }
-        }
-        if (!bDDRect)
-        {
-            /* No DD or the box is triclinic is this direction:
-             * we will use the normal grid ns that checks all cells
-             * that are within cut-off distance of the i-particle.
-             */
-            grid->n[i] = gmx::roundToInt(size * inv_r_ideal);
-            if (grid->n[i] < 2)
-            {
-                grid->n[i] = 2;
-            }
-            grid->cell_size[i] = size / grid->n[i];
-            grid->ncpddc[i]    = 0;
-        }
-        else
-        {
-            /* We use grid->ncpddc[i] such that all particles
-             * in one ns cell belong to a single DD cell only.
-             * We can then beforehand exclude certain ns grid cells
-             * for non-home i-particles.
-             */
-            grid->ncpddc[i] = gmx::roundToInt(izones_size[i] * inv_r_ideal);
-            if (grid->ncpddc[i] < 2)
-            {
-                grid->ncpddc[i] = 2;
-            }
-            grid->cell_size[i] = izones_size[i] / grid->ncpddc[i];
-            grid->n[i]         = grid->ncpddc[i] + static_cast<int>(radd / grid->cell_size[i]) + 1;
-        }
-        if (debug)
-        {
-            fprintf(debug, "grid dim %d size %d x %f: %f - %f\n", i, grid->n[i], grid->cell_size[i],
-                    grid->cell_offset[i], grid->cell_offset[i] + grid->n[i] * grid->cell_size[i]);
-        }
-    }
-
-    if (debug)
-    {
-        fprintf(debug, "CG ncg ideal %d, actual density %.1f\n", grid->ncg_ideal,
-                grid_density * grid->cell_size[XX] * grid->cell_size[YY] * grid->cell_size[ZZ]);
-    }
-}
-
-t_grid* init_grid(FILE* fplog, t_forcerec* fr)
-{
-    char*   ptr;
-    t_grid* grid;
-
-    snew(grid, 1);
-
-    grid->npbcdim = numPbcDimensions(fr->pbcType);
-
-    if (fr->pbcType == PbcType::XY && fr->nwall == 2)
-    {
-        grid->nboundeddim = 3;
-    }
-    else
-    {
-        grid->nboundeddim = grid->npbcdim;
-    }
-
-    if (debug)
-    {
-        fprintf(debug, "The coordinates are bounded in %d dimensions\n", grid->nboundeddim);
-    }
-
-    /* The ideal number of cg's per ns grid cell seems to be 10 */
-    grid->ncg_ideal = 10;
-    ptr             = getenv("GMX_NSCELL_NCG");
-    if (ptr)
-    {
-        sscanf(ptr, "%d", &grid->ncg_ideal);
-        if (fplog)
-        {
-            fprintf(fplog, "Set ncg_ideal to %d\n", grid->ncg_ideal);
-        }
-        if (grid->ncg_ideal <= 0)
-        {
-            gmx_fatal(FARGS, "The number of cg's per cell should be > 0");
-        }
-    }
-    if (debug)
-    {
-        fprintf(debug, "Set ncg_ideal to %d\n", grid->ncg_ideal);
-    }
-
-    return grid;
-}
-
-void done_grid(t_grid* grid)
-{
-    if (grid == nullptr)
-    {
-        return;
-    }
-    grid->nr = 0;
-    clear_ivec(grid->n);
-    grid->ncells = 0;
-    sfree(grid->cell_index);
-    sfree(grid->a);
-    sfree(grid->index);
-    sfree(grid->nra);
-    grid->cells_nalloc = 0;
-    sfree(grid->dcx2);
-    sfree(grid->dcy2);
-    sfree(grid->dcz2);
-    grid->dc_nalloc = 0;
-
-    if (debug)
-    {
-        fprintf(debug, "Successfully freed memory for grid pointers.");
-    }
-    sfree(grid);
-}
-
-int xyz2ci_(int nry, int nrz, int x, int y, int z)
-/* Return the cell index */
-{
-    return (nry * nrz * x + nrz * y + z);
-}
-
-void ci2xyz(t_grid* grid, int i, int* x, int* y, int* z)
-/* Return x,y and z from the cell index */
-{
-    int ci;
-
-    range_check_mesg(i, 0, grid->nr, range_warn);
-
-    ci = grid->cell_index[i];
-    *x = ci / (grid->n[YY] * grid->n[ZZ]);
-    ci -= (*x) * grid->n[YY] * grid->n[ZZ];
-    *y = ci / grid->n[ZZ];
-    ci -= (*y) * grid->n[ZZ];
-    *z = ci;
-}
-
-static int ci_not_used(const ivec n)
-{
-    /* Return an improbable value */
-    return xyz2ci(n[YY], n[ZZ], 3 * n[XX], 3 * n[YY], 3 * n[ZZ]);
-}
-
-static void set_grid_ncg(t_grid* grid, int ncg)
-{
-    int nr_old, i;
-
-    grid->nr = ncg;
-    if (grid->nr + 1 > grid->nr_alloc)
-    {
-        nr_old         = grid->nr_alloc;
-        grid->nr_alloc = over_alloc_dd(grid->nr) + 1;
-        srenew(grid->cell_index, grid->nr_alloc);
-        for (i = nr_old; i < grid->nr_alloc; i++)
-        {
-            grid->cell_index[i] = 0;
-        }
-        srenew(grid->a, grid->nr_alloc);
-    }
-}
-
-void grid_first(FILE*              fplog,
-                t_grid*            grid,
-                gmx_domdec_t*      dd,
-                const gmx_ddbox_t* ddbox,
-                matrix             box,
-                rvec               izones_x0,
-                rvec               izones_x1,
-                real               rlist,
-                real               grid_density)
-{
-    int i, m;
-
-    set_grid_sizes(box, izones_x0, izones_x1, rlist, dd, ddbox, grid, grid_density);
-
-    grid->ncells = grid->n[XX] * grid->n[YY] * grid->n[ZZ];
-
-    if (grid->ncells + 1 > grid->cells_nalloc)
-    {
-        /* Allocate double the size so we have some headroom */
-        grid->cells_nalloc = 2 * grid->ncells;
-        srenew(grid->nra, grid->cells_nalloc + 1);
-        srenew(grid->index, grid->cells_nalloc + 1);
-
-        if (fplog)
-        {
-            fprintf(fplog, "Grid: %d x %d x %d cells\n", grid->n[XX], grid->n[YY], grid->n[ZZ]);
-        }
-    }
-
-    m = std::max(grid->n[XX], std::max(grid->n[YY], grid->n[ZZ]));
-    if (m > grid->dc_nalloc)
-    {
-        /* Allocate with double the initial size for box scaling */
-        grid->dc_nalloc = 2 * m;
-        srenew(grid->dcx2, grid->dc_nalloc);
-        srenew(grid->dcy2, grid->dc_nalloc);
-        srenew(grid->dcz2, grid->dc_nalloc);
-    }
-
-    grid->nr = 0;
-    for (i = 0; (i < grid->ncells); i++)
-    {
-        grid->nra[i] = 0;
-    }
-}
-
-static void calc_bor(int cg0, int cg1, int ncg, int CG0[2], int CG1[2])
-{
-    if (cg1 > ncg)
-    {
-        CG0[0] = cg0;
-        CG1[0] = ncg;
-        CG0[1] = 0;
-        CG1[1] = cg1 - ncg;
-    }
-    else
-    {
-        CG0[0] = cg0;
-        CG1[0] = cg1;
-        CG0[1] = 0;
-        CG1[1] = 0;
-    }
-    if (debug)
-    {
-        int m;
-
-        fprintf(debug, "calc_bor: cg0=%d, cg1=%d, ncg=%d\n", cg0, cg1, ncg);
-        for (m = 0; (m < 2); m++)
-        {
-            fprintf(debug, "CG0[%d]=%d, CG1[%d]=%d\n", m, CG0[m], m, CG1[m]);
-        }
-    }
-}
-
-void calc_elemnr(t_grid* grid, int cg0, int cg1, int ncg)
-{
-    int  CG0[2], CG1[2];
-    int* cell_index = grid->cell_index;
-    int* nra        = grid->nra;
-    int  i, m, ncells;
-    int  ci, not_used;
-
-    ncells = grid->ncells;
-    if (ncells <= 0)
-    {
-        gmx_fatal(FARGS, "Number of grid cells is zero. Probably the system and box collapsed.\n");
-    }
-
-    not_used = ci_not_used(grid->n);
-
-    calc_bor(cg0, cg1, ncg, CG0, CG1);
-    for (m = 0; (m < 2); m++)
-    {
-        for (i = CG0[m]; (i < CG1[m]); i++)
-        {
-            ci = cell_index[i];
-            if (ci != not_used)
-            {
-                range_check_mesg(ci, 0, ncells, range_warn);
-                nra[ci]++;
-            }
-        }
-    }
-}
-
-void calc_ptrs(t_grid* grid)
-{
-    int* index = grid->index;
-    int* nra   = grid->nra;
-    int  ix, iy, iz, ci, nr;
-    int  nnra, ncells;
-
-    ncells = grid->ncells;
-    if (ncells <= 0)
-    {
-        gmx_fatal(FARGS, "Number of grid cells is zero. Probably the system and box collapsed.\n");
-    }
-
-    ci = nr = 0;
-    for (ix = 0; (ix < grid->n[XX]); ix++)
-    {
-        for (iy = 0; (iy < grid->n[YY]); iy++)
-        {
-            for (iz = 0; (iz < grid->n[ZZ]); iz++, ci++)
-            {
-                range_check_mesg(ci, 0, ncells, range_warn);
-                index[ci] = nr;
-                nnra      = nra[ci];
-                nr += nnra;
-                nra[ci] = 0;
-            }
-        }
-    }
-}
-
-void grid_last(t_grid* grid, int cg0, int cg1, int ncg)
-{
-    int  CG0[2], CG1[2];
-    int  i, m;
-    int  ci, not_used, ind, ncells;
-    int* cell_index = grid->cell_index;
-    int* nra        = grid->nra;
-    int* index      = grid->index;
-    int* a          = grid->a;
-
-    ncells = grid->ncells;
-    if (ncells <= 0)
-    {
-        gmx_fatal(FARGS, "Number of grid cells is zero. Probably the system and box collapsed.\n");
-    }
-
-    not_used = ci_not_used(grid->n);
-
-    calc_bor(cg0, cg1, ncg, CG0, CG1);
-    for (m = 0; (m < 2); m++)
-    {
-        for (i = CG0[m]; (i < CG1[m]); i++)
-        {
-            ci = cell_index[i];
-            if (ci != not_used)
-            {
-                range_check_mesg(ci, 0, ncells, range_warn);
-                ind = index[ci] + nra[ci]++;
-                range_check_mesg(ind, 0, grid->nr, range_warn);
-                a[ind] = i;
-            }
-        }
-    }
-}
-
-void fill_grid(gmx_domdec_zones_t* dd_zones, t_grid* grid, int ncg_tot, int cg0, int cg1, rvec cg_cm[])
-{
-    int*     cell_index;
-    int      nry, nrz;
-    rvec     n_box, offset;
-    int      zone, ccg0, ccg1, cg, d, not_used;
-    ivec     shift0, useall, b0, b1, ind;
-    gmx_bool bUse;
-
-    if (cg0 == -1)
-    {
-        /* We have already filled the grid up to grid->ncg,
-         * continue from there.
-         */
-        cg0 = grid->nr;
-    }
-
-    set_grid_ncg(grid, ncg_tot);
-
-    cell_index = grid->cell_index;
-
-    /* Initiate cell borders */
-    nry = grid->n[YY];
-    nrz = grid->n[ZZ];
-    for (d = 0; d < DIM; d++)
-    {
-        if (grid->cell_size[d] > 0)
-        {
-            n_box[d] = 1 / grid->cell_size[d];
-        }
-        else
-        {
-            n_box[d] = 0;
-        }
-    }
-    copy_rvec(grid->cell_offset, offset);
-
-    if (debug)
-    {
-        fprintf(debug, "Filling grid from %d to %d\n", cg0, cg1);
-    }
-
-    if (dd_zones == nullptr)
-    {
-        for (cg = cg0; cg < cg1; cg++)
-        {
-            for (d = 0; d < DIM; d++)
-            {
-                ind[d] = static_cast<int>((cg_cm[cg][d] - offset[d]) * n_box[d]);
-                /* With pbc we should be done here.
-                 * Without pbc cg's outside the grid
-                 * should be assigned to the closest grid cell.
-                 */
-                if (ind[d] < 0)
-                {
-                    ind[d] = 0;
-                }
-                else if (ind[d] >= grid->n[d])
-                {
-                    ind[d] = grid->n[d] - 1;
-                }
-            }
-            cell_index[cg] = xyz2ci(nry, nrz, ind[XX], ind[YY], ind[ZZ]);
-        }
-    }
-    else
-    {
-        for (zone = 0; zone < dd_zones->n; zone++)
-        {
-            ccg0 = dd_zones->cg_range[zone];
-            ccg1 = dd_zones->cg_range[zone + 1];
-            if (ccg1 <= cg0 || ccg0 >= cg1)
-            {
-                continue;
-            }
-
-            /* Determine the ns grid cell limits for this DD zone */
-            for (d = 0; d < DIM; d++)
-            {
-                shift0[d] = dd_zones->shift[zone][d];
-                useall[d] = static_cast<int>(shift0[d] == 0 || d >= grid->npbcdim);
-                /* Check if we need to do normal or optimized grid assignments.
-                 * Normal is required for dims without DD or triclinic dims.
-                 * DD edge cell on dims without pbc will be automatically
-                 * be correct, since the shift=0 zones with have b0 and b1
-                 * set to the grid boundaries and there are no shift=1 zones.
-                 */
-                if (grid->ncpddc[d] == 0)
-                {
-                    b0[d] = 0;
-                    b1[d] = grid->n[d];
-                }
-                else
-                {
-                    if (shift0[d] == 0)
-                    {
-                        b0[d] = 0;
-                        b1[d] = grid->ncpddc[d];
-                    }
-                    else
-                    {
-                        /* shift = 1 */
-                        b0[d] = grid->ncpddc[d];
-                        b1[d] = grid->n[d];
-                    }
-                }
-            }
-
-            not_used = ci_not_used(grid->n);
-
-            /* Put all the charge groups of this DD zone on the grid */
-            for (cg = ccg0; cg < ccg1; cg++)
-            {
-                if (cell_index[cg] == -1)
-                {
-                    /* This cg has moved to another node */
-                    cell_index[cg] = NSGRID_SIGNAL_MOVED_FAC * grid->ncells;
-                    continue;
-                }
-
-                bUse = TRUE;
-                for (d = 0; d < DIM; d++)
-                {
-                    ind[d] = static_cast<int>((cg_cm[cg][d] - offset[d]) * n_box[d]);
-                    /* Here we have to correct for rounding problems,
-                     * as this cg_cm to cell index operation is not necessarily
-                     * binary identical to the operation for the DD zone assignment
-                     * and therefore a cg could end up in an unused grid cell.
-                     * For dimensions without pbc we need to check
-                     * for cells on the edge if charge groups are beyond
-                     * the grid and if so, store them in the closest cell.
-                     */
-                    if (ind[d] < b0[d])
-                    {
-                        ind[d] = b0[d];
-                    }
-                    else if (ind[d] >= b1[d])
-                    {
-                        if (useall[d])
-                        {
-                            ind[d] = b1[d] - 1;
-                        }
-                        else
-                        {
-                            /* Charge groups in this DD zone further away than the cut-off
-                             * in direction do not participate in non-bonded interactions.
-                             */
-                            bUse = FALSE;
-                        }
-                    }
-                }
-                if (cg > grid->nr_alloc)
-                {
-                    fprintf(stderr, "WARNING: nra_alloc %d cg0 %d cg1 %d cg %d\n", grid->nr_alloc,
-                            cg0, cg1, cg);
-                }
-                if (bUse)
-                {
-                    cell_index[cg] = xyz2ci(nry, nrz, ind[XX], ind[YY], ind[ZZ]);
-                }
-                else
-                {
-                    cell_index[cg] = not_used;
-                }
-            }
-        }
-    }
-}
-
-void check_grid(t_grid* grid)
-{
-    int ix, iy, iz, ci, cci, nra;
-
-    if (grid->ncells <= 0)
-    {
-        gmx_fatal(FARGS, "Number of grid cells is zero. Probably the system and box collapsed.\n");
-    }
-
-    ci  = 0;
-    cci = 0;
-    for (ix = 0; (ix < grid->n[XX]); ix++)
-    {
-        for (iy = 0; (iy < grid->n[YY]); iy++)
-        {
-            for (iz = 0; (iz < grid->n[ZZ]); iz++, ci++)
-            {
-                if (ci > 0)
-                {
-                    nra = grid->index[ci] - grid->index[cci];
-                    if (nra != grid->nra[cci])
-                    {
-                        gmx_fatal(FARGS, "nra=%d, grid->nra=%d, cci=%d", nra, grid->nra[cci], cci);
-                    }
-                }
-                cci = xyz2ci(grid->n[YY], grid->n[ZZ], ix, iy, iz);
-                range_check_mesg(cci, 0, grid->ncells, range_warn);
-
-                if (cci != ci)
-                {
-                    gmx_fatal(FARGS, "ci = %d, cci = %d", ci, cci);
-                }
-            }
-        }
-    }
-}
-
-void print_grid(FILE* log, t_grid* grid)
-{
-    int i, nra, index;
-    int ix, iy, iz, ci;
-
-    fprintf(log, "nr:        %d\n", grid->nr);
-    fprintf(log, "nrx:       %d\n", grid->n[XX]);
-    fprintf(log, "nry:       %d\n", grid->n[YY]);
-    fprintf(log, "nrz:       %d\n", grid->n[ZZ]);
-    fprintf(log, "ncg_ideal: %d\n", grid->ncg_ideal);
-    fprintf(log, "    i  cell_index\n");
-    for (i = 0; (i < grid->nr); i++)
-    {
-        fprintf(log, "%5d  %5d\n", i, grid->cell_index[i]);
-    }
-    fprintf(log, "cells\n");
-    fprintf(log, " ix iy iz   nr  index  cgs...\n");
-    ci = 0;
-    for (ix = 0; (ix < grid->n[XX]); ix++)
-    {
-        for (iy = 0; (iy < grid->n[YY]); iy++)
-        {
-            for (iz = 0; (iz < grid->n[ZZ]); iz++, ci++)
-            {
-                index = grid->index[ci];
-                nra   = grid->nra[ci];
-                fprintf(log, "%3d%3d%3d%5d%5d", ix, iy, iz, nra, index);
-                for (i = 0; (i < nra); i++)
-                {
-                    fprintf(log, "%5d", grid->a[index + i]);
-                }
-                fprintf(log, "\n");
-            }
-        }
-    }
-    fflush(log);
-}
diff --git a/src/gromacs/mdlib/nsgrid.h b/src/gromacs/mdlib/nsgrid.h
deleted file mode 100644 (file)
index 4606a8b..0000000
+++ /dev/null
@@ -1,159 +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,2019, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_NSGRID_H
-#define GMX_MDLIB_NSGRID_H
-
-#include <cstdio>
-
-#include "gromacs/math/vectypes.h"
-#include "gromacs/utility/real.h"
-
-struct gmx_domdec_t;
-struct gmx_domdec_zones_t;
-struct gmx_ddbox_t;
-struct t_forcerec;
-struct t_grid;
-
-typedef struct t_grid
-{
-    int  nr;           // Total number of charge groups
-    int  nboundeddim;  // The number of bounded dimensions
-    int  npbcdim;      // The number of dimensions with pbc
-    int  ncg_ideal;    // The ideal number of cg's per cell
-    ivec n;            // The dimension of the grid
-    int  ncells;       // Total number of cells
-    int  cells_nalloc; // Allocation size of index and nra
-    ivec ncpddc;       // The number of cells per DD cell
-    rvec cell_size;    // The size of the cells
-    rvec cell_offset;  // The offset of the cell (0,0,0)
-    int* cell_index;   // The cell number of each cg
-    int* index;        // The index into a for each cell
-                       // The location of the cell in the index
-                       // array can be found by calling xyz2ci
-    int*  nra;         // The number of entries in a cell
-    int   icg0;        // The start of the i-cg range
-    int   icg1;        // The end of the i-cg range
-    rvec* os0;
-    rvec* os1;
-    int*  a;         // The grid of cgs
-    int   nr_alloc;  // Allocation size of cell_index and a
-    real* dcx2;      // Squared distance from atom to j-cell
-    real* dcy2;      // Squared distance from atom to j-cell
-    real* dcz2;      // Squared distance from atom to j-cell
-    int   dc_nalloc; // Allocation size of dcx2, dyc2, dcz2
-} t_grid;
-
-/*! \brief Used when estimating the interaction density.
- *
- * GRID_STDDEV_FAC * stddev estimates the interaction density. The
- * value sqrt(3) == 1.73205080757 gives a uniform load for a
- * rectangular 3D block of charge groups. For a sphere, it is not a
- * bad approximation for 4x1x1 up to 4x2x2.
- *
- * \todo It would be nicer to use sqrt(3) here, when all code that
- * includes this file is in C++, which will let us cope with the
- * std::sqrt<T> on Windows. */
-static const real GRID_STDDEV_FAC = 1.73205080757;
-
-/*! \brief The extent of the neighborsearch grid is a bit larger than sqrt(3)
- * to account for less dense regions at the edges of the system.
- */
-static const real NSGRID_STDDEV_FAC = 2.0;
-
-#define NSGRID_SIGNAL_MOVED_FAC 4
-/* A cell index of NSGRID_SIGNAL_MOVED_FAC*ncells signals
- * that a charge group moved to another DD domain.
- */
-
-t_grid* init_grid(FILE* fplog, t_forcerec* fr);
-
-void done_grid(t_grid* grid);
-
-void get_nsgrid_boundaries(int                  nboundeddim,
-                           matrix               box,
-                           struct gmx_domdec_t* dd,
-                           gmx_ddbox_t*         ddbox,
-                           rvec*                gr0,
-                           rvec*                gr1,
-                           int                  ncg,
-                           rvec*                cgcm,
-                           rvec                 grid_x0,
-                           rvec                 grid_x1,
-                           real*                grid_density);
-/* Return the ns grid boundaries grid_x0 and grid_x1
- * and the estimate for the grid density.
- * For non-bounded dimensions the boundaries are determined
- * from the average and std.dev. of cgcm.
- * The are determined from box, unless gr0!=NULL or gr1!=NULL,
- * then they are taken from gr0 or gr1.
- * With dd and unbounded dimensions, the proper grid borders for cells
- * on the edges are determined from cgcm.
- */
-
-void grid_first(FILE*                log,
-                t_grid*              grid,
-                struct gmx_domdec_t* dd,
-                const gmx_ddbox_t*   ddbox,
-                matrix               box,
-                rvec                 izones_x0,
-                rvec                 izones_x1,
-                real                 rlong,
-                real                 grid_density);
-
-void fill_grid(struct gmx_domdec_zones_t* dd_zones, t_grid* grid, int ncg_tot, int cg0, int cg1, rvec cg_cm[]);
-/* Allocates space on the grid for ncg_tot cg's.
- * Fills the grid with cg's from cg0 to cg1.
- * When cg0 is -1, contiues filling from grid->nr to cg1.
- */
-
-void calc_elemnr(t_grid* grid, int cg0, int cg1, int ncg);
-
-void calc_ptrs(t_grid* grid);
-
-void grid_last(t_grid* grid, int cg0, int cg1, int ncg);
-
-int xyz2ci_(int nry, int nrz, int x, int y, int z);
-#define xyz2ci(nry, nrz, x, y, z) ((nry) * (nrz) * (x) + (nrz) * (y) + (z))
-/* Return the cell index */
-
-void ci2xyz(t_grid* grid, int i, int* x, int* y, int* z);
-
-void check_grid(t_grid* grid);
-
-void print_grid(FILE* log, t_grid* grid);
-
-#endif
index a0a288dbeedcc0833aad70c13582581063d9ea9e..c15d4efef54cdf423c78c1c563ad61a9d3a68a5e 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2012,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cmath>
 
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdtypes/commrec.h"
@@ -166,7 +167,8 @@ void count_bonded_distances(const gmx_mtop_t& mtop, const t_inputrec& ir, double
     gmx_bool   bSimdBondeds        = FALSE;
 #endif
 
-    bExcl = (ir.cutoff_scheme == ecutsGROUP && inputrecExclForces(&ir) && !EEL_FULL(ir.coulombtype));
+    bExcl = (ir.cutoff_scheme == CutoffScheme::Group && inputrecExclForces(&ir)
+             && !EEL_FULL(ir.coulombtype));
 
     if (bSimdBondeds)
     {
@@ -181,7 +183,7 @@ void count_bonded_distances(const gmx_mtop_t& mtop, const t_inputrec& ir, double
         {
             nonsimd_step_frac = 0;
         }
-        if (ir.epc != epcNO && 1.0 / ir.nstpcouple > nonsimd_step_frac)
+        if (ir.epc != PressureCoupling::No && 1.0 / ir.nstpcouple > nonsimd_step_frac)
         {
             nonsimd_step_frac = 1.0 / ir.nstpcouple;
         }
@@ -277,7 +279,7 @@ static void pp_verlet_load(const gmx_mtop_t& mtop,
     const real nbnxn_refkernel_fac = 8.0;
 #endif
 
-    bQRF = (EEL_RF(ir.coulombtype) || ir.coulombtype == eelCUT);
+    bQRF = (EEL_RF(ir.coulombtype) || ir.coulombtype == CoulombInteractionType::Cut);
 
     gmx::ArrayRef<const t_iparams> iparams = mtop.ffparams.iparams;
     atnr                                   = mtop.ffparams.atnr;
@@ -336,20 +338,26 @@ static void pp_verlet_load(const gmx_mtop_t& mtop,
 
     if (debug)
     {
-        fprintf(debug, "nqlj %d nq %d nlj %d rlist %.3f r_eff %.3f pairs per atom %.1f\n", nqlj, nq,
-                nlj, ir.rlist, r_eff, nppa);
+        fprintf(debug,
+                "nqlj %d nq %d nlj %d rlist %.3f r_eff %.3f pairs per atom %.1f\n",
+                nqlj,
+                nq,
+                nlj,
+                ir.rlist,
+                r_eff,
+                nppa);
     }
 
     /* Determine the cost per pair interaction */
     c_qlj = (bQRF ? c_nbnxn_qrf_lj : c_nbnxn_qexp_lj);
     c_q   = (bQRF ? c_nbnxn_qrf : c_nbnxn_qexp);
     c_lj  = c_nbnxn_lj;
-    if (ir.vdw_modifier == eintmodPOTSWITCH || EVDW_PME(ir.vdwtype))
+    if (ir.vdw_modifier == InteractionModifiers::PotSwitch || EVDW_PME(ir.vdwtype))
     {
         c_qlj += c_nbnxn_ljexp_add;
         c_lj += c_nbnxn_ljexp_add;
     }
-    if (EVDW_PME(ir.vdwtype) && ir.ljpme_combination_rule == eljpmeLB)
+    if (EVDW_PME(ir.vdwtype) && ir.ljpme_combination_rule == LongRangeVdW::LB)
     {
         /* We don't have LJ-PME LB comb. rule kernels, we use slow kernels */
         c_qlj *= nbnxn_refkernel_fac;
@@ -400,7 +408,7 @@ float pme_load_estimate(const gmx_mtop_t& mtop, const t_inputrec& ir, const matr
     {
         double grid = ir.nkx * ir.nky * gridNkzFactor;
 
-        int f = ((ir.efep != efepNO && bChargePerturbed) ? 2 : 1);
+        int f = ((ir.efep != FreeEnergyPerturbationType::No && bChargePerturbed) ? 2 : 1);
         cost_redist += c_pme_redist * nq_tot;
         cost_spread += f * c_pme_spread * nq_tot * gmx::power3(ir.pme_order);
         cost_fft += f * c_pme_fft * grid * std::log(grid) / std::log(2.0);
@@ -411,8 +419,8 @@ float pme_load_estimate(const gmx_mtop_t& mtop, const t_inputrec& ir, const matr
     {
         double grid = ir.nkx * ir.nky * gridNkzFactor;
 
-        int f = ((ir.efep != efepNO && bTypePerturbed) ? 2 : 1);
-        if (ir.ljpme_combination_rule == eljpmeLB)
+        int f = ((ir.efep != FreeEnergyPerturbationType::No && bTypePerturbed) ? 2 : 1);
+        if (ir.ljpme_combination_rule == LongRangeVdW::LB)
         {
             /* LB combination rule: we have 7 mesh terms */
             f *= 7;
@@ -436,7 +444,12 @@ float pme_load_estimate(const gmx_mtop_t& mtop, const t_inputrec& ir, const matr
                 "cost_spread %f\n"
                 "cost_fft    %f\n"
                 "cost_solve  %f\n",
-                cost_bond, cost_pp, cost_redist, cost_spread, cost_fft, cost_solve);
+                cost_bond,
+                cost_pp,
+                cost_redist,
+                cost_spread,
+                cost_fft,
+                cost_solve);
 
         fprintf(debug, "Estimate for relative PME load: %.3f\n", ratio);
     }
index 0e8dc749bc89eee14a6b863df60dc0c8cbe0b063..0816c06bcd5fa8c47851bbd37f45047bb9858343 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,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -86,9 +86,6 @@ int add_binr(t_bin* b, int nr, const real r[])
     /* Copy pointer */
     rbuf = b->rbuf + b->nreal;
 
-#if (defined __ICC && __ICC >= 1500 || defined __ICL && __ICL >= 1500) && defined __MIC__
-#    pragma novector /* Work-around for incorrect vectorization */
-#endif
     for (i = 0; (i < nr); i++)
     {
         rbuf[i] = r[i];
@@ -134,6 +131,11 @@ int add_bind(t_bin* b, int nr, const double r[])
     return index;
 }
 
+int add_bind(t_bin* b, gmx::ArrayRef<const double> r)
+{
+    return add_bind(b, r.size(), r.data());
+}
+
 void sum_bin(t_bin* b, const t_commrec* cr)
 {
     int i;
@@ -173,3 +175,8 @@ void extract_bind(t_bin* b, int index, int nr, double r[])
         r[i] = rbuf[i];
     }
 }
+
+void extract_bind(t_bin* b, int index, gmx::ArrayRef<double> r)
+{
+    extract_bind(b, index, r.size(), r.data());
+}
index 20cf110ab751ec75205a0b9981410b7bfaf0d46e..3d1bb3dff95b650920f09700c76773cd30c9eedb 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,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +61,7 @@ void reset_bin(t_bin* b);
 int add_binr(t_bin* b, int nr, const real r[]);
 int add_binr(t_bin* b, gmx::ArrayRef<const real> r);
 int add_bind(t_bin* b, int nr, const double r[]);
+int add_bind(t_bin* b, gmx::ArrayRef<const double> r);
 /* Add reals to the bin. Returns index */
 
 void sum_bin(t_bin* b, const t_commrec* cr);
@@ -69,6 +70,7 @@ void sum_bin(t_bin* b, const t_commrec* cr);
 void extract_binr(t_bin* b, int index, int nr, real r[]);
 void extract_binr(t_bin* b, int index, gmx::ArrayRef<real> r);
 void extract_bind(t_bin* b, int index, int nr, double r[]);
+void extract_bind(t_bin* b, int index, gmx::ArrayRef<double> r);
 /* Extract values from the bin, starting from index (see add_bin) */
 
 #endif
index 7e807061ac970663c1c93cc43519a220dbb447db..a471a6c828721422171c68b0347fd28556d380b3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -80,7 +80,7 @@ ResetHandler::ResetHandler(compat::not_null<SimulationSignal*> signal,
                            bool                                resetHalfway,
                            real                                maximumHoursToRun,
                            const MDLogger&                     mdlog,
-                           gmx_wallcycle_t                     wcycle,
+                           gmx_wallcycle                     wcycle,
                            gmx_walltime_accounting_t           walltime_accounting) :
     signal_(*signal),
     rankCanSetSignal_(false),
@@ -144,7 +144,7 @@ bool ResetHandler::resetCountersImpl(int64_t                     step,
                                      t_nrnb*                     nrnb,
                                      const gmx_pme_t*            pme,
                                      const pme_load_balancing_t* pme_loadbal,
-                                     gmx_wallcycle_t             wcycle,
+                                     gmx_wallcycle             wcycle,
                                      gmx_walltime_accounting_t   walltime_accounting)
 {
     /* Reset either if signal has been passed, or if reset step has been reached */
@@ -194,14 +194,14 @@ bool ResetHandler::resetCountersImpl(int64_t                     step,
             resetGpuProfiler();
         }
 
-        wallcycle_stop(wcycle, ewcRUN);
+        wallcycle_stop(wcycle, WallCycleCounter::Run);
         wallcycle_reset_all(wcycle);
         if (DOMAINDECOMP(cr))
         {
             reset_dd_statistics_counters(cr->dd);
         }
         clear_nrnb(nrnb);
-        wallcycle_start(wcycle, ewcRUN);
+        wallcycle_start(wcycle, WallCycleCounter::Run);
         walltime_accounting_reset_time(walltime_accounting, step);
         print_date_and_time(fplog, cr->nodeid, "Restarted time", gmx_gettime());
 
index 2185c2b70a5c371ea490169f9c708558d9e1fdab..d8a4a4ffe63ca3fb4ed6878e604767d432c8721c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -161,8 +161,7 @@ public:
     {
         if (simulationNeedsReset_)
         {
-            if (resetCountersImpl(step, step_rel, mdlog, fplog, cr, nbv, nrnb, pme, pme_loadbal,
-                                  wcycle, walltime_accounting))
+            if (resetCountersImpl(step, step_rel, mdlog, fplog, cr, nbv, nrnb, pme, pme_loadbal, wcycle, walltime_accounting))
             {
                 // need to reset the counters only once
                 simulationNeedsReset_ = false;
index a113269537176bf3635183d78f1f12059e87e478..3eea60f6787681a5cb459296061f540eea7d196d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -69,7 +69,12 @@ void calc_rffac(FILE* fplog, real eps_r, real eps_rf, real Rc, real* krf, real*
         fprintf(fplog,
                 "%s:\n"
                 "epsRF = %g, rc = %g, krf = %g, crf = %g, epsfac = %g\n",
-                eel_names[eelRF], eps_rf, Rc, *krf, *crf, ONE_4PI_EPS0 / eps_r);
+                enumValueToString(CoulombInteractionType::RF),
+                eps_rf,
+                Rc,
+                *krf,
+                *crf,
+                gmx::c_one4PiEps0 / eps_r);
         // Make sure we don't lose resolution in pow() by casting real arg to double
         real rmin = gmx::invcbrt(static_cast<double>(*krf * 2.0));
         fprintf(fplog, "The electrostatics potential has its minimum at r = %g\n", rmin);
index 508bafc750c96cdce13d95da186ed5db65dd6c6b..24d0d58fb564d929be4dc92785c976258af3e440 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +57,6 @@
 #include "gromacs/math/invertmatrix.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/constr.h"
-#include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/pbcutil/ishift.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/pbcutil/pbc_simd.h"
@@ -66,6 +65,7 @@
 #include "gromacs/topology/idef.h"
 #include "gromacs/topology/ifunc.h"
 #include "gromacs/topology/mtop_util.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
 
@@ -146,8 +146,7 @@ settleParameters(const real mO, const real mH, const real invmO, const real invm
     if (debug)
     {
         fprintf(debug, "wh =%g, rc = %g, ra = %g\n", params.wh, params.rc, params.ra);
-        fprintf(debug, "rb = %g, irc2 = %g, dHH = %g, dOH = %g\n", params.rb, params.irc2,
-                params.dHH, params.dOH);
+        fprintf(debug, "rb = %g, irc2 = %g, dHH = %g, dOH = %g\n", params.rb, params.irc2, params.dHH, params.dOH);
     }
 
     return params;
@@ -157,13 +156,11 @@ SettleData::SettleData(const gmx_mtop_t& mtop) :
     useSimd_(getenv("GMX_DISABLE_SIMD_KERNELS") == nullptr)
 {
     /* Check that we have only one settle type */
-    int                  settle_type = -1;
-    gmx_mtop_ilistloop_t iloop       = gmx_mtop_ilistloop_init(mtop);
-    int                  nmol;
-    const int            nral1 = 1 + NRAL(F_SETTLE);
-    while (const InteractionLists* ilists = gmx_mtop_ilistloop_next(iloop, &nmol))
+    int       settle_type = -1;
+    const int nral1       = 1 + NRAL(F_SETTLE);
+    for (const auto ilists : IListRange(mtop))
     {
-        const InteractionList& ilist = (*ilists)[F_SETTLE];
+        const InteractionList& ilist = ilists.list()[F_SETTLE];
         for (int i = 0; i < ilist.size(); i += nral1)
         {
             if (settle_type == -1)
@@ -197,10 +194,10 @@ SettleData::SettleData(const gmx_mtop_t& mtop) :
     parametersAllMasses1_ = settleParameters(1.0, 1.0, 1.0, 1.0, dOH, dHH);
 }
 
-void SettleData::setConstraints(const InteractionList& il_settle,
-                                const int              numHomeAtoms,
-                                const real*            masses,
-                                const real*            inverseMasses)
+void SettleData::setConstraints(const InteractionList&    il_settle,
+                                const int                 numHomeAtoms,
+                                gmx::ArrayRef<const real> masses,
+                                gmx::ArrayRef<const real> inverseMasses)
 {
 #if GMX_SIMD_HAVE_REAL
     const int pack_size = GMX_SIMD_REAL_WIDTH;
@@ -221,9 +218,12 @@ void SettleData::setConstraints(const InteractionList& il_settle,
         {
             int firstO              = iatoms[1];
             int firstH              = iatoms[2];
-            parametersMassWeighted_ = settleParameters(
-                    masses[firstO], masses[firstH], inverseMasses[firstO], inverseMasses[firstH],
-                    parametersAllMasses1_.dOH, parametersAllMasses1_.dHH);
+            parametersMassWeighted_ = settleParameters(masses[firstO],
+                                                       masses[firstH],
+                                                       inverseMasses[firstO],
+                                                       inverseMasses[firstH],
+                                                       parametersAllMasses1_.dOH,
+                                                       parametersAllMasses1_.dHH);
         }
 
         const int paddedSize = ((nsettle + pack_size - 1) / pack_size) * pack_size;
@@ -770,8 +770,7 @@ void csettle(const SettleData&               settled,
         set_pbc_simd(pbc, pbcSimd);
 
         settleTemplateWrapper<SimdReal, SimdBool, GMX_SIMD_REAL_WIDTH, const real*>(
-                settled, nthread, thread, pbcSimd, xPtr, xprimePtr, invdt, vPtr, bCalcVirial,
-                vir_r_m_dr, bErrorHasOccurred);
+                settled, nthread, thread, pbcSimd, xPtr, xprimePtr, invdt, vPtr, bCalcVirial, vir_r_m_dr, bErrorHasOccurred);
     }
     else
 #endif
@@ -790,9 +789,8 @@ void csettle(const SettleData&               settled,
             pbcNonNull = &pbcNo;
         }
 
-        settleTemplateWrapper<real, bool, 1, const t_pbc*>(settled, nthread, thread, pbcNonNull,
-                                                           &xPtr[0], &xprimePtr[0], invdt, &vPtr[0],
-                                                           bCalcVirial, vir_r_m_dr, bErrorHasOccurred);
+        settleTemplateWrapper<real, bool, 1, const t_pbc*>(
+                settled, nthread, thread, pbcNonNull, &xPtr[0], &xprimePtr[0], invdt, &vPtr[0], bCalcVirial, vir_r_m_dr, bErrorHasOccurred);
     }
 }
 
index 4714bd669fcd4b9a2d78d254ec6dc54fb1dd87fb..86bf81fbf12478561e3563ca6b515a0354c67ec1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -121,10 +121,10 @@ public:
     SettleData(const gmx_mtop_t& mtop);
 
     //! Sets the constraints from the interaction list and the masses
-    void setConstraints(const InteractionList& il_settle,
-                        int                    numHomeAtoms,
-                        const real*            masses,
-                        const real*            inverseMasses);
+    void setConstraints(const InteractionList&    il_settle,
+                        int                       numHomeAtoms,
+                        gmx::ArrayRef<const real> masses,
+                        gmx::ArrayRef<const real> inverseMasses);
 
     //! Returns settle parameters for constraining coordinates and forces
     const SettleParameters& parametersMassWeighted() const { return parametersMassWeighted_; }
diff --git a/src/gromacs/mdlib/settle_gpu.cpp b/src/gromacs/mdlib/settle_gpu.cpp
new file mode 100644 (file)
index 0000000..0c19d7a
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 SETTLE using GPU
+ *
+ * This file contains implementation for the data management of GPU version of SETTLE constraints algorithm.
+ *
+ * \author Artem Zhmurov <zhmurov@gmail.com>
+ *
+ * \ingroup module_mdlib
+ */
+#include "gmxpre.h"
+
+#include "settle_gpu.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#include <cmath>
+
+#include <algorithm>
+
+#include "gromacs/gpu_utils/devicebuffer.h"
+#include "gromacs/gpu_utils/gputraits.h"
+#include "gromacs/math/functions.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/mdlib/settle_gpu_internal.h"
+#include "gromacs/pbcutil/pbc.h"
+
+namespace gmx
+{
+
+void SettleGpu::apply(const DeviceBuffer<Float3> d_x,
+                      DeviceBuffer<Float3>       d_xp,
+                      const bool                 updateVelocities,
+                      DeviceBuffer<Float3>       d_v,
+                      const real                 invdt,
+                      const bool                 computeVirial,
+                      tensor                     virialScaled,
+                      const PbcAiuc              pbcAiuc)
+{
+
+    // Early exit if no settles
+    if (numSettles_ == 0)
+    {
+        return;
+    }
+
+    if (computeVirial)
+    {
+        // Fill with zeros so the values can be reduced to it
+        // Only 6 values are needed because virial is symmetrical
+        clearDeviceBufferAsync(&d_virialScaled_, 0, 6, deviceStream_);
+    }
+
+    launchSettleGpuKernel(numSettles_,
+                          d_atomIds_,
+                          settleParameters_,
+                          d_x,
+                          d_xp,
+                          updateVelocities,
+                          d_v,
+                          invdt,
+                          computeVirial,
+                          d_virialScaled_,
+                          pbcAiuc,
+                          deviceStream_);
+
+
+    if (computeVirial)
+    {
+        copyFromDeviceBuffer(
+                h_virialScaled_.data(), &d_virialScaled_, 0, 6, deviceStream_, GpuApiCallBehavior::Sync, nullptr);
+
+        // Mapping [XX, XY, XZ, YY, YZ, ZZ] internal format to a tensor object
+        virialScaled[XX][XX] += h_virialScaled_[0];
+        virialScaled[XX][YY] += h_virialScaled_[1];
+        virialScaled[XX][ZZ] += h_virialScaled_[2];
+
+        virialScaled[YY][XX] += h_virialScaled_[1];
+        virialScaled[YY][YY] += h_virialScaled_[3];
+        virialScaled[YY][ZZ] += h_virialScaled_[4];
+
+        virialScaled[ZZ][XX] += h_virialScaled_[2];
+        virialScaled[ZZ][YY] += h_virialScaled_[4];
+        virialScaled[ZZ][ZZ] += h_virialScaled_[5];
+    }
+
+    return;
+}
+
+SettleGpu::SettleGpu(const gmx_mtop_t& mtop, const DeviceContext& deviceContext, const DeviceStream& deviceStream) :
+    deviceContext_(deviceContext),
+    deviceStream_(deviceStream)
+{
+    static_assert(sizeof(real) == sizeof(float),
+                  "Real numbers should be in single precision in GPU code.");
+
+    // This is to prevent the assertion failure for the systems without water
+    int totalSettles = 0;
+    for (unsigned mt = 0; mt < mtop.moltype.size(); mt++)
+    {
+        const int        nral1           = 1 + NRAL(F_SETTLE);
+        InteractionList  interactionList = mtop.moltype[mt].ilist[F_SETTLE];
+        std::vector<int> iatoms          = interactionList.iatoms;
+        totalSettles += iatoms.size() / nral1;
+    }
+    if (totalSettles == 0)
+    {
+        return;
+    }
+
+    // TODO This should be lifted to a separate subroutine that gets the values of Oxygen and
+    // Hydrogen masses, checks if they are consistent across the topology and if there is no more
+    // than two values for each mass if the free energy perturbation is enabled. In later case,
+    // masses may need to be updated on a regular basis (i.e. in set(...) method).
+    // TODO Do the checks for FEP
+    real mO = -1.0;
+    real mH = -1.0;
+
+    for (unsigned mt = 0; mt < mtop.moltype.size(); mt++)
+    {
+        const int        nral1           = 1 + NRAL(F_SETTLE);
+        InteractionList  interactionList = mtop.moltype[mt].ilist[F_SETTLE];
+        std::vector<int> iatoms          = interactionList.iatoms;
+        for (unsigned i = 0; i < iatoms.size() / nral1; i++)
+        {
+            WaterMolecule settler;
+            settler.ow1 = iatoms[i * nral1 + 1]; // Oxygen index
+            settler.hw2 = iatoms[i * nral1 + 2]; // First hydrogen index
+            settler.hw3 = iatoms[i * nral1 + 3]; // Second hydrogen index
+            t_atom ow1  = mtop.moltype[mt].atoms.atom[settler.ow1];
+            t_atom hw2  = mtop.moltype[mt].atoms.atom[settler.hw2];
+            t_atom hw3  = mtop.moltype[mt].atoms.atom[settler.hw3];
+
+            if (mO < 0)
+            {
+                mO = ow1.m;
+            }
+            if (mH < 0)
+            {
+                mH = hw2.m;
+            }
+            GMX_RELEASE_ASSERT(mO == ow1.m,
+                               "Topology has different values for oxygen mass. Should be identical "
+                               "in order to use SETTLE.");
+            GMX_RELEASE_ASSERT(hw2.m == hw3.m && hw2.m == mH,
+                               "Topology has different values for hydrogen mass. Should be "
+                               "identical in order to use SETTLE.");
+        }
+    }
+
+    GMX_RELEASE_ASSERT(mO > 0, "Could not find oxygen mass in the topology. Needed in SETTLE.");
+    GMX_RELEASE_ASSERT(mH > 0, "Could not find hydrogen mass in the topology. Needed in SETTLE.");
+
+    // TODO Very similar to SETTLE initialization on CPU. Should be lifted to a separate method
+    // (one that gets dOH and dHH values and checks them for consistency)
+    int settle_type = -1;
+    for (unsigned mt = 0; mt < mtop.moltype.size(); mt++)
+    {
+        const int       nral1           = 1 + NRAL(F_SETTLE);
+        InteractionList interactionList = mtop.moltype[mt].ilist[F_SETTLE];
+        for (int i = 0; i < interactionList.size(); i += nral1)
+        {
+            if (settle_type == -1)
+            {
+                settle_type = interactionList.iatoms[i];
+            }
+            else if (interactionList.iatoms[i] != settle_type)
+            {
+                gmx_fatal(FARGS,
+                          "The [molecules] section of your topology specifies more than one block "
+                          "of\n"
+                          "a [moleculetype] with a [settles] block. Only one such is allowed.\n"
+                          "If you are trying to partition your solvent into different *groups*\n"
+                          "(e.g. for freezing, T-coupling, etc.), you are using the wrong "
+                          "approach. Index\n"
+                          "files specify groups. Otherwise, you may wish to change the least-used\n"
+                          "block of molecules with SETTLE constraints into 3 normal constraints.");
+            }
+        }
+    }
+
+    GMX_RELEASE_ASSERT(settle_type >= 0, "settle_init called without settles");
+
+    real dOH = mtop.ffparams.iparams[settle_type].settle.doh;
+    real dHH = mtop.ffparams.iparams[settle_type].settle.dhh;
+
+    settleParameters_ = settleParameters(mO, mH, 1.0 / mO, 1.0 / mH, dOH, dHH);
+
+    allocateDeviceBuffer(&d_virialScaled_, 6, deviceContext_);
+    h_virialScaled_.resize(6);
+}
+
+SettleGpu::~SettleGpu()
+{
+    // Early exit if there is no settles
+    if (numSettles_ == 0)
+    {
+        return;
+    }
+    freeDeviceBuffer(&d_virialScaled_);
+    if (numAtomIdsAlloc_ > 0)
+    {
+        freeDeviceBuffer(&d_atomIds_);
+    }
+}
+
+void SettleGpu::set(const InteractionDefinitions& idef)
+{
+    const int              nral1     = 1 + NRAL(F_SETTLE);
+    const InteractionList& il_settle = idef.il[F_SETTLE];
+    ArrayRef<const int>    iatoms    = il_settle.iatoms;
+    numSettles_                      = il_settle.size() / nral1;
+
+    reallocateDeviceBuffer(&d_atomIds_, numSettles_, &numAtomIds_, &numAtomIdsAlloc_, deviceContext_);
+    h_atomIds_.resize(numSettles_);
+    for (int i = 0; i < numSettles_; i++)
+    {
+        WaterMolecule settler;
+        settler.ow1   = iatoms[i * nral1 + 1]; // Oxygen index
+        settler.hw2   = iatoms[i * nral1 + 2]; // First hydrogen index
+        settler.hw3   = iatoms[i * nral1 + 3]; // Second hydrogen index
+        h_atomIds_[i] = settler;
+    }
+    copyToDeviceBuffer(
+            &d_atomIds_, h_atomIds_.data(), 0, numSettles_, deviceStream_, GpuApiCallBehavior::Sync, nullptr);
+}
+
+} // namespace gmx
similarity index 82%
rename from src/gromacs/mdlib/settle_gpu.cuh
rename to src/gromacs/mdlib/settle_gpu.h
index 3a96ec4d3921bb20ea3f3ea3d60a0a2baf86dd24..641c53d95ab44240e94a9c229e30a59445108f2a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  *
  * \ingroup module_mdlib
  */
-#ifndef GMX_MDLIB_SETTLE_GPU_CUH
-#define GMX_MDLIB_SETTLE_GPU_CUH
+#ifndef GMX_MDLIB_SETTLE_GPU_H
+#define GMX_MDLIB_SETTLE_GPU_H
 
 #include "gmxpre.h"
 
+#include "gromacs/gpu_utils/devicebuffer_datatype.h"
 #include "gromacs/gpu_utils/device_context.h"
 #include "gromacs/gpu_utils/device_stream.h"
-#include "gromacs/gpu_utils/gputraits.cuh"
+#include "gromacs/gpu_utils/gputraits.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/invertmatrix.h"
 #include "gromacs/math/vec.h"
@@ -61,6 +62,18 @@ class InteractionDefinitions;
 namespace gmx
 {
 
+//! Indices of atoms in a water molecule
+struct WaterMolecule
+{
+    //! Oxygen atom
+    int ow1;
+    //! First hydrogen atom
+    int hw2;
+    //! Second hydrogen atom
+    int hw3;
+};
+
+
 /*! \internal \brief Class with interfaces and data for GPU version of SETTLE. */
 class SettleGpu
 {
@@ -101,14 +114,14 @@ public:
      * \param[in,out] virialScaled      Scaled virial tensor to be updated.
      * \param[in]     pbcAiuc           PBC data.
      */
-    void apply(const float3* d_x,
-               float3*       d_xp,
-               const bool    updateVelocities,
-               float3*       d_v,
-               const real    invdt,
-               const bool    computeVirial,
-               tensor        virialScaled,
-               const PbcAiuc pbcAiuc);
+    void apply(const DeviceBuffer<Float3> d_x,
+               DeviceBuffer<Float3>       d_xp,
+               const bool                 updateVelocities,
+               DeviceBuffer<Float3>       d_v,
+               const real                 invdt,
+               const bool                 computeVirial,
+               tensor                     virialScaled,
+               const PbcAiuc              pbcAiuc);
 
     /*! \brief
      * Update data-structures (e.g. after NB search step).
@@ -133,15 +146,15 @@ private:
     //! Scaled virial tensor (9 reals, GPU)
     std::vector<float> h_virialScaled_;
     //! Scaled virial tensor (9 reals, GPU)
-    float* d_virialScaled_;
+    DeviceBuffer<float> d_virialScaled_;
 
     //! Number of settles
     int numSettles_ = 0;
 
-    //! Indexes of atoms (.x for oxygen, .y and.z for hydrogens, CPU)
-    std::vector<int3> h_atomIds_;
-    //! Indexes of atoms (.x for oxygen, .y and.z for hydrogens, GPU)
-    int3* d_atomIds_;
+    //! Indexes of atoms (.i for oxygen, .j and.k for hydrogens, CPU)
+    std::vector<WaterMolecule> h_atomIds_;
+    //! Indexes of atoms (.i for oxygen, .j and.k for hydrogens, GPU)
+    DeviceBuffer<WaterMolecule> d_atomIds_;
     //! Current size of the array of atom IDs
     int numAtomIds_ = -1;
     //! Allocated size for the array of atom IDs
@@ -153,4 +166,4 @@ private:
 
 } // namespace gmx
 
-#endif // GMX_MDLIB_SETTLE_GPU_CUH
+#endif // GMX_MDLIB_SETTLE_GPU_H
similarity index 62%
rename from src/gromacs/mdlib/settle_gpu.cu
rename to src/gromacs/mdlib/settle_gpu_internal.cu
index c02f0d588438d5a45698a4ec65b35f6f16820d9a..11dd63b035a12592632c735cf7a9fd3fe06fc669 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  */
 /*! \internal \file
  *
- * \brief Implements SETTLE using CUDA
- *
- * This file contains implementation of SETTLE constraints algorithm
- * using CUDA, including class initialization, data-structures management
- * and GPU kernel.
+ * \brief CUDA-specific routines for the GPU implementation of SETTLE constraints algorithm.
  *
  *
  * \author Artem Zhmurov <zhmurov@gmail.com>
@@ -47,7 +43,7 @@
  */
 #include "gmxpre.h"
 
-#include "settle_gpu.cuh"
+#include "settle_gpu_internal.h"
 
 #include <assert.h>
 #include <stdio.h>
 #include "gromacs/gpu_utils/cuda_arch_utils.cuh"
 #include "gromacs/gpu_utils/cudautils.cuh"
 #include "gromacs/gpu_utils/devicebuffer.h"
-#include "gromacs/gpu_utils/gputraits.cuh"
+#include "gromacs/gpu_utils/gputraits.h"
+#include "gromacs/gpu_utils/typecasts.cuh"
 #include "gromacs/gpu_utils/vectype_ops.cuh"
+#include "gromacs/math/functions.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/pbcutil/pbc_aiuc_cuda.cuh"
@@ -69,9 +67,10 @@ namespace gmx
 {
 
 //! Number of CUDA threads in a block
-constexpr static int c_threadsPerBlock = 256;
+constexpr static int sc_threadsPerBlock = 256;
+
 //! Maximum number of threads in a block (for __launch_bounds__)
-constexpr static int c_maxThreadsPerBlock = c_threadsPerBlock;
+constexpr static int sc_maxThreadsPerBlock = sc_threadsPerBlock;
 
 /*! \brief SETTLE constraints kernel
  *
@@ -92,9 +91,9 @@ constexpr static int c_maxThreadsPerBlock = c_threadsPerBlock;
  * \param [in]      pbcAiuc          Periodic boundary conditions data.
  */
 template<bool updateVelocities, bool computeVirial>
-__launch_bounds__(c_maxThreadsPerBlock) __global__
+__launch_bounds__(sc_maxThreadsPerBlock) __global__
         void settle_kernel(const int numSettles,
-                           const int3* __restrict__ gm_settles,
+                           const WaterMolecule* __restrict__ gm_settles,
                            const SettleParameters pars,
                            const float3* __restrict__ gm_x,
                            float3* __restrict__ gm_xprime,
@@ -129,15 +128,15 @@ __launch_bounds__(c_maxThreadsPerBlock) __global__
     {
         // These are the indexes of three atoms in a single 'water' molecule.
         // TODO Can be reduced to one integer if atoms are consecutive in memory.
-        int3 indices = gm_settles[tid];
+        WaterMolecule indices = gm_settles[tid];
 
-        float3 x_ow1 = gm_x[indices.x];
-        float3 x_hw2 = gm_x[indices.y];
-        float3 x_hw3 = gm_x[indices.z];
+        float3 x_ow1 = gm_x[indices.ow1];
+        float3 x_hw2 = gm_x[indices.hw2];
+        float3 x_hw3 = gm_x[indices.hw3];
 
-        float3 xprime_ow1 = gm_xprime[indices.x];
-        float3 xprime_hw2 = gm_xprime[indices.y];
-        float3 xprime_hw3 = gm_xprime[indices.z];
+        float3 xprime_ow1 = gm_xprime[indices.ow1];
+        float3 xprime_hw2 = gm_xprime[indices.hw2];
+        float3 xprime_hw3 = gm_xprime[indices.hw3];
 
         float3 dist21 = pbcDxAiuc(pbcAiuc, x_hw2, x_ow1);
         float3 dist31 = pbcDxAiuc(pbcAiuc, x_hw3, x_ow1);
@@ -272,24 +271,24 @@ __launch_bounds__(c_maxThreadsPerBlock) __global__
         const float3 dxHw2 = b3 - b1;
         const float3 dxHw3 = c3 - c1;
 
-        gm_xprime[indices.x] = xprime_ow1 + dxOw1;
-        gm_xprime[indices.y] = xprime_hw2 + dxHw2;
-        gm_xprime[indices.z] = xprime_hw3 + dxHw3;
+        gm_xprime[indices.ow1] = xprime_ow1 + dxOw1;
+        gm_xprime[indices.hw2] = xprime_hw2 + dxHw2;
+        gm_xprime[indices.hw3] = xprime_hw3 + dxHw3;
 
         if (updateVelocities)
         {
-            float3 v_ow1 = gm_v[indices.x];
-            float3 v_hw2 = gm_v[indices.y];
-            float3 v_hw3 = gm_v[indices.z];
+            float3 v_ow1 = gm_v[indices.ow1];
+            float3 v_hw2 = gm_v[indices.hw2];
+            float3 v_hw3 = gm_v[indices.hw3];
 
             /* Add the position correction divided by dt to the velocity */
             v_ow1 = dxOw1 * invdt + v_ow1;
             v_hw2 = dxHw2 * invdt + v_hw2;
             v_hw3 = dxHw3 * invdt + v_hw3;
 
-            gm_v[indices.x] = v_ow1;
-            gm_v[indices.y] = v_hw2;
-            gm_v[indices.z] = v_hw3;
+            gm_v[indices.ow1] = v_ow1;
+            gm_v[indices.hw2] = v_hw2;
+            gm_v[indices.hw3] = v_hw3;
         }
 
         if (computeVirial)
@@ -395,218 +394,63 @@ inline auto getSettleKernelPtr(const bool updateVelocities, const bool computeVi
     return kernelPtr;
 }
 
-void SettleGpu::apply(const float3* d_x,
-                      float3*       d_xp,
-                      const bool    updateVelocities,
-                      float3*       d_v,
-                      const real    invdt,
-                      const bool    computeVirial,
-                      tensor        virialScaled,
-                      const PbcAiuc pbcAiuc)
+void launchSettleGpuKernel(const int                         numSettles,
+                           const DeviceBuffer<WaterMolecule> d_atomIds,
+                           const SettleParameters            settleParameters,
+                           const DeviceBuffer<Float3>        d_x,
+                           DeviceBuffer<Float3>              d_xp,
+                           const bool                        updateVelocities,
+                           DeviceBuffer<Float3>              d_v,
+                           const real                        invdt,
+                           const bool                        computeVirial,
+                           DeviceBuffer<float>               virialScaled,
+                           const PbcAiuc                     pbcAiuc,
+                           const DeviceStream&               deviceStream)
 {
-
-    ensureNoPendingDeviceError("In CUDA version SETTLE");
-
-    // Early exit if no settles
-    if (numSettles_ == 0)
-    {
-        return;
-    }
-
-    if (computeVirial)
-    {
-        // Fill with zeros so the values can be reduced to it
-        // Only 6 values are needed because virial is symmetrical
-        clearDeviceBufferAsync(&d_virialScaled_, 0, 6, deviceStream_);
-    }
+    static_assert(
+            gmx::isPowerOfTwo(sc_threadsPerBlock),
+            "Number of threads per block should be a power of two in order for reduction to work.");
 
     auto kernelPtr = getSettleKernelPtr(updateVelocities, computeVirial);
 
     KernelLaunchConfig config;
-    config.blockSize[0] = c_threadsPerBlock;
+    config.blockSize[0] = sc_threadsPerBlock;
     config.blockSize[1] = 1;
     config.blockSize[2] = 1;
-    config.gridSize[0]  = (numSettles_ + c_threadsPerBlock - 1) / c_threadsPerBlock;
+    config.gridSize[0]  = (numSettles + sc_threadsPerBlock - 1) / sc_threadsPerBlock;
     config.gridSize[1]  = 1;
     config.gridSize[2]  = 1;
+
     // Shared memory is only used for virial reduction
     if (computeVirial)
     {
-        config.sharedMemorySize = c_threadsPerBlock * 6 * sizeof(float);
+        config.sharedMemorySize = sc_threadsPerBlock * 6 * sizeof(float);
     }
     else
     {
         config.sharedMemorySize = 0;
     }
 
-    const auto kernelArgs = prepareGpuKernelArguments(kernelPtr, config, &numSettles_, &d_atomIds_,
-                                                      &settleParameters_, &d_x, &d_xp, &invdt, &d_v,
-                                                      &d_virialScaled_, &pbcAiuc);
-
-    launchGpuKernel(kernelPtr, config, deviceStream_, nullptr,
-                    "settle_kernel<updateVelocities, computeVirial>", kernelArgs);
-
-    if (computeVirial)
-    {
-        copyFromDeviceBuffer(h_virialScaled_.data(), &d_virialScaled_, 0, 6, deviceStream_,
-                             GpuApiCallBehavior::Sync, nullptr);
-
-        // Mapping [XX, XY, XZ, YY, YZ, ZZ] internal format to a tensor object
-        virialScaled[XX][XX] += h_virialScaled_[0];
-        virialScaled[XX][YY] += h_virialScaled_[1];
-        virialScaled[XX][ZZ] += h_virialScaled_[2];
-
-        virialScaled[YY][XX] += h_virialScaled_[1];
-        virialScaled[YY][YY] += h_virialScaled_[3];
-        virialScaled[YY][ZZ] += h_virialScaled_[4];
-
-        virialScaled[ZZ][XX] += h_virialScaled_[2];
-        virialScaled[ZZ][YY] += h_virialScaled_[4];
-        virialScaled[ZZ][ZZ] += h_virialScaled_[5];
-    }
+    const auto kernelArgs = prepareGpuKernelArguments(kernelPtr,
+                                                      config,
+                                                      &numSettles,
+                                                      &d_atomIds,
+                                                      &settleParameters,
+                                                      asFloat3Pointer(&d_x),
+                                                      asFloat3Pointer(&d_xp),
+                                                      &invdt,
+                                                      asFloat3Pointer(&d_v),
+                                                      &virialScaled,
+                                                      &pbcAiuc);
+
+    launchGpuKernel(kernelPtr,
+                    config,
+                    deviceStream,
+                    nullptr,
+                    "settle_kernel<updateVelocities, computeVirial>",
+                    kernelArgs);
 
     return;
 }
 
-SettleGpu::SettleGpu(const gmx_mtop_t& mtop, const DeviceContext& deviceContext, const DeviceStream& deviceStream) :
-    deviceContext_(deviceContext),
-    deviceStream_(deviceStream)
-{
-    static_assert(sizeof(real) == sizeof(float),
-                  "Real numbers should be in single precision in GPU code.");
-    static_assert(
-            c_threadsPerBlock > 0 && ((c_threadsPerBlock & (c_threadsPerBlock - 1)) == 0),
-            "Number of threads per block should be a power of two in order for reduction to work.");
-
-    // This is to prevent the assertion failure for the systems without water
-    int totalSettles = 0;
-    for (unsigned mt = 0; mt < mtop.moltype.size(); mt++)
-    {
-        const int        nral1           = 1 + NRAL(F_SETTLE);
-        InteractionList  interactionList = mtop.moltype.at(mt).ilist[F_SETTLE];
-        std::vector<int> iatoms          = interactionList.iatoms;
-        totalSettles += iatoms.size() / nral1;
-    }
-    if (totalSettles == 0)
-    {
-        return;
-    }
-
-    // TODO This should be lifted to a separate subroutine that gets the values of Oxygen and
-    // Hydrogen masses, checks if they are consistent across the topology and if there is no more
-    // than two values for each mass if the free energy perturbation is enabled. In later case,
-    // masses may need to be updated on a regular basis (i.e. in set(...) method).
-    // TODO Do the checks for FEP
-    real mO = -1.0;
-    real mH = -1.0;
-
-    for (unsigned mt = 0; mt < mtop.moltype.size(); mt++)
-    {
-        const int        nral1           = 1 + NRAL(F_SETTLE);
-        InteractionList  interactionList = mtop.moltype.at(mt).ilist[F_SETTLE];
-        std::vector<int> iatoms          = interactionList.iatoms;
-        for (unsigned i = 0; i < iatoms.size() / nral1; i++)
-        {
-            int3 settler;
-            settler.x  = iatoms[i * nral1 + 1]; // Oxygen index
-            settler.y  = iatoms[i * nral1 + 2]; // First hydrogen index
-            settler.z  = iatoms[i * nral1 + 3]; // Second hydrogen index
-            t_atom ow1 = mtop.moltype.at(mt).atoms.atom[settler.x];
-            t_atom hw2 = mtop.moltype.at(mt).atoms.atom[settler.y];
-            t_atom hw3 = mtop.moltype.at(mt).atoms.atom[settler.z];
-
-            if (mO < 0)
-            {
-                mO = ow1.m;
-            }
-            if (mH < 0)
-            {
-                mH = hw2.m;
-            }
-            GMX_RELEASE_ASSERT(mO == ow1.m,
-                               "Topology has different values for oxygen mass. Should be identical "
-                               "in order to use SETTLE.");
-            GMX_RELEASE_ASSERT(hw2.m == hw3.m && hw2.m == mH,
-                               "Topology has different values for hydrogen mass. Should be "
-                               "identical in order to use SETTLE.");
-        }
-    }
-
-    GMX_RELEASE_ASSERT(mO > 0, "Could not find oxygen mass in the topology. Needed in SETTLE.");
-    GMX_RELEASE_ASSERT(mH > 0, "Could not find hydrogen mass in the topology. Needed in SETTLE.");
-
-    // TODO Very similar to SETTLE initialization on CPU. Should be lifted to a separate method
-    // (one that gets dOH and dHH values and checks them for consistency)
-    int settle_type = -1;
-    for (unsigned mt = 0; mt < mtop.moltype.size(); mt++)
-    {
-        const int       nral1           = 1 + NRAL(F_SETTLE);
-        InteractionList interactionList = mtop.moltype.at(mt).ilist[F_SETTLE];
-        for (int i = 0; i < interactionList.size(); i += nral1)
-        {
-            if (settle_type == -1)
-            {
-                settle_type = interactionList.iatoms[i];
-            }
-            else if (interactionList.iatoms[i] != settle_type)
-            {
-                gmx_fatal(FARGS,
-                          "The [molecules] section of your topology specifies more than one block "
-                          "of\n"
-                          "a [moleculetype] with a [settles] block. Only one such is allowed.\n"
-                          "If you are trying to partition your solvent into different *groups*\n"
-                          "(e.g. for freezing, T-coupling, etc.), you are using the wrong "
-                          "approach. Index\n"
-                          "files specify groups. Otherwise, you may wish to change the least-used\n"
-                          "block of molecules with SETTLE constraints into 3 normal constraints.");
-            }
-        }
-    }
-
-    GMX_RELEASE_ASSERT(settle_type >= 0, "settle_init called without settles");
-
-    real dOH = mtop.ffparams.iparams[settle_type].settle.doh;
-    real dHH = mtop.ffparams.iparams[settle_type].settle.dhh;
-
-    settleParameters_ = settleParameters(mO, mH, 1.0 / mO, 1.0 / mH, dOH, dHH);
-
-    allocateDeviceBuffer(&d_virialScaled_, 6, deviceContext_);
-    h_virialScaled_.resize(6);
-}
-
-SettleGpu::~SettleGpu()
-{
-    // Early exit if there is no settles
-    if (numSettles_ == 0)
-    {
-        return;
-    }
-    freeDeviceBuffer(&d_virialScaled_);
-    if (numAtomIdsAlloc_ > 0)
-    {
-        freeDeviceBuffer(&d_atomIds_);
-    }
-}
-
-void SettleGpu::set(const InteractionDefinitions& idef)
-{
-    const int              nral1     = 1 + NRAL(F_SETTLE);
-    const InteractionList& il_settle = idef.il[F_SETTLE];
-    ArrayRef<const int>    iatoms    = il_settle.iatoms;
-    numSettles_                      = il_settle.size() / nral1;
-
-    reallocateDeviceBuffer(&d_atomIds_, numSettles_, &numAtomIds_, &numAtomIdsAlloc_, deviceContext_);
-    h_atomIds_.resize(numSettles_);
-    for (int i = 0; i < numSettles_; i++)
-    {
-        int3 settler;
-        settler.x        = iatoms[i * nral1 + 1]; // Oxygen index
-        settler.y        = iatoms[i * nral1 + 2]; // First hydrogen index
-        settler.z        = iatoms[i * nral1 + 3]; // Second hydrogen index
-        h_atomIds_.at(i) = settler;
-    }
-    copyToDeviceBuffer(&d_atomIds_, h_atomIds_.data(), 0, numSettles_, deviceStream_,
-                       GpuApiCallBehavior::Sync, nullptr);
-}
-
 } // namespace gmx
diff --git a/src/gromacs/mdlib/settle_gpu_internal.h b/src/gromacs/mdlib/settle_gpu_internal.h
new file mode 100644 (file)
index 0000000..9963944
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 backend-specific functions for GPU implementation of SETTLE.
+ *
+ * \author Artem Zhmurov <zhmurov@gmail.com>
+ *
+ * \ingroup module_mdlib
+ */
+#ifndef GMX_MDLIB_SETTLE_GPU_INTERNAL_H
+#define GMX_MDLIB_SETTLE_GPU_INTERNAL_H
+
+#include "gromacs/gpu_utils/devicebuffer_datatype.h"
+#include "gromacs/gpu_utils/gputraits.h"
+#include "gromacs/mdlib/settle_gpu.h"
+
+namespace gmx
+{
+
+/*! \brief Apply SETTLE.
+ *
+ * Applies SETTLE to coordinates and velocities, stored on GPU. Data at pointers d_xp and
+ * d_v change in the GPU memory. The results are not automatically copied back to the CPU
+ * memory. Method uses this class data structures which should be updated when needed using
+ * update method.
+ *
+ * \param[in]     numSettles        Number of SETTLE constraints.
+ * \param[in]     d_atomIds         Device buffer with indices of atoms to be SETTLEd.
+ * \param[in]     settleParameters  Parameters for SETTLE constraints.
+ * \param[in]     d_x               Coordinates before timestep (in GPU memory)
+ * \param[in,out] d_xp              Coordinates after timestep (in GPU memory). The
+ *                                  resulting constrained coordinates will be saved here.
+ * \param[in]     updateVelocities  If the velocities should be updated.
+ * \param[in,out] d_v               Velocities to update (in GPU memory, can be nullptr
+ *                                  if not updated)
+ * \param[in]     invdt             Reciprocal timestep (to scale Lagrange
+ *                                  multipliers when velocities are updated)
+ * \param[in]     computeVirial     If virial should be updated.
+ * \param[in,out] virialScaled      Scaled virial tensor to be updated.
+ * \param[in]     pbcAiuc           PBC data.
+ * \param[in]     deviceStream      Device stream to launch kernel in.
+ */
+void launchSettleGpuKernel(int                               numSettles,
+                           const DeviceBuffer<WaterMolecule> d_atomIds,
+                           const SettleParameters            settleParameters,
+                           const DeviceBuffer<Float3>        d_x,
+                           DeviceBuffer<Float3>              d_xp,
+                           const bool                        updateVelocities,
+                           DeviceBuffer<Float3>              d_v,
+                           const real                        invdt,
+                           const bool                        computeVirial,
+                           DeviceBuffer<float>               virialScaled,
+                           const PbcAiuc                     pbcAiuc,
+                           const DeviceStream&               deviceStream);
+
+} // namespace gmx
+
+#endif // GMX_MDLIB_SETTLE_GPU_INTERNAL_H
diff --git a/src/gromacs/mdlib/settle_gpu_internal_sycl.cpp b/src/gromacs/mdlib/settle_gpu_internal_sycl.cpp
new file mode 100644 (file)
index 0000000..ef063c3
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 SYCL-specific routines for the GPU implementation of SETTLE constraints algorithm.
+ *
+ * \author Artem Zhmurov <zhmurov@gmail.com>
+ *
+ * \ingroup module_mdlib
+ */
+
+#include "settle_gpu_internal.h"
+
+#include "gromacs/utility/gmxassert.h"
+
+namespace gmx
+{
+
+void launchSettleGpuKernel(const int /* numSettles */,
+                           const DeviceBuffer<WaterMolecule> /* d_atomIds */,
+                           const SettleParameters /* settleParameters */,
+                           const DeviceBuffer<Float3> /* d_x */,
+                           DeviceBuffer<Float3> /* d_xp */,
+                           const bool /* updateVelocities */,
+                           DeviceBuffer<Float3> /* d_v */,
+                           const real /* invdt */,
+                           const bool /* computeVirial */,
+                           DeviceBuffer<float> /* virialScaled */,
+                           const PbcAiuc /* pbcAiuc */,
+                           const DeviceStream& /* deviceStream */)
+{
+    // SYCL_TODO
+    GMX_RELEASE_ASSERT(false, "SETTLE is not yet implemented in SYCL.");
+
+    return;
+}
+
+} // namespace gmx
index ee5dee5f4f82ea38d7e3e045ba3582c2d1bb270e..47ef4167f233eb43f289ade1391e75879411d6d2 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +61,7 @@
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/invblock.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
 
@@ -111,8 +112,13 @@ static void pr_sortblock(FILE* fp, const char* title, int nsb, t_sortblock sb[])
     fprintf(fp, "%s\n", title);
     for (i = 0; (i < nsb); i++)
     {
-        fprintf(fp, "i: %5d, iatom: (%5d %5d %5d), blocknr: %5d\n", i, sb[i].iatom[0],
-                sb[i].iatom[1], sb[i].iatom[2], sb[i].blocknr);
+        fprintf(fp,
+                "i: %5d, iatom: (%5d %5d %5d), blocknr: %5d\n",
+                i,
+                sb[i].iatom[0],
+                sb[i].iatom[1],
+                sb[i].iatom[2],
+                sb[i].blocknr);
     }
 }
 
@@ -277,7 +283,7 @@ void cshake(const int            iatom[],
             ArrayRef<const RVec> initial_displacements,
             ArrayRef<const real> half_of_reduced_mass,
             real                 omega,
-            const real           invmass[],
+            ArrayRef<const real> invmass,
             ArrayRef<const real> distance_squared_tolerance,
             ArrayRef<real>       scaled_lagrange_multiplier,
             int*                 nerror)
@@ -366,7 +372,7 @@ static void crattle(const int            iatom[],
                     ArrayRef<const RVec> rij,
                     ArrayRef<const real> m2,
                     real                 omega,
-                    const real           invmass[],
+                    ArrayRef<const real> invmass,
                     ArrayRef<const real> distance_squared_tolerance,
                     ArrayRef<real>       scaled_lagrange_multiplier,
                     int*                 nerror,
@@ -435,7 +441,7 @@ static void crattle(const int            iatom[],
 //! Applies SHAKE
 static int vec_shakef(FILE*                     fplog,
                       shakedata*                shaked,
-                      const real                invmass[],
+                      ArrayRef<const real>      invmass,
                       int                       ncon,
                       ArrayRef<const t_iparams> ip,
                       const int*                iatom,
@@ -502,14 +508,36 @@ static int vec_shakef(FILE*                     fplog,
     switch (econq)
     {
         case ConstraintVariable::Positions:
-            cshake(iatom, ncon, &nit, maxnit, constraint_distance_squared, prime, pbc, rij,
-                   half_of_reduced_mass, omega, invmass, distance_squared_tolerance,
-                   scaled_lagrange_multiplier, &error);
+            cshake(iatom,
+                   ncon,
+                   &nit,
+                   maxnit,
+                   constraint_distance_squared,
+                   prime,
+                   pbc,
+                   rij,
+                   half_of_reduced_mass,
+                   omega,
+                   invmass,
+                   distance_squared_tolerance,
+                   scaled_lagrange_multiplier,
+                   &error);
             break;
         case ConstraintVariable::Velocities:
-            crattle(iatom, ncon, &nit, maxnit, constraint_distance_squared, prime, rij,
-                    half_of_reduced_mass, omega, invmass, distance_squared_tolerance,
-                    scaled_lagrange_multiplier, &error, invdt);
+            crattle(iatom,
+                    ncon,
+                    &nit,
+                    maxnit,
+                    constraint_distance_squared,
+                    prime,
+                    rij,
+                    half_of_reduced_mass,
+                    omega,
+                    invmass,
+                    distance_squared_tolerance,
+                    scaled_lagrange_multiplier,
+                    &error,
+                    invdt);
             break;
         default: gmx_incons("Unknown constraint quantity for SHAKE");
     }
@@ -530,12 +558,16 @@ static int vec_shakef(FILE*                     fplog,
             fprintf(fplog,
                     "Inner product between old and new vector <= 0.0!\n"
                     "constraint #%d atoms %d and %d\n",
-                    error - 1, iatom[3 * (error - 1) + 1] + 1, iatom[3 * (error - 1) + 2] + 1);
+                    error - 1,
+                    iatom[3 * (error - 1) + 1] + 1,
+                    iatom[3 * (error - 1) + 2] + 1);
         }
         fprintf(stderr,
                 "Inner product between old and new vector <= 0.0!\n"
                 "constraint #%d atoms %d and %d\n",
-                error - 1, iatom[3 * (error - 1) + 1] + 1, iatom[3 * (error - 1) + 2] + 1);
+                error - 1,
+                iatom[3 * (error - 1) + 1] + 1,
+                iatom[3 * (error - 1) + 2] + 1);
         nit = 0;
     }
 
@@ -605,7 +637,7 @@ static void check_cons(FILE*                     log,
                        const t_pbc*              pbc,
                        ArrayRef<const t_iparams> ip,
                        const int*                iatom,
-                       const real                invmass[],
+                       ArrayRef<const real>      invmass,
                        ConstraintVariable        econq)
 {
     int  ai, aj;
@@ -635,16 +667,30 @@ static void check_cons(FILE*                     log,
                     rvec_sub(prime[ai], prime[aj], dx);
                 }
                 dp = norm(dx);
-                fprintf(log, "%5d  %5.2f  %5d  %5.2f  %10.5f  %10.5f  %10.5f\n", ai + 1,
-                        1.0 / invmass[ai], aj + 1, 1.0 / invmass[aj], d, dp, ip[ia[0]].constr.dA);
+                fprintf(log,
+                        "%5d  %5.2f  %5d  %5.2f  %10.5f  %10.5f  %10.5f\n",
+                        ai + 1,
+                        1.0 / invmass[ai],
+                        aj + 1,
+                        1.0 / invmass[aj],
+                        d,
+                        dp,
+                        ip[ia[0]].constr.dA);
                 break;
             case ConstraintVariable::Velocities:
                 rvec_sub(v[ai], v[aj], dv);
                 d = iprod(dx, dv);
                 rvec_sub(prime[ai], prime[aj], dv);
                 dp = iprod(dx, dv);
-                fprintf(log, "%5d  %5.2f  %5d  %5.2f  %10.5f  %10.5f  %10.5f\n", ai + 1,
-                        1.0 / invmass[ai], aj + 1, 1.0 / invmass[aj], d, dp, 0.);
+                fprintf(log,
+                        "%5d  %5.2f  %5d  %5.2f  %10.5f  %10.5f  %10.5f\n",
+                        ai + 1,
+                        1.0 / invmass[ai],
+                        aj + 1,
+                        1.0 / invmass[aj],
+                        d,
+                        dp,
+                        0.);
                 break;
             default: gmx_incons("Unknown constraint quantity for SHAKE");
         }
@@ -654,7 +700,7 @@ static void check_cons(FILE*                     log,
 //! Applies SHAKE.
 static bool bshakef(FILE*                         log,
                     shakedata*                    shaked,
-                    const real                    invmass[],
+                    ArrayRef<const real>          invmass,
                     const InteractionDefinitions& idef,
                     const t_inputrec&             ir,
                     ArrayRef<const RVec>          x_s,
@@ -690,9 +736,25 @@ static bool bshakef(FILE*                         log,
     {
         blen = (shaked->sblock[i + 1] - shaked->sblock[i]);
         blen /= 3;
-        n0 = vec_shakef(log, shaked, invmass, blen, idef.iparams, iatoms, ir.shake_tol, x_s, prime,
-                        pbc, shaked->omega, ir.efep != efepNO, lambda, lam, invdt, v, bCalcVir,
-                        vir_r_m_dr, econq);
+        n0 = vec_shakef(log,
+                        shaked,
+                        invmass,
+                        blen,
+                        idef.iparams,
+                        iatoms,
+                        ir.shake_tol,
+                        x_s,
+                        prime,
+                        pbc,
+                        shaked->omega,
+                        ir.efep != FreeEnergyPerturbationType::No,
+                        lambda,
+                        lam,
+                        invdt,
+                        v,
+                        bCalcVir,
+                        vir_r_m_dr,
+                        econq);
 
         if (n0 == 0)
         {
@@ -713,7 +775,7 @@ static bool bshakef(FILE*                         log,
     /* only for position part? */
     if (econq == ConstraintVariable::Positions)
     {
-        if (ir.efep != efepNO)
+        if (ir.efep != FreeEnergyPerturbationType::No)
         {
             ArrayRef<const t_iparams> iparams = idef.iparams;
 
@@ -760,7 +822,7 @@ static bool bshakef(FILE*                         log,
 
 bool constrain_shake(FILE*                         log,
                      shakedata*                    shaked,
-                     const real                    invmass[],
+                     ArrayRef<const real>          invmass,
                      const InteractionDefinitions& idef,
                      const t_inputrec&             ir,
                      ArrayRef<const RVec>          x_s,
@@ -785,12 +847,27 @@ bool constrain_shake(FILE*                         log,
     switch (econq)
     {
         case (ConstraintVariable::Positions):
-            bOK = bshakef(log, shaked, invmass, idef, ir, x_s, xprime, pbc, nrnb, lambda, dvdlambda,
-                          invdt, v, bCalcVir, vir_r_m_dr, bDumpOnError, econq);
+            bOK = bshakef(
+                    log, shaked, invmass, idef, ir, x_s, xprime, pbc, nrnb, lambda, dvdlambda, invdt, v, bCalcVir, vir_r_m_dr, bDumpOnError, econq);
             break;
         case (ConstraintVariable::Velocities):
-            bOK = bshakef(log, shaked, invmass, idef, ir, x_s, vprime, pbc, nrnb, lambda, dvdlambda,
-                          invdt, {}, bCalcVir, vir_r_m_dr, bDumpOnError, econq);
+            bOK = bshakef(log,
+                          shaked,
+                          invmass,
+                          idef,
+                          ir,
+                          x_s,
+                          vprime,
+                          pbc,
+                          nrnb,
+                          lambda,
+                          dvdlambda,
+                          invdt,
+                          {},
+                          bCalcVir,
+                          vir_r_m_dr,
+                          bDumpOnError,
+                          econq);
             break;
         default:
             gmx_fatal(FARGS,
index 8559c57553855291095dedf5eadb2247512dc50c..f0723818bc7c899236e15558d90cd1c0ebdd8fa4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,17 +108,17 @@ void make_shake_sblock_dd(shakedata* shaked, const InteractionList& ilcon);
  * sblock[n] to sblock[n+1]. Array sblock should be large enough.
  * Return TRUE when OK, FALSE when shake-error
  */
-bool constrain_shake(FILE*                         log,       /* Log file                      */
-                     shakedata*                    shaked,    /* Total number of atoms */
-                     const real                    invmass[], /* Atomic masses         */
-                     const InteractionDefinitions& idef,      /* The interaction def           */
-                     const t_inputrec&             ir,        /* Input record                  */
-                     ArrayRef<const RVec>          x_s,       /* Coords before update          */
-                     ArrayRef<RVec>                xprime, /* Output coords when constraining x */
-                     ArrayRef<RVec>                vprime, /* Output coords when constraining v */
-                     const t_pbc*                  pbc,    /* PBC information              */
-                     t_nrnb*                       nrnb,   /* Performance measure          */
-                     real                          lambda, /* FEP lambda                   */
+bool constrain_shake(FILE*                         log,     /* Log file                        */
+                     shakedata*                    shaked,  /* Total number of atoms   */
+                     gmx::ArrayRef<const real>     invmass, /* Atomic masses           */
+                     const InteractionDefinitions& idef,    /* The interaction def             */
+                     const t_inputrec&             ir,      /* Input record                    */
+                     ArrayRef<const RVec>          x_s,     /* Coords before update            */
+                     ArrayRef<RVec>                xprime,  /* Output coords when constraining x */
+                     ArrayRef<RVec>                vprime,  /* Output coords when constraining v */
+                     const t_pbc*                  pbc,     /* PBC information              */
+                     t_nrnb*                       nrnb,    /* Performance measure          */
+                     real                          lambda,  /* FEP lambda                   */
                      real*                         dvdlambda,  /* FEP force                    */
                      real                          invdt,      /* 1/delta_t                    */
                      ArrayRef<RVec>                v,          /* Also constrain v if not empty  */
@@ -138,7 +138,7 @@ void cshake(const int            iatom[],
             ArrayRef<const RVec> rij,
             ArrayRef<const real> half_of_reduced_mass,
             real                 omega,
-            const real           invmass[],
+            ArrayRef<const real> invmass,
             ArrayRef<const real> distance_squared_tolerance,
             ArrayRef<real>       scaled_lagrange_multiplier,
             int*                 nerror);
index 392afa9fada7a1a18f94ce57d723ee29b4f7235b..cb7ba47acfcc1e4aff6fa8bcb5252d1fc1bdece5 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <csignal>
 #include <cstdlib>
 
+#include "gromacs/utility/enumerationhelpers.h"
+#include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 
-const char* gmx_stop_cond_name[] = { "None", "Stop at the next neighbor search step",
-                                     "Stop at the next step", "Abort" };
+const char* enumValueToString(StopCondition enumValue)
+{
+    constexpr gmx::EnumerationArray<StopCondition, const char*> stopConditionNames = {
+        "None", "Stop at the next neighbor search step", "Stop at the next step", "Abort"
+    };
+    return stopConditionNames[enumValue];
+}
 
 /* these do not neccesarily match the stop condition, but are
    referred to in the signal handler. */
-static const char* gmx_signal_name[] = {
+static const char* const gmx_signal_name[] = {
     "None", "INT",  "TERM", "second INT/TERM", "remote INT/TERM", "remote second INT/TERM",
     "USR1", "Abort"
 };
 
-static volatile sig_atomic_t stop_condition   = gmx_stop_cond_none;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static volatile StopCondition stop_condition = StopCondition::None;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static volatile sig_atomic_t last_signal_name = 0;
-
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static volatile sig_atomic_t usr_condition = 0;
 
 void gmx_reset_stop_condition()
 {
-    stop_condition = gmx_stop_cond_none;
+    stop_condition = StopCondition::None;
     // last_signal_name and usr_condition are left untouched by reset.
 }
 
@@ -77,7 +86,13 @@ static void signal_handler(int n)
         case SIGTERM:
         case SIGINT:
             /* we explicitly set things up to allow this: */
-            stop_condition++;
+            switch (stop_condition)
+            {
+                case StopCondition::None: stop_condition = StopCondition::NextNS; break;
+                case StopCondition::NextNS: stop_condition = StopCondition::Next; break;
+                case StopCondition::Next: stop_condition = StopCondition::Abort; break;
+                default: GMX_THROW(gmx::InternalError("Stop condition increased beyond abort"));
+            }
             if (n == SIGINT)
             {
                 last_signal_name = 1;
@@ -86,11 +101,11 @@ static void signal_handler(int n)
             {
                 last_signal_name = 2;
             }
-            if (stop_condition == gmx_stop_cond_next)
+            if (stop_condition == StopCondition::Next)
             {
                 last_signal_name = 3;
             }
-            if (stop_condition >= gmx_stop_cond_abort)
+            if (stop_condition >= StopCondition::Abort)
             {
                 abort();
             }
@@ -145,21 +160,21 @@ void signal_handler_install()
 #endif
 }
 
-gmx_stop_cond_t gmx_get_stop_condition()
+StopCondition gmx_get_stop_condition()
 {
-    return static_cast<gmx_stop_cond_t>(stop_condition);
+    return stop_condition;
 }
 
-void gmx_set_stop_condition(gmx_stop_cond_t recvd_stop_cond)
+void gmx_set_stop_condition(StopCondition recvd_stop_cond)
 {
     if (recvd_stop_cond > stop_condition)
     {
         stop_condition = recvd_stop_cond;
-        if (stop_condition == gmx_stop_cond_next_ns)
+        if (stop_condition == StopCondition::NextNS)
         {
             last_signal_name = 4;
         }
-        if (stop_condition == gmx_stop_cond_next)
+        if (stop_condition == StopCondition::Next)
         {
             last_signal_name = 5;
         }
index 35e831203756fe270e50fa2178eab5b6ab08bc11..1f56378958e1eae861c78febfc8ed58d04c5c36c 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,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -39,6 +39,8 @@
 
 #include "gromacs/utility/basedefinitions.h"
 
+#include <csignal>
+
 /* NOTE: the terminology is:
    incoming signals (provided by the operating system, or transmitted from
    other nodes) lead to stop conditions. These stop conditions should be
 
 /* the stop conditions. They are explicitly allowed to be compared against
    each other. */
-typedef enum
+enum class StopCondition : sig_atomic_t
 {
-    gmx_stop_cond_none = 0,
-    gmx_stop_cond_next_ns, /* stop a the next neighbour searching step */
-    gmx_stop_cond_next,    /* stop a the next step */
-    gmx_stop_cond_abort    /* stop now. (this should never be seen) */
-} gmx_stop_cond_t;
+    None = 0,
+    NextNS, /* stop a the next neighbour searching step */
+    Next,   /* stop a the next step */
+    Abort,  /* stop now. (this should never be seen) */
+    Count
+};
 
 /* Our names for the stop conditions.
    These must match the number given in gmx_stop_cond_t.*/
-extern const char* gmx_stop_cond_name[];
+const char* enumValueToString(StopCondition enumValue);
 
 /* the externally visible functions: */
 
@@ -64,10 +67,10 @@ extern const char* gmx_stop_cond_name[];
 void signal_handler_install();
 
 /* get the current stop condition */
-gmx_stop_cond_t gmx_get_stop_condition();
+StopCondition gmx_get_stop_condition();
 
 /* set the stop condition upon receiving a remote one */
-void gmx_set_stop_condition(gmx_stop_cond_t recvd_stop_cond);
+void gmx_set_stop_condition(StopCondition recvd_stop_cond);
 
 /*!
  * \brief Reinitializes the global stop condition.
index a235dbc1d5207b02934db78f20387cce761b3d48..2f82ddc6d347f618b519630d6ca72236cbe5596c 100644 (file)
@@ -58,8 +58,8 @@
 #include "gromacs/ewald/pme_pp_comm_gpu.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nonbonded/nb_free_energy.h"
-#include "gromacs/gmxlib/nonbonded/nb_kernel.h"
 #include "gromacs/gmxlib/nonbonded/nonbonded.h"
+#include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/gpu_utils/gpu_utils.h"
 #include "gromacs/imd/imd.h"
 #include "gromacs/listed_forces/disre.h"
@@ -146,7 +146,7 @@ static void sum_forces(ArrayRef<RVec> f, ArrayRef<const RVec> forceToAdd)
     GMX_ASSERT(f.size() >= forceToAdd.size(), "Accumulation buffer should be sufficiently large");
     const int end = forceToAdd.size();
 
-    int gmx_unused nt = gmx_omp_nthreads_get(emntDefault);
+    int gmx_unused nt = gmx_omp_nthreads_get(ModuleMultiThread::Default);
 #pragma omp parallel for num_threads(nt) schedule(static)
     for (int i = 0; i < end; i++)
     {
@@ -165,9 +165,10 @@ static void calc_virial(int                              start,
                         PbcType                          pbcType)
 {
     /* The short-range virial from surrounding boxes */
-    const rvec* fshift = as_rvec_array(forceWithShiftForces.shiftForces().data());
-    calc_vir(SHIFTS, fr->shift_vec, fshift, vir_part, pbcType == PbcType::Screw, box);
-    inc_nrnb(nrnb, eNR_VIRIAL, SHIFTS);
+    const rvec* fshift          = as_rvec_array(forceWithShiftForces.shiftForces().data());
+    const rvec* shiftVecPointer = as_rvec_array(fr->shift_vec.data());
+    calc_vir(gmx::c_numShiftVectors, shiftVecPointer, fshift, vir_part, pbcType == PbcType::Screw, box);
+    inc_nrnb(nrnb, eNR_VIRIAL, gmx::c_numShiftVectors);
 
     /* Calculate partial virial, for local atoms only, based on short range.
      * Total virial is computed in global_stat, called from do_md
@@ -183,7 +184,7 @@ static void calc_virial(int                              start,
 }
 
 static void pull_potential_wrapper(const t_commrec*               cr,
-                                   const t_inputrec*              ir,
+                                   const t_inputrec&              ir,
                                    const matrix                   box,
                                    gmx::ArrayRef<const gmx::RVec> x,
                                    gmx::ForceWithVirial*          force,
@@ -192,7 +193,7 @@ static void pull_potential_wrapper(const t_commrec*               cr,
                                    pull_t*                        pull_work,
                                    const real*                    lambda,
                                    double                         t,
-                                   gmx_wallcycle_t                wcycle)
+                                   gmx_wallcycle                wcycle)
 {
     t_pbc pbc;
     real  dvdl;
@@ -200,14 +201,21 @@ static void pull_potential_wrapper(const t_commrec*               cr,
     /* Calculate the center of mass forces, this requires communication,
      * which is why pull_potential is called close to other communication.
      */
-    wallcycle_start(wcycle, ewcPULLPOT);
-    set_pbc(&pbc, ir->pbcType, box);
+    wallcycle_start(wcycle, WallCycleCounter::PullPot);
+    set_pbc(&pbc, ir.pbcType, box);
     dvdl = 0;
     enerd->term[F_COM_PULL] +=
-            pull_potential(pull_work, mdatoms->massT, &pbc, cr, t, lambda[efptRESTRAINT],
-                           as_rvec_array(x.data()), force, &dvdl);
-    enerd->dvdl_lin[efptRESTRAINT] += dvdl;
-    wallcycle_stop(wcycle, ewcPULLPOT);
+            pull_potential(pull_work,
+                           gmx::arrayRefFromArray(mdatoms->massT, mdatoms->nr),
+                           &pbc,
+                           cr,
+                           t,
+                           lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Restraint)],
+                           x,
+                           force,
+                           &dvdl);
+    enerd->dvdl_lin[FreeEnergyPerturbationCouplingType::Restraint] += dvdl;
+    wallcycle_stop(wcycle, WallCycleCounter::PullPot);
 }
 
 static void pme_receive_force_ener(t_forcerec*           fr,
@@ -216,32 +224,40 @@ static void pme_receive_force_ener(t_forcerec*           fr,
                                    gmx_enerdata_t*       enerd,
                                    bool                  useGpuPmePpComms,
                                    bool                  receivePmeForceToGpu,
-                                   gmx_wallcycle_t       wcycle)
+                                   gmx_wallcycle       wcycle)
 {
     real  e_q, e_lj, dvdl_q, dvdl_lj;
     float cycles_ppdpme, cycles_seppme;
 
-    cycles_ppdpme = wallcycle_stop(wcycle, ewcPPDURINGPME);
+    cycles_ppdpme = wallcycle_stop(wcycle, WallCycleCounter::PpDuringPme);
     dd_cycles_add(cr->dd, cycles_ppdpme, ddCyclPPduringPME);
 
     /* In case of node-splitting, the PP nodes receive the long-range
      * forces, virial and energy from the PME nodes here.
      */
-    wallcycle_start(wcycle, ewcPP_PMEWAITRECVF);
+    wallcycle_start(wcycle, WallCycleCounter::PpPmeWaitRecvF);
     dvdl_q  = 0;
     dvdl_lj = 0;
-    gmx_pme_receive_f(fr->pmePpCommGpu.get(), cr, forceWithVirial, &e_q, &e_lj, &dvdl_q, &dvdl_lj,
-                      useGpuPmePpComms, receivePmeForceToGpu, &cycles_seppme);
+    gmx_pme_receive_f(fr->pmePpCommGpu.get(),
+                      cr,
+                      forceWithVirial,
+                      &e_q,
+                      &e_lj,
+                      &dvdl_q,
+                      &dvdl_lj,
+                      useGpuPmePpComms,
+                      receivePmeForceToGpu,
+                      &cycles_seppme);
     enerd->term[F_COUL_RECIP] += e_q;
     enerd->term[F_LJ_RECIP] += e_lj;
-    enerd->dvdl_lin[efptCOUL] += dvdl_q;
-    enerd->dvdl_lin[efptVDW] += dvdl_lj;
+    enerd->dvdl_lin[FreeEnergyPerturbationCouplingType::Coul] += dvdl_q;
+    enerd->dvdl_lin[FreeEnergyPerturbationCouplingType::Vdw] += dvdl_lj;
 
     if (wcycle)
     {
         dd_cycles_add(cr->dd, cycles_seppme, ddCyclPME);
     }
-    wallcycle_stop(wcycle, ewcPP_PMEWAITRECVF);
+    wallcycle_stop(wcycle, WallCycleCounter::PpPmeWaitRecvF);
 }
 
 static void print_large_forces(FILE*                fp,
@@ -260,8 +276,14 @@ static void print_large_forces(FILE*                fp,
         bool nonFinite = !std::isfinite(force2);
         if (force2 >= force2Tolerance || nonFinite)
         {
-            fprintf(fp, "step %" 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));
+            fprintf(fp,
+                    "step %" 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)
         {
@@ -280,7 +302,7 @@ static void print_large_forces(FILE*                fp,
 
 //! When necessary, spreads forces on vsites and computes the virial for \p forceOutputs->forceWithShiftForces()
 static void postProcessForceWithShiftForces(t_nrnb*                   nrnb,
-                                            gmx_wallcycle_t           wcycle,
+                                            gmx_wallcycle           wcycle,
                                             const matrix              box,
                                             ArrayRef<const RVec>      x,
                                             ForceOutputs*             forceOutputs,
@@ -311,8 +333,8 @@ static void postProcessForceWithShiftForces(t_nrnb*                   nrnb,
     if (stepWork.computeVirial)
     {
         /* Calculation of the virial must be done after vsites! */
-        calc_virial(0, mdatoms.homenr, as_rvec_array(x.data()), forceWithShiftForces, vir_force,
-                    box, nrnb, &fr, fr.pbcType);
+        calc_virial(
+                0, mdatoms.homenr, as_rvec_array(x.data()), forceWithShiftForces, vir_force, box, nrnb, &fr, fr.pbcType);
     }
 }
 
@@ -320,7 +342,7 @@ static void postProcessForceWithShiftForces(t_nrnb*                   nrnb,
 static void postProcessForces(const t_commrec*          cr,
                               int64_t                   step,
                               t_nrnb*                   nrnb,
-                              gmx_wallcycle_t           wcycle,
+                              gmx_wallcycle           wcycle,
                               const matrix              box,
                               ArrayRef<const RVec>      x,
                               ForceOutputs*             forceOutputs,
@@ -395,7 +417,7 @@ static void do_nb_verlet(t_forcerec*                fr,
                          const int                  clearF,
                          const int64_t              step,
                          t_nrnb*                    nrnb,
-                         gmx_wallcycle_t            wcycle)
+                         gmx_wallcycle            wcycle)
 {
     if (!stepWork.computeNonbondedForces)
     {
@@ -416,18 +438,27 @@ static void do_nb_verlet(t_forcerec*                fr,
             /* Prune the pair-list beyond fr->ic->rlistPrune using
              * the current coordinates of the atoms.
              */
-            wallcycle_sub_start(wcycle, ewcsNONBONDED_PRUNING);
+            wallcycle_sub_start(wcycle, WallCycleSubCounter::NonbondedPruning);
             nbv->dispatchPruneKernelCpu(ilocality, fr->shift_vec);
-            wallcycle_sub_stop(wcycle, ewcsNONBONDED_PRUNING);
+            wallcycle_sub_stop(wcycle, WallCycleSubCounter::NonbondedPruning);
         }
     }
 
-    nbv->dispatchNonbondedKernel(ilocality, *ic, stepWork, clearF, *fr, enerd, nrnb);
+    nbv->dispatchNonbondedKernel(
+            ilocality,
+            *ic,
+            stepWork,
+            clearF,
+            fr->shift_vec,
+            enerd->grpp.energyGroupPairTerms[fr->haveBuckingham ? NonBondedEnergyTerms::BuckinghamSR
+                                                                : NonBondedEnergyTerms::LJSR],
+            enerd->grpp.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR],
+            nrnb);
 }
 
 static inline void clearRVecs(ArrayRef<RVec> v, const bool useOpenmpThreading)
 {
-    int nth = gmx_omp_nthreads_get_simple_rvec_task(emntDefault, v.ssize());
+    int nth = gmx_omp_nthreads_get_simple_rvec_task(ModuleMultiThread::Default, v.ssize());
 
     /* Note that we would like to avoid this conditional by putting it
      * into the omp pragma instead, but then we still take the full
@@ -464,7 +495,7 @@ static real averageKineticEnergyEstimate(const t_grpopts& groupOptions)
         if (groupOptions.tau_t[g] >= 0)
         {
             nrdfCoupled += groupOptions.nrdf[g];
-            kineticEnergy += groupOptions.nrdf[g] * 0.5 * groupOptions.ref_t[g] * BOLTZ;
+            kineticEnergy += groupOptions.nrdf[g] * 0.5 * groupOptions.ref_t[g] * gmx::c_boltz;
         }
         else
         {
@@ -530,9 +561,13 @@ static void checkPotentialEnergyValidity(int64_t step, const gmx_enerdata_t& ene
                 "can be caused by overlapping interactions in bonded interactions or very large%s "
                 "coordinate values. Usually this is caused by a badly- or non-equilibrated initial "
                 "configuration, incorrect interactions or parameters in the topology.",
-                step, enerd.term[F_EPOT], energyIsNotFinite ? "not finite" : "extremely high",
-                enerd.term[F_LJ], enerd.term[F_COUL_SR],
-                energyIsNotFinite ? "non-finite" : "very high", energyIsNotFinite ? " or Nan" : "");
+                step,
+                enerd.term[F_EPOT],
+                energyIsNotFinite ? "not finite" : "extremely high",
+                enerd.term[F_LJ],
+                enerd.term[F_COUL_SR],
+                energyIsNotFinite ? "non-finite" : "very high",
+                energyIsNotFinite ? " or Nan" : "");
     }
 }
 
@@ -591,14 +626,14 @@ static bool haveSpecialForces(const t_inputrec&          inputrec,
  */
 static void computeSpecialForces(FILE*                          fplog,
                                  const t_commrec*               cr,
-                                 const t_inputrec*              inputrec,
+                                 const t_inputrec&              inputrec,
                                  gmx::Awh*                      awh,
                                  gmx_enfrot*                    enforcedRotation,
                                  gmx::ImdSession*               imdSession,
                                  pull_t*                        pull_work,
                                  int64_t                        step,
                                  double                         t,
-                                 gmx_wallcycle_t                wcycle,
+                                 gmx_wallcycle                wcycle,
                                  gmx::ForceProviders*           forceProviders,
                                  const matrix                   box,
                                  gmx::ArrayRef<const gmx::RVec> x,
@@ -616,52 +651,65 @@ static void computeSpecialForces(FILE*                          fplog,
      */
     if (stepWork.computeForces)
     {
-        gmx::ForceProviderInput  forceProviderInput(x, *mdatoms, t, box, *cr);
+        gmx::ForceProviderInput forceProviderInput(
+                x,
+                mdatoms->homenr,
+                gmx::arrayRefFromArray(mdatoms->chargeA, mdatoms->homenr),
+                gmx::arrayRefFromArray(mdatoms->massT, mdatoms->homenr),
+                t,
+                box,
+                *cr);
         gmx::ForceProviderOutput forceProviderOutput(forceWithVirialMtsLevel0, enerd);
 
         /* Collect forces from modules */
         forceProviders->calculateForces(forceProviderInput, &forceProviderOutput);
     }
 
-    if (inputrec->bPull && pull_have_potential(*pull_work))
+    if (inputrec.bPull && pull_have_potential(*pull_work))
     {
-        const int mtsLevel = forceGroupMtsLevel(inputrec->mtsLevels, gmx::MtsForceGroups::Pull);
+        const int mtsLevel = forceGroupMtsLevel(inputrec.mtsLevels, gmx::MtsForceGroups::Pull);
         if (mtsLevel == 0 || stepWork.computeSlowForces)
         {
             auto& forceWithVirial = (mtsLevel == 0) ? forceWithVirialMtsLevel0 : forceWithVirialMtsLevel1;
-            pull_potential_wrapper(cr, inputrec, box, x, forceWithVirial, mdatoms, enerd, pull_work,
-                                   lambda.data(), t, wcycle);
+            pull_potential_wrapper(
+                    cr, inputrec, box, x, forceWithVirial, mdatoms, enerd, pull_work, lambda.data(), t, wcycle);
         }
     }
     if (awh)
     {
-        const int mtsLevel = forceGroupMtsLevel(inputrec->mtsLevels, gmx::MtsForceGroups::Pull);
+        const int mtsLevel = forceGroupMtsLevel(inputrec.mtsLevels, gmx::MtsForceGroups::Pull);
         if (mtsLevel == 0 || stepWork.computeSlowForces)
         {
             const bool needForeignEnergyDifferences = awh->needForeignEnergyDifferences(step);
             std::vector<double> foreignLambdaDeltaH, foreignLambdaDhDl;
             if (needForeignEnergyDifferences)
             {
-                enerd->foreignLambdaTerms.finalizePotentialContributions(enerd->dvdl_lin, lambda,
-                                                                         *inputrec->fepvals);
+                enerd->foreignLambdaTerms.finalizePotentialContributions(
+                        enerd->dvdl_lin, lambda, *inputrec.fepvals);
                 std::tie(foreignLambdaDeltaH, foreignLambdaDhDl) = enerd->foreignLambdaTerms.getTerms(cr);
             }
 
             auto& forceWithVirial = (mtsLevel == 0) ? forceWithVirialMtsLevel0 : forceWithVirialMtsLevel1;
             enerd->term[F_COM_PULL] += awh->applyBiasForcesAndUpdateBias(
-                    inputrec->pbcType, mdatoms->massT, foreignLambdaDeltaH, foreignLambdaDhDl, box,
-                    forceWithVirial, t, step, wcycle, fplog);
+                    inputrec.pbcType,
+                    gmx::arrayRefFromArray(mdatoms->massT, mdatoms->nr),
+                    foreignLambdaDeltaH,
+                    foreignLambdaDhDl,
+                    box,
+                    forceWithVirial,
+                    t,
+                    step,
+                    wcycle,
+                    fplog);
         }
     }
-
-    rvec* f = as_rvec_array(forceWithVirialMtsLevel0->force_.data());
-
     /* Add the forces from enforced rotation potentials (if any) */
-    if (inputrec->bRot)
+    if (inputrec.bRot)
     {
-        wallcycle_start(wcycle, ewcROTadd);
-        enerd->term[F_COM_PULL] += add_rot_forces(enforcedRotation, f, cr, step, t);
-        wallcycle_stop(wcycle, ewcROTadd);
+        wallcycle_start(wcycle, WallCycleCounter::RotAdd);
+        enerd->term[F_COM_PULL] +=
+                add_rot_forces(enforcedRotation, forceWithVirialMtsLevel0->force_, cr, step, t);
+        wallcycle_stop(wcycle, WallCycleCounter::RotAdd);
     }
 
     if (ed)
@@ -671,13 +719,13 @@ static void computeSpecialForces(FILE*                          fplog,
          * Thus if no other algorithm (e.g. PME) requires it, the forces
          * here will contribute to the virial.
          */
-        do_flood(cr, inputrec, as_rvec_array(x.data()), f, ed, box, step, didNeighborSearch);
+        do_flood(cr, inputrec, x, forceWithVirialMtsLevel0->force_, ed, box, step, didNeighborSearch);
     }
 
     /* Add forces from interactive molecular dynamics (IMD), if any */
-    if (inputrec->bIMD && stepWork.computeForces)
+    if (inputrec.bIMD && stepWork.computeForces)
     {
-        imdSession->applyForces(f);
+        imdSession->applyForces(forceWithVirialMtsLevel0->force_);
     }
 }
 
@@ -695,7 +743,7 @@ static inline void launchPmeGpuSpread(gmx_pme_t*            pmedata,
                                       const StepWorkload&   stepWork,
                                       GpuEventSynchronizer* xReadyOnDevice,
                                       const real            lambdaQ,
-                                      gmx_wallcycle_t       wcycle)
+                                      gmx_wallcycle       wcycle)
 {
     pme_gpu_prepare_computation(pmedata, box, wcycle, stepWork);
     pme_gpu_launch_spread(pmedata, xReadyOnDevice, wcycle, lambdaQ);
@@ -712,7 +760,7 @@ static inline void launchPmeGpuSpread(gmx_pme_t*            pmedata,
  */
 static void launchPmeGpuFftAndGather(gmx_pme_t*               pmedata,
                                      const real               lambdaQ,
-                                     gmx_wallcycle_t          wcycle,
+                                     gmx_wallcycle          wcycle,
                                      const gmx::StepWorkload& stepWork)
 {
     pme_gpu_launch_complex_transforms(pmedata, wcycle, stepWork);
@@ -744,7 +792,7 @@ static void alternatePmeNbGpuWaitReduce(nonbonded_verlet_t* nbv,
                                         gmx_enerdata_t*     enerd,
                                         const real          lambdaQ,
                                         const StepWorkload& stepWork,
-                                        gmx_wallcycle_t     wcycle)
+                                        gmx_wallcycle     wcycle)
 {
     bool isPmeGpuDone = false;
     bool isNbGpuDone  = false;
@@ -757,9 +805,8 @@ static void alternatePmeNbGpuWaitReduce(nonbonded_verlet_t* nbv,
         {
             GpuTaskCompletion completionType =
                     (isNbGpuDone) ? GpuTaskCompletion::Wait : GpuTaskCompletion::Check;
-            isPmeGpuDone = pme_gpu_try_finish_task(pmedata, stepWork, wcycle,
-                                                   &forceOutputsPme->forceWithVirial(), enerd,
-                                                   lambdaQ, completionType);
+            isPmeGpuDone = pme_gpu_try_finish_task(
+                    pmedata, stepWork, wcycle, &forceOutputsPme->forceWithVirial(), enerd, lambdaQ, completionType);
         }
 
         if (!isNbGpuDone)
@@ -768,9 +815,14 @@ static void alternatePmeNbGpuWaitReduce(nonbonded_verlet_t* nbv,
             GpuTaskCompletion completionType =
                     (isPmeGpuDone) ? GpuTaskCompletion::Wait : GpuTaskCompletion::Check;
             isNbGpuDone = Nbnxm::gpu_try_finish_task(
-                    nbv->gpu_nbv, stepWork, AtomLocality::Local, enerd->grpp.ener[egLJSR].data(),
-                    enerd->grpp.ener[egCOULSR].data(), forceBuffersNonbonded.shiftForces(),
-                    completionType, wcycle);
+                    nbv->gpu_nbv,
+                    stepWork,
+                    AtomLocality::Local,
+                    enerd->grpp.energyGroupPairTerms[NonBondedEnergyTerms::LJSR].data(),
+                    enerd->grpp.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR].data(),
+                    forceBuffersNonbonded.shiftForces(),
+                    completionType,
+                    wcycle);
 
             if (isNbGpuDone)
             {
@@ -782,25 +834,31 @@ static void alternatePmeNbGpuWaitReduce(nonbonded_verlet_t* nbv,
 
 /*! \brief Set up the different force buffers; also does clearing.
  *
- * \param[in] forceHelperBuffers  Helper force buffers
- * \param[in] force     force array
- * \param[in] stepWork  Step schedule flags
- * \param[out] wcycle   wallcycle recording structure
+ * \param[in] forceHelperBuffers        Helper force buffers
+ * \param[in] force                     force array
+ * \param[in] domainWork                Domain lifetime workload flags
+ * \param[in] stepWork                  Step schedule flags
+ * \param[in] havePpDomainDecomposition Whether we have a PP domain decomposition
+ * \param[out] wcycle                   wallcycle recording structure
  *
- * \returns             Cleared force output structure
+ * \returns                             Cleared force output structure
  */
 static ForceOutputs setupForceOutputs(ForceHelperBuffers*                 forceHelperBuffers,
                                       gmx::ArrayRefWithPadding<gmx::RVec> force,
+                                      const DomainLifetimeWorkload&       domainWork,
                                       const StepWorkload&                 stepWork,
-                                      gmx_wallcycle_t                     wcycle)
+                                      const bool                          havePpDomainDecomposition,
+                                      gmx_wallcycle*                      wcycle)
 {
-    wallcycle_sub_start(wcycle, ewcsCLEAR_FORCE_BUFFER);
+    wallcycle_sub_start(wcycle, WallCycleSubCounter::ClearForceBuffer);
 
     /* NOTE: We assume fr->shiftForces is all zeros here */
-    gmx::ForceWithShiftForces forceWithShiftForces(force, stepWork.computeVirial,
-                                                   forceHelperBuffers->shiftForces());
+    gmx::ForceWithShiftForces forceWithShiftForces(
+            force, stepWork.computeVirial, forceHelperBuffers->shiftForces());
 
-    if (stepWork.computeForces)
+    if (stepWork.computeForces
+        && (domainWork.haveCpuLocalForceWork || !stepWork.useGpuFBufferOps
+            || (havePpDomainDecomposition && !stepWork.useGpuFHalo)))
     {
         /* Clear the short- and long-range forces */
         clearRVecs(forceWithShiftForces.force(), true);
@@ -833,10 +891,10 @@ static ForceOutputs setupForceOutputs(ForceHelperBuffers*                 forceH
         clearRVecs(forceWithVirial.force_, true);
     }
 
-    wallcycle_sub_stop(wcycle, ewcsCLEAR_FORCE_BUFFER);
+    wallcycle_sub_stop(wcycle, WallCycleSubCounter::ClearForceBuffer);
 
-    return ForceOutputs(forceWithShiftForces, forceHelperBuffers->haveDirectVirialContributions(),
-                        forceWithVirial);
+    return ForceOutputs(
+            forceWithShiftForces, forceHelperBuffers->haveDirectVirialContributions(), forceWithVirial);
 }
 
 
@@ -869,7 +927,8 @@ static DomainLifetimeWorkload setupDomainLifetimeWorkload(const t_inputrec&
     }
     domainWork.haveGpuBondedWork = ((fr.gpuBonded != nullptr) && fr.gpuBonded->haveInteractions());
     // Note that haveFreeEnergyWork is constant over the whole run
-    domainWork.haveFreeEnergyWork = (fr.efep != efepNO && mdatoms.nPerturbed != 0);
+    domainWork.haveFreeEnergyWork =
+            (fr.efep != FreeEnergyPerturbationType::No && mdatoms.nPerturbed != 0);
     // We assume we have local force work if there are CPU
     // force tasks including PME or nonbondeds.
     domainWork.haveCpuLocalForceWork =
@@ -942,7 +1001,7 @@ static void launchGpuEndOfStepTasks(nonbonded_verlet_t*               nbv,
                                     const gmx::MdrunScheduleWorkload& runScheduleWork,
                                     bool                              useGpuPmeOnThisRank,
                                     int64_t                           step,
-                                    gmx_wallcycle_t                   wcycle)
+                                    gmx_wallcycle                   wcycle)
 {
     if (runScheduleWork.simulationWork.useGpuNonbonded && runScheduleWork.stepWork.computeNonbondedForces)
     {
@@ -956,11 +1015,11 @@ static void launchGpuEndOfStepTasks(nonbonded_verlet_t*               nbv,
         }
 
         /* now clear the GPU outputs while we finish the step on the CPU */
-        wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU);
-        wallcycle_sub_start_nocount(wcycle, ewcsLAUNCH_GPU_NONBONDED);
+        wallcycle_start_nocount(wcycle, WallCycleCounter::LaunchGpu);
+        wallcycle_sub_start_nocount(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
         Nbnxm::gpu_clear_outputs(nbv->gpu_nbv, runScheduleWork.stepWork.computeVirial);
-        wallcycle_sub_stop(wcycle, ewcsLAUNCH_GPU_NONBONDED);
-        wallcycle_stop(wcycle, ewcLAUNCH_GPU);
+        wallcycle_sub_stop(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
+        wallcycle_stop(wcycle, WallCycleCounter::LaunchGpu);
     }
 
     if (useGpuPmeOnThisRank)
@@ -1017,8 +1076,10 @@ static void reduceAndUpdateMuTot(DipoleData*                   dipoleData,
     {
         for (int j = 0; j < DIM; j++)
         {
-            muTotal[j] = (1.0 - lambda[efptCOUL]) * dipoleData->muStateAB[0][j]
-                         + lambda[efptCOUL] * dipoleData->muStateAB[1][j];
+            muTotal[j] = (1.0 - lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)])
+                                 * dipoleData->muStateAB[0][j]
+                         + lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)]
+                                   * dipoleData->muStateAB[1][j];
         }
     }
 }
@@ -1035,7 +1096,7 @@ static void combineMtsForces(const int      numAtoms,
                              ArrayRef<RVec> forceMts,
                              const real     mtsFactor)
 {
-    const int gmx_unused numThreads = gmx_omp_nthreads_get(emntDefault);
+    const int gmx_unused numThreads = gmx_omp_nthreads_get(ModuleMultiThread::Default);
 #pragma omp parallel for num_threads(numThreads) schedule(static)
     for (int i = 0; i < numAtoms; i++)
     {
@@ -1064,9 +1125,12 @@ static void setupGpuForceReductions(gmx::MdrunScheduleWorkload* runScheduleWork,
     const bool accumulate =
             runScheduleWork->domainWork.haveCpuLocalForceWork || havePPDomainDecomposition(cr);
     const int atomStart = 0;
-    fr->gpuForceReduction[gmx::AtomLocality::Local]->reinit(
-            stateGpu->getForces(), nbv->getNumAtoms(AtomLocality::Local), nbv->getGridIndices(),
-            atomStart, accumulate, stateGpu->fReducedOnDevice());
+    fr->gpuForceReduction[gmx::AtomLocality::Local]->reinit(stateGpu->getForces(),
+                                                            nbv->getNumAtoms(AtomLocality::Local),
+                                                            nbv->getGridIndices(),
+                                                            atomStart,
+                                                            accumulate,
+                                                            stateGpu->fReducedOnDevice());
 
     // register forces and add dependencies
     fr->gpuForceReduction[gmx::AtomLocality::Local]->registerNbnxmForce(nbv->getGpuForces());
@@ -1074,16 +1138,22 @@ static void setupGpuForceReductions(gmx::MdrunScheduleWorkload* runScheduleWork,
     if (runScheduleWork->simulationWork.useGpuPme
         && (thisRankHasDuty(cr, DUTY_PME) || runScheduleWork->simulationWork.useGpuPmePpCommunication))
     {
-        void* forcePtr = thisRankHasDuty(cr, DUTY_PME) ? pme_gpu_get_device_f(fr->pmedata)
-                                                       : // PME force buffer on same GPU
-                                 fr->pmePpCommGpu->getGpuForceStagingPtr(); // buffer received from other GPU
+        DeviceBuffer<gmx::RVec> forcePtr =
+                thisRankHasDuty(cr, DUTY_PME) ? pme_gpu_get_device_f(fr->pmedata)
+                                              :                    // PME force buffer on same GPU
+                        fr->pmePpCommGpu->getGpuForceStagingPtr(); // buffer received from other GPU
         fr->gpuForceReduction[gmx::AtomLocality::Local]->registerRvecForce(forcePtr);
 
         GpuEventSynchronizer* const pmeSynchronizer =
                 (thisRankHasDuty(cr, DUTY_PME) ? pme_gpu_get_f_ready_synchronizer(fr->pmedata)
                                                : // PME force buffer on same GPU
                          fr->pmePpCommGpu->getForcesReadySynchronizer()); // buffer received from other GPU
-        fr->gpuForceReduction[gmx::AtomLocality::Local]->addDependency(pmeSynchronizer);
+
+        if (GMX_THREAD_MPI)
+        {
+            GMX_ASSERT(pmeSynchronizer != nullptr, "PME force ready cuda event should not be NULL");
+            fr->gpuForceReduction[gmx::AtomLocality::Local]->addDependency(pmeSynchronizer);
+        }
     }
 
     if ((runScheduleWork->domainWork.haveCpuLocalForceWork || havePPDomainDecomposition(cr))
@@ -1107,9 +1177,11 @@ static void setupGpuForceReductions(gmx::MdrunScheduleWorkload* runScheduleWork,
         const bool accumulate = runScheduleWork->domainWork.haveCpuBondedWork
                                 || runScheduleWork->domainWork.haveFreeEnergyWork;
         const int atomStart = dd_numHomeAtoms(*cr->dd);
-        fr->gpuForceReduction[gmx::AtomLocality::NonLocal]->reinit(
-                stateGpu->getForces(), nbv->getNumAtoms(AtomLocality::NonLocal),
-                nbv->getGridIndices(), atomStart, accumulate);
+        fr->gpuForceReduction[gmx::AtomLocality::NonLocal]->reinit(stateGpu->getForces(),
+                                                                   nbv->getNumAtoms(AtomLocality::NonLocal),
+                                                                   nbv->getGridIndices(),
+                                                                   atomStart,
+                                                                   accumulate);
 
         // register forces and add dependencies
         fr->gpuForceReduction[gmx::AtomLocality::NonLocal]->registerNbnxmForce(nbv->getGpuForces());
@@ -1125,18 +1197,18 @@ static void setupGpuForceReductions(gmx::MdrunScheduleWorkload* runScheduleWork,
 void do_force(FILE*                               fplog,
               const t_commrec*                    cr,
               const gmx_multisim_t*               ms,
-              const t_inputrec*                   inputrec,
+              const t_inputrec&                   inputrec,
               gmx::Awh*                           awh,
               gmx_enfrot*                         enforcedRotation,
               gmx::ImdSession*                    imdSession,
               pull_t*                             pull_work,
               int64_t                             step,
               t_nrnb*                             nrnb,
-              gmx_wallcycle_t                     wcycle,
+              gmx_wallcycle                     wcycle,
               const gmx_localtop_t*               top,
               const matrix                        box,
               gmx::ArrayRefWithPadding<gmx::RVec> x,
-              history_t*                          hist,
+              const history_t*                    hist,
               gmx::ForceBuffersView*              forceView,
               tensor                              vir_force,
               const t_mdatoms*                    mdatoms,
@@ -1157,14 +1229,14 @@ void do_force(FILE*                               fplog,
                "forces for");
 
     nonbonded_verlet_t*  nbv = fr->nbv.get();
-    interaction_const_t* ic  = fr->ic;
+    interaction_const_t* ic  = fr->ic.get();
 
     gmx::StatePropagatorDataGpu* stateGpu = fr->stateGpu;
 
     const SimulationWorkload& simulationWork = runScheduleWork->simulationWork;
 
-    runScheduleWork->stepWork    = setupStepWorkload(legacyFlags, inputrec->mtsLevels, step,
-                                                  simulationWork, thisRankHasDuty(cr, DUTY_PME));
+    runScheduleWork->stepWork = setupStepWorkload(
+            legacyFlags, inputrec.mtsLevels, step, simulationWork, thisRankHasDuty(cr, DUTY_PME));
     const StepWorkload& stepWork = runScheduleWork->stepWork;
 
     const bool useGpuPmeOnThisRank =
@@ -1195,8 +1267,10 @@ void do_force(FILE*                               fplog,
         const bool calcCGCM = (fillGrid && !DOMAINDECOMP(cr));
         if (calcCGCM)
         {
-            put_atoms_in_box_omp(fr->pbcType, box, x.unpaddedArrayRef().subArray(0, mdatoms->homenr),
-                                 gmx_omp_nthreads_get(emntDefault));
+            put_atoms_in_box_omp(fr->pbcType,
+                                 box,
+                                 x.unpaddedArrayRef().subArray(0, mdatoms->homenr),
+                                 gmx_omp_nthreads_get(ModuleMultiThread::Default));
             inc_nrnb(nrnb, eNR_SHIFTX, mdatoms->homenr);
         }
     }
@@ -1208,10 +1282,10 @@ void do_force(FILE*                               fplog,
     const bool reinitGpuPmePpComms =
             GMX_MPI && simulationWork.useGpuPmePpCommunication && (stepWork.doNeighborSearch);
 
-    const auto localXReadyOnDevice = (useGpuPmeOnThisRank || simulationWork.useGpuBufferOps)
-                                             ? stateGpu->getCoordinatesReadyOnDeviceEvent(
-                                                       AtomLocality::Local, simulationWork, stepWork)
-                                             : nullptr;
+    auto* localXReadyOnDevice = (useGpuPmeOnThisRank || simulationWork.useGpuBufferOps)
+                                        ? stateGpu->getCoordinatesReadyOnDeviceEvent(
+                                                  AtomLocality::Local, simulationWork, stepWork)
+                                        : nullptr;
 
     // Copy coordinate from the GPU if update is on the GPU and there
     // are forces to be computed on the CPU, or for the computation of
@@ -1237,22 +1311,6 @@ void do_force(FILE*                               fplog,
         haveCopiedXFromGpu = true;
     }
 
-    // If coordinates are to be sent to PME task from CPU memory, perform that send here.
-    // Otherwise the send will occur after H2D coordinate transfer.
-    if (GMX_MPI && !thisRankHasDuty(cr, DUTY_PME) && !pmeSendCoordinatesFromGpu && stepWork.computeSlowForces)
-    {
-        /* Send particle coordinates to the pme nodes */
-        if (!stepWork.doNeighborSearch && simulationWork.useGpuUpdate)
-        {
-            stateGpu->waitCoordinatesReadyOnHost(AtomLocality::Local);
-        }
-
-        gmx_pme_send_coordinates(fr, cr, box, as_rvec_array(x.unpaddedArrayRef().data()), lambda[efptCOUL],
-                                 lambda[efptVDW], (stepWork.computeVirial || stepWork.computeEnergy),
-                                 step, simulationWork.useGpuPmePpCommunication, reinitGpuPmePpComms,
-                                 pmeSendCoordinatesFromGpu, localXReadyOnDevice, wcycle);
-    }
-
     // Coordinates on the device are needed if PME or BufferOps are offloaded.
     // The local coordinates can be copied right away.
     // NOTE: Consider moving this copy to right after they are updated and constrained,
@@ -1280,20 +1338,39 @@ void do_force(FILE*                               fplog,
         }
     }
 
-    // If coordinates are to be sent to PME task from GPU memory, perform that send here.
-    // Otherwise the send will occur before the H2D coordinate transfer.
-    if (!thisRankHasDuty(cr, DUTY_PME) && pmeSendCoordinatesFromGpu)
+    if (GMX_MPI && !thisRankHasDuty(cr, DUTY_PME) && stepWork.computeSlowForces)
     {
         /* Send particle coordinates to the pme nodes */
-        gmx_pme_send_coordinates(fr, cr, box, as_rvec_array(x.unpaddedArrayRef().data()), lambda[efptCOUL],
-                                 lambda[efptVDW], (stepWork.computeVirial || stepWork.computeEnergy),
-                                 step, simulationWork.useGpuPmePpCommunication, reinitGpuPmePpComms,
-                                 pmeSendCoordinatesFromGpu, localXReadyOnDevice, wcycle);
+        if (!pmeSendCoordinatesFromGpu && !stepWork.doNeighborSearch && simulationWork.useGpuUpdate)
+        {
+            GMX_ASSERT(haveCopiedXFromGpu,
+                       "a wait should only be triggered if copy has been scheduled");
+            stateGpu->waitCoordinatesReadyOnHost(AtomLocality::Local);
+        }
+
+        gmx_pme_send_coordinates(fr,
+                                 cr,
+                                 box,
+                                 as_rvec_array(x.unpaddedArrayRef().data()),
+                                 lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)],
+                                 lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)],
+                                 (stepWork.computeVirial || stepWork.computeEnergy),
+                                 step,
+                                 simulationWork.useGpuPmePpCommunication,
+                                 reinitGpuPmePpComms,
+                                 pmeSendCoordinatesFromGpu,
+                                 localXReadyOnDevice,
+                                 wcycle);
     }
 
     if (useGpuPmeOnThisRank)
     {
-        launchPmeGpuSpread(fr->pmedata, box, stepWork, localXReadyOnDevice, lambda[efptCOUL], wcycle);
+        launchPmeGpuSpread(fr->pmedata,
+                           box,
+                           stepWork,
+                           localXReadyOnDevice,
+                           lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)],
+                           wcycle);
     }
 
     const gmx::DomainLifetimeWorkload& domainWork = runScheduleWork->domainWork;
@@ -1306,47 +1383,48 @@ void do_force(FILE*                               fplog,
             fr->wholeMoleculeTransform->updateForAtomPbcJumps(x.unpaddedArrayRef(), box);
         }
 
-        // TODO
-        // - vzero is constant, do we need to pass it?
-        // - box_diag should be passed directly to nbnxn_put_on_grid
-        //
-        rvec vzero;
-        clear_rvec(vzero);
-
-        rvec box_diag;
-        box_diag[XX] = box[XX][XX];
-        box_diag[YY] = box[YY][YY];
-        box_diag[ZZ] = box[ZZ][ZZ];
-
-        wallcycle_start(wcycle, ewcNS);
+        wallcycle_start(wcycle, WallCycleCounter::NS);
         if (!DOMAINDECOMP(cr))
         {
-            wallcycle_sub_start(wcycle, ewcsNBS_GRID_LOCAL);
-            nbnxn_put_on_grid(nbv, box, 0, vzero, box_diag, nullptr, { 0, mdatoms->homenr }, -1,
-                              fr->cginfo, x.unpaddedArrayRef(), 0, nullptr);
-            wallcycle_sub_stop(wcycle, ewcsNBS_GRID_LOCAL);
+            const rvec vzero       = { 0.0_real, 0.0_real, 0.0_real };
+            const rvec boxDiagonal = { box[XX][XX], box[YY][YY], box[ZZ][ZZ] };
+            wallcycle_sub_start(wcycle, WallCycleSubCounter::NBSGridLocal);
+            nbnxn_put_on_grid(nbv,
+                              box,
+                              0,
+                              vzero,
+                              boxDiagonal,
+                              nullptr,
+                              { 0, mdatoms->homenr },
+                              -1,
+                              fr->cginfo,
+                              x.unpaddedArrayRef(),
+                              0,
+                              nullptr);
+            wallcycle_sub_stop(wcycle, WallCycleSubCounter::NBSGridLocal);
         }
         else
         {
-            wallcycle_sub_start(wcycle, ewcsNBS_GRID_NONLOCAL);
+            wallcycle_sub_start(wcycle, WallCycleSubCounter::NBSGridNonLocal);
             nbnxn_put_on_grid_nonlocal(nbv, domdec_zones(cr->dd), fr->cginfo, x.unpaddedArrayRef());
-            wallcycle_sub_stop(wcycle, ewcsNBS_GRID_NONLOCAL);
+            wallcycle_sub_stop(wcycle, WallCycleSubCounter::NBSGridNonLocal);
         }
 
         nbv->setAtomProperties(gmx::constArrayRefFromArray(mdatoms->typeA, mdatoms->nr),
-                               gmx::constArrayRefFromArray(mdatoms->chargeA, mdatoms->nr), fr->cginfo);
+                               gmx::constArrayRefFromArray(mdatoms->chargeA, mdatoms->nr),
+                               fr->cginfo);
 
-        wallcycle_stop(wcycle, ewcNS);
+        wallcycle_stop(wcycle, WallCycleCounter::NS);
 
         /* initialize the GPU nbnxm atom data and bonded data structures */
         if (simulationWork.useGpuNonbonded)
         {
             // Note: cycle counting only nononbondeds, gpuBonded counts internally
-            wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU);
-            wallcycle_sub_start_nocount(wcycle, ewcsLAUNCH_GPU_NONBONDED);
+            wallcycle_start_nocount(wcycle, WallCycleCounter::LaunchGpu);
+            wallcycle_sub_start_nocount(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
             Nbnxm::gpu_init_atomdata(nbv->gpu_nbv, nbv->nbat.get());
-            wallcycle_sub_stop(wcycle, ewcsLAUNCH_GPU_NONBONDED);
-            wallcycle_stop(wcycle, ewcLAUNCH_GPU);
+            wallcycle_sub_stop(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
+            wallcycle_stop(wcycle, WallCycleCounter::LaunchGpu);
 
             if (fr->gpuBonded)
             {
@@ -1358,26 +1436,28 @@ void do_force(FILE*                               fplog,
                 // TODO the xq, f, and fshift buffers are now shared
                 // resources, so they should be maintained by a
                 // higher-level object than the nb module.
-                fr->gpuBonded->updateInteractionListsAndDeviceBuffers(
-                        nbv->getGridIndices(), top->idef, Nbnxm::gpu_get_xq(nbv->gpu_nbv),
-                        Nbnxm::gpu_get_f(nbv->gpu_nbv), Nbnxm::gpu_get_fshift(nbv->gpu_nbv));
+                fr->gpuBonded->updateInteractionListsAndDeviceBuffers(nbv->getGridIndices(),
+                                                                      top->idef,
+                                                                      Nbnxm::gpu_get_xq(nbv->gpu_nbv),
+                                                                      Nbnxm::gpu_get_f(nbv->gpu_nbv),
+                                                                      Nbnxm::gpu_get_fshift(nbv->gpu_nbv));
             }
         }
 
         // Need to run after the GPU-offload bonded interaction lists
         // are set up to be able to determine whether there is bonded work.
         runScheduleWork->domainWork = setupDomainLifetimeWorkload(
-                *inputrec, *fr, pull_work, ed, *mdatoms, simulationWork, stepWork);
+                inputrec, *fr, pull_work, ed, *mdatoms, simulationWork, stepWork);
 
-        wallcycle_start_nocount(wcycle, ewcNS);
-        wallcycle_sub_start(wcycle, ewcsNBS_SEARCH_LOCAL);
+        wallcycle_start_nocount(wcycle, WallCycleCounter::NS);
+        wallcycle_sub_start(wcycle, WallCycleSubCounter::NBSSearchLocal);
         /* Note that with a GPU the launch overhead of the list transfer is not timed separately */
         nbv->constructPairlist(InteractionLocality::Local, top->excls, step, nrnb);
 
         nbv->setupGpuShortRangeWork(fr->gpuBonded, InteractionLocality::Local);
 
-        wallcycle_sub_stop(wcycle, ewcsNBS_SEARCH_LOCAL);
-        wallcycle_stop(wcycle, ewcNS);
+        wallcycle_sub_stop(wcycle, WallCycleSubCounter::NBSSearchLocal);
+        wallcycle_stop(wcycle, WallCycleCounter::NS);
 
         if (stepWork.useGpuXBufferOps)
         {
@@ -1389,13 +1469,12 @@ void do_force(FILE*                               fplog,
             setupGpuForceReductions(runScheduleWork, cr, fr);
         }
     }
-    else if (!EI_TPI(inputrec->eI) && stepWork.computeNonbondedForces)
+    else if (!EI_TPI(inputrec.eI) && stepWork.computeNonbondedForces)
     {
         if (stepWork.useGpuXBufferOps)
         {
             GMX_ASSERT(stateGpu, "stateGpu should be valid when buffer ops are offloaded");
-            nbv->convertCoordinatesGpu(AtomLocality::Local, false, stateGpu->getCoordinates(),
-                                       localXReadyOnDevice);
+            nbv->convertCoordinatesGpu(AtomLocality::Local, stateGpu->getCoordinates(), localXReadyOnDevice);
         }
         else
         {
@@ -1406,7 +1485,7 @@ void do_force(FILE*                               fplog,
                            "a wait should only be triggered if copy has been scheduled");
                 stateGpu->waitCoordinatesReadyOnHost(AtomLocality::Local);
             }
-            nbv->convertCoordinates(AtomLocality::Local, false, x.unpaddedArrayRef());
+            nbv->convertCoordinates(AtomLocality::Local, x.unpaddedArrayRef());
         }
     }
 
@@ -1414,15 +1493,15 @@ void do_force(FILE*                               fplog,
     {
         ddBalanceRegionHandler.openBeforeForceComputationGpu();
 
-        wallcycle_start(wcycle, ewcLAUNCH_GPU);
-        wallcycle_sub_start(wcycle, ewcsLAUNCH_GPU_NONBONDED);
+        wallcycle_start(wcycle, WallCycleCounter::LaunchGpu);
+        wallcycle_sub_start(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
         Nbnxm::gpu_upload_shiftvec(nbv->gpu_nbv, nbv->nbat.get());
         if (stepWork.doNeighborSearch || !stepWork.useGpuXBufferOps)
         {
             Nbnxm::gpu_copy_xq_to_gpu(nbv->gpu_nbv, nbv->nbat.get(), AtomLocality::Local);
         }
-        wallcycle_sub_stop(wcycle, ewcsLAUNCH_GPU_NONBONDED);
-        wallcycle_stop(wcycle, ewcLAUNCH_GPU);
+        wallcycle_sub_stop(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
+        wallcycle_stop(wcycle, WallCycleCounter::LaunchGpu);
         // with X buffer ops offloaded to the GPU on all but the search steps
 
         // bonded work not split into separate local and non-local, so with DD
@@ -1433,11 +1512,11 @@ void do_force(FILE*                               fplog,
         }
 
         /* launch local nonbonded work on GPU */
-        wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU);
-        wallcycle_sub_start_nocount(wcycle, ewcsLAUNCH_GPU_NONBONDED);
+        wallcycle_start_nocount(wcycle, WallCycleCounter::LaunchGpu);
+        wallcycle_sub_start_nocount(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
         do_nb_verlet(fr, ic, enerd, stepWork, InteractionLocality::Local, enbvClearFNo, step, nrnb, wcycle);
-        wallcycle_sub_stop(wcycle, ewcsLAUNCH_GPU_NONBONDED);
-        wallcycle_stop(wcycle, ewcLAUNCH_GPU);
+        wallcycle_sub_stop(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
+        wallcycle_stop(wcycle, WallCycleCounter::LaunchGpu);
     }
 
     if (useGpuPmeOnThisRank)
@@ -1446,7 +1525,10 @@ void do_force(FILE*                               fplog,
         // X copy/transform to allow overlap as well as after the GPU NB
         // launch to avoid FFT launch overhead hijacking the CPU and delaying
         // the nonbonded kernel.
-        launchPmeGpuFftAndGather(fr->pmedata, lambda[efptCOUL], wcycle, stepWork);
+        launchPmeGpuFftAndGather(fr->pmedata,
+                                 lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)],
+                                 wcycle,
+                                 stepWork);
     }
 
     /* Communicate coordinates and sum dipole if necessary +
@@ -1456,14 +1538,14 @@ void do_force(FILE*                               fplog,
         if (stepWork.doNeighborSearch)
         {
             // TODO: fuse this branch with the above large stepWork.doNeighborSearch block
-            wallcycle_start_nocount(wcycle, ewcNS);
-            wallcycle_sub_start(wcycle, ewcsNBS_SEARCH_NONLOCAL);
+            wallcycle_start_nocount(wcycle, WallCycleCounter::NS);
+            wallcycle_sub_start(wcycle, WallCycleSubCounter::NBSSearchNonLocal);
             /* Note that with a GPU the launch overhead of the list transfer is not timed separately */
             nbv->constructPairlist(InteractionLocality::NonLocal, top->excls, step, nrnb);
 
             nbv->setupGpuShortRangeWork(fr->gpuBonded, InteractionLocality::NonLocal);
-            wallcycle_sub_stop(wcycle, ewcsNBS_SEARCH_NONLOCAL);
-            wallcycle_stop(wcycle, ewcNS);
+            wallcycle_sub_stop(wcycle, WallCycleSubCounter::NBSSearchNonLocal);
+            wallcycle_stop(wcycle, WallCycleCounter::NS);
             // TODO refactor this GPU halo exchange re-initialisation
             // to location in do_md where GPU halo exchange is
             // constructed at partitioning, after above stateGpu
@@ -1504,13 +1586,14 @@ void do_force(FILE*                               fplog,
                 {
                     stateGpu->copyCoordinatesToGpu(x.unpaddedArrayRef(), AtomLocality::NonLocal);
                 }
-                nbv->convertCoordinatesGpu(AtomLocality::NonLocal, false, stateGpu->getCoordinates(),
+                nbv->convertCoordinatesGpu(AtomLocality::NonLocal,
+                                           stateGpu->getCoordinates(),
                                            stateGpu->getCoordinatesReadyOnDeviceEvent(
                                                    AtomLocality::NonLocal, simulationWork, stepWork));
             }
             else
             {
-                nbv->convertCoordinates(AtomLocality::NonLocal, false, x.unpaddedArrayRef());
+                nbv->convertCoordinates(AtomLocality::NonLocal, x.unpaddedArrayRef());
             }
         }
 
@@ -1519,11 +1602,11 @@ void do_force(FILE*                               fplog,
 
             if (stepWork.doNeighborSearch || !stepWork.useGpuXBufferOps)
             {
-                wallcycle_start(wcycle, ewcLAUNCH_GPU);
-                wallcycle_sub_start(wcycle, ewcsLAUNCH_GPU_NONBONDED);
+                wallcycle_start(wcycle, WallCycleCounter::LaunchGpu);
+                wallcycle_sub_start(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
                 Nbnxm::gpu_copy_xq_to_gpu(nbv->gpu_nbv, nbv->nbat.get(), AtomLocality::NonLocal);
-                wallcycle_sub_stop(wcycle, ewcsLAUNCH_GPU_NONBONDED);
-                wallcycle_stop(wcycle, ewcLAUNCH_GPU);
+                wallcycle_sub_stop(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
+                wallcycle_stop(wcycle, WallCycleCounter::LaunchGpu);
             }
 
             if (domainWork.haveGpuBondedWork)
@@ -1532,33 +1615,32 @@ void do_force(FILE*                               fplog,
             }
 
             /* launch non-local nonbonded tasks on GPU */
-            wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU);
-            wallcycle_sub_start(wcycle, ewcsLAUNCH_GPU_NONBONDED);
-            do_nb_verlet(fr, ic, enerd, stepWork, InteractionLocality::NonLocal, enbvClearFNo, step,
-                         nrnb, wcycle);
-            wallcycle_sub_stop(wcycle, ewcsLAUNCH_GPU_NONBONDED);
-            wallcycle_stop(wcycle, ewcLAUNCH_GPU);
+            wallcycle_start_nocount(wcycle, WallCycleCounter::LaunchGpu);
+            wallcycle_sub_start(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
+            do_nb_verlet(fr, ic, enerd, stepWork, InteractionLocality::NonLocal, enbvClearFNo, step, nrnb, wcycle);
+            wallcycle_sub_stop(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
+            wallcycle_stop(wcycle, WallCycleCounter::LaunchGpu);
         }
     }
 
     if (simulationWork.useGpuNonbonded && stepWork.computeNonbondedForces)
     {
         /* launch D2H copy-back F */
-        wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU);
-        wallcycle_sub_start_nocount(wcycle, ewcsLAUNCH_GPU_NONBONDED);
+        wallcycle_start_nocount(wcycle, WallCycleCounter::LaunchGpu);
+        wallcycle_sub_start_nocount(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
 
         if (havePPDomainDecomposition(cr))
         {
             Nbnxm::gpu_launch_cpyback(nbv->gpu_nbv, nbv->nbat.get(), stepWork, AtomLocality::NonLocal);
         }
         Nbnxm::gpu_launch_cpyback(nbv->gpu_nbv, nbv->nbat.get(), stepWork, AtomLocality::Local);
-        wallcycle_sub_stop(wcycle, ewcsLAUNCH_GPU_NONBONDED);
+        wallcycle_sub_stop(wcycle, WallCycleSubCounter::LaunchGpuNonBonded);
 
         if (domainWork.haveGpuBondedWork && stepWork.computeEnergy)
         {
             fr->gpuBonded->launchEnergyTransfer();
         }
-        wallcycle_stop(wcycle, ewcLAUNCH_GPU);
+        wallcycle_stop(wcycle, WallCycleCounter::LaunchGpu);
     }
 
     gmx::ArrayRef<const gmx::RVec> xWholeMolecules;
@@ -1585,10 +1667,19 @@ void do_force(FILE*                               fplog,
          */
         gmx::ArrayRef<const gmx::RVec> xRef =
                 (xWholeMolecules.empty() ? x.unpaddedArrayRef() : xWholeMolecules);
-        calc_mu(start, mdatoms->homenr, xRef, mdatoms->chargeA, mdatoms->chargeB,
-                mdatoms->nChargePerturbed, dipoleData.muStaging[0], dipoleData.muStaging[1]);
+        calc_mu(start,
+                mdatoms->homenr,
+                xRef,
+                mdatoms->chargeA ? gmx::arrayRefFromArray(mdatoms->chargeA, mdatoms->nr)
+                                 : gmx::ArrayRef<real>{},
+                mdatoms->chargeB ? gmx::arrayRefFromArray(mdatoms->chargeB, mdatoms->nr)
+                                 : gmx::ArrayRef<real>{},
+                mdatoms->nChargePerturbed != 0,
+                dipoleData.muStaging[0],
+                dipoleData.muStaging[1]);
 
-        reduceAndUpdateMuTot(&dipoleData, cr, (fr->efep != efepNO), lambda, muTotal, ddBalanceRegionHandler);
+        reduceAndUpdateMuTot(
+                &dipoleData, cr, (fr->efep != FreeEnergyPerturbationType::No), lambda, muTotal, ddBalanceRegionHandler);
     }
 
     /* Reset energies */
@@ -1596,30 +1687,30 @@ void do_force(FILE*                               fplog,
 
     if (DOMAINDECOMP(cr) && !thisRankHasDuty(cr, DUTY_PME))
     {
-        wallcycle_start(wcycle, ewcPPDURINGPME);
+        wallcycle_start(wcycle, WallCycleCounter::PpDuringPme);
         dd_force_flop_start(cr->dd, nrnb);
     }
 
     // For the rest of the CPU tasks that depend on GPU-update produced coordinates,
     // this wait ensures that the D2H transfer is complete.
-    if ((simulationWork.useGpuUpdate)
+    if (simulationWork.useGpuUpdate && !stepWork.doNeighborSearch
         && (runScheduleWork->domainWork.haveCpuLocalForceWork || stepWork.computeVirial))
     {
+        GMX_ASSERT(haveCopiedXFromGpu, "a wait should only be triggered if copy has been scheduled");
         stateGpu->waitCoordinatesReadyOnHost(AtomLocality::Local);
     }
 
-    if (inputrec->bRot)
+    if (inputrec.bRot)
     {
-        wallcycle_start(wcycle, ewcROT);
-        do_rotation(cr, enforcedRotation, box, as_rvec_array(x.unpaddedArrayRef().data()), t, step,
-                    stepWork.doNeighborSearch);
-        wallcycle_stop(wcycle, ewcROT);
+        wallcycle_start(wcycle, WallCycleCounter::Rot);
+        do_rotation(cr, enforcedRotation, box, x.unpaddedConstArrayRef(), t, step, stepWork.doNeighborSearch);
+        wallcycle_stop(wcycle, WallCycleCounter::Rot);
     }
 
     /* Start the force cycle counter.
      * Note that a different counter is used for dynamic load balancing.
      */
-    wallcycle_start(wcycle, ewcFORCE);
+    wallcycle_start(wcycle, WallCycleCounter::Force);
 
     /* Set up and clear force outputs:
      * forceOutMtsLevel0:  everything except what is in the other two outputs
@@ -1628,15 +1719,18 @@ void do_force(FILE*                               fplog,
      * Without multiple time stepping all point to the same object.
      * With multiple time-stepping the use is different for MTS fast (level0 only) and slow steps.
      */
-    ForceOutputs forceOutMtsLevel0 =
-            setupForceOutputs(&fr->forceHelperBuffers[0], force, stepWork, wcycle);
+    ForceOutputs forceOutMtsLevel0 = setupForceOutputs(
+            &fr->forceHelperBuffers[0], force, domainWork, stepWork, havePPDomainDecomposition(cr), wcycle);
 
     // Force output for MTS combined forces, only set at level1 MTS steps
     std::optional<ForceOutputs> forceOutMts =
             (fr->useMts && stepWork.computeSlowForces)
                     ? std::optional(setupForceOutputs(&fr->forceHelperBuffers[1],
                                                       forceView->forceMtsCombinedWithPadding(),
-                                                      stepWork, wcycle))
+                                                      domainWork,
+                                                      stepWork,
+                                                      havePPDomainDecomposition(cr),
+                                                      wcycle))
                     : std::nullopt;
 
     ForceOutputs* forceOutMtsLevel1 =
@@ -1646,7 +1740,7 @@ void do_force(FILE*                               fplog,
 
     ForceOutputs* forceOutNonbonded = nonbondedAtMtsLevel1 ? forceOutMtsLevel1 : &forceOutMtsLevel0;
 
-    if (inputrec->bPull && pull_have_constraint(*pull_work))
+    if (inputrec.bPull && pull_have_constraint(*pull_work))
     {
         clear_pull_forces(pull_work);
     }
@@ -1666,22 +1760,50 @@ void do_force(FILE*                               fplog,
         do_nb_verlet(fr, ic, enerd, stepWork, InteractionLocality::Local, enbvClearFYes, step, nrnb, wcycle);
     }
 
-    if (fr->efep != efepNO && stepWork.computeNonbondedForces)
+    if (fr->efep != FreeEnergyPerturbationType::No && stepWork.computeNonbondedForces)
     {
         /* Calculate the local and non-local free energy interactions here.
          * Happens here on the CPU both with and without GPU.
          */
-        nbv->dispatchFreeEnergyKernel(InteractionLocality::Local, fr,
-                                      as_rvec_array(x.unpaddedArrayRef().data()),
-                                      &forceOutNonbonded->forceWithShiftForces(), *mdatoms,
-                                      inputrec->fepvals, lambda, enerd, stepWork, nrnb);
+        nbv->dispatchFreeEnergyKernel(
+                InteractionLocality::Local,
+                *fr,
+                x.unpaddedArrayRef(),
+                &forceOutNonbonded->forceWithShiftForces(),
+                mdatoms->chargeA ? gmx::arrayRefFromArray(mdatoms->chargeA, mdatoms->nr)
+                                 : gmx::ArrayRef<real>{},
+                mdatoms->chargeB ? gmx::arrayRefFromArray(mdatoms->chargeB, mdatoms->nr)
+                                 : gmx::ArrayRef<real>{},
+                mdatoms->typeA ? gmx::arrayRefFromArray(mdatoms->typeA, mdatoms->nr)
+                               : gmx::ArrayRef<int>{},
+                mdatoms->typeB ? gmx::arrayRefFromArray(mdatoms->typeB, mdatoms->nr)
+                               : gmx::ArrayRef<int>{},
+                inputrec.fepvals.get(),
+                lambda,
+                enerd,
+                stepWork,
+                nrnb);
 
         if (havePPDomainDecomposition(cr))
         {
-            nbv->dispatchFreeEnergyKernel(InteractionLocality::NonLocal, fr,
-                                          as_rvec_array(x.unpaddedArrayRef().data()),
-                                          &forceOutNonbonded->forceWithShiftForces(), *mdatoms,
-                                          inputrec->fepvals, lambda, enerd, stepWork, nrnb);
+            nbv->dispatchFreeEnergyKernel(
+                    InteractionLocality::NonLocal,
+                    *fr,
+                    x.unpaddedArrayRef(),
+                    &forceOutNonbonded->forceWithShiftForces(),
+                    mdatoms->chargeA ? gmx::arrayRefFromArray(mdatoms->chargeA, mdatoms->nr)
+                                     : gmx::ArrayRef<real>{},
+                    mdatoms->chargeB ? gmx::arrayRefFromArray(mdatoms->chargeB, mdatoms->nr)
+                                     : gmx::ArrayRef<real>{},
+                    mdatoms->typeA ? gmx::arrayRefFromArray(mdatoms->typeA, mdatoms->nr)
+                                   : gmx::ArrayRef<int>{},
+                    mdatoms->typeB ? gmx::arrayRefFromArray(mdatoms->typeB, mdatoms->nr)
+                                   : gmx::ArrayRef<int>{},
+                    inputrec.fepvals.get(),
+                    lambda,
+                    enerd,
+                    stepWork,
+                    nrnb);
         }
     }
 
@@ -1689,8 +1811,7 @@ void do_force(FILE*                               fplog,
     {
         if (havePPDomainDecomposition(cr))
         {
-            do_nb_verlet(fr, ic, enerd, stepWork, InteractionLocality::NonLocal, enbvClearFNo, step,
-                         nrnb, wcycle);
+            do_nb_verlet(fr, ic, enerd, stepWork, InteractionLocality::NonLocal, enbvClearFNo, step, nrnb, wcycle);
         }
 
         if (stepWork.computeForces)
@@ -1699,10 +1820,10 @@ void do_force(FILE*                               fplog,
              * This can be split into a local and a non-local part when overlapping
              * communication with calculation with domain decomposition.
              */
-            wallcycle_stop(wcycle, ewcFORCE);
+            wallcycle_stop(wcycle, WallCycleCounter::Force);
             nbv->atomdata_add_nbat_f_to_f(AtomLocality::All,
                                           forceOutNonbonded->forceWithShiftForces().force());
-            wallcycle_start_nocount(wcycle, ewcFORCE);
+            wallcycle_start_nocount(wcycle, WallCycleCounter::Force);
         }
 
         /* If there are multiple fshift output buffers we need to reduce them */
@@ -1718,21 +1839,34 @@ void do_force(FILE*                               fplog,
     // TODO Force flags should include haveFreeEnergyWork for this domain
     if (stepWork.useGpuXHalo && (domainWork.haveCpuBondedWork || domainWork.haveFreeEnergyWork))
     {
-        wallcycle_stop(wcycle, ewcFORCE);
+        wallcycle_stop(wcycle, WallCycleCounter::Force);
         /* Wait for non-local coordinate data to be copied from device */
         stateGpu->waitCoordinatesReadyOnHost(AtomLocality::NonLocal);
-        wallcycle_start_nocount(wcycle, ewcFORCE);
+        wallcycle_start_nocount(wcycle, WallCycleCounter::Force);
     }
 
     // Compute wall interactions, when present.
     // Note: should be moved to special forces.
-    if (inputrec->nwall && stepWork.computeNonbondedForces)
+    if (inputrec.nwall && stepWork.computeNonbondedForces)
     {
         /* foreign lambda component for walls */
-        real dvdl_walls = do_walls(*inputrec, *fr, box, *mdatoms, x.unpaddedConstArrayRef(),
-                                   &forceOutMtsLevel0.forceWithVirial(), lambda[efptVDW],
-                                   enerd->grpp.ener[egLJSR].data(), nrnb);
-        enerd->dvdl_lin[efptVDW] += dvdl_walls;
+        real dvdl_walls = do_walls(inputrec,
+                                   *fr,
+                                   box,
+                                   mdatoms->typeA ? gmx::arrayRefFromArray(mdatoms->typeA, mdatoms->nr)
+                                                  : gmx::ArrayRef<int>{},
+                                   mdatoms->typeB ? gmx::arrayRefFromArray(mdatoms->typeB, mdatoms->nr)
+                                                  : gmx::ArrayRef<int>{},
+                                   mdatoms->cENER ? gmx::arrayRefFromArray(mdatoms->cENER, mdatoms->nr)
+                                                  : gmx::ArrayRef<unsigned short>{},
+                                   mdatoms->homenr,
+                                   mdatoms->nPerturbed,
+                                   x.unpaddedConstArrayRef(),
+                                   &forceOutMtsLevel0.forceWithVirial(),
+                                   lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)],
+                                   enerd->grpp.energyGroupPairTerms[NonBondedEnergyTerms::LJSR],
+                                   nrnb);
+        enerd->dvdl_lin[FreeEnergyPerturbationCouplingType::Vdw] += dvdl_walls;
     }
 
     if (stepWork.computeListedForces)
@@ -1761,35 +1895,59 @@ void do_force(FILE*                               fplog,
         {
             ListedForces& listedForces = fr->listedForces[mtsIndex];
             ForceOutputs& forceOut     = (mtsIndex == 0 ? forceOutMtsLevel0 : *forceOutMtsLevel1);
-            listedForces.calculate(
-                    wcycle, box, inputrec->fepvals, cr, ms, x, xWholeMolecules, fr->fcdata.get(),
-                    hist, &forceOut, fr, &pbc, enerd, nrnb, lambda.data(), mdatoms,
-                    DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr, stepWork);
+            listedForces.calculate(wcycle,
+                                   box,
+                                   inputrec.fepvals.get(),
+                                   cr,
+                                   ms,
+                                   x,
+                                   xWholeMolecules,
+                                   fr->fcdata.get(),
+                                   hist,
+                                   &forceOut,
+                                   fr,
+                                   &pbc,
+                                   enerd,
+                                   nrnb,
+                                   lambda,
+                                   mdatoms,
+                                   DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr,
+                                   stepWork);
         }
     }
 
     if (stepWork.computeSlowForces)
     {
-        calculateLongRangeNonbondeds(fr, inputrec, cr, nrnb, wcycle, mdatoms,
-                                     x.unpaddedConstArrayRef(), &forceOutMtsLevel1->forceWithVirial(),
-                                     enerd, box, lambda.data(), as_rvec_array(dipoleData.muStateAB),
-                                     stepWork, ddBalanceRegionHandler);
+        calculateLongRangeNonbondeds(fr,
+                                     inputrec,
+                                     cr,
+                                     nrnb,
+                                     wcycle,
+                                     mdatoms,
+                                     x.unpaddedConstArrayRef(),
+                                     &forceOutMtsLevel1->forceWithVirial(),
+                                     enerd,
+                                     box,
+                                     lambda,
+                                     dipoleData.muStateAB,
+                                     stepWork,
+                                     ddBalanceRegionHandler);
     }
 
-    wallcycle_stop(wcycle, ewcFORCE);
+    wallcycle_stop(wcycle, WallCycleCounter::Force);
 
     // VdW dispersion correction, only computed on master rank to avoid double counting
     if ((stepWork.computeEnergy || stepWork.computeVirial) && fr->dispersionCorrection && MASTER(cr))
     {
         // Calculate long range corrections to pressure and energy
-        const DispersionCorrection::Correction correction =
-                fr->dispersionCorrection->calculate(box, lambda[efptVDW]);
+        const DispersionCorrection::Correction correction = fr->dispersionCorrection->calculate(
+                box, lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Vdw)]);
 
         if (stepWork.computeEnergy)
         {
             enerd->term[F_DISPCORR] = correction.energy;
             enerd->term[F_DVDL_VDW] += correction.dvdl;
-            enerd->dvdl_lin[efptVDW] += correction.dvdl;
+            enerd->dvdl_lin[FreeEnergyPerturbationCouplingType::Vdw] += correction.dvdl;
         }
         if (stepWork.computeVirial)
         {
@@ -1798,11 +1956,33 @@ void do_force(FILE*                               fplog,
         }
     }
 
-    computeSpecialForces(fplog, cr, inputrec, awh, enforcedRotation, imdSession, pull_work, step, t,
-                         wcycle, fr->forceProviders, box, x.unpaddedArrayRef(), mdatoms, lambda,
-                         stepWork, &forceOutMtsLevel0.forceWithVirial(),
-                         forceOutMtsLevel1 ? &forceOutMtsLevel1->forceWithVirial() : nullptr, enerd,
-                         ed, stepWork.doNeighborSearch);
+    computeSpecialForces(fplog,
+                         cr,
+                         inputrec,
+                         awh,
+                         enforcedRotation,
+                         imdSession,
+                         pull_work,
+                         step,
+                         t,
+                         wcycle,
+                         fr->forceProviders,
+                         box,
+                         x.unpaddedArrayRef(),
+                         mdatoms,
+                         lambda,
+                         stepWork,
+                         &forceOutMtsLevel0.forceWithVirial(),
+                         forceOutMtsLevel1 ? &forceOutMtsLevel1->forceWithVirial() : nullptr,
+                         enerd,
+                         ed,
+                         stepWork.doNeighborSearch);
+
+    if (havePPDomainDecomposition(cr) && stepWork.computeForces && stepWork.useGpuFHalo
+        && domainWork.haveCpuLocalForceWork)
+    {
+        stateGpu->copyForcesToGpu(forceOutMtsLevel0.forceWithShiftForces().force(), AtomLocality::Local);
+    }
 
     GMX_ASSERT(!(nonbondedAtMtsLevel1 && stepWork.useGpuFBufferOps),
                "The schedule below does not allow for nonbonded MTS with GPU buffer ops");
@@ -1821,15 +2001,20 @@ void do_force(FILE*                               fplog,
             if (simulationWork.useGpuNonbonded)
             {
                 cycles_wait_gpu += Nbnxm::gpu_wait_finish_task(
-                        nbv->gpu_nbv, stepWork, AtomLocality::NonLocal, enerd->grpp.ener[egLJSR].data(),
-                        enerd->grpp.ener[egCOULSR].data(), forceWithShiftForces.shiftForces(), wcycle);
+                        nbv->gpu_nbv,
+                        stepWork,
+                        AtomLocality::NonLocal,
+                        enerd->grpp.energyGroupPairTerms[NonBondedEnergyTerms::LJSR].data(),
+                        enerd->grpp.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR].data(),
+                        forceWithShiftForces.shiftForces(),
+                        wcycle);
             }
             else
             {
-                wallcycle_start_nocount(wcycle, ewcFORCE);
-                do_nb_verlet(fr, ic, enerd, stepWork, InteractionLocality::NonLocal, enbvClearFYes,
-                             step, nrnb, wcycle);
-                wallcycle_stop(wcycle, ewcFORCE);
+                wallcycle_start_nocount(wcycle, WallCycleCounter::Force);
+                do_nb_verlet(
+                        fr, ic, enerd, stepWork, InteractionLocality::NonLocal, enbvClearFYes, step, nrnb, wcycle);
+                wallcycle_stop(wcycle, WallCycleCounter::Force);
             }
 
             if (stepWork.useGpuFBufferOps)
@@ -1878,8 +2063,10 @@ void do_force(FILE*                               fplog,
     if (combineMtsForcesBeforeHaloExchange)
     {
         const int numAtoms = havePPDomainDecomposition(cr) ? dd_numAtomsZones(*cr->dd) : mdatoms->homenr;
-        combineMtsForces(numAtoms, force.unpaddedArrayRef(), forceView->forceMtsCombined(),
-                         inputrec->mtsLevels[1].stepFactor);
+        combineMtsForces(numAtoms,
+                         force.unpaddedArrayRef(),
+                         forceView->forceMtsCombined(),
+                         inputrec.mtsLevels[1].stepFactor);
     }
 
     if (havePPDomainDecomposition(cr))
@@ -1896,12 +2083,15 @@ void do_force(FILE*                               fplog,
 
             if (stepWork.useGpuFHalo)
             {
-                if (domainWork.haveCpuLocalForceWork)
+                // If there exist CPU forces, data from halo exchange should accumulate into these
+                bool accumulateForces = domainWork.haveCpuLocalForceWork;
+                if (!accumulateForces)
                 {
-                    stateGpu->copyForcesToGpu(forceOutMtsLevel0.forceWithShiftForces().force(),
-                                              AtomLocality::Local);
+                    // Force halo exchange will set a subset of local atoms with remote non-local data
+                    // First clear local portion of force array, so that untouched atoms are zero
+                    stateGpu->clearForcesOnGpu(AtomLocality::Local);
                 }
-                communicateGpuHaloForces(*cr, domainWork.haveCpuLocalForceWork);
+                communicateGpuHaloForces(*cr, accumulateForces);
             }
             else
             {
@@ -1931,14 +2121,24 @@ void do_force(FILE*                               fplog,
                              && !DOMAINDECOMP(cr) && !stepWork.useGpuFBufferOps);
     if (alternateGpuWait)
     {
-        alternatePmeNbGpuWaitReduce(fr->nbv.get(), fr->pmedata, forceOutNonbonded,
-                                    forceOutMtsLevel1, enerd, lambda[efptCOUL], stepWork, wcycle);
+        alternatePmeNbGpuWaitReduce(fr->nbv.get(),
+                                    fr->pmedata,
+                                    forceOutNonbonded,
+                                    forceOutMtsLevel1,
+                                    enerd,
+                                    lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)],
+                                    stepWork,
+                                    wcycle);
     }
 
     if (!alternateGpuWait && useGpuPmeOnThisRank)
     {
-        pme_gpu_wait_and_reduce(fr->pmedata, stepWork, wcycle,
-                                &forceOutMtsLevel1->forceWithVirial(), enerd, lambda[efptCOUL]);
+        pme_gpu_wait_and_reduce(fr->pmedata,
+                                stepWork,
+                                wcycle,
+                                &forceOutMtsLevel1->forceWithVirial(),
+                                enerd,
+                                lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Coul)]);
     }
 
     /* Wait for local GPU NB outputs on the non-alternating wait path */
@@ -1951,9 +2151,13 @@ void do_force(FILE*                               fplog,
          */
         const float gpuWaitApiOverheadMargin = 2e6F; /* cycles */
         const float waitCycles               = Nbnxm::gpu_wait_finish_task(
-                nbv->gpu_nbv, stepWork, AtomLocality::Local, enerd->grpp.ener[egLJSR].data(),
-                enerd->grpp.ener[egCOULSR].data(),
-                forceOutNonbonded->forceWithShiftForces().shiftForces(), wcycle);
+                nbv->gpu_nbv,
+                stepWork,
+                AtomLocality::Local,
+                enerd->grpp.energyGroupPairTerms[NonBondedEnergyTerms::LJSR].data(),
+                enerd->grpp.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR].data(),
+                forceOutNonbonded->forceWithShiftForces().shiftForces(),
+                wcycle);
 
         if (ddBalanceRegionHandler.useBalancingRegion())
         {
@@ -1976,10 +2180,17 @@ void do_force(FILE*                               fplog,
     {
         // NOTE: emulation kernel is not included in the balancing region,
         // but emulation mode does not target performance anyway
-        wallcycle_start_nocount(wcycle, ewcFORCE);
-        do_nb_verlet(fr, ic, enerd, stepWork, InteractionLocality::Local,
-                     DOMAINDECOMP(cr) ? enbvClearFNo : enbvClearFYes, step, nrnb, wcycle);
-        wallcycle_stop(wcycle, ewcFORCE);
+        wallcycle_start_nocount(wcycle, WallCycleCounter::Force);
+        do_nb_verlet(fr,
+                     ic,
+                     enerd,
+                     stepWork,
+                     InteractionLocality::Local,
+                     DOMAINDECOMP(cr) ? enbvClearFNo : enbvClearFYes,
+                     step,
+                     nrnb,
+                     wcycle);
+        wallcycle_stop(wcycle, WallCycleCounter::Force);
     }
 
     // If on GPU PME-PP comms path, receive forces from PME before GPU buffer ops
@@ -1990,9 +2201,13 @@ void do_force(FILE*                               fplog,
         /* In case of node-splitting, the PP nodes receive the long-range
          * forces, virial and energy from the PME nodes here.
          */
-        pme_receive_force_ener(fr, cr, &forceOutMtsLevel1->forceWithVirial(), enerd,
+        pme_receive_force_ener(fr,
+                               cr,
+                               &forceOutMtsLevel1->forceWithVirial(),
+                               enerd,
                                simulationWork.useGpuPmePpCommunication,
-                               stepWork.useGpuPmeFReduction, wcycle);
+                               stepWork.useGpuPmeFReduction,
+                               wcycle);
     }
 
 
@@ -2057,8 +2272,8 @@ void do_force(FILE*                               fplog,
         }
     }
 
-    launchGpuEndOfStepTasks(nbv, fr->gpuBonded, fr->pmedata, enerd, *runScheduleWork,
-                            useGpuPmeOnThisRank, step, wcycle);
+    launchGpuEndOfStepTasks(
+            nbv, fr->gpuBonded, fr->pmedata, enerd, *runScheduleWork, useGpuPmeOnThisRank, step, wcycle);
 
     if (DOMAINDECOMP(cr))
     {
@@ -2069,13 +2284,13 @@ void do_force(FILE*                               fplog,
                                         && combineMtsForcesBeforeHaloExchange);
     if (stepWork.computeForces)
     {
-        postProcessForceWithShiftForces(nrnb, wcycle, box, x.unpaddedArrayRef(), &forceOutMtsLevel0,
-                                        vir_force, *mdatoms, *fr, vsite, stepWork);
+        postProcessForceWithShiftForces(
+                nrnb, wcycle, box, x.unpaddedArrayRef(), &forceOutMtsLevel0, vir_force, *mdatoms, *fr, vsite, stepWork);
 
         if (fr->useMts && stepWork.computeSlowForces && !haveCombinedMtsForces)
         {
-            postProcessForceWithShiftForces(nrnb, wcycle, box, x.unpaddedArrayRef(), forceOutMtsLevel1,
-                                            vir_force, *mdatoms, *fr, vsite, stepWork);
+            postProcessForceWithShiftForces(
+                    nrnb, wcycle, box, x.unpaddedArrayRef(), forceOutMtsLevel1, vir_force, *mdatoms, *fr, vsite, stepWork);
         }
     }
 
@@ -2086,8 +2301,13 @@ void do_force(FILE*                               fplog,
         /* In case of node-splitting, the PP nodes receive the long-range
          * forces, virial and energy from the PME nodes here.
          */
-        pme_receive_force_ener(fr, cr, &forceOutMtsLevel1->forceWithVirial(), enerd,
-                               simulationWork.useGpuPmePpCommunication, false, wcycle);
+        pme_receive_force_ener(fr,
+                               cr,
+                               &forceOutMtsLevel1->forceWithVirial(),
+                               enerd,
+                               simulationWork.useGpuPmePpCommunication,
+                               false,
+                               wcycle);
     }
 
     if (stepWork.computeForces)
@@ -2097,27 +2317,29 @@ void do_force(FILE*                               fplog,
          * otherwise we have to post-process two outputs and then combine them.
          */
         ForceOutputs& forceOutCombined = (haveCombinedMtsForces ? forceOutMts.value() : forceOutMtsLevel0);
-        postProcessForces(cr, step, nrnb, wcycle, box, x.unpaddedArrayRef(), &forceOutCombined,
-                          vir_force, mdatoms, fr, vsite, stepWork);
+        postProcessForces(
+                cr, step, nrnb, wcycle, box, x.unpaddedArrayRef(), &forceOutCombined, vir_force, mdatoms, fr, vsite, stepWork);
 
         if (fr->useMts && stepWork.computeSlowForces && !haveCombinedMtsForces)
         {
-            postProcessForces(cr, step, nrnb, wcycle, box, x.unpaddedArrayRef(), forceOutMtsLevel1,
-                              vir_force, mdatoms, fr, vsite, stepWork);
+            postProcessForces(
+                    cr, step, nrnb, wcycle, box, x.unpaddedArrayRef(), forceOutMtsLevel1, vir_force, mdatoms, fr, vsite, stepWork);
 
-            combineMtsForces(mdatoms->homenr, force.unpaddedArrayRef(),
-                             forceView->forceMtsCombined(), inputrec->mtsLevels[1].stepFactor);
+            combineMtsForces(mdatoms->homenr,
+                             force.unpaddedArrayRef(),
+                             forceView->forceMtsCombined(),
+                             inputrec.mtsLevels[1].stepFactor);
         }
     }
 
     if (stepWork.computeEnergy)
     {
         /* Compute the final potential energy terms */
-        accumulatePotentialEnergies(enerd, lambda, inputrec->fepvals);
+        accumulatePotentialEnergies(enerd, lambda, inputrec.fepvals.get());
 
-        if (!EI_TPI(inputrec->eI))
+        if (!EI_TPI(inputrec.eI))
         {
-            checkPotentialEnergyValidity(step, *enerd, *inputrec);
+            checkPotentialEnergyValidity(step, *enerd, inputrec);
         }
     }
 
index 15f44ccbf4cfadfec6671f09190c109e2c05e9d9..8199dcb450f6b547a8823676a37d8cb36c62e072 100644 (file)
@@ -85,7 +85,9 @@ gmx::ArrayRef<real> SimulationSignaller::getCommunicationBuffer()
 {
     if (doIntraSim_)
     {
-        std::transform(std::begin(*signals_), std::end(*signals_), std::begin(mpiBuffer_),
+        std::transform(std::begin(*signals_),
+                       std::end(*signals_),
+                       std::begin(mpiBuffer_),
                        [](const SimulationSignals::value_type& s) { return s.sig; });
 
         return mpiBuffer_;
index a970c3fc0a71a7ba54ef9d67deb8d00f391f9cb2..a90ebe958d976a550c859189812073d89670e874 100644 (file)
@@ -94,8 +94,14 @@ static int mk_grey(gmx::ArrayRef<egCol> edgeColor, const t_graph* g, int* AtomI,
             range_check(ai + g0, 0, maxsid);
             if (sid[aj + g0].sid != -1)
             {
-                gmx_fatal(FARGS, "sid[%d]=%d, sid[%d]=%d, file %s, line %d", ai, sid[ai + g0].sid,
-                          aj, sid[aj + g0].sid, __FILE__, __LINE__);
+                gmx_fatal(FARGS,
+                          "sid[%d]=%d, sid[%d]=%d, file %s, line %d",
+                          ai,
+                          sid[ai + g0].sid,
+                          aj,
+                          sid[aj + g0].sid,
+                          __FILE__,
+                          __LINE__);
             }
             else
             {
index 7c41c480c83ac85b39bd97b41e9e0d6406eee185..7bfdc6eebed13b327e9af3436c84b1f1320c24b1 100644 (file)
@@ -49,7 +49,6 @@
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
-#include "gromacs/mdlib/constr.h"
 #include "gromacs/mdlib/md_support.h"
 #include "gromacs/mdlib/rbin.h"
 #include "gromacs/mdlib/tgroup.h"
@@ -141,46 +140,38 @@ static int filter_enerdterm(const real* afrom, gmx_bool bToBuffer, real* ato, gm
     return to;
 }
 
-void global_stat(const gmx_global_stat*  gs,
-                 const t_commrec*        cr,
-                 gmx_enerdata_t*         enerd,
-                 tensor                  fvir,
-                 tensor                  svir,
-                 const t_inputrec*       inputrec,
-                 gmx_ekindata_t*         ekind,
-                 const gmx::Constraints* constr,
-                 t_vcm*                  vcm,
-                 int                     nsig,
-                 real*                   sig,
-                 int*                    totalNumberOfBondedInteractions,
-                 bool                    bSumEkinhOld,
-                 int                     flags)
+void global_stat(const gmx_global_stat& gs,
+                 const t_commrec*       cr,
+                 gmx_enerdata_t*        enerd,
+                 tensor                 fvir,
+                 tensor                 svir,
+                 const t_inputrec&      inputrec,
+                 gmx_ekindata_t*        ekind,
+                 gmx::ArrayRef<real>    constraintsRmsdData,
+                 t_vcm*                 vcm,
+                 gmx::ArrayRef<real>    sig,
+                 bool                   bSumEkinhOld,
+                 int                    flags)
 /* instead of current system, gmx_booleans for summing virial, kinetic energy, and other terms */
 {
-    t_bin* rb;
-    int *  itc0, *itc1;
-    int    ie = 0, ifv = 0, isv = 0, irmsd = 0;
+    int ie = 0, ifv = 0, isv = 0, irmsd = 0;
     int idedl = 0, idedlo = 0, idvdll = 0, idvdlnl = 0, iepl = 0, icm = 0, imass = 0, ica = 0, inb = 0;
-    int      isig = -1;
-    int      icj = -1, ici = -1, icx = -1;
-    int      inn[egNR];
-    real     copyenerd[F_NRE];
-    int      nener, j;
-    double   nb;
-    gmx_bool bVV, bTemp, bEner, bPres, bConstrVir, bEkinAveVel, bReadEkin;
-    bool checkNumberOfBondedInteractions = (flags & CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS) != 0;
+    int isig = -1;
+    int icj = -1, ici = -1, icx = -1;
 
-    bVV         = EI_VV(inputrec->eI);
-    bTemp       = ((flags & CGLO_TEMPERATURE) != 0);
-    bEner       = ((flags & CGLO_ENERGY) != 0);
-    bPres       = ((flags & CGLO_PRESSURE) != 0);
-    bConstrVir  = ((flags & CGLO_CONSTRAINT) != 0);
-    bEkinAveVel = (inputrec->eI == eiVV || (inputrec->eI == eiVVAK && bPres));
-    bReadEkin   = ((flags & CGLO_READEKIN) != 0);
+    bool checkNumberOfBondedInteractions = (flags & CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS) != 0;
+    bool bVV                             = EI_VV(inputrec.eI);
+    bool bTemp                           = ((flags & CGLO_TEMPERATURE) != 0);
+    bool bEner                           = ((flags & CGLO_ENERGY) != 0);
+    bool bPres                           = ((flags & CGLO_PRESSURE) != 0);
+    bool bConstrVir                      = ((flags & CGLO_CONSTRAINT) != 0);
+    bool bEkinAveVel                     = (inputrec.eI == IntegrationAlgorithm::VV
+                        || (inputrec.eI == IntegrationAlgorithm::VVAK && bPres));
+    bool bReadEkin                       = ((flags & CGLO_READEKIN) != 0);
 
-    rb   = gs->rb;
-    itc0 = gs->itc0;
-    itc1 = gs->itc1;
+    t_bin* rb   = gs.rb;
+    int*   itc0 = gs.itc0;
+    int*   itc1 = gs.itc1;
 
 
     reset_bin(rb);
@@ -193,7 +184,8 @@ void global_stat(const gmx_global_stat*  gs,
        communicated and summed when they need to be, to avoid repeating
        the sums and overcounting. */
 
-    nener = filter_enerdterm(enerd->term, TRUE, copyenerd, bTemp, bPres, bEner);
+    std::array<real, F_NRE> copyenerd;
+    int nener = filter_enerdterm(enerd->term.data(), TRUE, copyenerd.data(), bTemp, bPres, bEner);
 
     /* First, the data that needs to be communicated with velocity verlet every time
        This is just the constraint virial.*/
@@ -207,7 +199,7 @@ void global_stat(const gmx_global_stat*  gs,
     {
         if (ekind)
         {
-            for (j = 0; (j < inputrec->opts.ngtc); j++)
+            for (int j = 0; (j < inputrec.opts.ngtc); j++)
             {
                 if (bSumEkinhOld)
                 {
@@ -240,30 +232,26 @@ void global_stat(const gmx_global_stat*  gs,
         ifv = add_binr(rb, DIM * DIM, fvir[0]);
     }
 
-    gmx::ArrayRef<real> rmsdData;
+    gmx::EnumerationArray<NonBondedEnergyTerms, int> inn;
     if (bEner)
     {
-        ie = add_binr(rb, nener, copyenerd);
-        if (constr)
+        ie = add_binr(rb, nener, copyenerd.data());
+        if (!constraintsRmsdData.empty())
         {
-            rmsdData = constr->rmsdData();
-            if (!rmsdData.empty())
-            {
-                irmsd = add_binr(rb, 2, rmsdData.data());
-            }
+            irmsd = add_binr(rb, 2, constraintsRmsdData.data());
         }
-
-        for (j = 0; (j < egNR); j++)
+        for (auto key : gmx::keysOf(inn))
         {
-            inn[j] = add_binr(rb, enerd->grpp.nener, enerd->grpp.ener[j].data());
+            inn[key] = add_binr(rb, enerd->grpp.nener, enerd->grpp.energyGroupPairTerms[key].data());
         }
-        if (inputrec->efep != efepNO)
+        if (inputrec.efep != FreeEnergyPerturbationType::No)
         {
-            idvdll  = add_bind(rb, efptNR, enerd->dvdl_lin);
-            idvdlnl = add_bind(rb, efptNR, enerd->dvdl_nonlin);
+            idvdll  = add_bind(rb, enerd->dvdl_lin);
+            idvdlnl = add_bind(rb, enerd->dvdl_nonlin);
             if (enerd->foreignLambdaTerms.numLambdas() > 0)
             {
-                iepl = add_bind(rb, enerd->foreignLambdaTerms.energies().size(),
+                iepl = add_bind(rb,
+                                enerd->foreignLambdaTerms.energies().size(),
                                 enerd->foreignLambdaTerms.energies().data());
             }
         }
@@ -273,7 +261,7 @@ void global_stat(const gmx_global_stat*  gs,
     {
         icm   = add_binr(rb, DIM * vcm->nr, vcm->group_p[0]);
         imass = add_binr(rb, vcm->nr, vcm->group_mass.data());
-        if (vcm->mode == ecmANGULAR)
+        if (vcm->mode == ComRemovalAlgorithm::Angular)
         {
             icj = add_binr(rb, DIM * vcm->nr, vcm->group_j[0]);
             icx = add_binr(rb, DIM * vcm->nr, vcm->group_x[0]);
@@ -281,21 +269,20 @@ void global_stat(const gmx_global_stat*  gs,
         }
     }
 
+    double nb;
     if (checkNumberOfBondedInteractions)
     {
-        nb  = cr->dd->nbonded_local;
+        GMX_RELEASE_ASSERT(DOMAINDECOMP(cr),
+                           "No need to check number of bonded interactions when not using domain "
+                           "decomposition");
+        nb  = numBondedInteractions(*cr->dd);
         inb = add_bind(rb, 1, &nb);
     }
-    if (nsig > 0)
+    if (!sig.empty())
     {
-        isig = add_binr(rb, nsig, sig);
+        isig = add_binr(rb, sig);
     }
 
-    /* Global sum it all */
-    if (debug)
-    {
-        fprintf(debug, "Summing %d energies\n", rb->maxreal);
-    }
     sum_bin(rb, cr);
 
     /* Extract all the data locally */
@@ -310,7 +297,7 @@ void global_stat(const gmx_global_stat*  gs,
     {
         if (ekind)
         {
-            for (j = 0; (j < inputrec->opts.ngtc); j++)
+            for (int j = 0; (j < inputrec.opts.ngtc); j++)
             {
                 if (bSumEkinhOld)
                 {
@@ -343,35 +330,36 @@ void global_stat(const gmx_global_stat*  gs,
 
     if (bEner)
     {
-        extract_binr(rb, ie, nener, copyenerd);
-        if (!rmsdData.empty())
+        extract_binr(rb, ie, nener, copyenerd.data());
+        if (!constraintsRmsdData.empty())
         {
-            extract_binr(rb, irmsd, rmsdData);
+            extract_binr(rb, irmsd, constraintsRmsdData);
         }
-
-        for (j = 0; (j < egNR); j++)
+        for (auto key : gmx::keysOf(inn))
         {
-            extract_binr(rb, inn[j], enerd->grpp.nener, enerd->grpp.ener[j].data());
+            extract_binr(rb, inn[key], enerd->grpp.nener, enerd->grpp.energyGroupPairTerms[key].data());
         }
-        if (inputrec->efep != efepNO)
+        if (inputrec.efep != FreeEnergyPerturbationType::No)
         {
-            extract_bind(rb, idvdll, efptNR, enerd->dvdl_lin);
-            extract_bind(rb, idvdlnl, efptNR, enerd->dvdl_nonlin);
+            extract_bind(rb, idvdll, enerd->dvdl_lin);
+            extract_bind(rb, idvdlnl, enerd->dvdl_nonlin);
             if (enerd->foreignLambdaTerms.numLambdas() > 0)
             {
-                extract_bind(rb, iepl, enerd->foreignLambdaTerms.energies().size(),
+                extract_bind(rb,
+                             iepl,
+                             enerd->foreignLambdaTerms.energies().size(),
                              enerd->foreignLambdaTerms.energies().data());
             }
         }
 
-        filter_enerdterm(copyenerd, FALSE, enerd->term, bTemp, bPres, bEner);
+        filter_enerdterm(copyenerd.data(), FALSE, enerd->term.data(), bTemp, bPres, bEner);
     }
 
     if (vcm)
     {
         extract_binr(rb, icm, DIM * vcm->nr, vcm->group_p[0]);
         extract_binr(rb, imass, vcm->nr, vcm->group_mass.data());
-        if (vcm->mode == ecmANGULAR)
+        if (vcm->mode == ComRemovalAlgorithm::Angular)
         {
             extract_binr(rb, icj, DIM * vcm->nr, vcm->group_j[0]);
             extract_binr(rb, icx, DIM * vcm->nr, vcm->group_x[0]);
@@ -382,11 +370,14 @@ void global_stat(const gmx_global_stat*  gs,
     if (checkNumberOfBondedInteractions)
     {
         extract_bind(rb, inb, 1, &nb);
-        *totalNumberOfBondedInteractions = gmx::roundToInt(nb);
+        GMX_RELEASE_ASSERT(DOMAINDECOMP(cr),
+                           "No need to check number of bonded interactions when not using domain "
+                           "decomposition");
+        setNumberOfBondedInteractionsOverAllDomains(*cr->dd, gmx::roundToInt(nb));
     }
 
-    if (nsig > 0)
+    if (!sig.empty())
     {
-        extract_binr(rb, isig, nsig, sig);
+        extract_binr(rb, isig, sig);
     }
 }
index a26520004f4c35b74ccfe646f49f2cb18d0eb72f..8001bf0d39605ea27d69fff2864f3f4bfe075441 100644 (file)
@@ -43,7 +43,7 @@
 
 #include "gromacs/math/vectypes.h"
 
-struct gmx_ekindata_t;
+class gmx_ekindata_t;
 struct gmx_enerdata_t;
 struct t_vcm;
 struct t_inputrec;
@@ -51,8 +51,10 @@ struct t_commrec;
 
 namespace gmx
 {
+template<typename T>
+class ArrayRef;
 class Constraints;
-}
+} // namespace gmx
 
 typedef struct gmx_global_stat* gmx_global_stat_t;
 
@@ -61,20 +63,18 @@ gmx_global_stat_t global_stat_init(const t_inputrec* ir);
 void global_stat_destroy(gmx_global_stat_t gs);
 
 /*! \brief All-reduce energy-like quantities over cr->mpi_comm_mysim  */
-void global_stat(const gmx_global_stat*  gs,
-                 const t_commrec*        cr,
-                 gmx_enerdata_t*         enerd,
-                 tensor                  fvir,
-                 tensor                  svir,
-                 const t_inputrec*       inputrec,
-                 gmx_ekindata_t*         ekind,
-                 const gmx::Constraints* constr,
-                 t_vcm*                  vcm,
-                 int                     nsig,
-                 real*                   sig,
-                 int*                    totalNumberOfBondedInteractions,
-                 bool                    bSumEkinhOld,
-                 int                     flags);
+void global_stat(const gmx_global_stat& gs,
+                 const t_commrec*       cr,
+                 gmx_enerdata_t*        enerd,
+                 tensor                 fvir,
+                 tensor                 svir,
+                 const t_inputrec&      inputrec,
+                 gmx_ekindata_t*        ekind,
+                 gmx::ArrayRef<real>    constraintsRmsdData,
+                 t_vcm*                 vcm,
+                 gmx::ArrayRef<real>    sig,
+                 bool                   bSumEkinhOld,
+                 int                    flags);
 
 /*! \brief Returns TRUE if io should be done */
 inline bool do_per_step(int64_t step, int64_t nstep)
index 040fd5fb1858a6325a2fa995016d61c90c53fe52..11a26a8d930784cd6ea8e03564be94a7b7481a5b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ StopHandler::StopHandler(compat::not_null<SimulationSignal*>      signal,
 }
 
 StopConditionSignal::StopConditionSignal(int nstList, bool makeBinaryReproducibleSimulation, int nstSignalComm) :
-    handledStopCondition_(gmx_stop_cond_none),
+    handledStopCondition_(StopCondition::None),
     makeBinaryReproducibleSimulation_(makeBinaryReproducibleSimulation),
     nstSignalComm_(nstSignalComm),
     nstList_(nstList)
@@ -79,15 +79,15 @@ StopSignal StopConditionSignal::getSignal(FILE* fplog)
     StopSignal signal = StopSignal::noSignal;
 
     /* Check whether everything is still alright */
-    if (static_cast<int>(gmx_get_stop_condition()) > handledStopCondition_)
+    if (gmx_get_stop_condition() > handledStopCondition_)
     {
         int nsteps_stop = -1;
 
         /* this just makes signals[].sig compatible with the hack
            of sending signals around by MPI_Reduce together with
            other floats */
-        if ((gmx_get_stop_condition() == gmx_stop_cond_next_ns)
-            || (makeBinaryReproducibleSimulation_ && gmx_get_stop_condition() == gmx_stop_cond_next))
+        if ((gmx_get_stop_condition() == StopCondition::NextNS)
+            || (makeBinaryReproducibleSimulation_ && gmx_get_stop_condition() == StopCondition::Next))
         {
             /* We need at least two global communication steps to pass
              * around the signal. We stop at a pair-list creation step
@@ -96,7 +96,7 @@ StopSignal StopConditionSignal::getSignal(FILE* fplog)
             signal      = StopSignal::stopAtNextNSStep;
             nsteps_stop = std::max(nstList_, 2 * nstSignalComm_);
         }
-        else if (gmx_get_stop_condition() == gmx_stop_cond_next)
+        else if (gmx_get_stop_condition() == StopCondition::Next)
         {
             /* Stop directly after the next global communication step.
              * This breaks exact continuation.
@@ -106,14 +106,18 @@ StopSignal StopConditionSignal::getSignal(FILE* fplog)
         }
         if (fplog)
         {
-            fprintf(fplog, "\n\nReceived the %s signal, stopping within %d steps\n\n",
-                    gmx_get_signal_name(), nsteps_stop);
+            fprintf(fplog,
+                    "\n\nReceived the %s signal, stopping within %d steps\n\n",
+                    gmx_get_signal_name(),
+                    nsteps_stop);
             fflush(fplog);
         }
-        fprintf(stderr, "\n\nReceived the %s signal, stopping within %d steps\n\n",
-                gmx_get_signal_name(), nsteps_stop);
+        fprintf(stderr,
+                "\n\nReceived the %s signal, stopping within %d steps\n\n",
+                gmx_get_signal_name(),
+                nsteps_stop);
         fflush(stderr);
-        handledStopCondition_ = static_cast<int>(gmx_get_stop_condition());
+        handledStopCondition_ = gmx_get_stop_condition();
     }
 
     return signal;
@@ -147,12 +151,16 @@ StopSignal StopConditionTime::getSignal(bool bNS, int64_t step, FILE* fplog, gmx
             fprintf(fplog,
                     "\nStep %s: Run time exceeded %.3f hours, "
                     "will terminate the run within %d steps\n",
-                    gmx_step_str(step, sbuf), maximumHoursToRun_ * 0.99, nsteps_stop);
+                    gmx_step_str(step, sbuf),
+                    maximumHoursToRun_ * 0.99,
+                    nsteps_stop);
         }
         fprintf(stderr,
                 "\nStep %s: Run time exceeded %.3f hours, "
                 "will terminate the run within %d steps\n",
-                gmx_step_str(step, sbuf), maximumHoursToRun_ * 0.99, nsteps_stop);
+                gmx_step_str(step, sbuf),
+                maximumHoursToRun_ * 0.99,
+                nsteps_stop);
         signalSent_ = true;
         return StopSignal::stopAtNextNSStep;
     }
@@ -196,8 +204,8 @@ std::unique_ptr<StopHandler> StopHandlerBuilder::getStopHandlerMD(compat::not_nu
         });
     }
 
-    return std::make_unique<StopHandler>(signal, simulationShareState, stopConditions_,
-                                         neverUpdateNeighborList);
+    return std::make_unique<StopHandler>(
+            signal, simulationShareState, stopConditions_, neverUpdateNeighborList);
 }
 
 } // namespace gmx
index d156b1c6d862a63a4e8de9207b2b2ce0c9750778..bcad296b73b0a5e7399c2545f42d2fe0b1b3a7b9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +84,7 @@ namespace gmx
  *   * stop at the next neighbor-searching step
  *   * stop as soon as signal is received
  */
-enum class StopSignal
+enum class StopSignal : int
 {
     noSignal         = 0,
     stopAtNextNSStep = 1,
@@ -151,7 +151,7 @@ public:
      */
     void setSignal() const
     {
-        for (auto& condition : stopConditions_)
+        for (const auto& condition : stopConditions_)
         {
             const StopSignal sig = condition();
             if (sig != StopSignal::noSignal)
@@ -207,10 +207,10 @@ public:
     StopSignal getSignal(FILE* fplog);
 
 private:
-    int        handledStopCondition_;
-    const bool makeBinaryReproducibleSimulation_;
-    const int  nstSignalComm_;
-    const int  nstList_;
+    StopCondition handledStopCondition_;
+    const bool    makeBinaryReproducibleSimulation_;
+    const int     nstSignalComm_;
+    const int     nstList_;
 };
 
 /*! \libinternal
diff --git a/src/gromacs/mdlib/tests/.clang-tidy b/src/gromacs/mdlib/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 96e4760622302a47ffec0d8ba8f5617da0387204..e50f85ab4f847cccf15a8f7b2ce03176dfdf5adb 100644 (file)
@@ -35,6 +35,7 @@
 gmx_add_unit_test(MdlibUnitTest mdlib-test HARDWARE_DETECTION
     CPP_SOURCE_FILES
         calc_verletbuf.cpp
+       calcvir.cpp
         constr.cpp
         constrtestdata.cpp
         constrtestrunners.cpp
diff --git a/src/gromacs/mdlib/tests/calcvir.cpp b/src/gromacs/mdlib/tests/calcvir.cpp
new file mode 100644 (file)
index 0000000..af09438
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 virial calculation.
+ *
+ * \author Joe Jordan <ejjordan@kth.se>
+ */
+#include "gmxpre.h"
+
+#include "gromacs/mdlib/calcvir.h"
+
+#include <gtest/gtest.h>
+
+#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
+
+namespace gmx
+{
+namespace test
+{
+namespace
+{
+
+
+class CalcvirTest : public ::testing::Test
+{
+public:
+    TestReferenceData      refData_;
+    TestReferenceChecker   checker_;
+    std::vector<gmx::RVec> coordinates_;
+    std::vector<gmx::RVec> forces_;
+    int                    numVirialAtoms_;
+    tensor                 virial_{ { 0 } };
+    FloatingPointTolerance tolerances =
+            FloatingPointTolerance(1e-16, 1.0e-16, 1e-16, 1.0e-7, 1000, 100, false);
+
+    CalcvirTest() :
+        checker_(refData_.rootChecker()),
+        coordinates_{ { 1, 2, 3 },
+                      {
+                              4,
+                              5,
+                              6,
+                      },
+                      { 7, 8, 9 },
+                      { 1, 5, 9 } },
+        forces_{ { 0.9, 0.1, 0.3 }, { 0.4, 0.7, 0.2 }, { 0.5, 1, 0.6 }, { 0.9, 0.7, 0.6 } },
+        numVirialAtoms_(coordinates_.size())
+    {
+        checker_.setDefaultTolerance(tolerances);
+    }
+
+private:
+};
+
+TEST_F(CalcvirTest, CanCalculateVirialAllAtomsInBox)
+{
+    calc_vir(numVirialAtoms_, as_rvec_array(coordinates_.data()), as_rvec_array(forces_.data()), virial_, false, nullptr);
+
+    checker_.checkVector(virial_[0], "Virial x");
+    checker_.checkVector(virial_[1], "Virial y");
+    checker_.checkVector(virial_[2], "Virial z");
+}
+
+TEST_F(CalcvirTest, CanCalculateVirialAllAtomsInBoxScrew)
+{
+
+    const matrix box = { { 10, 0, 0 }, { 0, 12, 0 }, { 0, 0, 14 } };
+    calc_vir(numVirialAtoms_, as_rvec_array(coordinates_.data()), as_rvec_array(forces_.data()), virial_, true, box);
+
+    checker_.checkVector(virial_[0], "Virial x");
+    checker_.checkVector(virial_[1], "Virial y");
+    checker_.checkVector(virial_[2], "Virial z");
+}
+
+TEST_F(CalcvirTest, CanCalculateVirialAtomsOutOfBoxScrewX)
+{
+
+    const matrix box = { { 5, 0, 0 }, { 0, 10, 0 }, { 0, 0, 12 } };
+    calc_vir(numVirialAtoms_, as_rvec_array(coordinates_.data()), as_rvec_array(forces_.data()), virial_, true, box);
+
+    checker_.checkVector(virial_[0], "Virial x");
+    checker_.checkVector(virial_[1], "Virial y");
+    checker_.checkVector(virial_[2], "Virial z");
+}
+
+TEST_F(CalcvirTest, CanCalculateVirialAtomsOutOfBoxScrewY)
+{
+
+    const matrix box = { { 10, 0, 0 }, { 0, 5, 0 }, { 0, 0, 12 } };
+    calc_vir(numVirialAtoms_, as_rvec_array(coordinates_.data()), as_rvec_array(forces_.data()), virial_, true, box);
+
+    checker_.checkVector(virial_[0], "Virial x");
+    checker_.checkVector(virial_[1], "Virial y");
+    checker_.checkVector(virial_[2], "Virial z");
+}
+
+TEST_F(CalcvirTest, CanCalculateVirialAtomsOutOfBoxScrewZ)
+{
+
+    const matrix box = { { 10, 0, 0 }, { 0, 12, 0 }, { 0, 0, 5 } };
+    calc_vir(numVirialAtoms_, as_rvec_array(coordinates_.data()), as_rvec_array(forces_.data()), virial_, true, box);
+
+    checker_.checkVector(virial_[0], "Virial x");
+    checker_.checkVector(virial_[1], "Virial y");
+    checker_.checkVector(virial_[2], "Virial z");
+}
+
+TEST_F(CalcvirTest, CanCalculateVirialAtomsOutOfBoxScrewXYZ)
+{
+
+    const matrix box = { { 4, 0, 0 }, { 0, 5, 0 }, { 0, 0, 6 } };
+    calc_vir(numVirialAtoms_, as_rvec_array(coordinates_.data()), as_rvec_array(forces_.data()), virial_, true, box);
+
+    checker_.checkVector(virial_[0], "Virial x");
+    checker_.checkVector(virial_[1], "Virial y");
+    checker_.checkVector(virial_[2], "Virial z");
+}
+
+} // namespace
+} // namespace test
+} // namespace gmx
index 75b691ef07813703da3cc1bdb0e9febe4a82a10c..2331b1f6492b698a98a0ad90f3e2e147bd7d5521 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -73,6 +73,263 @@ namespace test
 namespace
 {
 
+// Define the set of PBCs to run the test for
+const std::vector<t_pbc> c_pbcs = [] {
+    std::vector<t_pbc> pbcs;
+    t_pbc              pbc;
+
+    // Infinitely small box
+    matrix boxNone = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } };
+    set_pbc(&pbc, PbcType::No, boxNone);
+    pbcs.emplace_back(pbc);
+
+    // Rectangular box
+    matrix boxXyz = { { 10.0, 0.0, 0.0 }, { 0.0, 20.0, 0.0 }, { 0.0, 0.0, 15.0 } };
+    set_pbc(&pbc, PbcType::Xyz, boxXyz);
+    pbcs.emplace_back(pbc);
+
+    return pbcs;
+}();
+
+
+struct ConstraintsTestSystem
+{
+    //! Human-friendly name of the system.
+    std::string title;
+    //! Number of atoms in the system.
+    int numAtoms;
+    //! Atom masses. Size of this vector should be equal to numAtoms.
+    std::vector<real> masses;
+    /*! \brief List of constraints, organized in triples of integers.
+     *
+     * First integer is the index of type for a constraint, second
+     * and third are the indices of constrained atoms. The types
+     * of constraints should be sequential but not necessarily
+     * start from zero (which is the way they normally are in
+     * GROMACS).
+     */
+    std::vector<int> constraints;
+    /*! \brief Target values for bond lengths for bonds of each type.
+     *
+     * The size of this vector should be equal to the total number of
+     * unique types in constraints vector.
+     */
+    std::vector<real> constraintsR0;
+    //! Coordinates before integration step.
+    std::vector<RVec> x;
+    //! Coordinates after integration step, but before constraining.
+    std::vector<RVec> xPrime;
+    //! Velocities before constraining.
+    std::vector<RVec> v;
+
+    //! Reference values for scaled virial tensor.
+    tensor virialScaledRef;
+
+    //! Target tolerance for SHAKE.
+    real shakeTolerance = 0.0001;
+    /*! \brief Use successive over-relaxation method for SHAKE iterations.
+     *
+     * The general formula is:
+     * x_n+1 = (1-omega)*x_n + omega*f(x_n),
+     * where omega = 1 if SOR is off and may be < 1 if SOR is on.
+     */
+    bool shakeUseSOR = false;
+
+    //! Number of iterations used to compute the inverse matrix.
+    int lincsNIter = 1;
+    //! The order for algorithm that adjusts the direction of the bond after constraints are applied.
+    int lincslincsExpansionOrder = 4;
+    //! The threshold value for the change in bond angle. When exceeded the program will issue a warning
+    real lincsWarnAngle = 30.0;
+
+    FloatingPointTolerance lengthTolerance = absoluteTolerance(0.0002);
+    FloatingPointTolerance comTolerance    = absoluteTolerance(0.0001);
+    FloatingPointTolerance virialTolerance = absoluteTolerance(0.0001);
+};
+
+const std::vector<ConstraintsTestSystem> c_constraintsTestSystemList = [] {
+    std::vector<ConstraintsTestSystem> constraintsTestSystemList;
+    {
+        ConstraintsTestSystem constraintsTestSystem;
+
+        constraintsTestSystem.title    = "one constraint (e.g. OH)";
+        constraintsTestSystem.numAtoms = 2;
+
+        constraintsTestSystem.masses        = { 1.0, 12.0 };
+        constraintsTestSystem.constraints   = { 0, 0, 1 };
+        constraintsTestSystem.constraintsR0 = { 0.1 };
+
+        real oneTenthOverSqrtTwo = 0.1_real / std::sqrt(2.0_real);
+
+        constraintsTestSystem.x = { { 0.0, oneTenthOverSqrtTwo, 0.0 }, { oneTenthOverSqrtTwo, 0.0, 0.0 } };
+        constraintsTestSystem.xPrime = { { 0.01, 0.08, 0.01 }, { 0.06, 0.01, -0.01 } };
+        constraintsTestSystem.v      = { { 1.0, 2.0, 3.0 }, { 3.0, 2.0, 1.0 } };
+
+        tensor virialScaledRef = { { -5.58e-04, 5.58e-04, 0.00e+00 },
+                                   { 5.58e-04, -5.58e-04, 0.00e+00 },
+                                   { 0.00e+00, 0.00e+00, 0.00e+00 } };
+
+        memcpy(constraintsTestSystem.virialScaledRef, virialScaledRef, DIM * DIM * sizeof(real));
+
+        constraintsTestSystemList.emplace_back(constraintsTestSystem);
+    }
+    {
+        ConstraintsTestSystem constraintsTestSystem;
+
+        constraintsTestSystem.title         = "two disjoint constraints";
+        constraintsTestSystem.numAtoms      = 4;
+        constraintsTestSystem.masses        = { 0.5, 1.0 / 3.0, 0.25, 1.0 };
+        constraintsTestSystem.constraints   = { 0, 0, 1, 1, 2, 3 };
+        constraintsTestSystem.constraintsR0 = { 2.0, 1.0 };
+
+
+        constraintsTestSystem.x = { { 2.50, -3.10, 15.70 },
+                                    { 0.51, -3.02, 15.55 },
+                                    { -0.50, -3.00, 15.20 },
+                                    { -1.51, -2.95, 15.05 } };
+
+        constraintsTestSystem.xPrime = { { 2.50, -3.10, 15.70 },
+                                         { 0.51, -3.02, 15.55 },
+                                         { -0.50, -3.00, 15.20 },
+                                         { -1.51, -2.95, 15.05 } };
+
+        constraintsTestSystem.v = { { 0.0, 1.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, 0.0 } };
+
+        tensor virialScaledRef = { { 3.3e-03, -1.7e-04, 5.6e-04 },
+                                   { -1.7e-04, 8.9e-06, -2.8e-05 },
+                                   { 5.6e-04, -2.8e-05, 8.9e-05 } };
+
+        memcpy(constraintsTestSystem.virialScaledRef, virialScaledRef, DIM * DIM * sizeof(real));
+
+        constraintsTestSystemList.emplace_back(constraintsTestSystem);
+    }
+    {
+        ConstraintsTestSystem constraintsTestSystem;
+
+        constraintsTestSystem.title         = "three atoms, connected longitudinally (e.g. CH2)";
+        constraintsTestSystem.numAtoms      = 3;
+        constraintsTestSystem.masses        = { 1.0, 12.0, 16.0 };
+        constraintsTestSystem.constraints   = { 0, 0, 1, 1, 1, 2 };
+        constraintsTestSystem.constraintsR0 = { 0.1, 0.2 };
+
+        real oneTenthOverSqrtTwo    = 0.1_real / std::sqrt(2.0_real);
+        real twoTenthsOverSqrtThree = 0.2_real / std::sqrt(3.0_real);
+
+        constraintsTestSystem.x = { { oneTenthOverSqrtTwo, oneTenthOverSqrtTwo, 0.0 },
+                                    { 0.0, 0.0, 0.0 },
+                                    { twoTenthsOverSqrtThree, twoTenthsOverSqrtThree, twoTenthsOverSqrtThree } };
+
+        constraintsTestSystem.xPrime = { { 0.08, 0.07, 0.01 }, { -0.02, 0.01, -0.02 }, { 0.10, 0.12, 0.11 } };
+
+        constraintsTestSystem.v = { { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 } };
+
+        tensor virialScaledRef = { { 4.14e-03, 4.14e-03, 3.31e-03 },
+                                   { 4.14e-03, 4.14e-03, 3.31e-03 },
+                                   { 3.31e-03, 3.31e-03, 3.31e-03 } };
+
+        memcpy(constraintsTestSystem.virialScaledRef, virialScaledRef, DIM * DIM * sizeof(real));
+
+        constraintsTestSystemList.emplace_back(constraintsTestSystem);
+    }
+    {
+        ConstraintsTestSystem constraintsTestSystem;
+
+        constraintsTestSystem.title         = "four atoms, connected longitudinally";
+        constraintsTestSystem.numAtoms      = 4;
+        constraintsTestSystem.masses        = { 0.5, 1.0 / 3.0, 0.25, 1.0 };
+        constraintsTestSystem.constraints   = { 0, 0, 1, 1, 1, 2, 2, 2, 3 };
+        constraintsTestSystem.constraintsR0 = { 2.0, 1.0, 1.0 };
+
+
+        constraintsTestSystem.x = { { 2.50, -3.10, 15.70 },
+                                    { 0.51, -3.02, 15.55 },
+                                    { -0.50, -3.00, 15.20 },
+                                    { -1.51, -2.95, 15.05 } };
+
+        constraintsTestSystem.xPrime = { { 2.50, -3.10, 15.70 },
+                                         { 0.51, -3.02, 15.55 },
+                                         { -0.50, -3.00, 15.20 },
+                                         { -1.51, -2.95, 15.05 } };
+
+        constraintsTestSystem.v = {
+            { 0.0, 0.0, 2.0 }, { 0.0, 0.0, 3.0 }, { 0.0, 0.0, -4.0 }, { 0.0, 0.0, -1.0 }
+        };
+
+        tensor virialScaledRef = { { 1.15e-01, -4.20e-03, 2.12e-02 },
+                                   { -4.20e-03, 1.70e-04, -6.41e-04 },
+                                   { 2.12e-02, -6.41e-04, 5.45e-03 } };
+
+        memcpy(constraintsTestSystem.virialScaledRef, virialScaledRef, DIM * DIM * sizeof(real));
+
+
+        // Overriding default values since LINCS converges slowly for this system.
+        constraintsTestSystem.lincsNIter               = 4;
+        constraintsTestSystem.lincslincsExpansionOrder = 8;
+        constraintsTestSystem.virialTolerance          = absoluteTolerance(0.01);
+
+        constraintsTestSystemList.emplace_back(constraintsTestSystem);
+    }
+    {
+        ConstraintsTestSystem constraintsTestSystem;
+
+        constraintsTestSystem.title       = "three atoms, connected to the central atom (e.g. CH3)";
+        constraintsTestSystem.numAtoms    = 4;
+        constraintsTestSystem.masses      = { 12.0, 1.0, 1.0, 1.0 };
+        constraintsTestSystem.constraints = { 0, 0, 1, 0, 0, 2, 0, 0, 3 };
+        constraintsTestSystem.constraintsR0 = { 0.1 };
+
+
+        constraintsTestSystem.x = {
+            { 0.00, 0.00, 0.00 }, { 0.10, 0.00, 0.00 }, { 0.00, -0.10, 0.00 }, { 0.00, 0.00, 0.10 }
+        };
+
+        constraintsTestSystem.xPrime = { { 0.004, 0.009, -0.010 },
+                                         { 0.110, -0.006, 0.003 },
+                                         { -0.007, -0.102, -0.007 },
+                                         { -0.005, 0.011, 0.102 } };
+
+        constraintsTestSystem.v = { { 1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 } };
+
+        tensor virialScaledRef = { { 7.14e-04, 0.00e+00, 0.00e+00 },
+                                   { 0.00e+00, 1.08e-03, 0.00e+00 },
+                                   { 0.00e+00, 0.00e+00, 1.15e-03 } };
+
+        memcpy(constraintsTestSystem.virialScaledRef, virialScaledRef, DIM * DIM * sizeof(real));
+
+        constraintsTestSystemList.emplace_back(constraintsTestSystem);
+    }
+    {
+        ConstraintsTestSystem constraintsTestSystem;
+
+        constraintsTestSystem.title       = "basic triangle (three atoms, connected to each other)";
+        constraintsTestSystem.numAtoms    = 3;
+        constraintsTestSystem.masses      = { 1.0, 1.0, 1.0 };
+        constraintsTestSystem.constraints = { 0, 0, 1, 2, 0, 2, 1, 1, 2 };
+        constraintsTestSystem.constraintsR0 = { 0.1, 0.1, 0.1 };
+
+        real oneTenthOverSqrtTwo = 0.1_real / std::sqrt(2.0_real);
+
+        constraintsTestSystem.x = { { oneTenthOverSqrtTwo, 0.0, 0.0 },
+                                    { 0.0, oneTenthOverSqrtTwo, 0.0 },
+                                    { 0.0, 0.0, oneTenthOverSqrtTwo } };
+
+        constraintsTestSystem.xPrime = { { 0.09, -0.02, 0.01 }, { -0.02, 0.10, -0.02 }, { 0.03, -0.01, 0.07 } };
+
+        constraintsTestSystem.v = { { 1.0, 1.0, 1.0 }, { -2.0, -2.0, -2.0 }, { 1.0, 1.0, 1.0 } };
+
+        tensor virialScaledRef = { { 6.00e-04, -1.61e-03, 1.01e-03 },
+                                   { -1.61e-03, 2.53e-03, -9.25e-04 },
+                                   { 1.01e-03, -9.25e-04, -8.05e-05 } };
+
+        memcpy(constraintsTestSystem.virialScaledRef, virialScaledRef, DIM * DIM * sizeof(real));
+
+        constraintsTestSystemList.emplace_back(constraintsTestSystem);
+    }
+
+    return constraintsTestSystemList;
+}();
+
+
 /*! \brief Test fixture for constraints.
  *
  * The fixture uses following test systems:
@@ -91,37 +348,9 @@ namespace
  * For some systems, the value for scaled virial tensor is checked against
  * pre-computed data.
  */
-class ConstraintsTest : public ::testing::TestWithParam<std::string>
+class ConstraintsTest : public ::testing::TestWithParam<std::tuple<ConstraintsTestSystem, t_pbc>>
 {
 public:
-    //! PBC setups
-    std::unordered_map<std::string, t_pbc> pbcs_;
-
-    /*! \brief Test setup function.
-     *
-     * Setting up the pbcs and algorithms. Note, that corresponding string keywords
-     * have to be explicitly added at the end of this file when the tests are called.
-     *
-     */
-    void SetUp() override
-    {
-
-        //
-        // PBC initialization
-        //
-        t_pbc pbc;
-
-        // Infinitely small box
-        matrix boxNone = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } };
-        set_pbc(&pbc, PbcType::No, boxNone);
-        pbcs_["PBCNone"] = pbc;
-
-        // Rectangular box
-        matrix boxXyz = { { 10.0, 0.0, 0.0 }, { 0.0, 20.0, 0.0 }, { 0.0, 0.0, 15.0 } };
-        set_pbc(&pbc, PbcType::Xyz, boxXyz);
-        pbcs_["PBCXYZ"] = pbc;
-    }
-
     /*! \brief
      * The test on the final length of constrained bonds.
      *
@@ -161,7 +390,12 @@ public:
                     "rij = %f, which is not equal to r0 = %f for constraint #%zd, between atoms %d "
                     "and %d"
                     " (before constraining rij was %f).",
-                    d1, r0, c, i, j, d0);
+                    d1,
+                    r0,
+                    c,
+                    i,
+                    j,
+                    d0);
         }
     }
 
@@ -284,7 +518,8 @@ public:
                         << gmx::formatString(
                                    "Values in virial tensor at [%d][%d] are not within the "
                                    "tolerance from reference value.",
-                                   i, j);
+                                   i,
+                                   j);
             }
         }
     }
@@ -307,357 +542,57 @@ public:
     }
 };
 
-TEST_P(ConstraintsTest, SingleConstraint)
+TEST_P(ConstraintsTest, ConstraintsTest)
 {
-    std::string title    = "one constraint (e.g. OH)";
-    int         numAtoms = 2;
-
-    std::vector<real> masses        = { 1.0, 12.0 };
-    std::vector<int>  constraints   = { 0, 0, 1 };
-    std::vector<real> constraintsR0 = { 0.1 };
-
-    real oneTenthOverSqrtTwo = 0.1_real / std::sqrt(2.0_real);
-
-    std::vector<RVec> x = { { 0.0, oneTenthOverSqrtTwo, 0.0 }, { oneTenthOverSqrtTwo, 0.0, 0.0 } };
-    std::vector<RVec> xPrime = { { 0.01, 0.08, 0.01 }, { 0.06, 0.01, -0.01 } };
-    std::vector<RVec> v      = { { 1.0, 2.0, 3.0 }, { 3.0, 2.0, 1.0 } };
-
-    tensor virialScaledRef = { { -5.58e-04, 5.58e-04, 0.00e+00 },
-                               { 5.58e-04, -5.58e-04, 0.00e+00 },
-                               { 0.00e+00, 0.00e+00, 0.00e+00 } };
-
-    real     shakeTolerance = 0.0001;
-    gmx_bool shakeUseSOR    = false;
-
-    int  lincsNIter               = 1;
-    int  lincslincsExpansionOrder = 4;
-    real lincsWarnAngle           = 30.0;
-
-    std::unique_ptr<ConstraintsTestData> testData = std::make_unique<ConstraintsTestData>(
-            title, numAtoms, masses, constraints, constraintsR0, true, virialScaledRef, false, 0,
-            real(0.0), real(0.001), x, xPrime, v, shakeTolerance, shakeUseSOR, lincsNIter,
-            lincslincsExpansionOrder, lincsWarnAngle);
-
-    std::string pbcName = GetParam();
-    t_pbc       pbc     = pbcs_.at(pbcName);
+    auto                  params                = GetParam();
+    ConstraintsTestSystem constraintsTestSystem = std::get<0>(params);
+    t_pbc                 pbc                   = std::get<1>(params);
+
+    ConstraintsTestData testData(constraintsTestSystem.title,
+                                 constraintsTestSystem.numAtoms,
+                                 constraintsTestSystem.masses,
+                                 constraintsTestSystem.constraints,
+                                 constraintsTestSystem.constraintsR0,
+                                 true,
+                                 constraintsTestSystem.virialScaledRef,
+                                 false,
+                                 0,
+                                 real(0.0),
+                                 real(0.001),
+                                 constraintsTestSystem.x,
+                                 constraintsTestSystem.xPrime,
+                                 constraintsTestSystem.v,
+                                 constraintsTestSystem.shakeTolerance,
+                                 constraintsTestSystem.shakeUseSOR,
+                                 constraintsTestSystem.lincsNIter,
+                                 constraintsTestSystem.lincslincsExpansionOrder,
+                                 constraintsTestSystem.lincsWarnAngle);
 
     // Cycle through all available runners
     for (const auto& runner : getRunners())
     {
-        SCOPED_TRACE(formatString("Testing %s with %s using %s.", testData->title_.c_str(),
-                                  pbcName.c_str(), runner->name().c_str()));
+        SCOPED_TRACE(formatString("Testing %s with %s PBC using %s.",
+                                  testData.title_.c_str(),
+                                  c_pbcTypeNames[pbc.pbcType].c_str(),
+                                  runner->name().c_str()));
 
-        testData->reset();
+        testData.reset();
 
         // Apply constraints
-        runner->applyConstraints(testData.get(), pbc);
+        runner->applyConstraints(&testData, pbc);
 
-        checkConstrainsLength(absoluteTolerance(0.0002), *testData, pbc);
-        checkConstrainsDirection(*testData, pbc);
-        checkCOMCoordinates(absoluteTolerance(0.0001), *testData);
-        checkCOMVelocity(absoluteTolerance(0.0001), *testData);
-
-        checkVirialTensor(absoluteTolerance(0.0001), *testData);
+        checkConstrainsLength(constraintsTestSystem.lengthTolerance, testData, pbc);
+        checkConstrainsDirection(testData, pbc);
+        checkCOMCoordinates(constraintsTestSystem.comTolerance, testData);
+        checkCOMVelocity(constraintsTestSystem.comTolerance, testData);
+        checkVirialTensor(constraintsTestSystem.virialTolerance, testData);
     }
 }
 
-TEST_P(ConstraintsTest, TwoDisjointConstraints)
-{
-
-    std::string       title         = "two disjoint constraints";
-    int               numAtoms      = 4;
-    std::vector<real> masses        = { 0.5, 1.0 / 3.0, 0.25, 1.0 };
-    std::vector<int>  constraints   = { 0, 0, 1, 1, 2, 3 };
-    std::vector<real> constraintsR0 = { 2.0, 1.0 };
-
-
-    std::vector<RVec> x = {
-        { 2.50, -3.10, 15.70 }, { 0.51, -3.02, 15.55 }, { -0.50, -3.00, 15.20 }, { -1.51, -2.95, 15.05 }
-    };
-
-    std::vector<RVec> xPrime = {
-        { 2.50, -3.10, 15.70 }, { 0.51, -3.02, 15.55 }, { -0.50, -3.00, 15.20 }, { -1.51, -2.95, 15.05 }
-    };
-
-    std::vector<RVec> v = { { 0.0, 1.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, 0.0 } };
-
-    tensor virialScaledRef = { { 3.3e-03, -1.7e-04, 5.6e-04 },
-                               { -1.7e-04, 8.9e-06, -2.8e-05 },
-                               { 5.6e-04, -2.8e-05, 8.9e-05 } };
-
-    real     shakeTolerance = 0.0001;
-    gmx_bool shakeUseSOR    = false;
-
-    int  lincsNIter               = 1;
-    int  lincslincsExpansionOrder = 4;
-    real lincsWarnAngle           = 30.0;
-
-    std::unique_ptr<ConstraintsTestData> testData = std::make_unique<ConstraintsTestData>(
-            title, numAtoms, masses, constraints, constraintsR0, true, virialScaledRef, false, 0,
-            real(0.0), real(0.001), x, xPrime, v, shakeTolerance, shakeUseSOR, lincsNIter,
-            lincslincsExpansionOrder, lincsWarnAngle);
-
-    std::string pbcName = GetParam();
-    t_pbc       pbc     = pbcs_.at(pbcName);
-
-    // Cycle through all available runners
-    for (const auto& runner : getRunners())
-    {
-        SCOPED_TRACE(formatString("Testing %s with %s using %s.", testData->title_.c_str(),
-                                  pbcName.c_str(), runner->name().c_str()));
-
-        testData->reset();
-
-        // Apply constraints
-        runner->applyConstraints(testData.get(), pbc);
-
-        checkConstrainsLength(absoluteTolerance(0.0002), *testData, pbc);
-        checkConstrainsDirection(*testData, pbc);
-        checkCOMCoordinates(absoluteTolerance(0.0001), *testData);
-        checkCOMVelocity(absoluteTolerance(0.0001), *testData);
-
-        checkVirialTensor(absoluteTolerance(0.0001), *testData);
-    }
-}
-
-TEST_P(ConstraintsTest, ThreeSequentialConstraints)
-{
-
-    std::string       title         = "three atoms, connected longitudinally (e.g. CH2)";
-    int               numAtoms      = 3;
-    std::vector<real> masses        = { 1.0, 12.0, 16.0 };
-    std::vector<int>  constraints   = { 0, 0, 1, 1, 1, 2 };
-    std::vector<real> constraintsR0 = { 0.1, 0.2 };
-
-    real oneTenthOverSqrtTwo    = 0.1_real / std::sqrt(2.0_real);
-    real twoTenthsOverSqrtThree = 0.2_real / std::sqrt(3.0_real);
-
-    std::vector<RVec> x = { { oneTenthOverSqrtTwo, oneTenthOverSqrtTwo, 0.0 },
-                            { 0.0, 0.0, 0.0 },
-                            { twoTenthsOverSqrtThree, twoTenthsOverSqrtThree, twoTenthsOverSqrtThree } };
-
-    std::vector<RVec> xPrime = { { 0.08, 0.07, 0.01 }, { -0.02, 0.01, -0.02 }, { 0.10, 0.12, 0.11 } };
-
-    std::vector<RVec> v = { { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 } };
-
-    tensor virialScaledRef = { { 4.14e-03, 4.14e-03, 3.31e-03 },
-                               { 4.14e-03, 4.14e-03, 3.31e-03 },
-                               { 3.31e-03, 3.31e-03, 3.31e-03 } };
-
-    real     shakeTolerance = 0.0001;
-    gmx_bool shakeUseSOR    = false;
-
-    int  lincsNIter               = 1;
-    int  lincslincsExpansionOrder = 4;
-    real lincsWarnAngle           = 30.0;
-
-    std::unique_ptr<ConstraintsTestData> testData = std::make_unique<ConstraintsTestData>(
-            title, numAtoms, masses, constraints, constraintsR0, true, virialScaledRef, false, 0,
-            real(0.0), real(0.001), x, xPrime, v, shakeTolerance, shakeUseSOR, lincsNIter,
-            lincslincsExpansionOrder, lincsWarnAngle);
-
-    std::string pbcName = GetParam();
-    t_pbc       pbc     = pbcs_.at(pbcName);
-
-    // Cycle through all available runners
-    for (const auto& runner : getRunners())
-    {
-        SCOPED_TRACE(formatString("Testing %s with %s using %s.", testData->title_.c_str(),
-                                  pbcName.c_str(), runner->name().c_str()));
-
-        testData->reset();
-
-        // Apply constraints
-        runner->applyConstraints(testData.get(), pbc);
-
-        checkConstrainsLength(absoluteTolerance(0.0002), *testData, pbc);
-        checkConstrainsDirection(*testData, pbc);
-        checkCOMCoordinates(absoluteTolerance(0.0001), *testData);
-        checkCOMVelocity(absoluteTolerance(0.0001), *testData);
-
-        checkVirialTensor(absoluteTolerance(0.0001), *testData);
-    }
-}
-
-TEST_P(ConstraintsTest, ThreeConstraintsWithCentralAtom)
-{
-
-    std::string       title         = "three atoms, connected to the central atom (e.g. CH3)";
-    int               numAtoms      = 4;
-    std::vector<real> masses        = { 12.0, 1.0, 1.0, 1.0 };
-    std::vector<int>  constraints   = { 0, 0, 1, 0, 0, 2, 0, 0, 3 };
-    std::vector<real> constraintsR0 = { 0.1 };
-
-
-    std::vector<RVec> x = {
-        { 0.00, 0.00, 0.00 }, { 0.10, 0.00, 0.00 }, { 0.00, -0.10, 0.00 }, { 0.00, 0.00, 0.10 }
-    };
-
-    std::vector<RVec> xPrime = { { 0.004, 0.009, -0.010 },
-                                 { 0.110, -0.006, 0.003 },
-                                 { -0.007, -0.102, -0.007 },
-                                 { -0.005, 0.011, 0.102 } };
-
-    std::vector<RVec> v = { { 1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 } };
-
-    tensor virialScaledRef = { { 7.14e-04, 0.00e+00, 0.00e+00 },
-                               { 0.00e+00, 1.08e-03, 0.00e+00 },
-                               { 0.00e+00, 0.00e+00, 1.15e-03 } };
-
-    real     shakeTolerance = 0.0001;
-    gmx_bool shakeUseSOR    = false;
-
-    int  lincsNIter               = 1;
-    int  lincslincsExpansionOrder = 4;
-    real lincsWarnAngle           = 30.0;
-
-    std::unique_ptr<ConstraintsTestData> testData = std::make_unique<ConstraintsTestData>(
-            title, numAtoms, masses, constraints, constraintsR0, true, virialScaledRef, false, 0,
-            real(0.0), real(0.001), x, xPrime, v, shakeTolerance, shakeUseSOR, lincsNIter,
-            lincslincsExpansionOrder, lincsWarnAngle);
-
-    std::string pbcName = GetParam();
-    t_pbc       pbc     = pbcs_.at(pbcName);
-
-    // Cycle through all available runners
-    for (const auto& runner : getRunners())
-    {
-        SCOPED_TRACE(formatString("Testing %s with %s using %s.", testData->title_.c_str(),
-                                  pbcName.c_str(), runner->name().c_str()));
-
-        testData->reset();
-
-        // Apply constraints
-        runner->applyConstraints(testData.get(), pbc);
-
-        checkConstrainsLength(absoluteTolerance(0.0002), *testData, pbc);
-        checkConstrainsDirection(*testData, pbc);
-        checkCOMCoordinates(absoluteTolerance(0.0001), *testData);
-        checkCOMVelocity(absoluteTolerance(0.0001), *testData);
-
-        checkVirialTensor(absoluteTolerance(0.0001), *testData);
-    }
-}
-
-TEST_P(ConstraintsTest, FourSequentialConstraints)
-{
-
-    std::string       title         = "four atoms, connected longitudinally";
-    int               numAtoms      = 4;
-    std::vector<real> masses        = { 0.5, 1.0 / 3.0, 0.25, 1.0 };
-    std::vector<int>  constraints   = { 0, 0, 1, 1, 1, 2, 2, 2, 3 };
-    std::vector<real> constraintsR0 = { 2.0, 1.0, 1.0 };
-
-
-    std::vector<RVec> x = {
-        { 2.50, -3.10, 15.70 }, { 0.51, -3.02, 15.55 }, { -0.50, -3.00, 15.20 }, { -1.51, -2.95, 15.05 }
-    };
-
-    std::vector<RVec> xPrime = {
-        { 2.50, -3.10, 15.70 }, { 0.51, -3.02, 15.55 }, { -0.50, -3.00, 15.20 }, { -1.51, -2.95, 15.05 }
-    };
-
-    std::vector<RVec> v = { { 0.0, 0.0, 2.0 }, { 0.0, 0.0, 3.0 }, { 0.0, 0.0, -4.0 }, { 0.0, 0.0, -1.0 } };
-
-    tensor virialScaledRef = { { 1.15e-01, -4.20e-03, 2.12e-02 },
-                               { -4.20e-03, 1.70e-04, -6.41e-04 },
-                               { 2.12e-02, -6.41e-04, 5.45e-03 } };
-
-    real     shakeTolerance = 0.0001;
-    gmx_bool shakeUseSOR    = false;
-
-    int  lincsNIter               = 4;
-    int  lincslincsExpansionOrder = 8;
-    real lincsWarnAngle           = 30.0;
-
-    std::unique_ptr<ConstraintsTestData> testData = std::make_unique<ConstraintsTestData>(
-            title, numAtoms, masses, constraints, constraintsR0, true, virialScaledRef, false, 0,
-            real(0.0), real(0.001), x, xPrime, v, shakeTolerance, shakeUseSOR, lincsNIter,
-            lincslincsExpansionOrder, lincsWarnAngle);
-
-    std::string pbcName = GetParam();
-    t_pbc       pbc     = pbcs_.at(pbcName);
-
-    // Cycle through all available runners
-    for (const auto& runner : getRunners())
-    {
-        SCOPED_TRACE(formatString("Testing %s with %s using %s.", testData->title_.c_str(),
-                                  pbcName.c_str(), runner->name().c_str()));
-
-        testData->reset();
-
-        // Apply constraints
-        runner->applyConstraints(testData.get(), pbc);
-
-        checkConstrainsLength(absoluteTolerance(0.0002), *testData, pbc);
-        checkConstrainsDirection(*testData, pbc);
-        checkCOMCoordinates(absoluteTolerance(0.0001), *testData);
-        checkCOMVelocity(absoluteTolerance(0.0001), *testData);
-
-        checkVirialTensor(absoluteTolerance(0.01), *testData);
-    }
-}
-
-TEST_P(ConstraintsTest, TriangleOfConstraints)
-{
-
-    std::string       title         = "basic triangle (tree atoms, connected to each other)";
-    int               numAtoms      = 3;
-    std::vector<real> masses        = { 1.0, 1.0, 1.0 };
-    std::vector<int>  constraints   = { 0, 0, 1, 2, 0, 2, 1, 1, 2 };
-    std::vector<real> constraintsR0 = { 0.1, 0.1, 0.1 };
-
-    real oneTenthOverSqrtTwo = 0.1_real / std::sqrt(2.0_real);
-
-    std::vector<RVec> x = { { oneTenthOverSqrtTwo, 0.0, 0.0 },
-                            { 0.0, oneTenthOverSqrtTwo, 0.0 },
-                            { 0.0, 0.0, oneTenthOverSqrtTwo } };
-
-    std::vector<RVec> xPrime = { { 0.09, -0.02, 0.01 }, { -0.02, 0.10, -0.02 }, { 0.03, -0.01, 0.07 } };
-
-    std::vector<RVec> v = { { 1.0, 1.0, 1.0 }, { -2.0, -2.0, -2.0 }, { 1.0, 1.0, 1.0 } };
-
-    tensor virialScaledRef = { { 6.00e-04, -1.61e-03, 1.01e-03 },
-                               { -1.61e-03, 2.53e-03, -9.25e-04 },
-                               { 1.01e-03, -9.25e-04, -8.05e-05 } };
-
-    real     shakeTolerance = 0.0001;
-    gmx_bool shakeUseSOR    = false;
-
-    int  lincsNIter               = 1;
-    int  lincslincsExpansionOrder = 4;
-    real lincsWarnAngle           = 30.0;
-
-    std::unique_ptr<ConstraintsTestData> testData = std::make_unique<ConstraintsTestData>(
-            title, numAtoms, masses, constraints, constraintsR0, true, virialScaledRef, false, 0,
-            real(0.0), real(0.001), x, xPrime, v, shakeTolerance, shakeUseSOR, lincsNIter,
-            lincslincsExpansionOrder, lincsWarnAngle);
-
-    std::string pbcName = GetParam();
-    t_pbc       pbc     = pbcs_.at(pbcName);
-
-    // Cycle through all available runners
-    for (const auto& runner : getRunners())
-    {
-        SCOPED_TRACE(formatString("Testing %s with %s using %s.", testData->title_.c_str(),
-                                  pbcName.c_str(), runner->name().c_str()));
-
-        testData->reset();
-
-        // Apply constraints
-        runner->applyConstraints(testData.get(), pbc);
-
-        checkConstrainsLength(absoluteTolerance(0.0002), *testData, pbc);
-        checkConstrainsDirection(*testData, pbc);
-        checkCOMCoordinates(absoluteTolerance(0.0001), *testData);
-        checkCOMVelocity(absoluteTolerance(0.0001), *testData);
-
-        checkVirialTensor(absoluteTolerance(0.00001), *testData);
-    }
-}
-
-
-INSTANTIATE_TEST_CASE_P(WithParameters, ConstraintsTest, ::testing::Values("PBCNone", "PBCXYZ"));
+INSTANTIATE_TEST_CASE_P(WithParameters,
+                        ConstraintsTest,
+                        ::testing::Combine(::testing::ValuesIn(c_constraintsTestSystemList),
+                                           ::testing::ValuesIn(c_pbcs)));
 
 } // namespace
 } // namespace test
index 3de0c11b896b37adb798905aded2347f098e6e56..d1819bc7df138ad2b290c1067810863cb56326f4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -96,10 +96,10 @@ ConstraintsTestData::ConstraintsTestData(const std::string&       title,
     invdt_ = 1.0 / timestep; // Inverse timestep
 
     // Input record - data that usually comes from configuration file (.mdp)
-    ir_.efep    = 0;
+    ir_.efep    = FreeEnergyPerturbationType::No;
     ir_.init_t  = initialTime;
     ir_.delta_t = timestep;
-    ir_.eI      = 0;
+    ir_.eI      = IntegrationAlgorithm::MD;
 
     // Virial evaluation
     computeVirial_ = computeVirial;
@@ -122,12 +122,12 @@ ConstraintsTestData::ConstraintsTestData(const std::string&       title,
     dHdLambda_         = 0;
     if (compute_dHdLambda_)
     {
-        ir_.efep      = efepYES;
+        ir_.efep      = FreeEnergyPerturbationType::Yes;
         dHdLambdaRef_ = dHdLambdaRef;
     }
     else
     {
-        ir_.efep      = efepNO;
+        ir_.efep      = FreeEnergyPerturbationType::No;
         dHdLambdaRef_ = 0;
     }
 
index f57a9de20dc169a23e6d1cb99d5aed74aa61c269..608e05a2b73d41d0e72ae2c7519dbae93cbbc3c9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,11 +84,24 @@ void ShakeConstraintsRunner::applyConstraints(ConstraintsTestData* testData, t_p
 {
     shakedata shaked;
     make_shake_sblock_serial(&shaked, testData->idef_.get(), testData->numAtoms_);
-    bool success = constrain_shake(
-            nullptr, &shaked, testData->invmass_.data(), *testData->idef_, testData->ir_, testData->x_,
-            testData->xPrime_, testData->xPrime2_, nullptr, &testData->nrnb_, testData->lambda_,
-            &testData->dHdLambda_, testData->invdt_, testData->v_, testData->computeVirial_,
-            testData->virialScaled_, false, gmx::ConstraintVariable::Positions);
+    bool success = constrain_shake(nullptr,
+                                   &shaked,
+                                   testData->invmass_,
+                                   *testData->idef_,
+                                   testData->ir_,
+                                   testData->x_,
+                                   testData->xPrime_,
+                                   testData->xPrime2_,
+                                   nullptr,
+                                   &testData->nrnb_,
+                                   testData->lambda_,
+                                   &testData->dHdLambda_,
+                                   testData->invdt_,
+                                   testData->v_,
+                                   testData->computeVirial_,
+                                   testData->virialScaled_,
+                                   false,
+                                   gmx::ConstraintVariable::Positions);
     EXPECT_TRUE(success) << "Test failed with a false return value in SHAKE.";
 }
 
@@ -98,7 +111,7 @@ void LincsConstraintsRunner::applyConstraints(ConstraintsTestData* testData, t_p
     Lincs* lincsd;
     int    maxwarn         = 100;
     int    warncount_lincs = 0;
-    gmx_omp_nthreads_set(emntLINCS, 1);
+    gmx_omp_nthreads_set(ModuleMultiThread::Lincs, 1);
 
     // Communication record
     t_commrec cr;
@@ -114,24 +127,50 @@ void LincsConstraintsRunner::applyConstraints(ConstraintsTestData* testData, t_p
     for (const gmx_moltype_t& moltype : testData->mtop_.moltype)
     {
         // This function is in constr.cpp
-        at2con_mt.push_back(make_at2con(moltype, testData->mtop_.ffparams.iparams,
+        at2con_mt.push_back(make_at2con(moltype,
+                                        testData->mtop_.ffparams.iparams,
                                         flexibleConstraintTreatment(EI_DYNAMICS(testData->ir_.eI))));
     }
     // Initialize LINCS
-    lincsd = init_lincs(nullptr, testData->mtop_, testData->nflexcon_, at2con_mt, false,
-                        testData->ir_.nLincsIter, testData->ir_.nProjOrder);
-    set_lincs(*testData->idef_, testData->numAtoms_, testData->invmass_.data(), testData->lambda_,
-              EI_DYNAMICS(testData->ir_.eI), &cr, lincsd);
+    lincsd = init_lincs(nullptr,
+                        testData->mtop_,
+                        testData->nflexcon_,
+                        at2con_mt,
+                        false,
+                        testData->ir_.nLincsIter,
+                        testData->ir_.nProjOrder);
+    set_lincs(*testData->idef_,
+              testData->numAtoms_,
+              testData->invmass_,
+              testData->lambda_,
+              EI_DYNAMICS(testData->ir_.eI),
+              &cr,
+              lincsd);
 
     // Evaluate constraints
-    bool success = constrain_lincs(
-            false, testData->ir_, 0, lincsd, testData->invmass_.data(), &cr, &ms,
-            testData->x_.arrayRefWithPadding(), testData->xPrime_.arrayRefWithPadding(),
-            testData->xPrime2_.arrayRefWithPadding().unpaddedArrayRef(), pbc.box, &pbc,
-            testData->hasMassPerturbed_, testData->lambda_, &testData->dHdLambda_, testData->invdt_,
-            testData->v_.arrayRefWithPadding().unpaddedArrayRef(), testData->computeVirial_,
-            testData->virialScaled_, gmx::ConstraintVariable::Positions, &testData->nrnb_, maxwarn,
-            &warncount_lincs);
+    bool success = constrain_lincs(false,
+                                   testData->ir_,
+                                   0,
+                                   lincsd,
+                                   testData->invmass_,
+                                   &cr,
+                                   &ms,
+                                   testData->x_.arrayRefWithPadding(),
+                                   testData->xPrime_.arrayRefWithPadding(),
+                                   testData->xPrime2_.arrayRefWithPadding().unpaddedArrayRef(),
+                                   pbc.box,
+                                   &pbc,
+                                   testData->hasMassPerturbed_,
+                                   testData->lambda_,
+                                   &testData->dHdLambda_,
+                                   testData->invdt_,
+                                   testData->v_.arrayRefWithPadding().unpaddedArrayRef(),
+                                   testData->computeVirial_,
+                                   testData->virialScaled_,
+                                   gmx::ConstraintVariable::Positions,
+                                   &testData->nrnb_,
+                                   maxwarn,
+                                   &warncount_lincs);
     EXPECT_TRUE(success) << "Test failed with a false return value in LINCS.";
     EXPECT_EQ(warncount_lincs, 0) << "There were warnings in LINCS.";
     done_lincs(lincsd);
index 88cc8e866d48b951af5c795c7e3140e388b3554d..1f45f0ccab210a294b3a7a0e419a91b1f6d29800 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 @@
 #include <vector>
 
 #include "gromacs/gpu_utils/devicebuffer.cuh"
+#include "gromacs/gpu_utils/gputraits.h"
 #include "gromacs/hardware/device_information.h"
-#include "gromacs/mdlib/lincs_gpu.cuh"
+#include "gromacs/mdlib/lincs_gpu.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/utility/unique_cptr.h"
 
@@ -68,12 +69,17 @@ void LincsDeviceConstraintsRunner::applyConstraints(ConstraintsTestData* testDat
     const DeviceStream&  deviceStream  = testDevice_.deviceStream();
     setActiveDevice(testDevice_.deviceInfo());
 
-    auto lincsGpu = std::make_unique<LincsGpu>(testData->ir_.nLincsIter, testData->ir_.nProjOrder,
-                                               deviceContext, deviceStream);
+    auto lincsGpu = std::make_unique<LincsGpu>(
+            testData->ir_.nLincsIter, testData->ir_.nProjOrder, deviceContext, deviceStream);
 
-    bool    updateVelocities = true;
-    int     numAtoms         = testData->numAtoms_;
-    float3 *d_x, *d_xp, *d_v;
+    bool updateVelocities = true;
+    int  numAtoms         = testData->numAtoms_;
+
+    Float3* h_x  = gmx::asGenericFloat3Pointer(testData->x_);
+    Float3* h_xp = gmx::asGenericFloat3Pointer(testData->xPrime_);
+    Float3* h_v  = gmx::asGenericFloat3Pointer(testData->v_);
+
+    DeviceBuffer<Float3> d_x, d_xp, d_v;
 
     lincsGpu->set(*testData->idef_, testData->numAtoms_, testData->invmass_.data());
     PbcAiuc pbcAiuc;
@@ -83,24 +89,19 @@ void LincsDeviceConstraintsRunner::applyConstraints(ConstraintsTestData* testDat
     allocateDeviceBuffer(&d_xp, numAtoms, deviceContext);
     allocateDeviceBuffer(&d_v, numAtoms, deviceContext);
 
-    copyToDeviceBuffer(&d_x, (float3*)(testData->x_.data()), 0, numAtoms, deviceStream,
-                       GpuApiCallBehavior::Sync, nullptr);
-    copyToDeviceBuffer(&d_xp, (float3*)(testData->xPrime_.data()), 0, numAtoms, deviceStream,
-                       GpuApiCallBehavior::Sync, nullptr);
+    copyToDeviceBuffer(&d_x, h_x, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
+    copyToDeviceBuffer(&d_xp, h_xp, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
     if (updateVelocities)
     {
-        copyToDeviceBuffer(&d_v, (float3*)(testData->v_.data()), 0, numAtoms, deviceStream,
-                           GpuApiCallBehavior::Sync, nullptr);
+        copyToDeviceBuffer(&d_v, h_v, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
     }
-    lincsGpu->apply(d_x, d_xp, updateVelocities, d_v, testData->invdt_, testData->computeVirial_,
-                    testData->virialScaled_, pbcAiuc);
+    lincsGpu->apply(
+            d_x, d_xp, updateVelocities, d_v, testData->invdt_, testData->computeVirial_, testData->virialScaled_, pbcAiuc);
 
-    copyFromDeviceBuffer((float3*)(testData->xPrime_.data()), &d_xp, 0, numAtoms, deviceStream,
-                         GpuApiCallBehavior::Sync, nullptr);
+    copyFromDeviceBuffer(h_xp, &d_xp, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
     if (updateVelocities)
     {
-        copyFromDeviceBuffer((float3*)(testData->v_.data()), &d_v, 0, numAtoms, deviceStream,
-                             GpuApiCallBehavior::Sync, nullptr);
+        copyFromDeviceBuffer(h_v, &d_v, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
     }
 
     freeDeviceBuffer(&d_x);
index 4ebb7eb445c552fcafed1bcfca80fb5db0ace855..51a06b9f769d93837b2399ba68fab5371452be6f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -68,7 +68,7 @@
 #include "gromacs/mdtypes/state.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/cstringutil.h"
-#include "gromacs/utility/mdmodulenotification.h"
+#include "gromacs/utility/mdmodulesnotifiers.h"
 #include "gromacs/utility/stringutil.h"
 #include "gromacs/utility/textreader.h"
 #include "gromacs/utility/unique_cptr.h"
@@ -98,11 +98,11 @@ void fcloseWrapper(FILE* fp)
 struct EnergyOutputTestParameters
 {
     //! Thermostat (enum)
-    int temperatureCouplingScheme;
+    TemperatureCoupling temperatureCouplingScheme;
     //! Barostat (enum)
-    int pressureCouplingScheme;
+    PressureCoupling pressureCouplingScheme;
     //! Integrator
-    int integrator;
+    IntegrationAlgorithm integrator;
     //! Number of saved energy frames (to test averages output).
     int numFrames;
     //! If output should be initialized as a rerun.
@@ -116,17 +116,19 @@ struct EnergyOutputTestParameters
  * Only several combinations of the parameters are used. Using all possible combinations will
  * require ~10 MB of test data and ~2 sec to run the tests.
  */
-const EnergyOutputTestParameters parametersSets[] = { { etcNO, epcNO, eiMD, 1, false, false },
-                                                      { etcNO, epcNO, eiMD, 1, true, false },
-                                                      { etcNO, epcNO, eiMD, 1, false, true },
-                                                      { etcNO, epcNO, eiMD, 0, false, false },
-                                                      { etcNO, epcNO, eiMD, 10, false, false },
-                                                      { etcVRESCALE, epcNO, eiMD, 1, false, false },
-                                                      { etcNOSEHOOVER, epcNO, eiMD, 1, false, false },
-                                                      { etcNO, epcPARRINELLORAHMAN, eiMD, 1, false, false },
-                                                      { etcNO, epcMTTK, eiMD, 1, false, false },
-                                                      { etcNO, epcNO, eiVV, 1, false, false },
-                                                      { etcNO, epcMTTK, eiVV, 1, false, false } };
+const EnergyOutputTestParameters parametersSets[] = {
+    { TemperatureCoupling::No, PressureCoupling::No, IntegrationAlgorithm::MD, 1, false, false },
+    { TemperatureCoupling::No, PressureCoupling::No, IntegrationAlgorithm::MD, 1, true, false },
+    { TemperatureCoupling::No, PressureCoupling::No, IntegrationAlgorithm::MD, 1, false, true },
+    { TemperatureCoupling::No, PressureCoupling::No, IntegrationAlgorithm::MD, 0, false, false },
+    { TemperatureCoupling::No, PressureCoupling::No, IntegrationAlgorithm::MD, 10, false, false },
+    { TemperatureCoupling::VRescale, PressureCoupling::No, IntegrationAlgorithm::MD, 1, false, false },
+    { TemperatureCoupling::NoseHoover, PressureCoupling::No, IntegrationAlgorithm::MD, 1, false, false },
+    { TemperatureCoupling::No, PressureCoupling::ParrinelloRahman, IntegrationAlgorithm::MD, 1, false, false },
+    { TemperatureCoupling::No, PressureCoupling::Mttk, IntegrationAlgorithm::MD, 1, false, false },
+    { TemperatureCoupling::No, PressureCoupling::No, IntegrationAlgorithm::VV, 1, false, false },
+    { TemperatureCoupling::No, PressureCoupling::Mttk, IntegrationAlgorithm::VV, 1, false, false }
+};
 
 /*! \brief Test fixture to test energy output.
  *
@@ -136,6 +138,9 @@ const EnergyOutputTestParameters parametersSets[] = { { etcNO, epcNO, eiMD, 1, f
  */
 class EnergyOutputTest : public ::testing::TestWithParam<EnergyOutputTestParameters>
 {
+    int  numTempCouplingGroups_ = 3;
+    real cosAccel_              = 1.0;
+
 public:
     //! File manager
     TestFileManager fileManager_;
@@ -191,6 +196,7 @@ public:
     TestReferenceChecker checker_;
 
     EnergyOutputTest() :
+        ekindata_(numTempCouplingGroups_, cosAccel_, 1),
         logFilename_(fileManager_.getTemporaryFilePath(".log")),
         edrFilename_(fileManager_.getTemporaryFilePath(".edr")),
         log_(std::fopen(logFilename_.c_str(), "w")),
@@ -203,24 +209,24 @@ public:
         // F_EQM
         inputrec_.bQMMM = true;
         // F_RF_EXCL will not be tested - group scheme is not supported any more
-        inputrec_.cutoff_scheme = ecutsVERLET;
+        inputrec_.cutoff_scheme = CutoffScheme::Verlet;
         // F_COUL_RECIP
-        inputrec_.coulombtype = eelPME;
+        inputrec_.coulombtype = CoulombInteractionType::Pme;
         // F_LJ_RECIP
-        inputrec_.vdwtype = evdwPME;
+        inputrec_.vdwtype = VanDerWaalsType::Pme;
 
         // F_DVDL_COUL, F_DVDL_VDW, F_DVDL_BONDED, F_DVDL_RESTRAINT, F_DKDL and F_DVDL
-        inputrec_.efep                                  = efepYES;
-        inputrec_.fepvals->separate_dvdl[efptCOUL]      = true;
-        inputrec_.fepvals->separate_dvdl[efptVDW]       = true;
-        inputrec_.fepvals->separate_dvdl[efptBONDED]    = true;
-        inputrec_.fepvals->separate_dvdl[efptRESTRAINT] = true;
-        inputrec_.fepvals->separate_dvdl[efptMASS]      = true;
-        inputrec_.fepvals->separate_dvdl[efptCOUL]      = true;
-        inputrec_.fepvals->separate_dvdl[efptFEP]       = true;
+        inputrec_.efep = FreeEnergyPerturbationType::Yes;
+        inputrec_.fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Coul]      = true;
+        inputrec_.fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Vdw]       = true;
+        inputrec_.fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Bonded]    = true;
+        inputrec_.fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Restraint] = true;
+        inputrec_.fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Mass]      = true;
+        inputrec_.fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Coul]      = true;
+        inputrec_.fepvals->separate_dvdl[FreeEnergyPerturbationCouplingType::Fep]       = true;
 
         // F_DISPCORR and F_PDISPCORR
-        inputrec_.eDispCorr = edispcEner;
+        inputrec_.eDispCorr = DispersionCorrectionType::Ener;
         inputrec_.bRot      = true;
 
         // F_ECONSERVED
@@ -229,13 +235,13 @@ public:
         inputrec_.ref_p[ZZ][YY] = 0.0;
 
         // Dipole (mu)
-        inputrec_.ewald_geometry = eewg3DC;
+        inputrec_.ewald_geometry = EwaldGeometry::ThreeDC;
 
         // GMX_CONSTRAINTVIR environment variable should also be
         // set to print constraints and force virials separately.
         gmxSetenv("GMX_CONSTRAINTVIR", "true", 1);
         // To print constrain RMSD, constraints algorithm should be set to LINCS.
-        inputrec_.eConstrAlg = econtLINCS;
+        inputrec_.eConstrAlg = ConstraintAlgorithm::Lincs;
 
         mtop_.bIntermolecularInteractions = false;
 
@@ -310,20 +316,16 @@ public:
             mtop_.groups.groupNames.emplace_back(&handle);
         }
 
-        mtop_.groups.groups[SimulationAtomGroupType::EnergyOutput].resize(3);
+        mtop_.groups.groups[SimulationAtomGroupType::EnergyOutput].resize(numTempCouplingGroups_);
         mtop_.groups.groups[SimulationAtomGroupType::EnergyOutput][0] = 0;
         mtop_.groups.groups[SimulationAtomGroupType::EnergyOutput][1] = 1;
         mtop_.groups.groups[SimulationAtomGroupType::EnergyOutput][2] = 2;
 
-        mtop_.groups.groups[SimulationAtomGroupType::TemperatureCoupling].resize(3);
+        mtop_.groups.groups[SimulationAtomGroupType::TemperatureCoupling].resize(numTempCouplingGroups_);
         mtop_.groups.groups[SimulationAtomGroupType::TemperatureCoupling][0] = 0;
         mtop_.groups.groups[SimulationAtomGroupType::TemperatureCoupling][1] = 1;
         mtop_.groups.groups[SimulationAtomGroupType::TemperatureCoupling][2] = 2;
 
-        mtop_.groups.groups[SimulationAtomGroupType::Acceleration].resize(2);
-        mtop_.groups.groups[SimulationAtomGroupType::Acceleration][0] = 0;
-        mtop_.groups.groups[SimulationAtomGroupType::Acceleration][1] = 2;
-
         // Nose-Hoover chains
         inputrec_.bPrintNHChains     = true;
         inputrec_.opts.nhchainlength = 2;
@@ -344,23 +346,17 @@ public:
 
         // Kinetic energy and related data
         ekindata_.tcstat.resize(mtop_.groups.groups[SimulationAtomGroupType::TemperatureCoupling].size());
-        ekindata_.grpstat.resize(mtop_.groups.groups[SimulationAtomGroupType::Acceleration].size());
 
         // This is needed so that the ebin space will be allocated
-        inputrec_.cos_accel = 1.0;
-        // This is to keep the destructor happy (otherwise sfree() segfaults)
-        ekindata_.nthreads = 0;
-        snew(ekindata_.ekin_work_alloc, 1);
-        snew(ekindata_.ekin_work, 1);
-        snew(ekindata_.dekindl_work, 1);
+        inputrec_.cos_accel = cosAccel_;
 
         // Group options for annealing output
-        inputrec_.opts.ngtc = 3;
+        inputrec_.opts.ngtc = numTempCouplingGroups_;
         snew(inputrec_.opts.ref_t, inputrec_.opts.ngtc);
         snew(inputrec_.opts.annealing, inputrec_.opts.ngtc);
-        inputrec_.opts.annealing[0] = eannNO;
-        inputrec_.opts.annealing[1] = eannSINGLE;
-        inputrec_.opts.annealing[2] = eannPERIODIC;
+        inputrec_.opts.annealing[0] = SimulatedAnnealing::No;
+        inputrec_.opts.annealing[1] = SimulatedAnnealing::Single;
+        inputrec_.opts.annealing[2] = SimulatedAnnealing::Periodic;
 
         // This is to keep done_inputrec happy (otherwise sfree() segfaults)
         snew(inputrec_.opts.anneal_time, inputrec_.opts.ngtc);
@@ -374,8 +370,8 @@ public:
         // TODO EnergyOutput should not take Constraints object
         // TODO This object will always return zero as RMSD value.
         //      It is more relevant to have non-zero value for testing.
-        constraints_ = makeConstraints(mtop_, inputrec_, nullptr, false, nullptr, &cr_, nullptr,
-                                       nullptr, nullptr, false);
+        constraints_ = makeConstraints(
+                mtop_, inputrec_, nullptr, false, nullptr, &cr_, false, nullptr, nullptr, nullptr, false);
     }
 
     /*! \brief Helper function to generate synthetic data to output
@@ -423,9 +419,9 @@ public:
         // Group pairs
         for (int i = 0; i < enerdata_->grpp.nener; i++)
         {
-            for (int k = 0; k < egNR; k++)
+            for (int k = 0; k < static_cast<int>(NonBondedEnergyTerms::Count); k++)
             {
-                enerdata_->grpp.ener[k][i] = (*testValue += 0.1);
+                enerdata_->grpp.energyGroupPairTerms[k][i] = (*testValue += 0.1);
             }
         }
 
@@ -435,12 +431,9 @@ public:
             tcstat.T      = (*testValue += 0.1);
             tcstat.lambda = (*testValue += 0.1);
         }
-        for (auto& grpstat : ekindata_.grpstat)
-        {
-            grpstat.u[XX] = (*testValue += 0.1);
-            grpstat.u[YY] = (*testValue += 0.1);
-            grpstat.u[ZZ] = (*testValue += 0.1);
-        }
+        // Removing constant acceleration removed a total increment of 0.6
+        // To avoid unnecessary changes in reference data, we keep the increment
+        (*testValue += 0.6);
 
         // This conditional is to check whether the ebin was allocated.
         // Otherwise it will print cosacc data into the first bin.
@@ -624,26 +617,48 @@ TEST_P(EnergyOutputTest, CheckOutput)
         inputrec_.ref_p[YY][XX] = 1.0;
     }
 
-    MdModulesNotifier             mdModulesNotifier;
-    std::unique_ptr<EnergyOutput> energyOutput = std::make_unique<EnergyOutput>(
-            energyFile_, &mtop_, &inputrec_, nullptr, nullptr, parameters.isRerun,
-            StartingBehavior::NewSimulation, false, mdModulesNotifier);
+    MDModulesNotifiers            mdModulesNotifiers;
+    std::unique_ptr<EnergyOutput> energyOutput =
+            std::make_unique<EnergyOutput>(energyFile_,
+                                           mtop_,
+                                           inputrec_,
+                                           nullptr,
+                                           nullptr,
+                                           parameters.isRerun,
+                                           StartingBehavior::NewSimulation,
+                                           false,
+                                           mdModulesNotifiers);
 
     // Add synthetic data for a single step
     double testValue = 10.0;
     for (int frame = 0; frame < parameters.numFrames; frame++)
     {
         setStepData(&testValue);
-        energyOutput->addDataAtEnergyStep(
-                false, true, time_, tmass_, enerdata_.get(), nullptr, nullptr, box_,
-                PTCouplingArrays({ state_.boxv, state_.nosehoover_xi, state_.nosehoover_vxi,
-                                   state_.nhpres_xi, state_.nhpres_vxi }),
-                state_.fep_state, constraintsVirial_, forceVirial_, totalVirial_, pressure_,
-                &ekindata_, muTotal_, constraints_.get());
+        energyOutput->addDataAtEnergyStep(false,
+                                          true,
+                                          time_,
+                                          tmass_,
+                                          enerdata_.get(),
+                                          nullptr,
+                                          nullptr,
+                                          box_,
+                                          PTCouplingArrays({ state_.boxv,
+                                                             state_.nosehoover_xi,
+                                                             state_.nosehoover_vxi,
+                                                             state_.nhpres_xi,
+                                                             state_.nhpres_vxi }),
+                                          state_.fep_state,
+                                          constraintsVirial_,
+                                          forceVirial_,
+                                          totalVirial_,
+                                          pressure_,
+                                          &ekindata_,
+                                          muTotal_,
+                                          constraints_.get());
 
         energyOutput->printAnnealingTemperatures(log_, &mtop_.groups, &inputrec_.opts);
-        energyOutput->printStepToEnergyFile(energyFile_, true, false, false, log_, 100 * frame,
-                                            time_, nullptr, nullptr);
+        energyOutput->printStepToEnergyFile(
+                energyFile_, true, false, false, log_, 100 * frame, time_, nullptr, nullptr);
         time_ += 1.0;
     }
 
index 887a7913f35fe9eddf7ea98267370b06ffb180a1..9485d8e2a159ab39352212eeaccab5c8e6bba404 100644 (file)
@@ -54,6 +54,7 @@
 #include "gromacs/mdlib/expanded_internal.h"
 #include "gromacs/mdtypes/md_enums.h"
 
+#include "gromacs/utility/enumerationhelpers.h"
 #include "testutils/testasserts.h"
 
 namespace gmx
@@ -70,10 +71,11 @@ class CalculateAcceptanceWeightSimple : public ::testing::Test, public ::testing
 // Check that unimplemented calculation modes throw
 TEST_P(CalculateAcceptanceWeightSimple, UnknownCalculationModeThrows)
 {
-    for (auto calculationMode = 0; calculationMode < elamstatsNR; ++calculationMode)
+    for (auto calculationMode : gmx::EnumerationArray<LambdaWeightCalculation, bool>::keys())
     {
-        if (calculationMode != elamstatsBARKER && calculationMode != elamstatsMINVAR
-            && calculationMode != elamstatsMETROPOLIS)
+        if (calculationMode != LambdaWeightCalculation::Barker
+            && calculationMode != LambdaWeightCalculation::Minvar
+            && calculationMode != LambdaWeightCalculation::Metropolis)
         {
             EXPECT_THROW_GMX(calculateAcceptanceWeight(calculationMode, GetParam()), NotImplementedError);
         }
@@ -82,21 +84,21 @@ TEST_P(CalculateAcceptanceWeightSimple, UnknownCalculationModeThrows)
 // Check that implemented calculation modes don't throw
 TEST_P(CalculateAcceptanceWeightSimple, KnownCalculationModeDoesNotThrow)
 {
-    EXPECT_NO_THROW(calculateAcceptanceWeight(elamstatsMETROPOLIS, GetParam()));
-    EXPECT_NO_THROW(calculateAcceptanceWeight(elamstatsBARKER, GetParam()));
-    EXPECT_NO_THROW(calculateAcceptanceWeight(elamstatsMINVAR, GetParam()));
+    EXPECT_NO_THROW(calculateAcceptanceWeight(LambdaWeightCalculation::Metropolis, GetParam()));
+    EXPECT_NO_THROW(calculateAcceptanceWeight(LambdaWeightCalculation::Barker, GetParam()));
+    EXPECT_NO_THROW(calculateAcceptanceWeight(LambdaWeightCalculation::Minvar, GetParam()));
 }
 // Barker and MinVar are expected to be equal
 TEST_P(CalculateAcceptanceWeightSimple, BarkerAndMinVarAreIdentical)
 {
-    EXPECT_EQ(calculateAcceptanceWeight(elamstatsBARKER, GetParam()),
-              calculateAcceptanceWeight(elamstatsMINVAR, GetParam()));
+    EXPECT_EQ(calculateAcceptanceWeight(LambdaWeightCalculation::Barker, GetParam()),
+              calculateAcceptanceWeight(LambdaWeightCalculation::Minvar, GetParam()));
 }
 
 /*! \brief Test fixture accepting a calculation mode and an input value for
  *         calculateAcceptanceWeight as well as the expected output value
  */
-using RegressionTuple = std::tuple<int, real, real>;
+using RegressionTuple = std::tuple<LambdaWeightCalculation, real, real>;
 class CalculateAcceptanceWeightRangeRegression :
     public ::testing::Test,
     public ::testing::WithParamInterface<RegressionTuple>
@@ -119,20 +121,21 @@ INSTANTIATE_TEST_CASE_P(
 INSTANTIATE_TEST_CASE_P(
         RegressionTests,
         CalculateAcceptanceWeightRangeRegression,
-        ::testing::Values(RegressionTuple{ elamstatsMETROPOLIS, 0.0, 1.0 },
-                          RegressionTuple{ elamstatsMETROPOLIS, GMX_REAL_NEGZERO, 1.0 },
-                          RegressionTuple{ elamstatsMETROPOLIS, GMX_REAL_EPS, 1.0 },
-                          RegressionTuple{ elamstatsMETROPOLIS, -1.0, 1.0 },
-                          RegressionTuple{ elamstatsMETROPOLIS, -GMX_REAL_MAX, 1.0 },
-                          RegressionTuple{ elamstatsMETROPOLIS, 1.0, std::exp(-1.0) },
-                          RegressionTuple{ elamstatsMETROPOLIS, GMX_REAL_MAX, 0.0 },
-                          RegressionTuple{ elamstatsBARKER, 0.0, 0.5 },
-                          RegressionTuple{ elamstatsBARKER, GMX_REAL_NEGZERO, 0.5 },
-                          RegressionTuple{ elamstatsBARKER, GMX_REAL_EPS, 0.5 },
-                          RegressionTuple{ elamstatsBARKER, -1.0, 1.0 / (1.0 + std::exp(-1.0)) },
-                          RegressionTuple{ elamstatsBARKER, -GMX_REAL_MAX, 1.0 },
-                          RegressionTuple{ elamstatsBARKER, 1.0, 1.0 / (1.0 + std::exp(1.0)) },
-                          RegressionTuple{ elamstatsBARKER, GMX_REAL_MAX, 0.0 }));
+        ::testing::Values(
+                RegressionTuple{ LambdaWeightCalculation::Metropolis, 0.0, 1.0 },
+                RegressionTuple{ LambdaWeightCalculation::Metropolis, GMX_REAL_NEGZERO, 1.0 },
+                RegressionTuple{ LambdaWeightCalculation::Metropolis, GMX_REAL_EPS, 1.0 },
+                RegressionTuple{ LambdaWeightCalculation::Metropolis, -1.0, 1.0 },
+                RegressionTuple{ LambdaWeightCalculation::Metropolis, -GMX_REAL_MAX, 1.0 },
+                RegressionTuple{ LambdaWeightCalculation::Metropolis, 1.0, std::exp(-1.0) },
+                RegressionTuple{ LambdaWeightCalculation::Metropolis, GMX_REAL_MAX, 0.0 },
+                RegressionTuple{ LambdaWeightCalculation::Barker, 0.0, 0.5 },
+                RegressionTuple{ LambdaWeightCalculation::Barker, GMX_REAL_NEGZERO, 0.5 },
+                RegressionTuple{ LambdaWeightCalculation::Barker, GMX_REAL_EPS, 0.5 },
+                RegressionTuple{ LambdaWeightCalculation::Barker, -1.0, 1.0 / (1.0 + std::exp(-1.0)) },
+                RegressionTuple{ LambdaWeightCalculation::Barker, -GMX_REAL_MAX, 1.0 },
+                RegressionTuple{ LambdaWeightCalculation::Barker, 1.0, 1.0 / (1.0 + std::exp(1.0)) },
+                RegressionTuple{ LambdaWeightCalculation::Barker, GMX_REAL_MAX, 0.0 }));
 
 } // namespace
 } // namespace test
index a6ea79624dd7ebdc240935f1a250d29214c2ad1b..b2b3fe0fc39da6c03d9c3fddcd72b07456acfd62 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
 
 #include "gromacs/mdtypes/inputrec.h"
 
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "testutils/testasserts.h"
 #include "testutils/testmatchers.h"
 
@@ -76,7 +78,9 @@ struct FreeEnergyParameterTestParameters
     //! the current simulation step
     int64_t step = 0;
     //! the expected lambda at the current simulation step
-    std::array<real, efptNR> expectedLambdas = { -1, -1, -1, -1, -1, -1, -1 };
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> expectedLambdas = { -1, -1, -1,
+                                                                                        -1, -1, -1,
+                                                                                        -1 };
 };
 
 
@@ -133,28 +137,14 @@ public:
         fepvals.init_fep_state = GetParam().initFepState;
         fepvals.init_lambda    = GetParam().initLambda;
         fepvals.delta_lambda   = GetParam().deltaLambda;
-        fepvals.all_lambda     = getLambdaMatrix(GetParam().nLambda);
-        fepvals.n_lambda       = GetParam().nLambda;
+        std::fill(fepvals.all_lambda.begin(),
+                  fepvals.all_lambda.end(),
+                  defaultLambdaArrayForTest_[GetParam().nLambda]);
+        fepvals.n_lambda = GetParam().nLambda;
         return fepvals;
     }
 
-    /*! \brief construct a lambda matrix
-     *
-     * \param[in] nLambda
-     * \returns nLambda * eftpNR matrix with pre-defined values
-     */
-    double** getLambdaMatrix(int nLambda)
-    {
-        for (int i = 0; i < efptNR; ++i)
-        {
-            allLambda_[i] = defaultLambdaArrayForTest_[nLambda].data();
-        }
-        return allLambda_.data();
-    }
-
 private:
-    //! Construction aide for double ** matrix without snew
-    std::array<double*, efptNR> allLambda_;
     //! a set of default lambda arrays for different lengths
     std::vector<std::vector<double>> defaultLambdaArrayForTest_ = { {}, { 0.8 }, { 0.2, 0.8 }, { 0.2, 0.8, 0.8 } };
 };
index 85822ebe81799fa35352579686caf8abb97972bf..504b9600c279c7fc8b2943d9c632b56b3b6aa505 100644 (file)
@@ -228,15 +228,28 @@ TEST_P(LeapFrogTest, SimpleIntegration)
                 "groups and "
                 "%s pressure coupling (dt = %f, v0=(%f, %f, %f), f0=(%f, %f, %f), nstpcouple = "
                 "%d)",
-                runner->hardwareDescription().c_str(), parameters.numAtoms, parameters.numSteps,
-                parameters.numTCoupleGroups, parameters.nstpcouple == 0 ? "without" : "with",
-                parameters.timestep, parameters.v[XX], parameters.v[YY], parameters.v[ZZ],
-                parameters.f[XX], parameters.f[YY], parameters.f[ZZ], parameters.nstpcouple);
+                runner->hardwareDescription().c_str(),
+                parameters.numAtoms,
+                parameters.numSteps,
+                parameters.numTCoupleGroups,
+                parameters.nstpcouple == 0 ? "without" : "with",
+                parameters.timestep,
+                parameters.v[XX],
+                parameters.v[YY],
+                parameters.v[ZZ],
+                parameters.f[XX],
+                parameters.f[YY],
+                parameters.f[ZZ],
+                parameters.nstpcouple);
         SCOPED_TRACE(testDescription);
 
-        std::unique_ptr<LeapFrogTestData> testData = std::make_unique<LeapFrogTestData>(
-                parameters.numAtoms, parameters.timestep, parameters.v, parameters.f,
-                parameters.numTCoupleGroups, parameters.nstpcouple);
+        std::unique_ptr<LeapFrogTestData> testData =
+                std::make_unique<LeapFrogTestData>(parameters.numAtoms,
+                                                   parameters.timestep,
+                                                   parameters.v,
+                                                   parameters.f,
+                                                   parameters.numTCoupleGroups,
+                                                   parameters.nstpcouple);
 
         runner->integrate(testData.get(), parameters.numSteps);
 
index 2725e3dd0c21f7c8ad9f4c9824c7b9b6054a5192..9d1f7780be68a05a173877aad803ecd15881f374 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +83,7 @@ LeapFrogTestData::LeapFrogTestData(int        numAtoms,
     f_(numAtoms),
     inverseMasses_(numAtoms),
     inverseMassesPerDim_(numAtoms),
+    kineticEnergyData_(numTCoupleGroups == 0 ? 1 : numTCoupleGroups, 0.0, 1),
     numTCoupleGroups_(numTCoupleGroups)
 {
     mdAtoms_.nr = numAtoms_;
@@ -123,34 +124,32 @@ LeapFrogTestData::LeapFrogTestData(int        numAtoms,
 
     if (numTCoupleGroups_ == 0)
     {
-        inputRecord_.etc = etcNO;
+        inputRecord_.etc = TemperatureCoupling::No;
         for (int i = 0; i < numAtoms_; i++)
         {
             mdAtoms_.cTC[i] = 0;
         }
-        kineticEnergyData_.ngtc = 1;
         t_grp_tcstat temperatureCouplingGroupData;
         temperatureCouplingGroupData.lambda = 1.0;
-        kineticEnergyData_.tcstat.emplace_back(temperatureCouplingGroupData);
+        kineticEnergyData_.tcstat[0]        = temperatureCouplingGroupData;
     }
     else
     {
-        inputRecord_.etc = etcYES;
+        inputRecord_.etc = TemperatureCoupling::Yes;
         for (int i = 0; i < numAtoms_; i++)
         {
             mdAtoms_.cTC[i] = i % numTCoupleGroups_;
         }
-        kineticEnergyData_.ngtc = numTCoupleGroups_;
-        for (int i = 0; i < numTCoupleGroups; i++)
+        for (int i = 0; i < numTCoupleGroups_; i++)
         {
             real         tCoupleLambda = 1.0 - (i + 1.0) / 10.0;
             t_grp_tcstat temperatureCouplingGroupData;
             temperatureCouplingGroupData.lambda = tCoupleLambda;
-            kineticEnergyData_.tcstat.emplace_back(temperatureCouplingGroupData);
+            kineticEnergyData_.tcstat[i]        = temperatureCouplingGroupData;
         }
     }
 
-    inputRecord_.eI      = eiMD;
+    inputRecord_.eI      = IntegrationAlgorithm::MD;
     inputRecord_.delta_t = timestep_;
 
     state_.flags = 0;
@@ -167,27 +166,21 @@ LeapFrogTestData::LeapFrogTestData(int        numAtoms,
     state_.box[ZZ][YY] = 0.0;
     state_.box[ZZ][ZZ] = 10.0;
 
-    kineticEnergyData_.bNEMD            = false;
-    kineticEnergyData_.cosacc.cos_accel = 0.0;
-
-    kineticEnergyData_.nthreads = 1;
-    snew(kineticEnergyData_.ekin_work_alloc, kineticEnergyData_.nthreads);
-    snew(kineticEnergyData_.ekin_work, kineticEnergyData_.nthreads);
-    snew(kineticEnergyData_.dekindl_work, kineticEnergyData_.nthreads);
-
     mdAtoms_.homenr                   = numAtoms_;
     mdAtoms_.haveVsites               = false;
     mdAtoms_.havePartiallyFrozenAtoms = false;
     mdAtoms_.cFREEZE                  = nullptr;
 
     update_ = std::make_unique<Update>(inputRecord_, nullptr);
-    update_->setNumAtoms(numAtoms);
+    update_->updateAfterPartition(numAtoms,
+                                  gmx::ArrayRef<const unsigned short>(),
+                                  gmx::arrayRefFromArray(mdAtoms_.cTC, mdAtoms_.nr));
 
     doPressureCouple_ = (nstpcouple != 0);
 
     if (doPressureCouple_)
     {
-        inputRecord_.epc        = epcPARRINELLORAHMAN;
+        inputRecord_.epc        = PressureCoupling::ParrinelloRahman;
         inputRecord_.nstpcouple = nstpcouple;
         dtPressureCouple_       = inputRecord_.nstpcouple * inputRecord_.delta_t;
 
@@ -205,7 +198,7 @@ LeapFrogTestData::LeapFrogTestData(int        numAtoms,
     }
     else
     {
-        inputRecord_.epc               = epcNO;
+        inputRecord_.epc               = PressureCoupling::No;
         velocityScalingMatrix_[XX][XX] = 1.0;
         velocityScalingMatrix_[XX][YY] = 0.0;
         velocityScalingMatrix_[XX][ZZ] = 0.0;
index a9739e602830dd0e3159390fd445f0037cefdddc..a82d9fc9e797674f32c1b0ec3ee091b9d9ab8285 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,16 +67,38 @@ void LeapFrogHostTestRunner::integrate(LeapFrogTestData* testData, int numSteps)
         testData->state_.v[i] = testData->v_[i];
     }
 
-    gmx_omp_nthreads_set(emntUpdate, 1);
+    gmx_omp_nthreads_set(ModuleMultiThread::Update, 1);
 
     for (int step = 0; step < numSteps; step++)
     {
         testData->update_->update_coords(
-                testData->inputRecord_, step, &testData->mdAtoms_, &testData->state_, testData->f_,
-                testData->forceCalculationData_, &testData->kineticEnergyData_,
-                testData->velocityScalingMatrix_, etrtNONE, nullptr, false);
-        testData->update_->finish_update(testData->inputRecord_, &testData->mdAtoms_,
-                                         &testData->state_, nullptr, false);
+                testData->inputRecord_,
+                step,
+                testData->mdAtoms_.homenr,
+                testData->mdAtoms_.havePartiallyFrozenAtoms,
+                testData->mdAtoms_.ptype
+                        ? gmx::arrayRefFromArray(testData->mdAtoms_.ptype, testData->mdAtoms_.nr)
+                        : gmx::ArrayRef<ParticleType>{},
+                testData->mdAtoms_.invmass
+                        ? gmx::arrayRefFromArray(testData->mdAtoms_.invmass, testData->mdAtoms_.nr)
+                        : gmx::ArrayRef<real>{},
+                testData->mdAtoms_.invMassPerDim ? gmx::arrayRefFromArray(testData->mdAtoms_.invMassPerDim,
+                                                                          testData->mdAtoms_.nr)
+                                                 : gmx::ArrayRef<rvec>{},
+                &testData->state_,
+                testData->f_,
+                testData->forceCalculationData_,
+                &testData->kineticEnergyData_,
+                testData->velocityScalingMatrix_,
+                etrtNONE,
+                nullptr,
+                false);
+        testData->update_->finish_update(testData->inputRecord_,
+                                         testData->mdAtoms_.havePartiallyFrozenAtoms,
+                                         testData->mdAtoms_.homenr,
+                                         &testData->state_,
+                                         nullptr,
+                                         false);
     }
     const auto xp = makeArrayRef(*testData->update_->xp()).subArray(0, testData->numAtoms_);
     for (int i = 0; i < testData->numAtoms_; i++)
index 7590aa2dfa3cbdae7733a8e9ed457401d5058e75..37810d22dc4cf8baf10640c03791367dd0496d1d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "leapfrogtestdata.h"
 
+/*
+ * LeapFrog is available with CUDA and SYCL.
+ */
 #define HAVE_GPU_LEAPFROG (GMX_GPU_CUDA || GMX_GPU_SYCL)
 
 namespace gmx
index 1e102035d6cd2d1ef65ead3dada1416688031fef..97c9c2948125f4cc3b588cdb78506a5d13b02628 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +59,7 @@
 #    include "gromacs/mdlib/leapfrog_gpu.h"
 #endif
 
+#include "gromacs/gpu_utils/gputraits.h"
 #include "gromacs/hardware/device_information.h"
 #include "gromacs/mdlib/stat.h"
 
@@ -76,14 +77,12 @@ void LeapFrogDeviceTestRunner::integrate(LeapFrogTestData* testData, int numStep
 
     int numAtoms = testData->numAtoms_;
 
-    static_assert(sizeof(float3) == sizeof(*testData->x_.data()), "Incompatible types");
+    Float3* h_x  = gmx::asGenericFloat3Pointer(testData->x_);
+    Float3* h_xp = gmx::asGenericFloat3Pointer(testData->xPrime_);
+    Float3* h_v  = gmx::asGenericFloat3Pointer(testData->v_);
+    Float3* h_f  = gmx::asGenericFloat3Pointer(testData->f_);
 
-    float3* h_x  = reinterpret_cast<float3*>(testData->x_.data());
-    float3* h_xp = reinterpret_cast<float3*>(testData->xPrime_.data());
-    float3* h_v  = reinterpret_cast<float3*>(testData->v_.data());
-    float3* h_f  = reinterpret_cast<float3*>(testData->f_.data());
-
-    DeviceBuffer<float3> d_x, d_xp, d_v, d_f;
+    DeviceBuffer<Float3> d_x, d_xp, d_v, d_f;
 
     allocateDeviceBuffer(&d_x, numAtoms, deviceContext);
     allocateDeviceBuffer(&d_xp, numAtoms, deviceContext);
@@ -95,10 +94,10 @@ void LeapFrogDeviceTestRunner::integrate(LeapFrogTestData* testData, int numStep
     copyToDeviceBuffer(&d_v, h_v, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
     copyToDeviceBuffer(&d_f, h_f, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
 
-    auto integrator = std::make_unique<LeapFrogGpu>(deviceContext, deviceStream);
+    auto integrator =
+            std::make_unique<LeapFrogGpu>(deviceContext, deviceStream, testData->numTCoupleGroups_);
 
-    integrator->set(testData->numAtoms_, testData->inverseMasses_.data(),
-                    testData->numTCoupleGroups_, testData->mdAtoms_.cTC);
+    integrator->set(testData->numAtoms_, testData->inverseMasses_.data(), testData->mdAtoms_.cTC);
 
     bool doTempCouple = testData->numTCoupleGroups_ > 0;
     for (int step = 0; step < numSteps; step++)
@@ -107,9 +106,16 @@ void LeapFrogDeviceTestRunner::integrate(LeapFrogTestData* testData, int numStep
         bool doPressureCouple = testData->doPressureCouple_
                                 && do_per_step(step + testData->inputRecord_.nstpcouple - 1,
                                                testData->inputRecord_.nstpcouple);
-        integrator->integrate(d_x, d_xp, d_v, d_f, testData->timestep_, doTempCouple,
-                              testData->kineticEnergyData_.tcstat, doPressureCouple,
-                              testData->dtPressureCouple_, testData->velocityScalingMatrix_);
+        integrator->integrate(d_x,
+                              d_xp,
+                              d_v,
+                              d_f,
+                              testData->timestep_,
+                              doTempCouple,
+                              testData->kineticEnergyData_.tcstat,
+                              doPressureCouple,
+                              testData->dtPressureCouple_,
+                              testData->velocityScalingMatrix_);
     }
 
     copyFromDeviceBuffer(h_xp, &d_x, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
diff --git a/src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAllAtomsInBox.xml b/src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAllAtomsInBox.xml
new file mode 100644 (file)
index 0000000..a5fae73
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Vector Name="Virial x">
+    <Real Name="X">-3.4500000000000002</Real>
+    <Real Name="Y">-5.2999999999999998</Real>
+    <Real Name="Z">-2.9499999999999997</Real>
+  </Vector>
+  <Vector Name="Virial y">
+    <Real Name="X">-6.1500000000000004</Real>
+    <Real Name="Y">-7.5999999999999996</Real>
+    <Real Name="Z">-4.7000000000000002</Real>
+  </Vector>
+  <Vector Name="Virial z">
+    <Real Name="X">-8.8500000000000014</Real>
+    <Real Name="Y">-9.9000000000000004</Real>
+    <Real Name="Z">-6.4500000000000002</Real>
+  </Vector>
+</ReferenceData>
diff --git a/src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAllAtomsInBoxScrew.xml b/src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAllAtomsInBoxScrew.xml
new file mode 100644 (file)
index 0000000..a30fc18
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Vector Name="Virial x">
+    <Real Name="X">-9.9500000000000011</Real>
+    <Real Name="Y">-12.299999999999999</Real>
+    <Real Name="Z">-6.9499999999999993</Real>
+  </Vector>
+  <Vector Name="Virial y">
+    <Real Name="X">-13.950000000000001</Real>
+    <Real Name="Y">-16</Real>
+    <Real Name="Z">-9.5</Real>
+  </Vector>
+  <Vector Name="Virial z">
+    <Real Name="X">-17.949999999999999</Real>
+    <Real Name="Y">-19.699999999999999</Real>
+    <Real Name="Z">-12.050000000000001</Real>
+  </Vector>
+</ReferenceData>
diff --git a/src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAtomsOutOfBoxScrewX.xml b/src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAtomsOutOfBoxScrewX.xml
new file mode 100644 (file)
index 0000000..0e04480
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Vector Name="Virial x">
+    <Real Name="X">-6.7000000000000002</Real>
+    <Real Name="Y">-8.7999999999999989</Real>
+    <Real Name="Z">-4.9499999999999993</Real>
+  </Vector>
+  <Vector Name="Virial y">
+    <Real Name="X">-12.65</Real>
+    <Real Name="Y">-14.6</Real>
+    <Real Name="Z">-8.6999999999999993</Real>
+  </Vector>
+  <Vector Name="Virial z">
+    <Real Name="X">-16.649999999999999</Real>
+    <Real Name="Y">-18.300000000000001</Real>
+    <Real Name="Z">-11.25</Real>
+  </Vector>
+</ReferenceData>
diff --git a/src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAtomsOutOfBoxScrewXYZ.xml b/src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAtomsOutOfBoxScrewXYZ.xml
new file mode 100644 (file)
index 0000000..2ba024b
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Vector Name="Virial x">
+    <Real Name="X">-6.0499999999999998</Real>
+    <Real Name="Y">-8.0999999999999996</Real>
+    <Real Name="Z">-4.5499999999999998</Real>
+  </Vector>
+  <Vector Name="Virial y">
+    <Real Name="X">-9.4000000000000004</Real>
+    <Real Name="Y">-11.1</Real>
+    <Real Name="Z">-6.7000000000000002</Real>
+  </Vector>
+  <Vector Name="Virial z">
+    <Real Name="X">-12.75</Real>
+    <Real Name="Y">-14.1</Real>
+    <Real Name="Z">-8.8499999999999996</Real>
+  </Vector>
+</ReferenceData>
diff --git a/src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAtomsOutOfBoxScrewY.xml b/src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAtomsOutOfBoxScrewY.xml
new file mode 100644 (file)
index 0000000..9edd969
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Vector Name="Virial x">
+    <Real Name="X">-9.9500000000000011</Real>
+    <Real Name="Y">-12.299999999999999</Real>
+    <Real Name="Z">-6.9499999999999993</Real>
+  </Vector>
+  <Vector Name="Virial y">
+    <Real Name="X">-9.4000000000000004</Real>
+    <Real Name="Y">-11.1</Real>
+    <Real Name="Z">-6.7000000000000002</Real>
+  </Vector>
+  <Vector Name="Virial z">
+    <Real Name="X">-16.649999999999999</Real>
+    <Real Name="Y">-18.300000000000001</Real>
+    <Real Name="Z">-11.25</Real>
+  </Vector>
+</ReferenceData>
diff --git a/src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAtomsOutOfBoxScrewZ.xml b/src/gromacs/mdlib/tests/refdata/CalcvirTest_CanCalculateVirialAtomsOutOfBoxScrewZ.xml
new file mode 100644 (file)
index 0000000..26221b2
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Vector Name="Virial x">
+    <Real Name="X">-9.9500000000000011</Real>
+    <Real Name="Y">-12.299999999999999</Real>
+    <Real Name="Z">-6.9499999999999993</Real>
+  </Vector>
+  <Vector Name="Virial y">
+    <Real Name="X">-13.950000000000001</Real>
+    <Real Name="Y">-16</Real>
+    <Real Name="Z">-9.5</Real>
+  </Vector>
+  <Vector Name="Virial z">
+    <Real Name="X">-12.100000000000001</Real>
+    <Real Name="Y">-13.4</Real>
+    <Real Name="Z">-8.4499999999999993</Real>
+  </Vector>
+</ReferenceData>
index 9704ea60636b5e2cdb1a54882ac783b8c1a46e41..f100a6bc7f634178f233751ca1b5ec0038d168d8 100644 (file)
@@ -3,7 +3,7 @@
 <ReferenceData>
   <File Name="EnergyFile">
     <Sequence Name="EnergyTerms">
-      <Int Name="Length">97</Int>
+      <Int Name="Length">91</Int>
       <EnergyTerm>
         <String Name="Name">LJ-14</String>
         <String Name="Units">kJ/mol</String>
         <String Name="Name">T-Lipid</String>
         <String Name="Units">K</String>
       </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
     </Sequence>
     <Sequence Name="Frames">
       <Int Name="Length">1</Int>
         <String Name="Step">0</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">97</Int>
+          <Int Name="Length">91</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">11.499999999999995</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">18.000000000000007</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">18.20000000000001</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">18.300000000000011</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">18.400000000000013</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">18.500000000000014</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">18.600000000000016</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">18.700000000000017</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
     </Sequence>
   </File>
-  <Int Name="Number of Energy Terms">97</Int>
+  <Int Name="Number of Energy Terms">91</Int>
   <String Name="log">Current ref_t for group Water:     25.7
 Current ref_t for group Lipid:     25.8
 
@@ -865,9 +817,5 @@ Protein-Protein    1.31000e+01    1.32000e+01    1.34000e+01    1.35000e+01
       T-Protein        T-Water        T-Lipid
     1.76000e+01    1.78000e+01    1.80000e+01
 
-          Group             Ux             Uy             Uz
-        Protein    1.82000e+01    1.83000e+01    1.84000e+01
-          Lipid    1.85000e+01    1.86000e+01    1.87000e+01
-
 </String>
 </ReferenceData>
index 20cd6bec07c053852f4b0af4e27820679d124317..ac633a45670daae61c543c9e4443e3bed91ac59c 100644 (file)
@@ -3,7 +3,7 @@
 <ReferenceData>
   <File Name="EnergyFile">
     <Sequence Name="EnergyTerms">
-      <Int Name="Length">51</Int>
+      <Int Name="Length">45</Int>
       <EnergyTerm>
         <String Name="Name">LJ-14</String>
         <String Name="Units">kJ/mol</String>
         <String Name="Name">LJ-14:Lipid-Lipid</String>
         <String Name="Units">kJ/mol</String>
       </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
     </Sequence>
     <Sequence Name="Frames">
       <Int Name="Length">1</Int>
         <String Name="Step">0</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">51</Int>
+          <Int Name="Length">45</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">11.499999999999995</Real>
             <String Name="Name">LJ-14:Lipid-Lipid</String>
             <Real Name="Value">17.5</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">18.20000000000001</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">18.300000000000011</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">18.400000000000013</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">18.500000000000014</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">18.600000000000016</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">18.700000000000017</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
     </Sequence>
   </File>
-  <Int Name="Number of Energy Terms">51</Int>
+  <Int Name="Number of Energy Terms">45</Int>
   <String Name="log">Current ref_t for group Water:     25.7
 Current ref_t for group Lipid:     25.8
 
@@ -470,9 +422,5 @@ Protein-Protein    1.31000e+01    1.32000e+01    1.34000e+01    1.35000e+01
     Water-Lipid    1.56000e+01    1.57000e+01    1.59000e+01    1.60000e+01
     Lipid-Lipid    1.71000e+01    1.72000e+01    1.74000e+01    1.75000e+01
 
-          Group             Ux             Uy             Uz
-        Protein    1.82000e+01    1.83000e+01    1.84000e+01
-          Lipid    1.85000e+01    1.86000e+01    1.87000e+01
-
 </String>
 </ReferenceData>
index d7bf6a3dd583edab48026e0455ff426fd9e09b68..e7d41dbf15807d5e3970ec3812b5612a78654673 100644 (file)
@@ -3,7 +3,7 @@
 <ReferenceData>
   <File Name="EnergyFile">
     <Sequence Name="EnergyTerms">
-      <Int Name="Length">108</Int>
+      <Int Name="Length">102</Int>
       <EnergyTerm>
         <String Name="Name">LJ-14</String>
         <String Name="Units">kJ/mol</String>
         <String Name="Name">T-Lipid</String>
         <String Name="Units">K</String>
       </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
     </Sequence>
     <Sequence Name="Frames">
       <Int Name="Length">1</Int>
         <String Name="Step">0</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">108</Int>
+          <Int Name="Length">102</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">11.499999999999995</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">18.000000000000007</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">18.20000000000001</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">18.300000000000011</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">18.400000000000013</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">18.500000000000014</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">18.600000000000016</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">18.700000000000017</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
     </Sequence>
   </File>
-  <Int Name="Number of Energy Terms">108</Int>
+  <Int Name="Number of Energy Terms">102</Int>
   <String Name="log">Current ref_t for group Water:     25.7
 Current ref_t for group Lipid:     25.8
 
@@ -956,9 +908,5 @@ Protein-Protein    1.31000e+01    1.32000e+01    1.34000e+01    1.35000e+01
       T-Protein        T-Water        T-Lipid
     1.76000e+01    1.78000e+01    1.80000e+01
 
-          Group             Ux             Uy             Uz
-        Protein    1.82000e+01    1.83000e+01    1.84000e+01
-          Lipid    1.85000e+01    1.86000e+01    1.87000e+01
-
 </String>
 </ReferenceData>
index 9704ea60636b5e2cdb1a54882ac783b8c1a46e41..f100a6bc7f634178f233751ca1b5ec0038d168d8 100644 (file)
@@ -3,7 +3,7 @@
 <ReferenceData>
   <File Name="EnergyFile">
     <Sequence Name="EnergyTerms">
-      <Int Name="Length">97</Int>
+      <Int Name="Length">91</Int>
       <EnergyTerm>
         <String Name="Name">LJ-14</String>
         <String Name="Units">kJ/mol</String>
         <String Name="Name">T-Lipid</String>
         <String Name="Units">K</String>
       </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
     </Sequence>
     <Sequence Name="Frames">
       <Int Name="Length">1</Int>
         <String Name="Step">0</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">97</Int>
+          <Int Name="Length">91</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">11.499999999999995</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">18.000000000000007</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">18.20000000000001</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">18.300000000000011</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">18.400000000000013</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">18.500000000000014</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">18.600000000000016</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">18.700000000000017</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
     </Sequence>
   </File>
-  <Int Name="Number of Energy Terms">97</Int>
+  <Int Name="Number of Energy Terms">91</Int>
   <String Name="log">Current ref_t for group Water:     25.7
 Current ref_t for group Lipid:     25.8
 
@@ -865,9 +817,5 @@ Protein-Protein    1.31000e+01    1.32000e+01    1.34000e+01    1.35000e+01
       T-Protein        T-Water        T-Lipid
     1.76000e+01    1.78000e+01    1.80000e+01
 
-          Group             Ux             Uy             Uz
-        Protein    1.82000e+01    1.83000e+01    1.84000e+01
-          Lipid    1.85000e+01    1.86000e+01    1.87000e+01
-
 </String>
 </ReferenceData>
index 3484d5fcbb472a9b2ff3c10e8190477d8e80aae4..5376fc9a0aa6db0b9683020f03b1523218befeda 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
 <ReferenceData>
-  <Int Name="Number of Energy Terms">97</Int>
+  <Int Name="Number of Energy Terms">91</Int>
   <String Name="log">Current ref_t for group Water:      0.0
 Current ref_t for group Lipid:      0.0
 
index 783bbe699a520ec40b3b43dbba410745c1c4f6ce..efc4d8958ba513cf04a005cd11fe1cb1da9be23f 100644 (file)
@@ -3,7 +3,7 @@
 <ReferenceData>
   <File Name="EnergyFile">
     <Sequence Name="EnergyTerms">
-      <Int Name="Length">97</Int>
+      <Int Name="Length">91</Int>
       <EnergyTerm>
         <String Name="Name">LJ-14</String>
         <String Name="Units">kJ/mol</String>
         <String Name="Name">T-Lipid</String>
         <String Name="Units">K</String>
       </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
     </Sequence>
     <Sequence Name="Frames">
       <Int Name="Length">10</Int>
         <String Name="Step">0</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">97</Int>
+          <Int Name="Length">91</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">11.499999999999995</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">18.000000000000007</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">18.20000000000001</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">18.300000000000011</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">18.400000000000013</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">18.500000000000014</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">18.600000000000016</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">18.700000000000017</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
       <Frame>
         <String Name="Step">100</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">97</Int>
+          <Int Name="Length">91</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">28.900000000000162</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">35.400000000000254</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">35.600000000000257</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">35.700000000000259</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">35.80000000000026</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">35.900000000000261</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">36.000000000000263</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">36.100000000000264</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
       <Frame>
         <String Name="Step">200</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">97</Int>
+          <Int Name="Length">91</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">46.300000000000409</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">52.800000000000502</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">53.000000000000504</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">53.100000000000506</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">53.200000000000507</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">53.300000000000509</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">53.40000000000051</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">53.500000000000512</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
       <Frame>
         <String Name="Step">300</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">97</Int>
+          <Int Name="Length">91</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">63.700000000000657</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">70.200000000000301</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">70.40000000000029</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">70.500000000000284</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">70.600000000000279</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">70.700000000000273</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">70.800000000000267</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">70.900000000000261</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
       <Frame>
         <String Name="Step">400</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">97</Int>
+          <Int Name="Length">91</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">81.099999999999682</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">87.599999999999312</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">87.799999999999301</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">87.899999999999295</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">87.999999999999289</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">88.099999999999284</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">88.199999999999278</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">88.299999999999272</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
       <Frame>
         <String Name="Step">500</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">97</Int>
+          <Int Name="Length">91</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">98.499999999998693</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">104.99999999999832</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">105.19999999999831</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">105.29999999999831</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">105.3999999999983</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">105.49999999999829</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">105.59999999999829</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">105.69999999999828</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
       <Frame>
         <String Name="Step">600</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">97</Int>
+          <Int Name="Length">91</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">115.8999999999977</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">122.39999999999733</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">122.59999999999732</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">122.69999999999732</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">122.79999999999731</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">122.89999999999731</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">122.9999999999973</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">123.09999999999729</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
       <Frame>
         <String Name="Step">700</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">97</Int>
+          <Int Name="Length">91</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">133.29999999999671</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">139.79999999999634</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">139.99999999999633</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">140.09999999999633</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">140.19999999999632</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">140.29999999999632</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">140.39999999999631</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">140.49999999999631</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
       <Frame>
         <String Name="Step">800</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">97</Int>
+          <Int Name="Length">91</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">150.69999999999573</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">157.19999999999536</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">157.39999999999534</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">157.49999999999534</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">157.59999999999533</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">157.69999999999533</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">157.79999999999532</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">157.89999999999532</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
       <Frame>
         <String Name="Step">900</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">97</Int>
+          <Int Name="Length">91</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">168.09999999999474</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">174.59999999999437</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">174.79999999999436</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">174.89999999999435</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">174.99999999999434</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">175.09999999999434</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">175.19999999999433</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">175.29999999999433</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
     </Sequence>
   </File>
-  <Int Name="Number of Energy Terms">97</Int>
+  <Int Name="Number of Energy Terms">91</Int>
   <String Name="log">Current ref_t for group Water:     25.7
 Current ref_t for group Lipid:     25.8
 
@@ -4573,9 +4309,5 @@ Protein-Protein    9.14000e+01    9.15000e+01    9.17000e+01    9.18000e+01
       T-Protein        T-Water        T-Lipid
     9.59000e+01    9.61000e+01    9.63000e+01
 
-          Group             Ux             Uy             Uz
-        Protein    9.65000e+01    9.66000e+01    9.67000e+01
-          Lipid    9.68000e+01    9.69000e+01    9.70000e+01
-
 </String>
 </ReferenceData>
index 0fcc9ee95f8b30fbd9c8a7a108386eab617b6ed8..43e5ca6aebdd78614ced6d2f383ab05db698dbae 100644 (file)
@@ -3,7 +3,7 @@
 <ReferenceData>
   <File Name="EnergyFile">
     <Sequence Name="EnergyTerms">
-      <Int Name="Length">101</Int>
+      <Int Name="Length">95</Int>
       <EnergyTerm>
         <String Name="Name">LJ-14</String>
         <String Name="Units">kJ/mol</String>
         <String Name="Name">Lamb-Lipid</String>
         <String Name="Units"></String>
       </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
     </Sequence>
     <Sequence Name="Frames">
       <Int Name="Length">1</Int>
         <String Name="Step">0</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">101</Int>
+          <Int Name="Length">95</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">11.499999999999995</Real>
             <String Name="Name">Lamb-Lipid</String>
             <Real Name="Value">18.100000000000009</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">18.20000000000001</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">18.300000000000011</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">18.400000000000013</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">18.500000000000014</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">18.600000000000016</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">18.700000000000017</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
     </Sequence>
   </File>
-  <Int Name="Number of Energy Terms">101</Int>
+  <Int Name="Number of Energy Terms">95</Int>
   <String Name="log">Current ref_t for group Water:     25.7
 Current ref_t for group Lipid:     25.8
 
@@ -897,9 +849,5 @@ Protein-Protein    1.31000e+01    1.32000e+01    1.34000e+01    1.35000e+01
       T-Protein        T-Water        T-Lipid
     1.76000e+01    1.78000e+01    1.80000e+01
 
-          Group             Ux             Uy             Uz
-        Protein    1.82000e+01    1.83000e+01    1.84000e+01
-          Lipid    1.85000e+01    1.86000e+01    1.87000e+01
-
 </String>
 </ReferenceData>
index 03554d894a5d8624bd5c42f9cf4ef24ac8e7858a..73ca7a122f4a3c76105b6f297b31dbff8bdc3c23 100644 (file)
@@ -3,7 +3,7 @@
 <ReferenceData>
   <File Name="EnergyFile">
     <Sequence Name="EnergyTerms">
-      <Int Name="Length">104</Int>
+      <Int Name="Length">98</Int>
       <EnergyTerm>
         <String Name="Name">LJ-14</String>
         <String Name="Units">kJ/mol</String>
         <String Name="Name">vXi-Lipid</String>
         <String Name="Units">1/ps</String>
       </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
     </Sequence>
     <Sequence Name="Frames">
       <Int Name="Length">1</Int>
         <String Name="Step">0</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">104</Int>
+          <Int Name="Length">98</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">11.499999999999995</Real>
             <String Name="Name">vXi-Lipid</String>
             <Real Name="Value">26.400000000000126</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">18.20000000000001</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">18.300000000000011</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">18.400000000000013</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">18.500000000000014</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">18.600000000000016</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">18.700000000000017</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
     </Sequence>
   </File>
-  <Int Name="Number of Energy Terms">104</Int>
+  <Int Name="Number of Energy Terms">98</Int>
   <String Name="log">Current ref_t for group Water:     25.7
 Current ref_t for group Lipid:     25.8
 
@@ -921,9 +873,5 @@ Protein-Protein    1.31000e+01    1.32000e+01    1.34000e+01    1.35000e+01
       T-Protein        T-Water        T-Lipid
     1.76000e+01    1.78000e+01    1.80000e+01
 
-          Group             Ux             Uy             Uz
-        Protein    1.82000e+01    1.83000e+01    1.84000e+01
-          Lipid    1.85000e+01    1.86000e+01    1.87000e+01
-
 </String>
 </ReferenceData>
index d7bf6a3dd583edab48026e0455ff426fd9e09b68..e7d41dbf15807d5e3970ec3812b5612a78654673 100644 (file)
@@ -3,7 +3,7 @@
 <ReferenceData>
   <File Name="EnergyFile">
     <Sequence Name="EnergyTerms">
-      <Int Name="Length">108</Int>
+      <Int Name="Length">102</Int>
       <EnergyTerm>
         <String Name="Name">LJ-14</String>
         <String Name="Units">kJ/mol</String>
         <String Name="Name">T-Lipid</String>
         <String Name="Units">K</String>
       </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
     </Sequence>
     <Sequence Name="Frames">
       <Int Name="Length">1</Int>
         <String Name="Step">0</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">108</Int>
+          <Int Name="Length">102</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">11.499999999999995</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">18.000000000000007</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">18.20000000000001</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">18.300000000000011</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">18.400000000000013</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">18.500000000000014</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">18.600000000000016</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">18.700000000000017</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
     </Sequence>
   </File>
-  <Int Name="Number of Energy Terms">108</Int>
+  <Int Name="Number of Energy Terms">102</Int>
   <String Name="log">Current ref_t for group Water:     25.7
 Current ref_t for group Lipid:     25.8
 
@@ -956,9 +908,5 @@ Protein-Protein    1.31000e+01    1.32000e+01    1.34000e+01    1.35000e+01
       T-Protein        T-Water        T-Lipid
     1.76000e+01    1.78000e+01    1.80000e+01
 
-          Group             Ux             Uy             Uz
-        Protein    1.82000e+01    1.83000e+01    1.84000e+01
-          Lipid    1.85000e+01    1.86000e+01    1.87000e+01
-
 </String>
 </ReferenceData>
index d7bf6a3dd583edab48026e0455ff426fd9e09b68..e7d41dbf15807d5e3970ec3812b5612a78654673 100644 (file)
@@ -3,7 +3,7 @@
 <ReferenceData>
   <File Name="EnergyFile">
     <Sequence Name="EnergyTerms">
-      <Int Name="Length">108</Int>
+      <Int Name="Length">102</Int>
       <EnergyTerm>
         <String Name="Name">LJ-14</String>
         <String Name="Units">kJ/mol</String>
         <String Name="Name">T-Lipid</String>
         <String Name="Units">K</String>
       </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
     </Sequence>
     <Sequence Name="Frames">
       <Int Name="Length">1</Int>
         <String Name="Step">0</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">108</Int>
+          <Int Name="Length">102</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">11.499999999999995</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">18.000000000000007</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">18.20000000000001</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">18.300000000000011</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">18.400000000000013</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">18.500000000000014</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">18.600000000000016</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">18.700000000000017</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
     </Sequence>
   </File>
-  <Int Name="Number of Energy Terms">108</Int>
+  <Int Name="Number of Energy Terms">102</Int>
   <String Name="log">Current ref_t for group Water:     25.7
 Current ref_t for group Lipid:     25.8
 
@@ -956,9 +908,5 @@ Protein-Protein    1.31000e+01    1.32000e+01    1.34000e+01    1.35000e+01
       T-Protein        T-Water        T-Lipid
     1.76000e+01    1.78000e+01    1.80000e+01
 
-          Group             Ux             Uy             Uz
-        Protein    1.82000e+01    1.83000e+01    1.84000e+01
-          Lipid    1.85000e+01    1.86000e+01    1.87000e+01
-
 </String>
 </ReferenceData>
index 9704ea60636b5e2cdb1a54882ac783b8c1a46e41..f100a6bc7f634178f233751ca1b5ec0038d168d8 100644 (file)
@@ -3,7 +3,7 @@
 <ReferenceData>
   <File Name="EnergyFile">
     <Sequence Name="EnergyTerms">
-      <Int Name="Length">97</Int>
+      <Int Name="Length">91</Int>
       <EnergyTerm>
         <String Name="Name">LJ-14</String>
         <String Name="Units">kJ/mol</String>
         <String Name="Name">T-Lipid</String>
         <String Name="Units">K</String>
       </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Protein</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Ux-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uy-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
-      <EnergyTerm>
-        <String Name="Name">Uz-Lipid</String>
-        <String Name="Units">nm/ps</String>
-      </EnergyTerm>
     </Sequence>
     <Sequence Name="Frames">
       <Int Name="Length">1</Int>
         <String Name="Step">0</String>
         <String Name="NumSteps">0</String>
         <Sequence Name="EnergyTerms">
-          <Int Name="Length">97</Int>
+          <Int Name="Length">91</Int>
           <EnergyTerm>
             <String Name="Name">LJ-14</String>
             <Real Name="Value">11.499999999999995</Real>
             <String Name="Name">T-Lipid</String>
             <Real Name="Value">18.000000000000007</Real>
           </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Protein</String>
-            <Real Name="Value">18.20000000000001</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Protein</String>
-            <Real Name="Value">18.300000000000011</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Protein</String>
-            <Real Name="Value">18.400000000000013</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Ux-Lipid</String>
-            <Real Name="Value">18.500000000000014</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uy-Lipid</String>
-            <Real Name="Value">18.600000000000016</Real>
-          </EnergyTerm>
-          <EnergyTerm>
-            <String Name="Name">Uz-Lipid</String>
-            <Real Name="Value">18.700000000000017</Real>
-          </EnergyTerm>
         </Sequence>
       </Frame>
     </Sequence>
   </File>
-  <Int Name="Number of Energy Terms">97</Int>
+  <Int Name="Number of Energy Terms">91</Int>
   <String Name="log">Current ref_t for group Water:     25.7
 Current ref_t for group Lipid:     25.8
 
@@ -865,9 +817,5 @@ Protein-Protein    1.31000e+01    1.32000e+01    1.34000e+01    1.35000e+01
       T-Protein        T-Water        T-Lipid
     1.76000e+01    1.78000e+01    1.80000e+01
 
-          Group             Ux             Uy             Uz
-        Protein    1.82000e+01    1.83000e+01    1.84000e+01
-          Lipid    1.85000e+01    1.86000e+01    1.87000e+01
-
 </String>
 </ReferenceData>
index e565b52848700f347d30fa0dbaf5213a092be50f..1d71b0f420ebd3e0ef9afcca20c047cce0c8e031 100644 (file)
@@ -335,8 +335,11 @@ TEST_P(SettleTest, SatisfiesConstraints)
         // being tested, to help make failing tests comprehensible.
         std::string testDescription = formatString(
                 "Testing %s with %d SETTLEs, %s, %svelocities and %scalculating the virial.",
-                runner->hardwareDescription().c_str(), numSettles, pbcName.c_str(),
-                updateVelocities ? "with " : "without ", calcVirial ? "" : "not ");
+                runner->hardwareDescription().c_str(),
+                numSettles,
+                pbcName.c_str(),
+                updateVelocities ? "with " : "without ",
+                calcVirial ? "" : "not ");
 
         SCOPED_TRACE(testDescription);
 
index cfc2b0ca20ae3142340d0227573141337487ebb7..c494341cc2b836967ee24222176d6fc2d1e4a910 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -65,16 +65,23 @@ void SettleHostTestRunner::applySettle(SettleTestData*    testData,
 {
     SettleData settled(testData->mtop_);
 
-    settled.setConstraints(testData->idef_->il[F_SETTLE], testData->numAtoms_,
-                           testData->masses_.data(), testData->inverseMasses_.data());
+    settled.setConstraints(
+            testData->idef_->il[F_SETTLE], testData->numAtoms_, testData->masses_, testData->inverseMasses_);
 
     bool errorOccured;
     int  numThreads  = 1;
     int  threadIndex = 0;
-    csettle(settled, numThreads, threadIndex, &pbc, testData->x_.arrayRefWithPadding(),
-            testData->xPrime_.arrayRefWithPadding(), testData->reciprocalTimeStep_,
+    csettle(settled,
+            numThreads,
+            threadIndex,
+            &pbc,
+            testData->x_.arrayRefWithPadding(),
+            testData->xPrime_.arrayRefWithPadding(),
+            testData->reciprocalTimeStep_,
             updateVelocities ? testData->v_.arrayRefWithPadding() : ArrayRefWithPadding<RVec>(),
-            calcVirial, testData->virial_, &errorOccured);
+            calcVirial,
+            testData->virial_,
+            &errorOccured);
     EXPECT_FALSE(errorOccured) << testDescription;
 }
 
index 1200626ad07dc69cfe97eb3cc8a60b9e65f5048f..b35cf0be9b03ec11643c6896b127fba61dcdcfc2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 @@
 #include <vector>
 
 #include "gromacs/gpu_utils/devicebuffer.cuh"
+#include "gromacs/gpu_utils/gputraits.h"
 #include "gromacs/hardware/device_information.h"
-#include "gromacs/mdlib/settle_gpu.cuh"
+#include "gromacs/mdlib/settle_gpu.h"
 #include "gromacs/utility/unique_cptr.h"
 
 #include "testutils/test_device.h"
@@ -85,30 +86,29 @@ void SettleDeviceTestRunner::applySettle(SettleTestData* testData,
 
     int numAtoms = testData->numAtoms_;
 
-    float3 *d_x, *d_xp, *d_v;
+    DeviceBuffer<Float3> d_x, d_xp, d_v;
 
-    float3* h_x  = (float3*)(as_rvec_array(testData->x_.data()));
-    float3* h_xp = (float3*)(as_rvec_array(testData->xPrime_.data()));
-    float3* h_v  = (float3*)(as_rvec_array(testData->v_.data()));
+    Float3* h_x  = gmx::asGenericFloat3Pointer(testData->x_);
+    Float3* h_xp = gmx::asGenericFloat3Pointer(testData->xPrime_);
+    Float3* h_v  = gmx::asGenericFloat3Pointer(testData->v_);
 
     allocateDeviceBuffer(&d_x, numAtoms, deviceContext);
     allocateDeviceBuffer(&d_xp, numAtoms, deviceContext);
     allocateDeviceBuffer(&d_v, numAtoms, deviceContext);
 
-    copyToDeviceBuffer(&d_x, (float3*)h_x, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
-    copyToDeviceBuffer(&d_xp, (float3*)h_xp, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
+    copyToDeviceBuffer(&d_x, h_x, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
+    copyToDeviceBuffer(&d_xp, h_xp, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
     if (updateVelocities)
     {
-        copyToDeviceBuffer(&d_v, (float3*)h_v, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
+        copyToDeviceBuffer(&d_v, h_v, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
     }
-    settleGpu->apply(d_x, d_xp, updateVelocities, d_v, testData->reciprocalTimeStep_, calcVirial,
-                     testData->virial_, pbcAiuc);
+    settleGpu->apply(
+            d_x, d_xp, updateVelocities, d_v, testData->reciprocalTimeStep_, calcVirial, testData->virial_, pbcAiuc);
 
-    copyFromDeviceBuffer((float3*)h_xp, &d_xp, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
+    copyFromDeviceBuffer(h_xp, &d_xp, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
     if (updateVelocities)
     {
-        copyFromDeviceBuffer((float3*)h_v, &d_v, 0, numAtoms, deviceStream,
-                             GpuApiCallBehavior::Sync, nullptr);
+        copyFromDeviceBuffer(h_v, &d_v, 0, numAtoms, deviceStream, GpuApiCallBehavior::Sync, nullptr);
     }
 
     freeDeviceBuffer(&d_x);
index 4d29a38f918463e1e1e34f77a84e775897f94211..7f58294382fc033278734f35bfb22a0d68a67778 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -195,10 +195,20 @@ public:
         int               numIterations  = 0;
         int               numErrors      = 0;
 
-        cshake(iatom.data(), numConstraints, &numIterations, ShakeTest::maxNumIterations_,
-               constrainedDistancesSquared, finalPositions, nullptr, initialDisplacements,
-               halfOfReducedMasses, omega_, inverseMasses.data(), distanceSquaredTolerances,
-               lagrangianValues, &numErrors);
+        cshake(iatom.data(),
+               numConstraints,
+               &numIterations,
+               ShakeTest::maxNumIterations_,
+               constrainedDistancesSquared,
+               finalPositions,
+               nullptr,
+               initialDisplacements,
+               halfOfReducedMasses,
+               omega_,
+               inverseMasses,
+               distanceSquaredTolerances,
+               lagrangianValues,
+               &numErrors);
 
         std::vector<RVec> finalDisplacements    = computeDisplacements(iatom, finalPositions);
         std::vector<real> finalDistancesSquared = computeDistancesSquared(finalDisplacements);
@@ -218,7 +228,8 @@ public:
                                             + coordMax * GMX_REAL_EPS);
             // Assert that the constrained distances are within the required tolerance
             EXPECT_FLOAT_EQ_TOL(std::sqrt(constrainedDistancesSquared[i]),
-                                std::sqrt(finalDistancesSquared[i]), constraintTolerance);
+                                std::sqrt(finalDistancesSquared[i]),
+                                constraintTolerance);
         }
     }
 
index ff2c420f3aa1b277e83c7e4a0be5bb7f082db5d1..4b75b16a99971991a73a105afdf7c6c4e10de37e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -145,183 +145,228 @@ gmx_moltype_t waterFlexAngle()
     return moltype;
 }
 
-TEST(UpdateGroups, ethaneUA)
+//! Test fixture class
+class UpdateGroupsTest : public ::testing::Test
 {
-    gmx_mtop_t mtop;
-
-    mtop.moltype.emplace_back(ethaneUA());
-    t_iparams iparams;
-    iparams.constr = { 0.3, 0.3 };
-    mtop.ffparams.iparams.push_back(iparams);
+public:
+    //! Global toplogy to use in tests
+    gmx_mtop_t mtop_;
+    //! Default temperature for tests
+    real temperature_ = 298;
+};
+
+TEST_F(UpdateGroupsTest, WithEthaneUA)
+{
+    mtop_.moltype.emplace_back(ethaneUA());
+    {
+        t_iparams iparams;
+        iparams.constr = { 0.3, 0.3 };
+        mtop_.ffparams.iparams.push_back(iparams);
+    }
 
-    auto updateGroups = gmx::makeUpdateGroups(mtop);
+    auto updateGroupingsPerMoleculeType = gmx::makeUpdateGroupingsPerMoleculeType(mtop_);
 
-    ASSERT_EQ(updateGroups.size(), 1);
-    EXPECT_EQ(updateGroups[0].numBlocks(), 1);
+    ASSERT_EQ(updateGroupingsPerMoleculeType.size(), 1);
+    EXPECT_EQ(updateGroupingsPerMoleculeType[0].numBlocks(), 1);
 
-    real temperature = 298;
-    real maxRadius   = computeMaxUpdateGroupRadius(mtop, updateGroups, temperature);
+    real maxRadius = computeMaxUpdateGroupRadius(mtop_, updateGroupingsPerMoleculeType, temperature_);
     EXPECT_FLOAT_EQ(maxRadius, 0.3 / 2);
 }
 
-TEST(UpdateGroups, methane)
+TEST_F(UpdateGroupsTest, WithMethane)
 {
-    gmx_mtop_t mtop;
-
-    mtop.moltype.emplace_back(methane());
-    t_iparams iparams;
-    iparams.constr = { 0.1, 0.1 };
-    mtop.ffparams.iparams.push_back(iparams);
+    mtop_.moltype.emplace_back(methane());
+    {
+        t_iparams iparams;
+        iparams.constr = { 0.1, 0.1 };
+        mtop_.ffparams.iparams.push_back(iparams);
+    }
 
-    auto updateGroups = gmx::makeUpdateGroups(mtop);
+    auto updateGroupingsPerMoleculeType = gmx::makeUpdateGroupingsPerMoleculeType(mtop_);
 
-    ASSERT_EQ(updateGroups.size(), 1);
-    EXPECT_EQ(updateGroups[0].numBlocks(), 1);
+    ASSERT_EQ(updateGroupingsPerMoleculeType.size(), 1);
+    EXPECT_EQ(updateGroupingsPerMoleculeType[0].numBlocks(), 1);
 
-    real temperature = 298;
-    real maxRadius   = computeMaxUpdateGroupRadius(mtop, updateGroups, temperature);
+    real maxRadius = computeMaxUpdateGroupRadius(mtop_, updateGroupingsPerMoleculeType, temperature_);
     EXPECT_FLOAT_EQ(maxRadius, 0.14);
 }
-TEST(UpdateGroups, ethane)
+TEST_F(UpdateGroupsTest, WithEthane)
 {
-    gmx_mtop_t mtop;
+    mtop_.moltype.emplace_back(ethane());
+    {
+        t_iparams iparams;
+        iparams.constr = { 0.1, 0.1 };
+        mtop_.ffparams.iparams.push_back(iparams);
+        iparams.harmonic = { 107.800, 276.144, 107.800, 276.144 };
+        mtop_.ffparams.iparams.push_back(iparams);
+    }
+
+    auto updateGroupingsPerMoleculeType = gmx::makeUpdateGroupingsPerMoleculeType(mtop_);
+
+    ASSERT_EQ(updateGroupingsPerMoleculeType.size(), 1);
+    EXPECT_EQ(updateGroupingsPerMoleculeType[0].numBlocks(), 2);
 
-    mtop.moltype.emplace_back(ethane());
-    t_iparams iparams;
-    iparams.constr = { 0.1, 0.1 };
-    mtop.ffparams.iparams.push_back(iparams);
-    iparams.harmonic = { 107.800, 276.144, 107.800, 276.144 };
-    mtop.ffparams.iparams.push_back(iparams);
+    real maxRadius = computeMaxUpdateGroupRadius(mtop_, updateGroupingsPerMoleculeType, temperature_);
+    EXPECT_FLOAT_EQ(maxRadius, 0.094746813);
+}
 
-    auto updateGroups = gmx::makeUpdateGroups(mtop);
+TEST_F(UpdateGroupsTest, CheckRadiusCalculationAtDifferentTemperaturesWithEthane)
+{
+    mtop_.moltype.emplace_back(ethane());
+    {
+        t_iparams iparams;
+        iparams.constr = { 0.1, 0.1 };
+        mtop_.ffparams.iparams.push_back(iparams);
+        iparams.harmonic = { 107.800, 276.144, 107.800, 276.144 };
+        mtop_.ffparams.iparams.push_back(iparams);
+    }
 
-    ASSERT_EQ(updateGroups.size(), 1);
-    EXPECT_EQ(updateGroups[0].numBlocks(), 2);
+    auto updateGroupingsPerMoleculeType = gmx::makeUpdateGroupingsPerMoleculeType(mtop_);
 
-    real temperature = 298;
-    real maxRadius   = computeMaxUpdateGroupRadius(mtop, updateGroups, temperature);
+    ASSERT_EQ(updateGroupingsPerMoleculeType.size(), 1);
+    EXPECT_EQ(updateGroupingsPerMoleculeType[0].numBlocks(), 2);
+
+    real maxRadius = computeMaxUpdateGroupRadius(mtop_, updateGroupingsPerMoleculeType, temperature_);
     EXPECT_FLOAT_EQ(maxRadius, 0.094746813);
 
-    temperature = 0;
-    maxRadius   = computeMaxUpdateGroupRadius(mtop, updateGroups, temperature);
+    // Observe that the temperature affects the radius only when valid
+    temperature_ = 0;
+    maxRadius    = computeMaxUpdateGroupRadius(mtop_, updateGroupingsPerMoleculeType, temperature_);
     EXPECT_FLOAT_EQ(maxRadius, 0.10310466);
 
-    temperature = -1;
-    maxRadius   = computeMaxUpdateGroupRadius(mtop, updateGroups, temperature);
+    temperature_ = -1;
+    maxRadius    = computeMaxUpdateGroupRadius(mtop_, updateGroupingsPerMoleculeType, temperature_);
     EXPECT_FLOAT_EQ(maxRadius, 0.125);
 }
 
-TEST(UpdateGroups, butaneUA)
+TEST_F(UpdateGroupsTest, WithButaneUA)
 {
-    gmx_mtop_t mtop;
-
-    mtop.moltype.emplace_back(butaneUA());
-    t_iparams iparams;
-    iparams.constr = { 0.3, 0.3 };
-    mtop.ffparams.iparams.push_back(iparams);
+    mtop_.moltype.emplace_back(butaneUA());
+    {
+        t_iparams iparams;
+        iparams.constr = { 0.3, 0.3 };
+        mtop_.ffparams.iparams.push_back(iparams);
+    }
 
-    auto updateGroups = gmx::makeUpdateGroups(mtop);
+    auto updateGroupingsPerMoleculeType = gmx::makeUpdateGroupingsPerMoleculeType(mtop_);
 
-    EXPECT_EQ(updateGroups.size(), 0);
+    EXPECT_EQ(updateGroupingsPerMoleculeType.size(), 0);
 }
 
-TEST(UpdateGroups, waterThreeSite)
+TEST_F(UpdateGroupsTest, WithWaterThreeSite)
 {
-    gmx_mtop_t mtop;
+    mtop_.moltype.emplace_back(waterThreeSite());
+    {
+        t_iparams iparams;
+        iparams.settle = { 0.1, 0.1633 };
+        mtop_.ffparams.iparams.push_back(iparams);
+    }
 
-    mtop.moltype.emplace_back(waterThreeSite());
-    t_iparams iparams;
-    iparams.settle = { 0.1, 0.1633 };
-    mtop.ffparams.iparams.push_back(iparams);
+    auto updateGroupingsPerMoleculeType = gmx::makeUpdateGroupingsPerMoleculeType(mtop_);
 
-    auto updateGroups = gmx::makeUpdateGroups(mtop);
+    ASSERT_EQ(updateGroupingsPerMoleculeType.size(), 1);
+    EXPECT_EQ(updateGroupingsPerMoleculeType[0].numBlocks(), 1);
 
-    ASSERT_EQ(updateGroups.size(), 1);
-    EXPECT_EQ(updateGroups[0].numBlocks(), 1);
-
-    real temperature = 298;
-    real maxRadius   = computeMaxUpdateGroupRadius(mtop, updateGroups, temperature);
+    real maxRadius = computeMaxUpdateGroupRadius(mtop_, updateGroupingsPerMoleculeType, temperature_);
     EXPECT_FLOAT_EQ(maxRadius, 0.083887339);
 }
 
 // Tests update group with virtual site
-TEST(UpdateGroups, waterFourSite)
+TEST_F(UpdateGroupsTest, WithWaterFourSite)
 {
-    gmx_mtop_t mtop;
+    mtop_.moltype.emplace_back(waterFourSite());
+    {
+        t_iparams iparams[2];
+        iparams[0].settle = { 0.1, 0.1633 };
+        iparams[1].vsite  = { 0.128, 0.128 };
+        mtop_.ffparams.iparams.push_back(iparams[0]);
+        mtop_.ffparams.iparams.push_back(iparams[1]);
+    }
+
+    auto updateGroupingsPerMoleculeType = gmx::makeUpdateGroupingsPerMoleculeType(mtop_);
+
+    ASSERT_EQ(updateGroupingsPerMoleculeType.size(), 1);
+    EXPECT_EQ(updateGroupingsPerMoleculeType[0].numBlocks(), 1);
+}
 
-    mtop.moltype.emplace_back(waterFourSite());
-    t_iparams iparams[2];
-    iparams[0].settle = { 0.1, 0.1633 };
-    iparams[1].vsite  = { 0.128, 0.128 };
-    mtop.ffparams.iparams.push_back(iparams[0]);
-    mtop.ffparams.iparams.push_back(iparams[1]);
+TEST_F(UpdateGroupsTest, WithFourAtomsWithSettle)
+{
+    mtop_.moltype.emplace_back(waterThreeSite());
+    mtop_.moltype.back().atoms.nr = 4;
 
-    auto updateGroups = gmx::makeUpdateGroups(mtop);
+    auto updateGroupingsPerMoleculeType = gmx::makeUpdateGroupingsPerMoleculeType(mtop_);
 
-    ASSERT_EQ(updateGroups.size(), 1);
-    EXPECT_EQ(updateGroups[0].numBlocks(), 1);
+    ASSERT_EQ(updateGroupingsPerMoleculeType.size(), 1);
+    EXPECT_EQ(updateGroupingsPerMoleculeType[0].numBlocks(), 2);
 }
 
-TEST(UpdateGroups, fourAtomsWithSettle)
+// Tests groups with two constraints and an angle potential
+TEST_F(UpdateGroupsTest, WithWaterFlexAngle)
 {
-    gmx_mtop_t mtop;
+    mtop_.moltype.emplace_back(waterFlexAngle());
+    {
+        t_iparams iparams;
+        iparams.constr = { 0.1, 0.1 };
+        mtop_.ffparams.iparams.push_back(iparams);
+        iparams.harmonic = { 109.47, 383.0, 109.47, 383.0 };
+        mtop_.ffparams.iparams.push_back(iparams);
+    }
 
-    mtop.moltype.emplace_back(waterThreeSite());
-    mtop.moltype.back().atoms.nr = 4;
+    auto updateGroupingsPerMoleculeType = gmx::makeUpdateGroupingsPerMoleculeType(mtop_);
 
-    auto updateGroups = gmx::makeUpdateGroups(mtop);
+    ASSERT_EQ(updateGroupingsPerMoleculeType.size(), 1);
+    EXPECT_EQ(updateGroupingsPerMoleculeType[0].numBlocks(), 1);
 
-    ASSERT_EQ(updateGroups.size(), 1);
-    EXPECT_EQ(updateGroups[0].numBlocks(), 2);
+    real maxRadius = computeMaxUpdateGroupRadius(mtop_, updateGroupingsPerMoleculeType, temperature_);
+    EXPECT_FLOAT_EQ(maxRadius, 0.090824135);
 }
 
-// Tests groups with two constraints and an angle potential
-TEST(UpdateGroups, waterFlexAngle)
+TEST_F(UpdateGroupsTest, CheckRadiusCalculationAtDifferentTemperaturesWithWaterFlexAngle)
 {
-    gmx_mtop_t mtop;
-
-    mtop.moltype.emplace_back(waterFlexAngle());
-    t_iparams iparams;
-    iparams.constr = { 0.1, 0.1 };
-    mtop.ffparams.iparams.push_back(iparams);
-    iparams.harmonic = { 109.47, 383.0, 109.47, 383.0 };
-    mtop.ffparams.iparams.push_back(iparams);
+    mtop_.moltype.emplace_back(waterFlexAngle());
+    {
+        t_iparams iparams;
+        iparams.constr = { 0.1, 0.1 };
+        mtop_.ffparams.iparams.push_back(iparams);
+        iparams.harmonic = { 109.47, 383.0, 109.47, 383.0 };
+        mtop_.ffparams.iparams.push_back(iparams);
+    }
 
-    auto updateGroups = gmx::makeUpdateGroups(mtop);
+    auto updateGroupingsPerMoleculeType = gmx::makeUpdateGroupingsPerMoleculeType(mtop_);
 
-    ASSERT_EQ(updateGroups.size(), 1);
-    EXPECT_EQ(updateGroups[0].numBlocks(), 1);
+    ASSERT_EQ(updateGroupingsPerMoleculeType.size(), 1);
+    EXPECT_EQ(updateGroupingsPerMoleculeType[0].numBlocks(), 1);
 
-    real temperature = 298;
-    real maxRadius   = computeMaxUpdateGroupRadius(mtop, updateGroups, temperature);
+    real maxRadius = computeMaxUpdateGroupRadius(mtop_, updateGroupingsPerMoleculeType, temperature_);
     EXPECT_FLOAT_EQ(maxRadius, 0.090824135);
 
-    temperature = 0;
-    maxRadius   = computeMaxUpdateGroupRadius(mtop, updateGroups, temperature);
+    // Observe that the temperature affects the radius only when valid
+    temperature_ = 0;
+    maxRadius    = computeMaxUpdateGroupRadius(mtop_, updateGroupingsPerMoleculeType, temperature_);
     EXPECT_FLOAT_EQ(maxRadius, 0.1);
 
-    temperature = -1;
-    maxRadius   = computeMaxUpdateGroupRadius(mtop, updateGroups, temperature);
+    temperature_ = -1;
+    maxRadius    = computeMaxUpdateGroupRadius(mtop_, updateGroupingsPerMoleculeType, temperature_);
     EXPECT_FLOAT_EQ(maxRadius, 0.1);
 }
 
-TEST(UpdateGroups, twoMoltypes)
+TEST_F(UpdateGroupsTest, WithTwoMoltypes)
 {
-    gmx_mtop_t mtop;
-
-    mtop.moltype.emplace_back(methane());
-    t_iparams iparams;
-    iparams.constr = { 0.1, 0.1 };
-    mtop.ffparams.iparams.push_back(iparams);
-
-    mtop.moltype.emplace_back(waterThreeSite());
+    mtop_.moltype.emplace_back(methane());
+    {
+        t_iparams iparams;
+        iparams.constr = { 0.1, 0.1 };
+        mtop_.ffparams.iparams.push_back(iparams);
+    }
+
+    mtop_.moltype.emplace_back(waterThreeSite());
     // Note: iparams not accessed for SETTLE when not computing radius
 
-    auto updateGroups = gmx::makeUpdateGroups(mtop);
+    auto updateGroupingsPerMoleculeType = gmx::makeUpdateGroupingsPerMoleculeType(mtop_);
 
-    ASSERT_EQ(updateGroups.size(), 2);
-    EXPECT_EQ(updateGroups[0].numBlocks(), 1);
-    EXPECT_EQ(updateGroups[1].numBlocks(), 1);
+    ASSERT_EQ(updateGroupingsPerMoleculeType.size(), 2);
+    EXPECT_EQ(updateGroupingsPerMoleculeType[0].numBlocks(), 1);
+    EXPECT_EQ(updateGroupingsPerMoleculeType[1].numBlocks(), 1);
 }
 
 } // namespace
index b77e92b359ebfd52b89b8c3c0119b172933ca4c9..de28108a91ea0419e0bbb7e3534d03724d614582 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -109,10 +109,10 @@ TEST(UpdateGroupsCog, ComputesCogs)
     mtop.ffparams.iparams.push_back(iparams);
 
     // Run the test
-    auto updateGroups = makeUpdateGroups(mtop);
-    real temperature  = 300;
+    auto updateGroupingsPerMoleculeType = makeUpdateGroupingsPerMoleculeType(mtop);
+    real temperature                    = 300;
 
-    UpdateGroupsCog updateGroupsCog(mtop, updateGroups, temperature, numAtoms);
+    UpdateGroupsCog updateGroupsCog(mtop, updateGroupingsPerMoleculeType, temperature, numAtoms);
 
     EXPECT_FLOAT_EQ(updateGroupsCog.maxUpdateGroupRadius(), 0.083887339);
 
index 3505a1a1ea1b53865388a55cadcb07d1c788d00a..86f9d5b905bde00461cf434e63b24d9fbf147cb5 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "tgroup.h"
 
-#include <cmath>
-
-#include "gromacs/gmxlib/network.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/coupling.h"
-#include "gromacs/mdlib/gmx_omp_nthreads.h"
-#include "gromacs/mdlib/rbin.h"
 #include "gromacs/mdtypes/group.h"
 #include "gromacs/mdtypes/inputrec.h"
-#include "gromacs/mdtypes/mdatom.h"
-#include "gromacs/topology/mtop_util.h"
-#include "gromacs/topology/topology.h"
-#include "gromacs/utility/exceptions.h"
-#include "gromacs/utility/fatalerror.h"
-#include "gromacs/utility/futil.h"
-#include "gromacs/utility/smalloc.h"
-
-static void init_grpstat(const gmx_mtop_t* mtop, int ngacc, t_grp_acc gstat[])
-{
-    if (ngacc > 0)
-    {
-        const SimulationGroups& groups = mtop->groups;
-        for (const AtomProxy atomP : AtomRange(*mtop))
-        {
-            const t_atom& local = atomP.atom();
-            int           i     = atomP.globalAtomNumber();
-            int           grp   = getGroupType(groups, SimulationAtomGroupType::Acceleration, i);
-            if ((grp < 0) && (grp >= ngacc))
-            {
-                gmx_incons("Input for acceleration groups wrong");
-            }
-            gstat[grp].nat++;
-            /* This will not work for integrator BD */
-            gstat[grp].mA += local.m;
-            gstat[grp].mB += local.mB;
-        }
-    }
-}
-
-void init_ekindata(FILE gmx_unused*  log,
-                   const gmx_mtop_t* mtop,
-                   const t_grpopts*  opts,
-                   gmx_ekindata_t*   ekind,
-                   real              cos_accel)
-{
-    int i;
-
-    /* bNEMD tells if we should remove remove the COM velocity
-     * from the velocities during velocity scaling in T-coupling.
-     * Turn this on when we have multiple acceleration groups
-     * or one accelerated group.
-     */
-    ekind->bNEMD = (opts->ngacc > 1 || norm2(opts->acc[0]) > 0);
-
-    ekind->ngtc = opts->ngtc;
-    ekind->tcstat.resize(opts->ngtc);
-    /* Set Berendsen tcoupl lambda's to 1,
-     * so runs without Berendsen coupling are not affected.
-     */
-    for (i = 0; i < opts->ngtc; i++)
-    {
-        ekind->tcstat[i].lambda         = 1.0;
-        ekind->tcstat[i].vscale_nhc     = 1.0;
-        ekind->tcstat[i].ekinscaleh_nhc = 1.0;
-        ekind->tcstat[i].ekinscalef_nhc = 1.0;
-    }
-
-    int nthread     = gmx_omp_nthreads_get(emntUpdate);
-    ekind->nthreads = nthread;
-    snew(ekind->ekin_work_alloc, nthread);
-    snew(ekind->ekin_work, nthread);
-    snew(ekind->dekindl_work, nthread);
-#pragma omp parallel for num_threads(nthread) schedule(static)
-    for (int thread = 0; thread < nthread; thread++)
-    {
-        try
-        {
-#define EKIN_WORK_BUFFER_SIZE 2
-            /* Allocate 2 extra elements on both sides, so in single
-             * precision we have
-             * EKIN_WORK_BUFFER_SIZE*DIM*DIM*sizeof(real) = 72/144 bytes
-             * buffer on both sides to avoid cache pollution.
-             */
-            snew(ekind->ekin_work_alloc[thread], ekind->ngtc + 2 * EKIN_WORK_BUFFER_SIZE);
-            ekind->ekin_work[thread] = ekind->ekin_work_alloc[thread] + EKIN_WORK_BUFFER_SIZE;
-            /* Nasty hack so we can have the per-thread accumulation
-             * variable for dekindl in the same thread-local cache lines
-             * as the per-thread accumulation tensors for ekin[fh],
-             * because they are accumulated in the same loop. */
-            ekind->dekindl_work[thread] = &(ekind->ekin_work[thread][ekind->ngtc][0][0]);
-#undef EKIN_WORK_BUFFER_SIZE
-        }
-        GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
-    }
-
-    ekind->ngacc = opts->ngacc;
-    ekind->grpstat.resize(opts->ngacc);
-    init_grpstat(mtop, opts->ngacc, ekind->grpstat.data());
-
-    ekind->cosacc.cos_accel = cos_accel;
-}
-
-void accumulate_u(const t_commrec* cr, const t_grpopts* opts, gmx_ekindata_t* ekind)
-{
-    /* This routine will only be called when it's necessary */
-    t_bin* rb;
-    int    g;
-
-    rb = mk_bin();
-
-    for (g = 0; (g < opts->ngacc); g++)
-    {
-        add_binr(rb, DIM, ekind->grpstat[g].u);
-    }
-    sum_bin(rb, cr);
-
-    for (g = 0; (g < opts->ngacc); g++)
-    {
-        extract_binr(rb, DIM * g, DIM, ekind->grpstat[g].u);
-    }
-    destroy_bin(rb);
-}
-
-void update_ekindata(int              start,
-                     int              homenr,
-                     gmx_ekindata_t*  ekind,
-                     const t_grpopts* opts,
-                     const rvec       v[],
-                     const t_mdatoms* md,
-                     real             lambda)
-{
-    int  d, g, n;
-    real mv;
-
-    /* calculate mean velocities at whole timestep */
-    for (g = 0; (g < opts->ngtc); g++)
-    {
-        ekind->tcstat[g].T = 0;
-    }
-
-    if (ekind->bNEMD)
-    {
-        for (g = 0; (g < opts->ngacc); g++)
-        {
-            clear_rvec(ekind->grpstat[g].u);
-        }
-
-        g = 0;
-        for (n = start; (n < start + homenr); n++)
-        {
-            if (md->cACC)
-            {
-                g = md->cACC[n];
-            }
-            for (d = 0; (d < DIM); d++)
-            {
-                mv = md->massT[n] * v[n][d];
-                ekind->grpstat[g].u[d] += mv;
-            }
-        }
 
-        for (g = 0; (g < opts->ngacc); g++)
-        {
-            for (d = 0; (d < DIM); d++)
-            {
-                ekind->grpstat[g].u[d] /=
-                        (1 - lambda) * ekind->grpstat[g].mA + lambda * ekind->grpstat[g].mB;
-            }
-        }
-    }
-}
 
-real sum_ekin(const t_grpopts* opts, gmx_ekindata_t* ekind, real* dekindlambda, gmx_bool bEkinAveVel, gmx_bool bScaleEkin)
+real sum_ekin(const t_grpopts* opts, gmx_ekindata_t* ekind, real* dekindlambda, bool bEkinAveVel, bool bScaleEkin)
 {
     int           i, j, m, ngtc;
     real          T;
index 11349251dc7dec2d69efd0f7a9c219e821ddcb60..9a62f8fe0e3328bb0c5ce4e7599ea296ce6d1de2 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,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_MDLIB_TGROUP_H
 #define GMX_MDLIB_TGROUP_H
 
-#include <cstdio>
-
-#include "gromacs/math/vectypes.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
-struct gmx_ekindata_t;
-struct gmx_mtop_t;
-struct t_commrec;
+class gmx_ekindata_t;
 struct t_grpopts;
-struct t_mdatoms;
-
-void init_ekindata(FILE* log, const gmx_mtop_t* mtop, const t_grpopts* opts, gmx_ekindata_t* ekind, real cos_accel);
-/* Allocate memory and set the grpnr array. */
-
-void done_ekindata(gmx_ekindata_t* ekind);
-/* Free the memory */
-
-void accumulate_u(const t_commrec* cr, const t_grpopts* opts, gmx_ekindata_t* ekind);
 
-/* Communicate subsystem - group velocities and subsystem ekin respectively
- * and sum them up. Return them in grps.
- */
-
-real sum_ekin(const t_grpopts* opts, gmx_ekindata_t* ekind, real* dekindlambda, gmx_bool bEkinFullStep, gmx_bool bScaleEkin);
+real sum_ekin(const t_grpopts* opts, gmx_ekindata_t* ekind, real* dekindlambda, bool bEkinFullStep, bool bScaleEkin);
 /* Sum the group ekins into total ekin and calc temp per group,
  * return total temperature.
  */
 
-void update_ekindata(int              start,
-                     int              homenr,
-                     gmx_ekindata_t*  ekind,
-                     const t_grpopts* opts,
-                     const rvec       v[],
-                     const t_mdatoms* md,
-                     real             lambda);
-/* Do the update of group velocities (if bNEMD) and
- * (partial) group ekin.
- */
-
 #endif
index 09f1b6512da27fb796354a730669625a2a4a60ac..dd7e85afef3ddfd6b284912e37031a5ad9c3d582 100644 (file)
@@ -62,11 +62,11 @@ void do_md_trajectory_writing(FILE*                          fplog,
                               int64_t                        step,
                               int64_t                        step_rel,
                               double                         t,
-                              t_inputrec*                    ir,
+                              const t_inputrec*              ir,
                               t_state*                       state,
                               t_state*                       state_global,
                               ObservablesHistory*            observablesHistory,
-                              const gmx_mtop_t*              top_global,
+                              const gmx_mtop_t&              top_global,
                               t_forcerec*                    fr,
                               gmx_mdoutf_t                   outf,
                               const gmx::EnergyOutput&       energyOutput,
@@ -121,7 +121,7 @@ void do_md_trajectory_writing(FILE*                          fplog,
 
     if (mdof_flags != 0)
     {
-        wallcycle_start(mdoutf_get_wcycle(outf), ewcTRAJ);
+        wallcycle_start(mdoutf_get_wcycle(outf), WallCycleCounter::Traj);
         if (bCPT)
         {
             if (MASTER(cr))
@@ -146,8 +146,8 @@ void do_md_trajectory_writing(FILE*                          fplog,
         // Note that part of the following code is duplicated in StatePropagatorData::trajectoryWriterTeardown.
         // This duplication is needed while both legacy and modular code paths are in use.
         // TODO: Remove duplication asap, make sure to keep in sync in the meantime.
-        mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags, top_global->natoms, step, t, state,
-                                         state_global, observablesHistory, f, &checkpointDataHolder);
+        mdoutf_write_to_trajectory_files(
+                fplog, cr, outf, mdof_flags, top_global.natoms, step, t, state, state_global, observablesHistory, f, &checkpointDataHolder);
         if (bLastStep && step_rel == ir->nsteps && bDoConfOut && MASTER(cr) && !bRerunMD)
         {
             if (fr->bMolPBC && state == state_global)
@@ -177,16 +177,21 @@ void do_md_trajectory_writing(FILE*                          fplog,
             if (fr->bMolPBC && !ir->bPeriodicMols)
             {
                 /* Make molecules whole only for confout writing */
-                do_pbc_mtop(ir->pbcType, state->box, top_global, x_for_confout);
+                do_pbc_mtop(ir->pbcType, state->box, &top_global, x_for_confout);
             }
-            write_sto_conf_mtop(ftp2fn(efSTO, nfile, fnm), *top_global->name, top_global,
-                                x_for_confout, state_global->v.rvec_array(), ir->pbcType, state->box);
+            write_sto_conf_mtop(ftp2fn(efSTO, nfile, fnm),
+                                *top_global.name,
+                                top_global,
+                                x_for_confout,
+                                state_global->v.rvec_array(),
+                                ir->pbcType,
+                                state->box);
             if (fr->bMolPBC && state == state_global)
             {
                 sfree(x_for_confout);
             }
         }
-        wallcycle_stop(mdoutf_get_wcycle(outf), ewcTRAJ);
+        wallcycle_stop(mdoutf_get_wcycle(outf), WallCycleCounter::Traj);
     }
 #if GMX_FAHCORE
     if (MASTER(cr))
index a74c707e778abf205d4f755850cfc15cda2eca03..220b6056eb0a12e6bd3ff9ef355083720a1c8305 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 @@
 #include "gromacs/mdlib/mdoutf.h"
 #include "gromacs/timing/wallcycle.h"
 
-struct gmx_ekindata_t;
+class gmx_ekindata_t;
 struct gmx_mtop_t;
 struct ObservablesHistory;
 struct t_commrec;
@@ -67,11 +67,11 @@ void do_md_trajectory_writing(FILE*                          fplog,
                               int64_t                        step,
                               int64_t                        step_rel,
                               double                         t,
-                              t_inputrec*                    ir,
+                              const t_inputrec*              ir,
                               t_state*                       state,
                               t_state*                       state_global,
                               ObservablesHistory*            observablesHistory,
-                              const gmx_mtop_t*              top_global,
+                              const gmx_mtop_t&              top_global,
                               t_forcerec*                    fr,
                               gmx_mdoutf_t                   outf,
                               const gmx::EnergyOutput&       energyOutput,
index 46f848d4e73a42a083f975935ab5780274a1a796..c75ff3c6146810b1b5452548f5c366d69198d3a2 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <memory>
 
 #include "gromacs/domdec/domdec_struct.h"
-#include "gromacs/fileio/confio.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/listed_forces/disre.h"
 #include "gromacs/listed_forces/orires.h"
 #include "gromacs/math/functions.h"
-#include "gromacs/math/invertmatrix.h"
 #include "gromacs/math/paddedvector.h"
 #include "gromacs/math/units.h"
 #include "gromacs/math/vec.h"
-#include "gromacs/math/vecdump.h"
 #include "gromacs/mdlib/boxdeformation.h"
 #include "gromacs/mdlib/constr.h"
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
-#include "gromacs/mdlib/mdatoms.h"
 #include "gromacs/mdlib/stat.h"
 #include "gromacs/mdlib/tgroup.h"
 #include "gromacs/mdtypes/commrec.h"
@@ -68,9 +64,7 @@
 #include "gromacs/mdtypes/group.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
-#include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/mdtypes/state.h"
-#include "gromacs/pbcutil/boxutilities.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/pulling/pull.h"
 #include "gromacs/random/tabulatednormaldistribution.h"
@@ -82,7 +76,6 @@
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/gmxassert.h"
-#include "gromacs/utility/gmxomp.h"
 #include "gromacs/utility/smalloc.h"
 
 using namespace gmx; // TODO: Remove when this file is moved into gmx namespace
@@ -122,7 +115,11 @@ public:
 
     void update_coords(const t_inputrec&                                inputRecord,
                        int64_t                                          step,
-                       const t_mdatoms*                                 md,
+                       int                                              homenr,
+                       bool                                             havePartiallyFrozenAtoms,
+                       gmx::ArrayRef<const ParticleType>                ptype,
+                       gmx::ArrayRef<const real>                        invMass,
+                       gmx::ArrayRef<const rvec>                        invMassPerDim,
                        t_state*                                         state,
                        const gmx::ArrayRefWithPadding<const gmx::RVec>& f,
                        const t_fcdata&                                  fcdata,
@@ -132,27 +129,34 @@ public:
                        const t_commrec*                                 cr,
                        bool                                             haveConstraints);
 
-    void finish_update(const t_inputrec& inputRecord,
-                       const t_mdatoms*  md,
-                       t_state*          state,
-                       gmx_wallcycle_t   wcycle,
-                       bool              haveConstraints);
-
-    void update_sd_second_half(const t_inputrec& inputRecord,
-                               int64_t           step,
-                               real*             dvdlambda,
-                               const t_mdatoms*  md,
-                               t_state*          state,
-                               const t_commrec*  cr,
-                               t_nrnb*           nrnb,
-                               gmx_wallcycle_t   wcycle,
-                               gmx::Constraints* constr,
-                               bool              do_log,
-                               bool              do_ene);
-
-    void update_for_constraint_virial(const t_inputrec&                                inputRecord,
-                                      const t_mdatoms&                                 md,
-                                      const t_state&                                   state,
+    void finish_update(const t_inputrec&                   inputRecord,
+                       bool                                havePartiallyFrozenAtoms,
+                       int                                 homenr,
+                       gmx::ArrayRef<const unsigned short> cFREEZE,
+                       t_state*                            state,
+                       gmx_wallcycle*                      wcycle,
+                       bool                                haveConstraints);
+
+    void update_sd_second_half(const t_inputrec&                 inputRecord,
+                               int64_t                           step,
+                               real*                             dvdlambda,
+                               int                               homenr,
+                               gmx::ArrayRef<const ParticleType> ptype,
+                               gmx::ArrayRef<const real>         invMass,
+                               t_state*                          state,
+                               const t_commrec*                  cr,
+                               t_nrnb*                           nrnb,
+                               gmx_wallcycle*                    wcycle,
+                               gmx::Constraints*                 constr,
+                               bool                              do_log,
+                               bool                              do_ene);
+
+    void update_for_constraint_virial(const t_inputrec&         inputRecord,
+                                      int                       homenr,
+                                      bool                      havePartiallyFrozenAtoms,
+                                      gmx::ArrayRef<const real> invmass,
+                                      gmx::ArrayRef<const rvec> invMassPerDim,
+                                      const t_state&            state,
                                       const gmx::ArrayRefWithPadding<const gmx::RVec>& f,
                                       const gmx_ekindata_t&                            ekind);
 
@@ -166,6 +170,11 @@ public:
 
     BoxDeformation* deform() const { return deform_; }
 
+    //! Group index for freezing
+    gmx::ArrayRef<const unsigned short> cFREEZE_;
+    //! Group index for temperature coupling
+    gmx::ArrayRef<const unsigned short> cTC_;
+
 private:
     //! stochastic dynamics struct
     gmx_stochd_t sd_;
@@ -200,10 +209,14 @@ BoxDeformation* Update::deform() const
     return impl_->deform();
 }
 
-void Update::update_coords(const t_inputrec&                                inputRecord,
-                           int64_t                                          step,
-                           const t_mdatoms*                                 md,
-                           t_state*                                         state,
+void Update::update_coords(const t_inputrec&                 inputRecord,
+                           int64_t                           step,
+                           const int                         homenr,
+                           const bool                        havePartiallyFrozenAtoms,
+                           gmx::ArrayRef<const ParticleType> ptype,
+                           gmx::ArrayRef<const real>         invMass,
+                           gmx::ArrayRef<const rvec>         invMassPerDim,
+                           t_state*                          state,
                            const gmx::ArrayRefWithPadding<const gmx::RVec>& f,
                            const t_fcdata&                                  fcdata,
                            const gmx_ekindata_t*                            ekind,
@@ -212,42 +225,63 @@ void Update::update_coords(const t_inputrec&                                inpu
                            const t_commrec*                                 cr,
                            const bool                                       haveConstraints)
 {
-    return impl_->update_coords(inputRecord, step, md, state, f, fcdata, ekind, M, updatePart, cr,
+    return impl_->update_coords(inputRecord,
+                                step,
+                                homenr,
+                                havePartiallyFrozenAtoms,
+                                ptype,
+                                invMass,
+                                invMassPerDim,
+                                state,
+                                f,
+                                fcdata,
+                                ekind,
+                                M,
+                                updatePart,
+                                cr,
                                 haveConstraints);
 }
 
 void Update::finish_update(const t_inputrec& inputRecord,
-                           const t_mdatoms*  md,
+                           const bool        havePartiallyFrozenAtoms,
+                           const int         homenr,
                            t_state*          state,
-                           gmx_wallcycle_t   wcycle,
+                           gmx_wallcycle   wcycle,
                            const bool        haveConstraints)
 {
-    return impl_->finish_update(inputRecord, md, state, wcycle, haveConstraints);
+    return impl_->finish_update(
+            inputRecord, havePartiallyFrozenAtoms, homenr, impl_->cFREEZE_, state, wcycle, haveConstraints);
 }
 
-void Update::update_sd_second_half(const t_inputrec& inputRecord,
-                                   int64_t           step,
-                                   real*             dvdlambda,
-                                   const t_mdatoms*  md,
-                                   t_state*          state,
-                                   const t_commrec*  cr,
-                                   t_nrnb*           nrnb,
-                                   gmx_wallcycle_t   wcycle,
-                                   gmx::Constraints* constr,
-                                   bool              do_log,
-                                   bool              do_ene)
+void Update::update_sd_second_half(const t_inputrec&                 inputRecord,
+                                   int64_t                           step,
+                                   real*                             dvdlambda,
+                                   const int                         homenr,
+                                   gmx::ArrayRef<const ParticleType> ptype,
+                                   gmx::ArrayRef<const real>         invMass,
+                                   t_state*                          state,
+                                   const t_commrec*                  cr,
+                                   t_nrnb*                           nrnb,
+                                   gmx_wallcycle*                    wcycle,
+                                   gmx::Constraints*                 constr,
+                                   bool                              do_log,
+                                   bool                              do_ene)
 {
-    return impl_->update_sd_second_half(inputRecord, step, dvdlambda, md, state, cr, nrnb, wcycle,
-                                        constr, do_log, do_ene);
+    return impl_->update_sd_second_half(
+            inputRecord, step, dvdlambda, homenr, ptype, invMass, state, cr, nrnb, wcycle, constr, do_log, do_ene);
 }
 
-void Update::update_for_constraint_virial(const t_inputrec& inputRecord,
-                                          const t_mdatoms&  md,
-                                          const t_state&    state,
+void Update::update_for_constraint_virial(const t_inputrec&         inputRecord,
+                                          const int                 homenr,
+                                          const bool                havePartiallyFrozenAtoms,
+                                          gmx::ArrayRef<const real> invmass,
+                                          gmx::ArrayRef<const rvec> invMassPerDim,
+                                          const t_state&            state,
                                           const gmx::ArrayRefWithPadding<const gmx::RVec>& f,
                                           const gmx_ekindata_t&                            ekind)
 {
-    return impl_->update_for_constraint_virial(inputRecord, md, state, f, ekind);
+    return impl_->update_for_constraint_virial(
+            inputRecord, homenr, havePartiallyFrozenAtoms, invmass, invMassPerDim, state, f, ekind);
 }
 
 void Update::update_temperature_constants(const t_inputrec& inputRecord)
@@ -255,18 +289,6 @@ void Update::update_temperature_constants(const t_inputrec& inputRecord)
     return impl_->update_temperature_constants(inputRecord);
 }
 
-/*! \brief Sets the velocities of virtual sites to zero */
-static void clearVsiteVelocities(int start, int nrend, const unsigned short* particleType, rvec* gmx_restrict v)
-{
-    for (int a = start; a < nrend; a++)
-    {
-        if (particleType[a] == eptVSite)
-        {
-            clear_rvec(v[a]);
-        }
-    }
-}
-
 /*! \brief Sets whether we store the updated velocities */
 enum class StoreUpdatedVelocities
 {
@@ -308,7 +330,7 @@ enum class ApplyParrinelloRahmanVScaling
  * \param[in]    pRVScaleMatrixDiagonal Parrinello-Rahman v-scale matrix diagonal
  * \param[in]    x                      Input coordinates
  * \param[out]   xprime                 Updated coordinates
- * \param[inout] v                      Velocities
+ * \param[inout] v                      Velocities, type either rvec* or const rvec*
  * \param[in]    f                      Forces
  *
  * We expect this template to get good SIMD acceleration by most compilers,
@@ -316,19 +338,20 @@ enum class ApplyParrinelloRahmanVScaling
  * Note that we might get even better SIMD acceleration when we introduce
  * aligned (and padded) memory, possibly with some hints for the compilers.
  */
-template<StoreUpdatedVelocities storeUpdatedVelocities, NumTempScaleValues numTempScaleValues, ApplyParrinelloRahmanVScaling applyPRVScaling>
-static void updateMDLeapfrogSimple(int         start,
-                                   int         nrend,
-                                   real        dt,
-                                   real        dtPressureCouple,
-                                   const rvec* gmx_restrict          invMassPerDim,
-                                   gmx::ArrayRef<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)
+template<StoreUpdatedVelocities storeUpdatedVelocities, NumTempScaleValues numTempScaleValues, ApplyParrinelloRahmanVScaling applyPRVScaling, typename VelocityType>
+static std::enable_if_t<std::is_same<VelocityType, rvec>::value || std::is_same<VelocityType, const rvec>::value, void>
+updateMDLeapfrogSimple(int                                 start,
+                       int                                 nrend,
+                       real                                dt,
+                       real                                dtPressureCouple,
+                       gmx::ArrayRef<const rvec>           invMassPerDim,
+                       gmx::ArrayRef<const t_grp_tcstat>   tcstat,
+                       gmx::ArrayRef<const unsigned short> cTC,
+                       const rvec                          pRVScaleMatrixDiagonal,
+                       const rvec* gmx_restrict x,
+                       rvec* gmx_restrict xprime,
+                       VelocityType* gmx_restrict v,
+                       const rvec* gmx_restrict f)
 {
     real lambdaGroup;
 
@@ -358,11 +381,12 @@ static void updateMDLeapfrogSimple(int         start,
             {
                 vNew -= dtPressureCouple * pRVScaleMatrixDiagonal[d] * v[a][d];
             }
-            if (storeUpdatedVelocities == StoreUpdatedVelocities::yes)
+            // TODO: Remove NOLINTs once clang-tidy is updated to v11, it should be able to handle constexpr.
+            if constexpr (storeUpdatedVelocities == StoreUpdatedVelocities::yes) // NOLINT // NOLINTNEXTLINE
             {
                 v[a][d] = vNew;
             }
-            xprime[a][d] = x[a][d] + vNew * dt;
+            xprime[a][d] = x[a][d] + vNew * dt; // NOLINT(readability-misleading-indentation)
         }
     }
 }
@@ -433,19 +457,20 @@ static inline void simdStoreRvecs(rvec* r, int index, SimdReal r0, SimdReal r1,
  * \param[in]    tcstat                 Temperature coupling information
  * \param[in]    x                      Input coordinates
  * \param[out]   xprime                 Updated coordinates
- * \param[inout] v                      Velocities
+ * \param[inout] v                      Velocities, type either rvec* or const rvec*
  * \param[in]    f                      Forces
  */
-template<StoreUpdatedVelocities storeUpdatedVelocities>
-static void updateMDLeapfrogSimpleSimd(int         start,
-                                       int         nrend,
-                                       real        dt,
-                                       const real* gmx_restrict          invMass,
-                                       gmx::ArrayRef<const t_grp_tcstat> tcstat,
-                                       const rvec* gmx_restrict x,
-                                       rvec* gmx_restrict xprime,
-                                       rvec* gmx_restrict v,
-                                       const rvec* gmx_restrict f)
+template<StoreUpdatedVelocities storeUpdatedVelocities, typename VelocityType>
+static std::enable_if_t<std::is_same<VelocityType, rvec>::value || std::is_same<VelocityType, const rvec>::value, void>
+updateMDLeapfrogSimpleSimd(int                               start,
+                           int                               nrend,
+                           real                              dt,
+                           gmx::ArrayRef<const real>         invMass,
+                           gmx::ArrayRef<const t_grp_tcstat> tcstat,
+                           const rvec* gmx_restrict x,
+                           rvec* gmx_restrict xprime,
+                           VelocityType* gmx_restrict v,
+                           const rvec* gmx_restrict f)
 {
     SimdReal timestep(dt);
     SimdReal lambdaSystem(tcstat[0].lambda);
@@ -453,12 +478,12 @@ static void updateMDLeapfrogSimpleSimd(int         start,
     /* We declare variables here, since code is often slower when declaring them inside the loop */
 
     /* Note: We should implement a proper PaddedVector, so we don't need this check */
-    GMX_ASSERT(isSimdAligned(invMass), "invMass should be aligned");
+    GMX_ASSERT(isSimdAligned(invMass.data()), "invMass should be aligned");
 
     for (int a = start; a < nrend; a += GMX_SIMD_REAL_WIDTH)
     {
         SimdReal invMass0, invMass1, invMass2;
-        expandScalarsToTriplets(simdLoad(invMass + a), &invMass0, &invMass1, &invMass2);
+        expandScalarsToTriplets(simdLoad(invMass.data() + a), &invMass0, &invMass1, &invMass2);
 
         SimdReal v0, v1, v2;
         SimdReal f0, f1, f2;
@@ -469,12 +494,13 @@ static void updateMDLeapfrogSimpleSimd(int         start,
         v1 = fma(f1 * invMass1, timestep, lambdaSystem * v1);
         v2 = fma(f2 * invMass2, timestep, lambdaSystem * v2);
 
-        if (storeUpdatedVelocities == StoreUpdatedVelocities::yes)
+        // TODO: Remove NOLINTs once clang-tidy is updated to v11, it should be able to handle constexpr.
+        if constexpr (storeUpdatedVelocities == StoreUpdatedVelocities::yes) // NOLINT // NOLINTNEXTLINE
         {
             simdStoreRvecs(v, a, v0, v1, v2);
         }
 
-        SimdReal x0, x1, x2;
+        SimdReal x0, x1, x2; // NOLINT(readability-misleading-indentation)
         simdLoadRvecs(x, a, &x0, &x1, &x2);
 
         SimdReal xprime0 = fma(v0, timestep, x0);
@@ -491,7 +517,6 @@ static void updateMDLeapfrogSimpleSimd(int         start,
 enum class AccelerationType
 {
     none,
-    group,
     cosine
 };
 
@@ -504,8 +529,8 @@ enum class AccelerationType
  * \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]     accel             Acceleration per group.
- * \param[in]     md                Atom properties.
+ * \param[in]     cTC               Temperature coupling group indices
+ * \param[in]     invMassPerDim     Inverse mass per dimension
  * \param[in]     ekind             Kinetic energy data.
  * \param[in]     box               The box dimensions.
  * \param[in]     x                 Input coordinates.
@@ -517,15 +542,15 @@ enum class AccelerationType
  * \param[in]     M                 Parrinello-Rahman scaling matrix.
  */
 template<AccelerationType accelerationType>
-static void updateMDLeapfrogGeneral(int                   start,
-                                    int                   nrend,
-                                    bool                  doNoseHoover,
-                                    real                  dt,
-                                    real                  dtPressureCouple,
-                                    const rvec*           accel,
-                                    const t_mdatoms*      md,
-                                    const gmx_ekindata_t* ekind,
-                                    const matrix          box,
+static void updateMDLeapfrogGeneral(int                                 start,
+                                    int                                 nrend,
+                                    bool                                doNoseHoover,
+                                    real                                dt,
+                                    real                                dtPressureCouple,
+                                    gmx::ArrayRef<const unsigned short> cTC,
+                                    gmx::ArrayRef<const rvec>           invMassPerDim,
+                                    const gmx_ekindata_t*               ekind,
+                                    const matrix                        box,
                                     const rvec* gmx_restrict x,
                                     rvec* gmx_restrict xprime,
                                     rvec* gmx_restrict v,
@@ -540,22 +565,16 @@ static void updateMDLeapfrogGeneral(int                   start,
      * Holian et al. Phys Rev E 52(3) : 2338, 1995
      */
 
-    gmx::ArrayRef<const t_grp_tcstat> tcstat  = ekind->tcstat;
-    gmx::ArrayRef<const t_grp_acc>    grpstat = ekind->grpstat;
-    const unsigned short*             cTC     = md->cTC;
-    const unsigned short*             cACC    = md->cACC;
-
-    const rvec* gmx_restrict invMassPerDim = md->invMassPerDim;
+    gmx::ArrayRef<const t_grp_tcstat> tcstat = ekind->tcstat;
 
     /* Initialize group values, changed later when multiple groups are used */
-    int ga = 0;
     int gt = 0;
 
     real omega_Z = 2 * static_cast<real>(M_PI) / box[ZZ][ZZ];
 
     for (int n = start; n < nrend; n++)
     {
-        if (cTC)
+        if (!cTC.empty())
         {
             gt = cTC[n];
         }
@@ -563,20 +582,9 @@ static void updateMDLeapfrogGeneral(int                   start,
 
         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)
-                {
-                    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] * omega_Z);
                 vCosine = cosineZ * ekind->cosacc.vcos;
@@ -605,10 +613,6 @@ static void updateMDLeapfrogGeneral(int                   start,
             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)
                     {
@@ -631,32 +635,35 @@ static void do_update_md(int         start,
                          const rvec* gmx_restrict x,
                          rvec* gmx_restrict xprime,
                          rvec* gmx_restrict v,
-                         const rvec* gmx_restrict f,
-                         const rvec* gmx_restrict accel,
-                         const int                etc,
-                         const int                epc,
-                         const int                nsttcouple,
-                         const int                nstpcouple,
-                         const t_mdatoms*         md,
-                         const gmx_ekindata_t*    ekind,
-                         const matrix             box,
+                         const rvec* gmx_restrict            f,
+                         const TemperatureCoupling           etc,
+                         const PressureCoupling              epc,
+                         const int                           nsttcouple,
+                         const int                           nstpcouple,
+                         gmx::ArrayRef<const unsigned short> cTC,
+                         gmx::ArrayRef<const real> gmx_unused invmass,
+                         gmx::ArrayRef<const rvec>            invMassPerDim,
+                         const gmx_ekindata_t*                ekind,
+                         const matrix                         box,
                          const double* gmx_restrict nh_vxi,
-                         const matrix               M)
+                         const matrix               M,
+                         bool gmx_unused havePartiallyFrozenAtoms)
 {
     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 = (etc != etcNO && do_per_step(step + nsttcouple - 1, nsttcouple));
-    bool doNoseHoover = (etc == etcNOSEHOOVER && doTempCouple);
-    bool doParrinelloRahman =
-            (epc == epcPARRINELLORAHMAN && do_per_step(step + nstpcouple - 1, nstpcouple));
+    bool doTempCouple =
+            (etc != TemperatureCoupling::No && do_per_step(step + nsttcouple - 1, nsttcouple));
+    bool doNoseHoover       = (etc == TemperatureCoupling::NoseHoover && doTempCouple);
+    bool doParrinelloRahman = (epc == PressureCoupling::ParrinelloRahman
+                               && do_per_step(step + nstpcouple - 1, nstpcouple));
     bool doPROffDiagonal = (doParrinelloRahman && (M[YY][XX] != 0 || M[ZZ][XX] != 0 || M[ZZ][YY] != 0));
 
     real dtPressureCouple = (doParrinelloRahman ? nstpcouple * dt : 0);
 
-    /* NEMD (also cosine) acceleration is applied in updateMDLeapFrogGeneral */
-    bool doAcceleration = (ekind->bNEMD || ekind->cosacc.cos_accel != 0);
+    /* NEMD cosine acceleration is applied in updateMDLeapFrogGeneral */
+    bool doAcceleration = (ekind->cosacc.cos_accel != 0);
 
     if (doNoseHoover || doPROffDiagonal || doAcceleration)
     {
@@ -673,38 +680,45 @@ static void do_update_md(int         start,
 
         if (!doAcceleration)
         {
-            updateMDLeapfrogGeneral<AccelerationType::none>(start, nrend, doNoseHoover, dt,
-                                                            dtPressureCouple, accel, md, ekind, box, x,
-                                                            xprime, v, f, nh_vxi, nsttcouple, stepM);
-        }
-        else if (ekind->bNEMD)
-        {
-            updateMDLeapfrogGeneral<AccelerationType::group>(
-                    start, nrend, doNoseHoover, dt, dtPressureCouple, accel, md, ekind, box, x,
-                    xprime, v, f, nh_vxi, nsttcouple, stepM);
+            updateMDLeapfrogGeneral<AccelerationType::none>(start,
+                                                            nrend,
+                                                            doNoseHoover,
+                                                            dt,
+                                                            dtPressureCouple,
+                                                            cTC,
+                                                            invMassPerDim,
+                                                            ekind,
+                                                            box,
+                                                            x,
+                                                            xprime,
+                                                            v,
+                                                            f,
+                                                            nh_vxi,
+                                                            nsttcouple,
+                                                            stepM);
         }
         else
         {
-            updateMDLeapfrogGeneral<AccelerationType::cosine>(
-                    start, nrend, doNoseHoover, dt, dtPressureCouple, accel, md, ekind, box, x,
-                    xprime, v, f, nh_vxi, nsttcouple, stepM);
+            updateMDLeapfrogGeneral<AccelerationType::cosine>(start,
+                                                              nrend,
+                                                              doNoseHoover,
+                                                              dt,
+                                                              dtPressureCouple,
+                                                              cTC,
+                                                              invMassPerDim,
+                                                              ekind,
+                                                              box,
+                                                              x,
+                                                              xprime,
+                                                              v,
+                                                              f,
+                                                              nh_vxi,
+                                                              nsttcouple,
+                                                              stepM);
         }
     }
     else
     {
-        /* Use a simple and thus more efficient integration loop. */
-        /* The simple loop does not check for particle type (so it can
-         * be vectorized), which means we need to clear the velocities
-         * of virtual sites in advance, when present. Note that vsite
-         * velocities are computed after update and constraints from
-         * their displacement.
-         */
-        if (md->haveVsites)
-        {
-            /* Note: The overhead of this loop is completely neligible */
-            clearVsiteVelocities(start, nrend, md->ptype, v);
-        }
-
         /* 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),
@@ -713,9 +727,7 @@ static void do_update_md(int         start,
         bool haveSingleTempScaleValue = (!doTempCouple || ekind->ngtc == 1);
 
         /* Extract some pointers needed by all cases */
-        const unsigned short*             cTC           = md->cTC;
-        gmx::ArrayRef<const t_grp_tcstat> tcstat        = ekind->tcstat;
-        const rvec*                       invMassPerDim = md->invMassPerDim;
+        gmx::ArrayRef<const t_grp_tcstat> tcstat = ekind->tcstat;
 
         if (doParrinelloRahman)
         {
@@ -731,17 +743,13 @@ static void do_update_md(int         start,
 
             if (haveSingleTempScaleValue)
             {
-                updateMDLeapfrogSimple<StoreUpdatedVelocities::yes, NumTempScaleValues::single,
-                                       ApplyParrinelloRahmanVScaling::diagonal>(
-                        start, nrend, dt, dtPressureCouple, invMassPerDim, tcstat, cTC, diagM, x,
-                        xprime, v, f);
+                updateMDLeapfrogSimple<StoreUpdatedVelocities::yes, NumTempScaleValues::single, ApplyParrinelloRahmanVScaling::diagonal>(
+                        start, nrend, dt, dtPressureCouple, invMassPerDim, tcstat, cTC, diagM, x, xprime, v, f);
             }
             else
             {
-                updateMDLeapfrogSimple<StoreUpdatedVelocities::yes, NumTempScaleValues::multiple,
-                                       ApplyParrinelloRahmanVScaling::diagonal>(
-                        start, nrend, dt, dtPressureCouple, invMassPerDim, tcstat, cTC, diagM, x,
-                        xprime, v, f);
+                updateMDLeapfrogSimple<StoreUpdatedVelocities::yes, NumTempScaleValues::multiple, ApplyParrinelloRahmanVScaling::diagonal>(
+                        start, nrend, dt, dtPressureCouple, invMassPerDim, tcstat, cTC, diagM, x, xprime, v, f);
             }
         }
         else
@@ -755,26 +763,22 @@ static void do_update_md(int         start,
                  */
 #if GMX_HAVE_SIMD_UPDATE
                 /* Check if we can use invmass instead of invMassPerDim */
-                if (!md->havePartiallyFrozenAtoms)
+                if (!havePartiallyFrozenAtoms)
                 {
                     updateMDLeapfrogSimpleSimd<StoreUpdatedVelocities::yes>(
-                            start, nrend, dt, md->invmass, tcstat, x, xprime, v, f);
+                            start, nrend, dt, invmass, tcstat, x, xprime, v, f);
                 }
                 else
 #endif
                 {
-                    updateMDLeapfrogSimple<StoreUpdatedVelocities::yes, NumTempScaleValues::single,
-                                           ApplyParrinelloRahmanVScaling::no>(
-                            start, nrend, dt, dtPressureCouple, invMassPerDim, tcstat, cTC, nullptr,
-                            x, xprime, v, f);
+                    updateMDLeapfrogSimple<StoreUpdatedVelocities::yes, NumTempScaleValues::single, ApplyParrinelloRahmanVScaling::no>(
+                            start, nrend, dt, dtPressureCouple, invMassPerDim, tcstat, cTC, nullptr, x, xprime, v, f);
                 }
             }
             else
             {
-                updateMDLeapfrogSimple<StoreUpdatedVelocities::yes, NumTempScaleValues::multiple,
-                                       ApplyParrinelloRahmanVScaling::no>(
-                        start, nrend, dt, dtPressureCouple, invMassPerDim, tcstat, cTC, nullptr, x,
-                        xprime, v, f);
+                updateMDLeapfrogSimple<StoreUpdatedVelocities::yes, NumTempScaleValues::multiple, ApplyParrinelloRahmanVScaling::no>(
+                        start, nrend, dt, dtPressureCouple, invMassPerDim, tcstat, cTC, nullptr, x, xprime, v, f);
             }
         }
     }
@@ -785,10 +789,12 @@ static void doUpdateMDDoNotUpdateVelocities(int         start,
                                             real        dt,
                                             const rvec* gmx_restrict x,
                                             rvec* gmx_restrict xprime,
-                                            rvec* gmx_restrict v,
+                                            const rvec* gmx_restrict v,
                                             const rvec* gmx_restrict f,
-                                            const t_mdatoms&         md,
-                                            const gmx_ekindata_t&    ekind)
+                                            bool gmx_unused           havePartiallyFrozenAtoms,
+                                            gmx::ArrayRef<const real> gmx_unused invmass,
+                                            gmx::ArrayRef<const rvec>            invMassPerDim,
+                                            const gmx_ekindata_t&                ekind)
 {
     GMX_ASSERT(nrend == start || xprime != x,
                "For SIMD optimization certain compilers need to have xprime != x");
@@ -797,35 +803,33 @@ static void doUpdateMDDoNotUpdateVelocities(int         start,
 
     /* Check if we can use invmass instead of invMassPerDim */
 #if GMX_HAVE_SIMD_UPDATE
-    if (!md.havePartiallyFrozenAtoms)
+    if (!havePartiallyFrozenAtoms)
     {
-        updateMDLeapfrogSimpleSimd<StoreUpdatedVelocities::no>(start, nrend, dt, md.invmass, tcstat,
-                                                               x, xprime, v, f);
+        updateMDLeapfrogSimpleSimd<StoreUpdatedVelocities::no>(
+                start, nrend, dt, invmass, tcstat, x, xprime, v, f);
     }
     else
 #endif
     {
         updateMDLeapfrogSimple<StoreUpdatedVelocities::no, NumTempScaleValues::single, ApplyParrinelloRahmanVScaling::no>(
-                start, nrend, dt, dt, md.invMassPerDim, tcstat, nullptr, nullptr, x, xprime, v, f);
+                start, nrend, dt, dt, invMassPerDim, tcstat, gmx::ArrayRef<const unsigned short>(), nullptr, x, xprime, v, f);
     }
 }
 
-static void do_update_vv_vel(int                  start,
-                             int                  nrend,
-                             real                 dt,
-                             const rvec           accel[],
-                             const ivec           nFreeze[],
-                             const real           invmass[],
-                             const unsigned short ptype[],
-                             const unsigned short cFREEZE[],
-                             const unsigned short cACC[],
-                             rvec                 v[],
-                             const rvec           f[],
-                             gmx_bool             bExtended,
-                             real                 veta,
-                             real                 alpha)
+static void do_update_vv_vel(int                                 start,
+                             int                                 nrend,
+                             real                                dt,
+                             gmx::ArrayRef<const ivec>           nFreeze,
+                             gmx::ArrayRef<const real>           invmass,
+                             gmx::ArrayRef<const ParticleType>   ptype,
+                             gmx::ArrayRef<const unsigned short> cFREEZE,
+                             rvec                                v[],
+                             const rvec                          f[],
+                             gmx_bool                            bExtended,
+                             real                                veta,
+                             real                                alpha)
 {
-    int  gf = 0, ga = 0;
+    int  gf = 0;
     int  n, d;
     real g, mv1, mv2;
 
@@ -843,20 +847,16 @@ static void do_update_vv_vel(int                  start,
     for (n = start; n < nrend; n++)
     {
         real w_dt = invmass[n] * dt;
-        if (cFREEZE)
+        if (!cFREEZE.empty())
         {
             gf = cFREEZE[n];
         }
-        if (cACC)
-        {
-            ga = cACC[n];
-        }
 
         for (d = 0; d < DIM; d++)
         {
-            if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[gf][d])
+            if ((ptype[n] != ParticleType::Shell) && !nFreeze[gf][d])
             {
-                v[n][d] = mv1 * (mv1 * v[n][d] + 0.5 * (w_dt * mv2 * f[n][d])) + 0.5 * accel[ga][d] * dt;
+                v[n][d] = mv1 * (mv1 * v[n][d] + 0.5 * (w_dt * mv2 * f[n][d]));
             }
             else
             {
@@ -866,17 +866,17 @@ static void do_update_vv_vel(int                  start,
     }
 } /* do_update_vv_vel */
 
-static void do_update_vv_pos(int                  start,
-                             int                  nrend,
-                             real                 dt,
-                             const ivec           nFreeze[],
-                             const unsigned short ptype[],
-                             const unsigned short cFREEZE[],
-                             const rvec           x[],
-                             rvec                 xprime[],
-                             const rvec           v[],
-                             gmx_bool             bExtended,
-                             real                 veta)
+static void do_update_vv_pos(int                                 start,
+                             int                                 nrend,
+                             real                                dt,
+                             gmx::ArrayRef<const ivec>           nFreeze,
+                             gmx::ArrayRef<const ParticleType>   ptype,
+                             gmx::ArrayRef<const unsigned short> cFREEZE,
+                             const rvec                          x[],
+                             rvec                                xprime[],
+                             const rvec                          v[],
+                             gmx_bool                            bExtended,
+                             real                                veta)
 {
     int  gf = 0;
     int  n, d;
@@ -898,14 +898,14 @@ static void do_update_vv_pos(int                  start,
     for (n = start; n < nrend; n++)
     {
 
-        if (cFREEZE)
+        if (!cFREEZE.empty())
         {
             gf = cFREEZE[n];
         }
 
         for (d = 0; d < DIM; d++)
         {
-            if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[gf][d])
+            if ((ptype[n] != ParticleType::Shell) && !nFreeze[gf][d])
             {
                 xprime[n][d] = mr1 * (mr1 * x[n][d] + mr2 * dt * v[n][d]);
             }
@@ -922,7 +922,7 @@ gmx_stochd_t::gmx_stochd_t(const t_inputrec& inputRecord)
     const t_grpopts* opts = &inputRecord.opts;
     const int        ngtc = opts->ngtc;
 
-    if (inputRecord.eI == eiBD)
+    if (inputRecord.eI == IntegrationAlgorithm::BD)
     {
         bd_rf.resize(ngtc);
     }
@@ -959,7 +959,7 @@ gmx_stochd_t::gmx_stochd_t(const t_inputrec& inputRecord)
                 && (reft > 0)) /* tau_t or ref_t = 0 means that no randomization is done */
             {
                 randomize_group[gt] = true;
-                boltzfac[gt]        = BOLTZ * opts->ref_t[gt];
+                boltzfac[gt]        = gmx::c_boltz * opts->ref_t[gt];
             }
             else
             {
@@ -971,13 +971,13 @@ gmx_stochd_t::gmx_stochd_t(const t_inputrec& inputRecord)
 
 void Update::Impl::update_temperature_constants(const t_inputrec& inputRecord)
 {
-    if (inputRecord.eI == eiBD)
+    if (inputRecord.eI == IntegrationAlgorithm::BD)
     {
         if (inputRecord.bd_fric != 0)
         {
             for (int gt = 0; gt < inputRecord.opts.ngtc; gt++)
             {
-                sd_.bd_rf[gt] = std::sqrt(2.0 * BOLTZ * inputRecord.opts.ref_t[gt]
+                sd_.bd_rf[gt] = std::sqrt(2.0 * gmx::c_boltz * inputRecord.opts.ref_t[gt]
                                           / (inputRecord.bd_fric * inputRecord.delta_t));
             }
         }
@@ -985,15 +985,15 @@ void Update::Impl::update_temperature_constants(const t_inputrec& inputRecord)
         {
             for (int gt = 0; gt < inputRecord.opts.ngtc; gt++)
             {
-                sd_.bd_rf[gt] = std::sqrt(2.0 * BOLTZ * inputRecord.opts.ref_t[gt]);
+                sd_.bd_rf[gt] = std::sqrt(2.0 * gmx::c_boltz * inputRecord.opts.ref_t[gt]);
             }
         }
     }
-    if (inputRecord.eI == eiSD1)
+    if (inputRecord.eI == IntegrationAlgorithm::SD1)
     {
         for (int gt = 0; gt < inputRecord.opts.ngtc; gt++)
         {
-            real kT = BOLTZ * inputRecord.opts.ref_t[gt];
+            real kT = gmx::c_boltz * inputRecord.opts.ref_t[gt];
             /* The mass is accounted for later, since this differs per atom */
             sd_.sdsig[gt].V = std::sqrt(kT * (1 - sd_.sdc[gt].em * sd_.sdc[gt].em));
         }
@@ -1008,10 +1008,14 @@ Update::Impl::Impl(const t_inputrec& inputRecord, BoxDeformation* boxDeformation
     xp_.resizeWithPadding(0);
 }
 
-void Update::setNumAtoms(int numAtoms)
+void Update::updateAfterPartition(int                                 numAtoms,
+                                  gmx::ArrayRef<const unsigned short> cFREEZE,
+                                  gmx::ArrayRef<const unsigned short> cTC)
 {
 
     impl_->xp()->resizeWithPadding(numAtoms);
+    impl_->cFREEZE_ = cFREEZE;
+    impl_->cTC_     = cTC;
 }
 
 /*! \brief Sets the SD update type */
@@ -1036,37 +1040,34 @@ enum class SDUpdate : int
  * Thus three instantiations of this templated function will be made,
  * two with only one contribution, and one with both contributions. */
 template<SDUpdate updateType>
-static void doSDUpdateGeneral(const gmx_stochd_t&  sd,
-                              int                  start,
-                              int                  nrend,
-                              real                 dt,
-                              const rvec           accel[],
-                              const ivec           nFreeze[],
-                              const real           invmass[],
-                              const unsigned short ptype[],
-                              const unsigned short cFREEZE[],
-                              const unsigned short cACC[],
-                              const unsigned short cTC[],
-                              const rvec           x[],
-                              rvec                 xprime[],
-                              rvec                 v[],
-                              const rvec           f[],
-                              int64_t              step,
-                              int                  seed,
-                              const int*           gatindex)
+static void doSDUpdateGeneral(const gmx_stochd_t&                 sd,
+                              int                                 start,
+                              int                                 nrend,
+                              real                                dt,
+                              gmx::ArrayRef<const ivec>           nFreeze,
+                              gmx::ArrayRef<const real>           invmass,
+                              gmx::ArrayRef<const ParticleType>   ptype,
+                              gmx::ArrayRef<const unsigned short> cFREEZE,
+                              gmx::ArrayRef<const unsigned short> cTC,
+                              const rvec                          x[],
+                              rvec                                xprime[],
+                              rvec                                v[],
+                              const rvec                          f[],
+                              int64_t                             step,
+                              int                                 seed,
+                              const int*                          gatindex)
 {
-    // cTC, cACC and cFREEZE can be nullptr any time, but various
+    // cTC and cFREEZE can be nullptr any time, but various
     // instantiations do not make sense with particular pointer
     // values.
     if (updateType == SDUpdate::ForcesOnly)
     {
         GMX_ASSERT(f != nullptr, "SD update with only forces requires forces");
-        GMX_ASSERT(cTC == nullptr, "SD update with only forces cannot handle temperature groups");
+        GMX_ASSERT(cTC.empty(), "SD update with only forces cannot handle temperature groups");
     }
     if (updateType == SDUpdate::FrictionAndNoiseOnly)
     {
         GMX_ASSERT(f == nullptr, "SD update with only noise cannot handle forces");
-        GMX_ASSERT(cACC == nullptr, "SD update with only noise cannot handle acceleration groups");
     }
     if (updateType == SDUpdate::Combined)
     {
@@ -1086,17 +1087,16 @@ static void doSDUpdateGeneral(const gmx_stochd_t&  sd,
         real inverseMass = invmass[n];
         real invsqrtMass = std::sqrt(inverseMass);
 
-        int freezeGroup       = cFREEZE ? cFREEZE[n] : 0;
-        int accelerationGroup = cACC ? cACC[n] : 0;
-        int temperatureGroup  = cTC ? cTC[n] : 0;
+        int freezeGroup      = !cFREEZE.empty() ? cFREEZE[n] : 0;
+        int temperatureGroup = !cTC.empty() ? cTC[n] : 0;
 
         for (int d = 0; d < DIM; d++)
         {
-            if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[freezeGroup][d])
+            if ((ptype[n] != ParticleType::Shell) && !nFreeze[freezeGroup][d])
             {
                 if (updateType == SDUpdate::ForcesOnly)
                 {
-                    real vn = v[n][d] + (inverseMass * f[n][d] + accel[accelerationGroup][d]) * dt;
+                    real vn = v[n][d] + inverseMass * f[n][d] * dt;
                     v[n][d] = vn;
                     // Simple position update.
                     xprime[n][d] = x[n][d] + v[n][d] * dt;
@@ -1113,7 +1113,7 @@ static void doSDUpdateGeneral(const gmx_stochd_t&  sd,
                 }
                 else
                 {
-                    real vn = v[n][d] + (inverseMass * f[n][d] + accel[accelerationGroup][d]) * dt;
+                    real vn = v[n][d] + inverseMass * f[n][d] * dt;
                     v[n][d] = (vn * sd.sdc[temperatureGroup].em
                                + invsqrtMass * sd.sdsig[temperatureGroup].V * dist(rng));
                     // Here we include half of the friction+noise
@@ -1144,31 +1144,55 @@ static void do_update_sd(int         start,
                          const rvec* gmx_restrict x,
                          rvec* gmx_restrict xprime,
                          rvec* gmx_restrict v,
-                         const rvec* gmx_restrict f,
-                         const rvec               accel[],
-                         const ivec               nFreeze[],
-                         const real               invmass[],
-                         const unsigned short     ptype[],
-                         const unsigned short     cFREEZE[],
-                         const unsigned short     cACC[],
-                         const unsigned short     cTC[],
-                         int                      seed,
-                         const t_commrec*         cr,
-                         const gmx_stochd_t&      sd,
-                         bool                     haveConstraints)
+                         const rvec* gmx_restrict            f,
+                         gmx::ArrayRef<const ivec>           nFreeze,
+                         gmx::ArrayRef<const real>           invmass,
+                         gmx::ArrayRef<const ParticleType>   ptype,
+                         gmx::ArrayRef<const unsigned short> cFREEZE,
+                         gmx::ArrayRef<const unsigned short> cTC,
+                         int                                 seed,
+                         const t_commrec*                    cr,
+                         const gmx_stochd_t&                 sd,
+                         bool                                haveConstraints)
 {
     if (haveConstraints)
     {
         // With constraints, the SD update is done in 2 parts
-        doSDUpdateGeneral<SDUpdate::ForcesOnly>(sd, start, nrend, dt, accel, nFreeze, invmass,
-                                                ptype, cFREEZE, cACC, nullptr, x, xprime, v, f,
-                                                step, seed, nullptr);
+        doSDUpdateGeneral<SDUpdate::ForcesOnly>(sd,
+                                                start,
+                                                nrend,
+                                                dt,
+                                                nFreeze,
+                                                invmass,
+                                                ptype,
+                                                cFREEZE,
+                                                gmx::ArrayRef<const unsigned short>(),
+                                                x,
+                                                xprime,
+                                                v,
+                                                f,
+                                                step,
+                                                seed,
+                                                nullptr);
     }
     else
     {
-        doSDUpdateGeneral<SDUpdate::Combined>(
-                sd, start, nrend, dt, accel, nFreeze, invmass, ptype, cFREEZE, cACC, cTC, x, xprime,
-                v, f, step, seed, DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
+        doSDUpdateGeneral<SDUpdate::Combined>(sd,
+                                              start,
+                                              nrend,
+                                              dt,
+                                              nFreeze,
+                                              invmass,
+                                              ptype,
+                                              cFREEZE,
+                                              cTC,
+                                              x,
+                                              xprime,
+                                              v,
+                                              f,
+                                              step,
+                                              seed,
+                                              DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
     }
 }
 
@@ -1179,16 +1203,16 @@ static void do_update_bd(int         start,
                          const rvec* gmx_restrict x,
                          rvec* gmx_restrict xprime,
                          rvec* gmx_restrict v,
-                         const rvec* gmx_restrict f,
-                         const ivec               nFreeze[],
-                         const real               invmass[],
-                         const unsigned short     ptype[],
-                         const unsigned short     cFREEZE[],
-                         const unsigned short     cTC[],
-                         real                     friction_coefficient,
-                         const real*              rf,
-                         int                      seed,
-                         const int*               gatindex)
+                         const rvec* gmx_restrict            f,
+                         gmx::ArrayRef<const ivec>           nFreeze,
+                         gmx::ArrayRef<const real>           invmass,
+                         gmx::ArrayRef<const ParticleType>   ptype,
+                         gmx::ArrayRef<const unsigned short> cFREEZE,
+                         gmx::ArrayRef<const unsigned short> cTC,
+                         real                                friction_coefficient,
+                         const real*                         rf,
+                         int                                 seed,
+                         const int*                          gatindex)
 {
     /* note -- these appear to be full step velocities . . .  */
     int  gf = 0, gt = 0;
@@ -1212,17 +1236,17 @@ static void do_update_bd(int         start,
         rng.restart(step, ng);
         dist.reset();
 
-        if (cFREEZE)
+        if (!cFREEZE.empty())
         {
             gf = cFREEZE[n];
         }
-        if (cTC)
+        if (!cTC.empty())
         {
             gt = cTC[n];
         }
         for (d = 0; (d < DIM); d++)
         {
-            if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[gf][d])
+            if ((ptype[n] != ParticleType::Shell) && !nFreeze[gf][d])
             {
                 if (friction_coefficient != 0)
                 {
@@ -1308,19 +1332,23 @@ void restore_ekinstate_from_state(const t_commrec* cr, gmx_ekindata_t* ekind, co
         gmx_bcast(sizeof(n), &n, cr->mpi_comm_mygroup);
         for (i = 0; i < n; i++)
         {
-            gmx_bcast(DIM * DIM * sizeof(ekind->tcstat[i].ekinh[0][0]), ekind->tcstat[i].ekinh[0],
+            gmx_bcast(DIM * DIM * sizeof(ekind->tcstat[i].ekinh[0][0]),
+                      ekind->tcstat[i].ekinh[0],
                       cr->mpi_comm_mygroup);
-            gmx_bcast(DIM * DIM * sizeof(ekind->tcstat[i].ekinf[0][0]), ekind->tcstat[i].ekinf[0],
+            gmx_bcast(DIM * DIM * sizeof(ekind->tcstat[i].ekinf[0][0]),
+                      ekind->tcstat[i].ekinf[0],
                       cr->mpi_comm_mygroup);
             gmx_bcast(DIM * DIM * sizeof(ekind->tcstat[i].ekinh_old[0][0]),
-                      ekind->tcstat[i].ekinh_old[0], cr->mpi_comm_mygroup);
-
-            gmx_bcast(sizeof(ekind->tcstat[i].ekinscalef_nhc), &(ekind->tcstat[i].ekinscalef_nhc),
+                      ekind->tcstat[i].ekinh_old[0],
                       cr->mpi_comm_mygroup);
-            gmx_bcast(sizeof(ekind->tcstat[i].ekinscaleh_nhc), &(ekind->tcstat[i].ekinscaleh_nhc),
+
+            gmx_bcast(sizeof(ekind->tcstat[i].ekinscalef_nhc),
+                      &(ekind->tcstat[i].ekinscalef_nhc),
                       cr->mpi_comm_mygroup);
-            gmx_bcast(sizeof(ekind->tcstat[i].vscale_nhc), &(ekind->tcstat[i].vscale_nhc),
+            gmx_bcast(sizeof(ekind->tcstat[i].ekinscaleh_nhc),
+                      &(ekind->tcstat[i].ekinscaleh_nhc),
                       cr->mpi_comm_mygroup);
+            gmx_bcast(sizeof(ekind->tcstat[i].vscale_nhc), &(ekind->tcstat[i].vscale_nhc), cr->mpi_comm_mygroup);
         }
         gmx_bcast(DIM * DIM * sizeof(ekind->ekin[0][0]), ekind->ekin[0], cr->mpi_comm_mygroup);
 
@@ -1346,25 +1374,26 @@ void getThreadAtomRange(int numThreads, int threadIndex, int numAtoms, int* star
     }
 }
 
-void Update::Impl::update_sd_second_half(const t_inputrec& inputRecord,
-                                         int64_t           step,
-                                         real*             dvdlambda,
-                                         const t_mdatoms*  md,
-                                         t_state*          state,
-                                         const t_commrec*  cr,
-                                         t_nrnb*           nrnb,
-                                         gmx_wallcycle_t   wcycle,
-                                         gmx::Constraints* constr,
-                                         bool              do_log,
-                                         bool              do_ene)
+void Update::Impl::update_sd_second_half(const t_inputrec&                 inputRecord,
+                                         int64_t                           step,
+                                         real*                             dvdlambda,
+                                         int                               homenr,
+                                         gmx::ArrayRef<const ParticleType> ptype,
+                                         gmx::ArrayRef<const real>         invMass,
+                                         t_state*                          state,
+                                         const t_commrec*                  cr,
+                                         t_nrnb*                           nrnb,
+                                         gmx_wallcycle*                    wcycle,
+                                         gmx::Constraints*                 constr,
+                                         bool                              do_log,
+                                         bool                              do_ene)
 {
     if (!constr)
     {
         return;
     }
-    if (inputRecord.eI == eiSD1)
+    if (inputRecord.eI == IntegrationAlgorithm::SD1)
     {
-        int homenr = md->homenr;
 
         /* 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
@@ -1375,9 +1404,9 @@ void Update::Impl::update_sd_second_half(const t_inputrec& inputRecord,
          */
         real dt = inputRecord.delta_t;
 
-        wallcycle_start(wcycle, ewcUPDATE);
+        wallcycle_start(wcycle, WallCycleCounter::Update);
 
-        int nth = gmx_omp_nthreads_get(emntUpdate);
+        int nth = gmx_omp_nthreads_get(ModuleMultiThread::Update);
 
 #pragma omp parallel for num_threads(nth) schedule(static)
         for (int th = 0; th < nth; th++)
@@ -1388,42 +1417,66 @@ void Update::Impl::update_sd_second_half(const t_inputrec& inputRecord,
                 getThreadAtomRange(nth, th, homenr, &start_th, &end_th);
 
                 doSDUpdateGeneral<SDUpdate::FrictionAndNoiseOnly>(
-                        sd_, start_th, end_th, dt, inputRecord.opts.acc, inputRecord.opts.nFreeze,
-                        md->invmass, md->ptype, md->cFREEZE, nullptr, md->cTC, state->x.rvec_array(),
-                        xp_.rvec_array(), state->v.rvec_array(), nullptr, step, inputRecord.ld_seed,
+                        sd_,
+                        start_th,
+                        end_th,
+                        dt,
+                        gmx::arrayRefFromArray(inputRecord.opts.nFreeze, inputRecord.opts.ngfrz),
+                        invMass,
+                        ptype,
+                        cFREEZE_,
+                        cTC_,
+                        state->x.rvec_array(),
+                        xp_.rvec_array(),
+                        state->v.rvec_array(),
+                        nullptr,
+                        step,
+                        inputRecord.ld_seed,
                         DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
             }
             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
         }
         inc_nrnb(nrnb, eNR_UPDATE, homenr);
-        wallcycle_stop(wcycle, ewcUPDATE);
+        wallcycle_stop(wcycle, WallCycleCounter::Update);
 
         /* Constrain the coordinates upd->xp for half a time step */
         bool computeVirial = false;
-        constr->apply(do_log, do_ene, step, 1, 0.5, state->x.arrayRefWithPadding(),
-                      xp_.arrayRefWithPadding(), ArrayRef<RVec>(), state->box,
-                      state->lambda[efptBONDED], dvdlambda, state->v.arrayRefWithPadding(),
-                      computeVirial, nullptr, ConstraintVariable::Positions);
+        constr->apply(do_log,
+                      do_ene,
+                      step,
+                      1,
+                      0.5,
+                      state->x.arrayRefWithPadding(),
+                      xp_.arrayRefWithPadding(),
+                      ArrayRef<RVec>(),
+                      state->box,
+                      state->lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Bonded)],
+                      dvdlambda,
+                      state->v.arrayRefWithPadding(),
+                      computeVirial,
+                      nullptr,
+                      ConstraintVariable::Positions);
     }
 }
 
-void Update::Impl::finish_update(const t_inputrec& inputRecord,
-                                 const t_mdatoms*  md,
-                                 t_state*          state,
-                                 gmx_wallcycle_t   wcycle,
-                                 const bool        haveConstraints)
+void Update::Impl::finish_update(const t_inputrec&                   inputRecord,
+                                 const bool                          havePartiallyFrozenAtoms,
+                                 const int                           homenr,
+                                 gmx::ArrayRef<const unsigned short> cFREEZE,
+                                 t_state*                            state,
+                                 gmx_wallcycle*                      wcycle,
+                                 const bool                          haveConstraints)
 {
     /* NOTE: Currently we always integrate to a temporary buffer and
      * then copy the results back here.
      */
 
-    wallcycle_start_nocount(wcycle, ewcUPDATE);
+    wallcycle_start_nocount(wcycle, WallCycleCounter::Update);
 
-    const int homenr = md->homenr;
-    auto      xp     = makeConstArrayRef(xp_).subArray(0, homenr);
-    auto      x      = makeArrayRef(state->x).subArray(0, homenr);
+    auto xp = makeConstArrayRef(xp_).subArray(0, homenr);
+    auto x  = makeArrayRef(state->x).subArray(0, homenr);
 
-    if (md->havePartiallyFrozenAtoms && haveConstraints)
+    if (havePartiallyFrozenAtoms && haveConstraints)
     {
         /* We have atoms that are frozen along some, but not all dimensions,
          * then constraints will have moved them also along the frozen dimensions.
@@ -1433,7 +1486,7 @@ void Update::Impl::finish_update(const t_inputrec& inputRecord,
 
         for (int i = 0; i < homenr; i++)
         {
-            const int g = md->cFREEZE[i];
+            const int g = cFREEZE[i];
 
             for (int d = 0; d < DIM; d++)
             {
@@ -1449,7 +1502,7 @@ void Update::Impl::finish_update(const t_inputrec& inputRecord,
         /* We have no frozen atoms or fully frozen atoms which have not
          * been moved by the update, so we can simply copy all coordinates.
          */
-        int gmx_unused nth = gmx_omp_nthreads_get(emntUpdate);
+        int gmx_unused nth = gmx_omp_nthreads_get(ModuleMultiThread::Update);
 #pragma omp parallel for num_threads(nth) schedule(static)
         for (int i = 0; i < homenr; i++)
         {
@@ -1458,13 +1511,17 @@ void Update::Impl::finish_update(const t_inputrec& inputRecord,
         }
     }
 
-    wallcycle_stop(wcycle, ewcUPDATE);
+    wallcycle_stop(wcycle, WallCycleCounter::Update);
 }
 
-void Update::Impl::update_coords(const t_inputrec&                                inputRecord,
-                                 int64_t                                          step,
-                                 const t_mdatoms*                                 md,
-                                 t_state*                                         state,
+void Update::Impl::update_coords(const t_inputrec&                 inputRecord,
+                                 int64_t                           step,
+                                 int                               homenr,
+                                 bool                              havePartiallyFrozenAtoms,
+                                 gmx::ArrayRef<const ParticleType> ptype,
+                                 gmx::ArrayRef<const real>         invMass,
+                                 gmx::ArrayRef<const rvec>         invMassPerDim,
+                                 t_state*                          state,
                                  const gmx::ArrayRefWithPadding<const gmx::RVec>& f,
                                  const t_fcdata&                                  fcdata,
                                  const gmx_ekindata_t*                            ekind,
@@ -1479,23 +1536,21 @@ void Update::Impl::update_coords(const t_inputrec&
         gmx_incons("update_coords called for velocity without VV integrator");
     }
 
-    int homenr = md->homenr;
-
     /* Cast to real for faster code, no loss in precision (see comment above) */
     real dt = inputRecord.delta_t;
 
     /* We need to update the NMR restraint history when time averaging is used */
-    if (state->flags & (1 << estDISRE_RM3TAV))
+    if (state->flags & enumValueToBitMask(StateEntry::DisreRm3Tav))
     {
         update_disres_history(*fcdata.disres, &state->hist);
     }
-    if (state->flags & (1 << estORIRE_DTAV))
+    if (state->flags & enumValueToBitMask(StateEntry::OrireDtav))
     {
         update_orires_history(*fcdata.orires, &state->hist);
     }
 
     /* ############# START The update of velocities and positions ######### */
-    int nth = gmx_omp_nthreads_get(emntUpdate);
+    int nth = gmx_omp_nthreads_get(ModuleMultiThread::Update);
 
 #pragma omp parallel for num_threads(nth) schedule(static)
     for (int th = 0; th < nth; th++)
@@ -1512,29 +1567,72 @@ void Update::Impl::update_coords(const t_inputrec&
 
             switch (inputRecord.eI)
             {
-                case (eiMD):
-                    do_update_md(start_th, end_th, dt, step, x_rvec, xp_rvec, v_rvec, f_rvec,
-                                 inputRecord.opts.acc, inputRecord.etc, inputRecord.epc,
-                                 inputRecord.nsttcouple, inputRecord.nstpcouple, md, ekind,
-                                 state->box, state->nosehoover_vxi.data(), M);
+                case (IntegrationAlgorithm::MD):
+                    do_update_md(start_th,
+                                 end_th,
+                                 dt,
+                                 step,
+                                 x_rvec,
+                                 xp_rvec,
+                                 v_rvec,
+                                 f_rvec,
+                                 inputRecord.etc,
+                                 inputRecord.epc,
+                                 inputRecord.nsttcouple,
+                                 inputRecord.nstpcouple,
+                                 cTC_,
+                                 invMass,
+                                 invMassPerDim,
+                                 ekind,
+                                 state->box,
+                                 state->nosehoover_vxi.data(),
+                                 M,
+                                 havePartiallyFrozenAtoms);
                     break;
-                case (eiSD1):
-                    do_update_sd(start_th, end_th, dt, step, x_rvec, xp_rvec, v_rvec, f_rvec,
-                                 inputRecord.opts.acc, inputRecord.opts.nFreeze, md->invmass,
-                                 md->ptype, md->cFREEZE, md->cACC, md->cTC, inputRecord.ld_seed, cr,
-                                 sd_, haveConstraints);
+                case (IntegrationAlgorithm::SD1):
+                    do_update_sd(start_th,
+                                 end_th,
+                                 dt,
+                                 step,
+                                 x_rvec,
+                                 xp_rvec,
+                                 v_rvec,
+                                 f_rvec,
+                                 gmx::arrayRefFromArray(inputRecord.opts.nFreeze, inputRecord.opts.ngfrz),
+                                 invMass,
+                                 ptype,
+                                 cFREEZE_,
+                                 cTC_,
+                                 inputRecord.ld_seed,
+                                 cr,
+                                 sd_,
+                                 haveConstraints);
                     break;
-                case (eiBD):
-                    do_update_bd(start_th, end_th, dt, step, x_rvec, xp_rvec, v_rvec, f_rvec,
-                                 inputRecord.opts.nFreeze, md->invmass, md->ptype, md->cFREEZE,
-                                 md->cTC, inputRecord.bd_fric, sd_.bd_rf.data(), inputRecord.ld_seed,
+                case (IntegrationAlgorithm::BD):
+                    do_update_bd(start_th,
+                                 end_th,
+                                 dt,
+                                 step,
+                                 x_rvec,
+                                 xp_rvec,
+                                 v_rvec,
+                                 f_rvec,
+                                 gmx::arrayRefFromArray(inputRecord.opts.nFreeze, inputRecord.opts.ngfrz),
+                                 invMass,
+                                 ptype,
+                                 cFREEZE_,
+                                 cTC_,
+                                 inputRecord.bd_fric,
+                                 sd_.bd_rf.data(),
+                                 inputRecord.ld_seed,
                                  DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
                     break;
-                case (eiVV):
-                case (eiVVAK):
+                case (IntegrationAlgorithm::VV):
+                case (IntegrationAlgorithm::VVAK):
                 {
-                    gmx_bool bExtended = (inputRecord.etc == etcNOSEHOOVER || inputRecord.epc == epcPARRINELLORAHMAN
-                                          || inputRecord.epc == epcMTTK);
+                    gmx_bool bExtended = (inputRecord.etc == TemperatureCoupling::NoseHoover
+                                          || inputRecord.epc == PressureCoupling::ParrinelloRahman
+                                          || inputRecord.epc == PressureCoupling::Mttk);
 
                     /* assuming barostat coupled to group 0 */
                     real alpha = 1.0 + DIM / static_cast<real>(inputRecord.opts.nrdf[0]);
@@ -1542,14 +1640,33 @@ void Update::Impl::update_coords(const t_inputrec&
                     {
                         case etrtVELOCITY1:
                         case etrtVELOCITY2:
-                            do_update_vv_vel(start_th, end_th, dt, inputRecord.opts.acc,
-                                             inputRecord.opts.nFreeze, md->invmass, md->ptype, md->cFREEZE,
-                                             md->cACC, v_rvec, f_rvec, bExtended, state->veta, alpha);
+                            do_update_vv_vel(start_th,
+                                             end_th,
+                                             dt,
+                                             gmx::arrayRefFromArray(inputRecord.opts.nFreeze,
+                                                                    inputRecord.opts.ngfrz),
+                                             invMass,
+                                             ptype,
+                                             cFREEZE_,
+                                             v_rvec,
+                                             f_rvec,
+                                             bExtended,
+                                             state->veta,
+                                             alpha);
                             break;
                         case etrtPOSITION:
-                            do_update_vv_pos(start_th, end_th, dt, inputRecord.opts.nFreeze,
-                                             md->ptype, md->cFREEZE, x_rvec, xp_rvec, v_rvec,
-                                             bExtended, state->veta);
+                            do_update_vv_pos(start_th,
+                                             end_th,
+                                             dt,
+                                             gmx::arrayRefFromArray(inputRecord.opts.nFreeze,
+                                                                    inputRecord.opts.ngfrz),
+                                             ptype,
+                                             cFREEZE_,
+                                             x_rvec,
+                                             xp_rvec,
+                                             v_rvec,
+                                             bExtended,
+                                             state->veta);
                             break;
                     }
                     break;
@@ -1561,19 +1678,22 @@ void Update::Impl::update_coords(const t_inputrec&
     }
 }
 
-void Update::Impl::update_for_constraint_virial(const t_inputrec& inputRecord,
-                                                const t_mdatoms&  md,
-                                                const t_state&    state,
+void Update::Impl::update_for_constraint_virial(const t_inputrec&         inputRecord,
+                                                int                       homenr,
+                                                bool                      havePartiallyFrozenAtoms,
+                                                gmx::ArrayRef<const real> invmass,
+                                                gmx::ArrayRef<const rvec> invMassPerDim,
+                                                const t_state&            state,
                                                 const gmx::ArrayRefWithPadding<const gmx::RVec>& f,
                                                 const gmx_ekindata_t& ekind)
 {
-    GMX_ASSERT(inputRecord.eI == eiMD || inputRecord.eI == eiSD1,
+    GMX_ASSERT(inputRecord.eI == IntegrationAlgorithm::MD || inputRecord.eI == IntegrationAlgorithm::SD1,
                "Only leap-frog is supported here");
 
     // Cast to real for faster code, no loss in precision
     const real dt = inputRecord.delta_t;
 
-    const int nth = gmx_omp_nthreads_get(emntUpdate);
+    const int nth = gmx_omp_nthreads_get(ModuleMultiThread::Update);
 
 #pragma omp parallel for num_threads(nth) schedule(static)
     for (int th = 0; th < nth; th++)
@@ -1581,15 +1701,15 @@ void Update::Impl::update_for_constraint_virial(const t_inputrec& inputRecord,
         try
         {
             int start_th, end_th;
-            getThreadAtomRange(nth, th, md.homenr, &start_th, &end_th);
+            getThreadAtomRange(nth, th, homenr, &start_th, &end_th);
 
             const rvec* x_rvec  = state.x.rvec_array();
             rvec*       xp_rvec = xp_.rvec_array();
-            rvec*       v_rvec  = const_cast<rvec*>(state.v.rvec_array());
+            const rvec* v_rvec  = state.v.rvec_array();
             const rvec* f_rvec  = as_rvec_array(f.unpaddedConstArrayRef().data());
 
-            doUpdateMDDoNotUpdateVelocities(start_th, end_th, dt, x_rvec, xp_rvec, v_rvec, f_rvec,
-                                            md, ekind);
+            doUpdateMDDoNotUpdateVelocities(
+                    start_th, end_th, dt, x_rvec, xp_rvec, v_rvec, f_rvec, havePartiallyFrozenAtoms, invmass, invMassPerDim, ekind);
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
     }
index 9c3d434ec9f209d8dcbce531ec0f1fcbea70a2f1..6771d60f3d06fc72f0896296d5408b2d6de0c0fa 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_MDLIB_UPDATE_H
 #define GMX_MDLIB_UPDATE_H
 
+#include <memory>
+
 #include "gromacs/math/paddedvector.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/timing/wallcycle.h"
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/real.h"
 
 class ekinstate_t;
-struct gmx_ekindata_t;
+class gmx_ekindata_t;
 struct gmx_enerdata_t;
 enum class PbcType;
 struct t_fcdata;
 struct t_graph;
 struct t_grpopts;
 struct t_inputrec;
-struct t_mdatoms;
 struct t_nrnb;
 class t_state;
+enum class ParticleType;
 
 namespace gmx
 {
@@ -92,31 +92,43 @@ public:
      * \returns handle to box deformation class
      */
     BoxDeformation* deform() const;
-    /*! \brief Resizes buffer that stores intermediate coordinates.
+    /*! \brief Sets data that changes only at domain decomposition time.
      *
      * \param[in] numAtoms  Updated number of atoms.
+     * \param[in] cFREEZE   Group index for freezing
+     * \param[in] cTC       Group index for center of mass motion removal
      */
-    void setNumAtoms(int numAtoms);
+    void updateAfterPartition(int                                 numAtoms,
+                              gmx::ArrayRef<const unsigned short> cFREEZE,
+                              gmx::ArrayRef<const unsigned short> cTC);
 
     /*! \brief Perform numerical integration step.
      *
      * Selects the appropriate integrator, based on the input record and performs a numerical integration step.
      *
-     * \param[in]  inputRecord      Input record.
-     * \param[in]  step             Current timestep.
-     * \param[in]  md               MD atoms data.
-     * \param[in]  state            System state object.
-     * \param[in]  f                Buffer with atomic forces for home particles.
-     * \param[in]  fcdata           Force calculation data to update distance and orientation restraints.
-     * \param[in]  ekind            Kinetic energy data (for temperature coupling, energy groups, etc.).
-     * \param[in]  M                Parrinello-Rahman velocity scaling matrix.
-     * \param[in]  updatePart       What should be updated, coordinates or velocities. This enum only used in VV integrator.
-     * \param[in]  cr               Comunication record  (Old comment: these shouldn't be here -- need to think about it).
-     * \param[in]  haveConstraints  If the system has constraints.
+     * \param[in]  inputRecord               Input record.
+     * \param[in]  step                      Current timestep.
+     * \param[in]  homenr                    The number of atoms on this processor.
+     * \param[in]  havePartiallyFrozenAtoms  Whether atoms are frozen along 1 or 2 (not 3) dimensions?
+     * \param[in]  ptype                     The list of particle types.
+     * \param[in]  invMass                   Inverse atomic mass per atom, 0 for vsites and shells.
+     * \param[in]  invMassPerDim             Inverse atomic mass per atom and dimension, 0 for vsites, shells and frozen dimensions
+     * \param[in]  state                     System state object.
+     * \param[in]  f                         Buffer with atomic forces for home particles.
+     * \param[in]  fcdata                    Force calculation data to update distance and orientation restraints.
+     * \param[in]  ekind                     Kinetic energy data (for temperature coupling, energy groups, etc.).
+     * \param[in]  M                         Parrinello-Rahman velocity scaling matrix.
+     * \param[in]  updatePart                What should be updated, coordinates or velocities. This enum only used in VV integrator.
+     * \param[in]  cr                        Comunication record  (Old comment: these shouldn't be here -- need to think about it).
+     * \param[in]  haveConstraints           If the system has constraints.
      */
     void update_coords(const t_inputrec&                                inputRecord,
                        int64_t                                          step,
-                       const t_mdatoms*                                 md,
+                       int                                              homenr,
+                       bool                                             havePartiallyFrozenAtoms,
+                       gmx::ArrayRef<const ParticleType>                ptype,
+                       gmx::ArrayRef<const real>                        invMass,
+                       gmx::ArrayRef<const rvec>                        invMassPerDim,
                        t_state*                                         state,
                        const gmx::ArrayRefWithPadding<const gmx::RVec>& f,
                        const t_fcdata&                                  fcdata,
@@ -131,15 +143,17 @@ public:
      * Copy the updated coordinates to the main coordinates buffer for the atoms that are not frozen.
      *
      * \param[in]  inputRecord      Input record.
-     * \param[in]  md               MD atoms data.
+     * \param[in]  havePartiallyFrozenAtoms  Whether atoms are frozen along 1 or 2 (not 3) dimensions?
+     * \param[in]  homenr                    The number of atoms on this processor.
      * \param[in]  state            System state object.
      * \param[in]  wcycle           Wall-clock cycle counter.
      * \param[in]  haveConstraints  If the system has constraints.
      */
     void finish_update(const t_inputrec& inputRecord,
-                       const t_mdatoms*  md,
+                       bool              havePartiallyFrozenAtoms,
+                       int               homenr,
                        t_state*          state,
-                       gmx_wallcycle_t   wcycle,
+                       gmx_wallcycle   wcycle,
                        bool              haveConstraints);
 
     /*! \brief Secong part of the SD integrator.
@@ -150,7 +164,9 @@ public:
      * \param[in]  step         Current timestep.
      * \param[in]  dvdlambda    Free energy derivative. Contribution to be added to
      *                          the bonded interactions.
-     * \param[in]  md           MD atoms data.
+     * \param[in]  homenr       The number of atoms on this processor.
+     * \param[in]  ptype        The list of particle types.
+     * \param[in]  invMass      Inverse atomic mass per atom, 0 for vsites and shells.
      * \param[in]  state        System state object.
      * \param[in]  cr           Comunication record.
      * \param[in]  nrnb         Cycle counters.
@@ -160,24 +176,29 @@ public:
      * \param[in]  do_log       If this is logging step.
      * \param[in]  do_ene       If this is an energy evaluation step.
      */
-    void update_sd_second_half(const t_inputrec& inputRecord,
-                               int64_t           step,
-                               real*             dvdlambda,
-                               const t_mdatoms*  md,
-                               t_state*          state,
-                               const t_commrec*  cr,
-                               t_nrnb*           nrnb,
-                               gmx_wallcycle_t   wcycle,
-                               gmx::Constraints* constr,
-                               bool              do_log,
-                               bool              do_ene);
+    void update_sd_second_half(const t_inputrec&                 inputRecord,
+                               int64_t                           step,
+                               real*                             dvdlambda,
+                               int                               homenr,
+                               gmx::ArrayRef<const ParticleType> ptype,
+                               gmx::ArrayRef<const real>         invMass,
+                               t_state*                          state,
+                               const t_commrec*                  cr,
+                               t_nrnb*                           nrnb,
+                               gmx_wallcycle*                    wcycle,
+                               gmx::Constraints*                 constr,
+                               bool                              do_log,
+                               bool                              do_ene);
 
     /*! \brief Performs a leap-frog update without updating \p state so the constrain virial
      * can be computed.
      */
-    void update_for_constraint_virial(const t_inputrec&                                inputRecord,
-                                      const t_mdatoms&                                 md,
-                                      const t_state&                                   state,
+    void update_for_constraint_virial(const t_inputrec&         inputRecord,
+                                      int                       homenr,
+                                      bool                      havePartiallyFrozenAtoms,
+                                      gmx::ArrayRef<const real> invmass,
+                                      gmx::ArrayRef<const rvec> invMassPerDim,
+                                      const t_state&            state,
                                       const gmx::ArrayRefWithPadding<const gmx::RVec>& f,
                                       const gmx_ekindata_t&                            ekind);
 
@@ -208,7 +229,7 @@ private:
     //! Implementation type.
     class Impl;
     //! Implementation object.
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 }; // namespace gmx
index 581851f9a271cd93929b0f62ce8e145a2e92f98d..ce23e1dfa04123e2298c60c18e34dc8be8ced217 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_MDLIB_UPDATE_CONSTRAIN_GPU_H
 #define GMX_MDLIB_UPDATE_CONSTRAIN_GPU_H
 
+#include <memory>
+
 #include "gromacs/gpu_utils/devicebuffer_datatype.h"
 #include "gromacs/mdtypes/group.h"
 #include "gromacs/timing/wallcycle.h"
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/classhelpers.h"
 
 class DeviceContext;
 class DeviceStream;
@@ -75,18 +76,20 @@ public:
      * any) consumers of the updated coordinates. The \p xUpdatedOnDevice also can not be a nullptr
      * because the markEvent(...) method is called unconditionally.
      *
-     * \param[in] ir                Input record data: LINCS takes number of iterations and order of
-     *                              projection from it.
-     * \param[in] mtop              Topology of the system: SETTLE gets the masses for O and H atoms
-     *                              and target O-H and H-H distances from this object.
-     * \param[in] deviceContext     GPU device context.
-     * \param[in] deviceStream      GPU stream to use.
-     * \param[in] xUpdatedOnDevice  The event synchronizer to use to mark that update is done
-     *                              on the GPU.
-     * \param[in] wcycle            The wallclock counter
+     * \param[in] ir                  Input record data: LINCS takes number of iterations and order of
+     *                                projection from it.
+     * \param[in] mtop                Topology of the system: SETTLE gets the masses for O and H atoms
+     *                                and target O-H and H-H distances from this object.
+     * \param[in] numTempScaleValues  Number of temperature scaling groups. Zero for no temperature scaling.
+     * \param[in] deviceContext       GPU device context.
+     * \param[in] deviceStream        GPU stream to use.
+     * \param[in] xUpdatedOnDevice    The event synchronizer to use to mark that update is done
+     *                                on the GPU.
+     * \param[in] wcycle              The wallclock counter
      */
     UpdateConstrainGpu(const t_inputrec&     ir,
                        const gmx_mtop_t&     mtop,
+                       int                   numTempScaleValues,
                        const DeviceContext&  deviceContext,
                        const DeviceStream&   deviceStream,
                        GpuEventSynchronizer* xUpdatedOnDevice,
@@ -146,14 +149,12 @@ public:
      * \param[in]      d_f                 Device buffer with forces.
      * \param[in]      idef                System topology
      * \param[in]      md                  Atoms data.
-     * \param[in]      numTempScaleValues  Number of temperature scaling groups. Zero for no temperature scaling.
      */
     void set(DeviceBuffer<RVec>            d_x,
              DeviceBuffer<RVec>            d_v,
              DeviceBuffer<RVec>            d_f,
              const InteractionDefinitions& idef,
-             const t_mdatoms&              md,
-             int                           numTempScaleValues);
+             const t_mdatoms&              md);
 
     /*! \brief
      * Update PBC data.
@@ -179,7 +180,7 @@ public:
 
 private:
     class Impl;
-    gmx::PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index dc2b0421c3d8ce1ce1e1e0e959bdb6a7dc3abd67..b0f3872860900129780a8fe75ee9ec9f42e7e206 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +58,7 @@ class UpdateConstrainGpu::Impl
 
 UpdateConstrainGpu::UpdateConstrainGpu(const t_inputrec& /* ir   */,
                                        const gmx_mtop_t& /* mtop */,
+                                       const int /* numTempScaleValues */,
                                        const DeviceContext& /* deviceContext */,
                                        const DeviceStream& /* deviceStream */,
                                        GpuEventSynchronizer* /* xUpdatedOnDevice */,
@@ -101,8 +102,7 @@ void UpdateConstrainGpu::set(DeviceBuffer<RVec> /* d_x */,
                              DeviceBuffer<RVec> /* d_v */,
                              const DeviceBuffer<RVec> /* d_f */,
                              const InteractionDefinitions& /* idef */,
-                             const t_mdatoms& /* md */,
-                             const int /* numTempScaleValues */)
+                             const t_mdatoms& /* md */)
 {
     GMX_ASSERT(!impl_,
                "A CPU stub for UpdateConstrain was called instead of the correct implementation.");
index 825890ce82617273dd07e7d048fa05ee55d7b3e8..7ef37c094010d5c4d41497f5f01081b96e1b406a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gpu_utils/device_context.h"
 #include "gromacs/gpu_utils/device_stream.h"
 #include "gromacs/gpu_utils/devicebuffer.h"
+#include "gromacs/gpu_utils/gpueventsynchronizer.cuh"
 #include "gromacs/gpu_utils/gputraits.cuh"
 #include "gromacs/gpu_utils/vectype_ops.cuh"
 #include "gromacs/mdlib/leapfrog_gpu.h"
-#include "gromacs/mdlib/lincs_gpu.cuh"
-#include "gromacs/mdlib/settle_gpu.cuh"
 #include "gromacs/mdlib/update_constrain_gpu.h"
 #include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/timing/wallcycle.h"
@@ -79,15 +78,6 @@ constexpr static int c_threadsPerBlock = 256;
 //! Maximum number of threads in a block (for __launch_bounds__)
 constexpr static int c_maxThreadsPerBlock = c_threadsPerBlock;
 
-/*! \brief Scaling matrix struct.
- *
- * \todo Should be generalized.
- */
-struct ScalingMatrix
-{
-    float xx, yy, zz, yx, zx, zy;
-};
-
 __launch_bounds__(c_maxThreadsPerBlock) __global__
         static void scaleCoordinates_kernel(const int numAtoms,
                                             float3* __restrict__ gm_x,
@@ -117,8 +107,8 @@ void UpdateConstrainGpu::Impl::integrate(GpuEventSynchronizer*             fRead
                                          const float                       dtPressureCouple,
                                          const matrix                      prVelocityScalingMatrix)
 {
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_GPU_UPDATE_CONSTRAIN);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchGpuUpdateConstrain);
 
     // Clearing virial matrix
     // TODO There is no point in having separate virial matrix for constraints
@@ -129,8 +119,8 @@ void UpdateConstrainGpu::Impl::integrate(GpuEventSynchronizer*             fRead
 
     // The integrate should save a copy of the current coordinates in d_xp_ and write updated
     // once into d_x_. The d_xp_ is only needed by constraints.
-    integrator_->integrate(d_x_, d_xp_, d_v_, d_f_, dt, doTemperatureScaling, tcstat,
-                           doParrinelloRahman, dtPressureCouple, prVelocityScalingMatrix);
+    integrator_->integrate(
+            d_x_, d_xp_, d_v_, d_f_, dt, doTemperatureScaling, tcstat, doParrinelloRahman, dtPressureCouple, prVelocityScalingMatrix);
     // Constraints need both coordinates before (d_x_) and after (d_xp_) update. However, after constraints
     // are applied, the d_x_ can be discarded. So we intentionally swap the d_x_ and d_xp_ here to avoid the
     // d_xp_ -> d_x_ copy after constraints. Note that the integrate saves them in the wrong order as well.
@@ -149,64 +139,61 @@ void UpdateConstrainGpu::Impl::integrate(GpuEventSynchronizer*             fRead
 
     coordinatesReady_->markEvent(deviceStream_);
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_GPU_UPDATE_CONSTRAIN);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchGpuUpdateConstrain);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 
     return;
 }
 
 void UpdateConstrainGpu::Impl::scaleCoordinates(const matrix scalingMatrix)
 {
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_GPU_UPDATE_CONSTRAIN);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchGpuUpdateConstrain);
 
-    ScalingMatrix mu;
-    mu.xx = scalingMatrix[XX][XX];
-    mu.yy = scalingMatrix[YY][YY];
-    mu.zz = scalingMatrix[ZZ][ZZ];
-    mu.yx = scalingMatrix[YY][XX];
-    mu.zx = scalingMatrix[ZZ][XX];
-    mu.zy = scalingMatrix[ZZ][YY];
+    ScalingMatrix mu(scalingMatrix);
 
     const auto kernelArgs = prepareGpuKernelArguments(
             scaleCoordinates_kernel, coordinateScalingKernelLaunchConfig_, &numAtoms_, &d_x_, &mu);
-    launchGpuKernel(scaleCoordinates_kernel, coordinateScalingKernelLaunchConfig_, deviceStream_,
-                    nullptr, "scaleCoordinates_kernel", kernelArgs);
+    launchGpuKernel(scaleCoordinates_kernel,
+                    coordinateScalingKernelLaunchConfig_,
+                    deviceStream_,
+                    nullptr,
+                    "scaleCoordinates_kernel",
+                    kernelArgs);
     // TODO: Although this only happens on the pressure coupling steps, this synchronization
     //       can affect the performance if nstpcouple is small.
     deviceStream_.synchronize();
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_GPU_UPDATE_CONSTRAIN);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchGpuUpdateConstrain);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
 void UpdateConstrainGpu::Impl::scaleVelocities(const matrix scalingMatrix)
 {
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_GPU_UPDATE_CONSTRAIN);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchGpuUpdateConstrain);
 
-    ScalingMatrix mu;
-    mu.xx = scalingMatrix[XX][XX];
-    mu.yy = scalingMatrix[YY][YY];
-    mu.zz = scalingMatrix[ZZ][ZZ];
-    mu.yx = scalingMatrix[YY][XX];
-    mu.zx = scalingMatrix[ZZ][XX];
-    mu.zy = scalingMatrix[ZZ][YY];
+    ScalingMatrix mu(scalingMatrix);
 
     const auto kernelArgs = prepareGpuKernelArguments(
             scaleCoordinates_kernel, coordinateScalingKernelLaunchConfig_, &numAtoms_, &d_v_, &mu);
-    launchGpuKernel(scaleCoordinates_kernel, coordinateScalingKernelLaunchConfig_, deviceStream_,
-                    nullptr, "scaleCoordinates_kernel", kernelArgs);
+    launchGpuKernel(scaleCoordinates_kernel,
+                    coordinateScalingKernelLaunchConfig_,
+                    deviceStream_,
+                    nullptr,
+                    "scaleCoordinates_kernel",
+                    kernelArgs);
     // TODO: Although this only happens on the pressure coupling steps, this synchronization
     //       can affect the performance if nstpcouple is small.
     deviceStream_.synchronize();
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_GPU_UPDATE_CONSTRAIN);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchGpuUpdateConstrain);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
 UpdateConstrainGpu::Impl::Impl(const t_inputrec&     ir,
                                const gmx_mtop_t&     mtop,
+                               const int             numTempScaleValues,
                                const DeviceContext&  deviceContext,
                                const DeviceStream&   deviceStream,
                                GpuEventSynchronizer* xUpdatedOnDevice,
@@ -219,7 +206,7 @@ UpdateConstrainGpu::Impl::Impl(const t_inputrec&     ir,
     GMX_ASSERT(xUpdatedOnDevice != nullptr, "The event synchronizer can not be nullptr.");
 
 
-    integrator_ = std::make_unique<LeapFrogGpu>(deviceContext_, deviceStream_);
+    integrator_ = std::make_unique<LeapFrogGpu>(deviceContext_, deviceStream_, numTempScaleValues);
     lincsGpu_ = std::make_unique<LincsGpu>(ir.nLincsIter, ir.nProjOrder, deviceContext_, deviceStream_);
     settleGpu_ = std::make_unique<SettleGpu>(mtop, deviceContext_, deviceStream_);
 
@@ -231,42 +218,41 @@ UpdateConstrainGpu::Impl::Impl(const t_inputrec&     ir,
 
 UpdateConstrainGpu::Impl::~Impl() {}
 
-void UpdateConstrainGpu::Impl::set(DeviceBuffer<RVec>            d_x,
-                                   DeviceBuffer<RVec>            d_v,
-                                   const DeviceBuffer<RVec>      d_f,
+void UpdateConstrainGpu::Impl::set(DeviceBuffer<Float3>          d_x,
+                                   DeviceBuffer<Float3>          d_v,
+                                   const DeviceBuffer<Float3>    d_f,
                                    const InteractionDefinitions& idef,
-                                   const t_mdatoms&              md,
-                                   const int                     numTempScaleValues)
+                                   const t_mdatoms&              md)
 {
     // TODO wallcycle
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_GPU_UPDATE_CONSTRAIN);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchGpuUpdateConstrain);
 
     GMX_ASSERT(d_x != nullptr, "Coordinates device buffer should not be null.");
     GMX_ASSERT(d_v != nullptr, "Velocities device buffer should not be null.");
     GMX_ASSERT(d_f != nullptr, "Forces device buffer should not be null.");
 
-    d_x_ = reinterpret_cast<float3*>(d_x);
-    d_v_ = reinterpret_cast<float3*>(d_v);
-    d_f_ = reinterpret_cast<float3*>(d_f);
+    d_x_ = d_x;
+    d_v_ = d_v;
+    d_f_ = d_f;
 
     numAtoms_ = md.nr;
 
     reallocateDeviceBuffer(&d_xp_, numAtoms_, &numXp_, &numXpAlloc_, deviceContext_);
 
-    reallocateDeviceBuffer(&d_inverseMasses_, numAtoms_, &numInverseMasses_,
-                           &numInverseMassesAlloc_, deviceContext_);
+    reallocateDeviceBuffer(
+            &d_inverseMasses_, numAtoms_, &numInverseMasses_, &numInverseMassesAlloc_, deviceContext_);
 
     // Integrator should also update something, but it does not even have a method yet
-    integrator_->set(numAtoms_, md.invmass, numTempScaleValues, md.cTC);
+    integrator_->set(numAtoms_, md.invmass, md.cTC);
     lincsGpu_->set(idef, numAtoms_, md.invmass);
     settleGpu_->set(idef);
 
     coordinateScalingKernelLaunchConfig_.gridSize[0] =
             (numAtoms_ + c_threadsPerBlock - 1) / c_threadsPerBlock;
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_GPU_UPDATE_CONSTRAIN);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchGpuUpdateConstrain);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
 void UpdateConstrainGpu::Impl::setPbc(const PbcType pbcType, const matrix box)
@@ -282,11 +268,12 @@ GpuEventSynchronizer* UpdateConstrainGpu::Impl::getCoordinatesReadySync()
 
 UpdateConstrainGpu::UpdateConstrainGpu(const t_inputrec&     ir,
                                        const gmx_mtop_t&     mtop,
+                                       const int             numTempScaleValues,
                                        const DeviceContext&  deviceContext,
                                        const DeviceStream&   deviceStream,
                                        GpuEventSynchronizer* xUpdatedOnDevice,
                                        gmx_wallcycle*        wcycle) :
-    impl_(new Impl(ir, mtop, deviceContext, deviceStream, xUpdatedOnDevice, wcycle))
+    impl_(new Impl(ir, mtop, numTempScaleValues, deviceContext, deviceStream, xUpdatedOnDevice, wcycle))
 {
 }
 
@@ -303,8 +290,16 @@ void UpdateConstrainGpu::integrate(GpuEventSynchronizer*             fReadyOnDev
                                    const float                       dtPressureCouple,
                                    const matrix                      prVelocityScalingMatrix)
 {
-    impl_->integrate(fReadyOnDevice, dt, updateVelocities, computeVirial, virialScaled, doTemperatureScaling,
-                     tcstat, doParrinelloRahman, dtPressureCouple, prVelocityScalingMatrix);
+    impl_->integrate(fReadyOnDevice,
+                     dt,
+                     updateVelocities,
+                     computeVirial,
+                     virialScaled,
+                     doTemperatureScaling,
+                     tcstat,
+                     doParrinelloRahman,
+                     dtPressureCouple,
+                     prVelocityScalingMatrix);
 }
 
 void UpdateConstrainGpu::scaleCoordinates(const matrix scalingMatrix)
@@ -317,14 +312,13 @@ void UpdateConstrainGpu::scaleVelocities(const matrix scalingMatrix)
     impl_->scaleVelocities(scalingMatrix);
 }
 
-void UpdateConstrainGpu::set(DeviceBuffer<RVec>            d_x,
-                             DeviceBuffer<RVec>            d_v,
-                             const DeviceBuffer<RVec>      d_f,
+void UpdateConstrainGpu::set(DeviceBuffer<Float3>          d_x,
+                             DeviceBuffer<Float3>          d_v,
+                             const DeviceBuffer<Float3>    d_f,
                              const InteractionDefinitions& idef,
-                             const t_mdatoms&              md,
-                             const int                     numTempScaleValues)
+                             const t_mdatoms&              md)
 {
-    impl_->set(d_x, d_v, d_f, idef, md, numTempScaleValues);
+    impl_->set(d_x, d_v, d_f, idef, md);
 }
 
 void UpdateConstrainGpu::setPbc(const PbcType pbcType, const matrix box)
index 7453a98105712aca5264b16aa737789d8f53e213..bad3898602e0d934482e243a28fab68fd1df7f56 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "gromacs/gpu_utils/gpueventsynchronizer.cuh"
 #include "gromacs/mdlib/leapfrog_gpu.h"
-#include "gromacs/mdlib/lincs_gpu.cuh"
-#include "gromacs/mdlib/settle_gpu.cuh"
+#include "gromacs/mdlib/lincs_gpu.h"
+#include "gromacs/mdlib/settle_gpu.h"
 #include "gromacs/mdlib/update_constrain_gpu.h"
 #include "gromacs/mdtypes/inputrec.h"
 
+class GpuEventSynchronizer;
+
 namespace gmx
 {
 
@@ -71,18 +72,20 @@ public:
      * any) consumers of the updated coordinates. The \p xUpdatedOnDevice also can not be a nullptr
      * because the markEvent(...) method is called unconditionally.
      *
-     * \param[in] ir                Input record data: LINCS takes number of iterations and order of
-     *                              projection from it.
-     * \param[in] mtop              Topology of the system: SETTLE gets the masses for O and H atoms
-     *                              and target O-H and H-H distances from this object.
-     * \param[in] deviceContext     GPU device context.
-     * \param[in] deviceStream      GPU stream to use.
-     * \param[in] xUpdatedOnDevice  The event synchronizer to use to mark that
-     *                              update is done on the GPU.
-     * \param[in] wcycle            The wallclock counter
+     * \param[in] ir                  Input record data: LINCS takes number of iterations and order of
+     *                                projection from it.
+     * \param[in] mtop                Topology of the system: SETTLE gets the masses for O and H atoms
+     *                                and target O-H and H-H distances from this object.
+     * \param[in] numTempScaleValues  Number of temperature scaling groups. Set zero for no temperature coupling.
+     * \param[in] deviceContext       GPU device context.
+     * \param[in] deviceStream        GPU stream to use.
+     * \param[in] xUpdatedOnDevice    The event synchronizer to use to mark that
+     *                                update is done on the GPU.
+     * \param[in] wcycle              The wallclock counter
      */
     Impl(const t_inputrec&     ir,
          const gmx_mtop_t&     mtop,
+         int                   numTempScaleValues,
          const DeviceContext&  deviceContext,
          const DeviceStream&   deviceStream,
          GpuEventSynchronizer* xUpdatedOnDevice,
@@ -147,14 +150,12 @@ public:
      * \param[in]      d_f            Device buffer with forces.
      * \param[in] idef                System topology
      * \param[in] md                  Atoms data.
-     * \param[in] numTempScaleValues  Number of temperature scaling groups. Set zero for no temperature coupling.
      */
-    void set(DeviceBuffer<RVec>            d_x,
-             DeviceBuffer<RVec>            d_v,
-             const DeviceBuffer<RVec>      d_f,
+    void set(DeviceBuffer<Float3>          d_x,
+             DeviceBuffer<Float3>          d_v,
+             const DeviceBuffer<Float3>    d_f,
              const InteractionDefinitions& idef,
-             const t_mdatoms&              md,
-             const int                     numTempScaleValues);
+             const t_mdatoms&              md);
 
     /*! \brief
      * Update PBC data.
@@ -193,14 +194,14 @@ private:
     int numAtoms_;
 
     //! Local copy of the pointer to the device positions buffer
-    float3* d_x_;
+    DeviceBuffer<Float3> d_x_;
     //! Local copy of the pointer to the device velocities buffer
-    float3* d_v_;
+    DeviceBuffer<Float3> d_v_;
     //! Local copy of the pointer to the device forces buffer
-    float3* d_f_;
+    DeviceBuffer<Float3> d_f_;
 
     //! Device buffer for intermediate positions (maintained internally)
-    float3* d_xp_;
+    DeviceBuffer<Float3> d_xp_;
     //! Number of elements in shifted coordinates buffer
     int numXp_ = -1;
     //! Allocation size for the shifted coordinates buffer
@@ -208,7 +209,7 @@ private:
 
 
     //! 1/mass for all atoms (GPU)
-    real* d_inverseMasses_;
+    DeviceBuffer<real> d_inverseMasses_;
     //! Number of elements in reciprocal masses buffer
     int numInverseMasses_ = -1;
     //! Allocation size for the reciprocal masses buffer
@@ -227,6 +228,24 @@ private:
     gmx_wallcycle* wcycle_ = nullptr;
 };
 
+/*! \brief Scaling matrix struct.
+ *
+ * \todo Should be generalized.
+ */
+struct ScalingMatrix
+{
+    ScalingMatrix(const matrix m) :
+        xx(m[XX][XX]),
+        yy(m[YY][YY]),
+        zz(m[ZZ][ZZ]),
+        yx(m[YY][XX]),
+        zx(m[ZZ][XX]),
+        zy(m[ZZ][YY])
+    {
+    }
+    float xx, yy, zz, yx, zx, zy;
+};
+
 } // namespace gmx
 
 #endif // GMX_MDLIB_UPDATE_CONSTRAIN_GPU_IMPL_H
diff --git a/src/gromacs/mdlib/update_vv.cpp b/src/gromacs/mdlib/update_vv.cpp
new file mode 100644 (file)
index 0000000..57d1a14
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ * 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,2017 by the GROMACS development team.
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 "update_vv.h"
+
+#include <cmath>
+#include <cstdio>
+
+#include <algorithm>
+#include <memory>
+
+#include "gromacs/domdec/domdec.h"
+#include "gromacs/gmxlib/nrnb.h"
+#include "gromacs/math/units.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/mdlib/constr.h"
+#include "gromacs/mdlib/coupling.h"
+#include "gromacs/mdlib/enerdata_utils.h"
+#include "gromacs/mdlib/mdatoms.h"
+#include "gromacs/mdlib/md_support.h"
+#include "gromacs/mdlib/stat.h"
+#include "gromacs/mdlib/tgroup.h"
+#include "gromacs/mdlib/update.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/mdtypes/enerdata.h"
+#include "gromacs/mdtypes/fcdata.h"
+#include "gromacs/mdtypes/forcebuffers.h"
+#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/group.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/mdtypes/state.h"
+#include "gromacs/pulling/pull.h"
+#include "gromacs/timing/wallcycle.h"
+#include "gromacs/topology/topology.h"
+
+void integrateVVFirstStep(int64_t                                  step,
+                          bool                                     bFirstStep,
+                          bool                                     bInitStep,
+                          gmx::StartingBehavior                    startingBehavior,
+                          int                                      nstglobalcomm,
+                          const t_inputrec*                        ir,
+                          t_forcerec*                              fr,
+                          t_commrec*                               cr,
+                          t_state*                                 state,
+                          t_mdatoms*                               mdatoms,
+                          const t_fcdata&                          fcdata,
+                          t_extmass*                               MassQ,
+                          t_vcm*                                   vcm,
+                          const gmx_mtop_t&                        top_global,
+                          const gmx_localtop_t&                    top,
+                          gmx_enerdata_t*                          enerd,
+                          gmx_ekindata_t*                          ekind,
+                          gmx_global_stat*                         gstat,
+                          real*                                    last_ekin,
+                          bool                                     bCalcVir,
+                          tensor                                   total_vir,
+                          tensor                                   shake_vir,
+                          tensor                                   force_vir,
+                          tensor                                   pres,
+                          matrix                                   M,
+                          bool                                     do_log,
+                          bool                                     do_ene,
+                          bool                                     bCalcEner,
+                          bool                                     bGStat,
+                          bool                                     bStopCM,
+                          bool                                     bTrotter,
+                          bool                                     bExchanged,
+                          bool*                                    bSumEkinhOld,
+                          real*                                    saved_conserved_quantity,
+                          gmx::ForceBuffers*                       f,
+                          gmx::Update*                             upd,
+                          gmx::Constraints*                        constr,
+                          gmx::SimulationSignaller*                nullSignaller,
+                          std::array<std::vector<int>, ettTSEQMAX> trotter_seq,
+                          t_nrnb*                                  nrnb,
+                          const gmx::MDLogger&                     mdlog,
+                          FILE*                                    fplog,
+                          gmx_wallcycle*                           wcycle)
+{
+    if (!bFirstStep || startingBehavior == gmx::StartingBehavior::NewSimulation)
+    {
+        /*  ############### START FIRST UPDATE HALF-STEP FOR VV METHODS############### */
+        rvec* vbuf = nullptr;
+
+        wallcycle_start(wcycle, WallCycleCounter::Update);
+        if (ir->eI == IntegrationAlgorithm::VV && bInitStep)
+        {
+            /* if using velocity verlet with full time step Ekin,
+             * take the first half step only to compute the
+             * virial for the first step. From there,
+             * revert back to the initial coordinates
+             * so that the input is actually the initial step.
+             */
+            snew(vbuf, state->natoms);
+            copy_rvecn(state->v.rvec_array(), vbuf, 0, state->natoms); /* should make this better for parallelizing? */
+        }
+        else
+        {
+            /* this is for NHC in the Ekin(t+dt/2) version of vv */
+            trotter_update(ir,
+                           step,
+                           ekind,
+                           enerd,
+                           state,
+                           total_vir,
+                           mdatoms->homenr,
+                           mdatoms->cTC ? gmx::arrayRefFromArray(mdatoms->cTC, mdatoms->nr)
+                                        : gmx::ArrayRef<const unsigned short>(),
+                           gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
+                           MassQ,
+                           trotter_seq,
+                           ettTSEQ1);
+        }
+
+        upd->update_coords(*ir,
+                           step,
+                           mdatoms->homenr,
+                           mdatoms->havePartiallyFrozenAtoms,
+                           gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
+                           gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
+                           gmx::arrayRefFromArray(mdatoms->invMassPerDim, mdatoms->nr),
+                           state,
+                           f->view().forceWithPadding(),
+                           fcdata,
+                           ekind,
+                           M,
+                           etrtVELOCITY1,
+                           cr,
+                           constr != nullptr);
+
+        wallcycle_stop(wcycle, WallCycleCounter::Update);
+        constrain_velocities(constr, do_log, do_ene, step, state, nullptr, bCalcVir, shake_vir);
+        wallcycle_start(wcycle, WallCycleCounter::Update);
+        /* if VV, compute the pressure and constraints */
+        /* For VV2, we strictly only need this if using pressure
+         * control, but we really would like to have accurate pressures
+         * printed out.
+         * Think about ways around this in the future?
+         * For now, keep this choice in comments.
+         */
+        /*bPres = (ir->eI==IntegrationAlgorithm::VV || inputrecNptTrotter(ir)); */
+        /*bTemp = ((ir->eI==IntegrationAlgorithm::VV &&(!bInitStep)) || (ir->eI==IntegrationAlgorithm::VVAK && inputrecNptTrotter(ir)));*/
+        bool bPres = TRUE;
+        bool bTemp = ((ir->eI == IntegrationAlgorithm::VV && (!bInitStep))
+                      || (ir->eI == IntegrationAlgorithm::VVAK));
+        if (bCalcEner && ir->eI == IntegrationAlgorithm::VVAK)
+        {
+            *bSumEkinhOld = TRUE;
+        }
+        /* for vv, the first half of the integration actually corresponds to the previous step.
+            So we need information from the last step in the first half of the integration */
+        if (bGStat || do_per_step(step - 1, nstglobalcomm))
+        {
+            wallcycle_stop(wcycle, WallCycleCounter::Update);
+            int cglo_flags =
+                    ((bGStat ? CGLO_GSTAT : 0) | (bCalcEner ? CGLO_ENERGY : 0)
+                     | (bTemp ? CGLO_TEMPERATURE : 0) | (bPres ? CGLO_PRESSURE : 0)
+                     | (bPres ? CGLO_CONSTRAINT : 0) | (bStopCM ? CGLO_STOPCM : 0) | CGLO_SCALEEKIN);
+            if (DOMAINDECOMP(cr) && shouldCheckNumberOfBondedInteractions(*cr->dd))
+            {
+                cglo_flags |= CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS;
+            }
+            compute_globals(gstat,
+                            cr,
+                            ir,
+                            fr,
+                            ekind,
+                            makeConstArrayRef(state->x),
+                            makeConstArrayRef(state->v),
+                            state->box,
+                            mdatoms,
+                            nrnb,
+                            vcm,
+                            wcycle,
+                            enerd,
+                            force_vir,
+                            shake_vir,
+                            total_vir,
+                            pres,
+                            (bCalcEner && constr != nullptr) ? constr->rmsdData() : gmx::ArrayRef<real>{},
+                            nullSignaller,
+                            state->box,
+                            bSumEkinhOld,
+                            cglo_flags);
+            /* explanation of above:
+                a) We compute Ekin at the full time step
+                if 1) we are using the AveVel Ekin, and it's not the
+                initial step, or 2) if we are using AveEkin, but need the full
+                time step kinetic energy for the pressure (always true now, since we want accurate statistics).
+                b) If we are using EkinAveEkin for the kinetic energy for the temperature control, we still feed in
+                EkinAveVel because it's needed for the pressure */
+            if (DOMAINDECOMP(cr))
+            {
+                checkNumberOfBondedInteractions(
+                        mdlog, cr, top_global, &top, makeConstArrayRef(state->x), state->box);
+            }
+            if (bStopCM)
+            {
+                process_and_stopcm_grp(
+                        fplog, vcm, *mdatoms, makeArrayRef(state->x), makeArrayRef(state->v));
+                inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr);
+            }
+            wallcycle_start(wcycle, WallCycleCounter::Update);
+        }
+        /* temperature scaling and pressure scaling to produce the extended variables at t+dt */
+        if (!bInitStep)
+        {
+            if (bTrotter)
+            {
+                m_add(force_vir, shake_vir, total_vir); /* we need the un-dispersion corrected total vir here */
+                trotter_update(ir,
+                               step,
+                               ekind,
+                               enerd,
+                               state,
+                               total_vir,
+                               mdatoms->homenr,
+                               mdatoms->cTC ? gmx::arrayRefFromArray(mdatoms->cTC, mdatoms->nr)
+                                            : gmx::ArrayRef<const unsigned short>(),
+                               gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
+                               MassQ,
+                               trotter_seq,
+                               ettTSEQ2);
+
+                /* TODO This is only needed when we're about to write
+                 * a checkpoint, because we use it after the restart
+                 * (in a kludge?). But what should we be doing if
+                 * the startingBehavior is NewSimulation or bInitStep are true? */
+                if (inputrecNptTrotter(ir) || inputrecNphTrotter(ir))
+                {
+                    copy_mat(shake_vir, state->svir_prev);
+                    copy_mat(force_vir, state->fvir_prev);
+                }
+                if ((inputrecNptTrotter(ir) || inputrecNvtTrotter(ir)) && ir->eI == IntegrationAlgorithm::VV)
+                {
+                    /* update temperature and kinetic energy now that step is over - this is the v(t+dt) point */
+                    enerd->term[F_TEMP] = sum_ekin(
+                            &(ir->opts), ekind, nullptr, (ir->eI == IntegrationAlgorithm::VV), FALSE);
+                    enerd->term[F_EKIN] = trace(ekind->ekin);
+                }
+            }
+            else if (bExchanged)
+            {
+                wallcycle_stop(wcycle, WallCycleCounter::Update);
+                /* We need the kinetic energy at minus the half step for determining
+                 * the full step kinetic energy and possibly for T-coupling.*/
+                /* This may not be quite working correctly yet . . . . */
+                compute_globals(gstat,
+                                cr,
+                                ir,
+                                fr,
+                                ekind,
+                                makeConstArrayRef(state->x),
+                                makeConstArrayRef(state->v),
+                                state->box,
+                                mdatoms,
+                                nrnb,
+                                vcm,
+                                wcycle,
+                                enerd,
+                                nullptr,
+                                nullptr,
+                                nullptr,
+                                nullptr,
+                                gmx::ArrayRef<real>{},
+                                nullSignaller,
+                                state->box,
+                                bSumEkinhOld,
+                                CGLO_GSTAT | CGLO_TEMPERATURE);
+                wallcycle_start(wcycle, WallCycleCounter::Update);
+            }
+        }
+        /* if it's the initial step, we performed this first step just to get the constraint virial */
+        if (ir->eI == IntegrationAlgorithm::VV && bInitStep)
+        {
+            copy_rvecn(vbuf, state->v.rvec_array(), 0, state->natoms);
+            sfree(vbuf);
+        }
+        wallcycle_stop(wcycle, WallCycleCounter::Update);
+    }
+
+    /* compute the conserved quantity */
+    *saved_conserved_quantity = NPT_energy(ir, state, MassQ);
+    if (ir->eI == IntegrationAlgorithm::VV)
+    {
+        *last_ekin = enerd->term[F_EKIN];
+    }
+    if ((ir->eDispCorr != DispersionCorrectionType::EnerPres)
+        && (ir->eDispCorr != DispersionCorrectionType::AllEnerPres))
+    {
+        *saved_conserved_quantity -= enerd->term[F_DISPCORR];
+    }
+    /* sum up the foreign kinetic energy and dK/dl terms for vv.  currently done every step so that dhdl is correct in the .edr */
+    if (ir->efep != FreeEnergyPerturbationType::No)
+    {
+        accumulateKineticLambdaComponents(enerd, state->lambda, *ir->fepvals);
+    }
+}
+
+void integrateVVSecondStep(int64_t                                  step,
+                           const t_inputrec*                        ir,
+                           t_forcerec*                              fr,
+                           t_commrec*                               cr,
+                           t_state*                                 state,
+                           t_mdatoms*                               mdatoms,
+                           const t_fcdata&                          fcdata,
+                           t_extmass*                               MassQ,
+                           t_vcm*                                   vcm,
+                           pull_t*                                  pull_work,
+                           gmx_enerdata_t*                          enerd,
+                           gmx_ekindata_t*                          ekind,
+                           gmx_global_stat*                         gstat,
+                           real*                                    dvdl_constr,
+                           bool                                     bCalcVir,
+                           tensor                                   total_vir,
+                           tensor                                   shake_vir,
+                           tensor                                   force_vir,
+                           tensor                                   pres,
+                           matrix                                   M,
+                           matrix                                   lastbox,
+                           bool                                     do_log,
+                           bool                                     do_ene,
+                           bool                                     bGStat,
+                           bool*                                    bSumEkinhOld,
+                           gmx::ForceBuffers*                       f,
+                           std::vector<gmx::RVec>*                  cbuf,
+                           gmx::Update*                             upd,
+                           gmx::Constraints*                        constr,
+                           gmx::SimulationSignaller*                nullSignaller,
+                           std::array<std::vector<int>, ettTSEQMAX> trotter_seq,
+                           t_nrnb*                                  nrnb,
+                           gmx_wallcycle*                           wcycle)
+{
+    /* velocity half-step update */
+    upd->update_coords(*ir,
+                       step,
+                       mdatoms->homenr,
+                       mdatoms->havePartiallyFrozenAtoms,
+                       gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
+                       gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
+                       gmx::arrayRefFromArray(mdatoms->invMassPerDim, mdatoms->nr),
+                       state,
+                       f->view().forceWithPadding(),
+                       fcdata,
+                       ekind,
+                       M,
+                       etrtVELOCITY2,
+                       cr,
+                       constr != nullptr);
+
+
+    /* Above, initialize just copies ekinh into ekin,
+     * it doesn't copy position (for VV),
+     * and entire integrator for MD.
+     */
+
+    if (ir->eI == IntegrationAlgorithm::VVAK)
+    {
+        cbuf->resize(state->x.size());
+        std::copy(state->x.begin(), state->x.end(), cbuf->begin());
+    }
+
+    if (ir->bPull && ir->pull->bSetPbcRefToPrevStepCOM)
+    {
+        updatePrevStepPullCom(pull_work, state);
+    }
+
+    upd->update_coords(*ir,
+                       step,
+                       mdatoms->homenr,
+                       mdatoms->havePartiallyFrozenAtoms,
+                       gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
+                       gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
+                       gmx::arrayRefFromArray(mdatoms->invMassPerDim, mdatoms->nr),
+                       state,
+                       f->view().forceWithPadding(),
+                       fcdata,
+                       ekind,
+                       M,
+                       etrtPOSITION,
+                       cr,
+                       constr != nullptr);
+
+    wallcycle_stop(wcycle, WallCycleCounter::Update);
+
+    constrain_coordinates(
+            constr, do_log, do_ene, step, state, upd->xp()->arrayRefWithPadding(), dvdl_constr, bCalcVir, shake_vir);
+
+    upd->update_sd_second_half(*ir,
+                               step,
+                               dvdl_constr,
+                               mdatoms->homenr,
+                               gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
+                               gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
+                               state,
+                               cr,
+                               nrnb,
+                               wcycle,
+                               constr,
+                               do_log,
+                               do_ene);
+    upd->finish_update(
+            *ir, mdatoms->havePartiallyFrozenAtoms, mdatoms->homenr, state, wcycle, constr != nullptr);
+
+    if (ir->eI == IntegrationAlgorithm::VVAK)
+    {
+        /* erase F_EKIN and F_TEMP here? */
+        /* just compute the kinetic energy at the half step to perform a trotter step */
+        compute_globals(gstat,
+                        cr,
+                        ir,
+                        fr,
+                        ekind,
+                        makeConstArrayRef(state->x),
+                        makeConstArrayRef(state->v),
+                        state->box,
+                        mdatoms,
+                        nrnb,
+                        vcm,
+                        wcycle,
+                        enerd,
+                        force_vir,
+                        shake_vir,
+                        total_vir,
+                        pres,
+                        gmx::ArrayRef<real>{},
+                        nullSignaller,
+                        lastbox,
+                        bSumEkinhOld,
+                        (bGStat ? CGLO_GSTAT : 0) | CGLO_TEMPERATURE);
+        wallcycle_start(wcycle, WallCycleCounter::Update);
+        trotter_update(ir,
+                       step,
+                       ekind,
+                       enerd,
+                       state,
+                       total_vir,
+                       mdatoms->homenr,
+                       mdatoms->cTC ? gmx::arrayRefFromArray(mdatoms->cTC, mdatoms->nr)
+                                    : gmx::ArrayRef<const unsigned short>(),
+                       gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
+                       MassQ,
+                       trotter_seq,
+                       ettTSEQ4);
+        /* now we know the scaling, we can compute the positions again */
+        std::copy(cbuf->begin(), cbuf->end(), state->x.begin());
+
+        upd->update_coords(*ir,
+                           step,
+                           mdatoms->homenr,
+                           mdatoms->havePartiallyFrozenAtoms,
+                           gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
+                           gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
+                           gmx::arrayRefFromArray(mdatoms->invMassPerDim, mdatoms->nr),
+                           state,
+                           f->view().forceWithPadding(),
+                           fcdata,
+                           ekind,
+                           M,
+                           etrtPOSITION,
+                           cr,
+                           constr != nullptr);
+        wallcycle_stop(wcycle, WallCycleCounter::Update);
+
+        /* 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*/
+        upd->finish_update(*ir, mdatoms->havePartiallyFrozenAtoms, mdatoms->homenr, state, wcycle, false);
+    }
+    /* this factor or 2 correction is necessary
+        because half of the constraint force is removed
+        in the vv step, so we have to double it.  See
+        the Issue #1255.  It is not yet clear
+        if the factor of 2 is exact, or just a very
+        good approximation, and this will be
+        investigated.  The next step is to see if this
+        can be done adding a dhdl contribution from the
+        rattle step, but this is somewhat more
+        complicated with the current code. Will be
+        investigated, hopefully for 4.6.3. However,
+        this current solution is much better than
+        having it completely wrong.
+        */
+    enerd->term[F_DVDL_CONSTR] += 2 * *dvdl_constr;
+}
diff --git a/src/gromacs/mdlib/update_vv.h b/src/gromacs/mdlib/update_vv.h
new file mode 100644 (file)
index 0000000..ddc4f8b
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * 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,2017 by the GROMACS development team.
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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_UPDATE_VV_H
+#define GMX_MDLIB_UPDATE_VV_H
+
+#include <vector>
+
+#include "gromacs/math/vectypes.h"
+#include "gromacs/mdrunutility/handlerestart.h"
+#include "gromacs/mdtypes/md_enums.h"
+
+class gmx_ekindata_t;
+struct gmx_enerdata_t;
+struct gmx_global_stat;
+struct gmx_localtop_t;
+struct gmx_mtop_t;
+struct gmx_wallcycle;
+struct pull_t;
+struct t_commrec;
+struct t_extmass;
+struct t_fcdata;
+struct t_forcerec;
+struct t_inputrec;
+struct t_mdatoms;
+struct t_nrnb;
+class t_state;
+struct t_vcm;
+
+namespace gmx
+{
+class Constraints;
+class ForceBuffers;
+class MDLogger;
+class SimulationSignaller;
+class Update;
+} // namespace gmx
+
+/*! \brief Make the first step of Velocity Verlet integration
+ *
+ * \param[in]  step              Current timestep.
+ * \param[in]  bFirstStep        Is it a first step.
+ * \param[in]  bInitStep         Is it an initialization step.
+ * \param[in]  startingBehavior  Describes whether this is a restart appending to output files.
+ * \param[in]  nstglobalcomm     Will globals be computed on this step.
+ * \param[in]  ir                Input record.
+ * \param[in]  fr                Force record.
+ * \param[in]  cr                Comunication record.
+ * \param[in]  state             Simulation state.
+ * \param[in]  mdatoms           MD atoms data.
+ * \param[in]  fcdata            Force calculation data.
+ * \param[in]  MassQ             Mass/pressure data.
+ * \param[in]  vcm               Center of mass motion removal.
+ * \param[in]  top_global        Global topology.
+ * \param[in]  top               Local topology.
+ * \param[in]  enerd             Energy data.
+ * \param[in]  ekind             Kinetic energy data.
+ * \param[in]  gstat             Storage of thermodynamic parameters data.
+ * \param[out] last_ekin         Kinetic energies of the last step.
+ * \param[in]  bCalcVir          If the virial is computed on this step.
+ * \param[in]  total_vir         Total virial tensor.
+ * \param[in]  shake_vir         Constraints virial.
+ * \param[in]  force_vir         Force virial.
+ * \param[in]  pres              Pressure tensor.
+ * \param[in]  M                 Parrinello-Rahman velocity scaling matrix.
+ * \param[in]  do_log            Do logging on this step.
+ * \param[in]  do_ene            Print energies on this step.
+ * \param[in]  bCalcEner         Compute energies on this step.
+ * \param[in]  bGStat            Collect globals this step.
+ * \param[in]  bStopCM           Stop the center of mass motion on this step.
+ * \param[in]  bTrotter          Do trotter routines this step.
+ * \param[in]  bExchanged        If this is a replica exchange step.
+ * \param[out] bSumEkinhOld      Old kinetic energies will need to be summed up.
+ * \param[out] saved_conserved_quantity  Place to store the conserved energy.
+ * \param[in]  f                 Force buffers.
+ * \param[in]  upd               Update object.
+ * \param[in]  constr            Constraints object.
+ * \param[in]  nullSignaller     Simulation signaller.
+ * \param[in]  trotter_seq       NPT variables.
+ * \param[in]  nrnb              Cycle counters.
+ * \param[in]  mdlog             Logger.
+ * \param[in]  fplog             Another logger.
+ * \param[in]  wcycle            Wall-clock cycle counter.
+ */
+void integrateVVFirstStep(int64_t                                  step,
+                          bool                                     bFirstStep,
+                          bool                                     bInitStep,
+                          gmx::StartingBehavior                    startingBehavior,
+                          int                                      nstglobalcomm,
+                          const t_inputrec*                        ir,
+                          t_forcerec*                              fr,
+                          t_commrec*                               cr,
+                          t_state*                                 state,
+                          t_mdatoms*                               mdatoms,
+                          const t_fcdata&                          fcdata,
+                          t_extmass*                               MassQ,
+                          t_vcm*                                   vcm,
+                          const gmx_mtop_t&                        top_global,
+                          const gmx_localtop_t&                    top,
+                          gmx_enerdata_t*                          enerd,
+                          gmx_ekindata_t*                          ekind,
+                          gmx_global_stat*                         gstat,
+                          real*                                    last_ekin,
+                          bool                                     bCalcVir,
+                          tensor                                   total_vir,
+                          tensor                                   shake_vir,
+                          tensor                                   force_vir,
+                          tensor                                   pres,
+                          matrix                                   M,
+                          bool                                     do_log,
+                          bool                                     do_ene,
+                          bool                                     bCalcEner,
+                          bool                                     bGStat,
+                          bool                                     bStopCM,
+                          bool                                     bTrotter,
+                          bool                                     bExchanged,
+                          bool*                                    bSumEkinhOld,
+                          real*                                    saved_conserved_quantity,
+                          gmx::ForceBuffers*                       f,
+                          gmx::Update*                             upd,
+                          gmx::Constraints*                        constr,
+                          gmx::SimulationSignaller*                nullSignaller,
+                          std::array<std::vector<int>, ettTSEQMAX> trotter_seq,
+                          t_nrnb*                                  nrnb,
+                          const gmx::MDLogger&                     mdlog,
+                          FILE*                                    fplog,
+                          gmx_wallcycle*                           wcycle);
+
+
+/*! \brief Make the second step of Velocity Verlet integration
+ *
+ * \param[in]  step              Current timestep.
+ * \param[in]  ir                Input record.
+ * \param[in]  fr                Force record.
+ * \param[in]  cr                Comunication record.
+ * \param[in]  state             Simulation state.
+ * \param[in]  mdatoms           MD atoms data.
+ * \param[in]  fcdata            Force calculation data.
+ * \param[in]  MassQ             Mass/pressure data.
+ * \param[in]  vcm               Center of mass motion removal.
+ * \param[in]  pull_work         Pulling data.
+ * \param[in]  enerd             Energy data.
+ * \param[in]  ekind             Kinetic energy data.
+ * \param[in]  gstat             Storage of thermodynamic parameters data.
+ * \param[out] dvdl_constr       FEP data for constraints.
+ * \param[in]  bCalcVir          If the virial is computed on this step.
+ * \param[in]  total_vir         Total virial tensor.
+ * \param[in]  shake_vir         Constraints virial.
+ * \param[in]  force_vir         Force virial.
+ * \param[in]  pres              Pressure tensor.
+ * \param[in]  M                 Parrinello-Rahman velocity scaling matrix.
+ * \param[in]  lastbox           Last recorded PBC box.
+ * \param[in]  do_log            Do logging on this step.
+ * \param[in]  do_ene            Print energies on this step.
+ * \param[in]  bGStat            Collect globals this step.
+ * \param[out] bSumEkinhOld      Old kinetic energies need to be summed up.
+ * \param[in]  f                 Force buffers.
+ * \param[in]  cbuf              Buffer to store intermediate coordinates
+ * \param[in]  upd               Update object.
+ * \param[in]  constr            Constraints object.
+ * \param[in]  nullSignaller     Simulation signaller.
+ * \param[in]  trotter_seq       NPT variables.
+ * \param[in]  nrnb              Cycle counters.
+ * \param[in]  wcycle            Wall-clock cycle counter.
+ */
+void integrateVVSecondStep(int64_t                                  step,
+                           const t_inputrec*                        ir,
+                           t_forcerec*                              fr,
+                           t_commrec*                               cr,
+                           t_state*                                 state,
+                           t_mdatoms*                               mdatoms,
+                           const t_fcdata&                          fcdata,
+                           t_extmass*                               MassQ,
+                           t_vcm*                                   vcm,
+                           pull_t*                                  pull_work,
+                           gmx_enerdata_t*                          enerd,
+                           gmx_ekindata_t*                          ekind,
+                           gmx_global_stat*                         gstat,
+                           real*                                    dvdl_constr,
+                           bool                                     bCalcVir,
+                           tensor                                   total_vir,
+                           tensor                                   shake_vir,
+                           tensor                                   force_vir,
+                           tensor                                   pres,
+                           matrix                                   M,
+                           matrix                                   lastbox,
+                           bool                                     do_log,
+                           bool                                     do_ene,
+                           bool                                     bGStat,
+                           bool*                                    bSumEkinhOld,
+                           gmx::ForceBuffers*                       f,
+                           std::vector<gmx::RVec>*                  cbuf,
+                           gmx::Update*                             upd,
+                           gmx::Constraints*                        constr,
+                           gmx::SimulationSignaller*                nullSignaller,
+                           std::array<std::vector<int>, ettTSEQMAX> trotter_seq,
+                           t_nrnb*                                  nrnb,
+                           gmx_wallcycle*                           wcycle);
+
+
+#endif // GMX_MDLIB_UPDATE_VV_H
index cf4856825c432c8599f5847f3997e62cb00fae5e..fe040b6a98f4639f420393fe462ceb0f23d653e4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 @@
 
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/mdlib/constr.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/topology/idef.h"
@@ -337,7 +338,8 @@ static int detectGroup(int                     firstAtom,
 }
 
 /*! \brief Returns a list of update groups for \p moltype */
-static RangePartitioning makeUpdateGroups(const gmx_moltype_t& moltype, gmx::ArrayRef<const t_iparams> iparams)
+static RangePartitioning makeUpdateGroupingsPerMoleculeType(const gmx_moltype_t&           moltype,
+                                                            gmx::ArrayRef<const t_iparams> iparams)
 {
     RangePartitioning groups;
 
@@ -355,8 +357,8 @@ static RangePartitioning makeUpdateGroups(const gmx_moltype_t& moltype, gmx::Arr
     std::array<InteractionList, F_NRE> ilistsCombined;
     ilistsCombined[F_CONSTR] = jointConstraintList(moltype);
     /* We "include" flexible constraints, but none are present (checked above) */
-    const ListOfLists<int> at2con = make_at2con(moltype.atoms.nr, ilistsCombined, iparams,
-                                                FlexibleConstraintTreatment::Include);
+    const ListOfLists<int> at2con = make_at2con(
+            moltype.atoms.nr, ilistsCombined, iparams, FlexibleConstraintTreatment::Include);
 
     bool satisfiesCriteria = true;
 
@@ -385,16 +387,17 @@ static RangePartitioning makeUpdateGroups(const gmx_moltype_t& moltype, gmx::Arr
     return groups;
 }
 
-std::vector<RangePartitioning> makeUpdateGroups(const gmx_mtop_t& mtop)
+std::vector<RangePartitioning> makeUpdateGroupingsPerMoleculeType(const gmx_mtop_t& mtop)
 {
-    std::vector<RangePartitioning> updateGroups;
+    std::vector<RangePartitioning> updateGroupingsPerMoleculeType;
 
     bool systemSatisfiesCriteria = true;
     for (const gmx_moltype_t& moltype : mtop.moltype)
     {
-        updateGroups.push_back(makeUpdateGroups(moltype, mtop.ffparams.iparams));
+        updateGroupingsPerMoleculeType.push_back(
+                makeUpdateGroupingsPerMoleculeType(moltype, mtop.ffparams.iparams));
 
-        if (updateGroups.back().numBlocks() == 0)
+        if (updateGroupingsPerMoleculeType.back().numBlocks() == 0)
         {
             systemSatisfiesCriteria = false;
         }
@@ -402,10 +405,10 @@ std::vector<RangePartitioning> makeUpdateGroups(const gmx_mtop_t& mtop)
 
     if (!systemSatisfiesCriteria)
     {
-        updateGroups.clear();
+        updateGroupingsPerMoleculeType.clear();
     }
 
-    return updateGroups;
+    return updateGroupingsPerMoleculeType;
 }
 
 /*! \brief Returns a map of angles ilist.iatoms indices with the middle atom as key */
@@ -522,9 +525,10 @@ static real constraintGroupRadius(const gmx_moltype_t&                     molty
         /* Set number of stddevs such that change of exceeding < 10^-9 */
         constexpr real c_numSigma = 6.0;
         /* Compute the maximally stretched angle */
-        const real eqAngle = angleParams.harmonic.rA * DEG2RAD;
+        const real eqAngle = angleParams.harmonic.rA * gmx::c_deg2Rad;
         const real fc      = angleParams.harmonic.krA;
-        const real maxAngle = eqAngle + c_numSigma * BOLTZ * temperature / ((numPartnerAtoms - 1) * fc);
+        const real maxAngle =
+                eqAngle + c_numSigma * gmx::c_boltz * temperature / ((numPartnerAtoms - 1) * fc);
         if (maxAngle >= M_PI)
         {
             return -1;
@@ -586,7 +590,7 @@ static real constraintGroupRadius(const gmx_moltype_t&                     molty
 /*! \brief Returns the maximum update group radius for \p moltype */
 static real computeMaxUpdateGroupRadius(const gmx_moltype_t&           moltype,
                                         gmx::ArrayRef<const t_iparams> iparams,
-                                        const RangePartitioning&       updateGroups,
+                                        const RangePartitioning&       updateGrouping,
                                         real                           temperature)
 {
     GMX_RELEASE_ASSERT(!hasFlexibleConstraints(moltype, iparams),
@@ -599,9 +603,9 @@ static real computeMaxUpdateGroupRadius(const gmx_moltype_t&           moltype,
     const auto angleIndices = getAngleIndices(moltype);
 
     real maxRadius = 0;
-    for (int group = 0; group < updateGroups.numBlocks(); group++)
+    for (int group = 0; group < updateGrouping.numBlocks(); group++)
     {
-        if (updateGroups.block(group).size() == 1)
+        if (updateGrouping.block(group).size() == 1)
         {
             /* Single atom group, radius is zero */
             continue;
@@ -610,7 +614,7 @@ static real computeMaxUpdateGroupRadius(const gmx_moltype_t&           moltype,
         /* Find the atom maxAtom with the maximum number of constraints */
         int maxNumConstraints = 0;
         int maxAtom           = -1;
-        for (int a : updateGroups.block(group))
+        for (int a : updateGrouping.block(group))
         {
             const int numConstraints = at2con[a].ssize();
             if (numConstraints > maxNumConstraints)
@@ -679,8 +683,8 @@ static real computeMaxUpdateGroupRadius(const gmx_moltype_t&           moltype,
              */
             if (numConstraints == 2 && allTypesAreEqual && temperature > 0)
             {
-                radius = constraintGroupRadius<2>(moltype, iparams, maxAtom, at2con, angleIndices,
-                                                  maxConstraintLength, temperature);
+                radius = constraintGroupRadius<2>(
+                        moltype, iparams, maxAtom, at2con, angleIndices, maxConstraintLength, temperature);
             }
             /* With 3 constraints the maximum possible radius is 1.4 times
              * the constraint length, so it is worth computing a smaller
@@ -688,8 +692,8 @@ static real computeMaxUpdateGroupRadius(const gmx_moltype_t&           moltype,
              */
             if (numConstraints == 3 && allTypesAreEqual && temperature >= 0)
             {
-                radius = constraintGroupRadius<3>(moltype, iparams, maxAtom, at2con, angleIndices,
-                                                  maxConstraintLength, temperature);
+                radius = constraintGroupRadius<3>(
+                        moltype, iparams, maxAtom, at2con, angleIndices, maxConstraintLength, temperature);
                 if (temperature == 0 && radius >= 0)
                 {
                     /* Add a 10% margin for deviation at 0 K */
@@ -724,24 +728,24 @@ static real computeMaxUpdateGroupRadius(const gmx_moltype_t&           moltype,
 }
 
 real computeMaxUpdateGroupRadius(const gmx_mtop_t&                      mtop,
-                                 gmx::ArrayRef<const RangePartitioning> updateGroups,
+                                 gmx::ArrayRef<const RangePartitioning> updateGroupingsPerMoleculeType,
                                  real                                   temperature)
 {
-    if (updateGroups.empty())
+    if (updateGroupingsPerMoleculeType.empty())
     {
         return 0;
     }
 
-    GMX_RELEASE_ASSERT(updateGroups.size() == mtop.moltype.size(),
+    GMX_RELEASE_ASSERT(updateGroupingsPerMoleculeType.size() == mtop.moltype.size(),
                        "We need one update group entry per moleculetype");
 
     real maxRadius = 0;
 
     for (size_t moltype = 0; moltype < mtop.moltype.size(); moltype++)
     {
-        maxRadius = std::max(
-                maxRadius, computeMaxUpdateGroupRadius(mtop.moltype[moltype], mtop.ffparams.iparams,
-                                                       updateGroups[moltype], temperature));
+        const real radiusOfThisMoleculeType = computeMaxUpdateGroupRadius(
+                mtop.moltype[moltype], mtop.ffparams.iparams, updateGroupingsPerMoleculeType[moltype], temperature);
+        maxRadius = std::max(maxRadius, radiusOfThisMoleculeType);
     }
 
     return maxRadius;
index b88306b0925b5b3021406e1e52ce1d9bd94d133b..6daa2e22a805fa960eb6fd0d583fa8bb323984fa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,18 +71,18 @@ class RangePartitioning;
  *
  * \param[in] mtop  The system topology
  */
-std::vector<RangePartitioning> makeUpdateGroups(const gmx_mtop_t& mtop);
+std::vector<RangePartitioning> makeUpdateGroupingsPerMoleculeType(const gmx_mtop_t& mtop);
 
 /*! \brief Returns the maximum update group radius
  *
- * \note When \p updateGroups is empty, 0 is returned.
+ * \note When \p updateGroupingsPerMoleculeType is empty, 0 is returned.
  *
  * \param[in] mtop          The system topology
- * \param[in] updateGroups  List of update group, size should match the number of moltypes in \p mtop or be 0
+ * \param[in] updateGroupingsPerMoleculeType  List of update group, size should match the number of moltypes in \p mtop or be 0
  * \param[in] temperature   The maximum reference temperature, pass -1 when unknown or not applicable
  */
 real computeMaxUpdateGroupRadius(const gmx_mtop_t&                      mtop,
-                                 gmx::ArrayRef<const RangePartitioning> updateGroups,
+                                 gmx::ArrayRef<const RangePartitioning> updateGroupingsPerMoleculeType,
                                  real                                   temperature);
 
 } // namespace gmx
index 2739a398bce31f0ca5e9d5bce6bf5cd267f3d473..f73ae88de181b515669a5854e42c09fcce05c9dd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +53,7 @@ namespace gmx
 {
 
 UpdateGroupsCog::UpdateGroupsCog(const gmx_mtop_t&                           mtop,
-                                 gmx::ArrayRef<const gmx::RangePartitioning> updateGroupsPerMoleculetype,
+                                 gmx::ArrayRef<const gmx::RangePartitioning> updateGroupingsPerMoleculeType,
                                  real                                        temperature,
                                  int                                         numHomeAtoms) :
     globalToLocalMap_(numHomeAtoms),
@@ -62,19 +62,19 @@ UpdateGroupsCog::UpdateGroupsCog(const gmx_mtop_t&                           mto
     int firstUpdateGroupInMolecule = 0;
     for (const auto& molblock : mtop.molblock)
     {
-        const auto& updateGroups = updateGroupsPerMoleculetype[molblock.type];
-        indicesPerMoleculeblock_.push_back({ firstUpdateGroupInMolecule, updateGroups.numBlocks(), {} });
+        const auto& updateGrouping = updateGroupingsPerMoleculeType[molblock.type];
+        indicesPerMoleculeblock_.push_back({ firstUpdateGroupInMolecule, updateGrouping.numBlocks(), {} });
         auto& groupIndex = indicesPerMoleculeblock_.back().groupIndex_;
 
-        for (int block = 0; block < updateGroups.numBlocks(); block++)
+        for (int block = 0; block < updateGrouping.numBlocks(); block++)
         {
-            groupIndex.insert(groupIndex.end(), updateGroups.block(block).size(), block);
+            groupIndex.insert(groupIndex.end(), updateGrouping.block(block).size(), block);
         }
 
-        firstUpdateGroupInMolecule += molblock.nmol * updateGroups.numBlocks();
+        firstUpdateGroupInMolecule += molblock.nmol * updateGrouping.numBlocks();
     }
 
-    maxUpdateGroupRadius_ = computeMaxUpdateGroupRadius(mtop, updateGroupsPerMoleculetype, temperature);
+    maxUpdateGroupRadius_ = computeMaxUpdateGroupRadius(mtop, updateGroupingsPerMoleculeType, temperature);
 }
 
 void UpdateGroupsCog::addCogs(gmx::ArrayRef<const int>       globalAtomIndices,
@@ -95,7 +95,7 @@ void UpdateGroupsCog::addCogs(gmx::ArrayRef<const int>       globalAtomIndices,
         const int globalAtom = globalAtomIndices[localAtom];
         int       moleculeIndex;
         int       atomIndexInMolecule;
-        mtopGetMolblockIndex(&mtop_, globalAtom, &moleculeBlock, &moleculeIndex, &atomIndexInMolecule);
+        mtopGetMolblockIndex(mtop_, globalAtom, &moleculeBlock, &moleculeIndex, &atomIndexInMolecule);
         const auto& indicesForBlock        = indicesPerMoleculeblock_[moleculeBlock];
         int         globalUpdateGroupIndex = indicesForBlock.groupStart_
                                      + moleculeIndex * indicesForBlock.numGroupsPerMolecule_
index 65c6ac978d763184f3785c97df079fb3bffdfdb7..ca05d95814e911e8c96ef9dcf1aac0b636d490eb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -69,13 +69,13 @@ public:
      * \note \p numHomeAtoms only affects the performance up till the first
      *       call to clear().
      *
-     * \param[in] mtop                         The global topology
-     * \param[in] updateGroupsPerMoleculetype  List of update groups for each molecule type in \p mtop
-     * \param[in] temperature                  The maximum reference temperature, pass -1 when unknown or not applicable
-     * \param[in] numHomeAtoms                 Estimate of the number of home atoms per DD cell
+     * \param[in] mtop                            The global topology
+     * \param[in] updateGroupingsPerMoleculeType  List of update groups for each molecule type in \p mtop
+     * \param[in] temperature                     The maximum reference temperature, pass -1 when unknown or not applicable
+     * \param[in] numHomeAtoms                    Estimate of the number of home atoms per DD cell
      */
     UpdateGroupsCog(const gmx_mtop_t&                           mtop,
-                    gmx::ArrayRef<const gmx::RangePartitioning> updateGroupsPerMoleculetype,
+                    gmx::ArrayRef<const gmx::RangePartitioning> updateGroupingsPerMoleculeType,
                     real                                        temperature,
                     int                                         numHomeAtoms);
 
index 63a3df664a2855772605ccb429a10c131ae6b91a..a8f6f0edbadcf50b127fdfdb827c050a2b45e706 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 t_vcm::t_vcm(const SimulationGroups& groups, const t_inputrec& ir) :
     integratorConservesMomentum(!EI_RANDOM(ir.eI))
 {
-    mode     = (ir.nstcomm > 0) ? ir.comm_mode : ecmNO;
+    mode     = (ir.nstcomm > 0) ? ir.comm_mode : ComRemovalAlgorithm::No;
     ndim     = ndof_com(&ir);
     timeStep = ir.nstcomm * ir.delta_t;
 
-    if (mode == ecmANGULAR && ndim < 3)
+    if (mode == ComRemovalAlgorithm::Angular && ndim < 3)
     {
-        gmx_fatal(FARGS, "Can not have angular comm removal with pbc=%s",
-                  c_pbcTypeNames[ir.pbcType].c_str());
+        gmx_fatal(FARGS, "Can not have angular comm removal with pbc=%s", c_pbcTypeNames[ir.pbcType].c_str());
     }
 
-    if (mode != ecmNO)
+    if (mode != ComRemovalAlgorithm::No)
     {
         nr = groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval].size();
         /* Allocate one extra for a possible rest group */
@@ -77,7 +76,7 @@ t_vcm::t_vcm(const SimulationGroups& groups, const t_inputrec& ir) :
          * invalidation we add 2 elements to get a 152 byte separation.
          */
         stride = nr + 3;
-        if (mode == ecmANGULAR)
+        if (mode == ComRemovalAlgorithm::Angular)
         {
             snew(group_i, size);
 
@@ -98,7 +97,7 @@ t_vcm::t_vcm(const SimulationGroups& groups, const t_inputrec& ir) :
                     *groups.groupNames[groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval][g]];
         }
 
-        thread_vcm.resize(gmx_omp_nthreads_get(emntDefault) * stride);
+        thread_vcm.resize(gmx_omp_nthreads_get(ModuleMultiThread::Default) * stride);
     }
 
     nFreeze = ir.opts.nFreeze;
@@ -106,7 +105,7 @@ t_vcm::t_vcm(const SimulationGroups& groups, const t_inputrec& ir) :
 
 t_vcm::~t_vcm()
 {
-    if (mode == ecmANGULAR)
+    if (mode == ComRemovalAlgorithm::Angular)
     {
         sfree(group_i);
     }
@@ -116,9 +115,9 @@ void reportComRemovalInfo(FILE* fp, const t_vcm& vcm)
 {
 
     /* Copy pointer to group names and print it. */
-    if (fp && vcm.mode != ecmNO)
+    if (fp && vcm.mode != ComRemovalAlgorithm::No)
     {
-        fprintf(fp, "Center of mass motion removal mode is %s\n", ECOM(vcm.mode));
+        fprintf(fp, "Center of mass motion removal mode is %s\n", enumValueToString(vcm.mode));
         fprintf(fp,
                 "We have the following groups for center of"
                 " mass motion removal:\n");
@@ -157,11 +156,11 @@ void calc_vcm_grp(const t_mdatoms&               md,
                   gmx::ArrayRef<const gmx::RVec> v,
                   t_vcm*                         vcm)
 {
-    if (vcm->mode == ecmNO)
+    if (vcm->mode == ComRemovalAlgorithm::No)
     {
         return;
     }
-    int nthreads = gmx_omp_nthreads_get(emntDefault);
+    int nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Default);
 
     {
 #pragma omp parallel num_threads(nthreads) default(none) shared(x, v, vcm, md)
@@ -173,7 +172,7 @@ void calc_vcm_grp(const t_mdatoms&               md,
                 t_vcm_thread* vcm_t = &vcm->thread_vcm[t * vcm->stride + g];
                 vcm_t->mass         = 0;
                 clear_rvec(vcm_t->p);
-                if (vcm->mode == ecmANGULAR)
+                if (vcm->mode == ComRemovalAlgorithm::Angular)
                 {
                     /* Reset angular momentum */
                     clear_rvec(vcm_t->j);
@@ -200,7 +199,7 @@ void calc_vcm_grp(const t_mdatoms&               md,
                     vcm_t->p[m] += m0 * v[i][m];
                 }
 
-                if (vcm->mode == ecmANGULAR)
+                if (vcm->mode == ComRemovalAlgorithm::Angular)
                 {
                     /* Calculate angular momentum */
                     rvec j0;
@@ -221,7 +220,7 @@ void calc_vcm_grp(const t_mdatoms&               md,
             /* Reset linear momentum */
             vcm->group_mass[g] = 0;
             clear_rvec(vcm->group_p[g]);
-            if (vcm->mode == ecmANGULAR)
+            if (vcm->mode == ComRemovalAlgorithm::Angular)
             {
                 /* Reset angular momentum */
                 clear_rvec(vcm->group_j[g]);
@@ -235,7 +234,7 @@ void calc_vcm_grp(const t_mdatoms&               md,
                 t_vcm_thread* vcm_t = &vcm->thread_vcm[t * vcm->stride + g];
                 vcm->group_mass[g] += vcm_t->mass;
                 rvec_inc(vcm->group_p[g], vcm_t->p);
-                if (vcm->mode == ecmANGULAR)
+                if (vcm->mode == ComRemovalAlgorithm::Angular)
                 {
                     rvec_inc(vcm->group_j[g], vcm_t->j);
                     rvec_inc(vcm->group_x[g], vcm_t->x);
@@ -357,7 +356,7 @@ static void do_stopcm_grp(const t_mdatoms&         mdatoms,
                           gmx::ArrayRef<gmx::RVec> v,
                           const t_vcm&             vcm)
 {
-    if (vcm.mode == ecmNO)
+    if (vcm.mode == ComRemovalAlgorithm::No)
     {
         return;
     }
@@ -365,14 +364,14 @@ static void do_stopcm_grp(const t_mdatoms&         mdatoms,
         const int             homenr   = mdatoms.homenr;
         const unsigned short* group_id = mdatoms.cVCM;
 
-        int gmx_unused nth = gmx_omp_nthreads_get(emntDefault);
+        int gmx_unused nth = gmx_omp_nthreads_get(ModuleMultiThread::Default);
         // homenr could be shared, but gcc-8 & gcc-9 don't agree how to write that...
         // https://www.gnu.org/software/gcc/gcc-9/porting_to.html -> OpenMP data sharing
 #pragma omp parallel num_threads(nth) default(none) shared(x, v, vcm, group_id, mdatoms) \
         firstprivate(homenr)
         {
-            if (vcm.mode == ecmLINEAR || vcm.mode == ecmANGULAR
-                || (vcm.mode == ecmLINEAR_ACCELERATION_CORRECTION && x.empty()))
+            if (vcm.mode == ComRemovalAlgorithm::Linear || vcm.mode == ComRemovalAlgorithm::Angular
+                || (vcm.mode == ComRemovalAlgorithm::LinearAccelerationCorrection && x.empty()))
             {
                 /* Subtract linear momentum for v */
                 switch (vcm.ndim)
@@ -384,7 +383,7 @@ static void do_stopcm_grp(const t_mdatoms&         mdatoms,
             }
             else
             {
-                GMX_ASSERT(vcm.mode == ecmLINEAR_ACCELERATION_CORRECTION,
+                GMX_ASSERT(vcm.mode == ComRemovalAlgorithm::LinearAccelerationCorrection,
                            "When the mode is not linear or angular, it should be acceleration "
                            "correction");
                 /* Subtract linear momentum for v and x*/
@@ -401,7 +400,7 @@ static void do_stopcm_grp(const t_mdatoms&         mdatoms,
                         break;
                 }
             }
-            if (vcm.mode == ecmANGULAR)
+            if (vcm.mode == ComRemovalAlgorithm::Angular)
             {
                 /* Subtract angular momentum */
                 GMX_ASSERT(!x.empty(), "Need x to compute angular momentum correction");
@@ -474,7 +473,7 @@ static void process_and_check_cm_grp(FILE* fp, t_vcm* vcm, real Temp_Max)
     tensor Icm;
 
     /* First analyse the total results */
-    if (vcm->mode != ecmNO)
+    if (vcm->mode != ComRemovalAlgorithm::No)
     {
         for (g = 0; (g < vcm->nr); g++)
         {
@@ -486,7 +485,7 @@ static void process_and_check_cm_grp(FILE* fp, t_vcm* vcm, real Temp_Max)
             }
             /* Else it's zero anyway! */
         }
-        if (vcm->mode == ecmANGULAR)
+        if (vcm->mode == ComRemovalAlgorithm::Angular)
         {
             for (g = 0; (g < vcm->nr); g++)
             {
@@ -544,12 +543,16 @@ static void process_and_check_cm_grp(FILE* fp, t_vcm* vcm, real Temp_Max)
 
             if ((Temp_cm > Temp_Max) && fp)
             {
-                fprintf(fp, "Large VCM(group %s): %12.5f, %12.5f, %12.5f, Temp-cm: %12.5e\n",
-                        vcm->group_name[g], vcm->group_v[g][XX], vcm->group_v[g][YY],
-                        vcm->group_v[g][ZZ], Temp_cm);
+                fprintf(fp,
+                        "Large VCM(group %s): %12.5f, %12.5f, %12.5f, Temp-cm: %12.5e\n",
+                        vcm->group_name[g],
+                        vcm->group_v[g][XX],
+                        vcm->group_v[g][YY],
+                        vcm->group_v[g][ZZ],
+                        Temp_cm);
             }
 
-            if (vcm->mode == ecmANGULAR)
+            if (vcm->mode == ComRemovalAlgorithm::Angular)
             {
                 ekrot = 0.5 * iprod(vcm->group_j[g], vcm->group_w[g]);
                 // TODO: Change absolute energy comparison to relative
@@ -557,18 +560,37 @@ static void process_and_check_cm_grp(FILE* fp, t_vcm* vcm, real Temp_Max)
                 {
                     /* if we have an integrator that may not conserve momenta, skip */
                     tm = vcm->group_mass[g];
-                    fprintf(fp, "Group %s with mass %12.5e, Ekrot %12.5e Det(I) = %12.5e\n",
-                            vcm->group_name[g], tm, ekrot, det(vcm->group_i[g]));
-                    fprintf(fp, "  COM: %12.5f  %12.5f  %12.5f\n", vcm->group_x[g][XX],
-                            vcm->group_x[g][YY], vcm->group_x[g][ZZ]);
-                    fprintf(fp, "  P:   %12.5f  %12.5f  %12.5f\n", vcm->group_p[g][XX],
-                            vcm->group_p[g][YY], vcm->group_p[g][ZZ]);
-                    fprintf(fp, "  V:   %12.5f  %12.5f  %12.5f\n", vcm->group_v[g][XX],
-                            vcm->group_v[g][YY], vcm->group_v[g][ZZ]);
-                    fprintf(fp, "  J:   %12.5f  %12.5f  %12.5f\n", vcm->group_j[g][XX],
-                            vcm->group_j[g][YY], vcm->group_j[g][ZZ]);
-                    fprintf(fp, "  w:   %12.5f  %12.5f  %12.5f\n", vcm->group_w[g][XX],
-                            vcm->group_w[g][YY], vcm->group_w[g][ZZ]);
+                    fprintf(fp,
+                            "Group %s with mass %12.5e, Ekrot %12.5e Det(I) = %12.5e\n",
+                            vcm->group_name[g],
+                            tm,
+                            ekrot,
+                            det(vcm->group_i[g]));
+                    fprintf(fp,
+                            "  COM: %12.5f  %12.5f  %12.5f\n",
+                            vcm->group_x[g][XX],
+                            vcm->group_x[g][YY],
+                            vcm->group_x[g][ZZ]);
+                    fprintf(fp,
+                            "  P:   %12.5f  %12.5f  %12.5f\n",
+                            vcm->group_p[g][XX],
+                            vcm->group_p[g][YY],
+                            vcm->group_p[g][ZZ]);
+                    fprintf(fp,
+                            "  V:   %12.5f  %12.5f  %12.5f\n",
+                            vcm->group_v[g][XX],
+                            vcm->group_v[g][YY],
+                            vcm->group_v[g][ZZ]);
+                    fprintf(fp,
+                            "  J:   %12.5f  %12.5f  %12.5f\n",
+                            vcm->group_j[g][XX],
+                            vcm->group_j[g][YY],
+                            vcm->group_j[g][ZZ]);
+                    fprintf(fp,
+                            "  w:   %12.5f  %12.5f  %12.5f\n",
+                            vcm->group_w[g][XX],
+                            vcm->group_w[g][YY],
+                            vcm->group_w[g][ZZ]);
                     pr_rvecs(fp, 0, "Inertia tensor", vcm->group_i[g], DIM);
                 }
             }
@@ -582,7 +604,7 @@ void process_and_stopcm_grp(FILE*                    fplog,
                             gmx::ArrayRef<gmx::RVec> x,
                             gmx::ArrayRef<gmx::RVec> v)
 {
-    if (vcm->mode != ecmNO)
+    if (vcm->mode != ComRemovalAlgorithm::No)
     {
         // TODO: Replace fixed temperature of 1 by a system value
         process_and_check_cm_grp(fplog, vcm, 1);
index b0c142474101f740f8fda554d70e1b6ee6382118..eb33b56e4253c673dd523354a5f8a6987a4f0309 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #include <vector>
 
 #include "gromacs/math/vectypes.h"
+#include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
@@ -79,7 +80,7 @@ struct t_vcm
     //! Stride for thread data
     int stride = 0;
     //! One of the enums above
-    int mode = 0;
+    ComRemovalAlgorithm mode = ComRemovalAlgorithm::Linear;
     //! The number of dimensions for corr.
     int ndim = 0;
     //! The time step for COMM removal
index 35628004ecea0774db522eebf30461901a804bc6..d030f9d4aba335b2e3f1b592663e9d27e320473e 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 The GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
 #include "gromacs/mdtypes/commrec.h"
-#include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/pbcutil/ishift.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/timing/wallcycle.h"
@@ -165,7 +164,7 @@ struct VsiteThread
     //! The interaction lists, only vsite entries are used
     std::array<InteractionList, F_NRE> ilist;
     //! Local fshift accumulation buffer
-    std::array<RVec, SHIFTS> fshift;
+    std::array<RVec, c_numShiftVectors> fshift;
     //! Local virial dx*df accumulation buffer
     matrix dxdf;
     //! Tells if interdependent task idTask should be used (in addition to the rest of this task), this bool has the same value on all threads
@@ -214,7 +213,9 @@ public:
     //! Set VSites and distribute VSite work over threads, should be called after DD partitioning
     void setVirtualSites(ArrayRef<const InteractionList> ilist,
                          ArrayRef<const t_iparams>       iparams,
-                         const t_mdatoms&                mdatoms,
+                         int                             numAtoms,
+                         int                             homenr,
+                         ArrayRef<const ParticleType>    ptype,
                          bool                            useDomdec);
 
 private:
@@ -232,22 +233,28 @@ class VirtualSitesHandler::Impl
 {
 public:
     //! Constructor, domdec should be nullptr without DD
-    Impl(const gmx_mtop_t& mtop, gmx_domdec_t* domdec, PbcType pbcType);
+    Impl(const gmx_mtop_t&                 mtop,
+         gmx_domdec_t*                     domdec,
+         PbcType                           pbcType,
+         ArrayRef<const RangePartitioning> updateGroupingPerMoleculeType);
 
     //! Returns the number of virtual sites acting over multiple update groups
     int numInterUpdategroupVirtualSites() const { return numInterUpdategroupVirtualSites_; }
 
     //! Set VSites and distribute VSite work over threads, should be called after DD partitioning
-    void setVirtualSites(ArrayRef<const InteractionList> ilist, const t_mdatoms& mdatoms);
+    void setVirtualSites(ArrayRef<const InteractionList> ilist,
+                         int                             numAtoms,
+                         int                             homenr,
+                         ArrayRef<const ParticleType>    ptype);
 
     /*! \brief Create positions of vsite atoms based for the local system
      *
-     * \param[in,out] x        The coordinates
-     * \param[in]     dt       The time step
-     * \param[in,out] v        When != nullptr, velocities for vsites are set as displacement/dt
-     * \param[in]     box      The box
+     * \param[in,out] x          The coordinates
+     * \param[in,out] v          The velocities, needed if operation requires it
+     * \param[in]     box        The box
+     * \param[in]     operation  Whether we calculate positions, velocities, or both
      */
-    void construct(ArrayRef<RVec> x, real dt, ArrayRef<RVec> v, const matrix box) const;
+    void construct(ArrayRef<RVec> x, ArrayRef<RVec> v, const matrix box, VSiteOperation operation) const;
 
     /*! \brief Spread the force operating on the vsite atoms on the surrounding atoms.
      *
@@ -313,7 +320,7 @@ static int pbc_rvec_sub(const t_pbc* pbc, const rvec xi, const rvec xj, rvec dx)
     else
     {
         rvec_sub(xi, xj, dx);
-        return CENTRAL;
+        return c_centralShiftIndex;
     }
 }
 
@@ -323,87 +330,167 @@ static inline real inverseNorm(const rvec x)
     return gmx::invsqrt(iprod(x, x));
 }
 
+//! Whether we're calculating the virtual site position
+enum class VSiteCalculatePosition
+{
+    Yes,
+    No
+};
+//! Whether we're calculating the virtual site velocity
+enum class VSiteCalculateVelocity
+{
+    Yes,
+    No
+};
+
 #ifndef DOXYGEN
 /* Vsite construction routines */
 
-static void constr_vsite1(const rvec xi, rvec x)
-{
-    copy_rvec(xi, x);
+// GCC 8 falsely flags unused variables if constexpr prunes a code path, fixed in GCC 9
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85827
+// clang-format off
+GCC_DIAGNOSTIC_IGNORE(-Wunused-but-set-parameter)
+// clang-format on
 
-    /* TOTAL: 0 flops */
+template<VSiteCalculatePosition calculatePosition, VSiteCalculateVelocity calculateVelocity>
+static void constr_vsite1(const rvec xi, rvec x, const rvec vi, rvec v)
+{
+    if (calculatePosition == VSiteCalculatePosition::Yes)
+    {
+        copy_rvec(xi, x);
+        /* TOTAL: 0 flops */
+    }
+    if (calculateVelocity == VSiteCalculateVelocity::Yes)
+    {
+        copy_rvec(vi, v);
+    }
 }
 
-static void constr_vsite2(const rvec xi, const rvec xj, rvec x, real a, const t_pbc* pbc)
+template<VSiteCalculatePosition calculatePosition, VSiteCalculateVelocity calculateVelocity>
+static void
+constr_vsite2(const rvec xi, const rvec xj, rvec x, real a, const t_pbc* pbc, const rvec vi, const rvec vj, rvec v)
 {
-    real b = 1 - a;
+    const real b = 1 - a;
     /* 1 flop */
 
-    if (pbc)
+    if (calculatePosition == VSiteCalculatePosition::Yes)
     {
-        rvec dx;
-        pbc_dx_aiuc(pbc, xj, xi, dx);
-        x[XX] = xi[XX] + a * dx[XX];
-        x[YY] = xi[YY] + a * dx[YY];
-        x[ZZ] = xi[ZZ] + a * dx[ZZ];
+        if (pbc)
+        {
+            rvec dx;
+            pbc_dx_aiuc(pbc, xj, xi, dx);
+            x[XX] = xi[XX] + a * dx[XX];
+            x[YY] = xi[YY] + a * dx[YY];
+            x[ZZ] = xi[ZZ] + a * dx[ZZ];
+        }
+        else
+        {
+            x[XX] = b * xi[XX] + a * xj[XX];
+            x[YY] = b * xi[YY] + a * xj[YY];
+            x[ZZ] = b * xi[ZZ] + a * xj[ZZ];
+            /* 9 Flops */
+        }
+        /* TOTAL: 10 flops */
     }
-    else
+    if (calculateVelocity == VSiteCalculateVelocity::Yes)
     {
-        x[XX] = b * xi[XX] + a * xj[XX];
-        x[YY] = b * xi[YY] + a * xj[YY];
-        x[ZZ] = b * xi[ZZ] + a * xj[ZZ];
-        /* 9 Flops */
+        v[XX] = b * vi[XX] + a * vj[XX];
+        v[YY] = b * vi[YY] + a * vj[YY];
+        v[ZZ] = b * vi[ZZ] + a * vj[ZZ];
     }
-
-    /* TOTAL: 10 flops */
 }
 
-static void constr_vsite2FD(const rvec xi, const rvec xj, rvec x, real a, const t_pbc* pbc)
+template<VSiteCalculatePosition calculatePosition, VSiteCalculateVelocity calculateVelocity>
+static void
+constr_vsite2FD(const rvec xi, const rvec xj, rvec x, real a, const t_pbc* pbc, const rvec vi, const rvec vj, rvec v)
 {
-    rvec xij;
+    rvec xij = { 0 };
     pbc_rvec_sub(pbc, xj, xi, xij);
     /* 3 flops */
 
-    const real b = a * inverseNorm(xij);
+    const real invNormXij = inverseNorm(xij);
+    const real b          = a * invNormXij;
     /* 6 + 10 flops */
 
-    x[XX] = xi[XX] + b * xij[XX];
-    x[YY] = xi[YY] + b * xij[YY];
-    x[ZZ] = xi[ZZ] + b * xij[ZZ];
-    /* 6 Flops */
+    if (calculatePosition == VSiteCalculatePosition::Yes)
+    {
+        x[XX] = xi[XX] + b * xij[XX];
+        x[YY] = xi[YY] + b * xij[YY];
+        x[ZZ] = xi[ZZ] + b * xij[ZZ];
+        /* 6 Flops */
+        /* TOTAL: 25 flops */
+    }
+    if (calculateVelocity == VSiteCalculateVelocity::Yes)
+    {
+        rvec vij = { 0 };
+        rvec_sub(vj, vi, vij);
+        const real vijDotXij = iprod(vij, xij);
 
-    /* TOTAL: 25 flops */
+        v[XX] = vi[XX] + b * (vij[XX] - xij[XX] * vijDotXij * invNormXij * invNormXij);
+        v[YY] = vi[YY] + b * (vij[YY] - xij[YY] * vijDotXij * invNormXij * invNormXij);
+        v[ZZ] = vi[ZZ] + b * (vij[ZZ] - xij[ZZ] * vijDotXij * invNormXij * invNormXij);
+    }
 }
 
-static void constr_vsite3(const rvec xi, const rvec xj, const rvec xk, rvec x, real a, real b, const t_pbc* pbc)
+template<VSiteCalculatePosition calculatePosition, VSiteCalculateVelocity calculateVelocity>
+static void constr_vsite3(const rvec   xi,
+                          const rvec   xj,
+                          const rvec   xk,
+                          rvec         x,
+                          real         a,
+                          real         b,
+                          const t_pbc* pbc,
+                          const rvec   vi,
+                          const rvec   vj,
+                          const rvec   vk,
+                          rvec         v)
 {
-    real c = 1 - a - b;
+    const real c = 1 - a - b;
     /* 2 flops */
 
-    if (pbc)
+    if (calculatePosition == VSiteCalculatePosition::Yes)
     {
-        rvec dxj, dxk;
+        if (pbc)
+        {
+            rvec dxj, dxk;
 
-        pbc_dx_aiuc(pbc, xj, xi, dxj);
-        pbc_dx_aiuc(pbc, xk, xi, dxk);
-        x[XX] = xi[XX] + a * dxj[XX] + b * dxk[XX];
-        x[YY] = xi[YY] + a * dxj[YY] + b * dxk[YY];
-        x[ZZ] = xi[ZZ] + a * dxj[ZZ] + b * dxk[ZZ];
+            pbc_dx_aiuc(pbc, xj, xi, dxj);
+            pbc_dx_aiuc(pbc, xk, xi, dxk);
+            x[XX] = xi[XX] + a * dxj[XX] + b * dxk[XX];
+            x[YY] = xi[YY] + a * dxj[YY] + b * dxk[YY];
+            x[ZZ] = xi[ZZ] + a * dxj[ZZ] + b * dxk[ZZ];
+        }
+        else
+        {
+            x[XX] = c * xi[XX] + a * xj[XX] + b * xk[XX];
+            x[YY] = c * xi[YY] + a * xj[YY] + b * xk[YY];
+            x[ZZ] = c * xi[ZZ] + a * xj[ZZ] + b * xk[ZZ];
+            /* 15 Flops */
+        }
+        /* TOTAL: 17 flops */
     }
-    else
+    if (calculateVelocity == VSiteCalculateVelocity::Yes)
     {
-        x[XX] = c * xi[XX] + a * xj[XX] + b * xk[XX];
-        x[YY] = c * xi[YY] + a * xj[YY] + b * xk[YY];
-        x[ZZ] = c * xi[ZZ] + a * xj[ZZ] + b * xk[ZZ];
-        /* 15 Flops */
+        v[XX] = c * vi[XX] + a * vj[XX] + b * vk[XX];
+        v[YY] = c * vi[YY] + a * vj[YY] + b * vk[YY];
+        v[ZZ] = c * vi[ZZ] + a * vj[ZZ] + b * vk[ZZ];
     }
-
-    /* TOTAL: 17 flops */
 }
 
-static void constr_vsite3FD(const rvec xi, const rvec xj, const rvec xk, rvec x, real a, real b, const t_pbc* pbc)
+template<VSiteCalculatePosition calculatePosition, VSiteCalculateVelocity calculateVelocity>
+static void constr_vsite3FD(const rvec   xi,
+                            const rvec   xj,
+                            const rvec   xk,
+                            rvec         x,
+                            real         a,
+                            real         b,
+                            const t_pbc* pbc,
+                            const rvec   vi,
+                            const rvec   vj,
+                            const rvec   vk,
+                            rvec         v)
 {
     rvec xij, xjk, temp;
-    real c;
 
     pbc_rvec_sub(pbc, xj, xi, xij);
     pbc_rvec_sub(pbc, xk, xj, xjk);
@@ -415,45 +502,122 @@ static void constr_vsite3FD(const rvec xi, const rvec xj, const rvec xk, rvec x,
     temp[ZZ] = xij[ZZ] + a * xjk[ZZ];
     /* 6 flops */
 
-    c = b * inverseNorm(temp);
+    const real invNormTemp = inverseNorm(temp);
+    const real c           = b * invNormTemp;
     /* 6 + 10 flops */
 
-    x[XX] = xi[XX] + c * temp[XX];
-    x[YY] = xi[YY] + c * temp[YY];
-    x[ZZ] = xi[ZZ] + c * temp[ZZ];
-    /* 6 Flops */
+    if (calculatePosition == VSiteCalculatePosition::Yes)
+    {
+        x[XX] = xi[XX] + c * temp[XX];
+        x[YY] = xi[YY] + c * temp[YY];
+        x[ZZ] = xi[ZZ] + c * temp[ZZ];
+        /* 6 Flops */
+        /* TOTAL: 34 flops */
+    }
+    if (calculateVelocity == VSiteCalculateVelocity::Yes)
+    {
+        rvec vij = { 0 };
+        rvec vjk = { 0 };
+        rvec_sub(vj, vi, vij);
+        rvec_sub(vk, vj, vjk);
+        const rvec tempV = { vij[XX] + a * vjk[XX], vij[YY] + a * vjk[YY], vij[ZZ] + a * vjk[ZZ] };
+        const real tempDotTempV = iprod(temp, tempV);
 
-    /* TOTAL: 34 flops */
+        v[XX] = vi[XX] + c * (tempV[XX] - temp[XX] * tempDotTempV * invNormTemp * invNormTemp);
+        v[YY] = vi[YY] + c * (tempV[YY] - temp[YY] * tempDotTempV * invNormTemp * invNormTemp);
+        v[ZZ] = vi[ZZ] + c * (tempV[ZZ] - temp[ZZ] * tempDotTempV * invNormTemp * invNormTemp);
+    }
 }
 
-static void constr_vsite3FAD(const rvec xi, const rvec xj, const rvec xk, rvec x, real a, real b, const t_pbc* pbc)
-{
+template<VSiteCalculatePosition calculatePosition, VSiteCalculateVelocity calculateVelocity>
+static void constr_vsite3FAD(const rvec   xi,
+                             const rvec   xj,
+                             const rvec   xk,
+                             rvec         x,
+                             real         a,
+                             real         b,
+                             const t_pbc* pbc,
+                             const rvec   vi,
+                             const rvec   vj,
+                             const rvec   vk,
+                             rvec         v)
+{ // Note: a = d * cos(theta)
+    //       b = d * sin(theta)
     rvec xij, xjk, xp;
-    real a1, b1, c1, invdij;
 
     pbc_rvec_sub(pbc, xj, xi, xij);
     pbc_rvec_sub(pbc, xk, xj, xjk);
     /* 6 flops */
 
-    invdij = inverseNorm(xij);
-    c1     = invdij * invdij * iprod(xij, xjk);
-    xp[XX] = xjk[XX] - c1 * xij[XX];
-    xp[YY] = xjk[YY] - c1 * xij[YY];
-    xp[ZZ] = xjk[ZZ] - c1 * xij[ZZ];
-    a1     = a * invdij;
-    b1     = b * inverseNorm(xp);
+    const real invdij    = inverseNorm(xij);
+    const real xijDotXjk = iprod(xij, xjk);
+    const real c1        = invdij * invdij * xijDotXjk;
+    xp[XX]               = xjk[XX] - c1 * xij[XX];
+    xp[YY]               = xjk[YY] - c1 * xij[YY];
+    xp[ZZ]               = xjk[ZZ] - c1 * xij[ZZ];
+    const real a1        = a * invdij;
+    const real invNormXp = inverseNorm(xp);
+    const real b1        = b * invNormXp;
     /* 45 */
 
-    x[XX] = xi[XX] + a1 * xij[XX] + b1 * xp[XX];
-    x[YY] = xi[YY] + a1 * xij[YY] + b1 * xp[YY];
-    x[ZZ] = xi[ZZ] + a1 * xij[ZZ] + b1 * xp[ZZ];
-    /* 12 Flops */
-
-    /* TOTAL: 63 flops */
+    if (calculatePosition == VSiteCalculatePosition::Yes)
+    {
+        x[XX] = xi[XX] + a1 * xij[XX] + b1 * xp[XX];
+        x[YY] = xi[YY] + a1 * xij[YY] + b1 * xp[YY];
+        x[ZZ] = xi[ZZ] + a1 * xij[ZZ] + b1 * xp[ZZ];
+        /* 12 Flops */
+        /* TOTAL: 63 flops */
+    }
+
+    if (calculateVelocity == VSiteCalculateVelocity::Yes)
+    {
+        rvec vij = { 0 };
+        rvec vjk = { 0 };
+        rvec_sub(vj, vi, vij);
+        rvec_sub(vk, vj, vjk);
+
+        const real vijDotXjkPlusXijDotVjk = iprod(vij, xjk) + iprod(xij, vjk);
+        const real xijDotVij              = iprod(xij, vij);
+        const real invNormXij2            = invdij * invdij;
+
+        rvec vp = { 0 };
+        vp[XX]  = vjk[XX]
+                 - xij[XX] * invNormXij2
+                           * (vijDotXjkPlusXijDotVjk - invNormXij2 * xijDotXjk * xijDotVij * 2)
+                 - vij[XX] * xijDotXjk * invNormXij2;
+        vp[YY] = vjk[YY]
+                 - xij[YY] * invNormXij2
+                           * (vijDotXjkPlusXijDotVjk - invNormXij2 * xijDotXjk * xijDotVij * 2)
+                 - vij[YY] * xijDotXjk * invNormXij2;
+        vp[ZZ] = vjk[ZZ]
+                 - xij[ZZ] * invNormXij2
+                           * (vijDotXjkPlusXijDotVjk - invNormXij2 * xijDotXjk * xijDotVij * 2)
+                 - vij[ZZ] * xijDotXjk * invNormXij2;
+
+        const real xpDotVp = iprod(xp, vp);
+
+        v[XX] = vi[XX] + a1 * (vij[XX] - xij[XX] * xijDotVij * invdij * invdij)
+                + b1 * (vp[XX] - xp[XX] * xpDotVp * invNormXp * invNormXp);
+        v[YY] = vi[YY] + a1 * (vij[YY] - xij[YY] * xijDotVij * invdij * invdij)
+                + b1 * (vp[YY] - xp[YY] * xpDotVp * invNormXp * invNormXp);
+        v[ZZ] = vi[ZZ] + a1 * (vij[ZZ] - xij[ZZ] * xijDotVij * invdij * invdij)
+                + b1 * (vp[ZZ] - xp[ZZ] * xpDotVp * invNormXp * invNormXp);
+    }
 }
 
-static void
-constr_vsite3OUT(const rvec xi, const rvec xj, const rvec xk, rvec x, real a, real b, real c, const t_pbc* pbc)
+template<VSiteCalculatePosition calculatePosition, VSiteCalculateVelocity calculateVelocity>
+static void constr_vsite3OUT(const rvec   xi,
+                             const rvec   xj,
+                             const rvec   xk,
+                             rvec         x,
+                             real         a,
+                             real         b,
+                             real         c,
+                             const t_pbc* pbc,
+                             const rvec   vi,
+                             const rvec   vj,
+                             const rvec   vk,
+                             rvec         v)
 {
     rvec xij, xik, temp;
 
@@ -462,14 +626,34 @@ constr_vsite3OUT(const rvec xi, const rvec xj, const rvec xk, rvec x, real a, re
     cprod(xij, xik, temp);
     /* 15 Flops */
 
-    x[XX] = xi[XX] + a * xij[XX] + b * xik[XX] + c * temp[XX];
-    x[YY] = xi[YY] + a * xij[YY] + b * xik[YY] + c * temp[YY];
-    x[ZZ] = xi[ZZ] + a * xij[ZZ] + b * xik[ZZ] + c * temp[ZZ];
-    /* 18 Flops */
+    if (calculatePosition == VSiteCalculatePosition::Yes)
+    {
+        x[XX] = xi[XX] + a * xij[XX] + b * xik[XX] + c * temp[XX];
+        x[YY] = xi[YY] + a * xij[YY] + b * xik[YY] + c * temp[YY];
+        x[ZZ] = xi[ZZ] + a * xij[ZZ] + b * xik[ZZ] + c * temp[ZZ];
+        /* 18 Flops */
+        /* TOTAL: 33 flops */
+    }
+
+    if (calculateVelocity == VSiteCalculateVelocity::Yes)
+    {
+        rvec vij = { 0 };
+        rvec vik = { 0 };
+        rvec_sub(vj, vi, vij);
+        rvec_sub(vk, vi, vik);
+
+        rvec temp1 = { 0 };
+        rvec temp2 = { 0 };
+        cprod(vij, xik, temp1);
+        cprod(xij, vik, temp2);
 
-    /* TOTAL: 33 flops */
+        v[XX] = vi[XX] + a * vij[XX] + b * vik[XX] + c * (temp1[XX] + temp2[XX]);
+        v[YY] = vi[YY] + a * vij[YY] + b * vik[YY] + c * (temp1[YY] + temp2[YY]);
+        v[ZZ] = vi[ZZ] + a * vij[ZZ] + b * vik[ZZ] + c * (temp1[ZZ] + temp2[ZZ]);
+    }
 }
 
+template<VSiteCalculatePosition calculatePosition, VSiteCalculateVelocity calculateVelocity>
 static void constr_vsite4FD(const rvec   xi,
                             const rvec   xj,
                             const rvec   xk,
@@ -478,7 +662,12 @@ static void constr_vsite4FD(const rvec   xi,
                             real         a,
                             real         b,
                             real         c,
-                            const t_pbc* pbc)
+                            const t_pbc* pbc,
+                            const rvec   vi,
+                            const rvec   vj,
+                            const rvec   vk,
+                            const rvec   vl,
+                            rvec         v)
 {
     rvec xij, xjk, xjl, temp;
     real d;
@@ -494,17 +683,41 @@ static void constr_vsite4FD(const rvec   xi,
     temp[ZZ] = xij[ZZ] + a * xjk[ZZ] + b * xjl[ZZ];
     /* 12 flops */
 
-    d = c * inverseNorm(temp);
+    const real invRm = inverseNorm(temp);
+    d                = c * invRm;
     /* 6 + 10 flops */
 
-    x[XX] = xi[XX] + d * temp[XX];
-    x[YY] = xi[YY] + d * temp[YY];
-    x[ZZ] = xi[ZZ] + d * temp[ZZ];
-    /* 6 Flops */
+    if (calculatePosition == VSiteCalculatePosition::Yes)
+    {
+        x[XX] = xi[XX] + d * temp[XX];
+        x[YY] = xi[YY] + d * temp[YY];
+        x[ZZ] = xi[ZZ] + d * temp[ZZ];
+        /* 6 Flops */
+        /* TOTAL: 43 flops */
+    }
+    if (calculateVelocity == VSiteCalculateVelocity::Yes)
+    {
+        rvec vij = { 0 };
+        rvec vjk = { 0 };
+        rvec vjl = { 0 };
+
+        rvec_sub(vj, vi, vij);
+        rvec_sub(vk, vj, vjk);
+        rvec_sub(vl, vj, vjl);
 
-    /* TOTAL: 43 flops */
+        rvec vm = { 0 };
+        vm[XX]  = vij[XX] + a * vjk[XX] + b * vjl[XX];
+        vm[YY]  = vij[YY] + a * vjk[YY] + b * vjl[YY];
+        vm[ZZ]  = vij[ZZ] + a * vjk[ZZ] + b * vjl[ZZ];
+
+        const real vmDotRm = iprod(vm, temp);
+        v[XX]              = vi[XX] + d * (vm[XX] - temp[XX] * vmDotRm * invRm * invRm);
+        v[YY]              = vi[YY] + d * (vm[YY] - temp[YY] * vmDotRm * invRm * invRm);
+        v[ZZ]              = vi[ZZ] + d * (vm[ZZ] - temp[ZZ] * vmDotRm * invRm * invRm);
+    }
 }
 
+template<VSiteCalculatePosition calculatePosition, VSiteCalculateVelocity calculateVelocity>
 static void constr_vsite4FDN(const rvec   xi,
                              const rvec   xj,
                              const rvec   xk,
@@ -513,7 +726,12 @@ static void constr_vsite4FDN(const rvec   xi,
                              real         a,
                              real         b,
                              real         c,
-                             const t_pbc* pbc)
+                             const t_pbc* pbc,
+                             const rvec   vi,
+                             const rvec   vj,
+                             const rvec   vk,
+                             const rvec   vl,
+                             rvec         v)
 {
     rvec xij, xik, xil, ra, rb, rja, rjb, rm;
     real d;
@@ -540,53 +758,121 @@ static void constr_vsite4FDN(const rvec   xi,
     cprod(rja, rjb, rm);
     /* 9 flops */
 
-    d = c * inverseNorm(rm);
+    const real invNormRm = inverseNorm(rm);
+    d                    = c * invNormRm;
     /* 5+5+1 flops */
 
-    x[XX] = xi[XX] + d * rm[XX];
-    x[YY] = xi[YY] + d * rm[YY];
-    x[ZZ] = xi[ZZ] + d * rm[ZZ];
-    /* 6 Flops */
+    if (calculatePosition == VSiteCalculatePosition::Yes)
+    {
+        x[XX] = xi[XX] + d * rm[XX];
+        x[YY] = xi[YY] + d * rm[YY];
+        x[ZZ] = xi[ZZ] + d * rm[ZZ];
+        /* 6 Flops */
+        /* TOTAL: 47 flops */
+    }
+
+    if (calculateVelocity == VSiteCalculateVelocity::Yes)
+    {
+        rvec vij = { 0 };
+        rvec vik = { 0 };
+        rvec vil = { 0 };
+        rvec_sub(vj, vi, vij);
+        rvec_sub(vk, vi, vik);
+        rvec_sub(vl, vi, vil);
+
+        rvec vja = { 0 };
+        rvec vjb = { 0 };
+
+        vja[XX] = a * vik[XX] - vij[XX];
+        vja[YY] = a * vik[YY] - vij[YY];
+        vja[ZZ] = a * vik[ZZ] - vij[ZZ];
+        vjb[XX] = b * vil[XX] - vij[XX];
+        vjb[YY] = b * vil[YY] - vij[YY];
+        vjb[ZZ] = b * vil[ZZ] - vij[ZZ];
+
+        rvec temp1 = { 0 };
+        rvec temp2 = { 0 };
+        cprod(vja, rjb, temp1);
+        cprod(rja, vjb, temp2);
 
-    /* TOTAL: 47 flops */
+        rvec vm = { 0 };
+        vm[XX]  = temp1[XX] + temp2[XX];
+        vm[YY]  = temp1[YY] + temp2[YY];
+        vm[ZZ]  = temp1[ZZ] + temp2[ZZ];
+
+        const real rmDotVm = iprod(rm, vm);
+        v[XX]              = vi[XX] + d * (vm[XX] - rm[XX] * rmDotVm * invNormRm * invNormRm);
+        v[YY]              = vi[YY] + d * (vm[YY] - rm[YY] * rmDotVm * invNormRm * invNormRm);
+        v[ZZ]              = vi[ZZ] + d * (vm[ZZ] - rm[ZZ] * rmDotVm * invNormRm * invNormRm);
+    }
 }
 
-static int constr_vsiten(const t_iatom* ia, ArrayRef<const t_iparams> ip, ArrayRef<RVec> x, const t_pbc* pbc)
+template<VSiteCalculatePosition calculatePosition, VSiteCalculateVelocity calculateVelocity>
+static int constr_vsiten(const t_iatom*            ia,
+                         ArrayRef<const t_iparams> ip,
+                         ArrayRef<RVec>            x,
+                         const t_pbc*              pbc,
+                         ArrayRef<RVec>            v)
 {
     rvec x1, dx;
     dvec dsum;
-    int  n3, av, ai;
     real a;
+    dvec dvsum = { 0 };
+    rvec v1    = { 0 };
 
-    n3 = 3 * ip[ia[0]].vsiten.n;
-    av = ia[1];
-    ai = ia[2];
+    const int n3 = 3 * ip[ia[0]].vsiten.n;
+    const int av = ia[1];
+    int       ai = ia[2];
     copy_rvec(x[ai], x1);
+    copy_rvec(v[ai], v1);
     clear_dvec(dsum);
     for (int i = 3; i < n3; i += 3)
     {
         ai = ia[i + 2];
         a  = ip[ia[i]].vsiten.a;
-        if (pbc)
+        if (calculatePosition == VSiteCalculatePosition::Yes)
         {
-            pbc_dx_aiuc(pbc, x[ai], x1, dx);
+            if (pbc)
+            {
+                pbc_dx_aiuc(pbc, x[ai], x1, dx);
+            }
+            else
+            {
+                rvec_sub(x[ai], x1, dx);
+            }
+            dsum[XX] += a * dx[XX];
+            dsum[YY] += a * dx[YY];
+            dsum[ZZ] += a * dx[ZZ];
+            /* 9 Flops */
         }
-        else
+        if (calculateVelocity == VSiteCalculateVelocity::Yes)
         {
-            rvec_sub(x[ai], x1, dx);
+            rvec_sub(v[ai], v1, dx);
+            dvsum[XX] += a * dx[XX];
+            dvsum[YY] += a * dx[YY];
+            dvsum[ZZ] += a * dx[ZZ];
+            /* 9 Flops */
         }
-        dsum[XX] += a * dx[XX];
-        dsum[YY] += a * dx[YY];
-        dsum[ZZ] += a * dx[ZZ];
-        /* 9 Flops */
     }
 
-    x[av][XX] = x1[XX] + dsum[XX];
-    x[av][YY] = x1[YY] + dsum[YY];
-    x[av][ZZ] = x1[ZZ] + dsum[ZZ];
+    if (calculatePosition == VSiteCalculatePosition::Yes)
+    {
+        x[av][XX] = x1[XX] + dsum[XX];
+        x[av][YY] = x1[YY] + dsum[YY];
+        x[av][ZZ] = x1[ZZ] + dsum[ZZ];
+    }
+
+    if (calculateVelocity == VSiteCalculateVelocity::Yes)
+    {
+        v[av][XX] = v1[XX] + dvsum[XX];
+        v[av][YY] = v1[YY] + dvsum[YY];
+        v[av][ZZ] = v1[ZZ] + dvsum[ZZ];
+    }
 
     return n3;
 }
+// End GCC 8 bug
+GCC_DIAGNOSTIC_RESET
 
 #endif // DOXYGEN
 
@@ -615,29 +901,49 @@ static PbcMode getPbcMode(const t_pbc* pbcPtr)
 
 /*! \brief Executes the vsite construction task for a single thread
  *
+ * \tparam        operation  Whether we are calculating positions, velocities, or both
  * \param[in,out] x   Coordinates to construct vsites for
- * \param[in]     dt  Time step, needed when v is not empty
- * \param[in,out] v   When not empty, velocities are generated for virtual sites
+ * \param[in,out] v   Velocities are generated for virtual sites if `operation` requires it
  * \param[in]     ip  Interaction parameters for all interaction, only vsite parameters are used
  * \param[in]     ilist  The interaction lists, only vsites are usesd
  * \param[in]     pbc_null  PBC struct, used for PBC distance calculations when !=nullptr
  */
+template<VSiteCalculatePosition calculatePosition, VSiteCalculateVelocity calculateVelocity>
 static void construct_vsites_thread(ArrayRef<RVec>                  x,
-                                    const real                      dt,
                                     ArrayRef<RVec>                  v,
                                     ArrayRef<const t_iparams>       ip,
                                     ArrayRef<const InteractionList> ilist,
                                     const t_pbc*                    pbc_null)
 {
-    real inv_dt;
-    if (!v.empty())
-    {
-        inv_dt = 1.0 / dt;
-    }
-    else
-    {
-        inv_dt = 1.0;
-    }
+    if (calculateVelocity == VSiteCalculateVelocity::Yes)
+    {
+        GMX_RELEASE_ASSERT(!v.empty(),
+                           "Can't calculate velocities without access to velocity vector.");
+    }
+
+    // Work around clang bug (unfixed as of Feb 2021)
+    // https://bugs.llvm.org/show_bug.cgi?id=35450
+    // clang-format off
+    CLANG_DIAGNOSTIC_IGNORE(-Wunused-lambda-capture)
+    // clang-format on
+    // GCC 8 falsely flags unused variables if constexpr prunes a code path, fixed in GCC 9
+    // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85827
+    // clang-format off
+    GCC_DIAGNOSTIC_IGNORE(-Wunused-but-set-parameter)
+    // clang-format on
+    // getVOrNull returns a velocity rvec if we need it, nullptr otherwise.
+    auto getVOrNull = [v](int idx) -> real* {
+        if (calculateVelocity == VSiteCalculateVelocity::Yes)
+        {
+            return v[idx].as_vec();
+        }
+        else
+        {
+            return nullptr;
+        }
+    };
+    GCC_DIAGNOSTIC_RESET
+    CLANG_DIAGNOSTIC_RESET
 
     const PbcMode pbcMode = getPbcMode(pbc_null);
     /* We need another pbc pointer, as with charge groups we switch per vsite */
@@ -674,39 +980,97 @@ static void construct_vsites_thread(ArrayRef<RVec>                  x,
                 real b1, c1;
                 switch (ftype)
                 {
-                    case F_VSITE1: constr_vsite1(x[ai], x[avsite]); break;
+                    case F_VSITE1:
+                        constr_vsite1<calculatePosition, calculateVelocity>(
+                                x[ai], x[avsite], getVOrNull(ai), getVOrNull(avsite));
+                        break;
                     case F_VSITE2:
                         aj = ia[3];
-                        constr_vsite2(x[ai], x[aj], x[avsite], a1, pbc_null2);
+                        constr_vsite2<calculatePosition, calculateVelocity>(x[ai],
+                                                                            x[aj],
+                                                                            x[avsite],
+                                                                            a1,
+                                                                            pbc_null2,
+                                                                            getVOrNull(ai),
+                                                                            getVOrNull(aj),
+                                                                            getVOrNull(avsite));
                         break;
                     case F_VSITE2FD:
                         aj = ia[3];
-                        constr_vsite2FD(x[ai], x[aj], x[avsite], a1, pbc_null2);
+                        constr_vsite2FD<calculatePosition, calculateVelocity>(x[ai],
+                                                                              x[aj],
+                                                                              x[avsite],
+                                                                              a1,
+                                                                              pbc_null2,
+                                                                              getVOrNull(ai),
+                                                                              getVOrNull(aj),
+                                                                              getVOrNull(avsite));
                         break;
                     case F_VSITE3:
                         aj = ia[3];
                         ak = ia[4];
                         b1 = ip[tp].vsite.b;
-                        constr_vsite3(x[ai], x[aj], x[ak], x[avsite], a1, b1, pbc_null2);
+                        constr_vsite3<calculatePosition, calculateVelocity>(x[ai],
+                                                                            x[aj],
+                                                                            x[ak],
+                                                                            x[avsite],
+                                                                            a1,
+                                                                            b1,
+                                                                            pbc_null2,
+                                                                            getVOrNull(ai),
+                                                                            getVOrNull(aj),
+                                                                            getVOrNull(ak),
+                                                                            getVOrNull(avsite));
                         break;
                     case F_VSITE3FD:
                         aj = ia[3];
                         ak = ia[4];
                         b1 = ip[tp].vsite.b;
-                        constr_vsite3FD(x[ai], x[aj], x[ak], x[avsite], a1, b1, pbc_null2);
+                        constr_vsite3FD<calculatePosition, calculateVelocity>(x[ai],
+                                                                              x[aj],
+                                                                              x[ak],
+                                                                              x[avsite],
+                                                                              a1,
+                                                                              b1,
+                                                                              pbc_null2,
+                                                                              getVOrNull(ai),
+                                                                              getVOrNull(aj),
+                                                                              getVOrNull(ak),
+                                                                              getVOrNull(avsite));
                         break;
                     case F_VSITE3FAD:
                         aj = ia[3];
                         ak = ia[4];
                         b1 = ip[tp].vsite.b;
-                        constr_vsite3FAD(x[ai], x[aj], x[ak], x[avsite], a1, b1, pbc_null2);
+                        constr_vsite3FAD<calculatePosition, calculateVelocity>(x[ai],
+                                                                               x[aj],
+                                                                               x[ak],
+                                                                               x[avsite],
+                                                                               a1,
+                                                                               b1,
+                                                                               pbc_null2,
+                                                                               getVOrNull(ai),
+                                                                               getVOrNull(aj),
+                                                                               getVOrNull(ak),
+                                                                               getVOrNull(avsite));
                         break;
                     case F_VSITE3OUT:
                         aj = ia[3];
                         ak = ia[4];
                         b1 = ip[tp].vsite.b;
                         c1 = ip[tp].vsite.c;
-                        constr_vsite3OUT(x[ai], x[aj], x[ak], x[avsite], a1, b1, c1, pbc_null2);
+                        constr_vsite3OUT<calculatePosition, calculateVelocity>(x[ai],
+                                                                               x[aj],
+                                                                               x[ak],
+                                                                               x[avsite],
+                                                                               a1,
+                                                                               b1,
+                                                                               c1,
+                                                                               pbc_null2,
+                                                                               getVOrNull(ai),
+                                                                               getVOrNull(aj),
+                                                                               getVOrNull(ak),
+                                                                               getVOrNull(avsite));
                         break;
                     case F_VSITE4FD:
                         aj = ia[3];
@@ -714,7 +1078,20 @@ static void construct_vsites_thread(ArrayRef<RVec>                  x,
                         al = ia[5];
                         b1 = ip[tp].vsite.b;
                         c1 = ip[tp].vsite.c;
-                        constr_vsite4FD(x[ai], x[aj], x[ak], x[al], x[avsite], a1, b1, c1, pbc_null2);
+                        constr_vsite4FD<calculatePosition, calculateVelocity>(x[ai],
+                                                                              x[aj],
+                                                                              x[ak],
+                                                                              x[al],
+                                                                              x[avsite],
+                                                                              a1,
+                                                                              b1,
+                                                                              c1,
+                                                                              pbc_null2,
+                                                                              getVOrNull(ai),
+                                                                              getVOrNull(aj),
+                                                                              getVOrNull(ak),
+                                                                              getVOrNull(al),
+                                                                              getVOrNull(avsite));
                         break;
                     case F_VSITE4FDN:
                         aj = ia[3];
@@ -722,9 +1099,24 @@ static void construct_vsites_thread(ArrayRef<RVec>                  x,
                         al = ia[5];
                         b1 = ip[tp].vsite.b;
                         c1 = ip[tp].vsite.c;
-                        constr_vsite4FDN(x[ai], x[aj], x[ak], x[al], x[avsite], a1, b1, c1, pbc_null2);
+                        constr_vsite4FDN<calculatePosition, calculateVelocity>(x[ai],
+                                                                               x[aj],
+                                                                               x[ak],
+                                                                               x[al],
+                                                                               x[avsite],
+                                                                               a1,
+                                                                               b1,
+                                                                               c1,
+                                                                               pbc_null2,
+                                                                               getVOrNull(ai),
+                                                                               getVOrNull(aj),
+                                                                               getVOrNull(ak),
+                                                                               getVOrNull(al),
+                                                                               getVOrNull(avsite));
+                        break;
+                    case F_VSITEN:
+                        inc = constr_vsiten<calculatePosition, calculateVelocity>(ia, ip, x, pbc_null2, v);
                         break;
-                    case F_VSITEN: inc = constr_vsiten(ia, ip, x, pbc_null2); break;
                     default:
                         gmx_fatal(FARGS, "No such vsite type %d in %s, line %d", ftype, __FILE__, __LINE__);
                 }
@@ -734,18 +1126,11 @@ static void construct_vsites_thread(ArrayRef<RVec>                  x,
                     /* Keep the vsite in the same periodic image as before */
                     rvec dx;
                     int  ishift = pbc_dx_aiuc(pbc_null, x[avsite], xv, dx);
-                    if (ishift != CENTRAL)
+                    if (ishift != c_centralShiftIndex)
                     {
                         rvec_add(xv, dx, x[avsite]);
                     }
                 }
-                if (!v.empty())
-                {
-                    /* Calculate velocity of vsite... */
-                    rvec vv;
-                    rvec_sub(x[avsite], xv, vv);
-                    svmul(inv_dt, vv, v[avsite]);
-                }
 
                 /* Increment loop variables */
                 i += inc;
@@ -759,16 +1144,15 @@ static void construct_vsites_thread(ArrayRef<RVec>                  x,
  *
  * \param[in]     threadingInfo  Used to divide work over threads when != nullptr
  * \param[in,out] x   Coordinates to construct vsites for
- * \param[in]     dt  Time step, needed when v is not empty
  * \param[in,out] v   When not empty, velocities are generated for virtual sites
  * \param[in]     ip  Interaction parameters for all interaction, only vsite parameters are used
  * \param[in]     ilist  The interaction lists, only vsites are usesd
  * \param[in]     domainInfo  Information about PBC and DD
  * \param[in]     box  Used for PBC when PBC is set in domainInfo
  */
+template<VSiteCalculatePosition calculatePosition, VSiteCalculateVelocity calculateVelocity>
 static void construct_vsites(const ThreadingInfo*            threadingInfo,
                              ArrayRef<RVec>                  x,
-                             real                            dt,
                              ArrayRef<RVec>                  v,
                              ArrayRef<const t_iparams>       ip,
                              ArrayRef<const InteractionList> ilist,
@@ -791,8 +1175,8 @@ static void construct_vsites(const ThreadingInfo*            threadingInfo,
          */
         ivec null_ivec;
         clear_ivec(null_ivec);
-        pbc_null = set_pbc_dd(&pbc, domainInfo.pbcType_,
-                              useDomdec ? domainInfo.domdec_->numCells : null_ivec, FALSE, box);
+        pbc_null = set_pbc_dd(
+                &pbc, domainInfo.pbcType_, useDomdec ? domainInfo.domdec_->numCells : null_ivec, FALSE, box);
     }
     else
     {
@@ -801,12 +1185,20 @@ static void construct_vsites(const ThreadingInfo*            threadingInfo,
 
     if (useDomdec)
     {
-        dd_move_x_vsites(*domainInfo.domdec_, box, as_rvec_array(x.data()));
+        if (calculateVelocity == VSiteCalculateVelocity::Yes)
+        {
+            dd_move_x_and_v_vsites(
+                    *domainInfo.domdec_, box, as_rvec_array(x.data()), as_rvec_array(v.data()));
+        }
+        else
+        {
+            dd_move_x_vsites(*domainInfo.domdec_, box, as_rvec_array(x.data()));
+        }
     }
 
     if (threadingInfo == nullptr || threadingInfo->numThreads() == 1)
     {
-        construct_vsites_thread(x, dt, v, ip, ilist, pbc_null);
+        construct_vsites_thread<calculatePosition, calculateVelocity>(x, v, ip, ilist, pbc_null);
     }
     else
     {
@@ -819,31 +1211,52 @@ static void construct_vsites(const ThreadingInfo*            threadingInfo,
                 GMX_ASSERT(tData.rangeStart >= 0,
                            "The thread data should be initialized before calling construct_vsites");
 
-                construct_vsites_thread(x, dt, v, ip, tData.ilist, pbc_null);
+                construct_vsites_thread<calculatePosition, calculateVelocity>(
+                        x, v, ip, tData.ilist, pbc_null);
                 if (tData.useInterdependentTask)
                 {
                     /* Here we don't need a barrier (unlike the spreading),
                      * since both tasks only construct vsites from particles,
                      * or local vsites, not from non-local vsites.
                      */
-                    construct_vsites_thread(x, dt, v, ip, tData.idTask.ilist, pbc_null);
+                    construct_vsites_thread<calculatePosition, calculateVelocity>(
+                            x, v, ip, tData.idTask.ilist, pbc_null);
                 }
             }
             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
         }
         /* Now we can construct the vsites that might depend on other vsites */
-        construct_vsites_thread(x, dt, v, ip, threadingInfo->threadDataNonLocalDependent().ilist, pbc_null);
+        construct_vsites_thread<calculatePosition, calculateVelocity>(
+                x, v, ip, threadingInfo->threadDataNonLocalDependent().ilist, pbc_null);
     }
 }
 
-void VirtualSitesHandler::Impl::construct(ArrayRef<RVec> x, real dt, ArrayRef<RVec> v, const matrix box) const
+void VirtualSitesHandler::Impl::construct(ArrayRef<RVec> x,
+                                          ArrayRef<RVec> v,
+                                          const matrix   box,
+                                          VSiteOperation operation) const
 {
-    construct_vsites(&threadingInfo_, x, dt, v, iparams_, ilists_, domainInfo_, box);
+    switch (operation)
+    {
+        case VSiteOperation::Positions:
+            construct_vsites<VSiteCalculatePosition::Yes, VSiteCalculateVelocity::No>(
+                    &threadingInfo_, x, v, iparams_, ilists_, domainInfo_, box);
+            break;
+        case VSiteOperation::Velocities:
+            construct_vsites<VSiteCalculatePosition::No, VSiteCalculateVelocity::Yes>(
+                    &threadingInfo_, x, v, iparams_, ilists_, domainInfo_, box);
+            break;
+        case VSiteOperation::PositionsAndVelocities:
+            construct_vsites<VSiteCalculatePosition::Yes, VSiteCalculateVelocity::Yes>(
+                    &threadingInfo_, x, v, iparams_, ilists_, domainInfo_, box);
+            break;
+        default: gmx_fatal(FARGS, "Unknown virtual site operation");
+    }
 }
 
-void VirtualSitesHandler::construct(ArrayRef<RVec> x, real dt, ArrayRef<RVec> v, const matrix box) const
+void VirtualSitesHandler::construct(ArrayRef<RVec> x, ArrayRef<RVec> v, const matrix box, VSiteOperation operation) const
 {
-    impl_->construct(x, dt, v, box);
+    impl_->construct(x, v, box, operation);
 }
 
 void constructVirtualSites(ArrayRef<RVec> x, ArrayRef<const t_iparams> ip, ArrayRef<const InteractionList> ilist)
@@ -851,7 +1264,8 @@ void constructVirtualSites(ArrayRef<RVec> x, ArrayRef<const t_iparams> ip, Array
 {
     // No PBC, no DD
     const DomainInfo domainInfo;
-    construct_vsites(nullptr, x, 0, {}, ip, ilist, domainInfo, nullptr);
+    construct_vsites<VSiteCalculatePosition::Yes, VSiteCalculateVelocity::No>(
+            nullptr, x, {}, ip, ilist, domainInfo, nullptr);
 }
 
 #ifndef DOXYGEN
@@ -899,14 +1313,14 @@ static void spread_vsite2(const t_iatom        ia[],
         }
         else
         {
-            siv = CENTRAL;
-            sij = CENTRAL;
+            siv = c_centralShiftIndex;
+            sij = c_centralShiftIndex;
         }
 
-        if (siv != CENTRAL || sij != CENTRAL)
+        if (siv != c_centralShiftIndex || sij != c_centralShiftIndex)
         {
             rvec_inc(fshift[siv], f[av]);
-            rvec_dec(fshift[CENTRAL], fi);
+            rvec_dec(fshift[c_centralShiftIndex], fi);
             rvec_dec(fshift[sij], fj);
         }
     }
@@ -929,8 +1343,8 @@ void constructVirtualSitesGlobal(const gmx_mtop_t& mtop, gmx::ArrayRef<gmx::RVec
             int atomOffset = mtop.moleculeBlockIndices[mb].globalAtomStart;
             for (int mol = 0; mol < molb.nmol; mol++)
             {
-                constructVirtualSites(x.subArray(atomOffset, molt.atoms.nr), mtop.ffparams.iparams,
-                                      molt.ilist);
+                constructVirtualSites(
+                        x.subArray(atomOffset, molt.atoms.nr), mtop.ffparams.iparams, molt.ilist);
                 atomOffset += molt.atoms.nr;
             }
         }
@@ -989,15 +1403,15 @@ static void spread_vsite2FD(const t_iatom        ia[],
         }
         else
         {
-            svi = CENTRAL;
+            svi = c_centralShiftIndex;
         }
 
-        if (svi != CENTRAL || sji != CENTRAL)
+        if (svi != c_centralShiftIndex || sji != c_centralShiftIndex)
         {
             rvec_dec(fshift[svi], fv);
-            fshift[CENTRAL][XX] += fv[XX] - fj[XX];
-            fshift[CENTRAL][YY] += fv[YY] - fj[YY];
-            fshift[CENTRAL][ZZ] += fv[ZZ] - fj[ZZ];
+            fshift[c_centralShiftIndex][XX] += fv[XX] - fj[XX];
+            fshift[c_centralShiftIndex][YY] += fv[YY] - fj[YY];
+            fshift[c_centralShiftIndex][ZZ] += fv[ZZ] - fj[ZZ];
             fshift[sji][XX] += fj[XX];
             fshift[sji][YY] += fj[YY];
             fshift[sji][ZZ] += fj[ZZ];
@@ -1071,15 +1485,15 @@ static void spread_vsite3(const t_iatom        ia[],
         }
         else
         {
-            siv = CENTRAL;
-            sij = CENTRAL;
-            sik = CENTRAL;
+            siv = c_centralShiftIndex;
+            sij = c_centralShiftIndex;
+            sik = c_centralShiftIndex;
         }
 
-        if (siv != CENTRAL || sij != CENTRAL || sik != CENTRAL)
+        if (siv != c_centralShiftIndex || sij != c_centralShiftIndex || sik != c_centralShiftIndex)
         {
             rvec_inc(fshift[siv], f[av]);
-            rvec_dec(fshift[CENTRAL], fi);
+            rvec_dec(fshift[c_centralShiftIndex], fi);
             rvec_dec(fshift[sij], fj);
             rvec_dec(fshift[sik], fk);
         }
@@ -1154,15 +1568,15 @@ static void spread_vsite3FD(const t_iatom        ia[],
         }
         else
         {
-            svi = CENTRAL;
+            svi = c_centralShiftIndex;
         }
 
-        if (svi != CENTRAL || sji != CENTRAL || skj != CENTRAL)
+        if (svi != c_centralShiftIndex || sji != c_centralShiftIndex || skj != c_centralShiftIndex)
         {
             rvec_dec(fshift[svi], fv);
-            fshift[CENTRAL][XX] += fv[XX] - (1 + a) * temp[XX];
-            fshift[CENTRAL][YY] += fv[YY] - (1 + a) * temp[YY];
-            fshift[CENTRAL][ZZ] += fv[ZZ] - (1 + a) * temp[ZZ];
+            fshift[c_centralShiftIndex][XX] += fv[XX] - (1 + a) * temp[XX];
+            fshift[c_centralShiftIndex][YY] += fv[YY] - (1 + a) * temp[YY];
+            fshift[c_centralShiftIndex][ZZ] += fv[ZZ] - (1 + a) * temp[ZZ];
             fshift[sji][XX] += temp[XX];
             fshift[sji][YY] += temp[YY];
             fshift[sji][ZZ] += temp[ZZ];
@@ -1276,15 +1690,15 @@ static void spread_vsite3FAD(const t_iatom        ia[],
         }
         else
         {
-            svi = CENTRAL;
+            svi = c_centralShiftIndex;
         }
 
-        if (svi != CENTRAL || sji != CENTRAL || skj != CENTRAL)
+        if (svi != c_centralShiftIndex || sji != c_centralShiftIndex || skj != c_centralShiftIndex)
         {
             rvec_dec(fshift[svi], fv);
-            fshift[CENTRAL][XX] += fv[XX] - f1[XX] - (1 - c1) * f2[XX] + f3[XX];
-            fshift[CENTRAL][YY] += fv[YY] - f1[YY] - (1 - c1) * f2[YY] + f3[YY];
-            fshift[CENTRAL][ZZ] += fv[ZZ] - f1[ZZ] - (1 - c1) * f2[ZZ] + f3[ZZ];
+            fshift[c_centralShiftIndex][XX] += fv[XX] - f1[XX] - (1 - c1) * f2[XX] + f3[XX];
+            fshift[c_centralShiftIndex][YY] += fv[YY] - f1[YY] - (1 - c1) * f2[YY] + f3[YY];
+            fshift[c_centralShiftIndex][ZZ] += fv[ZZ] - f1[ZZ] - (1 - c1) * f2[ZZ] + f3[ZZ];
             fshift[sji][XX] += f1[XX] - c1 * f2[XX] - f3[XX];
             fshift[sji][YY] += f1[YY] - c1 * f2[YY] - f3[YY];
             fshift[sji][ZZ] += f1[ZZ] - c1 * f2[ZZ] - f3[ZZ];
@@ -1370,15 +1784,15 @@ static void spread_vsite3OUT(const t_iatom        ia[],
         }
         else
         {
-            svi = CENTRAL;
+            svi = c_centralShiftIndex;
         }
 
-        if (svi != CENTRAL || sji != CENTRAL || ski != CENTRAL)
+        if (svi != c_centralShiftIndex || sji != c_centralShiftIndex || ski != c_centralShiftIndex)
         {
             rvec_dec(fshift[svi], fv);
-            fshift[CENTRAL][XX] += fv[XX] - fj[XX] - fk[XX];
-            fshift[CENTRAL][YY] += fv[YY] - fj[YY] - fk[YY];
-            fshift[CENTRAL][ZZ] += fv[ZZ] - fj[ZZ] - fk[ZZ];
+            fshift[c_centralShiftIndex][XX] += fv[XX] - fj[XX] - fk[XX];
+            fshift[c_centralShiftIndex][YY] += fv[YY] - fj[YY] - fk[YY];
+            fshift[c_centralShiftIndex][ZZ] += fv[ZZ] - fj[ZZ] - fk[ZZ];
             rvec_inc(fshift[sji], fj);
             rvec_inc(fshift[ski], fk);
         }
@@ -1472,15 +1886,16 @@ static void spread_vsite4FD(const t_iatom        ia[],
         }
         else
         {
-            svi = CENTRAL;
+            svi = c_centralShiftIndex;
         }
 
-        if (svi != CENTRAL || sji != CENTRAL || skj != CENTRAL || slj != CENTRAL)
+        if (svi != c_centralShiftIndex || sji != c_centralShiftIndex || skj != c_centralShiftIndex
+            || slj != c_centralShiftIndex)
         {
             rvec_dec(fshift[svi], fv);
             for (m = 0; m < DIM; m++)
             {
-                fshift[CENTRAL][m] += fv[m] - (1 + a + b) * temp[m];
+                fshift[c_centralShiftIndex][m] += fv[m] - (1 + a + b) * temp[m];
                 fshift[sji][m] += temp[m];
                 fshift[skj][m] += a * temp[m];
                 fshift[slj][m] += b * temp[m];
@@ -1631,15 +2046,16 @@ static void spread_vsite4FDN(const t_iatom        ia[],
         }
         else
         {
-            svi = CENTRAL;
+            svi = c_centralShiftIndex;
         }
 
-        if (svi != CENTRAL || sij != CENTRAL || sik != CENTRAL || sil != CENTRAL)
+        if (svi != c_centralShiftIndex || sij != c_centralShiftIndex || sik != c_centralShiftIndex
+            || sil != c_centralShiftIndex)
         {
             rvec_dec(fshift[svi], fv);
-            fshift[CENTRAL][XX] += fv[XX] - fj[XX] - fk[XX] - fl[XX];
-            fshift[CENTRAL][YY] += fv[YY] - fj[YY] - fk[YY] - fl[YY];
-            fshift[CENTRAL][ZZ] += fv[ZZ] - fj[ZZ] - fk[ZZ] - fl[ZZ];
+            fshift[c_centralShiftIndex][XX] += fv[XX] - fj[XX] - fk[XX] - fl[XX];
+            fshift[c_centralShiftIndex][YY] += fv[YY] - fj[YY] - fk[YY] - fl[YY];
+            fshift[c_centralShiftIndex][ZZ] += fv[ZZ] - fj[ZZ] - fk[ZZ] - fl[ZZ];
             rvec_inc(fshift[sij], fj);
             rvec_inc(fshift[sik], fk);
             rvec_inc(fshift[sil], fl);
@@ -1691,16 +2107,16 @@ static int spread_vsiten(const t_iatom             ia[],
         }
         else
         {
-            siv = CENTRAL;
+            siv = c_centralShiftIndex;
         }
         a = ip[ia[i]].vsiten.a;
         svmul(a, f[av], fi);
         rvec_inc(f[ai], fi);
 
-        if (virialHandling == VirialHandling::Pbc && siv != CENTRAL)
+        if (virialHandling == VirialHandling::Pbc && siv != c_centralShiftIndex)
         {
             rvec_inc(fshift[siv], fi);
-            rvec_dec(fshift[CENTRAL], fi);
+            rvec_dec(fshift[c_centralShiftIndex], fi);
         }
         /* 6 Flops */
     }
@@ -1874,7 +2290,7 @@ void VirtualSitesHandler::Impl::spreadForces(ArrayRef<const RVec> x,
                                              const matrix         box,
                                              gmx_wallcycle*       wcycle)
 {
-    wallcycle_start(wcycle, ewcVSITESPREAD);
+    wallcycle_start(wcycle, WallCycleCounter::VsiteSpread);
 
     const bool useDomdec = domainInfo_.useDomdec();
 
@@ -1885,8 +2301,8 @@ void VirtualSitesHandler::Impl::spreadForces(ArrayRef<const RVec> x,
         /* This is wasting some CPU time as we now do this multiple times
          * per MD step.
          */
-        pbc_null = set_pbc_dd(&pbc, domainInfo_.pbcType_,
-                              useDomdec ? domainInfo_.domdec_->numCells : nullptr, FALSE, box);
+        pbc_null = set_pbc_dd(
+                &pbc, domainInfo_.pbcType_, useDomdec ? domainInfo_.domdec_->numCells : nullptr, FALSE, box);
     }
     else
     {
@@ -1920,8 +2336,15 @@ void VirtualSitesHandler::Impl::spreadForces(ArrayRef<const RVec> x,
     {
         /* First spread the vsites that might depend on non-local vsites */
         auto& nlDependentVSites = threadingInfo_.threadDataNonLocalDependent();
-        spreadForceWrapper(x, f, virialHandling, fshift, nlDependentVSites.dxdf, true, iparams_,
-                           nlDependentVSites.ilist, pbc_null);
+        spreadForceWrapper(x,
+                           f,
+                           virialHandling,
+                           fshift,
+                           nlDependentVSites.dxdf,
+                           true,
+                           iparams_,
+                           nlDependentVSites.ilist,
+                           pbc_null);
 
 #pragma omp parallel num_threads(numThreads)
         {
@@ -1941,7 +2364,7 @@ void VirtualSitesHandler::Impl::spreadForces(ArrayRef<const RVec> x,
                     {
                         fshift_t = tData.fshift;
 
-                        for (int i = 0; i < SHIFTS; i++)
+                        for (int i = 0; i < c_numShiftVectors; i++)
                         {
                             clear_rvec(fshift_t[i]);
                         }
@@ -1966,8 +2389,15 @@ void VirtualSitesHandler::Impl::spreadForces(ArrayRef<const RVec> x,
                     {
                         copy_rvec(f[idTask->vsite[i]], idTask->force[idTask->vsite[i]]);
                     }
-                    spreadForceWrapper(x, idTask->force, virialHandling, fshift_t, tData.dxdf, true,
-                                       iparams_, tData.idTask.ilist, pbc_null);
+                    spreadForceWrapper(x,
+                                       idTask->force,
+                                       virialHandling,
+                                       fshift_t,
+                                       tData.dxdf,
+                                       true,
+                                       iparams_,
+                                       tData.idTask.ilist,
+                                       pbc_null);
 
                     /* We need a barrier before reducing forces below
                      * that have been produced by a different thread above.
@@ -2003,8 +2433,8 @@ void VirtualSitesHandler::Impl::spreadForces(ArrayRef<const RVec> x,
                 }
 
                 /* Spread the vsites that spread locally only */
-                spreadForceWrapper(x, f, virialHandling, fshift_t, tData.dxdf, false, iparams_,
-                                   tData.ilist, pbc_null);
+                spreadForceWrapper(
+                        x, f, virialHandling, fshift_t, tData.dxdf, false, iparams_, tData.ilist, pbc_null);
             }
             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
         }
@@ -2013,7 +2443,7 @@ void VirtualSitesHandler::Impl::spreadForces(ArrayRef<const RVec> x,
         {
             for (int th = 1; th < numThreads; th++)
             {
-                for (int i = 0; i < SHIFTS; i++)
+                for (int i = 0; i < c_numShiftVectors; i++)
                 {
                     rvec_inc(fshift[i], threadingInfo_.threadData(th).fshift[i]);
                 }
@@ -2054,7 +2484,7 @@ void VirtualSitesHandler::Impl::spreadForces(ArrayRef<const RVec> x,
     inc_nrnb(nrnb, eNR_VSITE4FDN, vsite_count(ilists_, F_VSITE4FDN));
     inc_nrnb(nrnb, eNR_VSITEN, vsite_count(ilists_, F_VSITEN));
 
-    wallcycle_stop(wcycle, ewcVSITESPREAD);
+    wallcycle_stop(wcycle, WallCycleCounter::VsiteSpread);
 }
 
 /*! \brief Returns the an array with group indices for each atom
@@ -2107,7 +2537,7 @@ void VirtualSitesHandler::spreadForces(ArrayRef<const RVec> x,
 }
 
 int countInterUpdategroupVsites(const gmx_mtop_t&                           mtop,
-                                gmx::ArrayRef<const gmx::RangePartitioning> updateGroupingPerMoleculetype)
+                                gmx::ArrayRef<const gmx::RangePartitioning> updateGroupingsPerMoleculeType)
 {
     int n_intercg_vsite = 0;
     for (const gmx_molblock_t& molb : mtop.molblock)
@@ -2115,9 +2545,9 @@ int countInterUpdategroupVsites(const gmx_mtop_t&                           mtop
         const gmx_moltype_t& molt = mtop.moltype[molb.type];
 
         std::vector<int> atomToGroup;
-        if (!updateGroupingPerMoleculetype.empty())
+        if (!updateGroupingsPerMoleculeType.empty())
         {
-            atomToGroup = makeAtomToGroupMapping(updateGroupingPerMoleculetype[molb.type]);
+            atomToGroup = makeAtomToGroupMapping(updateGroupingsPerMoleculeType[molb.type]);
         }
         for (int ftype = c_ftypeVsiteStart; ftype < c_ftypeVsiteEnd; ftype++)
         {
@@ -2151,7 +2581,8 @@ int countInterUpdategroupVsites(const gmx_mtop_t&                           mtop
 
 std::unique_ptr<VirtualSitesHandler> makeVirtualSitesHandler(const gmx_mtop_t& mtop,
                                                              const t_commrec*  cr,
-                                                             PbcType           pbcType)
+                                                             PbcType           pbcType,
+                                                             ArrayRef<const RangePartitioning> updateGroupingPerMoleculeType)
 {
     GMX_RELEASE_ASSERT(cr != nullptr, "We need a valid commrec");
 
@@ -2166,7 +2597,7 @@ std::unique_ptr<VirtualSitesHandler> makeVirtualSitesHandler(const gmx_mtop_t& m
             GMX_ASSERT(ftype >= c_ftypeVsiteStart && ftype < c_ftypeVsiteEnd,
                        "c_ftypeVsiteStart and/or c_ftypeVsiteEnd do not have correct values");
 
-            nvsite += gmx_mtop_ftype_count(&mtop, ftype);
+            nvsite += gmx_mtop_ftype_count(mtop, ftype);
         }
         else
         {
@@ -2180,10 +2611,10 @@ std::unique_ptr<VirtualSitesHandler> makeVirtualSitesHandler(const gmx_mtop_t& m
         return vsite;
     }
 
-    return std::make_unique<VirtualSitesHandler>(mtop, cr->dd, pbcType);
+    return std::make_unique<VirtualSitesHandler>(mtop, cr->dd, pbcType, updateGroupingPerMoleculeType);
 }
 
-ThreadingInfo::ThreadingInfo() : numThreads_(gmx_omp_nthreads_get(emntVSITE))
+ThreadingInfo::ThreadingInfo() : numThreads_(gmx_omp_nthreads_get(ModuleMultiThread::VirtualSite))
 {
     if (numThreads_ > 1)
     {
@@ -2209,27 +2640,21 @@ ThreadingInfo::ThreadingInfo() : numThreads_(gmx_omp_nthreads_get(emntVSITE))
     }
 }
 
-//! Returns the number of inter update-group vsites
-static int getNumInterUpdategroupVsites(const gmx_mtop_t& mtop, const gmx_domdec_t* domdec)
-{
-    gmx::ArrayRef<const gmx::RangePartitioning> updateGroupingPerMoleculetype;
-    if (domdec)
-    {
-        updateGroupingPerMoleculetype = getUpdateGroupingPerMoleculetype(*domdec);
-    }
-
-    return countInterUpdategroupVsites(mtop, updateGroupingPerMoleculetype);
-}
-
-VirtualSitesHandler::Impl::Impl(const gmx_mtop_t& mtop, gmx_domdec_t* domdec, const PbcType pbcType) :
-    numInterUpdategroupVirtualSites_(getNumInterUpdategroupVsites(mtop, domdec)),
+VirtualSitesHandler::Impl::Impl(const gmx_mtop_t&                       mtop,
+                                gmx_domdec_t*                           domdec,
+                                const PbcType                           pbcType,
+                                const ArrayRef<const RangePartitioning> updateGroupingPerMoleculeType) :
+    numInterUpdategroupVirtualSites_(countInterUpdategroupVsites(mtop, updateGroupingPerMoleculeType)),
     domainInfo_({ pbcType, pbcType != PbcType::No && numInterUpdategroupVirtualSites_ > 0, domdec }),
     iparams_(mtop.ffparams.iparams)
 {
 }
 
-VirtualSitesHandler::VirtualSitesHandler(const gmx_mtop_t& mtop, gmx_domdec_t* domdec, const PbcType pbcType) :
-    impl_(new Impl(mtop, domdec, pbcType))
+VirtualSitesHandler::VirtualSitesHandler(const gmx_mtop_t&                       mtop,
+                                         gmx_domdec_t*                           domdec,
+                                         const PbcType                           pbcType,
+                                         const ArrayRef<const RangePartitioning> updateGroupingPerMoleculeType) :
+    impl_(new Impl(mtop, domdec, pbcType, updateGroupingPerMoleculeType))
 {
 }
 
@@ -2265,7 +2690,7 @@ static void assignVsitesToThread(VsiteThread*                    tData,
                                  gmx::ArrayRef<int>              taskIndex,
                                  ArrayRef<const InteractionList> ilist,
                                  ArrayRef<const t_iparams>       ip,
-                                 const unsigned short*           ptype)
+                                 ArrayRef<const ParticleType>    ptype)
 {
     for (int ftype = c_ftypeVsiteStart; ftype < c_ftypeVsiteEnd; ftype++)
     {
@@ -2300,7 +2725,7 @@ static void assignVsitesToThread(VsiteThread*                    tData,
                     /* Do a range check to avoid a harmless race on taskIndex */
                     if (iat[j] < tData->rangeStart || iat[j] >= tData->rangeEnd || taskIndex[iat[j]] != thread)
                     {
-                        if (!tData->useInterdependentTask || ptype[iat[j]] == eptVSite)
+                        if (!tData->useInterdependentTask || ptype[iat[j]] == ParticleType::VSite)
                         {
                             /* At least one constructing atom is a vsite
                              * that is not assigned to the same thread.
@@ -2330,7 +2755,7 @@ static void assignVsitesToThread(VsiteThread*                    tData,
                     /* Do a range check to avoid a harmless race on taskIndex */
                     if (iat[j] < tData->rangeStart || iat[j] >= tData->rangeEnd || taskIndex[iat[j]] != thread)
                     {
-                        GMX_ASSERT(ptype[iat[j]] != eptVSite,
+                        GMX_ASSERT(ptype[iat[j]] != ParticleType::VSite,
                                    "A vsite to be assigned in assignVsitesToThread has a vsite as "
                                    "a constructing atom that does not belong to our task, such "
                                    "vsites should be assigned to the single 'master' task");
@@ -2424,7 +2849,9 @@ static void assignVsitesToSingleTask(VsiteThread*                    tData,
 
 void ThreadingInfo::setVirtualSites(ArrayRef<const InteractionList> ilists,
                                     ArrayRef<const t_iparams>       iparams,
-                                    const t_mdatoms&                mdatoms,
+                                    const int                       numAtoms,
+                                    const int                       homenr,
+                                    ArrayRef<const ParticleType>    ptype,
                                     const bool                      useDomdec)
 {
     if (numThreads_ <= 1)
@@ -2497,20 +2924,23 @@ void ThreadingInfo::setVirtualSites(ArrayRef<const InteractionList> ilists,
          * When assigning vsites to threads, we should take care that the last
          * threads also covers the non-local range.
          */
-        vsite_atom_range = mdatoms.nr;
-        natperthread     = (mdatoms.homenr + numThreads_ - 1) / numThreads_;
+        vsite_atom_range = numAtoms;
+        natperthread     = (homenr + numThreads_ - 1) / numThreads_;
     }
 
     if (debug)
     {
-        fprintf(debug, "virtual site thread dist: natoms %d, range %d, natperthread %d\n",
-                mdatoms.nr, vsite_atom_range, natperthread);
+        fprintf(debug,
+                "virtual site thread dist: natoms %d, range %d, natperthread %d\n",
+                numAtoms,
+                vsite_atom_range,
+                natperthread);
     }
 
     /* To simplify the vsite assignment, we make an index which tells us
      * to which task particles, both non-vsites and vsites, are assigned.
      */
-    taskIndex_.resize(mdatoms.nr);
+    taskIndex_.resize(numAtoms);
 
     /* Initialize the task index array. Here we assign the non-vsite
      * particles to task=thread, so we easily figure out if vsites
@@ -2518,9 +2948,9 @@ void ThreadingInfo::setVirtualSites(ArrayRef<const InteractionList> ilists,
      */
     {
         int thread = 0;
-        for (int i = 0; i < mdatoms.nr; i++)
+        for (int i = 0; i < numAtoms; i++)
         {
-            if (mdatoms.ptype[i] == eptVSite)
+            if (ptype[i] == ParticleType::VSite)
             {
                 /* vsites are not assigned to a task yet */
                 taskIndex_[i] = -1;
@@ -2599,10 +3029,10 @@ void ThreadingInfo::setVirtualSites(ArrayRef<const InteractionList> ilists,
             else
             {
                 /* The last thread should cover up to the end of the range */
-                tData.rangeEnd = mdatoms.nr;
+                tData.rangeEnd = numAtoms;
             }
-            assignVsitesToThread(&tData, thread, numThreads_, natperthread, taskIndex_, ilists,
-                                 iparams, mdatoms.ptype);
+            assignVsitesToThread(
+                    &tData, thread, numThreads_, natperthread, taskIndex_, ilists, iparams, ptype);
 
             if (tData.useInterdependentTask)
             {
@@ -2644,7 +3074,8 @@ void ThreadingInfo::setVirtualSites(ArrayRef<const InteractionList> ilists,
 
     if (debug && numThreads_ > 1)
     {
-        fprintf(debug, "virtual site useInterdependentTask %d, nuse:\n",
+        fprintf(debug,
+                "virtual site useInterdependentTask %d, nuse:\n",
                 static_cast<int>(tData_[0]->useInterdependentTask));
         for (int th = 0; th < numThreads_ + 1; th++)
         {
@@ -2659,7 +3090,9 @@ void ThreadingInfo::setVirtualSites(ArrayRef<const InteractionList> ilists,
                 fprintf(debug, "%-20s thread dist:", interaction_function[ftype].longname);
                 for (int th = 0; th < numThreads_ + 1; th++)
                 {
-                    fprintf(debug, " %4d %4d ", tData_[th]->ilist[ftype].size(),
+                    fprintf(debug,
+                            " %4d %4d ",
+                            tData_[th]->ilist[ftype].size(),
                             tData_[th]->idTask.ilist[ftype].size());
                 }
                 fprintf(debug, "\n");
@@ -2681,16 +3114,21 @@ void ThreadingInfo::setVirtualSites(ArrayRef<const InteractionList> ilists,
 }
 
 void VirtualSitesHandler::Impl::setVirtualSites(ArrayRef<const InteractionList> ilists,
-                                                const t_mdatoms&                mdatoms)
+                                                const int                       numAtoms,
+                                                const int                       homenr,
+                                                ArrayRef<const ParticleType>    ptype)
 {
     ilists_ = ilists;
 
-    threadingInfo_.setVirtualSites(ilists, iparams_, mdatoms, domainInfo_.useDomdec());
+    threadingInfo_.setVirtualSites(ilists, iparams_, numAtoms, homenr, ptype, domainInfo_.useDomdec());
 }
 
-void VirtualSitesHandler::setVirtualSites(ArrayRef<const InteractionList> ilists, const t_mdatoms& mdatoms)
+void VirtualSitesHandler::setVirtualSites(ArrayRef<const InteractionList> ilists,
+                                          const int                       numAtoms,
+                                          const int                       homenr,
+                                          ArrayRef<const ParticleType>    ptype)
 {
-    impl_->setVirtualSites(ilists, mdatoms);
+    impl_->setVirtualSites(ilists, numAtoms, homenr, ptype);
 }
 
 } // namespace gmx
index ae7c932b5e5caf390dccc20acd6cc96d107eeccf..0606203ad50e606a3212a26fc2c67a8a77e0f285 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 The GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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"
 #include "gromacs/topology/idef.h"
-#include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/real.h"
 
 struct gmx_domdec_t;
 struct gmx_mtop_t;
 struct t_commrec;
 struct InteractionList;
-struct t_mdatoms;
 struct t_nrnb;
 struct gmx_wallcycle;
 enum class PbcType : int;
+enum class ParticleType : int;
 
 namespace gmx
 {
 class RangePartitioning;
+template<typename T>
+class ArrayRef;
 
 /*! \brief The start value of the vsite indices in the ftype enum
  *
@@ -81,6 +80,15 @@ static constexpr int c_ftypeVsiteEnd = F_VSITEN + 1;
 //! Type for storing PBC atom information for all vsite types in the system
 typedef std::array<std::vector<int>, c_ftypeVsiteEnd - c_ftypeVsiteStart> VsitePbc;
 
+//! Whether we calculate vsite positions, velocities, or both
+enum class VSiteOperation
+{
+    Positions,              //!< Calculate only positions
+    Velocities,             //!< Calculate only velocities
+    PositionsAndVelocities, //!< Calculate both positions and velocities
+    Count                   //!< The number of entries
+};
+
 /*! \libinternal
  * \brief Class that handles construction of vsites and spreading of vsite forces
  */
@@ -88,7 +96,10 @@ class VirtualSitesHandler
 {
 public:
     //! Constructor, used only be the makeVirtualSitesHandler() factory function
-    VirtualSitesHandler(const gmx_mtop_t& mtop, gmx_domdec_t* domdec, PbcType pbcType);
+    VirtualSitesHandler(const gmx_mtop_t&                 mtop,
+                        gmx_domdec_t*                     domdec,
+                        PbcType                           pbcType,
+                        ArrayRef<const RangePartitioning> updateGroupingPerMoleculeType);
 
     ~VirtualSitesHandler();
 
@@ -96,16 +107,19 @@ public:
     int numInterUpdategroupVirtualSites() const;
 
     //! Set VSites and distribute VSite work over threads, should be called after each DD partitioning
-    void setVirtualSites(ArrayRef<const InteractionList> ilist, const t_mdatoms& mdatoms);
+    void setVirtualSites(ArrayRef<const InteractionList> ilist,
+                         int                             numAtoms,
+                         int                             homenr,
+                         ArrayRef<const ParticleType>    ptype);
 
     /*! \brief Create positions of vsite atoms based for the local system
      *
-     * \param[in,out] x        The coordinates
-     * \param[in]     dt       The time step
-     * \param[in,out] v        When not empty, velocities for vsites are set as displacement/dt
-     * \param[in]     box      The box
+     * \param[in,out] x          The coordinates
+     * \param[in,out] v          The velocities, needed if operation requires it
+     * \param[in]     box        The box
+     * \param[in]     operation  Whether we calculate positions, velocities, or both
      */
-    void construct(ArrayRef<RVec> x, real dt, ArrayRef<RVec> v, const matrix box) const;
+    void construct(ArrayRef<RVec> x, ArrayRef<RVec> v, const matrix box, VSiteOperation operation) const;
 
     //! Tells how to handle virial contributions due to virtual sites
     enum class VirialHandling : int
@@ -138,7 +152,7 @@ private:
     //! Implementation type.
     class Impl;
     //! Implementation object.
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \brief Create positions of vsite atoms based for the local system
@@ -172,21 +186,25 @@ int countNonlinearVsites(const gmx_mtop_t& mtop);
 /*! \brief Return the number of virtual sites that cross update groups
  *
  * \param[in] mtop                           The global topology
- * \param[in] updateGroupingPerMoleculetype  Update grouping per molecule type, pass empty when not using update groups
+ * \param[in] updateGroupingsPerMoleculeType  Update grouping per molecule type, pass empty when not using update groups
  */
 int countInterUpdategroupVsites(const gmx_mtop_t&                 mtop,
-                                ArrayRef<const RangePartitioning> updateGroupingPerMoleculetype);
+                                ArrayRef<const RangePartitioning> updateGroupingsPerMoleculeType);
 
 /*! \brief Create the virtual site handler
  *
- * \param[in] mtop      The global topology
- * \param[in] cr        The communication record
- * \param[in] pbcType   The type of PBC
+ * \param[in] mtop                           The global topology
+ * \param[in] cr                             The communication record
+ * \param[in] pbcType                        The type of PBC
+ * \param[in] updateGroupingPerMoleculeType  Update grouping per molecule type, pass
+ *                                           empty when not using update groups
  * \returns A valid vsite handler object or nullptr when there are no virtual sites
  */
-std::unique_ptr<VirtualSitesHandler> makeVirtualSitesHandler(const gmx_mtop_t& mtop,
-                                                             const t_commrec*  cr,
-                                                             PbcType           pbcType);
+std::unique_ptr<VirtualSitesHandler>
+makeVirtualSitesHandler(const gmx_mtop_t&                 mtop,
+                        const t_commrec*                  cr,
+                        PbcType                           pbcType,
+                        ArrayRef<const RangePartitioning> updateGroupingPerMoleculeType);
 
 } // namespace gmx
 
index b8d5d77fd9fc53aea4bf55b2e933efffc3809eac..89a3adb2e744a466acb3f489fb0fde0c3e3e6a24 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/fileio/filetypes.h"
 #include "gromacs/gmxlib/nrnb.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdtypes/forceoutput.h"
@@ -62,7 +63,7 @@
 #include "gromacs/utility/smalloc.h"
 
 void make_wall_tables(FILE*                   fplog,
-                      const t_inputrec*       ir,
+                      const t_inputrec&       ir,
                       const char*             tabfn,
                       const SimulationGroups* groups,
                       t_forcerec*             fr)
@@ -70,28 +71,30 @@ void make_wall_tables(FILE*                   fplog,
     int  negp_pp;
     char buf[STRLEN];
 
-    negp_pp                         = ir->opts.ngener - ir->nwall;
+    negp_pp                         = ir.opts.ngener - ir.nwall;
     gmx::ArrayRef<const int> nm_ind = groups->groups[SimulationAtomGroupType::EnergyOutput];
 
     if (fplog)
     {
-        fprintf(fplog, "Reading user tables for %d energy groups with %d walls\n", negp_pp, ir->nwall);
+        fprintf(fplog, "Reading user tables for %d energy groups with %d walls\n", negp_pp, ir.nwall);
     }
 
-    snew(fr->wall_tab, ir->nwall);
-    for (int w = 0; w < ir->nwall; w++)
+    fr->wall_tab.resize(ir.nwall);
+    for (int w = 0; w < ir.nwall; w++)
     {
-        snew(fr->wall_tab[w], negp_pp);
+        fr->wall_tab[w].resize(negp_pp);
         for (int egp = 0; egp < negp_pp; egp++)
         {
             /* If the energy group pair is excluded, we don't need a table */
-            if (!(fr->egp_flags[egp * ir->opts.ngener + negp_pp + w] & EGP_EXCL))
+            if (!(fr->egp_flags[egp * ir.opts.ngener + negp_pp + w] & EGP_EXCL))
             {
                 sprintf(buf, "%s", tabfn);
-                sprintf(buf + strlen(tabfn) - strlen(ftp2ext(efXVG)) - 1, "_%s_%s.%s",
-                        *groups->groupNames[nm_ind[egp]], *groups->groupNames[nm_ind[negp_pp + w]],
+                sprintf(buf + strlen(tabfn) - strlen(ftp2ext(efXVG)) - 1,
+                        "_%s_%s.%s",
+                        *groups->groupNames[nm_ind[egp]],
+                        *groups->groupNames[nm_ind[negp_pp + w]],
                         ftp2ext(efXVG));
-                fr->wall_tab[w][egp] = make_tables(fplog, fr->ic, buf, 0, GMX_MAKETABLES_FORCEUSER);
+                fr->wall_tab[w][egp] = make_tables(fplog, fr->ic.get(), buf, 0, GMX_MAKETABLES_FORCEUSER);
 
                 /* Since wall have no charge, we can compress the table */
                 for (int i = 0; i <= fr->wall_tab[w][egp]->n; i++)
@@ -112,7 +115,10 @@ void make_wall_tables(FILE*                   fplog,
     gmx_fatal(FARGS,
               "An atom is beyond the wall: coordinates %f %f %f, distance %f\n"
               "You might want to use the mdp option wall_r_linpot",
-              x[a][XX], x[a][YY], x[a][ZZ], r);
+              x[a][XX],
+              x[a][YY],
+              x[a][ZZ],
+              r);
 }
 
 static void tableForce(real r, const t_forcetable& tab, real Cd, real Cr, real* V, real* F)
@@ -159,22 +165,25 @@ static void tableForce(real r, const t_forcetable& tab, real Cd, real Cr, real*
     }
 }
 
-real do_walls(const t_inputrec&              ir,
-              const t_forcerec&              fr,
-              const matrix                   box,
-              const t_mdatoms&               md,
-              gmx::ArrayRef<const gmx::RVec> x,
-              gmx::ForceWithVirial*          forceWithVirial,
-              real                           lambda,
-              real                           Vlj[],
-              t_nrnb*                        nrnb)
+real do_walls(const t_inputrec&                   ir,
+              const t_forcerec&                   fr,
+              const matrix                        box,
+              gmx::ArrayRef<const int>            typeA,
+              gmx::ArrayRef<const int>            typeB,
+              gmx::ArrayRef<const unsigned short> cENER,
+              const int                           homenr,
+              const int                           numPerturbedAtoms,
+              gmx::ArrayRef<const gmx::RVec>      x,
+              gmx::ForceWithVirial*               forceWithVirial,
+              real                                lambda,
+              gmx::ArrayRef<real>                 Vlj,
+              t_nrnb*                             nrnb)
 {
     constexpr real sixth   = 1.0 / 6.0;
     constexpr real twelfth = 1.0 / 12.0;
 
-    int                   ntw[2];
-    real                  fac_d[2], fac_r[2];
-    const unsigned short* gid = md.cENER;
+    int  ntw[2];
+    real fac_d[2], fac_r[2];
 
     const int   nwall     = ir.nwall;
     const int   ngid      = ir.opts.ngener;
@@ -187,11 +196,11 @@ real do_walls(const t_inputrec&              ir,
         ntw[w] = 2 * ntype * ir.wall_atomtype[w];
         switch (ir.wall_type)
         {
-            case ewt93:
+            case WallType::NineThree:
                 fac_d[w] = ir.wall_density[w] * M_PI / 6;
                 fac_r[w] = ir.wall_density[w] * M_PI / 45;
                 break;
-            case ewt104:
+            case WallType::TenFour:
                 fac_d[w] = ir.wall_density[w] * M_PI / 2;
                 fac_r[w] = ir.wall_density[w] * M_PI / 5;
                 break;
@@ -204,36 +213,36 @@ real do_walls(const t_inputrec&              ir,
 
     real   dvdlambda = 0;
     double sumRF     = 0;
-    for (int lam = 0; lam < (md.nPerturbed ? 2 : 1); lam++)
+    for (int lam = 0; lam < (numPerturbedAtoms ? 2 : 1); lam++)
     {
-        real       lamfac;
-        const int* type;
-        if (md.nPerturbed)
+        real                     lamfac;
+        gmx::ArrayRef<const int> type;
+        if (numPerturbedAtoms != 0)
         {
             if (lam == 0)
             {
                 lamfac = 1 - lambda;
-                type   = md.typeA;
+                type   = typeA;
             }
             else
             {
                 lamfac = lambda;
-                type   = md.typeB;
+                type   = typeB;
             }
         }
         else
         {
             lamfac = 1;
-            type   = md.typeA;
+            type   = typeA;
         }
 
         real Vlambda = 0;
-        for (int i = 0; i < md.homenr; i++)
+        for (int i = 0; i < homenr; i++)
         {
             for (int w = 0; w < std::min(nwall, 2); w++)
             {
                 /* The wall energy groups are always at the end of the list */
-                const int ggid = gid[i] * ngid + ngid - nwall + w;
+                const int ggid = cENER[i] * ngid + ngid - nwall + w;
                 const int at   = type[i];
                 /* nbfp now includes the 6/12 derivative prefactors */
                 const real Cd = nbfp[ntw[w] + 2 * at] * sixth;
@@ -267,11 +276,11 @@ real do_walls(const t_inputrec&              ir,
                     real r1, r2, r4, Vd, Vr;
                     switch (ir.wall_type)
                     {
-                        case ewtTABLE:
-                            tableForce(r, *fr.wall_tab[w][gid[i]], Cd, Cr, &V, &F);
+                        case WallType::Table:
+                            tableForce(r, *fr.wall_tab[w][cENER[i]], Cd, Cr, &V, &F);
                             F *= lamfac;
                             break;
-                        case ewt93:
+                        case WallType::NineThree:
                             r1 = 1 / r;
                             r2 = r1 * r1;
                             r4 = r2 * r2;
@@ -280,7 +289,7 @@ real do_walls(const t_inputrec&              ir,
                             V  = Vr - Vd;
                             F  = lamfac * (9 * Vr - 3 * Vd) * r1;
                             break;
-                        case ewt104:
+                        case WallType::TenFour:
                             r1 = 1 / r;
                             r2 = r1 * r1;
                             r4 = r2 * r2;
@@ -289,7 +298,7 @@ real do_walls(const t_inputrec&              ir,
                             V  = Vr - Vd;
                             F  = lamfac * (10 * Vr - 4 * Vd) * r1;
                             break;
-                        case ewt126:
+                        case WallType::TwelveSix:
                             r1 = 1 / r;
                             r2 = r1 * r1;
                             r4 = r2 * r2;
@@ -318,12 +327,12 @@ real do_walls(const t_inputrec&              ir,
                 }
             }
         }
-        if (md.nPerturbed)
+        if (numPerturbedAtoms != 0)
         {
             dvdlambda += (lam == 0 ? -1 : 1) * Vlambda;
         }
 
-        inc_nrnb(nrnb, eNR_WALLS, md.homenr);
+        inc_nrnb(nrnb, eNR_WALLS, homenr);
     }
 
     if (forceWithVirial->computeVirial_)
index 8a6316583420e921c1c30874888e9f68928171cc..01126f68625463f3b63f795aa8ef39ff576706fb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,19 +53,23 @@ class ForceWithVirial;
 } // namespace gmx
 
 void make_wall_tables(FILE*                   fplog,
-                      const t_inputrec*       ir,
+                      const t_inputrec&       ir,
                       const char*             tabfn,
                       const SimulationGroups* groups,
                       t_forcerec*             fr);
 
-real do_walls(const t_inputrec&              ir,
-              const t_forcerec&              fr,
-              const matrix                   box,
-              const t_mdatoms&               md,
-              gmx::ArrayRef<const gmx::RVec> x,
-              gmx::ForceWithVirial*          forceWithVirial,
-              real                           lambda,
-              real                           Vlj[],
-              t_nrnb*                        nrnb);
+real do_walls(const t_inputrec&                   ir,
+              const t_forcerec&                   fr,
+              const matrix                        box,
+              gmx::ArrayRef<const int>            typeA,
+              gmx::ArrayRef<const int>            typeB,
+              gmx::ArrayRef<const unsigned short> cENER,
+              int                                 homenr,
+              int                                 numPerturbedAtoms,
+              gmx::ArrayRef<const gmx::RVec>      x,
+              gmx::ForceWithVirial*               forceWithVirial,
+              real                                lambda,
+              gmx::ArrayRef<real>                 Vlj,
+              t_nrnb*                             nrnb);
 
 #endif
index cb714aff3de0a1a9ba8be7ea25c49bb626f4ce61..d5ddaf1a78b2c6fdc6706e0ff95c314c949b99a7 100644 (file)
@@ -32,6 +32,7 @@
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
+add_library(mdrun INTERFACE)
 gmx_add_libgromacs_sources(
     legacymdrunoptions.cpp
     legacysimulator.cpp
@@ -51,6 +52,38 @@ gmx_add_libgromacs_sources(
     tpi.cpp
     )
 
+# Source files have the following private module dependencies.
+target_link_libraries(mdrun PRIVATE
+#                      gmxlib
+#                      math
+#                      mdtypes
+#                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(mdrun PUBLIC
+target_include_directories(mdrun INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(mdrun PUBLIC
+target_link_libraries(mdrun INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when mdrun is an OBJECT target
+#target_link_libraries(mdrun PUBLIC legacy_api)
+#target_link_libraries(mdrun PRIVATE common)
+
+# Module dependencies
+# mdrun interfaces convey transitive dependence on these modules.
+#target_link_libraries(mdrun PUBLIC
+target_link_libraries(mdrun INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(mdrun PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(mdrun PRIVATE legacy_modules)
+
 # TODO: Find a home for this header and a scheme for installation.
 # This header straddles the installed libraries and is a transitive interface
 # from libgromacs to libgmxapi to libgmxapi clients. Near term efforts are
index 86ea3279a8ae7ebc7e7aed3aae894f93034e5fd4..37ffb33742438a4d9abdaf09ebc772ef369f19bb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 @@
 #include "gromacs/mdlib/stophandler.h"
 
 class energyhistory_t;
-struct gmx_ekindata_t;
+class gmx_ekindata_t;
 struct gmx_enerdata_t;
 struct gmx_enfrot;
 struct gmx_mtop_t;
@@ -71,7 +71,7 @@ class BoxDeformation;
 class Constraints;
 class MdrunScheduleWorkload;
 class IMDOutputProvider;
-struct MdModulesNotifier;
+struct MDModulesNotifiers;
 class ImdSession;
 class MDLogger;
 class MDAtoms;
@@ -123,12 +123,12 @@ public:
                         gmx_enfrot*                         enforcedRotation,
                         BoxDeformation*                     deform,
                         IMDOutputProvider*                  outputProvider,
-                        const MdModulesNotifier&            mdModulesNotifier,
+                        const MDModulesNotifiers&           mdModulesNotifiers,
                         t_inputrec*                         inputrec,
                         ImdSession*                         imdSession,
                         pull_t*                             pull_work,
                         t_swap*                             swap,
-                        gmx_mtop_t*                         top_global,
+                        const gmx_mtop_t&                   top_global,
                         t_state*                            state_global,
                         ObservablesHistory*                 observablesHistory,
                         MDAtoms*                            mdAtoms,
@@ -157,7 +157,7 @@ public:
         enforcedRotation(enforcedRotation),
         deform(deform),
         outputProvider(outputProvider),
-        mdModulesNotifier(mdModulesNotifier),
+        mdModulesNotifiers(mdModulesNotifiers),
         inputrec(inputrec),
         imdSession(imdSession),
         pull_work(pull_work),
@@ -208,10 +208,10 @@ public:
     BoxDeformation* deform;
     //! Handles writing output files.
     IMDOutputProvider* outputProvider;
-    //! Handles notifications to MdModules for checkpoint writing
-    const MdModulesNotifier& mdModulesNotifier;
-    //! Contains user input mdp options.
-    t_inputrec* inputrec;
+    //! Handles notifications to MDModules for checkpoint writing
+    const MDModulesNotifiers& mdModulesNotifiers;
+    //! Contains user input mdp options. Note: The const-ness is casted away in a few instances, see #3854.
+    const t_inputrec* inputrec;
     //! The Interactive Molecular Dynamics session.
     ImdSession* imdSession;
     //! The pull work object.
@@ -219,7 +219,7 @@ public:
     //! The coordinate-swapping session.
     t_swap* swap;
     //! Full system topology.
-    const gmx_mtop_t* top_global;
+    const gmx_mtop_t& top_global;
     //! Full simulation state (only non-nullptr on master rank).
     t_state* state_global;
     //! History of simulation observables.
index 42d0a7df38148980c1886cf03fa015fa5066e51c..c78f448792c1d8c54a66069444947cce51035f7f 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-2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2011-2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +85,18 @@ int LegacyMdrunOptions::updateFromCommandLine(int argc, char** argv, ArrayRef<co
         PCA_Flags |= PCA_DISABLE_INPUT_FILE_CHECKING;
     }
 
-    if (!parse_common_args(&argc, argv, PCA_Flags, ssize(filenames), filenames.data(), asize(pa),
-                           pa, ssize(desc), desc.data(), 0, nullptr, &oenv))
+    if (!parse_common_args(&argc,
+                           argv,
+                           PCA_Flags,
+                           ssize(filenames),
+                           filenames.data(),
+                           asize(pa),
+                           pa,
+                           ssize(desc),
+                           desc.data(),
+                           0,
+                           nullptr,
+                           &oenv))
     {
         return 0;
     }
@@ -101,17 +111,17 @@ int LegacyMdrunOptions::updateFromCommandLine(int argc, char** argv, ArrayRef<co
         // fix that by changing the parsing, once more of the roles of
         // handling, validating and implementing defaults for user
         // command-line options have been seperated.
-        hw_opt.gpuIdsAvailable       = gpuIdsAvailable;
+        hw_opt.devicesSelectedByUser = devicesSelectedByUser;
         hw_opt.userGpuTaskAssignment = userGpuTaskAssignment;
 
         const char* env = getenv("GMX_GPU_ID");
         if (env != nullptr)
         {
-            if (!hw_opt.gpuIdsAvailable.empty())
+            if (!hw_opt.devicesSelectedByUser.empty())
             {
                 gmx_fatal(FARGS, "GMX_GPU_ID and -gpu_id can not be used at the same time");
             }
-            hw_opt.gpuIdsAvailable = env;
+            hw_opt.devicesSelectedByUser = env;
         }
 
         env = getenv("GMX_GPUTASKS");
@@ -124,7 +134,7 @@ int LegacyMdrunOptions::updateFromCommandLine(int argc, char** argv, ArrayRef<co
             hw_opt.userGpuTaskAssignment = env;
         }
 
-        if (!hw_opt.gpuIdsAvailable.empty() && !hw_opt.userGpuTaskAssignment.empty())
+        if (!hw_opt.devicesSelectedByUser.empty() && !hw_opt.userGpuTaskAssignment.empty())
         {
             gmx_fatal(FARGS, "-gpu_id and -gputasks cannot be used at the same time");
         }
index 474f6f0396258f227def1cc012ec38bdeddca284..678f741648921d772abe84e54a6f2d9ae4547a8f 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-2020, by the GROMACS development team, led by
+ * Copyright (c) 2011-2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,21 +142,28 @@ public:
 
     /*! \brief Command line options, defaults, docs and storage for them to fill. */
     /*! \{ */
-    rvec        realddxyz                                                    = { 0, 0, 0 };
-    const char* ddrank_opt_choices[static_cast<int>(DdRankOrder::Count) + 1] = {
-        nullptr, "interleave", "pp_pme", "cartesian", nullptr
-    };
-    const char* dddlb_opt_choices[static_cast<int>(DlbOption::Count) + 1] = { nullptr, "auto", "no",
-                                                                              "yes", nullptr };
-    const char* thread_aff_opt_choices[static_cast<int>(ThreadAffinity::Count) + 1] = {
-        nullptr, "auto", "on", "off", nullptr
-    };
+    rvec        realddxyz                                                           = { 0, 0, 0 };
+    const char* ddrank_opt_choices[static_cast<int>(DdRankOrder::Count) + 1]        = { nullptr,
+                                                                                 "interleave",
+                                                                                 "pp_pme",
+                                                                                 "cartesian",
+                                                                                 nullptr };
+    const char* dddlb_opt_choices[static_cast<int>(DlbOption::Count) + 1]           = { nullptr,
+                                                                              "auto",
+                                                                              "no",
+                                                                              "yes",
+                                                                              nullptr };
+    const char* thread_aff_opt_choices[static_cast<int>(ThreadAffinity::Count) + 1] = { nullptr,
+                                                                                        "auto",
+                                                                                        "on",
+                                                                                        "off",
+                                                                                        nullptr };
     const char* nbpu_opt_choices[5]    = { nullptr, "auto", "cpu", "gpu", nullptr };
     const char* pme_opt_choices[5]     = { nullptr, "auto", "cpu", "gpu", nullptr };
     const char* pme_fft_opt_choices[5] = { nullptr, "auto", "cpu", "gpu", nullptr };
     const char* bonded_opt_choices[5]  = { nullptr, "auto", "cpu", "gpu", nullptr };
     const char* update_opt_choices[5]  = { nullptr, "auto", "cpu", "gpu", nullptr };
-    const char* gpuIdsAvailable        = "";
+    const char* devicesSelectedByUser  = "";
     const char* userGpuTaskAssignment  = "";
 
 
@@ -210,7 +217,7 @@ public:
         { "-gpu_id",
           FALSE,
           etSTR,
-          { &gpuIdsAvailable },
+          { &devicesSelectedByUser },
           "List of unique GPU device IDs available to use" },
         { "-gputasks",
           FALSE,
@@ -220,7 +227,7 @@ public:
         { "-ddcheck",
           FALSE,
           etBOOL,
-          { &domdecOptions.checkBondedInteractions },
+          { &domdecOptions.ddBondedChecking },
           "Check for all bonded interactions with DD" },
         { "-ddbondcomm",
           FALSE,
index c6687d7c3adf1c186cfaf1c0035444fe6ac87c47..8859945fcc394cbdc9096181758f671ffe3e0e74 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,11 +54,11 @@ void LegacySimulator::run()
 {
     switch (inputrec->eI)
     {
-        case eiMD:
-        case eiBD:
-        case eiSD1:
-        case eiVV:
-        case eiVVAK:
+        case IntegrationAlgorithm::MD:
+        case IntegrationAlgorithm::BD:
+        case IntegrationAlgorithm::SD1:
+        case IntegrationAlgorithm::VV:
+        case IntegrationAlgorithm::VVAK:
             if (!EI_DYNAMICS(inputrec->eI))
             {
                 GMX_THROW(APIError(
@@ -73,7 +73,7 @@ void LegacySimulator::run()
                 do_md();
             }
             break;
-        case eiMimic:
+        case IntegrationAlgorithm::Mimic:
             if (doRerun)
             {
                 do_rerun();
@@ -83,19 +83,20 @@ void LegacySimulator::run()
                 do_mimic();
             }
             break;
-        case eiSteep: do_steep(); break;
-        case eiCG: do_cg(); break;
-        case eiNM: do_nm(); break;
-        case eiLBFGS: do_lbfgs(); break;
-        case eiTPI:
-        case eiTPIC:
+        case IntegrationAlgorithm::Steep: do_steep(); break;
+        case IntegrationAlgorithm::CG: do_cg(); break;
+        case IntegrationAlgorithm::NM: do_nm(); break;
+        case IntegrationAlgorithm::LBFGS: do_lbfgs(); break;
+        case IntegrationAlgorithm::TPI:
+        case IntegrationAlgorithm::TPIC:
             if (!EI_TPI(inputrec->eI))
             {
                 GMX_THROW(APIError("do_tpi integrator would be called for a non-TPI integrator"));
             }
             do_tpi();
             break;
-        case eiSD2_REMOVED: GMX_THROW(NotImplementedError("SD2 integrator has been removed"));
+        case IntegrationAlgorithm::SD2Removed:
+            GMX_THROW(NotImplementedError("SD2 integrator has been removed"));
         default: GMX_THROW(APIError("Non existing integrator selected"));
     }
 }
index bc367f6e5761fddcd4dea8aa6a0a8906af9e00d8..186d257c486c8a7d1a25080f147bb10aef688ca3 100644 (file)
@@ -53,6 +53,7 @@
 #include <numeric>
 
 #include "gromacs/applied_forces/awh/awh.h"
+#include "gromacs/applied_forces/awh/read_params.h"
 #include "gromacs/commandline/filenm.h"
 #include "gromacs/domdec/collect.h"
 #include "gromacs/domdec/dlbtiming.h"
 #include "gromacs/mdlib/trajectory_writing.h"
 #include "gromacs/mdlib/update.h"
 #include "gromacs/mdlib/update_constrain_gpu.h"
+#include "gromacs/mdlib/update_vv.h"
 #include "gromacs/mdlib/vcm.h"
 #include "gromacs/mdlib/vsite.h"
 #include "gromacs/mdrunutility/handlerestart.h"
@@ -161,7 +163,8 @@ void gmx::LegacySimulator::do_md()
     // alias to avoid a large ripple of nearly useless changes.
     // t_inputrec is being replaced by IMdpOptionsProvider, so this
     // will go away eventually.
-    t_inputrec*  ir = inputrec;
+    const t_inputrec* ir = inputrec;
+
     int64_t      step, step_rel;
     double       t, t0 = ir->init_t;
     gmx_bool     bGStatEveryStep, bGStat, bCalcVir, bCalcEnerStep, bCalcEner;
@@ -178,7 +181,7 @@ void gmx::LegacySimulator::do_md()
     gmx_global_stat_t gstat;
     gmx_shellfc_t*    shellfc;
     gmx_bool          bSumEkinhOld, bDoReplEx, bExchanged, bNeedRepartition;
-    gmx_bool          bTemp, bPres, bTrotter;
+    gmx_bool          bTrotter;
     real              dvdl_constr;
     std::vector<RVec> cbuf;
     matrix            lastbox;
@@ -197,15 +200,6 @@ void gmx::LegacySimulator::do_md()
 
     bool bInteractiveMDstep = false;
 
-    /* Domain decomposition could incorrectly miss a bonded
-       interaction, but checking for that requires a global
-       communication stage, which does not otherwise happen in DD
-       code. So we do that alongside the first global energy reduction
-       after a new DD is made. These variables handle whether the
-       check happens, and the result it returns. */
-    bool shouldCheckNumberOfBondedInteractions = false;
-    int  totalNumberOfBondedInteractions       = -1;
-
     SimulationSignals signals;
     // Most global communnication stages don't propagate mdrun
     // signals, and will use this object to achieve that.
@@ -235,14 +229,23 @@ void gmx::LegacySimulator::do_md()
     int nstglobalcomm = computeGlobalCommunicationPeriod(mdlog, ir, cr);
     bGStatEveryStep   = (nstglobalcomm == 1);
 
-    const SimulationGroups* groups = &top_global->groups;
+    const SimulationGroups* groups = &top_global.groups;
 
     std::unique_ptr<EssentialDynamics> ed = nullptr;
     if (opt2bSet("-ei", nfile, fnm))
     {
         /* Initialize essential dynamics sampling */
-        ed = init_edsam(mdlog, opt2fn_null("-ei", nfile, fnm), opt2fn("-eo", nfile, fnm), top_global,
-                        ir, cr, constr, state_global, observablesHistory, oenv, startingBehavior);
+        ed = init_edsam(mdlog,
+                        opt2fn_null("-ei", nfile, fnm),
+                        opt2fn("-eo", nfile, fnm),
+                        top_global,
+                        *ir,
+                        cr,
+                        constr,
+                        state_global,
+                        observablesHistory,
+                        oenv,
+                        startingBehavior);
     }
     else if (observablesHistory->edsamHistory)
     {
@@ -254,10 +257,24 @@ void gmx::LegacySimulator::do_md()
 
     int*                fep_state = MASTER(cr) ? &state_global->fep_state : nullptr;
     gmx::ArrayRef<real> lambda    = MASTER(cr) ? state_global->lambda : gmx::ArrayRef<real>();
-    initialize_lambdas(fplog, *ir, MASTER(cr), fep_state, lambda);
-    Update     upd(*ir, deform);
-    const bool doSimulatedAnnealing = initSimulatedAnnealing(ir, &upd);
-    const bool useReplicaExchange   = (replExParams.exchangeInterval > 0);
+    initialize_lambdas(fplog,
+                       ir->efep,
+                       ir->bSimTemp,
+                       *ir->fepvals,
+                       ir->simtempvals->temperatures,
+                       gmx::arrayRefFromArray(ir->opts.ref_t, ir->opts.ngtc),
+                       MASTER(cr),
+                       fep_state,
+                       lambda);
+    Update upd(*ir, deform);
+    bool   doSimulatedAnnealing = false;
+    {
+        // TODO: Avoid changing inputrec (#3854)
+        // Simulated annealing updates the reference temperature.
+        auto* nonConstInputrec = const_cast<t_inputrec*>(inputrec);
+        doSimulatedAnnealing   = initSimulatedAnnealing(nonConstInputrec, &upd);
+    }
+    const bool useReplicaExchange = (replExParams.exchangeInterval > 0);
 
     const t_fcdata& fcdata = *fr->fcdata;
 
@@ -266,9 +283,8 @@ void gmx::LegacySimulator::do_md()
     {
         // TODO This implementation of ensemble orientation restraints is nasty because
         // a user can't just do multi-sim with single-sim orientation restraints.
-        bool usingEnsembleRestraints =
-                (fcdata.disres->nsystems > 1) || ((ms != nullptr) && (fcdata.orires->nr != 0));
-        bool awhUsesMultiSim = (ir->bDoAwh && ir->awhParams->shareBiasMultisim && (ms != nullptr));
+        bool usingEnsembleRestraints = (fcdata.disres->nsystems > 1) || ((ms != nullptr) && fcdata.orires);
+        bool awhUsesMultiSim = (ir->bDoAwh && ir->awhParams->shareBiasMultisim() && (ms != nullptr));
 
         // Replica exchange, ensemble restraints and AWH need all
         // simulations to remain synchronized, so they need
@@ -292,12 +308,29 @@ void gmx::LegacySimulator::do_md()
     {
         pleaseCiteCouplingAlgorithms(fplog, *ir);
     }
-    gmx_mdoutf* outf =
-            init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, mdModulesNotifier, ir,
-                        top_global, oenv, wcycle, startingBehavior, simulationsShareState, ms);
-    gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf), top_global, ir, pull_work,
-                                   mdoutf_get_fp_dhdl(outf), false, startingBehavior,
-                                   simulationsShareState, mdModulesNotifier);
+    gmx_mdoutf*       outf = init_mdoutf(fplog,
+                                   nfile,
+                                   fnm,
+                                   mdrunOptions,
+                                   cr,
+                                   outputProvider,
+                                   mdModulesNotifiers,
+                                   ir,
+                                   top_global,
+                                   oenv,
+                                   wcycle,
+                                   startingBehavior,
+                                   simulationsShareState,
+                                   ms);
+    gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf),
+                                   top_global,
+                                   *ir,
+                                   pull_work,
+                                   mdoutf_get_fp_dhdl(outf),
+                                   false,
+                                   startingBehavior,
+                                   simulationsShareState,
+                                   mdModulesNotifiers);
 
     gstat = global_stat_init(ir);
 
@@ -308,11 +341,15 @@ void gmx::LegacySimulator::do_md()
     const bool  useGpuForUpdate    = simulationWork.useGpuUpdate;
 
     /* Check for polarizable models and flexible constraints */
-    shellfc = init_shell_flexcon(fplog, top_global, constr ? constr->numFlexibleConstraints() : 0,
-                                 ir->nstcalcenergy, DOMAINDECOMP(cr), useGpuForPme);
+    shellfc = init_shell_flexcon(fplog,
+                                 top_global,
+                                 constr ? constr->numFlexibleConstraints() : 0,
+                                 ir->nstcalcenergy,
+                                 DOMAINDECOMP(cr),
+                                 useGpuForPme);
 
     {
-        double io = compute_io(ir, top_global->natoms, *groups, energyOutput.numEnergyTerms(), 1);
+        double io = compute_io(ir, top_global.natoms, *groups, energyOutput.numEnergyTerms(), 1);
         if ((io > 2000) && MASTER(cr))
         {
             fprintf(stderr, "\nWARNING: This run will generate roughly %.0f Mb of data\n\n", io);
@@ -323,25 +360,46 @@ void gmx::LegacySimulator::do_md()
     std::unique_ptr<t_state> stateInstance;
     t_state*                 state;
 
-    gmx_localtop_t top(top_global->ffparams);
+    gmx_localtop_t top(top_global.ffparams);
 
-    auto mdatoms = mdAtoms->mdatoms();
-
-    ForceBuffers f(fr->useMts, ((useGpuForNonbonded && useGpuForBufferOps) || useGpuForUpdate)
-                                       ? PinningPolicy::PinnedIfSupported
-                                       : PinningPolicy::CannotBePinned);
+    ForceBuffers     f(fr->useMts,
+                   ((useGpuForNonbonded && useGpuForBufferOps) || useGpuForUpdate)
+                           ? PinningPolicy::PinnedIfSupported
+                           : PinningPolicy::CannotBePinned);
+    const t_mdatoms* md = mdAtoms->mdatoms();
     if (DOMAINDECOMP(cr))
     {
         stateInstance = std::make_unique<t_state>();
         state         = stateInstance.get();
-        dd_init_local_state(cr->dd, state_global, state);
+        dd_init_local_state(*cr->dd, state_global, state);
 
         /* Distribute the charge groups over the nodes from the master node */
-        dd_partition_system(fplog, mdlog, ir->init_step, cr, TRUE, 1, state_global, *top_global, ir,
-                            imdSession, pull_work, state, &f, mdAtoms, &top, fr, vsite, constr,
-                            nrnb, nullptr, FALSE);
-        shouldCheckNumberOfBondedInteractions = true;
-        upd.setNumAtoms(state->natoms);
+        dd_partition_system(fplog,
+                            mdlog,
+                            ir->init_step,
+                            cr,
+                            TRUE,
+                            1,
+                            state_global,
+                            top_global,
+                            *ir,
+                            imdSession,
+                            pull_work,
+                            state,
+                            &f,
+                            mdAtoms,
+                            &top,
+                            fr,
+                            vsite,
+                            constr,
+                            nrnb,
+                            nullptr,
+                            FALSE);
+        upd.updateAfterPartition(state->natoms,
+                                 md->cFREEZE ? gmx::arrayRefFromArray(md->cFREEZE, md->nr)
+                                             : gmx::ArrayRef<const unsigned short>(),
+                                 md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
+                                         : gmx::ArrayRef<const unsigned short>());
     }
     else
     {
@@ -350,9 +408,13 @@ void gmx::LegacySimulator::do_md()
         state = state_global;
 
         /* Generate and initialize new topology */
-        mdAlgorithmsSetupAtomData(cr, ir, *top_global, &top, fr, &f, mdAtoms, constr, vsite, shellfc);
+        mdAlgorithmsSetupAtomData(cr, *ir, top_global, &top, fr, &f, mdAtoms, constr, vsite, shellfc);
 
-        upd.setNumAtoms(state->natoms);
+        upd.updateAfterPartition(state->natoms,
+                                 md->cFREEZE ? gmx::arrayRefFromArray(md->cFREEZE, md->nr)
+                                             : gmx::ArrayRef<const unsigned short>(),
+                                 md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
+                                         : gmx::ArrayRef<const unsigned short>());
     }
 
     std::unique_ptr<UpdateConstrainGpu> integrator;
@@ -366,33 +428,33 @@ void gmx::LegacySimulator::do_md()
                                    || constr->numConstraintsTotal() == 0,
                            "Constraints in domain decomposition are only supported with update "
                            "groups if using GPU update.\n");
-        GMX_RELEASE_ASSERT(ir->eConstrAlg != econtSHAKE || constr == nullptr
+        GMX_RELEASE_ASSERT(ir->eConstrAlg != ConstraintAlgorithm::Shake || constr == nullptr
                                    || constr->numConstraintsTotal() == 0,
                            "SHAKE is not supported with GPU update.");
         GMX_RELEASE_ASSERT(useGpuForPme || (useGpuForNonbonded && simulationWork.useGpuBufferOps),
                            "Either PME or short-ranged non-bonded interaction tasks must run on "
                            "the GPU to use GPU update.\n");
-        GMX_RELEASE_ASSERT(ir->eI == eiMD,
+        GMX_RELEASE_ASSERT(ir->eI == IntegrationAlgorithm::MD,
                            "Only the md integrator is supported with the GPU update.\n");
         GMX_RELEASE_ASSERT(
-                ir->etc != etcNOSEHOOVER,
+                ir->etc != TemperatureCoupling::NoseHoover,
                 "Nose-Hoover temperature coupling is not supported with the GPU update.\n");
         GMX_RELEASE_ASSERT(
-                ir->epc == epcNO || ir->epc == epcPARRINELLORAHMAN || ir->epc == epcBERENDSEN
-                        || ir->epc == epcCRESCALE,
+                ir->epc == PressureCoupling::No || ir->epc == PressureCoupling::ParrinelloRahman
+                        || ir->epc == PressureCoupling::Berendsen || ir->epc == PressureCoupling::CRescale,
                 "Only Parrinello-Rahman, Berendsen, and C-rescale pressure coupling are supported "
                 "with the GPU update.\n");
-        GMX_RELEASE_ASSERT(!mdatoms->haveVsites,
+        GMX_RELEASE_ASSERT(!md->haveVsites,
                            "Virtual sites are not supported with the GPU update.\n");
         GMX_RELEASE_ASSERT(ed == nullptr,
                            "Essential dynamics is not supported with the GPU update.\n");
         GMX_RELEASE_ASSERT(!ir->bPull || !pull_have_constraint(*ir->pull),
                            "Constraints pulling is not supported with the GPU update.\n");
-        GMX_RELEASE_ASSERT(fcdata.orires->nr == 0,
+        GMX_RELEASE_ASSERT(fcdata.orires == nullptr,
                            "Orientation restraints are not supported with the GPU update.\n");
         GMX_RELEASE_ASSERT(
-                ir->efep == efepNO
-                        || (!haveFepPerturbedMasses(*top_global) && !havePerturbedConstraints(*top_global)),
+                ir->efep == FreeEnergyPerturbationType::No
+                        || (!haveFepPerturbedMasses(top_global) && !havePerturbedConstraints(top_global)),
                 "Free energy perturbation of masses and constraints are not supported with the GPU "
                 "update.");
 
@@ -414,9 +476,13 @@ void gmx::LegacySimulator::do_md()
                 "Update stream should be initialized in order to use GPU "
                 "update-constraints.");
         integrator = std::make_unique<UpdateConstrainGpu>(
-                *ir, *top_global, fr->deviceStreamManager->context(),
+                *ir,
+                top_global,
+                ekind->ngtc,
+                fr->deviceStreamManager->context(),
                 fr->deviceStreamManager->stream(gmx::DeviceStreamType::UpdateAndConstraints),
-                stateGpu->xUpdatedOnDevice(), wcycle);
+                stateGpu->xUpdatedOnDevice(),
+                wcycle);
 
         integrator->setPbc(PbcType::Xyz, state->box);
     }
@@ -435,7 +501,7 @@ void gmx::LegacySimulator::do_md()
     // the global state to file and potentially for replica exchange.
     // (Global topology should persist.)
 
-    update_mdatoms(mdatoms, state->lambda[efptMASS]);
+    update_mdatoms(mdAtoms->mdatoms(), state->lambda[FreeEnergyPerturbationCouplingType::Mass]);
 
     if (ir->bExpanded)
     {
@@ -453,47 +519,58 @@ void gmx::LegacySimulator::do_md()
         EnergyData::initializeEnergyHistory(startingBehavior, observablesHistory, &energyOutput);
     }
 
-    preparePrevStepPullCom(ir, pull_work, mdatoms->massT, state, state_global, cr,
+    preparePrevStepPullCom(ir,
+                           pull_work,
+                           gmx::arrayRefFromArray(md->massT, md->nr),
+                           state,
+                           state_global,
+                           cr,
                            startingBehavior != StartingBehavior::NewSimulation);
 
     // TODO: Remove this by converting AWH into a ForceProvider
-    auto awh = prepareAwhModule(fplog, *ir, state_global, cr, ms,
+    auto awh = prepareAwhModule(fplog,
+                                *ir,
+                                state_global,
+                                cr,
+                                ms,
                                 startingBehavior != StartingBehavior::NewSimulation,
-                                shellfc != nullptr, opt2fn("-awh", nfile, fnm), pull_work);
+                                shellfc != nullptr,
+                                opt2fn("-awh", nfile, fnm),
+                                pull_work);
 
     if (useReplicaExchange && MASTER(cr))
     {
-        repl_ex = init_replica_exchange(fplog, ms, top_global->natoms, ir, replExParams);
+        repl_ex = init_replica_exchange(fplog, ms, top_global.natoms, ir, replExParams);
     }
     /* PME tuning is only supported in the Verlet scheme, with PME for
      * Coulomb. It is not supported with only LJ PME. */
     bPMETune = (mdrunOptions.tunePme && EEL_PME(fr->ic->eeltype) && !mdrunOptions.reproducible
-                && ir->cutoff_scheme != ecutsGROUP);
+                && ir->cutoff_scheme != CutoffScheme::Group);
 
     pme_load_balancing_t* pme_loadbal = nullptr;
     if (bPMETune)
     {
-        pme_loadbal_init(&pme_loadbal, cr, mdlog, *ir, state->box, *fr->ic, *fr->nbv, fr->pmedata,
-                         fr->nbv->useGpu());
+        pme_loadbal_init(
+                &pme_loadbal, cr, mdlog, *ir, state->box, *fr->ic, *fr->nbv, fr->pmedata, fr->nbv->useGpu());
     }
 
     if (!ir->bContinuation)
     {
-        if (state->flags & (1U << estV))
+        if (state->flags & enumValueToBitMask(StateEntry::V))
         {
             auto v = makeArrayRef(state->v);
             /* Set the velocities of vsites, shells and frozen atoms to zero */
-            for (i = 0; i < mdatoms->homenr; i++)
+            for (i = 0; i < md->homenr; i++)
             {
-                if (mdatoms->ptype[i] == eptVSite || mdatoms->ptype[i] == eptShell)
+                if (md->ptype[i] == ParticleType::Shell)
                 {
                     clear_rvec(v[i]);
                 }
-                else if (mdatoms->cFREEZE)
+                else if (md->cFREEZE)
                 {
                     for (m = 0; m < DIM; m++)
                     {
-                        if (ir->opts.nFreeze[mdatoms->cFREEZE[i]][m])
+                        if (ir->opts.nFreeze[md->cFREEZE[i]][m])
                         {
                             v[i][m] = 0;
                         }
@@ -505,18 +582,19 @@ void gmx::LegacySimulator::do_md()
         if (constr)
         {
             /* Constrain the initial coordinates and velocities */
-            do_constrain_first(fplog, constr, ir, mdatoms->nr, mdatoms->homenr,
-                               state->x.arrayRefWithPadding(), state->v.arrayRefWithPadding(),
-                               state->box, state->lambda[efptBONDED]);
-        }
-        if (vsite)
-        {
-            /* Construct the virtual sites for the initial configuration */
-            vsite->construct(state->x, ir->delta_t, {}, state->box);
+            do_constrain_first(fplog,
+                               constr,
+                               ir,
+                               md->nr,
+                               md->homenr,
+                               state->x.arrayRefWithPadding(),
+                               state->v.arrayRefWithPadding(),
+                               state->box,
+                               state->lambda[FreeEnergyPerturbationCouplingType::Bonded]);
         }
     }
 
-    if (ir->efep != efepNO)
+    if (ir->efep != FreeEnergyPerturbationType::No)
     {
         /* Set free energy calculation frequency as the greatest common
          * denominator of nstdhdl and repl_ex_nst. */
@@ -531,7 +609,7 @@ void gmx::LegacySimulator::do_md()
         }
         if (ir->bDoAwh)
         {
-            nstfep = std::gcd(ir->awhParams->nstSampleCoord, nstfep);
+            nstfep = std::gcd(ir->awhParams->nstSampleCoord(), nstfep);
         }
     }
 
@@ -539,7 +617,7 @@ void gmx::LegacySimulator::do_md()
      * this is the first step, since we might be restarting from a checkpoint,
      * and in that case we should not do any modifications to the state.
      */
-    bStopCM = (ir->comm_mode != ecmNO && !ir->bContinuation);
+    bStopCM = (ir->comm_mode != ComRemovalAlgorithm::No && !ir->bContinuation);
 
     // When restarting from a checkpoint, it can be appropriate to
     // initialize ekind from quantities in the checkpoint. Otherwise,
@@ -567,7 +645,7 @@ void gmx::LegacySimulator::do_md()
 
     bSumEkinhOld = FALSE;
 
-    t_vcm vcm(top_global->groups, *ir);
+    t_vcm vcm(top_global.groups, *ir);
     reportComRemovalInfo(fplog, vcm);
 
     /* To minimize communication, compute_globals computes the COM velocity
@@ -583,28 +661,50 @@ void gmx::LegacySimulator::do_md()
             cglo_flags_iteration |= CGLO_STOPCM;
             cglo_flags_iteration &= ~CGLO_TEMPERATURE;
         }
-        compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
-                        makeConstArrayRef(state->v), state->box, mdatoms, nrnb, &vcm, nullptr,
-                        enerd, force_vir, shake_vir, total_vir, pres, constr, &nullSignaller,
-                        state->box, &totalNumberOfBondedInteractions, &bSumEkinhOld,
-                        cglo_flags_iteration
-                                | (shouldCheckNumberOfBondedInteractions ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS
-                                                                         : 0));
+        if (DOMAINDECOMP(cr) && shouldCheckNumberOfBondedInteractions(*cr->dd) && cgloIteration == 0)
+        {
+            cglo_flags_iteration |= CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS;
+        }
+        compute_globals(gstat,
+                        cr,
+                        ir,
+                        fr,
+                        ekind,
+                        makeConstArrayRef(state->x),
+                        makeConstArrayRef(state->v),
+                        state->box,
+                        md,
+                        nrnb,
+                        &vcm,
+                        nullptr,
+                        enerd,
+                        force_vir,
+                        shake_vir,
+                        total_vir,
+                        pres,
+                        gmx::ArrayRef<real>{},
+                        &nullSignaller,
+                        state->box,
+                        &bSumEkinhOld,
+                        cglo_flags_iteration);
         if (cglo_flags_iteration & CGLO_STOPCM)
         {
             /* At initialization, do not pass x with acceleration-correction mode
              * to avoid (incorrect) correction of the initial coordinates.
              */
-            auto x = (vcm.mode == ecmLINEAR_ACCELERATION_CORRECTION) ? ArrayRef<RVec>()
-                                                                     : makeArrayRef(state->x);
-            process_and_stopcm_grp(fplog, &vcm, *mdatoms, x, makeArrayRef(state->v));
-            inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr);
+            auto x = (vcm.mode == ComRemovalAlgorithm::LinearAccelerationCorrection)
+                             ? ArrayRef<RVec>()
+                             : makeArrayRef(state->x);
+            process_and_stopcm_grp(fplog, &vcm, *md, x, makeArrayRef(state->v));
+            inc_nrnb(nrnb, eNR_STOPCM, md->homenr);
         }
     }
-    checkNumberOfBondedInteractions(mdlog, cr, totalNumberOfBondedInteractions, top_global, &top,
-                                    makeConstArrayRef(state->x), state->box,
-                                    &shouldCheckNumberOfBondedInteractions);
-    if (ir->eI == eiVVAK)
+    if (DOMAINDECOMP(cr))
+    {
+        checkNumberOfBondedInteractions(
+                mdlog, cr, top_global, &top, makeConstArrayRef(state->x), state->box);
+    }
+    if (ir->eI == IntegrationAlgorithm::VVAK)
     {
         /* a second call to get the half step temperature initialized as well */
         /* we do the same call as above, but turn the pressure off -- internally to
@@ -612,10 +712,28 @@ void gmx::LegacySimulator::do_md()
            kinetic energy calculation.  This minimized excess variables, but
            perhaps loses some logic?*/
 
-        compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
-                        makeConstArrayRef(state->v), state->box, mdatoms, nrnb, &vcm, nullptr,
-                        enerd, force_vir, shake_vir, total_vir, pres, constr, &nullSignaller,
-                        state->box, nullptr, &bSumEkinhOld, cglo_flags & ~CGLO_PRESSURE);
+        compute_globals(gstat,
+                        cr,
+                        ir,
+                        fr,
+                        ekind,
+                        makeConstArrayRef(state->x),
+                        makeConstArrayRef(state->v),
+                        state->box,
+                        md,
+                        nrnb,
+                        &vcm,
+                        nullptr,
+                        enerd,
+                        force_vir,
+                        shake_vir,
+                        total_vir,
+                        pres,
+                        gmx::ArrayRef<real>{},
+                        &nullSignaller,
+                        state->box,
+                        &bSumEkinhOld,
+                        cglo_flags & ~CGLO_PRESSURE);
     }
 
     /* Calculate the initial half step temperature, and save the ekinh_old */
@@ -635,15 +753,16 @@ void gmx::LegacySimulator::do_md()
     {
         if (!ir->bContinuation)
         {
-            if (constr && ir->eConstrAlg == econtLINCS)
+            if (constr && ir->eConstrAlg == ConstraintAlgorithm::Lincs)
             {
-                fprintf(fplog, "RMS relative constraint deviation after constraining: %.2e\n",
+                fprintf(fplog,
+                        "RMS relative constraint deviation after constraining: %.2e\n",
                         constr->rmsd());
             }
             if (EI_STATE_VELOCITY(ir->eI))
             {
                 real temp = enerd->term[F_TEMP];
-                if (ir->eI != eiVV)
+                if (ir->eI != IntegrationAlgorithm::VV)
                 {
                     /* Result of Ekin averaged over velocities of -half
                      * and +half step, while we only have -half step here.
@@ -655,7 +774,7 @@ void gmx::LegacySimulator::do_md()
         }
 
         char tbuf[20];
-        fprintf(stderr, "starting mdrun '%s'\n", *(top_global->name));
+        fprintf(stderr, "starting mdrun '%s'\n", *(top_global.name));
         if (ir->nsteps >= 0)
         {
             sprintf(tbuf, "%8.1f", (ir->init_step + ir->nsteps) * ir->delta_t);
@@ -666,9 +785,12 @@ void gmx::LegacySimulator::do_md()
         }
         if (ir->init_step > 0)
         {
-            fprintf(stderr, "%s steps, %s ps (continuing from step %s, %8.1f ps).\n",
-                    gmx_step_str(ir->init_step + ir->nsteps, sbuf), tbuf,
-                    gmx_step_str(ir->init_step, sbuf2), ir->init_step * ir->delta_t);
+            fprintf(stderr,
+                    "%s steps, %s ps (continuing from step %s, %8.1f ps).\n",
+                    gmx_step_str(ir->init_step + ir->nsteps, sbuf),
+                    tbuf,
+                    gmx_step_str(ir->init_step, sbuf2),
+                    ir->init_step * ir->delta_t);
         }
         else
         {
@@ -678,7 +800,7 @@ void gmx::LegacySimulator::do_md()
     }
 
     walltime_accounting_start_time(walltime_accounting);
-    wallcycle_start(wcycle, ewcRUN);
+    wallcycle_start(wcycle, WallCycleCounter::Run);
     print_start(fplog, cr, walltime_accounting, "mdrun");
 
     /***********************************************************
@@ -698,20 +820,38 @@ void gmx::LegacySimulator::do_md()
     step_rel = 0;
 
     auto stopHandler = stopHandlerBuilder->getStopHandlerMD(
-            compat::not_null<SimulationSignal*>(&signals[eglsSTOPCOND]), simulationsShareState,
-            MASTER(cr), ir->nstlist, mdrunOptions.reproducible, nstSignalComm,
-            mdrunOptions.maximumHoursToRun, ir->nstlist == 0, fplog, step, bNS, walltime_accounting);
+            compat::not_null<SimulationSignal*>(&signals[eglsSTOPCOND]),
+            simulationsShareState,
+            MASTER(cr),
+            ir->nstlist,
+            mdrunOptions.reproducible,
+            nstSignalComm,
+            mdrunOptions.maximumHoursToRun,
+            ir->nstlist == 0,
+            fplog,
+            step,
+            bNS,
+            walltime_accounting);
 
     auto checkpointHandler = std::make_unique<CheckpointHandler>(
-            compat::make_not_null<SimulationSignal*>(&signals[eglsCHKPT]), simulationsShareState,
-            ir->nstlist == 0, MASTER(cr), mdrunOptions.writeConfout,
+            compat::make_not_null<SimulationSignal*>(&signals[eglsCHKPT]),
+            simulationsShareState,
+            ir->nstlist == 0,
+            MASTER(cr),
+            mdrunOptions.writeConfout,
             mdrunOptions.checkpointOptions.period);
 
     const bool resetCountersIsLocal = true;
     auto       resetHandler         = std::make_unique<ResetHandler>(
             compat::make_not_null<SimulationSignal*>(&signals[eglsRESETCOUNTERS]),
-            !resetCountersIsLocal, ir->nsteps, MASTER(cr), mdrunOptions.timingOptions.resetHalfway,
-            mdrunOptions.maximumHoursToRun, mdlog, wcycle, walltime_accounting);
+            !resetCountersIsLocal,
+            ir->nsteps,
+            MASTER(cr),
+            mdrunOptions.timingOptions.resetHalfway,
+            mdrunOptions.maximumHoursToRun,
+            mdlog,
+            wcycle,
+            walltime_accounting);
 
     const DDBalanceRegionHandler ddBalanceRegionHandler(cr);
 
@@ -738,24 +878,35 @@ void gmx::LegacySimulator::do_md()
                 stateGpu->waitCoordinatesReadyOnHost(AtomLocality::Local);
             }
             /* PME grid + cut-off optimization with GPUs or PME nodes */
-            pme_loadbal_do(pme_loadbal, cr, (mdrunOptions.verbose && MASTER(cr)) ? stderr : nullptr,
-                           fplog, mdlog, *ir, fr, state->box, state->x, wcycle, step, step_rel,
-                           &bPMETunePrinting, simulationWork.useGpuPmePpCommunication);
-        }
-
-        wallcycle_start(wcycle, ewcSTEP);
+            pme_loadbal_do(pme_loadbal,
+                           cr,
+                           (mdrunOptions.verbose && MASTER(cr)) ? stderr : nullptr,
+                           fplog,
+                           mdlog,
+                           *ir,
+                           fr,
+                           state->box,
+                           state->x,
+                           wcycle,
+                           step,
+                           step_rel,
+                           &bPMETunePrinting,
+                           simulationWork.useGpuPmePpCommunication);
+        }
+
+        wallcycle_start(wcycle, WallCycleCounter::Step);
 
         bLastStep = (step_rel == ir->nsteps);
         t         = t0 + step * ir->delta_t;
 
         // TODO Refactor this, so that nstfep does not need a default value of zero
-        if (ir->efep != efepNO || ir->bSimTemp)
+        if (ir->efep != FreeEnergyPerturbationType::No || ir->bSimTemp)
         {
             /* find and set the current lambdas */
             state->lambda = currentLambdas(step, *(ir->fepvals), state->fep_state);
 
-            bDoDHDL     = do_per_step(step, ir->fepvals->nstdhdl);
-            bDoFEP      = ((ir->efep != efepNO) && do_per_step(step, nstfep));
+            bDoDHDL = do_per_step(step, ir->fepvals->nstdhdl);
+            bDoFEP  = ((ir->efep != FreeEnergyPerturbationType::No) && do_per_step(step, nstfep));
             bDoExpanded = (do_per_step(step, ir->expandedvals->nstexpanded) && (ir->bExpanded)
                            && (!bFirstStep));
         }
@@ -765,11 +916,14 @@ void gmx::LegacySimulator::do_md()
 
         if (doSimulatedAnnealing)
         {
-            update_annealing_target_temp(ir, t, &upd);
+            // TODO: Avoid changing inputrec (#3854)
+            // Simulated annealing updates the reference temperature.
+            auto* nonConstInputrec = const_cast<t_inputrec*>(inputrec);
+            update_annealing_target_temp(nonConstInputrec, t, &upd);
         }
 
         /* Stop Center of Mass motion */
-        bStopCM = (ir->comm_mode != ecmNO && do_per_step(step, ir->nstcomm));
+        bStopCM = (ir->comm_mode != ComRemovalAlgorithm::No && do_per_step(step, ir->nstcomm));
 
         /* Determine whether or not to do Neighbour Searching */
         bNS = (bFirstStep || bNStList || bExchanged || bNeedRepartition);
@@ -804,6 +958,25 @@ void gmx::LegacySimulator::do_md()
             stateGpu->waitCoordinatesReadyOnHost(AtomLocality::Local);
         }
 
+        // We only need to calculate virtual velocities if we are writing them in the current step
+        const bool needVirtualVelocitiesThisStep =
+                (vsite != nullptr)
+                && (do_per_step(step, ir->nstvout) || checkpointHandler->isCheckpointingStep());
+
+        if (vsite != nullptr)
+        {
+            // Virtual sites need to be updated before domain decomposition and forces are calculated
+            wallcycle_start(wcycle, WallCycleCounter::VsiteConstr);
+            // md-vv calculates virtual velocities once it has full-step real velocities
+            vsite->construct(state->x,
+                             state->v,
+                             state->box,
+                             (!EI_VV(inputrec->eI) && needVirtualVelocitiesThisStep)
+                                     ? VSiteOperation::PositionsAndVelocities
+                                     : VSiteOperation::Positions);
+            wallcycle_stop(wcycle, WallCycleCounter::VsiteConstr);
+        }
+
         if (bNS && !(bFirstStep && ir->bContinuation))
         {
             bMasterState = FALSE;
@@ -828,11 +1001,32 @@ void gmx::LegacySimulator::do_md()
             if (DOMAINDECOMP(cr))
             {
                 /* Repartition the domain decomposition */
-                dd_partition_system(fplog, mdlog, step, cr, bMasterState, nstglobalcomm, state_global,
-                                    *top_global, ir, imdSession, pull_work, state, &f, mdAtoms, &top,
-                                    fr, vsite, constr, nrnb, wcycle, do_verbose && !bPMETunePrinting);
-                shouldCheckNumberOfBondedInteractions = true;
-                upd.setNumAtoms(state->natoms);
+                dd_partition_system(fplog,
+                                    mdlog,
+                                    step,
+                                    cr,
+                                    bMasterState,
+                                    nstglobalcomm,
+                                    state_global,
+                                    top_global,
+                                    *ir,
+                                    imdSession,
+                                    pull_work,
+                                    state,
+                                    &f,
+                                    mdAtoms,
+                                    &top,
+                                    fr,
+                                    vsite,
+                                    constr,
+                                    nrnb,
+                                    wcycle,
+                                    do_verbose && !bPMETunePrinting);
+                upd.updateAfterPartition(state->natoms,
+                                         md->cFREEZE ? gmx::arrayRefFromArray(md->cFREEZE, md->nr)
+                                                     : gmx::ArrayRef<const unsigned short>(),
+                                         md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
+                                                 : gmx::ArrayRef<const unsigned short>());
             }
         }
 
@@ -847,29 +1041,52 @@ void gmx::LegacySimulator::do_md()
 
         if (MASTER(cr) && do_log)
         {
-            gmx::EnergyOutput::printHeader(fplog, step,
-                                           t); /* can we improve the information printed here? */
+            gmx::EnergyOutput::printHeader(
+                    fplog, step, t); /* can we improve the information printed here? */
         }
 
-        if (ir->efep != efepNO)
+        if (ir->efep != FreeEnergyPerturbationType::No)
         {
-            update_mdatoms(mdatoms, state->lambda[efptMASS]);
+            update_mdatoms(mdAtoms->mdatoms(), state->lambda[FreeEnergyPerturbationCouplingType::Mass]);
         }
 
         if (bExchanged)
         {
-
             /* We need the kinetic energy at minus the half step for determining
              * the full step kinetic energy and possibly for T-coupling.*/
             /* This may not be quite working correctly yet . . . . */
-            compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
-                            makeConstArrayRef(state->v), state->box, mdatoms, nrnb, &vcm, wcycle,
-                            enerd, nullptr, nullptr, nullptr, nullptr, constr, &nullSignaller,
-                            state->box, &totalNumberOfBondedInteractions, &bSumEkinhOld,
-                            CGLO_GSTAT | CGLO_TEMPERATURE | CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS);
-            checkNumberOfBondedInteractions(mdlog, cr, totalNumberOfBondedInteractions, top_global,
-                                            &top, makeConstArrayRef(state->x), state->box,
-                                            &shouldCheckNumberOfBondedInteractions);
+            int cglo_flags = CGLO_GSTAT | CGLO_TEMPERATURE;
+            if (DOMAINDECOMP(cr) && shouldCheckNumberOfBondedInteractions(*cr->dd))
+            {
+                cglo_flags |= CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS;
+            }
+            compute_globals(gstat,
+                            cr,
+                            ir,
+                            fr,
+                            ekind,
+                            makeConstArrayRef(state->x),
+                            makeConstArrayRef(state->v),
+                            state->box,
+                            md,
+                            nrnb,
+                            &vcm,
+                            wcycle,
+                            enerd,
+                            nullptr,
+                            nullptr,
+                            nullptr,
+                            nullptr,
+                            gmx::ArrayRef<real>{},
+                            &nullSignaller,
+                            state->box,
+                            &bSumEkinhOld,
+                            cglo_flags);
+            if (DOMAINDECOMP(cr))
+            {
+                checkNumberOfBondedInteractions(
+                        mdlog, cr, top_global, &top, makeConstArrayRef(state->x), state->box);
+            }
         }
         clear_mat(force_vir);
 
@@ -882,13 +1099,14 @@ void gmx::LegacySimulator::do_md()
         {
             bCalcEnerStep = do_per_step(step, ir->nstcalcenergy);
             bCalcVir      = bCalcEnerStep
-                       || (ir->epc != epcNO
+                       || (ir->epc != PressureCoupling::No
                            && (do_per_step(step, ir->nstpcouple) || do_per_step(step - 1, ir->nstpcouple)));
         }
         else
         {
             bCalcEnerStep = do_per_step(step, ir->nstcalcenergy);
-            bCalcVir = bCalcEnerStep || (ir->epc != epcNO && do_per_step(step, ir->nstpcouple));
+            bCalcVir      = bCalcEnerStep
+                       || (ir->epc != PressureCoupling::No && do_per_step(step, ir->nstpcouple));
         }
         bCalcEner = bCalcEnerStep;
 
@@ -915,12 +1133,38 @@ void gmx::LegacySimulator::do_md()
         if (shellfc)
         {
             /* Now is the time to relax the shells */
-            relax_shell_flexcon(fplog, cr, ms, mdrunOptions.verbose, enforcedRotation, step, ir,
-                                imdSession, pull_work, bNS, force_flags, &top, constr, enerd,
-                                state->natoms, state->x.arrayRefWithPadding(),
-                                state->v.arrayRefWithPadding(), state->box, state->lambda,
-                                &state->hist, &f.view(), force_vir, mdatoms, nrnb, wcycle, shellfc,
-                                fr, runScheduleWork, t, mu_tot, vsite, ddBalanceRegionHandler);
+            relax_shell_flexcon(fplog,
+                                cr,
+                                ms,
+                                mdrunOptions.verbose,
+                                enforcedRotation,
+                                step,
+                                ir,
+                                imdSession,
+                                pull_work,
+                                bNS,
+                                force_flags,
+                                &top,
+                                constr,
+                                enerd,
+                                state->natoms,
+                                state->x.arrayRefWithPadding(),
+                                state->v.arrayRefWithPadding(),
+                                state->box,
+                                state->lambda,
+                                &state->hist,
+                                &f.view(),
+                                force_vir,
+                                *md,
+                                nrnb,
+                                wcycle,
+                                shellfc,
+                                fr,
+                                runScheduleWork,
+                                t,
+                                mu_tot,
+                                vsite,
+                                ddBalanceRegionHandler);
         }
         else
         {
@@ -942,161 +1186,91 @@ void gmx::LegacySimulator::do_md()
              * This is parallellized as well, and does communication too.
              * Check comments in sim_util.c
              */
-            do_force(fplog, cr, ms, ir, awh.get(), enforcedRotation, imdSession, pull_work, step,
-                     nrnb, wcycle, &top, state->box, state->x.arrayRefWithPadding(), &state->hist,
-                     &f.view(), force_vir, mdatoms, enerd, state->lambda, fr, runScheduleWork,
-                     vsite, mu_tot, t, ed ? ed->getLegacyED() : nullptr,
-                     (bNS ? GMX_FORCE_NS : 0) | force_flags, ddBalanceRegionHandler);
+            do_force(fplog,
+                     cr,
+                     ms,
+                     *ir,
+                     awh.get(),
+                     enforcedRotation,
+                     imdSession,
+                     pull_work,
+                     step,
+                     nrnb,
+                     wcycle,
+                     &top,
+                     state->box,
+                     state->x.arrayRefWithPadding(),
+                     &state->hist,
+                     &f.view(),
+                     force_vir,
+                     md,
+                     enerd,
+                     state->lambda,
+                     fr,
+                     runScheduleWork,
+                     vsite,
+                     mu_tot,
+                     t,
+                     ed ? ed->getLegacyED() : nullptr,
+                     (bNS ? GMX_FORCE_NS : 0) | force_flags,
+                     ddBalanceRegionHandler);
         }
 
         // VV integrators do not need the following velocity half step
         // if it is the first step after starting from a checkpoint.
         // That is, the half step is needed on all other steps, and
         // also the first step when starting from a .tpr file.
-        if (EI_VV(ir->eI) && (!bFirstStep || startingBehavior == StartingBehavior::NewSimulation))
-        /*  ############### START FIRST UPDATE HALF-STEP FOR VV METHODS############### */
-        {
-            rvec* vbuf = nullptr;
-
-            wallcycle_start(wcycle, ewcUPDATE);
-            if (ir->eI == eiVV && bInitStep)
-            {
-                /* if using velocity verlet with full time step Ekin,
-                 * take the first half step only to compute the
-                 * virial for the first step. From there,
-                 * revert back to the initial coordinates
-                 * so that the input is actually the initial step.
-                 */
-                snew(vbuf, state->natoms);
-                copy_rvecn(state->v.rvec_array(), vbuf, 0,
-                           state->natoms); /* should make this better for parallelizing? */
-            }
-            else
-            {
-                /* this is for NHC in the Ekin(t+dt/2) version of vv */
-                trotter_update(ir, step, ekind, enerd, state, total_vir, mdatoms, &MassQ,
-                               trotter_seq, ettTSEQ1);
-            }
-
-            upd.update_coords(*ir, step, mdatoms, state, f.view().forceWithPadding(), fcdata, ekind,
-                              M, etrtVELOCITY1, cr, constr != nullptr);
-
-            wallcycle_stop(wcycle, ewcUPDATE);
-            constrain_velocities(constr, do_log, do_ene, step, state, nullptr, bCalcVir, shake_vir);
-            wallcycle_start(wcycle, ewcUPDATE);
-            /* if VV, compute the pressure and constraints */
-            /* For VV2, we strictly only need this if using pressure
-             * control, but we really would like to have accurate pressures
-             * printed out.
-             * Think about ways around this in the future?
-             * For now, keep this choice in comments.
-             */
-            /*bPres = (ir->eI==eiVV || inputrecNptTrotter(ir)); */
-            /*bTemp = ((ir->eI==eiVV &&(!bInitStep)) || (ir->eI==eiVVAK && inputrecNptTrotter(ir)));*/
-            bPres = TRUE;
-            bTemp = ((ir->eI == eiVV && (!bInitStep)) || (ir->eI == eiVVAK));
-            if (bCalcEner && ir->eI == eiVVAK)
-            {
-                bSumEkinhOld = TRUE;
-            }
-            /* for vv, the first half of the integration actually corresponds to the previous step.
-               So we need information from the last step in the first half of the integration */
-            if (bGStat || do_per_step(step - 1, nstglobalcomm))
-            {
-                wallcycle_stop(wcycle, ewcUPDATE);
-                compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
-                                makeConstArrayRef(state->v), state->box, mdatoms, nrnb, &vcm, wcycle,
-                                enerd, force_vir, shake_vir, total_vir, pres, constr, &nullSignaller,
-                                state->box, &totalNumberOfBondedInteractions, &bSumEkinhOld,
-                                (bGStat ? CGLO_GSTAT : 0) | (bCalcEner ? CGLO_ENERGY : 0)
-                                        | (bTemp ? CGLO_TEMPERATURE : 0) | (bPres ? CGLO_PRESSURE : 0)
-                                        | (bPres ? CGLO_CONSTRAINT : 0) | (bStopCM ? CGLO_STOPCM : 0)
-                                        | (shouldCheckNumberOfBondedInteractions ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS
-                                                                                 : 0)
-                                        | CGLO_SCALEEKIN);
-                /* explanation of above:
-                   a) We compute Ekin at the full time step
-                   if 1) we are using the AveVel Ekin, and it's not the
-                   initial step, or 2) if we are using AveEkin, but need the full
-                   time step kinetic energy for the pressure (always true now, since we want accurate statistics).
-                   b) If we are using EkinAveEkin for the kinetic energy for the temperature control, we still feed in
-                   EkinAveVel because it's needed for the pressure */
-                checkNumberOfBondedInteractions(mdlog, cr, totalNumberOfBondedInteractions,
-                                                top_global, &top, makeConstArrayRef(state->x),
-                                                state->box, &shouldCheckNumberOfBondedInteractions);
-                if (bStopCM)
-                {
-                    process_and_stopcm_grp(fplog, &vcm, *mdatoms, makeArrayRef(state->x),
-                                           makeArrayRef(state->v));
-                    inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr);
-                }
-                wallcycle_start(wcycle, ewcUPDATE);
-            }
-            /* temperature scaling and pressure scaling to produce the extended variables at t+dt */
-            if (!bInitStep)
-            {
-                if (bTrotter)
-                {
-                    m_add(force_vir, shake_vir,
-                          total_vir); /* we need the un-dispersion corrected total vir here */
-                    trotter_update(ir, step, ekind, enerd, state, total_vir, mdatoms, &MassQ,
-                                   trotter_seq, ettTSEQ2);
-
-                    /* TODO This is only needed when we're about to write
-                     * a checkpoint, because we use it after the restart
-                     * (in a kludge?). But what should we be doing if
-                     * the startingBehavior is NewSimulation or bInitStep are true? */
-                    if (inputrecNptTrotter(ir) || inputrecNphTrotter(ir))
-                    {
-                        copy_mat(shake_vir, state->svir_prev);
-                        copy_mat(force_vir, state->fvir_prev);
-                    }
-                    if ((inputrecNptTrotter(ir) || inputrecNvtTrotter(ir)) && ir->eI == eiVV)
-                    {
-                        /* update temperature and kinetic energy now that step is over - this is the v(t+dt) point */
-                        enerd->term[F_TEMP] =
-                                sum_ekin(&(ir->opts), ekind, nullptr, (ir->eI == eiVV), FALSE);
-                        enerd->term[F_EKIN] = trace(ekind->ekin);
-                    }
-                }
-                else if (bExchanged)
-                {
-                    wallcycle_stop(wcycle, ewcUPDATE);
-                    /* We need the kinetic energy at minus the half step for determining
-                     * the full step kinetic energy and possibly for T-coupling.*/
-                    /* This may not be quite working correctly yet . . . . */
-                    compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
-                                    makeConstArrayRef(state->v), state->box, mdatoms, nrnb, &vcm, wcycle,
-                                    enerd, nullptr, nullptr, nullptr, nullptr, constr, &nullSignaller,
-                                    state->box, nullptr, &bSumEkinhOld, CGLO_GSTAT | CGLO_TEMPERATURE);
-                    wallcycle_start(wcycle, ewcUPDATE);
-                }
-            }
-            /* 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.rvec_array(), 0, state->natoms);
-                sfree(vbuf);
-            }
-            wallcycle_stop(wcycle, ewcUPDATE);
-        }
-
-        /* compute the conserved quantity */
         if (EI_VV(ir->eI))
         {
-            saved_conserved_quantity = NPT_energy(ir, state, &MassQ);
-            if (ir->eI == eiVV)
+            integrateVVFirstStep(step,
+                                 bFirstStep,
+                                 bInitStep,
+                                 startingBehavior,
+                                 nstglobalcomm,
+                                 ir,
+                                 fr,
+                                 cr,
+                                 state,
+                                 mdAtoms->mdatoms(),
+                                 fcdata,
+                                 &MassQ,
+                                 &vcm,
+                                 top_global,
+                                 top,
+                                 enerd,
+                                 ekind,
+                                 gstat,
+                                 &last_ekin,
+                                 bCalcVir,
+                                 total_vir,
+                                 shake_vir,
+                                 force_vir,
+                                 pres,
+                                 M,
+                                 do_log,
+                                 do_ene,
+                                 bCalcEner,
+                                 bGStat,
+                                 bStopCM,
+                                 bTrotter,
+                                 bExchanged,
+                                 &bSumEkinhOld,
+                                 &saved_conserved_quantity,
+                                 &f,
+                                 &upd,
+                                 constr,
+                                 &nullSignaller,
+                                 trotter_seq,
+                                 nrnb,
+                                 mdlog,
+                                 fplog,
+                                 wcycle);
+            if (vsite != nullptr && needVirtualVelocitiesThisStep)
             {
-                last_ekin = enerd->term[F_EKIN];
-            }
-            if ((ir->eDispCorr != edispcEnerPres) && (ir->eDispCorr != edispcAllEnerPres))
-            {
-                saved_conserved_quantity -= enerd->term[F_DISPCORR];
-            }
-            /* sum up the foreign kinetic energy and dK/dl terms for vv.  currently done every step so that dhdl is correct in the .edr */
-            if (ir->efep != efepNO)
-            {
-                accumulateKineticLambdaComponents(enerd, state->lambda, *ir->fepvals);
+                // Positions were calculated earlier
+                wallcycle_start(wcycle, WallCycleCounter::VsiteConstr);
+                vsite->construct(state->x, state->v, state->box, VSiteOperation::Velocities);
+                wallcycle_stop(wcycle, WallCycleCounter::VsiteConstr);
             }
         }
 
@@ -1108,9 +1282,22 @@ void gmx::LegacySimulator::do_md()
                actually move to the new state before outputting
                statistics, but if performing simulated tempering, we
                do update the velocities and the tau_t. */
-
-            lamnew = ExpandedEnsembleDynamics(fplog, ir, enerd, state, &MassQ, state->fep_state,
-                                              state->dfhist, step, state->v.rvec_array(), mdatoms);
+            // TODO: Avoid changing inputrec (#3854)
+            // Simulated tempering updates the reference temperature.
+            // Expanded ensemble without simulated tempering does not change the inputrec.
+            auto* nonConstInputrec = const_cast<t_inputrec*>(inputrec);
+            lamnew                 = ExpandedEnsembleDynamics(fplog,
+                                              nonConstInputrec,
+                                              enerd,
+                                              state,
+                                              &MassQ,
+                                              state->fep_state,
+                                              state->dfhist,
+                                              step,
+                                              state->v.rvec_array(),
+                                              md->homenr,
+                                              md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
+                                                      : gmx::ArrayRef<const unsigned short>());
             /* history is maintained in state->dfhist, but state_global is what is sent to trajectory and log output */
             if (MASTER(cr))
             {
@@ -1155,12 +1342,30 @@ void gmx::LegacySimulator::do_md()
          * coordinates at time t. We must output all of this before
          * the update.
          */
-        do_md_trajectory_writing(fplog, cr, nfile, fnm, step, step_rel, t, ir, state, state_global,
-                                 observablesHistory, top_global, fr, outf, energyOutput, ekind,
-                                 f.view().force(), checkpointHandler->isCheckpointingStep(),
-                                 bRerunMD, bLastStep, mdrunOptions.writeConfout, bSumEkinhOld);
+        do_md_trajectory_writing(fplog,
+                                 cr,
+                                 nfile,
+                                 fnm,
+                                 step,
+                                 step_rel,
+                                 t,
+                                 ir,
+                                 state,
+                                 state_global,
+                                 observablesHistory,
+                                 top_global,
+                                 fr,
+                                 outf,
+                                 energyOutput,
+                                 ekind,
+                                 f.view().force(),
+                                 checkpointHandler->isCheckpointingStep(),
+                                 bRerunMD,
+                                 bLastStep,
+                                 mdrunOptions.writeConfout,
+                                 bSumEkinhOld);
         /* Check if IMD step and do IMD communication, if bIMD is TRUE. */
-        bInteractiveMDstep = imdSession->run(step, bNS, state->box, state->x.rvec_array(), t);
+        bInteractiveMDstep = imdSession->run(step, bNS, state->box, state->x, t);
 
         /* kludge -- virial is lost with restart for MTTK NPT control. Must reload (saved earlier). */
         if (startingBehavior != StartingBehavior::NewSimulation && bFirstStep
@@ -1190,7 +1395,16 @@ void gmx::LegacySimulator::do_md()
         if (ETC_ANDERSEN(ir->etc)) /* keep this outside of update_tcouple because of the extra info required to pass */
         {
             gmx_bool bIfRandomize;
-            bIfRandomize = update_randomize_velocities(ir, step, cr, mdatoms, state->v, &upd, constr);
+            bIfRandomize = update_randomize_velocities(ir,
+                                                       step,
+                                                       cr,
+                                                       md->homenr,
+                                                       md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
+                                                               : gmx::ArrayRef<const unsigned short>(),
+                                                       gmx::arrayRefFromArray(md->invmass, md->nr),
+                                                       state->v,
+                                                       &upd,
+                                                       constr);
             /* if we have constraints, we have to remove the kinetic energy parallel to the bonds */
             if (constr && bIfRandomize)
             {
@@ -1208,12 +1422,24 @@ void gmx::LegacySimulator::do_md()
 
         if (!useGpuForUpdate)
         {
-            wallcycle_start(wcycle, ewcUPDATE);
+            wallcycle_start(wcycle, WallCycleCounter::Update);
         }
         /* UPDATE PRESSURE VARIABLES IN TROTTER FORMULATION WITH CONSTRAINTS */
         if (bTrotter)
         {
-            trotter_update(ir, step, ekind, enerd, state, total_vir, mdatoms, &MassQ, trotter_seq, ettTSEQ3);
+            trotter_update(ir,
+                           step,
+                           ekind,
+                           enerd,
+                           state,
+                           total_vir,
+                           md->homenr,
+                           md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
+                                   : gmx::ArrayRef<const unsigned short>(),
+                           gmx::arrayRefFromArray(md->invmass, md->nr),
+                           &MassQ,
+                           trotter_seq,
+                           ettTSEQ3);
             /* We can only do Berendsen coupling after we have summed
              * the kinetic energy or virial. Since the happens
              * in global_state after update, we should only do it at
@@ -1222,28 +1448,17 @@ void gmx::LegacySimulator::do_md()
         }
         else
         {
-            update_tcouple(step, ir, state, ekind, &MassQ, mdatoms);
+            update_tcouple(step,
+                           ir,
+                           state,
+                           ekind,
+                           &MassQ,
+                           md->homenr,
+                           md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
+                                   : gmx::ArrayRef<const unsigned short>());
             update_pcouple_before_coordinates(fplog, step, ir, state, pressureCouplingMu, M, bInitStep);
         }
 
-        if (EI_VV(ir->eI))
-        {
-            /* velocity half-step update */
-            upd.update_coords(*ir, step, mdatoms, state, f.view().forceWithPadding(), fcdata, ekind,
-                              M, etrtVELOCITY2, cr, constr != nullptr);
-        }
-
-        /* Above, initialize just copies ekinh into ekin,
-         * it doesn't copy position (for VV),
-         * and entire integrator for MD.
-         */
-
-        if (ir->eI == eiVVAK)
-        {
-            cbuf.resize(state->x.size());
-            std::copy(state->x.begin(), state->x.end(), cbuf.begin());
-        }
-
         /* With leap-frog type integrators we compute the kinetic energy
          * at a whole time step as the average of the half-time step kinetic
          * energies of two subsequent steps. Therefore we need to compute the
@@ -1254,144 +1469,191 @@ void gmx::LegacySimulator::do_md()
 
         // Parrinello-Rahman requires the pressure to be availible before the update to compute
         // the velocity scaling matrix. Hence, it runs one step after the nstpcouple step.
-        const bool doParrinelloRahman = (ir->epc == epcPARRINELLORAHMAN
+        const bool doParrinelloRahman = (ir->epc == PressureCoupling::ParrinelloRahman
                                          && do_per_step(step + ir->nstpcouple - 1, ir->nstpcouple));
 
-        if (useGpuForUpdate)
+        if (EI_VV(ir->eI))
         {
-            if (bNS && (bFirstStep || DOMAINDECOMP(cr)))
+            GMX_ASSERT(!useGpuForUpdate, "GPU update is not supported with VVAK integrator.");
+
+            integrateVVSecondStep(step,
+                                  ir,
+                                  fr,
+                                  cr,
+                                  state,
+                                  mdAtoms->mdatoms(),
+                                  fcdata,
+                                  &MassQ,
+                                  &vcm,
+                                  pull_work,
+                                  enerd,
+                                  ekind,
+                                  gstat,
+                                  &dvdl_constr,
+                                  bCalcVir,
+                                  total_vir,
+                                  shake_vir,
+                                  force_vir,
+                                  pres,
+                                  M,
+                                  lastbox,
+                                  do_log,
+                                  do_ene,
+                                  bGStat,
+                                  &bSumEkinhOld,
+                                  &f,
+                                  &cbuf,
+                                  &upd,
+                                  constr,
+                                  &nullSignaller,
+                                  trotter_seq,
+                                  nrnb,
+                                  wcycle);
+        }
+        else
+        {
+            if (useGpuForUpdate)
             {
-                integrator->set(stateGpu->getCoordinates(), stateGpu->getVelocities(),
-                                stateGpu->getForces(), top.idef, *mdatoms, ekind->ngtc);
+                if (bNS && (bFirstStep || DOMAINDECOMP(cr)))
+                {
+                    integrator->set(stateGpu->getCoordinates(),
+                                    stateGpu->getVelocities(),
+                                    stateGpu->getForces(),
+                                    top.idef,
+                                    *md);
+
+                    // Copy data to the GPU after buffers might have being reinitialized
+                    stateGpu->copyVelocitiesToGpu(state->v, AtomLocality::Local);
+                    stateGpu->copyCoordinatesToGpu(state->x, AtomLocality::Local);
+                }
 
-                // Copy data to the GPU after buffers might have being reinitialized
-                stateGpu->copyVelocitiesToGpu(state->v, AtomLocality::Local);
-                stateGpu->copyCoordinatesToGpu(state->x, AtomLocality::Local);
-            }
+                if (simulationWork.useGpuPme && !runScheduleWork->simulationWork.useGpuPmePpCommunication
+                    && !thisRankHasDuty(cr, DUTY_PME))
+                {
+                    // The PME forces were recieved to the host, so have to be copied
+                    stateGpu->copyForcesToGpu(f.view().force(), AtomLocality::All);
+                }
+                else if (!runScheduleWork->stepWork.useGpuFBufferOps)
+                {
+                    // The buffer ops were not offloaded this step, so the forces are on the
+                    // host and have to be copied
+                    stateGpu->copyForcesToGpu(f.view().force(), AtomLocality::Local);
+                }
 
-            if (simulationWork.useGpuPme && !runScheduleWork->simulationWork.useGpuPmePpCommunication
-                && !thisRankHasDuty(cr, DUTY_PME))
-            {
-                // The PME forces were recieved to the host, so have to be copied
-                stateGpu->copyForcesToGpu(f.view().force(), AtomLocality::All);
+                const bool doTemperatureScaling =
+                        (ir->etc != TemperatureCoupling::No
+                         && do_per_step(step + ir->nsttcouple - 1, ir->nsttcouple));
+
+                // This applies Leap-Frog, LINCS and SETTLE in succession
+                integrator->integrate(
+                        stateGpu->getForcesReadyOnDeviceEvent(
+                                AtomLocality::Local, runScheduleWork->stepWork.useGpuFBufferOps),
+                        ir->delta_t,
+                        true,
+                        bCalcVir,
+                        shake_vir,
+                        doTemperatureScaling,
+                        ekind->tcstat,
+                        doParrinelloRahman,
+                        ir->nstpcouple * ir->delta_t,
+                        M);
+
+                // Copy velocities D2H after update if:
+                // - Globals are computed this step (includes the energy output steps).
+                // - Temperature is needed for the next step.
+                if (bGStat || needHalfStepKineticEnergy)
+                {
+                    stateGpu->copyVelocitiesFromGpu(state->v, AtomLocality::Local);
+                    stateGpu->waitVelocitiesReadyOnHost(AtomLocality::Local);
+                }
             }
-            else if (!runScheduleWork->stepWork.useGpuFBufferOps)
+            else
             {
-                // The buffer ops were not offloaded this step, so the forces are on the
-                // host and have to be copied
-                stateGpu->copyForcesToGpu(f.view().force(), AtomLocality::Local);
-            }
-
-            const bool doTemperatureScaling =
-                    (ir->etc != etcNO && do_per_step(step + ir->nsttcouple - 1, ir->nsttcouple));
-
-            // This applies Leap-Frog, LINCS and SETTLE in succession
-            integrator->integrate(stateGpu->getForcesReadyOnDeviceEvent(
-                                          AtomLocality::Local, runScheduleWork->stepWork.useGpuFBufferOps),
-                                  ir->delta_t, true, bCalcVir, shake_vir, doTemperatureScaling,
-                                  ekind->tcstat, doParrinelloRahman, ir->nstpcouple * ir->delta_t, M);
+                /* With multiple time stepping we need to do an additional normal
+                 * update step to obtain the virial, as the actual MTS integration
+                 * using an acceleration where the slow forces are multiplied by mtsFactor.
+                 * Using that acceleration would result in a virial with the slow
+                 * force contribution would be a factor mtsFactor too large.
+                 */
+                if (fr->useMts && bCalcVir && constr != nullptr)
+                {
+                    upd.update_for_constraint_virial(*ir,
+                                                     md->homenr,
+                                                     md->havePartiallyFrozenAtoms,
+                                                     gmx::arrayRefFromArray(md->invmass, md->nr),
+                                                     gmx::arrayRefFromArray(md->invMassPerDim, md->nr),
+                                                     *state,
+                                                     f.view().forceWithPadding(),
+                                                     *ekind);
+
+                    constrain_coordinates(constr,
+                                          do_log,
+                                          do_ene,
+                                          step,
+                                          state,
+                                          upd.xp()->arrayRefWithPadding(),
+                                          &dvdl_constr,
+                                          bCalcVir,
+                                          shake_vir);
+                }
 
-            // Copy velocities D2H after update if:
-            // - Globals are computed this step (includes the energy output steps).
-            // - Temperature is needed for the next step.
-            if (bGStat || needHalfStepKineticEnergy)
-            {
-                stateGpu->copyVelocitiesFromGpu(state->v, AtomLocality::Local);
-                stateGpu->waitVelocitiesReadyOnHost(AtomLocality::Local);
+                ArrayRefWithPadding<const RVec> forceCombined =
+                        (fr->useMts && step % ir->mtsLevels[1].stepFactor == 0)
+                                ? f.view().forceMtsCombinedWithPadding()
+                                : f.view().forceWithPadding();
+                upd.update_coords(*ir,
+                                  step,
+                                  md->homenr,
+                                  md->havePartiallyFrozenAtoms,
+                                  gmx::arrayRefFromArray(md->ptype, md->nr),
+                                  gmx::arrayRefFromArray(md->invmass, md->nr),
+                                  gmx::arrayRefFromArray(md->invMassPerDim, md->nr),
+                                  state,
+                                  forceCombined,
+                                  fcdata,
+                                  ekind,
+                                  M,
+                                  etrtPOSITION,
+                                  cr,
+                                  constr != nullptr);
+
+                wallcycle_stop(wcycle, WallCycleCounter::Update);
+
+                constrain_coordinates(constr,
+                                      do_log,
+                                      do_ene,
+                                      step,
+                                      state,
+                                      upd.xp()->arrayRefWithPadding(),
+                                      &dvdl_constr,
+                                      bCalcVir && !fr->useMts,
+                                      shake_vir);
+
+                upd.update_sd_second_half(*ir,
+                                          step,
+                                          &dvdl_constr,
+                                          md->homenr,
+                                          gmx::arrayRefFromArray(md->ptype, md->nr),
+                                          gmx::arrayRefFromArray(md->invmass, md->nr),
+                                          state,
+                                          cr,
+                                          nrnb,
+                                          wcycle,
+                                          constr,
+                                          do_log,
+                                          do_ene);
+                upd.finish_update(
+                        *ir, md->havePartiallyFrozenAtoms, md->homenr, state, wcycle, constr != nullptr);
             }
-        }
-        else
-        {
-            /* With multiple time stepping we need to do an additional normal
-             * update step to obtain the virial, as the actual MTS integration
-             * using an acceleration where the slow forces are multiplied by mtsFactor.
-             * Using that acceleration would result in a virial with the slow
-             * force contribution would be a factor mtsFactor too large.
-             */
-            if (fr->useMts && bCalcVir && constr != nullptr)
-            {
-                upd.update_for_constraint_virial(*ir, *mdatoms, *state, f.view().forceWithPadding(), *ekind);
 
-                constrain_coordinates(constr, do_log, do_ene, step, state,
-                                      upd.xp()->arrayRefWithPadding(), &dvdl_constr, bCalcVir, shake_vir);
+            if (ir->bPull && ir->pull->bSetPbcRefToPrevStepCOM)
+            {
+                updatePrevStepPullCom(pull_work, state);
             }
 
-            ArrayRefWithPadding<const RVec> forceCombined =
-                    (fr->useMts && step % ir->mtsLevels[1].stepFactor == 0)
-                            ? f.view().forceMtsCombinedWithPadding()
-                            : f.view().forceWithPadding();
-            upd.update_coords(*ir, step, mdatoms, state, forceCombined, fcdata, ekind, M,
-                              etrtPOSITION, cr, constr != nullptr);
-
-            wallcycle_stop(wcycle, ewcUPDATE);
-
-            constrain_coordinates(constr, do_log, do_ene, step, state, upd.xp()->arrayRefWithPadding(),
-                                  &dvdl_constr, bCalcVir && !fr->useMts, shake_vir);
-
-            upd.update_sd_second_half(*ir, step, &dvdl_constr, mdatoms, state, cr, nrnb, wcycle,
-                                      constr, do_log, do_ene);
-            upd.finish_update(*ir, mdatoms, state, wcycle, constr != nullptr);
-        }
-
-        if (ir->bPull && ir->pull->bSetPbcRefToPrevStepCOM)
-        {
-            updatePrevStepPullCom(pull_work, state);
-        }
-
-        if (ir->eI == eiVVAK)
-        {
-            /* erase F_EKIN and F_TEMP here? */
-            /* just compute the kinetic energy at the half step to perform a trotter step */
-            compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
-                            makeConstArrayRef(state->v), state->box, mdatoms, nrnb, &vcm, wcycle, enerd,
-                            force_vir, shake_vir, total_vir, pres, constr, &nullSignaller, lastbox,
-                            nullptr, &bSumEkinhOld, (bGStat ? CGLO_GSTAT : 0) | CGLO_TEMPERATURE);
-            wallcycle_start(wcycle, ewcUPDATE);
-            trotter_update(ir, step, ekind, enerd, state, total_vir, mdatoms, &MassQ, trotter_seq, ettTSEQ4);
-            /* now we know the scaling, we can compute the positions again */
-            std::copy(cbuf.begin(), cbuf.end(), state->x.begin());
-
-            upd.update_coords(*ir, step, mdatoms, state, f.view().forceWithPadding(), fcdata, ekind,
-                              M, etrtPOSITION, cr, constr != nullptr);
-            wallcycle_stop(wcycle, ewcUPDATE);
-
-            /* 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*/
-            upd.finish_update(*ir, mdatoms, state, wcycle, false);
-        }
-        if (EI_VV(ir->eI))
-        {
-            /* this factor or 2 correction is necessary
-               because half of the constraint force is removed
-               in the vv step, so we have to double it.  See
-               the Issue #1255.  It is not yet clear
-               if the factor of 2 is exact, or just a very
-               good approximation, and this will be
-               investigated.  The next step is to see if this
-               can be done adding a dhdl contribution from the
-               rattle step, but this is somewhat more
-               complicated with the current code. Will be
-               investigated, hopefully for 4.6.3. However,
-               this current solution is much better than
-               having it completely wrong.
-             */
-            enerd->term[F_DVDL_CONSTR] += 2 * dvdl_constr;
-        }
-        else
-        {
             enerd->term[F_DVDL_CONSTR] += dvdl_constr;
         }
 
-        if (vsite != nullptr)
-        {
-            wallcycle_start(wcycle, ewcVSITECONSTR);
-            vsite->construct(state->x, ir->delta_t, state->v, state->box);
-            wallcycle_stop(wcycle, ewcVSITECONSTR);
-        }
-
         /* ############## IF NOT VV, Calculate globals HERE  ############ */
         /* With Leap-Frog we can skip compute_globals at
          * non-communication steps, but we need to calculate
@@ -1420,24 +1682,46 @@ void gmx::LegacySimulator::do_md()
                 bool                doIntraSimSignal = true;
                 SimulationSignaller signaller(&signals, cr, ms, doInterSimSignal, doIntraSimSignal);
 
-                compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
-                                makeConstArrayRef(state->v), state->box, mdatoms, nrnb, &vcm,
-                                wcycle, enerd, force_vir, shake_vir, total_vir, pres, constr,
-                                &signaller, lastbox, &totalNumberOfBondedInteractions, &bSumEkinhOld,
-                                (bGStat ? CGLO_GSTAT : 0) | (!EI_VV(ir->eI) && bCalcEner ? CGLO_ENERGY : 0)
-                                        | (!EI_VV(ir->eI) && bStopCM ? CGLO_STOPCM : 0)
-                                        | (!EI_VV(ir->eI) ? CGLO_TEMPERATURE : 0)
-                                        | (!EI_VV(ir->eI) ? CGLO_PRESSURE : 0) | CGLO_CONSTRAINT
-                                        | (shouldCheckNumberOfBondedInteractions ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS
-                                                                                 : 0));
-                checkNumberOfBondedInteractions(mdlog, cr, totalNumberOfBondedInteractions,
-                                                top_global, &top, makeConstArrayRef(state->x),
-                                                state->box, &shouldCheckNumberOfBondedInteractions);
+                compute_globals(
+                        gstat,
+                        cr,
+                        ir,
+                        fr,
+                        ekind,
+                        makeConstArrayRef(state->x),
+                        makeConstArrayRef(state->v),
+                        state->box,
+                        md,
+                        nrnb,
+                        &vcm,
+                        wcycle,
+                        enerd,
+                        force_vir,
+                        shake_vir,
+                        total_vir,
+                        pres,
+                        (!EI_VV(ir->eI) && bCalcEner && constr != nullptr) ? constr->rmsdData()
+                                                                           : gmx::ArrayRef<real>{},
+                        &signaller,
+                        lastbox,
+                        &bSumEkinhOld,
+                        (bGStat ? CGLO_GSTAT : 0) | (!EI_VV(ir->eI) && bCalcEner ? CGLO_ENERGY : 0)
+                                | (!EI_VV(ir->eI) && bStopCM ? CGLO_STOPCM : 0)
+                                | (!EI_VV(ir->eI) ? CGLO_TEMPERATURE : 0)
+                                | (!EI_VV(ir->eI) ? CGLO_PRESSURE : 0) | CGLO_CONSTRAINT
+                                | (DOMAINDECOMP(cr) && shouldCheckNumberOfBondedInteractions(*cr->dd)
+                                           ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS
+                                           : 0));
+                if (DOMAINDECOMP(cr))
+                {
+                    checkNumberOfBondedInteractions(
+                            mdlog, cr, top_global, &top, makeConstArrayRef(state->x), state->box);
+                }
                 if (!EI_VV(ir->eI) && bStopCM)
                 {
-                    process_and_stopcm_grp(fplog, &vcm, *mdatoms, makeArrayRef(state->x),
-                                           makeArrayRef(state->v));
-                    inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr);
+                    process_and_stopcm_grp(
+                            fplog, &vcm, *md, makeArrayRef(state->x), makeArrayRef(state->v));
+                    inc_nrnb(nrnb, eNR_STOPCM, md->homenr);
 
                     // TODO: The special case of removing CM motion should be dealt more gracefully
                     if (useGpuForUpdate)
@@ -1448,7 +1732,7 @@ void gmx::LegacySimulator::do_md()
                         // (not because of a race on state->x being modified on the CPU while H2D is in progress).
                         stateGpu->waitCoordinatesCopiedToDevice(AtomLocality::Local);
                         // If the COM removal changed the velocities on the CPU, this has to be accounted for.
-                        if (vcm.mode != ecmNO)
+                        if (vcm.mode != ComRemovalAlgorithm::No)
                         {
                             stateGpu->copyVelocitiesToGpu(state->v, AtomLocality::Local);
                         }
@@ -1464,20 +1748,32 @@ void gmx::LegacySimulator::do_md()
            but what we actually need entering the new cycle is the new shake_vir value. Ideally, we could
            generate the new shake_vir, but test the veta value for convergence.  This will take some thought. */
 
-        if (ir->efep != efepNO && !EI_VV(ir->eI))
+        if (ir->efep != FreeEnergyPerturbationType::No && !EI_VV(ir->eI))
         {
             /* Sum up the foreign energy and dK/dl terms for md and sd.
                Currently done every step so that dH/dl is correct in the .edr */
             accumulateKineticLambdaComponents(enerd, state->lambda, *ir->fepvals);
         }
 
-        update_pcouple_after_coordinates(fplog, step, ir, mdatoms, pres, force_vir, shake_vir,
-                                         pressureCouplingMu, state, nrnb, upd.deform(), !useGpuForUpdate);
-
-        const bool doBerendsenPressureCoupling =
-                (inputrec->epc == epcBERENDSEN && do_per_step(step, inputrec->nstpcouple));
-        const bool doCRescalePressureCoupling =
-                (inputrec->epc == epcCRESCALE && do_per_step(step, inputrec->nstpcouple));
+        update_pcouple_after_coordinates(fplog,
+                                         step,
+                                         ir,
+                                         md->homenr,
+                                         md->cFREEZE ? gmx::arrayRefFromArray(md->cFREEZE, md->nr)
+                                                     : gmx::ArrayRef<const unsigned short>(),
+                                         pres,
+                                         force_vir,
+                                         shake_vir,
+                                         pressureCouplingMu,
+                                         state,
+                                         nrnb,
+                                         upd.deform(),
+                                         !useGpuForUpdate);
+
+        const bool doBerendsenPressureCoupling = (inputrec->epc == PressureCoupling::Berendsen
+                                                  && do_per_step(step, inputrec->nstpcouple));
+        const bool doCRescalePressureCoupling  = (inputrec->epc == PressureCoupling::CRescale
+                                                 && do_per_step(step, inputrec->nstpcouple));
         if (useGpuForUpdate
             && (doBerendsenPressureCoupling || doCRescalePressureCoupling || doParrinelloRahman))
         {
@@ -1508,7 +1804,7 @@ void gmx::LegacySimulator::do_md()
             /* #########  BEGIN PREPARING EDR OUTPUT  ###########  */
 
             /* use the directly determined last velocity, not actually the averaged half steps */
-            if (bTrotter && ir->eI == eiVV)
+            if (bTrotter && ir->eI == IntegrationAlgorithm::VV)
             {
                 enerd->term[F_EKIN] = last_ekin;
             }
@@ -1534,18 +1830,38 @@ void gmx::LegacySimulator::do_md()
             if (fplog && do_log && bDoExpanded)
             {
                 /* only needed if doing expanded ensemble */
-                PrintFreeEnergyInfoToFile(fplog, ir->fepvals, ir->expandedvals,
-                                          ir->bSimTemp ? ir->simtempvals : nullptr,
-                                          state_global->dfhist, state->fep_state, ir->nstlog, step);
+                PrintFreeEnergyInfoToFile(fplog,
+                                          ir->fepvals.get(),
+                                          ir->expandedvals.get(),
+                                          ir->bSimTemp ? ir->simtempvals.get() : nullptr,
+                                          state_global->dfhist,
+                                          state->fep_state,
+                                          ir->nstlog,
+                                          step);
             }
             if (bCalcEner)
             {
-                energyOutput.addDataAtEnergyStep(
-                        bDoDHDL, bCalcEnerStep, t, mdatoms->tmass, enerd, ir->fepvals,
-                        ir->expandedvals, lastbox,
-                        PTCouplingArrays{ state->boxv, state->nosehoover_xi, state->nosehoover_vxi,
-                                          state->nhpres_xi, state->nhpres_vxi },
-                        state->fep_state, shake_vir, force_vir, total_vir, pres, ekind, mu_tot, constr);
+                energyOutput.addDataAtEnergyStep(bDoDHDL,
+                                                 bCalcEnerStep,
+                                                 t,
+                                                 md->tmass,
+                                                 enerd,
+                                                 ir->fepvals.get(),
+                                                 ir->expandedvals.get(),
+                                                 lastbox,
+                                                 PTCouplingArrays{ state->boxv,
+                                                                   state->nosehoover_xi,
+                                                                   state->nosehoover_vxi,
+                                                                   state->nhpres_xi,
+                                                                   state->nhpres_vxi },
+                                                 state->fep_state,
+                                                 shake_vir,
+                                                 force_vir,
+                                                 total_vir,
+                                                 pres,
+                                                 ekind,
+                                                 mu_tot,
+                                                 constr);
             }
             else
             {
@@ -1557,14 +1873,20 @@ void gmx::LegacySimulator::do_md()
 
             if (doSimulatedAnnealing)
             {
-                gmx::EnergyOutput::printAnnealingTemperatures(do_log ? fplog : nullptr, groups,
-                                                              &(ir->opts));
+                gmx::EnergyOutput::printAnnealingTemperatures(
+                        do_log ? fplog : nullptr, groups, &(ir->opts));
             }
             if (do_log || do_ene || do_dr || do_or)
             {
-                energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf), do_ene, do_dr, do_or,
-                                                   do_log ? fplog : nullptr, step, t,
-                                                   fr->fcdata.get(), awh.get());
+                energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf),
+                                                   do_ene,
+                                                   do_dr,
+                                                   do_or,
+                                                   do_log ? fplog : nullptr,
+                                                   step,
+                                                   t,
+                                                   fr->fcdata.get(),
+                                                   awh.get());
             }
             if (do_log && ir->bDoAwh && awh->hasFepLambdaDimension())
             {
@@ -1609,11 +1931,19 @@ void gmx::LegacySimulator::do_md()
          * Not done in last step since trajectory writing happens before this call
          * in the MD loop and exchanges would be lost anyway. */
         bNeedRepartition = FALSE;
-        if ((ir->eSwapCoords != eswapNO) && (step > 0) && !bLastStep && do_per_step(step, ir->swap->nstswap))
-        {
-            bNeedRepartition =
-                    do_swapcoords(cr, step, t, ir, swap, wcycle, as_rvec_array(state->x.data()),
-                                  state->box, MASTER(cr) && mdrunOptions.verbose, bRerunMD);
+        if ((ir->eSwapCoords != SwapType::No) && (step > 0) && !bLastStep
+            && do_per_step(step, ir->swap->nstswap))
+        {
+            bNeedRepartition = do_swapcoords(cr,
+                                             step,
+                                             t,
+                                             ir,
+                                             swap,
+                                             wcycle,
+                                             as_rvec_array(state->x.data()),
+                                             state->box,
+                                             MASTER(cr) && mdrunOptions.verbose,
+                                             bRerunMD);
 
             if (bNeedRepartition && DOMAINDECOMP(cr))
             {
@@ -1630,11 +1960,32 @@ void gmx::LegacySimulator::do_md()
 
         if ((bExchanged || bNeedRepartition) && DOMAINDECOMP(cr))
         {
-            dd_partition_system(fplog, mdlog, step, cr, TRUE, 1, state_global, *top_global, ir,
-                                imdSession, pull_work, state, &f, mdAtoms, &top, fr, vsite, constr,
-                                nrnb, wcycle, FALSE);
-            shouldCheckNumberOfBondedInteractions = true;
-            upd.setNumAtoms(state->natoms);
+            dd_partition_system(fplog,
+                                mdlog,
+                                step,
+                                cr,
+                                TRUE,
+                                1,
+                                state_global,
+                                top_global,
+                                *ir,
+                                imdSession,
+                                pull_work,
+                                state,
+                                &f,
+                                mdAtoms,
+                                &top,
+                                fr,
+                                vsite,
+                                constr,
+                                nrnb,
+                                wcycle,
+                                FALSE);
+            upd.updateAfterPartition(state->natoms,
+                                     md->cFREEZE ? gmx::arrayRefFromArray(md->cFREEZE, md->nr)
+                                                 : gmx::ArrayRef<const unsigned short>(),
+                                     md->cTC ? gmx::arrayRefFromArray(md->cTC, md->nr)
+                                             : gmx::ArrayRef<const unsigned short>());
         }
 
         bFirstStep = FALSE;
@@ -1644,7 +1995,7 @@ void gmx::LegacySimulator::do_md()
         /* With all integrators, except VV, we need to retain the pressure
          * at the current step for coupling at the next step.
          */
-        if ((state->flags & (1U << estPRES_PREV))
+        if ((state->flags & enumValueToBitMask(StateEntry::PressurePrevious))
             && (bGStatEveryStep || (ir->nstpcouple > 0 && step % ir->nstpcouple == 0)))
         {
             /* Store the pressure in t_state for pressure coupling
@@ -1660,7 +2011,7 @@ void gmx::LegacySimulator::do_md()
             rescale_membed(step_rel, membed, as_rvec_array(state_global->x.data()));
         }
 
-        cycles = wallcycle_stop(wcycle, ewcSTEP);
+        cycles = wallcycle_stop(wcycle, WallCycleCounter::Step);
         if (DOMAINDECOMP(cr) && wcycle)
         {
             dd_cycles_add(cr->dd, cycles, ddCyclStep);
@@ -1677,8 +2028,8 @@ void gmx::LegacySimulator::do_md()
         }
 #endif
 
-        resetHandler->resetCounters(step, step_rel, mdlog, fplog, cr, fr->nbv.get(), nrnb,
-                                    fr->pmedata, pme_loadbal, wcycle, walltime_accounting);
+        resetHandler->resetCounters(
+                step, step_rel, mdlog, fplog, cr, fr->nbv.get(), nrnb, fr->pmedata, pme_loadbal, wcycle, walltime_accounting);
 
         /* If bIMD is TRUE, the master updates the IMD energy record and sends positions to VMD client */
         imdSession->updateEnergyRecordAndSendPositionsAndEnergies(bInteractiveMDstep, step, bCalcEner);
index 1014a0adde1933fa711ff80d20f16746abd7d021..9022b26e80c1dad7548a6f06614dfb4bff5fbe8e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +53,7 @@
 #include "gromacs/utility/keyvaluetree.h"
 #include "gromacs/utility/keyvaluetreebuilder.h"
 #include "gromacs/utility/keyvaluetreetransform.h"
-#include "gromacs/utility/mdmodulenotification.h"
+#include "gromacs/utility/mdmodulesnotifiers.h"
 #include "gromacs/utility/smalloc.h"
 
 namespace gmx
@@ -70,7 +70,7 @@ public:
     {
     }
 
-    void makeModuleOptions(Options* options)
+    void makeModuleOptions(Options* options) const
     {
         // Create a section for applied-forces modules
         auto appliedForcesOptions = options->addSection(OptionSection("applied-forces"));
@@ -96,7 +96,7 @@ public:
      * \note The notifier must be constructed before the modules and shall
      *       not be destructed before the modules are destructed.
      */
-    MdModulesNotifier notifier_;
+    MDModulesNotifiers notifiers_;
 
     std::unique_ptr<IMDModule>      densityFitting_;
     std::unique_ptr<IMDModule>      field_;
@@ -176,12 +176,12 @@ ForceProviders* MDModules::initForceProviders()
 
 void MDModules::subscribeToPreProcessingNotifications()
 {
-    impl_->densityFitting_->subscribeToPreProcessingNotifications(&impl_->notifier_);
+    impl_->densityFitting_->subscribeToPreProcessingNotifications(&impl_->notifiers_);
 }
 
 void MDModules::subscribeToSimulationSetupNotifications()
 {
-    impl_->densityFitting_->subscribeToSimulationSetupNotifications(&impl_->notifier_);
+    impl_->densityFitting_->subscribeToSimulationSetupNotifications(&impl_->notifiers_);
 }
 
 void MDModules::add(std::shared_ptr<gmx::IMDModule> module)
@@ -189,9 +189,9 @@ void MDModules::add(std::shared_ptr<gmx::IMDModule> module)
     impl_->modules_.emplace_back(std::move(module));
 }
 
-const MdModulesNotifier& MDModules::notifier()
+const MDModulesNotifiers& MDModules::notifiers()
 {
-    return impl_->notifier_;
+    return impl_->notifiers_;
 }
 
 } // namespace gmx
index 6fabb761cd3854fb41bbfcd35548cb2b559ce9fa..1bd23fd2371e09e12f56966b800d07bbc907dbe6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +43,7 @@
 #ifndef GMX_MDRUN_MDMODULES_H
 #define GMX_MDRUN_MDMODULES_H
 
-#include "gromacs/utility/classhelpers.h"
+#include <memory>
 
 
 struct t_inputrec;
@@ -58,7 +58,7 @@ class IKeyValueTreeErrorHandler;
 class IKeyValueTreeTransformRules;
 class IMDModule;
 class IMDOutputProvider;
-struct MdModulesNotifier;
+struct MDModulesNotifiers;
 
 /*! \libinternal \brief
  * Manages the collection of all modules used for mdrun.
@@ -144,17 +144,17 @@ public:
      */
     ForceProviders* initForceProviders();
 
-    /*! \brief Subscribe MdModules to simulation setup notifications.
+    /*! \brief Subscribe MDModules to simulation setup notifications.
      *
-     * Allows MdModules to subscribe to notifications that are called back
+     * Allows MDModules to subscribe to notifications that are called back
      * during the set up of an MD simulation, after the options were
      * assigned to the modules.
      */
     void subscribeToSimulationSetupNotifications();
 
-    /*! \brief Subscribe MdModules to notifications during pre-processing.
+    /*! \brief Subscribe MDModules to notifications during pre-processing.
      *
-     * Allows MdModules to subscribe to notifications that are called back
+     * Allows MDModules to subscribe to notifications that are called back
      * during pre processing an MD simulation, after the options were
      * assigned to the modules.
      */
@@ -184,14 +184,14 @@ public:
      */
     void add(std::shared_ptr<IMDModule> module);
 
-    /*! \brief Return a handle to the callbacks.
+    /*! \brief Return a handle to the notifiers used for callbacks between modules.
      */
-    const MdModulesNotifier& notifier();
+    const MDModulesNotifiers& notifiers();
 
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index e37d921c5a768584f9499e7750f214ec3d59dee5..c014f5ae2573ca99e87dd875df20e71bde844601 100644 (file)
@@ -141,7 +141,7 @@ using gmx::SimulationSignaller;
 
 void gmx::LegacySimulator::do_mimic()
 {
-    t_inputrec*       ir = inputrec;
+    const t_inputrec* ir = inputrec;
     int64_t           step, step_rel;
     double            t;
     bool              isLastStep               = false;
@@ -155,15 +155,6 @@ void gmx::LegacySimulator::do_mimic()
 
     double cycles;
 
-    /* Domain decomposition could incorrectly miss a bonded
-       interaction, but checking for that requires a global
-       communication stage, which does not otherwise happen in DD
-       code. So we do that alongside the first global energy reduction
-       after a new DD is made. These variables handle whether the
-       check happens, and the result it returns. */
-    bool shouldCheckNumberOfBondedInteractions = false;
-    int  totalNumberOfBondedInteractions       = -1;
-
     SimulationSignals signals;
     // Most global communnication stages don't propagate mdrun
     // signals, and will use this object to achieve that.
@@ -197,52 +188,93 @@ void gmx::LegacySimulator::do_mimic()
     {
         gmx_fatal(FARGS, "Multiple simulations not supported by MiMiC.");
     }
-    if (std::any_of(ir->opts.annealing, ir->opts.annealing + ir->opts.ngtc,
-                    [](int i) { return i != eannNO; }))
+    if (std::any_of(ir->opts.annealing, ir->opts.annealing + ir->opts.ngtc, [](SimulatedAnnealing i) {
+            return i != SimulatedAnnealing::No;
+        }))
     {
         gmx_fatal(FARGS, "Simulated annealing not supported by MiMiC.");
     }
 
     /* Settings for rerun */
-    ir->nstlist              = 1;
-    ir->nstcalcenergy        = 1;
+    {
+        // TODO: Avoid changing inputrec (#3854)
+        auto* nonConstInputrec               = const_cast<t_inputrec*>(inputrec);
+        nonConstInputrec->nstlist            = 1;
+        nonConstInputrec->nstcalcenergy      = 1;
+        nonConstInputrec->nstxout_compressed = 0;
+    }
     int        nstglobalcomm = 1;
     const bool bNS           = true;
 
     if (MASTER(cr))
     {
         MimicCommunicator::init();
-        auto nonConstGlobalTopology = const_cast<gmx_mtop_t*>(top_global);
+        auto* nonConstGlobalTopology = const_cast<gmx_mtop_t*>(&top_global);
         MimicCommunicator::sendInitData(nonConstGlobalTopology, state_global->x);
-        ir->nsteps = MimicCommunicator::getStepNumber();
+        // TODO: Avoid changing inputrec (#3854)
+        auto* nonConstInputrec   = const_cast<t_inputrec*>(inputrec);
+        nonConstInputrec->nsteps = MimicCommunicator::getStepNumber();
+    }
+    if (DOMAINDECOMP(cr))
+    {
+        // TODO: Avoid changing inputrec (#3854)
+        auto* nonConstInputrec = const_cast<t_inputrec*>(inputrec);
+        gmx_bcast(sizeof(ir->nsteps), &nonConstInputrec->nsteps, cr->mpi_comm_mygroup);
     }
 
-    ir->nstxout_compressed         = 0;
-    const SimulationGroups* groups = &top_global->groups;
+    const SimulationGroups* groups = &top_global.groups;
     {
-        auto nonConstGlobalTopology                          = const_cast<gmx_mtop_t*>(top_global);
-        nonConstGlobalTopology->intermolecularExclusionGroup = genQmmmIndices(*top_global);
+        auto* nonConstGlobalTopology                         = const_cast<gmx_mtop_t*>(&top_global);
+        nonConstGlobalTopology->intermolecularExclusionGroup = genQmmmIndices(top_global);
     }
 
-    initialize_lambdas(fplog, *ir, MASTER(cr), &state_global->fep_state, state_global->lambda);
+    initialize_lambdas(fplog,
+                       ir->efep,
+                       ir->bSimTemp,
+                       *ir->fepvals,
+                       ir->simtempvals->temperatures,
+                       gmx::arrayRefFromArray(ir->opts.ref_t, ir->opts.ngtc),
+                       MASTER(cr),
+                       &state_global->fep_state,
+                       state_global->lambda);
 
     const bool        simulationsShareState = false;
-    gmx_mdoutf*       outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider,
-                                   mdModulesNotifier, ir, top_global, oenv, wcycle,
-                                   StartingBehavior::NewSimulation, simulationsShareState, ms);
-    gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf), top_global, ir, pull_work,
-                                   mdoutf_get_fp_dhdl(outf), true, StartingBehavior::NewSimulation,
-                                   simulationsShareState, mdModulesNotifier);
+    gmx_mdoutf*       outf                  = init_mdoutf(fplog,
+                                   nfile,
+                                   fnm,
+                                   mdrunOptions,
+                                   cr,
+                                   outputProvider,
+                                   mdModulesNotifiers,
+                                   ir,
+                                   top_global,
+                                   oenv,
+                                   wcycle,
+                                   StartingBehavior::NewSimulation,
+                                   simulationsShareState,
+                                   ms);
+    gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf),
+                                   top_global,
+                                   *ir,
+                                   pull_work,
+                                   mdoutf_get_fp_dhdl(outf),
+                                   true,
+                                   StartingBehavior::NewSimulation,
+                                   simulationsShareState,
+                                   mdModulesNotifiers);
 
     gstat = global_stat_init(ir);
 
     /* Check for polarizable models and flexible constraints */
-    shellfc = init_shell_flexcon(fplog, top_global, constr ? constr->numFlexibleConstraints() : 0,
-                                 ir->nstcalcenergy, DOMAINDECOMP(cr),
+    shellfc = init_shell_flexcon(fplog,
+                                 top_global,
+                                 constr ? constr->numFlexibleConstraints() : 0,
+                                 ir->nstcalcenergy,
+                                 DOMAINDECOMP(cr),
                                  runScheduleWork->simulationWork.useGpuPme);
 
     {
-        double io = compute_io(ir, top_global->natoms, *groups, energyOutput.numEnergyTerms(), 1);
+        double io = compute_io(ir, top_global.natoms, *groups, energyOutput.numEnergyTerms(), 1);
         if ((io > 2000) && MASTER(cr))
         {
             fprintf(stderr, "\nWARNING: This run will generate roughly %.0f Mb of data\n\n", io);
@@ -253,20 +285,36 @@ void gmx::LegacySimulator::do_mimic()
     std::unique_ptr<t_state> stateInstance;
     t_state*                 state;
 
-    gmx_localtop_t top(top_global->ffparams);
+    gmx_localtop_t top(top_global.ffparams);
 
     if (DOMAINDECOMP(cr))
     {
         stateInstance = std::make_unique<t_state>();
         state         = stateInstance.get();
-        dd_init_local_state(cr->dd, state_global, state);
+        dd_init_local_state(*cr->dd, state_global, state);
 
         /* Distribute the charge groups over the nodes from the master node */
-        dd_partition_system(fplog, mdlog, ir->init_step, cr, TRUE, 1, state_global, *top_global, ir,
-                            imdSession, pull_work, state, &f, mdAtoms, &top, fr, vsite, constr,
-                            nrnb, nullptr, FALSE);
-        shouldCheckNumberOfBondedInteractions = true;
-        gmx_bcast(sizeof(ir->nsteps), &ir->nsteps, cr->mpi_comm_mygroup);
+        dd_partition_system(fplog,
+                            mdlog,
+                            ir->init_step,
+                            cr,
+                            TRUE,
+                            1,
+                            state_global,
+                            top_global,
+                            *ir,
+                            imdSession,
+                            pull_work,
+                            state,
+                            &f,
+                            mdAtoms,
+                            &top,
+                            fr,
+                            vsite,
+                            constr,
+                            nrnb,
+                            nullptr,
+                            FALSE);
     }
     else
     {
@@ -274,41 +322,63 @@ void gmx::LegacySimulator::do_mimic()
         /* Copy the pointer to the global state */
         state = state_global;
 
-        mdAlgorithmsSetupAtomData(cr, ir, *top_global, &top, fr, &f, mdAtoms, constr, vsite, shellfc);
+        mdAlgorithmsSetupAtomData(cr, *ir, top_global, &top, fr, &f, mdAtoms, constr, vsite, shellfc);
     }
 
-    auto mdatoms = mdAtoms->mdatoms();
+    auto* mdatoms = mdAtoms->mdatoms();
 
     // NOTE: The global state is no longer used at this point.
     // But state_global is still used as temporary storage space for writing
     // the global state to file and potentially for replica exchange.
     // (Global topology should persist.)
 
-    update_mdatoms(mdatoms, state->lambda[efptMASS]);
+    update_mdatoms(mdatoms, state->lambda[FreeEnergyPerturbationCouplingType::Mass]);
 
-    if (ir->efep != efepNO && ir->fepvals->nstdhdl != 0)
+    if (ir->efep != FreeEnergyPerturbationType::No && ir->fepvals->nstdhdl != 0)
     {
         doFreeEnergyPerturbation = true;
     }
 
     {
-        int cglo_flags =
-                (CGLO_GSTAT
-                 | (shouldCheckNumberOfBondedInteractions ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS : 0));
+        int cglo_flags = CGLO_GSTAT;
+        if (DOMAINDECOMP(cr) && shouldCheckNumberOfBondedInteractions(*cr->dd))
+        {
+            cglo_flags |= CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS;
+        }
         bool   bSumEkinhOld = false;
         t_vcm* vcm          = nullptr;
-        compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
-                        makeConstArrayRef(state->v), state->box, mdatoms, nrnb, vcm, nullptr, enerd,
-                        force_vir, shake_vir, total_vir, pres, constr, &nullSignaller, state->box,
-                        &totalNumberOfBondedInteractions, &bSumEkinhOld, cglo_flags);
+        compute_globals(gstat,
+                        cr,
+                        ir,
+                        fr,
+                        ekind,
+                        makeConstArrayRef(state->x),
+                        makeConstArrayRef(state->v),
+                        state->box,
+                        mdatoms,
+                        nrnb,
+                        vcm,
+                        nullptr,
+                        enerd,
+                        force_vir,
+                        shake_vir,
+                        total_vir,
+                        pres,
+                        gmx::ArrayRef<real>{},
+                        &nullSignaller,
+                        state->box,
+                        &bSumEkinhOld,
+                        cglo_flags);
+        if (DOMAINDECOMP(cr))
+        {
+            checkNumberOfBondedInteractions(
+                    mdlog, cr, top_global, &top, makeConstArrayRef(state->x), state->box);
+        }
     }
-    checkNumberOfBondedInteractions(mdlog, cr, totalNumberOfBondedInteractions, top_global, &top,
-                                    makeConstArrayRef(state->x), state->box,
-                                    &shouldCheckNumberOfBondedInteractions);
 
     if (MASTER(cr))
     {
-        fprintf(stderr, "starting MiMiC MD run '%s'\n\n", *(top_global->name));
+        fprintf(stderr, "starting MiMiC MD run '%s'\n\n", *(top_global.name));
         if (mdrunOptions.verbose)
         {
             fprintf(stderr,
@@ -320,7 +390,7 @@ void gmx::LegacySimulator::do_mimic()
     }
 
     walltime_accounting_start_time(walltime_accounting);
-    wallcycle_start(wcycle, ewcRUN);
+    wallcycle_start(wcycle, WallCycleCounter::Run);
     print_start(fplog, cr, walltime_accounting, "mdrun");
 
     /***********************************************************
@@ -348,9 +418,18 @@ void gmx::LegacySimulator::do_mimic()
     step_rel = 0;
 
     auto stopHandler = stopHandlerBuilder->getStopHandlerMD(
-            compat::not_null<SimulationSignal*>(&signals[eglsSTOPCOND]), false, MASTER(cr),
-            ir->nstlist, mdrunOptions.reproducible, nstglobalcomm, mdrunOptions.maximumHoursToRun,
-            ir->nstlist == 0, fplog, step, bNS, walltime_accounting);
+            compat::not_null<SimulationSignal*>(&signals[eglsSTOPCOND]),
+            false,
+            MASTER(cr),
+            ir->nstlist,
+            mdrunOptions.reproducible,
+            nstglobalcomm,
+            mdrunOptions.maximumHoursToRun,
+            ir->nstlist == 0,
+            fplog,
+            step,
+            bNS,
+            walltime_accounting);
 
     // we don't do counter resetting in rerun - finish will always be valid
     walltime_accounting_set_valid_finish(walltime_accounting);
@@ -362,7 +441,7 @@ void gmx::LegacySimulator::do_mimic()
     while (!isLastStep)
     {
         isLastStep = (isLastStep || (ir->nsteps >= 0 && step_rel == ir->nsteps));
-        wallcycle_start(wcycle, ewcSTEP);
+        wallcycle_start(wcycle, WallCycleCounter::Step);
 
         t = step;
 
@@ -371,7 +450,7 @@ void gmx::LegacySimulator::do_mimic()
             MimicCommunicator::getCoords(&state_global->x, state_global->natoms);
         }
 
-        if (ir->efep != efepNO)
+        if (ir->efep != FreeEnergyPerturbationType::No)
         {
             state->lambda = currentLambdas(step, *(ir->fepvals), state_global->fep_state);
         }
@@ -388,9 +467,9 @@ void gmx::LegacySimulator::do_mimic()
             }
             if (constructVsites)
             {
-                wallcycle_start(wcycle, ewcVSITECONSTR);
-                vsite->construct(state->x, ir->delta_t, state->v, state->box);
-                wallcycle_stop(wcycle, ewcVSITECONSTR);
+                wallcycle_start(wcycle, WallCycleCounter::VsiteConstr);
+                vsite->construct(state->x, state->v, state->box, VSiteOperation::PositionsAndVelocities);
+                wallcycle_stop(wcycle, WallCycleCounter::VsiteConstr);
             }
         }
 
@@ -398,10 +477,27 @@ void gmx::LegacySimulator::do_mimic()
         {
             /* Repartition the domain decomposition */
             const bool bMasterState = true;
-            dd_partition_system(fplog, mdlog, step, cr, bMasterState, nstglobalcomm, state_global,
-                                *top_global, ir, imdSession, pull_work, state, &f, mdAtoms, &top,
-                                fr, vsite, constr, nrnb, wcycle, mdrunOptions.verbose);
-            shouldCheckNumberOfBondedInteractions = true;
+            dd_partition_system(fplog,
+                                mdlog,
+                                step,
+                                cr,
+                                bMasterState,
+                                nstglobalcomm,
+                                state_global,
+                                top_global,
+                                *ir,
+                                imdSession,
+                                pull_work,
+                                state,
+                                &f,
+                                mdAtoms,
+                                &top,
+                                fr,
+                                vsite,
+                                constr,
+                                nrnb,
+                                wcycle,
+                                mdrunOptions.verbose);
         }
 
         if (MASTER(cr))
@@ -409,9 +505,9 @@ void gmx::LegacySimulator::do_mimic()
             EnergyOutput::printHeader(fplog, step, t); /* can we improve the information printed here? */
         }
 
-        if (ir->efep != efepNO)
+        if (ir->efep != FreeEnergyPerturbationType::No)
         {
-            update_mdatoms(mdatoms, state->lambda[efptMASS]);
+            update_mdatoms(mdatoms, state->lambda[FreeEnergyPerturbationCouplingType::Mass]);
         }
 
         force_flags = (GMX_FORCE_STATECHANGED | GMX_FORCE_DYNAMICBOX | GMX_FORCE_ALLFORCES
@@ -421,12 +517,38 @@ void gmx::LegacySimulator::do_mimic()
         if (shellfc)
         {
             /* Now is the time to relax the shells */
-            relax_shell_flexcon(fplog, cr, ms, mdrunOptions.verbose, enforcedRotation, step, ir,
-                                imdSession, pull_work, bNS, force_flags, &top, constr, enerd,
-                                state->natoms, state->x.arrayRefWithPadding(),
-                                state->v.arrayRefWithPadding(), state->box, state->lambda,
-                                &state->hist, &f.view(), force_vir, mdatoms, nrnb, wcycle, shellfc,
-                                fr, runScheduleWork, t, mu_tot, vsite, ddBalanceRegionHandler);
+            relax_shell_flexcon(fplog,
+                                cr,
+                                ms,
+                                mdrunOptions.verbose,
+                                enforcedRotation,
+                                step,
+                                ir,
+                                imdSession,
+                                pull_work,
+                                bNS,
+                                force_flags,
+                                &top,
+                                constr,
+                                enerd,
+                                state->natoms,
+                                state->x.arrayRefWithPadding(),
+                                state->v.arrayRefWithPadding(),
+                                state->box,
+                                state->lambda,
+                                &state->hist,
+                                &f.view(),
+                                force_vir,
+                                *mdatoms,
+                                nrnb,
+                                wcycle,
+                                shellfc,
+                                fr,
+                                runScheduleWork,
+                                t,
+                                mu_tot,
+                                vsite,
+                                ddBalanceRegionHandler);
         }
         else
         {
@@ -437,10 +559,34 @@ void gmx::LegacySimulator::do_mimic()
              */
             Awh*       awh = nullptr;
             gmx_edsam* ed  = nullptr;
-            do_force(fplog, cr, ms, ir, awh, enforcedRotation, imdSession, pull_work, step, nrnb,
-                     wcycle, &top, state->box, state->x.arrayRefWithPadding(), &state->hist,
-                     &f.view(), force_vir, mdatoms, enerd, state->lambda, fr, runScheduleWork,
-                     vsite, mu_tot, t, ed, GMX_FORCE_NS | force_flags, ddBalanceRegionHandler);
+            do_force(fplog,
+                     cr,
+                     ms,
+                     *ir,
+                     awh,
+                     enforcedRotation,
+                     imdSession,
+                     pull_work,
+                     step,
+                     nrnb,
+                     wcycle,
+                     &top,
+                     state->box,
+                     state->x.arrayRefWithPadding(),
+                     &state->hist,
+                     &f.view(),
+                     force_vir,
+                     mdatoms,
+                     enerd,
+                     state->lambda,
+                     fr,
+                     runScheduleWork,
+                     vsite,
+                     mu_tot,
+                     t,
+                     ed,
+                     GMX_FORCE_NS | force_flags,
+                     ddBalanceRegionHandler);
         }
 
         /* Now we have the energies and forces corresponding to the
@@ -450,10 +596,28 @@ void gmx::LegacySimulator::do_mimic()
             const bool isCheckpointingStep = false;
             const bool doRerun             = false;
             const bool bSumEkinhOld        = false;
-            do_md_trajectory_writing(fplog, cr, nfile, fnm, step, step_rel, t, ir, state,
-                                     state_global, observablesHistory, top_global, fr, outf,
-                                     energyOutput, ekind, f.view().force(), isCheckpointingStep,
-                                     doRerun, isLastStep, mdrunOptions.writeConfout, bSumEkinhOld);
+            do_md_trajectory_writing(fplog,
+                                     cr,
+                                     nfile,
+                                     fnm,
+                                     step,
+                                     step_rel,
+                                     t,
+                                     ir,
+                                     state,
+                                     state_global,
+                                     observablesHistory,
+                                     top_global,
+                                     fr,
+                                     outf,
+                                     energyOutput,
+                                     ekind,
+                                     f.view().force(),
+                                     isCheckpointingStep,
+                                     doRerun,
+                                     isLastStep,
+                                     mdrunOptions.writeConfout,
+                                     bSumEkinhOld);
         }
 
         stopHandler->setSignal();
@@ -465,27 +629,48 @@ void gmx::LegacySimulator::do_mimic()
             t_vcm*              vcm              = nullptr;
             SimulationSignaller signaller(&signals, cr, ms, doInterSimSignal, doIntraSimSignal);
 
-            compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
-                            makeConstArrayRef(state->v), state->box, mdatoms, nrnb, vcm, wcycle,
-                            enerd, nullptr, nullptr, nullptr, nullptr, constr, &signaller,
-                            state->box, &totalNumberOfBondedInteractions, &bSumEkinhOld,
-                            CGLO_GSTAT | CGLO_ENERGY
-                                    | (shouldCheckNumberOfBondedInteractions ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS
-                                                                             : 0));
-            checkNumberOfBondedInteractions(mdlog, cr, totalNumberOfBondedInteractions, top_global,
-                                            &top, makeConstArrayRef(state->x), state->box,
-                                            &shouldCheckNumberOfBondedInteractions);
+            int cglo_flags = CGLO_GSTAT | CGLO_ENERGY;
+            if (DOMAINDECOMP(cr) && shouldCheckNumberOfBondedInteractions(*cr->dd))
+            {
+                cglo_flags |= CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS;
+            }
+            compute_globals(gstat,
+                            cr,
+                            ir,
+                            fr,
+                            ekind,
+                            makeConstArrayRef(state->x),
+                            makeConstArrayRef(state->v),
+                            state->box,
+                            mdatoms,
+                            nrnb,
+                            vcm,
+                            wcycle,
+                            enerd,
+                            nullptr,
+                            nullptr,
+                            nullptr,
+                            nullptr,
+                            constr != nullptr ? constr->rmsdData() : gmx::ArrayRef<real>{},
+                            &signaller,
+                            state->box,
+                            &bSumEkinhOld,
+                            cglo_flags);
+            if (DOMAINDECOMP(cr))
+            {
+                checkNumberOfBondedInteractions(
+                        mdlog, cr, top_global, &top, makeConstArrayRef(state->x), state->box);
+            }
         }
 
         {
-            gmx::HostVector<gmx::RVec>     fglobal(top_global->natoms);
+            gmx::HostVector<gmx::RVec>     fglobal(top_global.natoms);
             gmx::ArrayRef<gmx::RVec>       ftemp;
             gmx::ArrayRef<const gmx::RVec> flocal = f.view().force();
             if (DOMAINDECOMP(cr))
             {
                 ftemp = gmx::makeArrayRef(fglobal);
-                dd_collect_vec(cr->dd, state->ddp_count, state->ddp_count_cg_gl, state->cg_gl,
-                               flocal, ftemp);
+                dd_collect_vec(cr->dd, state->ddp_count, state->ddp_count_cg_gl, state->cg_gl, flocal, ftemp);
             }
             else
             {
@@ -505,7 +690,7 @@ void gmx::LegacySimulator::do_mimic()
            but what we actually need entering the new cycle is the new shake_vir value. Ideally, we could
            generate the new shake_vir, but test the veta value for convergence.  This will take some thought. */
 
-        if (ir->efep != efepNO)
+        if (ir->efep != FreeEnergyPerturbationType::No)
         {
             /* Sum up the foreign energy and dhdl terms for md and sd.
                Currently done every step so that dhdl is correct in the .edr */
@@ -516,12 +701,27 @@ void gmx::LegacySimulator::do_mimic()
         if (MASTER(cr))
         {
             const bool bCalcEnerStep = true;
-            energyOutput.addDataAtEnergyStep(
-                    doFreeEnergyPerturbation, bCalcEnerStep, t, mdatoms->tmass, enerd, ir->fepvals,
-                    ir->expandedvals, state->box,
-                    PTCouplingArrays({ state->boxv, state->nosehoover_xi, state->nosehoover_vxi,
-                                       state->nhpres_xi, state->nhpres_vxi }),
-                    state->fep_state, shake_vir, force_vir, total_vir, pres, ekind, mu_tot, constr);
+            energyOutput.addDataAtEnergyStep(doFreeEnergyPerturbation,
+                                             bCalcEnerStep,
+                                             t,
+                                             mdatoms->tmass,
+                                             enerd,
+                                             ir->fepvals.get(),
+                                             ir->expandedvals.get(),
+                                             state->box,
+                                             PTCouplingArrays({ state->boxv,
+                                                                state->nosehoover_xi,
+                                                                state->nosehoover_vxi,
+                                                                state->nhpres_xi,
+                                                                state->nhpres_vxi }),
+                                             state->fep_state,
+                                             shake_vir,
+                                             force_vir,
+                                             total_vir,
+                                             pres,
+                                             ekind,
+                                             mu_tot,
+                                             constr);
 
             const bool do_ene = true;
             const bool do_log = true;
@@ -530,8 +730,15 @@ void gmx::LegacySimulator::do_mimic()
             const bool do_or  = ir->nstorireout != 0;
 
             EnergyOutput::printAnnealingTemperatures(do_log ? fplog : nullptr, groups, &(ir->opts));
-            energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf), do_ene, do_dr, do_or,
-                                               do_log ? fplog : nullptr, step, t, fr->fcdata.get(), awh);
+            energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf),
+                                               do_ene,
+                                               do_dr,
+                                               do_or,
+                                               do_log ? fplog : nullptr,
+                                               step,
+                                               t,
+                                               fr->fcdata.get(),
+                                               awh);
 
             if (do_per_step(step, ir->nstlog))
             {
@@ -552,7 +759,7 @@ void gmx::LegacySimulator::do_mimic()
             print_time(stderr, walltime_accounting, step, ir, cr);
         }
 
-        cycles = wallcycle_stop(wcycle, ewcSTEP);
+        cycles = wallcycle_stop(wcycle, WallCycleCounter::Step);
         if (DOMAINDECOMP(cr) && wcycle)
         {
             dd_cycles_add(cr->dd, cycles, ddCyclStep);
index b6b9376e3aaf9ab81fdc6b86b33cfa94e518b792..a1d42aa6c1f5eddd7e033dd7dc6c6bba03ca0aeb 100644 (file)
@@ -141,18 +141,18 @@ typedef struct em_state
 static void print_em_start(FILE*                     fplog,
                            const t_commrec*          cr,
                            gmx_walltime_accounting_t walltime_accounting,
-                           gmx_wallcycle_t           wcycle,
+                           gmx_wallcycle           wcycle,
                            const char*               name)
 {
     walltime_accounting_start_time(walltime_accounting);
-    wallcycle_start(wcycle, ewcRUN);
+    wallcycle_start(wcycle, WallCycleCounter::Run);
     print_start(fplog, cr, walltime_accounting, name);
 }
 
 //! Stop counting time for EM
-static void em_time_end(gmx_walltime_accounting_t walltime_accounting, gmx_wallcycle_t wcycle)
+static void em_time_end(gmx_walltime_accounting_t walltime_accounting, gmx_wallcycle* wcycle)
 {
-    wallcycle_stop(wcycle, ewcRUN);
+    wallcycle_stop(wcycle, WallCycleCounter::Run);
 
     walltime_accounting_end_time(walltime_accounting);
 }
@@ -238,12 +238,13 @@ static void print_converged(FILE*             fp,
         fprintf(fp,
                 "\n%s converged to machine precision in %s steps,\n"
                 "but did not reach the requested Fmax < %g.\n",
-                alg, gmx_step_str(count, buf), ftol);
+                alg,
+                gmx_step_str(count, buf),
+                ftol);
     }
     else
     {
-        fprintf(fp, "\n%s did not converge to Fmax < %g in %s steps.\n", alg, ftol,
-                gmx_step_str(count, buf));
+        fprintf(fp, "\n%s did not converge to Fmax < %g in %s steps.\n", alg, ftol, gmx_step_str(count, buf));
     }
 
 #if GMX_DOUBLE
@@ -259,7 +260,7 @@ static void print_converged(FILE*             fp,
 
 //! Compute the norm and max of the force array in parallel
 static void get_f_norm_max(const t_commrec*               cr,
-                           t_grpopts*                     opts,
+                           const t_grpopts*               opts,
                            t_mdatoms*                     mdatoms,
                            gmx::ArrayRef<const gmx::RVec> f,
                            real*                          fnorm,
@@ -356,7 +357,7 @@ static void get_f_norm_max(const t_commrec*               cr,
 }
 
 //! Compute the norm of the force
-static void get_state_f_norm_max(const t_commrec* cr, t_grpopts* opts, t_mdatoms* mdatoms, em_state_t* ems)
+static void get_state_f_norm_max(const t_commrec* cr, const t_grpopts* opts, t_mdatoms* mdatoms, em_state_t* ems)
 {
     get_f_norm_max(cr, opts, mdatoms, ems->f.view().force(), &ems->fnorm, &ems->fmax, &ems->a_fmax);
 }
@@ -366,11 +367,11 @@ static void init_em(FILE*                fplog,
                     const gmx::MDLogger& mdlog,
                     const char*          title,
                     const t_commrec*     cr,
-                    t_inputrec*          ir,
+                    const t_inputrec*    ir,
                     gmx::ImdSession*     imdSession,
                     pull_t*              pull_work,
                     t_state*             state_global,
-                    const gmx_mtop_t*    top_global,
+                    const gmx_mtop_t&    top_global,
                     em_state_t*          ems,
                     gmx_localtop_t*      top,
                     t_nrnb*              nrnb,
@@ -394,15 +395,26 @@ static void init_em(FILE*                fplog,
     }
     int*                fep_state = MASTER(cr) ? &state_global->fep_state : nullptr;
     gmx::ArrayRef<real> lambda    = MASTER(cr) ? state_global->lambda : gmx::ArrayRef<real>();
-    initialize_lambdas(fplog, *ir, MASTER(cr), fep_state, lambda);
-
-    if (ir->eI == eiNM)
+    initialize_lambdas(fplog,
+                       ir->efep,
+                       ir->bSimTemp,
+                       *ir->fepvals,
+                       ir->simtempvals->temperatures,
+                       gmx::arrayRefFromArray(ir->opts.ref_t, ir->opts.ngtc),
+                       MASTER(cr),
+                       fep_state,
+                       lambda);
+
+    if (ir->eI == IntegrationAlgorithm::NM)
     {
         GMX_ASSERT(shellfc != nullptr, "With NM we always support shells");
 
-        *shellfc =
-                init_shell_flexcon(stdout, top_global, constr ? constr->numFlexibleConstraints() : 0,
-                                   ir->nstcalcenergy, DOMAINDECOMP(cr), thisRankHasDuty(cr, DUTY_PME));
+        *shellfc = init_shell_flexcon(stdout,
+                                      top_global,
+                                      constr ? constr->numFlexibleConstraints() : 0,
+                                      ir->nstcalcenergy,
+                                      DOMAINDECOMP(cr),
+                                      thisRankHasDuty(cr, DUTY_PME));
     }
     else
     {
@@ -421,13 +433,31 @@ static void init_em(FILE*                fplog,
 
     if (DOMAINDECOMP(cr))
     {
-        dd_init_local_state(cr->dd, state_global, &ems->s);
+        dd_init_local_state(*cr->dd, state_global, &ems->s);
 
         /* Distribute the charge groups over the nodes from the master node */
-        dd_partition_system(fplog, mdlog, ir->init_step, cr, TRUE, 1, state_global, *top_global, ir,
-                            imdSession, pull_work, &ems->s, &ems->f, mdAtoms, top, fr, vsite,
-                            constr, nrnb, nullptr, FALSE);
-        dd_store_state(cr->dd, &ems->s);
+        dd_partition_system(fplog,
+                            mdlog,
+                            ir->init_step,
+                            cr,
+                            TRUE,
+                            1,
+                            state_global,
+                            top_global,
+                            *ir,
+                            imdSession,
+                            pull_work,
+                            &ems->s,
+                            &ems->f,
+                            mdAtoms,
+                            top,
+                            fr,
+                            vsite,
+                            constr,
+                            nrnb,
+                            nullptr,
+                            FALSE);
+        dd_store_state(*cr->dd, &ems->s);
     }
     else
     {
@@ -436,19 +466,21 @@ static void init_em(FILE*                fplog,
         ems->s = *state_global;
         state_change_natoms(&ems->s, ems->s.natoms);
 
-        mdAlgorithmsSetupAtomData(cr, ir, *top_global, top, fr, &ems->f, mdAtoms, constr, vsite,
-                                  shellfc ? *shellfc : nullptr);
+        mdAlgorithmsSetupAtomData(
+                cr, *ir, top_global, top, fr, &ems->f, mdAtoms, constr, vsite, shellfc ? *shellfc : nullptr);
     }
 
-    update_mdatoms(mdAtoms->mdatoms(), ems->s.lambda[efptMASS]);
+    update_mdatoms(mdAtoms->mdatoms(), ems->s.lambda[FreeEnergyPerturbationCouplingType::Mass]);
 
     if (constr)
     {
         // TODO how should this cross-module support dependency be managed?
-        if (ir->eConstrAlg == econtSHAKE && gmx_mtop_ftype_count(top_global, F_CONSTR) > 0)
+        if (ir->eConstrAlg == ConstraintAlgorithm::Shake && gmx_mtop_ftype_count(top_global, F_CONSTR) > 0)
         {
-            gmx_fatal(FARGS, "Can not do energy minimization with %s, use %s\n",
-                      econstr_names[econtSHAKE], econstr_names[econtLINCS]);
+            gmx_fatal(FARGS,
+                      "Can not do energy minimization with %s, use %s\n",
+                      enumValueToString(ConstraintAlgorithm::Shake),
+                      enumValueToString(ConstraintAlgorithm::Lincs));
         }
 
         if (!ir->bContinuation)
@@ -458,10 +490,21 @@ static void init_em(FILE*                fplog,
             bool computeEnergy = true;
             bool computeVirial = false;
             dvdl_constr        = 0;
-            constr->apply(needsLogging, computeEnergy, -1, 0, 1.0, ems->s.x.arrayRefWithPadding(),
-                          ems->s.x.arrayRefWithPadding(), ArrayRef<RVec>(), ems->s.box,
-                          ems->s.lambda[efptFEP], &dvdl_constr, gmx::ArrayRefWithPadding<RVec>(),
-                          computeVirial, nullptr, gmx::ConstraintVariable::Positions);
+            constr->apply(needsLogging,
+                          computeEnergy,
+                          -1,
+                          0,
+                          1.0,
+                          ems->s.x.arrayRefWithPadding(),
+                          ems->s.x.arrayRefWithPadding(),
+                          ArrayRef<RVec>(),
+                          ems->s.box,
+                          ems->s.lambda[FreeEnergyPerturbationCouplingType::Fep],
+                          &dvdl_constr,
+                          gmx::ArrayRefWithPadding<RVec>(),
+                          computeVirial,
+                          nullptr,
+                          gmx::ConstraintVariable::Positions);
         }
     }
 
@@ -481,7 +524,7 @@ static void init_em(FILE*                fplog,
 static void finish_em(const t_commrec*          cr,
                       gmx_mdoutf_t              outf,
                       gmx_walltime_accounting_t walltime_accounting,
-                      gmx_wallcycle_t           wcycle)
+                      gmx_wallcycle           wcycle)
 {
     if (!thisRankHasDuty(cr, DUTY_PME))
     {
@@ -511,8 +554,8 @@ static void write_em_traj(FILE*               fplog,
                           gmx_bool            bX,
                           gmx_bool            bF,
                           const char*         confout,
-                          const gmx_mtop_t*   top_global,
-                          t_inputrec*         ir,
+                          const gmx_mtop_t&   top_global,
+                          const t_inputrec*   ir,
                           int64_t             step,
                           em_state_t*         state,
                           t_state*            state_global,
@@ -536,9 +579,18 @@ static void write_em_traj(FILE*               fplog,
     }
 
     gmx::WriteCheckpointDataHolder checkpointDataHolder;
-    mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags, top_global->natoms, step,
-                                     static_cast<double>(step), &state->s, state_global,
-                                     observablesHistory, state->f.view().force(), &checkpointDataHolder);
+    mdoutf_write_to_trajectory_files(fplog,
+                                     cr,
+                                     outf,
+                                     mdof_flags,
+                                     top_global.natoms,
+                                     step,
+                                     static_cast<double>(step),
+                                     &state->s,
+                                     state_global,
+                                     observablesHistory,
+                                     state->f.view().force(),
+                                     &checkpointDataHolder);
 
     if (confout != nullptr)
     {
@@ -548,8 +600,8 @@ static void write_em_traj(FILE*               fplog,
             if (!bX)
             {
                 auto globalXRef = MASTER(cr) ? state_global->x : gmx::ArrayRef<gmx::RVec>();
-                dd_collect_vec(cr->dd, state->s.ddp_count, state->s.ddp_count_cg_gl, state->s.cg_gl,
-                               state->s.x, globalXRef);
+                dd_collect_vec(
+                        cr->dd, state->s.ddp_count, state->s.ddp_count_cg_gl, state->s.cg_gl, state->s.x, globalXRef);
             }
         }
         else
@@ -563,11 +615,16 @@ static void write_em_traj(FILE*               fplog,
             if (ir->pbcType != PbcType::No && !ir->bPeriodicMols && DOMAINDECOMP(cr))
             {
                 /* Make molecules whole only for confout writing */
-                do_pbc_mtop(ir->pbcType, state->s.box, top_global, state_global->x.rvec_array());
+                do_pbc_mtop(ir->pbcType, state->s.box, &top_global, state_global->x.rvec_array());
             }
 
-            write_sto_conf_mtop(confout, *top_global->name, top_global,
-                                state_global->x.rvec_array(), nullptr, ir->pbcType, state->s.box);
+            write_sto_conf_mtop(confout,
+                                *top_global.name,
+                                top_global,
+                                state_global->x.rvec_array(),
+                                nullptr,
+                                ir->pbcType,
+                                state->s.box);
         }
     }
 }
@@ -576,7 +633,7 @@ static void write_em_traj(FILE*               fplog,
 //
 // \returns true when the step succeeded, false when a constraint error occurred
 static bool do_em_step(const t_commrec*                          cr,
-                       t_inputrec*                               ir,
+                       const t_inputrec*                         ir,
                        t_mdatoms*                                md,
                        em_state_t*                               ems1,
                        real                                      a,
@@ -586,9 +643,9 @@ static bool do_em_step(const t_commrec*                          cr,
                        int64_t                                   count)
 
 {
-    t_state *s1, *s2;
-    int      start, end;
-    real     dvdl_constr;
+    t_state *    s1, *s2;
+    int          start, end;
+    real         dvdl_constr;
     int nthreads gmx_unused;
 
     bool validStep = true;
@@ -621,7 +678,7 @@ static bool do_em_step(const t_commrec*                          cr,
     start = 0;
     end   = md->homenr;
 
-    nthreads = gmx_omp_nthreads_get(emntUpdate);
+    nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Update);
 #pragma omp parallel num_threads(nthreads)
     {
         const rvec* x1 = s1->x.rvec_array();
@@ -653,7 +710,7 @@ static bool do_em_step(const t_commrec*                          cr,
             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
         }
 
-        if (s2->flags & (1 << estCGP))
+        if (s2->flags & enumValueToBitMask(StateEntry::Cgp))
         {
             /* Copy the CG p vector */
             const rvec* p1 = s1->cg_p.rvec_array();
@@ -686,10 +743,21 @@ static bool do_em_step(const t_commrec*                          cr,
     if (constr)
     {
         dvdl_constr = 0;
-        validStep   = constr->apply(
-                TRUE, TRUE, count, 0, 1.0, s1->x.arrayRefWithPadding(), s2->x.arrayRefWithPadding(),
-                ArrayRef<RVec>(), s2->box, s2->lambda[efptBONDED], &dvdl_constr,
-                gmx::ArrayRefWithPadding<RVec>(), false, nullptr, gmx::ConstraintVariable::Positions);
+        validStep   = constr->apply(TRUE,
+                                  TRUE,
+                                  count,
+                                  0,
+                                  1.0,
+                                  s1->x.arrayRefWithPadding(),
+                                  s2->x.arrayRefWithPadding(),
+                                  ArrayRef<RVec>(),
+                                  s2->box,
+                                  s2->lambda[FreeEnergyPerturbationCouplingType::Bonded],
+                                  &dvdl_constr,
+                                  gmx::ArrayRefWithPadding<RVec>(),
+                                  false,
+                                  nullptr,
+                                  gmx::ConstraintVariable::Positions);
 
         if (cr->nnodes > 1)
         {
@@ -703,12 +771,14 @@ static bool do_em_step(const t_commrec*                          cr,
         }
 
         // We should move this check to the different minimizers
-        if (!validStep && ir->eI != eiSteep)
+        if (!validStep && ir->eI != IntegrationAlgorithm::Steep)
         {
             gmx_fatal(FARGS,
                       "The coordinates could not be constrained. Minimizer '%s' can not handle "
                       "constraint failures, use minimizer '%s' before using '%s'.",
-                      EI(ir->eI), EI(eiSteep), EI(ir->eI));
+                      enumValueToString(ir->eI),
+                      enumValueToString(IntegrationAlgorithm::Steep),
+                      enumValueToString(ir->eI));
         }
     }
 
@@ -720,8 +790,8 @@ static void em_dd_partition_system(FILE*                fplog,
                                    const gmx::MDLogger& mdlog,
                                    int                  step,
                                    const t_commrec*     cr,
-                                   const gmx_mtop_t*    top_global,
-                                   t_inputrec*          ir,
+                                   const gmx_mtop_t&    top_global,
+                                   const t_inputrec*    ir,
                                    gmx::ImdSession*     imdSession,
                                    pull_t*              pull_work,
                                    em_state_t*          ems,
@@ -731,17 +801,83 @@ static void em_dd_partition_system(FILE*                fplog,
                                    VirtualSitesHandler* vsite,
                                    gmx::Constraints*    constr,
                                    t_nrnb*              nrnb,
-                                   gmx_wallcycle_t      wcycle)
+                                   gmx_wallcycle      wcycle)
 {
     /* Repartition the domain decomposition */
-    dd_partition_system(fplog, mdlog, step, cr, FALSE, 1, nullptr, *top_global, ir, imdSession, pull_work,
-                        &ems->s, &ems->f, mdAtoms, top, fr, vsite, constr, nrnb, wcycle, FALSE);
-    dd_store_state(cr->dd, &ems->s);
+    dd_partition_system(fplog,
+                        mdlog,
+                        step,
+                        cr,
+                        FALSE,
+                        1,
+                        nullptr,
+                        top_global,
+                        *ir,
+                        imdSession,
+                        pull_work,
+                        &ems->s,
+                        &ems->f,
+                        mdAtoms,
+                        top,
+                        fr,
+                        vsite,
+                        constr,
+                        nrnb,
+                        wcycle,
+                        FALSE);
+    dd_store_state(*cr->dd, &ems->s);
 }
 
 namespace
 {
 
+//! Copy coordinates, OpenMP parallelized, from \p refCoords to coords
+void setCoordinates(std::vector<RVec>* coords, ArrayRef<const RVec> refCoords)
+{
+    coords->resize(refCoords.size());
+
+    const int gmx_unused nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Update);
+#pragma omp parallel for num_threads(nthreads) schedule(static)
+    for (int i = 0; i < ssize(refCoords); i++)
+    {
+        (*coords)[i] = refCoords[i];
+    }
+}
+
+//! Returns the maximum difference an atom moved between two coordinate sets, over all ranks
+real maxCoordinateDifference(ArrayRef<const RVec> coords1, ArrayRef<const RVec> coords2, MPI_Comm mpiCommMyGroup)
+{
+    GMX_RELEASE_ASSERT(coords1.size() == coords2.size(), "Coordinate counts should match");
+
+    real maxDiffSquared = 0;
+
+    const int gmx_unused nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Update);
+#pragma omp parallel for reduction(max : maxDiffSquared) num_threads(nthreads) schedule(static)
+    for (int i = 0; i < ssize(coords1); i++)
+    {
+        maxDiffSquared = std::max(maxDiffSquared, gmx::norm2(coords1[i] - coords2[i]));
+    }
+
+#if GMX_MPI
+    int numRanks = 1;
+    if (mpiCommMyGroup != MPI_COMM_NULL)
+    {
+        MPI_Comm_size(mpiCommMyGroup, &numRanks);
+    }
+    if (numRanks > 1)
+    {
+        real maxDiffSquaredReduced;
+        MPI_Allreduce(
+                &maxDiffSquared, &maxDiffSquaredReduced, 1, GMX_DOUBLE ? MPI_DOUBLE : MPI_FLOAT, MPI_MAX, mpiCommMyGroup);
+        maxDiffSquared = maxDiffSquaredReduced;
+    }
+#else
+    GMX_UNUSED_VALUE(mpiCommMyGroup);
+#endif
+
+    return std::sqrt(maxDiffSquared);
+}
+
 /*! \brief Class to handle the work of setting and doing an energy evaluation.
  *
  * This class is a mere aggregate of parameters to pass to evaluate an
@@ -775,11 +911,11 @@ public:
     //! Coordinates multi-simulations.
     const gmx_multisim_t* ms;
     //! Holds the simulation topology.
-    const gmx_mtop_t* top_global;
+    const gmx_mtop_t& top_global;
     //! Holds the domain topology.
     gmx_localtop_t* top;
     //! User input options.
-    t_inputrec* inputrec;
+    const t_inputrec* inputrec;
     //! The Interactive Molecular Dynamics session.
     gmx::ImdSession* imdSession;
     //! The pull work object.
@@ -787,7 +923,7 @@ public:
     //! Manages flop accounting.
     t_nrnb* nrnb;
     //! Manages wall cycle accounting.
-    gmx_wallcycle_t wcycle;
+    gmx_wallcycle* wcycle;
     //! Coordinates global reduction.
     gmx_global_stat_t gstat;
     //! Handles virtual sites.
@@ -802,6 +938,10 @@ public:
     MdrunScheduleWorkload* runScheduleWork;
     //! Stores the computed energies.
     gmx_enerdata_t* enerd;
+    //! The DD partitioning count at which the pair list was generated
+    int ddpCountPairSearch;
+    //! The local coordinates that were used for pair searching, stored for computing displacements
+    std::vector<RVec> pairSearchCoordinates;
 };
 
 void EnergyEvaluator::run(em_state_t* ems, rvec mu_tot, tensor vir, tensor pres, int64_t count, gmx_bool bFirst)
@@ -815,39 +955,74 @@ void EnergyEvaluator::run(em_state_t* ems, rvec mu_tot, tensor vir, tensor pres,
     /* Set the time to the initial time, the time does not change during EM */
     t = inputrec->init_t;
 
-    if (bFirst || (DOMAINDECOMP(cr) && ems->s.ddp_count < cr->dd->ddp_count))
+    if (vsite)
+    {
+        vsite->construct(ems->s.x, {}, ems->s.box, gmx::VSiteOperation::Positions);
+    }
+
+    // Compute the buffer size of the pair list
+    const real bufferSize = inputrec->rlist - std::max(inputrec->rcoulomb, inputrec->rvdw);
+
+    if (bFirst || bufferSize <= 0 || (DOMAINDECOMP(cr) && ems->s.ddp_count != ddpCountPairSearch))
     {
         /* This is the first state or an old state used before the last ns */
         bNS = TRUE;
     }
     else
     {
-        bNS = FALSE;
-        if (inputrec->nstlist > 0)
-        {
-            bNS = TRUE;
-        }
+        // We need to generate a new pairlist when one atom moved more than half the buffer size
+        ArrayRef<const RVec> localCoordinates =
+                ArrayRef<const RVec>(ems->s.x).subArray(0, mdAtoms->mdatoms()->homenr);
+        bNS = 2 * maxCoordinateDifference(pairSearchCoordinates, localCoordinates, cr->mpi_comm_mygroup)
+              > bufferSize;
     }
 
-    if (vsite)
+    if (DOMAINDECOMP(cr) && bNS)
     {
-        vsite->construct(ems->s.x, 1, {}, ems->s.box);
+        /* Repartition the domain decomposition */
+        em_dd_partition_system(
+                fplog, mdlog, count, cr, top_global, inputrec, imdSession, pull_work, ems, top, mdAtoms, fr, vsite, constr, nrnb, wcycle);
+        ddpCountPairSearch = cr->dd->ddp_count;
     }
 
-    if (DOMAINDECOMP(cr) && bNS)
+    /* Store the local coordinates that will be used in the pair search, after we re-partitioned */
+    if (bufferSize > 0 && bNS)
     {
-        /* Repartition the domain decomposition */
-        em_dd_partition_system(fplog, mdlog, count, cr, top_global, inputrec, imdSession, pull_work,
-                               ems, top, mdAtoms, fr, vsite, constr, nrnb, wcycle);
+        ArrayRef<const RVec> localCoordinates =
+                constArrayRefFromArray(ems->s.x.data(), mdAtoms->mdatoms()->homenr);
+        setCoordinates(&pairSearchCoordinates, localCoordinates);
     }
 
     /* Calc force & energy on new trial position  */
     /* do_force always puts the charge groups in the box and shifts again
      * We do not unshift, so molecules are always whole in congrad.c
      */
-    do_force(fplog, cr, ms, inputrec, nullptr, nullptr, imdSession, pull_work, count, nrnb, wcycle,
-             top, ems->s.box, ems->s.x.arrayRefWithPadding(), &ems->s.hist, &ems->f.view(), force_vir,
-             mdAtoms->mdatoms(), enerd, ems->s.lambda, fr, runScheduleWork, vsite, mu_tot, t, nullptr,
+    do_force(fplog,
+             cr,
+             ms,
+             *inputrec,
+             nullptr,
+             nullptr,
+             imdSession,
+             pull_work,
+             count,
+             nrnb,
+             wcycle,
+             top,
+             ems->s.box,
+             ems->s.x.arrayRefWithPadding(),
+             &ems->s.hist,
+             &ems->f.view(),
+             force_vir,
+             mdAtoms->mdatoms(),
+             enerd,
+             ems->s.lambda,
+             fr,
+             runScheduleWork,
+             vsite,
+             mu_tot,
+             t,
+             nullptr,
              GMX_FORCE_STATECHANGED | GMX_FORCE_ALLFORCES | GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY
                      | (bNS ? GMX_FORCE_NS : 0),
              DDBalanceRegionHandler(cr));
@@ -857,21 +1032,31 @@ void EnergyEvaluator::run(em_state_t* ems, rvec mu_tot, tensor vir, tensor pres,
     clear_mat(pres);
 
     /* Communicate stuff when parallel */
-    if (PAR(cr) && inputrec->eI != eiNM)
+    if (PAR(cr) && inputrec->eI != IntegrationAlgorithm::NM)
     {
-        wallcycle_start(wcycle, ewcMoveE);
+        wallcycle_start(wcycle, WallCycleCounter::MoveE);
 
-        global_stat(gstat, cr, enerd, force_vir, shake_vir, inputrec, nullptr, nullptr, nullptr, 1,
-                    &terminate, nullptr, FALSE, CGLO_ENERGY | CGLO_PRESSURE | CGLO_CONSTRAINT);
+        global_stat(*gstat,
+                    cr,
+                    enerd,
+                    force_vir,
+                    shake_vir,
+                    *inputrec,
+                    nullptr,
+                    gmx::ArrayRef<real>{},
+                    nullptr,
+                    std::vector<real>(1, terminate),
+                    FALSE,
+                    CGLO_ENERGY | CGLO_PRESSURE | CGLO_CONSTRAINT);
 
-        wallcycle_stop(wcycle, ewcMoveE);
+        wallcycle_stop(wcycle, WallCycleCounter::MoveE);
     }
 
     if (fr->dispersionCorrection)
     {
         /* Calculate long range corrections to pressure and energy */
-        const DispersionCorrection::Correction correction =
-                fr->dispersionCorrection->calculate(ems->s.box, ems->s.lambda[efptVDW]);
+        const DispersionCorrection::Correction correction = fr->dispersionCorrection->calculate(
+                ems->s.box, ems->s.lambda[FreeEnergyPerturbationCouplingType::Vdw]);
 
         enerd->term[F_DISPCORR] = correction.energy;
         enerd->term[F_EPOT] += correction.energy;
@@ -893,9 +1078,20 @@ void EnergyEvaluator::run(em_state_t* ems, rvec mu_tot, tensor vir, tensor pres,
         bool computeVirial = true;
         dvdl_constr        = 0;
         auto f             = ems->f.view().forceWithPadding();
-        constr->apply(needsLogging, computeEnergy, count, 0, 1.0, ems->s.x.arrayRefWithPadding(), f,
-                      f.unpaddedArrayRef(), ems->s.box, ems->s.lambda[efptBONDED], &dvdl_constr,
-                      gmx::ArrayRefWithPadding<RVec>(), computeVirial, shake_vir,
+        constr->apply(needsLogging,
+                      computeEnergy,
+                      count,
+                      0,
+                      1.0,
+                      ems->s.x.arrayRefWithPadding(),
+                      f,
+                      f.unpaddedArrayRef(),
+                      ems->s.box,
+                      ems->s.lambda[FreeEnergyPerturbationCouplingType::Bonded],
+                      &dvdl_constr,
+                      gmx::ArrayRefWithPadding<RVec>(),
+                      computeVirial,
+                      shake_vir,
                       gmx::ConstraintVariable::ForceDispl);
         enerd->term[F_DVDL_CONSTR] += dvdl_constr;
         m_add(force_vir, shake_vir, vir);
@@ -908,7 +1104,7 @@ void EnergyEvaluator::run(em_state_t* ems, rvec mu_tot, tensor vir, tensor pres,
     clear_mat(ekin);
     enerd->term[F_PRES] = calc_pres(fr->pbcType, inputrec->nwall, ems->s.box, ekin, vir, pres);
 
-    if (inputrec->efep != efepNO)
+    if (inputrec->efep != FreeEnergyPerturbationType::No)
     {
         accumulateKineticLambdaComponents(enerd, ems->s.lambda, *inputrec->fepvals);
     }
@@ -923,8 +1119,8 @@ void EnergyEvaluator::run(em_state_t* ems, rvec mu_tot, tensor vir, tensor pres,
 
 //! Parallel utility summing energies and forces
 static double reorder_partsum(const t_commrec*  cr,
-                              t_grpopts*        opts,
-                              const gmx_mtop_t* top_global,
+                              const t_grpopts*  opts,
+                              const gmx_mtop_t& top_global,
                               const em_state_t* s_min,
                               const em_state_t* s_b)
 {
@@ -940,7 +1136,7 @@ static double reorder_partsum(const t_commrec*  cr,
      * This conflicts with the spirit of domain decomposition,
      * but to fully optimize this a much more complicated algorithm is required.
      */
-    const int natoms = top_global->natoms;
+    const int natoms = top_global.natoms;
     rvec*     fmg;
     snew(fmg, natoms);
 
@@ -951,7 +1147,7 @@ static double reorder_partsum(const t_commrec*  cr,
         copy_rvec(fm[i], fmg[a]);
         i++;
     }
-    gmx_sum(top_global->natoms * 3, fmg[0], cr);
+    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 */
     gmx::ArrayRef<const int> indicesB = s_b->s.cg_gl;
@@ -960,7 +1156,7 @@ static double reorder_partsum(const t_commrec*  cr,
     i                                     = 0;
     int                                gf = 0;
     gmx::ArrayRef<const unsigned char> grpnrFREEZE =
-            top_global->groups.groupNumbers[SimulationAtomGroupType::Freeze];
+            top_global.groups.groupNumbers[SimulationAtomGroupType::Freeze];
     for (int a : indicesB)
     {
         if (!grpnrFREEZE.empty())
@@ -984,9 +1180,9 @@ static double reorder_partsum(const t_commrec*  cr,
 
 //! Print some stuff, like beta, whatever that means.
 static real pr_beta(const t_commrec*  cr,
-                    t_grpopts*        opts,
+                    const t_grpopts*  opts,
                     t_mdatoms*        mdatoms,
-                    const gmx_mtop_t* top_global,
+                    const gmx_mtop_t& top_global,
                     const em_state_t* s_min,
                     const em_state_t* s_b)
 {
@@ -1042,7 +1238,7 @@ void LegacySimulator::do_cg()
 {
     const char* CG = "Polak-Ribiere Conjugate Gradients";
 
-    gmx_localtop_t    top(top_global->ffparams);
+    gmx_localtop_t    top(top_global.ffparams);
     gmx_global_stat_t gstat;
     double            tmp, minstep;
     real              stepsize;
@@ -1055,7 +1251,7 @@ void LegacySimulator::do_cg()
     tensor            vir, pres;
     int               number_steps, neval = 0, nstcg = inputrec->nstcgsteep;
     int               m, step, nminstep;
-    auto              mdatoms = mdAtoms->mdatoms();
+    auto*             mdatoms = mdAtoms->mdatoms();
 
     GMX_LOG(mdlog.info)
             .asParagraph()
@@ -1070,7 +1266,7 @@ void LegacySimulator::do_cg()
     if (MASTER(cr))
     {
         // In CG, the state is extended with a search direction
-        state_global->flags |= (1 << estCGP);
+        state_global->flags |= enumValueToBitMask(StateEntry::Cgp);
 
         // Ensure the extra per-atom state array gets allocated
         state_change_natoms(state_global, state_global->natoms);
@@ -1090,15 +1286,48 @@ void LegacySimulator::do_cg()
     em_state_t* s_c   = &s3;
 
     /* Init em and store the local state in s_min */
-    init_em(fplog, mdlog, CG, cr, inputrec, imdSession, pull_work, state_global, top_global, s_min,
-            &top, nrnb, fr, mdAtoms, &gstat, vsite, constr, nullptr);
+    init_em(fplog,
+            mdlog,
+            CG,
+            cr,
+            inputrec,
+            imdSession,
+            pull_work,
+            state_global,
+            top_global,
+            s_min,
+            &top,
+            nrnb,
+            fr,
+            mdAtoms,
+            &gstat,
+            vsite,
+            constr,
+            nullptr);
     const bool        simulationsShareState = false;
-    gmx_mdoutf*       outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider,
-                                   mdModulesNotifier, inputrec, top_global, nullptr, wcycle,
-                                   StartingBehavior::NewSimulation, simulationsShareState, ms);
-    gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf), top_global, inputrec, pull_work,
-                                   nullptr, false, StartingBehavior::NewSimulation,
-                                   simulationsShareState, mdModulesNotifier);
+    gmx_mdoutf*       outf                  = init_mdoutf(fplog,
+                                   nfile,
+                                   fnm,
+                                   mdrunOptions,
+                                   cr,
+                                   outputProvider,
+                                   mdModulesNotifiers,
+                                   inputrec,
+                                   top_global,
+                                   nullptr,
+                                   wcycle,
+                                   StartingBehavior::NewSimulation,
+                                   simulationsShareState,
+                                   ms);
+    gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf),
+                                   top_global,
+                                   *inputrec,
+                                   pull_work,
+                                   nullptr,
+                                   false,
+                                   StartingBehavior::NewSimulation,
+                                   simulationsShareState,
+                                   mdModulesNotifiers);
 
     /* Print to log file */
     print_em_start(fplog, cr, walltime_accounting, wcycle, CG);
@@ -1115,9 +1344,10 @@ void LegacySimulator::do_cg()
         sp_header(fplog, CG, inputrec->em_tol, number_steps);
     }
 
-    EnergyEvaluator energyEvaluator{ fplog,    mdlog,      cr,        ms,   top_global,      &top,
-                                     inputrec, imdSession, pull_work, nrnb, wcycle,          gstat,
-                                     vsite,    constr,     mdAtoms,   fr,   runScheduleWork, enerd };
+    EnergyEvaluator energyEvaluator{ fplog,  mdlog,           cr,         ms,        top_global,
+                                     &top,   inputrec,        imdSession, pull_work, nrnb,
+                                     wcycle, gstat,           vsite,      constr,    mdAtoms,
+                                     fr,     runScheduleWork, enerd,      -1,        {} };
     /* Call the force routine and some auxiliary (neighboursearching etc.) */
     /* do_force always puts the charge groups in the box and shifts again
      * We do not unshift, so molecules are always whole in congrad.c
@@ -1128,13 +1358,27 @@ void LegacySimulator::do_cg()
     {
         /* Copy stuff to the energy bin for easy printing etc. */
         matrix nullBox = {};
-        energyOutput.addDataAtEnergyStep(false, false, static_cast<double>(step), mdatoms->tmass,
-                                         enerd, nullptr, nullptr, nullBox, PTCouplingArrays(), 0,
-                                         nullptr, nullptr, vir, pres, nullptr, mu_tot, constr);
+        energyOutput.addDataAtEnergyStep(false,
+                                         false,
+                                         static_cast<double>(step),
+                                         mdatoms->tmass,
+                                         enerd,
+                                         nullptr,
+                                         nullptr,
+                                         nullBox,
+                                         PTCouplingArrays(),
+                                         0,
+                                         nullptr,
+                                         nullptr,
+                                         vir,
+                                         pres,
+                                         nullptr,
+                                         mu_tot,
+                                         constr);
 
         EnergyOutput::printHeader(fplog, step, step);
-        energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf), TRUE, FALSE, FALSE, fplog, step,
-                                           step, fr->fcdata.get(), nullptr);
+        energyOutput.printStepToEnergyFile(
+                mdoutf_get_fp_ene(outf), TRUE, FALSE, FALSE, fplog, step, step, fr->fcdata.get(), nullptr);
     }
 
     /* Estimate/guess the initial stepsize */
@@ -1242,7 +1486,7 @@ void LegacySimulator::do_cg()
             gmx_sumd(1, &minstep, cr);
         }
 
-        minstep = GMX_REAL_EPS / sqrt(minstep / (3 * top_global->natoms));
+        minstep = GMX_REAL_EPS / sqrt(minstep / (3 * top_global.natoms));
 
         if (stepsize < minstep)
         {
@@ -1254,8 +1498,8 @@ void LegacySimulator::do_cg()
         do_x = do_per_step(step, inputrec->nstxout);
         do_f = do_per_step(step, inputrec->nstfout);
 
-        write_em_traj(fplog, cr, outf, do_x, do_f, nullptr, top_global, inputrec, step, s_min,
-                      state_global, observablesHistory);
+        write_em_traj(
+                fplog, cr, outf, do_x, do_f, nullptr, top_global, inputrec, step, s_min, state_global, observablesHistory);
 
         /* Take a step downhill.
          * In theory, we should minimize the function along this direction.
@@ -1280,13 +1524,26 @@ void LegacySimulator::do_cg()
 
         if (DOMAINDECOMP(cr) && s_min->s.ddp_count < cr->dd->ddp_count)
         {
-            em_dd_partition_system(fplog, mdlog, step, cr, top_global, inputrec, imdSession,
-                                   pull_work, s_min, &top, mdAtoms, fr, vsite, constr, nrnb, wcycle);
+            em_dd_partition_system(fplog,
+                                   mdlog,
+                                   step,
+                                   cr,
+                                   top_global,
+                                   inputrec,
+                                   imdSession,
+                                   pull_work,
+                                   s_min,
+                                   &top,
+                                   mdAtoms,
+                                   fr,
+                                   vsite,
+                                   constr,
+                                   nrnb,
+                                   wcycle);
         }
 
         /* Take a trial step (new coords in s_c) */
-        do_em_step(cr, inputrec, mdatoms, s_min, c, s_min->s.cg_p.constArrayRefWithPadding(), s_c,
-                   constr, -1);
+        do_em_step(cr, inputrec, mdatoms, s_min, c, s_min->s.cg_p.constArrayRefWithPadding(), s_c, constr, -1);
 
         neval++;
         /* Calculate energy for the trial step */
@@ -1382,13 +1639,26 @@ void LegacySimulator::do_cg()
                 if (DOMAINDECOMP(cr) && s_min->s.ddp_count != cr->dd->ddp_count)
                 {
                     /* Reload the old state */
-                    em_dd_partition_system(fplog, mdlog, -1, cr, top_global, inputrec, imdSession, pull_work,
-                                           s_min, &top, mdAtoms, fr, vsite, constr, nrnb, wcycle);
+                    em_dd_partition_system(fplog,
+                                           mdlog,
+                                           -1,
+                                           cr,
+                                           top_global,
+                                           inputrec,
+                                           imdSession,
+                                           pull_work,
+                                           s_min,
+                                           &top,
+                                           mdAtoms,
+                                           fr,
+                                           vsite,
+                                           constr,
+                                           nrnb,
+                                           wcycle);
                 }
 
                 /* Take a trial step to this new point - new coords in s_b */
-                do_em_step(cr, inputrec, mdatoms, s_min, b,
-                           s_min->s.cg_p.constArrayRefWithPadding(), s_b, constr, -1);
+                do_em_step(cr, inputrec, mdatoms, s_min, b, s_min->s.cg_p.constArrayRefWithPadding(), s_b, constr, -1);
 
                 neval++;
                 /* Calculate energy for the trial step */
@@ -1415,8 +1685,7 @@ void LegacySimulator::do_cg()
 
                 if (debug)
                 {
-                    fprintf(debug, "CGE: EpotA %f EpotB %f EpotC %f gpb %f\n", s_a->epot, s_b->epot,
-                            s_c->epot, gpb);
+                    fprintf(debug, "CGE: EpotA %f EpotB %f EpotC %f gpb %f\n", s_a->epot, s_b->epot, s_c->epot, gpb);
                 }
 
                 epot_repl = s_b->epot;
@@ -1470,8 +1739,7 @@ void LegacySimulator::do_cg()
             {
                 if (debug)
                 {
-                    fprintf(debug, "CGE: C (%f) is lower than A (%f), moving C to B\n", s_c->epot,
-                            s_a->epot);
+                    fprintf(debug, "CGE: C (%f) is lower than A (%f), moving C to B\n", s_c->epot, s_a->epot);
                 }
                 swap_em_state(&s_b, &s_c);
                 gpb = gpc;
@@ -1480,8 +1748,7 @@ void LegacySimulator::do_cg()
             {
                 if (debug)
                 {
-                    fprintf(debug, "CGE: A (%f) is lower than C (%f), moving A to B\n", s_a->epot,
-                            s_c->epot);
+                    fprintf(debug, "CGE: A (%f) is lower than C (%f), moving A to B\n", s_a->epot, s_c->epot);
                 }
                 swap_em_state(&s_b, &s_a);
                 gpb = gpa;
@@ -1531,15 +1798,34 @@ void LegacySimulator::do_cg()
             if (mdrunOptions.verbose)
             {
                 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,
-                        s_min->epot, s_min->fnorm / sqrtNumAtoms, s_min->fmax, s_min->a_fmax + 1);
+                fprintf(stderr,
+                        "\rStep %d, Epot=%12.6e, Fnorm=%9.3e, Fmax=%9.3e (atom %d)\n",
+                        step,
+                        s_min->epot,
+                        s_min->fnorm / sqrtNumAtoms,
+                        s_min->fmax,
+                        s_min->a_fmax + 1);
                 fflush(stderr);
             }
             /* Store the new (lower) energies */
             matrix nullBox = {};
-            energyOutput.addDataAtEnergyStep(false, false, static_cast<double>(step), mdatoms->tmass,
-                                             enerd, nullptr, nullptr, nullBox, PTCouplingArrays(), 0,
-                                             nullptr, nullptr, vir, pres, nullptr, mu_tot, constr);
+            energyOutput.addDataAtEnergyStep(false,
+                                             false,
+                                             static_cast<double>(step),
+                                             mdatoms->tmass,
+                                             enerd,
+                                             nullptr,
+                                             nullptr,
+                                             nullBox,
+                                             PTCouplingArrays(),
+                                             0,
+                                             nullptr,
+                                             nullptr,
+                                             vir,
+                                             pres,
+                                             nullptr,
+                                             mu_tot,
+                                             constr);
 
             do_log = do_per_step(step, inputrec->nstlog);
             do_ene = do_per_step(step, inputrec->nstenergy);
@@ -1550,13 +1836,19 @@ void LegacySimulator::do_cg()
             {
                 EnergyOutput::printHeader(fplog, step, step);
             }
-            energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf), do_ene, FALSE, FALSE,
-                                               do_log ? fplog : nullptr, step, step,
-                                               fr->fcdata.get(), nullptr);
+            energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf),
+                                               do_ene,
+                                               FALSE,
+                                               FALSE,
+                                               do_log ? fplog : nullptr,
+                                               step,
+                                               step,
+                                               fr->fcdata.get(),
+                                               nullptr);
         }
 
         /* Send energies and positions to the IMD client if bIMD is TRUE. */
-        if (MASTER(cr) && imdSession->run(step, TRUE, state_global->box, state_global->x.rvec_array(), 0))
+        if (MASTER(cr) && imdSession->run(step, TRUE, state_global->box, state_global->x, 0))
         {
             imdSession->sendPositionsAndEnergies();
         }
@@ -1594,9 +1886,15 @@ void LegacySimulator::do_cg()
         if (!do_ene || !do_log)
         {
             /* Write final energy file entries */
-            energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf), !do_ene, FALSE, FALSE,
-                                               !do_log ? fplog : nullptr, step, step,
-                                               fr->fcdata.get(), nullptr);
+            energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf),
+                                               !do_ene,
+                                               FALSE,
+                                               FALSE,
+                                               !do_log ? fplog : nullptr,
+                                               step,
+                                               step,
+                                               fr->fcdata.get(),
+                                               nullptr);
         }
     }
 
@@ -1619,8 +1917,8 @@ void LegacySimulator::do_cg()
     do_x = !do_per_step(step, inputrec->nstxout);
     do_f = (inputrec->nstfout > 0 && !do_per_step(step, inputrec->nstfout));
 
-    write_em_traj(fplog, cr, outf, do_x, do_f, ftp2fn(efSTO, nfile, fnm), top_global, inputrec,
-                  step, s_min, state_global, observablesHistory);
+    write_em_traj(
+            fplog, cr, outf, do_x, do_f, ftp2fn(efSTO, nfile, fnm), top_global, inputrec, step, s_min, state_global, observablesHistory);
 
 
     if (MASTER(cr))
@@ -1643,22 +1941,9 @@ void LegacySimulator::do_lbfgs()
 {
     static const char* LBFGS = "Low-Memory BFGS Minimizer";
     em_state_t         ems;
-    gmx_localtop_t     top(top_global->ffparams);
+    gmx_localtop_t     top(top_global.ffparams);
     gmx_global_stat_t  gstat;
-    int                ncorr, nmaxcorr, point, cp, neval, nminstep;
-    double             stepsize, step_taken, gpa, gpb, gpc, tmp, minstep;
-    real *             rho, *alpha, *p, *s, **dx, **dg;
-    real               a, b, c, maxdelta, delta;
-    real               diag, Epot0;
-    real               dgdx, dgdg, sq, yr, beta;
-    gmx_bool           converged;
-    rvec               mu_tot = { 0 };
-    gmx_bool           do_log, do_ene, do_x, do_f, foundlower, *frozen;
-    tensor             vir, pres;
-    int                start, end, number_steps;
-    int                i, k, m, n, gf, step;
-    int                mdof_flags;
-    auto               mdatoms = mdAtoms->mdatoms();
+    auto*              mdatoms = mdAtoms->mdatoms();
 
     GMX_LOG(mdlog.info)
             .asParagraph()
@@ -1681,43 +1966,74 @@ void LegacySimulator::do_lbfgs()
                 "do not use constraints, or use another minimizer (e.g. steepest descent).");
     }
 
-    n        = 3 * state_global->natoms;
-    nmaxcorr = inputrec->nbfgscorr;
-
-    snew(frozen, n);
+    const int n        = 3 * state_global->natoms;
+    const int nmaxcorr = inputrec->nbfgscorr;
 
-    snew(p, n);
-    snew(rho, nmaxcorr);
-    snew(alpha, nmaxcorr);
+    std::vector<real> p(n);
+    std::vector<real> rho(nmaxcorr);
+    std::vector<real> alpha(nmaxcorr);
 
-    snew(dx, nmaxcorr);
-    for (i = 0; i < nmaxcorr; i++)
+    std::vector<std::vector<real>> dx(nmaxcorr);
+    for (auto& dxCorr : dx)
     {
-        snew(dx[i], n);
+        dxCorr.resize(n);
     }
 
-    snew(dg, nmaxcorr);
-    for (i = 0; i < nmaxcorr; i++)
+    std::vector<std::vector<real>> dg(nmaxcorr);
+    for (auto& dgCorr : dg)
     {
-        snew(dg[i], n);
+        dgCorr.resize(n);
     }
 
-    step  = 0;
-    neval = 0;
+    int step  = 0;
+    int neval = 0;
 
     /* Init em */
-    init_em(fplog, mdlog, LBFGS, cr, inputrec, imdSession, pull_work, state_global, top_global,
-            &ems, &top, nrnb, fr, mdAtoms, &gstat, vsite, constr, nullptr);
+    init_em(fplog,
+            mdlog,
+            LBFGS,
+            cr,
+            inputrec,
+            imdSession,
+            pull_work,
+            state_global,
+            top_global,
+            &ems,
+            &top,
+            nrnb,
+            fr,
+            mdAtoms,
+            &gstat,
+            vsite,
+            constr,
+            nullptr);
     const bool        simulationsShareState = false;
-    gmx_mdoutf*       outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider,
-                                   mdModulesNotifier, inputrec, top_global, nullptr, wcycle,
-                                   StartingBehavior::NewSimulation, simulationsShareState, ms);
-    gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf), top_global, inputrec, pull_work,
-                                   nullptr, false, StartingBehavior::NewSimulation,
-                                   simulationsShareState, mdModulesNotifier);
-
-    start = 0;
-    end   = mdatoms->homenr;
+    gmx_mdoutf*       outf                  = init_mdoutf(fplog,
+                                   nfile,
+                                   fnm,
+                                   mdrunOptions,
+                                   cr,
+                                   outputProvider,
+                                   mdModulesNotifiers,
+                                   inputrec,
+                                   top_global,
+                                   nullptr,
+                                   wcycle,
+                                   StartingBehavior::NewSimulation,
+                                   simulationsShareState,
+                                   ms);
+    gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf),
+                                   top_global,
+                                   *inputrec,
+                                   pull_work,
+                                   nullptr,
+                                   false,
+                                   StartingBehavior::NewSimulation,
+                                   simulationsShareState,
+                                   mdModulesNotifiers);
+
+    const int start = 0;
+    const int end   = mdatoms->homenr;
 
     /* We need 4 working states */
     em_state_t  s0{}, s1{}, s2{}, s3{};
@@ -1733,20 +2049,19 @@ void LegacySimulator::do_lbfgs()
     /* Print to log file */
     print_em_start(fplog, cr, walltime_accounting, wcycle, LBFGS);
 
-    do_log = do_ene = do_x = do_f = TRUE;
-
     /* Max number of steps */
-    number_steps = inputrec->nsteps;
+    const int number_steps = inputrec->nsteps;
 
     /* Create a 3*natoms index to tell whether each degree of freedom is frozen */
-    gf = 0;
-    for (i = start; i < end; i++)
+    std::vector<bool> frozen(n);
+    int               gf = 0;
+    for (int i = start; i < end; i++)
     {
         if (mdatoms->cFREEZE)
         {
             gf = mdatoms->cFREEZE[i];
         }
-        for (m = 0; m < DIM; m++)
+        for (int m = 0; m < DIM; m++)
         {
             frozen[3 * i + m] = (inputrec->opts.nFreeze[gf][m] != 0);
         }
@@ -1762,7 +2077,7 @@ void LegacySimulator::do_lbfgs()
 
     if (vsite)
     {
-        vsite->construct(state_global->x, 1, {}, state_global->box);
+        vsite->construct(state_global->x, {}, state_global->box, VSiteOperation::Positions);
     }
 
     /* Call the force routine and some auxiliary (neighboursearching etc.) */
@@ -1773,19 +2088,36 @@ void LegacySimulator::do_lbfgs()
     EnergyEvaluator energyEvaluator{ fplog,    mdlog,      cr,        ms,   top_global,      &top,
                                      inputrec, imdSession, pull_work, nrnb, wcycle,          gstat,
                                      vsite,    constr,     mdAtoms,   fr,   runScheduleWork, enerd };
+    rvec            mu_tot;
+    tensor          vir;
+    tensor          pres;
     energyEvaluator.run(&ems, mu_tot, vir, pres, -1, TRUE);
 
     if (MASTER(cr))
     {
         /* Copy stuff to the energy bin for easy printing etc. */
         matrix nullBox = {};
-        energyOutput.addDataAtEnergyStep(false, false, static_cast<double>(step), mdatoms->tmass,
-                                         enerd, nullptr, nullptr, nullBox, PTCouplingArrays(), 0,
-                                         nullptr, nullptr, vir, pres, nullptr, mu_tot, constr);
+        energyOutput.addDataAtEnergyStep(false,
+                                         false,
+                                         static_cast<double>(step),
+                                         mdatoms->tmass,
+                                         enerd,
+                                         nullptr,
+                                         nullptr,
+                                         nullBox,
+                                         PTCouplingArrays(),
+                                         0,
+                                         nullptr,
+                                         nullptr,
+                                         vir,
+                                         pres,
+                                         nullptr,
+                                         mu_tot,
+                                         constr);
 
         EnergyOutput::printHeader(fplog, step, step);
-        energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf), TRUE, FALSE, FALSE, fplog, step,
-                                           step, fr->fcdata.get(), nullptr);
+        energyOutput.printStepToEnergyFile(
+                mdoutf_get_fp_ene(outf), TRUE, FALSE, FALSE, fplog, step, step, fr->fcdata.get(), nullptr);
     }
 
     /* Set the initial step.
@@ -1809,11 +2141,11 @@ void LegacySimulator::do_lbfgs()
     }
 
     // Point is an index to the memory of search directions, where 0 is the first one.
-    point = 0;
+    int point = 0;
 
     // Set initial search direction to the force (-gradient), or 0 for frozen particles.
     real* fInit = static_cast<real*>(ems.f.view().force().data()[0]);
-    for (i = 0; i < n; i++)
+    for (int i = 0; i < n; i++)
     {
         if (!frozen[i])
         {
@@ -1829,25 +2161,28 @@ void LegacySimulator::do_lbfgs()
     // (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 / ems.fnorm;
+    double stepsize = 1.0 / ems.fnorm;
 
     /* Start the loop over BFGS steps.
      * Each successful step is counted, and we continue until
      * we either converge or reach the max number of steps.
      */
 
-    ncorr = 0;
+    bool do_log = true;
+    bool do_ene = true;
+
+    int ncorr = 0;
 
     /* Set the gradient from the force */
-    converged = FALSE;
-    for (step = 0; (number_steps < 0 || step <= number_steps) && !converged; step++)
+    bool converged = false;
+    for (int step = 0; (number_steps < 0 || step <= number_steps) && !converged; step++)
     {
 
         /* Write coordinates if necessary */
-        do_x = do_per_step(step, inputrec->nstxout);
-        do_f = do_per_step(step, inputrec->nstfout);
+        const bool do_x = do_per_step(step, inputrec->nstxout);
+        const bool do_f = do_per_step(step, inputrec->nstfout);
 
-        mdof_flags = 0;
+        int mdof_flags = 0;
         if (do_x)
         {
             mdof_flags |= MDOF_X;
@@ -1864,20 +2199,30 @@ void LegacySimulator::do_lbfgs()
         }
 
         gmx::WriteCheckpointDataHolder checkpointDataHolder;
-        mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags, top_global->natoms, step,
-                                         static_cast<real>(step), &ems.s, state_global, observablesHistory,
-                                         ems.f.view().force(), &checkpointDataHolder);
+        mdoutf_write_to_trajectory_files(fplog,
+                                         cr,
+                                         outf,
+                                         mdof_flags,
+                                         top_global.natoms,
+                                         step,
+                                         static_cast<real>(step),
+                                         &ems.s,
+                                         state_global,
+                                         observablesHistory,
+                                         ems.f.view().force(),
+                                         &checkpointDataHolder);
 
         /* 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];
+        gmx::ArrayRef<const real> s = dx[point];
 
-        real* xx = static_cast<real*>(ems.s.x.rvec_array()[0]);
-        real* ff = static_cast<real*>(ems.f.view().force().data()[0]);
+        const real* xx = static_cast<real*>(ems.s.x.rvec_array()[0]);
+        const real* ff = static_cast<real*>(ems.f.view().force().data()[0]);
 
         // calculate line gradient in position A
-        for (gpa = 0, i = 0; i < n; i++)
+        double gpa = 0;
+        for (int i = 0; i < n; i++)
         {
             gpa -= s[i] * ff[i];
         }
@@ -1885,9 +2230,10 @@ void LegacySimulator::do_lbfgs()
         /* Calculate minimum allowed stepsize along the line, before the average (norm)
          * relative change in coordinate is smaller than precision
          */
-        for (minstep = 0, i = 0; i < n; i++)
+        double minstep = 0;
+        for (int i = 0; i < n; i++)
         {
-            tmp = fabs(xx[i]);
+            double tmp = fabs(xx[i]);
             if (tmp < 1.0)
             {
                 tmp = 1.0;
@@ -1899,15 +2245,15 @@ void LegacySimulator::do_lbfgs()
 
         if (stepsize < minstep)
         {
-            converged = TRUE;
+            converged = true;
             break;
         }
 
         // Before taking any steps along the line, store the old position
-        *last       = ems;
-        real* lastx = static_cast<real*>(last->s.x.data()[0]);
-        real* lastf = static_cast<real*>(last->f.view().force().data()[0]);
-        Epot0       = ems.epot;
+        *last            = ems;
+        real*      lastx = static_cast<real*>(last->s.x.data()[0]);
+        real*      lastf = static_cast<real*>(last->f.view().force().data()[0]);
+        const real Epot0 = ems.epot;
 
         *sa = ems;
 
@@ -1938,11 +2284,13 @@ void LegacySimulator::do_lbfgs()
 
         // State "A" is the first position along the line.
         // reference position along line is initially zero
-        a = 0.0;
+        real a = 0;
 
         // Check stepsize first. We do not allow displacements
         // larger than emstep.
         //
+        real c;
+        real maxdelta;
         do
         {
             // Pick a new position C by adding stepsize to A.
@@ -1951,9 +2299,9 @@ void LegacySimulator::do_lbfgs()
             // Calculate what the largest change in any individual coordinate
             // would be (translation along line * gradient along line)
             maxdelta = 0;
-            for (i = 0; i < n; i++)
+            for (int i = 0; i < n; i++)
             {
-                delta = c * s[i];
+                real delta = c * s[i];
                 if (delta > maxdelta)
                 {
                     maxdelta = delta;
@@ -1968,7 +2316,7 @@ void LegacySimulator::do_lbfgs()
 
         // Take a trial step and move the coordinate array xc[] to position C
         real* xc = static_cast<real*>(sc->s.x.rvec_array()[0]);
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < n; i++)
         {
             xc[i] = lastx[i] + c * s[i];
         }
@@ -1978,8 +2326,9 @@ void LegacySimulator::do_lbfgs()
         energyEvaluator.run(sc, mu_tot, vir, pres, step, FALSE);
 
         // Calc line gradient in position C
-        real* fc = static_cast<real*>(sc->f.view().force()[0]);
-        for (gpc = 0, i = 0; i < n; i++)
+        real*  fc  = static_cast<real*>(sc->f.view().force()[0]);
+        double gpc = 0;
+        for (int i = 0; i < n; i++)
         {
             gpc -= s[i] * fc[i]; /* f is negative gradient, thus the sign */
         }
@@ -1992,11 +2341,11 @@ void LegacySimulator::do_lbfgs()
         // 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 = std::sqrt(GMX_REAL_EPS) * fabs(sa->epot);
+        double tmp = std::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.
-        foundlower = sc->epot < sa->epot || (gpc < 0 && sc->epot < (sa->epot + tmp));
+        bool foundlower = sc->epot < sa->epot || (gpc < 0 && sc->epot < (sa->epot + tmp));
         // If true, 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
         // search direction instead, which will be much more efficient than continuing
@@ -2012,6 +2361,7 @@ void LegacySimulator::do_lbfgs()
         // than with the stepsize, so no need to modify it. For the next search direction
         // it will be reset to 1/fnorm anyway.
 
+        double step_taken;
         if (!foundlower)
         {
             // OK, if we didn't find a lower value we will have to locate one now - there must
@@ -2022,14 +2372,15 @@ void LegacySimulator::do_lbfgs()
             // 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.
-            real fnorm = 0;
-            nminstep   = 0;
+            real fnorm    = 0;
+            int  nminstep = 0;
             do
             {
                 // Select a new trial point B in the interval [A,C].
                 // If the derivatives at points a & c have different sign we interpolate to zero,
                 // otherwise just do a bisection since there might be multiple minima/maxima
                 // inside the interval.
+                real b;
                 if (gpa < 0 && gpc > 0)
                 {
                     b = a + gpa * (a - c) / (gpc - gpa);
@@ -2049,7 +2400,7 @@ void LegacySimulator::do_lbfgs()
 
                 // Take a trial step to point B
                 real* xb = static_cast<real*>(sb->s.x.rvec_array()[0]);
-                for (i = 0; i < n; i++)
+                for (int i = 0; i < n; i++)
                 {
                     xb[i] = lastx[i] + b * s[i];
                 }
@@ -2060,8 +2411,9 @@ void LegacySimulator::do_lbfgs()
                 fnorm = sb->fnorm;
 
                 // Calculate gradient in point B
-                real* fb = static_cast<real*>(sb->f.view().force()[0]);
-                for (gpb = 0, i = 0; i < n; i++)
+                real*  fb  = static_cast<real*>(sb->f.view().force()[0]);
+                double gpb = 0;
+                for (int i = 0; i < n; i++)
                 {
                     gpb -= s[i] * fb[i]; /* f is negative gradient, thus the sign */
                 }
@@ -2105,7 +2457,7 @@ void LegacySimulator::do_lbfgs()
                 if (ncorr == 0)
                 {
                     /* Converged */
-                    converged = TRUE;
+                    converged = true;
                     break;
                 }
                 else
@@ -2113,7 +2465,7 @@ void LegacySimulator::do_lbfgs()
                     /* Reset memory */
                     ncorr = 0;
                     /* Search in gradient direction */
-                    for (i = 0; i < n; i++)
+                    for (int i = 0; i < n; i++)
                     {
                         dx[point][i] = ff[i];
                     }
@@ -2156,21 +2508,21 @@ void LegacySimulator::do_lbfgs()
             ncorr++;
         }
 
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < n; i++)
         {
             dg[point][i] = lastf[i] - ff[i];
             dx[point][i] *= step_taken;
         }
 
-        dgdg = 0;
-        dgdx = 0;
-        for (i = 0; i < n; i++)
+        real dgdg = 0;
+        real dgdx = 0;
+        for (int i = 0; i < n; i++)
         {
             dgdg += dg[point][i] * dg[point][i];
             dgdx += dg[point][i] * dx[point][i];
         }
 
-        diag = dgdx / dgdg;
+        const real diag = dgdx / dgdg;
 
         rho[point] = 1.0 / dgdx;
         point++;
@@ -2181,15 +2533,15 @@ void LegacySimulator::do_lbfgs()
         }
 
         /* Update */
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < n; i++)
         {
             p[i] = ff[i];
         }
 
-        cp = point;
+        int cp = point;
 
         /* Recursive update. First go back over the memory points */
-        for (k = 0; k < ncorr; k++)
+        for (int k = 0; k < ncorr; k++)
         {
             cp--;
             if (cp < 0)
@@ -2197,38 +2549,38 @@ void LegacySimulator::do_lbfgs()
                 cp = ncorr - 1;
             }
 
-            sq = 0;
-            for (i = 0; i < n; i++)
+            real sq = 0;
+            for (int i = 0; i < n; i++)
             {
                 sq += dx[cp][i] * p[i];
             }
 
             alpha[cp] = rho[cp] * sq;
 
-            for (i = 0; i < n; i++)
+            for (int i = 0; i < n; i++)
             {
                 p[i] -= alpha[cp] * dg[cp][i];
             }
         }
 
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < n; i++)
         {
             p[i] *= diag;
         }
 
         /* And then go forward again */
-        for (k = 0; k < ncorr; k++)
+        for (int k = 0; k < ncorr; k++)
         {
-            yr = 0;
-            for (i = 0; i < n; i++)
+            real yr = 0;
+            for (int i = 0; i < n; i++)
             {
                 yr += p[i] * dg[cp][i];
             }
 
-            beta = rho[cp] * yr;
-            beta = alpha[cp] - beta;
+            real beta = rho[cp] * yr;
+            beta      = alpha[cp] - beta;
 
-            for (i = 0; i < n; i++)
+            for (int i = 0; i < n; i++)
             {
                 p[i] += beta * dx[cp][i];
             }
@@ -2240,7 +2592,7 @@ void LegacySimulator::do_lbfgs()
             }
         }
 
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < n; i++)
         {
             if (!frozen[i])
             {
@@ -2258,15 +2610,34 @@ void LegacySimulator::do_lbfgs()
             if (mdrunOptions.verbose)
             {
                 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,
-                        ems.epot, ems.fnorm / sqrtNumAtoms, ems.fmax, ems.a_fmax + 1);
+                fprintf(stderr,
+                        "\rStep %d, Epot=%12.6e, Fnorm=%9.3e, Fmax=%9.3e (atom %d)\n",
+                        step,
+                        ems.epot,
+                        ems.fnorm / sqrtNumAtoms,
+                        ems.fmax,
+                        ems.a_fmax + 1);
                 fflush(stderr);
             }
             /* Store the new (lower) energies */
             matrix nullBox = {};
-            energyOutput.addDataAtEnergyStep(false, false, static_cast<double>(step), mdatoms->tmass,
-                                             enerd, nullptr, nullptr, nullBox, PTCouplingArrays(), 0,
-                                             nullptr, nullptr, vir, pres, nullptr, mu_tot, constr);
+            energyOutput.addDataAtEnergyStep(false,
+                                             false,
+                                             static_cast<double>(step),
+                                             mdatoms->tmass,
+                                             enerd,
+                                             nullptr,
+                                             nullptr,
+                                             nullBox,
+                                             PTCouplingArrays(),
+                                             0,
+                                             nullptr,
+                                             nullptr,
+                                             vir,
+                                             pres,
+                                             nullptr,
+                                             mu_tot,
+                                             constr);
 
             do_log = do_per_step(step, inputrec->nstlog);
             do_ene = do_per_step(step, inputrec->nstenergy);
@@ -2277,13 +2648,19 @@ void LegacySimulator::do_lbfgs()
             {
                 EnergyOutput::printHeader(fplog, step, step);
             }
-            energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf), do_ene, FALSE, FALSE,
-                                               do_log ? fplog : nullptr, step, step,
-                                               fr->fcdata.get(), nullptr);
+            energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf),
+                                               do_ene,
+                                               FALSE,
+                                               FALSE,
+                                               do_log ? fplog : nullptr,
+                                               step,
+                                               step,
+                                               fr->fcdata.get(),
+                                               nullptr);
         }
 
         /* Send x and E to IMD client, if bIMD is TRUE. */
-        if (imdSession->run(step, TRUE, state_global->box, state_global->x.rvec_array(), 0) && MASTER(cr))
+        if (imdSession->run(step, TRUE, state_global->box, state_global->x, 0) && MASTER(cr))
         {
             imdSession->sendPositionsAndEnergies();
         }
@@ -2320,8 +2697,14 @@ void LegacySimulator::do_lbfgs()
     }
     if (!do_ene || !do_log) /* Write final energy file entries */
     {
-        energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf), !do_ene, FALSE, FALSE,
-                                           !do_log ? fplog : nullptr, step, step, fr->fcdata.get(),
+        energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf),
+                                           !do_ene,
+                                           FALSE,
+                                           FALSE,
+                                           !do_log ? fplog : nullptr,
+                                           step,
+                                           step,
+                                           fr->fcdata.get(),
                                            nullptr);
     }
 
@@ -2338,10 +2721,10 @@ void LegacySimulator::do_lbfgs()
      * However, we should only do it if we did NOT already write this step
      * above (which we did if do_x or do_f was true).
      */
-    do_x = !do_per_step(step, inputrec->nstxout);
-    do_f = !do_per_step(step, inputrec->nstfout);
-    write_em_traj(fplog, cr, outf, do_x, do_f, ftp2fn(efSTO, nfile, fnm), top_global, inputrec,
-                  step, &ems, state_global, observablesHistory);
+    const bool do_x = !do_per_step(step, inputrec->nstxout);
+    const bool 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, observablesHistory);
 
     if (MASTER(cr))
     {
@@ -2361,7 +2744,7 @@ void LegacySimulator::do_lbfgs()
 void LegacySimulator::do_steep()
 {
     const char*       SD = "Steepest Descents";
-    gmx_localtop_t    top(top_global->ffparams);
+    gmx_localtop_t    top(top_global.ffparams);
     gmx_global_stat_t gstat;
     real              stepsize;
     real              ustep;
@@ -2371,7 +2754,7 @@ void LegacySimulator::do_steep()
     int               nsteps;
     int               count          = 0;
     int               steps_accepted = 0;
-    auto              mdatoms        = mdAtoms->mdatoms();
+    auto*             mdatoms        = mdAtoms->mdatoms();
 
     GMX_LOG(mdlog.info)
             .asParagraph()
@@ -2387,15 +2770,48 @@ void LegacySimulator::do_steep()
     em_state_t* s_try = &s1;
 
     /* Init em and store the local state in s_try */
-    init_em(fplog, mdlog, SD, cr, inputrec, imdSession, pull_work, state_global, top_global, s_try,
-            &top, nrnb, fr, mdAtoms, &gstat, vsite, constr, nullptr);
+    init_em(fplog,
+            mdlog,
+            SD,
+            cr,
+            inputrec,
+            imdSession,
+            pull_work,
+            state_global,
+            top_global,
+            s_try,
+            &top,
+            nrnb,
+            fr,
+            mdAtoms,
+            &gstat,
+            vsite,
+            constr,
+            nullptr);
     const bool        simulationsShareState = false;
-    gmx_mdoutf*       outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider,
-                                   mdModulesNotifier, inputrec, top_global, nullptr, wcycle,
-                                   StartingBehavior::NewSimulation, simulationsShareState, ms);
-    gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf), top_global, inputrec, pull_work,
-                                   nullptr, false, StartingBehavior::NewSimulation,
-                                   simulationsShareState, mdModulesNotifier);
+    gmx_mdoutf*       outf                  = init_mdoutf(fplog,
+                                   nfile,
+                                   fnm,
+                                   mdrunOptions,
+                                   cr,
+                                   outputProvider,
+                                   mdModulesNotifiers,
+                                   inputrec,
+                                   top_global,
+                                   nullptr,
+                                   wcycle,
+                                   StartingBehavior::NewSimulation,
+                                   simulationsShareState,
+                                   ms);
+    gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf),
+                                   top_global,
+                                   *inputrec,
+                                   pull_work,
+                                   nullptr,
+                                   false,
+                                   StartingBehavior::NewSimulation,
+                                   simulationsShareState,
+                                   mdModulesNotifiers);
 
     /* Print to log file  */
     print_em_start(fplog, cr, walltime_accounting, wcycle, SD);
@@ -2439,8 +2855,8 @@ void LegacySimulator::do_steep()
         bool validStep = true;
         if (count > 0)
         {
-            validStep = do_em_step(cr, inputrec, mdatoms, s_min, stepsize,
-                                   s_min->f.view().forceWithPadding(), s_try, constr, count);
+            validStep = do_em_step(
+                    cr, inputrec, mdatoms, s_min, stepsize, s_min->f.view().forceWithPadding(), s_try, constr, count);
         }
 
         if (validStep)
@@ -2468,8 +2884,13 @@ void LegacySimulator::do_steep()
         {
             if (mdrunOptions.verbose)
             {
-                fprintf(stderr, "Step=%5d, Dmax= %6.1e nm, Epot= %12.5e Fmax= %11.5e, atom= %d%c",
-                        count, ustep, s_try->epot, s_try->fmax, s_try->a_fmax + 1,
+                fprintf(stderr,
+                        "Step=%5d, Dmax= %6.1e nm, Epot= %12.5e Fmax= %11.5e, atom= %d%c",
+                        count,
+                        ustep,
+                        s_try->epot,
+                        s_try->fmax,
+                        s_try->a_fmax + 1,
                         ((count == 0) || (s_try->epot < s_min->epot)) ? '\n' : '\r');
                 fflush(stderr);
             }
@@ -2478,17 +2899,30 @@ void LegacySimulator::do_steep()
             {
                 /* Store the new (lower) energies  */
                 matrix nullBox = {};
-                energyOutput.addDataAtEnergyStep(false, false, static_cast<double>(count),
-                                                 mdatoms->tmass, enerd, nullptr, nullptr, nullBox,
-                                                 PTCouplingArrays(), 0, nullptr, nullptr, vir, pres,
-                                                 nullptr, mu_tot, constr);
+                energyOutput.addDataAtEnergyStep(false,
+                                                 false,
+                                                 static_cast<double>(count),
+                                                 mdatoms->tmass,
+                                                 enerd,
+                                                 nullptr,
+                                                 nullptr,
+                                                 nullBox,
+                                                 PTCouplingArrays(),
+                                                 0,
+                                                 nullptr,
+                                                 nullptr,
+                                                 vir,
+                                                 pres,
+                                                 nullptr,
+                                                 mu_tot,
+                                                 constr);
 
                 imdSession->fillEnergyRecord(count, TRUE);
 
                 const bool do_dr = do_per_step(steps_accepted, inputrec->nstdisreout);
                 const bool do_or = do_per_step(steps_accepted, inputrec->nstorireout);
-                energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf), TRUE, do_dr, do_or,
-                                                   fplog, count, count, fr->fcdata.get(), nullptr);
+                energyOutput.printStepToEnergyFile(
+                        mdoutf_get_fp_ene(outf), TRUE, do_dr, do_or, fplog, count, count, fr->fcdata.get(), nullptr);
                 fflush(fplog);
             }
         }
@@ -2517,8 +2951,8 @@ void LegacySimulator::do_steep()
             /* Write to trn, if necessary */
             do_x = do_per_step(steps_accepted, inputrec->nstxout);
             do_f = do_per_step(steps_accepted, inputrec->nstfout);
-            write_em_traj(fplog, cr, outf, do_x, do_f, nullptr, top_global, inputrec, count, s_min,
-                          state_global, observablesHistory);
+            write_em_traj(
+                    fplog, cr, outf, do_x, do_f, nullptr, top_global, inputrec, count, s_min, state_global, observablesHistory);
         }
         else
         {
@@ -2528,8 +2962,22 @@ void LegacySimulator::do_steep()
             if (DOMAINDECOMP(cr) && s_min->s.ddp_count != cr->dd->ddp_count)
             {
                 /* Reload the old state */
-                em_dd_partition_system(fplog, mdlog, count, cr, top_global, inputrec, imdSession,
-                                       pull_work, s_min, &top, mdAtoms, fr, vsite, constr, nrnb, wcycle);
+                em_dd_partition_system(fplog,
+                                       mdlog,
+                                       count,
+                                       cr,
+                                       top_global,
+                                       inputrec,
+                                       imdSession,
+                                       pull_work,
+                                       s_min,
+                                       &top,
+                                       mdAtoms,
+                                       fr,
+                                       vsite,
+                                       constr,
+                                       nrnb,
+                                       wcycle);
             }
         }
 
@@ -2558,8 +3006,11 @@ void LegacySimulator::do_steep()
         }
 
         /* Send IMD energies and positions, if bIMD is TRUE. */
-        if (imdSession->run(count, TRUE, MASTER(cr) ? state_global->box : nullptr,
-                            MASTER(cr) ? state_global->x.rvec_array() : nullptr, 0)
+        if (imdSession->run(count,
+                            TRUE,
+                            MASTER(cr) ? state_global->box : nullptr,
+                            MASTER(cr) ? state_global->x : gmx::ArrayRef<gmx::RVec>(),
+                            0)
             && MASTER(cr))
         {
             imdSession->sendPositionsAndEnergies();
@@ -2573,8 +3024,18 @@ void LegacySimulator::do_steep()
     {
         fprintf(stderr, "\nwriting lowest energy coordinates.\n");
     }
-    write_em_traj(fplog, cr, outf, TRUE, inputrec->nstfout != 0, ftp2fn(efSTO, nfile, fnm),
-                  top_global, inputrec, count, s_min, state_global, observablesHistory);
+    write_em_traj(fplog,
+                  cr,
+                  outf,
+                  TRUE,
+                  inputrec->nstfout != 0,
+                  ftp2fn(efSTO, nfile, fnm),
+                  top_global,
+                  inputrec,
+                  count,
+                  s_min,
+                  state_global,
+                  observablesHistory);
 
     if (MASTER(cr))
     {
@@ -2587,7 +3048,11 @@ void LegacySimulator::do_steep()
     finish_em(cr, outf, walltime_accounting, wcycle);
 
     /* To print the actual number of steps we needed somewhere */
-    inputrec->nsteps = count;
+    {
+        // TODO: Avoid changing inputrec (#3854)
+        auto* nonConstInputrec   = const_cast<t_inputrec*>(inputrec);
+        nonConstInputrec->nsteps = count;
+    }
 
     walltime_accounting_set_nsteps_done(walltime_accounting, count);
 }
@@ -2596,7 +3061,7 @@ void LegacySimulator::do_nm()
 {
     const char*         NM = "Normal Mode Analysis";
     int                 nnodes;
-    gmx_localtop_t      top(top_global->ffparams);
+    gmx_localtop_t      top(top_global.ffparams);
     gmx_global_stat_t   gstat;
     tensor              vir, pres;
     rvec                mu_tot = { 0 };
@@ -2607,11 +3072,11 @@ void LegacySimulator::do_nm()
     real*               full_matrix   = nullptr;
 
     /* added with respect to mdrun */
-    int  row, col;
-    real der_range = 10.0 * std::sqrt(GMX_REAL_EPS);
-    real x_min;
-    bool bIsMaster = MASTER(cr);
-    auto mdatoms   = mdAtoms->mdatoms();
+    int   row, col;
+    real  der_range = 10.0 * std::sqrt(GMX_REAL_EPS);
+    real  x_min;
+    bool  bIsMaster = MASTER(cr);
+    auto* mdatoms   = mdAtoms->mdatoms();
 
     GMX_LOG(mdlog.info)
             .asParagraph()
@@ -2633,12 +3098,39 @@ void LegacySimulator::do_nm()
     em_state_t state_work{};
 
     /* Init em and store the local state in state_minimum */
-    init_em(fplog, mdlog, NM, cr, inputrec, imdSession, pull_work, state_global, top_global,
-            &state_work, &top, nrnb, fr, mdAtoms, &gstat, vsite, constr, &shellfc);
+    init_em(fplog,
+            mdlog,
+            NM,
+            cr,
+            inputrec,
+            imdSession,
+            pull_work,
+            state_global,
+            top_global,
+            &state_work,
+            &top,
+            nrnb,
+            fr,
+            mdAtoms,
+            &gstat,
+            vsite,
+            constr,
+            &shellfc);
     const bool  simulationsShareState = false;
-    gmx_mdoutf* outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider,
-                                   mdModulesNotifier, inputrec, top_global, nullptr, wcycle,
-                                   StartingBehavior::NewSimulation, simulationsShareState, ms);
+    gmx_mdoutf* outf                  = init_mdoutf(fplog,
+                                   nfile,
+                                   fnm,
+                                   mdrunOptions,
+                                   cr,
+                                   outputProvider,
+                                   mdModulesNotifiers,
+                                   inputrec,
+                                   top_global,
+                                   nullptr,
+                                   wcycle,
+                                   StartingBehavior::NewSimulation,
+                                   simulationsShareState,
+                                   ms);
 
     std::vector<int>       atom_index = get_atom_index(top_global);
     std::vector<gmx::RVec> fneg(atom_index.size(), { 0, 0, 0 });
@@ -2699,12 +3191,18 @@ void LegacySimulator::do_nm()
     print_em_start(fplog, cr, walltime_accounting, wcycle, NM);
 
     /* fudge nr of steps to nr of atoms */
-    inputrec->nsteps = atom_index.size() * 2;
+    {
+        // TODO: Avoid changing inputrec (#3854)
+        auto* nonConstInputrec   = const_cast<t_inputrec*>(inputrec);
+        nonConstInputrec->nsteps = atom_index.size() * 2;
+    }
 
     if (bIsMaster)
     {
-        fprintf(stderr, "starting normal mode calculation '%s'\n%" PRId64 " steps.\n\n",
-                *(top_global->name), inputrec->nsteps);
+        fprintf(stderr,
+                "starting normal mode calculation '%s'\n%" PRId64 " steps.\n\n",
+                *(top_global.name),
+                inputrec->nsteps);
     }
 
     nnodes = cr->nnodes;
@@ -2771,13 +3269,38 @@ void LegacySimulator::do_nm()
                 if (shellfc)
                 {
                     /* Now is the time to relax the shells */
-                    relax_shell_flexcon(fplog, cr, ms, mdrunOptions.verbose, nullptr, step, inputrec,
-                                        imdSession, pull_work, bNS, force_flags, &top, constr, enerd,
-                                        state_work.s.natoms, state_work.s.x.arrayRefWithPadding(),
-                                        state_work.s.v.arrayRefWithPadding(), state_work.s.box,
-                                        state_work.s.lambda, &state_work.s.hist, &state_work.f.view(),
-                                        vir, mdatoms, nrnb, wcycle, shellfc, fr, runScheduleWork, t,
-                                        mu_tot, vsite, DDBalanceRegionHandler(nullptr));
+                    relax_shell_flexcon(fplog,
+                                        cr,
+                                        ms,
+                                        mdrunOptions.verbose,
+                                        nullptr,
+                                        step,
+                                        inputrec,
+                                        imdSession,
+                                        pull_work,
+                                        bNS,
+                                        force_flags,
+                                        &top,
+                                        constr,
+                                        enerd,
+                                        state_work.s.natoms,
+                                        state_work.s.x.arrayRefWithPadding(),
+                                        state_work.s.v.arrayRefWithPadding(),
+                                        state_work.s.box,
+                                        state_work.s.lambda,
+                                        &state_work.s.hist,
+                                        &state_work.f.view(),
+                                        vir,
+                                        *mdatoms,
+                                        nrnb,
+                                        wcycle,
+                                        shellfc,
+                                        fr,
+                                        runScheduleWork,
+                                        t,
+                                        mu_tot,
+                                        vsite,
+                                        DDBalanceRegionHandler(nullptr));
                     bNS = false;
                     step++;
                 }
@@ -2790,8 +3313,7 @@ void LegacySimulator::do_nm()
 
                 if (dx == 0)
                 {
-                    std::copy(state_work_f.begin(), state_work_f.begin() + atom_index.size(),
-                              fneg.begin());
+                    std::copy(state_work_f.begin(), state_work_f.begin() + atom_index.size(), fneg.begin());
                 }
             }
 
@@ -2810,8 +3332,7 @@ void LegacySimulator::do_nm()
             {
 #if GMX_MPI
 #    define mpi_type GMX_MPI_REAL
-                MPI_Send(dfdx[0], atom_index.size() * DIM, mpi_type, MASTER(cr), cr->nodeid,
-                         cr->mpi_comm_mygroup);
+                MPI_Send(dfdx[0], atom_index.size() * DIM, mpi_type, MASTER(cr), cr->nodeid, cr->mpi_comm_mygroup);
 #endif
             }
             else
@@ -2822,8 +3343,7 @@ void LegacySimulator::do_nm()
                     {
 #if GMX_MPI
                         MPI_Status stat;
-                        MPI_Recv(dfdx[0], atom_index.size() * DIM, mpi_type, node, node,
-                                 cr->mpi_comm_mygroup, &stat);
+                        MPI_Recv(dfdx[0], atom_index.size() * DIM, mpi_type, node, node, cr->mpi_comm_mygroup, &stat);
 #    undef mpi_type
 #endif
                     }
@@ -2860,8 +3380,10 @@ void LegacySimulator::do_nm()
         /* write progress */
         if (bIsMaster && mdrunOptions.verbose)
         {
-            fprintf(stderr, "\rFinished step %d out of %td",
-                    std::min<int>(atom + nnodes, atom_index.size()), ssize(atom_index));
+            fprintf(stderr,
+                    "\rFinished step %d out of %td",
+                    std::min<int>(atom + nnodes, atom_index.size()),
+                    ssize(atom_index));
             fflush(stderr);
         }
     }
index c40161d9ef31b4a88521ca77c7e75e32dd207389..5ec63824c2adfd63b4aee20995e869fd241e89d0 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-2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2011-2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "gmxpre.h"
 
+#include "gromacs/utility/enumerationhelpers.h"
 #include "replicaexchange.h"
 
 #include "config.h"
@@ -66,6 +67,7 @@
 #include "gromacs/random/threefry.h"
 #include "gromacs/random/uniformintdistribution.h"
 #include "gromacs/random/uniformrealdistribution.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/smalloc.h"
@@ -79,13 +81,13 @@ constexpr int c_probabilityCutoff = 100;
 #define MSRANK(ms, nodeid) (nodeid)
 
 //! Enum for replica exchange flavours
-enum
+enum class ReplicaExchangeType : int
 {
-    ereTEMP,
-    ereLAMBDA,
-    ereENDSINGLE,
-    ereTL,
-    ereNR
+    Temperature,
+    Lambda,
+    EndSingle,
+    TemperatureLambda,
+    Count
 };
 /*! \brief Strings describing replica exchange flavours.
  *
@@ -97,8 +99,13 @@ enum
  *  'lambda_and_pressure', 'temperature_lambda_pressure'?; Let's wait
  *  until we feel better about the pressure control methods giving
  *  exact ensembles.  Right now, we assume constant pressure */
-static const char* erename[ereNR] = { "temperature", "lambda", "end_single_marker",
-                                      "temperature and lambda" };
+static const char* enumValueToString(ReplicaExchangeType enumValue)
+{
+    constexpr gmx::EnumerationArray<ReplicaExchangeType, const char*> replicateExchangeTypeNames = {
+        "temperature", "lambda", "end_single_marker", "temperature and lambda"
+    };
+    return replicateExchangeTypeNames[enumValue];
+}
 
 //! Working data for replica exchange.
 struct gmx_repl_ex
@@ -109,10 +116,10 @@ struct gmx_repl_ex
     int nrepl;
     //! Temperature
     real temp;
-    //! Replica exchange type from ere enum
-    int type;
+    //! Replica exchange type from ReplicaExchangeType enum
+    ReplicaExchangeType type;
     //! Quantity, e.g. temperature or lambda; first index is ere, second index is replica ID
-    real** q;
+    gmx::EnumerationArray<ReplicaExchangeType, real*> q;
     //! Use constant pressure and temperature
     gmx_bool bNPT;
     //! Replica pressures
@@ -160,7 +167,7 @@ struct gmx_repl_ex
 // TODO We should add Doxygen here some time.
 //! \cond
 
-static gmx_bool repl_quantity(const gmx_multisim_t* ms, struct gmx_repl_ex* re, int ere, real q)
+static gmx_bool repl_quantity(const gmx_multisim_t* ms, struct gmx_repl_ex* re, ReplicaExchangeType ere, real q)
 {
     real*    qall;
     gmx_bool bDiff;
@@ -237,7 +244,6 @@ gmx_repl_ex_t init_replica_exchange(FILE*                            fplog,
 
     re->repl  = ms->simulationIndex_;
     re->nrepl = ms->numSimulations_;
-    snew(re->q, ereENDSINGLE);
 
     fprintf(fplog, "Repl  There are %d replicas:\n", re->nrepl);
 
@@ -246,15 +252,15 @@ gmx_repl_ex_t init_replica_exchange(FILE*                            fplog,
      * but it does guarantee that we can perform replica exchange.
      */
     check_multi_int(fplog, ms, numAtomsInSystem, "the number of atoms", FALSE);
-    check_multi_int(fplog, ms, ir->eI, "the integrator", FALSE);
+    check_multi_int(fplog, ms, static_cast<int>(ir->eI), "the integrator", FALSE);
     check_multi_int64(fplog, ms, ir->init_step + ir->nsteps, "init_step+nsteps", FALSE);
     const int nst = replExParams.exchangeInterval;
-    check_multi_int64(fplog, ms, (ir->init_step + nst - 1) / nst,
-                      "first exchange step: init_step/-replex", FALSE);
-    check_multi_int(fplog, ms, ir->etc, "the temperature coupling", FALSE);
+    check_multi_int64(
+            fplog, ms, (ir->init_step + nst - 1) / nst, "first exchange step: init_step/-replex", FALSE);
+    check_multi_int(fplog, ms, static_cast<int>(ir->etc), "the temperature coupling", FALSE);
     check_multi_int(fplog, ms, ir->opts.ngtc, "the number of temperature coupling groups", FALSE);
-    check_multi_int(fplog, ms, ir->epc, "the pressure coupling", FALSE);
-    check_multi_int(fplog, ms, ir->efep, "free energy", FALSE);
+    check_multi_int(fplog, ms, static_cast<int>(ir->epc), "the pressure coupling", FALSE);
+    check_multi_int(fplog, ms, static_cast<int>(ir->efep), "free energy", FALSE);
     check_multi_int(fplog, ms, ir->fepvals->n_lambda, "number of lambda states", FALSE);
 
     re->temp = ir->opts.ref_t[0];
@@ -271,13 +277,14 @@ gmx_repl_ex_t init_replica_exchange(FILE*                            fplog,
         }
     }
 
-    re->type = -1;
-    bTemp    = repl_quantity(ms, re, ereTEMP, re->temp);
-    if (ir->efep != efepNO)
+    re->type = ReplicaExchangeType::Count;
+    bTemp    = repl_quantity(ms, re, ReplicaExchangeType::Temperature, re->temp);
+    if (ir->efep != FreeEnergyPerturbationType::No)
     {
-        bLambda = repl_quantity(ms, re, ereLAMBDA, static_cast<real>(ir->fepvals->init_fep_state));
+        bLambda = repl_quantity(
+                ms, re, ReplicaExchangeType::Lambda, static_cast<real>(ir->fepvals->init_fep_state));
     }
-    if (re->type == -1) /* nothing was assigned */
+    if (re->type == ReplicaExchangeType::Count) /* nothing was assigned */
     {
         gmx_fatal(FARGS,
                   "The properties of the %d systems are all the same, there is nothing to exchange",
@@ -285,24 +292,25 @@ gmx_repl_ex_t init_replica_exchange(FILE*                            fplog,
     }
     if (bLambda && bTemp)
     {
-        re->type = ereTL;
+        re->type = ReplicaExchangeType::TemperatureLambda;
     }
 
     if (bTemp)
     {
         please_cite(fplog, "Sugita1999a");
-        if (ir->epc != epcNO)
+        if (ir->epc != PressureCoupling::No)
         {
             re->bNPT = TRUE;
             fprintf(fplog, "Repl  Using Constant Pressure REMD.\n");
             please_cite(fplog, "Okabe2001a");
         }
-        if (ir->etc == etcBERENDSEN)
+        if (ir->etc == TemperatureCoupling::Berendsen)
         {
             gmx_fatal(FARGS,
                       "REMD with the %s thermostat does not produce correct potential energy "
                       "distributions, consider using the %s thermostat instead",
-                      ETCOUPLTYPE(ir->etc), ETCOUPLTYPE(etcVRESCALE));
+                      enumValueToString(ir->etc),
+                      enumValueToString(TemperatureCoupling::VRescale));
         }
     }
     if (bLambda)
@@ -315,7 +323,7 @@ gmx_repl_ex_t init_replica_exchange(FILE*                            fplog,
     if (re->bNPT)
     {
         snew(re->pres, re->nrepl);
-        if (ir->epct == epctSURFACETENSION)
+        if (ir->epct == PressureCouplingType::SurfaceTension)
         {
             pres = ir->ref_p[ZZ][ZZ];
         }
@@ -346,7 +354,7 @@ gmx_repl_ex_t init_replica_exchange(FILE*                            fplog,
         re->ind[i] = i;
     }
 
-    if (re->type < ereENDSINGLE)
+    if (re->type < ReplicaExchangeType::EndSingle)
     {
 
         for (i = 0; i < re->nrepl; i++)
@@ -362,12 +370,16 @@ gmx_repl_ex_t init_replica_exchange(FILE*                            fplog,
                     gmx_fatal(FARGS,
                               "Replicas with indices %d < %d have %ss %g > %g, please order your "
                               "replicas on increasing %s",
-                              i, j, erename[re->type], re->q[re->type][i], re->q[re->type][j],
-                              erename[re->type]);
+                              i,
+                              j,
+                              enumValueToString(re->type),
+                              re->q[re->type][i],
+                              re->q[re->type][j],
+                              enumValueToString(re->type));
                 }
                 else if (re->q[re->type][re->ind[j]] == re->q[re->type][re->ind[i]])
                 {
-                    gmx_fatal(FARGS, "Two replicas have identical %ss", erename[re->type]);
+                    gmx_fatal(FARGS, "Two replicas have identical %ss", enumValueToString(re->type));
                 }
             }
         }
@@ -382,7 +394,7 @@ gmx_repl_ex_t init_replica_exchange(FILE*                            fplog,
 
     switch (re->type)
     {
-        case ereTEMP:
+        case ReplicaExchangeType::Temperature:
             fprintf(fplog, "\nReplica exchange in temperature\n");
             for (i = 0; i < re->nrepl; i++)
             {
@@ -390,7 +402,7 @@ gmx_repl_ex_t init_replica_exchange(FILE*                            fplog,
             }
             fprintf(fplog, "\n");
             break;
-        case ereLAMBDA:
+        case ReplicaExchangeType::Lambda:
             fprintf(fplog, "\nReplica exchange in lambda\n");
             for (i = 0; i < re->nrepl; i++)
             {
@@ -398,16 +410,16 @@ gmx_repl_ex_t init_replica_exchange(FILE*                            fplog,
             }
             fprintf(fplog, "\n");
             break;
-        case ereTL:
+        case ReplicaExchangeType::TemperatureLambda:
             fprintf(fplog, "\nReplica exchange in temperature and lambda state\n");
             for (i = 0; i < re->nrepl; i++)
             {
-                fprintf(fplog, " %5.1f", re->q[ereTEMP][re->ind[i]]);
+                fprintf(fplog, " %5.1f", re->q[ReplicaExchangeType::Temperature][re->ind[i]]);
             }
             fprintf(fplog, "\n");
             for (i = 0; i < re->nrepl; i++)
             {
-                fprintf(fplog, " %5d", static_cast<int>(re->q[ereLAMBDA][re->ind[i]]));
+                fprintf(fplog, " %5d", static_cast<int>(re->q[ReplicaExchangeType::Lambda][re->ind[i]]));
             }
             fprintf(fplog, "\n");
             break;
@@ -544,8 +556,7 @@ static void exchange_doubles(const gmx_multisim_t gmx_unused* ms, int gmx_unused
             MPI_Request mpi_req;
 
             MPI_Isend(v, n * sizeof(double), MPI_BYTE, MSRANK(ms, b), 0, ms->mastersComm_, &mpi_req);
-            MPI_Recv(buf, n * sizeof(double), MPI_BYTE, MSRANK(ms, b), 0, ms->mastersComm_,
-                     MPI_STATUS_IGNORE);
+            MPI_Recv(buf, n * sizeof(double), MPI_BYTE, MSRANK(ms, b), 0, ms->mastersComm_, MPI_STATUS_IGNORE);
             MPI_Wait(&mpi_req, MPI_STATUS_IGNORE);
         }
 #endif
@@ -575,8 +586,7 @@ static void exchange_rvecs(const gmx_multisim_t gmx_unused* ms, int gmx_unused b
             MPI_Request mpi_req;
 
             MPI_Isend(v[0], n * sizeof(rvec), MPI_BYTE, MSRANK(ms, b), 0, ms->mastersComm_, &mpi_req);
-            MPI_Recv(buf[0], n * sizeof(rvec), MPI_BYTE, MSRANK(ms, b), 0, ms->mastersComm_,
-                     MPI_STATUS_IGNORE);
+            MPI_Recv(buf[0], n * sizeof(rvec), MPI_BYTE, MSRANK(ms, b), 0, ms->mastersComm_, MPI_STATUS_IGNORE);
             MPI_Wait(&mpi_req, MPI_STATUS_IGNORE);
         }
 #endif
@@ -767,14 +777,14 @@ static real calc_delta(FILE* fplog, gmx_bool bPrint, struct gmx_repl_ex* re, int
 
     switch (re->type)
     {
-        case ereTEMP:
+        case ReplicaExchangeType::Temperature:
             /*
              * Okabe et. al. Chem. Phys. Lett. 335 (2001) 435-439
              */
             ediff = Epot[b] - Epot[a];
             delta = -(beta[bp] - beta[ap]) * ediff;
             break;
-        case ereLAMBDA:
+        case ReplicaExchangeType::Lambda:
             /* two cases:  when we are permuted, and not.  */
             /* non-permuted:
                ediff =  E_new - E_old
@@ -802,7 +812,7 @@ static real calc_delta(FILE* fplog, gmx_bool bPrint, struct gmx_repl_ex* re, int
             ediff = (de[bp][a] - de[ap][a]) + (de[ap][b] - de[bp][b]);
             delta = ediff * beta[a]; /* assume all same temperature in this case */
             break;
-        case ereTL:
+        case ReplicaExchangeType::TemperatureLambda:
             /* not permuted:  */
             /* delta =  reduced E_new - reduced E_old
                      =  [beta_b H_b(x_a) + beta_a H_a(x_b)] - [beta_b H_b(x_b) + beta_a H_a(x_a)]
@@ -840,7 +850,7 @@ static real calc_delta(FILE* fplog, gmx_bool bPrint, struct gmx_repl_ex* re, int
     if (re->bNPT)
     {
         /* revist the calculation for 5.0.  Might be some improvements. */
-        dpV = (beta[ap] * re->pres[ap] - beta[bp] * re->pres[bp]) * (Vol[b] - Vol[a]) / PRESFAC;
+        dpV = (beta[ap] * re->pres[ap] - beta[bp] * re->pres[bp]) * (Vol[b] - Vol[a]) / gmx::c_presfac;
         if (bPrint)
         {
             fprintf(fplog, "  dpV = %10.3e  d = %10.3e\n", dpV, delta + dpV);
@@ -883,7 +893,7 @@ static void test_for_replica_exchange(FILE*                 fplog,
         bVol              = TRUE;
         re->Vol[re->repl] = vol;
     }
-    if ((re->type == ereTEMP || re->type == ereTL))
+    if ((re->type == ReplicaExchangeType::Temperature || re->type == ReplicaExchangeType::TemperatureLambda))
     {
         for (i = 0; i < re->nrepl; i++)
         {
@@ -894,17 +904,17 @@ static void test_for_replica_exchange(FILE*                 fplog,
         /* temperatures of different states*/
         for (i = 0; i < re->nrepl; i++)
         {
-            re->beta[i] = 1.0 / (re->q[ereTEMP][i] * BOLTZ);
+            re->beta[i] = 1.0 / (re->q[ReplicaExchangeType::Temperature][i] * gmx::c_boltz);
         }
     }
     else
     {
         for (i = 0; i < re->nrepl; i++)
         {
-            re->beta[i] = 1.0 / (re->temp * BOLTZ); /* we have a single temperature */
+            re->beta[i] = 1.0 / (re->temp * gmx::c_boltz); /* we have a single temperature */
         }
     }
-    if (re->type == ereLAMBDA || re->type == ereTL)
+    if (re->type == ReplicaExchangeType::Lambda || re->type == ReplicaExchangeType::TemperatureLambda)
     {
         bDLambda = TRUE;
         /* lambda differences. */
@@ -919,7 +929,8 @@ static void test_for_replica_exchange(FILE*                 fplog,
         }
         for (i = 0; i < re->nrepl; i++)
         {
-            re->de[i][re->repl] = enerd->foreignLambdaTerms.deltaH(re->q[ereLAMBDA][i]);
+            re->de[i][re->repl] =
+                    enerd->foreignLambdaTerms.deltaH(re->q[ReplicaExchangeType::Lambda][i]);
         }
     }
 
@@ -1317,10 +1328,12 @@ gmx_bool replica_exchange(FILE*                 fplog,
             }
             /* For temperature-type replica exchange, we need to scale
              * the velocities. */
-            if (re->type == ereTEMP || re->type == ereTL)
+            if (re->type == ReplicaExchangeType::Temperature || re->type == ReplicaExchangeType::TemperatureLambda)
             {
-                scale_velocities(state->v, std::sqrt(re->q[ereTEMP][replica_id]
-                                                     / re->q[ereTEMP][re->destinations[replica_id]]));
+                scale_velocities(
+                        state->v,
+                        std::sqrt(re->q[ReplicaExchangeType::Temperature][replica_id]
+                                  / re->q[ReplicaExchangeType::Temperature][re->destinations[replica_id]]));
             }
         }
 
@@ -1343,8 +1356,11 @@ void print_replica_exchange_statistics(FILE* fplog, struct gmx_repl_ex* re)
 
     if (re->nex == 0)
     {
-        fprintf(fplog, "Repl  %d attempts, %d odd, %d even\n", re->nattempt[0] + re->nattempt[1],
-                re->nattempt[1], re->nattempt[0]);
+        fprintf(fplog,
+                "Repl  %d attempts, %d odd, %d even\n",
+                re->nattempt[0] + re->nattempt[1],
+                re->nattempt[1],
+                re->nattempt[0]);
 
         fprintf(fplog, "Repl  average probabilities:\n");
         for (i = 1; i < re->nrepl; i++)
index 36333d3c94273c5ecc147dfce8c94fc1d6824988..78271fae4824e620cf3969fc14ce6097ad9a40e2 100644 (file)
@@ -145,13 +145,11 @@ using gmx::VirtualSitesHandler;
  * \param[in,out] globalState     The global state container
  * \param[in]     constructVsites When true, vsite coordinates are constructed
  * \param[in]     vsite           Vsite setup, can be nullptr when \p constructVsites = false
- * \param[in]     timeStep        Time step, used for constructing vsites
  */
 static void prepareRerunState(const t_trxframe&          rerunFrame,
                               t_state*                   globalState,
                               bool                       constructVsites,
-                              const VirtualSitesHandler* vsite,
-                              double                     timeStep)
+                              const VirtualSitesHandler* vsite)
 {
     auto x      = makeArrayRef(globalState->x);
     auto rerunX = arrayRefFromArray(reinterpret_cast<gmx::RVec*>(rerunFrame.x), globalState->natoms);
@@ -162,7 +160,7 @@ static void prepareRerunState(const t_trxframe&          rerunFrame,
     {
         GMX_ASSERT(vsite, "Need valid vsite for constructing vsites");
 
-        vsite->construct(globalState->x, timeStep, globalState->v, globalState->box);
+        vsite->construct(globalState->x, globalState->v, globalState->box, gmx::VSiteOperation::PositionsAndVelocities);
     }
 }
 
@@ -174,7 +172,7 @@ void gmx::LegacySimulator::do_rerun()
     // alias to avoid a large ripple of nearly useless changes.
     // t_inputrec is being replaced by IMdpOptionsProvider, so this
     // will go away eventually.
-    t_inputrec*       ir = inputrec;
+    const t_inputrec* ir = inputrec;
     int64_t           step, step_rel;
     double            t;
     bool              isLastStep               = false;
@@ -184,22 +182,13 @@ void gmx::LegacySimulator::do_rerun()
     t_trxstatus*      status = nullptr;
     rvec              mu_tot;
     t_trxframe        rerun_fr;
-    gmx_localtop_t    top(top_global->ffparams);
+    gmx_localtop_t    top(top_global.ffparams);
     ForceBuffers      f;
     gmx_global_stat_t gstat;
     gmx_shellfc_t*    shellfc;
 
     double cycles;
 
-    /* Domain decomposition could incorrectly miss a bonded
-       interaction, but checking for that requires a global
-       communication stage, which does not otherwise happen in DD
-       code. So we do that alongside the first global energy reduction
-       after a new DD is made. These variables handle whether the
-       check happens, and the result it returns. */
-    bool shouldCheckNumberOfBondedInteractions = false;
-    int  totalNumberOfBondedInteractions       = -1;
-
     SimulationSignals signals;
     // Most global communnication stages don't propagate mdrun
     // signals, and will use this object to achieve that.
@@ -212,7 +201,7 @@ void gmx::LegacySimulator::do_rerun()
                     "be available in a different form in a future version of GROMACS, "
                     "e.g. gmx rerun -f.");
 
-    if (ir->efep != efepNO
+    if (ir->efep != FreeEnergyPerturbationType::No
         && (mdAtoms->mdatoms()->nMassPerturbed > 0 || (constr && constr->havePerturbedConstraints())))
     {
         gmx_fatal(FARGS,
@@ -248,8 +237,9 @@ void gmx::LegacySimulator::do_rerun()
     {
         gmx_fatal(FARGS, "Multiple simulations not supported by rerun.");
     }
-    if (std::any_of(ir->opts.annealing, ir->opts.annealing + ir->opts.ngtc,
-                    [](int i) { return i != eannNO; }))
+    if (std::any_of(ir->opts.annealing, ir->opts.annealing + ir->opts.ngtc, [](SimulatedAnnealing i) {
+            return i != SimulatedAnnealing::No;
+        }))
     {
         gmx_fatal(FARGS, "Simulated annealing not supported by rerun.");
     }
@@ -268,38 +258,70 @@ void gmx::LegacySimulator::do_rerun()
     }
 
     /* Settings for rerun */
-    ir->nstlist              = 1;
-    ir->nstcalcenergy        = 1;
+    {
+        // TODO: Avoid changing inputrec (#3854)
+        auto* nonConstInputrec               = const_cast<t_inputrec*>(inputrec);
+        nonConstInputrec->nstlist            = 1;
+        nonConstInputrec->nstcalcenergy      = 1;
+        nonConstInputrec->nstxout_compressed = 0;
+    }
     int        nstglobalcomm = 1;
     const bool bNS           = true;
 
-    ir->nstxout_compressed         = 0;
-    const SimulationGroups* groups = &top_global->groups;
-    if (ir->eI == eiMimic)
+    const SimulationGroups* groups = &top_global.groups;
+    if (ir->eI == IntegrationAlgorithm::Mimic)
     {
-        auto nonConstGlobalTopology                          = const_cast<gmx_mtop_t*>(top_global);
-        nonConstGlobalTopology->intermolecularExclusionGroup = genQmmmIndices(*top_global);
+        auto* nonConstGlobalTopology                         = const_cast<gmx_mtop_t*>(&top_global);
+        nonConstGlobalTopology->intermolecularExclusionGroup = genQmmmIndices(top_global);
     }
     int*                fep_state = MASTER(cr) ? &state_global->fep_state : nullptr;
     gmx::ArrayRef<real> lambda    = MASTER(cr) ? state_global->lambda : gmx::ArrayRef<real>();
-    initialize_lambdas(fplog, *ir, MASTER(cr), fep_state, lambda);
+    initialize_lambdas(fplog,
+                       ir->efep,
+                       ir->bSimTemp,
+                       *ir->fepvals,
+                       ir->simtempvals->temperatures,
+                       gmx::arrayRefFromArray(ir->opts.ref_t, ir->opts.ngtc),
+                       MASTER(cr),
+                       fep_state,
+                       lambda);
     const bool        simulationsShareState = false;
-    gmx_mdoutf*       outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider,
-                                   mdModulesNotifier, ir, top_global, oenv, wcycle,
-                                   StartingBehavior::NewSimulation, simulationsShareState, ms);
-    gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf), top_global, ir, pull_work,
-                                   mdoutf_get_fp_dhdl(outf), true, StartingBehavior::NewSimulation,
-                                   simulationsShareState, mdModulesNotifier);
+    gmx_mdoutf*       outf                  = init_mdoutf(fplog,
+                                   nfile,
+                                   fnm,
+                                   mdrunOptions,
+                                   cr,
+                                   outputProvider,
+                                   mdModulesNotifiers,
+                                   ir,
+                                   top_global,
+                                   oenv,
+                                   wcycle,
+                                   StartingBehavior::NewSimulation,
+                                   simulationsShareState,
+                                   ms);
+    gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf),
+                                   top_global,
+                                   *ir,
+                                   pull_work,
+                                   mdoutf_get_fp_dhdl(outf),
+                                   true,
+                                   StartingBehavior::NewSimulation,
+                                   simulationsShareState,
+                                   mdModulesNotifiers);
 
     gstat = global_stat_init(ir);
 
     /* Check for polarizable models and flexible constraints */
-    shellfc = init_shell_flexcon(fplog, top_global, constr ? constr->numFlexibleConstraints() : 0,
-                                 ir->nstcalcenergy, DOMAINDECOMP(cr),
+    shellfc = init_shell_flexcon(fplog,
+                                 top_global,
+                                 constr ? constr->numFlexibleConstraints() : 0,
+                                 ir->nstcalcenergy,
+                                 DOMAINDECOMP(cr),
                                  runScheduleWork->simulationWork.useGpuPme);
 
     {
-        double io = compute_io(ir, top_global->natoms, *groups, energyOutput.numEnergyTerms(), 1);
+        double io = compute_io(ir, top_global.natoms, *groups, energyOutput.numEnergyTerms(), 1);
         if ((io > 2000) && MASTER(cr))
         {
             fprintf(stderr, "\nWARNING: This run will generate roughly %.0f Mb of data\n\n", io);
@@ -314,13 +336,30 @@ void gmx::LegacySimulator::do_rerun()
     {
         stateInstance = std::make_unique<t_state>();
         state         = stateInstance.get();
-        dd_init_local_state(cr->dd, state_global, state);
+        dd_init_local_state(*cr->dd, state_global, state);
 
         /* Distribute the charge groups over the nodes from the master node */
-        dd_partition_system(fplog, mdlog, ir->init_step, cr, TRUE, 1, state_global, *top_global, ir,
-                            imdSession, pull_work, state, &f, mdAtoms, &top, fr, vsite, constr,
-                            nrnb, nullptr, FALSE);
-        shouldCheckNumberOfBondedInteractions = true;
+        dd_partition_system(fplog,
+                            mdlog,
+                            ir->init_step,
+                            cr,
+                            TRUE,
+                            1,
+                            state_global,
+                            top_global,
+                            *ir,
+                            imdSession,
+                            pull_work,
+                            state,
+                            &f,
+                            mdAtoms,
+                            &top,
+                            fr,
+                            vsite,
+                            constr,
+                            nrnb,
+                            nullptr,
+                            FALSE);
     }
     else
     {
@@ -328,44 +367,67 @@ void gmx::LegacySimulator::do_rerun()
         /* Copy the pointer to the global state */
         state = state_global;
 
-        mdAlgorithmsSetupAtomData(cr, ir, *top_global, &top, fr, &f, mdAtoms, constr, vsite, shellfc);
+        mdAlgorithmsSetupAtomData(cr, *ir, top_global, &top, fr, &f, mdAtoms, constr, vsite, shellfc);
     }
 
-    auto mdatoms = mdAtoms->mdatoms();
+    auto* mdatoms = mdAtoms->mdatoms();
 
     // NOTE: The global state is no longer used at this point.
     // But state_global is still used as temporary storage space for writing
     // the global state to file and potentially for replica exchange.
     // (Global topology should persist.)
 
-    update_mdatoms(mdatoms, state->lambda[efptMASS]);
+    update_mdatoms(mdatoms, state->lambda[FreeEnergyPerturbationCouplingType::Mass]);
 
-    if (ir->efep != efepNO && ir->fepvals->nstdhdl != 0)
+    if (ir->efep != FreeEnergyPerturbationType::No && ir->fepvals->nstdhdl != 0)
     {
         doFreeEnergyPerturbation = true;
     }
 
     {
-        int cglo_flags =
-                (CGLO_GSTAT
-                 | (shouldCheckNumberOfBondedInteractions ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS : 0));
+        int cglo_flags = CGLO_GSTAT;
+        if (DOMAINDECOMP(cr) && shouldCheckNumberOfBondedInteractions(*cr->dd))
+        {
+            cglo_flags |= CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS;
+        }
         bool   bSumEkinhOld = false;
         t_vcm* vcm          = nullptr;
-        compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
-                        makeConstArrayRef(state->v), state->box, mdatoms, nrnb, vcm, nullptr, enerd,
-                        force_vir, shake_vir, total_vir, pres, constr, &nullSignaller, state->box,
-                        &totalNumberOfBondedInteractions, &bSumEkinhOld, cglo_flags);
+        compute_globals(gstat,
+                        cr,
+                        ir,
+                        fr,
+                        ekind,
+                        makeConstArrayRef(state->x),
+                        makeConstArrayRef(state->v),
+                        state->box,
+                        mdatoms,
+                        nrnb,
+                        vcm,
+                        nullptr,
+                        enerd,
+                        force_vir,
+                        shake_vir,
+                        total_vir,
+                        pres,
+                        gmx::ArrayRef<real>{},
+                        &nullSignaller,
+                        state->box,
+                        &bSumEkinhOld,
+                        cglo_flags);
+        if (DOMAINDECOMP(cr))
+        {
+            checkNumberOfBondedInteractions(
+                    mdlog, cr, top_global, &top, makeConstArrayRef(state->x), state->box);
+        }
     }
-    checkNumberOfBondedInteractions(mdlog, cr, totalNumberOfBondedInteractions, top_global, &top,
-                                    makeConstArrayRef(state->x), state->box,
-                                    &shouldCheckNumberOfBondedInteractions);
 
     if (MASTER(cr))
     {
         fprintf(stderr,
                 "starting md rerun '%s', reading coordinates from"
                 " input trajectory '%s'\n\n",
-                *(top_global->name), opt2fn("-rerun", nfile, fnm));
+                *(top_global.name),
+                opt2fn("-rerun", nfile, fnm));
         if (mdrunOptions.verbose)
         {
             fprintf(stderr,
@@ -377,7 +439,7 @@ void gmx::LegacySimulator::do_rerun()
     }
 
     walltime_accounting_start_time(walltime_accounting);
-    wallcycle_start(wcycle, ewcRUN);
+    wallcycle_start(wcycle, WallCycleCounter::Run);
     print_start(fplog, cr, walltime_accounting, "mdrun");
 
     /***********************************************************
@@ -397,12 +459,13 @@ void gmx::LegacySimulator::do_rerun()
     if (MASTER(cr))
     {
         isLastStep = !read_first_frame(oenv, &status, opt2fn("-rerun", nfile, fnm), &rerun_fr, TRX_NEED_X);
-        if (rerun_fr.natoms != top_global->natoms)
+        if (rerun_fr.natoms != top_global.natoms)
         {
             gmx_fatal(FARGS,
                       "Number of atoms in trajectory (%d) does not match the "
                       "run input file (%d)\n",
-                      rerun_fr.natoms, top_global->natoms);
+                      rerun_fr.natoms,
+                      top_global.natoms);
         }
 
         if (ir->pbcType != PbcType::No)
@@ -413,7 +476,8 @@ void gmx::LegacySimulator::do_rerun()
                           "Rerun trajectory frame step %" PRId64
                           " time %f "
                           "does not contain a box, while pbc is used",
-                          rerun_fr.step, rerun_fr.time);
+                          rerun_fr.step,
+                          rerun_fr.time);
             }
             if (max_cutoff2(ir->pbcType, rerun_fr.box) < gmx::square(fr->rlist))
             {
@@ -421,7 +485,8 @@ void gmx::LegacySimulator::do_rerun()
                           "Rerun trajectory frame step %" PRId64
                           " time %f "
                           "has too small box dimensions",
-                          rerun_fr.step, rerun_fr.time);
+                          rerun_fr.step,
+                          rerun_fr.time);
             }
         }
     }
@@ -449,9 +514,18 @@ void gmx::LegacySimulator::do_rerun()
     step_rel = 0;
 
     auto stopHandler = stopHandlerBuilder->getStopHandlerMD(
-            compat::not_null<SimulationSignal*>(&signals[eglsSTOPCOND]), false, MASTER(cr),
-            ir->nstlist, mdrunOptions.reproducible, nstglobalcomm, mdrunOptions.maximumHoursToRun,
-            ir->nstlist == 0, fplog, step, bNS, walltime_accounting);
+            compat::not_null<SimulationSignal*>(&signals[eglsSTOPCOND]),
+            false,
+            MASTER(cr),
+            ir->nstlist,
+            mdrunOptions.reproducible,
+            nstglobalcomm,
+            mdrunOptions.maximumHoursToRun,
+            ir->nstlist == 0,
+            fplog,
+            step,
+            bNS,
+            walltime_accounting);
 
     // we don't do counter resetting in rerun - finish will always be valid
     walltime_accounting_set_valid_finish(walltime_accounting);
@@ -462,7 +536,7 @@ void gmx::LegacySimulator::do_rerun()
     isLastStep = (isLastStep || (ir->nsteps >= 0 && step_rel > ir->nsteps));
     while (!isLastStep)
     {
-        wallcycle_start(wcycle, ewcSTEP);
+        wallcycle_start(wcycle, WallCycleCounter::Step);
 
         if (rerun_fr.bStep)
         {
@@ -478,7 +552,7 @@ void gmx::LegacySimulator::do_rerun()
             t = step;
         }
 
-        if (ir->efep != efepNO && MASTER(cr))
+        if (ir->efep != FreeEnergyPerturbationType::No && MASTER(cr))
         {
             if (rerun_fr.bLambda)
             {
@@ -505,7 +579,7 @@ void gmx::LegacySimulator::do_rerun()
                           "decomposition, "
                           "use a single rank");
             }
-            prepareRerunState(rerun_fr, state_global, constructVsites, vsite, ir->delta_t);
+            prepareRerunState(rerun_fr, state_global, constructVsites, vsite);
         }
 
         isLastStep = isLastStep || stopHandler->stoppingAfterCurrentStep(bNS);
@@ -514,10 +588,27 @@ void gmx::LegacySimulator::do_rerun()
         {
             /* Repartition the domain decomposition */
             const bool bMasterState = true;
-            dd_partition_system(fplog, mdlog, step, cr, bMasterState, nstglobalcomm, state_global,
-                                *top_global, ir, imdSession, pull_work, state, &f, mdAtoms, &top,
-                                fr, vsite, constr, nrnb, wcycle, mdrunOptions.verbose);
-            shouldCheckNumberOfBondedInteractions = true;
+            dd_partition_system(fplog,
+                                mdlog,
+                                step,
+                                cr,
+                                bMasterState,
+                                nstglobalcomm,
+                                state_global,
+                                top_global,
+                                *ir,
+                                imdSession,
+                                pull_work,
+                                state,
+                                &f,
+                                mdAtoms,
+                                &top,
+                                fr,
+                                vsite,
+                                constr,
+                                nrnb,
+                                wcycle,
+                                mdrunOptions.verbose);
         }
 
         if (MASTER(cr))
@@ -525,9 +616,9 @@ void gmx::LegacySimulator::do_rerun()
             EnergyOutput::printHeader(fplog, step, t); /* can we improve the information printed here? */
         }
 
-        if (ir->efep != efepNO)
+        if (ir->efep != FreeEnergyPerturbationType::No)
         {
-            update_mdatoms(mdatoms, state->lambda[efptMASS]);
+            update_mdatoms(mdatoms, state->lambda[FreeEnergyPerturbationCouplingType::Mass]);
         }
 
         force_flags = (GMX_FORCE_STATECHANGED | GMX_FORCE_DYNAMICBOX | GMX_FORCE_ALLFORCES
@@ -537,12 +628,38 @@ void gmx::LegacySimulator::do_rerun()
         if (shellfc)
         {
             /* Now is the time to relax the shells */
-            relax_shell_flexcon(fplog, cr, ms, mdrunOptions.verbose, enforcedRotation, step, ir,
-                                imdSession, pull_work, bNS, force_flags, &top, constr, enerd,
-                                state->natoms, state->x.arrayRefWithPadding(),
-                                state->v.arrayRefWithPadding(), state->box, state->lambda,
-                                &state->hist, &f.view(), force_vir, mdatoms, nrnb, wcycle, shellfc,
-                                fr, runScheduleWork, t, mu_tot, vsite, ddBalanceRegionHandler);
+            relax_shell_flexcon(fplog,
+                                cr,
+                                ms,
+                                mdrunOptions.verbose,
+                                enforcedRotation,
+                                step,
+                                ir,
+                                imdSession,
+                                pull_work,
+                                bNS,
+                                force_flags,
+                                &top,
+                                constr,
+                                enerd,
+                                state->natoms,
+                                state->x.arrayRefWithPadding(),
+                                state->v.arrayRefWithPadding(),
+                                state->box,
+                                state->lambda,
+                                &state->hist,
+                                &f.view(),
+                                force_vir,
+                                *mdatoms,
+                                nrnb,
+                                wcycle,
+                                shellfc,
+                                fr,
+                                runScheduleWork,
+                                t,
+                                mu_tot,
+                                vsite,
+                                ddBalanceRegionHandler);
         }
         else
         {
@@ -553,10 +670,34 @@ void gmx::LegacySimulator::do_rerun()
              */
             Awh*       awh = nullptr;
             gmx_edsam* ed  = nullptr;
-            do_force(fplog, cr, ms, ir, awh, enforcedRotation, imdSession, pull_work, step, nrnb,
-                     wcycle, &top, state->box, state->x.arrayRefWithPadding(), &state->hist,
-                     &f.view(), force_vir, mdatoms, enerd, state->lambda, fr, runScheduleWork,
-                     vsite, mu_tot, t, ed, GMX_FORCE_NS | force_flags, ddBalanceRegionHandler);
+            do_force(fplog,
+                     cr,
+                     ms,
+                     *ir,
+                     awh,
+                     enforcedRotation,
+                     imdSession,
+                     pull_work,
+                     step,
+                     nrnb,
+                     wcycle,
+                     &top,
+                     state->box,
+                     state->x.arrayRefWithPadding(),
+                     &state->hist,
+                     &f.view(),
+                     force_vir,
+                     mdatoms,
+                     enerd,
+                     state->lambda,
+                     fr,
+                     runScheduleWork,
+                     vsite,
+                     mu_tot,
+                     t,
+                     ed,
+                     GMX_FORCE_NS | force_flags,
+                     ddBalanceRegionHandler);
         }
 
         /* Now we have the energies and forces corresponding to the
@@ -566,21 +707,32 @@ void gmx::LegacySimulator::do_rerun()
             const bool isCheckpointingStep = false;
             const bool doRerun             = true;
             const bool bSumEkinhOld        = false;
-            do_md_trajectory_writing(fplog, cr, nfile, fnm, step, step_rel, t, ir, state,
-                                     state_global, observablesHistory, top_global, fr, outf,
-                                     energyOutput, ekind, f.view().force(), isCheckpointingStep,
-                                     doRerun, isLastStep, mdrunOptions.writeConfout, bSumEkinhOld);
+            do_md_trajectory_writing(fplog,
+                                     cr,
+                                     nfile,
+                                     fnm,
+                                     step,
+                                     step_rel,
+                                     t,
+                                     ir,
+                                     state,
+                                     state_global,
+                                     observablesHistory,
+                                     top_global,
+                                     fr,
+                                     outf,
+                                     energyOutput,
+                                     ekind,
+                                     f.view().force(),
+                                     isCheckpointingStep,
+                                     doRerun,
+                                     isLastStep,
+                                     mdrunOptions.writeConfout,
+                                     bSumEkinhOld);
         }
 
         stopHandler->setSignal();
 
-        if (vsite != nullptr)
-        {
-            wallcycle_start(wcycle, ewcVSITECONSTR);
-            vsite->construct(state->x, ir->delta_t, state->v, state->box);
-            wallcycle_stop(wcycle, ewcVSITECONSTR);
-        }
-
         {
             const bool          doInterSimSignal = false;
             const bool          doIntraSimSignal = true;
@@ -588,16 +740,38 @@ void gmx::LegacySimulator::do_rerun()
             t_vcm*              vcm              = nullptr;
             SimulationSignaller signaller(&signals, cr, ms, doInterSimSignal, doIntraSimSignal);
 
-            compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
-                            makeConstArrayRef(state->v), state->box, mdatoms, nrnb, vcm, wcycle,
-                            enerd, force_vir, shake_vir, total_vir, pres, constr, &signaller,
-                            state->box, &totalNumberOfBondedInteractions, &bSumEkinhOld,
-                            CGLO_GSTAT | CGLO_ENERGY
-                                    | (shouldCheckNumberOfBondedInteractions ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS
-                                                                             : 0));
-            checkNumberOfBondedInteractions(mdlog, cr, totalNumberOfBondedInteractions, top_global,
-                                            &top, makeConstArrayRef(state->x), state->box,
-                                            &shouldCheckNumberOfBondedInteractions);
+            int cglo_flags = CGLO_GSTAT | CGLO_ENERGY;
+            if (DOMAINDECOMP(cr) && shouldCheckNumberOfBondedInteractions(*cr->dd))
+            {
+                cglo_flags |= CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS;
+            }
+            compute_globals(gstat,
+                            cr,
+                            ir,
+                            fr,
+                            ekind,
+                            makeConstArrayRef(state->x),
+                            makeConstArrayRef(state->v),
+                            state->box,
+                            mdatoms,
+                            nrnb,
+                            vcm,
+                            wcycle,
+                            enerd,
+                            force_vir,
+                            shake_vir,
+                            total_vir,
+                            pres,
+                            constr != nullptr ? constr->rmsdData() : gmx::ArrayRef<real>{},
+                            &signaller,
+                            state->box,
+                            &bSumEkinhOld,
+                            cglo_flags);
+            if (DOMAINDECOMP(cr))
+            {
+                checkNumberOfBondedInteractions(
+                        mdlog, cr, top_global, &top, makeConstArrayRef(state->x), state->box);
+            }
         }
 
         /* Note: this is OK, but there are some numerical precision issues with using the convergence of
@@ -609,12 +783,27 @@ void gmx::LegacySimulator::do_rerun()
         if (MASTER(cr))
         {
             const bool bCalcEnerStep = true;
-            energyOutput.addDataAtEnergyStep(
-                    doFreeEnergyPerturbation, bCalcEnerStep, t, mdatoms->tmass, enerd, ir->fepvals,
-                    ir->expandedvals, state->box,
-                    PTCouplingArrays({ state->boxv, state->nosehoover_xi, state->nosehoover_vxi,
-                                       state->nhpres_xi, state->nhpres_vxi }),
-                    state->fep_state, shake_vir, force_vir, total_vir, pres, ekind, mu_tot, constr);
+            energyOutput.addDataAtEnergyStep(doFreeEnergyPerturbation,
+                                             bCalcEnerStep,
+                                             t,
+                                             mdatoms->tmass,
+                                             enerd,
+                                             ir->fepvals.get(),
+                                             ir->expandedvals.get(),
+                                             state->box,
+                                             PTCouplingArrays({ state->boxv,
+                                                                state->nosehoover_xi,
+                                                                state->nosehoover_vxi,
+                                                                state->nhpres_xi,
+                                                                state->nhpres_vxi }),
+                                             state->fep_state,
+                                             shake_vir,
+                                             force_vir,
+                                             total_vir,
+                                             pres,
+                                             ekind,
+                                             mu_tot,
+                                             constr);
 
             const bool do_ene = true;
             const bool do_log = true;
@@ -623,8 +812,15 @@ void gmx::LegacySimulator::do_rerun()
             const bool do_or  = ir->nstorireout != 0;
 
             EnergyOutput::printAnnealingTemperatures(do_log ? fplog : nullptr, groups, &(ir->opts));
-            energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf), do_ene, do_dr, do_or,
-                                               do_log ? fplog : nullptr, step, t, fr->fcdata.get(), awh);
+            energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf),
+                                               do_ene,
+                                               do_dr,
+                                               do_or,
+                                               do_log ? fplog : nullptr,
+                                               step,
+                                               t,
+                                               fr->fcdata.get(),
+                                               awh);
 
             if (ir->bPull)
             {
@@ -653,11 +849,20 @@ void gmx::LegacySimulator::do_rerun()
         /* Ion/water position swapping.
          * Not done in last step since trajectory writing happens before this call
          * in the MD loop and exchanges would be lost anyway. */
-        if ((ir->eSwapCoords != eswapNO) && (step > 0) && !isLastStep && do_per_step(step, ir->swap->nstswap))
+        if ((ir->eSwapCoords != SwapType::No) && (step > 0) && !isLastStep
+            && do_per_step(step, ir->swap->nstswap))
         {
             const bool doRerun = true;
-            do_swapcoords(cr, step, t, ir, swap, wcycle, rerun_fr.x, rerun_fr.box,
-                          MASTER(cr) && mdrunOptions.verbose, doRerun);
+            do_swapcoords(cr,
+                          step,
+                          t,
+                          ir,
+                          swap,
+                          wcycle,
+                          rerun_fr.x,
+                          rerun_fr.box,
+                          MASTER(cr) && mdrunOptions.verbose,
+                          doRerun);
         }
 
         if (MASTER(cr))
@@ -671,7 +876,7 @@ void gmx::LegacySimulator::do_rerun()
             rerun_parallel_comm(cr, &rerun_fr, &isLastStep);
         }
 
-        cycles = wallcycle_stop(wcycle, ewcSTEP);
+        cycles = wallcycle_stop(wcycle, WallCycleCounter::Step);
         if (DOMAINDECOMP(cr) && wcycle)
         {
             dd_cycles_add(cr->dd, cycles, ddCyclStep);
index 2a5a7c2fe88cb93e61e4f4e8ffeb9233ea92f3c3..f309a376a2c9edeee6a38c3c856f836bc8ba97dd 100644 (file)
@@ -64,6 +64,7 @@
 #include "gromacs/domdec/localatomsetmanager.h"
 #include "gromacs/domdec/partition.h"
 #include "gromacs/ewald/ewald_utils.h"
+#include "gromacs/ewald/pme.h"
 #include "gromacs/ewald/pme_gpu_program.h"
 #include "gromacs/ewald/pme_only.h"
 #include "gromacs/ewald/pme_pp_comm_gpu.h"
 #include "gromacs/utility/keyvaluetree.h"
 #include "gromacs/utility/logger.h"
 #include "gromacs/utility/loggerbuilder.h"
-#include "gromacs/utility/mdmodulenotification.h"
+#include "gromacs/utility/mdmodulesnotifiers.h"
 #include "gromacs/utility/physicalnodecommunicator.h"
 #include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/mpiinfo.h"
 
 #include "isimulator.h"
 #include "membedholder.h"
@@ -205,13 +207,78 @@ static DevelopmentFeatureFlags manageDevelopmentFeatures(const gmx::MDLogger& md
 
     devFlags.enableGpuBufferOps =
             GMX_GPU_CUDA && useGpuForNonbonded && (getenv("GMX_USE_GPU_BUFFER_OPS") != nullptr);
-    devFlags.enableGpuHaloExchange = GMX_GPU_CUDA && GMX_THREAD_MPI && getenv("GMX_GPU_DD_COMMS") != nullptr;
+    devFlags.enableGpuHaloExchange = GMX_GPU_CUDA && getenv("GMX_GPU_DD_COMMS") != nullptr;
     devFlags.forceGpuUpdateDefault = (getenv("GMX_FORCE_UPDATE_DEFAULT_GPU") != nullptr) || GMX_FAHCORE;
-    devFlags.enableGpuPmePPComm =
-            GMX_GPU_CUDA && GMX_THREAD_MPI && getenv("GMX_GPU_PME_PP_COMMS") != nullptr;
+    devFlags.enableGpuPmePPComm = GMX_GPU_CUDA && getenv("GMX_GPU_PME_PP_COMMS") != nullptr;
 
 #pragma GCC diagnostic pop
 
+    // Direct GPU comm path is being used with CUDA_AWARE_MPI
+    // make sure underlying MPI implementation is CUDA-aware
+    if (!GMX_THREAD_MPI && (devFlags.enableGpuPmePPComm || devFlags.enableGpuHaloExchange))
+    {
+        const bool haveDetectedCudaAwareMpi =
+                (checkMpiCudaAwareSupport() == CudaAwareMpiStatus::Supported);
+        const bool forceCudaAwareMpi = (getenv("GMX_FORCE_CUDA_AWARE_MPI") != nullptr);
+
+        if (!haveDetectedCudaAwareMpi && forceCudaAwareMpi)
+        {
+            // CUDA-aware support not detected in MPI library but, user has forced it's use
+            GMX_LOG(mdlog.warning)
+                    .asParagraph()
+                    .appendTextFormatted(
+                            "This run has forced use of 'CUDA-aware MPI'. "
+                            "But, GROMACS cannot determine if underlying MPI "
+                            "is CUDA-aware. GROMACS recommends use of latest openMPI version "
+                            "for CUDA-aware support. "
+                            "If you observe failures at runtime, try unsetting "
+                            "GMX_FORCE_CUDA_AWARE_MPI environment variable.");
+        }
+
+        if (haveDetectedCudaAwareMpi || forceCudaAwareMpi)
+        {
+            devFlags.usingCudaAwareMpi = true;
+            GMX_LOG(mdlog.warning)
+                    .asParagraph()
+                    .appendTextFormatted(
+                            "Using CUDA-aware MPI for 'GPU halo exchange' or 'GPU PME-PP "
+                            "communications' feature.");
+        }
+        else
+        {
+            if (devFlags.enableGpuHaloExchange)
+            {
+                GMX_LOG(mdlog.warning)
+                        .asParagraph()
+                        .appendTextFormatted(
+                                "GMX_GPU_DD_COMMS environment variable detected, but the 'GPU "
+                                "halo exchange' feature will not be enabled as GROMACS couldn't "
+                                "detect CUDA_aware support in underlying MPI implementation.");
+                devFlags.enableGpuHaloExchange = false;
+            }
+            if (devFlags.enableGpuPmePPComm)
+            {
+                GMX_LOG(mdlog.warning)
+                        .asParagraph()
+                        .appendText(
+                                "GMX_GPU_PME_PP_COMMS environment variable detected, but the "
+                                "'GPU PME-PP communications' feature will not be enabled as "
+                                "GROMACS couldn't "
+                                "detect CUDA_aware support in underlying MPI implementation.");
+                devFlags.enableGpuPmePPComm = false;
+            }
+
+            GMX_LOG(mdlog.warning)
+                    .asParagraph()
+                    .appendTextFormatted(
+                            "GROMACS recommends use of latest OpenMPI version for CUDA-aware "
+                            "support. "
+                            "If you are certain about CUDA-aware support in your MPI library, "
+                            "you can force it's use by setting environment variable "
+                            " GMX_FORCE_CUDA_AWARE_MPI.");
+        }
+    }
+
     if (devFlags.enableGpuBufferOps)
     {
         GMX_LOG(mdlog.warning)
@@ -372,7 +439,7 @@ static void mdrunner_start_fn(const void* arg)
 {
     try
     {
-        auto masterMdrunner = reinterpret_cast<const gmx::Mdrunner*>(arg);
+        const auto* masterMdrunner = reinterpret_cast<const gmx::Mdrunner*>(arg);
         /* copy the arg list to make sure that it's thread-local. This
            doesn't copy pointed-to items, of course; fnm, cr and fplog
            are reset in the call below, all others should be const. */
@@ -388,8 +455,7 @@ void Mdrunner::spawnThreads(int numThreadsToLaunch)
 #if GMX_THREAD_MPI
     /* now spawn new threads that start mdrunner_start_fn(), while
        the main thread returns. Thread affinity is handled later. */
-    if (tMPI_Init_fn(TRUE, numThreadsToLaunch, TMPI_AFFINITY_NONE, mdrunner_start_fn,
-                     static_cast<const void*>(this))
+    if (tMPI_Init_fn(TRUE, numThreadsToLaunch, TMPI_AFFINITY_NONE, mdrunner_start_fn, static_cast<const void*>(this))
         != TMPI_SUCCESS)
     {
         GMX_THROW(gmx::InternalError("Failed to spawn thread-MPI threads"));
@@ -413,14 +479,14 @@ static void prepare_verlet_scheme(FILE*               fplog,
                                   t_commrec*          cr,
                                   t_inputrec*         ir,
                                   int                 nstlist_cmdline,
-                                  const gmx_mtop_t*   mtop,
+                                  const gmx_mtop_t&   mtop,
                                   const matrix        box,
                                   bool                makeGpuPairList,
                                   const gmx::CpuInfo& cpuinfo)
 {
     // We checked the cut-offs in grompp, but double-check here.
     // We have PME+LJcutoff kernels for rcoulomb>rvdw.
-    if (EEL_PME_EWALD(ir->coulombtype) && ir->vdwtype == eelCUT)
+    if (EEL_PME_EWALD(ir->coulombtype) && ir->vdwtype == VanDerWaalsType::Cut)
     {
         GMX_RELEASE_ASSERT(ir->rcoulomb >= ir->rvdw,
                            "With Verlet lists and PME we should have rcoulomb>=rvdw");
@@ -431,7 +497,8 @@ static void prepare_verlet_scheme(FILE*               fplog,
                            "With Verlet lists and no PME rcoulomb and rvdw should be identical");
     }
     /* For NVE simulations, we will retain the initial list buffer */
-    if (EI_DYNAMICS(ir->eI) && ir->verletbuf_tol > 0 && !(EI_MD(ir->eI) && ir->etc == etcNO))
+    if (EI_DYNAMICS(ir->eI) && ir->verletbuf_tol > 0
+        && !(EI_MD(ir->eI) && ir->etc == TemperatureCoupling::No))
     {
         /* Update the Verlet buffer size for the current run setup */
 
@@ -444,7 +511,7 @@ static void prepare_verlet_scheme(FILE*               fplog,
         VerletbufListSetup listSetup = verletbufGetSafeListSetup(listType);
 
         const real rlist_new =
-                calcVerletBufferSize(*mtop, det(box), *ir, ir->nstlist, ir->nstlist - 1, -1, listSetup);
+                calcVerletBufferSize(mtop, det(box), *ir, ir->nstlist, ir->nstlist - 1, -1, listSetup);
 
         if (rlist_new != ir->rlist)
         {
@@ -452,7 +519,10 @@ static void prepare_verlet_scheme(FILE*               fplog,
             {
                 fprintf(fplog,
                         "\nChanging rlist from %g to %g for non-bonded %dx%d atom kernels\n\n",
-                        ir->rlist, rlist_new, listSetup.cluster_size_i, listSetup.cluster_size_j);
+                        ir->rlist,
+                        rlist_new,
+                        listSetup.cluster_size_i,
+                        listSetup.cluster_size_j);
             }
             ir->rlist = rlist_new;
         }
@@ -460,14 +530,15 @@ static void prepare_verlet_scheme(FILE*               fplog,
 
     if (nstlist_cmdline > 0 && (!EI_DYNAMICS(ir->eI) || ir->verletbuf_tol <= 0))
     {
-        gmx_fatal(FARGS, "Can not set nstlist without %s",
+        gmx_fatal(FARGS,
+                  "Can not set nstlist without %s",
                   !EI_DYNAMICS(ir->eI) ? "dynamics" : "verlet-buffer-tolerance");
     }
 
     if (EI_DYNAMICS(ir->eI))
     {
         /* Set or try nstlist values */
-        increaseNstlist(fplog, cr, ir, nstlist_cmdline, mtop, box, makeGpuPairList, cpuinfo);
+        increaseNstlist(fplog, cr, ir, nstlist_cmdline, &mtop, box, makeGpuPairList, cpuinfo);
     }
 }
 
@@ -490,11 +561,13 @@ static void override_nsteps_cmdline(const gmx::MDLogger& mdlog, int64_t nsteps_c
         {
             sprintf(sbuf_msg,
                     "Overriding nsteps with value passed on the command line: %s steps, %.3g ps",
-                    gmx_step_str(nsteps_cmdline, sbuf_steps), fabs(nsteps_cmdline * ir->delta_t));
+                    gmx_step_str(nsteps_cmdline, sbuf_steps),
+                    fabs(nsteps_cmdline * ir->delta_t));
         }
         else
         {
-            sprintf(sbuf_msg, "Overriding nsteps with value passed on the command line: %s steps",
+            sprintf(sbuf_msg,
+                    "Overriding nsteps with value passed on the command line: %s steps",
                     gmx_step_str(nsteps_cmdline, sbuf_steps));
         }
 
@@ -590,9 +663,9 @@ static TaskTarget findTaskTarget(const char* optionString)
 static void finish_run(FILE*                     fplog,
                        const gmx::MDLogger&      mdlog,
                        const t_commrec*          cr,
-                       const t_inputrec*         inputrec,
+                       const t_inputrec&         inputrec,
                        t_nrnb                    nrnb[],
-                       gmx_wallcycle_t           wcycle,
+                       gmx_wallcycle           wcycle,
                        gmx_walltime_accounting_t walltime_accounting,
                        nonbonded_verlet_t*       nbv,
                        const gmx_pme_t*          pme,
@@ -615,7 +688,7 @@ static void finish_run(FILE*                     fplog,
        Further, we only report performance for dynamical integrators,
        because those are the only ones for which we plan to
        consider doing any optimizations. */
-    bool printReport = EI_DYNAMICS(inputrec->eI) && SIMMASTER(cr);
+    bool printReport = EI_DYNAMICS(inputrec.eI) && SIMMASTER(cr);
 
     if (printReport && !walltime_accounting_get_valid_finish(walltime_accounting))
     {
@@ -632,7 +705,7 @@ static void finish_run(FILE*                     fplog,
         nrnbTotalStorage = std::make_unique<t_nrnb>();
         nrnb_tot         = nrnbTotalStorage.get();
 #if GMX_MPI
-        MPI_Allreduce(nrnb->n, nrnb_tot->n, eNRNB, MPI_DOUBLE, MPI_SUM, cr->mpi_comm_mysim);
+        MPI_Allreduce(nrnb->n.data(), nrnb_tot->n.data(), eNRNB, MPI_DOUBLE, MPI_SUM, cr->mpi_comm_mysim);
 #endif
     }
     else
@@ -647,13 +720,16 @@ static void finish_run(FILE*                     fplog,
     {
 #if GMX_MPI
         /* reduce elapsed_time over all MPI ranks in the current simulation */
-        MPI_Allreduce(&elapsed_time, &elapsed_time_over_all_ranks, 1, MPI_DOUBLE, MPI_SUM,
-                      cr->mpi_comm_mysim);
+        MPI_Allreduce(&elapsed_time, &elapsed_time_over_all_ranks, 1, MPI_DOUBLE, MPI_SUM, cr->mpi_comm_mysim);
         elapsed_time_over_all_ranks /= cr->nnodes;
         /* Reduce elapsed_time_over_all_threads over all MPI ranks in the
          * current simulation. */
-        MPI_Allreduce(&elapsed_time_over_all_threads, &elapsed_time_over_all_threads_over_all_ranks,
-                      1, MPI_DOUBLE, MPI_SUM, cr->mpi_comm_mysim);
+        MPI_Allreduce(&elapsed_time_over_all_threads,
+                      &elapsed_time_over_all_threads_over_all_ranks,
+                      1,
+                      MPI_DOUBLE,
+                      MPI_SUM,
+                      cr->mpi_comm_mysim);
 #endif
     }
     else
@@ -676,15 +752,15 @@ static void finish_run(FILE*                     fplog,
      * to the code that handled the thread region, so that there's a
      * mechanism to keep cycle counting working during the transition
      * to task parallelism. */
-    int nthreads_pp  = gmx_omp_nthreads_get(emntNonbonded);
-    int nthreads_pme = gmx_omp_nthreads_get(emntPME);
-    wallcycle_scale_by_num_threads(wcycle, thisRankHasDuty(cr, DUTY_PME) && !thisRankHasDuty(cr, DUTY_PP),
-                                   nthreads_pp, nthreads_pme);
+    int nthreads_pp  = gmx_omp_nthreads_get(ModuleMultiThread::Nonbonded);
+    int nthreads_pme = gmx_omp_nthreads_get(ModuleMultiThread::Pme);
+    wallcycle_scale_by_num_threads(
+            wcycle, thisRankHasDuty(cr, DUTY_PME) && !thisRankHasDuty(cr, DUTY_PP), nthreads_pp, nthreads_pme);
     auto cycle_sum(wallcycle_sum(cr, wcycle));
 
     if (printReport)
     {
-        auto nbnxn_gpu_timings =
+        auto* nbnxn_gpu_timings =
                 (nbv != nullptr && nbv->useGpu()) ? Nbnxm::gpu_get_timings(nbv->gpu_nbv) : nullptr;
         gmx_wallclock_gpu_pme_t pme_gpu_timings = {};
 
@@ -692,40 +768,55 @@ static void finish_run(FILE*                     fplog,
         {
             pme_gpu_get_timings(pme, &pme_gpu_timings);
         }
-        wallcycle_print(fplog, mdlog, cr->nnodes, cr->npmenodes, nthreads_pp, nthreads_pme,
-                        elapsed_time_over_all_ranks, wcycle, cycle_sum, nbnxn_gpu_timings,
+        wallcycle_print(fplog,
+                        mdlog,
+                        cr->nnodes,
+                        cr->npmenodes,
+                        nthreads_pp,
+                        nthreads_pme,
+                        elapsed_time_over_all_ranks,
+                        wcycle,
+                        cycle_sum,
+                        nbnxn_gpu_timings,
                         &pme_gpu_timings);
 
-        if (EI_DYNAMICS(inputrec->eI))
+        if (EI_DYNAMICS(inputrec.eI))
         {
-            delta_t = inputrec->delta_t;
+            delta_t = inputrec.delta_t;
         }
 
         if (fplog)
         {
-            print_perf(fplog, elapsed_time_over_all_threads_over_all_ranks, elapsed_time_over_all_ranks,
+            print_perf(fplog,
+                       elapsed_time_over_all_threads_over_all_ranks,
+                       elapsed_time_over_all_ranks,
                        walltime_accounting_get_nsteps_done_since_reset(walltime_accounting),
-                       delta_t, nbfs, mflop);
+                       delta_t,
+                       nbfs,
+                       mflop);
         }
         if (bWriteStat)
         {
-            print_perf(stderr, elapsed_time_over_all_threads_over_all_ranks, elapsed_time_over_all_ranks,
+            print_perf(stderr,
+                       elapsed_time_over_all_threads_over_all_ranks,
+                       elapsed_time_over_all_ranks,
                        walltime_accounting_get_nsteps_done_since_reset(walltime_accounting),
-                       delta_t, nbfs, mflop);
+                       delta_t,
+                       nbfs,
+                       mflop);
         }
     }
 }
 
 int Mdrunner::mdrunner()
 {
-    matrix                    box;
-    t_forcerec*               fr               = nullptr;
-    real                      ewaldcoeff_q     = 0;
-    real                      ewaldcoeff_lj    = 0;
-    int                       nChargePerturbed = -1, nTypePerturbed = 0;
-    gmx_wallcycle_t           wcycle;
-    gmx_walltime_accounting_t walltime_accounting = nullptr;
-    MembedHolder              membedHolder(filenames.size(), filenames.data());
+    matrix                      box;
+    std::unique_ptr<t_forcerec> fr;
+    real                        ewaldcoeff_q     = 0;
+    real                        ewaldcoeff_lj    = 0;
+    int                         nChargePerturbed = -1, nTypePerturbed = 0;
+    gmx_walltime_accounting_t   walltime_accounting = nullptr;
+    MembedHolder                membedHolder(filenames.size(), filenames.data());
 
     /* CAUTION: threads may be started later on in this function, so
        cr doesn't reflect the final parallel state right now */
@@ -766,8 +857,9 @@ int Mdrunner::mdrunner()
 
     gmx_print_detected_hardware(fplog, isSimulationMasterRank && isMasterSim(ms), mdlog, hwinfo_);
 
-    std::vector<int> gpuIdsToUse = makeGpuIdsToUse(hwinfo_->deviceInfoList, hw_opt.gpuIdsAvailable);
-    const int        numDevicesToUse = gmx::ssize(gpuIdsToUse);
+    std::vector<int> availableDevices =
+            makeListOfAvailableDevices(hwinfo_->deviceInfoList, hw_opt.devicesSelectedByUser);
+    const int numAvailableDevices = gmx::ssize(availableDevices);
 
     // Print citation requests after all software/hardware printing
     pleaseCiteGromacs(fplog);
@@ -789,13 +881,13 @@ int Mdrunner::mdrunner()
         /* Read (nearly) all data required for the simulation
          * and keep the partly serialized tpr contents to send to other ranks later
          */
-        applyGlobalSimulationState(*inputHolder_.get(), partialDeserializedTpr.get(),
-                                   globalState.get(), inputrec.get(), &mtop);
+        applyGlobalSimulationState(
+                *inputHolder_.get(), partialDeserializedTpr.get(), globalState.get(), inputrec.get(), &mtop);
     }
 
     /* Check and update the hardware options for internal consistency */
-    checkAndUpdateHardwareOptions(mdlog, &hw_opt, isSimulationMasterRank, domdecOptions.numPmeRanks,
-                                  inputrec.get());
+    checkAndUpdateHardwareOptions(
+            mdlog, &hw_opt, isSimulationMasterRank, domdecOptions.numPmeRanks, inputrec.get());
 
     if (GMX_THREAD_MPI && isSimulationMasterRank)
     {
@@ -810,13 +902,21 @@ int Mdrunner::mdrunner()
             // the number of GPUs to choose the number of ranks.
             auto canUseGpuForNonbonded = buildSupportsNonbondedOnGpu(nullptr);
             useGpuForNonbonded         = decideWhetherToUseGpusForNonbondedWithThreadMpi(
-                    nonbondedTarget, numDevicesToUse, userGpuTaskAssignment, emulateGpuNonbonded,
+                    nonbondedTarget,
+                    numAvailableDevices > 0,
+                    userGpuTaskAssignment,
+                    emulateGpuNonbonded,
                     canUseGpuForNonbonded,
                     gpuAccelerationOfNonbondedIsUseful(mdlog, *inputrec, GMX_THREAD_MPI),
                     hw_opt.nthreads_tmpi);
-            useGpuForPme = decideWhetherToUseGpusForPmeWithThreadMpi(
-                    useGpuForNonbonded, pmeTarget, numDevicesToUse, userGpuTaskAssignment, *hwinfo_,
-                    *inputrec, hw_opt.nthreads_tmpi, domdecOptions.numPmeRanks);
+            useGpuForPme = decideWhetherToUseGpusForPmeWithThreadMpi(useGpuForNonbonded,
+                                                                     pmeTarget,
+                                                                     numAvailableDevices,
+                                                                     userGpuTaskAssignment,
+                                                                     *hwinfo_,
+                                                                     *inputrec,
+                                                                     hw_opt.nthreads_tmpi,
+                                                                     domdecOptions.numPmeRanks);
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
 
@@ -825,9 +925,15 @@ int Mdrunner::mdrunner()
          * TODO Over-writing the user-supplied value here does
          * prevent any possible subsequent checks from working
          * correctly. */
-        hw_opt.nthreads_tmpi =
-                get_nthreads_mpi(hwinfo_, &hw_opt, numDevicesToUse, useGpuForNonbonded, useGpuForPme,
-                                 inputrec.get(), &mtop, mdlog, membedHolder.doMembed());
+        hw_opt.nthreads_tmpi = get_nthreads_mpi(hwinfo_,
+                                                &hw_opt,
+                                                numAvailableDevices,
+                                                useGpuForNonbonded,
+                                                useGpuForPme,
+                                                inputrec.get(),
+                                                mtop,
+                                                mdlog,
+                                                membedHolder.doMembed());
 
         // Now start the threads for thread MPI.
         spawnThreads(hw_opt.nthreads_tmpi);
@@ -858,17 +964,26 @@ int Mdrunner::mdrunner()
             // On non-master ranks, allocate the object that will receive data in the following call.
             inputrec = std::make_unique<t_inputrec>();
         }
-        init_parallel(cr->mpiDefaultCommunicator, MASTER(cr), inputrec.get(), &mtop,
+        init_parallel(cr->mpiDefaultCommunicator,
+                      MASTER(cr),
+                      inputrec.get(),
+                      &mtop,
                       partialDeserializedTpr.get());
     }
     GMX_RELEASE_ASSERT(inputrec != nullptr, "All ranks should have a valid inputrec now");
     partialDeserializedTpr.reset(nullptr);
 
+    GMX_RELEASE_ASSERT(
+            !inputrec->useConstantAcceleration,
+            "Linear acceleration has been removed in GROMACS 2022, and was broken for many years "
+            "before that. Use GROMACS 4.5 or earlier if you need this feature.");
+
     // Now the number of ranks is known to all ranks, and each knows
     // the inputrec read by the master rank. The ranks can now all run
     // the task-deciding functions and will agree on the result
     // without needing to communicate.
-    const bool useDomainDecomposition = (PAR(cr) && !(EI_TPI(inputrec->eI) || inputrec->eI == eiNM));
+    const bool useDomainDecomposition =
+            (PAR(cr) && !(EI_TPI(inputrec->eI) || inputrec->eI == IntegrationAlgorithm::NM));
 
     // Note that these variables describe only their own node.
     //
@@ -888,14 +1003,22 @@ int Mdrunner::mdrunner()
         // assignment.
         auto canUseGpuForNonbonded = buildSupportsNonbondedOnGpu(nullptr);
         useGpuForNonbonded         = decideWhetherToUseGpusForNonbonded(
-                nonbondedTarget, userGpuTaskAssignment, emulateGpuNonbonded, canUseGpuForNonbonded,
-                gpuAccelerationOfNonbondedIsUseful(mdlog, *inputrec, !GMX_THREAD_MPI), gpusWereDetected);
-        useGpuForPme = decideWhetherToUseGpusForPme(
-                useGpuForNonbonded, pmeTarget, userGpuTaskAssignment, *hwinfo_, *inputrec,
-                cr->sizeOfDefaultCommunicator, domdecOptions.numPmeRanks, gpusWereDetected);
-        useGpuForBonded = decideWhetherToUseGpusForBonded(useGpuForNonbonded, useGpuForPme,
-                                                          bondedTarget, *inputrec, mtop,
-                                                          domdecOptions.numPmeRanks, gpusWereDetected);
+                nonbondedTarget,
+                userGpuTaskAssignment,
+                emulateGpuNonbonded,
+                canUseGpuForNonbonded,
+                gpuAccelerationOfNonbondedIsUseful(mdlog, *inputrec, !GMX_THREAD_MPI),
+                gpusWereDetected);
+        useGpuForPme    = decideWhetherToUseGpusForPme(useGpuForNonbonded,
+                                                    pmeTarget,
+                                                    userGpuTaskAssignment,
+                                                    *hwinfo_,
+                                                    *inputrec,
+                                                    cr->sizeOfDefaultCommunicator,
+                                                    domdecOptions.numPmeRanks,
+                                                    gpusWereDetected);
+        useGpuForBonded = decideWhetherToUseGpusForBonded(
+                useGpuForNonbonded, useGpuForPme, bondedTarget, *inputrec, mtop, domdecOptions.numPmeRanks, gpusWereDetected);
     }
     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
 
@@ -906,9 +1029,15 @@ int Mdrunner::mdrunner()
     const DevelopmentFeatureFlags devFlags =
             manageDevelopmentFeatures(mdlog, useGpuForNonbonded, pmeRunMode);
 
-    const bool useModularSimulator =
-            checkUseModularSimulator(false, inputrec.get(), doRerun, mtop, ms, replExParams,
-                                     nullptr, doEssentialDynamics, membedHolder.doMembed());
+    const bool useModularSimulator = checkUseModularSimulator(false,
+                                                              inputrec.get(),
+                                                              doRerun,
+                                                              mtop,
+                                                              ms,
+                                                              replExParams,
+                                                              nullptr,
+                                                              doEssentialDynamics,
+                                                              membedHolder.doMembed());
 
     // Build restraints.
     // TODO: hide restraint implementation details from Mdrunner.
@@ -924,13 +1053,13 @@ int Mdrunner::mdrunner()
 
     // TODO: Error handling
     mdModules_->assignOptionsToModules(*inputrec->params, nullptr);
-    // now that the MdModules know their options, they know which callbacks to sign up to
+    // now that the MDModules know their options, they know which callbacks to sign up to
     mdModules_->subscribeToSimulationSetupNotifications();
-    const auto& mdModulesNotifier = mdModules_->notifier().simulationSetupNotifications_;
+    const auto& setupNotifier = mdModules_->notifiers().simulationSetupNotifier_;
 
     if (inputrec->internalParameters != nullptr)
     {
-        mdModulesNotifier.notify(*inputrec->internalParameters);
+        setupNotifier.notify(*inputrec->internalParameters);
     }
 
     if (fplog != nullptr)
@@ -942,7 +1071,7 @@ int Mdrunner::mdrunner()
     if (SIMMASTER(cr))
     {
         /* In rerun, set velocities to zero if present */
-        if (doRerun && ((globalState->flags & (1 << estV)) != 0))
+        if (doRerun && ((globalState->flags & enumValueToBitMask(StateEntry::V)) != 0))
         {
             // rerun does not use velocities
             GMX_LOG(mdlog.info)
@@ -954,7 +1083,7 @@ int Mdrunner::mdrunner()
             {
                 clear_rvec(globalState->v[i]);
             }
-            globalState->flags &= ~(1 << estV);
+            globalState->flags &= ~enumValueToBitMask(StateEntry::V);
         }
 
         /* now make sure the state is initialized and propagated */
@@ -964,14 +1093,14 @@ int Mdrunner::mdrunner()
     /* NM and TPI parallelize over force/energy calculations, not atoms,
      * so we need to initialize and broadcast the global state.
      */
-    if (inputrec->eI == eiNM || inputrec->eI == eiTPI)
+    if (inputrec->eI == IntegrationAlgorithm::NM || inputrec->eI == IntegrationAlgorithm::TPI)
     {
         if (!MASTER(cr))
         {
             globalState = std::make_unique<t_state>();
         }
-        broadcastStateWithoutDynamics(cr->mpiDefaultCommunicator, DOMAINDECOMP(cr), PAR(cr),
-                                      globalState.get());
+        broadcastStateWithoutDynamics(
+                cr->mpiDefaultCommunicator, DOMAINDECOMP(cr), PAR(cr), globalState.get());
     }
 
     /* A parallel command line option consistency check that we can
@@ -994,45 +1123,66 @@ int Mdrunner::mdrunner()
 #endif
     }
 
-    if (doRerun && (EI_ENERGY_MINIMIZATION(inputrec->eI) || eiNM == inputrec->eI))
+    if (doRerun && (EI_ENERGY_MINIMIZATION(inputrec->eI) || IntegrationAlgorithm::NM == inputrec->eI))
     {
         gmx_fatal(FARGS,
                   "The .mdp file specified an energy mininization or normal mode algorithm, and "
                   "these are not compatible with mdrun -rerun");
     }
 
+    /* Object for collecting reasons for not using PME-only ranks */
+    SeparatePmeRanksPermitted separatePmeRanksPermitted;
+
+    /* Permit MDModules to notify whether they want to use PME-only ranks */
+    setupNotifier.notify(&separatePmeRanksPermitted);
+
+    /* If simulation is not using PME then disable PME-only ranks */
     if (!(EEL_PME(inputrec->coulombtype) || EVDW_PME(inputrec->vdwtype)))
     {
-        if (domdecOptions.numPmeRanks > 0)
-        {
-            gmx_fatal_collective(FARGS, cr->mpiDefaultCommunicator, MASTER(cr),
-                                 "PME-only ranks are requested, but the system does not use PME "
-                                 "for electrostatics or LJ");
-        }
-
-        domdecOptions.numPmeRanks = 0;
+        separatePmeRanksPermitted.disablePmeRanks(
+                "PME-only ranks are requested, but the system does not use PME "
+                "for electrostatics or LJ");
     }
 
+    /* With NB GPUs we don't automatically use PME-only CPU ranks. PME ranks can
+     * improve performance with many threads per GPU, since our OpenMP
+     * scaling is bad, but it's difficult to automate the setup.
+     */
     if (useGpuForNonbonded && domdecOptions.numPmeRanks < 0)
     {
-        /* With NB GPUs we don't automatically use PME-only CPU ranks. PME ranks can
-         * improve performance with many threads per GPU, since our OpenMP
-         * scaling is bad, but it's difficult to automate the setup.
-         */
+        separatePmeRanksPermitted.disablePmeRanks(
+                "PME-only CPU ranks are not automatically used when "
+                "non-bonded interactions are computed on GPUs");
+    }
+
+    /* If GPU is used for PME then only 1 PME rank is permitted */
+    if (useGpuForPme && (domdecOptions.numPmeRanks < 0 || domdecOptions.numPmeRanks > 1))
+    {
+        separatePmeRanksPermitted.disablePmeRanks(
+                "PME GPU decomposition is not supported. Only one separate PME-only GPU rank "
+                "can be used.");
+    }
+
+    /* Disable PME-only ranks if some parts of the code requested so and it's up to GROMACS to decide */
+    if (!separatePmeRanksPermitted.permitSeparatePmeRanks() && domdecOptions.numPmeRanks < 0)
+    {
         domdecOptions.numPmeRanks = 0;
+        GMX_LOG(mdlog.info)
+                .asParagraph()
+                .appendText("Simulation will not use PME-only ranks because: "
+                            + separatePmeRanksPermitted.reasonsWhyDisabled());
     }
-    if (useGpuForPme)
+
+    /* If some parts of the code could not use PME-only ranks and
+     * user explicitly used mdrun -npme option then throw an error */
+    if (!separatePmeRanksPermitted.permitSeparatePmeRanks() && domdecOptions.numPmeRanks > 0)
     {
-        if (domdecOptions.numPmeRanks < 0)
-        {
-            domdecOptions.numPmeRanks = 0;
-            // TODO possibly print a note that one can opt-in for a separate PME GPU rank?
-        }
-        else
-        {
-            GMX_RELEASE_ASSERT(domdecOptions.numPmeRanks <= 1,
-                               "PME GPU decomposition is not supported");
-        }
+        gmx_fatal_collective(FARGS,
+                             cr->mpiDefaultCommunicator,
+                             MASTER(cr),
+                             "Requested -npme %d option is not viable because: %s",
+                             domdecOptions.numPmeRanks,
+                             separatePmeRanksPermitted.reasonsWhyDisabled().c_str());
     }
 
     /* NMR restraints must be initialized before load_checkpoint,
@@ -1046,18 +1196,29 @@ int Mdrunner::mdrunner()
     /* This needs to be called before read_checkpoint to extend the state */
     t_disresdata* disresdata;
     snew(disresdata, 1);
-    init_disres(fplog, &mtop, inputrec.get(), DisResRunMode::MDRun,
+    init_disres(fplog,
+                mtop,
+                inputrec.get(),
+                DisResRunMode::MDRun,
                 MASTER(cr) ? DDRole::Master : DDRole::Agent,
-                PAR(cr) ? NumRanks::Multiple : NumRanks::Single, cr->mpi_comm_mysim, ms, disresdata,
-                globalState.get(), replExParams.exchangeInterval > 0);
+                PAR(cr) ? NumRanks::Multiple : NumRanks::Single,
+                cr->mpi_comm_mysim,
+                ms,
+                disresdata,
+                globalState.get(),
+                replExParams.exchangeInterval > 0);
 
-    t_oriresdata* oriresdata;
-    snew(oriresdata, 1);
-    init_orires(fplog, &mtop, inputrec.get(), cr, ms, globalState.get(), oriresdata);
+    std::unique_ptr<t_oriresdata> oriresData;
+    if (gmx_mtop_ftype_count(mtop, F_ORIRES) > 0)
+    {
+        oriresData = std::make_unique<t_oriresdata>(fplog, mtop, *inputrec, cr, ms, globalState.get());
+    }
 
-    auto deform = prepareBoxDeformation(
-            globalState != nullptr ? globalState->box : box, MASTER(cr) ? DDRole::Master : DDRole::Agent,
-            PAR(cr) ? NumRanks::Multiple : NumRanks::Single, cr->mpi_comm_mygroup, *inputrec);
+    auto deform = prepareBoxDeformation(globalState != nullptr ? globalState->box : box,
+                                        MASTER(cr) ? DDRole::Master : DDRole::Agent,
+                                        PAR(cr) ? NumRanks::Multiple : NumRanks::Single,
+                                        cr->mpi_comm_mygroup,
+                                        *inputrec);
 
 #if GMX_FAHCORE
     /* We have to remember the generation's first step before reading checkpoint.
@@ -1093,10 +1254,17 @@ int Mdrunner::mdrunner()
 
         // Finish applying initial simulation state information from external sources on all ranks.
         // Reconcile checkpoint file data with Mdrunner state established up to this point.
-        applyLocalState(*inputHolder_.get(), logFileHandle, cr, domdecOptions.numCells,
-                        inputrec.get(), globalState.get(), &observablesHistory,
-                        mdrunOptions.reproducible, mdModules_->notifier(),
-                        modularSimulatorCheckpointData.get(), useModularSimulator);
+        applyLocalState(*inputHolder_.get(),
+                        logFileHandle,
+                        cr,
+                        domdecOptions.numCells,
+                        inputrec.get(),
+                        globalState.get(),
+                        &observablesHistory,
+                        mdrunOptions.reproducible,
+                        mdModules_->notifiers(),
+                        modularSimulatorCheckpointData.get(),
+                        useModularSimulator);
         // TODO: (#3652) Synchronize filesystem state, SimulationInput contents, and program
         //  invariants
         //  on all code paths.
@@ -1147,7 +1315,7 @@ int Mdrunner::mdrunner()
         gmx_bcast(sizeof(box), box, cr->mpiDefaultCommunicator);
     }
 
-    if (inputrec->cutoff_scheme != ecutsVERLET)
+    if (inputrec->cutoff_scheme != CutoffScheme::Verlet)
     {
         gmx_fatal(FARGS,
                   "This group-scheme .tpr file can no longer be run by mdrun. Please update to the "
@@ -1158,7 +1326,12 @@ int Mdrunner::mdrunner()
      * increase rlist) tries to check if the newly chosen value fits with the DD scheme. As this is
      * run before any DD scheme is set up, this check is never executed. See #3334 for more details.
      */
-    prepare_verlet_scheme(fplog, cr, inputrec.get(), nstlist_cmdline, &mtop, box,
+    prepare_verlet_scheme(fplog,
+                          cr,
+                          inputrec.get(),
+                          nstlist_cmdline,
+                          mtop,
+                          box,
                           useGpuForNonbonded || (emulateGpuNonbonded == EmulateGpuNonbonded::Yes),
                           *hwinfo_->cpuInfo);
 
@@ -1170,7 +1343,13 @@ int Mdrunner::mdrunner()
     if (useDomainDecomposition)
     {
         ddBuilder = std::make_unique<DomainDecompositionBuilder>(
-                mdlog, cr, domdecOptions, mdrunOptions, mtop, *inputrec, box,
+                mdlog,
+                cr,
+                domdecOptions,
+                mdrunOptions,
+                mtop,
+                *inputrec,
+                box,
                 positionsFromStatePointer(globalState.get()));
     }
     else
@@ -1190,9 +1369,18 @@ int Mdrunner::mdrunner()
 
     // Produce the task assignment for this rank - done after DD is constructed
     GpuTaskAssignments gpuTaskAssignments = GpuTaskAssignmentsBuilder::build(
-            gpuIdsToUse, userGpuTaskAssignment, *hwinfo_, simulationCommunicator, physicalNodeComm,
-            nonbondedTarget, pmeTarget, bondedTarget, updateTarget, useGpuForNonbonded,
-            useGpuForPme, thisRankHasDuty(cr, DUTY_PP),
+            availableDevices,
+            userGpuTaskAssignment,
+            *hwinfo_,
+            simulationCommunicator,
+            physicalNodeComm,
+            nonbondedTarget,
+            pmeTarget,
+            bondedTarget,
+            updateTarget,
+            useGpuForNonbonded,
+            useGpuForPme,
+            thisRankHasDuty(cr, DUTY_PP),
             // TODO cr->duty & DUTY_PME should imply that a PME
             // algorithm is active, but currently does not.
             EEL_PME(inputrec->coulombtype) && thisRankHasDuty(cr, DUTY_PME));
@@ -1242,11 +1430,22 @@ int Mdrunner::mdrunner()
         const bool useUpdateGroups = cr->dd ? ddUsesUpdateGroups(*cr->dd) : false;
         const bool haveFrozenAtoms = inputrecFrozenAtoms(inputrec.get());
 
-        useGpuForUpdate = decideWhetherToUseGpuForUpdate(
-                useDomainDecomposition, useUpdateGroups, pmeRunMode, domdecOptions.numPmeRanks > 0,
-                useGpuForNonbonded, updateTarget, gpusWereDetected, *inputrec, mtop,
-                doEssentialDynamics, gmx_mtop_ftype_count(mtop, F_ORIRES) > 0,
-                replExParams.exchangeInterval > 0, haveFrozenAtoms, doRerun, devFlags, mdlog);
+        useGpuForUpdate = decideWhetherToUseGpuForUpdate(useDomainDecomposition,
+                                                         useUpdateGroups,
+                                                         pmeRunMode,
+                                                         domdecOptions.numPmeRanks > 0,
+                                                         useGpuForNonbonded,
+                                                         updateTarget,
+                                                         gpusWereDetected,
+                                                         *inputrec,
+                                                         mtop,
+                                                         doEssentialDynamics,
+                                                         gmx_mtop_ftype_count(mtop, F_ORIRES) > 0,
+                                                         replExParams.exchangeInterval > 0,
+                                                         haveFrozenAtoms,
+                                                         doRerun,
+                                                         devFlags,
+                                                         mdlog);
     }
     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
 
@@ -1266,14 +1465,22 @@ int Mdrunner::mdrunner()
 
     MdrunScheduleWorkload runScheduleWork;
 
-    bool useGpuDirectHalo = decideWhetherToUseGpuForHalo(
-            devFlags, havePPDomainDecomposition(cr), useGpuForNonbonded, useModularSimulator,
-            doRerun, EI_ENERGY_MINIMIZATION(inputrec->eI));
+    bool useGpuDirectHalo = decideWhetherToUseGpuForHalo(devFlags,
+                                                         havePPDomainDecomposition(cr),
+                                                         useGpuForNonbonded,
+                                                         useModularSimulator,
+                                                         doRerun,
+                                                         EI_ENERGY_MINIMIZATION(inputrec->eI));
 
     // Also populates the simulation constant workload description.
-    runScheduleWork.simulationWork = createSimulationWorkload(
-            *inputrec, disableNonbondedCalculation, devFlags, useGpuForNonbonded, pmeRunMode,
-            useGpuForBonded, useGpuForUpdate, useGpuDirectHalo);
+    runScheduleWork.simulationWork = createSimulationWorkload(*inputrec,
+                                                              disableNonbondedCalculation,
+                                                              devFlags,
+                                                              useGpuForNonbonded,
+                                                              pmeRunMode,
+                                                              useGpuForBonded,
+                                                              useGpuForUpdate,
+                                                              useGpuDirectHalo);
 
     std::unique_ptr<DeviceStreamManager> deviceStreamManager = nullptr;
 
@@ -1291,7 +1498,7 @@ int Mdrunner::mdrunner()
     // where appropriate.
     if (!userGpuTaskAssignment.empty())
     {
-        gpuTaskAssignments.logPerformanceHints(mdlog, numDevicesToUse);
+        gpuTaskAssignments.logPerformanceHints(mdlog, numAvailableDevices);
     }
 
     if (PAR(cr))
@@ -1310,10 +1517,12 @@ int Mdrunner::mdrunner()
                 .appendTextFormatted(
                         "This is simulation %d out of %d running as a composite GROMACS\n"
                         "multi-simulation job. Setup for this simulation:\n",
-                        ms->simulationIndex_, ms->numSimulations_);
+                        ms->simulationIndex_,
+                        ms->numSimulations_);
     }
     GMX_LOG(mdlog.warning)
-            .appendTextFormatted("Using %d MPI %s\n", cr->nnodes,
+            .appendTextFormatted("Using %d MPI %s\n",
+                                 cr->nnodes,
 #    if GMX_THREAD_MPI
                                  cr->nnodes == 1 ? "thread" : "threads"
 #    else
@@ -1330,23 +1539,18 @@ int Mdrunner::mdrunner()
     // the OpenMP support.
     gmx_check_thread_affinity_set(mdlog, &hw_opt, hwinfo_->nthreads_hw_avail, FALSE);
     /* Check and update the number of OpenMP threads requested */
-    checkAndUpdateRequestedNumOpenmpThreads(&hw_opt, *hwinfo_, cr, ms, physicalNodeComm.size_,
-                                            pmeRunMode, mtop, *inputrec);
-
-    gmx_omp_nthreads_init(mdlog, cr, hwinfo_->nthreads_hw_avail, physicalNodeComm.size_,
-                          hw_opt.nthreads_omp, hw_opt.nthreads_omp_pme, !thisRankHasDuty(cr, DUTY_PP));
-
-    // Enable FP exception detection, but not in
-    // Release mode and not for compilers with known buggy FP
-    // exception support (clang with any optimization) or suspected
-    // buggy FP exception support (gcc 7.* with optimization).
-#if !defined NDEBUG                                                                         \
-        && !((defined __clang__ || (defined(__GNUC__) && !defined(__ICC) && __GNUC__ == 7)) \
-             && defined __OPTIMIZE__)
-    const bool bEnableFPE = true;
-#else
-    const bool bEnableFPE = false;
-#endif
+    checkAndUpdateRequestedNumOpenmpThreads(
+            &hw_opt, *hwinfo_, cr, ms, physicalNodeComm.size_, pmeRunMode, mtop, *inputrec);
+
+    gmx_omp_nthreads_init(mdlog,
+                          cr,
+                          hwinfo_->nthreads_hw_avail,
+                          physicalNodeComm.size_,
+                          hw_opt.nthreads_omp,
+                          hw_opt.nthreads_omp_pme,
+                          !thisRankHasDuty(cr, DUTY_PP));
+
+    const bool bEnableFPE = gmxShouldEnableFPExceptions();
     // FIXME - reconcile with gmx_feenableexcept() call from CommandLineModuleManager::run()
     if (bEnableFPE)
     {
@@ -1354,17 +1558,18 @@ int Mdrunner::mdrunner()
     }
 
     /* Now that we know the setup is consistent, check for efficiency */
-    check_resource_division_efficiency(hwinfo_, gpuTaskAssignments.thisRankHasAnyGpuTask(),
-                                       mdrunOptions.ntompOptionIsSet, cr, mdlog);
+    check_resource_division_efficiency(
+            hwinfo_, gpuTaskAssignments.thisRankHasAnyGpuTask(), mdrunOptions.ntompOptionIsSet, cr, mdlog);
 
     /* getting number of PP/PME threads on this MPI / tMPI rank.
        PME: env variable should be read only on one node to make sure it is
        identical everywhere;
      */
-    const int numThreadsOnThisRank = thisRankHasDuty(cr, DUTY_PP) ? gmx_omp_nthreads_get(emntNonbonded)
-                                                                  : gmx_omp_nthreads_get(emntPME);
-    checkHardwareOversubscription(numThreadsOnThisRank, cr->nodeid, *hwinfo_->hardwareTopology,
-                                  physicalNodeComm, mdlog);
+    const int numThreadsOnThisRank = thisRankHasDuty(cr, DUTY_PP)
+                                             ? gmx_omp_nthreads_get(ModuleMultiThread::Nonbonded)
+                                             : gmx_omp_nthreads_get(ModuleMultiThread::Pme);
+    checkHardwareOversubscription(
+            numThreadsOnThisRank, cr->nodeid, *hwinfo_->hardwareTopology, physicalNodeComm, mdlog);
 
     // Enable Peer access between GPUs where available
     // Only for DD, only master PP rank needs to perform setup, and only if thread MPI plus
@@ -1373,7 +1578,7 @@ int Mdrunner::mdrunner()
         && (runScheduleWork.simulationWork.useGpuHaloExchange
             || runScheduleWork.simulationWork.useGpuPmePpCommunication))
     {
-        setupGpuDevicePeerAccess(gpuIdsToUse, mdlog);
+        setupGpuDevicePeerAccess(gpuTaskAssignments.deviceIdsAssigned(), mdlog);
     }
 
     if (hw_opt.threadAffinity != ThreadAffinity::Off)
@@ -1385,12 +1590,18 @@ int Mdrunner::mdrunner()
         gmx_check_thread_affinity_set(mdlog, &hw_opt, hwinfo_->nthreads_hw_avail, TRUE);
 
         int numThreadsOnThisNode, intraNodeThreadOffset;
-        analyzeThreadsOnThisNode(physicalNodeComm, numThreadsOnThisRank, &numThreadsOnThisNode,
-                                 &intraNodeThreadOffset);
+        analyzeThreadsOnThisNode(
+                physicalNodeComm, numThreadsOnThisRank, &numThreadsOnThisNode, &intraNodeThreadOffset);
 
         /* Set the CPU affinity */
-        gmx_set_thread_affinity(mdlog, cr, &hw_opt, *hwinfo_->hardwareTopology, numThreadsOnThisRank,
-                                numThreadsOnThisNode, intraNodeThreadOffset, nullptr);
+        gmx_set_thread_affinity(mdlog,
+                                cr,
+                                &hw_opt,
+                                *hwinfo_->hardwareTopology,
+                                numThreadsOnThisRank,
+                                numThreadsOnThisNode,
+                                intraNodeThreadOffset,
+                                nullptr);
     }
 
     if (mdrunOptions.timingOptions.resetStep > -1)
@@ -1401,20 +1612,27 @@ int Mdrunner::mdrunner()
                         "The -resetstep functionality is deprecated, and may be removed in a "
                         "future version.");
     }
-    wcycle = wallcycle_init(fplog, mdrunOptions.timingOptions.resetStep, cr);
+    std::unique_ptr<gmx_wallcycle> wcycle =
+            wallcycle_init(fplog, mdrunOptions.timingOptions.resetStep, cr);
 
     if (PAR(cr))
     {
         /* Master synchronizes its value of reset_counters with all nodes
          * including PME only nodes */
-        int64_t reset_counters = wcycle_get_reset_counters(wcycle);
+        int64_t reset_counters = wcycle_get_reset_counters(wcycle.get());
         gmx_bcast(sizeof(reset_counters), &reset_counters, cr->mpi_comm_mysim);
-        wcycle_set_reset_counters(wcycle, reset_counters);
+        wcycle_set_reset_counters(wcycle.get(), reset_counters);
     }
 
     // Membrane embedding must be initialized before we call init_forcerec()
-    membedHolder.initializeMembed(fplog, filenames.size(), filenames.data(), &mtop, inputrec.get(),
-                                  globalState.get(), cr, &mdrunOptions.checkpointOptions.period);
+    membedHolder.initializeMembed(fplog,
+                                  filenames.size(),
+                                  filenames.data(),
+                                  &mtop,
+                                  inputrec.get(),
+                                  globalState.get(),
+                                  cr,
+                                  &mdrunOptions.checkpointOptions.period);
 
     const bool               thisRankHasPmeGpuTask = gpuTaskAssignments.thisRankHasPmeGpuTask();
     std::unique_ptr<MDAtoms> mdAtoms;
@@ -1424,20 +1642,28 @@ int Mdrunner::mdrunner()
     t_nrnb nrnb;
     if (thisRankHasDuty(cr, DUTY_PP))
     {
-        mdModulesNotifier.notify(*cr);
-        mdModulesNotifier.notify(&atomSets);
-        mdModulesNotifier.notify(inputrec->pbcType);
-        mdModulesNotifier.notify(SimulationTimeStep{ inputrec->delta_t });
+        setupNotifier.notify(*cr);
+        setupNotifier.notify(&atomSets);
+        setupNotifier.notify(mtop);
+        setupNotifier.notify(inputrec->pbcType);
+        setupNotifier.notify(SimulationTimeStep{ inputrec->delta_t });
         /* Initiate forcerecord */
-        fr                 = new t_forcerec;
+        fr                 = std::make_unique<t_forcerec>();
         fr->forceProviders = mdModules_->initForceProviders();
-        init_forcerec(fplog, mdlog, fr, inputrec.get(), &mtop, cr, box,
+        init_forcerec(fplog,
+                      mdlog,
+                      fr.get(),
+                      *inputrec,
+                      mtop,
+                      cr,
+                      box,
                       opt2fn("-table", filenames.size(), filenames.data()),
                       opt2fn("-tablep", filenames.size(), filenames.data()),
-                      opt2fns("-tableb", filenames.size(), filenames.data()), pforce);
+                      opt2fns("-tableb", filenames.size(), filenames.data()),
+                      pforce);
         // Dirty hack, for fixing disres and orires should be made mdmodules
         fr->fcdata->disres = disresdata;
-        fr->fcdata->orires = oriresdata;
+        fr->fcdata->orires.swap(oriresData);
 
         // Save a handle to device stream manager to use elsewhere in the code
         // TODO: Forcerec is not a correct place to store it.
@@ -1454,13 +1680,22 @@ int Mdrunner::mdrunner()
                     "GPU PP-PME stream should be valid in order to use GPU PME-PP direct "
                     "communications.");
             fr->pmePpCommGpu = std::make_unique<gmx::PmePpCommGpu>(
-                    cr->mpi_comm_mysim, cr->dd->pme_nodeid, deviceStreamManager->context(),
+                    cr->mpi_comm_mysim,
+                    cr->dd->pme_nodeid,
+                    deviceStreamManager->context(),
                     deviceStreamManager->stream(DeviceStreamType::PmePpTransfer));
         }
 
-        fr->nbv = Nbnxm::init_nb_verlet(mdlog, inputrec.get(), fr, cr, *hwinfo_,
+        fr->nbv = Nbnxm::init_nb_verlet(mdlog,
+                                        *inputrec,
+                                        *fr,
+                                        cr,
+                                        *hwinfo_,
                                         runScheduleWork.simulationWork.useGpuNonbonded,
-                                        deviceStreamManager.get(), &mtop, box, wcycle);
+                                        deviceStreamManager.get(),
+                                        mtop,
+                                        box,
+                                        wcycle.get());
         // TODO: Move the logic below to a GPU bonded builder
         if (runScheduleWork.simulationWork.useGpuBonded)
         {
@@ -1468,8 +1703,11 @@ int Mdrunner::mdrunner()
                                "GPU device stream manager should be valid in order to use GPU "
                                "version of bonded forces.");
             gpuBonded = std::make_unique<GpuBonded>(
-                    mtop.ffparams, fr->ic->epsfac * fr->fudgeQQ, deviceStreamManager->context(),
-                    deviceStreamManager->bondedStream(havePPDomainDecomposition(cr)), wcycle);
+                    mtop.ffparams,
+                    fr->ic->epsfac * fr->fudgeQQ,
+                    deviceStreamManager->context(),
+                    deviceStreamManager->bondedStream(havePPDomainDecomposition(cr)),
+                    wcycle.get());
             fr->gpuBonded = gpuBonded.get();
         }
 
@@ -1489,7 +1727,12 @@ int Mdrunner::mdrunner()
         }
 
         /* Initialize the virtual site communication */
-        vsite = makeVirtualSitesHandler(mtop, cr, fr->pbcType);
+        gmx::ArrayRef<const gmx::RangePartitioning> updateGroupingsPerMoleculeType;
+        if (DOMAINDECOMP(cr))
+        {
+            updateGroupingsPerMoleculeType = getUpdateGroupingsPerMoleculeType(*cr->dd);
+        }
+        vsite = makeVirtualSitesHandler(mtop, cr, fr->pbcType, updateGroupingsPerMoleculeType);
 
         calc_shifts(box, fr->shift_vec);
 
@@ -1513,6 +1756,11 @@ int Mdrunner::mdrunner()
                 constructVirtualSitesGlobal(mtop, globalState->x);
             }
         }
+        // Make the DD reverse topology, now that any vsites that are present are available
+        if (DOMAINDECOMP(cr))
+        {
+            dd_make_reverse_top(fplog, cr->dd, mtop, vsite.get(), *inputrec, domdecOptions.ddBondedChecking);
+        }
 
         if (EEL_PME(fr->ic->eeltype) || EVDW_PME(fr->ic->vdwtype))
         {
@@ -1594,11 +1842,21 @@ int Mdrunner::mdrunner()
                                 ? &deviceStreamManager->stream(DeviceStreamType::Pme)
                                 : nullptr;
 
-                pmedata = gmx_pme_init(cr, getNumPmeDomains(cr->dd), inputrec.get(),
-                                       nChargePerturbed != 0, nTypePerturbed != 0,
-                                       mdrunOptions.reproducible, ewaldcoeff_q, ewaldcoeff_lj,
-                                       gmx_omp_nthreads_get(emntPME), pmeRunMode, nullptr,
-                                       deviceContext, pmeStream, pmeGpuProgram.get(), mdlog);
+                pmedata = gmx_pme_init(cr,
+                                       getNumPmeDomains(cr->dd),
+                                       inputrec.get(),
+                                       nChargePerturbed != 0,
+                                       nTypePerturbed != 0,
+                                       mdrunOptions.reproducible,
+                                       ewaldcoeff_q,
+                                       ewaldcoeff_lj,
+                                       gmx_omp_nthreads_get(ModuleMultiThread::Pme),
+                                       pmeRunMode,
+                                       nullptr,
+                                       deviceContext,
+                                       pmeStream,
+                                       pmeGpuProgram.get(),
+                                       mdlog);
             }
             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
         }
@@ -1619,12 +1877,17 @@ int Mdrunner::mdrunner()
     if (thisRankHasDuty(cr, DUTY_PP))
     {
         /* Assumes uniform use of the number of OpenMP threads */
-        walltime_accounting = walltime_accounting_init(gmx_omp_nthreads_get(emntDefault));
+        walltime_accounting = walltime_accounting_init(gmx_omp_nthreads_get(ModuleMultiThread::Default));
 
         if (inputrec->bPull)
         {
             /* Initialize pull code */
-            pull_work = init_pull(fplog, inputrec->pull.get(), inputrec.get(), &mtop, cr, &atomSets,
+            pull_work = init_pull(fplog,
+                                  inputrec->pull.get(),
+                                  inputrec.get(),
+                                  mtop,
+                                  cr,
+                                  &atomSets,
                                   inputrec->fepvals->init_lambda);
             if (inputrec->pull->bXOutAverage || inputrec->pull->bFOutAverage)
             {
@@ -1640,24 +1903,48 @@ int Mdrunner::mdrunner()
         if (inputrec->bRot)
         {
             /* Initialize enforced rotation code */
-            enforcedRotation = init_rot(fplog, inputrec.get(), filenames.size(), filenames.data(),
-                                        cr, &atomSets, globalState.get(), &mtop, oenv, mdrunOptions,
+            enforcedRotation = init_rot(fplog,
+                                        inputrec.get(),
+                                        filenames.size(),
+                                        filenames.data(),
+                                        cr,
+                                        &atomSets,
+                                        globalState.get(),
+                                        mtop,
+                                        oenv,
+                                        mdrunOptions,
                                         startingBehavior);
         }
 
         t_swap* swap = nullptr;
-        if (inputrec->eSwapCoords != eswapNO)
+        if (inputrec->eSwapCoords != SwapType::No)
         {
             /* Initialize ion swapping code */
-            swap = init_swapcoords(fplog, inputrec.get(),
+            swap = init_swapcoords(fplog,
+                                   inputrec.get(),
                                    opt2fn_master("-swap", filenames.size(), filenames.data(), cr),
-                                   &mtop, globalState.get(), &observablesHistory, cr, &atomSets,
-                                   oenv, mdrunOptions, startingBehavior);
+                                   mtop,
+                                   globalState.get(),
+                                   &observablesHistory,
+                                   cr,
+                                   &atomSets,
+                                   oenv,
+                                   mdrunOptions,
+                                   startingBehavior);
         }
 
         /* Let makeConstraints know whether we have essential dynamics constraints. */
-        auto constr = makeConstraints(mtop, *inputrec, pull_work, doEssentialDynamics, fplog, cr,
-                                      ms, &nrnb, wcycle, fr->bMolPBC);
+        auto constr = makeConstraints(mtop,
+                                      *inputrec,
+                                      pull_work,
+                                      doEssentialDynamics,
+                                      fplog,
+                                      cr,
+                                      DOMAINDECOMP(cr) && ddMayHaveSplitConstraints(*cr->dd),
+                                      ms,
+                                      &nrnb,
+                                      wcycle.get(),
+                                      fr->bMolPBC);
 
         /* Energy terms and groups */
         gmx_enerdata_t enerd(mtop.groups.groups[SimulationAtomGroupType::EnergyOutput].size(),
@@ -1665,37 +1952,48 @@ int Mdrunner::mdrunner()
 
         // cos acceleration is only supported by md, but older tpr
         // files might still combine it with other integrators
-        GMX_RELEASE_ASSERT(inputrec->cos_accel == 0.0 || inputrec->eI == eiMD,
+        GMX_RELEASE_ASSERT(inputrec->cos_accel == 0.0 || inputrec->eI == IntegrationAlgorithm::MD,
                            "cos_acceleration is only supported by integrator=md");
 
         /* Kinetic energy data */
-        gmx_ekindata_t ekind;
-        init_ekindata(fplog, &mtop, &(inputrec->opts), &ekind, inputrec->cos_accel);
+        gmx_ekindata_t ekind(inputrec->opts.ngtc,
+                             inputrec->cos_accel,
+                             gmx_omp_nthreads_get(ModuleMultiThread::Update));
 
         /* Set up interactive MD (IMD) */
-        auto imdSession =
-                makeImdSession(inputrec.get(), cr, wcycle, &enerd, ms, &mtop, mdlog,
-                               MASTER(cr) ? globalState->x.rvec_array() : nullptr, filenames.size(),
-                               filenames.data(), oenv, mdrunOptions.imdOptions, startingBehavior);
+        auto imdSession = makeImdSession(inputrec.get(),
+                                         cr,
+                                         wcycle.get(),
+                                         &enerd,
+                                         ms,
+                                         mtop,
+                                         mdlog,
+                                         MASTER(cr) ? globalState->x : gmx::ArrayRef<gmx::RVec>(),
+                                         filenames.size(),
+                                         filenames.data(),
+                                         oenv,
+                                         mdrunOptions.imdOptions,
+                                         startingBehavior);
 
         if (DOMAINDECOMP(cr))
         {
             GMX_RELEASE_ASSERT(fr, "fr was NULL while cr->duty was DUTY_PP");
-            /* This call is not included in init_domain_decomposition mainly
+            /* This call is not included in init_domain_decomposition
              * because fr->cginfo_mb is set later.
              */
-            dd_init_bondeds(fplog, cr->dd, mtop, vsite.get(), inputrec.get(),
-                            domdecOptions.checkBondedInteractions, fr->cginfo_mb);
+            makeBondedLinks(cr->dd, mtop, fr->cginfo_mb);
         }
 
         if (runScheduleWork.simulationWork.useGpuBufferOps)
         {
             fr->gpuForceReduction[gmx::AtomLocality::Local] = std::make_unique<gmx::GpuForceReduction>(
                     deviceStreamManager->context(),
-                    deviceStreamManager->stream(gmx::DeviceStreamType::NonBondedLocal), wcycle);
+                    deviceStreamManager->stream(gmx::DeviceStreamType::NonBondedLocal),
+                    wcycle.get());
             fr->gpuForceReduction[gmx::AtomLocality::NonLocal] = std::make_unique<gmx::GpuForceReduction>(
                     deviceStreamManager->context(),
-                    deviceStreamManager->stream(gmx::DeviceStreamType::NonBondedNonLocal), wcycle);
+                    deviceStreamManager->stream(gmx::DeviceStreamType::NonBondedNonLocal),
+                    wcycle.get());
         }
 
         std::unique_ptr<gmx::StatePropagatorDataGpu> stateGpu;
@@ -1703,13 +2001,14 @@ int Mdrunner::mdrunner()
             && ((runScheduleWork.simulationWork.useGpuPme && thisRankHasDuty(cr, DUTY_PME))
                 || runScheduleWork.simulationWork.useGpuBufferOps))
         {
-            GpuApiCallBehavior transferKind = (inputrec->eI == eiMD && !doRerun && !useModularSimulator)
-                                                      ? GpuApiCallBehavior::Async
-                                                      : GpuApiCallBehavior::Sync;
+            GpuApiCallBehavior transferKind =
+                    (inputrec->eI == IntegrationAlgorithm::MD && !doRerun && !useModularSimulator)
+                            ? GpuApiCallBehavior::Async
+                            : GpuApiCallBehavior::Sync;
             GMX_RELEASE_ASSERT(deviceStreamManager != nullptr,
                                "GPU device stream manager should be initialized to use GPU.");
             stateGpu = std::make_unique<gmx::StatePropagatorDataGpu>(
-                    *deviceStreamManager, transferKind, pme_gpu_get_block_size(fr->pmedata), wcycle);
+                    *deviceStreamManager, transferKind, pme_gpu_get_block_size(fr->pmedata), wcycle.get());
             fr->stateGpu = stateGpu.get();
         }
 
@@ -1723,20 +2022,19 @@ int Mdrunner::mdrunner()
 
 
         simulatorBuilder.add(SimulatorEnv(fplog, cr, ms, mdlog, oenv));
-        simulatorBuilder.add(Profiling(&nrnb, walltime_accounting, wcycle));
+        simulatorBuilder.add(Profiling(&nrnb, walltime_accounting, wcycle.get()));
         simulatorBuilder.add(ConstraintsParam(
-                constr.get(), enforcedRotation ? enforcedRotation->getLegacyEnfrot() : nullptr,
-                vsite.get()));
+                constr.get(), enforcedRotation ? enforcedRotation->getLegacyEnfrot() : nullptr, vsite.get()));
         // TODO: Separate `fr` to a separate add, and make the `build` handle the coupling sensibly.
-        simulatorBuilder.add(LegacyInput(static_cast<int>(filenames.size()), filenames.data(),
-                                         inputrec.get(), fr));
+        simulatorBuilder.add(LegacyInput(
+                static_cast<int>(filenames.size()), filenames.data(), inputrec.get(), fr.get()));
         simulatorBuilder.add(ReplicaExchangeParameters(replExParams));
         simulatorBuilder.add(InteractiveMD(imdSession.get()));
-        simulatorBuilder.add(SimulatorModules(mdModules_->outputProvider(), mdModules_->notifier()));
+        simulatorBuilder.add(SimulatorModules(mdModules_->outputProvider(), mdModules_->notifiers()));
         simulatorBuilder.add(CenterOfMassPulling(pull_work));
         // Todo move to an MDModule
         simulatorBuilder.add(IonSwapping(swap));
-        simulatorBuilder.add(TopologyData(&mtop, mdAtoms.get()));
+        simulatorBuilder.add(TopologyData(mtop, mdAtoms.get()));
         simulatorBuilder.add(BoxDeformationHandle(deform.get()));
         simulatorBuilder.add(std::move(modularSimulatorCheckpointData));
 
@@ -1760,21 +2058,34 @@ int Mdrunner::mdrunner()
     {
         GMX_RELEASE_ASSERT(pmedata, "pmedata was NULL while cr->duty was not DUTY_PP");
         /* do PME only */
-        walltime_accounting = walltime_accounting_init(gmx_omp_nthreads_get(emntPME));
-        gmx_pmeonly(pmedata, cr, &nrnb, wcycle, walltime_accounting, inputrec.get(), pmeRunMode,
+        walltime_accounting = walltime_accounting_init(gmx_omp_nthreads_get(ModuleMultiThread::Pme));
+        gmx_pmeonly(pmedata,
+                    cr,
+                    &nrnb,
+                    wcycle.get(),
+                    walltime_accounting,
+                    inputrec.get(),
+                    pmeRunMode,
+                    runScheduleWork.simulationWork.useGpuPmePpCommunication,
                     deviceStreamManager.get());
     }
 
-    wallcycle_stop(wcycle, ewcRUN);
+    wallcycle_stop(wcycle.get(), WallCycleCounter::Run);
 
     /* Finish up, write some stuff
      * if rerunMD, don't write last frame again
      */
-    finish_run(fplog, mdlog, cr, inputrec.get(), &nrnb, wcycle, walltime_accounting,
-               fr ? fr->nbv.get() : nullptr, pmedata, EI_DYNAMICS(inputrec->eI) && !isMultiSim(ms));
+    finish_run(fplog,
+               mdlog,
+               cr,
+               *inputrec,
+               &nrnb,
+               wcycle.get(),
+               walltime_accounting,
+               fr ? fr->nbv.get() : nullptr,
+               pmedata,
+               EI_DYNAMICS(inputrec->eI) && !isMultiSim(ms));
 
-    // clean up cycle counter
-    wallcycle_destroy(wcycle);
 
     deviceStreamManager.reset(nullptr);
     // Free PME data
@@ -1792,12 +2103,9 @@ int Mdrunner::mdrunner()
     globalState.reset(nullptr);
     mdModules_.reset(nullptr); // destruct force providers here as they might also use the GPU
     gpuBonded.reset(nullptr);
-    /* Free pinned buffers in *fr */
-    delete fr;
-    fr = nullptr;
+    fr.reset(nullptr); // destruct forcerec before gpu
     // TODO convert to C++ so we can get rid of these frees
     sfree(disresdata);
-    sfree(oriresdata);
 
     if (!hwinfo_->deviceInfoList.empty())
     {
@@ -1824,7 +2132,14 @@ int Mdrunner::mdrunner()
     {
         physicalNodeComm.barrier();
     }
-    releaseDevice(deviceInfo);
+
+    if (!devFlags.usingCudaAwareMpi)
+    {
+        // Don't reset GPU in case of CUDA-AWARE MPI
+        // UCX creates CUDA buffers which are cleaned-up as part of MPI_Finalize()
+        // resetting the device before MPI_Finalize() results in crashes inside UCX
+        releaseDevice(deviceInfo);
+    }
 
     /* Does what it says */
     print_date_and_time(fplog, cr->nodeid, "Finished mdrun", gmx_gettime());
index ccc3c3e3cae7fb7718dc8144c82c4f6797758591..3c000e1addacb8d365d04d18ba986c2f0f078a25 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gmxlib/network.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/math/vecdump.h"
 #include "gromacs/mdlib/constr.h"
@@ -61,7 +62,6 @@
 #include "gromacs/mdlib/force.h"
 #include "gromacs/mdlib/force_flags.h"
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
-#include "gromacs/mdlib/mdatoms.h"
 #include "gromacs/mdlib/vsite.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/enerdata.h"
@@ -152,20 +152,17 @@ static void pr_shell(FILE* fplog, ArrayRef<const t_shell> shells)
  * started, but even when called, the prediction was always
  * over-written by a subsequent call in the MD loop, so has been
  * removed. */
-static void predict_shells(FILE*                   fplog,
-                           ArrayRef<RVec>          x,
-                           ArrayRef<RVec>          v,
-                           real                    dt,
-                           ArrayRef<const t_shell> shells,
-                           const real              mass[],
-                           gmx_mtop_t*             mtop,
-                           gmx_bool                bInit)
+static void predict_shells(FILE*                     fplog,
+                           ArrayRef<RVec>            x,
+                           ArrayRef<RVec>            v,
+                           real                      dt,
+                           ArrayRef<const t_shell>   shells,
+                           gmx::ArrayRef<const real> mass,
+                           gmx_bool                  bInit)
 {
     int  m, n1, n2, n3;
     real dt_1, fudge, tm, m1, m2, m3;
 
-    GMX_RELEASE_ASSERT(mass || mtop, "Must have masses or a way to look them up");
-
     /* 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
      * without
@@ -188,7 +185,6 @@ static void predict_shells(FILE*                   fplog,
         dt_1 = fudge * dt;
     }
 
-    int molb = 0;
     for (const t_shell& shell : shells)
     {
         const int s1 = shell.shellIndex;
@@ -208,17 +204,8 @@ static void predict_shells(FILE*                   fplog,
             case 2:
                 n1 = shell.nucl1;
                 n2 = shell.nucl2;
-                if (mass)
-                {
-                    m1 = mass[n1];
-                    m2 = mass[n2];
-                }
-                else
-                {
-                    /* Not the correct masses with FE, but it is just a prediction... */
-                    m1 = mtopGetAtomMass(mtop, n1, &molb);
-                    m2 = mtopGetAtomMass(mtop, n2, &molb);
-                }
+                m1 = mass[n1];
+                m2 = mass[n2];
                 tm = dt_1 / (m1 + m2);
                 for (m = 0; (m < DIM); m++)
                 {
@@ -229,19 +216,9 @@ static void predict_shells(FILE*                   fplog,
                 n1 = shell.nucl1;
                 n2 = shell.nucl2;
                 n3 = shell.nucl3;
-                if (mass)
-                {
-                    m1 = mass[n1];
-                    m2 = mass[n2];
-                    m3 = mass[n3];
-                }
-                else
-                {
-                    /* Not the correct masses with FE, but it is just a prediction... */
-                    m1 = mtopGetAtomMass(mtop, n1, &molb);
-                    m2 = mtopGetAtomMass(mtop, n2, &molb);
-                    m3 = mtopGetAtomMass(mtop, n3, &molb);
-                }
+                m1 = mass[n1];
+                m2 = mass[n2];
+                m3 = mass[n3];
                 tm = dt_1 / (m1 + m2 + m3);
                 for (m = 0; (m < DIM); m++)
                 {
@@ -254,7 +231,7 @@ static void predict_shells(FILE*                   fplog,
 }
 
 gmx_shellfc_t* init_shell_flexcon(FILE*             fplog,
-                                  const gmx_mtop_t* mtop,
+                                  const gmx_mtop_t& mtop,
                                   int               nflexcon,
                                   int               nstcalcenergy,
                                   bool              usingDomainDecomposition,
@@ -270,22 +247,21 @@ gmx_shellfc_t* init_shell_flexcon(FILE*             fplog,
 #define NBT asize(bondtypes)
     const gmx_ffparams_t* ffparams;
 
-    const std::array<int, eptNR> numParticles = gmx_mtop_particletype_count(*mtop);
+    const gmx::EnumerationArray<ParticleType, int> numParticles = gmx_mtop_particletype_count(mtop);
     if (fplog)
     {
         /* Print the number of each particle type */
-        int pType = 0;
-        for (const auto& n : numParticles)
+        for (const auto entry : gmx::keysOf(numParticles))
         {
-            if (n != 0)
+            const int number = numParticles[entry];
+            if (number != 0)
             {
-                fprintf(fplog, "There are: %d %ss\n", n, ptype_str[pType]);
+                fprintf(fplog, "There are: %d %ss\n", number, enumValueToString(entry));
             }
-            pType++;
         }
     }
 
-    nshell = numParticles[eptShell];
+    nshell = numParticles[ParticleType::Shell];
 
     if (nshell == 0 && nflexcon == 0)
     {
@@ -321,14 +297,14 @@ gmx_shellfc_t* init_shell_flexcon(FILE*             fplog,
     /* We have shells: fill the shell data structure */
 
     /* Global system sized array, this should be avoided */
-    std::vector<int> shell_index(mtop->natoms);
+    std::vector<int> shell_index(mtop.natoms);
 
     nshell = 0;
-    for (const AtomProxy atomP : AtomRange(*mtop))
+    for (const AtomProxy atomP : AtomRange(mtop))
     {
         const t_atom& local = atomP.atom();
         int           i     = atomP.globalAtomNumber();
-        if (local.ptype == eptShell)
+        if (local.ptype == ParticleType::Shell)
         {
             shell_index[i] = nshell++;
         }
@@ -336,25 +312,25 @@ gmx_shellfc_t* init_shell_flexcon(FILE*             fplog,
 
     std::vector<t_shell> shell(nshell);
 
-    ffparams = &mtop->ffparams;
+    ffparams = &mtop.ffparams;
 
     /* Now fill the structures */
     /* TODO: See if we can use update groups that cover shell constructions */
     shfc->bInterCG = FALSE;
     ns             = 0;
     a_offset       = 0;
-    for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
+    for (size_t mb = 0; mb < mtop.molblock.size(); mb++)
     {
-        const gmx_molblock_t* molb = &mtop->molblock[mb];
-        const gmx_moltype_t*  molt = &mtop->moltype[molb->type];
+        const gmx_molblock_t& molb = mtop.molblock[mb];
+        const gmx_moltype_t&  molt = mtop.moltype[molb.type];
 
-        const t_atom* atom = molt->atoms.atom;
-        for (mol = 0; mol < molb->nmol; mol++)
+        const t_atom* atom = molt.atoms.atom;
+        for (mol = 0; mol < molb.nmol; mol++)
         {
             for (j = 0; (j < NBT); j++)
             {
-                const int* ia = molt->ilist[bondtypes[j]].iatoms.data();
-                for (i = 0; (i < molt->ilist[bondtypes[j]].size());)
+                const int* ia = molt.ilist[bondtypes[j]].iatoms.data();
+                for (i = 0; (i < molt.ilist[bondtypes[j]].size());)
                 {
                     type  = ia[0];
                     ftype = ffparams->functype[type];
@@ -370,12 +346,12 @@ gmx_shellfc_t* init_shell_flexcon(FILE*             fplog,
                         case F_CUBICBONDS:
                         case F_POLARIZATION:
                         case F_ANHARM_POL:
-                            if (atom[ia[1]].ptype == eptShell)
+                            if (atom[ia[1]].ptype == ParticleType::Shell)
                             {
                                 aS = ia[1];
                                 aN = ia[2];
                             }
-                            else if (atom[ia[2]].ptype == eptShell)
+                            else if (atom[ia[2]].ptype == ParticleType::Shell)
                             {
                                 aS = ia[2];
                                 aN = ia[1];
@@ -450,9 +426,12 @@ gmx_shellfc_t* init_shell_flexcon(FILE*             fplog,
                                     gmx_fatal(FARGS,
                                               "polarize can not be used with qA(%e) != qB(%e) for "
                                               "atom %d of molecule block %zu",
-                                              qS, atom[aS].qB, aS + 1, mb + 1);
+                                              qS,
+                                              atom[aS].qB,
+                                              aS + 1,
+                                              mb + 1);
                                 }
-                                shell[nsi].k += gmx::square(qS) * ONE_4PI_EPS0
+                                shell[nsi].k += gmx::square(qS) * gmx::c_one4PiEps0
                                                 / ffparams->iparams[type].polarize.alpha;
                                 break;
                             case F_WATER_POL:
@@ -461,13 +440,16 @@ gmx_shellfc_t* init_shell_flexcon(FILE*             fplog,
                                     gmx_fatal(FARGS,
                                               "water_pol can not be used with qA(%e) != qB(%e) for "
                                               "atom %d of molecule block %zu",
-                                              qS, atom[aS].qB, aS + 1, mb + 1);
+                                              qS,
+                                              atom[aS].qB,
+                                              aS + 1,
+                                              mb + 1);
                                 }
                                 alpha = (ffparams->iparams[type].wpol.al_x
                                          + ffparams->iparams[type].wpol.al_y
                                          + ffparams->iparams[type].wpol.al_z)
                                         / 3.0;
-                                shell[nsi].k += gmx::square(qS) * ONE_4PI_EPS0 / alpha;
+                                shell[nsi].k += gmx::square(qS) * gmx::c_one4PiEps0 / alpha;
                                 break;
                             default: gmx_fatal(FARGS, "Death Horror: %s, %d", __FILE__, __LINE__);
                         }
@@ -477,7 +459,7 @@ gmx_shellfc_t* init_shell_flexcon(FILE*             fplog,
                     i += nra + 1;
                 }
             }
-            a_offset += molt->atoms.nr;
+            a_offset += molt.atoms.nr;
         }
         /* Done with this molecule type */
     }
@@ -553,7 +535,7 @@ gmx_shellfc_t* init_shell_flexcon(FILE*             fplog,
     return shfc;
 }
 
-void gmx::make_local_shells(const t_commrec* cr, const t_mdatoms* md, gmx_shellfc_t* shfc)
+void gmx::make_local_shells(const t_commrec* cr, const t_mdatoms& md, gmx_shellfc_t* shfc)
 {
     int           a0, a1;
     gmx_domdec_t* dd = nullptr;
@@ -576,9 +558,10 @@ void gmx::make_local_shells(const t_commrec* cr, const t_mdatoms* md, gmx_shellf
 
     std::vector<t_shell>& shells = shfc->shells;
     shells.clear();
+    auto* ptype = md.ptype;
     for (int i = a0; i < a1; i++)
     {
-        if (md->ptype[i] == eptShell)
+        if (ptype[i] == ParticleType::Shell)
         {
             if (dd)
             {
@@ -819,8 +802,13 @@ static void dump_shells(FILE* fp, ArrayRef<RVec> f, real ftol, ArrayRef<const t_
         ff2           = iprod(f[ind], f[ind]);
         if (ff2 > ft2)
         {
-            fprintf(fp, "SHELL %5d, force %10.5f  %10.5f  %10.5f, |f| %10.5f\n", ind, f[ind][XX],
-                    f[ind][YY], f[ind][ZZ], std::sqrt(ff2));
+            fprintf(fp,
+                    "SHELL %5d, force %10.5f  %10.5f  %10.5f, |f| %10.5f\n",
+                    ind,
+                    f[ind][XX],
+                    f[ind][YY],
+                    f[ind][ZZ],
+                    std::sqrt(ff2));
         }
     }
 }
@@ -831,7 +819,7 @@ static void init_adir(gmx_shellfc_t*            shfc,
                       const t_commrec*          cr,
                       int                       dd_ac1,
                       int64_t                   step,
-                      const t_mdatoms*          md,
+                      const t_mdatoms&          md,
                       int                       end,
                       ArrayRefWithPadding<RVec> xOld,
                       ArrayRef<RVec>            x_init,
@@ -842,9 +830,8 @@ static void init_adir(gmx_shellfc_t*            shfc,
                       ArrayRef<const real>      lambda,
                       real*                     dvdlambda)
 {
-    double          dt, w_dt;
-    int             n, d;
-    unsigned short* ptype;
+    double dt, w_dt;
+    int    n, d;
 
     if (DOMAINDECOMP(cr))
     {
@@ -861,18 +848,18 @@ static void init_adir(gmx_shellfc_t*            shfc,
     rvec* x_old = as_rvec_array(xOld.paddedArrayRef().data());
     rvec* x     = as_rvec_array(xCurrent.paddedArrayRef().data());
 
-    ptype = md->ptype;
-
-    dt = ir->delta_t;
+    auto* ptype   = md.ptype;
+    auto  invmass = gmx::arrayRefFromArray(md.invmass, md.nr);
+    dt            = ir->delta_t;
 
-    /* Does NOT work with freeze or acceleration groups (yet) */
+    /* Does NOT work with freeze groups (yet) */
     for (n = 0; n < end; n++)
     {
-        w_dt = md->invmass[n] * dt;
+        w_dt = invmass[n] * dt;
 
         for (d = 0; d < DIM; d++)
         {
-            if ((ptype[n] != eptVSite) && (ptype[n] != eptShell))
+            if ((ptype[n] != ParticleType::VSite) && (ptype[n] != ParticleType::Shell))
             {
                 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;
@@ -887,13 +874,35 @@ static void init_adir(gmx_shellfc_t*            shfc,
     bool needsLogging  = false;
     bool computeEnergy = false;
     bool computeVirial = false;
-    constr->apply(needsLogging, computeEnergy, step, 0, 1.0, xCurrent,
-                  shfc->adir_xnold.arrayRefWithPadding(), {}, box, lambda[efptBONDED],
-                  &(dvdlambda[efptBONDED]), {}, computeVirial, nullptr,
+    constr->apply(needsLogging,
+                  computeEnergy,
+                  step,
+                  0,
+                  1.0,
+                  xCurrent,
+                  shfc->adir_xnold.arrayRefWithPadding(),
+                  {},
+                  box,
+                  lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Bonded)],
+                  &(dvdlambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Bonded)]),
+                  {},
+                  computeVirial,
+                  nullptr,
                   gmx::ConstraintVariable::Positions);
-    constr->apply(needsLogging, computeEnergy, step, 0, 1.0, xCurrent,
-                  shfc->adir_xnew.arrayRefWithPadding(), {}, box, lambda[efptBONDED],
-                  &(dvdlambda[efptBONDED]), {}, computeVirial, nullptr,
+    constr->apply(needsLogging,
+                  computeEnergy,
+                  step,
+                  0,
+                  1.0,
+                  xCurrent,
+                  shfc->adir_xnew.arrayRefWithPadding(),
+                  {},
+                  box,
+                  lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Bonded)],
+                  &(dvdlambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Bonded)]),
+                  {},
+                  computeVirial,
+                  nullptr,
                   gmx::ConstraintVariable::Positions);
 
     for (n = 0; n < end; n++)
@@ -901,15 +910,27 @@ static void init_adir(gmx_shellfc_t*            shfc,
         for (d = 0; d < DIM; d++)
         {
             xnew[n][d] = -(2 * x[n][d] - xnold[n][d] - xnew[n][d]) / gmx::square(dt)
-                         - f[n][d] * md->invmass[n];
+                         - f[n][d] * invmass[n];
         }
         clear_rvec(acc_dir[n]);
     }
 
     /* Project the acceleration on the old bond directions */
-    constr->apply(needsLogging, computeEnergy, step, 0, 1.0, xOld, shfc->adir_xnew.arrayRefWithPadding(),
-                  acc_dir, box, lambda[efptBONDED], &(dvdlambda[efptBONDED]), {}, computeVirial,
-                  nullptr, gmx::ConstraintVariable::Deriv_FlexCon);
+    constr->apply(needsLogging,
+                  computeEnergy,
+                  step,
+                  0,
+                  1.0,
+                  xOld,
+                  shfc->adir_xnew.arrayRefWithPadding(),
+                  acc_dir,
+                  box,
+                  lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Bonded)],
+                  &(dvdlambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Bonded)]),
+                  {},
+                  computeVirial,
+                  nullptr,
+                  gmx::ConstraintVariable::Deriv_FlexCon);
 }
 
 void relax_shell_flexcon(FILE*                         fplog,
@@ -931,12 +952,12 @@ void relax_shell_flexcon(FILE*                         fplog,
                          ArrayRefWithPadding<RVec>     vPadded,
                          const matrix                  box,
                          ArrayRef<real>                lambda,
-                         history_t*                    hist,
+                         const history_t*              hist,
                          gmx::ForceBuffersView*        f,
                          tensor                        force_vir,
-                         const t_mdatoms*              md,
+                         const t_mdatoms&              md,
                          t_nrnb*                       nrnb,
-                         gmx_wallcycle_t               wcycle,
+                         gmx_wallcycle               wcycle,
                          gmx_shellfc_t*                shfc,
                          t_forcerec*                   fr,
                          gmx::MdrunScheduleWorkload*   runScheduleWork,
@@ -950,7 +971,7 @@ void relax_shell_flexcon(FILE*                         fplog,
     real dum = 0;
     char sbuf[22];
     int  nat, dd_ac0, dd_ac1 = 0, i;
-    int  homenr = md->homenr, end = homenr;
+    int  homenr = md.homenr, end = homenr;
     int  d, Min = 0, count = 0;
 #define Try (1 - Min) /* At start Try = 1 */
 
@@ -963,10 +984,10 @@ void relax_shell_flexcon(FILE*                         fplog,
 
     if (DOMAINDECOMP(cr))
     {
-        nat = dd_natoms_vsite(cr->dd);
+        nat = dd_natoms_vsite(*cr->dd);
         if (nflexcon > 0)
         {
-            dd_get_constraint_range(cr->dd, &dd_ac0, &dd_ac1);
+            dd_get_constraint_range(*cr->dd, &dd_ac0, &dd_ac1);
             nat = std::max(nat, dd_ac1);
         }
     }
@@ -1003,8 +1024,8 @@ void relax_shell_flexcon(FILE*                         fplog,
          * before do_force is called, which normally puts all
          * charge groups in the box.
          */
-        put_atoms_in_box_omp(fr->pbcType, box, x.subArray(0, md->homenr),
-                             gmx_omp_nthreads_get(emntDefault));
+        put_atoms_in_box_omp(
+                fr->pbcType, box, x.subArray(0, md.homenr), gmx_omp_nthreads_get(ModuleMultiThread::Default));
     }
 
     if (nflexcon)
@@ -1021,12 +1042,13 @@ void relax_shell_flexcon(FILE*                         fplog,
         }
     }
 
+    auto massT = gmx::arrayRefFromArray(md.massT, md.nr);
     /* Do a prediction of the shell positions, when appropriate.
      * Without velocities (EM, NM, BD) we only do initial prediction.
      */
     if (shfc->predictShells && !bCont && (EI_STATE_VELOCITY(inputrec->eI) || bInit))
     {
-        predict_shells(fplog, x, v, inputrec->delta_t, shells, md->massT, nullptr, bInit);
+        predict_shells(fplog, x, v, inputrec->delta_t, shells, massT, bInit);
     }
 
     /* Calculate the forces first time around */
@@ -1036,23 +1058,61 @@ void relax_shell_flexcon(FILE*                         fplog,
     }
     int                   shellfc_flags = force_flags | (bVerbose ? GMX_FORCE_ENERGY : 0);
     gmx::ForceBuffersView forceViewInit = gmx::ForceBuffersView(forceWithPadding[Min], {}, false);
-    do_force(fplog, cr, ms, inputrec, nullptr, enforcedRotation, imdSession, pull_work, mdstep,
-             nrnb, wcycle, top, box, xPadded, hist, &forceViewInit, force_vir, md, enerd, lambda,
-             fr, runScheduleWork, vsite, mu_tot, t, nullptr,
-             (bDoNS ? GMX_FORCE_NS : 0) | shellfc_flags, ddBalanceRegionHandler);
+    do_force(fplog,
+             cr,
+             ms,
+             *inputrec,
+             nullptr,
+             enforcedRotation,
+             imdSession,
+             pull_work,
+             mdstep,
+             nrnb,
+             wcycle,
+             top,
+             box,
+             xPadded,
+             hist,
+             &forceViewInit,
+             force_vir,
+             &md,
+             enerd,
+             lambda,
+             fr,
+             runScheduleWork,
+             vsite,
+             mu_tot,
+             t,
+             nullptr,
+             (bDoNS ? GMX_FORCE_NS : 0) | shellfc_flags,
+             ddBalanceRegionHandler);
 
     sf_dir = 0;
     if (nflexcon)
     {
-        init_adir(shfc, constr, inputrec, cr, dd_ac1, mdstep, md, end, shfc->x_old.arrayRefWithPadding(),
-                  x, xPadded, force[Min], shfc->acc_dir, box, lambda, &dum);
+        init_adir(shfc,
+                  constr,
+                  inputrec,
+                  cr,
+                  dd_ac1,
+                  mdstep,
+                  md,
+                  end,
+                  shfc->x_old.arrayRefWithPadding(),
+                  x,
+                  xPadded,
+                  force[Min],
+                  shfc->acc_dir,
+                  box,
+                  lambda,
+                  &dum);
 
         for (i = 0; i < end; i++)
         {
-            sf_dir += md->massT[i] * norm2(shfc->acc_dir[i]);
+            sf_dir += massT[i] * norm2(shfc->acc_dir[i]);
         }
     }
-    accumulatePotentialEnergies(enerd, lambda, inputrec->fepvals);
+    accumulatePotentialEnergies(enerd, lambda, inputrec->fepvals.get());
     Epot[Min] = enerd->term[F_EPOT];
 
     df[Min] = rms_force(cr, forceWithPadding[Min].paddedArrayRef(), shells, nflexcon, &sf_dir, &Epot[Min]);
@@ -1064,7 +1124,7 @@ void relax_shell_flexcon(FILE*                         fplog,
 
     if (gmx_debug_at)
     {
-        pr_rvecs(debug, 0, "force0", as_rvec_array(force[Min].data()), md->nr);
+        pr_rvecs(debug, 0, "force0", as_rvec_array(force[Min].data()), md.nr);
     }
 
     if (!shells.empty() || nflexcon > 0)
@@ -1073,9 +1133,11 @@ void relax_shell_flexcon(FILE*                         fplog,
          * shell positions are updated, therefore the other particles must
          * be set here, in advance.
          */
-        std::copy(xPadded.paddedArrayRef().begin(), xPadded.paddedArrayRef().end(),
+        std::copy(xPadded.paddedArrayRef().begin(),
+                  xPadded.paddedArrayRef().end(),
                   posWithPadding[Min].paddedArrayRef().begin());
-        std::copy(xPadded.paddedArrayRef().begin(), xPadded.paddedArrayRef().end(),
+        std::copy(xPadded.paddedArrayRef().begin(),
+                  xPadded.paddedArrayRef().end(),
                   posWithPadding[Try].paddedArrayRef().begin());
     }
 
@@ -1101,14 +1163,27 @@ void relax_shell_flexcon(FILE*                         fplog,
     {
         if (vsite)
         {
-            vsite->construct(pos[Min], inputrec->delta_t, v, box);
+            vsite->construct(pos[Min], v, box, gmx::VSiteOperation::PositionsAndVelocities);
         }
 
         if (nflexcon)
         {
-            init_adir(shfc, constr, inputrec, cr, dd_ac1, mdstep, md, end,
-                      shfc->x_old.arrayRefWithPadding(), x, posWithPadding[Min], force[Min],
-                      shfc->acc_dir, box, lambda, &dum);
+            init_adir(shfc,
+                      constr,
+                      inputrec,
+                      cr,
+                      dd_ac1,
+                      mdstep,
+                      md,
+                      end,
+                      shfc->x_old.arrayRefWithPadding(),
+                      x,
+                      posWithPadding[Min],
+                      force[Min],
+                      shfc->acc_dir,
+                      box,
+                      lambda,
+                      &dum);
 
             directional_sd(pos[Min], pos[Try], shfc->acc_dir, end, fr->fc_stepsize);
         }
@@ -1123,10 +1198,35 @@ void relax_shell_flexcon(FILE*                         fplog,
         }
         /* Try the new positions */
         gmx::ForceBuffersView forceViewTry = gmx::ForceBuffersView(forceWithPadding[Try], {}, false);
-        do_force(fplog, cr, ms, inputrec, nullptr, enforcedRotation, imdSession, pull_work, 1, nrnb, wcycle,
-                 top, box, posWithPadding[Try], hist, &forceViewTry, force_vir, md, enerd, lambda, fr,
-                 runScheduleWork, vsite, mu_tot, t, nullptr, shellfc_flags, ddBalanceRegionHandler);
-        accumulatePotentialEnergies(enerd, lambda, inputrec->fepvals);
+        do_force(fplog,
+                 cr,
+                 ms,
+                 *inputrec,
+                 nullptr,
+                 enforcedRotation,
+                 imdSession,
+                 pull_work,
+                 1,
+                 nrnb,
+                 wcycle,
+                 top,
+                 box,
+                 posWithPadding[Try],
+                 hist,
+                 &forceViewTry,
+                 force_vir,
+                 &md,
+                 enerd,
+                 lambda,
+                 fr,
+                 runScheduleWork,
+                 vsite,
+                 mu_tot,
+                 t,
+                 nullptr,
+                 shellfc_flags,
+                 ddBalanceRegionHandler);
+        accumulatePotentialEnergies(enerd, lambda, inputrec->fepvals.get());
         if (gmx_debug_at)
         {
             pr_rvecs(debug, 0, "RELAX: force[Min]", as_rvec_array(force[Min].data()), homenr);
@@ -1135,14 +1235,27 @@ void relax_shell_flexcon(FILE*                         fplog,
         sf_dir = 0;
         if (nflexcon)
         {
-            init_adir(shfc, constr, inputrec, cr, dd_ac1, mdstep, md, end,
-                      shfc->x_old.arrayRefWithPadding(), x, posWithPadding[Try], force[Try],
-                      shfc->acc_dir, box, lambda, &dum);
+            init_adir(shfc,
+                      constr,
+                      inputrec,
+                      cr,
+                      dd_ac1,
+                      mdstep,
+                      md,
+                      end,
+                      shfc->x_old.arrayRefWithPadding(),
+                      x,
+                      posWithPadding[Try],
+                      force[Try],
+                      shfc->acc_dir,
+                      box,
+                      lambda,
+                      &dum);
 
             ArrayRef<const RVec> acc_dir = shfc->acc_dir;
             for (i = 0; i < end; i++)
             {
-                sf_dir += md->massT[i] * norm2(acc_dir[i]);
+                sf_dir += massT[i] * norm2(acc_dir[i]);
             }
         }
 
@@ -1210,11 +1323,17 @@ void relax_shell_flexcon(FILE*                         fplog,
         /* Note that the energies and virial are incorrect when not converged */
         if (fplog)
         {
-            fprintf(fplog, "step %s: EM did not converge in %d iterations, RMS force %6.2e\n",
-                    gmx_step_str(mdstep, sbuf), number_steps, df[Min]);
+            fprintf(fplog,
+                    "step %s: EM did not converge in %d iterations, RMS force %6.2e\n",
+                    gmx_step_str(mdstep, sbuf),
+                    number_steps,
+                    df[Min]);
         }
-        fprintf(stderr, "step %s: EM did not converge in %d iterations, RMS force %6.2e\n",
-                gmx_step_str(mdstep, sbuf), number_steps, df[Min]);
+        fprintf(stderr,
+                "step %s: EM did not converge in %d iterations, RMS force %6.2e\n",
+                gmx_step_str(mdstep, sbuf),
+                number_steps,
+                df[Min]);
     }
 
     /* Copy back the coordinates and the forces */
@@ -1227,9 +1346,11 @@ void done_shellfc(FILE* fplog, gmx_shellfc_t* shfc, int64_t numSteps)
     if (shfc && fplog && numSteps > 0)
     {
         double numStepsAsDouble = static_cast<double>(numSteps);
-        fprintf(fplog, "Fraction of iterations that converged:           %.2f %%\n",
+        fprintf(fplog,
+                "Fraction of iterations that converged:           %.2f %%\n",
                 (shfc->numConvergedIterations * 100.0) / numStepsAsDouble);
-        fprintf(fplog, "Average number of force evaluations per MD step: %.2f\n\n",
+        fprintf(fplog,
+                "Average number of force evaluations per MD step: %.2f\n\n",
                 shfc->numForceEvaluations / numStepsAsDouble);
     }
 
index f5145cfb8d36864a0a8e99ec48121bc597825ae4..b8a314679c3638fb3d0b5235b0721ce073c09ee6 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #include "gromacs/math/vectypes.h"
 #include "gromacs/timing/wallcycle.h"
 #include "gromacs/topology/atoms.h"
+#include "gromacs/utility/enumerationhelpers.h"
 
 class DDBalanceRegionHandler;
 struct gmx_enerdata_t;
@@ -84,7 +85,7 @@ class VirtualSitesHandler;
  * \returns a pointer to an initialized \c shellfc object.
  */
 gmx_shellfc_t* init_shell_flexcon(FILE*             fplog,
-                                  const gmx_mtop_t* mtop,
+                                  const gmx_mtop_t& mtop,
                                   int               nflexcon,
                                   int               nstcalcenergy,
                                   bool              usingDomainDecomposition,
@@ -110,12 +111,12 @@ void relax_shell_flexcon(FILE*                               log,
                          gmx::ArrayRefWithPadding<gmx::RVec> v,
                          const matrix                        box,
                          gmx::ArrayRef<real>                 lambda,
-                         history_t*                          hist,
+                         const history_t*                    hist,
                          gmx::ForceBuffersView*              f,
                          tensor                              force_vir,
-                         const t_mdatoms*                    md,
+                         const t_mdatoms&                    md,
                          t_nrnb*                             nrnb,
-                         gmx_wallcycle_t                     wcycle,
+                         gmx_wallcycle                     wcycle,
                          gmx_shellfc_t*                      shfc,
                          t_forcerec*                         fr,
                          gmx::MdrunScheduleWorkload*         runScheduleWork,
@@ -135,6 +136,6 @@ void done_shellfc(FILE* fplog, gmx_shellfc_t* shellfc, int64_t numSteps);
  * \param[in]  mtop  Molecular topology.
  * \returns Array holding the number of particles of a type
  */
-std::array<int, eptNR> countPtypes(FILE* fplog, const gmx_mtop_t* mtop);
+gmx::EnumerationArray<ParticleType, int> countPtypes(FILE* fplog, const gmx_mtop_t& mtop);
 
 #endif
index a29c252103b11cc5927c9f29891ac78aea22af63..34ee98a100c74efddea14093dee42f1c2b6cccd7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ void applyGlobalSimulationState(const SimulationInput&      simulationInput,
                                 t_inputrec*                 inputRecord,
                                 gmx_mtop_t*                 molecularTopology)
 {
-    *partialDeserializedTpr = read_tpx_state(simulationInput.tprFilename_.c_str(), inputRecord,
-                                             globalState, molecularTopology);
+    *partialDeserializedTpr = read_tpx_state(
+            simulationInput.tprFilename_.c_str(), inputRecord, globalState, molecularTopology);
 }
 
 void applyLocalState(const SimulationInput&         simulationInput,
@@ -64,13 +64,21 @@ void applyLocalState(const SimulationInput&         simulationInput,
                      t_state*                       state,
                      ObservablesHistory*            observablesHistory,
                      bool                           reproducibilityRequested,
-                     const MdModulesNotifier&       mdModulesNotifier,
+                     const MDModulesNotifiers&      mdModulesNotifiers,
                      gmx::ReadCheckpointDataHolder* modularSimulatorCheckpointData,
                      const bool                     useModularSimulator)
 {
-    load_checkpoint(simulationInput.cpiFilename_.c_str(), logfio, cr, dd_nc, inputRecord, state,
-                    observablesHistory, reproducibilityRequested, mdModulesNotifier,
-                    modularSimulatorCheckpointData, useModularSimulator);
+    load_checkpoint(simulationInput.cpiFilename_.c_str(),
+                    logfio,
+                    cr,
+                    dd_nc,
+                    inputRecord,
+                    state,
+                    observablesHistory,
+                    reproducibilityRequested,
+                    mdModulesNotifiers,
+                    modularSimulatorCheckpointData,
+                    useModularSimulator);
 }
 
 } // end namespace gmx
index 896018219c957fb3282a2fe6213591dce5302d03..9c7d225aa0acfa99f00880d717410cf166bd2d17 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/mdrun/simulationinputhandle.h"
 #include "gromacs/mdtypes/checkpointdata.h"
-#include "gromacs/utility/mdmodulenotification.h"
+#include "gromacs/utility/mdmodulesnotifiers.h"
 
 // Forward declarations for types from other modules that are opaque to the public API.
 // TODO: Document the sources of these symbols or import a (self-documenting) fwd header.
@@ -140,7 +140,7 @@ void                     applyGlobalTopology(const SimulationInput&, gmx_mtop_t*
  *       SimulationInput implementation.
  *
  * \todo Consider refactoring to decouple the checkpoint facility from its consumers
- *       (state, observablesHistory, mdModulesNotifier, and parts of ir).
+ *       (state, observablesHistory, mdModulesNotifiers, and parts of ir).
  *
  * \warning It is the caller’s responsibility to make sure that
  * preconditions are satisfied for the parameter objects.
@@ -157,7 +157,7 @@ void applyLocalState(const SimulationInput&         simulationInput,
                      t_state*                       state,
                      ObservablesHistory*            observablesHistory,
                      bool                           reproducibilityRequested,
-                     const MdModulesNotifier&       notifier,
+                     const MDModulesNotifiers&      notifiers,
                      gmx::ReadCheckpointDataHolder* modularSimulatorCheckpointData,
                      bool                           useModularSimulator);
 
index f1ed995d53f15bcc67a7af90d9f5243b4e95f99e..90b87f703d6b119a1ef4225180c44c8b5d1277f5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019-2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,7 +51,7 @@
 #include "gromacs/mdtypes/state.h"
 #include "gromacs/modularsimulator/modularsimulator.h"
 #include "gromacs/topology/topology.h"
-#include "gromacs/utility/mdmodulenotification.h"
+#include "gromacs/utility/mdmodulesnotifiers.h"
 
 #include "legacysimulator.h"
 #include "membedholder.h"
@@ -128,39 +128,77 @@ std::unique_ptr<ISimulator> SimulatorBuilder::build(bool useModularSimulator)
     {
         // NOLINTNEXTLINE(modernize-make-unique): make_unique does not work with private constructor
         return std::unique_ptr<ModularSimulator>(new ModularSimulator(
-                std::make_unique<LegacySimulatorData>(
-                        simulatorEnv_->fplog_, simulatorEnv_->commRec_, simulatorEnv_->multisimCommRec_,
-                        simulatorEnv_->logger_, legacyInput_->numFile, legacyInput_->filenames,
-                        simulatorEnv_->outputEnv_, simulatorConfig_->mdrunOptions_,
-                        simulatorConfig_->startingBehavior_, constraintsParam_->vsite,
-                        constraintsParam_->constr, constraintsParam_->enforcedRotation,
-                        boxDeformation_->deform, simulatorModules_->outputProvider,
-                        simulatorModules_->mdModulesNotifier, legacyInput_->inputrec,
-                        interactiveMD_->imdSession, centerOfMassPulling_->pull_work, ionSwapping_->ionSwap,
-                        topologyData_->top_global, simulatorStateData_->globalState_p,
-                        simulatorStateData_->observablesHistory_p, topologyData_->mdAtoms,
-                        profiling_->nrnb, profiling_->wallCycle, legacyInput_->forceRec,
-                        simulatorStateData_->enerdata_p, simulatorStateData_->ekindata_p,
-                        simulatorConfig_->runScheduleWork_, *replicaExchangeParameters_,
-                        membedHolder_->membed(), profiling_->walltimeAccounting,
-                        std::move(stopHandlerBuilder_), simulatorConfig_->mdrunOptions_.rerun),
+                std::make_unique<LegacySimulatorData>(simulatorEnv_->fplog_,
+                                                      simulatorEnv_->commRec_,
+                                                      simulatorEnv_->multisimCommRec_,
+                                                      simulatorEnv_->logger_,
+                                                      legacyInput_->numFile,
+                                                      legacyInput_->filenames,
+                                                      simulatorEnv_->outputEnv_,
+                                                      simulatorConfig_->mdrunOptions_,
+                                                      simulatorConfig_->startingBehavior_,
+                                                      constraintsParam_->vsite,
+                                                      constraintsParam_->constr,
+                                                      constraintsParam_->enforcedRotation,
+                                                      boxDeformation_->deform,
+                                                      simulatorModules_->outputProvider,
+                                                      simulatorModules_->mdModulesNotifiers,
+                                                      legacyInput_->inputrec,
+                                                      interactiveMD_->imdSession,
+                                                      centerOfMassPulling_->pull_work,
+                                                      ionSwapping_->ionSwap,
+                                                      topologyData_->top_global,
+                                                      simulatorStateData_->globalState_p,
+                                                      simulatorStateData_->observablesHistory_p,
+                                                      topologyData_->mdAtoms,
+                                                      profiling_->nrnb,
+                                                      profiling_->wallCycle,
+                                                      legacyInput_->forceRec,
+                                                      simulatorStateData_->enerdata_p,
+                                                      simulatorStateData_->ekindata_p,
+                                                      simulatorConfig_->runScheduleWork_,
+                                                      *replicaExchangeParameters_,
+                                                      membedHolder_->membed(),
+                                                      profiling_->walltimeAccounting,
+                                                      std::move(stopHandlerBuilder_),
+                                                      simulatorConfig_->mdrunOptions_.rerun),
                 std::move(modularSimulatorCheckpointData_)));
     }
     // NOLINTNEXTLINE(modernize-make-unique): make_unique does not work with private constructor
-    return std::unique_ptr<LegacySimulator>(new LegacySimulator(
-            simulatorEnv_->fplog_, simulatorEnv_->commRec_, simulatorEnv_->multisimCommRec_,
-            simulatorEnv_->logger_, legacyInput_->numFile, legacyInput_->filenames,
-            simulatorEnv_->outputEnv_, simulatorConfig_->mdrunOptions_,
-            simulatorConfig_->startingBehavior_, constraintsParam_->vsite,
-            constraintsParam_->constr, constraintsParam_->enforcedRotation, boxDeformation_->deform,
-            simulatorModules_->outputProvider, simulatorModules_->mdModulesNotifier,
-            legacyInput_->inputrec, interactiveMD_->imdSession, centerOfMassPulling_->pull_work,
-            ionSwapping_->ionSwap, topologyData_->top_global, simulatorStateData_->globalState_p,
-            simulatorStateData_->observablesHistory_p, topologyData_->mdAtoms, profiling_->nrnb,
-            profiling_->wallCycle, legacyInput_->forceRec, simulatorStateData_->enerdata_p,
-            simulatorStateData_->ekindata_p, simulatorConfig_->runScheduleWork_,
-            *replicaExchangeParameters_, membedHolder_->membed(), profiling_->walltimeAccounting,
-            std::move(stopHandlerBuilder_), simulatorConfig_->mdrunOptions_.rerun));
+    return std::unique_ptr<LegacySimulator>(new LegacySimulator(simulatorEnv_->fplog_,
+                                                                simulatorEnv_->commRec_,
+                                                                simulatorEnv_->multisimCommRec_,
+                                                                simulatorEnv_->logger_,
+                                                                legacyInput_->numFile,
+                                                                legacyInput_->filenames,
+                                                                simulatorEnv_->outputEnv_,
+                                                                simulatorConfig_->mdrunOptions_,
+                                                                simulatorConfig_->startingBehavior_,
+                                                                constraintsParam_->vsite,
+                                                                constraintsParam_->constr,
+                                                                constraintsParam_->enforcedRotation,
+                                                                boxDeformation_->deform,
+                                                                simulatorModules_->outputProvider,
+                                                                simulatorModules_->mdModulesNotifiers,
+                                                                legacyInput_->inputrec,
+                                                                interactiveMD_->imdSession,
+                                                                centerOfMassPulling_->pull_work,
+                                                                ionSwapping_->ionSwap,
+                                                                topologyData_->top_global,
+                                                                simulatorStateData_->globalState_p,
+                                                                simulatorStateData_->observablesHistory_p,
+                                                                topologyData_->mdAtoms,
+                                                                profiling_->nrnb,
+                                                                profiling_->wallCycle,
+                                                                legacyInput_->forceRec,
+                                                                simulatorStateData_->enerdata_p,
+                                                                simulatorStateData_->ekindata_p,
+                                                                simulatorConfig_->runScheduleWork_,
+                                                                *replicaExchangeParameters_,
+                                                                membedHolder_->membed(),
+                                                                profiling_->walltimeAccounting,
+                                                                std::move(stopHandlerBuilder_),
+                                                                simulatorConfig_->mdrunOptions_.rerun));
 }
 
 void SimulatorBuilder::add(MembedHolder&& membedHolder)
index 761d3af220ebee7aff52ec1f26d14837a992eefb..225072407856981edbf1663ccdcff41a3b7334b2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019-2020, by the GROMACS development team, led by
+ * Copyright (c) 2019-2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +45,7 @@
 
 
 class energyhistory_t;
-struct gmx_ekindata_t;
+class gmx_ekindata_t;
 struct gmx_enerdata_t;
 struct gmx_enfrot;
 struct gmx_mtop_t;
@@ -75,7 +75,7 @@ class MdrunScheduleWorkload;
 class MembedHolder;
 class MDAtoms;
 class MDLogger;
-struct MdModulesNotifier;
+struct MDModulesNotifiers;
 struct MdrunOptions;
 class ReadCheckpointDataHolder;
 enum class StartingBehavior;
@@ -263,14 +263,14 @@ public:
 class SimulatorModules
 {
 public:
-    SimulatorModules(IMDOutputProvider* mdOutputProvider, const MdModulesNotifier& notifier) :
+    SimulatorModules(IMDOutputProvider* mdOutputProvider, const MDModulesNotifiers& notifiers) :
         outputProvider(mdOutputProvider),
-        mdModulesNotifier(notifier)
+        mdModulesNotifiers(notifiers)
     {
     }
 
-    IMDOutputProvider*       outputProvider;
-    const MdModulesNotifier& mdModulesNotifier;
+    IMDOutputProvider*        outputProvider;
+    const MDModulesNotifiers& mdModulesNotifiers;
 };
 
 class CenterOfMassPulling
@@ -305,14 +305,14 @@ class TopologyData
 {
 public:
     //! Build collection from simulation data.
-    TopologyData(gmx_mtop_t* globalTopology, MDAtoms* mdAtoms) :
+    TopologyData(const gmx_mtop_t& globalTopology, MDAtoms* mdAtoms) :
         top_global(globalTopology),
         mdAtoms(mdAtoms)
     {
     }
 
     //! Handle to global simulation topology.
-    gmx_mtop_t* top_global;
+    const gmx_mtop_t& top_global;
     //! Handle to information about MDAtoms.
     MDAtoms* mdAtoms;
 };
index 7536de08ebf5c8a641f6f670309453d292ec4f64..3b83b4b89e70edc1364454c0b6d79450bee4987f 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,13 +144,13 @@ static real reactionFieldExclusionCorrection(gmx::ArrayRef<const gmx::RVec> x,
     for (int i = beginAtom; i < mdatoms.homenr; i++)
     {
         const real qi = mdatoms.chargeA[i];
-        energy -= 0.5 * qi * qi * ic.c_rf;
+        energy -= 0.5 * qi * qi * ic.reactionFieldShift;
 
         for (int j = i + 1; j < mdatoms.homenr; j++)
         {
             const real qj  = mdatoms.chargeA[j];
             const real rsq = distance2(x[i], x[j]);
-            energy += qi * qj * (ic.k_rf * rsq - ic.c_rf);
+            energy += qi * qj * (ic.reactionFieldCoefficient * rsq - ic.reactionFieldShift);
         }
     }
 
@@ -163,9 +163,10 @@ namespace gmx
 // TODO: Convert to use the nbnxm kernels by putting the system and the teset molecule on two separate search grids
 void LegacySimulator::do_tpi()
 {
-    GMX_RELEASE_ASSERT(gmx_omp_nthreads_get(emntDefault) == 1, "TPI does not support OpenMP");
+    GMX_RELEASE_ASSERT(gmx_omp_nthreads_get(ModuleMultiThread::Default) == 1,
+                       "TPI does not support OpenMP");
 
-    gmx_localtop_t    top(top_global->ffparams);
+    gmx_localtop_t    top(top_global.ffparams);
     gmx::ForceBuffers f;
     real              lambda, t, temp, beta, drmax, epot;
     double            embU, sum_embU, *sum_UgembU, V, V_all, VembU_all;
@@ -191,7 +192,7 @@ void LegacySimulator::do_tpi()
     double            invbinw, *bin, refvolshift, logV, bUlogV;
     gmx_bool          bEnergyOutOfBounds;
     const char*       tpid_leg[2] = { "direct", "reweighted" };
-    auto              mdatoms     = mdAtoms->mdatoms();
+    auto*             mdatoms     = mdAtoms->mdatoms();
 
     GMX_UNUSED_VALUE(outputProvider);
 
@@ -221,11 +222,11 @@ void LegacySimulator::do_tpi()
 
     nnodes = cr->nnodes;
 
-    gmx_mtop_generate_local_top(*top_global, &top, inputrec->efep != efepNO);
+    gmx_mtop_generate_local_top(top_global, &top, inputrec->efep != FreeEnergyPerturbationType::No);
 
-    const SimulationGroups* groups = &top_global->groups;
+    const SimulationGroups* groups = &top_global.groups;
 
-    bCavity = (inputrec->eI == eiTPIC);
+    bCavity = (inputrec->eI == IntegrationAlgorithm::TPIC);
     if (bCavity)
     {
         ptr = getenv("GMX_TPIC_MASSES");
@@ -277,7 +278,7 @@ void LegacySimulator::do_tpi()
         }
         fprintf(fplog, "\n  The temperature for test particle insertion is %.3f K\n\n", temp);
     }
-    beta = 1.0 / (BOLTZ * temp);
+    beta = 1.0 / (gmx::c_boltz * temp);
 
     /* Number of insertions per frame */
     nsteps = inputrec->nsteps;
@@ -298,20 +299,20 @@ void LegacySimulator::do_tpi()
         sscanf(dump_pdb, "%20lf", &dump_ener);
     }
 
-    atoms2md(top_global, inputrec, -1, {}, top_global->natoms, mdAtoms);
+    atoms2md(top_global, *inputrec, -1, {}, top_global.natoms, mdAtoms);
     update_mdatoms(mdatoms, inputrec->fepvals->init_lambda);
 
-    f.resize(top_global->natoms);
+    f.resize(top_global.natoms);
 
     /* Print to log file  */
     walltime_accounting_start_time(walltime_accounting);
-    wallcycle_start(wcycle, ewcRUN);
+    wallcycle_start(wcycle, WallCycleCounter::Run);
     print_start(fplog, cr, walltime_accounting, "Test Particle Insertion");
 
     /* The last charge group is the group to be inserted */
-    const t_atoms& atomsToInsert = top_global->moltype[top_global->molblock.back().type].atoms;
-    a_tp0                        = top_global->natoms - atomsToInsert.nr;
-    a_tp1                        = top_global->natoms;
+    const t_atoms& atomsToInsert = top_global.moltype[top_global.molblock.back().type].atoms;
+    a_tp0                        = top_global.natoms - atomsToInsert.nr;
+    a_tp1                        = top_global.natoms;
     if (debug)
     {
         fprintf(debug, "TPI atoms %d-%d\n", a_tp0, a_tp1);
@@ -321,7 +322,7 @@ void LegacySimulator::do_tpi()
 
     if (EEL_PME(fr->ic->eeltype))
     {
-        gmx_pme_reinit_atoms(fr->pmedata, a_tp0, nullptr, nullptr);
+        gmx_pme_reinit_atoms(fr->pmedata, a_tp0, {}, {});
     }
 
     /* With reacion-field we have distance dependent potentials
@@ -340,7 +341,7 @@ void LegacySimulator::do_tpi()
 
     snew(x_mol, a_tp1 - a_tp0);
 
-    bDispCorr = (inputrec->eDispCorr != edispcNO);
+    bDispCorr = (inputrec->eDispCorr != DispersionCorrectionType::No);
     bCharge   = FALSE;
     for (i = a_tp0; i < a_tp1; i++)
     {
@@ -386,10 +387,11 @@ void LegacySimulator::do_tpi()
 
     if (fplog)
     {
-        fprintf(fplog, "\nWill insert %d atoms %s partial charges\n", a_tp1 - a_tp0,
-                bCharge ? "with" : "without");
+        fprintf(fplog, "\nWill insert %d atoms %s partial charges\n", a_tp1 - a_tp0, bCharge ? "with" : "without");
 
-        fprintf(fplog, "\nWill insert %" PRId64 " times in each frame of %s\n", nsteps,
+        fprintf(fplog,
+                "\nWill insert %" PRId64 " times in each frame of %s\n",
+                nsteps,
                 opt2fn("-rerun", nfile, fnm));
     }
 
@@ -404,14 +406,16 @@ void LegacySimulator::do_tpi()
                 gmx_fatal(FARGS,
                           "Re-using the neighborlist %d times for insertions of a single atom in a "
                           "sphere of radius %f does not make sense",
-                          inputrec->nstlist, drmax);
+                          inputrec->nstlist,
+                          drmax);
             }
             if (fplog)
             {
                 fprintf(fplog,
                         "Will use the same neighborlist for %d insertions in a sphere of radius "
                         "%f\n",
-                        inputrec->nstlist, drmax);
+                        inputrec->nstlist,
+                        drmax);
             }
         }
     }
@@ -431,8 +435,12 @@ void LegacySimulator::do_tpi()
      * inserted atoms located in the center of the sphere, so we need
      * a buffer of size of the sphere and molecule radius.
      */
-    inputrec->rlist = maxCutoff + 2 * inputrec->rtpi + 2 * molRadius;
-    fr->rlist       = inputrec->rlist;
+    {
+        // TODO: Avoid changing inputrec (#3854)
+        auto* nonConstInputrec  = const_cast<t_inputrec*>(inputrec);
+        nonConstInputrec->rlist = maxCutoff + 2 * inputrec->rtpi + 2 * molRadius;
+    }
+    fr->rlist = inputrec->rlist;
     fr->nbv->changePairlistRadii(inputrec->rlist, inputrec->rlist);
 
     ngid   = groups->groups[SimulationAtomGroupType::EnergyOutput].size();
@@ -475,8 +483,11 @@ void LegacySimulator::do_tpi()
 
     if (MASTER(cr))
     {
-        fp_tpi = xvgropen(opt2fn("-tpi", nfile, fnm), "TPI energies", "Time (ps)",
-                          "(kJ mol\\S-1\\N) / (nm\\S3\\N)", oenv);
+        fp_tpi = xvgropen(opt2fn("-tpi", nfile, fnm),
+                          "TPI energies",
+                          "Time (ps)",
+                          "(kJ mol\\S-1\\N) / (nm\\S3\\N)",
+                          oenv);
         xvgr_subtitle(fp_tpi, "f. are averages over one frame", oenv);
         snew(leg, 4 + nener);
         e = 0;
@@ -492,7 +503,8 @@ void LegacySimulator::do_tpi()
         leg[e++] = gmx_strdup(str);
         for (i = 0; i < ngid; i++)
         {
-            sprintf(str, "f. <U\\sVdW %s\\Ne\\S-\\betaU\\N>",
+            sprintf(str,
+                    "f. <U\\sVdW %s\\Ne\\S-\\betaU\\N>",
                     *(groups->groupNames[groups->groups[SimulationAtomGroupType::EnergyOutput][i]]));
             leg[e++] = gmx_strdup(str);
         }
@@ -505,7 +517,8 @@ void LegacySimulator::do_tpi()
         {
             for (i = 0; i < ngid; i++)
             {
-                sprintf(str, "f. <U\\sCoul %s\\Ne\\S-\\betaU\\N>",
+                sprintf(str,
+                        "f. <U\\sCoul %s\\Ne\\S-\\betaU\\N>",
                         *(groups->groupNames[groups->groups[SimulationAtomGroupType::EnergyOutput][i]]));
                 leg[e++] = gmx_strdup(str);
             }
@@ -547,16 +560,19 @@ void LegacySimulator::do_tpi()
                   "Number of atoms in trajectory (%d)%s "
                   "is not equal the number in the run input file (%d) "
                   "minus the number of atoms to insert (%d)\n",
-                  rerun_fr.natoms, bCavity ? " minus one" : "", mdatoms->nr, a_tp1 - a_tp0);
+                  rerun_fr.natoms,
+                  bCavity ? " minus one" : "",
+                  mdatoms->nr,
+                  a_tp1 - a_tp0);
     }
 
     refvolshift = log(det(rerun_fr.box));
 
     switch (inputrec->eI)
     {
-        case eiTPI: stepblocksize = inputrec->nstlist; break;
-        case eiTPIC: stepblocksize = 1; break;
-        default: gmx_fatal(FARGS, "Unknown integrator %s", ei_names[inputrec->eI]);
+        case IntegrationAlgorithm::TPI: stepblocksize = inputrec->nstlist; break;
+        case IntegrationAlgorithm::TPIC: stepblocksize = 1; break;
+        default: gmx_fatal(FARGS, "Unknown integrator %s", enumValueToString(inputrec->eI));
     }
 
     while (bNotLastFrame)
@@ -602,8 +618,8 @@ void LegacySimulator::do_tpi()
         /* Put all atoms except for the inserted ones on the grid */
         rvec vzero       = { 0, 0, 0 };
         rvec boxDiagonal = { box[XX][XX], box[YY][YY], box[ZZ][ZZ] };
-        nbnxn_put_on_grid(fr->nbv.get(), box, 0, vzero, boxDiagonal, nullptr, { 0, a_tp0 }, -1,
-                          fr->cginfo, x, 0, nullptr);
+        nbnxn_put_on_grid(
+                fr->nbv.get(), box, 0, vzero, boxDiagonal, nullptr, { 0, a_tp0 }, -1, fr->cginfo, x, 0, nullptr);
 
         step = cr->nodeid * stepblocksize;
         while (step < nsteps)
@@ -674,8 +690,8 @@ void LegacySimulator::do_tpi()
                 }
 
                 /* Put the inserted molecule on it's own search grid */
-                nbnxn_put_on_grid(fr->nbv.get(), box, 1, x_init, x_init, nullptr, { a_tp0, a_tp1 },
-                                  -1, fr->cginfo, x, 0, nullptr);
+                nbnxn_put_on_grid(
+                        fr->nbv.get(), box, 1, x_init, x_init, nullptr, { a_tp0, a_tp1 }, -1, fr->cginfo, x, 0, nullptr);
 
                 /* TODO: Avoid updating all atoms at every bNS step */
                 fr->nbv->setAtomProperties(gmx::constArrayRefFromArray(mdatoms->typeA, mdatoms->nr),
@@ -725,8 +741,7 @@ void LegacySimulator::do_tpi()
                 real angleX = 2 * M_PI * dist(rng);
                 real angleY = 2 * M_PI * dist(rng);
                 real angleZ = 2 * M_PI * dist(rng);
-                rotate_conf(a_tp1 - a_tp0, state_global->x.rvec_array() + a_tp0, nullptr, angleX,
-                            angleY, angleZ);
+                rotate_conf(a_tp1 - a_tp0, state_global->x.rvec_array() + a_tp0, nullptr, angleX, angleY, angleZ);
                 /* Shift to the insertion location */
                 for (i = a_tp0; i < a_tp1; i++)
                 {
@@ -735,7 +750,7 @@ void LegacySimulator::do_tpi()
             }
 
             /* Note: NonLocal refers to the inserted molecule */
-            fr->nbv->convertCoordinates(AtomLocality::NonLocal, false, x);
+            fr->nbv->convertCoordinates(AtomLocality::NonLocal, x);
 
             /* Clear some matrix variables  */
             clear_mat(force_vir);
@@ -753,10 +768,32 @@ void LegacySimulator::do_tpi()
             // might raise, then restore the old behaviour.
             std::fenv_t floatingPointEnvironment;
             std::feholdexcept(&floatingPointEnvironment);
-            do_force(fplog, cr, ms, inputrec, nullptr, nullptr, imdSession, pull_work, step, nrnb,
-                     wcycle, &top, state_global->box, state_global->x.arrayRefWithPadding(),
-                     &state_global->hist, &f.view(), force_vir, mdatoms, enerd,
-                     state_global->lambda, fr, runScheduleWork, nullptr, mu_tot, t, nullptr,
+            do_force(fplog,
+                     cr,
+                     ms,
+                     *inputrec,
+                     nullptr,
+                     nullptr,
+                     imdSession,
+                     pull_work,
+                     step,
+                     nrnb,
+                     wcycle,
+                     &top,
+                     state_global->box,
+                     state_global->x.arrayRefWithPadding(),
+                     &state_global->hist,
+                     &f.view(),
+                     force_vir,
+                     mdatoms,
+                     enerd,
+                     state_global->lambda,
+                     fr,
+                     runScheduleWork,
+                     nullptr,
+                     mu_tot,
+                     t,
+                     nullptr,
                      GMX_FORCE_NONBONDED | GMX_FORCE_ENERGY | (bStateChanged ? GMX_FORCE_STATECHANGED : 0),
                      DDBalanceRegionHandler(nullptr));
             std::feclearexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
@@ -811,8 +848,10 @@ void LegacySimulator::do_tpi()
                 if (debug)
                 {
                     fprintf(debug,
-                            "\n  time %.3f, step %d: non-finite energy %f, using exp(-bU)=0\n", t,
-                            static_cast<int>(step), epot);
+                            "\n  time %.3f, step %d: non-finite energy %f, using exp(-bU)=0\n",
+                            t,
+                            static_cast<int>(step),
+                            epot);
                 }
                 embU = 0;
             }
@@ -824,18 +863,22 @@ void LegacySimulator::do_tpi()
                 /* Determine the weighted energy contributions of each energy group */
                 e = 0;
                 sum_UgembU[e++] += epot * embU;
-                if (fr->bBHAM)
+                if (fr->haveBuckingham)
                 {
                     for (i = 0; i < ngid; i++)
                     {
-                        sum_UgembU[e++] += enerd->grpp.ener[egBHAMSR][GID(i, gid_tp, ngid)] * embU;
+                        sum_UgembU[e++] +=
+                                enerd->grpp.energyGroupPairTerms[NonBondedEnergyTerms::BuckinghamSR][GID(i, gid_tp, ngid)]
+                                * embU;
                     }
                 }
                 else
                 {
                     for (i = 0; i < ngid; i++)
                     {
-                        sum_UgembU[e++] += enerd->grpp.ener[egLJSR][GID(i, gid_tp, ngid)] * embU;
+                        sum_UgembU[e++] +=
+                                enerd->grpp.energyGroupPairTerms[NonBondedEnergyTerms::LJSR][GID(i, gid_tp, ngid)]
+                                * embU;
                     }
                 }
                 if (bDispCorr)
@@ -846,7 +889,9 @@ void LegacySimulator::do_tpi()
                 {
                     for (i = 0; i < ngid; i++)
                     {
-                        sum_UgembU[e++] += enerd->grpp.ener[egCOULSR][GID(i, gid_tp, ngid)] * embU;
+                        sum_UgembU[e++] +=
+                                enerd->grpp.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR][GID(i, gid_tp, ngid)]
+                                * embU;
                     }
                     if (bRFExcl)
                     {
@@ -879,16 +924,26 @@ void LegacySimulator::do_tpi()
 
             if (debug)
             {
-                fprintf(debug, "TPI %7d %12.5e %12.5f %12.5f %12.5f\n", static_cast<int>(step),
-                        epot, x_tp[XX], x_tp[YY], x_tp[ZZ]);
+                fprintf(debug,
+                        "TPI %7d %12.5e %12.5f %12.5f %12.5f\n",
+                        static_cast<int>(step),
+                        epot,
+                        x_tp[XX],
+                        x_tp[YY],
+                        x_tp[ZZ]);
             }
 
             if (dump_pdb && epot <= dump_ener)
             {
                 sprintf(str, "t%g_step%d.pdb", t, static_cast<int>(step));
                 sprintf(str2, "t: %f step %d ener: %f", t, static_cast<int>(step), epot);
-                write_sto_conf_mtop(str, str2, top_global, state_global->x.rvec_array(),
-                                    state_global->v.rvec_array(), inputrec->pbcType, state_global->box);
+                write_sto_conf_mtop(str,
+                                    str2,
+                                    top_global,
+                                    state_global->x.rvec_array(),
+                                    state_global->v.rvec_array(),
+                                    inputrec->pbcType,
+                                    state_global->box);
             }
 
             step++;
@@ -914,13 +969,19 @@ void LegacySimulator::do_tpi()
         {
             if (mdrunOptions.verbose || frame % 10 == 0 || frame < 10)
             {
-                fprintf(stderr, "mu %10.3e <mu> %10.3e\n", -log(sum_embU / nsteps) / beta,
+                fprintf(stderr,
+                        "mu %10.3e <mu> %10.3e\n",
+                        -log(sum_embU / nsteps) / beta,
                         -log(VembU_all / V_all) / beta);
             }
 
-            fprintf(fp_tpi, "%10.3f %12.5e %12.5e %12.5e %12.5e", t,
+            fprintf(fp_tpi,
+                    "%10.3f %12.5e %12.5e %12.5e %12.5e",
+                    t,
                     VembU_all == 0 ? 20 / beta : -log(VembU_all / V_all) / beta,
-                    sum_embU == 0 ? 20 / beta : -log(sum_embU / nsteps) / beta, sum_embU / nsteps, V);
+                    sum_embU == 0 ? 20 / beta : -log(sum_embU / nsteps) / beta,
+                    sum_embU / nsteps,
+                    V);
             for (e = 0; e < nener; e++)
             {
                 fprintf(fp_tpi, " %12.5e", sum_UgembU[e] / nsteps);
@@ -966,16 +1027,18 @@ void LegacySimulator::do_tpi()
     }
     if (MASTER(cr))
     {
-        fp_tpi = xvgropen(opt2fn("-tpid", nfile, fnm), "TPI energy distribution",
-                          "\\betaU - log(V/<V>)", "count", oenv);
+        fp_tpi = xvgropen(opt2fn("-tpid", nfile, fnm),
+                          "TPI energy distribution",
+                          "\\betaU - log(V/<V>)",
+                          "count",
+                          oenv);
         sprintf(str, "number \\betaU > %g: %9.3e", bU_bin_limit, bin[0]);
         xvgr_subtitle(fp_tpi, str, oenv);
         xvgr_legend(fp_tpi, 2, tpid_leg, oenv);
         for (i = nbin - 1; i > 0; i--)
         {
             bUlogV = -i / invbinw + bU_logV_bin_limit - refvolshift + log(V_all / frame);
-            fprintf(fp_tpi, "%6.2f %10d %12.5e\n", bUlogV, roundToInt(bin[i]),
-                    bin[i] * exp(-bUlogV) * V_all / VembU_all);
+            fprintf(fp_tpi, "%6.2f %10d %12.5e\n", bUlogV, roundToInt(bin[i]), bin[i] * exp(-bUlogV) * V_all / VembU_all);
         }
         xvgrclose(fp_tpi);
     }
index b1d76c52792e4a3fd635c99a483e0425e2f8fc4b..7ca19227bc37f2f5fad8741ccdec19bb47acf115 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2015,2016,2019, by the GROMACS development team, led by
+# Copyright (c) 2015,2016,2019,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -32,6 +32,7 @@
 # To help us fund GROMACS development, we humbly ask that you cite
 # the research papers on the package. Check out http://www.gromacs.org.
 
+add_library(mdrunutility INTERFACE)
 gmx_add_libgromacs_sources(
     handlerestart.cpp
     logging.cpp
@@ -40,6 +41,38 @@ gmx_add_libgromacs_sources(
     threadaffinity.cpp
     )
 
+# Source files have the following private module dependencies.
+target_link_libraries(mdrunutility PRIVATE
+#                      gmxlib
+#                      math
+#                      mdtypes
+#                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(mdrunutility PUBLIC
+target_include_directories(mdrunutility INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(mdrunutility PUBLIC
+target_link_libraries(mdrunutility INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when mdrunutility is an OBJECT target
+#target_link_libraries(mdrunutility PUBLIC legacy_api)
+#target_link_libraries(mdrunutility PRIVATE common)
+
+# Module dependencies
+# mdrunutility interfaces convey transitive dependence on these modules.
+#target_link_libraries(mdrunutility PUBLIC
+target_link_libraries(mdrunutility INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(mdrunutility PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(mdrunutility PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index 6c6804f1bbf9181d02ae91b2d46c68aa10a34b65..68db1fbfd7316e0b435bcc0c19ad503c82f6ef39 100644 (file)
@@ -188,7 +188,8 @@ gmx_bool exist_output_file(const char* fnm_cp, int nfile, const t_filenm fnm[])
             "part), or instruct mdrun to write new output files with mdrun -noappend. In "
             "the last case, you will not be able to use appending in future for this "
             "simulation.",
-            numFilesMissing, outputfiles.size());
+            numFilesMissing,
+            outputfiles.size());
     GMX_THROW(InconsistentInputError(stream.toString()));
 }
 
@@ -295,7 +296,8 @@ StartingBehaviorHandler chooseStartingBehavior(const AppendingBehavior appending
     GMX_RELEASE_ASSERT(Path::extensionMatches(logFilename, ftp2ext(efLOG)),
                        formatString("The checkpoint file or its reading is broken, the first "
                                     "output file '%s' must be a log file with extension '%s'",
-                                    logFilename, ftp2ext(efLOG))
+                                    logFilename,
+                                    ftp2ext(efLOG))
                                .c_str());
 
     if (appendingBehavior != AppendingBehavior::NoAppending)
@@ -353,7 +355,8 @@ StartingBehaviorHandler chooseStartingBehavior(const AppendingBehavior appending
                         "Cannot restart with appending because the previous simulation part used "
                         "%s precision which does not match the %s precision used by this build "
                         "of GROMACS. Either use matching precision or use mdrun -noappend.",
-                        precisionToString(headerContents.double_prec), precisionToString(GMX_DOUBLE))));
+                        precisionToString(headerContents.double_prec),
+                        precisionToString(GMX_DOUBLE))));
             }
         }
         // If the previous log filename had a part number, then we
@@ -401,7 +404,8 @@ void checkOutputFile(t_fileio* fileToCheck, const gmx_file_position_t& outputfil
                     "Can't read %d bytes of '%s' to compute checksum. The file "
                     "has been replaced or its contents have been modified. Cannot "
                     "do appending because of this condition.",
-                    outputfile.checksumSize, outputfile.filename);
+                    outputfile.checksumSize,
+                    outputfile.filename);
             GMX_THROW(InconsistentInputError(message));
         }
     }
@@ -543,8 +547,8 @@ void StartingBehaviorHandler::ensureMultiSimBehaviorsMatch(const gmx_multisim_t*
 
     auto startingBehaviors = gatherIntFromMultiSimulation(ms, static_cast<int>(startingBehavior));
     bool identicalStartingBehaviors =
-            (std::adjacent_find(std::begin(startingBehaviors), std::end(startingBehaviors),
-                                std::not_equal_to<>())
+            (std::adjacent_find(
+                     std::begin(startingBehaviors), std::end(startingBehaviors), std::not_equal_to<>())
              == std::end(startingBehaviors));
 
     const EnumerationArray<StartingBehavior, std::string> behaviorStrings = {
@@ -569,8 +573,8 @@ simulations wanted the following respective behaviors:
         for (index simIndex = 0; simIndex != ssize(startingBehaviors); ++simIndex)
         {
             auto behavior = static_cast<StartingBehavior>(startingBehaviors[simIndex]);
-            message += formatString("  Simulation %6zd: %s\n", simIndex,
-                                    behaviorStrings[behavior].c_str());
+            message += formatString(
+                    "  Simulation %6zd: %s\n", simIndex, behaviorStrings[behavior].c_str());
         }
         GMX_THROW(InconsistentInputError(message));
     }
@@ -585,9 +589,10 @@ simulations wanted the following respective behaviors:
     // describes the same simulation part. If those don't match, then
     // the simulation cannot proceed.
     auto simulationParts = gatherIntFromMultiSimulation(ms, headerContents->simulation_part);
-    bool identicalSimulationParts = (std::adjacent_find(std::begin(simulationParts),
-                                                        std::end(simulationParts), std::not_equal_to<>())
-                                     == std::end(simulationParts));
+    bool identicalSimulationParts =
+            (std::adjacent_find(
+                     std::begin(simulationParts), std::end(simulationParts), std::not_equal_to<>())
+             == std::end(simulationParts));
 
     if (!identicalSimulationParts)
     {
index 70aba55b948f4cfa45462e09ab322756c5385a27..caf38d7cceb63bf20f33bea04ad641fb04114f07 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +84,8 @@ std::unique_ptr<gmx_multisim_t> buildMultiSimulation(MPI_Comm
     {
         auto message = gmx::formatString(
                 "The number of ranks (%d) is not a multiple of the number of simulations (%td)",
-                numRanks, multidirs.ssize());
+                numRanks,
+                multidirs.ssize());
         GMX_THROW(gmx::InconsistentInputError(message));
     }
 
@@ -94,8 +95,11 @@ std::unique_ptr<gmx_multisim_t> buildMultiSimulation(MPI_Comm
 
     if (debug)
     {
-        fprintf(debug, "We have %td simulations, %d ranks per simulation, local simulation is %d\n",
-                multidirs.ssize(), numRanksPerSimulation, rankWithinWorldComm / numRanksPerSimulation);
+        fprintf(debug,
+                "We have %td simulations, %d ranks per simulation, local simulation is %d\n",
+                multidirs.ssize(),
+                numRanksPerSimulation,
+                rankWithinWorldComm / numRanksPerSimulation);
     }
 
     int numSimulations = multidirs.size();
@@ -165,46 +169,14 @@ gmx_multisim_t::~gmx_multisim_t()
 #if GMX_MPI
 static void gmx_sumd_comm(int nr, double r[], MPI_Comm mpi_comm)
 {
-#    if MPI_IN_PLACE_EXISTS
     MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_DOUBLE, MPI_SUM, mpi_comm);
-#    else
-    /* this function is only used in code that is not performance critical,
-       (during setup, when comm_rec is not the appropriate communication
-       structure), so this isn't as bad as it looks. */
-    double* buf;
-    int     i;
-
-    snew(buf, nr);
-    MPI_Allreduce(r, buf, nr, MPI_DOUBLE, MPI_SUM, mpi_comm);
-    for (i = 0; i < nr; i++)
-    {
-        r[i] = buf[i];
-    }
-    sfree(buf);
-#    endif
 }
 #endif
 
 #if GMX_MPI
 static void gmx_sumf_comm(int nr, float r[], MPI_Comm mpi_comm)
 {
-#    if MPI_IN_PLACE_EXISTS
     MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_FLOAT, MPI_SUM, mpi_comm);
-#    else
-    /* this function is only used in code that is not performance critical,
-       (during setup, when comm_rec is not the appropriate communication
-       structure), so this isn't as bad as it looks. */
-    float* buf;
-    int    i;
-
-    snew(buf, nr);
-    MPI_Allreduce(r, buf, nr, MPI_FLOAT, MPI_SUM, mpi_comm);
-    for (i = 0; i < nr; i++)
-    {
-        r[i] = buf[i];
-    }
-    sfree(buf);
-#    endif
 }
 #endif
 
@@ -231,14 +203,7 @@ void gmx_sumi_sim(int gmx_unused nr, int gmx_unused r[], const gmx_multisim_t gm
 #if !GMX_MPI
     GMX_RELEASE_ASSERT(false, "Invalid call to gmx_sumi_sim");
 #else
-#    if MPI_IN_PLACE_EXISTS
     MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_INT, MPI_SUM, ms->mastersComm_);
-#    else
-    /* this is thread-unsafe, but it will do for now: */
-    ms->intBuffer.resize(nr);
-    MPI_Allreduce(r, ms->intBuffer.data(), ms->intBuffer.size(), MPI_INT, MPI_SUM, ms->mastersComm_);
-    std::copy(std::begin(ms->intBuffer), std::end(ms->intBuffer), r);
-#    endif
 #endif
 }
 
@@ -247,14 +212,7 @@ void gmx_sumli_sim(int gmx_unused nr, int64_t gmx_unused r[], const gmx_multisim
 #if !GMX_MPI
     GMX_RELEASE_ASSERT(false, "Invalid call to gmx_sumli_sim");
 #else
-#    if MPI_IN_PLACE_EXISTS
     MPI_Allreduce(MPI_IN_PLACE, r, nr, MPI_INT64_T, MPI_SUM, ms->mastersComm_);
-#    else
-    /* this is thread-unsafe, but it will do for now: */
-    ms->int64Buffer.resize(nr);
-    MPI_Allreduce(r, ms->int64Buffer.data(), ms->int64Buffer.size(), MPI_INT64_T, MPI_SUM, ms->mastersComm_);
-    std::copy(std::begin(ms->int64Buffer), std::end(ms->int64Buffer), r);
-#    endif
 #endif
 }
 
index eb0f75bec585f9ff5a8ab8c3a47fa450d6522bed..ef41a38c8e2badfda925d80079f52d255e55959f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -113,21 +113,6 @@ struct gmx_multisim_t
     MPI_Comm mastersComm_ = MPI_COMM_NULL;
     //! The MPI communicator between ranks of this simulation.
     MPI_Comm simulationComm_ = MPI_COMM_NULL;
-    /*! \brief Communication buffers needed if MPI_IN_PLACE isn't supported
-     *
-     * Other types could be added as needed.
-     *
-     * These vectors are unused when MPI_IN_PLACE is available
-     * and could be removed with preprocessing (or perhaps
-     * templating) or simply requiring MPI 2.0 (the standard
-     * introduced in 1997). However, the additional cache pressure
-     * introduced by the extra size of this type is not of great
-     * concern, since we have at most one per MPI rank.
-     * See issue #3591. */
-    //! \{
-    std::vector<int>     intBuffer_;
-    std::vector<int64_t> int64Buffer_;
-    //! \}
 };
 
 //! Calculate the sum over the simulations of an array of ints
index 5a4a3caea9ab80723da83a81fabc03e44c0aa18e..5c429237117066c343699efc2ed8ffb0c4516a05 100644 (file)
@@ -126,6 +126,6 @@ void print_start(FILE* fplog, const t_commrec* cr, gmx_walltime_accounting_t wal
     char buf[STRLEN];
 
     sprintf(buf, "Started %s", name);
-    print_date_and_time(fplog, cr->nodeid, buf,
-                        walltime_accounting_get_start_time_stamp(walltime_accounting));
+    print_date_and_time(
+            fplog, cr->nodeid, buf, walltime_accounting_get_start_time_stamp(walltime_accounting));
 }
diff --git a/src/gromacs/mdrunutility/tests/.clang-tidy b/src/gromacs/mdrunutility/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index e538b8ffeddf3529ba31202757571cc24022d46f..900eee12c590946b3a46ac6defbd29f5af3dcc87 100644 (file)
@@ -34,6 +34,8 @@
 
 gmx_add_unit_test_library(mdrunutility-test-shared
                           threadaffinitytest.cpp)
+target_link_libraries(mdrunutility-test-shared PRIVATE common)
+target_link_libraries(mdrunutility-test-shared PUBLIC legacy_api)
 
 gmx_add_unit_test(MdrunUtilityUnitTests mdrunutility-test
     CPP_SOURCE_FILES
index ade195c5d45a23f44c123b13089c16d72e943509..cda3de427dd5d67536c50bde5381f4c95a43f7e3 100644 (file)
@@ -132,8 +132,8 @@ public:
     }
     void expectPinningMessage(bool userSpecifiedStride, int stride)
     {
-        std::string pattern = formatString("Pinning threads .* %s.* stride of %d",
-                                           userSpecifiedStride ? "user" : "auto", stride);
+        std::string pattern = formatString(
+                "Pinning threads .* %s.* stride of %d", userSpecifiedStride ? "user" : "auto", stride);
         expectInfoMatchingRegex(pattern.c_str());
     }
     void expectLogMessageMatchingRegexIf(MDLogger::LogLevel level, const char* re, bool condition)
@@ -152,10 +152,15 @@ public:
         }
         gmx::PhysicalNodeCommunicator comm(MPI_COMM_WORLD, physicalNodeId_);
         int                           numThreadsOnThisNode, indexWithinNodeOfFirstThreadOnThisRank;
-        analyzeThreadsOnThisNode(comm, numThreadsOnThisRank, &numThreadsOnThisNode,
-                                 &indexWithinNodeOfFirstThreadOnThisRank);
-        gmx_set_thread_affinity(logHelper_.logger(), cr_, &hwOpt_, *hwTop_, numThreadsOnThisRank,
-                                numThreadsOnThisNode, indexWithinNodeOfFirstThreadOnThisRank,
+        analyzeThreadsOnThisNode(
+                comm, numThreadsOnThisRank, &numThreadsOnThisNode, &indexWithinNodeOfFirstThreadOnThisRank);
+        gmx_set_thread_affinity(logHelper_.logger(),
+                                cr_,
+                                &hwOpt_,
+                                *hwTop_,
+                                numThreadsOnThisRank,
+                                numThreadsOnThisNode,
+                                indexWithinNodeOfFirstThreadOnThisRank,
                                 &affinityAccess_);
     }
 
index 8cf377acbf160ab0ee2c720f86bea938eecc880b..f046c966e5ad1d3d1b91e6ca8b7824bcd7b233b6 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -82,6 +82,7 @@ public:
 };
 
 //! Global instance of DefaultThreadAffinityAccess
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 DefaultThreadAffinityAccess g_defaultAffinityAccess;
 
 } // namespace
@@ -138,11 +139,11 @@ static bool get_thread_affinity_layout(const gmx::MDLogger&         mdlog,
         hwThreadsPerCore = hwTop.machine().sockets[0].cores[0].hwThreads.size();
         snew(*localityOrder, hwThreads);
         int i = 0;
-        for (auto& s : hwTop.machine().sockets)
+        for (const auto& s : hwTop.machine().sockets)
         {
-            for (auto& c : s.cores)
+            for (const auto& c : s.cores)
             {
-                for (auto& t : c.hwThreads)
+                for (const auto& t : c.hwThreads)
                 {
                     (*localityOrder)[i++] = t.logicalProcessorId;
                 }
@@ -262,7 +263,8 @@ static bool get_thread_affinity_layout(const gmx::MDLogger&         mdlog,
     {
         GMX_LOG(mdlog.info)
                 .appendTextFormatted("Pinning threads with a%s logical core stride of %d",
-                                     bPickPinStride ? "n auto-selected" : " user-specified", *pin_stride);
+                                     bPickPinStride ? "n auto-selected" : " user-specified",
+                                     *pin_stride);
     }
 
     *issuedWarning = alreadyWarned;
@@ -317,7 +319,11 @@ static bool set_affinity(const t_commrec*            cr,
                 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, ret ? 1 : 0);
+                        cr->nodeid,
+                        gmx_omp_get_thread_num(),
+                        index,
+                        core,
+                        ret ? 1 : 0);
             }
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
@@ -330,7 +336,8 @@ static bool set_affinity(const t_commrec*            cr,
         sprintf(msg,
                 "Looks like we have set affinity for more threads than "
                 "we have (%d > %d)!\n",
-                nth_affinity_set, nthread_local);
+                nth_affinity_set,
+                nthread_local);
         gmx_incons(msg);
     }
 
@@ -356,7 +363,10 @@ static bool set_affinity(const t_commrec*            cr,
 
         if (nthread_local > 1)
         {
-            sprintf(sbuf2, "for %d/%d thread%s ", nthread_local - nth_affinity_set, nthread_local,
+            sprintf(sbuf2,
+                    "for %d/%d thread%s ",
+                    nthread_local - nth_affinity_set,
+                    nthread_local,
                     nthread_local > 1 ? "s" : "");
         }
 
@@ -382,8 +392,8 @@ void analyzeThreadsOnThisNode(const gmx::PhysicalNodeCommunicator& physicalNodeC
         /* MPI_Scan is inclusive, but here we need exclusive */
         *intraNodeThreadOffset -= numThreadsOnThisRank;
         /* Get the total number of threads on this physical node */
-        MPI_Allreduce(&numThreadsOnThisRank, numThreadsOnThisNode, 1, MPI_INT, MPI_SUM,
-                      physicalNodeComm.comm_);
+        MPI_Allreduce(
+                &numThreadsOnThisRank, numThreadsOnThisNode, 1, MPI_INT, MPI_SUM, physicalNodeComm.comm_);
     }
 #else
     GMX_UNUSED_VALUE(physicalNodeComm);
@@ -446,17 +456,23 @@ void gmx_set_thread_affinity(const gmx::MDLogger&         mdlog,
 
     bool affinityIsAutoAndNumThreadsIsNotAuto =
             (hw_opt->threadAffinity == ThreadAffinity::Auto && !hw_opt->totNumThreadsIsAuto);
-    bool issuedWarning;
-    bool validLayout = get_thread_affinity_layout(
-            mdlog, cr, hwTop, numThreadsOnThisNode, affinityIsAutoAndNumThreadsIsNotAuto, offset,
-            &core_pinning_stride, &localityOrder, &issuedWarning);
+    bool                   issuedWarning;
+    bool                   validLayout = get_thread_affinity_layout(mdlog,
+                                                  cr,
+                                                  hwTop,
+                                                  numThreadsOnThisNode,
+                                                  affinityIsAutoAndNumThreadsIsNotAuto,
+                                                  offset,
+                                                  &core_pinning_stride,
+                                                  &localityOrder,
+                                                  &issuedWarning);
     const gmx::sfree_guard localityOrderGuard(localityOrder);
 
     bool allAffinitiesSet;
     if (validLayout)
     {
-        allAffinitiesSet = set_affinity(cr, numThreadsOnThisRank, intraNodeThreadOffset, offset,
-                                        core_pinning_stride, localityOrder, affinityAccess);
+        allAffinitiesSet = set_affinity(
+                cr, numThreadsOnThisRank, intraNodeThreadOffset, offset, core_pinning_stride, localityOrder, affinityAccess);
     }
     else
     {
@@ -502,8 +518,10 @@ static bool detectDefaultAffinityMask(const int nthreads_hw_avail)
     {
         if (debug)
         {
-            fprintf(debug, "%d hardware threads detected, but %d was returned by CPU_COUNT",
-                    nthreads_hw_avail, CPU_COUNT(&mask_current));
+            fprintf(debug,
+                    "%d hardware threads detected, but %d was returned by CPU_COUNT",
+                    nthreads_hw_avail,
+                    CPU_COUNT(&mask_current));
         }
         detectedDefaultAffinityMask = false;
     }
index 7af2f8f080f505abc1ef9f3a9c5015fd5ca70607..a9640d1d0eaeee9476816bc10a96be6de4f8f052 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2018, by the GROMACS development team, led by
+# Copyright (c) 2018,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(mdspan INTERFACE)
+
+# Public interface for modules, including dependencies and interfaces
+target_include_directories(mdspan INTERFACE
+        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index 7a62dd61c8725f99dc9568a09061ae74bc66d514..cff8eeea47aeda0891e72d5925ba0accbdca6c1c 100644 (file)
@@ -89,7 +89,10 @@ template<class BasicMdspan>
 constexpr BasicMdspan addElementwise(const BasicMdspan& span1, const BasicMdspan& span2)
 {
     BasicMdspan result(span1);
-    std::transform(begin(span1), end(span1), begin(span2), begin(result),
+    std::transform(begin(span1),
+                   end(span1),
+                   begin(span2),
+                   begin(result),
                    std::plus<typename BasicMdspan::element_type>());
     return result;
 }
@@ -99,7 +102,10 @@ template<class BasicMdspan>
 constexpr BasicMdspan subtractElementwise(const BasicMdspan& span1, const BasicMdspan& span2)
 {
     BasicMdspan result(span1);
-    std::transform(begin(span1), end(span1), begin(span2), begin(result),
+    std::transform(begin(span1),
+                   end(span1),
+                   begin(span2),
+                   begin(result),
                    std::minus<typename BasicMdspan::element_type>());
     return result;
 }
@@ -109,7 +115,10 @@ template<class BasicMdspan>
 constexpr BasicMdspan multiplyElementwise(const BasicMdspan& span1, const BasicMdspan& span2)
 {
     BasicMdspan result(span1);
-    std::transform(begin(span1), end(span1), begin(span2), begin(result),
+    std::transform(begin(span1),
+                   end(span1),
+                   begin(span2),
+                   begin(result),
                    std::multiplies<typename BasicMdspan::element_type>());
     return result;
 }
@@ -119,7 +128,10 @@ template<class BasicMdspan>
 constexpr BasicMdspan divideElementwise(const BasicMdspan& span1, const BasicMdspan& span2)
 {
     BasicMdspan result(span1);
-    std::transform(begin(span1), end(span1), begin(span2), begin(result),
+    std::transform(begin(span1),
+                   end(span1),
+                   begin(span2),
+                   begin(result),
                    std::divides<typename BasicMdspan::element_type>());
     return result;
 }
diff --git a/src/gromacs/mdspan/tests/.clang-tidy b/src/gromacs/mdspan/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 79e8dc9776474dd51f6a032e066896fe31a0bc41..d0dd1b6239a8cffa0a1472dcd1721dd0f2a1adf7 100644 (file)
@@ -40,3 +40,4 @@ gmx_add_unit_test(MDSpanTests mdspan-test
         layouts.cpp
         mdspan.cpp
         )
+target_link_libraries(mdspan-test PRIVATE mdspan)
index c61c5598f2845f1d60fb659dc283d6838bd7d32e..cb24993566bb40a468924cb1c5ed3f0c52023622 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -240,14 +240,14 @@ struct MdSpanTest : public ::testing::Test
                           bool contiguous,
                           bool strided)
     {
-        check_properties_internal(my_mdspan_mapping, always_unique, always_contiguous,
-                                  always_strided, unique, contiguous, strided);
-        check_properties_internal(my_mdspan_map_acc, always_unique, always_contiguous,
-                                  always_strided, unique, contiguous, strided);
-        check_properties_internal(my_mdspan_extents, always_unique, always_contiguous,
-                                  always_strided, unique, contiguous, strided);
-        check_properties_internal(my_mdspan_copy, always_unique, always_contiguous, always_strided,
-                                  unique, contiguous, strided);
+        check_properties_internal(
+                my_mdspan_mapping, always_unique, always_contiguous, always_strided, unique, contiguous, strided);
+        check_properties_internal(
+                my_mdspan_map_acc, always_unique, always_contiguous, always_strided, unique, contiguous, strided);
+        check_properties_internal(
+                my_mdspan_extents, always_unique, always_contiguous, always_strided, unique, contiguous, strided);
+        check_properties_internal(
+                my_mdspan_copy, always_unique, always_contiguous, always_strided, unique, contiguous, strided);
     }
 
     void check_operator()
index 8f60ea640a7eec3b1004a1f52c56f1751682efac..f4517b6cdcddf3f9a4123c865014bd3113eee829 100644 (file)
@@ -32,6 +32,9 @@
 # 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 up the module library
+add_library(mdtypes INTERFACE)
+
 file(GLOB MDTYPES_SOURCES
     checkpointdata.cpp
     df_history.cpp
@@ -66,6 +69,38 @@ else()
       )
 endif()
 
+# Source files have the following private module dependencies.
+target_link_libraries(mdtypes PRIVATE
+                      #                      gmxlib
+                      #                      math
+                      #                      mdtypes
+                      #                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(mdtypes PUBLIC
+target_include_directories(mdtypes INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(mdtypes PUBLIC
+target_link_libraries(mdtypes INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when fileio is an OBJECT target
+#target_link_libraries(mdtypes PUBLIC legacy_api)
+#target_link_libraries(mdtypes PRIVATE common)
+
+# Module dependencies
+# fileio interfaces convey transitive dependence on these modules.
+#target_link_libraries(mdtypes PUBLIC
+target_link_libraries(mdtypes INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(mdtypes PRIVATE tng_io)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(mdtypes PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index 3b5574931334e873e2aac61d74071e802f84aed0..b3ce1dd905faf9d5d8cf5e61ad4a10187c1941e2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -50,7 +50,6 @@
 #include <vector>
 
 #include "gromacs/mdtypes/awh_correlation_history.h"
-#include "gromacs/utility/basedefinitions.h"
 
 namespace gmx
 {
index 951a7d25907ebf55a8728690d0f147b6057a467f..930bd0601113acf3dbd91f4983a0d09b37537258 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_AWH_PARAMS_H
 #define GMX_MDTYPES_AWH_PARAMS_H
 
+#include <vector>
+
 #include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/classhelpers.h"
+
+struct t_inpfile;
+struct t_inputrec;
+struct pull_params_t;
+using warninp_t = struct warninp*;
 
 namespace gmx
 {
 
+class ISerializer;
 //! Target distribution enum.
-enum
+enum class AwhTargetType : int
 {
-    eawhtargetCONSTANT,
-    eawhtargetCUTOFF,
-    eawhtargetBOLTZMANN,
-    eawhtargetLOCALBOLTZMANN,
-    eawhtargetNR
+    Constant,
+    Cutoff,
+    Boltzmann,
+    LocalBoltzmann,
+    Count,
+    Default = Constant
 };
 //! String for target distribution.
-extern const char* eawhtarget_names[eawhtargetNR + 1];
-//! Macro for target distribution string.
-#define EAWHTARGET(e) enum_name(e, gmx::eawhtargetNR, gmx::eawhtarget_names)
+const char* enumValueToString(AwhTargetType enumValue);
 
 //! Weight histogram growth enum.
-enum
+enum class AwhHistogramGrowthType : int
 {
-    eawhgrowthEXP_LINEAR,
-    eawhgrowthLINEAR,
-    eawhgrowthNR
+    ExponentialLinear,
+    Linear,
+    Count,
+    Default = ExponentialLinear
 };
 //! String for weight histogram growth
-extern const char* eawhgrowth_names[eawhgrowthNR + 1];
-//! Macro for weight histogram growth string.
-#define EAWHGROWTH(e) enum_name(e, gmx::eawhgrowthNR, gmx::eawhgrowth_names)
+const char* enumValueToString(AwhHistogramGrowthType enumValue);
 
 //! AWH potential type enum.
-enum
+enum class AwhPotentialType : int
 {
-    eawhpotentialCONVOLVED,
-    eawhpotentialUMBRELLA,
-    eawhpotentialNR
+    Convolved,
+    Umbrella,
+    Count,
+    Default = Convolved
 };
 //! String for AWH potential type
-extern const char* eawhpotential_names[eawhpotentialNR + 1];
-//! Macro for AWH potential type string.
-#define EAWHPOTENTIAL(e) enum_name(e, gmx::eawhpotentialNR, gmx::eawhpotential_names)
+const char* enumValueToString(AwhPotentialType enumValue);
 
 //! AWH bias reaction coordinate provider
-enum
+enum class AwhCoordinateProviderType : int
 {
-    eawhcoordproviderPULL,
-    eawhcoordproviderFREE_ENERGY_LAMBDA,
-    eawhcoordproviderNR
+    Pull,
+    FreeEnergyLambda,
+    Count,
+    Default = Pull
 };
 //! String for AWH bias reaction coordinate provider.
-extern const char* eawhcoordprovider_names[eawhcoordproviderNR + 1];
-//! Macro for AWH bias reaction coordinate provider.
-#define EAWHCOORDPROVIDER(e) enum_name(e, gmx::eawhcoordproviderNR, gmx::eawhcoordprovider_names)
+const char* enumValueToString(AwhCoordinateProviderType enumValue);
 
-/*! \cond INTERNAL */
-
-//! Parameters for an AWH coordinate dimension.
-struct AwhDimParams
+class AwhDimParams
 {
-    int    eCoordProvider; /**< The module providing the reaction coordinate. */
-    int    coordIndex;     /**< Index of reaction coordinate in the provider. */
-    double origin;         /**< Start value of the interval. */
-    double end;            /**< End value of the interval. */
-    double period;         /**< The period of this dimension (= 0 if not periodic). */
-    double forceConstant;  /**< The force constant in kJ/mol/nm^2, kJ/mol/rad^2 */
-    double diffusion; /**< Estimated diffusion constant in units of nm^2/ps, rad^2/ps or ps^-1. */
-    double coordValueInit; /**< The initial coordinate value. */
-    double coverDiameter; /**< The diameter that needs to be sampled around a point before it is considered covered. */
-};
+public:
+    //! Constructor from input file.
+    AwhDimParams(std::vector<t_inpfile>* inp, const std::string& prefix, warninp_t wi, bool bComment);
+    //! Constructor to generate from file reading.
+    explicit AwhDimParams(ISerializer* serializer);
 
-//! Parameters for an AWH bias.
-struct AwhBiasParams
-{
-    // TODO: Turn dimParams into a std::vector when moved into AWH module
-    int           ndim;         /**< Dimension of the coordinate space. */
-    AwhDimParams* dimParams;    /**< AWH parameters per dimension. */
-    int           eTarget;      /**< Type of target distribution. */
-    double   targetBetaScaling; /**< Beta scaling value for Boltzmann type target distributions. */
-    double   targetCutoff; /**< Free energy cutoff value for cutoff type target distribution in kJ/mol.*/
-    int      eGrowth;      /**< How the biasing histogram grows. */
-    int      bUserData;    /**< Is there a user-defined initial PMF estimate and target estimate? */
-    double   errorInitial; /**< Estimated initial free energy error in kJ/mol. */
-    int      shareGroup; /**< When >0, the bias is shared with biases of the same group and across multiple simulations when shareBiasMultisim=true */
-    gmx_bool equilibrateHistogram; /**< True if the simulation starts out by equilibrating the histogram. */
+    //! Move constructor.
+    AwhDimParams(AwhDimParams&&) = default;
+    //! Move assignment operator.
+    AwhDimParams& operator=(AwhDimParams&&) = default;
+    //! Delete copy constructor.
+    AwhDimParams(const AwhDimParams&) = delete;
+    //! Delete copy assignment.
+    AwhDimParams& operator=(const AwhDimParams&) = delete;
+
+    //! Which module is providing the reaction coordinate.
+    AwhCoordinateProviderType coordinateProvider() const { return eCoordProvider_; }
+    //! Index for reaction coordinate in provider.
+    int coordinateIndex() const { return coordIndex_; }
+    //! Start value for interval.
+    double origin() const { return origin_; }
+    //! End value for interval.
+    double end() const { return end_; }
+    //! Period for the dimension.
+    double period() const { return period_; }
+    //! Set period value dependent on state.
+    void setPeriod(double period) { period_ = period; }
+    //! Force constant for this dimension.
+    double forceConstant() const { return forceConstant_; }
+    //! Estimated diffusion constant.
+    double diffusion() const { return diffusion_; }
+    //! Initial value for coordinate.
+    double initialCoordinate() const { return coordValueInit_; }
+    //! Set initial coordinate value dependent on state.
+    void setInitialCoordinate(double initialCoordinate) { coordValueInit_ = initialCoordinate; }
+    //! Diameter needed to be sampled.
+    double coverDiameter() const { return coverDiameter_; }
+    //! Write datastructure.
+    void serialize(ISerializer* serializer);
+
+private:
+    //! The module providing the reaction coordinate.
+    AwhCoordinateProviderType eCoordProvider_;
+    //! Index of reaction coordinate in the provider.
+    int coordIndex_ = 0;
+    //! Start value of the interval.
+    double origin_ = 0.0;
+    //! End value of the interval.
+    double end_ = 0.0;
+    //! The period of this dimension (= 0 if not periodic).
+    double period_ = 0.0;
+    //! The force constant in kJ/mol/nm^2, kJ/mol/rad^2
+    double forceConstant_ = 0.0;
+    //! Estimated diffusion constant in units of nm^2/ps or rad^2/ps or ps^-1.
+    double diffusion_ = 0.0;
+    //! The initial coordinate value.
+    double coordValueInit_ = 0.0;
+    //! The diameter that needs to be sampled around a point before it is considered covered.
+    double coverDiameter_ = 0.0;
 };
 
-//! Parameters for AWH.
-struct AwhParams
+class AwhBiasParams
 {
-    // TODO: Turn awhBiasParams into a std::vector when moved into AWH module
-    int            numBias;       /**< The number of AWH biases.*/
-    AwhBiasParams* awhBiasParams; /**< AWH bias parameters.*/
-    int64_t        seed;          /**< Random seed.*/
-    int            nstOut;        /**< Output step interval.*/
-    int      nstSampleCoord; /**< Number of samples per coordinate sample (also used for PMF) */
-    int      numSamplesUpdateFreeEnergy; /**< Number of samples per free energy update. */
-    int      ePotential;                 /**< Type of potential. */
-    gmx_bool shareBiasMultisim; /**< When true, share biases with shareGroup>0 between multi-simulations */
+public:
+    //! Constructor from input file.
+    AwhBiasParams(std::vector<t_inpfile>* inp, const std::string& prefix, warninp_t wi, bool bComment);
+    //! Constructor to generate from file reading.
+    explicit AwhBiasParams(ISerializer* serializer);
+
+    //! Move constructor.
+    AwhBiasParams(AwhBiasParams&&) = default;
+    //! Move assignment operator.
+    AwhBiasParams& operator=(AwhBiasParams&&) = default;
+    //! Delete copy constructor.
+    AwhBiasParams(const AwhBiasParams&) = delete;
+    //! Delete copy assignment.
+    AwhBiasParams& operator=(const AwhBiasParams&) = delete;
+
+    //! Which target distribution is searched.
+    AwhTargetType targetDistribution() const { return eTarget_; }
+    //! Beta scaling to reach target distribution.
+    double targetBetaScaling() const { return targetBetaScaling_; }
+    //! Cutoff for target.
+    double targetCutoff() const { return targetCutoff_; }
+    //! Which kind of growth to use.
+    AwhHistogramGrowthType growthType() const { return eGrowth_; }
+    //! User provided PMF estimate.
+    bool userPMFEstimate() const { return bUserData_; }
+    //! Estimated initial free energy error in kJ/mol.
+    double initialErrorEstimate() const { return errorInitial_; }
+    //! Dimensions of coordinate space.
+    int ndim() const { return dimParams_.size(); }
+    //! Number of groups to share this bias with.
+    int shareGroup() const { return shareGroup_; }
+    //! If the simulation starts with equilibrating histogram.
+    bool equilibrateHistogram() const { return equilibrateHistogram_; }
+    //! Access to dimension parameters.
+    ArrayRef<AwhDimParams> dimParams() { return dimParams_; }
+    //! Const access to dimension parameters.
+    ArrayRef<const AwhDimParams> dimParams() const { return dimParams_; }
+    //! Write datastructure.
+    void serialize(ISerializer* serializer);
+
+private:
+    //! AWH parameters per dimension.
+    std::vector<AwhDimParams> dimParams_;
+    //! Type of target distribution.
+    AwhTargetType eTarget_;
+    //! Beta scaling value for Boltzmann type target distributions.
+    double targetBetaScaling_;
+    //! Free energy cutoff value for cutoff type target distribution in kJ/mol.
+    double targetCutoff_;
+    //! How the biasing histogram grows.
+    AwhHistogramGrowthType eGrowth_;
+    //! Is there a user-defined initial PMF estimate and target estimate?
+    bool bUserData_;
+    //! Estimated initial free energy error in kJ/mol.
+    double errorInitial_;
+    //! When >0, the bias is shared with biases of the same group and across multiple simulations when shareBiasMultisim=true
+    int shareGroup_;
+    //! True if the simulation starts out by equilibrating the histogram.
+    bool equilibrateHistogram_;
 };
+/*! \internal
+ * \brief Structure holding parameter information for AWH.
+ */
+class AwhParams
+{
+public:
+    //! Constructor from input file.
+    AwhParams(std::vector<t_inpfile>* inp, warninp_t wi);
+    //! Constructor used to generate awh parameter from file reading.
+    explicit AwhParams(ISerializer* serializer);
 
-/*! \endcond */
+    //! Move constructor.
+    AwhParams(AwhParams&&) = default;
+    //! Move assignment operator.
+    AwhParams& operator=(AwhParams&&) = default;
+    //! Delete copy constructor.
+    AwhParams(const AwhParams&) = delete;
+    //! Delete copy assignment.
+    AwhParams& operator=(const AwhParams&) = delete;
+
+    //! Get number of biases.
+    int numBias() const { return awhBiasParams_.size(); }
+    //! Get access to bias parameters.
+    ArrayRef<AwhBiasParams> awhBiasParams() { return awhBiasParams_; }
+    //! Const access to bias parameters.
+    ArrayRef<const AwhBiasParams> awhBiasParams() const { return awhBiasParams_; }
+    //! What king of potential is being used. \todo should use actual enum class.
+    AwhPotentialType potential() const { return potentialEnum_; }
+    //! Seed used for starting AWH.
+    int64_t seed() const { return seed_; }
+    //! Output step interval.
+    int nstout() const { return nstOut_; }
+    //! Number of samples per coordinate sample.
+    int nstSampleCoord() const { return nstSampleCoord_; }
+    //! Number of samples per free energy update.
+    int numSamplesUpdateFreeEnergy() const { return numSamplesUpdateFreeEnergy_; }
+    //! If biases are shared in multisim.
+    bool shareBiasMultisim() const { return shareBiasMultisim_; }
+    //! Serialize awh parameters.
+    void serialize(ISerializer* serializer);
+
+private:
+    //! AWH bias parameters.
+    std::vector<AwhBiasParams> awhBiasParams_;
+    //! Random seed.
+    int64_t seed_;
+    //! Output step interval.
+    int nstOut_;
+    //! Number of samples per coordinate sample (also used for PMF)
+    int nstSampleCoord_;
+    //! Number of samples per free energy update.
+    int numSamplesUpdateFreeEnergy_;
+    //! Type of potential.
+    AwhPotentialType potentialEnum_;
+    //! Whether to share biases with shareGroup>0 between multi-simulations.
+    bool shareBiasMultisim_;
+};
 
 } // namespace gmx
 
index c541d9c85d1389a4ae5e5bbef7bbd06c750fa4da..c63de6bb90c8434ecedd89dcccc48c500e06bacd 100644 (file)
@@ -477,8 +477,7 @@ inline void ReadCheckpointData::arrayRef(const std::string& key, ArrayRef<RVec>
     for (; outputIt != outputEnd && inputIt != inputEnd; outputIt++, inputIt++)
     {
         auto storedRVec = inputIt->asObject()["RVec"].asArray().values();
-        *outputIt       = { storedRVec[XX].cast<real>(), storedRVec[YY].cast<real>(),
-                      storedRVec[ZZ].cast<real>() };
+        *outputIt = { storedRVec[XX].cast<real>(), storedRVec[YY].cast<real>(), storedRVec[ZZ].cast<real>() };
     }
 }
 
index bef393da4275ac826234a620f896c330deb5a4d7..9213187567f21ef625c1cd5d5e2120ea2f620ab8 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <stddef.h>
 
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/gmxmpi.h"
 
-struct mpi_in_place_buf_t;
 struct gmx_domdec_t;
 
 #define DUTY_PP (1U << 0U)
@@ -107,10 +105,6 @@ struct t_commrec
      * This should be read through thisRankHasDuty() or getThisRankDuties().
      */
     int duty;
-
-    /* these buffers are used as destination buffers if MPI_IN_PLACE isn't
-       supported.*/
-    mpi_in_place_buf_t* mpb;
 };
 
 /*! \brief
index 70ce4f66efedff1345494de40590ae08256aedae..3398cd69aa98cde1bbd5c8740b61dbd1695eb87a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/mdtypes/md_enums.h"
 #include "gromacs/topology/idef.h"
 #include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/real.h"
 
@@ -49,14 +50,14 @@ struct t_commrec;
 struct t_lambda;
 
 // The non-bonded energy terms accumulated for energy group pairs
-enum
+enum class NonBondedEnergyTerms : int
 {
-    egCOULSR,
-    egLJSR,
-    egBHAMSR,
-    egCOUL14,
-    egLJ14,
-    egNR
+    CoulombSR,
+    LJSR,
+    BuckinghamSR,
+    Coulomb14,
+    LJ14,
+    Count
 };
 
 // Struct for accumulating non-bonded energies between energy group pairs
@@ -64,14 +65,14 @@ struct gmx_grppairener_t
 {
     gmx_grppairener_t(int numEnergyGroups) : nener(numEnergyGroups * numEnergyGroups)
     {
-        for (auto& elem : ener)
+        for (auto& term : energyGroupPairTerms)
         {
-            elem.resize(nener);
+            term.resize(nener);
         }
     }
 
-    int                                 nener; /* The number of energy group pairs */
-    std::array<std::vector<real>, egNR> ener;  /* Energy terms for each pair of groups */
+    int nener; /* The number of energy group pairs */
+    gmx::EnumerationArray<NonBondedEnergyTerms, std::vector<real>> energyGroupPairTerms; /* Energy terms for each pair of groups */
 };
 
 //! Accumulates free-energy foreign lambda energies and dH/dlamba
@@ -195,13 +196,13 @@ struct gmx_enerdata_t
     gmx_enerdata_t(int numEnergyGroups, int numFepLambdas);
 
     //! The energies for all different interaction types
-    real term[F_NRE] = { 0 };
+    std::array<real, F_NRE> term = { 0 };
     //! Energy group pair non-bonded energies
     struct gmx_grppairener_t grpp;
     //! Contributions to dV/dlambda with linear dependence on lambda
-    double dvdl_lin[efptNR] = { 0 };
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, double> dvdl_lin = { 0 };
     //! Contributions to dV/dlambda with non-linear dependence on lambda
-    double dvdl_nonlin[efptNR] = { 0 };
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, double> dvdl_nonlin = { 0 };
     /* The idea is that dvdl terms with linear lambda dependence will be added
      * automatically to enerpart_lambda. Terms with non-linear lambda dependence
      * should explicitly determine the energies at foreign lambda points
@@ -211,7 +212,7 @@ struct gmx_enerdata_t
     ForeignLambdaTerms foreignLambdaTerms;
 
     //! Alternate, temporary array for storing foreign lambda energies
-    real foreign_term[F_NRE] = { 0 };
+    std::array<real, F_NRE> foreign_term = { 0 };
     //! Alternate, temporary  array for storing foreign lambda group pair energies
     struct gmx_grppairener_t foreign_grpp;
 };
index 638ba98ed08160d7fad4861a4e34e05eb60514fd..d86ddd98b1f4824f33fc8d8438d09f4a9f851a5c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,7 +51,6 @@
 #include <memory>
 #include <vector>
 
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
 //! \cond INTERNAL
@@ -74,7 +73,7 @@ public:
     //! Lambda at start time
     double start_lambda;
     //! Whether the lambda value is set. Here for backward-compatibility.
-    gmx_bool start_lambda_set;
+    bool start_lambda_set;
 
     //! Read / write data from / to checkpoint object
     template<gmx::CheckpointDataOperation operation>
index 09dce8f273f319b959feda55db855f28a71ad220..0da8e1a69e4c8dbc5f5d61b23b9e2e31c9db7c2f 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_FCDATA_H
 #define GMX_MDTYPES_FCDATA_H
 
+#include <memory>
 #include <vector>
 
 #include "gromacs/math/vectypes.h"
 #include "gromacs/topology/idef.h"
-#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/real.h"
 
+enum class DistanceRestraintWeighting : int;
+struct gmx_mtop_t;
+struct gmx_multisim_t;
+struct t_commrec;
+struct t_inputrec;
+class t_state;
+
 typedef real rvec5[5];
 
 /* Distance restraining stuff */
 typedef struct t_disresdata
 {
-    int      dr_weighting; /* Weighting of pairs in one restraint              */
-    gmx_bool dr_bMixed;    /* Use sqrt of the instantaneous times              *
-                            * the time averaged violation                      */
-    real dr_fc;            /* Force constant for disres,                       *
-                            * which is multiplied by a (possibly)              *
-                            * different factor for each restraint              */
-    real  dr_tau;          /* Time constant for disres                   */
-    real  ETerm;           /* multiplication factor for time averaging         */
-    real  ETerm1;          /* 1 - ETerm1                                       */
-    real  exp_min_t_tau;   /* Factor for slowly switching on the force         */
-    int   nres;            /* The number of distance restraints                */
-    int   npair;           /* The number of distance restraint pairs           */
-    int   type_min;        /* The minimum iparam type index for restraints     */
-    real  sumviol;         /* The sum of violations                            */
-    real* rt;              /* The instantaneous distance (npair)               */
-    real* rm3tav;          /* The time averaged distance (npair)               */
-    real* Rtl_6;           /* The instantaneous r^-6 (nres)                    */
-    real* Rt_6;            /* The instantaneous ensemble averaged r^-6 (nres)  */
-    real* Rtav_6;          /* The time and ensemble averaged r^-6 (nres)       */
-    int   nsystems;        /* The number of systems for ensemble averaging     */
+    DistanceRestraintWeighting dr_weighting; /* Weighting of pairs in one restraint              */
+    bool                       dr_bMixed;    /* Use sqrt of the instantaneous times              *
+                                              * the time averaged violation                      */
+    real dr_fc;                              /* Force constant for disres,                       *
+                                              * which is multiplied by a (possibly)              *
+                                              * different factor for each restraint              */
+    real  dr_tau;                            /* Time constant for disres                         */
+    real  ETerm;                             /* multiplication factor for time averaging         */
+    real  ETerm1;                            /* 1 - ETerm1                                       */
+    real  exp_min_t_tau;                     /* Factor for slowly switching on the force         */
+    int   nres;                              /* The number of distance restraints                */
+    int   npair;                             /* The number of distance restraint pairs           */
+    int   type_min;                          /* The minimum iparam type index for restraints     */
+    real  sumviol;                           /* The sum of violations                            */
+    real* rt;                                /* The instantaneous distance (npair)               */
+    real* rm3tav;                            /* The time averaged distance (npair)               */
+    real* Rtl_6;                             /* The instantaneous r^-6 (nres)                    */
+    real* Rt_6;                              /* The instantaneous ensemble averaged r^-6 (nres)  */
+    real* Rtav_6;                            /* The time and ensemble averaged r^-6 (nres)       */
+    int   nsystems;                          /* The number of systems for ensemble averaging     */
 
     /* TODO: Implement a proper solution for parallel disre indexing */
     const t_iatom* forceatomsStart; /* Pointer to the start of the disre forceatoms */
@@ -83,36 +92,92 @@ struct OriresMatEq
 };
 
 /* Orientation restraining stuff */
-typedef struct t_oriresdata
+struct t_oriresdata
 {
-    real         fc;            /* Force constant for the restraints                  */
-    real         edt;           /* Multiplication factor for time averaging           */
-    real         edt_1;         /* 1 - edt                                            */
-    real         exp_min_t_tau; /* Factor for slowly switching on the force         */
-    int          nr;            /* The number of orientation restraints               */
-    int          nex;           /* The number of experiments                          */
-    int          typeMin;       /* The minimum iparam type index for restraints       */
-    int          nref;          /* The number of atoms for the fit                    */
-    real*        mref;          /* The masses of the reference atoms                  */
-    rvec*        xref;          /* The reference coordinates for the fit (nref)       */
-    rvec*        xtmp;          /* Temporary array for fitting (nref)                 */
-    matrix       R;             /* Rotation matrix to rotate to the reference coor.   */
-    tensor*      S;             /* Array of order tensors for each experiment (nexp)  */
-    rvec5*       Dinsl;         /* The order matrix D for all restraints (nr x 5)     */
-    rvec5*       Dins;          /* The ensemble averaged D (nr x 5)                   */
-    rvec5*       Dtav;          /* The time and ensemble averaged D (nr x 5)          */
-    real*        oinsl;         /* The calculated instantaneous orientations          */
-    real*        oins;          /* The calculated emsemble averaged orientations      */
-    real*        otav;          /* The calculated time and ensemble averaged orient.  */
-    real         rmsdev;        /* The weighted (using kfac) RMS deviation            */
-    OriresMatEq* tmpEq;         /* An temporary array of matrix + rhs                 */
-    real*        eig;           /* Eigenvalues/vectors, for output only (nex x 12)    */
-
-    /* variables for diagonalization with diagonalize_orires_tensors()*/
-    double** M;
-    double*  eig_diag;
-    double** v;
-} t_oriresdata;
+    /*! Constructor
+     *
+     * \param[in] fplog  Log file, can be nullptr
+     * \param[in] mtop   The global topology
+     * \param[in] ir     The input record
+     * \param[in] cr     The commrec, can be nullptr when not running in parallel
+     * \param[in] ms     The multisim communicator, pass nullptr to avoid ensemble averaging
+     * \param[in,out] globalState  The global state, orientation restraint entires are added
+     *
+     * \throws InvalidInputError when there is domain decomposition, fewer than 5 restraints,
+     *         periodic molecules or more than 1 molecule for a moleculetype with restraints.
+     */
+    t_oriresdata(FILE*                 fplog,
+                 const gmx_mtop_t&     mtop,
+                 const t_inputrec&     ir,
+                 const t_commrec*      cr,
+                 const gmx_multisim_t* ms,
+                 t_state*              globalState);
+
+    //! Destructor
+    ~t_oriresdata();
+
+    //! Force constant for the restraints
+    real fc;
+    //! Multiplication factor for time averaging
+    real edt;
+    //! 1 - edt
+    real edt_1;
+    //! Factor for slowly switching on the force
+    real exp_min_t_tau;
+    //! The number of orientation restraints
+    const int numRestraints;
+    //! The number of experiments
+    int numExperiments;
+    //! The minimum iparam type index for restraints
+    int typeMin;
+    //! The number of atoms for the fit
+    int numReferenceAtoms;
+    //! The masses of the reference atoms
+    std::vector<real> mref;
+    //! The reference coordinates for the fit
+    std::vector<gmx::RVec> xref;
+    //! Temporary array for fitting
+    std::vector<gmx::RVec> xtmp;
+    //! Rotation matrix to rotate to the reference coordinates
+    matrix rotationMatrix;
+    //! Array of order tensors, one for each experiment
+    tensor* orderTensors = nullptr;
+    //! The order tensor D for all restraints
+    rvec5* DTensors = nullptr;
+    //! The ensemble averaged D for all restraints
+    rvec5* DTensorsEnsembleAv = nullptr;
+    //! The time and ensemble averaged D restraints
+    rvec5* DTensorsTimeAndEnsembleAv = nullptr;
+    //! The calculated instantaneous orientations
+    std::vector<real> orientations;
+    //! The calculated emsemble averaged orientations
+    gmx::ArrayRef<real> orientationsEnsembleAv;
+    //! Buffer for the calculated emsemble averaged orientations, only used with ensemble averaging
+    std::vector<real> orientationsEnsembleAvBuffer;
+    //! The calculated time and ensemble averaged orientations
+    gmx::ArrayRef<real> orientationsTimeAndEnsembleAv;
+    //! The weighted (using kfac) RMS deviation
+    std::vector<real> orientationsTimeAndEnsembleAvBuffer;
+    //! Buffer for the weighted (using kfac) RMS deviation, only used with time averaging
+    real rmsdev;
+    //! An temporary array of matrix + rhs
+    std::vector<OriresMatEq> tmpEq;
+    //! The number of eigenvalues + eigenvectors per experiment
+    static constexpr int c_numEigenRealsPerExperiment = 12;
+    //! Eigenvalues/vectors, for output only (numExperiments x 12)
+    std::vector<real> eigenOutput;
+
+    // variables for diagonalization with diagonalize_orires_tensors()
+    //! Tensor to diagonalize
+    std::array<gmx::DVec, DIM> M;
+    //! Eigenvalues
+    std::array<double, DIM> eig_diag;
+    //! Eigenvectors
+    std::array<gmx::DVec, DIM> v;
+
+    // Default copy and assign would be incorrect and manual versions are not yet implemented.
+    GMX_DISALLOW_COPY_AND_ASSIGN(t_oriresdata);
+};
 
 /* Cubic spline table for tabulated bonded interactions */
 struct bondedtable_t
@@ -136,8 +201,8 @@ struct t_fcdata
     std::vector<bondedtable_t> dihtab;
 
     // TODO: Convert to C++ and unique_ptr (currently this data is not freed)
-    t_disresdata* disres = nullptr;
-    t_oriresdata* orires = nullptr;
+    t_disresdata*                 disres = nullptr;
+    std::unique_ptr<t_oriresdata> orires;
 };
 
 #endif
index ee0c0d0d916e00a30961649ed19dbd218121da81..03d3e66f29ab430d99256aab16713efc8f33285c 100644 (file)
@@ -88,8 +88,8 @@ void ForceBuffers::resize(int numAtoms)
     {
         forceMtsCombined_.resizeWithPadding(numAtoms);
     }
-    view_ = ForceBuffersView(force_.arrayRefWithPadding(), forceMtsCombined_.arrayRefWithPadding(),
-                             useForceMtsCombined_);
+    view_ = ForceBuffersView(
+            force_.arrayRefWithPadding(), forceMtsCombined_.arrayRefWithPadding(), useForceMtsCombined_);
 }
 
 } // namespace gmx
index fe7c8d5899ed95447e8dfc6db482ed225e39751e..9c49e2f00aeaeadf8deb0300b049b6d4a47e3a4d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_FORCEBUFFERS_H
 #define GMX_MDTYPES_FORCEBUFFERS_H
 
+#include <memory>
+
 #include "gromacs/gpu_utils/hostallocator.h"
-#include "gromacs/math/arrayrefwithpadding.h"
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
+template<typename T>
+class ArrayRef;
+template<typename T>
+class ArrayRefWithPadding;
 
 enum class PinningPolicy : int;
 
index c31bcf05ba5f6536fc8cfa63aacbe824ea835f08..a9a9ae6b2c563b6c77e3cfd114ad5d99666e7f5b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +74,7 @@ public:
      *
      * \param[in] force          A force buffer that will be used for storing forces
      * \param[in] computeVirial  True when algorithms are required to provide their virial contribution (for the current force evaluation)
-     * \param[in] shiftForces    A shift forces buffer of size SHIFTS, only used with \p computeVirial = true
+     * \param[in] shiftForces    A shift forces buffer of size c_numShiftVectors, only used with \p computeVirial = true
      */
     ForceWithShiftForces(const gmx::ArrayRefWithPadding<gmx::RVec>& force,
                          const bool                                 computeVirial,
@@ -110,7 +110,7 @@ private:
     gmx::ArrayRefWithPadding<gmx::RVec> force_;
     //! True when virial computation is requested
     bool computeVirial_;
-    //! A buffer for storing the shift forces, size SHIFTS
+    //! A buffer for storing the shift forces, size c_numShiftVectors
     gmx::ArrayRef<gmx::RVec> shiftForces_;
     //! Tells whether we have spread the vsite forces
     bool haveSpreadVsiteForces_ = false;
index 98ad9ff1aba668fb5ef72c08fe0a20500244e7cc..218c7b26c9a4dd9edb62135577e8d7fa31494d4d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +44,9 @@
 
 #include "gromacs/math/vectypes.h"
 #include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/pbcutil/ishift.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
 #include "locality.h"
@@ -60,7 +60,7 @@ class DispersionCorrection;
 class ListedForces;
 struct t_fcdata;
 struct t_forcetable;
-struct t_QMMMrec;
+struct interaction_const_t;
 
 namespace gmx
 {
@@ -106,16 +106,8 @@ class WholeMoleculeTransform;
  * this value should be slighlty smaller than sqrt(GMX_FLOAT_MAX).
  */
 #define GMX_CUTOFF_INF 1E+18
-
-/* enums for the neighborlist type */
-enum
-{
-    enbvdwNONE,
-    enbvdwLJ,
-    enbvdwBHAM,
-    enbvdwTAB,
-    enbvdwNR
-};
+//! Check the cuttoff
+real cutoff_inf(real cutoff);
 
 struct cginfo_mb_t
 {
@@ -159,7 +151,7 @@ public:
         return forceBufferForDirectVirialContributions_;
     }
 
-    //! Returns the buffer for shift forces, size SHIFTS
+    //! Returns the buffer for shift forces, size c_numShiftVectors
     gmx::ArrayRef<gmx::RVec> shiftForces() { return shiftForces_; }
 
     //! Resizes the direct virial contribution buffer, when present
@@ -170,12 +162,12 @@ private:
     bool haveDirectVirialContributions_ = false;
     //! Force buffer for force computation with direct virial contributions
     std::vector<gmx::RVec> forceBufferForDirectVirialContributions_;
-    //! Shift force array for computing the virial, size SHIFTS
+    //! Shift force array for computing the virial, size c_numShiftVectors
     std::vector<gmx::RVec> shiftForces_;
 };
-
+// NOLINTNEXTLINE (clang-analyzer-optin.performance.Padding)
 struct t_forcerec
-{ // NOLINT (clang-analyzer-optin.performance.Padding)
+{
     // Declare an explicit constructor and destructor, so they can be
     // implemented in a single source file, so that not every source
     // file that includes this one needs to understand how to find the
@@ -183,19 +175,19 @@ struct t_forcerec
     t_forcerec();
     ~t_forcerec();
 
-    struct interaction_const_t* ic = nullptr;
+    std::unique_ptr<interaction_const_t> ic;
 
     /* PBC stuff */
     PbcType pbcType = PbcType::Xyz;
     //! Tells whether atoms inside a molecule can be in different periodic images,
     //  i.e. whether we need to take into account PBC when computing distances inside molecules.
     //  This determines whether PBC must be considered for e.g. bonded interactions.
-    gmx_bool bMolPBC     = FALSE;
-    int      rc_scaling  = 0;
-    rvec     posres_com  = { 0 };
-    rvec     posres_comB = { 0 };
+    bool            bMolPBC     = false;
+    RefCoordScaling rc_scaling  = RefCoordScaling::No;
+    gmx::RVec       posres_com  = { 0, 0, 0 };
+    gmx::RVec       posres_comB = { 0, 0, 0 };
 
-    gmx_bool use_simd_kernels = FALSE;
+    bool use_simd_kernels = false;
 
     /* Interaction for calculated in kernels. In many cases this is similar to
      * the electrostatics settings in the inputrecord, but the difference is that
@@ -206,10 +198,10 @@ struct t_forcerec
      * tabulated we already included the inputrec modification there, so the kernel
      * modification setting will say 'none' in that case.
      */
-    int nbkernel_elec_interaction = 0;
-    int nbkernel_vdw_interaction  = 0;
-    int nbkernel_elec_modifier    = 0;
-    int nbkernel_vdw_modifier     = 0;
+    NbkernelElecType     nbkernel_elec_interaction = NbkernelElecType::None;
+    NbkernelVdwType      nbkernel_vdw_interaction  = NbkernelVdwType::None;
+    InteractionModifiers nbkernel_elec_modifier    = InteractionModifiers::None;
+    InteractionModifiers nbkernel_vdw_modifier     = InteractionModifiers::None;
 
     /* Cut-Off stuff.
      * Infinite cut-off's will be GMX_CUTOFF_INF (unlike in t_inputrec: 0).
@@ -217,9 +209,9 @@ struct t_forcerec
     real rlist = 0;
 
     /* Charge sum for topology A/B ([0]/[1]) for Ewald corrections */
-    double qsum[2]  = { 0 };
-    double q2sum[2] = { 0 };
-    double c6sum[2] = { 0 };
+    std::array<double, 2> qsum  = { 0 };
+    std::array<double, 2> q2sum = { 0 };
+    std::array<double, 2> c6sum = { 0 };
 
     /* Dispersion correction stuff */
     std::unique_ptr<DispersionCorrection> dispersionCorrection;
@@ -227,21 +219,17 @@ struct t_forcerec
     /* Fudge factors */
     real fudgeQQ = 0;
 
-    /* Table stuff */
-    gmx_bool bcoultab = FALSE;
-    gmx_bool bvdwtab  = FALSE;
-
-    t_forcetable* pairsTable = nullptr; /* for 1-4 interactions, [pairs] and [pairs_nb] */
+    std::unique_ptr<t_forcetable> pairsTable; /* for 1-4 interactions, [pairs] and [pairs_nb] */
 
     /* Free energy */
-    int efep = 0;
+    FreeEnergyPerturbationType efep = FreeEnergyPerturbationType::No;
 
     /* Information about atom properties for the molecule blocks in the system */
     std::vector<cginfo_mb_t> cginfo_mb;
     /* Information about atom properties for local and non-local atoms */
     std::vector<int> cginfo;
 
-    rvec* shift_vec = nullptr;
+    std::vector<gmx::RVec> shift_vec;
 
     std::unique_ptr<gmx::WholeMoleculeTransform> wholeMoleculeTransform;
 
@@ -249,8 +237,8 @@ struct t_forcerec
     std::unique_ptr<nonbonded_verlet_t> nbv;
 
     /* The wall tables (if used) */
-    int             nwall    = 0;
-    t_forcetable*** wall_tab = nullptr;
+    int                                                     nwall = 0;
+    std::vector<std::vector<std::unique_ptr<t_forcetable>>> wall_tab;
 
     /* The number of atoms participating in do_force_lowlevel */
     int natoms_force = 0;
@@ -261,17 +249,17 @@ struct t_forcerec
     std::vector<ForceHelperBuffers> forceHelperBuffers;
 
     /* Data for PPPM/PME/Ewald */
-    struct gmx_pme_t* pmedata                = nullptr;
-    int               ljpme_combination_rule = 0;
+    gmx_pme_t*   pmedata                = nullptr;
+    LongRangeVdW ljpme_combination_rule = LongRangeVdW::Geom;
 
     /* PME/Ewald stuff */
-    struct gmx_ewald_tab_t* ewald_table = nullptr;
+    std::unique_ptr<gmx_ewald_tab_t> ewald_table;
 
     /* Non bonded Parameter lists */
-    int               ntype = 0; /* Number of atom types */
-    gmx_bool          bBHAM = FALSE;
+    int               ntype          = 0; /* Number of atom types */
+    bool              haveBuckingham = false;
     std::vector<real> nbfp;
-    real*             ljpme_c6grid = nullptr; /* C6-values used on grid in LJPME */
+    std::vector<real> ljpme_c6grid; /* C6-values used on grid in LJPME */
 
     /* Energy group pair flags */
     int* egp_flags = nullptr;
@@ -312,8 +300,8 @@ struct t_forcerec
     gmx::GpuBonded* gpuBonded = nullptr;
 
     /* Ewald correction thread local virial and energy data */
-    int                         nthread_ewc = 0;
-    struct ewald_corr_thread_t* ewc_t       = nullptr;
+    int                              nthread_ewc = 0;
+    std::vector<ewald_corr_thread_t> ewc_t;
 
     gmx::ForceProviders* forceProviders = nullptr;
 
index b0c15ca8525b9ce873f998b634cf89f8e1055c17..8e708c737d7be5e818ba77b8ab25f461375ab014 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "group.h"
 
+#include "gromacs/utility/exceptions.h"
+
+gmx_ekindata_t::gmx_ekindata_t(int numTempCoupleGroups, real cos_accel, int numThreads) :
+    ngtc(numTempCoupleGroups),
+    nthreads_(numThreads)
+{
+    tcstat.resize(ngtc);
+    /* Set Berendsen tcoupl lambda's to 1,
+     * so runs without Berendsen coupling are not affected.
+     */
+    for (int i = 0; i < ngtc; i++)
+    {
+        tcstat[i].lambda         = 1.0;
+        tcstat[i].vscale_nhc     = 1.0;
+        tcstat[i].ekinscaleh_nhc = 1.0;
+        tcstat[i].ekinscalef_nhc = 1.0;
+    }
+
+    snew(ekin_work_alloc, nthreads_);
+    snew(ekin_work, nthreads_);
+    snew(dekindl_work, nthreads_);
+
+#pragma omp parallel for num_threads(nthreads_) schedule(static)
+    for (int thread = 0; thread < nthreads_; thread++)
+    {
+        try
+        {
+            constexpr int EKIN_WORK_BUFFER_SIZE = 2;
+            /* Allocate 2 extra elements on both sides, so in single
+             * precision we have
+             * EKIN_WORK_BUFFER_SIZE*DIM*DIM*sizeof(real) = 72/144 bytes
+             * buffer on both sides to avoid cache pollution.
+             */
+            snew(ekin_work_alloc[thread], ngtc + 2 * EKIN_WORK_BUFFER_SIZE);
+            ekin_work[thread] = ekin_work_alloc[thread] + EKIN_WORK_BUFFER_SIZE;
+            /* Nasty hack so we can have the per-thread accumulation
+             * variable for dekindl in the same thread-local cache lines
+             * as the per-thread accumulation tensors for ekin[fh],
+             * because they are accumulated in the same loop. */
+            dekindl_work[thread] = &(ekin_work[thread][ngtc][0][0]);
+        }
+        GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
+    }
+
+    cosacc.cos_accel = cos_accel;
+}
+
 gmx_ekindata_t::~gmx_ekindata_t()
 {
-    for (int i = 0; i < nthreads; i++)
+    for (int i = 0; i < nthreads_; i++)
     {
         sfree(ekin_work_alloc[i]);
     }
index d39e7c8cb5cefe5e0e547a439cc408a5f975f7d0..27ebd8e1be21fc67d5f780f55748917960a9efe2 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,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -40,7 +40,6 @@
 #include <vector>
 
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 #include "gromacs/utility/smalloc.h"
 
@@ -66,20 +65,6 @@ struct t_grp_tcstat
     double vscale_nhc = 0;
 };
 
-struct t_grp_acc
-{
-    //! Number of atoms in this group
-    int nat = 0;
-    //! Mean velocities of home particles
-    rvec u = { 0 };
-    //! Previous mean velocities of home particles
-    rvec uold = { 0 };
-    //! Mass for topology A
-    double mA = 0;
-    //! Mass for topology B
-    double mB = 0;
-};
-
 struct t_cos_acc
 {
     //! The acceleration for the cosine profile
@@ -90,14 +75,12 @@ struct t_cos_acc
     real vcos = 0;
 };
 
-struct gmx_ekindata_t
+class gmx_ekindata_t
 {
-    //! Whether non-equilibrium MD is active (ie. constant or cosine acceleration)
-    gmx_bool bNEMD;
+public:
+    gmx_ekindata_t(int numTempCoupleGroups, real cos_accel, int numThreads);
     //! The number of T-coupling groups
-    int ngtc = 0;
-    //! For size of ekin_work
-    int nthreads = 0;
+    int ngtc;
     //! T-coupling data
     std::vector<t_grp_tcstat> tcstat;
     //! Allocated locations for *_work members
@@ -106,10 +89,6 @@ struct gmx_ekindata_t
     tensor** ekin_work = nullptr;
     //! Work location for dekindl per thread
     real** dekindl_work = nullptr;
-    //! The number of acceleration groups
-    int ngacc = 0;
-    //! Acceleration data
-    std::vector<t_grp_acc> grpstat;
     //! overall kinetic energy
     tensor ekin = { { 0 } };
     //! overall 1/2 step kinetic energy
@@ -122,6 +101,10 @@ struct gmx_ekindata_t
     t_cos_acc cosacc;
 
     ~gmx_ekindata_t();
+
+private:
+    //! For size of ekin_work
+    int nthreads_ = 0;
 };
 
 #define GID(igid, jgid, gnr) \
index 52a50e509757078593ca192344dd05bcb5443797..6ae3730fc84a12ac39b9901e473536e276601dac 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ bool ForceProviders::hasForceProvider() const
 void ForceProviders::calculateForces(const ForceProviderInput& forceProviderInput,
                                      ForceProviderOutput*      forceProviderOutput) const
 {
-    for (auto provider : impl_->providers_)
+    for (auto* provider : impl_->providers_)
     {
         provider->calculateForces(forceProviderInput, forceProviderOutput);
     }
index f15de6adb785f6e30821550a028cb0ce3e14395a..3006bf88e971914fe5786a54ed72b97cde1b2a5f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_IFORCEPROVIDER_H
 #define GMX_MDTYPES_IFORCEPROVIDER_H
 
+#include <memory>
+
 #include "gromacs/math/vec.h"
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/gmxassert.h"
 
 struct gmx_enerdata_t;
 struct t_commrec;
 struct t_forcerec;
-struct t_mdatoms;
 
 namespace gmx
 {
@@ -81,28 +81,36 @@ class ForceProviderInput
 public:
     /*! \brief Constructor assembles all necessary force provider input data
      *
-     * \param[in]  x        Atomic positions
-     * \param[in]  cr       Communication record structure
-     * \param[in]  box      The simulation box
-     * \param[in]  time     The current time in the simulation
-     * \param[in]  mdatoms  The atomic data
+     * \param[in]  x        Atomic positions.
+     * \param[in]  homenr   Number of atoms on the domain.
+     * \param[in]  chargeA  Atomic charges for atoms on the domain.
+     * \param[in]  massT    Atomic masses for atoms on the domain.
+     * \param[in]  time     The current time in the simulation.
+     * \param[in]  box      The simulation box.
+     * \param[in]  cr       Communication record structure.
      */
     ForceProviderInput(ArrayRef<const RVec> x,
-                       const t_mdatoms&     mdatoms,
+                       int                  homenr,
+                       ArrayRef<const real> chargeA,
+                       ArrayRef<const real> massT,
                        double               time,
                        const matrix         box,
                        const t_commrec&     cr) :
         x_(x),
-        mdatoms_(mdatoms),
+        homenr_(homenr),
+        chargeA_(chargeA),
+        massT_(massT),
         t_(time),
         cr_(cr)
     {
         copy_mat(box, box_);
     }
 
-    ArrayRef<const RVec> x_;       //!< The atomic positions
-    const t_mdatoms&     mdatoms_; //!< Atomic data
-    double               t_;       //!< The current time in the simulation
+    ArrayRef<const RVec> x_; //!< The atomic positions
+    int                  homenr_;
+    ArrayRef<const real> chargeA_;
+    ArrayRef<const real> massT_;
+    double               t_; //!< The current time in the simulation
     matrix               box_ = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; //!< The simulation box
     const t_commrec&     cr_; //!< Communication record structure
 };
@@ -200,7 +208,7 @@ public:
 private:
     class Impl;
 
-    gmx::PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 83283417b4873cfa1b0ef9d52d0c47db6725c25b..2f5dde528e93a6aca159a77f5826dd1955df19a2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,7 +51,7 @@ namespace gmx
 class ForceProviders;
 class IMDOutputProvider;
 class IMdpOptionProvider;
-struct MdModulesNotifier;
+struct MDModulesNotifiers;
 
 /*! \libinternal \brief
  * Extension module for \Gromacs simulations.
@@ -75,9 +75,9 @@ public:
     //! Initializes force providers from this module.
     virtual void initForceProviders(ForceProviders* forceProviders) = 0;
     //! Subscribe to simulation setup notifications
-    virtual void subscribeToSimulationSetupNotifications(MdModulesNotifier* notifier) = 0;
+    virtual void subscribeToSimulationSetupNotifications(MDModulesNotifiers* notifiers) = 0;
     //! Subscribe to pre processing notifications
-    virtual void subscribeToPreProcessingNotifications(MdModulesNotifier* notifier) = 0;
+    virtual void subscribeToPreProcessingNotifications(MDModulesNotifiers* notifiers) = 0;
 };
 
 } // namespace gmx
index 05a09523fbaa3909a97b16532397a7f8e4e0e899..de1626255cea0fffe1f17ebc732a86dc60821151 100644 (file)
@@ -37,6 +37,7 @@
  */
 #include "gmxpre.h"
 
+#include "gromacs/utility/enumerationhelpers.h"
 #include "inputrec.h"
 
 #include <cstdio>
 #include <cstring>
 
 #include <algorithm>
+#include <memory>
 #include <numeric>
 
+#include "gromacs/applied_forces/awh/read_params.h"
 #include "gromacs/math/veccompare.h"
 #include "gromacs/math/vecdump.h"
 #include "gromacs/mdtypes/awh_params.h"
@@ -88,9 +91,9 @@ t_inputrec::t_inputrec()
     // TODO When this memset is removed, remove the suppression of
     // gcc -Wno-class-memaccess in a CMakeLists.txt file.
     std::memset(this, 0, sizeof(*this)); // NOLINT(bugprone-undefined-memory-manipulation)
-    snew(fepvals, 1);
-    snew(expandedvals, 1);
-    snew(simtempvals, 1);
+    fepvals      = std::make_unique<t_lambda>();
+    expandedvals = std::make_unique<t_expanded>();
+    simtempvals  = std::make_unique<t_simtemp>();
 }
 
 t_inputrec::~t_inputrec()
@@ -119,22 +122,22 @@ int ir_optimal_nstcalcenergy(const t_inputrec* ir)
     return nst;
 }
 
-int tcouple_min_integration_steps(int etc)
+int tcouple_min_integration_steps(TemperatureCoupling etc)
 {
     int n;
 
     switch (etc)
     {
-        case etcNO: n = 0; break;
-        case etcBERENDSEN:
-        case etcYES: n = nstmin_berendsen_tcouple; break;
-        case etcVRESCALE:
+        case TemperatureCoupling::No: n = 0; break;
+        case TemperatureCoupling::Berendsen:
+        case TemperatureCoupling::Yes: n = nstmin_berendsen_tcouple; break;
+        case TemperatureCoupling::VRescale:
             /* V-rescale supports instantaneous rescaling */
             n = 0;
             break;
-        case etcNOSEHOOVER: n = nstmin_harmonic; break;
-        case etcANDERSEN:
-        case etcANDERSENMASSIVE: n = 1; break;
+        case TemperatureCoupling::NoseHoover: n = nstmin_harmonic; break;
+        case TemperatureCoupling::Andersen:
+        case TemperatureCoupling::AndersenMassive: n = 1; break;
         default: gmx_incons("Unknown etc value");
     }
 
@@ -152,7 +155,7 @@ int ir_optimal_nsttcouple(const t_inputrec* ir)
     nwanted = c_defaultNstTCouple;
 
     tau_min = 1e20;
-    if (ir->etc != etcNO)
+    if (ir->etc != TemperatureCoupling::No)
     {
         for (g = 0; g < ir->opts.ngtc; g++)
         {
@@ -183,18 +186,18 @@ int ir_optimal_nsttcouple(const t_inputrec* ir)
     return n;
 }
 
-int pcouple_min_integration_steps(int epc)
+int pcouple_min_integration_steps(PressureCoupling epc)
 {
     int n;
 
     switch (epc)
     {
-        case epcNO: n = 0; break;
-        case epcBERENDSEN:
-        case epcCRESCALE:
-        case epcISOTROPIC: n = nstmin_berendsen_pcouple; break;
-        case epcPARRINELLORAHMAN:
-        case epcMTTK: n = nstmin_harmonic; break;
+        case PressureCoupling::No: n = 0; break;
+        case PressureCoupling::Berendsen:
+        case PressureCoupling::CRescale:
+        case PressureCoupling::Isotropic: n = nstmin_berendsen_pcouple; break;
+        case PressureCoupling::ParrinelloRahman:
+        case PressureCoupling::Mttk: n = nstmin_harmonic; break;
         default: gmx_incons("Unknown epc value");
     }
 
@@ -243,48 +246,43 @@ int ir_optimal_nstpcouple(const t_inputrec* ir)
 
 gmx_bool ir_coulomb_switched(const t_inputrec* ir)
 {
-    return (ir->coulombtype == eelSWITCH || ir->coulombtype == eelSHIFT
-            || ir->coulombtype == eelPMESWITCH || ir->coulombtype == eelPMEUSERSWITCH
-            || ir->coulomb_modifier == eintmodPOTSWITCH || ir->coulomb_modifier == eintmodFORCESWITCH);
+    return (ir->coulombtype == CoulombInteractionType::Switch
+            || ir->coulombtype == CoulombInteractionType::Shift
+            || ir->coulombtype == CoulombInteractionType::PmeSwitch
+            || ir->coulombtype == CoulombInteractionType::PmeUserSwitch
+            || ir->coulomb_modifier == InteractionModifiers::PotSwitch
+            || ir->coulomb_modifier == InteractionModifiers::ForceSwitch);
 }
 
 gmx_bool ir_coulomb_is_zero_at_cutoff(const t_inputrec* ir)
 {
-    return (ir->cutoff_scheme == ecutsVERLET || ir_coulomb_switched(ir)
-            || ir->coulomb_modifier != eintmodNONE || ir->coulombtype == eelRF_ZERO);
+    return (ir->cutoff_scheme == CutoffScheme::Verlet || ir_coulomb_switched(ir)
+            || ir->coulomb_modifier != InteractionModifiers::None
+            || ir->coulombtype == CoulombInteractionType::RFZero);
 }
 
 gmx_bool ir_coulomb_might_be_zero_at_cutoff(const t_inputrec* ir)
 {
-    return (ir_coulomb_is_zero_at_cutoff(ir) || ir->coulombtype == eelUSER || ir->coulombtype == eelPMEUSER);
+    return (ir_coulomb_is_zero_at_cutoff(ir) || ir->coulombtype == CoulombInteractionType::User
+            || ir->coulombtype == CoulombInteractionType::PmeUser);
 }
 
 gmx_bool ir_vdw_switched(const t_inputrec* ir)
 {
-    return (ir->vdwtype == evdwSWITCH || ir->vdwtype == evdwSHIFT
-            || ir->vdw_modifier == eintmodPOTSWITCH || ir->vdw_modifier == eintmodFORCESWITCH);
+    return (ir->vdwtype == VanDerWaalsType::Switch || ir->vdwtype == VanDerWaalsType::Shift
+            || ir->vdw_modifier == InteractionModifiers::PotSwitch
+            || ir->vdw_modifier == InteractionModifiers::ForceSwitch);
 }
 
 gmx_bool ir_vdw_is_zero_at_cutoff(const t_inputrec* ir)
 {
-    return (ir->cutoff_scheme == ecutsVERLET || ir_vdw_switched(ir) || ir->vdw_modifier != eintmodNONE);
+    return (ir->cutoff_scheme == CutoffScheme::Verlet || ir_vdw_switched(ir)
+            || ir->vdw_modifier != InteractionModifiers::None);
 }
 
 gmx_bool ir_vdw_might_be_zero_at_cutoff(const t_inputrec* ir)
 {
-    return (ir_vdw_is_zero_at_cutoff(ir) || ir->vdwtype == evdwUSER);
-}
-
-static void done_lambdas(t_lambda* fep)
-{
-    if (fep->n_lambda > 0)
-    {
-        for (int i = 0; i < efptNR; i++)
-        {
-            sfree(fep->all_lambda[i]);
-        }
-    }
-    sfree(fep->all_lambda);
+    return (ir_vdw_is_zero_at_cutoff(ir) || ir->vdwtype == VanDerWaalsType::User);
 }
 
 static void done_t_rot(t_rot* rot)
@@ -305,6 +303,21 @@ static void done_t_rot(t_rot* rot)
     sfree(rot);
 }
 
+static void done_t_swapCoords(t_swapcoords* swapCoords)
+{
+    if (swapCoords == nullptr)
+    {
+        return;
+    }
+    for (int i = 0; i < swapCoords->ngrp; i++)
+    {
+        sfree(swapCoords->grp[i].ind);
+        sfree(swapCoords->grp[i].molname);
+    }
+    sfree(swapCoords->grp);
+    sfree(swapCoords);
+}
+
 void done_inputrec(t_inputrec* ir)
 {
     sfree(ir->opts.nrdf);
@@ -319,14 +332,10 @@ void done_inputrec(t_inputrec* ir)
     sfree(ir->opts.anneal_time);
     sfree(ir->opts.anneal_temp);
     sfree(ir->opts.tau_t);
-    sfree(ir->opts.acc);
     sfree(ir->opts.nFreeze);
     sfree(ir->opts.egp_flags);
-    done_lambdas(ir->fepvals);
-    sfree(ir->fepvals);
-    sfree(ir->expandedvals);
-    sfree(ir->simtempvals);
 
+    done_t_swapCoords(ir->swap);
     done_t_rot(ir->rot);
     delete ir->params;
 }
@@ -368,7 +377,7 @@ static void pr_grp_opts(FILE* out, int indent, const char* title, const t_grpopt
     fprintf(out, "annealing%s", bMDPformat ? " = " : ":");
     for (i = 0; (i < opts->ngtc); i++)
     {
-        fprintf(out, "  %10s", EANNEAL(opts->annealing[i]));
+        fprintf(out, "  %10s", enumValueToString(opts->annealing[i]));
     }
     fprintf(out, "\n");
 
@@ -398,17 +407,6 @@ static void pr_grp_opts(FILE* out, int indent, const char* title, const t_grpopt
         }
     }
 
-    pr_indent(out, indent);
-    fprintf(out, "acc:\t");
-    for (i = 0; (i < opts->ngacc); i++)
-    {
-        for (m = 0; (m < DIM); m++)
-        {
-            fprintf(out, "  %10g", opts->acc[i][m]);
-        }
-    }
-    fprintf(out, "\n");
-
     pr_indent(out, indent);
     fprintf(out, "nfreeze:");
     for (i = 0; (i < opts->ngfrz); i++)
@@ -439,8 +437,15 @@ static void pr_matrix(FILE* fp, int indent, const char* title, const rvec* m, gm
 {
     if (bMDPformat)
     {
-        fprintf(fp, "%-10s    = %g %g %g %g %g %g\n", title, m[XX][XX], m[YY][YY], m[ZZ][ZZ],
-                m[XX][YY], m[XX][ZZ], m[YY][ZZ]);
+        fprintf(fp,
+                "%-10s    = %g %g %g %g %g %g\n",
+                title,
+                m[XX][XX],
+                m[YY][YY],
+                m[ZZ][ZZ],
+                m[XX][YY],
+                m[XX][ZZ],
+                m[YY][ZZ]);
     }
     else
     {
@@ -470,12 +475,12 @@ static void pr_pull_coord(FILE* fp, int indent, int c, const t_pull_coord* pcrd)
 
     pr_indent(fp, indent);
     fprintf(fp, "pull-coord %d:\n", c);
-    PS("type", EPULLTYPE(pcrd->eType));
-    if (pcrd->eType == epullEXTERNAL)
+    PS("type", enumValueToString(pcrd->eType));
+    if (pcrd->eType == PullingAlgorithm::External)
     {
         PS("potential-provider", pcrd->externalPotentialProvider.c_str());
     }
-    PS("geometry", EPULLGEOM(pcrd->eGeom));
+    PS("geometry", enumValueToString(pcrd->eGeom));
     for (g = 0; g < pcrd->ngroup; g++)
     {
         char buf[STRLEN];
@@ -495,36 +500,36 @@ static void pr_pull_coord(FILE* fp, int indent, int c, const t_pull_coord* pcrd)
 
 static void pr_simtempvals(FILE* fp, int indent, const t_simtemp* simtemp, int n_lambda)
 {
-    PS("simulated-tempering-scaling", ESIMTEMP(simtemp->eSimTempScale));
+    PS("simulated-tempering-scaling", enumValueToString(simtemp->eSimTempScale));
     PR("sim-temp-low", simtemp->simtemp_low);
     PR("sim-temp-high", simtemp->simtemp_high);
-    pr_rvec(fp, indent, "simulated tempering temperatures", simtemp->temperatures, n_lambda, TRUE);
+    pr_rvec(fp, indent, "simulated tempering temperatures", simtemp->temperatures.data(), n_lambda, TRUE);
 }
 
 static void pr_expandedvals(FILE* fp, int indent, const t_expanded* expand, int n_lambda)
 {
 
     PI("nstexpanded", expand->nstexpanded);
-    PS("lmc-stats", elamstats_names[expand->elamstats]);
-    PS("lmc-move", elmcmove_names[expand->elmcmove]);
-    PS("lmc-weights-equil", elmceq_names[expand->elmceq]);
-    if (expand->elmceq == elmceqNUMATLAM)
+    PS("lmc-stats", enumValueToString(expand->elamstats));
+    PS("lmc-move", enumValueToString(expand->elmcmove));
+    PS("lmc-weights-equil", enumValueToString(expand->elmceq));
+    if (expand->elmceq == LambdaWeightWillReachEquilibrium::NumAtLambda)
     {
         PI("weight-equil-number-all-lambda", expand->equil_n_at_lam);
     }
-    if (expand->elmceq == elmceqSAMPLES)
+    if (expand->elmceq == LambdaWeightWillReachEquilibrium::Samples)
     {
         PI("weight-equil-number-samples", expand->equil_samples);
     }
-    if (expand->elmceq == elmceqSTEPS)
+    if (expand->elmceq == LambdaWeightWillReachEquilibrium::Steps)
     {
         PI("weight-equil-number-steps", expand->equil_steps);
     }
-    if (expand->elmceq == elmceqWLDELTA)
+    if (expand->elmceq == LambdaWeightWillReachEquilibrium::WLDelta)
     {
         PR("weight-equil-wl-delta", expand->equil_wl_delta);
     }
-    if (expand->elmceq == elmceqRATIO)
+    if (expand->elmceq == LambdaWeightWillReachEquilibrium::Ratio)
     {
         PR("weight-equil-count-ratio", expand->equil_ratio);
     }
@@ -543,13 +548,13 @@ static void pr_expandedvals(FILE* fp, int indent, const t_expanded* expand, int
     PS("wl-oneovert", EBOOL(expand->bWLoneovert));
 
     pr_indent(fp, indent);
-    pr_rvec(fp, indent, "init-lambda-weights", expand->init_lambda_weights, n_lambda, TRUE);
+    pr_rvec(fp, indent, "init-lambda-weights", expand->init_lambda_weights.data(), n_lambda, TRUE);
     PS("init-weights", EBOOL(expand->bInit_weights));
 }
 
 static void pr_fepvals(FILE* fp, int indent, const t_lambda* fep, gmx_bool bMDPformat)
 {
-    int i, j;
+    int j;
 
     PR("init-lambda", fep->init_lambda);
     PI("init-lambda-state", fep->init_fep_state);
@@ -564,9 +569,9 @@ static void pr_fepvals(FILE* fp, int indent, const t_lambda* fep, gmx_bool bMDPf
     {
         pr_indent(fp, indent);
         fprintf(fp, "separate-dvdl%s\n", bMDPformat ? " = " : ":");
-        for (i = 0; i < efptNR; i++)
+        for (auto i : gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, bool>::keys())
         {
-            fprintf(fp, "%18s = ", efpt_names[i]);
+            fprintf(fp, "%18s = ", enumValueToString(i));
             if (fep->separate_dvdl[i])
             {
                 fprintf(fp, "  TRUE");
@@ -578,9 +583,10 @@ static void pr_fepvals(FILE* fp, int indent, const t_lambda* fep, gmx_bool bMDPf
             fprintf(fp, "\n");
         }
         fprintf(fp, "all-lambdas%s\n", bMDPformat ? " = " : ":");
-        for (i = 0; i < efptNR; i++)
+        for (auto key : gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, bool>::keys())
         {
-            fprintf(fp, "%18s = ", efpt_names[i]);
+            fprintf(fp, "%18s = ", enumValueToString(key));
+            int i = static_cast<int>(key);
             for (j = 0; j < fep->n_lambda; j++)
             {
                 fprintf(fp, "  %10g", fep->all_lambda[i][j]);
@@ -589,7 +595,7 @@ static void pr_fepvals(FILE* fp, int indent, const t_lambda* fep, gmx_bool bMDPf
         }
     }
     PI("calc-lambda-neighbors", fep->lambda_neighbors);
-    PS("dhdl-print-energy", edHdLPrintEnergy_names[fep->edHdLPrintEnergy]);
+    PS("dhdl-print-energy", enumValueToString(fep->edHdLPrintEnergy));
     PR("sc-alpha", fep->sc_alpha);
     PI("sc-power", fep->sc_power);
     PR("sc-r-power", fep->sc_r_power);
@@ -598,8 +604,8 @@ static void pr_fepvals(FILE* fp, int indent, const t_lambda* fep, gmx_bool bMDPf
     PS("sc-coul", EBOOL(fep->bScCoul));
     PI("dh-hist-size", fep->dh_hist_size);
     PD("dh-hist-spacing", fep->dh_hist_spacing);
-    PS("separate-dhdl-file", SEPDHDLFILETYPE(fep->separate_dhdl_file));
-    PS("dhdl-derivatives", DHDLDERIVATIVESTYPE(fep->dhdl_derivatives));
+    PS("separate-dhdl-file", enumValueToString(fep->separate_dhdl_file));
+    PS("dhdl-derivatives", enumValueToString(fep->dhdl_derivatives));
 };
 
 static void pr_pull(FILE* fp, int indent, const pull_params_t& pull)
@@ -628,66 +634,70 @@ static void pr_pull(FILE* fp, int indent, const pull_params_t& pull)
     }
 }
 
-static void pr_awh_bias_dim(FILE* fp, int indent, gmx::AwhDimParams* awhDimParams, const char* prefix)
+static void pr_awh_bias_dim(FILE* fp, int indent, const gmx::AwhDimParams& awhDimParams, const char* prefix)
 {
     pr_indent(fp, indent);
     indent++;
     fprintf(fp, "%s:\n", prefix);
-    PS("coord-provider", EAWHCOORDPROVIDER(awhDimParams->eCoordProvider));
-    PI("coord-index", awhDimParams->coordIndex + 1);
-    PR("start", awhDimParams->origin);
-    PR("end", awhDimParams->end);
-    PR("period", awhDimParams->period);
-    PR("force-constant", awhDimParams->forceConstant);
-    PR("diffusion", awhDimParams->diffusion);
-    PR("cover-diameter", awhDimParams->coverDiameter);
+    PS("coord-provider", enumValueToString(awhDimParams.coordinateProvider()));
+    PI("coord-index", awhDimParams.coordinateIndex() + 1);
+    PR("start", awhDimParams.origin());
+    PR("end", awhDimParams.end());
+    PR("period", awhDimParams.period());
+    PR("force-constant", awhDimParams.forceConstant());
+    PR("diffusion", awhDimParams.diffusion());
+    PR("cover-diameter", awhDimParams.coverDiameter());
 }
 
-static void pr_awh_bias(FILE* fp, int indent, gmx::AwhBiasParams* awhBiasParams, const char* prefix)
+static void pr_awh_bias(FILE* fp, int indent, const gmx::AwhBiasParams& awhBiasParams, const char* prefix)
 {
     char opt[STRLEN];
 
     sprintf(opt, "%s-error-init", prefix);
-    PR(opt, awhBiasParams->errorInitial);
+    PR(opt, awhBiasParams.initialErrorEstimate());
     sprintf(opt, "%s-growth", prefix);
-    PS(opt, EAWHGROWTH(awhBiasParams->eGrowth));
+    PS(opt, enumValueToString(awhBiasParams.growthType()));
     sprintf(opt, "%s-target", prefix);
-    PS(opt, EAWHTARGET(awhBiasParams->eTarget));
+    PS(opt, enumValueToString(awhBiasParams.targetDistribution()));
     sprintf(opt, "%s-target-beta-scalng", prefix);
-    PR(opt, awhBiasParams->targetBetaScaling);
+    PR(opt, awhBiasParams.targetBetaScaling());
     sprintf(opt, "%s-target-cutoff", prefix);
-    PR(opt, awhBiasParams->targetCutoff);
+    PR(opt, awhBiasParams.targetCutoff());
     sprintf(opt, "%s-user-data", prefix);
-    PS(opt, EBOOL(awhBiasParams->bUserData));
+    PS(opt, EBOOL(awhBiasParams.userPMFEstimate()));
     sprintf(opt, "%s-share-group", prefix);
-    PI(opt, awhBiasParams->shareGroup);
+    PI(opt, awhBiasParams.shareGroup());
     sprintf(opt, "%s-equilibrate-histogram", prefix);
-    PS(opt, EBOOL(awhBiasParams->equilibrateHistogram));
+    PS(opt, EBOOL(awhBiasParams.equilibrateHistogram()));
     sprintf(opt, "%s-ndim", prefix);
-    PI(opt, awhBiasParams->ndim);
+    PI(opt, awhBiasParams.ndim());
 
-    for (int d = 0; d < awhBiasParams->ndim; d++)
+    int d = 0;
+    for (const auto& dimParam : awhBiasParams.dimParams())
     {
         char prefixdim[STRLEN];
         sprintf(prefixdim, "%s-dim%d", prefix, d + 1);
-        pr_awh_bias_dim(fp, indent, &awhBiasParams->dimParams[d], prefixdim);
+        pr_awh_bias_dim(fp, indent, dimParam, prefixdim);
+        d++;
     }
 }
 
 static void pr_awh(FILE* fp, int indent, gmx::AwhParams* awhParams)
 {
-    PS("awh-potential", EAWHPOTENTIAL(awhParams->ePotential));
-    PI("awh-seed", awhParams->seed);
-    PI("awh-nstout", awhParams->nstOut);
-    PI("awh-nstsample", awhParams->nstSampleCoord);
-    PI("awh-nsamples-update", awhParams->numSamplesUpdateFreeEnergy);
-    PS("awh-share-bias-multisim", EBOOL(awhParams->shareBiasMultisim));
-    PI("awh-nbias", awhParams->numBias);
+    PS("awh-potential", enumValueToString(awhParams->potential()));
+    PI("awh-seed", awhParams->seed());
+    PI("awh-nstout", awhParams->nstout());
+    PI("awh-nstsample", awhParams->nstSampleCoord());
+    PI("awh-nsamples-update", awhParams->numSamplesUpdateFreeEnergy());
+    PS("awh-share-bias-multisim", EBOOL(awhParams->shareBiasMultisim()));
+    PI("awh-nbias", awhParams->numBias());
 
-    for (int k = 0; k < awhParams->numBias; k++)
+    int k = 0;
+    for (const auto& awhBiasParam : awhParams->awhBiasParams())
     {
         auto prefix = gmx::formatString("awh%d", k + 1);
-        pr_awh_bias(fp, indent, &awhParams->awhBiasParams[k], prefix.c_str());
+        pr_awh_bias(fp, indent, awhBiasParam, prefix.c_str());
+        k++;
     }
 }
 
@@ -696,7 +706,7 @@ static void pr_rotgrp(FILE* fp, int indent, int g, const t_rotgrp* rotg)
     pr_indent(fp, indent);
     fprintf(fp, "rot-group %d:\n", g);
     indent += 2;
-    PS("rot-type", EROTGEOM(rotg->eType));
+    PS("rot-type", enumValueToString(rotg->eType));
     PS("rot-massw", EBOOL(rotg->bMassW));
     pr_ivec_block(fp, indent, "atom", rotg->ind, rotg->nat, TRUE);
     pr_rvecs(fp, indent, "x-ref", rotg->x_ref, rotg->nat);
@@ -707,7 +717,7 @@ static void pr_rotgrp(FILE* fp, int indent, int g, const t_rotgrp* rotg)
     PR("rot-slab-dist", rotg->slab_dist);
     PR("rot-min-gauss", rotg->min_gaussian);
     PR("rot-eps", rotg->eps);
-    PS("rot-fit-method", EROTFIT(rotg->eFittype));
+    PS("rot-fit-method", enumValueToString(rotg->eFittype));
     PI("rot-potfit-nstep", rotg->PotAngle_nstep);
     PR("rot-potfit-step", rotg->PotAngle_step);
 }
@@ -750,11 +760,19 @@ static void pr_swap(FILE* fp, int indent, const t_swapcoords* swap)
     }
 
     /* The solvent group */
-    snprintf(str, STRLEN, "solvent group %s", swap->grp[eGrpSolvent].molname);
-    pr_ivec_block(fp, indent, str, swap->grp[eGrpSolvent].ind, swap->grp[eGrpSolvent].nat, TRUE);
+    snprintf(str,
+             STRLEN,
+             "solvent group %s",
+             swap->grp[static_cast<int>(SwapGroupSplittingType::Solvent)].molname);
+    pr_ivec_block(fp,
+                  indent,
+                  str,
+                  swap->grp[static_cast<int>(SwapGroupSplittingType::Solvent)].ind,
+                  swap->grp[static_cast<int>(SwapGroupSplittingType::Solvent)].nat,
+                  TRUE);
 
     /* Now print the indices for all the ion groups: */
-    for (int ig = eSwapFixedGrpNR; ig < swap->ngrp; ig++)
+    for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < swap->ngrp; ig++)
     {
         snprintf(str, STRLEN, "ion group %s", swap->grp[ig].molname);
         pr_ivec_block(fp, indent, str, swap->grp[ig].ind, swap->grp[ig].nat, TRUE);
@@ -771,7 +789,7 @@ static void pr_swap(FILE* fp, int indent, const t_swapcoords* swap)
     /* Print the requested ion counts for both compartments */
     for (int ic = eCompA; ic <= eCompB; ic++)
     {
-        for (int ig = eSwapFixedGrpNR; ig < swap->ngrp; ig++)
+        for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < swap->ngrp; ig++)
         {
             snprintf(str, STRLEN, "%s-in-%c", swap->grp[ig].molname, 'A' + ic);
             PI(str, swap->grp[ig].nmolReq[ic]);
@@ -805,7 +823,7 @@ void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir,
          * options are written in the default mdout.mdp, and with
          * the same user-exposed names to facilitate debugging.
          */
-        PS("integrator", EI(ir->eI));
+        PS("integrator", enumValueToString(ir->eI));
         PR("tinit", ir->init_t);
         PR("dt", ir->delta_t);
         PSTEP("nsteps", ir->nsteps);
@@ -835,7 +853,7 @@ void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir,
                 PI(factorKey.c_str(), mtsLevel.stepFactor);
             }
         }
-        PS("comm-mode", ECOM(ir->comm_mode));
+        PS("comm-mode", enumValueToString(ir->comm_mode));
         PI("nstcomm", ir->nstcomm);
 
         /* Langevin dynamics */
@@ -864,7 +882,7 @@ void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir,
         PR("compressed-x-precision", ir->x_compression_precision);
 
         /* Neighborsearching parameters */
-        PS("cutoff-scheme", ECUTSCHEME(ir->cutoff_scheme));
+        PS("cutoff-scheme", enumValueToString(ir->cutoff_scheme));
         PI("nstlist", ir->nstlist);
         PS("pbc", c_pbcTypeNames[ir->pbcType].c_str());
         PS("periodic-molecules", EBOOL(ir->bPeriodicMols));
@@ -872,8 +890,8 @@ void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir,
         PR("rlist", ir->rlist);
 
         /* Options for electrostatics and VdW */
-        PS("coulombtype", EELTYPE(ir->coulombtype));
-        PS("coulomb-modifier", INTMODIFIER(ir->coulomb_modifier));
+        PS("coulombtype", enumValueToString(ir->coulombtype));
+        PS("coulomb-modifier", enumValueToString(ir->coulomb_modifier));
         PR("rcoulomb-switch", ir->rcoulomb_switch);
         PR("rcoulomb", ir->rcoulomb);
         if (ir->epsilon_r != 0)
@@ -892,11 +910,11 @@ void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir,
         {
             PS("epsilon-rf", infbuf);
         }
-        PS("vdw-type", EVDWTYPE(ir->vdwtype));
-        PS("vdw-modifier", INTMODIFIER(ir->vdw_modifier));
+        PS("vdw-type", enumValueToString(ir->vdwtype));
+        PS("vdw-modifier", enumValueToString(ir->vdw_modifier));
         PR("rvdw-switch", ir->rvdw_switch);
         PR("rvdw", ir->rvdw);
-        PS("DispCorr", EDISPCORR(ir->eDispCorr));
+        PS("DispCorr", enumValueToString(ir->eDispCorr));
         PR("table-extension", ir->tabext);
 
         PR("fourierspacing", ir->fourier_spacing);
@@ -906,30 +924,28 @@ void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir,
         PI("pme-order", ir->pme_order);
         PR("ewald-rtol", ir->ewald_rtol);
         PR("ewald-rtol-lj", ir->ewald_rtol_lj);
-        PS("lj-pme-comb-rule", ELJPMECOMBNAMES(ir->ljpme_combination_rule));
-        PR("ewald-geometry", ir->ewald_geometry);
+        PS("lj-pme-comb-rule", enumValueToString(ir->ljpme_combination_rule));
+        PS("ewald-geometry", enumValueToString(ir->ewald_geometry));
         PR("epsilon-surface", ir->epsilon_surface);
 
         /* Options for weak coupling algorithms */
-        PS("tcoupl", ETCOUPLTYPE(ir->etc));
+        PS("tcoupl", enumValueToString(ir->etc));
         PI("nsttcouple", ir->nsttcouple);
         PI("nh-chain-length", ir->opts.nhchainlength);
         PS("print-nose-hoover-chain-variables", EBOOL(ir->bPrintNHChains));
 
-        PS("pcoupl", EPCOUPLTYPE(ir->epc));
-        PS("pcoupltype", EPCOUPLTYPETYPE(ir->epct));
+        PS("pcoupl", enumValueToString(ir->epc));
+        PS("pcoupltype", enumValueToString(ir->epct));
         PI("nstpcouple", ir->nstpcouple);
         PR("tau-p", ir->tau_p);
         pr_matrix(fp, indent, "compressibility", ir->compress, bMDPformat);
         pr_matrix(fp, indent, "ref-p", ir->ref_p, bMDPformat);
-        PS("refcoord-scaling", EREFSCALINGTYPE(ir->refcoord_scaling));
+        PS("refcoord-scaling", enumValueToString(ir->refcoord_scaling));
 
         if (bMDPformat)
         {
-            fprintf(fp, "posres-com  = %g %g %g\n", ir->posres_com[XX], ir->posres_com[YY],
-                    ir->posres_com[ZZ]);
-            fprintf(fp, "posres-comB = %g %g %g\n", ir->posres_comB[XX], ir->posres_comB[YY],
-                    ir->posres_comB[ZZ]);
+            fprintf(fp, "posres-com  = %g %g %g\n", ir->posres_com[XX], ir->posres_com[YY], ir->posres_com[ZZ]);
+            fprintf(fp, "posres-comB = %g %g %g\n", ir->posres_comB[XX], ir->posres_comB[YY], ir->posres_comB[ZZ]);
         }
         else
         {
@@ -943,7 +959,7 @@ void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir,
         pr_int(fp, indent, "ngQM", ir->opts.ngQM);
 
         /* CONSTRAINT OPTIONS */
-        PS("constraint-algorithm", ECONSTRTYPE(ir->eConstrAlg));
+        PS("constraint-algorithm", enumValueToString(ir->eConstrAlg));
         PS("continuation", EBOOL(ir->bContinuation));
 
         PS("Shake-SOR", EBOOL(ir->bShakeSOR));
@@ -954,7 +970,7 @@ void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir,
 
         /* Walls */
         PI("nwall", ir->nwall);
-        PS("wall-type", EWALLTYPE(ir->wall_type));
+        PS("wall-type", enumValueToString(ir->wall_type));
         PR("wall-r-linpot", ir->wall_r_linpot);
         /* wall-atomtype */
         PI("wall-atomtype[0]", ir->wall_atomtype[0]);
@@ -975,7 +991,7 @@ void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir,
         PS("awh", EBOOL(ir->bDoAwh));
         if (ir->bDoAwh)
         {
-            pr_awh(fp, indent, ir->awhParams);
+            pr_awh(fp, indent, ir->awhParams.get());
         }
 
         /* ENFORCED ROTATION */
@@ -993,8 +1009,8 @@ void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir,
         }
 
         /* NMR refinement stuff */
-        PS("disre", EDISRETYPE(ir->eDisre));
-        PS("disre-weighting", EDISREWEIGHTING(ir->eDisreWeighting));
+        PS("disre", enumValueToString(ir->eDisre));
+        PS("disre-weighting", enumValueToString(ir->eDisreWeighting));
         PS("disre-mixed", EBOOL(ir->bDisreMixed));
         PR("dr-fc", ir->dr_fc);
         PR("dr-tau", ir->dr_tau);
@@ -1005,14 +1021,14 @@ void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir,
         PR("nstorireout", ir->nstorireout);
 
         /* FREE ENERGY VARIABLES */
-        PS("free-energy", EFEPTYPE(ir->efep));
-        if (ir->efep != efepNO || ir->bSimTemp)
+        PS("free-energy", enumValueToString(ir->efep));
+        if (ir->efep != FreeEnergyPerturbationType::No || ir->bSimTemp)
         {
-            pr_fepvals(fp, indent, ir->fepvals, bMDPformat);
+            pr_fepvals(fp, indent, ir->fepvals.get(), bMDPformat);
         }
         if (ir->bExpanded)
         {
-            pr_expandedvals(fp, indent, ir->expandedvals, ir->fepvals->n_lambda);
+            pr_expandedvals(fp, indent, ir->expandedvals.get(), ir->fepvals->n_lambda);
         }
 
         /* NON-equilibrium MD stuff */
@@ -1023,12 +1039,12 @@ void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir,
         PS("simulated-tempering", EBOOL(ir->bSimTemp));
         if (ir->bSimTemp)
         {
-            pr_simtempvals(fp, indent, ir->simtempvals, ir->fepvals->n_lambda);
+            pr_simtempvals(fp, indent, ir->simtempvals.get(), ir->fepvals->n_lambda);
         }
 
         /* ION/WATER SWAPPING FOR COMPUTATIONAL ELECTROPHYSIOLOGY */
-        PS("swapcoords", ESWAPTYPE(ir->eSwapCoords));
-        if (ir->eSwapCoords != eswapNO)
+        PS("swapcoords", enumValueToString(ir->eSwapCoords));
+        if (ir->eSwapCoords != SwapType::No)
         {
             pr_swap(fp, indent, ir->swap);
         }
@@ -1063,7 +1079,6 @@ static void cmp_grpopts(FILE* fp, const t_grpopts* opt1, const t_grpopts* opt2,
     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++)
@@ -1071,9 +1086,8 @@ static void cmp_grpopts(FILE* fp, const t_grpopts* opt1, const t_grpopts* opt2,
         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]);
+        cmpEnum(fp, "inputrec->grpopts.annealing", 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);
@@ -1092,15 +1106,10 @@ static void cmp_grpopts(FILE* fp, const t_grpopts* opt1, const t_grpopts* opt2,
             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]);
+                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]);
@@ -1115,8 +1124,8 @@ static void cmp_pull(FILE* fp)
 }
 
 static void cmp_awhDimParams(FILE*                    fp,
-                             const gmx::AwhDimParams* dimp1,
-                             const gmx::AwhDimParams* dimp2,
+                             const gmx::AwhDimParams& dimp1,
+                             const gmx::AwhDimParams& dimp2,
                              int                      dimIndex,
                              real                     ftol,
                              real                     abstol)
@@ -1124,64 +1133,103 @@ static void cmp_awhDimParams(FILE*                    fp,
     /* Note that we have double index here, but the compare functions only
      * support one index, so here we only print the dim index and not the bias.
      */
-    cmp_int(fp, "inputrec.awhParams->bias?->dim->coord_index", dimIndex, dimp1->coordIndex,
-            dimp2->coordIndex);
-    cmp_double(fp, "inputrec->awhParams->bias?->dim->period", dimIndex, dimp1->period,
-               dimp2->period, ftol, abstol);
-    cmp_double(fp, "inputrec->awhParams->bias?->dim->diffusion", dimIndex, dimp1->diffusion,
-               dimp2->diffusion, ftol, abstol);
-    cmp_double(fp, "inputrec->awhParams->bias?->dim->origin", dimIndex, dimp1->origin,
-               dimp2->origin, ftol, abstol);
-    cmp_double(fp, "inputrec->awhParams->bias?->dim->end", dimIndex, dimp1->end, dimp2->end, ftol, abstol);
-    cmp_double(fp, "inputrec->awhParams->bias?->dim->coord_value_init", dimIndex,
-               dimp1->coordValueInit, dimp2->coordValueInit, ftol, abstol);
-    cmp_double(fp, "inputrec->awhParams->bias?->dim->coverDiameter", dimIndex, dimp1->coverDiameter,
-               dimp2->coverDiameter, ftol, abstol);
+    cmp_int(fp,
+            "inputrec.awhParams->bias?->dim->coord_index",
+            dimIndex,
+            dimp1.coordinateIndex(),
+            dimp2.coordinateIndex());
+    cmp_double(fp, "inputrec->awhParams->bias?->dim->period", dimIndex, dimp1.period(), dimp2.period(), ftol, abstol);
+    cmp_double(fp,
+               "inputrec->awhParams->bias?->dim->diffusion",
+               dimIndex,
+               dimp1.diffusion(),
+               dimp2.diffusion(),
+               ftol,
+               abstol);
+    cmp_double(fp, "inputrec->awhParams->bias?->dim->origin", dimIndex, dimp1.origin(), dimp2.origin(), ftol, abstol);
+    cmp_double(fp, "inputrec->awhParams->bias?->dim->end", dimIndex, dimp1.end(), dimp2.end(), ftol, abstol);
+    cmp_double(fp,
+               "inputrec->awhParams->bias?->dim->coord_value_init",
+               dimIndex,
+               dimp1.initialCoordinate(),
+               dimp2.initialCoordinate(),
+               ftol,
+               abstol);
+    cmp_double(fp,
+               "inputrec->awhParams->bias?->dim->coverDiameter",
+               dimIndex,
+               dimp1.coverDiameter(),
+               dimp2.coverDiameter(),
+               ftol,
+               abstol);
 }
 
 static void cmp_awhBiasParams(FILE*                     fp,
-                              const gmx::AwhBiasParams* bias1,
-                              const gmx::AwhBiasParams* bias2,
+                              const gmx::AwhBiasParams& bias1,
+                              const gmx::AwhBiasParams& bias2,
                               int                       biasIndex,
                               real                      ftol,
                               real                      abstol)
 {
-    cmp_int(fp, "inputrec->awhParams->ndim", biasIndex, bias1->ndim, bias2->ndim);
-    cmp_int(fp, "inputrec->awhParams->biaseTarget", biasIndex, bias1->eTarget, bias2->eTarget);
-    cmp_double(fp, "inputrec->awhParams->biastargetBetaScaling", biasIndex,
-               bias1->targetBetaScaling, bias2->targetBetaScaling, ftol, abstol);
-    cmp_double(fp, "inputrec->awhParams->biastargetCutoff", biasIndex, bias1->targetCutoff,
-               bias2->targetCutoff, ftol, abstol);
-    cmp_int(fp, "inputrec->awhParams->biaseGrowth", biasIndex, bias1->eGrowth, bias2->eGrowth);
-    cmp_bool(fp, "inputrec->awhParams->biasbUserData", biasIndex, bias1->bUserData != 0,
-             bias2->bUserData != 0);
-    cmp_double(fp, "inputrec->awhParams->biaserror_initial", biasIndex, bias1->errorInitial,
-               bias2->errorInitial, ftol, abstol);
-    cmp_int(fp, "inputrec->awhParams->biasShareGroup", biasIndex, bias1->shareGroup, bias2->shareGroup);
-
-    for (int dim = 0; dim < std::min(bias1->ndim, bias2->ndim); dim++)
-    {
-        cmp_awhDimParams(fp, &bias1->dimParams[dim], &bias2->dimParams[dim], dim, ftol, abstol);
+    cmp_int(fp, "inputrec->awhParams->ndim", biasIndex, bias1.ndim(), bias2.ndim());
+    cmpEnum<gmx::AwhTargetType>(
+            fp, "inputrec->awhParams->biaseTarget", bias1.targetDistribution(), bias2.targetDistribution());
+    cmp_double(fp,
+               "inputrec->awhParams->biastargetBetaScaling",
+               biasIndex,
+               bias1.targetBetaScaling(),
+               bias2.targetBetaScaling(),
+               ftol,
+               abstol);
+    cmp_double(fp,
+               "inputrec->awhParams->biastargetCutoff",
+               biasIndex,
+               bias1.targetCutoff(),
+               bias2.targetCutoff(),
+               ftol,
+               abstol);
+    cmpEnum<gmx::AwhHistogramGrowthType>(
+            fp, "inputrec->awhParams->biaseGrowth", bias1.growthType(), bias2.growthType());
+    cmp_bool(fp, "inputrec->awhParams->biasbUserData", biasIndex, bias1.userPMFEstimate(), bias2.userPMFEstimate());
+    cmp_double(fp,
+               "inputrec->awhParams->biaserror_initial",
+               biasIndex,
+               bias1.initialErrorEstimate(),
+               bias2.initialErrorEstimate(),
+               ftol,
+               abstol);
+    cmp_int(fp, "inputrec->awhParams->biasShareGroup", biasIndex, bias1.shareGroup(), bias2.shareGroup());
+
+    const auto dimParams1 = bias1.dimParams();
+    const auto dimParams2 = bias2.dimParams();
+    for (int dim = 0; dim < std::min(bias1.ndim(), bias2.ndim()); dim++)
+    {
+        cmp_awhDimParams(fp, dimParams1[dim], dimParams2[dim], dim, ftol, abstol);
     }
 }
 
-static void cmp_awhParams(FILE* fp, const gmx::AwhParams* awh1, const gmx::AwhParams* awh2, real ftol, real abstol)
+static void cmp_awhParams(FILE* fp, const gmx::AwhParams& awh1, const gmx::AwhParams& awh2, real ftol, real abstol)
 {
-    cmp_int(fp, "inputrec->awhParams->nbias", -1, awh1->numBias, awh2->numBias);
-    cmp_int64(fp, "inputrec->awhParams->seed", awh1->seed, awh2->seed);
-    cmp_int(fp, "inputrec->awhParams->nstout", -1, awh1->nstOut, awh2->nstOut);
-    cmp_int(fp, "inputrec->awhParams->nstsample_coord", -1, awh1->nstSampleCoord, awh2->nstSampleCoord);
-    cmp_int(fp, "inputrec->awhParams->nsamples_update_free_energy", -1,
-            awh1->numSamplesUpdateFreeEnergy, awh2->numSamplesUpdateFreeEnergy);
-    cmp_int(fp, "inputrec->awhParams->ePotential", -1, awh1->ePotential, awh2->ePotential);
-    cmp_bool(fp, "inputrec->awhParams->shareBiasMultisim", -1, awh1->shareBiasMultisim,
-             awh2->shareBiasMultisim);
-
-    if (awh1->numBias == awh2->numBias)
-    {
-        for (int bias = 0; bias < awh1->numBias; bias++)
+    cmp_int(fp, "inputrec->awhParams->nbias", -1, awh1.numBias(), awh2.numBias());
+    cmp_int64(fp, "inputrec->awhParams->seed", awh1.seed(), awh2.seed());
+    cmp_int(fp, "inputrec->awhParams->nstout", -1, awh1.nstout(), awh2.nstout());
+    cmp_int(fp, "inputrec->awhParams->nstsample_coord", -1, awh1.nstSampleCoord(), awh2.nstSampleCoord());
+    cmp_int(fp,
+            "inputrec->awhParams->nsamples_update_free_energy",
+            -1,
+            awh1.numSamplesUpdateFreeEnergy(),
+            awh2.numSamplesUpdateFreeEnergy());
+    cmpEnum<gmx::AwhPotentialType>(
+            fp, "inputrec->awhParams->ePotential", awh1.potential(), awh2.potential());
+    cmp_bool(fp, "inputrec->awhParams->shareBiasMultisim", -1, awh1.shareBiasMultisim(), awh2.shareBiasMultisim());
+
+    if (awh1.numBias() == awh2.numBias())
+    {
+        const auto awhBiasParams1 = awh1.awhBiasParams();
+        const auto awhBiasParams2 = awh2.awhBiasParams();
+        for (int bias = 0; bias < awh1.numBias(); bias++)
         {
-            cmp_awhBiasParams(fp, &awh1->awhBiasParams[bias], &awh2->awhBiasParams[bias], bias, ftol, abstol);
+            cmp_awhBiasParams(fp, awhBiasParams1[bias], awhBiasParams2[bias], bias, ftol, abstol);
         }
     }
 }
@@ -1194,15 +1242,18 @@ static void cmp_simtempvals(FILE*            fp,
                             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);
+    cmpEnum(fp, "inputrec->simtempvals->eSimTempScale", 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);
+        cmp_real(fp,
+                 "inputrec->simtempvals->temperatures",
+                 -1,
+                 simtemp1->temperatures[i],
+                 simtemp2->temperatures[i],
+                 ftol,
+                 abstol);
     }
 }
 
@@ -1220,58 +1271,76 @@ static void cmp_expandedvals(FILE*             fp,
 
     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_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);
+    cmpEnum(fp, "inputrec->expandedvals->lambda-stats", expand1->elamstats, expand2->elamstats);
+    cmpEnum(fp, "inputrec->expandedvals->lambda-mc-move", 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->lmc-forced-nstart", -1, expand1->lmc_forced_nstart, expand2->lmc_forced_nstart);
+    cmpEnum(fp, "inputrec->expandedvals->lambda-weights-equil", 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->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->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);
+    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_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 (i = 0; i < static_cast<int>(FreeEnergyPerturbationCouplingType::Count); 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_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);
@@ -1279,13 +1348,12 @@ static void cmp_fepvals(FILE* fp, const t_lambda* fep1, const t_lambda* fep2, re
     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);
+    cmpEnum(fp, "inputrec->fepvals->edHdLPrintEnergy", 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);
+    cmpEnum(fp, "inputrec->separate_dhdl_file", fep1->separate_dhdl_file, fep2->separate_dhdl_file);
+    cmpEnum(fp, "inputrec->dhdl_derivatives", 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);
+    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)
@@ -1299,7 +1367,7 @@ void cmp_inputrec(FILE* fp, const t_inputrec* ir1, const t_inputrec* ir2, real f
      * #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);
+    cmpEnum(fp, "inputrec->eI", 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);
@@ -1307,17 +1375,23 @@ void cmp_inputrec(FILE* fp, const t_inputrec* ir1, const t_inputrec* ir2, real f
     if (ir1->useMts && ir2->useMts)
     {
         cmp_int(fp, "inputrec->mts-levels", -1, ir1->mtsLevels.size(), ir2->mtsLevels.size());
-        cmp_int(fp, "inputrec->mts-level2-forces", -1, ir1->mtsLevels[1].forceGroups.to_ulong(),
+        cmp_int(fp,
+                "inputrec->mts-level2-forces",
+                -1,
+                ir1->mtsLevels[1].forceGroups.to_ulong(),
                 ir2->mtsLevels[1].forceGroups.to_ulong());
-        cmp_int(fp, "inputrec->mts-level2-factor", -1, ir1->mtsLevels[1].stepFactor,
+        cmp_int(fp,
+                "inputrec->mts-level2-factor",
+                -1,
+                ir1->mtsLevels[1].stepFactor,
                 ir2->mtsLevels[1].stepFactor);
     }
     cmp_int(fp, "inputrec->pbcType", -1, static_cast<int>(ir1->pbcType), static_cast<int>(ir2->pbcType));
     cmp_bool(fp, "inputrec->bPeriodicMols", -1, ir1->bPeriodicMols, ir2->bPeriodicMols);
-    cmp_int(fp, "inputrec->cutoff_scheme", -1, ir1->cutoff_scheme, ir2->cutoff_scheme);
+    cmpEnum(fp, "inputrec->cutoff_scheme", ir1->cutoff_scheme, ir2->cutoff_scheme);
     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);
+    cmpEnum(fp, "inputrec->comm_mode", 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);
@@ -1327,25 +1401,35 @@ void cmp_inputrec(FILE* fp, const t_inputrec* ir1, const t_inputrec* ir2, real f
     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->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);
+    cmpEnum(fp, "inputrec->ewald_geometry", 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, static_cast<int>(ir1->bContinuation),
+    cmp_int(fp,
+            "inputrec->bContinuation",
+            -1,
+            static_cast<int>(ir1->bContinuation),
             static_cast<int>(ir2->bContinuation));
-    cmp_int(fp, "inputrec->bShakeSOR", -1, static_cast<int>(ir1->bShakeSOR),
-            static_cast<int>(ir2->bShakeSOR));
-    cmp_int(fp, "inputrec->etc", -1, ir1->etc, ir2->etc);
-    cmp_int(fp, "inputrec->bPrintNHChains", -1, static_cast<int>(ir1->bPrintNHChains),
+    cmp_int(fp, "inputrec->bShakeSOR", -1, static_cast<int>(ir1->bShakeSOR), static_cast<int>(ir2->bShakeSOR));
+    cmpEnum(fp, "inputrec->etc", ir1->etc, ir2->etc);
+    cmp_int(fp,
+            "inputrec->bPrintNHChains",
+            -1,
+            static_cast<int>(ir1->bPrintNHChains),
             static_cast<int>(ir2->bPrintNHChains));
-    cmp_int(fp, "inputrec->epc", -1, ir1->epc, ir2->epc);
-    cmp_int(fp, "inputrec->epct", -1, ir1->epct, ir2->epct);
+    cmpEnum(fp, "inputrec->epc", ir1->epc, ir2->epc);
+    cmpEnum(fp, "inputrec->epct", 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);
@@ -1353,43 +1437,50 @@ void cmp_inputrec(FILE* fp, const t_inputrec* ir1, const t_inputrec* ir2, real f
     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);
+    cmpEnum(fp, "refcoord_scaling", 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);
+    cmpEnum(fp, "inputrec->coulombtype", ir1->coulombtype, ir2->coulombtype);
+    cmpEnum(fp, "inputrec->coulomb_modifier", 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);
+    cmpEnum(fp, "inputrec->vdwtype", ir1->vdwtype, ir2->vdwtype);
+    cmpEnum(fp, "inputrec->vdw_modifier", 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->eDispCorr", -1, ir1->eDispCorr, ir2->eDispCorr);
+    cmpEnum(fp, "inputrec->eDispCorr", 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);
+    cmpEnum(fp, "inputrec->efep", ir1->efep, ir2->efep);
+    cmp_fepvals(fp, ir1->fepvals.get(), ir2->fepvals.get(), ftol, abstol);
     cmp_int(fp, "inputrec->bSimTemp", -1, static_cast<int>(ir1->bSimTemp), static_cast<int>(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_simtempvals(fp,
+                        ir1->simtempvals.get(),
+                        ir2->simtempvals.get(),
+                        std::min(ir1->fepvals->n_lambda, ir2->fepvals->n_lambda),
+                        ftol,
+                        abstol);
     }
-    cmp_int(fp, "inputrec->bExpanded", -1, static_cast<int>(ir1->bExpanded),
-            static_cast<int>(ir2->bExpanded));
+    cmp_int(fp, "inputrec->bExpanded", -1, static_cast<int>(ir1->bExpanded), static_cast<int>(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_expandedvals(fp,
+                         ir1->expandedvals.get(),
+                         ir2->expandedvals.get(),
+                         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);
+    cmpEnum(fp, "inputrec->wall_type", 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);
@@ -1405,14 +1496,13 @@ void cmp_inputrec(FILE* fp, const t_inputrec* ir1, const t_inputrec* ir2, real f
     cmp_bool(fp, "inputrec->bDoAwh", -1, ir1->bDoAwh, ir2->bDoAwh);
     if (ir1->bDoAwh && ir2->bDoAwh)
     {
-        cmp_awhParams(fp, ir1->awhParams, ir2->awhParams, ftol, abstol);
+        cmp_awhParams(fp, *ir1->awhParams, *ir2->awhParams, ftol, abstol);
     }
 
-    cmp_int(fp, "inputrec->eDisre", -1, ir1->eDisre, ir2->eDisre);
+    cmpEnum(fp, "inputrec->eDisre", 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, static_cast<int>(ir1->bDisreMixed),
-            static_cast<int>(ir2->bDisreMixed));
+    cmpEnum(fp, "inputrec->eDisreWeighting", ir1->eDisreWeighting, ir2->eDisreWeighting);
+    cmp_int(fp, "inputrec->bDisreMixed", -1, static_cast<int>(ir1->bDisreMixed), static_cast<int>(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);
@@ -1424,7 +1514,7 @@ void cmp_inputrec(FILE* fp, const t_inputrec* ir1, const t_inputrec* ir2, real f
     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);
+    cmpEnum(fp, "inputrec->eConstrAlg", 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);
@@ -1466,19 +1556,20 @@ gmx_bool inputrecDeform(const t_inputrec* ir)
 
 gmx_bool inputrecDynamicBox(const t_inputrec* ir)
 {
-    return (ir->epc != epcNO || ir->eI == eiTPI || inputrecDeform(ir));
+    return (ir->epc != PressureCoupling::No || ir->eI == IntegrationAlgorithm::TPI || inputrecDeform(ir));
 }
 
 gmx_bool inputrecPreserveShape(const t_inputrec* ir)
 {
-    return (ir->epc != epcNO && ir->deform[XX][XX] == 0
-            && (ir->epct == epctISOTROPIC || ir->epct == epctSEMIISOTROPIC));
+    return (ir->epc != PressureCoupling::No && ir->deform[XX][XX] == 0
+            && (ir->epct == PressureCouplingType::Isotropic
+                || ir->epct == PressureCouplingType::SemiIsotropic));
 }
 
 gmx_bool inputrecNeedMutot(const t_inputrec* ir)
 {
-    return ((ir->coulombtype == eelEWALD || EEL_PME(ir->coulombtype))
-            && (ir->ewald_geometry == eewg3DC || ir->epsilon_surface != 0));
+    return ((ir->coulombtype == CoulombInteractionType::Ewald || EEL_PME(ir->coulombtype))
+            && (ir->ewald_geometry == EwaldGeometry::ThreeDC || ir->epsilon_surface != 0));
 }
 
 gmx_bool inputrecExclForces(const t_inputrec* ir)
@@ -1488,17 +1579,20 @@ gmx_bool inputrecExclForces(const t_inputrec* ir)
 
 gmx_bool inputrecNptTrotter(const t_inputrec* ir)
 {
-    return (((ir->eI == eiVV) || (ir->eI == eiVVAK)) && (ir->epc == epcMTTK) && (ir->etc == etcNOSEHOOVER));
+    return (((ir->eI == IntegrationAlgorithm::VV) || (ir->eI == IntegrationAlgorithm::VVAK))
+            && (ir->epc == PressureCoupling::Mttk) && (ir->etc == TemperatureCoupling::NoseHoover));
 }
 
 gmx_bool inputrecNvtTrotter(const t_inputrec* ir)
 {
-    return (((ir->eI == eiVV) || (ir->eI == eiVVAK)) && (ir->epc != epcMTTK) && (ir->etc == etcNOSEHOOVER));
+    return (((ir->eI == IntegrationAlgorithm::VV) || (ir->eI == IntegrationAlgorithm::VVAK))
+            && (ir->epc != PressureCoupling::Mttk) && (ir->etc == TemperatureCoupling::NoseHoover));
 }
 
 gmx_bool inputrecNphTrotter(const t_inputrec* ir)
 {
-    return (((ir->eI == eiVV) || (ir->eI == eiVVAK)) && (ir->epc == epcMTTK) && (ir->etc != etcNOSEHOOVER));
+    return (((ir->eI == IntegrationAlgorithm::VV) || (ir->eI == IntegrationAlgorithm::VVAK))
+            && (ir->epc == PressureCoupling::Mttk) && (ir->etc != TemperatureCoupling::NoseHoover));
 }
 
 bool inputrecPbcXY2Walls(const t_inputrec* ir)
@@ -1520,7 +1614,7 @@ bool integratorHasConservedEnergyQuantity(const t_inputrec* ir)
         // Energy minimization or stochastic integrator: no conservation
         return false;
     }
-    else if (ir->etc == etcNO && ir->epc == epcNO)
+    else if (ir->etc == TemperatureCoupling::No && ir->epc == PressureCoupling::No)
     {
         // The total energy is conserved, no additional conserved quanitity
         return false;
@@ -1529,7 +1623,7 @@ bool integratorHasConservedEnergyQuantity(const t_inputrec* ir)
     {
         // Shear stress with Parrinello-Rahman is not supported (tedious)
         bool shearWithPR =
-                ((ir->epc == epcPARRINELLORAHMAN || ir->epc == epcMTTK)
+                ((ir->epc == PressureCoupling::ParrinelloRahman || ir->epc == PressureCoupling::Mttk)
                  && (ir->ref_p[YY][XX] != 0 || ir->ref_p[ZZ][XX] != 0 || ir->ref_p[ZZ][YY] != 0));
 
         return !ETC_ANDERSEN(ir->etc) && !shearWithPR;
@@ -1538,7 +1632,8 @@ bool integratorHasConservedEnergyQuantity(const t_inputrec* ir)
 
 bool integratorHasReferenceTemperature(const t_inputrec* ir)
 {
-    return ((ir->etc != etcNO) || EI_SD(ir->eI) || (ir->eI == eiBD) || EI_TPI(ir->eI));
+    return ((ir->etc != TemperatureCoupling::No) || EI_SD(ir->eI)
+            || (ir->eI == IntegrationAlgorithm::BD) || EI_TPI(ir->eI));
 }
 
 int inputrec2nboundeddim(const t_inputrec* ir)
@@ -1571,12 +1666,12 @@ int ndof_com(const t_inputrec* ir)
 
 real maxReferenceTemperature(const t_inputrec& ir)
 {
-    if (EI_ENERGY_MINIMIZATION(ir.eI) || ir.eI == eiNM)
+    if (EI_ENERGY_MINIMIZATION(ir.eI) || ir.eI == IntegrationAlgorithm::NM)
     {
         return 0;
     }
 
-    if (EI_MD(ir.eI) && ir.etc == etcNO)
+    if (EI_MD(ir.eI) && ir.etc == TemperatureCoupling::No)
     {
         return -1;
     }
@@ -1599,7 +1694,8 @@ real maxReferenceTemperature(const t_inputrec& ir)
 
 bool haveEwaldSurfaceContribution(const t_inputrec& ir)
 {
-    return EEL_PME_EWALD(ir.coulombtype) && (ir.ewald_geometry == eewg3DC || ir.epsilon_surface != 0);
+    return EEL_PME_EWALD(ir.coulombtype)
+           && (ir.ewald_geometry == EwaldGeometry::ThreeDC || ir.epsilon_surface != 0);
 }
 
 bool haveFreeEnergyType(const t_inputrec& ir, const int fepType)
index 6e4ee727ab460c59fb8e6c377a56670c930fe41e..60c95bfdccf9333d41879c4aee526bbde7f2ee41 100644 (file)
@@ -45,7 +45,7 @@
 
 #include "gromacs/math/vectypes.h"
 #include "gromacs/mdtypes/md_enums.h"
-#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/real.h"
 
 #define EGP_EXCL (1 << 0)
@@ -58,7 +58,7 @@ struct pull_params_t;
 namespace gmx
 {
 class Awh;
-struct AwhParams;
+class AwhParams;
 class KeyValueTreeObject;
 struct MtsLevel;
 } // namespace gmx
@@ -71,8 +71,6 @@ struct t_grpopts
     int ngtc;
     //! Number of of Nose-Hoover chains per group
     int nhchainlength;
-    //! Number of Accelerate groups
-    int ngacc;
     //! Number of Freeze groups
     int ngfrz;
     //! Number of Energy groups
@@ -82,7 +80,7 @@ struct t_grpopts
     //! Coupling temperature   per group
     real* ref_t;
     //! No/simple/periodic simulated annealing for each group
-    int* annealing;
+    SimulatedAnnealing* annealing;
     //! Number of annealing time points per group
     int* anneal_npoints;
     //! For each group: Time points
@@ -91,8 +89,6 @@ struct t_grpopts
     real** anneal_temp;
     //! Tau coupling time
     real* tau_t;
-    //! Acceleration per group
-    rvec* acc;
     //! Whether the group will be frozen in each direction
     ivec* nFreeze;
     //! Exclusions/tables of energy group pairs
@@ -106,13 +102,13 @@ struct t_grpopts
 struct t_simtemp
 {
     //! Simulated temperature scaling; linear or exponential
-    int eSimTempScale;
+    SimulatedTempering eSimTempScale;
     //! The low temperature for simulated tempering
     real simtemp_low;
     //! The high temperature for simulated tempering
     real simtemp_high;
     //! The range of temperatures used for simulated tempering
-    real* temperatures;
+    std::vector<real> temperatures;
 };
 
 struct t_lambda
@@ -126,11 +122,11 @@ struct t_lambda
     //! Change of lambda per time step (fraction of (0.1)
     double delta_lambda;
     //! Print no, total or potential energies in dhdl
-    int edHdLPrintEnergy;
+    FreeEnergyPrintEnergy edHdLPrintEnergy;
     //! The number of foreign lambda points
     int n_lambda;
     //! The array of all lambda values
-    double** all_lambda;
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, std::vector<double>> all_lambda;
     //! The number of neighboring lambda states to calculate the energy for in up and down directions (-1 for all)
     int lambda_neighbors;
     //! The first lambda to calculate energies for
@@ -148,13 +144,13 @@ struct t_lambda
     //! Free energy soft-core sigma for ?????
     real sc_sigma_min;
     //! Use softcore for the coulomb portion as well (default FALSE)
-    gmx_bool bScCoul;
+    bool bScCoul;
     //! Whether to print the dvdl term associated with this term; if it is not specified as separate, it is lumped with the FEP term
-    gmx_bool separate_dvdl[efptNR];
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, bool> separate_dvdl;
     //! Whether to write a separate dhdl.xvg file note: NOT a gmx_bool, but an enum
-    int separate_dhdl_file;
+    SeparateDhdlFile separate_dhdl_file;
     //! Whether to calculate+write dhdl derivatives note: NOT a gmx_bool, but an enum
-    int dhdl_derivatives;
+    DhDlDerivativeCalculation dhdl_derivatives;
     //! The maximum table size for the dH histogram
     int dh_hist_size;
     //! The spacing for the dH histogram
@@ -166,11 +162,11 @@ struct t_expanded
     //! The frequency of expanded ensemble state changes
     int nstexpanded;
     //! Which type of move updating do we use for lambda monte carlo (or no for none)
-    int elamstats;
+    LambdaWeightCalculation elamstats;
     //! What move set will be we using for state space moves
-    int elmcmove;
+    LambdaMoveCalculation elmcmove;
     //! The method we use to decide of we have equilibrated the weights
-    int elmceq;
+    LambdaWeightWillReachEquilibrium elmceq;
     //! The minumum number of samples at each lambda for deciding whether we have reached a minimum
     int equil_n_at_lam;
     //! Wang-Landau delta at which we stop equilibrating weights
@@ -184,7 +180,7 @@ struct t_expanded
     //! Random number seed for lambda mc switches
     int lmc_seed;
     //! Whether to use minumum variance weighting
-    gmx_bool minvar;
+    bool minvar;
     //! The number of samples needed before kicking into minvar routine
     int minvarmin;
     //! The offset for the variance in MinVar
@@ -192,7 +188,7 @@ struct t_expanded
     //! Range of cvalues used for BAR
     int c_range;
     //! Whether to print symmetrized matrices
-    gmx_bool bSymmetrizedTMatrix;
+    bool bSymmetrizedTMatrix;
     //! How frequently to print the transition matrices
     int nstTij;
     //! Number of repetitions in the MC lambda jumps MRS -- VERIFY THIS
@@ -208,21 +204,21 @@ struct t_expanded
     //! Starting delta for Wang-Landau
     real init_wl_delta;
     //! Use one over t convergence for Wang-Landau when the delta get sufficiently small
-    gmx_bool bWLoneovert;
+    bool bWLoneovert;
     //! Did we initialize the weights? TODO: REMOVE FOR 5.0, no longer needed with new logic
-    gmx_bool bInit_weights;
+    bool bInit_weights;
     //! To override the main temperature, or define it if it's not defined
     real mc_temp;
     //! User-specified initial weights to start with
-    real* init_lambda_weights;
+    std::vector<real> init_lambda_weights;
 };
 
 struct t_rotgrp
 {
     //! Rotation type for this group
-    int eType;
+    EnforcedRotationGroupType eType;
     //! Use mass-weighed positions?
-    int bMassW;
+    bool bMassW;
     //! Number of atoms in the group
     int nat;
     //! The global atoms numbers
@@ -238,7 +234,7 @@ struct t_rotgrp
     //! Pivot point of rotation axis (nm)
     rvec pivot;
     //! Type of fit to determine actual group angle
-    int eFittype;
+    RotationGroupFitting eFittype;
     //! Number of angles around the reference angle for which the rotation potential is also evaluated (for fit type 'potential' only)
     int PotAngle_nstep;
     //! Distance between two angles in degrees (for fit type 'potential' only)
@@ -280,7 +276,7 @@ struct t_swapGroup
     //! The global ion group atoms numbers
     int* ind;
     //! Requested number of molecules of this type per compartment
-    int nmolReq[eCompNR];
+    gmx::EnumerationArray<Compartment, int> nmolReq;
 };
 
 struct t_swapcoords
@@ -288,7 +284,7 @@ struct t_swapcoords
     //! Period between when a swap is attempted
     int nstswap;
     //! Use mass-weighted positions in split group
-    gmx_bool massw_split[2];
+    bool massw_split[2];
     /*! \brief Split cylinders defined by radius, upper and lower
      * extension. The split cylinders define the channels and are
      * each anchored in the center of the split group */
@@ -302,7 +298,7 @@ struct t_swapcoords
     //! Ion counts may deviate from the requested values by +-threshold before a swap is done
     real threshold;
     //! Offset of the swap layer (='bulk') with respect to the compartment-defining layers
-    real bulkOffset[eCompNR];
+    gmx::EnumerationArray<Compartment, real> bulkOffset;
     //! Number of groups to be controlled
     int ngrp;
     //! All swap groups, including split and solvent
@@ -317,7 +313,7 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
     ~t_inputrec();
 
     //! Integration method
-    int eI;
+    IntegrationAlgorithm eI;
     //! Number of steps to be taken
     int64_t nsteps;
     //! Used in checkpointing to separate chunks
@@ -327,13 +323,13 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
     //! Frequency of energy calc. and T/P coupl. upd.
     int nstcalcenergy;
     //! Group or verlet cutoffs
-    int cutoff_scheme;
+    CutoffScheme cutoff_scheme;
     //! Number of steps before pairlist is generated
     int nstlist;
     //! Number of steps after which center of mass motion is removed
     int nstcomm;
     //! Center of mass motion removal algorithm
-    int comm_mode;
+    ComRemovalAlgorithm comm_mode;
     //! Number of steps after which print to logfile
     int nstlog;
     //! Number of steps after which X is output
@@ -371,27 +367,27 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
     //! Real space tolerance for LJ-Ewald
     real ewald_rtol_lj;
     //! Normal/3D ewald, or pseudo-2D LR corrections
-    int ewald_geometry;
+    EwaldGeometry ewald_geometry;
     //! Epsilon for PME dipole correction
     real epsilon_surface;
     //! Type of combination rule in LJ-PME
-    int ljpme_combination_rule;
+    LongRangeVdW ljpme_combination_rule;
     //! Type of periodic boundary conditions
     PbcType pbcType;
     //! Periodic molecules
     bool bPeriodicMols;
     //! Continuation run: starting state is correct (ie. constrained)
-    gmx_bool bContinuation;
+    bool bContinuation;
     //! Temperature coupling
-    int etc;
+    TemperatureCoupling etc;
     //! Interval in steps for temperature coupling
     int nsttcouple;
     //! Whether to print nose-hoover chains
-    gmx_bool bPrintNHChains;
+    bool bPrintNHChains;
     //! Pressure coupling
-    int epc;
+    PressureCoupling epc;
     //! Pressure coupling type
-    int epct;
+    PressureCouplingType epct;
     //! Interval in steps for pressure coupling
     int nstpcouple;
     //! Pressure coupling time (ps)
@@ -401,7 +397,7 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
     //! Compressibility ((mol nm^3)/kJ)
     tensor compress;
     //! How to scale absolute reference coordinates
-    int refcoord_scaling;
+    RefCoordScaling refcoord_scaling;
     //! The COM of the posres atoms
     rvec posres_com;
     //! The B-state COM of the posres atoms
@@ -415,9 +411,9 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
     //! Radius for test particle insertion
     real rtpi;
     //! Type of electrostatics treatment
-    int coulombtype;
+    CoulombInteractionType coulombtype;
     //! Modify the Coulomb interaction
-    int coulomb_modifier;
+    InteractionModifiers coulomb_modifier;
     //! Coulomb switch range start (nm)
     real rcoulomb_switch;
     //! Coulomb cutoff (nm)
@@ -429,39 +425,39 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
     //! Always false (no longer supported)
     bool implicit_solvent;
     //! Type of Van der Waals treatment
-    int vdwtype;
+    VanDerWaalsType vdwtype;
     //! Modify the Van der Waals interaction
-    int vdw_modifier;
+    InteractionModifiers vdw_modifier;
     //! Van der Waals switch range start (nm)
     real rvdw_switch;
     //! Van der Waals cutoff (nm)
     real rvdw;
     //! Perform Long range dispersion corrections
-    int eDispCorr;
+    DispersionCorrectionType eDispCorr;
     //! Extension of the table beyond the cut-off, as well as the table length for 1-4 interac.
     real tabext;
     //! Tolerance for shake
     real shake_tol;
     //! Free energy calculations
-    int efep;
+    FreeEnergyPerturbationType efep;
     //! Data for the FEP state
-    t_lambda* fepvals;
+    std::unique_ptr<t_lambda> fepvals;
     //! Whether to do simulated tempering
-    gmx_bool bSimTemp;
+    bool bSimTemp;
     //! Variables for simulated tempering
-    t_simtemp* simtempvals;
+    std::unique_ptr<t_simtemp> simtempvals;
     //! Whether expanded ensembles are used
-    gmx_bool bExpanded;
+    bool bExpanded;
     //! Expanded ensemble parameters
-    t_expanded* expandedvals;
+    std::unique_ptr<t_expanded> expandedvals;
     //! Type of distance restraining
-    int eDisre;
+    DistanceRestraintRefinement eDisre;
     //! Force constant for time averaged distance restraints
     real dr_fc;
     //! Type of weighting of pairs in one restraints
-    int eDisreWeighting;
+    DistanceRestraintWeighting eDisreWeighting;
     //! Use combination of time averaged and instantaneous violations
-    gmx_bool bDisreMixed;
+    bool bDisreMixed;
     //! Frequency of writing pair distances to enx
     int nstdisreout;
     //! Time constant for memory function in disres
@@ -485,7 +481,7 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
     //! Number of corrections to the Hessian to keep
     int nbfgscorr;
     //! Type of constraint algorithm
-    int eConstrAlg;
+    ConstraintAlgorithm eConstrAlg;
     //! Order of the LINCS Projection Algorithm
     int nProjOrder;
     //! Warn if any bond rotates more than this many degrees
@@ -493,7 +489,7 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
     //! Number of iterations in the final LINCS step
     int nLincsIter;
     //! Use successive overrelaxation for shake
-    gmx_bool bShakeSOR;
+    bool bShakeSOR;
     //! Friction coefficient for BD (amu/ps)
     real bd_fric;
     //! Random seed for SD and BD
@@ -501,7 +497,7 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
     //! The number of walls
     int nwall;
     //! The type of walls
-    int wall_type;
+    WallType wall_type;
     //! The potentail is linear for r<=wall_r_linpot
     real wall_r_linpot;
     //! The atom type for walls
@@ -513,29 +509,29 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
 
     /* COM pulling data */
     //! Do we do COM pulling?
-    gmx_bool bPull;
+    bool bPull;
     //! The data for center of mass pulling
     std::unique_ptr<pull_params_t> pull;
 
     /* AWH bias data */
     //! Whether to use AWH biasing for PMF calculations
-    gmx_bool bDoAwh;
+    bool bDoAwh;
     //! AWH biasing parameters
-    gmx::AwhParams* awhParams;
+    std::unique_ptr<gmx::AwhParams> awhParams;
 
     /* Enforced rotation data */
     //! Whether to calculate enforced rotation potential(s)
-    gmx_bool bRot;
+    bool bRot;
     //! The data for enforced rotation potentials
     t_rot* rot;
 
     //! Whether to do ion/water position exchanges (CompEL)
-    int eSwapCoords;
+    SwapType eSwapCoords;
     //! Swap data structure.
     t_swapcoords* swap;
 
     //! Whether the tpr makes an interactive MD session possible.
-    gmx_bool bIMD;
+    bool bIMD;
     //! Interactive molecular dynamics
     t_IMD* imd;
 
@@ -557,13 +553,15 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
     //! Group options
     t_grpopts opts;
     //! QM/MM calculation
-    gmx_bool bQMMM;
+    bool bQMMM;
 
     /* Fields for removed features go here (better caching) */
     //! Whether AdResS is enabled - always false if a valid .tpr was read
-    gmx_bool bAdress;
+    bool bAdress;
     //! Whether twin-range scheme is active - always false if a valid .tpr was read
-    gmx_bool useTwinRange;
+    bool useTwinRange;
+    //! Whether we have constant acceleration - removed in GROMACS 2022
+    bool useConstantAcceleration;
 
     //! KVT object that contains input parameters converted to the new style.
     gmx::KeyValueTreeObject* params;
@@ -574,39 +572,39 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
 
 int ir_optimal_nstcalcenergy(const t_inputrec* ir);
 
-int tcouple_min_integration_steps(int etc);
+int tcouple_min_integration_steps(TemperatureCoupling etc);
 
 int ir_optimal_nsttcouple(const t_inputrec* ir);
 
-int pcouple_min_integration_steps(int epc);
+int pcouple_min_integration_steps(PressureCoupling epc);
 
 int ir_optimal_nstpcouple(const t_inputrec* ir);
 
 /* Returns if the Coulomb force or potential is switched to zero */
-gmx_bool ir_coulomb_switched(const t_inputrec* ir);
+bool ir_coulomb_switched(const t_inputrec* ir);
 
 /* Returns if the Coulomb interactions are zero beyond the rcoulomb.
  * Note: always returns TRUE for the Verlet cut-off scheme.
  */
-gmx_bool ir_coulomb_is_zero_at_cutoff(const t_inputrec* ir);
+bool ir_coulomb_is_zero_at_cutoff(const t_inputrec* ir);
 
 /* As ir_coulomb_is_zero_at_cutoff, but also returns TRUE for user tabulated
  * interactions, since these might be zero beyond rcoulomb.
  */
-gmx_bool ir_coulomb_might_be_zero_at_cutoff(const t_inputrec* ir);
+bool ir_coulomb_might_be_zero_at_cutoff(const t_inputrec* ir);
 
 /* Returns if the Van der Waals force or potential is switched to zero */
-gmx_bool ir_vdw_switched(const t_inputrec* ir);
+bool ir_vdw_switched(const t_inputrec* ir);
 
 /* Returns if the Van der Waals interactions are zero beyond the rvdw.
  * Note: always returns TRUE for the Verlet cut-off scheme.
  */
-gmx_bool ir_vdw_is_zero_at_cutoff(const t_inputrec* ir);
+bool ir_vdw_is_zero_at_cutoff(const t_inputrec* ir);
 
 /* As ir_vdw_is_zero_at_cutoff, but also returns TRUE for user tabulated
  * interactions, since these might be zero beyond rvdw.
  */
-gmx_bool ir_vdw_might_be_zero_at_cutoff(const t_inputrec* ir);
+bool ir_vdw_might_be_zero_at_cutoff(const t_inputrec* ir);
 
 /*! \brief Free memory from input record.
  *
@@ -616,30 +614,30 @@ gmx_bool ir_vdw_might_be_zero_at_cutoff(const t_inputrec* ir);
  */
 void done_inputrec(t_inputrec* ir);
 
-void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir, gmx_bool bMDPformat);
+void pr_inputrec(FILE* fp, int indent, const char* title, const t_inputrec* ir, 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, const pull_params_t& pull, real ftol, real abstol);
 
 
-gmx_bool inputrecDeform(const t_inputrec* ir);
+bool inputrecDeform(const t_inputrec* ir);
 
-gmx_bool inputrecDynamicBox(const t_inputrec* ir);
+bool inputrecDynamicBox(const t_inputrec* ir);
 
-gmx_bool inputrecPreserveShape(const t_inputrec* ir);
+bool inputrecPreserveShape(const t_inputrec* ir);
 
-gmx_bool inputrecNeedMutot(const t_inputrec* ir);
+bool inputrecNeedMutot(const t_inputrec* ir);
 
-gmx_bool inputrecTwinRange(const t_inputrec* ir);
+bool inputrecTwinRange(const t_inputrec* ir);
 
-gmx_bool inputrecExclForces(const t_inputrec* ir);
+bool inputrecExclForces(const t_inputrec* ir);
 
-gmx_bool inputrecNptTrotter(const t_inputrec* ir);
+bool inputrecNptTrotter(const t_inputrec* ir);
 
-gmx_bool inputrecNvtTrotter(const t_inputrec* ir);
+bool inputrecNvtTrotter(const t_inputrec* ir);
 
-gmx_bool inputrecNphTrotter(const t_inputrec* ir);
+bool inputrecNphTrotter(const t_inputrec* ir);
 
 /*! \brief Return true if the simulation is 2D periodic with two walls. */
 bool inputrecPbcXY2Walls(const t_inputrec* ir);
index 230dca2bff54cdb586c950b73cdd783ee7e76f59..9353a24047aa105f840968e450cd0f975652f118 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/ewald/ewald_utils.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
+#include "gromacs/mdlib/rf_util.h"
+#include "gromacs/mdtypes/forcerec.h"
 #include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/topology/topology.h"
+#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/pleasecite.h"
 
 interaction_const_t::SoftCoreParameters::SoftCoreParameters(const t_lambda& fepvals) :
     alphaVdw(fepvals.sc_alpha),
@@ -51,3 +58,320 @@ interaction_const_t::SoftCoreParameters::SoftCoreParameters(const t_lambda& fepv
     // This is checked during tpr reading, so we can assert here
     GMX_RELEASE_ASSERT(fepvals.sc_r_power == 6.0, "We only support soft-core r-power 6");
 }
+
+/*! \brief Print Coulomb Ewald citations and set ewald coefficients */
+static void initCoulombEwaldParameters(FILE*                fp,
+                                       const t_inputrec&    ir,
+                                       bool                 systemHasNetCharge,
+                                       interaction_const_t* ic)
+{
+    if (!EEL_PME_EWALD(ir.coulombtype))
+    {
+        return;
+    }
+
+    if (fp)
+    {
+        fprintf(fp, "Will do PME sum in reciprocal space for electrostatic interactions.\n");
+
+        if (ir.coulombtype == CoulombInteractionType::P3mAD)
+        {
+            please_cite(fp, "Hockney1988");
+            please_cite(fp, "Ballenegger2012");
+        }
+        else
+        {
+            please_cite(fp, "Essmann95a");
+        }
+
+        if (ir.ewald_geometry == EwaldGeometry::ThreeDC)
+        {
+            if (fp)
+            {
+                fprintf(fp,
+                        "Using the Ewald3DC correction for systems with a slab geometry%s.\n",
+                        systemHasNetCharge ? " and net charge" : "");
+            }
+            please_cite(fp, "In-Chul99a");
+            if (systemHasNetCharge)
+            {
+                please_cite(fp, "Ballenegger2009");
+            }
+        }
+    }
+
+    ic->ewaldcoeff_q = calc_ewaldcoeff_q(ir.rcoulomb, ir.ewald_rtol);
+    if (fp)
+    {
+        fprintf(fp, "Using a Gaussian width (1/beta) of %g nm for Ewald\n", 1 / ic->ewaldcoeff_q);
+    }
+
+    if (ic->coulomb_modifier == InteractionModifiers::PotShift)
+    {
+        GMX_RELEASE_ASSERT(ic->rcoulomb != 0, "Cutoff radius cannot be zero");
+        ic->sh_ewald = std::erfc(ic->ewaldcoeff_q * ic->rcoulomb) / ic->rcoulomb;
+    }
+    else
+    {
+        ic->sh_ewald = 0;
+    }
+}
+
+/*! \brief Print Van der Waals Ewald citations and set ewald coefficients */
+static void initVdwEwaldParameters(FILE* fp, const t_inputrec& ir, interaction_const_t* ic)
+{
+    if (!EVDW_PME(ir.vdwtype))
+    {
+        return;
+    }
+
+    if (fp)
+    {
+        fprintf(fp, "Will do PME sum in reciprocal space for LJ dispersion interactions.\n");
+        please_cite(fp, "Essmann95a");
+    }
+    ic->ewaldcoeff_lj = calc_ewaldcoeff_lj(ir.rvdw, ir.ewald_rtol_lj);
+    if (fp)
+    {
+        fprintf(fp, "Using a Gaussian width (1/beta) of %g nm for LJ Ewald\n", 1 / ic->ewaldcoeff_lj);
+    }
+
+    if (ic->vdw_modifier == InteractionModifiers::PotShift)
+    {
+        real crc2       = gmx::square(ic->ewaldcoeff_lj * ic->rvdw);
+        ic->sh_lj_ewald = (std::exp(-crc2) * (1 + crc2 + 0.5 * crc2 * crc2) - 1) / gmx::power6(ic->rvdw);
+    }
+    else
+    {
+        ic->sh_lj_ewald = 0;
+    }
+}
+
+static real calcBuckinghamBMax(FILE* fplog, const gmx_mtop_t& mtop)
+{
+    const t_atoms *at1, *at2;
+    int            i, j, tpi, tpj, ntypes;
+    real           b, bmin;
+
+    if (fplog)
+    {
+        fprintf(fplog, "Determining largest Buckingham b parameter for table\n");
+    }
+    ntypes = mtop.ffparams.atnr;
+
+    bmin            = -1;
+    real bham_b_max = 0;
+    for (size_t mt1 = 0; mt1 < mtop.moltype.size(); mt1++)
+    {
+        at1 = &mtop.moltype[mt1].atoms;
+        for (i = 0; (i < at1->nr); i++)
+        {
+            tpi = at1->atom[i].type;
+            if (tpi >= ntypes)
+            {
+                gmx_fatal(FARGS, "Atomtype[%d] = %d, maximum = %d", i, tpi, ntypes);
+            }
+
+            for (size_t mt2 = mt1; mt2 < mtop.moltype.size(); mt2++)
+            {
+                at2 = &mtop.moltype[mt2].atoms;
+                for (j = 0; (j < at2->nr); j++)
+                {
+                    tpj = at2->atom[j].type;
+                    if (tpj >= ntypes)
+                    {
+                        gmx_fatal(FARGS, "Atomtype[%d] = %d, maximum = %d", j, tpj, ntypes);
+                    }
+                    b = mtop.ffparams.iparams[tpi * ntypes + tpj].bham.b;
+                    if (b > bham_b_max)
+                    {
+                        bham_b_max = b;
+                    }
+                    if ((b < bmin) || (bmin == -1))
+                    {
+                        bmin = b;
+                    }
+                }
+            }
+        }
+    }
+    if (fplog)
+    {
+        fprintf(fplog, "Buckingham b parameters, min: %g, max: %g\n", bmin, bham_b_max);
+    }
+
+    return bham_b_max;
+}
+
+static void clear_force_switch_constants(shift_consts_t* sc)
+{
+    sc->c2   = 0;
+    sc->c3   = 0;
+    sc->cpot = 0;
+}
+
+static void force_switch_constants(real p, real rsw, real rc, shift_consts_t* sc)
+{
+    /* Here we determine the coefficient for shifting the force to zero
+     * between distance rsw and the cut-off rc.
+     * For a potential of r^-p, we have force p*r^-(p+1).
+     * But to save flops we absorb p in the coefficient.
+     * Thus we get:
+     * force/p   = r^-(p+1) + c2*r^2 + c3*r^3
+     * potential = r^-p + c2/3*r^3 + c3/4*r^4 + cpot
+     */
+    sc->c2   = ((p + 1) * rsw - (p + 4) * rc) / (pow(rc, p + 2) * gmx::square(rc - rsw));
+    sc->c3   = -((p + 1) * rsw - (p + 3) * rc) / (pow(rc, p + 2) * gmx::power3(rc - rsw));
+    sc->cpot = -pow(rc, -p) + p * sc->c2 / 3 * gmx::power3(rc - rsw)
+               + p * sc->c3 / 4 * gmx::power4(rc - rsw);
+}
+
+static void potential_switch_constants(real rsw, real rc, switch_consts_t* sc)
+{
+    /* The switch function is 1 at rsw and 0 at rc.
+     * The derivative and second derivate are zero at both ends.
+     * rsw        = max(r - r_switch, 0)
+     * sw         = 1 + c3*rsw^3 + c4*rsw^4 + c5*rsw^5
+     * dsw        = 3*c3*rsw^2 + 4*c4*rsw^3 + 5*c5*rsw^4
+     * force      = force*dsw - potential*sw
+     * potential *= sw
+     */
+    sc->c3 = -10 / gmx::power3(rc - rsw);
+    sc->c4 = 15 / gmx::power4(rc - rsw);
+    sc->c5 = -6 / gmx::power5(rc - rsw);
+}
+
+
+interaction_const_t init_interaction_const(FILE* fp, const t_inputrec& ir, const gmx_mtop_t& mtop, bool systemHasNetCharge)
+{
+    interaction_const_t interactionConst;
+
+    interactionConst.coulombEwaldTables = std::make_unique<EwaldCorrectionTables>();
+    interactionConst.vdwEwaldTables     = std::make_unique<EwaldCorrectionTables>();
+
+    /* Lennard-Jones */
+    interactionConst.vdwtype         = ir.vdwtype;
+    interactionConst.vdw_modifier    = ir.vdw_modifier;
+    interactionConst.reppow          = mtop.ffparams.reppow;
+    interactionConst.rvdw            = cutoff_inf(ir.rvdw);
+    interactionConst.rvdw_switch     = ir.rvdw_switch;
+    interactionConst.ljpme_comb_rule = ir.ljpme_combination_rule;
+    interactionConst.useBuckingham   = (mtop.ffparams.functype[0] == F_BHAM);
+    if (interactionConst.useBuckingham)
+    {
+        interactionConst.buckinghamBMax = calcBuckinghamBMax(fp, mtop);
+    }
+
+    initVdwEwaldParameters(fp, ir, &interactionConst);
+
+    clear_force_switch_constants(&interactionConst.dispersion_shift);
+    clear_force_switch_constants(&interactionConst.repulsion_shift);
+
+    switch (interactionConst.vdw_modifier)
+    {
+        case InteractionModifiers::PotShift:
+            /* Only shift the potential, don't touch the force */
+            interactionConst.dispersion_shift.cpot = -1.0 / gmx::power6(interactionConst.rvdw);
+            interactionConst.repulsion_shift.cpot  = -1.0 / gmx::power12(interactionConst.rvdw);
+            break;
+        case InteractionModifiers::ForceSwitch:
+            /* Switch the force, switch and shift the potential */
+            force_switch_constants(
+                    6.0, interactionConst.rvdw_switch, interactionConst.rvdw, &interactionConst.dispersion_shift);
+            force_switch_constants(
+                    12.0, interactionConst.rvdw_switch, interactionConst.rvdw, &interactionConst.repulsion_shift);
+            break;
+        case InteractionModifiers::PotSwitch:
+            /* Switch the potential and force */
+            potential_switch_constants(
+                    interactionConst.rvdw_switch, interactionConst.rvdw, &interactionConst.vdw_switch);
+            break;
+        case InteractionModifiers::None:
+        case InteractionModifiers::ExactCutoff:
+            /* Nothing to do here */
+            break;
+        default: gmx_incons("unimplemented potential modifier");
+    }
+
+    /* Electrostatics */
+    interactionConst.eeltype          = ir.coulombtype;
+    interactionConst.coulomb_modifier = ir.coulomb_modifier;
+    interactionConst.rcoulomb         = cutoff_inf(ir.rcoulomb);
+    interactionConst.rcoulomb_switch  = ir.rcoulomb_switch;
+    interactionConst.epsilon_r        = ir.epsilon_r;
+
+    /* Set the Coulomb energy conversion factor */
+    if (interactionConst.epsilon_r != 0)
+    {
+        interactionConst.epsfac = gmx::c_one4PiEps0 / interactionConst.epsilon_r;
+    }
+    else
+    {
+        /* eps = 0 is infinite dieletric: no Coulomb interactions */
+        interactionConst.epsfac = 0;
+    }
+
+    /* Reaction-field */
+    if (EEL_RF(interactionConst.eeltype))
+    {
+        GMX_RELEASE_ASSERT(interactionConst.eeltype != CoulombInteractionType::GRFNotused,
+                           "GRF is no longer supported");
+        interactionConst.reactionFieldPermitivity = ir.epsilon_rf;
+        calc_rffac(fp,
+                   interactionConst.epsilon_r,
+                   interactionConst.reactionFieldPermitivity,
+                   interactionConst.rcoulomb,
+                   &interactionConst.reactionFieldCoefficient,
+                   &interactionConst.reactionFieldShift);
+    }
+    else
+    {
+        /* For plain cut-off we might use the reaction-field kernels */
+        interactionConst.reactionFieldPermitivity = interactionConst.epsilon_r;
+        interactionConst.reactionFieldCoefficient = 0;
+        if (ir.coulomb_modifier == InteractionModifiers::PotShift)
+        {
+            interactionConst.reactionFieldShift = 1 / interactionConst.rcoulomb;
+        }
+        else
+        {
+            interactionConst.reactionFieldShift = 0;
+        }
+    }
+
+    initCoulombEwaldParameters(fp, ir, systemHasNetCharge, &interactionConst);
+
+    if (fp != nullptr)
+    {
+        real dispersion_shift;
+
+        dispersion_shift = interactionConst.dispersion_shift.cpot;
+        if (EVDW_PME(interactionConst.vdwtype))
+        {
+            dispersion_shift -= interactionConst.sh_lj_ewald;
+        }
+        fprintf(fp,
+                "Potential shift: LJ r^-12: %.3e r^-6: %.3e",
+                interactionConst.repulsion_shift.cpot,
+                dispersion_shift);
+
+        if (interactionConst.eeltype == CoulombInteractionType::Cut)
+        {
+            fprintf(fp, ", Coulomb %.e", -interactionConst.reactionFieldShift);
+        }
+        else if (EEL_PME(interactionConst.eeltype))
+        {
+            fprintf(fp, ", Ewald %.3e", -interactionConst.sh_ewald);
+        }
+        fprintf(fp, "\n");
+    }
+
+    if (ir.efep != FreeEnergyPerturbationType::No)
+    {
+        GMX_RELEASE_ASSERT(ir.fepvals, "ir.fepvals should be set wth free-energy");
+        interactionConst.softCoreParameters =
+                std::make_unique<interaction_const_t::SoftCoreParameters>(*ir.fepvals);
+    }
+
+    return interactionConst;
+}
index 9114297bab5e789f37299e823228083122b0e931..aee0a64ea9eb51782b6f055db6757659fb5d8871 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_INTERACTION_CONST_H
 #define GMX_MDTYPES_INTERACTION_CONST_H
 
+#include <cstdio>
+
 #include <memory>
 #include <vector>
 
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/utility/alignedallocator.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
 struct t_lambda;
+struct t_inputrec;
+struct gmx_mtop_t;
 
 /* Used with force switching or a constant potential shift:
  * rsw       = max(r - r_switch, 0)
@@ -127,40 +130,43 @@ struct interaction_const_t
     };
 
     /* VdW */
-    int                    vdwtype          = evdwCUT;
-    int                    vdw_modifier     = eintmodNONE;
+    VanDerWaalsType        vdwtype          = VanDerWaalsType::Cut;
+    InteractionModifiers   vdw_modifier     = InteractionModifiers::None;
     double                 reppow           = 12;
     real                   rvdw             = 1;
     real                   rvdw_switch      = 0;
     struct shift_consts_t  dispersion_shift = { 0, 0, 0 };
     struct shift_consts_t  repulsion_shift  = { 0, 0, 0 };
     struct switch_consts_t vdw_switch       = { 0, 0, 0 };
-    gmx_bool               useBuckingham    = false;
+    bool                   useBuckingham    = false;
     real                   buckinghamBMax   = 0;
 
     /* type of electrostatics */
-    int eeltype          = eelCUT;
-    int coulomb_modifier = eintmodNONE;
+    CoulombInteractionType eeltype          = CoulombInteractionType::Cut;
+    InteractionModifiers   coulomb_modifier = InteractionModifiers::None;
 
     /* Coulomb */
     real rcoulomb        = 1;
     real rcoulomb_switch = 0;
 
     /* PME/Ewald */
-    real ewaldcoeff_q    = 0;
-    real ewaldcoeff_lj   = 0;
-    int  ljpme_comb_rule = eljpmeGEOM; /* LJ combination rule for the LJ PME mesh part */
-    real sh_ewald        = 0;          /* -sh_ewald is added to the direct space potential */
-    real sh_lj_ewald     = 0;          /* sh_lj_ewald is added to the correction potential */
+    real ewaldcoeff_q  = 0;
+    real ewaldcoeff_lj = 0;
+    LongRangeVdW ljpme_comb_rule = LongRangeVdW::Geom; /* LJ combination rule for the LJ PME mesh part */
+    real sh_ewald                = 0; /* -sh_ewald is added to the direct space potential */
+    real sh_lj_ewald = 0;             /* sh_lj_ewald is added to the correction potential */
 
     /* Dielectric constant resp. multiplication factor for charges */
     real epsilon_r = 1;
     real epsfac    = 1;
 
     /* Constants for reaction-field or plain cut-off */
-    real epsilon_rf = 1;
-    real k_rf       = 0;
-    real c_rf       = 0;
+    //! Dielectric constant for reaction field beyond the cutoff distance
+    real reactionFieldPermitivity = 1;
+    //! Coefficient for reaction field; scales relation between epsilon_r and reactionFieldPermitivity
+    real reactionFieldCoefficient = 0;
+    //! Constant shift to reaction field Coulomb interaction to make potential an integral of force
+    real reactionFieldShift = 0;
 
     // Coulomb Ewald correction table
     std::unique_ptr<EwaldCorrectionTables> coulombEwaldTables;
@@ -171,4 +177,15 @@ struct interaction_const_t
     std::unique_ptr<SoftCoreParameters> softCoreParameters;
 };
 
+/*! \brief Construct interaction constants
+ *
+ * This data is used (particularly) by search and force code for
+ * short-range interactions. Many of these are constant for the whole
+ * simulation; some are constant only after PME tuning completes.
+ */
+interaction_const_t init_interaction_const(FILE*             fp,
+                                           const t_inputrec& ir,
+                                           const gmx_mtop_t& mtop,
+                                           bool              systemHasNetCharge);
+
 #endif
index 4805336f1ca4e5a01a59f38aba0b1b7e3760823f..709fcfa3ace519afedc06a7cada6a1135126f41f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_MDTYPES_LOCALITY_H
 
 #include "gromacs/utility/enumerationhelpers.h"
+#include "gromacs/utility/exceptions.h"
 
 namespace gmx
 {
@@ -83,6 +84,33 @@ static const EnumerationArray<InteractionLocality, const char*> c_interactionLoc
     { "local", "non-local" }
 };
 
+/*! \brief Convert atom locality to interaction locality.
+ *
+ *  In the current implementation the this is straightforward conversion:
+ *  local to local, non-local to non-local.
+ *
+ *  \param[in] atomLocality Atom locality specifier
+ *  \returns                Interaction locality corresponding to the atom locality passed.
+ */
+static inline InteractionLocality atomToInteractionLocality(const AtomLocality atomLocality)
+{
+
+    /* determine interaction locality from atom locality */
+    if (atomLocality == AtomLocality::Local)
+    {
+        return InteractionLocality::Local;
+    }
+    else if (atomLocality == AtomLocality::NonLocal)
+    {
+        return InteractionLocality::NonLocal;
+    }
+    else
+    {
+        GMX_THROW(gmx::InconsistentInputError(
+                "Only Local and NonLocal atom locities can be converted to interaction locality."));
+    }
+}
+
 } // namespace gmx
 
 #endif // GMX_MDTYPES_LOCALITY_H
index 65eef2ff80294259cfa8b9b8a8c5cc400b9a5fbf..d8999ba87cad94740a32d479cd0c5b252c0ed41f 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -39,7 +39,9 @@
 
 #include "md_enums.h"
 
-const char* enum_name(int index, int max_index, const char* names[])
+#include "gromacs/utility/enumerationhelpers.h"
+
+const char* enum_name(int index, int max_index, const char* const names[])
 {
     if (index < 0 || index >= max_index)
     {
@@ -52,142 +54,351 @@ const char* enum_name(int index, int max_index, const char* names[])
     }
 }
 
-const char* yesno_names[BOOL_NR + 1] = { "no", "yes", nullptr };
-
-const char* ei_names[eiNR + 1] = { "md",    "steep",      "cg",    "bd",   "sd2 - removed",
-                                   "nm",    "l-bfgs",     "tpi",   "tpic", "sd",
-                                   "md-vv", "md-vv-avek", "mimic", nullptr };
+const char* enumValueToString(IntegrationAlgorithm enumValue)
+{
+    static constexpr gmx::EnumerationArray<IntegrationAlgorithm, const char*> interationAlgorithmNames = {
+        "md",  "steep", "cg", "bd",    "sd2 - removed", "nm",   "l-bfgs",
+        "tpi", "tpic",  "sd", "md-vv", "md-vv-avek",    "mimic"
+    };
+    return interationAlgorithmNames[enumValue];
+}
 
-const char* ecutscheme_names[ecutsNR + 1] = { "Verlet", "Group", nullptr };
+const char* enumValueToString(CoulombInteractionType enumValue)
+{
+    static constexpr gmx::EnumerationArray<CoulombInteractionType, const char*> coloumbTreatmentNames = {
+        "Cut-off",
+        "Reaction-Field",
+        "Generalized-Reaction-Field (unused)",
+        "PME",
+        "Ewald",
+        "P3M-AD",
+        "Poisson",
+        "Switch",
+        "Shift",
+        "User",
+        "Generalized-Born (unused)",
+        "Reaction-Field-nec (unsupported)",
+        "Encad-shift (unused)",
+        "PME-User",
+        "PME-Switch",
+        "PME-User-Switch",
+        "Reaction-Field-zero"
+    };
+    return coloumbTreatmentNames[enumValue];
+}
 
-const char* erefscaling_names[erscNR + 1] = { "No", "All", "COM", nullptr };
+const char* enumValueToString(EwaldGeometry enumValue)
+{
+    static constexpr gmx::EnumerationArray<EwaldGeometry, const char*> ewaldGeometryNames = {
+        "3d", "3dc"
+    };
+    return ewaldGeometryNames[enumValue];
+}
 
-const char* eel_names[eelNR + 1] = { "Cut-off",
-                                     "Reaction-Field",
-                                     "Generalized-Reaction-Field (unused)",
-                                     "PME",
-                                     "Ewald",
-                                     "P3M-AD",
-                                     "Poisson",
-                                     "Switch",
-                                     "Shift",
-                                     "User",
-                                     "Generalized-Born (unused)",
-                                     "Reaction-Field-nec (unsupported)",
-                                     "Encad-shift (unused)",
-                                     "PME-User",
-                                     "PME-Switch",
-                                     "PME-User-Switch",
-                                     "Reaction-Field-zero",
-                                     nullptr };
+const char* enumValueToString(LongRangeVdW enumValue)
+{
+    static constexpr gmx::EnumerationArray<LongRangeVdW, const char*> longRangeVdWNames = {
+        "Geometric", "Lorentz-Berthelot"
+    };
+    return longRangeVdWNames[enumValue];
+}
 
-const char* eewg_names[eewgNR + 1] = { "3d", "3dc", nullptr };
+const char* enumValueToString(VanDerWaalsType enumValue)
+{
+    static constexpr gmx::EnumerationArray<VanDerWaalsType, const char*> vanDerWaalsTypeNames = {
+        "Cut-off", "Switch", "Shift", "User", "Encad-shift (unused)", "PME"
+    };
+    return vanDerWaalsTypeNames[enumValue];
+}
 
-const char* eljpme_names[eljpmeNR + 1] = { "Geometric", "Lorentz-Berthelot", nullptr };
+const char* enumValueToString(ConstraintAlgorithm enumValue)
+{
+    static constexpr gmx::EnumerationArray<ConstraintAlgorithm, const char*> constraintAlgorithmNames = {
+        "Lincs", "Shake"
+    };
+    return constraintAlgorithmNames[enumValue];
+}
 
-const char* evdw_names[evdwNR + 1] = { "Cut-off", "Switch", "Shift", "User", "Encad-shift (unused)",
-                                       "PME",     nullptr };
+const char* enumValueToString(InteractionModifiers enumValue)
+{
+    static constexpr gmx::EnumerationArray<InteractionModifiers, const char*> interactionModifierNames = {
+        "Potential-shift-Verlet", "Potential-shift", "None",
+        "Potential-switch",       "Exact-cutoff",    "Force-switch"
+    };
+    return interactionModifierNames[enumValue];
+}
 
-const char* econstr_names[econtNR + 1] = { "Lincs", "Shake", nullptr };
+const char* enumValueToString(TemperatureCoupling enumValue)
+{
+    static constexpr gmx::EnumerationArray<TemperatureCoupling, const char*> temperatureCouplingNames = {
+        "No", "Berendsen", "Nose-Hoover", "yes", "Andersen", "Andersen-massive", "V-rescale"
+    }; /* yes is alias for berendsen */
+    return temperatureCouplingNames[enumValue];
+}
 
-const char* eintmod_names[eintmodNR + 1] = {
-    "Potential-shift-Verlet", "Potential-shift", "None", "Potential-switch",
-    "Exact-cutoff",           "Force-switch",    nullptr
-};
+const char* enumValueToString(PressureCoupling enumValue)
+{
+    static constexpr gmx::EnumerationArray<PressureCoupling, const char*> pressureCouplingNames = {
+        "No", "Berendsen", "Parrinello-Rahman", "Isotropic", "MTTK", "C-rescale"
+    }; /* isotropic is alias for berendsen */
+    return pressureCouplingNames[enumValue];
+}
 
-const char* etcoupl_names[etcNR + 1] = {
-    "No", "Berendsen", "Nose-Hoover", "yes", "Andersen", "Andersen-massive", "V-rescale", nullptr
-}; /* yes is alias for berendsen */
+const char* enumValueToString(Boolean enumValue)
+{
+    static constexpr gmx::EnumerationArray<Boolean, const char*> booleanNames = { "no", "yes" };
+    return booleanNames[enumValue];
+}
 
-const char* epcoupl_names[epcNR + 1] = { "No",        "Berendsen", "Parrinello-Rahman",
-                                         "Isotropic", "MTTK",      "C-rescale",
-                                         nullptr }; /* isotropic is alias for berendsen */
+const char* booleanValueToString(bool value)
+{
+    Boolean enumValue = value ? Boolean::Yes : Boolean::No;
+    return enumValueToString(enumValue);
+}
 
-const char* epcoupltype_names[epctNR + 1] = { "Isotropic", "Semiisotropic", "Anisotropic",
-                                              "Surface-Tension", nullptr };
+const char* enumValueToString(RefCoordScaling enumValue)
+{
+    static constexpr gmx::EnumerationArray<RefCoordScaling, const char*> refCoordScalingNames = {
+        "No", "All", "COM"
+    };
+    return refCoordScalingNames[enumValue];
+}
 
-const char* edisre_names[edrNR + 1] = { "No", "Simple", "Ensemble", nullptr };
+const char* enumValueToString(CutoffScheme enumValue)
+{
+    static constexpr gmx::EnumerationArray<CutoffScheme, const char*> cutoffSchemeNames = {
+        "Verlet", "Group"
+    };
+    return cutoffSchemeNames[enumValue];
+}
 
-const char* edisreweighting_names[edrwNR + 1] = { "Conservative", "Equal", nullptr };
+const char* enumValueToString(PressureCouplingType enumValue)
+{
+    static constexpr gmx::EnumerationArray<PressureCouplingType, const char*> pressureCouplingTypeNames = {
+        "Isotropic", "Semiisotropic", "Anisotropic", "Surface-Tension"
+    };
+    return pressureCouplingTypeNames[enumValue];
+}
 
-const char* enbf_names[eNBF_NR + 1] = { "", "LJ", "Buckingham", nullptr };
+const char* enumValueToString(DistanceRestraintRefinement enumValue)
+{
+    static constexpr gmx::EnumerationArray<DistanceRestraintRefinement, const char*> distanceRestraintRefinementNames = {
+        "No", "Simple", "Ensemble"
+    };
+    return distanceRestraintRefinementNames[enumValue];
+}
 
-const char* ecomb_names[eCOMB_NR + 1] = { "", "Geometric", "Arithmetic", "GeomSigEps", nullptr };
+const char* enumValueToString(DistanceRestraintWeighting enumValue)
+{
+    static constexpr gmx::EnumerationArray<DistanceRestraintWeighting, const char*> distanceRestraintWeightingNames = {
+        "Conservative", "Equal"
+    };
+    return distanceRestraintWeightingNames[enumValue];
+}
 
-const char* esimtemp_names[esimtempNR + 1] = { "geometric", "exponential", "linear", nullptr };
+const char* enumValueToString(VanDerWaalsPotential enumValue)
+{
+    static constexpr gmx::EnumerationArray<VanDerWaalsPotential, const char*> vanDerWaalsPotentialNames = {
+        "None", "LJ", "Buckingham"
+    };
+    return vanDerWaalsPotentialNames[enumValue];
+}
 
-const char* efep_names[efepNR + 1] = { "no", "yes", "static", "slow-growth", "expanded", nullptr };
+const char* enumValueToString(CombinationRule enumValue)
+{
+    static constexpr gmx::EnumerationArray<CombinationRule, const char*> combinationRuleNames = {
+        "None", "Geometric", "Arithmetic", "GeomSigEps"
+    };
+    return combinationRuleNames[enumValue];
+}
 
-const char* efpt_names[efptNR + 1] = { "fep-lambdas",         "mass-lambdas",   "coul-lambdas",
-                                       "vdw-lambdas",         "bonded-lambdas", "restraint-lambdas",
-                                       "temperature-lambdas", nullptr };
+const char* enumValueToString(SimulatedTempering enumValue)
+{
+    static constexpr gmx::EnumerationArray<SimulatedTempering, const char*> simulatedTemperingNames = {
+        "geometric", "exponential", "linear"
+    };
+    return simulatedTemperingNames[enumValue];
+}
 
-const char* efpt_singular_names[efptNR + 1] = { "fep-lambda",         "mass-lambda",
-                                                "coul-lambda",        "vdw-lambda",
-                                                "bonded-lambda",      "restraint-lambda",
-                                                "temperature-lambda", nullptr };
+const char* enumValueToString(FreeEnergyPerturbationType enumValue)
+{
+    static constexpr gmx::EnumerationArray<FreeEnergyPerturbationType, const char*> freeEnergyPerturbationTypeNames = {
+        "no", "yes", "static", "slow-growth", "expanded"
+    };
+    return freeEnergyPerturbationTypeNames[enumValue];
+}
 
-const char* edHdLPrintEnergy_names[edHdLPrintEnergyNR + 1] = { "no", "total", "potential", "yes", nullptr };
+const char* enumValueToString(FreeEnergyPerturbationCouplingType enumValue)
+{
+    static constexpr gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, const char*> freeEnergyPerturbationCouplingTypeNames = {
+        "fep-lambdas",    "mass-lambdas",      "coul-lambdas",       "vdw-lambdas",
+        "bonded-lambdas", "restraint-lambdas", "temperature-lambdas"
+    };
+    return freeEnergyPerturbationCouplingTypeNames[enumValue];
+}
 
-const char* elamstats_names[elamstatsNR + 1] = {
-    "no",     "metropolis-transition", "barker-transition",
-    "minvar", "wang-landau",           "weighted-wang-landau",
-    nullptr
-};
+const char* enumValueToStringSingular(FreeEnergyPerturbationCouplingType enumValue)
+{
+    static constexpr gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, const char*> freeEnergyPerturbationCouplingTypeNames = {
+        "fep-lambda",    "mass-lambda",      "coul-lambda",       "vdw-lambda",
+        "bonded-lambda", "restraint-lambda", "temperature-lambda"
+    };
+    return freeEnergyPerturbationCouplingTypeNames[enumValue];
+}
 
-const char* elmcmove_names[elmcmoveNR + 1] = { "no",    "metropolis",         "barker",
-                                               "gibbs", "metropolized-gibbs", nullptr };
+const char* enumValueToString(FreeEnergyPrintEnergy enumValue)
+{
+    static constexpr gmx::EnumerationArray<FreeEnergyPrintEnergy, const char*> freeEnergyPrintNames = {
+        "no", "total", "potential", "yes"
+    };
+    return freeEnergyPrintNames[enumValue];
+}
 
-const char* elmceq_names[elmceqNR + 1] = { "no",           "yes",
-                                           "wl-delta",     "number-all-lambda",
-                                           "number-steps", "number-samples",
-                                           "count-ratio",  nullptr };
+const char* enumValueToString(LambdaWeightCalculation enumValue)
+{
+    static constexpr gmx::EnumerationArray<LambdaWeightCalculation, const char*> lambdaWeightCalculationNames = {
+        "no",     "metropolis-transition", "barker-transition",
+        "minvar", "wang-landau",           "weighted-wang-landau"
+    };
+    return lambdaWeightCalculationNames[enumValue];
+}
 
-const char* separate_dhdl_file_names[esepdhdlfileNR + 1] = { "yes", "no", nullptr };
+const char* enumValueToString(LambdaMoveCalculation enumValue)
+{
+    static constexpr gmx::EnumerationArray<LambdaMoveCalculation, const char*> lambdaMoveCalculationNames = {
+        "no", "metropolis", "barker", "gibbs", "metropolized-gibbs"
+    };
+    return lambdaMoveCalculationNames[enumValue];
+}
 
-const char* dhdl_derivatives_names[edhdlderivativesNR + 1] = { "yes", "no", nullptr };
+const char* enumValueToString(LambdaWeightWillReachEquilibrium enumValue)
+{
+    static constexpr gmx::EnumerationArray<LambdaWeightWillReachEquilibrium, const char*> lambdaWeightEquilibriumNames = {
+        "no",         "yes", "wl-delta", "number-all-lambda", "number-steps", "number-samples",
+        "count-ratio"
+    };
+    return lambdaWeightEquilibriumNames[enumValue];
+}
 
-const char* esol_names[esolNR + 1] = { "No", "SPC", "TIP4p", nullptr };
+const char* enumValueToString(SeparateDhdlFile enumValue)
+{
+    static constexpr gmx::EnumerationArray<SeparateDhdlFile, const char*> separateDhdlFileNames = {
+        "yes", "no"
+    };
+    return separateDhdlFileNames[enumValue];
+}
 
-const char* edispc_names[edispcNR + 1] = { "No",          "EnerPres", "Ener",
-                                           "AllEnerPres", "AllEner",  nullptr };
+const char* enumValueToString(DhDlDerivativeCalculation enumValue)
+{
+    static constexpr gmx::EnumerationArray<DhDlDerivativeCalculation, const char*> dhdlDerivativeCalculationNames = {
+        "yes", "no"
+    };
+    return dhdlDerivativeCalculationNames[enumValue];
+}
 
-const char* ecm_names[ecmNR + 1] = { "Linear", "Angular", "None", "Linear-acceleration-correction", nullptr };
+const char* enumValueToString(SolventModel enumValue)
+{
+    static constexpr gmx::EnumerationArray<SolventModel, const char*> solventModelNames = {
+        "No", "SPC", "TIP4p"
+    };
+    return solventModelNames[enumValue];
+}
 
-const char* eann_names[eannNR + 1] = { "No", "Single", "Periodic", nullptr };
+const char* enumValueToString(DispersionCorrectionType enumValue)
+{
+    static constexpr gmx::EnumerationArray<DispersionCorrectionType, const char*> dispersionCorrectionTypeNames = {
+        "No", "EnerPres", "Ener", "AllEnerPres", "AllEner"
+    };
+    return dispersionCorrectionTypeNames[enumValue];
+}
 
-const char* ewt_names[ewtNR + 1] = { "9-3", "10-4", "table", "12-6", nullptr };
+const char* enumValueToString(ComRemovalAlgorithm enumValue)
+{
+    static constexpr gmx::EnumerationArray<ComRemovalAlgorithm, const char*> comRemovalAlgorithmNames = {
+        "Linear", "Angular", "None", "Linear-acceleration-correction"
+    };
+    return comRemovalAlgorithmNames[enumValue];
+}
 
-const char* epull_names[epullNR + 1] = { "umbrella",    "constraint",       "constant-force",
-                                         "flat-bottom", "flat-bottom-high", "external-potential",
-                                         nullptr };
+const char* enumValueToString(SimulatedAnnealing enumValue)
+{
+    static constexpr gmx::EnumerationArray<SimulatedAnnealing, const char*> simulatedAnnealingNames = {
+        "No", "Single", "Periodic"
+    };
+    return simulatedAnnealingNames[enumValue];
+}
 
-const char* epullg_names[epullgNR + 1] = { "distance",           "direction",          "cylinder",
-                                           "direction-periodic", "direction-relative", "angle",
-                                           "dihedral",           "angle-axis",         nullptr };
+const char* enumValueToString(WallType enumValue)
+{
+    static constexpr gmx::EnumerationArray<WallType, const char*> wallTypeNames = {
+        "9-3", "10-4", "table", "12-6"
+    };
+    return wallTypeNames[enumValue];
+}
 
-const char* erotg_names[erotgNR + 1] = { "iso",   "iso-pf",  "pm",     "pm-pf", "rm",
-                                         "rm-pf", "rm2",     "rm2-pf", "flex",  "flex-t",
-                                         "flex2", "flex2-t", nullptr };
+const char* enumValueToString(PullingAlgorithm enumValue)
+{
+    static constexpr gmx::EnumerationArray<PullingAlgorithm, const char*> pullAlgorithmNames = {
+        "umbrella",    "constraint",       "constant-force",
+        "flat-bottom", "flat-bottom-high", "external-potential"
+    };
+    return pullAlgorithmNames[enumValue];
+}
 
-const char* erotg_fitnames[erotgFitNR + 1] = { "rmsd", "norm", "potential", nullptr };
+const char* enumValueToString(PullGroupGeometry enumValue)
+{
+    static constexpr gmx::EnumerationArray<PullGroupGeometry, const char*> pullGroupControlNames = {
+        "distance",           "direction", "cylinder", "direction-periodic",
+        "direction-relative", "angle",     "dihedral", "angle-axis"
+    };
+    return pullGroupControlNames[enumValue];
+}
 
-const char* eSwapTypes_names[eSwapTypesNR + 1] = { "no", "X", "Y", "Z", nullptr };
+const char* enumValueToString(EnforcedRotationGroupType enumValue)
+{
+    static constexpr gmx::EnumerationArray<EnforcedRotationGroupType, const char*> enforcedRotationGroupNames = {
+        "iso", "iso-pf", "pm",   "pm-pf",  "rm",    "rm-pf",
+        "rm2", "rm2-pf", "flex", "flex-t", "flex2", "flex2-t"
+    };
+    return enforcedRotationGroupNames[enumValue];
+}
 
-const char* eSwapFixedGrp_names[eSwapFixedGrpNR + 1] = { "Split0", "Split1", "Solvent", nullptr };
+const char* enumValueToString(RotationGroupFitting enumValue)
+{
+    static constexpr gmx::EnumerationArray<RotationGroupFitting, const char*> rotationGroupFittingNames = {
+        "rmsd", "norm", "potential"
+    };
+    return rotationGroupFittingNames[enumValue];
+}
 
-const char* gmx_nblist_geometry_names[GMX_NBLIST_GEOMETRY_NR + 1] = {
-    "Particle-Particle", "Water3-Particle", "Water3-Water3", "Water4-Particle",
-    "Water4-Water4",     "CG-CG",           nullptr
-};
+const char* enumValueToString(SwapType enumValue)
+{
+    static constexpr gmx::EnumerationArray<SwapType, const char*> swapTypeNames = {
+        "no", "X", "Y", "Z"
+    };
+    return swapTypeNames[enumValue];
+}
 
-const char* gmx_nblist_interaction_names[GMX_NBLIST_INTERACTION_NR + 1] = { "Standard",
-                                                                            "Free_Energy", nullptr };
+const char* enumValueToString(SwapGroupSplittingType enumValue)
+{
+    static constexpr gmx::EnumerationArray<SwapGroupSplittingType, const char*> swapGroupSplittingTypeNames = {
+        "Split0", "Split1", "Solvent"
+    };
+    return swapGroupSplittingTypeNames[enumValue];
+}
 
-const char* gmx_nbkernel_elec_names[GMX_NBKERNEL_ELEC_NR + 1] = {
-    "None", "Coulomb", "Reaction-Field", "Cubic-Spline-Table", "Ewald", nullptr
-};
+const char* enumValueToString(NbkernelElecType enumValue)
+{
+    static constexpr gmx::EnumerationArray<NbkernelElecType, const char*> nbkernelElecTypeNames = {
+        "None", "Coulomb", "Reaction-Field", "Cubic-Spline-Table", "Ewald"
+    };
+    return nbkernelElecTypeNames[enumValue];
+}
 
-const char* gmx_nbkernel_vdw_names[GMX_NBKERNEL_VDW_NR + 1] = { "None",       "Lennard-Jones",
-                                                                "Buckingham", "Cubic-Spline-Table",
-                                                                "LJEwald",    nullptr };
+const char* enumValueToString(NbkernelVdwType enumValue)
+{
+    static constexpr gmx::EnumerationArray<NbkernelVdwType, const char*> nbkernelVdwTypeNames = {
+        "None", "Lennard-Jones", "Buckingham", "Cubic-Spline-Table", "LJEwald"
+    };
+    return nbkernelVdwTypeNames[enumValue];
+}
index 508a94f6bf16f2314cca7425277b46a6c5724563..59485bdb4289b5c1ae3cf754155f002f1cdf0ea8 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +46,6 @@
 #ifndef GMX_MDTYPES_MD_ENUMS_H
 #define GMX_MDTYPES_MD_ENUMS_H
 
-#include "gromacs/utility/basedefinitions.h"
-
 /*! \brief Return a string from a list of strings
  *
  * If index if within 0 .. max_index-1 returns the corresponding string
  * \param[in] names     The array
  * \return the correct string or "no name defined"
  */
-const char* enum_name(int index, int max_index, const char* names[]);
+const char* enum_name(int index, int max_index, const char* const names[]);
+
+/*! \brief Enum for setting answer to yes or no
+ */
+enum class Boolean : int
+{
+    No,
+    Yes,
+    Count,
+    Default = No
+};
 
-//! Boolean strings no or yes
-extern const char* yesno_names[BOOL_NR + 1];
+//! Return name of boolean selection.
+const char* enumValueToString(Boolean enumValue);
+//! Return name of boolean selection for actual bool.
+const char* booleanValueToString(bool value);
 
 //! \brief The two compartments for CompEL setups.
-enum eCompartment
+enum class Compartment : int
 {
-    eCompA,
-    eCompB,
-    eCompNR
+    A,
+    B,
+    Count
 };
 
 /*! \brief The channels that define with their COM the compartment boundaries in CompEL setups.
  *
  * In principle one could also use modified setups with more than two channels.
  */
-enum eChannel
+enum class Channel : int
 {
-    eChan0,
-    eChan1,
-    eChanNR
+    Zero,
+    One,
+    Count
 };
 
 /*! \brief Temperature coupling type
  *
  * yes is an alias for berendsen
+ *
+ * Note: Keep `Count` as the second-to-last entry, and `Default` as the last entry -
+ *       this is needed to keep EnumerationWrapper, EnumerationArray and (de)serialization
+ *       working.
  */
-enum
-{
-    etcNO,
-    etcBERENDSEN,
-    etcNOSEHOOVER,
-    etcYES,
-    etcANDERSEN,
-    etcANDERSENMASSIVE,
-    etcVRESCALE,
-    etcNR
-};
-//! Strings corresponding to temperatyre coupling types
-extern const char* etcoupl_names[etcNR + 1];
-//! Macro for selecting t coupling string
-#define ETCOUPLTYPE(e) enum_name(e, etcNR, etcoupl_names)
+enum class TemperatureCoupling : int
+{
+    No,
+    Berendsen,
+    NoseHoover,
+    Yes,
+    Andersen,
+    AndersenMassive,
+    VRescale,
+    Count,
+    Default = No
+};
+//! Return names of temperature coupling schemes
+const char* enumValueToString(TemperatureCoupling enumValue);
 //! Return whether this is andersen coupling
-#define ETC_ANDERSEN(e) (((e) == etcANDERSENMASSIVE) || ((e) == etcANDERSEN))
+#define ETC_ANDERSEN(e) \
+    (((e) == TemperatureCoupling::AndersenMassive) || ((e) == TemperatureCoupling::Andersen))
 
 /*! \brief Pressure coupling types
  *
  * isotropic is an alias for berendsen
+ *
+ * Note: Keep `Count` as the second-to-last entry, and `Default` as the last entry -
+ *       this is needed to keep EnumerationWrapper, EnumerationArray and (de)serialization
+ *       working.
  */
-enum
+enum class PressureCoupling : int
 {
-    epcNO,
-    epcBERENDSEN,
-    epcPARRINELLORAHMAN,
-    epcISOTROPIC,
-    epcMTTK,
-    epcCRESCALE,
-    epcNR
+    No,
+    Berendsen,
+    ParrinelloRahman,
+    Isotropic,
+    Mttk,
+    CRescale,
+    Count,
+    Default = No
 };
-//! String corresponding to pressure coupling algorithm
-extern const char* epcoupl_names[epcNR + 1];
-//! Macro to return the correct pcoupling string
-#define EPCOUPLTYPE(e) enum_name(e, epcNR, epcoupl_names)
+//! Return names of pressure coupling schemes
+const char* enumValueToString(PressureCoupling enumValue);
 
 //! Flat-bottom posres geometries
 enum
@@ -139,17 +156,17 @@ enum
 };
 
 //! Relative coordinate scaling type for position restraints.
-enum
+enum class RefCoordScaling : int
 {
-    erscNO,
-    erscALL,
-    erscCOM,
-    erscNR
+    No,
+    All,
+    Com,
+    Count,
+    Default = No
 };
-//! String corresponding to relativ coordinate scaling.
-extern const char* erefscaling_names[erscNR + 1];
-//! Macro to select correct coordinate scaling string.
-#define EREFSCALINGTYPE(e) enum_name(e, erscNR, erefscaling_names)
+
+//! String corresponding to relative coordinate scaling.
+const char* enumValueToString(RefCoordScaling enumValue);
 
 //! Trotter decomposition extended variable parts.
 enum
@@ -180,132 +197,132 @@ enum
 };
 
 //! Pressure coupling type
-enum
+enum class PressureCouplingType : int
 {
-    epctISOTROPIC,
-    epctSEMIISOTROPIC,
-    epctANISOTROPIC,
-    epctSURFACETENSION,
-    epctNR
+    Isotropic,
+    SemiIsotropic,
+    Anisotropic,
+    SurfaceTension,
+    Count,
+    Default = Isotropic
 };
 //! String corresponding to pressure coupling type
-extern const char* epcoupltype_names[epctNR + 1];
-//! Macro to select the right string for pcoupl type
-#define EPCOUPLTYPETYPE(e) enum_name(e, epctNR, epcoupltype_names)
+const char* enumValueToString(PressureCouplingType enumValue);
 
 //! \\brief Cutoff scheme
-enum
+enum class CutoffScheme : int
 {
-    ecutsVERLET,
-    ecutsGROUP,
-    ecutsNR
+    Verlet,
+    Group,
+    Count,
+    Default = Verlet
 };
 //! String corresponding to cutoff scheme
-extern const char* ecutscheme_names[ecutsNR + 1];
-//! Macro to select the right string for cutoff scheme
-#define ECUTSCHEME(e) enum_name(e, ecutsNR, ecutscheme_names)
+const char* enumValueToString(CutoffScheme enumValue);
 
 /*! \brief Coulomb / VdW interaction modifiers.
  *
  * grompp replaces eintmodPOTSHIFT_VERLET_UNSUPPORTED by eintmodPOTSHIFT.
  * Exactcutoff is only used by Reaction-field-zero, and is not user-selectable.
  */
-enum eintmod
+enum class InteractionModifiers : int
 {
-    eintmodPOTSHIFT_VERLET_UNSUPPORTED,
-    eintmodPOTSHIFT,
-    eintmodNONE,
-    eintmodPOTSWITCH,
-    eintmodEXACTCUTOFF,
-    eintmodFORCESWITCH,
-    eintmodNR
+    PotShiftVerletUnsupported,
+    PotShift,
+    None,
+    PotSwitch,
+    ExactCutoff,
+    ForceSwitch,
+    Count,
+    Default = PotShiftVerletUnsupported
 };
 //! String corresponding to interaction modifiers
-extern const char* eintmod_names[eintmodNR + 1];
-//! Macro to select the correct string for modifiers
-#define INTMODIFIER(e) enum_name(e, eintmodNR, eintmod_names)
+const char* enumValueToString(InteractionModifiers enumValue);
 
 /*! \brief Cut-off treatment for Coulomb */
-enum
-{
-    eelCUT,
-    eelRF,
-    eelGRF_NOTUSED,
-    eelPME,
-    eelEWALD,
-    eelP3M_AD,
-    eelPOISSON,
-    eelSWITCH,
-    eelSHIFT,
-    eelUSER,
-    eelGB_NOTUSED,
-    eelRF_NEC_UNSUPPORTED,
-    eelENCADSHIFT_NOTUSED,
-    eelPMEUSER,
-    eelPMESWITCH,
-    eelPMEUSERSWITCH,
-    eelRF_ZERO,
-    eelNR
+enum class CoulombInteractionType : int
+{
+    Cut,
+    RF,
+    GRFNotused,
+    Pme,
+    Ewald,
+    P3mAD,
+    Poisson,
+    Switch,
+    Shift,
+    User,
+    GBNotused,
+    RFNecUnsupported,
+    EncadShiftNotused,
+    PmeUser,
+    PmeSwitch,
+    PmeUserSwitch,
+    RFZero,
+    Count,
+    Default = Cut
 };
 //! String corresponding to Coulomb treatment
-extern const char* eel_names[eelNR + 1];
-//! Macro for correct string for Coulomb treatment
-#define EELTYPE(e) enum_name(e, eelNR, eel_names)
+const char* enumValueToString(CoulombInteractionType enumValue);
 
 //! Ewald geometry.
-enum
+enum class EwaldGeometry : int
 {
-    eewg3D,
-    eewg3DC,
-    eewgNR
+    ThreeD,
+    ThreeDC,
+    Count,
+    Default = ThreeD
 };
 //! String corresponding to Ewald geometry
-extern const char* eewg_names[eewgNR + 1];
+const char* enumValueToString(EwaldGeometry enumValue);
 
 //! Macro telling us whether we use reaction field
-#define EEL_RF(e) \
-    ((e) == eelRF || (e) == eelGRF_NOTUSED || (e) == eelRF_NEC_UNSUPPORTED || (e) == eelRF_ZERO)
+#define EEL_RF(e)                                                                   \
+    ((e) == CoulombInteractionType::RF || (e) == CoulombInteractionType::GRFNotused \
+     || (e) == CoulombInteractionType::RFNecUnsupported || (e) == CoulombInteractionType::RFZero)
 
 //! Macro telling us whether we use PME
-#define EEL_PME(e) \
-    ((e) == eelPME || (e) == eelPMESWITCH || (e) == eelPMEUSER || (e) == eelPMEUSERSWITCH || (e) == eelP3M_AD)
+#define EEL_PME(e)                                                                             \
+    ((e) == CoulombInteractionType::Pme || (e) == CoulombInteractionType::PmeSwitch            \
+     || (e) == CoulombInteractionType::PmeUser || (e) == CoulombInteractionType::PmeUserSwitch \
+     || (e) == CoulombInteractionType::P3mAD)
 //! Macro telling us whether we use PME or full Ewald
-#define EEL_PME_EWALD(e) (EEL_PME(e) || (e) == eelEWALD)
+#define EEL_PME_EWALD(e) (EEL_PME(e) || (e) == CoulombInteractionType::Ewald)
 //! Macro telling us whether we use full electrostatics of any sort
-#define EEL_FULL(e) (EEL_PME_EWALD(e) || (e) == eelPOISSON)
+#define EEL_FULL(e) (EEL_PME_EWALD(e) || (e) == CoulombInteractionType::Poisson)
 //! Macro telling us whether we use user defined electrostatics
-#define EEL_USER(e) ((e) == eelUSER || (e) == eelPMEUSER || (e) == (eelPMEUSERSWITCH))
+#define EEL_USER(e)                                                                \
+    ((e) == CoulombInteractionType::User || (e) == CoulombInteractionType::PmeUser \
+     || (e) == (CoulombInteractionType::PmeUserSwitch))
 
 //! Van der Waals interaction treatment
-enum
+enum class VanDerWaalsType : int
 {
-    evdwCUT,
-    evdwSWITCH,
-    evdwSHIFT,
-    evdwUSER,
-    evdwENCADSHIFT_UNUSED,
-    evdwPME,
-    evdwNR
+    Cut,
+    Switch,
+    Shift,
+    User,
+    EncadShiftUnused,
+    Pme,
+    Count,
+    Default = Cut
 };
 //! String corresponding to Van der Waals treatment
-extern const char* evdw_names[evdwNR + 1];
-//! Macro for selecting correct string for VdW treatment
-#define EVDWTYPE(e) enum_name(e, evdwNR, evdw_names)
+const char* enumValueToString(VanDerWaalsType enumValue);
 
 //! Type of long-range VdW treatment of combination rules
-enum
+enum class LongRangeVdW : int
 {
-    eljpmeGEOM,
-    eljpmeLB,
-    eljpmeNR
+    Geom,
+    LB,
+    Count,
+    Default = Geom
 };
 //! String for LJPME combination rule treatment
-extern const char* eljpme_names[eljpmeNR + 1];
-//! Macro for correct LJPME comb rule name
-#define ELJPMECOMBNAMES(e) enum_name(e, eljpmeNR, eljpme_names)
+const char* enumValueToString(LongRangeVdW enumValue);
 
 //! Macro to tell us whether we use LJPME
-#define EVDW_PME(e) ((e) == evdwPME)
+#define EVDW_PME(e) ((e) == VanDerWaalsType::Pme)
 
 /*! \brief Integrator algorithm
  *
@@ -315,480 +332,444 @@ extern const char* eljpme_names[eljpmeNR + 1];
  * eiVVAK uses 1/2*(KE(t-dt/2)+KE(t+dt/2)) as the kinetic energy,
  * and the half step kinetic energy for temperature control
  */
-enum
-{
-    eiMD,
-    eiSteep,
-    eiCG,
-    eiBD,
-    eiSD2_REMOVED,
-    eiNM,
-    eiLBFGS,
-    eiTPI,
-    eiTPIC,
-    eiSD1,
-    eiVV,
-    eiVVAK,
-    eiMimic,
-    eiNR
+enum class IntegrationAlgorithm : int
+{
+    MD,
+    Steep,
+    CG,
+    BD,
+    SD2Removed,
+    NM,
+    LBFGS,
+    TPI,
+    TPIC,
+    SD1,
+    VV,
+    VVAK,
+    Mimic,
+    Count,
+    Default = MD
 };
 //! Name of the integrator algorithm
-extern const char* ei_names[eiNR + 1];
-//! Macro returning integrator string
-#define EI(e) enum_name(e, eiNR, ei_names)
+const char* enumValueToString(IntegrationAlgorithm enumValue);
 //! Do we use MiMiC QM/MM?
-#define EI_MIMIC(e) ((e) == eiMimic)
+#define EI_MIMIC(e) ((e) == IntegrationAlgorithm::Mimic)
 //! Do we use velocity Verlet
-#define EI_VV(e) ((e) == eiVV || (e) == eiVVAK)
+#define EI_VV(e) ((e) == IntegrationAlgorithm::VV || (e) == IntegrationAlgorithm::VVAK)
 //! Do we use molecular dynamics
-#define EI_MD(e) ((e) == eiMD || EI_VV(e) || EI_MIMIC(e))
+#define EI_MD(e) ((e) == IntegrationAlgorithm::MD || EI_VV(e) || EI_MIMIC(e))
 //! Do we use stochastic dynamics
-#define EI_SD(e) ((e) == eiSD1)
+#define EI_SD(e) ((e) == IntegrationAlgorithm::SD1)
 //! Do we use any stochastic integrator
-#define EI_RANDOM(e) (EI_SD(e) || (e) == eiBD)
+#define EI_RANDOM(e) (EI_SD(e) || (e) == IntegrationAlgorithm::BD)
 /*above integrators may not conserve momenta*/
 //! Do we use any type of dynamics
 #define EI_DYNAMICS(e) (EI_MD(e) || EI_RANDOM(e))
 //! Or do we use minimization
-#define EI_ENERGY_MINIMIZATION(e) ((e) == eiSteep || (e) == eiCG || (e) == eiLBFGS)
+#define EI_ENERGY_MINIMIZATION(e)                                          \
+    ((e) == IntegrationAlgorithm::Steep || (e) == IntegrationAlgorithm::CG \
+     || (e) == IntegrationAlgorithm::LBFGS)
 //! Do we apply test particle insertion
-#define EI_TPI(e) ((e) == eiTPI || (e) == eiTPIC)
+#define EI_TPI(e) ((e) == IntegrationAlgorithm::TPI || (e) == IntegrationAlgorithm::TPIC)
 //! Do we deal with particle velocities
 #define EI_STATE_VELOCITY(e) (EI_MD(e) || EI_SD(e))
 
 //! Constraint algorithm
-enum
+enum class ConstraintAlgorithm : int
 {
-    econtLINCS,
-    econtSHAKE,
-    econtNR
+    Lincs,
+    Shake,
+    Count,
+    Default = Lincs
 };
 //! String corresponding to constraint algorithm
-extern const char* econstr_names[econtNR + 1];
-//! Macro to select the correct string
-#define ECONSTRTYPE(e) enum_name(e, econtNR, econstr_names)
+const char* enumValueToString(ConstraintAlgorithm enumValue);
 
 //! Distance restraint refinement algorithm
-enum
+enum class DistanceRestraintRefinement : int
 {
-    edrNone,
-    edrSimple,
-    edrEnsemble,
-    edrNR
+    None,
+    Simple,
+    Ensemble,
+    Count,
+    Default = None
 };
 //! String corresponding to distance restraint algorithm
-extern const char* edisre_names[edrNR + 1];
-//! Macro to select the right disre algorithm string
-#define EDISRETYPE(e) enum_name(e, edrNR, edisre_names)
+const char* enumValueToString(DistanceRestraintRefinement enumValue);
 
 //! Distance restraints weighting type
-enum
+enum class DistanceRestraintWeighting : int
 {
-    edrwConservative,
-    edrwEqual,
-    edrwNR
+    Conservative,
+    Equal,
+    Count,
+    Default = Conservative
 };
 //! String corresponding to distance restraint weighting
-extern const char* edisreweighting_names[edrwNR + 1];
-//! Macro corresponding to dr weighting
-#define EDISREWEIGHTING(e) enum_name(e, edrwNR, edisreweighting_names)
+const char* enumValueToString(DistanceRestraintWeighting enumValue);
 
 //! Combination rule algorithm.
-enum
+enum class CombinationRule : int
 {
-    eCOMB_NONE,
-    eCOMB_GEOMETRIC,
-    eCOMB_ARITHMETIC,
-    eCOMB_GEOM_SIG_EPS,
-    eCOMB_NR
+    None,
+    Geometric,
+    Arithmetic,
+    GeomSigEps,
+    Count,
+    Default = Geometric
 };
 //! String for combination rule algorithm
-extern const char* ecomb_names[eCOMB_NR + 1];
-//! Macro to select the comb rule string
-#define ECOMBNAME(e) enum_name(e, eCOMB_NR, ecomb_names)
+const char* enumValueToString(CombinationRule enumValue);
 
 //! Van der Waals potential.
-enum
+enum class VanDerWaalsPotential : int
 {
-    eNBF_NONE,
-    eNBF_LJ,
-    eNBF_BHAM,
-    eNBF_NR
+    None,
+    LJ,
+    Buckingham,
+    Count,
+    Default = LJ
 };
 //! String corresponding to Van der Waals potential
-extern const char* enbf_names[eNBF_NR + 1];
-//! Macro for correct VdW potential string
-#define ENBFNAME(e) enum_name(e, eNBF_NR, enbf_names)
+const char* enumValueToString(VanDerWaalsPotential enumValue);
 
 //! Simulated tempering methods.
-enum
+enum class SimulatedTempering : int
 {
-    esimtempGEOMETRIC,
-    esimtempEXPONENTIAL,
-    esimtempLINEAR,
-    esimtempNR
+    Geometric,
+    Exponential,
+    Linear,
+    Count,
+    Default = Geometric
 };
 //! String corresponding to simulated tempering
-extern const char* esimtemp_names[esimtempNR + 1];
-//! Macro for correct tempering string
-#define ESIMTEMP(e) enum_name(e, esimtempNR, esimtemp_names)
+const char* enumValueToString(SimulatedTempering enumValue);
 
 /*! \brief Free energy perturbation type
- *
- * efepNO, there are no evaluations at other states.
- * efepYES, treated equivalently to efepSTATIC.
- * efepSTATIC, then lambdas do not change during the simulation.
- * efepSLOWGROWTH, then the states change monotonically
- * throughout the simulation.
- * efepEXPANDED, then expanded ensemble simulations are occuring.
  */
-enum
-{
-    efepNO,
-    efepYES,
-    efepSTATIC,
-    efepSLOWGROWTH,
-    efepEXPANDED,
-    efepNR
+enum class FreeEnergyPerturbationType : int
+{
+    //! there are no evaluations at other states
+    No,
+    //! treated equivalently to Static
+    Yes,
+    //! then lambdas do not change during the simulation
+    Static,
+    //! then the states change monotonically throughout the simulation
+    SlowGrowth,
+    //! then expanded ensemble simulations are occuring
+    Expanded,
+    Count,
+    Default = No
 };
 //! String corresponding to FEP type.
-extern const char* efep_names[efepNR + 1];
-//! Macro corresponding to FEP string.
-#define EFEPTYPE(e) enum_name(e, efepNR, efep_names)
+const char* enumValueToString(FreeEnergyPerturbationType enumValue);
 
 //! Free energy pertubation coupling types.
-enum
-{
-    efptFEP,
-    efptMASS,
-    efptCOUL,
-    efptVDW,
-    efptBONDED,
-    efptRESTRAINT,
-    efptTEMPERATURE,
-    efptNR
+enum class FreeEnergyPerturbationCouplingType : int
+{
+    Fep,
+    Mass,
+    Coul,
+    Vdw,
+    Bonded,
+    Restraint,
+    Temperature,
+    Count,
+    Default = Fep
 };
 //! String for FEP coupling type
-extern const char* efpt_names[efptNR + 1];
-//! Long names for FEP coupling type
-extern const char* efpt_singular_names[efptNR + 1];
+const char* enumValueToString(FreeEnergyPerturbationCouplingType enumValue);
+//! String for FEP coupling type, singular mention.
+const char* enumValueToStringSingular(FreeEnergyPerturbationCouplingType enumValue);
 
 /*! \brief What to print for free energy calculations
  *
  * Printing the energy to the free energy dhdl file.
- * YES is an alias to TOTAL, and
+ * Yes is an alias to Total, and
  * will be converted in readir, so we never have to account for it in code.
  */
-enum
+enum class FreeEnergyPrintEnergy : int
 {
-    edHdLPrintEnergyNO,
-    edHdLPrintEnergyTOTAL,
-    edHdLPrintEnergyPOTENTIAL,
-    edHdLPrintEnergyYES,
-    edHdLPrintEnergyNR
+    No,
+    Total,
+    Potential,
+    Yes,
+    Count,
+    Default = No
 };
 //! String corresponding to printing of free energy
-extern const char* edHdLPrintEnergy_names[edHdLPrintEnergyNR + 1];
+const char* enumValueToString(FreeEnergyPrintEnergy enumValue);
 
 /*! \brief How the lambda weights are calculated
- *
- * elamstatsMETROPOLIS - using the metropolis criteria
- * elamstatsBARKER     - using the Barker critera for transition weights,
- *                       also called unoptimized Bennett
- * elamstatsMINVAR     - using Barker + minimum variance for weights
- * elamstatsWL         - Wang-Landu (using visitation counts)
- * elamstatsWWL        - Weighted Wang-Landau (using optimized Gibbs
- *                       weighted visitation counts)
  */
-enum
-{
-    elamstatsNO,
-    elamstatsMETROPOLIS,
-    elamstatsBARKER,
-    elamstatsMINVAR,
-    elamstatsWL,
-    elamstatsWWL,
-    elamstatsNR
+enum class LambdaWeightCalculation : int
+{
+    //! don't calculate
+    No,
+    //! using the metropolis criteria
+    Metropolis,
+    //! using the Barker critera for transition weights, also called unoptimized Bennett
+    Barker,
+    //! using Barker + minimum variance for weights
+    Minvar,
+    //! Wang-Landu (using visitation counts)
+    WL,
+    //! Weighted Wang-Landau (using optimized Gibbs weighted visitation counts)
+    WWL,
+    Count,
+    Default = No
 };
 //! String corresponding to lambda weights
-extern const char* elamstats_names[elamstatsNR + 1];
+const char* enumValueToString(LambdaWeightCalculation enumValue);
 //! Macro telling us whether we use expanded ensemble
-#define ELAMSTATS_EXPANDED(e) ((e) > elamstatsNO)
+#define ELAMSTATS_EXPANDED(e) ((e) > LambdaWeightCalculation::No)
 //! Macro telling us whether we use some kind of Wang-Landau
-#define EWL(e) ((e) == elamstatsWL || (e) == elamstatsWWL)
+#define EWL(e) ((e) == LambdaWeightCalculation::WL || (e) == LambdaWeightCalculation::WWL)
 
 /*! \brief How moves in lambda are calculated
- *
- * elmovemcMETROPOLIS - using the Metropolis criteria, and 50% up and down
- * elmovemcBARKER     - using the Barker criteria, and 50% up and down
- * elmovemcGIBBS      - computing the transition using the marginalized
- *                      probabilities of the lambdas
- * elmovemcMETGIBBS   - computing the transition using the metropolized
- *                      version of Gibbs (Monte Carlo Strategies in
- *                      Scientific computing, Liu, p. 134)
  */
-enum
-{
-    elmcmoveNO,
-    elmcmoveMETROPOLIS,
-    elmcmoveBARKER,
-    elmcmoveGIBBS,
-    elmcmoveMETGIBBS,
-    elmcmoveNR
+enum class LambdaMoveCalculation : int
+{
+    //! don't calculate move
+    No,
+    //! using the Metropolis criteria, and 50% up and down
+    Metropolis,
+    //! using the Barker criteria, and 50% up and down
+    Barker,
+    //! computing the transition using the marginalized probabilities of the lambdas
+    Gibbs,
+    /*! \brief
+     * using the metropolized version of Gibbs
+     *
+     * Monte Carlo Strategies in Scientific computing, Liu, p. 134
+     */
+    MetropolisGibbs,
+    Count,
+    Default = No
 };
 //! String corresponding to lambda moves
-extern const char* elmcmove_names[elmcmoveNR + 1];
+const char* enumValueToString(LambdaMoveCalculation enumValue);
 
 /*! \brief How we decide whether weights have reached equilibrium
- *
- * elmceqNO       - never stop, weights keep going
- * elmceqYES      - fix the weights from the beginning; no movement
- * elmceqWLDELTA  - stop when the WL-delta falls below a certain level
- * elmceqNUMATLAM - stop when we have a certain number of samples at
- *                  every step
- * elmceqSTEPS    - stop when we've run a certain total number of steps
- * elmceqSAMPLES  - stop when we've run a certain total number of samples
- * elmceqRATIO    - stop when the ratio of samples (lowest to highest)
- *                  is sufficiently large
  */
-enum
-{
-    elmceqNO,
-    elmceqYES,
-    elmceqWLDELTA,
-    elmceqNUMATLAM,
-    elmceqSTEPS,
-    elmceqSAMPLES,
-    elmceqRATIO,
-    elmceqNR
+enum class LambdaWeightWillReachEquilibrium : int
+{
+    //! never stop, weights keep going
+    No,
+    //! fix the weights from the beginning; no movement
+    Yes,
+    //! stop when the WL-delta falls below a certain level
+    WLDelta,
+    //! stop when we have a certain number of samples at every step
+    NumAtLambda,
+    //! stop when we've run a certain total number of steps
+    Steps,
+    //! stop when we've run a certain total number of samples
+    Samples,
+    //! stop when the ratio of samples (lowest to highest) is sufficiently large
+    Ratio,
+    Count,
+    Default = No
 };
 //! String corresponding to equilibrium algorithm
-extern const char* elmceq_names[elmceqNR + 1];
+const char* enumValueToString(LambdaWeightWillReachEquilibrium enumValue);
 
 /*! \brief separate_dhdl_file selection
  *
  * NOTE: YES is the first one. Do NOT interpret this one as a gmx_bool
+ * Why was this done this way, just .........
  */
-enum
+enum class SeparateDhdlFile : int
 {
-    esepdhdlfileYES,
-    esepdhdlfileNO,
-    esepdhdlfileNR
+    Yes,
+    No,
+    Count,
+    Default = Yes
 };
 //! String corresponding to separate DHDL file selection
-extern const char* separate_dhdl_file_names[esepdhdlfileNR + 1];
-//! Monster macro for DHDL file selection
-#define SEPDHDLFILETYPE(e) enum_name(e, esepdhdlfileNR, separate_dhdl_file_names)
+const char* enumValueToString(SeparateDhdlFile enumValue);
 
 /*! \brief dhdl_derivatives selection \
  *
  * NOTE: YES is the first one. Do NOT interpret this one as a gmx_bool
+ * Why was this done this way, just .........
  */
-enum
+enum class DhDlDerivativeCalculation : int
 {
-    edhdlderivativesYES,
-    edhdlderivativesNO,
-    edhdlderivativesNR
+    Yes,
+    No,
+    Count,
+    Default = Yes
 };
 //! String for DHDL derivatives
-extern const char* dhdl_derivatives_names[edhdlderivativesNR + 1];
-//! YAMM (Yet another monster macro)
-#define DHDLDERIVATIVESTYPE(e) enum_name(e, edhdlderivativesNR, dhdl_derivatives_names)
+const char* enumValueToString(DhDlDerivativeCalculation enumValue);
 
 /*! \brief Solvent model
  *
  * Distinguishes classical water types with 3 or 4 particles
  */
-enum
+enum class SolventModel : int
 {
-    esolNO,
-    esolSPC,
-    esolTIP4P,
-    esolNR
+    No,
+    Spc,
+    Tip4p,
+    Count,
+    Default = Spc
 };
 //! String corresponding to solvent type
-extern const char* esol_names[esolNR + 1];
-//! Macro lest we print the wrong solvent model string
-#define ESOLTYPE(e) enum_name(e, esolNR, esol_names)
+const char* enumValueToString(SolventModel enumValue);
 
 //! Dispersion correction.
-enum
+enum class DispersionCorrectionType : int
 {
-    edispcNO,
-    edispcEnerPres,
-    edispcEner,
-    edispcAllEnerPres,
-    edispcAllEner,
-    edispcNR
+    No,
+    EnerPres,
+    Ener,
+    AllEnerPres,
+    AllEner,
+    Count,
+    Default = No
 };
 //! String corresponding to dispersion corrections
-extern const char* edispc_names[edispcNR + 1];
-//! Macro for dispcorr string
-#define EDISPCORR(e) enum_name(e, edispcNR, edispc_names)
+const char* enumValueToString(DispersionCorrectionType enumValue);
 
 //! Center of mass motion removal algorithm.
-enum
+enum class ComRemovalAlgorithm : int
 {
-    ecmLINEAR,
-    ecmANGULAR,
-    ecmNO,
-    ecmLINEAR_ACCELERATION_CORRECTION,
-    ecmNR
+    Linear,
+    Angular,
+    No,
+    LinearAccelerationCorrection,
+    Count,
+    Default = Linear
 };
 //! String corresponding to COM removal
-extern const char* ecm_names[ecmNR + 1];
-//! Macro for COM removal string
-#define ECOM(e) enum_name(e, ecmNR, ecm_names)
+const char* enumValueToString(ComRemovalAlgorithm enumValue);
 
 //! Algorithm for simulated annealing.
-enum
+enum class SimulatedAnnealing : int
 {
-    eannNO,
-    eannSINGLE,
-    eannPERIODIC,
-    eannNR
+    No,
+    Single,
+    Periodic,
+    Count,
+    Default = No
 };
 //! String for simulated annealing
-extern const char* eann_names[eannNR + 1];
-//! And macro for simulated annealing string
-#define EANNEAL(e) enum_name(e, eannNR, eann_names)
+const char* enumValueToString(SimulatedAnnealing enumValue);
 
 //! Wall types.
-enum
+enum class WallType : int
 {
-    ewt93,
-    ewt104,
-    ewtTABLE,
-    ewt126,
-    ewtNR
+    NineThree,
+    TenFour,
+    Table,
+    TwelveSix,
+    Count,
+    Default = NineThree
 };
 //! String corresponding to wall type
-extern const char* ewt_names[ewtNR + 1];
-//! Macro for wall type string
-#define EWALLTYPE(e) enum_name(e, ewtNR, ewt_names)
+const char* enumValueToString(WallType enumValue);
 
 //! Pulling algorithm.
-enum
+enum class PullingAlgorithm : int
 {
-    epullUMBRELLA,
-    epullCONSTRAINT,
-    epullCONST_F,
-    epullFLATBOTTOM,
-    epullFLATBOTTOMHIGH,
-    epullEXTERNAL,
-    epullNR
+    Umbrella,
+    Constraint,
+    ConstantForce,
+    FlatBottom,
+    FlatBottomHigh,
+    External,
+    Count,
+    Default = Umbrella
 };
 //! String for pulling algorithm
-extern const char* epull_names[epullNR + 1];
-//! Macro for pulling string
-#define EPULLTYPE(e) enum_name(e, epullNR, epull_names)
+const char* enumValueToString(PullingAlgorithm enumValue);
 
 //! Control of pull groups
-enum
-{
-    epullgDIST,
-    epullgDIR,
-    epullgCYL,
-    epullgDIRPBC,
-    epullgDIRRELATIVE,
-    epullgANGLE,
-    epullgDIHEDRAL,
-    epullgANGLEAXIS,
-    epullgNR
+enum class PullGroupGeometry : int
+{
+    Distance,
+    Direction,
+    Cylinder,
+    DirectionPBC,
+    DirectionRelative,
+    Angle,
+    Dihedral,
+    AngleAxis,
+    Count,
+    Default = Distance
 };
 //! String for pull groups
-extern const char* epullg_names[epullgNR + 1];
-//! Macro for pull group string
-#define EPULLGEOM(e) enum_name(e, epullgNR, epullg_names)
+const char* enumValueToString(PullGroupGeometry enumValue);
 
 //! Enforced rotation groups.
-enum
-{
-    erotgISO,
-    erotgISOPF,
-    erotgPM,
-    erotgPMPF,
-    erotgRM,
-    erotgRMPF,
-    erotgRM2,
-    erotgRM2PF,
-    erotgFLEX,
-    erotgFLEXT,
-    erotgFLEX2,
-    erotgFLEX2T,
-    erotgNR
+enum class EnforcedRotationGroupType : int
+{
+    Iso,
+    Isopf,
+    Pm,
+    Pmpf,
+    Rm,
+    Rmpf,
+    Rm2,
+    Rm2pf,
+    Flex,
+    Flext,
+    Flex2,
+    Flex2t,
+    Count,
+    Default = Iso
 };
 //! Rotation group names
-extern const char* erotg_names[erotgNR + 1];
-//! Macro for rot group names
-#define EROTGEOM(e) enum_name(e, erotgNR, erotg_names)
+const char* enumValueToString(EnforcedRotationGroupType enumValue);
 //! String for rotation group origin names
-extern const char* erotg_originnames[erotgNR + 1];
-//! Macro for rot group origin names
-#define EROTORIGIN(e) enum_name(e, erotgOriginNR, erotg_originnames)
+const char* enumValueToLongString(EnforcedRotationGroupType enumValue);
 
 //! Rotation group fitting type
-enum
+enum class RotationGroupFitting : int
 {
-    erotgFitRMSD,
-    erotgFitNORM,
-    erotgFitPOT,
-    erotgFitNR
+    Rmsd,
+    Norm,
+    Pot,
+    Count,
+    Default = Rmsd
 };
 //! String corresponding to rotation group fitting
-extern const char* erotg_fitnames[erotgFitNR + 1];
-//! Macro for rot group fit names
-#define EROTFIT(e) enum_name(e, erotgFitNR, erotg_fitnames)
+const char* enumValueToString(RotationGroupFitting enumValue);
 
 /*! \brief Direction along which ion/water swaps happen
  *
  * Part of "Computational Electrophysiology" (CompEL) setups
  */
-enum eSwaptype
+enum class SwapType : int
 {
-    eswapNO,
-    eswapX,
-    eswapY,
-    eswapZ,
-    eSwapTypesNR
+    No,
+    X,
+    Y,
+    Z,
+    Count,
+    Default = No
 };
 //! Names for swapping
-extern const char* eSwapTypes_names[eSwapTypesNR + 1];
-//! Macro for swapping string
-#define ESWAPTYPE(e) enum_name(e, eSwapTypesNR, eSwapTypes_names)
+const char* enumValueToString(SwapType enumValue);
 
 /*! \brief Swap group splitting type
  *
  * These are just the fixed groups we need for any setup. In t_swap's grp
  * entry after that follows the variable number of swap groups.
  */
-enum
+enum class SwapGroupSplittingType : int
 {
-    eGrpSplit0,
-    eGrpSplit1,
-    eGrpSolvent,
-    eSwapFixedGrpNR
+    Split0,
+    Split1,
+    Solvent,
+    Count,
+    Default = Solvent
 };
 //! String for swap group splitting
-extern const char* eSwapFixedGrp_names[eSwapFixedGrpNR + 1];
-
-/*! \brief Neighborlist geometry type.
- *
- * Kernels will compute interactions between two particles,
- * 3-center water, 4-center water or coarse-grained beads.
- */
-enum gmx_nblist_kernel_geometry
-{
-    GMX_NBLIST_GEOMETRY_PARTICLE_PARTICLE,
-    GMX_NBLIST_GEOMETRY_WATER3_PARTICLE,
-    GMX_NBLIST_GEOMETRY_WATER3_WATER3,
-    GMX_NBLIST_GEOMETRY_WATER4_PARTICLE,
-    GMX_NBLIST_GEOMETRY_WATER4_WATER4,
-    GMX_NBLIST_GEOMETRY_CG_CG,
-    GMX_NBLIST_GEOMETRY_NR
-};
-//! String corresponding to nblist geometry names
-extern const char* gmx_nblist_geometry_names[GMX_NBLIST_GEOMETRY_NR + 1];
+const char* enumValueToString(SwapGroupSplittingType enumValue);
 
 /*! \brief Types of electrostatics calculations
  *
@@ -796,17 +777,18 @@ extern const char* gmx_nblist_geometry_names[GMX_NBLIST_GEOMETRY_NR + 1];
  * Note that these do NOT necessarily correspond to the user selections
  * in the MDP file; many interactions for instance map to tabulated kernels.
  */
-enum gmx_nbkernel_elec
+enum class NbkernelElecType : int
 {
-    GMX_NBKERNEL_ELEC_NONE,
-    GMX_NBKERNEL_ELEC_COULOMB,
-    GMX_NBKERNEL_ELEC_REACTIONFIELD,
-    GMX_NBKERNEL_ELEC_CUBICSPLINETABLE,
-    GMX_NBKERNEL_ELEC_EWALD,
-    GMX_NBKERNEL_ELEC_NR
+    None,
+    Coulomb,
+    ReactionField,
+    CubicSplineTable,
+    Ewald,
+    Count,
+    Default = None
 };
 //! String corresponding to electrostatics kernels
-extern const char* gmx_nbkernel_elec_names[GMX_NBKERNEL_ELEC_NR + 1];
+const char* enumValueToString(NbkernelElecType enumValue);
 
 /*! \brief Types of vdw calculations available
  *
@@ -814,26 +796,17 @@ extern const char* gmx_nbkernel_elec_names[GMX_NBKERNEL_ELEC_NR + 1];
  * Note that these do NOT necessarily correspond to the user selections
  * in the MDP file; many interactions for instance map to tabulated kernels.
  */
-enum gmx_nbkernel_vdw
+enum class NbkernelVdwType : int
 {
-    GMX_NBKERNEL_VDW_NONE,
-    GMX_NBKERNEL_VDW_LENNARDJONES,
-    GMX_NBKERNEL_VDW_BUCKINGHAM,
-    GMX_NBKERNEL_VDW_CUBICSPLINETABLE,
-    GMX_NBKERNEL_VDW_LJEWALD,
-    GMX_NBKERNEL_VDW_NR
+    None,
+    LennardJones,
+    Buckingham,
+    CubicSplineTable,
+    LJEwald,
+    Count,
+    Default = None
 };
 //! String corresponding to VdW kernels
-extern const char* gmx_nbkernel_vdw_names[GMX_NBKERNEL_VDW_NR + 1];
-
-//! \brief Types of interactions inside the neighborlist
-enum gmx_nblist_interaction_type
-{
-    GMX_NBLIST_INTERACTION_STANDARD,
-    GMX_NBLIST_INTERACTION_FREE_ENERGY,
-    GMX_NBLIST_INTERACTION_NR
-};
-//! String corresponding to interactions in neighborlist code
-extern const char* gmx_nblist_interaction_names[GMX_NBLIST_INTERACTION_NR + 1];
+const char* enumValueToString(NbkernelVdwType enumValue);
 
 #endif /* GMX_MDTYPES_MD_ENUMS_H */
index c8a41643e6daec466d5e60578e47f28300ca3cc6..91ee9f00d7d2e4afed8d34be4af8eeddf87fcab9 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_MDTYPES_MDATOM_H
 
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
+enum class ParticleType : int;
+
 typedef struct t_mdatoms
 {
     //! Total mass in state A
@@ -63,11 +64,11 @@ typedef struct t_mdatoms
     //! Number of energy groups
     int nenergrp;
     //! Do we have multiple center of mass motion removal groups
-    gmx_bool bVCMgrps;
+    bool bVCMgrps;
     //! Do we have any virtual sites?
-    gmx_bool haveVsites;
+    bool haveVsites;
     //! Do we have atoms that are frozen along 1 or 2 (not 3) dimensions?
-    gmx_bool havePartiallyFrozenAtoms;
+    bool havePartiallyFrozenAtoms;
     //! Number of perturbed atoms
     int nPerturbed;
     //! Number of atoms for which the mass is perturbed
@@ -77,7 +78,7 @@ typedef struct t_mdatoms
     //! Number of atoms for which the type is perturbed
     int nTypePerturbed;
     //! Do we have orientation restraints
-    gmx_bool bOrires;
+    bool bOrires;
     //! Atomic mass in A state
     real* massA;
     //! Atomic mass in B state
@@ -105,19 +106,17 @@ typedef struct t_mdatoms
     //! Van der Waals radius sigma^3 in the B state
     real* sigma3B;
     //! Is this atom perturbed
-    gmx_bool* bPerturbed;
+    bool* bPerturbed;
     //! Type of atom in the A state
     int* typeA;
     //! Type of atom in the B state
     int* typeB;
     //! Particle type
-    unsigned short* ptype;
+    ParticleType* ptype;
     //! Group index for temperature coupling
     unsigned short* cTC;
     //! Group index for energy matrix
     unsigned short* cENER;
-    //! Group index for acceleration
-    unsigned short* cACC;
     //! Group index for freezing
     unsigned short* cFREEZE;
     //! Group index for center of mass motion removal
index 02bcf41be33c7f765b74dd9de4eb892a8bb1d52c..2bd5072a806623770f0a4e5ba61e1f5326f5d3c7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "multipletimestepping.h"
 
+#include <optional>
+
 #include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/pull_params.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/stringutil.h"
 
 namespace gmx
 {
@@ -56,41 +61,164 @@ int nonbondedMtsFactor(const t_inputrec& ir)
     }
 }
 
-void assertMtsRequirements(const t_inputrec& ir)
+std::vector<MtsLevel> setupMtsLevels(const GromppMtsOpts& mtsOpts, std::vector<std::string>* errorMessages)
+{
+    std::vector<MtsLevel> mtsLevels;
+
+    if (mtsOpts.numLevels != 2)
+    {
+        if (errorMessages)
+        {
+            errorMessages->push_back("Only mts-levels = 2 is supported");
+        }
+    }
+    else
+    {
+        mtsLevels.resize(2);
+
+        const std::vector<std::string> inputForceGroups = gmx::splitString(mtsOpts.level2Forces);
+        auto&                          forceGroups      = mtsLevels[1].forceGroups;
+        for (const auto& inputForceGroup : inputForceGroups)
+        {
+            bool found     = false;
+            int  nameIndex = 0;
+            for (const auto& forceGroupName : gmx::mtsForceGroupNames)
+            {
+                if (gmx::equalCaseInsensitive(inputForceGroup, forceGroupName))
+                {
+                    forceGroups.set(nameIndex);
+                    found = true;
+                }
+                nameIndex++;
+            }
+            if (!found && errorMessages)
+            {
+                errorMessages->push_back(
+                        gmx::formatString("Unknown MTS force group '%s'", inputForceGroup.c_str()));
+            }
+        }
+
+        // Make the level 0 use the complement of the force groups of group 1
+        mtsLevels[0].forceGroups = ~mtsLevels[1].forceGroups;
+        mtsLevels[0].stepFactor  = 1;
+
+        mtsLevels[1].stepFactor = mtsOpts.level2Factor;
+
+        if (errorMessages && mtsLevels[1].stepFactor <= 1)
+        {
+            errorMessages->push_back("mts-factor should be larger than 1");
+        }
+    }
+
+    return mtsLevels;
+}
+
+bool haveValidMtsSetup(const t_inputrec& ir)
+{
+    return (ir.useMts && ir.mtsLevels.size() == 2 && ir.mtsLevels[1].stepFactor > 1);
+}
+
+namespace
+{
+
+//! Checks whether \p nstValue is a multiple of the largest MTS step, returns an error string for parameter \p param when this is not the case
+std::optional<std::string> checkMtsInterval(ArrayRef<const MtsLevel> mtsLevels, const char* param, const int nstValue)
+{
+    GMX_RELEASE_ASSERT(mtsLevels.size() >= 2, "Need at least two levels for MTS");
+
+    const int mtsFactor = mtsLevels.back().stepFactor;
+    if (nstValue % mtsFactor == 0)
+    {
+        return {};
+    }
+    else
+    {
+        return gmx::formatString(
+                "With MTS, %s = %d should be a multiple of mts-factor = %d", param, nstValue, mtsFactor);
+    }
+}
+
+} // namespace
+
+std::vector<std::string> checkMtsRequirements(const t_inputrec& ir)
 {
+    std::vector<std::string> errorMessages;
+
     if (!ir.useMts)
     {
-        return;
+        return errorMessages;
     }
 
-    GMX_RELEASE_ASSERT(ir.mtsLevels.size() >= 2, "Need at least two levels for MTS");
+    GMX_RELEASE_ASSERT(haveValidMtsSetup(ir), "MTS setup should be valid here");
+
+    ArrayRef<const MtsLevel> mtsLevels = ir.mtsLevels;
+
+    if (!(ir.eI == IntegrationAlgorithm::MD || ir.eI == IntegrationAlgorithm::SD1))
+    {
+        errorMessages.push_back(gmx::formatString(
+                "Multiple time stepping is only supported with integrators %s and %s",
+                enumValueToString(IntegrationAlgorithm::MD),
+                enumValueToString(IntegrationAlgorithm::SD1)));
+    }
 
-    GMX_RELEASE_ASSERT(ir.mtsLevels[0].stepFactor == 1, "Base MTS step should be 1");
+    if ((EEL_FULL(ir.coulombtype) || EVDW_PME(ir.vdwtype))
+        && forceGroupMtsLevel(ir.mtsLevels, MtsForceGroups::LongrangeNonbonded) == 0)
+    {
+        errorMessages.emplace_back(
+                "With long-range electrostatics and/or LJ treatment, the long-range part "
+                "has to be part of the mts-level2-forces");
+    }
 
-    GMX_RELEASE_ASSERT((!EEL_FULL(ir.coulombtype) && !EVDW_PME(ir.vdwtype))
-                               || forceGroupMtsLevel(ir.mtsLevels, MtsForceGroups::LongrangeNonbonded) > 0,
-                       "Long-range nonbondeds should be in the highest MTS level");
+    std::optional<std::string> mesg;
+    if (ir.nstcalcenergy > 0)
+    {
+        if ((mesg = checkMtsInterval(mtsLevels, "nstcalcenergy", ir.nstcalcenergy)))
+        {
+            errorMessages.push_back(mesg.value());
+        }
+    }
+    if ((mesg = checkMtsInterval(mtsLevels, "nstenergy", ir.nstenergy)))
+    {
+        errorMessages.push_back(mesg.value());
+    }
+    if ((mesg = checkMtsInterval(mtsLevels, "nstlog", ir.nstlog)))
+    {
+        errorMessages.push_back(mesg.value());
+    }
+    if ((mesg = checkMtsInterval(mtsLevels, "nstfout", ir.nstfout)))
+    {
+        errorMessages.push_back(mesg.value());
+    }
+    if (ir.efep != FreeEnergyPerturbationType::No)
+    {
+        if ((mesg = checkMtsInterval(mtsLevels, "nstdhdl", ir.fepvals->nstdhdl)))
+        {
+            errorMessages.push_back(mesg.value());
+        }
+    }
+    if (mtsLevels.back().forceGroups[static_cast<int>(gmx::MtsForceGroups::Nonbonded)])
+    {
+        if ((mesg = checkMtsInterval(mtsLevels, "nstlist", ir.nstlist)))
+        {
+            errorMessages.push_back(mesg.value());
+        }
+    }
 
-    for (const auto& mtsLevel : ir.mtsLevels)
+    if (ir.bPull)
     {
-        const int mtsFactor = mtsLevel.stepFactor;
-        GMX_RELEASE_ASSERT(ir.nstcalcenergy % mtsFactor == 0,
-                           "nstcalcenergy should be a multiple of mtsFactor");
-        GMX_RELEASE_ASSERT(ir.nstenergy % mtsFactor == 0,
-                           "nstenergy should be a multiple of mtsFactor");
-        GMX_RELEASE_ASSERT(ir.nstlog % mtsFactor == 0, "nstlog should be a multiple of mtsFactor");
-        GMX_RELEASE_ASSERT(ir.epc == epcNO || ir.nstpcouple % mtsFactor == 0,
-                           "nstpcouple should be a multiple of mtsFactor");
-        GMX_RELEASE_ASSERT(ir.efep == efepNO || ir.fepvals->nstdhdl % mtsFactor == 0,
-                           "nstdhdl should be a multiple of mtsFactor");
-        if (ir.mtsLevels.back().forceGroups[static_cast<int>(gmx::MtsForceGroups::Nonbonded)])
+        const int pullMtsLevel  = gmx::forceGroupMtsLevel(ir.mtsLevels, gmx::MtsForceGroups::Pull);
+        const int mtsStepFactor = ir.mtsLevels[pullMtsLevel].stepFactor;
+        if (ir.pull->nstxout % mtsStepFactor != 0)
+        {
+            errorMessages.emplace_back("pull-nstxout should be a multiple of mts-factor");
+        }
+        if (ir.pull->nstfout % mtsStepFactor != 0)
         {
-            GMX_RELEASE_ASSERT(ir.nstlist % ir.mtsLevels.back().stepFactor == 0,
-                               "With multiple time stepping for the non-bonded pair interactions, "
-                               "nstlist should be a "
-                               "multiple of mtsFactor");
+            errorMessages.emplace_back("pull-nstfout should be a multiple of mts-factor");
         }
     }
+
+    return errorMessages;
 }
 
 } // namespace gmx
index 5796114005aea21d695b4281488294ac672efd4d..f59a5b49f8d7eeab4b6d739f13d33ac33dc139f2 100644 (file)
@@ -35,6 +35,9 @@
 #ifndef GMX_MULTIPLETIMESTEPPING_H
 #define GMX_MULTIPLETIMESTEPPING_H
 
+#include <string>
+#include <vector>
+
 #include <bitset>
 
 #include "gromacs/utility/arrayref.h"
@@ -58,6 +61,7 @@ enum class MtsForceGroups : int
     Count               //!< The number of groups above
 };
 
+//! Names for the MTS force groups
 static const gmx::EnumerationArray<MtsForceGroups, std::string> mtsForceGroupNames = {
     "longrange-nonbonded", "nonbonded", "pair", "dihedral", "angle", "pull", "awh"
 };
@@ -89,8 +93,42 @@ static inline int forceGroupMtsLevel(ArrayRef<const MtsLevel> mtsLevels, const M
  */
 int nonbondedMtsFactor(const t_inputrec& ir);
 
-//! (Release) Asserts that all multiple time-stepping requirements on \p ir are fulfilled
-void assertMtsRequirements(const t_inputrec& ir);
+//! Struct for passing the MTS mdp options to setupMtsLevels()
+struct GromppMtsOpts
+{
+    //! The number of MTS levels
+    int numLevels = 0;
+    //! The names of the force groups assigned by the user to level 2, internal index 1
+    std::string level2Forces;
+    //! The step factor assigned by the user to level 2, internal index 1
+    int level2Factor = 0;
+};
+
+/*! \brief Sets up and returns the MTS levels and checks requirements of MTS
+ *
+ * Appends errors about allowed input values ir to errorMessages, when not nullptr.
+ *
+ * \param[in]     mtsOpts        Options for setting the MTS levels
+ * \param[in,out] errorMessages  List of error messages, can be nullptr
+ */
+std::vector<MtsLevel> setupMtsLevels(const GromppMtsOpts& mtsOpts, std::vector<std::string>* errorMessages);
+
+/*! \brief Returns whether we use MTS and the MTS setup is internally valid
+ *
+ * Note that setupMtsLevels would have returned at least one error message
+ * when this function returns false
+ */
+bool haveValidMtsSetup(const t_inputrec& ir);
+
+/*! \brief Checks whether the MTS requirements on other algorithms and output frequencies are met
+ *
+ * Note: exits with an assertion failure when
+ * ir.useMts == true && haveValidMtsSetup(ir) == false
+ *
+ * \param[in] ir  Complete input record
+ * \returns list of error messages, empty when all MTS requirements are met
+ */
+std::vector<std::string> checkMtsRequirements(const t_inputrec& ir);
 
 } // namespace gmx
 
index 9ac98c5aaab459d7110ff2ace87c5fde8a4870be..63fc565ae745ae08c4c994008f91831c87f48dbf 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,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/mdtypes/md_enums.h"
 #include "gromacs/utility/alignedallocator.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
-typedef unsigned long t_excl;
-
 /* The interactions contained in a (possibly merged) table
  * for computing electrostatic, VDW repulsion and/or VDW dispersion
  * contributions.
@@ -79,100 +77,27 @@ enum gmx_table_format
     GMX_TABLE_FORMAT_NR
 };
 
-enum
+struct t_nblist
 {
-    eNL_VDWQQ,
-    eNL_VDW,
-    eNL_QQ,
-    eNL_VDWQQ_FREE,
-    eNL_VDW_FREE,
-    eNL_QQ_FREE,
-    eNL_VDWQQ_WATER,
-    eNL_QQ_WATER,
-    eNL_VDWQQ_WATERWATER,
-    eNL_QQ_WATERWATER,
-    eNL_NR
+    int              nri    = 0; /* Current number of i particles         */
+    int              maxnri = 0; /* Max number of i particles     */
+    int              nrj    = 0; /* Current number of j particles         */
+    int              maxnrj = 0; /* ;Max number of j particles    */
+    std::vector<int> iinr;       /* The i-elements                        */
+    std::vector<int> gid;        /* Index in energy arrays                */
+    std::vector<int> shift;      /* Shift vector index                    */
+    std::vector<int> jindex;     /* Index in jjnr                         */
+    std::vector<int> jjnr;       /* The j-atom list                       */
+    std::vector<int> excl_fep;   /* Exclusions for FEP with Verlet scheme */
 };
 
-#define MAX_CG 1024
-
-typedef struct
-{
-    int ncg;
-    int nj;
-    int jcg[MAX_CG];
-} t_ns_buf;
-
-
-/* The maximum charge group size because of minimum size of t_excl
- * could be 32 bits.
- */
-#define MAX_CHARGEGROUP_SIZE 32
-
-/* The maximum charge group size for CG-CG nblists.
- * The excl entry in t_nblist uses blocks of this size.
- */
-#define MAX_CGCGSIZE 32
-
-typedef struct t_nblist
-{
-    int igeometry; /* The type of list (atom, water, etc.)  */
-    int ielec;     /* Coulomb loop type index for kernels   */
-    int ielecmod;  /* Coulomb modifier (e.g. switch/shift)  */
-    int ivdw;      /* VdW loop type index for kernels       */
-    int ivdwmod;   /* VdW modifier (e.g. switch/shift)      */
-    int type;      /* Type of interaction, listed in
-                      gmx_nblist_interaction_type           */
-
-    int     nri, maxnri; /* Current/max number of i particles     */
-    int     nrj, maxnrj; /* Current/max number of j particles     */
-    int*    iinr;        /* The i-elements                        */
-    int*    iinr_end;    /* The end atom, only with enlistCG      */
-    int*    gid;         /* Index in energy arrays                */
-    int*    shift;       /* Shift vector index                    */
-    int*    jindex;      /* Index in jjnr                         */
-    int*    jjnr;        /* The j-atom list                       */
-    int*    jjnr_end;    /* The end atom, only with enltypeCG     */
-    char*   excl_fep;    /* Exclusions for FEP with Verlet scheme */
-    t_excl* excl;        /* Exclusions, only with enltypeCG       */
-
-    /* We use separate pointers for kernels that compute both potential
-     * and force (vf suffix), only potential (v) or only force (f)
-     */
-    void* kernelptr_vf;
-    void* kernelptr_v;
-    void* kernelptr_f;
-
-    /* Pad the list of neighbors for each i atom with "-1" entries up to the
-     * simd_padding_width, if it is larger than 0. This is necessary for many
-     * accelerated kernels using single-instruction multiple-data operations
-     * internally.
-     */
-    int simd_padding_width;
-
-} t_nblist;
-
-/* For atom I =  nblist->iinr[N] (0 <= N < nblist->nri) there can be
- * several neighborlists (N's), for different energy groups (gid) and
- * different shifts (shift).
- * For corresponding J atoms for each list start at:
- * nblist->jjnr[JI]
- * with nblist->jindex[N] <= JI < nblist->jindex[N+1]
- *
- * enlist is of the form enlistUNIT1_UNIT2:
- * UNIT ATOM:  there is one atom: iinr[N] or jjnr[JI]
- * UNIT SPC:   there are 3 atoms: iinr[N],iinr[N]+1,iinr[N]+2, jjnr analog.
- * UNIT TIP4P: there are 4 atoms: iinr[N],...,iinr[N]+3, jjnr analog.
- * UNIT CG:    there are N atoms: iinr[N],...,iinr_end[N]-1, jjnr analog.
- *
- * Clear?
- */
-
 /* Structure describing the data in a single table */
 struct t_forcetable
 {
     t_forcetable(enum gmx_table_interaction interaction, enum gmx_table_format format);
 
+    ~t_forcetable();
+
     enum gmx_table_interaction interaction; /* Types of interactions stored in this table */
     enum gmx_table_format      format;      /* Interpolation type and data format */
 
@@ -191,26 +116,4 @@ struct t_forcetable
     int stride; /* Distance to next table point (number of fp variables per table point in total) */
 };
 
-struct gmx_ns_t
-{
-    gmx_bool       bCGlist;
-    int*           simple_aaj;
-    struct t_grid* grid;
-    t_excl*        bexcl;
-    gmx_bool*      bHaveVdW;
-    t_ns_buf**     ns_buf;
-    gmx_bool*      bExcludeAlleg;
-    int            nra_alloc;
-    int            cg_alloc;
-    int**          nl_sr;
-    int*           nsr;
-    int**          nl_lr_ljc;
-    int**          nl_lr_one;
-    int*           nlr_ljc;
-    int*           nlr_one;
-    /* the nblists should probably go in here */
-    gmx_bool nblist_initialized; /* has the nblist been initialized?  */
-    int      dump_nl;            /* neighbour list dump level (from env. var. GMX_DUMP_NL)*/
-};
-
 #endif /* GMX_MDTYPES_NBLIST_H */
index c0709ca353edb9ac738bcf1681d44e57c2fe039d..8e623df1bc1a0d0a84dbff82211e5180e6375549 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -69,17 +69,17 @@ struct t_pull_group
 };
 
 /*! Maximum number of pull groups that can be used in a pull coordinate */
-static const int c_pullCoordNgroupMax = 6;
+static constexpr int c_pullCoordNgroupMax = 6;
 
 /*! \brief Struct that defines a pull coordinate */
 struct t_pull_coord
 {
     //! The pull type: umbrella, constraint, ...
-    int eType = 0;
+    PullingAlgorithm eType = PullingAlgorithm::Umbrella;
     //! Name of the module providing   the external potential, only used with eType==epullEXTERNAL
     std::string externalPotentialProvider;
     //! The pull geometry
-    int eGeom = 0;
+    PullGroupGeometry eGeom = PullGroupGeometry::Distance;
     //! The number of groups, depends on eGeom
     int ngroup = 0;
     /*! \brief The pull groups:
@@ -108,6 +108,8 @@ struct t_pull_coord
     real k = 0.0;
     //! Force constant for state B
     real kB = 0.0;
+    //! The index of this coordinate in the list of coordinates
+    int coordIndex = -1;
 };
 
 /*! \brief Struct containing all pull parameters */
index 0f36009513b6d8f6afa60bb12ac7cc54221de96f..fe207526272e86fd4abcc8fbb20f6717e9ab49cd 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 /* The source code in this file should be thread-safe.
       Please keep it that way. */
 
-history_t::history_t() :
-    disre_initf(0),
-    ndisrepairs(0),
-    disre_rm3tav(nullptr),
-    orire_initf(0),
-    norire_Dtav(0),
-    orire_Dtav(nullptr)
-{
-}
+history_t::history_t() : disre_initf(0), orire_initf(0) {}
 
 ekinstate_t::ekinstate_t() :
     bUpToDate(FALSE),
@@ -167,15 +159,15 @@ void state_change_natoms(t_state* state, int natoms)
 
     /* We need padding, since we might use SIMD access, but the
      * containers here all ensure that. */
-    if (state->flags & (1 << estX))
+    if (state->flags & enumValueToBitMask(StateEntry::X))
     {
         state->x.resizeWithPadding(natoms);
     }
-    if (state->flags & (1 << estV))
+    if (state->flags & enumValueToBitMask(StateEntry::V))
     {
         state->v.resizeWithPadding(natoms);
     }
-    if (state->flags & (1 << estCGP))
+    if (state->flags & enumValueToBitMask(StateEntry::Cgp))
     {
         state->cg_p.resizeWithPadding(natoms);
     }
@@ -206,17 +198,17 @@ void comp_state(const t_state* st1, const t_state* st2, gmx_bool bRMSD, real fto
     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))
+    if (st1->flags & enumValueToBitMask(StateEntry::SVirPrev))
     {
         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))
+    if (st1->flags & enumValueToBitMask(StateEntry::FVirPrev))
     {
         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))
+    if (st1->flags & enumValueToBitMask(StateEntry::PressurePrevious))
     {
         fprintf(stdout, "comparing prev_pres\n");
         cmp_rvecs(stdout, "pres_prev", DIM, st1->pres_prev, st2->pres_prev, FALSE, ftol, abstol);
@@ -230,8 +222,7 @@ void comp_state(const t_state* st1, const t_state* st2, gmx_bool bRMSD, real fto
             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_real(stdout, "nosehoover_xi", i, st1->nosehoover_xi[nc + j], st2->nosehoover_xi[nc + j], ftol, abstol);
             }
         }
     }
@@ -243,8 +234,7 @@ void comp_state(const t_state* st1, const t_state* st2, gmx_bool bRMSD, real fto
             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_real(stdout, "nosehoover_xi", i, st1->nhpres_xi[nc + j], st2->nhpres_xi[nc + j], ftol, abstol);
             }
         }
     }
@@ -252,17 +242,17 @@ void comp_state(const t_state* st1, const t_state* st2, gmx_bool bRMSD, real fto
     cmp_int(stdout, "natoms", -1, st1->natoms, st2->natoms);
     if (st1->natoms == st2->natoms)
     {
-        if ((st1->flags & (1 << estX)) && (st2->flags & (1 << estX)))
+        if ((st1->flags & enumValueToBitMask(StateEntry::X))
+            && (st2->flags & enumValueToBitMask(StateEntry::X)))
         {
             fprintf(stdout, "comparing x\n");
-            cmp_rvecs(stdout, "x", st1->natoms, st1->x.rvec_array(), st2->x.rvec_array(), bRMSD,
-                      ftol, abstol);
+            cmp_rvecs(stdout, "x", st1->natoms, st1->x.rvec_array(), st2->x.rvec_array(), bRMSD, ftol, abstol);
         }
-        if ((st1->flags & (1 << estV)) && (st2->flags & (1 << estV)))
+        if ((st1->flags & enumValueToBitMask(StateEntry::V))
+            && (st2->flags & enumValueToBitMask(StateEntry::V)))
         {
             fprintf(stdout, "comparing v\n");
-            cmp_rvecs(stdout, "v", st1->natoms, st1->v.rvec_array(), st2->v.rvec_array(), bRMSD,
-                      ftol, abstol);
+            cmp_rvecs(stdout, "v", st1->natoms, st1->v.rvec_array(), st2->v.rvec_array(), bRMSD, ftol, abstol);
         }
     }
 }
@@ -327,7 +317,7 @@ void set_box_rel(const t_inputrec* ir, t_state* state)
 
     if (inputrecPreserveShape(ir))
     {
-        const int ndim = ir->epct == epctSEMIISOTROPIC ? 2 : 3;
+        const int ndim = ir->epct == PressureCouplingType::SemiIsotropic ? 2 : 3;
         do_box_rel(ndim, ir->deform, state->box_rel, state->box, true);
     }
 }
@@ -336,12 +326,12 @@ void preserve_box_shape(const t_inputrec* ir, matrix box_rel, matrix box)
 {
     if (inputrecPreserveShape(ir))
     {
-        const int ndim = ir->epct == epctSEMIISOTROPIC ? 2 : 3;
+        const int ndim = ir->epct == PressureCouplingType::SemiIsotropic ? 2 : 3;
         do_box_rel(ndim, ir->deform, box_rel, box, false);
     }
 }
 
-void printLambdaStateToLog(FILE* fplog, const gmx::ArrayRef<real> lambda, const bool isInitialOutput)
+void printLambdaStateToLog(FILE* fplog, gmx::ArrayRef<const real> lambda, const bool isInitialOutput)
 {
     if (fplog != nullptr)
     {
@@ -354,50 +344,57 @@ void printLambdaStateToLog(FILE* fplog, const gmx::ArrayRef<real> lambda, const
     }
 }
 
-void initialize_lambdas(FILE* fplog, const t_inputrec& ir, bool isMaster, int* fep_state, gmx::ArrayRef<real> lambda)
+void initialize_lambdas(FILE*                            fplog,
+                        const FreeEnergyPerturbationType freeEnergyPerturbationType,
+                        const bool                       haveSimulatedTempering,
+                        const t_lambda&                  fep,
+                        gmx::ArrayRef<const real>        simulatedTemperingTemps,
+                        gmx::ArrayRef<real>              ref_t,
+                        bool                             isMaster,
+                        int*                             fep_state,
+                        gmx::ArrayRef<real>              lambda)
 {
     /* TODO: Clean up initialization of fep_state and lambda in
        t_state.  This function works, but could probably use a logic
        rewrite to keep all the different types of efep straight. */
 
-    if ((ir.efep == efepNO) && (!ir.bSimTemp))
+    if ((freeEnergyPerturbationType == FreeEnergyPerturbationType::No) && (!haveSimulatedTempering))
     {
         return;
     }
 
-    const t_lambda* fep = ir.fepvals;
     if (isMaster)
     {
-        *fep_state = fep->init_fep_state; /* this might overwrite the checkpoint
+        *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 (int i = 0; i < efptNR; i++)
+    for (int i = 0; i < static_cast<int>(FreeEnergyPerturbationCouplingType::Count); i++)
     {
         double thisLambda;
         /* overwrite lambda state with init_lambda for now for backwards compatibility */
-        if (fep->init_lambda >= 0) /* if it's -1, it was never initialized */
+        if (fep.init_lambda >= 0) /* if it's -1, it was never initialized */
         {
-            thisLambda = fep->init_lambda;
+            thisLambda = fep.init_lambda;
         }
         else
         {
-            thisLambda = fep->all_lambda[i][fep->init_fep_state];
+            thisLambda = fep.all_lambda[i][fep.init_fep_state];
         }
         if (isMaster)
         {
             lambda[i] = thisLambda;
         }
     }
-    if (ir.bSimTemp)
+    if (haveSimulatedTempering)
     {
         /* need to rescale control temperatures to match current state */
-        for (int i = 0; i < ir.opts.ngtc; i++)
+        for (int i = 0; i < ref_t.ssize(); i++)
         {
-            if (ir.opts.ref_t[i] > 0)
+            if (ref_t[i] > 0)
             {
-                ir.opts.ref_t[i] = ir.simtempvals->temperatures[fep->init_fep_state];
+                ref_t[i] = simulatedTemperingTemps[fep.init_fep_state];
             }
         }
     }
index e38f3f7dbc7941fb8c283b75a18ee71251dffff0..4b0f8a3b9be3a844a072f67d73880ccb86e60631 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/paddedvector.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/mdtypes/md_enums.h"
-#include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/real.h"
 
 struct t_inputrec;
+struct t_lambda;
+enum class FreeEnergyPerturbationType;
 
 namespace gmx
 {
@@ -93,42 +94,52 @@ using PaddedHostVector = gmx::PaddedHostVector<T>;
  * The order of these enums should not be changed,
  * since that affects the checkpoint (.cpt) file format.
  */
-enum
+enum class StateEntry : int
 {
-    estLAMBDA,
-    estBOX,
-    estBOX_REL,
-    estBOXV,
-    estPRES_PREV,
-    estNH_XI,
-    estTHERM_INT,
-    estX,
-    estV,
-    estSDX_NOTSUPPORTED,
-    estCGP,
-    estLD_RNG_NOTSUPPORTED,
-    estLD_RNGI_NOTSUPPORTED,
-    estDISRE_INITF,
-    estDISRE_RM3TAV,
-    estORIRE_INITF,
-    estORIRE_DTAV,
-    estSVIR_PREV,
-    estNH_VXI,
-    estVETA,
-    estVOL0,
-    estNHPRES_XI,
-    estNHPRES_VXI,
-    estFVIR_PREV,
-    estFEPSTATE,
-    estMC_RNG_NOTSUPPORTED,
-    estMC_RNGI_NOTSUPPORTED,
-    estBAROS_INT,
-    estPULLCOMPREVSTEP,
-    estNR
+    Lambda,
+    Box,
+    BoxRel,
+    BoxV,
+    PressurePrevious,
+    Nhxi,
+    ThermInt,
+    X,
+    V,
+    SDxNotSupported,
+    Cgp,
+    LDRngNotSupported,
+    LDRngINotSupported,
+    DisreInitF,
+    DisreRm3Tav,
+    OrireInitF,
+    OrireDtav,
+    SVirPrev,
+    Nhvxi,
+    Veta,
+    Vol0,
+    Nhpresxi,
+    Nhpresvxi,
+    FVirPrev,
+    FepState,
+    MCRngNotSupported,
+    MCRngINotSupported,
+    BarosInt,
+    PullComPrevStep,
+    Count
 };
 
-//! \brief The names of the state entries, defined in src/gmxlib/checkpoint.c
-extern const char* est_names[estNR];
+//! \brief The names of the state entries, defined in src/gromacs/fileio/checkpoint.cpp
+const char* enumValueToString(StateEntry enumValue);
+/*! \brief Convert enum to bitmask value.
+ *
+ * Used for setting flags in checkpoint header and verifying which flags are set.
+ */
+template<typename Enum>
+inline int enumValueToBitMask(Enum enumValue)
+{
+    static_assert(static_cast<int>(Enum::Count) <= std::numeric_limits<int>::digits);
+    return 1 << static_cast<int>(enumValue);
+}
 
 /*! \libinternal \brief History information for NMR distance and orientation restraints
  *
@@ -142,12 +153,10 @@ class history_t
 public:
     history_t();
 
-    real  disre_initf;  //!< The scaling factor for initializing the time av.
-    int   ndisrepairs;  //!< The number of distance restraints
-    real* disre_rm3tav; //!< The r^-3 time averaged pair distances
-    real  orire_initf;  //!< The scaling factor for initializing the time av.
-    int   norire_Dtav;  //!< The number of matrix element in dtav (npair*5)
-    real* orire_Dtav;   //!< The time averaged orientation tensors
+    real              disre_initf;  //!< The scaling factor for initializing the time av.
+    std::vector<real> disre_rm3tav; //!< The r^-3 time averaged pair distances
+    real              orire_initf;  //!< The scaling factor for initializing the time av.
+    std::vector<real> orire_Dtav;   //!< The time averaged orientation tensors
 };
 
 /*! \libinternal \brief Struct used for checkpointing only
@@ -162,7 +171,7 @@ class ekinstate_t
 public:
     ekinstate_t();
 
-    gmx_bool            bUpToDate;      //!< Test if all data is up to date
+    bool                bUpToDate;      //!< Test if all data is up to date
     int                 ekin_n;         //!< The number of tensors
     tensor*             ekinh;          //!< Half step Ekin, size \p ekin_n
     tensor*             ekinf;          //!< Full step Ekin, size \p ekin_n
@@ -197,10 +206,10 @@ typedef struct df_history_t
 {
     int nlambda; //!< total number of lambda states - for history
 
-    gmx_bool bEquil;   //!< Have we reached equilibration
-    int*     n_at_lam; //!< number of points observed at each lambda
-    real*    wl_histo; //!< histogram for WL flatness determination
-    real     wl_delta; //!< current wang-landau delta
+    bool  bEquil;   //!< Have we reached equilibration
+    int*  n_at_lam; //!< number of points observed at each lambda
+    real* wl_histo; //!< histogram for WL flatness determination
+    real  wl_delta; //!< current wang-landau delta
 
     real* sum_weights; //!< weights of the states
     real* sum_dg; //!< free energies of the states -- not actually used for weighting, but informational
@@ -237,22 +246,22 @@ public:
     int nnhpres;       //!< The number of NH-chains for the MTTK barostat (always 1 or 0)
     int nhchainlength; //!< The NH-chain length for temperature coupling and MTTK barostat
     int flags; //!< Set of bit-flags telling which entries are present, see enum at the top of the file
-    int                      fep_state;      //!< indicates which of the alchemical states we are in
-    std::array<real, efptNR> lambda;         //!< Free-energy lambda vector
-    matrix                   box;            //!< Matrix of box vectors
-    matrix                   box_rel;        //!< Relative box vectors to preserve box shape
-    matrix                   boxv;           //!< Box velocities for Parrinello-Rahman P-coupling
-    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
-    std::vector<double>      nosehoover_xi;  //!< Nose-Hoover coordinates (ngtc)
-    std::vector<double>      nosehoover_vxi; //!< Nose-Hoover velocities (ngtc)
-    std::vector<double>      nhpres_xi;      //!< Pressure Nose-Hoover coordinates
-    std::vector<double>      nhpres_vxi;     //!< Pressure Nose-Hoover velocities
-    std::vector<double>      therm_integral; //!< Work exterted N-H/V-rescale T-coupling (ngtc)
-    double                   baros_integral; //!< For Berendsen P-coupling conserved quantity
-    real                     veta;           //!< Trotter based isotropic P-coupling
-    real vol0; //!< Initial volume,required for computing MTTK conserved quantity
+    int fep_state; //!< indicates which of the alchemical states we are in
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> lambda; //!< Free-energy lambda vector
+    matrix                                                          box; //!< Matrix of box vectors
+    matrix              box_rel;        //!< Relative box vectors to preserve box shape
+    matrix              boxv;           //!< Box velocities for Parrinello-Rahman P-coupling
+    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
+    std::vector<double> nosehoover_xi;  //!< Nose-Hoover coordinates (ngtc)
+    std::vector<double> nosehoover_vxi; //!< Nose-Hoover velocities (ngtc)
+    std::vector<double> nhpres_xi;      //!< Pressure Nose-Hoover coordinates
+    std::vector<double> nhpres_vxi;     //!< Pressure Nose-Hoover velocities
+    std::vector<double> therm_integral; //!< Work exterted N-H/V-rescale T-coupling (ngtc)
+    double              baros_integral; //!< For Berendsen P-coupling conserved quantity
+    real                veta;           //!< Trotter based isotropic P-coupling
+    real                vol0; //!< Initial volume,required for computing MTTK conserved quantity
     PaddedHostVector<gmx::RVec> x;    //!< The coordinates (natoms)
     PaddedHostVector<gmx::RVec> v;    //!< The velocities (natoms)
     PaddedHostVector<gmx::RVec> cg_p; //!< p vector for conjugate gradient minimization
@@ -284,17 +293,6 @@ struct t_extmass
     tensor              Winvm; /* inverse pressure mass tensor, computed       */
 };
 
-
-typedef struct
-{
-    real    veta;
-    double  rscale;
-    double  vscale;
-    double  rvscale;
-    double  alpha;
-    double* vscale_nhc;
-} t_vetavars;
-
 #endif // DOXYGEN
 
 //! Resizes the T- and P-coupling state variables
@@ -307,7 +305,7 @@ void state_change_natoms(t_state* state, int natoms);
 void init_dfhist_state(t_state* state, int dfhistNumLambda);
 
 /*! \brief Compares two states, write the differences to stdout */
-void comp_state(const t_state* st1, const t_state* st2, gmx_bool bRMSD, real ftol, real abstol);
+void comp_state(const t_state* st1, const t_state* st2, bool bRMSD, real ftol, real abstol);
 
 /*! \brief Allocates an rvec pointer and copy the contents of v to it */
 rvec* makeRvecArray(gmx::ArrayRef<const gmx::RVec> v, gmx::index n);
@@ -358,7 +356,7 @@ static inline gmx::ArrayRef<const gmx::RVec> positionsFromStatePointer(const t_s
  * \param[in] lambda The array of lambda values.
  * \param[in] isInitialOutput Whether this output is the initial lambda state or not.
  */
-void printLambdaStateToLog(FILE* fplog, gmx::ArrayRef<real> lambda, bool isInitialOutput);
+void printLambdaStateToLog(FILE* fplog, gmx::ArrayRef<const real> lambda, bool isInitialOutput);
 
 
 /*! \brief Fills fep_state and lambda if needed
@@ -367,6 +365,14 @@ void printLambdaStateToLog(FILE* fplog, gmx::ArrayRef<real> lambda, bool isIniti
  * and lambda on master rank.
  *
  * Reports the initial lambda state to the log file. */
-void initialize_lambdas(FILE* fplog, const t_inputrec& ir, bool isMaster, int* fep_state, gmx::ArrayRef<real> lambda);
+void initialize_lambdas(FILE*                      fplog,
+                        FreeEnergyPerturbationType freeEnergyPerturbationType,
+                        bool                       haveSimulatedTempering,
+                        const t_lambda&            fep,
+                        gmx::ArrayRef<const real>  simulatedTemperingTemps,
+                        gmx::ArrayRef<real>        ref_t,
+                        bool                       isMaster,
+                        int*                       fep_state,
+                        gmx::ArrayRef<real>        lambda);
 
 #endif
index 89e6d622ac270a39ac566501ac558da92de7934b..3f66196509f742859e0dcd670cc5f0189a62fad4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 @@
 #ifndef GMX_MDTYPES_STATE_PROPAGATOR_DATA_GPU_H
 #define GMX_MDTYPES_STATE_PROPAGATOR_DATA_GPU_H
 
+#include <memory>
 #include <tuple>
 
 #include "gromacs/gpu_utils/devicebuffer_datatype.h"
@@ -269,6 +270,12 @@ public:
      */
     void copyForcesToGpu(gmx::ArrayRef<const gmx::RVec> h_f, AtomLocality atomLocality);
 
+    /*! \brief Clear forces in the GPU memory.
+     *
+     *  \param[in] atomLocality  Locality of the particles to clear.
+     */
+    void clearForcesOnGpu(AtomLocality atomLocality);
+
     /*! \brief Get the event synchronizer for the forces ready on device.
      *
      *  Returns either of the event synchronizers, depending on the offload scenario
@@ -326,7 +333,7 @@ public:
 
 private:
     class Impl;
-    gmx::PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
     GMX_DISALLOW_COPY_AND_ASSIGN(StatePropagatorDataGpu);
 };
 
index 3274d3dd02bf8892e3de11f951669fcdb578e1f7..f112d1b1cb08180971938eda99eb4632f9e6e6fc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -206,6 +206,13 @@ void StatePropagatorDataGpu::copyForcesToGpu(const gmx::ArrayRef<const gmx::RVec
                "GPU implementation.");
 }
 
+void StatePropagatorDataGpu::clearForcesOnGpu(AtomLocality /* atomLocality */)
+{
+    GMX_ASSERT(!impl_,
+               "A CPU stub method from GPU state propagator data was called instead of one from "
+               "GPU implementation.");
+}
+
 GpuEventSynchronizer* StatePropagatorDataGpu::getForcesReadyOnDeviceEvent(AtomLocality /* atomLocality */,
                                                                           bool /* useGpuFBufferOps */)
 {
index 17737b547714846a81ad941545d64d3233bdbaad..cc9f92bcfe9883351caa1f73bc42740ed57ed55e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
 
 #include "config.h"
 
+#include <memory>
+
 #include "gromacs/gpu_utils/devicebuffer.h"
 #if GMX_GPU_CUDA
 #    include "gromacs/gpu_utils/gpueventsynchronizer.cuh"
@@ -55,9 +57,9 @@
 #elif GMX_GPU_SYCL
 #    include "gromacs/gpu_utils/gpueventsynchronizer_sycl.h"
 #endif
+
 #include "gromacs/math/vectypes.h"
 #include "gromacs/mdtypes/state_propagator_data_gpu.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/enumerationhelpers.h"
 
 struct gmx_wallcycle;
@@ -263,6 +265,12 @@ public:
      */
     void copyForcesToGpu(gmx::ArrayRef<const gmx::RVec> h_f, AtomLocality atomLocality);
 
+    /*! \brief Clear forces in the GPU memory.
+     *
+     *  \param[in] atomLocality  Locality of the particles to clear.
+     */
+    void clearForcesOnGpu(AtomLocality atomLocality);
+
     /*! \brief Get the event synchronizer for the forces ready on device.
      *
      *  Returns either of the event synchronizers, depending on the offload scenario
@@ -422,6 +430,20 @@ private:
                         int                      dataSize,
                         AtomLocality             atomLocality,
                         const DeviceStream&      deviceStream);
+
+    /*! \brief Performs the clearing of data in device buffer.
+     *
+     * \todo Template on locality.
+     *
+     *  \param[out] d_data         Device-side buffer.
+     *  \param[in]  dataSize       Device-side data allocation size.
+     *  \param[in]  atomLocality   If all, local or non-local ranges should be cleared.
+     *  \param[in]  deviceStream   GPU stream to execute copy in.
+     */
+    void clearOnDevice(DeviceBuffer<RVec>  d_data,
+                       int                 dataSize,
+                       AtomLocality        atomLocality,
+                       const DeviceStream& deviceStream);
 };
 
 } // namespace gmx
index 8737f63ba9fdd5e29121b779f8e05e4489549547..69e11d69c0671f3ce2765f900f1a0baa462e6a11 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +136,8 @@ StatePropagatorDataGpu::Impl::~Impl() {}
 
 void StatePropagatorDataGpu::Impl::reinit(int numAtomsLocal, int numAtomsAll)
 {
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start_nocount(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start_nocount(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
 
     numAtomsLocal_ = numAtomsLocal;
     numAtomsAll_   = numAtomsAll;
@@ -174,8 +174,8 @@ void StatePropagatorDataGpu::Impl::reinit(int numAtomsLocal, int numAtomsAll)
         clearDeviceBufferAsync(&d_f_, 0, d_fCapacity_, *localStream_);
     }
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
 std::tuple<int, int> StatePropagatorDataGpu::Impl::getAtomRangesFromAtomLocality(AtomLocality atomLocality)
@@ -234,8 +234,13 @@ void StatePropagatorDataGpu::Impl::copyToDevice(DeviceBuffer<RVec>
         GMX_ASSERT(atomsStartAt + numAtomsToCopy <= h_data.ssize(),
                    "The host buffer is smaller than the requested copy range.");
 
-        copyToDeviceBuffer(&d_data, reinterpret_cast<const RVec*>(&h_data.data()[atomsStartAt]),
-                           atomsStartAt, numAtomsToCopy, deviceStream, transferKind_, nullptr);
+        copyToDeviceBuffer(&d_data,
+                           reinterpret_cast<const RVec*>(&h_data.data()[atomsStartAt]),
+                           atomsStartAt,
+                           numAtomsToCopy,
+                           deviceStream,
+                           transferKind_,
+                           nullptr);
     }
 }
 
@@ -263,8 +268,38 @@ void StatePropagatorDataGpu::Impl::copyFromDevice(gmx::ArrayRef<gmx::RVec> h_dat
         GMX_ASSERT(atomsStartAt + numAtomsToCopy <= h_data.ssize(),
                    "The host buffer is smaller than the requested copy range.");
 
-        copyFromDeviceBuffer(reinterpret_cast<RVec*>(&h_data.data()[atomsStartAt]), &d_data,
-                             atomsStartAt, numAtomsToCopy, deviceStream, transferKind_, nullptr);
+        copyFromDeviceBuffer(reinterpret_cast<RVec*>(&h_data.data()[atomsStartAt]),
+                             &d_data,
+                             atomsStartAt,
+                             numAtomsToCopy,
+                             deviceStream,
+                             transferKind_,
+                             nullptr);
+    }
+}
+
+void StatePropagatorDataGpu::Impl::clearOnDevice(DeviceBuffer<RVec>  d_data,
+                                                 int                 dataSize,
+                                                 AtomLocality        atomLocality,
+                                                 const DeviceStream& deviceStream)
+{
+    GMX_UNUSED_VALUE(dataSize);
+
+    GMX_ASSERT(atomLocality < AtomLocality::Count, "Wrong atom locality.");
+
+    GMX_ASSERT(dataSize >= 0, "Trying to clear to device buffer before it was allocated.");
+
+    GMX_ASSERT(deviceStream.isValid(), "No stream is valid for clearing with given atom locality.");
+
+    int atomsStartAt, numAtomsToClear;
+    std::tie(atomsStartAt, numAtomsToClear) = getAtomRangesFromAtomLocality(atomLocality);
+
+    if (numAtomsToClear != 0)
+    {
+        GMX_ASSERT(atomsStartAt + numAtomsToClear <= dataSize,
+                   "The device allocation is smaller than requested clear range.");
+
+        clearDeviceBufferAsync(&d_data, atomsStartAt, numAtomsToClear, deviceStream);
     }
 }
 
@@ -281,8 +316,8 @@ void StatePropagatorDataGpu::Impl::copyCoordinatesToGpu(const gmx::ArrayRef<cons
     GMX_ASSERT(deviceStream != nullptr,
                "No stream is valid for copying positions with given atom locality.");
 
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
 
     copyToDevice(d_x_, h_x, d_xSize_, atomLocality, *deviceStream);
 
@@ -295,8 +330,8 @@ void StatePropagatorDataGpu::Impl::copyCoordinatesToGpu(const gmx::ArrayRef<cons
         xReadyOnDevice_[atomLocality].markEvent(*deviceStream);
     }
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
 GpuEventSynchronizer*
@@ -328,10 +363,10 @@ StatePropagatorDataGpu::Impl::getCoordinatesReadyOnDeviceEvent(AtomLocality atom
 
 void StatePropagatorDataGpu::Impl::waitCoordinatesCopiedToDevice(AtomLocality atomLocality)
 {
-    wallcycle_start(wcycle_, ewcWAIT_GPU_STATE_PROPAGATOR_DATA);
+    wallcycle_start(wcycle_, WallCycleCounter::WaitGpuStatePropagatorData);
     GMX_ASSERT(atomLocality < AtomLocality::Count, "Wrong atom locality.");
     xReadyOnDevice_[atomLocality].waitForEvent();
-    wallcycle_stop(wcycle_, ewcWAIT_GPU_STATE_PROPAGATOR_DATA);
+    wallcycle_stop(wcycle_, WallCycleCounter::WaitGpuStatePropagatorData);
 }
 
 GpuEventSynchronizer* StatePropagatorDataGpu::Impl::xUpdatedOnDevice()
@@ -346,22 +381,22 @@ void StatePropagatorDataGpu::Impl::copyCoordinatesFromGpu(gmx::ArrayRef<gmx::RVe
     GMX_ASSERT(deviceStream != nullptr,
                "No stream is valid for copying positions with given atom locality.");
 
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
 
     copyFromDevice(h_x, d_x_, d_xSize_, atomLocality, *deviceStream);
     // Note: unlike copyCoordinatesToGpu this is not used in OpenCL, and the conditional is not needed.
     xReadyOnHost_[atomLocality].markEvent(*deviceStream);
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
 void StatePropagatorDataGpu::Impl::waitCoordinatesReadyOnHost(AtomLocality atomLocality)
 {
-    wallcycle_start(wcycle_, ewcWAIT_GPU_STATE_PROPAGATOR_DATA);
+    wallcycle_start(wcycle_, WallCycleCounter::WaitGpuStatePropagatorData);
     xReadyOnHost_[atomLocality].waitForEvent();
-    wallcycle_stop(wcycle_, ewcWAIT_GPU_STATE_PROPAGATOR_DATA);
+    wallcycle_stop(wcycle_, WallCycleCounter::WaitGpuStatePropagatorData);
 }
 
 
@@ -378,14 +413,14 @@ void StatePropagatorDataGpu::Impl::copyVelocitiesToGpu(const gmx::ArrayRef<const
     GMX_ASSERT(deviceStream != nullptr,
                "No stream is valid for copying velocities with given atom locality.");
 
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
 
     copyToDevice(d_v_, h_v, d_vSize_, atomLocality, *deviceStream);
     vReadyOnDevice_[atomLocality].markEvent(*deviceStream);
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
 GpuEventSynchronizer* StatePropagatorDataGpu::Impl::getVelocitiesReadyOnDeviceEvent(AtomLocality atomLocality)
@@ -401,21 +436,21 @@ void StatePropagatorDataGpu::Impl::copyVelocitiesFromGpu(gmx::ArrayRef<gmx::RVec
     GMX_ASSERT(deviceStream != nullptr,
                "No stream is valid for copying velocities with given atom locality.");
 
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
 
     copyFromDevice(h_v, d_v_, d_vSize_, atomLocality, *deviceStream);
     vReadyOnHost_[atomLocality].markEvent(*deviceStream);
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
 void StatePropagatorDataGpu::Impl::waitVelocitiesReadyOnHost(AtomLocality atomLocality)
 {
-    wallcycle_start(wcycle_, ewcWAIT_GPU_STATE_PROPAGATOR_DATA);
+    wallcycle_start(wcycle_, WallCycleCounter::WaitGpuStatePropagatorData);
     vReadyOnHost_[atomLocality].waitForEvent();
-    wallcycle_stop(wcycle_, ewcWAIT_GPU_STATE_PROPAGATOR_DATA);
+    wallcycle_stop(wcycle_, WallCycleCounter::WaitGpuStatePropagatorData);
 }
 
 
@@ -432,14 +467,30 @@ void StatePropagatorDataGpu::Impl::copyForcesToGpu(const gmx::ArrayRef<const gmx
     GMX_ASSERT(deviceStream != nullptr,
                "No stream is valid for copying forces with given atom locality.");
 
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
 
     copyToDevice(d_f_, h_f, d_fSize_, atomLocality, *deviceStream);
     fReadyOnDevice_[atomLocality].markEvent(*deviceStream);
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
+}
+
+void StatePropagatorDataGpu::Impl::clearForcesOnGpu(AtomLocality atomLocality)
+{
+    GMX_ASSERT(atomLocality < AtomLocality::Count, "Wrong atom locality.");
+    const DeviceStream* deviceStream = fCopyStreams_[atomLocality];
+    GMX_ASSERT(deviceStream != nullptr,
+               "No stream is valid for clearing forces with given atom locality.");
+
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
+
+    clearOnDevice(d_f_, d_fSize_, atomLocality, *deviceStream);
+
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
 GpuEventSynchronizer* StatePropagatorDataGpu::Impl::getForcesReadyOnDeviceEvent(AtomLocality atomLocality,
@@ -467,21 +518,21 @@ void StatePropagatorDataGpu::Impl::copyForcesFromGpu(gmx::ArrayRef<gmx::RVec> h_
     GMX_ASSERT(deviceStream != nullptr,
                "No stream is valid for copying forces with given atom locality.");
 
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
 
     copyFromDevice(h_f, d_f_, d_fSize_, atomLocality, *deviceStream);
     fReadyOnHost_[atomLocality].markEvent(*deviceStream);
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_STATE_PROPAGATOR_DATA);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchStatePropagatorData);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
 void StatePropagatorDataGpu::Impl::waitForcesReadyOnHost(AtomLocality atomLocality)
 {
-    wallcycle_start(wcycle_, ewcWAIT_GPU_STATE_PROPAGATOR_DATA);
+    wallcycle_start(wcycle_, WallCycleCounter::WaitGpuStatePropagatorData);
     fReadyOnHost_[atomLocality].waitForEvent();
-    wallcycle_stop(wcycle_, ewcWAIT_GPU_STATE_PROPAGATOR_DATA);
+    wallcycle_stop(wcycle_, WallCycleCounter::WaitGpuStatePropagatorData);
 }
 
 const DeviceStream* StatePropagatorDataGpu::Impl::getUpdateStream()
@@ -612,6 +663,11 @@ void StatePropagatorDataGpu::copyForcesToGpu(const gmx::ArrayRef<const gmx::RVec
     return impl_->copyForcesToGpu(h_f, atomLocality);
 }
 
+void StatePropagatorDataGpu::clearForcesOnGpu(AtomLocality atomLocality)
+{
+    return impl_->clearForcesOnGpu(atomLocality);
+}
+
 GpuEventSynchronizer* StatePropagatorDataGpu::getForcesReadyOnDeviceEvent(AtomLocality atomLocality,
                                                                           bool useGpuFBufferOps)
 {
index aeb26465c1f2204e3924281d1834023d07dfb28c..9637463bb3d17041a212bbcbab901d4e4e32b851 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_MDLIB_SWAPHISTORY_H
 
 #include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/utility/enumerationhelpers.h"
 
+enum class Domain : int;
+enum class ChannelHistory : int;
 /* History of an ion type used in position swapping
  */
-typedef struct swapstateIons_t
+struct swapstateIons_t
 {
-    int  nMolReq[eCompNR];      // Requested # of molecules per compartment
-    int* nMolReq_p[eCompNR];    // Pointer to this data (for checkpoint writing)
-    int  inflow_net[eCompNR];   // Flux determined from the # of swaps
-    int* inflow_net_p[eCompNR]; // Pointer to this data
-    int* nMolPast[eCompNR];     // Array with nAverage entries for history
-    int* nMolPast_p[eCompNR];   // Pointer points to the first entry only
+    gmx::EnumerationArray<Compartment, int> nMolReq; // Requested # of molecules per compartment
+    gmx::EnumerationArray<Compartment, int*> nMolReq_p; // Pointer to this data (for checkpoint writing)
+    gmx::EnumerationArray<Compartment, int>  inflow_net;   // Flux determined from the # of swaps
+    gmx::EnumerationArray<Compartment, int*> inflow_net_p; // Pointer to this data
+    gmx::EnumerationArray<Compartment, int*> nMolPast;   // Array with nAverage entries for history
+    gmx::EnumerationArray<Compartment, int*> nMolPast_p; // Pointer points to the first entry only
 
     // Channel flux detection, this is counting only and has no influence on whether swaps are performed or not:                                                                 */
-    int            fluxfromAtoB[eCompNR];   // Flux determined from the split cylinders
-    int*           fluxfromAtoB_p[eCompNR]; // Pointer to this data
-    int            nMol;                    // Number of molecules, size of the following arrays
-    unsigned char* comp_from;               // Ion came from which compartment?
-    unsigned char* channel_label;           // Through which channel did this ion pass?
-} swapstateIons_t;
+    gmx::EnumerationArray<Channel, int>  fluxfromAtoB;   // Flux determined from the split cylinders
+    gmx::EnumerationArray<Channel, int*> fluxfromAtoB_p; // Pointer to this data
+    int                                  nMol; // Number of molecules, size of the following arrays
+    Domain*                              comp_from;     // Ion came from which compartment?
+    ChannelHistory*                      channel_label; // Through which channel did this ion pass?
+};
 
 /* Position swapping state
  *
@@ -74,16 +77,16 @@ typedef struct swapstateIons_t
  */
 typedef struct swaphistory_t
 {
-    int  eSwapCoords; // Swapping along x, y, or z-direction?
-    int  nIonTypes;   // Number of ion types, this is the size of the following arrays
+    SwapType eSwapCoords; // Swapping along x, y, or z-direction?
+    int      nIonTypes;   // Number of ion types, this is the size of the following arrays
     int  nAverage; // Use average over this many swap attempt steps when determining the ion counts
     int  fluxleak; // Ions not going through any channel (bad!)
-    int* fluxleak_p;               // Pointer to this data
-    gmx_bool         bFromCpt;     // Did we start from a checkpoint file?
-    int              nat[eChanNR]; // Size of xc_old_whole, i.e. the number of atoms in each channel
-    rvec*            xc_old_whole[eChanNR]; // Last known whole positions of the two channels (important for multimeric ch.!)
-    rvec**           xc_old_whole_p[eChanNR]; // Pointer to these positions
-    swapstateIons_t* ionType;                 // History information for one ion type
+    int* fluxleak_p;                         // Pointer to this data
+    bool bFromCpt;                           // Did we start from a checkpoint file?
+    gmx::EnumerationArray<Channel, int> nat; // Size of xc_old_whole, i.e. the number of atoms in each channel
+    gmx::EnumerationArray<Channel, rvec*>  xc_old_whole; // Last known whole positions of the two channels (important for multimeric ch.!)
+    gmx::EnumerationArray<Channel, rvec**> xc_old_whole_p; // Pointer to these positions
+    swapstateIons_t*                       ionType;        // History information for one ion type
 } swaphistory_t;
 
 #endif
diff --git a/src/gromacs/mdtypes/tests/.clang-tidy b/src/gromacs/mdtypes/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 69e1b6b00b17e8bebf82e474a0a5d423843ab274..90d37b1d51389edbc0d15720cd30f7b4f16e7d8d 100644 (file)
@@ -36,4 +36,5 @@ gmx_add_unit_test(MdtypesUnitTest mdtypes-test
     CPP_SOURCE_FILES
         checkpointdata.cpp
         forcebuffers.cpp
+        multipletimestepping.cpp
         )
diff --git a/src/gromacs/mdtypes/tests/multipletimestepping.cpp b/src/gromacs/mdtypes/tests/multipletimestepping.cpp
new file mode 100644 (file)
index 0000000..e9fdc2e
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 the MultipleTimeStepping class and stand-alone functions.
+ *
+ * \author berk Hess <hess@kth.se>
+ * \ingroup module_mdtypes
+ */
+#include "gmxpre.h"
+
+#include "gromacs/mdtypes/multipletimestepping.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/smalloc.h"
+
+#include "testutils/testasserts.h"
+
+namespace gmx
+{
+
+namespace test
+{
+
+namespace
+{
+
+//! brief Sets up the MTS levels in \p ir and tests whether the number of errors matches \p numExpectedErrors
+void setAndCheckMtsLevels(const GromppMtsOpts& mtsOpts, t_inputrec* ir, const int numExpectedErrors)
+{
+    std::vector<std::string> errorMessages;
+    ir->useMts    = true;
+    ir->mtsLevels = setupMtsLevels(mtsOpts, &errorMessages);
+
+    if (haveValidMtsSetup(*ir))
+    {
+        std::vector<std::string> errorMessagesCheck = checkMtsRequirements(*ir);
+
+        // Concatenate the two lists with error messages
+        errorMessages.insert(errorMessages.end(), errorMessagesCheck.begin(), errorMessagesCheck.end());
+    }
+
+    EXPECT_EQ(errorMessages.size(), numExpectedErrors);
+}
+
+} // namespace
+
+//! Checks that only numLevels = 2 does not produce an error
+TEST(MultipleTimeStepping, ChecksNumLevels)
+{
+    for (int numLevels = 0; numLevels <= 3; numLevels++)
+    {
+        GromppMtsOpts mtsOpts;
+        mtsOpts.numLevels    = numLevels;
+        mtsOpts.level2Factor = 2;
+
+        t_inputrec ir;
+
+        setAndCheckMtsLevels(mtsOpts, &ir, numLevels != 2 ? 1 : 0);
+    }
+}
+
+//! Test that each force group works
+TEST(MultipleTimeStepping, SelectsForceGroups)
+{
+    for (int forceGroupIndex = 0; forceGroupIndex < static_cast<int>(MtsForceGroups::Count);
+         forceGroupIndex++)
+    {
+        const MtsForceGroups forceGroup = static_cast<MtsForceGroups>(forceGroupIndex);
+        SCOPED_TRACE("Testing force group " + mtsForceGroupNames[forceGroup]);
+
+        GromppMtsOpts mtsOpts;
+        mtsOpts.numLevels    = 2;
+        mtsOpts.level2Forces = mtsForceGroupNames[forceGroup];
+        mtsOpts.level2Factor = 2;
+
+        t_inputrec ir;
+
+        setAndCheckMtsLevels(mtsOpts, &ir, 0);
+
+        EXPECT_EQ(ir.mtsLevels[1].forceGroups.count(), 1);
+        EXPECT_EQ(ir.mtsLevels[1].forceGroups[forceGroupIndex], true);
+    }
+}
+
+//! Checks that factor is checked
+TEST(MultipleTimeStepping, ChecksStepFactor)
+{
+    for (int stepFactor = 0; stepFactor <= 3; stepFactor++)
+    {
+        GromppMtsOpts mtsOpts;
+        mtsOpts.numLevels    = 2;
+        mtsOpts.level2Factor = stepFactor;
+
+        t_inputrec ir;
+
+        setAndCheckMtsLevels(mtsOpts, &ir, stepFactor < 2 ? 1 : 0);
+    }
+}
+
+namespace
+{
+
+GromppMtsOpts simpleMtsOpts()
+{
+    GromppMtsOpts mtsOpts;
+    mtsOpts.numLevels    = 2;
+    mtsOpts.level2Forces = "nonbonded";
+    mtsOpts.level2Factor = 4;
+
+    return mtsOpts;
+}
+
+} // namespace
+
+TEST(MultipleTimeStepping, ChecksPmeIsAtLastLevel)
+{
+    const GromppMtsOpts mtsOpts = simpleMtsOpts();
+
+    t_inputrec ir;
+    ir.coulombtype = CoulombInteractionType::Pme;
+
+    setAndCheckMtsLevels(mtsOpts, &ir, 1);
+}
+
+//! Test fixture base for parametrizing interval tests
+using MtsIntervalTestParams = std::tuple<std::string, int>;
+class MtsIntervalTest : public ::testing::Test, public ::testing::WithParamInterface<MtsIntervalTestParams>
+{
+public:
+    MtsIntervalTest()
+    {
+        const auto  params        = GetParam();
+        const auto& parameterName = std::get<0>(params);
+        const auto  interval      = std::get<1>(params);
+        numExpectedErrors_        = (interval == 4 ? 0 : 1);
+
+        if (parameterName == "nstcalcenergy")
+        {
+            ir_.nstcalcenergy = interval;
+        }
+        else if (parameterName == "nstenergy")
+        {
+            ir_.nstenergy = interval;
+        }
+        else if (parameterName == "nstfout")
+        {
+            ir_.nstfout = interval;
+        }
+        else if (parameterName == "nstlist")
+        {
+            ir_.nstlist = interval;
+        }
+        else if (parameterName == "nstdhdl")
+        {
+            ir_.efep             = FreeEnergyPerturbationType::Yes;
+            ir_.fepvals->nstdhdl = interval;
+        }
+        else
+
+        {
+            GMX_RELEASE_ASSERT(false, "unknown parameter name");
+        }
+    }
+
+    t_inputrec ir_;
+    int        numExpectedErrors_;
+};
+
+TEST_P(MtsIntervalTest, Works)
+{
+    const GromppMtsOpts mtsOpts = simpleMtsOpts();
+
+    setAndCheckMtsLevels(mtsOpts, &ir_, numExpectedErrors_);
+}
+
+INSTANTIATE_TEST_CASE_P(
+        ChecksStepInterval,
+        MtsIntervalTest,
+        ::testing::Combine(
+                ::testing::Values("nstcalcenergy", "nstenergy", "nstfout", "nstlist", "nstdhdl"),
+                ::testing::Values(3, 4, 5)));
+
+// Check that correct input does not produce errors
+TEST(MultipleTimeStepping, ChecksIntegrator)
+{
+    const GromppMtsOpts mtsOpts = simpleMtsOpts();
+
+    t_inputrec ir;
+    ir.eI = IntegrationAlgorithm::BD;
+
+    setAndCheckMtsLevels(mtsOpts, &ir, 1);
+}
+
+} // namespace test
+} // namespace gmx
index 143271e29f787da3cbff19f52d05016e1a5b8f5c..84040bd4c7173dfcd59cac6ea45d8a41984a0572 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2018,2019, by the GROMACS development team, led by
+# Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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(
-        communicator.cpp
-        utilities.cpp
+# Set up the module library
+add_library(mimic INTERFACE)
+file(GLOB MIMIC_SOURCES *.cpp)
+set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${MIMIC_SOURCES} PARENT_SCOPE)
+
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(mimic PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(mimic PUBLIC
+target_include_directories(mimic INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(mimic PUBLIC
+target_link_libraries(mimic INTERFACE
+                      legacy_api
 )
 
+# TODO: when mimic is an OBJECT target
+#target_link_libraries(mimic PUBLIC legacy_api)
+#target_link_libraries(mimic PRIVATE common)
+
+# Module dependencies
+# mimic interfaces convey transitive dependence on these modules.
+#target_link_libraries(mimic PUBLIC
+target_link_libraries(mimic INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(mimic PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(mimic PRIVATE legacy_modules)
+
index 12dcf874d3f976913149edf461766bd8eb2ca813..177dc8813b0f883a2ecd2d98cc24e349da3eaee9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -141,7 +141,7 @@ void gmx::MimicCommunicator::sendInitData(gmx_mtop_t* mtop, PaddedHostVector<gmx
                 bonds.push_back(offset + at1 + 1);
                 bonds.push_back(offset + at2 + 1);
                 bondLengths.push_back(static_cast<double>(mtop->ffparams.iparams[contype].constr.dA)
-                                      / BOHR2NM);
+                                      / gmx::c_bohr2Nm);
             }
 
             for (int ncon = 0; ncon < nsettle; ++ncon)
@@ -165,11 +165,11 @@ void gmx::MimicCommunicator::sendInitData(gmx_mtop_t* mtop, PaddedHostVector<gmx
                 bonds.push_back(offset + h1 + 1);
                 bonds.push_back(offset + h2 + 1);
                 bondLengths.push_back(static_cast<double>(mtop->ffparams.iparams[contype].constr.dA)
-                                      / BOHR2NM);
+                                      / gmx::c_bohr2Nm);
                 bondLengths.push_back(static_cast<double>(mtop->ffparams.iparams[contype].constr.dA)
-                                      / BOHR2NM);
+                                      / gmx::c_bohr2Nm);
                 bondLengths.push_back(static_cast<double>(mtop->ffparams.iparams[contype].constr.dB)
-                                      / BOHR2NM);
+                                      / gmx::c_bohr2Nm);
             }
 
             nAtomsMol.push_back(type->atoms.nr);
@@ -234,9 +234,9 @@ void gmx::MimicCommunicator::sendInitData(gmx_mtop_t* mtop, PaddedHostVector<gmx
     std::vector<double> convertedCoords;
     for (auto& coord : coords)
     {
-        convertedCoords.push_back(static_cast<double>(coord[0]) / BOHR2NM);
-        convertedCoords.push_back(static_cast<double>(coord[1]) / BOHR2NM);
-        convertedCoords.push_back(static_cast<double>(coord[2]) / BOHR2NM);
+        convertedCoords.push_back(static_cast<double>(coord[0]) / gmx::c_bohr2Nm);
+        convertedCoords.push_back(static_cast<double>(coord[1]) / gmx::c_bohr2Nm);
+        convertedCoords.push_back(static_cast<double>(coord[2]) / gmx::c_bohr2Nm);
     }
 
     // sending array of coordinates
@@ -256,15 +256,15 @@ void gmx::MimicCommunicator::getCoords(PaddedHostVector<RVec>* x, const int nato
     MCL_receive(&*coords.begin(), 3 * natoms, TYPE_DOUBLE, 0);
     for (int j = 0; j < natoms; ++j)
     {
-        (*x)[j][0] = static_cast<real>(coords[j * 3] * BOHR2NM);
-        (*x)[j][1] = static_cast<real>(coords[j * 3 + 1] * BOHR2NM);
-        (*x)[j][2] = static_cast<real>(coords[j * 3 + 2] * BOHR2NM);
+        (*x)[j][0] = static_cast<real>(coords[j * 3] * gmx::c_bohr2Nm);
+        (*x)[j][1] = static_cast<real>(coords[j * 3 + 1] * gmx::c_bohr2Nm);
+        (*x)[j][2] = static_cast<real>(coords[j * 3 + 2] * gmx::c_bohr2Nm);
     }
 }
 
 void gmx::MimicCommunicator::sendEnergies(real energy)
 {
-    double convertedEnergy = energy / (HARTREE2KJ * AVOGADRO);
+    double convertedEnergy = energy / (gmx::c_hartree2Kj * gmx::c_avogadro);
     MCL_send(&convertedEnergy, 1, TYPE_DOUBLE, 0);
 }
 
@@ -273,9 +273,9 @@ void gmx::MimicCommunicator::sendForces(gmx::ArrayRef<gmx::RVec> forces, int nat
     std::vector<double> convertedForce;
     for (int j = 0; j < natoms; ++j)
     {
-        convertedForce.push_back(static_cast<real>(forces[j][0]) / HARTREE_BOHR2MD);
-        convertedForce.push_back(static_cast<real>(forces[j][1]) / HARTREE_BOHR2MD);
-        convertedForce.push_back(static_cast<real>(forces[j][2]) / HARTREE_BOHR2MD);
+        convertedForce.push_back(static_cast<real>(forces[j][0]) / gmx::c_hartreeBohr2Md);
+        convertedForce.push_back(static_cast<real>(forces[j][1]) / gmx::c_hartreeBohr2Md);
+        convertedForce.push_back(static_cast<real>(forces[j][2]) / gmx::c_hartreeBohr2Md);
     }
     MCL_send(&*convertedForce.begin(), convertedForce.size(), TYPE_DOUBLE, 0);
 }
index ac50973e41ceb9cd2278ad4afb69a58d2050a519..327f2de5e2aec3a97e6a543830384878ff4aa273 100644 (file)
 file(GLOB MODULARSIMULATOR_SOURCES *.cpp)
 
 add_library(modularsimulator OBJECT ${MODULARSIMULATOR_SOURCES})
-target_include_directories(modularsimulator SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/src/external)
-gmx_target_compile_options(modularsimulator)
-target_compile_definitions(modularsimulator PRIVATE HAVE_CONFIG_H)
-# Should be possible to remove this when resolving #3290
-target_include_directories(modularsimulator SYSTEM BEFORE PRIVATE ${PROJECT_SOURCE_DIR}/src/external/thread_mpi/include)
 
-if(GMX_OPENMP)
+if (GMX_OPENMP)
     # Explicitly set properties for modular simulator module to compile with openmp
     set_target_properties(modularsimulator PROPERTIES COMPILE_OPTIONS $<TARGET_PROPERTY:OpenMP::OpenMP_CXX,INTERFACE_COMPILE_OPTIONS>)
-endif()
+endif ()
 
 if (WIN32)
     gmx_target_warning_suppression(modularsimulator /wd4244 HAS_NO_MSVC_LOSSY_CONVERSION)
     gmx_target_warning_suppression(modularsimulator /wd4996 HAS_NO_MSVC_UNSAFE_FUNCTION)
-else()
+else ()
     # Several std::move uses are redundant in C++14, but clang before
     # 3.9 had a bug that needed them. gcc 9 can warn about their use,
     # which we need to supress. This suppression should be removed
     # when GROMACS requires clang 3.9 or higher.
     gmx_target_warning_suppression(modularsimulator "-Wno-redundant-move" HAS_NO_REDUNDANT_MOVE)
-endif()
+endif ()
+
+target_include_directories(modularsimulator SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/src/external)
+gmx_target_compile_options(modularsimulator)
+target_compile_definitions(modularsimulator PRIVATE HAVE_CONFIG_H)
+# Should be possible to remove this when resolving #3290
+target_include_directories(modularsimulator SYSTEM BEFORE PRIVATE ${PROJECT_SOURCE_DIR}/src/external/thread_mpi/include)
+
+# Source files have the following private external dependencies.
+target_link_libraries(modularsimulator PRIVATE tng_io)
+
+# Source files have the following private infrastructure dependencies.
+target_link_libraries(modularsimulator PRIVATE common)
+
+# Source files have the following private module dependencies.
+# TODO: Explicitly link specific modules.
+target_link_libraries(modularsimulator PRIVATE legacy_modules)
+target_link_libraries(modularsimulator PRIVATE
+                      gmxlib
+                      math
+                      mdtypes
+                      tng_io
+                      )
+
+# Public interface for modules, including dependencies and interfaces
+target_include_directories(modularsimulator PUBLIC
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+target_link_libraries(modularsimulator PUBLIC
+                      legacy_api
+                      )
+
+# Module dependencies
+# This module convey transitive dependence on these modules.
+target_link_libraries(modularsimulator PUBLIC
+                      utility
+                      )
 
 list(APPEND libgromacs_object_library_dependencies modularsimulator)
 set(libgromacs_object_library_dependencies ${libgromacs_object_library_dependencies} PARENT_SCOPE)
index 64487905f47fb3b2efe8d1550030312bfc67beea..cebedc784792d569acc0acb95dc6dd1589ebd8a6 100644 (file)
@@ -124,8 +124,8 @@ void CheckpointHelper::writeCheckpoint(Step step, Time time)
 
     if (MASTER(cr_))
     {
-        mdoutf_write_checkpoint(trajectoryElement_->outf_, fplog_, cr_, step, time, state_global_,
-                                observablesHistory_, &checkpointDataHolder);
+        mdoutf_write_checkpoint(
+                trajectoryElement_->outf_, fplog_, cr_, step, time, state_global_, observablesHistory_, &checkpointDataHolder);
     }
 }
 
@@ -170,7 +170,8 @@ void CheckpointHelperBuilder::registerClient(ICheckpointHelperClient* client)
                     formatString(
                             "CheckpointHelper client with key %s registered for checkpointing, "
                             "but %s does not exist in the input checkpoint file.",
-                            key.c_str(), key.c_str())
+                            key.c_str(),
+                            key.c_str())
                             .c_str());
         }
         client->restoreCheckpointState(
index 83c9bcd03e9c5f9fb3ea9996793e7700266a3d34..80b184f598384dedae278383651c498796402bba 100644 (file)
@@ -227,8 +227,8 @@ std::unique_ptr<CheckpointHelper> CheckpointHelperBuilder::build(Args&&... args)
 
     std::vector<std::tuple<std::string, ICheckpointHelperClient*>>&& clients = { clientsMap_.begin(),
                                                                                  clientsMap_.end() };
-    return std::make_unique<CheckpointHelper>(std::move(clients), std::move(checkpointHandler_),
-                                              std::forward<Args>(args)...);
+    return std::make_unique<CheckpointHelper>(
+            std::move(clients), std::move(checkpointHandler_), std::forward<Args>(args)...);
 }
 
 } // namespace gmx
index 28062291c6917dceb190a9fdf700d78c4ef46464..fac796b43815147429d2e943c96b236c6b82ecd5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "computeglobalselement.h"
 
-#include "gromacs/domdec/partition.h"
+#include "gromacs/domdec/domdec.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdlib/constr.h"
 #include "gromacs/mdlib/md_support.h"
 #include "gromacs/mdlib/mdatoms.h"
 #include "gromacs/mdlib/stat.h"
@@ -78,24 +79,22 @@ ComputeGlobalsElement<algorithm>::ComputeGlobalsElement(StatePropagatorData* sta
                                                         t_nrnb*            nrnb,
                                                         gmx_wallcycle*     wcycle,
                                                         t_forcerec*        fr,
-                                                        const gmx_mtop_t*  global_top,
+                                                        const gmx_mtop_t&  global_top,
                                                         Constraints*       constr) :
     energyReductionStep_(-1),
     virialReductionStep_(-1),
     vvSchedulingStep_(-1),
-    doStopCM_(inputrec->comm_mode != ecmNO),
+    doStopCM_(inputrec->comm_mode != ComRemovalAlgorithm::No),
     nstcomm_(inputrec->nstcomm),
     nstglobalcomm_(nstglobalcomm),
     lastStep_(inputrec->nsteps + inputrec->init_step),
     initStep_(inputrec->init_step),
     nullSignaller_(std::make_unique<SimulationSignaller>(nullptr, nullptr, nullptr, false, false)),
-    totalNumberOfBondedInteractions_(0),
-    shouldCheckNumberOfBondedInteractions_(false),
     statePropagatorData_(statePropagatorData),
     energyData_(energyData),
     localTopology_(nullptr),
     freeEnergyPerturbationData_(freeEnergyPerturbationData),
-    vcm_(global_top->groups, *inputrec),
+    vcm_(global_top.groups, *inputrec),
     signals_(signals),
     fplog_(fplog),
     mdlog_(mdlog),
@@ -135,10 +134,11 @@ void ComputeGlobalsElement<algorithm>::elementSetup()
         auto v = statePropagatorData_->velocitiesView();
         // At initialization, do not pass x with acceleration-correction mode
         // to avoid (incorrect) correction of the initial coordinates.
-        auto x = vcm_.mode == ecmLINEAR_ACCELERATION_CORRECTION ? ArrayRefWithPadding<RVec>()
-                                                                : statePropagatorData_->positionsView();
-        process_and_stopcm_grp(fplog_, &vcm_, *mdAtoms_->mdatoms(), x.unpaddedArrayRef(),
-                               v.unpaddedArrayRef());
+        auto x = vcm_.mode == ComRemovalAlgorithm::LinearAccelerationCorrection
+                         ? ArrayRefWithPadding<RVec>()
+                         : statePropagatorData_->positionsView();
+        process_and_stopcm_grp(
+                fplog_, &vcm_, *mdAtoms_->mdatoms(), x.unpaddedArrayRef(), v.unpaddedArrayRef());
         inc_nrnb(nrnb_, eNR_STOPCM, mdAtoms_->mdatoms()->homenr);
     }
 
@@ -202,8 +202,8 @@ void ComputeGlobalsElement<algorithm>::scheduleTask(Step step,
         const bool doInterSimSignal = false;
 
         // Make signaller to signal stop / reset / checkpointing signals
-        auto signaller = std::make_shared<SimulationSignaller>(signals_, cr_, nullptr,
-                                                               doInterSimSignal, doIntraSimSignal);
+        auto signaller = std::make_shared<SimulationSignaller>(
+                signals_, cr_, nullptr, doInterSimSignal, doIntraSimSignal);
 
         registerRunFunction([this, step, flags, signaller = std::move(signaller)]() {
             compute(step, flags, signaller.get(), true);
@@ -281,15 +281,37 @@ void ComputeGlobalsElement<algorithm>::compute(gmx::Step            step,
     auto lastbox = useLastBox ? statePropagatorData_->constPreviousBox()
                               : statePropagatorData_->constBox();
 
-    compute_globals(
-            gstat_, cr_, inputrec_, fr_, energyData_->ekindata(), x, v, box, mdAtoms_->mdatoms(),
-            nrnb_, &vcm_, step != -1 ? wcycle_ : nullptr, energyData_->enerdata(),
-            energyData_->forceVirial(step), energyData_->constraintVirial(step),
-            energyData_->totalVirial(step), energyData_->pressure(step), constr_, signaller,
-            lastbox, &totalNumberOfBondedInteractions_, energyData_->needToSumEkinhOld(),
-            flags | (shouldCheckNumberOfBondedInteractions_ ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS : 0));
-    checkNumberOfBondedInteractions(mdlog_, cr_, totalNumberOfBondedInteractions_, top_global_,
-                                    localTopology_, x, box, &shouldCheckNumberOfBondedInteractions_);
+    if (DOMAINDECOMP(cr_) && shouldCheckNumberOfBondedInteractions(*cr_->dd))
+    {
+        flags |= CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS;
+    }
+    compute_globals(gstat_,
+                    cr_,
+                    inputrec_,
+                    fr_,
+                    energyData_->ekindata(),
+                    x,
+                    v,
+                    box,
+                    mdAtoms_->mdatoms(),
+                    nrnb_,
+                    &vcm_,
+                    step != -1 ? wcycle_ : nullptr,
+                    energyData_->enerdata(),
+                    energyData_->forceVirial(step),
+                    energyData_->constraintVirial(step),
+                    energyData_->totalVirial(step),
+                    energyData_->pressure(step),
+                    (((flags & CGLO_ENERGY) != 0) && constr_ != nullptr) ? constr_->rmsdData()
+                                                                         : gmx::ArrayRef<real>{},
+                    signaller,
+                    lastbox,
+                    energyData_->needToSumEkinhOld(),
+                    flags);
+    if (DOMAINDECOMP(cr_))
+    {
+        checkNumberOfBondedInteractions(mdlog_, cr_, top_global_, localTopology_, x, box);
+    }
     if (flags & CGLO_STOPCM && !isInit)
     {
         process_and_stopcm_grp(fplog_, &vcm_, *mdAtoms_->mdatoms(), x, v);
@@ -297,18 +319,6 @@ void ComputeGlobalsElement<algorithm>::compute(gmx::Step            step,
     }
 }
 
-template<ComputeGlobalsAlgorithm algorithm>
-CheckBondedInteractionsCallback ComputeGlobalsElement<algorithm>::getCheckNumberOfBondedInteractionsCallback()
-{
-    return [this]() { needToCheckNumberOfBondedInteractions(); };
-}
-
-template<ComputeGlobalsAlgorithm algorithm>
-void ComputeGlobalsElement<algorithm>::needToCheckNumberOfBondedInteractions()
-{
-    shouldCheckNumberOfBondedInteractions_ = true;
-}
-
 template<ComputeGlobalsAlgorithm algorithm>
 void ComputeGlobalsElement<algorithm>::setTopology(const gmx_localtop_t* top)
 {
@@ -357,18 +367,21 @@ ISimulatorElement* ComputeGlobalsElement<ComputeGlobalsAlgorithm::LeapFrog>::get
 {
     auto* element = builderHelper->storeElement(
             std::make_unique<ComputeGlobalsElement<ComputeGlobalsAlgorithm::LeapFrog>>(
-                    statePropagatorData, energyData, freeEnergyPerturbationData,
+                    statePropagatorData,
+                    energyData,
+                    freeEnergyPerturbationData,
                     globalCommunicationHelper->simulationSignals(),
-                    globalCommunicationHelper->nstglobalcomm(), legacySimulatorData->fplog,
-                    legacySimulatorData->mdlog, legacySimulatorData->cr,
-                    legacySimulatorData->inputrec, legacySimulatorData->mdAtoms,
-                    legacySimulatorData->nrnb, legacySimulatorData->wcycle, legacySimulatorData->fr,
-                    legacySimulatorData->top_global, legacySimulatorData->constr));
-
-    // TODO: Remove this when DD can reduce bonded interactions independently (#3421)
-    auto* castedElement = static_cast<ComputeGlobalsElement<ComputeGlobalsAlgorithm::LeapFrog>*>(element);
-    globalCommunicationHelper->setCheckBondedInteractionsCallback(
-            castedElement->getCheckNumberOfBondedInteractionsCallback());
+                    globalCommunicationHelper->nstglobalcomm(),
+                    legacySimulatorData->fplog,
+                    legacySimulatorData->mdlog,
+                    legacySimulatorData->cr,
+                    legacySimulatorData->inputrec,
+                    legacySimulatorData->mdAtoms,
+                    legacySimulatorData->nrnb,
+                    legacySimulatorData->wcycle,
+                    legacySimulatorData->fr,
+                    legacySimulatorData->top_global,
+                    legacySimulatorData->constr));
 
     return element;
 }
@@ -396,18 +409,21 @@ ISimulatorElement* ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerlet
     {
         ISimulatorElement* vvComputeGlobalsElement = builderHelper->storeElement(
                 std::make_unique<ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerlet>>(
-                        statePropagatorData, energyData, freeEnergyPerturbationData,
+                        statePropagatorData,
+                        energyData,
+                        freeEnergyPerturbationData,
                         globalCommunicationHelper->simulationSignals(),
-                        globalCommunicationHelper->nstglobalcomm(), simulator->fplog, simulator->mdlog,
-                        simulator->cr, simulator->inputrec, simulator->mdAtoms, simulator->nrnb,
-                        simulator->wcycle, simulator->fr, simulator->top_global, simulator->constr));
-
-        // TODO: Remove this when DD can reduce bonded interactions independently (#3421)
-        auto* castedElement =
-                static_cast<ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerlet>*>(
-                        vvComputeGlobalsElement);
-        globalCommunicationHelper->setCheckBondedInteractionsCallback(
-                castedElement->getCheckNumberOfBondedInteractionsCallback());
+                        globalCommunicationHelper->nstglobalcomm(),
+                        simulator->fplog,
+                        simulator->mdlog,
+                        simulator->cr,
+                        simulator->inputrec,
+                        simulator->mdAtoms,
+                        simulator->nrnb,
+                        simulator->wcycle,
+                        simulator->fr,
+                        simulator->top_global,
+                        simulator->constr));
         builderHelper->storeValue(key, vvComputeGlobalsElement);
         return vvComputeGlobalsElement;
     }
index b949145703a85b7f42c6030d6a3014dad1367e6e..2ae60fa09605a4ce935e21d477b793340904c975 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -118,7 +118,7 @@ public:
                           t_nrnb*                     nrnb,
                           gmx_wallcycle*              wcycle,
                           t_forcerec*                 fr,
-                          const gmx_mtop_t*           global_top,
+                          const gmx_mtop_t&           global_top,
                           Constraints*                constr);
 
     //! Destructor
@@ -252,7 +252,7 @@ private:
     //! Contains user input mdp options.
     const t_inputrec* inputrec_;
     //! Full system topology - only needed for checkNumberOfBondedInteractions.
-    const gmx_mtop_t* top_global_;
+    const gmx_mtop_t& top_global_;
     //! Atom parameters for this domain.
     const MDAtoms* mdAtoms_;
     //! Handles constraints.
index 8519279a8e8d349ba215327c0c3d142b9fc18f35..06383b360345531c481df1e3e6d4e25081e5bc94 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,23 +88,31 @@ template<ConstraintVariable variable>
 void ConstraintsElement<variable>::elementSetup()
 {
     if (!inputrec_->bContinuation
-        && ((variable == ConstraintVariable::Positions && inputrec_->eI == eiMD)
-            || (variable == ConstraintVariable::Velocities && inputrec_->eI == eiVV)))
+        && ((variable == ConstraintVariable::Positions && inputrec_->eI == IntegrationAlgorithm::MD)
+            || (variable == ConstraintVariable::Velocities && inputrec_->eI == IntegrationAlgorithm::VV)))
     {
-        const real lambdaBonded = freeEnergyPerturbationData_
-                                          ? freeEnergyPerturbationData_->constLambdaView()[efptBONDED]
-                                          : 0;
+        const real lambdaBonded =
+                freeEnergyPerturbationData_
+                        ? freeEnergyPerturbationData_->constLambdaView()[static_cast<int>(
+                                  FreeEnergyPerturbationCouplingType::Bonded)]
+                        : 0;
         // Constrain the initial coordinates and velocities
-        do_constrain_first(
-                fplog_, constr_, inputrec_, statePropagatorData_->totalNumAtoms(),
-                statePropagatorData_->localNumAtoms(), statePropagatorData_->positionsView(),
-                statePropagatorData_->velocitiesView(), statePropagatorData_->box(), lambdaBonded);
+        do_constrain_first(fplog_,
+                           constr_,
+                           inputrec_,
+                           statePropagatorData_->totalNumAtoms(),
+                           statePropagatorData_->localNumAtoms(),
+                           statePropagatorData_->positionsView(),
+                           statePropagatorData_->velocitiesView(),
+                           statePropagatorData_->box(),
+                           lambdaBonded);
 
         if (isMasterRank_)
         {
-            if (inputrec_->eConstrAlg == econtLINCS)
+            if (inputrec_->eConstrAlg == ConstraintAlgorithm::Lincs)
             {
-                fprintf(fplog_, "RMS relative constraint deviation after constraining: %.2e\n",
+                fprintf(fplog_,
+                        "RMS relative constraint deviation after constraining: %.2e\n",
                         constr_->rmsd());
             }
         }
@@ -137,7 +145,10 @@ void ConstraintsElement<variable>::apply(Step step, bool calculateVirial, bool w
     ArrayRefWithPadding<RVec> v;
 
     const real lambdaBonded =
-            freeEnergyPerturbationData_ ? freeEnergyPerturbationData_->constLambdaView()[efptBONDED] : 0;
+            freeEnergyPerturbationData_
+                    ? freeEnergyPerturbationData_
+                              ->constLambdaView()[static_cast<int>(FreeEnergyPerturbationCouplingType::Bonded)]
+                    : 0;
     real dvdlambda = 0;
 
     switch (variable)
@@ -155,12 +166,25 @@ void ConstraintsElement<variable>::apply(Step step, bool calculateVirial, bool w
         default: gmx_fatal(FARGS, "Constraint algorithm not implemented for modular simulator.");
     }
 
-    constr_->apply(writeLog, writeEnergy, step, 1, 1.0, x, xprime, min_proj, statePropagatorData_->box(),
-                   lambdaBonded, &dvdlambda, v, calculateVirial, vir_con, variable);
+    constr_->apply(writeLog,
+                   writeEnergy,
+                   step,
+                   1,
+                   1.0,
+                   x,
+                   xprime,
+                   min_proj,
+                   statePropagatorData_->box(),
+                   lambdaBonded,
+                   &dvdlambda,
+                   v,
+                   calculateVirial,
+                   vir_con,
+                   variable);
 
     if (calculateVirial)
     {
-        if (inputrec_->eI == eiVV)
+        if (inputrec_->eI == IntegrationAlgorithm::VV)
         {
             // For some reason, the shake virial in VV is reset twice a step.
             // Energy element will only do this once per step.
@@ -216,10 +240,15 @@ ISimulatorElement* ConstraintsElement<variable>::getElementPointerImpl(
         FreeEnergyPerturbationData*             freeEnergyPerturbationData,
         GlobalCommunicationHelper gmx_unused* globalCommunicationHelper)
 {
-    return builderHelper->storeElement(std::make_unique<ConstraintsElement<variable>>(
-            legacySimulatorData->constr, statePropagatorData, energyData,
-            freeEnergyPerturbationData, MASTER(legacySimulatorData->cr), legacySimulatorData->fplog,
-            legacySimulatorData->inputrec, legacySimulatorData->mdAtoms->mdatoms()));
+    return builderHelper->storeElement(
+            std::make_unique<ConstraintsElement<variable>>(legacySimulatorData->constr,
+                                                           statePropagatorData,
+                                                           energyData,
+                                                           freeEnergyPerturbationData,
+                                                           MASTER(legacySimulatorData->cr),
+                                                           legacySimulatorData->fplog,
+                                                           legacySimulatorData->inputrec,
+                                                           legacySimulatorData->mdAtoms->mdatoms()));
 }
 
 // Explicit template initializations
index 9128119bfebf7724131de5b222fc4810b6937a7d..e9af4e1fd315a017fd0247d1b8a142592313ae52 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 namespace gmx
 {
-DomDecHelper::DomDecHelper(bool                            isVerbose,
-                           int                             verbosePrintInterval,
-                           StatePropagatorData*            statePropagatorData,
-                           FreeEnergyPerturbationData*     freeEnergyPerturbationData,
-                           TopologyHolder*                 topologyHolder,
-                           CheckBondedInteractionsCallback checkBondedInteractionsCallback,
-                           int                             nstglobalcomm,
-                           FILE*                           fplog,
-                           t_commrec*                      cr,
-                           const MDLogger&                 mdlog,
-                           Constraints*                    constr,
-                           t_inputrec*                     inputrec,
-                           MDAtoms*                        mdAtoms,
-                           t_nrnb*                         nrnb,
-                           gmx_wallcycle*                  wcycle,
-                           t_forcerec*                     fr,
-                           VirtualSitesHandler*            vsite,
-                           ImdSession*                     imdSession,
-                           pull_t*                         pull_work) :
+DomDecHelper::DomDecHelper(bool                        isVerbose,
+                           int                         verbosePrintInterval,
+                           StatePropagatorData*        statePropagatorData,
+                           FreeEnergyPerturbationData* freeEnergyPerturbationData,
+                           TopologyHolder*             topologyHolder,
+                           int                         nstglobalcomm,
+                           FILE*                       fplog,
+                           t_commrec*                  cr,
+                           const MDLogger&             mdlog,
+                           Constraints*                constr,
+                           const t_inputrec*           inputrec,
+                           MDAtoms*                    mdAtoms,
+                           t_nrnb*                     nrnb,
+                           gmx_wallcycle*              wcycle,
+                           t_forcerec*                 fr,
+                           VirtualSitesHandler*        vsite,
+                           ImdSession*                 imdSession,
+                           pull_t*                     pull_work) :
     nextNSStep_(-1),
     isVerbose_(isVerbose),
     verbosePrintInterval_(verbosePrintInterval),
@@ -82,7 +81,6 @@ DomDecHelper::DomDecHelper(bool                            isVerbose,
     statePropagatorData_(statePropagatorData),
     freeEnergyPerturbationData_(freeEnergyPerturbationData),
     topologyHolder_(topologyHolder),
-    checkBondedInteractionsCallback_(std::move(checkBondedInteractionsCallback)),
     fplog_(fplog),
     cr_(cr),
     mdlog_(mdlog),
@@ -108,8 +106,12 @@ void DomDecHelper::setup()
     gmx_wallcycle* wcycle        = nullptr;
 
     // Distribute the charge groups over the nodes from the master node
-    partitionSystem(verbose, isMasterState, nstglobalcomm, wcycle,
-                    statePropagatorData_->localState(), statePropagatorData_->globalState());
+    partitionSystem(verbose,
+                    isMasterState,
+                    nstglobalcomm,
+                    wcycle,
+                    statePropagatorData_->localState(),
+                    statePropagatorData_->globalState());
 }
 
 void DomDecHelper::run(Step step, Time gmx_unused time)
@@ -154,13 +156,28 @@ void DomDecHelper::partitionSystem(bool                     verbose,
     ForceBuffers* forcePointer = statePropagatorData_->forcePointer();
 
     // Distribute the charge groups over the nodes from the master node
-    dd_partition_system(fplog_, mdlog_, inputrec_->init_step, cr_, isMasterState, nstglobalcomm,
-                        globalState, topologyHolder_->globalTopology(), inputrec_, imdSession_,
-                        pull_work_, localState.get(), forcePointer, mdAtoms_,
-                        topologyHolder_->localTopology_.get(), fr_, vsite_, constr_, nrnb_, wcycle,
+    dd_partition_system(fplog_,
+                        mdlog_,
+                        inputrec_->init_step,
+                        cr_,
+                        isMasterState,
+                        nstglobalcomm,
+                        globalState,
+                        topologyHolder_->globalTopology(),
+                        *inputrec_,
+                        imdSession_,
+                        pull_work_,
+                        localState.get(),
+                        forcePointer,
+                        mdAtoms_,
+                        topologyHolder_->localTopology_.get(),
+                        fr_,
+                        vsite_,
+                        constr_,
+                        nrnb_,
+                        wcycle,
                         verbose);
     topologyHolder_->updateLocalTopology();
-    checkBondedInteractionsCallback_();
     statePropagatorData_->setLocalState(std::move(localState));
     if (freeEnergyPerturbationData_)
     {
index 2b6691c1578a199618059eb3e67c90f22f3be9c2..8469cecc89291f1a5eabadd54c2b1ec899c7b9a9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -68,9 +68,6 @@ class VirtualSitesHandler;
 //! \addtogroup module_modularsimulator
 //! \{
 
-//! The function type allowing to request a check of the number of bonded interactions
-typedef std::function<void()> CheckBondedInteractionsCallback;
-
 /*! \internal
  * \brief Infrastructure element responsible for domain decomposition
  *
@@ -88,25 +85,24 @@ class DomDecHelper final : public INeighborSearchSignallerClient
 {
 public:
     //! Constructor
-    DomDecHelper(bool                            isVerbose,
-                 int                             verbosePrintInterval,
-                 StatePropagatorData*            statePropagatorData,
-                 FreeEnergyPerturbationData*     freeEnergyPerturbationData,
-                 TopologyHolder*                 topologyHolder,
-                 CheckBondedInteractionsCallback checkBondedInteractionsCallback,
-                 int                             nstglobalcomm,
-                 FILE*                           fplog,
-                 t_commrec*                      cr,
-                 const MDLogger&                 mdlog,
-                 Constraints*                    constr,
-                 t_inputrec*                     inputrec,
-                 MDAtoms*                        mdAtoms,
-                 t_nrnb*                         nrnb,
-                 gmx_wallcycle*                  wcycle,
-                 t_forcerec*                     fr,
-                 VirtualSitesHandler*            vsite,
-                 ImdSession*                     imdSession,
-                 pull_t*                         pull_work);
+    DomDecHelper(bool                        isVerbose,
+                 int                         verbosePrintInterval,
+                 StatePropagatorData*        statePropagatorData,
+                 FreeEnergyPerturbationData* freeEnergyPerturbationData,
+                 TopologyHolder*             topologyHolder,
+                 int                         nstglobalcomm,
+                 FILE*                       fplog,
+                 t_commrec*                  cr,
+                 const MDLogger&             mdlog,
+                 Constraints*                constr,
+                 const t_inputrec*           inputrec,
+                 MDAtoms*                    mdAtoms,
+                 t_nrnb*                     nrnb,
+                 gmx_wallcycle*              wcycle,
+                 t_forcerec*                 fr,
+                 VirtualSitesHandler*        vsite,
+                 ImdSession*                 imdSession,
+                 pull_t*                     pull_work);
 
     /*! \brief Run domain decomposition
      *
@@ -142,8 +138,6 @@ private:
     FreeEnergyPerturbationData* freeEnergyPerturbationData_;
     //! Pointer to the topology
     TopologyHolder* topologyHolder_;
-    //! Pointer to the ComputeGlobalsHelper object - to ask for # of bonded interaction checking
-    CheckBondedInteractionsCallback checkBondedInteractionsCallback_;
 
     //! Helper function unifying the DD partitioning calls in setup() and run()
     void partitionSystem(bool                     verbose,
@@ -163,7 +157,7 @@ private:
     //! Handles constraints.
     Constraints* constr_;
     //! Contains user input mdp options.
-    t_inputrec* inputrec_;
+    const t_inputrec* inputrec_;
     //! Atom parameters for this domain.
     MDAtoms* mdAtoms_;
     //! Manages flop accounting.
index 87b7ef8e0fe9f4957360c203a795746f30555576..0e2e7e94325d57b3b4014974730acf0e44ab1112 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gmxlib/network.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/compute_io.h"
-#include "gromacs/mdlib/coupling.h"
 #include "gromacs/mdlib/enerdata_utils.h"
 #include "gromacs/mdlib/energyoutput.h"
 #include "gromacs/mdlib/mdatoms.h"
 #include "gromacs/mdlib/mdoutf.h"
 #include "gromacs/mdlib/stat.h"
+#include "gromacs/mdlib/tgroup.h"
 #include "gromacs/mdlib/update.h"
-#include "gromacs/mdrunutility/handlerestart.h"
-#include "gromacs/mdtypes/checkpointdata.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/enerdata.h"
 #include "gromacs/mdtypes/energyhistory.h"
+#include "gromacs/mdtypes/group.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/mdtypes/observableshistory.h"
 
 #include "freeenergyperturbationdata.h"
 #include "modularsimulator.h"
-#include "parrinellorahmanbarostat.h"
 #include "simulatoralgorithm.h"
 #include "statepropagatordata.h"
-#include "velocityscalingtemperaturecoupling.h"
 
 struct pull_t;
 class t_state;
@@ -80,7 +77,7 @@ class Awh;
 
 EnergyData::EnergyData(StatePropagatorData*        statePropagatorData,
                        FreeEnergyPerturbationData* freeEnergyPerturbationData,
-                       const gmx_mtop_t*           globalTopology,
+                       const gmx_mtop_t&           globalTopology,
                        const t_inputrec*           inputrec,
                        const MDAtoms*              mdAtoms,
                        gmx_enerdata_t*             enerd,
@@ -88,7 +85,7 @@ EnergyData::EnergyData(StatePropagatorData*        statePropagatorData,
                        const Constraints*          constr,
                        FILE*                       fplog,
                        t_fcdata*                   fcd,
-                       const MdModulesNotifier&    mdModulesNotifier,
+                       const MDModulesNotifiers&   mdModulesNotifiers,
                        bool                        isMasterRank,
                        ObservablesHistory*         observablesHistory,
                        StartingBehavior            startingBehavior,
@@ -104,8 +101,6 @@ EnergyData::EnergyData(StatePropagatorData*        statePropagatorData,
     startingBehavior_(startingBehavior),
     statePropagatorData_(statePropagatorData),
     freeEnergyPerturbationData_(freeEnergyPerturbationData),
-    velocityScalingTemperatureCoupling_(nullptr),
-    parrinelloRahmanBarostat_(nullptr),
     inputrec_(inputrec),
     top_global_(globalTopology),
     mdAtoms_(mdAtoms),
@@ -114,8 +109,8 @@ EnergyData::EnergyData(StatePropagatorData*        statePropagatorData,
     constr_(constr),
     fplog_(fplog),
     fcd_(fcd),
-    mdModulesNotifier_(mdModulesNotifier),
-    groups_(&globalTopology->groups),
+    mdModulesNotifiers_(mdModulesNotifiers),
+    groups_(&globalTopology.groups),
     observablesHistory_(observablesHistory),
     simulationsShareState_(simulationsShareState)
 {
@@ -140,8 +135,8 @@ void EnergyData::Element::scheduleTask(Step step, Time time, const RegisterRunFu
     auto isFreeEnergyCalculationStep = freeEnergyCalculationStep_ == step;
     if (isEnergyCalculationStep || writeEnergy)
     {
-        registerRunFunction([this, time, isEnergyCalculationStep, isFreeEnergyCalculationStep]() {
-            energyData_->doStep(time, isEnergyCalculationStep, isFreeEnergyCalculationStep);
+        registerRunFunction([this, step, time, isEnergyCalculationStep, isFreeEnergyCalculationStep]() {
+            energyData_->doStep(step, time, isEnergyCalculationStep, isFreeEnergyCalculationStep);
         });
     }
     else
@@ -167,9 +162,15 @@ void EnergyData::Element::trajectoryWriterSetup(gmx_mdoutf* outf)
 void EnergyData::setup(gmx_mdoutf* outf)
 {
     pull_t* pull_work = nullptr;
-    energyOutput_     = std::make_unique<EnergyOutput>(
-            mdoutf_get_fp_ene(outf), top_global_, inputrec_, pull_work, mdoutf_get_fp_dhdl(outf),
-            false, startingBehavior_, simulationsShareState_, mdModulesNotifier_);
+    energyOutput_     = std::make_unique<EnergyOutput>(mdoutf_get_fp_ene(outf),
+                                                   top_global_,
+                                                   *inputrec_,
+                                                   pull_work,
+                                                   mdoutf_get_fp_dhdl(outf),
+                                                   false,
+                                                   startingBehavior_,
+                                                   simulationsShareState_,
+                                                   mdModulesNotifiers_);
 
     if (!isMasterRank_)
     {
@@ -181,7 +182,7 @@ void EnergyData::setup(gmx_mdoutf* outf)
     // TODO: This probably doesn't really belong here...
     //       but we have all we need in this element,
     //       so we'll leave it here for now!
-    double io = compute_io(inputrec_, top_global_->natoms, *groups_, energyOutput_->numEnergyTerms(), 1);
+    double io = compute_io(inputrec_, top_global_.natoms, *groups_, energyOutput_->numEnergyTerms(), 1);
     if ((io > 2000) && isMasterRank_)
     {
         fprintf(stderr, "\nWARNING: This run will generate roughly %.0f Mb of data\n\n", io);
@@ -189,7 +190,7 @@ void EnergyData::setup(gmx_mdoutf* outf)
     if (!inputrec_->bContinuation)
     {
         real temp = enerd_->term[F_TEMP];
-        if (inputrec_->eI != eiVV)
+        if (inputrec_->eI != IntegrationAlgorithm::VV)
         {
             /* Result of Ekin averaged over velocities of -half
              * and +half step, while we only have -half step here.
@@ -233,34 +234,45 @@ std::optional<SignallerCallback> EnergyData::Element::registerEnergyCallback(Ene
     return std::nullopt;
 }
 
-void EnergyData::doStep(Time time, bool isEnergyCalculationStep, bool isFreeEnergyCalculationStep)
+void EnergyData::doStep(Step step, Time time, bool isEnergyCalculationStep, bool isFreeEnergyCalculationStep)
 {
     enerd_->term[F_ETOT] = enerd_->term[F_EPOT] + enerd_->term[F_EKIN];
     if (freeEnergyPerturbationData_)
     {
-        accumulateKineticLambdaComponents(enerd_, freeEnergyPerturbationData_->constLambdaView(),
-                                          *inputrec_->fepvals);
+        accumulateKineticLambdaComponents(
+                enerd_, freeEnergyPerturbationData_->constLambdaView(), *inputrec_->fepvals);
     }
     if (integratorHasConservedEnergyQuantity(inputrec_))
     {
-        enerd_->term[F_ECONSERVED] =
-                enerd_->term[F_ETOT]
-                + (velocityScalingTemperatureCoupling_
-                           ? velocityScalingTemperatureCoupling_->conservedEnergyContribution()
-                           : 0)
-                + (parrinelloRahmanBarostat_ ? parrinelloRahmanBarostat_->conservedEnergyContribution() : 0);
+        enerd_->term[F_ECONSERVED] = enerd_->term[F_ETOT];
+        for (const auto& energyContibution : conservedEnergyContributions_)
+        {
+            enerd_->term[F_ECONSERVED] += energyContibution(step, time);
+        }
     }
     matrix nullMatrix = {};
     energyOutput_->addDataAtEnergyStep(
-            isFreeEnergyCalculationStep, isEnergyCalculationStep, time, mdAtoms_->mdatoms()->tmass, enerd_,
-            inputrec_->fepvals, inputrec_->expandedvals, statePropagatorData_->constPreviousBox(),
-            PTCouplingArrays({ parrinelloRahmanBarostat_ ? parrinelloRahmanBarostat_->boxVelocities() : nullMatrix,
+            isFreeEnergyCalculationStep,
+            isEnergyCalculationStep,
+            time,
+            mdAtoms_->mdatoms()->tmass,
+            enerd_,
+            inputrec_->fepvals.get(),
+            inputrec_->expandedvals.get(),
+            statePropagatorData_->constPreviousBox(),
+            PTCouplingArrays({ parrinelloRahmanBoxVelocities_ ? parrinelloRahmanBoxVelocities_() : nullMatrix,
                                {},
                                {},
                                {},
                                {} }),
             freeEnergyPerturbationData_ ? freeEnergyPerturbationData_->currentFEPState() : 0,
-            shakeVirial_, forceVirial_, totalVirial_, pressure_, ekind_, muTot_, constr_);
+            shakeVirial_,
+            forceVirial_,
+            totalVirial_,
+            pressure_,
+            ekind_,
+            muTot_,
+            constr_);
 }
 
 void EnergyData::write(gmx_mdoutf* outf, Step step, Time time, bool writeTrajectory, bool writeLog)
@@ -275,8 +287,8 @@ void EnergyData::write(gmx_mdoutf* outf, Step step, Time time, bool writeTraject
 
     // energyOutput_->printAnnealingTemperatures(writeLog ? fplog_ : nullptr, groups_, &(inputrec_->opts));
     Awh* awh = nullptr;
-    energyOutput_->printStepToEnergyFile(mdoutf_get_fp_ene(outf), writeTrajectory, do_dr, do_or,
-                                         writeLog ? fplog_ : nullptr, step, time, fcd_, awh);
+    energyOutput_->printStepToEnergyFile(
+            mdoutf_get_fp_ene(outf), writeTrajectory, do_dr, do_or, writeLog ? fplog_ : nullptr, step, time, fcd_, awh);
 }
 
 void EnergyData::addToForceVirial(const tensor virial, Step step)
@@ -342,8 +354,7 @@ rvec* EnergyData::pressure(Step gmx_unused step)
         pressureStep_ = step;
         clear_mat(pressure_);
     }
-    GMX_ASSERT(step >= pressureStep_ || pressureStep_ == -1,
-               "Asked for pressure of previous step.");
+    GMX_ASSERT(step >= pressureStep_ || pressureStep_ == -1, "Asked for pressure of previous step.");
     return pressure_;
 }
 
@@ -428,7 +439,8 @@ void EnergyData::Element::restoreCheckpointState(std::optional<ReadCheckpointDat
     energyData_->hasReadEkinFromCheckpoint_ = MASTER(cr) ? energyData_->ekinstate_.bUpToDate : false;
     if (PAR(cr))
     {
-        gmx_bcast(sizeof(hasReadEkinFromCheckpoint_), &energyData_->hasReadEkinFromCheckpoint_,
+        gmx_bcast(sizeof(hasReadEkinFromCheckpoint_),
+                  &energyData_->hasReadEkinFromCheckpoint_,
                   cr->mpi_comm_mygroup);
     }
     if (energyData_->hasReadEkinFromCheckpoint_)
@@ -487,14 +499,34 @@ void EnergyData::initializeEnergyHistory(StartingBehavior    startingBehavior,
     energyOutput->fillEnergyHistory(observablesHistory->energyHistory.get());
 }
 
-void EnergyData::setVelocityScalingTemperatureCoupling(const VelocityScalingTemperatureCoupling* velocityScalingTemperatureCoupling)
+void EnergyData::addConservedEnergyContribution(EnergyContribution&& energyContribution)
 {
-    velocityScalingTemperatureCoupling_ = velocityScalingTemperatureCoupling;
+    conservedEnergyContributions_.emplace_back(std::move(energyContribution));
 }
 
-void EnergyData::setParrinelloRahamnBarostat(const gmx::ParrinelloRahmanBarostat* parrinelloRahmanBarostat)
+void EnergyData::setParrinelloRahmanBoxVelocities(std::function<const rvec*()>&& parrinelloRahmanBoxVelocities)
 {
-    parrinelloRahmanBarostat_ = parrinelloRahmanBarostat;
+    GMX_RELEASE_ASSERT(!parrinelloRahmanBoxVelocities_,
+                       "Received a second callback to the Parrinello-Rahman velocities");
+    parrinelloRahmanBoxVelocities_ = parrinelloRahmanBoxVelocities;
+}
+
+void EnergyData::updateKineticEnergy()
+{
+    // The legacy sum_ekin function does not offer named types, so define variables for readability
+    // dEkin/dlambda is not handled here
+    real* dEkinDLambda = nullptr;
+    // Whether we use the full step kinetic energy (vs the average of half step KEs)
+    const bool useFullStepKineticEnergy = (inputrec_->eI == IntegrationAlgorithm::VV);
+    /* Whether we're ignoring the NHC scaling factor, only used if useFullStepKineticEnergy
+     * is true. (This parameter is confusing, as it is named `bScaleEkin`, but prompts the
+     * function to ignore scaling. There is no use case within modular simulator to ignore
+     * these, so we set this to false.) */
+    const bool ignoreScalingFactor = false;
+
+    enerd_->term[F_TEMP] = sum_ekin(
+            &(inputrec_->opts), ekind_, dEkinDLambda, useFullStepKineticEnergy, ignoreScalingFactor);
+    enerd_->term[F_EKIN] = trace(ekind_->ekin);
 }
 
 EnergyData::Element* EnergyData::element()
index 29e2a0d28f4829f98e86ece3842c54b6deb72905..7ecfb55b1ffe7fdd030a865628e5f7734e71a32b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_ENERGYELEMENT_MICROSTATE_H
 #define GMX_ENERGYELEMENT_MICROSTATE_H
 
-#include "gromacs/math/vectypes.h"
 #include "gromacs/mdtypes/state.h"
 
 #include "modularsimulatorinterfaces.h"
 
-struct gmx_ekindata_t;
+class gmx_ekindata_t;
 struct gmx_enerdata_t;
 struct gmx_mtop_t;
 struct ObservablesHistory;
@@ -70,7 +69,10 @@ class ModularSimulatorAlgorithmBuilderHelper;
 class ParrinelloRahmanBarostat;
 class StatePropagatorData;
 class VelocityScalingTemperatureCoupling;
-struct MdModulesNotifier;
+struct MDModulesNotifiers;
+
+//! Function type for elements contributing energy
+using EnergyContribution = std::function<real(Step, Time)>;
 
 /*! \internal
  * \ingroup module_modularsimulator
@@ -96,7 +98,7 @@ public:
     //! Constructor
     EnergyData(StatePropagatorData*        statePropagatorData,
                FreeEnergyPerturbationData* freeEnergyPerturbationData,
-               const gmx_mtop_t*           globalTopology,
+               const gmx_mtop_t&           globalTopology,
                const t_inputrec*           inputrec,
                const MDAtoms*              mdAtoms,
                gmx_enerdata_t*             enerd,
@@ -104,7 +106,7 @@ public:
                const Constraints*          constr,
                FILE*                       fplog,
                t_fcdata*                   fcd,
-               const MdModulesNotifier&    mdModulesNotifier,
+               const MDModulesNotifiers&   mdModulesNotifiers,
                bool                        isMasterRank,
                ObservablesHistory*         observablesHistory,
                StartingBehavior            startingBehavior,
@@ -188,21 +190,19 @@ public:
      */
     [[nodiscard]] bool hasReadEkinFromCheckpoint() const;
 
-    /*! \brief Set velocity scaling temperature coupling
+    /*! \brief Add conserved energy contribution
      *
-     * This allows to set a pointer to a velocity scaling temperature coupling
-     * element used to obtain contributions to the conserved energy.
-     * TODO: This should be made obsolete my a more modular energy element
+     * This allows other elements to register callbacks for contributions to
+     * the conserved energy term.
      */
-    void setVelocityScalingTemperatureCoupling(const VelocityScalingTemperatureCoupling* velocityScalingTemperatureCoupling);
+    void addConservedEnergyContribution(EnergyContribution&& energyContribution);
 
     /*! \brief set Parrinello-Rahman barostat
      *
      * This allows to set a pointer to the Parrinello-Rahman barostat used to
      * print the box velocities.
-     * TODO: This should be made obsolete my a more modular energy element
      */
-    void setParrinelloRahamnBarostat(const ParrinelloRahmanBarostat* parrinelloRahmanBarostat);
+    void setParrinelloRahmanBoxVelocities(std::function<const rvec*()>&& parrinelloRahmanBoxVelocities);
 
     /*! \brief Initialize energy history
      *
@@ -213,6 +213,10 @@ public:
                                         ObservablesHistory* observablesHistory,
                                         EnergyOutput*       energyOutput);
 
+    /*! \brief Request (local) kinetic energy update
+     */
+    void updateKineticEnergy();
+
     //! The element taking part in the simulator loop
     class Element;
     //! Get pointer to element (whose lifetime is managed by this)
@@ -229,11 +233,12 @@ private:
 
     /*! \brief Save data at energy steps
      *
+     * \param step  The current step
      * \param time  The current time
      * \param isEnergyCalculationStep  Whether the current step is an energy calculation step
      * \param isFreeEnergyCalculationStep  Whether the current step is a free energy calculation step
      */
-    void doStep(Time time, bool isEnergyCalculationStep, bool isFreeEnergyCalculationStep);
+    void doStep(Step step, Time time, bool isEnergyCalculationStep, bool isFreeEnergyCalculationStep);
 
     /*! \brief Write to energy trajectory
      *
@@ -290,14 +295,16 @@ private:
     StatePropagatorData* statePropagatorData_;
     //! Pointer to the free energy perturbation data
     FreeEnergyPerturbationData* freeEnergyPerturbationData_;
-    //! Pointer to the vrescale thermostat
-    const VelocityScalingTemperatureCoupling* velocityScalingTemperatureCoupling_;
-    //! Pointer to the Parrinello-Rahman barostat
-    const ParrinelloRahmanBarostat* parrinelloRahmanBarostat_;
+
+    //! Callbacks contributing to the conserved energy term
+    std::vector<EnergyContribution> conservedEnergyContributions_;
+    //! Callback to the Parrinello-Rahman box velocities
+    std::function<const rvec*()> parrinelloRahmanBoxVelocities_;
+
     //! Contains user input mdp options.
     const t_inputrec* inputrec_;
     //! Full system topology.
-    const gmx_mtop_t* top_global_;
+    const gmx_mtop_t& top_global_;
     //! Atom parameters for this domain.
     const MDAtoms* mdAtoms_;
     //! Energy data structure
@@ -310,8 +317,8 @@ private:
     FILE* fplog_;
     //! Helper struct for force calculations.
     t_fcdata* fcd_;
-    //! Notification to MD modules
-    const MdModulesNotifier& mdModulesNotifier_;
+    //! Notifiers to MD modules
+    const MDModulesNotifiers& mdModulesNotifiers_;
     //! Global topology groups
     const SimulationGroups* groups_;
     //! History of simulation observables.
index 3aae7e375606c2cb712adafcc8a3582f33c071bb..77565e161c3f83475c1e4854d3f87b72ba43f5fd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ ForceElement::ForceElement(StatePropagatorData*        statePropagatorData,
                            ImdSession*            imdSession,
                            pull_t*                pull_work,
                            Constraints*           constr,
-                           const gmx_mtop_t*      globalTopology,
+                           const gmx_mtop_t&      globalTopology,
                            gmx_enfrot*            enforcedRotation) :
     shellfc_(init_shell_flexcon(fplog,
                                 globalTopology,
@@ -124,13 +124,13 @@ ForceElement::ForceElement(StatePropagatorData*        statePropagatorData,
     constr_(constr),
     enforcedRotation_(enforcedRotation)
 {
-    lambda_.fill(0);
+    std::fill(lambda_.begin(), lambda_.end(), 0);
 
     if (doShellFC_ && !DOMAINDECOMP(cr))
     {
         // This was done in mdAlgorithmsSetupAtomData(), but shellfc
         // won't be available outside this element.
-        make_local_shells(cr, mdAtoms->mdatoms(), shellfc_);
+        make_local_shells(cr, *mdAtoms->mdatoms(), shellfc_);
     }
 }
 
@@ -194,12 +194,38 @@ void ForceElement::run(Step step, Time time, unsigned int flags)
     {
         auto v = statePropagatorData_->velocitiesView();
 
-        relax_shell_flexcon(
-                fplog_, cr_, ms, isVerbose_, enforcedRotation_, step, inputrec_, imdSession_,
-                pull_work_, step == nextNSStep_, static_cast<int>(flags), localTopology_, constr_,
-                energyData_->enerdata(), statePropagatorData_->localNumAtoms(), x, v, box, lambda,
-                hist, &forces, force_vir, mdAtoms_->mdatoms(), nrnb_, wcycle_, shellfc_, fr_,
-                runScheduleWork_, time, energyData_->muTot(), vsite_, ddBalanceRegionHandler_);
+        relax_shell_flexcon(fplog_,
+                            cr_,
+                            ms,
+                            isVerbose_,
+                            enforcedRotation_,
+                            step,
+                            inputrec_,
+                            imdSession_,
+                            pull_work_,
+                            step == nextNSStep_,
+                            static_cast<int>(flags),
+                            localTopology_,
+                            constr_,
+                            energyData_->enerdata(),
+                            statePropagatorData_->localNumAtoms(),
+                            x,
+                            v,
+                            box,
+                            lambda,
+                            hist,
+                            &forces,
+                            force_vir,
+                            *mdAtoms_->mdatoms(),
+                            nrnb_,
+                            wcycle_,
+                            shellfc_,
+                            fr_,
+                            runScheduleWork_,
+                            time,
+                            energyData_->muTot(),
+                            vsite_,
+                            ddBalanceRegionHandler_);
         nShellRelaxationSteps_++;
     }
     else
@@ -208,10 +234,34 @@ void ForceElement::run(Step step, Time time, unsigned int flags)
         Awh*       awh = nullptr;
         gmx_edsam* ed  = nullptr;
 
-        do_force(fplog_, cr_, ms, inputrec_, awh, enforcedRotation_, imdSession_, pull_work_, step,
-                 nrnb_, wcycle_, localTopology_, box, x, hist, &forces, force_vir,
-                 mdAtoms_->mdatoms(), energyData_->enerdata(), lambda, fr_, runScheduleWork_, vsite_,
-                 energyData_->muTot(), time, ed, static_cast<int>(flags), ddBalanceRegionHandler_);
+        do_force(fplog_,
+                 cr_,
+                 ms,
+                 *inputrec_,
+                 awh,
+                 enforcedRotation_,
+                 imdSession_,
+                 pull_work_,
+                 step,
+                 nrnb_,
+                 wcycle_,
+                 localTopology_,
+                 box,
+                 x,
+                 hist,
+                 &forces,
+                 force_vir,
+                 mdAtoms_->mdatoms(),
+                 energyData_->enerdata(),
+                 lambda,
+                 fr_,
+                 runScheduleWork_,
+                 vsite_,
+                 energyData_->muTot(),
+                 time,
+                 ed,
+                 static_cast<int>(flags),
+                 ddBalanceRegionHandler_);
     }
     energyData_->addToForceVirial(force_vir, step);
 }
@@ -261,12 +311,25 @@ ForceElement::getElementPointerImpl(LegacySimulatorData*                    lega
 {
     const bool isVerbose    = legacySimulatorData->mdrunOptions.verbose;
     const bool isDynamicBox = inputrecDynamicBox(legacySimulatorData->inputrec);
-    return builderHelper->storeElement(std::make_unique<ForceElement>(
-            statePropagatorData, energyData, freeEnergyPerturbationData, isVerbose, isDynamicBox,
-            legacySimulatorData->fplog, legacySimulatorData->cr, legacySimulatorData->inputrec,
-            legacySimulatorData->mdAtoms, legacySimulatorData->nrnb, legacySimulatorData->fr,
-            legacySimulatorData->wcycle, legacySimulatorData->runScheduleWork, legacySimulatorData->vsite,
-            legacySimulatorData->imdSession, legacySimulatorData->pull_work, legacySimulatorData->constr,
-            legacySimulatorData->top_global, legacySimulatorData->enforcedRotation));
+    return builderHelper->storeElement(
+            std::make_unique<ForceElement>(statePropagatorData,
+                                           energyData,
+                                           freeEnergyPerturbationData,
+                                           isVerbose,
+                                           isDynamicBox,
+                                           legacySimulatorData->fplog,
+                                           legacySimulatorData->cr,
+                                           legacySimulatorData->inputrec,
+                                           legacySimulatorData->mdAtoms,
+                                           legacySimulatorData->nrnb,
+                                           legacySimulatorData->fr,
+                                           legacySimulatorData->wcycle,
+                                           legacySimulatorData->runScheduleWork,
+                                           legacySimulatorData->vsite,
+                                           legacySimulatorData->imdSession,
+                                           legacySimulatorData->pull_work,
+                                           legacySimulatorData->constr,
+                                           legacySimulatorData->top_global,
+                                           legacySimulatorData->enforcedRotation));
 }
 } // namespace gmx
index 0ee81e0430a0fa505d2a3896e1f9d96644ded86f..27ba90a665d07590c3701ec5b17106d87923a8c1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,7 @@
 
 #include "gromacs/domdec/dlbtiming.h"
 #include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/real.h"
 
 #include "modularsimulatorinterfaces.h"
@@ -108,7 +109,7 @@ public:
                  ImdSession*                 imdSession,
                  pull_t*                     pull_work,
                  Constraints*                constr,
-                 const gmx_mtop_t*           globalTopology,
+                 const gmx_mtop_t&           globalTopology,
                  gmx_enfrot*                 enforcedRotation);
 
     /*! \brief Register force calculation for step / time
@@ -193,7 +194,7 @@ private:
      * Used if FEP is off, since do_force
      * requires lambda to be allocated anyway
      */
-    std::array<real, efptNR> lambda_;
+    gmx::EnumerationArray<FreeEnergyPerturbationType, real> lambda_;
 
     // Access to ISimulator data
     //! Handles logging.
index 77037bf2426d667f2b3a26e265ab17a46a83d4e7..de8fbdc008645ccb8d1af46c501c9aed427533eb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 namespace gmx
 {
 
-FreeEnergyPerturbationData::FreeEnergyPerturbationData(FILE* fplog, const t_inputrec* inputrec, MDAtoms* mdAtoms) :
-    element_(std::make_unique<Element>(this, inputrec->fepvals->delta_lambda)),
+FreeEnergyPerturbationData::FreeEnergyPerturbationData(FILE* fplog, const t_inputrec& inputrec, MDAtoms* mdAtoms) :
+    element_(std::make_unique<Element>(this, inputrec.fepvals->delta_lambda)),
     lambda_(),
     currentFEPState_(0),
     fplog_(fplog),
     inputrec_(inputrec),
     mdAtoms_(mdAtoms)
 {
-    lambda_.fill(0);
+    std::fill(lambda_.begin(), lambda_.end(), 0);
     // The legacy implementation only filled the lambda vector in state_global, which is only
     // available on master. We have the lambda vector available everywhere, so we pass a `true`
     // for isMaster on all ranks. See #3647.
-    initialize_lambdas(fplog_, *inputrec_, true, &currentFEPState_, lambda_);
+    initialize_lambdas(fplog_,
+                       inputrec_.efep,
+                       inputrec_.bSimTemp,
+                       *inputrec_.fepvals,
+                       inputrec_.simtempvals->temperatures,
+                       gmx::arrayRefFromArray(inputrec_.opts.ref_t, inputrec_.opts.ngtc),
+                       true,
+                       &currentFEPState_,
+                       lambda_);
 }
 
 void FreeEnergyPerturbationData::Element::scheduleTask(Step step,
@@ -88,7 +96,7 @@ void FreeEnergyPerturbationData::Element::scheduleTask(Step step,
 void FreeEnergyPerturbationData::updateLambdas(Step step)
 {
     // at beginning of step (if lambdas change...)
-    lambda_ = currentLambdas(step, *(inputrec_->fepvals), currentFEPState_);
+    lambda_ = currentLambdas(step, *(inputrec_.fepvals), currentFEPState_);
     updateMDAtoms();
 }
 
@@ -109,7 +117,7 @@ int FreeEnergyPerturbationData::currentFEPState()
 
 void FreeEnergyPerturbationData::updateMDAtoms()
 {
-    update_mdatoms(mdAtoms_->mdatoms(), lambda_[efptMASS]);
+    update_mdatoms(mdAtoms_->mdatoms(), lambda_[FreeEnergyPerturbationCouplingType::Mass]);
 }
 
 namespace
@@ -158,7 +166,8 @@ void FreeEnergyPerturbationData::Element::restoreCheckpointState(std::optional<R
     if (DOMAINDECOMP(cr))
     {
         dd_bcast(cr->dd, sizeof(int), &freeEnergyPerturbationData_->currentFEPState_);
-        dd_bcast(cr->dd, ssize(freeEnergyPerturbationData_->lambda_) * int(sizeof(real)),
+        dd_bcast(cr->dd,
+                 ssize(freeEnergyPerturbationData_->lambda_) * int(sizeof(real)),
                  freeEnergyPerturbationData_->lambda_.data());
     }
 }
@@ -201,9 +210,9 @@ void FreeEnergyPerturbationData::readCheckpointToTrxFrame(t_trxframe* trxFrame,
 {
     if (readCheckpointData)
     {
-        FreeEnergyPerturbationData freeEnergyPerturbationData;
+        FreeEnergyPerturbationData freeEnergyPerturbationData(nullptr, t_inputrec(), nullptr);
         freeEnergyPerturbationData.doCheckpointData(&readCheckpointData.value());
-        trxFrame->lambda    = freeEnergyPerturbationData.lambda_[efptFEP];
+        trxFrame->lambda = freeEnergyPerturbationData.lambda_[FreeEnergyPerturbationCouplingType::Fep];
         trxFrame->fep_state = freeEnergyPerturbationData.currentFEPState_;
     }
     else
index 25c2a52916e6bfaa2b6430ccfa5205fdd10d1515..98d9cfc80e5155a170783d0bf01288dfb9e583b7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/mdtypes/md_enums.h"
 #include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/real.h"
 
 #include "modularsimulatorinterfaces.h"
@@ -76,7 +77,7 @@ class FreeEnergyPerturbationData final
 {
 public:
     //! Constructor
-    FreeEnergyPerturbationData(FILE* fplog, const t_inputrec* inputrec, MDAtoms* mdAtoms);
+    FreeEnergyPerturbationData(FILE* fplog, const t_inputrec& inputrec, MDAtoms* mdAtoms);
 
     //! Get a view of the current lambda vector
     ArrayRef<real> lambdaView();
@@ -99,8 +100,6 @@ public:
     static const std::string& checkpointID();
 
 private:
-    //! Default constructor - only used internally
-    FreeEnergyPerturbationData() = default;
     //! Update the lambda values
     void updateLambdas(Step step);
     //! Helper function to read from / write to CheckpointData
@@ -111,14 +110,14 @@ private:
     std::unique_ptr<Element> element_;
 
     //! The lambda vector
-    std::array<real, efptNR> lambda_;
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> lambda_;
     //! The current free energy state
     int currentFEPState_;
 
     //! Handles logging.
     FILE* fplog_;
     //! Contains user input mdp options.
-    const t_inputrec* inputrec_;
+    const t_inputrec& inputrec_;
     //! Atom parameters for this domain.
     MDAtoms* mdAtoms_;
 };
index e2c7c8ac6dd96c5ecd7348b2efc9e36426c2df8c..2431e18aa2e759101ada4a27a1c968354bfe00b2 100644 (file)
@@ -106,68 +106,71 @@ void ModularSimulator::run()
 
 void ModularSimulator::addIntegrationElements(ModularSimulatorAlgorithmBuilder* builder)
 {
-    if (legacySimulatorData_->inputrec->eI == eiMD)
+    if (legacySimulatorData_->inputrec->eI == IntegrationAlgorithm::MD)
     {
         // The leap frog integration algorithm
         builder->add<ForceElement>();
         builder->add<StatePropagatorData::Element>();
-        if (legacySimulatorData_->inputrec->etc == etcVRESCALE
-            || legacySimulatorData_->inputrec->etc == etcBERENDSEN)
+        if (legacySimulatorData_->inputrec->etc == TemperatureCoupling::VRescale
+            || legacySimulatorData_->inputrec->etc == TemperatureCoupling::Berendsen
+            || legacySimulatorData_->inputrec->etc == TemperatureCoupling::NoseHoover)
         {
-            builder->add<VelocityScalingTemperatureCoupling>(-1, UseFullStepKE::No,
-                                                             ReportPreviousStepConservedEnergy::No);
+            builder->add<VelocityScalingTemperatureCoupling>(Offset(-1),
+                                                             UseFullStepKE::No,
+                                                             ReportPreviousStepConservedEnergy::No,
+                                                             PropagatorTag("LeapFrogPropagator"));
         }
-        builder->add<Propagator<IntegrationStep::LeapFrog>>(legacySimulatorData_->inputrec->delta_t,
-                                                            RegisterWithThermostat::True,
-                                                            RegisterWithBarostat::True);
+        builder->add<Propagator<IntegrationStage::LeapFrog>>(
+                PropagatorTag("LeapFrogPropagator"), TimeStep(legacySimulatorData_->inputrec->delta_t));
         if (legacySimulatorData_->constr)
         {
             builder->add<ConstraintsElement<ConstraintVariable::Positions>>();
         }
         builder->add<ComputeGlobalsElement<ComputeGlobalsAlgorithm::LeapFrog>>();
-        builder->add<EnergyData::Element>();
-        if (legacySimulatorData_->inputrec->epc == epcPARRINELLORAHMAN)
+        if (legacySimulatorData_->inputrec->epc == PressureCoupling::ParrinelloRahman)
         {
-            builder->add<ParrinelloRahmanBarostat>(-1);
+            builder->add<ParrinelloRahmanBarostat>(Offset(-1), PropagatorTag("LeapFrogPropagator"));
         }
     }
-    else if (legacySimulatorData_->inputrec->eI == eiVV)
+    else if (legacySimulatorData_->inputrec->eI == IntegrationAlgorithm::VV)
     {
         // The velocity verlet integration algorithm
         builder->add<ForceElement>();
-        builder->add<Propagator<IntegrationStep::VelocitiesOnly>>(
-                0.5 * legacySimulatorData_->inputrec->delta_t, RegisterWithThermostat::False,
-                RegisterWithBarostat::True);
+        builder->add<Propagator<IntegrationStage::VelocitiesOnly>>(
+                PropagatorTag("VelocityHalfStep"), TimeStep(0.5 * legacySimulatorData_->inputrec->delta_t));
         if (legacySimulatorData_->constr)
         {
             builder->add<ConstraintsElement<ConstraintVariable::Velocities>>();
         }
         builder->add<ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerlet>>();
         builder->add<StatePropagatorData::Element>();
-        if (legacySimulatorData_->inputrec->etc == etcVRESCALE
-            || legacySimulatorData_->inputrec->etc == etcBERENDSEN)
+        if (legacySimulatorData_->inputrec->etc == TemperatureCoupling::VRescale
+            || legacySimulatorData_->inputrec->etc == TemperatureCoupling::Berendsen)
         {
             builder->add<VelocityScalingTemperatureCoupling>(
-                    0, UseFullStepKE::Yes, ReportPreviousStepConservedEnergy::Yes);
+                    Offset(0),
+                    UseFullStepKE::Yes,
+                    ReportPreviousStepConservedEnergy::Yes,
+                    PropagatorTag("VelocityHalfAndPositionFullStep"));
         }
-        builder->add<Propagator<IntegrationStep::VelocityVerletPositionsAndVelocities>>(
-                legacySimulatorData_->inputrec->delta_t, RegisterWithThermostat::True,
-                RegisterWithBarostat::False);
+        builder->add<Propagator<IntegrationStage::VelocityVerletPositionsAndVelocities>>(
+                PropagatorTag("VelocityHalfAndPositionFullStep"),
+                TimeStep(legacySimulatorData_->inputrec->delta_t));
         if (legacySimulatorData_->constr)
         {
             builder->add<ConstraintsElement<ConstraintVariable::Positions>>();
         }
         builder->add<ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerlet>>();
-        builder->add<EnergyData::Element>();
-        if (legacySimulatorData_->inputrec->epc == epcPARRINELLORAHMAN)
+        if (legacySimulatorData_->inputrec->epc == PressureCoupling::ParrinelloRahman)
         {
-            builder->add<ParrinelloRahmanBarostat>(-1);
+            builder->add<ParrinelloRahmanBarostat>(Offset(-1), PropagatorTag("VelocityHalfStep"));
         }
     }
     else
     {
         gmx_fatal(FARGS, "Integrator not implemented for the modular simulator.");
     }
+    builder->add<EnergyData::Element>();
 }
 
 bool ModularSimulator::isInputCompatible(bool                             exitOnFailure,
@@ -203,57 +206,61 @@ bool ModularSimulator::isInputCompatible(bool                             exitOn
             "or unset both to recover default behavior.");
 
     GMX_RELEASE_ASSERT(
-            !(modularSimulatorExplicitlyTurnedOff && inputrec->eI == eiVV
-              && inputrec->epc == epcPARRINELLORAHMAN),
+            !(modularSimulatorExplicitlyTurnedOff && inputrec->eI == IntegrationAlgorithm::VV
+              && inputrec->epc == PressureCoupling::ParrinelloRahman),
             "Cannot use a Parrinello-Rahman barostat with md-vv and "
             "GMX_DISABLE_MODULAR_SIMULATOR=ON, "
             "as the Parrinello-Rahman barostat is not implemented in the legacy simulator. Unset "
             "GMX_DISABLE_MODULAR_SIMULATOR or use a different pressure control algorithm.");
 
     bool isInputCompatible = conditionalAssert(
-            inputrec->eI == eiMD || inputrec->eI == eiVV,
+            inputrec->eI == IntegrationAlgorithm::MD || inputrec->eI == IntegrationAlgorithm::VV,
             "Only integrators md and md-vv are supported by the modular simulator.");
     isInputCompatible = isInputCompatible
-                        && conditionalAssert(inputrec->eI != eiMD || modularSimulatorExplicitlyTurnedOn,
+                        && conditionalAssert(inputrec->eI != IntegrationAlgorithm::MD
+                                                     || modularSimulatorExplicitlyTurnedOn,
                                              "Set GMX_USE_MODULAR_SIMULATOR=ON to use the modular "
                                              "simulator with integrator md.");
     isInputCompatible =
             isInputCompatible
             && conditionalAssert(
-                       !inputrec->useMts,
-                       "Multiple time stepping is not supported by the modular simulator.");
+                    !inputrec->useMts,
+                    "Multiple time stepping is not supported by the modular simulator.");
     isInputCompatible =
             isInputCompatible
             && conditionalAssert(!doRerun, "Rerun is not supported by the modular simulator.");
     isInputCompatible = isInputCompatible
-                        && conditionalAssert(inputrec->etc == etcNO || inputrec->etc == etcVRESCALE
-                                                     || inputrec->etc == etcBERENDSEN,
-                                             "Only v-rescale and Berendsen thermostat are "
-                                             "supported by the modular simulator.");
+                        && conditionalAssert(inputrec->etc == TemperatureCoupling::No
+                                                     || inputrec->etc == TemperatureCoupling::VRescale
+                                                     || inputrec->etc == TemperatureCoupling::Berendsen
+                                                     || (inputrec->etc == TemperatureCoupling::NoseHoover
+                                                         && inputrec->eI == IntegrationAlgorithm::MD),
+                                             "Only v-rescale, Berendsen and Nose-Hoover "
+                                             "thermostats are supported by the modular simulator.");
     isInputCompatible =
             isInputCompatible
             && conditionalAssert(
-                       inputrec->epc == epcNO || inputrec->epc == epcPARRINELLORAHMAN,
-                       "Only Parrinello-Rahman barostat is supported by the modular simulator.");
+                    inputrec->epc == PressureCoupling::No || inputrec->epc == PressureCoupling::ParrinelloRahman,
+                    "Only Parrinello-Rahman barostat is supported by the modular simulator.");
     isInputCompatible =
             isInputCompatible
             && conditionalAssert(
-                       !(inputrecNptTrotter(inputrec) || inputrecNphTrotter(inputrec)
-                         || inputrecNvtTrotter(inputrec)),
-                       "Legacy Trotter decomposition is not supported by the modular simulator.");
-    isInputCompatible = isInputCompatible
-                        && conditionalAssert(inputrec->efep == efepNO || inputrec->efep == efepYES
-                                                     || inputrec->efep == efepSLOWGROWTH,
-                                             "Expanded ensemble free energy calculation is not "
-                                             "supported by the modular simulator.");
+                    !(inputrecNptTrotter(inputrec) || inputrecNphTrotter(inputrec)
+                      || inputrecNvtTrotter(inputrec)),
+                    "Legacy Trotter decomposition is not supported by the modular simulator.");
+    isInputCompatible =
+            isInputCompatible
+            && conditionalAssert(inputrec->efep == FreeEnergyPerturbationType::No
+                                         || inputrec->efep == FreeEnergyPerturbationType::Yes
+                                         || inputrec->efep == FreeEnergyPerturbationType::SlowGrowth,
+                                 "Expanded ensemble free energy calculation is not "
+                                 "supported by the modular simulator.");
     isInputCompatible = isInputCompatible
                         && conditionalAssert(!inputrec->bPull,
                                              "Pulling is not supported by the modular simulator.");
     isInputCompatible =
             isInputCompatible
-            && conditionalAssert(inputrec->opts.ngacc == 1 && inputrec->opts.acc[0][XX] == 0.0
-                                         && inputrec->opts.acc[0][YY] == 0.0
-                                         && inputrec->opts.acc[0][ZZ] == 0.0 && inputrec->cos_accel == 0.0,
+            && conditionalAssert(inputrec->cos_accel == 0.0,
                                  "Acceleration is not supported by the modular simulator.");
     isInputCompatible =
             isInputCompatible
@@ -262,12 +269,12 @@ bool ModularSimulator::isInputCompatible(bool                             exitOn
     isInputCompatible =
             isInputCompatible
             && conditionalAssert(
-                       inputrec->deform[XX][XX] == 0.0 && inputrec->deform[XX][YY] == 0.0
-                               && inputrec->deform[XX][ZZ] == 0.0 && inputrec->deform[YY][XX] == 0.0
-                               && inputrec->deform[YY][YY] == 0.0 && inputrec->deform[YY][ZZ] == 0.0
-                               && inputrec->deform[ZZ][XX] == 0.0 && inputrec->deform[ZZ][YY] == 0.0
-                               && inputrec->deform[ZZ][ZZ] == 0.0,
-                       "Deformation is not supported by the modular simulator.");
+                    inputrec->deform[XX][XX] == 0.0 && inputrec->deform[XX][YY] == 0.0
+                            && inputrec->deform[XX][ZZ] == 0.0 && inputrec->deform[YY][XX] == 0.0
+                            && inputrec->deform[YY][YY] == 0.0 && inputrec->deform[YY][ZZ] == 0.0
+                            && inputrec->deform[ZZ][XX] == 0.0 && inputrec->deform[ZZ][YY] == 0.0
+                            && inputrec->deform[ZZ][ZZ] == 0.0,
+                    "Deformation is not supported by the modular simulator.");
     isInputCompatible =
             isInputCompatible
             && conditionalAssert(gmx_mtop_interaction_count(globalTopology, IF_VSITE) == 0,
@@ -282,8 +289,8 @@ bool ModularSimulator::isInputCompatible(bool                             exitOn
     isInputCompatible =
             isInputCompatible
             && conditionalAssert(
-                       gmx_mtop_ftype_count(globalTopology, F_ORIRES) == 0,
-                       "Orientation restraints are not supported by the modular simulator.");
+                    gmx_mtop_ftype_count(globalTopology, F_ORIRES) == 0,
+                    "Orientation restraints are not supported by the modular simulator.");
     isInputCompatible =
             isInputCompatible
             && conditionalAssert(ms == nullptr,
@@ -300,7 +307,7 @@ bool ModularSimulator::isInputCompatible(bool                             exitOn
     }
     else
     {
-        auto distantRestraintEnsembleEnvVar = getenv("GMX_DISRE_ENSEMBLE_SIZE");
+        auto* distantRestraintEnsembleEnvVar = getenv("GMX_DISRE_ENSEMBLE_SIZE");
         numEnsembleRestraintSystems =
                 (ms != nullptr && distantRestraintEnsembleEnvVar != nullptr)
                         ? static_cast<int>(strtol(distantRestraintEnsembleEnvVar, nullptr, 10))
@@ -327,7 +334,7 @@ bool ModularSimulator::isInputCompatible(bool                             exitOn
             && conditionalAssert(!doEssentialDynamics,
                                  "Essential dynamics is not supported by the modular simulator.");
     isInputCompatible = isInputCompatible
-                        && conditionalAssert(inputrec->eSwapCoords == eswapNO,
+                        && conditionalAssert(inputrec->eSwapCoords == SwapType::No,
                                              "Ion / water position swapping is not supported by "
                                              "the modular simulator.");
     isInputCompatible =
@@ -342,8 +349,8 @@ bool ModularSimulator::isInputCompatible(bool                             exitOn
     isInputCompatible =
             isInputCompatible
             && conditionalAssert(
-                       getenv("GMX_FORCE_UPDATE_DEFAULT_GPU") == nullptr,
-                       "Integration on the GPU is not supported by the modular simulator.");
+                    getenv("GMX_FORCE_UPDATE_DEFAULT_GPU") == nullptr,
+                    "Integration on the GPU is not supported by the modular simulator.");
     // Modular simulator is centered around NS updates
     // TODO: think how to handle nstlist == 0
     isInputCompatible = isInputCompatible
@@ -353,7 +360,8 @@ bool ModularSimulator::isInputCompatible(bool                             exitOn
     isInputCompatible = isInputCompatible
                         && conditionalAssert(!GMX_FAHCORE,
                                              "GMX_FAHCORE not supported by the modular simulator.");
-    if (!isInputCompatible && (inputrec->eI == eiVV && inputrec->epc == epcPARRINELLORAHMAN))
+    if (!isInputCompatible
+        && (inputrec->eI == IntegrationAlgorithm::VV && inputrec->epc == PressureCoupling::ParrinelloRahman))
     {
         gmx_fatal(FARGS,
                   "Requested Parrinello-Rahman barostat with md-vv. This combination is only "
@@ -361,7 +369,6 @@ bool ModularSimulator::isInputCompatible(bool                             exitOn
                   "only available in the legacy simulator. Use a different pressure control "
                   "algorithm.");
     }
-
     return isInputCompatible;
 }
 
@@ -375,9 +382,13 @@ ModularSimulator::ModularSimulator(std::unique_ptr<LegacySimulatorData>      leg
 
 void ModularSimulator::checkInputForDisabledFunctionality()
 {
-    isInputCompatible(true, legacySimulatorData_->inputrec, legacySimulatorData_->mdrunOptions.rerun,
-                      *legacySimulatorData_->top_global, legacySimulatorData_->ms,
-                      legacySimulatorData_->replExParams, legacySimulatorData_->fr->fcdata.get(),
+    isInputCompatible(true,
+                      legacySimulatorData_->inputrec,
+                      legacySimulatorData_->mdrunOptions.rerun,
+                      legacySimulatorData_->top_global,
+                      legacySimulatorData_->ms,
+                      legacySimulatorData_->replExParams,
+                      legacySimulatorData_->fr->fcdata.get(),
                       opt2bSet("-ei", legacySimulatorData_->nfile, legacySimulatorData_->fnm),
                       legacySimulatorData_->membed != nullptr);
     if (legacySimulatorData_->observablesHistory->edsamHistory)
@@ -397,8 +408,7 @@ void ModularSimulator::readCheckpointToTrxFrame(t_trxframe*               fr,
                        "ModularSimulator::readCheckpointToTrxFrame can only read checkpoints "
                        "written by modular simulator.");
     fr->bStep = true;
-    fr->step =
-            int64_to_int(checkpointHeaderContents.step, "conversion of checkpoint to trajectory");
+    fr->step = int64_to_int(checkpointHeaderContents.step, "conversion of checkpoint to trajectory");
     fr->bTime = true;
     fr->time  = checkpointHeaderContents.t;
 
index 0ed26a68fbad13478689d7c650a75d439f9b2a14..3dcbb6b03a2ec27c2962087699de1d62431a6301 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,14 @@ namespace gmx
 {
 template<typename T>
 class ArrayRef;
-template<class Signaller>
-class SignallerBuilder;
-class NeighborSearchSignaller;
+class EnergySignaller;
 class LastStepSignaller;
 class LoggingSignaller;
+class NeighborSearchSignaller;
+enum class ScaleVelocities;
+template<class Signaller>
+class SignallerBuilder;
 class TrajectorySignaller;
-class EnergySignaller;
 
 //! \addtogroup module_modularsimulator
 //! \{
@@ -455,26 +456,100 @@ enum class ModularSimulatorBuilderState
 typedef std::function<void(Step)> PropagatorCallback;
 
 /*! \internal
- * \brief Information needed to connect a propagator to a thermostat
+ * \brief Strong type used to name propagators
  */
-struct PropagatorThermostatConnection
+struct PropagatorTag
 {
-    //! Function variable for setting velocity scaling variables.
-    std::function<void(int)> setNumVelocityScalingVariables;
-    //! Function variable for receiving view on velocity scaling.
-    std::function<ArrayRef<real>()> getViewOnVelocityScaling;
-    //! Function variable for callback.
-    std::function<PropagatorCallback()> getVelocityScalingCallback;
+    //! Explicit constructor
+    explicit PropagatorTag(std::string_view name) : name_(name) {}
+    //! Can be used as string
+    operator const std::string&() const { return name_; }
+    //! Equality operator
+    bool operator==(const PropagatorTag& other) const { return name_ == other.name_; }
+    //! Inequality operator
+    bool operator!=(const PropagatorTag& other) const { return name_ != other.name_; }
+
+private:
+    //! The name of the propagator
+    const std::string name_;
+};
+
+/*! \internal
+ * \brief Strong type used to denote propagation time steps
+ */
+struct TimeStep
+{
+    //! Explicit constructor
+    explicit TimeStep(real timeStep) : timeStep_(timeStep) {}
+    //! Can be used as underlying type
+    operator const real&() const { return timeStep_; }
+
+private:
+    //! The time step
+    real timeStep_;
+};
+
+/*! \internal
+ * \brief Strong type used to denote scheduling offsets
+ */
+struct Offset
+{
+    //! Explicit constructor
+    explicit Offset(int offset) : offset_(offset) {}
+    //! Can be used as underlying type
+    operator const int&() const { return offset_; }
+
+private:
+    //! The offset
+    int offset_;
 };
 
 /*! \internal
- * \brief Information needed to connect a propagator to a barostat
+ * \brief Information needed to connect a propagator to a temperature and / or pressure coupling element
  */
-struct PropagatorBarostatConnection
+struct PropagatorConnection
 {
-    //! Function variable for receiving view on pressure scaling matrix.
+    //! The tag of the creating propagator
+    PropagatorTag tag;
+
+    //! Whether the propagator offers start velocity scaling
+    bool hasStartVelocityScaling() const
+    {
+        return setNumVelocityScalingVariables && getVelocityScalingCallback && getViewOnStartVelocityScaling;
+    }
+    //! Whether the propagator offers end velocity scaling
+    bool hasEndVelocityScaling() const
+    {
+        return setNumVelocityScalingVariables && getVelocityScalingCallback && getViewOnEndVelocityScaling;
+    }
+    //! Whether the propagator offers position scaling
+    bool hasPositionScaling() const
+    {
+        return setNumPositionScalingVariables && getPositionScalingCallback && getViewOnPositionScaling;
+    }
+    //! Whether the propagator offers Parrinello-Rahman scaling
+    bool hasParrinelloRahmanScaling() const
+    {
+        return getPRScalingCallback && getViewOnPRScalingMatrix;
+    }
+
+    //! Function object for setting velocity scaling variables
+    std::function<void(int, ScaleVelocities)> setNumVelocityScalingVariables;
+    //! Function object for setting velocity scaling variables
+    std::function<void(int)> setNumPositionScalingVariables;
+    //! Function object for receiving view on velocity scaling (before step)
+    std::function<ArrayRef<real>()> getViewOnStartVelocityScaling;
+    //! Function object for receiving view on velocity scaling (after step)
+    std::function<ArrayRef<real>()> getViewOnEndVelocityScaling;
+    //! Function object for receiving view on position scaling
+    std::function<ArrayRef<real>()> getViewOnPositionScaling;
+    //! Function object to request callback allowing to signal a velocity scaling step
+    std::function<PropagatorCallback()> getVelocityScalingCallback;
+    //! Function object to request callback allowing to signal a position scaling step
+    std::function<PropagatorCallback()> getPositionScalingCallback;
+    //! Function object for receiving view on pressure scaling matrix
     std::function<ArrayRef<rvec>()> getViewOnPRScalingMatrix;
-    //! Function variable for callback.
+    //! Function object to request callback allowing to signal a Parrinello-Rahman scaling step
     std::function<PropagatorCallback()> getPRScalingCallback;
 };
 
index 7bf5c7fe999c4a2d43ac0652184097cfeaa9ba67..b06b8744dc1af25c251c38dd80c737ede651dcfe 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,17 +81,29 @@ ParrinelloRahmanBarostat::ParrinelloRahmanBarostat(int                  nstpcoup
     boxVelocity_{ { 0 } },
     statePropagatorData_(statePropagatorData),
     energyData_(energyData),
+    nextEnergyCalculationStep_(-1),
     fplog_(fplog),
     inputrec_(inputrec),
     mdAtoms_(mdAtoms)
 {
-    energyData->setParrinelloRahamnBarostat(this);
+    energyData->setParrinelloRahmanBoxVelocities([this]() { return boxVelocity_; });
+    energyData->addConservedEnergyContribution([this](Step gmx_used_in_debug step, Time /*unused*/) {
+        GMX_ASSERT(conservedEnergyContributionStep_ == step,
+                   "Parrinello-Rahman conserved energy step mismatch.");
+        return conservedEnergyContribution_;
+    });
 }
 
-void ParrinelloRahmanBarostat::connectWithPropagator(const PropagatorBarostatConnection& connectionData)
+void ParrinelloRahmanBarostat::connectWithMatchingPropagator(const PropagatorConnection& connectionData,
+                                                             const PropagatorTag& propagatorTag)
 {
-    scalingTensor_      = connectionData.getViewOnPRScalingMatrix();
-    propagatorCallback_ = connectionData.getPRScalingCallback();
+    if (connectionData.tag == propagatorTag)
+    {
+        GMX_RELEASE_ASSERT(connectionData.hasParrinelloRahmanScaling(),
+                           "Connection data lacks Parrinello-Rahman scaling");
+        scalingTensor_      = connectionData.getViewOnPRScalingMatrix();
+        propagatorCallback_ = connectionData.getPRScalingCallback();
+    }
 }
 
 void ParrinelloRahmanBarostat::scheduleTask(Step step,
@@ -100,7 +112,16 @@ void ParrinelloRahmanBarostat::scheduleTask(Step step,
 {
     const bool scaleOnNextStep = do_per_step(step + nstpcouple_ + offset_ + 1, nstpcouple_);
     const bool scaleOnThisStep = do_per_step(step + nstpcouple_ + offset_, nstpcouple_);
+    const bool contributeEnergyThisStep = (step == nextEnergyCalculationStep_);
 
+    if (contributeEnergyThisStep)
+    {
+        // For compatibility with legacy md, we store this before integrating the box velocities
+        registerRunFunction([this, step]() {
+            conservedEnergyContribution_     = conservedEnergyContribution();
+            conservedEnergyContributionStep_ = step;
+        });
+    }
     if (scaleOnThisStep)
     {
         registerRunFunction([this]() { scaleBoxAndPositions(); });
@@ -116,8 +137,17 @@ void ParrinelloRahmanBarostat::scheduleTask(Step step,
 void ParrinelloRahmanBarostat::integrateBoxVelocityEquations(Step step)
 {
     auto box = statePropagatorData_->constBox();
-    parrinellorahman_pcoupl(fplog_, step, inputrec_, couplingTimeStep_, energyData_->pressure(step),
-                            box, boxRel_, boxVelocity_, scalingTensor_.data(), mu_, false);
+    parrinellorahman_pcoupl(fplog_,
+                            step,
+                            inputrec_,
+                            couplingTimeStep_,
+                            energyData_->pressure(step),
+                            box,
+                            boxRel_,
+                            boxVelocity_,
+                            scalingTensor_.data(),
+                            mu_,
+                            false);
     // multiply matrix by the coupling time step to avoid having the propagator needing to know about that
     msmul(scalingTensor_.data(), couplingTimeStep_, scalingTensor_.data());
 }
@@ -152,14 +182,15 @@ void ParrinelloRahmanBarostat::elementSetup()
         throw MissingElementConnectionError(
                 "Parrinello-Rahman barostat was not connected to a propagator.\n"
                 "Connection to a propagator element is needed to scale the velocities.\n"
-                "Use connectWithPropagator(...) before building the ModularSimulatorAlgorithm "
+                "Use connectWithMatchingPropagator(...) before building the "
+                "ModularSimulatorAlgorithm "
                 "object.");
     }
 
     if (inputrecPreserveShape(inputrec_))
     {
         auto      box  = statePropagatorData_->box();
-        const int ndim = inputrec_->epct == epctSEMIISOTROPIC ? 2 : 3;
+        const int ndim = inputrec_->epct == PressureCouplingType::SemiIsotropic ? 2 : 3;
         do_box_rel(ndim, inputrec_->deform, boxRel_, box, true);
     }
 
@@ -175,8 +206,17 @@ void ParrinelloRahmanBarostat::elementSetup()
         // The call to parrinellorahman_pcoupl is using nullptr for fplog (since we don't expect any
         // output here) and for the pressure (since it might not be calculated yet, and we don't need it).
         auto box = statePropagatorData_->constBox();
-        parrinellorahman_pcoupl(nullptr, initStep_, inputrec_, couplingTimeStep_, nullptr, box,
-                                boxRel_, boxVelocity_, scalingTensor_.data(), mu_, true);
+        parrinellorahman_pcoupl(nullptr,
+                                initStep_,
+                                inputrec_,
+                                couplingTimeStep_,
+                                nullptr,
+                                box,
+                                boxRel_,
+                                boxVelocity_,
+                                scalingTensor_.data(),
+                                mu_,
+                                true);
         // multiply matrix by the coupling time step to avoid having the propagator needing to know about that
         msmul(scalingTensor_.data(), couplingTimeStep_, scalingTensor_.data());
 
@@ -201,7 +241,7 @@ real ParrinelloRahmanBarostat::conservedEnergyContribution() const
     {
         for (int j = 0; j <= i; j++)
         {
-            real invMass = PRESFAC * (4 * M_PI * M_PI * inputrec_->compress[i][j])
+            real invMass = c_presfac * (4 * M_PI * M_PI * inputrec_->compress[i][j])
                            / (3 * inputrec_->tau_p * inputrec_->tau_p * maxBoxLength);
             if (invMass > 0)
             {
@@ -217,7 +257,7 @@ real ParrinelloRahmanBarostat::conservedEnergyContribution() const
      * track of unwrapped box diagonal elements. This case is
      * excluded in integratorHasConservedEnergyQuantity().
      */
-    energy += volume * trace(inputrec_->ref_p) / (DIM * PRESFAC);
+    energy += volume * trace(inputrec_->ref_p) / (DIM * c_presfac);
 
     return energy;
 }
@@ -275,6 +315,15 @@ const std::string& ParrinelloRahmanBarostat::clientID()
     return identifier_;
 }
 
+std::optional<SignallerCallback> ParrinelloRahmanBarostat::registerEnergyCallback(EnergySignallerEvent event)
+{
+    if (event == EnergySignallerEvent::EnergyCalculationStep)
+    {
+        return [this](Step step, Time /*unused*/) { nextEnergyCalculationStep_ = step; };
+    }
+    return std::nullopt;
+}
+
 ISimulatorElement* ParrinelloRahmanBarostat::getElementPointerImpl(
         LegacySimulatorData*                    legacySimulatorData,
         ModularSimulatorAlgorithmBuilderHelper* builderHelper,
@@ -282,17 +331,24 @@ ISimulatorElement* ParrinelloRahmanBarostat::getElementPointerImpl(
         EnergyData*                             energyData,
         FreeEnergyPerturbationData gmx_unused* freeEnergyPerturbationData,
         GlobalCommunicationHelper gmx_unused* globalCommunicationHelper,
-        int                                   offset)
+        Offset                                offset,
+        const PropagatorTag&                  propagatorTag)
 {
     auto* element  = builderHelper->storeElement(std::make_unique<ParrinelloRahmanBarostat>(
-            legacySimulatorData->inputrec->nstpcouple, offset,
+            legacySimulatorData->inputrec->nstpcouple,
+            offset,
             legacySimulatorData->inputrec->delta_t * legacySimulatorData->inputrec->nstpcouple,
-            legacySimulatorData->inputrec->init_step, statePropagatorData, energyData,
-            legacySimulatorData->fplog, legacySimulatorData->inputrec, legacySimulatorData->mdAtoms));
+            legacySimulatorData->inputrec->init_step,
+            statePropagatorData,
+            energyData,
+            legacySimulatorData->fplog,
+            legacySimulatorData->inputrec,
+            legacySimulatorData->mdAtoms));
     auto* barostat = static_cast<ParrinelloRahmanBarostat*>(element);
-    builderHelper->registerBarostat([barostat](const PropagatorBarostatConnection& connection) {
-        barostat->connectWithPropagator(connection);
-    });
+    builderHelper->registerTemperaturePressureControl(
+            [barostat, propagatorTag](const PropagatorConnection& connection) {
+                barostat->connectWithMatchingPropagator(connection, propagatorTag);
+            });
     return element;
 }
 
index 77ede5316557e06407ec222c53b6426d77e99aef..b49ba6de17e129bdd5199971780219ed2a9925fd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +70,7 @@ class StatePropagatorData;
  *     scaling factor, and
  *   * scales the box and the positions of the system.
  */
-class ParrinelloRahmanBarostat final : public ISimulatorElement, public ICheckpointHelperClient
+class ParrinelloRahmanBarostat final : public ISimulatorElement, public ICheckpointHelperClient, public IEnergySignallerClient
 {
 public:
     //! Constructor
@@ -99,11 +99,10 @@ public:
 
     //! Getter for the box velocities
     [[nodiscard]] const rvec* boxVelocities() const;
-    //! Contribution to the conserved energy (called by energy data)
-    [[nodiscard]] real conservedEnergyContribution() const;
 
     //! Connect this to propagator
-    void connectWithPropagator(const PropagatorBarostatConnection& connectionData);
+    void connectWithMatchingPropagator(const PropagatorConnection& connectionData,
+                                       const PropagatorTag&        propagatorTag);
 
     //! ICheckpointHelperClient write checkpoint implementation
     void saveCheckpointState(std::optional<WriteCheckpointData> checkpointData, const t_commrec* cr) override;
@@ -120,17 +119,20 @@ public:
      * \param energyData  Pointer to the \c EnergyData object
      * \param freeEnergyPerturbationData  Pointer to the \c FreeEnergyPerturbationData object
      * \param globalCommunicationHelper  Pointer to the \c GlobalCommunicationHelper object
+     * \param propagatorTag  Tag of the propagator to connect to
      * \param offset  The step offset at which the barostat is applied
      *
      * \return  Pointer to the element to be added. Element needs to have been stored using \c storeElement
      */
-    static ISimulatorElement* getElementPointerImpl(LegacySimulatorData* legacySimulatorData,
-                                                    ModularSimulatorAlgorithmBuilderHelper* builderHelper,
-                                                    StatePropagatorData*        statePropagatorData,
-                                                    EnergyData*                 energyData,
-                                                    FreeEnergyPerturbationData* freeEnergyPerturbationData,
-                                                    GlobalCommunicationHelper* globalCommunicationHelper,
-                                                    int                        offset);
+    static ISimulatorElement*
+    getElementPointerImpl(LegacySimulatorData*                    legacySimulatorData,
+                          ModularSimulatorAlgorithmBuilderHelper* builderHelper,
+                          StatePropagatorData*                    statePropagatorData,
+                          EnergyData*                             energyData,
+                          FreeEnergyPerturbationData gmx_unused* freeEnergyPerturbationData,
+                          GlobalCommunicationHelper gmx_unused* globalCommunicationHelper,
+                          Offset                                offset,
+                          const PropagatorTag&                  propagatorTag);
 
 private:
     //! The frequency at which the barostat is applied
@@ -154,6 +156,11 @@ private:
     //! Box velocity
     tensor boxVelocity_;
 
+    //! Current conserved energy contribution
+    real conservedEnergyContribution_;
+    //! Step of current conserved energy contribution
+    Step conservedEnergyContributionStep_;
+
     // TODO: Clarify relationship to data objects and find a more robust alternative to raw pointers (#3583)
     //! Pointer to the micro state
     StatePropagatorData* statePropagatorData_;
@@ -171,6 +178,14 @@ private:
     template<CheckpointDataOperation operation>
     void doCheckpointData(CheckpointData<operation>* checkpointData);
 
+    //! IEnergySignallerClient implementation
+    std::optional<SignallerCallback> registerEnergyCallback(EnergySignallerEvent event) override;
+    //! The next communicated energy calculation step
+    Step nextEnergyCalculationStep_;
+
+    //! Contribution to the conserved energy
+    [[nodiscard]] real conservedEnergyContribution() const;
+
     // Access to ISimulator data
     //! Handles logging.
     FILE* fplog_;
index a75ea901a6fb19271cf783e96c1618870a58cafd..e8be0aba8f930c472eafb6b3bfdd98ffc37af86a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ bool PmeLoadBalanceHelper::doPmeLoadBalancing(const MdrunOptions& mdrunOptions,
                                               const t_forcerec*   fr)
 {
     return (mdrunOptions.tunePme && EEL_PME(fr->ic->eeltype) && !mdrunOptions.reproducible
-            && inputrec->cutoff_scheme != ecutsGROUP);
+            && inputrec->cutoff_scheme != CutoffScheme::Group);
 }
 
 PmeLoadBalanceHelper::PmeLoadBalanceHelper(bool                 isVerbose,
@@ -91,8 +91,8 @@ void PmeLoadBalanceHelper::setup()
     auto box = statePropagatorData_->constBox();
     GMX_RELEASE_ASSERT(box[0][0] != 0 && box[1][1] != 0 && box[2][2] != 0,
                        "PmeLoadBalanceHelper cannot be initialized with zero box.");
-    pme_loadbal_init(&pme_loadbal_, cr_, mdlog_, *inputrec_, box, *fr_->ic, *fr_->nbv, fr_->pmedata,
-                     fr_->nbv->useGpu());
+    pme_loadbal_init(
+            &pme_loadbal_, cr_, mdlog_, *inputrec_, box, *fr_->ic, *fr_->nbv, fr_->pmedata, fr_->nbv->useGpu());
 }
 
 void PmeLoadBalanceHelper::run(gmx::Step step, gmx::Time gmx_unused time)
@@ -105,10 +105,20 @@ void PmeLoadBalanceHelper::run(gmx::Step step, gmx::Time gmx_unused time)
     // PME grid + cut-off optimization with GPUs or PME nodes
     // TODO pass SimulationWork object into this function, such that last argument can be set as
     // simulationWork.useGpuPmePpCommunication as is done in main MD loop.
-    pme_loadbal_do(pme_loadbal_, cr_, (isVerbose_ && MASTER(cr_)) ? stderr : nullptr, fplog_,
-                   mdlog_, *inputrec_, fr_, statePropagatorData_->constBox(),
-                   statePropagatorData_->constPositionsView().paddedArrayRef(), wcycle_, step,
-                   step - inputrec_->init_step, &bPMETunePrinting_, false);
+    pme_loadbal_do(pme_loadbal_,
+                   cr_,
+                   (isVerbose_ && MASTER(cr_)) ? stderr : nullptr,
+                   fplog_,
+                   mdlog_,
+                   *inputrec_,
+                   fr_,
+                   statePropagatorData_->constBox(),
+                   statePropagatorData_->constPositionsView().paddedArrayRef(),
+                   wcycle_,
+                   step,
+                   step - inputrec_->init_step,
+                   &bPMETunePrinting_,
+                   false);
 }
 
 void PmeLoadBalanceHelper::teardown()
index b40abb9b1e6e2dadf7780ded7e1c69f6fdcab835..0e56ed06608b66aee1cf4442d8d00c9903c0b157 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/timing/wallcycle.h"
-#include "gromacs/utility/fatalerror.h"
 
 #include "modularsimulator.h"
 #include "simulatoralgorithm.h"
 
 namespace gmx
 {
+namespace
+{
+// Names of integration steps, only used locally for error messages
+constexpr EnumerationArray<IntegrationStage, const char*> integrationStepNames = {
+    "IntegrationStage::PositionsOnly",   "IntegrationStage::VelocitiesOnly",
+    "IntegrationStage::LeapFrog",        "IntegrationStage::VelocityVerletPositionsAndVelocities",
+    "IntegrationStage::ScaleVelocities", "IntegrationStage::ScalePositions"
+};
+} // namespace
+
 //! Update velocities
-template<NumVelocityScalingValues numVelocityScalingValues, ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling>
+template<NumVelocityScalingValues        numStartVelocityScalingValues,
+         ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling,
+         NumVelocityScalingValues        numEndVelocityScalingValues>
 static void inline updateVelocities(int         a,
                                     real        dt,
-                                    real        lambda,
+                                    real        lambdaStart,
+                                    real        lambdaEnd,
                                     const rvec* gmx_restrict invMassPerDim,
                                     rvec* gmx_restrict v,
                                     const rvec* gmx_restrict f,
@@ -74,32 +86,36 @@ static void inline updateVelocities(int         a,
     for (int d = 0; d < DIM; d++)
     {
         // TODO: Extract this into policy classes
-        if (numVelocityScalingValues != NumVelocityScalingValues::None
+        if (numStartVelocityScalingValues != NumVelocityScalingValues::None
             && parrinelloRahmanVelocityScaling == ParrinelloRahmanVelocityScaling::No)
         {
-            v[a][d] *= lambda;
+            v[a][d] *= lambdaStart;
         }
-        if (numVelocityScalingValues != NumVelocityScalingValues::None
+        if (numStartVelocityScalingValues != NumVelocityScalingValues::None
             && parrinelloRahmanVelocityScaling == ParrinelloRahmanVelocityScaling::Diagonal)
         {
-            v[a][d] *= (lambda - diagPR[d]);
+            v[a][d] *= (lambdaStart - diagPR[d]);
         }
-        if (numVelocityScalingValues != NumVelocityScalingValues::None
+        if (numStartVelocityScalingValues != NumVelocityScalingValues::None
             && parrinelloRahmanVelocityScaling == ParrinelloRahmanVelocityScaling::Full)
         {
-            v[a][d] = lambda * v[a][d] - iprod(matrixPR[d], v[a]);
+            v[a][d] = lambdaStart * v[a][d] - iprod(matrixPR[d], v[a]);
         }
-        if (numVelocityScalingValues == NumVelocityScalingValues::None
+        if (numStartVelocityScalingValues == NumVelocityScalingValues::None
             && parrinelloRahmanVelocityScaling == ParrinelloRahmanVelocityScaling::Diagonal)
         {
             v[a][d] *= (1 - diagPR[d]);
         }
-        if (numVelocityScalingValues == NumVelocityScalingValues::None
+        if (numStartVelocityScalingValues == NumVelocityScalingValues::None
             && parrinelloRahmanVelocityScaling == ParrinelloRahmanVelocityScaling::Full)
         {
             v[a][d] -= iprod(matrixPR[d], v[a]);
         }
         v[a][d] += f[a][d] * invMassPerDim[a][d] * dt;
+        if (numEndVelocityScalingValues != NumVelocityScalingValues::None)
+        {
+            v[a][d] *= lambdaEnd;
+        }
     }
 }
 
@@ -116,6 +132,32 @@ static void inline updatePositions(int         a,
     }
 }
 
+//! Scale velocities
+template<NumVelocityScalingValues numStartVelocityScalingValues>
+static void inline scaleVelocities(int a, real lambda, rvec* gmx_restrict v)
+{
+    if (numStartVelocityScalingValues != NumVelocityScalingValues::None)
+    {
+        for (int d = 0; d < DIM; d++)
+        {
+            v[a][d] *= lambda;
+        }
+    }
+}
+
+//! Scale positions
+template<NumPositionScalingValues numPositionScalingValues>
+static void inline scalePositions(int a, real lambda, rvec* gmx_restrict x)
+{
+    if (numPositionScalingValues != NumPositionScalingValues::None)
+    {
+        for (int d = 0; d < DIM; d++)
+        {
+            x[a][d] *= lambda;
+        }
+    }
+}
+
 //! Helper function diagonalizing the PR matrix if possible
 template<ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling>
 static inline bool diagonalizePRMatrix(matrix matrixPR, rvec diagPR)
@@ -142,16 +184,19 @@ static inline bool diagonalizePRMatrix(matrix matrixPR, rvec diagPR)
 
 //! Propagation (position only)
 template<>
-template<NumVelocityScalingValues numVelocityScalingValues, ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling>
-void Propagator<IntegrationStep::PositionsOnly>::run()
+template<NumVelocityScalingValues        numStartVelocityScalingValues,
+         ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling,
+         NumVelocityScalingValues        numEndVelocityScalingValues,
+         NumPositionScalingValues        numPositionScalingValues>
+void Propagator<IntegrationStage::PositionsOnly>::run()
 {
-    wallcycle_start(wcycle_, ewcUPDATE);
+    wallcycle_start(wcycle_, WallCycleCounter::Update);
 
     auto xp = as_rvec_array(statePropagatorData_->positionsView().paddedArrayRef().data());
-    auto x = as_rvec_array(statePropagatorData_->constPreviousPositionsView().paddedArrayRef().data());
-    auto v = as_rvec_array(statePropagatorData_->constVelocitiesView().paddedArrayRef().data());
+    auto x  = as_rvec_array(statePropagatorData_->constPositionsView().paddedArrayRef().data());
+    auto v  = as_rvec_array(statePropagatorData_->constVelocitiesView().paddedArrayRef().data());
 
-    int nth    = gmx_omp_nthreads_get(emntUpdate);
+    int nth    = gmx_omp_nthreads_get(ModuleMultiThread::Update);
     int homenr = mdAtoms_->mdatoms()->homenr;
 
 #pragma omp parallel for num_threads(nth) schedule(static) default(none) shared(nth, homenr, x, xp, v)
@@ -169,33 +214,82 @@ void Propagator<IntegrationStep::PositionsOnly>::run()
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
     }
-    wallcycle_stop(wcycle_, ewcUPDATE);
+    wallcycle_stop(wcycle_, WallCycleCounter::Update);
+}
+
+//! Propagation (scale position only)
+template<>
+template<NumVelocityScalingValues        numStartVelocityScalingValues,
+         ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling,
+         NumVelocityScalingValues        numEndVelocityScalingValues,
+         NumPositionScalingValues        numPositionScalingValues>
+void Propagator<IntegrationStage::ScalePositions>::run()
+{
+    wallcycle_start(wcycle_, WallCycleCounter::Update);
+
+    auto* x = as_rvec_array(statePropagatorData_->positionsView().paddedArrayRef().data());
+
+    const real lambda =
+            (numPositionScalingValues == NumPositionScalingValues::Single) ? positionScaling_[0] : 1.0;
+
+    int nth    = gmx_omp_nthreads_get(ModuleMultiThread::Update);
+    int homenr = mdAtoms_->mdatoms()->homenr;
+
+#pragma omp parallel for num_threads(nth) schedule(static) default(none) shared(nth, homenr, x) \
+        firstprivate(lambda)
+    for (int th = 0; th < nth; th++)
+    {
+        try
+        {
+            int start_th, end_th;
+            getThreadAtomRange(nth, th, homenr, &start_th, &end_th);
+
+            for (int a = start_th; a < end_th; a++)
+            {
+                scalePositions<numPositionScalingValues>(
+                        a,
+                        (numPositionScalingValues == NumPositionScalingValues::Multiple)
+                                ? positionScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                : lambda,
+                        x);
+            }
+        }
+        GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
+    }
+    wallcycle_stop(wcycle_, WallCycleCounter::Update);
 }
 
 //! Propagation (velocity only)
 template<>
-template<NumVelocityScalingValues numVelocityScalingValues, ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling>
-void Propagator<IntegrationStep::VelocitiesOnly>::run()
+template<NumVelocityScalingValues        numStartVelocityScalingValues,
+         ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling,
+         NumVelocityScalingValues        numEndVelocityScalingValues,
+         NumPositionScalingValues        numPositionScalingValues>
+void Propagator<IntegrationStage::VelocitiesOnly>::run()
 {
-    wallcycle_start(wcycle_, ewcUPDATE);
+    wallcycle_start(wcycle_, WallCycleCounter::Update);
 
     auto v = as_rvec_array(statePropagatorData_->velocitiesView().paddedArrayRef().data());
     auto f = as_rvec_array(statePropagatorData_->constForcesView().force().data());
     auto invMassPerDim = mdAtoms_->mdatoms()->invMassPerDim;
 
-    const real lambda =
-            (numVelocityScalingValues == NumVelocityScalingValues::Single) ? velocityScaling_[0] : 1.0;
+    const real lambdaStart = (numStartVelocityScalingValues == NumVelocityScalingValues::Single)
+                                     ? startVelocityScaling_[0]
+                                     : 1.0;
+    const real lambdaEnd = (numEndVelocityScalingValues == NumVelocityScalingValues::Single)
+                                   ? endVelocityScaling_[0]
+                                   : 1.0;
 
     const bool isFullScalingMatrixDiagonal =
             diagonalizePRMatrix<parrinelloRahmanVelocityScaling>(matrixPR_, diagPR_);
 
-    const int nth    = gmx_omp_nthreads_get(emntUpdate);
+    const int nth    = gmx_omp_nthreads_get(ModuleMultiThread::Update);
     const int homenr = mdAtoms_->mdatoms()->homenr;
 
 // const variables could be shared, but gcc-8 & gcc-9 don't agree how to write that...
 // https://www.gnu.org/software/gcc/gcc-9/porting_to.html -> OpenMP data sharing
-#pragma omp parallel for num_threads(nth) schedule(static) default(none) \
-        shared(v, f, invMassPerDim) firstprivate(nth, homenr, lambda, isFullScalingMatrixDiagonal)
+#pragma omp parallel for num_threads(nth) schedule(static) default(none) shared(v, f, invMassPerDim) \
+        firstprivate(nth, homenr, lambdaStart, lambdaEnd, isFullScalingMatrixDiagonal)
     for (int th = 0; th < nth; th++)
     {
         try
@@ -207,55 +301,79 @@ void Propagator<IntegrationStep::VelocitiesOnly>::run()
             {
                 if (isFullScalingMatrixDiagonal)
                 {
-                    updateVelocities<numVelocityScalingValues, ParrinelloRahmanVelocityScaling::Diagonal>(
-                            a, timestep_,
-                            numVelocityScalingValues == NumVelocityScalingValues::Multiple
-                                    ? velocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
-                                    : lambda,
-                            invMassPerDim, v, f, diagPR_, matrixPR_);
+                    updateVelocities<numStartVelocityScalingValues, ParrinelloRahmanVelocityScaling::Diagonal, numEndVelocityScalingValues>(
+                            a,
+                            timestep_,
+                            numStartVelocityScalingValues == NumVelocityScalingValues::Multiple
+                                    ? startVelocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                    : lambdaStart,
+                            numEndVelocityScalingValues == NumVelocityScalingValues::Multiple
+                                    ? endVelocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                    : lambdaEnd,
+                            invMassPerDim,
+                            v,
+                            f,
+                            diagPR_,
+                            matrixPR_);
                 }
                 else
                 {
-                    updateVelocities<numVelocityScalingValues, parrinelloRahmanVelocityScaling>(
-                            a, timestep_,
-                            numVelocityScalingValues == NumVelocityScalingValues::Multiple
-                                    ? velocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
-                                    : lambda,
-                            invMassPerDim, v, f, diagPR_, matrixPR_);
+                    updateVelocities<numStartVelocityScalingValues, parrinelloRahmanVelocityScaling, numEndVelocityScalingValues>(
+                            a,
+                            timestep_,
+                            numStartVelocityScalingValues == NumVelocityScalingValues::Multiple
+                                    ? startVelocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                    : lambdaStart,
+                            numEndVelocityScalingValues == NumVelocityScalingValues::Multiple
+                                    ? endVelocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                    : lambdaEnd,
+                            invMassPerDim,
+                            v,
+                            f,
+                            diagPR_,
+                            matrixPR_);
                 }
             }
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
     }
-    wallcycle_stop(wcycle_, ewcUPDATE);
+    wallcycle_stop(wcycle_, WallCycleCounter::Update);
 }
 
 //! Propagation (leapfrog case - position and velocity)
 template<>
-template<NumVelocityScalingValues numVelocityScalingValues, ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling>
-void Propagator<IntegrationStep::LeapFrog>::run()
+template<NumVelocityScalingValues        numStartVelocityScalingValues,
+         ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling,
+         NumVelocityScalingValues        numEndVelocityScalingValues,
+         NumPositionScalingValues        numPositionScalingValues>
+void Propagator<IntegrationStage::LeapFrog>::run()
 {
-    wallcycle_start(wcycle_, ewcUPDATE);
+    wallcycle_start(wcycle_, WallCycleCounter::Update);
 
     auto xp = as_rvec_array(statePropagatorData_->positionsView().paddedArrayRef().data());
-    auto x = as_rvec_array(statePropagatorData_->constPreviousPositionsView().paddedArrayRef().data());
-    auto v = as_rvec_array(statePropagatorData_->velocitiesView().paddedArrayRef().data());
-    auto f = as_rvec_array(statePropagatorData_->constForcesView().force().data());
+    auto x  = as_rvec_array(statePropagatorData_->constPositionsView().paddedArrayRef().data());
+    auto v  = as_rvec_array(statePropagatorData_->velocitiesView().paddedArrayRef().data());
+    auto f  = as_rvec_array(statePropagatorData_->constForcesView().force().data());
     auto invMassPerDim = mdAtoms_->mdatoms()->invMassPerDim;
 
-    const real lambda =
-            (numVelocityScalingValues == NumVelocityScalingValues::Single) ? velocityScaling_[0] : 1.0;
+    const real lambdaStart = (numStartVelocityScalingValues == NumVelocityScalingValues::Single)
+                                     ? startVelocityScaling_[0]
+                                     : 1.0;
+    const real lambdaEnd = (numEndVelocityScalingValues == NumVelocityScalingValues::Single)
+                                   ? endVelocityScaling_[0]
+                                   : 1.0;
 
     const bool isFullScalingMatrixDiagonal =
             diagonalizePRMatrix<parrinelloRahmanVelocityScaling>(matrixPR_, diagPR_);
 
-    const int nth    = gmx_omp_nthreads_get(emntUpdate);
+    const int nth    = gmx_omp_nthreads_get(ModuleMultiThread::Update);
     const int homenr = mdAtoms_->mdatoms()->homenr;
 
 // const variables could be shared, but gcc-8 & gcc-9 don't agree how to write that...
 // https://www.gnu.org/software/gcc/gcc-9/porting_to.html -> OpenMP data sharing
-#pragma omp parallel for num_threads(nth) schedule(static) default(none) shared( \
-        x, xp, v, f, invMassPerDim) firstprivate(nth, homenr, lambda, isFullScalingMatrixDiagonal)
+#pragma omp parallel for num_threads(nth) schedule(static) default(none) \
+        shared(x, xp, v, f, invMassPerDim)                               \
+                firstprivate(nth, homenr, lambdaStart, lambdaEnd, isFullScalingMatrixDiagonal)
     for (int th = 0; th < nth; th++)
     {
         try
@@ -267,56 +385,80 @@ void Propagator<IntegrationStep::LeapFrog>::run()
             {
                 if (isFullScalingMatrixDiagonal)
                 {
-                    updateVelocities<numVelocityScalingValues, ParrinelloRahmanVelocityScaling::Diagonal>(
-                            a, timestep_,
-                            numVelocityScalingValues == NumVelocityScalingValues::Multiple
-                                    ? velocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
-                                    : lambda,
-                            invMassPerDim, v, f, diagPR_, matrixPR_);
+                    updateVelocities<numStartVelocityScalingValues, ParrinelloRahmanVelocityScaling::Diagonal, numEndVelocityScalingValues>(
+                            a,
+                            timestep_,
+                            numStartVelocityScalingValues == NumVelocityScalingValues::Multiple
+                                    ? startVelocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                    : lambdaStart,
+                            numEndVelocityScalingValues == NumVelocityScalingValues::Multiple
+                                    ? endVelocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                    : lambdaEnd,
+                            invMassPerDim,
+                            v,
+                            f,
+                            diagPR_,
+                            matrixPR_);
                 }
                 else
                 {
-                    updateVelocities<numVelocityScalingValues, parrinelloRahmanVelocityScaling>(
-                            a, timestep_,
-                            numVelocityScalingValues == NumVelocityScalingValues::Multiple
-                                    ? velocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
-                                    : lambda,
-                            invMassPerDim, v, f, diagPR_, matrixPR_);
+                    updateVelocities<numStartVelocityScalingValues, parrinelloRahmanVelocityScaling, numEndVelocityScalingValues>(
+                            a,
+                            timestep_,
+                            numStartVelocityScalingValues == NumVelocityScalingValues::Multiple
+                                    ? startVelocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                    : lambdaStart,
+                            numEndVelocityScalingValues == NumVelocityScalingValues::Multiple
+                                    ? endVelocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                    : lambdaEnd,
+                            invMassPerDim,
+                            v,
+                            f,
+                            diagPR_,
+                            matrixPR_);
                 }
                 updatePositions(a, timestep_, x, xp, v);
             }
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
     }
-    wallcycle_stop(wcycle_, ewcUPDATE);
+    wallcycle_stop(wcycle_, WallCycleCounter::Update);
 }
 
 //! Propagation (velocity verlet stage 2 - velocity and position)
 template<>
-template<NumVelocityScalingValues numVelocityScalingValues, ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling>
-void Propagator<IntegrationStep::VelocityVerletPositionsAndVelocities>::run()
+template<NumVelocityScalingValues        numStartVelocityScalingValues,
+         ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling,
+         NumVelocityScalingValues        numEndVelocityScalingValues,
+         NumPositionScalingValues        numPositionScalingValues>
+void Propagator<IntegrationStage::VelocityVerletPositionsAndVelocities>::run()
 {
-    wallcycle_start(wcycle_, ewcUPDATE);
+    wallcycle_start(wcycle_, WallCycleCounter::Update);
 
     auto xp = as_rvec_array(statePropagatorData_->positionsView().paddedArrayRef().data());
-    auto x = as_rvec_array(statePropagatorData_->constPreviousPositionsView().paddedArrayRef().data());
-    auto v = as_rvec_array(statePropagatorData_->velocitiesView().paddedArrayRef().data());
-    auto f = as_rvec_array(statePropagatorData_->constForcesView().force().data());
+    auto x  = as_rvec_array(statePropagatorData_->constPositionsView().paddedArrayRef().data());
+    auto v  = as_rvec_array(statePropagatorData_->velocitiesView().paddedArrayRef().data());
+    auto f  = as_rvec_array(statePropagatorData_->constForcesView().force().data());
     auto invMassPerDim = mdAtoms_->mdatoms()->invMassPerDim;
 
-    const real lambda =
-            (numVelocityScalingValues == NumVelocityScalingValues::Single) ? velocityScaling_[0] : 1.0;
+    const real lambdaStart = (numStartVelocityScalingValues == NumVelocityScalingValues::Single)
+                                     ? startVelocityScaling_[0]
+                                     : 1.0;
+    const real lambdaEnd = (numEndVelocityScalingValues == NumVelocityScalingValues::Single)
+                                   ? endVelocityScaling_[0]
+                                   : 1.0;
 
     const bool isFullScalingMatrixDiagonal =
             diagonalizePRMatrix<parrinelloRahmanVelocityScaling>(matrixPR_, diagPR_);
 
-    const int nth    = gmx_omp_nthreads_get(emntUpdate);
+    const int nth    = gmx_omp_nthreads_get(ModuleMultiThread::Update);
     const int homenr = mdAtoms_->mdatoms()->homenr;
 
 // const variables could be shared, but gcc-8 & gcc-9 don't agree how to write that...
 // https://www.gnu.org/software/gcc/gcc-9/porting_to.html -> OpenMP data sharing
-#pragma omp parallel for num_threads(nth) schedule(static) default(none) shared( \
-        x, xp, v, f, invMassPerDim) firstprivate(nth, homenr, lambda, isFullScalingMatrixDiagonal)
+#pragma omp parallel for num_threads(nth) schedule(static) default(none) \
+        shared(x, xp, v, f, invMassPerDim)                               \
+                firstprivate(nth, homenr, lambdaStart, lambdaEnd, isFullScalingMatrixDiagonal)
     for (int th = 0; th < nth; th++)
     {
         try
@@ -328,39 +470,107 @@ void Propagator<IntegrationStep::VelocityVerletPositionsAndVelocities>::run()
             {
                 if (isFullScalingMatrixDiagonal)
                 {
-                    updateVelocities<numVelocityScalingValues, ParrinelloRahmanVelocityScaling::Diagonal>(
-                            a, 0.5 * timestep_,
-                            numVelocityScalingValues == NumVelocityScalingValues::Multiple
-                                    ? velocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
-                                    : lambda,
-                            invMassPerDim, v, f, diagPR_, matrixPR_);
+                    updateVelocities<numStartVelocityScalingValues, ParrinelloRahmanVelocityScaling::Diagonal, numEndVelocityScalingValues>(
+                            a,
+                            0.5 * timestep_,
+                            numStartVelocityScalingValues == NumVelocityScalingValues::Multiple
+                                    ? startVelocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                    : lambdaStart,
+                            numEndVelocityScalingValues == NumVelocityScalingValues::Multiple
+                                    ? endVelocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                    : lambdaEnd,
+                            invMassPerDim,
+                            v,
+                            f,
+                            diagPR_,
+                            matrixPR_);
                 }
                 else
                 {
-                    updateVelocities<numVelocityScalingValues, parrinelloRahmanVelocityScaling>(
-                            a, 0.5 * timestep_,
-                            numVelocityScalingValues == NumVelocityScalingValues::Multiple
-                                    ? velocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
-                                    : lambda,
-                            invMassPerDim, v, f, diagPR_, matrixPR_);
+                    updateVelocities<numStartVelocityScalingValues, parrinelloRahmanVelocityScaling, numEndVelocityScalingValues>(
+                            a,
+                            0.5 * timestep_,
+                            numStartVelocityScalingValues == NumVelocityScalingValues::Multiple
+                                    ? startVelocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                    : lambdaStart,
+                            numEndVelocityScalingValues == NumVelocityScalingValues::Multiple
+                                    ? endVelocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                    : lambdaEnd,
+                            invMassPerDim,
+                            v,
+                            f,
+                            diagPR_,
+                            matrixPR_);
                 }
                 updatePositions(a, timestep_, x, xp, v);
             }
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
     }
-    wallcycle_stop(wcycle_, ewcUPDATE);
+    wallcycle_stop(wcycle_, WallCycleCounter::Update);
+}
+
+//! Scaling (velocity scaling only)
+template<>
+template<NumVelocityScalingValues        numStartVelocityScalingValues,
+         ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling,
+         NumVelocityScalingValues        numEndVelocityScalingValues,
+         NumPositionScalingValues        numPositionScalingValues>
+void Propagator<IntegrationStage::ScaleVelocities>::run()
+{
+    if (numStartVelocityScalingValues == NumVelocityScalingValues::None)
+    {
+        return;
+    }
+    wallcycle_start(wcycle_, WallCycleCounter::Update);
+
+    auto* v = as_rvec_array(statePropagatorData_->velocitiesView().paddedArrayRef().data());
+
+    const real lambdaStart = (numStartVelocityScalingValues == NumVelocityScalingValues::Single)
+                                     ? startVelocityScaling_[0]
+                                     : 1.0;
+
+    const int nth    = gmx_omp_nthreads_get(ModuleMultiThread::Update);
+    const int homenr = mdAtoms_->mdatoms()->homenr;
+
+// const variables could be shared, but gcc-8 & gcc-9 don't agree how to write that...
+// https://www.gnu.org/software/gcc/gcc-9/porting_to.html -> OpenMP data sharing
+#pragma omp parallel for num_threads(nth) schedule(static) default(none) shared(v) \
+        firstprivate(nth, homenr, lambdaStart)
+    for (int th = 0; th < nth; th++)
+    {
+        try
+        {
+            int start_th = 0;
+            int end_th   = 0;
+            getThreadAtomRange(nth, th, homenr, &start_th, &end_th);
+
+            for (int a = start_th; a < end_th; a++)
+            {
+                scaleVelocities<numStartVelocityScalingValues>(
+                        a,
+                        numStartVelocityScalingValues == NumVelocityScalingValues::Multiple
+                                ? startVelocityScaling_[mdAtoms_->mdatoms()->cTC[a]]
+                                : lambdaStart,
+                        v);
+            }
+        }
+        GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
+    }
+    wallcycle_stop(wcycle_, WallCycleCounter::Update);
 }
 
-template<IntegrationStep algorithm>
-Propagator<algorithm>::Propagator(double               timestep,
-                                  StatePropagatorData* statePropagatorData,
-                                  const MDAtoms*       mdAtoms,
-                                  gmx_wallcycle*       wcycle) :
+template<IntegrationStage integrationStage>
+Propagator<integrationStage>::Propagator(double               timestep,
+                                         StatePropagatorData* statePropagatorData,
+                                         const MDAtoms*       mdAtoms,
+                                         gmx_wallcycle*       wcycle) :
     timestep_(timestep),
     statePropagatorData_(statePropagatorData),
-    doSingleVelocityScaling_(false),
-    doGroupVelocityScaling_(false),
+    doSingleStartVelocityScaling_(false),
+    doGroupStartVelocityScaling_(false),
+    doSingleEndVelocityScaling_(false),
+    doGroupEndVelocityScaling_(false),
     scalingStepVelocity_(-1),
     diagPR_{ 0 },
     matrixPR_{ { 0 } },
@@ -370,44 +580,145 @@ Propagator<algorithm>::Propagator(double               timestep,
 {
 }
 
-template<IntegrationStep algorithm>
-void Propagator<algorithm>::scheduleTask(Step gmx_unused step,
-                                         Time gmx_unused            time,
-                                         const RegisterRunFunction& registerRunFunction)
+template<IntegrationStage integrationStage>
+void Propagator<integrationStage>::scheduleTask(Step step,
+                                                Time gmx_unused            time,
+                                                const RegisterRunFunction& registerRunFunction)
 {
-    const bool doSingleVScalingThisStep = (doSingleVelocityScaling_ && (step == scalingStepVelocity_));
-    const bool doGroupVScalingThisStep = (doGroupVelocityScaling_ && (step == scalingStepVelocity_));
+    const bool doSingleVScalingThisStep =
+            (doSingleStartVelocityScaling_ && (step == scalingStepVelocity_));
+    const bool doGroupVScalingThisStep = (doGroupStartVelocityScaling_ && (step == scalingStepVelocity_));
 
-    const bool doParrinelloRahmanThisStep = (step == scalingStepPR_);
+    if (integrationStage == IntegrationStage::ScaleVelocities)
+    {
+        // IntegrationStage::ScaleVelocities only needs to run if some kind of
+        // velocity scaling is needed on the current step.
+        if (!doSingleVScalingThisStep && !doGroupVScalingThisStep)
+        {
+            return;
+        }
+    }
 
-    if (doSingleVScalingThisStep)
+    if (integrationStage == IntegrationStage::ScalePositions)
     {
-        if (doParrinelloRahmanThisStep)
+        // IntegrationStage::ScalePositions only needs to run if
+        // position scaling is needed on the current step.
+        if (step != scalingStepPosition_)
+        {
+            return;
+        }
+        // Since IntegrationStage::ScalePositions is the only stage for which position scaling
+        // is implemented we handle it here to avoid enlarging the decision tree below.
+        if (doSinglePositionScaling_)
         {
             registerRunFunction([this]() {
-                run<NumVelocityScalingValues::Single, ParrinelloRahmanVelocityScaling::Full>();
+                run<NumVelocityScalingValues::None,
+                    ParrinelloRahmanVelocityScaling::No,
+                    NumVelocityScalingValues::None,
+                    NumPositionScalingValues::Single>();
             });
         }
-        else
+        else if (doGroupPositionScaling_)
         {
             registerRunFunction([this]() {
-                run<NumVelocityScalingValues::Single, ParrinelloRahmanVelocityScaling::No>();
+                run<NumVelocityScalingValues::None,
+                    ParrinelloRahmanVelocityScaling::No,
+                    NumVelocityScalingValues::None,
+                    NumPositionScalingValues::Multiple>();
             });
         }
     }
+
+    const bool doParrinelloRahmanThisStep = (step == scalingStepPR_);
+
+    if (doSingleVScalingThisStep)
+    {
+        if (doParrinelloRahmanThisStep)
+        {
+            if (doSingleEndVelocityScaling_)
+            {
+                registerRunFunction([this]() {
+                    run<NumVelocityScalingValues::Single,
+                        ParrinelloRahmanVelocityScaling::Full,
+                        NumVelocityScalingValues::Single,
+                        NumPositionScalingValues::None>();
+                });
+            }
+            else
+            {
+                registerRunFunction([this]() {
+                    run<NumVelocityScalingValues::Single,
+                        ParrinelloRahmanVelocityScaling::Full,
+                        NumVelocityScalingValues::None,
+                        NumPositionScalingValues::None>();
+                });
+            }
+        }
+        else
+        {
+            if (doSingleEndVelocityScaling_)
+            {
+                registerRunFunction([this]() {
+                    run<NumVelocityScalingValues::Single,
+                        ParrinelloRahmanVelocityScaling::No,
+                        NumVelocityScalingValues::Single,
+                        NumPositionScalingValues::None>();
+                });
+            }
+            else
+            {
+                registerRunFunction([this]() {
+                    run<NumVelocityScalingValues::Single,
+                        ParrinelloRahmanVelocityScaling::No,
+                        NumVelocityScalingValues::None,
+                        NumPositionScalingValues::None>();
+                });
+            }
+        }
+    }
     else if (doGroupVScalingThisStep)
     {
         if (doParrinelloRahmanThisStep)
         {
-            registerRunFunction([this]() {
-                run<NumVelocityScalingValues::Multiple, ParrinelloRahmanVelocityScaling::Full>();
-            });
+            if (doGroupEndVelocityScaling_)
+            {
+                registerRunFunction([this]() {
+                    run<NumVelocityScalingValues::Multiple,
+                        ParrinelloRahmanVelocityScaling::Full,
+                        NumVelocityScalingValues::Multiple,
+                        NumPositionScalingValues::None>();
+                });
+            }
+            else
+            {
+                registerRunFunction([this]() {
+                    run<NumVelocityScalingValues::Multiple,
+                        ParrinelloRahmanVelocityScaling::Full,
+                        NumVelocityScalingValues::None,
+                        NumPositionScalingValues::None>();
+                });
+            }
         }
         else
         {
-            registerRunFunction([this]() {
-                run<NumVelocityScalingValues::Multiple, ParrinelloRahmanVelocityScaling::No>();
-            });
+            if (doGroupEndVelocityScaling_)
+            {
+                registerRunFunction([this]() {
+                    run<NumVelocityScalingValues::Multiple,
+                        ParrinelloRahmanVelocityScaling::No,
+                        NumVelocityScalingValues::Multiple,
+                        NumPositionScalingValues::None>();
+                });
+            }
+            else
+            {
+                registerRunFunction([this]() {
+                    run<NumVelocityScalingValues::Multiple,
+                        ParrinelloRahmanVelocityScaling::No,
+                        NumVelocityScalingValues::None,
+                        NumPositionScalingValues::None>();
+                });
+            }
         }
     }
     else
@@ -415,62 +726,158 @@ void Propagator<algorithm>::scheduleTask(Step gmx_unused step,
         if (doParrinelloRahmanThisStep)
         {
             registerRunFunction([this]() {
-                run<NumVelocityScalingValues::None, ParrinelloRahmanVelocityScaling::Full>();
+                run<NumVelocityScalingValues::None,
+                    ParrinelloRahmanVelocityScaling::Full,
+                    NumVelocityScalingValues::None,
+                    NumPositionScalingValues::None>();
             });
         }
         else
         {
             registerRunFunction([this]() {
-                run<NumVelocityScalingValues::None, ParrinelloRahmanVelocityScaling::No>();
+                run<NumVelocityScalingValues::None,
+                    ParrinelloRahmanVelocityScaling::No,
+                    NumVelocityScalingValues::None,
+                    NumPositionScalingValues::None>();
             });
         }
     }
 }
 
-template<IntegrationStep algorithm>
-void Propagator<algorithm>::setNumVelocityScalingVariables(int numVelocityScalingVariables)
+template<IntegrationStage integrationStage>
+constexpr bool hasStartVelocityScaling()
 {
-    if (algorithm == IntegrationStep::PositionsOnly)
-    {
-        gmx_fatal(FARGS, "Velocity scaling not implemented for IntegrationStep::PositionsOnly.");
-    }
-    GMX_ASSERT(velocityScaling_.empty(),
-               "Number of velocity scaling variables cannot be changed once set.");
+    return (integrationStage == IntegrationStage::VelocitiesOnly
+            || integrationStage == IntegrationStage::LeapFrog
+            || integrationStage == IntegrationStage::VelocityVerletPositionsAndVelocities
+            || integrationStage == IntegrationStage::ScaleVelocities);
+}
 
-    velocityScaling_.resize(numVelocityScalingVariables, 1.);
-    doSingleVelocityScaling_ = numVelocityScalingVariables == 1;
-    doGroupVelocityScaling_  = numVelocityScalingVariables > 1;
+template<IntegrationStage integrationStage>
+constexpr bool hasEndVelocityScaling()
+{
+    return (hasStartVelocityScaling<integrationStage>()
+            && integrationStage != IntegrationStage::ScaleVelocities);
 }
 
-template<IntegrationStep algorithm>
-ArrayRef<real> Propagator<algorithm>::viewOnVelocityScaling()
+template<IntegrationStage integrationStage>
+constexpr bool hasPositionScaling()
 {
-    if (algorithm == IntegrationStep::PositionsOnly)
-    {
-        gmx_fatal(FARGS, "Velocity scaling not implemented for IntegrationStep::PositionsOnly.");
-    }
-    GMX_ASSERT(!velocityScaling_.empty(), "Number of velocity scaling variables not set.");
+    return (integrationStage == IntegrationStage::ScalePositions);
+}
 
-    return velocityScaling_;
+template<IntegrationStage integrationStage>
+constexpr bool hasParrinelloRahmanScaling()
+{
+    return (integrationStage == IntegrationStage::VelocitiesOnly
+            || integrationStage == IntegrationStage::LeapFrog
+            || integrationStage == IntegrationStage::VelocityVerletPositionsAndVelocities);
 }
 
-template<IntegrationStep algorithm>
-PropagatorCallback Propagator<algorithm>::velocityScalingCallback()
+template<IntegrationStage integrationStage>
+void Propagator<integrationStage>::setNumVelocityScalingVariables(int numVelocityScalingVariables,
+                                                                  ScaleVelocities scaleVelocities)
 {
-    if (algorithm == IntegrationStep::PositionsOnly)
+    GMX_RELEASE_ASSERT(
+            hasStartVelocityScaling<integrationStage>() || hasEndVelocityScaling<integrationStage>(),
+            formatString("Velocity scaling not implemented for %s", integrationStepNames[integrationStage])
+                    .c_str());
+    GMX_RELEASE_ASSERT(startVelocityScaling_.empty(),
+                       "Number of velocity scaling variables cannot be changed once set.");
+
+    const bool scaleEndVelocities = (scaleVelocities == ScaleVelocities::PreStepAndPostStep);
+    startVelocityScaling_.resize(numVelocityScalingVariables, 1.);
+    if (scaleEndVelocities)
     {
-        gmx_fatal(FARGS, "Velocity scaling not implemented for IntegrationStep::PositionsOnly.");
+        endVelocityScaling_.resize(numVelocityScalingVariables, 1.);
     }
+    doSingleStartVelocityScaling_ = numVelocityScalingVariables == 1;
+    doGroupStartVelocityScaling_  = numVelocityScalingVariables > 1;
+    doSingleEndVelocityScaling_   = doSingleStartVelocityScaling_ && scaleEndVelocities;
+    doGroupEndVelocityScaling_    = doGroupStartVelocityScaling_ && scaleEndVelocities;
+}
 
-    return [this](Step step) { scalingStepVelocity_ = step; };
+template<IntegrationStage integrationStage>
+void Propagator<integrationStage>::setNumPositionScalingVariables(int numPositionScalingVariables)
+{
+    GMX_RELEASE_ASSERT(hasPositionScaling<integrationStage>(),
+                       formatString("Position scaling not implemented for %s",
+                                    integrationStepNames[integrationStage])
+                               .c_str());
+    GMX_RELEASE_ASSERT(positionScaling_.empty(),
+                       "Number of position scaling variables cannot be changed once set.");
+    positionScaling_.resize(numPositionScalingVariables, 1.);
+    doSinglePositionScaling_ = (numPositionScalingVariables == 1);
+    doGroupPositionScaling_  = (numPositionScalingVariables > 1);
 }
 
-template<IntegrationStep algorithm>
-ArrayRef<rvec> Propagator<algorithm>::viewOnPRScalingMatrix()
+template<IntegrationStage integrationStage>
+ArrayRef<real> Propagator<integrationStage>::viewOnStartVelocityScaling()
+{
+    GMX_RELEASE_ASSERT(hasStartVelocityScaling<integrationStage>(),
+                       formatString("Start velocity scaling not implemented for %s",
+                                    integrationStepNames[integrationStage])
+                               .c_str());
+    GMX_RELEASE_ASSERT(!startVelocityScaling_.empty(),
+                       "Number of velocity scaling variables not set.");
+
+    return startVelocityScaling_;
+}
+
+template<IntegrationStage integrationStage>
+ArrayRef<real> Propagator<integrationStage>::viewOnEndVelocityScaling()
+{
+    GMX_RELEASE_ASSERT(hasEndVelocityScaling<integrationStage>(),
+                       formatString("End velocity scaling not implemented for %s",
+                                    integrationStepNames[integrationStage])
+                               .c_str());
+    GMX_RELEASE_ASSERT(!endVelocityScaling_.empty(),
+                       "Number of velocity scaling variables not set.");
+
+    return endVelocityScaling_;
+}
+
+template<IntegrationStage integrationStage>
+ArrayRef<real> Propagator<integrationStage>::viewOnPositionScaling()
+{
+    GMX_RELEASE_ASSERT(hasPositionScaling<integrationStage>(),
+                       formatString("Position scaling not implemented for %s",
+                                    integrationStepNames[integrationStage])
+                               .c_str());
+    GMX_RELEASE_ASSERT(!positionScaling_.empty(), "Number of position scaling variables not set.");
+
+    return positionScaling_;
+}
+
+template<IntegrationStage integrationStage>
+PropagatorCallback Propagator<integrationStage>::velocityScalingCallback()
 {
     GMX_RELEASE_ASSERT(
-            algorithm != IntegrationStep::PositionsOnly,
-            "Parrinello-Rahman scaling not implemented for IntegrationStep::PositionsOnly.");
+            hasStartVelocityScaling<integrationStage>() || hasEndVelocityScaling<integrationStage>(),
+            formatString("Velocity scaling not implemented for %s", integrationStepNames[integrationStage])
+                    .c_str());
+
+    return [this](Step step) { scalingStepVelocity_ = step; };
+}
+
+template<IntegrationStage integrationStage>
+PropagatorCallback Propagator<integrationStage>::positionScalingCallback()
+{
+    GMX_RELEASE_ASSERT(hasPositionScaling<integrationStage>(),
+                       formatString("Position scaling not implemented for %s",
+                                    integrationStepNames[integrationStage])
+                               .c_str());
+
+    return [this](Step step) { scalingStepPosition_ = step; };
+}
+
+template<IntegrationStage integrationStage>
+ArrayRef<rvec> Propagator<integrationStage>::viewOnPRScalingMatrix()
+{
+    GMX_RELEASE_ASSERT(hasParrinelloRahmanScaling<integrationStage>(),
+                       formatString("Parrinello-Rahman scaling not implemented for %s",
+                                    integrationStepNames[integrationStage])
+                               .c_str());
 
     clear_mat(matrixPR_);
     // gcc-5 needs this to be explicit (all other tested compilers would be ok
@@ -478,52 +885,142 @@ ArrayRef<rvec> Propagator<algorithm>::viewOnPRScalingMatrix()
     return ArrayRef<rvec>(matrixPR_);
 }
 
-template<IntegrationStep algorithm>
-PropagatorCallback Propagator<algorithm>::prScalingCallback()
+template<IntegrationStage integrationStage>
+PropagatorCallback Propagator<integrationStage>::prScalingCallback()
 {
-    GMX_RELEASE_ASSERT(
-            algorithm != IntegrationStep::PositionsOnly,
-            "Parrinello-Rahman scaling not implemented for IntegrationStep::PositionsOnly.");
+    GMX_RELEASE_ASSERT(hasParrinelloRahmanScaling<integrationStage>(),
+                       formatString("Parrinello-Rahman scaling not implemented for %s",
+                                    integrationStepNames[integrationStage])
+                               .c_str());
 
     return [this](Step step) { scalingStepPR_ = step; };
 }
 
-template<IntegrationStep algorithm>
-ISimulatorElement* Propagator<algorithm>::getElementPointerImpl(
+template<IntegrationStage integrationStage>
+static PropagatorConnection getConnection(Propagator<integrationStage> gmx_unused* propagator,
+                                          const PropagatorTag&                     propagatorTag)
+{
+    // gmx_unused is needed because gcc-7 & gcc-8 can't see that
+    // propagator is used for all IntegrationStage options
+
+    PropagatorConnection propagatorConnection{ propagatorTag };
+
+    // The clang-tidy version on our current CI throws 3 different warnings
+    // for the if constexpr lines, so disable linting for now. Also, this only
+    // works if the brace is on the same line, so turn off clang-format as well
+    // clang-format off
+    // NOLINTNEXTLINE
+    if constexpr (hasStartVelocityScaling<integrationStage>() || hasEndVelocityScaling<integrationStage>()) {
+        // clang-format on
+        propagatorConnection.setNumVelocityScalingVariables =
+                [propagator](int num, ScaleVelocities scaleVelocities) {
+                    propagator->setNumVelocityScalingVariables(num, scaleVelocities);
+                };
+        propagatorConnection.getVelocityScalingCallback = [propagator]() {
+            return propagator->velocityScalingCallback();
+        };
+    }
+    // clang-format off
+    // NOLINTNEXTLINE
+    if constexpr (hasStartVelocityScaling<integrationStage>()) {
+        // clang-format on
+        propagatorConnection.getViewOnStartVelocityScaling = [propagator]() {
+            return propagator->viewOnStartVelocityScaling();
+        };
+    }
+    // clang-format off
+    // NOLINTNEXTLINE
+    if constexpr (hasEndVelocityScaling<integrationStage>()) {
+        // clang-format on
+        propagatorConnection.getViewOnEndVelocityScaling = [propagator]() {
+            return propagator->viewOnEndVelocityScaling();
+        };
+    }
+    // clang-format off
+    // NOLINTNEXTLINE
+    if constexpr (hasPositionScaling<integrationStage>()) {
+        // clang-format on
+        propagatorConnection.setNumPositionScalingVariables = [propagator](int num) {
+            propagator->setNumPositionScalingVariables(num);
+        };
+        propagatorConnection.getViewOnPositionScaling = [propagator]() {
+            return propagator->viewOnPositionScaling();
+        };
+        propagatorConnection.getPositionScalingCallback = [propagator]() {
+            return propagator->positionScalingCallback();
+        };
+    }
+    // clang-format off
+    // NOLINTNEXTLINE
+    if constexpr (hasParrinelloRahmanScaling<integrationStage>()) {
+        // clang-format on
+        propagatorConnection.getViewOnPRScalingMatrix = [propagator]() {
+            return propagator->viewOnPRScalingMatrix();
+        };
+        propagatorConnection.getPRScalingCallback = [propagator]() {
+            return propagator->prScalingCallback();
+        };
+    }
+
+    // NOLINTNEXTLINE(readability-misleading-indentation)
+    return propagatorConnection;
+}
+
+// doxygen is confused by the two definitions
+//! \cond
+template<IntegrationStage integrationStage>
+ISimulatorElement* Propagator<integrationStage>::getElementPointerImpl(
         LegacySimulatorData*                    legacySimulatorData,
         ModularSimulatorAlgorithmBuilderHelper* builderHelper,
         StatePropagatorData*                    statePropagatorData,
         EnergyData gmx_unused*     energyData,
         FreeEnergyPerturbationData gmx_unused* freeEnergyPerturbationData,
         GlobalCommunicationHelper gmx_unused* globalCommunicationHelper,
-        double                                timestep,
-        RegisterWithThermostat                registerWithThermostat,
-        RegisterWithBarostat                  registerWithBarostat)
+        const PropagatorTag&                  propagatorTag,
+        TimeStep                              timestep)
 {
-    auto* element = builderHelper->storeElement(std::make_unique<Propagator<algorithm>>(
+    GMX_RELEASE_ASSERT(!(integrationStage == IntegrationStage::ScaleVelocities
+                         || integrationStage == IntegrationStage::ScalePositions)
+                               || (timestep == 0.0),
+                       "Scaling elements don't propagate the system.");
+    auto* element    = builderHelper->storeElement(std::make_unique<Propagator<integrationStage>>(
             timestep, statePropagatorData, legacySimulatorData->mdAtoms, legacySimulatorData->wcycle));
-    if (registerWithThermostat == RegisterWithThermostat::True)
-    {
-        auto* propagator = static_cast<Propagator<algorithm>*>(element);
-        builderHelper->registerWithThermostat(
-                { [propagator](int num) { propagator->setNumVelocityScalingVariables(num); },
-                  [propagator]() { return propagator->viewOnVelocityScaling(); },
-                  [propagator]() { return propagator->velocityScalingCallback(); } });
-    }
-    if (registerWithBarostat == RegisterWithBarostat::True)
-    {
-        auto* propagator = static_cast<Propagator<algorithm>*>(element);
-        builderHelper->registerWithBarostat(
-                { [propagator]() { return propagator->viewOnPRScalingMatrix(); },
-                  [propagator]() { return propagator->prScalingCallback(); } });
-    }
+    auto* propagator = static_cast<Propagator<integrationStage>*>(element);
+    builderHelper->registerPropagator(getConnection<integrationStage>(propagator, propagatorTag));
     return element;
 }
 
+template<IntegrationStage integrationStage>
+ISimulatorElement* Propagator<integrationStage>::getElementPointerImpl(
+        LegacySimulatorData*                    legacySimulatorData,
+        ModularSimulatorAlgorithmBuilderHelper* builderHelper,
+        StatePropagatorData*                    statePropagatorData,
+        EnergyData*                             energyData,
+        FreeEnergyPerturbationData*             freeEnergyPerturbationData,
+        GlobalCommunicationHelper*              globalCommunicationHelper,
+        const PropagatorTag&                    propagatorTag)
+{
+    GMX_RELEASE_ASSERT(
+            integrationStage == IntegrationStage::ScaleVelocities
+                    || integrationStage == IntegrationStage::ScalePositions,
+            "Adding a propagator without time step is only allowed for scaling elements");
+    return getElementPointerImpl(legacySimulatorData,
+                                 builderHelper,
+                                 statePropagatorData,
+                                 energyData,
+                                 freeEnergyPerturbationData,
+                                 globalCommunicationHelper,
+                                 propagatorTag,
+                                 TimeStep(0.0));
+}
+//! \endcond
+
 // Explicit template initializations
-template class Propagator<IntegrationStep::PositionsOnly>;
-template class Propagator<IntegrationStep::VelocitiesOnly>;
-template class Propagator<IntegrationStep::LeapFrog>;
-template class Propagator<IntegrationStep::VelocityVerletPositionsAndVelocities>;
+template class Propagator<IntegrationStage::PositionsOnly>;
+template class Propagator<IntegrationStage::VelocitiesOnly>;
+template class Propagator<IntegrationStage::LeapFrog>;
+template class Propagator<IntegrationStage::VelocityVerletPositionsAndVelocities>;
+template class Propagator<IntegrationStage::ScaleVelocities>;
+template class Propagator<IntegrationStage::ScalePositions>;
 
 } // namespace gmx
index df505c5f7fc94aac0b214a9cbe6b7ba45dde8404..631a98f133782fface5d4f07495e118585b1a6b1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,39 +67,32 @@ class StatePropagatorData;
 //! \addtogroup module_modularsimulator
 //! \{
 
-//! Whether built propagator should be registered with thermostat
-enum class RegisterWithThermostat
+//! Which velocities the thermostat scales
+enum class ScaleVelocities
 {
-    True,
-    False
+    PreStepOnly,
+    PreStepAndPostStep
 };
-//! Whether built propagator should be registered with barostat
-enum class RegisterWithBarostat
+
+//! The different integration types we know about
+enum class IntegrationStage
 {
-    True,
-    False
+    PositionsOnly,                        //!< Moves the position vector by the given time step
+    VelocitiesOnly,                       //!< Moves the velocity vector by the given time step
+    LeapFrog,                             //!< Manual fusion of the previous two propagators
+    VelocityVerletPositionsAndVelocities, //!< Manual position (full dt) and velocity (half dt) fusion
+    ScaleVelocities,                      //!< Only scale velocities, don't propagate
+    ScalePositions,                       //!< Only scale positions, don't propagate
+    Count                                 //!< The number of enum entries
 };
 
-/*! \brief The different integration types we know about
- *
- * PositionsOnly:
- *   Moves the position vector by the given time step
- * VelocitiesOnly:
- *   Moves the velocity vector by the given time step
- * LeapFrog:
- *   Is a manual fusion of the previous two propagators
- * VelocityVerletPositionsAndVelocities:
- *   Is a manual fusion of VelocitiesOnly and PositionsOnly,
- *   where VelocitiesOnly is only propagated by half the
- *   time step of the positions.
- */
-enum class IntegrationStep
+//! Sets the number of different position scaling values
+enum class NumPositionScalingValues
 {
-    PositionsOnly,
-    VelocitiesOnly,
-    LeapFrog,
-    VelocityVerletPositionsAndVelocities,
-    Count
+    None,     //!< No position scaling (either this step or ever)
+    Single,   //!< Single scaling value (either one group or all values =1)
+    Multiple, //!< Multiple scaling values, need to use T-group indices
+    Count     //!< The number of enum entries
 };
 
 //! Sets the number of different velocity scaling values
@@ -129,9 +122,9 @@ enum class ParrinelloRahmanVelocityScaling
  * functions allows to have performance comparable to fused update elements
  * while keeping easily re-orderable single instructions.
  *
- * \tparam algorithm  The integration types
+ * \tparam integrationStep  The integration types
  */
-template<IntegrationStep algorithm>
+template<IntegrationStage integrationStage>
 class Propagator final : public ISimulatorElement
 {
 public:
@@ -142,6 +135,10 @@ public:
                gmx_wallcycle*       wcycle);
 
     /*! \brief Register run function for step / time
+     *
+     * This function will determine the required flavor of the run function to be registered
+     * for the current step. In case of the pure scaling integrator stage, it might also skip
+     * the function registration if no scaling is needed.
      *
      * \param step                 The step number
      * \param time                 The time
@@ -155,11 +152,19 @@ public:
     void elementTeardown() override {}
 
     //! Set the number of velocity scaling variables
-    void setNumVelocityScalingVariables(int numVelocityScalingVariables);
-    //! Get view on the velocity scaling vector
-    ArrayRef<real> viewOnVelocityScaling();
+    void setNumVelocityScalingVariables(int numVelocityScalingVariables, ScaleVelocities scaleVelocities);
+    //! Set the number of position scaling variables
+    void setNumPositionScalingVariables(int numPositionScalingVariables);
+    //! Get view on the scaling vector applied to start of step velocities
+    ArrayRef<real> viewOnStartVelocityScaling();
+    //! Get view on the scaling vector applied to end of step velocities
+    ArrayRef<real> viewOnEndVelocityScaling();
+    //! Get view on the scaling vector applied to the positions
+    ArrayRef<real> viewOnPositionScaling();
     //! Get velocity scaling callback
     PropagatorCallback velocityScalingCallback();
+    //! Get position scaling callback
+    PropagatorCallback positionScalingCallback();
 
     //! Get view on the full PR scaling matrix
     ArrayRef<rvec> viewOnPRScalingMatrix();
@@ -174,9 +179,8 @@ public:
      * \param energyData  Pointer to the \c EnergyData object
      * \param freeEnergyPerturbationData  Pointer to the \c FreeEnergyPerturbationData object
      * \param globalCommunicationHelper  Pointer to the \c GlobalCommunicationHelper object
+     * \param propagatorTag  The name of the propagator to simplify connection
      * \param timestep  The time step the propagator uses
-     * \param registerWithThermostat  Whether this propagator should be registered with the thermostat
-     * \param registerWithBarostat  Whether this propagator should be registered with the barostat
      *
      * \return  Pointer to the element to be added. Element needs to have been stored using \c storeElement
      */
@@ -186,13 +190,37 @@ public:
                                                     EnergyData*                 energyData,
                                                     FreeEnergyPerturbationData* freeEnergyPerturbationData,
                                                     GlobalCommunicationHelper* globalCommunicationHelper,
-                                                    double                     timestep,
-                                                    RegisterWithThermostat registerWithThermostat,
-                                                    RegisterWithBarostat   registerWithBarostat);
+                                                    const PropagatorTag&       propagatorTag,
+                                                    TimeStep                   timestep);
+
+    /*! \brief Factory method implementation
+     *
+     * Version without time step for pure scaling elements
+     *
+     * \param legacySimulatorData  Pointer allowing access to simulator level data
+     * \param builderHelper  ModularSimulatorAlgorithmBuilder helper object
+     * \param statePropagatorData  Pointer to the \c StatePropagatorData object
+     * \param energyData  Pointer to the \c EnergyData object
+     * \param freeEnergyPerturbationData  Pointer to the \c FreeEnergyPerturbationData object
+     * \param globalCommunicationHelper  Pointer to the \c GlobalCommunicationHelper object
+     * \param propagatorTag  The name of the propagator to simplify connection
+     *
+     * \return  Pointer to the element to be added. Element needs to have been stored using \c storeElement
+     */
+    static ISimulatorElement* getElementPointerImpl(LegacySimulatorData* legacySimulatorData,
+                                                    ModularSimulatorAlgorithmBuilderHelper* builderHelper,
+                                                    StatePropagatorData*        statePropagatorData,
+                                                    EnergyData*                 energyData,
+                                                    FreeEnergyPerturbationData* freeEnergyPerturbationData,
+                                                    GlobalCommunicationHelper* globalCommunicationHelper,
+                                                    const PropagatorTag&       propagatorTag);
 
 private:
     //! The actual propagation
-    template<NumVelocityScalingValues numVelocityScalingValues, ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling>
+    template<NumVelocityScalingValues        numStartVelocityScalingValues,
+             ParrinelloRahmanVelocityScaling parrinelloRahmanVelocityScaling,
+             NumVelocityScalingValues        numEndVelocityScalingValues,
+             NumPositionScalingValues        numPositionScalingValues>
     void run();
 
     //! The time step
@@ -202,14 +230,28 @@ private:
     //! Pointer to the micro state
     StatePropagatorData* statePropagatorData_;
 
-    //! Whether we're doing single-value velocity scaling
-    bool doSingleVelocityScaling_;
-    //! Wether we're doing group-wise velocity scaling
-    bool doGroupVelocityScaling_;
+    //! Whether we're doing single-value velocity scaling (velocities at start of step)
+    bool doSingleStartVelocityScaling_;
+    //! Whether we're doing group-wise velocity scaling (velocities at start of step)
+    bool doGroupStartVelocityScaling_;
+    //! Whether we're doing single-value velocity scaling (velocities at end of step)
+    bool doSingleEndVelocityScaling_;
+    //! Wether we're doing group-wise velocity scaling (velocities at end of step)
+    bool doGroupEndVelocityScaling_;
+    //! Whether we're doing single-value position scaling
+    bool doSinglePositionScaling_;
+    //! Whether we're doing group-wise position scaling
+    bool doGroupPositionScaling_;
+    //! The vector of velocity scaling values
+    std::vector<real> startVelocityScaling_;
     //! The vector of velocity scaling values
-    std::vector<real> velocityScaling_;
+    std::vector<real> endVelocityScaling_;
+    //! The vector of position scaling values
+    std::vector<real> positionScaling_;
     //! The next velocity scaling step
     Step scalingStepVelocity_;
+    //! The next position scaling step
+    Step scalingStepPosition_;
 
     //! The diagonal of the PR scaling matrix
     rvec diagPR_;
index 45edd4352efb54e96344a9d931a5946a57db9398..70ed23d556e1ff147283b9c559ca73a221cec0db 100644 (file)
@@ -220,13 +220,15 @@ EnergySignaller::EnergySignaller(std::vector<SignallerCallback> calculateEnergyC
                                  std::vector<SignallerCallback> calculateFreeEnergyCallbacks,
                                  int                            nstcalcenergy,
                                  int                            nstcalcfreeenergy,
-                                 int                            nstcalcvirial) :
+                                 int                            nstcalcvirial,
+                                 EnergySignallerVirialMode      virialMode) :
     calculateEnergyCallbacks_(std::move(calculateEnergyCallbacks)),
     calculateVirialCallbacks_(std::move(calculateVirialCallbacks)),
     calculateFreeEnergyCallbacks_(std::move(calculateFreeEnergyCallbacks)),
     nstcalcenergy_(nstcalcenergy),
     nstcalcfreeenergy_(nstcalcfreeenergy),
     nstcalcvirial_(nstcalcvirial),
+    virialMode_(virialMode),
     energyWritingStep_(-1),
     trajectoryRegistrationDone_(false),
     loggingStep_(-1),
@@ -236,16 +238,22 @@ EnergySignaller::EnergySignaller(std::vector<SignallerCallback> calculateEnergyC
 
 void EnergySignaller::signal(Step step, Time time)
 {
-    bool calculateEnergy     = do_per_step(step, nstcalcenergy_);
-    bool calculateFreeEnergy = do_per_step(step, nstcalcfreeenergy_);
-    bool calculateVirial     = do_per_step(step, nstcalcvirial_);
-    bool writeEnergy         = energyWritingStep_ == step;
+    const bool writeEnergy     = (energyWritingStep_ == step);
+    const bool writeLog        = (loggingStep_ == step);
+    const bool calculateEnergy = writeEnergy || writeLog || do_per_step(step, nstcalcenergy_);
+    const bool calculateVirial = calculateEnergy
+                                 || ((virialMode_ == EnergySignallerVirialMode::OnStep
+                                      || virialMode_ == EnergySignallerVirialMode::OnStepAndNext)
+                                     && do_per_step(step, nstcalcvirial_))
+                                 || (virialMode_ == EnergySignallerVirialMode::OnStepAndNext
+                                     && do_per_step(step - 1, nstcalcvirial_));
+    const bool calculateFreeEnergy = do_per_step(step, nstcalcfreeenergy_);
 
-    if (calculateEnergy || writeEnergy || step == loggingStep_)
+    if (calculateEnergy)
     {
         runAllCallbacks(calculateEnergyCallbacks_, step, time);
     }
-    if (calculateEnergy || writeEnergy || step == loggingStep_ || calculateVirial)
+    if (calculateVirial)
     {
         runAllCallbacks(calculateVirialCallbacks_, step, time);
     }
index 2fa20c51293e5f92d087735018674690141f4f2b..b9c50c74d64e950e45ffb31b505c33259c0be9a9 100644 (file)
@@ -333,6 +333,15 @@ private:
     std::optional<SignallerCallback> registerLastStepCallback() override;
 };
 
+//! When we calculate virial
+enum class EnergySignallerVirialMode
+{
+    Off,           //!< No specific virial calculation - calculate when energy is calculated
+    OnStep,        //!< Calculate on virial frequency steps
+    OnStepAndNext, //!< Calculate on virial frequency steps and on step after
+    Count          //!< The number of entries
+};
+
 /*! \internal
  * \ingroup module_modularsimulator
  * \brief Element signalling energy related special steps
@@ -372,13 +381,15 @@ private:
      * \param nstcalcenergy                 The energy calculation frequency
      * \param nstcalcfreeenergy             The free energy calculation frequency
      * \param nstcalcvirial                 The free energy calculation frequency
+     * \param virialMode                    Indicates which steps will calculate virial
      */
     EnergySignaller(std::vector<SignallerCallback> calculateEnergyCallbacks,
                     std::vector<SignallerCallback> calculateVirialCallbacks,
                     std::vector<SignallerCallback> calculateFreeEnergyCallbacks,
                     int                            nstcalcenergy,
                     int                            nstcalcfreeenergy,
-                    int                            nstcalcvirial);
+                    int                            nstcalcvirial,
+                    EnergySignallerVirialMode      virialMode);
 
     //! Client callbacks
     //! {
@@ -393,6 +404,8 @@ private:
     const int nstcalcfreeenergy_;
     //! The virial calculation frequency
     const int nstcalcvirial_;
+    //! The virial calculation mode
+    const EnergySignallerVirialMode virialMode_;
 
     //! ITrajectorySignallerClient implementation
     std::optional<SignallerCallback> registerTrajectorySignallerCallback(TrajectoryEvent event) override;
@@ -468,9 +481,10 @@ std::unique_ptr<EnergySignaller> SignallerBuilder<EnergySignaller>::build(Args&&
     auto calculateFreeEnergyCallbacks =
             buildCallbackVector(EnergySignallerEvent::FreeEnergyCalculationStep);
     // NOLINTNEXTLINE(modernize-make-unique): make_unique does not work with private constructor
-    return std::unique_ptr<EnergySignaller>(new EnergySignaller(
-            std::move(calculateEnergyCallbacks), std::move(calculateVirialCallbacks),
-            std::move(calculateFreeEnergyCallbacks), std::forward<Args>(args)...));
+    return std::unique_ptr<EnergySignaller>(new EnergySignaller(std::move(calculateEnergyCallbacks),
+                                                                std::move(calculateVirialCallbacks),
+                                                                std::move(calculateFreeEnergyCallbacks),
+                                                                std::forward<Args>(args)...));
 }
 
 //! Helper function to get the callbacks from the clients
index 9b90fd16c916c228bf47df2c8d41110e505c2f9b..bfb6c5cd28a6fb104ba2a0edd5caa7127a1b4ece 100644 (file)
 #include "energydata.h"
 #include "freeenergyperturbationdata.h"
 #include "modularsimulator.h"
-#include "parrinellorahmanbarostat.h"
 #include "pmeloadbalancehelper.h"
 #include "propagator.h"
 #include "statepropagatordata.h"
-#include "velocityscalingtemperaturecoupling.h"
 
 namespace gmx
 {
@@ -92,7 +90,7 @@ ModularSimulatorAlgorithm::ModularSimulatorAlgorithm(std::string              to
                                                      t_commrec*               cr,
                                                      const MDLogger&          mdlog,
                                                      const MdrunOptions&      mdrunOptions,
-                                                     t_inputrec*              inputrec,
+                                                     const t_inputrec*        inputrec,
                                                      t_nrnb*                  nrnb,
                                                      gmx_wallcycle*           wcycle,
                                                      t_forcerec*              fr,
@@ -204,8 +202,8 @@ void ModularSimulatorAlgorithm::simulatorSetup()
         fprintf(stderr, "starting mdrun '%s'\n", topologyName_.c_str());
         if (inputrec->nsteps >= 0)
         {
-            timeString = formatString("%8.1f", static_cast<double>(inputrec->init_step + inputrec->nsteps)
-                                                       * inputrec->delta_t);
+            timeString = formatString(
+                    "%8.1f", static_cast<double>(inputrec->init_step + inputrec->nsteps) * inputrec->delta_t);
         }
         else
         {
@@ -213,20 +211,22 @@ void ModularSimulatorAlgorithm::simulatorSetup()
         }
         if (inputrec->init_step > 0)
         {
-            fprintf(stderr, "%s steps, %s ps (continuing from step %s, %8.1f ps).\n",
-                    gmx_step_str(inputrec->init_step + inputrec->nsteps, sbuf), timeString.c_str(),
-                    gmx_step_str(inputrec->init_step, sbuf2), inputrec->init_step * inputrec->delta_t);
+            fprintf(stderr,
+                    "%s steps, %s ps (continuing from step %s, %8.1f ps).\n",
+                    gmx_step_str(inputrec->init_step + inputrec->nsteps, sbuf),
+                    timeString.c_str(),
+                    gmx_step_str(inputrec->init_step, sbuf2),
+                    inputrec->init_step * inputrec->delta_t);
         }
         else
         {
-            fprintf(stderr, "%s steps, %s ps.\n", gmx_step_str(inputrec->nsteps, sbuf),
-                    timeString.c_str());
+            fprintf(stderr, "%s steps, %s ps.\n", gmx_step_str(inputrec->nsteps, sbuf), timeString.c_str());
         }
         fprintf(fplog, "\n");
     }
 
     walltime_accounting_start_time(walltime_accounting);
-    wallcycle_start(wcycle, ewcRUN);
+    wallcycle_start(wcycle, WallCycleCounter::Run);
     print_start(fplog, cr, walltime_accounting, "mdrun");
 
     step_ = inputrec->init_step;
@@ -273,7 +273,7 @@ void ModularSimulatorAlgorithm::preStep(Step step, Time gmx_unused time, bool is
     stophandlerCurrentStep_ = step;
     stopHandler_->setSignal();
 
-    wallcycle_start(wcycle, ewcSTEP);
+    wallcycle_start(wcycle, WallCycleCounter::Step);
 }
 
 void ModularSimulatorAlgorithm::postStep(Step step, Time gmx_unused time)
@@ -299,16 +299,23 @@ void ModularSimulatorAlgorithm::postStep(Step step, Time gmx_unused time)
         print_time(stderr, walltime_accounting, step, inputrec, cr);
     }
 
-    double cycles = wallcycle_stop(wcycle, ewcSTEP);
+    double cycles = wallcycle_stop(wcycle, WallCycleCounter::Step);
     if (DOMAINDECOMP(cr) && wcycle)
     {
         dd_cycles_add(cr->dd, static_cast<float>(cycles), ddCyclStep);
     }
 
-    resetHandler_->resetCounters(
-            step, step - inputrec->init_step, mdlog, fplog, cr, fr->nbv.get(), nrnb, fr->pmedata,
-            pmeLoadBalanceHelper_ ? pmeLoadBalanceHelper_->loadBalancingObject() : nullptr, wcycle,
-            walltime_accounting);
+    resetHandler_->resetCounters(step,
+                                 step - inputrec->init_step,
+                                 mdlog,
+                                 fplog,
+                                 cr,
+                                 fr->nbv.get(),
+                                 nrnb,
+                                 fr->pmedata,
+                                 pmeLoadBalanceHelper_ ? pmeLoadBalanceHelper_->loadBalancingObject() : nullptr,
+                                 wcycle,
+                                 walltime_accounting);
 }
 
 void ModularSimulatorAlgorithm::populateTaskQueue()
@@ -395,29 +402,43 @@ ModularSimulatorAlgorithmBuilder::ModularSimulatorAlgorithmBuilder(
                              legacySimulatorData->startingBehavior,
                              legacySimulatorData->cr)
 {
-    if (legacySimulatorData->inputrec->efep != efepNO)
+    if (legacySimulatorData->inputrec->efep != FreeEnergyPerturbationType::No)
     {
         freeEnergyPerturbationData_ = std::make_unique<FreeEnergyPerturbationData>(
-                legacySimulatorData->fplog, legacySimulatorData->inputrec, legacySimulatorData->mdAtoms);
+                legacySimulatorData->fplog, *legacySimulatorData->inputrec, legacySimulatorData->mdAtoms);
     }
 
     statePropagatorData_ = std::make_unique<StatePropagatorData>(
-            legacySimulatorData->top_global->natoms, legacySimulatorData->fplog, legacySimulatorData->cr,
-            legacySimulatorData->state_global, legacySimulatorData->fr->nbv->useGpu(),
-            legacySimulatorData->fr->bMolPBC, legacySimulatorData->mdrunOptions.writeConfout,
-            opt2fn("-c", legacySimulatorData->nfile, legacySimulatorData->fnm), legacySimulatorData->inputrec,
-            legacySimulatorData->mdAtoms->mdatoms(), legacySimulatorData->top_global);
+            legacySimulatorData->top_global.natoms,
+            legacySimulatorData->fplog,
+            legacySimulatorData->cr,
+            legacySimulatorData->state_global,
+            legacySimulatorData->fr->nbv->useGpu(),
+            legacySimulatorData->fr->bMolPBC,
+            legacySimulatorData->mdrunOptions.writeConfout,
+            opt2fn("-c", legacySimulatorData->nfile, legacySimulatorData->fnm),
+            legacySimulatorData->inputrec,
+            legacySimulatorData->mdAtoms->mdatoms(),
+            legacySimulatorData->top_global);
 
     // Multi sim is turned off
     const bool simulationsShareState = false;
 
-    energyData_ = std::make_unique<EnergyData>(
-            statePropagatorData_.get(), freeEnergyPerturbationData_.get(), legacySimulatorData->top_global,
-            legacySimulatorData->inputrec, legacySimulatorData->mdAtoms, legacySimulatorData->enerd,
-            legacySimulatorData->ekind, legacySimulatorData->constr, legacySimulatorData->fplog,
-            legacySimulatorData->fr->fcdata.get(), legacySimulatorData->mdModulesNotifier,
-            MASTER(legacySimulatorData->cr), legacySimulatorData->observablesHistory,
-            legacySimulatorData->startingBehavior, simulationsShareState);
+    energyData_ = std::make_unique<EnergyData>(statePropagatorData_.get(),
+                                               freeEnergyPerturbationData_.get(),
+                                               legacySimulatorData->top_global,
+                                               legacySimulatorData->inputrec,
+                                               legacySimulatorData->mdAtoms,
+                                               legacySimulatorData->enerd,
+                                               legacySimulatorData->ekind,
+                                               legacySimulatorData->constr,
+                                               legacySimulatorData->fplog,
+                                               legacySimulatorData->fr->fcdata.get(),
+                                               legacySimulatorData->mdModulesNotifiers,
+                                               MASTER(legacySimulatorData->cr),
+                                               legacySimulatorData->observablesHistory,
+                                               legacySimulatorData->startingBehavior,
+                                               simulationsShareState);
 }
 
 ModularSimulatorAlgorithm ModularSimulatorAlgorithmBuilder::build()
@@ -430,26 +451,24 @@ ModularSimulatorAlgorithm ModularSimulatorAlgorithmBuilder::build()
     algorithmHasBeenBuilt_ = true;
 
     // Connect propagators with thermostat / barostat
-    for (const auto& thermostatRegistration : thermostatRegistrationFunctions_)
+    for (const auto& registrationFunction : pressureTemperatureControlRegistrationFunctions_)
     {
-        for (const auto& connection : propagatorThermostatConnections_)
+        for (const auto& connection : propagatorConnections_)
         {
-            thermostatRegistration(connection);
-        }
-    }
-    for (const auto& barostatRegistration : barostatRegistrationFunctions_)
-    {
-        for (const auto& connection : propagatorBarostatConnections_)
-        {
-            barostatRegistration(connection);
+            registrationFunction(connection);
         }
     }
 
-    ModularSimulatorAlgorithm algorithm(
-            *(legacySimulatorData_->top_global->name), legacySimulatorData_->fplog,
-            legacySimulatorData_->cr, legacySimulatorData_->mdlog, legacySimulatorData_->mdrunOptions,
-            legacySimulatorData_->inputrec, legacySimulatorData_->nrnb, legacySimulatorData_->wcycle,
-            legacySimulatorData_->fr, legacySimulatorData_->walltime_accounting);
+    ModularSimulatorAlgorithm algorithm(*(legacySimulatorData_->top_global.name),
+                                        legacySimulatorData_->fplog,
+                                        legacySimulatorData_->cr,
+                                        legacySimulatorData_->mdlog,
+                                        legacySimulatorData_->mdrunOptions,
+                                        legacySimulatorData_->inputrec,
+                                        legacySimulatorData_->nrnb,
+                                        legacySimulatorData_->wcycle,
+                                        legacySimulatorData_->fr,
+                                        legacySimulatorData_->walltime_accounting);
     registerWithInfrastructureAndSignallers(algorithm.signalHelper_.get());
     algorithm.statePropagatorData_        = std::move(statePropagatorData_);
     algorithm.energyData_                 = std::move(energyData_);
@@ -463,11 +482,16 @@ ModularSimulatorAlgorithm ModularSimulatorAlgorithmBuilder::build()
     algorithm.stopHandler_ = legacySimulatorData_->stopHandlerBuilder->getStopHandlerMD(
             compat::not_null<SimulationSignal*>(
                     &(*globalCommunicationHelper_.simulationSignals())[eglsSTOPCOND]),
-            simulationsShareState, MASTER(legacySimulatorData_->cr),
-            legacySimulatorData_->inputrec->nstlist, legacySimulatorData_->mdrunOptions.reproducible,
-            globalCommunicationHelper_.nstglobalcomm(), legacySimulatorData_->mdrunOptions.maximumHoursToRun,
-            legacySimulatorData_->inputrec->nstlist == 0, legacySimulatorData_->fplog,
-            algorithm.stophandlerCurrentStep_, algorithm.stophandlerIsNSStep_,
+            simulationsShareState,
+            MASTER(legacySimulatorData_->cr),
+            legacySimulatorData_->inputrec->nstlist,
+            legacySimulatorData_->mdrunOptions.reproducible,
+            globalCommunicationHelper_.nstglobalcomm(),
+            legacySimulatorData_->mdrunOptions.maximumHoursToRun,
+            legacySimulatorData_->inputrec->nstlist == 0,
+            legacySimulatorData_->fplog,
+            algorithm.stophandlerCurrentStep_,
+            algorithm.stophandlerIsNSStep_,
             legacySimulatorData_->walltime_accounting);
 
     // Build reset handler
@@ -475,26 +499,38 @@ ModularSimulatorAlgorithm ModularSimulatorAlgorithmBuilder::build()
     algorithm.resetHandler_                  = std::make_unique<ResetHandler>(
             compat::make_not_null<SimulationSignal*>(
                     &(*globalCommunicationHelper_.simulationSignals())[eglsRESETCOUNTERS]),
-            simulationsShareResetCounters, legacySimulatorData_->inputrec->nsteps,
-            MASTER(legacySimulatorData_->cr), legacySimulatorData_->mdrunOptions.timingOptions.resetHalfway,
-            legacySimulatorData_->mdrunOptions.maximumHoursToRun, legacySimulatorData_->mdlog,
-            legacySimulatorData_->wcycle, legacySimulatorData_->walltime_accounting);
+            simulationsShareResetCounters,
+            legacySimulatorData_->inputrec->nsteps,
+            MASTER(legacySimulatorData_->cr),
+            legacySimulatorData_->mdrunOptions.timingOptions.resetHalfway,
+            legacySimulatorData_->mdrunOptions.maximumHoursToRun,
+            legacySimulatorData_->mdlog,
+            legacySimulatorData_->wcycle,
+            legacySimulatorData_->walltime_accounting);
 
     // Build topology holder
-    algorithm.topologyHolder_ = topologyHolderBuilder_.build(
-            *legacySimulatorData_->top_global, legacySimulatorData_->cr,
-            legacySimulatorData_->inputrec, legacySimulatorData_->fr, legacySimulatorData_->mdAtoms,
-            legacySimulatorData_->constr, legacySimulatorData_->vsite);
+    algorithm.topologyHolder_ = topologyHolderBuilder_.build(legacySimulatorData_->top_global,
+                                                             legacySimulatorData_->cr,
+                                                             legacySimulatorData_->inputrec,
+                                                             legacySimulatorData_->fr,
+                                                             legacySimulatorData_->mdAtoms,
+                                                             legacySimulatorData_->constr,
+                                                             legacySimulatorData_->vsite);
 
     // Build PME load balance helper
     if (PmeLoadBalanceHelper::doPmeLoadBalancing(legacySimulatorData_->mdrunOptions,
                                                  legacySimulatorData_->inputrec,
                                                  legacySimulatorData_->fr))
     {
-        algorithm.pmeLoadBalanceHelper_ = std::make_unique<PmeLoadBalanceHelper>(
-                legacySimulatorData_->mdrunOptions.verbose, algorithm.statePropagatorData_.get(),
-                legacySimulatorData_->fplog, legacySimulatorData_->cr, legacySimulatorData_->mdlog,
-                legacySimulatorData_->inputrec, legacySimulatorData_->wcycle, legacySimulatorData_->fr);
+        algorithm.pmeLoadBalanceHelper_ =
+                std::make_unique<PmeLoadBalanceHelper>(legacySimulatorData_->mdrunOptions.verbose,
+                                                       algorithm.statePropagatorData_.get(),
+                                                       legacySimulatorData_->fplog,
+                                                       legacySimulatorData_->cr,
+                                                       legacySimulatorData_->mdlog,
+                                                       legacySimulatorData_->inputrec,
+                                                       legacySimulatorData_->wcycle,
+                                                       legacySimulatorData_->fr);
         registerWithInfrastructureAndSignallers(algorithm.pmeLoadBalanceHelper_.get());
     }
     // Build domdec helper
@@ -503,25 +539,39 @@ ModularSimulatorAlgorithm ModularSimulatorAlgorithmBuilder::build()
         algorithm.domDecHelper_ = std::make_unique<DomDecHelper>(
                 legacySimulatorData_->mdrunOptions.verbose,
                 legacySimulatorData_->mdrunOptions.verboseStepPrintInterval,
-                algorithm.statePropagatorData_.get(), algorithm.freeEnergyPerturbationData_.get(),
+                algorithm.statePropagatorData_.get(),
+                algorithm.freeEnergyPerturbationData_.get(),
                 algorithm.topologyHolder_.get(),
-                globalCommunicationHelper_.moveCheckBondedInteractionsCallback(),
-                globalCommunicationHelper_.nstglobalcomm(), legacySimulatorData_->fplog,
-                legacySimulatorData_->cr, legacySimulatorData_->mdlog, legacySimulatorData_->constr,
-                legacySimulatorData_->inputrec, legacySimulatorData_->mdAtoms, legacySimulatorData_->nrnb,
-                legacySimulatorData_->wcycle, legacySimulatorData_->fr, legacySimulatorData_->vsite,
-                legacySimulatorData_->imdSession, legacySimulatorData_->pull_work);
+                globalCommunicationHelper_.nstglobalcomm(),
+                legacySimulatorData_->fplog,
+                legacySimulatorData_->cr,
+                legacySimulatorData_->mdlog,
+                legacySimulatorData_->constr,
+                legacySimulatorData_->inputrec,
+                legacySimulatorData_->mdAtoms,
+                legacySimulatorData_->nrnb,
+                legacySimulatorData_->wcycle,
+                legacySimulatorData_->fr,
+                legacySimulatorData_->vsite,
+                legacySimulatorData_->imdSession,
+                legacySimulatorData_->pull_work);
         registerWithInfrastructureAndSignallers(algorithm.domDecHelper_.get());
     }
 
     // Build trajectory element
-    auto trajectoryElement = trajectoryElementBuilder_.build(
-            legacySimulatorData_->fplog, legacySimulatorData_->nfile, legacySimulatorData_->fnm,
-            legacySimulatorData_->mdrunOptions, legacySimulatorData_->cr,
-            legacySimulatorData_->outputProvider, legacySimulatorData_->mdModulesNotifier,
-            legacySimulatorData_->inputrec, legacySimulatorData_->top_global,
-            legacySimulatorData_->oenv, legacySimulatorData_->wcycle,
-            legacySimulatorData_->startingBehavior, simulationsShareState);
+    auto trajectoryElement = trajectoryElementBuilder_.build(legacySimulatorData_->fplog,
+                                                             legacySimulatorData_->nfile,
+                                                             legacySimulatorData_->fnm,
+                                                             legacySimulatorData_->mdrunOptions,
+                                                             legacySimulatorData_->cr,
+                                                             legacySimulatorData_->outputProvider,
+                                                             legacySimulatorData_->mdModulesNotifiers,
+                                                             legacySimulatorData_->inputrec,
+                                                             legacySimulatorData_->top_global,
+                                                             legacySimulatorData_->oenv,
+                                                             legacySimulatorData_->wcycle,
+                                                             legacySimulatorData_->startingBehavior,
+                                                             simulationsShareState);
     registerWithInfrastructureAndSignallers(trajectoryElement.get());
 
     // Build free energy element
@@ -538,14 +588,20 @@ ModularSimulatorAlgorithm ModularSimulatorAlgorithmBuilder::build()
     {
         checkpointHelperBuilder_.setCheckpointHandler(std::make_unique<CheckpointHandler>(
                 compat::make_not_null<SimulationSignal*>(&(*algorithm.signals_)[eglsCHKPT]),
-                simulationsShareState, legacySimulatorData_->inputrec->nstlist == 0,
-                MASTER(legacySimulatorData_->cr), legacySimulatorData_->mdrunOptions.writeConfout,
+                simulationsShareState,
+                legacySimulatorData_->inputrec->nstlist == 0,
+                MASTER(legacySimulatorData_->cr),
+                legacySimulatorData_->mdrunOptions.writeConfout,
                 legacySimulatorData_->mdrunOptions.checkpointOptions.period));
-        algorithm.checkpointHelper_ = checkpointHelperBuilder_.build(
-                legacySimulatorData_->inputrec->init_step, trajectoryElement.get(),
-                legacySimulatorData_->fplog, legacySimulatorData_->cr,
-                legacySimulatorData_->observablesHistory, legacySimulatorData_->walltime_accounting,
-                legacySimulatorData_->state_global, legacySimulatorData_->mdrunOptions.writeConfout);
+        algorithm.checkpointHelper_ =
+                checkpointHelperBuilder_.build(legacySimulatorData_->inputrec->init_step,
+                                               trajectoryElement.get(),
+                                               legacySimulatorData_->fplog,
+                                               legacySimulatorData_->cr,
+                                               legacySimulatorData_->observablesHistory,
+                                               legacySimulatorData_->walltime_accounting,
+                                               legacySimulatorData_->state_global,
+                                               legacySimulatorData_->mdrunOptions.writeConfout);
         registerWithInfrastructureAndSignallers(algorithm.checkpointHelper_.get());
     }
 
@@ -570,20 +626,36 @@ ModularSimulatorAlgorithm ModularSimulatorAlgorithmBuilder::build()
             registerWithInfrastructureAndSignallers(signaller.get());
             algorithm.signallerList_.emplace(algorithm.signallerList_.begin(), std::move(signaller));
         };
-        const auto* inputrec = legacySimulatorData_->inputrec;
+        const auto* inputrec   = legacySimulatorData_->inputrec;
+        auto        virialMode = EnergySignallerVirialMode::Off;
+        if (inputrec->epc != PressureCoupling::No)
+        {
+            if (EI_VV(inputrec->eI))
+            {
+                virialMode = EnergySignallerVirialMode::OnStepAndNext;
+            }
+            else
+            {
+                virialMode = EnergySignallerVirialMode::OnStep;
+            }
+        }
         addSignaller(energySignallerBuilder_.build(
-                inputrec->nstcalcenergy, inputrec->fepvals->nstdhdl, inputrec->nstpcouple));
-        addSignaller(trajectorySignallerBuilder_.build(
-                inputrec->nstxout, inputrec->nstvout, inputrec->nstfout,
-                inputrec->nstxout_compressed, trajectoryElement->tngBoxOut(),
-                trajectoryElement->tngLambdaOut(), trajectoryElement->tngBoxOutCompressed(),
-                trajectoryElement->tngLambdaOutCompressed(), inputrec->nstenergy));
-        addSignaller(loggingSignallerBuilder_.build(inputrec->nstlog, inputrec->init_step,
-                                                    legacySimulatorData_->startingBehavior));
-        addSignaller(lastStepSignallerBuilder_.build(inputrec->nsteps, inputrec->init_step,
-                                                     algorithm.stopHandler_.get()));
-        addSignaller(neighborSearchSignallerBuilder_.build(inputrec->nstlist, inputrec->init_step,
-                                                           inputrec->init_t));
+                inputrec->nstcalcenergy, inputrec->fepvals->nstdhdl, inputrec->nstpcouple, virialMode));
+        addSignaller(trajectorySignallerBuilder_.build(inputrec->nstxout,
+                                                       inputrec->nstvout,
+                                                       inputrec->nstfout,
+                                                       inputrec->nstxout_compressed,
+                                                       trajectoryElement->tngBoxOut(),
+                                                       trajectoryElement->tngLambdaOut(),
+                                                       trajectoryElement->tngBoxOutCompressed(),
+                                                       trajectoryElement->tngLambdaOutCompressed(),
+                                                       inputrec->nstenergy));
+        addSignaller(loggingSignallerBuilder_.build(
+                inputrec->nstlog, inputrec->init_step, legacySimulatorData_->startingBehavior));
+        addSignaller(lastStepSignallerBuilder_.build(
+                inputrec->nsteps, inputrec->init_step, algorithm.stopHandler_.get()));
+        addSignaller(neighborSearchSignallerBuilder_.build(
+                inputrec->nstlist, inputrec->init_step, inputrec->init_t));
     }
 
     // Create element list
@@ -621,8 +693,9 @@ ISimulatorElement* ModularSimulatorAlgorithmBuilder::addElementToSimulatorAlgori
 bool ModularSimulatorAlgorithmBuilder::elementExists(const ISimulatorElement* element) const
 {
     // Check whether element exists in element list
-    if (std::any_of(elements_.begin(), elements_.end(),
-                    [element](auto& existingElement) { return element == existingElement.get(); }))
+    if (std::any_of(elements_.begin(), elements_.end(), [element](auto& existingElement) {
+            return element == existingElement.get();
+        }))
     {
         return true;
     }
@@ -667,21 +740,6 @@ SimulationSignals* GlobalCommunicationHelper::simulationSignals()
     return simulationSignals_;
 }
 
-void GlobalCommunicationHelper::setCheckBondedInteractionsCallback(CheckBondedInteractionsCallback callback)
-{
-    checkBondedInteractionsCallback_ = std::move(callback);
-}
-
-CheckBondedInteractionsCallback GlobalCommunicationHelper::moveCheckBondedInteractionsCallback()
-{
-    if (!checkBondedInteractionsCallback_)
-    {
-        throw SimulationAlgorithmSetupError(
-                "Requested CheckBondedInteractionsCallback before it was set.");
-    }
-    return *checkBondedInteractionsCallback_;
-}
-
 ModularSimulatorAlgorithmBuilderHelper::ModularSimulatorAlgorithmBuilderHelper(
         ModularSimulatorAlgorithmBuilder* builder) :
     builder_(builder)
@@ -711,27 +769,15 @@ std::optional<std::any> ModularSimulatorAlgorithmBuilderHelper::getStoredValue(c
     }
 }
 
-void ModularSimulatorAlgorithmBuilderHelper::registerThermostat(
-        std::function<void(const PropagatorThermostatConnection&)> registrationFunction)
+void ModularSimulatorAlgorithmBuilderHelper::registerTemperaturePressureControl(
+        std::function<void(const PropagatorConnection&)> registrationFunction)
 {
-    builder_->thermostatRegistrationFunctions_.emplace_back(std::move(registrationFunction));
+    builder_->pressureTemperatureControlRegistrationFunctions_.emplace_back(std::move(registrationFunction));
 }
 
-void ModularSimulatorAlgorithmBuilderHelper::registerBarostat(
-        std::function<void(const PropagatorBarostatConnection&)> registrationFunction)
+void ModularSimulatorAlgorithmBuilderHelper::registerPropagator(PropagatorConnection connectionData)
 {
-    builder_->barostatRegistrationFunctions_.emplace_back(std::move(registrationFunction));
+    builder_->propagatorConnections_.emplace_back(std::move(connectionData));
 }
 
-void ModularSimulatorAlgorithmBuilderHelper::registerWithThermostat(PropagatorThermostatConnection connectionData)
-{
-    builder_->propagatorThermostatConnections_.emplace_back(std::move(connectionData));
-}
-
-void ModularSimulatorAlgorithmBuilderHelper::registerWithBarostat(PropagatorBarostatConnection connectionData)
-{
-    builder_->propagatorBarostatConnections_.emplace_back(std::move(connectionData));
-}
-
-
 } // namespace gmx
index e1e94f9150cb9b9b869c34bdc3fce135dc5e864e..a7e9e2a62f6331fd7ff191f82a4e614a7dd82edc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 namespace gmx
 {
-enum class IntegrationStep;
+enum class IntegrationStage;
 class EnergyData;
 class ModularSimulator;
 class ResetHandler;
-template<IntegrationStep algorithm>
+template<IntegrationStage integrationStage>
 class Propagator;
 class TopologyHolder;
 
@@ -108,7 +108,7 @@ private:
                               t_commrec*               cr,
                               const MDLogger&          mdlog,
                               const MdrunOptions&      mdrunOptions,
-                              t_inputrec*              inputrec,
+                              const t_inputrec*        inputrec,
                               t_nrnb*                  nrnb,
                               gmx_wallcycle*           wcycle,
                               t_forcerec*              fr,
@@ -263,7 +263,7 @@ private:
     //! Contains command-line options to mdrun.
     const MdrunOptions& mdrunOptions;
     //! Contains user input mdp options.
-    t_inputrec* inputrec;
+    const t_inputrec* inputrec;
     //! Manages flop accounting.
     t_nrnb* nrnb;
     //! Manages wall cycle accounting.
@@ -292,18 +292,11 @@ public:
     //! Get a pointer to the signals vector
     [[nodiscard]] SimulationSignals* simulationSignals();
 
-    //! Set the callback to check the number of bonded interactions
-    void setCheckBondedInteractionsCallback(CheckBondedInteractionsCallback callback);
-    //! Move the callback to check the number of bonded interactions
-    [[nodiscard]] CheckBondedInteractionsCallback moveCheckBondedInteractionsCallback();
-
 private:
     //! Compute globals communication period
     const int nstglobalcomm_;
     //! Signal vector (used by stop / reset / checkpointing signaller)
     SimulationSignals* simulationSignals_;
-    //! Callback to check the number of bonded interactions
-    std::optional<CheckBondedInteractionsCallback> checkBondedInteractionsCallback_;
 };
 
 class ModularSimulatorAlgorithmBuilder;
@@ -331,14 +324,10 @@ public:
     void storeValue(const std::string& key, const ValueType& value);
     //! Get previously stored data. Returns std::nullopt if key is not found.
     std::optional<std::any> getStoredValue(const std::string& key) const;
-    //! Register a thermostat that accepts propagator registrations
-    void registerThermostat(std::function<void(const PropagatorThermostatConnection&)> registrationFunction);
-    //! Register a barostat that accepts propagator registrations
-    void registerBarostat(std::function<void(const PropagatorBarostatConnection&)> registrationFunction);
-    //! Register a propagator to the thermostat used
-    void registerWithThermostat(PropagatorThermostatConnection connectionData);
-    //! Register a propagator to the barostat used
-    void registerWithBarostat(PropagatorBarostatConnection connectionData);
+    //! Register temperature / pressure control algorithm to be matched with a propagator
+    void registerTemperaturePressureControl(std::function<void(const PropagatorConnection&)> registrationFunction);
+    //! Register a propagator to be used with a temperature / pressure control algorithm
+    void registerPropagator(PropagatorConnection connectionData);
 
 private:
     //! Pointer to the associated ModularSimulatorAlgorithmBuilder
@@ -481,14 +470,10 @@ private:
      */
     std::vector<ICheckpointHelperClient*> checkpointClients_;
 
-    //! List of thermostat registration functions
-    std::vector<std::function<void(const PropagatorThermostatConnection&)>> thermostatRegistrationFunctions_;
-    //! List of barostat registration functions
-    std::vector<std::function<void(const PropagatorBarostatConnection&)>> barostatRegistrationFunctions_;
-    //! List of data to connect propagators to thermostats
-    std::vector<PropagatorThermostatConnection> propagatorThermostatConnections_;
-    //! List of data to connect propagators to barostats
-    std::vector<PropagatorBarostatConnection> propagatorBarostatConnections_;
+    //! List of data to connect propagators to thermostats / barostats
+    std::vector<PropagatorConnection> propagatorConnections_;
+    //! List of temperature / pressure control registration functions
+    std::vector<std::function<void(const PropagatorConnection&)>> pressureTemperatureControlRegistrationFunctions_;
 };
 
 /*! \internal
@@ -549,9 +534,13 @@ ISimulatorElement* getElementPointer(LegacySimulatorData*                    leg
                                      GlobalCommunicationHelper*  globalCommunicationHelper,
                                      Args&&... args)
 {
-    return Element::getElementPointerImpl(legacySimulatorData, builderHelper, statePropagatorData,
-                                          energyData, freeEnergyPerturbationData,
-                                          globalCommunicationHelper, std::forward<Args>(args)...);
+    return Element::getElementPointerImpl(legacySimulatorData,
+                                          builderHelper,
+                                          statePropagatorData,
+                                          energyData,
+                                          freeEnergyPerturbationData,
+                                          globalCommunicationHelper,
+                                          std::forward<Args>(args)...);
 }
 
 template<typename Element, typename... Args>
@@ -564,10 +553,13 @@ void ModularSimulatorAlgorithmBuilder::add(Args&&... args)
     }
 
     // Get element from factory method
-    auto* element = static_cast<Element*>(getElementPointer<Element>(
-            legacySimulatorData_, &elementAdditionHelper_, statePropagatorData_.get(),
-            energyData_.get(), freeEnergyPerturbationData_.get(), &globalCommunicationHelper_,
-            std::forward<Args>(args)...));
+    auto* element = static_cast<Element*>(getElementPointer<Element>(legacySimulatorData_,
+                                                                     &elementAdditionHelper_,
+                                                                     statePropagatorData_.get(),
+                                                                     energyData_.get(),
+                                                                     freeEnergyPerturbationData_.get(),
+                                                                     &globalCommunicationHelper_,
+                                                                     std::forward<Args>(args)...));
 
     // Make sure returned element pointer is owned by *this
     // Ensuring this makes sure we can control the life time
index 92691193211a10c919416d3762627a8fda0a6003..4dd6a899f27f8bd358a543a8e2a4ecec5f22eaea 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "gmxpre.h"
 
+#include "gromacs/utility/enumerationhelpers.h"
 #include "statepropagatordata.h"
 
 #include "gromacs/commandline/filenm.h"
@@ -82,7 +83,7 @@ StatePropagatorData::StatePropagatorData(int                numAtoms,
                                          const std::string& finalConfigurationFilename,
                                          const t_inputrec*  inputrec,
                                          const t_mdatoms*   mdatoms,
-                                         const gmx_mtop_t*  globalTop) :
+                                         const gmx_mtop_t&  globalTop) :
     totalNumAtoms_(numAtoms),
     localNAtoms_(0),
     box_{ { 0 } },
@@ -110,8 +111,8 @@ StatePropagatorData::StatePropagatorData(int                numAtoms,
     if (DOMAINDECOMP(cr))
     {
         auto localState = std::make_unique<t_state>();
-        dd_init_local_state(cr->dd, globalState, localState.get());
-        stateHasVelocities = ((static_cast<unsigned int>(localState->flags) & (1U << estV)) != 0U);
+        dd_init_local_state(*cr->dd, globalState, localState.get());
+        stateHasVelocities = ((localState->flags & enumValueToBitMask(StateEntry::V)) != 0);
         setLocalState(std::move(localState));
     }
     else
@@ -122,7 +123,7 @@ StatePropagatorData::StatePropagatorData(int                numAtoms,
         x_           = globalState->x;
         v_           = globalState->v;
         copy_mat(globalState->box, box_);
-        stateHasVelocities = ((static_cast<unsigned int>(globalState->flags) & (1U << estV)) != 0U);
+        stateHasVelocities = ((globalState->flags & enumValueToBitMask(StateEntry::V)) != 0);
         previousX_.resizeWithPadding(localNAtoms_);
         ddpCount_ = globalState->ddp_count;
         copyPosition();
@@ -148,7 +149,7 @@ StatePropagatorData::StatePropagatorData(int                numAtoms,
             // Set the velocities of vsites, shells and frozen atoms to zero
             for (int i = 0; i < mdatoms->homenr; i++)
             {
-                if (mdatoms->ptype[i] == eptVSite || mdatoms->ptype[i] == eptShell)
+                if (mdatoms->ptype[i] == ParticleType::Shell)
                 {
                     clear_rvec(v[i]);
                 }
@@ -164,7 +165,7 @@ StatePropagatorData::StatePropagatorData(int                numAtoms,
                 }
             }
         }
-        if (inputrec->eI == eiVV)
+        if (inputrec->eI == IntegrationAlgorithm::VV)
         {
             vvResetVelocities_ = true;
         }
@@ -257,7 +258,8 @@ int StatePropagatorData::totalNumAtoms() const
 std::unique_ptr<t_state> StatePropagatorData::localState()
 {
     auto state   = std::make_unique<t_state>();
-    state->flags = (1U << estX) | (1U << estV) | (1U << estBOX);
+    state->flags = enumValueToBitMask(StateEntry::X) | enumValueToBitMask(StateEntry::V)
+                   | enumValueToBitMask(StateEntry::Box);
     state_change_natoms(state.get(), localNAtoms_);
     state->x = x_;
     state->v = v_;
@@ -307,7 +309,7 @@ ForceBuffers* StatePropagatorData::forcePointer()
 
 void StatePropagatorData::copyPosition()
 {
-    int nth = gmx_omp_nthreads_get(emntUpdate);
+    int nth = gmx_omp_nthreads_get(ModuleMultiThread::Update);
 
 #pragma omp parallel for num_threads(nth) schedule(static) default(none) shared(nth)
     for (int th = 0; th < nth; th++)
@@ -357,12 +359,11 @@ void StatePropagatorData::Element::saveState()
     localStateBackup_ = statePropagatorData_->localState();
     if (freeEnergyPerturbationData_)
     {
-        localStateBackup_->fep_state = freeEnergyPerturbationData_->currentFEPState();
-        for (unsigned long i = 0; i < localStateBackup_->lambda.size(); ++i)
-        {
-            localStateBackup_->lambda[i] = freeEnergyPerturbationData_->constLambdaView()[i];
-        }
-        localStateBackup_->flags |= (1U << estLAMBDA) | (1U << estFEPSTATE);
+        localStateBackup_->fep_state    = freeEnergyPerturbationData_->currentFEPState();
+        ArrayRef<const real> lambdaView = freeEnergyPerturbationData_->constLambdaView();
+        std::copy(lambdaView.begin(), lambdaView.end(), localStateBackup_->lambda.begin());
+        localStateBackup_->flags |=
+                enumValueToBitMask(StateEntry::Lambda) | enumValueToBitMask(StateEntry::FepState);
     }
 }
 
@@ -392,7 +393,7 @@ StatePropagatorData::Element::registerTrajectoryWriterCallback(TrajectoryEvent e
 
 void StatePropagatorData::Element::write(gmx_mdoutf_t outf, Step currentStep, Time currentTime)
 {
-    wallcycle_start(mdoutf_get_wcycle(outf), ewcTRAJ);
+    wallcycle_start(mdoutf_get_wcycle(outf), WallCycleCounter::Traj);
     unsigned int mdof_flags = 0;
     if (do_per_step(currentStep, nstxout_))
     {
@@ -429,7 +430,7 @@ void StatePropagatorData::Element::write(gmx_mdoutf_t outf, Step currentStep, Ti
 
     if (mdof_flags == 0)
     {
-        wallcycle_stop(mdoutf_get_wcycle(outf), ewcTRAJ);
+        wallcycle_stop(mdoutf_get_wcycle(outf), WallCycleCounter::Traj);
         return;
     }
     GMX_ASSERT(localStateBackup_, "Trajectory writing called, but no state saved.");
@@ -437,16 +438,24 @@ void StatePropagatorData::Element::write(gmx_mdoutf_t outf, Step currentStep, Ti
     // TODO: This is only used for CPT - needs to be filled when we turn CPT back on
     ObservablesHistory* observablesHistory = nullptr;
 
-    mdoutf_write_to_trajectory_files(
-            fplog_, cr_, outf, static_cast<int>(mdof_flags), statePropagatorData_->totalNumAtoms_,
-            currentStep, currentTime, localStateBackup_.get(), statePropagatorData_->globalState_,
-            observablesHistory, statePropagatorData_->f_.view().force(), &dummyCheckpointDataHolder_);
+    mdoutf_write_to_trajectory_files(fplog_,
+                                     cr_,
+                                     outf,
+                                     static_cast<int>(mdof_flags),
+                                     statePropagatorData_->totalNumAtoms_,
+                                     currentStep,
+                                     currentTime,
+                                     localStateBackup_.get(),
+                                     statePropagatorData_->globalState_,
+                                     observablesHistory,
+                                     statePropagatorData_->f_.view().force(),
+                                     &dummyCheckpointDataHolder_);
 
     if (currentStep != lastStep_ || !isRegularSimulationEnd_)
     {
         localStateBackup_.reset();
     }
-    wallcycle_stop(mdoutf_get_wcycle(outf), ewcTRAJ);
+    wallcycle_stop(mdoutf_get_wcycle(outf), WallCycleCounter::Traj);
 }
 
 void StatePropagatorData::Element::elementSetup()
@@ -507,11 +516,17 @@ void StatePropagatorData::Element::saveCheckpointState(std::optional<WriteCheckp
     if (DOMAINDECOMP(cr))
     {
         // Collect state from all ranks into global vectors
-        dd_collect_vec(cr->dd, statePropagatorData_->ddpCount_, statePropagatorData_->ddpCountCgGl_,
-                       statePropagatorData_->cgGl_, statePropagatorData_->x_,
+        dd_collect_vec(cr->dd,
+                       statePropagatorData_->ddpCount_,
+                       statePropagatorData_->ddpCountCgGl_,
+                       statePropagatorData_->cgGl_,
+                       statePropagatorData_->x_,
                        statePropagatorData_->xGlobal_);
-        dd_collect_vec(cr->dd, statePropagatorData_->ddpCount_, statePropagatorData_->ddpCountCgGl_,
-                       statePropagatorData_->cgGl_, statePropagatorData_->v_,
+        dd_collect_vec(cr->dd,
+                       statePropagatorData_->ddpCount_,
+                       statePropagatorData_->ddpCountCgGl_,
+                       statePropagatorData_->cgGl_,
+                       statePropagatorData_->v_,
                        statePropagatorData_->vGlobal_);
     }
     else
@@ -519,9 +534,11 @@ void StatePropagatorData::Element::saveCheckpointState(std::optional<WriteCheckp
         // Everything is local - copy local vectors into global ones
         statePropagatorData_->xGlobal_.resizeWithPadding(statePropagatorData_->totalNumAtoms());
         statePropagatorData_->vGlobal_.resizeWithPadding(statePropagatorData_->totalNumAtoms());
-        std::copy(statePropagatorData_->x_.begin(), statePropagatorData_->x_.end(),
+        std::copy(statePropagatorData_->x_.begin(),
+                  statePropagatorData_->x_.end(),
                   statePropagatorData_->xGlobal_.begin());
-        std::copy(statePropagatorData_->v_.begin(), statePropagatorData_->v_.end(),
+        std::copy(statePropagatorData_->v_.begin(),
+                  statePropagatorData_->v_.end(),
                   statePropagatorData_->vGlobal_.begin());
     }
     if (MASTER(cr))
@@ -563,9 +580,12 @@ void StatePropagatorData::Element::restoreCheckpointState(std::optional<ReadChec
     // Copy data to global state to be distributed by DD at setup stage
     if (DOMAINDECOMP(cr) && MASTER(cr))
     {
-        updateGlobalState(statePropagatorData_->globalState_, statePropagatorData_->xGlobal_,
-                          statePropagatorData_->vGlobal_, statePropagatorData_->box_,
-                          statePropagatorData_->ddpCount_, statePropagatorData_->ddpCountCgGl_,
+        updateGlobalState(statePropagatorData_->globalState_,
+                          statePropagatorData_->xGlobal_,
+                          statePropagatorData_->vGlobal_,
+                          statePropagatorData_->box_,
+                          statePropagatorData_->ddpCount_,
+                          statePropagatorData_->ddpCountCgGl_,
                           statePropagatorData_->cgGl_);
     }
     // Everything is local - copy global vectors to local ones
@@ -573,9 +593,11 @@ void StatePropagatorData::Element::restoreCheckpointState(std::optional<ReadChec
     {
         statePropagatorData_->x_.resizeWithPadding(statePropagatorData_->totalNumAtoms_);
         statePropagatorData_->v_.resizeWithPadding(statePropagatorData_->totalNumAtoms_);
-        std::copy(statePropagatorData_->xGlobal_.begin(), statePropagatorData_->xGlobal_.end(),
+        std::copy(statePropagatorData_->xGlobal_.begin(),
+                  statePropagatorData_->xGlobal_.end(),
                   statePropagatorData_->x_.begin());
-        std::copy(statePropagatorData_->vGlobal_.begin(), statePropagatorData_->vGlobal_.end(),
+        std::copy(statePropagatorData_->vGlobal_.begin(),
+                  statePropagatorData_->vGlobal_.end(),
                   statePropagatorData_->v_.begin());
     }
 }
@@ -597,17 +619,25 @@ void StatePropagatorData::Element::trajectoryWriterTeardown(gmx_mdoutf* gmx_unus
 
     GMX_ASSERT(localStateBackup_, "Final trajectory writing called, but no state saved.");
 
-    wallcycle_start(mdoutf_get_wcycle(outf), ewcTRAJ);
+    wallcycle_start(mdoutf_get_wcycle(outf), WallCycleCounter::Traj);
     if (DOMAINDECOMP(cr_))
     {
         auto globalXRef =
                 MASTER(cr_) ? statePropagatorData_->globalState_->x : gmx::ArrayRef<gmx::RVec>();
-        dd_collect_vec(cr_->dd, localStateBackup_->ddp_count, localStateBackup_->ddp_count_cg_gl,
-                       localStateBackup_->cg_gl, localStateBackup_->x, globalXRef);
+        dd_collect_vec(cr_->dd,
+                       localStateBackup_->ddp_count,
+                       localStateBackup_->ddp_count_cg_gl,
+                       localStateBackup_->cg_gl,
+                       localStateBackup_->x,
+                       globalXRef);
         auto globalVRef =
                 MASTER(cr_) ? statePropagatorData_->globalState_->v : gmx::ArrayRef<gmx::RVec>();
-        dd_collect_vec(cr_->dd, localStateBackup_->ddp_count, localStateBackup_->ddp_count_cg_gl,
-                       localStateBackup_->cg_gl, localStateBackup_->v, globalVRef);
+        dd_collect_vec(cr_->dd,
+                       localStateBackup_->ddp_count,
+                       localStateBackup_->ddp_count_cg_gl,
+                       localStateBackup_->cg_gl,
+                       localStateBackup_->v,
+                       globalVRef);
     }
     else
     {
@@ -621,15 +651,20 @@ void StatePropagatorData::Element::trajectoryWriterTeardown(gmx_mdoutf* gmx_unus
         if (canMoleculesBeDistributedOverPBC_ && !systemHasPeriodicMolecules_)
         {
             // Make molecules whole only for confout writing
-            do_pbc_mtop(pbcType_, localStateBackup_->box, top_global_,
+            do_pbc_mtop(pbcType_,
+                        localStateBackup_->box,
+                        &top_global_,
                         statePropagatorData_->globalState_->x.rvec_array());
         }
-        write_sto_conf_mtop(finalConfigurationFilename_.c_str(), *top_global_->name, top_global_,
+        write_sto_conf_mtop(finalConfigurationFilename_.c_str(),
+                            *top_global_.name,
+                            top_global_,
                             statePropagatorData_->globalState_->x.rvec_array(),
-                            statePropagatorData_->globalState_->v.rvec_array(), pbcType_,
+                            statePropagatorData_->globalState_->v.rvec_array(),
+                            pbcType_,
                             localStateBackup_->box);
     }
-    wallcycle_stop(mdoutf_get_wcycle(outf), ewcTRAJ);
+    wallcycle_stop(mdoutf_get_wcycle(outf), WallCycleCounter::Traj);
 }
 
 std::optional<SignallerCallback> StatePropagatorData::Element::registerLastStepCallback()
@@ -651,7 +686,7 @@ StatePropagatorData::Element::Element(StatePropagatorData* statePropagatorData,
                                       bool                 writeFinalConfiguration,
                                       std::string          finalConfigurationFilename,
                                       const t_inputrec*    inputrec,
-                                      const gmx_mtop_t*    globalTop) :
+                                      const gmx_mtop_t&    globalTop) :
     statePropagatorData_(statePropagatorData),
     nstxout_(nstxout),
     nstvout_(nstvout),
index fe277200617671a5cdbf863b6123a240db7869e7..3994d8b62486857714168dffad3f77fe7141cbb6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ public:
                         const std::string& finalConfigurationFilename,
                         const t_inputrec*  inputrec,
                         const t_mdatoms*   mdatoms,
-                        const gmx_mtop_t*  globalTop);
+                        const gmx_mtop_t&  globalTop);
 
     // Allow access to state
     //! Get write access to position vector
@@ -274,7 +274,7 @@ public:
             bool                 writeFinalConfiguration,
             std::string          finalConfigurationFilename,
             const t_inputrec*    inputrec,
-            const gmx_mtop_t*    globalTop);
+            const gmx_mtop_t&    globalTop);
 
     /*! \brief Register run function for step / time
      *
@@ -399,7 +399,7 @@ private:
     //! Handles communication.
     const t_commrec* cr_;
     //! Full system topology.
-    const gmx_mtop_t* top_global_;
+    const gmx_mtop_t& top_global_;
 };
 
 } // namespace gmx
index 8fb91190b05ee8f9cd7d8ba3fd7354392e4dc3b2..bbef75bad29a492de2550ede9f0b69fce9f4fe7c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +70,8 @@ TopologyHolder::TopologyHolder(std::vector<ITopologyHolderClient*> clients,
         // Note: Legacy mdrun resizes the force buffer in mdAlgorithmsSetupAtomData()
         //       TopologyHolder has no access to the forces, so we are passing a nullptr
         //       TODO: Find a unique approach to resizing the forces in modular simulator (#3461)
-        mdAlgorithmsSetupAtomData(cr, inputrec, globalTopology, localTopology_.get(), fr, nullptr,
-                                  mdAtoms, constr, vsite, nullptr);
+        mdAlgorithmsSetupAtomData(
+                cr, *inputrec, globalTopology, localTopology_.get(), fr, nullptr, mdAtoms, constr, vsite, nullptr);
     }
     // Send copy of initial topology to clients
     updateLocalTopology();
index 5a4b55cbabf164a515d282bca1642c5c52cb8272..276d80d9745fbc5279223a85d1d7a6494d655f83 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +56,9 @@ TrajectoryElement::TrajectoryElement(std::vector<ITrajectoryWriterClient*> write
                                      const MdrunOptions&                   mdrunOptions,
                                      const t_commrec*                      cr,
                                      gmx::IMDOutputProvider*               outputProvider,
-                                     const MdModulesNotifier&              mdModulesNotifier,
+                                     const MDModulesNotifiers&             mdModulesNotifiers,
                                      const t_inputrec*                     inputrec,
-                                     const gmx_mtop_t*                     top_global,
+                                     const gmx_mtop_t&                     top_global,
                                      const gmx_output_env_t*               oenv,
                                      gmx_wallcycle*                        wcycle,
                                      StartingBehavior                      startingBehavior,
@@ -72,7 +72,7 @@ TrajectoryElement::TrajectoryElement(std::vector<ITrajectoryWriterClient*> write
                       mdrunOptions,
                       cr,
                       outputProvider,
-                      mdModulesNotifier,
+                      mdModulesNotifiers,
                       inputrec,
                       top_global,
                       oenv,
index 5b3d60001948fda0823b66bcf714070214f003a0..4f8d487eacba056bf98172bd078338d2b3c00be7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ struct t_inputrec;
 namespace gmx
 {
 class IMDOutputProvider;
-struct MdModulesNotifier;
+struct MDModulesNotifiers;
 struct MdrunOptions;
 enum class StartingBehavior;
 
@@ -135,9 +135,9 @@ private:
                       const MdrunOptions&                   mdrunOptions,
                       const t_commrec*                      cr,
                       IMDOutputProvider*                    outputProvider,
-                      const MdModulesNotifier&              mdModulesNotifier,
+                      const MDModulesNotifiers&             mdModulesNotifiers,
                       const t_inputrec*                     inputrec,
-                      const gmx_mtop_t*                     top_global,
+                      const gmx_mtop_t&                     top_global,
                       const gmx_output_env_t*               oenv,
                       gmx_wallcycle*                        wcycle,
                       StartingBehavior                      startingBehavior,
index 3a2e482b54d46337ad9f482b848560c4e69ea74c..3f323c1acf04f1651d68632550bc743105eb694e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/mdtypes/group.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/strconvert.h"
 
 #include "modularsimulator.h"
 #include "simulatoralgorithm.h"
@@ -87,8 +88,8 @@ class ITemperatureCouplingImpl
 {
 public:
     //! Allow access to the scaling vectors
-    virtual void connectWithPropagator(const PropagatorThermostatConnection& connectionData,
-                                       int numTemperatureGroups) = 0;
+    virtual void connectWithPropagator(const PropagatorConnection& connectionData,
+                                       int                         numTemperatureGroups) = 0;
 
     /*! \brief Make a temperature control step
      *
@@ -138,15 +139,17 @@ public:
         }
 
         const real referenceKineticEnergy =
-                0.5 * temperatureCouplingData.referenceTemperature[temperatureGroup] * BOLTZ
+                0.5 * temperatureCouplingData.referenceTemperature[temperatureGroup] * gmx::c_boltz
                 * temperatureCouplingData.numDegreesOfFreedom[temperatureGroup];
 
         const real newKineticEnergy =
-                vrescale_resamplekin(currentKineticEnergy, referenceKineticEnergy,
+                vrescale_resamplekin(currentKineticEnergy,
+                                     referenceKineticEnergy,
                                      temperatureCouplingData.numDegreesOfFreedom[temperatureGroup],
                                      temperatureCouplingData.couplingTime[temperatureGroup]
                                              / temperatureCouplingData.couplingTimeStep,
-                                     step, seed_);
+                                     step,
+                                     seed_);
 
         // Analytically newKineticEnergy >= 0, but we check for rounding errors
         if (newKineticEnergy <= 0)
@@ -160,8 +163,12 @@ public:
 
         if (debug)
         {
-            fprintf(debug, "TC: group %d: Ekr %g, Ek %g, Ek_new %g, Lambda: %g\n", temperatureGroup,
-                    referenceKineticEnergy, currentKineticEnergy, newKineticEnergy,
+            fprintf(debug,
+                    "TC: group %d: Ekr %g, Ek %g, Ek_new %g, Lambda: %g\n",
+                    temperatureGroup,
+                    referenceKineticEnergy,
+                    currentKineticEnergy,
+                    newKineticEnergy,
                     lambdaStartVelocities_[temperatureGroup]);
         }
 
@@ -170,11 +177,12 @@ public:
     }
 
     //! Connect with propagator - v-rescale only scales start step velocities
-    void connectWithPropagator(const PropagatorThermostatConnection& connectionData,
-                               int                                   numTemperatureGroups) override
+    void connectWithPropagator(const PropagatorConnection& connectionData, int numTemperatureGroups) override
     {
-        connectionData.setNumVelocityScalingVariables(numTemperatureGroups);
-        lambdaStartVelocities_ = connectionData.getViewOnVelocityScaling();
+        GMX_RELEASE_ASSERT(connectionData.hasStartVelocityScaling(),
+                           "V-Rescale requires start velocity scaling.");
+        connectionData.setNumVelocityScalingVariables(numTemperatureGroups, ScaleVelocities::PreStepOnly);
+        lambdaStartVelocities_ = connectionData.getViewOnStartVelocityScaling();
     }
 
     //! No data to write to checkpoint
@@ -230,8 +238,11 @@ public:
                 std::max<real>(std::min<real>(lambda, 1.25_real), 0.8_real);
         if (debug)
         {
-            fprintf(debug, "TC: group %d: T: %g, Lambda: %g\n", temperatureGroup,
-                    currentTemperature, lambdaStartVelocities_[temperatureGroup]);
+            fprintf(debug,
+                    "TC: group %d: T: %g, Lambda: %g\n",
+                    temperatureGroup,
+                    currentTemperature,
+                    lambdaStartVelocities_[temperatureGroup]);
         }
         return temperatureCouplingData.temperatureCouplingIntegral[temperatureGroup]
                - (lambdaStartVelocities_[temperatureGroup] * lambdaStartVelocities_[temperatureGroup]
@@ -239,11 +250,12 @@ public:
     }
 
     //! Connect with propagator - Berendsen only scales start step velocities
-    void connectWithPropagator(const PropagatorThermostatConnection& connectionData,
-                               int                                   numTemperatureGroups) override
+    void connectWithPropagator(const PropagatorConnection& connectionData, int numTemperatureGroups) override
     {
-        connectionData.setNumVelocityScalingVariables(numTemperatureGroups);
-        lambdaStartVelocities_ = connectionData.getViewOnVelocityScaling();
+        GMX_RELEASE_ASSERT(connectionData.hasStartVelocityScaling(),
+                           "Berendsen T-coupling requires start velocity scaling.");
+        connectionData.setNumVelocityScalingVariables(numTemperatureGroups, ScaleVelocities::PreStepOnly);
+        lambdaStartVelocities_ = connectionData.getViewOnStartVelocityScaling();
     }
 
     //! No data to write to checkpoint
@@ -262,6 +274,174 @@ private:
     ArrayRef<real> lambdaStartVelocities_;
 };
 
+// Prepare NoseHooverTemperatureCoupling checkpoint data
+namespace
+{
+/*!
+ * \brief Enum describing the contents NoseHoover writes to modular checkpoint
+ *
+ * When changing the checkpoint content, add a new element just above Count, and adjust the
+ * checkpoint functionality.
+ */
+enum class NHCheckpointVersion
+{
+    Base, //!< First version of modular checkpointing
+    Count //!< Number of entries. Add new versions right above this!
+};
+constexpr auto c_nhCurrentVersion = NHCheckpointVersion(int(NHCheckpointVersion::Count) - 1);
+} // namespace
+
+/*! \internal
+ * \brief Implements the Nose-Hoover temperature coupling
+ */
+class NoseHooverTemperatureCoupling final : public ITemperatureCouplingImpl
+{
+public:
+    //! Apply the Nose-Hoover temperature control
+    real apply(Step gmx_unused                step,
+               int                            temperatureGroup,
+               real                           currentKineticEnergy,
+               real                           currentTemperature,
+               const TemperatureCouplingData& thermostatData) override
+    {
+        return applyLeapFrog(
+                step, temperatureGroup, currentKineticEnergy, currentTemperature, thermostatData);
+    }
+
+    /*! \brief Apply for leap-frog
+     *
+     * This is called after the force calculation, before coordinate update
+     *
+     * We expect system to be at x(t), v(t-dt/2), f(t), T(t-dt/2)
+     * Internal variables are at xi(t-dt), v_xi(t-dt)
+     * Force on xi is calculated at time of system temperature
+     * After calling this, we will have xi(t), v_xi(t)
+     * The thermostat integral returned is a function of xi and v_xi,
+     * and hence at time t.
+     *
+     * This performs an update of the thermostat variables calculated as
+     *     a_xi(t-dt/2) = (T_sys(t-dt/2) - T_ref) / mass_xi;
+     *     v_xi(t) = v_xi(t-dt) + dt_xi * a_xi(t-dt/2);
+     *     xi(t) = xi(t-dt) + dt_xi * (v_xi(t-dt) + v_xi(t))/2;
+     *
+     * This will be followed by leap-frog integration of coordinates, calculated as
+     *     v(t-dt/2) *= - 0.5 * dt * v_xi(t);  // scale previous velocities
+     *     v(t+dt/2) = update_leapfrog_v(v(t-dt/2), f(t));  // do whatever LF does
+     *     v(t+dt/2) *= 1 / (1 + 0.5 * dt * v_xi(t))  // scale new velocities
+     *     x(t+dt) = update_leapfrog_x(x(t), v(t+dt/2));  // do whatever LF does
+     */
+    real applyLeapFrog(Step gmx_unused                step,
+                       int                            temperatureGroup,
+                       real                           currentKineticEnergy,
+                       real                           currentTemperature,
+                       const TemperatureCouplingData& thermostatData)
+    {
+        if (!(thermostatData.couplingTime[temperatureGroup] >= 0
+              && thermostatData.numDegreesOfFreedom[temperatureGroup] > 0 && currentKineticEnergy > 0))
+        {
+            lambdaStartVelocities_[temperatureGroup] = 1.0;
+            lambdaEndVelocities_[temperatureGroup]   = 1.0;
+            return thermostatData.temperatureCouplingIntegral[temperatureGroup];
+        }
+
+        const auto oldXiVelocity = xiVelocities_[temperatureGroup];
+        const auto xiAcceleration =
+                invXiMass_[temperatureGroup]
+                * (currentTemperature - thermostatData.referenceTemperature[temperatureGroup]);
+        xiVelocities_[temperatureGroup] += thermostatData.couplingTimeStep * xiAcceleration;
+        xi_[temperatureGroup] += thermostatData.couplingTimeStep
+                                 * (oldXiVelocity + xiVelocities_[temperatureGroup]) * 0.5;
+        lambdaStartVelocities_[temperatureGroup] =
+                (1 - 0.5 * thermostatData.couplingTimeStep * xiVelocities_[temperatureGroup]);
+        lambdaEndVelocities_[temperatureGroup] =
+                1. / (1 + 0.5 * thermostatData.couplingTimeStep * xiVelocities_[temperatureGroup]);
+
+        // Current value of the thermostat integral
+        return 0.5 * c_boltz * thermostatData.numDegreesOfFreedom[temperatureGroup]
+                       * (xiVelocities_[temperatureGroup] * xiVelocities_[temperatureGroup])
+                       / invXiMass_[temperatureGroup]
+               + thermostatData.numDegreesOfFreedom[temperatureGroup] * xi_[temperatureGroup]
+                         * c_boltz * thermostatData.referenceTemperature[temperatureGroup];
+    }
+
+    //! Connect with propagator - Nose-Hoover scales start and end step velocities
+    void connectWithPropagator(const PropagatorConnection& connectionData, int numTemperatureGroups) override
+    {
+        GMX_RELEASE_ASSERT(
+                connectionData.hasStartVelocityScaling() && connectionData.hasEndVelocityScaling(),
+                "Nose-Hoover T-coupling requires both start and end velocity scaling.");
+        connectionData.setNumVelocityScalingVariables(numTemperatureGroups,
+                                                      ScaleVelocities::PreStepAndPostStep);
+        lambdaStartVelocities_ = connectionData.getViewOnStartVelocityScaling();
+        lambdaEndVelocities_   = connectionData.getViewOnEndVelocityScaling();
+    }
+
+    //! Constructor
+    NoseHooverTemperatureCoupling(int                  numTemperatureGroups,
+                                  ArrayRef<const real> referenceTemperature,
+                                  ArrayRef<const real> couplingTime)
+    {
+        xi_.resize(numTemperatureGroups, 0.0);
+        xiVelocities_.resize(numTemperatureGroups, 0.0);
+        invXiMass_.resize(numTemperatureGroups, 0.0);
+        for (auto temperatureGroup = 0; temperatureGroup < numTemperatureGroups; ++temperatureGroup)
+        {
+            if (referenceTemperature[temperatureGroup] > 0 && couplingTime[temperatureGroup] > 0)
+            {
+                // Note: This mass definition is equal to legacy md
+                //       legacy md-vv divides the mass by ndof * kB
+                invXiMass_[temperatureGroup] = 1.0
+                                               / (gmx::square(couplingTime[temperatureGroup] / M_2PI)
+                                                  * referenceTemperature[temperatureGroup]);
+            }
+        }
+    }
+
+    //! Helper function to read from / write to CheckpointData
+    template<CheckpointDataOperation operation>
+    void doCheckpointData(CheckpointData<operation>* checkpointData)
+    {
+        checkpointVersion(checkpointData, "Nose-Hoover version", c_nhCurrentVersion);
+        checkpointData->arrayRef("xi", makeCheckpointArrayRef<operation>(xi_));
+        checkpointData->arrayRef("xi velocities", makeCheckpointArrayRef<operation>(xiVelocities_));
+    }
+
+    //! Write thermostat dof to checkpoint
+    void writeCheckpoint(std::optional<WriteCheckpointData> checkpointData, const t_commrec* cr) override
+    {
+        if (MASTER(cr))
+        {
+            doCheckpointData(&checkpointData.value());
+        }
+    }
+    //! Read thermostat dof from checkpoint
+    void readCheckpoint(std::optional<ReadCheckpointData> checkpointData, const t_commrec* cr) override
+    {
+        if (MASTER(cr))
+        {
+            doCheckpointData(&checkpointData.value());
+        }
+        if (DOMAINDECOMP(cr))
+        {
+            dd_bcast(cr->dd, xi_.size() * sizeof(real), xi_.data());
+            dd_bcast(cr->dd, xiVelocities_.size() * sizeof(real), xiVelocities_.data());
+        }
+    }
+
+private:
+    //! The thermostat degree of freedom
+    std::vector<real> xi_;
+    //! Velocity of the thermostat dof
+    std::vector<real> xiVelocities_;
+    //! Inverse mass of the thermostat dof
+    std::vector<real> invXiMass_;
+
+    //! View on the scaling factor of the propagator (pre-step velocities)
+    ArrayRef<real> lambdaStartVelocities_;
+    //! View on the scaling factor of the propagator (post-step velocities)
+    ArrayRef<real> lambdaEndVelocities_;
+};
+
 VelocityScalingTemperatureCoupling::VelocityScalingTemperatureCoupling(
         int                               nstcouple,
         int                               offset,
@@ -274,7 +454,7 @@ VelocityScalingTemperatureCoupling::VelocityScalingTemperatureCoupling(
         const real*                       couplingTime,
         const real*                       numDegreesOfFreedom,
         EnergyData*                       energyData,
-        TemperatureCouplingType           couplingType) :
+        TemperatureCoupling               couplingType) :
     nstcouple_(nstcouple),
     offset_(offset),
     useFullStepKE_(useFullStepKE),
@@ -285,32 +465,42 @@ VelocityScalingTemperatureCoupling::VelocityScalingTemperatureCoupling(
     couplingTime_(couplingTime, couplingTime + numTemperatureGroups),
     numDegreesOfFreedom_(numDegreesOfFreedom, numDegreesOfFreedom + numTemperatureGroups),
     temperatureCouplingIntegral_(numTemperatureGroups, 0.0),
-    energyData_(energyData)
+    energyData_(energyData),
+    nextEnergyCalculationStep_(-1)
 {
-    if (reportPreviousConservedEnergy_ == ReportPreviousStepConservedEnergy::Yes)
-    {
-        temperatureCouplingIntegralPreviousStep_ = temperatureCouplingIntegral_;
-    }
-    energyData->setVelocityScalingTemperatureCoupling(this);
-    if (couplingType == etcVRESCALE)
+    if (couplingType == TemperatureCoupling::VRescale)
     {
         temperatureCouplingImpl_ = std::make_unique<VRescaleTemperatureCoupling>(seed);
     }
-    else if (couplingType == etcBERENDSEN)
+    else if (couplingType == TemperatureCoupling::Berendsen)
     {
         temperatureCouplingImpl_ = std::make_unique<BerendsenTemperatureCoupling>();
     }
+    else if (couplingType == TemperatureCoupling::NoseHoover)
+    {
+        temperatureCouplingImpl_ = std::make_unique<NoseHooverTemperatureCoupling>(
+                numTemperatureGroups_, referenceTemperature_, couplingTime_);
+    }
     else
     {
-        throw NotImplementedError("Temperature coupling " + std::string(ETCOUPLTYPE(couplingType))
+        throw NotImplementedError("Temperature coupling " + std::string(enumValueToString(couplingType))
                                   + " is not implemented for modular simulator.");
     }
+    energyData->addConservedEnergyContribution([this](Step gmx_used_in_debug step, Time /*unused*/) {
+        GMX_ASSERT(conservedEnergyContributionStep_ == step,
+                   "VelocityScalingTemperatureCoupling conserved energy step mismatch.");
+        return conservedEnergyContribution_;
+    });
 }
 
-void VelocityScalingTemperatureCoupling::connectWithPropagator(const PropagatorThermostatConnection& connectionData)
+void VelocityScalingTemperatureCoupling::connectWithMatchingPropagator(const PropagatorConnection& connectionData,
+                                                                       const PropagatorTag& propagatorTag)
 {
-    temperatureCouplingImpl_->connectWithPropagator(connectionData, numTemperatureGroups_);
-    propagatorCallback_ = connectionData.getVelocityScalingCallback();
+    if (connectionData.tag == propagatorTag)
+    {
+        temperatureCouplingImpl_->connectWithPropagator(connectionData, numTemperatureGroups_);
+        propagatorCallback_ = connectionData.getVelocityScalingCallback();
+    }
 }
 
 void VelocityScalingTemperatureCoupling::elementSetup()
@@ -320,7 +510,8 @@ void VelocityScalingTemperatureCoupling::elementSetup()
         throw MissingElementConnectionError(
                 "Velocity scaling temperature coupling was not connected to a propagator.\n"
                 "Connection to a propagator element is needed to scale the velocities.\n"
-                "Use connectWithPropagator(...) before building the ModularSimulatorAlgorithm "
+                "Use connectWithMatchingPropagator(...) before building the "
+                "ModularSimulatorAlgorithm "
                 "object.");
     }
 }
@@ -337,6 +528,15 @@ void VelocityScalingTemperatureCoupling::scheduleTask(Step step,
      *       of the kinetic energy is needed.
      *
      */
+    if (step == nextEnergyCalculationStep_
+        && reportPreviousConservedEnergy_ == ReportPreviousStepConservedEnergy::Yes)
+    {
+        // add conserved energy before we do T-coupling
+        registerRunFunction([this, step]() {
+            conservedEnergyContribution_     = conservedEnergyContribution();
+            conservedEnergyContributionStep_ = step;
+        });
+    }
     if (do_per_step(step + nstcouple_ + offset_, nstcouple_))
     {
         // do T-coupling this step
@@ -345,19 +545,23 @@ void VelocityScalingTemperatureCoupling::scheduleTask(Step step,
         // Let propagator know that we want to do T-coupling
         propagatorCallback_(step);
     }
+    if (step == nextEnergyCalculationStep_
+        && reportPreviousConservedEnergy_ == ReportPreviousStepConservedEnergy::No)
+    {
+        // add conserved energy after we did T-coupling
+        registerRunFunction([this, step]() {
+            conservedEnergyContribution_     = conservedEnergyContribution();
+            conservedEnergyContributionStep_ = step;
+        });
+    }
 }
 
 void VelocityScalingTemperatureCoupling::setLambda(Step step)
 {
-    // if we report the previous energy, calculate before the step
-    if (reportPreviousConservedEnergy_ == ReportPreviousStepConservedEnergy::Yes)
-    {
-        temperatureCouplingIntegralPreviousStep_ = temperatureCouplingIntegral_;
-    }
-
     const auto*             ekind          = energyData_->ekindata();
-    TemperatureCouplingData thermostatData = { couplingTimeStep_, referenceTemperature_, couplingTime_,
-                                               numDegreesOfFreedom_, temperatureCouplingIntegral_ };
+    TemperatureCouplingData thermostatData = {
+        couplingTimeStep_, referenceTemperature_, couplingTime_, numDegreesOfFreedom_, temperatureCouplingIntegral_
+    };
 
     for (int temperatureGroup = 0; (temperatureGroup < numTemperatureGroups_); temperatureGroup++)
     {
@@ -421,7 +625,8 @@ void VelocityScalingTemperatureCoupling::restoreCheckpointState(std::optional<Re
     }
     if (DOMAINDECOMP(cr))
     {
-        dd_bcast(cr->dd, ssize(temperatureCouplingIntegral_) * int(sizeof(double)),
+        dd_bcast(cr->dd,
+                 ssize(temperatureCouplingIntegral_) * int(sizeof(double)),
                  temperatureCouplingIntegral_.data());
     }
     temperatureCouplingImpl_->readCheckpoint(
@@ -438,41 +643,50 @@ const std::string& VelocityScalingTemperatureCoupling::clientID()
 
 real VelocityScalingTemperatureCoupling::conservedEnergyContribution() const
 {
-    if (reportPreviousConservedEnergy_ == ReportPreviousStepConservedEnergy::Yes)
-    {
-        return std::accumulate(temperatureCouplingIntegralPreviousStep_.begin(),
-                               temperatureCouplingIntegralPreviousStep_.end(), 0.0);
-    }
-    else
+    return std::accumulate(temperatureCouplingIntegral_.begin(), temperatureCouplingIntegral_.end(), 0.0);
+}
+
+std::optional<SignallerCallback> VelocityScalingTemperatureCoupling::registerEnergyCallback(EnergySignallerEvent event)
+{
+    if (event == EnergySignallerEvent::EnergyCalculationStep)
     {
-        return std::accumulate(temperatureCouplingIntegral_.begin(),
-                               temperatureCouplingIntegral_.end(), 0.0);
+        return [this](Step step, Time /*unused*/) { nextEnergyCalculationStep_ = step; };
     }
+    return std::nullopt;
 }
 
 ISimulatorElement* VelocityScalingTemperatureCoupling::getElementPointerImpl(
         LegacySimulatorData*                    legacySimulatorData,
         ModularSimulatorAlgorithmBuilderHelper* builderHelper,
         StatePropagatorData gmx_unused* statePropagatorData,
-        EnergyData gmx_unused*     energyData,
+        EnergyData*                     energyData,
         FreeEnergyPerturbationData gmx_unused* freeEnergyPerturbationData,
         GlobalCommunicationHelper gmx_unused* globalCommunicationHelper,
-        int                                   offset,
+        Offset                                offset,
         UseFullStepKE                         useFullStepKE,
-        ReportPreviousStepConservedEnergy     reportPreviousStepConservedEnergy)
+        ReportPreviousStepConservedEnergy     reportPreviousStepConservedEnergy,
+        const PropagatorTag&                  propagatorTag)
 {
     // Element is now owned by the caller of this method, who will handle lifetime (see ModularSimulatorAlgorithm)
     auto* element = builderHelper->storeElement(std::make_unique<VelocityScalingTemperatureCoupling>(
-            legacySimulatorData->inputrec->nsttcouple, offset, useFullStepKE, reportPreviousStepConservedEnergy,
-            legacySimulatorData->inputrec->ld_seed, legacySimulatorData->inputrec->opts.ngtc,
+            legacySimulatorData->inputrec->nsttcouple,
+            offset,
+            useFullStepKE,
+            reportPreviousStepConservedEnergy,
+            legacySimulatorData->inputrec->ld_seed,
+            legacySimulatorData->inputrec->opts.ngtc,
             legacySimulatorData->inputrec->delta_t * legacySimulatorData->inputrec->nsttcouple,
-            legacySimulatorData->inputrec->opts.ref_t, legacySimulatorData->inputrec->opts.tau_t,
-            legacySimulatorData->inputrec->opts.nrdf, energyData, legacySimulatorData->inputrec->etc));
+            legacySimulatorData->inputrec->opts.ref_t,
+            legacySimulatorData->inputrec->opts.tau_t,
+            legacySimulatorData->inputrec->opts.nrdf,
+            energyData,
+            legacySimulatorData->inputrec->etc));
     auto* thermostat = static_cast<VelocityScalingTemperatureCoupling*>(element);
     // Capturing pointer is safe because lifetime is handled by caller
-    builderHelper->registerThermostat([thermostat](const PropagatorThermostatConnection& connection) {
-        thermostat->connectWithPropagator(connection);
-    });
+    builderHelper->registerTemperaturePressureControl(
+            [thermostat, propagatorTag](const PropagatorConnection& connection) {
+                thermostat->connectWithMatchingPropagator(connection, propagatorTag);
+            });
     return element;
 }
 
index 9bd3f740382d0501b4e122f7f5fdca9465a39a20..489c9262adc09042ad4353af3ad57099ebdb8f60 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -75,9 +75,6 @@ enum class ReportPreviousStepConservedEnergy
     Count
 };
 
-//! Typedef to match current use of ints as types.
-using TemperatureCouplingType = int;
-
 /*! \internal
  * \ingroup module_modularsimulator
  * \brief Element implementing the a velocity-scaling thermostat
@@ -89,7 +86,10 @@ using TemperatureCouplingType = int;
  * implementations of the ITemperatureCouplingImpl interface, while the element
  * handles the scheduling and interfacing with other elements.
  */
-class VelocityScalingTemperatureCoupling final : public ISimulatorElement, public ICheckpointHelperClient
+class VelocityScalingTemperatureCoupling final :
+    public ISimulatorElement,
+    public ICheckpointHelperClient,
+    public IEnergySignallerClient
 {
 public:
     //! Constructor
@@ -104,7 +104,7 @@ public:
                                        const real*                       couplingTime,
                                        const real*                       numDegreesOfFreedom,
                                        EnergyData*                       energyData,
-                                       TemperatureCouplingType           couplingType);
+                                       TemperatureCoupling               couplingType);
 
     /*! \brief Register run function for step / time
      *
@@ -119,11 +119,9 @@ public:
     //! No element teardown needed
     void elementTeardown() override {}
 
-    //! Contribution to the conserved energy (called by energy data)
-    [[nodiscard]] real conservedEnergyContribution() const;
-
     //! Connect this to propagator
-    void connectWithPropagator(const PropagatorThermostatConnection& connectionData);
+    void connectWithMatchingPropagator(const PropagatorConnection& connectionData,
+                                       const PropagatorTag&        propagatorTag);
 
     //! ICheckpointHelperClient write checkpoint implementation
     void saveCheckpointState(std::optional<WriteCheckpointData> checkpointData, const t_commrec* cr) override;
@@ -140,6 +138,7 @@ public:
      * \param energyData  Pointer to the \c EnergyData object
      * \param freeEnergyPerturbationData  Pointer to the \c FreeEnergyPerturbationData object
      * \param globalCommunicationHelper  Pointer to the \c GlobalCommunicationHelper object
+     * \param propagatorTag  Tag of the propagator to connect to
      * \param offset  The step offset at which the thermostat is applied
      * \param useFullStepKE  Whether full step or half step KE is used
      * \param reportPreviousStepConservedEnergy  Report the previous or the current step conserved energy
@@ -153,9 +152,10 @@ public:
                           EnergyData*                             energyData,
                           FreeEnergyPerturbationData*             freeEnergyPerturbationData,
                           GlobalCommunicationHelper*              globalCommunicationHelper,
-                          int                                     offset,
+                          Offset                                  offset,
                           UseFullStepKE                           useFullStepKE,
-                          ReportPreviousStepConservedEnergy reportPreviousStepConservedEnergy);
+                          ReportPreviousStepConservedEnergy       reportPreviousStepConservedEnergy,
+                          const PropagatorTag&                    propagatorTag);
 
 private:
     //! The frequency at which the thermostat is applied
@@ -179,8 +179,11 @@ private:
     const std::vector<real> numDegreesOfFreedom_;
     //! Work exerted by thermostat per group
     std::vector<double> temperatureCouplingIntegral_;
-    //! Work exerted by thermostat per group (backup from previous step)
-    std::vector<double> temperatureCouplingIntegralPreviousStep_;
+
+    //! Current conserved energy contribution
+    real conservedEnergyContribution_;
+    //! Step of current conserved energy contribution
+    Step conservedEnergyContributionStep_;
 
     // TODO: Clarify relationship to data objects and find a more robust alternative to raw pointers (#3583)
     //! Pointer to the energy data (for ekindata)
@@ -191,6 +194,8 @@ private:
 
     //! Set new lambda value (at T-coupling steps)
     void setLambda(Step step);
+    //! Contribution to the conserved energy
+    [[nodiscard]] real conservedEnergyContribution() const;
 
     //! The temperature coupling implementation
     std::unique_ptr<ITemperatureCouplingImpl> temperatureCouplingImpl_;
@@ -200,6 +205,11 @@ private:
     //! Helper function to read from / write to CheckpointData
     template<CheckpointDataOperation operation>
     void doCheckpointData(CheckpointData<operation>* checkpointData);
+
+    //! IEnergySignallerClient implementation
+    std::optional<SignallerCallback> registerEnergyCallback(EnergySignallerEvent event) override;
+    //! The next communicated energy calculation step
+    Step nextEnergyCalculationStep_;
 };
 
 } // namespace gmx
index c576b8558d34a2831f7876d08ff661671b25e9a8..91738e62355aabf3d49f15ba066a85b79d6d2486 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -32,6 +32,9 @@
 # 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 up the module library
+add_library(nbnxm INTERFACE)
+
 add_subdirectory(kernels_simd_4xm)
 add_subdirectory(kernels_simd_2xmm)
 
@@ -66,7 +69,7 @@ if(GMX_GPU_CUDA)
     gmx_add_libgromacs_sources(nbnxm_gpu_data_mgmt.cpp)
     _gmx_add_files_to_property(CUDA_SOURCES
         nbnxm_gpu_data_mgmt.cpp
-       )
+        )
 endif()
 
 if(GMX_GPU_OPENCL)
@@ -75,4 +78,35 @@ if(GMX_GPU_OPENCL)
     gmx_add_libgromacs_sources(nbnxm_gpu_data_mgmt.cpp)
 endif()
 
+if(GMX_GPU_SYCL)
+    add_subdirectory(sycl)
+    gmx_add_libgromacs_sources(nbnxm_gpu_data_mgmt.cpp)
+    _gmx_add_files_to_property(SYCL_SOURCES nbnxm_gpu_data_mgmt.cpp nbnxm.cpp)
+endif()
+
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${NBNXM_SOURCES} PARENT_SCOPE)
+
+
+# Source files have the following private module dependencies.
+target_link_libraries(nbnxm PRIVATE
+        )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(nbnxm PUBLIC
+target_include_directories(nbnxm INTERFACE
+        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(nbnxm PUBLIC
+target_link_libraries(nbnxm INTERFACE
+        legacy_api
+        )
+
+# TODO: when nbnxm is an OBJECT target
+#target_link_libraries(nbnxm PUBLIC legacy_api)
+#target_link_libraries(nbnxm PRIVATE common)
+
+# Module dependencies
+# nbnxm interfaces convey transitive dependence on these modules.
+#target_link_libraries(nbnxm PUBLIC
+target_link_libraries(nbnxm INTERFACE
+        utility
+        )
index dd4eddd0ca38ca1c9c3ebd903256047cc9145b2b..bce2b142aecf82791e308f0aa93bf12a1af7d0c6 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "atomdata.h"
 
-#include <cassert>
 #include <cmath>
 #include <cstdlib>
 #include <cstring>
 
 #include <algorithm>
 
-#include "thread_mpi/atomic.h"
-
 #include "gromacs/math/functions.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
 #include "gromacs/mdtypes/forcerec.h" // only for GET_CGINFO_*
+#include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/nbnxm/nbnxm.h"
 #include "gromacs/pbcutil/ishift.h"
 #include "gromacs/simd/simd.h"
@@ -59,7 +57,6 @@
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxomp.h"
 #include "gromacs/utility/logger.h"
-#include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/strconvert.h"
 #include "gromacs/utility/stringutil.h"
 
 
 using namespace gmx; // TODO: Remove when this file is moved into gmx namespace
 
+
+const char* enumValueToString(LJCombinationRule enumValue)
+{
+    static constexpr gmx::EnumerationArray<LJCombinationRule, const char*> s_ljCombinationRuleNames = {
+        "Geometric", "Lorentz-Berthelot", "None"
+    };
+    return s_ljCombinationRuleNames[enumValue];
+}
+
 void nbnxn_atomdata_t::resizeCoordinateBuffer(int numAtoms)
 {
     numAtoms_ = numAtoms;
@@ -101,7 +107,7 @@ nbnxn_atomdata_output_t::nbnxn_atomdata_output_t(Nbnxm::KernelType  kernelType,
     Vvdw({}, { pinningPolicy }),
     Vc({}, { pinningPolicy })
 {
-    fshift.resize(SHIFTS * DIM);
+    fshift.resize(gmx::c_numShiftVectors * DIM);
     Vvdw.resize(numEnergyGroups * numEnergyGroups);
     Vc.resize(numEnergyGroups * numEnergyGroups);
 
@@ -117,15 +123,13 @@ nbnxn_atomdata_output_t::nbnxn_atomdata_output_t(Nbnxm::KernelType  kernelType,
 
 static void copy_int_to_nbat_int(const int* a, int na, int na_round, const int* in, int fill, int* innb)
 {
-    int i, j;
-
-    j = 0;
-    for (i = 0; i < na; i++)
+    int j = 0;
+    for (int i = 0; i < na; i++)
     {
         innb[j++] = in[a[i]];
     }
     /* Complete the partially filled last cell with fill */
-    for (; i < na_round; i++)
+    for (int i = na; i < na_round; i++)
     {
         innb[j++] = fill;
     }
@@ -145,107 +149,113 @@ void copy_rvec_to_nbat_real(const int* a, int na, int na_round, const rvec* x, i
      */
     const real farAway = -1000000;
 
-    int i, j, c;
-
-    switch (nbatFormat)
+    if (nbatFormat == nbatXYZ)
     {
-        case nbatXYZ:
-            j = a0 * STRIDE_XYZ;
-            for (i = 0; i < na; i++)
-            {
-                xnb[j++] = x[a[i]][XX];
-                xnb[j++] = x[a[i]][YY];
-                xnb[j++] = x[a[i]][ZZ];
-            }
-            /* Complete the partially filled last cell with farAway elements */
-            for (; i < na_round; i++)
-            {
-                xnb[j++] = farAway;
-                xnb[j++] = farAway;
-                xnb[j++] = farAway;
-            }
-            break;
-        case nbatXYZQ:
-            j = a0 * STRIDE_XYZQ;
-            for (i = 0; i < na; i++)
-            {
-                xnb[j++] = x[a[i]][XX];
-                xnb[j++] = x[a[i]][YY];
-                xnb[j++] = x[a[i]][ZZ];
-                j++;
-            }
-            /* Complete the partially filled last cell with zeros */
-            for (; i < na_round; i++)
-            {
-                xnb[j++] = farAway;
-                xnb[j++] = farAway;
-                xnb[j++] = farAway;
-                j++;
-            }
-            break;
-        case nbatX4:
-            j = atom_to_x_index<c_packX4>(a0);
-            c = a0 & (c_packX4 - 1);
-            for (i = 0; i < na; i++)
+        int i = 0;
+        int j = a0 * STRIDE_XYZ;
+        for (; i < na; i++)
+        {
+            xnb[j++] = x[a[i]][XX];
+            xnb[j++] = x[a[i]][YY];
+            xnb[j++] = x[a[i]][ZZ];
+        }
+        /* Complete the partially filled last cell with farAway elements */
+        for (; i < na_round; i++)
+        {
+            xnb[j++] = farAway;
+            xnb[j++] = farAway;
+            xnb[j++] = farAway;
+        }
+    }
+    else if (nbatFormat == nbatXYZQ)
+    {
+        int i = 0;
+        int j = a0 * STRIDE_XYZQ;
+        for (; i < na; i++)
+        {
+            xnb[j++] = x[a[i]][XX];
+            xnb[j++] = x[a[i]][YY];
+            xnb[j++] = x[a[i]][ZZ];
+            j++;
+        }
+        /* Complete the partially filled last cell with zeros */
+        for (; i < na_round; i++)
+        {
+            xnb[j++] = farAway;
+            xnb[j++] = farAway;
+            xnb[j++] = farAway;
+            j++;
+        }
+    }
+    else if (nbatFormat == nbatX4)
+    {
+        int i = 0;
+        int j = atom_to_x_index<c_packX4>(a0);
+        int c = a0 & (c_packX4 - 1);
+        for (; i < na; i++)
+        {
+            xnb[j + XX * c_packX4] = x[a[i]][XX];
+            xnb[j + YY * c_packX4] = x[a[i]][YY];
+            xnb[j + ZZ * c_packX4] = x[a[i]][ZZ];
+            j++;
+            c++;
+            if (c == c_packX4)
             {
-                xnb[j + XX * c_packX4] = x[a[i]][XX];
-                xnb[j + YY * c_packX4] = x[a[i]][YY];
-                xnb[j + ZZ * c_packX4] = x[a[i]][ZZ];
-                j++;
-                c++;
-                if (c == c_packX4)
-                {
-                    j += (DIM - 1) * c_packX4;
-                    c = 0;
-                }
+                j += (DIM - 1) * c_packX4;
+                c = 0;
             }
-            /* Complete the partially filled last cell with zeros */
-            for (; i < na_round; i++)
+        }
+        /* Complete the partially filled last cell with zeros */
+        for (; i < na_round; i++)
+        {
+            xnb[j + XX * c_packX4] = farAway;
+            xnb[j + YY * c_packX4] = farAway;
+            xnb[j + ZZ * c_packX4] = farAway;
+            j++;
+            c++;
+            if (c == c_packX4)
             {
-                xnb[j + XX * c_packX4] = farAway;
-                xnb[j + YY * c_packX4] = farAway;
-                xnb[j + ZZ * c_packX4] = farAway;
-                j++;
-                c++;
-                if (c == c_packX4)
-                {
-                    j += (DIM - 1) * c_packX4;
-                    c = 0;
-                }
+                j += (DIM - 1) * c_packX4;
+                c = 0;
             }
-            break;
-        case nbatX8:
-            j = atom_to_x_index<c_packX8>(a0);
-            c = a0 & (c_packX8 - 1);
-            for (i = 0; i < na; i++)
+        }
+    }
+    else if (nbatFormat == nbatX8)
+    {
+        int i = 0;
+        int j = atom_to_x_index<c_packX8>(a0);
+        int c = a0 & (c_packX8 - 1);
+        for (; i < na; i++)
+        {
+            xnb[j + XX * c_packX8] = x[a[i]][XX];
+            xnb[j + YY * c_packX8] = x[a[i]][YY];
+            xnb[j + ZZ * c_packX8] = x[a[i]][ZZ];
+            j++;
+            c++;
+            if (c == c_packX8)
             {
-                xnb[j + XX * c_packX8] = x[a[i]][XX];
-                xnb[j + YY * c_packX8] = x[a[i]][YY];
-                xnb[j + ZZ * c_packX8] = x[a[i]][ZZ];
-                j++;
-                c++;
-                if (c == c_packX8)
-                {
-                    j += (DIM - 1) * c_packX8;
-                    c = 0;
-                }
+                j += (DIM - 1) * c_packX8;
+                c = 0;
             }
-            /* Complete the partially filled last cell with zeros */
-            for (; i < na_round; i++)
+        }
+        /* Complete the partially filled last cell with zeros */
+        for (; i < na_round; i++)
+        {
+            xnb[j + XX * c_packX8] = farAway;
+            xnb[j + YY * c_packX8] = farAway;
+            xnb[j + ZZ * c_packX8] = farAway;
+            j++;
+            c++;
+            if (c == c_packX8)
             {
-                xnb[j + XX * c_packX8] = farAway;
-                xnb[j + YY * c_packX8] = farAway;
-                xnb[j + ZZ * c_packX8] = farAway;
-                j++;
-                c++;
-                if (c == c_packX8)
-                {
-                    j += (DIM - 1) * c_packX8;
-                    c = 0;
-                }
+                j += (DIM - 1) * c_packX8;
+                c = 0;
             }
-            break;
-        default: gmx_incons("Unsupported nbnxn_atomdata_t format");
+        }
+    }
+    else
+    {
+        gmx_incons("Unsupported nbnxn_atomdata_t format");
     }
 }
 
@@ -289,11 +299,9 @@ static void set_lj_parameter_data(nbnxn_atomdata_t::Params* params, gmx_bool bSI
      * not per pair of atom types.
      */
     params->nbfp_comb.resize(nt * 2);
-    switch (params->comb_rule)
+    switch (params->ljCombinationRule)
     {
-        case ljcrGEOM:
-            params->comb_rule = ljcrGEOM;
-
+        case LJCombinationRule::Geometric:
             for (int i = 0; i < nt; i++)
             {
                 /* Store the sqrt of the diagonal from the nbfp matrix */
@@ -301,7 +309,7 @@ static void set_lj_parameter_data(nbnxn_atomdata_t::Params* params, gmx_bool bSI
                 params->nbfp_comb[i * 2 + 1] = std::sqrt(params->nbfp[(i * nt + i) * 2 + 1]);
             }
             break;
-        case ljcrLB:
+        case LJCombinationRule::LorentzBerthelot:
             for (int i = 0; i < nt; i++)
             {
                 /* Get 6*C6 and 12*C12 from the diagonal of the nbfp matrix */
@@ -322,7 +330,7 @@ static void set_lj_parameter_data(nbnxn_atomdata_t::Params* params, gmx_bool bSI
                 }
             }
             break;
-        case ljcrNONE:
+        case LJCombinationRule::None:
             /* We always store the full matrix (see code above) */
             break;
         default: gmx_incons("Unknown combination rule");
@@ -336,7 +344,7 @@ nbnxn_atomdata_t::SimdMasks::SimdMasks()
     /* Set the diagonal cluster pair exclusion mask setup data.
      * In the kernel we check 0 < j - i to generate the masks.
      * Here we store j - i for generating the mask for the first i,
-     * we substract 0.5 to avoid rounding issues.
+     * we subtract 0.5 to avoid rounding issues.
      * In the kernel we can subtract 1 to generate the subsequent mask.
      */
     const int simd_4xn_diag_size = std::max(c_nbnxnCpuIClusterSize, simd_width);
@@ -424,18 +432,6 @@ nbnxn_atomdata_t::Params::Params(gmx::PinningPolicy pinningPolicy) :
 {
 }
 
-nbnxn_atomdata_t::nbnxn_atomdata_t(gmx::PinningPolicy pinningPolicy) :
-    params_(pinningPolicy),
-    numAtoms_(0),
-    natoms_local(0),
-    shift_vec({}, { pinningPolicy }),
-    x_({}, { pinningPolicy }),
-    simdMasks(),
-    bUseBufferFlags(FALSE),
-    bUseTreeReduce(FALSE)
-{
-}
-
 /* Initializes an nbnxn_atomdata_t::Params data structure */
 static void nbnxn_atomdata_params_init(const gmx::MDLogger&      mdlog,
                                        nbnxn_atomdata_t::Params* params,
@@ -445,10 +441,6 @@ static void nbnxn_atomdata_params_init(const gmx::MDLogger&      mdlog,
                                        ArrayRef<const real>      nbfp,
                                        int                       n_energygroups)
 {
-    real     c6, c12, tol;
-    char*    ptr;
-    gmx_bool simple, bCombGeom, bCombLB, bSIMD;
-
     if (debug)
     {
         fprintf(debug, "There are %d atom types in the system, adding one for nbnxn_atomdata_t\n", ntype);
@@ -460,25 +452,23 @@ static void nbnxn_atomdata_params_init(const gmx::MDLogger&      mdlog,
     /* A tolerance of 1e-5 seems reasonable for (possibly hand-typed)
      * force-field floating point parameters.
      */
-    tol = 1e-5;
-    ptr = getenv("GMX_LJCOMB_TOL");
-    if (ptr != nullptr)
+    real        tol               = 1e-5;
+    const char* tolOverrideString = getenv("GMX_LJCOMB_TOL");
+    if (tolOverrideString != nullptr)
     {
-        double dbl;
-
-        sscanf(ptr, "%lf", &dbl);
-        tol = dbl;
+        double tolOverride = std::strtod(tolOverrideString, nullptr);
+        tol                = tolOverride;
     }
-    bCombGeom = TRUE;
-    bCombLB   = TRUE;
+    bool bCombGeom = true;
+    bool bCombLB   = true;
 
     /* Temporarily fill params->nbfp_comb with sigma and epsilon
      * to check for the LB rule.
      */
     for (int i = 0; i < ntype; i++)
     {
-        c6  = nbfp[(i * ntype + i) * 2] / 6.0;
-        c12 = nbfp[(i * ntype + i) * 2 + 1] / 12.0;
+        const real c6  = nbfp[(i * ntype + i) * 2] / 6.0;
+        const real c12 = nbfp[(i * ntype + i) * 2 + 1] / 12.0;
         if (c6 > 0 && c12 > 0)
         {
             params->nbfp_comb[i * 2]     = gmx::sixthroot(c12 / c6);
@@ -492,7 +482,7 @@ static void nbnxn_atomdata_params_init(const gmx::MDLogger&      mdlog,
         else
         {
             /* Can not use LB rule with only dispersion or repulsion */
-            bCombLB = FALSE;
+            bCombLB = false;
         }
     }
 
@@ -505,16 +495,16 @@ static void nbnxn_atomdata_params_init(const gmx::MDLogger&      mdlog,
                 /* fr->nbfp has been updated, so that array too now stores c6/c12 including
                  * the 6.0/12.0 prefactors to save 2 flops in the most common case (force-only).
                  */
-                c6                                               = nbfp[(i * ntype + j) * 2];
-                c12                                              = nbfp[(i * ntype + j) * 2 + 1];
+                real c6  = nbfp[(i * ntype + j) * 2];
+                real c12 = nbfp[(i * ntype + j) * 2 + 1];
+
                 params->nbfp[(i * params->numTypes + j) * 2]     = c6;
                 params->nbfp[(i * params->numTypes + j) * 2 + 1] = c12;
 
                 /* Compare 6*C6 and 12*C12 for geometric cobination rule */
                 bCombGeom =
                         bCombGeom
-                        && gmx_within_tol(c6 * c6,
-                                          nbfp[(i * ntype + i) * 2] * nbfp[(j * ntype + j) * 2], tol)
+                        && gmx_within_tol(c6 * c6, nbfp[(i * ntype + i) * 2] * nbfp[(j * ntype + j) * 2], tol)
                         && gmx_within_tol(c12 * c12,
                                           nbfp[(i * ntype + i) * 2 + 1] * nbfp[(j * ntype + j) * 2 + 1],
                                           tol);
@@ -527,9 +517,9 @@ static void nbnxn_atomdata_params_init(const gmx::MDLogger&      mdlog,
                         && ((c6 == 0 && c12 == 0
                              && (params->nbfp_comb[i * 2 + 1] == 0 || params->nbfp_comb[j * 2 + 1] == 0))
                             || (c6 > 0 && c12 > 0
-                                && gmx_within_tol(
-                                           gmx::sixthroot(c12 / c6),
-                                           0.5 * (params->nbfp_comb[i * 2] + params->nbfp_comb[j * 2]), tol)
+                                && gmx_within_tol(gmx::sixthroot(c12 / c6),
+                                                  0.5 * (params->nbfp_comb[i * 2] + params->nbfp_comb[j * 2]),
+                                                  tol)
                                 && gmx_within_tol(0.25 * c6 * c6 / c12,
                                                   std::sqrt(params->nbfp_comb[i * 2 + 1]
                                                             * params->nbfp_comb[j * 2 + 1]),
@@ -545,59 +535,64 @@ static void nbnxn_atomdata_params_init(const gmx::MDLogger&      mdlog,
     }
     if (debug)
     {
-        fprintf(debug, "Combination rules: geometric %s Lorentz-Berthelot %s\n",
-                gmx::boolToString(bCombGeom), gmx::boolToString(bCombLB));
+        fprintf(debug,
+                "Combination rules: geometric %s Lorentz-Berthelot %s\n",
+                gmx::boolToString(bCombGeom),
+                gmx::boolToString(bCombLB));
     }
 
-    simple = Nbnxm::kernelTypeUsesSimplePairlist(kernelType);
+    const bool simple = Nbnxm::kernelTypeUsesSimplePairlist(kernelType);
 
     switch (enbnxninitcombrule)
     {
         case enbnxninitcombruleDETECT:
-            /* We prefer the geometic combination rule,
+            /* We prefer the geometric combination rule,
              * as that gives a slightly faster kernel than the LB rule.
              */
             if (bCombGeom)
             {
-                params->comb_rule = ljcrGEOM;
+                params->ljCombinationRule = LJCombinationRule::Geometric;
             }
             else if (bCombLB)
             {
-                params->comb_rule = ljcrLB;
+                params->ljCombinationRule = LJCombinationRule::LorentzBerthelot;
             }
             else
             {
-                params->comb_rule = ljcrNONE;
+                params->ljCombinationRule = LJCombinationRule::None;
 
                 params->nbfp_comb.clear();
             }
 
             {
                 std::string mesg;
-                if (params->comb_rule == ljcrNONE)
+                if (params->ljCombinationRule == LJCombinationRule::None)
                 {
                     mesg = "Using full Lennard-Jones parameter combination matrix";
                 }
                 else
                 {
-                    mesg = gmx::formatString(
-                            "Using %s Lennard-Jones combination rule",
-                            params->comb_rule == ljcrGEOM ? "geometric" : "Lorentz-Berthelot");
+                    mesg = gmx::formatString("Using %s Lennard-Jones combination rule",
+                                             enumValueToString(params->ljCombinationRule));
                 }
                 GMX_LOG(mdlog.info).asParagraph().appendText(mesg);
             }
             break;
-        case enbnxninitcombruleGEOM: params->comb_rule = ljcrGEOM; break;
-        case enbnxninitcombruleLB: params->comb_rule = ljcrLB; break;
+        case enbnxninitcombruleGEOM:
+            params->ljCombinationRule = LJCombinationRule::Geometric;
+            break;
+        case enbnxninitcombruleLB:
+            params->ljCombinationRule = LJCombinationRule::LorentzBerthelot;
+            break;
         case enbnxninitcombruleNONE:
-            params->comb_rule = ljcrNONE;
+            params->ljCombinationRule = LJCombinationRule::None;
 
             params->nbfp_comb.clear();
             break;
         default: gmx_incons("Unknown enbnxninitcombrule");
     }
 
-    bSIMD = Nbnxm::kernelTypeIsSimd(kernelType);
+    const bool bSIMD = Nbnxm::kernelTypeIsSimd(kernelType);
 
     set_lj_parameter_data(params, bSIMD);
 
@@ -620,86 +615,66 @@ static void nbnxn_atomdata_params_init(const gmx::MDLogger&      mdlog,
 }
 
 /* Initializes an nbnxn_atomdata_t data structure */
-void nbnxn_atomdata_init(const gmx::MDLogger&    mdlog,
-                         nbnxn_atomdata_t*       nbat,
-                         const Nbnxm::KernelType kernelType,
-                         int                     enbnxninitcombrule,
-                         int                     ntype,
-                         ArrayRef<const real>    nbfp,
-                         int                     n_energygroups,
-                         int                     nout)
+nbnxn_atomdata_t::nbnxn_atomdata_t(gmx::PinningPolicy      pinningPolicy,
+                                   const gmx::MDLogger&    mdlog,
+                                   const Nbnxm::KernelType kernelType,
+                                   int                     enbnxninitcombrule,
+                                   int                     ntype,
+                                   ArrayRef<const real>    nbfp,
+                                   int                     n_energygroups,
+                                   int                     nout) :
+    params_(pinningPolicy),
+    numAtoms_(0),
+    natoms_local(0),
+    shift_vec({}, { pinningPolicy }),
+    x_({}, { pinningPolicy }),
+    simdMasks(),
+    bUseBufferFlags(FALSE)
 {
-    nbnxn_atomdata_params_init(mdlog, &nbat->paramsDeprecated(), kernelType, enbnxninitcombrule,
-                               ntype, nbfp, n_energygroups);
+    nbnxn_atomdata_params_init(
+            mdlog, &paramsDeprecated(), kernelType, enbnxninitcombrule, ntype, nbfp, n_energygroups);
 
     const bool simple = Nbnxm::kernelTypeUsesSimplePairlist(kernelType);
     const bool bSIMD  = Nbnxm::kernelTypeIsSimd(kernelType);
 
     if (simple)
     {
-        int pack_x;
-
         if (bSIMD)
         {
-            pack_x = std::max(c_nbnxnCpuIClusterSize, Nbnxm::JClusterSizePerKernelType[kernelType]);
+            int pack_x = std::max(c_nbnxnCpuIClusterSize, Nbnxm::JClusterSizePerKernelType[kernelType]);
             switch (pack_x)
             {
-                case 4: nbat->XFormat = nbatX4; break;
-                case 8: nbat->XFormat = nbatX8; break;
+                case 4: XFormat = nbatX4; break;
+                case 8: XFormat = nbatX8; break;
                 default: gmx_incons("Unsupported packing width");
             }
         }
         else
         {
-            nbat->XFormat = nbatXYZ;
+            XFormat = nbatXYZ;
         }
 
-        nbat->FFormat = nbat->XFormat;
+        FFormat = XFormat;
     }
     else
     {
-        nbat->XFormat = nbatXYZQ;
-        nbat->FFormat = nbatXYZ;
+        XFormat = nbatXYZQ;
+        FFormat = nbatXYZ;
     }
 
-    nbat->shift_vec.resize(SHIFTS);
+    shift_vec.resize(gmx::c_numShiftVectors);
 
-    nbat->xstride = (nbat->XFormat == nbatXYZQ ? STRIDE_XYZQ : DIM);
-    nbat->fstride = (nbat->FFormat == nbatXYZQ ? STRIDE_XYZQ : DIM);
+    xstride = (XFormat == nbatXYZQ ? STRIDE_XYZQ : DIM);
+    fstride = (FFormat == nbatXYZQ ? STRIDE_XYZQ : DIM);
 
     /* Initialize the output data structures */
     for (int i = 0; i < nout; i++)
     {
-        const auto& pinningPolicy = nbat->params().type.get_allocator().pinningPolicy();
-        nbat->out.emplace_back(kernelType, nbat->params().nenergrp, 1 << nbat->params().neg_2log,
-                               pinningPolicy);
-    }
-
-    nbat->buffer_flags.clear();
-
-    const int nth = gmx_omp_nthreads_get(emntNonbonded);
-
-    const char* ptr = getenv("GMX_USE_TREEREDUCE");
-    if (ptr != nullptr)
-    {
-        nbat->bUseTreeReduce = (strtol(ptr, nullptr, 10) != 0);
-    }
-#if defined __MIC__
-    else if (nth > 8) /*on the CPU we currently don't benefit even at 32*/
-    {
-        nbat->bUseTreeReduce = 1;
+        const auto& pinningPolicy = params().type.get_allocator().pinningPolicy();
+        out.emplace_back(kernelType, params().nenergrp, 1 << params().neg_2log, pinningPolicy);
     }
-#endif
-    else
-    {
-        nbat->bUseTreeReduce = false;
-    }
-    if (nbat->bUseTreeReduce)
-    {
-        GMX_LOG(mdlog.info).asParagraph().appendText("Using tree force reduction");
 
-        nbat->syncStep = new tMPI_Atomic[nth];
-    }
+    buffer_flags.clear();
 }
 
 template<int packSize>
@@ -735,8 +710,11 @@ static void nbnxn_atomdata_set_atomtypes(nbnxn_atomdata_t::Params* params,
             const int atomOffset = grid.firstAtomInColumn(i);
 
             copy_int_to_nbat_int(gridSet.atomIndices().data() + atomOffset,
-                                 grid.numAtomsInColumn(i), numAtoms, atomTypes.data(),
-                                 params->numTypes - 1, params->type.data() + atomOffset);
+                                 grid.numAtomsInColumn(i),
+                                 numAtoms,
+                                 atomTypes.data(),
+                                 params->numTypes - 1,
+                                 params->type.data() + atomOffset);
         }
     }
 }
@@ -748,7 +726,7 @@ static void nbnxn_atomdata_set_ljcombparams(nbnxn_atomdata_t::Params* params,
 {
     params->lj_comb.resize(gridSet.numGridAtomsTotal() * 2);
 
-    if (params->comb_rule != ljcrNONE)
+    if (params->ljCombinationRule != LJCombinationRule::None)
     {
         for (const Nbnxm::Grid& grid : gridSet.grids())
         {
@@ -761,19 +739,23 @@ static void nbnxn_atomdata_set_ljcombparams(nbnxn_atomdata_t::Params* params,
                 if (XFormat == nbatX4)
                 {
                     copy_lj_to_nbat_lj_comb<c_packX4>(params->nbfp_comb,
-                                                      params->type.data() + atomOffset, numAtoms,
+                                                      params->type.data() + atomOffset,
+                                                      numAtoms,
                                                       params->lj_comb.data() + atomOffset * 2);
                 }
                 else if (XFormat == nbatX8)
                 {
                     copy_lj_to_nbat_lj_comb<c_packX8>(params->nbfp_comb,
-                                                      params->type.data() + atomOffset, numAtoms,
+                                                      params->type.data() + atomOffset,
+                                                      numAtoms,
                                                       params->lj_comb.data() + atomOffset * 2);
                 }
                 else if (XFormat == nbatXYZQ)
                 {
-                    copy_lj_to_nbat_lj_comb<1>(params->nbfp_comb, params->type.data() + atomOffset,
-                                               numAtoms, params->lj_comb.data() + atomOffset * 2);
+                    copy_lj_to_nbat_lj_comb<1>(params->nbfp_comb,
+                                               params->type.data() + atomOffset,
+                                               numAtoms,
+                                               params->lj_comb.data() + atomOffset * 2);
                 }
             }
         }
@@ -802,14 +784,13 @@ static void nbnxn_atomdata_set_charges(nbnxn_atomdata_t*     nbat,
             if (nbat->XFormat == nbatXYZQ)
             {
                 real* q = nbat->x().data() + atomOffset * STRIDE_XYZQ + ZZ + 1;
-                int   i;
-                for (i = 0; i < numAtoms; i++)
+                for (int i = 0; i < numAtoms; i++)
                 {
                     *q = charges[gridSet.atomIndices()[atomOffset + i]];
                     q += STRIDE_XYZQ;
                 }
                 /* Complete the partially filled last cell with zeros */
-                for (; i < paddedNumAtoms; i++)
+                for (int i = numAtoms; i < paddedNumAtoms; i++)
                 {
                     *q = 0;
                     q += STRIDE_XYZQ;
@@ -818,14 +799,13 @@ static void nbnxn_atomdata_set_charges(nbnxn_atomdata_t*     nbat,
             else
             {
                 real* q = nbat->paramsDeprecated().q.data() + atomOffset;
-                int   i;
-                for (i = 0; i < numAtoms; i++)
+                for (int i = 0; i < numAtoms; i++)
                 {
                     *q = charges[gridSet.atomIndices()[atomOffset + i]];
                     q++;
                 }
                 /* Complete the partially filled last cell with zeros */
-                for (; i < paddedNumAtoms; i++)
+                for (int i = numAtoms; i < paddedNumAtoms; i++)
                 {
                     *q = 0;
                     q++;
@@ -844,33 +824,17 @@ static void nbnxn_atomdata_set_charges(nbnxn_atomdata_t*     nbat,
 static void nbnxn_atomdata_mask_fep(nbnxn_atomdata_t* nbat, const Nbnxm::GridSet& gridSet)
 {
     nbnxn_atomdata_t::Params& params = nbat->paramsDeprecated();
-    real*                     q;
-    int                       stride_q;
 
-    if (nbat->XFormat == nbatXYZQ)
-    {
-        q        = nbat->x().data() + ZZ + 1;
-        stride_q = STRIDE_XYZQ;
-    }
-    else
-    {
-        q        = params.q.data();
-        stride_q = 1;
-    }
+    const bool formatIsXYZQ = (nbat->XFormat == nbatXYZQ);
+
+    real* q        = formatIsXYZQ ? (nbat->x().data() + ZZ + 1) : params.q.data();
+    int   stride_q = formatIsXYZQ ? STRIDE_XYZQ : 1;
 
     for (const Nbnxm::Grid& grid : gridSet.grids())
     {
-        int nsubc;
-        if (grid.geometry().isSimple)
-        {
-            nsubc = 1;
-        }
-        else
-        {
-            nsubc = c_gpuNumClusterPerCell;
-        }
+        const int nsubc = (grid.geometry().isSimple) ? 1 : c_gpuNumClusterPerCell;
 
-        int c_offset = grid.firstAtomInColumn(0);
+        const int c_offset = grid.firstAtomInColumn(0);
 
         /* Loop over all columns and copy and fill */
         for (int c = 0; c < grid.numCells() * nsubc; c++)
@@ -899,14 +863,11 @@ static void nbnxn_atomdata_mask_fep(nbnxn_atomdata_t* nbat, const Nbnxm::GridSet
 static void
 copy_egp_to_nbat_egps(const int* a, int na, int na_round, int na_c, int bit_shift, const int* in, int* innb)
 {
-    int i;
-    int comb;
-
-    int j = 0;
-    for (i = 0; i < na; i += na_c)
+    int i = 0, j = 0;
+    for (; i < na; i += na_c)
     {
         /* Store na_c energy group numbers into one int */
-        comb = 0;
+        int comb = 0;
         for (int sa = 0; sa < na_c; sa++)
         {
             int at = a[i + sa];
@@ -944,8 +905,12 @@ static void nbnxn_atomdata_set_energygroups(nbnxn_atomdata_t::Params* params,
             const int numAtoms   = grid.paddedNumAtomsInColumn(i);
             const int atomOffset = grid.firstAtomInColumn(i);
 
-            copy_egp_to_nbat_egps(gridSet.atomIndices().data() + atomOffset, grid.numAtomsInColumn(i),
-                                  numAtoms, c_nbnxnCpuIClusterSize, params->neg_2log, atomInfo.data(),
+            copy_egp_to_nbat_egps(gridSet.atomIndices().data() + atomOffset,
+                                  grid.numAtomsInColumn(i),
+                                  numAtoms,
+                                  c_nbnxnCpuIClusterSize,
+                                  params->neg_2log,
+                                  atomInfo.data(),
                                   params->energrp.data() + grid.atomToCluster(atomOffset));
         }
     }
@@ -976,15 +941,10 @@ void nbnxn_atomdata_set(nbnxn_atomdata_t*     nbat,
 }
 
 /* Copies the shift vector array to nbnxn_atomdata_t */
-void nbnxn_atomdata_copy_shiftvec(gmx_bool bDynamicBox, rvec* shift_vec, nbnxn_atomdata_t* nbat)
+void nbnxn_atomdata_copy_shiftvec(gmx_bool bDynamicBox, gmx::ArrayRef<gmx::RVec> shift_vec, nbnxn_atomdata_t* nbat)
 {
-    int i;
-
     nbat->bDynamicBox = bDynamicBox;
-    for (i = 0; i < SHIFTS; i++)
-    {
-        copy_rvec(shift_vec[i], nbat->shift_vec[i]);
-    }
+    std::copy(shift_vec.begin(), shift_vec.end(), nbat->shift_vec.begin());
 }
 
 // This is slightly different from nbnxn_get_atom_range(...) at the end of the file
@@ -1017,7 +977,6 @@ static void getAtomRanges(const Nbnxm::GridSet&   gridSet,
 /* Copies (and reorders) the coordinates to nbnxn_atomdata_t */
 void nbnxn_atomdata_copy_x_to_nbat_x(const Nbnxm::GridSet&   gridSet,
                                      const gmx::AtomLocality locality,
-                                     bool                    fillLocal,
                                      const rvec*             coordinates,
                                      nbnxn_atomdata_t*       nbat)
 {
@@ -1026,12 +985,7 @@ void nbnxn_atomdata_copy_x_to_nbat_x(const Nbnxm::GridSet&   gridSet,
     int gridEnd   = 0;
     getAtomRanges(gridSet, locality, &gridBegin, &gridEnd);
 
-    if (fillLocal)
-    {
-        nbat->natoms_local = gridSet.grids()[0].atomIndexEnd();
-    }
-
-    const int nth = gmx_omp_nthreads_get(emntPairsearch);
+    const int nth = gmx_omp_nthreads_get(ModuleMultiThread::Pairsearch);
 #pragma omp parallel for num_threads(nth) schedule(static)
     for (int th = 0; th < nth; th++)
     {
@@ -1050,21 +1004,13 @@ void nbnxn_atomdata_copy_x_to_nbat_x(const Nbnxm::GridSet&   gridSet,
                     const int na  = grid.numAtomsInColumn(cxy);
                     const int ash = grid.firstAtomInColumn(cxy);
 
-                    int na_fill;
-                    if (g == 0 && fillLocal)
-                    {
-                        na_fill = grid.paddedNumAtomsInColumn(cxy);
-                    }
-                    else
-                    {
-                        /* We fill only the real particle locations.
-                         * We assume the filling entries at the end have been
-                         * properly set before during pair-list generation.
-                         */
-                        na_fill = na;
-                    }
-                    copy_rvec_to_nbat_real(gridSet.atomIndices().data() + ash, na, na_fill,
-                                           coordinates, nbat->XFormat, nbat->x().data(), ash);
+                    copy_rvec_to_nbat_real(gridSet.atomIndices().data() + ash,
+                                           na,
+                                           na,
+                                           coordinates,
+                                           nbat->XFormat,
+                                           nbat->x().data(),
+                                           ash);
                 }
             }
         }
@@ -1075,11 +1021,11 @@ void nbnxn_atomdata_copy_x_to_nbat_x(const Nbnxm::GridSet&   gridSet,
 /* Copies (and reorders) the coordinates to nbnxn_atomdata_t on the GPU*/
 void nbnxn_atomdata_x_to_nbat_x_gpu(const Nbnxm::GridSet&   gridSet,
                                     const gmx::AtomLocality locality,
-                                    bool                    fillLocal,
                                     NbnxmGpu*               gpu_nbv,
                                     DeviceBuffer<RVec>      d_x,
                                     GpuEventSynchronizer*   xReadyOnDevice)
 {
+    GMX_ASSERT(xReadyOnDevice != nullptr, "Need a valid GpuEventSynchronizer object");
 
     int gridBegin = 0;
     int gridEnd   = 0;
@@ -1087,8 +1033,14 @@ void nbnxn_atomdata_x_to_nbat_x_gpu(const Nbnxm::GridSet&   gridSet,
 
     for (int g = gridBegin; g < gridEnd; g++)
     {
-        nbnxn_gpu_x_to_nbat_x(gridSet.grids()[g], fillLocal && g == 0, gpu_nbv, d_x, xReadyOnDevice,
-                              locality, g, gridSet.numColumnsMax());
+        nbnxn_gpu_x_to_nbat_x(gridSet.grids()[g],
+                              gpu_nbv,
+                              d_x,
+                              (g == gridBegin) ? xReadyOnDevice : nullptr, // Sync on first iteration only
+                              locality,
+                              g,
+                              gridSet.numColumnsMax(),
+                              (g == gridEnd - 1));
     }
 }
 
@@ -1120,7 +1072,7 @@ gmx_unused static void nbnxn_atomdata_reduce_reals(real* gmx_restrict dest,
     }
     else
     {
-        /* The destination buffer is unitialized, set it first */
+        /* The destination buffer is uninitialized, set it first */
         for (int i = i0; i < i1; i++)
         {
             dest[i] = src[0][i];
@@ -1227,173 +1179,27 @@ static void nbnxn_atomdata_add_nbat_f_to_f_part(const Nbnxm::GridSet&          g
     }
 }
 
-static inline unsigned char reverse_bits(unsigned char b)
-{
-    /* http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64BitsDiv */
-    return (b * 0x0202020202ULL & 0x010884422010ULL) % 1023;
-}
-
-static void nbnxn_atomdata_add_nbat_f_to_f_treereduce(nbnxn_atomdata_t* nbat, int nth)
-{
-    gmx::ArrayRef<const gmx_bitmask_t> flags = nbat->buffer_flags;
-
-    int next_pow2 = 1 << (gmx::log2I(nth - 1) + 1);
-
-    const int numOutputBuffers = nbat->out.size();
-    GMX_ASSERT(numOutputBuffers == nth,
-               "tree-reduce currently only works for numOutputBuffers==nth");
-
-    memset(nbat->syncStep, 0, sizeof(*(nbat->syncStep)) * nth);
-
-#pragma omp parallel num_threads(nth)
-    {
-        try
-        {
-            int b0, b1, b;
-            int i0, i1;
-            int group_size, th;
-
-            th = gmx_omp_get_thread_num();
-
-            for (group_size = 2; group_size < 2 * next_pow2; group_size *= 2)
-            {
-                int index[2], group_pos, partner_pos, wu;
-                int partner_th = th ^ (group_size / 2);
-
-                if (group_size > 2)
-                {
-#ifdef TMPI_ATOMICS
-                    /* wait on partner thread - replaces full barrier */
-                    int sync_th, sync_group_size;
-
-#    if defined(__clang__) && __clang_major__ >= 8
-                    // Suppress warnings that the use of memory_barrier may be excessive
-                    // Only exists beginning with clang-8
-#        pragma clang diagnostic push
-#        pragma clang diagnostic ignored "-Watomic-implicit-seq-cst"
-#    endif
-
-                    tMPI_Atomic_memory_barrier(); /* guarantee data is saved before marking work as done */
-                    tMPI_Atomic_set(&(nbat->syncStep[th]), group_size / 2); /* mark previous step as completed */
-
-                    /* find thread to sync with. Equal to partner_th unless nth is not a power of two. */
-                    for (sync_th = partner_th, sync_group_size = group_size;
-                         sync_th >= nth && sync_group_size > 2; sync_group_size /= 2)
-                    {
-                        sync_th &= ~(sync_group_size / 4);
-                    }
-                    if (sync_th < nth) /* otherwise nothing to sync index[1] will be >=nout */
-                    {
-                        /* wait on the thread which computed input data in previous step */
-                        while (tMPI_Atomic_get(static_cast<volatile tMPI_Atomic_t*>(&(nbat->syncStep[sync_th])))
-                               < group_size / 2)
-                        {
-                            gmx_pause();
-                        }
-                        /* guarantee that no later load happens before wait loop is finisehd */
-                        tMPI_Atomic_memory_barrier();
-                    }
-#    if defined(__clang__) && __clang_major__ >= 8
-#        pragma clang diagnostic pop
-#    endif
-#else /* TMPI_ATOMICS */
-#    pragma omp barrier
-#endif
-                }
-
-                /* Calculate buffers to sum (result goes into first buffer) */
-                group_pos = th % group_size;
-                index[0]  = th - group_pos;
-                index[1]  = index[0] + group_size / 2;
-
-                /* If no second buffer, nothing to do */
-                if (index[1] >= numOutputBuffers && group_size > 2)
-                {
-                    continue;
-                }
-
-#if NBNXN_BUFFERFLAG_MAX_THREADS > 256
-#    error reverse_bits assumes max 256 threads
-#endif
-                /* Position is permuted so that one of the 2 vectors being added was computed on the same thread in the previous step.
-                   This improves locality and enables to sync with just a single thread between steps (=the levels in the btree).
-                   The permutation which allows this corresponds to reversing the bits of the group position.
-                 */
-                group_pos = reverse_bits(group_pos) / (256 / group_size);
-
-                partner_pos = group_pos ^ 1;
-
-                /* loop over two work-units (own and partner) */
-                for (wu = 0; wu < 2; wu++)
-                {
-                    if (wu == 1)
-                    {
-                        if (partner_th < nth)
-                        {
-                            break; /* partner exists we don't have to do his work */
-                        }
-                        else
-                        {
-                            group_pos = partner_pos;
-                        }
-                    }
-
-                    /* Calculate the cell-block range for our thread */
-                    b0 = (flags.size() * group_pos) / group_size;
-                    b1 = (flags.size() * (group_pos + 1)) / group_size;
-
-                    for (b = b0; b < b1; b++)
-                    {
-                        i0 = b * NBNXN_BUFFERFLAG_SIZE * nbat->fstride;
-                        i1 = (b + 1) * NBNXN_BUFFERFLAG_SIZE * nbat->fstride;
-
-                        if (bitmask_is_set(flags[b], index[1]) || group_size > 2)
-                        {
-                            const real* fIndex1 = nbat->out[index[1]].f.data();
-#if GMX_SIMD
-                            nbnxn_atomdata_reduce_reals_simd
-#else
-                            nbnxn_atomdata_reduce_reals
-#endif
-                                    (nbat->out[index[0]].f.data(),
-                                     bitmask_is_set(flags[b], index[0]) || group_size > 2, &fIndex1,
-                                     1, i0, i1);
-                        }
-                        else if (!bitmask_is_set(flags[b], index[0]))
-                        {
-                            nbnxn_atomdata_clear_reals(nbat->out[index[0]].f, i0, i1);
-                        }
-                    }
-                }
-            }
-        }
-        GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
-    }
-}
-
-
-static void nbnxn_atomdata_add_nbat_f_to_f_stdreduce(nbnxn_atomdata_t* nbat, int nth)
+static void nbnxn_atomdata_add_nbat_f_to_f_reduce(nbnxn_atomdata_t* nbat, int nth)
 {
 #pragma omp parallel for num_threads(nth) schedule(static)
     for (int th = 0; th < nth; th++)
     {
         try
         {
-            int         nfptr;
             const real* fptr[NBNXN_BUFFERFLAG_MAX_THREADS];
 
             gmx::ArrayRef<const gmx_bitmask_t> flags = nbat->buffer_flags;
 
             /* Calculate the cell-block range for our thread */
-            int b0 = (flags.size() * th) / nth;
-            int b1 = (flags.size() * (th + 1)) / nth;
+            const int b0 = (flags.size() * th) / nth;
+            const int b1 = (flags.size() * (th + 1)) / nth;
 
             for (int b = b0; b < b1; b++)
             {
-                int i0 = b * NBNXN_BUFFERFLAG_SIZE * nbat->fstride;
-                int i1 = (b + 1) * NBNXN_BUFFERFLAG_SIZE * nbat->fstride;
+                const int i0 = b * NBNXN_BUFFERFLAG_SIZE * nbat->fstride;
+                const int i1 = (b + 1) * NBNXN_BUFFERFLAG_SIZE * nbat->fstride;
 
-                nfptr = 0;
+                int nfptr = 0;
                 for (gmx::index out = 1; out < gmx::ssize(nbat->out); out++)
                 {
                     if (bitmask_is_set(flags[b], out))
@@ -1435,7 +1241,7 @@ void reduceForces(nbnxn_atomdata_t* nbat, const gmx::AtomLocality locality, cons
         return;
     }
 
-    int nth = gmx_omp_nthreads_get(emntNonbonded);
+    int nth = gmx_omp_nthreads_get(ModuleMultiThread::Nonbonded);
 
     if (nbat->out.size() > 1)
     {
@@ -1447,22 +1253,15 @@ void reduceForces(nbnxn_atomdata_t* nbat, const gmx::AtomLocality locality, cons
         /* Reduce the force thread output buffers into buffer 0, before adding
          * them to the, differently ordered, "real" force buffer.
          */
-        if (nbat->bUseTreeReduce)
-        {
-            nbnxn_atomdata_add_nbat_f_to_f_treereduce(nbat, nth);
-        }
-        else
-        {
-            nbnxn_atomdata_add_nbat_f_to_f_stdreduce(nbat, nth);
-        }
+        nbnxn_atomdata_add_nbat_f_to_f_reduce(nbat, nth);
     }
 #pragma omp parallel for num_threads(nth) schedule(static)
     for (int th = 0; th < nth; th++)
     {
         try
         {
-            nbnxn_atomdata_add_nbat_f_to_f_part(gridSet, *nbat, nbat->out[0], a0 + ((th + 0) * na) / nth,
-                                                a0 + ((th + 1) * na) / nth, f);
+            nbnxn_atomdata_add_nbat_f_to_f_part(
+                    gridSet, *nbat, nbat->out[0], a0 + ((th + 0) * na) / nth, a0 + ((th + 1) * na) / nth, f);
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
     }
@@ -1472,7 +1271,7 @@ void nbnxn_atomdata_add_nbat_fshift_to_fshift(const nbnxn_atomdata_t& nbat, gmx:
 {
     gmx::ArrayRef<const nbnxn_atomdata_output_t> outputBuffers = nbat.out;
 
-    for (int s = 0; s < SHIFTS; s++)
+    for (int s = 0; s < gmx::c_numShiftVectors; s++)
     {
         rvec sum;
         clear_rvec(sum);
index df3362b11489ed1de4dcef1a53880ea8b32a3d6c..23b0759abba388c9687a8a2ed073a87679952dc7 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@
 #include "gromacs/gpu_utils/hostallocator.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/mdtypes/locality.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/bitmask.h"
 #include "gromacs/utility/real.h"
 
@@ -64,7 +63,6 @@ class MDLogger;
 struct NbnxmGpu;
 struct nbnxn_atomdata_t;
 struct nonbonded_verlet_t;
-struct tMPI_Atomic;
 
 class GpuEventSynchronizer;
 
@@ -124,7 +122,7 @@ struct nbnxn_atomdata_output_t
 
     //! f, size natoms*fstride
     gmx::HostVector<real> f;
-    //! Shift force array, size SHIFTS*DIM
+    //! Shift force array, size c_numShiftVectors*DIM
     gmx::HostVector<real> fshift;
     //! Temporary Van der Waals group energy storage
     gmx::HostVector<real> Vvdw;
@@ -155,15 +153,22 @@ struct nbnxn_atomdata_output_t
 #define NBNXN_BUFFERFLAG_MAX_THREADS (BITMASK_SIZE)
 
 
-/*! \brief LJ combination rules: geometric, Lorentz-Berthelot, none */
-enum
+//! LJ combination rules
+enum class LJCombinationRule : int
 {
-    ljcrGEOM,
-    ljcrLB,
-    ljcrNONE,
-    ljcrNR
+    //! Geometric
+    Geometric,
+    //! Lorentz-Berthelot
+    LorentzBerthelot,
+    //! No rule
+    None,
+    //! Size of the enum
+    Count
 };
 
+//! String corresponding to LJ combination rule
+const char* enumValueToString(LJCombinationRule enumValue);
+
 /*! \internal
  * \brief Struct that stores atom related data for the nbnxn module
  *
@@ -187,7 +192,7 @@ struct nbnxn_atomdata_t
         //! Lennard-Jone 6*C6 and 12*C12 parameters, size numTypes*2*2
         gmx::HostVector<real> nbfp;
         //! Combination rule, see enum defined above
-        int comb_rule;
+        LJCombinationRule ljCombinationRule;
         //! LJ parameters per atom type, size numTypes*2
         gmx::HostVector<real> nbfp_comb;
         //! As nbfp, but with a stride for the present SIMD architecture
@@ -226,9 +231,24 @@ struct nbnxn_atomdata_t
 
     /*! \brief Constructor
      *
-     * \param[in] pinningPolicy  Sets the pinning policy for all data that might be transfered to a GPU
+     * \param[in] pinningPolicy      Sets the pinning policy for all data that might be transferred
+     *                               to a GPU
+     * \param[in] mdlog              The logger
+     * \param[in] kernelType         Nonbonded NxN kernel type
+     * \param[in] enbnxninitcombrule LJ combination rule
+     * \param[in] ntype              Number of atom types
+     * \param[in] nbfp               Non-bonded force parameters
+     * \param[in] n_energygroups     Number of energy groups
+     * \param[in] nout               Number of output data structures
      */
-    nbnxn_atomdata_t(gmx::PinningPolicy pinningPolicy);
+    nbnxn_atomdata_t(gmx::PinningPolicy        pinningPolicy,
+                     const gmx::MDLogger&      mdlog,
+                     Nbnxm::KernelType         kernelType,
+                     int                       enbnxninitcombrule,
+                     int                       ntype,
+                     gmx::ArrayRef<const real> nbfp,
+                     int                       n_energygroups,
+                     int                       nout);
 
     //! Returns a const reference to the parameters
     const Params& params() const { return params_; }
@@ -265,7 +285,7 @@ public:
     //! The format of f, enum
     int FFormat;
     //! Do we need to update shift_vec every step?
-    gmx_bool bDynamicBox;
+    bool bDynamicBox;
     //! Shift vectors, copied from t_forcerec
     gmx::HostVector<gmx::RVec> shift_vec;
     //! stride for a coordinate in x (usually 3 or 4)
@@ -287,13 +307,9 @@ public:
     //! Reduction related data
     //! \{
     //! Use the flags or operate on all atoms
-    gmx_bool bUseBufferFlags;
+    bool bUseBufferFlags;
     //! Flags for buffer zeroing+reduc.
     std::vector<gmx_bitmask_t> buffer_flags;
-    //! Use tree for force reduction
-    gmx_bool bUseTreeReduce;
-    //! Synchronization step for tree reduce
-    tMPI_Atomic* syncStep;
     //! \}
 };
 
@@ -311,22 +327,6 @@ enum
     enbnxninitcombruleNONE
 };
 
-/*! \brief Initialize the non-bonded atom data structure.
- *
- * The enum for nbatXFormat is in the file defining nbnxn_atomdata_t.
- * Copy the ntypes*ntypes*2 sized nbfp non-bonded parameter list
- * to the atom data structure.
- * enbnxninitcombrule sets what combination rule data gets stored in nbat.
- */
-void nbnxn_atomdata_init(const gmx::MDLogger&      mdlog,
-                         nbnxn_atomdata_t*         nbat,
-                         Nbnxm::KernelType         kernelType,
-                         int                       enbnxninitcombrule,
-                         int                       ntype,
-                         gmx::ArrayRef<const real> nbfp,
-                         int                       n_energygroups,
-                         int                       nout);
-
 //! Sets the atomdata after pair search
 void nbnxn_atomdata_set(nbnxn_atomdata_t*         nbat,
                         const Nbnxm::GridSet&     gridSet,
@@ -335,7 +335,7 @@ void nbnxn_atomdata_set(nbnxn_atomdata_t*         nbat,
                         gmx::ArrayRef<const int>  atomInfo);
 
 //! Copy the shift vectors to nbat
-void nbnxn_atomdata_copy_shiftvec(gmx_bool dynamic_box, rvec* shift_vec, nbnxn_atomdata_t* nbat);
+void nbnxn_atomdata_copy_shiftvec(bool dynamic_box, gmx::ArrayRef<gmx::RVec> shift_vec, nbnxn_atomdata_t* nbat);
 
 /*! \brief Transform coordinates to xbat layout
  *
@@ -343,13 +343,11 @@ void nbnxn_atomdata_copy_shiftvec(gmx_bool dynamic_box, rvec* shift_vec, nbnxn_a
  *
  * \param[in] gridSet      The grids data.
  * \param[in] locality     If the transformation should be applied to local or non local coordinates.
- * \param[in] fillLocal    Tells if the local filler particle coordinates should be zeroed.
  * \param[in] coordinates  Coordinates in plain rvec format.
  * \param[in,out] nbat     Data in NBNXM format, used for mapping formats and to locate the output buffer.
  */
 void nbnxn_atomdata_copy_x_to_nbat_x(const Nbnxm::GridSet& gridSet,
                                      gmx::AtomLocality     locality,
-                                     bool                  fillLocal,
                                      const rvec*           coordinates,
                                      nbnxn_atomdata_t*     nbat);
 
@@ -360,14 +358,12 @@ void nbnxn_atomdata_copy_x_to_nbat_x(const Nbnxm::GridSet& gridSet,
  *
  * \param[in]     gridSet    The grids data.
  * \param[in]     locality   If the transformation should be applied to local or non local coordinates.
- * \param[in]     fillLocal  Tells if the local filler particle coordinates should be zeroed.
  * \param[in,out] gpu_nbv    The NBNXM GPU data structure.
  * \param[in]     d_x        Coordinates to be copied (in plain rvec format).
  * \param[in]     xReadyOnDevice   Event synchronizer indicating that the coordinates are ready in the device memory.
  */
 void nbnxn_atomdata_x_to_nbat_x_gpu(const Nbnxm::GridSet&   gridSet,
                                     gmx::AtomLocality       locality,
-                                    bool                    fillLocal,
                                     NbnxmGpu*               gpu_nbv,
                                     DeviceBuffer<gmx::RVec> d_x,
                                     GpuEventSynchronizer*   xReadyOnDevice);
index af0b2926995fea593ab5f4921f8a60867986f600..5ac216df225f38e106e55bcdfb2c0ef5943e8a06 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
 #include <optional>
 
 #include "gromacs/gmxlib/nrnb.h"
+#include "gromacs/math/units.h"
+#include "gromacs/math/vectypes.h"
 #include "gromacs/mdlib/dispersioncorrection.h"
 #include "gromacs/mdlib/force_flags.h"
 #include "gromacs/mdlib/forcerec.h"
@@ -146,18 +148,19 @@ static interaction_const_t setupInteractionConst(const KernelBenchOptions& optio
 {
     interaction_const_t ic;
 
-    ic.vdwtype      = evdwCUT;
-    ic.vdw_modifier = eintmodPOTSHIFT;
+    ic.vdwtype      = VanDerWaalsType::Cut;
+    ic.vdw_modifier = InteractionModifiers::PotShift;
     ic.rvdw         = options.pairlistCutoff;
 
-    ic.eeltype          = (options.coulombType == BenchMarkCoulomb::Pme ? eelPME : eelRF);
-    ic.coulomb_modifier = eintmodPOTSHIFT;
+    ic.eeltype = (options.coulombType == BenchMarkCoulomb::Pme ? CoulombInteractionType::Pme
+                                                               : CoulombInteractionType::RF);
+    ic.coulomb_modifier = InteractionModifiers::PotShift;
     ic.rcoulomb         = options.pairlistCutoff;
 
-    // Reaction-field with epsilon_rf=inf
+    // Reaction-field with reactionFieldPermitivity=inf
     // TODO: Replace by calc_rffac() after refactoring that
-    ic.k_rf = 0.5 * std::pow(ic.rcoulomb, -3);
-    ic.c_rf = 1 / ic.rcoulomb + ic.k_rf * ic.rcoulomb * ic.rcoulomb;
+    ic.reactionFieldCoefficient = 0.5 * std::pow(ic.rcoulomb, -3);
+    ic.reactionFieldShift = 1 / ic.rcoulomb + ic.reactionFieldCoefficient * ic.rcoulomb * ic.rcoulomb;
 
     if (EEL_PME_EWALD(ic.eeltype))
     {
@@ -190,23 +193,26 @@ static std::unique_ptr<nonbonded_verlet_t> setupNbnxmForBenchInstance(const Kern
 
     PairlistParams pairlistParams(kernelSetup.kernelType, false, options.pairlistCutoff, false);
 
-    GridSet gridSet(PbcType::Xyz, false, nullptr, nullptr, pairlistParams.pairlistType, false,
-                    numThreads, pinPolicy);
+    GridSet gridSet(
+            PbcType::Xyz, false, nullptr, nullptr, pairlistParams.pairlistType, false, numThreads, pinPolicy);
 
     auto pairlistSets = std::make_unique<PairlistSets>(pairlistParams, false, 0);
 
-    auto pairSearch =
-            std::make_unique<PairSearch>(PbcType::Xyz, false, nullptr, nullptr,
-                                         pairlistParams.pairlistType, false, numThreads, pinPolicy);
+    auto pairSearch = std::make_unique<PairSearch>(
+            PbcType::Xyz, false, nullptr, nullptr, pairlistParams.pairlistType, false, numThreads, pinPolicy);
 
-    auto atomData = std::make_unique<nbnxn_atomdata_t>(pinPolicy);
+    auto atomData = std::make_unique<nbnxn_atomdata_t>(pinPolicy,
+                                                       gmx::MDLogger(),
+                                                       kernelSetup.kernelType,
+                                                       combinationRule,
+                                                       system.numAtomTypes,
+                                                       system.nonbondedParameters,
+                                                       1,
+                                                       numThreads);
 
     // Put everything together
-    auto nbv = std::make_unique<nonbonded_verlet_t>(std::move(pairlistSets), std::move(pairSearch),
-                                                    std::move(atomData), kernelSetup, nullptr, nullptr);
-
-    nbnxn_atomdata_init(gmx::MDLogger(), nbv->nbat.get(), kernelSetup.kernelType, combinationRule,
-                        system.numAtomTypes, system.nonbondedParameters, 1, numThreads);
+    auto nbv = std::make_unique<nonbonded_verlet_t>(
+            std::move(pairlistSets), std::move(pairSearch), std::move(atomData), kernelSetup, nullptr, nullptr);
 
     t_nrnb nrnb;
 
@@ -226,9 +232,18 @@ static std::unique_ptr<nonbonded_verlet_t> setupNbnxmForBenchInstance(const Kern
 
     const real atomDensity = system.coordinates.size() / det(system.box);
 
-    nbnxn_put_on_grid(nbv.get(), system.box, 0, lowerCorner, upperCorner, nullptr,
-                      { 0, int(system.coordinates.size()) }, atomDensity, atomInfo,
-                      system.coordinates, 0, nullptr);
+    nbnxn_put_on_grid(nbv.get(),
+                      system.box,
+                      0,
+                      lowerCorner,
+                      upperCorner,
+                      nullptr,
+                      { 0, int(system.coordinates.size()) },
+                      atomDensity,
+                      atomInfo,
+                      system.coordinates,
+                      0,
+                      nullptr);
 
     nbv->constructPairlist(gmx::InteractionLocality::Local, system.excls, 0, &nrnb);
 
@@ -297,18 +312,22 @@ static void setupAndRunInstance(const gmx::BenchmarkSystem& system,
         stepWork.computeEnergy = true;
     }
 
-    const gmx::EnumerationArray<BenchMarkKernels, std::string> kernelNames = { "auto", "no", "4xM",
-                                                                               "2xMM" };
+    const gmx::EnumerationArray<BenchMarkKernels, std::string> kernelNames = {
+        "auto", "no", "4xM", "2xMM"
+    };
 
-    const gmx::EnumerationArray<BenchMarkCombRule, std::string> combruleNames = { "geom.", "LB",
+    const gmx::EnumerationArray<BenchMarkCombRule, std::string> combruleNames = { "geom.",
+                                                                                  "LB",
                                                                                   "none" };
 
     if (!doWarmup)
     {
-        fprintf(stdout, "%-7s %-4s %-5s %-4s ",
+        fprintf(stdout,
+                "%-7s %-4s %-5s %-4s ",
                 options.coulombType == BenchMarkCoulomb::Pme ? "Ewald" : "RF",
                 options.useHalfLJOptimization ? "half" : "all",
-                combruleNames[options.ljCombinationRule].c_str(), kernelNames[options.nbnxmSimd].c_str());
+                combruleNames[options.ljCombinationRule].c_str(),
+                kernelNames[options.nbnxmSimd].c_str());
         if (!options.outputFile.empty())
         {
             fprintf(system.csv,
@@ -319,8 +338,11 @@ static void setupAndRunInstance(const gmx::BenchmarkSystem& system,
 #else
                     0,
 #endif
-                    system.coordinates.size(), options.pairlistCutoff, options.numThreads,
-                    options.numIterations, options.computeVirialAndEnergy ? "yes" : "no",
+                    system.coordinates.size(),
+                    options.pairlistCutoff,
+                    options.numThreads,
+                    options.numIterations,
+                    options.computeVirialAndEnergy ? "yes" : "no",
                     (options.coulombType != BenchMarkCoulomb::ReactionField)
                             ? ((options.nbnxmSimd == BenchMarkKernels::SimdNo || options.useTabulatedEwaldCorr)
                                        ? "table"
@@ -336,8 +358,16 @@ static void setupAndRunInstance(const gmx::BenchmarkSystem& system,
     // Run pre-iteration to avoid cache misses
     for (int iter = 0; iter < options.numPreIterations; iter++)
     {
-        nbv->dispatchNonbondedKernel(gmx::InteractionLocality::Local, ic, stepWork, enbvClearFYes,
-                                     system.forceRec, &enerd, &nrnb);
+        nbv->dispatchNonbondedKernel(
+                gmx::InteractionLocality::Local,
+                ic,
+                stepWork,
+                enbvClearFYes,
+                system.forceRec.shift_vec,
+                enerd.grpp.energyGroupPairTerms[system.forceRec.haveBuckingham ? NonBondedEnergyTerms::BuckinghamSR
+                                                                               : NonBondedEnergyTerms::LJSR],
+                enerd.grpp.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR],
+                &nrnb);
     }
 
     const int numIterations = (doWarmup ? options.numWarmupIterations : options.numIterations);
@@ -347,8 +377,16 @@ static void setupAndRunInstance(const gmx::BenchmarkSystem& system,
     for (int iter = 0; iter < numIterations; iter++)
     {
         // Run the kernel without force clearing
-        nbv->dispatchNonbondedKernel(gmx::InteractionLocality::Local, ic, stepWork, enbvClearFNo,
-                                     system.forceRec, &enerd, &nrnb);
+        nbv->dispatchNonbondedKernel(
+                gmx::InteractionLocality::Local,
+                ic,
+                stepWork,
+                enbvClearFNo,
+                system.forceRec.shift_vec,
+                enerd.grpp.energyGroupPairTerms[system.forceRec.haveBuckingham ? NonBondedEnergyTerms::BuckinghamSR
+                                                                               : NonBondedEnergyTerms::LJSR],
+                enerd.grpp.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR],
+                &nrnb);
     }
     cycles = gmx_cycles_read() - cycles;
     if (!doWarmup)
@@ -358,25 +396,37 @@ static void setupAndRunInstance(const gmx::BenchmarkSystem& system,
             const double uSec = static_cast<double>(cycles) * gmx_cycles_calibrate(1.0) * 1.e6;
             if (options.cyclesPerPair)
             {
-                fprintf(stdout, "%13.2f %13.3f %10.3f %10.3f\n", uSec, uSec / options.numIterations,
+                fprintf(stdout,
+                        "%13.2f %13.3f %10.3f %10.3f\n",
+                        uSec,
+                        uSec / options.numIterations,
                         uSec / (options.numIterations * numPairs),
                         uSec / (options.numIterations * numUsefulPairs));
                 if (!options.outputFile.empty())
                 {
-                    fprintf(system.csv, "\"%.3f\",\"%.4f\",\"%.4f\",\"%.4f\"\n", uSec,
-                            uSec / options.numIterations, uSec / (options.numIterations * numPairs),
+                    fprintf(system.csv,
+                            "\"%.3f\",\"%.4f\",\"%.4f\",\"%.4f\"\n",
+                            uSec,
+                            uSec / options.numIterations,
+                            uSec / (options.numIterations * numPairs),
                             uSec / (options.numIterations * numUsefulPairs));
                 }
             }
             else
             {
-                fprintf(stdout, "%13.2f %13.3f %10.3f %10.3f\n", uSec, uSec / options.numIterations,
+                fprintf(stdout,
+                        "%13.2f %13.3f %10.3f %10.3f\n",
+                        uSec,
+                        uSec / options.numIterations,
                         options.numIterations * numPairs / uSec,
                         options.numIterations * numUsefulPairs / uSec);
                 if (!options.outputFile.empty())
                 {
-                    fprintf(system.csv, "\"%.3f\",\"%.4f\",\"%.4f\",\"%.4f\"\n", uSec,
-                            uSec / options.numIterations, options.numIterations * numPairs / uSec,
+                    fprintf(system.csv,
+                            "\"%.3f\",\"%.4f\",\"%.4f\",\"%.4f\"\n",
+                            uSec,
+                            uSec / options.numIterations,
+                            options.numIterations * numPairs / uSec,
                             options.numIterations * numUsefulPairs / uSec);
                 }
             }
@@ -386,15 +436,20 @@ static void setupAndRunInstance(const gmx::BenchmarkSystem& system,
             const double dCycles = static_cast<double>(cycles);
             if (options.cyclesPerPair)
             {
-                fprintf(stdout, "%10.3f %10.4f %8.4f %8.4f\n", cycles * 1e-6,
+                fprintf(stdout,
+                        "%10.3f %10.4f %8.4f %8.4f\n",
+                        cycles * 1e-6,
                         dCycles / options.numIterations * 1e-6,
                         dCycles / (options.numIterations * numPairs),
                         dCycles / (options.numIterations * numUsefulPairs));
             }
             else
             {
-                fprintf(stdout, "%10.3f %10.4f %8.4f %8.4f\n", dCycles * 1e-6,
-                        dCycles / options.numIterations * 1e-6, options.numIterations * numPairs / dCycles,
+                fprintf(stdout,
+                        "%10.3f %10.4f %8.4f %8.4f\n",
+                        dCycles * 1e-6,
+                        dCycles / options.numIterations * 1e-6,
+                        options.numIterations * numPairs / dCycles,
                         options.numIterations * numUsefulPairs / dCycles);
             }
         }
@@ -404,8 +459,8 @@ static void setupAndRunInstance(const gmx::BenchmarkSystem& system,
 void bench(const int sizeFactor, const KernelBenchOptions& options)
 {
     // We don't want to call gmx_omp_nthreads_init(), so we init what we need
-    gmx_omp_nthreads_set(emntPairsearch, options.numThreads);
-    gmx_omp_nthreads_set(emntNonbonded, options.numThreads);
+    gmx_omp_nthreads_set(ModuleMultiThread::Pairsearch, options.numThreads);
+    gmx_omp_nthreads_set(ModuleMultiThread::Nonbonded, options.numThreads);
 
     const gmx::BenchmarkSystem system(sizeFactor, options.outputFile);
 
@@ -460,7 +515,8 @@ void bench(const int sizeFactor, const KernelBenchOptions& options)
     fprintf(stdout, "Compute energies:     %s\n", options.computeVirialAndEnergy ? "yes" : "no");
     if (options.coulombType != BenchMarkCoulomb::ReactionField)
     {
-        fprintf(stdout, "Ewald excl. corr.:    %s\n",
+        fprintf(stdout,
+                "Ewald excl. corr.:    %s\n",
                 options.nbnxmSimd == BenchMarkKernels::SimdNo || options.useTabulatedEwaldCorr
                         ? "table"
                         : "analytical");
@@ -474,7 +530,8 @@ void bench(const int sizeFactor, const KernelBenchOptions& options)
 
     if (options.reportTime)
     {
-        fprintf(stdout, "Coulomb LJ   comb. SIMD       usec         usec/it.        %s\n",
+        fprintf(stdout,
+                "Coulomb LJ   comb. SIMD       usec         usec/it.        %s\n",
                 options.cyclesPerPair ? "usec/pair" : "pairs/usec");
         if (!options.outputFile.empty())
         {
@@ -489,7 +546,8 @@ void bench(const int sizeFactor, const KernelBenchOptions& options)
     }
     else
     {
-        fprintf(stdout, "Coulomb LJ   comb. SIMD    Mcycles  Mcycles/it.   %s\n",
+        fprintf(stdout,
+                "Coulomb LJ   comb. SIMD    Mcycles  Mcycles/it.   %s\n",
                 options.cyclesPerPair ? "cycles/pair" : "pairs/cycle");
         if (!options.outputFile.empty())
         {
index de4d738969b6e6daeebc94a9805a857c0682fb3f..1ba1c01d90e1c8ca2075b80fbc3f9f1fb026189d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ constexpr real c12Oxygen = 2.634129e-06;
 // A fatal error is generated when this is not the case.
 static void generateCoordinates(int multiplicationFactor, std::vector<gmx::RVec>* coordinates, matrix box)
 {
-    if (multiplicationFactor < 1 || (multiplicationFactor & (multiplicationFactor - 1)) != 0)
+    if (!gmx::isPowerOfTwo(multiplicationFactor))
     {
         gmx_fatal(FARGS, "The size factor has to be a power of 2");
     }
@@ -115,8 +115,11 @@ static void generateCoordinates(int multiplicationFactor, std::vector<gmx::RVec>
             dim = 0;
         }
     }
-    printf("Stacking a box of %zu atoms %d x %d x %d times\n", coordinates1000.size(), factors[XX],
-           factors[YY], factors[ZZ]);
+    printf("Stacking a box of %zu atoms %d x %d x %d times\n",
+           coordinates1000.size(),
+           factors[XX],
+           factors[YY],
+           factors[ZZ]);
 
     coordinates->resize(factors[XX] * factors[YY] * factors[ZZ] * coordinates1000.size());
 
@@ -197,7 +200,7 @@ BenchmarkSystem::BenchmarkSystem(const int multiplicationFactor, const std::stri
 
     forceRec.ntype = numAtomTypes;
     forceRec.nbfp  = nonbondedParameters;
-    snew(forceRec.shift_vec, SHIFTS);
+    forceRec.shift_vec.resize(gmx::c_numShiftVectors);
     calc_shifts(box, forceRec.shift_vec);
     if (!outputFile.empty())
     {
index c7f680ab0c76f32b82ba1c51c5c9af0bb6a77388..80da0881e21f5b84693be3ac847bcfe24bf6d689 100644 (file)
@@ -87,8 +87,7 @@ static inline ClusterDistanceKernelType getClusterDistanceKernelType(const Pairl
 #elif GMX_SIMD && GMX_SIMD_REAL_WIDTH == 8
         return ClusterDistanceKernelType::CpuSimd_2xMM;
 #else
-        GMX_RELEASE_ASSERT(false,
-                           "Expect 4-wide or 8-wide SIMD with 4x4 list and nbat SIMD layout");
+        GMX_RELEASE_ASSERT(false, "Expect 4-wide or 8-wide SIMD with 4x4 list and nbat SIMD layout");
 #endif
     }
     else
index 9a9ffc6c1ce8ca46bd4f726eb4fab006e1c2d2cd..2df2a14ea2e96e2723a8d4fcdc3295602cc6552b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +53,6 @@
 
  * \param[in]     numColumns          Extent of cell-level parallelism.
  * \param[out]    gm_xq               Coordinates buffer in nbnxm layout.
- * \tparam        setFillerCoords     Whether to set the coordinates of the filler particles.
  * \param[in]     gm_x                Coordinates buffer.
  * \param[in]     gm_atomIndex        Atom index mapping.
  * \param[in]     gm_numAtoms         Array of number of atoms.
@@ -61,7 +60,6 @@
  * \param[in]     cellOffset          First cell.
  * \param[in]     numAtomsPerCell     Number of atoms per cell.
  */
-template<bool setFillerCoords>
 static __global__ void nbnxn_gpu_x_to_nbat_x_kernel(int numColumns,
                                                     float4* __restrict__ gm_xq,
                                                     const float3* __restrict__ gm_x,
@@ -83,19 +81,6 @@ static __global__ void nbnxn_gpu_x_to_nbat_x_kernel(int numColumns,
 
         const int numAtoms = gm_numAtoms[cxy];
         const int offset   = (cellOffset + gm_cellIndex[cxy]) * numAtomsPerCell;
-        int       numAtomsRounded;
-        if (setFillerCoords)
-        {
-            // TODO: This can be done more efficiently
-            numAtomsRounded = (gm_cellIndex[cxy + 1] - gm_cellIndex[cxy]) * numAtomsPerCell;
-        }
-        else
-        {
-            // We fill only the real particle locations.
-            // We assume the filling entries at the end have been
-            // properly set before during pair-list generation.
-            numAtomsRounded = numAtoms;
-        }
 
         const int threadIndex = blockIdx.x * blockDim.x + threadIdx.x;
 
@@ -104,7 +89,7 @@ static __global__ void nbnxn_gpu_x_to_nbat_x_kernel(int numColumns,
         float3* gm_xqDest = (float3*)&gm_xq[threadIndex + offset];
 
         // Perform layout conversion of each element.
-        if (threadIndex < numAtomsRounded)
+        if (threadIndex < numAtoms)
         {
             if (threadIndex < numAtoms)
             {
index 48f02fde9e55783bef5f8592247c5499d8c020b7..4869756afef30f3444f30c726773d4498623e367 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +122,7 @@ namespace Nbnxm
 constexpr static int c_bufOpsThreadsPerBlock = 128;
 
 /*! Nonbonded kernel function pointer type */
-typedef void (*nbnxn_cu_kfunc_ptr_t)(const cu_atomdata_t, const NBParamGpu, const gpu_plist, bool);
+typedef void (*nbnxn_cu_kfunc_ptr_t)(const NBAtomDataGpu, const NBParamGpu, const gpu_plist, bool);
 
 /*********************************/
 
@@ -145,7 +145,8 @@ static inline int calc_nb_kernel_nblock(int nwork_units, const DeviceInformation
                   "Watch out, the input system is too large to simulate!\n"
                   "The number of nonbonded work units (=number of super-clusters) exceeds the"
                   "maximum grid size in x dimension (%d > %d)!",
-                  nwork_units, max_grid_x_size);
+                  nwork_units,
+                  max_grid_x_size);
     }
 
     return nwork_units;
@@ -164,104 +165,165 @@ static inline int calc_nb_kernel_nblock(int nwork_units, const DeviceInformation
  */
 
 /*! Force-only kernel function pointers. */
-static const nbnxn_cu_kfunc_ptr_t nb_kfunc_noener_noprune_ptr[eelTypeNR][evdwTypeNR] = {
-    { nbnxn_kernel_ElecCut_VdwLJ_F_cuda, nbnxn_kernel_ElecCut_VdwLJCombGeom_F_cuda,
-      nbnxn_kernel_ElecCut_VdwLJCombLB_F_cuda, nbnxn_kernel_ElecCut_VdwLJFsw_F_cuda,
-      nbnxn_kernel_ElecCut_VdwLJPsw_F_cuda, nbnxn_kernel_ElecCut_VdwLJEwCombGeom_F_cuda,
+static const nbnxn_cu_kfunc_ptr_t nb_kfunc_noener_noprune_ptr[c_numElecTypes][c_numVdwTypes] = {
+    { nbnxn_kernel_ElecCut_VdwLJ_F_cuda,
+      nbnxn_kernel_ElecCut_VdwLJCombGeom_F_cuda,
+      nbnxn_kernel_ElecCut_VdwLJCombLB_F_cuda,
+      nbnxn_kernel_ElecCut_VdwLJFsw_F_cuda,
+      nbnxn_kernel_ElecCut_VdwLJPsw_F_cuda,
+      nbnxn_kernel_ElecCut_VdwLJEwCombGeom_F_cuda,
       nbnxn_kernel_ElecCut_VdwLJEwCombLB_F_cuda },
-    { nbnxn_kernel_ElecRF_VdwLJ_F_cuda, nbnxn_kernel_ElecRF_VdwLJCombGeom_F_cuda,
-      nbnxn_kernel_ElecRF_VdwLJCombLB_F_cuda, nbnxn_kernel_ElecRF_VdwLJFsw_F_cuda,
-      nbnxn_kernel_ElecRF_VdwLJPsw_F_cuda, nbnxn_kernel_ElecRF_VdwLJEwCombGeom_F_cuda,
+    { nbnxn_kernel_ElecRF_VdwLJ_F_cuda,
+      nbnxn_kernel_ElecRF_VdwLJCombGeom_F_cuda,
+      nbnxn_kernel_ElecRF_VdwLJCombLB_F_cuda,
+      nbnxn_kernel_ElecRF_VdwLJFsw_F_cuda,
+      nbnxn_kernel_ElecRF_VdwLJPsw_F_cuda,
+      nbnxn_kernel_ElecRF_VdwLJEwCombGeom_F_cuda,
       nbnxn_kernel_ElecRF_VdwLJEwCombLB_F_cuda },
-    { nbnxn_kernel_ElecEwQSTab_VdwLJ_F_cuda, nbnxn_kernel_ElecEwQSTab_VdwLJCombGeom_F_cuda,
-      nbnxn_kernel_ElecEwQSTab_VdwLJCombLB_F_cuda, nbnxn_kernel_ElecEwQSTab_VdwLJFsw_F_cuda,
-      nbnxn_kernel_ElecEwQSTab_VdwLJPsw_F_cuda, nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_F_cuda,
+    { nbnxn_kernel_ElecEwQSTab_VdwLJ_F_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJCombGeom_F_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJCombLB_F_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJFsw_F_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJPsw_F_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_F_cuda,
       nbnxn_kernel_ElecEwQSTab_VdwLJEwCombLB_F_cuda },
-    { nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJ_F_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJCombGeom_F_cuda,
-      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJCombLB_F_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJFsw_F_cuda,
-      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_F_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombGeom_F_cuda,
+    { nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJ_F_cuda,
+      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJCombGeom_F_cuda,
+      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJCombLB_F_cuda,
+      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJFsw_F_cuda,
+      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_F_cuda,
+      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombGeom_F_cuda,
       nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombLB_F_cuda },
-    { nbnxn_kernel_ElecEw_VdwLJ_F_cuda, nbnxn_kernel_ElecEw_VdwLJCombGeom_F_cuda,
-      nbnxn_kernel_ElecEw_VdwLJCombLB_F_cuda, nbnxn_kernel_ElecEw_VdwLJFsw_F_cuda,
-      nbnxn_kernel_ElecEw_VdwLJPsw_F_cuda, nbnxn_kernel_ElecEw_VdwLJEwCombGeom_F_cuda,
+    { nbnxn_kernel_ElecEw_VdwLJ_F_cuda,
+      nbnxn_kernel_ElecEw_VdwLJCombGeom_F_cuda,
+      nbnxn_kernel_ElecEw_VdwLJCombLB_F_cuda,
+      nbnxn_kernel_ElecEw_VdwLJFsw_F_cuda,
+      nbnxn_kernel_ElecEw_VdwLJPsw_F_cuda,
+      nbnxn_kernel_ElecEw_VdwLJEwCombGeom_F_cuda,
       nbnxn_kernel_ElecEw_VdwLJEwCombLB_F_cuda },
-    { nbnxn_kernel_ElecEwTwinCut_VdwLJ_F_cuda, nbnxn_kernel_ElecEwTwinCut_VdwLJCombGeom_F_cuda,
-      nbnxn_kernel_ElecEwTwinCut_VdwLJCombLB_F_cuda, nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_F_cuda,
-      nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_F_cuda, nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombGeom_F_cuda,
+    { nbnxn_kernel_ElecEwTwinCut_VdwLJ_F_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJCombGeom_F_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJCombLB_F_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_F_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_F_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombGeom_F_cuda,
       nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombLB_F_cuda }
 };
 
 /*! Force + energy kernel function pointers. */
-static const nbnxn_cu_kfunc_ptr_t nb_kfunc_ener_noprune_ptr[eelTypeNR][evdwTypeNR] = {
-    { nbnxn_kernel_ElecCut_VdwLJ_VF_cuda, nbnxn_kernel_ElecCut_VdwLJCombGeom_VF_cuda,
-      nbnxn_kernel_ElecCut_VdwLJCombLB_VF_cuda, nbnxn_kernel_ElecCut_VdwLJFsw_VF_cuda,
-      nbnxn_kernel_ElecCut_VdwLJPsw_VF_cuda, nbnxn_kernel_ElecCut_VdwLJEwCombGeom_VF_cuda,
+static const nbnxn_cu_kfunc_ptr_t nb_kfunc_ener_noprune_ptr[c_numElecTypes][c_numVdwTypes] = {
+    { nbnxn_kernel_ElecCut_VdwLJ_VF_cuda,
+      nbnxn_kernel_ElecCut_VdwLJCombGeom_VF_cuda,
+      nbnxn_kernel_ElecCut_VdwLJCombLB_VF_cuda,
+      nbnxn_kernel_ElecCut_VdwLJFsw_VF_cuda,
+      nbnxn_kernel_ElecCut_VdwLJPsw_VF_cuda,
+      nbnxn_kernel_ElecCut_VdwLJEwCombGeom_VF_cuda,
       nbnxn_kernel_ElecCut_VdwLJEwCombLB_VF_cuda },
-    { nbnxn_kernel_ElecRF_VdwLJ_VF_cuda, nbnxn_kernel_ElecRF_VdwLJCombGeom_VF_cuda,
-      nbnxn_kernel_ElecRF_VdwLJCombLB_VF_cuda, nbnxn_kernel_ElecRF_VdwLJFsw_VF_cuda,
-      nbnxn_kernel_ElecRF_VdwLJPsw_VF_cuda, nbnxn_kernel_ElecRF_VdwLJEwCombGeom_VF_cuda,
+    { nbnxn_kernel_ElecRF_VdwLJ_VF_cuda,
+      nbnxn_kernel_ElecRF_VdwLJCombGeom_VF_cuda,
+      nbnxn_kernel_ElecRF_VdwLJCombLB_VF_cuda,
+      nbnxn_kernel_ElecRF_VdwLJFsw_VF_cuda,
+      nbnxn_kernel_ElecRF_VdwLJPsw_VF_cuda,
+      nbnxn_kernel_ElecRF_VdwLJEwCombGeom_VF_cuda,
       nbnxn_kernel_ElecRF_VdwLJEwCombLB_VF_cuda },
-    { nbnxn_kernel_ElecEwQSTab_VdwLJ_VF_cuda, nbnxn_kernel_ElecEwQSTab_VdwLJCombGeom_VF_cuda,
-      nbnxn_kernel_ElecEwQSTab_VdwLJCombLB_VF_cuda, nbnxn_kernel_ElecEwQSTab_VdwLJFsw_VF_cuda,
-      nbnxn_kernel_ElecEwQSTab_VdwLJPsw_VF_cuda, nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_VF_cuda,
+    { nbnxn_kernel_ElecEwQSTab_VdwLJ_VF_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJCombGeom_VF_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJCombLB_VF_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJFsw_VF_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJPsw_VF_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_VF_cuda,
       nbnxn_kernel_ElecEwQSTab_VdwLJEwCombLB_VF_cuda },
-    { nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJ_VF_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJCombGeom_VF_cuda,
-      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJCombLB_VF_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJFsw_VF_cuda,
-      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_VF_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombGeom_VF_cuda,
+    { nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJ_VF_cuda,
+      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJCombGeom_VF_cuda,
+      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJCombLB_VF_cuda,
+      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJFsw_VF_cuda,
+      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_VF_cuda,
+      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombGeom_VF_cuda,
       nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombLB_VF_cuda },
-    { nbnxn_kernel_ElecEw_VdwLJ_VF_cuda, nbnxn_kernel_ElecEw_VdwLJCombGeom_VF_cuda,
-      nbnxn_kernel_ElecEw_VdwLJCombLB_VF_cuda, nbnxn_kernel_ElecEw_VdwLJFsw_VF_cuda,
-      nbnxn_kernel_ElecEw_VdwLJPsw_VF_cuda, nbnxn_kernel_ElecEw_VdwLJEwCombGeom_VF_cuda,
+    { nbnxn_kernel_ElecEw_VdwLJ_VF_cuda,
+      nbnxn_kernel_ElecEw_VdwLJCombGeom_VF_cuda,
+      nbnxn_kernel_ElecEw_VdwLJCombLB_VF_cuda,
+      nbnxn_kernel_ElecEw_VdwLJFsw_VF_cuda,
+      nbnxn_kernel_ElecEw_VdwLJPsw_VF_cuda,
+      nbnxn_kernel_ElecEw_VdwLJEwCombGeom_VF_cuda,
       nbnxn_kernel_ElecEw_VdwLJEwCombLB_VF_cuda },
-    { nbnxn_kernel_ElecEwTwinCut_VdwLJ_VF_cuda, nbnxn_kernel_ElecEwTwinCut_VdwLJCombGeom_VF_cuda,
-      nbnxn_kernel_ElecEwTwinCut_VdwLJCombLB_VF_cuda, nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_VF_cuda,
-      nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_VF_cuda, nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombGeom_VF_cuda,
+    { nbnxn_kernel_ElecEwTwinCut_VdwLJ_VF_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJCombGeom_VF_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJCombLB_VF_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_VF_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_VF_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombGeom_VF_cuda,
       nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombLB_VF_cuda }
 };
 
 /*! Force + pruning kernel function pointers. */
-static const nbnxn_cu_kfunc_ptr_t nb_kfunc_noener_prune_ptr[eelTypeNR][evdwTypeNR] = {
-    { nbnxn_kernel_ElecCut_VdwLJ_F_prune_cuda, nbnxn_kernel_ElecCut_VdwLJCombGeom_F_prune_cuda,
-      nbnxn_kernel_ElecCut_VdwLJCombLB_F_prune_cuda, nbnxn_kernel_ElecCut_VdwLJFsw_F_prune_cuda,
-      nbnxn_kernel_ElecCut_VdwLJPsw_F_prune_cuda, nbnxn_kernel_ElecCut_VdwLJEwCombGeom_F_prune_cuda,
+static const nbnxn_cu_kfunc_ptr_t nb_kfunc_noener_prune_ptr[c_numElecTypes][c_numVdwTypes] = {
+    { nbnxn_kernel_ElecCut_VdwLJ_F_prune_cuda,
+      nbnxn_kernel_ElecCut_VdwLJCombGeom_F_prune_cuda,
+      nbnxn_kernel_ElecCut_VdwLJCombLB_F_prune_cuda,
+      nbnxn_kernel_ElecCut_VdwLJFsw_F_prune_cuda,
+      nbnxn_kernel_ElecCut_VdwLJPsw_F_prune_cuda,
+      nbnxn_kernel_ElecCut_VdwLJEwCombGeom_F_prune_cuda,
       nbnxn_kernel_ElecCut_VdwLJEwCombLB_F_prune_cuda },
-    { nbnxn_kernel_ElecRF_VdwLJ_F_prune_cuda, nbnxn_kernel_ElecRF_VdwLJCombGeom_F_prune_cuda,
-      nbnxn_kernel_ElecRF_VdwLJCombLB_F_prune_cuda, nbnxn_kernel_ElecRF_VdwLJFsw_F_prune_cuda,
-      nbnxn_kernel_ElecRF_VdwLJPsw_F_prune_cuda, nbnxn_kernel_ElecRF_VdwLJEwCombGeom_F_prune_cuda,
+    { nbnxn_kernel_ElecRF_VdwLJ_F_prune_cuda,
+      nbnxn_kernel_ElecRF_VdwLJCombGeom_F_prune_cuda,
+      nbnxn_kernel_ElecRF_VdwLJCombLB_F_prune_cuda,
+      nbnxn_kernel_ElecRF_VdwLJFsw_F_prune_cuda,
+      nbnxn_kernel_ElecRF_VdwLJPsw_F_prune_cuda,
+      nbnxn_kernel_ElecRF_VdwLJEwCombGeom_F_prune_cuda,
       nbnxn_kernel_ElecRF_VdwLJEwCombLB_F_prune_cuda },
-    { nbnxn_kernel_ElecEwQSTab_VdwLJ_F_prune_cuda, nbnxn_kernel_ElecEwQSTab_VdwLJCombGeom_F_prune_cuda,
-      nbnxn_kernel_ElecEwQSTab_VdwLJCombLB_F_prune_cuda, nbnxn_kernel_ElecEwQSTab_VdwLJFsw_F_prune_cuda,
-      nbnxn_kernel_ElecEwQSTab_VdwLJPsw_F_prune_cuda, nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_F_prune_cuda,
+    { nbnxn_kernel_ElecEwQSTab_VdwLJ_F_prune_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJCombGeom_F_prune_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJCombLB_F_prune_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJFsw_F_prune_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJPsw_F_prune_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_F_prune_cuda,
       nbnxn_kernel_ElecEwQSTab_VdwLJEwCombLB_F_prune_cuda },
     { nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJ_F_prune_cuda,
       nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJCombGeom_F_prune_cuda,
       nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJCombLB_F_prune_cuda,
-      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJFsw_F_prune_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_F_prune_cuda,
+      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJFsw_F_prune_cuda,
+      nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_F_prune_cuda,
       nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombGeom_F_prune_cuda,
       nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombLB_F_prune_cuda },
-    { nbnxn_kernel_ElecEw_VdwLJ_F_prune_cuda, nbnxn_kernel_ElecEw_VdwLJCombGeom_F_prune_cuda,
-      nbnxn_kernel_ElecEw_VdwLJCombLB_F_prune_cuda, nbnxn_kernel_ElecEw_VdwLJFsw_F_prune_cuda,
-      nbnxn_kernel_ElecEw_VdwLJPsw_F_prune_cuda, nbnxn_kernel_ElecEw_VdwLJEwCombGeom_F_prune_cuda,
+    { nbnxn_kernel_ElecEw_VdwLJ_F_prune_cuda,
+      nbnxn_kernel_ElecEw_VdwLJCombGeom_F_prune_cuda,
+      nbnxn_kernel_ElecEw_VdwLJCombLB_F_prune_cuda,
+      nbnxn_kernel_ElecEw_VdwLJFsw_F_prune_cuda,
+      nbnxn_kernel_ElecEw_VdwLJPsw_F_prune_cuda,
+      nbnxn_kernel_ElecEw_VdwLJEwCombGeom_F_prune_cuda,
       nbnxn_kernel_ElecEw_VdwLJEwCombLB_F_prune_cuda },
-    { nbnxn_kernel_ElecEwTwinCut_VdwLJ_F_prune_cuda, nbnxn_kernel_ElecEwTwinCut_VdwLJCombGeom_F_prune_cuda,
-      nbnxn_kernel_ElecEwTwinCut_VdwLJCombLB_F_prune_cuda, nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_F_prune_cuda,
-      nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_F_prune_cuda, nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombGeom_F_prune_cuda,
+    { nbnxn_kernel_ElecEwTwinCut_VdwLJ_F_prune_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJCombGeom_F_prune_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJCombLB_F_prune_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_F_prune_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_F_prune_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombGeom_F_prune_cuda,
       nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombLB_F_prune_cuda }
 };
 
 /*! Force + energy + pruning kernel function pointers. */
-static const nbnxn_cu_kfunc_ptr_t nb_kfunc_ener_prune_ptr[eelTypeNR][evdwTypeNR] = {
-    { nbnxn_kernel_ElecCut_VdwLJ_VF_prune_cuda, nbnxn_kernel_ElecCut_VdwLJCombGeom_VF_prune_cuda,
-      nbnxn_kernel_ElecCut_VdwLJCombLB_VF_prune_cuda, nbnxn_kernel_ElecCut_VdwLJFsw_VF_prune_cuda,
-      nbnxn_kernel_ElecCut_VdwLJPsw_VF_prune_cuda, nbnxn_kernel_ElecCut_VdwLJEwCombGeom_VF_prune_cuda,
+static const nbnxn_cu_kfunc_ptr_t nb_kfunc_ener_prune_ptr[c_numElecTypes][c_numVdwTypes] = {
+    { nbnxn_kernel_ElecCut_VdwLJ_VF_prune_cuda,
+      nbnxn_kernel_ElecCut_VdwLJCombGeom_VF_prune_cuda,
+      nbnxn_kernel_ElecCut_VdwLJCombLB_VF_prune_cuda,
+      nbnxn_kernel_ElecCut_VdwLJFsw_VF_prune_cuda,
+      nbnxn_kernel_ElecCut_VdwLJPsw_VF_prune_cuda,
+      nbnxn_kernel_ElecCut_VdwLJEwCombGeom_VF_prune_cuda,
       nbnxn_kernel_ElecCut_VdwLJEwCombLB_VF_prune_cuda },
-    { nbnxn_kernel_ElecRF_VdwLJ_VF_prune_cuda, nbnxn_kernel_ElecRF_VdwLJCombGeom_VF_prune_cuda,
-      nbnxn_kernel_ElecRF_VdwLJCombLB_VF_prune_cuda, nbnxn_kernel_ElecRF_VdwLJFsw_VF_prune_cuda,
-      nbnxn_kernel_ElecRF_VdwLJPsw_VF_prune_cuda, nbnxn_kernel_ElecRF_VdwLJEwCombGeom_VF_prune_cuda,
+    { nbnxn_kernel_ElecRF_VdwLJ_VF_prune_cuda,
+      nbnxn_kernel_ElecRF_VdwLJCombGeom_VF_prune_cuda,
+      nbnxn_kernel_ElecRF_VdwLJCombLB_VF_prune_cuda,
+      nbnxn_kernel_ElecRF_VdwLJFsw_VF_prune_cuda,
+      nbnxn_kernel_ElecRF_VdwLJPsw_VF_prune_cuda,
+      nbnxn_kernel_ElecRF_VdwLJEwCombGeom_VF_prune_cuda,
       nbnxn_kernel_ElecRF_VdwLJEwCombLB_VF_prune_cuda },
-    { nbnxn_kernel_ElecEwQSTab_VdwLJ_VF_prune_cuda, nbnxn_kernel_ElecEwQSTab_VdwLJCombGeom_VF_prune_cuda,
-      nbnxn_kernel_ElecEwQSTab_VdwLJCombLB_VF_prune_cuda, nbnxn_kernel_ElecEwQSTab_VdwLJFsw_VF_prune_cuda,
-      nbnxn_kernel_ElecEwQSTab_VdwLJPsw_VF_prune_cuda, nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_VF_prune_cuda,
+    { nbnxn_kernel_ElecEwQSTab_VdwLJ_VF_prune_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJCombGeom_VF_prune_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJCombLB_VF_prune_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJFsw_VF_prune_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJPsw_VF_prune_cuda,
+      nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_VF_prune_cuda,
       nbnxn_kernel_ElecEwQSTab_VdwLJEwCombLB_VF_prune_cuda },
     { nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJ_VF_prune_cuda,
       nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJCombGeom_VF_prune_cuda,
@@ -270,29 +332,35 @@ static const nbnxn_cu_kfunc_ptr_t nb_kfunc_ener_prune_ptr[eelTypeNR][evdwTypeNR]
       nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_VF_prune_cuda,
       nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombGeom_VF_prune_cuda,
       nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombLB_VF_prune_cuda },
-    { nbnxn_kernel_ElecEw_VdwLJ_VF_prune_cuda, nbnxn_kernel_ElecEw_VdwLJCombGeom_VF_prune_cuda,
-      nbnxn_kernel_ElecEw_VdwLJCombLB_VF_prune_cuda, nbnxn_kernel_ElecEw_VdwLJFsw_VF_prune_cuda,
-      nbnxn_kernel_ElecEw_VdwLJPsw_VF_prune_cuda, nbnxn_kernel_ElecEw_VdwLJEwCombGeom_VF_prune_cuda,
+    { nbnxn_kernel_ElecEw_VdwLJ_VF_prune_cuda,
+      nbnxn_kernel_ElecEw_VdwLJCombGeom_VF_prune_cuda,
+      nbnxn_kernel_ElecEw_VdwLJCombLB_VF_prune_cuda,
+      nbnxn_kernel_ElecEw_VdwLJFsw_VF_prune_cuda,
+      nbnxn_kernel_ElecEw_VdwLJPsw_VF_prune_cuda,
+      nbnxn_kernel_ElecEw_VdwLJEwCombGeom_VF_prune_cuda,
       nbnxn_kernel_ElecEw_VdwLJEwCombLB_VF_prune_cuda },
-    { nbnxn_kernel_ElecEwTwinCut_VdwLJ_VF_prune_cuda, nbnxn_kernel_ElecEwTwinCut_VdwLJCombGeom_VF_prune_cuda,
+    { nbnxn_kernel_ElecEwTwinCut_VdwLJ_VF_prune_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJCombGeom_VF_prune_cuda,
       nbnxn_kernel_ElecEwTwinCut_VdwLJCombLB_VF_prune_cuda,
-      nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_VF_prune_cuda, nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_VF_prune_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_VF_prune_cuda,
+      nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_VF_prune_cuda,
       nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombGeom_VF_prune_cuda,
       nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombLB_VF_prune_cuda }
 };
 
 /*! Return a pointer to the kernel version to be executed at the current step. */
-static inline nbnxn_cu_kfunc_ptr_t select_nbnxn_kernel(int                     eeltype,
-                                                       int                     evdwtype,
+static inline nbnxn_cu_kfunc_ptr_t select_nbnxn_kernel(enum ElecType           elecType,
+                                                       enum VdwType            vdwType,
                                                        bool                    bDoEne,
                                                        bool                    bDoPrune,
                                                        const DeviceInformation gmx_unused* deviceInfo)
 {
-    nbnxn_cu_kfunc_ptr_t res;
+    const int elecTypeIdx = static_cast<int>(elecType);
+    const int vdwTypeIdx  = static_cast<int>(vdwType);
 
-    GMX_ASSERT(eeltype < eelTypeNR,
+    GMX_ASSERT(elecTypeIdx < c_numElecTypes,
                "The electrostatics type requested is not implemented in the CUDA kernels.");
-    GMX_ASSERT(evdwtype < evdwTypeNR,
+    GMX_ASSERT(vdwTypeIdx < c_numVdwTypes,
                "The VdW type requested is not implemented in the CUDA kernels.");
 
     /* assert assumptions made by the kernels */
@@ -306,26 +374,24 @@ static inline nbnxn_cu_kfunc_ptr_t select_nbnxn_kernel(int                     e
     {
         if (bDoPrune)
         {
-            res = nb_kfunc_ener_prune_ptr[eeltype][evdwtype];
+            return nb_kfunc_ener_prune_ptr[elecTypeIdx][vdwTypeIdx];
         }
         else
         {
-            res = nb_kfunc_ener_noprune_ptr[eeltype][evdwtype];
+            return nb_kfunc_ener_noprune_ptr[elecTypeIdx][vdwTypeIdx];
         }
     }
     else
     {
         if (bDoPrune)
         {
-            res = nb_kfunc_noener_prune_ptr[eeltype][evdwtype];
+            return nb_kfunc_noener_prune_ptr[elecTypeIdx][vdwTypeIdx];
         }
         else
         {
-            res = nb_kfunc_noener_noprune_ptr[eeltype][evdwtype];
+            return nb_kfunc_noener_noprune_ptr[elecTypeIdx][vdwTypeIdx];
         }
     }
-
-    return res;
 }
 
 /*! \brief Calculates the amount of shared memory required by the nonbonded kernel in use. */
@@ -344,7 +410,7 @@ static inline int calc_shmem_required_nonbonded(const int               num_thre
     /* cj in shared memory, for each warp separately */
     shmem += num_threads_z * c_nbnxnGpuClusterpairSplit * c_nbnxnGpuJgroupSize * sizeof(int);
 
-    if (nbp->vdwtype == evdwTypeCUTCOMBGEOM || nbp->vdwtype == evdwTypeCUTCOMBLB)
+    if (nbp->vdwType == VdwType::CutCombGeom || nbp->vdwType == VdwType::CutCombLB)
     {
         /* i-atom LJ combination parameters in shared memory */
         shmem += c_nbnxnGpuNumClusterPerSupercluster * c_clSize * sizeof(float2);
@@ -358,112 +424,6 @@ static inline int calc_shmem_required_nonbonded(const int               num_thre
     return shmem;
 }
 
-/*! \brief Sync the nonlocal stream with dependent tasks in the local queue.
- *
- *  As the point where the local stream tasks can be considered complete happens
- *  at the same call point where the nonlocal stream should be synced with the
- *  the local, this function records the event if called with the local stream as
- *  argument and inserts in the GPU stream a wait on the event on the nonlocal.
- */
-void nbnxnInsertNonlocalGpuDependency(const NbnxmGpu* nb, const InteractionLocality interactionLocality)
-{
-    const DeviceStream& deviceStream = *nb->deviceStreams[interactionLocality];
-
-    /* When we get here all misc operations issued in the local stream as well as
-       the local xq H2D are done,
-       so we record that in the local stream and wait for it in the nonlocal one.
-       This wait needs to precede any PP tasks, bonded or nonbonded, that may
-       compute on interactions between local and nonlocal atoms.
-     */
-    if (nb->bUseTwoStreams)
-    {
-        if (interactionLocality == InteractionLocality::Local)
-        {
-            cudaError_t stat = cudaEventRecord(nb->misc_ops_and_local_H2D_done, deviceStream.stream());
-            CU_RET_ERR(stat, "cudaEventRecord on misc_ops_and_local_H2D_done failed");
-        }
-        else
-        {
-            cudaError_t stat =
-                    cudaStreamWaitEvent(deviceStream.stream(), nb->misc_ops_and_local_H2D_done, 0);
-            CU_RET_ERR(stat, "cudaStreamWaitEvent on misc_ops_and_local_H2D_done failed");
-        }
-    }
-}
-
-/*! \brief Launch asynchronously the xq buffer host to device copy. */
-void gpu_copy_xq_to_gpu(NbnxmGpu* nb, const nbnxn_atomdata_t* nbatom, const AtomLocality atomLocality)
-{
-    GMX_ASSERT(nb, "Need a valid nbnxn_gpu object");
-
-    GMX_ASSERT(atomLocality == AtomLocality::Local || atomLocality == AtomLocality::NonLocal,
-               "Only local and non-local xq transfers are supported");
-
-    const InteractionLocality iloc = gpuAtomToInteractionLocality(atomLocality);
-
-    int adat_begin, adat_len; /* local/nonlocal offset and length used for xq and f */
-
-    cu_atomdata_t*      adat         = nb->atdat;
-    gpu_plist*          plist        = nb->plist[iloc];
-    cu_timers_t*        t            = nb->timers;
-    const DeviceStream& deviceStream = *nb->deviceStreams[iloc];
-
-    bool bDoTime = nb->bDoTime;
-
-    /* Don't launch the non-local H2D copy if there is no dependent
-       work to do: neither non-local nor other (e.g. bonded) work
-       to do that has as input the nbnxn coordaintes.
-       Doing the same for the local kernel is more complicated, since the
-       local part of the force array also depends on the non-local kernel.
-       So to avoid complicating the code and to reduce the risk of bugs,
-       we always call the local local x+q copy (and the rest of the local
-       work in nbnxn_gpu_launch_kernel().
-     */
-    if ((iloc == InteractionLocality::NonLocal) && !haveGpuShortRangeWork(*nb, iloc))
-    {
-        plist->haveFreshList = false;
-
-        return;
-    }
-
-    /* calculate the atom data index range based on locality */
-    if (atomLocality == AtomLocality::Local)
-    {
-        adat_begin = 0;
-        adat_len   = adat->natoms_local;
-    }
-    else
-    {
-        adat_begin = adat->natoms_local;
-        adat_len   = adat->natoms - adat->natoms_local;
-    }
-
-    /* HtoD x, q */
-    /* beginning of timed HtoD section */
-    if (bDoTime)
-    {
-        t->xf[atomLocality].nb_h2d.openTimingRegion(deviceStream);
-    }
-
-    static_assert(sizeof(adat->xq[0]) == sizeof(float4),
-                  "The size of the xyzq buffer element should be equal to the size of float4.");
-    copyToDeviceBuffer(&adat->xq, reinterpret_cast<const float4*>(nbatom->x().data()) + adat_begin,
-                       adat_begin, adat_len, deviceStream, GpuApiCallBehavior::Async, nullptr);
-
-    if (bDoTime)
-    {
-        t->xf[atomLocality].nb_h2d.closeTimingRegion(deviceStream);
-    }
-
-    /* When we get here all misc operations issued in the local stream as well as
-       the local xq H2D are done,
-       so we record that in the local stream and wait for it in the nonlocal one.
-       This wait needs to precede any PP tasks, bonded or nonbonded, that may
-       compute on interactions between local and nonlocal atoms.
-     */
-    nbnxnInsertNonlocalGpuDependency(nb, iloc);
-}
-
 /*! As we execute nonbonded workload in separate streams, before launching
    the kernel we need to make sure that he following operations have completed:
    - atomdata allocation and related H2D transfers (every nstlist step);
@@ -483,10 +443,10 @@ void gpu_copy_xq_to_gpu(NbnxmGpu* nb, const nbnxn_atomdata_t* nbatom, const Atom
  */
 void gpu_launch_kernel(NbnxmGpu* nb, const gmx::StepWorkload& stepWork, const InteractionLocality iloc)
 {
-    cu_atomdata_t*      adat         = nb->atdat;
+    NBAtomDataGpu*      adat         = nb->atdat;
     NBParamGpu*         nbp          = nb->nbparam;
     gpu_plist*          plist        = nb->plist[iloc];
-    cu_timers_t*        t            = nb->timers;
+    Nbnxm::GpuTimers*   timers       = nb->timers;
     const DeviceStream& deviceStream = *nb->deviceStreams[iloc];
 
     bool bDoTime = nb->bDoTime;
@@ -525,7 +485,7 @@ void gpu_launch_kernel(NbnxmGpu* nb, const gmx::StepWorkload& stepWork, const In
     /* beginning of timed nonbonded calculation section */
     if (bDoTime)
     {
-        t->interaction[iloc].nb_k.openTimingRegion(deviceStream);
+        timers->interaction[iloc].nb_k.openTimingRegion(deviceStream);
     }
 
     /* Kernel launch config:
@@ -555,14 +515,22 @@ void gpu_launch_kernel(NbnxmGpu* nb, const gmx::StepWorkload& stepWork, const In
                 "Non-bonded GPU launch configuration:\n\tThread block: %zux%zux%zu\n\t"
                 "\tGrid: %zux%zu\n\t#Super-clusters/clusters: %d/%d (%d)\n"
                 "\tShMem: %zu\n",
-                config.blockSize[0], config.blockSize[1], config.blockSize[2], config.gridSize[0],
-                config.gridSize[1], plist->nsci * c_nbnxnGpuNumClusterPerSupercluster,
-                c_nbnxnGpuNumClusterPerSupercluster, plist->na_c, config.sharedMemorySize);
-    }
-
-    auto*      timingEvent = bDoTime ? t->interaction[iloc].nb_k.fetchNextEvent() : nullptr;
+                config.blockSize[0],
+                config.blockSize[1],
+                config.blockSize[2],
+                config.gridSize[0],
+                config.gridSize[1],
+                plist->nsci * c_nbnxnGpuNumClusterPerSupercluster,
+                c_nbnxnGpuNumClusterPerSupercluster,
+                plist->na_c,
+                config.sharedMemorySize);
+    }
+
+    auto*      timingEvent = bDoTime ? timers->interaction[iloc].nb_k.fetchNextEvent() : nullptr;
     const auto kernel =
-            select_nbnxn_kernel(nbp->eeltype, nbp->vdwtype, stepWork.computeEnergy,
+            select_nbnxn_kernel(nbp->elecType,
+                                nbp->vdwType,
+                                stepWork.computeEnergy,
                                 (plist->haveFreshList && !nb->timers->interaction[iloc].didPrune),
                                 &nb->deviceContext_->deviceInfo());
     const auto kernelArgs =
@@ -571,7 +539,7 @@ void gpu_launch_kernel(NbnxmGpu* nb, const gmx::StepWorkload& stepWork, const In
 
     if (bDoTime)
     {
-        t->interaction[iloc].nb_k.closeTimingRegion(deviceStream);
+        timers->interaction[iloc].nb_k.closeTimingRegion(deviceStream);
     }
 
     if (GMX_NATIVE_WINDOWS)
@@ -596,10 +564,10 @@ static inline int calc_shmem_required_prune(const int num_threads_z)
 
 void gpu_launch_kernel_pruneonly(NbnxmGpu* nb, const InteractionLocality iloc, const int numParts)
 {
-    cu_atomdata_t*      adat         = nb->atdat;
+    NBAtomDataGpu*      adat         = nb->atdat;
     NBParamGpu*         nbp          = nb->nbparam;
     gpu_plist*          plist        = nb->plist[iloc];
-    cu_timers_t*        t            = nb->timers;
+    Nbnxm::GpuTimers*   timers       = nb->timers;
     const DeviceStream& deviceStream = *nb->deviceStreams[iloc];
 
     bool bDoTime = nb->bDoTime;
@@ -650,7 +618,8 @@ void gpu_launch_kernel_pruneonly(NbnxmGpu* nb, const InteractionLocality iloc, c
     GpuRegionTimer* timer = nullptr;
     if (bDoTime)
     {
-        timer = &(plist->haveFreshList ? t->interaction[iloc].prune_k : t->interaction[iloc].rollingPrune_k);
+        timer = &(plist->haveFreshList ? timers->interaction[iloc].prune_k
+                                       : timers->interaction[iloc].rollingPrune_k);
     }
 
     /* beginning of timed prune calculation section */
@@ -664,7 +633,7 @@ void gpu_launch_kernel_pruneonly(NbnxmGpu* nb, const InteractionLocality iloc, c
      *   and j-cluster concurrency, in x, y, and z, respectively.
      * - The 1D block-grid contains as many blocks as super-clusters.
      */
-    int num_threads_z = c_cudaPruneKernelJ4Concurrency;
+    int num_threads_z = c_pruneKernelJ4Concurrency;
     int nblock        = calc_nb_kernel_nblock(numSciInPart, &nb->deviceContext_->deviceInfo());
     KernelLaunchConfig config;
     config.blockSize[0]     = c_clSize;
@@ -679,9 +648,15 @@ void gpu_launch_kernel_pruneonly(NbnxmGpu* nb, const InteractionLocality iloc, c
                 "Pruning GPU kernel launch configuration:\n\tThread block: %zux%zux%zu\n\t"
                 "\tGrid: %zux%zu\n\t#Super-clusters/clusters: %d/%d (%d)\n"
                 "\tShMem: %zu\n",
-                config.blockSize[0], config.blockSize[1], config.blockSize[2], config.gridSize[0],
-                config.gridSize[1], numSciInPart * c_nbnxnGpuNumClusterPerSupercluster,
-                c_nbnxnGpuNumClusterPerSupercluster, plist->na_c, config.sharedMemorySize);
+                config.blockSize[0],
+                config.blockSize[1],
+                config.blockSize[2],
+                config.gridSize[0],
+                config.gridSize[1],
+                numSciInPart * c_nbnxnGpuNumClusterPerSupercluster,
+                c_nbnxnGpuNumClusterPerSupercluster,
+                plist->na_c,
+                config.sharedMemorySize);
     }
 
     auto*          timingEvent  = bDoTime ? timer->fetchNextEvent() : nullptr;
@@ -717,109 +692,13 @@ void gpu_launch_kernel_pruneonly(NbnxmGpu* nb, const InteractionLocality iloc, c
     }
 }
 
-void gpu_launch_cpyback(NbnxmGpu*                nb,
-                        nbnxn_atomdata_t*        nbatom,
-                        const gmx::StepWorkload& stepWork,
-                        const AtomLocality       atomLocality)
-{
-    GMX_ASSERT(nb, "Need a valid nbnxn_gpu object");
-
-    cudaError_t stat;
-    int         adat_begin, adat_len; /* local/nonlocal offset and length used for xq and f */
-
-    /* determine interaction locality from atom locality */
-    const InteractionLocality iloc = gpuAtomToInteractionLocality(atomLocality);
-
-    /* extract the data */
-    cu_atomdata_t*      adat         = nb->atdat;
-    cu_timers_t*        t            = nb->timers;
-    bool                bDoTime      = nb->bDoTime;
-    const DeviceStream& deviceStream = *nb->deviceStreams[iloc];
-
-    /* don't launch non-local copy-back if there was no non-local work to do */
-    if ((iloc == InteractionLocality::NonLocal) && !haveGpuShortRangeWork(*nb, iloc))
-    {
-        return;
-    }
-
-    getGpuAtomRange(adat, atomLocality, &adat_begin, &adat_len);
-
-    /* beginning of timed D2H section */
-    if (bDoTime)
-    {
-        t->xf[atomLocality].nb_d2h.openTimingRegion(deviceStream);
-    }
-
-    /* With DD the local D2H transfer can only start after the non-local
-       kernel has finished. */
-    if (iloc == InteractionLocality::Local && nb->bUseTwoStreams)
-    {
-        stat = cudaStreamWaitEvent(deviceStream.stream(), nb->nonlocal_done, 0);
-        CU_RET_ERR(stat, "cudaStreamWaitEvent on nonlocal_done failed");
-    }
-
-    /* DtoH f
-     * Skip if buffer ops / reduction is offloaded to the GPU.
-     */
-    if (!stepWork.useGpuFBufferOps)
-    {
-        static_assert(
-                sizeof(adat->f[0]) == sizeof(float3),
-                "The size of the force buffer element should be equal to the size of float3.");
-        copyFromDeviceBuffer(reinterpret_cast<float3*>(nbatom->out[0].f.data()) + adat_begin, &adat->f,
-                             adat_begin, adat_len, deviceStream, GpuApiCallBehavior::Async, nullptr);
-    }
-
-    /* After the non-local D2H is launched the nonlocal_done event can be
-       recorded which signals that the local D2H can proceed. This event is not
-       placed after the non-local kernel because we want the non-local data
-       back first. */
-    if (iloc == InteractionLocality::NonLocal)
-    {
-        stat = cudaEventRecord(nb->nonlocal_done, deviceStream.stream());
-        CU_RET_ERR(stat, "cudaEventRecord on nonlocal_done failed");
-    }
-
-    /* only transfer energies in the local stream */
-    if (iloc == InteractionLocality::Local)
-    {
-        /* DtoH fshift when virial is needed */
-        if (stepWork.computeVirial)
-        {
-            static_assert(sizeof(nb->nbst.fshift[0]) == sizeof(adat->fshift[0]),
-                          "Sizes of host- and device-side shift vectors should be the same.");
-            copyFromDeviceBuffer(nb->nbst.fshift, &adat->fshift, 0, SHIFTS, deviceStream,
-                                 GpuApiCallBehavior::Async, nullptr);
-        }
-
-        /* DtoH energies */
-        if (stepWork.computeEnergy)
-        {
-            static_assert(sizeof(nb->nbst.e_lj[0]) == sizeof(adat->e_lj[0]),
-                          "Sizes of host- and device-side LJ energy terms should be the same.");
-            copyFromDeviceBuffer(nb->nbst.e_lj, &adat->e_lj, 0, 1, deviceStream,
-                                 GpuApiCallBehavior::Async, nullptr);
-            static_assert(sizeof(nb->nbst.e_el[0]) == sizeof(adat->e_el[0]),
-                          "Sizes of host- and device-side electrostatic energy terms should be the "
-                          "same.");
-            copyFromDeviceBuffer(nb->nbst.e_el, &adat->e_el, 0, 1, deviceStream,
-                                 GpuApiCallBehavior::Async, nullptr);
-        }
-    }
-
-    if (bDoTime)
-    {
-        t->xf[atomLocality].nb_d2h.closeTimingRegion(deviceStream);
-    }
-}
-
 void cuda_set_cacheconfig()
 {
     cudaError_t stat;
 
-    for (int i = 0; i < eelTypeNR; i++)
+    for (int i = 0; i < c_numElecTypes; i++)
     {
-        for (int j = 0; j < evdwTypeNR; j++)
+        for (int j = 0; j < c_numVdwTypes; j++)
         {
             /* Default kernel 32/32 kB Shared/L1 */
             cudaFuncSetCacheConfig(nb_kfunc_ener_prune_ptr[i][j], cudaFuncCachePreferEqual);
@@ -833,25 +712,31 @@ void cuda_set_cacheconfig()
 
 /* X buffer operations on GPU: performs conversion from rvec to nb format. */
 void nbnxn_gpu_x_to_nbat_x(const Nbnxm::Grid&        grid,
-                           bool                      setFillerCoords,
                            NbnxmGpu*                 nb,
                            DeviceBuffer<gmx::RVec>   d_x,
                            GpuEventSynchronizer*     xReadyOnDevice,
                            const Nbnxm::AtomLocality locality,
                            int                       gridId,
-                           int                       numColumnsMax)
+                           int                       numColumnsMax,
+                           bool                      mustInsertNonLocalDependency)
 {
     GMX_ASSERT(nb, "Need a valid nbnxn_gpu object");
 
-    cu_atomdata_t* adat = nb->atdat;
+    NBAtomDataGpu* adat = nb->atdat;
 
     const int                  numColumns      = grid.numColumns();
     const int                  cellOffset      = grid.cellOffset();
     const int                  numAtomsPerCell = grid.numAtomsPerCell();
-    Nbnxm::InteractionLocality interactionLoc  = gpuAtomToInteractionLocality(locality);
+    Nbnxm::InteractionLocality interactionLoc  = atomToInteractionLocality(locality);
 
     const DeviceStream& deviceStream = *nb->deviceStreams[interactionLoc];
 
+    if (xReadyOnDevice != nullptr)
+    {
+        // We only need to wait on the first iteration of the loop
+        xReadyOnDevice->enqueueWaitEvent(deviceStream);
+    }
+
     int numAtoms = grid.srcAtomEnd() - grid.srcAtomBegin();
     // avoid empty kernel launch, skip to inserting stream dependency
     if (numAtoms != 0)
@@ -859,9 +744,6 @@ void nbnxn_gpu_x_to_nbat_x(const Nbnxm::Grid&        grid,
         // TODO: This will only work with CUDA
         GMX_ASSERT(d_x, "Need a valid device pointer");
 
-        // ensure that coordinates are ready on the device before launching the kernel
-        GMX_ASSERT(xReadyOnDevice, "Need a valid GpuEventSynchronizer object");
-        xReadyOnDevice->enqueueWaitEvent(deviceStream);
 
         KernelLaunchConfig config;
         config.blockSize[0] = c_bufOpsThreadsPerBlock;
@@ -875,26 +757,32 @@ void nbnxn_gpu_x_to_nbat_x(const Nbnxm::Grid&        grid,
                    "Can not have empty grid, early return above avoids this");
         config.sharedMemorySize = 0;
 
-        auto kernelFn = setFillerCoords ? nbnxn_gpu_x_to_nbat_x_kernel<true>
-                                        : nbnxn_gpu_x_to_nbat_x_kernel<false>;
+        auto       kernelFn      = nbnxn_gpu_x_to_nbat_x_kernel;
         float4*    d_xq          = adat->xq;
         float3*    d_xFloat3     = asFloat3(d_x);
         const int* d_atomIndices = nb->atomIndices;
         const int* d_cxy_na      = &nb->cxy_na[numColumnsMax * gridId];
         const int* d_cxy_ind     = &nb->cxy_ind[numColumnsMax * gridId];
-        const auto kernelArgs    = prepareGpuKernelArguments(kernelFn, config, &numColumns, &d_xq,
-                                                          &d_xFloat3, &d_atomIndices, &d_cxy_na,
-                                                          &d_cxy_ind, &cellOffset, &numAtomsPerCell);
+        const auto kernelArgs    = prepareGpuKernelArguments(kernelFn,
+                                                          config,
+                                                          &numColumns,
+                                                          &d_xq,
+                                                          &d_xFloat3,
+                                                          &d_atomIndices,
+                                                          &d_cxy_na,
+                                                          &d_cxy_ind,
+                                                          &cellOffset,
+                                                          &numAtomsPerCell);
         launchGpuKernel(kernelFn, config, deviceStream, nullptr, "XbufferOps", kernelArgs);
     }
 
-    // TODO: note that this is not necessary when there astreamre no local atoms, that is:
-    // (numAtoms == 0 && interactionLoc == InteractionLocality::Local)
-    // but for now we avoid that optimization
-    nbnxnInsertNonlocalGpuDependency(nb, interactionLoc);
+    if (mustInsertNonLocalDependency)
+    {
+        Nbnxm::nbnxnInsertNonlocalGpuDependency(nb, interactionLoc);
+    }
 }
 
-void* getGpuForces(NbnxmGpu* nb)
+DeviceBuffer<Float3> getGpuForces(NbnxmGpu* nb)
 {
     return nb->atdat->f;
 }
index bedabd85c8bb7eef62d8596c6ccd25c6a526fca7..3477f2e19251e1ab49f0efae43f18c9b9df6057d 100644 (file)
 // TODO Remove this comment when the above order issue is resolved
 #include "gromacs/gpu_utils/cudautils.cuh"
 #include "gromacs/gpu_utils/device_context.h"
-#include "gromacs/gpu_utils/device_stream_manager.h"
 #include "gromacs/gpu_utils/gpu_utils.h"
 #include "gromacs/gpu_utils/gpueventsynchronizer.cuh"
-#include "gromacs/gpu_utils/pmalloc_cuda.h"
+#include "gromacs/gpu_utils/pmalloc.h"
 #include "gromacs/hardware/device_information.h"
 #include "gromacs/hardware/device_management.h"
 #include "gromacs/math/vectypes.h"
@@ -92,454 +91,16 @@ namespace Nbnxm
  */
 static unsigned int gpu_min_ci_balanced_factor = 44;
 
-/* Fw. decl. */
-static void nbnxn_cuda_clear_e_fshift(NbnxmGpu* nb);
-
-/*! Initializes the atomdata structure first time, it only gets filled at
-    pair-search. */
-static void init_atomdata_first(cu_atomdata_t* ad, int ntypes, const DeviceContext& deviceContext)
-{
-    ad->ntypes = ntypes;
-    allocateDeviceBuffer(&ad->shift_vec, SHIFTS, deviceContext);
-    ad->bShiftVecUploaded = false;
-
-    allocateDeviceBuffer(&ad->fshift, SHIFTS, deviceContext);
-    allocateDeviceBuffer(&ad->e_lj, 1, deviceContext);
-    allocateDeviceBuffer(&ad->e_el, 1, deviceContext);
-
-    /* initialize to nullptr poiters to data that is not allocated here and will
-       need reallocation in nbnxn_cuda_init_atomdata */
-    ad->xq = nullptr;
-    ad->f  = nullptr;
-
-    /* size -1 indicates that the respective array hasn't been initialized yet */
-    ad->natoms = -1;
-    ad->nalloc = -1;
-}
-
-/*! Initializes the nonbonded parameter data structure. */
-static void init_nbparam(NBParamGpu*                     nbp,
-                         const interaction_const_t*      ic,
-                         const PairlistParams&           listParams,
-                         const nbnxn_atomdata_t::Params& nbatParams,
-                         const DeviceContext&            deviceContext)
+void gpu_init_platform_specific(NbnxmGpu* /* nb */)
 {
-    int ntypes;
-
-    ntypes = nbatParams.numTypes;
-
-    set_cutoff_parameters(nbp, ic, listParams);
-
-    /* The kernel code supports LJ combination rules (geometric and LB) for
-     * all kernel types, but we only generate useful combination rule kernels.
-     * We currently only use LJ combination rule (geometric and LB) kernels
-     * for plain cut-off LJ. On Maxwell the force only kernels speed up 15%
-     * with PME and 20% with RF, the other kernels speed up about half as much.
-     * For LJ force-switch the geometric rule would give 7% speed-up, but this
-     * combination is rarely used. LJ force-switch with LB rule is more common,
-     * but gives only 1% speed-up.
-     */
-    if (ic->vdwtype == evdwCUT)
-    {
-        switch (ic->vdw_modifier)
-        {
-            case eintmodNONE:
-            case eintmodPOTSHIFT:
-                switch (nbatParams.comb_rule)
-                {
-                    case ljcrNONE: nbp->vdwtype = evdwTypeCUT; break;
-                    case ljcrGEOM: nbp->vdwtype = evdwTypeCUTCOMBGEOM; break;
-                    case ljcrLB: nbp->vdwtype = evdwTypeCUTCOMBLB; break;
-                    default:
-                        gmx_incons(
-                                "The requested LJ combination rule is not implemented in the CUDA "
-                                "GPU accelerated kernels!");
-                }
-                break;
-            case eintmodFORCESWITCH: nbp->vdwtype = evdwTypeFSWITCH; break;
-            case eintmodPOTSWITCH: nbp->vdwtype = evdwTypePSWITCH; break;
-            default:
-                gmx_incons(
-                        "The requested VdW interaction modifier is not implemented in the CUDA GPU "
-                        "accelerated kernels!");
-        }
-    }
-    else if (ic->vdwtype == evdwPME)
-    {
-        if (ic->ljpme_comb_rule == ljcrGEOM)
-        {
-            assert(nbatParams.comb_rule == ljcrGEOM);
-            nbp->vdwtype = evdwTypeEWALDGEOM;
-        }
-        else
-        {
-            assert(nbatParams.comb_rule == ljcrLB);
-            nbp->vdwtype = evdwTypeEWALDLB;
-        }
-    }
-    else
-    {
-        gmx_incons(
-                "The requested VdW type is not implemented in the CUDA GPU accelerated kernels!");
-    }
-
-    if (ic->eeltype == eelCUT)
-    {
-        nbp->eeltype = eelTypeCUT;
-    }
-    else if (EEL_RF(ic->eeltype))
-    {
-        nbp->eeltype = eelTypeRF;
-    }
-    else if ((EEL_PME(ic->eeltype) || ic->eeltype == eelEWALD))
-    {
-        nbp->eeltype = nbnxn_gpu_pick_ewald_kernel_type(*ic, deviceContext.deviceInfo());
-    }
-    else
-    {
-        /* Shouldn't happen, as this is checked when choosing Verlet-scheme */
-        gmx_incons(
-                "The requested electrostatics type is not implemented in the CUDA GPU accelerated "
-                "kernels!");
-    }
-
-    /* generate table for PME */
-    nbp->coulomb_tab = nullptr;
-    if (nbp->eeltype == eelTypeEWALD_TAB || nbp->eeltype == eelTypeEWALD_TAB_TWIN)
-    {
-        GMX_RELEASE_ASSERT(ic->coulombEwaldTables, "Need valid Coulomb Ewald correction tables");
-        init_ewald_coulomb_force_table(*ic->coulombEwaldTables, nbp, deviceContext);
-    }
-
-    /* set up LJ parameter lookup table */
-    if (!useLjCombRule(nbp->vdwtype))
-    {
-        initParamLookupTable(&nbp->nbfp, &nbp->nbfp_texobj, nbatParams.nbfp.data(),
-                             2 * ntypes * ntypes, deviceContext);
-    }
-
-    /* set up LJ-PME parameter lookup table */
-    if (ic->vdwtype == evdwPME)
-    {
-        initParamLookupTable(&nbp->nbfp_comb, &nbp->nbfp_comb_texobj, nbatParams.nbfp_comb.data(),
-                             2 * ntypes, deviceContext);
-    }
-}
-
-/*! Initializes simulation constant data. */
-static void cuda_init_const(NbnxmGpu*                       nb,
-                            const interaction_const_t*      ic,
-                            const PairlistParams&           listParams,
-                            const nbnxn_atomdata_t::Params& nbatParams)
-{
-    init_atomdata_first(nb->atdat, nbatParams.numTypes, *nb->deviceContext_);
-    init_nbparam(nb->nbparam, ic, listParams, nbatParams, *nb->deviceContext_);
-
-    /* clear energy and shift force outputs */
-    nbnxn_cuda_clear_e_fshift(nb);
-}
-
-NbnxmGpu* gpu_init(const gmx::DeviceStreamManager& deviceStreamManager,
-                   const interaction_const_t*      ic,
-                   const PairlistParams&           listParams,
-                   const nbnxn_atomdata_t*         nbat,
-                   bool                            bLocalAndNonlocal)
-{
-    cudaError_t stat;
-
-    auto nb            = new NbnxmGpu();
-    nb->deviceContext_ = &deviceStreamManager.context();
-    snew(nb->atdat, 1);
-    snew(nb->nbparam, 1);
-    snew(nb->plist[InteractionLocality::Local], 1);
-    if (bLocalAndNonlocal)
-    {
-        snew(nb->plist[InteractionLocality::NonLocal], 1);
-    }
-
-    nb->bUseTwoStreams = bLocalAndNonlocal;
-
-    nb->timers = new cu_timers_t();
-    snew(nb->timings, 1);
-
-    /* init nbst */
-    pmalloc((void**)&nb->nbst.e_lj, sizeof(*nb->nbst.e_lj));
-    pmalloc((void**)&nb->nbst.e_el, sizeof(*nb->nbst.e_el));
-    pmalloc((void**)&nb->nbst.fshift, SHIFTS * sizeof(*nb->nbst.fshift));
-
-    init_plist(nb->plist[InteractionLocality::Local]);
-
-    /* local/non-local GPU streams */
-    GMX_RELEASE_ASSERT(deviceStreamManager.streamIsValid(gmx::DeviceStreamType::NonBondedLocal),
-                       "Local non-bonded stream should be initialized to use GPU for non-bonded.");
-    nb->deviceStreams[InteractionLocality::Local] =
-            &deviceStreamManager.stream(gmx::DeviceStreamType::NonBondedLocal);
-    if (nb->bUseTwoStreams)
-    {
-        init_plist(nb->plist[InteractionLocality::NonLocal]);
-
-        /* Note that the device we're running on does not have to support
-         * priorities, because we are querying the priority range which in this
-         * case will be a single value.
-         */
-        GMX_RELEASE_ASSERT(deviceStreamManager.streamIsValid(gmx::DeviceStreamType::NonBondedNonLocal),
-                           "Non-local non-bonded stream should be initialized to use GPU for "
-                           "non-bonded with domain decomposition.");
-        nb->deviceStreams[InteractionLocality::NonLocal] =
-                &deviceStreamManager.stream(gmx::DeviceStreamType::NonBondedNonLocal);
-        ;
-    }
-
-    /* init events for sychronization (timing disabled for performance reasons!) */
-    stat = cudaEventCreateWithFlags(&nb->nonlocal_done, cudaEventDisableTiming);
-    CU_RET_ERR(stat, "cudaEventCreate on nonlocal_done failed");
-    stat = cudaEventCreateWithFlags(&nb->misc_ops_and_local_H2D_done, cudaEventDisableTiming);
-    CU_RET_ERR(stat, "cudaEventCreate on misc_ops_and_local_H2D_done failed");
-
-    nb->xNonLocalCopyD2HDone = new GpuEventSynchronizer();
-
-    /* WARNING: CUDA timings are incorrect with multiple streams.
-     *          This is the main reason why they are disabled by default.
-     */
-    // TODO: Consider turning on by default when we can detect nr of streams.
-    nb->bDoTime = (getenv("GMX_ENABLE_GPU_TIMING") != nullptr);
-
-    if (nb->bDoTime)
-    {
-        init_timings(nb->timings);
-    }
-
     /* set the kernel type for the current GPU */
     /* pick L1 cache configuration */
     cuda_set_cacheconfig();
-
-    cuda_init_const(nb, ic, listParams, nbat->params());
-
-    nb->atomIndicesSize       = 0;
-    nb->atomIndicesSize_alloc = 0;
-    nb->ncxy_na               = 0;
-    nb->ncxy_na_alloc         = 0;
-    nb->ncxy_ind              = 0;
-    nb->ncxy_ind_alloc        = 0;
-
-    if (debug)
-    {
-        fprintf(debug, "Initialized CUDA data structures.\n");
-    }
-
-    return nb;
-}
-
-void gpu_upload_shiftvec(NbnxmGpu* nb, const nbnxn_atomdata_t* nbatom)
-{
-    cu_atomdata_t*      adat        = nb->atdat;
-    const DeviceStream& localStream = *nb->deviceStreams[InteractionLocality::Local];
-
-    /* only if we have a dynamic box */
-    if (nbatom->bDynamicBox || !adat->bShiftVecUploaded)
-    {
-        static_assert(sizeof(adat->shift_vec[0]) == sizeof(nbatom->shift_vec[0]),
-                      "Sizes of host- and device-side shift vectors should be the same.");
-        copyToDeviceBuffer(&adat->shift_vec, reinterpret_cast<const float3*>(nbatom->shift_vec.data()),
-                           0, SHIFTS, localStream, GpuApiCallBehavior::Async, nullptr);
-        adat->bShiftVecUploaded = true;
-    }
-}
-
-/*! Clears the first natoms_clear elements of the GPU nonbonded force output array. */
-static void nbnxn_cuda_clear_f(NbnxmGpu* nb, int natoms_clear)
-{
-    cu_atomdata_t*      adat        = nb->atdat;
-    const DeviceStream& localStream = *nb->deviceStreams[InteractionLocality::Local];
-    clearDeviceBufferAsync(&adat->f, 0, natoms_clear, localStream);
-}
-
-/*! Clears nonbonded shift force output array and energy outputs on the GPU. */
-static void nbnxn_cuda_clear_e_fshift(NbnxmGpu* nb)
-{
-    cu_atomdata_t*      adat        = nb->atdat;
-    const DeviceStream& localStream = *nb->deviceStreams[InteractionLocality::Local];
-
-    clearDeviceBufferAsync(&adat->fshift, 0, SHIFTS, localStream);
-    clearDeviceBufferAsync(&adat->e_lj, 0, 1, localStream);
-    clearDeviceBufferAsync(&adat->e_el, 0, 1, localStream);
-}
-
-void gpu_clear_outputs(NbnxmGpu* nb, bool computeVirial)
-{
-    nbnxn_cuda_clear_f(nb, nb->atdat->natoms);
-    /* clear shift force array and energies if the outputs were
-       used in the current step */
-    if (computeVirial)
-    {
-        nbnxn_cuda_clear_e_fshift(nb);
-    }
 }
 
-void gpu_init_atomdata(NbnxmGpu* nb, const nbnxn_atomdata_t* nbat)
+void gpu_free_platform_specific(NbnxmGpu* /* nb */)
 {
-    int                  nalloc, natoms;
-    bool                 realloced;
-    bool                 bDoTime       = nb->bDoTime;
-    cu_timers_t*         timers        = nb->timers;
-    cu_atomdata_t*       d_atdat       = nb->atdat;
-    const DeviceContext& deviceContext = *nb->deviceContext_;
-    const DeviceStream&  localStream   = *nb->deviceStreams[InteractionLocality::Local];
-
-    natoms    = nbat->numAtoms();
-    realloced = false;
-
-    if (bDoTime)
-    {
-        /* time async copy */
-        timers->atdat.openTimingRegion(localStream);
-    }
-
-    /* need to reallocate if we have to copy more atoms than the amount of space
-       available and only allocate if we haven't initialized yet, i.e d_atdat->natoms == -1 */
-    if (natoms > d_atdat->nalloc)
-    {
-        nalloc = over_alloc_small(natoms);
-
-        /* free up first if the arrays have already been initialized */
-        if (d_atdat->nalloc != -1)
-        {
-            freeDeviceBuffer(&d_atdat->f);
-            freeDeviceBuffer(&d_atdat->xq);
-            freeDeviceBuffer(&d_atdat->atom_types);
-            freeDeviceBuffer(&d_atdat->lj_comb);
-        }
-
-        allocateDeviceBuffer(&d_atdat->f, nalloc, deviceContext);
-        allocateDeviceBuffer(&d_atdat->xq, nalloc, deviceContext);
-        if (useLjCombRule(nb->nbparam->vdwtype))
-        {
-            allocateDeviceBuffer(&d_atdat->lj_comb, nalloc, deviceContext);
-        }
-        else
-        {
-            allocateDeviceBuffer(&d_atdat->atom_types, nalloc, deviceContext);
-        }
-
-        d_atdat->nalloc = nalloc;
-        realloced       = true;
-    }
-
-    d_atdat->natoms       = natoms;
-    d_atdat->natoms_local = nbat->natoms_local;
-
-    /* need to clear GPU f output if realloc happened */
-    if (realloced)
-    {
-        nbnxn_cuda_clear_f(nb, nalloc);
-    }
-
-    if (useLjCombRule(nb->nbparam->vdwtype))
-    {
-        static_assert(sizeof(d_atdat->lj_comb[0]) == sizeof(float2),
-                      "Size of the LJ parameters element should be equal to the size of float2.");
-        copyToDeviceBuffer(&d_atdat->lj_comb,
-                           reinterpret_cast<const float2*>(nbat->params().lj_comb.data()), 0,
-                           natoms, localStream, GpuApiCallBehavior::Async, nullptr);
-    }
-    else
-    {
-        static_assert(sizeof(d_atdat->atom_types[0]) == sizeof(nbat->params().type[0]),
-                      "Sizes of host- and device-side atom types should be the same.");
-        copyToDeviceBuffer(&d_atdat->atom_types, nbat->params().type.data(), 0, natoms, localStream,
-                           GpuApiCallBehavior::Async, nullptr);
-    }
-
-    if (bDoTime)
-    {
-        timers->atdat.closeTimingRegion(localStream);
-    }
-}
-
-void gpu_free(NbnxmGpu* nb)
-{
-    cudaError_t    stat;
-    cu_atomdata_t* atdat;
-    NBParamGpu*    nbparam;
-
-    if (nb == nullptr)
-    {
-        return;
-    }
-
-    atdat   = nb->atdat;
-    nbparam = nb->nbparam;
-
-    if ((!nbparam->coulomb_tab)
-        && (nbparam->eeltype == eelTypeEWALD_TAB || nbparam->eeltype == eelTypeEWALD_TAB_TWIN))
-    {
-        destroyParamLookupTable(&nbparam->coulomb_tab, nbparam->coulomb_tab_texobj);
-    }
-
-    stat = cudaEventDestroy(nb->nonlocal_done);
-    CU_RET_ERR(stat, "cudaEventDestroy failed on timers->nonlocal_done");
-    stat = cudaEventDestroy(nb->misc_ops_and_local_H2D_done);
-    CU_RET_ERR(stat, "cudaEventDestroy failed on timers->misc_ops_and_local_H2D_done");
-
-    delete nb->timers;
-
-    if (!useLjCombRule(nb->nbparam->vdwtype))
-    {
-        destroyParamLookupTable(&nbparam->nbfp, nbparam->nbfp_texobj);
-    }
-
-    if (nbparam->vdwtype == evdwTypeEWALDGEOM || nbparam->vdwtype == evdwTypeEWALDLB)
-    {
-        destroyParamLookupTable(&nbparam->nbfp_comb, nbparam->nbfp_comb_texobj);
-    }
-
-    freeDeviceBuffer(&atdat->shift_vec);
-    freeDeviceBuffer(&atdat->fshift);
-
-    freeDeviceBuffer(&atdat->e_lj);
-    freeDeviceBuffer(&atdat->e_el);
-
-    freeDeviceBuffer(&atdat->f);
-    freeDeviceBuffer(&atdat->xq);
-    freeDeviceBuffer(&atdat->atom_types);
-    freeDeviceBuffer(&atdat->lj_comb);
-
-    /* Free plist */
-    auto* plist = nb->plist[InteractionLocality::Local];
-    freeDeviceBuffer(&plist->sci);
-    freeDeviceBuffer(&plist->cj4);
-    freeDeviceBuffer(&plist->imask);
-    freeDeviceBuffer(&plist->excl);
-    sfree(plist);
-    if (nb->bUseTwoStreams)
-    {
-        auto* plist_nl = nb->plist[InteractionLocality::NonLocal];
-        freeDeviceBuffer(&plist_nl->sci);
-        freeDeviceBuffer(&plist_nl->cj4);
-        freeDeviceBuffer(&plist_nl->imask);
-        freeDeviceBuffer(&plist_nl->excl);
-        sfree(plist_nl);
-    }
-
-    /* Free nbst */
-    pfree(nb->nbst.e_lj);
-    nb->nbst.e_lj = nullptr;
-
-    pfree(nb->nbst.e_el);
-    nb->nbst.e_el = nullptr;
-
-    pfree(nb->nbst.fshift);
-    nb->nbst.fshift = nullptr;
-
-    sfree(atdat);
-    sfree(nbparam);
-    sfree(nb->timings);
-    delete nb;
-
-    if (debug)
-    {
-        fprintf(debug, "Cleaned up CUDA data structures.\n");
-    }
+    // Nothing specific in CUDA
 }
 
 int gpu_min_ci_balanced(NbnxmGpu* nb)
@@ -566,95 +127,7 @@ DeviceBuffer<gmx::RVec> gpu_get_fshift(NbnxmGpu* nb)
 {
     assert(nb);
 
-    return reinterpret_cast<DeviceBuffer<gmx::RVec>>(nb->atdat->fshift);
-}
-
-/* Initialization for X buffer operations on GPU. */
-/* TODO  Remove explicit pinning from host arrays from here and manage in a more natural way*/
-void nbnxn_gpu_init_x_to_nbat_x(const Nbnxm::GridSet& gridSet, NbnxmGpu* gpu_nbv)
-{
-    const DeviceStream& deviceStream  = *gpu_nbv->deviceStreams[InteractionLocality::Local];
-    bool                bDoTime       = gpu_nbv->bDoTime;
-    const int           maxNumColumns = gridSet.numColumnsMax();
-
-    reallocateDeviceBuffer(&gpu_nbv->cxy_na, maxNumColumns * gridSet.grids().size(),
-                           &gpu_nbv->ncxy_na, &gpu_nbv->ncxy_na_alloc, *gpu_nbv->deviceContext_);
-    reallocateDeviceBuffer(&gpu_nbv->cxy_ind, maxNumColumns * gridSet.grids().size(),
-                           &gpu_nbv->ncxy_ind, &gpu_nbv->ncxy_ind_alloc, *gpu_nbv->deviceContext_);
-
-    for (unsigned int g = 0; g < gridSet.grids().size(); g++)
-    {
-
-        const Nbnxm::Grid& grid = gridSet.grids()[g];
-
-        const int  numColumns      = grid.numColumns();
-        const int* atomIndices     = gridSet.atomIndices().data();
-        const int  atomIndicesSize = gridSet.atomIndices().size();
-        const int* cxy_na          = grid.cxy_na().data();
-        const int* cxy_ind         = grid.cxy_ind().data();
-
-        reallocateDeviceBuffer(&gpu_nbv->atomIndices, atomIndicesSize, &gpu_nbv->atomIndicesSize,
-                               &gpu_nbv->atomIndicesSize_alloc, *gpu_nbv->deviceContext_);
-
-        if (atomIndicesSize > 0)
-        {
-
-            if (bDoTime)
-            {
-                gpu_nbv->timers->xf[AtomLocality::Local].nb_h2d.openTimingRegion(deviceStream);
-            }
-
-            copyToDeviceBuffer(&gpu_nbv->atomIndices, atomIndices, 0, atomIndicesSize, deviceStream,
-                               GpuApiCallBehavior::Async, nullptr);
-
-            if (bDoTime)
-            {
-                gpu_nbv->timers->xf[AtomLocality::Local].nb_h2d.closeTimingRegion(deviceStream);
-            }
-        }
-
-        if (numColumns > 0)
-        {
-            if (bDoTime)
-            {
-                gpu_nbv->timers->xf[AtomLocality::Local].nb_h2d.openTimingRegion(deviceStream);
-            }
-
-            int* destPtr = &gpu_nbv->cxy_na[maxNumColumns * g];
-            copyToDeviceBuffer(&destPtr, cxy_na, 0, numColumns, deviceStream,
-                               GpuApiCallBehavior::Async, nullptr);
-
-            if (bDoTime)
-            {
-                gpu_nbv->timers->xf[AtomLocality::Local].nb_h2d.closeTimingRegion(deviceStream);
-            }
-
-            if (bDoTime)
-            {
-                gpu_nbv->timers->xf[AtomLocality::Local].nb_h2d.openTimingRegion(deviceStream);
-            }
-
-            destPtr = &gpu_nbv->cxy_ind[maxNumColumns * g];
-            copyToDeviceBuffer(&destPtr, cxy_ind, 0, numColumns, deviceStream,
-                               GpuApiCallBehavior::Async, nullptr);
-
-            if (bDoTime)
-            {
-                gpu_nbv->timers->xf[AtomLocality::Local].nb_h2d.closeTimingRegion(deviceStream);
-            }
-        }
-    }
-
-    // The above data is transferred on the local stream but is a
-    // dependency of the nonlocal stream (specifically the nonlocal X
-    // buf ops kernel).  We therefore set a dependency to ensure
-    // that the nonlocal stream waits on the local stream here.
-    // This call records an event in the local stream:
-    nbnxnInsertNonlocalGpuDependency(gpu_nbv, Nbnxm::InteractionLocality::Local);
-    // ...and this call instructs the nonlocal stream to wait on that event:
-    nbnxnInsertNonlocalGpuDependency(gpu_nbv, Nbnxm::InteractionLocality::NonLocal);
-
-    return;
+    return reinterpret_cast<DeviceBuffer<gmx::RVec>>(nb->atdat->fShift);
 }
 
 } // namespace Nbnxm
index 6b307e4ca9e2e63856b9ac647994fb7e37e41d04..7df9231d515902ecb1f59b2df9302a15b4d6fe81 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
 
 #include "gromacs/gpu_utils/cuda_arch_utils.cuh"
 #include "gromacs/gpu_utils/cuda_kernel_utils.cuh"
+#include "gromacs/gpu_utils/typecasts.cuh"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/pbcutil/ishift.h"
 /* Note that floating-point constants in CUDA code should be suffixed
@@ -158,7 +160,7 @@ __launch_bounds__(THREADS_PER_BLOCK)
         __global__ void NB_KERNEL_FUNC_NAME(nbnxn_kernel, _F_cuda)
 #    endif /* CALC_ENERGIES */
 #endif     /* PRUNE_NBL */
-                (const cu_atomdata_t atdat, const NBParamGpu nbparam, const Nbnxm::gpu_plist plist, bool bCalcFshift)
+                (const NBAtomDataGpu atdat, const NBParamGpu nbparam, const Nbnxm::gpu_plist plist, bool bCalcFshift)
 #ifdef FUNCTION_DECLARATION_ONLY
                         ; /* Only do function declaration, omit the function body. */
 #else
@@ -171,15 +173,15 @@ __launch_bounds__(THREADS_PER_BLOCK)
             nbnxn_cj4_t* pl_cj4      = plist.cj4;
     const nbnxn_excl_t*  excl        = plist.excl;
 #    ifndef LJ_COMB
-    const int*           atom_types  = atdat.atom_types;
-    int                  ntypes      = atdat.ntypes;
+    const int*           atom_types  = atdat.atomTypes;
+    int                  ntypes      = atdat.numTypes;
 #    else
-    const float2* lj_comb = atdat.lj_comb;
+    const float2* lj_comb = atdat.ljComb;
     float2        ljcp_i, ljcp_j;
 #    endif
     const float4*        xq          = atdat.xq;
-    float3*              f           = atdat.f;
-    const float3*        shift_vec   = atdat.shift_vec;
+    float3*              f           = asFloat3(atdat.f);
+    const float3*        shift_vec   = asFloat3(atdat.shiftVec);
     float                rcoulomb_sq = nbparam.rcoulomb_sq;
 #    ifdef VDW_CUTOFF_CHECK
     float                rvdw_sq     = nbparam.rvdw_sq;
@@ -204,10 +206,10 @@ __launch_bounds__(THREADS_PER_BLOCK)
     float                beta        = nbparam.ewald_beta;
     float                ewald_shift = nbparam.sh_ewald;
 #        else
-    float c_rf = nbparam.c_rf;
+    float reactionFieldShift = nbparam.c_rf;
 #        endif /* EL_EWALD_ANY */
-    float*               e_lj        = atdat.e_lj;
-    float*               e_el        = atdat.e_el;
+    float*               e_lj        = atdat.eLJ;
+    float*               e_el        = atdat.eElec;
 #    endif     /* CALC_ENERGIES */
 
     /* thread/block/warp id-s */
@@ -324,7 +326,8 @@ __launch_bounds__(THREADS_PER_BLOCK)
     E_el         = 0.0f;
 
 #        ifdef EXCLUSION_FORCES /* Ewald or RF */
-    if (nb_sci.shift == CENTRAL && pl_cj4[cij4_start].cj[0] == sci * c_nbnxnGpuNumClusterPerSupercluster)
+    if (nb_sci.shift == gmx::c_centralShiftIndex
+        && pl_cj4[cij4_start].cj[0] == sci * c_nbnxnGpuNumClusterPerSupercluster)
     {
         /* we have the diagonal: add the charge and LJ self interaction energy term */
         for (i = 0; i < c_nbnxnGpuNumClusterPerSupercluster; i++)
@@ -335,15 +338,9 @@ __launch_bounds__(THREADS_PER_BLOCK)
 #            endif
 
 #            ifdef LJ_EWALD
-#                if DISABLE_CUDA_TEXTURES
-            E_lj += LDG(&nbparam.nbfp[atom_types[(sci * c_nbnxnGpuNumClusterPerSupercluster + i) * c_clSize + tidxi]
-                                      * (ntypes + 1) * 2]);
-#                else
-            E_lj += tex1Dfetch<float>(
-                    nbparam.nbfp_texobj,
-                    atom_types[(sci * c_nbnxnGpuNumClusterPerSupercluster + i) * c_clSize + tidxi]
-                            * (ntypes + 1) * 2);
-#                endif
+            // load only the first 4 bytes of the parameter pair (equivalent with nbfp[idx].x)
+            E_lj += LDG((float*)&nbparam.nbfp[atom_types[(sci * c_nbnxnGpuNumClusterPerSupercluster + i) * c_clSize + tidxi]
+                                              * (ntypes + 1)]);
 #            endif
         }
 
@@ -357,7 +354,7 @@ __launch_bounds__(THREADS_PER_BLOCK)
         /* Correct for epsfac^2 due to adding qi^2 */
         E_el /= nbparam.epsfac * c_clSize * NTHREAD_Z;
 #                if defined EL_RF || defined EL_CUTOFF
-        E_el *= -0.5f * c_rf;
+        E_el *= -0.5f * reactionFieldShift;
 #                else
         E_el *= -beta * M_FLOAT_1_SQRTPI; /* last factor 1/sqrt(pi) */
 #                endif
@@ -368,7 +365,7 @@ __launch_bounds__(THREADS_PER_BLOCK)
 #    endif /* CALC_ENERGIES */
 
 #    ifdef EXCLUSION_FORCES
-    const int nonSelfInteraction = !(nb_sci.shift == CENTRAL & tidxj <= tidxi);
+    const int nonSelfInteraction = !(nb_sci.shift == gmx::c_centralShiftIndex & tidxj <= tidxi);
 #    endif
 
     /* loop over the j clusters = seen by any of the atoms in the current super-cluster;
@@ -517,20 +514,28 @@ __launch_bounds__(THREADS_PER_BLOCK)
 #    ifdef LJ_EWALD
 #        ifdef LJ_EWALD_COMB_GEOM
 #            ifdef CALC_ENERGIES
-                                calculate_lj_ewald_comb_geom_F_E(nbparam, typei, typej, r2, inv_r2,
-                                                                 lje_coeff2, lje_coeff6_6, int_bit,
-                                                                 &F_invr, &E_lj_p);
+                                calculate_lj_ewald_comb_geom_F_E(
+                                        nbparam, typei, typej, r2, inv_r2, lje_coeff2, lje_coeff6_6, int_bit, &F_invr, &E_lj_p);
 #            else
-                                calculate_lj_ewald_comb_geom_F(nbparam, typei, typej, r2, inv_r2,
-                                                               lje_coeff2, lje_coeff6_6, &F_invr);
+                                calculate_lj_ewald_comb_geom_F(
+                                        nbparam, typei, typej, r2, inv_r2, lje_coeff2, lje_coeff6_6, &F_invr);
 #            endif /* CALC_ENERGIES */
 #        elif defined LJ_EWALD_COMB_LB
-                                calculate_lj_ewald_comb_LB_F_E(nbparam, typei, typej, r2, inv_r2,
-                                                               lje_coeff2, lje_coeff6_6,
+                                calculate_lj_ewald_comb_LB_F_E(nbparam,
+                                                               typei,
+                                                               typej,
+                                                               r2,
+                                                               inv_r2,
+                                                               lje_coeff2,
+                                                               lje_coeff6_6,
 #            ifdef CALC_ENERGIES
-                                                               int_bit, &F_invr, &E_lj_p
+                                                               int_bit,
+                                                               &F_invr,
+                                                               &E_lj_p
 #            else
-                                                               0, &F_invr, nullptr
+                                                               0,
+                                                               &F_invr,
+                                                               nullptr
 #            endif /* CALC_ENERGIES */
                                 );
 #        endif     /* LJ_EWALD_COMB_GEOM */
@@ -582,10 +587,11 @@ __launch_bounds__(THREADS_PER_BLOCK)
 
 #    ifdef CALC_ENERGIES
 #        ifdef EL_CUTOFF
-                                E_el += qi * qj_f * (int_bit * inv_r - c_rf);
+                                E_el += qi * qj_f * (int_bit * inv_r - reactionFieldShift);
 #        endif
 #        ifdef EL_RF
-                                E_el += qi * qj_f * (int_bit * inv_r + 0.5f * two_k_rf * r2 - c_rf);
+                                E_el += qi * qj_f
+                                        * (int_bit * inv_r + 0.5f * two_k_rf * r2 - reactionFieldShift);
 #        endif
 #        ifdef EL_EWALD_ANY
                                 /* 1.0f - erff is faster than erfcf */
@@ -622,7 +628,7 @@ __launch_bounds__(THREADS_PER_BLOCK)
     }
 
     /* skip central shifts when summing shift forces */
-    if (nb_sci.shift == CENTRAL)
+    if (nb_sci.shift == gmx::c_centralShiftIndex)
     {
         bCalcFshift = false;
     }
@@ -639,7 +645,8 @@ __launch_bounds__(THREADS_PER_BLOCK)
     /* add up local shift forces into global mem, tidxj indexes x,y,z */
     if (bCalcFshift && (tidxj & 3) < 3)
     {
-        atomicAdd(&(atdat.fshift[nb_sci.shift].x) + (tidxj & 3), fshift_buf);
+        float3* fShift = asFloat3(atdat.fShift);
+        atomicAdd(&(fShift[nb_sci.shift].x) + (tidxj & 3), fshift_buf);
     }
 
 #    ifdef CALC_ENERGIES
index fb8ebb2e766fec2574438098b1ef3efe34b52758..34de55d1948f95d8bc8523c0a706c23ee556e9f4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -39,7 +39,7 @@
 #ifndef FUNCTION_DECLARATION_ONLY
 /* Instantiate external template functions */
 template __global__ void
-nbnxn_kernel_prune_cuda<false>(const cu_atomdata_t, const NBParamGpu, const Nbnxm::gpu_plist, int, int);
+nbnxn_kernel_prune_cuda<false>(const NBAtomDataGpu, const NBParamGpu, const Nbnxm::gpu_plist, int, int);
 template __global__ void
-nbnxn_kernel_prune_cuda<true>(const cu_atomdata_t, const NBParamGpu, const Nbnxm::gpu_plist, int, int);
+nbnxn_kernel_prune_cuda<true>(const NBAtomDataGpu, const NBParamGpu, const Nbnxm::gpu_plist, int, int);
 #endif
index 563e1edc0c74b4faa13492f3d2af70b19c5a5d4d..bcc3dd1b09d641a76ef6408d775c8e5686a2364f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "gmxpre.h"
 
 #include "gromacs/gpu_utils/cuda_arch_utils.cuh"
+#include "gromacs/gpu_utils/typecasts.cuh"
 #include "gromacs/math/utilities.h"
 #include "gromacs/pbcutil/ishift.h"
 
  */
 template<bool haveFreshList>
 __launch_bounds__(THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP) __global__
-        void nbnxn_kernel_prune_cuda(const cu_atomdata_t    atdat,
+        void nbnxn_kernel_prune_cuda(const NBAtomDataGpu    atdat,
                                      const NBParamGpu       nbparam,
                                      const Nbnxm::gpu_plist plist,
                                      int                    numParts,
@@ -114,9 +115,9 @@ __launch_bounds__(THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP) __global__
 // Add extern declarations so each translation unit understands that
 // there will be a definition provided.
 extern template __global__ void
-nbnxn_kernel_prune_cuda<true>(const cu_atomdata_t, const NBParamGpu, const Nbnxm::gpu_plist, int, int);
+nbnxn_kernel_prune_cuda<true>(const NBAtomDataGpu, const NBParamGpu, const Nbnxm::gpu_plist, int, int);
 extern template __global__ void
-nbnxn_kernel_prune_cuda<false>(const cu_atomdata_t, const NBParamGpu, const Nbnxm::gpu_plist, int, int);
+nbnxn_kernel_prune_cuda<false>(const NBAtomDataGpu, const NBParamGpu, const Nbnxm::gpu_plist, int, int);
 #else
 {
 
@@ -124,7 +125,7 @@ nbnxn_kernel_prune_cuda<false>(const cu_atomdata_t, const NBParamGpu, const Nbnx
     const nbnxn_sci_t* pl_sci    = plist.sci;
     nbnxn_cj4_t*       pl_cj4    = plist.cj4;
     const float4*      xq        = atdat.xq;
-    const float3*      shift_vec = atdat.shift_vec;
+    const float3*      shift_vec = asFloat3(atdat.shiftVec);
 
     float rlistOuter_sq = nbparam.rlistOuter_sq;
     float rlistInner_sq = nbparam.rlistInner_sq;
index 4850298f8f154082b8b19c2a395aab938fe8d59c..b916997a22c6097663814395762edb474e384e65 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -204,11 +204,13 @@ static __forceinline__ __device__ void
 static __forceinline__ __device__ float calculate_lj_ewald_c6grid(const NBParamGpu nbparam, int typei, int typej)
 {
 #    if DISABLE_CUDA_TEXTURES
-    return LDG(&nbparam.nbfp_comb[2 * typei]) * LDG(&nbparam.nbfp_comb[2 * typej]);
+    float c6_i = LDG(&nbparam.nbfp_comb[typei]).x;
+    float c6_j = LDG(&nbparam.nbfp_comb[typej]).x;
 #    else
-    return tex1Dfetch<float>(nbparam.nbfp_comb_texobj, 2 * typei)
-           * tex1Dfetch<float>(nbparam.nbfp_comb_texobj, 2 * typej);
+    float c6_i = tex1Dfetch<float2>(nbparam.nbfp_comb_texobj, typei).x;
+    float c6_j = tex1Dfetch<float2>(nbparam.nbfp_comb_texobj, typej).x;
 #    endif /* DISABLE_CUDA_TEXTURES */
+    return c6_i * c6_j;
 }
 
 
@@ -278,19 +280,11 @@ static __forceinline__ __device__ void calculate_lj_ewald_comb_geom_F_E(const NB
  */
 static __forceinline__ __device__ float2 fetch_nbfp_comb_c6_c12(const NBParamGpu nbparam, int type)
 {
-    float2 c6c12;
 #    if DISABLE_CUDA_TEXTURES
-    /* Force an 8-byte fetch to save a memory instruction. */
-    float2* nbfp_comb = (float2*)nbparam.nbfp_comb;
-    c6c12             = LDG(&nbfp_comb[type]);
+    return LDG(&nbparam.nbfp_comb[type]);
 #    else
-    /* NOTE: as we always do 8-byte aligned loads, we could
-       fetch float2 here too just as above. */
-    c6c12.x = tex1Dfetch<float>(nbparam.nbfp_comb_texobj, 2 * type);
-    c6c12.y = tex1Dfetch<float>(nbparam.nbfp_comb_texobj, 2 * type + 1);
+    return tex1Dfetch<float2>(nbparam.nbfp_comb_texobj, type);
 #    endif /* DISABLE_CUDA_TEXTURES */
-
-    return c6c12;
 }
 
 
@@ -357,8 +351,8 @@ static __forceinline__ __device__ float2 fetch_coulomb_force_r(const NBParamGpu
     d.x = LDG(&nbparam.coulomb_tab[index]);
     d.y = LDG(&nbparam.coulomb_tab[index + 1]);
 #    else
-    d.x     = tex1Dfetch<float>(nbparam.coulomb_tab_texobj, index);
-    d.y     = tex1Dfetch<float>(nbparam.coulomb_tab_texobj, index + 1);
+    d.x   = tex1Dfetch<float>(nbparam.coulomb_tab_texobj, index);
+    d.y   = tex1Dfetch<float>(nbparam.coulomb_tab_texobj, index + 1);
 #    endif // DISABLE_CUDA_TEXTURES
 
     return d;
@@ -397,19 +391,14 @@ static __forceinline__ __device__ float interpolate_coulomb_force_r(const NBPara
  */
 static __forceinline__ __device__ void fetch_nbfp_c6_c12(float& c6, float& c12, const NBParamGpu nbparam, int baseIndex)
 {
+    float2 c6c12;
 #    if DISABLE_CUDA_TEXTURES
-    /* Force an 8-byte fetch to save a memory instruction. */
-    float2* nbfp = (float2*)nbparam.nbfp;
-    float2  c6c12;
-    c6c12 = LDG(&nbfp[baseIndex]);
-    c6    = c6c12.x;
-    c12   = c6c12.y;
+    c6c12 = LDG(&nbparam.nbfp[baseIndex]);
 #    else
-    /* NOTE: as we always do 8-byte aligned loads, we could
-       fetch float2 here too just as above. */
-    c6  = tex1Dfetch<float>(nbparam.nbfp_texobj, 2 * baseIndex);
-    c12 = tex1Dfetch<float>(nbparam.nbfp_texobj, 2 * baseIndex + 1);
+    c6c12 = tex1Dfetch<float2>(nbparam.nbfp_texobj, baseIndex);
 #    endif // DISABLE_CUDA_TEXTURES
+    c6  = c6c12.x;
+    c12 = c6c12.y;
 }
 
 
index 7c92a1abdc648ab403a495a0687ce796a3e19c66..91464b8010efaa9e88f52c75118998ca109695e2 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2012, The GROMACS development team.
- * Copyright (c) 2013-2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013-2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 @@
 #include "gromacs/gpu_utils/cudautils.cuh"
 #include "gromacs/gpu_utils/devicebuffer.h"
 #include "gromacs/gpu_utils/devicebuffer_datatype.h"
+#include "gromacs/gpu_utils/gpueventsynchronizer.cuh"
 #include "gromacs/gpu_utils/gputraits.cuh"
 #include "gromacs/mdtypes/interaction_const.h"
 #include "gromacs/nbnxm/gpu_types_common.h"
 #include "gromacs/timing/gpu_timing.h"
 #include "gromacs/utility/enumerationhelpers.h"
 
-/*! \brief Macro definining default for the prune kernel's j4 processing concurrency.
- *
- *  The GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY macro allows compile-time override.
- */
-#ifndef GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY
-#    define GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY 4
-#endif
-/*! \brief Default for the prune kernel's j4 processing concurrency.
- *
- *  Initialized using the #GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY macro which allows compile-time override.
- */
-const int c_cudaPruneKernelJ4Concurrency = GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY;
-
 /* TODO: consider moving this to kernel_utils */
 /* Convenience defines */
 /*! \brief cluster size = number of atoms per cluster. */
 static constexpr int c_clSize = c_nbnxnGpuClusterSize;
 
-/* All structs prefixed with "cu_" hold data used in GPU calculations and
- * are passed to the kernels, except cu_timers_t. */
-/*! \cond */
-typedef struct cu_atomdata cu_atomdata_t;
-/*! \endcond */
-
-
-/** \internal
- * \brief Staging area for temporary data downloaded from the GPU.
- *
- *  The energies/shift forces get downloaded here first, before getting added
- *  to the CPU-side aggregate values.
- */
-struct nb_staging_t
-{
-    //! LJ energy
-    float* e_lj = nullptr;
-    //! electrostatic energy
-    float* e_el = nullptr;
-    //! shift forces
-    float3* fshift = nullptr;
-};
-
-/** \internal
- * \brief Nonbonded atom data - both inputs and outputs.
- */
-struct cu_atomdata
-{
-    //! number of atoms
-    int natoms;
-    //! number of local atoms
-    int natoms_local;
-    //! allocation size for the atom data (xq, f)
-    int nalloc;
-
-    //! atom coordinates + charges, size natoms
-    DeviceBuffer<float4> xq;
-    //! force output array, size natoms
-    DeviceBuffer<float3> f;
-
-    //! LJ energy output, size 1
-    DeviceBuffer<float> e_lj;
-    //! Electrostatics energy input, size 1
-    DeviceBuffer<float> e_el;
-
-    //! shift forces
-    DeviceBuffer<float3> fshift;
-
-    //! number of atom types
-    int ntypes;
-    //! atom type indices, size natoms
-    DeviceBuffer<int> atom_types;
-    //! sqrt(c6),sqrt(c12) size natoms
-    DeviceBuffer<float2> lj_comb;
-
-    //! shifts
-    DeviceBuffer<float3> shift_vec;
-    //! true if the shift vector has been uploaded
-    bool bShiftVecUploaded;
-};
-
-/** \internal
- * \brief Typedef of actual timer type.
- */
-typedef struct Nbnxm::gpu_timers_t cu_timers_t;
-
-class GpuEventSynchronizer;
-
 /*! \internal
  * \brief Main data structure for CUDA nonbonded force calculations.
  */
@@ -156,8 +76,11 @@ struct NbnxmGpu
     const DeviceContext* deviceContext_;
     /*! \brief true if doing both local/non-local NB work on GPU */
     bool bUseTwoStreams = false;
+    //! true indicates that the nonlocal_done event was marked
+    bool bNonLocalStreamDoneMarked = false;
+
     /*! \brief atom data */
-    cu_atomdata_t* atdat = nullptr;
+    NBAtomDataGpu* atdat = nullptr;
     /*! \brief array of atom indices */
     int* atomIndices = nullptr;
     /*! \brief size of atom indices */
@@ -181,22 +104,19 @@ struct NbnxmGpu
     /*! \brief pair-list data structures (local and non-local) */
     gmx::EnumerationArray<Nbnxm::InteractionLocality, Nbnxm::gpu_plist*> plist = { { nullptr } };
     /*! \brief staging area where fshift/energies get downloaded */
-    nb_staging_t nbst;
+    NBStagingData nbst;
     /*! \brief local and non-local GPU streams */
     gmx::EnumerationArray<Nbnxm::InteractionLocality, const DeviceStream*> deviceStreams;
 
-    /*! \brief Events used for synchronization */
-    /*! \{ */
     /*! \brief Event triggered when the non-local non-bonded
      * kernel is done (and the local transfer can proceed) */
-    cudaEvent_t nonlocal_done = nullptr;
+    GpuEventSynchronizer nonlocal_done;
     /*! \brief Event triggered when the tasks issued in the local
      * stream that need to precede the non-local force or buffer
      * operation calculations are done (e.g. f buffer 0-ing, local
      * x/q H2D, buffer op initialization in local stream that is
      * required also by nonlocal stream ) */
-    cudaEvent_t misc_ops_and_local_H2D_done = nullptr;
-    /*! \} */
+    GpuEventSynchronizer misc_ops_and_local_H2D_done;
 
     /*! \brief True if there is work for the current domain in the
      * respective locality.
@@ -208,10 +128,6 @@ struct NbnxmGpu
      * will be true. */
     gmx::EnumerationArray<Nbnxm::InteractionLocality, bool> haveWork = { { false } };
 
-    /*! \brief Event triggered when non-local coordinate buffer
-     * has been copied from device to host. */
-    GpuEventSynchronizer* xNonLocalCopyD2HDone = nullptr;
-
     /* NOTE: With current CUDA versions (<=5.0) timing doesn't work with multiple
      * concurrent streams, so we won't time if both l/nl work is done on GPUs.
      * Timer init/uninit is still done even with timing off so only the condition
@@ -219,7 +135,7 @@ struct NbnxmGpu
     /*! \brief True if event-based timing is enabled. */
     bool bDoTime = false;
     /*! \brief CUDA event-based timers. */
-    cu_timers_t* timers = nullptr;
+    Nbnxm::GpuTimers* timers = nullptr;
     /*! \brief Timing data. TODO: deprecate this and query timers for accumulated data instead */
     gmx_wallclock_gpu_nbnxn_t* timings = nullptr;
 };
index 7d41ee618022e3dbb6bfb18b6c9f22aeeda9c622..bf9c25a5e70a16db2942bebf4822ee763a200fce 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "opencl/nbnxm_ocl_types.h"
 #endif
 
+#if GMX_GPU_SYCL
+#    include "sycl/nbnxm_sycl_types.h"
+#endif
+
 #include "gromacs/gpu_utils/gpu_utils.h"
-#include "gromacs/listed_forces/gpubonded.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdtypes/simulation_workload.h"
 #include "gromacs/nbnxm/nbnxm.h"
 #include "gromacs/pbcutil/ishift.h"
 #include "gromacs/timing/gpu_timing.h"
 #include "gromacs/timing/wallcycle.h"
-#include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/stringutil.h"
 
 #include "gpu_common_utils.h"
@@ -77,136 +79,24 @@ class GpuBonded;
 namespace Nbnxm
 {
 
-/*! \brief Check that atom locality values are valid for the GPU module.
- *
- *  In the GPU module atom locality "all" is not supported, the local and
- *  non-local ranges are treated separately.
- *
- *  \param[in] atomLocality atom locality specifier
- */
-static inline void validateGpuAtomLocality(const AtomLocality atomLocality)
-{
-    std::string str = gmx::formatString(
-            "Invalid atom locality passed (%d); valid here is only "
-            "local (%d) or nonlocal (%d)",
-            static_cast<int>(atomLocality), static_cast<int>(AtomLocality::Local),
-            static_cast<int>(AtomLocality::NonLocal));
-
-    GMX_ASSERT(atomLocality == AtomLocality::Local || atomLocality == AtomLocality::NonLocal, str.c_str());
-}
-
-/*! \brief Convert atom locality to interaction locality.
- *
- *  In the current implementation the this is straightforward conversion:
- *  local to local, non-local to non-local.
- *
- *  \param[in] atomLocality Atom locality specifier
- *  \returns                Interaction locality corresponding to the atom locality passed.
- */
-static inline InteractionLocality gpuAtomToInteractionLocality(const AtomLocality atomLocality)
-{
-    validateGpuAtomLocality(atomLocality);
-
-    /* determine interaction locality from atom locality */
-    if (atomLocality == AtomLocality::Local)
-    {
-        return InteractionLocality::Local;
-    }
-    else if (atomLocality == AtomLocality::NonLocal)
-    {
-        return InteractionLocality::NonLocal;
-    }
-    else
-    {
-        gmx_incons("Wrong locality");
-    }
-}
-
-
-//NOLINTNEXTLINE(misc-definitions-in-headers)
-void setupGpuShortRangeWork(NbnxmGpu* nb, const gmx::GpuBonded* gpuBonded, const gmx::InteractionLocality iLocality)
-{
-    GMX_ASSERT(nb, "Need a valid nbnxn_gpu object");
-
-    // There is short-range work if the pair list for the provided
-    // interaction locality contains entries or if there is any
-    // bonded work (as this is not split into local/nonlocal).
-    nb->haveWork[iLocality] = ((nb->plist[iLocality]->nsci != 0)
-                               || (gpuBonded != nullptr && gpuBonded->haveInteractions()));
-}
-
-/*! \brief Returns true if there is GPU short-range work for the given interaction locality.
- *
- * Note that as, unlike nonbonded tasks, bonded tasks are not split into local/nonlocal,
- * and therefore if there are GPU offloaded bonded interactions, this function will return
- * true for all interaction localities.
- *
- * \param[inout]  nb        Pointer to the nonbonded GPU data structure
- * \param[in]     iLocality Interaction locality identifier
- */
-static bool haveGpuShortRangeWork(const NbnxmGpu& nb, const gmx::InteractionLocality iLocality)
-{
-    return nb.haveWork[iLocality];
-}
-
-//NOLINTNEXTLINE(misc-definitions-in-headers)
-bool haveGpuShortRangeWork(const NbnxmGpu* nb, const gmx::AtomLocality aLocality)
-{
-    GMX_ASSERT(nb, "Need a valid nbnxn_gpu object");
-
-    return haveGpuShortRangeWork(*nb, gpuAtomToInteractionLocality(aLocality));
-}
-
-
-/*! \brief Calculate atom range and return start index and length.
- *
- * \param[in] atomData Atom descriptor data structure
- * \param[in] atomLocality Atom locality specifier
- * \param[out] atomRangeBegin Starting index of the atom range in the atom data array.
- * \param[out] atomRangeLen Atom range length in the atom data array.
- */
-template<typename AtomDataT>
-static inline void getGpuAtomRange(const AtomDataT*   atomData,
-                                   const AtomLocality atomLocality,
-                                   int*               atomRangeBegin,
-                                   int*               atomRangeLen)
-{
-    assert(atomData);
-    validateGpuAtomLocality(atomLocality);
-
-    /* calculate the atom data index range based on locality */
-    if (atomLocality == AtomLocality::Local)
-    {
-        *atomRangeBegin = 0;
-        *atomRangeLen   = atomData->natoms_local;
-    }
-    else
-    {
-        *atomRangeBegin = atomData->natoms_local;
-        *atomRangeLen   = atomData->natoms - atomData->natoms_local;
-    }
-}
-
-
 /*! \brief Count pruning kernel time if either kernel has been triggered
  *
  *  We do the accounting for either of the two pruning kernel flavors:
  *   - 1st pass prune: ran during the current step (prior to the force kernel);
  *   - rolling prune:  ran at the end of the previous step (prior to the current step H2D xq);
  *
- * Note that the resetting of cu_timers_t::didPrune and cu_timers_t::didRollingPrune should happen
- * after calling this function.
+ * Note that the resetting of Nbnxm::GpuTimers::didPrune and Nbnxm::GpuTimers::didRollingPrune
+ * should happen after calling this function.
  *
  * \param[in] timers   structs with GPU timer objects
  * \param[inout] timings  GPU task timing data
  * \param[in] iloc        interaction locality
  */
-template<typename GpuTimers>
-static void countPruneKernelTime(GpuTimers*                 timers,
+static void countPruneKernelTime(Nbnxm::GpuTimers*          timers,
                                  gmx_wallclock_gpu_nbnxn_t* timings,
                                  const InteractionLocality  iloc)
 {
-    gpu_timers_t::Interaction& iTimers = timers->interaction[iloc];
+    GpuTimers::Interaction& iTimers = timers->interaction[iloc];
 
     // We might have not done any pruning (e.g. if we skipped with empty domains).
     if (!iTimers.didPrune && !iTimers.didRollingPrune)
@@ -236,7 +126,6 @@ static void countPruneKernelTime(GpuTimers*                 timers,
  * Note that this function should always be called after the transfers into the
  * staging buffers has completed.
  *
- * \tparam     StagingData    Type of staging data
  * \param[in]  nbst           Nonbonded staging data
  * \param[in]  iLocality      Interaction locality specifier
  * \param[in]  reduceEnergies True if energy reduction should be done
@@ -245,8 +134,7 @@ static void countPruneKernelTime(GpuTimers*                 timers,
  * \param[out] e_el           Variable to accumulate electrostatic energy into
  * \param[out] fshift         Pointer to the array of shift forces to accumulate into
  */
-template<typename StagingData>
-static inline void gpu_reduce_staged_outputs(const StagingData&        nbst,
+static inline void gpu_reduce_staged_outputs(const NBStagingData&      nbst,
                                              const InteractionLocality iLocality,
                                              const bool                reduceEnergies,
                                              const bool                reduceFshift,
@@ -259,15 +147,15 @@ static inline void gpu_reduce_staged_outputs(const StagingData&        nbst,
     {
         if (reduceEnergies)
         {
-            *e_lj += *nbst.e_lj;
-            *e_el += *nbst.e_el;
+            *e_lj += *nbst.eLJ;
+            *e_el += *nbst.eElec;
         }
 
         if (reduceFshift)
         {
-            for (int i = 0; i < SHIFTS; i++)
+            for (int i = 0; i < gmx::c_numShiftVectors; i++)
             {
-                rvec_inc(fshift[i], nbst.fshift[i]);
+                rvec_inc(fshift[i], nbst.fShift[i]);
             }
         }
     }
@@ -284,7 +172,6 @@ static inline void gpu_reduce_staged_outputs(const StagingData&        nbst,
  *      counters could end up being inconsistent due to not being incremented
  *      on some of the node when this is skipped on empty local domains!
  *
- * \tparam     GpuTimers         GPU timers type
  * \tparam     GpuPairlist       Pair list type
  * \param[out] timings           Pointer to the NB GPU timings data
  * \param[in]  timers            Pointer to GPU timers data
@@ -294,9 +181,9 @@ static inline void gpu_reduce_staged_outputs(const StagingData&        nbst,
  * \param[in]  doTiming          True if timing is enabled.
  *
  */
-template<typename GpuTimers, typename GpuPairlist>
+template<typename GpuPairlist>
 static inline void gpu_accumulate_timings(gmx_wallclock_gpu_nbnxn_t* timings,
-                                          GpuTimers*                 timers,
+                                          Nbnxm::GpuTimers*          timers,
                                           const GpuPairlist*         plist,
                                           AtomLocality               atomLocality,
                                           const gmx::StepWorkload&   stepWork,
@@ -309,7 +196,7 @@ static inline void gpu_accumulate_timings(gmx_wallclock_gpu_nbnxn_t* timings,
     }
 
     /* determine interaction locality from atom locality */
-    const InteractionLocality iLocality        = gpuAtomToInteractionLocality(atomLocality);
+    const InteractionLocality iLocality        = atomToInteractionLocality(atomLocality);
     const bool                didEnergyKernels = stepWork.computeEnergy;
 
     /* only increase counter once (at local F wait) */
@@ -374,7 +261,7 @@ bool gpu_try_finish_task(NbnxmGpu*                nb,
     GMX_ASSERT(nb, "Need a valid nbnxn_gpu object");
 
     /* determine interaction locality from atom locality */
-    const InteractionLocality iLocality = gpuAtomToInteractionLocality(aloc);
+    const InteractionLocality iLocality = atomToInteractionLocality(aloc);
 
 
     // Transfers are launched and therefore need to be waited on if:
@@ -390,7 +277,7 @@ bool gpu_try_finish_task(NbnxmGpu*                nb,
     //  We skip when during the non-local phase there was actually no work to do.
     //  This is consistent with nbnxn_gpu_launch_kernel but it also considers possible
     //  bonded GPU work.
-    if ((iLocality == InteractionLocality::Local) || haveGpuShortRangeWork(*nb, iLocality))
+    if ((iLocality == InteractionLocality::Local) || haveGpuShortRangeWork(nb, iLocality))
     {
         // Query the state of the GPU stream and return early if we're not done
         if (completionKind == GpuTaskCompletion::Check)
@@ -399,18 +286,18 @@ bool gpu_try_finish_task(NbnxmGpu*                nb,
             // we start without counting and only when the task finished we issue a
             // start/stop to increment.
             // GpuTaskCompletion::Wait mode the timing is expected to be done in the caller.
-            wallcycle_start_nocount(wcycle, ewcWAIT_GPU_NB_L);
+            wallcycle_start_nocount(wcycle, WallCycleCounter::WaitGpuNbL);
 
             if (!haveStreamTasksCompleted(*nb->deviceStreams[iLocality]))
             {
-                wallcycle_stop(wcycle, ewcWAIT_GPU_NB_L);
+                wallcycle_stop(wcycle, WallCycleCounter::WaitGpuNbL);
 
                 // Early return to skip the steps below that we have to do only
                 // after the NB task completed
                 return false;
             }
 
-            wallcycle_increment_event_count(wcycle, ewcWAIT_GPU_NB_L);
+            wallcycle_increment_event_count(wcycle, WallCycleCounter::WaitGpuNbL);
         }
         else if (haveResultToWaitFor)
         {
@@ -424,14 +311,22 @@ bool gpu_try_finish_task(NbnxmGpu*                nb,
 
         if (stepWork.computeEnergy || stepWork.computeVirial)
         {
-            gpu_reduce_staged_outputs(nb->nbst, iLocality, stepWork.computeEnergy, stepWork.computeVirial,
-                                      e_lj, e_el, as_rvec_array(shiftForces.data()));
+            gpu_reduce_staged_outputs(nb->nbst,
+                                      iLocality,
+                                      stepWork.computeEnergy,
+                                      stepWork.computeVirial,
+                                      e_lj,
+                                      e_el,
+                                      as_rvec_array(shiftForces.data()));
         }
     }
 
-    /* Always reset both pruning flags (doesn't hurt doing it even when timing is off). */
-    nb->timers->interaction[iLocality].didPrune =
-            nb->timers->interaction[iLocality].didRollingPrune = false;
+    /* Reset both pruning flags. */
+    if (nb->bDoTime)
+    {
+        nb->timers->interaction[iLocality].didPrune =
+                nb->timers->interaction[iLocality].didRollingPrune = false;
+    }
 
     /* Turn off initial list pruning (doesn't hurt if this is not pair-search step). */
     nb->plist[iLocality]->haveFreshList = false;
@@ -465,9 +360,9 @@ float gpu_wait_finish_task(NbnxmGpu*                nb,
                            gmx::ArrayRef<gmx::RVec> shiftForces,
                            gmx_wallcycle*           wcycle)
 {
-    auto cycleCounter = (gpuAtomToInteractionLocality(aloc) == InteractionLocality::Local)
-                                ? ewcWAIT_GPU_NB_L
-                                : ewcWAIT_GPU_NB_NL;
+    auto cycleCounter = (atomToInteractionLocality(aloc) == InteractionLocality::Local)
+                                ? WallCycleCounter::WaitGpuNbL
+                                : WallCycleCounter::WaitGpuNbNL;
 
     wallcycle_start(wcycle, cycleCounter);
     gpu_try_finish_task(nb, stepWork, aloc, e_lj, e_el, shiftForces, GpuTaskCompletion::Wait, wcycle);
index af0c69f36c8ddb12e49849ae742616a289d99c93..0d81e2f05a4dcb786aa91ec5752ea10db65b27f6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_NBNXM_GPU_COMMON_UTILS_H
 #define GMX_NBNXM_GPU_COMMON_UTILS_H
 
-#include "config.h"
-
-#include "gromacs/nbnxm/nbnxm.h"
-
-#if GMX_GPU_CUDA
-#    include "cuda/nbnxm_cuda_types.h"
-#endif
-
-#if GMX_GPU_OPENCL
-#    include "opencl/nbnxm_ocl_types.h"
-#endif
+#include "gromacs/listed_forces/gpubonded.h"
+#include "gromacs/mdtypes/locality.h"
+#include "gromacs/nbnxm/gpu_types_common.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/range.h"
 
 namespace Nbnxm
 {
@@ -70,6 +64,32 @@ static inline bool canSkipNonbondedWork(const NbnxmGpu& nb, InteractionLocality
     return (iloc == InteractionLocality::NonLocal && nb.plist[iloc]->nsci == 0);
 }
 
+/*! \brief Calculate atom range and return start index and length.
+ *
+ * \param[in] atomData Atom descriptor data structure
+ * \param[in] atomLocality Atom locality specifier
+ * \returns Range of indexes for selected locality.
+ */
+static inline gmx::Range<int> getGpuAtomRange(const NBAtomDataGpu* atomData, const AtomLocality atomLocality)
+{
+    assert(atomData);
+
+    /* calculate the atom data index range based on locality */
+    if (atomLocality == AtomLocality::Local)
+    {
+        return gmx::Range<int>(0, atomData->numAtomsLocal);
+    }
+    else if (atomLocality == AtomLocality::NonLocal)
+    {
+        return gmx::Range<int>(atomData->numAtomsLocal, atomData->numAtoms);
+    }
+    else
+    {
+        GMX_THROW(gmx::InconsistentInputError(
+                "Only Local and NonLocal atom locities can be used to get atom ranges in NBNXM."));
+    }
+}
+
 } // namespace Nbnxm
 
 #endif
index a472cb437dabaf08cc4b8603cdf692614000ca85..3f04782c4f52a95158763a9945bfac2800dc958b 100644 (file)
@@ -2,6 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 +51,8 @@
 #include "gromacs/gpu_utils/gpu_macros.h"
 #include "gromacs/mdtypes/locality.h"
 
+#include "nbnxm.h"
+
 struct NbnxmGpu;
 struct DeviceInformation;
 struct gmx_wallclock_gpu_nbnxn_t;
@@ -92,7 +95,7 @@ void gpu_init_atomdata(NbnxmGpu gmx_unused* nb, const nbnxn_atomdata_t gmx_unuse
  */
 GPU_FUNC_QUALIFIER
 void gpu_pme_loadbal_update_param(const struct nonbonded_verlet_t gmx_unused* nbv,
-                                  const interaction_const_t gmx_unused* ic) GPU_FUNC_TERM;
+                                  const interaction_const_t gmx_unused& ic) GPU_FUNC_TERM;
 
 /** Uploads shift vector to the GPU if the box is dynamic (otherwise just returns). */
 GPU_FUNC_QUALIFIER
@@ -124,13 +127,6 @@ int gpu_min_ci_balanced(NbnxmGpu gmx_unused* nb) GPU_FUNC_TERM_WITH_RETURN(-1);
 GPU_FUNC_QUALIFIER
 bool gpu_is_kernel_ewald_analytical(const NbnxmGpu gmx_unused* nb) GPU_FUNC_TERM_WITH_RETURN(FALSE);
 
-/** Returns an opaque pointer to the GPU command stream
- *  Note: CUDA only.
- */
-CUDA_FUNC_QUALIFIER
-const DeviceStream* gpu_get_command_stream(NbnxmGpu gmx_unused* nb, gmx::InteractionLocality gmx_unused iloc)
-        CUDA_FUNC_TERM_WITH_RETURN(nullptr);
-
 /** Returns an opaque pointer to the GPU coordinate+charge array
  *  Note: CUDA only.
  */
index f3c4bd385bde7140ac08150e045e1e40ef04a466..74e2a02d07e35acb9643952e9cb13fd4aca55056 100644 (file)
 
 #include "config.h"
 
+#include "gromacs/mdtypes/interaction_const.h"
 #include "gromacs/mdtypes/locality.h"
 #include "gromacs/utility/enumerationhelpers.h"
 
+#include "nbnxm.h"
 #include "pairlist.h"
 
 #if GMX_GPU_OPENCL
 #    include "gromacs/gpu_utils/gpuregiontimer.cuh"
 #endif
 
+#if GMX_GPU_SYCL
+#    include "gromacs/gpu_utils/gpuregiontimer_sycl.h"
+#endif
+
+/*! \brief Macro definining default for the prune kernel's j4 processing concurrency.
+ *
+ *  The GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY macro allows compile-time override with the default value of 4.
+ */
+#ifndef GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY
+#    define GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY 4
+#endif
+//! Default for the prune kernel's j4 processing concurrency.
+static constexpr int c_pruneKernelJ4Concurrency = GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY;
+
+/*! \internal
+ * \brief Staging area for temporary data downloaded from the GPU.
+ *
+ * Since SYCL buffers already have host-side storage, this is a bit redundant.
+ * But it allows prefetching of the data from GPU, and brings GPU backends closer together.
+ */
+struct NBStagingData
+{
+    //! LJ energy
+    float* eLJ = nullptr;
+    //! electrostatic energy
+    float* eElec = nullptr;
+    //! shift forces
+    Float3* fShift = nullptr;
+};
+
+/** \internal
+ * \brief Nonbonded atom data - both inputs and outputs.
+ */
+struct NBAtomDataGpu
+{
+    //! number of atoms
+    int numAtoms;
+    //! number of local atoms
+    int numAtomsLocal;
+    //! allocation size for the atom data (xq, f)
+    int numAtomsAlloc;
+
+    //! atom coordinates + charges, size \ref numAtoms
+    DeviceBuffer<Float4> xq;
+    //! force output array, size \ref numAtoms
+    DeviceBuffer<Float3> f;
+
+    //! LJ energy output, size 1
+    DeviceBuffer<float> eLJ;
+    //! Electrostatics energy input, size 1
+    DeviceBuffer<float> eElec;
+
+    //! shift forces
+    DeviceBuffer<Float3> fShift;
+
+    //! number of atom types
+    int numTypes;
+    //! atom type indices, size \ref numAtoms
+    DeviceBuffer<int> atomTypes;
+    //! sqrt(c6),sqrt(c12) size \ref numAtoms
+    DeviceBuffer<Float2> ljComb;
+
+    //! shifts
+    DeviceBuffer<Float3> shiftVec;
+    //! true if the shift vector has been uploaded
+    bool shiftVecUploaded;
+};
+
 /** \internal
  * \brief Parameters required for the GPU nonbonded calculations.
  */
 struct NBParamGpu
 {
 
-    //! type of electrostatics, takes values from #eelType
-    int eeltype;
-    //! type of VdW impl., takes values from #evdwType
-    int vdwtype;
+    //! type of electrostatics
+    enum Nbnxm::ElecType elecType;
+    //! type of VdW impl.
+    enum Nbnxm::VdwType vdwType;
 
     //! charge multiplication factor
     float epsfac;
@@ -76,7 +146,7 @@ struct NBParamGpu
     float two_k_rf;
     //! Ewald/PME parameter
     float ewald_beta;
-    //! Ewald/PME correction term substracted from the direct-space potential
+    //! Ewald/PME correction term subtracted from the direct-space potential
     float sh_ewald;
     //! LJ-Ewald/PME correction term added to the correction potential
     float sh_lj_ewald;
@@ -105,12 +175,12 @@ struct NBParamGpu
     switch_consts_t vdw_switch;
 
     /* LJ non-bonded parameters - accessed through texture memory */
-    //! nonbonded parameter table with C6/C12 pairs per atom type-pair, 2*ntype^2 elements
-    DeviceBuffer<float> nbfp;
+    //! nonbonded parameter table with 6*C6/12*C12 pairs per atom type-pair, ntype^2 elements
+    DeviceBuffer<Float2> nbfp{};
     //! texture object bound to nbfp
     DeviceTexture nbfp_texobj;
-    //! nonbonded parameter table per atom type, 2*ntype elements
-    DeviceBuffer<float> nbfp_comb;
+    //! nonbonded parameter table per atom type, ntype elements
+    DeviceBuffer<Float2> nbfp_comb{};
     //! texture object bound to nbfp_comb
     DeviceTexture nbfp_comb_texobj;
 
@@ -118,7 +188,7 @@ struct NBParamGpu
     //! table scale/spacing
     float coulomb_tab_scale;
     //! pointer to the table in the device memory
-    DeviceBuffer<float> coulomb_tab;
+    DeviceBuffer<float> coulomb_tab{};
     //! texture object bound to coulomb_tab
     DeviceTexture coulomb_tab_texobj;
 };
@@ -135,7 +205,7 @@ using gmx::InteractionLocality;
  * The two-sized arrays hold the local and non-local values and should always
  * be indexed with eintLocal/eintNonlocal.
  */
-struct gpu_timers_t
+struct GpuTimers
 {
     /*! \internal
      * \brief Timers for local or non-local coordinate/force transfers
@@ -174,7 +244,7 @@ struct gpu_timers_t
     //! timers for coordinate/force transfers (every step)
     gmx::EnumerationArray<AtomLocality, XFTransfers> xf;
     //! timers for interaction related transfers
-    gmx::EnumerationArray<InteractionLocality, Nbnxm::gpu_timers_t::Interaction> interaction;
+    gmx::EnumerationArray<InteractionLocality, Nbnxm::GpuTimers::Interaction> interaction;
 };
 
 /*! \internal
index d852ec4f0899db0a550287aaa9419b28ea9a9fce..56584071e7c69816a57ebaadcf660b1cb123d0b3 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -100,6 +100,41 @@ static real gridAtomDensity(int numAtoms, const rvec lowerCorner, const rvec upp
     return static_cast<real>(numAtoms) / (size[XX] * size[YY] * size[ZZ]);
 }
 
+// Get approximate dimensions of each cell. Returns the length along X and Y.
+static std::array<real, DIM - 1> getTargetCellLength(const Grid::Geometry& geometry, const real atomDensity)
+{
+    if (geometry.isSimple)
+    {
+        /* To minimize the zero interactions, we should make
+         * the largest of the i/j cell cubic.
+         */
+        int numAtomsInCell = std::max(geometry.numAtomsICluster, geometry.numAtomsJCluster);
+
+        /* Approximately cubic cells */
+        real tlen = std::cbrt(numAtomsInCell / atomDensity);
+        return { tlen, tlen };
+    }
+    else
+    {
+        /* Approximately cubic sub cells */
+        real tlen = std::cbrt(geometry.numAtomsICluster / atomDensity);
+        return { tlen * c_gpuNumClusterPerCellX, tlen * c_gpuNumClusterPerCellY };
+    }
+}
+
+static int getMaxNumCells(const Grid::Geometry& geometry, const int numAtoms, const int numColumns)
+{
+    if (geometry.numAtomsJCluster <= geometry.numAtomsICluster)
+    {
+        return numAtoms / geometry.numAtomsPerCell + numColumns;
+    }
+    else
+    {
+        return numAtoms / geometry.numAtomsPerCell
+               + numColumns * geometry.numAtomsJCluster / geometry.numAtomsICluster;
+    }
+}
+
 void Grid::setDimensions(const int          ddZone,
                          const int          numAtoms,
                          gmx::RVec          lowerCorner,
@@ -146,33 +181,14 @@ void Grid::setDimensions(const int          ddZone,
         GMX_ASSERT(atomDensity > 0, "With one or more atoms, the density should be positive");
 
         /* target cell length */
-        real tlen_x;
-        real tlen_y;
-        if (geometry_.isSimple)
-        {
-            /* To minimize the zero interactions, we should make
-             * the largest of the i/j cell cubic.
-             */
-            int numAtomsInCell = std::max(geometry_.numAtomsICluster, geometry_.numAtomsJCluster);
+        const std::array<real, DIM - 1> tlen = getTargetCellLength(geometry_, atomDensity);
 
-            /* Approximately cubic cells */
-            real tlen = std::cbrt(numAtomsInCell / atomDensity);
-            tlen_x    = tlen;
-            tlen_y    = tlen;
-        }
-        else
-        {
-            /* Approximately cubic sub cells */
-            real tlen = std::cbrt(geometry_.numAtomsICluster / atomDensity);
-            tlen_x    = tlen * c_gpuNumClusterPerCellX;
-            tlen_y    = tlen * c_gpuNumClusterPerCellY;
-        }
         /* We round ncx and ncy down, because we get less cell pairs
          * in the pairlist when the fixed cell dimensions (x,y) are
          * larger than the variable one (z) than the other way around.
          */
-        dimensions_.numCells[XX] = std::max(1, static_cast<int>(size[XX] / tlen_x));
-        dimensions_.numCells[YY] = std::max(1, static_cast<int>(size[YY] / tlen_y));
+        dimensions_.numCells[XX] = std::max(1, static_cast<int>(size[XX] / tlen[XX]));
+        dimensions_.numCells[YY] = std::max(1, static_cast<int>(size[YY] / tlen[YY]));
     }
     else
     {
@@ -205,16 +221,7 @@ void Grid::setDimensions(const int          ddZone,
     changePinningPolicy(&cxy_ind_, pinningPolicy);
 
     /* Worst case scenario of 1 atom in each last cell */
-    int maxNumCells;
-    if (geometry_.numAtomsJCluster <= geometry_.numAtomsICluster)
-    {
-        maxNumCells = numAtoms / geometry_.numAtomsPerCell + numColumns();
-    }
-    else
-    {
-        maxNumCells = numAtoms / geometry_.numAtomsPerCell
-                      + numColumns() * geometry_.numAtomsJCluster / geometry_.numAtomsICluster;
-    }
+    const int maxNumCells = getMaxNumCells(geometry_, numAtoms, numColumns());
 
     if (!geometry_.isSimple)
     {
@@ -334,8 +341,16 @@ static void sort_atoms(int      dim,
         /* As we can have rounding effect, we use > iso >= here */
         if (relevantAtomsAreWithinGridBounds && (zi < 0 || (dd_zone == 0 && zi > n_per_h * c_sortGridRatio)))
         {
-            gmx_fatal(FARGS, "(int)((x[%d][%c]=%f - %f)*%f) = %d, not in 0 - %d*%d\n", a[i],
-                      'x' + dim, x[a[i]][dim], h0, invh, zi, n_per_h, c_sortGridRatio);
+            gmx_fatal(FARGS,
+                      "(int)((x[%d][%c]=%f - %f)*%f) = %d, not in 0 - %d*%d\n",
+                      a[i],
+                      'x' + dim,
+                      x[a[i]][dim],
+                      h0,
+                      invh,
+                      zi,
+                      n_per_h,
+                      c_sortGridRatio);
         }
 #endif
         if (zi < 0)
@@ -343,7 +358,7 @@ static void sort_atoms(int      dim,
             zi = 0;
         }
 
-        /* In a non-local domain, particles communcated for bonded interactions
+        /* In a non-local domain, particles communicated for bonded interactions
          * can be far beyond the grid size, which is set by the non-bonded
          * cut-off distance. We sort such particles into the last cell.
          */
@@ -453,16 +468,13 @@ static float R2F_U(const float x)
 //! Computes the bounding box for na coordinates in order x,y,z, bb order xyz0
 static void calc_bounding_box(int na, int stride, const real* x, BoundingBox* bb)
 {
-    int  i;
-    real xl, xh, yl, yh, zl, zh;
-
-    i  = 0;
-    xl = x[i + XX];
-    xh = x[i + XX];
-    yl = x[i + YY];
-    yh = x[i + YY];
-    zl = x[i + ZZ];
-    zh = x[i + ZZ];
+    int  i  = 0;
+    real xl = x[i + XX];
+    real xh = x[i + XX];
+    real yl = x[i + YY];
+    real yh = x[i + YY];
+    real zl = x[i + ZZ];
+    real zh = x[i + ZZ];
     i += stride;
     for (int j = 1; j < na; j++)
     {
@@ -486,14 +498,12 @@ static void calc_bounding_box(int na, int stride, const real* x, BoundingBox* bb
 /*! \brief Computes the bounding box for na packed coordinates, bb order xyz0 */
 static void calc_bounding_box_x_x4(int na, const real* x, BoundingBox* bb)
 {
-    real xl, xh, yl, yh, zl, zh;
-
-    xl = x[XX * c_packX4];
-    xh = x[XX * c_packX4];
-    yl = x[YY * c_packX4];
-    yh = x[YY * c_packX4];
-    zl = x[ZZ * c_packX4];
-    zh = x[ZZ * c_packX4];
+    real xl = x[XX * c_packX4];
+    real xh = x[XX * c_packX4];
+    real yl = x[YY * c_packX4];
+    real yh = x[YY * c_packX4];
+    real zl = x[ZZ * c_packX4];
+    real zh = x[ZZ * c_packX4];
     for (int j = 1; j < na; j++)
     {
         xl = std::min(xl, x[j + XX * c_packX4]);
@@ -515,14 +525,12 @@ static void calc_bounding_box_x_x4(int na, const real* x, BoundingBox* bb)
 /*! \brief Computes the bounding box for na coordinates, bb order xyz0 */
 static void calc_bounding_box_x_x8(int na, const real* x, BoundingBox* bb)
 {
-    real xl, xh, yl, yh, zl, zh;
-
-    xl = x[XX * c_packX8];
-    xh = x[XX * c_packX8];
-    yl = x[YY * c_packX8];
-    yh = x[YY * c_packX8];
-    zl = x[ZZ * c_packX8];
-    zh = x[ZZ * c_packX8];
+    real xl = x[XX * c_packX8];
+    real xh = x[XX * c_packX8];
+    real yl = x[YY * c_packX8];
+    real yh = x[YY * c_packX8];
+    real zl = x[ZZ * c_packX8];
+    real zh = x[ZZ * c_packX8];
     for (int j = 1; j < na; j++)
     {
         xl = std::min(xl, x[j + XX * c_packX8]);
@@ -582,16 +590,13 @@ gmx_unused static void calc_bounding_box_x_x4_halves(int na, const real* x, Boun
 /*! \brief Computes the bounding box for na coordinates in order xyz, bb order xxxxyyyyzzzz */
 static void calc_bounding_box_xxxx(int na, int stride, const real* x, float* bb)
 {
-    int  i;
-    real xl, xh, yl, yh, zl, zh;
-
-    i  = 0;
-    xl = x[i + XX];
-    xh = x[i + XX];
-    yl = x[i + YY];
-    yh = x[i + YY];
-    zl = x[i + ZZ];
-    zh = x[i + ZZ];
+    int  i  = 0;
+    real xl = x[i + XX];
+    real xh = x[i + XX];
+    real yl = x[i + YY];
+    real yh = x[i + YY];
+    real zl = x[i + ZZ];
+    real zh = x[i + ZZ];
     i += stride;
     for (int j = 1; j < na; j++)
     {
@@ -673,8 +678,7 @@ static void combine_bounding_box_pairs(const Grid&                      grid,
         const int sc2 = grid.firstCellInColumn(i) >> 1;
         /* For odd numbers skip the last bb here */
         const int nc2 = (grid.numAtomsInColumn(i) + 3) >> (2 + 1);
-        int       c2;
-        for (c2 = sc2; c2 < sc2 + nc2; c2++)
+        for (int c2 = sc2; c2 < sc2 + nc2; c2++)
         {
 #if NBNXN_SEARCH_BB_SIMD4
             Simd4Float min_S, max_S;
@@ -691,6 +695,7 @@ static void combine_bounding_box_pairs(const Grid&                      grid,
         if (((grid.numAtomsInColumn(i) + 3) >> 2) & 1)
         {
             /* The bb count in this column is odd: duplicate the last bb */
+            int c2        = sc2 + nc2;
             bbj[c2].lower = bb[c2 * 2].lower;
             bbj[c2].upper = bb[c2 * 2].upper;
         }
@@ -717,20 +722,26 @@ static void print_bbsizes_simple(FILE* fp, const Grid& grid)
                                             / (dims.atomDensity * dims.cellSize[XX] * dims.cellSize[YY])
                                   : 0.0);
 
-    fprintf(fp, "ns bb: grid %4.2f %4.2f %4.2f abs %4.2f %4.2f %4.2f rel %4.2f %4.2f %4.2f\n",
-            dims.cellSize[XX], dims.cellSize[YY], avgCellSizeZ, ba[XX], ba[YY], ba[ZZ],
-            ba[XX] * dims.invCellSize[XX], ba[YY] * dims.invCellSize[YY],
+    fprintf(fp,
+            "ns bb: grid %4.2f %4.2f %4.2f abs %4.2f %4.2f %4.2f rel %4.2f %4.2f %4.2f\n",
+            dims.cellSize[XX],
+            dims.cellSize[YY],
+            avgCellSizeZ,
+            ba[XX],
+            ba[YY],
+            ba[ZZ],
+            ba[XX] * dims.invCellSize[XX],
+            ba[YY] * dims.invCellSize[YY],
             dims.atomDensity > 0 ? ba[ZZ] / avgCellSizeZ : 0.0);
 }
 
 /*! \brief Prints the average bb size, used for debug output */
 static void print_bbsizes_supersub(FILE* fp, const Grid& grid)
 {
-    int  ns;
     dvec ba;
 
     clear_dvec(ba);
-    ns = 0;
+    int ns = 0;
     for (int c = 0; c < grid.numCells(); c++)
     {
 #if NBNXN_BBXXXX
@@ -768,9 +779,14 @@ static void print_bbsizes_supersub(FILE* fp, const Grid& grid)
                                                * dims.cellSize[YY] * c_gpuNumClusterPerCellZ)
                                   : 0.0);
 
-    fprintf(fp, "ns bb: grid %4.2f %4.2f %4.2f abs %4.2f %4.2f %4.2f rel %4.2f %4.2f %4.2f\n",
+    fprintf(fp,
+            "ns bb: grid %4.2f %4.2f %4.2f abs %4.2f %4.2f %4.2f rel %4.2f %4.2f %4.2f\n",
             dims.cellSize[XX] / c_gpuNumClusterPerCellX,
-            dims.cellSize[YY] / c_gpuNumClusterPerCellY, avgClusterSizeZ, ba[XX], ba[YY], ba[ZZ],
+            dims.cellSize[YY] / c_gpuNumClusterPerCellY,
+            avgClusterSizeZ,
+            ba[XX],
+            ba[YY],
+            ba[ZZ],
             ba[XX] * c_gpuNumClusterPerCellX * dims.invCellSize[XX],
             ba[YY] * c_gpuNumClusterPerCellY * dims.invCellSize[YY],
             dims.atomDensity > 0 ? ba[ZZ] / avgClusterSizeZ : 0.0);
@@ -876,7 +892,11 @@ void Grid::fillCell(GridSetData*                   gridSetData,
          * Then sort_cluster_on_flag will only set the flags and the sorting
          * will not affect the atom order.
          */
-        sort_cluster_on_flag(geometry_.numAtomsICluster, atomStart, atomEnd, atinfo, atomIndices,
+        sort_cluster_on_flag(geometry_.numAtomsICluster,
+                             atomStart,
+                             atomEnd,
+                             atinfo,
+                             atomIndices,
                              flags_.data() + atomToCluster(atomStart) - cellOffset_);
     }
 
@@ -903,8 +923,13 @@ void Grid::fillCell(GridSetData*                   gridSetData,
         cells[atomIndices[at]] = at;
     }
 
-    copy_rvec_to_nbat_real(atomIndices.data() + atomStart, numAtoms, geometry_.numAtomsICluster,
-                           as_rvec_array(x.data()), nbat->XFormat, nbat->x().data(), atomStart);
+    copy_rvec_to_nbat_real(atomIndices.data() + atomStart,
+                           numAtoms,
+                           geometry_.numAtomsICluster,
+                           as_rvec_array(x.data()),
+                           nbat->XFormat,
+                           nbat->x().data(),
+                           atomStart);
 
     if (nbat->XFormat == nbatX4)
     {
@@ -917,7 +942,8 @@ void Grid::fillCell(GridSetData*                   gridSetData,
         {
             calc_bounding_box_x_x4_halves(numAtoms,
                                           nbat->x().data() + atom_to_x_index<c_packX4>(atomStart),
-                                          bb_ptr, bbj_.data() + offset * 2);
+                                          bb_ptr,
+                                          bbj_.data() + offset * 2);
         }
         else
 #endif
@@ -948,21 +974,25 @@ void Grid::fillCell(GridSetData*                   gridSetData,
         if (nbat->XFormat == nbatXYZQ)
         {
             GMX_ASSERT(bb_work_aligned != nullptr, "Must have valid aligned work structure");
-            calc_bounding_box_xxxx_simd4(numAtoms, nbat->x().data() + atomStart * nbat->xstride,
-                                         bb_work_aligned, pbb_ptr);
+            calc_bounding_box_xxxx_simd4(
+                    numAtoms, nbat->x().data() + atomStart * nbat->xstride, bb_work_aligned, pbb_ptr);
         }
         else
 #    endif
         {
-            calc_bounding_box_xxxx(numAtoms, nbat->xstride,
-                                   nbat->x().data() + atomStart * nbat->xstride, pbb_ptr);
+            calc_bounding_box_xxxx(
+                    numAtoms, nbat->xstride, nbat->x().data() + atomStart * nbat->xstride, pbb_ptr);
         }
         if (gmx_debug_at)
         {
-            fprintf(debug, "cell %4d bb %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n",
-                    atomToCluster(atomStart), pbb_ptr[0 * c_packedBoundingBoxesDimSize],
-                    pbb_ptr[3 * c_packedBoundingBoxesDimSize], pbb_ptr[1 * c_packedBoundingBoxesDimSize],
-                    pbb_ptr[4 * c_packedBoundingBoxesDimSize], pbb_ptr[2 * c_packedBoundingBoxesDimSize],
+            fprintf(debug,
+                    "cell %4d bb %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n",
+                    atomToCluster(atomStart),
+                    pbb_ptr[0 * c_packedBoundingBoxesDimSize],
+                    pbb_ptr[3 * c_packedBoundingBoxesDimSize],
+                    pbb_ptr[1 * c_packedBoundingBoxesDimSize],
+                    pbb_ptr[4 * c_packedBoundingBoxesDimSize],
+                    pbb_ptr[2 * c_packedBoundingBoxesDimSize],
                     pbb_ptr[5 * c_packedBoundingBoxesDimSize]);
         }
     }
@@ -978,9 +1008,15 @@ void Grid::fillCell(GridSetData*                   gridSetData,
         if (gmx_debug_at)
         {
             int bbo = atomToCluster(atomStart - cellOffset_ * geometry_.numAtomsPerCell);
-            fprintf(debug, "cell %4d bb %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n",
-                    atomToCluster(atomStart), bb_[bbo].lower.x, bb_[bbo].lower.y, bb_[bbo].lower.z,
-                    bb_[bbo].upper.x, bb_[bbo].upper.y, bb_[bbo].upper.z);
+            fprintf(debug,
+                    "cell %4d bb %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n",
+                    atomToCluster(atomStart),
+                    bb_[bbo].lower.x,
+                    bb_[bbo].lower.y,
+                    bb_[bbo].lower.z,
+                    bb_[bbo].upper.x,
+                    bb_[bbo].upper.y,
+                    bb_[bbo].upper.z);
         }
     }
 }
@@ -995,8 +1031,11 @@ void Grid::sortColumnsCpuGeometry(GridSetData*                   gridSetData,
 {
     if (debug)
     {
-        fprintf(debug, "cell_offset %d sorting columns %d - %d\n", cellOffset_,
-                *columnRange.begin(), *columnRange.end());
+        fprintf(debug,
+                "cell_offset %d sorting columns %d - %d\n",
+                cellOffset_,
+                *columnRange.begin(),
+                *columnRange.end());
     }
 
     const bool relevantAtomsAreWithinGridBounds = (dimensions_.maxAtomGroupRadius == 0);
@@ -1011,9 +1050,17 @@ void Grid::sortColumnsCpuGeometry(GridSetData*                   gridSetData,
         const int atomOffset = firstAtomInColumn(cxy);
 
         /* Sort the atoms within each x,y column on z coordinate */
-        sort_atoms(ZZ, FALSE, dd_zone, relevantAtomsAreWithinGridBounds,
-                   gridSetData->atomIndices.data() + atomOffset, numAtoms, x, dimensions_.lowerCorner[ZZ],
-                   1.0 / dimensions_.gridSize[ZZ], numCellsZ * numAtomsPerCell, sort_work);
+        sort_atoms(ZZ,
+                   FALSE,
+                   dd_zone,
+                   relevantAtomsAreWithinGridBounds,
+                   gridSetData->atomIndices.data() + atomOffset,
+                   numAtoms,
+                   x,
+                   dimensions_.lowerCorner[ZZ],
+                   1.0 / dimensions_.gridSize[ZZ],
+                   numCellsZ * numAtomsPerCell,
+                   sort_work);
 
         /* Fill the ncz cells in this column */
         const int firstCell  = firstCellInColumn(cxy);
@@ -1022,8 +1069,9 @@ void Grid::sortColumnsCpuGeometry(GridSetData*                   gridSetData,
         {
             const int cell = firstCell + cellZ;
 
-            const int atomOffsetCell = atomOffset + cellZ * numAtomsPerCell;
-            const int numAtomsCell = std::min(numAtomsPerCell, numAtoms - (atomOffsetCell - atomOffset));
+            const int atomOffsetCell       = atomOffset + cellZ * numAtomsPerCell;
+            const int numAtomsLeftInColumn = std::max(numAtoms - (atomOffsetCell - atomOffset), 0);
+            const int numAtomsCell         = std::min(numAtomsPerCell, numAtomsLeftInColumn);
 
             fillCell(gridSetData, nbat, atomOffsetCell, atomOffsetCell + numAtomsCell, atinfo, x, nullptr);
 
@@ -1056,14 +1104,17 @@ void Grid::sortColumnsGpuGeometry(GridSetData*                   gridSetData,
                                   const gmx::Range<int>          columnRange,
                                   gmx::ArrayRef<int>             sort_work)
 {
-    BoundingBox  bb_work_array[2];
-    BoundingBox* bb_work_aligned = reinterpret_cast<BoundingBox*>(
+    BoundingBox bb_work_array[2];
+    auto*       bb_work_aligned = reinterpret_cast<BoundingBox*>(
             (reinterpret_cast<std::size_t>(bb_work_array + 1)) & (~(static_cast<std::size_t>(15))));
 
     if (debug)
     {
-        fprintf(debug, "cell_offset %d sorting columns %d - %d\n", cellOffset_,
-                *columnRange.begin(), *columnRange.end());
+        fprintf(debug,
+                "cell_offset %d sorting columns %d - %d\n",
+                cellOffset_,
+                *columnRange.begin(),
+                *columnRange.end());
     }
 
     const bool relevantAtomsAreWithinGridBounds = (dimensions_.maxAtomGroupRadius == 0);
@@ -1090,9 +1141,17 @@ void Grid::sortColumnsGpuGeometry(GridSetData*                   gridSetData,
         const int atomOffset       = firstAtomInColumn(cxy);
 
         /* Sort the atoms within each x,y column on z coordinate */
-        sort_atoms(ZZ, FALSE, dd_zone, relevantAtomsAreWithinGridBounds,
-                   atomIndices.data() + atomOffset, numAtomsInColumn, x, dimensions_.lowerCorner[ZZ],
-                   1.0 / dimensions_.gridSize[ZZ], numCellsInColumn * numAtomsPerCell, sort_work);
+        sort_atoms(ZZ,
+                   FALSE,
+                   dd_zone,
+                   relevantAtomsAreWithinGridBounds,
+                   atomIndices.data() + atomOffset,
+                   numAtomsInColumn,
+                   x,
+                   dimensions_.lowerCorner[ZZ],
+                   1.0 / dimensions_.gridSize[ZZ],
+                   numCellsInColumn * numAtomsPerCell,
+                   sort_work);
 
         /* This loop goes over the cells and clusters along z at once */
         for (int sub_z = 0; sub_z < numCellsInColumn * c_gpuNumClusterPerCellZ; sub_z++)
@@ -1111,9 +1170,9 @@ void Grid::sortColumnsGpuGeometry(GridSetData*                   gridSetData,
                 const int numAtoms =
                         std::min(numAtomsPerCell, numAtomsInColumn - (atomOffsetZ - atomOffset));
 
-                numClusters_[cell] =
-                        std::min(c_gpuNumClusterPerCell, (numAtoms + geometry_.numAtomsICluster - 1)
-                                                                 / geometry_.numAtomsICluster);
+                numClusters_[cell] = std::min(
+                        c_gpuNumClusterPerCell,
+                        (numAtoms + geometry_.numAtomsICluster - 1) / geometry_.numAtomsICluster);
 
                 /* Store the z-boundaries of the bounding box of the cell */
                 bbcz_[cell].lower = x[atomIndices[atomOffsetZ]][ZZ];
@@ -1123,10 +1182,17 @@ void Grid::sortColumnsGpuGeometry(GridSetData*                   gridSetData,
             if (c_gpuNumClusterPerCellY > 1)
             {
                 /* Sort the atoms along y */
-                sort_atoms(YY, (sub_z & 1) != 0, dd_zone, relevantAtomsAreWithinGridBounds,
-                           atomIndices.data() + atomOffsetZ, numAtomsZ, x,
+                sort_atoms(YY,
+                           (sub_z & 1) != 0,
+                           dd_zone,
+                           relevantAtomsAreWithinGridBounds,
+                           atomIndices.data() + atomOffsetZ,
+                           numAtomsZ,
+                           x,
                            dimensions_.lowerCorner[YY] + gridY * dimensions_.cellSize[YY],
-                           dimensions_.invCellSize[YY], subdiv_z, sort_work);
+                           dimensions_.invCellSize[YY],
+                           subdiv_z,
+                           sort_work);
             }
 
             for (int sub_y = 0; sub_y < c_gpuNumClusterPerCellY; sub_y++)
@@ -1137,10 +1203,17 @@ void Grid::sortColumnsGpuGeometry(GridSetData*                   gridSetData,
                 if (c_gpuNumClusterPerCellX > 1)
                 {
                     /* Sort the atoms along x */
-                    sort_atoms(XX, ((cz * c_gpuNumClusterPerCellY + sub_y) & 1) != 0, dd_zone,
-                               relevantAtomsAreWithinGridBounds, atomIndices.data() + atomOffsetY, numAtomsY,
-                               x, dimensions_.lowerCorner[XX] + gridX * dimensions_.cellSize[XX],
-                               dimensions_.invCellSize[XX], subdiv_y, sort_work);
+                    sort_atoms(XX,
+                               ((cz * c_gpuNumClusterPerCellY + sub_y) & 1) != 0,
+                               dd_zone,
+                               relevantAtomsAreWithinGridBounds,
+                               atomIndices.data() + atomOffsetY,
+                               numAtomsY,
+                               x,
+                               dimensions_.lowerCorner[XX] + gridX * dimensions_.cellSize[XX],
+                               dimensions_.invCellSize[XX],
+                               subdiv_y,
+                               sort_work);
                 }
 
                 for (int sub_x = 0; sub_x < c_gpuNumClusterPerCellX; sub_x++)
@@ -1149,8 +1222,7 @@ void Grid::sortColumnsGpuGeometry(GridSetData*                   gridSetData,
                     const int numAtomsX =
                             std::min(subdiv_x, numAtomsInColumn - (atomOffsetX - atomOffset));
 
-                    fillCell(gridSetData, nbat, atomOffsetX, atomOffsetX + numAtomsX, atinfo, x,
-                             bb_work_aligned);
+                    fillCell(gridSetData, nbat, atomOffsetX, atomOffsetX + numAtomsX, atinfo, x, bb_work_aligned);
                 }
             }
         }
@@ -1218,11 +1290,18 @@ void Grid::calcColumnIndices(const Grid::Dimensions&        gridDims,
                     gmx_fatal(FARGS,
                               "grid cell cx %d cy %d out of range (max %d %d)\n"
                               "atom %f %f %f, grid->c0 %f %f",
-                              cx, cy, gridDims.numCells[XX], gridDims.numCells[YY], x[i][XX],
-                              x[i][YY], x[i][ZZ], gridDims.lowerCorner[XX], gridDims.lowerCorner[YY]);
+                              cx,
+                              cy,
+                              gridDims.numCells[XX],
+                              gridDims.numCells[YY],
+                              x[i][XX],
+                              x[i][YY],
+                              x[i][ZZ],
+                              gridDims.lowerCorner[XX],
+                              gridDims.lowerCorner[YY]);
                 }
 #endif
-                /* Take care of potential rouding issues */
+                /* Take care of potential rounding issues */
                 cx = std::min(cx, gridDims.numCells[XX] - 1);
                 cy = std::min(cy, gridDims.numCells[YY] - 1);
 
@@ -1299,7 +1378,7 @@ void Grid::setCellIndices(int                            ddZone,
     srcAtomBegin_ = *atomRange.begin();
     srcAtomEnd_   = *atomRange.end();
 
-    const int nthread = gmx_omp_nthreads_get(emntPairsearch);
+    const int nthread = gmx_omp_nthreads_get(ModuleMultiThread::Pairsearch);
 
     const int numAtomsPerCell = geometry_.numAtomsPerCell;
 
@@ -1340,9 +1419,15 @@ void Grid::setCellIndices(int                            ddZone,
 
     if (debug)
     {
-        fprintf(debug, "ns na_sc %d na_c %d super-cells: %d x %d y %d z %.1f maxz %d\n",
-                numAtomsPerCell, geometry_.numAtomsICluster, numCellsTotal_, dimensions_.numCells[XX],
-                dimensions_.numCells[YY], numCellsTotal_ / (static_cast<double>(numColumns())), ncz_max);
+        fprintf(debug,
+                "ns na_sc %d na_c %d super-cells: %d x %d y %d z %.1f maxz %d\n",
+                numAtomsPerCell,
+                geometry_.numAtomsICluster,
+                numCellsTotal_,
+                dimensions_.numCells[XX],
+                dimensions_.numCells[YY],
+                numCellsTotal_ / (static_cast<double>(numColumns())),
+                ncz_max);
         if (gmx_debug_at)
         {
             int i = 0;
@@ -1402,13 +1487,13 @@ void Grid::setCellIndices(int                            ddZone,
                                         ((thread + 1) * numColumns()) / nthread);
             if (geometry_.isSimple)
             {
-                sortColumnsCpuGeometry(gridSetData, ddZone, atinfo, x, nbat, columnRange,
-                                       gridWork[thread].sortBuffer);
+                sortColumnsCpuGeometry(
+                        gridSetData, ddZone, atinfo, x, nbat, columnRange, gridWork[thread].sortBuffer);
             }
             else
             {
-                sortColumnsGpuGeometry(gridSetData, ddZone, atinfo, x, nbat, columnRange,
-                                       gridWork[thread].sortBuffer);
+                sortColumnsGpuGeometry(
+                        gridSetData, ddZone, atinfo, x, nbat, columnRange, gridWork[thread].sortBuffer);
             }
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
@@ -1436,7 +1521,9 @@ void Grid::setCellIndices(int                            ddZone,
         }
         else
         {
-            fprintf(debug, "ns non-zero sub-cells: %d average atoms %.2f\n", numClustersTotal_,
+            fprintf(debug,
+                    "ns non-zero sub-cells: %d average atoms %.2f\n",
+                    numClustersTotal_,
                     atomRange.size() / static_cast<double>(numClustersTotal_));
 
             print_bbsizes_supersub(debug, *this);
index 806ee91f2bdb8826801f7d4816e6081197a7ee53..6c1a5b8b964889aecee17c0f0b89da549a153eda 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -62,9 +62,7 @@
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/range.h"
 
-struct gmx_domdec_zones_t;
 struct nbnxn_atomdata_t;
-struct nbnxn_search;
 enum class PairlistType;
 
 namespace gmx
index a2e83ddc6a5e72b94159af34902013bc5fc37e4e..3070568e74fd2ec58e510964585cd58d2b7b6e8b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,14 +57,15 @@ namespace Nbnxm
 //! Returns the number of search grids
 static int numGrids(const GridSet::DomainSetup& domainSetup)
 {
-    int numGrids;
+    // One grid for the test particle, one for the rest
+    static constexpr int sc_numGridsForTestParticleInsertion = 2;
     if (domainSetup.doTestParticleInsertion)
     {
-        numGrids = 2;
+        return sc_numGridsForTestParticleInsertion;
     }
     else
     {
-        numGrids = 1;
+        int numGrids = 1;
         for (auto haveDD : domainSetup.haveMultipleDomainsPerDim)
         {
             if (haveDD)
@@ -72,9 +73,8 @@ static int numGrids(const GridSet::DomainSetup& domainSetup)
                 numGrids *= 2;
             }
         }
+        return numGrids;
     }
-
-    return numGrids;
 }
 
 GridSet::DomainSetup::DomainSetup(const PbcType             pbcType,
@@ -132,6 +132,19 @@ void GridSet::setLocalAtomOrder()
     }
 }
 
+static int getGridOffset(gmx::ArrayRef<const Grid> grids, int gridIndex)
+{
+    if (gridIndex == 0)
+    {
+        return 0;
+    }
+    else
+    {
+        const Nbnxm::Grid& previousGrid = grids[gridIndex - 1];
+        return previousGrid.atomIndexEnd() / previousGrid.geometry().numAtomsPerCell;
+    }
+}
+
 void GridSet::putOnGrid(const matrix                   box,
                         const int                      gridIndex,
                         const rvec                     lowerCorner,
@@ -145,22 +158,11 @@ void GridSet::putOnGrid(const matrix                   box,
                         const int*                     move,
                         nbnxn_atomdata_t*              nbat)
 {
-    Nbnxm::Grid& grid = grids_[gridIndex];
-
-    int cellOffset;
-    if (gridIndex == 0)
-    {
-        cellOffset = 0;
-    }
-    else
-    {
-        const Nbnxm::Grid& previousGrid = grids_[gridIndex - 1];
-        cellOffset = previousGrid.atomIndexEnd() / previousGrid.geometry().numAtomsPerCell;
-    }
-
-    const int n = atomRange.size();
+    Nbnxm::Grid& grid               = grids_[gridIndex];
+    const int    cellOffset         = getGridOffset(grids_, gridIndex);
+    const int    n                  = atomRange.size();
+    real         maxAtomGroupRadius = NAN;
 
-    real maxAtomGroupRadius;
     if (gridIndex == 0)
     {
         copy_mat(box, box_);
@@ -193,8 +195,8 @@ void GridSet::putOnGrid(const matrix                   box,
     const int ddZone = (domainSetup_.doTestParticleInsertion ? 0 : gridIndex);
     // grid data used in GPU transfers inherits the gridset pinning policy
     auto pinPolicy = gridSetData_.cells.get_allocator().pinningPolicy();
-    grid.setDimensions(ddZone, n - numAtomsMoved, lowerCorner, upperCorner, atomDensity,
-                       maxAtomGroupRadius, haveFep_, pinPolicy);
+    grid.setDimensions(
+            ddZone, n - numAtomsMoved, lowerCorner, upperCorner, atomDensity, maxAtomGroupRadius, haveFep_, pinPolicy);
 
     for (GridWork& work : gridWork_)
     {
@@ -204,7 +206,7 @@ void GridSet::putOnGrid(const matrix                   box,
     /* Make space for the new cell indices */
     gridSetData_.cells.resize(*atomRange.end());
 
-    const int nthread = gmx_omp_nthreads_get(emntPairsearch);
+    const int nthread = gmx_omp_nthreads_get(ModuleMultiThread::Pairsearch);
     GMX_ASSERT(nthread > 0, "We expect the OpenMP thread count to be set");
 
 #pragma omp parallel for num_threads(nthread) schedule(static)
@@ -212,15 +214,23 @@ void GridSet::putOnGrid(const matrix                   box,
     {
         try
         {
-            Grid::calcColumnIndices(grid.dimensions(), updateGroupsCog, atomRange, x, ddZone, move, thread,
-                                    nthread, gridSetData_.cells, gridWork_[thread].numAtomsPerColumn);
+            Grid::calcColumnIndices(grid.dimensions(),
+                                    updateGroupsCog,
+                                    atomRange,
+                                    x,
+                                    ddZone,
+                                    move,
+                                    thread,
+                                    nthread,
+                                    gridSetData_.cells,
+                                    gridWork_[thread].numAtomsPerColumn);
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
     }
 
     /* Copy the already computed cell indices to the grid and sort, when needed */
-    grid.setCellIndices(ddZone, cellOffset, &gridSetData_, gridWork_, atomRange, atomInfo.data(), x,
-                        numAtomsMoved, nbat);
+    grid.setCellIndices(
+            ddZone, cellOffset, &gridSetData_, gridWork_, atomRange, atomInfo.data(), x, numAtomsMoved, nbat);
 
     if (gridIndex == 0)
     {
index 3e9ffe4c8a9ff7a856a1c50a543b13f16d664f79..340a673f5ee7b1fe55e713ef738129b369e5a841 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #include "grid.h"
 #include "gridsetdata.h"
 
-
+struct gmx_domdec_zones_t;
 struct nbnxn_atomdata_t;
 enum class PairlistType;
 enum class PbcType : int;
index ac176fa6cd4407fa0b98f613bed0daf0a4f4d0a5..bcc60fc1d4a39c26dd1202df5ee6e692bc06919a 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -68,7 +68,7 @@ template<int numComponentsPerElement>
 static void clearBufferFlagged(const nbnxn_atomdata_t& nbat, int outputIndex, gmx::ArrayRef<real> buffer)
 {
     gmx::ArrayRef<const gmx_bitmask_t> flags = nbat.buffer_flags;
-    gmx_bitmask_t                      our_flag;
+    gmx_bitmask_t                      our_flag; // NOLINT(cppcoreguidelines-init-variables)
     bitmask_init_bit(&our_flag, outputIndex);
 
     constexpr size_t numComponentsPerBlock = NBNXN_BUFFERFLAG_SIZE * numComponentsPerElement;
@@ -98,9 +98,7 @@ void clearForceBuffer(nbnxn_atomdata_t* nbat, int outputIndex)
 
 void clear_fshift(real* fshift)
 {
-    int i;
-
-    for (i = 0; i < SHIFTS * DIM; i++)
+    for (int i = 0; i < gmx::c_numShiftVectors * DIM; i++)
     {
         fshift[i] = 0;
     }
index aaf9bd863e04a50c198bf840f3998fc9a176165e..f84ddf3a56f68b3b4a4efe9afed979c7eefb5e5b 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +38,6 @@
 
 #include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/gmxlib/nonbonded/nb_free_energy.h"
-#include "gromacs/gmxlib/nonbonded/nb_kernel.h"
 #include "gromacs/gmxlib/nonbonded/nonbonded.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/mdlib/enerdata_utils.h"
 #include "gromacs/mdtypes/interaction_const.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/mdtypes/nblist.h"
 #include "gromacs/mdtypes/simulation_workload.h"
 #include "gromacs/nbnxm/gpu_data_mgmt.h"
 #include "gromacs/nbnxm/nbnxm.h"
 #include "gromacs/simd/simd.h"
 #include "gromacs/timing/wallcycle.h"
+#include "gromacs/utility/enumerationhelpers.h"
+#include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/real.h"
 
 #include "kernel_common.h"
 #include "nbnxm_gpu.h"
-#include "nbnxm_gpu_data_mgmt.h"
 #include "nbnxm_simd.h"
 #include "pairlistset.h"
 #include "pairlistsets.h"
@@ -134,39 +135,12 @@ static void reduceGroupEnergySimdBuffers(int numGroups, int numGroups_2log, nbnx
     }
 }
 
-/*! \brief Dispatches the non-bonded N versus M atom cluster CPU kernels.
- *
- * OpenMP parallelization is performed within this function.
- * Energy reduction, but not force and shift force reduction, is performed
- * within this function.
- *
- * \param[in]     pairlistSet   Pairlists with local or non-local interactions to compute
- * \param[in]     kernelSetup   The non-bonded kernel setup
- * \param[in,out] nbat          The atomdata for the interactions
- * \param[in]     ic            Non-bonded interaction constants
- * \param[in]     shiftVectors  The PBC shift vectors
- * \param[in]     stepWork      Flags that tell what to compute
- * \param[in]     clearF        Enum that tells if to clear the force output buffer
- * \param[out]    vCoulomb      Output buffer for Coulomb energies
- * \param[out]    vVdw          Output buffer for Van der Waals energies
- * \param[in]     wcycle        Pointer to cycle counting data structure.
- */
-static void nbnxn_kernel_cpu(const PairlistSet&         pairlistSet,
-                             const Nbnxm::KernelSetup&  kernelSetup,
-                             nbnxn_atomdata_t*          nbat,
-                             const interaction_const_t& ic,
-                             rvec*                      shiftVectors,
-                             const gmx::StepWorkload&   stepWork,
-                             int                        clearF,
-                             real*                      vCoulomb,
-                             real*                      vVdw,
-                             gmx_wallcycle*             wcycle)
+static int getCoulombKernelType(const Nbnxm::KernelSetup& kernelSetup, const interaction_const_t& ic)
 {
 
-    int coulkt;
-    if (EEL_RF(ic.eeltype) || ic.eeltype == eelCUT)
+    if (EEL_RF(ic.eeltype) || ic.eeltype == CoulombInteractionType::Cut)
     {
-        coulkt = coulktRF;
+        return coulktRF;
     }
     else
     {
@@ -174,72 +148,118 @@ static void nbnxn_kernel_cpu(const PairlistSet&         pairlistSet,
         {
             if (ic.rcoulomb == ic.rvdw)
             {
-                coulkt = coulktTAB;
+                return coulktTAB;
             }
             else
             {
-                coulkt = coulktTAB_TWIN;
+                return coulktTAB_TWIN;
             }
         }
         else
         {
             if (ic.rcoulomb == ic.rvdw)
             {
-                coulkt = coulktEWALD;
+                return coulktEWALD;
             }
             else
             {
-                coulkt = coulktEWALD_TWIN;
+                return coulktEWALD_TWIN;
             }
         }
     }
+}
 
-    const nbnxn_atomdata_t::Params& nbatParams = nbat->params();
-
-    int vdwkt = 0;
-    if (ic.vdwtype == evdwCUT)
+static int getVdwKernelType(const Nbnxm::KernelSetup&       kernelSetup,
+                            const nbnxn_atomdata_t::Params& nbatParams,
+                            const interaction_const_t&      ic)
+{
+    if (ic.vdwtype == VanDerWaalsType::Cut)
     {
         switch (ic.vdw_modifier)
         {
-            case eintmodNONE:
-            case eintmodPOTSHIFT:
-                switch (nbatParams.comb_rule)
+            case InteractionModifiers::None:
+            case InteractionModifiers::PotShift:
+                switch (nbatParams.ljCombinationRule)
                 {
-                    case ljcrGEOM: vdwkt = vdwktLJCUT_COMBGEOM; break;
-                    case ljcrLB: vdwkt = vdwktLJCUT_COMBLB; break;
-                    case ljcrNONE: vdwkt = vdwktLJCUT_COMBNONE; break;
-                    default: GMX_RELEASE_ASSERT(false, "Unknown combination rule");
+                    case LJCombinationRule::Geometric: return vdwktLJCUT_COMBGEOM;
+                    case LJCombinationRule::LorentzBerthelot: return vdwktLJCUT_COMBLB;
+                    case LJCombinationRule::None: return vdwktLJCUT_COMBNONE;
+                    default: gmx_incons("Unknown combination rule");
                 }
-                break;
-            case eintmodFORCESWITCH: vdwkt = vdwktLJFORCESWITCH; break;
-            case eintmodPOTSWITCH: vdwkt = vdwktLJPOTSWITCH; break;
-            default: GMX_RELEASE_ASSERT(false, "Unsupported VdW interaction modifier");
+            case InteractionModifiers::ForceSwitch: return vdwktLJFORCESWITCH;
+            case InteractionModifiers::PotSwitch: return vdwktLJPOTSWITCH;
+            default:
+                std::string errorMsg =
+                        gmx::formatString("Unsupported VdW interaction modifier %s (%d)",
+                                          enumValueToString(ic.vdw_modifier),
+                                          static_cast<int>(ic.vdw_modifier));
+                gmx_incons(errorMsg);
         }
     }
-    else if (ic.vdwtype == evdwPME)
+    else if (ic.vdwtype == VanDerWaalsType::Pme)
     {
-        if (ic.ljpme_comb_rule == eljpmeGEOM)
+        if (ic.ljpme_comb_rule == LongRangeVdW::Geom)
         {
-            vdwkt = vdwktLJEWALDCOMBGEOM;
+            return vdwktLJEWALDCOMBGEOM;
         }
         else
         {
-            vdwkt = vdwktLJEWALDCOMBLB;
             /* At setup we (should have) selected the C reference kernel */
             GMX_RELEASE_ASSERT(kernelSetup.kernelType == Nbnxm::KernelType::Cpu4x4_PlainC,
                                "Only the C reference nbnxn SIMD kernel supports LJ-PME with LB "
                                "combination rules");
+            return vdwktLJEWALDCOMBLB;
         }
     }
     else
     {
-        GMX_RELEASE_ASSERT(false, "Unsupported VdW interaction type");
+        std::string errorMsg = gmx::formatString("Unsupported VdW interaction type %s (%d)",
+                                                 enumValueToString(ic.vdwtype),
+                                                 static_cast<int>(ic.vdwtype));
+        gmx_incons(errorMsg);
     }
+}
+
+/*! \brief Dispatches the non-bonded N versus M atom cluster CPU kernels.
+ *
+ * OpenMP parallelization is performed within this function.
+ * Energy reduction, but not force and shift force reduction, is performed
+ * within this function.
+ *
+ * \param[in]     pairlistSet   Pairlists with local or non-local interactions to compute
+ * \param[in]     kernelSetup   The non-bonded kernel setup
+ * \param[in,out] nbat          The atomdata for the interactions
+ * \param[in]     ic            Non-bonded interaction constants
+ * \param[in]     shiftVectors  The PBC shift vectors
+ * \param[in]     stepWork      Flags that tell what to compute
+ * \param[in]     clearF        Enum that tells if to clear the force output buffer
+ * \param[out]    vCoulomb      Output buffer for Coulomb energies
+ * \param[out]    vVdw          Output buffer for Van der Waals energies
+ * \param[in]     wcycle        Pointer to cycle counting data structure.
+ */
+static void nbnxn_kernel_cpu(const PairlistSet&             pairlistSet,
+                             const Nbnxm::KernelSetup&      kernelSetup,
+                             nbnxn_atomdata_t*              nbat,
+                             const interaction_const_t&     ic,
+                             gmx::ArrayRef<const gmx::RVec> shiftVectors,
+                             const gmx::StepWorkload&       stepWork,
+                             int                            clearF,
+                             real*                          vCoulomb,
+                             real*                          vVdw,
+                             gmx_wallcycle*                 wcycle)
+{
+
+    const nbnxn_atomdata_t::Params& nbatParams = nbat->params();
+
+    const int coulkt = getCoulombKernelType(kernelSetup, ic);
+    const int vdwkt  = getVdwKernelType(kernelSetup, nbatParams, ic);
 
     gmx::ArrayRef<const NbnxnPairlistCpu> pairlists = pairlistSet.cpuLists();
 
-    int gmx_unused nthreads = gmx_omp_nthreads_get(emntNonbonded);
-    wallcycle_sub_start(wcycle, ewcsNONBONDED_CLEAR);
+    const auto* shiftVecPointer = as_rvec_array(shiftVectors.data());
+
+    int gmx_unused nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Nonbonded);
+    wallcycle_sub_start(wcycle, WallCycleSubCounter::NonbondedClear);
 #pragma omp parallel for schedule(static) num_threads(nthreads)
     for (gmx::index nb = 0; nb < pairlists.ssize(); nb++)
     {
@@ -256,8 +276,8 @@ static void nbnxn_kernel_cpu(const PairlistSet&         pairlistSet,
 
         if (nb == 0)
         {
-            wallcycle_sub_stop(wcycle, ewcsNONBONDED_CLEAR);
-            wallcycle_sub_start(wcycle, ewcsNONBONDED_KERNEL);
+            wallcycle_sub_stop(wcycle, WallCycleSubCounter::NonbondedClear);
+            wallcycle_sub_start(wcycle, WallCycleSubCounter::NonbondedKernel);
         }
 
         // TODO: Change to reference
@@ -269,16 +289,16 @@ static void nbnxn_kernel_cpu(const PairlistSet&         pairlistSet,
             switch (kernelSetup.kernelType)
             {
                 case Nbnxm::KernelType::Cpu4x4_PlainC:
-                    nbnxn_kernel_noener_ref[coulkt][vdwkt](pairlist, nbat, &ic, shiftVectors, out);
+                    nbnxn_kernel_noener_ref[coulkt][vdwkt](pairlist, nbat, &ic, shiftVecPointer, out);
                     break;
 #ifdef GMX_NBNXN_SIMD_2XNN
                 case Nbnxm::KernelType::Cpu4xN_Simd_2xNN:
-                    nbnxm_kernel_noener_simd_2xmm[coulkt][vdwkt](pairlist, nbat, &ic, shiftVectors, out);
+                    nbnxm_kernel_noener_simd_2xmm[coulkt][vdwkt](pairlist, nbat, &ic, shiftVecPointer, out);
                     break;
 #endif
 #ifdef GMX_NBNXN_SIMD_4XN
                 case Nbnxm::KernelType::Cpu4xN_Simd_4xN:
-                    nbnxm_kernel_noener_simd_4xm[coulkt][vdwkt](pairlist, nbat, &ic, shiftVectors, out);
+                    nbnxm_kernel_noener_simd_4xm[coulkt][vdwkt](pairlist, nbat, &ic, shiftVecPointer, out);
                     break;
 #endif
                 default: GMX_RELEASE_ASSERT(false, "Unsupported kernel architecture");
@@ -293,16 +313,16 @@ static void nbnxn_kernel_cpu(const PairlistSet&         pairlistSet,
             switch (kernelSetup.kernelType)
             {
                 case Nbnxm::KernelType::Cpu4x4_PlainC:
-                    nbnxn_kernel_ener_ref[coulkt][vdwkt](pairlist, nbat, &ic, shiftVectors, out);
+                    nbnxn_kernel_ener_ref[coulkt][vdwkt](pairlist, nbat, &ic, shiftVecPointer, out);
                     break;
 #ifdef GMX_NBNXN_SIMD_2XNN
                 case Nbnxm::KernelType::Cpu4xN_Simd_2xNN:
-                    nbnxm_kernel_ener_simd_2xmm[coulkt][vdwkt](pairlist, nbat, &ic, shiftVectors, out);
+                    nbnxm_kernel_ener_simd_2xmm[coulkt][vdwkt](pairlist, nbat, &ic, shiftVecPointer, out);
                     break;
 #endif
 #ifdef GMX_NBNXN_SIMD_4XN
                 case Nbnxm::KernelType::Cpu4xN_Simd_4xN:
-                    nbnxm_kernel_ener_simd_4xm[coulkt][vdwkt](pairlist, nbat, &ic, shiftVectors, out);
+                    nbnxm_kernel_ener_simd_4xm[coulkt][vdwkt](pairlist, nbat, &ic, shiftVecPointer, out);
                     break;
 #endif
                 default: GMX_RELEASE_ASSERT(false, "Unsupported kernel architecture");
@@ -319,18 +339,19 @@ static void nbnxn_kernel_cpu(const PairlistSet&         pairlistSet,
             {
                 case Nbnxm::KernelType::Cpu4x4_PlainC:
                     unrollj = c_nbnxnCpuIClusterSize;
-                    nbnxn_kernel_energrp_ref[coulkt][vdwkt](pairlist, nbat, &ic, shiftVectors, out);
+                    nbnxn_kernel_energrp_ref[coulkt][vdwkt](pairlist, nbat, &ic, shiftVecPointer, out);
                     break;
 #ifdef GMX_NBNXN_SIMD_2XNN
                 case Nbnxm::KernelType::Cpu4xN_Simd_2xNN:
                     unrollj = GMX_SIMD_REAL_WIDTH / 2;
-                    nbnxm_kernel_energrp_simd_2xmm[coulkt][vdwkt](pairlist, nbat, &ic, shiftVectors, out);
+                    nbnxm_kernel_energrp_simd_2xmm[coulkt][vdwkt](
+                            pairlist, nbat, &ic, shiftVecPointer, out);
                     break;
 #endif
 #ifdef GMX_NBNXN_SIMD_4XN
                 case Nbnxm::KernelType::Cpu4xN_Simd_4xN:
                     unrollj = GMX_SIMD_REAL_WIDTH;
-                    nbnxm_kernel_energrp_simd_4xm[coulkt][vdwkt](pairlist, nbat, &ic, shiftVectors, out);
+                    nbnxm_kernel_energrp_simd_4xm[coulkt][vdwkt](pairlist, nbat, &ic, shiftVecPointer, out);
                     break;
 #endif
                 default: GMX_RELEASE_ASSERT(false, "Unsupported kernel architecture");
@@ -354,7 +375,7 @@ static void nbnxn_kernel_cpu(const PairlistSet&         pairlistSet,
             }
         }
     }
-    wallcycle_sub_stop(wcycle, ewcsNONBONDED_KERNEL);
+    wallcycle_sub_stop(wcycle, WallCycleSubCounter::NonbondedKernel);
 
     if (stepWork.computeEnergy)
     {
@@ -370,8 +391,8 @@ static void accountFlops(t_nrnb*                    nrnb,
 {
     const bool usingGpuKernels = nbv.useGpu();
 
-    int enr_nbnxn_kernel_ljc;
-    if (EEL_RF(ic.eeltype) || ic.eeltype == eelCUT)
+    int enr_nbnxn_kernel_ljc = eNRNB;
+    if (EEL_RF(ic.eeltype) || ic.eeltype == CoulombInteractionType::Cut)
     {
         enr_nbnxn_kernel_ljc = eNR_NBNXN_LJ_RF;
     }
@@ -397,33 +418,37 @@ static void accountFlops(t_nrnb*                    nrnb,
     /* The Coulomb-only kernels are offset -eNR_NBNXN_LJ_RF+eNR_NBNXN_RF */
     inc_nrnb(nrnb, enr_nbnxn_kernel_ljc - eNR_NBNXN_LJ_RF + eNR_NBNXN_RF, pairlistSet.natpair_q_);
 
-    if (ic.vdw_modifier == eintmodFORCESWITCH)
+    if (ic.vdw_modifier == InteractionModifiers::ForceSwitch)
     {
         /* We add up the switch cost separately */
-        inc_nrnb(nrnb, eNR_NBNXN_ADD_LJ_FSW + (stepWork.computeEnergy ? 1 : 0),
+        inc_nrnb(nrnb,
+                 eNR_NBNXN_ADD_LJ_FSW + (stepWork.computeEnergy ? 1 : 0),
                  pairlistSet.natpair_ljq_ + pairlistSet.natpair_lj_);
     }
-    if (ic.vdw_modifier == eintmodPOTSWITCH)
+    if (ic.vdw_modifier == InteractionModifiers::PotSwitch)
     {
         /* We add up the switch cost separately */
-        inc_nrnb(nrnb, eNR_NBNXN_ADD_LJ_PSW + (stepWork.computeEnergy ? 1 : 0),
+        inc_nrnb(nrnb,
+                 eNR_NBNXN_ADD_LJ_PSW + (stepWork.computeEnergy ? 1 : 0),
                  pairlistSet.natpair_ljq_ + pairlistSet.natpair_lj_);
     }
-    if (ic.vdwtype == evdwPME)
+    if (ic.vdwtype == VanDerWaalsType::Pme)
     {
         /* We add up the LJ Ewald cost separately */
-        inc_nrnb(nrnb, eNR_NBNXN_ADD_LJ_EWALD + (stepWork.computeEnergy ? 1 : 0),
+        inc_nrnb(nrnb,
+                 eNR_NBNXN_ADD_LJ_EWALD + (stepWork.computeEnergy ? 1 : 0),
                  pairlistSet.natpair_ljq_ + pairlistSet.natpair_lj_);
     }
 }
 
-void nonbonded_verlet_t::dispatchNonbondedKernel(gmx::InteractionLocality   iLocality,
-                                                 const interaction_const_t& ic,
-                                                 const gmx::StepWorkload&   stepWork,
-                                                 int                        clearF,
-                                                 const t_forcerec&          fr,
-                                                 gmx_enerdata_t*            enerd,
-                                                 t_nrnb*                    nrnb)
+void nonbonded_verlet_t::dispatchNonbondedKernel(gmx::InteractionLocality       iLocality,
+                                                 const interaction_const_t&     ic,
+                                                 const gmx::StepWorkload&       stepWork,
+                                                 int                            clearF,
+                                                 gmx::ArrayRef<const gmx::RVec> shiftvec,
+                                                 gmx::ArrayRef<real> repulsionDispersionSR,
+                                                 gmx::ArrayRef<real> CoulombSR,
+                                                 t_nrnb*             nrnb) const
 {
     const PairlistSet& pairlistSet = pairlistSets().pairlistSet(iLocality);
 
@@ -432,9 +457,15 @@ void nonbonded_verlet_t::dispatchNonbondedKernel(gmx::InteractionLocality   iLoc
         case Nbnxm::KernelType::Cpu4x4_PlainC:
         case Nbnxm::KernelType::Cpu4xN_Simd_4xN:
         case Nbnxm::KernelType::Cpu4xN_Simd_2xNN:
-            nbnxn_kernel_cpu(pairlistSet, kernelSetup(), nbat.get(), ic, fr.shift_vec, stepWork,
-                             clearF, enerd->grpp.ener[egCOULSR].data(),
-                             fr.bBHAM ? enerd->grpp.ener[egBHAMSR].data() : enerd->grpp.ener[egLJSR].data(),
+            nbnxn_kernel_cpu(pairlistSet,
+                             kernelSetup(),
+                             nbat.get(),
+                             ic,
+                             shiftvec,
+                             stepWork,
+                             clearF,
+                             CoulombSR.data(),
+                             repulsionDispersionSR.data(),
                              wcycle_);
             break;
 
@@ -443,10 +474,16 @@ void nonbonded_verlet_t::dispatchNonbondedKernel(gmx::InteractionLocality   iLoc
             break;
 
         case Nbnxm::KernelType::Cpu8x8x8_PlainC:
-            nbnxn_kernel_gpu_ref(
-                    pairlistSet.gpuList(), nbat.get(), &ic, fr.shift_vec, stepWork, clearF,
-                    nbat->out[0].f, nbat->out[0].fshift.data(), enerd->grpp.ener[egCOULSR].data(),
-                    fr.bBHAM ? enerd->grpp.ener[egBHAMSR].data() : enerd->grpp.ener[egLJSR].data());
+            nbnxn_kernel_gpu_ref(pairlistSet.gpuList(),
+                                 nbat.get(),
+                                 &ic,
+                                 shiftvec,
+                                 stepWork,
+                                 clearF,
+                                 nbat->out[0].f,
+                                 nbat->out[0].fshift.data(),
+                                 CoulombSR.data(),
+                                 repulsionDispersionSR.data());
             break;
 
         default: GMX_RELEASE_ASSERT(false, "Invalid nonbonded kernel type passed!");
@@ -455,13 +492,16 @@ void nonbonded_verlet_t::dispatchNonbondedKernel(gmx::InteractionLocality   iLoc
     accountFlops(nrnb, pairlistSet, *this, ic, stepWork);
 }
 
-void nonbonded_verlet_t::dispatchFreeEnergyKernel(gmx::InteractionLocality   iLocality,
-                                                  const t_forcerec*          fr,
-                                                  rvec                       x[],
+void nonbonded_verlet_t::dispatchFreeEnergyKernel(gmx::InteractionLocality       iLocality,
+                                                  const t_forcerec&              fr,
+                                                  gmx::ArrayRef<const gmx::RVec> coords,
                                                   gmx::ForceWithShiftForces* forceWithShiftForces,
-                                                  const t_mdatoms&           mdatoms,
+                                                  gmx::ArrayRef<const real>  chargeA,
+                                                  gmx::ArrayRef<const real>  chargeB,
+                                                  gmx::ArrayRef<const int>   typeA,
+                                                  gmx::ArrayRef<const int>   typeB,
                                                   t_lambda*                  fepvals,
-                                                  gmx::ArrayRef<real const>  lambda,
+                                                  gmx::ArrayRef<const real>  lambda,
                                                   gmx_enerdata_t*            enerd,
                                                   const gmx::StepWorkload&   stepWork,
                                                   t_nrnb*                    nrnb)
@@ -491,39 +531,60 @@ void nonbonded_verlet_t::dispatchFreeEnergyKernel(gmx::InteractionLocality   iLo
         donb_flags |= GMX_NONBONDED_DO_POTENTIAL;
     }
 
-    nb_kernel_data_t kernel_data;
-    real             dvdl_nb[efptNR] = { 0 };
-    kernel_data.flags                = donb_flags;
-    kernel_data.lambda               = lambda.data();
-    kernel_data.dvdl                 = dvdl_nb;
+    gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> dvdl_nb      = { 0 };
+    int                                                             kernelFlags  = donb_flags;
+    gmx::ArrayRef<const real>                                       kernelLambda = lambda;
+    gmx::ArrayRef<real>                                             kernelDvdl   = dvdl_nb;
 
-    kernel_data.energygrp_elec = enerd->grpp.ener[egCOULSR].data();
-    kernel_data.energygrp_vdw  = enerd->grpp.ener[egLJSR].data();
+    gmx::ArrayRef<real> energygrp_elec = enerd->grpp.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR];
+    gmx::ArrayRef<real> energygrp_vdw = enerd->grpp.energyGroupPairTerms[NonBondedEnergyTerms::LJSR];
 
-    GMX_ASSERT(gmx_omp_nthreads_get(emntNonbonded) == nbl_fep.ssize(),
+    GMX_ASSERT(gmx_omp_nthreads_get(ModuleMultiThread::Nonbonded) == nbl_fep.ssize(),
                "Number of lists should be same as number of NB threads");
 
-    wallcycle_sub_start(wcycle_, ewcsNONBONDED_FEP);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::NonbondedFep);
 #pragma omp parallel for schedule(static) num_threads(nbl_fep.ssize())
     for (gmx::index th = 0; th < nbl_fep.ssize(); th++)
     {
         try
         {
-            gmx_nb_free_energy_kernel(nbl_fep[th].get(), x, forceWithShiftForces, fr, &mdatoms,
-                                      &kernel_data, nrnb);
+            gmx_nb_free_energy_kernel(*nbl_fep[th],
+                                      coords,
+                                      forceWithShiftForces,
+                                      fr.use_simd_kernels,
+                                      fr.ntype,
+                                      fr.rlist,
+                                      *fr.ic,
+                                      fr.shift_vec,
+                                      fr.nbfp,
+                                      fr.ljpme_c6grid,
+                                      chargeA,
+                                      chargeB,
+                                      typeA,
+                                      typeB,
+                                      kernelFlags,
+                                      kernelLambda,
+                                      kernelDvdl,
+                                      energygrp_elec,
+                                      energygrp_vdw,
+                                      nrnb);
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
     }
 
     if (fepvals->sc_alpha != 0)
     {
-        enerd->dvdl_nonlin[efptVDW] += dvdl_nb[efptVDW];
-        enerd->dvdl_nonlin[efptCOUL] += dvdl_nb[efptCOUL];
+        enerd->dvdl_nonlin[FreeEnergyPerturbationCouplingType::Vdw] +=
+                dvdl_nb[FreeEnergyPerturbationCouplingType::Vdw];
+        enerd->dvdl_nonlin[FreeEnergyPerturbationCouplingType::Coul] +=
+                dvdl_nb[FreeEnergyPerturbationCouplingType::Coul];
     }
     else
     {
-        enerd->dvdl_lin[efptVDW] += dvdl_nb[efptVDW];
-        enerd->dvdl_lin[efptCOUL] += dvdl_nb[efptCOUL];
+        enerd->dvdl_lin[FreeEnergyPerturbationCouplingType::Vdw] +=
+                dvdl_nb[FreeEnergyPerturbationCouplingType::Vdw];
+        enerd->dvdl_lin[FreeEnergyPerturbationCouplingType::Coul] +=
+                dvdl_nb[FreeEnergyPerturbationCouplingType::Coul];
     }
 
     /* If we do foreign lambda and we have soft-core interactions
@@ -531,18 +592,20 @@ void nonbonded_verlet_t::dispatchFreeEnergyKernel(gmx::InteractionLocality   iLo
      */
     if (fepvals->n_lambda > 0 && stepWork.computeDhdl && fepvals->sc_alpha != 0)
     {
-        real lam_i[efptNR];
-        kernel_data.flags = (donb_flags & ~(GMX_NONBONDED_DO_FORCE | GMX_NONBONDED_DO_SHIFTFORCE))
-                            | GMX_NONBONDED_DO_FOREIGNLAMBDA;
-        kernel_data.lambda         = lam_i;
-        kernel_data.dvdl           = dvdl_nb;
-        kernel_data.energygrp_elec = enerd->foreign_grpp.ener[egCOULSR].data();
-        kernel_data.energygrp_vdw  = enerd->foreign_grpp.ener[egLJSR].data();
+        gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real> lam_i;
+        kernelFlags = (donb_flags & ~(GMX_NONBONDED_DO_FORCE | GMX_NONBONDED_DO_SHIFTFORCE))
+                      | GMX_NONBONDED_DO_FOREIGNLAMBDA;
+        kernelLambda = lam_i;
+        kernelDvdl   = dvdl_nb;
+        gmx::ArrayRef<real> energygrp_elec =
+                enerd->foreign_grpp.energyGroupPairTerms[NonBondedEnergyTerms::CoulombSR];
+        gmx::ArrayRef<real> energygrp_vdw =
+                enerd->foreign_grpp.energyGroupPairTerms[NonBondedEnergyTerms::LJSR];
 
         for (gmx::index i = 0; i < 1 + enerd->foreignLambdaTerms.numLambdas(); i++)
         {
             std::fill(std::begin(dvdl_nb), std::end(dvdl_nb), 0);
-            for (int j = 0; j < efptNR; j++)
+            for (int j = 0; j < static_cast<int>(FreeEnergyPerturbationCouplingType::Count); j++)
             {
                 lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i - 1]);
             }
@@ -552,16 +615,37 @@ void nonbonded_verlet_t::dispatchFreeEnergyKernel(gmx::InteractionLocality   iLo
             {
                 try
                 {
-                    gmx_nb_free_energy_kernel(nbl_fep[th].get(), x, forceWithShiftForces, fr,
-                                              &mdatoms, &kernel_data, nrnb);
+                    gmx_nb_free_energy_kernel(*nbl_fep[th],
+                                              coords,
+                                              forceWithShiftForces,
+                                              fr.use_simd_kernels,
+                                              fr.ntype,
+                                              fr.rlist,
+                                              *fr.ic,
+                                              fr.shift_vec,
+                                              fr.nbfp,
+                                              fr.ljpme_c6grid,
+                                              chargeA,
+                                              chargeB,
+                                              typeA,
+                                              typeB,
+                                              kernelFlags,
+                                              kernelLambda,
+                                              kernelDvdl,
+                                              energygrp_elec,
+                                              energygrp_vdw,
+                                              nrnb);
                 }
                 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
             }
 
-            sum_epot(enerd->foreign_grpp, enerd->foreign_term);
-            enerd->foreignLambdaTerms.accumulate(i, enerd->foreign_term[F_EPOT],
-                                                 dvdl_nb[efptVDW] + dvdl_nb[efptCOUL]);
+            sum_epot(enerd->foreign_grpp, enerd->foreign_term.data());
+            enerd->foreignLambdaTerms.accumulate(
+                    i,
+                    enerd->foreign_term[F_EPOT],
+                    dvdl_nb[FreeEnergyPerturbationCouplingType::Vdw]
+                            + dvdl_nb[FreeEnergyPerturbationCouplingType::Coul]);
         }
     }
-    wallcycle_sub_stop(wcycle_, ewcsNONBONDED_FEP);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::NonbondedFep);
 }
index 0b25a95da821aee752c1d00278a000f7e903839a..32f70f2cea0fd35720c4c892385f49c3462f478b 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <algorithm>
 
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdtypes/interaction_const.h"
 
 static constexpr int c_clSize = c_nbnxnGpuClusterSize;
 
-void nbnxn_kernel_gpu_ref(const NbnxnPairlistGpu*    nbl,
-                          const nbnxn_atomdata_t*    nbat,
-                          const interaction_const_t* iconst,
-                          rvec*                      shift_vec,
-                          const gmx::StepWorkload&   stepWork,
-                          int                        clearF,
-                          gmx::ArrayRef<real>        f,
-                          real*                      fshift,
-                          real*                      Vc,
-                          real*                      Vvdw)
+void nbnxn_kernel_gpu_ref(const NbnxnPairlistGpu*        nbl,
+                          const nbnxn_atomdata_t*        nbat,
+                          const interaction_const_t*     iconst,
+                          gmx::ArrayRef<const gmx::RVec> shiftvec,
+                          const gmx::StepWorkload&       stepWork,
+                          int                            clearF,
+                          gmx::ArrayRef<real>            f,
+                          real*                          fshift,
+                          real*                          Vc,
+                          real*                          Vvdw)
 {
-    gmx_bool            bEwald;
-    const real*         Ftab = nullptr;
-    real                rcut2, rvdw2, rlist2;
-    int                 ntype;
-    real                facel;
-    int                 ish3;
-    int                 sci;
-    int                 cj4_ind0, cj4_ind1, cj4_ind;
-    int                 ci, cj;
-    int                 ic, jc, ia, ja, is, ifs, js, jfs, im, jm;
-    int                 n0;
-    int                 ggid;
-    real                shX, shY, shZ;
-    real                fscal, tx, ty, tz;
-    real                rinvsq;
-    real                iq;
-    real                qq, vcoul = 0, krsq, vctot;
-    int                 nti;
-    int                 tj;
-    real                rt, r, eps;
-    real                rinvsix;
-    real                Vvdwtot;
-    real                Vvdw_rep, Vvdw_disp;
-    real                ix, iy, iz, fix, fiy, fiz;
-    real                jx, jy, jz;
-    real                dx, dy, dz, rsq, rinv;
-    real                int_bit;
-    real                fexcl;
-    real                c6, c12;
+    real                fscal = NAN;
+    real                vcoul = 0;
     const nbnxn_excl_t* excl[2];
 
-    int npair_tot, npair;
-    int nhwu, nhwu_pruned;
-
     if (nbl->na_ci != c_clSize)
     {
         gmx_fatal(FARGS,
                   "The neighborlist cluster size in the GPU reference kernel is %d, expected it to "
                   "be %d",
-                  nbl->na_ci, c_clSize);
+                  nbl->na_ci,
+                  c_clSize);
     }
 
     if (clearF == enbvClearFYes)
@@ -116,59 +88,56 @@ void nbnxn_kernel_gpu_ref(const NbnxnPairlistGpu*    nbl,
         }
     }
 
-    bEwald = EEL_FULL(iconst->eeltype);
-    if (bEwald)
-    {
-        Ftab = iconst->coulombEwaldTables->tableF.data();
-    }
+    const bool bEwald = EEL_FULL(iconst->eeltype);
 
-    rcut2 = iconst->rcoulomb * iconst->rcoulomb;
-    rvdw2 = iconst->rvdw * iconst->rvdw;
+    const real rcut2 = iconst->rcoulomb * iconst->rcoulomb;
+    const real rvdw2 = iconst->rvdw * iconst->rvdw;
 
-    rlist2 = nbl->rlist * nbl->rlist;
+    const real rlist2 = nbl->rlist * nbl->rlist;
 
-    const int* type      = nbat->params().type.data();
-    facel                = iconst->epsfac;
-    const real* shiftvec = shift_vec[0];
+    const int*  type     = nbat->params().type.data();
+    const real  facel    = iconst->epsfac;
     const real* vdwparam = nbat->params().nbfp.data();
-    ntype                = nbat->params().numTypes;
+    const int   ntype    = nbat->params().numTypes;
 
     const real* x = nbat->x().data();
 
-    npair_tot   = 0;
-    nhwu        = 0;
-    nhwu_pruned = 0;
+    int npair_tot   = 0;
+    int nhwu        = 0;
+    int nhwu_pruned = 0;
 
     for (const nbnxn_sci_t& nbln : nbl->sci)
     {
-        ish3     = 3 * nbln.shift;
-        shX      = shiftvec[ish3];
-        shY      = shiftvec[ish3 + 1];
-        shZ      = shiftvec[ish3 + 2];
-        cj4_ind0 = nbln.cj4_ind_start;
-        cj4_ind1 = nbln.cj4_ind_end;
-        sci      = nbln.sci;
-        vctot    = 0;
-        Vvdwtot  = 0;
-
-        if (nbln.shift == CENTRAL && nbl->cj4[cj4_ind0].cj[0] == sci * c_nbnxnGpuNumClusterPerSupercluster)
+        const int  ish      = nbln.shift;
+        const int  ish3     = DIM * ish;
+        const real shX      = shiftvec[ish][XX];
+        const real shY      = shiftvec[ish][YY];
+        const real shZ      = shiftvec[ish][ZZ];
+        const int  cj4_ind0 = nbln.cj4_ind_start;
+        const int  cj4_ind1 = nbln.cj4_ind_end;
+        const int  sci      = nbln.sci;
+        real       vctot    = 0;
+        real       Vvdwtot  = 0;
+
+        if (nbln.shift == gmx::c_centralShiftIndex
+            && nbl->cj4[cj4_ind0].cj[0] == sci * c_nbnxnGpuNumClusterPerSupercluster)
         {
             /* we have the diagonal:
              * add the charge self interaction energy term
              */
-            for (im = 0; im < c_nbnxnGpuNumClusterPerSupercluster; im++)
+            for (int im = 0; im < c_nbnxnGpuNumClusterPerSupercluster; im++)
             {
-                ci = sci * c_nbnxnGpuNumClusterPerSupercluster + im;
-                for (ic = 0; ic < c_clSize; ic++)
+                const int ci = sci * c_nbnxnGpuNumClusterPerSupercluster + im;
+                for (int ic = 0; ic < c_clSize; ic++)
                 {
-                    ia = ci * c_clSize + ic;
-                    iq = x[ia * nbat->xstride + 3];
+                    const int ia = ci * c_clSize + ic;
+                    real      iq = x[ia * nbat->xstride + 3];
                     vctot += iq * iq;
                 }
             }
             if (!bEwald)
             {
-                vctot *= -facel * 0.5 * iconst->c_rf;
+                vctot *= -facel * 0.5 * iconst->reactionFieldShift;
             }
             else
             {
@@ -177,16 +146,16 @@ void nbnxn_kernel_gpu_ref(const NbnxnPairlistGpu*    nbl,
             }
         }
 
-        for (cj4_ind = cj4_ind0; (cj4_ind < cj4_ind1); cj4_ind++)
+        for (int cj4_ind = cj4_ind0; (cj4_ind < cj4_ind1); cj4_ind++)
         {
             excl[0] = &nbl->excl[nbl->cj4[cj4_ind].imei[0].excl_ind];
             excl[1] = &nbl->excl[nbl->cj4[cj4_ind].imei[1].excl_ind];
 
-            for (jm = 0; jm < c_nbnxnGpuJgroupSize; jm++)
+            for (int jm = 0; jm < c_nbnxnGpuJgroupSize; jm++)
             {
-                cj = nbl->cj4[cj4_ind].cj[jm];
+                const int cj = nbl->cj4[cj4_ind].cj[jm];
 
-                for (im = 0; im < c_nbnxnGpuNumClusterPerSupercluster; im++)
+                for (int im = 0; im < c_nbnxnGpuNumClusterPerSupercluster; im++)
                 {
                     /* We're only using the first imask,
                      * but here imei[1].imask is identical.
@@ -194,56 +163,54 @@ void nbnxn_kernel_gpu_ref(const NbnxnPairlistGpu*    nbl,
                     if ((nbl->cj4[cj4_ind].imei[0].imask >> (jm * c_nbnxnGpuNumClusterPerSupercluster + im))
                         & 1)
                     {
-                        gmx_bool within_rlist;
-
-                        ci = sci * c_nbnxnGpuNumClusterPerSupercluster + im;
+                        const int ci = sci * c_nbnxnGpuNumClusterPerSupercluster + im;
 
-                        within_rlist = FALSE;
-                        npair        = 0;
-                        for (ic = 0; ic < c_clSize; ic++)
+                        bool within_rlist = false;
+                        int  npair        = 0;
+                        for (int ic = 0; ic < c_clSize; ic++)
                         {
-                            ia = ci * c_clSize + ic;
+                            const int ia = ci * c_clSize + ic;
 
-                            is  = ia * nbat->xstride;
-                            ifs = ia * nbat->fstride;
-                            ix  = shX + x[is + 0];
-                            iy  = shY + x[is + 1];
-                            iz  = shZ + x[is + 2];
-                            iq  = facel * x[is + 3];
-                            nti = ntype * 2 * type[ia];
+                            const int  is  = ia * nbat->xstride;
+                            const int  ifs = ia * nbat->fstride;
+                            const real ix  = shX + x[is + 0];
+                            const real iy  = shY + x[is + 1];
+                            const real iz  = shZ + x[is + 2];
+                            const real iq  = facel * x[is + 3];
+                            const int  nti = ntype * 2 * type[ia];
 
-                            fix = 0;
-                            fiy = 0;
-                            fiz = 0;
+                            real fix = 0;
+                            real fiy = 0;
+                            real fiz = 0;
 
-                            for (jc = 0; jc < c_clSize; jc++)
+                            for (int jc = 0; jc < c_clSize; jc++)
                             {
-                                ja = cj * c_clSize + jc;
+                                const int ja = cj * c_clSize + jc;
 
-                                if (nbln.shift == CENTRAL && ci == cj && ja <= ia)
+                                if (nbln.shift == gmx::c_centralShiftIndex && ci == cj && ja <= ia)
                                 {
                                     continue;
                                 }
 
                                 constexpr int clusterPerSplit =
                                         c_nbnxnGpuClusterSize / c_nbnxnGpuClusterpairSplit;
-                                int_bit = static_cast<real>(
+                                const real int_bit = static_cast<real>(
                                         (excl[jc / clusterPerSplit]->pair[(jc & (clusterPerSplit - 1)) * c_clSize + ic]
                                          >> (jm * c_nbnxnGpuNumClusterPerSupercluster + im))
                                         & 1);
 
-                                js  = ja * nbat->xstride;
-                                jfs = ja * nbat->fstride;
-                                jx  = x[js + 0];
-                                jy  = x[js + 1];
-                                jz  = x[js + 2];
-                                dx  = ix - jx;
-                                dy  = iy - jy;
-                                dz  = iz - jz;
-                                rsq = dx * dx + dy * dy + dz * dz;
+                                int        js  = ja * nbat->xstride;
+                                int        jfs = ja * nbat->fstride;
+                                const real jx  = x[js + 0];
+                                const real jy  = x[js + 1];
+                                const real jz  = x[js + 2];
+                                const real dx  = ix - jx;
+                                const real dy  = iy - jy;
+                                const real dz  = iz - jz;
+                                real       rsq = dx * dx + dy * dy + dz * dz;
                                 if (rsq < rlist2)
                                 {
-                                    within_rlist = TRUE;
+                                    within_rlist = true;
                                 }
                                 if (rsq >= rcut2)
                                 {
@@ -258,28 +225,29 @@ void nbnxn_kernel_gpu_ref(const NbnxnPairlistGpu*    nbl,
                                 // Ensure distance do not become so small that r^-12 overflows
                                 rsq = std::max(rsq, c_nbnxnMinDistanceSquared);
 
-                                rinv   = gmx::invsqrt(rsq);
-                                rinvsq = rinv * rinv;
+                                const real rinv   = gmx::invsqrt(rsq);
+                                const real rinvsq = rinv * rinv;
 
-                                qq = iq * x[js + 3];
+                                const real qq = iq * x[js + 3];
                                 if (!bEwald)
                                 {
                                     /* Reaction-field */
-                                    krsq  = iconst->k_rf * rsq;
-                                    fscal = qq * (int_bit * rinv - 2 * krsq) * rinvsq;
+                                    const real krsq = iconst->reactionFieldCoefficient * rsq;
+                                    fscal           = qq * (int_bit * rinv - 2 * krsq) * rinvsq;
                                     if (stepWork.computeEnergy)
                                     {
-                                        vcoul = qq * (int_bit * rinv + krsq - iconst->c_rf);
+                                        vcoul = qq * (int_bit * rinv + krsq - iconst->reactionFieldShift);
                                     }
                                 }
                                 else
                                 {
-                                    r   = rsq * rinv;
-                                    rt  = r * iconst->coulombEwaldTables->scale;
-                                    n0  = static_cast<int>(rt);
-                                    eps = rt - static_cast<real>(n0);
+                                    const real  r    = rsq * rinv;
+                                    const real  rt   = r * iconst->coulombEwaldTables->scale;
+                                    const int   n0   = static_cast<int>(rt);
+                                    const real  eps  = rt - static_cast<real>(n0);
+                                    const real* Ftab = iconst->coulombEwaldTables->tableF.data();
 
-                                    fexcl = (1 - eps) * Ftab[n0] + eps * Ftab[n0 + 1];
+                                    const real fexcl = (1 - eps) * Ftab[n0] + eps * Ftab[n0 + 1];
 
                                     fscal = qq * (int_bit * rinvsq - fexcl) * rinv;
 
@@ -293,15 +261,15 @@ void nbnxn_kernel_gpu_ref(const NbnxnPairlistGpu*    nbl,
 
                                 if (rsq < rvdw2)
                                 {
-                                    tj = nti + 2 * type[ja];
+                                    const int tj = nti + 2 * type[ja];
 
                                     /* Vanilla Lennard-Jones cutoff */
-                                    c6  = vdwparam[tj];
-                                    c12 = vdwparam[tj + 1];
+                                    const real c6  = vdwparam[tj];
+                                    const real c12 = vdwparam[tj + 1];
 
-                                    rinvsix   = int_bit * rinvsq * rinvsq * rinvsq;
-                                    Vvdw_disp = c6 * rinvsix;
-                                    Vvdw_rep  = c12 * rinvsix * rinvsix;
+                                    const real rinvsix   = int_bit * rinvsq * rinvsq * rinvsq;
+                                    const real Vvdw_disp = c6 * rinvsix;
+                                    const real Vvdw_rep  = c12 * rinvsix * rinvsix;
                                     fscal += (Vvdw_rep - Vvdw_disp) * rinvsq;
 
                                     if (stepWork.computeEnergy)
@@ -316,12 +284,12 @@ void nbnxn_kernel_gpu_ref(const NbnxnPairlistGpu*    nbl,
                                     }
                                 }
 
-                                tx  = fscal * dx;
-                                ty  = fscal * dy;
-                                tz  = fscal * dz;
-                                fix = fix + tx;
-                                fiy = fiy + ty;
-                                fiz = fiz + tz;
+                                real tx = fscal * dx;
+                                real ty = fscal * dy;
+                                real tz = fscal * dz;
+                                fix     = fix + tx;
+                                fiy     = fiy + ty;
+                                fiz     = fiz + tz;
                                 f[jfs + 0] -= tx;
                                 f[jfs + 1] -= ty;
                                 f[jfs + 2] -= tz;
@@ -347,7 +315,7 @@ void nbnxn_kernel_gpu_ref(const NbnxnPairlistGpu*    nbl,
                                     nhwu_pruned++;
                                 }
 
-                                within_rlist = FALSE;
+                                within_rlist = false;
                                 npair        = 0;
                             }
                         }
@@ -358,22 +326,28 @@ void nbnxn_kernel_gpu_ref(const NbnxnPairlistGpu*    nbl,
 
         if (stepWork.computeEnergy)
         {
-            ggid       = 0;
-            Vc[ggid]   = Vc[ggid] + vctot;
-            Vvdw[ggid] = Vvdw[ggid] + Vvdwtot;
+            const int ggid = 0;
+            Vc[ggid]       = Vc[ggid] + vctot;
+            Vvdw[ggid]     = Vvdw[ggid] + Vvdwtot;
         }
     }
 
     if (debug)
     {
-        fprintf(debug, "number of half %dx%d atom pairs: %d after pruning: %d fraction %4.2f\n",
-                nbl->na_ci, nbl->na_ci, nhwu, nhwu_pruned, nhwu_pruned / static_cast<double>(nhwu));
-        fprintf(debug, "generic kernel pair interactions:            %d\n",
-                nhwu * nbl->na_ci / 2 * nbl->na_ci);
-        fprintf(debug, "generic kernel post-prune pair interactions: %d\n",
+        fprintf(debug,
+                "number of half %dx%d atom pairs: %d after pruning: %d fraction %4.2f\n",
+                nbl->na_ci,
+                nbl->na_ci,
+                nhwu,
+                nhwu_pruned,
+                nhwu_pruned / static_cast<double>(nhwu));
+        fprintf(debug, "generic kernel pair interactions:            %d\n", nhwu * nbl->na_ci / 2 * nbl->na_ci);
+        fprintf(debug,
+                "generic kernel post-prune pair interactions: %d\n",
                 nhwu_pruned * nbl->na_ci / 2 * nbl->na_ci);
         fprintf(debug, "generic kernel non-zero pair interactions:   %d\n", npair_tot);
-        fprintf(debug, "ratio non-zero/post-prune pair interactions: %4.2f\n",
+        fprintf(debug,
+                "ratio non-zero/post-prune pair interactions: %4.2f\n",
                 npair_tot / static_cast<double>(nhwu_pruned * gmx::exactDiv(nbl->na_ci, 2) * nbl->na_ci));
     }
 }
index 57570a7efb6b5f05ec8b74b47b075a35299efebd..83c59b65f073fee429ba6202cb6cd9d5ec0a2cf7 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,15 +60,15 @@ class StepWorkload;
 }
 
 //! Reference (slow) kernel for nb n vs n GPU type pair lists
-void nbnxn_kernel_gpu_ref(const NbnxnPairlistGpu*    nbl,
-                          const nbnxn_atomdata_t*    nbat,
-                          const interaction_const_t* iconst,
-                          rvec*                      shift_vec,
-                          const gmx::StepWorkload&   stepWork,
-                          int                        clearF,
-                          gmx::ArrayRef<real>        f,
-                          real*                      fshift,
-                          real*                      Vc,
-                          real*                      Vvdw);
+void nbnxn_kernel_gpu_ref(const NbnxnPairlistGpu*        nbl,
+                          const nbnxn_atomdata_t*        nbat,
+                          const interaction_const_t*     iconst,
+                          gmx::ArrayRef<const gmx::RVec> shiftvec,
+                          const gmx::StepWorkload&       stepWork,
+                          int                            clearF,
+                          gmx::ArrayRef<real>            f,
+                          real*                          fshift,
+                          real*                          Vc,
+                          real*                          Vvdw);
 
 #endif
index 242536c99f7784930b795552a39db7ceef2e188a..9d22aeddc2e041f4ce8ee64f05d1c59f0624046a 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2017 The GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,69 +107,117 @@ nbk_func_ener nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombLB_VgrpF_ref;
  * advantage in using combination rules, so we (re-)use the same kernel.
  */
 //! \{
-static p_nbk_func_noener nbnxn_kernel_noener_ref[coulktNR][vdwktNR_ref] = {
-    { nbnxn_kernel_ElecRF_VdwLJ_F_ref, nbnxn_kernel_ElecRF_VdwLJ_F_ref, nbnxn_kernel_ElecRF_VdwLJ_F_ref,
-      nbnxn_kernel_ElecRF_VdwLJFsw_F_ref, nbnxn_kernel_ElecRF_VdwLJPsw_F_ref,
-      nbnxn_kernel_ElecRF_VdwLJEwCombGeom_F_ref, nbnxn_kernel_ElecRF_VdwLJEwCombLB_F_ref },
-    { nbnxn_kernel_ElecQSTab_VdwLJ_F_ref, nbnxn_kernel_ElecQSTab_VdwLJ_F_ref, nbnxn_kernel_ElecQSTab_VdwLJ_F_ref,
-      nbnxn_kernel_ElecQSTab_VdwLJFsw_F_ref, nbnxn_kernel_ElecQSTab_VdwLJPsw_F_ref,
-      nbnxn_kernel_ElecQSTab_VdwLJEwCombGeom_F_ref, nbnxn_kernel_ElecQSTab_VdwLJEwCombLB_F_ref },
-    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_F_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_F_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_F_ref,
+static const p_nbk_func_noener nbnxn_kernel_noener_ref[coulktNR][vdwktNR_ref] = {
+    { nbnxn_kernel_ElecRF_VdwLJ_F_ref,
+      nbnxn_kernel_ElecRF_VdwLJ_F_ref,
+      nbnxn_kernel_ElecRF_VdwLJ_F_ref,
+      nbnxn_kernel_ElecRF_VdwLJFsw_F_ref,
+      nbnxn_kernel_ElecRF_VdwLJPsw_F_ref,
+      nbnxn_kernel_ElecRF_VdwLJEwCombGeom_F_ref,
+      nbnxn_kernel_ElecRF_VdwLJEwCombLB_F_ref },
+    { nbnxn_kernel_ElecQSTab_VdwLJ_F_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJ_F_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJ_F_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJFsw_F_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJPsw_F_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJEwCombGeom_F_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJEwCombLB_F_ref },
+    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_F_ref,
       nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombLB_F_ref },
-    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_F_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_F_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_F_ref,
+    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_F_ref,
       nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombLB_F_ref },
-    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_F_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_F_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_F_ref,
+    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_F_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_F_ref,
       nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombLB_F_ref }
 };
 
-static p_nbk_func_ener nbnxn_kernel_ener_ref[coulktNR][vdwktNR_ref] = {
-    { nbnxn_kernel_ElecRF_VdwLJ_VF_ref, nbnxn_kernel_ElecRF_VdwLJ_VF_ref, nbnxn_kernel_ElecRF_VdwLJ_VF_ref,
-      nbnxn_kernel_ElecRF_VdwLJFsw_VF_ref, nbnxn_kernel_ElecRF_VdwLJPsw_VF_ref,
-      nbnxn_kernel_ElecRF_VdwLJEwCombGeom_VF_ref, nbnxn_kernel_ElecRF_VdwLJEwCombLB_VF_ref },
-    { nbnxn_kernel_ElecQSTab_VdwLJ_VF_ref, nbnxn_kernel_ElecQSTab_VdwLJ_VF_ref,
-      nbnxn_kernel_ElecQSTab_VdwLJ_VF_ref, nbnxn_kernel_ElecQSTab_VdwLJFsw_VF_ref,
-      nbnxn_kernel_ElecQSTab_VdwLJPsw_VF_ref, nbnxn_kernel_ElecQSTab_VdwLJEwCombGeom_VF_ref,
+static const p_nbk_func_ener nbnxn_kernel_ener_ref[coulktNR][vdwktNR_ref] = {
+    { nbnxn_kernel_ElecRF_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecRF_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecRF_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecRF_VdwLJFsw_VF_ref,
+      nbnxn_kernel_ElecRF_VdwLJPsw_VF_ref,
+      nbnxn_kernel_ElecRF_VdwLJEwCombGeom_VF_ref,
+      nbnxn_kernel_ElecRF_VdwLJEwCombLB_VF_ref },
+    { nbnxn_kernel_ElecQSTab_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJFsw_VF_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJPsw_VF_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJEwCombGeom_VF_ref,
       nbnxn_kernel_ElecQSTab_VdwLJEwCombLB_VF_ref },
-    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_VF_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_VF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_VF_ref,
+    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_VF_ref,
       nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombLB_VF_ref },
-    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_VF_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_VF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_VF_ref,
+    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_VF_ref,
       nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombLB_VF_ref },
-    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_VF_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_VF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_VF_ref,
+    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_VF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_VF_ref,
       nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombLB_VF_ref }
 };
 
-static p_nbk_func_ener nbnxn_kernel_energrp_ref[coulktNR][vdwktNR_ref] = {
-    { nbnxn_kernel_ElecRF_VdwLJ_VgrpF_ref, nbnxn_kernel_ElecRF_VdwLJ_VgrpF_ref,
-      nbnxn_kernel_ElecRF_VdwLJ_VgrpF_ref, nbnxn_kernel_ElecRF_VdwLJFsw_VgrpF_ref,
-      nbnxn_kernel_ElecRF_VdwLJPsw_VgrpF_ref, nbnxn_kernel_ElecRF_VdwLJEwCombGeom_VgrpF_ref,
+static const p_nbk_func_ener nbnxn_kernel_energrp_ref[coulktNR][vdwktNR_ref] = {
+    { nbnxn_kernel_ElecRF_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecRF_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecRF_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecRF_VdwLJFsw_VgrpF_ref,
+      nbnxn_kernel_ElecRF_VdwLJPsw_VgrpF_ref,
+      nbnxn_kernel_ElecRF_VdwLJEwCombGeom_VgrpF_ref,
       nbnxn_kernel_ElecRF_VdwLJEwCombLB_VgrpF_ref },
-    { nbnxn_kernel_ElecQSTab_VdwLJ_VgrpF_ref, nbnxn_kernel_ElecQSTab_VdwLJ_VgrpF_ref,
-      nbnxn_kernel_ElecQSTab_VdwLJ_VgrpF_ref, nbnxn_kernel_ElecQSTab_VdwLJFsw_VgrpF_ref,
-      nbnxn_kernel_ElecQSTab_VdwLJPsw_VgrpF_ref, nbnxn_kernel_ElecQSTab_VdwLJEwCombGeom_VgrpF_ref,
+    { nbnxn_kernel_ElecQSTab_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJFsw_VgrpF_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJPsw_VgrpF_ref,
+      nbnxn_kernel_ElecQSTab_VdwLJEwCombGeom_VgrpF_ref,
       nbnxn_kernel_ElecQSTab_VdwLJEwCombLB_VgrpF_ref },
-    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_VgrpF_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_VgrpF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_VgrpF_ref,
+    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_VgrpF_ref,
       nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombLB_VgrpF_ref },
-    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_VgrpF_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_VgrpF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_VgrpF_ref,
+    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_VgrpF_ref,
       nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombLB_VgrpF_ref },
-    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_VgrpF_ref,
-      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_VgrpF_ref, nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_VgrpF_ref,
+    { nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJ_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJFsw_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJPsw_VgrpF_ref,
+      nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombGeom_VgrpF_ref,
       nbnxn_kernel_ElecQSTabTwinCut_VdwLJEwCombLB_VgrpF_ref }
 };
 //! \}
index 59d9147aa6d2d4e57026e0ee73f2cc3ac06756aa..1de0703a89d408f165cd58116d951b4713fd6311 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #endif
 
 {
-    int cj;
-#ifdef ENERGY_GROUPS
-    int egp_cj;
-#endif
-    int i;
-
-    cj = l_cj[cjind].cj;
+    const int cj = l_cj[cjind].cj;
 
 #ifdef ENERGY_GROUPS
-    egp_cj = nbatParams.energrp[cj];
+    const int egp_cj = nbatParams.energrp[cj];
 #endif
-    for (i = 0; i < UNROLLI; i++)
+    for (int i = 0; i < UNROLLI; i++)
     {
-        int ai;
-        int type_i_off;
-        int j;
-
-        ai = ci * UNROLLI + i;
+        const int ai = ci * UNROLLI + i;
 
-        type_i_off = type[ai] * ntype2;
+        const int type_i_off = type[ai] * ntype2;
 
-        for (j = 0; j < UNROLLJ; j++)
+        for (int j = 0; j < UNROLLJ; j++)
         {
-            int  aj;
-            real dx, dy, dz;
-            real rsq, rinv;
-            real rinvsq, rinvsix;
-            real c6, c12;
             real FrLJ6 = 0, FrLJ12 = 0, frLJ = 0;
-            real VLJ gmx_unused;
-#if defined LJ_FORCE_SWITCH || defined LJ_POT_SWITCH
-            real r, rsw;
-#endif
-
-#ifdef CALC_COULOMB
-            real qq;
-            real fcoul;
-#    ifdef CALC_COUL_TAB
-            real rs, frac;
-            int  ri;
-            real fexcl;
-#    endif
-#    ifdef CALC_ENERGIES
-            real vcoul;
-#    endif
-#endif
-            real fscal;
-            real fx, fy, fz;
 
             /* A multiply mask used to zero an interaction
              * when either the distance cutoff is exceeded, or
              * (if appropriate) the i and j indices are
              * unsuitable for this kind of inner loop. */
-            real skipmask;
-
 #ifdef CHECK_EXCLS
             /* A multiply mask used to zero an interaction
              * when that interaction should be excluded
              * (e.g. because of bonding). */
-            real interact = static_cast<real>((l_cj[cjind].excl >> (i * UNROLLI + j)) & 1);
+            const real interact = static_cast<real>((l_cj[cjind].excl >> (i * UNROLLI + j)) & 1);
 #    ifndef EXCL_FORCES
-            skipmask = interact;
+            real skipmask = interact;
 #    else
-            skipmask = (cj == ci_sh && j <= i) ? 0.0 : 1.0;
+            real skipmask = (cj == ci_sh && j <= i) ? 0.0 : 1.0;
 #    endif
 #else
             constexpr real interact = 1.0;
-            skipmask                = interact;
+            real           skipmask = interact;
 #endif
 
-            VLJ = 0;
+            real gmx_unused VLJ = 0;
 
-            aj = cj * UNROLLJ + j;
+            const int aj = cj * UNROLLJ + j;
 
-            dx = xi[i * XI_STRIDE + XX] - x[aj * X_STRIDE + XX];
-            dy = xi[i * XI_STRIDE + YY] - x[aj * X_STRIDE + YY];
-            dz = xi[i * XI_STRIDE + ZZ] - x[aj * X_STRIDE + ZZ];
+            const real dx = xi[i * XI_STRIDE + XX] - x[aj * X_STRIDE + XX];
+            const real dy = xi[i * XI_STRIDE + YY] - x[aj * X_STRIDE + YY];
+            const real dz = xi[i * XI_STRIDE + ZZ] - x[aj * X_STRIDE + ZZ];
 
-            rsq = dx * dx + dy * dy + dz * dz;
+            real rsq = dx * dx + dy * dy + dz * dz;
 
             /* Prepare to enforce the cut-off. */
             skipmask = (rsq >= rcut2) ? 0 : skipmask;
             npair++;
 #endif
 
-            rinv = gmx::invsqrt(rsq);
+            real rinv = gmx::invsqrt(rsq);
             /* 5 flops for invsqrt */
 
             /* Partially enforce the cut-off (and perhaps
              * the Coulomb table during lookup. */
             rinv = rinv * skipmask;
 
-            rinvsq = rinv * rinv;
+            const real rinvsq = rinv * rinv;
 
 #ifdef HALF_LJ
             if (i < UNROLLI / 2)
 #endif
             {
-                c6  = nbfp[type_i_off + type[aj] * 2];
-                c12 = nbfp[type_i_off + type[aj] * 2 + 1];
+                const real c6  = nbfp[type_i_off + type[aj] * 2];
+                const real c12 = nbfp[type_i_off + type[aj] * 2 + 1];
 
 #if defined LJ_CUT || defined LJ_FORCE_SWITCH || defined LJ_POT_SWITCH
-                rinvsix = interact * rinvsq * rinvsq * rinvsq;
-                FrLJ6   = c6 * rinvsix;
-                FrLJ12  = c12 * rinvsix * rinvsix;
-                frLJ    = FrLJ12 - FrLJ6;
+                real rinvsix = interact * rinvsq * rinvsq * rinvsq;
+                FrLJ6        = c6 * rinvsix;
+                FrLJ12       = c12 * rinvsix * rinvsix;
+                frLJ         = FrLJ12 - FrLJ6;
                 /* 7 flops for r^-2 + LJ force */
 #    if defined CALC_ENERGIES || defined LJ_POT_SWITCH
                 VLJ = (FrLJ12 + c12 * ic->repulsion_shift.cpot) / 12
 
 #if defined LJ_FORCE_SWITCH || defined LJ_POT_SWITCH
                 /* Force or potential switching from ic->rvdw_switch */
-                r   = rsq * rinv;
-                rsw = r - ic->rvdw_switch;
-                rsw = (rsw >= 0.0 ? rsw : 0.0);
+                real r   = rsq * rinv;
+                real rsw = r - ic->rvdw_switch;
+                rsw      = (rsw >= 0.0 ? rsw : 0.0);
 #endif
 #ifdef LJ_FORCE_SWITCH
                 frLJ += -c6 * (ic->dispersion_shift.c2 + ic->dispersion_shift.c3 * rsw) * rsw * rsw * r
 
 #ifdef LJ_POT_SWITCH
                 {
-                    real sw, dsw;
-
-                    sw  = 1.0 + (swV3 + (swV4 + swV5 * rsw) * rsw) * rsw * rsw * rsw;
-                    dsw = (swF2 + (swF3 + swF4 * rsw) * rsw) * rsw * rsw;
+                    const real sw  = 1.0 + (swV3 + (swV4 + swV5 * rsw) * rsw) * rsw * rsw * rsw;
+                    const real dsw = (swF2 + (swF3 + swF4 * rsw) * rsw) * rsw * rsw;
 
                     frLJ = frLJ * sw - r * VLJ * dsw;
                     VLJ *= sw;
 
 #ifdef LJ_EWALD
                 {
-                    real c6grid, rinvsix_nm, cr2, expmcr2, poly;
-#    ifdef CALC_ENERGIES
-                    real sh_mask;
-#    endif
-
 #    ifdef LJ_EWALD_COMB_GEOM
-                    c6grid = ljc[type[ai] * 2] * ljc[type[aj] * 2];
+                    const real c6grid = ljc[type[ai] * 2] * ljc[type[aj] * 2];
 #    elif defined LJ_EWALD_COMB_LB
+                    real c6grid = NAN;
                     {
-                        real sigma, sigma2, epsilon;
-
                         /* These sigma and epsilon are scaled to give 6*C6 */
-                        sigma   = ljc[type[ai] * 2] + ljc[type[aj] * 2];
-                        epsilon = ljc[type[ai] * 2 + 1] * ljc[type[aj] * 2 + 1];
+                        const real sigma   = ljc[type[ai] * 2] + ljc[type[aj] * 2];
+                        const real epsilon = ljc[type[ai] * 2 + 1] * ljc[type[aj] * 2 + 1];
 
-                        sigma2 = sigma * sigma;
-                        c6grid = epsilon * sigma2 * sigma2 * sigma2;
+                        const real sigma2 = sigma * sigma;
+                        c6grid            = epsilon * sigma2 * sigma2 * sigma2;
                     }
 #    else
 #        error "No LJ Ewald combination rule defined"
 
 #    ifdef CHECK_EXCLS
                     /* Recalculate rinvsix without exclusion mask */
-                    rinvsix_nm = rinvsq * rinvsq * rinvsq;
+                    const real rinvsix_nm = rinvsq * rinvsq * rinvsq;
 #    else
-                    rinvsix_nm = rinvsix;
+                    const real rinvsix_nm = rinvsix;
 #    endif
-                    cr2 = lje_coeff2 * rsq;
+                    const real cr2 = lje_coeff2 * rsq;
 #    if GMX_DOUBLE
-                    expmcr2 = exp(-cr2);
+                    const real expmcr2 = exp(-cr2);
 #    else
-                    expmcr2    = expf(-cr2);
+                    const real expmcr2    = expf(-cr2);
 #    endif
-                    poly = 1 + cr2 + 0.5 * cr2 * cr2;
+                    const real poly = 1 + cr2 + 0.5 * cr2 * cr2;
 
                     /* Subtract the grid force from the total LJ force */
                     frLJ += c6grid * (rinvsix_nm - expmcr2 * (rinvsix_nm * poly + lje_coeff6_6));
 #    ifdef CALC_ENERGIES
                     /* Shift should only be applied to real LJ pairs */
-                    sh_mask = lje_vc * interact;
+                    const real sh_mask = lje_vc * interact;
 
                     VLJ += c6grid / 6 * (rinvsix_nm * (1 - expmcr2 * poly) + sh_mask);
 #    endif
 #ifdef VDW_CUTOFF_CHECK
                 /* Mask for VdW cut-off shorter than Coulomb cut-off */
                 {
-                    real skipmask_rvdw;
-
-                    skipmask_rvdw = (rsq < rvdw2) ? 1.0 : 0.0;
+                    real skipmask_rvdw = (rsq < rvdw2) ? 1.0 : 0.0;
                     frLJ *= skipmask_rvdw;
 #    ifdef CALC_ENERGIES
                     VLJ *= skipmask_rvdw;
              * to the force and potential, and the easiest way
              * to do this is to zero the charges in
              * advance. */
-            qq = skipmask * qi[i] * q[aj];
+            const real qq = skipmask * qi[i] * q[aj];
 
 #    ifdef CALC_COUL_RF
-            fcoul = qq * (interact * rinv * rinvsq - k_rf2);
+            real fcoul = qq * (interact * rinv * rinvsq - k_rf2);
             /* 4 flops for RF force */
 #        ifdef CALC_ENERGIES
-            vcoul = qq * (interact * rinv + k_rf * rsq - c_rf);
+            real vcoul = qq * (interact * rinv + reactionFieldCoefficient * rsq - reactionFieldShift);
             /* 4 flops for RF energy */
 #        endif
 #    endif
 
 #    ifdef CALC_COUL_TAB
-            rs   = rsq * rinv * tab_coul_scale;
-            ri   = int(rs);
-            frac = rs - static_cast<real>(ri);
+            const real rs   = rsq * rinv * tab_coul_scale;
+            const int  ri   = int(rs);
+            const real frac = rs - static_cast<real>(ri);
 #        if !GMX_DOUBLE
             /* fexcl = F_i + frac * (F_(i+1)-F_i) */
-            fexcl = tab_coul_FDV0[ri * 4] + frac * tab_coul_FDV0[ri * 4 + 1];
+            const real fexcl = tab_coul_FDV0[ri * 4] + frac * tab_coul_FDV0[ri * 4 + 1];
 #        else
             /* fexcl = (1-frac) * F_i + frac * F_(i+1) */
-            fexcl = (1 - frac) * tab_coul_F[ri] + frac * tab_coul_F[ri + 1];
+            const real fexcl = (1 - frac) * tab_coul_F[ri] + frac * tab_coul_F[ri + 1];
 #        endif
-            fcoul = interact * rinvsq - fexcl;
+            real fcoul = interact * rinvsq - fexcl;
             /* 7 flops for float 1/r-table force */
 #        ifdef CALC_ENERGIES
 #            if !GMX_DOUBLE
-            vcoul = qq
+            real vcoul =
+                    qq
                     * (interact * (rinv - ic->sh_ewald)
                        - (tab_coul_FDV0[ri * 4 + 2] - halfsp * frac * (tab_coul_FDV0[ri * 4] + fexcl)));
             /* 7 flops for float 1/r-table energy (8 with excls) */
 #            else
-            vcoul = qq
-                    * (interact * (rinv - ic->sh_ewald)
-                       - (tab_coul_V[ri] - halfsp * frac * (tab_coul_F[ri] + fexcl)));
+            real vcoul = qq
+                         * (interact * (rinv - ic->sh_ewald)
+                            - (tab_coul_V[ri] - halfsp * frac * (tab_coul_F[ri] + fexcl)));
 #            endif
 #        endif
             fcoul *= qq * rinv;
 #endif
 
 #ifdef CALC_COULOMB
+            static constexpr bool sc_halfLJ =
 #    ifdef HALF_LJ
-            if (i < UNROLLI / 2)
-#    endif
-            {
-                fscal = frLJ * rinvsq + fcoul;
-                /* 2 flops for scalar LJ+Coulomb force */
-            }
-#    ifdef HALF_LJ
-            else
-            {
-                fscal = fcoul;
-            }
+                    true;
+#    else
+                    false;
 #    endif
+            /* 2 flops for scalar LJ+Coulomb force if !HALF_LJ || (i < UNROLLI / 2) */
+            const real fscal = (!sc_halfLJ || (i < UNROLLI / 2)) ? frLJ * rinvsq + fcoul : fcoul;
 #else
-            fscal = frLJ * rinvsq;
+            const real fscal = frLJ * rinvsq;
 #endif
-            fx = fscal * dx;
-            fy = fscal * dy;
-            fz = fscal * dz;
+            const real fx = fscal * dx;
+            const real fy = fscal * dy;
+            const real fz = fscal * dz;
 
             /* Increment i-atom force */
             fi[i * FI_STRIDE + XX] += fx;
index fe53ea2775a161aa0e91174c2f3aa144fe81b499..a74d579ec54004aaaf0fd99ee2c0262874871117 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,138 +110,88 @@ void
     real* Vc   = out->Vc.data();
 #endif
 
-    const nbnxn_cj_t* l_cj;
-    real              rcut2;
-#ifdef VDW_CUTOFF_CHECK
-    real rvdw2;
-#endif
-    int      ntype2;
-    real     facel;
-    int      ci, ci_sh;
-    int      ish, ishf;
-    gmx_bool do_LJ, half_LJ, do_coul;
-    int      cjind0, cjind1, cjind;
-
     real xi[UNROLLI * XI_STRIDE];
     real fi[UNROLLI * FI_STRIDE];
     real qi[UNROLLI];
 
-#ifdef CALC_ENERGIES
-#    ifndef ENERGY_GROUPS
-
-    real Vvdw_ci, Vc_ci;
-#    else
-    int         egp_mask;
-    int         egp_sh_i[UNROLLI];
-#    endif
-#endif
-#ifdef LJ_POT_SWITCH
-    real swV3, swV4, swV5;
-    real swF2, swF3, swF4;
-#endif
-#ifdef LJ_EWALD
-    real lje_coeff2, lje_coeff6_6;
-#    ifdef CALC_ENERGIES
-    real lje_vc;
-#    endif
-#endif
-
-#ifdef CALC_COUL_RF
-    real k_rf2;
-#    ifdef CALC_ENERGIES
-    real k_rf, c_rf;
-#    endif
-#endif
-#ifdef CALC_COUL_TAB
-#    ifdef CALC_ENERGIES
-    real halfsp;
-#    endif
-#    if !GMX_DOUBLE
-    const real* tab_coul_FDV0;
-#    else
-    const real* tab_coul_F;
-    const real gmx_unused* tab_coul_V;
-#    endif
-#endif
-
 #ifdef COUNT_PAIRS
     int npair = 0;
 #endif
 
 #ifdef LJ_POT_SWITCH
-    swV3 = ic->vdw_switch.c3;
-    swV4 = ic->vdw_switch.c4;
-    swV5 = ic->vdw_switch.c5;
-    swF2 = 3 * ic->vdw_switch.c3;
-    swF3 = 4 * ic->vdw_switch.c4;
-    swF4 = 5 * ic->vdw_switch.c5;
+    const real swV3 = ic->vdw_switch.c3;
+    const real swV4 = ic->vdw_switch.c4;
+    const real swV5 = ic->vdw_switch.c5;
+    const real swF2 = 3 * ic->vdw_switch.c3;
+    const real swF3 = 4 * ic->vdw_switch.c4;
+    const real swF4 = 5 * ic->vdw_switch.c5;
 #endif
 
     const nbnxn_atomdata_t::Params& nbatParams = nbat->params();
 
 #ifdef LJ_EWALD
-    lje_coeff2   = ic->ewaldcoeff_lj * ic->ewaldcoeff_lj;
-    lje_coeff6_6 = lje_coeff2 * lje_coeff2 * lje_coeff2 / 6.0;
+    const real lje_coeff2   = ic->ewaldcoeff_lj * ic->ewaldcoeff_lj;
+    const real lje_coeff6_6 = lje_coeff2 * lje_coeff2 * lje_coeff2 / 6.0;
 #    ifdef CALC_ENERGIES
-    lje_vc = ic->sh_lj_ewald;
+    const real lje_vc = ic->sh_lj_ewald;
 #    endif
 
     const real* ljc = nbatParams.nbfp_comb.data();
 #endif
 
 #ifdef CALC_COUL_RF
-    k_rf2 = 2 * ic->k_rf;
+    const real k_rf2 = 2 * ic->reactionFieldCoefficient;
 #    ifdef CALC_ENERGIES
-    k_rf = ic->k_rf;
-    c_rf = ic->c_rf;
+    const real reactionFieldCoefficient = ic->reactionFieldCoefficient;
+    const real reactionFieldShift       = ic->reactionFieldShift;
 #    endif
 #endif
 #ifdef CALC_COUL_TAB
     const real tab_coul_scale = ic->coulombEwaldTables->scale;
 #    ifdef CALC_ENERGIES
-    halfsp = 0.5 / tab_coul_scale;
+    const real halfsp = 0.5 / tab_coul_scale;
 #    endif
 
 #    if !GMX_DOUBLE
-    tab_coul_FDV0 = ic->coulombEwaldTables->tableFDV0.data();
+    const real* tab_coul_FDV0 = ic->coulombEwaldTables->tableFDV0.data();
 #    else
-    tab_coul_F = ic->coulombEwaldTables->tableF.data();
-    tab_coul_V = ic->coulombEwaldTables->tableV.data();
+    const real* tab_coul_F = ic->coulombEwaldTables->tableF.data();
+#        ifdef CALC_ENERGIES
+    const real* tab_coul_V = ic->coulombEwaldTables->tableV.data();
+#        endif
 #    endif
 #endif
 
 #ifdef ENERGY_GROUPS
-    egp_mask = (1 << nbatParams.neg_2log) - 1;
+    const int egp_mask = (1 << nbatParams.neg_2log) - 1;
 #endif
 
 
-    rcut2 = ic->rcoulomb * ic->rcoulomb;
+    const real rcut2 = ic->rcoulomb * ic->rcoulomb;
 #ifdef VDW_CUTOFF_CHECK
-    rvdw2 = ic->rvdw * ic->rvdw;
+    const real rvdw2 = ic->rvdw * ic->rvdw;
 #endif
 
-    ntype2               = nbatParams.numTypes * 2;
+    const int   ntype2   = nbatParams.numTypes * 2;
     const real* nbfp     = nbatParams.nbfp.data();
     const real* q        = nbatParams.q.data();
     const int*  type     = nbatParams.type.data();
-    facel                = ic->epsfac;
+    const real  facel    = ic->epsfac;
     const real* shiftvec = shift_vec[0];
     const real* x        = nbat->x().data();
 
-    l_cj = nbl->cj.data();
+    const nbnxn_cj_t* l_cj = nbl->cj.data();
 
     for (const nbnxn_ci_t& ciEntry : nbl->ci)
     {
-        int i, d;
-
-        ish = (ciEntry.shift & NBNXN_CI_SHIFT);
+        const int ish = (ciEntry.shift & NBNXN_CI_SHIFT);
         /* x, f and fshift are assumed to be stored with stride 3 */
-        ishf   = ish * DIM;
-        cjind0 = ciEntry.cj_ind_start;
-        cjind1 = ciEntry.cj_ind_end;
+        const int ishf   = ish * DIM;
+        const int cjind0 = ciEntry.cj_ind_start;
+        const int cjind1 = ciEntry.cj_ind_end;
         /* Currently only works super-cells equal to sub-cells */
-        ci    = ciEntry.ci;
-        ci_sh = (ish == CENTRAL ? ci : -1);
+        const int ci    = ciEntry.ci;
+        const int ci_sh = (ish == gmx::c_centralShiftIndex ? ci : -1);
 
         /* We have 5 LJ/C combinations, but use only three inner loops,
          * as the other combinations are unlikely and/or not much faster:
@@ -249,22 +199,23 @@ void
          * inner LJ + C      for full-LJ + C
          * inner LJ          for full-LJ + no-C / half-LJ + no-C
          */
-        do_LJ   = ((ciEntry.shift & NBNXN_CI_DO_LJ(0)) != 0);
-        do_coul = ((ciEntry.shift & NBNXN_CI_DO_COUL(0)) != 0);
-        half_LJ = (((ciEntry.shift & NBNXN_CI_HALF_LJ(0)) != 0) || !do_LJ) && do_coul;
+        const bool do_LJ   = ((ciEntry.shift & NBNXN_CI_DO_LJ(0)) != 0);
+        const bool do_coul = ((ciEntry.shift & NBNXN_CI_DO_COUL(0)) != 0);
+        const bool half_LJ = (((ciEntry.shift & NBNXN_CI_HALF_LJ(0)) != 0) || !do_LJ) && do_coul;
 #ifdef CALC_ENERGIES
 
 #    ifdef LJ_EWALD
-        gmx_bool do_self = TRUE;
+        const bool do_self = true;
 #    else
-        gmx_bool do_self = do_coul;
+        const bool do_self = do_coul;
 #    endif
 
 #    ifndef ENERGY_GROUPS
-        Vvdw_ci = 0;
-        Vc_ci   = 0;
+        real Vvdw_ci = 0;
+        real Vc_ci   = 0;
 #    else
-        for (i = 0; i < UNROLLI; i++)
+        int        egp_sh_i[UNROLLI];
+        for (int i = 0; i < UNROLLI; i++)
         {
             egp_sh_i[i] = ((nbatParams.energrp[ci] >> (i * nbatParams.neg_2log)) & egp_mask)
                           * nbatParams.nenergrp;
@@ -272,9 +223,9 @@ void
 #    endif
 #endif
 
-        for (i = 0; i < UNROLLI; i++)
+        for (int i = 0; i < UNROLLI; i++)
         {
-            for (d = 0; d < DIM; d++)
+            for (int d = 0; d < DIM; d++)
             {
                 xi[i * XI_STRIDE + d] = x[(ci * UNROLLI + i) * X_STRIDE + d] + shiftvec[ishf + d];
                 fi[i * FI_STRIDE + d] = 0;
@@ -286,29 +237,26 @@ void
 #ifdef CALC_ENERGIES
         if (do_self)
         {
-            real Vc_sub_self;
-
 #    ifdef CALC_COUL_RF
-            Vc_sub_self = 0.5 * c_rf;
+            const real Vc_sub_self = 0.5 * reactionFieldShift;
 #    endif
 #    ifdef CALC_COUL_TAB
 #        if GMX_DOUBLE
-            Vc_sub_self = 0.5 * tab_coul_V[0];
+            const real Vc_sub_self = 0.5 * tab_coul_V[0];
 #        else
-            Vc_sub_self = 0.5 * tab_coul_FDV0[2];
+            const real Vc_sub_self = 0.5 * tab_coul_FDV0[2];
 #        endif
 #    endif
 
             if (l_cj[ciEntry.cj_ind_start].cj == ci_sh)
             {
-                for (i = 0; i < UNROLLI; i++)
+                for (int i = 0; i < UNROLLI; i++)
                 {
-                    int egp_ind;
 #    ifdef ENERGY_GROUPS
-                    egp_ind = egp_sh_i[i]
-                              + ((nbatParams.energrp[ci] >> (i * nbatParams.neg_2log)) & egp_mask);
+                    const int egp_ind =
+                            egp_sh_i[i] + ((nbatParams.energrp[ci] >> (i * nbatParams.neg_2log)) & egp_mask);
 #    else
-                    egp_ind = 0;
+                    const int egp_ind = 0;
 #    endif
                     /* Coulomb self interaction */
                     Vc[egp_ind] -= qi[i] * q[ci * UNROLLI + i] * Vc_sub_self;
@@ -325,7 +273,7 @@ void
         }
 #endif /* CALC_ENERGIES */
 
-        cjind = cjind0;
+        int cjind = cjind0;
         while (cjind < cjind1 && nbl->cj[cjind].excl != 0xffff)
         {
 #define CHECK_EXCLS
@@ -374,9 +322,9 @@ void
         }
 
         /* Add accumulated i-forces to the force array */
-        for (i = 0; i < UNROLLI; i++)
+        for (int i = 0; i < UNROLLI; i++)
         {
-            for (d = 0; d < DIM; d++)
+            for (int d = 0; d < DIM; d++)
             {
                 f[(ci * UNROLLI + i) * F_STRIDE + d] += fi[i * FI_STRIDE + d];
             }
@@ -385,9 +333,9 @@ void
         if (fshift != nullptr)
         {
             /* Add i forces to shifted force list */
-            for (i = 0; i < UNROLLI; i++)
+            for (int i = 0; i < UNROLLI; i++)
             {
-                for (d = 0; d < DIM; d++)
+                for (int d = 0; d < DIM; d++)
                 {
                     fshift[ishf + d] += fi[i * FI_STRIDE + d];
                 }
index 245529cd47bd02027afb1e1314f40f9298fc6f58..8d94eaed563a01f4f252ccdc3451fe72f359263e 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/gmxassert.h"
 
 /* Prune a single NbnxnPairlistCpu entry with distance rlistInner */
-void nbnxn_kernel_prune_ref(NbnxnPairlistCpu*       nbl,
-                            const nbnxn_atomdata_t* nbat,
-                            const rvec* gmx_restrict shift_vec,
-                            real                     rlistInner)
+void nbnxn_kernel_prune_ref(NbnxnPairlistCpu*              nbl,
+                            const nbnxn_atomdata_t*        nbat,
+                            gmx::ArrayRef<const gmx::RVec> shiftvec,
+                            real                           rlistInner)
 {
     /* We avoid push_back() for efficiency reasons and resize after filling */
     nbl->ci.resize(nbl->ciOuter.size());
@@ -57,8 +58,7 @@ void nbnxn_kernel_prune_ref(NbnxnPairlistCpu*       nbl,
     const nbnxn_cj_t* gmx_restrict cjOuter = nbl->cjOuter.data();
     nbnxn_cj_t* gmx_restrict cjInner       = nbl->cj.data();
 
-    const real* gmx_restrict shiftvec = shift_vec[0];
-    const real* gmx_restrict x        = nbat->x().data();
+    const real* gmx_restrict x = nbat->x().data();
 
     const real rlist2 = rlistInner * rlistInner;
 
@@ -93,8 +93,7 @@ void nbnxn_kernel_prune_ref(NbnxnPairlistCpu*       nbl,
         {
             for (int d = 0; d < DIM; d++)
             {
-                xi[i * c_xiStride + d] =
-                        x[(ci * c_iUnroll + i) * c_xStride + d] + shiftvec[ish * DIM + d];
+                xi[i * c_xiStride + d] = x[(ci * c_iUnroll + i) * c_xStride + d] + shiftvec[ish][d];
             }
         }
 
index 1df5dc065dc40d02914648064ecffd0c7d3fd42a..d29cc4266cb0c8e567976d98786cfaca5c775efb 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 nbnxn_atomdata_t;
 struct NbnxnPairlistCpu;
 
+namespace gmx
+{
+template<typename>
+class ArrayRef;
+}
 /*! \brief Prune a single NbnxnPairlistCpu entry with distance \p rlistInner
  *
  * Reads a cluster pairlist \p nbl->ciOuter, \p nbl->cjOuter and writes
  * all cluster pairs within \p rlistInner to \p nbl->ci, \p nbl->cj.
  */
-void nbnxn_kernel_prune_ref(NbnxnPairlistCpu*       nbl,
-                            const nbnxn_atomdata_t* nbat,
-                            const rvec* gmx_restrict shift_vec,
-                            real                     rlistInner);
+void nbnxn_kernel_prune_ref(NbnxnPairlistCpu*              nbl,
+                            const nbnxn_atomdata_t*        nbat,
+                            gmx::ArrayRef<const gmx::RVec> shiftvec,
+                            real                           rlistInner);
index 6f6a2400b5ac5c333f6adffeac2fb539a627710b..34160ab8c917e3cb01a6b5433f33b996e0dd3213 100644 (file)
@@ -79,7 +79,8 @@ static inline void add_ener_grp_halves(gmx::SimdReal e_S, real* v0, real* v1, co
     for (int jj = 0; jj < (UNROLLJ / 2); jj++)
     {
         incrDualHsimd(v0 + offset_jj[jj] + jj * GMX_SIMD_REAL_WIDTH / 2,
-                      v1 + offset_jj[jj] + jj * GMX_SIMD_REAL_WIDTH / 2, e_S);
+                      v1 + offset_jj[jj] + jj * GMX_SIMD_REAL_WIDTH / 2,
+                      e_S);
     }
 }
 #endif
index 458c23b1b8fa2fe9caf8008fe23f1e141cc5d447..6d55bbe1dc6864d83f636ce384f3332ae120cbaa 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +64,6 @@
 #endif
 
 {
-    int cj, aj, ajx, ajy, ajz;
-
 #ifdef ENERGY_GROUPS
     /* Energy group indices for two atoms packed into one int */
     int egp_jj[UNROLLJ / 2];
     SimdReal c6s_j_S, c12s_j_S;
 #    endif
 
-#    if defined LJ_COMB_GEOM || defined LJ_COMB_LB || defined LJ_EWALD_GEOM
-    /* Index for loading LJ parameters, complicated when interleaving */
-    int aj2;
-#    endif
-
     /* Intermediate variables for LJ calculation */
 #    ifndef LJ_COMB_LB
     SimdReal rinvsix_S0;
 #endif /* CALC_LJ */
 
     /* j-cluster index */
-    cj = l_cj[cjind].cj;
+    const int cj = l_cj[cjind].cj;
 
     /* Atom indices (of the first atom in the cluster) */
-    aj = cj * UNROLLJ;
+    const int aj = cj * UNROLLJ;
 #if defined CALC_LJ && (defined LJ_COMB_GEOM || defined LJ_COMB_LB || defined LJ_EWALD_GEOM)
-    aj2 = aj * 2;
+    /* Index for loading LJ parameters, complicated when interleaving */
+    const int aj2 = aj * 2;
 #endif
-    ajx = aj * DIM;
-    ajy = ajx + STRIDE;
-    ajz = ajy + STRIDE;
+    const int ajx = aj * DIM;
+    const int ajy = ajx + STRIDE;
+    const int ajz = ajy + STRIDE;
 
 #ifdef CHECK_EXCLS
-    gmx_load_simd_2xnn_interactions(static_cast<int>(l_cj[cjind].excl), filter_S0, filter_S2,
-                                    &interact_S0, &interact_S2);
+    gmx_load_simd_2xnn_interactions(
+            static_cast<int>(l_cj[cjind].excl), filter_S0, filter_S2, &interact_S0, &interact_S2);
 #endif /* CHECK_EXCLS */
 
     /* load j atom coordinates */
             c6_S2 * fma(sixth_S, rinvsix_S2, v_fswitch_pr(rsw_S2, rsw2_S2, p6_6cpot_S, p6_vc3_S, p6_vc4_S));
 #            endif
     SimdReal VLJ12_S0 = c12_S0
-                        * fma(twelveth_S, rinvsix_S0 * rinvsix_S0,
+                        * fma(twelveth_S,
+                              rinvsix_S0 * rinvsix_S0,
                               v_fswitch_pr(rsw_S0, rsw2_S0, p12_12cpot_S, p12_vc3_S, p12_vc4_S));
 #            ifndef HALF_LJ
     SimdReal VLJ12_S2 = c12_S2
-                        * fma(twelveth_S, rinvsix_S2 * rinvsix_S2,
+                        * fma(twelveth_S,
+                              rinvsix_S2 * rinvsix_S2,
                               v_fswitch_pr(rsw_S2, rsw2_S2, p12_12cpot_S, p12_vc3_S, p12_vc4_S));
 #            endif
 #            undef v_fswitch_pr
          * r^-6*cexp*(1 + cr2 + cr2^2/2 + cr2^3/6) = cexp*(r^-6*poly + c^6/6)
          */
         frLJ_S0 = fma(c6grid_S0,
-                      fnma(expmcr2_S0, fma(rinvsix_nm_S0, poly_S0, lje_c6_6_S), rinvsix_nm_S0), frLJ_S0);
+                      fnma(expmcr2_S0, fma(rinvsix_nm_S0, poly_S0, lje_c6_6_S), rinvsix_nm_S0),
+                      frLJ_S0);
 #        ifndef HALF_LJ
         frLJ_S2 = fma(c6grid_S2,
-                      fnma(expmcr2_S2, fma(rinvsix_nm_S2, poly_S2, lje_c6_6_S), rinvsix_nm_S2), frLJ_S2);
+                      fnma(expmcr2_S2, fma(rinvsix_nm_S2, poly_S2, lje_c6_6_S), rinvsix_nm_S2),
+                      frLJ_S2);
 #        endif
 
 #        ifdef CALC_ENERGIES
 #            endif
 
         VLJ_S0 = fma(sixth_S * c6grid_S0,
-                     fma(rinvsix_nm_S0, fnma(expmcr2_S0, poly_S0, one_S), sh_mask_S0), VLJ_S0);
+                     fma(rinvsix_nm_S0, fnma(expmcr2_S0, poly_S0, one_S), sh_mask_S0),
+                     VLJ_S0);
 #            ifndef HALF_LJ
         VLJ_S2 = fma(sixth_S * c6grid_S2,
-                     fma(rinvsix_nm_S2, fnma(expmcr2_S2, poly_S2, one_S), sh_mask_S2), VLJ_S2);
+                     fma(rinvsix_nm_S2, fnma(expmcr2_S2, poly_S2, one_S), sh_mask_S2),
+                     VLJ_S2);
 #            endif
 #        endif /* CALC_ENERGIES */
     }
      * complicated when the i- and j-cluster size don't match.
      */
     {
-        int egps_j;
 #        if UNROLLJ == 2
-        egps_j    = nbatParams.energrp[cj >> 1];
-        egp_jj[0] = ((egps_j >> ((cj & 1) * egps_jshift)) & egps_jmask) * egps_jstride;
+        const int egps_j = nbatParams.energrp[cj >> 1];
+        egp_jj[0]        = ((egps_j >> ((cj & 1) * egps_jshift)) & egps_jmask) * egps_jstride;
 #        else
         /* We assume UNROLLI <= UNROLLJ */
-        int jdi;
-        for (jdi = 0; jdi < UNROLLJ / UNROLLI; jdi++)
+        for (int jdi = 0; jdi < UNROLLJ / UNROLLI; jdi++)
         {
-            int jj;
-            egps_j = nbatParams.energrp[cj * (UNROLLJ / UNROLLI) + jdi];
-            for (jj = 0; jj < (UNROLLI / 2); jj++)
+            const int egps_j = nbatParams.energrp[cj * (UNROLLJ / UNROLLI) + jdi];
+            for (int jj = 0; jj < (UNROLLI / 2); jj++)
             {
                 egp_jj[jdi * (UNROLLI / 2) + jj] =
                         ((egps_j >> (jj * egps_jshift)) & egps_jmask) * egps_jstride;
index 8d0c0251287981beb0936b5e35608f35e8a81279..be27518f939fae5c88fc6c377a5341b0abc41a22 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
     real* Vvdw = out->VSvdw.data();
     real* Vc   = out->VSc.data();
 #    else
-    real* Vvdw = out->Vvdw.data();
-    real* Vc   = out->Vc.data();
+    real*       Vvdw       = out->Vvdw.data();
+    real*       Vc         = out->Vc.data();
 #    endif
 #endif
 
-    const nbnxn_cj_t* l_cj;
-    int               ci, ci_sh;
-    int               ish, ish3;
-    gmx_bool          do_LJ, half_LJ, do_coul;
-    int               cjind0, cjind1, cjind;
-
-#ifdef ENERGY_GROUPS
-    int   Vstride_i;
-    int   egps_ishift, egps_imask;
-    int   egps_jshift, egps_jmask, egps_jstride;
-    int   egps_i;
-    real* vvdwtp[UNROLLI];
-    real* vctp[UNROLLI];
-#endif
-
     SimdReal shX_S;
     SimdReal shY_S;
     SimdReal shZ_S;
 
 #ifdef CALC_COUL_TAB
     /* Coulomb table variables */
-    SimdReal    invtsp_S;
-    const real* tab_coul_F;
-#    if defined CALC_ENERGIES && !defined TAB_FDV0
-    const real*                           tab_coul_V;
-#    endif
+    SimdReal invtsp_S;
 
 #    ifdef CALC_ENERGIES
     SimdReal mhalfsp_S;
 #    endif
 #endif
 #ifdef LJ_EWALD_GEOM
-    real     lj_ewaldcoeff2, lj_ewaldcoeff6_6;
     SimdReal half_S, lje_c2_S, lje_c6_6_S;
 #endif
 
     SimdReal rcvdw2_S;
 #endif
 
-    int ninner;
-
 #ifdef COUNT_PAIRS
     int npair = 0;
 #endif
 
 #ifdef CALC_COUL_RF
     /* Reaction-field constants */
-    mrc_3_S = SimdReal(-2 * ic->k_rf);
+    mrc_3_S = SimdReal(-2 * ic->reactionFieldCoefficient);
 #    ifdef CALC_ENERGIES
-    hrc_3_S  = SimdReal(ic->k_rf);
-    moh_rc_S = SimdReal(-ic->c_rf);
+    hrc_3_S  = SimdReal(ic->reactionFieldCoefficient);
+    moh_rc_S = SimdReal(-ic->reactionFieldShift);
 #    endif
 #endif
 
 #    endif
 
 #    ifdef TAB_FDV0
-    tab_coul_F = ic->coulombEwaldTables->tableFDV0.data();
+    const real* tab_coul_F = ic->coulombEwaldTables->tableFDV0.data();
 #    else
-    tab_coul_F = ic->coulombEwaldTables->tableF.data();
+    const real* tab_coul_F = ic->coulombEwaldTables->tableF.data();
 #        ifdef CALC_ENERGIES
-    tab_coul_V = ic->coulombEwaldTables->tableV.data();
+    const real* tab_coul_V = ic->coulombEwaldTables->tableV.data();
 #        endif
 #    endif
 #endif /* CALC_COUL_TAB */
 #    endif
 #endif
 #ifdef LJ_EWALD_GEOM
-    half_S           = SimdReal(0.5);
-    lj_ewaldcoeff2   = ic->ewaldcoeff_lj * ic->ewaldcoeff_lj;
-    lj_ewaldcoeff6_6 = lj_ewaldcoeff2 * lj_ewaldcoeff2 * lj_ewaldcoeff2 / 6;
-    lje_c2_S         = SimdReal(lj_ewaldcoeff2);
-    lje_c6_6_S       = SimdReal(lj_ewaldcoeff6_6);
+    half_S                      = SimdReal(0.5);
+    const real lj_ewaldcoeff2   = ic->ewaldcoeff_lj * ic->ewaldcoeff_lj;
+    const real lj_ewaldcoeff6_6 = lj_ewaldcoeff2 * lj_ewaldcoeff2 * lj_ewaldcoeff2 / 6;
+    lje_c2_S                    = SimdReal(lj_ewaldcoeff2);
+    lje_c6_6_S                  = SimdReal(lj_ewaldcoeff6_6);
 #    ifdef CALC_ENERGIES
     /* Determine the grid potential at the cut-off */
     SimdReal lje_vc_S = SimdReal(ic->sh_lj_ewald);
 #endif /* FIX_LJ_C */
 
 #ifdef ENERGY_GROUPS
-    egps_ishift  = nbatParams.neg_2log;
-    egps_imask   = (1 << egps_ishift) - 1;
-    egps_jshift  = 2 * nbatParams.neg_2log;
-    egps_jmask   = (1 << egps_jshift) - 1;
-    egps_jstride = (UNROLLJ >> 1) * UNROLLJ;
+    const int egps_ishift  = nbatParams.neg_2log;
+    const int egps_imask   = (1 << egps_ishift) - 1;
+    const int egps_jshift  = 2 * nbatParams.neg_2log;
+    const int egps_jmask   = (1 << egps_jshift) - 1;
+    const int egps_jstride = (UNROLLJ >> 1) * UNROLLJ;
     /* Major division is over i-particle energy groups, determine the stride */
-    Vstride_i = nbatParams.nenergrp * (1 << nbatParams.neg_2log) * egps_jstride;
+    const int Vstride_i = nbatParams.nenergrp * (1 << nbatParams.neg_2log) * egps_jstride;
 #endif
 
-    l_cj = nbl->cj.data();
+    const nbnxn_cj_t* l_cj = nbl->cj.data();
 
-    ninner = 0;
+    int ninner = 0;
     for (const nbnxn_ci_t& ciEntry : nbl->ci)
     {
-        ish    = (ciEntry.shift & NBNXN_CI_SHIFT);
-        ish3   = ish * 3;
-        cjind0 = ciEntry.cj_ind_start;
-        cjind1 = ciEntry.cj_ind_end;
-        ci     = ciEntry.ci;
-        ci_sh  = (ish == CENTRAL ? ci : -1);
+        const int ish    = (ciEntry.shift & NBNXN_CI_SHIFT);
+        const int ish3   = ish * 3;
+        const int cjind0 = ciEntry.cj_ind_start;
+        const int cjind1 = ciEntry.cj_ind_end;
+        const int ci     = ciEntry.ci;
+        const int ci_sh  = (ish == gmx::c_centralShiftIndex ? ci : -1);
 
         shX_S = SimdReal(shiftvec[ish3]);
         shY_S = SimdReal(shiftvec[ish3 + 1]);
          * inner LJ + C      for full-LJ + C
          * inner LJ          for full-LJ + no-C / half-LJ + no-C
          */
-        do_LJ   = ((ciEntry.shift & NBNXN_CI_DO_LJ(0)) != 0);
-        do_coul = ((ciEntry.shift & NBNXN_CI_DO_COUL(0)) != 0);
-        half_LJ = (((ciEntry.shift & NBNXN_CI_HALF_LJ(0)) != 0) || !do_LJ) && do_coul;
+        const bool do_LJ   = ((ciEntry.shift & NBNXN_CI_DO_LJ(0)) != 0);
+        const bool do_coul = ((ciEntry.shift & NBNXN_CI_DO_COUL(0)) != 0);
+        const bool half_LJ = (((ciEntry.shift & NBNXN_CI_HALF_LJ(0)) != 0) || !do_LJ) && do_coul;
 
 #ifdef ENERGY_GROUPS
-        egps_i = nbatParams.energrp[ci];
+        const int egps_i = nbatParams.energrp[ci];
+        real*     vvdwtp[UNROLLI];
+        real*     vctp[UNROLLI];
         {
-            int ia, egp_ia;
-
-            for (ia = 0; ia < UNROLLI; ia++)
+            for (int ia = 0; ia < UNROLLI; ia++)
             {
-                egp_ia     = (egps_i >> (ia * egps_ishift)) & egps_imask;
+                int egp_ia = (egps_i >> (ia * egps_ishift)) & egps_imask;
                 vvdwtp[ia] = Vvdw + egp_ia * Vstride_i;
                 vctp[ia]   = Vc + egp_ia * Vstride_i;
             }
             {
                 if (do_coul)
                 {
-                    real Vc_sub_self;
-                    int  ia;
-
 #    ifdef CALC_COUL_RF
-                    Vc_sub_self = 0.5 * ic->c_rf;
+                    const real Vc_sub_self = 0.5 * ic->reactionFieldShift;
 #    endif
 #    ifdef CALC_COUL_TAB
 #        ifdef TAB_FDV0
-                    Vc_sub_self = 0.5 * tab_coul_F[2];
+                    const real Vc_sub_self = 0.5 * tab_coul_F[2];
 #        else
-                    Vc_sub_self = 0.5 * tab_coul_V[0];
+                    const real Vc_sub_self = 0.5 * tab_coul_V[0];
 #        endif
 #    endif
 #    ifdef CALC_COUL_EWALD
                     /* beta/sqrt(pi) */
-                    Vc_sub_self = 0.5 * ic->ewaldcoeff_q * M_2_SQRTPI;
+                    const real Vc_sub_self = 0.5 * ic->ewaldcoeff_q * M_2_SQRTPI;
 #    endif
 
-                    for (ia = 0; ia < UNROLLI; ia++)
+                    for (int ia = 0; ia < UNROLLI; ia++)
                     {
-                        real qi;
-
-                        qi = q[sci + ia];
+                        const real qi = q[sci + ia];
 #    ifdef ENERGY_GROUPS
                         vctp[ia][((egps_i >> (ia * egps_ishift)) & egps_imask) * egps_jstride]
 #    else
 
 #    ifdef LJ_EWALD_GEOM
                 {
-                    int ia;
-
-                    for (ia = 0; ia < UNROLLI; ia++)
+                    for (int ia = 0; ia < UNROLLI; ia++)
                     {
-                        real c6_i;
-
-                        c6_i = nbatParams.nbfp[nbatParams.type[sci + ia] * (nbatParams.numTypes + 1) * 2]
-                               / 6;
+                        const real c6_i =
+                                nbatParams.nbfp[nbatParams.type[sci + ia] * (nbatParams.numTypes + 1) * 2]
+                                / 6;
 #        ifdef ENERGY_GROUPS
                         vvdwtp[ia][((egps_i >> (ia * egps_ishift)) & egps_imask) * egps_jstride]
 #        else
         fiz_S0 = setZero();
         fiz_S2 = setZero();
 
-        cjind = cjind0;
+        int cjind = cjind0;
 
         /* Currently all kernels use (at least half) LJ */
 #define CALC_LJ
index 3787909e12c21ea4ae4126700fef653ac4d2ff39..eab55185f00ca913e425502c662ecf2593dac4fb 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #endif
 
 /* Prune a single nbnxn_pairtlist_t entry with distance rlistInner */
-void nbnxn_kernel_prune_2xnn(NbnxnPairlistCpu*       nbl,
-                             const nbnxn_atomdata_t* nbat,
-                             const rvec* gmx_restrict shift_vec,
-                             real                     rlistInner)
+void nbnxn_kernel_prune_2xnn(NbnxnPairlistCpu*              nbl,
+                             const nbnxn_atomdata_t*        nbat,
+                             gmx::ArrayRef<const gmx::RVec> shiftvec,
+                             real                           rlistInner)
 {
 #ifdef GMX_NBNXN_SIMD_2XNN
     using namespace gmx;
@@ -66,8 +67,7 @@ void nbnxn_kernel_prune_2xnn(NbnxnPairlistCpu*       nbl,
     const nbnxn_cj_t* gmx_restrict cjOuter = nbl->cjOuter.data();
     nbnxn_cj_t* gmx_restrict cjInner       = nbl->cj.data();
 
-    const real* gmx_restrict shiftvec = shift_vec[0];
-    const real* gmx_restrict x        = nbat->x().data();
+    const real* gmx_restrict x = nbat->x().data();
 
     const SimdReal rlist2_S(rlistInner * rlistInner);
 
@@ -85,13 +85,12 @@ void nbnxn_kernel_prune_2xnn(NbnxnPairlistCpu*       nbl,
         ciInner[nciInner].cj_ind_start = ncjInner;
 
         /* Extract shift data */
-        int ish  = (ciEntry->shift & NBNXN_CI_SHIFT);
-        int ish3 = ish * 3;
-        int ci   = ciEntry->ci;
+        int ish = (ciEntry->shift & NBNXN_CI_SHIFT);
+        int ci  = ciEntry->ci;
 
-        SimdReal shX_S = SimdReal(shiftvec[ish3]);
-        SimdReal shY_S = SimdReal(shiftvec[ish3 + 1]);
-        SimdReal shZ_S = SimdReal(shiftvec[ish3 + 2]);
+        SimdReal shX_S = SimdReal(shiftvec[ish][XX]);
+        SimdReal shY_S = SimdReal(shiftvec[ish][YY]);
+        SimdReal shZ_S = SimdReal(shiftvec[ish][ZZ]);
 
 #    if UNROLLJ <= 4
         int scix = ci * STRIDE * DIM;
@@ -171,7 +170,7 @@ void nbnxn_kernel_prune_2xnn(NbnxnPairlistCpu*       nbl,
 
     GMX_UNUSED_VALUE(nbl);
     GMX_UNUSED_VALUE(nbat);
-    GMX_UNUSED_VALUE(shift_vec);
+    GMX_UNUSED_VALUE(shiftvec);
     GMX_UNUSED_VALUE(rlistInner);
 
 #endif /* GMX_NBNXN_SIMD_2XNN */
index ce2b8780301852a1b6bf08c7d57c40d6d294c9da..9abafd8b21dba8d1d15d8d6e0a5f6b5786b41104 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 nbnxn_atomdata_t;
 struct NbnxnPairlistCpu;
 
+namespace gmx
+{
+template<typename>
+class ArrayRef;
+}
+
 /*! \brief Prune a single NbnxnPairlistCpu entry with distance \p rlistInner
  *
  * Reads a cluster pairlist \p nbl->ciOuter, \p nbl->cjOuter and writes
  * all cluster pairs within \p rlistInner to \p nbl->ci, \p nbl->cj.
  */
-void nbnxn_kernel_prune_2xnn(NbnxnPairlistCpu*       nbl,
-                             const nbnxn_atomdata_t* nbat,
-                             const rvec* gmx_restrict shift_vec,
-                             real                     rlistInner);
+void nbnxn_kernel_prune_2xnn(NbnxnPairlistCpu*              nbl,
+                             const nbnxn_atomdata_t*        nbat,
+                             gmx::ArrayRef<const gmx::RVec> shift_vec,
+                             real                           rlistInner);
index 4f18775a4b92ca0aa2d376b62099ce3bf964ecdf..30cff8abe7a23d571b2f7feeb5d60f181b24bc01 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2019 by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +143,7 @@ nbk_func_ener nbnxm_kernel_ElecEwTwinCut_VdwLJEwCombGeom_VgrpF_2xmm;
  * The minor index of the array goes over both the LJ combination rules,
  * which is only supported by plain cut-off, and the LJ switch/PME functions.
  */
-static p_nbk_func_noener nbnxm_kernel_noener_simd_2xmm[coulktNR][vdwktNR] = {
+static const p_nbk_func_noener nbnxm_kernel_noener_simd_2xmm[coulktNR][vdwktNR] = {
     {
             nbnxm_kernel_ElecRF_VdwLJCombGeom_F_2xmm,
             nbnxm_kernel_ElecRF_VdwLJCombLB_F_2xmm,
@@ -185,7 +186,7 @@ static p_nbk_func_noener nbnxm_kernel_noener_simd_2xmm[coulktNR][vdwktNR] = {
     },
 };
 
-static p_nbk_func_ener nbnxm_kernel_ener_simd_2xmm[coulktNR][vdwktNR] = {
+static const p_nbk_func_ener nbnxm_kernel_ener_simd_2xmm[coulktNR][vdwktNR] = {
     {
             nbnxm_kernel_ElecRF_VdwLJCombGeom_VF_2xmm,
             nbnxm_kernel_ElecRF_VdwLJCombLB_VF_2xmm,
@@ -228,7 +229,7 @@ static p_nbk_func_ener nbnxm_kernel_ener_simd_2xmm[coulktNR][vdwktNR] = {
     },
 };
 
-static p_nbk_func_ener nbnxm_kernel_energrp_simd_2xmm[coulktNR][vdwktNR] = {
+static const p_nbk_func_ener nbnxm_kernel_energrp_simd_2xmm[coulktNR][vdwktNR] = {
     {
             nbnxm_kernel_ElecRF_VdwLJCombGeom_VgrpF_2xmm,
             nbnxm_kernel_ElecRF_VdwLJCombLB_VgrpF_2xmm,
index 3b4dca5715ef68de3cfee912e84d704e94230c87..1ad55177eed52207754c23dbf118f27df7180944 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,13 +76,12 @@ static_assert(UNROLLI == c_nbnxnCpuIClusterSize, "UNROLLI should match the i-clu
 static inline void add_ener_grp(gmx::SimdReal e_S, real* v, const int* offset_jj)
 {
     using namespace gmx;
-    int jj;
 
     /* We need to balance the number of store operations with
      * the rapidly increases number of combinations of energy groups.
      * We add to a temporary buffer for 1 i-group vs 2 j-groups.
      */
-    for (jj = 0; jj < (UNROLLJ / 2); jj++)
+    for (int jj = 0; jj < (UNROLLJ / 2); jj++)
     {
         SimdReal v_S;
 
index 01646f3b04dabfc41239c09bbed8d2e5f5f17de7..bd73f8db4e2cfd1b3b16fec04b280048a0b8c4bf 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +57,6 @@
 #    endif
 
 {
-    int cj, ajx, ajy, ajz;
-    int gmx_unused aj;
 
 #    ifdef ENERGY_GROUPS
     /* Energy group indices for two atoms packed into one int */
     SimdReal c6s_j_S, c12s_j_S;
 #        endif
 
-#        if defined LJ_COMB_GEOM || defined LJ_COMB_LB || defined LJ_EWALD_GEOM
-    /* Index for loading LJ parameters, complicated when interleaving */
-    int aj2;
-#        endif
-
     /* Intermediate variables for LJ calculation */
 #        ifndef LJ_COMB_LB
     SimdReal rinvsix_S0;
 #    endif /* CALC_LJ */
 
     /* j-cluster index */
-    cj = l_cj[cjind].cj;
+    const int cj = l_cj[cjind].cj;
 
     /* Atom indices (of the first atom in the cluster) */
-    aj = cj * UNROLLJ;
+    const int   aj = cj * UNROLLJ;
 #    if defined CALC_LJ && (defined LJ_COMB_GEOM || defined LJ_COMB_LB || defined LJ_EWALD_GEOM)
+    /* Index for loading LJ parameters, complicated when interleaving */
 #        if UNROLLJ == STRIDE
-    aj2 = aj * 2;
+    const int aj2 = aj * 2;
 #        else
-    aj2 = (cj >> 1) * 2 * STRIDE + (cj & 1) * UNROLLJ;
+    const int aj2 = (cj >> 1) * 2 * STRIDE + (cj & 1) * UNROLLJ;
 #        endif
 #    endif
 #    if UNROLLJ == STRIDE
-    ajx = aj * DIM;
+    const int ajx = aj * DIM;
 #    else
-    ajx = (cj >> 1) * DIM * STRIDE + (cj & 1) * UNROLLJ;
+    const int ajx = (cj >> 1) * DIM * STRIDE + (cj & 1) * UNROLLJ;
 #    endif
-    ajy = ajx + STRIDE;
-    ajz = ajy + STRIDE;
+    const int ajy = ajx + STRIDE;
+    const int ajz = ajy + STRIDE;
 
 #    ifdef CHECK_EXCLS
-    gmx_load_simd_4xn_interactions(static_cast<int>(l_cj[cjind].excl), filter_S0, filter_S1,
-                                   filter_S2, filter_S3, nbat->simdMasks.interaction_array.data(),
-                                   &interact_S0, &interact_S1, &interact_S2, &interact_S3);
+    gmx_load_simd_4xn_interactions(static_cast<int>(l_cj[cjind].excl),
+                                   filter_S0,
+                                   filter_S1,
+                                   filter_S2,
+                                   filter_S3,
+                                   nbat->simdMasks.interaction_array.data(),
+                                   &interact_S0,
+                                   &interact_S1,
+                                   &interact_S2,
+                                   &interact_S3);
 #    endif /* CHECK_EXCLS */
 
     /* load j atom coordinates */
             c6_S3 * fma(sixth_S, rinvsix_S3, v_fswitch_r(rsw_S3, rsw2_S3, p6_6cpot_S, p6_vc3_S, p6_vc4_S));
 #                endif
     SimdReal VLJ12_S0 = c12_S0
-                        * fma(twelveth_S, rinvsix_S0 * rinvsix_S0,
+                        * fma(twelveth_S,
+                              rinvsix_S0 * rinvsix_S0,
                               v_fswitch_r(rsw_S0, rsw2_S0, p12_12cpot_S, p12_vc3_S, p12_vc4_S));
     SimdReal VLJ12_S1 = c12_S1
-                        * fma(twelveth_S, rinvsix_S1 * rinvsix_S1,
+                        * fma(twelveth_S,
+                              rinvsix_S1 * rinvsix_S1,
                               v_fswitch_r(rsw_S1, rsw2_S1, p12_12cpot_S, p12_vc3_S, p12_vc4_S));
 #                ifndef HALF_LJ
     SimdReal VLJ12_S2 = c12_S2
-                        * fma(twelveth_S, rinvsix_S2 * rinvsix_S2,
+                        * fma(twelveth_S,
+                              rinvsix_S2 * rinvsix_S2,
                               v_fswitch_r(rsw_S2, rsw2_S2, p12_12cpot_S, p12_vc3_S, p12_vc4_S));
     SimdReal VLJ12_S3 = c12_S3
-                        * fma(twelveth_S, rinvsix_S3 * rinvsix_S3,
+                        * fma(twelveth_S,
+                              rinvsix_S3 * rinvsix_S3,
                               v_fswitch_r(rsw_S3, rsw2_S3, p12_12cpot_S, p12_vc3_S, p12_vc4_S));
 #                endif
 #                undef v_fswitch_r
          * r^-6*cexp*(1 + cr2 + cr2^2/2 + cr2^3/6) = cexp*(r^-6*poly + c^6/6)
          */
         frLJ_S0 = fma(c6grid_S0,
-                      fnma(expmcr2_S0, fma(rinvsix_nm_S0, poly_S0, lje_c6_6_S), rinvsix_nm_S0), frLJ_S0);
+                      fnma(expmcr2_S0, fma(rinvsix_nm_S0, poly_S0, lje_c6_6_S), rinvsix_nm_S0),
+                      frLJ_S0);
         frLJ_S1 = fma(c6grid_S1,
-                      fnma(expmcr2_S1, fma(rinvsix_nm_S1, poly_S1, lje_c6_6_S), rinvsix_nm_S1), frLJ_S1);
+                      fnma(expmcr2_S1, fma(rinvsix_nm_S1, poly_S1, lje_c6_6_S), rinvsix_nm_S1),
+                      frLJ_S1);
 #            ifndef HALF_LJ
         frLJ_S2 = fma(c6grid_S2,
-                      fnma(expmcr2_S2, fma(rinvsix_nm_S2, poly_S2, lje_c6_6_S), rinvsix_nm_S2), frLJ_S2);
+                      fnma(expmcr2_S2, fma(rinvsix_nm_S2, poly_S2, lje_c6_6_S), rinvsix_nm_S2),
+                      frLJ_S2);
         frLJ_S3 = fma(c6grid_S3,
-                      fnma(expmcr2_S3, fma(rinvsix_nm_S3, poly_S3, lje_c6_6_S), rinvsix_nm_S3), frLJ_S3);
+                      fnma(expmcr2_S3, fma(rinvsix_nm_S3, poly_S3, lje_c6_6_S), rinvsix_nm_S3),
+                      frLJ_S3);
 #            endif
 
 #            ifdef CALC_ENERGIES
 #                endif
 
         VLJ_S0 = fma(sixth_S * c6grid_S0,
-                     fma(rinvsix_nm_S0, fnma(expmcr2_S0, poly_S0, one_S), sh_mask_S0), VLJ_S0);
+                     fma(rinvsix_nm_S0, fnma(expmcr2_S0, poly_S0, one_S), sh_mask_S0),
+                     VLJ_S0);
         VLJ_S1 = fma(sixth_S * c6grid_S1,
-                     fma(rinvsix_nm_S1, fnma(expmcr2_S1, poly_S1, one_S), sh_mask_S1), VLJ_S1);
+                     fma(rinvsix_nm_S1, fnma(expmcr2_S1, poly_S1, one_S), sh_mask_S1),
+                     VLJ_S1);
 #                ifndef HALF_LJ
         VLJ_S2 = fma(sixth_S * c6grid_S2,
-                     fma(rinvsix_nm_S2, fnma(expmcr2_S2, poly_S2, one_S), sh_mask_S2), VLJ_S2);
+                     fma(rinvsix_nm_S2, fnma(expmcr2_S2, poly_S2, one_S), sh_mask_S2),
+                     VLJ_S2);
         VLJ_S3 = fma(sixth_S * c6grid_S3,
-                     fma(rinvsix_nm_S3, fnma(expmcr2_S3, poly_S3, one_S), sh_mask_S3), VLJ_S3);
+                     fma(rinvsix_nm_S3, fnma(expmcr2_S3, poly_S3, one_S), sh_mask_S3),
+                     VLJ_S3);
 #                endif
 #            endif /* CALC_ENERGIES */
     }
      * complicated when the i- and j-cluster size don't match.
      */
     {
-        int egps_j;
 #            if UNROLLJ == 2
-        egps_j    = nbatParams.energrp[cj >> 1];
-        egp_jj[0] = ((egps_j >> ((cj & 1) * egps_jshift)) & egps_jmask) * egps_jstride;
+        const int egps_j = nbatParams.energrp[cj >> 1];
+        egp_jj[0]        = ((egps_j >> ((cj & 1) * egps_jshift)) & egps_jmask) * egps_jstride;
 #            else
         /* We assume UNROLLI <= UNROLLJ */
-        int jdi;
-        for (jdi = 0; jdi < UNROLLJ / UNROLLI; jdi++)
+        for (int jdi = 0; jdi < UNROLLJ / UNROLLI; jdi++)
         {
-            int jj;
-            egps_j = nbatParams.energrp[cj * (UNROLLJ / UNROLLI) + jdi];
-            for (jj = 0; jj < (UNROLLI / 2); jj++)
+            const int egps_j = nbatParams.energrp[cj * (UNROLLJ / UNROLLI) + jdi];
+            for (int jj = 0; jj < (UNROLLI / 2); jj++)
             {
                 egp_jj[jdi * (UNROLLI / 2) + jj] =
                         ((egps_j >> (jj * egps_jshift)) & egps_jmask) * egps_jstride;
index 19ea6304ba15f17bacf99d28213a7b51261b6983..1946355f26e6b3b0c5f642983aed49553501c24b 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
     real* Vvdw = out->VSvdw.data();
     real* Vc   = out->VSc.data();
 #    else
-    real* Vvdw = out->Vvdw.data();
-    real* Vc   = out->Vc.data();
+    real*       Vvdw       = out->Vvdw.data();
+    real*       Vc         = out->Vc.data();
 #    endif
 #endif
 
-    const nbnxn_cj_t* l_cj;
-    int               ci, ci_sh;
-    int               ish, ish3;
-    gmx_bool          do_LJ, half_LJ, do_coul;
-    int               cjind0, cjind1, cjind;
-
-#ifdef ENERGY_GROUPS
-    int   Vstride_i;
-    int   egps_ishift, egps_imask;
-    int   egps_jshift, egps_jmask, egps_jstride;
-    int   egps_i;
-    real* vvdwtp[UNROLLI];
-    real* vctp[UNROLLI];
-#endif
-
     SimdReal shX_S;
     SimdReal shY_S;
     SimdReal shZ_S;
 
 #ifdef CALC_COUL_TAB
     /* Coulomb table variables */
-    SimdReal    invtsp_S;
-    const real* tab_coul_F;
-#    if defined CALC_ENERGIES && !defined TAB_FDV0
-    const real gmx_unused* tab_coul_V;
-#    endif
+    SimdReal invtsp_S;
 #    ifdef CALC_ENERGIES
     SimdReal mhalfsp_S;
 #    endif
 #    endif
 #endif
 #ifdef LJ_EWALD_GEOM
-    real     lj_ewaldcoeff2, lj_ewaldcoeff6_6;
     SimdReal half_S, lje_c2_S, lje_c6_6_S;
 #endif
 
     SimdReal rcvdw2_S;
 #endif
 
-    int ninner;
-
 #ifdef COUNT_PAIRS
     int npair = 0;
 #endif
 
 #ifdef CALC_COUL_RF
     /* Reaction-field constants */
-    mrc_3_S = SimdReal(-2 * ic->k_rf);
+    mrc_3_S = SimdReal(-2 * ic->reactionFieldCoefficient);
 #    ifdef CALC_ENERGIES
-    hrc_3_S  = SimdReal(ic->k_rf);
-    moh_rc_S = SimdReal(-ic->c_rf);
+    hrc_3_S  = SimdReal(ic->reactionFieldCoefficient);
+    moh_rc_S = SimdReal(-ic->reactionFieldShift);
 #    endif
 #endif
 
 #    endif
 
 #    ifdef TAB_FDV0
-    tab_coul_F = ic->coulombEwaldTables->tableFDV0.data();
+    const real* tab_coul_F = ic->coulombEwaldTables->tableFDV0.data();
 #    else
-    tab_coul_F = ic->coulombEwaldTables->tableF.data();
+    const real* tab_coul_F = ic->coulombEwaldTables->tableF.data();
 #        ifdef CALC_ENERGIES
-    tab_coul_V = ic->coulombEwaldTables->tableV.data();
+    const real* tab_coul_V = ic->coulombEwaldTables->tableV.data();
 #        endif
 #    endif
 #endif /* CALC_COUL_TAB */
 #    endif
 #endif
 #ifdef LJ_EWALD_GEOM
-    half_S           = SimdReal(0.5);
-    lj_ewaldcoeff2   = ic->ewaldcoeff_lj * ic->ewaldcoeff_lj;
-    lj_ewaldcoeff6_6 = lj_ewaldcoeff2 * lj_ewaldcoeff2 * lj_ewaldcoeff2 / 6;
-    lje_c2_S         = SimdReal(lj_ewaldcoeff2);
-    lje_c6_6_S       = SimdReal(lj_ewaldcoeff6_6);
+    half_S                      = SimdReal(0.5);
+    const real lj_ewaldcoeff2   = ic->ewaldcoeff_lj * ic->ewaldcoeff_lj;
+    const real lj_ewaldcoeff6_6 = lj_ewaldcoeff2 * lj_ewaldcoeff2 * lj_ewaldcoeff2 / 6;
+    lje_c2_S                    = SimdReal(lj_ewaldcoeff2);
+    lje_c6_6_S                  = SimdReal(lj_ewaldcoeff6_6);
 #    ifdef CALC_ENERGIES
     /* Determine the grid potential at the cut-off */
     SimdReal lje_vc_S(ic->sh_lj_ewald);
 #endif /* FIX_LJ_C */
 
 #ifdef ENERGY_GROUPS
-    egps_ishift  = nbatParams.neg_2log;
-    egps_imask   = (1 << egps_ishift) - 1;
-    egps_jshift  = 2 * nbatParams.neg_2log;
-    egps_jmask   = (1 << egps_jshift) - 1;
-    egps_jstride = (UNROLLJ >> 1) * UNROLLJ;
+    const int egps_ishift  = nbatParams.neg_2log;
+    const int egps_imask   = (1 << egps_ishift) - 1;
+    const int egps_jshift  = 2 * nbatParams.neg_2log;
+    const int egps_jmask   = (1 << egps_jshift) - 1;
+    const int egps_jstride = (UNROLLJ >> 1) * UNROLLJ;
     /* Major division is over i-particle energy groups, determine the stride */
-    Vstride_i = nbatParams.nenergrp * (1 << nbatParams.neg_2log) * egps_jstride;
+    const int Vstride_i = nbatParams.nenergrp * (1 << nbatParams.neg_2log) * egps_jstride;
 #endif
 
-    l_cj = nbl->cj.data();
+    const nbnxn_cj_t* l_cj = nbl->cj.data();
 
-    ninner = 0;
+    int ninner = 0;
 
     for (const nbnxn_ci_t& ciEntry : nbl->ci)
     {
-        ish    = (ciEntry.shift & NBNXN_CI_SHIFT);
-        ish3   = ish * 3;
-        cjind0 = ciEntry.cj_ind_start;
-        cjind1 = ciEntry.cj_ind_end;
-        ci     = ciEntry.ci;
-        ci_sh  = (ish == CENTRAL ? ci : -1);
+        const int ish    = (ciEntry.shift & NBNXN_CI_SHIFT);
+        const int ish3   = ish * 3;
+        const int cjind0 = ciEntry.cj_ind_start;
+        const int cjind1 = ciEntry.cj_ind_end;
+        const int ci     = ciEntry.ci;
+        const int ci_sh  = (ish == gmx::c_centralShiftIndex ? ci : -1);
 
         shX_S = SimdReal(shiftvec[ish3]);
         shY_S = SimdReal(shiftvec[ish3 + 1]);
          * inner LJ + C      for full-LJ + C
          * inner LJ          for full-LJ + no-C / half-LJ + no-C
          */
-        do_LJ   = ((ciEntry.shift & NBNXN_CI_DO_LJ(0)) != 0);
-        do_coul = ((ciEntry.shift & NBNXN_CI_DO_COUL(0)) != 0);
-        half_LJ = (((ciEntry.shift & NBNXN_CI_HALF_LJ(0)) != 0) || !do_LJ) && do_coul;
+        const bool do_LJ   = ((ciEntry.shift & NBNXN_CI_DO_LJ(0)) != 0);
+        const bool do_coul = ((ciEntry.shift & NBNXN_CI_DO_COUL(0)) != 0);
+        const bool half_LJ = (((ciEntry.shift & NBNXN_CI_HALF_LJ(0)) != 0) || !do_LJ) && do_coul;
 
 #ifdef ENERGY_GROUPS
-        egps_i = nbatParams.energrp[ci];
+        real*     vvdwtp[UNROLLI];
+        real*     vctp[UNROLLI];
+        const int egps_i = nbatParams.energrp[ci];
         {
-            int ia, egp_ia;
-
-            for (ia = 0; ia < UNROLLI; ia++)
+            for (int ia = 0; ia < UNROLLI; ia++)
             {
-                egp_ia     = (egps_i >> (ia * egps_ishift)) & egps_imask;
+                int egp_ia = (egps_i >> (ia * egps_ishift)) & egps_imask;
                 vvdwtp[ia] = Vvdw + egp_ia * Vstride_i;
                 vctp[ia]   = Vc + egp_ia * Vstride_i;
             }
 
 #ifdef CALC_ENERGIES
 #    ifdef LJ_EWALD_GEOM
-        gmx_bool do_self = TRUE;
+        const bool do_self = true;
 #    else
-        gmx_bool do_self = do_coul;
+        const bool do_self = do_coul;
 #    endif
 #    if UNROLLJ == 4
         if (do_self && l_cj[ciEntry.cj_ind_start].cj == ci_sh)
                 {
                     if (do_coul)
                     {
-                        real Vc_sub_self;
-                        int  ia;
-
 #    ifdef CALC_COUL_RF
-                        Vc_sub_self = 0.5 * ic->c_rf;
+                        const real Vc_sub_self = 0.5 * ic->reactionFieldShift;
 #    endif
 #    ifdef CALC_COUL_TAB
 #        ifdef TAB_FDV0
-                        Vc_sub_self = 0.5 * tab_coul_F[2];
+                        const real Vc_sub_self = 0.5 * tab_coul_F[2];
 #        else
-                        Vc_sub_self = 0.5 * tab_coul_V[0];
+                        const real Vc_sub_self = 0.5 * tab_coul_V[0];
 #        endif
 #    endif
 #    ifdef CALC_COUL_EWALD
                         /* beta/sqrt(pi) */
-                        Vc_sub_self = 0.5 * ic->ewaldcoeff_q * M_2_SQRTPI;
+                        const real Vc_sub_self = 0.5 * ic->ewaldcoeff_q * M_2_SQRTPI;
 #    endif
 
-                        for (ia = 0; ia < UNROLLI; ia++)
+                        for (int ia = 0; ia < UNROLLI; ia++)
                         {
-                            real qi;
-
-                            qi = q[sci + ia];
+                            const real qi = q[sci + ia];
 #    ifdef ENERGY_GROUPS
                             vctp[ia][((egps_i >> (ia * egps_ishift)) & egps_imask) * egps_jstride]
 #    else
 
 #    ifdef LJ_EWALD_GEOM
                     {
-                        int ia;
-
-                        for (ia = 0; ia < UNROLLI; ia++)
+                        for (int ia = 0; ia < UNROLLI; ia++)
                         {
-                            real c6_i;
-
-                            c6_i = nbatParams.nbfp[nbatParams.type[sci + ia] * (nbatParams.numTypes + 1) * 2]
-                                   / 6;
+                            real c6_i =
+                                    nbatParams.nbfp[nbatParams.type[sci + ia] * (nbatParams.numTypes + 1) * 2]
+                                    / 6;
 #        ifdef ENERGY_GROUPS
                             vvdwtp[ia][((egps_i >> (ia * egps_ishift)) & egps_imask) * egps_jstride]
 #        else
 #endif
 
         /* Load i atom data */
-        int sciy = scix + STRIDE;
-        int sciz = sciy + STRIDE;
-        ix_S0    = SimdReal(x[scix]) + shX_S;
-        ix_S1    = SimdReal(x[scix + 1]) + shX_S;
-        ix_S2    = SimdReal(x[scix + 2]) + shX_S;
-        ix_S3    = SimdReal(x[scix + 3]) + shX_S;
-        iy_S0    = SimdReal(x[sciy]) + shY_S;
-        iy_S1    = SimdReal(x[sciy + 1]) + shY_S;
-        iy_S2    = SimdReal(x[sciy + 2]) + shY_S;
-        iy_S3    = SimdReal(x[sciy + 3]) + shY_S;
-        iz_S0    = SimdReal(x[sciz]) + shZ_S;
-        iz_S1    = SimdReal(x[sciz + 1]) + shZ_S;
-        iz_S2    = SimdReal(x[sciz + 2]) + shZ_S;
-        iz_S3    = SimdReal(x[sciz + 3]) + shZ_S;
+        const int sciy = scix + STRIDE;
+        const int sciz = sciy + STRIDE;
+        ix_S0          = SimdReal(x[scix]) + shX_S;
+        ix_S1          = SimdReal(x[scix + 1]) + shX_S;
+        ix_S2          = SimdReal(x[scix + 2]) + shX_S;
+        ix_S3          = SimdReal(x[scix + 3]) + shX_S;
+        iy_S0          = SimdReal(x[sciy]) + shY_S;
+        iy_S1          = SimdReal(x[sciy + 1]) + shY_S;
+        iy_S2          = SimdReal(x[sciy + 2]) + shY_S;
+        iy_S3          = SimdReal(x[sciy + 3]) + shY_S;
+        iz_S0          = SimdReal(x[sciz]) + shZ_S;
+        iz_S1          = SimdReal(x[sciz + 1]) + shZ_S;
+        iz_S2          = SimdReal(x[sciz + 2]) + shZ_S;
+        iz_S3          = SimdReal(x[sciz + 3]) + shZ_S;
 
         if (do_coul)
         {
         fiz_S2 = setZero();
         fiz_S3 = setZero();
 
-        cjind = cjind0;
+        int cjind = cjind0;
 
         /* Currently all kernels use (at least half) LJ */
 #define CALC_LJ
index d48a526f83f92043aed64f843a27e53185f021f4..cb2059a713230ad8ca8b28200fd6a5201ae7a77b 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #endif
 
 /* Prune a single nbnxn_pairtlist_t entry with distance rlistInner */
-void nbnxn_kernel_prune_4xn(NbnxnPairlistCpu*       nbl,
-                            const nbnxn_atomdata_t* nbat,
-                            const rvec* gmx_restrict shift_vec,
-                            real                     rlistInner)
+void nbnxn_kernel_prune_4xn(NbnxnPairlistCpu*              nbl,
+                            const nbnxn_atomdata_t*        nbat,
+                            gmx::ArrayRef<const gmx::RVec> shiftvec,
+                            real                           rlistInner)
 {
 #ifdef GMX_NBNXN_SIMD_4XN
     using namespace gmx;
@@ -66,8 +67,7 @@ void nbnxn_kernel_prune_4xn(NbnxnPairlistCpu*       nbl,
     const nbnxn_cj_t* gmx_restrict cjOuter = nbl->cjOuter.data();
     nbnxn_cj_t* gmx_restrict cjInner       = nbl->cj.data();
 
-    const real* gmx_restrict shiftvec = shift_vec[0];
-    const real* gmx_restrict x        = nbat->x().data();
+    const real* gmx_restrict x = nbat->x().data();
 
     const SimdReal rlist2_S(rlistInner * rlistInner);
 
@@ -85,13 +85,12 @@ void nbnxn_kernel_prune_4xn(NbnxnPairlistCpu*       nbl,
         ciInner[nciInner].cj_ind_start = ncjInner;
 
         /* Extract shift data */
-        int ish  = (ciEntry->shift & NBNXN_CI_SHIFT);
-        int ish3 = ish * 3;
-        int ci   = ciEntry->ci;
+        int ish = (ciEntry->shift & NBNXN_CI_SHIFT);
+        int ci  = ciEntry->ci;
 
-        SimdReal shX_S = SimdReal(shiftvec[ish3]);
-        SimdReal shY_S = SimdReal(shiftvec[ish3 + 1]);
-        SimdReal shZ_S = SimdReal(shiftvec[ish3 + 2]);
+        SimdReal shX_S = SimdReal(shiftvec[ish][XX]);
+        SimdReal shY_S = SimdReal(shiftvec[ish][YY]);
+        SimdReal shZ_S = SimdReal(shiftvec[ish][ZZ]);
 
 #    if UNROLLJ <= 4
         int scix = ci * STRIDE * DIM;
@@ -189,7 +188,7 @@ void nbnxn_kernel_prune_4xn(NbnxnPairlistCpu*       nbl,
 
     GMX_UNUSED_VALUE(nbl);
     GMX_UNUSED_VALUE(nbat);
-    GMX_UNUSED_VALUE(shift_vec);
+    GMX_UNUSED_VALUE(shiftvec);
     GMX_UNUSED_VALUE(rlistInner);
 
 #endif /* GMX_NBNXN_SIMD_4XN */
index ca6113dde9411e05f63bc1c69dd148098ce2f42e..025ba4a02e97a8a287738e9dfff389fac01fb718 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 nbnxn_atomdata_t;
 struct NbnxnPairlistCpu;
 
+namespace gmx
+{
+template<typename>
+class ArrayRef;
+}
+
 /*! \brief Prune a single NbnxnPairlistCpu entry with distance \p rlistInner
  *
  * Reads a cluster pairlist \p nbl->ciOuter, \p nbl->cjOuter and writes
  * all cluster pairs within \p rlistInner to \p nbl->ci, \p nbl->cj.
  */
-void nbnxn_kernel_prune_4xn(NbnxnPairlistCpu*       nbl,
-                            const nbnxn_atomdata_t* nbat,
-                            const rvec* gmx_restrict shift_vec,
-                            real                     rlistInner);
+void nbnxn_kernel_prune_4xn(NbnxnPairlistCpu*              nbl,
+                            const nbnxn_atomdata_t*        nbat,
+                            gmx::ArrayRef<const gmx::RVec> shiftvec,
+                            real                           rlistInner);
index d95df1c7687ed66bfe3c07eb604f56980dbf2259..2168d180aaf3abe72d2c0ea1fb9942abb161d2d6 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2019 by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +143,7 @@ nbk_func_ener nbnxm_kernel_ElecEwTwinCut_VdwLJEwCombGeom_VgrpF_4xm;
  * The minor index of the array goes over both the LJ combination rules,
  * which is only supported by plain cut-off, and the LJ switch/PME functions.
  */
-static p_nbk_func_noener nbnxm_kernel_noener_simd_4xm[coulktNR][vdwktNR] = {
+static const p_nbk_func_noener nbnxm_kernel_noener_simd_4xm[coulktNR][vdwktNR] = {
     {
             nbnxm_kernel_ElecRF_VdwLJCombGeom_F_4xm,
             nbnxm_kernel_ElecRF_VdwLJCombLB_F_4xm,
@@ -185,7 +186,7 @@ static p_nbk_func_noener nbnxm_kernel_noener_simd_4xm[coulktNR][vdwktNR] = {
     },
 };
 
-static p_nbk_func_ener nbnxm_kernel_ener_simd_4xm[coulktNR][vdwktNR] = {
+static const p_nbk_func_ener nbnxm_kernel_ener_simd_4xm[coulktNR][vdwktNR] = {
     {
             nbnxm_kernel_ElecRF_VdwLJCombGeom_VF_4xm,
             nbnxm_kernel_ElecRF_VdwLJCombLB_VF_4xm,
@@ -228,7 +229,7 @@ static p_nbk_func_ener nbnxm_kernel_ener_simd_4xm[coulktNR][vdwktNR] = {
     },
 };
 
-static p_nbk_func_ener nbnxm_kernel_energrp_simd_4xm[coulktNR][vdwktNR] = {
+static const p_nbk_func_ener nbnxm_kernel_energrp_simd_4xm[coulktNR][vdwktNR] = {
     {
             nbnxm_kernel_ElecRF_VdwLJCombGeom_VgrpF_4xm,
             nbnxm_kernel_ElecRF_VdwLJCombLB_VgrpF_4xm,
index 76e2eead9f07d18144c568948f3b7b5c34b95667..ecc0ecc2ca6c9ee5dcd9e1bb84fa0216ec69b156 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -68,8 +68,17 @@ void nbnxn_put_on_grid(nonbonded_verlet_t*            nb_verlet,
                        int                            numAtomsMoved,
                        const int*                     move)
 {
-    nb_verlet->pairSearch_->putOnGrid(box, gridIndex, lowerCorner, upperCorner, updateGroupsCog,
-                                      atomRange, atomDensity, atomInfo, x, numAtomsMoved, move,
+    nb_verlet->pairSearch_->putOnGrid(box,
+                                      gridIndex,
+                                      lowerCorner,
+                                      upperCorner,
+                                      updateGroupsCog,
+                                      atomRange,
+                                      atomDensity,
+                                      atomInfo,
+                                      x,
+                                      numAtomsMoved,
+                                      move,
                                       nb_verlet->nbat.get());
 }
 
@@ -88,8 +97,17 @@ void nbnxn_put_on_grid_nonlocal(nonbonded_verlet_t*              nbv,
             c1[d] = zones->size[zone].bb_x1[d];
         }
 
-        nbnxn_put_on_grid(nbv, nullptr, zone, c0, c1, nullptr,
-                          { zones->cg_range[zone], zones->cg_range[zone + 1] }, -1, atomInfo, x, 0,
+        nbnxn_put_on_grid(nbv,
+                          nullptr,
+                          zone,
+                          c0,
+                          c1,
+                          nullptr,
+                          { zones->cg_range[zone], zones->cg_range[zone + 1] },
+                          -1,
+                          atomInfo,
+                          x,
+                          0,
                           nullptr);
     }
 }
@@ -114,44 +132,42 @@ gmx::ArrayRef<const int> nonbonded_verlet_t::getLocalAtomOrder() const
     return gmx::constArrayRefFromArray(pairSearch_->gridSet().atomIndices().data(), numIndices);
 }
 
-void nonbonded_verlet_t::setLocalAtomOrder()
+void nonbonded_verlet_t::setLocalAtomOrder() const
 {
     pairSearch_->setLocalAtomOrder();
 }
 
 void nonbonded_verlet_t::setAtomProperties(gmx::ArrayRef<const int>  atomTypes,
                                            gmx::ArrayRef<const real> atomCharges,
-                                           gmx::ArrayRef<const int>  atomInfo)
+                                           gmx::ArrayRef<const int>  atomInfo) const
 {
     nbnxn_atomdata_set(nbat.get(), pairSearch_->gridSet(), atomTypes, atomCharges, atomInfo);
 }
 
 void nonbonded_verlet_t::convertCoordinates(const gmx::AtomLocality        locality,
-                                            const bool                     fillLocal,
                                             gmx::ArrayRef<const gmx::RVec> coordinates)
 {
-    wallcycle_start(wcycle_, ewcNB_XF_BUF_OPS);
-    wallcycle_sub_start(wcycle_, ewcsNB_X_BUF_OPS);
+    wallcycle_start(wcycle_, WallCycleCounter::NbXFBufOps);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::NBXBufOps);
 
-    nbnxn_atomdata_copy_x_to_nbat_x(pairSearch_->gridSet(), locality, fillLocal,
-                                    as_rvec_array(coordinates.data()), nbat.get());
+    nbnxn_atomdata_copy_x_to_nbat_x(
+            pairSearch_->gridSet(), locality, as_rvec_array(coordinates.data()), nbat.get());
 
-    wallcycle_sub_stop(wcycle_, ewcsNB_X_BUF_OPS);
-    wallcycle_stop(wcycle_, ewcNB_XF_BUF_OPS);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::NBXBufOps);
+    wallcycle_stop(wcycle_, WallCycleCounter::NbXFBufOps);
 }
 
 void nonbonded_verlet_t::convertCoordinatesGpu(const gmx::AtomLocality locality,
-                                               const bool              fillLocal,
                                                DeviceBuffer<gmx::RVec> d_x,
                                                GpuEventSynchronizer*   xReadyOnDevice)
 {
-    wallcycle_start(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start(wcycle_, ewcsLAUNCH_GPU_NB_X_BUF_OPS);
+    wallcycle_start(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::LaunchGpuNBXBufOps);
 
-    nbnxn_atomdata_x_to_nbat_x_gpu(pairSearch_->gridSet(), locality, fillLocal, gpu_nbv, d_x, xReadyOnDevice);
+    nbnxn_atomdata_x_to_nbat_x_gpu(pairSearch_->gridSet(), locality, gpu_nbv, d_x, xReadyOnDevice);
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_GPU_NB_X_BUF_OPS);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchGpuNBXBufOps);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
 
 gmx::ArrayRef<const int> nonbonded_verlet_t::getGridIndices() const
@@ -165,21 +181,21 @@ void nonbonded_verlet_t::atomdata_add_nbat_f_to_f(const gmx::AtomLocality  local
 
     /* Skip the reduction if there was no short-range GPU work to do
      * (either NB or both NB and bonded work). */
-    if (!pairlistIsSimple() && !Nbnxm::haveGpuShortRangeWork(gpu_nbv, locality))
+    if (!pairlistIsSimple() && !Nbnxm::haveGpuShortRangeWork(gpu_nbv, atomToInteractionLocality(locality)))
     {
         return;
     }
 
-    wallcycle_start(wcycle_, ewcNB_XF_BUF_OPS);
-    wallcycle_sub_start(wcycle_, ewcsNB_F_BUF_OPS);
+    wallcycle_start(wcycle_, WallCycleCounter::NbXFBufOps);
+    wallcycle_sub_start(wcycle_, WallCycleSubCounter::NBFBufOps);
 
     reduceForces(nbat.get(), locality, pairSearch_->gridSet(), as_rvec_array(force.data()));
 
-    wallcycle_sub_stop(wcycle_, ewcsNB_F_BUF_OPS);
-    wallcycle_stop(wcycle_, ewcNB_XF_BUF_OPS);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::NBFBufOps);
+    wallcycle_stop(wcycle_, WallCycleCounter::NbXFBufOps);
 }
 
-int nonbonded_verlet_t::getNumAtoms(const gmx::AtomLocality locality)
+int nonbonded_verlet_t::getNumAtoms(const gmx::AtomLocality locality) const
 {
     int numAtoms = 0;
     switch (locality)
@@ -197,7 +213,7 @@ int nonbonded_verlet_t::getNumAtoms(const gmx::AtomLocality locality)
     return numAtoms;
 }
 
-void* nonbonded_verlet_t::getGpuForces()
+DeviceBuffer<gmx::RVec> nonbonded_verlet_t::getGpuForces() const
 {
     return Nbnxm::getGpuForces(gpu_nbv);
 }
@@ -212,13 +228,13 @@ real nonbonded_verlet_t::pairlistOuterRadius() const
     return pairlistSets_->params().rlistOuter;
 }
 
-void nonbonded_verlet_t::changePairlistRadii(real rlistOuter, real rlistInner)
+void nonbonded_verlet_t::changePairlistRadii(real rlistOuter, real rlistInner) const
 {
     pairlistSets_->changePairlistRadii(rlistOuter, rlistInner);
 }
 
 void nonbonded_verlet_t::setupGpuShortRangeWork(const gmx::GpuBonded*          gpuBonded,
-                                                const gmx::InteractionLocality iLocality)
+                                                const gmx::InteractionLocality iLocality) const
 {
     if (useGpu() && !emulateGpu())
     {
@@ -226,14 +242,9 @@ void nonbonded_verlet_t::setupGpuShortRangeWork(const gmx::GpuBonded*          g
     }
 }
 
-void nonbonded_verlet_t::atomdata_init_copy_x_to_nbat_x_gpu()
+void nonbonded_verlet_t::atomdata_init_copy_x_to_nbat_x_gpu() const
 {
     Nbnxm::nbnxn_gpu_init_x_to_nbat_x(pairSearch_->gridSet(), gpu_nbv);
 }
 
-void nonbonded_verlet_t::insertNonlocalGpuDependency(const gmx::InteractionLocality interactionLocality)
-{
-    Nbnxm::nbnxnInsertNonlocalGpuDependency(gpu_nbv, interactionLocality);
-}
-
 /*! \endcond */
index 2596350e52dc8096590c8278f4583ca0ec68f77f..6d5cdccd694427c814b57850cca351b399b3a3a3 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -128,13 +128,13 @@ struct gmx_mtop_t;
 struct NbnxmGpu;
 struct gmx_wallcycle;
 struct interaction_const_t;
+enum class LJCombinationRule;
 struct nbnxn_atomdata_t;
 struct nonbonded_verlet_t;
 class PairSearch;
 class PairlistSets;
 struct t_commrec;
 struct t_lambda;
-struct t_mdatoms;
 struct t_nrnb;
 struct t_forcerec;
 struct t_inputrec;
@@ -155,13 +155,62 @@ class StepWorkload;
 class UpdateGroupsCog;
 } // namespace gmx
 
+//! Namespace for non-bonded kernels
 namespace Nbnxm
 {
 enum class KernelType;
-}
 
-namespace Nbnxm
+/*! \brief Nbnxm electrostatic GPU kernel flavors.
+ *
+ *  Types of electrostatics implementations available in the GPU non-bonded
+ *  force kernels. These represent both the electrostatics types implemented
+ *  by the kernels (cut-off, RF, and Ewald - a subset of what's defined in
+ *  enums.h) as well as encode implementation details analytical/tabulated
+ *  and single or twin cut-off (for Ewald kernels).
+ *  Note that the cut-off and RF kernels have only analytical flavor and unlike
+ *  in the CPU kernels, the tabulated kernels are ATM Ewald-only.
+ *
+ *  The row-order of pointers to different electrostatic kernels defined in
+ *  nbnxn_cuda.cu by the nb_*_kfunc_ptr function pointer table
+ *  should match the order of enumerated types below.
+ */
+enum class ElecType : int
+{
+    Cut,          //!< Plain cut-off
+    RF,           //!< Reaction field
+    EwaldTab,     //!< Tabulated Ewald with single cut-off
+    EwaldTabTwin, //!< Tabulated Ewald with twin cut-off
+    EwaldAna,     //!< Analytical Ewald with single cut-off
+    EwaldAnaTwin, //!< Analytical Ewald with twin cut-off
+    Count         //!< Number of valid values
+};
+
+//! Number of possible \ref ElecType values.
+constexpr int c_numElecTypes = static_cast<int>(ElecType::Count);
+
+/*! \brief Nbnxm VdW GPU kernel flavors.
+ *
+ * The enumerates values correspond to the LJ implementations in the GPU non-bonded
+ * kernels.
+ *
+ * The column-order of pointers to different electrostatic kernels defined in
+ * nbnxn_cuda_ocl.cpp/.cu by the nb_*_kfunc_ptr function pointer table
+ * should match the order of enumerated types below.
+ */
+enum class VdwType : int
 {
+    Cut,         //!< Plain cut-off
+    CutCombGeom, //!< Cut-off with geometric combination rules
+    CutCombLB,   //!< Cut-off with Lorentz-Berthelot combination rules
+    FSwitch,     //!< Smooth force switch
+    PSwitch,     //!< Smooth potential switch
+    EwaldGeom,   //!< Ewald with geometric combination rules
+    EwaldLB,     //!< Ewald with Lorentz-Berthelot combination rules
+    Count        //!< Number of valid values
+};
+
+//! Number of possible \ref VdwType values.
+constexpr int c_numVdwTypes = static_cast<int>(VdwType::Count);
 
 /*! \brief Nonbonded NxN kernel types: plain C, CPU SIMD, GPU, GPU emulation */
 enum class KernelType : int
@@ -236,14 +285,12 @@ public:
     //! Return whether the pairlist is of simple, CPU type
     bool pairlistIsSimple() const { return !useGpu() && !emulateGpu(); }
 
-    //! Initialize the pair list sets, TODO this should be private
-    void initPairlistSets(bool haveMultipleDomains);
 
     //! Returns the order of the local atoms on the grid
     gmx::ArrayRef<const int> getLocalAtomOrder() const;
 
     //! Sets the order of the local atoms to the order grid atom ordering
-    void setLocalAtomOrder();
+    void setLocalAtomOrder() const;
 
     //! Returns the index position of the atoms on the search grid
     gmx::ArrayRef<const int> getGridIndices() const;
@@ -263,42 +310,36 @@ public:
     void constructPairlist(gmx::InteractionLocality     iLocality,
                            const gmx::ListOfLists<int>& exclusions,
                            int64_t                      step,
-                           t_nrnb*                      nrnb);
+                           t_nrnb*                      nrnb) const;
 
     //! Updates all the atom properties in Nbnxm
     void setAtomProperties(gmx::ArrayRef<const int>  atomTypes,
                            gmx::ArrayRef<const real> atomCharges,
-                           gmx::ArrayRef<const int>  atomInfo);
+                           gmx::ArrayRef<const int>  atomInfo) const;
 
     /*!\brief Convert the coordinates to NBNXM format for the given locality.
      *
      * The API function for the transformation of the coordinates from one layout to another.
      *
      * \param[in] locality     Whether coordinates for local or non-local atoms should be
-     * transformed. \param[in] fillLocal    If the coordinates for filler particles should be
-     * zeroed. \param[in] coordinates  Coordinates in plain rvec format to be transformed.
+     * transformed. \param[in] coordinates  Coordinates in plain rvec format to be transformed.
      */
-    void convertCoordinates(gmx::AtomLocality locality, bool fillLocal, gmx::ArrayRef<const gmx::RVec> coordinates);
+    void convertCoordinates(gmx::AtomLocality locality, gmx::ArrayRef<const gmx::RVec> coordinates);
 
     /*!\brief Convert the coordinates to NBNXM format on the GPU for the given locality
      *
      * The API function for the transformation of the coordinates from one layout to another in the GPU memory.
      *
      * \param[in] locality        Whether coordinates for local or non-local atoms should be transformed.
-     * \param[in] fillLocal       If the coordinates for filler particles should be zeroed.
      * \param[in] d_x             GPU coordinates buffer in plain rvec format to be transformed.
      * \param[in] xReadyOnDevice  Event synchronizer indicating that the coordinates are ready in the device memory.
      */
     void convertCoordinatesGpu(gmx::AtomLocality       locality,
-                               bool                    fillLocal,
                                DeviceBuffer<gmx::RVec> d_x,
                                GpuEventSynchronizer*   xReadyOnDevice);
 
     //! Init for GPU version of setup coordinates in Nbnxm
-    void atomdata_init_copy_x_to_nbat_x_gpu();
-
-    //! Sync the nonlocal GPU stream with dependent tasks in the local queue.
-    void insertNonlocalGpuDependency(gmx::InteractionLocality interactionLocality);
+    void atomdata_init_copy_x_to_nbat_x_gpu() const;
 
     //! Returns a reference to the pairlist sets
     const PairlistSets& pairlistSets() const { return *pairlistSets_; }
@@ -310,31 +351,36 @@ public:
     bool isDynamicPruningStepGpu(int64_t step) const;
 
     //! Dispatches the dynamic pruning kernel for the given locality, for CPU lists
-    void dispatchPruneKernelCpu(gmx::InteractionLocality iLocality, const rvec* shift_vec);
+    void dispatchPruneKernelCpu(gmx::InteractionLocality       iLocality,
+                                gmx::ArrayRef<const gmx::RVec> shift_vec) const;
 
     //! Dispatches the dynamic pruning kernel for GPU lists
     void dispatchPruneKernelGpu(int64_t step);
 
     //! \brief Executes the non-bonded kernel of the GPU or launches it on the GPU
-    void dispatchNonbondedKernel(gmx::InteractionLocality   iLocality,
-                                 const interaction_const_t& ic,
-                                 const gmx::StepWorkload&   stepWork,
-                                 int                        clearF,
-                                 const t_forcerec&          fr,
-                                 gmx_enerdata_t*            enerd,
-                                 t_nrnb*                    nrnb);
+    void dispatchNonbondedKernel(gmx::InteractionLocality       iLocality,
+                                 const interaction_const_t&     ic,
+                                 const gmx::StepWorkload&       stepWork,
+                                 int                            clearF,
+                                 gmx::ArrayRef<const gmx::RVec> shiftvec,
+                                 gmx::ArrayRef<real>            repulsionDispersionSR,
+                                 gmx::ArrayRef<real>            CoulombSR,
+                                 t_nrnb*                        nrnb) const;
 
     //! Executes the non-bonded free-energy kernel, always runs on the CPU
-    void dispatchFreeEnergyKernel(gmx::InteractionLocality   iLocality,
-                                  const t_forcerec*          fr,
-                                  rvec                       x[],
-                                  gmx::ForceWithShiftForces* forceWithShiftForces,
-                                  const t_mdatoms&           mdatoms,
-                                  t_lambda*                  fepvals,
-                                  gmx::ArrayRef<const real>  lambda,
-                                  gmx_enerdata_t*            enerd,
-                                  const gmx::StepWorkload&   stepWork,
-                                  t_nrnb*                    nrnb);
+    void dispatchFreeEnergyKernel(gmx::InteractionLocality       iLocality,
+                                  const t_forcerec&              fr,
+                                  gmx::ArrayRef<const gmx::RVec> coords,
+                                  gmx::ForceWithShiftForces*     forceWithShiftForces,
+                                  gmx::ArrayRef<const real>      chargeA,
+                                  gmx::ArrayRef<const real>      chargeB,
+                                  gmx::ArrayRef<const int>       typeA,
+                                  gmx::ArrayRef<const int>       typeB,
+                                  t_lambda*                      fepvals,
+                                  gmx::ArrayRef<const real>      lambda,
+                                  gmx_enerdata_t*                enerd,
+                                  const gmx::StepWorkload&       stepWork,
+                                  t_nrnb*                        nrnb);
 
     /*! \brief Add the forces stored in nbat to f, zeros the forces in nbat
      * \param [in] locality         Local or non-local
@@ -342,34 +388,18 @@ public:
      */
     void atomdata_add_nbat_f_to_f(gmx::AtomLocality locality, gmx::ArrayRef<gmx::RVec> force);
 
-    /*! \brief Add the forces stored in nbat to total force using GPU buffer opse
-     *
-     * \param [in]     locality             Local or non-local
-     * \param [in,out] totalForcesDevice    Force to be added to
-     * \param [in]     forcesPmeDevice      Device buffer with PME forces
-     * \param[in]      dependencyList       List of synchronizers that represent the dependencies the reduction task needs to sync on.
-     * \param [in]     useGpuFPmeReduction  Whether PME forces should be added
-     * \param [in]     accumulateForce      If the total force buffer already contains data
-     */
-    void atomdata_add_nbat_f_to_f_gpu(gmx::AtomLocality                          locality,
-                                      DeviceBuffer<gmx::RVec>                    totalForcesDevice,
-                                      void*                                      forcesPmeDevice,
-                                      gmx::ArrayRef<GpuEventSynchronizer* const> dependencyList,
-                                      bool useGpuFPmeReduction,
-                                      bool accumulateForce);
-
     /*! \brief Get the number of atoms for a given locality
      *
      * \param [in] locality   Local or non-local
      * \returns               The number of atoms for given locality
      */
-    int getNumAtoms(gmx::AtomLocality locality);
+    int getNumAtoms(gmx::AtomLocality locality) const;
 
     /*! \brief Get the pointer to the GPU nonbonded force buffer
      *
      * \returns A pointer to the force buffer in GPU memory
      */
-    void* getGpuForces();
+    DeviceBuffer<gmx::RVec> getGpuForces() const;
 
     //! Return the kernel setup
     const Nbnxm::KernelSetup& kernelSetup() const { return kernelSetup_; }
@@ -381,13 +411,12 @@ public:
     real pairlistOuterRadius() const;
 
     //! Changes the pair-list outer and inner radius
-    void changePairlistRadii(real rlistOuter, real rlistInner);
+    void changePairlistRadii(real rlistOuter, real rlistInner) const;
 
     //! Set up internal flags that indicate what type of short-range work there is.
-    void setupGpuShortRangeWork(const gmx::GpuBonded* gpuBonded, gmx::InteractionLocality iLocality);
+    void setupGpuShortRangeWork(const gmx::GpuBonded* gpuBonded, gmx::InteractionLocality iLocality) const;
 
     // TODO: Make all data members private
-public:
     //! All data related to the pair lists
     std::unique_ptr<PairlistSets> pairlistSets_;
     //! Working data for constructing the pairlists
@@ -411,13 +440,13 @@ namespace Nbnxm
 
 /*! \brief Creates an Nbnxm object */
 std::unique_ptr<nonbonded_verlet_t> init_nb_verlet(const gmx::MDLogger& mdlog,
-                                                   const t_inputrec*    ir,
-                                                   const t_forcerec*    fr,
-                                                   const t_commrec*     cr,
+                                                   const t_inputrec&    inputrec,
+                                                   const t_forcerec&    forcerec,
+                                                   const t_commrec*     commrec,
                                                    const gmx_hw_info_t& hardwareInfo,
                                                    bool                 useGpuForNonbonded,
                                                    const gmx::DeviceStreamManager* deviceStreamManager,
-                                                   const gmx_mtop_t*               mtop,
+                                                   const gmx_mtop_t&               mtop,
                                                    matrix                          box,
                                                    gmx_wallcycle*                  wcycle);
 
index 0df65f2bc55f327269619062f81785a5b7315a5e..68e60974d6f133a964af97afe70c80b7b8a3787c 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  */
 static inline int get_2log(int n)
 {
-    int log2;
-
-    log2 = 0;
-    while ((1 << log2) < n)
-    {
-        log2++;
-    }
-    if ((1 << log2) != n)
+    if (!gmx::isPowerOfTwo(n))
     {
         gmx_fatal(FARGS, "nbnxn na_c (%d) is not a power of 2", n);
     }
 
-    return log2;
+    return gmx::log2I(n);
 }
 
 namespace Nbnxm
@@ -78,19 +71,22 @@ namespace Nbnxm
 
 /*! \brief The nbnxn i-cluster size in atoms for each nbnxn kernel type */
 static constexpr gmx::EnumerationArray<KernelType, int> IClusterSizePerKernelType = {
-    { 0, c_nbnxnCpuIClusterSize, c_nbnxnCpuIClusterSize, c_nbnxnCpuIClusterSize,
-      c_nbnxnGpuClusterSize, c_nbnxnGpuClusterSize }
+    { 0, c_nbnxnCpuIClusterSize, c_nbnxnCpuIClusterSize, c_nbnxnCpuIClusterSize, c_nbnxnGpuClusterSize, c_nbnxnGpuClusterSize }
 };
 
 /*! \brief The nbnxn j-cluster size in atoms for each nbnxn kernel type */
 static constexpr gmx::EnumerationArray<KernelType, int> JClusterSizePerKernelType = {
-    { 0, c_nbnxnCpuIClusterSize,
+    { 0,
+      c_nbnxnCpuIClusterSize,
 #if GMX_SIMD
-      GMX_SIMD_REAL_WIDTH, GMX_SIMD_REAL_WIDTH / 2,
+      GMX_SIMD_REAL_WIDTH,
+      GMX_SIMD_REAL_WIDTH / 2,
 #else
-      0, 0,
+      0,
+      0,
 #endif
-      c_nbnxnGpuClusterSize, c_nbnxnGpuClusterSize / 2 }
+      c_nbnxnGpuClusterSize,
+      c_nbnxnGpuClusterSize / 2 }
 };
 
 /*! \brief Returns whether the pair-list corresponding to nb_kernel_type is simple */
index b18d16a7a46a2ed2b874bcad2038d44df3c6edc3..eb1becbf7d466605e365337e50d72b59e175f027 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,8 @@
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
+#include "nbnxm.h"
+
 struct interaction_const_t;
 struct nbnxn_atomdata_t;
 struct gmx_wallcycle;
@@ -62,52 +64,6 @@ class GpuBonded;
 class StepWorkload;
 } // namespace gmx
 
-/*! \brief Nbnxm electrostatic GPU kernel flavors.
- *
- *  Types of electrostatics implementations available in the GPU non-bonded
- *  force kernels. These represent both the electrostatics types implemented
- *  by the kernels (cut-off, RF, and Ewald - a subset of what's defined in
- *  enums.h) as well as encode implementation details analytical/tabulated
- *  and single or twin cut-off (for Ewald kernels).
- *  Note that the cut-off and RF kernels have only analytical flavor and unlike
- *  in the CPU kernels, the tabulated kernels are ATM Ewald-only.
- *
- *  The row-order of pointers to different electrostatic kernels defined in
- *  nbnxn_cuda.cu by the nb_*_kfunc_ptr function pointer table
- *  should match the order of enumerated types below.
- */
-enum eelType : int
-{
-    eelTypeCUT,
-    eelTypeRF,
-    eelTypeEWALD_TAB,
-    eelTypeEWALD_TAB_TWIN,
-    eelTypeEWALD_ANA,
-    eelTypeEWALD_ANA_TWIN,
-    eelTypeNR
-};
-
-/*! \brief Nbnxm VdW GPU kernel flavors.
- *
- * The enumerates values correspond to the LJ implementations in the GPU non-bonded
- * kernels.
- *
- * The column-order of pointers to different electrostatic kernels defined in
- * nbnxn_cuda_ocl.cpp/.cu by the nb_*_kfunc_ptr function pointer table
- * should match the order of enumerated types below.
- */
-enum evdwType : int
-{
-    evdwTypeCUT,
-    evdwTypeCUTCOMBGEOM,
-    evdwTypeCUTCOMBLB,
-    evdwTypeFSWITCH,
-    evdwTypePSWITCH,
-    evdwTypeEWALDGEOM,
-    evdwTypeEWALDLB,
-    evdwTypeNR
-};
-
 namespace Nbnxm
 {
 
@@ -115,14 +71,14 @@ class Grid;
 
 /*! \brief Returns true if LJ combination rules are used in the non-bonded kernels.
  *
- *  \param[in] vdwType  The VdW interaction/implementation type as defined by evdwType
+ *  \param[in] vdwType  The VdW interaction/implementation type as defined by VdwType
  *                      enumeration.
  *
  * \returns Whether combination rules are used by the run.
  */
-static inline bool useLjCombRule(const int vdwType)
+static inline bool useLjCombRule(const enum VdwType vdwType)
 {
-    return (vdwType == evdwTypeCUTCOMBGEOM || vdwType == evdwTypeCUTCOMBLB);
+    return (vdwType == VdwType::CutCombGeom || vdwType == VdwType::CutCombLB);
 }
 
 /*! \brief
@@ -277,14 +233,13 @@ float gpu_wait_finish_task(NbnxmGpu gmx_unused*    nb,
 
 /*! \brief Initialization for X buffer operations on GPU.
  * Called on the NS step and performs (re-)allocations and memory copies. !*/
-CUDA_FUNC_QUALIFIER
+GPU_FUNC_QUALIFIER
 void nbnxn_gpu_init_x_to_nbat_x(const Nbnxm::GridSet gmx_unused& gridSet,
-                                NbnxmGpu gmx_unused* gpu_nbv) CUDA_FUNC_TERM;
+                                NbnxmGpu gmx_unused* gpu_nbv) GPU_FUNC_TERM;
 
 /*! \brief X buffer operations on GPU: performs conversion from rvec to nb format.
  *
  * \param[in]     grid             Grid to be converted.
- * \param[in]     setFillerCoords  If the filler coordinates are used.
  * \param[in,out] gpu_nbv          The nonbonded data GPU structure.
  * \param[in]     d_x              Device-side coordinates in plain rvec format.
  * \param[in]     xReadyOnDevice   Event synchronizer indicating that the coordinates are ready in
@@ -292,24 +247,32 @@ void nbnxn_gpu_init_x_to_nbat_x(const Nbnxm::GridSet gmx_unused& gridSet,
  * \param[in]     locality         Copy coordinates for local or non-local atoms.
  * \param[in]     gridId           Index of the grid being converted.
  * \param[in]     numColumnsMax    Maximum number of columns in the grid.
+ * \param[in]     mustInsertNonLocalDependency Whether synchronization between local and non-local
+ * streams should be added. Typically, true if and only if that is the last grid in gridset.
  */
 CUDA_FUNC_QUALIFIER
 void nbnxn_gpu_x_to_nbat_x(const Nbnxm::Grid gmx_unused& grid,
-                           bool gmx_unused setFillerCoords,
                            NbnxmGpu gmx_unused*    gpu_nbv,
                            DeviceBuffer<gmx::RVec> gmx_unused d_x,
                            GpuEventSynchronizer gmx_unused* xReadyOnDevice,
                            gmx::AtomLocality gmx_unused locality,
                            int gmx_unused gridId,
-                           int gmx_unused numColumnsMax) CUDA_FUNC_TERM;
+                           int gmx_unused numColumnsMax,
+                           bool gmx_unused mustInsertNonLocalDependency) CUDA_FUNC_TERM;
 
 /*! \brief Sync the nonlocal stream with dependent tasks in the local queue.
+ *
+ *  As the point where the local stream tasks can be considered complete happens
+ *  at the same call point where the nonlocal stream should be synced with the
+ *  the local, this function records the event if called with the local stream as
+ *  argument and inserts in the GPU stream a wait on the event on the nonlocal.
+ *
  * \param[in] nb                   The nonbonded data GPU structure
  * \param[in] interactionLocality  Local or NonLocal sync point
  */
-CUDA_FUNC_QUALIFIER
-void nbnxnInsertNonlocalGpuDependency(const NbnxmGpu gmx_unused* nb,
-                                      gmx::InteractionLocality gmx_unused interactionLocality) CUDA_FUNC_TERM;
+GPU_FUNC_QUALIFIER
+void nbnxnInsertNonlocalGpuDependency(NbnxmGpu gmx_unused* nb,
+                                      gmx::InteractionLocality gmx_unused interactionLocality) GPU_FUNC_TERM;
 
 /*! \brief Set up internal flags that indicate what type of short-range work there is.
  *
@@ -328,32 +291,29 @@ void setupGpuShortRangeWork(NbnxmGpu gmx_unused* nb,
                             const gmx::GpuBonded gmx_unused* gpuBonded,
                             gmx::InteractionLocality gmx_unused iLocality) GPU_FUNC_TERM;
 
-/*! \brief Returns true if there is GPU short-range work for the given atom locality.
+/*! \brief Returns true if there is GPU short-range work for the given interaction locality.
  *
  * Note that as, unlike nonbonded tasks, bonded tasks are not split into local/nonlocal,
  * and therefore if there are GPU offloaded bonded interactions, this function will return
  * true for both local and nonlocal atom range.
  *
- * \param[inout]  nb        Pointer to the nonbonded GPU data structure
- * \param[in]     aLocality Atom locality identifier
+ * \param[inout]  nb                   Pointer to the nonbonded GPU data structure
+ * \param[in]     interactionLocality  Interaction locality identifier
+ *
+ * \return Whether there is short range work for a given locality.
  */
 GPU_FUNC_QUALIFIER
-bool haveGpuShortRangeWork(const NbnxmGpu gmx_unused* nb, gmx::AtomLocality gmx_unused aLocality)
+bool haveGpuShortRangeWork(const NbnxmGpu gmx_unused* nb, gmx::InteractionLocality gmx_unused interactionLocality)
         GPU_FUNC_TERM_WITH_RETURN(false);
 
-/*! \brief sync CPU thread on coordinate copy to device
- * \param[in] nb                   The nonbonded data GPU structure
- */
-CUDA_FUNC_QUALIFIER
-void nbnxn_wait_x_on_device(NbnxmGpu gmx_unused* nb) CUDA_FUNC_TERM;
-
 /*! \brief Get the pointer to the GPU nonbonded force buffer
  *
  * \param[in] nb  The nonbonded data GPU structure
  * \returns       A pointer to the force buffer in GPU memory
  */
 CUDA_FUNC_QUALIFIER
-void* getGpuForces(NbnxmGpu gmx_unused* nb) CUDA_FUNC_TERM_WITH_RETURN(nullptr);
+DeviceBuffer<gmx::RVec> getGpuForces(NbnxmGpu gmx_unused* nb)
+        CUDA_FUNC_TERM_WITH_RETURN(DeviceBuffer<gmx::RVec>{});
 
 } // namespace Nbnxm
 #endif
index 8c8fd338a19cf14ed8100680d1789c3713439860..ce93e61e01f5988e26056fbd0ac16140684b3c3a 100644 (file)
 #    include "opencl/nbnxm_ocl_types.h"
 #endif
 
+#if GMX_GPU_SYCL
+#    include "sycl/nbnxm_sycl_types.h"
+#endif
+
 #include "nbnxm_gpu_data_mgmt.h"
 
+#include "gromacs/gpu_utils/device_stream_manager.h"
+#include "gromacs/gpu_utils/gputraits.h"
+#include "gromacs/gpu_utils/pmalloc.h"
 #include "gromacs/hardware/device_information.h"
+#include "gromacs/mdtypes/interaction_const.h"
+#include "gromacs/mdtypes/simulation_workload.h"
+#include "gromacs/nbnxm/gpu_common_utils.h"
 #include "gromacs/nbnxm/gpu_data_mgmt.h"
+#include "gromacs/nbnxm/gridset.h"
+#include "gromacs/pbcutil/ishift.h"
 #include "gromacs/timing/gpu_timing.h"
+#include "gromacs/pbcutil/ishift.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/fatalerror.h"
 
 #include "nbnxm_gpu.h"
 #include "pairlistsets.h"
 namespace Nbnxm
 {
 
-void init_ewald_coulomb_force_table(const EwaldCorrectionTables& tables,
-                                    NBParamGpu*                  nbp,
-                                    const DeviceContext&         deviceContext)
+static inline void issueClFlushInStream(const DeviceStream& deviceStream)
 {
-    if (nbp->coulomb_tab)
+#if GMX_GPU_OPENCL
+    /* Based on the v1.2 section 5.13 of the OpenCL spec, a flush is needed
+     * in the stream after marking an event in it in order to be able to sync with
+     * the event from another stream.
+     */
+    cl_int cl_error = clFlush(deviceStream.stream());
+    if (cl_error != CL_SUCCESS)
     {
-        destroyParamLookupTable(&nbp->coulomb_tab, nbp->coulomb_tab_texobj);
+        GMX_THROW(gmx::InternalError("clFlush failed: " + ocl_get_error_string(cl_error)));
     }
-
-    nbp->coulomb_tab_scale = tables.scale;
-    initParamLookupTable(&nbp->coulomb_tab, &nbp->coulomb_tab_texobj, tables.tableF.data(),
-                         tables.tableF.size(), deviceContext);
+#else
+    GMX_UNUSED_VALUE(deviceStream);
+#endif
 }
 
-void inline printEnvironmentVariableDeprecationMessage(bool               isEnvironmentVariableSet,
-                                                       const std::string& environmentVariableSuffix)
+static inline void init_ewald_coulomb_force_table(const EwaldCorrectionTables& tables,
+                                                  NBParamGpu*                  nbp,
+                                                  const DeviceContext&         deviceContext)
 {
-    if (isEnvironmentVariableSet)
+    if (nbp->coulomb_tab)
     {
-        fprintf(stderr,
-                "Environment variables GMX_CUDA_%s and GMX_OCL_%s are deprecated and will be\n"
-                "removed in release 2022, please use GMX_GPU_%s instead.",
-                environmentVariableSuffix.c_str(), environmentVariableSuffix.c_str(),
-                environmentVariableSuffix.c_str());
+        destroyParamLookupTable(&nbp->coulomb_tab, nbp->coulomb_tab_texobj);
     }
+
+    nbp->coulomb_tab_scale = tables.scale;
+    initParamLookupTable(
+            &nbp->coulomb_tab, &nbp->coulomb_tab_texobj, tables.tableF.data(), tables.tableF.size(), deviceContext);
 }
 
-int nbnxn_gpu_pick_ewald_kernel_type(const interaction_const_t& ic,
-                                     const DeviceInformation gmx_unused& deviceInfo)
+static inline ElecType nbnxn_gpu_pick_ewald_kernel_type(const interaction_const_t& ic,
+                                                        const DeviceInformation gmx_unused& deviceInfo)
 {
     bool bTwinCut = (ic.rcoulomb != ic.rvdw);
-    int  kernel_type;
 
     /* Benchmarking/development environment variables to force the use of
        analytical or tabulated Ewald kernel. */
-
-    // Remove these when old environment variables are deprecated
-    const bool forceAnalyticalEwaldLegacy = (getenv("GMX_CUDA_NB_ANA_EWALD") != nullptr)
-                                            || (getenv("GMX_OCL_NB_ANA_EWALD") != nullptr);
-    const bool forceTabulatedEwaldLegacy = (getenv("GMX_CUDA_NB_TAB_EWALD") != nullptr)
-                                           || (getenv("GMX_OCL_NB_TAB_EWALD") != nullptr);
-    const bool forceTwinCutoffEwaldLegacy = (getenv("GMX_CUDA_NB_EWALD_TWINCUT") != nullptr)
-                                            || (getenv("GMX_OCL_NB_EWALD_TWINCUT") != nullptr);
-
-    printEnvironmentVariableDeprecationMessage(forceAnalyticalEwaldLegacy, "NB_ANA_EWALD");
-    printEnvironmentVariableDeprecationMessage(forceTabulatedEwaldLegacy, "NB_TAB_EWALD");
-    printEnvironmentVariableDeprecationMessage(forceTwinCutoffEwaldLegacy, "NB_EWALD_TWINCUT");
-
-    const bool forceAnalyticalEwald =
-            (getenv("GMX_GPU_NB_ANA_EWALD") != nullptr) || forceAnalyticalEwaldLegacy;
-    const bool forceTabulatedEwald =
-            (getenv("GMX_GPU_NB_TAB_EWALD") != nullptr) || forceTabulatedEwaldLegacy;
-    const bool forceTwinCutoffEwald =
-            (getenv("GMX_GPU_NB_EWALD_TWINCUT") != nullptr) || forceTwinCutoffEwaldLegacy;
+    const bool forceAnalyticalEwald = (getenv("GMX_GPU_NB_ANA_EWALD") != nullptr);
+    const bool forceTabulatedEwald  = (getenv("GMX_GPU_NB_TAB_EWALD") != nullptr);
+    const bool forceTwinCutoffEwald = (getenv("GMX_GPU_NB_EWALD_TWINCUT") != nullptr);
 
     if (forceAnalyticalEwald && forceTabulatedEwald)
     {
@@ -163,56 +165,39 @@ int nbnxn_gpu_pick_ewald_kernel_type(const interaction_const_t& ic,
        forces it (use it for debugging/benchmarking only). */
     if (!bTwinCut && !forceTwinCutoffEwald)
     {
-        kernel_type = bUseAnalyticalEwald ? eelTypeEWALD_ANA : eelTypeEWALD_TAB;
+        return bUseAnalyticalEwald ? ElecType::EwaldAna : ElecType::EwaldTab;
     }
     else
     {
-        kernel_type = bUseAnalyticalEwald ? eelTypeEWALD_ANA_TWIN : eelTypeEWALD_TAB_TWIN;
+        return bUseAnalyticalEwald ? ElecType::EwaldAnaTwin : ElecType::EwaldTabTwin;
     }
-
-    return kernel_type;
 }
 
-void set_cutoff_parameters(NBParamGpu* nbp, const interaction_const_t* ic, const PairlistParams& listParams)
+static inline void set_cutoff_parameters(NBParamGpu*                nbp,
+                                         const interaction_const_t& ic,
+                                         const PairlistParams&      listParams)
 {
-    nbp->ewald_beta        = ic->ewaldcoeff_q;
-    nbp->sh_ewald          = ic->sh_ewald;
-    nbp->epsfac            = ic->epsfac;
-    nbp->two_k_rf          = 2.0 * ic->k_rf;
-    nbp->c_rf              = ic->c_rf;
-    nbp->rvdw_sq           = ic->rvdw * ic->rvdw;
-    nbp->rcoulomb_sq       = ic->rcoulomb * ic->rcoulomb;
+    nbp->ewald_beta        = ic.ewaldcoeff_q;
+    nbp->sh_ewald          = ic.sh_ewald;
+    nbp->epsfac            = ic.epsfac;
+    nbp->two_k_rf          = 2.0 * ic.reactionFieldCoefficient;
+    nbp->c_rf              = ic.reactionFieldShift;
+    nbp->rvdw_sq           = ic.rvdw * ic.rvdw;
+    nbp->rcoulomb_sq       = ic.rcoulomb * ic.rcoulomb;
     nbp->rlistOuter_sq     = listParams.rlistOuter * listParams.rlistOuter;
     nbp->rlistInner_sq     = listParams.rlistInner * listParams.rlistInner;
     nbp->useDynamicPruning = listParams.useDynamicPruning;
 
-    nbp->sh_lj_ewald   = ic->sh_lj_ewald;
-    nbp->ewaldcoeff_lj = ic->ewaldcoeff_lj;
+    nbp->sh_lj_ewald   = ic.sh_lj_ewald;
+    nbp->ewaldcoeff_lj = ic.ewaldcoeff_lj;
 
-    nbp->rvdw_switch      = ic->rvdw_switch;
-    nbp->dispersion_shift = ic->dispersion_shift;
-    nbp->repulsion_shift  = ic->repulsion_shift;
-    nbp->vdw_switch       = ic->vdw_switch;
+    nbp->rvdw_switch      = ic.rvdw_switch;
+    nbp->dispersion_shift = ic.dispersion_shift;
+    nbp->repulsion_shift  = ic.repulsion_shift;
+    nbp->vdw_switch       = ic.vdw_switch;
 }
 
-void gpu_pme_loadbal_update_param(const nonbonded_verlet_t* nbv, const interaction_const_t* ic)
-{
-    if (!nbv || !nbv->useGpu())
-    {
-        return;
-    }
-    NbnxmGpu*   nb  = nbv->gpu_nbv;
-    NBParamGpu* nbp = nb->nbparam;
-
-    set_cutoff_parameters(nbp, ic, nbv->pairlistSets().params());
-
-    nbp->eeltype = nbnxn_gpu_pick_ewald_kernel_type(*ic, nb->deviceContext_->deviceInfo());
-
-    GMX_RELEASE_ASSERT(ic->coulombEwaldTables, "Need valid Coulomb Ewald correction tables");
-    init_ewald_coulomb_force_table(*ic->coulombEwaldTables, nbp, *nb->deviceContext_);
-}
-
-void init_plist(gpu_plist* pl)
+static inline void init_plist(gpu_plist* pl)
 {
     /* initialize to nullptr pointers to data that is not allocated here and will
        need reallocation in nbnxn_gpu_init_pairlist */
@@ -236,18 +221,16 @@ void init_plist(gpu_plist* pl)
     pl->rollingPruningPart     = 0;
 }
 
-void init_timings(gmx_wallclock_gpu_nbnxn_t* t)
+static inline void init_timings(gmx_wallclock_gpu_nbnxn_t* t)
 {
-    int i, j;
-
     t->nb_h2d_t = 0.0;
     t->nb_d2h_t = 0.0;
     t->nb_c     = 0;
     t->pl_h2d_t = 0.0;
     t->pl_h2d_c = 0;
-    for (i = 0; i < 2; i++)
+    for (int i = 0; i < 2; i++)
     {
-        for (j = 0; j < 2; j++)
+        for (int j = 0; j < 2; j++)
         {
             t->ktime[i][j].t = 0.0;
             t->ktime[i][j].c = 0;
@@ -259,6 +242,290 @@ void init_timings(gmx_wallclock_gpu_nbnxn_t* t)
     t->dynamicPruneTime.t = 0.0;
 }
 
+/*! \brief Initialize \p atomdata first time; it only gets filled at pair-search. */
+static inline void initAtomdataFirst(NBAtomDataGpu*       atomdata,
+                                     int                  numTypes,
+                                     const DeviceContext& deviceContext,
+                                     const DeviceStream&  localStream)
+{
+    atomdata->numTypes = numTypes;
+    allocateDeviceBuffer(&atomdata->shiftVec, gmx::c_numShiftVectors, deviceContext);
+    atomdata->shiftVecUploaded = false;
+
+    allocateDeviceBuffer(&atomdata->fShift, gmx::c_numShiftVectors, deviceContext);
+    allocateDeviceBuffer(&atomdata->eLJ, 1, deviceContext);
+    allocateDeviceBuffer(&atomdata->eElec, 1, deviceContext);
+
+    clearDeviceBufferAsync(&atomdata->fShift, 0, gmx::c_numShiftVectors, localStream);
+    clearDeviceBufferAsync(&atomdata->eElec, 0, 1, localStream);
+    clearDeviceBufferAsync(&atomdata->eLJ, 0, 1, localStream);
+
+    /* initialize to nullptr pointers to data that is not allocated here and will
+       need reallocation in later */
+    atomdata->xq = nullptr;
+    atomdata->f  = nullptr;
+
+    /* size -1 indicates that the respective array hasn't been initialized yet */
+    atomdata->numAtoms      = -1;
+    atomdata->numAtomsAlloc = -1;
+}
+
+static inline VdwType nbnxmGpuPickVdwKernelType(const interaction_const_t& ic,
+                                                LJCombinationRule          ljCombinationRule)
+{
+    if (ic.vdwtype == VanDerWaalsType::Cut)
+    {
+        switch (ic.vdw_modifier)
+        {
+            case InteractionModifiers::None:
+            case InteractionModifiers::PotShift:
+                switch (ljCombinationRule)
+                {
+                    case LJCombinationRule::None: return VdwType::Cut;
+                    case LJCombinationRule::Geometric: return VdwType::CutCombGeom;
+                    case LJCombinationRule::LorentzBerthelot: return VdwType::CutCombLB;
+                    default:
+                        GMX_THROW(gmx::InconsistentInputError(gmx::formatString(
+                                "The requested LJ combination rule %s is not implemented in "
+                                "the GPU accelerated kernels!",
+                                enumValueToString(ljCombinationRule))));
+                }
+            case InteractionModifiers::ForceSwitch: return VdwType::FSwitch;
+            case InteractionModifiers::PotSwitch: return VdwType::PSwitch;
+            default:
+                GMX_THROW(gmx::InconsistentInputError(
+                        gmx::formatString("The requested VdW interaction modifier %s is not "
+                                          "implemented in the GPU accelerated kernels!",
+                                          enumValueToString(ic.vdw_modifier))));
+        }
+    }
+    else if (ic.vdwtype == VanDerWaalsType::Pme)
+    {
+        if (ic.ljpme_comb_rule == LongRangeVdW::Geom)
+        {
+            GMX_RELEASE_ASSERT(
+                    ljCombinationRule == LJCombinationRule::Geometric,
+                    "Combination rules for long- and short-range interactions should match.");
+            return VdwType::EwaldGeom;
+        }
+        else
+        {
+            GMX_RELEASE_ASSERT(
+                    ljCombinationRule == LJCombinationRule::LorentzBerthelot,
+                    "Combination rules for long- and short-range interactions should match.");
+            return VdwType::EwaldLB;
+        }
+    }
+    else
+    {
+        GMX_THROW(gmx::InconsistentInputError(gmx::formatString(
+                "The requested VdW type %s is not implemented in the GPU accelerated kernels!",
+                enumValueToString(ic.vdwtype))));
+    }
+}
+
+static inline ElecType nbnxmGpuPickElectrostaticsKernelType(const interaction_const_t& ic,
+                                                            const DeviceInformation&   deviceInfo)
+{
+    if (ic.eeltype == CoulombInteractionType::Cut)
+    {
+        return ElecType::Cut;
+    }
+    else if (EEL_RF(ic.eeltype))
+    {
+        return ElecType::RF;
+    }
+    else if ((EEL_PME(ic.eeltype) || ic.eeltype == CoulombInteractionType::Ewald))
+    {
+        return nbnxn_gpu_pick_ewald_kernel_type(ic, deviceInfo);
+    }
+    else
+    {
+        /* Shouldn't happen, as this is checked when choosing Verlet-scheme */
+        GMX_THROW(gmx::InconsistentInputError(
+                gmx::formatString("The requested electrostatics type %s is not implemented in "
+                                  "the GPU accelerated kernels!",
+                                  enumValueToString(ic.eeltype))));
+    }
+}
+
+/*! \brief Initialize the nonbonded parameter data structure. */
+static inline void initNbparam(NBParamGpu*                     nbp,
+                               const interaction_const_t&      ic,
+                               const PairlistParams&           listParams,
+                               const nbnxn_atomdata_t::Params& nbatParams,
+                               const DeviceContext&            deviceContext)
+{
+    const int numTypes = nbatParams.numTypes;
+
+    set_cutoff_parameters(nbp, ic, listParams);
+
+    nbp->vdwType  = nbnxmGpuPickVdwKernelType(ic, nbatParams.ljCombinationRule);
+    nbp->elecType = nbnxmGpuPickElectrostaticsKernelType(ic, deviceContext.deviceInfo());
+
+    if (ic.vdwtype == VanDerWaalsType::Pme)
+    {
+        if (ic.ljpme_comb_rule == LongRangeVdW::Geom)
+        {
+            GMX_ASSERT(nbatParams.ljCombinationRule == LJCombinationRule::Geometric,
+                       "Combination rule mismatch!");
+        }
+        else
+        {
+            GMX_ASSERT(nbatParams.ljCombinationRule == LJCombinationRule::LorentzBerthelot,
+                       "Combination rule mismatch!");
+        }
+    }
+
+    /* generate table for PME */
+    if (nbp->elecType == ElecType::EwaldTab || nbp->elecType == ElecType::EwaldTabTwin)
+    {
+        GMX_RELEASE_ASSERT(ic.coulombEwaldTables, "Need valid Coulomb Ewald correction tables");
+        init_ewald_coulomb_force_table(*ic.coulombEwaldTables, nbp, deviceContext);
+    }
+
+    /* set up LJ parameter lookup table */
+    if (!useLjCombRule(nbp->vdwType))
+    {
+        static_assert(sizeof(decltype(nbp->nbfp)) == 2 * sizeof(decltype(*nbatParams.nbfp.data())),
+                      "Mismatch in the size of host / device data types");
+        initParamLookupTable(&nbp->nbfp,
+                             &nbp->nbfp_texobj,
+                             reinterpret_cast<const Float2*>(nbatParams.nbfp.data()),
+                             numTypes * numTypes,
+                             deviceContext);
+    }
+
+    /* set up LJ-PME parameter lookup table */
+    if (ic.vdwtype == VanDerWaalsType::Pme)
+    {
+        static_assert(sizeof(decltype(nbp->nbfp_comb))
+                              == 2 * sizeof(decltype(*nbatParams.nbfp_comb.data())),
+                      "Mismatch in the size of host / device data types");
+        initParamLookupTable(&nbp->nbfp_comb,
+                             &nbp->nbfp_comb_texobj,
+                             reinterpret_cast<const Float2*>(nbatParams.nbfp_comb.data()),
+                             numTypes,
+                             deviceContext);
+    }
+}
+
+NbnxmGpu* gpu_init(const gmx::DeviceStreamManager& deviceStreamManager,
+                   const interaction_const_t*      ic,
+                   const PairlistParams&           listParams,
+                   const nbnxn_atomdata_t*         nbat,
+                   const bool                      bLocalAndNonlocal)
+{
+    auto* nb                              = new NbnxmGpu();
+    nb->deviceContext_                    = &deviceStreamManager.context();
+    nb->atdat                             = new NBAtomDataGpu;
+    nb->nbparam                           = new NBParamGpu;
+    nb->plist[InteractionLocality::Local] = new Nbnxm::gpu_plist;
+    if (bLocalAndNonlocal)
+    {
+        nb->plist[InteractionLocality::NonLocal] = new Nbnxm::gpu_plist;
+    }
+
+    nb->bUseTwoStreams = bLocalAndNonlocal;
+
+    nb->timers = new Nbnxm::GpuTimers();
+    snew(nb->timings, 1);
+
+    /* WARNING: CUDA timings are incorrect with multiple streams.
+     * This is the main reason why they are disabled by default.
+     * Can be enabled by setting GMX_ENABLE_GPU_TIMING environment variable.
+     * TODO: Consider turning on by default when we can detect nr of streams.
+     *
+     * OpenCL timing is enabled by default and can be disabled by
+     * GMX_DISABLE_GPU_TIMING environment variable.
+     *
+     * Timing is disabled in SYCL.
+     */
+    nb->bDoTime = (GMX_GPU_CUDA && (getenv("GMX_ENABLE_GPU_TIMING") != nullptr))
+                  || (GMX_GPU_OPENCL && (getenv("GMX_DISABLE_GPU_TIMING") == nullptr));
+
+    if (nb->bDoTime)
+    {
+        init_timings(nb->timings);
+    }
+
+    /* init nbst */
+    pmalloc(reinterpret_cast<void**>(&nb->nbst.eLJ), sizeof(*nb->nbst.eLJ));
+    pmalloc(reinterpret_cast<void**>(&nb->nbst.eElec), sizeof(*nb->nbst.eElec));
+    pmalloc(reinterpret_cast<void**>(&nb->nbst.fShift), gmx::c_numShiftVectors * sizeof(*nb->nbst.fShift));
+
+    init_plist(nb->plist[InteractionLocality::Local]);
+
+    /* local/non-local GPU streams */
+    GMX_RELEASE_ASSERT(deviceStreamManager.streamIsValid(gmx::DeviceStreamType::NonBondedLocal),
+                       "Local non-bonded stream should be initialized to use GPU for non-bonded.");
+    const DeviceStream& localStream = deviceStreamManager.stream(gmx::DeviceStreamType::NonBondedLocal);
+    nb->deviceStreams[InteractionLocality::Local] = &localStream;
+    // In general, it's not strictly necessary to use 2 streams for SYCL, since they are
+    // out-of-order. But for the time being, it will be less disruptive to keep them.
+    if (nb->bUseTwoStreams)
+    {
+        init_plist(nb->plist[InteractionLocality::NonLocal]);
+
+        GMX_RELEASE_ASSERT(deviceStreamManager.streamIsValid(gmx::DeviceStreamType::NonBondedNonLocal),
+                           "Non-local non-bonded stream should be initialized to use GPU for "
+                           "non-bonded with domain decomposition.");
+        nb->deviceStreams[InteractionLocality::NonLocal] =
+                &deviceStreamManager.stream(gmx::DeviceStreamType::NonBondedNonLocal);
+    }
+
+    const nbnxn_atomdata_t::Params& nbatParams    = nbat->params();
+    const DeviceContext&            deviceContext = *nb->deviceContext_;
+
+    initNbparam(nb->nbparam, *ic, listParams, nbatParams, deviceContext);
+    initAtomdataFirst(nb->atdat, nbatParams.numTypes, deviceContext, localStream);
+
+    gpu_init_platform_specific(nb);
+
+    if (debug)
+    {
+        fprintf(debug, "Initialized NBNXM GPU data structures.\n");
+    }
+
+    return nb;
+}
+
+void gpu_pme_loadbal_update_param(const nonbonded_verlet_t* nbv, const interaction_const_t& ic)
+{
+    if (!nbv || !nbv->useGpu())
+    {
+        return;
+    }
+    NbnxmGpu*   nb  = nbv->gpu_nbv;
+    NBParamGpu* nbp = nb->nbparam;
+
+    set_cutoff_parameters(nbp, ic, nbv->pairlistSets().params());
+
+    nbp->elecType = nbnxn_gpu_pick_ewald_kernel_type(ic, nb->deviceContext_->deviceInfo());
+
+    GMX_RELEASE_ASSERT(ic.coulombEwaldTables, "Need valid Coulomb Ewald correction tables");
+    init_ewald_coulomb_force_table(*ic.coulombEwaldTables, nbp, *nb->deviceContext_);
+}
+
+void gpu_upload_shiftvec(NbnxmGpu* nb, const nbnxn_atomdata_t* nbatom)
+{
+    NBAtomDataGpu*      adat        = nb->atdat;
+    const DeviceStream& localStream = *nb->deviceStreams[InteractionLocality::Local];
+
+    /* only if we have a dynamic box */
+    if (nbatom->bDynamicBox || !adat->shiftVecUploaded)
+    {
+        copyToDeviceBuffer(&adat->shiftVec,
+                           gmx::asGenericFloat3Pointer(nbatom->shift_vec),
+                           0,
+                           gmx::c_numShiftVectors,
+                           localStream,
+                           GpuApiCallBehavior::Async,
+                           nullptr);
+        adat->shiftVecUploaded = true;
+    }
+}
+
 //! This function is documented in the header file
 void gpu_init_pairlist(NbnxmGpu* nb, const NbnxnPairlistGpu* h_plist, const InteractionLocality iloc)
 {
@@ -278,13 +545,15 @@ void gpu_init_pairlist(NbnxmGpu* nb, const NbnxnPairlistGpu* h_plist, const Inte
     {
         if (d_plist->na_c != h_plist->na_ci)
         {
-            sprintf(sbuf, "In init_plist: the #atoms per cell has changed (from %d to %d)",
-                    d_plist->na_c, h_plist->na_ci);
+            sprintf(sbuf,
+                    "In init_plist: the #atoms per cell has changed (from %d to %d)",
+                    d_plist->na_c,
+                    h_plist->na_ci);
             gmx_incons(sbuf);
         }
     }
 
-    gpu_timers_t::Interaction& iTimers = nb->timers->interaction[iloc];
+    GpuTimers::Interaction& iTimers = nb->timers->interaction[iloc];
 
     if (bDoTime)
     {
@@ -295,23 +564,41 @@ void gpu_init_pairlist(NbnxmGpu* nb, const NbnxnPairlistGpu* h_plist, const Inte
     // TODO most of this function is same in CUDA and OpenCL, move into the header
     const DeviceContext& deviceContext = *nb->deviceContext_;
 
-    reallocateDeviceBuffer(&d_plist->sci, h_plist->sci.size(), &d_plist->nsci, &d_plist->sci_nalloc,
-                           deviceContext);
-    copyToDeviceBuffer(&d_plist->sci, h_plist->sci.data(), 0, h_plist->sci.size(), deviceStream,
-                       GpuApiCallBehavior::Async, bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
+    reallocateDeviceBuffer(
+            &d_plist->sci, h_plist->sci.size(), &d_plist->nsci, &d_plist->sci_nalloc, deviceContext);
+    copyToDeviceBuffer(&d_plist->sci,
+                       h_plist->sci.data(),
+                       0,
+                       h_plist->sci.size(),
+                       deviceStream,
+                       GpuApiCallBehavior::Async,
+                       bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
 
-    reallocateDeviceBuffer(&d_plist->cj4, h_plist->cj4.size(), &d_plist->ncj4, &d_plist->cj4_nalloc,
-                           deviceContext);
-    copyToDeviceBuffer(&d_plist->cj4, h_plist->cj4.data(), 0, h_plist->cj4.size(), deviceStream,
-                       GpuApiCallBehavior::Async, bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
+    reallocateDeviceBuffer(
+            &d_plist->cj4, h_plist->cj4.size(), &d_plist->ncj4, &d_plist->cj4_nalloc, deviceContext);
+    copyToDeviceBuffer(&d_plist->cj4,
+                       h_plist->cj4.data(),
+                       0,
+                       h_plist->cj4.size(),
+                       deviceStream,
+                       GpuApiCallBehavior::Async,
+                       bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
 
-    reallocateDeviceBuffer(&d_plist->imask, h_plist->cj4.size() * c_nbnxnGpuClusterpairSplit,
-                           &d_plist->nimask, &d_plist->imask_nalloc, deviceContext);
+    reallocateDeviceBuffer(&d_plist->imask,
+                           h_plist->cj4.size() * c_nbnxnGpuClusterpairSplit,
+                           &d_plist->nimask,
+                           &d_plist->imask_nalloc,
+                           deviceContext);
 
-    reallocateDeviceBuffer(&d_plist->excl, h_plist->excl.size(), &d_plist->nexcl,
-                           &d_plist->excl_nalloc, deviceContext);
-    copyToDeviceBuffer(&d_plist->excl, h_plist->excl.data(), 0, h_plist->excl.size(), deviceStream,
-                       GpuApiCallBehavior::Async, bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
+    reallocateDeviceBuffer(
+            &d_plist->excl, h_plist->excl.size(), &d_plist->nexcl, &d_plist->excl_nalloc, deviceContext);
+    copyToDeviceBuffer(&d_plist->excl,
+                       h_plist->excl.data(),
+                       0,
+                       h_plist->excl.size(),
+                       deviceStream,
+                       GpuApiCallBehavior::Async,
+                       bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
 
     if (bDoTime)
     {
@@ -322,6 +609,122 @@ void gpu_init_pairlist(NbnxmGpu* nb, const NbnxnPairlistGpu* h_plist, const Inte
     d_plist->haveFreshList = true;
 }
 
+void gpu_init_atomdata(NbnxmGpu* nb, const nbnxn_atomdata_t* nbat)
+{
+    bool                 bDoTime       = nb->bDoTime;
+    Nbnxm::GpuTimers*    timers        = bDoTime ? nb->timers : nullptr;
+    NBAtomDataGpu*       atdat         = nb->atdat;
+    const DeviceContext& deviceContext = *nb->deviceContext_;
+    const DeviceStream&  localStream   = *nb->deviceStreams[InteractionLocality::Local];
+
+    int  numAtoms  = nbat->numAtoms();
+    bool realloced = false;
+
+    if (bDoTime)
+    {
+        /* time async copy */
+        timers->atdat.openTimingRegion(localStream);
+    }
+
+    /* need to reallocate if we have to copy more atoms than the amount of space
+       available and only allocate if we haven't initialized yet, i.e atdat->natoms == -1 */
+    if (numAtoms > atdat->numAtomsAlloc)
+    {
+        int numAlloc = over_alloc_small(numAtoms);
+
+        /* free up first if the arrays have already been initialized */
+        if (atdat->numAtomsAlloc != -1)
+        {
+            freeDeviceBuffer(&atdat->f);
+            freeDeviceBuffer(&atdat->xq);
+            if (useLjCombRule(nb->nbparam->vdwType))
+            {
+                freeDeviceBuffer(&atdat->ljComb);
+            }
+            else
+            {
+                freeDeviceBuffer(&atdat->atomTypes);
+            }
+        }
+
+
+        allocateDeviceBuffer(&atdat->f, numAlloc, deviceContext);
+        allocateDeviceBuffer(&atdat->xq, numAlloc, deviceContext);
+
+        if (useLjCombRule(nb->nbparam->vdwType))
+        {
+            // Two Lennard-Jones parameters per atom
+            allocateDeviceBuffer(&atdat->ljComb, numAlloc, deviceContext);
+        }
+        else
+        {
+            allocateDeviceBuffer(&atdat->atomTypes, numAlloc, deviceContext);
+        }
+
+        atdat->numAtomsAlloc = numAlloc;
+        realloced            = true;
+    }
+
+    atdat->numAtoms      = numAtoms;
+    atdat->numAtomsLocal = nbat->natoms_local;
+
+    /* need to clear GPU f output if realloc happened */
+    if (realloced)
+    {
+        clearDeviceBufferAsync(&atdat->f, 0, atdat->numAtomsAlloc, localStream);
+    }
+
+    if (useLjCombRule(nb->nbparam->vdwType))
+    {
+        static_assert(
+                sizeof(Float2) == 2 * sizeof(*nbat->params().lj_comb.data()),
+                "Size of a pair of LJ parameters elements should be equal to the size of Float2.");
+        copyToDeviceBuffer(&atdat->ljComb,
+                           reinterpret_cast<const Float2*>(nbat->params().lj_comb.data()),
+                           0,
+                           numAtoms,
+                           localStream,
+                           GpuApiCallBehavior::Async,
+                           bDoTime ? timers->atdat.fetchNextEvent() : nullptr);
+    }
+    else
+    {
+        static_assert(sizeof(int) == sizeof(*nbat->params().type.data()),
+                      "Sizes of host- and device-side atom types should be the same.");
+        copyToDeviceBuffer(&atdat->atomTypes,
+                           nbat->params().type.data(),
+                           0,
+                           numAtoms,
+                           localStream,
+                           GpuApiCallBehavior::Async,
+                           bDoTime ? timers->atdat.fetchNextEvent() : nullptr);
+    }
+
+    if (bDoTime)
+    {
+        timers->atdat.closeTimingRegion(localStream);
+    }
+
+    /* kick off the tasks enqueued above to ensure concurrency with the search */
+    issueClFlushInStream(localStream);
+}
+
+void gpu_clear_outputs(NbnxmGpu* nb, bool computeVirial)
+{
+    NBAtomDataGpu*      adat        = nb->atdat;
+    const DeviceStream& localStream = *nb->deviceStreams[InteractionLocality::Local];
+    // Clear forces
+    clearDeviceBufferAsync(&adat->f, 0, nb->atdat->numAtoms, localStream);
+    // Clear shift force array and energies if the outputs were used in the current step
+    if (computeVirial)
+    {
+        clearDeviceBufferAsync(&adat->fShift, 0, gmx::c_numShiftVectors, localStream);
+        clearDeviceBufferAsync(&adat->eLJ, 0, 1, localStream);
+        clearDeviceBufferAsync(&adat->eElec, 0, 1, localStream);
+    }
+    issueClFlushInStream(localStream);
+}
+
 //! This function is documented in the header file
 gmx_wallclock_gpu_nbnxn_t* gpu_get_timings(NbnxmGpu* nb)
 {
@@ -339,7 +742,444 @@ void gpu_reset_timings(nonbonded_verlet_t* nbv)
 
 bool gpu_is_kernel_ewald_analytical(const NbnxmGpu* nb)
 {
-    return ((nb->nbparam->eeltype == eelTypeEWALD_ANA) || (nb->nbparam->eeltype == eelTypeEWALD_ANA_TWIN));
+    return ((nb->nbparam->elecType == ElecType::EwaldAna)
+            || (nb->nbparam->elecType == ElecType::EwaldAnaTwin));
+}
+
+void setupGpuShortRangeWork(NbnxmGpu* nb, const gmx::GpuBonded* gpuBonded, const gmx::InteractionLocality iLocality)
+{
+    GMX_ASSERT(nb, "Need a valid nbnxn_gpu object");
+
+    // There is short-range work if the pair list for the provided
+    // interaction locality contains entries or if there is any
+    // bonded work (as this is not split into local/nonlocal).
+    nb->haveWork[iLocality] = ((nb->plist[iLocality]->nsci != 0)
+                               || (gpuBonded != nullptr && gpuBonded->haveInteractions()));
+}
+
+bool haveGpuShortRangeWork(const NbnxmGpu* nb, const gmx::InteractionLocality interactionLocality)
+{
+    GMX_ASSERT(nb, "Need a valid nbnxn_gpu object");
+
+    return nb->haveWork[interactionLocality];
+}
+
+/*! \brief
+ * Launch asynchronously the download of nonbonded forces from the GPU
+ * (and energies/shift forces if required).
+ */
+void gpu_launch_cpyback(NbnxmGpu*                nb,
+                        struct nbnxn_atomdata_t* nbatom,
+                        const gmx::StepWorkload& stepWork,
+                        const AtomLocality       atomLocality)
+{
+    GMX_ASSERT(nb, "Need a valid nbnxn_gpu object");
+
+    /* determine interaction locality from atom locality */
+    const InteractionLocality iloc = atomToInteractionLocality(atomLocality);
+    GMX_ASSERT(iloc == InteractionLocality::Local
+                       || (iloc == InteractionLocality::NonLocal && nb->bNonLocalStreamDoneMarked == false),
+               "Non-local stream is indicating that the copy back event is enqueued at the "
+               "beginning of the copy back function.");
+
+    /* extract the data */
+    NBAtomDataGpu*      adat         = nb->atdat;
+    Nbnxm::GpuTimers*   timers       = nb->timers;
+    bool                bDoTime      = nb->bDoTime;
+    const DeviceStream& deviceStream = *nb->deviceStreams[iloc];
+
+    /* don't launch non-local copy-back if there was no non-local work to do */
+    if ((iloc == InteractionLocality::NonLocal) && !haveGpuShortRangeWork(nb, iloc))
+    {
+        /* TODO An alternative way to signal that non-local work is
+           complete is to use a clEnqueueMarker+clEnqueueBarrier
+           pair. However, the use of bNonLocalStreamDoneMarked has the
+           advantage of being local to the host, so probably minimizes
+           overhead. Curiously, for NVIDIA OpenCL with an empty-domain
+           test case, overall simulation performance was higher with
+           the API calls, but this has not been tested on AMD OpenCL,
+           so could be worth considering in future. */
+        nb->bNonLocalStreamDoneMarked = false;
+        return;
+    }
+
+    /* local/nonlocal offset and length used for xq and f */
+    auto atomsRange = getGpuAtomRange(adat, atomLocality);
+
+    /* beginning of timed D2H section */
+    if (bDoTime)
+    {
+        timers->xf[atomLocality].nb_d2h.openTimingRegion(deviceStream);
+    }
+
+    /* With DD the local D2H transfer can only start after the non-local
+       has been launched. */
+    if (iloc == InteractionLocality::Local && nb->bNonLocalStreamDoneMarked)
+    {
+        nb->nonlocal_done.enqueueWaitEvent(deviceStream);
+        nb->bNonLocalStreamDoneMarked = false;
+    }
+
+    /* DtoH f */
+    if (!stepWork.useGpuFBufferOps)
+    {
+        static_assert(
+                sizeof(*nbatom->out[0].f.data()) == sizeof(float),
+                "The host force buffer should be in single precision to match device data size.");
+        copyFromDeviceBuffer(reinterpret_cast<Float3*>(nbatom->out[0].f.data()) + atomsRange.begin(),
+                             &adat->f,
+                             atomsRange.begin(),
+                             atomsRange.size(),
+                             deviceStream,
+                             GpuApiCallBehavior::Async,
+                             bDoTime ? timers->xf[atomLocality].nb_d2h.fetchNextEvent() : nullptr);
+
+        issueClFlushInStream(deviceStream);
+    }
+
+    /* After the non-local D2H is launched the nonlocal_done event can be
+       recorded which signals that the local D2H can proceed. This event is not
+       placed after the non-local kernel because we first need the non-local
+       data back first. */
+    if (iloc == InteractionLocality::NonLocal)
+    {
+        nb->nonlocal_done.markEvent(deviceStream);
+        nb->bNonLocalStreamDoneMarked = true;
+    }
+
+    /* only transfer energies in the local stream */
+    if (iloc == InteractionLocality::Local)
+    {
+        /* DtoH fshift when virial is needed */
+        if (stepWork.computeVirial)
+        {
+            static_assert(
+                    sizeof(*nb->nbst.fShift) == sizeof(Float3),
+                    "Sizes of host- and device-side shift vector elements should be the same.");
+            copyFromDeviceBuffer(nb->nbst.fShift,
+                                 &adat->fShift,
+                                 0,
+                                 gmx::c_numShiftVectors,
+                                 deviceStream,
+                                 GpuApiCallBehavior::Async,
+                                 bDoTime ? timers->xf[atomLocality].nb_d2h.fetchNextEvent() : nullptr);
+        }
+
+        /* DtoH energies */
+        if (stepWork.computeEnergy)
+        {
+            static_assert(sizeof(*nb->nbst.eLJ) == sizeof(float),
+                          "Sizes of host- and device-side LJ energy terms should be the same.");
+            copyFromDeviceBuffer(nb->nbst.eLJ,
+                                 &adat->eLJ,
+                                 0,
+                                 1,
+                                 deviceStream,
+                                 GpuApiCallBehavior::Async,
+                                 bDoTime ? timers->xf[atomLocality].nb_d2h.fetchNextEvent() : nullptr);
+            static_assert(sizeof(*nb->nbst.eElec) == sizeof(float),
+                          "Sizes of host- and device-side electrostatic energy terms should be the "
+                          "same.");
+            copyFromDeviceBuffer(nb->nbst.eElec,
+                                 &adat->eElec,
+                                 0,
+                                 1,
+                                 deviceStream,
+                                 GpuApiCallBehavior::Async,
+                                 bDoTime ? timers->xf[atomLocality].nb_d2h.fetchNextEvent() : nullptr);
+        }
+    }
+
+    if (bDoTime)
+    {
+        timers->xf[atomLocality].nb_d2h.closeTimingRegion(deviceStream);
+    }
+}
+
+void nbnxnInsertNonlocalGpuDependency(NbnxmGpu* nb, const InteractionLocality interactionLocality)
+{
+    const DeviceStream& deviceStream = *nb->deviceStreams[interactionLocality];
+
+    /* When we get here all misc operations issued in the local stream as well as
+       the local xq H2D are done,
+       so we record that in the local stream and wait for it in the nonlocal one.
+       This wait needs to precede any PP tasks, bonded or nonbonded, that may
+       compute on interactions between local and nonlocal atoms.
+     */
+    if (nb->bUseTwoStreams)
+    {
+        if (interactionLocality == InteractionLocality::Local)
+        {
+            nb->misc_ops_and_local_H2D_done.markEvent(deviceStream);
+            issueClFlushInStream(deviceStream);
+        }
+        else
+        {
+            nb->misc_ops_and_local_H2D_done.enqueueWaitEvent(deviceStream);
+        }
+    }
+}
+
+/*! \brief Launch asynchronously the xq buffer host to device copy. */
+void gpu_copy_xq_to_gpu(NbnxmGpu* nb, const nbnxn_atomdata_t* nbatom, const AtomLocality atomLocality)
+{
+    GMX_ASSERT(nb, "Need a valid nbnxn_gpu object");
+
+    const InteractionLocality iloc = atomToInteractionLocality(atomLocality);
+
+    NBAtomDataGpu*      adat         = nb->atdat;
+    gpu_plist*          plist        = nb->plist[iloc];
+    Nbnxm::GpuTimers*   timers       = nb->timers;
+    const DeviceStream& deviceStream = *nb->deviceStreams[iloc];
+
+    const bool bDoTime = nb->bDoTime;
+
+    /* Don't launch the non-local H2D copy if there is no dependent
+       work to do: neither non-local nor other (e.g. bonded) work
+       to do that has as input the nbnxn coordaintes.
+       Doing the same for the local kernel is more complicated, since the
+       local part of the force array also depends on the non-local kernel.
+       So to avoid complicating the code and to reduce the risk of bugs,
+       we always call the local local x+q copy (and the rest of the local
+       work in nbnxn_gpu_launch_kernel().
+     */
+    if ((iloc == InteractionLocality::NonLocal) && !haveGpuShortRangeWork(nb, iloc))
+    {
+        plist->haveFreshList = false;
+
+        // The event is marked for Local interactions unconditionally,
+        // so it has to be released here because of the early return
+        // for NonLocal interactions.
+        nb->misc_ops_and_local_H2D_done.reset();
+
+        return;
+    }
+
+    /* local/nonlocal offset and length used for xq and f */
+    const auto atomsRange = getGpuAtomRange(adat, atomLocality);
+
+    /* beginning of timed HtoD section */
+    if (bDoTime)
+    {
+        timers->xf[atomLocality].nb_h2d.openTimingRegion(deviceStream);
+    }
+
+    /* HtoD x, q */
+    GMX_ASSERT(nbatom->XFormat == nbatXYZQ,
+               "The coordinates should be in xyzq format to copy to the Float4 device buffer.");
+    copyToDeviceBuffer(&adat->xq,
+                       reinterpret_cast<const Float4*>(nbatom->x().data()) + atomsRange.begin(),
+                       atomsRange.begin(),
+                       atomsRange.size(),
+                       deviceStream,
+                       GpuApiCallBehavior::Async,
+                       nullptr);
+
+    if (bDoTime)
+    {
+        timers->xf[atomLocality].nb_h2d.closeTimingRegion(deviceStream);
+    }
+
+    /* When we get here all misc operations issued in the local stream as well as
+       the local xq H2D are done,
+       so we record that in the local stream and wait for it in the nonlocal one.
+       This wait needs to precede any PP tasks, bonded or nonbonded, that may
+       compute on interactions between local and nonlocal atoms.
+     */
+    nbnxnInsertNonlocalGpuDependency(nb, iloc);
+}
+
+
+/* Initialization for X buffer operations on GPU. */
+void nbnxn_gpu_init_x_to_nbat_x(const Nbnxm::GridSet& gridSet, NbnxmGpu* gpu_nbv)
+{
+    const DeviceStream& localStream   = *gpu_nbv->deviceStreams[InteractionLocality::Local];
+    const bool          bDoTime       = gpu_nbv->bDoTime;
+    const int           maxNumColumns = gridSet.numColumnsMax();
+
+    reallocateDeviceBuffer(&gpu_nbv->cxy_na,
+                           maxNumColumns * gridSet.grids().size(),
+                           &gpu_nbv->ncxy_na,
+                           &gpu_nbv->ncxy_na_alloc,
+                           *gpu_nbv->deviceContext_);
+    reallocateDeviceBuffer(&gpu_nbv->cxy_ind,
+                           maxNumColumns * gridSet.grids().size(),
+                           &gpu_nbv->ncxy_ind,
+                           &gpu_nbv->ncxy_ind_alloc,
+                           *gpu_nbv->deviceContext_);
+
+    for (unsigned int g = 0; g < gridSet.grids().size(); g++)
+    {
+        const Nbnxm::Grid& grid = gridSet.grids()[g];
+
+        const int  numColumns      = grid.numColumns();
+        const int* atomIndices     = gridSet.atomIndices().data();
+        const int  atomIndicesSize = gridSet.atomIndices().size();
+        const int* cxy_na          = grid.cxy_na().data();
+        const int* cxy_ind         = grid.cxy_ind().data();
+
+        auto* timerH2D = bDoTime ? &gpu_nbv->timers->xf[AtomLocality::Local].nb_h2d : nullptr;
+
+        reallocateDeviceBuffer(&gpu_nbv->atomIndices,
+                               atomIndicesSize,
+                               &gpu_nbv->atomIndicesSize,
+                               &gpu_nbv->atomIndicesSize_alloc,
+                               *gpu_nbv->deviceContext_);
+
+        if (atomIndicesSize > 0)
+        {
+            if (bDoTime)
+            {
+                timerH2D->openTimingRegion(localStream);
+            }
+
+            copyToDeviceBuffer(&gpu_nbv->atomIndices,
+                               atomIndices,
+                               0,
+                               atomIndicesSize,
+                               localStream,
+                               GpuApiCallBehavior::Async,
+                               bDoTime ? timerH2D->fetchNextEvent() : nullptr);
+
+            if (bDoTime)
+            {
+                timerH2D->closeTimingRegion(localStream);
+            }
+        }
+
+        if (numColumns > 0)
+        {
+            if (bDoTime)
+            {
+                timerH2D->openTimingRegion(localStream);
+            }
+
+            copyToDeviceBuffer(&gpu_nbv->cxy_na,
+                               cxy_na,
+                               maxNumColumns * g,
+                               numColumns,
+                               localStream,
+                               GpuApiCallBehavior::Async,
+                               bDoTime ? timerH2D->fetchNextEvent() : nullptr);
+
+            if (bDoTime)
+            {
+                timerH2D->closeTimingRegion(localStream);
+            }
+
+            if (bDoTime)
+            {
+                timerH2D->openTimingRegion(localStream);
+            }
+
+            copyToDeviceBuffer(&gpu_nbv->cxy_ind,
+                               cxy_ind,
+                               maxNumColumns * g,
+                               numColumns,
+                               localStream,
+                               GpuApiCallBehavior::Async,
+                               bDoTime ? timerH2D->fetchNextEvent() : nullptr);
+
+            if (bDoTime)
+            {
+                timerH2D->closeTimingRegion(localStream);
+            }
+        }
+    }
+
+    // The above data is transferred on the local stream but is a
+    // dependency of the nonlocal stream (specifically the nonlocal X
+    // buf ops kernel).  We therefore set a dependency to ensure
+    // that the nonlocal stream waits on the local stream here.
+    // This call records an event in the local stream:
+    nbnxnInsertNonlocalGpuDependency(gpu_nbv, Nbnxm::InteractionLocality::Local);
+    // ...and this call instructs the nonlocal stream to wait on that event:
+    nbnxnInsertNonlocalGpuDependency(gpu_nbv, Nbnxm::InteractionLocality::NonLocal);
+}
+
+//! This function is documented in the header file
+void gpu_free(NbnxmGpu* nb)
+{
+    if (nb == nullptr)
+    {
+        return;
+    }
+
+    gpu_free_platform_specific(nb);
+
+    delete nb->timers;
+    sfree(nb->timings);
+
+    NBAtomDataGpu* atdat   = nb->atdat;
+    NBParamGpu*    nbparam = nb->nbparam;
+
+    /* Free atdat */
+    freeDeviceBuffer(&(nb->atdat->xq));
+    freeDeviceBuffer(&(nb->atdat->f));
+    freeDeviceBuffer(&(nb->atdat->eLJ));
+    freeDeviceBuffer(&(nb->atdat->eElec));
+    freeDeviceBuffer(&(nb->atdat->fShift));
+    freeDeviceBuffer(&(nb->atdat->shiftVec));
+    if (useLjCombRule(nb->nbparam->vdwType))
+    {
+        freeDeviceBuffer(&atdat->ljComb);
+    }
+    else
+    {
+        freeDeviceBuffer(&atdat->atomTypes);
+    }
+
+    /* Free nbparam */
+    if (nbparam->elecType == ElecType::EwaldTab || nbparam->elecType == ElecType::EwaldTabTwin)
+    {
+        destroyParamLookupTable(&nbparam->coulomb_tab, nbparam->coulomb_tab_texobj);
+    }
+
+    if (!useLjCombRule(nb->nbparam->vdwType))
+    {
+        destroyParamLookupTable(&nbparam->nbfp, nbparam->nbfp_texobj);
+    }
+
+    if (nbparam->vdwType == VdwType::EwaldGeom || nbparam->vdwType == VdwType::EwaldLB)
+    {
+        destroyParamLookupTable(&nbparam->nbfp_comb, nbparam->nbfp_comb_texobj);
+    }
+
+    /* Free plist */
+    auto* plist = nb->plist[InteractionLocality::Local];
+    freeDeviceBuffer(&plist->sci);
+    freeDeviceBuffer(&plist->cj4);
+    freeDeviceBuffer(&plist->imask);
+    freeDeviceBuffer(&plist->excl);
+    delete plist;
+    if (nb->bUseTwoStreams)
+    {
+        auto* plist_nl = nb->plist[InteractionLocality::NonLocal];
+        freeDeviceBuffer(&plist_nl->sci);
+        freeDeviceBuffer(&plist_nl->cj4);
+        freeDeviceBuffer(&plist_nl->imask);
+        freeDeviceBuffer(&plist_nl->excl);
+        delete plist_nl;
+    }
+
+    /* Free nbst */
+    pfree(nb->nbst.eLJ);
+    nb->nbst.eLJ = nullptr;
+
+    pfree(nb->nbst.eElec);
+    nb->nbst.eElec = nullptr;
+
+    pfree(nb->nbst.fShift);
+    nb->nbst.fShift = nullptr;
+
+    delete atdat;
+    delete nbparam;
+    delete nb;
+
+    if (debug)
+    {
+        fprintf(debug, "Cleaned up NBNXM GPU data structures.\n");
+    }
 }
 
 } // namespace Nbnxm
index b417566db4fd96e10356b33e7a3877e42fc10d4f..19652c712a21d09e67119ddbb897d595d6a60a6d 100644 (file)
@@ -44,6 +44,7 @@
 #ifndef GMX_NBNXM_NBNXM_GPU_DATA_MGMT_H
 #define GMX_NBNXM_NBNXM_GPU_DATA_MGMT_H
 
+class DeviceContext;
 struct interaction_const_t;
 struct NBParamGpu;
 struct PairlistParams;
@@ -58,29 +59,11 @@ namespace Nbnxm
 
 struct gpu_plist;
 
-/*! \brief Tabulates the Ewald Coulomb force and initializes the size/scale and the table GPU array.
- *
- * If called with an already allocated table, it just re-uploads the
- * table.
- */
-void init_ewald_coulomb_force_table(const EwaldCorrectionTables& tables,
-                                    NBParamGpu*                  nbp,
-                                    const DeviceContext&         deviceContext);
-
-/*! \brief Selects the Ewald kernel type, analytical or tabulated, single or twin cut-off. */
-int nbnxn_gpu_pick_ewald_kernel_type(const interaction_const_t gmx_unused& ic,
-                                     const DeviceInformation&              deviceInfo);
-
-/*! \brief Copies all parameters related to the cut-off from ic to nbp
- */
-void set_cutoff_parameters(NBParamGpu* nbp, const interaction_const_t* ic, const PairlistParams& listParams);
-
-/*! \brief Initializes the pair list data structure.
- */
-void init_plist(gpu_plist* pl);
+/*! \brief Initializes the NBNXM GPU data structures. */
+void gpu_init_platform_specific(NbnxmGpu* nb);
 
-/*! \brief Initializes the timings data structure. */
-void init_timings(gmx_wallclock_gpu_nbnxn_t* t);
+/*! \brief Releases the NBNXM GPU data structures. */
+void gpu_free_platform_specific(NbnxmGpu* nb);
 
 } // namespace Nbnxm
 
index 74086df3dea8b21e94ca2da97fdf639d1ece69ea..422840d889afd285cd58ff8419eedaef24f02e1e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +83,9 @@ enum class NonbondedResource : int
  * If the return value is FALSE and fplog/cr != NULL, prints a fallback
  * message to fplog/stderr.
  */
-static gmx_bool nbnxn_simd_supported(const gmx::MDLogger& mdlog, const t_inputrec* ir)
+static bool nbnxn_simd_supported(const gmx::MDLogger& mdlog, const t_inputrec& inputrec)
 {
-    if (ir->vdwtype == evdwPME && ir->ljpme_combination_rule == eljpmeLB)
+    if (inputrec.vdwtype == VanDerWaalsType::Pme && inputrec.ljpme_combination_rule == LongRangeVdW::LB)
     {
         /* LJ PME with LB combination rule does 7 mesh operations.
          * This so slow that we don't compile SIMD non-bonded kernels
@@ -102,7 +102,7 @@ static gmx_bool nbnxn_simd_supported(const gmx::MDLogger& mdlog, const t_inputre
 }
 
 /*! \brief Returns the most suitable CPU kernel type and Ewald handling */
-static KernelSetup pick_nbnxn_kernel_cpu(const t_inputrec gmx_unused* ir,
+static KernelSetup pick_nbnxn_kernel_cpu(const t_inputrec gmx_unused& inputrec,
                                          const gmx_hw_info_t gmx_unused& hardwareInfo)
 {
     KernelSetup kernelSetup;
@@ -140,7 +140,7 @@ static KernelSetup pick_nbnxn_kernel_cpu(const t_inputrec gmx_unused* ir,
          */
         kernelSetup.kernelType = KernelType::Cpu4xN_Simd_4xN;
 
-        if (!GMX_SIMD_HAVE_FMA && (EEL_PME_EWALD(ir->coulombtype) || EVDW_PME(ir->vdwtype)))
+        if (!GMX_SIMD_HAVE_FMA && (EEL_PME_EWALD(inputrec.coulombtype) || EVDW_PME(inputrec.vdwtype)))
         {
             /* We have Ewald kernels without FMA (Intel Sandy/Ivy Bridge).
              * There are enough instructions to make 2x(4+4) efficient.
@@ -212,25 +212,22 @@ static KernelSetup pick_nbnxn_kernel_cpu(const t_inputrec gmx_unused* ir,
 
 const char* lookup_kernel_name(const KernelType kernelType)
 {
-    const char* returnvalue = nullptr;
     switch (kernelType)
     {
-        case KernelType::NotSet: returnvalue = "not set"; break;
-        case KernelType::Cpu4x4_PlainC: returnvalue = "plain C"; break;
+        case KernelType::NotSet: return "not set";
+        case KernelType::Cpu4x4_PlainC: return "plain C";
         case KernelType::Cpu4xN_Simd_4xN:
         case KernelType::Cpu4xN_Simd_2xNN:
 #if GMX_SIMD
-            returnvalue = "SIMD";
+            return "SIMD";
 #else  // GMX_SIMD
-            returnvalue = "not available";
+            return "not available";
 #endif // GMX_SIMD
-            break;
-        case KernelType::Gpu8x8x8: returnvalue = "GPU"; break;
-        case KernelType::Cpu8x8x8_PlainC: returnvalue = "plain C"; break;
+        case KernelType::Gpu8x8x8: return "GPU";
+        case KernelType::Cpu8x8x8_PlainC: return "plain C";
 
         default: gmx_fatal(FARGS, "Illegal kernel type selected");
     }
-    return returnvalue;
 };
 
 /*! \brief Returns the most suitable kernel type and Ewald handling */
@@ -238,7 +235,7 @@ static KernelSetup pick_nbnxn_kernel(const gmx::MDLogger&     mdlog,
                                      gmx_bool                 use_simd_kernels,
                                      const gmx_hw_info_t&     hardwareInfo,
                                      const NonbondedResource& nonbondedResource,
-                                     const t_inputrec*        ir)
+                                     const t_inputrec&        inputrec)
 {
     KernelSetup kernelSetup;
 
@@ -256,9 +253,9 @@ static KernelSetup pick_nbnxn_kernel(const gmx::MDLogger&     mdlog,
     }
     else
     {
-        if (use_simd_kernels && nbnxn_simd_supported(mdlog, ir))
+        if (use_simd_kernels && nbnxn_simd_supported(mdlog, inputrec))
         {
-            kernelSetup = pick_nbnxn_kernel_cpu(ir, hardwareInfo);
+            kernelSetup = pick_nbnxn_kernel_cpu(inputrec, hardwareInfo);
         }
         else
         {
@@ -300,11 +297,11 @@ PairlistSets::PairlistSets(const PairlistParams& pairlistParams,
     params_(pairlistParams),
     minimumIlistCountForGpuBalancing_(minimumIlistCountForGpuBalancing)
 {
-    localSet_ = std::make_unique<PairlistSet>(gmx::InteractionLocality::Local, params_);
+    localSet_ = std::make_unique<PairlistSet>(params_);
 
     if (haveMultipleDomains)
     {
-        nonlocalSet_ = std::make_unique<PairlistSet>(gmx::InteractionLocality::NonLocal, params_);
+        nonlocalSet_ = std::make_unique<PairlistSet>(params_);
     }
 }
 
@@ -314,28 +311,26 @@ namespace Nbnxm
 /*! \brief Gets and returns the minimum i-list count for balacing based on the GPU used or env.var. when set */
 static int getMinimumIlistCountForGpuBalancing(NbnxmGpu* nbnxmGpu)
 {
-    int minimumIlistCount;
-
     if (const char* env = getenv("GMX_NB_MIN_CI"))
     {
-        char* end;
+        char* end = nullptr;
 
-        minimumIlistCount = strtol(env, &end, 10);
+        int minimumIlistCount = strtol(env, &end, 10);
         if (!end || (*end != 0) || minimumIlistCount < 0)
         {
-            gmx_fatal(FARGS,
-                      "Invalid value passed in GMX_NB_MIN_CI=%s, non-negative integer required", env);
+            gmx_fatal(
+                    FARGS, "Invalid value passed in GMX_NB_MIN_CI=%s, non-negative integer required", env);
         }
 
         if (debug)
         {
-            fprintf(debug, "Neighbor-list balancing parameter: %d (passed as env. var.)\n",
-                    minimumIlistCount);
+            fprintf(debug, "Neighbor-list balancing parameter: %d (passed as env. var.)\n", minimumIlistCount);
         }
+        return minimumIlistCount;
     }
     else
     {
-        minimumIlistCount = gpu_min_ci_balanced(nbnxmGpu);
+        int minimumIlistCount = gpu_min_ci_balanced(nbnxmGpu);
         if (debug)
         {
             fprintf(debug,
@@ -343,19 +338,47 @@ static int getMinimumIlistCountForGpuBalancing(NbnxmGpu* nbnxmGpu)
                     "multi-processors)\n",
                     minimumIlistCount);
         }
+        return minimumIlistCount;
     }
+}
 
-    return minimumIlistCount;
+static int getENbnxnInitCombRule(const t_forcerec& forcerec)
+{
+    if (forcerec.ic->vdwtype == VanDerWaalsType::Cut
+        && (forcerec.ic->vdw_modifier == InteractionModifiers::None
+            || forcerec.ic->vdw_modifier == InteractionModifiers::PotShift)
+        && getenv("GMX_NO_LJ_COMB_RULE") == nullptr)
+    {
+        /* Plain LJ cut-off: we can optimize with combination rules */
+        return enbnxninitcombruleDETECT;
+    }
+    else if (forcerec.ic->vdwtype == VanDerWaalsType::Pme)
+    {
+        /* LJ-PME: we need to use a combination rule for the grid */
+        if (forcerec.ljpme_combination_rule == LongRangeVdW::Geom)
+        {
+            return enbnxninitcombruleGEOM;
+        }
+        else
+        {
+            return enbnxninitcombruleLB;
+        }
+    }
+    else
+    {
+        /* We use a full combination matrix: no rule required */
+        return enbnxninitcombruleNONE;
+    }
 }
 
 std::unique_ptr<nonbonded_verlet_t> init_nb_verlet(const gmx::MDLogger& mdlog,
-                                                   const t_inputrec*    ir,
-                                                   const t_forcerec*    fr,
-                                                   const t_commrec*     cr,
+                                                   const t_inputrec&    inputrec,
+                                                   const t_forcerec&    forcerec,
+                                                   const t_commrec*     commrec,
                                                    const gmx_hw_info_t& hardwareInfo,
-                                                   const bool           useGpuForNonbonded,
+                                                   bool                 useGpuForNonbonded,
                                                    const gmx::DeviceStreamManager* deviceStreamManager,
-                                                   const gmx_mtop_t*               mtop,
+                                                   const gmx_mtop_t&               mtop,
                                                    matrix                          box,
                                                    gmx_wallcycle*                  wcycle)
 {
@@ -378,49 +401,25 @@ std::unique_ptr<nonbonded_verlet_t> init_nb_verlet(const gmx::MDLogger& mdlog,
         nonbondedResource = NonbondedResource::Cpu;
     }
 
-    Nbnxm::KernelSetup kernelSetup =
-            pick_nbnxn_kernel(mdlog, fr->use_simd_kernels, hardwareInfo, nonbondedResource, ir);
+    Nbnxm::KernelSetup kernelSetup = pick_nbnxn_kernel(
+            mdlog, forcerec.use_simd_kernels, hardwareInfo, nonbondedResource, inputrec);
 
-    const bool haveMultipleDomains = havePPDomainDecomposition(cr);
+    const bool haveMultipleDomains = havePPDomainDecomposition(commrec);
 
-    bool           bFEP_NonBonded = (fr->efep != efepNO) && haveFepPerturbedNBInteractions(*mtop);
-    PairlistParams pairlistParams(kernelSetup.kernelType, bFEP_NonBonded, ir->rlist, haveMultipleDomains);
+    bool bFEP_NonBonded = (forcerec.efep != FreeEnergyPerturbationType::No)
+                          && haveFepPerturbedNBInteractions(mtop);
+    PairlistParams pairlistParams(
+            kernelSetup.kernelType, bFEP_NonBonded, inputrec.rlist, haveMultipleDomains);
 
-    setupDynamicPairlistPruning(mdlog, ir, mtop, box, fr->ic, &pairlistParams);
+    setupDynamicPairlistPruning(mdlog, inputrec, mtop, box, *forcerec.ic, &pairlistParams);
 
-    int enbnxninitcombrule;
-    if (fr->ic->vdwtype == evdwCUT
-        && (fr->ic->vdw_modifier == eintmodNONE || fr->ic->vdw_modifier == eintmodPOTSHIFT)
-        && getenv("GMX_NO_LJ_COMB_RULE") == nullptr)
-    {
-        /* Plain LJ cut-off: we can optimize with combination rules */
-        enbnxninitcombrule = enbnxninitcombruleDETECT;
-    }
-    else if (fr->ic->vdwtype == evdwPME)
-    {
-        /* LJ-PME: we need to use a combination rule for the grid */
-        if (fr->ljpme_combination_rule == eljpmeGEOM)
-        {
-            enbnxninitcombrule = enbnxninitcombruleGEOM;
-        }
-        else
-        {
-            enbnxninitcombrule = enbnxninitcombruleLB;
-        }
-    }
-    else
-    {
-        /* We use a full combination matrix: no rule required */
-        enbnxninitcombrule = enbnxninitcombruleNONE;
-    }
+    const int enbnxninitcombrule = getENbnxnInitCombRule(forcerec);
 
     auto pinPolicy = (useGpuForNonbonded ? gmx::PinningPolicy::PinnedIfSupported
                                          : gmx::PinningPolicy::CannotBePinned);
 
-    auto nbat = std::make_unique<nbnxn_atomdata_t>(pinPolicy);
-
-    int mimimumNumEnergyGroupNonbonded = ir->opts.ngener;
-    if (ir->opts.ngener - ir->nwall == 1)
+    int mimimumNumEnergyGroupNonbonded = inputrec.opts.ngener;
+    if (inputrec.opts.ngener - inputrec.nwall == 1)
     {
         /* We have only one non-wall energy group, we do not need energy group
          * support in the non-bondeds kernels, since all non-bonded energy
@@ -428,9 +427,16 @@ std::unique_ptr<nonbonded_verlet_t> init_nb_verlet(const gmx::MDLogger& mdlog,
          */
         mimimumNumEnergyGroupNonbonded = 1;
     }
-    nbnxn_atomdata_init(mdlog, nbat.get(), kernelSetup.kernelType, enbnxninitcombrule, fr->ntype,
-                        fr->nbfp, mimimumNumEnergyGroupNonbonded,
-                        (useGpuForNonbonded || emulateGpu) ? 1 : gmx_omp_nthreads_get(emntNonbonded));
+
+    auto nbat = std::make_unique<nbnxn_atomdata_t>(
+            pinPolicy,
+            mdlog,
+            kernelSetup.kernelType,
+            enbnxninitcombrule,
+            forcerec.ntype,
+            forcerec.nbfp,
+            mimimumNumEnergyGroupNonbonded,
+            (useGpuForNonbonded || emulateGpu) ? 1 : gmx_omp_nthreads_get(ModuleMultiThread::Nonbonded));
 
     NbnxmGpu* gpu_nbv                          = nullptr;
     int       minimumIlistCountForGpuBalancing = 0;
@@ -441,21 +447,27 @@ std::unique_ptr<nonbonded_verlet_t> init_nb_verlet(const gmx::MDLogger& mdlog,
         GMX_RELEASE_ASSERT(
                 (deviceStreamManager != nullptr),
                 "Device stream manager should be initialized in order to use GPU for non-bonded.");
-        gpu_nbv = gpu_init(*deviceStreamManager, fr->ic, pairlistParams, nbat.get(), haveMultipleDomains);
+        gpu_nbv = gpu_init(
+                *deviceStreamManager, forcerec.ic.get(), pairlistParams, nbat.get(), haveMultipleDomains);
 
         minimumIlistCountForGpuBalancing = getMinimumIlistCountForGpuBalancing(gpu_nbv);
     }
 
-    auto pairlistSets = std::make_unique<PairlistSets>(pairlistParams, haveMultipleDomains,
-                                                       minimumIlistCountForGpuBalancing);
-
-    auto pairSearch = std::make_unique<PairSearch>(
-            ir->pbcType, EI_TPI(ir->eI), DOMAINDECOMP(cr) ? &cr->dd->numCells : nullptr,
-            DOMAINDECOMP(cr) ? domdec_zones(cr->dd) : nullptr, pairlistParams.pairlistType,
-            bFEP_NonBonded, gmx_omp_nthreads_get(emntPairsearch), pinPolicy);
-
-    return std::make_unique<nonbonded_verlet_t>(std::move(pairlistSets), std::move(pairSearch),
-                                                std::move(nbat), kernelSetup, gpu_nbv, wcycle);
+    auto pairlistSets = std::make_unique<PairlistSets>(
+            pairlistParams, haveMultipleDomains, minimumIlistCountForGpuBalancing);
+
+    auto pairSearch =
+            std::make_unique<PairSearch>(inputrec.pbcType,
+                                         EI_TPI(inputrec.eI),
+                                         DOMAINDECOMP(commrec) ? &commrec->dd->numCells : nullptr,
+                                         DOMAINDECOMP(commrec) ? domdec_zones(commrec->dd) : nullptr,
+                                         pairlistParams.pairlistType,
+                                         bFEP_NonBonded,
+                                         gmx_omp_nthreads_get(ModuleMultiThread::Pairsearch),
+                                         pinPolicy);
+
+    return std::make_unique<nonbonded_verlet_t>(
+            std::move(pairlistSets), std::move(pairSearch), std::move(nbat), kernelSetup, gpu_nbv, wcycle);
 }
 
 } // namespace Nbnxm
index dec5605f1f8624f0b1655462342ae41270e98193..f29e5553591e1ad835af6a82c8b71fbc18c7e526 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 /*! \brief The nbnxn SIMD 4xN and 2x(N+N) kernels can be added independently.
  * Currently the 2xNN SIMD kernels only make sense with:
  *  8-way SIMD: 4x4 setup, works with AVX-256 in single precision
- * 16-way SIMD: 4x8 setup, works with Intel MIC in single precision
+ * 16-way SIMD: 4x8 setup, not currently in use, but worked with Intel MIC
  */
 #    if GMX_SIMD_REAL_WIDTH == 2 || GMX_SIMD_REAL_WIDTH == 4 || GMX_SIMD_REAL_WIDTH == 8
 #        define GMX_NBNXN_SIMD_4XN
index dab11de27837bc842a8dafe168f84117ef0b6ea6..e4e875c2aff990a9ff044991b58af77362291097 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2012,2013,2014,2015,2018 by the GROMACS development team.
-# Copyright (c) 2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
@@ -82,6 +82,7 @@ foreach(ELEC_DEF IN LISTS ELEC_DEFS)
                 -DNBNXM_MIN_DISTANCE_SQUARED_VALUE_FLOAT=3.82e-07
                 -Dc_nbnxnGpuNumClusterPerSupercluster=8
                 -Dc_nbnxnGpuJgroupSize=4
+                -Dc_centralShiftIndex=22
                 -DIATYPE_SHMEM
                 -c -I ${CMAKE_SOURCE_DIR}/src -std=cl1.2
                 -Weverything  -Wno-conversion -Wno-missing-variable-declarations -Wno-used-but-marked-unused
index 48e8ed03ad37e1189abc522330af67ef03932779..3bde29600811dddcd8e7ad6ef88b37553bac18b5 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -68,8 +68,6 @@
 #    include <limits>
 #endif
 
-#include "thread_mpi/atomic.h"
-
 #include "gromacs/gpu_utils/device_context.h"
 #include "gromacs/gpu_utils/gputraits_ocl.h"
 #include "gromacs/gpu_utils/oclutils.h"
@@ -83,7 +81,6 @@
 #include "gromacs/nbnxm/nbnxm.h"
 #include "gromacs/nbnxm/nbnxm_gpu.h"
 #include "gromacs/nbnxm/pairlist.h"
-#include "gromacs/pbcutil/ishift.h"
 #include "gromacs/timing/gpu_timing.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
@@ -147,7 +144,8 @@ static inline void validate_global_work_size(const KernelLaunchConfig& config,
                         "Watch out, the input system is too large to simulate!\n"
                         "The number of nonbonded work units (=number of super-clusters) exceeds the"
                         "device capabilities. Global work size limit exceeded (%zu > %zu)!",
-                        global_work_size[i], device_limit);
+                        global_work_size[i],
+                        device_limit);
             }
         }
     }
@@ -162,17 +160,25 @@ static inline void validate_global_work_size(const KernelLaunchConfig& config,
  */
 
 /*! \brief Force-only kernel function names. */
-static const char* nb_kfunc_noener_noprune_ptr[eelTypeNR][evdwTypeNR] = {
-    { "nbnxn_kernel_ElecCut_VdwLJ_F_opencl", "nbnxn_kernel_ElecCut_VdwLJCombGeom_F_opencl",
-      "nbnxn_kernel_ElecCut_VdwLJCombLB_F_opencl", "nbnxn_kernel_ElecCut_VdwLJFsw_F_opencl",
-      "nbnxn_kernel_ElecCut_VdwLJPsw_F_opencl", "nbnxn_kernel_ElecCut_VdwLJEwCombGeom_F_opencl",
+static const char* nb_kfunc_noener_noprune_ptr[c_numElecTypes][c_numVdwTypes] = {
+    { "nbnxn_kernel_ElecCut_VdwLJ_F_opencl",
+      "nbnxn_kernel_ElecCut_VdwLJCombGeom_F_opencl",
+      "nbnxn_kernel_ElecCut_VdwLJCombLB_F_opencl",
+      "nbnxn_kernel_ElecCut_VdwLJFsw_F_opencl",
+      "nbnxn_kernel_ElecCut_VdwLJPsw_F_opencl",
+      "nbnxn_kernel_ElecCut_VdwLJEwCombGeom_F_opencl",
       "nbnxn_kernel_ElecCut_VdwLJEwCombLB_F_opencl" },
-    { "nbnxn_kernel_ElecRF_VdwLJ_F_opencl", "nbnxn_kernel_ElecRF_VdwLJCombGeom_F_opencl",
-      "nbnxn_kernel_ElecRF_VdwLJCombLB_F_opencl", "nbnxn_kernel_ElecRF_VdwLJFsw_F_opencl",
-      "nbnxn_kernel_ElecRF_VdwLJPsw_F_opencl", "nbnxn_kernel_ElecRF_VdwLJEwCombGeom_F_opencl",
+    { "nbnxn_kernel_ElecRF_VdwLJ_F_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJCombGeom_F_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJCombLB_F_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJFsw_F_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJPsw_F_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJEwCombGeom_F_opencl",
       "nbnxn_kernel_ElecRF_VdwLJEwCombLB_F_opencl" },
-    { "nbnxn_kernel_ElecEwQSTab_VdwLJ_F_opencl", "nbnxn_kernel_ElecEwQSTab_VdwLJCombGeom_F_opencl",
-      "nbnxn_kernel_ElecEwQSTab_VdwLJCombLB_F_opencl", "nbnxn_kernel_ElecEwQSTab_VdwLJFsw_F_opencl",
+    { "nbnxn_kernel_ElecEwQSTab_VdwLJ_F_opencl",
+      "nbnxn_kernel_ElecEwQSTab_VdwLJCombGeom_F_opencl",
+      "nbnxn_kernel_ElecEwQSTab_VdwLJCombLB_F_opencl",
+      "nbnxn_kernel_ElecEwQSTab_VdwLJFsw_F_opencl",
       "nbnxn_kernel_ElecEwQSTab_VdwLJPsw_F_opencl",
       "nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_F_opencl",
       "nbnxn_kernel_ElecEwQSTab_VdwLJEwCombLB_F_opencl" },
@@ -183,31 +189,43 @@ static const char* nb_kfunc_noener_noprune_ptr[eelTypeNR][evdwTypeNR] = {
       "nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_F_opencl",
       "nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombGeom_F_opencl",
       "nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombLB_F_opencl" },
-    { "nbnxn_kernel_ElecEw_VdwLJ_F_opencl", "nbnxn_kernel_ElecEw_VdwLJCombGeom_F_opencl",
-      "nbnxn_kernel_ElecEw_VdwLJCombLB_F_opencl", "nbnxn_kernel_ElecEw_VdwLJFsw_F_opencl",
-      "nbnxn_kernel_ElecEw_VdwLJPsw_F_opencl", "nbnxn_kernel_ElecEw_VdwLJEwCombGeom_F_opencl",
+    { "nbnxn_kernel_ElecEw_VdwLJ_F_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJCombGeom_F_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJCombLB_F_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJFsw_F_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJPsw_F_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJEwCombGeom_F_opencl",
       "nbnxn_kernel_ElecEw_VdwLJEwCombLB_F_opencl" },
     { "nbnxn_kernel_ElecEwTwinCut_VdwLJ_F_opencl",
       "nbnxn_kernel_ElecEwTwinCut_VdwLJCombGeom_F_opencl",
       "nbnxn_kernel_ElecEwTwinCut_VdwLJCombLB_F_opencl",
-      "nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_F_opencl", "nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_F_opencl",
+      "nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_F_opencl",
+      "nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_F_opencl",
       "nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombGeom_F_opencl",
       "nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombLB_F_opencl" }
 };
 
 /*! \brief Force + energy kernel function pointers. */
-static const char* nb_kfunc_ener_noprune_ptr[eelTypeNR][evdwTypeNR] = {
-    { "nbnxn_kernel_ElecCut_VdwLJ_VF_opencl", "nbnxn_kernel_ElecCut_VdwLJCombGeom_VF_opencl",
-      "nbnxn_kernel_ElecCut_VdwLJCombLB_VF_opencl", "nbnxn_kernel_ElecCut_VdwLJFsw_VF_opencl",
-      "nbnxn_kernel_ElecCut_VdwLJPsw_VF_opencl", "nbnxn_kernel_ElecCut_VdwLJEwCombGeom_VF_opencl",
+static const char* nb_kfunc_ener_noprune_ptr[c_numElecTypes][c_numVdwTypes] = {
+    { "nbnxn_kernel_ElecCut_VdwLJ_VF_opencl",
+      "nbnxn_kernel_ElecCut_VdwLJCombGeom_VF_opencl",
+      "nbnxn_kernel_ElecCut_VdwLJCombLB_VF_opencl",
+      "nbnxn_kernel_ElecCut_VdwLJFsw_VF_opencl",
+      "nbnxn_kernel_ElecCut_VdwLJPsw_VF_opencl",
+      "nbnxn_kernel_ElecCut_VdwLJEwCombGeom_VF_opencl",
       "nbnxn_kernel_ElecCut_VdwLJEwCombLB_VF_opencl" },
-    { "nbnxn_kernel_ElecRF_VdwLJ_VF_opencl", "nbnxn_kernel_ElecRF_VdwLJCombGeom_VF_opencl",
-      "nbnxn_kernel_ElecRF_VdwLJCombLB_VF_opencl", "nbnxn_kernel_ElecRF_VdwLJFsw_VF_opencl",
-      "nbnxn_kernel_ElecRF_VdwLJPsw_VF_opencl", "nbnxn_kernel_ElecRF_VdwLJEwCombGeom_VF_opencl",
+    { "nbnxn_kernel_ElecRF_VdwLJ_VF_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJCombGeom_VF_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJCombLB_VF_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJFsw_VF_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJPsw_VF_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJEwCombGeom_VF_opencl",
       "nbnxn_kernel_ElecRF_VdwLJEwCombLB_VF_opencl" },
-    { "nbnxn_kernel_ElecEwQSTab_VdwLJ_VF_opencl", "nbnxn_kernel_ElecEwQSTab_VdwLJCombGeom_VF_opencl",
+    { "nbnxn_kernel_ElecEwQSTab_VdwLJ_VF_opencl",
+      "nbnxn_kernel_ElecEwQSTab_VdwLJCombGeom_VF_opencl",
       "nbnxn_kernel_ElecEwQSTab_VdwLJCombLB_VF_opencl",
-      "nbnxn_kernel_ElecEwQSTab_VdwLJFsw_VF_opencl", "nbnxn_kernel_ElecEwQSTab_VdwLJPsw_VF_opencl",
+      "nbnxn_kernel_ElecEwQSTab_VdwLJFsw_VF_opencl",
+      "nbnxn_kernel_ElecEwQSTab_VdwLJPsw_VF_opencl",
       "nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_VF_opencl",
       "nbnxn_kernel_ElecEwQSTab_VdwLJEwCombLB_VF_opencl" },
     { "nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJ_VF_opencl",
@@ -217,9 +235,12 @@ static const char* nb_kfunc_ener_noprune_ptr[eelTypeNR][evdwTypeNR] = {
       "nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_VF_opencl",
       "nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombGeom_VF_opencl",
       "nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombLB_VF_opencl" },
-    { "nbnxn_kernel_ElecEw_VdwLJ_VF_opencl", "nbnxn_kernel_ElecEw_VdwLJCombGeom_VF_opencl",
-      "nbnxn_kernel_ElecEw_VdwLJCombLB_VF_opencl", "nbnxn_kernel_ElecEw_VdwLJFsw_VF_opencl",
-      "nbnxn_kernel_ElecEw_VdwLJPsw_VF_opencl", "nbnxn_kernel_ElecEw_VdwLJEwCombGeom_VF_opencl",
+    { "nbnxn_kernel_ElecEw_VdwLJ_VF_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJCombGeom_VF_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJCombLB_VF_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJFsw_VF_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJPsw_VF_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJEwCombGeom_VF_opencl",
       "nbnxn_kernel_ElecEw_VdwLJEwCombLB_VF_opencl" },
     { "nbnxn_kernel_ElecEwTwinCut_VdwLJ_VF_opencl",
       "nbnxn_kernel_ElecEwTwinCut_VdwLJCombGeom_VF_opencl",
@@ -231,16 +252,19 @@ static const char* nb_kfunc_ener_noprune_ptr[eelTypeNR][evdwTypeNR] = {
 };
 
 /*! \brief Force + pruning kernel function pointers. */
-static const char* nb_kfunc_noener_prune_ptr[eelTypeNR][evdwTypeNR] = {
+static const char* nb_kfunc_noener_prune_ptr[c_numElecTypes][c_numVdwTypes] = {
     { "nbnxn_kernel_ElecCut_VdwLJ_F_prune_opencl",
       "nbnxn_kernel_ElecCut_VdwLJCombGeom_F_prune_opencl",
       "nbnxn_kernel_ElecCut_VdwLJCombLB_F_prune_opencl",
-      "nbnxn_kernel_ElecCut_VdwLJFsw_F_prune_opencl", "nbnxn_kernel_ElecCut_VdwLJPsw_F_prune_opencl",
+      "nbnxn_kernel_ElecCut_VdwLJFsw_F_prune_opencl",
+      "nbnxn_kernel_ElecCut_VdwLJPsw_F_prune_opencl",
       "nbnxn_kernel_ElecCut_VdwLJEwCombGeom_F_prune_opencl",
       "nbnxn_kernel_ElecCut_VdwLJEwCombLB_F_prune_opencl" },
-    { "nbnxn_kernel_ElecRF_VdwLJ_F_prune_opencl", "nbnxn_kernel_ElecRF_VdwLJCombGeom_F_prune_opencl",
+    { "nbnxn_kernel_ElecRF_VdwLJ_F_prune_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJCombGeom_F_prune_opencl",
       "nbnxn_kernel_ElecRF_VdwLJCombLB_F_prune_opencl",
-      "nbnxn_kernel_ElecRF_VdwLJFsw_F_prune_opencl", "nbnxn_kernel_ElecRF_VdwLJPsw_F_prune_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJFsw_F_prune_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJPsw_F_prune_opencl",
       "nbnxn_kernel_ElecRF_VdwLJEwCombGeom_F_prune_opencl",
       "nbnxn_kernel_ElecRF_VdwLJEwCombLB_F_prune_opencl" },
     { "nbnxn_kernel_ElecEwQSTab_VdwLJ_F_prune_opencl",
@@ -257,9 +281,11 @@ static const char* nb_kfunc_noener_prune_ptr[eelTypeNR][evdwTypeNR] = {
       "nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_F_prune_opencl",
       "nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombGeom_F_prune_opencl",
       "nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombLB_F_prune_opencl" },
-    { "nbnxn_kernel_ElecEw_VdwLJ_F_prune_opencl", "nbnxn_kernel_ElecEw_VdwLJCombGeom_F_prune_opencl",
+    { "nbnxn_kernel_ElecEw_VdwLJ_F_prune_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJCombGeom_F_prune_opencl",
       "nbnxn_kernel_ElecEw_VdwLJCombLB_F_prune_opencl",
-      "nbnxn_kernel_ElecEw_VdwLJFsw_F_prune_opencl", "nbnxn_kernel_ElecEw_VdwLJPsw_F_prune_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJFsw_F_prune_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJPsw_F_prune_opencl",
       "nbnxn_kernel_ElecEw_VdwLJEwCombGeom_F_prune_opencl",
       "nbnxn_kernel_ElecEw_VdwLJEwCombLB_F_prune_opencl" },
     { "nbnxn_kernel_ElecEwTwinCut_VdwLJ_F_prune_opencl",
@@ -272,7 +298,7 @@ static const char* nb_kfunc_noener_prune_ptr[eelTypeNR][evdwTypeNR] = {
 };
 
 /*! \brief Force + energy + pruning kernel function pointers. */
-static const char* nb_kfunc_ener_prune_ptr[eelTypeNR][evdwTypeNR] = {
+static const char* nb_kfunc_ener_prune_ptr[c_numElecTypes][c_numVdwTypes] = {
     { "nbnxn_kernel_ElecCut_VdwLJ_VF_prune_opencl",
       "nbnxn_kernel_ElecCut_VdwLJCombGeom_VF_prune_opencl",
       "nbnxn_kernel_ElecCut_VdwLJCombLB_VF_prune_opencl",
@@ -283,7 +309,8 @@ static const char* nb_kfunc_ener_prune_ptr[eelTypeNR][evdwTypeNR] = {
     { "nbnxn_kernel_ElecRF_VdwLJ_VF_prune_opencl",
       "nbnxn_kernel_ElecRF_VdwLJCombGeom_VF_prune_opencl",
       "nbnxn_kernel_ElecRF_VdwLJCombLB_VF_prune_opencl",
-      "nbnxn_kernel_ElecRF_VdwLJFsw_VF_prune_opencl", "nbnxn_kernel_ElecRF_VdwLJPsw_VF_prune_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJFsw_VF_prune_opencl",
+      "nbnxn_kernel_ElecRF_VdwLJPsw_VF_prune_opencl",
       "nbnxn_kernel_ElecRF_VdwLJEwCombGeom_VF_prune_opencl",
       "nbnxn_kernel_ElecRF_VdwLJEwCombLB_VF_prune_opencl" },
     { "nbnxn_kernel_ElecEwQSTab_VdwLJ_VF_prune_opencl",
@@ -303,7 +330,8 @@ static const char* nb_kfunc_ener_prune_ptr[eelTypeNR][evdwTypeNR] = {
     { "nbnxn_kernel_ElecEw_VdwLJ_VF_prune_opencl",
       "nbnxn_kernel_ElecEw_VdwLJCombGeom_VF_prune_opencl",
       "nbnxn_kernel_ElecEw_VdwLJCombLB_VF_prune_opencl",
-      "nbnxn_kernel_ElecEw_VdwLJFsw_VF_prune_opencl", "nbnxn_kernel_ElecEw_VdwLJPsw_VF_prune_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJFsw_VF_prune_opencl",
+      "nbnxn_kernel_ElecEw_VdwLJPsw_VF_prune_opencl",
       "nbnxn_kernel_ElecEw_VdwLJEwCombGeom_VF_prune_opencl",
       "nbnxn_kernel_ElecEw_VdwLJEwCombLB_VF_prune_opencl" },
     { "nbnxn_kernel_ElecEwTwinCut_VdwLJ_VF_prune_opencl",
@@ -341,50 +369,55 @@ static inline cl_kernel selectPruneKernel(cl_kernel kernel_pruneonly[], bool fir
  *  OpenCL kernel objects are cached in nb. If the requested kernel is not
  *  found in the cache, it will be created and the cache will be updated.
  */
-static inline cl_kernel select_nbnxn_kernel(NbnxmGpu* nb, int eeltype, int evdwtype, bool bDoEne, bool bDoPrune)
+static inline cl_kernel
+select_nbnxn_kernel(NbnxmGpu* nb, enum ElecType elecType, enum VdwType vdwType, bool bDoEne, bool bDoPrune)
 {
     const char* kernel_name_to_run;
     cl_kernel*  kernel_ptr;
     cl_int      cl_error;
 
-    GMX_ASSERT(eeltype < eelTypeNR,
+    const int elecTypeIdx = static_cast<int>(elecType);
+    const int vdwTypeIdx  = static_cast<int>(vdwType);
+
+    GMX_ASSERT(elecTypeIdx < c_numElecTypes,
                "The electrostatics type requested is not implemented in the OpenCL kernels.");
-    GMX_ASSERT(evdwtype < evdwTypeNR,
+    GMX_ASSERT(vdwTypeIdx < c_numVdwTypes,
                "The VdW type requested is not implemented in the OpenCL kernels.");
 
     if (bDoEne)
     {
         if (bDoPrune)
         {
-            kernel_name_to_run = nb_kfunc_ener_prune_ptr[eeltype][evdwtype];
-            kernel_ptr         = &(nb->kernel_ener_prune_ptr[eeltype][evdwtype]);
+            kernel_name_to_run = nb_kfunc_ener_prune_ptr[elecTypeIdx][vdwTypeIdx];
+            kernel_ptr         = &(nb->kernel_ener_prune_ptr[elecTypeIdx][vdwTypeIdx]);
         }
         else
         {
-            kernel_name_to_run = nb_kfunc_ener_noprune_ptr[eeltype][evdwtype];
-            kernel_ptr         = &(nb->kernel_ener_noprune_ptr[eeltype][evdwtype]);
+            kernel_name_to_run = nb_kfunc_ener_noprune_ptr[elecTypeIdx][vdwTypeIdx];
+            kernel_ptr         = &(nb->kernel_ener_noprune_ptr[elecTypeIdx][vdwTypeIdx]);
         }
     }
     else
     {
         if (bDoPrune)
         {
-            kernel_name_to_run = nb_kfunc_noener_prune_ptr[eeltype][evdwtype];
-            kernel_ptr         = &(nb->kernel_noener_prune_ptr[eeltype][evdwtype]);
+            kernel_name_to_run = nb_kfunc_noener_prune_ptr[elecTypeIdx][vdwTypeIdx];
+            kernel_ptr         = &(nb->kernel_noener_prune_ptr[elecTypeIdx][vdwTypeIdx]);
         }
         else
         {
-            kernel_name_to_run = nb_kfunc_noener_noprune_ptr[eeltype][evdwtype];
-            kernel_ptr         = &(nb->kernel_noener_noprune_ptr[eeltype][evdwtype]);
+            kernel_name_to_run = nb_kfunc_noener_noprune_ptr[elecTypeIdx][vdwTypeIdx];
+            kernel_ptr         = &(nb->kernel_noener_noprune_ptr[elecTypeIdx][vdwTypeIdx]);
         }
     }
 
     if (nullptr == kernel_ptr[0])
     {
         *kernel_ptr = clCreateKernel(nb->dev_rundata->program, kernel_name_to_run, &cl_error);
-        GMX_ASSERT(cl_error == CL_SUCCESS, ("clCreateKernel failed: " + ocl_get_error_string(cl_error)
-                                            + " for kernel named " + kernel_name_to_run)
-                                                   .c_str());
+        GMX_ASSERT(cl_error == CL_SUCCESS,
+                   ("clCreateKernel failed: " + ocl_get_error_string(cl_error)
+                    + " for kernel named " + kernel_name_to_run)
+                           .c_str());
     }
 
     return *kernel_ptr;
@@ -392,7 +425,7 @@ static inline cl_kernel select_nbnxn_kernel(NbnxmGpu* nb, int eeltype, int evdwt
 
 /*! \brief Calculates the amount of shared memory required by the nonbonded kernel in use.
  */
-static inline int calc_shmem_required_nonbonded(int vdwType, bool bPrefetchLjParam)
+static inline int calc_shmem_required_nonbonded(enum VdwType vdwType, bool bPrefetchLjParam)
 {
     int shmem;
 
@@ -438,7 +471,7 @@ static void fillin_ocl_structures(NBParamGpu* nbp, cl_nbparam_params_t* nbparams
     nbparams_params->coulomb_tab_scale = nbp->coulomb_tab_scale;
     nbparams_params->c_rf              = nbp->c_rf;
     nbparams_params->dispersion_shift  = nbp->dispersion_shift;
-    nbparams_params->eeltype           = nbp->eeltype;
+    nbparams_params->elecType          = nbp->elecType;
     nbparams_params->epsfac            = nbp->epsfac;
     nbparams_params->ewaldcoeff_lj     = nbp->ewaldcoeff_lj;
     nbparams_params->ewald_beta        = nbp->ewald_beta;
@@ -451,121 +484,10 @@ static void fillin_ocl_structures(NBParamGpu* nbp, cl_nbparam_params_t* nbparams
     nbparams_params->sh_ewald          = nbp->sh_ewald;
     nbparams_params->sh_lj_ewald       = nbp->sh_lj_ewald;
     nbparams_params->two_k_rf          = nbp->two_k_rf;
-    nbparams_params->vdwtype           = nbp->vdwtype;
+    nbparams_params->vdwType           = nbp->vdwType;
     nbparams_params->vdw_switch        = nbp->vdw_switch;
 }
 
-/*! \brief Enqueues a wait for event completion.
- *
- * Then it releases the event and sets it to 0.
- * Don't use this function when more than one wait will be issued for the event.
- * Equivalent to Cuda Stream Sync. */
-static void sync_ocl_event(cl_command_queue stream, cl_event* ocl_event)
-{
-    cl_int gmx_unused cl_error;
-
-    /* Enqueue wait */
-    cl_error = clEnqueueBarrierWithWaitList(stream, 1, ocl_event, nullptr);
-    GMX_RELEASE_ASSERT(CL_SUCCESS == cl_error, ocl_get_error_string(cl_error).c_str());
-
-    /* Release event and reset it to 0. It is ok to release it as enqueuewaitforevents performs implicit retain for events. */
-    cl_error = clReleaseEvent(*ocl_event);
-    GMX_ASSERT(cl_error == CL_SUCCESS,
-               ("clReleaseEvent failed: " + ocl_get_error_string(cl_error)).c_str());
-    *ocl_event = nullptr;
-}
-
-/*! \brief Launch asynchronously the xq buffer host to device copy. */
-void gpu_copy_xq_to_gpu(NbnxmGpu* nb, const nbnxn_atomdata_t* nbatom, const AtomLocality atomLocality)
-{
-    GMX_ASSERT(nb, "Need a valid nbnxn_gpu object");
-
-    const InteractionLocality iloc = gpuAtomToInteractionLocality(atomLocality);
-
-    /* local/nonlocal offset and length used for xq and f */
-    int adat_begin, adat_len;
-
-    cl_atomdata_t*      adat         = nb->atdat;
-    gpu_plist*          plist        = nb->plist[iloc];
-    cl_timers_t*        t            = nb->timers;
-    const DeviceStream& deviceStream = *nb->deviceStreams[iloc];
-
-    bool bDoTime = nb->bDoTime;
-
-    /* Don't launch the non-local H2D copy if there is no dependent
-       work to do: neither non-local nor other (e.g. bonded) work
-       to do that has as input the nbnxn coordinates.
-       Doing the same for the local kernel is more complicated, since the
-       local part of the force array also depends on the non-local kernel.
-       So to avoid complicating the code and to reduce the risk of bugs,
-       we always call the local local x+q copy (and the rest of the local
-       work in nbnxn_gpu_launch_kernel().
-     */
-    if ((iloc == InteractionLocality::NonLocal) && !haveGpuShortRangeWork(*nb, iloc))
-    {
-        plist->haveFreshList = false;
-
-        return;
-    }
-
-    /* calculate the atom data index range based on locality */
-    if (atomLocality == AtomLocality::Local)
-    {
-        adat_begin = 0;
-        adat_len   = adat->natoms_local;
-    }
-    else
-    {
-        adat_begin = adat->natoms_local;
-        adat_len   = adat->natoms - adat->natoms_local;
-    }
-
-    /* beginning of timed HtoD section */
-    if (bDoTime)
-    {
-        t->xf[atomLocality].nb_h2d.openTimingRegion(deviceStream);
-    }
-
-    /* HtoD x, q */
-    GMX_ASSERT(sizeof(float) == sizeof(*nbatom->x().data()),
-               "The size of the xyzq buffer element should be equal to the size of float4.");
-    copyToDeviceBuffer(&adat->xq, nbatom->x().data() + adat_begin * 4, adat_begin * 4, adat_len * 4,
-                       deviceStream, GpuApiCallBehavior::Async,
-                       bDoTime ? t->xf[atomLocality].nb_h2d.fetchNextEvent() : nullptr);
-
-    if (bDoTime)
-    {
-        t->xf[atomLocality].nb_h2d.closeTimingRegion(deviceStream);
-    }
-
-    /* When we get here all misc operations issues in the local stream as well as
-       the local xq H2D are done,
-       so we record that in the local stream and wait for it in the nonlocal one. */
-    if (nb->bUseTwoStreams)
-    {
-        if (iloc == InteractionLocality::Local)
-        {
-            cl_int gmx_used_in_debug cl_error = clEnqueueMarkerWithWaitList(
-                    deviceStream.stream(), 0, nullptr, &(nb->misc_ops_and_local_H2D_done));
-            GMX_ASSERT(cl_error == CL_SUCCESS,
-                       ("clEnqueueMarkerWithWaitList failed: " + ocl_get_error_string(cl_error)).c_str());
-
-            /* Based on the v1.2 section 5.13 of the OpenCL spec, a flush is needed
-             * in the local stream in order to be able to sync with the above event
-             * from the non-local stream.
-             */
-            cl_error = clFlush(deviceStream.stream());
-            GMX_ASSERT(cl_error == CL_SUCCESS,
-                       ("clFlush failed: " + ocl_get_error_string(cl_error)).c_str());
-        }
-        else
-        {
-            sync_ocl_event(deviceStream.stream(), &(nb->misc_ops_and_local_H2D_done));
-        }
-    }
-}
-
-
 /*! \brief Launch GPU kernel
 
    As we execute nonbonded workload in separate queues, before launching
@@ -586,10 +508,10 @@ void gpu_copy_xq_to_gpu(NbnxmGpu* nb, const nbnxn_atomdata_t* nbatom, const Atom
  */
 void gpu_launch_kernel(NbnxmGpu* nb, const gmx::StepWorkload& stepWork, const Nbnxm::InteractionLocality iloc)
 {
-    cl_atomdata_t*      adat         = nb->atdat;
+    NBAtomDataGpu*      adat         = nb->atdat;
     NBParamGpu*         nbp          = nb->nbparam;
     gpu_plist*          plist        = nb->plist[iloc];
-    cl_timers_t*        t            = nb->timers;
+    Nbnxm::GpuTimers*   timers       = nb->timers;
     const DeviceStream& deviceStream = *nb->deviceStreams[iloc];
 
     bool bDoTime = nb->bDoTime;
@@ -631,13 +553,13 @@ void gpu_launch_kernel(NbnxmGpu* nb, const gmx::StepWorkload& stepWork, const Nb
     /* beginning of timed nonbonded calculation section */
     if (bDoTime)
     {
-        t->interaction[iloc].nb_k.openTimingRegion(deviceStream);
+        timers->interaction[iloc].nb_k.openTimingRegion(deviceStream);
     }
 
     /* kernel launch config */
 
     KernelLaunchConfig config;
-    config.sharedMemorySize = calc_shmem_required_nonbonded(nbp->vdwtype, nb->bPrefetchLjParam);
+    config.sharedMemorySize = calc_shmem_required_nonbonded(nbp->vdwType, nb->bPrefetchLjParam);
     config.blockSize[0]     = c_clSize;
     config.blockSize[1]     = c_clSize;
     config.gridSize[0]      = plist->nsci;
@@ -649,45 +571,79 @@ void gpu_launch_kernel(NbnxmGpu* nb, const gmx::StepWorkload& stepWork, const Nb
         fprintf(debug,
                 "Non-bonded GPU launch configuration:\n\tLocal work size: %zux%zux%zu\n\t"
                 "Global work size : %zux%zu\n\t#Super-clusters/clusters: %d/%d (%d)\n",
-                config.blockSize[0], config.blockSize[1], config.blockSize[2],
-                config.blockSize[0] * config.gridSize[0], config.blockSize[1] * config.gridSize[1],
+                config.blockSize[0],
+                config.blockSize[1],
+                config.blockSize[2],
+                config.blockSize[0] * config.gridSize[0],
+                config.blockSize[1] * config.gridSize[1],
                 plist->nsci * c_nbnxnGpuNumClusterPerSupercluster,
-                c_nbnxnGpuNumClusterPerSupercluster, plist->na_c);
+                c_nbnxnGpuNumClusterPerSupercluster,
+                plist->na_c);
     }
 
     fillin_ocl_structures(nbp, &nbparams_params);
 
-    auto*          timingEvent  = bDoTime ? t->interaction[iloc].nb_k.fetchNextEvent() : nullptr;
+    auto* timingEvent = bDoTime ? timers->interaction[iloc].nb_k.fetchNextEvent() : nullptr;
     constexpr char kernelName[] = "k_calc_nb";
     const auto     kernel =
-            select_nbnxn_kernel(nb, nbp->eeltype, nbp->vdwtype, stepWork.computeEnergy,
+            select_nbnxn_kernel(nb,
+                                nbp->elecType,
+                                nbp->vdwType,
+                                stepWork.computeEnergy,
                                 (plist->haveFreshList && !nb->timers->interaction[iloc].didPrune));
 
 
     // The OpenCL kernel takes int as second to last argument because bool is
     // not supported as a kernel argument type (sizeof(bool) is implementation defined).
     const int computeFshift = static_cast<int>(stepWork.computeVirial);
-    if (useLjCombRule(nb->nbparam->vdwtype))
-    {
-        const auto kernelArgs = prepareGpuKernelArguments(
-                kernel, config, &nbparams_params, &adat->xq, &adat->f, &adat->e_lj, &adat->e_el,
-                &adat->fshift, &adat->lj_comb, &adat->shift_vec, &nbp->nbfp, &nbp->nbfp_comb,
-                &nbp->coulomb_tab, &plist->sci, &plist->cj4, &plist->excl, &computeFshift);
+    if (useLjCombRule(nb->nbparam->vdwType))
+    {
+        const auto kernelArgs = prepareGpuKernelArguments(kernel,
+                                                          config,
+                                                          &nbparams_params,
+                                                          &adat->xq,
+                                                          &adat->f,
+                                                          &adat->eLJ,
+                                                          &adat->eElec,
+                                                          &adat->fShift,
+                                                          &adat->ljComb,
+                                                          &adat->shiftVec,
+                                                          &nbp->nbfp,
+                                                          &nbp->nbfp_comb,
+                                                          &nbp->coulomb_tab,
+                                                          &plist->sci,
+                                                          &plist->cj4,
+                                                          &plist->excl,
+                                                          &computeFshift);
 
         launchGpuKernel(kernel, config, deviceStream, timingEvent, kernelName, kernelArgs);
     }
     else
     {
-        const auto kernelArgs = prepareGpuKernelArguments(
-                kernel, config, &adat->ntypes, &nbparams_params, &adat->xq, &adat->f, &adat->e_lj,
-                &adat->e_el, &adat->fshift, &adat->atom_types, &adat->shift_vec, &nbp->nbfp, &nbp->nbfp_comb,
-                &nbp->coulomb_tab, &plist->sci, &plist->cj4, &plist->excl, &computeFshift);
+        const auto kernelArgs = prepareGpuKernelArguments(kernel,
+                                                          config,
+                                                          &adat->numTypes,
+                                                          &nbparams_params,
+                                                          &adat->xq,
+                                                          &adat->f,
+                                                          &adat->eLJ,
+                                                          &adat->eElec,
+                                                          &adat->fShift,
+                                                          &adat->atomTypes,
+                                                          &adat->shiftVec,
+                                                          &nbp->nbfp,
+                                                          &nbp->nbfp_comb,
+                                                          &nbp->coulomb_tab,
+                                                          &plist->sci,
+                                                          &plist->cj4,
+                                                          &plist->excl,
+                                                          &computeFshift);
         launchGpuKernel(kernel, config, deviceStream, timingEvent, kernelName, kernelArgs);
     }
 
     if (bDoTime)
     {
-        t->interaction[iloc].nb_k.closeTimingRegion(deviceStream);
+        timers->interaction[iloc].nb_k.closeTimingRegion(deviceStream);
     }
 }
 
@@ -723,10 +679,10 @@ static inline int calc_shmem_required_prune(const int num_threads_z)
  */
 void gpu_launch_kernel_pruneonly(NbnxmGpu* nb, const InteractionLocality iloc, const int numParts)
 {
-    cl_atomdata_t*      adat         = nb->atdat;
+    NBAtomDataGpu*      adat         = nb->atdat;
     NBParamGpu*         nbp          = nb->nbparam;
     gpu_plist*          plist        = nb->plist[iloc];
-    cl_timers_t*        t            = nb->timers;
+    Nbnxm::GpuTimers*   timers       = nb->timers;
     const DeviceStream& deviceStream = *nb->deviceStreams[iloc];
     bool                bDoTime      = nb->bDoTime;
 
@@ -776,7 +732,8 @@ void gpu_launch_kernel_pruneonly(NbnxmGpu* nb, const InteractionLocality iloc, c
     GpuRegionTimer* timer = nullptr;
     if (bDoTime)
     {
-        timer = &(plist->haveFreshList ? t->interaction[iloc].prune_k : t->interaction[iloc].rollingPrune_k);
+        timer = &(plist->haveFreshList ? timers->interaction[iloc].prune_k
+                                       : timers->interaction[iloc].rollingPrune_k);
     }
 
     /* beginning of timed prune calculation section */
@@ -790,9 +747,7 @@ void gpu_launch_kernel_pruneonly(NbnxmGpu* nb, const InteractionLocality iloc, c
      *   and j-cluster concurrency, in x, y, and z, respectively.
      * - The 1D block-grid contains as many blocks as super-clusters.
      */
-    int num_threads_z = c_oclPruneKernelJ4ConcurrencyDEFAULT;
-
-
+    int num_threads_z = c_pruneKernelJ4Concurrency;
     /* kernel launch config */
     KernelLaunchConfig config;
     config.sharedMemorySize = calc_shmem_required_prune(num_threads_z);
@@ -809,10 +764,15 @@ void gpu_launch_kernel_pruneonly(NbnxmGpu* nb, const InteractionLocality iloc, c
                 "Pruning GPU kernel launch configuration:\n\tLocal work size: %zux%zux%zu\n\t"
                 "\tGlobal work size: %zux%zu\n\t#Super-clusters/clusters: %d/%d (%d)\n"
                 "\tShMem: %zu\n",
-                config.blockSize[0], config.blockSize[1], config.blockSize[2],
-                config.blockSize[0] * config.gridSize[0], config.blockSize[1] * config.gridSize[1],
+                config.blockSize[0],
+                config.blockSize[1],
+                config.blockSize[2],
+                config.blockSize[0] * config.gridSize[0],
+                config.blockSize[1] * config.gridSize[1],
                 plist->nsci * c_nbnxnGpuNumClusterPerSupercluster,
-                c_nbnxnGpuNumClusterPerSupercluster, plist->na_c, config.sharedMemorySize);
+                c_nbnxnGpuNumClusterPerSupercluster,
+                plist->na_c,
+                config.sharedMemorySize);
     }
 
     cl_nbparam_params_t nbparams_params;
@@ -821,9 +781,16 @@ void gpu_launch_kernel_pruneonly(NbnxmGpu* nb, const InteractionLocality iloc, c
     auto*          timingEvent  = bDoTime ? timer->fetchNextEvent() : nullptr;
     constexpr char kernelName[] = "k_pruneonly";
     const auto     pruneKernel  = selectPruneKernel(nb->kernel_pruneonly, plist->haveFreshList);
-    const auto     kernelArgs   = prepareGpuKernelArguments(pruneKernel, config, &nbparams_params,
-                                                      &adat->xq, &adat->shift_vec, &plist->sci,
-                                                      &plist->cj4, &plist->imask, &numParts, &part);
+    const auto     kernelArgs   = prepareGpuKernelArguments(pruneKernel,
+                                                      config,
+                                                      &nbparams_params,
+                                                      &adat->xq,
+                                                      &adat->shiftVec,
+                                                      &plist->sci,
+                                                      &plist->cj4,
+                                                      &plist->imask,
+                                                      &numParts,
+                                                      &part);
     launchGpuKernel(pruneKernel, config, deviceStream, timingEvent, kernelName, kernelArgs);
 
     if (plist->haveFreshList)
@@ -844,113 +811,4 @@ void gpu_launch_kernel_pruneonly(NbnxmGpu* nb, const InteractionLocality iloc, c
     }
 }
 
-/*! \brief
- * Launch asynchronously the download of nonbonded forces from the GPU
- * (and energies/shift forces if required).
- */
-void gpu_launch_cpyback(NbnxmGpu*                nb,
-                        struct nbnxn_atomdata_t* nbatom,
-                        const gmx::StepWorkload& stepWork,
-                        const AtomLocality       aloc)
-{
-    GMX_ASSERT(nb, "Need a valid nbnxn_gpu object");
-
-    cl_int gmx_unused cl_error;
-    int               adat_begin, adat_len; /* local/nonlocal offset and length used for xq and f */
-
-    /* determine interaction locality from atom locality */
-    const InteractionLocality iloc = gpuAtomToInteractionLocality(aloc);
-
-    cl_atomdata_t*      adat         = nb->atdat;
-    cl_timers_t*        t            = nb->timers;
-    bool                bDoTime      = nb->bDoTime;
-    const DeviceStream& deviceStream = *nb->deviceStreams[iloc];
-
-    /* don't launch non-local copy-back if there was no non-local work to do */
-    if ((iloc == InteractionLocality::NonLocal) && !haveGpuShortRangeWork(*nb, iloc))
-    {
-        /* TODO An alternative way to signal that non-local work is
-           complete is to use a clEnqueueMarker+clEnqueueBarrier
-           pair. However, the use of bNonLocalStreamActive has the
-           advantage of being local to the host, so probably minimizes
-           overhead. Curiously, for NVIDIA OpenCL with an empty-domain
-           test case, overall simulation performance was higher with
-           the API calls, but this has not been tested on AMD OpenCL,
-           so could be worth considering in future. */
-        nb->bNonLocalStreamActive = CL_FALSE;
-        return;
-    }
-
-    getGpuAtomRange(adat, aloc, &adat_begin, &adat_len);
-
-    /* beginning of timed D2H section */
-    if (bDoTime)
-    {
-        t->xf[aloc].nb_d2h.openTimingRegion(deviceStream);
-    }
-
-    /* With DD the local D2H transfer can only start after the non-local
-       has been launched. */
-    if (iloc == InteractionLocality::Local && nb->bNonLocalStreamActive)
-    {
-        sync_ocl_event(deviceStream.stream(), &(nb->nonlocal_done));
-    }
-
-    /* DtoH f */
-    GMX_ASSERT(sizeof(*nbatom->out[0].f.data()) == sizeof(float),
-               "The host force buffer should be in single precision to match device data size.");
-    copyFromDeviceBuffer(&nbatom->out[0].f[adat_begin * DIM], &adat->f, adat_begin * DIM,
-                         adat_len * DIM, deviceStream, GpuApiCallBehavior::Async,
-                         bDoTime ? t->xf[aloc].nb_d2h.fetchNextEvent() : nullptr);
-
-    /* kick off work */
-    cl_error = clFlush(deviceStream.stream());
-    GMX_ASSERT(cl_error == CL_SUCCESS, ("clFlush failed: " + ocl_get_error_string(cl_error)).c_str());
-
-    /* After the non-local D2H is launched the nonlocal_done event can be
-       recorded which signals that the local D2H can proceed. This event is not
-       placed after the non-local kernel because we first need the non-local
-       data back first. */
-    if (iloc == InteractionLocality::NonLocal)
-    {
-        cl_error = clEnqueueMarkerWithWaitList(deviceStream.stream(), 0, nullptr, &(nb->nonlocal_done));
-        GMX_ASSERT(cl_error == CL_SUCCESS,
-                   ("clEnqueueMarkerWithWaitList failed: " + ocl_get_error_string(cl_error)).c_str());
-        nb->bNonLocalStreamActive = CL_TRUE;
-    }
-
-    /* only transfer energies in the local stream */
-    if (iloc == InteractionLocality::Local)
-    {
-        /* DtoH fshift when virial is needed */
-        if (stepWork.computeVirial)
-        {
-            GMX_ASSERT(sizeof(*nb->nbst.fshift) == DIM * sizeof(float),
-                       "Sizes of host- and device-side shift vector elements should be the same.");
-            copyFromDeviceBuffer(reinterpret_cast<float*>(nb->nbst.fshift), &adat->fshift, 0,
-                                 SHIFTS * DIM, deviceStream, GpuApiCallBehavior::Async,
-                                 bDoTime ? t->xf[aloc].nb_d2h.fetchNextEvent() : nullptr);
-        }
-
-        /* DtoH energies */
-        if (stepWork.computeEnergy)
-        {
-            GMX_ASSERT(sizeof(*nb->nbst.e_lj) == sizeof(float),
-                       "Sizes of host- and device-side LJ energy terms should be the same.");
-            copyFromDeviceBuffer(nb->nbst.e_lj, &adat->e_lj, 0, 1, deviceStream, GpuApiCallBehavior::Async,
-                                 bDoTime ? t->xf[aloc].nb_d2h.fetchNextEvent() : nullptr);
-            GMX_ASSERT(sizeof(*nb->nbst.e_el) == sizeof(float),
-                       "Sizes of host- and device-side electrostatic energy terms should be the "
-                       "same.");
-            copyFromDeviceBuffer(nb->nbst.e_el, &adat->e_el, 0, 1, deviceStream, GpuApiCallBehavior::Async,
-                                 bDoTime ? t->xf[aloc].nb_d2h.fetchNextEvent() : nullptr);
-        }
-    }
-
-    if (bDoTime)
-    {
-        t->xf[aloc].nb_d2h.closeTimingRegion(deviceStream);
-    }
-}
-
 } // namespace Nbnxm
index 87872c6552eec67a01d182e40fe1786a81ebe64a..bef4f21f16e282a1e0fe4e240498f5c6b52b2234 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * \author Berk Hess <hess@kth.se>
  * \ingroup module_nbnxm
  */
-#ifndef NBNXN_OPENCL_CONSTS_H
-#define NBNXN_OPENCL_CONSTS_H
+#ifndef NBNXN_OCL_CONSTS_H
+#define NBNXN_OCL_CONSTS_H
 
-/*! \internal \file
- * \brief Macros defining platform-dependent defaults for the prune kernel's j4 processing concurrency.
- *
- *  The GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY macro allows compile-time override.
+/*! \brief Macro definining default for the prune kernel's j4 processing concurrency.
  *
- * \ingroup module_nbnxm
+ *  The GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY macro allows compile-time override with the default value of 4.
  */
-/*! @{ */
-#define GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY_DEFAULT 4
-// The following has to match getOclPruneKernelJ4Concurrency
-#define GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY_DEFAULT
-/*! @} */
+#ifndef GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY
+#    define GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY 4
+#endif
+
 #endif
index ac99cf926d7a94b25427712ac54888df86e4bcda..ea901eb7157196c521144bbf3179a0a7bd7ef0b7 100644 (file)
@@ -52,8 +52,7 @@
 
 #include <cmath>
 
-#include "gromacs/gpu_utils/device_stream_manager.h"
-#include "gromacs/gpu_utils/oclutils.h"
+#include "gromacs/gpu_utils/pmalloc.h"
 #include "gromacs/hardware/device_information.h"
 #include "gromacs/hardware/device_management.h"
 #include "gromacs/math/vectypes.h"
@@ -67,7 +66,6 @@
 #include "gromacs/nbnxm/nbnxm_gpu.h"
 #include "gromacs/nbnxm/nbnxm_gpu_data_mgmt.h"
 #include "gromacs/nbnxm/pairlistsets.h"
-#include "gromacs/pbcutil/ishift.h"
 #include "gromacs/timing/gpu_timing.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
@@ -99,158 +97,6 @@ namespace Nbnxm
  */
 static unsigned int gpu_min_ci_balanced_factor = 50;
 
-
-/*! \brief Initializes the atomdata structure first time, it only gets filled at
-    pair-search.
- */
-static void init_atomdata_first(cl_atomdata_t* ad, int ntypes, const DeviceContext& deviceContext)
-{
-    ad->ntypes = ntypes;
-
-    allocateDeviceBuffer(&ad->shift_vec, SHIFTS * DIM, deviceContext);
-    ad->bShiftVecUploaded = CL_FALSE;
-
-    allocateDeviceBuffer(&ad->fshift, SHIFTS * DIM, deviceContext);
-    allocateDeviceBuffer(&ad->e_lj, 1, deviceContext);
-    allocateDeviceBuffer(&ad->e_el, 1, deviceContext);
-
-    /* initialize to nullptr pointers to data that is not allocated here and will
-       need reallocation in nbnxn_gpu_init_atomdata */
-    ad->xq = nullptr;
-    ad->f  = nullptr;
-
-    /* size -1 indicates that the respective array hasn't been initialized yet */
-    ad->natoms = -1;
-    ad->nalloc = -1;
-}
-
-/*! \brief Returns the kinds of electrostatics and Vdw OpenCL
- *  kernels that will be used.
- *
- * Respectively, these values are from enum eelOcl and enum
- * evdwOcl. */
-static void map_interaction_types_to_gpu_kernel_flavors(const interaction_const_t* ic,
-                                                        int                        combRule,
-                                                        int*                       gpu_eeltype,
-                                                        int*                       gpu_vdwtype,
-                                                        const DeviceContext&       deviceContext)
-{
-    if (ic->vdwtype == evdwCUT)
-    {
-        switch (ic->vdw_modifier)
-        {
-            case eintmodNONE:
-            case eintmodPOTSHIFT:
-                switch (combRule)
-                {
-                    case ljcrNONE: *gpu_vdwtype = evdwTypeCUT; break;
-                    case ljcrGEOM: *gpu_vdwtype = evdwTypeCUTCOMBGEOM; break;
-                    case ljcrLB: *gpu_vdwtype = evdwTypeCUTCOMBLB; break;
-                    default:
-                        gmx_incons(
-                                "The requested LJ combination rule is not implemented in the "
-                                "OpenCL GPU accelerated kernels!");
-                }
-                break;
-            case eintmodFORCESWITCH: *gpu_vdwtype = evdwTypeFSWITCH; break;
-            case eintmodPOTSWITCH: *gpu_vdwtype = evdwTypePSWITCH; break;
-            default:
-                gmx_incons(
-                        "The requested VdW interaction modifier is not implemented in the GPU "
-                        "accelerated kernels!");
-        }
-    }
-    else if (ic->vdwtype == evdwPME)
-    {
-        if (ic->ljpme_comb_rule == ljcrGEOM)
-        {
-            *gpu_vdwtype = evdwTypeEWALDGEOM;
-        }
-        else
-        {
-            *gpu_vdwtype = evdwTypeEWALDLB;
-        }
-    }
-    else
-    {
-        gmx_incons("The requested VdW type is not implemented in the GPU accelerated kernels!");
-    }
-
-    if (ic->eeltype == eelCUT)
-    {
-        *gpu_eeltype = eelTypeCUT;
-    }
-    else if (EEL_RF(ic->eeltype))
-    {
-        *gpu_eeltype = eelTypeRF;
-    }
-    else if ((EEL_PME(ic->eeltype) || ic->eeltype == eelEWALD))
-    {
-        *gpu_eeltype = nbnxn_gpu_pick_ewald_kernel_type(*ic, deviceContext.deviceInfo());
-    }
-    else
-    {
-        /* Shouldn't happen, as this is checked when choosing Verlet-scheme */
-        gmx_incons(
-                "The requested electrostatics type is not implemented in the GPU accelerated "
-                "kernels!");
-    }
-}
-
-/*! \brief Initializes the nonbonded parameter data structure.
- */
-static void init_nbparam(NBParamGpu*                     nbp,
-                         const interaction_const_t*      ic,
-                         const PairlistParams&           listParams,
-                         const nbnxn_atomdata_t::Params& nbatParams,
-                         const DeviceContext&            deviceContext)
-{
-    set_cutoff_parameters(nbp, ic, listParams);
-
-    map_interaction_types_to_gpu_kernel_flavors(ic, nbatParams.comb_rule, &(nbp->eeltype),
-                                                &(nbp->vdwtype), deviceContext);
-
-    if (ic->vdwtype == evdwPME)
-    {
-        if (ic->ljpme_comb_rule == ljcrGEOM)
-        {
-            GMX_ASSERT(nbatParams.comb_rule == ljcrGEOM, "Combination rule mismatch!");
-        }
-        else
-        {
-            GMX_ASSERT(nbatParams.comb_rule == ljcrLB, "Combination rule mismatch!");
-        }
-    }
-    /* generate table for PME */
-    nbp->coulomb_tab = nullptr;
-    if (nbp->eeltype == eelTypeEWALD_TAB || nbp->eeltype == eelTypeEWALD_TAB_TWIN)
-    {
-        GMX_RELEASE_ASSERT(ic->coulombEwaldTables, "Need valid Coulomb Ewald correction tables");
-        init_ewald_coulomb_force_table(*ic->coulombEwaldTables, nbp, deviceContext);
-    }
-    else
-    {
-        allocateDeviceBuffer(&nbp->coulomb_tab, 1, deviceContext);
-    }
-
-    const int nnbfp      = 2 * nbatParams.numTypes * nbatParams.numTypes;
-    const int nnbfp_comb = 2 * nbatParams.numTypes;
-
-    {
-        /* set up LJ parameter lookup table */
-        DeviceBuffer<real> nbfp;
-        initParamLookupTable(&nbfp, nullptr, nbatParams.nbfp.data(), nnbfp, deviceContext);
-        nbp->nbfp = nbfp;
-
-        if (ic->vdwtype == evdwPME)
-        {
-            DeviceBuffer<float> nbfp_comb;
-            initParamLookupTable(&nbfp_comb, nullptr, nbatParams.nbfp_comb.data(), nnbfp_comb, deviceContext);
-            nbp->nbfp_comb = nbfp_comb;
-        }
-    }
-}
-
 /*! \brief Initializes the OpenCL kernel pointers of the nbnxn_ocl_ptr_t input data structure. */
 static cl_kernel nbnxn_gpu_create_kernel(NbnxmGpu* nb, const char* kernel_name)
 {
@@ -260,47 +106,16 @@ static cl_kernel nbnxn_gpu_create_kernel(NbnxmGpu* nb, const char* kernel_name)
     kernel = clCreateKernel(nb->dev_rundata->program, kernel_name, &cl_error);
     if (CL_SUCCESS != cl_error)
     {
-        gmx_fatal(FARGS, "Failed to create kernel '%s' for GPU #%s: OpenCL error %d", kernel_name,
-                  nb->deviceContext_->deviceInfo().device_name, cl_error);
+        gmx_fatal(FARGS,
+                  "Failed to create kernel '%s' for GPU #%s: OpenCL error %d",
+                  kernel_name,
+                  nb->deviceContext_->deviceInfo().device_name,
+                  cl_error);
     }
 
     return kernel;
 }
 
-/*! \brief Clears nonbonded shift force output array and energy outputs on the GPU.
- */
-static void nbnxn_ocl_clear_e_fshift(NbnxmGpu* nb)
-{
-
-    cl_int           cl_error;
-    cl_atomdata_t*   adat = nb->atdat;
-    cl_command_queue ls   = nb->deviceStreams[InteractionLocality::Local]->stream();
-
-    size_t local_work_size[3]  = { 1, 1, 1 };
-    size_t global_work_size[3] = { 1, 1, 1 };
-
-    cl_int shifts = SHIFTS * 3;
-
-    cl_int arg_no;
-
-    cl_kernel zero_e_fshift = nb->kernel_zero_e_fshift;
-
-    local_work_size[0] = 64;
-    // Round the total number of threads up from the array size
-    global_work_size[0] = ((shifts + local_work_size[0] - 1) / local_work_size[0]) * local_work_size[0];
-
-    arg_no   = 0;
-    cl_error = clSetKernelArg(zero_e_fshift, arg_no++, sizeof(cl_mem), &(adat->fshift));
-    cl_error |= clSetKernelArg(zero_e_fshift, arg_no++, sizeof(cl_mem), &(adat->e_lj));
-    cl_error |= clSetKernelArg(zero_e_fshift, arg_no++, sizeof(cl_mem), &(adat->e_el));
-    cl_error |= clSetKernelArg(zero_e_fshift, arg_no++, sizeof(cl_uint), &shifts);
-    GMX_ASSERT(cl_error == CL_SUCCESS, ocl_get_error_string(cl_error).c_str());
-
-    cl_error = clEnqueueNDRangeKernel(ls, zero_e_fshift, 3, nullptr, global_work_size,
-                                      local_work_size, 0, nullptr, nullptr);
-    GMX_ASSERT(cl_error == CL_SUCCESS, ocl_get_error_string(cl_error).c_str());
-}
-
 /*! \brief Initializes the OpenCL kernel pointers of the nbnxn_ocl_ptr_t input data structure. */
 static void nbnxn_gpu_init_kernels(NbnxmGpu* nb)
 {
@@ -321,89 +136,13 @@ static void nbnxn_gpu_init_kernels(NbnxmGpu* nb)
     nb->kernel_pruneonly[epruneFirst] = nbnxn_gpu_create_kernel(nb, "nbnxn_kernel_prune_opencl");
     nb->kernel_pruneonly[epruneRolling] =
             nbnxn_gpu_create_kernel(nb, "nbnxn_kernel_prune_rolling_opencl");
-
-    /* Init auxiliary kernels */
-    nb->kernel_zero_e_fshift = nbnxn_gpu_create_kernel(nb, "zero_e_fshift");
-}
-
-/*! \brief Initializes simulation constant data.
- *
- *  Initializes members of the atomdata and nbparam structs and
- *  clears e/fshift output buffers.
- */
-static void nbnxn_ocl_init_const(cl_atomdata_t*                  atomData,
-                                 NBParamGpu*                     nbParams,
-                                 const interaction_const_t*      ic,
-                                 const PairlistParams&           listParams,
-                                 const nbnxn_atomdata_t::Params& nbatParams,
-                                 const DeviceContext&            deviceContext)
-{
-    init_atomdata_first(atomData, nbatParams.numTypes, deviceContext);
-    init_nbparam(nbParams, ic, listParams, nbatParams, deviceContext);
 }
 
-
-//! This function is documented in the header file
-NbnxmGpu* gpu_init(const gmx::DeviceStreamManager& deviceStreamManager,
-                   const interaction_const_t*      ic,
-                   const PairlistParams&           listParams,
-                   const nbnxn_atomdata_t*         nbat,
-                   const bool                      bLocalAndNonlocal)
+void gpu_init_platform_specific(NbnxmGpu* nb)
 {
-    GMX_ASSERT(ic, "Need a valid interaction constants object");
-
-    auto nb            = new NbnxmGpu();
-    nb->deviceContext_ = &deviceStreamManager.context();
-    snew(nb->atdat, 1);
-    snew(nb->nbparam, 1);
-    snew(nb->plist[InteractionLocality::Local], 1);
-    if (bLocalAndNonlocal)
-    {
-        snew(nb->plist[InteractionLocality::NonLocal], 1);
-    }
-
-    nb->bUseTwoStreams = bLocalAndNonlocal;
-
-    nb->timers = new cl_timers_t();
-    snew(nb->timings, 1);
-
     /* set device info, just point it to the right GPU among the detected ones */
     nb->dev_rundata = new gmx_device_runtime_data_t();
 
-    /* init nbst */
-    pmalloc(reinterpret_cast<void**>(&nb->nbst.e_lj), sizeof(*nb->nbst.e_lj));
-    pmalloc(reinterpret_cast<void**>(&nb->nbst.e_el), sizeof(*nb->nbst.e_el));
-    pmalloc(reinterpret_cast<void**>(&nb->nbst.fshift), SHIFTS * sizeof(*nb->nbst.fshift));
-
-    init_plist(nb->plist[InteractionLocality::Local]);
-
-    /* OpenCL timing disabled if GMX_DISABLE_GPU_TIMING is defined. */
-    nb->bDoTime = (getenv("GMX_DISABLE_GPU_TIMING") == nullptr);
-
-    /* local/non-local GPU streams */
-    GMX_RELEASE_ASSERT(deviceStreamManager.streamIsValid(gmx::DeviceStreamType::NonBondedLocal),
-                       "Local non-bonded stream should be initialized to use GPU for non-bonded.");
-    nb->deviceStreams[InteractionLocality::Local] =
-            &deviceStreamManager.stream(gmx::DeviceStreamType::NonBondedLocal);
-
-    if (nb->bUseTwoStreams)
-    {
-        init_plist(nb->plist[InteractionLocality::NonLocal]);
-
-        GMX_RELEASE_ASSERT(deviceStreamManager.streamIsValid(gmx::DeviceStreamType::NonBondedNonLocal),
-                           "Non-local non-bonded stream should be initialized to use GPU for "
-                           "non-bonded with domain decomposition.");
-        nb->deviceStreams[InteractionLocality::NonLocal] =
-                &deviceStreamManager.stream(gmx::DeviceStreamType::NonBondedNonLocal);
-    }
-
-    if (nb->bDoTime)
-    {
-        init_timings(nb->timings);
-    }
-
-    nbnxn_ocl_init_const(nb->atdat, nb->nbparam, ic, listParams, nbat->params(), *nb->deviceContext_);
-
     /* Enable LJ param manual prefetch for AMD or Intel or if we request through env. var.
      * TODO: decide about NVIDIA
      */
@@ -418,167 +157,16 @@ NbnxmGpu* gpu_init(const gmx::DeviceStreamManager& deviceStreamManager,
      */
     nbnxn_gpu_compile_kernels(nb);
     nbnxn_gpu_init_kernels(nb);
-
-    /* clear energy and shift force outputs */
-    nbnxn_ocl_clear_e_fshift(nb);
-
-    if (debug)
-    {
-        fprintf(debug, "Initialized OpenCL data structures.\n");
-    }
-
-    return nb;
-}
-
-/*! \brief Clears the first natoms_clear elements of the GPU nonbonded force output array.
- */
-static void nbnxn_ocl_clear_f(NbnxmGpu* nb, int natoms_clear)
-{
-    if (natoms_clear == 0)
-    {
-        return;
-    }
-
-    cl_atomdata_t*      atomData    = nb->atdat;
-    const DeviceStream& localStream = *nb->deviceStreams[InteractionLocality::Local];
-
-    clearDeviceBufferAsync(&atomData->f, 0, natoms_clear * DIM, localStream);
-}
-
-//! This function is documented in the header file
-void gpu_clear_outputs(NbnxmGpu* nb, bool computeVirial)
-{
-    nbnxn_ocl_clear_f(nb, nb->atdat->natoms);
-    /* clear shift force array and energies if the outputs were
-       used in the current step */
-    if (computeVirial)
-    {
-        nbnxn_ocl_clear_e_fshift(nb);
-    }
-
-    /* kick off buffer clearing kernel to ensure concurrency with constraints/update */
-    cl_int gmx_unused cl_error;
-    cl_error = clFlush(nb->deviceStreams[InteractionLocality::Local]->stream());
-    GMX_ASSERT(cl_error == CL_SUCCESS, ("clFlush failed: " + ocl_get_error_string(cl_error)).c_str());
-}
-
-//! This function is documented in the header file
-void gpu_upload_shiftvec(NbnxmGpu* nb, const nbnxn_atomdata_t* nbatom)
-{
-    cl_atomdata_t*      adat         = nb->atdat;
-    const DeviceStream& deviceStream = *nb->deviceStreams[InteractionLocality::Local];
-
-    /* only if we have a dynamic box */
-    if (nbatom->bDynamicBox || !adat->bShiftVecUploaded)
-    {
-        GMX_ASSERT(sizeof(float) * DIM == sizeof(*nbatom->shift_vec.data()),
-                   "Sizes of host- and device-side shift vectors should be the same.");
-        copyToDeviceBuffer(&adat->shift_vec, reinterpret_cast<const float*>(nbatom->shift_vec.data()),
-                           0, SHIFTS * DIM, deviceStream, GpuApiCallBehavior::Async, nullptr);
-        adat->bShiftVecUploaded = CL_TRUE;
-    }
-}
-
-//! This function is documented in the header file
-void gpu_init_atomdata(NbnxmGpu* nb, const nbnxn_atomdata_t* nbat)
-{
-    cl_int               cl_error;
-    int                  nalloc, natoms;
-    bool                 realloced;
-    bool                 bDoTime       = nb->bDoTime;
-    cl_timers_t*         timers        = nb->timers;
-    cl_atomdata_t*       d_atdat       = nb->atdat;
-    const DeviceContext& deviceContext = *nb->deviceContext_;
-    const DeviceStream&  deviceStream  = *nb->deviceStreams[InteractionLocality::Local];
-
-    natoms    = nbat->numAtoms();
-    realloced = false;
-
-    if (bDoTime)
-    {
-        /* time async copy */
-        timers->atdat.openTimingRegion(deviceStream);
-    }
-
-    /* need to reallocate if we have to copy more atoms than the amount of space
-       available and only allocate if we haven't initialized yet, i.e d_atdat->natoms == -1 */
-    if (natoms > d_atdat->nalloc)
-    {
-        nalloc = over_alloc_small(natoms);
-
-        /* free up first if the arrays have already been initialized */
-        if (d_atdat->nalloc != -1)
-        {
-            freeDeviceBuffer(&d_atdat->f);
-            freeDeviceBuffer(&d_atdat->xq);
-            freeDeviceBuffer(&d_atdat->lj_comb);
-            freeDeviceBuffer(&d_atdat->atom_types);
-        }
-
-
-        allocateDeviceBuffer(&d_atdat->f, nalloc * DIM, deviceContext);
-        allocateDeviceBuffer(&d_atdat->xq, nalloc * (DIM + 1), deviceContext);
-
-        if (useLjCombRule(nb->nbparam->vdwtype))
-        {
-            // Two Lennard-Jones parameters per atom
-            allocateDeviceBuffer(&d_atdat->lj_comb, nalloc * 2, deviceContext);
-        }
-        else
-        {
-            allocateDeviceBuffer(&d_atdat->atom_types, nalloc, deviceContext);
-        }
-
-        d_atdat->nalloc = nalloc;
-        realloced       = true;
-    }
-
-    d_atdat->natoms       = natoms;
-    d_atdat->natoms_local = nbat->natoms_local;
-
-    /* need to clear GPU f output if realloc happened */
-    if (realloced)
-    {
-        nbnxn_ocl_clear_f(nb, nalloc);
-    }
-
-    if (useLjCombRule(nb->nbparam->vdwtype))
-    {
-        GMX_ASSERT(sizeof(float) == sizeof(*nbat->params().lj_comb.data()),
-                   "Size of the LJ parameters element should be equal to the size of float2.");
-        copyToDeviceBuffer(&d_atdat->lj_comb, nbat->params().lj_comb.data(), 0, 2 * natoms,
-                           deviceStream, GpuApiCallBehavior::Async,
-                           bDoTime ? timers->atdat.fetchNextEvent() : nullptr);
-    }
-    else
-    {
-        GMX_ASSERT(sizeof(int) == sizeof(*nbat->params().type.data()),
-                   "Sizes of host- and device-side atom types should be the same.");
-        copyToDeviceBuffer(&d_atdat->atom_types, nbat->params().type.data(), 0, natoms, deviceStream,
-                           GpuApiCallBehavior::Async, bDoTime ? timers->atdat.fetchNextEvent() : nullptr);
-    }
-
-    if (bDoTime)
-    {
-        timers->atdat.closeTimingRegion(deviceStream);
-    }
-
-    /* kick off the tasks enqueued above to ensure concurrency with the search */
-    cl_error = clFlush(deviceStream.stream());
-    GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
-                       ("clFlush failed: " + ocl_get_error_string(cl_error)).c_str());
 }
 
 /*! \brief Releases an OpenCL kernel pointer */
 static void free_kernel(cl_kernel* kernel_ptr)
 {
-    cl_int gmx_unused cl_error;
-
     GMX_ASSERT(kernel_ptr, "Need a valid kernel pointer");
 
     if (*kernel_ptr)
     {
-        cl_error = clReleaseKernel(*kernel_ptr);
+        cl_int cl_error = clReleaseKernel(*kernel_ptr);
         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
                            ("clReleaseKernel failed: " + ocl_get_error_string(cl_error)).c_str());
 
@@ -589,9 +177,7 @@ static void free_kernel(cl_kernel* kernel_ptr)
 /*! \brief Releases a list of OpenCL kernel pointers */
 static void free_kernels(cl_kernel* kernels, int count)
 {
-    int i;
-
-    for (i = 0; i < count; i++)
+    for (int i = 0; i < count; i++)
     {
         free_kernel(kernels + i);
     }
@@ -616,13 +202,8 @@ static void freeGpuProgram(cl_program program)
 }
 
 //! This function is documented in the header file
-void gpu_free(NbnxmGpu* nb)
+void gpu_free_platform_specific(NbnxmGpu* nb)
 {
-    if (nb == nullptr)
-    {
-        return;
-    }
-
     /* Free kernels */
     // NOLINTNEXTLINE(bugprone-sizeof-expression)
     int kernel_count = sizeof(nb->kernel_ener_noprune_ptr) / sizeof(nb->kernel_ener_noprune_ptr[0][0]);
@@ -640,76 +221,8 @@ void gpu_free(NbnxmGpu* nb)
     kernel_count = sizeof(nb->kernel_noener_prune_ptr) / sizeof(nb->kernel_noener_prune_ptr[0][0]);
     free_kernels(nb->kernel_noener_prune_ptr[0], kernel_count);
 
-    free_kernel(&(nb->kernel_zero_e_fshift));
-
-    /* Free atdat */
-    freeDeviceBuffer(&(nb->atdat->xq));
-    freeDeviceBuffer(&(nb->atdat->f));
-    freeDeviceBuffer(&(nb->atdat->e_lj));
-    freeDeviceBuffer(&(nb->atdat->e_el));
-    freeDeviceBuffer(&(nb->atdat->fshift));
-    freeDeviceBuffer(&(nb->atdat->lj_comb));
-    freeDeviceBuffer(&(nb->atdat->atom_types));
-    freeDeviceBuffer(&(nb->atdat->shift_vec));
-    sfree(nb->atdat);
-
-    /* Free nbparam */
-    freeDeviceBuffer(&(nb->nbparam->nbfp));
-    freeDeviceBuffer(&(nb->nbparam->nbfp_comb));
-    freeDeviceBuffer(&(nb->nbparam->coulomb_tab));
-    sfree(nb->nbparam);
-
-    /* Free plist */
-    auto* plist = nb->plist[InteractionLocality::Local];
-    freeDeviceBuffer(&plist->sci);
-    freeDeviceBuffer(&plist->cj4);
-    freeDeviceBuffer(&plist->imask);
-    freeDeviceBuffer(&plist->excl);
-    sfree(plist);
-    if (nb->bUseTwoStreams)
-    {
-        auto* plist_nl = nb->plist[InteractionLocality::NonLocal];
-        freeDeviceBuffer(&plist_nl->sci);
-        freeDeviceBuffer(&plist_nl->cj4);
-        freeDeviceBuffer(&plist_nl->imask);
-        freeDeviceBuffer(&plist_nl->excl);
-        sfree(plist_nl);
-    }
-
-    /* Free nbst */
-    pfree(nb->nbst.e_lj);
-    nb->nbst.e_lj = nullptr;
-
-    pfree(nb->nbst.e_el);
-    nb->nbst.e_el = nullptr;
-
-    pfree(nb->nbst.fshift);
-    nb->nbst.fshift = nullptr;
-
-    /* Free other events */
-    if (nb->nonlocal_done)
-    {
-        clReleaseEvent(nb->nonlocal_done);
-        nb->nonlocal_done = nullptr;
-    }
-    if (nb->misc_ops_and_local_H2D_done)
-    {
-        clReleaseEvent(nb->misc_ops_and_local_H2D_done);
-        nb->misc_ops_and_local_H2D_done = nullptr;
-    }
-
     freeGpuProgram(nb->dev_rundata->program);
     delete nb->dev_rundata;
-
-    /* Free timers and timings */
-    delete nb->timers;
-    sfree(nb->timings);
-    delete nb;
-
-    if (debug)
-    {
-        fprintf(debug, "Cleaned up OpenCL data structures.\n");
-    }
 }
 
 //! This function is documented in the header file
index 18c583937b6e50caf78c994d0ea3c59461b0b4b3..dfc2c5a6e2401838b1cfeeb80c33aa2a3f2b6985 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -99,18 +99,18 @@ static const char* kernel_VdW_family_definitions[] = {
 
 /*! \brief Returns a string with the compiler defines required to avoid all flavour generation
  *
- * For example if flavour eelTypeRF with evdwTypeFSWITCH, the output will be such that the corresponding
+ * For example if flavour ElecType::RF with VdwType::FSwitch, the output will be such that the corresponding
  * kernel flavour is generated:
  * -DGMX_OCL_FASTGEN          (will replace flavour generator nbnxn_ocl_kernels.clh with nbnxn_ocl_kernels_fastgen.clh)
- * -DEL_RF                    (The eelTypeRF flavour)
+ * -DEL_RF                    (The ElecType::RF flavour)
  * -DEELNAME=_ElecRF          (The first part of the generated kernel name )
- * -DLJ_EWALD_COMB_GEOM       (The evdwTypeFSWITCH flavour)
+ * -DLJ_EWALD_COMB_GEOM       (The VdwType::FSwitch flavour)
  * -DVDWNAME=_VdwLJEwCombGeom (The second part of the generated kernel name )
  *
  * prune/energy are still generated as originally. It is only the flavour-level that has changed, so that
  * only the required flavour for the simulation is compiled.
  *
- * If eeltype is single-range Ewald, then we need to add the
+ * If elecType is single-range Ewald, then we need to add the
  * twin-cutoff flavour kernels to the JIT, because PME tuning might
  * need it. This path sets -DGMX_OCL_FASTGEN_ADD_TWINCUT, which
  * triggers the use of nbnxn_ocl_kernels_fastgen_add_twincut.clh. This
@@ -122,19 +122,22 @@ static const char* kernel_VdW_family_definitions[] = {
  * JIT defaults to compiling all kernel flavours.
  *
  * \param[in]  bFastGen    Whether FastGen should be used
- * \param[in]  eeltype     Electrostatics kernel flavour for FastGen
- * \param[in]  vdwtype     VDW kernel flavour for FastGen
+ * \param[in]  elecType    Electrostatics kernel flavour for FastGen
+ * \param[in]  vdwType     VDW kernel flavour for FastGen
  * \return                 String with the defines if FastGen is active
  *
  * \throws std::bad_alloc if out of memory
  */
-static std::string makeDefinesForKernelTypes(bool bFastGen, int eeltype, int vdwtype)
+static std::string makeDefinesForKernelTypes(bool                 bFastGen,
+                                             enum Nbnxm::ElecType elecType,
+                                             enum Nbnxm::VdwType  vdwType)
 {
+    using Nbnxm::ElecType;
     std::string defines_for_kernel_types;
 
     if (bFastGen)
     {
-        bool bIsEwaldSingleCutoff = (eeltype == eelTypeEWALD_TAB || eeltype == eelTypeEWALD_ANA);
+        bool bIsEwaldSingleCutoff = (elecType == ElecType::EwaldTab || elecType == ElecType::EwaldAna);
 
         if (bIsEwaldSingleCutoff)
         {
@@ -146,8 +149,8 @@ static std::string makeDefinesForKernelTypes(bool bFastGen, int eeltype, int vdw
                nbnxn_ocl_kernels_fastgen.clh. */
             defines_for_kernel_types += "-DGMX_OCL_FASTGEN";
         }
-        defines_for_kernel_types += kernel_electrostatic_family_definitions[eeltype];
-        defines_for_kernel_types += kernel_VdW_family_definitions[vdwtype];
+        defines_for_kernel_types += kernel_electrostatic_family_definitions[static_cast<int>(elecType)];
+        defines_for_kernel_types += kernel_VdW_family_definitions[static_cast<int>(vdwType)];
     }
 
     return defines_for_kernel_types;
@@ -182,7 +185,7 @@ void nbnxn_gpu_compile_kernels(NbnxmGpu* nb)
     try
     {
         std::string extraDefines =
-                makeDefinesForKernelTypes(bFastGen, nb->nbparam->eeltype, nb->nbparam->vdwtype);
+                makeDefinesForKernelTypes(bFastGen, nb->nbparam->elecType, nb->nbparam->vdwType);
 
         /* Here we pass macros and static const/constexpr int variables defined
          * in include files outside the opencl as macros, to avoid
@@ -196,23 +199,32 @@ void nbnxn_gpu_compile_kernels(NbnxmGpu* nb)
                 " -DNBNXM_MIN_DISTANCE_SQUARED_VALUE_FLOAT=%g"
                 " -Dc_nbnxnGpuNumClusterPerSupercluster=%d"
                 " -Dc_nbnxnGpuJgroupSize=%d"
+                " -Dc_centralShiftIndex=%d"
                 "%s",
-                c_nbnxnGpuClusterSize, c_nbnxnMinDistanceSquared, c_nbnxnGpuNumClusterPerSupercluster,
-                c_nbnxnGpuJgroupSize, (nb->bPrefetchLjParam) ? " -DIATYPE_SHMEM" : "");
+                c_nbnxnGpuClusterSize,
+                c_nbnxnMinDistanceSquared,
+                c_nbnxnGpuNumClusterPerSupercluster,
+                c_nbnxnGpuJgroupSize,
+                gmx::c_centralShiftIndex,
+                (nb->bPrefetchLjParam) ? " -DIATYPE_SHMEM" : "");
         try
         {
             /* TODO when we have a proper MPI-aware logging module,
                the log output here should be written there */
-            program = gmx::ocl::compileProgram(
-                    stderr, "gromacs/nbnxm/opencl", "nbnxm_ocl_kernels.cl", extraDefines,
-                    nb->deviceContext_->context(), nb->deviceContext_->deviceInfo().oclDeviceId,
-                    nb->deviceContext_->deviceInfo().deviceVendor);
+            program = gmx::ocl::compileProgram(stderr,
+                                               "gromacs/nbnxm/opencl",
+                                               "nbnxm_ocl_kernels.cl",
+                                               extraDefines,
+                                               nb->deviceContext_->context(),
+                                               nb->deviceContext_->deviceInfo().oclDeviceId,
+                                               nb->deviceContext_->deviceInfo().deviceVendor);
         }
         catch (gmx::GromacsException& e)
         {
-            e.prependContext(gmx::formatString(
-                    "Failed to compile/load nbnxm kernels for GPU #%d %s\n",
-                    nb->deviceContext_->deviceInfo().id, nb->deviceContext_->deviceInfo().device_name));
+            e.prependContext(
+                    gmx::formatString("Failed to compile/load nbnxm kernels for GPU #%d %s\n",
+                                      nb->deviceContext_->deviceInfo().id,
+                                      nb->deviceContext_->deviceInfo().device_name));
             throw;
         }
     }
index 7f9925059c767e79e077a0d3e6df20c16c4163a2..68c1a9df7accde262fbb5633db92bbc7bfbcefd9 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,11 +126,11 @@ __kernel void NB_KERNEL_FUNC_NAME(nbnxn_kernel, _F_opencl)
 #else
                 const __global int* restrict atom_types, /* IN  */
 #endif
-                const __global float* restrict shift_vec,             /* IN stores float3 values */
-                __constant const float* gmx_unused nbfp_climg2d,      /* IN  */
-                __constant const float* gmx_unused nbfp_comb_climg2d, /* IN  */
-                __constant const float* gmx_unused coulomb_tab_climg2d, /* IN  */
-                const __global nbnxn_sci_t* pl_sci,                     /* IN  */
+                const __global float* restrict shift_vec,          /* IN stores float3 values */
+                __constant const float2* restrict gmx_unused nbfp, /* IN  */
+                __constant const float2* restrict gmx_unused nbfp_comb,  /* IN  */
+                __constant const float* restrict gmx_unused coulomb_tab, /* IN  */
+                const __global nbnxn_sci_t* pl_sci,                      /* IN  */
 #ifndef PRUNE_NBL
                 const
 #endif
@@ -232,8 +232,10 @@ __kernel void NB_KERNEL_FUNC_NAME(nbnxn_kernel, _F_opencl)
         const int ai = ci * CL_SIZE + tidxi;
 
         float4 xqbuf = xq[ai]
-                       + (float4)(shift_vec[3 * nb_sci.shift], shift_vec[3 * nb_sci.shift + 1],
-                                  shift_vec[3 * nb_sci.shift + 2], 0.0F);
+                       + (float4)(shift_vec[3 * nb_sci.shift],
+                                  shift_vec[3 * nb_sci.shift + 1],
+                                  shift_vec[3 * nb_sci.shift + 2],
+                                  0.0F);
         xqbuf.w *= nbparam->epsfac;
         xqib[(tidxj + i) * CL_SIZE + tidxi] = xqbuf;
 #ifdef IATYPE_SHMEM
@@ -274,7 +276,8 @@ __kernel void NB_KERNEL_FUNC_NAME(nbnxn_kernel, _F_opencl)
     float E_el = 0.0F;
 
 #    if defined EXCLUSION_FORCES /* Ewald or RF */
-    if (nb_sci.shift == CENTRAL && pl_cj4[cij4_start].cj[0] == sci * c_nbnxnGpuNumClusterPerSupercluster)
+    if (nb_sci.shift == c_centralShiftIndex
+        && pl_cj4[cij4_start].cj[0] == sci * c_nbnxnGpuNumClusterPerSupercluster)
     {
         /* we have the diagonal: add the charge and LJ self interaction energy term */
         for (int i = 0; i < c_nbnxnGpuNumClusterPerSupercluster; i++)
@@ -284,8 +287,8 @@ __kernel void NB_KERNEL_FUNC_NAME(nbnxn_kernel, _F_opencl)
             E_el += qi * qi;
 #        endif
 #        if defined LJ_EWALD
-            E_lj += nbfp_climg2d[atom_types[(sci * c_nbnxnGpuNumClusterPerSupercluster + i) * CL_SIZE + tidxi]
-                                 * (ntypes + 1) * 2];
+            E_lj += nbfp[atom_types[(sci * c_nbnxnGpuNumClusterPerSupercluster + i) * CL_SIZE + tidxi] * (ntypes + 1)]
+                            .x;
 #        endif /* LJ_EWALD */
         }
 
@@ -310,7 +313,7 @@ __kernel void NB_KERNEL_FUNC_NAME(nbnxn_kernel, _F_opencl)
 #endif /* CALC_ENERGIES */
 
 #ifdef EXCLUSION_FORCES
-    const int nonSelfInteraction = !(nb_sci.shift == CENTRAL & tidxj <= tidxi);
+    const int nonSelfInteraction = !(nb_sci.shift == c_centralShiftIndex & tidxj <= tidxi);
 #endif
 
     /* loop over the j clusters = seen by any of the atoms in the current super-cluster */
@@ -409,8 +412,10 @@ __kernel void NB_KERNEL_FUNC_NAME(nbnxn_kernel, _F_opencl)
 #endif                          /* IATYPE_SHMEM */
                                 /* LJ 6*C6 and 12*C12 */
 #ifndef LJ_COMB
-                                const float c6  = nbfp_climg2d[2 * (ntypes * typei + typej)];
-                                const float c12 = nbfp_climg2d[2 * (ntypes * typei + typej) + 1];
+                                const float2 c6c12 = nbfp[ntypes * typei + typej];
+
+                                const float c6  = c6c12.x;
+                                const float c12 = c6c12.y;
 #else /* LJ_COMB */
 #    ifdef LJ_COMB_GEOM
                                 const float c6     = ljcp_i.x * ljcp_j.x;
@@ -472,20 +477,40 @@ __kernel void NB_KERNEL_FUNC_NAME(nbnxn_kernel, _F_opencl)
 #ifdef LJ_EWALD
 #    ifdef LJ_EWALD_COMB_GEOM
 #        ifdef CALC_ENERGIES
-                                calculate_lj_ewald_comb_geom_F_E(
-                                        nbfp_comb_climg2d, nbparam, typei, typej, r2, inv_r2,
-                                        lje_coeff2, lje_coeff6_6, int_bit, &F_invr, &E_lj_p);
+                                calculate_lj_ewald_comb_geom_F_E(nbfp_comb,
+                                                                 nbparam,
+                                                                 typei,
+                                                                 typej,
+                                                                 r2,
+                                                                 inv_r2,
+                                                                 lje_coeff2,
+                                                                 lje_coeff6_6,
+                                                                 int_bit,
+                                                                 &F_invr,
+                                                                 &E_lj_p);
 #        else
-                                calculate_lj_ewald_comb_geom_F(nbfp_comb_climg2d, typei, typej, r2, inv_r2,
-                                                               lje_coeff2, lje_coeff6_6, &F_invr);
+                                calculate_lj_ewald_comb_geom_F(
+                                        nbfp_comb, typei, typej, r2, inv_r2, lje_coeff2, lje_coeff6_6, &F_invr);
 #        endif /* CALC_ENERGIES */
 #    elif defined LJ_EWALD_COMB_LB
-                                calculate_lj_ewald_comb_LB_F_E(nbfp_comb_climg2d, nbparam, typei, typej,
-                                                               r2, inv_r2, lje_coeff2, lje_coeff6_6,
+                                calculate_lj_ewald_comb_LB_F_E(nbfp_comb,
+                                                               nbparam,
+                                                               typei,
+                                                               typej,
+                                                               r2,
+                                                               inv_r2,
+                                                               lje_coeff2,
+                                                               lje_coeff6_6,
 #        ifdef CALC_ENERGIES
-                                                               int_bit, true, &F_invr, &E_lj_p
+                                                               int_bit,
+                                                               true,
+                                                               &F_invr,
+                                                               &E_lj_p
 #        else
-                                                               0, false, &F_invr, 0
+                                                               0,
+                                                               false,
+                                                               &F_invr,
+                                                               0
 #        endif /* CALC_ENERGIES */
                                 );
 #    endif     /* LJ_EWALD_COMB_GEOM */
@@ -532,8 +557,8 @@ __kernel void NB_KERNEL_FUNC_NAME(nbnxn_kernel, _F_opencl)
 #elif defined EL_EWALD_TAB
                                 F_invr += qi * qj_f
                                           * (int_bit * inv_r2
-                                             - interpolate_coulomb_force_r(coulomb_tab_climg2d, r2 * inv_r,
-                                                                           coulomb_tab_scale))
+                                             - interpolate_coulomb_force_r(
+                                                       coulomb_tab, r2 * inv_r, coulomb_tab_scale))
                                           * inv_r;
 #endif /* EL_EWALD_ANA/TAB */
 
@@ -580,7 +605,7 @@ __kernel void NB_KERNEL_FUNC_NAME(nbnxn_kernel, _F_opencl)
     }
 
     /* skip central shifts when summing shift forces */
-    if (nb_sci.shift == CENTRAL)
+    if (nb_sci.shift == c_centralShiftIndex)
     {
         bCalcFshift = 0;
     }
index dfafdcbf28d2ca2adf115661b94a47870a3f1078..49d19645a9928b11e134a9858827926b3edd1e99 100644 (file)
@@ -155,8 +155,10 @@ nbnxn_kernel_prune_rolling_opencl
             /* We don't need q, but using float4 in shmem avoids bank conflicts */
             const float4 tmp = xq[ai];
             const float4 xi  = tmp
-                              + (float4)(shift_vec[3 * nb_sci.shift], shift_vec[3 * nb_sci.shift + 1],
-                                         shift_vec[3 * nb_sci.shift + 2], 0.0F);
+                              + (float4)(shift_vec[3 * nb_sci.shift],
+                                         shift_vec[3 * nb_sci.shift + 1],
+                                         shift_vec[3 * nb_sci.shift + 2],
+                                         0.0F);
             xib[(tidxj + i) * c_clSize + tidxi] = xi;
         }
     }
index 46c08c2d715020cb014767e2d35c37e37686cf89..4e2e208d40d9aa8e40ff6f8b57f726d7398e48ef 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "gromacs/gpu_utils/device_utils.clh"
 #include "gromacs/gpu_utils/vectype_ops.clh"
-#include "gromacs/pbcutil/ishift.h"
 
 #include "nbnxm_ocl_consts.h"
 
 
 
 #    ifdef __GNUC__
-/* GCC, clang, and some ICC pretending to be GCC */
+/* GCC, clang */
 #        define gmx_unused __attribute__((unused))
 #    else
 #        define gmx_unused
@@ -156,10 +155,10 @@ typedef struct
 typedef struct cl_nbparam_params
 {
 
-    //! type of electrostatics, takes values from #eelCu
-    int eeltype;
-    //! type of VdW impl., takes values from #evdwCu
-    int vdwtype;
+    //! type of electrostatics, takes values from #ElecType
+    int elecType;
+    //! type of VdW impl., takes values from #VdwType
+    int vdwType;
 
     //! charge multiplication factor
     float epsfac;
@@ -237,10 +236,10 @@ typedef struct
 } nbnxn_excl_t;
 
 /*! i-cluster interaction mask for a super-cluster with all c_nbnxnGpuNumClusterPerSupercluster bits set */
-__constant unsigned supercl_interaction_mask = ((1U << c_nbnxnGpuNumClusterPerSupercluster) - 1U);
+__constant const unsigned supercl_interaction_mask = ((1U << c_nbnxnGpuNumClusterPerSupercluster) - 1U);
 
 /*! Minimum single precision threshold for r^2 to avoid r^-12 overflow. */
-__constant float c_nbnxnMinDistanceSquared = NBNXM_MIN_DISTANCE_SQUARED_VALUE_FLOAT;
+__constant const float c_nbnxnMinDistanceSquared = NBNXM_MIN_DISTANCE_SQUARED_VALUE_FLOAT;
 
 gmx_opencl_inline void preloadCj4Generic(__local int*        sm_cjPreload,
                                          const __global int* gm_cj,
@@ -456,19 +455,28 @@ gmx_opencl_inline void calculate_potential_switch_F_E(const cl_nbparam_params_t*
     *E_lj *= sw;
 }
 
+/*! \brief Fetch C6 grid contribution coefficients and return the product of these.
+ */
+gmx_opencl_inline float calculate_lj_ewald_c6grid(__constant const float2* nbfp_comb, int typei, int typej)
+{
+    const float c6_i = nbfp_comb[typei].x;
+    const float c6_j = nbfp_comb[typej].x;
+    return c6_i * c6_j;
+}
+
 /*! Calculate LJ-PME grid force contribution with
  *  geometric combination rule.
  */
-gmx_opencl_inline void calculate_lj_ewald_comb_geom_F(__constant const float* nbfp_comb_climg2d,
-                                                      int                     typei,
-                                                      int                     typej,
-                                                      float                   r2,
-                                                      float                   inv_r2,
-                                                      float                   lje_coeff2,
-                                                      float                   lje_coeff6_6,
-                                                      float*                  F_invr)
+gmx_opencl_inline void calculate_lj_ewald_comb_geom_F(__constant const float2* nbfp_comb,
+                                                      int                      typei,
+                                                      int                      typej,
+                                                      float                    r2,
+                                                      float                    inv_r2,
+                                                      float                    lje_coeff2,
+                                                      float                    lje_coeff6_6,
+                                                      float*                   F_invr)
 {
-    const float c6grid = nbfp_comb_climg2d[2 * typei] * nbfp_comb_climg2d[2 * typej];
+    const float c6grid = calculate_lj_ewald_c6grid(nbfp_comb, typei, typej);
 
     /* Recalculate inv_r6 without exclusion mask */
     const float inv_r6_nm = inv_r2 * inv_r2 * inv_r2;
@@ -483,7 +491,7 @@ gmx_opencl_inline void calculate_lj_ewald_comb_geom_F(__constant const float* nb
 /*! Calculate LJ-PME grid force + energy contribution with
  *  geometric combination rule.
  */
-gmx_opencl_inline void calculate_lj_ewald_comb_geom_F_E(__constant const float* nbfp_comb_climg2d,
+gmx_opencl_inline void calculate_lj_ewald_comb_geom_F_E(__constant const float2*   nbfp_comb,
                                                         const cl_nbparam_params_t* nbparam,
                                                         int                        typei,
                                                         int                        typej,
@@ -495,7 +503,7 @@ gmx_opencl_inline void calculate_lj_ewald_comb_geom_F_E(__constant const float*
                                                         float*                     F_invr,
                                                         float*                     E_lj)
 {
-    const float c6grid = nbfp_comb_climg2d[2 * typei] * nbfp_comb_climg2d[2 * typej];
+    const float c6grid = calculate_lj_ewald_c6grid(nbfp_comb, typei, typej);
 
     /* Recalculate inv_r6 without exclusion mask */
     const float inv_r6_nm = inv_r2 * inv_r2 * inv_r2;
@@ -516,7 +524,7 @@ gmx_opencl_inline void calculate_lj_ewald_comb_geom_F_E(__constant const float*
  *  We use a single F+E kernel with conditional because the performance impact
  *  of this is pretty small and LB on the CPU is anyway very slow.
  */
-gmx_opencl_inline void calculate_lj_ewald_comb_LB_F_E(__constant const float*    nbfp_comb_climg2d,
+gmx_opencl_inline void calculate_lj_ewald_comb_LB_F_E(__constant const float2*   nbfp_comb,
                                                       const cl_nbparam_params_t* nbparam,
                                                       int                        typei,
                                                       int                        typej,
@@ -530,9 +538,10 @@ gmx_opencl_inline void calculate_lj_ewald_comb_LB_F_E(__constant const float*
                                                       float*                     E_lj)
 {
     /* sigma and epsilon are scaled to give 6*C6 */
-    const float sigma = nbfp_comb_climg2d[2 * typei] + nbfp_comb_climg2d[2 * typej];
-
-    const float epsilon = nbfp_comb_climg2d[2 * typei + 1] * nbfp_comb_climg2d[2 * typej + 1];
+    const float2 c6c12_i = nbfp_comb[typei];
+    const float2 c6c12_j = nbfp_comb[typej];
+    const float  sigma   = c6c12_i.x + c6c12_j.x;
+    const float  epsilon = c6c12_i.y * c6c12_j.y;
 
     const float sigma2 = sigma * sigma;
     const float c6grid = epsilon * sigma2 * sigma2 * sigma2;
@@ -558,16 +567,14 @@ gmx_opencl_inline void calculate_lj_ewald_comb_LB_F_E(__constant const float*
 /*! Interpolate Ewald coulomb force using the table through the tex_nbfp texture.
  *  Original idea: from the OpenMM project
  */
-gmx_opencl_inline float interpolate_coulomb_force_r(__constant const float* coulomb_tab_climg2d,
-                                                    float                   r,
-                                                    float                   scale)
+gmx_opencl_inline float interpolate_coulomb_force_r(__constant const float* coulomb_tab, float r, float scale)
 {
     float normalized = scale * r;
     int   index      = (int)normalized;
     float fract2     = normalized - (float)index;
     float fract1     = 1.0F - fract2;
 
-    return fract1 * coulomb_tab_climg2d[index] + fract2 * coulomb_tab_climg2d[index + 1];
+    return fract1 * coulomb_tab[index] + fract2 * coulomb_tab[index + 1];
 }
 
 /*! Calculate analytical Ewald correction term. */
index 8aa7f451204069fc62bbca8953c548566f067fe1..1f6cabf615b20677b3cea9c681449ce25ca1e568 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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.
  */
-/* Auxiliary kernels */
-
-/* Very few data */
-__kernel void zero_e_fshift(__global float* fshift, __global float* e_lj, __global float* e_el, const unsigned int Nbuf)
-{
-    unsigned int tidx = get_global_id(0);
-    if (tidx < Nbuf)
-    {
-        fshift[tidx] = 0.0F;
-    }
-    if (tidx == 0)
-    {
-        *e_lj = 0.0F;
-        *e_el = 0.0F;
-    }
-}
-
 /* Generate pruning kernels. */
 #define HAVE_FRESH_LIST 1
 #include "nbnxm_ocl_kernel_pruneonly.clh"
index a517c2fd04eb3a0539e582fcd4d4cd28cacffa05..3037663842250d1b2022f6fdddb2f1d0c7090db0 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
 
 #include "gromacs/gpu_utils/devicebuffer.h"
 #include "gromacs/gpu_utils/gmxopencl.h"
+#include "gromacs/gpu_utils/gpueventsynchronizer_ocl.h"
 #include "gromacs/gpu_utils/gputraits_ocl.h"
 #include "gromacs/gpu_utils/oclutils.h"
 #include "gromacs/mdtypes/interaction_const.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/real.h"
 
-#include "nbnxm_ocl_consts.h"
-
 struct gmx_wallclock_gpu_nbnxn_t;
 
-/* kernel does #include "gromacs/math/utilities.h" */
-/* Move the actual useful stuff here: */
-
-//! Define 1/sqrt(pi)
-#define M_FLOAT_1_SQRTPI 0.564189583547756f
-
-/*! \brief Constants for platform-dependent defaults for the prune kernel's j4 processing concurrency.
- *
- *  Initialized using macros that can be overridden at compile-time (using #GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY).
- */
-/*! @{ */
-const int c_oclPruneKernelJ4ConcurrencyDEFAULT = GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY_DEFAULT;
-/*! @} */
-
 /*! \brief Pruning kernel flavors.
  *
  * The values correspond to the first call of the pruning post-list generation
@@ -89,62 +74,6 @@ enum ePruneKind
     ePruneNR
 };
 
-/*! \internal
- * \brief Staging area for temporary data downloaded from the GPU.
- *
- *  The energies/shift forces get downloaded here first, before getting added
- *  to the CPU-side aggregate values.
- */
-struct nb_staging_t
-{
-    //! LJ energy
-    float* e_lj = nullptr;
-    //! electrostatic energy
-    float* e_el = nullptr;
-    //! float3 buffer with shift forces
-    float (*fshift)[3] = nullptr;
-};
-
-/*! \internal
- * \brief Nonbonded atom data - both inputs and outputs.
- */
-typedef struct cl_atomdata
-{
-    //! number of atoms
-    int natoms;
-    //! number of local atoms
-    int natoms_local;
-    //! allocation size for the atom data (xq, f)
-    int nalloc;
-
-    //! float4 buffer with atom coordinates + charges, size natoms
-    DeviceBuffer<float> xq;
-
-    //! float3 buffer with force output array, size natoms
-    DeviceBuffer<float> f;
-
-    //! LJ energy output, size 1
-    DeviceBuffer<float> e_lj;
-    //! Electrostatics energy input, size 1
-    DeviceBuffer<float> e_el;
-
-    //! float3 buffer with shift forces
-    DeviceBuffer<float> fshift;
-
-    //! number of atom types
-    int ntypes;
-    //! int buffer with atom type indices, size natoms
-    DeviceBuffer<int> atom_types;
-    //! float2 buffer with sqrt(c6),sqrt(c12), size natoms
-    DeviceBuffer<float> lj_comb;
-
-    //! float3 buffer with shifts values
-    DeviceBuffer<float> shift_vec;
-
-    //! true if the shift vector has been uploaded
-    bool bShiftVecUploaded;
-} cl_atomdata_t;
-
 /*! \internal
  * \brief Data structure shared between the OpenCL device code and OpenCL host code
  *
@@ -153,10 +82,10 @@ typedef struct cl_atomdata
 typedef struct cl_nbparam_params
 {
 
-    //! type of electrostatics, takes values from #eelType
-    int eeltype;
-    //! type of VdW impl., takes values from #evdwType
-    int vdwtype;
+    //! type of electrostatics
+    enum Nbnxm::ElecType elecType;
+    //! type of VdW impl.
+    enum Nbnxm::VdwType vdwType;
 
     //! charge multiplication factor
     float epsfac;
@@ -166,7 +95,7 @@ typedef struct cl_nbparam_params
     float two_k_rf;
     //! Ewald/PME parameter
     float ewald_beta;
-    //! Ewald/PME correction term substracted from the direct-space potential
+    //! Ewald/PME correction term subtracted from the direct-space potential
     float sh_ewald;
     //! LJ-Ewald/PME correction term added to the correction potential
     float sh_lj_ewald;
@@ -198,11 +127,6 @@ typedef struct cl_nbparam_params
 } cl_nbparam_params_t;
 
 
-/** \internal
- * \brief Typedef of actual timer type.
- */
-typedef struct Nbnxm::gpu_timers_t cl_timers_t;
-
 /*! \internal
  * \brief Main data structure for OpenCL nonbonded force calculations.
  */
@@ -219,10 +143,10 @@ struct NbnxmGpu
     /**< Pointers to non-bonded kernel functions
      * organized similar with nb_kfunc_xxx arrays in nbnxn_ocl.cpp */
     ///@{
-    cl_kernel kernel_noener_noprune_ptr[eelTypeNR][evdwTypeNR] = { { nullptr } };
-    cl_kernel kernel_ener_noprune_ptr[eelTypeNR][evdwTypeNR]   = { { nullptr } };
-    cl_kernel kernel_noener_prune_ptr[eelTypeNR][evdwTypeNR]   = { { nullptr } };
-    cl_kernel kernel_ener_prune_ptr[eelTypeNR][evdwTypeNR]     = { { nullptr } };
+    cl_kernel kernel_noener_noprune_ptr[Nbnxm::c_numElecTypes][Nbnxm::c_numVdwTypes] = { { nullptr } };
+    cl_kernel kernel_ener_noprune_ptr[Nbnxm::c_numElecTypes][Nbnxm::c_numVdwTypes] = { { nullptr } };
+    cl_kernel kernel_noener_prune_ptr[Nbnxm::c_numElecTypes][Nbnxm::c_numVdwTypes] = { { nullptr } };
+    cl_kernel kernel_ener_prune_ptr[Nbnxm::c_numElecTypes][Nbnxm::c_numVdwTypes] = { { nullptr } };
     ///@}
     //! prune kernels, ePruneKind defined the kernel kinds
     cl_kernel kernel_pruneonly[ePruneNR] = { nullptr };
@@ -232,25 +156,44 @@ struct NbnxmGpu
 
     /**< auxiliary kernels implementing memset-like functions */
     ///@{
-    cl_kernel kernel_memset_f      = nullptr;
-    cl_kernel kernel_memset_f2     = nullptr;
-    cl_kernel kernel_memset_f3     = nullptr;
-    cl_kernel kernel_zero_e_fshift = nullptr;
+    cl_kernel kernel_memset_f  = nullptr;
+    cl_kernel kernel_memset_f2 = nullptr;
+    cl_kernel kernel_memset_f3 = nullptr;
     ///@}
 
     //! true if doing both local/non-local NB work on GPU
     bool bUseTwoStreams = false;
-    //! true indicates that the nonlocal_done event was enqueued
-    bool bNonLocalStreamActive = false;
+    //! true indicates that the nonlocal_done event was marked
+    bool bNonLocalStreamDoneMarked = false;
 
     //! atom data
-    cl_atomdata_t* atdat = nullptr;
+    NBAtomDataGpu* atdat = nullptr;
     //! parameters required for the non-bonded calc.
     NBParamGpu* nbparam = nullptr;
     //! pair-list data structures (local and non-local)
     gmx::EnumerationArray<Nbnxm::InteractionLocality, Nbnxm::gpu_plist*> plist = { nullptr };
     //! staging area where fshift/energies get downloaded
-    nb_staging_t nbst;
+    NBStagingData nbst;
+
+    // Data for GPU-side coordinate conversion between integrator and NBNXM
+    /*! \brief array of atom indices */
+    DeviceBuffer<int> atomIndices;
+    /*! \brief size of atom indices */
+    int atomIndicesSize = 0;
+    /*! \brief size of atom indices allocated in device buffer */
+    int atomIndicesSize_alloc = 0;
+    /*! \brief x buf ops num of atoms */
+    DeviceBuffer<int> cxy_na;
+    /*! \brief number of elements in cxy_na */
+    int ncxy_na = 0;
+    /*! \brief number of elements allocated allocated in device buffer */
+    int ncxy_na_alloc = 0;
+    /*! \brief x buf ops cell index mapping */
+    DeviceBuffer<int> cxy_ind;
+    /*! \brief number of elements in cxy_ind */
+    int ncxy_ind = 0;
+    /*! \brief number of elements allocated allocated in device buffer */
+    int ncxy_ind_alloc = 0;
 
     //! local and non-local GPU queues
     gmx::EnumerationArray<Nbnxm::InteractionLocality, const DeviceStream*> deviceStreams;
@@ -259,13 +202,13 @@ struct NbnxmGpu
     /*! \{ */
     /*! \brief Event triggered when the non-local non-bonded
      * kernel is done (and the local transfer can proceed) */
-    cl_event nonlocal_done = nullptr;
+    GpuEventSynchronizer nonlocal_done;
     /*! \brief Event triggered when the tasks issued in the local
      * stream that need to precede the non-local force or buffer
      * operation calculations are done (e.g. f buffer 0-ing, local
      * x/q H2D, buffer op initialization in local stream that is
      * required also by nonlocal stream ) */
-    cl_event misc_ops_and_local_H2D_done = nullptr;
+    GpuEventSynchronizer misc_ops_and_local_H2D_done;
     /*! \} */
 
     //! True if there has been local/nonlocal GPU work, either bonded or nonbonded, scheduled
@@ -277,7 +220,7 @@ struct NbnxmGpu
     //! True if event-based timing is enabled.
     bool bDoTime = false;
     //! OpenCL event-based timers.
-    cl_timers_t* timers = nullptr;
+    Nbnxm::GpuTimers* timers = nullptr;
     //! Timing data. TODO: deprecate this and query timers for accumulated data instead
     gmx_wallclock_gpu_nbnxn_t* timings = nullptr;
 };
index 3f9a9f21c563926dfcfcd5df2ad18b0a43584da5..3d061b149f9dfc7c3ed29e08bac6990eee6c6108 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/domdec/domdec_struct.h"
 #include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
@@ -84,7 +85,7 @@ using BoundingBox1D = Nbnxm::BoundingBox1D; // TODO: Remove when refactoring thi
 
 using Grid = Nbnxm::Grid; // TODO: Remove when refactoring this file
 
-// Convience alias for partial Nbnxn namespace usage
+// Convenience alias for partial Nbnxn namespace usage
 using InteractionLocality = gmx::InteractionLocality;
 
 /* We shift the i-particles backward for PBC.
@@ -217,29 +218,6 @@ static inline int xIndexFromCj(int cj)
 }
 #endif // defined(GMX_NBNXN_SIMD_4XN) || defined(GMX_NBNXN_SIMD_2XNN)
 
-
-void nbnxn_init_pairlist_fep(t_nblist* nl)
-{
-    nl->type      = GMX_NBLIST_INTERACTION_FREE_ENERGY;
-    nl->igeometry = GMX_NBLIST_GEOMETRY_PARTICLE_PARTICLE;
-    /* The interaction functions are set in the free energy kernel fuction */
-    nl->ivdw     = -1;
-    nl->ivdwmod  = -1;
-    nl->ielec    = -1;
-    nl->ielecmod = -1;
-
-    nl->maxnri   = 0;
-    nl->maxnrj   = 0;
-    nl->nri      = 0;
-    nl->nrj      = 0;
-    nl->iinr     = nullptr;
-    nl->gid      = nullptr;
-    nl->shift    = nullptr;
-    nl->jindex   = nullptr;
-    nl->jjnr     = nullptr;
-    nl->excl_fep = nullptr;
-}
-
 static constexpr int sizeNeededForBufferFlags(const int numAtoms)
 {
     return (numAtoms + NBNXN_BUFFERFLAG_SIZE - 1) / NBNXN_BUFFERFLAG_SIZE;
@@ -515,7 +493,7 @@ clusterpair_in_range(const NbnxnPairlistGpuWork& work, int si, int csj, int stri
     static_assert(c_nbnxnGpuClusterSize == 8 || c_nbnxnGpuClusterSize == 4,
                   "A cluster is hard-coded to 4/8 atoms.");
 
-    Simd4Real rc2_S = Simd4Real(rlist2);
+    Simd4Real rc2_S{ rlist2 };
 
     const real* x_i = work.iSuperClusterData.xSimd.data();
 
@@ -677,17 +655,13 @@ NbnxnPairlistGpu::NbnxnPairlistGpu(gmx::PinningPolicy pinningPolicy) :
 }
 
 // TODO: Move to pairlistset.cpp
-PairlistSet::PairlistSet(const InteractionLocality locality, const PairlistParams& pairlistParams) :
-    locality_(locality),
-    params_(pairlistParams)
+PairlistSet::PairlistSet(const PairlistParams& pairlistParams) :
+    params_(pairlistParams),
+    combineLists_(sc_isGpuPairListType[pairlistParams.pairlistType]), // Currently GPU lists are always combined
+    isCpuType_(!sc_isGpuPairListType[pairlistParams.pairlistType])
 {
-    isCpuType_ = (params_.pairlistType == PairlistType::Simple4x2
-                  || params_.pairlistType == PairlistType::Simple4x4
-                  || params_.pairlistType == PairlistType::Simple4x8);
-    // Currently GPU lists are always combined
-    combineLists_ = !isCpuType_;
 
-    const int numLists = gmx_omp_nthreads_get(emntNonbonded);
+    const int numLists = gmx_omp_nthreads_get(ModuleMultiThread::Nonbonded);
 
     if (!combineLists_ && numLists > NBNXN_BUFFERFLAG_MAX_THREADS)
     {
@@ -695,7 +669,9 @@ PairlistSet::PairlistSet(const InteractionLocality locality, const PairlistParam
                   "%d OpenMP threads were requested. Since the non-bonded force buffer reduction "
                   "is prohibitively slow with more than %d threads, we do not allow this. Use %d "
                   "or less OpenMP threads.",
-                  numLists, NBNXN_BUFFERFLAG_MAX_THREADS, NBNXN_BUFFERFLAG_MAX_THREADS);
+                  numLists,
+                  NBNXN_BUFFERFLAG_MAX_THREADS,
+                  NBNXN_BUFFERFLAG_MAX_THREADS);
     }
 
     if (isCpuType_)
@@ -734,7 +710,6 @@ PairlistSet::PairlistSet(const InteractionLocality locality, const PairlistParam
                  * impacts performance.
                  */
                 fepLists_[i] = std::make_unique<t_nblist>();
-                nbnxn_init_pairlist_fep(fepLists_[i].get());
             }
             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
         }
@@ -753,17 +728,23 @@ static void print_nblist_statistics(FILE*                   fp,
     fprintf(fp, "nbl nci %zu ncj %d\n", nbl.ci.size(), nbl.ncjInUse);
     const int numAtomsJCluster = grid.geometry().numAtomsJCluster;
     const double numAtomsPerCell = nbl.ncjInUse / static_cast<double>(grid.numCells()) * numAtomsJCluster;
-    fprintf(fp, "nbl na_cj %d rl %g ncp %d per cell %.1f atoms %.1f ratio %.2f\n", nbl.na_cj, rl,
-            nbl.ncjInUse, nbl.ncjInUse / static_cast<double>(grid.numCells()), numAtomsPerCell,
+    fprintf(fp,
+            "nbl na_cj %d rl %g ncp %d per cell %.1f atoms %.1f ratio %.2f\n",
+            nbl.na_cj,
+            rl,
+            nbl.ncjInUse,
+            nbl.ncjInUse / static_cast<double>(grid.numCells()),
+            numAtomsPerCell,
             numAtomsPerCell
                     / (0.5 * 4.0 / 3.0 * M_PI * rl * rl * rl * grid.numCells() * numAtomsJCluster
                        / (dims.gridSize[XX] * dims.gridSize[YY] * dims.gridSize[ZZ])));
 
-    fprintf(fp, "nbl average j cell list length %.1f\n",
+    fprintf(fp,
+            "nbl average j cell list length %.1f\n",
             0.25 * nbl.ncjInUse / std::max(static_cast<double>(nbl.ci.size()), 1.0));
 
-    int cs[SHIFTS] = { 0 };
-    int npexcl     = 0;
+    int cs[gmx::c_numShiftVectors] = { 0 };
+    int npexcl                     = 0;
     for (const nbnxn_ci_t& ciEntry : nbl.ci)
     {
         cs[ciEntry.shift & NBNXN_CI_SHIFT] += ciEntry.cj_ind_end - ciEntry.cj_ind_start;
@@ -775,9 +756,12 @@ static void print_nblist_statistics(FILE*                   fp,
             j++;
         }
     }
-    fprintf(fp, "nbl cell pairs, total: %zu excl: %d %.1f%%\n", nbl.cj.size(), npexcl,
+    fprintf(fp,
+            "nbl cell pairs, total: %zu excl: %d %.1f%%\n",
+            nbl.cj.size(),
+            npexcl,
             100 * npexcl / std::max(static_cast<double>(nbl.cj.size()), 1.0));
-    for (int s = 0; s < SHIFTS; s++)
+    for (int s = 0; s < gmx::c_numShiftVectors; s++)
     {
         if (cs[s] > 0)
         {
@@ -795,12 +779,21 @@ static void print_nblist_statistics(FILE*                   fp,
     const Grid&             grid = gridSet.grids()[0];
     const Grid::Dimensions& dims = grid.dimensions();
 
-    fprintf(fp, "nbl nsci %zu ncj4 %zu nsi %d excl4 %zu\n", nbl.sci.size(), nbl.cj4.size(),
-            nbl.nci_tot, nbl.excl.size());
+    fprintf(fp,
+            "nbl nsci %zu ncj4 %zu nsi %d excl4 %zu\n",
+            nbl.sci.size(),
+            nbl.cj4.size(),
+            nbl.nci_tot,
+            nbl.excl.size());
     const int numAtomsCluster = grid.geometry().numAtomsICluster;
     const double numAtomsPerCell = nbl.nci_tot / static_cast<double>(grid.numClusters()) * numAtomsCluster;
-    fprintf(fp, "nbl na_c %d rl %g ncp %d per cell %.1f atoms %.1f ratio %.2f\n", nbl.na_ci, rl,
-            nbl.nci_tot, nbl.nci_tot / static_cast<double>(grid.numClusters()), numAtomsPerCell,
+    fprintf(fp,
+            "nbl na_c %d rl %g ncp %d per cell %.1f atoms %.1f ratio %.2f\n",
+            nbl.na_ci,
+            rl,
+            nbl.nci_tot,
+            nbl.nci_tot / static_cast<double>(grid.numClusters()),
+            numAtomsPerCell,
             numAtomsPerCell
                     / (0.5 * 4.0 / 3.0 * M_PI * rl * rl * rl * grid.numClusters() * numAtomsCluster
                        / (dims.gridSize[XX] * dims.gridSize[YY] * dims.gridSize[ZZ])));
@@ -837,14 +830,20 @@ static void print_nblist_statistics(FILE*                   fp,
         sum_nsp /= nbl.sci.size();
         sum_nsp2 /= nbl.sci.size();
     }
-    fprintf(fp, "nbl #cluster-pairs: av %.1f stddev %.1f max %d\n", sum_nsp,
-            std::sqrt(sum_nsp2 - sum_nsp * sum_nsp), nsp_max);
+    fprintf(fp,
+            "nbl #cluster-pairs: av %.1f stddev %.1f max %d\n",
+            sum_nsp,
+            std::sqrt(sum_nsp2 - sum_nsp * sum_nsp),
+            nsp_max);
 
     if (!nbl.cj4.empty())
     {
         for (int b = 0; b <= c_gpuNumClusterPerCell; b++)
         {
-            fprintf(fp, "nbl j-list #i-subcell %d %7d %4.1f\n", b, c[b],
+            fprintf(fp,
+                    "nbl j-list #i-subcell %d %7d %4.1f\n",
+                    b,
+                    c[b],
                     100.0 * c[b] / size_t{ nbl.cj4.size() * c_nbnxnGpuJgroupSize });
         }
     }
@@ -974,9 +973,7 @@ static void makeClusterListSimple(const Grid&       jGrid,
     const BoundingBox* gmx_restrict bb_ci = nbl->work->iClusterData.bb.data();
     const real* gmx_restrict x_ci         = nbl->work->iClusterData.x.data();
 
-    gmx_bool InRange;
-
-    InRange = FALSE;
+    bool InRange = false;
     while (!InRange && jclusterFirst <= jclusterLast)
     {
         real d2 = clusterBoundingBoxDistance2(bb_ci[0], jGrid.jBoundingBoxes()[jclusterFirst]);
@@ -989,7 +986,7 @@ static void makeClusterListSimple(const Grid&       jGrid,
          */
         if (d2 < rbb2)
         {
-            InRange = TRUE;
+            InRange = true;
         }
         else if (d2 < rlist2)
         {
@@ -1021,7 +1018,7 @@ static void makeClusterListSimple(const Grid&       jGrid,
         return;
     }
 
-    InRange = FALSE;
+    InRange = false;
     while (!InRange && jclusterLast > jclusterFirst)
     {
         real d2 = clusterBoundingBoxDistance2(bb_ci[0], jGrid.jBoundingBoxes()[jclusterLast]);
@@ -1034,7 +1031,7 @@ static void makeClusterListSimple(const Grid&       jGrid,
          */
         if (d2 < rbb2)
         {
-            InRange = TRUE;
+            InRange = true;
         }
         else if (d2 < rlist2)
         {
@@ -1132,21 +1129,14 @@ static void make_cluster_list_supersub(const Grid&       iGrid,
 
         const int cj_gl = jGrid.cellOffset() * c_gpuNumClusterPerCell + cj;
 
-        int ci1;
-        if (excludeSubDiagonal && sci == scj)
-        {
-            ci1 = subc + 1;
-        }
-        else
-        {
-            ci1 = iGrid.numClustersPerCell()[sci];
-        }
+        int ci1 = (excludeSubDiagonal && sci == scj) ? subc + 1 : iGrid.numClustersPerCell()[sci];
+
 
 #if NBNXN_BBXXXX
         /* Determine all ci1 bb distances in one call with SIMD4 */
         const int offset = packedBoundingBoxesIndex(cj) + (cj & (c_packedBoundingBoxesDimSize - 1));
-        clusterBoundingBoxDistance2_xxxx_simd4(jGrid.packedBoundingBoxes().data() + offset, ci1,
-                                               pbb_ci, d2l);
+        clusterBoundingBoxDistance2_xxxx_simd4(
+                jGrid.packedBoundingBoxes().data() + offset, ci1, pbb_ci, d2l);
         *numDistanceChecks += c_nbnxnGpuClusterSize * 2;
 #endif
 
@@ -1307,23 +1297,20 @@ static inline int findJClusterInJList(int                             jCluster,
                                       const JListRanges&              ranges,
                                       gmx::ArrayRef<const CjListType> cjList)
 {
-    int index;
-
     if (jCluster < ranges.cjFirst + ranges.numDirect)
     {
         /* We can calculate the index directly using the offset */
-        index = ranges.cjIndexStart + jCluster - ranges.cjFirst;
+        return ranges.cjIndexStart + jCluster - ranges.cjFirst;
     }
     else
     {
         /* Search for jCluster using bisection */
-        index          = -1;
+        int index      = -1;
         int rangeStart = ranges.cjIndexStart + ranges.numDirect;
         int rangeEnd   = ranges.cjIndexEnd;
-        int rangeMiddle;
         while (index == -1 && rangeStart < rangeEnd)
         {
-            rangeMiddle = (rangeStart + rangeEnd) >> 1;
+            int rangeMiddle = (rangeStart + rangeEnd) >> 1;
 
             const int clusterMiddle = nblCj(cjList, rangeMiddle);
 
@@ -1340,9 +1327,8 @@ static inline int findJClusterInJList(int                             jCluster,
                 rangeStart = rangeMiddle + 1;
             }
         }
+        return index;
     }
-
-    return index;
 }
 
 // TODO: Get rid of the two functions below by renaming sci to ci (or something better)
@@ -1452,16 +1438,10 @@ static inline void fep_list_new_nri_copy(t_nblist* nlist)
 /* Rellocate FEP list for size nl->maxnri, TODO: replace by C++ */
 static void reallocate_nblist(t_nblist* nl)
 {
-    if (gmx_debug_at)
-    {
-        fprintf(debug,
-                "reallocating neigborlist (ielec=%d, ivdw=%d, igeometry=%d, type=%d), maxnri=%d\n",
-                nl->ielec, nl->ivdw, nl->igeometry, nl->type, nl->maxnri);
-    }
-    srenew(nl->iinr, nl->maxnri);
-    srenew(nl->gid, nl->maxnri);
-    srenew(nl->shift, nl->maxnri);
-    srenew(nl->jindex, nl->maxnri + 1);
+    nl->iinr.resize(nl->maxnri);
+    nl->gid.resize(nl->maxnri);
+    nl->shift.resize(nl->maxnri);
+    nl->jindex.resize(nl->maxnri + 1);
 }
 
 /* For load balancing of the free-energy lists over threads, we set
@@ -1491,14 +1471,8 @@ static void make_fep_list(gmx::ArrayRef<const int> atomIndices,
                           const Grid&     jGrid,
                           t_nblist*       nlist)
 {
-    int      ci, cj_ind_start, cj_ind_end, cja, cjr;
-    int      nri_max;
-    int      gid_i = 0, gid_j, gid;
-    int      egp_shift, egp_mask;
-    int      gid_cj = 0;
-    int      ind_i, ind_j, ai, aj;
-    int      nri;
-    gmx_bool bFEP_i, bFEP_i_all;
+    int gid_i  = 0;
+    int gid_cj = 0;
 
     if (nbl_ci->cj_ind_end == nbl_ci->cj_ind_start)
     {
@@ -1506,16 +1480,16 @@ static void make_fep_list(gmx::ArrayRef<const int> atomIndices,
         return;
     }
 
-    ci = nbl_ci->ci;
+    const int ci = nbl_ci->ci;
 
-    cj_ind_start = nbl_ci->cj_ind_start;
-    cj_ind_end   = nbl_ci->cj_ind_end;
+    const int cj_ind_start = nbl_ci->cj_ind_start;
+    const int cj_ind_end   = nbl_ci->cj_ind_end;
 
     /* In worst case we have alternating energy groups
      * and create #atom-pair lists, which means we need the size
      * of a cluster pair (na_ci*na_cj) times the number of cj's.
      */
-    nri_max = nbl->na_ci * nbl->na_cj * (cj_ind_end - cj_ind_start);
+    const int nri_max = nbl->na_ci * nbl->na_cj * (cj_ind_end - cj_ind_start);
     if (nlist->nri + nri_max > nlist->maxnri)
     {
         nlist->maxnri = over_alloc_large(nlist->nri + nri_max);
@@ -1535,37 +1509,38 @@ static void make_fep_list(gmx::ArrayRef<const int> atomIndices,
         gmx_fatal(FARGS,
                   "The Verlet scheme with %dx%d kernels and free-energy only supports up to %zu "
                   "energy groups",
-                  iGrid.geometry().numAtomsICluster, numAtomsJCluster,
+                  iGrid.geometry().numAtomsICluster,
+                  numAtomsJCluster,
                   (sizeof(gid_cj) * 8) / numAtomsJCluster);
     }
 
-    egp_shift = nbatParams.neg_2log;
-    egp_mask  = (1 << egp_shift) - 1;
+    const int egp_shift = nbatParams.neg_2log;
+    const int egp_mask  = (1 << egp_shift) - 1;
 
     /* Loop over the atoms in the i sub-cell */
-    bFEP_i_all = TRUE;
+    bool bFEP_i_all = true;
     for (int i = 0; i < nbl->na_ci; i++)
     {
-        ind_i = ci * nbl->na_ci + i;
-        ai    = atomIndices[ind_i];
+        const int ind_i = ci * nbl->na_ci + i;
+        const int ai    = atomIndices[ind_i];
         if (ai >= 0)
         {
-            nri                    = nlist->nri;
+            int nri                = nlist->nri;
             nlist->jindex[nri + 1] = nlist->jindex[nri];
             nlist->iinr[nri]       = ai;
             /* The actual energy group pair index is set later */
             nlist->gid[nri]   = 0;
             nlist->shift[nri] = nbl_ci->shift & NBNXN_CI_SHIFT;
 
-            bFEP_i = iGrid.atomIsPerturbed(ci - iGrid.cellOffset(), i);
+            bool bFEP_i = iGrid.atomIsPerturbed(ci - iGrid.cellOffset(), i);
 
             bFEP_i_all = bFEP_i_all && bFEP_i;
 
             if (nlist->nrj + (cj_ind_end - cj_ind_start) * nbl->na_cj > nlist->maxnrj)
             {
                 nlist->maxnrj = over_alloc_small(nlist->nrj + (cj_ind_end - cj_ind_start) * nbl->na_cj);
-                srenew(nlist->jjnr, nlist->maxnrj);
-                srenew(nlist->excl_fep, nlist->maxnrj);
+                nlist->jjnr.resize(nlist->maxnrj);
+                nlist->excl_fep.resize(nlist->maxnrj);
             }
 
             if (ngid > 1)
@@ -1575,14 +1550,15 @@ static void make_fep_list(gmx::ArrayRef<const int> atomIndices,
 
             for (int cj_ind = cj_ind_start; cj_ind < cj_ind_end; cj_ind++)
             {
-                unsigned int fep_cj;
+                unsigned int fep_cj = 0U;
+                gid_cj              = 0;
 
-                cja = nbl->cj[cj_ind].cj;
+                const int cja = nbl->cj[cj_ind].cj;
 
                 if (numAtomsJCluster == jGrid.geometry().numAtomsICluster)
                 {
-                    cjr    = cja - jGrid.cellOffset();
-                    fep_cj = jGrid.fepBits(cjr);
+                    const int cjr = cja - jGrid.cellOffset();
+                    fep_cj        = jGrid.fepBits(cjr);
                     if (ngid > 1)
                     {
                         gid_cj = nbatParams.energrp[cja];
@@ -1590,7 +1566,7 @@ static void make_fep_list(gmx::ArrayRef<const int> atomIndices,
                 }
                 else if (2 * numAtomsJCluster == jGrid.geometry().numAtomsICluster)
                 {
-                    cjr = cja - jGrid.cellOffset() * 2;
+                    const int cjr = cja - jGrid.cellOffset() * 2;
                     /* Extract half of the ci fep/energrp mask */
                     fep_cj = (jGrid.fepBits(cjr >> 1) >> ((cjr & 1) * numAtomsJCluster))
                              & ((1 << numAtomsJCluster) - 1);
@@ -1602,7 +1578,7 @@ static void make_fep_list(gmx::ArrayRef<const int> atomIndices,
                 }
                 else
                 {
-                    cjr = cja - (jGrid.cellOffset() >> 1);
+                    const int cjr = cja - (jGrid.cellOffset() >> 1);
                     /* Combine two ci fep masks/energrp */
                     fep_cj = jGrid.fepBits(cjr * 2)
                              + (jGrid.fepBits(cjr * 2 + 1) << jGrid.geometry().numAtomsICluster);
@@ -1619,14 +1595,14 @@ static void make_fep_list(gmx::ArrayRef<const int> atomIndices,
                     for (int j = 0; j < nbl->na_cj; j++)
                     {
                         /* Is this interaction perturbed and not excluded? */
-                        ind_j = cja * nbl->na_cj + j;
-                        aj    = atomIndices[ind_j];
+                        const int ind_j = cja * nbl->na_cj + j;
+                        const int aj    = atomIndices[ind_j];
                         if (aj >= 0 && (bFEP_i || (fep_cj & (1 << j))) && (!bDiagRemoved || ind_j >= ind_i))
                         {
                             if (ngid > 1)
                             {
-                                gid_j = (gid_cj >> (j * egp_shift)) & egp_mask;
-                                gid   = GID(gid_i, gid_j, ngid);
+                                const int gid_j = (gid_cj >> (j * egp_shift)) & egp_mask;
+                                const int gid   = GID(gid_i, gid_j, ngid);
 
                                 if (nlist->nrj > nlist->jindex[nri] && nlist->gid[nri] != gid)
                                 {
@@ -1709,14 +1685,6 @@ static void make_fep_list(gmx::ArrayRef<const int> atomIndices,
                           const Grid&              jGrid,
                           t_nblist*                nlist)
 {
-    int                nri_max;
-    int                c_abs;
-    int                ind_i, ind_j, ai, aj;
-    int                nri;
-    gmx_bool           bFEP_i;
-    real               xi, yi, zi;
-    const nbnxn_cj4_t* cj4;
-
     const int numJClusterGroups = nbl_sci->numJClusterGroups();
     if (numJClusterGroups == 0)
     {
@@ -1736,7 +1704,8 @@ static void make_fep_list(gmx::ArrayRef<const int> atomIndices,
      * So for each of the na_sc i-atoms, we need max one FEP list
      * for each max_nrj_fep j-atoms.
      */
-    nri_max = nbl->na_sc * nbl->na_cj * (1 + (numJClusterGroups * c_nbnxnGpuJgroupSize) / max_nrj_fep);
+    const int nri_max =
+            nbl->na_sc * nbl->na_cj * (1 + (numJClusterGroups * c_nbnxnGpuJgroupSize) / max_nrj_fep);
     if (nlist->nri + nri_max > nlist->maxnri)
     {
         nlist->maxnri = over_alloc_large(nlist->nri + nri_max);
@@ -1746,38 +1715,39 @@ static void make_fep_list(gmx::ArrayRef<const int> atomIndices,
     /* Loop over the atoms in the i super-cluster */
     for (int c = 0; c < c_gpuNumClusterPerCell; c++)
     {
-        c_abs = sci * c_gpuNumClusterPerCell + c;
+        const int c_abs = sci * c_gpuNumClusterPerCell + c;
 
         for (int i = 0; i < nbl->na_ci; i++)
         {
-            ind_i = c_abs * nbl->na_ci + i;
-            ai    = atomIndices[ind_i];
+            const int ind_i = c_abs * nbl->na_ci + i;
+            const int ai    = atomIndices[ind_i];
             if (ai >= 0)
             {
-                nri                    = nlist->nri;
+                int nri                = nlist->nri;
                 nlist->jindex[nri + 1] = nlist->jindex[nri];
                 nlist->iinr[nri]       = ai;
                 /* With GPUs, energy groups are not supported */
                 nlist->gid[nri]   = 0;
                 nlist->shift[nri] = nbl_sci->shift & NBNXN_CI_SHIFT;
 
-                bFEP_i = iGrid.atomIsPerturbed(c_abs - iGrid.cellOffset() * c_gpuNumClusterPerCell, i);
+                const bool bFEP_i =
+                        iGrid.atomIsPerturbed(c_abs - iGrid.cellOffset() * c_gpuNumClusterPerCell, i);
 
-                xi = nbat->x()[ind_i * nbat->xstride + XX] + shx;
-                yi = nbat->x()[ind_i * nbat->xstride + YY] + shy;
-                zi = nbat->x()[ind_i * nbat->xstride + ZZ] + shz;
+                real xi = nbat->x()[ind_i * nbat->xstride + XX] + shx;
+                real yi = nbat->x()[ind_i * nbat->xstride + YY] + shy;
+                real zi = nbat->x()[ind_i * nbat->xstride + ZZ] + shz;
 
                 const int nrjMax = nlist->nrj + numJClusterGroups * c_nbnxnGpuJgroupSize * nbl->na_cj;
                 if (nrjMax > nlist->maxnrj)
                 {
                     nlist->maxnrj = over_alloc_small(nrjMax);
-                    srenew(nlist->jjnr, nlist->maxnrj);
-                    srenew(nlist->excl_fep, nlist->maxnrj);
+                    nlist->jjnr.resize(nlist->maxnrj);
+                    nlist->excl_fep.resize(nlist->maxnrj);
                 }
 
                 for (int cj4_ind = cj4_ind_start; cj4_ind < cj4_ind_end; cj4_ind++)
                 {
-                    cj4 = &nbl->cj4[cj4_ind];
+                    const nbnxn_cj4_t* cj4 = &nbl->cj4[cj4_ind];
 
                     for (int gcj = 0; gcj < c_nbnxnGpuJgroupSize; gcj++)
                     {
@@ -1794,25 +1764,22 @@ static void make_fep_list(gmx::ArrayRef<const int> atomIndices,
                             for (int j = 0; j < nbl->na_cj; j++)
                             {
                                 /* Is this interaction perturbed and not excluded? */
-                                ind_j = (jGrid.cellOffset() * c_gpuNumClusterPerCell + cjr) * nbl->na_cj + j;
-                                aj = atomIndices[ind_j];
+                                const int ind_j =
+                                        (jGrid.cellOffset() * c_gpuNumClusterPerCell + cjr) * nbl->na_cj + j;
+                                const int aj = atomIndices[ind_j];
                                 if (aj >= 0 && (bFEP_i || jGrid.atomIsPerturbed(cjr, j))
                                     && (!bDiagRemoved || ind_j >= ind_i))
                                 {
-                                    int          excl_pair;
-                                    unsigned int excl_bit;
-                                    real         dx, dy, dz;
-
                                     const int jHalf =
                                             j / (c_nbnxnGpuClusterSize / c_nbnxnGpuClusterpairSplit);
                                     nbnxn_excl_t& excl = get_exclusion_mask(nbl, cj4_ind, jHalf);
 
-                                    excl_pair = a_mod_wj(j) * nbl->na_ci + i;
-                                    excl_bit  = (1U << (gcj * c_gpuNumClusterPerCell + c));
+                                    int          excl_pair = a_mod_wj(j) * nbl->na_ci + i;
+                                    unsigned int excl_bit = (1U << (gcj * c_gpuNumClusterPerCell + c));
 
-                                    dx = nbat->x()[ind_j * nbat->xstride + XX] - xi;
-                                    dy = nbat->x()[ind_j * nbat->xstride + YY] - yi;
-                                    dz = nbat->x()[ind_j * nbat->xstride + ZZ] - zi;
+                                    real dx = nbat->x()[ind_j * nbat->xstride + XX] - xi;
+                                    real dy = nbat->x()[ind_j * nbat->xstride + YY] - yi;
+                                    real dz = nbat->x()[ind_j * nbat->xstride + ZZ] - zi;
 
                                     /* The unpruned GPU list has more than 2/3
                                      * of the atom pairs beyond rlist. Using
@@ -1888,7 +1855,8 @@ static void setExclusionsForIEntry(const Nbnxm::GridSet& gridSet,
      * Note that here we can not use cj4_ind_end, since the last cj4
      * can be only partially filled, so we use cj_ind.
      */
-    const JListRanges ranges(iEntry.cj4_ind_start * c_nbnxnGpuJgroupSize, nbl->work->cj_ind,
+    const JListRanges ranges(iEntry.cj4_ind_start * c_nbnxnGpuJgroupSize,
+                             nbl->work->cj_ind,
                              gmx::makeConstArrayRef(nbl->cj4));
 
     GMX_ASSERT(nbl->na_ci == c_nbnxnGpuClusterSize, "na_ci should match the GPU cluster size");
@@ -2081,16 +2049,15 @@ static void split_sci_entry(NbnxnPairlistGpu* nbl,
                             int               thread,
                             int               nthread)
 {
-    int nsp_max;
+
+    int nsp_max = nsp_target_av;
 
     if (progBal)
     {
-        float nsp_est;
-
         /* Estimate the total numbers of ci's of the nblist combined
          * over all threads using the target number of ci's.
          */
-        nsp_est = (nsp_tot_est * thread) / nthread + nbl->nci_tot;
+        float nsp_est = (nsp_tot_est * thread) / nthread + nbl->nci_tot;
 
         /* The first ci blocks should be larger, to avoid overhead.
          * The last ci blocks should be smaller, to improve load balancing.
@@ -2100,10 +2067,6 @@ static void split_sci_entry(NbnxnPairlistGpu* nbl,
          */
         nsp_max = static_cast<int>(nsp_target_av * (nsp_tot_est * 1.5 / (nsp_est + nsp_tot_est)));
     }
-    else
-    {
-        nsp_max = nsp_target_av;
-    }
 
     const int cj4_start = nbl->sci.back().cj4_ind_start;
     const int cj4_end   = nbl->sci.back().cj4_ind_end;
@@ -2230,9 +2193,9 @@ static void clear_pairlist_fep(t_nblist* nl)
 {
     nl->nri = 0;
     nl->nrj = 0;
-    if (nl->jindex == nullptr)
+    if (nl->jindex.empty())
     {
-        snew(nl->jindex, 1);
+        nl->jindex.resize(1);
     }
     nl->jindex[0] = 0;
 }
@@ -2295,8 +2258,8 @@ gmx_unused static void set_icell_bb_supersub(gmx::ArrayRef<const BoundingBox> bb
 gmx_unused static void set_icell_bb(const Grid& iGrid, int ci, real shx, real shy, real shz, NbnxnPairlistGpuWork* work)
 {
 #if NBNXN_BBXXXX
-    set_icell_bbxxxx_supersub(iGrid.packedBoundingBoxes(), ci, shx, shy, shz,
-                              work->iSuperClusterData.bbPacked.data());
+    set_icell_bbxxxx_supersub(
+            iGrid.packedBoundingBoxes(), ci, shx, shy, shz, work->iSuperClusterData.bbPacked.data());
 #else
     set_icell_bb_supersub(iGrid.iBoundingBoxes(), ci, shx, shy, shz, work->iSuperClusterData.bb.data());
 #endif
@@ -2437,11 +2400,7 @@ static real effective_buffer_1x1_vs_MxN(const Grid& iGrid, const Grid& jGrid)
 /* Estimates the interaction volume^2 for non-local interactions */
 static real nonlocal_vol2(const struct gmx_domdec_zones_t* zones, const rvec ls, real r)
 {
-    real cl, ca, za;
-    real vold_est;
-    real vol2_est_tot;
-
-    vol2_est_tot = 0;
+    real vol2_est_tot = 0;
 
     /* Here we simply add up the volumes of 1, 2 or 3 1D decomposition
      * not home interaction volume^2. As these volumes are not additive,
@@ -2454,9 +2413,9 @@ static real nonlocal_vol2(const struct gmx_domdec_zones_t* zones, const rvec ls,
     {
         if (zones->shift[z][XX] + zones->shift[z][YY] + zones->shift[z][ZZ] == 1)
         {
-            cl = 0;
-            ca = 1;
-            za = 1;
+            real cl = 0;
+            real ca = 1;
+            real za = 1;
             for (int d = 0; d < DIM; d++)
             {
                 if (zones->shift[z][d] == 0)
@@ -2468,7 +2427,7 @@ static real nonlocal_vol2(const struct gmx_domdec_zones_t* zones, const rvec ls,
             }
 
             /* 4 octants of a sphere */
-            vold_est = 0.25 * M_PI * r * r * r * r;
+            real vold_est = 0.25 * M_PI * r * r * r * r;
             /* 4 quarter pie slices on the edges */
             vold_est += 4 * cl * M_PI / 6.0 * r * r * r;
             /* One rectangular volume on a face */
@@ -2493,7 +2452,6 @@ static void get_nsubpair_target(const Nbnxm::GridSet&     gridSet,
      * Maxwell is less sensitive to the exact value.
      */
     const int nsubpair_target_min = 36;
-    real      r_eff_sup, vol_est, nsp_est, nsp_est_nl;
 
     const Grid& grid = gridSet.grids()[0];
 
@@ -2521,22 +2479,20 @@ static void get_nsubpair_target(const Nbnxm::GridSet&     gridSet,
     ls[ZZ] = numAtomsCluster / (dims.atomDensity * ls[XX] * ls[YY]);
 
     /* The formulas below are a heuristic estimate of the average nsj per si*/
-    r_eff_sup = rlist + nbnxn_get_rlist_effective_inc(numAtomsCluster, ls);
+    const real r_eff_sup = rlist + nbnxn_get_rlist_effective_inc(numAtomsCluster, ls);
 
-    if (!gridSet.domainSetup().haveMultipleDomains || gridSet.domainSetup().zones->n == 1)
-    {
-        nsp_est_nl = 0;
-    }
-    else
+    real nsp_est_nl = 0;
+    if (gridSet.domainSetup().haveMultipleDomains && gridSet.domainSetup().zones->n != 1)
     {
         nsp_est_nl = gmx::square(dims.atomDensity / numAtomsCluster)
                      * nonlocal_vol2(gridSet.domainSetup().zones, ls, r_eff_sup);
     }
 
+    real nsp_est = nsp_est_nl;
     if (iloc == InteractionLocality::Local)
     {
         /* Sub-cell interacts with itself */
-        vol_est = ls[XX] * ls[YY] * ls[ZZ];
+        real vol_est = ls[XX] * ls[YY] * ls[ZZ];
         /* 6/2 rectangular volume on the faces */
         vol_est += (ls[XX] * ls[YY] + ls[XX] * ls[ZZ] + ls[YY] * ls[ZZ]) * r_eff_sup;
         /* 12/2 quarter pie slices on the edges */
@@ -2552,7 +2508,7 @@ static void get_nsubpair_target(const Nbnxm::GridSet&     gridSet,
         /* Subtract the non-local pair count */
         nsp_est -= nsp_est_nl;
 
-        /* For small cut-offs nsp_est will be an underesimate.
+        /* For small cut-offs nsp_est will be an underestimate.
          * With DD nsp_est_nl is an overestimate so nsp_est can get negative.
          * So to avoid too small or negative nsp_est we set a minimum of
          * all cells interacting with all 3^3 direct neighbors (3^3-1)/2+1=14.
@@ -2568,10 +2524,6 @@ static void get_nsubpair_target(const Nbnxm::GridSet&     gridSet,
             fprintf(debug, "nsp_est local %5.1f non-local %5.1f\n", nsp_est, nsp_est_nl);
         }
     }
-    else
-    {
-        nsp_est = nsp_est_nl;
-    }
 
     /* Thus the (average) maximum j-list size should be as follows.
      * Since there is overhead, we shouldn't make the lists too small
@@ -2591,8 +2543,7 @@ static void print_nblist_ci_cj(FILE* fp, const NbnxnPairlistCpu& nbl)
 {
     for (const nbnxn_ci_t& ciEntry : nbl.ci)
     {
-        fprintf(fp, "ci %4d  shift %2d  ncj %3d\n", ciEntry.ci, ciEntry.shift,
-                ciEntry.cj_ind_end - ciEntry.cj_ind_start);
+        fprintf(fp, "ci %4d  shift %2d  ncj %3d\n", ciEntry.ci, ciEntry.shift, ciEntry.cj_ind_end - ciEntry.cj_ind_start);
 
         for (int j = ciEntry.cj_ind_start; j < ciEntry.cj_ind_end; j++)
         {
@@ -2623,8 +2574,7 @@ static void print_nblist_sci_cj(FILE* fp, const NbnxnPairlistGpu& nbl)
                 }
             }
         }
-        fprintf(fp, "ci %4d  shift %2d  ncj4 %2d ncp %3d\n", sci.sci, sci.shift,
-                sci.numJClusterGroups(), ncp);
+        fprintf(fp, "ci %4d  shift %2d  ncj4 %2d ncp %3d\n", sci.sci, sci.shift, sci.numJClusterGroups(), ncp);
     }
 }
 
@@ -2634,7 +2584,7 @@ static void combine_nblists(gmx::ArrayRef<const NbnxnPairlistGpu> nbls, NbnxnPai
     int nsci  = nblc->sci.size();
     int ncj4  = nblc->cj4.size();
     int nexcl = nblc->excl.size();
-    for (auto& nbl : nbls)
+    for (const auto& nbl : nbls)
     {
         nsci += nbl.sci.size();
         ncj4 += nbl.cj4.size();
@@ -2650,7 +2600,7 @@ static void combine_nblists(gmx::ArrayRef<const NbnxnPairlistGpu> nbls, NbnxnPai
     /* Each thread should copy its own data to the combined arrays,
      * as otherwise data will go back and forth between different caches.
      */
-    const int gmx_unused nthreads = gmx_omp_nthreads_get(emntPairsearch);
+    const int gmx_unused nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Pairsearch);
 
 #pragma omp parallel for num_threads(nthreads) schedule(static)
     for (gmx::index n = 0; n < nbls.ssize(); n++)
@@ -2695,7 +2645,7 @@ static void combine_nblists(gmx::ArrayRef<const NbnxnPairlistGpu> nbls, NbnxnPai
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
     }
 
-    for (auto& nbl : nbls)
+    for (const auto& nbl : nbls)
     {
         nblc->nci_tot += nbl.nci_tot;
     }
@@ -2723,7 +2673,7 @@ static void balance_fep_lists(gmx::ArrayRef<std::unique_ptr<t_nblist>> fepLists,
 
     const int nrj_target = (nrj_tot + numLists - 1) / numLists;
 
-    GMX_ASSERT(gmx_omp_nthreads_get(emntNonbonded) == numLists,
+    GMX_ASSERT(gmx_omp_nthreads_get(ModuleMultiThread::Nonbonded) == numLists,
                "We should have as many work objects as FEP lists");
 
 #pragma omp parallel for schedule(static) num_threads(numLists)
@@ -2744,8 +2694,8 @@ static void balance_fep_lists(gmx::ArrayRef<std::unique_ptr<t_nblist>> fepLists,
             if (nri_tot > nbl->maxnri || nrj_tot > nbl->maxnrj)
             {
                 nbl->maxnrj = over_alloc_small(nrj_tot);
-                srenew(nbl->jjnr, nbl->maxnrj);
-                srenew(nbl->excl_fep, nbl->maxnrj);
+                nbl->jjnr.resize(nbl->maxnrj);
+                nbl->excl_fep.resize(nbl->maxnrj);
             }
 
             clear_pairlist_fep(nbl);
@@ -2762,10 +2712,8 @@ static void balance_fep_lists(gmx::ArrayRef<std::unique_ptr<t_nblist>> fepLists,
 
         for (int i = 0; i < nbls->nri; i++)
         {
-            int nrj;
-
             /* The number of pairs in this i-entry */
-            nrj = nbls->jindex[i + 1] - nbls->jindex[i];
+            const int nrj = nbls->jindex[i + 1] - nbls->jindex[i];
 
             /* Decide if list th_dest is too large and we should procede
              * to the next destination list.
@@ -2856,19 +2804,17 @@ static float boundingbox_only_distance2(const Grid::Dimensions& iGridDims,
      * is only performed when only 1 out of 8 sub-cells in within range,
      * this is because the GPU is much faster than the cpu.
      */
-    real bbx, bby;
-    real rbb2;
 
-    bbx = 0.5 * (iGridDims.cellSize[XX] + jGridDims.cellSize[XX]);
-    bby = 0.5 * (iGridDims.cellSize[YY] + jGridDims.cellSize[YY]);
+    real bbx = 0.5 * (iGridDims.cellSize[XX] + jGridDims.cellSize[XX]);
+    real bby = 0.5 * (iGridDims.cellSize[YY] + jGridDims.cellSize[YY]);
     if (!simple)
     {
         bbx /= c_gpuNumClusterPerCellX;
         bby /= c_gpuNumClusterPerCellY;
     }
 
-    rbb2 = std::max(0.0, rlist - 0.5 * std::sqrt(bbx * bbx + bby * bby));
-    rbb2 = rbb2 * rbb2;
+    real rbb2 = std::max(0.0, rlist - 0.5 * std::sqrt(bbx * bbx + bby * bby));
+    rbb2      = rbb2 * rbb2;
 
 #if !GMX_DOUBLE
     return rbb2;
@@ -2882,7 +2828,6 @@ static int get_ci_block_size(const Grid& iGrid, const bool haveMultipleDomains,
     const int ci_block_enum      = 5;
     const int ci_block_denom     = 11;
     const int ci_block_min_atoms = 16;
-    int       ci_block;
 
     /* Here we decide how to distribute the blocks over the threads.
      * We use prime numbers to try to avoid that the grid size becomes
@@ -2897,8 +2842,8 @@ static int get_ci_block_size(const Grid& iGrid, const bool haveMultipleDomains,
      */
     GMX_ASSERT(iGrid.dimensions().numCells[XX] > 0, "Grid can't be empty");
     GMX_ASSERT(numLists > 0, "We need at least one list");
-    ci_block = (iGrid.numCells() * ci_block_enum)
-               / (ci_block_denom * iGrid.dimensions().numCells[XX] * numLists);
+    int ci_block = (iGrid.numCells() * ci_block_enum)
+                   / (ci_block_denom * iGrid.dimensions().numCells[XX] * numLists);
 
     const int numAtomsPerCell = iGrid.geometry().numAtomsPerCell;
 
@@ -2972,19 +2917,19 @@ static void makeClusterListWrapper(NbnxnPairlistCpu* nbl,
     switch (kernelType)
     {
         case ClusterDistanceKernelType::CpuPlainC:
-            makeClusterListSimple(jGrid, nbl, ci, firstCell, lastCell, excludeSubDiagonal,
-                                  nbat->x().data(), rlist2, rbb2, numDistanceChecks);
+            makeClusterListSimple(
+                    jGrid, nbl, ci, firstCell, lastCell, excludeSubDiagonal, nbat->x().data(), rlist2, rbb2, numDistanceChecks);
             break;
 #ifdef GMX_NBNXN_SIMD_4XN
         case ClusterDistanceKernelType::CpuSimd_4xM:
-            makeClusterListSimd4xn(jGrid, nbl, ci, firstCell, lastCell, excludeSubDiagonal,
-                                   nbat->x().data(), rlist2, rbb2, numDistanceChecks);
+            makeClusterListSimd4xn(
+                    jGrid, nbl, ci, firstCell, lastCell, excludeSubDiagonal, nbat->x().data(), rlist2, rbb2, numDistanceChecks);
             break;
 #endif
 #ifdef GMX_NBNXN_SIMD_2XNN
         case ClusterDistanceKernelType::CpuSimd_2xMM:
-            makeClusterListSimd2xnn(jGrid, nbl, ci, firstCell, lastCell, excludeSubDiagonal,
-                                    nbat->x().data(), rlist2, rbb2, numDistanceChecks);
+            makeClusterListSimd2xnn(
+                    jGrid, nbl, ci, firstCell, lastCell, excludeSubDiagonal, nbat->x().data(), rlist2, rbb2, numDistanceChecks);
             break;
 #endif
         default: GMX_ASSERT(false, "Unhandled kernel type");
@@ -3006,8 +2951,8 @@ static void makeClusterListWrapper(NbnxnPairlistGpu* nbl,
 {
     for (int cj = firstCell; cj <= lastCell; cj++)
     {
-        make_cluster_list_supersub(iGrid, jGrid, nbl, ci, cj, excludeSubDiagonal, nbat->xstride,
-                                   nbat->x().data(), rlist2, rbb2, numDistanceChecks);
+        make_cluster_list_supersub(
+                iGrid, jGrid, nbl, ci, cj, excludeSubDiagonal, nbat->xstride, nbat->x().data(), rlist2, rbb2, numDistanceChecks);
     }
 }
 
@@ -3091,20 +3036,11 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
                                      T*                      nbl,
                                      t_nblist*               nbl_fep)
 {
-    int            na_cj_2log;
     matrix         box;
     real           rl_fep2 = 0;
-    float          rbb2;
-    int            ci_b, ci, ci_x, ci_y, ci_xy;
     ivec           shp;
-    real           bx0, bx1, by0, by1, bz0, bz1;
-    real           bz1_frac;
-    real           d2cx, d2z, d2z_cx, d2z_cy, d2zx, d2zxy, d2xy;
-    int            cxf, cxl, cyf, cyf_x, cyl;
-    int            numDistanceChecks;
     int            gridi_flag_shift = 0, gridj_flag_shift = 0;
     gmx_bitmask_t* gridj_flag = nullptr;
-    int            ncj_old_i, ncj_old_j;
 
     if (jGrid.geometry().isSimple != pairlistIsSimple(*nbl)
         || iGrid.geometry().isSimple != pairlistIsSimple(*nbl))
@@ -3115,8 +3051,8 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
     sync_work(nbl);
     GMX_ASSERT(nbl->na_ci == jGrid.geometry().numAtomsICluster,
                "The cluster sizes in the list and grid should match");
-    nbl->na_cj = JClusterSizePerListType[pairlistType];
-    na_cj_2log = get_2log(nbl->na_cj);
+    nbl->na_cj           = JClusterSizePerListType[pairlistType];
+    const int na_cj_2log = get_2log(nbl->na_cj);
 
     nbl->rlist = rlist;
 
@@ -3144,7 +3080,7 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
          * We should not simply use rlist, since then we would not have
          * the small, effective buffering of the NxN lists.
          * The buffer is on overestimate, but the resulting cost for pairs
-         * beyond rlist is neglible compared to the FEP pairs within rlist.
+         * beyond rlist is negligible compared to the FEP pairs within rlist.
          */
         rl_fep2 = nbl->rlist + effective_buffer_1x1_vs_MxN(iGrid, jGrid);
 
@@ -3158,7 +3094,8 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
     const Grid::Dimensions& iGridDims = iGrid.dimensions();
     const Grid::Dimensions& jGridDims = jGrid.dimensions();
 
-    rbb2 = boundingbox_only_distance2(iGridDims, jGridDims, nbl->rlist, pairlistIsSimple(*nbl));
+    const float rbb2 =
+            boundingbox_only_distance2(iGridDims, jGridDims, nbl->rlist, pairlistIsSimple(*nbl));
 
     if (debug)
     {
@@ -3215,11 +3152,14 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
 
     if (debug)
     {
-        fprintf(debug, "nbl nc_i %d col.av. %.1f ci_block %d\n", iGrid.numCells(),
-                iGrid.numCells() / static_cast<double>(iGrid.numColumns()), ci_block);
+        fprintf(debug,
+                "nbl nc_i %d col.av. %.1f ci_block %d\n",
+                iGrid.numCells(),
+                iGrid.numCells() / static_cast<double>(iGrid.numColumns()),
+                ci_block);
     }
 
-    numDistanceChecks = 0;
+    int numDistanceChecks = 0;
 
     const real listRangeBBToJCell2 =
             gmx::square(listRangeForBoundingBoxToGridCell(rlist, jGrid.dimensions()));
@@ -3227,29 +3167,24 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
     /* Initially ci_b and ci to 1 before where we want them to start,
      * as they will both be incremented in next_ci.
      */
-    ci_b = -1;
-    ci   = th * ci_block - 1;
-    ci_x = 0;
-    ci_y = 0;
+    int ci_b = -1;
+    int ci   = th * ci_block - 1;
+    int ci_x = 0;
+    int ci_y = 0;
     while (next_ci(iGrid, nth, ci_block, &ci_x, &ci_y, &ci_b, &ci))
     {
         if (bSimple && flags_i[ci] == 0)
         {
             continue;
         }
-        ncj_old_i = getNumSimpleJClustersInList(*nbl);
+        const int ncj_old_i = getNumSimpleJClustersInList(*nbl);
 
-        d2cx = 0;
+        real d2cx = 0;
         if (!isIntraGridList && shp[XX] == 0)
         {
-            if (bSimple)
-            {
-                bx1 = bb_i[ci].upper.x;
-            }
-            else
-            {
-                bx1 = iGridDims.lowerCorner[XX] + (real(ci_x) + 1) * iGridDims.cellSize[XX];
-            }
+            const real bx1 =
+                    bSimple ? bb_i[ci].upper.x
+                            : iGridDims.lowerCorner[XX] + (real(ci_x) + 1) * iGridDims.cellSize[XX];
             if (bx1 < jGridDims.lowerCorner[XX])
             {
                 d2cx = gmx::square(jGridDims.lowerCorner[XX] - bx1);
@@ -3261,37 +3196,34 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
             }
         }
 
-        ci_xy = ci_x * iGridDims.numCells[YY] + ci_y;
+        int ci_xy = ci_x * iGridDims.numCells[YY] + ci_y;
 
         /* Loop over shift vectors in three dimensions */
         for (int tz = -shp[ZZ]; tz <= shp[ZZ]; tz++)
         {
             const real shz = real(tz) * box[ZZ][ZZ];
 
-            bz0 = bbcz_i[ci].lower + shz;
-            bz1 = bbcz_i[ci].upper + shz;
+            real bz0 = bbcz_i[ci].lower + shz;
+            real bz1 = bbcz_i[ci].upper + shz;
 
-            if (tz == 0)
-            {
-                d2z = 0;
-            }
-            else if (tz < 0)
+            real d2z = 0;
+            if (tz < 0)
             {
                 d2z = gmx::square(bz1);
             }
-            else
+            else if (tz > 0)
             {
                 d2z = gmx::square(bz0 - box[ZZ][ZZ]);
             }
 
-            d2z_cx = d2z + d2cx;
+            const real d2z_cx = d2z + d2cx;
 
             if (d2z_cx >= rlist2)
             {
                 continue;
             }
 
-            bz1_frac = bz1 / real(iGrid.numCellsInColumn(ci_xy));
+            real bz1_frac = bz1 / real(iGrid.numCellsInColumn(ci_xy));
             if (bz1_frac < 0)
             {
                 bz1_frac = 0;
@@ -3302,17 +3234,14 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
             {
                 const real shy = real(ty) * box[YY][YY] + real(tz) * box[ZZ][YY];
 
-                if (bSimple)
-                {
-                    by0 = bb_i[ci].lower.y + shy;
-                    by1 = bb_i[ci].upper.y + shy;
-                }
-                else
-                {
-                    by0 = iGridDims.lowerCorner[YY] + (real(ci_y)) * iGridDims.cellSize[YY] + shy;
-                    by1 = iGridDims.lowerCorner[YY] + (real(ci_y) + 1) * iGridDims.cellSize[YY] + shy;
-                }
+                const real by0 = bSimple ? bb_i[ci].lower.y + shy
+                                         : iGridDims.lowerCorner[YY]
+                                                   + (real(ci_y)) * iGridDims.cellSize[YY] + shy;
+                const real by1 = bSimple ? bb_i[ci].upper.y + shy
+                                         : iGridDims.lowerCorner[YY]
+                                                   + (real(ci_y) + 1) * iGridDims.cellSize[YY] + shy;
 
+                int cyf, cyl; //NOLINT(cppcoreguidelines-init-variables)
                 get_cell_range<YY>(by0, by1, jGridDims, d2z_cx, rlist, &cyf, &cyl);
 
                 if (cyf > cyl)
@@ -3320,7 +3249,7 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
                     continue;
                 }
 
-                d2z_cy = d2z;
+                real d2z_cy = d2z;
                 if (by1 < jGridDims.lowerCorner[YY])
                 {
                     d2z_cy += gmx::square(jGridDims.lowerCorner[YY] - by1);
@@ -3332,11 +3261,11 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
 
                 for (int tx = -shp[XX]; tx <= shp[XX]; tx++)
                 {
-                    const int shift = XYZ2IS(tx, ty, tz);
+                    const int shift = xyzToShiftIndex(tx, ty, tz);
 
-                    const bool excludeSubDiagonal = (isIntraGridList && shift == CENTRAL);
+                    const bool excludeSubDiagonal = (isIntraGridList && shift == gmx::c_centralShiftIndex);
 
-                    if (c_pbcShiftBackward && isIntraGridList && shift > CENTRAL)
+                    if (c_pbcShiftBackward && isIntraGridList && shift > gmx::c_centralShiftIndex)
                     {
                         continue;
                     }
@@ -3344,17 +3273,14 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
                     const real shx =
                             real(tx) * box[XX][XX] + real(ty) * box[YY][XX] + real(tz) * box[ZZ][XX];
 
-                    if (bSimple)
-                    {
-                        bx0 = bb_i[ci].lower.x + shx;
-                        bx1 = bb_i[ci].upper.x + shx;
-                    }
-                    else
-                    {
-                        bx0 = iGridDims.lowerCorner[XX] + (real(ci_x)) * iGridDims.cellSize[XX] + shx;
-                        bx1 = iGridDims.lowerCorner[XX] + (real(ci_x) + 1) * iGridDims.cellSize[XX] + shx;
-                    }
+                    const real bx0 = bSimple ? bb_i[ci].lower.x + shx
+                                             : iGridDims.lowerCorner[XX]
+                                                       + (real(ci_x)) * iGridDims.cellSize[XX] + shx;
+                    const real bx1 = bSimple ? bb_i[ci].upper.x + shx
+                                             : iGridDims.lowerCorner[XX]
+                                                       + (real(ci_x) + 1) * iGridDims.cellSize[XX] + shx;
 
+                    int cxf, cxl; //NOLINT(cppcoreguidelines-init-variables)
                     get_cell_range<XX>(bx0, bx1, jGridDims, d2z_cy, rlist, &cxf, &cxl);
 
                     if (cxf > cxl)
@@ -3374,13 +3300,19 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
 
                     set_icell_bb(iGrid, ci, shx, shy, shz, nbl->work.get());
 
-                    icell_set_x(cell0_i + ci, shx, shy, shz, nbat->xstride, nbat->x().data(),
-                                kernelType, nbl->work.get());
+                    icell_set_x(cell0_i + ci,
+                                shx,
+                                shy,
+                                shz,
+                                nbat->xstride,
+                                nbat->x().data(),
+                                kernelType,
+                                nbl->work.get());
 
                     for (int cx = cxf; cx <= cxl; cx++)
                     {
                         const real cx_real = cx;
-                        d2zx               = d2z;
+                        real       d2zx    = d2z;
                         if (jGridDims.lowerCorner[XX] + cx_real * jGridDims.cellSize[XX] > bx1)
                         {
                             d2zx += gmx::square(jGridDims.lowerCorner[XX]
@@ -3392,18 +3324,13 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
                                                 + (cx_real + 1) * jGridDims.cellSize[XX] - bx0);
                         }
 
-                        if (isIntraGridList && cx == 0 && (!c_pbcShiftBackward || shift == CENTRAL)
-                            && cyf < ci_y)
-                        {
-                            /* Leave the pairs with i > j.
-                             * Skip half of y when i and j have the same x.
-                             */
-                            cyf_x = ci_y;
-                        }
-                        else
-                        {
-                            cyf_x = cyf;
-                        }
+                        /* When true, leave the pairs with i > j.
+                         * Skip half of y when i and j have the same x.
+                         */
+                        const bool skipHalfY = (isIntraGridList && cx == 0
+                                                && (!c_pbcShiftBackward || shift == gmx::c_centralShiftIndex)
+                                                && cyf < ci_y);
+                        const int  cyf_x     = skipHalfY ? ci_y : cyf;
 
                         for (int cy = cyf_x; cy <= cyl; cy++)
                         {
@@ -3413,7 +3340,7 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
                                     jGrid.firstCellInColumn(cx * jGridDims.numCells[YY] + cy + 1);
 
                             const real cy_real = cy;
-                            d2zxy              = d2zx;
+                            real       d2zxy   = d2zx;
                             if (jGridDims.lowerCorner[YY] + cy_real * jGridDims.cellSize[YY] > by1)
                             {
                                 d2zxy += gmx::square(jGridDims.lowerCorner[YY]
@@ -3448,7 +3375,7 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
                                     midCell = columnEnd - 1;
                                 }
 
-                                d2xy = d2zxy - d2z;
+                                const real d2xy = d2zxy - d2z;
 
                                 /* Find the lowest cell that can possibly
                                  * be within range.
@@ -3509,7 +3436,7 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
                                     /* We want each atom/cell pair only once,
                                      * only use cj >= ci.
                                      */
-                                    if (!c_pbcShiftBackward || shift == CENTRAL)
+                                    if (!c_pbcShiftBackward || shift == gmx::c_centralShiftIndex)
                                     {
                                         firstCell = std::max(firstCell, ci);
                                     }
@@ -3522,11 +3449,20 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
                                                "column");
 
                                     /* For f buffer flags with simple lists */
-                                    ncj_old_j = getNumSimpleJClustersInList(*nbl);
-
-                                    makeClusterListWrapper(nbl, iGrid, ci, jGrid, firstCell, lastCell,
-                                                           excludeSubDiagonal, nbat, rlist2, rbb2,
-                                                           kernelType, &numDistanceChecks);
+                                    const int ncj_old_j = getNumSimpleJClustersInList(*nbl);
+
+                                    makeClusterListWrapper(nbl,
+                                                           iGrid,
+                                                           ci,
+                                                           jGrid,
+                                                           firstCell,
+                                                           lastCell,
+                                                           excludeSubDiagonal,
+                                                           nbat,
+                                                           rlist2,
+                                                           rbb2,
+                                                           kernelType,
+                                                           &numDistanceChecks);
 
                                     if (bFBufferFlag)
                                     {
@@ -3542,14 +3478,24 @@ static void nbnxn_make_pairlist_part(const Nbnxm::GridSet&   gridSet,
                     if (!exclusions.empty())
                     {
                         /* Set the exclusions for this ci list */
-                        setExclusionsForIEntry(gridSet, nbl, excludeSubDiagonal, na_cj_2log,
-                                               *getOpenIEntry(nbl), exclusions);
+                        setExclusionsForIEntry(
+                                gridSet, nbl, excludeSubDiagonal, na_cj_2log, *getOpenIEntry(nbl), exclusions);
                     }
 
                     if (haveFep)
                     {
-                        make_fep_list(gridSet.atomIndices(), nbat, nbl, excludeSubDiagonal,
-                                      getOpenIEntry(nbl), shx, shy, shz, rl_fep2, iGrid, jGrid, nbl_fep);
+                        make_fep_list(gridSet.atomIndices(),
+                                      nbat,
+                                      nbl,
+                                      excludeSubDiagonal,
+                                      getOpenIEntry(nbl),
+                                      shx,
+                                      shy,
+                                      shz,
+                                      rl_fep2,
+                                      iGrid,
+                                      jGrid,
+                                      nbl_fep);
                     }
 
                     /* Close this ci list */
@@ -3599,13 +3545,12 @@ static void reduce_buffer_flags(gmx::ArrayRef<PairsearchWork> searchWork,
 
 static void print_reduction_cost(gmx::ArrayRef<const gmx_bitmask_t> flags, int nout)
 {
-    int           nelem, nkeep, ncopy, nred, out;
-    gmx_bitmask_t mask_0;
+    int nelem = 0;
+    int nkeep = 0;
+    int ncopy = 0;
+    int nred  = 0;
 
-    nelem = 0;
-    nkeep = 0;
-    ncopy = 0;
-    nred  = 0;
+    gmx_bitmask_t mask_0; // NOLINT(cppcoreguidelines-init-variables)
     bitmask_init_bit(&mask_0, 0);
     for (const gmx_bitmask_t& flag_mask : flags)
     {
@@ -3618,7 +3563,7 @@ static void print_reduction_cost(gmx::ArrayRef<const gmx_bitmask_t> flags, int n
         else if (!bitmask_is_zero(flag_mask))
         {
             int c = 0;
-            for (out = 0; out < nout; out++)
+            for (int out = 0; out < nout; out++)
             {
                 if (bitmask_is_set(flag_mask, out))
                 {
@@ -3639,7 +3584,12 @@ static void print_reduction_cost(gmx::ArrayRef<const gmx_bitmask_t> flags, int n
     const auto numFlags = static_cast<double>(flags.size());
     fprintf(debug,
             "nbnxn reduction: #flag %zu #list %d elem %4.2f, keep %4.2f copy %4.2f red %4.2f\n",
-            flags.size(), nout, nelem / numFlags, nkeep / numFlags, ncopy / numFlags, nred / numFlags);
+            flags.size(),
+            nout,
+            nelem / numFlags,
+            nkeep / numFlags,
+            ncopy / numFlags,
+            nred / numFlags);
 }
 
 /* Copies the list entries from src to dest when cjStart <= *cjGlobal < cjEnd.
@@ -3682,7 +3632,7 @@ static void copySelectedListRange(const nbnxn_ci_t* gmx_restrict srcCi,
     }
 }
 
-#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ == 7
+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 7
 /* Avoid gcc 7 avx512 loop vectorization bug (actually only needed with -mavx512f) */
 #    pragma GCC push_options
 #    pragma GCC optimize("no-tree-vectorize")
@@ -3703,7 +3653,7 @@ static int countClusterpairs(gmx::ArrayRef<const NbnxnPairlistCpu> pairlists)
     return ncjTotal;
 }
 
-#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ == 7
+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 7
 #    pragma GCC pop_options
 #endif
 
@@ -3766,8 +3716,8 @@ static void rebalanceSimpleLists(gmx::ArrayRef<const NbnxnPairlistCpu> srcSet,
                         }
                         else
                         {
-                            copySelectedListRange<false>(srcCi, src, &dest, flag, iFlagShift,
-                                                         jFlagShift, t);
+                            copySelectedListRange<false>(
+                                    srcCi, src, &dest, flag, iFlagShift, jFlagShift, t);
                         }
                     }
                     cjGlobal += ncj;
@@ -3918,7 +3868,8 @@ static Range<int> getJZoneRange(const gmx_domdec_zones_t* ddZones,
 //! Prepares CPU lists produced by the search for dynamic pruning
 static void prepareListsForDynamicPruning(gmx::ArrayRef<NbnxnPairlistCpu> lists);
 
-void PairlistSet::constructPairlists(const Nbnxm::GridSet&         gridSet,
+void PairlistSet::constructPairlists(gmx::InteractionLocality      locality,
+                                     const Nbnxm::GridSet&         gridSet,
                                      gmx::ArrayRef<PairsearchWork> searchWork,
                                      nbnxn_atomdata_t*             nbat,
                                      const ListOfLists<int>&       exclusions,
@@ -3928,12 +3879,6 @@ void PairlistSet::constructPairlists(const Nbnxm::GridSet&         gridSet,
 {
     const real rlist = params_.rlistOuter;
 
-    int      nsubpair_target;
-    float    nsubpair_tot_est;
-    int      ci_block;
-    gmx_bool progBal;
-    int      np_tot, np_noq, np_hlj, nap;
-
     const int numLists = (isCpuType_ ? cpuLists_.size() : gpuLists_.size());
 
     if (debug)
@@ -3943,20 +3888,17 @@ void PairlistSet::constructPairlists(const Nbnxm::GridSet&         gridSet,
 
     nbat->bUseBufferFlags = (nbat->out.size() > 1);
     /* We should re-init the flags before making the first list */
-    if (nbat->bUseBufferFlags && locality_ == InteractionLocality::Local)
+    if (nbat->bUseBufferFlags && locality == InteractionLocality::Local)
     {
         resizeAndZeroBufferFlags(&nbat->buffer_flags, nbat->numAtoms());
     }
 
+    int   nsubpair_target  = 0;
+    float nsubpair_tot_est = 0.0F;
     if (!isCpuType_ && minimumIlistCountForGpuBalancing > 0)
     {
-        get_nsubpair_target(gridSet, locality_, rlist, minimumIlistCountForGpuBalancing,
-                            &nsubpair_target, &nsubpair_tot_est);
-    }
-    else
-    {
-        nsubpair_target  = 0;
-        nsubpair_tot_est = 0;
+        get_nsubpair_target(
+                gridSet, locality, rlist, minimumIlistCountForGpuBalancing, &nsubpair_target, &nsubpair_tot_est);
     }
 
     /* Clear all pair-lists */
@@ -3978,16 +3920,16 @@ void PairlistSet::constructPairlists(const Nbnxm::GridSet&         gridSet,
     }
 
     const gmx_domdec_zones_t* ddZones = gridSet.domainSetup().zones;
-    GMX_ASSERT(locality_ == InteractionLocality::Local || ddZones != nullptr,
+    GMX_ASSERT(locality == InteractionLocality::Local || ddZones != nullptr,
                "Nonlocal interaction locality with null ddZones.");
 
-    const auto iZoneRange = getIZoneRange(gridSet.domainSetup(), locality_);
+    const auto iZoneRange = getIZoneRange(gridSet.domainSetup(), locality);
 
     for (const int iZone : iZoneRange)
     {
         const Grid& iGrid = gridSet.grids()[iZone];
 
-        const auto jZoneRange = getJZoneRange(ddZones, locality_, iZone);
+        const auto jZoneRange = getJZoneRange(ddZones, locality, iZone);
 
         for (int jZone : jZoneRange)
         {
@@ -4000,12 +3942,13 @@ void PairlistSet::constructPairlists(const Nbnxm::GridSet&         gridSet,
 
             searchCycleCounting->start(enbsCCsearch);
 
-            ci_block = get_ci_block_size(iGrid, gridSet.domainSetup().haveMultipleDomains, numLists);
+            const int ci_block =
+                    get_ci_block_size(iGrid, gridSet.domainSetup().haveMultipleDomains, numLists);
 
             /* With GPU: generate progressively smaller lists for
              * load balancing for local only or non-local with 2 zones.
              */
-            progBal = (locality_ == InteractionLocality::Local || ddZones->n <= 2);
+            const bool progBal = (locality == InteractionLocality::Local || ddZones->n <= 2);
 
 #pragma omp parallel for num_threads(numLists) schedule(static)
             for (int th = 0; th < numLists; th++)
@@ -4036,17 +3979,43 @@ void PairlistSet::constructPairlists(const Nbnxm::GridSet&         gridSet,
                     /* Divide the i cells equally over the pairlists */
                     if (isCpuType_)
                     {
-                        nbnxn_make_pairlist_part(gridSet, iGrid, jGrid, &work, nbat, exclusions, rlist,
-                                                 params_.pairlistType, ci_block, nbat->bUseBufferFlags,
-                                                 nsubpair_target, progBal, nsubpair_tot_est, th,
-                                                 numLists, &cpuLists_[th], fepListPtr);
+                        nbnxn_make_pairlist_part(gridSet,
+                                                 iGrid,
+                                                 jGrid,
+                                                 &work,
+                                                 nbat,
+                                                 exclusions,
+                                                 rlist,
+                                                 params_.pairlistType,
+                                                 ci_block,
+                                                 nbat->bUseBufferFlags,
+                                                 nsubpair_target,
+                                                 progBal,
+                                                 nsubpair_tot_est,
+                                                 th,
+                                                 numLists,
+                                                 &cpuLists_[th],
+                                                 fepListPtr);
                     }
                     else
                     {
-                        nbnxn_make_pairlist_part(gridSet, iGrid, jGrid, &work, nbat, exclusions, rlist,
-                                                 params_.pairlistType, ci_block, nbat->bUseBufferFlags,
-                                                 nsubpair_target, progBal, nsubpair_tot_est, th,
-                                                 numLists, &gpuLists_[th], fepListPtr);
+                        nbnxn_make_pairlist_part(gridSet,
+                                                 iGrid,
+                                                 jGrid,
+                                                 &work,
+                                                 nbat,
+                                                 exclusions,
+                                                 rlist,
+                                                 params_.pairlistType,
+                                                 ci_block,
+                                                 nbat->bUseBufferFlags,
+                                                 nsubpair_target,
+                                                 progBal,
+                                                 nsubpair_tot_est,
+                                                 th,
+                                                 numLists,
+                                                 &gpuLists_[th],
+                                                 fepListPtr);
                     }
 
                     work.cycleCounter.stop();
@@ -4055,9 +4024,9 @@ void PairlistSet::constructPairlists(const Nbnxm::GridSet&         gridSet,
             }
             searchCycleCounting->stop(enbsCCsearch);
 
-            np_tot = 0;
-            np_noq = 0;
-            np_hlj = 0;
+            int np_tot = 0;
+            int np_noq = 0;
+            int np_hlj = 0;
             for (int th = 0; th < numLists; th++)
             {
                 inc_nrnb(nrnb, eNR_NBNXN_DIST2, searchWork[th].ndistc);
@@ -4076,14 +4045,9 @@ void PairlistSet::constructPairlists(const Nbnxm::GridSet&         gridSet,
                     np_tot += nbl.nci_tot;
                 }
             }
-            if (isCpuType_)
-            {
-                nap = cpuLists_[0].na_ci * cpuLists_[0].na_cj;
-            }
-            else
-            {
-                nap = gmx::square(gpuLists_[0].na_ci);
-            }
+            const int nap = isCpuType_ ? cpuLists_[0].na_ci * cpuLists_[0].na_cj
+                                       : gmx::square(gpuLists_[0].na_ci);
+
             natpair_ljq_ = (np_tot - np_noq) * nap - np_hlj * nap / 2;
             natpair_lj_  = np_noq * nap;
             natpair_q_   = np_hlj * nap / 2;
@@ -4217,8 +4181,13 @@ void PairlistSets::construct(const InteractionLocality iLocality,
             "exclusions should either be empty or the number of lists should match the number of "
             "local i-atoms");
 
-    pairlistSet(iLocality).constructPairlists(gridSet, pairSearch->work(), nbat, exclusions,
-                                              minimumIlistCountForGpuBalancing_, nrnb,
+    pairlistSet(iLocality).constructPairlists(iLocality,
+                                              gridSet,
+                                              pairSearch->work(),
+                                              nbat,
+                                              exclusions,
+                                              minimumIlistCountForGpuBalancing_,
+                                              nrnb,
                                               &pairSearch->cycleCounting_);
 
     if (iLocality == InteractionLocality::Local)
@@ -4247,7 +4216,7 @@ void PairlistSets::construct(const InteractionLocality iLocality,
 void nonbonded_verlet_t::constructPairlist(const InteractionLocality iLocality,
                                            const ListOfLists<int>&   exclusions,
                                            int64_t                   step,
-                                           t_nrnb*                   nrnb)
+                                           t_nrnb*                   nrnb) const
 {
     pairlistSets_->construct(iLocality, pairSearch_.get(), nbat.get(), exclusions, step, nrnb);
 
index 5bdfba33a83a672f98b6ef8dff6db958ab1b5683..bb9db400baac0a5bbed00a3e7782378ac48c6c99 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -299,7 +299,4 @@ struct NbnxnPairlistGpu
     gmx_cache_protect_t cp1;
 };
 
-//! Initializes a free-energy pair-list
-void nbnxn_init_pairlist_fep(t_nblist* nl);
-
 #endif
index c7f72b4d9d85ad531dae49bb7dcbee095dc63b76..6c8bc8f46de2110504854536bebbe7b3c1b86e24 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,10 +57,9 @@ static inline void icell_set_x_simd_2xnn(int  ci,
                                          const real*           x,
                                          NbnxnPairlistCpuWork* work)
 {
-    int   ia;
     real* x_ci_simd = work->iClusterData.xSimd.data();
 
-    ia = xIndexFromCi<NbnxnLayout::Simd2xNN>(ci);
+    const int ia = xIndexFromCi<NbnxnLayout::Simd2xNN>(ci);
 
     store(x_ci_simd + 0 * GMX_SIMD_REAL_WIDTH,
           loadU1DualHsimd(x + ia + 0 * c_xStride2xNN + 0) + SimdReal(shx));
@@ -78,7 +77,7 @@ static inline void icell_set_x_simd_2xnn(int  ci,
 
 /*! \brief SIMD code for checking and adding cluster-pairs to the list using coordinates in packed format.
  *
- * Checks bouding box distances and possibly atom pair distances.
+ * Checks bounding box distances and possibly atom pair distances.
  * This is an accelerated version of make_cluster_list_simple.
  *
  * \param[in]     jGrid               The j-grid
@@ -121,10 +120,6 @@ static inline void makeClusterListSimd2xnn(const Grid&       jGrid,
 
     SimdReal rc2_S;
 
-    gmx_bool InRange;
-    float    d2;
-    int      xind_f, xind_l;
-
     int jclusterFirst = cjFromCi<NbnxnLayout::Simd2xNN, 0>(firstCell);
     int jclusterLast  = cjFromCi<NbnxnLayout::Simd2xNN, 1>(lastCell);
     GMX_ASSERT(jclusterLast >= jclusterFirst,
@@ -133,10 +128,10 @@ static inline void makeClusterListSimd2xnn(const Grid&       jGrid,
 
     rc2_S = SimdReal(rlist2);
 
-    InRange = FALSE;
+    bool InRange = false;
     while (!InRange && jclusterFirst <= jclusterLast)
     {
-        d2 = clusterBoundingBoxDistance2(bb_ci[0], jGrid.jBoundingBoxes()[jclusterFirst]);
+        const float d2 = clusterBoundingBoxDistance2(bb_ci[0], jGrid.jBoundingBoxes()[jclusterFirst]);
         *numDistanceChecks += 2;
 
         /* Check if the distance is within the distance where
@@ -146,11 +141,11 @@ static inline void makeClusterListSimd2xnn(const Grid&       jGrid,
          */
         if (d2 < rbb2)
         {
-            InRange = TRUE;
+            InRange = true;
         }
         else if (d2 < rlist2)
         {
-            xind_f = xIndexFromCj<NbnxnLayout::Simd2xNN>(
+            const int xind_f = xIndexFromCj<NbnxnLayout::Simd2xNN>(
                     cjFromCi<NbnxnLayout::Simd2xNN, 0>(jGrid.cellOffset()) + jclusterFirst);
 
             jx_S = loadDuplicateHsimd(x_j + xind_f + 0 * c_xStride2xNN);
@@ -188,10 +183,10 @@ static inline void makeClusterListSimd2xnn(const Grid&       jGrid,
         return;
     }
 
-    InRange = FALSE;
+    InRange = false;
     while (!InRange && jclusterLast > jclusterFirst)
     {
-        d2 = clusterBoundingBoxDistance2(bb_ci[0], jGrid.jBoundingBoxes()[jclusterLast]);
+        const float d2 = clusterBoundingBoxDistance2(bb_ci[0], jGrid.jBoundingBoxes()[jclusterLast]);
         *numDistanceChecks += 2;
 
         /* Check if the distance is within the distance where
@@ -201,11 +196,11 @@ static inline void makeClusterListSimd2xnn(const Grid&       jGrid,
          */
         if (d2 < rbb2)
         {
-            InRange = TRUE;
+            InRange = true;
         }
         else if (d2 < rlist2)
         {
-            xind_l = xIndexFromCj<NbnxnLayout::Simd2xNN>(
+            const int xind_l = xIndexFromCj<NbnxnLayout::Simd2xNN>(
                     cjFromCi<NbnxnLayout::Simd2xNN, 0>(jGrid.cellOffset()) + jclusterLast);
 
             jx_S = loadDuplicateHsimd(x_j + xind_l + 0 * c_xStride2xNN);
index ce8cf3f28f446204653cefa837bbaf5e7f8e8a96..e2328fe49e1718f858fb96b118344925d8c9bb0c 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,10 +56,9 @@ static inline void icell_set_x_simd_4xn(int  ci,
                                         const real*           x,
                                         NbnxnPairlistCpuWork* work)
 {
-    int   ia;
     real* x_ci_simd = work->iClusterData.xSimd.data();
 
-    ia = xIndexFromCi<NbnxnLayout::Simd4xN>(ci);
+    const int ia = xIndexFromCi<NbnxnLayout::Simd4xN>(ci);
 
     store(x_ci_simd + 0 * GMX_SIMD_REAL_WIDTH, SimdReal(x[ia + 0 * c_xStride4xN] + shx));
     store(x_ci_simd + 1 * GMX_SIMD_REAL_WIDTH, SimdReal(x[ia + 1 * c_xStride4xN] + shy));
@@ -77,7 +76,7 @@ static inline void icell_set_x_simd_4xn(int  ci,
 
 /*! \brief SIMD code for checking and adding cluster-pairs to the list using coordinates in packed format.
  *
- * Checks bouding box distances and possibly atom pair distances.
+ * Checks bounding box distances and possibly atom pair distances.
  * This is an accelerated version of make_cluster_list_simple.
  *
  * \param[in]     jGrid               The j-grid
@@ -126,10 +125,6 @@ static inline void makeClusterListSimd4xn(const Grid&       jGrid,
 
     SimdReal rc2_S;
 
-    gmx_bool InRange;
-    float    d2;
-    int      xind_f, xind_l;
-
     /* Convert the j-range from i-cluster size indexing to j-cluster indexing */
     int jclusterFirst = cjFromCi<NbnxnLayout::Simd4xN, 0>(firstCell);
     int jclusterLast  = cjFromCi<NbnxnLayout::Simd4xN, 1>(lastCell);
@@ -139,10 +134,10 @@ static inline void makeClusterListSimd4xn(const Grid&       jGrid,
 
     rc2_S = SimdReal(rlist2);
 
-    InRange = FALSE;
+    bool InRange = false;
     while (!InRange && jclusterFirst <= jclusterLast)
     {
-        d2 = clusterBoundingBoxDistance2(bb_ci[0], jGrid.jBoundingBoxes()[jclusterFirst]);
+        const float d2 = clusterBoundingBoxDistance2(bb_ci[0], jGrid.jBoundingBoxes()[jclusterFirst]);
         *numDistanceChecks += 2;
 
         /* Check if the distance is within the distance where
@@ -152,11 +147,11 @@ static inline void makeClusterListSimd4xn(const Grid&       jGrid,
          */
         if (d2 < rbb2)
         {
-            InRange = TRUE;
+            InRange = true;
         }
         else if (d2 < rlist2)
         {
-            xind_f = xIndexFromCj<NbnxnLayout::Simd4xN>(
+            const int xind_f = xIndexFromCj<NbnxnLayout::Simd4xN>(
                     cjFromCi<NbnxnLayout::Simd4xN, 0>(jGrid.cellOffset()) + jclusterFirst);
 
             jx_S = load<SimdReal>(x_j + xind_f + 0 * c_xStride4xN);
@@ -207,10 +202,10 @@ static inline void makeClusterListSimd4xn(const Grid&       jGrid,
         return;
     }
 
-    InRange = FALSE;
+    InRange = false;
     while (!InRange && jclusterLast > jclusterFirst)
     {
-        d2 = clusterBoundingBoxDistance2(bb_ci[0], jGrid.jBoundingBoxes()[jclusterLast]);
+        const float d2 = clusterBoundingBoxDistance2(bb_ci[0], jGrid.jBoundingBoxes()[jclusterLast]);
         *numDistanceChecks += 2;
 
         /* Check if the distance is within the distance where
@@ -220,11 +215,11 @@ static inline void makeClusterListSimd4xn(const Grid&       jGrid,
          */
         if (d2 < rbb2)
         {
-            InRange = TRUE;
+            InRange = true;
         }
         else if (d2 < rlist2)
         {
-            xind_l = xIndexFromCj<NbnxnLayout::Simd4xN>(
+            const int xind_l = xIndexFromCj<NbnxnLayout::Simd4xN>(
                     cjFromCi<NbnxnLayout::Simd4xN, 0>(jGrid.cellOffset()) + jclusterLast);
 
             jx_S = load<SimdReal>(x_j + xind_l + 0 * c_xStride4xN);
index 6d0afa41cec234a0ab1e901848ac1be04803a59e..f9f61db40f6278efca9525be89628076eec66ec6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -79,8 +79,8 @@
  */
 static bool supportsDynamicPairlistGenerationInterval(const t_inputrec& ir)
 {
-    return ir.cutoff_scheme == ecutsVERLET && EI_DYNAMICS(ir.eI)
-           && !(EI_MD(ir.eI) && ir.etc == etcNO) && ir.verletbuf_tol > 0;
+    return ir.cutoff_scheme == CutoffScheme::Verlet && EI_DYNAMICS(ir.eI)
+           && !(EI_MD(ir.eI) && ir.etc == TemperatureCoupling::No) && ir.verletbuf_tol > 0;
 }
 
 /*! \brief Cost of non-bonded kernels
@@ -136,12 +136,7 @@ void increaseNstlist(FILE*               fp,
         return;
     }
 
-    float       listfac_ok, listfac_max;
-    int         nstlist_orig, nstlist_prev;
-    real        rlist_inc, rlist_ok, rlist_max;
-    real        rlist_new, rlist_prev;
     size_t      nstlist_ind = 0;
-    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 "
@@ -190,7 +185,7 @@ void increaseNstlist(FILE*               fp,
         }
     }
 
-    if (EI_MD(ir->eI) && ir->etc == etcNO)
+    if (EI_MD(ir->eI) && ir->etc == TemperatureCoupling::No)
     {
         if (MASTER(cr))
         {
@@ -229,21 +224,14 @@ void increaseNstlist(FILE*               fp,
                        "In all cases that do not support dynamic nstlist, we should have returned "
                        "with an appropriate message above");
 
-    if (useOrEmulateGpuForNonbondeds)
-    {
-        listfac_ok = c_nbnxnListSizeFactorGPU;
-    }
-    else if (cpuinfo.brandString().find("Xeon Phi") != std::string::npos)
-    {
-        listfac_ok = c_nbnxnListSizeFactorIntelXeonPhi;
-    }
-    else
-    {
-        listfac_ok = c_nbnxnListSizeFactorCpu;
-    }
-    listfac_max = listfac_ok + c_nbnxnListSizeFactorMargin;
+    const bool  runningOnXeonPhi = (cpuinfo.brandString().find("Xeon Phi") != std::string::npos);
+    const float listfac_ok       = useOrEmulateGpuForNonbondeds
+                                     ? c_nbnxnListSizeFactorGPU
+                                     : runningOnXeonPhi ? c_nbnxnListSizeFactorIntelXeonPhi
+                                                        : c_nbnxnListSizeFactorCpu;
+    float listfac_max = listfac_ok + c_nbnxnListSizeFactorMargin;
 
-    nstlist_orig = ir->nstlist;
+    const int nstlist_orig = ir->nstlist;
     if (nstlist_cmdline > 0)
     {
         if (fp)
@@ -260,24 +248,25 @@ void increaseNstlist(FILE*               fp,
     /* Allow rlist to make the list a given factor larger than the list
      * would be with the reference value for nstlist (10*mtsFactor).
      */
-    nstlist_prev = ir->nstlist;
-    ir->nstlist  = nbnxnReferenceNstlist * mtsFactor;
+    int nstlist_prev = ir->nstlist;
+    ir->nstlist      = nbnxnReferenceNstlist * mtsFactor;
     const real rlistWithReferenceNstlist =
             calcVerletBufferSize(*mtop, det(box), *ir, ir->nstlist, ir->nstlist - 1, -1, listSetup);
     ir->nstlist = nstlist_prev;
 
     /* Determine the pair list size increase due to zero interactions */
-    rlist_inc = nbnxn_get_rlist_effective_inc(listSetup.cluster_size_j, mtop->natoms / det(box));
-    rlist_ok  = (rlistWithReferenceNstlist + rlist_inc) * std::cbrt(listfac_ok) - rlist_inc;
-    rlist_max = (rlistWithReferenceNstlist + rlist_inc) * std::cbrt(listfac_max) - rlist_inc;
+    real rlist_inc = nbnxn_get_rlist_effective_inc(listSetup.cluster_size_j, mtop->natoms / det(box));
+    real rlist_ok  = (rlistWithReferenceNstlist + rlist_inc) * std::cbrt(listfac_ok) - rlist_inc;
+    real rlist_max = (rlistWithReferenceNstlist + rlist_inc) * std::cbrt(listfac_max) - rlist_inc;
     if (debug)
     {
-        fprintf(debug, "nstlist tuning: rlist_inc %.3f rlist_ok %.3f rlist_max %.3f\n", rlist_inc,
-                rlist_ok, rlist_max);
+        fprintf(debug, "nstlist tuning: rlist_inc %.3f rlist_ok %.3f rlist_max %.3f\n", rlist_inc, rlist_ok, rlist_max);
     }
 
-    nstlist_prev = nstlist_orig;
-    rlist_prev   = ir->rlist;
+    nstlist_prev    = nstlist_orig;
+    real rlist_prev = ir->rlist;
+    real rlist_new  = 0;
+    bool bBox = false, bDD = false, bCont = false;
     do
     {
         if (nstlist_cmdline <= 0)
@@ -286,12 +275,12 @@ void increaseNstlist(FILE*               fp,
         }
 
         /* Set the pair-list buffer size in ir */
-        rlist_new = calcVerletBufferSize(*mtop, det(box), *ir, ir->nstlist, ir->nstlist - mtsFactor,
-                                         -1, listSetup);
+        rlist_new = calcVerletBufferSize(
+                *mtop, det(box), *ir, ir->nstlist, ir->nstlist - mtsFactor, -1, listSetup);
 
         /* Does rlist fit in the box? */
         bBox = (gmx::square(rlist_new) < max_cutoff2(ir->pbcType, box));
-        bDD  = TRUE;
+        bDD  = true;
         if (bBox && DOMAINDECOMP(cr))
         {
             /* Currently (as of July 2020), the code in this if clause is never executed.
@@ -311,11 +300,15 @@ void increaseNstlist(FILE*               fp,
 
         if (debug)
         {
-            fprintf(debug, "nstlist %d rlist %.3f bBox %s bDD %s\n", ir->nstlist, rlist_new,
-                    gmx::boolToString(bBox), gmx::boolToString(bDD));
+            fprintf(debug,
+                    "nstlist %d rlist %.3f bBox %s bDD %s\n",
+                    ir->nstlist,
+                    rlist_new,
+                    gmx::boolToString(bBox),
+                    gmx::boolToString(bDD));
         }
 
-        bCont = FALSE;
+        bCont = false;
 
         if (nstlist_cmdline <= 0)
         {
@@ -331,8 +324,8 @@ void increaseNstlist(FILE*               fp,
                 /* Stick with the previous nstlist */
                 ir->nstlist = nstlist_prev;
                 rlist_new   = rlist_prev;
-                bBox        = TRUE;
-                bDD         = TRUE;
+                bBox        = true;
+                bDD         = true;
             }
         }
 
@@ -350,8 +343,12 @@ void increaseNstlist(FILE*               fp,
     }
     else if (ir->nstlist != nstlist_orig || rlist_new != ir->rlist)
     {
-        sprintf(buf, "Changing nstlist from %d to %d, rlist from %g to %g", nstlist_orig,
-                ir->nstlist, ir->rlist, rlist_new);
+        sprintf(buf,
+                "Changing nstlist from %d to %d, rlist from %g to %g",
+                nstlist_orig,
+                ir->nstlist,
+                ir->rlist,
+                rlist_new);
         if (MASTER(cr))
         {
             fprintf(stderr, "%s\n\n", buf);
@@ -386,42 +383,43 @@ static const int c_nbnxnDynamicListPruningMinLifetime = 4;
 
 /*! \brief Set the dynamic pairlist pruning parameters in \p ic
  *
- * \param[in]     ir          The input parameter record
+ * \param[in]     inputrec          The input parameter record
  * \param[in]     mtop        The global topology
  * \param[in]     box         The unit cell
  * \param[in]     useGpuList  Tells if we are using a GPU type pairlist
  * \param[in]     listSetup   The nbnxn pair list setup
  * \param[in]     userSetNstlistPrune  The user set ic->nstlistPrune (using an env.var.)
- * \param[in] ic              The nonbonded interactions constants
+ * \param[in]     interactionConst              The nonbonded interactions constants
  * \param[in,out] listParams  The list setup parameters
  */
-static void setDynamicPairlistPruningParameters(const t_inputrec*          ir,
-                                                const gmx_mtop_t*          mtop,
+static void setDynamicPairlistPruningParameters(const t_inputrec&          inputrec,
+                                                const gmx_mtop_t&          mtop,
                                                 const matrix               box,
                                                 const bool                 useGpuList,
                                                 const VerletbufListSetup&  listSetup,
                                                 const bool                 userSetNstlistPrune,
-                                                const interaction_const_t* ic,
+                                                const interaction_const_t& interactionConst,
                                                 PairlistParams*            listParams)
 {
     /* When applying multiple time stepping to the non-bonded forces,
      * we only compute them every mtsFactor steps, so all parameters here
      * should be a multiple of mtsFactor.
      */
-    listParams->mtsFactor = gmx::nonbondedMtsFactor(*ir);
+    listParams->mtsFactor = gmx::nonbondedMtsFactor(inputrec);
 
     const int mtsFactor = listParams->mtsFactor;
 
-    GMX_RELEASE_ASSERT(ir->nstlist % mtsFactor == 0, "nstlist should be a multiple of mtsFactor");
+    GMX_RELEASE_ASSERT(inputrec.nstlist % mtsFactor == 0,
+                       "nstlist should be a multiple of mtsFactor");
 
-    listParams->lifetime = ir->nstlist - mtsFactor;
+    listParams->lifetime = inputrec.nstlist - mtsFactor;
 
     /* When nstlistPrune was set by the user, we need to execute one loop
      * iteration to determine rlistInner.
      * Otherwise we compute rlistInner and increase nstlist as long as
      * we have a pairlist buffer of length 0 (i.e. rlistInner == cutoff).
      */
-    const real interactionCutoff = std::max(ic->rcoulomb, ic->rvdw);
+    const real interactionCutoff = std::max(interactionConst.rcoulomb, interactionConst.rvdw);
     int        tunedNstlistPrune = listParams->nstlistPrune;
     do
     {
@@ -431,15 +429,15 @@ static void setDynamicPairlistPruningParameters(const t_inputrec*          ir,
          */
         int listLifetime         = tunedNstlistPrune - (useGpuList ? 0 : mtsFactor);
         listParams->nstlistPrune = tunedNstlistPrune;
-        listParams->rlistInner   = calcVerletBufferSize(*mtop, det(box), *ir, tunedNstlistPrune,
-                                                      listLifetime, -1, listSetup);
+        listParams->rlistInner   = calcVerletBufferSize(
+                mtop, det(box), inputrec, tunedNstlistPrune, listLifetime, -1, listSetup);
 
         /* On the GPU we apply the dynamic pruning in a rolling fashion
          * every c_nbnxnGpuRollingListPruningInterval steps,
          * so keep nstlistPrune a multiple of the interval.
          */
         tunedNstlistPrune += (useGpuList ? c_nbnxnGpuRollingListPruningInterval : 1) * mtsFactor;
-    } while (!userSetNstlistPrune && tunedNstlistPrune < ir->nstlist
+    } while (!userSetNstlistPrune && tunedNstlistPrune < inputrec.nstlist
              && listParams->rlistInner == interactionCutoff);
 
     if (userSetNstlistPrune)
@@ -449,7 +447,7 @@ static void setDynamicPairlistPruningParameters(const t_inputrec*          ir,
     else
     {
         /* Determine the pair list size increase due to zero interactions */
-        real rlistInc = nbnxn_get_rlist_effective_inc(listSetup.cluster_size_j, mtop->natoms / det(box));
+        real rlistInc = nbnxn_get_rlist_effective_inc(listSetup.cluster_size_j, mtop.natoms / det(box));
 
         /* Dynamic pruning is only useful when the inner list is smaller than
          * the outer. The factor 0.99 ensures at least 3% list size reduction.
@@ -497,17 +495,17 @@ static std::string formatListSetup(const std::string& listName,
     std::string nstListFormat =
             "%" + gmx::formatString("%zu", gmx::formatString("%d", nstListForSpacing).size()) + "d";
     listSetup += gmx::formatString(nstListFormat.c_str(), nstList);
-    listSetup += gmx::formatString(" steps, buffer %.3f nm, rlist %.3f nm\n",
-                                   rList - interactionCutoff, rList);
+    listSetup += gmx::formatString(
+            " steps, buffer %.3f nm, rlist %.3f nm\n", rList - interactionCutoff, rList);
 
     return listSetup;
 }
 
 void setupDynamicPairlistPruning(const gmx::MDLogger&       mdlog,
-                                 const t_inputrec*          ir,
-                                 const gmx_mtop_t*          mtop,
+                                 const t_inputrec&          inputrec,
+                                 const gmx_mtop_t&          mtop,
                                  matrix                     box,
-                                 const interaction_const_t* ic,
+                                 const interaction_const_t& interactionConst,
                                  PairlistParams*            listParams)
 {
     GMX_RELEASE_ASSERT(listParams->rlistOuter > 0, "With the nbnxn setup rlist should be > 0");
@@ -519,9 +517,9 @@ void setupDynamicPairlistPruning(const gmx::MDLogger&       mdlog,
                                     JClusterSizePerListType[listParams->pairlistType] };
 
     /* Currently emulation mode does not support dual pair-lists */
-    const bool useGpuList = (listParams->pairlistType == PairlistType::HierarchicalNxN);
+    const bool useGpuList = sc_isGpuPairListType[listParams->pairlistType];
 
-    if (supportsDynamicPairlistGenerationInterval(*ir) && getenv("GMX_DISABLE_DYNAMICPRUNING") == nullptr)
+    if (supportsDynamicPairlistGenerationInterval(inputrec) && getenv("GMX_DISABLE_DYNAMICPRUNING") == nullptr)
     {
         /* Note that nstlistPrune can have any value independently of nstlist.
          * Actually applying rolling pruning is only useful when
@@ -532,10 +530,10 @@ void setupDynamicPairlistPruning(const gmx::MDLogger&       mdlog,
 
         if (userSetNstlistPrune)
         {
-            char* end;
+            char* end                = nullptr;
             listParams->nstlistPrune = strtol(env, &end, 10);
             if (!end || (*end != 0)
-                || !(listParams->nstlistPrune > 0 && listParams->nstlistPrune < ir->nstlist))
+                || !(listParams->nstlistPrune > 0 && listParams->nstlistPrune < inputrec.nstlist))
             {
                 gmx_fatal(FARGS,
                           "Invalid value passed in GMX_NSTLIST_DYNAMICPRUNING=%s, should be > 0 "
@@ -554,8 +552,8 @@ void setupDynamicPairlistPruning(const gmx::MDLogger&       mdlog,
             listParams->nstlistPrune = c_nbnxnDynamicListPruningMinLifetime;
         }
 
-        setDynamicPairlistPruningParameters(ir, mtop, box, useGpuList, ls, userSetNstlistPrune, ic,
-                                            listParams);
+        setDynamicPairlistPruningParameters(
+                inputrec, mtop, box, useGpuList, ls, userSetNstlistPrune, interactionConst, listParams);
 
         if (listParams->useDynamicPruning && useGpuList)
         {
@@ -563,10 +561,11 @@ void setupDynamicPairlistPruning(const gmx::MDLogger&       mdlog,
              * rolling pruning interval slightly shorter than nstlistTune,
              * thus giving correct results, but a slightly lower efficiency.
              */
-            GMX_RELEASE_ASSERT(listParams->nstlistPrune >= c_nbnxnGpuRollingListPruningInterval, ("With dynamic list pruning on GPUs pruning frequency must be at least as large as the rolling pruning interval ("
-                                                                                                  + std::to_string(c_nbnxnGpuRollingListPruningInterval)
-                                                                                                  + ").")
-                                                                                                         .c_str());
+            GMX_RELEASE_ASSERT(listParams->nstlistPrune >= c_nbnxnGpuRollingListPruningInterval,
+                               ("With dynamic list pruning on GPUs pruning frequency must be at "
+                                "least as large as the rolling pruning interval ("
+                                + std::to_string(c_nbnxnGpuRollingListPruningInterval) + ").")
+                                       .c_str());
             listParams->numRollingPruningParts =
                     listParams->nstlistPrune / c_nbnxnGpuRollingListPruningInterval;
         }
@@ -578,46 +577,51 @@ void setupDynamicPairlistPruning(const gmx::MDLogger&       mdlog,
 
     std::string mesg;
 
-    const real interactionCutoff = std::max(ic->rcoulomb, ic->rvdw);
+    const real interactionCutoff = std::max(interactionConst.rcoulomb, interactionConst.rvdw);
     if (listParams->useDynamicPruning)
     {
         mesg += gmx::formatString(
-                "Using a dual %dx%d pair-list setup updated with dynamic%s pruning:\n", ls.cluster_size_i,
-                ls.cluster_size_j, listParams->numRollingPruningParts > 1 ? ", rolling" : "");
-        mesg += formatListSetup("outer", ir->nstlist, ir->nstlist, listParams->rlistOuter, interactionCutoff);
-        mesg += formatListSetup("inner", listParams->nstlistPrune, ir->nstlist,
-                                listParams->rlistInner, interactionCutoff);
+                "Using a dual %dx%d pair-list setup updated with dynamic%s pruning:\n",
+                ls.cluster_size_i,
+                ls.cluster_size_j,
+                listParams->numRollingPruningParts > 1 ? ", rolling" : "");
+        mesg += formatListSetup(
+                "outer", inputrec.nstlist, inputrec.nstlist, listParams->rlistOuter, interactionCutoff);
+        mesg += formatListSetup(
+                "inner", listParams->nstlistPrune, inputrec.nstlist, listParams->rlistInner, interactionCutoff);
     }
     else
     {
         mesg += gmx::formatString("Using a %dx%d pair-list setup:\n", ls.cluster_size_i, ls.cluster_size_j);
-        mesg += formatListSetup("", ir->nstlist, ir->nstlist, listParams->rlistOuter, interactionCutoff);
+        mesg += formatListSetup(
+                "", inputrec.nstlist, inputrec.nstlist, listParams->rlistOuter, interactionCutoff);
     }
-    if (supportsDynamicPairlistGenerationInterval(*ir))
+    if (supportsDynamicPairlistGenerationInterval(inputrec))
     {
         const VerletbufListSetup listSetup1x1 = { 1, 1 };
-        const real rlistOuter = calcVerletBufferSize(*mtop, det(box), *ir, ir->nstlist,
-                                                     ir->nstlist - 1, -1, listSetup1x1);
-        real       rlistInner = rlistOuter;
+        const real               rlistOuter   = calcVerletBufferSize(
+                mtop, det(box), inputrec, inputrec.nstlist, inputrec.nstlist - 1, -1, listSetup1x1);
+        real rlistInner = rlistOuter;
         if (listParams->useDynamicPruning)
         {
             int listLifeTime = listParams->nstlistPrune - (useGpuList ? 0 : 1);
-            rlistInner       = calcVerletBufferSize(*mtop, det(box), *ir, listParams->nstlistPrune,
-                                              listLifeTime, -1, listSetup1x1);
+            rlistInner       = calcVerletBufferSize(
+                    mtop, det(box), inputrec, listParams->nstlistPrune, listLifeTime, -1, listSetup1x1);
         }
 
         mesg += gmx::formatString(
                 "At tolerance %g kJ/mol/ps per atom, equivalent classical 1x1 list would be:\n",
-                ir->verletbuf_tol);
+                inputrec.verletbuf_tol);
         if (listParams->useDynamicPruning)
         {
-            mesg += formatListSetup("outer", ir->nstlist, ir->nstlist, rlistOuter, interactionCutoff);
-            mesg += formatListSetup("inner", listParams->nstlistPrune, ir->nstlist, rlistInner,
-                                    interactionCutoff);
+            mesg += formatListSetup(
+                    "outer", inputrec.nstlist, inputrec.nstlist, rlistOuter, interactionCutoff);
+            mesg += formatListSetup(
+                    "inner", listParams->nstlistPrune, inputrec.nstlist, rlistInner, interactionCutoff);
         }
         else
         {
-            mesg += formatListSetup("", ir->nstlist, ir->nstlist, rlistOuter, interactionCutoff);
+            mesg += formatListSetup("", inputrec.nstlist, inputrec.nstlist, rlistOuter, interactionCutoff);
         }
     }
 
index 88a550a1a18f2ed3bfac899cfbdffb0d091a40eb..4e9a66dc26c6b7b22e442359facce559439a5e25 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,17 +85,17 @@ void increaseNstlist(FILE*               fplog,
 /*! \brief Set up the dynamic pairlist pruning
  *
  * \param[in,out] mdlog            MD logger
- * \param[in]     ir               The input parameter record
+ * \param[in]     inputrec         The input parameter record
  * \param[in]     mtop             The global topology
  * \param[in]     box              The unit cell
- * \param[in]     ic               The nonbonded interactions constants
+ * \param[in]     interactionConst The nonbonded interactions constants
  * \param[in,out] listParams       The list setup parameters
  */
 void setupDynamicPairlistPruning(const gmx::MDLogger&       mdlog,
-                                 const t_inputrec*          ir,
-                                 const gmx_mtop_t*          mtop,
+                                 const t_inputrec&          inputrec,
+                                 const gmx_mtop_t&          mtop,
                                  matrix                     box,
-                                 const interaction_const_t* ic,
+                                 const interaction_const_t& interactionConst,
                                  PairlistParams*            listParams);
 
 #endif /* NBNXM_PAIRLIST_TUNING_H */
index 9eefac4a9d656e873ccf9f3fdce68f05d5443a3b..a204a3eeda2a7652e8d71242be57a9b18922c030 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +59,9 @@ enum class KernelType;
 //! The i-cluster size for CPU kernels, always 4 atoms
 static constexpr int c_nbnxnCpuIClusterSize = 4;
 
-//! The i- and j-cluster size for GPU lists, 8 atoms for CUDA, set at compile time for OpenCL
-#if GMX_GPU_OPENCL
-static constexpr int c_nbnxnGpuClusterSize = GMX_OPENCL_NB_CLUSTER_SIZE;
+//! The i- and j-cluster size for GPU lists, 8 atoms for CUDA, set at compile time for OpenCL and SYCL
+#if GMX_GPU_OPENCL || GMX_GPU_SYCL
+static constexpr int c_nbnxnGpuClusterSize = GMX_GPU_NB_CLUSTER_SIZE;
 #else
 static constexpr int c_nbnxnGpuClusterSize = 8;
 #endif
@@ -106,6 +106,10 @@ static constexpr gmx::EnumerationArray<PairlistType, int> IClusterSizePerListTyp
 static constexpr gmx::EnumerationArray<PairlistType, int> JClusterSizePerListType = {
     { 2, 4, 8, c_nbnxnGpuClusterSize }
 };
+//! True if given pairlist type is used on GPU, false if on CPU.
+static constexpr gmx::EnumerationArray<PairlistType, bool> sc_isGpuPairListType = {
+    { false, false, false, true }
+};
 
 /*! \internal
  * \brief The setup for generating and pruning the nbnxn pair list.
index 3728dc9863a83f750efff75d0c76e8bdb51817ad..c88a907f378ca5c8f7af06702aa9341ef75425fd 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,12 +83,13 @@ class PairlistSet
 {
 public:
     //! Constructor: initializes the pairlist set as empty
-    PairlistSet(gmx::InteractionLocality locality, const PairlistParams& listParams);
+    PairlistSet(const PairlistParams& listParams);
 
     ~PairlistSet();
 
     //! Constructs the pairlists in the set using the coordinates in \p nbat
-    void constructPairlists(const Nbnxm::GridSet&         gridSet,
+    void constructPairlists(gmx::InteractionLocality      locality,
+                            const Nbnxm::GridSet&         gridSet,
                             gmx::ArrayRef<PairsearchWork> searchWork,
                             nbnxn_atomdata_t*             nbat,
                             const gmx::ListOfLists<int>&  exclusions,
@@ -97,10 +98,7 @@ public:
                             SearchCycleCounting*          searchCycleCounting);
 
     //! Dispatch the kernel for dynamic pairlist pruning
-    void dispatchPruneKernel(const nbnxn_atomdata_t* nbat, const rvec* shift_vec);
-
-    //! Returns the locality
-    gmx::InteractionLocality locality() const { return locality_; }
+    void dispatchPruneKernel(const nbnxn_atomdata_t* nbat, gmx::ArrayRef<const gmx::RVec> shift_vec);
 
     //! Returns the lists of CPU pairlists
     gmx::ArrayRef<const NbnxnPairlistCpu> cpuLists() const { return cpuLists_; }
@@ -122,8 +120,6 @@ public:
     gmx::ArrayRef<const std::unique_ptr<t_nblist>> fepLists() const { return fepLists_; }
 
 private:
-    //! The locality of the pairlist set
-    gmx::InteractionLocality locality_;
     //! List of pairlists in CPU layout
     std::vector<NbnxnPairlistCpu> cpuLists_;
     //! List of working list for rebalancing CPU lists
index 0119680c72581d53faf78fc73523264b1a4b473c..8bbb92d9c4878b67ceae572a59ce272b0d4a4940 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +84,9 @@ public:
                    t_nrnb*                      nrnb);
 
     //! Dispatches the dynamic pruning kernel for the given locality
-    void dispatchPruneKernel(gmx::InteractionLocality iLocality,
-                             const nbnxn_atomdata_t*  nbat,
-                             const rvec*              shift_vec);
+    void dispatchPruneKernel(gmx::InteractionLocality       iLocality,
+                             const nbnxn_atomdata_t*        nbat,
+                             gmx::ArrayRef<const gmx::RVec> shift_vec);
 
     //! Returns the pair list parameters
     const PairlistParams& params() const { return params_; }
index 3fce22eab74e0aa0eb30dbc65c8f39056f42f804..b30f37a50b320b6ba533fcd13102654d92f72f4e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +57,7 @@
 //! Working data for the actual i-supercell during pair search \internal
 struct NbnxnPairlistCpuWork
 {
-    //! Struct for storing coordinats and bounding box for an i-entry during search \internal
+    //! Struct for storing coordinates and bounding box for an i-entry during search \internal
     struct IClusterData
     {
         IClusterData() :
index be981232e2182344757d52db878a3f0da8920e0b..546b95ff65baf7283103f925d228774d596d1380 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +46,6 @@
 #include "pairsearch.h"
 
 #include "gromacs/mdtypes/nblist.h"
-#include "gromacs/utility/smalloc.h"
 
 #include "pairlist.h"
 
 void SearchCycleCounting::printCycles(FILE* fp, gmx::ArrayRef<const PairsearchWork> work) const
 {
     fprintf(fp, "\n");
-    fprintf(fp, "ns %4d grid %4.1f search %4.1f", cc_[enbsCCgrid].count(),
-            cc_[enbsCCgrid].averageMCycles(), cc_[enbsCCsearch].averageMCycles());
+    fprintf(fp,
+            "ns %4d grid %4.1f search %4.1f",
+            cc_[enbsCCgrid].count(),
+            cc_[enbsCCgrid].averageMCycles(),
+            cc_[enbsCCsearch].averageMCycles());
 
     if (work.size() > 1)
     {
@@ -72,30 +74,19 @@ void SearchCycleCounting::printCycles(FILE* fp, gmx::ArrayRef<const PairsearchWo
     fprintf(fp, "\n");
 }
 
-/*! \brief Frees the contents of a legacy t_nblist struct */
-static void free_nblist(t_nblist* nl)
-{
-    sfree(nl->iinr);
-    sfree(nl->gid);
-    sfree(nl->shift);
-    sfree(nl->jindex);
-    sfree(nl->jjnr);
-    sfree(nl->excl_fep);
-}
-
 #ifndef DOXYGEN
 
-PairsearchWork::PairsearchWork() : cp0({ { 0 } }), ndistc(0), nbl_fep(new t_nblist), cp1({ { 0 } })
+PairsearchWork::PairsearchWork() :
+    cp0({ { 0 } }),
+    ndistc(0),
+    nbl_fep(std::make_unique<t_nblist>()),
+    cp1({ { 0 } })
 {
-    nbnxn_init_pairlist_fep(nbl_fep.get());
 }
 
 #endif // !DOXYGEN
 
-PairsearchWork::~PairsearchWork()
-{
-    free_nblist(nbl_fep.get());
-}
+PairsearchWork::~PairsearchWork() = default;
 
 PairSearch::PairSearch(const PbcType             pbcType,
                        const bool                doTestParticleInsertion,
index bd5529dbd516b332a01abe63b8b9e7797f9137e2..7da87cf5c3ad6d711a79ae939ae016b6060055c3 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -40,7 +40,7 @@
  *
  * The PairSearch class holds the domain setup, the search grids
  * and helper object for the pair search. It manages the search work.
- * The actual gridding and pairlist generation is performeed by the
+ * The actual gridding and pairlist generation is performed by the
  * GridSet/Grid and PairlistSet/Pairlist classes, respectively.
  *
  * \author Berk Hess <hess@kth.se>
@@ -54,7 +54,6 @@
 #include <memory>
 #include <vector>
 
-#include "gromacs/domdec/domdec.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/nbnxm/atomdata.h"
 #include "gromacs/timing/cyclecounter.h"
@@ -151,7 +150,7 @@ struct PairsearchWork
 
     ~PairsearchWork();
 
-    //! Buffer to avoid cache polution
+    //! Buffer to avoid cache pollution
     gmx_cache_protect_t cp0;
 
     //! Temporary buffer for sorting atoms within a grid column
@@ -194,8 +193,18 @@ public:
     {
         cycleCounting_.start(enbsCCgrid);
 
-        gridSet_.putOnGrid(box, ddZone, lowerCorner, upperCorner, updateGroupsCog, atomRange,
-                           atomDensity, atomInfo, x, numAtomsMoved, move, nbat);
+        gridSet_.putOnGrid(box,
+                           ddZone,
+                           lowerCorner,
+                           upperCorner,
+                           updateGroupsCog,
+                           atomRange,
+                           atomDensity,
+                           atomInfo,
+                           x,
+                           numAtomsMoved,
+                           move,
+                           nbat);
 
         cycleCounting_.stop(enbsCCgrid);
     }
index 1ad8ef347a39dfe8fba74f2b7e9e307f6a42ab0c..0c7e29970b3238f7641b60c03489ff1bed44c2a5 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020 by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 void PairlistSets::dispatchPruneKernel(const gmx::InteractionLocality iLocality,
                                        const nbnxn_atomdata_t*        nbat,
-                                       const rvec*                    shift_vec)
+                                       gmx::ArrayRef<const gmx::RVec> shift_vec)
 {
     pairlistSet(iLocality).dispatchPruneKernel(nbat, shift_vec);
 }
 
-void PairlistSet::dispatchPruneKernel(const nbnxn_atomdata_t* nbat, const rvec* shift_vec)
+void PairlistSet::dispatchPruneKernel(const nbnxn_atomdata_t* nbat, gmx::ArrayRef<const gmx::RVec> shift_vec)
 {
     const real rlistInner = params_.rlistInner;
 
     GMX_ASSERT(cpuLists_[0].ciOuter.size() >= cpuLists_[0].ci.size(),
                "Here we should either have an empty ci list or ciOuter should be >= ci");
 
-    int gmx_unused nthreads = gmx_omp_nthreads_get(emntNonbonded);
+    int gmx_unused nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Nonbonded);
     GMX_ASSERT(nthreads == static_cast<gmx::index>(cpuLists_.size()),
                "The number of threads should match the number of lists");
 #pragma omp parallel for schedule(static) num_threads(nthreads)
@@ -91,23 +92,25 @@ void PairlistSet::dispatchPruneKernel(const nbnxn_atomdata_t* nbat, const rvec*
     }
 }
 
-void nonbonded_verlet_t::dispatchPruneKernelCpu(const gmx::InteractionLocality iLocality, const rvec* shift_vec)
+void nonbonded_verlet_t::dispatchPruneKernelCpu(const gmx::InteractionLocality iLocality,
+                                                gmx::ArrayRef<const gmx::RVec> shift_vec) const
 {
     pairlistSets_->dispatchPruneKernel(iLocality, nbat.get(), shift_vec);
 }
 
 void nonbonded_verlet_t::dispatchPruneKernelGpu(int64_t step)
 {
-    wallcycle_start_nocount(wcycle_, ewcLAUNCH_GPU);
-    wallcycle_sub_start_nocount(wcycle_, ewcsLAUNCH_GPU_NONBONDED);
+    wallcycle_start_nocount(wcycle_, WallCycleCounter::LaunchGpu);
+    wallcycle_sub_start_nocount(wcycle_, WallCycleSubCounter::LaunchGpuNonBonded);
 
     const bool stepIsEven =
             (pairlistSets().numStepsWithPairlist(step) % (2 * pairlistSets().params().mtsFactor) == 0);
 
     Nbnxm::gpu_launch_kernel_pruneonly(
-            gpu_nbv, stepIsEven ? gmx::InteractionLocality::Local : gmx::InteractionLocality::NonLocal,
+            gpu_nbv,
+            stepIsEven ? gmx::InteractionLocality::Local : gmx::InteractionLocality::NonLocal,
             pairlistSets().params().numRollingPruningParts);
 
-    wallcycle_sub_stop(wcycle_, ewcsLAUNCH_GPU_NONBONDED);
-    wallcycle_stop(wcycle_, ewcLAUNCH_GPU);
+    wallcycle_sub_stop(wcycle_, WallCycleSubCounter::LaunchGpuNonBonded);
+    wallcycle_stop(wcycle_, WallCycleCounter::LaunchGpu);
 }
similarity index 83%
rename from cmake/Platform/XeonPhi.cmake
rename to src/gromacs/nbnxm/sycl/CMakeLists.txt
index a23feaf9f84947085f3baff62e3ddaedb8fd0e10..4a6cc29b19562097537cc872bbcdd28db93d05fc 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) 2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
-set(CMAKE_SYSTEM_NAME Linux)
-set(CMAKE_SYSTEM_PROCESSOR XeonPhi)
-if(NOT GMX_MPI)
-    set(CMAKE_C_COMPILER "icc")
-    set(CMAKE_CXX_COMPILER "icpc")
-else()
-    set(CMAKE_C_COMPILER "mpiicc") #FindMPI doesn't work (#14991)
-    set(CMAKE_CXX_COMPILER "mpiicpc")
+if (GMX_GPU_SYCL)
+    file(GLOB NBNXM_SYCL_SOURCES *.cpp)
+    set(NBNXM_SOURCES ${NBNXM_SOURCES} ${NBNXM_SYCL_SOURCES} PARENT_SCOPE)
+    _gmx_add_files_to_property(SYCL_SOURCES ${NBNXM_SYCL_SOURCES})
 endif()
diff --git a/src/gromacs/nbnxm/sycl/nbnxm_sycl.cpp b/src/gromacs/nbnxm/sycl/nbnxm_sycl.cpp
new file mode 100644 (file)
index 0000000..d508a20
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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
+ *  Data management and kernel launch functions for nbnxm sycl.
+ *
+ *  \ingroup module_nbnxm
+ */
+#include "gmxpre.h"
+
+#include "gromacs/nbnxm/gpu_common.h"
+#include "gromacs/utility/exceptions.h"
+
+#include "nbnxm_sycl_kernel.h"
+#include "nbnxm_sycl_kernel_pruneonly.h"
+#include "nbnxm_sycl_types.h"
+
+namespace Nbnxm
+{
+
+void gpu_launch_kernel_pruneonly(NbnxmGpu* nb, const InteractionLocality iloc, const int numParts)
+{
+    gpu_plist* plist = nb->plist[iloc];
+
+    if (plist->haveFreshList)
+    {
+        GMX_ASSERT(numParts == 1, "With first pruning we expect 1 part");
+
+        /* Set rollingPruningNumParts to signal that it is not set */
+        plist->rollingPruningNumParts = 0;
+        plist->rollingPruningPart     = 0;
+    }
+    else
+    {
+        if (plist->rollingPruningNumParts == 0)
+        {
+            plist->rollingPruningNumParts = numParts;
+        }
+        else
+        {
+            GMX_ASSERT(numParts == plist->rollingPruningNumParts,
+                       "It is not allowed to change numParts in between list generation steps");
+        }
+    }
+
+    /* Use a local variable for part and update in plist, so we can return here
+     * without duplicating the part increment code.
+     */
+    const int part = plist->rollingPruningPart;
+
+    plist->rollingPruningPart++;
+    if (plist->rollingPruningPart >= plist->rollingPruningNumParts)
+    {
+        plist->rollingPruningPart = 0;
+    }
+
+    /* Compute the number of list entries to prune in this pass */
+    const int numSciInPart = (plist->nsci - part) / numParts;
+
+    /* Don't launch the kernel if there is no work to do */
+    if (numSciInPart <= 0)
+    {
+        plist->haveFreshList = false;
+        return;
+    }
+
+    launchNbnxmKernelPruneOnly(nb, iloc, numParts, part, numSciInPart);
+
+    if (plist->haveFreshList)
+    {
+        plist->haveFreshList = false;
+        nb->didPrune[iloc]   = true; // Mark that pruning has been done
+    }
+    else
+    {
+        nb->didRollingPrune[iloc] = true; // Mark that rolling pruning has been done
+    }
+}
+
+void gpu_launch_kernel(NbnxmGpu* nb, const gmx::StepWorkload& stepWork, const Nbnxm::InteractionLocality iloc)
+{
+    const NBParamGpu* nbp   = nb->nbparam;
+    gpu_plist*        plist = nb->plist[iloc];
+
+    if (canSkipNonbondedWork(*nb, iloc))
+    {
+        plist->haveFreshList = false;
+        return;
+    }
+
+    if (nbp->useDynamicPruning && plist->haveFreshList)
+    {
+        // Prunes for rlistOuter and rlistInner, sets plist->haveFreshList=false
+        gpu_launch_kernel_pruneonly(nb, iloc, 1);
+    }
+
+    if (plist->nsci == 0)
+    {
+        /* Don't launch an empty local kernel */
+        return;
+    }
+
+    launchNbnxmKernel(nb, stepWork, iloc);
+}
+
+} // namespace Nbnxm
diff --git a/src/gromacs/nbnxm/sycl/nbnxm_sycl_data_mgmt.cpp b/src/gromacs/nbnxm/sycl/nbnxm_sycl_data_mgmt.cpp
new file mode 100644 (file)
index 0000000..eb94244
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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
+ *  Stubs of functions that must be defined by nbnxm sycl implementation.
+ *
+ *  \ingroup module_nbnxm
+ */
+#include "gmxpre.h"
+
+#include "gromacs/gpu_utils/pmalloc.h"
+#include "gromacs/hardware/device_information.h"
+#include "gromacs/mdtypes/interaction_const.h"
+#include "gromacs/nbnxm/atomdata.h"
+#include "gromacs/nbnxm/gpu_data_mgmt.h"
+#include "gromacs/nbnxm/nbnxm_gpu.h"
+#include "gromacs/nbnxm/nbnxm_gpu_data_mgmt.h"
+#include "gromacs/pbcutil/ishift.h"
+#include "gromacs/utility/exceptions.h"
+
+#include "nbnxm_sycl_types.h"
+
+namespace Nbnxm
+{
+
+void gpu_init_platform_specific(NbnxmGpu* /* nb */)
+{
+    // Nothing specific in SYCL
+}
+
+void gpu_free_platform_specific(NbnxmGpu* /* nb */)
+{
+    // Nothing specific in SYCL
+}
+
+int gpu_min_ci_balanced(NbnxmGpu* nb)
+{
+    // SYCL-TODO: Logic and magic values taken from OpenCL
+    static constexpr unsigned int balancedFactor = 50;
+    if (nb == nullptr)
+    {
+        return 0;
+    }
+    const cl::sycl::device device = nb->deviceContext_->deviceInfo().syclDevice;
+    const int numComputeUnits     = device.get_info<cl::sycl::info::device::max_compute_units>();
+    return balancedFactor * numComputeUnits;
+}
+
+} // namespace Nbnxm
diff --git a/src/gromacs/nbnxm/sycl/nbnxm_sycl_kernel.cpp b/src/gromacs/nbnxm/sycl/nbnxm_sycl_kernel.cpp
new file mode 100644 (file)
index 0000000..a2bfe59
--- /dev/null
@@ -0,0 +1,1043 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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
+ *  NBNXM SYCL kernels
+ *
+ *  \ingroup module_nbnxm
+ */
+#include "gmxpre.h"
+
+#include "nbnxm_sycl_kernel.h"
+
+#include "gromacs/gpu_utils/devicebuffer.h"
+#include "gromacs/gpu_utils/gmxsycl.h"
+#include "gromacs/math/functions.h"
+#include "gromacs/mdtypes/simulation_workload.h"
+#include "gromacs/pbcutil/ishift.h"
+#include "gromacs/utility/template_mp.h"
+
+#include "nbnxm_sycl_kernel_utils.h"
+#include "nbnxm_sycl_types.h"
+
+namespace Nbnxm
+{
+
+//! \brief Set of boolean constants mimicking preprocessor macros.
+template<enum ElecType elecType, enum VdwType vdwType>
+struct EnergyFunctionProperties {
+    static constexpr bool elecCutoff = (elecType == ElecType::Cut); ///< EL_CUTOFF
+    static constexpr bool elecRF     = (elecType == ElecType::RF);  ///< EL_RF
+    static constexpr bool elecEwaldAna =
+            (elecType == ElecType::EwaldAna || elecType == ElecType::EwaldAnaTwin); ///< EL_EWALD_ANA
+    static constexpr bool elecEwaldTab =
+            (elecType == ElecType::EwaldTab || elecType == ElecType::EwaldTabTwin); ///< EL_EWALD_TAB
+    static constexpr bool elecEwaldTwin =
+            (elecType == ElecType::EwaldAnaTwin || elecType == ElecType::EwaldTabTwin);
+    static constexpr bool elecEwald        = (elecEwaldAna || elecEwaldTab); ///< EL_EWALD_ANY
+    static constexpr bool vdwCombLB        = (vdwType == VdwType::CutCombLB);
+    static constexpr bool vdwCombGeom      = (vdwType == VdwType::CutCombGeom); ///< LJ_COMB_GEOM
+    static constexpr bool vdwComb          = (vdwCombLB || vdwCombGeom);        ///< LJ_COMB
+    static constexpr bool vdwEwaldCombGeom = (vdwType == VdwType::EwaldGeom); ///< LJ_EWALD_COMB_GEOM
+    static constexpr bool vdwEwaldCombLB   = (vdwType == VdwType::EwaldLB);   ///< LJ_EWALD_COMB_LB
+    static constexpr bool vdwEwald         = (vdwEwaldCombGeom || vdwEwaldCombLB); ///< LJ_EWALD
+    static constexpr bool vdwFSwitch       = (vdwType == VdwType::FSwitch); ///< LJ_FORCE_SWITCH
+    static constexpr bool vdwPSwitch       = (vdwType == VdwType::PSwitch); ///< LJ_POT_SWITCH
+};
+
+//! \brief Templated constants to shorten kernel function declaration.
+//@{
+template<enum VdwType vdwType>
+constexpr bool ljComb = EnergyFunctionProperties<ElecType::Count, vdwType>().vdwComb;
+
+template<enum ElecType elecType> // Yes, ElecType
+constexpr bool vdwCutoffCheck = EnergyFunctionProperties<elecType, VdwType::Count>().elecEwaldTwin;
+
+template<enum ElecType elecType>
+constexpr bool elecEwald = EnergyFunctionProperties<elecType, VdwType::Count>().elecEwald;
+
+template<enum ElecType elecType>
+constexpr bool elecEwaldTab = EnergyFunctionProperties<elecType, VdwType::Count>().elecEwaldTab;
+
+template<enum VdwType vdwType>
+constexpr bool ljEwald = EnergyFunctionProperties<ElecType::Count, vdwType>().vdwEwald;
+//@}
+
+using cl::sycl::access::fence_space;
+using cl::sycl::access::mode;
+using cl::sycl::access::target;
+
+static inline Float2 convertSigmaEpsilonToC6C12(const float sigma, const float epsilon)
+{
+    const float sigma2 = sigma * sigma;
+    const float sigma6 = sigma2 * sigma2 * sigma2;
+    const float c6     = epsilon * sigma6;
+    const float c12    = c6 * sigma6;
+
+    return Float2(c6, c12);
+}
+
+template<bool doCalcEnergies>
+static inline void ljForceSwitch(const shift_consts_t         dispersionShift,
+                                 const shift_consts_t         repulsionShift,
+                                 const float                  rVdwSwitch,
+                                 const float                  c6,
+                                 const float                  c12,
+                                 const float                  rInv,
+                                 const float                  r2,
+                                 cl::sycl::private_ptr<float> fInvR,
+                                 cl::sycl::private_ptr<float> eLJ)
+{
+    /* force switch constants */
+    const float dispShiftV2 = dispersionShift.c2;
+    const float dispShiftV3 = dispersionShift.c3;
+    const float repuShiftV2 = repulsionShift.c2;
+    const float repuShiftV3 = repulsionShift.c3;
+
+    const float r       = r2 * rInv;
+    const float rSwitch = cl::sycl::fdim(r, rVdwSwitch); // max(r - rVdwSwitch, 0)
+
+    *fInvR += -c6 * (dispShiftV2 + dispShiftV3 * rSwitch) * rSwitch * rSwitch * rInv
+              + c12 * (repuShiftV2 + repuShiftV3 * rSwitch) * rSwitch * rSwitch * rInv;
+
+    if constexpr (doCalcEnergies)
+    {
+        const float dispShiftF2 = dispShiftV2 / 3;
+        const float dispShiftF3 = dispShiftV3 / 4;
+        const float repuShiftF2 = repuShiftV2 / 3;
+        const float repuShiftF3 = repuShiftV3 / 4;
+        *eLJ += c6 * (dispShiftF2 + dispShiftF3 * rSwitch) * rSwitch * rSwitch * rSwitch
+                - c12 * (repuShiftF2 + repuShiftF3 * rSwitch) * rSwitch * rSwitch * rSwitch;
+    }
+}
+
+//! \brief Fetch C6 grid contribution coefficients and return the product of these.
+template<enum VdwType vdwType>
+static inline float calculateLJEwaldC6Grid(const DeviceAccessor<Float2, mode::read> a_nbfpComb,
+                                           const int                                typeI,
+                                           const int                                typeJ)
+{
+    if constexpr (vdwType == VdwType::EwaldGeom)
+    {
+        return a_nbfpComb[typeI][0] * a_nbfpComb[typeJ][0];
+    }
+    else
+    {
+        static_assert(vdwType == VdwType::EwaldLB);
+        /* sigma and epsilon are scaled to give 6*C6 */
+        const Float2 c6c12_i = a_nbfpComb[typeI];
+        const Float2 c6c12_j = a_nbfpComb[typeJ];
+
+        const float sigma   = c6c12_i[0] + c6c12_j[0];
+        const float epsilon = c6c12_i[1] * c6c12_j[1];
+
+        const float sigma2 = sigma * sigma;
+        return epsilon * sigma2 * sigma2 * sigma2;
+    }
+}
+
+//! Calculate LJ-PME grid force contribution with geometric or LB combination rule.
+template<bool doCalcEnergies, enum VdwType vdwType>
+static inline void ljEwaldComb(const DeviceAccessor<Float2, mode::read> a_nbfpComb,
+                               const float                              sh_lj_ewald,
+                               const int                                typeI,
+                               const int                                typeJ,
+                               const float                              r2,
+                               const float                              r2Inv,
+                               const float                              lje_coeff2,
+                               const float                              lje_coeff6_6,
+                               const float                              int_bit,
+                               cl::sycl::private_ptr<float>             fInvR,
+                               cl::sycl::private_ptr<float>             eLJ)
+{
+    const float c6grid = calculateLJEwaldC6Grid<vdwType>(a_nbfpComb, typeI, typeJ);
+
+    /* Recalculate inv_r6 without exclusion mask */
+    const float inv_r6_nm = r2Inv * r2Inv * r2Inv;
+    const float cr2       = lje_coeff2 * r2;
+    const float expmcr2   = cl::sycl::exp(-cr2);
+    const float poly      = 1.0F + cr2 + 0.5F * cr2 * cr2;
+
+    /* Subtract the grid force from the total LJ force */
+    *fInvR += c6grid * (inv_r6_nm - expmcr2 * (inv_r6_nm * poly + lje_coeff6_6)) * r2Inv;
+
+    if constexpr (doCalcEnergies)
+    {
+        /* Shift should be applied only to real LJ pairs */
+        const float sh_mask = sh_lj_ewald * int_bit;
+        *eLJ += c_oneSixth * c6grid * (inv_r6_nm * (1.0F - expmcr2 * poly) + sh_mask);
+    }
+}
+
+/*! \brief Apply potential switch. */
+template<bool doCalcEnergies>
+static inline void ljPotentialSwitch(const switch_consts_t        vdwSwitch,
+                                     const float                  rVdwSwitch,
+                                     const float                  rInv,
+                                     const float                  r2,
+                                     cl::sycl::private_ptr<float> fInvR,
+                                     cl::sycl::private_ptr<float> eLJ)
+{
+    /* potential switch constants */
+    const float switchV3 = vdwSwitch.c3;
+    const float switchV4 = vdwSwitch.c4;
+    const float switchV5 = vdwSwitch.c5;
+    const float switchF2 = 3 * vdwSwitch.c3;
+    const float switchF3 = 4 * vdwSwitch.c4;
+    const float switchF4 = 5 * vdwSwitch.c5;
+
+    const float r       = r2 * rInv;
+    const float rSwitch = r - rVdwSwitch;
+
+    if (rSwitch > 0.0F)
+    {
+        const float sw =
+                1.0F + (switchV3 + (switchV4 + switchV5 * rSwitch) * rSwitch) * rSwitch * rSwitch * rSwitch;
+        const float dsw = (switchF2 + (switchF3 + switchF4 * rSwitch) * rSwitch) * rSwitch * rSwitch;
+
+        *fInvR = (*fInvR) * sw - rInv * (*eLJ) * dsw;
+        if constexpr (doCalcEnergies)
+        {
+            *eLJ *= sw;
+        }
+    }
+}
+
+
+/*! \brief Calculate analytical Ewald correction term. */
+static inline float pmeCorrF(const float z2)
+{
+    constexpr float FN6 = -1.7357322914161492954e-8F;
+    constexpr float FN5 = 1.4703624142580877519e-6F;
+    constexpr float FN4 = -0.000053401640219807709149F;
+    constexpr float FN3 = 0.0010054721316683106153F;
+    constexpr float FN2 = -0.019278317264888380590F;
+    constexpr float FN1 = 0.069670166153766424023F;
+    constexpr float FN0 = -0.75225204789749321333F;
+
+    constexpr float FD4 = 0.0011193462567257629232F;
+    constexpr float FD3 = 0.014866955030185295499F;
+    constexpr float FD2 = 0.11583842382862377919F;
+    constexpr float FD1 = 0.50736591960530292870F;
+    constexpr float FD0 = 1.0F;
+
+    const float z4 = z2 * z2;
+
+    float       polyFD0 = FD4 * z4 + FD2;
+    const float polyFD1 = FD3 * z4 + FD1;
+    polyFD0             = polyFD0 * z4 + FD0;
+    polyFD0             = polyFD1 * z2 + polyFD0;
+
+    polyFD0 = 1.0F / polyFD0;
+
+    float polyFN0 = FN6 * z4 + FN4;
+    float polyFN1 = FN5 * z4 + FN3;
+    polyFN0       = polyFN0 * z4 + FN2;
+    polyFN1       = polyFN1 * z4 + FN1;
+    polyFN0       = polyFN0 * z4 + FN0;
+    polyFN0       = polyFN1 * z2 + polyFN0;
+
+    return polyFN0 * polyFD0;
+}
+
+/*! \brief Linear interpolation using exactly two FMA operations.
+ *
+ *  Implements numeric equivalent of: (1-t)*d0 + t*d1.
+ */
+template<typename T>
+static inline T lerp(T d0, T d1, T t)
+{
+    return fma(t, d1, fma(-t, d0, d0));
+}
+
+/*! \brief Interpolate Ewald coulomb force correction using the F*r table. */
+static inline float interpolateCoulombForceR(const DeviceAccessor<float, mode::read> a_coulombTab,
+                                             const float coulombTabScale,
+                                             const float r)
+{
+    const float normalized = coulombTabScale * r;
+    const int   index      = static_cast<int>(normalized);
+    const float fraction   = normalized - index;
+
+    const float left  = a_coulombTab[index];
+    const float right = a_coulombTab[index + 1];
+
+    return lerp(left, right, fraction); // TODO: cl::sycl::mix
+}
+
+/*! \brief Reduce c_clSize j-force components and atomically accumulate into a_f.
+ *
+ * c_clSize consecutive threads hold the force components of a j-atom which we
+ * reduced in log2(cl_Size) steps using shift and atomically accumulate them into \p a_f.
+ */
+static inline void reduceForceJShuffle(Float3                             f,
+                                       const cl::sycl::nd_item<1>         itemIdx,
+                                       const int                          tidxi,
+                                       const int                          aidx,
+                                       DeviceAccessor<float, mode_atomic> a_f)
+{
+    static_assert(c_clSize == 8 || c_clSize == 4);
+    sycl_2020::sub_group sg = itemIdx.get_sub_group();
+
+    f[0] += sycl_2020::shift_left(sg, f[0], 1);
+    f[1] += sycl_2020::shift_right(sg, f[1], 1);
+    f[2] += sycl_2020::shift_left(sg, f[2], 1);
+    if (tidxi & 1)
+    {
+        f[0] = f[1];
+    }
+
+    f[0] += sycl_2020::shift_left(sg, f[0], 2);
+    f[2] += sycl_2020::shift_right(sg, f[2], 2);
+    if (tidxi & 2)
+    {
+        f[0] = f[2];
+    }
+
+    if constexpr (c_clSize == 8)
+    {
+        f[0] += sycl_2020::shift_left(sg, f[0], 4);
+    }
+
+    if (tidxi < 3)
+    {
+        atomicFetchAdd(a_f, 3 * aidx + tidxi, f[0]);
+    }
+}
+
+
+/*! \brief Final i-force reduction.
+ *
+ * Reduce c_nbnxnGpuNumClusterPerSupercluster i-force componets stored in \p fCiBuf[]
+ * accumulating atomically into \p a_f.
+ * If \p calcFShift is true, further reduce shift forces and atomically accumulate into \p a_fShift.
+ *
+ * This implementation works only with power of two array sizes.
+ */
+static inline void reduceForceIAndFShift(cl::sycl::accessor<float, 1, mode::read_write, target::local> sm_buf,
+                                         const Float3 fCiBuf[c_nbnxnGpuNumClusterPerSupercluster],
+                                         const bool   calcFShift,
+                                         const cl::sycl::nd_item<1>         itemIdx,
+                                         const int                          tidxi,
+                                         const int                          tidxj,
+                                         const int                          sci,
+                                         const int                          shift,
+                                         DeviceAccessor<float, mode_atomic> a_f,
+                                         DeviceAccessor<float, mode_atomic> a_fShift)
+{
+    // must have power of two elements in fCiBuf
+    static_assert(gmx::isPowerOfTwo(c_nbnxnGpuNumClusterPerSupercluster));
+
+    static constexpr int bufStride  = c_clSize * c_clSize;
+    static constexpr int clSizeLog2 = gmx::StaticLog2<c_clSize>::value;
+    const int            tidx       = tidxi + tidxj * c_clSize;
+    float                fShiftBuf  = 0;
+    for (int ciOffset = 0; ciOffset < c_nbnxnGpuNumClusterPerSupercluster; ciOffset++)
+    {
+        const int aidx = (sci * c_nbnxnGpuNumClusterPerSupercluster + ciOffset) * c_clSize + tidxi;
+        /* store i forces in shmem */
+        sm_buf[tidx]                 = fCiBuf[ciOffset][0];
+        sm_buf[bufStride + tidx]     = fCiBuf[ciOffset][1];
+        sm_buf[2 * bufStride + tidx] = fCiBuf[ciOffset][2];
+        itemIdx.barrier(fence_space::local_space);
+
+        /* Reduce the initial c_clSize values for each i atom to half
+         * every step by using c_clSize * i threads. */
+        int i = c_clSize / 2;
+        for (int j = clSizeLog2 - 1; j > 0; j--)
+        {
+            if (tidxj < i)
+            {
+                sm_buf[tidxj * c_clSize + tidxi] += sm_buf[(tidxj + i) * c_clSize + tidxi];
+                sm_buf[bufStride + tidxj * c_clSize + tidxi] +=
+                        sm_buf[bufStride + (tidxj + i) * c_clSize + tidxi];
+                sm_buf[2 * bufStride + tidxj * c_clSize + tidxi] +=
+                        sm_buf[2 * bufStride + (tidxj + i) * c_clSize + tidxi];
+            }
+            i >>= 1;
+            itemIdx.barrier(fence_space::local_space);
+        }
+
+        /* i == 1, last reduction step, writing to global mem */
+        /* Split the reduction between the first 3 line threads
+           Threads with line id 0 will do the reduction for (float3).x components
+           Threads with line id 1 will do the reduction for (float3).y components
+           Threads with line id 2 will do the reduction for (float3).z components. */
+        if (tidxj < 3)
+        {
+            const float f =
+                    sm_buf[tidxj * bufStride + tidxi] + sm_buf[tidxj * bufStride + c_clSize + tidxi];
+            atomicFetchAdd(a_f, 3 * aidx + tidxj, f);
+            if (calcFShift)
+            {
+                fShiftBuf += f;
+            }
+        }
+        itemIdx.barrier(fence_space::local_space);
+    }
+    /* add up local shift forces into global mem */
+    if (calcFShift)
+    {
+        /* Only threads with tidxj < 3 will update fshift.
+           The threads performing the update must be the same as the threads
+           storing the reduction result above. */
+        if (tidxj < 3)
+        {
+            atomicFetchAdd(a_fShift, 3 * shift + tidxj, fShiftBuf);
+        }
+    }
+}
+
+/*! \brief Main kernel for NBNXM.
+ *
+ */
+template<bool doPruneNBL, bool doCalcEnergies, enum ElecType elecType, enum VdwType vdwType>
+auto nbnxmKernel(cl::sycl::handler&                                   cgh,
+                 DeviceAccessor<Float4, mode::read>                   a_xq,
+                 DeviceAccessor<float, mode_atomic>                   a_f,
+                 DeviceAccessor<Float3, mode::read>                   a_shiftVec,
+                 DeviceAccessor<float, mode_atomic>                   a_fShift,
+                 OptionalAccessor<float, mode_atomic, doCalcEnergies> a_energyElec,
+                 OptionalAccessor<float, mode_atomic, doCalcEnergies> a_energyVdw,
+                 DeviceAccessor<nbnxn_cj4_t, doPruneNBL ? mode::read_write : mode::read> a_plistCJ4,
+                 DeviceAccessor<nbnxn_sci_t, mode::read>                                 a_plistSci,
+                 DeviceAccessor<nbnxn_excl_t, mode::read>                    a_plistExcl,
+                 OptionalAccessor<Float2, mode::read, ljComb<vdwType>>       a_ljComb,
+                 OptionalAccessor<int, mode::read, !ljComb<vdwType>>         a_atomTypes,
+                 OptionalAccessor<Float2, mode::read, !ljComb<vdwType>>      a_nbfp,
+                 OptionalAccessor<Float2, mode::read, ljEwald<vdwType>>      a_nbfpComb,
+                 OptionalAccessor<float, mode::read, elecEwaldTab<elecType>> a_coulombTab,
+                 const int                                                   numTypes,
+                 const float                                                 rCoulombSq,
+                 const float                                                 rVdwSq,
+                 const float                                                 twoKRf,
+                 const float                                                 ewaldBeta,
+                 const float                                                 rlistOuterSq,
+                 const float                                                 ewaldShift,
+                 const float                                                 epsFac,
+                 const float                                                 ewaldCoeffLJ,
+                 const float                                                 cRF,
+                 const shift_consts_t                                        dispersionShift,
+                 const shift_consts_t                                        repulsionShift,
+                 const switch_consts_t                                       vdwSwitch,
+                 const float                                                 rVdwSwitch,
+                 const float                                                 ljEwaldShift,
+                 const float                                                 coulombTabScale,
+                 const bool                                                  calcShift)
+{
+    static constexpr EnergyFunctionProperties<elecType, vdwType> props;
+
+    cgh.require(a_xq);
+    cgh.require(a_f);
+    cgh.require(a_shiftVec);
+    cgh.require(a_fShift);
+    if constexpr (doCalcEnergies)
+    {
+        cgh.require(a_energyElec);
+        cgh.require(a_energyVdw);
+    }
+    cgh.require(a_plistCJ4);
+    cgh.require(a_plistSci);
+    cgh.require(a_plistExcl);
+    if constexpr (!props.vdwComb)
+    {
+        cgh.require(a_atomTypes);
+        cgh.require(a_nbfp);
+    }
+    else
+    {
+        cgh.require(a_ljComb);
+    }
+    if constexpr (props.vdwEwald)
+    {
+        cgh.require(a_nbfpComb);
+    }
+    if constexpr (props.elecEwaldTab)
+    {
+        cgh.require(a_coulombTab);
+    }
+
+    // shmem buffer for i x+q pre-loading
+    cl::sycl::accessor<Float4, 2, mode::read_write, target::local> sm_xq(
+            cl::sycl::range<2>(c_nbnxnGpuNumClusterPerSupercluster, c_clSize), cgh);
+
+    // shmem buffer for force reduction
+    // SYCL-TODO: Make into 3D; section 4.7.6.11 of SYCL2020 specs
+    cl::sycl::accessor<float, 1, mode::read_write, target::local> sm_reductionBuffer(
+            cl::sycl::range<1>(c_clSize * c_clSize * DIM), cgh);
+
+    auto sm_atomTypeI = [&]() {
+        if constexpr (!props.vdwComb)
+        {
+            return cl::sycl::accessor<int, 2, mode::read_write, target::local>(
+                    cl::sycl::range<2>(c_nbnxnGpuNumClusterPerSupercluster, c_clSize), cgh);
+        }
+        else
+        {
+            return nullptr;
+        }
+    }();
+
+    auto sm_ljCombI = [&]() {
+        if constexpr (props.vdwComb)
+        {
+            return cl::sycl::accessor<Float2, 2, mode::read_write, target::local>(
+                    cl::sycl::range<2>(c_nbnxnGpuNumClusterPerSupercluster, c_clSize), cgh);
+        }
+        else
+        {
+            return nullptr;
+        }
+    }();
+
+    /* Flag to control the calculation of exclusion forces in the kernel
+     * We do that with Ewald (elec/vdw) and RF. Cut-off only has exclusion
+     * energy terms. */
+    constexpr bool doExclusionForces =
+            (props.elecEwald || props.elecRF || props.vdwEwald || (props.elecCutoff && doCalcEnergies));
+
+    // The post-prune j-i cluster-pair organization is linked to how exclusion and interaction mask data is stored.
+    // Currently this is ideally suited for 32-wide subgroup size but slightly less so for others,
+    // e.g. subGroupSize > prunedClusterPairSize on AMD GCN / CDNA.
+    // Hence, the two are decoupled.
+    constexpr int prunedClusterPairSize = c_clSize * c_splitClSize;
+#if defined(HIPSYCL_PLATFORM_ROCM) // SYCL-TODO AMD RDNA/RDNA2 has 32-wide exec; how can we check for that?
+    gmx_unused constexpr int subGroupSize = c_clSize * c_clSize;
+#else
+    gmx_unused constexpr int subGroupSize = prunedClusterPairSize;
+#endif
+
+    return [=](cl::sycl::nd_item<1> itemIdx) [[intel::reqd_sub_group_size(subGroupSize)]]
+    {
+        /* thread/block/warp id-s */
+        const cl::sycl::id<3> localId = unflattenId<c_clSize, c_clSize>(itemIdx.get_local_id());
+        const unsigned        tidxi   = localId[0];
+        const unsigned        tidxj   = localId[1];
+        const unsigned        tidx    = tidxj * c_clSize + tidxi;
+        const unsigned        tidxz   = 0;
+
+        // Group indexing was flat originally, no need to unflatten it.
+        const unsigned bidx = itemIdx.get_group(0);
+
+        const sycl_2020::sub_group sg = itemIdx.get_sub_group();
+        // Could use sg.get_group_range to compute the imask & exclusion Idx, but too much of the logic relies on it anyway
+        // and in cases where prunedClusterPairSize != subGroupSize we can't use it anyway
+        const unsigned imeiIdx = tidx / prunedClusterPairSize;
+
+        Float3 fCiBuf[c_nbnxnGpuNumClusterPerSupercluster]; // i force buffer
+        for (int i = 0; i < c_nbnxnGpuNumClusterPerSupercluster; i++)
+        {
+            fCiBuf[i] = Float3(0.0F, 0.0F, 0.0F);
+        }
+
+        const nbnxn_sci_t nbSci     = a_plistSci[bidx];
+        const int         sci       = nbSci.sci;
+        const int         cij4Start = nbSci.cj4_ind_start;
+        const int         cij4End   = nbSci.cj4_ind_end;
+
+        // Only needed if props.elecEwaldAna
+        const float beta2 = ewaldBeta * ewaldBeta;
+        const float beta3 = ewaldBeta * ewaldBeta * ewaldBeta;
+
+        for (int i = 0; i < c_nbnxnGpuNumClusterPerSupercluster; i += c_clSize)
+        {
+            /* Pre-load i-atom x and q into shared memory */
+            const int             ci       = sci * c_nbnxnGpuNumClusterPerSupercluster + tidxj + i;
+            const int             ai       = ci * c_clSize + tidxi;
+            const cl::sycl::id<2> cacheIdx = cl::sycl::id<2>(tidxj + i, tidxi);
+
+            const Float3 shift = a_shiftVec[nbSci.shift];
+            Float4       xqi   = a_xq[ai];
+            xqi += Float4(shift[0], shift[1], shift[2], 0.0F);
+            xqi[3] *= epsFac;
+            sm_xq[cacheIdx] = xqi;
+
+            if constexpr (!props.vdwComb)
+            {
+                // Pre-load the i-atom types into shared memory
+                sm_atomTypeI[cacheIdx] = a_atomTypes[ai];
+            }
+            else
+            {
+                // Pre-load the LJ combination parameters into shared memory
+                sm_ljCombI[cacheIdx] = a_ljComb[ai];
+            }
+        }
+        itemIdx.barrier(fence_space::local_space);
+
+        float ewaldCoeffLJ_2, ewaldCoeffLJ_6_6; // Only needed if (props.vdwEwald)
+        if constexpr (props.vdwEwald)
+        {
+            ewaldCoeffLJ_2   = ewaldCoeffLJ * ewaldCoeffLJ;
+            ewaldCoeffLJ_6_6 = ewaldCoeffLJ_2 * ewaldCoeffLJ_2 * ewaldCoeffLJ_2 * c_oneSixth;
+        }
+
+        float energyVdw, energyElec; // Only needed if (doCalcEnergies)
+        if constexpr (doCalcEnergies)
+        {
+            energyVdw = energyElec = 0.0F;
+        }
+        if constexpr (doCalcEnergies && doExclusionForces)
+        {
+            if (nbSci.shift == gmx::c_centralShiftIndex
+                && a_plistCJ4[cij4Start].cj[0] == sci * c_nbnxnGpuNumClusterPerSupercluster)
+            {
+                // we have the diagonal: add the charge and LJ self interaction energy term
+                for (int i = 0; i < c_nbnxnGpuNumClusterPerSupercluster; i++)
+                {
+                    // TODO: Are there other options?
+                    if constexpr (props.elecEwald || props.elecRF || props.elecCutoff)
+                    {
+                        const float qi = sm_xq[i][tidxi][3];
+                        energyElec += qi * qi;
+                    }
+                    if constexpr (props.vdwEwald)
+                    {
+                        energyVdw +=
+                                a_nbfp[a_atomTypes[(sci * c_nbnxnGpuNumClusterPerSupercluster + i) * c_clSize + tidxi]
+                                       * (numTypes + 1)][0];
+                    }
+                }
+                /* divide the self term(s) equally over the j-threads, then multiply with the coefficients. */
+                if constexpr (props.vdwEwald)
+                {
+                    energyVdw /= c_clSize;
+                    energyVdw *= 0.5F * c_oneSixth * ewaldCoeffLJ_6_6; // c_OneTwelfth?
+                }
+                if constexpr (props.elecRF || props.elecCutoff)
+                {
+                    // Correct for epsfac^2 due to adding qi^2 */
+                    energyElec /= epsFac * c_clSize;
+                    energyElec *= -0.5F * cRF;
+                }
+                if constexpr (props.elecEwald)
+                {
+                    // Correct for epsfac^2 due to adding qi^2 */
+                    energyElec /= epsFac * c_clSize;
+                    energyElec *= -ewaldBeta * c_OneOverSqrtPi; /* last factor 1/sqrt(pi) */
+                }
+            } // (nbSci.shift == gmx::c_centralShiftIndex && a_plistCJ4[cij4Start].cj[0] == sci * c_nbnxnGpuNumClusterPerSupercluster)
+        }     // (doCalcEnergies && doExclusionForces)
+
+        // Only needed if (doExclusionForces)
+        const bool nonSelfInteraction = !(nbSci.shift == gmx::c_centralShiftIndex & tidxj <= tidxi);
+
+        // loop over the j clusters = seen by any of the atoms in the current super-cluster
+        for (int j4 = cij4Start + tidxz; j4 < cij4End; j4 += 1)
+        {
+            unsigned imask = a_plistCJ4[j4].imei[imeiIdx].imask;
+            if (!doPruneNBL && !imask)
+            {
+                continue;
+            }
+            const int wexclIdx = a_plistCJ4[j4].imei[imeiIdx].excl_ind;
+            static_assert(gmx::isPowerOfTwo(prunedClusterPairSize));
+            const unsigned wexcl = a_plistExcl[wexclIdx].pair[tidx & (prunedClusterPairSize - 1)];
+            for (int jm = 0; jm < c_nbnxnGpuJgroupSize; jm++)
+            {
+                const bool maskSet =
+                        imask & (superClInteractionMask << (jm * c_nbnxnGpuNumClusterPerSupercluster));
+                if (!maskSet)
+                {
+                    continue;
+                }
+                unsigned  maskJI = (1U << (jm * c_nbnxnGpuNumClusterPerSupercluster));
+                const int cj     = a_plistCJ4[j4].cj[jm];
+                const int aj     = cj * c_clSize + tidxj;
+
+                // load j atom data
+                const Float4 xqj = a_xq[aj];
+
+                const Float3 xj(xqj[0], xqj[1], xqj[2]);
+                const float  qj = xqj[3];
+                int          atomTypeJ; // Only needed if (!props.vdwComb)
+                Float2       ljCombJ;   // Only needed if (props.vdwComb)
+                if constexpr (props.vdwComb)
+                {
+                    ljCombJ = a_ljComb[aj];
+                }
+                else
+                {
+                    atomTypeJ = a_atomTypes[aj];
+                }
+
+                Float3 fCjBuf(0.0F, 0.0F, 0.0F);
+
+                for (int i = 0; i < c_nbnxnGpuNumClusterPerSupercluster; i++)
+                {
+                    if (imask & maskJI)
+                    {
+                        // i cluster index
+                        const int ci = sci * c_nbnxnGpuNumClusterPerSupercluster + i;
+                        // all threads load an atom from i cluster ci into shmem!
+                        const Float4 xqi = sm_xq[i][tidxi];
+                        const Float3 xi(xqi[0], xqi[1], xqi[2]);
+
+                        // distance between i and j atoms
+                        const Float3 rv = xi - xj;
+                        float        r2 = norm2(rv);
+
+                        if constexpr (doPruneNBL)
+                        {
+                            /* If _none_ of the atoms pairs are in cutoff range,
+                             * the bit corresponding to the current
+                             * cluster-pair in imask gets set to 0. */
+                            if (!sycl_2020::group_any_of(sg, r2 < rlistOuterSq))
+                            {
+                                imask &= ~maskJI;
+                            }
+                        }
+                        const float pairExclMask = (wexcl & maskJI) ? 1.0F : 0.0F;
+
+                        // cutoff & exclusion check
+
+                        const bool notExcluded = doExclusionForces ? (nonSelfInteraction | (ci != cj))
+                                                                   : (wexcl & maskJI);
+
+                        // SYCL-TODO: Check optimal way of branching here.
+                        if ((r2 < rCoulombSq) && notExcluded)
+                        {
+                            const float qi = xqi[3];
+                            int         atomTypeI; // Only needed if (!props.vdwComb)
+                            float       sigma, epsilon;
+                            Float2      c6c12;
+
+                            if constexpr (!props.vdwComb)
+                            {
+                                /* LJ 6*C6 and 12*C12 */
+                                atomTypeI = sm_atomTypeI[i][tidxi];
+                                c6c12     = a_nbfp[numTypes * atomTypeI + atomTypeJ];
+                            }
+                            else
+                            {
+                                const Float2 ljCombI = sm_ljCombI[i][tidxi];
+                                if constexpr (props.vdwCombGeom)
+                                {
+                                    c6c12 = Float2(ljCombI[0] * ljCombJ[0], ljCombI[1] * ljCombJ[1]);
+                                }
+                                else
+                                {
+                                    static_assert(props.vdwCombLB);
+                                    // LJ 2^(1/6)*sigma and 12*epsilon
+                                    sigma   = ljCombI[0] + ljCombJ[0];
+                                    epsilon = ljCombI[1] * ljCombJ[1];
+                                    if constexpr (doCalcEnergies)
+                                    {
+                                        c6c12 = convertSigmaEpsilonToC6C12(sigma, epsilon);
+                                    }
+                                } // props.vdwCombGeom
+                            }     // !props.vdwComb
+
+                            // c6 and c12 are unused and garbage iff props.vdwCombLB && !doCalcEnergies
+                            const float c6  = c6c12[0];
+                            const float c12 = c6c12[1];
+
+                            // Ensure distance do not become so small that r^-12 overflows
+                            r2 = std::max(r2, c_nbnxnMinDistanceSquared);
+#if GMX_SYCL_HIPSYCL
+                            // No fast/native functions in some compilation passes
+                            const float rInv = cl::sycl::rsqrt(r2);
+#else
+                            // SYCL-TODO: sycl::half_precision::rsqrt?
+                            const float rInv = cl::sycl::native::rsqrt(r2);
+#endif
+                            const float r2Inv = rInv * rInv;
+                            float       r6Inv, fInvR, energyLJPair;
+                            if constexpr (!props.vdwCombLB || doCalcEnergies)
+                            {
+                                r6Inv = r2Inv * r2Inv * r2Inv;
+                                if constexpr (doExclusionForces)
+                                {
+                                    // SYCL-TODO: Check if true for SYCL
+                                    /* We could mask r2Inv, but with Ewald masking both
+                                     * r6Inv and fInvR is faster */
+                                    r6Inv *= pairExclMask;
+                                }
+                                fInvR = r6Inv * (c12 * r6Inv - c6) * r2Inv;
+                            }
+                            else
+                            {
+                                float sig_r  = sigma * rInv;
+                                float sig_r2 = sig_r * sig_r;
+                                float sig_r6 = sig_r2 * sig_r2 * sig_r2;
+                                if constexpr (doExclusionForces)
+                                {
+                                    sig_r6 *= pairExclMask;
+                                }
+                                fInvR = epsilon * sig_r6 * (sig_r6 - 1.0F) * r2Inv;
+                            } // (!props.vdwCombLB || doCalcEnergies)
+                            if constexpr (doCalcEnergies || props.vdwPSwitch)
+                            {
+                                energyLJPair = pairExclMask
+                                               * (c12 * (r6Inv * r6Inv + repulsionShift.cpot) * c_oneTwelfth
+                                                  - c6 * (r6Inv + dispersionShift.cpot) * c_oneSixth);
+                            }
+                            if constexpr (props.vdwFSwitch)
+                            {
+                                ljForceSwitch<doCalcEnergies>(
+                                        dispersionShift, repulsionShift, rVdwSwitch, c6, c12, rInv, r2, &fInvR, &energyLJPair);
+                            }
+                            if constexpr (props.vdwEwald)
+                            {
+                                ljEwaldComb<doCalcEnergies, vdwType>(a_nbfpComb,
+                                                                     ljEwaldShift,
+                                                                     atomTypeI,
+                                                                     atomTypeJ,
+                                                                     r2,
+                                                                     r2Inv,
+                                                                     ewaldCoeffLJ_2,
+                                                                     ewaldCoeffLJ_6_6,
+                                                                     pairExclMask,
+                                                                     &fInvR,
+                                                                     &energyLJPair);
+                            } // (props.vdwEwald)
+                            if constexpr (props.vdwPSwitch)
+                            {
+                                ljPotentialSwitch<doCalcEnergies>(
+                                        vdwSwitch, rVdwSwitch, rInv, r2, &fInvR, &energyLJPair);
+                            }
+                            if constexpr (props.elecEwaldTwin)
+                            {
+                                // Separate VDW cut-off check to enable twin-range cut-offs
+                                // (rVdw < rCoulomb <= rList)
+                                const float vdwInRange = (r2 < rVdwSq) ? 1.0F : 0.0F;
+                                fInvR *= vdwInRange;
+                                if constexpr (doCalcEnergies)
+                                {
+                                    energyLJPair *= vdwInRange;
+                                }
+                            }
+                            if constexpr (doCalcEnergies)
+                            {
+                                energyVdw += energyLJPair;
+                            }
+
+                            if constexpr (props.elecCutoff)
+                            {
+                                if constexpr (doExclusionForces)
+                                {
+                                    fInvR += qi * qj * pairExclMask * r2Inv * rInv;
+                                }
+                                else
+                                {
+                                    fInvR += qi * qj * r2Inv * rInv;
+                                }
+                            }
+                            if constexpr (props.elecRF)
+                            {
+                                fInvR += qi * qj * (pairExclMask * r2Inv * rInv - twoKRf);
+                            }
+                            if constexpr (props.elecEwaldAna)
+                            {
+                                fInvR += qi * qj
+                                         * (pairExclMask * r2Inv * rInv + pmeCorrF(beta2 * r2) * beta3);
+                            }
+                            if constexpr (props.elecEwaldTab)
+                            {
+                                fInvR += qi * qj
+                                         * (pairExclMask * r2Inv
+                                            - interpolateCoulombForceR(
+                                                      a_coulombTab, coulombTabScale, r2 * rInv))
+                                         * rInv;
+                            }
+
+                            if constexpr (doCalcEnergies)
+                            {
+                                if constexpr (props.elecCutoff)
+                                {
+                                    energyElec += qi * qj * (pairExclMask * rInv - cRF);
+                                }
+                                if constexpr (props.elecRF)
+                                {
+                                    energyElec +=
+                                            qi * qj * (pairExclMask * rInv + 0.5f * twoKRf * r2 - cRF);
+                                }
+                                if constexpr (props.elecEwald)
+                                {
+                                    energyElec +=
+                                            qi * qj
+                                            * (rInv * (pairExclMask - cl::sycl::erf(r2 * rInv * ewaldBeta))
+                                               - pairExclMask * ewaldShift);
+                                }
+                            }
+
+                            const Float3 forceIJ = rv * fInvR;
+
+                            /* accumulate j forces in registers */
+                            fCjBuf -= forceIJ;
+                            /* accumulate i forces in registers */
+                            fCiBuf[i] += forceIJ;
+                        } // (r2 < rCoulombSq) && notExcluded
+                    }     // (imask & maskJI)
+                    /* shift the mask bit by 1 */
+                    maskJI += maskJI;
+                } // for (int i = 0; i < c_nbnxnGpuNumClusterPerSupercluster; i++)
+                /* reduce j forces */
+                reduceForceJShuffle(fCjBuf, itemIdx, tidxi, aj, a_f);
+            } // for (int jm = 0; jm < c_nbnxnGpuJgroupSize; jm++)
+            if constexpr (doPruneNBL)
+            {
+                /* Update the imask with the new one which does not contain the
+                 * out of range clusters anymore. */
+                a_plistCJ4[j4].imei[imeiIdx].imask = imask;
+            }
+        } // for (int j4 = cij4Start; j4 < cij4End; j4 += 1)
+
+        /* skip central shifts when summing shift forces */
+        const bool doCalcShift = (calcShift && !(nbSci.shift == gmx::c_centralShiftIndex));
+
+        reduceForceIAndFShift(
+                sm_reductionBuffer, fCiBuf, doCalcShift, itemIdx, tidxi, tidxj, sci, nbSci.shift, a_f, a_fShift);
+
+        if constexpr (doCalcEnergies)
+        {
+            const float energyVdwGroup = sycl_2020::group_reduce(
+                    itemIdx.get_group(), energyVdw, 0.0F, sycl_2020::plus<float>());
+            const float energyElecGroup = sycl_2020::group_reduce(
+                    itemIdx.get_group(), energyElec, 0.0F, sycl_2020::plus<float>());
+
+            if (tidx == 0)
+            {
+                atomicFetchAdd(a_energyVdw, 0, energyVdwGroup);
+                atomicFetchAdd(a_energyElec, 0, energyElecGroup);
+            }
+        }
+    };
+}
+
+// SYCL 1.2.1 requires providing a unique type for a kernel. Should not be needed for SYCL2020.
+template<bool doPruneNBL, bool doCalcEnergies, enum ElecType elecType, enum VdwType vdwType>
+class NbnxmKernelName;
+
+template<bool doPruneNBL, bool doCalcEnergies, enum ElecType elecType, enum VdwType vdwType, class... Args>
+cl::sycl::event launchNbnxmKernel(const DeviceStream& deviceStream, const int numSci, Args&&... args)
+{
+    // Should not be needed for SYCL2020.
+    using kernelNameType = NbnxmKernelName<doPruneNBL, doCalcEnergies, elecType, vdwType>;
+
+    /* Kernel launch config:
+     * - The thread block dimensions match the size of i-clusters, j-clusters,
+     *   and j-cluster concurrency, in x, y, and z, respectively.
+     * - The 1D block-grid contains as many blocks as super-clusters.
+     */
+    const int                   numBlocks = numSci;
+    const cl::sycl::range<3>    blockSize{ c_clSize, c_clSize, 1 };
+    const cl::sycl::range<3>    globalSize{ numBlocks * blockSize[0], blockSize[1], blockSize[2] };
+    const cl::sycl::nd_range<3> range{ globalSize, blockSize };
+
+    cl::sycl::queue q = deviceStream.stream();
+
+    cl::sycl::event e = q.submit([&](cl::sycl::handler& cgh) {
+        auto kernel = nbnxmKernel<doPruneNBL, doCalcEnergies, elecType, vdwType>(
+                cgh, std::forward<Args>(args)...);
+        cgh.parallel_for<kernelNameType>(flattenNDRange(range), kernel);
+    });
+
+    return e;
+}
+
+template<class... Args>
+cl::sycl::event chooseAndLaunchNbnxmKernel(bool          doPruneNBL,
+                                           bool          doCalcEnergies,
+                                           enum ElecType elecType,
+                                           enum VdwType  vdwType,
+                                           Args&&... args)
+{
+    return gmx::dispatchTemplatedFunction(
+            [&](auto doPruneNBL_, auto doCalcEnergies_, auto elecType_, auto vdwType_) {
+                return launchNbnxmKernel<doPruneNBL_, doCalcEnergies_, elecType_, vdwType_>(
+                        std::forward<Args>(args)...);
+            },
+            doPruneNBL,
+            doCalcEnergies,
+            elecType,
+            vdwType);
+}
+
+void launchNbnxmKernel(NbnxmGpu* nb, const gmx::StepWorkload& stepWork, const InteractionLocality iloc)
+{
+    NBAtomDataGpu*      adat         = nb->atdat;
+    NBParamGpu*         nbp          = nb->nbparam;
+    gpu_plist*          plist        = nb->plist[iloc];
+    const bool          doPruneNBL   = (plist->haveFreshList && !nb->didPrune[iloc]);
+    const DeviceStream& deviceStream = *nb->deviceStreams[iloc];
+
+    // Casting to float simplifies using atomic ops in the kernel
+    cl::sycl::buffer<Float3, 1> f(*adat->f.buffer_);
+    auto                        fAsFloat = f.reinterpret<float, 1>(f.get_count() * DIM);
+    cl::sycl::buffer<Float3, 1> fShift(*adat->fShift.buffer_);
+    auto fShiftAsFloat = fShift.reinterpret<float, 1>(fShift.get_count() * DIM);
+
+    cl::sycl::event e = chooseAndLaunchNbnxmKernel(doPruneNBL,
+                                                   stepWork.computeEnergy,
+                                                   nbp->elecType,
+                                                   nbp->vdwType,
+                                                   deviceStream,
+                                                   plist->nsci,
+                                                   adat->xq,
+                                                   fAsFloat,
+                                                   adat->shiftVec,
+                                                   fShiftAsFloat,
+                                                   adat->eElec,
+                                                   adat->eLJ,
+                                                   plist->cj4,
+                                                   plist->sci,
+                                                   plist->excl,
+                                                   adat->ljComb,
+                                                   adat->atomTypes,
+                                                   nbp->nbfp,
+                                                   nbp->nbfp_comb,
+                                                   nbp->coulomb_tab,
+                                                   adat->numTypes,
+                                                   nbp->rcoulomb_sq,
+                                                   nbp->rvdw_sq,
+                                                   nbp->two_k_rf,
+                                                   nbp->ewald_beta,
+                                                   nbp->rlistOuter_sq,
+                                                   nbp->sh_ewald,
+                                                   nbp->epsfac,
+                                                   nbp->ewaldcoeff_lj,
+                                                   nbp->c_rf,
+                                                   nbp->dispersion_shift,
+                                                   nbp->repulsion_shift,
+                                                   nbp->vdw_switch,
+                                                   nbp->rvdw_switch,
+                                                   nbp->sh_lj_ewald,
+                                                   nbp->coulomb_tab_scale,
+                                                   stepWork.computeVirial);
+}
+
+} // namespace Nbnxm
similarity index 74%
rename from src/gromacs/utility/mutex.h
rename to src/gromacs/nbnxm/sycl/nbnxm_sycl_kernel.h
index 34c7375f223d96e588633e3118cbec3a8050f247..dd7f52138d9c2c850b2254577b6b7054ef313aa5 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) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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
+/*! \internal \file
  * \brief
- * Declares C++11-style basic threading primitives
- * (gmx::Mutex, gmx::lock_guard).
+ * Declares nbnxn sycl helper functions
  *
- * For now, the implementation is imported from thread-MPI.
- *
- * \author Teemu Murtola <teemu.murtola@gmail.com>
- * \inlibraryapi
- * \ingroup module_utility
+ * \ingroup module_nbnxm
  */
-#ifndef GMX_THREADING_MUTEX_H
-#define GMX_THREADING_MUTEX_H
-
-#include "thread_mpi/mutex.h"
+#ifndef GMX_NBNXM_SYCL_NBNXM_SYCL_KERNEL_H
+#define GMX_NBNXM_SYCL_NBNXM_SYCL_KERNEL_H
 
+// Forward declarations
 namespace gmx
 {
+enum class InteractionLocality;
+class StepWorkload;
+} // namespace gmx
+struct NbnxmGpu;
 
-//! \cond libapi
-/*! \libinternal \brief
- * C++11-compatible basic mutex.
- */
-typedef tMPI::mutex Mutex;
-//! \endcond
-using tMPI::lock_guard;
+namespace Nbnxm
+{
+using gmx::InteractionLocality;
 
-} // namespace gmx
+void launchNbnxmKernel(NbnxmGpu* nb, const gmx::StepWorkload& stepWork, const InteractionLocality iloc);
+
+} // namespace Nbnxm
 
-#endif
+#endif // GMX_NBNXM_SYCL_NBNXM_SYCL_KERNEL_H
diff --git a/src/gromacs/nbnxm/sycl/nbnxm_sycl_kernel_pruneonly.cpp b/src/gromacs/nbnxm/sycl/nbnxm_sycl_kernel_pruneonly.cpp
new file mode 100644 (file)
index 0000000..a2cc1f8
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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
+ *  NBNXM SYCL kernels
+ *
+ *  \ingroup module_nbnxm
+ */
+#include "gmxpre.h"
+
+#include "nbnxm_sycl_kernel_pruneonly.h"
+
+#include "gromacs/gpu_utils/devicebuffer.h"
+#include "gromacs/gpu_utils/gmxsycl.h"
+#include "gromacs/utility/template_mp.h"
+
+#include "nbnxm_sycl_kernel_utils.h"
+#include "nbnxm_sycl_types.h"
+
+using cl::sycl::access::fence_space;
+using cl::sycl::access::mode;
+using cl::sycl::access::target;
+
+namespace Nbnxm
+{
+
+/*! \brief Prune-only kernel for NBNXM.
+ *
+ */
+template<bool haveFreshList>
+auto nbnxmKernelPruneOnly(cl::sycl::handler&                            cgh,
+                          DeviceAccessor<Float4, mode::read>            a_xq,
+                          DeviceAccessor<Float3, mode::read>            a_shiftVec,
+                          DeviceAccessor<nbnxn_cj4_t, mode::read_write> a_plistCJ4,
+                          DeviceAccessor<nbnxn_sci_t, mode::read>       a_plistSci,
+                          DeviceAccessor<unsigned int, haveFreshList ? mode::write : mode::read> a_plistIMask,
+                          const float rlistOuterSq,
+                          const float rlistInnerSq,
+                          const int   numParts,
+                          const int   part)
+{
+    cgh.require(a_xq);
+    cgh.require(a_shiftVec);
+    cgh.require(a_plistCJ4);
+    cgh.require(a_plistSci);
+    cgh.require(a_plistIMask);
+
+    /* shmem buffer for i x+q pre-loading */
+    cl::sycl::accessor<Float4, 2, mode::read_write, target::local> sm_xq(
+            cl::sycl::range<2>(c_nbnxnGpuNumClusterPerSupercluster, c_clSize), cgh);
+
+    constexpr int warpSize = c_clSize * c_clSize / 2;
+
+    /* Somewhat weird behavior inherited from OpenCL.
+     * With clSize == 4, we use sub_group size of 16 (not enforced in OpenCL implementation, but chosen
+     * by the IGC compiler), however for data layout we consider it to be 8.
+     * Setting sub_group size to 8 slows down the prune-only kernel 1.5-2 times.
+     * For clSize == But we need to set specific sub_group size >= 32 for clSize == 8 for correctness,
+     * but it causes very poor performance.
+     */
+    constexpr int gmx_unused requiredSubGroupSize = (c_clSize == 4) ? 16 : warpSize;
+
+    /* Requirements:
+     * Work group (block) must have range (c_clSize, c_clSize, ...) (for localId calculation, easy
+     * to change). */
+    return [=](cl::sycl::nd_item<1> itemIdx) [[intel::reqd_sub_group_size(requiredSubGroupSize)]]
+    {
+        const cl::sycl::id<3> localId = unflattenId<c_clSize, c_clSize>(itemIdx.get_local_id());
+        // thread/block/warp id-s
+        const unsigned tidxi = localId[0];
+        const unsigned tidxj = localId[1];
+        const int      tidx  = tidxj * c_clSize + tidxi;
+        const unsigned tidxz = localId[2];
+        const unsigned bidx  = itemIdx.get_group(0);
+
+        const sycl_2020::sub_group sg   = itemIdx.get_sub_group();
+        const unsigned             widx = tidx / warpSize;
+
+        // my i super-cluster's index = sciOffset + current bidx * numParts + part
+        const nbnxn_sci_t nbSci     = a_plistSci[bidx * numParts + part];
+        const int         sci       = nbSci.sci;           /* super-cluster */
+        const int         cij4Start = nbSci.cj4_ind_start; /* first ...*/
+        const int         cij4End   = nbSci.cj4_ind_end;   /* and last index of j clusters */
+
+        if (tidxz == 0)
+        {
+            for (int i = 0; i < c_nbnxnGpuNumClusterPerSupercluster; i += c_clSize)
+            {
+                /* Pre-load i-atom x and q into shared memory */
+                const int ci = sci * c_nbnxnGpuNumClusterPerSupercluster + tidxj + i;
+                const int ai = ci * c_clSize + tidxi;
+
+                /* We don't need q, but using float4 in shmem avoids bank conflicts.
+                   (but it also wastes L2 bandwidth). */
+                const Float4 xq    = a_xq[ai];
+                const Float3 shift = a_shiftVec[nbSci.shift];
+                const Float4 xi(xq[0] + shift[0], xq[1] + shift[1], xq[2] + shift[2], xq[3]);
+                sm_xq[tidxj + i][tidxi] = xi;
+            }
+        }
+        itemIdx.barrier(fence_space::local_space);
+
+        /* loop over the j clusters = seen by any of the atoms in the current super-cluster.
+         * The loop stride c_syclPruneKernelJ4Concurrency ensures that consecutive warps-pairs are
+         * assigned consecutive j4's entries. */
+        for (int j4 = cij4Start + tidxz; j4 < cij4End; j4 += c_syclPruneKernelJ4Concurrency)
+        {
+            unsigned imaskFull, imaskCheck, imaskNew;
+
+            if constexpr (haveFreshList)
+            {
+                /* Read the mask from the list transferred from the CPU */
+                imaskFull = a_plistCJ4[j4].imei[widx].imask;
+                /* We attempt to prune all pairs present in the original list */
+                imaskCheck = imaskFull;
+                imaskNew   = 0;
+            }
+            else
+            {
+                /* Read the mask from the "warp-pruned" by rlistOuter mask array */
+                imaskFull = a_plistIMask[j4 * c_nbnxnGpuClusterpairSplit + widx];
+                /* Read the old rolling pruned mask, use as a base for new */
+                imaskNew = a_plistCJ4[j4].imei[widx].imask;
+                /* We only need to check pairs with different mask */
+                imaskCheck = (imaskNew ^ imaskFull);
+            }
+
+            if (imaskCheck)
+            {
+                for (int jm = 0; jm < c_nbnxnGpuJgroupSize; jm++)
+                {
+                    if (imaskCheck & (superClInteractionMask << (jm * c_nbnxnGpuNumClusterPerSupercluster)))
+                    {
+                        unsigned mask_ji = (1U << (jm * c_nbnxnGpuNumClusterPerSupercluster));
+                        // SYCL-TODO: Reevaluate prefetching methods
+                        const int cj = a_plistCJ4[j4].cj[jm];
+                        const int aj = cj * c_clSize + tidxj;
+
+                        /* load j atom data */
+                        const Float4 tmp = a_xq[aj];
+                        const Float3 xj(tmp[0], tmp[1], tmp[2]);
+
+                        for (int i = 0; i < c_nbnxnGpuNumClusterPerSupercluster; i++)
+                        {
+                            if (imaskCheck & mask_ji)
+                            {
+                                // load i-cluster coordinates from shmem
+                                const Float4 xi = sm_xq[i][tidxi];
+                                // distance between i and j atoms
+                                Float3 rv(xi[0], xi[1], xi[2]);
+                                rv -= xj;
+                                const float r2 = norm2(rv);
+
+                                /* If _none_ of the atoms pairs are in rlistOuter
+                                 * range, the bit corresponding to the current
+                                 * cluster-pair in imask gets set to 0. */
+                                if (haveFreshList && !(sycl_2020::group_any_of(sg, r2 < rlistOuterSq)))
+                                {
+                                    imaskFull &= ~mask_ji;
+                                }
+                                /* If any atom pair is within range, set the bit
+                                 * corresponding to the current cluster-pair. */
+                                if (sycl_2020::group_any_of(sg, r2 < rlistInnerSq))
+                                {
+                                    imaskNew |= mask_ji;
+                                }
+                            } // (imaskCheck & mask_ji)
+                            /* shift the mask bit by 1 */
+                            mask_ji += mask_ji;
+                        } // (int i = 0; i < c_nbnxnGpuNumClusterPerSupercluster; i++)
+                    } // (imaskCheck & (superClInteractionMask << (jm * c_nbnxnGpuNumClusterPerSupercluster)))
+                } // for (int jm = 0; jm < c_nbnxnGpuJgroupSize; jm++)
+
+                if constexpr (haveFreshList)
+                {
+                    /* copy the list pruned to rlistOuter to a separate buffer */
+                    a_plistIMask[j4 * c_nbnxnGpuClusterpairSplit + widx] = imaskFull;
+                }
+                /* update the imask with only the pairs up to rlistInner */
+                a_plistCJ4[j4].imei[widx].imask = imaskNew;
+            } // (imaskCheck)
+        } // for (int j4 = cij4_start + tidxz; j4 < cij4_end; j4 += c_syclPruneKernelJ4Concurrency)
+    };
+}
+
+// SYCL 1.2.1 requires providing a unique type for a kernel. Should not be needed for SYCL2020.
+template<bool haveFreshList>
+class NbnxmKernelPruneOnlyName;
+
+template<bool haveFreshList, class... Args>
+cl::sycl::event launchNbnxmKernelPruneOnly(const DeviceStream& deviceStream,
+                                           const int           numSciInPart,
+                                           Args&&... args)
+{
+    // Should not be needed for SYCL2020.
+    using kernelNameType = NbnxmKernelPruneOnlyName<haveFreshList>;
+
+    /* Kernel launch config:
+     * - The thread block dimensions match the size of i-clusters, j-clusters,
+     *   and j-cluster concurrency, in x, y, and z, respectively.
+     * - The 1D block-grid contains as many blocks as super-clusters.
+     */
+    const unsigned long         numBlocks = numSciInPart;
+    const cl::sycl::range<3>    blockSize{ c_clSize, c_clSize, c_syclPruneKernelJ4Concurrency };
+    const cl::sycl::range<3>    globalSize{ numBlocks * blockSize[0], blockSize[1], blockSize[2] };
+    const cl::sycl::nd_range<3> range{ globalSize, blockSize };
+
+    cl::sycl::queue q = deviceStream.stream();
+
+    cl::sycl::event e = q.submit([&](cl::sycl::handler& cgh) {
+        auto kernel = nbnxmKernelPruneOnly<haveFreshList>(cgh, std::forward<Args>(args)...);
+        cgh.parallel_for<kernelNameType>(flattenNDRange(range), kernel);
+    });
+
+    return e;
+}
+
+template<class... Args>
+cl::sycl::event chooseAndLaunchNbnxmKernelPruneOnly(bool haveFreshList, Args&&... args)
+{
+    return gmx::dispatchTemplatedFunction(
+            [&](auto haveFreshList_) {
+                return launchNbnxmKernelPruneOnly<haveFreshList_>(std::forward<Args>(args)...);
+            },
+            haveFreshList);
+}
+
+void launchNbnxmKernelPruneOnly(NbnxmGpu*                 nb,
+                                const InteractionLocality iloc,
+                                const int                 numParts,
+                                const int                 part,
+                                const int                 numSciInPart)
+{
+    NBAtomDataGpu*      adat          = nb->atdat;
+    NBParamGpu*         nbp           = nb->nbparam;
+    gpu_plist*          plist         = nb->plist[iloc];
+    const bool          haveFreshList = plist->haveFreshList;
+    const DeviceStream& deviceStream  = *nb->deviceStreams[iloc];
+
+    cl::sycl::event e = chooseAndLaunchNbnxmKernelPruneOnly(haveFreshList,
+                                                            deviceStream,
+                                                            numSciInPart,
+                                                            adat->xq,
+                                                            adat->shiftVec,
+                                                            plist->cj4,
+                                                            plist->sci,
+                                                            plist->imask,
+                                                            nbp->rlistOuter_sq,
+                                                            nbp->rlistInner_sq,
+                                                            numParts,
+                                                            part);
+}
+
+} // namespace Nbnxm
similarity index 67%
rename from src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_general.h
rename to src/gromacs/nbnxm/sycl/nbnxm_sycl_kernel_pruneonly.h
index d93c8086e807c249ce558bb3eccf6462ba4bb702..6af97b1d1ed190f803a3ee1f53c6c7a91db6a255 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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.
  */
+/*! \internal \file
+ * \brief
+ * Declares nbnxn sycl helper functions
+ *
+ * \ingroup module_nbnxm
+ */
+#ifndef GMX_NBNXM_SYCL_NBNXM_SYCL_KERNEL_PRUNEONLY_H
+#define GMX_NBNXM_SYCL_NBNXM_SYCL_KERNEL_PRUNEONLY_H
 
-#ifndef GMX_SIMD_IMPLEMENTATION_IBM_VMX_GENERAL_H
-#define GMX_SIMD_IMPLEMENTATION_IBM_VMX_GENERAL_H
-
+// Forward declarations
 namespace gmx
 {
+enum class InteractionLocality;
+}
+struct NbnxmGpu;
 
-static inline void simdPrefetch(const void* m)
+namespace Nbnxm
 {
-#if defined(__ibmxl__) || defined(__xlC__)
-    __dcbt(m);
-#elif defined __GNUC__
-    __builtin_prefetch(m);
-#endif
-}
+using gmx::InteractionLocality;
+
+void launchNbnxmKernelPruneOnly(NbnxmGpu*                 nb,
+                                const InteractionLocality iloc,
+                                const int                 numParts,
+                                const int                 part,
+                                const int                 numSciInPart);
 
-} // namespace gmx
+} // namespace Nbnxm
 
-#endif // GMX_SIMD_IMPLEMENTATION_IBM_VMX_GENERAL_H
+#endif // GMX_NBNXM_SYCL_NBNXM_SYCL_KERNEL_PRUNEONLY_H
diff --git a/src/gromacs/nbnxm/sycl/nbnxm_sycl_kernel_utils.h b/src/gromacs/nbnxm/sycl/nbnxm_sycl_kernel_utils.h
new file mode 100644 (file)
index 0000000..46c9e38
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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
+ * Helper functions and constants for SYCL NBNXM kernels
+ *
+ * \ingroup module_nbnxm
+ */
+#ifndef GMX_NBNXM_SYCL_NBNXN_SYCL_KERNEL_UTILS_H
+#define GMX_NBNXM_SYCL_NBNXN_SYCL_KERNEL_UTILS_H
+
+#include "gromacs/gpu_utils/sycl_kernel_utils.h"
+#include "gromacs/nbnxm/pairlist.h"
+#include "gromacs/nbnxm/pairlistparams.h"
+
+namespace Nbnxm
+{
+
+#ifndef GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY
+#    define GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY 4
+#endif
+/*! \brief Macro defining default for the prune kernel's j4 processing concurrency.
+ *
+ *  The GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY macro allows compile-time override.
+ */
+static constexpr int c_syclPruneKernelJ4Concurrency = GMX_NBNXN_PRUNE_KERNEL_J4_CONCURRENCY;
+
+/* Convenience constants */
+/*! \cond */
+// cluster size = number of atoms per cluster.
+static constexpr int c_clSize = c_nbnxnGpuClusterSize;
+// j-cluster size after split (4 in the current implementation).
+static constexpr int c_splitClSize = c_clSize / c_nbnxnGpuClusterpairSplit;
+// i-cluster interaction mask for a super-cluster with all c_nbnxnGpuNumClusterPerSupercluster=8 bits set.
+static constexpr unsigned superClInteractionMask = ((1U << c_nbnxnGpuNumClusterPerSupercluster) - 1U);
+
+// 1/sqrt(pi), same value as \c M_FLOAT_1_SQRTPI in other NB kernels.
+static constexpr float c_OneOverSqrtPi = 0.564189583547756F;
+// 1/6, same value as in other NB kernels.
+static constexpr float c_oneSixth = 0.16666667F;
+// 1/12, same value as in other NB kernels.
+static constexpr float c_oneTwelfth = 0.08333333F;
+/*! \endcond */
+
+/* The following functions are necessary because on some versions of Intel OpenCL RT, subgroups
+ * do not properly work (segfault or create subgroups of size 1) if used in kernels
+ * with non-1-dimensional workgroup. */
+//! \brief Convert 3D range to 1D
+static inline cl::sycl::range<1> flattenRange(cl::sycl::range<3> range3d)
+{
+    return cl::sycl::range<1>(range3d.size());
+}
+
+//! \brief Convert 3D nd_range to 1D
+static inline cl::sycl::nd_range<1> flattenNDRange(cl::sycl::nd_range<3> nd_range3d)
+{
+    return cl::sycl::nd_range<1>(flattenRange(nd_range3d.get_global_range()),
+                                 flattenRange(nd_range3d.get_local_range()));
+}
+
+//! \brief Convert flattened 1D index to 3D
+template<int rangeX, int rangeY>
+static inline cl::sycl::id<3> unflattenId(cl::sycl::id<1> id1d)
+{
+    constexpr unsigned rangeXY = rangeX * rangeY;
+    const unsigned     id      = id1d[0];
+    const unsigned     z       = id / rangeXY;
+    const unsigned     xy      = id % rangeXY;
+    return cl::sycl::id<3>(xy % rangeX, xy / rangeX, z);
+}
+
+} // namespace Nbnxm
+
+#endif // GMX_NBNXM_SYCL_NBNXN_SYCL_KERNEL_UTILS_H
diff --git a/src/gromacs/nbnxm/sycl/nbnxm_sycl_types.h b/src/gromacs/nbnxm/sycl/nbnxm_sycl_types.h
new file mode 100644 (file)
index 0000000..a0d8c91
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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
+ *  Data types used internally in the nbnxm_sycl module.
+ *
+ *  \ingroup module_nbnxm
+ */
+
+#ifndef NBNXM_SYCL_TYPES_H
+#define NBNXM_SYCL_TYPES_H
+
+#include "gromacs/gpu_utils/devicebuffer.h"
+#include "gromacs/gpu_utils/devicebuffer_sycl.h"
+#include "gromacs/gpu_utils/gmxsycl.h"
+#include "gromacs/gpu_utils/gpueventsynchronizer_sycl.h"
+#include "gromacs/gpu_utils/gputraits.h"
+#include "gromacs/gpu_utils/syclutils.h"
+#include "gromacs/nbnxm/gpu_types_common.h"
+#include "gromacs/nbnxm/nbnxm.h"
+#include "gromacs/nbnxm/pairlist.h"
+#include "gromacs/timing/gpu_timing.h"
+#include "gromacs/utility/enumerationhelpers.h"
+
+class GpuEventSynchronizer;
+
+/*! \internal
+ * \brief Main data structure for SYCL nonbonded force calculations.
+ */
+struct NbnxmGpu
+{
+    /*! \brief GPU device context.
+     *
+     * \todo Make it constant reference, once NbnxmGpu is a proper class.
+     */
+    const DeviceContext* deviceContext_;
+    /*! \brief true if doing both local/non-local NB work on GPU */
+    bool bUseTwoStreams = false;
+    /*! \brief true indicates that the nonlocal_done event was marked */
+    bool bNonLocalStreamDoneMarked = false;
+    /*! \brief atom data */
+    NBAtomDataGpu* atdat = nullptr;
+
+    // Data for GPU-side coordinate conversion between integrator and NBNXM
+    /*! \brief array of atom indices */
+    DeviceBuffer<int> atomIndices;
+    /*! \brief size of atom indices */
+    int atomIndicesSize = 0;
+    /*! \brief size of atom indices allocated in device buffer */
+    int atomIndicesSize_alloc = 0;
+    /*! \brief x buf ops num of atoms */
+    DeviceBuffer<int> cxy_na;
+    /*! \brief number of elements in cxy_na */
+    int ncxy_na = 0;
+    /*! \brief number of elements allocated allocated in device buffer */
+    int ncxy_na_alloc = 0;
+    /*! \brief x buf ops cell index mapping */
+    DeviceBuffer<int> cxy_ind;
+    /*! \brief number of elements in cxy_ind */
+    int ncxy_ind = 0;
+    /*! \brief number of elements allocated allocated in device buffer */
+    int ncxy_ind_alloc = 0;
+
+    NBParamGpu* nbparam = nullptr;
+    /*! \brief pair-list data structures (local and non-local) */
+    gmx::EnumerationArray<Nbnxm::InteractionLocality, Nbnxm::gpu_plist*> plist = { { nullptr } };
+    /*! \brief staging area where fshift/energies get downloaded. Will be removed in SYCL. */
+    NBStagingData nbst;
+    /*! \brief local and non-local GPU streams */
+    gmx::EnumerationArray<Nbnxm::InteractionLocality, const DeviceStream*> deviceStreams;
+
+    /*! \brief True if event-based timing is enabled. Always false for SYCL. */
+    bool bDoTime = false;
+    /*! \brief Dummy timers. */
+    Nbnxm::GpuTimers* timers = nullptr;
+    /*! \brief Dummy timing data. */
+    gmx_wallclock_gpu_nbnxn_t* timings = nullptr;
+
+    //! true when a pair-list transfer has been done at this step
+    gmx::EnumerationArray<Nbnxm::InteractionLocality, bool> didPairlistH2D = { { false } };
+    //! true when we we did pruning on this step
+    gmx::EnumerationArray<Nbnxm::InteractionLocality, bool> didPrune = { { false } };
+    //! true when we did rolling pruning (at the previous step)
+    gmx::EnumerationArray<Nbnxm::InteractionLocality, bool> didRollingPrune = { { false } };
+
+    /*! \brief Event triggered when the non-local non-bonded
+     * kernel is done (and the local transfer can proceed) */
+    GpuEventSynchronizer nonlocal_done;
+    /*! \brief Event triggered when the tasks issued in the local
+     * stream that need to precede the non-local force or buffer
+     * operation calculations are done (e.g. f buffer 0-ing, local
+     * x/q H2D, buffer op initialization in local stream that is
+     * required also by nonlocal stream ) */
+    GpuEventSynchronizer misc_ops_and_local_H2D_done;
+
+    /*! \brief True if there is work for the current domain in the
+     * respective locality.
+     *
+     * This includes local/nonlocal GPU work, either bonded or
+     * nonbonded, scheduled to be executed in the current
+     * domain. As long as bonded work is not split up into
+     * local/nonlocal, if there is bonded GPU work, both flags
+     * will be true. */
+    gmx::EnumerationArray<Nbnxm::InteractionLocality, bool> haveWork = { { false } };
+
+    /*! \brief Pointer to event synchronizer triggered when the local
+     * GPU buffer ops / reduction is complete. Would be deprecated in SYCL.
+     *
+     * \note That the synchronizer is managed outside of this module
+     * in StatePropagatorDataGpu.
+     */
+    GpuEventSynchronizer* localFReductionDone = nullptr;
+};
+
+#endif /* NBNXM_SYCL_TYPES_H */
index c34de31cc06950baecba9262bd219fdd62bd2a03..9f92f29f4e26409bfd91d1e59e44332d9863f63b 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,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(onlinehelp INTERFACE)
 file(GLOB ONLINEHELP_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${ONLINEHELP_SOURCES} PARENT_SCOPE)
 
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(onlinehelp PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(onlinehelp PUBLIC
+target_include_directories(onlinehelp INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(onlinehelp PUBLIC
+target_link_libraries(onlinehelp INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when onlinehelp is an OBJECT target
+#target_link_libraries(onlinehelp PUBLIC legacy_api)
+#target_link_libraries(onlinehelp PRIVATE common)
+
+# Module dependencies
+# onlinehelp interfaces convey transitive dependence on these modules.
+#target_link_libraries(onlinehelp PUBLIC
+target_link_libraries(onlinehelp INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(onlinehelp PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(onlinehelp PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index 56062527346af2fbeacf9858cf9d6d72f9773a26..079d4cec8cb78f337b64de83f804c1649bfe2b14 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2016,2017 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,7 @@
 #include "gromacs/onlinehelp/helpwritercontext.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/basedefinitions.h"
 
 namespace gmx
 {
index 8ce680719b78fa8346ccd9b1e902ed7c70a7e98a..c5cc667404385306c4fe8ec64408ef16bfb94696 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_ONLINEHELP_HELPFORMAT_H
 #define GMX_ONLINEHELP_HELPFORMAT_H
 
+#include <memory>
 #include <string>
 
-#include "gromacs/utility/classhelpers.h"
-
 namespace gmx
 {
 
@@ -227,7 +226,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index de9dfcedd8572c196364f6748be5cb4f1bec00ee..c61927b4591f88ad59e9998372e47875f5c58c58 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2014,2015,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -134,8 +134,8 @@ void HelpManager::enterTopic(const char* name)
         }
         else
         {
-            GMX_THROW(InvalidInputError(formatString("Help topic '%s' has no subtopic '%s'",
-                                                     impl_->currentTopicAsString().c_str(), name)));
+            GMX_THROW(InvalidInputError(formatString(
+                    "Help topic '%s' has no subtopic '%s'", impl_->currentTopicAsString().c_str(), name)));
         }
     }
     impl_->topicStack_.push_back(newTopic);
index 7c6874322426f2ecd005638e313a800b961d7c75..03a4ec37cf5cc4936080685e339c825790befc81 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_ONLINEHELP_HELPMANAGER_H
 #define GMX_ONLINEHELP_HELPMANAGER_H
 
+#include <memory>
 #include <string>
 
-#include "gromacs/utility/classhelpers.h"
-
 namespace gmx
 {
 
@@ -98,7 +97,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 044a15c0d0ef8ca6786d11a52edd84ddca4def63..875c1c0bedc013e04fa20c74957e139e43a579b3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2014,2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +46,6 @@
 #include <memory>
 
 #include "gromacs/onlinehelp/ihelptopic.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/stringutil.h"
 
 namespace gmx
@@ -175,7 +174,7 @@ protected:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \cond libapi */
index f89611ab9c861b02d7cc30e4d840188a971c3a35..940d0a94409c02ac71623aefa8147bcf206dc9dc 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +52,7 @@
 #include <vector>
 
 #include "gromacs/onlinehelp/helpformat.h"
+#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/programcontext.h"
@@ -445,8 +446,7 @@ std::string HelpWriterContext::Impl::replaceLinks(const std::string& input) cons
     if (state_->links_ != nullptr)
     {
         HelpLinks::Impl::LinkList::const_iterator link;
-        for (link = state_->links_->impl_->links_.begin();
-             link != state_->links_->impl_->links_.end(); ++link)
+        for (link = state_->links_->impl_->links_.begin(); link != state_->links_->impl_->links_.end(); ++link)
         {
             result = replaceAllWords(result, link->linkName, link->replacement);
         }
index 4ce7b4fff60327438b566e16474412bdabf5afee..cf16c066cf686d95859a0afd850cbe86379254b5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_ONLINEHELP_HELPWRITERCONTEXT_H
 #define GMX_ONLINEHELP_HELPWRITERCONTEXT_H
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -106,7 +107,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     //! Allows the context to use the links.
     friend class HelpWriterContext;
@@ -297,7 +298,7 @@ private:
      */
     explicit HelpWriterContext(Impl* impl);
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     GMX_DISALLOW_ASSIGN(HelpWriterContext);
 };
index 52eda481e1010dc231b780e78208543f4bc6c6a5..3ac9998433811c9f3b1a5d0e1d80c2cbc0f8430d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #ifndef GMX_ONLINEHELP_RSTPARSER_H
 #define GMX_ONLINEHELP_RSTPARSER_H
 
+#include <memory>
 #include <string>
 
 #include "gromacs/utility/classhelpers.h"
diff --git a/src/gromacs/onlinehelp/tests/.clang-tidy b/src/gromacs/onlinehelp/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index ad53c3b6ddb9fa2528a29c0bc9dd616a86073494..a22b6e83cddb15da2218e92301a1cd177b422c92 100644 (file)
@@ -34,6 +34,7 @@
 
 gmx_add_unit_test_library(onlinehelp-test-shared
                           mock_helptopic.cpp)
+target_link_libraries(onlinehelp-test-shared PUBLIC common)
 
 gmx_add_unit_test(OnlineHelpUnitTests onlinehelp-test
     CPP_SOURCE_FILES
index d67ef3fa03bc27b18aec9f14624ab06734f56b92..29e80ddc8a9ef2d6353a8915510cfa4903958533 100644 (file)
@@ -33,6 +33,9 @@
 # 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 up the module library
+add_library(options INTERFACE)
+
 gmx_add_libgromacs_sources(
     abstractoption.cpp
     abstractsection.cpp
@@ -65,6 +68,30 @@ if(GMX_INSTALL_LEGACY_API)
             DESTINATION include/gromacs/options)
 endif()
 
+# Source files have the following private module dependencies.
+target_link_libraries(options PRIVATE
+               )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(options PUBLIC
+target_include_directories(options INTERFACE
+               $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(options PUBLIC
+target_link_libraries(options INTERFACE
+               legacy_api
+               )
+
+# TODO: when options is an OBJECT target
+#target_link_libraries(options PUBLIC legacy_api)
+#target_link_libraries(options PRIVATE common)
+
+# Module dependencies
+# options interfaces convey transitive dependence on these modules.
+#target_link_libraries(options PUBLIC
+target_link_libraries(options INTERFACE
+                      utility
+               )
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index 06883d6db93cd3fe4bb86b1d359b14c9458b55f4..fa34c5dae44f6794261ac5d043f13f9cb7b24fef 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2017, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +55,7 @@
 #ifndef GMX_OPTIONS_ABSTRACTOPTION_H
 #define GMX_OPTIONS_ABSTRACTOPTION_H
 
+#include <memory>
 #include <string>
 #include <vector>
 
index f6dd415181c8099a6673806b82124906e8c46c44..b99946639f8fc44aa9958aaf8d7c8d02ab2623fc 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2014,2015 by the GROMACS development team.
- * Copyright (c) 2016,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #ifndef GMX_OPTIONS_ABSTRACTOPTIONSTORAGE_H
 #define GMX_OPTIONS_ABSTRACTOPTIONSTORAGE_H
 
+#include <memory>
 #include <string>
 #include <vector>
 
index 975176954d424e9a447e05636536733cba0fd158..d1f3f98ac2eb22177aad97eac7dd96cdfda96811 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
 #ifndef GMX_OPTIONS_ABSTRACTSECTION_H
 #define GMX_OPTIONS_ABSTRACTSECTION_H
 
+#include <memory>
+
 #include "gromacs/options/ioptionscontainerwithsections.h"
 #include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/gmxassert.h"
index 65e489568048e64fe1e57bfafef1b514dd2b5159..d432055b261f13ef94bdcfc34c520bda42e7a215 100644 (file)
@@ -563,7 +563,9 @@ private:
     AbstractOptionStorage* createStorage(const OptionManagerContainer& /*managers*/) const override
     {
         // TODO: Implement storeCount() if necessary.
-        return internal::createEnumOptionStorage(*this, enumValues_, enumValuesCount_,
+        return internal::createEnumOptionStorage(*this,
+                                                 enumValues_,
+                                                 enumValuesCount_,
                                                  convertToInt(MyBase::defaultValue()),
                                                  convertToInt(MyBase::defaultValueIfSet()),
                                                  std::make_unique<internal::EnumIndexStore<EnumType>>(
@@ -675,7 +677,9 @@ private:
     AbstractOptionStorage* createStorage(const OptionManagerContainer& /*managers*/) const override
     {
         // TODO: Implement storeCount() if necessary.
-        return internal::createEnumOptionStorage(*this, enumValues_, enumValuesCount_,
+        return internal::createEnumOptionStorage(*this,
+                                                 enumValues_,
+                                                 enumValuesCount_,
                                                  convertToInt(MyBase::defaultValue()),
                                                  convertToInt(MyBase::defaultValueIfSet()),
                                                  std::make_unique<internal::EnumIndexStore<EnumType>>(
index 9df3722459ea383fae4194513bd7b66b089c2182..41aea4bf508d1d0be445640a042778dfcdba57e7 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/options/filenameoptionmanager.h"
 #include "gromacs/options/optionmanagercontainer.h"
 #include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/stringutil.h"
@@ -80,11 +81,9 @@ struct FileTypeMapping
 };
 
 //! Mappings from OptionFileType to file types in filetypes.h.
-const FileTypeMapping c_fileTypeMapping[] = { { eftTopology, efTPS },   { eftRunInput, efTPR },
-                                              { eftTrajectory, efTRX }, { eftEnergy, efEDR },
-                                              { eftPDB, efPDB },        { eftIndex, efNDX },
-                                              { eftPlot, efXVG },       { eftGenericData, efDAT },
-                                              { eftCsv, efCSV } };
+constexpr EnumerationArray<OptionFileType, int> sc_fileTypeMapping = { efTPS, efTPR, efTRX,
+                                                                       efEDR, efPDB, efNDX,
+                                                                       efXVG, efDAT, efCSV };
 
 /********************************************************************
  * FileTypeHandler
@@ -211,19 +210,17 @@ FileNameOptionStorage::FileNameOptionStorage(const FileNameOption& settings, Fil
 {
     GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes),
                        "allowMultiple() is not supported for file name options");
-    if (settings.optionType_ == eftUnknown && settings.legacyType_ >= 0)
+    if (settings.optionType_ == OptionFileType::Count && settings.legacyType_ >= 0)
     {
         fileType_ = settings.legacyType_;
     }
     else
     {
-        ArrayRef<const FileTypeMapping>                 map(c_fileTypeMapping);
-        ArrayRef<const FileTypeMapping>::const_iterator i;
-        for (i = map.begin(); i != map.end(); ++i)
+        for (auto i : keysOf(sc_fileTypeMapping))
         {
-            if (i->optionType == settings.optionType_)
+            if (i == settings.optionType_)
             {
-                fileType_ = i->fileType;
+                fileType_ = sc_fileTypeMapping[i];
                 break;
             }
         }
@@ -360,7 +357,8 @@ std::string FileNameOptionStorage::processValue(const std::string& value) const
                 "File '%s' cannot be used by GROMACS because it "
                 "does not have a recognizable extension.\n"
                 "The following extensions are possible for this option:\n  %s",
-                value.c_str(), joinStrings(extensions(), ", ").c_str());
+                value.c_str(),
+                joinStrings(extensions(), ", ").c_str());
         GMX_THROW(InvalidInputError(message));
     }
     else if (!isValidType(fileType))
@@ -368,7 +366,8 @@ std::string FileNameOptionStorage::processValue(const std::string& value) const
         std::string message = formatString(
                 "File name '%s' cannot be used for this option.\n"
                 "Only the following extensions are possible:\n  %s",
-                value.c_str(), joinStrings(extensions(), ", ").c_str());
+                value.c_str(),
+                joinStrings(extensions(), ", ").c_str());
         GMX_THROW(InvalidInputError(message));
     }
     return value;
index 1aaef894be43be9ba7ee5fba25444857b096ddc6..74df7e01144d05f41bc1ea24ba7f7ba638d8019b 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +76,7 @@ public:
     //! Initializes an option with the given name.
     explicit FileNameOption(const char* name) :
         MyBase(name),
-        optionType_(eftUnknown),
+        optionType_(OptionFileType::Count),
         legacyType_(-1),
         defaultBasename_(nullptr),
         defaultType_(-1),
index 54a4d407ff064101ee7a79983e18df6ac54f4806..28f0dc59582d95145ee48c0094f4bdb307deb09f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2017,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -192,7 +192,7 @@ std::string FileNameOptionManager::completeFileName(const std::string& value, co
         }
         else if (fileType == efNR)
         {
-            const std::string processedValue = findExistingExtension(value, option, impl_->redirector_);
+            std::string processedValue = findExistingExtension(value, option, impl_->redirector_);
             if (!processedValue.empty())
             {
                 return processedValue;
@@ -211,7 +211,8 @@ std::string FileNameOptionManager::completeFileName(const std::string& value, co
                 std::string message = formatString(
                         "File '%s' does not exist or is not accessible.\n"
                         "The following extensions were tried to complete the file name:\n  %s",
-                        value.c_str(), joinStrings(option.extensions(), ", ").c_str());
+                        value.c_str(),
+                        joinStrings(option.extensions(), ", ").c_str());
                 GMX_THROW(InvalidInputError(message));
             }
         }
@@ -256,7 +257,7 @@ std::string FileNameOptionManager::completeDefaultFileName(const std::string&
     const std::string realPrefix = !impl_->defaultFileName_.empty() ? impl_->defaultFileName_ : prefix;
     if (bInput && !impl_->bInputCheckingDisabled_)
     {
-        const std::string completedName = findExistingExtension(realPrefix, option, impl_->redirector_);
+        std::string completedName = findExistingExtension(realPrefix, option, impl_->redirector_);
         if (!completedName.empty())
         {
             return completedName;
@@ -276,7 +277,8 @@ std::string FileNameOptionManager::completeDefaultFileName(const std::string&
                     "No file name was provided, and the default file "
                     "'%s' does not exist or is not accessible.\n"
                     "The following extensions were tried to complete the file name:\n  %s",
-                    prefix.c_str(), joinStrings(option.extensions(), ", ").c_str());
+                    prefix.c_str(),
+                    joinStrings(option.extensions(), ", ").c_str());
             GMX_THROW(InvalidInputError(message));
         }
         else if (option.isRequired())
@@ -285,7 +287,8 @@ std::string FileNameOptionManager::completeDefaultFileName(const std::string&
                     "Required option was not provided, and the default file "
                     "'%s' does not exist or is not accessible.\n"
                     "The following extensions were tried to complete the file name:\n  %s",
-                    prefix.c_str(), joinStrings(option.extensions(), ", ").c_str());
+                    prefix.c_str(),
+                    joinStrings(option.extensions(), ", ").c_str());
             GMX_THROW(InvalidInputError(message));
         }
         // We get here with the legacy optional behavior.
index 3fe2f075e970af19d42dfb8c3cb0d81585a58271..642426ca9dda77006652bc4971d3e101a6ba2ff8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_OPTIONS_FILENAMEOPTIONMANAGER_H
 #define GMX_OPTIONS_FILENAMEOPTIONMANAGER_H
 
+#include <memory>
 #include <string>
 
 #include "gromacs/options/options.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
@@ -171,7 +171,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index cc8e4d5dc4a37d464cf6f1bb7dddd96cd500ec4f..70b672d857a7a5c37eeb6f3b1117597c2ea76197 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012,2015,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2015,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,19 +51,18 @@ namespace gmx
  *
  * \ingroup module_options
  */
-enum OptionFileType
+enum class OptionFileType : int
 {
-    eftUnknown,
-    eftTopology,
-    eftRunInput,
-    eftTrajectory,
-    eftEnergy,
-    eftPDB,
-    eftIndex,
-    eftPlot,
-    eftGenericData,
-    eftCsv,
-    eftOptionFileType_NR
+    Topology,
+    RunInput,
+    Trajectory,
+    Energy,
+    PDB,
+    Index,
+    Plot,
+    GenericData,
+    Csv,
+    Count
 };
 
 } // namespace gmx
index 0914a10173a496289bcc6b354028ff3bc2947591..cfd343bddc2b89f76395316706f55e10bf75cd9a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2017,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_OPTIONS_OPTIONMANAGERCONTAINER_H
 #define GMX_OPTIONS_OPTIONMANAGERCONTAINER_H
 
+#include <memory>
 #include <vector>
 
 #include "gromacs/utility/classhelpers.h"
index 69dcb4c52570ab7ad0043b550107555bc7355968..b2ef29668f9601e70bbde04d0b744dfb64346d4e 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2014,2015 by the GROMACS development team.
- * Copyright (c) 2016,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_OPTIONS_OPTIONS_H
 #define GMX_OPTIONS_OPTIONS_H
 
+#include <memory>
 #include <string>
 
 #include "gromacs/options/ioptionscontainerwithsections.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
@@ -159,7 +159,7 @@ private:
     // From IOptionsContainer
     OptionInfo* addOptionImpl(const AbstractOption& settings) override;
 
-    PrivateImplPointer<internal::OptionsImpl> impl_;
+    std::unique_ptr<internal::OptionsImpl> impl_;
 
     //! Needed to be able to extend the interface of this object.
     friend class OptionsAssigner;
index b72219faa05ed060a336f4d00d4b0ccaa7811c3e..cd0c3574d2b8b70fed8b0155ff20104b2940a977 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/options/optionmanagercontainer.h"
 #include "gromacs/options/options.h"
 #include "gromacs/options/optionsection.h"
+#include "gromacs/utility/classhelpers.h"
 
 #include "isectionstorage.h"
 
index 3892140566f1a3a5a994163025e5d47487e9f1e2..0ab59fe5415b34141909c7145df1364dee0915c8 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2015,2016,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_OPTIONS_OPTIONSASSIGNER_H
 #define GMX_OPTIONS_OPTIONSASSIGNER_H
 
+#include <memory>
 #include <string>
 
-#include "gromacs/utility/classhelpers.h"
-
 namespace gmx
 {
 
@@ -207,7 +206,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 0af38875c7622c801c567d03d0245c3a7fabdfab..e7f6ed9a6539bbafd60bff5bdb7bb95fe6afd6d7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +43,7 @@
 #ifndef GMX_OPTIONS_OPTIONSECTION_H
 #define GMX_OPTIONS_OPTIONSECTION_H
 
-#include "gromacs/utility/classhelpers.h"
+#include <memory>
 
 #include "abstractsection.h"
 
index 5a47d077c2f10bacf02bd517bdedd3bfbaaef2d9..64b888a262b1fcffb23a4556b7bb14abfb1b25e2 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2014,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstddef>
 
+#include <memory>
 #include <string>
 
 #include "gromacs/options/abstractoption.h"
diff --git a/src/gromacs/options/tests/.clang-tidy b/src/gromacs/options/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 4196277d4c5103b9957cb032e35ed15e99ba756a..9af9567ca9fab1b8d6a866f4b473a8380ec75a8b 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -62,8 +62,12 @@ TEST(FileNameOptionTest, HandlesRequiredDefaultValueWithoutExtension)
 {
     gmx::Options options;
     std::string  value;
-    ASSERT_NO_THROW_GMX(options.addOption(
-            FileNameOption("f").store(&value).required().filetype(gmx::eftGenericData).outputFile().defaultBasename("testfile")));
+    ASSERT_NO_THROW_GMX(options.addOption(FileNameOption("f")
+                                                  .store(&value)
+                                                  .required()
+                                                  .filetype(gmx::OptionFileType::GenericData)
+                                                  .outputFile()
+                                                  .defaultBasename("testfile")));
     EXPECT_EQ("testfile.dat", value);
 
     gmx::OptionsAssigner assigner(&options);
@@ -78,8 +82,12 @@ TEST(FileNameOptionTest, HandlesRequiredOptionWithoutValue)
 {
     gmx::Options options;
     std::string  value;
-    ASSERT_NO_THROW_GMX(options.addOption(
-            FileNameOption("f").store(&value).required().filetype(gmx::eftGenericData).outputFile().defaultBasename("testfile")));
+    ASSERT_NO_THROW_GMX(options.addOption(FileNameOption("f")
+                                                  .store(&value)
+                                                  .required()
+                                                  .filetype(gmx::OptionFileType::GenericData)
+                                                  .outputFile()
+                                                  .defaultBasename("testfile")));
     EXPECT_EQ("testfile.dat", value);
 
     gmx::OptionsAssigner assigner(&options);
@@ -97,7 +105,7 @@ TEST(FileNameOptionTest, HandlesOptionalUnsetOption)
     gmx::Options options;
     std::string  value;
     ASSERT_NO_THROW_GMX(options.addOption(
-            FileNameOption("f").store(&value).filetype(gmx::eftTrajectory).outputFile().defaultBasename("testfile")));
+            FileNameOption("f").store(&value).filetype(gmx::OptionFileType::Trajectory).outputFile().defaultBasename("testfile")));
     EXPECT_TRUE(value.empty());
 
     gmx::OptionsAssigner assigner(&options);
@@ -113,7 +121,7 @@ TEST(FileNameOptionTest, HandlesOptionalDefaultValueWithoutExtension)
     gmx::Options options;
     std::string  value;
     ASSERT_NO_THROW_GMX(options.addOption(
-            FileNameOption("f").store(&value).filetype(gmx::eftIndex).outputFile().defaultBasename("testfile")));
+            FileNameOption("f").store(&value).filetype(gmx::OptionFileType::Index).outputFile().defaultBasename("testfile")));
     EXPECT_TRUE(value.empty());
 
     gmx::OptionsAssigner assigner(&options);
@@ -133,7 +141,7 @@ TEST(FileNameOptionTest, HandlesRequiredCustomDefaultExtension)
     ASSERT_NO_THROW_GMX(options.addOption(FileNameOption("f")
                                                   .store(&value)
                                                   .required()
-                                                  .filetype(gmx::eftTrajectory)
+                                                  .filetype(gmx::OptionFileType::Trajectory)
                                                   .outputFile()
                                                   .defaultBasename("testfile")
                                                   .defaultType(efPDB)));
@@ -153,7 +161,7 @@ TEST(FileNameOptionTest, HandlesOptionalCustomDefaultExtension)
     std::string  value;
     ASSERT_NO_THROW_GMX(options.addOption(FileNameOption("f")
                                                   .store(&value)
-                                                  .filetype(gmx::eftTrajectory)
+                                                  .filetype(gmx::OptionFileType::Trajectory)
                                                   .outputFile()
                                                   .defaultBasename("testfile")
                                                   .defaultType(efPDB)));
@@ -173,8 +181,8 @@ TEST(FileNameOptionTest, GivesErrorOnUnknownFileSuffix)
 {
     gmx::Options options;
     std::string  value;
-    ASSERT_NO_THROW_GMX(
-            options.addOption(FileNameOption("f").store(&value).filetype(gmx::eftIndex).outputFile()));
+    ASSERT_NO_THROW_GMX(options.addOption(
+            FileNameOption("f").store(&value).filetype(gmx::OptionFileType::Index).outputFile()));
     EXPECT_TRUE(value.empty());
 
     gmx::OptionsAssigner assigner(&options);
@@ -193,7 +201,7 @@ TEST(FileNameOptionTest, GivesErrorOnInvalidFileSuffix)
     gmx::Options options;
     std::string  value;
     ASSERT_NO_THROW_GMX(options.addOption(
-            FileNameOption("f").store(&value).filetype(gmx::eftTrajectory).outputFile()));
+            FileNameOption("f").store(&value).filetype(gmx::OptionFileType::Trajectory).outputFile()));
     EXPECT_TRUE(value.empty());
 
     gmx::OptionsAssigner assigner(&options);
@@ -211,8 +219,12 @@ TEST(FileNameOptionTest, HandlesRequiredCsvValueWithoutExtension)
 {
     gmx::Options options;
     std::string  value;
-    ASSERT_NO_THROW_GMX(options.addOption(
-            FileNameOption("f").store(&value).required().filetype(gmx::eftCsv).outputFile().defaultBasename("testfile")));
+    ASSERT_NO_THROW_GMX(options.addOption(FileNameOption("f")
+                                                  .store(&value)
+                                                  .required()
+                                                  .filetype(gmx::OptionFileType::Csv)
+                                                  .outputFile()
+                                                  .defaultBasename("testfile")));
     EXPECT_EQ("testfile.csv", value);
 
     gmx::OptionsAssigner assigner(&options);
@@ -227,8 +239,12 @@ TEST(FileNameOptionTest, HandlesRequiredCsvOptionWithoutValue)
 {
     gmx::Options options;
     std::string  value;
-    ASSERT_NO_THROW_GMX(options.addOption(
-            FileNameOption("f").store(&value).required().filetype(gmx::eftCsv).outputFile().defaultBasename("testfile")));
+    ASSERT_NO_THROW_GMX(options.addOption(FileNameOption("f")
+                                                  .store(&value)
+                                                  .required()
+                                                  .filetype(gmx::OptionFileType::Csv)
+                                                  .outputFile()
+                                                  .defaultBasename("testfile")));
     EXPECT_EQ("testfile.csv", value);
 
     gmx::OptionsAssigner assigner(&options);
index 8a5c55b2da5606671d3a46eac03fcd1ec1b5da62..3bc96ebabedb88f9e8ed013c8bf1ef9e69acf697 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ TEST_F(FileNameOptionManagerTest, AddsMissingExtension)
 {
     std::string value;
     ASSERT_NO_THROW_GMX(options_.addOption(
-            FileNameOption("f").store(&value).filetype(gmx::eftTrajectory).outputFile()));
+            FileNameOption("f").store(&value).filetype(gmx::OptionFileType::Trajectory).outputFile()));
 
     gmx::OptionsAssigner assigner(&options_);
     EXPECT_NO_THROW_GMX(assigner.start());
@@ -100,7 +100,7 @@ TEST_F(FileNameOptionManagerTest, AddsMissingCustomDefaultExtension)
 {
     std::string value;
     ASSERT_NO_THROW_GMX(options_.addOption(
-            FileNameOption("f").store(&value).filetype(gmx::eftTrajectory).outputFile().defaultType(efPDB)));
+            FileNameOption("f").store(&value).filetype(gmx::OptionFileType::Trajectory).outputFile().defaultType(efPDB)));
 
     gmx::OptionsAssigner assigner(&options_);
     EXPECT_NO_THROW_GMX(assigner.start());
@@ -116,8 +116,8 @@ TEST_F(FileNameOptionManagerTest, AddsMissingCustomDefaultExtension)
 TEST_F(FileNameOptionManagerTest, GivesErrorOnMissingInputFile)
 {
     std::string value;
-    ASSERT_NO_THROW_GMX(
-            options_.addOption(FileNameOption("f").store(&value).filetype(gmx::eftIndex).inputFile()));
+    ASSERT_NO_THROW_GMX(options_.addOption(
+            FileNameOption("f").store(&value).filetype(gmx::OptionFileType::Index).inputFile()));
     EXPECT_TRUE(value.empty());
 
     gmx::OptionsAssigner assigner(&options_);
@@ -135,7 +135,7 @@ TEST_F(FileNameOptionManagerTest, GivesErrorOnMissingGenericInputFile)
 {
     std::string value;
     ASSERT_NO_THROW_GMX(options_.addOption(
-            FileNameOption("f").store(&value).filetype(gmx::eftTrajectory).inputFile()));
+            FileNameOption("f").store(&value).filetype(gmx::OptionFileType::Trajectory).inputFile()));
     EXPECT_TRUE(value.empty());
 
     gmx::OptionsAssigner assigner(&options_);
@@ -153,7 +153,7 @@ TEST_F(FileNameOptionManagerTest, GivesErrorOnMissingDefaultInputFile)
 {
     std::string value;
     ASSERT_NO_THROW_GMX(options_.addOption(
-            FileNameOption("f").store(&value).filetype(gmx::eftIndex).inputFile().defaultBasename("missing")));
+            FileNameOption("f").store(&value).filetype(gmx::OptionFileType::Index).inputFile().defaultBasename("missing")));
 
     gmx::OptionsAssigner assigner(&options_);
     EXPECT_NO_THROW_GMX(assigner.start());
@@ -166,8 +166,12 @@ TEST_F(FileNameOptionManagerTest, GivesErrorOnMissingDefaultInputFile)
 TEST_F(FileNameOptionManagerTest, GivesErrorOnMissingRequiredInputFile)
 {
     std::string value;
-    ASSERT_NO_THROW_GMX(options_.addOption(
-            FileNameOption("f").store(&value).required().filetype(gmx::eftIndex).inputFile().defaultBasename("missing")));
+    ASSERT_NO_THROW_GMX(options_.addOption(FileNameOption("f")
+                                                   .store(&value)
+                                                   .required()
+                                                   .filetype(gmx::OptionFileType::Index)
+                                                   .inputFile()
+                                                   .defaultBasename("missing")));
     EXPECT_EQ("missing.ndx", value);
 
     gmx::OptionsAssigner assigner(&options_);
@@ -180,7 +184,7 @@ TEST_F(FileNameOptionManagerTest, AcceptsMissingInputFileIfSpecified)
 {
     std::string value;
     ASSERT_NO_THROW_GMX(options_.addOption(
-            FileNameOption("f").store(&value).filetype(gmx::eftIndex).inputFile().allowMissing()));
+            FileNameOption("f").store(&value).filetype(gmx::OptionFileType::Index).inputFile().allowMissing()));
     EXPECT_TRUE(value.empty());
 
     gmx::OptionsAssigner assigner(&options_);
@@ -199,7 +203,7 @@ TEST_F(FileNameOptionManagerTest, AcceptsMissingDefaultInputFileIfSpecified)
     std::string value;
     ASSERT_NO_THROW_GMX(options_.addOption(FileNameOption("f")
                                                    .store(&value)
-                                                   .filetype(gmx::eftIndex)
+                                                   .filetype(gmx::OptionFileType::Index)
                                                    .inputFile()
                                                    .defaultBasename("missing")
                                                    .allowMissing()));
@@ -220,7 +224,7 @@ TEST_F(FileNameOptionManagerTest, AcceptsMissingRequiredInputFileIfSpecified)
     ASSERT_NO_THROW_GMX(options_.addOption(FileNameOption("f")
                                                    .store(&value)
                                                    .required()
-                                                   .filetype(gmx::eftIndex)
+                                                   .filetype(gmx::OptionFileType::Index)
                                                    .inputFile()
                                                    .defaultBasename("missing")
                                                    .allowMissing()));
@@ -240,7 +244,7 @@ TEST_F(FileNameOptionManagerTest, AddsMissingExtensionBasedOnExistingFile)
 
     std::string value;
     ASSERT_NO_THROW_GMX(options_.addOption(
-            FileNameOption("f").store(&value).filetype(gmx::eftTrajectory).inputFile()));
+            FileNameOption("f").store(&value).filetype(gmx::OptionFileType::Trajectory).inputFile()));
 
     gmx::OptionsAssigner assigner(&options_);
     EXPECT_NO_THROW_GMX(assigner.start());
@@ -258,8 +262,12 @@ TEST_F(FileNameOptionManagerTest, AddsMissingExtensionForRequiredDefaultNameBase
     addExistingFile("testfile.trr");
 
     std::string value;
-    ASSERT_NO_THROW_GMX(options_.addOption(
-            FileNameOption("f").store(&value).required().filetype(gmx::eftTrajectory).inputFile().defaultBasename("testfile")));
+    ASSERT_NO_THROW_GMX(options_.addOption(FileNameOption("f")
+                                                   .store(&value)
+                                                   .required()
+                                                   .filetype(gmx::OptionFileType::Trajectory)
+                                                   .inputFile()
+                                                   .defaultBasename("testfile")));
     EXPECT_EQ("testfile.xtc", value);
 
     gmx::OptionsAssigner assigner(&options_);
@@ -278,7 +286,7 @@ TEST_F(FileNameOptionManagerTest, AddsMissingExtensionForOptionalDefaultNameBase
 
     std::string value;
     ASSERT_NO_THROW_GMX(options_.addOption(
-            FileNameOption("f").store(&value).filetype(gmx::eftTrajectory).inputFile().defaultBasename("testfile")));
+            FileNameOption("f").store(&value).filetype(gmx::OptionFileType::Trajectory).inputFile().defaultBasename("testfile")));
 
     gmx::OptionsAssigner assigner(&options_);
     EXPECT_NO_THROW_GMX(assigner.start());
@@ -295,8 +303,12 @@ TEST_F(FileNameOptionManagerTest, AddsMissingExtensionForRequiredFromDefaultName
     addExistingFile("testfile.trr");
 
     std::string value;
-    ASSERT_NO_THROW_GMX(options_.addOption(
-            FileNameOption("f").store(&value).required().filetype(gmx::eftTrajectory).inputFile().defaultBasename("foo")));
+    ASSERT_NO_THROW_GMX(options_.addOption(FileNameOption("f")
+                                                   .store(&value)
+                                                   .required()
+                                                   .filetype(gmx::OptionFileType::Trajectory)
+                                                   .inputFile()
+                                                   .defaultBasename("foo")));
     ASSERT_NO_THROW_GMX(manager_.addDefaultFileNameOption(&options_, "deffnm"));
     EXPECT_EQ("foo.xtc", value);
 
@@ -317,7 +329,7 @@ TEST_F(FileNameOptionManagerTest, AddsMissingExtensionForOptionalFromDefaultName
 
     std::string value;
     ASSERT_NO_THROW_GMX(options_.addOption(
-            FileNameOption("f").store(&value).filetype(gmx::eftTrajectory).inputFile().defaultBasename("foo")));
+            FileNameOption("f").store(&value).filetype(gmx::OptionFileType::Trajectory).inputFile().defaultBasename("foo")));
     ASSERT_NO_THROW_GMX(manager_.addDefaultFileNameOption(&options_, "deffnm"));
 
     gmx::OptionsAssigner assigner(&options_);
@@ -340,7 +352,7 @@ TEST_F(FileNameOptionManagerTest, DefaultNameOptionWorksWithoutInputChecking)
     ASSERT_NO_THROW_GMX(options_.addOption(FileNameOption("f")
                                                    .store(&value)
                                                    .required()
-                                                   .filetype(gmx::eftIndex)
+                                                   .filetype(gmx::OptionFileType::Index)
                                                    .inputFile()
                                                    .defaultBasename("default")
                                                    .allowMissing()));
index 0dc7a4f2d41621976641904656b9f5acdd8ec150..2b09594759aafa507ac1ade7af611e4f6f9775b2 100644 (file)
@@ -69,8 +69,9 @@ namespace
  *
  * These must correspond to the TimeUnit enum in the header!
  */
-const EnumerationArray<TimeUnit, const char*> c_timeUnitNames = { { "fs", "ps", "ns", "us", "ms",
-                                                                    "s" } };
+const EnumerationArray<TimeUnit, const char*> c_timeUnitNames = {
+    { "fs", "ps", "ns", "us", "ms", "s" }
+};
 /*! \brief
  * Scaling factors from each time unit to internal units (=picoseconds).
  *
@@ -145,7 +146,8 @@ void TimeUnitBehavior::setTimeUnitFromEnvironment()
                     "Time unit provided with environment variable GMXTIMEUNIT=%s "
                     "is not recognized as a valid time unit.\n"
                     "Possible values are: %s",
-                    value, joinStrings(c_timeUnitNames, ", ").c_str());
+                    value,
+                    joinStrings(c_timeUnitNames, ", ").c_str());
             GMX_THROW(InvalidInputError(message));
         }
         setTimeUnit(result);
index 222771b3e28266042bdde4caeaa01611cce395b0..ad62d206cca60a02b3648d44a29c79a0094aac5e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2014,2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
 #ifndef GMX_OPTIONS_TIMEUNITMANAGER_H
 #define GMX_OPTIONS_TIMEUNITMANAGER_H
 
+#include <memory>
+
 #include "gromacs/fileio/oenv.h"
 #include "gromacs/options/ioptionsbehavior.h"
 #include "gromacs/utility/classhelpers.h"
index d8d14b58ff31db21fe0391d029f11cbac17e896b..d43ad7d789e1dca4df55147e7c55b54098909231 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -183,8 +183,8 @@ private:
         if (currentObject_->keyExists(name))
         {
             currentKnownNames_->insert(name);
-            auto parentObject     = currentObject_;
-            auto parentKnownNames = currentKnownNames_;
+            const auto* parentObject     = currentObject_;
+            auto*       parentKnownNames = currentKnownNames_;
             // TODO: Consider what to do with mismatching types.
             currentObject_ = &(*currentObject_)[name].asObject();
             currentPath_.append(name);
@@ -231,7 +231,7 @@ private:
     {
         const std::string& name          = section.name();
         auto               parentBuilder = currentObjectBuilder_;
-        auto               parentObject  = currentSourceObject_;
+        const auto*        parentObject  = currentSourceObject_;
         currentObjectBuilder_            = currentObjectBuilder_.addObject(name);
         currentSourceObject_ = (currentSourceObject_ != nullptr && currentSourceObject_->keyExists(name)
                                         ? &(*currentSourceObject_)[name].asObject()
@@ -316,8 +316,9 @@ void checkForUnknownOptionsInKeyValueTree(const KeyValueTreeObject& tree, const
     helper.processOptionSection(options.rootSection());
     if (helper.hasUnknownPaths())
     {
-        std::string paths(formatAndJoin(helper.unknownPaths(), "\n  ",
-                                        [](const KeyValueTreePath& path) { return path.toString(); }));
+        std::string paths(formatAndJoin(helper.unknownPaths(), "\n  ", [](const KeyValueTreePath& path) {
+            return path.toString();
+        }));
         std::string message("Unknown input values:\n  " + paths);
         GMX_THROW(InvalidInputError(message));
     }
index 63a5dacfcb851d02010ba126a500d65bed456dc3..57ddbc882592f2ab2db913ab8c60d8a3860defc2 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 up the module library
+add_library(pbcutil INTERFACE)
 file(GLOB PBCUTIL_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${PBCUTIL_SOURCES} PARENT_SCOPE)
 
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(pbcutil PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(pbcutil PUBLIC
+target_include_directories(pbcutil INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(pbcutil PUBLIC
+target_link_libraries(pbcutil INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when pbcutil is an OBJECT target
+#target_link_libraries(pbcutil PUBLIC legacy_api)
+#target_link_libraries(pbcutil PRIVATE common)
+
+# Module dependencies
+# pbcutil interfaces convey transitive dependence on these modules.
+#target_link_libraries(pbcutil PUBLIC
+target_link_libraries(pbcutil INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(pbcutil PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(pbcutil PRIVATE legacy_modules)
+
 if(GMX_INSTALL_LEGACY_API)
   install(FILES
           pbc.h
index 870db8ca528737111975b3eaa645e94cdfc34596..e2456e30e3ae6eba316b1b864e281e67233975cc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_PBCUTIL_COM_H
 
 #include <algorithm>
+#include <memory>
 
 #include "gromacs/math/vec.h"
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/classhelpers.h"
 
 #include "pbcenums.h"
 
index 83743374371b4cf9c4e3af8940273e260389e9c7..7a25fd39c227f64187d4023bebf8c972366f3e4f 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,2019, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_PBCUTIL_ISHIFT_H
 #define GMX_PBCUTIL_ISHIFT_H
 
-#define D_BOX_Z 1
-#define D_BOX_Y 1
-#define D_BOX_X 2
-#define N_BOX_Z (2 * D_BOX_Z + 1)
-#define N_BOX_Y (2 * D_BOX_Y + 1)
-#define N_BOX_X (2 * D_BOX_X + 1)
-#define N_IVEC (N_BOX_Z * N_BOX_Y * N_BOX_X)
-#define CENTRAL (N_IVEC / 2)
-#define SHIFTS N_IVEC
+namespace gmx
+{
+//! Maximum dimensions of grid expressing shifts across PBC
+//! \{
+constexpr int c_dBoxZ = 1;
+constexpr int c_dBoxY = 1;
+constexpr int c_dBoxX = 2;
+//! \}
+namespace detail
+{
+constexpr int c_nBoxZ    = 2 * gmx::c_dBoxZ + 1;
+constexpr int c_nBoxY    = 2 * gmx::c_dBoxY + 1;
+constexpr int c_nBoxX    = 2 * gmx::c_dBoxX + 1;
+constexpr int c_numIvecs = detail::c_nBoxZ * detail::c_nBoxY * detail::c_nBoxX;
+} // namespace detail
 
-#define XYZ2IS(x, y, z) (N_BOX_X * (N_BOX_Y * ((z) + D_BOX_Z) + (y) + D_BOX_Y) + (x) + D_BOX_X)
-#define IVEC2IS(iv) (XYZ2IS((iv)[XX], (iv)[YY], (iv)[ZZ]))
-#define IS2X(iv) (((iv) % N_BOX_X) - D_BOX_X)
-#define IS2Y(iv) ((((iv) / N_BOX_X) % N_BOX_Y) - D_BOX_Y)
-#define IS2Z(iv) ((iv) / (N_BOX_X * N_BOX_Y) - D_BOX_Z)
+constexpr int c_centralShiftIndex = detail::c_numIvecs / 2;
+constexpr int c_numShiftVectors   = detail::c_numIvecs;
 
+//! Convert grid coordinates to shift index
+static inline int xyzToShiftIndex(int x, int y, int z)
+{
+    return (detail::c_nBoxX * (detail::c_nBoxY * ((z) + gmx::c_dBoxZ) + (y) + gmx::c_dBoxY) + (x)
+            + gmx::c_dBoxX);
+}
+
+//! Convert grid coordinates to shift index
+static inline int ivecToShiftIndex(ivec iv)
+{
+    return (xyzToShiftIndex((iv)[XX], (iv)[YY], (iv)[ZZ]));
+}
+
+//! Return the shift in the X dimension of grid space corresponding to \c iv
+static inline int shiftIndexToXDim(int iv)
+{
+    return (((iv) % detail::c_nBoxX) - gmx::c_dBoxX);
+}
+} // namespace gmx
 #endif
index 99824fc17274af270eb60b82cdb891e9cd2ccdb4..b71484d1ea812876e6cd9b283d1c5781a423cdd4 100644 (file)
@@ -124,7 +124,8 @@ static bool mk_igraph(EdgesGenerator* edgesG, int ftype, const T& il, int at_end
                           "You are probably trying to use a trajectory which does "
                           "not match the first %d atoms of the run input file.\n"
                           "You can make a matching run input file with gmx convert-tpr.",
-                          at_end, at_end);
+                          at_end,
+                          at_end);
             }
             if (ftype == F_SETTLE)
             {
@@ -186,10 +187,14 @@ void p_graph(FILE* log, const char* title, const t_graph* g)
     {
         if (!g->edges[i].empty())
         {
-            fprintf(log, "%5d%7d%7d%7d %1s%5zu", g->edgeAtomBegin + i + 1,
-                    g->ishift[g->edgeAtomBegin + i][XX], g->ishift[g->edgeAtomBegin + i][YY],
+            fprintf(log,
+                    "%5d%7d%7d%7d %1s%5zu",
+                    g->edgeAtomBegin + i + 1,
+                    g->ishift[g->edgeAtomBegin + i][XX],
+                    g->ishift[g->edgeAtomBegin + i][YY],
                     g->ishift[g->edgeAtomBegin + i][ZZ],
-                    (!g->edgeColor.empty()) ? cc[g->edgeColor[i]] : " ", g->edges[i].size());
+                    (!g->edgeColor.empty()) ? cc[g->edgeColor[i]] : " ",
+                    g->edges[i].size());
             for (const int edge : g->edges[i])
             {
                 fprintf(log, " %5d", edge + 1);
@@ -293,7 +298,9 @@ static gmx_bool determine_graph_parts(const EdgesGenerator& edgesG, ArrayRef<int
         }
         if (debug)
         {
-            fprintf(debug, "graph partNr[] numAtomsChanged=%d, bMultiPart=%s\n", numAtomsChanged,
+            fprintf(debug,
+                    "graph partNr[] numAtomsChanged=%d, bMultiPart=%s\n",
+                    numAtomsChanged,
                     gmx::boolToString(haveMultipleParts));
         }
     } while (numAtomsChanged > 0);
@@ -625,8 +632,17 @@ static int mk_grey(ArrayRef<egCol> edgeColor,
                         "mk_grey: shifts for atom %d due to atom %d\n"
                         "are (%d,%d,%d), should be (%d,%d,%d)\n"
                         "dx = (%g,%g,%g)\n",
-                        aj + 1, ai + 1, is_aj[XX], is_aj[YY], is_aj[ZZ], g->ishift[aj][XX],
-                        g->ishift[aj][YY], g->ishift[aj][ZZ], dx[XX], dx[YY], dx[ZZ]);
+                        aj + 1,
+                        ai + 1,
+                        is_aj[XX],
+                        is_aj[YY],
+                        is_aj[ZZ],
+                        g->ishift[aj][XX],
+                        g->ishift[aj][YY],
+                        g->ishift[aj][ZZ],
+                        dx[XX],
+                        dx[YY],
+                        dx[ZZ]);
             }
             (*nerror)++;
         }
@@ -788,7 +804,9 @@ void mk_mshift(FILE* log, t_graph* g, PbcType pbcType, const matrix box, const r
                     "There are inconsistent shifts over periodic boundaries in a molecule type "
                     "consisting of %d atoms. The longest distance involved in such interactions is "
                     "%.3f nm which is %s half the box length.",
-                    g->shiftAtomEnd, maxDistance, maxDistance >= 0.5 * minBoxSize ? "above" : "close to");
+                    g->shiftAtomEnd,
+                    maxDistance,
+                    maxDistance >= 0.5 * minBoxSize ? "above" : "close to");
 
             switch (g->parts)
             {
index c741b3f7d6377e781909e7de7a7ec5bbd2c6fdea..7f34a67f8f23bff901e8cdc3fa93875675b4656a 100644 (file)
@@ -63,8 +63,9 @@
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/smalloc.h"
 
-const gmx::EnumerationArray<PbcType, std::string> c_pbcTypeNames = { { "xyz", "no", "xy", "screw",
-                                                                       "unset" } };
+const gmx::EnumerationArray<PbcType, std::string> c_pbcTypeNames = {
+    { "xyz", "no", "xy", "screw", "unset" }
+};
 
 /* Skip 0 so we have more chance of detecting if we forgot to call set_pbc. */
 enum
@@ -165,7 +166,7 @@ const char* check_box(PbcType pbcType, const matrix box)
 void matrix_convert(matrix box, const rvec vec, const rvec angleInDegrees)
 {
     rvec angle;
-    svmul(DEG2RAD, angleInDegrees, angle);
+    svmul(gmx::c_deg2Rad, angleInDegrees, angle);
     box[XX][XX] = vec[XX];
     box[YY][XX] = vec[YY] * cos(angle[ZZ]);
     box[YY][YY] = vec[YY] * sin(angle[ZZ]);
@@ -207,6 +208,7 @@ real max_cutoff2(PbcType pbcType, const matrix box)
 }
 
 //! Set to true if warning has been printed
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static gmx_bool bWarnedGuess = FALSE;
 
 PbcType guessPbcType(const matrix box)
@@ -232,7 +234,9 @@ PbcType guessPbcType(const matrix box)
             fprintf(stderr,
                     "WARNING: Unsupported box diagonal %f %f %f, "
                     "will not use periodic boundary conditions\n\n",
-                    box[XX][XX], box[YY][YY], box[ZZ][ZZ]);
+                    box[XX][XX],
+                    box[YY][YY],
+                    box[ZZ][ZZ]);
             bWarnedGuess = TRUE;
         }
         pbcType = PbcType::No;
@@ -549,9 +553,18 @@ static void low_set_pbc(t_pbc* pbc, PbcType pbcType, const ivec dd_pbc, const ma
                                             fprintf(debug,
                                                     "  tricvec %2d = %2d %2d %2d  %5.2f %5.2f  "
                                                     "%5.2f %5.2f %5.2f  %5.2f %5.2f %5.2f\n",
-                                                    pbc->ntric_vec, i, j, k, sqrt(d2old),
-                                                    sqrt(d2new), trial[XX], trial[YY], trial[ZZ],
-                                                    pos[XX], pos[YY], pos[ZZ]);
+                                                    pbc->ntric_vec,
+                                                    i,
+                                                    j,
+                                                    k,
+                                                    sqrt(d2old),
+                                                    sqrt(d2new),
+                                                    trial[XX],
+                                                    trial[YY],
+                                                    trial[ZZ],
+                                                    pos[XX],
+                                                    pos[YY],
+                                                    pos[ZZ]);
                                         }
                                     }
                                 }
@@ -1053,10 +1066,10 @@ int pbc_dx_aiuc(const t_pbc* pbc, const rvec x1, const rvec x2, rvec dx)
                       "Internal error in pbc_dx_aiuc, set_pbc_dd or set_pbc has not been called");
     }
 
-    is = IVEC2IS(ishift);
+    is = gmx::ivecToShiftIndex(ishift);
     if (debug)
     {
-        range_check_mesg(is, 0, SHIFTS, "PBC shift vector index range check.");
+        range_check_mesg(is, 0, gmx::c_numShiftVectors, "PBC shift vector index range check.");
     }
 
     return is;
@@ -1183,13 +1196,13 @@ void pbc_dx_d(const t_pbc* pbc, const dvec x1, const dvec x2, dvec dx)
     }
 }
 
-void calc_shifts(const matrix box, rvec shift_vec[])
+void calc_shifts(const matrix box, gmx::ArrayRef<gmx::RVec> shift_vec)
 {
-    for (int n = 0, m = -D_BOX_Z; m <= D_BOX_Z; m++)
+    for (int n = 0, m = -gmx::c_dBoxZ; m <= gmx::c_dBoxZ; m++)
     {
-        for (int l = -D_BOX_Y; l <= D_BOX_Y; l++)
+        for (int l = -gmx::c_dBoxY; l <= gmx::c_dBoxY; l++)
         {
-            for (int k = -D_BOX_X; k <= D_BOX_X; k++, n++)
+            for (int k = -gmx::c_dBoxX; k <= gmx::c_dBoxX; k++, n++)
             {
                 for (int d = 0; d < DIM; d++)
                 {
index 1a67c9b98fbc313d10e489bd7150f3be055edee5..acda69c65e9e0469e8c2e1442f0d595e9a8ca2d4 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +43,6 @@
 #include <string>
 
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/real.h"
 struct gmx_domdec_t;
 struct gmx_mtop_t;
 
+namespace gmx
+{
+template<typename>
+class ArrayRef;
+} // namespace gmx
+
 //! Enumeration that contains all supported periodic boundary setups.
 enum class PbcType : int
 {
@@ -195,7 +200,7 @@ PbcType guessPbcType(const matrix box);
  * \param[in] box   The simulation cell
  * \return TRUE when the box was corrected.
  */
-gmx_bool correct_box(FILE* fplog, int step, tensor box);
+bool correct_box(FILE* fplog, int step, tensor box);
 
 /*! \brief Initiate the periodic boundary condition algorithms.
  *
@@ -228,7 +233,7 @@ void set_pbc(t_pbc* pbc, PbcType pbcType, const matrix box);
  * \param[in] box         The box tensor
  * \return the pbc structure when pbc operations are required, NULL otherwise.
  */
-t_pbc* set_pbc_dd(t_pbc* pbc, PbcType pbcType, const ivec domdecCells, gmx_bool bSingleDir, const matrix box);
+t_pbc* set_pbc_dd(t_pbc* pbc, PbcType pbcType, const ivec domdecCells, bool bSingleDir, const matrix box);
 
 /*! \brief Compute distance with PBC
  *
@@ -255,7 +260,7 @@ void pbc_dx(const t_pbc* pbc, const rvec x1, const rvec x2, rvec dx);
  * \param[in]    x2  Coordinates for particle 2
  * \param[out]   dx  Distance vector
  * \return the ishift required to shift x1 at closest distance to x2;
- * i.e. if 0<=ishift<SHIFTS then x1 - x2 + shift_vec[ishift] = dx
+ * i.e. if 0<=ishift<c_numShiftVectors then x1 - x2 + shift_vec[ishift] = dx
  * (see calc_shifts below on how to obtain shift_vec)
  */
 int pbc_dx_aiuc(const t_pbc* pbc, const rvec x1, const rvec x2, rvec dx);
@@ -278,7 +283,7 @@ void pbc_dx_d(const t_pbc* pbc, const dvec x1, const dvec x2, dvec dx);
  * \param[in]  box       The simulation box
  * \param[out] shift_vec The shifting vectors
  */
-void calc_shifts(const matrix box, rvec shift_vec[]);
+void calc_shifts(const matrix box, gmx::ArrayRef<gmx::RVec> shift_vec);
 
 /*! \brief Calculates the center of the box.
  *
index 96661613f6765a10dfcb4f5c1541598ce21f50ee..4911850f4f2f100568303ecb8a62040464a91a3a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_PBCUTIL_PBC_AIUC_CUDA_CUH
 
 #include "gromacs/gpu_utils/vectype_ops.cuh"
+#include "gromacs/pbcutil/ishift.h"
 #include "gromacs/pbcutil/pbc_aiuc.h"
 
+static inline __device__ int xyzToShiftIndex(int x, int y, int z)
+{
+    return (gmx::detail::c_nBoxX * (gmx::detail::c_nBoxY * ((z) + gmx::c_dBoxZ) + (y) + gmx::c_dBoxY)
+            + (x) + gmx::c_dBoxX);
+}
+
+static inline __device__ int int3ToShiftIndex(int3 iv)
+{
+    return (xyzToShiftIndex(iv.x, iv.y, iv.z));
+}
+
 /*! \brief Computes the vector between two points taking PBC into account.
  *
  * Computes the vector dr between points r2 and r1, taking into account the
@@ -102,13 +114,13 @@ static __forceinline__ __device__ int
 
     if (returnShift)
     {
-        ivec ishift;
+        int3 ishift;
 
-        ishift[XX] = -__float2int_rn(shx);
-        ishift[YY] = -__float2int_rn(shy);
-        ishift[ZZ] = -__float2int_rn(shz);
+        ishift.x = -__float2int_rn(shx);
+        ishift.y = -__float2int_rn(shy);
+        ishift.z = -__float2int_rn(shz);
 
-        return IVEC2IS(ishift);
+        return int3ToShiftIndex(ishift);
     }
     else
     {
index eb230a604370212c8adbca08e2a44749ecc9107f..f55da56f8149e6bdfe23a26cdf6c05236c1efadd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 namespace gmx
 {
 
-/*! \brief Names for different centering types.
- *
- * Those names need to be in sync with the CenteringType enum class
- * and reflect the same fields there.
- */
-static EnumerationArray<CenteringType, const char*> c_centeringTypeShortNames = {
-    { "Triclinic", "Rectangular", "Zero-Based" }
-};
-
-/*! \brief Names for different centering types.
- *
- * Those names need to be in sync with the UnitCellType enum class
- * and reflect the same fields there.
- */
-static EnumerationArray<UnitCellType, const char*> c_unitCellTypeShortNames = {
-    { "Triclinic", "Rectangular", "Compact" }
-};
-
 const char* centerTypeNames(CenteringType type)
 {
+    constexpr EnumerationArray<CenteringType, const char*> c_centeringTypeShortNames = {
+        "Triclinic", "Rectangular", "Zero-Based"
+    };
     return c_centeringTypeShortNames[type];
 }
 
 const char* unitCellTypeNames(UnitCellType type)
 {
+    constexpr EnumerationArray<UnitCellType, const char*> c_unitCellTypeShortNames = {
+        "Triclinic", "Rectangular", "Compact"
+    };
     return c_unitCellTypeShortNames[type];
 }
 
index 3b8f887feed3c4c2a19fa0a85717992f67f0a2ac..400c1c84592d81f3db402db0ce32ec777e6f7f16 100644 (file)
@@ -124,14 +124,16 @@ void calc_pbc_cluster(int ecenter, int nrefat, t_topology* top, PbcType pbcType,
                 gmx_fatal(FARGS,
                           "Molecule %d marked for clustering but not atom %d in it - check your "
                           "index!",
-                          i + 1, j + 1);
+                          i + 1,
+                          j + 1);
             }
             else if (!bMol[i] && bTmp[j])
             {
                 gmx_fatal(FARGS,
                           "Atom %d marked for clustering but not molecule %d - this is an internal "
                           "error...",
-                          j + 1, i + 1);
+                          j + 1,
+                          i + 1);
             }
             else if (bMol[i])
             {
@@ -297,7 +299,10 @@ void put_molecule_com_in_box(int      unitcell_enum,
                 fprintf(debug,
                         "\nShifting position of molecule %d "
                         "by %8.3f  %8.3f  %8.3f\n",
-                        i + 1, shift[XX], shift[YY], shift[ZZ]);
+                        i + 1,
+                        shift[XX],
+                        shift[YY],
+                        shift[ZZ]);
             }
             for (j = mols->index[i]; (j < mols->index[i + 1] && j < natoms); j++)
             {
@@ -355,8 +360,12 @@ void put_residue_com_in_box(int     unitcell_enum,
                     fprintf(debug,
                             "\nShifting position of residue %d (atoms %d-%d) "
                             "by %g,%g,%g\n",
-                            atom[res_start].resind + 1, res_start + 1, res_end + 1, shift[XX],
-                            shift[YY], shift[ZZ]);
+                            atom[res_start].resind + 1,
+                            res_start + 1,
+                            res_end + 1,
+                            shift[XX],
+                            shift[YY],
+                            shift[ZZ]);
                 }
                 for (j = res_start; j < res_end; j++)
                 {
index 0a01be35a5dd7cb2b4b64fd4a7e19f88ee114ac6..9f8f591dd7e92f6509d05d9afc341c157f192817 100644 (file)
@@ -101,7 +101,8 @@ static t_graph* gmx_rmpbc_get_graph(gmx_rmpbc_t gpbc, PbcType pbcType, int natom
         {
             gmx_fatal(FARGS,
                       "Structure or trajectory file has more atoms (%d) than the topology (%d)",
-                      natoms, gpbc->natoms_init);
+                      natoms,
+                      gpbc->natoms_init);
         }
         gpbc->ngraph++;
         srenew(gpbc->graph, gpbc->ngraph);
diff --git a/src/gromacs/pbcutil/tests/.clang-tidy b/src/gromacs/pbcutil/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 84249c46b1b2dafd7e59281f071ef3c6bdad4e44..7442b01326dc191f75767d1fd498192fcf733680 100644 (file)
@@ -165,8 +165,8 @@ void COMInPlaceTest::runTestMolecule(const matrix box)
     auto unitcell = std::get<0>(params);
     auto center   = std::get<1>(params);
     auto pbcType  = std::get<2>(params);
-    placeCoordinatesWithCOMInBox(pbcType, unitcell, center, box, testCoordinates_, testTopology_,
-                                 COMShiftType::Molecule);
+    placeCoordinatesWithCOMInBox(
+            pbcType, unitcell, center, box, testCoordinates_, testTopology_, COMShiftType::Molecule);
     std::string testString = "Molecule " + std::string(unitCellTypeNames(unitcell))
                              + std::string(centerTypeNames(center)) + c_pbcTypeNames[pbcType]
                              + c_pbcTypeNames[guessPbcType(box)];
@@ -179,8 +179,8 @@ void COMInPlaceTest::runTestResidue(const matrix box)
     auto unitcell = std::get<0>(params);
     auto center   = std::get<1>(params);
     auto pbcType  = std::get<2>(params);
-    placeCoordinatesWithCOMInBox(pbcType, unitcell, center, box, testCoordinates_, testTopology_,
-                                 COMShiftType::Residue);
+    placeCoordinatesWithCOMInBox(
+            pbcType, unitcell, center, box, testCoordinates_, testTopology_, COMShiftType::Residue);
     std::string testString = "Residue " + std::string(unitCellTypeNames(unitcell))
                              + std::string(centerTypeNames(center)) + c_pbcTypeNames[pbcType]
                              + c_pbcTypeNames[guessPbcType(box)];
index 47e3cf5bbc86b64f8f6ec27e9b1bc980c7245bd3..79c126c41b641dd545aee517d52718f8ad508440 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/math/vectypes.h"
 #include "gromacs/pbcutil/ishift.h"
+#include "gromacs/utility/arrayref.h"
 
 #include "testutils/refdata.h"
 
@@ -61,8 +62,8 @@ TEST(PbcTest, CalcShiftsWorks)
     // Choose box vector entries whose magnitudes will lead to unique
     // shift vector values when the largest box shift in any dimension
     // is two.
-    const matrix box = { { 0.01, 1, -100 }, { 300, -0.03, 3 }, { -6, -600, 0.06 } };
-    rvec         shiftVectors[SHIFTS];
+    const matrix           box = { { 0.01, 1, -100 }, { 300, -0.03, 3 }, { -6, -600, 0.06 } };
+    std::vector<gmx::RVec> shiftVectors(c_numShiftVectors);
 
     calc_shifts(box, shiftVectors);
 
index 2cd5293920680734507fc31ebd8500c022acb590..88fa1a8a50038b9d94f41ced6f6adaca3cbcd70e 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
+# Copyright (c) 2014,2015,2016,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(pulling INTERFACE)
 file(GLOB PULLING_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${PULLING_SOURCES} PARENT_SCOPE)
 
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(pulling PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(pulling PUBLIC
+target_include_directories(pulling INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(pulling PUBLIC
+target_link_libraries(pulling INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when pulling is an OBJECT target
+#target_link_libraries(pulling PUBLIC legacy_api)
+#target_link_libraries(pulling PRIVATE common)
+
+# Module dependencies
+# pulling interfaces convey transitive dependence on these modules.
+#target_link_libraries(pulling PUBLIC
+target_link_libraries(pulling INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(pulling PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(pulling PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index e534415e70a6b3678ed26aa4ecbcab26f4114324..af388dd9a69c87c6f68bc019f744f67313404789 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -91,11 +91,11 @@ static void addToPullxHistory(pull_t* pull)
             pcrdHistory.dr23[m] += pcrd.spatialData.dr23[m];
             pcrdHistory.dr45[m] += pcrd.spatialData.dr45[m];
         }
-        if (pcrd.params.eGeom == epullgCYL)
+        if (pcrd.params.eGeom == PullGroupGeometry::Cylinder)
         {
             for (int m = 0; m < DIM; m++)
             {
-                pcrdHistory.dynaX[m] += pull->dyna[c].x[m];
+                pcrdHistory.dynaX[m] += pcrd.dynamicGroup0->x[m];
             }
         }
     }
@@ -174,11 +174,11 @@ static void pull_print_coord_dr(FILE*                out,
                                 double               referenceValue,
                                 const int            numValuesInSum)
 {
-    const double unit_factor = pull_conversion_factor_internal2userinput(&coordParams);
+    const double unit_factor = pull_conversion_factor_internal2userinput(coordParams);
 
     fprintf(out, "\t%g", pcrdData.value * unit_factor / numValuesInSum);
 
-    if (pullParams.bPrintRefValue && coordParams.eType != epullEXTERNAL)
+    if (pullParams.bPrintRefValue && coordParams.eType != PullingAlgorithm::External)
     {
         fprintf(out, "\t%g", referenceValue * unit_factor / numValuesInSum);
     }
@@ -212,18 +212,18 @@ static void pull_print_x(FILE* out, pull_t* pull, double t)
             pcrdHistory = &pull->coordForceHistory->pullCoordinateSums[c];
 
             numValuesInSum = pull->coordForceHistory->numValuesInXSum;
-            pull_print_coord_dr(out, pull->params, pcrd.params, *pcrdHistory, pcrdHistory->valueRef,
-                                numValuesInSum);
+            pull_print_coord_dr(
+                    out, pull->params, pcrd.params, *pcrdHistory, pcrdHistory->valueRef, numValuesInSum);
         }
         else
         {
-            pull_print_coord_dr(out, pull->params, pcrd.params, pcrd.spatialData, pcrd.value_ref,
-                                numValuesInSum);
+            pull_print_coord_dr(
+                    out, pull->params, pcrd.params, pcrd.spatialData, pcrd.value_ref, numValuesInSum);
         }
 
         if (pull->params.bPrintCOM)
         {
-            if (pcrd.params.eGeom == epullgCYL)
+            if (pcrd.params.eGeom == PullGroupGeometry::Cylinder)
             {
                 for (int m = 0; m < DIM; m++)
                 {
@@ -236,7 +236,7 @@ static void pull_print_x(FILE* out, pull_t* pull, double t)
                         }
                         else
                         {
-                            fprintf(out, "\t%g", pull->dyna[c].x[m]);
+                            fprintf(out, "\t%g", pcrd.dynamicGroup0->x[m]);
                         }
                     }
                 }
@@ -249,7 +249,8 @@ static void pull_print_x(FILE* out, pull_t* pull, double t)
                     {
                         if (pull->bXOutAverage)
                         {
-                            fprintf(out, "\t%g",
+                            fprintf(out,
+                                    "\t%g",
                                     pull->coordForceHistory->pullGroupSums[pcrd.params.group[0]].x[m]
                                             / numValuesInSum);
                         }
@@ -268,7 +269,8 @@ static void pull_print_x(FILE* out, pull_t* pull, double t)
                     {
                         if (pull->bXOutAverage)
                         {
-                            fprintf(out, "\t%g",
+                            fprintf(out,
+                                    "\t%g",
                                     pull->coordForceHistory->pullGroupSums[pcrd.params.group[g]].x[m]
                                             / numValuesInSum);
                         }
@@ -297,7 +299,8 @@ static void pull_print_f(FILE* out, const pull_t* pull, double t)
     {
         for (size_t c = 0; c < pull->coord.size(); c++)
         {
-            fprintf(out, "\t%g",
+            fprintf(out,
+                    "\t%g",
                     pull->coordForceHistory->pullCoordinateSums[c].scalarForce
                             / pull->coordForceHistory->numValuesInFSum);
         }
@@ -438,8 +441,8 @@ static FILE* open_pull_out(const char*             fn,
          * the group COMs for all the groups (+ ngroups_max*DIM)
          * and the components of the distance vectors can be printed (+ (ngroups_max/2)*DIM).
          */
-        snew(setname, pull->coord.size()
-                              * (1 + 1 + c_pullCoordNgroupMax * DIM + c_pullCoordNgroupMax / 2 * DIM));
+        snew(setname,
+             pull->coord.size() * (1 + 1 + c_pullCoordNgroupMax * DIM + c_pullCoordNgroupMax / 2 * DIM));
 
         nsets = 0;
         for (size_t c = 0; c < pull->coord.size(); c++)
@@ -454,7 +457,7 @@ static FILE* open_pull_out(const char*             fn,
                 sprintf(buf, "%zu", c + 1);
                 setname[nsets] = gmx_strdup(buf);
                 nsets++;
-                if (pull->params.bPrintRefValue && pull->coord[c].params.eType != epullEXTERNAL)
+                if (pull->params.bPrintRefValue && pull->coord[c].params.eType != PullingAlgorithm::External)
                 {
                     sprintf(buf, "%zu ref", c + 1);
                     setname[nsets] = gmx_strdup(buf);
index 7727fe15f6708f7c5e76e29e916525c5f2f78879..e40cecf28c11063bdd62df118f84902ac499f880 100644 (file)
@@ -48,6 +48,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <mutex>
 
 #include "gromacs/commandline/filenm.h"
 #include "gromacs/domdec/domdec_struct.h"
@@ -57,6 +58,7 @@
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/mdlib/gmx_omp_nthreads.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/topology/mtop_lookup.h"
 #include "gromacs/topology/topology.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/gmxassert.h"
-#include "gromacs/utility/mutex.h"
 #include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/real.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/strconvert.h"
+#include "gromacs/utility/stringutil.h"
 
 #include "pull_internal.h"
 
@@ -86,6 +90,14 @@ namespace gmx
 extern template LocalAtomSet LocalAtomSetManager::add<void, void>(ArrayRef<const int> globalAtomIndex);
 } // namespace gmx
 
+using gmx::ArrayRef;
+using gmx::RVec;
+
+/*! \brief Tells whether the pull geometry is an angle type */
+constexpr gmx::EnumerationArray<PullGroupGeometry, bool> sc_isAngleType = {
+    { false, false, false, false, false, true, true, true }
+};
+
 static int groupPbcFromParams(const t_pull_group& params, bool setPbcRefToPrevStepCOM)
 {
     if (params.ind.size() <= 1)
@@ -117,9 +129,11 @@ static int groupPbcFromParams(const t_pull_group& params, bool setPbcRefToPrevSt
  */
 pull_group_work_t::pull_group_work_t(const t_pull_group& params,
                                      gmx::LocalAtomSet   atomSet,
-                                     bool                bSetPbcRefToPrevStepCOM) :
+                                     bool                bSetPbcRefToPrevStepCOM,
+                                     int                 maxNumThreads) :
     params(params),
     epgrppbc(groupPbcFromParams(params, bSetPbcRefToPrevStepCOM)),
+    maxNumThreads(maxNumThreads),
     needToCalcCom(false),
     atomSet(atomSet),
     mwscale(0),
@@ -130,27 +144,23 @@ pull_group_work_t::pull_group_work_t(const t_pull_group& params,
     clear_dvec(xp);
 };
 
-bool pull_coordinate_is_angletype(const t_pull_coord* pcrd)
-{
-    return (pcrd->eGeom == epullgANGLE || pcrd->eGeom == epullgDIHEDRAL || pcrd->eGeom == epullgANGLEAXIS);
-}
-
 static bool pull_coordinate_is_directional(const t_pull_coord* pcrd)
 {
-    return (pcrd->eGeom == epullgDIR || pcrd->eGeom == epullgDIRPBC
-            || pcrd->eGeom == epullgDIRRELATIVE || pcrd->eGeom == epullgCYL);
+    return (pcrd->eGeom == PullGroupGeometry::Direction || pcrd->eGeom == PullGroupGeometry::DirectionPBC
+            || pcrd->eGeom == PullGroupGeometry::DirectionRelative
+            || pcrd->eGeom == PullGroupGeometry::Cylinder);
 }
 
-const char* pull_coordinate_units(const t_pull_coord* pcrd)
+const char* pull_coordinate_units(const t_pull_coord& pcrd)
 {
-    return pull_coordinate_is_angletype(pcrd) ? "deg" : "nm";
+    return sc_isAngleType[pcrd.eGeom] ? "deg" : "nm";
 }
 
-double pull_conversion_factor_userinput2internal(const t_pull_coord* pcrd)
+double pull_conversion_factor_userinput2internal(const t_pull_coord& pcrd)
 {
-    if (pull_coordinate_is_angletype(pcrd))
+    if (sc_isAngleType[pcrd.eGeom])
     {
-        return DEG2RAD;
+        return gmx::c_deg2Rad;
     }
     else
     {
@@ -158,11 +168,11 @@ double pull_conversion_factor_userinput2internal(const t_pull_coord* pcrd)
     }
 }
 
-double pull_conversion_factor_internal2userinput(const t_pull_coord* pcrd)
+double pull_conversion_factor_internal2userinput(const t_pull_coord& pcrd)
 {
-    if (pull_coordinate_is_angletype(pcrd))
+    if (sc_isAngleType[pcrd.eGeom])
     {
-        return RAD2DEG;
+        return gmx::c_rad2Deg;
     }
     else
     {
@@ -171,24 +181,24 @@ double pull_conversion_factor_internal2userinput(const t_pull_coord* pcrd)
 }
 
 /* Apply forces in a mass weighted fashion for part of the pull group */
-static void apply_forces_grp_part(const pull_group_work_t* pgrp,
+static void apply_forces_grp_part(const pull_group_work_t& pgrp,
                                   int                      ind_start,
                                   int                      ind_end,
-                                  const real*              masses,
+                                  ArrayRef<const real>     masses,
                                   const dvec               f_pull,
-                                  int                      sign,
+                                  const int                sign,
                                   rvec*                    f)
 {
-    double inv_wm = pgrp->mwscale;
+    const double inv_wm = pgrp.mwscale;
 
-    auto localAtomIndices = pgrp->atomSet.localIndex();
+    auto localAtomIndices = pgrp.atomSet.localIndex();
     for (int i = ind_start; i < ind_end; i++)
     {
         int    ii    = localAtomIndices[i];
         double wmass = masses[ii];
-        if (!pgrp->localWeights.empty())
+        if (!pgrp.localWeights.empty())
         {
-            wmass *= pgrp->localWeights[i];
+            wmass *= pgrp.localWeights[i];
         }
 
         for (int d = 0; d < DIM; d++)
@@ -199,16 +209,15 @@ static void apply_forces_grp_part(const pull_group_work_t* pgrp,
 }
 
 /* Apply forces in a mass weighted fashion */
-static void apply_forces_grp(const pull_group_work_t* pgrp,
-                             const real*              masses,
+static void apply_forces_grp(const pull_group_work_t& pgrp,
+                             ArrayRef<const real>     masses,
                              const dvec               f_pull,
-                             int                      sign,
-                             rvec*                    f,
-                             int                      nthreads)
+                             const int                sign,
+                             rvec*                    f)
 {
-    auto localAtomIndices = pgrp->atomSet.localIndex();
+    auto localAtomIndices = pgrp.atomSet.localIndex();
 
-    if (pgrp->params.ind.size() == 1 && pgrp->atomSet.numAtomsLocal() == 1)
+    if (pgrp.params.ind.size() == 1 && pgrp.atomSet.numAtomsLocal() == 1)
     {
         /* Only one atom and our rank has this atom: we can skip
          * the mass weighting, which means that this code also works
@@ -221,17 +230,18 @@ static void apply_forces_grp(const pull_group_work_t* pgrp,
     }
     else
     {
-        if (localAtomIndices.size() <= c_pullMaxNumLocalAtomsSingleThreaded)
+        const int numThreads = pgrp.numThreads();
+        if (numThreads == 1)
         {
             apply_forces_grp_part(pgrp, 0, localAtomIndices.size(), masses, f_pull, sign, f);
         }
         else
         {
-#pragma omp parallel for num_threads(nthreads) schedule(static)
-            for (int th = 0; th < nthreads; th++)
+#pragma omp parallel for num_threads(numThreads) schedule(static)
+            for (int th = 0; th < numThreads; th++)
             {
-                int ind_start = (localAtomIndices.size() * (th + 0)) / nthreads;
-                int ind_end   = (localAtomIndices.size() * (th + 1)) / nthreads;
+                int ind_start = (localAtomIndices.size() * (th + 0)) / numThreads;
+                int ind_end   = (localAtomIndices.size() * (th + 1)) / numThreads;
                 apply_forces_grp_part(pgrp, ind_start, ind_end, masses, f_pull, sign, f);
             }
         }
@@ -239,27 +249,27 @@ static void apply_forces_grp(const pull_group_work_t* pgrp,
 }
 
 /* Apply forces in a mass weighted fashion to a cylinder group */
-static void apply_forces_cyl_grp(const pull_group_work_t* pgrp,
+static void apply_forces_cyl_grp(const pull_group_work_t& pgrp,
                                  const double             dv_corr,
-                                 const real*              masses,
+                                 ArrayRef<const real>     masses,
                                  const dvec               f_pull,
                                  double                   f_scal,
-                                 int                      sign,
-                                 rvec*                    f,
-                                 int gmx_unused nthreads)
+                                 const int                sign,
+                                 rvec*                    f)
 {
-    double inv_wm = pgrp->mwscale;
+    const double inv_wm = pgrp.mwscale;
 
-    auto localAtomIndices = pgrp->atomSet.localIndex();
+    auto localAtomIndices = pgrp.atomSet.localIndex();
 
     /* The cylinder group is always a slab in the system, thus large.
      * Therefore we always thread-parallelize this group.
      */
-    int numAtomsLocal = localAtomIndices.size();
-#pragma omp parallel for num_threads(nthreads) schedule(static)
+    const int numAtomsLocal         = localAtomIndices.size();
+    const int gmx_unused numThreads = pgrp.numThreads();
+#pragma omp parallel for num_threads(numThreads) schedule(static)
     for (int i = 0; i < numAtomsLocal; i++)
     {
-        double weight = pgrp->localWeights[i];
+        double weight = pgrp.localWeights[i];
         if (weight == 0)
         {
             continue;
@@ -270,7 +280,7 @@ static void apply_forces_cyl_grp(const pull_group_work_t* pgrp,
          * to be corrected for an offset (dv_corr), which was unknown when
          * we calculated dv.
          */
-        double dv_com = pgrp->dv[i] + dv_corr;
+        double dv_com = pgrp.dv[i] + dv_corr;
 
         /* Here we not only add the pull force working along vec (f_pull),
          * but also a radial component, due to the dependence of the weights
@@ -278,7 +288,7 @@ static void apply_forces_cyl_grp(const pull_group_work_t* pgrp,
          */
         for (int m = 0; m < DIM; m++)
         {
-            f[ii][m] += sign * inv_wm * (mass * weight * f_pull[m] + pgrp->mdw[i][m] * dv_com * f_scal);
+            f[ii][m] += sign * inv_wm * (mass * weight * f_pull[m] + pgrp.mdw[i][m] * dv_com * f_scal);
         }
     }
 }
@@ -286,12 +296,12 @@ static void apply_forces_cyl_grp(const pull_group_work_t* pgrp,
 /* Apply torque forces in a mass weighted fashion to the groups that define
  * the pull vector direction for pull coordinate pcrd.
  */
-static void apply_forces_vec_torque(const struct pull_t*     pull,
-                                    const pull_coord_work_t* pcrd,
-                                    const real*              masses,
-                                    rvec*                    f)
+static void apply_forces_vec_torque(const pull_coord_work_t&          pcrd,
+                                    ArrayRef<const pull_group_work_t> pullGroups,
+                                    ArrayRef<const real>              masses,
+                                    rvec*                             f)
 {
-    const PullCoordSpatialData& spatialData = pcrd->spatialData;
+    const PullCoordSpatialData& spatialData = pcrd.spatialData;
 
     /* The component inpr along the pull vector is accounted for in the usual
      * way. Here we account for the component perpendicular to vec.
@@ -310,20 +320,20 @@ static void apply_forces_vec_torque(const struct pull_t*     pull,
     dvec f_perp;
     for (int m = 0; m < DIM; m++)
     {
-        f_perp[m] = (spatialData.dr01[m] - inpr * spatialData.vec[m]) / spatialData.vec_len * pcrd->scalarForce;
+        f_perp[m] = (spatialData.dr01[m] - inpr * spatialData.vec[m]) / spatialData.vec_len * pcrd.scalarForce;
     }
 
     /* Apply the force to the groups defining the vector using opposite signs */
-    apply_forces_grp(&pull->group[pcrd->params.group[2]], masses, f_perp, -1, f, pull->nthreads);
-    apply_forces_grp(&pull->group[pcrd->params.group[3]], masses, f_perp, 1, f, pull->nthreads);
+    apply_forces_grp(pullGroups[pcrd.params.group[2]], masses, f_perp, -1, f);
+    apply_forces_grp(pullGroups[pcrd.params.group[3]], masses, f_perp, 1, f);
 }
 
 /* Apply forces in a mass weighted fashion */
-static void apply_forces_coord(struct pull_t*               pull,
-                               int                          coord,
-                               const PullCoordVectorForces& forces,
-                               const real*                  masses,
-                               rvec*                        f)
+static void apply_forces_coord(const pull_coord_work_t&          pcrd,
+                               ArrayRef<const pull_group_work_t> pullGroups,
+                               const PullCoordVectorForces&      forces,
+                               ArrayRef<const real>              masses,
+                               rvec*                             f)
 {
     /* Here it would be more efficient to use one large thread-parallel
      * region instead of potential parallel regions within apply_forces_grp.
@@ -331,12 +341,10 @@ static void apply_forces_coord(struct pull_t*               pull,
      * to data races.
      */
 
-    const pull_coord_work_t& pcrd = pull->coord[coord];
-
-    if (pcrd.params.eGeom == epullgCYL)
+    if (pcrd.params.eGeom == PullGroupGeometry::Cylinder)
     {
-        apply_forces_cyl_grp(&pull->dyna[coord], pcrd.spatialData.cyl_dev, masses, forces.force01,
-                             pcrd.scalarForce, -1, f, pull->nthreads);
+        apply_forces_cyl_grp(
+                *pcrd.dynamicGroup0, pcrd.spatialData.cyl_dev, masses, forces.force01, pcrd.scalarForce, -1, f);
 
         /* Sum the force along the vector and the radial force */
         dvec f_tot;
@@ -344,38 +352,33 @@ static void apply_forces_coord(struct pull_t*               pull,
         {
             f_tot[m] = forces.force01[m] + pcrd.scalarForce * pcrd.spatialData.ffrad[m];
         }
-        apply_forces_grp(&pull->group[pcrd.params.group[1]], masses, f_tot, 1, f, pull->nthreads);
+        apply_forces_grp(pullGroups[pcrd.params.group[1]], masses, f_tot, 1, f);
     }
     else
     {
-        if (pcrd.params.eGeom == epullgDIRRELATIVE)
+        if (pcrd.params.eGeom == PullGroupGeometry::DirectionRelative)
         {
             /* We need to apply the torque forces to the pull groups
              * that define the pull vector.
              */
-            apply_forces_vec_torque(pull, &pcrd, masses, f);
+            apply_forces_vec_torque(pcrd, pullGroups, masses, f);
         }
 
-        if (!pull->group[pcrd.params.group[0]].params.ind.empty())
+        if (!pullGroups[pcrd.params.group[0]].params.ind.empty())
         {
-            apply_forces_grp(&pull->group[pcrd.params.group[0]], masses, forces.force01, -1, f,
-                             pull->nthreads);
+            apply_forces_grp(pullGroups[pcrd.params.group[0]], masses, forces.force01, -1, f);
         }
-        apply_forces_grp(&pull->group[pcrd.params.group[1]], masses, forces.force01, 1, f, pull->nthreads);
+        apply_forces_grp(pullGroups[pcrd.params.group[1]], masses, forces.force01, 1, f);
 
         if (pcrd.params.ngroup >= 4)
         {
-            apply_forces_grp(&pull->group[pcrd.params.group[2]], masses, forces.force23, -1, f,
-                             pull->nthreads);
-            apply_forces_grp(&pull->group[pcrd.params.group[3]], masses, forces.force23, 1, f,
-                             pull->nthreads);
+            apply_forces_grp(pullGroups[pcrd.params.group[2]], masses, forces.force23, -1, f);
+            apply_forces_grp(pullGroups[pcrd.params.group[3]], masses, forces.force23, 1, f);
         }
         if (pcrd.params.ngroup >= 6)
         {
-            apply_forces_grp(&pull->group[pcrd.params.group[4]], masses, forces.force45, -1, f,
-                             pull->nthreads);
-            apply_forces_grp(&pull->group[pcrd.params.group[5]], masses, forces.force45, 1, f,
-                             pull->nthreads);
+            apply_forces_grp(pullGroups[pcrd.params.group[4]], masses, forces.force45, -1, f);
+            apply_forces_grp(pullGroups[pcrd.params.group[5]], masses, forces.force45, 1, f);
         }
     }
 }
@@ -456,32 +459,36 @@ real max_pull_distance2(const pull_coord_work_t* pcrd, const t_pbc* pbc)
  * \param[in]  max_dist2    The maximum distance squared
  * \param[out] dr           The distance vector
  */
-static void low_get_pull_coord_dr(const struct pull_t*     pull,
+static void low_get_pull_coord_dr(const pull_t&            pull,
                                   const pull_coord_work_t* pcrd,
                                   const t_pbc*             pbc,
                                   const dvec               xg,
-                                  dvec                     xref,
+                                  const dvec               xref,
                                   const int                groupIndex0,
                                   const int                groupIndex1,
                                   const double             max_dist2,
                                   dvec                     dr)
 {
-    const pull_group_work_t* pgrp0 = &pull->group[pcrd->params.group[0]];
+    const pull_group_work_t& pgrp0 = pull.group[pcrd->params.group[0]];
+
+    // Group coordinate, to be updated with the reference position
+    dvec xrefr;
 
     /* Only the first group can be an absolute reference, in that case nat=0 */
-    if (pgrp0->params.ind.empty())
+    if (pgrp0.params.ind.empty())
     {
         for (int m = 0; m < DIM; m++)
         {
-            xref[m] = pcrd->params.origin[m];
+            xrefr[m] = pcrd->params.origin[m];
         }
     }
-
-    dvec xrefr;
-    copy_dvec(xref, xrefr);
+    else
+    {
+        copy_dvec(xref, xrefr);
+    }
 
     dvec dref = { 0, 0, 0 };
-    if (pcrd->params.eGeom == epullgDIRPBC)
+    if (pcrd->params.eGeom == PullGroupGeometry::DirectionPBC)
     {
         for (int m = 0; m < DIM; m++)
         {
@@ -514,11 +521,17 @@ static void low_get_pull_coord_dr(const struct pull_t*     pull,
         gmx_fatal(FARGS,
                   "Distance between pull groups %d and %d (%f nm) is larger than 0.49 times the "
                   "box size (%f).\n%s",
-                  pcrd->params.group[groupIndex0], pcrd->params.group[groupIndex1], sqrt(dr2),
-                  sqrt(0.98 * 0.98 * max_dist2), pcrd->params.eGeom == epullgDIR ? "You might want to consider using \"pull-geometry = direction-periodic\" instead.\n" : "");
+                  pcrd->params.group[groupIndex0],
+                  pcrd->params.group[groupIndex1],
+                  sqrt(dr2),
+                  sqrt(0.98 * 0.98 * max_dist2),
+                  pcrd->params.eGeom == PullGroupGeometry::Direction
+                          ? "You might want to consider using \"pull-geometry = "
+                            "direction-periodic\" instead.\n"
+                          : "");
     }
 
-    if (pcrd->params.eGeom == epullgDIRPBC)
+    if (pcrd->params.eGeom == PullGroupGeometry::DirectionPBC)
     {
         dvec_inc(dr, dref);
     }
@@ -527,17 +540,19 @@ static void low_get_pull_coord_dr(const struct pull_t*     pull,
 /* This function returns the distance based on the contents of the pull struct.
  * pull->coord[coord_ind].dr, and potentially vector, are updated.
  */
-static void get_pull_coord_dr(struct pull_t* pull, int coord_ind, const t_pbc* pbc)
+static void get_pull_coord_dr(const pull_t& pull, pull_coord_work_t* pcrd, const t_pbc* pbc)
 {
-    pull_coord_work_t*    pcrd        = &pull->coord[coord_ind];
+    const int coord_ind = pcrd->params.coordIndex;
+
     PullCoordSpatialData& spatialData = pcrd->spatialData;
 
     double md2;
     /* With AWH pulling we allow for periodic pulling with geometry=direction.
      * TODO: Store a periodicity flag instead of checking for external pull provider.
      */
-    if (pcrd->params.eGeom == epullgDIRPBC
-        || (pcrd->params.eGeom == epullgDIR && pcrd->params.eType == epullEXTERNAL))
+    if (pcrd->params.eGeom == PullGroupGeometry::DirectionPBC
+        || (pcrd->params.eGeom == PullGroupGeometry::Direction
+            && pcrd->params.eType == PullingAlgorithm::External))
     {
         md2 = -1;
     }
@@ -546,14 +561,14 @@ static void get_pull_coord_dr(struct pull_t* pull, int coord_ind, const t_pbc* p
         md2 = static_cast<double>(max_pull_distance2(pcrd, pbc));
     }
 
-    if (pcrd->params.eGeom == epullgDIRRELATIVE)
+    if (pcrd->params.eGeom == PullGroupGeometry::DirectionRelative)
     {
         /* We need to determine the pull vector */
         dvec vec;
         int  m;
 
-        const pull_group_work_t& pgrp2 = pull->group[pcrd->params.group[2]];
-        const pull_group_work_t& pgrp3 = pull->group[pcrd->params.group[3]];
+        const pull_group_work_t& pgrp2 = pull.group[pcrd->params.group[2]];
+        const pull_group_work_t& pgrp3 = pull.group[pcrd->params.group[3]];
 
         pbc_dx_d(pbc, pgrp3.x, pgrp2.x, vec);
 
@@ -568,34 +583,45 @@ static void get_pull_coord_dr(struct pull_t* pull, int coord_ind, const t_pbc* p
         }
         if (debug)
         {
-            fprintf(debug, "pull coord %d vector: %6.3f %6.3f %6.3f normalized: %6.3f %6.3f %6.3f\n",
-                    coord_ind, vec[XX], vec[YY], vec[ZZ], spatialData.vec[XX], spatialData.vec[YY],
+            fprintf(debug,
+                    "pull coord %d vector: %6.3f %6.3f %6.3f normalized: %6.3f %6.3f %6.3f\n",
+                    coord_ind,
+                    vec[XX],
+                    vec[YY],
+                    vec[ZZ],
+                    spatialData.vec[XX],
+                    spatialData.vec[YY],
                     spatialData.vec[ZZ]);
         }
     }
 
-    pull_group_work_t* pgrp0 = &pull->group[pcrd->params.group[0]];
-    pull_group_work_t* pgrp1 = &pull->group[pcrd->params.group[1]];
+    const pull_group_work_t& pgrp0 = pull.group[pcrd->params.group[0]];
+    const pull_group_work_t& pgrp1 = pull.group[pcrd->params.group[1]];
 
-    low_get_pull_coord_dr(pull, pcrd, pbc, pgrp1->x,
-                          pcrd->params.eGeom == epullgCYL ? pull->dyna[coord_ind].x : pgrp0->x, 0,
-                          1, md2, spatialData.dr01);
+    low_get_pull_coord_dr(
+            pull,
+            pcrd,
+            pbc,
+            pgrp1.x,
+            pcrd->params.eGeom == PullGroupGeometry::Cylinder ? pcrd->dynamicGroup0->x : pgrp0.x,
+            0,
+            1,
+            md2,
+            spatialData.dr01);
 
     if (pcrd->params.ngroup >= 4)
     {
-        pull_group_work_t *pgrp2, *pgrp3;
-        pgrp2 = &pull->group[pcrd->params.group[2]];
-        pgrp3 = &pull->group[pcrd->params.group[3]];
+        const pull_group_work_t& pgrp2 = pull.group[pcrd->params.group[2]];
+        const pull_group_work_t& pgrp3 = pull.group[pcrd->params.group[3]];
 
-        low_get_pull_coord_dr(pull, pcrd, pbc, pgrp3->x, pgrp2->x, 2, 3, md2, spatialData.dr23);
+        low_get_pull_coord_dr(pull, pcrd, pbc, pgrp3.x, pgrp2.x, 2, 3, md2, spatialData.dr23);
     }
     if (pcrd->params.ngroup >= 6)
     {
-        pull_group_work_t *pgrp4, *pgrp5;
-        pgrp4 = &pull->group[pcrd->params.group[4]];
-        pgrp5 = &pull->group[pcrd->params.group[5]];
+        const pull_group_work_t& pgrp4 = pull.group[pcrd->params.group[4]];
+        const pull_group_work_t& pgrp5 = pull.group[pcrd->params.group[5]];
 
-        low_get_pull_coord_dr(pull, pcrd, pbc, pgrp5->x, pgrp4->x, 4, 5, md2, spatialData.dr45);
+        low_get_pull_coord_dr(pull, pcrd, pbc, pgrp5.x, pgrp4.x, 4, 5, md2, spatialData.dr45);
     }
 }
 
@@ -615,49 +641,52 @@ static void make_periodic_2pi(double* x)
     }
 }
 
-/* This function should always be used to modify pcrd->value_ref */
-static void low_set_pull_coord_reference_value(pull_coord_work_t* pcrd, int coord_ind, double value_ref)
+/* This function should always be used to get values for setting value_ref in pull_coord_work_t */
+static double sanitizePullCoordReferenceValue(const t_pull_coord& pcrdParams, double value_ref)
 {
-    GMX_ASSERT(pcrd->params.eType != epullEXTERNAL,
+    GMX_ASSERT(pcrdParams.eType != PullingAlgorithm::External,
                "The pull coord reference value should not be used with type external-potential");
 
-    if (pcrd->params.eGeom == epullgDIST)
+    if (pcrdParams.eGeom == PullGroupGeometry::Distance)
     {
         if (value_ref < 0)
         {
             gmx_fatal(FARGS,
                       "Pull reference distance for coordinate %d (%f) needs to be non-negative",
-                      coord_ind + 1, value_ref);
+                      pcrdParams.coordIndex + 1,
+                      value_ref);
         }
     }
-    else if (pcrd->params.eGeom == epullgANGLE || pcrd->params.eGeom == epullgANGLEAXIS)
+    else if (pcrdParams.eGeom == PullGroupGeometry::Angle || pcrdParams.eGeom == PullGroupGeometry::AngleAxis)
     {
         if (value_ref < 0 || value_ref > M_PI)
         {
             gmx_fatal(FARGS,
                       "Pull reference angle for coordinate %d (%f) needs to be in the allowed "
                       "interval [0,180] deg",
-                      coord_ind + 1,
-                      value_ref * pull_conversion_factor_internal2userinput(&pcrd->params));
+                      pcrdParams.coordIndex + 1,
+                      value_ref * pull_conversion_factor_internal2userinput(pcrdParams));
         }
     }
-    else if (pcrd->params.eGeom == epullgDIHEDRAL)
+    else if (pcrdParams.eGeom == PullGroupGeometry::Dihedral)
     {
         /* Allow pulling to be periodic for dihedral angles by remapping the reference value to the interval [-pi, pi). */
         make_periodic_2pi(&value_ref);
     }
 
-    pcrd->value_ref = value_ref;
+    return value_ref;
 }
 
-static void update_pull_coord_reference_value(pull_coord_work_t* pcrd, int coord_ind, double t)
+static void updatePullCoordReferenceValue(double* referenceValue, const t_pull_coord& pcrdParams, double t)
 {
+    GMX_ASSERT(referenceValue, "Need a valid reference value object");
+
     /* With zero rate the reference value is set initially and doesn't change */
-    if (pcrd->params.rate != 0)
+    if (pcrdParams.rate != 0)
     {
-        double value_ref = (pcrd->params.init + pcrd->params.rate * t)
-                           * pull_conversion_factor_userinput2internal(&pcrd->params);
-        low_set_pull_coord_reference_value(pcrd, coord_ind, value_ref);
+        const double inputValue = (pcrdParams.init + pcrdParams.rate * t)
+                                  * pull_conversion_factor_userinput2internal(pcrdParams);
+        *referenceValue = sanitizePullCoordReferenceValue(pcrdParams, inputValue);
     }
 }
 
@@ -685,39 +714,36 @@ static double get_dihedral_angle_coord(PullCoordSpatialData* spatialData)
 /* Calculates pull->coord[coord_ind].value.
  * This function also updates pull->coord[coord_ind].dr.
  */
-static void get_pull_coord_distance(struct pull_t* pull, int coord_ind, const t_pbc* pbc)
+static void get_pull_coord_distance(const pull_t& pull, pull_coord_work_t* pcrd, const t_pbc* pbc)
 {
-    pull_coord_work_t* pcrd;
-    int                m;
-
-    pcrd = &pull->coord[coord_ind];
-
-    get_pull_coord_dr(pull, coord_ind, pbc);
+    get_pull_coord_dr(pull, pcrd, pbc);
 
     PullCoordSpatialData& spatialData = pcrd->spatialData;
 
     switch (pcrd->params.eGeom)
     {
-        case epullgDIST:
+        case PullGroupGeometry::Distance:
             /* Pull along the vector between the com's */
             spatialData.value = dnorm(spatialData.dr01);
             break;
-        case epullgDIR:
-        case epullgDIRPBC:
-        case epullgDIRRELATIVE:
-        case epullgCYL:
+        case PullGroupGeometry::Direction:
+        case PullGroupGeometry::DirectionPBC:
+        case PullGroupGeometry::DirectionRelative:
+        case PullGroupGeometry::Cylinder:
             /* Pull along vec */
             spatialData.value = 0;
-            for (m = 0; m < DIM; m++)
+            for (int m = 0; m < DIM; m++)
             {
                 spatialData.value += spatialData.vec[m] * spatialData.dr01[m];
             }
             break;
-        case epullgANGLE:
+        case PullGroupGeometry::Angle:
             spatialData.value = gmx_angle_between_dvecs(spatialData.dr01, spatialData.dr23);
             break;
-        case epullgDIHEDRAL: spatialData.value = get_dihedral_angle_coord(&spatialData); break;
-        case epullgANGLEAXIS:
+        case PullGroupGeometry::Dihedral:
+            spatialData.value = get_dihedral_angle_coord(&spatialData);
+            break;
+        case PullGroupGeometry::AngleAxis:
             spatialData.value = gmx_angle_between_dvecs(spatialData.dr01, spatialData.vec);
             break;
         default: gmx_incons("Unsupported pull type in get_pull_coord_distance");
@@ -727,34 +753,31 @@ static void get_pull_coord_distance(struct pull_t* pull, int coord_ind, const t_
 /* Returns the deviation from the reference value.
  * Updates pull->coord[coord_ind].dr, .value and .value_ref.
  */
-static double get_pull_coord_deviation(struct pull_t* pull, int coord_ind, const t_pbc* pbc, double t)
+static double get_pull_coord_deviation(const pull_t& pull, pull_coord_work_t* pcrd, const t_pbc* pbc, double t)
 {
-    pull_coord_work_t* pcrd;
-    double             dev = 0;
-
-    pcrd = &pull->coord[coord_ind];
+    double dev = 0;
 
     /* Update the reference value before computing the distance,
      * since it is used in the distance computation with periodic pulling.
      */
-    update_pull_coord_reference_value(pcrd, coord_ind, t);
+    updatePullCoordReferenceValue(&pcrd->value_ref, pcrd->params, t);
 
-    get_pull_coord_distance(pull, coord_ind, pbc);
+    get_pull_coord_distance(pull, pcrd, pbc);
 
-    get_pull_coord_distance(pull, coord_ind, pbc);
+    get_pull_coord_distance(pull, pcrd, pbc);
 
     /* Determine the deviation */
     dev = pcrd->spatialData.value - pcrd->value_ref;
 
     /* Check that values are allowed */
-    if (pcrd->params.eGeom == epullgDIST && pcrd->spatialData.value == 0)
+    if (pcrd->params.eGeom == PullGroupGeometry::Distance && pcrd->spatialData.value == 0)
     {
         /* With no vector we can not determine the direction for the force,
          * so we set the force to zero.
          */
         dev = 0;
     }
-    else if (pcrd->params.eGeom == epullgDIHEDRAL)
+    else if (pcrd->params.eGeom == PullGroupGeometry::Dihedral)
     {
         /* The reference value is in [-pi, pi). The coordinate value is in (-pi, pi].
            Thus, the unwrapped deviation is here in (-2pi, 2pi].
@@ -765,9 +788,9 @@ static double get_pull_coord_deviation(struct pull_t* pull, int coord_ind, const
     return dev;
 }
 
-double get_pull_coord_value(struct pull_t* pull, int coord_ind, const t_pbc* pbc)
+double get_pull_coord_value(pull_t* pull, int coord_ind, const t_pbc* pbc)
 {
-    get_pull_coord_distance(pull, coord_ind, pbc);
+    get_pull_coord_distance(*pull, &pull->coord[coord_ind], pbc);
 
     return pull->coord[coord_ind].spatialData.value;
 }
@@ -785,8 +808,14 @@ void clear_pull_forces(pull_t* pull)
 }
 
 /* Apply constraint using SHAKE */
-static void
-do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaster, tensor vir, double dt, double t)
+static void do_constraint(struct pull_t* pull,
+                          t_pbc*         pbc,
+                          ArrayRef<RVec> x,
+                          ArrayRef<RVec> v,
+                          gmx_bool       bMaster,
+                          tensor         vir,
+                          double         dt,
+                          double         t)
 {
 
     dvec*    r_ij;   /* x[i] com of i in prev. step. Obeys constr. -> r_ij[i] */
@@ -821,7 +850,7 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
 
         pcrd = &pull->coord[c];
 
-        if (pcrd->params.eType != epullCONSTRAINT)
+        if (pcrd->params.eType != PullingAlgorithm::Constraint)
         {
             continue;
         }
@@ -830,16 +859,21 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
          * We don't modify dr and value anymore, so these values are also used
          * for printing.
          */
-        get_pull_coord_distance(pull, c, pbc);
+        get_pull_coord_distance(*pull, pcrd, pbc);
 
         const PullCoordSpatialData& spatialData = pcrd->spatialData;
         if (debug)
         {
-            fprintf(debug, "Pull coord %zu dr %f %f %f\n", c, spatialData.dr01[XX],
-                    spatialData.dr01[YY], spatialData.dr01[ZZ]);
+            fprintf(debug,
+                    "Pull coord %zu dr %f %f %f\n",
+                    c,
+                    spatialData.dr01[XX],
+                    spatialData.dr01[YY],
+                    spatialData.dr01[ZZ]);
         }
 
-        if (pcrd->params.eGeom == epullgDIR || pcrd->params.eGeom == epullgDIRPBC)
+        if (pcrd->params.eGeom == PullGroupGeometry::Direction
+            || pcrd->params.eGeom == PullGroupGeometry::DirectionPBC)
         {
             /* Select the component along vec */
             a = 0;
@@ -880,19 +914,19 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
 
             pcrd = &pull->coord[c];
 
-            if (pcrd->params.eType != epullCONSTRAINT)
+            if (pcrd->params.eType != PullingAlgorithm::Constraint)
             {
                 continue;
             }
 
-            update_pull_coord_reference_value(pcrd, c, t);
+            updatePullCoordReferenceValue(&pcrd->value_ref, pcrd->params, t);
 
             pgrp0 = &pull->group[pcrd->params.group[0]];
             pgrp1 = &pull->group[pcrd->params.group[1]];
 
             /* Get the current difference vector */
-            low_get_pull_coord_dr(pull, pcrd, pbc, rnew[pcrd->params.group[1]],
-                                  rnew[pcrd->params.group[0]], 0, 1, -1, unc_ij);
+            low_get_pull_coord_dr(
+                    *pull, pcrd, pbc, rnew[pcrd->params.group[1]], rnew[pcrd->params.group[0]], 0, 1, -1, unc_ij);
 
             if (debug)
             {
@@ -903,13 +937,14 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
 
             switch (pcrd->params.eGeom)
             {
-                case epullgDIST:
+                case PullGroupGeometry::Distance:
                     if (pcrd->value_ref <= 0)
                     {
                         gmx_fatal(
                                 FARGS,
                                 "The pull constraint reference distance for group %zu is <= 0 (%f)",
-                                c, pcrd->value_ref);
+                                c,
+                                pcrd->value_ref);
                     }
 
                     {
@@ -932,8 +967,7 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
 
                         if (debug)
                         {
-                            fprintf(debug, "Pull ax^2+bx+c=0: a=%e b=%e c=%e lambda=%e\n", c_a, c_b,
-                                    c_c, lambda);
+                            fprintf(debug, "Pull ax^2+bx+c=0: a=%e b=%e c=%e lambda=%e\n", c_a, c_b, c_c, lambda);
                         }
                     }
 
@@ -942,9 +976,9 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
                     dsvmul(lambda * rm * pgrp0->invtm, r_ij[c], dr0);
                     dr_tot[c] += -lambda * dnorm(r_ij[c]);
                     break;
-                case epullgDIR:
-                case epullgDIRPBC:
-                case epullgCYL:
+                case PullGroupGeometry::Direction:
+                case PullGroupGeometry::DirectionPBC:
+                case PullGroupGeometry::Cylinder:
                     /* A 1-dimensional constraint along a vector */
                     a = 0;
                     for (m = 0; m < DIM; m++)
@@ -975,14 +1009,35 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
 
                 g0 = pcrd->params.group[0];
                 g1 = pcrd->params.group[1];
-                low_get_pull_coord_dr(pull, pcrd, pbc, rnew[g1], rnew[g0], 0, 1, -1, tmp);
-                low_get_pull_coord_dr(pull, pcrd, pbc, dr1, dr0, 0, 1, -1, tmp3);
-                fprintf(debug, "Pull cur %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n", rnew[g0][0],
-                        rnew[g0][1], rnew[g0][2], rnew[g1][0], rnew[g1][1], rnew[g1][2], dnorm(tmp));
-                fprintf(debug, "Pull ref %8s %8s %8s   %8s %8s %8s d: %8.5f\n", "", "", "", "", "",
-                        "", pcrd->value_ref);
-                fprintf(debug, "Pull cor %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n", dr0[0],
-                        dr0[1], dr0[2], dr1[0], dr1[1], dr1[2], dnorm(tmp3));
+                low_get_pull_coord_dr(*pull, pcrd, pbc, rnew[g1], rnew[g0], 0, 1, -1, tmp);
+                low_get_pull_coord_dr(*pull, pcrd, pbc, dr1, dr0, 0, 1, -1, tmp3);
+                fprintf(debug,
+                        "Pull cur %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n",
+                        rnew[g0][0],
+                        rnew[g0][1],
+                        rnew[g0][2],
+                        rnew[g1][0],
+                        rnew[g1][1],
+                        rnew[g1][2],
+                        dnorm(tmp));
+                fprintf(debug,
+                        "Pull ref %8s %8s %8s   %8s %8s %8s d: %8.5f\n",
+                        "",
+                        "",
+                        "",
+                        "",
+                        "",
+                        "",
+                        pcrd->value_ref);
+                fprintf(debug,
+                        "Pull cor %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n",
+                        dr0[0],
+                        dr0[1],
+                        dr0[2],
+                        dr1[0],
+                        dr1[1],
+                        dr1[2],
+                        dnorm(tmp3));
             } /* END DEBUG */
 
             /* Update the COMs with dr */
@@ -993,22 +1048,22 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
         /* Check if all constraints are fullfilled now */
         for (pull_coord_work_t& coord : pull->coord)
         {
-            if (coord.params.eType != epullCONSTRAINT)
+            if (coord.params.eType != PullingAlgorithm::Constraint)
             {
                 continue;
             }
 
-            low_get_pull_coord_dr(pull, &coord, pbc, rnew[coord.params.group[1]],
-                                  rnew[coord.params.group[0]], 0, 1, -1, unc_ij);
+            low_get_pull_coord_dr(
+                    *pull, &coord, pbc, rnew[coord.params.group[1]], rnew[coord.params.group[0]], 0, 1, -1, unc_ij);
 
             switch (coord.params.eGeom)
             {
-                case epullgDIST:
+                case PullGroupGeometry::Distance:
                     bConverged = fabs(dnorm(unc_ij) - coord.value_ref) < pull->params.constr_tol;
                     break;
-                case epullgDIR:
-                case epullgDIRPBC:
-                case epullgCYL:
+                case PullGroupGeometry::Direction:
+                case PullGroupGeometry::DirectionPBC:
+                case PullGroupGeometry::Cylinder:
                     for (m = 0; m < DIM; m++)
                     {
                         vec[m] = coord.spatialData.vec[m];
@@ -1017,6 +1072,11 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
                     dsvmul(inpr, vec, unc_ij);
                     bConverged = fabs(diprod(unc_ij, vec) - coord.value_ref) < pull->params.constr_tol;
                     break;
+                default:
+                    GMX_ASSERT(false,
+                               gmx::formatString("Geometry %s not handled here",
+                                                 enumValueToString(coord.params.eGeom))
+                                       .c_str());
             }
 
             if (!bConverged)
@@ -1027,7 +1087,10 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
                             "Pull constraint not converged: "
                             "groups %d %d,"
                             "d_ref = %f, current d = %f\n",
-                            coord.params.group[0], coord.params.group[1], coord.value_ref, dnorm(unc_ij));
+                            coord.params.group[0],
+                            coord.params.group[1],
+                            coord.value_ref,
+                            dnorm(unc_ij));
                 }
 
                 bConverged_all = FALSE;
@@ -1045,7 +1108,7 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
 
     /* DONE ITERATING, NOW UPDATE COORDINATES AND CALC. CONSTRAINT FORCES */
 
-    if (v)
+    if (!v.empty())
     {
         invdt = 1 / dt;
     }
@@ -1081,7 +1144,7 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
             {
                 x[ii][m] += tmp[m];
             }
-            if (v)
+            if (!v.empty())
             {
                 for (m = 0; m < DIM; m++)
                 {
@@ -1098,7 +1161,7 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
 
         pcrd = &pull->coord[c];
 
-        if (pcrd->params.eType != epullCONSTRAINT)
+        if (pcrd->params.eType != PullingAlgorithm::Constraint)
         {
             continue;
         }
@@ -1110,7 +1173,7 @@ do_constraint(struct pull_t* pull, t_pbc* pbc, rvec* x, rvec* v, gmx_bool bMaste
                    * dt * dt);
         pcrd->scalarForce += force;
 
-        if (vir != nullptr && pcrd->params.eGeom != epullgDIRPBC && bMaster)
+        if (vir != nullptr && pcrd->params.eGeom != PullGroupGeometry::DirectionPBC && bMaster)
         {
             double f_invr;
 
@@ -1148,7 +1211,7 @@ static void add_virial_coord_dr(tensor vir, const dvec dr, const dvec f)
 /* Adds the pull contribution to the virial */
 static void add_virial_coord(tensor vir, const pull_coord_work_t& pcrd, const PullCoordVectorForces& forces)
 {
-    if (vir != nullptr && pcrd.params.eGeom != epullgDIRPBC)
+    if (vir != nullptr && pcrd.params.eGeom != PullGroupGeometry::DirectionPBC)
     {
         /* Add the pull contribution for each distance vector to the virial. */
         add_virial_coord_dr(vir, pcrd.spatialData.dr01, forces.force01);
@@ -1176,15 +1239,15 @@ static void calc_pull_coord_scalar_force_and_potential(pull_coord_work_t* pcrd,
 
     switch (pcrd->params.eType)
     {
-        case epullUMBRELLA:
-        case epullFLATBOTTOM:
-        case epullFLATBOTTOMHIGH:
+        case PullingAlgorithm::Umbrella:
+        case PullingAlgorithm::FlatBottom:
+        case PullingAlgorithm::FlatBottomHigh:
             /* The only difference between an umbrella and a flat-bottom
              * potential is that a flat-bottom is zero above or below
                the reference value.
              */
-            if ((pcrd->params.eType == epullFLATBOTTOM && dev < 0)
-                || (pcrd->params.eType == epullFLATBOTTOMHIGH && dev > 0))
+            if ((pcrd->params.eType == PullingAlgorithm::FlatBottom && dev < 0)
+                || (pcrd->params.eType == PullingAlgorithm::FlatBottomHigh && dev > 0))
             {
                 dev = 0;
             }
@@ -1193,12 +1256,12 @@ static void calc_pull_coord_scalar_force_and_potential(pull_coord_work_t* pcrd,
             *V += 0.5 * k * gmx::square(dev);
             *dVdl += 0.5 * dkdl * gmx::square(dev);
             break;
-        case epullCONST_F:
+        case PullingAlgorithm::ConstantForce:
             pcrd->scalarForce = -k;
             *V += k * pcrd->spatialData.value;
             *dVdl += dkdl * pcrd->spatialData.value;
             break;
-        case epullEXTERNAL:
+        case PullingAlgorithm::External:
             gmx_incons(
                     "the scalar pull force should not be calculated internally for pull type "
                     "external");
@@ -1214,7 +1277,7 @@ static PullCoordVectorForces calculateVectorForces(const pull_coord_work_t& pcrd
     /* The geometry of the coordinate determines how the scalar force relates to the force on each group */
     PullCoordVectorForces forces;
 
-    if (params.eGeom == epullgDIST)
+    if (params.eGeom == PullGroupGeometry::Distance)
     {
         double invdr01 = spatialData.value > 0 ? 1. / spatialData.value : 0.;
         for (int m = 0; m < DIM; m++)
@@ -1222,7 +1285,7 @@ static PullCoordVectorForces calculateVectorForces(const pull_coord_work_t& pcrd
             forces.force01[m] = pcrd.scalarForce * spatialData.dr01[m] * invdr01;
         }
     }
-    else if (params.eGeom == epullgANGLE)
+    else if (params.eGeom == PullGroupGeometry::Angle)
     {
 
         double cos_theta, cos_theta2;
@@ -1266,7 +1329,7 @@ static PullCoordVectorForces calculateVectorForces(const pull_coord_work_t& pcrd
             clear_dvec(forces.force23);
         }
     }
-    else if (params.eGeom == epullgANGLEAXIS)
+    else if (params.eGeom == PullGroupGeometry::AngleAxis)
     {
         double cos_theta, cos_theta2;
 
@@ -1297,7 +1360,7 @@ static PullCoordVectorForces calculateVectorForces(const pull_coord_work_t& pcrd
             clear_dvec(forces.force01);
         }
     }
-    else if (params.eGeom == epullgDIHEDRAL)
+    else if (params.eGeom == PullGroupGeometry::Dihedral)
     {
         double m2, n2, tol, sqrdist_32;
         dvec   dr32;
@@ -1323,9 +1386,8 @@ static PullCoordVectorForces calculateVectorForces(const pull_coord_work_t& pcrd
             dist_32        = sqrdist_32 * inv_dist_32;
 
             /* Forces on groups 0, 1 */
-            a_01 = pcrd.scalarForce * dist_32 / m2; /* scalarForce is -dV/dphi */
-            dsvmul(-a_01, spatialData.planevec_m,
-                   forces.force01); /* added sign to get force on group 1, not 0 */
+            a_01 = pcrd.scalarForce * dist_32 / m2;                /* scalarForce is -dV/dphi */
+            dsvmul(-a_01, spatialData.planevec_m, forces.force01); /* added sign to get force on group 1, not 0 */
 
             /* Forces on groups 4, 5 */
             a_45 = -pcrd.scalarForce * dist_32 / n2;
@@ -1363,9 +1425,10 @@ static PullCoordVectorForces calculateVectorForces(const pull_coord_work_t& pcrd
  * We could use a different, local mutex for each pull object, but the overhead
  * is extremely small here and registration is only done during initialization.
  */
-static gmx::Mutex registrationMutex;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static std::mutex registrationMutex;
 
-using Lock = gmx::lock_guard<gmx::Mutex>;
+using Lock = std::lock_guard<std::mutex>;
 
 void register_external_pull_potential(struct pull_t* pull, int coord_index, const char* provider)
 {
@@ -1378,18 +1441,24 @@ void register_external_pull_potential(struct pull_t* pull, int coord_index, cons
         gmx_fatal(FARGS,
                   "Module '%s' attempted to register an external potential for pull coordinate %d "
                   "which is out of the pull coordinate range %d - %zu\n",
-                  provider, coord_index + 1, 1, pull->coord.size());
+                  provider,
+                  coord_index + 1,
+                  1,
+                  pull->coord.size());
     }
 
     pull_coord_work_t* pcrd = &pull->coord[coord_index];
 
-    if (pcrd->params.eType != epullEXTERNAL)
+    if (pcrd->params.eType != PullingAlgorithm::External)
     {
         gmx_fatal(
                 FARGS,
                 "Module '%s' attempted to register an external potential for pull coordinate %d "
                 "which of type '%s', whereas external potentials are only supported with type '%s'",
-                provider, coord_index + 1, epull_names[pcrd->params.eType], epull_names[epullEXTERNAL]);
+                provider,
+                coord_index + 1,
+                enumValueToString(pcrd->params.eType),
+                enumValueToString(PullingAlgorithm::External));
     }
 
     GMX_RELEASE_ASSERT(!pcrd->params.externalPotentialProvider.empty(),
@@ -1400,7 +1469,9 @@ void register_external_pull_potential(struct pull_t* pull, int coord_index, cons
         gmx_fatal(FARGS,
                   "Module '%s' attempted to register an external potential for pull coordinate %d "
                   "which expects the external potential to be provided by a module named '%s'",
-                  provider, coord_index + 1, pcrd->params.externalPotentialProvider.c_str());
+                  provider,
+                  coord_index + 1,
+                  pcrd->params.externalPotentialProvider.c_str());
     }
 
     /* Lock to avoid (extremely unlikely) simultaneous reading and writing of
@@ -1414,7 +1485,8 @@ void register_external_pull_potential(struct pull_t* pull, int coord_index, cons
         gmx_fatal(FARGS,
                   "Module '%s' attempted to register an external potential for pull coordinate %d "
                   "more than once",
-                  provider, coord_index + 1);
+                  provider,
+                  coord_index + 1);
     }
 
     pcrd->bExternalPotentialProviderHasBeenRegistered = true;
@@ -1432,7 +1504,7 @@ static void check_external_potential_registration(const struct pull_t* pull)
         size_t c;
         for (c = 0; c < pull->coord.size(); c++)
         {
-            if (pull->coord[c].params.eType == epullEXTERNAL
+            if (pull->coord[c].params.eType == PullingAlgorithm::External
                 && !pull->coord[c].bExternalPotentialProviderHasBeenRegistered)
             {
                 break;
@@ -1446,12 +1518,12 @@ static void check_external_potential_registration(const struct pull_t* pull)
                   "No external provider for external pull potentials have been provided for %d "
                   "pull coordinates. The first coordinate without provider is number %zu, which "
                   "expects a module named '%s' to provide the external potential.",
-                  pull->numUnregisteredExternalPotentials, c + 1,
+                  pull->numUnregisteredExternalPotentials,
+                  c + 1,
                   pull->coord[c].params.externalPotentialProvider.c_str());
     }
 }
 
-
 /* Pull takes care of adding the forces of the external potential.
  * The external potential module  has to make sure that the corresponding
  * potential energy is added either to the pull term or to a term
@@ -1460,7 +1532,7 @@ static void check_external_potential_registration(const struct pull_t* pull)
 void apply_external_pull_coord_force(struct pull_t*        pull,
                                      int                   coord_index,
                                      double                coord_force,
-                                     const real*           masses,
+                                     ArrayRef<const real>  masses,
                                      gmx::ForceWithVirial* forceWithVirial)
 {
     pull_coord_work_t* pcrd;
@@ -1473,7 +1545,7 @@ void apply_external_pull_coord_force(struct pull_t*        pull,
         pcrd = &pull->coord[coord_index];
 
         GMX_RELEASE_ASSERT(
-                pcrd->params.eType == epullEXTERNAL,
+                pcrd->params.eType == PullingAlgorithm::External,
                 "The pull force can only be set externally on pull coordinates of external type");
 
         GMX_ASSERT(pcrd->bExternalPotentialProviderHasBeenRegistered,
@@ -1493,8 +1565,8 @@ void apply_external_pull_coord_force(struct pull_t*        pull,
             forceWithVirial->addVirialContribution(virial);
         }
 
-        apply_forces_coord(pull, coord_index, pullCoordForces, masses,
-                           as_rvec_array(forceWithVirial->force_.data()));
+        apply_forces_coord(
+                *pcrd, pull->group, pullCoordForces, masses, as_rvec_array(forceWithVirial->force_.data()));
     }
 
     pull->numExternalPotentialsStillToBeAppliedThisStep--;
@@ -1503,37 +1575,35 @@ void apply_external_pull_coord_force(struct pull_t*        pull,
 /* Calculate the pull potential and scalar force for a pull coordinate.
  * Returns the vector forces for the pull coordinate.
  */
-static PullCoordVectorForces do_pull_pot_coord(struct pull_t* pull,
-                                               int            coord_ind,
-                                               t_pbc*         pbc,
-                                               double         t,
-                                               real           lambda,
-                                               real*          V,
-                                               tensor         vir,
-                                               real*          dVdl)
+static PullCoordVectorForces do_pull_pot_coord(const pull_t&      pull,
+                                               pull_coord_work_t* pcrd,
+                                               t_pbc*             pbc,
+                                               double             t,
+                                               real               lambda,
+                                               real*              V,
+                                               tensor             vir,
+                                               real*              dVdl)
 {
-    pull_coord_work_t& pcrd = pull->coord[coord_ind];
+    assert(pcrd->params.eType != PullingAlgorithm::Constraint);
 
-    assert(pcrd.params.eType != epullCONSTRAINT);
+    double dev = get_pull_coord_deviation(pull, pcrd, pbc, t);
 
-    double dev = get_pull_coord_deviation(pull, coord_ind, pbc, t);
+    calc_pull_coord_scalar_force_and_potential(pcrd, dev, lambda, V, dVdl);
 
-    calc_pull_coord_scalar_force_and_potential(&pcrd, dev, lambda, V, dVdl);
+    PullCoordVectorForces pullCoordForces = calculateVectorForces(*pcrd);
 
-    PullCoordVectorForces pullCoordForces = calculateVectorForces(pcrd);
-
-    add_virial_coord(vir, pcrd, pullCoordForces);
+    add_virial_coord(vir, *pcrd, pullCoordForces);
 
     return pullCoordForces;
 }
 
 real pull_potential(struct pull_t*        pull,
-                    const real*           masses,
+                    ArrayRef<const real>  masses,
                     t_pbc*                pbc,
                     const t_commrec*      cr,
                     double                t,
                     real                  lambda,
-                    const rvec*           x,
+                    ArrayRef<const RVec>  x,
                     gmx::ForceWithVirial* force,
                     real*                 dvdlambda)
 {
@@ -1551,7 +1621,7 @@ real pull_potential(struct pull_t*        pull,
     {
         real dVdl = 0;
 
-        pull_calc_coms(cr, pull, masses, pbc, t, x, nullptr);
+        pull_calc_coms(cr, pull, masses, pbc, t, x, {});
 
         rvec*      f             = as_rvec_array(force->force_.data());
         matrix     virial        = { { 0 } };
@@ -1563,16 +1633,17 @@ real pull_potential(struct pull_t*        pull,
 
             /* For external potential the force is assumed to be given by an external module by a
                call to apply_pull_coord_external_force */
-            if (pcrd->params.eType == epullCONSTRAINT || pcrd->params.eType == epullEXTERNAL)
+            if (pcrd->params.eType == PullingAlgorithm::Constraint
+                || pcrd->params.eType == PullingAlgorithm::External)
             {
                 continue;
             }
 
             PullCoordVectorForces pullCoordForces = do_pull_pot_coord(
-                    pull, c, pbc, t, lambda, &V, computeVirial ? virial : nullptr, &dVdl);
+                    *pull, pcrd, pbc, t, lambda, &V, computeVirial ? virial : nullptr, &dVdl);
 
             /* Distribute the force over the atoms in the pulled groups */
-            apply_forces_coord(pull, c, pullCoordForces, masses, f);
+            apply_forces_coord(*pcrd, pull->group, pullCoordForces, masses, f);
         }
 
         if (MASTER(cr))
@@ -1590,16 +1661,16 @@ real pull_potential(struct pull_t*        pull,
     return (MASTER(cr) ? V : 0.0);
 }
 
-void pull_constraint(struct pull_t*   pull,
-                     const real*      masses,
-                     t_pbc*           pbc,
-                     const t_commrec* cr,
-                     double           dt,
-                     double           t,
-                     rvec*            x,
-                     rvec*            xp,
-                     rvec*            v,
-                     tensor           vir)
+void pull_constraint(struct pull_t*       pull,
+                     ArrayRef<const real> masses,
+                     t_pbc*               pbc,
+                     const t_commrec*     cr,
+                     double               dt,
+                     double               t,
+                     ArrayRef<RVec>       x,
+                     ArrayRef<RVec>       xp,
+                     ArrayRef<RVec>       v,
+                     tensor               vir)
 {
     assert(pull != nullptr);
 
@@ -1674,8 +1745,11 @@ void dd_make_local_pull_groups(const t_commrec* cr, struct pull_t* pull)
 
         if (debug && dd != nullptr)
         {
-            fprintf(debug, "Our DD rank (%3d) pull #atoms>0 or master: %s, will be part %s\n", dd->rank,
-                    gmx::boolToString(bMustParticipate), gmx::boolToString(bWillParticipate));
+            fprintf(debug,
+                    "Our DD rank (%3d) pull #atoms>0 or master: %s, will be part %s\n",
+                    dd->rank,
+                    gmx::boolToString(bMustParticipate),
+                    gmx::boolToString(bWillParticipate));
         }
 
         if (bWillParticipate)
@@ -1750,7 +1824,7 @@ static void init_pull_group_index(FILE*              fplog,
                                   pull_group_work_t* pg,
                                   gmx_bool           bConstraint,
                                   const ivec         pulldim_con,
-                                  const gmx_mtop_t*  mtop,
+                                  const gmx_mtop_t&  mtop,
                                   const t_inputrec*  ir,
                                   real               lambda)
 {
@@ -1758,13 +1832,13 @@ static void init_pull_group_index(FILE*              fplog,
      * But we still want to have the correct mass-weighted COMs.
      * So we store the real masses in the weights.
      */
-    const bool setWeights =
-            (!pg->params.weight.empty() || EI_ENERGY_MINIMIZATION(ir->eI) || ir->eI == eiBD);
+    const bool setWeights = (!pg->params.weight.empty() || EI_ENERGY_MINIMIZATION(ir->eI)
+                             || ir->eI == IntegrationAlgorithm::BD);
 
     /* In parallel, store we need to extract localWeights from weights at DD time */
     std::vector<real>& weights = ((cr && PAR(cr)) ? pg->globalWeights : pg->localWeights);
 
-    const SimulationGroups& groups = mtop->groups;
+    const SimulationGroups& groups = mtop.groups;
 
     /* Count frozen dimensions and (weighted) mass */
     int    nfrozen = 0;
@@ -1788,7 +1862,7 @@ static void init_pull_group_index(FILE*              fplog,
         }
         const t_atom& atom = mtopGetAtomParameters(mtop, ii, &molb);
         real          m;
-        if (ir->efep == efepNO)
+        if (ir->efep == FreeEnergyPerturbationType::No)
         {
             m = atom.m;
         }
@@ -1811,7 +1885,7 @@ static void init_pull_group_index(FILE*              fplog,
             w *= m;
             m = 1;
         }
-        else if (ir->eI == eiBD)
+        else if (ir->eI == IntegrationAlgorithm::BD)
         {
             real mbd;
             if (ir->bd_fric != 0.0F)
@@ -1854,14 +1928,17 @@ static void init_pull_group_index(FILE*              fplog,
         }
         else
         {
-            gmx_fatal(FARGS, "The total%s mass of pull group %d is zero",
-                      !pg->params.weight.empty() ? " weighted" : "", g);
+            gmx_fatal(FARGS,
+                      "The total%s mass of pull group %d is zero",
+                      !pg->params.weight.empty() ? " weighted" : "",
+                      g);
         }
     }
     if (fplog)
     {
         fprintf(fplog, "Pull group %d: %5zu atoms, mass %9.3f", g, pg->params.ind.size(), tmass);
-        if (!pg->params.weight.empty() || EI_ENERGY_MINIMIZATION(ir->eI) || ir->eI == eiBD)
+        if (!pg->params.weight.empty() || EI_ENERGY_MINIMIZATION(ir->eI)
+            || ir->eI == IntegrationAlgorithm::BD)
         {
             fprintf(fplog, ", weighted mass %9.3f", wmass * wmass / wwmass);
         }
@@ -1900,7 +1977,7 @@ static void init_pull_group_index(FILE*              fplog,
 struct pull_t* init_pull(FILE*                     fplog,
                          const pull_params_t*      pull_params,
                          const t_inputrec*         ir,
-                         const gmx_mtop_t*         mtop,
+                         const gmx_mtop_t&         mtop,
                          const t_commrec*          cr,
                          gmx::LocalAtomSetManager* atomSets,
                          real                      lambda)
@@ -1913,10 +1990,15 @@ struct pull_t* init_pull(FILE*                     fplog,
     /* Copy the pull parameters */
     pull->params = *pull_params;
 
+    /* The gmx_omp_nthreads module might not be initialized here, so max(1,) */
+    const int maxNumThreads = std::max(1, gmx_omp_nthreads_get(ModuleMultiThread::Default));
+
     for (int i = 0; i < pull_params->ngroup; ++i)
     {
-        pull->group.emplace_back(pull_params->group[i], atomSets->add(pull_params->group[i].ind),
-                                 pull_params->bSetPbcRefToPrevStepCOM);
+        pull->group.emplace_back(pull_params->group[i],
+                                 atomSets->add(pull_params->group[i].ind),
+                                 pull_params->bSetPbcRefToPrevStepCOM,
+                                 maxNumThreads);
     }
 
     if (cr != nullptr && DOMAINDECOMP(cr))
@@ -1947,6 +2029,9 @@ struct pull_t* init_pull(FILE*                     fplog,
 
     for (int c = 0; c < pull->params.ncoord; c++)
     {
+        GMX_RELEASE_ASSERT(pull_params->coord[c].coordIndex == c,
+                           "The stored index should match the position in the vector");
+
         /* Construct a pull coordinate, copying all coordinate parameters */
         pull->coord.emplace_back(pull_params->coord[c]);
 
@@ -1954,14 +2039,14 @@ struct pull_t* init_pull(FILE*                     fplog,
 
         switch (pcrd->params.eGeom)
         {
-            case epullgDIST:
-            case epullgDIRRELATIVE: /* Direction vector is determined at each step */
-            case epullgANGLE:
-            case epullgDIHEDRAL: break;
-            case epullgDIR:
-            case epullgDIRPBC:
-            case epullgCYL:
-            case epullgANGLEAXIS:
+            case PullGroupGeometry::Distance:
+            case PullGroupGeometry::DirectionRelative: /* Direction vector is determined at each step */
+            case PullGroupGeometry::Angle:
+            case PullGroupGeometry::Dihedral: break;
+            case PullGroupGeometry::Direction:
+            case PullGroupGeometry::DirectionPBC:
+            case PullGroupGeometry::Cylinder:
+            case PullGroupGeometry::AngleAxis:
                 copy_rvec_to_dvec(pull_params->coord[c].vec, pcrd->spatialData.vec);
                 break;
             default:
@@ -1976,24 +2061,29 @@ struct pull_t* init_pull(FILE*                     fplog,
                  */
                 gmx_fatal(FARGS,
                           "Pull geometry not supported for pull coordinate %d. The geometry enum "
-                          "%d in the input is larger than that supported by the code (up to %d). "
+                          "%s in the input is larger than that supported by the code (up to %d). "
                           "You are probably reading a tpr file generated with a newer version of "
-                          "Gromacs with an binary from an older version of Gromacs.",
-                          c + 1, pcrd->params.eGeom, epullgNR - 1);
+                          "GROMACS with an binary from an older version of Gromacs.",
+                          c + 1,
+                          enumValueToString(pcrd->params.eGeom),
+                          static_cast<int>(PullGroupGeometry::Count) - 1);
         }
 
-        if (pcrd->params.eType == epullCONSTRAINT)
+        if (pcrd->params.eType == PullingAlgorithm::Constraint)
         {
             /* Check restrictions of the constraint pull code */
-            if (pcrd->params.eGeom == epullgCYL || pcrd->params.eGeom == epullgDIRRELATIVE
-                || pcrd->params.eGeom == epullgANGLE || pcrd->params.eGeom == epullgDIHEDRAL
-                || pcrd->params.eGeom == epullgANGLEAXIS)
+            if (pcrd->params.eGeom == PullGroupGeometry::Cylinder
+                || pcrd->params.eGeom == PullGroupGeometry::DirectionRelative
+                || pcrd->params.eGeom == PullGroupGeometry::Angle
+                || pcrd->params.eGeom == PullGroupGeometry::Dihedral
+                || pcrd->params.eGeom == PullGroupGeometry::AngleAxis)
             {
                 gmx_fatal(FARGS,
                           "Pulling of type %s can not be combined with geometry %s. Consider using "
                           "pull type %s.",
-                          epull_names[pcrd->params.eType], epullg_names[pcrd->params.eGeom],
-                          epull_names[epullUMBRELLA]);
+                          enumValueToString(pcrd->params.eType),
+                          enumValueToString(pcrd->params.eGeom),
+                          enumValueToString(PullingAlgorithm::Umbrella));
             }
 
             GMX_RELEASE_ASSERT(
@@ -2007,12 +2097,13 @@ struct pull_t* init_pull(FILE*                     fplog,
             pull->bPotential = TRUE;
         }
 
-        if (pcrd->params.eGeom == epullgCYL)
+        if (pcrd->params.eGeom == PullGroupGeometry::Cylinder)
         {
             pull->bCylinder = TRUE;
         }
-        else if (pcrd->params.eGeom == epullgANGLE || pcrd->params.eGeom == epullgDIHEDRAL
-                 || pcrd->params.eGeom == epullgANGLEAXIS)
+        else if (pcrd->params.eGeom == PullGroupGeometry::Angle
+                 || pcrd->params.eGeom == PullGroupGeometry::Dihedral
+                 || pcrd->params.eGeom == PullGroupGeometry::AngleAxis)
         {
             pull->bAngle = TRUE;
         }
@@ -2024,7 +2115,7 @@ struct pull_t* init_pull(FILE*                     fplog,
         for (int i = 0; i < pcrd->params.ngroup; i++)
         {
             int groupIndex = pcrd->params.group[i];
-            if (groupIndex > 0 && !(pcrd->params.eGeom == epullgCYL && i == 0))
+            if (groupIndex > 0 && !(pcrd->params.eGeom == PullGroupGeometry::Cylinder && i == 0))
             {
                 pull->group[groupIndex].needToCalcCom = true;
             }
@@ -2034,11 +2125,11 @@ struct pull_t* init_pull(FILE*                     fplog,
         if (pcrd->params.rate == 0)
         {
             /* Initialize the constant reference value */
-            if (pcrd->params.eType != epullEXTERNAL)
+            if (pcrd->params.eType != PullingAlgorithm::External)
             {
-                low_set_pull_coord_reference_value(
-                        pcrd, c,
-                        pcrd->params.init * pull_conversion_factor_userinput2internal(&pcrd->params));
+                pcrd->value_ref = sanitizePullCoordReferenceValue(
+                        pcrd->params,
+                        pcrd->params.init * pull_conversion_factor_userinput2internal(pcrd->params));
             }
             else
             {
@@ -2054,7 +2145,7 @@ struct pull_t* init_pull(FILE*                     fplog,
             }
         }
 
-        if (pcrd->params.eType == epullEXTERNAL)
+        if (pcrd->params.eType == PullingAlgorithm::External)
         {
             GMX_RELEASE_ASSERT(
                     pcrd->params.rate == 0,
@@ -2104,8 +2195,12 @@ struct pull_t* init_pull(FILE*                     fplog,
         int numRealGroups = pull->group.size() - 1;
         GMX_RELEASE_ASSERT(numRealGroups > 0,
                            "The reference absolute position pull group should always be present");
-        fprintf(fplog, "with %zu pull coordinate%s and %d group%s\n", pull->coord.size(),
-                pull->coord.size() == 1 ? "" : "s", numRealGroups, numRealGroups == 1 ? "" : "s");
+        fprintf(fplog,
+                "with %zu pull coordinate%s and %d group%s\n",
+                pull->coord.size(),
+                pull->coord.size() == 1 ? "" : "s",
+                numRealGroups,
+                numRealGroups == 1 ? "" : "s");
         if (bAbs)
         {
             fprintf(fplog, "with an absolute reference\n");
@@ -2173,7 +2268,7 @@ struct pull_t* init_pull(FILE*                     fplog,
                         {
                             pulldim[m] = 1;
 
-                            if (coord.params.eType == epullCONSTRAINT)
+                            if (coord.params.eType == PullingAlgorithm::Constraint)
                             {
                                 bConstraint    = TRUE;
                                 pulldim_con[m] = 1;
@@ -2229,9 +2324,9 @@ struct pull_t* init_pull(FILE*                     fplog,
     /* If we use cylinder coordinates, do some initialising for them */
     if (pull->bCylinder)
     {
-        for (const pull_coord_work_t& coord : pull->coord)
+        for (pull_coord_work_t& coord : pull->coord)
         {
-            if (coord.params.eGeom == epullgCYL)
+            if (coord.params.eGeom == PullGroupGeometry::Cylinder)
             {
                 if (pull->group[coord.params.group[0]].params.ind.empty())
                 {
@@ -2240,15 +2335,13 @@ struct pull_t* init_pull(FILE*                     fplog,
                               "reference!\n");
                 }
             }
-            const auto& referenceGroup = pull->group[coord.params.group[0]];
-            pull->dyna.emplace_back(referenceGroup.params, referenceGroup.atomSet,
-                                    pull->params.bSetPbcRefToPrevStepCOM);
+            const auto& group0  = pull->group[coord.params.group[0]];
+            coord.dynamicGroup0 = std::make_unique<pull_group_work_t>(
+                    group0.params, group0.atomSet, pull->params.bSetPbcRefToPrevStepCOM, maxNumThreads);
         }
     }
 
-    /* The gmx_omp_nthreads module might not be initialized here, so max(1,) */
-    pull->nthreads = std::max(1, gmx_omp_nthreads_get(emntDefault));
-    pull->comSums.resize(pull->nthreads);
+    pull->comSums.resize(maxNumThreads);
 
     comm = &pull->comm;
 
@@ -2308,13 +2401,13 @@ static void destroy_pull(struct pull_t* pull)
     delete pull;
 }
 
-void preparePrevStepPullCom(const t_inputrec* ir,
-                            pull_t*           pull_work,
-                            const real*       masses,
-                            t_state*          state,
-                            const t_state*    state_global,
-                            const t_commrec*  cr,
-                            bool              startingFromCheckpoint)
+void preparePrevStepPullCom(const t_inputrec*    ir,
+                            pull_t*              pull_work,
+                            ArrayRef<const real> masses,
+                            t_state*             state,
+                            const t_state*       state_global,
+                            const t_commrec*     cr,
+                            bool                 startingFromCheckpoint)
 {
     if (!ir->pull || !ir->pull->bSetPbcRefToPrevStepCOM)
     {
@@ -2331,7 +2424,8 @@ void preparePrevStepPullCom(const t_inputrec* ir,
         {
             /* Only the master rank has the checkpointed COM from the previous step */
             gmx_bcast(sizeof(double) * state->pull_com_prev_step.size(),
-                      &state->pull_com_prev_step[0], cr->mpi_comm_mygroup);
+                      &state->pull_com_prev_step[0],
+                      cr->mpi_comm_mygroup);
         }
         setPrevStepPullComFromState(pull_work, state);
     }
@@ -2339,7 +2433,8 @@ void preparePrevStepPullCom(const t_inputrec* ir,
     {
         t_pbc pbc;
         set_pbc(&pbc, ir->pbcType, state->box);
-        initPullComFromPrevStep(cr, pull_work, masses, &pbc, state->x.rvec_array());
+        initPullComFromPrevStep(
+                cr, pull_work, masses, &pbc, state->x.arrayRefWithPadding().unpaddedArrayRef());
         updatePrevStepPullCom(pull_work, state);
     }
 }
@@ -2374,7 +2469,7 @@ bool pull_have_constraint(const pull_params_t& pullParameters)
 {
     for (int c = 0; c < pullParameters.ncoord; c++)
     {
-        if (pullParameters.coord[c].eType == epullCONSTRAINT)
+        if (pullParameters.coord[c].eType == PullingAlgorithm::Constraint)
         {
             return true;
         }
index 2f87228ecb929a2edfe1c7d9827cabb7c9f6d4bc..a4e0cf05511fe1582154be1637a649c8678dcb55 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,37 +72,32 @@ class t_state;
 
 namespace gmx
 {
+template<typename>
+class ArrayRef;
 class ForceWithVirial;
 class LocalAtomSetManager;
 } // namespace gmx
 
-/*! \brief Returns if the pull coordinate is an angle
- *
- * \param[in] pcrd The pull coordinate to query the type for.
- * \returns a boolean telling if the coordinate is of angle type.
- */
-bool pull_coordinate_is_angletype(const t_pull_coord* pcrd);
-
 /*! \brief Returns the units of the pull coordinate.
  *
  * \param[in] pcrd The pull coordinate to query the units for.
  * \returns a string with the units of the coordinate.
  */
-const char* pull_coordinate_units(const t_pull_coord* pcrd);
+const char* pull_coordinate_units(const t_pull_coord& pcrd);
 
 /*! \brief Returns the conversion factor from the pull coord init/rate unit to internal value unit.
  *
  * \param[in] pcrd The pull coordinate to get the conversion factor for.
  * \returns the conversion factor.
  */
-double pull_conversion_factor_userinput2internal(const t_pull_coord* pcrd);
+double pull_conversion_factor_userinput2internal(const t_pull_coord& pcrd);
 
 /*! \brief Returns the conversion factor from the pull coord internal value unit to the init/rate unit.
  *
  * \param[in] pcrd The pull coordinate to get the conversion factor for.
  * \returns the conversion factor.
  */
-double pull_conversion_factor_internal2userinput(const t_pull_coord* pcrd);
+double pull_conversion_factor_internal2userinput(const t_pull_coord& pcrd);
 
 /*! \brief Get the value for pull coord coord_ind.
  *
@@ -155,12 +150,11 @@ void register_external_pull_potential(struct pull_t* pull, int coord_index, cons
  * \param[in]     masses           Atoms masses.
  * \param[in,out] forceWithVirial  Force and virial buffers.
  */
-void apply_external_pull_coord_force(struct pull_t*        pull,
-                                     int                   coord_index,
-                                     double                coord_force,
-                                     const real*           masses,
-                                     gmx::ForceWithVirial* forceWithVirial);
-
+void apply_external_pull_coord_force(struct pull_t*            pull,
+                                     int                       coord_index,
+                                     double                    coord_force,
+                                     gmx::ArrayRef<const real> masses,
+                                     gmx::ForceWithVirial*     forceWithVirial);
 
 /*! \brief Set the all the pull forces to zero.
  *
@@ -183,15 +177,15 @@ void clear_pull_forces(struct pull_t* pull);
  *
  * \returns The pull potential energy.
  */
-real pull_potential(struct pull_t*        pull,
-                    const real*           masses,
-                    struct t_pbc*         pbc,
-                    const t_commrec*      cr,
-                    double                t,
-                    real                  lambda,
-                    const rvec*           x,
-                    gmx::ForceWithVirial* force,
-                    real*                 dvdlambda);
+real pull_potential(struct pull_t*                 pull,
+                    gmx::ArrayRef<const real>      masses,
+                    struct t_pbc*                  pbc,
+                    const t_commrec*               cr,
+                    double                         t,
+                    real                           lambda,
+                    gmx::ArrayRef<const gmx::RVec> x,
+                    gmx::ForceWithVirial*          force,
+                    real*                          dvdlambda);
 
 
 /*! \brief Constrain the coordinates xp in the directions in x
@@ -208,16 +202,16 @@ real pull_potential(struct pull_t*        pull,
  * \param[in,out] v      Velocities, which may get a pull correction.
  * \param[in,out] vir    The virial, which, if != NULL, gets a pull correction.
  */
-void pull_constraint(struct pull_t*   pull,
-                     const real*      masses,
-                     struct t_pbc*    pbc,
-                     const t_commrec* cr,
-                     double           dt,
-                     double           t,
-                     rvec*            x,
-                     rvec*            xp,
-                     rvec*            v,
-                     tensor           vir);
+void pull_constraint(struct pull_t*            pull,
+                     gmx::ArrayRef<const real> masses,
+                     struct t_pbc*             pbc,
+                     const t_commrec*          cr,
+                     double                    dt,
+                     double                    t,
+                     gmx::ArrayRef<gmx::RVec>  x,
+                     gmx::ArrayRef<gmx::RVec>  xp,
+                     gmx::ArrayRef<gmx::RVec>  v,
+                     tensor                    vir);
 
 
 /*! \brief Make a selection of the home atoms for all pull groups.
@@ -242,7 +236,7 @@ void dd_make_local_pull_groups(const t_commrec* cr, struct pull_t* pull);
 struct pull_t* init_pull(FILE*                     fplog,
                          const pull_params_t*      pull_params,
                          const t_inputrec*         ir,
-                         const gmx_mtop_t*         mtop,
+                         const gmx_mtop_t&         mtop,
                          const t_commrec*          cr,
                          gmx::LocalAtomSetManager* atomSets,
                          real                      lambda);
@@ -266,13 +260,13 @@ void finish_pull(struct pull_t* pull);
  * \param[in,out] xp   Updated x, can be NULL.
  *
  */
-void pull_calc_coms(const t_commrec* cr,
-                    pull_t*          pull,
-                    const real*      masses,
-                    t_pbc*           pbc,
-                    double           t,
-                    const rvec       x[],
-                    rvec*            xp);
+void pull_calc_coms(const t_commrec*               cr,
+                    pull_t*                        pull,
+                    gmx::ArrayRef<const real>      masses,
+                    t_pbc*                         pbc,
+                    double                         t,
+                    gmx::ArrayRef<const gmx::RVec> x,
+                    gmx::ArrayRef<gmx::RVec>       xp);
 
 /*! \brief Margin for checking pull group PBC distances compared to half the box size */
 static constexpr real c_pullGroupPbcMargin = 0.9;
@@ -297,7 +291,7 @@ static constexpr real c_pullGroupSmallGroupThreshold = 0.5;
  * \param[in] pbcMargin  The minimum margin (as a fraction) to half the box size
  * \returns -1 when all groups obey PBC or the first group index that fails PBC
  */
-int pullCheckPbcWithinGroups(const pull_t& pull, const rvec* x, const t_pbc& pbc, real pbcMargin);
+int pullCheckPbcWithinGroups(const pull_t& pull, gmx::ArrayRef<const gmx::RVec> x, const t_pbc& pbc, real pbcMargin);
 
 /*! \brief Checks whether a specific group that uses a reference atom is within PBC restrictions
  *
@@ -376,13 +370,13 @@ void updatePrevStepPullCom(struct pull_t* pull, t_state* state);
  * \param[in] cr                     Struct for communication info.
  * \param[in] startingFromCheckpoint Is the simulation starting from a checkpoint?
  */
-void preparePrevStepPullCom(const t_inputrec* ir,
-                            pull_t*           pull_work,
-                            const real*       masses,
-                            t_state*          state,
-                            const t_state*    state_global,
-                            const t_commrec*  cr,
-                            bool              startingFromCheckpoint);
+void preparePrevStepPullCom(const t_inputrec*         ir,
+                            pull_t*                   pull_work,
+                            gmx::ArrayRef<const real> masses,
+                            t_state*                  state,
+                            const t_state*            state_global,
+                            const t_commrec*          cr,
+                            bool                      startingFromCheckpoint);
 
 /*! \brief Initializes the COM of the previous step (set to initial COM)
  *
@@ -392,6 +386,10 @@ void preparePrevStepPullCom(const t_inputrec* ir,
  * \param[in] pbc      Information struct about periodicity.
  * \param[in] x        The local positions.
  */
-void initPullComFromPrevStep(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc* pbc, const rvec x[]);
+void initPullComFromPrevStep(const t_commrec*               cr,
+                             pull_t*                        pull,
+                             gmx::ArrayRef<const real>      masses,
+                             t_pbc*                         pbc,
+                             gmx::ArrayRef<const gmx::RVec> x);
 
 #endif
index 1973e5f116034ecdb0c190e1b487ace9b6e22610..749d70379c8df9265c726ed9140dd2e49ab3120d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -91,14 +91,25 @@ struct pull_group_work_t
      * \param[in] params                  The group parameters set by the user
      * \param[in] atomSet                 The global to local atom set manager
      * \param[in] setPbcRefToPrevStepCOM Does this pull group use the COM from the previous step as reference position?
+     * \param[in] maxNumThreads           Use either this number of threads of 1 for operations on x and f
      */
-    pull_group_work_t(const t_pull_group& params, gmx::LocalAtomSet atomSet, bool setPbcRefToPrevStepCOM);
+    pull_group_work_t(const t_pull_group& params,
+                      gmx::LocalAtomSet   atomSet,
+                      bool                setPbcRefToPrevStepCOM,
+                      int                 maxNumThreads);
+
+    //! Returns the number of threads to use for local atom operations based on the local atom count
+    int numThreads() const
+    {
+        return atomSet.numAtomsLocal() <= c_pullMaxNumLocalAtomsSingleThreaded ? 1 : maxNumThreads;
+    }
 
     /* Data only modified at initialization */
     const t_pull_group params;   /**< The pull group parameters */
     const int          epgrppbc; /**< The type of pbc for this pull group, see enum above */
-    bool               needToCalcCom; /**< Do we need to calculate the COM? (Not for group 0 or if only used as cylinder group) */
-    std::vector<real>  globalWeights; /**< Weights per atom set by the user and/or mass/friction coefficients, if empty all weights are equal */
+    const int maxNumThreads; /**< The maximum number of threads to use for operations on x and f */
+    bool      needToCalcCom; /**< Do we need to calculate the COM? (Not for group 0 or if only used as cylinder group) */
+    std::vector<real> globalWeights; /**< Weights per atom set by the user and/or mass/friction coefficients, if empty all weights are equal */
 
     /* Data modified only at init or at domain decomposition */
     gmx::LocalAtomSet                  atomSet;      /**< Global to local atom set mapper */
@@ -149,6 +160,9 @@ struct pull_coord_work_t
 
     const t_pull_coord params; /* Pull coordinate parameters */
 
+    /* Dynamic pull group 0 for this coordinate with dynamic weights, only present when needed */
+    std::unique_ptr<pull_group_work_t> dynamicGroup0;
+
     double value_ref; /* The reference value, usually init+rate*t, units of nm or rad */
 
     PullCoordSpatialData spatialData; /* Data defining the current geometry */
@@ -236,7 +250,6 @@ struct pull_t
 
     /* Parameters + dynamic data for groups */
     std::vector<pull_group_work_t> group; /* The pull group param and work data */
-    std::vector<pull_group_work_t> dyna;  /* Dynamic groups for geom=cylinder */
 
     /* Parameters + dynamic data for coordinates */
     std::vector<pull_coord_work_t> coord; /* The pull group param and work data */
@@ -244,8 +257,7 @@ struct pull_t
     /* Global dynamic data */
     gmx_bool bSetPBCatoms; /* Do we need to set x_pbc for the groups? */
 
-    int                  nthreads; /* Number of threads used by the pull code */
-    std::vector<ComSums> comSums;  /* Work array for summing for COM, 1 entry per thread */
+    std::vector<ComSums> comSums; /* Work array for summing for COM, 1 entry per thread */
 
     pull_comm_t comm; /* Communication parameters, communicator and buffers */
 
index 17cb7bdd8cf6e9b6e9ce0e9e4f05910d02f9f823..f4e0ba526af8436cdd0ea69d604c32ae8ac3532d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +59,7 @@
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/linearalgebra/nrjac.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/groupcoord.h"
@@ -79,7 +80,7 @@
 #include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/smalloc.h"
 
-static char const* RotStr = { "Enforced rotation:" };
+static const std::string RotStr = { "Enforced rotation:" };
 
 /* Set the minimum weight for the determination of the slab centers */
 #define WEIGHT_MIN (10 * GMX_FLOAT_MIN)
@@ -323,16 +324,21 @@ gmx_enfrot* EnforcedRotation::getLegacyEnfrot()
 /* Activate output of forces for correctness checks */
 /* #define PRINT_FORCES */
 #ifdef PRINT_FORCES
-#    define PRINT_FORCE_J                                                                          \
-        fprintf(stderr, "f%d = %15.8f %15.8f %15.8f\n", erg->xc_ref_ind[j], erg->f_rot_loc[j][XX], \
-                erg->f_rot_loc[j][YY], erg->f_rot_loc[j][ZZ]);
+#    define PRINT_FORCE_J                       \
+        fprintf(stderr,                         \
+                "f%d = %15.8f %15.8f %15.8f\n", \
+                erg->xc_ref_ind[j],             \
+                erg->f_rot_loc[j][XX],          \
+                erg->f_rot_loc[j][YY],          \
+                erg->f_rot_loc[j][ZZ]);
 #    define PRINT_POT_TAU                   \
         if (MASTER(cr))                     \
         {                                   \
             fprintf(stderr,                 \
                     "potential = %15.8f\n"  \
                     "torque    = %15.8f\n", \
-                    erg->V, erg->torque_v); \
+                    erg->V,                 \
+                    erg->torque_v);         \
         }
 #else
 #    define PRINT_FORCE_J
@@ -340,12 +346,16 @@ gmx_enfrot* EnforcedRotation::getLegacyEnfrot()
 #endif
 
 /* Shortcuts for often used queries */
-#define ISFLEX(rg)                                                                            \
-    (((rg)->eType == erotgFLEX) || ((rg)->eType == erotgFLEXT) || ((rg)->eType == erotgFLEX2) \
-     || ((rg)->eType == erotgFLEX2T))
-#define ISCOLL(rg)                                                                            \
-    (((rg)->eType == erotgFLEX) || ((rg)->eType == erotgFLEXT) || ((rg)->eType == erotgFLEX2) \
-     || ((rg)->eType == erotgFLEX2T) || ((rg)->eType == erotgRMPF) || ((rg)->eType == erotgRM2PF))
+#define ISFLEX(rg)                                                                                         \
+    (((rg)->eType == EnforcedRotationGroupType::Flex) || ((rg)->eType == EnforcedRotationGroupType::Flext) \
+     || ((rg)->eType == EnforcedRotationGroupType::Flex2)                                                  \
+     || ((rg)->eType == EnforcedRotationGroupType::Flex2t))
+#define ISCOLL(rg)                                                                                         \
+    (((rg)->eType == EnforcedRotationGroupType::Flex) || ((rg)->eType == EnforcedRotationGroupType::Flext) \
+     || ((rg)->eType == EnforcedRotationGroupType::Flex2)                                                  \
+     || ((rg)->eType == EnforcedRotationGroupType::Flex2t)                                                 \
+     || ((rg)->eType == EnforcedRotationGroupType::Rmpf)                                                   \
+     || ((rg)->eType == EnforcedRotationGroupType::Rm2pf))
 
 
 /* Does any of the rotation groups use slab decomposition? */
@@ -369,7 +379,7 @@ static gmx_bool HavePotFitGroups(const t_rot* rot)
 {
     for (int g = 0; g < rot->ngrp; g++)
     {
-        if (erotgFitPOT == rot->grp[g].eFittype)
+        if (RotationGroupFitting::Pot == rot->grp[g].eFittype)
         {
             return TRUE;
         }
@@ -435,7 +445,7 @@ static real get_fitangle(const gmx_enfrotgrp* erg)
 /* Reduce potential angle fit data for this group at this time step? */
 static inline gmx_bool bPotAngle(const gmx_enfrot* er, const t_rotgrp* rotg, int64_t step)
 {
-    return ((erotgFitPOT == rotg->eFittype)
+    return ((RotationGroupFitting::Pot == rotg->eFittype)
             && (do_per_step(step, er->nstsout) || do_per_step(step, er->nstrout)));
 }
 
@@ -486,12 +496,11 @@ static void reduce_output(const t_commrec* cr, gmx_enfrot* er, real t, int64_t s
         }
         if (count > er->mpi_bufsize)
         {
-            gmx_fatal(FARGS, "%s MPI buffer overflow, please report this error.", RotStr);
+            gmx_fatal(FARGS, "%s MPI buffer overflow, please report this error.", RotStr.c_str());
         }
 
 #if GMX_MPI
-        MPI_Reduce(er->mpi_inbuf, er->mpi_outbuf, count, GMX_MPI_REAL, MPI_SUM, MASTERRANK(cr),
-                   cr->mpi_comm_mygroup);
+        MPI_Reduce(er->mpi_inbuf, er->mpi_outbuf, count, GMX_MPI_REAL, MPI_SUM, MASTERRANK(cr), cr->mpi_comm_mygroup);
 #endif
 
         /* Copy back the reduced data from the buffer on the master */
@@ -539,7 +548,7 @@ static void reduce_output(const t_commrec* cr, gmx_enfrot* er, real t, int64_t s
             /* Output to main rotation output file: */
             if (do_per_step(step, er->nstrout))
             {
-                if (erotgFitPOT == rotg->eFittype)
+                if (RotationGroupFitting::Pot == rotg->eFittype)
                 {
                     fitangle = get_fitangle(erg);
                 }
@@ -578,7 +587,7 @@ static void reduce_output(const t_commrec* cr, gmx_enfrot* er, real t, int64_t s
                 }
 
                 /* Output to angles log file: */
-                if (erotgFitPOT == rotg->eFittype)
+                if (RotationGroupFitting::Pot == rotg->eFittype)
                 {
                     fprintf(er->out_angles, "%12.3e%6d%12.4f", t, erg->groupIndex, erg->degangle);
                     /* Output energies at a set of angles around the reference angle */
@@ -600,7 +609,7 @@ static void reduce_output(const t_commrec* cr, gmx_enfrot* er, real t, int64_t s
 
 /* Add the forces from enforced rotation potential to the local forces.
  * Should be called after the SR forces have been evaluated */
-real add_rot_forces(gmx_enfrot* er, rvec f[], const t_commrec* cr, int64_t step, real t)
+real add_rot_forces(gmx_enfrot* er, gmx::ArrayRef<gmx::RVec> force, const t_commrec* cr, int64_t step, real t)
 {
     real Vrot = 0.0; /* If more than one rotation group is present, Vrot
                         assembles the local parts from all groups         */
@@ -617,7 +626,7 @@ real add_rot_forces(gmx_enfrot* er, rvec f[], const t_commrec* cr, int64_t step,
             /* Get the right index of the local force */
             int ii = localRotationGroupIndex[l];
             /* Add */
-            rvec_inc(f[ii], erg->f_rot_loc[l]);
+            rvec_inc(force[ii], erg->f_rot_loc[l]);
         }
     }
 
@@ -742,8 +751,7 @@ static void get_slab_centers(gmx_enfrotgrp* erg,  /* Enforced rotation group wor
         /* We can do the calculations ONLY if there is weight in the slab! */
         if (erg->slab_weights[slabIndex] > WEIGHT_MIN)
         {
-            svmul(1.0 / erg->slab_weights[slabIndex], erg->slab_center[slabIndex],
-                  erg->slab_center[slabIndex]);
+            svmul(1.0 / erg->slab_weights[slabIndex], erg->slab_center[slabIndex], erg->slab_center[slabIndex]);
         }
         else
         {
@@ -766,8 +774,12 @@ static void get_slab_centers(gmx_enfrotgrp* erg,  /* Enforced rotation group wor
         for (int j = erg->slab_first; j <= erg->slab_last; j++)
         {
             int slabIndex = j - erg->slab_first;
-            fprintf(out_slabs, "%6d%12.3e%12.3e%12.3e", j, erg->slab_center[slabIndex][XX],
-                    erg->slab_center[slabIndex][YY], erg->slab_center[slabIndex][ZZ]);
+            fprintf(out_slabs,
+                    "%6d%12.3e%12.3e%12.3e",
+                    j,
+                    erg->slab_center[slabIndex][XX],
+                    erg->slab_center[slabIndex][YY],
+                    erg->slab_center[slabIndex][ZZ]);
         }
         fprintf(out_slabs, "\n");
     }
@@ -867,8 +879,7 @@ static FILE* open_output_file(const char* fn, int steps, const char what[])
 
     fp = gmx_ffopen(fn, "w");
 
-    fprintf(fp, "# Output of %s is written in intervals of %d time step%s.\n#\n", what, steps,
-            steps > 1 ? "s" : "");
+    fprintf(fp, "# Output of %s is written in intervals of %d time step%s.\n#\n", what, steps, steps > 1 ? "s" : "");
 
     return fp;
 }
@@ -892,8 +903,11 @@ static FILE* open_slab_out(const char* fn, gmx_enfrot* er)
             gmx_enfrotgrp* erg = &ergRef;
             if (ISFLEX(erg->rotg))
             {
-                fprintf(fp, "# Rotation group %d (%s), slab distance %f nm, %s.\n", erg->groupIndex,
-                        erotg_names[erg->rotg->eType], erg->rotg->slab_dist,
+                fprintf(fp,
+                        "# Rotation group %d (%s), slab distance %f nm, %s.\n",
+                        erg->groupIndex,
+                        enumValueToString(erg->rotg->eType),
+                        erg->rotg->slab_dist,
                         erg->rotg->bMassW ? "centers of mass" : "geometrical centers");
             }
         }
@@ -958,12 +972,16 @@ static FILE* open_rot_out(const char* fn, const gmx_output_env_t* oenv, gmx_enfr
     }
     else
     {
-        fp = xvgropen(fn, "Rotation angles and energy", "Time (ps)",
-                      "angles (degrees) and energies (kJ/mol)", oenv);
+        fp = xvgropen(fn,
+                      "Rotation angles and energy",
+                      "Time (ps)",
+                      "angles (degrees) and energies (kJ/mol)",
+                      oenv);
         fprintf(fp,
                 "# Output of enforced rotation data is written in intervals of %d time "
                 "step%s.\n#\n",
-                er->nstrout, er->nstrout > 1 ? "s" : "");
+                er->nstrout,
+                er->nstrout > 1 ? "s" : "");
         fprintf(fp,
                 "# The scalar tau is the torque (kJ/mol) in the direction of the rotation vector "
                 "v.\n");
@@ -980,17 +998,26 @@ static FILE* open_rot_out(const char* fn, const gmx_output_env_t* oenv, gmx_enfr
             bFlex                     = ISFLEX(rotg);
 
             fprintf(fp, "#\n");
-            fprintf(fp, "# ROTATION GROUP %d, potential type '%s':\n", g, erotg_names[rotg->eType]);
-            fprintf(fp, "# rot-massw%d          %s\n", g, yesno_names[rotg->bMassW]);
-            fprintf(fp, "# rot-vec%d            %12.5e %12.5e %12.5e\n", g, erg->vec[XX],
-                    erg->vec[YY], erg->vec[ZZ]);
+            fprintf(fp, "# ROTATION GROUP %d, potential type '%s':\n", g, enumValueToString(rotg->eType));
+            fprintf(fp, "# rot-massw%d          %s\n", g, booleanValueToString(rotg->bMassW));
+            fprintf(fp,
+                    "# rot-vec%d            %12.5e %12.5e %12.5e\n",
+                    g,
+                    erg->vec[XX],
+                    erg->vec[YY],
+                    erg->vec[ZZ]);
             fprintf(fp, "# rot-rate%d           %12.5e degrees/ps\n", g, rotg->rate);
             fprintf(fp, "# rot-k%d              %12.5e kJ/(mol*nm^2)\n", g, rotg->k);
-            if (rotg->eType == erotgISO || rotg->eType == erotgPM || rotg->eType == erotgRM
-                || rotg->eType == erotgRM2)
+            if (rotg->eType == EnforcedRotationGroupType::Iso || rotg->eType == EnforcedRotationGroupType::Pm
+                || rotg->eType == EnforcedRotationGroupType::Rm
+                || rotg->eType == EnforcedRotationGroupType::Rm2)
             {
-                fprintf(fp, "# rot-pivot%d          %12.5e %12.5e %12.5e  nm\n", g, rotg->pivot[XX],
-                        rotg->pivot[YY], rotg->pivot[ZZ]);
+                fprintf(fp,
+                        "# rot-pivot%d          %12.5e %12.5e %12.5e  nm\n",
+                        g,
+                        rotg->pivot[XX],
+                        rotg->pivot[YY],
+                        rotg->pivot[ZZ]);
             }
 
             if (bFlex)
@@ -1000,27 +1027,43 @@ static FILE* open_rot_out(const char* fn, const gmx_output_env_t* oenv, gmx_enfr
             }
 
             /* Output the centers of the rotation groups for the pivot-free potentials */
-            if ((rotg->eType == erotgISOPF) || (rotg->eType == erotgPMPF) || (rotg->eType == erotgRMPF)
-                || (rotg->eType == erotgRM2PF || (rotg->eType == erotgFLEXT) || (rotg->eType == erotgFLEX2T)))
+            if ((rotg->eType == EnforcedRotationGroupType::Isopf)
+                || (rotg->eType == EnforcedRotationGroupType::Pmpf)
+                || (rotg->eType == EnforcedRotationGroupType::Rmpf)
+                || (rotg->eType == EnforcedRotationGroupType::Rm2pf
+                    || (rotg->eType == EnforcedRotationGroupType::Flext)
+                    || (rotg->eType == EnforcedRotationGroupType::Flex2t)))
             {
-                fprintf(fp, "# ref. grp. %d center  %12.5e %12.5e %12.5e\n", g,
-                        erg->xc_ref_center[XX], erg->xc_ref_center[YY], erg->xc_ref_center[ZZ]);
+                fprintf(fp,
+                        "# ref. grp. %d center  %12.5e %12.5e %12.5e\n",
+                        g,
+                        erg->xc_ref_center[XX],
+                        erg->xc_ref_center[YY],
+                        erg->xc_ref_center[ZZ]);
 
-                fprintf(fp, "# grp. %d init.center  %12.5e %12.5e %12.5e\n", g, erg->xc_center[XX],
-                        erg->xc_center[YY], erg->xc_center[ZZ]);
+                fprintf(fp,
+                        "# grp. %d init.center  %12.5e %12.5e %12.5e\n",
+                        g,
+                        erg->xc_center[XX],
+                        erg->xc_center[YY],
+                        erg->xc_center[ZZ]);
             }
 
-            if ((rotg->eType == erotgRM2) || (rotg->eType == erotgFLEX2) || (rotg->eType == erotgFLEX2T))
+            if ((rotg->eType == EnforcedRotationGroupType::Rm2)
+                || (rotg->eType == EnforcedRotationGroupType::Flex2)
+                || (rotg->eType == EnforcedRotationGroupType::Flex2t))
             {
                 fprintf(fp, "# rot-eps%d            %12.5e nm^2\n", g, rotg->eps);
             }
-            if (erotgFitPOT == rotg->eFittype)
+            if (RotationGroupFitting::Pot == rotg->eFittype)
             {
                 fprintf(fp, "#\n");
                 fprintf(fp,
                         "# theta_fit%d is determined by first evaluating the potential for %d "
                         "angles around theta_ref%d.\n",
-                        g, rotg->PotAngle_nstep, g);
+                        g,
+                        rotg->PotAngle_nstep,
+                        g);
                 fprintf(fp,
                         "# The fit angle is the one with the smallest potential. It is given as "
                         "the deviation\n");
@@ -1059,7 +1102,7 @@ static FILE* open_rot_out(const char* fn, const gmx_output_env_t* oenv, gmx_enfr
 
             /* For flexible axis rotation we use RMSD fitting to determine the
              * actual angle of the rotation group */
-            if (bFlex || erotgFitPOT == rotg->eFittype)
+            if (bFlex || RotationGroupFitting::Pot == rotg->eFittype)
             {
                 sprintf(buf, "theta_fit%d", g);
             }
@@ -1126,7 +1169,7 @@ static FILE* open_angles_out(const char* fn, gmx_enfrot* er)
 
             /* Output for this group happens only if potential type is flexible or
              * if fit type is potential! */
-            if (ISFLEX(rotg) || (erotgFitPOT == rotg->eFittype))
+            if (ISFLEX(rotg) || (RotationGroupFitting::Pot == rotg->eFittype))
             {
                 if (ISFLEX(rotg))
                 {
@@ -1137,17 +1180,23 @@ static FILE* open_angles_out(const char* fn, gmx_enfrot* er)
                     buf[0] = '\0';
                 }
 
-                fprintf(fp, "#\n# ROTATION GROUP %d '%s',%s fit type '%s'.\n", g,
-                        erotg_names[rotg->eType], buf, erotg_fitnames[rotg->eFittype]);
+                fprintf(fp,
+                        "#\n# ROTATION GROUP %d '%s',%s fit type '%s'.\n",
+                        g,
+                        enumValueToString(rotg->eType),
+                        buf,
+                        enumValueToString(rotg->eFittype));
 
                 /* Special type of fitting using the potential minimum. This is
                  * done for the whole group only, not for the individual slabs. */
-                if (erotgFitPOT == rotg->eFittype)
+                if (RotationGroupFitting::Pot == rotg->eFittype)
                 {
                     fprintf(fp,
                             "#    To obtain theta_fit%d, the potential is evaluated for %d angles "
                             "around theta_ref%d\n",
-                            g, rotg->PotAngle_nstep, g);
+                            g,
+                            rotg->PotAngle_nstep,
+                            g);
                     fprintf(fp,
                             "#    The fit angle in the rotation standard outfile is the one with "
                             "minimal energy E(theta_fit) [kJ/mol].\n");
@@ -1160,7 +1209,7 @@ static FILE* open_angles_out(const char* fn, gmx_enfrot* er)
                 print_aligned_short(fp, "grp");
                 print_aligned(fp, "theta_ref");
 
-                if (erotgFitPOT == rotg->eFittype)
+                if (RotationGroupFitting::Pot == rotg->eFittype)
                 {
                     /* Output the set of angles around the reference angle */
                     for (int i = 0; i < rotg->PotAngle_nstep; i++)
@@ -1211,14 +1260,21 @@ static FILE* open_torque_out(const char* fn, gmx_enfrot* er)
             const gmx_enfrotgrp* erg  = &er->enfrotgrp[g];
             if (ISFLEX(rotg))
             {
-                fprintf(fp, "# Rotation group %d (%s), slab distance %f nm.\n", g,
-                        erotg_names[rotg->eType], rotg->slab_dist);
+                fprintf(fp,
+                        "# Rotation group %d (%s), slab distance %f nm.\n",
+                        g,
+                        enumValueToString(rotg->eType),
+                        rotg->slab_dist);
                 fprintf(fp,
                         "# The scalar tau is the torque (kJ/mol) in the direction of the rotation "
                         "vector.\n");
                 fprintf(fp, "# To obtain the vectorial torque, multiply tau with\n");
-                fprintf(fp, "# rot-vec%d            %10.3e %10.3e %10.3e\n", g, erg->vec[XX],
-                        erg->vec[YY], erg->vec[ZZ]);
+                fprintf(fp,
+                        "# rot-vec%d            %10.3e %10.3e %10.3e\n",
+                        g,
+                        erg->vec[XX],
+                        erg->vec[YY],
+                        erg->vec[ZZ]);
                 fprintf(fp, "#\n");
             }
         }
@@ -1572,7 +1628,7 @@ static real flex_fit_angle(gmx_enfrotgrp* erg)
     get_center(erg->xc, erg->mc_sorted, erg->rotg->nat, center);
 
     /* === Determine the optimal fit angle for the rotation group === */
-    if (erg->rotg->eFittype == erotgFitNORM)
+    if (erg->rotg->eFittype == RotationGroupFitting::Norm)
     {
         /* Normalize every position to it's reference length */
         for (int i = 0; i < erg->rotg->nat; i++)
@@ -1593,8 +1649,8 @@ static real flex_fit_angle(gmx_enfrotgrp* erg)
     /* From the point of view of the current positions, the reference has rotated
      * backwards. Since we output the angle relative to the fixed reference,
      * we need the minus sign. */
-    fitangle = -opt_angle_analytic(erg->xc_ref_sorted, fitcoords, erg->mc_sorted, erg->rotg->nat,
-                                   erg->xc_ref_center, center, erg->vec);
+    fitangle = -opt_angle_analytic(
+            erg->xc_ref_sorted, fitcoords, erg->mc_sorted, erg->rotg->nat, erg->xc_ref_center, center, erg->vec);
 
     return fitangle;
 }
@@ -1677,7 +1733,7 @@ static void flex_fit_angle_perslab(gmx_enfrotgrp* erg, double t, real degangle,
             /* Get the center of the slabs reference and current positions */
             get_center(sd->ref, sd->weight, sd->nat, ref_center);
             get_center(sd->x, sd->weight, sd->nat, act_center);
-            if (erg->rotg->eFittype == erotgFitNORM)
+            if (erg->rotg->eFittype == RotationGroupFitting::Norm)
             {
                 /* Normalize every position to it's reference length
                  * prior to performing the fit */
@@ -1692,8 +1748,8 @@ static void flex_fit_angle_perslab(gmx_enfrotgrp* erg, double t, real degangle,
                 clear_rvec(ref_center);
                 clear_rvec(act_center);
             }
-            fitangle = -opt_angle_analytic(sd->ref, sd->x, sd->weight, sd->nat, ref_center,
-                                           act_center, erg->vec);
+            fitangle = -opt_angle_analytic(
+                    sd->ref, sd->x, sd->weight, sd->nat, ref_center, act_center, erg->vec);
             fprintf(fp, "%6d%6d%12.3f", n, sd->nat, fitangle);
         }
     }
@@ -1954,12 +2010,12 @@ static void flex_precalc_inner_sum(const gmx_enfrotgrp* erg)
 }
 
 
-static real do_flex2_lowlevel(gmx_enfrotgrp* erg,
-                              real           sigma, /* The Gaussian width sigma */
-                              rvec           x[],
-                              gmx_bool       bOutstepRot,
-                              gmx_bool       bOutstepSlab,
-                              const matrix   box)
+static real do_flex2_lowlevel(gmx_enfrotgrp*                 erg,
+                              real                           sigma, /* The Gaussian width sigma */
+                              gmx::ArrayRef<const gmx::RVec> coords,
+                              gmx_bool                       bOutstepRot,
+                              gmx_bool                       bOutstepSlab,
+                              const matrix                   box)
 {
     int  count, ii, iigrp;
     rvec xj;          /* position in the i-sum                         */
@@ -1995,7 +2051,7 @@ static real do_flex2_lowlevel(gmx_enfrotgrp* erg,
      * them again for every atom */
     flex2_precalc_inner_sum(erg);
 
-    bCalcPotFit = (bOutstepRot || bOutstepSlab) && (erotgFitPOT == erg->rotg->eFittype);
+    bCalcPotFit = (bOutstepRot || bOutstepSlab) && (RotationGroupFitting::Pot == erg->rotg->eFittype);
 
     /********************************************************/
     /* Main loop over all local atoms of the rotation group */
@@ -2020,7 +2076,7 @@ static real do_flex2_lowlevel(gmx_enfrotgrp* erg,
          * Note that erg->xc_center contains the center of mass in case the flex2-t
          * potential was chosen. For the flex2 potential erg->xc_center must be
          * zero. */
-        rvec_sub(x[ii], erg->xc_center, xj);
+        rvec_sub(coords[ii], erg->xc_center, xj);
 
         /* Shift this atom such that it is near its reference */
         shift_single_coord(box, xj, erg->xc_shifts[iigrp]);
@@ -2191,14 +2247,26 @@ static real do_flex2_lowlevel(gmx_enfrotgrp* erg,
         }
 
 #ifdef SUM_PARTS
-        fprintf(stderr, "sum1: %15.8f %15.8f %15.8f\n", -erg->rotg->k * sum1vec[XX],
-                -erg->rotg->k * sum1vec[YY], -erg->rotg->k * sum1vec[ZZ]);
-        fprintf(stderr, "sum2: %15.8f %15.8f %15.8f\n", erg->rotg->k * sum2vec[XX],
-                erg->rotg->k * sum2vec[YY], erg->rotg->k * sum2vec[ZZ]);
-        fprintf(stderr, "sum3: %15.8f %15.8f %15.8f\n", -erg->rotg->k * sum3vec[XX],
-                -erg->rotg->k * sum3vec[YY], -erg->rotg->k * sum3vec[ZZ]);
-        fprintf(stderr, "sum4: %15.8f %15.8f %15.8f\n", 0.5 * erg->rotg->k * sum4vec[XX],
-                0.5 * erg->rotg->k * sum4vec[YY], 0.5 * erg->rotg->k * sum4vec[ZZ]);
+        fprintf(stderr,
+                "sum1: %15.8f %15.8f %15.8f\n",
+                -erg->rotg->k * sum1vec[XX],
+                -erg->rotg->k * sum1vec[YY],
+                -erg->rotg->k * sum1vec[ZZ]);
+        fprintf(stderr,
+                "sum2: %15.8f %15.8f %15.8f\n",
+                erg->rotg->k * sum2vec[XX],
+                erg->rotg->k * sum2vec[YY],
+                erg->rotg->k * sum2vec[ZZ]);
+        fprintf(stderr,
+                "sum3: %15.8f %15.8f %15.8f\n",
+                -erg->rotg->k * sum3vec[XX],
+                -erg->rotg->k * sum3vec[YY],
+                -erg->rotg->k * sum3vec[ZZ]);
+        fprintf(stderr,
+                "sum4: %15.8f %15.8f %15.8f\n",
+                0.5 * erg->rotg->k * sum4vec[XX],
+                0.5 * erg->rotg->k * sum4vec[YY],
+                0.5 * erg->rotg->k * sum4vec[ZZ]);
 #endif
 
         PRINT_FORCE_J
@@ -2210,11 +2278,11 @@ static real do_flex2_lowlevel(gmx_enfrotgrp* erg,
 
 
 static real do_flex_lowlevel(gmx_enfrotgrp* erg,
-                             real         sigma, /* The Gaussian width sigma                      */
-                             rvec         x[],
-                             gmx_bool     bOutstepRot,
-                             gmx_bool     bOutstepSlab,
-                             const matrix box)
+                             real sigma, /* The Gaussian width sigma                      */
+                             gmx::ArrayRef<const gmx::RVec> coords,
+                             gmx_bool                       bOutstepRot,
+                             gmx_bool                       bOutstepSlab,
+                             const matrix                   box)
 {
     int      count, iigrp;
     rvec     xj, yj0;        /* current and reference position                */
@@ -2242,7 +2310,7 @@ static real do_flex_lowlevel(gmx_enfrotgrp* erg,
      * them again for every atom */
     flex_precalc_inner_sum(erg);
 
-    bCalcPotFit = (bOutstepRot || bOutstepSlab) && (erotgFitPOT == erg->rotg->eFittype);
+    bCalcPotFit = (bOutstepRot || bOutstepSlab) && (RotationGroupFitting::Pot == erg->rotg->eFittype);
 
     /********************************************************/
     /* Main loop over all local atoms of the rotation group */
@@ -2267,7 +2335,7 @@ static real do_flex_lowlevel(gmx_enfrotgrp* erg,
          * Note that erg->xc_center contains the center of mass in case the flex-t
          * potential was chosen. For the flex potential erg->xc_center must be
          * zero. */
-        rvec_sub(x[ii], erg->xc_center, xj);
+        rvec_sub(coords[ii], erg->xc_center, xj);
 
         /* Shift this atom such that it is near its reference */
         shift_single_coord(box, xj, erg->xc_shifts[iigrp]);
@@ -2525,14 +2593,18 @@ static void get_firstlast_slab_check(gmx_enfrotgrp* erg, /* The rotation group (
     /* Check whether we have reference data to compare against */
     if (erg->slab_first < erg->slab_first_ref)
     {
-        gmx_fatal(FARGS, "%s No reference data for first slab (n=%d), unable to proceed.", RotStr,
+        gmx_fatal(FARGS,
+                  "%s No reference data for first slab (n=%d), unable to proceed.",
+                  RotStr.c_str(),
                   erg->slab_first);
     }
 
     /* Check whether we have reference data to compare against */
     if (erg->slab_last > erg->slab_last_ref)
     {
-        gmx_fatal(FARGS, "%s No reference data for last slab (n=%d), unable to proceed.", RotStr,
+        gmx_fatal(FARGS,
+                  "%s No reference data for last slab (n=%d), unable to proceed.",
+                  RotStr.c_str(),
                   erg->slab_last);
     }
 }
@@ -2542,11 +2614,11 @@ static void get_firstlast_slab_check(gmx_enfrotgrp* erg, /* The rotation group (
 static void do_flexible(gmx_bool       bMaster,
                         gmx_enfrot*    enfrot, /* Other rotation data                        */
                         gmx_enfrotgrp* erg,
-                        rvec           x[], /* The local positions                        */
-                        const matrix   box,
-                        double         t,           /* Time in picoseconds                        */
-                        gmx_bool       bOutstepRot, /* Output to main rotation output file        */
-                        gmx_bool bOutstepSlab)      /* Output per-slab data                       */
+                        gmx::ArrayRef<const gmx::RVec> coords, /* The local positions */
+                        const matrix                   box,
+                        double   t,            /* Time in picoseconds                        */
+                        gmx_bool bOutstepRot,  /* Output to main rotation output file        */
+                        gmx_bool bOutstepSlab) /* Output per-slab data                       */
 {
     int  nslabs;
     real sigma; /* The Gaussian width sigma */
@@ -2577,13 +2649,15 @@ static void do_flexible(gmx_bool       bMaster,
     }
 
     /* Call the rotational forces kernel */
-    if (erg->rotg->eType == erotgFLEX || erg->rotg->eType == erotgFLEXT)
+    if (erg->rotg->eType == EnforcedRotationGroupType::Flex
+        || erg->rotg->eType == EnforcedRotationGroupType::Flext)
     {
-        erg->V = do_flex_lowlevel(erg, sigma, x, bOutstepRot, bOutstepSlab, box);
+        erg->V = do_flex_lowlevel(erg, sigma, coords, bOutstepRot, bOutstepSlab, box);
     }
-    else if (erg->rotg->eType == erotgFLEX2 || erg->rotg->eType == erotgFLEX2T)
+    else if (erg->rotg->eType == EnforcedRotationGroupType::Flex2
+             || erg->rotg->eType == EnforcedRotationGroupType::Flex2t)
     {
-        erg->V = do_flex2_lowlevel(erg, sigma, x, bOutstepRot, bOutstepSlab, box);
+        erg->V = do_flex2_lowlevel(erg, sigma, coords, bOutstepRot, bOutstepSlab, box);
     }
     else
     {
@@ -2592,7 +2666,7 @@ static void do_flexible(gmx_bool       bMaster,
 
     /* Determine angle by RMSD fit to the reference - Let's hope this */
     /* only happens once in a while, since this is not parallelized! */
-    if (bMaster && (erotgFitPOT != erg->rotg->eFittype))
+    if (bMaster && (RotationGroupFitting::Pot != erg->rotg->eFittype))
     {
         if (bOutstepRot)
         {
@@ -2689,8 +2763,9 @@ static void do_fixed(gmx_enfrotgrp* erg,
 
     gmx_bool bProject;
 
-    bProject    = (erg->rotg->eType == erotgPM) || (erg->rotg->eType == erotgPMPF);
-    bCalcPotFit = (bOutstepRot || bOutstepSlab) && (erotgFitPOT == erg->rotg->eFittype);
+    bProject = (erg->rotg->eType == EnforcedRotationGroupType::Pm)
+               || (erg->rotg->eType == EnforcedRotationGroupType::Pmpf);
+    bCalcPotFit = (bOutstepRot || bOutstepSlab) && (RotationGroupFitting::Pot == erg->rotg->eFittype);
 
     N_M                                      = erg->rotg->nat * erg->invmass;
     const auto& collectiveRotationGroupIndex = erg->atomSet->collectiveIndex();
@@ -2732,8 +2807,7 @@ static void do_fixed(gmx_enfrotgrp* erg,
 
                 /* Rotate with the alternative angle. Like rotate_local_reference(),
                  * just for a single local atom */
-                mvmul(erg->PotAngleFit->rotmat[ifit], erg->rotg->x_ref[jj],
-                      fit_xr_loc); /* fit_xr_loc = Omega*(y_i-y_c) */
+                mvmul(erg->PotAngleFit->rotmat[ifit], erg->rotg->x_ref[jj], fit_xr_loc); /* fit_xr_loc = Omega*(y_i-y_c) */
 
                 /* Calculate Omega*(y_i-y_c)-(x_i-x_c) */
                 rvec_sub(fit_xr_loc, xi_xc, dr);
@@ -2793,7 +2867,7 @@ static void do_radial_motion(gmx_enfrotgrp* erg,
     real wj;  /* Mass-weighting of the positions */
     real N_M; /* N/M */
 
-    bCalcPotFit = (bOutstepRot || bOutstepSlab) && (erotgFitPOT == erg->rotg->eFittype);
+    bCalcPotFit = (bOutstepRot || bOutstepSlab) && (RotationGroupFitting::Pot == erg->rotg->eFittype);
 
     N_M                                      = erg->rotg->nat * erg->invmass;
     const auto& collectiveRotationGroupIndex = erg->atomSet->collectiveIndex();
@@ -2833,8 +2907,7 @@ static void do_radial_motion(gmx_enfrotgrp* erg,
 
                 /* Rotate with the alternative angle. Like rotate_local_reference(),
                  * just for a single local atom */
-                mvmul(erg->PotAngleFit->rotmat[ifit], erg->rotg->x_ref[jj],
-                      fit_tmpvec); /* fit_tmpvec = Omega*(yj0-u) */
+                mvmul(erg->PotAngleFit->rotmat[ifit], erg->rotg->x_ref[jj], fit_tmpvec); /* fit_tmpvec = Omega*(yj0-u) */
 
                 /* Calculate Omega.(yj0-u) */
                 cprod(erg->vec, fit_tmpvec, tmpvec); /* tmpvec = v x Omega.(yj0-u) */
@@ -2869,11 +2942,11 @@ static void do_radial_motion(gmx_enfrotgrp* erg,
 
 
 /* Calculate the radial motion pivot-free potential and forces */
-static void do_radial_motion_pf(gmx_enfrotgrp* erg,
-                                rvec           x[], /* The positions                              */
-                                const matrix   box, /* The simulation box                         */
-                                gmx_bool bOutstepRot,  /* Output to main rotation output file  */
-                                gmx_bool bOutstepSlab) /* Output per-slab data */
+static void do_radial_motion_pf(gmx_enfrotgrp*                 erg,
+                                gmx::ArrayRef<const gmx::RVec> coords, /* The positions */
+                                const matrix box, /* The simulation box                         */
+                                gmx_bool     bOutstepRot, /* Output to main rotation output file  */
+                                gmx_bool     bOutstepSlab)    /* Output per-slab data */
 {
     rvec     xj;      /* Current position */
     rvec     xj_xc;   /* xj  - xc  */
@@ -2892,7 +2965,7 @@ static void do_radial_motion_pf(gmx_enfrotgrp* erg,
     real mj, wi, wj; /* Mass-weighting of the positions */
     real N_M;        /* N/M */
 
-    bCalcPotFit = (bOutstepRot || bOutstepSlab) && (erotgFitPOT == erg->rotg->eFittype);
+    bCalcPotFit = (bOutstepRot || bOutstepSlab) && (RotationGroupFitting::Pot == erg->rotg->eFittype);
 
     N_M = erg->rotg->nat * erg->invmass;
 
@@ -2938,7 +3011,7 @@ static void do_radial_motion_pf(gmx_enfrotgrp* erg,
         wj = N_M * mj;
 
         /* Current position of this atom: x[ii][XX/YY/ZZ] */
-        copy_rvec(x[ii], xj);
+        copy_rvec(coords[ii], xj);
 
         /* Shift this atom such that it is near its reference */
         shift_single_coord(box, xj, erg->xc_shifts[iigrp]);
@@ -3071,9 +3144,9 @@ static void radial_motion2_precalc_inner_sum(const gmx_enfrotgrp* erg, rvec inne
 
 
 /* Calculate the radial motion 2 potential and forces */
-static void do_radial_motion2(gmx_enfrotgrp* erg,
-                              rvec           x[],   /* The positions                              */
-                              const matrix   box,   /* The simulation box                         */
+static void do_radial_motion2(gmx_enfrotgrp*                 erg,
+                              gmx::ArrayRef<const gmx::RVec> coords, /* The positions */
+                              const matrix box,     /* The simulation box                         */
                               gmx_bool bOutstepRot, /* Output to main rotation output file        */
                               gmx_bool bOutstepSlab) /* Output per-slab data */
 {
@@ -3094,8 +3167,8 @@ static void do_radial_motion2(gmx_enfrotgrp* erg,
     rvec     innersumvec;
     gmx_bool bCalcPotFit;
 
-    bPF         = erg->rotg->eType == erotgRM2PF;
-    bCalcPotFit = (bOutstepRot || bOutstepSlab) && (erotgFitPOT == erg->rotg->eFittype);
+    bPF         = erg->rotg->eType == EnforcedRotationGroupType::Rm2pf;
+    bCalcPotFit = (bOutstepRot || bOutstepSlab) && (RotationGroupFitting::Pot == erg->rotg->eFittype);
 
     clear_rvec(yj0_yc0); /* Make the compiler happy */
 
@@ -3128,7 +3201,7 @@ static void do_radial_motion2(gmx_enfrotgrp* erg,
             mj = erg->mc[iigrp];
 
             /* Current position of this atom: x[ii] */
-            copy_rvec(x[ii], xj);
+            copy_rvec(coords[ii], xj);
 
             /* Shift this atom such that it is near its reference */
             shift_single_coord(box, xj, erg->xc_shifts[iigrp]);
@@ -3199,8 +3272,7 @@ static void do_radial_motion2(gmx_enfrotgrp* erg,
                     int iigrp = collectiveRotationGroupIndex[j];
                     /* Rotate with the alternative angle. Like rotate_local_reference(),
                      * just for a single local atom */
-                    mvmul(erg->PotAngleFit->rotmat[ifit], erg->rotg->x_ref[iigrp],
-                          fit_rj); /* fit_rj = Omega*(yj0-u) */
+                    mvmul(erg->PotAngleFit->rotmat[ifit], erg->rotg->x_ref[iigrp], fit_rj); /* fit_rj = Omega*(yj0-u) */
                 }
                 fit_fac = iprod(v_xj_u, fit_rj); /* fac = (v x (xj-u)).fit_rj */
                 /* Add to the rotation potential for this angle: */
@@ -3275,8 +3347,11 @@ static void allocate_slabs(gmx_enfrotgrp* erg, FILE* fplog, gmx_bool bVerbose)
 
     if ((nullptr != fplog) && bVerbose)
     {
-        fprintf(fplog, "%s allocating memory to store data for %d slabs (rotation group %d).\n",
-                RotStr, nslabs, erg->groupIndex);
+        fprintf(fplog,
+                "%s allocating memory to store data for %d slabs (rotation group %d).\n",
+                RotStr.c_str(),
+                nslabs,
+                erg->groupIndex);
     }
     snew(erg->slab_center, nslabs);
     snew(erg->slab_center_ref, nslabs);
@@ -3368,16 +3443,16 @@ static inline void copy_correct_pbc_image(const rvec xcurr, /* copy vector xcurr
 }
 
 
-static void init_rot_group(FILE*            fplog,
-                           const t_commrec* cr,
-                           gmx_enfrotgrp*   erg,
-                           rvec*            x,
-                           gmx_mtop_t*      mtop,
-                           gmx_bool         bVerbose,
-                           FILE*            out_slabs,
-                           const matrix     box,
-                           t_inputrec*      ir,
-                           gmx_bool         bOutputCenters)
+static void init_rot_group(FILE*             fplog,
+                           const t_commrec*  cr,
+                           gmx_enfrotgrp*    erg,
+                           rvec*             x,
+                           const gmx_mtop_t& mtop,
+                           gmx_bool          bVerbose,
+                           FILE*             out_slabs,
+                           const matrix      box,
+                           t_inputrec*       ir,
+                           gmx_bool          bOutputCenters)
 {
     rvec            coord, xref, *xdum;
     gmx_bool        bFlex, bColl;
@@ -3401,7 +3476,7 @@ static void init_rot_group(FILE*            fplog,
         snew(erg->xc_eshifts, erg->rotg->nat);
         snew(erg->xc_old, erg->rotg->nat);
 
-        if (erg->rotg->eFittype == erotgFitNORM)
+        if (erg->rotg->eFittype == RotationGroupFitting::Norm)
         {
             snew(erg->xc_ref_length, erg->rotg->nat); /* in case fit type NORM is chosen */
             snew(erg->xc_norm, erg->rotg->nat);
@@ -3418,7 +3493,7 @@ static void init_rot_group(FILE*            fplog,
 
     /* Make space for the calculation of the potential at other angles (used
      * for fitting only) */
-    if (erotgFitPOT == erg->rotg->eFittype)
+    if (RotationGroupFitting::Pot == erg->rotg->eFittype)
     {
         snew(erg->PotAngleFit, 1);
         snew(erg->PotAngleFit->degangle, erg->rotg->PotAngle_nstep);
@@ -3466,8 +3541,10 @@ static void init_rot_group(FILE*            fplog,
     erg->invmass = 1.0 / totalmass;
 
     /* Set xc_ref_center for any rotation potential */
-    if ((erg->rotg->eType == erotgISO) || (erg->rotg->eType == erotgPM)
-        || (erg->rotg->eType == erotgRM) || (erg->rotg->eType == erotgRM2))
+    if ((erg->rotg->eType == EnforcedRotationGroupType::Iso)
+        || (erg->rotg->eType == EnforcedRotationGroupType::Pm)
+        || (erg->rotg->eType == EnforcedRotationGroupType::Rm)
+        || (erg->rotg->eType == EnforcedRotationGroupType::Rm2))
     {
         /* Set the pivot point for the fixed, stationary-axis potentials. This
          * won't change during the simulation */
@@ -3534,7 +3611,8 @@ static void init_rot_group(FILE*            fplog,
 #endif
     }
 
-    if ((erg->rotg->eType != erotgFLEX) && (erg->rotg->eType != erotgFLEX2))
+    if ((erg->rotg->eType != EnforcedRotationGroupType::Flex)
+        && (erg->rotg->eType != EnforcedRotationGroupType::Flex2))
     {
         /* Put the reference positions into origin: */
         for (int i = 0; i < erg->rotg->nat; i++)
@@ -3565,7 +3643,7 @@ static void init_rot_group(FILE*            fplog,
         get_slab_centers(erg, erg->rotg->x_ref, erg->mc, -1, out_slabs, bOutputCenters, TRUE);
 
         /* Length of each x_rotref vector from center (needed if fit routine NORM is chosen): */
-        if (erg->rotg->eFittype == erotgFitNORM)
+        if (erg->rotg->eFittype == RotationGroupFitting::Norm)
         {
             for (int i = 0; i < erg->rotg->nat; i++)
             {
@@ -3596,7 +3674,7 @@ static int calc_mpi_bufsize(const gmx_enfrot* er)
         }
 
         /* Add space for the potentials at different angles: */
-        if (erotgFitPOT == erg->rotg->eFittype)
+        if (RotationGroupFitting::Pot == erg->rotg->eFittype)
         {
             count_group += erg->rotg->PotAngle_nstep;
         }
@@ -3616,7 +3694,7 @@ std::unique_ptr<gmx::EnforcedRotation> init_rot(FILE*                       fplo
                                                 const t_commrec*            cr,
                                                 gmx::LocalAtomSetManager*   atomSets,
                                                 const t_state*              globalState,
-                                                gmx_mtop_t*                 mtop,
+                                                const gmx_mtop_t&           mtop,
                                                 const gmx_output_env_t*     oenv,
                                                 const gmx::MdrunOptions&    mdrunOptions,
                                                 const gmx::StartingBehavior startingBehavior)
@@ -3626,7 +3704,7 @@ std::unique_ptr<gmx::EnforcedRotation> init_rot(FILE*                       fplo
 
     if (MASTER(cr) && mdrunOptions.verbose)
     {
-        fprintf(stdout, "%s Initializing ...\n", RotStr);
+        fprintf(stdout, "%s Initializing ...\n", RotStr.c_str());
     }
 
     auto        enforcedRotation = std::make_unique<gmx::EnforcedRotation>();
@@ -3648,7 +3726,7 @@ std::unique_ptr<gmx::EnforcedRotation> init_rot(FILE*                       fplo
     {
         if (nullptr != fplog)
         {
-            fprintf(fplog, "%s rerun - will write rotation output every available step.\n", RotStr);
+            fprintf(fplog, "%s rerun - will write rotation output every available step.\n", RotStr.c_str());
         }
         er->nstrout = 1;
         er->nstsout = 1;
@@ -3669,9 +3747,9 @@ std::unique_ptr<gmx::EnforcedRotation> init_rot(FILE*                       fplo
     {
         /* Remove pbc, make molecule whole.
          * When ir->bContinuation=TRUE this has already been done, but ok. */
-        snew(x_pbc, mtop->natoms);
-        copy_rvecn(globalState->x.rvec_array(), x_pbc, 0, mtop->natoms);
-        do_pbc_first_mtop(nullptr, ir->pbcType, globalState->box, mtop, x_pbc);
+        snew(x_pbc, mtop.natoms);
+        copy_rvecn(globalState->x.rvec_array(), x_pbc, 0, mtop.natoms);
+        do_pbc_first_mtop(nullptr, ir->pbcType, globalState->box, &mtop, x_pbc);
         /* All molecules will be whole now, but not necessarily in the home box.
          * Additionally, if a rotation group consists of more than one molecule
          * (e.g. two strands of DNA), each one of them can end up in a different
@@ -3691,15 +3769,26 @@ std::unique_ptr<gmx::EnforcedRotation> init_rot(FILE*                       fplo
 
         if (nullptr != fplog)
         {
-            fprintf(fplog, "%s group %d type '%s'\n", RotStr, groupIndex, erotg_names[erg->rotg->eType]);
+            fprintf(fplog,
+                    "%s group %d type '%s'\n",
+                    RotStr.c_str(),
+                    groupIndex,
+                    enumValueToString(erg->rotg->eType));
         }
 
         if (erg->rotg->nat > 0)
         {
             nat_max = std::max(nat_max, erg->rotg->nat);
 
-            init_rot_group(fplog, cr, erg, x_pbc, mtop, mdrunOptions.verbose, er->out_slabs,
-                           MASTER(cr) ? globalState->box : nullptr, ir,
+            init_rot_group(fplog,
+                           cr,
+                           erg,
+                           x_pbc,
+                           mtop,
+                           mdrunOptions.verbose,
+                           er->out_slabs,
+                           MASTER(cr) ? globalState->box : nullptr,
+                           ir,
                            !er->restartWithAppending); /* Do not output the reference centers
                                                         * again if we are appending */
         }
@@ -3773,7 +3862,7 @@ static void rotate_local_reference(gmx_enfrotgrp* erg)
 /* Select the PBC representation for each local x position and store that
  * for later usage. We assume the right PBC image of an x is the one nearest to
  * its rotated reference */
-static void choose_pbc_image(rvec x[], gmx_enfrotgrp* erg, const matrix box, int npbcdim)
+static void choose_pbc_image(gmx::ArrayRef<const gmx::RVec> coords, gmx_enfrotgrp* erg, const matrix box, int npbcdim)
 {
     const auto& localRotationGroupIndex = erg->atomSet->localIndex();
     for (gmx::index i = 0; i < localRotationGroupIndex.ssize(); i++)
@@ -3790,12 +3879,18 @@ static void choose_pbc_image(rvec x[], gmx_enfrotgrp* erg, const matrix box, int
         copy_rvec(erg->xr_loc[i], xref);
         rvec_inc(xref, erg->xc_ref_center);
 
-        copy_correct_pbc_image(x[ii], erg->x_loc_pbc[i], xref, box, npbcdim);
+        copy_correct_pbc_image(coords[ii], erg->x_loc_pbc[i], xref, box, npbcdim);
     }
 }
 
 
-void do_rotation(const t_commrec* cr, gmx_enfrot* er, const matrix box, rvec x[], real t, int64_t step, gmx_bool bNS)
+void do_rotation(const t_commrec*               cr,
+                 gmx_enfrot*                    er,
+                 const matrix                   box,
+                 gmx::ArrayRef<const gmx::RVec> coords,
+                 real                           t,
+                 int64_t                        step,
+                 gmx_bool                       bNS)
 {
     gmx_bool    outstep_slab, outstep_rot;
     gmx_bool    bColl;
@@ -3837,10 +3932,18 @@ void do_rotation(const t_commrec* cr, gmx_enfrot* er, const matrix box, rvec x[]
             /* Transfer the rotation group's positions such that every node has
              * all of them. Every node contributes its local positions x and stores
              * it in the collective erg->xc array. */
-            communicate_group_positions(cr, erg->xc, erg->xc_shifts, erg->xc_eshifts, bNS, x,
-                                        rotg->nat, erg->atomSet->numAtomsLocal(),
+            communicate_group_positions(cr,
+                                        erg->xc,
+                                        erg->xc_shifts,
+                                        erg->xc_eshifts,
+                                        bNS,
+                                        as_rvec_array(coords.data()),
+                                        rotg->nat,
+                                        erg->atomSet->numAtomsLocal(),
                                         erg->atomSet->localIndex().data(),
-                                        erg->atomSet->collectiveIndex().data(), erg->xc_old, box);
+                                        erg->atomSet->collectiveIndex().data(),
+                                        erg->xc_old,
+                                        box);
         }
         else
         {
@@ -3862,13 +3965,14 @@ void do_rotation(const t_commrec* cr, gmx_enfrot* er, const matrix box, rvec x[]
 
             /* Choose the nearest PBC images of the group atoms with respect
              * to the rotated reference positions */
-            choose_pbc_image(x, erg, box, 3);
+            choose_pbc_image(coords, erg, box, 3);
 
             /* Get the center of the rotation group */
-            if ((rotg->eType == erotgISOPF) || (rotg->eType == erotgPMPF))
+            if ((rotg->eType == EnforcedRotationGroupType::Isopf)
+                || (rotg->eType == EnforcedRotationGroupType::Pmpf))
             {
-                get_center_comm(cr, erg->x_loc_pbc, erg->m_loc, erg->atomSet->numAtomsLocal(),
-                                rotg->nat, erg->xc_center);
+                get_center_comm(
+                        cr, erg->x_loc_pbc, erg->m_loc, erg->atomSet->numAtomsLocal(), rotg->nat, erg->xc_center);
             }
         }
 
@@ -3896,7 +4000,7 @@ void do_rotation(const t_commrec* cr, gmx_enfrot* er, const matrix box, rvec x[]
         }
 
         /* Calculate angles and rotation matrices for potential fitting: */
-        if ((outstep_rot || outstep_slab) && (erotgFitPOT == rotg->eFittype))
+        if ((outstep_rot || outstep_slab) && (RotationGroupFitting::Pot == rotg->eFittype))
         {
             fit = erg->PotAngleFit;
             for (int i = 0; i < rotg->PotAngle_nstep; i++)
@@ -3916,29 +4020,35 @@ void do_rotation(const t_commrec* cr, gmx_enfrot* er, const matrix box, rvec x[]
 
         switch (rotg->eType)
         {
-            case erotgISO:
-            case erotgISOPF:
-            case erotgPM:
-            case erotgPMPF: do_fixed(erg, outstep_rot, outstep_slab); break;
-            case erotgRM: do_radial_motion(erg, outstep_rot, outstep_slab); break;
-            case erotgRMPF: do_radial_motion_pf(erg, x, box, outstep_rot, outstep_slab); break;
-            case erotgRM2:
-            case erotgRM2PF: do_radial_motion2(erg, x, box, outstep_rot, outstep_slab); break;
-            case erotgFLEXT:
-            case erotgFLEX2T:
+            case EnforcedRotationGroupType::Iso:
+            case EnforcedRotationGroupType::Isopf:
+            case EnforcedRotationGroupType::Pm:
+            case EnforcedRotationGroupType::Pmpf: do_fixed(erg, outstep_rot, outstep_slab); break;
+            case EnforcedRotationGroupType::Rm:
+                do_radial_motion(erg, outstep_rot, outstep_slab);
+                break;
+            case EnforcedRotationGroupType::Rmpf:
+                do_radial_motion_pf(erg, coords, box, outstep_rot, outstep_slab);
+                break;
+            case EnforcedRotationGroupType::Rm2:
+            case EnforcedRotationGroupType::Rm2pf:
+                do_radial_motion2(erg, coords, box, outstep_rot, outstep_slab);
+                break;
+            case EnforcedRotationGroupType::Flext:
+            case EnforcedRotationGroupType::Flex2t:
                 /* Subtract the center of the rotation group from the collective positions array
                  * Also store the center in erg->xc_center since it needs to be subtracted
                  * in the low level routines from the local coordinates as well */
                 get_center(erg->xc, erg->mc, rotg->nat, erg->xc_center);
                 svmul(-1.0, erg->xc_center, transvec);
                 translate_x(erg->xc, rotg->nat, transvec);
-                do_flexible(MASTER(cr), er, erg, x, box, t, outstep_rot, outstep_slab);
+                do_flexible(MASTER(cr), er, erg, coords, box, t, outstep_rot, outstep_slab);
                 break;
-            case erotgFLEX:
-            case erotgFLEX2:
+            case EnforcedRotationGroupType::Flex:
+            case EnforcedRotationGroupType::Flex2:
                 /* Do NOT subtract the center of mass in the low level routines! */
                 clear_rvec(erg->xc_center);
-                do_flexible(MASTER(cr), er, erg, x, box, t, outstep_rot, outstep_slab);
+                do_flexible(MASTER(cr), er, erg, coords, box, t, outstep_rot, outstep_slab);
                 break;
             default: gmx_fatal(FARGS, "No such rotation potential.");
         }
index b8af04c51e8f61ed7316058f8ffc30bb164a1b9a..d367317dc755e5330c155c1b5ac0f24046fe726c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #include <memory>
 
 #include "gromacs/math/vectypes.h"
-#include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/classhelpers.h"
 
 struct gmx_domdec_t;
 struct gmx_enfrot;
@@ -72,6 +70,8 @@ namespace gmx
 enum class StartingBehavior;
 class LocalAtomSetManager;
 struct MdrunOptions;
+template<typename>
+class ArrayRef;
 
 class EnforcedRotation
 {
@@ -88,7 +88,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
@@ -120,7 +120,7 @@ std::unique_ptr<gmx::EnforcedRotation> init_rot(FILE*                     fplog,
                                                 const t_commrec*          cr,
                                                 gmx::LocalAtomSetManager* atomSets,
                                                 const t_state*            globalState,
-                                                gmx_mtop_t*               mtop,
+                                                const gmx_mtop_t&         mtop,
                                                 const gmx_output_env_t*   oenv,
                                                 const gmx::MdrunOptions&  mdrunOptions,
                                                 gmx::StartingBehavior     startingBehavior);
@@ -134,13 +134,19 @@ std::unique_ptr<gmx::EnforcedRotation> init_rot(FILE*                     fplog,
  * \param cr      Pointer to MPI communication data.
  * \param er      Pointer to the enforced rotation working data.
  * \param box     Simulation box, needed to make group whole.
- * \param x       The positions of all the local particles.
+ * \param coords  The positions of all the local particles.
  * \param t       Time.
  * \param step    The time step.
  * \param bNS     After domain decomposition / neighbor searching several
  *                local arrays have to be updated (masses, shifts)
  */
-void do_rotation(const t_commrec* cr, gmx_enfrot* er, const matrix box, rvec x[], real t, int64_t step, gmx_bool bNS);
+void do_rotation(const t_commrec*               cr,
+                 gmx_enfrot*                    er,
+                 const matrix                   box,
+                 gmx::ArrayRef<const gmx::RVec> coords,
+                 real                           t,
+                 int64_t                        step,
+                 bool                           bNS);
 
 
 /*! \brief Add the enforced rotation forces to the official force array.
@@ -153,14 +159,14 @@ void do_rotation(const t_commrec* cr, gmx_enfrot* er, const matrix box, rvec x[]
  * the potential, the angle of the group(s), and torques).
  *
  * \param er      Pointer to the enforced rotation working data.
- * \param f       The local forces to which the rotational forces have
+ * \param force   The local forces to which the rotational forces have
  *                to be added.
  * \param cr      Pointer to MPI communication data.
  * \param step    The time step, used for output.
  * \param t       Time, used for output.
  * \returns       The potential energy of the rotation potentials.
  */
-real add_rot_forces(gmx_enfrot* er, rvec f[], const t_commrec* cr, int64_t step, real t);
+real add_rot_forces(gmx_enfrot* er, gmx::ArrayRef<gmx::RVec> force, const t_commrec* cr, int64_t step, real t);
 
 
 #endif
index a1c646c826ead2e847862b71783b96de6ff48b2a..a1257ceb64f39a3886547b889a80083a42eef9b0 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/confio.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/math/vectypes.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
-#include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/mdtypes/state.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/pulling/pull.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/gmxassert.h"
@@ -62,6 +64,9 @@
 
 #include "pull_internal.h"
 
+using gmx::ArrayRef;
+using gmx::RVec;
+
 #if GMX_MPI
 
 // Helper function to deduce MPI datatype from the type of data
@@ -107,19 +112,7 @@ static void pullAllReduce(const t_commrec* cr, pull_comm_t* comm, int n, T* data
         {
             /* Separate branch because gmx_sum uses cr->mpi_comm_mygroup */
 #if GMX_MPI
-#    if MPI_IN_PLACE_EXISTS
             MPI_Allreduce(MPI_IN_PLACE, data, n, mpiDatatype(data), MPI_SUM, comm->mpi_comm_com);
-#    else
-            std::vector<T> buf(n);
-
-            MPI_Allreduce(data, buf.data(), n, mpiDatatype(data), MPI_SUM, comm->mpi_comm_com);
-
-            /* Copy the result from the buffer to the input/output data */
-            for (int i = 0; i < n; i++)
-            {
-                data[i] = buf[i];
-            }
-#    endif
 #else
             gmx_incons("comm->bParticipateAll=FALSE without GMX_MPI");
 #endif
@@ -130,7 +123,7 @@ static void pullAllReduce(const t_commrec* cr, pull_comm_t* comm, int n, T* data
 /* Copies the coordinates of the PBC atom of pgrp to x_pbc.
  * When those coordinates are not available on this rank, clears x_pbc.
  */
-static void setPbcAtomCoords(const pull_group_work_t& pgrp, const rvec* x, rvec x_pbc)
+static void setPbcAtomCoords(const pull_group_work_t& pgrp, ArrayRef<const RVec> x, rvec x_pbc)
 {
     if (pgrp.pbcAtomSet != nullptr)
     {
@@ -151,7 +144,7 @@ static void setPbcAtomCoords(const pull_group_work_t& pgrp, const rvec* x, rvec
     }
 }
 
-static void pull_set_pbcatoms(const t_commrec* cr, struct pull_t* pull, const rvec* x, gmx::ArrayRef<gmx::RVec> x_pbc)
+static void pull_set_pbcatoms(const t_commrec* cr, struct pull_t* pull, ArrayRef<const RVec> x, ArrayRef<RVec> x_pbc)
 {
     int numPbcAtoms = 0;
     for (size_t g = 0; g < pull->group.size(); g++)
@@ -178,8 +171,12 @@ static void pull_set_pbcatoms(const t_commrec* cr, struct pull_t* pull, const rv
     }
 }
 
-static void
-make_cyl_refgrps(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc* pbc, double t, const rvec* x)
+static void make_cyl_refgrps(const t_commrec*     cr,
+                             pull_t*              pull,
+                             ArrayRef<const real> masses,
+                             t_pbc*               pbc,
+                             double               t,
+                             ArrayRef<const RVec> x)
 {
     pull_comm_t* comm = &pull->comm;
 
@@ -189,13 +186,11 @@ make_cyl_refgrps(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc* p
     double inv_cyl_r2 = 1.0 / gmx::square(pull->params.cylinder_r);
 
     /* loop over all groups to make a reference group for each*/
-    for (size_t c = 0; c < pull->coord.size(); c++)
+    int bufferOffset = 0;
+    for (pull_coord_work_t& pcrd : pull->coord)
     {
-        pull_coord_work_t* pcrd;
-        double             sum_a, wmass, wwmass;
-        dvec               radf_fac0, radf_fac1;
-
-        pcrd = &pull->coord[c];
+        double sum_a, wmass, wwmass;
+        dvec   radf_fac0, radf_fac1;
 
         sum_a  = 0;
         wmass  = 0;
@@ -203,14 +198,14 @@ make_cyl_refgrps(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc* p
         clear_dvec(radf_fac0);
         clear_dvec(radf_fac1);
 
-        if (pcrd->params.eGeom == epullgCYL)
+        if (pcrd.params.eGeom == PullGroupGeometry::Cylinder)
         {
             /* pref will be the same group for all pull coordinates */
-            const pull_group_work_t& pref  = pull->group[pcrd->params.group[0]];
-            const pull_group_work_t& pgrp  = pull->group[pcrd->params.group[1]];
-            pull_group_work_t&       pdyna = pull->dyna[c];
+            const pull_group_work_t& pref  = pull->group[pcrd.params.group[0]];
+            const pull_group_work_t& pgrp  = pull->group[pcrd.params.group[1]];
+            pull_group_work_t&       pdyna = *pcrd.dynamicGroup0;
             rvec                     direction;
-            copy_dvec_to_rvec(pcrd->spatialData.vec, direction);
+            copy_dvec_to_rvec(pcrd.spatialData.vec, direction);
 
             /* Since we have not calculated the COM of the cylinder group yet,
              * we calculate distances with respect to location of the pull
@@ -218,15 +213,15 @@ make_cyl_refgrps(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc* p
              * here we already have the COM of the pull group. This resolves
              * any PBC issues and we don't need to use a PBC-atom here.
              */
-            if (pcrd->params.rate != 0)
+            if (pcrd.params.rate != 0)
             {
                 /* With rate=0, value_ref is set initially */
-                pcrd->value_ref = pcrd->params.init + pcrd->params.rate * t;
+                pcrd.value_ref = pcrd.params.init + pcrd.params.rate * t;
             }
             rvec reference;
             for (int m = 0; m < DIM; m++)
             {
-                reference[m] = pgrp.x[m] - pcrd->spatialData.vec[m] * pcrd->value_ref;
+                reference[m] = pgrp.x[m] - pcrd.spatialData.vec[m] * pcrd.value_ref;
             }
 
             auto localAtomIndices = pref.atomSet.localIndex();
@@ -293,8 +288,9 @@ make_cyl_refgrps(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc* p
             }
         }
 
-        auto buffer = gmx::arrayRefFromArray(
-                comm->cylinderBuffer.data() + c * c_cylinderBufferStride, c_cylinderBufferStride);
+        auto buffer = gmx::arrayRefFromArray(comm->cylinderBuffer.data() + bufferOffset,
+                                             c_cylinderBufferStride);
+        bufferOffset += c_cylinderBufferStride;
 
         buffer[0] = wmass;
         buffer[1] = wwmass;
@@ -315,28 +311,26 @@ make_cyl_refgrps(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc* p
         pullAllReduce(cr, comm, pull->coord.size() * c_cylinderBufferStride, comm->cylinderBuffer.data());
     }
 
-    for (size_t c = 0; c < pull->coord.size(); c++)
+    bufferOffset = 0;
+    for (pull_coord_work_t& pcrd : pull->coord)
     {
-        pull_coord_work_t* pcrd;
-
-        pcrd = &pull->coord[c];
-
-        if (pcrd->params.eGeom == epullgCYL)
+        if (pcrd.params.eGeom == PullGroupGeometry::Cylinder)
         {
-            pull_group_work_t*    pdyna       = &pull->dyna[c];
-            pull_group_work_t*    pgrp        = &pull->group[pcrd->params.group[1]];
-            PullCoordSpatialData& spatialData = pcrd->spatialData;
-
-            auto buffer = gmx::constArrayRefFromArray(
-                    comm->cylinderBuffer.data() + c * c_cylinderBufferStride, c_cylinderBufferStride);
-            double wmass   = buffer[0];
-            double wwmass  = buffer[1];
-            pdyna->mwscale = 1.0 / wmass;
+            pull_group_work_t&    dynamicGroup0 = *pcrd.dynamicGroup0;
+            pull_group_work_t&    group1        = pull->group[pcrd.params.group[1]];
+            PullCoordSpatialData& spatialData   = pcrd.spatialData;
+
+            auto buffer = gmx::constArrayRefFromArray(comm->cylinderBuffer.data() + bufferOffset,
+                                                      c_cylinderBufferStride);
+            bufferOffset += c_cylinderBufferStride;
+            double wmass          = buffer[0];
+            double wwmass         = buffer[1];
+            dynamicGroup0.mwscale = 1.0 / wmass;
             /* Cylinder pulling can't be used with constraints, but we set
              * wscale and invtm anyhow, in case someone would like to use them.
              */
-            pdyna->wscale = wmass / wwmass;
-            pdyna->invtm  = wwmass / (wmass * wmass);
+            dynamicGroup0.wscale = wmass / wwmass;
+            dynamicGroup0.invtm  = wwmass / (wmass * wmass);
 
             /* We store the deviation of the COM from the reference location
              * used above, since we need it when we apply the radial forces
@@ -345,9 +339,9 @@ make_cyl_refgrps(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc* p
             spatialData.cyl_dev = 0;
             for (int m = 0; m < DIM; m++)
             {
-                double reference = pgrp->x[m] - spatialData.vec[m] * pcrd->value_ref;
-                double dist      = -spatialData.vec[m] * buffer[2] * pdyna->mwscale;
-                pdyna->x[m]      = reference - dist;
+                double reference   = group1.x[m] - spatialData.vec[m] * pcrd.value_ref;
+                double dist        = -spatialData.vec[m] * buffer[2] * dynamicGroup0.mwscale;
+                dynamicGroup0.x[m] = reference - dist;
                 spatialData.cyl_dev += dist;
             }
             /* Now we know the exact COM of the cylinder reference group,
@@ -362,10 +356,18 @@ make_cyl_refgrps(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc* p
 
             if (debug)
             {
-                fprintf(debug, "Pull cylinder group %zu:%8.3f%8.3f%8.3f m:%8.3f\n", c, pdyna->x[0],
-                        pdyna->x[1], pdyna->x[2], 1.0 / pdyna->invtm);
-                fprintf(debug, "ffrad %8.3f %8.3f %8.3f\n", spatialData.ffrad[XX],
-                        spatialData.ffrad[YY], spatialData.ffrad[ZZ]);
+                fprintf(debug,
+                        "Pull cylinder group %d:%8.3f%8.3f%8.3f m:%8.3f\n",
+                        pcrd.params.coordIndex,
+                        dynamicGroup0.x[0],
+                        dynamicGroup0.x[1],
+                        dynamicGroup0.x[2],
+                        1.0 / dynamicGroup0.invtm);
+                fprintf(debug,
+                        "ffrad %8.3f %8.3f %8.3f\n",
+                        spatialData.ffrad[XX],
+                        spatialData.ffrad[YY],
+                        spatialData.ffrad[ZZ]);
             }
         }
     }
@@ -386,9 +388,9 @@ static double atan2_0_2pi(double y, double x)
 static void sum_com_part(const pull_group_work_t* pgrp,
                          int                      ind_start,
                          int                      ind_end,
-                         const rvec*              x,
-                         const rvec*              xp,
-                         const real*              mass,
+                         ArrayRef<const RVec>     x,
+                         ArrayRef<const RVec>     xp,
+                         ArrayRef<const real>     mass,
                          const t_pbc*             pbc,
                          const rvec               x_pbc,
                          ComSums*                 sum_com)
@@ -424,7 +426,7 @@ static void sum_com_part(const pull_group_work_t* pgrp,
             {
                 sum_wmx[d] += wm * x[ii][d];
             }
-            if (xp)
+            if (!xp.empty())
             {
                 for (int d = 0; d < DIM; d++)
                 {
@@ -442,7 +444,7 @@ static void sum_com_part(const pull_group_work_t* pgrp,
             {
                 sum_wmx[d] += wm * dx[d];
             }
-            if (xp)
+            if (!xp.empty())
             {
                 /* For xp add the difference between xp and x to dx,
                  * such that we use the same periodic image,
@@ -459,7 +461,7 @@ static void sum_com_part(const pull_group_work_t* pgrp,
     sum_com->sum_wm  = sum_wm;
     sum_com->sum_wwm = sum_wwm;
     copy_dvec(sum_wmx, sum_com->sum_wmx);
-    if (xp)
+    if (!xp.empty())
     {
         copy_dvec(sum_wmxp, sum_com->sum_wmxp);
     }
@@ -470,9 +472,9 @@ static void sum_com_part_cosweight(const pull_group_work_t* pgrp,
                                    int                      ind_end,
                                    int                      cosdim,
                                    real                     twopi_box,
-                                   const rvec*              x,
-                                   const rvec*              xp,
-                                   const real*              mass,
+                                   ArrayRef<const RVec>     x,
+                                   ArrayRef<const RVec>     xp,
+                                   ArrayRef<const real>     mass,
                                    ComSums*                 sum_com)
 {
     /* Cosine weighting geometry */
@@ -499,7 +501,7 @@ static void sum_com_part_cosweight(const pull_group_work_t* pgrp,
         sum_csm += static_cast<double>(cw * sw * m);
         sum_ssm += static_cast<double>(sw * sw * m);
 
-        if (xp != nullptr)
+        if (!xp.empty())
         {
             real cw = std::cos(xp[ii][cosdim] * twopi_box);
             real sw = std::sin(xp[ii][cosdim] * twopi_box);
@@ -518,12 +520,13 @@ static void sum_com_part_cosweight(const pull_group_work_t* pgrp,
 }
 
 /* calculates center of mass of selection index from all coordinates x */
-// Compiler segfault with 2019_update_5 and 2020_initial
-#if defined(__INTEL_COMPILER) \
-        && ((__INTEL_COMPILER == 1900 && __INTEL_COMPILER_UPDATE >= 5) || __INTEL_COMPILER >= 1910)
-#    pragma intel optimization_level 2
-#endif
-void pull_calc_coms(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc* pbc, double t, const rvec x[], rvec* xp)
+void pull_calc_coms(const t_commrec*     cr,
+                    pull_t*              pull,
+                    ArrayRef<const real> masses,
+                    t_pbc*               pbc,
+                    double               t,
+                    ArrayRef<const RVec> x,
+                    ArrayRef<RVec>       xp)
 {
     real         twopi_box = 0;
     pull_comm_t* comm;
@@ -613,9 +616,9 @@ void pull_calc_coms(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc
                 if (pgrp->params.ind.size() == 1 && pgrp->atomSet.numAtomsLocal() == 1
                     && masses[pgrp->atomSet.localIndex()[0]] == 0)
                 {
-                    GMX_ASSERT(xp == nullptr,
+                    GMX_ASSERT(xp.empty(),
                                "We should not have groups with zero mass with constraints, i.e. "
-                               "xp!=NULL");
+                               "xp not empty");
 
                     /* Copy the single atom coordinate */
                     for (int d = 0; d < DIM; d++)
@@ -628,22 +631,22 @@ void pull_calc_coms(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc
                 }
                 else if (pgrp->atomSet.numAtomsLocal() <= c_pullMaxNumLocalAtomsSingleThreaded)
                 {
-                    sum_com_part(pgrp, 0, pgrp->atomSet.numAtomsLocal(), x, xp, masses, pbc, x_pbc,
-                                 &comSumsTotal);
+                    sum_com_part(pgrp, 0, pgrp->atomSet.numAtomsLocal(), x, xp, masses, pbc, x_pbc, &comSumsTotal);
                 }
                 else
                 {
-#pragma omp parallel for num_threads(pull->nthreads) schedule(static)
-                    for (int t = 0; t < pull->nthreads; t++)
+                    const int numThreads = pgrp->numThreads();
+#pragma omp parallel for num_threads(numThreads) schedule(static)
+                    for (int t = 0; t < numThreads; t++)
                     {
-                        int ind_start = (pgrp->atomSet.numAtomsLocal() * (t + 0)) / pull->nthreads;
-                        int ind_end   = (pgrp->atomSet.numAtomsLocal() * (t + 1)) / pull->nthreads;
-                        sum_com_part(pgrp, ind_start, ind_end, x, xp, masses, pbc, x_pbc,
-                                     &pull->comSums[t]);
+                        int ind_start = (pgrp->atomSet.numAtomsLocal() * (t + 0)) / numThreads;
+                        int ind_end   = (pgrp->atomSet.numAtomsLocal() * (t + 1)) / numThreads;
+                        sum_com_part(
+                                pgrp, ind_start, ind_end, x, xp, masses, pbc, x_pbc, &pull->comSums[t]);
                     }
 
                     /* Reduce the thread contributions to sum_com[0] */
-                    for (int t = 1; t < pull->nthreads; t++)
+                    for (int t = 1; t < numThreads; t++)
                     {
                         comSumsTotal.sum_wm += pull->comSums[t].sum_wm;
                         comSumsTotal.sum_wwm += pull->comSums[t].sum_wwm;
@@ -672,18 +675,19 @@ void pull_calc_coms(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc
                  * This uses a slab of the system, thus we always have many
                  * atoms in the pull groups. Therefore, always use threads.
                  */
-#pragma omp parallel for num_threads(pull->nthreads) schedule(static)
-                for (int t = 0; t < pull->nthreads; t++)
+                const int numThreads = pgrp->numThreads();
+#pragma omp parallel for num_threads(numThreads) schedule(static)
+                for (int t = 0; t < numThreads; t++)
                 {
-                    int ind_start = (pgrp->atomSet.numAtomsLocal() * (t + 0)) / pull->nthreads;
-                    int ind_end   = (pgrp->atomSet.numAtomsLocal() * (t + 1)) / pull->nthreads;
-                    sum_com_part_cosweight(pgrp, ind_start, ind_end, pull->cosdim, twopi_box, x, xp,
-                                           masses, &pull->comSums[t]);
+                    int ind_start = (pgrp->atomSet.numAtomsLocal() * (t + 0)) / numThreads;
+                    int ind_end   = (pgrp->atomSet.numAtomsLocal() * (t + 1)) / numThreads;
+                    sum_com_part_cosweight(
+                            pgrp, ind_start, ind_end, pull->cosdim, twopi_box, x, xp, masses, &pull->comSums[t]);
                 }
 
                 /* Reduce the thread contributions to comSums[0] */
                 ComSums& comSumsTotal = pull->comSums[0];
-                for (int t = 1; t < pull->nthreads; t++)
+                for (int t = 1; t < numThreads; t++)
                 {
                     comSumsTotal.sum_cm += pull->comSums[t].sum_cm;
                     comSumsTotal.sum_sm += pull->comSums[t].sum_sm;
@@ -714,7 +718,9 @@ void pull_calc_coms(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc
         }
     }
 
-    pullAllReduce(cr, comm, pull->group.size() * c_comBufferStride * DIM,
+    pullAllReduce(cr,
+                  comm,
+                  pull->group.size() * c_comBufferStride * DIM,
                   static_cast<double*>(comm->comBuffer[0]));
 
     for (size_t g = 0; g < pull->group.size(); g++)
@@ -750,14 +756,14 @@ void pull_calc_coms(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc
                 for (m = 0; m < DIM; m++)
                 {
                     pgrp->x[m] = comBuffer[0][m] * pgrp->mwscale;
-                    if (xp)
+                    if (!xp.empty())
                     {
                         pgrp->xp[m] = comBuffer[1][m] * pgrp->mwscale;
                     }
                     if (pgrp->epgrppbc == epgrppbcREFAT || pgrp->epgrppbc == epgrppbcPREVSTEPCOM)
                     {
                         pgrp->x[m] += comm->pbcAtomBuffer[g][m];
-                        if (xp)
+                        if (!xp.empty())
                         {
                             pgrp->xp[m] += comm->pbcAtomBuffer[g][m];
                         }
@@ -791,7 +797,7 @@ void pull_calc_coms(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc
                     pgrp->localWeights[i] = csw * std::cos(twopi_box * x[ii][pull->cosdim])
                                             + snw * std::sin(twopi_box * x[ii][pull->cosdim]);
                 }
-                if (xp)
+                if (!xp.empty())
                 {
                     csw                    = comBuffer[2][0];
                     snw                    = comBuffer[2][1];
@@ -817,9 +823,9 @@ using BoolVec = gmx::BasicVector<bool>;
 /* Returns whether the pull group obeys the PBC restrictions */
 static bool pullGroupObeysPbcRestrictions(const pull_group_work_t& group,
                                           const BoolVec&           dimUsed,
-                                          const rvec*              x,
+                                          ArrayRef<const RVec>     x,
                                           const t_pbc&             pbc,
-                                          const gmx::RVec&         x_pbc,
+                                          const RVec&              x_pbc,
                                           const real               pbcMargin)
 {
     /* Determine which dimensions are relevant for PBC */
@@ -903,7 +909,7 @@ static bool pullGroupObeysPbcRestrictions(const pull_group_work_t& group,
     return true;
 }
 
-int pullCheckPbcWithinGroups(const pull_t& pull, const rvec* x, const t_pbc& pbc, real pbcMargin)
+int pullCheckPbcWithinGroups(const pull_t& pull, ArrayRef<const RVec> x, const t_pbc& pbc, real pbcMargin)
 {
     if (pbc.pbcType == PbcType::No)
     {
@@ -912,14 +918,15 @@ int pullCheckPbcWithinGroups(const pull_t& pull, const rvec* x, const t_pbc& pbc
 
     /* Determine what dimensions are used for each group by pull coordinates */
     std::vector<BoolVec> dimUsed(pull.group.size(), { false, false, false });
-    for (size_t c = 0; c < pull.coord.size(); c++)
+    for (const pull_coord_work_t& pcrd : pull.coord)
     {
-        const t_pull_coord& coordParams = pull.coord[c].params;
+        const t_pull_coord& coordParams = pcrd.params;
         for (int groupIndex = 0; groupIndex < coordParams.ngroup; groupIndex++)
         {
             for (int d = 0; d < DIM; d++)
             {
-                if (coordParams.dim[d] && !(coordParams.eGeom == epullgCYL && groupIndex == 0))
+                if (coordParams.dim[d]
+                    && !(coordParams.eGeom == PullGroupGeometry::Cylinder && groupIndex == 0))
                 {
                     dimUsed[coordParams.group[groupIndex]][d] = true;
                 }
@@ -941,11 +948,7 @@ int pullCheckPbcWithinGroups(const pull_t& pull, const rvec* x, const t_pbc& pbc
     return -1;
 }
 
-bool pullCheckPbcWithinGroup(const pull_t&                  pull,
-                             gmx::ArrayRef<const gmx::RVec> x,
-                             const t_pbc&                   pbc,
-                             int                            groupNr,
-                             real                           pbcMargin)
+bool pullCheckPbcWithinGroup(const pull_t& pull, ArrayRef<const RVec> x, const t_pbc& pbc, int groupNr, real pbcMargin)
 {
     if (pbc.pbcType == PbcType::No)
     {
@@ -962,16 +965,17 @@ bool pullCheckPbcWithinGroup(const pull_t&                  pull,
 
     /* Determine what dimensions are used for each group by pull coordinates */
     BoolVec dimUsed = { false, false, false };
-    for (size_t c = 0; c < pull.coord.size(); c++)
+    for (const pull_coord_work_t& pcrd : pull.coord)
     {
-        const t_pull_coord& coordParams = pull.coord[c].params;
+        const t_pull_coord& coordParams = pcrd.params;
         for (int groupIndex = 0; groupIndex < coordParams.ngroup; groupIndex++)
         {
             if (coordParams.group[groupIndex] == groupNr)
             {
                 for (int d = 0; d < DIM; d++)
                 {
-                    if (coordParams.dim[d] && !(coordParams.eGeom == epullgCYL && groupIndex == 0))
+                    if (coordParams.dim[d]
+                        && !(coordParams.eGeom == PullGroupGeometry::Cylinder && groupIndex == 0))
                     {
                         dimUsed[d] = true;
                     }
@@ -980,8 +984,8 @@ bool pullCheckPbcWithinGroup(const pull_t&                  pull,
         }
     }
 
-    return (pullGroupObeysPbcRestrictions(group, dimUsed, as_rvec_array(x.data()), pbc,
-                                          pull.comm.pbcAtomBuffer[groupNr], pbcMargin));
+    return (pullGroupObeysPbcRestrictions(
+            group, dimUsed, x, pbc, pull.comm.pbcAtomBuffer[groupNr], pbcMargin));
 }
 
 void setPrevStepPullComFromState(struct pull_t* pull, const t_state* state)
@@ -1024,7 +1028,11 @@ void allocStatePrevStepPullCom(t_state* state, const pull_t* pull)
     }
 }
 
-void initPullComFromPrevStep(const t_commrec* cr, pull_t* pull, const real* masses, t_pbc* pbc, const rvec x[])
+void initPullComFromPrevStep(const t_commrec*     cr,
+                             pull_t*              pull,
+                             ArrayRef<const real> masses,
+                             t_pbc*               pbc,
+                             ArrayRef<const RVec> x)
 {
     pull_comm_t* comm   = &pull->comm;
     size_t       ngroup = pull->group.size();
@@ -1053,7 +1061,7 @@ void initPullComFromPrevStep(const t_commrec* cr, pull_t* pull, const real* mass
                        "Groups with no atoms, or only one atom, should not "
                        "use the COM from the previous step as reference.");
 
-            rvec x_pbc = { 0, 0, 0 };
+            RVec x_pbc = { 0, 0, 0 };
             copy_rvec(comm->pbcAtomBuffer[g], x_pbc);
 
             if (debug)
@@ -1073,22 +1081,21 @@ void initPullComFromPrevStep(const t_commrec* cr, pull_t* pull, const real* mass
 
             if (pgrp->atomSet.numAtomsLocal() <= c_pullMaxNumLocalAtomsSingleThreaded)
             {
-                sum_com_part(pgrp, 0, pgrp->atomSet.numAtomsLocal(), x, nullptr, masses, pbc, x_pbc,
-                             &comSumsTotal);
+                sum_com_part(pgrp, 0, pgrp->atomSet.numAtomsLocal(), x, {}, masses, pbc, x_pbc, &comSumsTotal);
             }
             else
             {
-#pragma omp parallel for num_threads(pull->nthreads) schedule(static)
-                for (int t = 0; t < pull->nthreads; t++)
+                const int numThreads = pgrp->numThreads();
+#pragma omp parallel for num_threads(numThreads) schedule(static)
+                for (int t = 0; t < numThreads; t++)
                 {
-                    int ind_start = (pgrp->atomSet.numAtomsLocal() * (t + 0)) / pull->nthreads;
-                    int ind_end   = (pgrp->atomSet.numAtomsLocal() * (t + 1)) / pull->nthreads;
-                    sum_com_part(pgrp, ind_start, ind_end, x, nullptr, masses, pbc, x_pbc,
-                                 &pull->comSums[t]);
+                    int ind_start = (pgrp->atomSet.numAtomsLocal() * (t + 0)) / numThreads;
+                    int ind_end   = (pgrp->atomSet.numAtomsLocal() * (t + 1)) / numThreads;
+                    sum_com_part(pgrp, ind_start, ind_end, x, {}, masses, pbc, x_pbc, &pull->comSums[t]);
                 }
 
                 /* Reduce the thread contributions to sum_com[0] */
-                for (int t = 1; t < pull->nthreads; t++)
+                for (int t = 1; t < numThreads; t++)
                 {
                     comSumsTotal.sum_wm += pull->comSums[t].sum_wm;
                     comSumsTotal.sum_wwm += pull->comSums[t].sum_wwm;
@@ -1147,8 +1154,7 @@ void initPullComFromPrevStep(const t_commrec* cr, pull_t* pull, const real* mass
                 }
                 if (debug)
                 {
-                    fprintf(debug, "Pull group %zu wmass %f invtm %f\n", g, 1.0 / pgrp->mwscale,
-                            pgrp->invtm);
+                    fprintf(debug, "Pull group %zu wmass %f invtm %f\n", g, 1.0 / pgrp->mwscale, pgrp->invtm);
                     fprintf(debug, "Initialising prev step COM of pull group %zu to", g);
                     for (int m = 0; m < DIM; m++)
                     {
diff --git a/src/gromacs/pulling/tests/.clang-tidy b/src/gromacs/pulling/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index fe8e604d6c656ab620a684173b69717b159e7fb8..a0f551f627af172770b8859ec63647d15439c374 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -93,10 +93,11 @@ protected:
         {
             // Distance pulling in all 3 dimensions
             t_pull_coord params;
-            params.eGeom   = epullgDIST;
-            params.dim[XX] = 1;
-            params.dim[YY] = 1;
-            params.dim[ZZ] = 1;
+            params.eGeom      = PullGroupGeometry::Distance;
+            params.dim[XX]    = 1;
+            params.dim[YY]    = 1;
+            params.dim[ZZ]    = 1;
+            params.coordIndex = 0;
             pull_coord_work_t pcrd(params);
             clear_dvec(pcrd.spatialData.vec);
 
@@ -105,44 +106,47 @@ protected:
             {
                 minBoxSize2 = std::min(minBoxSize2, norm2(box[d]));
             }
-            EXPECT_REAL_EQ_TOL(0.25 * minBoxSize2, max_pull_distance2(&pcrd, &pbc),
-                               defaultRealTolerance());
+            EXPECT_REAL_EQ_TOL(
+                    0.25 * minBoxSize2, max_pull_distance2(&pcrd, &pbc), defaultRealTolerance());
         }
 
         {
             // Distance pulling along Z
             t_pull_coord params;
-            params.eGeom   = epullgDIST;
-            params.dim[XX] = 0;
-            params.dim[YY] = 0;
-            params.dim[ZZ] = 1;
+            params.eGeom      = PullGroupGeometry::Distance;
+            params.dim[XX]    = 0;
+            params.dim[YY]    = 0;
+            params.dim[ZZ]    = 1;
+            params.coordIndex = 0;
             pull_coord_work_t pcrd(params);
             clear_dvec(pcrd.spatialData.vec);
-            EXPECT_REAL_EQ_TOL(0.25 * boxSizeZSquared, max_pull_distance2(&pcrd, &pbc),
-                               defaultRealTolerance());
+            EXPECT_REAL_EQ_TOL(
+                    0.25 * boxSizeZSquared, max_pull_distance2(&pcrd, &pbc), defaultRealTolerance());
         }
 
         {
             // Directional pulling along Z
             t_pull_coord params;
-            params.eGeom   = epullgDIR;
-            params.dim[XX] = 1;
-            params.dim[YY] = 1;
-            params.dim[ZZ] = 1;
+            params.eGeom      = PullGroupGeometry::Direction;
+            params.dim[XX]    = 1;
+            params.dim[YY]    = 1;
+            params.dim[ZZ]    = 1;
+            params.coordIndex = 0;
             pull_coord_work_t pcrd(params);
             clear_dvec(pcrd.spatialData.vec);
             pcrd.spatialData.vec[ZZ] = 1;
-            EXPECT_REAL_EQ_TOL(0.25 * boxSizeZSquared, max_pull_distance2(&pcrd, &pbc),
-                               defaultRealTolerance());
+            EXPECT_REAL_EQ_TOL(
+                    0.25 * boxSizeZSquared, max_pull_distance2(&pcrd, &pbc), defaultRealTolerance());
         }
 
         {
             // Directional pulling along X
             t_pull_coord params;
-            params.eGeom   = epullgDIR;
-            params.dim[XX] = 1;
-            params.dim[YY] = 1;
-            params.dim[ZZ] = 1;
+            params.eGeom      = PullGroupGeometry::Direction;
+            params.dim[XX]    = 1;
+            params.dim[YY]    = 1;
+            params.dim[ZZ]    = 1;
+            params.coordIndex = 0;
             pull_coord_work_t pcrd(params);
             clear_dvec(pcrd.spatialData.vec);
             pcrd.spatialData.vec[XX] = 1;
index fbdf2dabdff2caeec346a280359dd4556c3eb505..9605699e3a5b3451e3fd4bf385b18bf8d940bbfc 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2015,2016,2019, by the GROMACS development team, led by
+# Copyright (c) 2015,2016,2019,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(random INTERFACE)
 file(GLOB RANDOM_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${RANDOM_SOURCES} PARENT_SCOPE)
 
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(random PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(random PUBLIC
+target_include_directories(random INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(random PUBLIC
+target_link_libraries(random INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when random is an OBJECT target
+#target_link_libraries(random PUBLIC legacy_api)
+#target_link_libraries(random PRIVATE common)
+
+# Module dependencies
+# random interfaces convey transitive dependence on these modules.
+#target_link_libraries(random PUBLIC
+target_link_libraries(random INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(random PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(random PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index 7df6fa1d348d27247af9d5b526bff573fc509484..a038f1f09e9fcdfe7436389950019cc64828efdc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +52,7 @@
 #include <cmath>
 
 #include <limits>
+#include <memory>
 
 #include "gromacs/random/uniformrealdistribution.h"
 #include "gromacs/utility/classhelpers.h"
@@ -134,7 +135,6 @@ public:
         bool operator!=(const param_type& x) const { return !operator==(x); }
     };
 
-public:
     /*! \brief Construct new distribution with given floating-point parameter.
      *
      * \param lambda   lambda/decay parameter
index 24e7fd3b095d295f7a1db5c87c6d23647ca32480..0b23b04c7949505e1bff14c8df7d30a2c68a30b7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +55,7 @@
 #include <cmath>
 
 #include <limits>
+#include <memory>
 
 #include "gromacs/random/exponentialdistribution.h"
 #include "gromacs/random/uniformrealdistribution.h"
@@ -92,7 +93,7 @@ namespace gmx
 /*! \brief Gamma distribution
  *
  *  The C++ standard library does provide a gamma distribution, but when
- *  using libstdc++-4.4.7 with at least gcc-4.6 or icc-14.0 the headers
+ *  using libstdc++-4.4.7 with at least gcc-4.6 the headers
  *  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
@@ -166,7 +167,6 @@ public:
         bool operator!=(const param_type& x) const { return !operator==(x); }
     };
 
-public:
     /*! \brief Construct new distribution with given floating-point parameters.
      *
      * \param alpha  First parameter of gamma distribution
index 5242e97d1cad14ae813c0021fb5d9514f36aad3c..4380758705f52d7f9d2fd7e0bdb890efc11d9a02 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -51,6 +51,7 @@
 #include <cmath>
 
 #include <limits>
+#include <memory>
 
 #include "gromacs/random/uniformrealdistribution.h"
 #include "gromacs/utility/classhelpers.h"
@@ -151,7 +152,6 @@ public:
         bool operator!=(const param_type& x) const { return !operator==(x); }
     };
 
-public:
     /*! \brief Construct new distribution with given floating-point parameters.
      *
      * \param mean     Mean of normal distribution
index 29b16faffd68d9ea64c2f8aba34017930485dfa8..1664c286ca5eb161f736de03a692cff0d444b5e4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 @@
 
 #include <array>
 #include <limits>
+#include <memory>
 
 #include "gromacs/math/functions.h"
 #include "gromacs/math/utilities.h"
@@ -212,7 +213,6 @@ public:
         return table;
     }
 
-public:
     /*! \brief Construct new normal distribution with specified mean & stdddev.
      *
      *  \param mean    Mean value of tabulated normal distribution
diff --git a/src/gromacs/random/tests/.clang-tidy b/src/gromacs/random/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index a31e6ead193dac9b32ffc6ee3139e5e8e708fca4..acf09b7ceb4b8bfe4f0eee34b7b67bd2e6041e69 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +123,9 @@ const std::vector<uint64_t> bitsZero{ { 0, 0, 0, 0 } };
  *  The 2x64 flavors of ThreeFry64 will use the first four values, while
  *  the 4x64 version uses all eight.
  */
-const std::vector<uint64_t> bitsOne{ { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL,
-                                       0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL } };
+const std::vector<uint64_t> bitsOne{
+    { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL }
+};
 
 /*! \brief Constant array of integers with bitpattern from Pi.
  *
@@ -132,8 +133,9 @@ const std::vector<uint64_t> bitsOne{ { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFF
  *  The 2x64 flavors of ThreeFry64 will use the first four values, while
  *  the 4x64 version uses all eight.
  */
-const std::vector<uint64_t> bitsPi{ { 0x243f6a8885a308d3ULL, 0x13198a2e03707344ULL,
-                                      0xa4093822299f31d0ULL, 0x082efa98ec4e6c89ULL } };
+const std::vector<uint64_t> bitsPi{
+    { 0x243f6a8885a308d3ULL, 0x13198a2e03707344ULL, 0xa4093822299f31d0ULL, 0x082efa98ec4e6c89ULL }
+};
 
 // Test the known ansers for the ThreeFry random function when the argument
 // is (1) all zero, (2) all ones, (3) the bits of pi, for a bunch of different flavors of ThreeFry.
index 4946a3092e8f8ab618e1cb96ecffac4b7cced6d7..9ff38a7aa2c552d1af676ed65d417baf7c89ccff 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <array>
 #include <limits>
+#include <memory>
 
 #include "gromacs/math/functions.h"
 #include "gromacs/random/seed.h"
index bde17a2daeb74a1fd6066fa587c0fa73d8c464cf..2e2b4835ea715ffdd8071c3cae28fdbf202ace52 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #define GMX_RANDOM_UNIFORMINTDISTRIBUTION_H
 
 #include <limits>
+#include <memory>
 
 #include "gromacs/math/functions.h"
 #include "gromacs/utility/basedefinitions.h"
@@ -121,7 +122,6 @@ public:
         bool operator!=(const param_type& x) const { return !operator==(x); }
     };
 
-public:
     /*! \brief Construct new distribution with given integer parameters.
      *
      * \param a   Lower end of range (inclusive)
index 17a1e9240fd383c2990466a91d134fbabd65cfde..f54fb43d222868e964d006afcfe974f49c26f05f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <limits>
+#include <memory>
 #include <type_traits>
 
 #include "gromacs/math/functions.h"
+
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/gmxassert.h"
@@ -209,7 +211,6 @@ public:
         bool operator!=(const param_type& x) const { return !operator==(x); }
     };
 
-public:
     /*! \brief Construct new distribution with given floating-point parameters.
      *
      * \param a   Lower end of range (inclusive)
index 06a082e57fdd4005f2d62ec91472474fc2bd5405..d2d52f521dc9e27e39edc77c0e0440e374030024 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+# Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(restraint INTERFACE)
+file(GLOB RESTRAINT_SOURCES *.cpp)
+set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${RESTRAINT_SOURCES} PARENT_SCOPE)
 
-gmx_add_libgromacs_sources(
-    manager.cpp
-    restraintmdmodule.cpp
-    )
-# TODO this is a hacky way to expose things for the API and needs to be changed to something proper
-install(FILES restraintpotential.h DESTINATION include/gromacs/restraint)
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(restraint PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(restraint PUBLIC
+target_include_directories(restraint INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(restraint PUBLIC
+target_link_libraries(restraint INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when restraint is an OBJECT target
+#target_link_libraries(restraint PUBLIC legacy_api)
+#target_link_libraries(restraint PRIVATE common)
+
+# Module dependencies
+# restraint interfaces convey transitive dependence on these modules.
+#target_link_libraries(restraint PUBLIC
+target_link_libraries(restraint INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(restraint PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(restraint PRIVATE legacy_modules)
 
 if (BUILD_TESTING)
     add_subdirectory(tests)
index ad73da367e36d66fe88fccea1b9829b9abbbc90d..96a4a16f7a026d7205f35fe7faa27b4085e7499a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,12 @@ public:
 
 private:
     //! Regulate initialization of the shared resource when (re)initialized.
+    // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
     static std::mutex initializationMutex_;
 };
 
 // Initialize static members
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 std::mutex RestraintManager::Impl::initializationMutex_{};
 
 
index b1dcb03d09c0f3eef63b75d5b6e2062fc581d262..bc4233cba39a8a5ece58c8a455e28b38ebb1e819 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -68,8 +68,8 @@ void RestraintForceProvider::calculateForces(const ForceProviderInput& forceProv
 {
     GMX_ASSERT(restraint_, "Restraint must be initialized.");
 
-    const auto& mdatoms = forceProviderInput.mdatoms_;
-    GMX_ASSERT(mdatoms.homenr >= 0, "number of home atoms must be non-negative.");
+    const int homenr = forceProviderInput.homenr_;
+    GMX_ASSERT(homenr >= 0, "number of home atoms must be non-negative.");
 
     const auto& box = forceProviderInput.box_;
     GMX_ASSERT(check_box(PbcType::Unset, box) == nullptr, "Invalid box.");
@@ -80,7 +80,7 @@ void RestraintForceProvider::calculateForces(const ForceProviderInput& forceProv
     const auto& cr = forceProviderInput.cr_;
     const auto& t  = forceProviderInput.t_;
     // Cooperatively get Cartesian coordinates for center of mass of each site
-    RVec r1 = sites_[0].centerOfMass(cr, static_cast<size_t>(mdatoms.homenr), x, t);
+    RVec r1 = sites_[0].centerOfMass(cr, static_cast<size_t>(homenr), x, t);
     // r2 is to be constructed as
     // r2 = (site[N] - site[N-1]) + (site_{N-1} - site_{N-2}) + ... + (site_2 - site_1) + site_1
     // where the minimum image convention is applied to each path but not to the overall sum.
@@ -96,8 +96,8 @@ void RestraintForceProvider::calculateForces(const ForceProviderInput& forceProv
     // a big molecule in a small box.
     for (size_t i = 0; i < sites_.size() - 1; ++i)
     {
-        RVec a = sites_[i].centerOfMass(cr, static_cast<size_t>(mdatoms.homenr), x, t);
-        RVec b = sites_[i + 1].centerOfMass(cr, static_cast<size_t>(mdatoms.homenr), x, t);
+        RVec a = sites_[i].centerOfMass(cr, static_cast<size_t>(homenr), x, t);
+        RVec b = sites_[i + 1].centerOfMass(cr, static_cast<size_t>(homenr), x, t);
         // dr = minimum_image_vector(b - a)
         pbc_dx(&pbc, b, a, dr);
         r2[0] += dr[0];
@@ -130,7 +130,7 @@ void RestraintForceProvider::calculateForces(const ForceProviderInput& forceProv
     const int  site1  = static_cast<int>(sites_.front().index());
     const int* aLocal = &site1;
     // Set forces using index `site1` if no domain decomposition, otherwise set with local index if available.
-    auto& force = forceProviderOutput->forceWithVirial_.force_;
+    const auto& force = forceProviderOutput->forceWithVirial_.force_;
     if ((cr.dd == nullptr) || (aLocal = cr.dd->ga2la->findHome(site1)))
     {
         force[static_cast<size_t>(*aLocal)] += result.force;
@@ -194,9 +194,11 @@ std::unique_ptr<RestraintMDModule> RestraintMDModule::create(std::shared_ptr<IRe
     return newModule;
 }
 
-void RestraintMDModule::subscribeToSimulationSetupNotifications(MdModulesNotifier* /*notifier*/) {}
+void RestraintMDModule::subscribeToSimulationSetupNotifications(MDModulesNotifiers* /*notifiers*/)
+{
+}
 
-void RestraintMDModule::subscribeToPreProcessingNotifications(MdModulesNotifier* /*notifier*/) {}
+void RestraintMDModule::subscribeToPreProcessingNotifications(MDModulesNotifiers* /*notifiers*/) {}
 
 // private constructor to implement static create() method.
 RestraintMDModule::RestraintMDModule(std::unique_ptr<RestraintMDModuleImpl> restraint) :
index 9825a1b80390b9f446313a9259fc136af3a57b22..57fd28d282675896aedfbe6b3dca230f17f09931 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +53,7 @@ namespace gmx
 
 // Forward declaration to allow opaque pointer to library internal class.
 class RestraintMDModuleImpl;
-struct MdModulesNotifier;
+struct MDModulesNotifiers;
 
 /*! \libinternal \ingroup module_restraint
  * \brief MDModule wrapper for Restraint implementations.
@@ -115,9 +115,9 @@ public:
     void initForceProviders(ForceProviders* forceProviders) override;
 
     //! Subscribe to simulation setup notifications
-    void subscribeToSimulationSetupNotifications(MdModulesNotifier* notifier) override;
+    void subscribeToSimulationSetupNotifications(MDModulesNotifiers* notifiers) override;
     //! Subscribe to pre processing notifications
-    void subscribeToPreProcessingNotifications(MdModulesNotifier* notifier) override;
+    void subscribeToPreProcessingNotifications(MDModulesNotifiers* notifiers) override;
 
 private:
     /*!
index 328d0ba6bc4135c49c5a8923b5b146ce91ad32b2..8cfab33f45706d09565f230dfa1a59ffc367b4c4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -135,9 +135,9 @@ public:
         if (DOMAINDECOMP(&cr)) // Domain decomposition
         {
             // Get global-to-local indexing structure
-            auto crossRef = cr.dd->ga2la;
+            auto* crossRef = cr.dd->ga2la;
             GMX_ASSERT(crossRef, "Domain decomposition must provide global/local cross-reference.");
-            if (const auto localIndex = crossRef->findHome(index_))
+            if (const auto* localIndex = crossRef->findHome(index_))
             {
                 GMX_ASSERT(localIndex,
                            "Expect not to reach this point if findHome does not find index_.");
diff --git a/src/gromacs/restraint/tests/.clang-tidy b/src/gromacs/restraint/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
diff --git a/src/gromacs/selection/.clang-tidy b/src/gromacs/selection/.clang-tidy
new file mode 100644 (file)
index 0000000..beb02dc
--- /dev/null
@@ -0,0 +1,90 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -bugprone-reserved-identifier
+# Quite a large number of functions use the _FName style for naming
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# The selection code has a large amount of static or exported non-const
+# variables that are out of scope for quick rework
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion, -bugprone-reserved-identifier,
+         -cppcoreguidelines-avoid-non-const-global-variables
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index e621fa58813b9033bb42c1d709a304e2ffe9c414..90a4648243030c4190e635b1422682cb9e9aeb04 100644 (file)
@@ -33,6 +33,9 @@
 # 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 up the module library
+add_library(selection INTERFACE)
+
 file(GLOB SELECTION_SOURCES *.cpp)
 file(GLOB SCANNER_SOURCES scanner.cpp parser.cpp)
 list(REMOVE_ITEM SELECTION_SOURCES ${SCANNER_SOURCES})
@@ -56,9 +59,43 @@ else()
     gmx_target_warning_suppression(scanner -Wno-missing-declarations HAS_NO_MISSING_DECLARATIONS)
     gmx_target_warning_suppression(scanner -Wno-null-conversion HAS_NO_NULL_CONVERSIONS)
 endif()
+target_link_libraries(scanner PRIVATE legacy_api)
+# TODO: Use explicit module dependencies.
+target_link_libraries(scanner PRIVATE legacy_modules)
+
 list(APPEND libgromacs_object_library_dependencies scanner)
 set(libgromacs_object_library_dependencies ${libgromacs_object_library_dependencies} PARENT_SCOPE)
 
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(selection PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(selection PUBLIC
+target_include_directories(selection INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(selection PUBLIC
+target_link_libraries(selection INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when selection is an OBJECT target
+#target_link_libraries(selection PUBLIC legacy_api)
+#target_link_libraries(selection PRIVATE common)
+
+# Module dependencies
+# selection interfaces convey transitive dependence on these modules.
+#target_link_libraries(selection PUBLIC
+target_link_libraries(selection INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(selection PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(selection PRIVATE legacy_modules)
+
 if(GMX_INSTALL_LEGACY_API)
     install(FILES
            indexutil.h
index 356482ccd1a0163c7f1aa2fad097d45ec3b23686..f76ecbd6e0c5e1b045c23cdf845f16b13a32a66c 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2009-2018, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -86,7 +86,7 @@ void gmx_calc_com(const gmx_mtop_t* top, rvec x[], int nrefat, const int index[]
     for (int m = 0; m < nrefat; ++m)
     {
         const int  ai   = index[m];
-        const real mass = mtopGetAtomMass(top, ai, &molb);
+        const real mass = mtopGetAtomMass(*top, ai, &molb);
         for (int j = 0; j < DIM; ++j)
         {
             xout[j] += mass * x[ai][j];
@@ -113,7 +113,7 @@ void gmx_calc_cog_f(const gmx_mtop_t* top, rvec f[], int nrefat, const int index
     for (int m = 0; m < nrefat; ++m)
     {
         const int  ai   = index[m];
-        const real mass = mtopGetAtomMass(top, ai, &molb);
+        const real mass = mtopGetAtomMass(*top, ai, &molb);
         for (int j = 0; j < DIM; ++j)
         {
             fout[j] += f[ai][j] / mass;
@@ -257,7 +257,7 @@ void gmx_calc_com_pbc(const gmx_mtop_t* top, rvec x[], const t_pbc* pbc, int nre
     for (int m = 0; m < nrefat; ++m)
     {
         const int  ai   = index[m];
-        const real mass = mtopGetAtomMass(top, ai, &molb);
+        const real mass = mtopGetAtomMass(*top, ai, &molb);
         for (int j = 0; j < DIM; ++j)
         {
             xout[j] += mass * x[ai][j];
@@ -278,7 +278,7 @@ void gmx_calc_com_pbc(const gmx_mtop_t* top, rvec x[], const t_pbc* pbc, int nre
             {
                 rvec       dx, xtest;
                 const int  ai   = index[m];
-                const real mass = mtopGetAtomMass(top, ai, &molb) / mtot;
+                const real mass = mtopGetAtomMass(*top, ai, &molb) / mtot;
                 pbc_dx(pbc, x[ai], xout, dx);
                 rvec_add(xout, dx, xtest);
                 for (int j = 0; j < DIM; ++j)
@@ -363,7 +363,7 @@ void gmx_calc_com_block(const gmx_mtop_t* top, rvec x[], const t_block* block, c
         for (int i = block->index[b]; i < block->index[b + 1]; ++i)
         {
             const int  ai   = index[i];
-            const real mass = mtopGetAtomMass(top, ai, &molb);
+            const real mass = mtopGetAtomMass(*top, ai, &molb);
             for (int d = 0; d < DIM; ++d)
             {
                 xb[d] += mass * x[ai][d];
@@ -394,7 +394,7 @@ void gmx_calc_cog_f_block(const gmx_mtop_t* top, rvec f[], const t_block* block,
         for (int i = block->index[b]; i < block->index[b + 1]; ++i)
         {
             const int  ai   = index[i];
-            const real mass = mtopGetAtomMass(top, ai, &molb);
+            const real mass = mtopGetAtomMass(*top, ai, &molb);
             for (int d = 0; d < DIM; ++d)
             {
                 fb[d] += f[ai][d] / mass;
index 52a26628d936f2b75bb2a1fd77c2674c7708e4a7..154a1a12d0f130f3f3e1a854b92a3d8629e51354 100644 (file)
@@ -1782,8 +1782,8 @@ static void init_method(const SelectionTreeElementPointer& sel, const gmx_mtop_t
     if (sel->u.expr.method->init && (bAtomVal || !(sel->flags & SEL_METHODINIT)))
     {
         sel->flags |= SEL_METHODINIT;
-        sel->u.expr.method->init(top, sel->u.expr.method->nparams, sel->u.expr.method->param,
-                                 sel->u.expr.mdata);
+        sel->u.expr.method->init(
+                top, sel->u.expr.method->nparams, sel->u.expr.method->param, sel->u.expr.mdata);
     }
     if (bAtomVal || !(sel->flags & SEL_OUTINIT))
     {
@@ -2614,8 +2614,8 @@ void compileSelection(SelectionCollection* coll)
     for (i = 0; i < sc->sel.size(); ++i)
     {
         gmx::internal::SelectionData& sel = *sc->sel[i];
-        init_pos_keyword_defaults(&sel.rootElement(), coll->impl_->spost_.c_str(),
-                                  coll->impl_->rpost_.c_str(), &sel);
+        init_pos_keyword_defaults(
+                &sel.rootElement(), coll->impl_->spost_.c_str(), coll->impl_->rpost_.c_str(), &sel);
     }
 
     /* Remove any unused variables. */
index fd2be1443437a43bf7c4dee377c195985ed0b1c8..23781cee8cfc0177dc1e85f98eefd9603273f17f 100644 (file)
@@ -953,8 +953,7 @@ void _gmx_sel_evaluate_method(gmx_sel_evaluate_t*                     data,
                     expandValueForPositions(sel->v.u.r, &sel->v.nr, sel->u.expr.pos);
                     break;
                 default:
-                    GMX_RELEASE_ASSERT(false,
-                                       "Unimplemented value type for position update method");
+                    GMX_RELEASE_ASSERT(false, "Unimplemented value type for position update method");
             }
         }
     }
index 5a6a4507bc3845ce3d261a1d3933d56d8f3eb94c..af168f624213487debb70d978916042bdd72da92 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2009,2010,2011,2012,2013 by the GROMACS development team.
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +77,9 @@ IndexGroupsAndNames::IndexGroupsAndNames(const t_blocka& indexGroup, ArrayRef<ch
 
 bool IndexGroupsAndNames::containsGroupName(const std::string& groupName) const
 {
-    return std::any_of(
-            std::begin(groupNames_), std::end(groupNames_),
-            [&groupName](const std::string& name) { return equalCaseInsensitive(groupName, name); });
+    return std::any_of(std::begin(groupNames_), std::end(groupNames_), [&groupName](const std::string& name) {
+        return equalCaseInsensitive(groupName, name);
+    });
 }
 
 std::vector<index> IndexGroupsAndNames::indices(const std::string& groupName) const
@@ -96,14 +96,17 @@ std::vector<index> IndexGroupsAndNames::indices(const std::string& groupName) co
                           "of grompp."));
     }
     const auto groupNamePosition = std::find_if(
-            std::begin(groupNames_), std::end(groupNames_),
-            [&groupName](const std::string& name) { return equalCaseInsensitive(groupName, name); });
+            std::begin(groupNames_), std::end(groupNames_), [&groupName](const std::string& name) {
+                return equalCaseInsensitive(groupName, name);
+            });
     const auto groupIndex = std::distance(std::begin(groupNames_), groupNamePosition);
     const auto groupSize  = indexGroup_.index[groupIndex + 1] - indexGroup_.index[groupIndex];
     std::vector<index> groupIndices(groupSize);
     const auto         startingIndex = indexGroup_.index[groupIndex];
     std::iota(std::begin(groupIndices), std::end(groupIndices), startingIndex);
-    std::transform(std::begin(groupIndices), std::end(groupIndices), std::begin(groupIndices),
+    std::transform(std::begin(groupIndices),
+                   std::end(groupIndices),
+                   std::begin(groupIndices),
                    [blockLookup = indexGroup_.a](auto i) { return blockLookup[i]; });
     return groupIndices;
 }
@@ -162,7 +165,7 @@ void gmx_ana_indexgrps_init(gmx_ana_indexgrps_t** g, gmx_mtop_t* top, const char
     {
         block = new_blocka();
         // TODO: Propagate mtop further.
-        t_atoms atoms = gmx_mtop_global_atoms(top);
+        t_atoms atoms = gmx_mtop_global_atoms(*top);
         analyse(&atoms, block, &names, FALSE, FALSE);
         done_atom(&atoms);
     }
@@ -767,14 +770,14 @@ static bool next_group_index(int atomIndex, const gmx_mtop_t* top, e_index_t typ
         case INDEX_RES:
         {
             int resind, molb = 0;
-            mtopGetAtomAndResidueName(top, atomIndex, &molb, nullptr, nullptr, nullptr, &resind);
+            mtopGetAtomAndResidueName(*top, atomIndex, &molb, nullptr, nullptr, nullptr, &resind);
             *id = resind;
             break;
         }
         case INDEX_MOL:
         {
             int molb = 0;
-            *id      = mtopGetMoleculeIndex(top, atomIndex, &molb);
+            *id      = mtopGetMoleculeIndex(*top, atomIndex, &molb);
             break;
         }
         case INDEX_UNKNOWN:
@@ -885,7 +888,7 @@ void gmx_ana_index_make_block(t_blocka* t, const gmx_mtop_t* top, gmx_ana_index_
                     case INDEX_RES:
                     {
                         int molnr, atnr_mol;
-                        mtopGetMolblockIndex(top, ai, &molb, &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;
                         const int      currentResid = mol_atoms.atom[atnr_mol].resind;
@@ -912,7 +915,7 @@ void gmx_ana_index_make_block(t_blocka* t, const gmx_mtop_t* top, gmx_ana_index_
                     case INDEX_MOL:
                     {
                         int molnr, atnr_mol;
-                        mtopGetMolblockIndex(top, ai, &molb, &molnr, &atnr_mol);
+                        mtopGetMolblockIndex(*top, ai, &molb, &molnr, &atnr_mol);
                         const MoleculeBlockIndices& blockIndices = top->moleculeBlockIndices[molb];
                         const int                   atomStart    = blockIndices.globalAtomStart
                                               + (id - blockIndices.moleculeIndexStart)
@@ -1035,9 +1038,9 @@ bool gmx_ana_index_has_full_ablocks(gmx_ana_index_t* g, t_blocka* b)
  * \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)
+static bool is_at_residue_boundary(const gmx_mtop_t& top, int a, int* molb)
 {
-    if (a == -1 || a + 1 == top->natoms)
+    if (a == -1 || a + 1 == top.natoms)
     {
         return true;
     }
@@ -1086,11 +1089,11 @@ bool gmx_ana_index_has_complete_elems(gmx_ana_index_t* g, e_index_t type, const
                 // Check if a is consecutive or on a residue boundary
                 if (a != aPrev + 1)
                 {
-                    if (!is_at_residue_boundary(top, aPrev, &molb))
+                    if (!is_at_residue_boundary(*top, aPrev, &molb))
                     {
                         return false;
                     }
-                    if (!is_at_residue_boundary(top, a - 1, &molb))
+                    if (!is_at_residue_boundary(*top, a - 1, &molb))
                     {
                         return false;
                     }
@@ -1099,7 +1102,7 @@ bool gmx_ana_index_has_complete_elems(gmx_ana_index_t* g, e_index_t type, const
             }
             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))
+            if (!is_at_residue_boundary(*top, a, &molb))
             {
                 return false;
             }
index 96443c208da233a26f60c0cc009cad3e5f18fb74..693b4e020e0a9cbeddb815f653b34f1f52fef30b 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2009,2010,2011,2012,2013 by the GROMACS development team.
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstring>
 
 #include <algorithm>
+#include <mutex>
 #include <vector>
 
 #include "gromacs/math/functions.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/listoflists.h"
-#include "gromacs/utility/mutex.h"
 #include "gromacs/utility/stringutil.h"
 
 #include "position.h"
@@ -320,7 +321,7 @@ private:
     //! Data structure to hold the grid cell contents.
     CellList cells_;
 
-    Mutex          createPairSearchMutex_;
+    std::mutex     createPairSearchMutex_;
     PairSearchList pairSearchList_;
 
     friend class AnalysisNeighborhoodPairSearchImpl;
@@ -451,7 +452,7 @@ AnalysisNeighborhoodSearchImpl::~AnalysisNeighborhoodSearchImpl()
 
 AnalysisNeighborhoodSearchImpl::PairSearchImplPointer AnalysisNeighborhoodSearchImpl::getPairSearch()
 {
-    lock_guard<Mutex> lock(createPairSearchMutex_);
+    std::lock_guard<std::mutex> lock(createPairSearchMutex_);
     // TODO: Consider whether this needs to/can be faster, e.g., by keeping a
     // separate pool of unused search objects.
     PairSearchList::const_iterator i;
@@ -906,8 +907,8 @@ void AnalysisNeighborhoodSearchImpl::init(AnalysisNeighborhood::SearchMode     m
     }
     else if (bTryGrid_)
     {
-        bGrid_ = initGrid(pbc_, positions.count_, positions.x_,
-                          mode == AnalysisNeighborhood::eSearchMode_Grid);
+        bGrid_ = initGrid(
+                pbc_, positions.count_, positions.x_, mode == AnalysisNeighborhood::eSearchMode_Grid);
     }
     refIndices_ = positions.indices_;
     if (bGrid_)
@@ -1254,7 +1255,7 @@ public:
 
     SearchImplPointer getSearch();
 
-    Mutex                   createSearchMutex_;
+    std::mutex              createSearchMutex_;
     SearchList              searchList_;
     real                    cutoff_;
     const ListOfLists<int>* excls_;
@@ -1264,7 +1265,7 @@ public:
 
 AnalysisNeighborhood::Impl::SearchImplPointer AnalysisNeighborhood::Impl::getSearch()
 {
-    lock_guard<Mutex> lock(createSearchMutex_);
+    std::lock_guard<std::mutex> lock(createSearchMutex_);
     // TODO: Consider whether this needs to/can be faster, e.g., by keeping a
     // separate pool of unused search objects.
     SearchList::const_iterator i;
index 7066cafd12d14bedad6061bdf7e26e821a58c8ff..5a445784b71989d70def7fee9ecec63368473cd4 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2009-2018, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +55,7 @@
 #include "gromacs/math/vec.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/real.h"
 
@@ -317,7 +317,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \brief
index 9c44d422da13e859f4f3734391206cf19e47fdeb..c6b42e81b5d0a8991a34ece1ed02776ee1568109 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2009,2010,2011,2012,2013 by the GROMACS development team.
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
 #include <string>
 
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/exceptions.h"
@@ -149,8 +150,8 @@ static void convert_value(SelectionParserValue* value, e_selvalue_t type, Except
         /* Integers to floating point are easy */
         if (value->type == INT_VALUE && type == REAL_VALUE)
         {
-            *value = SelectionParserValue::createRealRange(value->u.i.i1, value->u.i.i2,
-                                                           value->location());
+            *value = SelectionParserValue::createRealRange(
+                    value->u.i.i1, value->u.i.i2, value->location());
             return;
         }
         /* Reals that are integer-valued can also be converted */
@@ -327,7 +328,7 @@ static void parse_values_range(const SelectionParserValueList& values, gmx_ana_s
     /* Sort the ranges and merge consequent ones */
     if (param->val.type == INT_VALUE)
     {
-        const auto range_data = reinterpret_cast<std::array<int, 2>*>(idata);
+        auto* range_data = reinterpret_cast<std::array<int, 2>*>(idata);
         sort(range_data, range_data + n, cmp_range<int>);
         for (i = j = 2; i < 2 * n; i += 2)
         {
@@ -348,7 +349,7 @@ static void parse_values_range(const SelectionParserValueList& values, gmx_ana_s
     }
     else
     {
-        const auto range_data = reinterpret_cast<std::array<real, 2>*>(rdata);
+        auto* range_data = reinterpret_cast<std::array<real, 2>*>(rdata);
         sort(range_data, range_data + n, cmp_range<real>);
         for (i = j = 2; i < 2 * n; i += 2)
         {
@@ -532,8 +533,7 @@ static void parse_values_varnum(const SelectionParserValueList&    values,
                 GMX_RELEASE_ASSERT(false, "Variable-count value type not implemented");
         }
     }
-    GMX_RELEASE_ASSERT(i == valueCount,
-                       "Inconsistent value count wrt. the actual value population");
+    GMX_RELEASE_ASSERT(i == valueCount, "Inconsistent value count wrt. the actual value population");
     if (param->nvalptr)
     {
         *param->nvalptr = param->val.nr;
index d7e536358e8a8d8225215d90d8b38fb2fa002973..9f78139847f1668f1f16900a4e4e6a23a9aa1543 100644 (file)
@@ -706,8 +706,8 @@ static SelectionTreeElementPointer init_keyword_internal(gmx_ana_selmethod_t*
         SelectionParserParameterList params;
         params.push_back(SelectionParserParameter::createFromExpression(nullptr, child));
         params.push_back(SelectionParserParameter::create(nullptr, std::move(args), location));
-        _gmx_sel_parse_params(params, root->u.expr.method->nparams, root->u.expr.method->param,
-                              root, scanner);
+        _gmx_sel_parse_params(
+                params, root->u.expr.method->nparams, root->u.expr.method->param, root, scanner);
     }
     set_refpos_type(&sc->pcc, child, rpost);
 
@@ -847,8 +847,8 @@ SelectionTreeElementPointer _gmx_sel_init_modifier(gmx_ana_selmethod_t*
         root = modifier;
     }
     /* Process the parameters */
-    _gmx_sel_parse_params(*params, modifier->u.expr.method->nparams, modifier->u.expr.method->param,
-                          modifier, scanner);
+    _gmx_sel_parse_params(
+            *params, modifier->u.expr.method->nparams, modifier->u.expr.method->param, modifier, scanner);
 
     return root;
 }
index 38b8bb67ea73cf0132c5a972db564988fb8662c7..4e5995608413ece25eb925fa789892efdfc4e8cc 100644 (file)
@@ -1341,17 +1341,17 @@ void gmx_ana_poscalc_update(gmx_ana_poscalc_t* pc,
                 break;
             default:
                 // TODO: It would probably be better to do this without the type casts.
-                gmx_calc_comg_block(top, fr->x, reinterpret_cast<t_block*>(&pc->b), index.data(),
-                                    bMass, p->x);
+                gmx_calc_comg_block(
+                        top, fr->x, reinterpret_cast<t_block*>(&pc->b), index.data(), bMass, p->x);
                 if (p->v && fr->bV)
                 {
-                    gmx_calc_comg_block(top, fr->v, reinterpret_cast<t_block*>(&pc->b),
-                                        index.data(), bMass, p->v);
+                    gmx_calc_comg_block(
+                            top, fr->v, reinterpret_cast<t_block*>(&pc->b), index.data(), bMass, p->v);
                 }
                 if (p->f && fr->bF)
                 {
-                    gmx_calc_comg_f_block(top, fr->f, reinterpret_cast<t_block*>(&pc->b),
-                                          index.data(), bMass, p->f);
+                    gmx_calc_comg_f_block(
+                            top, fr->f, reinterpret_cast<t_block*>(&pc->b), index.data(), bMass, p->f);
                 }
                 break;
         }
index 224a4be226330445f11f1bdc6a53c9368107712d..f17c859c2803c62a9a538290dbe016ef52c3c140 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2009-2016, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +55,7 @@
 
 #include <cstdio>
 
-#include "gromacs/utility/classhelpers.h"
+#include <memory>
 
 /*! \name Flags for position calculation.
  * \anchor poscalc_flags
@@ -340,7 +340,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     /*! \brief
      * Needed to access the implementation class from the C code.
index bce1d67548e415008c15c1b3f13c345eb9c63898..48a1c56e0a3beea7455b06a11cc75c8be592e226 100644 (file)
 
 #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
 
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types. 
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
 #include <inttypes.h>
 typedef int8_t flex_int8_t;
 typedef uint8_t flex_uint8_t;
@@ -571,10 +564,6 @@ static yyconst flex_int16_t yy_chk[151] =
 // manually.
 #define YY_BREAK
 
-#ifdef __INTEL_COMPILER
-// Ignore unused variables in generated code.
-#pragma warning(disable:593)
-#endif
 #define YY_NO_UNISTD_H 1
 
 
index cd0f9512577db30f0b29cda8f61f01123d8ecfa1..632115a43b538e40f59617f75e608dabc4a980d5 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2009,2010,2011,2012,2013 by the GROMACS development team.
- * Copyright (c) 2014,2015,2016,2020, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 // manually.
 #define YY_BREAK
 
-#ifdef __INTEL_COMPILER
-// Ignore unused variables in generated code.
-#pragma warning(disable:593)
-#endif
 %}
 
 INTEGER    [[:digit:]]+
index 14d3030508e30446a5df94834a9bda7f9531da50..239c614eb8bf7f7e9d3ce9f02d2e810cea8216cb 100644 (file)
 
 #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
 
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types. 
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
 #include <inttypes.h>
 typedef int8_t flex_int8_t;
 typedef uint8_t flex_uint8_t;
index 20926675fdcbb4a5f6d2b0626a8dcee95d934297..34fbee597329e6b8bd5647bd02f1ed4e81b51a8b 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2009,2010,2011,2012,2013 by the GROMACS development team.
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -179,7 +179,7 @@ void computeMassesAndCharges(const gmx_mtop_t*    top,
         for (int i = pos.m.mapb.index[b]; i < pos.m.mapb.index[b + 1]; ++i)
         {
             const int     index = pos.m.mapb.a[i];
-            const t_atom& atom  = mtopGetAtomParameters(top, index, &molb);
+            const t_atom& atom  = mtopGetAtomParameters(*top, index, &molb);
             mass += atom.m;
             charge += atom.q;
         }
@@ -296,7 +296,8 @@ int Selection::initOriginalIdsToGroup(const gmx_mtop_t* top, e_index_t type)
         std::string message = formatString(
                 "Cannot group selection '%s' into %s, because some "
                 "positions have atoms from more than one such group.",
-                name(), type == INDEX_MOL ? "molecules" : "residues");
+                name(),
+                type == INDEX_MOL ? "molecules" : "residues");
         GMX_THROW(InconsistentInputError(message));
     }
 }
@@ -304,8 +305,14 @@ int Selection::initOriginalIdsToGroup(const gmx_mtop_t* top, e_index_t type)
 
 void Selection::printInfo(FILE* fp) const
 {
-    fprintf(fp, "\"%s\" (%d position%s, %d atom%s%s)", name(), posCount(), posCount() == 1 ? "" : "s",
-            atomCount(), atomCount() == 1 ? "" : "s", isDynamic() ? ", dynamic" : "");
+    fprintf(fp,
+            "\"%s\" (%d position%s, %d atom%s%s)",
+            name(),
+            posCount(),
+            posCount() == 1 ? "" : "s",
+            atomCount(),
+            atomCount() == 1 ? "" : "s",
+            isDynamic() ? ", dynamic" : "");
     fprintf(fp, "\n");
 }
 
index 733e37628a08c2240ce8baa90474abd61b1f886f..8d950d5a6244091e439dfbb5e86ca0b247dddb10 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2009,2010,2011,2012,2013 by the GROMACS development team.
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #ifndef GMX_SELECTION_SELECTION_H
 #define GMX_SELECTION_SELECTION_H
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -123,6 +124,8 @@ public:
     bool hasFlag(SelectionFlag flag) const { return flags_.test(flag); }
     //! Sets the flags for this selection.
     void setFlags(SelectionFlags flags) { flags_ = flags; }
+    //! Returns the current flags.
+    SelectionFlags flags() const { return flags_; }
 
     //! \copydoc Selection::initCoveredFraction()
     bool initCoveredFraction(e_coverfrac_t type);
index a9c6e6825aea95cfa26d8577b2915cc9d9c11983..ed13f9c69fea8bbc2bb0318ce1934148bd8ac466 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
 #include <cstdio>
 
 #include <memory>
+#include <optional>
 #include <string>
 #include <vector>
 
@@ -57,7 +58,6 @@
 #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"
@@ -257,14 +257,14 @@ void printCurrentStatus(TextWriter*              writer,
         }
         for (size_t i = firstSelection; i < sc->sel.size(); ++i)
         {
-            writer->writeString(formatString(" %2d. %s\n", static_cast<int>(i - firstSelection + 1),
-                                             sc->sel[i]->selectionText()));
+            writer->writeString(formatString(
+                    " %2d. %s\n", static_cast<int>(i - firstSelection + 1), sc->sel[i]->selectionText()));
         }
         if (maxCount > 0)
         {
             const int remaining = maxCount - static_cast<int>(sc->sel.size() - firstSelection);
-            writer->writeString(formatString("(%d more selection%s required)\n", remaining,
-                                             remaining > 1 ? "s" : ""));
+            writer->writeString(formatString(
+                    "(%d more selection%s required)\n", remaining, remaining > 1 ? "s" : ""));
         }
     }
 }
@@ -530,8 +530,55 @@ SelectionCollection::Impl::requiredTopologyPropertiesForPositionType(const std::
 SelectionCollection::SelectionCollection() : impl_(new Impl) {}
 
 
-SelectionCollection::~SelectionCollection() {}
+SelectionCollection::~SelectionCollection() = default;
 
+SelectionCollection::SelectionCollection(const SelectionCollection& rhs) :
+    impl_(std::make_unique<Impl>())
+{
+    setReferencePosType(rhs.impl_->rpost_.empty() ? PositionCalculationCollection::typeEnumValues[0]
+                                                  : rhs.impl_->rpost_.c_str());
+    setOutputPosType(rhs.impl_->spost_.empty() ? PositionCalculationCollection::typeEnumValues[0]
+                                               : rhs.impl_->spost_.c_str());
+    setDebugLevel(static_cast<int>(rhs.impl_->debugLevel_));
+
+    for (size_t i = 0; i < rhs.impl_->sc_.sel.size(); i++)
+    {
+        const auto& selectionOption = rhs.impl_->sc_.sel[i];
+        parseFromString(selectionOption->selectionText());
+        impl_->sc_.sel[i]->setFlags(selectionOption->flags());
+    }
+
+    // Topology has been initialized in rhs if top is non-null or natoms is set.
+    // Note this needs to be set after selections are parsed to register topology requirements properly.
+    if (rhs.impl_->sc_.top != nullptr || rhs.impl_->sc_.gall.isize > 0)
+    {
+        setTopology(rhs.impl_->sc_.top, rhs.impl_->sc_.gall.isize);
+        gmx_ana_index_copy(&impl_->sc_.gall, &rhs.impl_->sc_.gall, /*balloc=*/false);
+    }
+
+    if (rhs.impl_->grps_ != nullptr)
+    {
+        setIndexGroups(rhs.impl_->grps_);
+    }
+
+    // Only compile the selection if rhs is compiled.
+    if (rhs.impl_->sc_.mempool != nullptr)
+    {
+        compile();
+    }
+}
+
+SelectionCollection& SelectionCollection::operator=(SelectionCollection rhs)
+{
+    rhs.swap(*this);
+    return *this;
+}
+
+void SelectionCollection::swap(SelectionCollection& rhs)
+{
+    using std::swap;
+    swap(impl_, rhs.impl_);
+}
 
 void SelectionCollection::initOptions(IOptionsContainer* options, SelectionTypeOption selectionTypeOption)
 {
@@ -594,7 +641,7 @@ void SelectionCollection::setDebugLevel(int debugLevel)
 }
 
 
-void SelectionCollection::setTopology(gmx_mtop_t* top, int natoms)
+void SelectionCollection::setTopology(const gmx_mtop_t* top, int natoms)
 {
     GMX_RELEASE_ASSERT(natoms > 0 || top != nullptr,
                        "The number of atoms must be given if there is no topology");
@@ -688,8 +735,8 @@ bool SelectionCollection::requiresIndexGroups() const
 SelectionList SelectionCollection::parseFromStdin(int count, bool bInteractive, const std::string& context)
 {
     StandardInputStream inputStream;
-    return parseInteractive(count, &inputStream,
-                            bInteractive ? &TextOutputFile::standardError() : nullptr, context);
+    return parseInteractive(
+            count, &inputStream, bInteractive ? &TextOutputFile::standardError() : nullptr, context);
 }
 
 namespace
@@ -717,8 +764,8 @@ SelectionList SelectionCollection::parseInteractive(int                count,
     yyscan_t scanner;
 
     const std::unique_ptr<TextWriter> statusWriter(initStatusWriter(statusStream));
-    _gmx_sel_init_lexer(&scanner, &impl_->sc_, statusWriter.get(), count,
-                        impl_->bExternalGroupsSet_, impl_->grps_);
+    _gmx_sel_init_lexer(
+            &scanner, &impl_->sc_, statusWriter.get(), count, impl_->bExternalGroupsSet_, impl_->grps_);
     return runParser(scanner, inputStream, true, count, context);
 }
 
@@ -853,7 +900,8 @@ void SelectionCollection::evaluate(t_trxframe* fr, t_pbc* pbc)
                     "Trajectory has less atoms (%d) than what is required for "
                     "evaluating the provided selections (atoms up to index %d "
                     "are required).",
-                    fr->natoms, maxAtomIndex + 1);
+                    fr->natoms,
+                    maxAtomIndex + 1);
             GMX_THROW(InconsistentInputError(message));
         }
     }
@@ -876,6 +924,20 @@ void SelectionCollection::evaluateFinal(int nframes)
     evaluator.evaluateFinal(this, nframes);
 }
 
+std::optional<Selection> SelectionCollection::selection(std::string_view selName) const
+{
+    const auto& selections = impl_->sc_.sel;
+    if (const auto foundIter = std::find_if(
+                selections.cbegin(),
+                selections.cend(),
+                [selName](const auto& selection) { return selection->name() == selName; });
+        foundIter != selections.end())
+    {
+        return Selection(foundIter->get());
+    }
+    return std::nullopt;
+}
+
 
 void SelectionCollection::printTree(FILE* fp, bool bValues) const
 {
@@ -903,4 +965,9 @@ void SelectionCollection::printXvgrInfo(FILE* out) const
     std::fprintf(out, "#\n");
 }
 
+void swap(SelectionCollection& lhs, SelectionCollection& rhs)
+{
+    lhs.swap(rhs);
+}
+
 } // namespace gmx
index a168aaa1b22551c138fb6c977d38579550944284..e02ed9f32ac35a191de09c5224d85f0c1255bb6f 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2015,2016,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <memory>
+#include <optional>
 #include <string>
 #include <vector>
 
 #include "gromacs/selection/selection.h" // For gmx::SelectionList
-#include "gromacs/utility/classhelpers.h"
 
 struct gmx_ana_indexgrps_t;
 struct gmx_mtop_t;
@@ -61,7 +62,6 @@ namespace gmx
 {
 
 class IOptionsContainer;
-class SelectionCompiler;
 class SelectionEvaluator;
 class TextInputStream;
 class TextOutputStream;
@@ -81,6 +81,11 @@ struct SelectionTopologyProperties;
  * setOutputPosType().  See these methods for more details on the
  * initialization options.
  *
+ * SelectionCollections can be copied. Copies retain the same pointers to external indices (if set)
+ * and the topology (if set), and are compiled if the copied collection is compiled. Selection
+ * objects created from a given SelectionCollection are tied only to the original collection, so
+ * a copy of a SelectionCollection will not update pre-existing Selections on evaluate() calls.
+ *
  * After setting the default values, one or more selections can be parsed with
  * one or more calls to parseInteractive(), parseFromStdin(), parseFromFile(), and/or
  * parseFromString().  After all selections are parsed, the topology must be
@@ -138,6 +143,10 @@ public:
     SelectionCollection();
     ~SelectionCollection();
 
+    SelectionCollection(const SelectionCollection& rhs);
+    SelectionCollection& operator=(SelectionCollection rhs);
+    void                 swap(SelectionCollection& rhs);
+
     /*! \brief
      * Initializes options for setting global properties on the collection.
      *
@@ -246,7 +255,7 @@ public:
      * Does not throw currently, but this is subject to change when more
      * underlying code is converted to C++.
      */
-    void setTopology(gmx_mtop_t* top, int natoms);
+    void setTopology(const gmx_mtop_t* top, int natoms);
     /*! \brief
      * Sets the external index groups to use for the selections.
      *
@@ -388,7 +397,13 @@ public:
      * Does not throw.
      */
     void evaluateFinal(int nframes);
-
+    /*! \brief
+     * Retrieves a Selection handle for the selection with the given name
+     *
+     * @param selName name of the selection to return
+     * @return The selection with the given name, or nullopt if no such selection exists.
+     */
+    [[nodiscard]] std::optional<Selection> selection(std::string_view selName) const;
     /*! \brief
      * Prints a human-readable version of the internal selection element
      * tree.
@@ -414,7 +429,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     // Needed for the compiler to freely modify the collection.
     friend void compileSelection(SelectionCollection* coll);
@@ -422,6 +437,8 @@ private:
     friend class SelectionEvaluator;
 };
 
+void swap(SelectionCollection& lhs, SelectionCollection& rhs);
+
 } // namespace gmx
 
 #endif
index 5419a6bb876ae1cf1ef4f2a80e28039d6171bf16..3da677e2b12ae2488989730bd18f7091a66be3f8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -148,7 +148,7 @@ public:
         getMassesIfRequired(top);
     }
 
-    void getMassesIfRequired(gmx_mtop_t* top)
+    void getMassesIfRequired(gmx_mtop_t* top) const
     {
         const bool massRequired = selections_.requiredTopologyProperties().needsMasses;
         if (!massRequired)
@@ -193,7 +193,7 @@ SelectionOptionBehavior::~SelectionOptionBehavior() {}
 void SelectionOptionBehavior::initOptions(IOptionsContainer* options)
 {
     options->addOption(FileNameOption("n")
-                               .filetype(eftIndex)
+                               .filetype(OptionFileType::Index)
                                .inputFile()
                                .store(&impl_->ndxfile_)
                                .defaultBasename("index")
index 16f1a572c221a91b9e4c4a7a7bf34ad0bb824d1b..cc26a907268b797804f2c68d921652469e797e1b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_SELECTION_SELECTIONOPTIONBEHAVIOR_H
 #define GMX_SELECTION_SELECTIONOPTIONBEHAVIOR_H
 
+#include <memory>
 #include <string>
 
 #include "gromacs/options/ioptionsbehavior.h"
-#include "gromacs/utility/classhelpers.h"
 
 struct gmx_mtop_t;
 
@@ -173,7 +173,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 
index bc755086c4e51833d0330ff26694eef9089e31e4..3d6a601e746d87ba9002519e1ad9acd11eac506f 100644 (file)
@@ -176,7 +176,10 @@ void SelectionOptionManager::Impl::placeSelectionsInRequests(const SelectionList
                         formatString("Too few selections provided for '%s': "
                                      "Expected %d selections, but only %d left "
                                      "after assigning the first %d to other selections.",
-                                     request.name().c_str(), request.count(), remaining, assigned)));
+                                     request.name().c_str(),
+                                     request.count(),
+                                     remaining,
+                                     assigned)));
             }
             last = first + request.count();
         }
@@ -195,7 +198,10 @@ void SelectionOptionManager::Impl::placeSelectionsInRequests(const SelectionList
                                      "selections to be assigned to '%s'. "
                                      "Resolution for such cases is not implemented, "
                                      "and may be impossible.",
-                                     name, conflictName, name, conflictName)));
+                                     name,
+                                     conflictName,
+                                     name,
+                                     conflictName)));
             }
             last = selections.end();
         }
@@ -212,7 +218,9 @@ void SelectionOptionManager::Impl::placeSelectionsInRequests(const SelectionList
                 formatString("Too many selections provided: "
                              "Expected %d selections, but %d provided. "
                              "Last %d selections could not be assigned to any option.",
-                             assigned, count, remaining)));
+                             assigned,
+                             count,
+                             remaining)));
     }
 }
 
@@ -291,8 +299,8 @@ void SelectionOptionManager::parseRequestedFromStdin(bool bInteractive)
     for (i = impl_->requests_.begin(); i != impl_->requests_.end(); ++i)
     {
         const Impl::SelectionRequest& request = *i;
-        std::string   context = formatString("for option '%s'\n(%s)", request.name().c_str(),
-                                           request.description().c_str());
+        std::string                   context = formatString(
+                "for option '%s'\n(%s)", request.name().c_str(), request.description().c_str());
         SelectionList selections =
                 impl_->collection_.parseFromStdin(request.count(), bInteractive, context);
         request.storage_->addSelections(selections, true);
index 96baec9eff5f20b8cf02fa036ab631f94f6d55ca..2bdcc5fe0eb09285ffb467b1c4dde70ea95ae3bd 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_SELECTION_SELECTIONOPTIONMANAGER_H
 #define GMX_SELECTION_SELECTIONOPTIONMANAGER_H
 
+#include <memory>
 #include <string>
 
 #include "gromacs/options/options.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
@@ -216,7 +216,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     /*! \brief
      * Needed for handling delayed selection parsing requests.
index d81d5ff4a8223486ada26e481455acec3d47c8d3..05f89fc48e9e1ab140608ef8aaff3347529167e9 100644 (file)
@@ -469,7 +469,8 @@ void SelectionTreeElement::checkIndexGroup(int natoms)
                 "Group '%s' cannot be used in selections, because it "
                 "contains negative atom indices and/or references atoms "
                 "not present (largest allowed atom index is %d).",
-                name().c_str(), natoms);
+                name().c_str(),
+                natoms);
         GMX_THROW(InconsistentInputError(message));
     }
 }
@@ -564,8 +565,7 @@ void _gmx_selelem_print_tree(FILE* fp, const gmx::SelectionTreeElement& sel, boo
 {
     int i;
 
-    fprintf(fp, "%*c %s %s", level * 2 + 1, '*', _gmx_selelem_type_str(sel),
-            _gmx_sel_value_type_str(&sel.v));
+    fprintf(fp, "%*c %s %s", level * 2 + 1, '*', _gmx_selelem_type_str(sel), _gmx_sel_value_type_str(&sel.v));
     if (!sel.name().empty())
     {
         fprintf(fp, " \"%s\"", sel.name().c_str());
@@ -716,8 +716,7 @@ void _gmx_selelem_print_tree(FILE* fp, const gmx::SelectionTreeElement& sel, boo
                  * segfaults when printing the selection tree. */
                 if (sel.v.u.p->x)
                 {
-                    fprintf(fp, "(%f, %f, %f)", sel.v.u.p->x[0][XX], sel.v.u.p->x[0][YY],
-                            sel.v.u.p->x[0][ZZ]);
+                    fprintf(fp, "(%f, %f, %f)", sel.v.u.p->x[0][XX], sel.v.u.p->x[0][YY], sel.v.u.p->x[0][ZZ]);
                 }
                 else
                 {
index ec96ec50fdf868f6d48db210e7154bd89188a33c..9e6362b579b0244514fac1b488c773133af62da0 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2009,2010,2011,2012,2013 by the GROMACS development team.
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/onlinehelp/helptopic.h"
 #include "gromacs/onlinehelp/helpwritercontext.h"
+#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/stringutil.h"
index a648c3ca4f8ee3d6fb922c097271f6a1b7831706..489fb975609dc5ca9ffe5337d70a077de0552ce1 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2009-2018, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,53 +181,65 @@ static bool check_params(FILE*                                  fp,
         {
             if (param[i].val.type != INT_VALUE && param[i].val.type != REAL_VALUE)
             {
-                report_param_error(fp, name, param[i].name,
+                report_param_error(fp,
+                                   name,
+                                   param[i].name,
                                    "error: SPAR_RANGES cannot be set for a non-numeric parameter");
                 bOk = false;
             }
             if (param[i].flags & SPAR_DYNAMIC)
             {
-                report_param_error(fp, name, param[i].name,
+                report_param_error(fp,
+                                   name,
+                                   param[i].name,
                                    "warning: SPAR_DYNAMIC does not have effect with SPAR_RANGES");
                 param[i].flags &= ~SPAR_DYNAMIC;
             }
             if (!(param[i].flags & SPAR_VARNUM) && param[i].val.nr != 1)
             {
                 report_param_error(
-                        fp, name, param[i].name,
+                        fp,
+                        name,
+                        param[i].name,
                         "error: range should take either one or an arbitrary number of values");
                 bOk = false;
             }
             if (param[i].flags & SPAR_ATOMVAL)
             {
-                report_param_error(fp, name, param[i].name,
-                                   "error: SPAR_RANGES and SPAR_ATOMVAL both set");
+                report_param_error(
+                        fp, name, param[i].name, "error: SPAR_RANGES and SPAR_ATOMVAL both set");
                 bOk = false;
             }
         }
         if ((param[i].flags & SPAR_VARNUM) && (param[i].flags & SPAR_ATOMVAL))
         {
-            report_param_error(fp, name, param[i].name,
-                               "error: SPAR_VARNUM and SPAR_ATOMVAL both set");
+            report_param_error(
+                    fp, name, param[i].name, "error: SPAR_VARNUM and SPAR_ATOMVAL both set");
             bOk = false;
         }
         if (param[i].flags & SPAR_ENUMVAL)
         {
             if (param[i].val.type != STR_VALUE)
             {
-                report_param_error(fp, name, param[i].name,
+                report_param_error(fp,
+                                   name,
+                                   param[i].name,
                                    "error: SPAR_ENUMVAL can only be set for string parameters");
                 bOk = false;
             }
             if (param[i].val.nr != 1)
             {
-                report_param_error(fp, name, param[i].name,
+                report_param_error(fp,
+                                   name,
+                                   param[i].name,
                                    "error: SPAR_ENUMVAL parameters should take exactly one value");
                 bOk = false;
             }
             if (param[i].flags & (SPAR_DYNAMIC | SPAR_VARNUM | SPAR_ATOMVAL))
             {
-                report_param_error(fp, name, param[i].name,
+                report_param_error(fp,
+                                   name,
+                                   param[i].name,
                                    "error: only SPAR_OPTIONAL supported with SPAR_ENUMVAL");
                 bOk = false;
             }
@@ -237,7 +249,9 @@ static bool check_params(FILE*                                  fp,
         {
             if (param[i].val.nr != 0)
             {
-                report_param_error(fp, name, param[i].name,
+                report_param_error(fp,
+                                   name,
+                                   param[i].name,
                                    "error: number of values should be zero for boolean parameters");
                 bOk = false;
             }
@@ -247,7 +261,9 @@ static bool check_params(FILE*                                  fp,
             /* Any other flags should not be specified */
             if (param[i].flags & ~SPAR_OPTIONAL)
             {
-                report_param_error(fp, name, param[i].name,
+                report_param_error(fp,
+                                   name,
+                                   param[i].name,
                                    "error: boolean parameter should not have any flags set");
                 bOk = false;
             }
@@ -258,7 +274,9 @@ static bool check_params(FILE*                                  fp,
             if (param[i].val.nr != -1)
             {
                 report_param_error(
-                        fp, name, param[i].name,
+                        fp,
+                        name,
+                        param[i].name,
                         "warning: val.nr is not -1 although SPAR_VARNUM/SPAR_ATOMVAL is set");
             }
             param[i].val.nr = -1;
@@ -295,8 +313,8 @@ static bool check_params(FILE*                                  fp,
         {
             if (param[i].name[j] != '_' && !isalnum(param[i].name[j]))
             {
-                report_param_error(fp, name, param[i].name,
-                                   "error: name contains non-alphanumeric characters");
+                report_param_error(
+                        fp, name, param[i].name, "error: name contains non-alphanumeric characters");
                 bOk = false;
                 break;
             }
@@ -308,7 +326,9 @@ static bool check_params(FILE*                                  fp,
         /* Check that the name does not conflict with a method */
         if (symtab.findSymbol(param[i].name) != nullptr)
         {
-            report_param_error(fp, name, param[i].name,
+            report_param_error(fp,
+                               name,
+                               param[i].name,
                                "error: name conflicts with another method or a keyword");
             bOk = false;
         }
@@ -322,7 +342,9 @@ static bool check_params(FILE*                                  fp,
         gmx_ana_selparam_t*  param  = gmx_ana_selmethod_find_param(name, method);
         if (param)
         {
-            report_param_error(fp, method->name, param->name,
+            report_param_error(fp,
+                               method->name,
+                               param->name,
                                "error: name conflicts with another method or a keyword");
             bOk = false;
         }
@@ -353,7 +375,8 @@ static bool check_callbacks(FILE* fp, gmx_ana_selmethod_t* method)
     /* Make some checks on init_data and free */
     if (method->nparams > 0 && !method->init_data)
     {
-        report_error(fp, method->name,
+        report_error(fp,
+                     method->name,
                      "error: init_data should be provided because the method has parameters");
         bOk = false;
     }
@@ -364,14 +387,16 @@ static bool check_callbacks(FILE* fp, gmx_ana_selmethod_t* method)
     /* Check presence of outinit for position-valued methods */
     if (method->type == POS_VALUE && !method->outinit)
     {
-        report_error(fp, method->name,
+        report_error(fp,
+                     method->name,
                      "error: outinit should be provided because the method has POS_VALUE");
         bOk = false;
     }
     /* Check presence of outinit for variable output count methods */
     if ((method->flags & SMETH_VARNUMVAL) && !method->outinit)
     {
-        report_error(fp, method->name,
+        report_error(fp,
+                     method->name,
                      "error: outinit should be provided because the method has SMETH_VARNUMVAL");
         bOk = false;
     }
@@ -447,7 +472,8 @@ static bool check_method(FILE* fp, gmx_ana_selmethod_t* method, const gmx::Selec
         /* Check that conflicting flags are not present. */
         if (method->flags & SMETH_VARNUMVAL)
         {
-            report_error(fp, method->name,
+            report_error(fp,
+                         method->name,
                          "error: SMETH_VARNUMVAL cannot be set for group-valued methods");
             bOk = false;
         }
@@ -462,7 +488,8 @@ static bool check_method(FILE* fp, gmx_ana_selmethod_t* method, const gmx::Selec
     }
     if ((method->flags & SMETH_CHARVAL) && method->type != STR_VALUE)
     {
-        report_error(fp, method->name,
+        report_error(fp,
+                     method->name,
                      "error: SMETH_CHARVAL can only be specified for STR_VALUE methods");
         bOk = false;
     }
@@ -506,7 +533,8 @@ static bool check_modifier(FILE* fp, gmx_ana_selmethod_t* method, const gmx::Sel
     /* Check flags */
     if (method->flags & (SMETH_SINGLEVAL | SMETH_VARNUMVAL))
     {
-        report_error(fp, method->name,
+        report_error(fp,
+                     method->name,
                      "error: modifier should not have SMETH_SINGLEVAL or SMETH_VARNUMVAL set");
         bOk = false;
     }
index d649a874a4f396552de2a8aebf8588eba700ecb8..3dd91a6ab5804c6c9259bd58fe87e4493548cd73 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2009,2010,2011,2012,2013 by the GROMACS development team.
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -356,8 +356,10 @@ gmx_ana_selmethod_t sm_insolidangle = {
     &init_frame_insolidangle,
     nullptr,
     &evaluate_insolidangle,
-    { "insolidangle center POS span POS_EXPR [cutoff REAL]", "Selecting atoms in a solid angle",
-      asize(help_insolidangle), help_insolidangle },
+    { "insolidangle center POS span POS_EXPR [cutoff REAL]",
+      "Selecting atoms in a solid angle",
+      asize(help_insolidangle),
+      help_insolidangle },
 };
 
 static void* init_data_insolidangle(int /* npar */, gmx_ana_selparam_t* param)
@@ -395,12 +397,12 @@ static void init_insolidangle(const gmx_mtop_t* /* top */,
         GMX_THROW(gmx::InvalidInputError("Angle cutoff should be > 0"));
     }
 
-    surf->angcut *= DEG2RAD;
+    surf->angcut *= gmx::c_deg2Rad;
 
     surf->distccut      = -std::cos(surf->angcut);
     surf->targetbinsize = surf->angcut / 2;
     surf->ntbins        = static_cast<int>(M_PI / surf->targetbinsize);
-    surf->tbinsize      = (180.0 / surf->ntbins) * DEG2RAD;
+    surf->tbinsize      = (180.0 / surf->ntbins) * gmx::c_deg2Rad;
 
     snew(surf->tbin, static_cast<int>(M_PI / surf->tbinsize) + 1);
     surf->maxbins = 0;
index 1bf833e32a336465ef1a048a77bf7a41d148caec..d7936966c348a7371d218680a37ca0766cbea7ab 100644 (file)
@@ -242,8 +242,11 @@ static void init_output_common(const gmx_mtop_t* top, gmx_ana_selvalue_t* out, v
     {
         out->u.p->m.type = d->p1.m.type;
     }
-    gmx_ana_pos_reserve_for_append(out->u.p, d->p1.count() + d->p2.count(),
-                                   d->p1.m.b.nra + d->p2.m.b.nra, d->p1.v != nullptr, d->p1.f != nullptr);
+    gmx_ana_pos_reserve_for_append(out->u.p,
+                                   d->p1.count() + d->p2.count(),
+                                   d->p1.m.b.nra + d->p2.m.b.nra,
+                                   d->p1.v != nullptr,
+                                   d->p1.f != nullptr);
     gmx_ana_pos_empty_init(out->u.p);
 }
 
index f8a4e8c17518bc7bbf677bf4bbd2365c9746ab17..c8c24cd6beb9414362e643c2d848840ccd7c6dc6 100644 (file)
@@ -206,8 +206,8 @@ static void init_output_permute(const gmx_mtop_t* /* top */, gmx_ana_selvalue_t*
     int                   i, j, b;
 
     out->u.p->m.type = d->p.m.type;
-    gmx_ana_pos_reserve_for_append(out->u.p, d->p.count(), d->p.m.b.nra, d->p.v != nullptr,
-                                   d->p.f != nullptr);
+    gmx_ana_pos_reserve_for_append(
+            out->u.p, d->p.count(), d->p.m.b.nra, d->p.v != nullptr, d->p.f != nullptr);
     gmx_ana_pos_empty_init(out->u.p);
     for (i = 0; i < d->p.count(); i += d->n)
     {
index 2083f1203302decf93cb9f99661731200426c55f..1dbc4f0fafa857086fd99ea6aeb93ece5960e269 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2009,2010,2011,2012,2013 by the GROMACS development team.
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -470,7 +470,7 @@ static void evaluate_resnr(const gmx::SelMethodEvalContext& context,
     int molb = 0;
     for (int i = 0; i < g->isize; ++i)
     {
-        mtopGetAtomAndResidueName(context.top, g->index[i], &molb, nullptr, &out->u.i[i], nullptr, nullptr);
+        mtopGetAtomAndResidueName(*context.top, g->index[i], &molb, nullptr, &out->u.i[i], nullptr, nullptr);
     }
 }
 
@@ -490,7 +490,7 @@ static void evaluate_resindex(const gmx::SelMethodEvalContext& context,
     for (int i = 0; i < g->isize; ++i)
     {
         int resind;
-        mtopGetAtomAndResidueName(context.top, g->index[i], &molb, nullptr, nullptr, nullptr, &resind);
+        mtopGetAtomAndResidueName(*context.top, g->index[i], &molb, nullptr, nullptr, nullptr, &resind);
         out->u.i[i] = resind + 1;
     }
 }
@@ -521,7 +521,7 @@ static void evaluate_molindex(const gmx::SelMethodEvalContext& context,
     int molb = 0;
     for (int i = 0; i < g->isize; ++i)
     {
-        out->u.i[i] = mtopGetMoleculeIndex(context.top, g->index[i], &molb) + 1;
+        out->u.i[i] = mtopGetMoleculeIndex(*context.top, g->index[i], &molb) + 1;
     }
 }
 
@@ -541,7 +541,7 @@ static void evaluate_atomname(const gmx::SelMethodEvalContext& context,
     for (int i = 0; i < g->isize; ++i)
     {
         const char* atom_name;
-        mtopGetAtomAndResidueName(context.top, g->index[i], &molb, &atom_name, nullptr, nullptr, nullptr);
+        mtopGetAtomAndResidueName(*context.top, g->index[i], &molb, &atom_name, nullptr, nullptr, nullptr);
         out->u.s[i] = const_cast<char*>(atom_name);
     }
 }
@@ -561,7 +561,7 @@ static void evaluate_pdbatomname(const gmx::SelMethodEvalContext& context,
     int molb = 0;
     for (int i = 0; i < g->isize; ++i)
     {
-        const char* s = mtopGetAtomPdbInfo(context.top, g->index[i], &molb).atomnm;
+        const char* s = mtopGetAtomPdbInfo(*context.top, g->index[i], &molb).atomnm;
         while (std::isspace(*s))
         {
             ++s;
@@ -595,7 +595,7 @@ static void evaluate_atomtype(const gmx::SelMethodEvalContext& context,
     for (int i = 0; i < g->isize; ++i)
     {
         int atomIndexInMolecule;
-        mtopGetMolblockIndex(context.top, g->index[i], &molb, nullptr, &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];
     }
@@ -616,7 +616,7 @@ static void evaluate_resname(const gmx::SelMethodEvalContext& context,
     int molb = 0;
     for (int i = 0; i < g->isize; ++i)
     {
-        out->u.s[i] = *mtopGetResidueInfo(context.top, g->index[i], &molb).name;
+        out->u.s[i] = *mtopGetResidueInfo(*context.top, g->index[i], &molb).name;
     }
 }
 
@@ -635,7 +635,7 @@ static void evaluate_insertcode(const gmx::SelMethodEvalContext& context,
     int molb = 0;
     for (int i = 0; i < g->isize; ++i)
     {
-        out->u.s[i][0] = mtopGetResidueInfo(context.top, g->index[i], &molb).ic;
+        out->u.s[i][0] = mtopGetResidueInfo(*context.top, g->index[i], &molb).ic;
     }
 }
 
@@ -654,7 +654,7 @@ static void evaluate_chain(const gmx::SelMethodEvalContext& context,
     int molb = 0;
     for (int i = 0; i < g->isize; ++i)
     {
-        out->u.s[i][0] = mtopGetResidueInfo(context.top, g->index[i], &molb).chainid;
+        out->u.s[i][0] = mtopGetResidueInfo(*context.top, g->index[i], &molb).chainid;
     }
 }
 
@@ -674,7 +674,7 @@ static void evaluate_mass(const gmx::SelMethodEvalContext& context,
     int molb = 0;
     for (int i = 0; i < g->isize; ++i)
     {
-        out->u.r[i] = mtopGetAtomMass(context.top, g->index[i], &molb);
+        out->u.r[i] = mtopGetAtomMass(*context.top, g->index[i], &molb);
     }
 }
 
@@ -702,7 +702,7 @@ static void evaluate_charge(const gmx::SelMethodEvalContext& context,
     int molb = 0;
     for (int i = 0; i < g->isize; ++i)
     {
-        out->u.r[i] = mtopGetAtomParameters(context.top, g->index[i], &molb).q;
+        out->u.r[i] = mtopGetAtomParameters(*context.top, g->index[i], &molb).q;
     }
 }
 
@@ -729,7 +729,7 @@ static void evaluate_altloc(const gmx::SelMethodEvalContext& context,
     int molb = 0;
     for (int i = 0; i < g->isize; ++i)
     {
-        out->u.s[i][0] = mtopGetAtomPdbInfo(context.top, g->index[i], &molb).altloc;
+        out->u.s[i][0] = mtopGetAtomPdbInfo(*context.top, g->index[i], &molb).altloc;
     }
 }
 
@@ -749,7 +749,7 @@ static void evaluate_occupancy(const gmx::SelMethodEvalContext& context,
     int molb = 0;
     for (int i = 0; i < g->isize; ++i)
     {
-        out->u.r[i] = mtopGetAtomPdbInfo(context.top, g->index[i], &molb).occup;
+        out->u.r[i] = mtopGetAtomPdbInfo(*context.top, g->index[i], &molb).occup;
     }
 }
 
@@ -769,7 +769,7 @@ static void evaluate_betafactor(const gmx::SelMethodEvalContext& context,
     int molb = 0;
     for (int i = 0; i < g->isize; ++i)
     {
-        out->u.r[i] = mtopGetAtomPdbInfo(context.top, g->index[i], &molb).bfac;
+        out->u.r[i] = mtopGetAtomPdbInfo(*context.top, g->index[i], &molb).bfac;
     }
 }
 
index b435dda6b7ea1178c125c2dfeaaaf44b244ca8af..fb8b6bd7d79df0235a098ee867c914f6ec9b801c 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2009-2017, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -231,7 +231,7 @@ SelectionParserSymbolIterator::~SelectionParserSymbolIterator() {}
 
 SelectionParserSymbolIterator& SelectionParserSymbolIterator::operator=(const SelectionParserSymbolIterator& other)
 {
-    impl_.reset(new Impl(*other.impl_));
+    impl_ = std::make_unique<Impl>(*other.impl_);
     return *this;
 }
 
index 5feeeac876cbaf67ecbf8cedba0babcd2b1bd98e..21e6fbc684e3a9d4834fe3915ad961ae8650f46f 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2009,2010,2011,2012,2013 by the GROMACS development team.
- * Copyright (c) 2014,2015,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_SELECTION_SYMREC_H
 
 #include <iterator>
+#include <memory>
 #include <string>
 
 #include <boost/stl_interfaces/iterator_interface.hpp>
 
-#include "gromacs/utility/classhelpers.h"
-
 #include "selelem.h"
 
 struct gmx_ana_selmethod_t;
@@ -118,7 +117,7 @@ private:
      */
     explicit SelectionParserSymbol(Impl* impl);
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     /*! \brief
      * Needed to call the constructor and for other initialization.
@@ -179,7 +178,7 @@ private:
      */
     explicit SelectionParserSymbolIterator(Impl* impl);
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     /*! \brief
      * Needed to access the constructor.
@@ -260,7 +259,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     /*! \brief
      * Needed to access implementation types.
index a58289be0d15530522e5668902cdcfc0ea404c06..afc4fcce3b160b2df559df173f315f56fd71d367 100644 (file)
@@ -143,8 +143,8 @@ void IndexBlockTest::checkBlocka(const char* id)
     for (int i = 0; i < blocka_.nr; ++i)
     {
         gmx::test::TestReferenceChecker blockCompound(compound.checkCompound("Block", nullptr));
-        blockCompound.checkSequence(&blocka_.a[blocka_.index[i]], &blocka_.a[blocka_.index[i + 1]],
-                                    "Atoms");
+        blockCompound.checkSequence(
+                &blocka_.a[blocka_.index[i]], &blocka_.a[blocka_.index[i + 1]], "Atoms");
     }
 }
 
@@ -545,8 +545,8 @@ void IndexMapTest::checkMapping(int atomCount, const int atoms[], const char* na
     for (int i = 0; i < map_.mapb.nr; ++i)
     {
         gmx::test::TestReferenceChecker blockCompound(compound.checkCompound("Block", nullptr));
-        blockCompound.checkSequence(&atoms[map_.mapb.index[i]], &atoms[map_.mapb.index[i + 1]],
-                                    "Atoms");
+        blockCompound.checkSequence(
+                &atoms[map_.mapb.index[i]], &atoms[map_.mapb.index[i + 1]], "Atoms");
         blockCompound.checkInteger(map_.refid[i], "RefId");
         blockCompound.checkInteger(map_.mapid[i], "MapId");
         int originalIdIndex = (map_.refid[i] != -1 ? map_.refid[i] : i);
@@ -673,8 +673,9 @@ public:
         addGroupToBlocka_(indicesGroupSecondA_);
         addGroupToBlocka_(indicesGroupC_);
 
-        const char* const namesAsConstCharArray[4] = { groupNames[0].c_str(), groupNames[1].c_str(),
-                                                       groupNames[2].c_str(), groupNames[3].c_str() };
+        const char* const namesAsConstCharArray[4] = {
+            groupNames[0].c_str(), groupNames[1].c_str(), groupNames[2].c_str(), groupNames[3].c_str()
+        };
         indexGroupAndNames_ = std::make_unique<gmx::IndexGroupsAndNames>(blockA_, namesAsConstCharArray);
     }
     ~IndexGroupsAndNamesTest() override { done_blocka(&blockA_); }
index d0f61f30f7d934a480198c574a3c12e382fe3c7f..4601e45fd5ab9526a84a0d8da766f991ee0bd986 100644 (file)
@@ -626,8 +626,8 @@ void NeighborhoodSearchTest::testPairSearchFull(gmx::AnalysisNeighborhoodSearch*
             if (selfPairs)
             {
                 searchPair              = NeighborhoodSearchTestData::RefPair(testIndex, 0.0);
-                const auto otherRefPair = std::lower_bound(refPairs[refIndex].begin(),
-                                                           refPairs[refIndex].end(), searchPair);
+                const auto otherRefPair = std::lower_bound(
+                        refPairs[refIndex].begin(), refPairs[refIndex].end(), searchPair);
                 GMX_RELEASE_ASSERT(otherRefPair != refPairs[refIndex].end(),
                                    "Precomputed reference data is not symmetric");
                 otherRefPair->bFound = true;
@@ -1111,8 +1111,13 @@ TEST_F(NeighborhoodSearchTest, SimpleSearchExclusions)
             nb_.initSearch(&data.pbc_, data.refPositions().exclusionIds(helper.refPosIds()));
     ASSERT_EQ(gmx::AnalysisNeighborhood::eSearchMode_Simple, search.mode());
 
-    testPairSearchFull(&search, data, data.testPositions().exclusionIds(helper.testPosIds()),
-                       helper.exclusions(), {}, {}, false);
+    testPairSearchFull(&search,
+                       data,
+                       data.testPositions().exclusionIds(helper.testPosIds()),
+                       helper.exclusions(),
+                       {},
+                       {},
+                       false);
 }
 
 TEST_F(NeighborhoodSearchTest, GridSearchExclusions)
@@ -1129,8 +1134,13 @@ TEST_F(NeighborhoodSearchTest, GridSearchExclusions)
             nb_.initSearch(&data.pbc_, data.refPositions().exclusionIds(helper.refPosIds()));
     ASSERT_EQ(gmx::AnalysisNeighborhood::eSearchMode_Grid, search.mode());
 
-    testPairSearchFull(&search, data, data.testPositions().exclusionIds(helper.testPosIds()),
-                       helper.exclusions(), {}, {}, false);
+    testPairSearchFull(&search,
+                       data,
+                       data.testPositions().exclusionIds(helper.testPosIds()),
+                       helper.exclusions(),
+                       {},
+                       {},
+                       false);
 }
 
 } // namespace
index 9748909eb1e31ff202b75071062dc5776989e656..f4f2fcafe3bb775256943b82ce33722e834b49fa 100644 (file)
@@ -324,8 +324,8 @@ void PositionCalculationTest::checkPositions(gmx::test::TestReferenceChecker* ch
     for (int i = 0; i < p->count(); ++i)
     {
         gmx::test::TestReferenceChecker posCompound(compound.checkCompound("Position", nullptr));
-        posCompound.checkSequence(&p->m.mapb.a[p->m.mapb.index[i]],
-                                  &p->m.mapb.a[p->m.mapb.index[i + 1]], "Atoms");
+        posCompound.checkSequence(
+                &p->m.mapb.a[p->m.mapb.index[i]], &p->m.mapb.a[p->m.mapb.index[i + 1]], "Atoms");
         posCompound.checkInteger(p->m.refid[i], "RefId");
         if (bCoordinates)
         {
diff --git a/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_CopiedSelectionWithIndexPostCompilation.xml b/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_CopiedSelectionWithIndexPostCompilation.xml
new file mode 100644 (file)
index 0000000..8cae2e6
--- /dev/null
@@ -0,0 +1,130 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <ParsedSelections Name="Parsed">
+    <ParsedSelection Name="Selection1">
+      <String Name="Input">group "GrpA"</String>
+      <String Name="Name">GrpA</String>
+      <String Name="Text">group "GrpA"</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection2">
+      <String Name="Input">GrpB</String>
+      <String Name="Name">GrpB</String>
+      <String Name="Text">GrpB</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection3">
+      <String Name="Input">1</String>
+      <String Name="Name">GrpB</String>
+      <String Name="Text">1</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection4">
+      <String Name="Input">group "GrpB" and resname RB</String>
+      <String Name="Name">group "GrpB" and resname RB</String>
+      <String Name="Text">group "GrpB" and resname RB</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection5">
+      <String Name="Input">group "GrpA" permute 5 3 2 1 4</String>
+      <String Name="Name">group "GrpA" permute 5 3 2 1 4</String>
+      <String Name="Text">group "GrpA" permute 5 3 2 1 4</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection6">
+      <String Name="Input">group "GrpA" plus group "GrpB"</String>
+      <String Name="Name">group "GrpA" plus group "GrpB"</String>
+      <String Name="Text">group "GrpA" plus group "GrpB"</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection7">
+      <String Name="Input">res_cog of group "GrpA"</String>
+      <String Name="Name">res_cog of group "GrpA"</String>
+      <String Name="Text">res_cog of group "GrpA"</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+  </ParsedSelections>
+  <CompiledSelections Name="Compiled">
+    <Selection Name="Selection1">
+      <String Name="Name">GrpA</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <String Name="Name">GrpB</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection3">
+      <String Name="Name">GrpB</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection4">
+      <String Name="Name">group "GrpB" and resname RB</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">3</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection5">
+      <String Name="Name">group "GrpA" permute 5 3 2 1 4</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>3</Int>
+        <Int>2</Int>
+        <Int>1</Int>
+        <Int>4</Int>
+        <Int>0</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection6">
+      <String Name="Name">group "GrpA" plus group "GrpB"</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">10</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection7">
+      <String Name="Name">res_cog of group "GrpA"</String>
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+      </Sequence>
+    </Selection>
+  </CompiledSelections>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_CopiedSelectionWorksPostCompilation.xml b/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_CopiedSelectionWorksPostCompilation.xml
new file mode 100644 (file)
index 0000000..3c59289
--- /dev/null
@@ -0,0 +1,397 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <ParsedSelections Name="Parsed">
+    <ParsedSelection Name="Selection1">
+      <String Name="Input">x &gt; 2</String>
+      <String Name="Text">x &gt; 2</String>
+      <Bool Name="Dynamic">true</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection2">
+      <String Name="Input">2 &lt; x</String>
+      <String Name="Text">2 &lt; x</String>
+      <Bool Name="Dynamic">true</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection3">
+      <String Name="Input">y &gt; resnr</String>
+      <String Name="Text">y &gt; resnr</String>
+      <Bool Name="Dynamic">true</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection4">
+      <String Name="Input">resnr &lt; 2.5</String>
+      <String Name="Text">resnr &lt; 2.5</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection5">
+      <String Name="Input">2.5 &gt; resnr</String>
+      <String Name="Text">2.5 &gt; resnr</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+  </ParsedSelections>
+  <CompiledSelections Name="Compiled">
+    <Selection Name="Selection1">
+      <Sequence Name="Atoms">
+        <Int Name="Length">15</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <Sequence Name="Atoms">
+        <Int Name="Length">15</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection3">
+      <Sequence Name="Atoms">
+        <Int Name="Length">15</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection4">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection5">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+    </Selection>
+  </CompiledSelections>
+  <EvaluatedSelections Name="Frame1">
+    <Selection Name="Selection1">
+      <Sequence Name="Atoms">
+        <Int Name="Length">7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">7</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <Sequence Name="Atoms">
+        <Int Name="Length">7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">7</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection3">
+      <Sequence Name="Atoms">
+        <Int Name="Length">4</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>7</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">4</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection4">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">6</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection5">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">6</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+  </EvaluatedSelections>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_CopiedSelectionWorksPreCompilation.xml b/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_CopiedSelectionWorksPreCompilation.xml
new file mode 100644 (file)
index 0000000..3c59289
--- /dev/null
@@ -0,0 +1,397 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <ParsedSelections Name="Parsed">
+    <ParsedSelection Name="Selection1">
+      <String Name="Input">x &gt; 2</String>
+      <String Name="Text">x &gt; 2</String>
+      <Bool Name="Dynamic">true</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection2">
+      <String Name="Input">2 &lt; x</String>
+      <String Name="Text">2 &lt; x</String>
+      <Bool Name="Dynamic">true</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection3">
+      <String Name="Input">y &gt; resnr</String>
+      <String Name="Text">y &gt; resnr</String>
+      <Bool Name="Dynamic">true</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection4">
+      <String Name="Input">resnr &lt; 2.5</String>
+      <String Name="Text">resnr &lt; 2.5</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection5">
+      <String Name="Input">2.5 &gt; resnr</String>
+      <String Name="Text">2.5 &gt; resnr</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+  </ParsedSelections>
+  <CompiledSelections Name="Compiled">
+    <Selection Name="Selection1">
+      <Sequence Name="Atoms">
+        <Int Name="Length">15</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <Sequence Name="Atoms">
+        <Int Name="Length">15</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection3">
+      <Sequence Name="Atoms">
+        <Int Name="Length">15</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection4">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection5">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+    </Selection>
+  </CompiledSelections>
+  <EvaluatedSelections Name="Frame1">
+    <Selection Name="Selection1">
+      <Sequence Name="Atoms">
+        <Int Name="Length">7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">7</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <Sequence Name="Atoms">
+        <Int Name="Length">7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">7</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection3">
+      <Sequence Name="Atoms">
+        <Int Name="Length">4</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>7</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">4</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection4">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">6</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection5">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">6</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+  </EvaluatedSelections>
+</ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_CopiedSelectionsAreIndependent.xml b/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_CopiedSelectionsAreIndependent.xml
new file mode 100644 (file)
index 0000000..3c59289
--- /dev/null
@@ -0,0 +1,397 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <ParsedSelections Name="Parsed">
+    <ParsedSelection Name="Selection1">
+      <String Name="Input">x &gt; 2</String>
+      <String Name="Text">x &gt; 2</String>
+      <Bool Name="Dynamic">true</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection2">
+      <String Name="Input">2 &lt; x</String>
+      <String Name="Text">2 &lt; x</String>
+      <Bool Name="Dynamic">true</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection3">
+      <String Name="Input">y &gt; resnr</String>
+      <String Name="Text">y &gt; resnr</String>
+      <Bool Name="Dynamic">true</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection4">
+      <String Name="Input">resnr &lt; 2.5</String>
+      <String Name="Text">resnr &lt; 2.5</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection5">
+      <String Name="Input">2.5 &gt; resnr</String>
+      <String Name="Text">2.5 &gt; resnr</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+  </ParsedSelections>
+  <CompiledSelections Name="Compiled">
+    <Selection Name="Selection1">
+      <Sequence Name="Atoms">
+        <Int Name="Length">15</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <Sequence Name="Atoms">
+        <Int Name="Length">15</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection3">
+      <Sequence Name="Atoms">
+        <Int Name="Length">15</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection4">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection5">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+    </Selection>
+  </CompiledSelections>
+  <EvaluatedSelections Name="Frame1">
+    <Selection Name="Selection1">
+      <Sequence Name="Atoms">
+        <Int Name="Length">7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">7</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <Sequence Name="Atoms">
+        <Int Name="Length">7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">7</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">3</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">4</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection3">
+      <Sequence Name="Atoms">
+        <Int Name="Length">4</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>7</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">4</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection4">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">6</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection5">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+      </Sequence>
+      <Sequence Name="Positions">
+        <Int Name="Length">6</Int>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">3</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">1</Real>
+            <Real Name="Y">4</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">1</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+        <Position>
+          <Vector Name="Coordinates">
+            <Real Name="X">2</Real>
+            <Real Name="Y">2</Real>
+            <Real Name="Z">0</Real>
+          </Vector>
+        </Position>
+      </Sequence>
+    </Selection>
+  </EvaluatedSelections>
+</ReferenceData>
index b8c02bb836e3e2a62a66096a21690c718b816797..7b835c0481285364cf115603283779d975717fb1 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -138,7 +138,6 @@ void SelectionCollectionTest::loadIndexGroups(const char* filename)
     sc_.setIndexGroups(grps_);
 }
 
-
 /********************************************************************
  * Test fixture for interactive SelectionCollection tests
  */
@@ -160,7 +159,8 @@ void SelectionCollectionInteractiveTest::runTest(int  count,
 {
     helper_.setInputLines(inputLines);
     // TODO: Check something about the returned selections as well.
-    ASSERT_NO_THROW_GMX(sc_.parseInteractive(count, &helper_.inputStream(),
+    ASSERT_NO_THROW_GMX(sc_.parseInteractive(count,
+                                             &helper_.inputStream(),
                                              bInteractive ? &helper_.outputStream() : nullptr,
                                              "for test context"));
     helper_.checkSession();
@@ -199,12 +199,13 @@ public:
     void runTest(int natoms, const gmx::ArrayRef<const char* const>& selections);
     void runTest(const char* filename, const gmx::ArrayRef<const char* const>& selections);
 
+    void checkCompiled();
+
 private:
     static void checkSelection(gmx::test::TestReferenceChecker* checker,
                                const gmx::Selection&            sel,
                                TestFlags                        flags);
 
-    void checkCompiled();
 
     gmx::test::TestReferenceData    data_;
     gmx::test::TestReferenceChecker checker_;
@@ -635,6 +636,47 @@ TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets4)
 
 // TODO: Tests for more evaluation errors
 
+
+/********************************************************************
+ * Tests for retrieving selections.
+ */
+TEST_F(SelectionCollectionTest, RetrieveValidSelection)
+{
+    ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
+    const std::optional<gmx::Selection> retrievedSel = sc_.selection(sel_[0].name());
+    ASSERT_TRUE(retrievedSel.has_value());
+    EXPECT_STREQ(sel_[0].name(), retrievedSel->name());
+}
+
+TEST_F(SelectionCollectionTest, RetrieveInvalidSelection)
+{
+    ASSERT_FALSE(sc_.selection("some invalid key").has_value());
+}
+
+/********************************************************************
+ * Tests for assignment/copying.
+ */
+TEST_F(SelectionCollectionTest, CanCopyEmptyCollection)
+{
+    EXPECT_NO_THROW_GMX(gmx::SelectionCollection sc2(sc_));
+}
+
+TEST_F(SelectionCollectionTest, CopiedSelectionListsAreHandledSeparately)
+{
+    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());
+    gmx::SelectionCollection sc2(sc_);
+    ASSERT_NO_THROW_GMX(sel_[1].setEvaluateVelocities(true));
+    ASSERT_NO_THROW_GMX(sel_[1].setEvaluateForces(true));
+    ASSERT_NO_THROW_GMX(sc2.compile());
+    // These would only be populated if sc_.compile() was called
+    EXPECT_FALSE(sel_[1].hasVelocities());
+    EXPECT_FALSE(sel_[1].hasForces());
+}
+
+
 /********************************************************************
  * Tests for interactive selection input
  */
@@ -742,7 +784,8 @@ TEST_F(SelectionCollectionDataTest, HandlesAllNone)
 
 TEST_F(SelectionCollectionDataTest, HandlesAtomnr)
 {
-    static const char* const selections[] = { "atomnr 1 to 3 6 to 8", "atomnr 4 2 5 to 7",
+    static const char* const selections[] = { "atomnr 1 to 3 6 to 8",
+                                              "atomnr 4 2 5 to 7",
                                               "atomnr <= 5" };
     runTest(10, selections);
 }
@@ -777,8 +820,9 @@ TEST_F(SelectionCollectionDataTest, HandlesAtomname)
 
 TEST_F(SelectionCollectionDataTest, HandlesPdbAtomname)
 {
-    static const char* const selections[] = { "name HG21", "name 1HG2", "pdbname HG21 CB",
-                                              "pdbatomname 1HG2" };
+    static const char* const selections[] = {
+        "name HG21", "name 1HG2", "pdbname HG21 CB", "pdbatomname 1HG2"
+    };
     runTest("simple.pdb", selections);
 }
 
@@ -888,9 +932,11 @@ TEST_F(SelectionCollectionDataTest, HandlesSameResidueName)
 
 TEST_F(SelectionCollectionDataTest, HandlesPositionKeywords)
 {
-    static const char* const selections[] = { "cog of resnr 1 3", "res_cog of name CB and resnr 1 3",
+    static const char* const selections[] = { "cog of resnr 1 3",
+                                              "res_cog of name CB and resnr 1 3",
                                               "whole_res_cog of name CB and resnr 1 3",
-                                              "part_res_cog of x < 3", "dyn_res_cog of x < 3" };
+                                              "part_res_cog of x < 3",
+                                              "dyn_res_cog of x < 3" };
     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates | efTestPositionAtoms);
     runTest("simple.gro", selections);
 }
@@ -946,7 +992,8 @@ TEST_F(SelectionCollectionDataTest, HandlesPermuteModifier)
 TEST_F(SelectionCollectionDataTest, HandlesPlusModifier)
 {
     static const char* const selections[] = {
-        "name S2 plus name S1", "res_cog of resnr 2 plus res_cog of resnr 1 plus res_cog of resnr 3",
+        "name S2 plus name S1",
+        "res_cog of resnr 2 plus res_cog of resnr 1 plus res_cog of resnr 3",
         "name S1 and y < 3 plus res_cog of x < 2.5"
     };
     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates | efTestPositionAtoms
@@ -1003,7 +1050,8 @@ TEST_F(SelectionCollectionDataTest, ComputesMassesAndChargesWithoutTopology)
 TEST_F(SelectionCollectionDataTest, HandlesFramesWithAtomSubsets)
 {
     const int         index[]      = { 0, 1, 2, 3, 4, 5, 9, 10, 11 };
-    const char* const selections[] = { "resnr 1 4", "atomnr 1 2 5 11 and y > 2",
+    const char* const selections[] = { "resnr 1 4",
+                                       "atomnr 1 2 5 11 and y > 2",
                                        "res_cog of atomnr 2 5 11" };
     setFlags(TestFlags() | efTestEvaluation | efTestPositionAtoms);
     ASSERT_NO_FATAL_FAILURE(runParser(selections));
@@ -1022,7 +1070,8 @@ TEST_F(SelectionCollectionDataTest, HandlesFramesWithAtomSubsets)
 TEST_F(SelectionCollectionDataTest, HandlesSelectionNames)
 {
     static const char* const selections[] = { "\"GroupSelection\" group \"GrpA\"",
-                                              "\"DynamicSelection\" x < 5", "y < 3" };
+                                              "\"DynamicSelection\" x < 5",
+                                              "y < 3" };
     setFlags(TestFlags() | efTestSelectionNames);
     ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
     runTest(10, selections);
@@ -1030,7 +1079,9 @@ TEST_F(SelectionCollectionDataTest, HandlesSelectionNames)
 
 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelections)
 {
-    static const char* const selections[] = { "group \"GrpA\"", "GrpB", "1",
+    static const char* const selections[] = { "group \"GrpA\"",
+                                              "GrpB",
+                                              "1",
                                               // These test that the name of the group is not too
                                               // eagerly promoted to the name of the selection.
                                               "group \"GrpB\" and resname RB",
@@ -1044,8 +1095,9 @@ TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelections)
 
 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelectionsDelayed)
 {
-    static const char* const selections[] = { "group \"GrpA\"", "GrpB", "1",
-                                              "group \"GrpB\" and resname RB" };
+    static const char* const selections[] = {
+        "group \"GrpA\"", "GrpB", "1", "group \"GrpB\" and resname RB"
+    };
     setFlags(TestFlags() | efTestSelectionNames);
     ASSERT_NO_FATAL_FAILURE(runParser(selections));
     ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
@@ -1155,7 +1207,8 @@ TEST_F(SelectionCollectionDataTest, HandlesRegexMatching)
 TEST_F(SelectionCollectionDataTest, HandlesBasicBoolean)
 {
     static const char* const selections[] = {
-        "atomnr 1 to 5 and atomnr 2 to 7", "atomnr 1 to 5 or not atomnr 3 to 8",
+        "atomnr 1 to 5 and atomnr 2 to 7",
+        "atomnr 1 to 5 or not atomnr 3 to 8",
         "not not atomnr 1 to 5 and atomnr 2 to 6 and not not atomnr 3 to 7",
         "atomnr 1 to 5 and (atomnr 2 to 7 and atomnr 3 to 6)",
         "x < 5 and atomnr 1 to 5 and y < 3 and atomnr 2 to 4"
@@ -1177,8 +1230,7 @@ TEST_F(SelectionCollectionDataTest, HandlesDynamicAtomValuedParameters)
 
 TEST_F(SelectionCollectionDataTest, HandlesEmptySelectionWithUnevaluatedExpressions)
 {
-    static const char* const selections[] = { "none and x > 2",
-                                              "none and same resname as resnr 2" };
+    static const char* const selections[] = { "none and x > 2", "none and same resname as resnr 2" };
     runTest("simple.gro", selections);
 }
 
@@ -1224,8 +1276,9 @@ TEST_F(SelectionCollectionDataTest, HandlesKeywordOfPositionsInArithmetic)
 
 TEST_F(SelectionCollectionDataTest, HandlesNumericComparisons)
 {
-    static const char* const selections[] = { "x > 2", "2 < x", "y > resnr", "resnr < 2.5",
-                                              "2.5 > resnr" };
+    static const char* const selections[] = {
+        "x > 2", "2 < x", "y > resnr", "resnr < 2.5", "2.5 > resnr"
+    };
     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
     runTest("simple.gro", selections);
 }
@@ -1241,8 +1294,9 @@ TEST_F(SelectionCollectionDataTest, HandlesArithmeticExpressions)
 
 TEST_F(SelectionCollectionDataTest, HandlesNumericVariables)
 {
-    static const char* const selections[] = { "value = x + y", "value <= 4", "index = resnr",
-                                              "index < 3" };
+    static const char* const selections[] = {
+        "value = x + y", "value <= 4", "index = resnr", "index < 3"
+    };
     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
     runTest("simple.gro", selections);
 }
@@ -1272,7 +1326,8 @@ TEST_F(SelectionCollectionDataTest, HandlesPositionVariables)
 
 TEST_F(SelectionCollectionDataTest, HandlesPositionVariableInModifier)
 {
-    static const char* const selections[] = { "foo = cog of resnr 1", "cog of resnr 2 plus foo",
+    static const char* const selections[] = { "foo = cog of resnr 1",
+                                              "cog of resnr 2 plus foo",
                                               "cog of resnr 3 plus foo" };
     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
     runTest("simple.gro", selections);
@@ -1281,7 +1336,8 @@ TEST_F(SelectionCollectionDataTest, HandlesPositionVariableInModifier)
 
 TEST_F(SelectionCollectionDataTest, HandlesConstantPositionInVariable)
 {
-    static const char* const selections[] = { "constpos = [1.0, 2.5, 0.5]", "constpos",
+    static const char* const selections[] = { "constpos = [1.0, 2.5, 0.5]",
+                                              "constpos",
                                               "within 2 of constpos" };
     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates | efTestPositionAtoms);
     runTest("simple.gro", selections);
@@ -1290,8 +1346,11 @@ TEST_F(SelectionCollectionDataTest, HandlesConstantPositionInVariable)
 
 TEST_F(SelectionCollectionDataTest, HandlesNumericConstantsInVariables)
 {
-    static const char* const selections[] = { "constint = 4", "constreal1 = 0.5", "constreal2 = 2.7",
-                                              "resnr < constint", "x + constreal1 < constreal2" };
+    static const char* const selections[] = { "constint = 4",
+                                              "constreal1 = 0.5",
+                                              "constreal2 = 2.7",
+                                              "resnr < constint",
+                                              "x + constreal1 < constreal2" };
     setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
     runTest("simple.gro", selections);
 }
@@ -1304,7 +1363,8 @@ TEST_F(SelectionCollectionDataTest, HandlesNumericConstantsInVariables)
 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysis)
 {
     static const char* const selections[] = {
-        "atomnr 1 to 5 and atomnr 2 to 7 and x < 2", "atomnr 1 to 5 and (atomnr 4 to 7 or x < 2)",
+        "atomnr 1 to 5 and atomnr 2 to 7 and x < 2",
+        "atomnr 1 to 5 and (atomnr 4 to 7 or x < 2)",
         "atomnr 1 to 5 and y < 3 and (atomnr 4 to 7 or x < 2)",
         "atomnr 1 to 5 and not (atomnr 4 to 7 or x < 2)",
         "atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x < 2))"
@@ -1344,8 +1404,10 @@ TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithMoreVariable
 
 TEST_F(SelectionCollectionDataTest, HandlesUnusedVariables)
 {
-    static const char* const selections[] = { "unused1 = atomnr 1 to 3", "foo = atomnr 4 to 7",
-                                              "atomnr 1 to 6 and foo", "unused2 = atomnr 3 to 5" };
+    static const char* const selections[] = { "unused1 = atomnr 1 to 3",
+                                              "foo = atomnr 4 to 7",
+                                              "atomnr 1 to 6 and foo",
+                                              "unused2 = atomnr 3 to 5" };
     runTest(10, selections);
 }
 
@@ -1353,15 +1415,17 @@ TEST_F(SelectionCollectionDataTest, HandlesUnusedVariables)
 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithStaticEvaluationGroups)
 {
     static const char* const selections[] = { "foo = atomnr 4 to 7 and x < 2",
-                                              "atomnr 1 to 5 and foo", "atomnr 3 to 7 and foo" };
+                                              "atomnr 1 to 5 and foo",
+                                              "atomnr 3 to 7 and foo" };
     runTest(10, selections);
 }
 
 
 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups)
 {
-    static const char* const selections[] = { "foo = atomnr 4 to 7 and x < 2",
-                                              "atomnr 1 to 6 and foo", "within 1 of foo", "foo" };
+    static const char* const selections[] = {
+        "foo = atomnr 4 to 7 and x < 2", "atomnr 1 to 6 and foo", "within 1 of foo", "foo"
+    };
     runTest(10, selections);
 }
 
@@ -1369,10 +1433,127 @@ TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups)
 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups2)
 {
     static const char* const selections[] = { "foo = atomnr 1 to 8 and x < 10",
-                                              "atomnr 1 to 5 and y < 10 and foo", "foo" };
+                                              "atomnr 1 to 5 and y < 10 and foo",
+                                              "foo" };
     setFlags(TestFlags() | efTestEvaluation);
     runTest("simple.gro", selections);
 }
 
+/*******************************************************************
+ * Tests for copy validation.
+ *
+ * These tests ensure that copies of a SelectionCollection behave as the original while being
+ * independently evaluated.
+ */
+TEST_F(SelectionCollectionDataTest, CopiedSelectionWorksPreCompilation)
+{
+    static const char* const selections[] = {
+        "x > 2", "2 < x", "y > resnr", "resnr < 2.5", "2.5 > resnr"
+    };
+    setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
+    ASSERT_NO_FATAL_FAILURE(runParser(selections));
+    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+    std::vector<std::string> selNames;
+    for (const auto& sel : sel_)
+    {
+        selNames.emplace_back(sel.name());
+    }
+    // Swap copied selection with original and update selections, to reuse the testing machinery.
+    gmx::SelectionCollection sc2(sc_);
+    sc_ = sc2;
+    std::vector<gmx::Selection> sel2;
+    for (const std::string_view selName : selNames)
+    {
+        std::optional<gmx::Selection> maybeSel = sc_.selection(selName);
+        ASSERT_TRUE(maybeSel.has_value());
+        sel2.push_back(*maybeSel);
+    }
+    sel_ = std::move(sel2);
+
+    ASSERT_NO_FATAL_FAILURE(runCompiler());
+    ASSERT_NO_FATAL_FAILURE(runEvaluate());
+    ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
+}
+
+TEST_F(SelectionCollectionDataTest, CopiedSelectionWorksPostCompilation)
+{
+    static const char* const selections[] = {
+        "x > 2", "2 < x", "y > resnr", "resnr < 2.5", "2.5 > resnr"
+    };
+    setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
+    ASSERT_NO_FATAL_FAILURE(runParser(selections));
+    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+
+    ASSERT_NO_FATAL_FAILURE(runCompiler());
+    // Note the copy is made post-compilation.
+    std::vector<std::string> selNames;
+    for (const auto& sel : sel_)
+    {
+        selNames.emplace_back(sel.name());
+    }
+    gmx::SelectionCollection sc2(sc_);
+    sc_ = sc2;
+    std::vector<gmx::Selection> sel2;
+    for (const std::string_view selName : selNames)
+    {
+        std::optional<gmx::Selection> maybeSel = sc_.selection(selName);
+        ASSERT_TRUE(maybeSel.has_value());
+        sel2.push_back(*maybeSel);
+    }
+    sel_ = std::move(sel2);
+
+    ASSERT_NO_FATAL_FAILURE(runEvaluate());
+    ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
+}
+
+TEST_F(SelectionCollectionDataTest, CopiedSelectionsAreIndependent)
+{
+    static const char* const selections[] = {
+        "x > 2", "2 < x", "y > resnr", "resnr < 2.5", "2.5 > resnr"
+    };
+    setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
+    ASSERT_NO_FATAL_FAILURE(runParser(selections));
+    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+
+    ASSERT_NO_FATAL_FAILURE(runCompiler());
+    // Check that copy evaluation does not conflict with original.
+    gmx::SelectionCollection sc2(sc_);
+    ASSERT_NO_THROW_GMX(sc2.evaluate(topManager_.frame(), nullptr));
+
+    ASSERT_NO_FATAL_FAILURE(runEvaluate());
+    ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
+}
+
+TEST_F(SelectionCollectionDataTest, CopiedSelectionWithIndexPostCompilation)
+{
+    static const char* const selections[] = { "group \"GrpA\"",
+                                              "GrpB",
+                                              "1",
+                                              "group \"GrpB\" and resname RB",
+                                              "group \"GrpA\" permute 5 3 2 1 4",
+                                              "group \"GrpA\" plus group \"GrpB\"",
+                                              "res_cog of group \"GrpA\"" };
+    setFlags(TestFlags() | efTestSelectionNames);
+    ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
+    ASSERT_NO_FATAL_FAILURE(runParser(selections));
+    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+    ASSERT_NO_FATAL_FAILURE(runCompiler());
+    std::vector<std::string> selNames;
+    for (const auto& sel : sel_)
+    {
+        selNames.emplace_back(sel.name());
+    }
+    gmx::SelectionCollection sc2(sc_);
+    sc_ = sc2;
+    std::vector<gmx::Selection> sel2;
+    for (const std::string_view selName : selNames)
+    {
+        std::optional<gmx::Selection> maybeSel = sc_.selection(selName);
+        ASSERT_TRUE(maybeSel.has_value());
+        sel2.push_back(*maybeSel);
+    }
+    sel_ = std::move(sel2);
+    checkCompiled();
+}
 
 } // namespace
index 8b6388db44bfe893d199f9e5437902f12b53b9e3..dcb450937dc9fe35c15435c8b3907b04ed3f736e 100644 (file)
@@ -126,8 +126,13 @@ void TopologyManager::loadTopology(const char* filename)
 
     GMX_RELEASE_ASSERT(mtop_ == nullptr, "Topology initialized more than once");
     mtop_ = std::make_unique<gmx_mtop_t>();
-    readConfAndTopology(gmx::test::TestFileManager::getInputFilePath(filename).c_str(), &fullTopology,
-                        mtop_.get(), &pbcType, frame_ != nullptr ? &xtop : nullptr, nullptr, box);
+    readConfAndTopology(gmx::test::TestFileManager::getInputFilePath(filename).c_str(),
+                        &fullTopology,
+                        mtop_.get(),
+                        &pbcType,
+                        frame_ != nullptr ? &xtop : nullptr,
+                        nullptr,
+                        box);
 
     if (frame_ != nullptr)
     {
index 341d9cc90b4de756859cf98ce781a9cea71730ab..44179a030414c7312ec52cdd34469758109b0f21 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,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+add_library(simd INTERFACE)
 file(GLOB SIMD_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${SIMD_SOURCES} PARENT_SCOPE)
 
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(simd PUBLIC
+target_include_directories(simd INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(simd PUBLIC
+target_link_libraries(simd INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when simd is an OBJECT target
+#target_link_libraries(simd PUBLIC legacy_api)
+#target_link_libraries(simd PRIVATE common)
+
+# Module dependencies
+# simd interfaces convey transitive dependence on these modules.
+#target_link_libraries(simd PUBLIC
+target_link_libraries(simd INTERFACE
+                      utility
+                      )
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
diff --git a/src/gromacs/simd/impl_arm_neon/impl_arm_neon.h b/src/gromacs/simd/impl_arm_neon/impl_arm_neon.h
deleted file mode 100644 (file)
index 2c4718e..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 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.
- */
-
-#ifndef GMX_SIMD_IMPL_ARM_NEON_H
-#define GMX_SIMD_IMPL_ARM_NEON_H
-
-#include "impl_arm_neon_definitions.h"
-#include "impl_arm_neon_general.h"
-// Arm/Neon cannot do double precision SIMD4
-#include "impl_arm_neon_simd4_float.h"
-// Arm/Neon cannot do double precision SIMD
-#include "impl_arm_neon_simd_float.h"
-// Arm/Neon cannot do double precision SIMD utilities
-#include "impl_arm_neon_util_float.h"
-
-#endif // GMX_SIMD_IMPL_ARM_NEON_H
diff --git a/src/gromacs/simd/impl_arm_neon/impl_arm_neon_definitions.h b/src/gromacs/simd/impl_arm_neon/impl_arm_neon_definitions.h
deleted file mode 100644 (file)
index 5aa27d5..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2017,2018,2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_ARM_NEON_DEFINITIONS_H
-#define GMX_SIMD_IMPL_ARM_NEON_DEFINITIONS_H
-
-#define GMX_SIMD 1
-#define GMX_SIMD_HAVE_FLOAT 1
-#define GMX_SIMD_HAVE_DOUBLE 0
-#define GMX_SIMD_HAVE_LOADU 1
-#define GMX_SIMD_HAVE_STOREU 1
-#define GMX_SIMD_HAVE_LOGICAL 1
-#define GMX_SIMD_HAVE_FMA 1
-#define GMX_SIMD_HAVE_FINT32_EXTRACT 1
-#define GMX_SIMD_HAVE_FINT32_LOGICAL 1
-#define GMX_SIMD_HAVE_FINT32_ARITHMETICS 1
-#define GMX_SIMD_HAVE_DINT32_EXTRACT 0
-#define GMX_SIMD_HAVE_DINT32_LOGICAL 0
-#define GMX_SIMD_HAVE_DINT32_ARITHMETICS 0
-#define GMX_SIMD_HAVE_NATIVE_COPYSIGN_FLOAT 0
-#define GMX_SIMD_HAVE_NATIVE_RSQRT_ITER_FLOAT \
-    0 // Although there is support, it is disabled in GROMACS, because rsqrtIter does not work correctly for inputs near MAX_FLOAT
-#define GMX_SIMD_HAVE_NATIVE_RCP_ITER_FLOAT 1
-#define GMX_SIMD_HAVE_NATIVE_LOG_FLOAT 0
-#define GMX_SIMD_HAVE_NATIVE_EXP2_FLOAT 0
-#define GMX_SIMD_HAVE_NATIVE_EXP_FLOAT 0
-#define GMX_SIMD_HAVE_NATIVE_COPYSIGN_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_RSQRT_ITER_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_RCP_ITER_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_LOG_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_EXP2_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_EXP_DOUBLE 0
-#define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
-#define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 0
-#define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0 // No need for half-simd, width is 4
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 0
-
-#define GMX_SIMD4_HAVE_FLOAT 1
-#define GMX_SIMD4_HAVE_DOUBLE 0
-
-// Implementation details
-#define GMX_SIMD_FLOAT_WIDTH 4
-#undef GMX_SIMD_DOUBLE_WIDTH
-#define GMX_SIMD_FINT32_WIDTH 4
-#undef GMX_SIMD_DINT32_WIDTH
-#define GMX_SIMD4_WIDTH 4
-#define GMX_SIMD_ALIGNMENT 16 // Bytes (4*single)
-#define GMX_SIMD_RSQRT_BITS 8
-#define GMX_SIMD_RCP_BITS 8
-
-#endif // GMX_SIMD_IMPL_ARM_NEON_DEFINITIONS_H
diff --git a/src/gromacs/simd/impl_arm_neon/impl_arm_neon_simd4_float.h b/src/gromacs/simd/impl_arm_neon/impl_arm_neon_simd4_float.h
deleted file mode 100644 (file)
index b947b4b..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2019, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_ARM_NEON_SIMD4_FLOAT_H
-#define GMX_SIMD_IMPL_ARM_NEON_SIMD4_FLOAT_H
-
-#include "config.h"
-
-#include <cassert>
-#include <cstddef>
-
-#include <arm_neon.h>
-
-namespace gmx
-{
-
-class Simd4Float
-{
-public:
-    Simd4Float() {}
-
-    Simd4Float(float f) : simdInternal_(vdupq_n_f32(f)) {}
-
-    // Internal utility constructor to simplify return statements
-    Simd4Float(float32x4_t simd) : simdInternal_(simd) {}
-
-    float32x4_t simdInternal_;
-};
-
-class Simd4FBool
-{
-public:
-    Simd4FBool() {}
-
-    //! \brief Construct from scalar bool
-    Simd4FBool(bool b) : simdInternal_(vdupq_n_u32(b ? 0xFFFFFFFF : 0)) {}
-
-    // Internal utility constructor to simplify return statements
-    Simd4FBool(uint32x4_t simd) : simdInternal_(simd) {}
-
-    uint32x4_t simdInternal_;
-};
-
-static inline Simd4Float gmx_simdcall load4(const float* m)
-{
-    assert(size_t(m) % 16 == 0);
-    return { vld1q_f32(m) };
-}
-
-static inline void gmx_simdcall store4(float* m, Simd4Float a)
-{
-    assert(size_t(m) % 16 == 0);
-    vst1q_f32(m, a.simdInternal_);
-}
-
-static inline Simd4Float gmx_simdcall load4U(const float* m)
-{
-    return { vld1q_f32(m) };
-}
-
-static inline void gmx_simdcall store4U(float* m, Simd4Float a)
-{
-    vst1q_f32(m, a.simdInternal_);
-}
-
-static inline Simd4Float gmx_simdcall simd4SetZeroF()
-{
-    return { vdupq_n_f32(0.0F) };
-}
-
-static inline Simd4Float gmx_simdcall operator&(Simd4Float a, Simd4Float b)
-{
-    return { vreinterpretq_f32_s32(vandq_s32(vreinterpretq_s32_f32(a.simdInternal_),
-                                             vreinterpretq_s32_f32(b.simdInternal_))) };
-}
-
-static inline Simd4Float gmx_simdcall andNot(Simd4Float a, Simd4Float b)
-{
-    return { vreinterpretq_f32_s32(vbicq_s32(vreinterpretq_s32_f32(b.simdInternal_),
-                                             vreinterpretq_s32_f32(a.simdInternal_))) };
-}
-
-static inline Simd4Float gmx_simdcall operator|(Simd4Float a, Simd4Float b)
-{
-    return { vreinterpretq_f32_s32(vorrq_s32(vreinterpretq_s32_f32(a.simdInternal_),
-                                             vreinterpretq_s32_f32(b.simdInternal_))) };
-}
-
-static inline Simd4Float gmx_simdcall operator^(Simd4Float a, Simd4Float b)
-{
-    return { vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(a.simdInternal_),
-                                             vreinterpretq_s32_f32(b.simdInternal_))) };
-}
-
-static inline Simd4Float gmx_simdcall operator+(Simd4Float a, Simd4Float b)
-{
-    return { vaddq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall operator-(Simd4Float a, Simd4Float b)
-{
-    return { vsubq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall operator-(Simd4Float x)
-{
-    return { vnegq_f32(x.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall operator*(Simd4Float a, Simd4Float b)
-{
-    return { vmulq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-// Override for Neon-Asimd
-#if GMX_SIMD_ARM_NEON
-static inline Simd4Float gmx_simdcall fma(Simd4Float a, Simd4Float b, Simd4Float c)
-{
-    return {
-#    ifdef __ARM_FEATURE_FMA
-        vfmaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_)
-#    else
-        vmlaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_)
-#    endif
-    };
-}
-
-static inline Simd4Float gmx_simdcall fms(Simd4Float a, Simd4Float b, Simd4Float c)
-{
-    return {
-#    ifdef __ARM_FEATURE_FMA
-        vnegq_f32(vfmsq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_))
-#    else
-        vnegq_f32(vmlsq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_))
-#    endif
-    };
-}
-
-static inline Simd4Float gmx_simdcall fnma(Simd4Float a, Simd4Float b, Simd4Float c)
-{
-    return {
-#    ifdef __ARM_FEATURE_FMA
-        vfmsq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_)
-#    else
-        vmlsq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_)
-#    endif
-    };
-}
-
-static inline Simd4Float gmx_simdcall fnms(Simd4Float a, Simd4Float b, Simd4Float c)
-{
-    return {
-#    ifdef __ARM_FEATURE_FMA
-        vnegq_f32(vfmaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_))
-#    else
-        vnegq_f32(vmlaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_))
-#    endif
-    };
-}
-#endif
-
-static inline Simd4Float gmx_simdcall rsqrt(Simd4Float x)
-{
-    return { vrsqrteq_f32(x.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall abs(Simd4Float x)
-{
-    return { vabsq_f32(x.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall max(Simd4Float a, Simd4Float b)
-{
-    return { vmaxq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall min(Simd4Float a, Simd4Float b)
-{
-    return { vminq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-// Override for Neon-Asimd
-#if GMX_SIMD_ARM_NEON
-static inline Simd4Float gmx_simdcall round(Simd4Float x)
-{
-    // Convert x to nearest integer
-    float32x4_t signBitOfX = vreinterpretq_f32_u32(
-            vandq_u32(vdupq_n_u32(0x80000000), vreinterpretq_u32_f32(x.simdInternal_)));
-    float32x4_t half = vdupq_n_f32(0.5F);
-    float32x4_t corr = vreinterpretq_f32_u32(
-            vorrq_u32(vreinterpretq_u32_f32(half), vreinterpretq_u32_f32(signBitOfX)));
-
-    int32x4_t integerX = vcvtq_s32_f32(vaddq_f32(x.simdInternal_, corr));
-
-    // Convert back to float
-
-    return { vcvtq_f32_s32(integerX) };
-}
-
-static inline Simd4Float gmx_simdcall trunc(Simd4Float x)
-{
-    return { vcvtq_f32_s32(vcvtq_s32_f32(x.simdInternal_)) };
-}
-#endif
-
-static inline void gmx_simdcall transpose(Simd4Float* v0, Simd4Float* v1, Simd4Float* v2, Simd4Float* v3)
-{
-    float32x4x2_t t0  = vuzpq_f32(v0->simdInternal_, v2->simdInternal_);
-    float32x4x2_t t1  = vuzpq_f32(v1->simdInternal_, v3->simdInternal_);
-    float32x4x2_t t2  = vtrnq_f32(t0.val[0], t1.val[0]);
-    float32x4x2_t t3  = vtrnq_f32(t0.val[1], t1.val[1]);
-    v0->simdInternal_ = t2.val[0];
-    v1->simdInternal_ = t3.val[0];
-    v2->simdInternal_ = t2.val[1];
-    v3->simdInternal_ = t3.val[1];
-}
-
-static inline Simd4FBool gmx_simdcall operator==(Simd4Float a, Simd4Float b)
-{
-    return { vceqq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4FBool gmx_simdcall operator!=(Simd4Float a, Simd4Float b)
-{
-    return { vmvnq_u32(vceqq_f32(a.simdInternal_, b.simdInternal_)) };
-}
-
-static inline Simd4FBool gmx_simdcall operator<(Simd4Float a, Simd4Float b)
-{
-    return { vcltq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4FBool gmx_simdcall operator<=(Simd4Float a, Simd4Float b)
-{
-    return { vcleq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4FBool gmx_simdcall operator&&(Simd4FBool a, Simd4FBool b)
-{
-    return { vandq_u32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4FBool gmx_simdcall operator||(Simd4FBool a, Simd4FBool b)
-{
-    return { vorrq_u32(a.simdInternal_, b.simdInternal_) };
-}
-
-// Override for Neon-Asimd
-#if GMX_SIMD_ARM_NEON
-static inline bool gmx_simdcall anyTrue(Simd4FBool a)
-{
-    uint32x4_t x = a.simdInternal_;
-    uint32x4_t y = vextq_u32(x, x, 2);
-
-    x = vorrq_u32(x, y);
-    y = vextq_u32(x, x, 1);
-    x = vorrq_u32(x, y);
-    return (vgetq_lane_u32(x, 0) != 0);
-}
-#endif
-
-static inline Simd4Float gmx_simdcall selectByMask(Simd4Float a, Simd4FBool m)
-{
-    return { vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(a.simdInternal_), m.simdInternal_)) };
-}
-
-static inline Simd4Float gmx_simdcall selectByNotMask(Simd4Float a, Simd4FBool m)
-{
-    return { vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(a.simdInternal_), m.simdInternal_)) };
-}
-
-static inline Simd4Float gmx_simdcall blend(Simd4Float a, Simd4Float b, Simd4FBool sel)
-{
-    return { vbslq_f32(sel.simdInternal_, b.simdInternal_, a.simdInternal_) };
-}
-
-// Override for Neon-Asimd
-#if GMX_SIMD_ARM_NEON
-static inline float gmx_simdcall reduce(Simd4Float a)
-{
-    float32x4_t x = a.simdInternal_;
-    float32x4_t y = vextq_f32(x, x, 2);
-
-    x = vaddq_f32(x, y);
-    y = vextq_f32(x, x, 1);
-    x = vaddq_f32(x, y);
-    return vgetq_lane_f32(x, 0);
-}
-
-static inline float gmx_simdcall dotProduct(Simd4Float a, Simd4Float b)
-{
-    Simd4Float c;
-
-    c = a * b;
-    /* set 4th element to 0, then add all of them */
-    c.simdInternal_ = vsetq_lane_f32(0.0F, c.simdInternal_, 3);
-    return reduce(c);
-}
-#endif
-
-} // namespace gmx
-
-#endif // GMX_SIMD_IMPL_ARM_NEON_SIMD4_FLOAT_H
diff --git a/src/gromacs/simd/impl_arm_neon/impl_arm_neon_simd_float.h b/src/gromacs/simd/impl_arm_neon/impl_arm_neon_simd_float.h
deleted file mode 100644 (file)
index 6dc9184..0000000
+++ /dev/null
@@ -1,609 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2016,2017,2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_ARM_NEON_SIMD_FLOAT_H
-#define GMX_SIMD_IMPL_ARM_NEON_SIMD_FLOAT_H
-
-#include "config.h"
-
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-
-#include <arm_neon.h>
-
-#include "gromacs/math/utilities.h"
-
-namespace gmx
-{
-
-class SimdFloat
-{
-public:
-    SimdFloat() {}
-
-    SimdFloat(float f) : simdInternal_(vdupq_n_f32(f)) {}
-
-    // Internal utility constructor to simplify return statements
-    SimdFloat(float32x4_t simd) : simdInternal_(simd) {}
-
-    float32x4_t simdInternal_;
-};
-
-class SimdFInt32
-{
-public:
-    SimdFInt32() {}
-
-    SimdFInt32(std::int32_t i) : simdInternal_(vdupq_n_s32(i)) {}
-
-    // Internal utility constructor to simplify return statements
-    SimdFInt32(int32x4_t simd) : simdInternal_(simd) {}
-
-    int32x4_t simdInternal_;
-};
-
-class SimdFBool
-{
-public:
-    SimdFBool() {}
-
-    SimdFBool(bool b) : simdInternal_(vdupq_n_u32(b ? 0xFFFFFFFF : 0)) {}
-
-    // Internal utility constructor to simplify return statements
-    SimdFBool(uint32x4_t simd) : simdInternal_(simd) {}
-
-    uint32x4_t simdInternal_;
-};
-
-class SimdFIBool
-{
-public:
-    SimdFIBool() {}
-
-    SimdFIBool(bool b) : simdInternal_(vdupq_n_u32(b ? 0xFFFFFFFF : 0)) {}
-
-    // Internal utility constructor to simplify return statements
-    SimdFIBool(uint32x4_t simd) : simdInternal_(simd) {}
-
-    uint32x4_t simdInternal_;
-};
-
-static inline SimdFloat gmx_simdcall simdLoad(const float* m, SimdFloatTag = {})
-{
-    assert(std::size_t(m) % 16 == 0);
-    return { vld1q_f32(m) };
-}
-
-static inline void gmx_simdcall store(float* m, SimdFloat a)
-{
-    assert(std::size_t(m) % 16 == 0);
-    vst1q_f32(m, a.simdInternal_);
-}
-
-static inline SimdFloat gmx_simdcall simdLoadU(const float* m, SimdFloatTag = {})
-{
-    return { vld1q_f32(m) };
-}
-
-static inline void gmx_simdcall storeU(float* m, SimdFloat a)
-{
-    vst1q_f32(m, a.simdInternal_);
-}
-
-static inline SimdFloat gmx_simdcall setZeroF()
-{
-    return { vdupq_n_f32(0.0F) };
-}
-
-static inline SimdFInt32 gmx_simdcall simdLoad(const std::int32_t* m, SimdFInt32Tag)
-{
-    assert(std::size_t(m) % 16 == 0);
-    return { vld1q_s32(m) };
-}
-
-static inline void gmx_simdcall store(std::int32_t* m, SimdFInt32 a)
-{
-    assert(std::size_t(m) % 16 == 0);
-    vst1q_s32(m, a.simdInternal_);
-}
-
-static inline SimdFInt32 gmx_simdcall simdLoadU(const std::int32_t* m, SimdFInt32Tag)
-{
-    return { vld1q_s32(m) };
-}
-
-static inline void gmx_simdcall storeU(std::int32_t* m, SimdFInt32 a)
-{
-    vst1q_s32(m, a.simdInternal_);
-}
-
-static inline SimdFInt32 gmx_simdcall setZeroFI()
-{
-    return { vdupq_n_s32(0) };
-}
-
-template<int index>
-gmx_simdcall static inline std::int32_t extract(SimdFInt32 a)
-{
-    return vgetq_lane_s32(a.simdInternal_, index);
-}
-
-static inline SimdFloat gmx_simdcall operator&(SimdFloat a, SimdFloat b)
-{
-    return { vreinterpretq_f32_s32(vandq_s32(vreinterpretq_s32_f32(a.simdInternal_),
-                                             vreinterpretq_s32_f32(b.simdInternal_))) };
-}
-
-static inline SimdFloat gmx_simdcall andNot(SimdFloat a, SimdFloat b)
-{
-    return { vreinterpretq_f32_s32(vbicq_s32(vreinterpretq_s32_f32(b.simdInternal_),
-                                             vreinterpretq_s32_f32(a.simdInternal_))) };
-}
-
-static inline SimdFloat gmx_simdcall operator|(SimdFloat a, SimdFloat b)
-{
-    return { vreinterpretq_f32_s32(vorrq_s32(vreinterpretq_s32_f32(a.simdInternal_),
-                                             vreinterpretq_s32_f32(b.simdInternal_))) };
-}
-
-static inline SimdFloat gmx_simdcall operator^(SimdFloat a, SimdFloat b)
-{
-    return { vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(a.simdInternal_),
-                                             vreinterpretq_s32_f32(b.simdInternal_))) };
-}
-
-static inline SimdFloat gmx_simdcall operator+(SimdFloat a, SimdFloat b)
-{
-    return { vaddq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall operator-(SimdFloat a, SimdFloat b)
-{
-    return { vsubq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall operator-(SimdFloat x)
-{
-    return { vnegq_f32(x.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall operator*(SimdFloat a, SimdFloat b)
-{
-    return { vmulq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-// Override for Neon-Asimd
-#if GMX_SIMD_ARM_NEON
-static inline SimdFloat gmx_simdcall fma(SimdFloat a, SimdFloat b, SimdFloat c)
-{
-    return {
-#    ifdef __ARM_FEATURE_FMA
-        vfmaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_)
-#    else
-        vmlaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_)
-#    endif
-    };
-}
-
-static inline SimdFloat gmx_simdcall fms(SimdFloat a, SimdFloat b, SimdFloat c)
-{
-    return {
-#    ifdef __ARM_FEATURE_FMA
-        vnegq_f32(vfmsq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_))
-#    else
-        vnegq_f32(vmlsq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_))
-#    endif
-    };
-}
-
-static inline SimdFloat gmx_simdcall fnma(SimdFloat a, SimdFloat b, SimdFloat c)
-{
-    return {
-#    ifdef __ARM_FEATURE_FMA
-        vfmsq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_)
-#    else
-        vmlsq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_)
-#    endif
-    };
-}
-
-static inline SimdFloat gmx_simdcall fnms(SimdFloat a, SimdFloat b, SimdFloat c)
-{
-    return {
-#    ifdef __ARM_FEATURE_FMA
-        vnegq_f32(vfmaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_))
-#    else
-        vnegq_f32(vmlaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_))
-#    endif
-    };
-}
-#endif
-
-static inline SimdFloat gmx_simdcall rsqrt(SimdFloat x)
-{
-    return { vrsqrteq_f32(x.simdInternal_) };
-}
-
-// The SIMD implementation seems to overflow when we square lu for
-// values close to FLOAT_MAX, so we fall back on the version in
-// simd_math.h, which is probably slightly slower.
-#if GMX_SIMD_HAVE_NATIVE_RSQRT_ITER_FLOAT
-static inline SimdFloat gmx_simdcall rsqrtIter(SimdFloat lu, SimdFloat x)
-{
-    return { vmulq_f32(lu.simdInternal_,
-                       vrsqrtsq_f32(vmulq_f32(lu.simdInternal_, lu.simdInternal_), x.simdInternal_)) };
-}
-#endif
-
-static inline SimdFloat gmx_simdcall rcp(SimdFloat x)
-{
-    return { vrecpeq_f32(x.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall rcpIter(SimdFloat lu, SimdFloat x)
-{
-    return { vmulq_f32(lu.simdInternal_, vrecpsq_f32(lu.simdInternal_, x.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall maskAdd(SimdFloat a, SimdFloat b, SimdFBool m)
-{
-    b.simdInternal_ =
-            vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(b.simdInternal_), m.simdInternal_));
-
-    return { vaddq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall maskzMul(SimdFloat a, SimdFloat b, SimdFBool m)
-{
-    SimdFloat tmp = a * b;
-
-    return { vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(tmp.simdInternal_), m.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall maskzFma(SimdFloat a, SimdFloat b, SimdFloat c, SimdFBool m)
-{
-#ifdef __ARM_FEATURE_FMA
-    float32x4_t tmp = vfmaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_);
-#else
-    float32x4_t tmp = vmlaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_);
-#endif
-
-    return { vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(tmp), m.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall maskzRsqrt(SimdFloat x, SimdFBool m)
-{
-    // The result will always be correct since we mask the result with m, but
-    // for debug builds we also want to make sure not to generate FP exceptions
-#ifndef NDEBUG
-    x.simdInternal_ = vbslq_f32(m.simdInternal_, x.simdInternal_, vdupq_n_f32(1.0F));
-#endif
-    return { vreinterpretq_f32_u32(
-            vandq_u32(vreinterpretq_u32_f32(vrsqrteq_f32(x.simdInternal_)), m.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall maskzRcp(SimdFloat x, SimdFBool m)
-{
-    // The result will always be correct since we mask the result with m, but
-    // for debug builds we also want to make sure not to generate FP exceptions
-#ifndef NDEBUG
-    x.simdInternal_ = vbslq_f32(m.simdInternal_, x.simdInternal_, vdupq_n_f32(1.0F));
-#endif
-    return { vreinterpretq_f32_u32(
-            vandq_u32(vreinterpretq_u32_f32(vrecpeq_f32(x.simdInternal_)), m.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall abs(SimdFloat x)
-{
-    return { vabsq_f32(x.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall max(SimdFloat a, SimdFloat b)
-{
-    return { vmaxq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall min(SimdFloat a, SimdFloat b)
-{
-    return { vminq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-// Round and trunc operations are defined at the end of this file, since they
-// need to use float-to-integer and integer-to-float conversions.
-
-template<MathOptimization opt = MathOptimization::Safe>
-static inline SimdFloat gmx_simdcall frexp(SimdFloat value, SimdFInt32* exponent)
-{
-    const int32x4_t exponentMask = vdupq_n_s32(0x7F800000);
-    const int32x4_t mantissaMask = vdupq_n_s32(0x807FFFFF);
-    const int32x4_t exponentBias = vdupq_n_s32(126); // add 1 to make our definition identical to frexp()
-    const float32x4_t half = vdupq_n_f32(0.5F);
-    int32x4_t         iExponent;
-
-    iExponent = vandq_s32(vreinterpretq_s32_f32(value.simdInternal_), exponentMask);
-    iExponent = vsubq_s32(vshrq_n_s32(iExponent, 23), exponentBias);
-
-    float32x4_t result = vreinterpretq_f32_s32(
-            vorrq_s32(vandq_s32(vreinterpretq_s32_f32(value.simdInternal_), mantissaMask),
-                      vreinterpretq_s32_f32(half)));
-
-    if (opt == MathOptimization::Safe)
-    {
-        uint32x4_t valueIsZero = vceqq_f32(value.simdInternal_, vdupq_n_f32(0.0F));
-        iExponent              = vbicq_s32(iExponent, vreinterpretq_s32_u32(valueIsZero));
-        result                 = vbslq_f32(valueIsZero, value.simdInternal_, result);
-    }
-
-    exponent->simdInternal_ = iExponent;
-    return { result };
-}
-
-template<MathOptimization opt = MathOptimization::Safe>
-static inline SimdFloat gmx_simdcall ldexp(SimdFloat value, SimdFInt32 exponent)
-{
-    const int32x4_t exponentBias = vdupq_n_s32(127);
-    int32x4_t       iExponent    = vaddq_s32(exponent.simdInternal_, exponentBias);
-
-    if (opt == MathOptimization::Safe)
-    {
-        // Make sure biased argument is not negative
-        iExponent = vmaxq_s32(iExponent, vdupq_n_s32(0));
-    }
-
-    iExponent = vshlq_n_s32(iExponent, 23);
-
-    return { vmulq_f32(value.simdInternal_, vreinterpretq_f32_s32(iExponent)) };
-}
-
-// Override for Neon-Asimd
-#if GMX_SIMD_ARM_NEON
-static inline float gmx_simdcall reduce(SimdFloat a)
-{
-    float32x4_t x = a.simdInternal_;
-    float32x4_t y = vextq_f32(x, x, 2);
-
-    x = vaddq_f32(x, y);
-    y = vextq_f32(x, x, 1);
-    x = vaddq_f32(x, y);
-    return vgetq_lane_f32(x, 0);
-}
-#endif
-
-static inline SimdFBool gmx_simdcall operator==(SimdFloat a, SimdFloat b)
-{
-    return { vceqq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFBool gmx_simdcall operator!=(SimdFloat a, SimdFloat b)
-{
-    return { vmvnq_u32(vceqq_f32(a.simdInternal_, b.simdInternal_)) };
-}
-
-static inline SimdFBool gmx_simdcall operator<(SimdFloat a, SimdFloat b)
-{
-    return { vcltq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFBool gmx_simdcall operator<=(SimdFloat a, SimdFloat b)
-{
-    return { vcleq_f32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFBool gmx_simdcall testBits(SimdFloat a)
-{
-    uint32x4_t tmp = vreinterpretq_u32_f32(a.simdInternal_);
-
-    return { vtstq_u32(tmp, tmp) };
-}
-
-static inline SimdFBool gmx_simdcall operator&&(SimdFBool a, SimdFBool b)
-{
-
-    return { vandq_u32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFBool gmx_simdcall operator||(SimdFBool a, SimdFBool b)
-{
-    return { vorrq_u32(a.simdInternal_, b.simdInternal_) };
-}
-
-// Override for Neon-Asimd
-#if GMX_SIMD_ARM_NEON
-static inline bool gmx_simdcall anyTrue(SimdFBool a)
-{
-    uint32x4_t x = a.simdInternal_;
-    uint32x4_t y = vextq_u32(x, x, 2);
-
-    x = vorrq_u32(x, y);
-    y = vextq_u32(x, x, 1);
-    x = vorrq_u32(x, y);
-    return (vgetq_lane_u32(x, 0) != 0);
-}
-#endif
-
-static inline SimdFloat gmx_simdcall selectByMask(SimdFloat a, SimdFBool m)
-{
-    return { vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(a.simdInternal_), m.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall selectByNotMask(SimdFloat a, SimdFBool m)
-{
-    return { vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(a.simdInternal_), m.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall blend(SimdFloat a, SimdFloat b, SimdFBool sel)
-{
-    return { vbslq_f32(sel.simdInternal_, b.simdInternal_, a.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator&(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vandq_s32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall andNot(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vbicq_s32(b.simdInternal_, a.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator|(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vorrq_s32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator^(SimdFInt32 a, SimdFInt32 b)
-{
-    return { veorq_s32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator+(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vaddq_s32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator-(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vsubq_s32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator*(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vmulq_s32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFIBool gmx_simdcall operator==(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vceqq_s32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFIBool gmx_simdcall testBits(SimdFInt32 a)
-{
-    return { vtstq_s32(a.simdInternal_, a.simdInternal_) };
-}
-
-static inline SimdFIBool gmx_simdcall operator<(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vcltq_s32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFIBool gmx_simdcall operator&&(SimdFIBool a, SimdFIBool b)
-{
-    return { vandq_u32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFIBool gmx_simdcall operator||(SimdFIBool a, SimdFIBool b)
-{
-    return { vorrq_u32(a.simdInternal_, b.simdInternal_) };
-}
-
-// Override for Neon-Asimd
-#if GMX_SIMD_ARM_NEON
-static inline bool gmx_simdcall anyTrue(SimdFIBool a)
-{
-    uint32x4_t x = a.simdInternal_;
-    uint32x4_t y = vextq_u32(x, x, 2);
-
-    x = vorrq_u32(x, y);
-    y = vextq_u32(x, x, 1);
-    x = vorrq_u32(x, y);
-    return (vgetq_lane_u32(x, 0) != 0);
-}
-#endif
-
-static inline SimdFInt32 gmx_simdcall selectByMask(SimdFInt32 a, SimdFIBool m)
-{
-    return { vandq_s32(a.simdInternal_, vreinterpretq_s32_u32(m.simdInternal_)) };
-}
-
-static inline SimdFInt32 gmx_simdcall selectByNotMask(SimdFInt32 a, SimdFIBool m)
-{
-    return { vbicq_s32(a.simdInternal_, vreinterpretq_s32_u32(m.simdInternal_)) };
-}
-
-static inline SimdFInt32 gmx_simdcall blend(SimdFInt32 a, SimdFInt32 b, SimdFIBool sel)
-{
-    return { vbslq_s32(sel.simdInternal_, b.simdInternal_, a.simdInternal_) };
-}
-
-// Override for Neon-Asimd
-#if GMX_SIMD_ARM_NEON
-static inline SimdFInt32 gmx_simdcall cvtR2I(SimdFloat a)
-{
-    float32x4_t signBitOfA = vreinterpretq_f32_u32(
-            vandq_u32(vdupq_n_u32(0x80000000), vreinterpretq_u32_f32(a.simdInternal_)));
-    float32x4_t half = vdupq_n_f32(0.5F);
-    float32x4_t corr = vreinterpretq_f32_u32(
-            vorrq_u32(vreinterpretq_u32_f32(half), vreinterpretq_u32_f32(signBitOfA)));
-
-    return { vcvtq_s32_f32(vaddq_f32(a.simdInternal_, corr)) };
-}
-#endif
-
-static inline SimdFInt32 gmx_simdcall cvttR2I(SimdFloat a)
-{
-    return { vcvtq_s32_f32(a.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall cvtI2R(SimdFInt32 a)
-{
-    return { vcvtq_f32_s32(a.simdInternal_) };
-}
-
-static inline SimdFIBool gmx_simdcall cvtB2IB(SimdFBool a)
-{
-    return { a.simdInternal_ };
-}
-
-static inline SimdFBool gmx_simdcall cvtIB2B(SimdFIBool a)
-{
-    return { a.simdInternal_ };
-}
-
-// Override for Neon-Asimd
-#if GMX_SIMD_ARM_NEON
-static inline SimdFloat gmx_simdcall round(SimdFloat x)
-{
-    return cvtI2R(cvtR2I(x));
-}
-
-static inline SimdFloat gmx_simdcall trunc(SimdFloat x)
-{
-    return cvtI2R(cvttR2I(x));
-}
-#endif
-
-} // namespace gmx
-
-#endif // GMX_SIMD_IMPL_ARM_NEON_SIMD_FLOAT_H
diff --git a/src/gromacs/simd/impl_arm_neon/impl_arm_neon_util_float.h b/src/gromacs/simd/impl_arm_neon/impl_arm_neon_util_float.h
deleted file mode 100644 (file)
index 1834805..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_ARM_NEON_UTIL_FLOAT_H
-#define GMX_SIMD_IMPL_ARM_NEON_UTIL_FLOAT_H
-
-#include "config.h"
-
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-
-#include <arm_neon.h>
-
-#include "gromacs/utility/basedefinitions.h"
-
-#include "impl_arm_neon_simd_float.h"
-
-
-namespace gmx
-{
-
-template<int align>
-static inline void gmx_simdcall gatherLoadTranspose(const float*       base,
-                                                    const std::int32_t offset[],
-                                                    SimdFloat*         v0,
-                                                    SimdFloat*         v1,
-                                                    SimdFloat*         v2,
-                                                    SimdFloat*         v3)
-{
-    assert(std::size_t(offset) % 16 == 0);
-    assert(std::size_t(base) % 16 == 0);
-    assert(align % 4 == 0);
-
-    // Unfortunately we cannot use the beautiful Neon structured load
-    // instructions since the data comes from four different memory locations.
-    float32x4x2_t t0 =
-            vuzpq_f32(vld1q_f32(base + align * offset[0]), vld1q_f32(base + align * offset[2]));
-    float32x4x2_t t1 =
-            vuzpq_f32(vld1q_f32(base + align * offset[1]), vld1q_f32(base + align * offset[3]));
-    float32x4x2_t t2  = vtrnq_f32(t0.val[0], t1.val[0]);
-    float32x4x2_t t3  = vtrnq_f32(t0.val[1], t1.val[1]);
-    v0->simdInternal_ = t2.val[0];
-    v1->simdInternal_ = t3.val[0];
-    v2->simdInternal_ = t2.val[1];
-    v3->simdInternal_ = t3.val[1];
-}
-
-template<int align>
-static inline void gmx_simdcall
-                   gatherLoadTranspose(const float* base, const std::int32_t offset[], SimdFloat* v0, SimdFloat* v1)
-{
-    assert(std::size_t(offset) % 16 == 0);
-    assert(std::size_t(base) % 8 == 0);
-    assert(align % 2 == 0);
-
-    v0->simdInternal_ =
-            vcombine_f32(vld1_f32(base + align * offset[0]), vld1_f32(base + align * offset[2]));
-    v1->simdInternal_ =
-            vcombine_f32(vld1_f32(base + align * offset[1]), vld1_f32(base + align * offset[3]));
-
-    float32x4x2_t tmp = vtrnq_f32(v0->simdInternal_, v1->simdInternal_);
-
-    v0->simdInternal_ = tmp.val[0];
-    v1->simdInternal_ = tmp.val[1];
-}
-
-static const int c_simdBestPairAlignmentFloat = 2;
-
-template<int align>
-static inline void gmx_simdcall gatherLoadUTranspose(const float*       base,
-                                                     const std::int32_t offset[],
-                                                     SimdFloat*         v0,
-                                                     SimdFloat*         v1,
-                                                     SimdFloat*         v2)
-{
-    assert(std::size_t(offset) % 16 == 0);
-
-    float32x4x2_t t0 =
-            vuzpq_f32(vld1q_f32(base + align * offset[0]), vld1q_f32(base + align * offset[2]));
-    float32x4x2_t t1 =
-            vuzpq_f32(vld1q_f32(base + align * offset[1]), vld1q_f32(base + align * offset[3]));
-    float32x4x2_t t2  = vtrnq_f32(t0.val[0], t1.val[0]);
-    float32x4x2_t t3  = vtrnq_f32(t0.val[1], t1.val[1]);
-    v0->simdInternal_ = t2.val[0];
-    v1->simdInternal_ = t3.val[0];
-    v2->simdInternal_ = t2.val[1];
-}
-
-
-template<int align>
-static inline void gmx_simdcall
-                   transposeScatterStoreU(float* base, const std::int32_t offset[], SimdFloat v0, SimdFloat v1, SimdFloat v2)
-{
-    assert(std::size_t(offset) % 16 == 0);
-
-    float32x4x2_t tmp = vtrnq_f32(v0.simdInternal_, v1.simdInternal_);
-
-    vst1_f32(base + align * offset[0], vget_low_f32(tmp.val[0]));
-    vst1_f32(base + align * offset[1], vget_low_f32(tmp.val[1]));
-    vst1_f32(base + align * offset[2], vget_high_f32(tmp.val[0]));
-    vst1_f32(base + align * offset[3], vget_high_f32(tmp.val[1]));
-
-    vst1q_lane_f32(base + align * offset[0] + 2, v2.simdInternal_, 0);
-    vst1q_lane_f32(base + align * offset[1] + 2, v2.simdInternal_, 1);
-    vst1q_lane_f32(base + align * offset[2] + 2, v2.simdInternal_, 2);
-    vst1q_lane_f32(base + align * offset[3] + 2, v2.simdInternal_, 3);
-}
-
-
-template<int align>
-static inline void gmx_simdcall
-                   transposeScatterIncrU(float* base, const std::int32_t offset[], SimdFloat v0, SimdFloat v1, SimdFloat v2)
-{
-    assert(std::size_t(offset) % 16 == 0);
-
-    if (align < 4)
-    {
-        float32x2_t   t0, t1, t2, t3;
-        float32x4x2_t tmp = vtrnq_f32(v0.simdInternal_, v1.simdInternal_);
-
-        t0 = vget_low_f32(tmp.val[0]);
-        t1 = vget_low_f32(tmp.val[1]);
-        t2 = vget_high_f32(tmp.val[0]);
-        t3 = vget_high_f32(tmp.val[1]);
-
-        t0 = vadd_f32(t0, vld1_f32(base + align * offset[0]));
-        vst1_f32(base + align * offset[0], t0);
-        base[align * offset[0] + 2] += vgetq_lane_f32(v2.simdInternal_, 0);
-
-        t1 = vadd_f32(t1, vld1_f32(base + align * offset[1]));
-        vst1_f32(base + align * offset[1], t1);
-        base[align * offset[1] + 2] += vgetq_lane_f32(v2.simdInternal_, 1);
-
-        t2 = vadd_f32(t2, vld1_f32(base + align * offset[2]));
-        vst1_f32(base + align * offset[2], t2);
-        base[align * offset[2] + 2] += vgetq_lane_f32(v2.simdInternal_, 2);
-
-        t3 = vadd_f32(t3, vld1_f32(base + align * offset[3]));
-        vst1_f32(base + align * offset[3], t3);
-        base[align * offset[3] + 2] += vgetq_lane_f32(v2.simdInternal_, 3);
-    }
-    else
-    {
-        // Extra elements means we can use full width-4 load/store operations
-        float32x4x2_t t0 = vuzpq_f32(v0.simdInternal_, v2.simdInternal_);
-        float32x4x2_t t1 = vuzpq_f32(v1.simdInternal_, vdupq_n_f32(0.0F));
-        float32x4x2_t t2 = vtrnq_f32(t0.val[0], t1.val[0]);
-        float32x4x2_t t3 = vtrnq_f32(t0.val[1], t1.val[1]);
-        float32x4_t   t4 = t2.val[0];
-        float32x4_t   t5 = t3.val[0];
-        float32x4_t   t6 = t2.val[1];
-        float32x4_t   t7 = t3.val[1];
-
-        vst1q_f32(base + align * offset[0], vaddq_f32(t4, vld1q_f32(base + align * offset[0])));
-        vst1q_f32(base + align * offset[1], vaddq_f32(t5, vld1q_f32(base + align * offset[1])));
-        vst1q_f32(base + align * offset[2], vaddq_f32(t6, vld1q_f32(base + align * offset[2])));
-        vst1q_f32(base + align * offset[3], vaddq_f32(t7, vld1q_f32(base + align * offset[3])));
-    }
-}
-
-template<int align>
-static inline void gmx_simdcall
-                   transposeScatterDecrU(float* base, const std::int32_t offset[], SimdFloat v0, SimdFloat v1, SimdFloat v2)
-{
-    assert(std::size_t(offset) % 16 == 0);
-
-    if (align < 4)
-    {
-        float32x2_t   t0, t1, t2, t3;
-        float32x4x2_t tmp = vtrnq_f32(v0.simdInternal_, v1.simdInternal_);
-
-        t0 = vget_low_f32(tmp.val[0]);
-        t1 = vget_low_f32(tmp.val[1]);
-        t2 = vget_high_f32(tmp.val[0]);
-        t3 = vget_high_f32(tmp.val[1]);
-
-        t0 = vsub_f32(vld1_f32(base + align * offset[0]), t0);
-        vst1_f32(base + align * offset[0], t0);
-        base[align * offset[0] + 2] -= vgetq_lane_f32(v2.simdInternal_, 0);
-
-        t1 = vsub_f32(vld1_f32(base + align * offset[1]), t1);
-        vst1_f32(base + align * offset[1], t1);
-        base[align * offset[1] + 2] -= vgetq_lane_f32(v2.simdInternal_, 1);
-
-        t2 = vsub_f32(vld1_f32(base + align * offset[2]), t2);
-        vst1_f32(base + align * offset[2], t2);
-        base[align * offset[2] + 2] -= vgetq_lane_f32(v2.simdInternal_, 2);
-
-        t3 = vsub_f32(vld1_f32(base + align * offset[3]), t3);
-        vst1_f32(base + align * offset[3], t3);
-        base[align * offset[3] + 2] -= vgetq_lane_f32(v2.simdInternal_, 3);
-    }
-    else
-    {
-        // Extra elements means we can use full width-4 load/store operations
-        float32x4x2_t t0 = vuzpq_f32(v0.simdInternal_, v2.simdInternal_);
-        float32x4x2_t t1 = vuzpq_f32(v1.simdInternal_, vdupq_n_f32(0.0F));
-        float32x4x2_t t2 = vtrnq_f32(t0.val[0], t1.val[0]);
-        float32x4x2_t t3 = vtrnq_f32(t0.val[1], t1.val[1]);
-        float32x4_t   t4 = t2.val[0];
-        float32x4_t   t5 = t3.val[0];
-        float32x4_t   t6 = t2.val[1];
-        float32x4_t   t7 = t3.val[1];
-
-        vst1q_f32(base + align * offset[0], vsubq_f32(vld1q_f32(base + align * offset[0]), t4));
-        vst1q_f32(base + align * offset[1], vsubq_f32(vld1q_f32(base + align * offset[1]), t5));
-        vst1q_f32(base + align * offset[2], vsubq_f32(vld1q_f32(base + align * offset[2]), t6));
-        vst1q_f32(base + align * offset[3], vsubq_f32(vld1q_f32(base + align * offset[3]), t7));
-    }
-}
-
-static inline void gmx_simdcall expandScalarsToTriplets(SimdFloat  scalar,
-                                                        SimdFloat* triplets0,
-                                                        SimdFloat* triplets1,
-                                                        SimdFloat* triplets2)
-{
-    float32x2_t lo, hi;
-    float32x4_t t0, t1, t2, t3;
-
-    lo = vget_low_f32(scalar.simdInternal_);
-    hi = vget_high_f32(scalar.simdInternal_);
-
-    t0 = vdupq_lane_f32(lo, 0);
-    t1 = vdupq_lane_f32(lo, 1);
-    t2 = vdupq_lane_f32(hi, 0);
-    t3 = vdupq_lane_f32(hi, 1);
-
-    triplets0->simdInternal_ = vextq_f32(t0, t1, 1);
-    triplets1->simdInternal_ = vextq_f32(t1, t2, 2);
-    triplets2->simdInternal_ = vextq_f32(t2, t3, 3);
-}
-
-
-template<int align>
-static inline void gmx_simdcall gatherLoadBySimdIntTranspose(const float* base,
-                                                             SimdFInt32   offset,
-                                                             SimdFloat*   v0,
-                                                             SimdFloat*   v1,
-                                                             SimdFloat*   v2,
-                                                             SimdFloat*   v3)
-{
-    alignas(GMX_SIMD_ALIGNMENT) std::int32_t ioffset[GMX_SIMD_FINT32_WIDTH];
-
-    assert(std::size_t(base) % 16 == 0);
-    assert(align % 4 == 0);
-
-    store(ioffset, offset);
-    gatherLoadTranspose<align>(base, ioffset, v0, v1, v2, v3);
-}
-
-template<int align>
-static inline void gmx_simdcall
-                   gatherLoadBySimdIntTranspose(const float* base, SimdFInt32 offset, SimdFloat* v0, SimdFloat* v1)
-{
-    alignas(GMX_SIMD_ALIGNMENT) std::int32_t ioffset[GMX_SIMD_FINT32_WIDTH];
-
-    store(ioffset, offset);
-    gatherLoadTranspose<align>(base, ioffset, v0, v1);
-}
-
-
-template<int align>
-static inline void gmx_simdcall
-                   gatherLoadUBySimdIntTranspose(const float* base, SimdFInt32 offset, SimdFloat* v0, SimdFloat* v1)
-{
-    alignas(GMX_SIMD_ALIGNMENT) std::int32_t ioffset[GMX_SIMD_FINT32_WIDTH];
-
-    store(ioffset, offset);
-    v0->simdInternal_ =
-            vcombine_f32(vld1_f32(base + align * ioffset[0]), vld1_f32(base + align * ioffset[2]));
-    v1->simdInternal_ =
-            vcombine_f32(vld1_f32(base + align * ioffset[1]), vld1_f32(base + align * ioffset[3]));
-    float32x4x2_t tmp = vtrnq_f32(v0->simdInternal_, v1->simdInternal_);
-    v0->simdInternal_ = tmp.val[0];
-    v1->simdInternal_ = tmp.val[1];
-}
-
-static inline float gmx_simdcall reduceIncr4ReturnSum(float* m, SimdFloat v0, SimdFloat v1, SimdFloat v2, SimdFloat v3)
-{
-    assert(std::size_t(m) % 16 == 0);
-
-    float32x4x2_t t0 = vuzpq_f32(v0.simdInternal_, v2.simdInternal_);
-    float32x4x2_t t1 = vuzpq_f32(v1.simdInternal_, v3.simdInternal_);
-    float32x4x2_t t2 = vtrnq_f32(t0.val[0], t1.val[0]);
-    float32x4x2_t t3 = vtrnq_f32(t0.val[1], t1.val[1]);
-    v0.simdInternal_ = t2.val[0];
-    v1.simdInternal_ = t3.val[0];
-    v2.simdInternal_ = t2.val[1];
-    v3.simdInternal_ = t3.val[1];
-
-    v0 = v0 + v1;
-    v2 = v2 + v3;
-    v0 = v0 + v2;
-    v2 = v0 + simdLoad(m);
-    store(m, v2);
-
-    return reduce(v0);
-}
-
-} // namespace gmx
-
-#endif // GMX_SIMD_IMPL_ARM_NEON_UTIL_FLOAT_H
index 2b7162367d1bccf797478b18e248beaf48c1e1ec..d08a00a0ad4524c2b763296b227a7c2bf24b858b 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,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_ARM_NEON_ASIMD_GENERAL_H
 #define GMX_SIMD_IMPL_ARM_NEON_ASIMD_GENERAL_H
 
-#include "gromacs/simd/impl_arm_neon/impl_arm_neon_general.h"
+namespace gmx
+{
+
+static inline void simdPrefetch(void* m)
+{
+#ifdef __GNUC__
+    __builtin_prefetch(m);
+#endif
+}
+
+} // namespace gmx
 
 #endif // GMX_SIMD_IMPL_ARM_NEON_ASIMD_GENERAL_H
index d77d4a2f307b56147b3db248a8e515be075fa710..f23c7d8ed339ef2bad52a3866abac4f683c789d0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_ARM_NEON_ASIMD_SIMD4_FLOAT_H
 #define GMX_SIMD_IMPL_ARM_NEON_ASIMD_SIMD4_FLOAT_H
 
 #include "config.h"
 
-#include <arm_neon.h>
+#include <cassert>
+#include <cstddef>
 
-#include "gromacs/simd/impl_arm_neon/impl_arm_neon_simd4_float.h"
+#include <arm_neon.h>
 
 namespace gmx
 {
 
+class Simd4Float
+{
+public:
+    Simd4Float() {}
+
+    Simd4Float(float f) : simdInternal_(vdupq_n_f32(f)) {}
+
+    // Internal utility constructor to simplify return statements
+    Simd4Float(float32x4_t simd) : simdInternal_(simd) {}
+
+    float32x4_t simdInternal_;
+};
+
+class Simd4FBool
+{
+public:
+    Simd4FBool() {}
+
+    //! \brief Construct from scalar bool
+    Simd4FBool(bool b) : simdInternal_(vdupq_n_u32(b ? 0xFFFFFFFF : 0)) {}
+
+    // Internal utility constructor to simplify return statements
+    Simd4FBool(uint32x4_t simd) : simdInternal_(simd) {}
+
+    uint32x4_t simdInternal_;
+};
+
+static inline Simd4Float gmx_simdcall load4(const float* m)
+{
+    assert(size_t(m) % 16 == 0);
+    return { vld1q_f32(m) };
+}
+
+static inline void gmx_simdcall store4(float* m, Simd4Float a)
+{
+    assert(size_t(m) % 16 == 0);
+    vst1q_f32(m, a.simdInternal_);
+}
+
+static inline Simd4Float gmx_simdcall load4U(const float* m)
+{
+    return { vld1q_f32(m) };
+}
+
+static inline void gmx_simdcall store4U(float* m, Simd4Float a)
+{
+    vst1q_f32(m, a.simdInternal_);
+}
+
+static inline Simd4Float gmx_simdcall simd4SetZeroF()
+{
+    return { vdupq_n_f32(0.0F) };
+}
+
+static inline Simd4Float gmx_simdcall operator&(Simd4Float a, Simd4Float b)
+{
+    return { vreinterpretq_f32_s32(vandq_s32(vreinterpretq_s32_f32(a.simdInternal_),
+                                             vreinterpretq_s32_f32(b.simdInternal_))) };
+}
+
+static inline Simd4Float gmx_simdcall andNot(Simd4Float a, Simd4Float b)
+{
+    return { vreinterpretq_f32_s32(vbicq_s32(vreinterpretq_s32_f32(b.simdInternal_),
+                                             vreinterpretq_s32_f32(a.simdInternal_))) };
+}
+
+static inline Simd4Float gmx_simdcall operator|(Simd4Float a, Simd4Float b)
+{
+    return { vreinterpretq_f32_s32(vorrq_s32(vreinterpretq_s32_f32(a.simdInternal_),
+                                             vreinterpretq_s32_f32(b.simdInternal_))) };
+}
+
+static inline Simd4Float gmx_simdcall operator^(Simd4Float a, Simd4Float b)
+{
+    return { vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(a.simdInternal_),
+                                             vreinterpretq_s32_f32(b.simdInternal_))) };
+}
+
+static inline Simd4Float gmx_simdcall operator+(Simd4Float a, Simd4Float b)
+{
+    return { vaddq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline Simd4Float gmx_simdcall operator-(Simd4Float a, Simd4Float b)
+{
+    return { vsubq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline Simd4Float gmx_simdcall operator-(Simd4Float x)
+{
+    return { vnegq_f32(x.simdInternal_) };
+}
+
+static inline Simd4Float gmx_simdcall operator*(Simd4Float a, Simd4Float b)
+{
+    return { vmulq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline Simd4Float gmx_simdcall rsqrt(Simd4Float x)
+{
+    return { vrsqrteq_f32(x.simdInternal_) };
+}
+
+static inline Simd4Float gmx_simdcall abs(Simd4Float x)
+{
+    return { vabsq_f32(x.simdInternal_) };
+}
+
+static inline Simd4Float gmx_simdcall max(Simd4Float a, Simd4Float b)
+{
+    return { vmaxq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline Simd4Float gmx_simdcall min(Simd4Float a, Simd4Float b)
+{
+    return { vminq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline void gmx_simdcall transpose(Simd4Float* v0, Simd4Float* v1, Simd4Float* v2, Simd4Float* v3)
+{
+    float32x4x2_t t0  = vuzpq_f32(v0->simdInternal_, v2->simdInternal_);
+    float32x4x2_t t1  = vuzpq_f32(v1->simdInternal_, v3->simdInternal_);
+    float32x4x2_t t2  = vtrnq_f32(t0.val[0], t1.val[0]);
+    float32x4x2_t t3  = vtrnq_f32(t0.val[1], t1.val[1]);
+    v0->simdInternal_ = t2.val[0];
+    v1->simdInternal_ = t3.val[0];
+    v2->simdInternal_ = t2.val[1];
+    v3->simdInternal_ = t3.val[1];
+}
+
+static inline Simd4FBool gmx_simdcall operator==(Simd4Float a, Simd4Float b)
+{
+    return { vceqq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline Simd4FBool gmx_simdcall operator!=(Simd4Float a, Simd4Float b)
+{
+    return { vmvnq_u32(vceqq_f32(a.simdInternal_, b.simdInternal_)) };
+}
+
+static inline Simd4FBool gmx_simdcall operator<(Simd4Float a, Simd4Float b)
+{
+    return { vcltq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline Simd4FBool gmx_simdcall operator<=(Simd4Float a, Simd4Float b)
+{
+    return { vcleq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline Simd4FBool gmx_simdcall operator&&(Simd4FBool a, Simd4FBool b)
+{
+    return { vandq_u32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline Simd4FBool gmx_simdcall operator||(Simd4FBool a, Simd4FBool b)
+{
+    return { vorrq_u32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline Simd4Float gmx_simdcall selectByMask(Simd4Float a, Simd4FBool m)
+{
+    return { vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(a.simdInternal_), m.simdInternal_)) };
+}
+
+static inline Simd4Float gmx_simdcall selectByNotMask(Simd4Float a, Simd4FBool m)
+{
+    return { vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(a.simdInternal_), m.simdInternal_)) };
+}
+
+static inline Simd4Float gmx_simdcall blend(Simd4Float a, Simd4Float b, Simd4FBool sel)
+{
+    return { vbslq_f32(sel.simdInternal_, b.simdInternal_, a.simdInternal_) };
+}
+
 static inline Simd4Float gmx_simdcall fma(Simd4Float a, Simd4Float b, Simd4Float c)
 {
     return { vfmaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_) };
index ee825f388d642749767ddc8aecd4497876b4f489..90ab9ef5a45810027dd27a7f45f1f62fa8b046d6 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016,2017,2019,2020, by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_ARM_NEON_ASIMD_SIMD_FLOAT_H
 #define GMX_SIMD_IMPL_ARM_NEON_ASIMD_SIMD_FLOAT_H
 
 #include "config.h"
 
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+
 #include <arm_neon.h>
 
-#include "gromacs/simd/impl_arm_neon/impl_arm_neon_simd_float.h"
+#include "gromacs/math/utilities.h"
 
 namespace gmx
 {
 
+class SimdFloat
+{
+public:
+    SimdFloat() {}
+
+    SimdFloat(float f) : simdInternal_(vdupq_n_f32(f)) {}
+
+    // Internal utility constructor to simplify return statements
+    SimdFloat(float32x4_t simd) : simdInternal_(simd) {}
+
+    float32x4_t simdInternal_;
+};
+
+class SimdFInt32
+{
+public:
+    SimdFInt32() {}
+
+    SimdFInt32(std::int32_t i) : simdInternal_(vdupq_n_s32(i)) {}
+
+    // Internal utility constructor to simplify return statements
+    SimdFInt32(int32x4_t simd) : simdInternal_(simd) {}
+
+    int32x4_t simdInternal_;
+};
+
+class SimdFBool
+{
+public:
+    SimdFBool() {}
+
+    SimdFBool(bool b) : simdInternal_(vdupq_n_u32(b ? 0xFFFFFFFF : 0)) {}
+
+    // Internal utility constructor to simplify return statements
+    SimdFBool(uint32x4_t simd) : simdInternal_(simd) {}
+
+    uint32x4_t simdInternal_;
+};
+
+class SimdFIBool
+{
+public:
+    SimdFIBool() {}
+
+    SimdFIBool(bool b) : simdInternal_(vdupq_n_u32(b ? 0xFFFFFFFF : 0)) {}
+
+    // Internal utility constructor to simplify return statements
+    SimdFIBool(uint32x4_t simd) : simdInternal_(simd) {}
+
+    uint32x4_t simdInternal_;
+};
+
+static inline SimdFloat gmx_simdcall simdLoad(const float* m, SimdFloatTag = {})
+{
+    assert(std::size_t(m) % 16 == 0);
+    return { vld1q_f32(m) };
+}
+
+static inline void gmx_simdcall store(float* m, SimdFloat a)
+{
+    assert(std::size_t(m) % 16 == 0);
+    vst1q_f32(m, a.simdInternal_);
+}
+
+static inline SimdFloat gmx_simdcall simdLoadU(const float* m, SimdFloatTag = {})
+{
+    return { vld1q_f32(m) };
+}
+
+static inline void gmx_simdcall storeU(float* m, SimdFloat a)
+{
+    vst1q_f32(m, a.simdInternal_);
+}
+
+static inline SimdFloat gmx_simdcall setZeroF()
+{
+    return { vdupq_n_f32(0.0F) };
+}
+
+static inline SimdFInt32 gmx_simdcall simdLoad(const std::int32_t* m, SimdFInt32Tag)
+{
+    assert(std::size_t(m) % 16 == 0);
+    return { vld1q_s32(m) };
+}
+
+static inline void gmx_simdcall store(std::int32_t* m, SimdFInt32 a)
+{
+    assert(std::size_t(m) % 16 == 0);
+    vst1q_s32(m, a.simdInternal_);
+}
+
+static inline SimdFInt32 gmx_simdcall simdLoadU(const std::int32_t* m, SimdFInt32Tag)
+{
+    return { vld1q_s32(m) };
+}
+
+static inline void gmx_simdcall storeU(std::int32_t* m, SimdFInt32 a)
+{
+    vst1q_s32(m, a.simdInternal_);
+}
+
+static inline SimdFInt32 gmx_simdcall setZeroFI()
+{
+    return { vdupq_n_s32(0) };
+}
+
+template<int index>
+gmx_simdcall static inline std::int32_t extract(SimdFInt32 a)
+{
+    return vgetq_lane_s32(a.simdInternal_, index);
+}
+
+static inline SimdFloat gmx_simdcall operator&(SimdFloat a, SimdFloat b)
+{
+    return { vreinterpretq_f32_s32(vandq_s32(vreinterpretq_s32_f32(a.simdInternal_),
+                                             vreinterpretq_s32_f32(b.simdInternal_))) };
+}
+
+static inline SimdFloat gmx_simdcall andNot(SimdFloat a, SimdFloat b)
+{
+    return { vreinterpretq_f32_s32(vbicq_s32(vreinterpretq_s32_f32(b.simdInternal_),
+                                             vreinterpretq_s32_f32(a.simdInternal_))) };
+}
+
+static inline SimdFloat gmx_simdcall operator|(SimdFloat a, SimdFloat b)
+{
+    return { vreinterpretq_f32_s32(vorrq_s32(vreinterpretq_s32_f32(a.simdInternal_),
+                                             vreinterpretq_s32_f32(b.simdInternal_))) };
+}
+
+static inline SimdFloat gmx_simdcall operator^(SimdFloat a, SimdFloat b)
+{
+    return { vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(a.simdInternal_),
+                                             vreinterpretq_s32_f32(b.simdInternal_))) };
+}
+
+static inline SimdFloat gmx_simdcall operator+(SimdFloat a, SimdFloat b)
+{
+    return { vaddq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFloat gmx_simdcall operator-(SimdFloat a, SimdFloat b)
+{
+    return { vsubq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFloat gmx_simdcall operator-(SimdFloat x)
+{
+    return { vnegq_f32(x.simdInternal_) };
+}
+
+static inline SimdFloat gmx_simdcall operator*(SimdFloat a, SimdFloat b)
+{
+    return { vmulq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFloat gmx_simdcall rsqrt(SimdFloat x)
+{
+    return { vrsqrteq_f32(x.simdInternal_) };
+}
+
+// The SIMD implementation seems to overflow when we square lu for
+// values close to FLOAT_MAX, so we fall back on the version in
+// simd_math.h, which is probably slightly slower.
+#if GMX_SIMD_HAVE_NATIVE_RSQRT_ITER_FLOAT
+static inline SimdFloat gmx_simdcall rsqrtIter(SimdFloat lu, SimdFloat x)
+{
+    return { vmulq_f32(lu.simdInternal_,
+                       vrsqrtsq_f32(vmulq_f32(lu.simdInternal_, lu.simdInternal_), x.simdInternal_)) };
+}
+#endif
+
+static inline SimdFloat gmx_simdcall rcp(SimdFloat x)
+{
+    return { vrecpeq_f32(x.simdInternal_) };
+}
+
+static inline SimdFloat gmx_simdcall rcpIter(SimdFloat lu, SimdFloat x)
+{
+    return { vmulq_f32(lu.simdInternal_, vrecpsq_f32(lu.simdInternal_, x.simdInternal_)) };
+}
+
+static inline SimdFloat gmx_simdcall maskAdd(SimdFloat a, SimdFloat b, SimdFBool m)
+{
+    b.simdInternal_ =
+            vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(b.simdInternal_), m.simdInternal_));
+
+    return { vaddq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFloat gmx_simdcall maskzMul(SimdFloat a, SimdFloat b, SimdFBool m)
+{
+    SimdFloat tmp = a * b;
+
+    return { vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(tmp.simdInternal_), m.simdInternal_)) };
+}
+
+static inline SimdFloat gmx_simdcall maskzFma(SimdFloat a, SimdFloat b, SimdFloat c, SimdFBool m)
+{
+#ifdef __ARM_FEATURE_FMA
+    float32x4_t tmp = vfmaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_);
+#else
+    float32x4_t tmp = vmlaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_);
+#endif
+
+    return { vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(tmp), m.simdInternal_)) };
+}
+
+static inline SimdFloat gmx_simdcall maskzRsqrt(SimdFloat x, SimdFBool m)
+{
+    // The result will always be correct since we mask the result with m, but
+    // for debug builds we also want to make sure not to generate FP exceptions
+#ifndef NDEBUG
+    x.simdInternal_ = vbslq_f32(m.simdInternal_, x.simdInternal_, vdupq_n_f32(1.0F));
+#endif
+    return { vreinterpretq_f32_u32(
+            vandq_u32(vreinterpretq_u32_f32(vrsqrteq_f32(x.simdInternal_)), m.simdInternal_)) };
+}
+
+static inline SimdFloat gmx_simdcall maskzRcp(SimdFloat x, SimdFBool m)
+{
+    // The result will always be correct since we mask the result with m, but
+    // for debug builds we also want to make sure not to generate FP exceptions
+#ifndef NDEBUG
+    x.simdInternal_ = vbslq_f32(m.simdInternal_, x.simdInternal_, vdupq_n_f32(1.0F));
+#endif
+    return { vreinterpretq_f32_u32(
+            vandq_u32(vreinterpretq_u32_f32(vrecpeq_f32(x.simdInternal_)), m.simdInternal_)) };
+}
+
+static inline SimdFloat gmx_simdcall abs(SimdFloat x)
+{
+    return { vabsq_f32(x.simdInternal_) };
+}
+
+static inline SimdFloat gmx_simdcall max(SimdFloat a, SimdFloat b)
+{
+    return { vmaxq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFloat gmx_simdcall min(SimdFloat a, SimdFloat b)
+{
+    return { vminq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+// Round and trunc operations are defined at the end of this file, since they
+// need to use float-to-integer and integer-to-float conversions.
+
+template<MathOptimization opt = MathOptimization::Safe>
+static inline SimdFloat gmx_simdcall frexp(SimdFloat value, SimdFInt32* exponent)
+{
+    const int32x4_t exponentMask = vdupq_n_s32(0x7F800000);
+    const int32x4_t mantissaMask = vdupq_n_s32(0x807FFFFF);
+    const int32x4_t exponentBias = vdupq_n_s32(126); // add 1 to make our definition identical to frexp()
+    const float32x4_t half = vdupq_n_f32(0.5F);
+    int32x4_t         iExponent;
+
+    iExponent = vandq_s32(vreinterpretq_s32_f32(value.simdInternal_), exponentMask);
+    iExponent = vsubq_s32(vshrq_n_s32(iExponent, 23), exponentBias);
+
+    float32x4_t result = vreinterpretq_f32_s32(
+            vorrq_s32(vandq_s32(vreinterpretq_s32_f32(value.simdInternal_), mantissaMask),
+                      vreinterpretq_s32_f32(half)));
+
+    if (opt == MathOptimization::Safe)
+    {
+        uint32x4_t valueIsZero = vceqq_f32(value.simdInternal_, vdupq_n_f32(0.0F));
+        iExponent              = vbicq_s32(iExponent, vreinterpretq_s32_u32(valueIsZero));
+        result                 = vbslq_f32(valueIsZero, value.simdInternal_, result);
+    }
+
+    exponent->simdInternal_ = iExponent;
+    return { result };
+}
+
+template<MathOptimization opt = MathOptimization::Safe>
+static inline SimdFloat gmx_simdcall ldexp(SimdFloat value, SimdFInt32 exponent)
+{
+    const int32x4_t exponentBias = vdupq_n_s32(127);
+    int32x4_t       iExponent    = vaddq_s32(exponent.simdInternal_, exponentBias);
+
+    if (opt == MathOptimization::Safe)
+    {
+        // Make sure biased argument is not negative
+        iExponent = vmaxq_s32(iExponent, vdupq_n_s32(0));
+    }
+
+    iExponent = vshlq_n_s32(iExponent, 23);
+
+    return { vmulq_f32(value.simdInternal_, vreinterpretq_f32_s32(iExponent)) };
+}
+
+static inline SimdFBool gmx_simdcall operator==(SimdFloat a, SimdFloat b)
+{
+    return { vceqq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFBool gmx_simdcall operator!=(SimdFloat a, SimdFloat b)
+{
+    return { vmvnq_u32(vceqq_f32(a.simdInternal_, b.simdInternal_)) };
+}
+
+static inline SimdFBool gmx_simdcall operator<(SimdFloat a, SimdFloat b)
+{
+    return { vcltq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFBool gmx_simdcall operator<=(SimdFloat a, SimdFloat b)
+{
+    return { vcleq_f32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFBool gmx_simdcall testBits(SimdFloat a)
+{
+    uint32x4_t tmp = vreinterpretq_u32_f32(a.simdInternal_);
+
+    return { vtstq_u32(tmp, tmp) };
+}
+
+static inline SimdFBool gmx_simdcall operator&&(SimdFBool a, SimdFBool b)
+{
+
+    return { vandq_u32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFBool gmx_simdcall operator||(SimdFBool a, SimdFBool b)
+{
+    return { vorrq_u32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFloat gmx_simdcall selectByMask(SimdFloat a, SimdFBool m)
+{
+    return { vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(a.simdInternal_), m.simdInternal_)) };
+}
+
+static inline SimdFloat gmx_simdcall selectByNotMask(SimdFloat a, SimdFBool m)
+{
+    return { vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(a.simdInternal_), m.simdInternal_)) };
+}
+
+static inline SimdFloat gmx_simdcall blend(SimdFloat a, SimdFloat b, SimdFBool sel)
+{
+    return { vbslq_f32(sel.simdInternal_, b.simdInternal_, a.simdInternal_) };
+}
+
+static inline SimdFInt32 gmx_simdcall operator&(SimdFInt32 a, SimdFInt32 b)
+{
+    return { vandq_s32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFInt32 gmx_simdcall andNot(SimdFInt32 a, SimdFInt32 b)
+{
+    return { vbicq_s32(b.simdInternal_, a.simdInternal_) };
+}
+
+static inline SimdFInt32 gmx_simdcall operator|(SimdFInt32 a, SimdFInt32 b)
+{
+    return { vorrq_s32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFInt32 gmx_simdcall operator^(SimdFInt32 a, SimdFInt32 b)
+{
+    return { veorq_s32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFInt32 gmx_simdcall operator+(SimdFInt32 a, SimdFInt32 b)
+{
+    return { vaddq_s32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFInt32 gmx_simdcall operator-(SimdFInt32 a, SimdFInt32 b)
+{
+    return { vsubq_s32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFInt32 gmx_simdcall operator*(SimdFInt32 a, SimdFInt32 b)
+{
+    return { vmulq_s32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFIBool gmx_simdcall operator==(SimdFInt32 a, SimdFInt32 b)
+{
+    return { vceqq_s32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFIBool gmx_simdcall testBits(SimdFInt32 a)
+{
+    return { vtstq_s32(a.simdInternal_, a.simdInternal_) };
+}
+
+static inline SimdFIBool gmx_simdcall operator<(SimdFInt32 a, SimdFInt32 b)
+{
+    return { vcltq_s32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFIBool gmx_simdcall operator&&(SimdFIBool a, SimdFIBool b)
+{
+    return { vandq_u32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFIBool gmx_simdcall operator||(SimdFIBool a, SimdFIBool b)
+{
+    return { vorrq_u32(a.simdInternal_, b.simdInternal_) };
+}
+
+static inline SimdFInt32 gmx_simdcall selectByMask(SimdFInt32 a, SimdFIBool m)
+{
+    return { vandq_s32(a.simdInternal_, vreinterpretq_s32_u32(m.simdInternal_)) };
+}
+
+static inline SimdFInt32 gmx_simdcall selectByNotMask(SimdFInt32 a, SimdFIBool m)
+{
+    return { vbicq_s32(a.simdInternal_, vreinterpretq_s32_u32(m.simdInternal_)) };
+}
+
+static inline SimdFInt32 gmx_simdcall blend(SimdFInt32 a, SimdFInt32 b, SimdFIBool sel)
+{
+    return { vbslq_s32(sel.simdInternal_, b.simdInternal_, a.simdInternal_) };
+}
+
+static inline SimdFInt32 gmx_simdcall cvttR2I(SimdFloat a)
+{
+    return { vcvtq_s32_f32(a.simdInternal_) };
+}
+
+static inline SimdFloat gmx_simdcall cvtI2R(SimdFInt32 a)
+{
+    return { vcvtq_f32_s32(a.simdInternal_) };
+}
+
+static inline SimdFIBool gmx_simdcall cvtB2IB(SimdFBool a)
+{
+    return { a.simdInternal_ };
+}
+
+static inline SimdFBool gmx_simdcall cvtIB2B(SimdFIBool a)
+{
+    return { a.simdInternal_ };
+}
+
 static inline SimdFloat gmx_simdcall fma(SimdFloat a, SimdFloat b, SimdFloat c)
 {
     return { vfmaq_f32(c.simdInternal_, b.simdInternal_, a.simdInternal_) };
index 177cc7ddda461f01e997638b22e45ba7b8c9fa5b..25bd43b07118d6f4f079fdbada1171a503475e1e 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * 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,2017,2018 by the GROMACS development team.
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_ARM_NEON_ASIMD_UTIL_FLOAT_H
 #define GMX_SIMD_IMPL_ARM_NEON_ASIMD_UTIL_FLOAT_H
 
-#include "gromacs/simd/impl_arm_neon/impl_arm_neon_util_float.h"
+#include "config.h"
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+
+#include <arm_neon.h>
+
+#include "gromacs/utility/basedefinitions.h"
+
+
+namespace gmx
+{
+
+template<int align>
+static inline void gmx_simdcall gatherLoadTranspose(const float*       base,
+                                                    const std::int32_t offset[],
+                                                    SimdFloat*         v0,
+                                                    SimdFloat*         v1,
+                                                    SimdFloat*         v2,
+                                                    SimdFloat*         v3)
+{
+    assert(std::size_t(offset) % 16 == 0);
+    assert(std::size_t(base) % 16 == 0);
+    assert(align % 4 == 0);
+
+    // Unfortunately we cannot use the beautiful Neon structured load
+    // instructions since the data comes from four different memory locations.
+    float32x4x2_t t0 =
+            vuzpq_f32(vld1q_f32(base + align * offset[0]), vld1q_f32(base + align * offset[2]));
+    float32x4x2_t t1 =
+            vuzpq_f32(vld1q_f32(base + align * offset[1]), vld1q_f32(base + align * offset[3]));
+    float32x4x2_t t2  = vtrnq_f32(t0.val[0], t1.val[0]);
+    float32x4x2_t t3  = vtrnq_f32(t0.val[1], t1.val[1]);
+    v0->simdInternal_ = t2.val[0];
+    v1->simdInternal_ = t3.val[0];
+    v2->simdInternal_ = t2.val[1];
+    v3->simdInternal_ = t3.val[1];
+}
+
+template<int align>
+static inline void gmx_simdcall
+                   gatherLoadTranspose(const float* base, const std::int32_t offset[], SimdFloat* v0, SimdFloat* v1)
+{
+    assert(std::size_t(offset) % 16 == 0);
+    assert(std::size_t(base) % 8 == 0);
+    assert(align % 2 == 0);
+
+    v0->simdInternal_ =
+            vcombine_f32(vld1_f32(base + align * offset[0]), vld1_f32(base + align * offset[2]));
+    v1->simdInternal_ =
+            vcombine_f32(vld1_f32(base + align * offset[1]), vld1_f32(base + align * offset[3]));
+
+    float32x4x2_t tmp = vtrnq_f32(v0->simdInternal_, v1->simdInternal_);
+
+    v0->simdInternal_ = tmp.val[0];
+    v1->simdInternal_ = tmp.val[1];
+}
+
+static const int c_simdBestPairAlignmentFloat = 2;
+
+template<int align>
+static inline void gmx_simdcall gatherLoadUTranspose(const float*       base,
+                                                     const std::int32_t offset[],
+                                                     SimdFloat*         v0,
+                                                     SimdFloat*         v1,
+                                                     SimdFloat*         v2)
+{
+    assert(std::size_t(offset) % 16 == 0);
+
+    float32x4x2_t t0 =
+            vuzpq_f32(vld1q_f32(base + align * offset[0]), vld1q_f32(base + align * offset[2]));
+    float32x4x2_t t1 =
+            vuzpq_f32(vld1q_f32(base + align * offset[1]), vld1q_f32(base + align * offset[3]));
+    float32x4x2_t t2  = vtrnq_f32(t0.val[0], t1.val[0]);
+    float32x4x2_t t3  = vtrnq_f32(t0.val[1], t1.val[1]);
+    v0->simdInternal_ = t2.val[0];
+    v1->simdInternal_ = t3.val[0];
+    v2->simdInternal_ = t2.val[1];
+}
+
+
+template<int align>
+static inline void gmx_simdcall
+                   transposeScatterStoreU(float* base, const std::int32_t offset[], SimdFloat v0, SimdFloat v1, SimdFloat v2)
+{
+    assert(std::size_t(offset) % 16 == 0);
+
+    float32x4x2_t tmp = vtrnq_f32(v0.simdInternal_, v1.simdInternal_);
+
+    vst1_f32(base + align * offset[0], vget_low_f32(tmp.val[0]));
+    vst1_f32(base + align * offset[1], vget_low_f32(tmp.val[1]));
+    vst1_f32(base + align * offset[2], vget_high_f32(tmp.val[0]));
+    vst1_f32(base + align * offset[3], vget_high_f32(tmp.val[1]));
+
+    vst1q_lane_f32(base + align * offset[0] + 2, v2.simdInternal_, 0);
+    vst1q_lane_f32(base + align * offset[1] + 2, v2.simdInternal_, 1);
+    vst1q_lane_f32(base + align * offset[2] + 2, v2.simdInternal_, 2);
+    vst1q_lane_f32(base + align * offset[3] + 2, v2.simdInternal_, 3);
+}
+
+
+template<int align>
+static inline void gmx_simdcall
+                   transposeScatterIncrU(float* base, const std::int32_t offset[], SimdFloat v0, SimdFloat v1, SimdFloat v2)
+{
+    assert(std::size_t(offset) % 16 == 0);
+
+    if (align < 4)
+    {
+        float32x2_t   t0, t1, t2, t3;
+        float32x4x2_t tmp = vtrnq_f32(v0.simdInternal_, v1.simdInternal_);
+
+        t0 = vget_low_f32(tmp.val[0]);
+        t1 = vget_low_f32(tmp.val[1]);
+        t2 = vget_high_f32(tmp.val[0]);
+        t3 = vget_high_f32(tmp.val[1]);
+
+        t0 = vadd_f32(t0, vld1_f32(base + align * offset[0]));
+        vst1_f32(base + align * offset[0], t0);
+        base[align * offset[0] + 2] += vgetq_lane_f32(v2.simdInternal_, 0);
+
+        t1 = vadd_f32(t1, vld1_f32(base + align * offset[1]));
+        vst1_f32(base + align * offset[1], t1);
+        base[align * offset[1] + 2] += vgetq_lane_f32(v2.simdInternal_, 1);
+
+        t2 = vadd_f32(t2, vld1_f32(base + align * offset[2]));
+        vst1_f32(base + align * offset[2], t2);
+        base[align * offset[2] + 2] += vgetq_lane_f32(v2.simdInternal_, 2);
+
+        t3 = vadd_f32(t3, vld1_f32(base + align * offset[3]));
+        vst1_f32(base + align * offset[3], t3);
+        base[align * offset[3] + 2] += vgetq_lane_f32(v2.simdInternal_, 3);
+    }
+    else
+    {
+        // Extra elements means we can use full width-4 load/store operations
+        float32x4x2_t t0 = vuzpq_f32(v0.simdInternal_, v2.simdInternal_);
+        float32x4x2_t t1 = vuzpq_f32(v1.simdInternal_, vdupq_n_f32(0.0F));
+        float32x4x2_t t2 = vtrnq_f32(t0.val[0], t1.val[0]);
+        float32x4x2_t t3 = vtrnq_f32(t0.val[1], t1.val[1]);
+        float32x4_t   t4 = t2.val[0];
+        float32x4_t   t5 = t3.val[0];
+        float32x4_t   t6 = t2.val[1];
+        float32x4_t   t7 = t3.val[1];
+
+        vst1q_f32(base + align * offset[0], vaddq_f32(t4, vld1q_f32(base + align * offset[0])));
+        vst1q_f32(base + align * offset[1], vaddq_f32(t5, vld1q_f32(base + align * offset[1])));
+        vst1q_f32(base + align * offset[2], vaddq_f32(t6, vld1q_f32(base + align * offset[2])));
+        vst1q_f32(base + align * offset[3], vaddq_f32(t7, vld1q_f32(base + align * offset[3])));
+    }
+}
+
+template<int align>
+static inline void gmx_simdcall
+                   transposeScatterDecrU(float* base, const std::int32_t offset[], SimdFloat v0, SimdFloat v1, SimdFloat v2)
+{
+    assert(std::size_t(offset) % 16 == 0);
+
+    if (align < 4)
+    {
+        float32x2_t   t0, t1, t2, t3;
+        float32x4x2_t tmp = vtrnq_f32(v0.simdInternal_, v1.simdInternal_);
+
+        t0 = vget_low_f32(tmp.val[0]);
+        t1 = vget_low_f32(tmp.val[1]);
+        t2 = vget_high_f32(tmp.val[0]);
+        t3 = vget_high_f32(tmp.val[1]);
+
+        t0 = vsub_f32(vld1_f32(base + align * offset[0]), t0);
+        vst1_f32(base + align * offset[0], t0);
+        base[align * offset[0] + 2] -= vgetq_lane_f32(v2.simdInternal_, 0);
+
+        t1 = vsub_f32(vld1_f32(base + align * offset[1]), t1);
+        vst1_f32(base + align * offset[1], t1);
+        base[align * offset[1] + 2] -= vgetq_lane_f32(v2.simdInternal_, 1);
+
+        t2 = vsub_f32(vld1_f32(base + align * offset[2]), t2);
+        vst1_f32(base + align * offset[2], t2);
+        base[align * offset[2] + 2] -= vgetq_lane_f32(v2.simdInternal_, 2);
+
+        t3 = vsub_f32(vld1_f32(base + align * offset[3]), t3);
+        vst1_f32(base + align * offset[3], t3);
+        base[align * offset[3] + 2] -= vgetq_lane_f32(v2.simdInternal_, 3);
+    }
+    else
+    {
+        // Extra elements means we can use full width-4 load/store operations
+        float32x4x2_t t0 = vuzpq_f32(v0.simdInternal_, v2.simdInternal_);
+        float32x4x2_t t1 = vuzpq_f32(v1.simdInternal_, vdupq_n_f32(0.0F));
+        float32x4x2_t t2 = vtrnq_f32(t0.val[0], t1.val[0]);
+        float32x4x2_t t3 = vtrnq_f32(t0.val[1], t1.val[1]);
+        float32x4_t   t4 = t2.val[0];
+        float32x4_t   t5 = t3.val[0];
+        float32x4_t   t6 = t2.val[1];
+        float32x4_t   t7 = t3.val[1];
+
+        vst1q_f32(base + align * offset[0], vsubq_f32(vld1q_f32(base + align * offset[0]), t4));
+        vst1q_f32(base + align * offset[1], vsubq_f32(vld1q_f32(base + align * offset[1]), t5));
+        vst1q_f32(base + align * offset[2], vsubq_f32(vld1q_f32(base + align * offset[2]), t6));
+        vst1q_f32(base + align * offset[3], vsubq_f32(vld1q_f32(base + align * offset[3]), t7));
+    }
+}
+
+static inline void gmx_simdcall expandScalarsToTriplets(SimdFloat  scalar,
+                                                        SimdFloat* triplets0,
+                                                        SimdFloat* triplets1,
+                                                        SimdFloat* triplets2)
+{
+    float32x2_t lo, hi;
+    float32x4_t t0, t1, t2, t3;
+
+    lo = vget_low_f32(scalar.simdInternal_);
+    hi = vget_high_f32(scalar.simdInternal_);
+
+    t0 = vdupq_lane_f32(lo, 0);
+    t1 = vdupq_lane_f32(lo, 1);
+    t2 = vdupq_lane_f32(hi, 0);
+    t3 = vdupq_lane_f32(hi, 1);
+
+    triplets0->simdInternal_ = vextq_f32(t0, t1, 1);
+    triplets1->simdInternal_ = vextq_f32(t1, t2, 2);
+    triplets2->simdInternal_ = vextq_f32(t2, t3, 3);
+}
+
+
+template<int align>
+static inline void gmx_simdcall gatherLoadBySimdIntTranspose(const float* base,
+                                                             SimdFInt32   offset,
+                                                             SimdFloat*   v0,
+                                                             SimdFloat*   v1,
+                                                             SimdFloat*   v2,
+                                                             SimdFloat*   v3)
+{
+    alignas(GMX_SIMD_ALIGNMENT) std::int32_t ioffset[GMX_SIMD_FINT32_WIDTH];
+
+    assert(std::size_t(base) % 16 == 0);
+    assert(align % 4 == 0);
+
+    store(ioffset, offset);
+    gatherLoadTranspose<align>(base, ioffset, v0, v1, v2, v3);
+}
+
+template<int align>
+static inline void gmx_simdcall
+                   gatherLoadBySimdIntTranspose(const float* base, SimdFInt32 offset, SimdFloat* v0, SimdFloat* v1)
+{
+    alignas(GMX_SIMD_ALIGNMENT) std::int32_t ioffset[GMX_SIMD_FINT32_WIDTH];
+
+    store(ioffset, offset);
+    gatherLoadTranspose<align>(base, ioffset, v0, v1);
+}
+
+
+template<int align>
+static inline void gmx_simdcall
+                   gatherLoadUBySimdIntTranspose(const float* base, SimdFInt32 offset, SimdFloat* v0, SimdFloat* v1)
+{
+    alignas(GMX_SIMD_ALIGNMENT) std::int32_t ioffset[GMX_SIMD_FINT32_WIDTH];
+
+    store(ioffset, offset);
+    v0->simdInternal_ =
+            vcombine_f32(vld1_f32(base + align * ioffset[0]), vld1_f32(base + align * ioffset[2]));
+    v1->simdInternal_ =
+            vcombine_f32(vld1_f32(base + align * ioffset[1]), vld1_f32(base + align * ioffset[3]));
+    float32x4x2_t tmp = vtrnq_f32(v0->simdInternal_, v1->simdInternal_);
+    v0->simdInternal_ = tmp.val[0];
+    v1->simdInternal_ = tmp.val[1];
+}
+
+static inline float gmx_simdcall reduceIncr4ReturnSum(float* m, SimdFloat v0, SimdFloat v1, SimdFloat v2, SimdFloat v3)
+{
+    assert(std::size_t(m) % 16 == 0);
+
+    float32x4x2_t t0 = vuzpq_f32(v0.simdInternal_, v2.simdInternal_);
+    float32x4x2_t t1 = vuzpq_f32(v1.simdInternal_, v3.simdInternal_);
+    float32x4x2_t t2 = vtrnq_f32(t0.val[0], t1.val[0]);
+    float32x4x2_t t3 = vtrnq_f32(t0.val[1], t1.val[1]);
+    v0.simdInternal_ = t2.val[0];
+    v1.simdInternal_ = t3.val[0];
+    v2.simdInternal_ = t2.val[1];
+    v3.simdInternal_ = t3.val[1];
+
+    v0 = v0 + v1;
+    v2 = v2 + v3;
+    v0 = v0 + v2;
+    v2 = v0 + simdLoad(m);
+    store(m, v2);
+
+    return reduce(v0);
+}
+
+} // namespace gmx
 
 #endif // GMX_SIMD_IMPL_ARM_NEON_ASIMD_UTIL_FLOAT_H
index 037f3e6c05b872b394da1c7bfa52549222109541..7834553a13a006e5168ae4e9a79533aad785d44c 100644 (file)
@@ -116,29 +116,29 @@ static inline Simd4Double gmx_simdcall simd4SetZeroD()
 static inline Simd4Double gmx_simdcall operator&(Simd4Double a, Simd4Double b)
 {
     svbool_t pg = svptrue_b64();
-    return { svreinterpret_f64_s64(svand_s64_z(pg, svreinterpret_s64_f64(a.simdInternal_),
-                                               svreinterpret_s64_f64(b.simdInternal_))) };
+    return { svreinterpret_f64_s64(svand_s64_z(
+            pg, svreinterpret_s64_f64(a.simdInternal_), svreinterpret_s64_f64(b.simdInternal_))) };
 }
 
 static inline Simd4Double gmx_simdcall andNot(Simd4Double a, Simd4Double b)
 {
     svbool_t pg = svptrue_b64();
-    return { svreinterpret_f64_s64(svbic_s64_z(pg, svreinterpret_s64_f64(b.simdInternal_),
-                                               svreinterpret_s64_f64(a.simdInternal_))) };
+    return { svreinterpret_f64_s64(svbic_s64_z(
+            pg, svreinterpret_s64_f64(b.simdInternal_), svreinterpret_s64_f64(a.simdInternal_))) };
 }
 
 static inline Simd4Double gmx_simdcall operator|(Simd4Double a, Simd4Double b)
 {
     svbool_t pg = svptrue_b64();
-    return { svreinterpret_f64_s64(svorr_s64_z(pg, svreinterpret_s64_f64(a.simdInternal_),
-                                               svreinterpret_s64_f64(b.simdInternal_))) };
+    return { svreinterpret_f64_s64(svorr_s64_z(
+            pg, svreinterpret_s64_f64(a.simdInternal_), svreinterpret_s64_f64(b.simdInternal_))) };
 }
 
 static inline Simd4Double gmx_simdcall operator^(Simd4Double a, Simd4Double b)
 {
     svbool_t pg = svptrue_b64();
-    return { svreinterpret_f64_s64(sveor_s64_z(pg, svreinterpret_s64_f64(a.simdInternal_),
-                                               svreinterpret_s64_f64(b.simdInternal_))) };
+    return { svreinterpret_f64_s64(sveor_s64_z(
+            pg, svreinterpret_s64_f64(a.simdInternal_), svreinterpret_s64_f64(b.simdInternal_))) };
 }
 
 static inline Simd4Double gmx_simdcall operator+(Simd4Double a, Simd4Double b)
index 99046af962d184b0d8b495fcded0209f3f42eab4..773a44eff9466a7795811454b80a42226a859fff 100644 (file)
@@ -174,8 +174,7 @@ static inline void gmx_simdcall store(std::int32_t* m, SimdDInt32 a)
 {
     assert(0 == (std::size_t(m) % GMX_SIMD_ALIGNMENT));
     svbool_t pg = svwhilelt_b32(0, (int32_t)GMX_SIMD_DINT32_WIDTH);
-    svst1_s32(pg, m,
-              svuzp1(svreinterpret_s32_s64(a.simdInternal_), svreinterpret_s32_s64(a.simdInternal_)));
+    svst1_s32(pg, m, svuzp1(svreinterpret_s32_s64(a.simdInternal_), svreinterpret_s32_s64(a.simdInternal_)));
 }
 
 static inline SimdDInt32 gmx_simdcall simdLoadU(const std::int32_t* m, SimdDInt32Tag)
@@ -187,8 +186,7 @@ static inline SimdDInt32 gmx_simdcall simdLoadU(const std::int32_t* m, SimdDInt3
 static inline void gmx_simdcall storeU(std::int32_t* m, SimdDInt32 a)
 {
     svbool_t pg = svwhilelt_b32(0, (int32_t)GMX_SIMD_DINT32_WIDTH);
-    svst1_s32(pg, m,
-              svuzp1(svreinterpret_s32_s64(a.simdInternal_), svreinterpret_s32_s64(a.simdInternal_)));
+    svst1_s32(pg, m, svuzp1(svreinterpret_s32_s64(a.simdInternal_), svreinterpret_s32_s64(a.simdInternal_)));
 }
 
 static inline SimdDInt32 gmx_simdcall setZeroDI()
@@ -213,29 +211,29 @@ gmx_simdcall static inline double extract(SimdDouble a)
 static inline SimdDouble gmx_simdcall operator&(SimdDouble a, SimdDouble b)
 {
     svbool_t pg = svptrue_b64();
-    return { svreinterpret_f64_s64(svand_s64_x(pg, svreinterpret_s64_f64(a.simdInternal_),
-                                               svreinterpret_s64_f64(b.simdInternal_))) };
+    return { svreinterpret_f64_s64(svand_s64_x(
+            pg, svreinterpret_s64_f64(a.simdInternal_), svreinterpret_s64_f64(b.simdInternal_))) };
 }
 
 static inline SimdDouble gmx_simdcall andNot(SimdDouble a, SimdDouble b)
 {
     svbool_t pg = svptrue_b64();
-    return { svreinterpret_f64_s64(svbic_s64_x(pg, svreinterpret_s64_f64(b.simdInternal_),
-                                               svreinterpret_s64_f64(a.simdInternal_))) };
+    return { svreinterpret_f64_s64(svbic_s64_x(
+            pg, svreinterpret_s64_f64(b.simdInternal_), svreinterpret_s64_f64(a.simdInternal_))) };
 }
 
 static inline SimdDouble gmx_simdcall operator|(SimdDouble a, SimdDouble b)
 {
     svbool_t pg = svptrue_b64();
-    return { svreinterpret_f64_s64(svorr_s64_x(pg, svreinterpret_s64_f64(a.simdInternal_),
-                                               svreinterpret_s64_f64(b.simdInternal_))) };
+    return { svreinterpret_f64_s64(svorr_s64_x(
+            pg, svreinterpret_s64_f64(a.simdInternal_), svreinterpret_s64_f64(b.simdInternal_))) };
 }
 
 static inline SimdDouble gmx_simdcall operator^(SimdDouble a, SimdDouble b)
 {
     svbool_t pg = svptrue_b64();
-    return { svreinterpret_f64_s64(sveor_s64_x(pg, svreinterpret_s64_f64(a.simdInternal_),
-                                               svreinterpret_s64_f64(b.simdInternal_))) };
+    return { svreinterpret_f64_s64(sveor_s64_x(
+            pg, svreinterpret_s64_f64(a.simdInternal_), svreinterpret_s64_f64(b.simdInternal_))) };
 }
 
 static inline SimdDouble gmx_simdcall operator+(SimdDouble a, SimdDouble b)
@@ -391,9 +389,10 @@ static inline SimdDouble gmx_simdcall frexp(SimdDouble value, SimdDInt32* expone
             pg, svreinterpret_s64_u64(svlsr_n_u64_x(pg, svreinterpret_u64_s64(iExponent), 52)), exponentBias);
 
 
-    svfloat64_t result = svreinterpret_f64_s64(svorr_s64_x(
-            pg, svand_s64_x(pg, svreinterpret_s64_f64(value.simdInternal_), mantissaMask),
-            svreinterpret_s64_f64(half)));
+    svfloat64_t result = svreinterpret_f64_s64(
+            svorr_s64_x(pg,
+                        svand_s64_x(pg, svreinterpret_s64_f64(value.simdInternal_), mantissaMask),
+                        svreinterpret_s64_f64(half)));
 
     if (opt == MathOptimization::Safe)
     {
index 1171124f1924536ee7887042bc84d506f5dac37e..2945ea66a03df0b95445dfc3bdd2ad37a8da11a5 100644 (file)
@@ -211,29 +211,29 @@ gmx_simdcall static inline float extract(SimdFloat a)
 static inline SimdFloat gmx_simdcall operator&(SimdFloat a, SimdFloat b)
 {
     svbool_t pg = svptrue_b32();
-    return { svreinterpret_f32_s32(svand_s32_x(pg, svreinterpret_s32_f32(a.simdInternal_),
-                                               svreinterpret_s32_f32(b.simdInternal_))) };
+    return { svreinterpret_f32_s32(svand_s32_x(
+            pg, svreinterpret_s32_f32(a.simdInternal_), svreinterpret_s32_f32(b.simdInternal_))) };
 }
 
 static inline SimdFloat gmx_simdcall andNot(SimdFloat a, SimdFloat b)
 {
     svbool_t pg = svptrue_b32();
-    return { svreinterpret_f32_s32(svbic_s32_x(pg, svreinterpret_s32_f32(b.simdInternal_),
-                                               svreinterpret_s32_f32(a.simdInternal_))) };
+    return { svreinterpret_f32_s32(svbic_s32_x(
+            pg, svreinterpret_s32_f32(b.simdInternal_), svreinterpret_s32_f32(a.simdInternal_))) };
 }
 
 static inline SimdFloat gmx_simdcall operator|(SimdFloat a, SimdFloat b)
 {
     svbool_t pg = svptrue_b32();
-    return { svreinterpret_f32_s32(svorr_s32_x(pg, svreinterpret_s32_f32(a.simdInternal_),
-                                               svreinterpret_s32_f32(b.simdInternal_))) };
+    return { svreinterpret_f32_s32(svorr_s32_x(
+            pg, svreinterpret_s32_f32(a.simdInternal_), svreinterpret_s32_f32(b.simdInternal_))) };
 }
 
 static inline SimdFloat gmx_simdcall operator^(SimdFloat a, SimdFloat b)
 {
     svbool_t pg = svptrue_b32();
-    return { svreinterpret_f32_s32(sveor_s32_x(pg, svreinterpret_s32_f32(a.simdInternal_),
-                                               svreinterpret_s32_f32(b.simdInternal_))) };
+    return { svreinterpret_f32_s32(sveor_s32_x(
+            pg, svreinterpret_s32_f32(a.simdInternal_), svreinterpret_s32_f32(b.simdInternal_))) };
 }
 
 static inline SimdFloat gmx_simdcall operator+(SimdFloat a, SimdFloat b)
@@ -393,10 +393,10 @@ static inline SimdFloat gmx_simdcall frexp(SimdFloat value, SimdFInt32* exponent
     iExponent = svsub_s32_x(
             pg, svreinterpret_s32_u32(svlsr_n_u32_x(pg, svreinterpret_u32_s32(iExponent), 23)), exponentBias);
 
-
-    svfloat32_t result = svreinterpret_f32_s32(svorr_s32_x(
-            pg, svand_s32_x(pg, svreinterpret_s32_f32(value.simdInternal_), mantissaMask),
-            svreinterpret_s32_f32(half)));
+    svfloat32_t result = svreinterpret_f32_s32(
+            svorr_s32_x(pg,
+                        svand_s32_x(pg, svreinterpret_s32_f32(value.simdInternal_), mantissaMask),
+                        svreinterpret_s32_f32(half)));
 
     if (opt == MathOptimization::Safe)
     {
index cffd79f15c8911cd32b896af09c8c0f209f15fa6..d3d054c97d1b17e4a9151645bec3bc73d998299b 100644 (file)
@@ -90,7 +90,8 @@ static inline void gmx_simdcall gatherLoadTranspose(const double*      base,
     svint64_t offsets;
     svbool_t  pg = svptrue_b64();
     offsets      = svmul_n_s64_x(
-            pg, svunpklo_s64(svld1_s32(svwhilelt_b32(0, (int32_t)GMX_SIMD_DINT32_WIDTH), offset)),
+            pg,
+            svunpklo_s64(svld1_s32(svwhilelt_b32(0, (int32_t)GMX_SIMD_DINT32_WIDTH), offset)),
             align * sizeof(double));
     v0->simdInternal_ = svld1_gather_s64offset_f64(pg, base, offsets);
     offsets           = svadd_n_s64_x(pg, offsets, sizeof(double));
@@ -146,7 +147,8 @@ static inline void gmx_simdcall gatherLoadUTranspose(const double*      base,
     svint64_t offsets;
     svbool_t  pg = svptrue_b64();
     offsets      = svmul_n_s64_x(
-            pg, svunpklo_s64(svld1_s32(svwhilelt_b32(0, (int32_t)GMX_SIMD_DINT32_WIDTH), offset)),
+            pg,
+            svunpklo_s64(svld1_s32(svwhilelt_b32(0, (int32_t)GMX_SIMD_DINT32_WIDTH), offset)),
             align * sizeof(double));
     v0->simdInternal_ = svld1_gather_s64offset_f64(pg, base, offsets);
     offsets           = svadd_n_s64_x(pg, offsets, sizeof(double));
@@ -168,7 +170,8 @@ static inline void gmx_simdcall transposeScatterStoreU(double*            base,
     svint64_t offsets;
     svbool_t  pg = svptrue_b64();
     offsets      = svmul_n_s64_x(
-            pg, svunpklo_s64(svld1_s32(svwhilelt_b32(0, (int32_t)GMX_SIMD_DINT32_WIDTH), offset)),
+            pg,
+            svunpklo_s64(svld1_s32(svwhilelt_b32(0, (int32_t)GMX_SIMD_DINT32_WIDTH), offset)),
             align * sizeof(double));
     svst1_scatter_s64offset_f64(pg, base, offsets, v0.simdInternal_);
     offsets = svadd_n_s64_x(pg, offsets, sizeof(double));
@@ -415,7 +418,8 @@ static inline void gmx_simdcall gatherLoadTransposeHsimd(const double*      base
     svbool_t    pg = svwhilelt_b64(0, (int32_t)GMX_SIMD_DOUBLE_WIDTH / 2);
     svfloat64_t _v0, _v1;
     offsets = svmul_n_s64_x(
-            pg, svunpklo(svld1_s32(svwhilelt_b32(0, (int32_t)GMX_SIMD_DINT32_WIDTH / 2), offset)),
+            pg,
+            svunpklo(svld1_s32(svwhilelt_b32(0, (int32_t)GMX_SIMD_DINT32_WIDTH / 2), offset)),
             align * sizeof(double));
     _v0               = svld1_gather_s64offset_f64(pg, base0, offsets);
     _v1               = svld1_gather_s64offset_f64(pg, base1, offsets);
diff --git a/src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx.h b/src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx.h
deleted file mode 100644 (file)
index 315dc7d..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef GMX_SIMD_IMPLEMENTATION_IBM_VMX_H
-#define GMX_SIMD_IMPLEMENTATION_IBM_VMX_H
-
-#include "impl_ibm_vmx_definitions.h"
-#include "impl_ibm_vmx_general.h"
-// No double precision available for VMX
-#include "impl_ibm_vmx_simd4_float.h"
-#include "impl_ibm_vmx_simd_float.h"
-#include "impl_ibm_vmx_util_float.h"
-
-#endif // GMX_SIMD_IMPLEMENTATION_IBM_VMX_H
diff --git a/src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_definitions.h b/src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_definitions.h
deleted file mode 100644 (file)
index ece4a52..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2017,2018,2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPLEMENTATION_IBM_VMX_DEFINITIONS_H
-#define GMX_SIMD_IMPLEMENTATION_IBM_VMX_DEFINITIONS_H
-
-#include <altivec.h>
-
-#if defined(__GNUC__) && !defined(__ibmxl__) && !defined(__xlC__)
-// According to G++ documentation, when using altivec in C++ we
-// must undefine vector & bool macros after including altivec.h
-#    undef vector
-#    undef bool
-#    define vmxBool __bool
-#else
-// We cannot undefine bool on xlc, but somehow it works anyway
-#    define vmxBool bool
-#endif
-
-#define GMX_SIMD 1
-#define GMX_SIMD_HAVE_FLOAT 1
-#define GMX_SIMD_HAVE_DOUBLE 0
-#define GMX_SIMD_HAVE_LOADU 0
-#define GMX_SIMD_HAVE_STOREU 0
-
-#define GMX_SIMD_HAVE_LOGICAL 1
-#define GMX_SIMD_HAVE_FMA 1
-#define GMX_SIMD_HAVE_FINT32_EXTRACT 0
-#define GMX_SIMD_HAVE_FINT32_LOGICAL 1
-#define GMX_SIMD_HAVE_FINT32_ARITHMETICS 1
-#define GMX_SIMD_HAVE_DINT32_EXTRACT 0
-#define GMX_SIMD_HAVE_DINT32_LOGICAL 0
-#define GMX_SIMD_HAVE_DINT32_ARITHMETICS 0
-#define GMX_SIMD_HAVE_NATIVE_COPYSIGN_FLOAT 0
-#define GMX_SIMD_HAVE_NATIVE_RSQRT_ITER_FLOAT 0
-#define GMX_SIMD_HAVE_NATIVE_RCP_ITER_FLOAT 0
-#define GMX_SIMD_HAVE_NATIVE_LOG_FLOAT 0
-#define GMX_SIMD_HAVE_NATIVE_EXP2_FLOAT 0
-#define GMX_SIMD_HAVE_NATIVE_EXP_FLOAT 0
-#define GMX_SIMD_HAVE_NATIVE_COPYSIGN_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_RSQRT_ITER_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_RCP_ITER_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_LOG_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_EXP2_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_EXP_DOUBLE 0
-#define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 0
-#define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 0
-#define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 0 // No need for half-simd, width is 4
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 0
-
-#define GMX_SIMD4_HAVE_FLOAT 1
-#define GMX_SIMD4_HAVE_DOUBLE 0
-
-// Implementation details
-#define GMX_SIMD_FLOAT_WIDTH 4
-#undef GMX_SIMD_DOUBLE_WIDTH
-#define GMX_SIMD_FINT32_WIDTH 4
-#undef GMX_SIMD_DINT32_WIDTH
-#define GMX_SIMD4_WIDTH 4
-#define GMX_SIMD_ALIGNMENT 16 // Bytes (4*single)
-#define GMX_SIMD_RSQRT_BITS 14
-#define GMX_SIMD_RCP_BITS 14
-
-#endif // GMX_SIMD_IMPLEMENTATION_IBM_VMX_DEFINITIONS_H
diff --git a/src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_simd4_float.h b/src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_simd4_float.h
deleted file mode 100644 (file)
index c489f92..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2019, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPLEMENTATION_IBM_VMX_SIMD4_FLOAT_H
-#define GMX_SIMD_IMPLEMENTATION_IBM_VMX_SIMD4_FLOAT_H
-
-#include "config.h"
-
-#include "gromacs/utility/basedefinitions.h"
-
-#include "impl_ibm_vmx_definitions.h"
-
-namespace gmx
-{
-
-class Simd4Float
-{
-public:
-    Simd4Float() {}
-
-    Simd4Float(float f)
-    {
-        __vector unsigned char perm;
-
-        simdInternal_ = vec_lde(0, const_cast<float*>(&f));
-        perm          = vec_lvsl(0, const_cast<float*>(&f));
-        simdInternal_ = vec_perm(simdInternal_, simdInternal_, perm);
-        simdInternal_ = vec_splat(simdInternal_, 0);
-    }
-
-    // Internal utility constructor to simplify return statements
-    Simd4Float(__vector float simd) : simdInternal_(simd) {}
-
-    __vector float simdInternal_;
-};
-
-class Simd4FBool
-{
-public:
-    Simd4FBool() {}
-
-    Simd4FBool(bool b)
-    {
-        simdInternal_ = reinterpret_cast<__vector vmxBool int>(vec_splat_u32(b ? 0xFFFFFFFF : 0));
-    }
-
-    // Internal utility constructor to simplify return statements
-    Simd4FBool(__vector vmxBool int simd) : simdInternal_(simd) {}
-
-    __vector vmxBool int simdInternal_;
-};
-
-static inline Simd4Float gmx_simdcall load4(const float* m)
-{
-    return { vec_ld(0, const_cast<float*>(m)) };
-}
-
-static inline void gmx_simdcall store4(float* m, Simd4Float a)
-{
-    vec_st(a.simdInternal_, 0, const_cast<float*>(m));
-}
-
-static inline Simd4Float gmx_simdcall simd4SetZeroF()
-{
-    return { reinterpret_cast<__vector float>(vec_splat_u32(0)) };
-}
-
-static inline Simd4Float gmx_simdcall operator&(Simd4Float a, Simd4Float b)
-{
-    return { vec_and(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall andNot(Simd4Float a, Simd4Float b)
-{
-    return { vec_andc(b.simdInternal_, a.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall operator|(Simd4Float a, Simd4Float b)
-{
-    return { vec_or(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall operator^(Simd4Float a, Simd4Float b)
-{
-    return { vec_xor(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall operator+(Simd4Float a, Simd4Float b)
-{
-    return { vec_add(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall operator-(Simd4Float a, Simd4Float b)
-{
-    return { vec_sub(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall operator-(Simd4Float x)
-{
-    return { vec_xor(x.simdInternal_,
-                     reinterpret_cast<__vector float>(vec_sl(vec_splat_u32(-1), vec_splat_u32(-1)))) };
-}
-
-static inline Simd4Float gmx_simdcall operator*(Simd4Float a, Simd4Float b)
-{
-    return { vec_madd(a.simdInternal_, b.simdInternal_,
-                      reinterpret_cast<__vector float>(vec_splat_u32(0))) };
-}
-
-static inline Simd4Float gmx_simdcall fma(Simd4Float a, Simd4Float b, Simd4Float c)
-{
-    return { vec_madd(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall fms(Simd4Float a, Simd4Float b, Simd4Float c)
-{
-    return { vec_madd(a.simdInternal_, b.simdInternal_, -c.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall fnma(Simd4Float a, Simd4Float b, Simd4Float c)
-{
-    return { vec_nmsub(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall fnms(Simd4Float a, Simd4Float b, Simd4Float c)
-{
-    return { -vec_madd(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall rsqrt(Simd4Float x)
-{
-    return { vec_rsqrte(x.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall abs(Simd4Float x)
-{
-    return { vec_abs(x.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall max(Simd4Float a, Simd4Float b)
-{
-    return { vec_max(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall min(Simd4Float a, Simd4Float b)
-{
-    return { vec_min(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall round(Simd4Float x)
-{
-    return { vec_round(x.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall trunc(Simd4Float x)
-{
-    return { vec_trunc(x.simdInternal_) };
-}
-
-static inline float gmx_simdcall dotProduct(Simd4Float a, Simd4Float b)
-{
-    float res;
-
-    __vector float c = vec_madd(a.simdInternal_, b.simdInternal_,
-                                reinterpret_cast<__vector float>(vec_splat_u32(0)));
-    // Keep only elements 0,1,2 by shifting in zero from right (xor of a vector with itself is 0)
-    c = vec_sld(c, vec_xor(a.simdInternal_, a.simdInternal_), 4);
-    // calculate sum
-    c = vec_add(c, vec_sld(c, c, 8));
-    c = vec_add(c, vec_sld(c, c, 4));
-    vec_ste(c, 0, &res);
-    return res;
-}
-
-static inline void gmx_simdcall transpose(Simd4Float* v0, Simd4Float* v1, Simd4Float* v2, Simd4Float* v3)
-{
-    __vector float t0 = vec_mergeh(v0->simdInternal_, v2->simdInternal_);
-    __vector float t1 = vec_mergel(v0->simdInternal_, v2->simdInternal_);
-    __vector float t2 = vec_mergeh(v1->simdInternal_, v3->simdInternal_);
-    __vector float t3 = vec_mergel(v1->simdInternal_, v3->simdInternal_);
-    v0->simdInternal_ = vec_mergeh(t0, t2);
-    v1->simdInternal_ = vec_mergel(t0, t2);
-    v2->simdInternal_ = vec_mergeh(t1, t3);
-    v3->simdInternal_ = vec_mergel(t1, t3);
-}
-
-static inline Simd4FBool gmx_simdcall operator==(Simd4Float a, Simd4Float b)
-{
-    return { vec_cmpeq(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4FBool gmx_simdcall operator!=(Simd4Float a, Simd4Float b)
-{
-    return { vec_or(vec_cmpgt(a.simdInternal_, b.simdInternal_),
-                    vec_cmplt(a.simdInternal_, b.simdInternal_)) };
-}
-
-static inline Simd4FBool gmx_simdcall operator<(Simd4Float a, Simd4Float b)
-{
-    return { vec_cmplt(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4FBool gmx_simdcall operator<=(Simd4Float a, Simd4Float b)
-{
-    return { vec_cmple(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4FBool gmx_simdcall operator&&(Simd4FBool a, Simd4FBool b)
-{
-    return { vec_and(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4FBool gmx_simdcall operator||(Simd4FBool a, Simd4FBool b)
-{
-    return { vec_or(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline bool gmx_simdcall anyTrue(Simd4FBool a)
-{
-    return vec_any_ne(a.simdInternal_, reinterpret_cast<__vector vmxBool int>(vec_splat_u32(0)));
-}
-
-static inline Simd4Float gmx_simdcall selectByMask(Simd4Float a, Simd4FBool m)
-{
-    return { vec_and(a.simdInternal_, reinterpret_cast<__vector float>(m.simdInternal_)) };
-}
-
-static inline Simd4Float gmx_simdcall selectByNotMask(Simd4Float a, Simd4FBool m)
-{
-    return { vec_andc(a.simdInternal_, reinterpret_cast<__vector float>(m.simdInternal_)) };
-}
-
-static inline Simd4Float gmx_simdcall blend(Simd4Float a, Simd4Float b, Simd4FBool sel)
-{
-    return { vec_sel(a.simdInternal_, b.simdInternal_, sel.simdInternal_) };
-}
-
-static inline float gmx_simdcall reduce(Simd4Float a)
-{
-    __vector float c = a.simdInternal_;
-    float          res;
-
-    // calculate sum
-    c = vec_add(c, vec_sld(c, c, 8));
-    c = vec_add(c, vec_sld(c, c, 4));
-    vec_ste(c, 0, &res);
-    return res;
-}
-
-} // namespace gmx
-
-#endif // GMX_SIMD_IMPLEMENTATION_IBM_VMX_SIMD4_FLOAT_H
diff --git a/src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_simd_float.h b/src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_simd_float.h
deleted file mode 100644 (file)
index 4284e00..0000000
+++ /dev/null
@@ -1,517 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2016,2017,2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPLEMENTATION_IBM_VMX_SIMD_FLOAT_H
-#define GMX_SIMD_IMPLEMENTATION_IBM_VMX_SIMD_FLOAT_H
-
-#include "config.h"
-
-#include <cstdint>
-
-#include "gromacs/math/utilities.h"
-#include "gromacs/utility/basedefinitions.h"
-
-#include "impl_ibm_vmx_definitions.h"
-
-namespace gmx
-{
-
-class SimdFloat
-{
-public:
-    SimdFloat() {}
-
-    SimdFloat(float f)
-    {
-        __vector unsigned char perm;
-
-        simdInternal_ = vec_lde(0, const_cast<float*>(&f));
-        perm          = vec_lvsl(0, const_cast<float*>(&f));
-        simdInternal_ = vec_perm(simdInternal_, simdInternal_, perm);
-        simdInternal_ = vec_splat(simdInternal_, 0);
-    }
-
-    // Internal utility constructor to simplify return statements
-    SimdFloat(__vector float simd) : simdInternal_(simd) {}
-
-    __vector float simdInternal_;
-};
-
-class SimdFInt32
-{
-public:
-    SimdFInt32() {}
-
-    SimdFInt32(std::int32_t i)
-    {
-        __vector unsigned char perm;
-
-        simdInternal_ = vec_lde(0, const_cast<int*>(&i));
-        perm          = vec_lvsl(0, const_cast<int*>(&i));
-        simdInternal_ = vec_perm(simdInternal_, simdInternal_, perm);
-        simdInternal_ = vec_splat(simdInternal_, 0);
-    }
-
-
-    // Internal utility constructor to simplify return statements
-    SimdFInt32(__vector signed int simd) : simdInternal_(simd) {}
-
-    __vector signed int simdInternal_;
-};
-
-class SimdFBool
-{
-public:
-    SimdFBool() {}
-
-    SimdFBool(bool b) :
-        simdInternal_(reinterpret_cast<__vector vmxBool int>(vec_splats(b ? 0xFFFFFFFF : 0)))
-    {
-    }
-
-    // Internal utility constructor to simplify return statements
-    SimdFBool(__vector vmxBool int simd) : simdInternal_(simd) {}
-
-    __vector vmxBool int simdInternal_;
-};
-
-class SimdFIBool
-{
-public:
-    SimdFIBool() {}
-
-    SimdFIBool(bool b) :
-        simdInternal_(reinterpret_cast<__vector vmxBool int>(vec_splat_u32(b ? 0xFFFFFFFF : 0)))
-    {
-    }
-
-    // Internal utility constructor to simplify return statements
-    SimdFIBool(__vector vmxBool int simd) : simdInternal_(simd) {}
-
-    __vector vmxBool int simdInternal_;
-};
-
-static inline SimdFloat gmx_simdcall simdLoad(const float* m, SimdFloatTag = {})
-{
-    return { vec_ld(0, const_cast<float*>(m)) };
-}
-
-static inline void gmx_simdcall store(float* m, SimdFloat a)
-{
-    vec_st(a.simdInternal_, 0, const_cast<float*>(m));
-}
-
-static inline SimdFloat gmx_simdcall setZeroF()
-{
-    return { reinterpret_cast<__vector float>(vec_splat_u32(0)) };
-}
-
-static inline SimdFInt32 gmx_simdcall simdLoad(const std::int32_t* m, SimdFInt32Tag)
-{
-    return { vec_ld(0, const_cast<int*>(m)) };
-}
-
-static inline void gmx_simdcall store(std::int32_t* m, SimdFInt32 a)
-{
-    vec_st(a.simdInternal_, 0, const_cast<int*>(m));
-}
-
-static inline SimdFInt32 gmx_simdcall setZeroFI()
-{
-    return { vec_splat_s32(0) };
-}
-
-static inline SimdFloat gmx_simdcall operator&(SimdFloat a, SimdFloat b)
-{
-    return { vec_and(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall andNot(SimdFloat a, SimdFloat b)
-{
-    return { vec_andc(b.simdInternal_, a.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall operator|(SimdFloat a, SimdFloat b)
-{
-    return { vec_or(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall operator^(SimdFloat a, SimdFloat b)
-{
-    return { vec_xor(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall operator+(SimdFloat a, SimdFloat b)
-{
-    return { vec_add(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall operator-(SimdFloat a, SimdFloat b)
-{
-    return { vec_sub(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall operator-(SimdFloat x)
-{
-    return { vec_xor(x.simdInternal_,
-                     reinterpret_cast<__vector float>(vec_sl(vec_splat_u32(-1), vec_splat_u32(-1)))) };
-}
-
-static inline SimdFloat gmx_simdcall operator*(SimdFloat a, SimdFloat b)
-{
-    return { vec_madd(a.simdInternal_, b.simdInternal_,
-                      reinterpret_cast<__vector float>(vec_splat_u32(0))) };
-}
-
-static inline SimdFloat gmx_simdcall fma(SimdFloat a, SimdFloat b, SimdFloat c)
-{
-    return { vec_madd(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall fms(SimdFloat a, SimdFloat b, SimdFloat c)
-{
-    return { vec_madd(a.simdInternal_, b.simdInternal_, -c.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall fnma(SimdFloat a, SimdFloat b, SimdFloat c)
-{
-    return { vec_nmsub(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall fnms(SimdFloat a, SimdFloat b, SimdFloat c)
-{
-    return { -vec_madd(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall rsqrt(SimdFloat x)
-{
-    return { vec_rsqrte(x.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall rcp(SimdFloat x)
-{
-    return { vec_re(x.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall maskAdd(SimdFloat a, SimdFloat b, SimdFBool m)
-{
-    return { vec_add(a.simdInternal_,
-                     vec_and(b.simdInternal_, reinterpret_cast<__vector float>(m.simdInternal_))) };
-}
-
-static inline SimdFloat gmx_simdcall maskzMul(SimdFloat a, SimdFloat b, SimdFBool m)
-{
-    SimdFloat prod = a * b;
-
-    return { vec_and(prod.simdInternal_, reinterpret_cast<__vector float>(m.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall maskzFma(SimdFloat a, SimdFloat b, SimdFloat c, SimdFBool m)
-{
-    SimdFloat prod = fma(a, b, c);
-
-    return { vec_and(prod.simdInternal_, reinterpret_cast<__vector float>(m.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall maskzRsqrt(SimdFloat x, SimdFBool m)
-{
-#ifndef NDEBUG
-    SimdFloat one(1.0F);
-    x.simdInternal_ = vec_sel(one.simdInternal_, x.simdInternal_, m.simdInternal_);
-#endif
-    return { vec_and(vec_rsqrte(x.simdInternal_), reinterpret_cast<__vector float>(m.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall maskzRcp(SimdFloat x, SimdFBool m)
-{
-#ifndef NDEBUG
-    SimdFloat one(1.0F);
-    x.simdInternal_ = vec_sel(one.simdInternal_, x.simdInternal_, m.simdInternal_);
-#endif
-    return { vec_and(vec_re(x.simdInternal_), reinterpret_cast<__vector float>(m.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall abs(SimdFloat x)
-{
-    return { vec_abs(x.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall max(SimdFloat a, SimdFloat b)
-{
-    return { vec_max(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall min(SimdFloat a, SimdFloat b)
-{
-    return { vec_min(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall round(SimdFloat x)
-{
-    return { vec_round(x.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall trunc(SimdFloat x)
-{
-    return { vec_trunc(x.simdInternal_) };
-}
-
-template<MathOptimization opt = MathOptimization::Safe>
-static inline SimdFloat gmx_simdcall frexp(SimdFloat value, SimdFInt32* exponent)
-{
-    // Generate constants without memory operations
-    const __vector signed int exponentMask =
-            vec_sl(vec_add(vec_splat_s32(15), vec_sl(vec_splat_s32(15), vec_splat_u32(4))),
-                   vec_add(vec_splat_u32(15), vec_splat_u32(8))); // 0x7F800000
-    const __vector signed int exponentBias =
-            vec_sub(vec_sl(vec_splat_s32(1), vec_splat_u32(7)), vec_splat_s32(2)); // 126
-    const SimdFloat     half(0.5F);
-    __vector signed int iExponent;
-
-    __vector vmxBool int valueIsZero =
-            vec_cmpeq(value.simdInternal_, reinterpret_cast<__vector float>(vec_splat_u32(0)));
-
-    iExponent = vec_and(reinterpret_cast<__vector signed int>(value.simdInternal_), exponentMask);
-    iExponent = vec_sr(iExponent, vec_add(vec_splat_u32(15), vec_splat_u32(8)));
-    iExponent = vec_sub(iExponent, exponentBias);
-    iExponent = vec_andc(iExponent, reinterpret_cast<__vector int>(valueIsZero));
-
-    __vector float result =
-            vec_or(vec_andc(value.simdInternal_, reinterpret_cast<__vector float>(exponentMask)),
-                   half.simdInternal_);
-    result = vec_sel(result, value.simdInternal_, valueIsZero);
-
-    exponent->simdInternal_ = iExponent;
-
-    return { result };
-}
-
-template<MathOptimization opt = MathOptimization::Safe>
-static inline SimdFloat gmx_simdcall ldexp(SimdFloat value, SimdFInt32 exponent)
-{
-    const __vector signed int exponentBias =
-            vec_sub(vec_sl(vec_splat_s32(1), vec_splat_u32(7)), vec_splat_s32(1)); // 127
-    __vector signed int iExponent;
-
-    iExponent = vec_add(exponent.simdInternal_, exponentBias);
-
-    if (opt == MathOptimization::Safe)
-    {
-        // Make sure biased argument is not negative
-        iExponent = vec_max(iExponent, vec_splat_s32(0));
-    }
-
-    iExponent = vec_sl(iExponent, vec_add(vec_splat_u32(15), vec_splat_u32(8)));
-
-    return { vec_madd(value.simdInternal_, reinterpret_cast<__vector float>(iExponent),
-                      reinterpret_cast<__vector float>(vec_splat_u32(0))) };
-}
-
-static inline float gmx_simdcall reduce(SimdFloat a)
-{
-    __vector float c = a.simdInternal_;
-    float          res;
-
-    // calculate sum
-    c = vec_add(c, vec_sld(c, c, 8));
-    c = vec_add(c, vec_sld(c, c, 4));
-    vec_ste(c, 0, &res);
-    return res;
-}
-
-static inline SimdFBool gmx_simdcall operator==(SimdFloat a, SimdFloat b)
-{
-    return { vec_cmpeq(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFBool gmx_simdcall operator!=(SimdFloat a, SimdFloat b)
-{
-    return { vec_or(vec_cmpgt(a.simdInternal_, b.simdInternal_),
-                    vec_cmplt(a.simdInternal_, b.simdInternal_)) };
-}
-
-static inline SimdFBool gmx_simdcall operator<(SimdFloat a, SimdFloat b)
-{
-    return { vec_cmplt(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFBool gmx_simdcall operator<=(SimdFloat a, SimdFloat b)
-{
-    return { vec_cmple(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFBool gmx_simdcall testBits(SimdFloat a)
-{
-    return { vec_cmpgt(reinterpret_cast<__vector unsigned int>(a.simdInternal_), vec_splat_u32(0)) };
-}
-
-static inline SimdFBool gmx_simdcall operator&&(SimdFBool a, SimdFBool b)
-{
-    return { vec_and(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFBool gmx_simdcall operator||(SimdFBool a, SimdFBool b)
-{
-    return { vec_or(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline bool gmx_simdcall anyTrue(SimdFBool a)
-{
-    return vec_any_ne(a.simdInternal_, reinterpret_cast<__vector vmxBool int>(vec_splat_u32(0)));
-}
-
-static inline SimdFloat gmx_simdcall selectByMask(SimdFloat a, SimdFBool m)
-{
-    return { vec_and(a.simdInternal_, reinterpret_cast<__vector float>(m.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall selectByNotMask(SimdFloat a, SimdFBool m)
-{
-    return { vec_andc(a.simdInternal_, reinterpret_cast<__vector float>(m.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall blend(SimdFloat a, SimdFloat b, SimdFBool sel)
-{
-    return { vec_sel(a.simdInternal_, b.simdInternal_, sel.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator&(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vec_and(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall andNot(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vec_andc(b.simdInternal_, a.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator|(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vec_or(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator^(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vec_xor(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator+(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vec_add(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator-(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vec_sub(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator*(SimdFInt32 a, SimdFInt32 b)
-{
-    return { a.simdInternal_ * b.simdInternal_ };
-}
-
-static inline SimdFIBool gmx_simdcall operator==(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vec_cmpeq(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFIBool gmx_simdcall testBits(SimdFInt32 a)
-{
-    return { vec_cmpgt(reinterpret_cast<__vector unsigned int>(a.simdInternal_), vec_splat_u32(0)) };
-}
-
-static inline SimdFIBool gmx_simdcall operator<(SimdFInt32 a, SimdFInt32 b)
-{
-    return { vec_cmplt(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFIBool gmx_simdcall operator&&(SimdFIBool a, SimdFIBool b)
-{
-    return { vec_and(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFIBool gmx_simdcall operator||(SimdFIBool a, SimdFIBool b)
-{
-    return { vec_or(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline bool gmx_simdcall anyTrue(SimdFIBool a)
-{
-    return vec_any_ne(a.simdInternal_, reinterpret_cast<__vector vmxBool int>(vec_splat_u32(0)));
-}
-
-static inline SimdFInt32 gmx_simdcall selectByMask(SimdFInt32 a, SimdFIBool m)
-{
-    return { vec_and(a.simdInternal_, reinterpret_cast<__vector signed int>(m.simdInternal_)) };
-}
-
-static inline SimdFInt32 gmx_simdcall selectByNotMask(SimdFInt32 a, SimdFIBool m)
-{
-    return { vec_andc(a.simdInternal_, reinterpret_cast<__vector signed int>(m.simdInternal_)) };
-}
-
-static inline SimdFInt32 gmx_simdcall blend(SimdFInt32 a, SimdFInt32 b, SimdFIBool sel)
-{
-    return { vec_sel(a.simdInternal_, b.simdInternal_, sel.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall cvtR2I(SimdFloat a)
-{
-    return { vec_cts(vec_round(a.simdInternal_), 0) };
-}
-
-static inline SimdFInt32 gmx_simdcall cvttR2I(SimdFloat a)
-{
-    return { vec_cts(a.simdInternal_, 0) };
-}
-
-static inline SimdFloat gmx_simdcall cvtI2R(SimdFInt32 a)
-{
-    return { vec_ctf(a.simdInternal_, 0) };
-}
-
-static inline SimdFIBool gmx_simdcall cvtB2IB(SimdFBool a)
-{
-    return { a.simdInternal_ };
-}
-
-static inline SimdFBool gmx_simdcall cvtIB2B(SimdFIBool a)
-{
-    return { a.simdInternal_ };
-}
-
-} // namespace gmx
-
-#endif // GMX_SIMD_IMPLEMENTATION_IBM_VMX_SIMD_FLOAT_H
diff --git a/src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_util_float.h b/src/gromacs/simd/impl_ibm_vmx/impl_ibm_vmx_util_float.h
deleted file mode 100644 (file)
index 95f424d..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_IBM_VMX_UTIL_FLOAT_H
-#define GMX_SIMD_IMPL_IBM_VMX_UTIL_FLOAT_H
-
-#include "config.h"
-
-#include <cstddef>
-#include <cstdint>
-
-#include "gromacs/utility/basedefinitions.h"
-
-#include "impl_ibm_vmx_definitions.h"
-#include "impl_ibm_vmx_simd_float.h"
-
-namespace gmx
-{
-
-template<int align>
-static inline void gmx_simdcall gatherLoadTranspose(const float*       base,
-                                                    const std::int32_t offset[],
-                                                    SimdFloat*         v0,
-                                                    SimdFloat*         v1,
-                                                    SimdFloat*         v2,
-                                                    SimdFloat*         v3)
-{
-    *v0 = simdLoad(base + align * offset[0]);
-    *v1 = simdLoad(base + align * offset[1]);
-    *v2 = simdLoad(base + align * offset[2]);
-    *v3 = simdLoad(base + align * offset[3]);
-
-    __vector float t0 = vec_mergeh(v0->simdInternal_, v2->simdInternal_);
-    __vector float t1 = vec_mergel(v0->simdInternal_, v2->simdInternal_);
-    __vector float t2 = vec_mergeh(v1->simdInternal_, v3->simdInternal_);
-    __vector float t3 = vec_mergel(v1->simdInternal_, v3->simdInternal_);
-    v0->simdInternal_ = vec_mergeh(t0, t2);
-    v1->simdInternal_ = vec_mergel(t0, t2);
-    v2->simdInternal_ = vec_mergeh(t1, t3);
-    v3->simdInternal_ = vec_mergel(t1, t3);
-}
-
-template<int align>
-static inline void gmx_simdcall
-                   gatherLoadTranspose(const float* base, const std::int32_t offset[], SimdFloat* v0, SimdFloat* v1)
-{
-    if (align % 4 == 0)
-    {
-        SimdFloat t2, t3;
-
-        gatherLoadTranspose<align>(base, offset, v0, v1, &t2, &t3);
-    }
-    else
-    {
-        __vector float         t0, t1, t2, t3, t4, t5, t6, t7;
-        __vector unsigned char p0, p1, p2, p3;
-
-        // This is REALLY slow, since we have no choice but to load individual
-        // elements when we cannot guarantee that we can access beyond the end of
-        // the memory. Fortunately, 99% of the usage should be the aligned-to-4
-        // case above instead.
-        t0                = vec_lde(0, base + align * offset[0]);
-        t1                = vec_lde(0, base + align * offset[1]);
-        t2                = vec_lde(0, base + align * offset[2]);
-        t3                = vec_lde(0, base + align * offset[3]);
-        p0                = vec_lvsl(0, base + align * offset[0]);
-        p1                = vec_lvsl(0, base + align * offset[1]);
-        p2                = vec_lvsl(0, base + align * offset[2]);
-        p3                = vec_lvsl(0, base + align * offset[3]);
-        t0                = vec_perm(t0, t0, p0);
-        t1                = vec_perm(t1, t1, p1);
-        t2                = vec_perm(t2, t2, p2);
-        t3                = vec_perm(t3, t3, p3);
-        t0                = vec_mergeh(t0, t2);
-        t1                = vec_mergeh(t1, t3);
-        v0->simdInternal_ = vec_mergeh(t0, t1);
-
-        t4                = vec_lde(0, base + align * offset[0] + 1);
-        t5                = vec_lde(0, base + align * offset[1] + 1);
-        t6                = vec_lde(0, base + align * offset[2] + 1);
-        t7                = vec_lde(0, base + align * offset[3] + 1);
-        p0                = vec_lvsl(0, base + align * offset[0] + 1);
-        p1                = vec_lvsl(0, base + align * offset[1] + 1);
-        p2                = vec_lvsl(0, base + align * offset[2] + 1);
-        p3                = vec_lvsl(0, base + align * offset[3] + 1);
-        t4                = vec_perm(t4, t4, p0);
-        t5                = vec_perm(t5, t5, p1);
-        t6                = vec_perm(t6, t6, p2);
-        t7                = vec_perm(t7, t7, p3);
-        t4                = vec_mergeh(t4, t6);
-        t5                = vec_mergeh(t5, t7);
-        v1->simdInternal_ = vec_mergeh(t4, t5);
-    }
-}
-
-static const int c_simdBestPairAlignmentFloat = 2;
-
-template<int align>
-static inline void gmx_simdcall gatherLoadUTranspose(const float*       base,
-                                                     const std::int32_t offset[],
-                                                     SimdFloat*         v0,
-                                                     SimdFloat*         v1,
-                                                     SimdFloat*         v2)
-{
-    if (align % 4 == 0)
-    {
-        SimdFloat t3;
-        gatherLoadTranspose<align>(base, offset, v0, v1, v2, &t3);
-    }
-    else
-    {
-        __vector float         t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11;
-        __vector unsigned char p0, p1, p2, p3;
-
-        // This is REALLY slow, since we have no choice but to load individual
-        // elements when we cannot guarantee that we can access beyond the end of
-        // the memory. Unfortunately this is likely the most common case.
-        t0                = vec_lde(0, base + align * offset[0]);
-        t1                = vec_lde(0, base + align * offset[1]);
-        t2                = vec_lde(0, base + align * offset[2]);
-        t3                = vec_lde(0, base + align * offset[3]);
-        p0                = vec_lvsl(0, base + align * offset[0]);
-        p1                = vec_lvsl(0, base + align * offset[1]);
-        p2                = vec_lvsl(0, base + align * offset[2]);
-        p3                = vec_lvsl(0, base + align * offset[3]);
-        t0                = vec_perm(t0, t0, p0);
-        t1                = vec_perm(t1, t1, p1);
-        t2                = vec_perm(t2, t2, p2);
-        t3                = vec_perm(t3, t3, p3);
-        t0                = vec_mergeh(t0, t2);
-        t1                = vec_mergeh(t1, t3);
-        v0->simdInternal_ = vec_mergeh(t0, t1);
-
-        t4                = vec_lde(0, base + align * offset[0] + 1);
-        t5                = vec_lde(0, base + align * offset[1] + 1);
-        t6                = vec_lde(0, base + align * offset[2] + 1);
-        t7                = vec_lde(0, base + align * offset[3] + 1);
-        p0                = vec_lvsl(0, base + align * offset[0] + 1);
-        p1                = vec_lvsl(0, base + align * offset[1] + 1);
-        p2                = vec_lvsl(0, base + align * offset[2] + 1);
-        p3                = vec_lvsl(0, base + align * offset[3] + 1);
-        t4                = vec_perm(t4, t4, p0);
-        t5                = vec_perm(t5, t5, p1);
-        t6                = vec_perm(t6, t6, p2);
-        t7                = vec_perm(t7, t7, p3);
-        t4                = vec_mergeh(t4, t6);
-        t5                = vec_mergeh(t5, t7);
-        v1->simdInternal_ = vec_mergeh(t4, t5);
-
-        t8                = vec_lde(0, base + align * offset[0] + 2);
-        t9                = vec_lde(0, base + align * offset[1] + 2);
-        t10               = vec_lde(0, base + align * offset[2] + 2);
-        t11               = vec_lde(0, base + align * offset[3] + 2);
-        p0                = vec_lvsl(0, base + align * offset[0] + 2);
-        p1                = vec_lvsl(0, base + align * offset[1] + 2);
-        p2                = vec_lvsl(0, base + align * offset[2] + 2);
-        p3                = vec_lvsl(0, base + align * offset[3] + 2);
-        t8                = vec_perm(t8, t8, p0);
-        t9                = vec_perm(t9, t9, p1);
-        t10               = vec_perm(t10, t10, p2);
-        t11               = vec_perm(t11, t11, p3);
-        t8                = vec_mergeh(t8, t10);
-        t9                = vec_mergeh(t9, t11);
-        v2->simdInternal_ = vec_mergeh(t8, t9);
-    }
-}
-
-
-template<int align>
-static inline void gmx_simdcall
-                   transposeScatterStoreU(float* base, const std::int32_t offset[], SimdFloat v0, SimdFloat v1, SimdFloat v2)
-{
-    __vector unsigned char p0, p1, p2, p3;
-
-    __vector float t0 = vec_mergeh(v0.simdInternal_, v2.simdInternal_);
-    __vector float t1 = vec_mergel(v0.simdInternal_, v2.simdInternal_);
-    __vector float t2 = vec_mergeh(v1.simdInternal_, v2.simdInternal_);
-    __vector float t3 = vec_mergel(v1.simdInternal_, v2.simdInternal_);
-    __vector float t4 = vec_mergeh(t0, t2);
-    __vector float t5 = vec_mergel(t0, t2);
-    __vector float t6 = vec_mergeh(t1, t3);
-    __vector float t7 = vec_mergel(t1, t3);
-
-    p0 = vec_lvsr(0, base + align * offset[0]);
-    p1 = vec_lvsr(0, base + align * offset[1]);
-    p2 = vec_lvsr(0, base + align * offset[2]);
-    p3 = vec_lvsr(0, base + align * offset[3]);
-
-    t4 = vec_perm(t4, t4, p0);
-    t5 = vec_perm(t5, t5, p1);
-    t6 = vec_perm(t6, t6, p2);
-    t7 = vec_perm(t7, t7, p3);
-
-    vec_ste(t4, 0, base + align * offset[0]);
-    vec_ste(t4, 4, base + align * offset[0]);
-    vec_ste(t4, 8, base + align * offset[0]);
-    vec_ste(t5, 0, base + align * offset[1]);
-    vec_ste(t5, 4, base + align * offset[1]);
-    vec_ste(t5, 8, base + align * offset[1]);
-    vec_ste(t6, 0, base + align * offset[2]);
-    vec_ste(t6, 4, base + align * offset[2]);
-    vec_ste(t6, 8, base + align * offset[2]);
-    vec_ste(t7, 0, base + align * offset[3]);
-    vec_ste(t7, 4, base + align * offset[3]);
-    vec_ste(t7, 8, base + align * offset[3]);
-}
-
-
-template<int align>
-static inline void gmx_simdcall
-                   transposeScatterIncrU(float* base, const std::int32_t offset[], SimdFloat v0, SimdFloat v1, SimdFloat v2)
-{
-    if (align % 4 == 0)
-    {
-        __vector float zero = reinterpret_cast<__vector float>(vec_splat_u32(0));
-        __vector float t0   = vec_mergeh(v0.simdInternal_, v2.simdInternal_);
-        __vector float t1   = vec_mergel(v0.simdInternal_, v2.simdInternal_);
-        __vector float t2   = vec_mergeh(v1.simdInternal_, zero);
-        __vector float t3   = vec_mergel(v1.simdInternal_, zero);
-        __vector float t4   = vec_mergeh(t0, t2);
-        __vector float t5   = vec_mergel(t0, t2);
-        __vector float t6   = vec_mergeh(t1, t3);
-        __vector float t7   = vec_mergel(t1, t3);
-
-        vec_st(vec_add(vec_ld(0, base + align * offset[0]), t4), 0, base + align * offset[0]);
-        vec_st(vec_add(vec_ld(0, base + align * offset[1]), t5), 0, base + align * offset[1]);
-        vec_st(vec_add(vec_ld(0, base + align * offset[2]), t6), 0, base + align * offset[2]);
-        vec_st(vec_add(vec_ld(0, base + align * offset[3]), t7), 0, base + align * offset[3]);
-    }
-    else
-    {
-        alignas(GMX_SIMD_ALIGNMENT) float rdata0[GMX_SIMD_FLOAT_WIDTH];
-        alignas(GMX_SIMD_ALIGNMENT) float rdata1[GMX_SIMD_FLOAT_WIDTH];
-        alignas(GMX_SIMD_ALIGNMENT) float rdata2[GMX_SIMD_FLOAT_WIDTH];
-
-        vec_st(v0.simdInternal_, 0, rdata0);
-        vec_st(v1.simdInternal_, 0, rdata1);
-        vec_st(v2.simdInternal_, 0, rdata2);
-
-        base[align * offset[0] + 0] += rdata0[0];
-        base[align * offset[0] + 1] += rdata1[0];
-        base[align * offset[0] + 2] += rdata2[0];
-        base[align * offset[1] + 0] += rdata0[1];
-        base[align * offset[1] + 1] += rdata1[1];
-        base[align * offset[1] + 2] += rdata2[1];
-        base[align * offset[2] + 0] += rdata0[2];
-        base[align * offset[2] + 1] += rdata1[2];
-        base[align * offset[2] + 2] += rdata2[2];
-        base[align * offset[3] + 0] += rdata0[3];
-        base[align * offset[3] + 1] += rdata1[3];
-        base[align * offset[3] + 2] += rdata2[3];
-    }
-}
-
-template<int align>
-static inline void gmx_simdcall
-                   transposeScatterDecrU(float* base, const std::int32_t offset[], SimdFloat v0, SimdFloat v1, SimdFloat v2)
-{
-    if (align % 4 == 0)
-    {
-        __vector float zero = reinterpret_cast<__vector float>(vec_splat_u32(0));
-        __vector float t0   = vec_mergeh(v0.simdInternal_, v2.simdInternal_);
-        __vector float t1   = vec_mergel(v0.simdInternal_, v2.simdInternal_);
-        __vector float t2   = vec_mergeh(v1.simdInternal_, zero);
-        __vector float t3   = vec_mergel(v1.simdInternal_, zero);
-        __vector float t4   = vec_mergeh(t0, t2);
-        __vector float t5   = vec_mergel(t0, t2);
-        __vector float t6   = vec_mergeh(t1, t3);
-        __vector float t7   = vec_mergel(t1, t3);
-
-        vec_st(vec_sub(vec_ld(0, base + align * offset[0]), t4), 0, base + align * offset[0]);
-        vec_st(vec_sub(vec_ld(0, base + align * offset[1]), t5), 0, base + align * offset[1]);
-        vec_st(vec_sub(vec_ld(0, base + align * offset[2]), t6), 0, base + align * offset[2]);
-        vec_st(vec_sub(vec_ld(0, base + align * offset[3]), t7), 0, base + align * offset[3]);
-    }
-    else
-    {
-        alignas(GMX_SIMD_ALIGNMENT) float rdata0[GMX_SIMD_FLOAT_WIDTH];
-        alignas(GMX_SIMD_ALIGNMENT) float rdata1[GMX_SIMD_FLOAT_WIDTH];
-        alignas(GMX_SIMD_ALIGNMENT) float rdata2[GMX_SIMD_FLOAT_WIDTH];
-
-        vec_st(v0.simdInternal_, 0, rdata0);
-        vec_st(v1.simdInternal_, 0, rdata1);
-        vec_st(v2.simdInternal_, 0, rdata2);
-
-        base[align * offset[0] + 0] -= rdata0[0];
-        base[align * offset[0] + 1] -= rdata1[0];
-        base[align * offset[0] + 2] -= rdata2[0];
-        base[align * offset[1] + 0] -= rdata0[1];
-        base[align * offset[1] + 1] -= rdata1[1];
-        base[align * offset[1] + 2] -= rdata2[1];
-        base[align * offset[2] + 0] -= rdata0[2];
-        base[align * offset[2] + 1] -= rdata1[2];
-        base[align * offset[2] + 2] -= rdata2[2];
-        base[align * offset[3] + 0] -= rdata0[3];
-        base[align * offset[3] + 1] -= rdata1[3];
-        base[align * offset[3] + 2] -= rdata2[3];
-    }
-}
-
-static inline void gmx_simdcall expandScalarsToTriplets(SimdFloat  scalar,
-                                                        SimdFloat* triplets0,
-                                                        SimdFloat* triplets1,
-                                                        SimdFloat* triplets2)
-{
-    const __vector unsigned char perm0 = { 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7 };
-    const __vector unsigned char perm1 = { 4, 5, 6, 7, 4, 5, 6, 7, 8, 9, 10, 11, 8, 9, 10, 11 };
-    const __vector unsigned char perm2 = { 8,  9,  10, 11, 12, 13, 14, 15,
-                                           12, 13, 14, 15, 12, 13, 14, 15 };
-
-    triplets0->simdInternal_ = vec_perm(scalar.simdInternal_, scalar.simdInternal_, perm0);
-    triplets1->simdInternal_ = vec_perm(scalar.simdInternal_, scalar.simdInternal_, perm1);
-    triplets2->simdInternal_ = vec_perm(scalar.simdInternal_, scalar.simdInternal_, perm2);
-}
-
-
-template<int align>
-static inline void gmx_simdcall gatherLoadBySimdIntTranspose(const float* base,
-                                                             SimdFInt32   offset,
-                                                             SimdFloat*   v0,
-                                                             SimdFloat*   v1,
-                                                             SimdFloat*   v2,
-                                                             SimdFloat*   v3)
-{
-    alignas(GMX_SIMD_ALIGNMENT) std::int32_t ioffset[GMX_SIMD_FINT32_WIDTH];
-
-    vec_st(offset.simdInternal_, 0, ioffset);
-    gatherLoadTranspose<align>(base, ioffset, v0, v1, v2, v3);
-}
-
-template<int align>
-static inline void gmx_simdcall
-                   gatherLoadBySimdIntTranspose(const float* base, SimdFInt32 offset, SimdFloat* v0, SimdFloat* v1)
-{
-    alignas(GMX_SIMD_ALIGNMENT) std::int32_t ioffset[GMX_SIMD_FINT32_WIDTH];
-
-    vec_st(offset.simdInternal_, 0, ioffset);
-    gatherLoadTranspose<align>(base, ioffset, v0, v1);
-}
-
-
-static inline float gmx_simdcall reduceIncr4ReturnSum(float* m, SimdFloat v0, SimdFloat v1, SimdFloat v2, SimdFloat v3)
-{
-    __vector float t0 = vec_mergeh(v0.simdInternal_, v2.simdInternal_);
-    __vector float t1 = vec_mergel(v0.simdInternal_, v2.simdInternal_);
-    __vector float t2 = vec_mergeh(v1.simdInternal_, v3.simdInternal_);
-    __vector float t3 = vec_mergel(v1.simdInternal_, v3.simdInternal_);
-    v0.simdInternal_  = vec_mergeh(t0, t2);
-    v1.simdInternal_  = vec_mergel(t0, t2);
-    v2.simdInternal_  = vec_mergeh(t1, t3);
-    v3.simdInternal_  = vec_mergel(t1, t3);
-
-    v0 = v0 + v1;
-    v2 = v2 + v3;
-    v0 = v0 + v2;
-    v2 = v0 + simdLoad(m);
-    store(m, v2);
-
-    return reduce(v0);
-}
-
-} // namespace gmx
-
-#endif // GMX_SIMD_IMPL_IBM_VMX_UTIL_FLOAT_H
index 3c6f3009b17249895b49c14fa763f15e814972c3..53981ed8a7d6b54af3c684af189c25c4df4057a7 100644 (file)
@@ -415,10 +415,11 @@ static inline double gmx_simdcall reduce(SimdDouble x)
     const __vector unsigned char perm = { 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7 };
 #ifdef __xlC__
     /* old xlc version 12 does not understand vec_perm() with double arguments */
-    x.simdInternal_ = vec_add(
-            x.simdInternal_, reinterpret_cast<__vector double>(vec_perm(
-                                     reinterpret_cast<__vector signed int>(x.simdInternal_),
-                                     reinterpret_cast<__vector signed int>(x.simdInternal_), perm)));
+    x.simdInternal_ = vec_add(x.simdInternal_,
+                              reinterpret_cast<__vector double>(vec_perm(
+                                      reinterpret_cast<__vector signed int>(x.simdInternal_),
+                                      reinterpret_cast<__vector signed int>(x.simdInternal_),
+                                      perm)));
 #else
     x.simdInternal_ = vec_add(x.simdInternal_, vec_perm(x.simdInternal_, x.simdInternal_, perm));
 #endif
diff --git a/src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace.h b/src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace.h
deleted file mode 100644 (file)
index 384c317..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 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.
- */
-
-#ifndef GMX_SIMD_IMPL_SPARC64_HPC_ACE_H
-#define GMX_SIMD_IMPL_SPARC64_HPC_ACE_H
-
-#include "impl_sparc64_hpc_ace_simd_double.h"
-#include "impl_sparc64_hpc_ace_simd_float.h"
-/* No SIMD4 support, since both single & double are only 2-wide */
-
-#endif /* GMX_SIMD_IMPL_SPARC64_HPC_ACE_H */
diff --git a/src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace_common.h b/src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace_common.h
deleted file mode 100644 (file)
index 2762635..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2018,2019, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_SPARC64_HPC_ACE_COMMON_H
-#define GMX_SIMD_IMPL_SPARC64_HPC_ACE_COMMON_H
-
-/* Capability definitions for Sparc64 HPC-ACE */
-/* HPC-ACE is actually double-only on the register level, but we also implement
- * a single-precision interface where we only offer single-precision accuracy
- * in math functions - this can save quite a few cycles.
- */
-#define GMX_SIMD 1
-#define GMX_SIMD_HAVE_FLOAT 1
-#define GMX_SIMD_HAVE_DOUBLE 1
-#define GMX_SIMD_HAVE_LOADU 0
-#define GMX_SIMD_HAVE_STOREU 0
-#define GMX_SIMD_HAVE_LOGICAL 1
-#define GMX_SIMD_HAVE_FMA 1
-#define GMX_SIMD_HAVE_FINT32_EXTRACT 1
-#define GMX_SIMD_HAVE_FINT32_LOGICAL 1
-#define GMX_SIMD_HAVE_FINT32_ARITHMETICS 0
-#define GMX_SIMD_HAVE_DINT32_EXTRACT 1
-#define GMX_SIMD_HAVE_DINT32_LOGICAL 1
-#define GMX_SIMD_HAVE_DINT32_ARITHMETICS 0
-#define GMX_SIMD4_HAVE_FLOAT 0
-#define GMX_SIMD4_HAVE_DOUBLE 0
-
-/* Implementation details */
-#define GMX_SIMD_FLOAT_WIDTH 2
-#define GMX_SIMD_DOUBLE_WIDTH 2
-#define GMX_SIMD_FINT32_WIDTH 2
-#define GMX_SIMD_DINT32_WIDTH 2
-/* No SIMD4 support in either single or double */
-#define GMX_SIMD_RSQRT_BITS 10
-#define GMX_SIMD_RCP_BITS 9
-
-#endif /* GMX_SIMD_IMPL_SPARC64_HPC_ACE_COMMON_H */
diff --git a/src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace_simd_double.h b/src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace_simd_double.h
deleted file mode 100644 (file)
index e811489..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2019, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_SPARC64_HPC_ACE_SIMD_DOUBLE_H
-#define GMX_SIMD_IMPL_SPARC64_HPC_ACE_SIMD_DOUBLE_H
-
-/* Fujitsu header borrows the name from SSE2, since some instructions have aliases.
- * Environment/compiler version GM-1.2.0-17 seems to be buggy; when -Xg is
- * defined to enable GNUC extensions, this sets _ISOC99_SOURCE, which in
- * turn causes all intrinsics to be declared inline _instead_ of static. This
- * leads to duplicate symbol errors at link time.
- * To work around this we unset this before including the HPC-ACE header, and
- * reset the value afterwards.
- */
-#ifdef _ISOC99_SOURCE
-#    undef _ISOC99_SOURCE
-#    define SAVE_ISOC99_SOURCE
-#endif
-
-#include <emmintrin.h>
-
-#ifdef SAVE_ISOC99_SOURCE
-#    define _ISOC99_SOURCE
-#    undef SAVE_ISOC99_SOURCE
-#endif
-
-#include <cmath>
-#include <cstdint>
-
-#include "impl_sparc64_hpc_ace_common.h"
-
-/****************************************************
- *      DOUBLE PRECISION SIMD IMPLEMENTATION        *
- ****************************************************/
-#define SimdDouble _fjsp_v2r8
-#define simdLoadD _fjsp_load_v2r8
-#define simdLoad1D(m) _fjsp_set_v2r8((*m), (*m))
-#define simdSet1D(a) _fjsp_set_v2r8(a, a)
-#define simdStoreD _fjsp_store_v2r8
-#define simdLoadUD simdLoadD
-/* No unaligned store of SimdDouble */
-#define simdSetZeroD _fjsp_setzero_v2r8
-#define simdAddD _fjsp_add_v2r8
-#define simdSubD _fjsp_sub_v2r8
-#define simdMulD _fjsp_mul_v2r8
-#define simdFmaddD(a, b, c) _fjsp_madd_v2r8(a, b, c)
-#define simdFmsubD(a, b, c) _fjsp_msub_v2r8(a, b, c)
-#define simdFnmaddD(a, b, c) _fjsp_nmsub_v2r8(a, b, c)
-#define simdFnmsubD(a, b, c) _fjsp_nmadd_v2r8(a, b, c)
-#define simdAndD _fjsp_and_v2r8
-#define simdAndNotD _fjsp_andnot1_v2r8
-#define simdOrD _fjsp_or_v2r8
-#define simdXorD _fjsp_xor_v2r8
-#define simdRsqrtD(x) _fjsp_rsqrta_v2r8(x)
-#define simdRcpD(x) _fjsp_rcpa_v2r8(x)
-#define simdAbsD(x) _fjsp_abs_v2r8(x)
-#define simdNegD(x) _fjsp_neg_v2r8(x)
-#define simdMaxD _fjsp_max_v2r8
-#define simdMinD _fjsp_min_v2r8
-#define simdRoundD(x) simdCvtI2D(simdCvtD2I(x))
-#define simdTruncD(x) simdCvtI2D(simdCvttD2I(x))
-#define simdFractionD(x) simdSubD(x, simdTruncD(x))
-#define simdGetExponentD simdGetExponentD_sparc64_hpc_ace
-#define simdGetMantissaD simdGetMantissaD_sparc64_hpc_ace
-#define simdSetExponentD simdSetExponentD_sparc64_hpc_ace
-/* integer datatype corresponding to double: SimdDInt32 */
-#define SimdDInt32 _fjsp_v2r8
-#define simdLoadDI(m) simdLoadDI_sparc64_hpc_ace(m)
-#define simdSet1DI(i) simdSet1DI_sparc64_hpc_ace(i)
-#define simdStoreDI(m, x) simdStoreDI_sparc64_hpc_ace(m, x)
-#define simdLoadUDI simdLoadDI
-/* No unaligned store of SimdDInt32 */
-#define simdSetZeroDI _fjsp_setzero_v2r8
-#define simdCvtD2I simdCvtD2I_sparc64_hpc_ace
-#define simdCvttD2I _fjsp_dtox_v2r8
-#define simdCvtI2D _fjsp_xtod_v2r8
-#define simdExtractDI simdExtractDI_sparc64_hpc_ace
-/* Integer logical ops on SimdDInt32 */
-#define simdSlliDI simdSlliDI_sparc64_hpc_ace
-#define simdSrliDI simdSrliDI_sparc64_hpc_ace
-#define simdAndDI _fjsp_and_v2r8
-#define simdAndNotDI _fjsp_andnot1_v2r8
-#define simdOrDI _fjsp_or_v2r8
-#define simdXorDI _fjsp_xor_v2r8
-/* Integer arithmetic ops on integer datatype corresponding to double */
-/* Boolean & comparison operations on SimdDouble */
-#define SimdDBool _fjsp_v2r8
-#define simdCmpEqD _fjsp_cmpeq_v2r8
-#define simdCmpLtD _fjsp_cmplt_v2r8
-#define simdCmpLeD _fjsp_cmple_v2r8
-#define simdAndDB _fjsp_and_v2r8
-#define simdOrDB _fjsp_or_v2r8
-#define simdAnyTrueDB gmx_simd_anytrue_d_sparc64_hpc_ace
-#define simdMaskD _fjsp_and_v2r8
-#define simdMaskNotD(a, sel) _fjsp_andnot1_v2r8(sel, a)
-#define simdBlendD(a, b, sel) _fjsp_selmov_v2r8(b, a, sel)
-#define simdReduceD(a) simdReduceD_sparc64_hpc_ace(a)
-
-/* No boolean & comparison operations on SimdDInt32 */
-/* Float/double conversion */
-#define simdCvtF2D(f) (f)
-#define simdCvtD2F(d) (d)
-
-
-/****************************************************
- * DOUBLE PRECISION IMPLEMENTATION HELPER FUNCTIONS *
- ****************************************************/
-static inline SimdDInt32 simdLoadDI_sparc64_hpc_ace(const int* m)
-{
-    union {
-        _fjsp_v2r8    simd;
-        long long int i[2];
-    } conv;
-
-    conv.i[0] = m[0];
-    conv.i[1] = m[1];
-
-    return _fjsp_load_v2r8((double*)&(conv.simd));
-}
-
-static inline void simdStoreDI_sparc64_hpc_ace(int* m, SimdDInt32 x)
-{
-    union {
-        _fjsp_v2r8    simd;
-        long long int i[2];
-    } conv;
-
-    _fjsp_store_v2r8((double*)&(conv.simd), x);
-
-    m[0] = conv.i[0];
-    m[1] = conv.i[1];
-}
-
-static inline SimdDInt32 simdSet1DI_sparc64_hpc_ace(int i)
-{
-    union {
-        _fjsp_v2r8    simd;
-        long long int i[2];
-    } conv;
-
-    conv.i[0] = i;
-    conv.i[1] = i;
-
-    return _fjsp_load_v2r8((double*)&(conv.simd));
-}
-
-static inline int simdExtractDI_sparc64_hpc_ace(SimdDInt32 x, int i)
-{
-    long long int res;
-    /* This conditional should be optimized away at compile time */
-    if (i == 0)
-    {
-        _fjsp_storel_v2r8((double*)&res, x);
-    }
-    else
-    {
-        _fjsp_storeh_v2r8((double*)&res, x);
-    }
-    return (int)res;
-}
-
-static inline SimdDInt32 simdSlliDI_sparc64_hpc_ace(SimdDInt32 x, int i)
-{
-    _fjsp_v2i8 ix = *((_fjsp_v2i8*)&x);
-    ix            = _fjsp_slli_v2i8(ix, i);
-    x             = *((_fjsp_v2r8*)&ix);
-    return x;
-}
-
-static inline SimdDInt32 simdSrliDI_sparc64_hpc_ace(SimdDInt32 x, int i)
-{
-    _fjsp_v2i8 ix = *((_fjsp_v2i8*)&x);
-    ix            = _fjsp_srli_v2i8(ix, i);
-    x             = *((_fjsp_v2r8*)&ix);
-    return x;
-}
-
-static inline SimdDInt32 simdCvtD2I_sparc64_hpc_ace(SimdDouble x)
-{
-    _fjsp_v2r8 signbit = _fjsp_set_v2r8(-0.0, -0.0);
-    _fjsp_v2r8 half    = _fjsp_set_v2r8(0.5, 0.5);
-
-    x = _fjsp_add_v2r8(x, _fjsp_or_v2r8(_fjsp_and_v2r8(signbit, x), half));
-    return _fjsp_dtox_v2r8(x);
-}
-
-static inline int gmx_simd_anytrue_d_sparc64_hpc_ace(SimdDBool x)
-{
-    long long int i;
-    x = _fjsp_or_v2r8(x, _fjsp_unpackhi_v2r8(x, x));
-    _fjsp_storel_v2r8((double*)&i, x);
-    return (i != 0LL);
-}
-
-static inline double simdReduceD_sparc64_hpc_ace(SimdDouble x)
-{
-    double d;
-    x = _fjsp_add_v2r8(x, _fjsp_unpackhi_v2r8(x, x));
-    _fjsp_storel_v2r8(&d, x);
-    return d;
-}
-
-
-static inline SimdDouble simdGetExponentD_sparc64_hpc_ace(SimdDouble x)
-{
-    /* HPC-ACE cannot cast _fjsp_v2r8 to _fjsp_v4i4, so to perform shifts we
-     * would need to store and reload. Since we are only operating on two
-     * numbers it is likely more efficient to do the operations directly on
-     * normal registers.
-     */
-    const std::int64_t expmask = 0x7ff0000000000000LL;
-    const std::int64_t expbias = 1023LL;
-
-    union {
-        _fjsp_v2r8    simd;
-        long long int i[2];
-    } conv;
-
-    _fjsp_store_v2r8((double*)&conv.simd, x);
-    conv.i[0] = ((conv.i[0] & expmask) >> 52) - expbias;
-    conv.i[1] = ((conv.i[1] & expmask) >> 52) - expbias;
-    x         = _fjsp_load_v2r8((double*)&conv.simd);
-    return _fjsp_xtod_v2r8(x);
-}
-
-static inline SimdDouble simdGetMantissaD_sparc64_hpc_ace(SimdDouble x)
-{
-    std::int64_t mantmask[2] = { 0x000fffffffffffffLL, 0x000fffffffffffffLL };
-    SimdDouble   one         = _fjsp_set_v2r8(1.0, 1.0);
-
-    x = _fjsp_and_v2r8(x, _fjsp_load_v2r8((double*)mantmask));
-    return _fjsp_or_v2r8(x, one);
-}
-
-static inline SimdDouble simdSetExponentD_sparc64_hpc_ace(SimdDouble x)
-{
-    const std::int64_t expbias = 1023;
-    union {
-        _fjsp_v2r8    simd;
-        long long int i[2];
-    } conv;
-
-
-    _fjsp_store_v2r8((double*)&conv.simd, simdCvtD2I_sparc64_hpc_ace(x));
-    conv.i[0] = (conv.i[0] + expbias) << 52;
-    conv.i[1] = (conv.i[1] + expbias) << 52;
-
-    return _fjsp_load_v2r8((double*)&conv.simd);
-}
-
-#endif /* GMX_SIMD_IMPL_SPARC64_HPC_ACE_SIMD_DOUBLE_H */
diff --git a/src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace_simd_float.h b/src/gromacs/simd/impl_sparc64_hpc_ace/impl_sparc64_hpc_ace_simd_float.h
deleted file mode 100644 (file)
index 54749ea..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2019, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_SPARC64_HPC_ACE_SIMD_FLOAT_H
-#define GMX_SIMD_IMPL_SPARC64_HPC_ACE_SIMD_FLOAT_H
-
-/* Fujitsu header borrows the name from SSE2, since some instructions have aliases.
- * Environment/compiler version GM-1.2.0-17 seems to be buggy; when -Xg is
- * defined to enable GNUC extensions, this sets _ISOC99_SOURCE, which in
- * turn causes all intrinsics to be declared inline _instead_ of static. This
- * leads to duplicate symbol errors at link time.
- * To work around this we unset this before including the HPC-ACE header, and
- * reset the value afterwards.
- */
-#ifdef _ISOC99_SOURCE
-#    undef _ISOC99_SOURCE
-#    define SAVE_ISOC99_SOURCE
-#endif
-
-#include <emmintrin.h>
-
-#ifdef SAVE_ISOC99_SOURCE
-#    define _ISOC99_SOURCE
-#    undef SAVE_ISOC99_SOURCE
-#endif
-
-#include <math.h>
-
-#include "impl_sparc64_hpc_ace_common.h"
-
-/* HPC-ACE is a bit strange; some instructions like
- * shifts only work on _integer_ versions of SIMD
- * registers, but there are no intrinsics to load
- * or convert, or even to cast. The only way to use
- * them is to declare unions with the SIMD integer
- * type. However, this will lead to extra load ops,
- * and the normal real-to-int and int-to-real
- * conversions work purely on the v2r8 fp regs.
- * Since our most common usage is to convert and
- * then extract the result for table lookups, we
- * define the SimdFInt32 datatype to use
- * the v2r8 rather than v2i8 SIMD type.
- */
-
-/****************************************************
- *      SINGLE PRECISION SIMD IMPLEMENTATION        *
- ****************************************************/
-#define SimdFloat _fjsp_v2r8
-#define simdLoadF simdLoadF_sparc64_hpc_ace
-#define simdLoad1F(m) _fjsp_set_v2r8((*m), (*m))
-#define simdSet1F(a) _fjsp_set_v2r8(a, a)
-#define simdStoreF simdStoreF_sparc64_hpc_ace
-#define simdLoadUF simdLoadF
-/* No unaligned store of SimdFloat */
-#define simdSetZeroF _fjsp_setzero_v2r8
-#define simdAddF _fjsp_add_v2r8
-#define simdSubF _fjsp_sub_v2r8
-#define simdMulF _fjsp_mul_v2r8
-#define simdFmaddF(a, b, c) _fjsp_madd_v2r8(a, b, c)
-#define simdFmsubF(a, b, c) _fjsp_msub_v2r8(a, b, c)
-#define simdFnmaddF(a, b, c) _fjsp_nmsub_v2r8(a, b, c)
-#define simdFnmsubF(a, b, c) _fjsp_nmadd_v2r8(a, b, c)
-#define simdAndF _fjsp_and_v2r8
-#define simdAndNotF _fjsp_andnot1_v2r8
-#define simdOrF _fjsp_or_v2r8
-#define simdXorF _fjsp_xor_v2r8
-#define simdRsqrtF _fjsp_rsqrta_v2r8
-#define simdRcpF _fjsp_rcpa_v2r8
-#define simdAbsF(x) _fjsp_abs_v2r8(x)
-#define simdNegF(x) _fjsp_neg_v2r8(x)
-#define simdMaxF _fjsp_max_v2r8
-#define simdMinF _fjsp_min_v2r8
-#define simdRoundF(x) simdRoundD(x)
-#define simdTruncF(x) simdTruncD(x)
-#define simdFractionF(x) simdSubF(x, simdTruncF(x))
-#define simdGetExponentF simdGetExponentD_sparc64_hpc_ace
-#define simdGetMantissaF simdGetMantissaD_sparc64_hpc_ace
-#define simdSetExponentF simdSetExponentD_sparc64_hpc_ace
-/* integer datatype corresponding to float: SimdFInt32 */
-#define SimdFInt32 _fjsp_v2r8
-#define simdLoadFI(m) simdLoadDI_sparc64_hpc_ace(m)
-#define simdSet1FI(i) simdSet1DI_sparc64_hpc_ace(i)
-#define simdStoreFI(m, x) simdStoreDI_sparc64_hpc_ace(m, x)
-#define simdLoadUFI simdLoadFI
-/* No unaligned store of SimdFInt32 */
-#define simdSetZeroFI _fjsp_setzero_v2r8
-#define simdCvtF2I simdCvtD2I
-#define simdCvttF2I _fjsp_dtox_v2r8
-#define simdCvtI2F _fjsp_xtod_v2r8
-#define simdExtractFI simdExtractDI_sparc64_hpc_ace
-/* Integer logical ops on SimdFInt32 */
-/* Shifts are horrible since they require memory re-loads. */
-#define simdSlliFI simdSlliDI_sparc64_hpc_ace
-#define simdSrliFI simdSrliDI_sparc64_hpc_ace
-#define simdAndFI _fjsp_and_v2r8
-#define simdAndNotFI(a, b) _fjsp_andnot1_v2r8(a, b)
-#define simdOrFI _fjsp_or_v2r8
-#define simdXorFI _fjsp_xor_v2r8
-/* No integer arithmetic ops on SimdFInt32 */
-/* Boolean & comparison operations on SimdFloat */
-#define SimdFBool _fjsp_v2r8
-#define simdCmpEqF _fjsp_cmpeq_v2r8
-#define simdCmpLtF _fjsp_cmplt_v2r8
-#define simdCmpLeF _fjsp_cmple_v2r8
-#define simdAndFB _fjsp_and_v2r8
-#define simdOrFB _fjsp_or_v2r8
-#define simdAnyTrueFB gmx_simd_anytrue_d_sparc64_hpc_ace
-#define simdMaskF _fjsp_and_v2r8
-#define simdMaskNotF(a, sel) _fjsp_andnot1_v2r8(sel, a)
-#define simdBlendF(a, b, s) _fjsp_selmov_v2r8(b, a, s)
-#define simdReduceF(a) simdReduceD_sparc64_hpc_ace(a)
-/* No boolean & comparison operations on SimdFInt32 */
-/* No conversions between different booleans */
-
-/****************************************************
- * SINGLE PRECISION IMPLEMENTATION HELPER FUNCTIONS *
- ****************************************************/
-static inline SimdFloat simdLoadF_sparc64_hpc_ace(const float* m)
-{
-    /* We are not allowed to cast single-to-double registers, but we can
-     * masquerade the memory location as a variable of type _fjsp_v2r4.
-     */
-    const _fjsp_v2r4* p = (const _fjsp_v2r4*)m;
-    _fjsp_v2r4        simd;
-
-    simd = *p;
-    return _fjsp_stod_v2r8(simd);
-}
-
-static inline void simdStoreF_sparc64_hpc_ace(float* m, SimdFloat x)
-{
-    /* We are not allowed to cast single-to-double registers, but we can
-     * masquerade the memory location as a variable of type _fjsp_v2r4.
-     */
-    _fjsp_v2r4* p = (_fjsp_v2r4*)m;
-    *p            = _fjsp_dtos_v2r4(x);
-}
-
-/* Note that some single precision defines refer to the double precision helpers */
-
-#endif /* GMX_SIMD_IMPL_SPARC64_HPC_ACE_SIMD_FLOAT_H */
index db17ac26bd50a63d77bb4b6c1e9969d786aac472..d60a11c52cb9c053172d611de58c335583e5b053 100644 (file)
@@ -331,9 +331,10 @@ static inline SimdDouble frexp(SimdDouble value, SimdDInt32* exponent)
         // precision fields, but a bit below we'll need a corresponding integer variable with 4x
         // 32-bit fields. Since AVX1 does not support shuffling across the upper/lower 128-bit
         // lanes, we need to extract those first, and then shuffle between two 128-bit variables.
-        __m128i iValueIsZero = _mm_castps_si128(_mm_shuffle_ps(
-                _mm256_extractf128_ps(_mm256_castpd_ps(valueIsZero), 0x0),
-                _mm256_extractf128_ps(_mm256_castpd_ps(valueIsZero), 0x1), _MM_SHUFFLE(2, 0, 2, 0)));
+        __m128i iValueIsZero = _mm_castps_si128(
+                _mm_shuffle_ps(_mm256_extractf128_ps(_mm256_castpd_ps(valueIsZero), 0x0),
+                               _mm256_extractf128_ps(_mm256_castpd_ps(valueIsZero), 0x1),
+                               _MM_SHUFFLE(2, 0, 2, 0)));
 
         // Set exponent to 0 when input value was zero
         iExponentLow = _mm_andnot_si128(iValueIsZero, iExponentLow);
index 0e0957a8130962aa7f21cea9155a91213d9fe058..532dd2eb1e451d4b47f91fbb47b9a13a38ee2fd2 100644 (file)
@@ -179,25 +179,33 @@ static inline void gmx_simdcall gatherLoadUTranspose(const float*       base,
         // we can use aligned loads since base should also be aligned in this case
         assert(std::size_t(base) % 16 == 0);
         t1 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_load_ps(base + align * offset[0])),
-                                  _mm_load_ps(base + align * offset[4]), 0x1);
+                                  _mm_load_ps(base + align * offset[4]),
+                                  0x1);
         t2 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_load_ps(base + align * offset[1])),
-                                  _mm_load_ps(base + align * offset[5]), 0x1);
+                                  _mm_load_ps(base + align * offset[5]),
+                                  0x1);
         t3 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_load_ps(base + align * offset[2])),
-                                  _mm_load_ps(base + align * offset[6]), 0x1);
+                                  _mm_load_ps(base + align * offset[6]),
+                                  0x1);
         t4 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_load_ps(base + align * offset[3])),
-                                  _mm_load_ps(base + align * offset[7]), 0x1);
+                                  _mm_load_ps(base + align * offset[7]),
+                                  0x1);
     }
     else
     {
         // Use unaligned loads
         t1 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_loadu_ps(base + align * offset[0])),
-                                  _mm_loadu_ps(base + align * offset[4]), 0x1);
+                                  _mm_loadu_ps(base + align * offset[4]),
+                                  0x1);
         t2 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_loadu_ps(base + align * offset[1])),
-                                  _mm_loadu_ps(base + align * offset[5]), 0x1);
+                                  _mm_loadu_ps(base + align * offset[5]),
+                                  0x1);
         t3 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_loadu_ps(base + align * offset[2])),
-                                  _mm_loadu_ps(base + align * offset[6]), 0x1);
+                                  _mm_loadu_ps(base + align * offset[6]),
+                                  0x1);
         t4 = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_loadu_ps(base + align * offset[3])),
-                                  _mm_loadu_ps(base + align * offset[7]), 0x1);
+                                  _mm_loadu_ps(base + align * offset[7]),
+                                  0x1);
     }
 
     t5                = _mm256_unpacklo_ps(t1, t2);
@@ -325,34 +333,38 @@ static inline void gmx_simdcall
                          _mm_add_ps(_mm_load_ps(base + align * offset[2]), _mm256_castps256_ps128(t7)));
             _mm_store_ps(base + align * offset[3],
                          _mm_add_ps(_mm_load_ps(base + align * offset[3]), _mm256_castps256_ps128(t8)));
-            _mm_store_ps(base + align * offset[4], _mm_add_ps(_mm_load_ps(base + align * offset[4]),
-                                                              _mm256_extractf128_ps(t5, 0x1)));
-            _mm_store_ps(base + align * offset[5], _mm_add_ps(_mm_load_ps(base + align * offset[5]),
-                                                              _mm256_extractf128_ps(t6, 0x1)));
-            _mm_store_ps(base + align * offset[6], _mm_add_ps(_mm_load_ps(base + align * offset[6]),
-                                                              _mm256_extractf128_ps(t7, 0x1)));
-            _mm_store_ps(base + align * offset[7], _mm_add_ps(_mm_load_ps(base + align * offset[7]),
-                                                              _mm256_extractf128_ps(t8, 0x1)));
+            _mm_store_ps(base + align * offset[4],
+                         _mm_add_ps(_mm_load_ps(base + align * offset[4]), _mm256_extractf128_ps(t5, 0x1)));
+            _mm_store_ps(base + align * offset[5],
+                         _mm_add_ps(_mm_load_ps(base + align * offset[5]), _mm256_extractf128_ps(t6, 0x1)));
+            _mm_store_ps(base + align * offset[6],
+                         _mm_add_ps(_mm_load_ps(base + align * offset[6]), _mm256_extractf128_ps(t7, 0x1)));
+            _mm_store_ps(base + align * offset[7],
+                         _mm_add_ps(_mm_load_ps(base + align * offset[7]), _mm256_extractf128_ps(t8, 0x1)));
         }
         else
         {
             // alignment >=5, but not a multiple of 4
-            _mm_storeu_ps(base + align * offset[0], _mm_add_ps(_mm_loadu_ps(base + align * offset[0]),
-                                                               _mm256_castps256_ps128(t5)));
-            _mm_storeu_ps(base + align * offset[1], _mm_add_ps(_mm_loadu_ps(base + align * offset[1]),
-                                                               _mm256_castps256_ps128(t6)));
-            _mm_storeu_ps(base + align * offset[2], _mm_add_ps(_mm_loadu_ps(base + align * offset[2]),
-                                                               _mm256_castps256_ps128(t7)));
-            _mm_storeu_ps(base + align * offset[3], _mm_add_ps(_mm_loadu_ps(base + align * offset[3]),
-                                                               _mm256_castps256_ps128(t8)));
-            _mm_storeu_ps(base + align * offset[4], _mm_add_ps(_mm_loadu_ps(base + align * offset[4]),
-                                                               _mm256_extractf128_ps(t5, 0x1)));
-            _mm_storeu_ps(base + align * offset[5], _mm_add_ps(_mm_loadu_ps(base + align * offset[5]),
-                                                               _mm256_extractf128_ps(t6, 0x1)));
-            _mm_storeu_ps(base + align * offset[6], _mm_add_ps(_mm_loadu_ps(base + align * offset[6]),
-                                                               _mm256_extractf128_ps(t7, 0x1)));
-            _mm_storeu_ps(base + align * offset[7], _mm_add_ps(_mm_loadu_ps(base + align * offset[7]),
-                                                               _mm256_extractf128_ps(t8, 0x1)));
+            _mm_storeu_ps(base + align * offset[0],
+                          _mm_add_ps(_mm_loadu_ps(base + align * offset[0]), _mm256_castps256_ps128(t5)));
+            _mm_storeu_ps(base + align * offset[1],
+                          _mm_add_ps(_mm_loadu_ps(base + align * offset[1]), _mm256_castps256_ps128(t6)));
+            _mm_storeu_ps(base + align * offset[2],
+                          _mm_add_ps(_mm_loadu_ps(base + align * offset[2]), _mm256_castps256_ps128(t7)));
+            _mm_storeu_ps(base + align * offset[3],
+                          _mm_add_ps(_mm_loadu_ps(base + align * offset[3]), _mm256_castps256_ps128(t8)));
+            _mm_storeu_ps(
+                    base + align * offset[4],
+                    _mm_add_ps(_mm_loadu_ps(base + align * offset[4]), _mm256_extractf128_ps(t5, 0x1)));
+            _mm_storeu_ps(
+                    base + align * offset[5],
+                    _mm_add_ps(_mm_loadu_ps(base + align * offset[5]), _mm256_extractf128_ps(t6, 0x1)));
+            _mm_storeu_ps(
+                    base + align * offset[6],
+                    _mm_add_ps(_mm_loadu_ps(base + align * offset[6]), _mm256_extractf128_ps(t7, 0x1)));
+            _mm_storeu_ps(
+                    base + align * offset[7],
+                    _mm_add_ps(_mm_loadu_ps(base + align * offset[7]), _mm256_extractf128_ps(t8, 0x1)));
         }
     }
 }
@@ -453,34 +465,38 @@ static inline void gmx_simdcall
                          _mm_sub_ps(_mm_load_ps(base + align * offset[2]), _mm256_castps256_ps128(t7)));
             _mm_store_ps(base + align * offset[3],
                          _mm_sub_ps(_mm_load_ps(base + align * offset[3]), _mm256_castps256_ps128(t8)));
-            _mm_store_ps(base + align * offset[4], _mm_sub_ps(_mm_load_ps(base + align * offset[4]),
-                                                              _mm256_extractf128_ps(t5, 0x1)));
-            _mm_store_ps(base + align * offset[5], _mm_sub_ps(_mm_load_ps(base + align * offset[5]),
-                                                              _mm256_extractf128_ps(t6, 0x1)));
-            _mm_store_ps(base + align * offset[6], _mm_sub_ps(_mm_load_ps(base + align * offset[6]),
-                                                              _mm256_extractf128_ps(t7, 0x1)));
-            _mm_store_ps(base + align * offset[7], _mm_sub_ps(_mm_load_ps(base + align * offset[7]),
-                                                              _mm256_extractf128_ps(t8, 0x1)));
+            _mm_store_ps(base + align * offset[4],
+                         _mm_sub_ps(_mm_load_ps(base + align * offset[4]), _mm256_extractf128_ps(t5, 0x1)));
+            _mm_store_ps(base + align * offset[5],
+                         _mm_sub_ps(_mm_load_ps(base + align * offset[5]), _mm256_extractf128_ps(t6, 0x1)));
+            _mm_store_ps(base + align * offset[6],
+                         _mm_sub_ps(_mm_load_ps(base + align * offset[6]), _mm256_extractf128_ps(t7, 0x1)));
+            _mm_store_ps(base + align * offset[7],
+                         _mm_sub_ps(_mm_load_ps(base + align * offset[7]), _mm256_extractf128_ps(t8, 0x1)));
         }
         else
         {
             // alignment >=5, but not a multiple of 4
-            _mm_storeu_ps(base + align * offset[0], _mm_sub_ps(_mm_loadu_ps(base + align * offset[0]),
-                                                               _mm256_castps256_ps128(t5)));
-            _mm_storeu_ps(base + align * offset[1], _mm_sub_ps(_mm_loadu_ps(base + align * offset[1]),
-                                                               _mm256_castps256_ps128(t6)));
-            _mm_storeu_ps(base + align * offset[2], _mm_sub_ps(_mm_loadu_ps(base + align * offset[2]),
-                                                               _mm256_castps256_ps128(t7)));
-            _mm_storeu_ps(base + align * offset[3], _mm_sub_ps(_mm_loadu_ps(base + align * offset[3]),
-                                                               _mm256_castps256_ps128(t8)));
-            _mm_storeu_ps(base + align * offset[4], _mm_sub_ps(_mm_loadu_ps(base + align * offset[4]),
-                                                               _mm256_extractf128_ps(t5, 0x1)));
-            _mm_storeu_ps(base + align * offset[5], _mm_sub_ps(_mm_loadu_ps(base + align * offset[5]),
-                                                               _mm256_extractf128_ps(t6, 0x1)));
-            _mm_storeu_ps(base + align * offset[6], _mm_sub_ps(_mm_loadu_ps(base + align * offset[6]),
-                                                               _mm256_extractf128_ps(t7, 0x1)));
-            _mm_storeu_ps(base + align * offset[7], _mm_sub_ps(_mm_loadu_ps(base + align * offset[7]),
-                                                               _mm256_extractf128_ps(t8, 0x1)));
+            _mm_storeu_ps(base + align * offset[0],
+                          _mm_sub_ps(_mm_loadu_ps(base + align * offset[0]), _mm256_castps256_ps128(t5)));
+            _mm_storeu_ps(base + align * offset[1],
+                          _mm_sub_ps(_mm_loadu_ps(base + align * offset[1]), _mm256_castps256_ps128(t6)));
+            _mm_storeu_ps(base + align * offset[2],
+                          _mm_sub_ps(_mm_loadu_ps(base + align * offset[2]), _mm256_castps256_ps128(t7)));
+            _mm_storeu_ps(base + align * offset[3],
+                          _mm_sub_ps(_mm_loadu_ps(base + align * offset[3]), _mm256_castps256_ps128(t8)));
+            _mm_storeu_ps(
+                    base + align * offset[4],
+                    _mm_sub_ps(_mm_loadu_ps(base + align * offset[4]), _mm256_extractf128_ps(t5, 0x1)));
+            _mm_storeu_ps(
+                    base + align * offset[5],
+                    _mm_sub_ps(_mm_loadu_ps(base + align * offset[5]), _mm256_extractf128_ps(t6, 0x1)));
+            _mm_storeu_ps(
+                    base + align * offset[6],
+                    _mm_sub_ps(_mm_loadu_ps(base + align * offset[6]), _mm256_extractf128_ps(t7, 0x1)));
+            _mm_storeu_ps(
+                    base + align * offset[7],
+                    _mm_sub_ps(_mm_loadu_ps(base + align * offset[7]), _mm256_extractf128_ps(t8, 0x1)));
         }
     }
 }
index 75b7c2d66393ece26f43c66ed871ed4775af6327..165717e7d1ede6e093b1cd2f8dd1ee14bdbf427a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2016,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -220,26 +220,34 @@ static inline void gmx_simdcall transpose(Simd4Double* v0, Simd4Double* v1, Simd
 
 static inline Simd4DBool gmx_simdcall operator==(Simd4Double a, Simd4Double b)
 {
-    return { _mm512_mask_cmp_pd_mask(avx512Int2Mask(0xF), _mm512_castpd256_pd512(a.simdInternal_),
-                                     _mm512_castpd256_pd512(b.simdInternal_), _CMP_EQ_OQ) };
+    return { _mm512_mask_cmp_pd_mask(avx512Int2Mask(0xF),
+                                     _mm512_castpd256_pd512(a.simdInternal_),
+                                     _mm512_castpd256_pd512(b.simdInternal_),
+                                     _CMP_EQ_OQ) };
 }
 
 static inline Simd4DBool gmx_simdcall operator!=(Simd4Double a, Simd4Double b)
 {
-    return { _mm512_mask_cmp_pd_mask(avx512Int2Mask(0xF), _mm512_castpd256_pd512(a.simdInternal_),
-                                     _mm512_castpd256_pd512(b.simdInternal_), _CMP_NEQ_OQ) };
+    return { _mm512_mask_cmp_pd_mask(avx512Int2Mask(0xF),
+                                     _mm512_castpd256_pd512(a.simdInternal_),
+                                     _mm512_castpd256_pd512(b.simdInternal_),
+                                     _CMP_NEQ_OQ) };
 }
 
 static inline Simd4DBool gmx_simdcall operator<(Simd4Double a, Simd4Double b)
 {
-    return { _mm512_mask_cmp_pd_mask(avx512Int2Mask(0xF), _mm512_castpd256_pd512(a.simdInternal_),
-                                     _mm512_castpd256_pd512(b.simdInternal_), _CMP_LT_OQ) };
+    return { _mm512_mask_cmp_pd_mask(avx512Int2Mask(0xF),
+                                     _mm512_castpd256_pd512(a.simdInternal_),
+                                     _mm512_castpd256_pd512(b.simdInternal_),
+                                     _CMP_LT_OQ) };
 }
 
 static inline Simd4DBool gmx_simdcall operator<=(Simd4Double a, Simd4Double b)
 {
-    return { _mm512_mask_cmp_pd_mask(avx512Int2Mask(0xF), _mm512_castpd256_pd512(a.simdInternal_),
-                                     _mm512_castpd256_pd512(b.simdInternal_), _CMP_LE_OQ) };
+    return { _mm512_mask_cmp_pd_mask(avx512Int2Mask(0xF),
+                                     _mm512_castpd256_pd512(a.simdInternal_),
+                                     _mm512_castpd256_pd512(b.simdInternal_),
+                                     _CMP_LE_OQ) };
 }
 
 static inline Simd4DBool gmx_simdcall operator&&(Simd4DBool a, Simd4DBool b)
@@ -259,14 +267,14 @@ static inline bool gmx_simdcall anyTrue(Simd4DBool x)
 
 static inline Simd4Double gmx_simdcall selectByMask(Simd4Double a, Simd4DBool m)
 {
-    return { _mm512_castpd512_pd256(_mm512_mask_mov_pd(_mm512_setzero_pd(), m.simdInternal_,
-                                                       _mm512_castpd256_pd512(a.simdInternal_))) };
+    return { _mm512_castpd512_pd256(_mm512_mask_mov_pd(
+            _mm512_setzero_pd(), m.simdInternal_, _mm512_castpd256_pd512(a.simdInternal_))) };
 }
 
 static inline Simd4Double gmx_simdcall selectByNotMask(Simd4Double a, Simd4DBool m)
 {
-    return { _mm512_castpd512_pd256(_mm512_mask_mov_pd(_mm512_castpd256_pd512(a.simdInternal_),
-                                                       m.simdInternal_, _mm512_setzero_pd())) };
+    return { _mm512_castpd512_pd256(_mm512_mask_mov_pd(
+            _mm512_castpd256_pd512(a.simdInternal_), m.simdInternal_, _mm512_setzero_pd())) };
 }
 
 static inline Simd4Double gmx_simdcall blend(Simd4Double a, Simd4Double b, Simd4DBool sel)
index 48debf7f2fb4a18040635262caa1959dcc118076..46928859ecff80948ba8b468f85bbe82058547b1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -218,26 +218,34 @@ static inline void gmx_simdcall transpose(Simd4Float* v0, Simd4Float* v1, Simd4F
 
 static inline Simd4FBool gmx_simdcall operator==(Simd4Float a, Simd4Float b)
 {
-    return { _mm512_mask_cmp_ps_mask(avx512Int2Mask(0xF), _mm512_castps128_ps512(a.simdInternal_),
-                                     _mm512_castps128_ps512(b.simdInternal_), _CMP_EQ_OQ) };
+    return { _mm512_mask_cmp_ps_mask(avx512Int2Mask(0xF),
+                                     _mm512_castps128_ps512(a.simdInternal_),
+                                     _mm512_castps128_ps512(b.simdInternal_),
+                                     _CMP_EQ_OQ) };
 }
 
 static inline Simd4FBool gmx_simdcall operator!=(Simd4Float a, Simd4Float b)
 {
-    return { _mm512_mask_cmp_ps_mask(avx512Int2Mask(0xF), _mm512_castps128_ps512(a.simdInternal_),
-                                     _mm512_castps128_ps512(b.simdInternal_), _CMP_NEQ_OQ) };
+    return { _mm512_mask_cmp_ps_mask(avx512Int2Mask(0xF),
+                                     _mm512_castps128_ps512(a.simdInternal_),
+                                     _mm512_castps128_ps512(b.simdInternal_),
+                                     _CMP_NEQ_OQ) };
 }
 
 static inline Simd4FBool gmx_simdcall operator<(Simd4Float a, Simd4Float b)
 {
-    return { _mm512_mask_cmp_ps_mask(avx512Int2Mask(0xF), _mm512_castps128_ps512(a.simdInternal_),
-                                     _mm512_castps128_ps512(b.simdInternal_), _CMP_LT_OQ) };
+    return { _mm512_mask_cmp_ps_mask(avx512Int2Mask(0xF),
+                                     _mm512_castps128_ps512(a.simdInternal_),
+                                     _mm512_castps128_ps512(b.simdInternal_),
+                                     _CMP_LT_OQ) };
 }
 
 static inline Simd4FBool gmx_simdcall operator<=(Simd4Float a, Simd4Float b)
 {
-    return { _mm512_mask_cmp_ps_mask(avx512Int2Mask(0xF), _mm512_castps128_ps512(a.simdInternal_),
-                                     _mm512_castps128_ps512(b.simdInternal_), _CMP_LE_OQ) };
+    return { _mm512_mask_cmp_ps_mask(avx512Int2Mask(0xF),
+                                     _mm512_castps128_ps512(a.simdInternal_),
+                                     _mm512_castps128_ps512(b.simdInternal_),
+                                     _CMP_LE_OQ) };
 }
 
 static inline Simd4FBool gmx_simdcall operator&&(Simd4FBool a, Simd4FBool b)
@@ -257,14 +265,14 @@ static inline bool gmx_simdcall anyTrue(Simd4FBool a)
 
 static inline Simd4Float gmx_simdcall selectByMask(Simd4Float a, Simd4FBool m)
 {
-    return { _mm512_castps512_ps128(_mm512_mask_mov_ps(_mm512_setzero_ps(), m.simdInternal_,
-                                                       _mm512_castps128_ps512(a.simdInternal_))) };
+    return { _mm512_castps512_ps128(_mm512_mask_mov_ps(
+            _mm512_setzero_ps(), m.simdInternal_, _mm512_castps128_ps512(a.simdInternal_))) };
 }
 
 static inline Simd4Float gmx_simdcall selectByNotMask(Simd4Float a, Simd4FBool m)
 {
-    return { _mm512_castps512_ps128(_mm512_mask_mov_ps(_mm512_castps128_ps512(a.simdInternal_),
-                                                       m.simdInternal_, _mm512_setzero_ps())) };
+    return { _mm512_castps512_ps128(_mm512_mask_mov_ps(
+            _mm512_castps128_ps512(a.simdInternal_), m.simdInternal_, _mm512_setzero_ps())) };
 }
 
 static inline Simd4Float gmx_simdcall blend(Simd4Float a, Simd4Float b, Simd4FBool sel)
index 8dd20c2e6c898601d809c25d0b423c0146eb5215..669c2aaeff8be7332e0b1eed5acb9c3fb3c537f3 100644 (file)
@@ -315,8 +315,8 @@ static inline SimdDouble frexp(SimdDouble value, SimdDInt32* exponent)
         iExponent = _mm256_add_epi32(iExponent, _mm256_set1_epi32(1));
 
         // Set result to value (+-0) when it is zero.
-        result = _mm512_mask_getmant_pd(value.simdInternal_, valueIsNonZero, value.simdInternal_,
-                                        _MM_MANT_NORM_p5_1, _MM_MANT_SIGN_src);
+        result = _mm512_mask_getmant_pd(
+                value.simdInternal_, valueIsNonZero, value.simdInternal_, _MM_MANT_NORM_p5_1, _MM_MANT_SIGN_src);
     }
     else
     {
@@ -423,7 +423,8 @@ static inline SimdDouble gmx_simdcall copysign(SimdDouble a, SimdDouble b)
 {
     return { _mm512_castsi512_pd(_mm512_ternarylogic_epi64(_mm512_castpd_si512(a.simdInternal_),
                                                            _mm512_castpd_si512(b.simdInternal_),
-                                                           _mm512_set1_epi64(INT64_MIN), 0xD8)) };
+                                                           _mm512_set1_epi64(INT64_MIN),
+                                                           0xD8)) };
 }
 
 static inline SimdDInt32 gmx_simdcall operator&(SimdDInt32 a, SimdDInt32 b)
@@ -463,20 +464,25 @@ static inline SimdDInt32 gmx_simdcall operator*(SimdDInt32 a, SimdDInt32 b)
 
 static inline SimdDIBool gmx_simdcall operator==(SimdDInt32 a, SimdDInt32 b)
 {
-    return { _mm512_mask_cmp_epi32_mask(avx512Int2Mask(0xFF), _mm512_castsi256_si512(a.simdInternal_),
-                                        _mm512_castsi256_si512(b.simdInternal_), _MM_CMPINT_EQ) };
+    return { _mm512_mask_cmp_epi32_mask(avx512Int2Mask(0xFF),
+                                        _mm512_castsi256_si512(a.simdInternal_),
+                                        _mm512_castsi256_si512(b.simdInternal_),
+                                        _MM_CMPINT_EQ) };
 }
 
 static inline SimdDIBool gmx_simdcall testBits(SimdDInt32 a)
 {
-    return { _mm512_mask_test_epi32_mask(avx512Int2Mask(0xFF), _mm512_castsi256_si512(a.simdInternal_),
+    return { _mm512_mask_test_epi32_mask(avx512Int2Mask(0xFF),
+                                         _mm512_castsi256_si512(a.simdInternal_),
                                          _mm512_castsi256_si512(a.simdInternal_)) };
 }
 
 static inline SimdDIBool gmx_simdcall operator<(SimdDInt32 a, SimdDInt32 b)
 {
-    return { _mm512_mask_cmp_epi32_mask(avx512Int2Mask(0xFF), _mm512_castsi256_si512(a.simdInternal_),
-                                        _mm512_castsi256_si512(b.simdInternal_), _MM_CMPINT_LT) };
+    return { _mm512_mask_cmp_epi32_mask(avx512Int2Mask(0xFF),
+                                        _mm512_castsi256_si512(a.simdInternal_),
+                                        _mm512_castsi256_si512(b.simdInternal_),
+                                        _MM_CMPINT_LT) };
 }
 
 static inline SimdDIBool gmx_simdcall operator&&(SimdDIBool a, SimdDIBool b)
@@ -508,9 +514,9 @@ static inline SimdDInt32 gmx_simdcall selectByNotMask(SimdDInt32 a, SimdDIBool m
 
 static inline SimdDInt32 gmx_simdcall blend(SimdDInt32 a, SimdDInt32 b, SimdDIBool sel)
 {
-    return { _mm512_castsi512_si256(
-            _mm512_mask_blend_epi32(sel.simdInternal_, _mm512_castsi256_si512(a.simdInternal_),
-                                    _mm512_castsi256_si512(b.simdInternal_))) };
+    return { _mm512_castsi512_si256(_mm512_mask_blend_epi32(sel.simdInternal_,
+                                                            _mm512_castsi256_si512(a.simdInternal_),
+                                                            _mm512_castsi256_si512(b.simdInternal_))) };
 }
 
 static inline SimdDInt32 gmx_simdcall cvtR2I(SimdDouble a)
index 6ef6b774d3d83f0612301312892a774a84366a63..86594486f197542ab8954fd66e451c01fe44a714 100644 (file)
@@ -309,8 +309,8 @@ static inline SimdFloat gmx_simdcall frexp(SimdFloat value, SimdFInt32* exponent
         iExponent = _mm512_mask_add_epi32(iExponent, valueIsNonZero, iExponent, _mm512_set1_epi32(1));
 
         // Set result to input value when the latter is +-0
-        result = _mm512_mask_getmant_ps(value.simdInternal_, valueIsNonZero, value.simdInternal_,
-                                        _MM_MANT_NORM_p5_1, _MM_MANT_SIGN_src);
+        result = _mm512_mask_getmant_ps(
+                value.simdInternal_, valueIsNonZero, value.simdInternal_, _MM_MANT_NORM_p5_1, _MM_MANT_SIGN_src);
     }
     else
     {
@@ -415,7 +415,8 @@ static inline SimdFloat gmx_simdcall copysign(SimdFloat a, SimdFloat b)
 {
     return { _mm512_castsi512_ps(_mm512_ternarylogic_epi32(_mm512_castps_si512(a.simdInternal_),
                                                            _mm512_castps_si512(b.simdInternal_),
-                                                           _mm512_set1_epi32(INT32_MIN), 0xD8)) };
+                                                           _mm512_set1_epi32(INT32_MIN),
+                                                           0xD8)) };
 }
 
 static inline SimdFInt32 gmx_simdcall operator&(SimdFInt32 a, SimdFInt32 b)
index dac65b097816f658f7b1b4b4ccca6b47c8215172..acde31b609bf00510a1e0854d7cc685186fff762 100644 (file)
@@ -164,8 +164,9 @@ static inline void gmx_simdcall
     __m512d                                  t[4], t5, t6, t7, t8;
     alignas(GMX_SIMD_ALIGNMENT) std::int64_t o[8];
     // TODO: should use fastMultiply
-    _mm512_store_epi64(o, _mm512_cvtepi32_epi64(_mm256_mullo_epi32(
-                                  _mm256_load_si256((const __m256i*)(offset)), _mm256_set1_epi32(align))));
+    _mm512_store_epi64(o,
+                       _mm512_cvtepi32_epi64(_mm256_mullo_epi32(
+                               _mm256_load_si256((const __m256i*)(offset)), _mm256_set1_epi32(align))));
     t5   = _mm512_unpacklo_pd(v0.simdInternal_, v1.simdInternal_);
     t6   = _mm512_unpackhi_pd(v0.simdInternal_, v1.simdInternal_);
     t7   = _mm512_unpacklo_pd(v2.simdInternal_, _mm512_setzero_pd());
@@ -178,11 +179,13 @@ static inline void gmx_simdcall
     {
         for (int i = 0; i < 4; i++)
         {
-            _mm512_mask_storeu_pd(base + o[0 + i], avx512Int2Mask(7),
+            _mm512_mask_storeu_pd(base + o[0 + i],
+                                  avx512Int2Mask(7),
                                   _mm512_castpd256_pd512(_mm256_add_pd(_mm256_loadu_pd(base + o[0 + i]),
                                                                        _mm512_castpd512_pd256(t[i]))));
             _mm512_mask_storeu_pd(
-                    base + o[4 + i], avx512Int2Mask(7),
+                    base + o[4 + i],
+                    avx512Int2Mask(7),
                     _mm512_castpd256_pd512(_mm256_add_pd(_mm256_loadu_pd(base + o[4 + i]),
                                                          _mm512_extractf64x4_pd(t[i], 1))));
         }
@@ -193,20 +196,24 @@ static inline void gmx_simdcall
         {
             for (int i = 0; i < 4; i++)
             {
-                _mm256_store_pd(base + o[0 + i], _mm256_add_pd(_mm256_load_pd(base + o[0 + i]),
-                                                               _mm512_castpd512_pd256(t[i])));
-                _mm256_store_pd(base + o[4 + i], _mm256_add_pd(_mm256_load_pd(base + o[4 + i]),
-                                                               _mm512_extractf64x4_pd(t[i], 1)));
+                _mm256_store_pd(
+                        base + o[0 + i],
+                        _mm256_add_pd(_mm256_load_pd(base + o[0 + i]), _mm512_castpd512_pd256(t[i])));
+                _mm256_store_pd(base + o[4 + i],
+                                _mm256_add_pd(_mm256_load_pd(base + o[4 + i]),
+                                              _mm512_extractf64x4_pd(t[i], 1)));
             }
         }
         else
         {
             for (int i = 0; i < 4; i++)
             {
-                _mm256_storeu_pd(base + o[0 + i], _mm256_add_pd(_mm256_loadu_pd(base + o[0 + i]),
-                                                                _mm512_castpd512_pd256(t[i])));
-                _mm256_storeu_pd(base + o[4 + i], _mm256_add_pd(_mm256_loadu_pd(base + o[4 + i]),
-                                                                _mm512_extractf64x4_pd(t[i], 1)));
+                _mm256_storeu_pd(
+                        base + o[0 + i],
+                        _mm256_add_pd(_mm256_loadu_pd(base + o[0 + i]), _mm512_castpd512_pd256(t[i])));
+                _mm256_storeu_pd(base + o[4 + i],
+                                 _mm256_add_pd(_mm256_loadu_pd(base + o[4 + i]),
+                                               _mm512_extractf64x4_pd(t[i], 1)));
             }
         }
     }
@@ -219,8 +226,9 @@ static inline void gmx_simdcall
     __m512d                                  t[4], t5, t6, t7, t8;
     alignas(GMX_SIMD_ALIGNMENT) std::int64_t o[8];
     // TODO: should use fastMultiply
-    _mm512_store_epi64(o, _mm512_cvtepi32_epi64(_mm256_mullo_epi32(
-                                  _mm256_load_si256((const __m256i*)(offset)), _mm256_set1_epi32(align))));
+    _mm512_store_epi64(o,
+                       _mm512_cvtepi32_epi64(_mm256_mullo_epi32(
+                               _mm256_load_si256((const __m256i*)(offset)), _mm256_set1_epi32(align))));
     t5   = _mm512_unpacklo_pd(v0.simdInternal_, v1.simdInternal_);
     t6   = _mm512_unpackhi_pd(v0.simdInternal_, v1.simdInternal_);
     t7   = _mm512_unpacklo_pd(v2.simdInternal_, _mm512_setzero_pd());
@@ -233,11 +241,13 @@ static inline void gmx_simdcall
     {
         for (int i = 0; i < 4; i++)
         {
-            _mm512_mask_storeu_pd(base + o[0 + i], avx512Int2Mask(7),
+            _mm512_mask_storeu_pd(base + o[0 + i],
+                                  avx512Int2Mask(7),
                                   _mm512_castpd256_pd512(_mm256_sub_pd(_mm256_loadu_pd(base + o[0 + i]),
                                                                        _mm512_castpd512_pd256(t[i]))));
             _mm512_mask_storeu_pd(
-                    base + o[4 + i], avx512Int2Mask(7),
+                    base + o[4 + i],
+                    avx512Int2Mask(7),
                     _mm512_castpd256_pd512(_mm256_sub_pd(_mm256_loadu_pd(base + o[4 + i]),
                                                          _mm512_extractf64x4_pd(t[i], 1))));
         }
@@ -248,20 +258,24 @@ static inline void gmx_simdcall
         {
             for (int i = 0; i < 4; i++)
             {
-                _mm256_store_pd(base + o[0 + i], _mm256_sub_pd(_mm256_load_pd(base + o[0 + i]),
-                                                               _mm512_castpd512_pd256(t[i])));
-                _mm256_store_pd(base + o[4 + i], _mm256_sub_pd(_mm256_load_pd(base + o[4 + i]),
-                                                               _mm512_extractf64x4_pd(t[i], 1)));
+                _mm256_store_pd(
+                        base + o[0 + i],
+                        _mm256_sub_pd(_mm256_load_pd(base + o[0 + i]), _mm512_castpd512_pd256(t[i])));
+                _mm256_store_pd(base + o[4 + i],
+                                _mm256_sub_pd(_mm256_load_pd(base + o[4 + i]),
+                                              _mm512_extractf64x4_pd(t[i], 1)));
             }
         }
         else
         {
             for (int i = 0; i < 4; i++)
             {
-                _mm256_storeu_pd(base + o[0 + i], _mm256_sub_pd(_mm256_loadu_pd(base + o[0 + i]),
-                                                                _mm512_castpd512_pd256(t[i])));
-                _mm256_storeu_pd(base + o[4 + i], _mm256_sub_pd(_mm256_loadu_pd(base + o[4 + i]),
-                                                                _mm512_extractf64x4_pd(t[i], 1)));
+                _mm256_storeu_pd(
+                        base + o[0 + i],
+                        _mm256_sub_pd(_mm256_loadu_pd(base + o[0 + i]), _mm512_castpd512_pd256(t[i])));
+                _mm256_storeu_pd(base + o[4 + i],
+                                 _mm256_sub_pd(_mm256_loadu_pd(base + o[4 + i]),
+                                               _mm512_extractf64x4_pd(t[i], 1)));
             }
         }
     }
@@ -294,10 +308,10 @@ static inline double gmx_simdcall
 
     t0 = _mm512_add_pd(v0.simdInternal_, _mm512_permute_pd(v0.simdInternal_, 0x55));
     t2 = _mm512_add_pd(v2.simdInternal_, _mm512_permute_pd(v2.simdInternal_, 0x55));
-    t0 = _mm512_mask_add_pd(t0, avx512Int2Mask(0xAA), v1.simdInternal_,
-                            _mm512_permute_pd(v1.simdInternal_, 0x55));
-    t2 = _mm512_mask_add_pd(t2, avx512Int2Mask(0xAA), v3.simdInternal_,
-                            _mm512_permute_pd(v3.simdInternal_, 0x55));
+    t0 = _mm512_mask_add_pd(
+            t0, avx512Int2Mask(0xAA), v1.simdInternal_, _mm512_permute_pd(v1.simdInternal_, 0x55));
+    t2 = _mm512_mask_add_pd(
+            t2, avx512Int2Mask(0xAA), v3.simdInternal_, _mm512_permute_pd(v3.simdInternal_, 0x55));
     t0 = _mm512_add_pd(t0, _mm512_shuffle_f64x2(t0, t0, 0x4E));
     t0 = _mm512_mask_add_pd(t0, avx512Int2Mask(0xF0), t2, _mm512_shuffle_f64x2(t2, t2, 0x4E));
     t0 = _mm512_add_pd(t0, _mm512_shuffle_f64x2(t0, t0, 0xB1));
@@ -331,8 +345,8 @@ static inline SimdDouble gmx_simdcall loadDuplicateHsimd(const double* m)
 
 static inline SimdDouble gmx_simdcall loadU1DualHsimd(const double* m)
 {
-    return { _mm512_insertf64x4(_mm512_broadcastsd_pd(_mm_load_sd(m)),
-                                _mm256_broadcastsd_pd(_mm_load_sd(m + 1)), 1) };
+    return { _mm512_insertf64x4(
+            _mm512_broadcastsd_pd(_mm_load_sd(m)), _mm256_broadcastsd_pd(_mm_load_sd(m + 1)), 1) };
 }
 
 
@@ -410,8 +424,8 @@ static inline double gmx_simdcall reduceIncr4ReturnSumHsimd(double* m, SimdDoubl
     assert(std::size_t(m) % 32 == 0);
 
     t0 = _mm512_add_pd(v0.simdInternal_, _mm512_permutex_pd(v0.simdInternal_, 0x4E));
-    t0 = _mm512_mask_add_pd(t0, avx512Int2Mask(0xCC), v1.simdInternal_,
-                            _mm512_permutex_pd(v1.simdInternal_, 0x4E));
+    t0 = _mm512_mask_add_pd(
+            t0, avx512Int2Mask(0xCC), v1.simdInternal_, _mm512_permutex_pd(v1.simdInternal_, 0x4E));
     t0 = _mm512_add_pd(t0, _mm512_permutex_pd(t0, 0xB1));
     t0 = _mm512_mask_shuffle_f64x2(t0, avx512Int2Mask(0xAA), t0, t0, 0xEE);
 
@@ -428,8 +442,8 @@ static inline double gmx_simdcall reduceIncr4ReturnSumHsimd(double* m, SimdDoubl
 
 static inline SimdDouble gmx_simdcall loadU4NOffset(const double* m, int offset)
 {
-    return { _mm512_insertf64x4(_mm512_castpd256_pd512(_mm256_loadu_pd(m)),
-                                _mm256_loadu_pd(m + offset), 1) };
+    return { _mm512_insertf64x4(
+            _mm512_castpd256_pd512(_mm256_loadu_pd(m)), _mm256_loadu_pd(m + offset), 1) };
 }
 
 } // namespace gmx
index 8c3f9621a1f123ec28bf99a5a872deb34f620223..65d1320d6760476ca20e6a0030d6064dfaba774f 100644 (file)
@@ -173,16 +173,20 @@ static inline void gmx_simdcall
         t[3] = _mm512_shuffle_ps(t6, v2.simdInternal_, _MM_SHUFFLE(3, 3, 3, 2));
         for (i = 0; i < 4; i++)
         {
-            _mm512_mask_storeu_ps(base + o[i], avx512Int2Mask(7),
+            _mm512_mask_storeu_ps(base + o[i],
+                                  avx512Int2Mask(7),
                                   _mm512_castps128_ps512(_mm_add_ps(_mm_loadu_ps(base + o[i]),
                                                                     _mm512_castps512_ps128(t[i]))));
-            _mm512_mask_storeu_ps(base + o[4 + i], avx512Int2Mask(7),
+            _mm512_mask_storeu_ps(base + o[4 + i],
+                                  avx512Int2Mask(7),
                                   _mm512_castps128_ps512(_mm_add_ps(_mm_loadu_ps(base + o[4 + i]),
                                                                     _mm512_extractf32x4_ps(t[i], 1))));
-            _mm512_mask_storeu_ps(base + o[8 + i], avx512Int2Mask(7),
+            _mm512_mask_storeu_ps(base + o[8 + i],
+                                  avx512Int2Mask(7),
                                   _mm512_castps128_ps512(_mm_add_ps(_mm_loadu_ps(base + o[8 + i]),
                                                                     _mm512_extractf32x4_ps(t[i], 2))));
-            _mm512_mask_storeu_ps(base + o[12 + i], avx512Int2Mask(7),
+            _mm512_mask_storeu_ps(base + o[12 + i],
+                                  avx512Int2Mask(7),
                                   _mm512_castps128_ps512(_mm_add_ps(_mm_loadu_ps(base + o[12 + i]),
                                                                     _mm512_extractf32x4_ps(t[i], 3))));
         }
@@ -208,8 +212,8 @@ static inline void gmx_simdcall
                              _mm_add_ps(_mm_load_ps(base + o[4 + i]), _mm512_extractf32x4_ps(t[i], 1)));
                 _mm_store_ps(base + o[8 + i],
                              _mm_add_ps(_mm_load_ps(base + o[8 + i]), _mm512_extractf32x4_ps(t[i], 2)));
-                _mm_store_ps(base + o[12 + i], _mm_add_ps(_mm_load_ps(base + o[12 + i]),
-                                                          _mm512_extractf32x4_ps(t[i], 3)));
+                _mm_store_ps(base + o[12 + i],
+                             _mm_add_ps(_mm_load_ps(base + o[12 + i]), _mm512_extractf32x4_ps(t[i], 3)));
             }
         }
         else
@@ -218,12 +222,12 @@ static inline void gmx_simdcall
             {
                 _mm_storeu_ps(base + o[i],
                               _mm_add_ps(_mm_loadu_ps(base + o[i]), _mm512_castps512_ps128(t[i])));
-                _mm_storeu_ps(base + o[4 + i], _mm_add_ps(_mm_loadu_ps(base + o[4 + i]),
-                                                          _mm512_extractf32x4_ps(t[i], 1)));
-                _mm_storeu_ps(base + o[8 + i], _mm_add_ps(_mm_loadu_ps(base + o[8 + i]),
-                                                          _mm512_extractf32x4_ps(t[i], 2)));
-                _mm_storeu_ps(base + o[12 + i], _mm_add_ps(_mm_loadu_ps(base + o[12 + i]),
-                                                           _mm512_extractf32x4_ps(t[i], 3)));
+                _mm_storeu_ps(base + o[4 + i],
+                              _mm_add_ps(_mm_loadu_ps(base + o[4 + i]), _mm512_extractf32x4_ps(t[i], 1)));
+                _mm_storeu_ps(base + o[8 + i],
+                              _mm_add_ps(_mm_loadu_ps(base + o[8 + i]), _mm512_extractf32x4_ps(t[i], 2)));
+                _mm_storeu_ps(base + o[12 + i],
+                              _mm_add_ps(_mm_loadu_ps(base + o[12 + i]), _mm512_extractf32x4_ps(t[i], 3)));
             }
         }
     }
@@ -247,16 +251,20 @@ static inline void gmx_simdcall
         t[3] = _mm512_shuffle_ps(t6, v2.simdInternal_, _MM_SHUFFLE(3, 3, 3, 2));
         for (i = 0; i < 4; i++)
         {
-            _mm512_mask_storeu_ps(base + o[i], avx512Int2Mask(7),
+            _mm512_mask_storeu_ps(base + o[i],
+                                  avx512Int2Mask(7),
                                   _mm512_castps128_ps512(_mm_sub_ps(_mm_loadu_ps(base + o[i]),
                                                                     _mm512_castps512_ps128(t[i]))));
-            _mm512_mask_storeu_ps(base + o[4 + i], avx512Int2Mask(7),
+            _mm512_mask_storeu_ps(base + o[4 + i],
+                                  avx512Int2Mask(7),
                                   _mm512_castps128_ps512(_mm_sub_ps(_mm_loadu_ps(base + o[4 + i]),
                                                                     _mm512_extractf32x4_ps(t[i], 1))));
-            _mm512_mask_storeu_ps(base + o[8 + i], avx512Int2Mask(7),
+            _mm512_mask_storeu_ps(base + o[8 + i],
+                                  avx512Int2Mask(7),
                                   _mm512_castps128_ps512(_mm_sub_ps(_mm_loadu_ps(base + o[8 + i]),
                                                                     _mm512_extractf32x4_ps(t[i], 2))));
-            _mm512_mask_storeu_ps(base + o[12 + i], avx512Int2Mask(7),
+            _mm512_mask_storeu_ps(base + o[12 + i],
+                                  avx512Int2Mask(7),
                                   _mm512_castps128_ps512(_mm_sub_ps(_mm_loadu_ps(base + o[12 + i]),
                                                                     _mm512_extractf32x4_ps(t[i], 3))));
         }
@@ -282,8 +290,8 @@ static inline void gmx_simdcall
                              _mm_sub_ps(_mm_load_ps(base + o[4 + i]), _mm512_extractf32x4_ps(t[i], 1)));
                 _mm_store_ps(base + o[8 + i],
                              _mm_sub_ps(_mm_load_ps(base + o[8 + i]), _mm512_extractf32x4_ps(t[i], 2)));
-                _mm_store_ps(base + o[12 + i], _mm_sub_ps(_mm_load_ps(base + o[12 + i]),
-                                                          _mm512_extractf32x4_ps(t[i], 3)));
+                _mm_store_ps(base + o[12 + i],
+                             _mm_sub_ps(_mm_load_ps(base + o[12 + i]), _mm512_extractf32x4_ps(t[i], 3)));
             }
         }
         else
@@ -292,12 +300,12 @@ static inline void gmx_simdcall
             {
                 _mm_storeu_ps(base + o[i],
                               _mm_sub_ps(_mm_loadu_ps(base + o[i]), _mm512_castps512_ps128(t[i])));
-                _mm_storeu_ps(base + o[4 + i], _mm_sub_ps(_mm_loadu_ps(base + o[4 + i]),
-                                                          _mm512_extractf32x4_ps(t[i], 1)));
-                _mm_storeu_ps(base + o[8 + i], _mm_sub_ps(_mm_loadu_ps(base + o[8 + i]),
-                                                          _mm512_extractf32x4_ps(t[i], 2)));
-                _mm_storeu_ps(base + o[12 + i], _mm_sub_ps(_mm_loadu_ps(base + o[12 + i]),
-                                                           _mm512_extractf32x4_ps(t[i], 3)));
+                _mm_storeu_ps(base + o[4 + i],
+                              _mm_sub_ps(_mm_loadu_ps(base + o[4 + i]), _mm512_extractf32x4_ps(t[i], 1)));
+                _mm_storeu_ps(base + o[8 + i],
+                              _mm_sub_ps(_mm_loadu_ps(base + o[8 + i]), _mm512_extractf32x4_ps(t[i], 2)));
+                _mm_storeu_ps(base + o[12 + i],
+                              _mm_sub_ps(_mm_loadu_ps(base + o[12 + i]), _mm512_extractf32x4_ps(t[i], 3)));
             }
         }
     }
@@ -326,11 +334,11 @@ static inline float gmx_simdcall reduceIncr4ReturnSum(float* m, SimdFloat v0, Si
     assert(std::size_t(m) % 16 == 0);
 
     t0 = _mm512_add_ps(v0.simdInternal_, _mm512_permute_ps(v0.simdInternal_, 0x4E));
-    t0 = _mm512_mask_add_ps(t0, avx512Int2Mask(0xCCCC), v2.simdInternal_,
-                            _mm512_permute_ps(v2.simdInternal_, 0x4E));
+    t0 = _mm512_mask_add_ps(
+            t0, avx512Int2Mask(0xCCCC), v2.simdInternal_, _mm512_permute_ps(v2.simdInternal_, 0x4E));
     t1 = _mm512_add_ps(v1.simdInternal_, _mm512_permute_ps(v1.simdInternal_, 0x4E));
-    t1 = _mm512_mask_add_ps(t1, avx512Int2Mask(0xCCCC), v3.simdInternal_,
-                            _mm512_permute_ps(v3.simdInternal_, 0x4E));
+    t1 = _mm512_mask_add_ps(
+            t1, avx512Int2Mask(0xCCCC), v3.simdInternal_, _mm512_permute_ps(v3.simdInternal_, 0x4E));
     t2 = _mm512_add_ps(t0, _mm512_permute_ps(t0, 0xB1));
     t2 = _mm512_mask_add_ps(t2, avx512Int2Mask(0xAAAA), t1, _mm512_permute_ps(t1, 0xB1));
 
@@ -355,7 +363,8 @@ static inline SimdFloat gmx_simdcall loadDualHsimd(const float* m0, const float*
 
     return { _mm512_castpd_ps(_mm512_insertf64x4(
             _mm512_castpd256_pd512(_mm256_load_pd(reinterpret_cast<const double*>(m0))),
-            _mm256_load_pd(reinterpret_cast<const double*>(m1)), 1)) };
+            _mm256_load_pd(reinterpret_cast<const double*>(m1)),
+            1)) };
 }
 
 static inline SimdFloat gmx_simdcall loadDuplicateHsimd(const float* m)
@@ -366,8 +375,8 @@ static inline SimdFloat gmx_simdcall loadDuplicateHsimd(const float* m)
 
 static inline SimdFloat gmx_simdcall loadU1DualHsimd(const float* m)
 {
-    return { _mm512_shuffle_f32x4(_mm512_broadcastss_ps(_mm_load_ss(m)),
-                                  _mm512_broadcastss_ps(_mm_load_ss(m + 1)), 0x44) };
+    return { _mm512_shuffle_f32x4(
+            _mm512_broadcastss_ps(_mm_load_ss(m)), _mm512_broadcastss_ps(_mm_load_ss(m + 1)), 0x44) };
 }
 
 
diff --git a/src/gromacs/simd/impl_x86_mic/impl_x86_mic.h b/src/gromacs/simd/impl_x86_mic/impl_x86_mic.h
deleted file mode 100644 (file)
index 5cf004b..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 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.
- */
-
-#ifndef GMX_SIMD_IMPL_X86_MIC_H
-#define GMX_SIMD_IMPL_X86_MIC_H
-
-#include "impl_x86_mic_definitions.h"
-#include "impl_x86_mic_general.h"
-#include "impl_x86_mic_simd4_double.h"
-#include "impl_x86_mic_simd4_float.h"
-#include "impl_x86_mic_simd_double.h"
-#include "impl_x86_mic_simd_float.h"
-#include "impl_x86_mic_util_double.h"
-#include "impl_x86_mic_util_float.h"
-
-#endif // GMX_SIMD_IMPL_X86_MIC_H
diff --git a/src/gromacs/simd/impl_x86_mic/impl_x86_mic_definitions.h b/src/gromacs/simd/impl_x86_mic/impl_x86_mic_definitions.h
deleted file mode 100644 (file)
index 2f85b0c..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2017,2018,2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_X86_MIC_DEFINITIONS_H
-#define GMX_SIMD_IMPL_X86_MIC_DEFINITIONS_H
-
-#define GMX_SIMD 1
-#define GMX_SIMD_HAVE_FLOAT 1
-#define GMX_SIMD_HAVE_DOUBLE 1
-#define GMX_SIMD_HAVE_LOADU 1
-#define GMX_SIMD_HAVE_STOREU 1
-#define GMX_SIMD_HAVE_LOGICAL 1
-#define GMX_SIMD_HAVE_FMA 1
-#define GMX_SIMD_HAVE_FINT32_EXTRACT 1
-#define GMX_SIMD_HAVE_FINT32_LOGICAL 1
-#define GMX_SIMD_HAVE_FINT32_ARITHMETICS 1
-#define GMX_SIMD_HAVE_DINT32_EXTRACT 1
-#define GMX_SIMD_HAVE_DINT32_LOGICAL 1
-#define GMX_SIMD_HAVE_DINT32_ARITHMETICS 1
-#define GMX_SIMD_HAVE_NATIVE_COPYSIGN_FLOAT 0
-#define GMX_SIMD_HAVE_NATIVE_RSQRT_ITER_FLOAT 0
-#define GMX_SIMD_HAVE_NATIVE_RCP_ITER_FLOAT 0
-#define GMX_SIMD_HAVE_NATIVE_LOG_FLOAT 1
-#define GMX_SIMD_HAVE_NATIVE_EXP2_FLOAT 1
-#define GMX_SIMD_HAVE_NATIVE_EXP_FLOAT 1
-#define GMX_SIMD_HAVE_NATIVE_COPYSIGN_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_RSQRT_ITER_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_RCP_ITER_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_LOG_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_EXP2_DOUBLE 0
-#define GMX_SIMD_HAVE_NATIVE_EXP_DOUBLE 0
-#define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_FLOAT 1
-#define GMX_SIMD_HAVE_GATHER_LOADU_BYSIMDINT_TRANSPOSE_DOUBLE 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_FLOAT 1
-#define GMX_SIMD_HAVE_HSIMD_UTIL_DOUBLE 1
-
-#define GMX_SIMD4_HAVE_FLOAT 1
-#define GMX_SIMD4_HAVE_DOUBLE 1
-
-// Implementation details
-#define GMX_SIMD_FLOAT_WIDTH 16
-#define GMX_SIMD_DOUBLE_WIDTH 8
-#define GMX_SIMD_FINT32_WIDTH 16
-#define GMX_SIMD_DINT32_WIDTH 8
-#define GMX_SIMD4_WIDTH 4
-#define GMX_SIMD_ALIGNMENT 64 // Bytes (16*single or 8*double)
-#define GMX_SIMD_RSQRT_BITS 23
-#define GMX_SIMD_RCP_BITS 23
-
-#endif // GMX_SIMD_IMPL_X86_MIC_DEFINITIONS_H
diff --git a/src/gromacs/simd/impl_x86_mic/impl_x86_mic_simd4_double.h b/src/gromacs/simd/impl_x86_mic/impl_x86_mic_simd4_double.h
deleted file mode 100644 (file)
index b4965c9..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2017,2019, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_X86_MIC_SIMD4_DOUBLE_H
-#define GMX_SIMD_IMPL_X86_MIC_SIMD4_DOUBLE_H
-
-#include "config.h"
-
-#include <cassert>
-
-#include <immintrin.h>
-
-#include "gromacs/utility/basedefinitions.h"
-
-#include "impl_x86_mic_simd_double.h"
-
-namespace gmx
-{
-
-class Simd4Double
-{
-public:
-    Simd4Double() {}
-
-    Simd4Double(double d) : simdInternal_(_mm512_set1_pd(d)) {}
-
-    // Internal utility constructor to simplify return statements
-    Simd4Double(__m512d simd) : simdInternal_(simd) {}
-
-    __m512d simdInternal_;
-};
-
-class Simd4DBool
-{
-public:
-    Simd4DBool() {}
-
-    // Internal utility constructor to simplify return statements
-    Simd4DBool(__mmask16 simd) : simdInternal_(simd) {}
-
-    __mmask16 simdInternal_;
-};
-
-static inline Simd4Double gmx_simdcall load4(const double* m)
-{
-    assert(size_t(m) % 32 == 0);
-    return { _mm512_mask_extload_pd(_mm512_undefined_pd(), _mm512_int2mask(0xF), m,
-                                    _MM_UPCONV_PD_NONE, _MM_BROADCAST_4X8, _MM_HINT_NONE) };
-}
-
-static inline void gmx_simdcall store4(double* m, Simd4Double a)
-{
-    assert(size_t(m) % 32 == 0);
-    _mm512_mask_packstorelo_pd(m, _mm512_int2mask(0xF), a.simdInternal_);
-}
-
-static inline Simd4Double gmx_simdcall load4U(const double* m)
-{
-    return { _mm512_mask_loadunpackhi_pd(
-            _mm512_mask_loadunpacklo_pd(_mm512_undefined_pd(), _mm512_int2mask(0xF), m),
-            _mm512_int2mask(0xF), m + 8) };
-}
-
-static inline void gmx_simdcall store4U(double* m, Simd4Double a)
-{
-    _mm512_mask_packstorelo_pd(m, _mm512_int2mask(0xF), a.simdInternal_);
-    _mm512_mask_packstorehi_pd(m + 8, _mm512_int2mask(0xF), a.simdInternal_);
-}
-
-static inline Simd4Double gmx_simdcall simd4SetZeroD()
-{
-    return { _mm512_setzero_pd() };
-}
-
-static inline Simd4Double gmx_simdcall operator&(Simd4Double a, Simd4Double b)
-{
-    return { _mm512_castsi512_pd(_mm512_mask_and_epi32(
-            _mm512_undefined_epi32(), _mm512_int2mask(0x00FF), _mm512_castpd_si512(a.simdInternal_),
-            _mm512_castpd_si512(b.simdInternal_))) };
-}
-
-static inline Simd4Double gmx_simdcall andNot(Simd4Double a, Simd4Double b)
-{
-    return { _mm512_castsi512_pd(_mm512_mask_andnot_epi32(
-            _mm512_undefined_epi32(), _mm512_int2mask(0x00FF), _mm512_castpd_si512(a.simdInternal_),
-            _mm512_castpd_si512(b.simdInternal_))) };
-}
-
-static inline Simd4Double gmx_simdcall operator|(Simd4Double a, Simd4Double b)
-{
-    return { _mm512_castsi512_pd(_mm512_mask_or_epi32(
-            _mm512_undefined_epi32(), _mm512_int2mask(0x00FF), _mm512_castpd_si512(a.simdInternal_),
-            _mm512_castpd_si512(b.simdInternal_))) };
-}
-
-static inline Simd4Double gmx_simdcall operator^(Simd4Double a, Simd4Double b)
-{
-    return { _mm512_castsi512_pd(_mm512_mask_xor_epi32(
-            _mm512_undefined_epi32(), _mm512_int2mask(0x00FF), _mm512_castpd_si512(a.simdInternal_),
-            _mm512_castpd_si512(b.simdInternal_))) };
-}
-
-static inline Simd4Double gmx_simdcall operator+(Simd4Double a, Simd4Double b)
-{
-    return { _mm512_mask_add_pd(_mm512_undefined_pd(), _mm512_int2mask(0xF), a.simdInternal_,
-                                b.simdInternal_) };
-}
-
-static inline Simd4Double gmx_simdcall operator-(Simd4Double a, Simd4Double b)
-{
-    return { _mm512_mask_sub_pd(_mm512_undefined_pd(), _mm512_int2mask(0xF), a.simdInternal_,
-                                b.simdInternal_) };
-}
-
-static inline Simd4Double gmx_simdcall operator-(Simd4Double x)
-{
-    return { _mm512_mask_addn_pd(_mm512_undefined_pd(), _mm512_int2mask(0xF), x.simdInternal_,
-                                 _mm512_setzero_pd()) };
-}
-
-static inline Simd4Double gmx_simdcall operator*(Simd4Double a, Simd4Double b)
-{
-    return { _mm512_mask_mul_pd(_mm512_undefined_pd(), _mm512_int2mask(0xF), a.simdInternal_,
-                                b.simdInternal_) };
-}
-
-static inline Simd4Double gmx_simdcall fma(Simd4Double a, Simd4Double b, Simd4Double c)
-{
-    return { _mm512_mask_fmadd_pd(a.simdInternal_, _mm512_int2mask(0xF), b.simdInternal_, c.simdInternal_) };
-}
-
-static inline Simd4Double gmx_simdcall fms(Simd4Double a, Simd4Double b, Simd4Double c)
-{
-    return { _mm512_mask_fmsub_pd(a.simdInternal_, _mm512_int2mask(0xF), b.simdInternal_, c.simdInternal_) };
-}
-
-static inline Simd4Double gmx_simdcall fnma(Simd4Double a, Simd4Double b, Simd4Double c)
-{
-    return { _mm512_mask_fnmadd_pd(a.simdInternal_, _mm512_int2mask(0xF), b.simdInternal_, c.simdInternal_) };
-}
-
-static inline Simd4Double gmx_simdcall fnms(Simd4Double a, Simd4Double b, Simd4Double c)
-{
-    return { _mm512_mask_fnmsub_pd(a.simdInternal_, _mm512_int2mask(0xF), b.simdInternal_, c.simdInternal_) };
-}
-
-static inline Simd4Double gmx_simdcall rsqrt(Simd4Double x)
-{
-    return { _mm512_mask_cvtpslo_pd(
-            _mm512_undefined_pd(), _mm512_int2mask(0xF),
-            _mm512_mask_rsqrt23_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF),
-                                   _mm512_mask_cvtpd_pslo(_mm512_undefined_ps(),
-                                                          _mm512_int2mask(0xF), x.simdInternal_))) };
-}
-
-static inline Simd4Double gmx_simdcall abs(Simd4Double x)
-{
-    return { _mm512_castsi512_pd(_mm512_mask_andnot_epi32(
-            _mm512_undefined_epi32(), _mm512_int2mask(0x00FF),
-            _mm512_castpd_si512(_mm512_set1_pd(GMX_DOUBLE_NEGZERO)), _mm512_castpd_si512(x.simdInternal_)))
-
-    };
-}
-
-static inline Simd4Double gmx_simdcall max(Simd4Double a, Simd4Double b)
-{
-    return { _mm512_mask_gmax_pd(_mm512_undefined_pd(), _mm512_int2mask(0xF), a.simdInternal_,
-                                 b.simdInternal_) };
-}
-
-static inline Simd4Double gmx_simdcall min(Simd4Double a, Simd4Double b)
-{
-    return { _mm512_mask_gmin_pd(_mm512_undefined_pd(), _mm512_int2mask(0xF), a.simdInternal_,
-                                 b.simdInternal_) };
-}
-
-static inline Simd4Double gmx_simdcall round(Simd4Double x)
-{
-    return { _mm512_mask_roundfxpnt_adjust_pd(_mm512_undefined_pd(), _mm512_int2mask(0xF), x.simdInternal_,
-                                              _MM_FROUND_TO_NEAREST_INT, _MM_EXPADJ_NONE) };
-}
-
-static inline Simd4Double gmx_simdcall trunc(Simd4Double x)
-{
-    return { _mm512_mask_roundfxpnt_adjust_pd(_mm512_undefined_pd(), _mm512_int2mask(0xF),
-                                              x.simdInternal_, _MM_FROUND_TO_ZERO, _MM_EXPADJ_NONE) };
-}
-
-static inline double gmx_simdcall dotProduct(Simd4Double a, Simd4Double b)
-{
-    return _mm512_mask_reduce_add_pd(_mm512_int2mask(7),
-                                     _mm512_mask_mul_pd(_mm512_undefined_pd(), _mm512_int2mask(7),
-                                                        a.simdInternal_, b.simdInternal_));
-}
-
-static inline void gmx_simdcall transpose(Simd4Double* v0, Simd4Double* v1, Simd4Double* v2, Simd4Double* v3)
-{
-    __m512i t0 = _mm512_mask_permute4f128_epi32(_mm512_castpd_si512(v0->simdInternal_), 0xFF00,
-                                                _mm512_castpd_si512(v1->simdInternal_), _MM_PERM_BABA);
-    __m512i t1 = _mm512_mask_permute4f128_epi32(_mm512_castpd_si512(v2->simdInternal_), 0xFF00,
-                                                _mm512_castpd_si512(v3->simdInternal_), _MM_PERM_BABA);
-
-    t0 = _mm512_permutevar_epi32(
-            _mm512_set_epi32(15, 14, 7, 6, 13, 12, 5, 4, 11, 10, 3, 2, 9, 8, 1, 0), t0);
-    t1 = _mm512_permutevar_epi32(
-            _mm512_set_epi32(15, 14, 7, 6, 13, 12, 5, 4, 11, 10, 3, 2, 9, 8, 1, 0), t1);
-
-    v0->simdInternal_ = _mm512_mask_swizzle_pd(_mm512_castsi512_pd(t0), _mm512_int2mask(0xCC),
-                                               _mm512_castsi512_pd(t1), _MM_SWIZ_REG_BADC);
-    v1->simdInternal_ = _mm512_mask_swizzle_pd(_mm512_castsi512_pd(t1), _mm512_int2mask(0x33),
-                                               _mm512_castsi512_pd(t0), _MM_SWIZ_REG_BADC);
-
-    v2->simdInternal_ =
-            _mm512_castps_pd(_mm512_permute4f128_ps(_mm512_castpd_ps(v0->simdInternal_), _MM_PERM_DCDC));
-    v3->simdInternal_ =
-            _mm512_castps_pd(_mm512_permute4f128_ps(_mm512_castpd_ps(v1->simdInternal_), _MM_PERM_DCDC));
-}
-
-// Picky, picky, picky:
-// icc-16 complains about "Illegal value of immediate argument to intrinsic"
-// unless we use
-// 1) Ordered-quiet for ==
-// 2) Unordered-quiet for !=
-// 3) Ordered-signaling for < and <=
-
-static inline Simd4DBool gmx_simdcall operator==(Simd4Double a, Simd4Double b)
-{
-    return { _mm512_mask_cmp_pd_mask(_mm512_int2mask(0xF), a.simdInternal_, b.simdInternal_, _CMP_EQ_OQ) };
-}
-
-static inline Simd4DBool gmx_simdcall operator!=(Simd4Double a, Simd4Double b)
-{
-    return { _mm512_mask_cmp_pd_mask(_mm512_int2mask(0xF), a.simdInternal_, b.simdInternal_, _CMP_NEQ_UQ) };
-}
-
-static inline Simd4DBool gmx_simdcall operator<(Simd4Double a, Simd4Double b)
-{
-    return { _mm512_mask_cmp_pd_mask(_mm512_int2mask(0xF), a.simdInternal_, b.simdInternal_, _CMP_LT_OS) };
-}
-
-static inline Simd4DBool gmx_simdcall operator<=(Simd4Double a, Simd4Double b)
-{
-    return { _mm512_mask_cmp_pd_mask(_mm512_int2mask(0xF), a.simdInternal_, b.simdInternal_, _CMP_LE_OS) };
-}
-
-static inline Simd4DBool gmx_simdcall operator&&(Simd4DBool a, Simd4DBool b)
-{
-    return { _mm512_kand(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4DBool gmx_simdcall operator||(Simd4DBool a, Simd4DBool b)
-{
-    return { _mm512_kor(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline bool gmx_simdcall anyTrue(Simd4DBool a)
-{
-    return (_mm512_mask2int(a.simdInternal_) & 0xF) != 0;
-}
-
-static inline Simd4Double gmx_simdcall selectByMask(Simd4Double a, Simd4DBool m)
-{
-    return { _mm512_mask_mov_pd(_mm512_setzero_pd(), m.simdInternal_, a.simdInternal_) };
-}
-
-static inline Simd4Double gmx_simdcall selectByNotMask(Simd4Double a, Simd4DBool m)
-{
-    return { _mm512_mask_mov_pd(_mm512_setzero_pd(), _mm512_knot(m.simdInternal_), a.simdInternal_) };
-}
-
-static inline Simd4Double gmx_simdcall blend(Simd4Double a, Simd4Double b, Simd4DBool sel)
-{
-    return { _mm512_mask_blend_pd(sel.simdInternal_, a.simdInternal_, b.simdInternal_) };
-}
-
-static inline double gmx_simdcall reduce(Simd4Double a)
-{
-    return _mm512_mask_reduce_add_pd(_mm512_int2mask(0xF), a.simdInternal_);
-}
-
-} // namespace gmx
-
-#endif // GMX_SIMD_IMPL_X86_MIC_SIMD4_DOUBLE_H
diff --git a/src/gromacs/simd/impl_x86_mic/impl_x86_mic_simd4_float.h b/src/gromacs/simd/impl_x86_mic/impl_x86_mic_simd4_float.h
deleted file mode 100644 (file)
index a9bb3a8..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2019, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_X86_MIC_SIMD4_FLOAT_H
-#define GMX_SIMD_IMPL_X86_MIC_SIMD4_FLOAT_H
-
-#include "config.h"
-
-#include <cassert>
-
-#include <immintrin.h>
-
-#include "gromacs/utility/basedefinitions.h"
-
-#include "impl_x86_mic_simd_float.h"
-
-namespace gmx
-{
-
-class Simd4Float
-{
-public:
-    Simd4Float() {}
-
-    Simd4Float(float f) : simdInternal_(_mm512_set1_ps(f)) {}
-
-    // Internal utility constructor to simplify return statements
-    Simd4Float(__m512 simd) : simdInternal_(simd) {}
-
-    __m512 simdInternal_;
-};
-
-class Simd4FBool
-{
-public:
-    Simd4FBool() {}
-
-    // Internal utility constructor to simplify return statements
-    Simd4FBool(__mmask16 simd) : simdInternal_(simd) {}
-
-    __mmask16 simdInternal_;
-};
-
-static inline Simd4Float gmx_simdcall load4(const float* m)
-{
-    assert(size_t(m) % 16 == 0);
-    return { _mm512_mask_extload_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF), m,
-                                    _MM_UPCONV_PS_NONE, _MM_BROADCAST_4X16, _MM_HINT_NONE) };
-}
-
-static inline void gmx_simdcall store4(float* m, Simd4Float a)
-{
-    assert(size_t(m) % 16 == 0);
-    _mm512_mask_packstorelo_ps(m, _mm512_int2mask(0xF), a.simdInternal_);
-}
-
-static inline Simd4Float gmx_simdcall load4U(const float* m)
-{
-    return { _mm512_mask_loadunpackhi_ps(
-            _mm512_mask_loadunpacklo_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF), m),
-            _mm512_int2mask(0xF), m + 16) };
-}
-
-static inline void gmx_simdcall store4U(float* m, Simd4Float a)
-{
-    _mm512_mask_packstorelo_ps(m, _mm512_int2mask(0xF), a.simdInternal_);
-    _mm512_mask_packstorehi_ps(m + 16, _mm512_int2mask(0xF), a.simdInternal_);
-}
-
-static inline Simd4Float gmx_simdcall simd4SetZeroF()
-{
-    return { _mm512_setzero_ps() };
-}
-
-static inline Simd4Float gmx_simdcall operator&(Simd4Float a, Simd4Float b)
-{
-    return { _mm512_castsi512_ps(_mm512_mask_and_epi32(_mm512_undefined_epi32(), _mm512_int2mask(0xF),
-                                                       _mm512_castps_si512(a.simdInternal_),
-                                                       _mm512_castps_si512(b.simdInternal_))) };
-}
-
-static inline Simd4Float gmx_simdcall andNot(Simd4Float a, Simd4Float b)
-{
-    return { _mm512_castsi512_ps(_mm512_mask_andnot_epi32(
-            _mm512_undefined_epi32(), _mm512_int2mask(0xF), _mm512_castps_si512(a.simdInternal_),
-            _mm512_castps_si512(b.simdInternal_))) };
-}
-
-static inline Simd4Float gmx_simdcall operator|(Simd4Float a, Simd4Float b)
-{
-    return { _mm512_castsi512_ps(_mm512_mask_or_epi32(_mm512_undefined_epi32(), _mm512_int2mask(0xF),
-                                                      _mm512_castps_si512(a.simdInternal_),
-                                                      _mm512_castps_si512(b.simdInternal_))) };
-}
-
-static inline Simd4Float gmx_simdcall operator^(Simd4Float a, Simd4Float b)
-{
-    return { _mm512_castsi512_ps(_mm512_mask_xor_epi32(_mm512_undefined_epi32(), _mm512_int2mask(0xF),
-                                                       _mm512_castps_si512(a.simdInternal_),
-                                                       _mm512_castps_si512(b.simdInternal_))) };
-}
-
-static inline Simd4Float gmx_simdcall operator+(Simd4Float a, Simd4Float b)
-{
-    return { _mm512_mask_add_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF), a.simdInternal_,
-                                b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall operator-(Simd4Float a, Simd4Float b)
-{
-    return { _mm512_mask_sub_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF), a.simdInternal_,
-                                b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall operator-(Simd4Float x)
-{
-    return { _mm512_mask_addn_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF), x.simdInternal_,
-                                 _mm512_setzero_ps()) };
-}
-
-static inline Simd4Float gmx_simdcall operator*(Simd4Float a, Simd4Float b)
-{
-    return { _mm512_mask_mul_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF), a.simdInternal_,
-                                b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall fma(Simd4Float a, Simd4Float b, Simd4Float c)
-{
-    return { _mm512_mask_fmadd_ps(a.simdInternal_, _mm512_int2mask(0xF), b.simdInternal_, c.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall fms(Simd4Float a, Simd4Float b, Simd4Float c)
-{
-    return { _mm512_mask_fmsub_ps(a.simdInternal_, _mm512_int2mask(0xF), b.simdInternal_, c.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall fnma(Simd4Float a, Simd4Float b, Simd4Float c)
-{
-    return { _mm512_mask_fnmadd_ps(a.simdInternal_, _mm512_int2mask(0xF), b.simdInternal_, c.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall fnms(Simd4Float a, Simd4Float b, Simd4Float c)
-{
-    return { _mm512_mask_fnmsub_ps(a.simdInternal_, _mm512_int2mask(0xF), b.simdInternal_, c.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall rsqrt(Simd4Float x)
-{
-    return { _mm512_mask_rsqrt23_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF), x.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall abs(Simd4Float x)
-{
-    return { _mm512_castsi512_ps(_mm512_mask_andnot_epi32(
-            _mm512_undefined_epi32(), _mm512_int2mask(0xF),
-            _mm512_castps_si512(_mm512_set1_ps(GMX_FLOAT_NEGZERO)), _mm512_castps_si512(x.simdInternal_))) };
-}
-
-static inline Simd4Float gmx_simdcall max(Simd4Float a, Simd4Float b)
-{
-    return { _mm512_mask_gmax_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF), a.simdInternal_,
-                                 b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall min(Simd4Float a, Simd4Float b)
-{
-    return { _mm512_mask_gmin_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF), a.simdInternal_,
-                                 b.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall round(Simd4Float x)
-{
-    return { _mm512_mask_round_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF), x.simdInternal_,
-                                  _MM_FROUND_TO_NEAREST_INT, _MM_EXPADJ_NONE) };
-}
-
-static inline Simd4Float gmx_simdcall trunc(Simd4Float x)
-{
-    return { _mm512_mask_round_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF), x.simdInternal_,
-                                  _MM_FROUND_TO_ZERO, _MM_EXPADJ_NONE) };
-}
-
-static inline float gmx_simdcall dotProduct(Simd4Float a, Simd4Float b)
-{
-    __m512 x = _mm512_mask_mul_ps(_mm512_setzero_ps(), _mm512_int2mask(0x7), a.simdInternal_,
-                                  b.simdInternal_);
-    x        = _mm512_add_ps(x, _mm512_swizzle_ps(x, _MM_SWIZ_REG_BADC));
-    x        = _mm512_add_ps(x, _mm512_swizzle_ps(x, _MM_SWIZ_REG_CDAB));
-    float f;
-    _mm512_mask_packstorelo_ps(&f, _mm512_mask2int(0x1), x);
-    return f;
-}
-
-static inline void gmx_simdcall transpose(Simd4Float* v0, Simd4Float* v1, Simd4Float* v2, Simd4Float* v3)
-{
-    v0->simdInternal_ = _mm512_mask_permute4f128_ps(v0->simdInternal_, _mm512_int2mask(0x00F0),
-                                                    v1->simdInternal_, _MM_PERM_AAAA);
-    v2->simdInternal_ = _mm512_mask_permute4f128_ps(v2->simdInternal_, _mm512_int2mask(0x00F0),
-                                                    v3->simdInternal_, _MM_PERM_AAAA);
-    v0->simdInternal_ = _mm512_mask_permute4f128_ps(v0->simdInternal_, _mm512_int2mask(0xFF00),
-                                                    v2->simdInternal_, _MM_PERM_BABA);
-    v0->simdInternal_ = _mm512_castsi512_ps(_mm512_permutevar_epi32(
-            _mm512_set_epi32(15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0),
-            _mm512_castps_si512(v0->simdInternal_)));
-    v1->simdInternal_ = _mm512_mask_permute4f128_ps(_mm512_setzero_ps(), _mm512_int2mask(0x000F),
-                                                    v0->simdInternal_, _MM_PERM_BBBB);
-    v2->simdInternal_ = _mm512_mask_permute4f128_ps(_mm512_setzero_ps(), _mm512_int2mask(0x000F),
-                                                    v0->simdInternal_, _MM_PERM_CCCC);
-    v3->simdInternal_ = _mm512_mask_permute4f128_ps(_mm512_setzero_ps(), _mm512_int2mask(0x000F),
-                                                    v0->simdInternal_, _MM_PERM_DDDD);
-}
-
-// Picky, picky, picky:
-// icc-16 complains about "Illegal value of immediate argument to intrinsic"
-// unless we use
-// 1) Ordered-quiet for ==
-// 2) Unordered-quiet for !=
-// 3) Ordered-signaling for < and <=
-
-static inline Simd4FBool gmx_simdcall operator==(Simd4Float a, Simd4Float b)
-{
-    return { _mm512_mask_cmp_ps_mask(_mm512_int2mask(0xF), a.simdInternal_, b.simdInternal_, _CMP_EQ_OQ) };
-}
-
-static inline Simd4FBool gmx_simdcall operator!=(Simd4Float a, Simd4Float b)
-{
-    return { _mm512_mask_cmp_ps_mask(_mm512_int2mask(0xF), a.simdInternal_, b.simdInternal_, _CMP_NEQ_UQ) };
-}
-
-static inline Simd4FBool gmx_simdcall operator<(Simd4Float a, Simd4Float b)
-{
-    return { _mm512_mask_cmp_ps_mask(_mm512_int2mask(0xF), a.simdInternal_, b.simdInternal_, _CMP_LT_OS) };
-}
-
-static inline Simd4FBool gmx_simdcall operator<=(Simd4Float a, Simd4Float b)
-{
-    return { _mm512_mask_cmp_ps_mask(_mm512_int2mask(0xF), a.simdInternal_, b.simdInternal_, _CMP_LE_OS) };
-}
-
-static inline Simd4FBool gmx_simdcall operator&&(Simd4FBool a, Simd4FBool b)
-{
-    return { _mm512_kand(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline Simd4FBool gmx_simdcall operator||(Simd4FBool a, Simd4FBool b)
-{
-    return { _mm512_kor(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline bool gmx_simdcall anyTrue(Simd4FBool a)
-{
-    return (_mm512_mask2int(a.simdInternal_) & 0xF) != 0;
-}
-
-static inline Simd4Float gmx_simdcall selectByMask(Simd4Float a, Simd4FBool m)
-{
-    return { _mm512_mask_mov_ps(_mm512_setzero_ps(), m.simdInternal_, a.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall selectByNotMask(Simd4Float a, Simd4FBool m)
-{
-    return { _mm512_mask_mov_ps(_mm512_setzero_ps(), _mm512_knot(m.simdInternal_), a.simdInternal_) };
-}
-
-static inline Simd4Float gmx_simdcall blend(Simd4Float a, Simd4Float b, Simd4FBool sel)
-{
-    return { _mm512_mask_blend_ps(sel.simdInternal_, a.simdInternal_, b.simdInternal_) };
-}
-
-static inline float gmx_simdcall reduce(Simd4Float a)
-{
-    __m512 x = a.simdInternal_;
-    x        = _mm512_add_ps(x, _mm512_swizzle_ps(x, _MM_SWIZ_REG_BADC));
-    x        = _mm512_add_ps(x, _mm512_swizzle_ps(x, _MM_SWIZ_REG_CDAB));
-    float f;
-    _mm512_mask_packstorelo_ps(&f, _mm512_mask2int(0x1), x);
-    return f;
-}
-
-} // namespace gmx
-
-#endif // GMX_SIMD_IMPL_X86_MIC_SIMD4_FLOAT_H
diff --git a/src/gromacs/simd/impl_x86_mic/impl_x86_mic_simd_double.h b/src/gromacs/simd/impl_x86_mic/impl_x86_mic_simd_double.h
deleted file mode 100644 (file)
index 7fe86f9..0000000
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2016,2017,2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_X86_MIC_SIMD_DOUBLE_H
-#define GMX_SIMD_IMPL_X86_MIC_SIMD_DOUBLE_H
-
-#include "config.h"
-
-#include <cassert>
-#include <cstdint>
-
-#include <immintrin.h>
-
-#include "gromacs/math/utilities.h"
-#include "gromacs/utility/basedefinitions.h"
-
-#include "impl_x86_mic_simd_float.h"
-
-namespace gmx
-{
-
-class SimdDouble
-{
-public:
-    SimdDouble() {}
-
-    SimdDouble(double d) : simdInternal_(_mm512_set1_pd(d)) {}
-
-    // Internal utility constructor to simplify return statements
-    SimdDouble(__m512d simd) : simdInternal_(simd) {}
-
-    __m512d simdInternal_;
-};
-
-class SimdDInt32
-{
-public:
-    SimdDInt32() {}
-
-    SimdDInt32(std::int32_t i) : simdInternal_(_mm512_set1_epi32(i)) {}
-
-    // Internal utility constructor to simplify return statements
-    SimdDInt32(__m512i simd) : simdInternal_(simd) {}
-
-    __m512i simdInternal_;
-};
-
-class SimdDBool
-{
-public:
-    SimdDBool() {}
-
-    // Internal utility constructor to simplify return statements
-    SimdDBool(__mmask8 simd) : simdInternal_(simd) {}
-
-    __mmask8 simdInternal_;
-};
-
-class SimdDIBool
-{
-public:
-    SimdDIBool() {}
-
-    // Internal utility constructor to simplify return statements
-    SimdDIBool(__mmask16 simd) : simdInternal_(simd) {}
-
-    __mmask16 simdInternal_;
-};
-
-static inline SimdDouble gmx_simdcall simdLoad(const double* m, SimdDoubleTag = {})
-{
-    assert(std::size_t(m) % 64 == 0);
-    return { _mm512_load_pd(m) };
-}
-
-static inline void gmx_simdcall store(double* m, SimdDouble a)
-{
-    assert(std::size_t(m) % 64 == 0);
-    _mm512_store_pd(m, a.simdInternal_);
-}
-
-static inline SimdDouble gmx_simdcall simdLoadU(const double* m, SimdDoubleTag = {})
-{
-    return { _mm512_loadunpackhi_pd(_mm512_loadunpacklo_pd(_mm512_undefined_pd(), m), m + 8) };
-}
-
-static inline void gmx_simdcall storeU(double* m, SimdDouble a)
-{
-    _mm512_packstorelo_pd(m, a.simdInternal_);
-    _mm512_packstorehi_pd(m + 8, a.simdInternal_);
-}
-
-static inline SimdDouble gmx_simdcall setZeroD()
-{
-    return { _mm512_setzero_pd() };
-}
-
-static inline SimdDInt32 gmx_simdcall simdLoad(const std::int32_t* m, SimdDInt32Tag)
-{
-    assert(std::size_t(m) % 32 == 0);
-    return { _mm512_extload_epi64(m, _MM_UPCONV_EPI64_NONE, _MM_BROADCAST_4X8, _MM_HINT_NONE) };
-}
-
-static inline void gmx_simdcall store(std::int32_t* m, SimdDInt32 a)
-{
-    assert(std::size_t(m) % 32 == 0);
-    _mm512_mask_packstorelo_epi32(m, _mm512_int2mask(0x00FF), a.simdInternal_);
-}
-
-static inline SimdDInt32 gmx_simdcall simdLoadU(const std::int32_t* m, SimdDInt32Tag)
-{
-    return { _mm512_mask_loadunpackhi_epi32(
-            _mm512_mask_loadunpacklo_epi32(_mm512_undefined_epi32(), _mm512_int2mask(0x00FF), m),
-            _mm512_int2mask(0x00FF), m + 16) };
-}
-
-static inline void gmx_simdcall storeU(std::int32_t* m, SimdDInt32 a)
-{
-    _mm512_mask_packstorelo_epi32(m, _mm512_int2mask(0x00FF), a.simdInternal_);
-    _mm512_mask_packstorehi_epi32(m + 16, _mm512_int2mask(0x00FF), a.simdInternal_);
-}
-
-static inline SimdDInt32 gmx_simdcall setZeroDI()
-{
-    return { _mm512_setzero_epi32() };
-}
-
-template<int index>
-static inline std::int32_t gmx_simdcall extract(SimdDInt32 a)
-{
-    int r;
-    _mm512_mask_packstorelo_epi32(&r, _mm512_mask2int(1 << index), a.simdInternal_);
-    return r;
-}
-
-static inline SimdDouble gmx_simdcall operator&(SimdDouble a, SimdDouble b)
-{
-    return { _mm512_castsi512_pd(_mm512_and_epi32(_mm512_castpd_si512(a.simdInternal_),
-                                                  _mm512_castpd_si512(b.simdInternal_))) };
-}
-
-static inline SimdDouble gmx_simdcall andNot(SimdDouble a, SimdDouble b)
-{
-    return { _mm512_castsi512_pd(_mm512_andnot_epi32(_mm512_castpd_si512(a.simdInternal_),
-                                                     _mm512_castpd_si512(b.simdInternal_))) };
-}
-
-static inline SimdDouble gmx_simdcall operator|(SimdDouble a, SimdDouble b)
-{
-    return { _mm512_castsi512_pd(_mm512_or_epi32(_mm512_castpd_si512(a.simdInternal_),
-                                                 _mm512_castpd_si512(b.simdInternal_))) };
-}
-
-static inline SimdDouble gmx_simdcall operator^(SimdDouble a, SimdDouble b)
-{
-    return { _mm512_castsi512_pd(_mm512_xor_epi32(_mm512_castpd_si512(a.simdInternal_),
-                                                  _mm512_castpd_si512(b.simdInternal_))) };
-}
-
-static inline SimdDouble gmx_simdcall operator+(SimdDouble a, SimdDouble b)
-{
-    return { _mm512_add_pd(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDouble gmx_simdcall operator-(SimdDouble a, SimdDouble b)
-{
-    return { _mm512_sub_pd(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDouble gmx_simdcall operator-(SimdDouble x)
-{
-    return { _mm512_addn_pd(x.simdInternal_, _mm512_setzero_pd()) };
-}
-
-static inline SimdDouble gmx_simdcall operator*(SimdDouble a, SimdDouble b)
-{
-    return { _mm512_mul_pd(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDouble gmx_simdcall fma(SimdDouble a, SimdDouble b, SimdDouble c)
-{
-    return { _mm512_fmadd_pd(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline SimdDouble gmx_simdcall fms(SimdDouble a, SimdDouble b, SimdDouble c)
-{
-    return { _mm512_fmsub_pd(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline SimdDouble gmx_simdcall fnma(SimdDouble a, SimdDouble b, SimdDouble c)
-{
-    return { _mm512_fnmadd_pd(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline SimdDouble gmx_simdcall fnms(SimdDouble a, SimdDouble b, SimdDouble c)
-{
-    return { _mm512_fnmsub_pd(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline SimdDouble gmx_simdcall rsqrt(SimdDouble x)
-{
-    return { _mm512_cvtpslo_pd(_mm512_rsqrt23_ps(_mm512_cvtpd_pslo(x.simdInternal_))) };
-}
-
-static inline SimdDouble gmx_simdcall rcp(SimdDouble x)
-{
-    return { _mm512_cvtpslo_pd(_mm512_rcp23_ps(_mm512_cvtpd_pslo(x.simdInternal_))) };
-}
-
-static inline SimdDouble gmx_simdcall maskAdd(SimdDouble a, SimdDouble b, SimdDBool m)
-{
-    return { _mm512_mask_add_pd(a.simdInternal_, m.simdInternal_, a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDouble gmx_simdcall maskzMul(SimdDouble a, SimdDouble b, SimdDBool m)
-{
-    return { _mm512_mask_mul_pd(_mm512_setzero_pd(), m.simdInternal_, a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDouble gmx_simdcall maskzFma(SimdDouble a, SimdDouble b, SimdDouble c, SimdDBool m)
-{
-    return { _mm512_mask_mov_pd(_mm512_setzero_pd(), m.simdInternal_,
-                                _mm512_fmadd_pd(a.simdInternal_, b.simdInternal_, c.simdInternal_)) };
-}
-
-static inline SimdDouble gmx_simdcall maskzRsqrt(SimdDouble x, SimdDBool m)
-{
-    return { _mm512_cvtpslo_pd(_mm512_mask_rsqrt23_ps(_mm512_setzero_ps(), m.simdInternal_,
-                                                      _mm512_cvtpd_pslo(x.simdInternal_))) };
-}
-
-static inline SimdDouble gmx_simdcall maskzRcp(SimdDouble x, SimdDBool m)
-{
-    return { _mm512_cvtpslo_pd(_mm512_mask_rcp23_ps(_mm512_setzero_ps(), m.simdInternal_,
-                                                    _mm512_cvtpd_pslo(x.simdInternal_))) };
-}
-
-static inline SimdDouble gmx_simdcall abs(SimdDouble x)
-{
-    return { _mm512_castsi512_pd(_mm512_andnot_epi32(_mm512_castpd_si512(_mm512_set1_pd(GMX_DOUBLE_NEGZERO)),
-                                                     _mm512_castpd_si512(x.simdInternal_))) };
-}
-
-static inline SimdDouble gmx_simdcall max(SimdDouble a, SimdDouble b)
-{
-    return { _mm512_gmax_pd(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDouble gmx_simdcall min(SimdDouble a, SimdDouble b)
-{
-    return { _mm512_gmin_pd(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDouble gmx_simdcall round(SimdDouble x)
-{
-    return { _mm512_roundfxpnt_adjust_pd(x.simdInternal_, _MM_FROUND_TO_NEAREST_INT, _MM_EXPADJ_NONE) };
-}
-
-static inline SimdDouble gmx_simdcall trunc(SimdDouble x)
-{
-    return { _mm512_roundfxpnt_adjust_pd(x.simdInternal_, _MM_FROUND_TO_ZERO, _MM_EXPADJ_NONE) };
-}
-
-template<MathOptimization opt = MathOptimization::Safe>
-static inline SimdDouble frexp(SimdDouble value, SimdDInt32* exponent)
-{
-    __m512d rExponent;
-    __m512i iExponent;
-    __m512d result;
-
-    if (opt == MathOptimization::Safe)
-    {
-        // For the safe branch, we use the masked operations to only assign results if the
-        // input value was nonzero, and otherwise set exponent to 0, and the fraction to the input (+-0).
-        __mmask8 valueIsNonZero =
-                _mm512_cmp_pd_mask(_mm512_setzero_pd(), value.simdInternal_, _CMP_NEQ_OQ);
-        rExponent = _mm512_mask_getexp_pd(_mm512_setzero_pd(), valueIsNonZero, value.simdInternal_);
-
-        // Create an integer -1 value, and use masking in the conversion as the result for
-        // zero-value input. When we later add 1 to all fields, the fields that were formerly -1
-        // (corresponding to zero exponent) will be assigned -1 + 1 = 0.
-        iExponent = _mm512_mask_cvtfxpnt_roundpd_epi32lo(_mm512_set_epi32(-1), valueIsNonZero,
-                                                         rExponent, _MM_FROUND_TO_NEAREST_INT);
-        iExponent = _mm512__add_epi32(iExponent, _mm512_set1_epi32(1));
-
-        // Set result to value (+-0) when it is zero.
-        result = _mm512_mask_getmant_pd(value.simdInternal_, valueIsNonZero, value.simdInternal_,
-                                        _MM_MANT_NORM_p5_1, _MM_MANT_SIGN_src);
-    }
-    else
-    {
-        rExponent = _mm512_getexp_pd(value.simdInternal_);
-        iExponent = _mm512_cvtfxpnt_roundpd_epi32lo(rExponent, _MM_FROUND_TO_NEAREST_INT);
-        iExponent = _mm512_add_epi32(iExponent, _mm512_set1_epi32(1));
-        result    = _mm512_getmant_pd(value.simdInternal_, _MM_MANT_NORM_p5_1, _MM_MANT_SIGN_src);
-    }
-
-    exponent->simdInternal_ = iExponent;
-
-    return { result };
-}
-
-template<MathOptimization opt = MathOptimization::Safe>
-static inline SimdDouble ldexp(SimdDouble value, SimdDInt32 exponent)
-{
-    const __m512i exponentBias = _mm512_set1_epi32(1023);
-    __m512i       iExponent    = _mm512_add_epi32(exponent.simdInternal_, exponentBias);
-
-    if (opt == MathOptimization::Safe)
-    {
-        // Make sure biased argument is not negative
-        iExponent = _mm512_max_epi32(iExponent, _mm512_setzero_epi32());
-    }
-
-    iExponent = _mm512_permutevar_epi32(
-            _mm512_set_epi32(7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0), iExponent);
-    iExponent = _mm512_mask_slli_epi32(_mm512_setzero_epi32(), _mm512_int2mask(0xAAAA), iExponent, 20);
-    return _mm512_mul_pd(_mm512_castsi512_pd(iExponent), value.simdInternal_);
-}
-
-static inline double gmx_simdcall reduce(SimdDouble a)
-{
-    return _mm512_reduce_add_pd(a.simdInternal_);
-}
-
-// Picky, picky, picky:
-// icc-16 complains about "Illegal value of immediate argument to intrinsic"
-// unless we use
-// 1) Ordered-quiet for ==
-// 2) Unordered-quiet for !=
-// 3) Ordered-signaling for < and <=
-
-static inline SimdDBool gmx_simdcall operator==(SimdDouble a, SimdDouble b)
-{
-    return { _mm512_cmp_pd_mask(a.simdInternal_, b.simdInternal_, _CMP_EQ_OQ) };
-}
-
-static inline SimdDBool gmx_simdcall operator!=(SimdDouble a, SimdDouble b)
-{
-    return { _mm512_cmp_pd_mask(a.simdInternal_, b.simdInternal_, _CMP_NEQ_UQ) };
-}
-
-static inline SimdDBool gmx_simdcall operator<(SimdDouble a, SimdDouble b)
-{
-    return { _mm512_cmp_pd_mask(a.simdInternal_, b.simdInternal_, _CMP_LT_OS) };
-}
-
-static inline SimdDBool gmx_simdcall operator<=(SimdDouble a, SimdDouble b)
-{
-    return { _mm512_cmp_pd_mask(a.simdInternal_, b.simdInternal_, _CMP_LE_OS) };
-}
-
-static inline SimdDBool gmx_simdcall testBits(SimdDouble a)
-{
-    // This is a bit problematic since Knight's corner does not have any 64-bit integer comparisons,
-    // and we cannot use floating-point since values with just a single bit set can evaluate to 0.0.
-    // Instead, we do it as
-    // 1) Do a logical or of the high/low 32 bits
-    // 2) Do a permute so we have the low 32 bits of each value in the low 8 32-bit elements
-    // 3) Do an integer comparison, and cast so we just keep the low 8 bits of the mask.
-    //
-    // By default we will use integers for the masks in the nonbonded kernels, so this shouldn't
-    // have any significant performance drawbacks.
-
-    __m512i ia = _mm512_castpd_si512(a.simdInternal_);
-
-    ia = _mm512_or_epi32(ia, _mm512_swizzle_epi32(ia, _MM_SWIZ_REG_CDAB));
-    ia = _mm512_permutevar_epi32(
-            _mm512_set_epi32(15, 13, 11, 9, 7, 5, 3, 1, 14, 12, 10, 8, 6, 4, 2, 0), ia);
-
-    return { static_cast<__mmask8>(_mm512_cmp_epi32_mask(ia, _mm512_setzero_si512(), _MM_CMPINT_NE)) };
-}
-
-static inline SimdDBool gmx_simdcall operator&&(SimdDBool a, SimdDBool b)
-{
-    return { static_cast<__mmask8>(_mm512_kand(a.simdInternal_, b.simdInternal_)) };
-}
-
-static inline SimdDBool gmx_simdcall operator||(SimdDBool a, SimdDBool b)
-{
-    return { static_cast<__mmask8>(_mm512_kor(a.simdInternal_, b.simdInternal_)) };
-}
-
-static inline bool gmx_simdcall anyTrue(SimdDBool a)
-{
-    return _mm512_mask2int(a.simdInternal_) != 0;
-}
-
-static inline SimdDouble gmx_simdcall selectByMask(SimdDouble a, SimdDBool m)
-{
-    return { _mm512_mask_mov_pd(_mm512_setzero_pd(), m.simdInternal_, a.simdInternal_) };
-}
-
-static inline SimdDouble gmx_simdcall selectByNotMask(SimdDouble a, SimdDBool m)
-{
-    return { _mm512_mask_mov_pd(a.simdInternal_, m.simdInternal_, _mm512_setzero_pd()) };
-}
-
-static inline SimdDouble gmx_simdcall blend(SimdDouble a, SimdDouble b, SimdDBool sel)
-{
-    return { _mm512_mask_blend_pd(sel.simdInternal_, a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDInt32 gmx_simdcall operator&(SimdDInt32 a, SimdDInt32 b)
-{
-    return { _mm512_and_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDInt32 gmx_simdcall andNot(SimdDInt32 a, SimdDInt32 b)
-{
-    return { _mm512_andnot_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDInt32 gmx_simdcall operator|(SimdDInt32 a, SimdDInt32 b)
-{
-    return { _mm512_or_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDInt32 gmx_simdcall operator^(SimdDInt32 a, SimdDInt32 b)
-{
-    return { _mm512_xor_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDInt32 gmx_simdcall operator+(SimdDInt32 a, SimdDInt32 b)
-{
-    return { _mm512_add_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDInt32 gmx_simdcall operator-(SimdDInt32 a, SimdDInt32 b)
-{
-    return { _mm512_sub_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDInt32 gmx_simdcall operator*(SimdDInt32 a, SimdDInt32 b)
-{
-    return { _mm512_mullo_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDIBool gmx_simdcall operator==(SimdDInt32 a, SimdDInt32 b)
-{
-    return { _mm512_cmp_epi32_mask(a.simdInternal_, b.simdInternal_, _MM_CMPINT_EQ) };
-}
-
-static inline SimdDIBool gmx_simdcall testBits(SimdDInt32 a)
-{
-    return { _mm512_cmp_epi32_mask(a.simdInternal_, _mm512_setzero_si512(), _MM_CMPINT_NE) };
-}
-
-static inline SimdDIBool gmx_simdcall operator<(SimdDInt32 a, SimdDInt32 b)
-{
-    return { _mm512_cmp_epi32_mask(a.simdInternal_, b.simdInternal_, _MM_CMPINT_LT) };
-}
-
-static inline SimdDIBool gmx_simdcall operator&&(SimdDIBool a, SimdDIBool b)
-{
-    return { _mm512_kand(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDIBool gmx_simdcall operator||(SimdDIBool a, SimdDIBool b)
-{
-    return { _mm512_kor(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline bool gmx_simdcall anyTrue(SimdDIBool a)
-{
-    return (_mm512_mask2int(a.simdInternal_) & 0xFF) != 0;
-}
-
-static inline SimdDInt32 gmx_simdcall selectByMask(SimdDInt32 a, SimdDIBool m)
-{
-    return { _mm512_mask_mov_epi32(_mm512_setzero_epi32(), m.simdInternal_, a.simdInternal_) };
-}
-
-static inline SimdDInt32 gmx_simdcall selectByNotMask(SimdDInt32 a, SimdDIBool m)
-{
-    return { _mm512_mask_mov_epi32(a.simdInternal_, m.simdInternal_, _mm512_setzero_epi32()) };
-}
-
-static inline SimdDInt32 gmx_simdcall blend(SimdDInt32 a, SimdDInt32 b, SimdDIBool sel)
-{
-    return { _mm512_mask_blend_epi32(sel.simdInternal_, a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdDInt32 gmx_simdcall cvtR2I(SimdDouble a)
-{
-    return { _mm512_cvtfxpnt_roundpd_epi32lo(a.simdInternal_, _MM_FROUND_TO_NEAREST_INT) };
-}
-
-static inline SimdDInt32 gmx_simdcall cvttR2I(SimdDouble a)
-{
-    return { _mm512_cvtfxpnt_roundpd_epi32lo(a.simdInternal_, _MM_FROUND_TO_ZERO) };
-}
-
-static inline SimdDouble gmx_simdcall cvtI2R(SimdDInt32 a)
-{
-    return { _mm512_cvtepi32lo_pd(a.simdInternal_) };
-}
-
-static inline SimdDIBool gmx_simdcall cvtB2IB(SimdDBool a)
-{
-    return { a.simdInternal_ };
-}
-
-static inline SimdDBool gmx_simdcall cvtIB2B(SimdDIBool a)
-{
-    return { static_cast<__mmask8>(a.simdInternal_) };
-}
-
-static inline void gmx_simdcall cvtF2DD(SimdFloat f, SimdDouble* d0, SimdDouble* d1)
-{
-    __m512i i1 = _mm512_permute4f128_epi32(_mm512_castps_si512(f.simdInternal_), _MM_PERM_DCDC);
-
-    *d0 = _mm512_cvtpslo_pd(f.simdInternal_);
-    *d1 = _mm512_cvtpslo_pd(_mm512_castsi512_ps(i1));
-}
-
-static inline SimdFloat gmx_simdcall cvtDD2F(SimdDouble d0, SimdDouble d1)
-{
-    __m512 f0 = _mm512_cvtpd_pslo(d0.simdInternal_);
-    __m512 f1 = _mm512_cvtpd_pslo(d1.simdInternal_);
-    return { _mm512_mask_permute4f128_ps(f0, _mm512_int2mask(0xFF00), f1, _MM_PERM_BABA) };
-}
-
-} // namespace gmx
-
-#endif // GMX_SIMD_IMPL_X86_MIC_SIMD_DOUBLE_H
diff --git a/src/gromacs/simd/impl_x86_mic/impl_x86_mic_simd_float.h b/src/gromacs/simd/impl_x86_mic/impl_x86_mic_simd_float.h
deleted file mode 100644 (file)
index f1ab6da..0000000
+++ /dev/null
@@ -1,572 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2016,2017,2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_X86_MIC_SIMD_FLOAT_H
-#define GMX_SIMD_IMPL_X86_MIC_SIMD_FLOAT_H
-
-#include "config.h"
-
-#include <cassert>
-#include <cstdint>
-
-#include <immintrin.h>
-
-#include "gromacs/math/utilities.h"
-
-namespace gmx
-{
-
-class SimdFloat
-{
-public:
-    SimdFloat() {}
-
-    SimdFloat(float f) : simdInternal_(_mm512_set1_ps(f)) {}
-
-    // Internal utility constructor to simplify return statements
-    SimdFloat(__m512 simd) : simdInternal_(simd) {}
-
-    __m512 simdInternal_;
-};
-
-class SimdFInt32
-{
-public:
-    SimdFInt32() {}
-
-    SimdFInt32(std::int32_t i) : simdInternal_(_mm512_set1_epi32(i)) {}
-
-    // Internal utility constructor to simplify return statements
-    SimdFInt32(__m512i simd) : simdInternal_(simd) {}
-
-    __m512i simdInternal_;
-};
-
-class SimdFBool
-{
-public:
-    SimdFBool() {}
-
-    SimdFBool(bool b) : simdInternal_(_mm512_int2mask(b ? 0xFFFF : 0)) {}
-
-    // Internal utility constructor to simplify return statements
-    SimdFBool(__mmask16 simd) : simdInternal_(simd) {}
-
-    __mmask16 simdInternal_;
-};
-
-class SimdFIBool
-{
-public:
-    SimdFIBool() {}
-
-    SimdFIBool(bool b) : simdInternal_(_mm512_int2mask(b ? 0xFFFF : 0)) {}
-
-    // Internal utility constructor to simplify return statements
-    SimdFIBool(__mmask16 simd) : simdInternal_(simd) {}
-
-    __mmask16 simdInternal_;
-};
-
-static inline SimdFloat gmx_simdcall simdLoad(const float* m, SimdFloatTag = {})
-{
-    assert(std::size_t(m) % 64 == 0);
-    return { _mm512_load_ps(m) };
-}
-
-static inline void gmx_simdcall store(float* m, SimdFloat a)
-{
-    assert(std::size_t(m) % 64 == 0);
-    _mm512_store_ps(m, a.simdInternal_);
-}
-
-static inline SimdFloat gmx_simdcall simdLoadU(const float* m, SimdFloatTag = {})
-{
-    return { _mm512_loadunpackhi_ps(_mm512_loadunpacklo_ps(_mm512_undefined_ps(), m), m + 16) };
-}
-
-static inline void gmx_simdcall storeU(float* m, SimdFloat a)
-{
-    _mm512_packstorelo_ps(m, a.simdInternal_);
-    _mm512_packstorehi_ps(m + 16, a.simdInternal_);
-}
-
-static inline SimdFloat gmx_simdcall setZeroF()
-{
-    return { _mm512_setzero_ps() };
-}
-
-static inline SimdFInt32 gmx_simdcall simdLoad(const std::int32_t* m, SimdFInt32Tag)
-{
-    assert(std::size_t(m) % 64 == 0);
-    return { _mm512_load_epi32(m) };
-}
-
-static inline void gmx_simdcall store(std::int32_t* m, SimdFInt32 a)
-{
-    assert(std::size_t(m) % 64 == 0);
-    _mm512_store_epi32(m, a.simdInternal_);
-}
-
-static inline SimdFInt32 gmx_simdcall simdLoadU(const std::int32_t* m, SimdFInt32Tag)
-{
-    return { _mm512_loadunpackhi_epi32(_mm512_loadunpacklo_epi32(_mm512_undefined_epi32(), m), m + 16) };
-}
-
-static inline void gmx_simdcall storeU(std::int32_t* m, SimdFInt32 a)
-{
-    _mm512_packstorelo_epi32(m, a.simdInternal_);
-    _mm512_packstorehi_epi32(m + 16, a.simdInternal_);
-}
-
-static inline SimdFInt32 gmx_simdcall setZeroFI()
-{
-    return { _mm512_setzero_si512() };
-}
-
-
-template<int index>
-static inline std::int32_t gmx_simdcall extract(SimdFInt32 a)
-{
-    int r;
-    _mm512_mask_packstorelo_epi32(&r, _mm512_mask2int(1 << index), a.simdInternal_);
-    return r;
-}
-
-static inline SimdFloat gmx_simdcall operator&(SimdFloat a, SimdFloat b)
-{
-    return { _mm512_castsi512_ps(_mm512_and_epi32(_mm512_castps_si512(a.simdInternal_),
-                                                  _mm512_castps_si512(b.simdInternal_))) };
-}
-
-static inline SimdFloat gmx_simdcall andNot(SimdFloat a, SimdFloat b)
-{
-    return { _mm512_castsi512_ps(_mm512_andnot_epi32(_mm512_castps_si512(a.simdInternal_),
-                                                     _mm512_castps_si512(b.simdInternal_))) };
-}
-
-static inline SimdFloat gmx_simdcall operator|(SimdFloat a, SimdFloat b)
-{
-    return { _mm512_castsi512_ps(_mm512_or_epi32(_mm512_castps_si512(a.simdInternal_),
-                                                 _mm512_castps_si512(b.simdInternal_))) };
-}
-
-static inline SimdFloat gmx_simdcall operator^(SimdFloat a, SimdFloat b)
-{
-    return { _mm512_castsi512_ps(_mm512_xor_epi32(_mm512_castps_si512(a.simdInternal_),
-                                                  _mm512_castps_si512(b.simdInternal_))) };
-}
-
-static inline SimdFloat gmx_simdcall operator+(SimdFloat a, SimdFloat b)
-{
-    return { _mm512_add_ps(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall operator-(SimdFloat a, SimdFloat b)
-{
-    return { _mm512_sub_ps(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall operator-(SimdFloat x)
-{
-    return { _mm512_addn_ps(x.simdInternal_, _mm512_setzero_ps()) };
-}
-
-static inline SimdFloat gmx_simdcall operator*(SimdFloat a, SimdFloat b)
-{
-    return { _mm512_mul_ps(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall fma(SimdFloat a, SimdFloat b, SimdFloat c)
-{
-    return { _mm512_fmadd_ps(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall fms(SimdFloat a, SimdFloat b, SimdFloat c)
-{
-    return { _mm512_fmsub_ps(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall fnma(SimdFloat a, SimdFloat b, SimdFloat c)
-{
-    return { _mm512_fnmadd_ps(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall fnms(SimdFloat a, SimdFloat b, SimdFloat c)
-{
-    return { _mm512_fnmsub_ps(a.simdInternal_, b.simdInternal_, c.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall rsqrt(SimdFloat x)
-{
-    return { _mm512_rsqrt23_ps(x.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall rcp(SimdFloat x)
-{
-    return { _mm512_rcp23_ps(x.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall maskAdd(SimdFloat a, SimdFloat b, SimdFBool m)
-{
-    return { _mm512_mask_add_ps(a.simdInternal_, m.simdInternal_, a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall maskzMul(SimdFloat a, SimdFloat b, SimdFBool m)
-{
-    return { _mm512_mask_mul_ps(_mm512_setzero_ps(), m.simdInternal_, a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall maskzFma(SimdFloat a, SimdFloat b, SimdFloat c, SimdFBool m)
-{
-    return { _mm512_mask_mov_ps(_mm512_setzero_ps(), m.simdInternal_,
-                                _mm512_fmadd_ps(a.simdInternal_, b.simdInternal_, c.simdInternal_)) };
-}
-
-static inline SimdFloat gmx_simdcall maskzRsqrt(SimdFloat x, SimdFBool m)
-{
-    return { _mm512_mask_rsqrt23_ps(_mm512_setzero_ps(), m.simdInternal_, x.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall maskzRcp(SimdFloat x, SimdFBool m)
-{
-    return { _mm512_mask_rcp23_ps(_mm512_setzero_ps(), m.simdInternal_, x.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall abs(SimdFloat x)
-{
-    return { _mm512_castsi512_ps(_mm512_andnot_epi32(_mm512_castps_si512(_mm512_set1_ps(GMX_FLOAT_NEGZERO)),
-                                                     _mm512_castps_si512(x.simdInternal_))) };
-}
-
-static inline SimdFloat gmx_simdcall max(SimdFloat a, SimdFloat b)
-{
-    return { _mm512_gmax_ps(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall min(SimdFloat a, SimdFloat b)
-{
-    return { _mm512_gmin_ps(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall round(SimdFloat x)
-{
-    return { _mm512_round_ps(x.simdInternal_, _MM_FROUND_TO_NEAREST_INT, _MM_EXPADJ_NONE) };
-}
-
-static inline SimdFloat gmx_simdcall trunc(SimdFloat x)
-{
-    return { _mm512_round_ps(x.simdInternal_, _MM_FROUND_TO_ZERO, _MM_EXPADJ_NONE) };
-}
-
-template<MathOptimization opt = MathOptimization::Safe>
-static inline SimdFloat gmx_simdcall frexp(SimdFloat value, SimdFInt32* exponent)
-{
-    __m512  rExponent;
-    __m512i iExponent;
-    __m512  result;
-
-    if (opt == MathOptimization::Safe)
-    {
-        // For the safe branch, we use the masked operations to only assign results if the
-        // input value was nonzero, and otherwise set exponent to 0, and the fraction to the input (+-0).
-        __mmask16 valueIsNonZero =
-                _mm512_cmp_ps_mask(_mm512_setzero_ps(), value.simdInternal_, _CMP_NEQ_OQ);
-        rExponent = _mm512_mask_getexp_ps(_mm512_setzero_ps(), valueIsNonZero, value.simdInternal_);
-        iExponent = _mm512_cvtfxpnt_round_adjustps_epi32(rExponent, _MM_FROUND_TO_NEAREST_INT,
-                                                         _MM_EXPADJ_NONE);
-        iExponent = _mm512_mask_add_epi32(iExponent, valueIsNonZero, iExponent, _mm512_set1_epi32(1));
-
-        // Set result to input value when the latter is +-0
-        result = _mm512_mask_getmant_ps(value.simdInternal_, valueIsNonZero, value.simdInternal_,
-                                        _MM_MANT_NORM_p5_1, _MM_MANT_SIGN_src);
-    }
-    else
-    {
-        rExponent = _mm512_getexp_ps(value.simdInternal_);
-        iExponent = _mm512_cvtfxpnt_round_adjustps_epi32(rExponent, _MM_FROUND_TO_NEAREST_INT,
-                                                         _MM_EXPADJ_NONE);
-        iExponent = _mm512_add_epi32(iExponent, _mm512_set1_epi32(1));
-        result    = _mm512_getmant_ps(value.simdInternal_, _MM_MANT_NORM_p5_1, _MM_MANT_SIGN_src);
-    }
-
-    exponent->simdInternal_ = iExponent;
-
-    return { result };
-}
-
-template<MathOptimization opt = MathOptimization::Safe>
-static inline SimdFloat gmx_simdcall ldexp(SimdFloat value, SimdFInt32 exponent)
-{
-    const __m512i exponentBias = _mm512_set1_epi32(127);
-    __m512i       iExponent    = _mm512_add_epi32(exponent.simdInternal_, exponentBias);
-
-    if (opt == MathOptimization::Safe)
-    {
-        // Make sure biased argument is not negative
-        iExponent = _mm512_max_epi32(iExponent, _mm512_setzero_epi32());
-    }
-
-    iExponent = _mm512_slli_epi32(iExponent, 23);
-
-    return { _mm512_mul_ps(value.simdInternal_, _mm512_castsi512_ps(iExponent)) };
-}
-
-static inline float gmx_simdcall reduce(SimdFloat a)
-{
-    return _mm512_reduce_add_ps(a.simdInternal_);
-}
-
-// Picky, picky, picky:
-// icc-16 complains about "Illegal value of immediate argument to intrinsic"
-// unless we use
-// 1) Ordered-quiet for ==
-// 2) Unordered-quiet for !=
-// 3) Ordered-signaling for < and <=
-
-static inline SimdFBool gmx_simdcall operator==(SimdFloat a, SimdFloat b)
-{
-    return { _mm512_cmp_ps_mask(a.simdInternal_, b.simdInternal_, _CMP_EQ_OQ) };
-}
-
-static inline SimdFBool gmx_simdcall operator!=(SimdFloat a, SimdFloat b)
-{
-    return { _mm512_cmp_ps_mask(a.simdInternal_, b.simdInternal_, _CMP_NEQ_UQ) };
-}
-
-static inline SimdFBool gmx_simdcall operator<(SimdFloat a, SimdFloat b)
-{
-    return { _mm512_cmp_ps_mask(a.simdInternal_, b.simdInternal_, _CMP_LT_OS) };
-}
-
-static inline SimdFBool gmx_simdcall operator<=(SimdFloat a, SimdFloat b)
-{
-    return { _mm512_cmp_ps_mask(a.simdInternal_, b.simdInternal_, _CMP_LE_OS) };
-}
-
-static inline SimdFBool gmx_simdcall testBits(SimdFloat a)
-{
-    return { _mm512_test_epi32_mask(_mm512_castps_si512(a.simdInternal_),
-                                    _mm512_castps_si512(a.simdInternal_)) };
-}
-
-static inline SimdFBool gmx_simdcall operator&&(SimdFBool a, SimdFBool b)
-{
-    return { _mm512_kand(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFBool gmx_simdcall operator||(SimdFBool a, SimdFBool b)
-{
-    return { _mm512_kor(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline bool gmx_simdcall anyTrue(SimdFBool a)
-{
-    return _mm512_mask2int(a.simdInternal_) != 0;
-}
-
-static inline SimdFloat gmx_simdcall selectByMask(SimdFloat a, SimdFBool m)
-{
-    return { _mm512_mask_mov_ps(_mm512_setzero_ps(), m.simdInternal_, a.simdInternal_) };
-}
-
-static inline SimdFloat gmx_simdcall selectByNotMask(SimdFloat a, SimdFBool m)
-{
-    return { _mm512_mask_mov_ps(a.simdInternal_, m.simdInternal_, _mm512_setzero_ps()) };
-}
-
-static inline SimdFloat gmx_simdcall blend(SimdFloat a, SimdFloat b, SimdFBool sel)
-{
-    return { _mm512_mask_blend_ps(sel.simdInternal_, a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator&(SimdFInt32 a, SimdFInt32 b)
-{
-    return { _mm512_and_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall andNot(SimdFInt32 a, SimdFInt32 b)
-{
-    return { _mm512_andnot_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator|(SimdFInt32 a, SimdFInt32 b)
-{
-    return { _mm512_or_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator^(SimdFInt32 a, SimdFInt32 b)
-{
-    return { _mm512_xor_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator+(SimdFInt32 a, SimdFInt32 b)
-{
-    return { _mm512_add_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator-(SimdFInt32 a, SimdFInt32 b)
-{
-    return { _mm512_sub_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall operator*(SimdFInt32 a, SimdFInt32 b)
-{
-    return { _mm512_mullo_epi32(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFIBool gmx_simdcall operator==(SimdFInt32 a, SimdFInt32 b)
-{
-    return { _mm512_cmp_epi32_mask(a.simdInternal_, b.simdInternal_, _MM_CMPINT_EQ) };
-}
-
-static inline SimdFIBool gmx_simdcall testBits(SimdFInt32 a)
-{
-    return { _mm512_test_epi32_mask(a.simdInternal_, a.simdInternal_) };
-}
-
-static inline SimdFIBool gmx_simdcall operator<(SimdFInt32 a, SimdFInt32 b)
-{
-    return { _mm512_cmp_epi32_mask(a.simdInternal_, b.simdInternal_, _MM_CMPINT_LT) };
-}
-
-static inline SimdFIBool gmx_simdcall operator&&(SimdFIBool a, SimdFIBool b)
-{
-    return { _mm512_kand(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFIBool gmx_simdcall operator||(SimdFIBool a, SimdFIBool b)
-{
-    return { _mm512_kor(a.simdInternal_, b.simdInternal_) };
-}
-
-static inline bool gmx_simdcall anyTrue(SimdFIBool a)
-{
-    return _mm512_mask2int(a.simdInternal_) != 0;
-}
-
-static inline SimdFInt32 gmx_simdcall selectByMask(SimdFInt32 a, SimdFIBool m)
-{
-    return { _mm512_mask_mov_epi32(_mm512_setzero_epi32(), m.simdInternal_, a.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall selectByNotMask(SimdFInt32 a, SimdFIBool m)
-{
-    return { _mm512_mask_mov_epi32(a.simdInternal_, m.simdInternal_, _mm512_setzero_epi32()) };
-}
-
-static inline SimdFInt32 gmx_simdcall blend(SimdFInt32 a, SimdFInt32 b, SimdFIBool sel)
-{
-    return { _mm512_mask_blend_epi32(sel.simdInternal_, a.simdInternal_, b.simdInternal_) };
-}
-
-static inline SimdFInt32 gmx_simdcall cvtR2I(SimdFloat a)
-{
-    return { _mm512_cvtfxpnt_round_adjustps_epi32(a.simdInternal_, _MM_FROUND_TO_NEAREST_INT,
-                                                  _MM_EXPADJ_NONE) };
-}
-
-static inline SimdFInt32 gmx_simdcall cvttR2I(SimdFloat a)
-{
-    return { _mm512_cvtfxpnt_round_adjustps_epi32(a.simdInternal_, _MM_FROUND_TO_ZERO, _MM_EXPADJ_NONE) };
-}
-
-static inline SimdFloat gmx_simdcall cvtI2R(SimdFInt32 a)
-{
-    return { _mm512_cvtfxpnt_round_adjustepi32_ps(a.simdInternal_, _MM_FROUND_TO_NEAREST_INT,
-                                                  _MM_EXPADJ_NONE) };
-}
-
-static inline SimdFIBool gmx_simdcall cvtB2IB(SimdFBool a)
-{
-    return { a.simdInternal_ };
-}
-
-static inline SimdFBool gmx_simdcall cvtIB2B(SimdFIBool a)
-{
-    return { a.simdInternal_ };
-}
-
-
-template<MathOptimization opt = MathOptimization::Safe>
-static inline SimdFloat gmx_simdcall exp2(SimdFloat x)
-{
-    return { _mm512_exp223_ps(_mm512_cvtfxpnt_round_adjustps_epi32(
-            x.simdInternal_, _MM_ROUND_MODE_NEAREST, _MM_EXPADJ_24)) };
-}
-
-template<MathOptimization opt = MathOptimization::Safe>
-static inline SimdFloat gmx_simdcall exp(SimdFloat x)
-{
-    const __m512 argscale    = _mm512_set1_ps(1.44269504088896341F);
-    const __m512 invargscale = _mm512_set1_ps(-0.69314718055994528623F);
-
-    if (opt == MathOptimization::Safe)
-    {
-        // Set the limit to gurantee flush to zero
-        const SimdFloat smallArgLimit(-88.f);
-        // Since we multiply the argument by 1.44, for the safe version we need to make
-        // sure this doesn't result in overflow
-        x = max(x, smallArgLimit);
-    }
-
-    __m512 xscaled = _mm512_mul_ps(x.simdInternal_, argscale);
-    __m512 r       = _mm512_exp223_ps(
-            _mm512_cvtfxpnt_round_adjustps_epi32(xscaled, _MM_ROUND_MODE_NEAREST, _MM_EXPADJ_24));
-
-    // exp2a23_ps provides 23 bits of accuracy, but we ruin some of that with our argument
-    // scaling. To correct this, we find the difference between the scaled argument and
-    // the true one (extended precision arithmetics does not appear to be necessary to
-    // fulfill our accuracy requirements) and then multiply by the exponent of this
-    // correction since exp(a+b)=exp(a)*exp(b).
-    // Note that this only adds two instructions (and maybe some constant loads).
-
-    // find the difference
-    x = _mm512_fmadd_ps(invargscale, xscaled, x.simdInternal_);
-    // x will now be a _very_ small number, so approximate exp(x)=1+x.
-    // We should thus apply the correction as r'=r*(1+x)=r+r*x
-    r = _mm512_fmadd_ps(r, x.simdInternal_, r);
-    return { r };
-}
-
-static inline SimdFloat gmx_simdcall log(SimdFloat x)
-{
-    return { _mm512_mul_ps(_mm512_set1_ps(0.693147180559945286226764F),
-                           _mm512_log2ae23_ps(x.simdInternal_)) };
-}
-
-} // namespace gmx
-
-#endif // GMX_SIMD_IMPL_X86_MIC_SIMD_FLOAT_H
diff --git a/src/gromacs/simd/impl_x86_mic/impl_x86_mic_util_double.h b/src/gromacs/simd/impl_x86_mic/impl_x86_mic_util_double.h
deleted file mode 100644 (file)
index 18769d6..0000000
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_X86_MIC_UTIL_DOUBLE_H
-#define GMX_SIMD_IMPL_X86_MIC_UTIL_DOUBLE_H
-
-#include "config.h"
-
-#include <cassert>
-#include <cstdint>
-
-#include <immintrin.h>
-
-#include "gromacs/utility/basedefinitions.h"
-
-#include "impl_x86_mic_simd_double.h"
-
-namespace gmx
-{
-
-namespace
-{
-/* This is an internal helper function used by decr3Hsimd(...).
- */
-inline void gmx_simdcall decrHsimd(double* m, SimdDouble a)
-{
-    __m512d t;
-
-    assert(std::size_t(m) % 32 == 0);
-
-    t               = _mm512_extload_pd(m, _MM_UPCONV_PD_NONE, _MM_BROADCAST_4X8, _MM_HINT_NONE);
-    a.simdInternal_ = _mm512_add_pd(
-            a.simdInternal_,
-            _mm512_castps_pd(_mm512_permute4f128_ps(_mm512_castpd_ps(a.simdInternal_), _MM_PERM_BADC)));
-    t = _mm512_sub_pd(t, a.simdInternal_);
-    _mm512_mask_packstorelo_pd(m, _mm512_int2mask(0x0F), t);
-}
-} // namespace
-
-// On MIC it is better to use scatter operations, so we define the load routines
-// that use a SIMD offset variable first.
-
-template<int align>
-static inline void gmx_simdcall gatherLoadBySimdIntTranspose(const double* base,
-                                                             SimdDInt32    simdoffset,
-                                                             SimdDouble*   v0,
-                                                             SimdDouble*   v1,
-                                                             SimdDouble*   v2,
-                                                             SimdDouble*   v3)
-{
-    assert((size_t)base % 32 == 0);
-    assert(align % 4 == 0);
-
-    // All instructions might be latency ~4 on MIC, so we use shifts where we
-    // only need a single instruction (since the shift parameter is an immediate),
-    // but multiplication otherwise.
-    if (align == 4)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 2);
-    }
-    else if (align == 8)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 3);
-    }
-    else
-    {
-        simdoffset = simdoffset * SimdDInt32(align);
-    }
-
-    v0->simdInternal_ = _mm512_i32logather_pd(simdoffset.simdInternal_, base, sizeof(double));
-    v1->simdInternal_ = _mm512_i32logather_pd(simdoffset.simdInternal_, base + 1, sizeof(double));
-    v2->simdInternal_ = _mm512_i32logather_pd(simdoffset.simdInternal_, base + 2, sizeof(double));
-    v3->simdInternal_ = _mm512_i32logather_pd(simdoffset.simdInternal_, base + 3, sizeof(double));
-}
-
-template<int align>
-static inline void gmx_simdcall gatherLoadUBySimdIntTranspose(const double* base,
-                                                              SimdDInt32    simdoffset,
-                                                              SimdDouble*   v0,
-                                                              SimdDouble*   v1)
-{
-    // All instructions might be latency ~4 on MIC, so we use shifts where we
-    // only need a single instruction (since the shift parameter is an immediate),
-    // but multiplication otherwise.
-    if (align == 2)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 1);
-    }
-    else if (align == 4)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 2);
-    }
-    else if (align == 8)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 3);
-    }
-    else
-    {
-        simdoffset = simdoffset * SimdDInt32(align);
-    }
-
-    v0->simdInternal_ = _mm512_i32logather_pd(simdoffset.simdInternal_, base, sizeof(double));
-    v1->simdInternal_ = _mm512_i32logather_pd(simdoffset.simdInternal_, base + 1, sizeof(double));
-}
-
-template<int align>
-static inline void gmx_simdcall gatherLoadBySimdIntTranspose(const double* base,
-                                                             SimdDInt32    simdoffset,
-                                                             SimdDouble*   v0,
-                                                             SimdDouble*   v1)
-{
-    assert(std::size_t(base) % 16 == 0);
-    assert(align % 2 == 0);
-    gatherLoadUBySimdIntTranspose<align>(base, simdoffset, v0, v1);
-}
-
-
-template<int align>
-static inline void gmx_simdcall gatherLoadTranspose(const double*      base,
-                                                    const std::int32_t offset[],
-                                                    SimdDouble*        v0,
-                                                    SimdDouble*        v1,
-                                                    SimdDouble*        v2,
-                                                    SimdDouble*        v3)
-{
-    gatherLoadBySimdIntTranspose<align>(base, simdLoad(offset, SimdDInt32Tag()), v0, v1, v2, v3);
-}
-
-template<int align>
-static inline void gmx_simdcall
-                   gatherLoadTranspose(const double* base, const std::int32_t offset[], SimdDouble* v0, SimdDouble* v1)
-{
-    gatherLoadBySimdIntTranspose<align>(base, simdLoad(offset, SimdDInt32Tag()), v0, v1);
-}
-
-static const int c_simdBestPairAlignmentDouble = 2;
-
-template<int align>
-static inline void gmx_simdcall gatherLoadUTranspose(const double*      base,
-                                                     const std::int32_t offset[],
-                                                     SimdDouble*        v0,
-                                                     SimdDouble*        v1,
-                                                     SimdDouble*        v2)
-{
-    SimdDInt32 simdoffset;
-
-    assert(std::size_t(offset) % 32 == 0);
-
-    simdoffset = simdLoad(offset, SimdDInt32Tag());
-
-    // All instructions might be latency ~4 on MIC, so we use shifts where we
-    // only need a single instruction (since the shift parameter is an immediate),
-    // but multiplication otherwise.
-    if (align == 4)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 2);
-    }
-    else if (align == 8)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 3);
-    }
-    else
-    {
-        simdoffset = simdoffset * SimdDInt32(align);
-    }
-
-    v0->simdInternal_ = _mm512_i32logather_pd(simdoffset.simdInternal_, base, sizeof(double));
-    v1->simdInternal_ = _mm512_i32logather_pd(simdoffset.simdInternal_, base + 1, sizeof(double));
-    v2->simdInternal_ = _mm512_i32logather_pd(simdoffset.simdInternal_, base + 2, sizeof(double));
-}
-
-template<int align>
-static inline void gmx_simdcall transposeScatterStoreU(double*            base,
-                                                       const std::int32_t offset[],
-                                                       SimdDouble         v0,
-                                                       SimdDouble         v1,
-                                                       SimdDouble         v2)
-{
-    SimdDInt32 simdoffset;
-
-    assert(std::size_t(offset) % 32 == 0);
-
-    simdoffset = simdLoad(offset, SimdDInt32Tag());
-
-    // All instructions might be latency ~4 on MIC, so we use shifts where we
-    // only need a single instruction (since the shift parameter is an immediate),
-    // but multiplication otherwise.
-    if (align == 4)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 2);
-    }
-    else if (align == 8)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 3);
-    }
-    else
-    {
-        simdoffset = simdoffset * SimdDInt32(align);
-    }
-
-    _mm512_i32loscatter_pd(base, simdoffset.simdInternal_, v0.simdInternal_, sizeof(double));
-    _mm512_i32loscatter_pd(base + 1, simdoffset.simdInternal_, v1.simdInternal_, sizeof(double));
-    _mm512_i32loscatter_pd(base + 2, simdoffset.simdInternal_, v2.simdInternal_, sizeof(double));
-}
-
-template<int align>
-static inline void gmx_simdcall
-                   transposeScatterIncrU(double* base, const std::int32_t offset[], SimdDouble v0, SimdDouble v1, SimdDouble v2)
-{
-    alignas(GMX_SIMD_ALIGNMENT) double rdata0[GMX_SIMD_DOUBLE_WIDTH];
-    alignas(GMX_SIMD_ALIGNMENT) double rdata1[GMX_SIMD_DOUBLE_WIDTH];
-    alignas(GMX_SIMD_ALIGNMENT) double rdata2[GMX_SIMD_DOUBLE_WIDTH];
-
-    store(rdata0, v0);
-    store(rdata1, v1);
-    store(rdata2, v2);
-
-    for (int i = 0; i < GMX_SIMD_DOUBLE_WIDTH; i++)
-    {
-        base[align * offset[i] + 0] += rdata0[i];
-        base[align * offset[i] + 1] += rdata1[i];
-        base[align * offset[i] + 2] += rdata2[i];
-    }
-}
-
-template<int align>
-static inline void gmx_simdcall
-                   transposeScatterDecrU(double* base, const std::int32_t offset[], SimdDouble v0, SimdDouble v1, SimdDouble v2)
-{
-    alignas(GMX_SIMD_ALIGNMENT) double rdata0[GMX_SIMD_DOUBLE_WIDTH];
-    alignas(GMX_SIMD_ALIGNMENT) double rdata1[GMX_SIMD_DOUBLE_WIDTH];
-    alignas(GMX_SIMD_ALIGNMENT) double rdata2[GMX_SIMD_DOUBLE_WIDTH];
-
-    store(rdata0, v0);
-    store(rdata1, v1);
-    store(rdata2, v2);
-
-    for (int i = 0; i < GMX_SIMD_DOUBLE_WIDTH; i++)
-    {
-        base[align * offset[i] + 0] -= rdata0[i];
-        base[align * offset[i] + 1] -= rdata1[i];
-        base[align * offset[i] + 2] -= rdata2[i];
-    }
-}
-
-static inline void gmx_simdcall expandScalarsToTriplets(SimdDouble  scalar,
-                                                        SimdDouble* triplets0,
-                                                        SimdDouble* triplets1,
-                                                        SimdDouble* triplets2)
-{
-    triplets0->simdInternal_ = _mm512_castsi512_pd(
-            _mm512_permutevar_epi32(_mm512_set_epi32(5, 4, 5, 4, 3, 2, 3, 2, 3, 2, 1, 0, 1, 0, 1, 0),
-                                    _mm512_castpd_si512(scalar.simdInternal_)));
-    triplets1->simdInternal_ = _mm512_castsi512_pd(_mm512_permutevar_epi32(
-            _mm512_set_epi32(11, 10, 9, 8, 9, 8, 9, 8, 7, 6, 7, 6, 7, 6, 5, 4),
-            _mm512_castpd_si512(scalar.simdInternal_)));
-    triplets2->simdInternal_ = _mm512_castsi512_pd(_mm512_permutevar_epi32(
-            _mm512_set_epi32(15, 14, 15, 14, 15, 14, 13, 12, 13, 12, 13, 12, 11, 10, 11, 10),
-            _mm512_castpd_si512(scalar.simdInternal_)));
-}
-
-
-static inline double gmx_simdcall
-                     reduceIncr4ReturnSum(double* m, SimdDouble v0, SimdDouble v1, SimdDouble v2, SimdDouble v3)
-{
-    double  d;
-    __m512d t0, t1, t2, t3;
-
-    assert(std::size_t(m) % 32 == 0);
-
-    t0 = _mm512_swizzle_pd(_mm512_mask_blend_pd(_mm512_int2mask(0x33), v0.simdInternal_, v2.simdInternal_),
-                           _MM_SWIZ_REG_BADC);
-    t2 = _mm512_mask_blend_pd(_mm512_int2mask(0x33), v2.simdInternal_, v0.simdInternal_);
-    t1 = _mm512_swizzle_pd(_mm512_mask_blend_pd(_mm512_int2mask(0x33), v1.simdInternal_, v3.simdInternal_),
-                           _MM_SWIZ_REG_BADC);
-    t3 = _mm512_mask_blend_pd(_mm512_int2mask(0x33), v3.simdInternal_, v1.simdInternal_);
-    t0 = _mm512_add_pd(t0, t2);
-    t1 = _mm512_add_pd(t1, t3);
-
-    t2 = _mm512_swizzle_pd(_mm512_mask_blend_pd(_mm512_int2mask(0b01010101), t0, t1), _MM_SWIZ_REG_CDAB);
-    t3 = _mm512_mask_blend_pd(_mm512_int2mask(0b01010101), t1, t0);
-    t2 = _mm512_add_pd(t2, t3);
-
-    t2 = _mm512_add_pd(t2, _mm512_castps_pd(_mm512_permute4f128_ps(_mm512_castpd_ps(t2), _MM_PERM_BADC)));
-
-    t0 = _mm512_mask_extload_pd(_mm512_undefined_pd(), _mm512_int2mask(0xF), m, _MM_UPCONV_PD_NONE,
-                                _MM_BROADCAST_4X8, _MM_HINT_NONE);
-    t0 = _mm512_add_pd(t0, t2);
-    _mm512_mask_packstorelo_pd(m, _mm512_int2mask(0xF), t0);
-
-    t2 = _mm512_add_pd(t2, _mm512_swizzle_pd(t2, _MM_SWIZ_REG_BADC));
-    t2 = _mm512_add_pd(t2, _mm512_swizzle_pd(t2, _MM_SWIZ_REG_CDAB));
-
-    _mm512_mask_packstorelo_pd(&d, _mm512_mask2int(0x01), t2);
-    return d;
-}
-
-static inline SimdDouble gmx_simdcall loadDualHsimd(const double* m0, const double* m1)
-{
-    assert(std::size_t(m0) % 32 == 0);
-    assert(std::size_t(m1) % 32 == 0);
-
-    return _mm512_mask_extload_pd(
-            _mm512_extload_pd(m0, _MM_UPCONV_PD_NONE, _MM_BROADCAST_4X8, _MM_HINT_NONE),
-            _mm512_int2mask(0xF0), m1, _MM_UPCONV_PD_NONE, _MM_BROADCAST_4X8, _MM_HINT_NONE);
-}
-
-static inline SimdDouble gmx_simdcall loadDuplicateHsimd(const double* m)
-{
-    assert(std::size_t(m) % 32 == 0);
-
-    return _mm512_extload_pd(m, _MM_UPCONV_PD_NONE, _MM_BROADCAST_4X8, _MM_HINT_NONE);
-}
-
-static inline SimdDouble gmx_simdcall loadU1DualHsimd(const double* m)
-{
-    return _mm512_mask_extload_pd(
-            _mm512_extload_pd(m, _MM_UPCONV_PD_NONE, _MM_BROADCAST_1X8, _MM_HINT_NONE),
-            _mm512_int2mask(0xF0), m + 1, _MM_UPCONV_PD_NONE, _MM_BROADCAST_1X8, _MM_HINT_NONE);
-}
-
-
-static inline void gmx_simdcall storeDualHsimd(double* m0, double* m1, SimdDouble a)
-{
-    assert(std::size_t(m0) % 32 == 0);
-    assert(std::size_t(m1) % 32 == 0);
-
-    _mm512_mask_packstorelo_pd(m0, _mm512_int2mask(0x0F), a.simdInternal_);
-    _mm512_mask_packstorelo_pd(m1, _mm512_int2mask(0xF0), a.simdInternal_);
-}
-
-static inline void gmx_simdcall incrDualHsimd(double* m0, double* m1, SimdDouble a)
-{
-    assert(std::size_t(m0) % 32 == 0);
-    assert(std::size_t(m1) % 32 == 0);
-
-    __m512d x;
-
-    // Update lower half
-    x = _mm512_extload_pd(m0, _MM_UPCONV_PD_NONE, _MM_BROADCAST_4X8, _MM_HINT_NONE);
-    x = _mm512_add_pd(x, a.simdInternal_);
-    _mm512_mask_packstorelo_pd(m0, _mm512_int2mask(0x0F), x);
-
-    // Update upper half
-    x = _mm512_extload_pd(m1, _MM_UPCONV_PD_NONE, _MM_BROADCAST_4X8, _MM_HINT_NONE);
-    x = _mm512_add_pd(x, a.simdInternal_);
-    _mm512_mask_packstorelo_pd(m1, _mm512_int2mask(0xF0), x);
-}
-
-static inline void gmx_simdcall decr3Hsimd(double* m, SimdDouble a0, SimdDouble a1, SimdDouble a2)
-{
-    assert(std::size_t(m) % 32 == 0);
-    decrHsimd(m, a0);
-    decrHsimd(m + GMX_SIMD_DOUBLE_WIDTH / 2, a1);
-    decrHsimd(m + GMX_SIMD_DOUBLE_WIDTH, a2);
-}
-
-
-template<int align>
-static inline void gmx_simdcall gatherLoadTransposeHsimd(const double*      base0,
-                                                         const double*      base1,
-                                                         const std::int32_t offset[],
-                                                         SimdDouble*        v0,
-                                                         SimdDouble*        v1)
-{
-    __m512i idx0, idx1, idx;
-    __m512d tmp1, tmp2;
-
-    assert(std::size_t(offset) % 16 == 0);
-    assert(std::size_t(base0) % 16 == 0);
-    assert(std::size_t(base1) % 16 == 0);
-    assert(std::size_t(align) % 2 == 0);
-
-    idx0 = _mm512_extload_epi32(offset, _MM_UPCONV_EPI32_NONE, _MM_BROADCAST_4X16, _MM_HINT_NONE);
-
-    idx0 = _mm512_mullo_epi32(idx0, _mm512_set1_epi32(align));
-    idx1 = _mm512_add_epi32(idx0, _mm512_set1_epi32(1));
-
-    idx = _mm512_mask_permute4f128_epi32(idx0, _mm512_int2mask(0x00F0), idx1, _MM_PERM_AAAA);
-
-    tmp1 = _mm512_i32logather_pd(idx, base0, sizeof(double));
-    tmp2 = _mm512_i32logather_pd(idx, base1, sizeof(double));
-
-    v0->simdInternal_ = _mm512_castps_pd(_mm512_mask_permute4f128_ps(
-            _mm512_castpd_ps(tmp1), _mm512_int2mask(0xFF00), _mm512_castpd_ps(tmp2), _MM_PERM_BABA));
-    v1->simdInternal_ = _mm512_castps_pd(_mm512_mask_permute4f128_ps(
-            _mm512_castpd_ps(tmp2), _mm512_int2mask(0x00FF), _mm512_castpd_ps(tmp1), _MM_PERM_DCDC));
-}
-
-static inline double gmx_simdcall reduceIncr4ReturnSumHsimd(double* m, SimdDouble v0, SimdDouble v1)
-{
-    double  d;
-    __m512d t0, t1;
-
-    assert(std::size_t(m) % 32 == 0);
-
-    t0 = _mm512_add_pd(v0.simdInternal_, _mm512_swizzle_pd(v0.simdInternal_, _MM_SWIZ_REG_BADC));
-    t0 = _mm512_mask_add_pd(t0, _mm512_int2mask(0xCC), v1.simdInternal_,
-                            _mm512_swizzle_pd(v1.simdInternal_, _MM_SWIZ_REG_BADC));
-    t0 = _mm512_add_pd(t0, _mm512_swizzle_pd(t0, _MM_SWIZ_REG_CDAB));
-    t0 = _mm512_castps_pd(_mm512_mask_permute4f128_ps(_mm512_castpd_ps(t0), _mm512_int2mask(0xCCCC),
-                                                      _mm512_castpd_ps(t0), _MM_PERM_DCDC));
-
-    t1 = _mm512_mask_extload_pd(_mm512_undefined_pd(), _mm512_int2mask(0xF), m, _MM_UPCONV_PD_NONE,
-                                _MM_BROADCAST_4X8, _MM_HINT_NONE);
-    t1 = _mm512_add_pd(t1, t0);
-    _mm512_mask_packstorelo_pd(m, _mm512_int2mask(0xF), t1);
-
-    t0 = _mm512_add_pd(t0, _mm512_swizzle_pd(t0, _MM_SWIZ_REG_BADC));
-    t0 = _mm512_add_pd(t0, _mm512_swizzle_pd(t0, _MM_SWIZ_REG_CDAB));
-
-    _mm512_mask_packstorelo_pd(&d, _mm512_mask2int(0x03), t0);
-    return d;
-}
-
-} // namespace gmx
-
-#endif // GMX_SIMD_IMPL_X86_MIC_UTIL_DOUBLE_H
diff --git a/src/gromacs/simd/impl_x86_mic/impl_x86_mic_util_float.h b/src/gromacs/simd/impl_x86_mic/impl_x86_mic_util_float.h
deleted file mode 100644 (file)
index 13a6147..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_X86_MIC_UTIL_FLOAT_H
-#define GMX_SIMD_IMPL_X86_MIC_UTIL_FLOAT_H
-
-#include "config.h"
-
-#include <cassert>
-#include <cstdint>
-
-#include <immintrin.h>
-
-#include "gromacs/utility/basedefinitions.h"
-
-#include "impl_x86_mic_simd_float.h"
-
-namespace gmx
-{
-
-namespace
-{
-/* This is an internal helper function used by decr3Hsimd(...).
- */
-inline void gmx_simdcall decrHsimd(float* m, SimdFloat a)
-{
-    __m512 t;
-
-    assert(std::size_t(m) % 32 == 0);
-
-    t = _mm512_castpd_ps(_mm512_extload_pd(reinterpret_cast<const double*>(m), _MM_UPCONV_PD_NONE,
-                                           _MM_BROADCAST_4X8, _MM_HINT_NONE));
-    a = _mm512_add_ps(a.simdInternal_, _mm512_permute4f128_ps(a.simdInternal_, _MM_PERM_BADC));
-    t = _mm512_sub_ps(t, a.simdInternal_);
-    _mm512_mask_packstorelo_ps(m, _mm512_int2mask(0x00FF), t);
-}
-} // namespace
-
-// On MIC it is better to use scatter operations, so we define the load routines
-// that use a SIMD offset variable first.
-
-template<int align>
-static inline void gmx_simdcall gatherLoadBySimdIntTranspose(const float* base,
-                                                             SimdFInt32   simdoffset,
-                                                             SimdFloat*   v0,
-                                                             SimdFloat*   v1,
-                                                             SimdFloat*   v2,
-                                                             SimdFloat*   v3)
-{
-    assert(std::size_t(base) % 16 == 0);
-    assert(align % 4 == 0);
-
-    // All instructions might be latency ~4 on MIC, so we use shifts where we
-    // only need a single instruction (since the shift parameter is an immediate),
-    // but multiplication otherwise.
-    if (align == 4)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 2);
-    }
-    else if (align == 8)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 3);
-    }
-    else
-    {
-        simdoffset = simdoffset * SimdFInt32(align);
-    }
-
-    v0->simdInternal_ = _mm512_i32gather_ps(simdoffset.simdInternal_, base, sizeof(float));
-    v1->simdInternal_ = _mm512_i32gather_ps(simdoffset.simdInternal_, base + 1, sizeof(float));
-    v2->simdInternal_ = _mm512_i32gather_ps(simdoffset.simdInternal_, base + 2, sizeof(float));
-    v3->simdInternal_ = _mm512_i32gather_ps(simdoffset.simdInternal_, base + 3, sizeof(float));
-}
-
-template<int align>
-static inline void gmx_simdcall
-                   gatherLoadUBySimdIntTranspose(const float* base, SimdFInt32 simdoffset, SimdFloat* v0, SimdFloat* v1)
-{
-    // All instructions might be latency ~4 on MIC, so we use shifts where we
-    // only need a single instruction (since the shift parameter is an immediate),
-    // but multiplication otherwise.
-    // For align == 2 we can merge the constant into the scale parameter,
-    // which can take constants up to 8 in total.
-    if (align == 2)
-    {
-        v0->simdInternal_ = _mm512_i32gather_ps(simdoffset.simdInternal_, base, align * sizeof(float));
-        v1->simdInternal_ =
-                _mm512_i32gather_ps(simdoffset.simdInternal_, base + 1, align * sizeof(float));
-    }
-    else
-    {
-        if (align == 4)
-        {
-            simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 2);
-        }
-        else if (align == 8)
-        {
-            simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 3);
-        }
-        else
-        {
-            simdoffset = simdoffset * SimdFInt32(align);
-        }
-        v0->simdInternal_ = _mm512_i32gather_ps(simdoffset.simdInternal_, base, sizeof(float));
-        v1->simdInternal_ = _mm512_i32gather_ps(simdoffset.simdInternal_, base + 1, sizeof(float));
-    }
-}
-
-template<int align>
-static inline void gmx_simdcall
-                   gatherLoadBySimdIntTranspose(const float* base, SimdFInt32 simdoffset, SimdFloat* v0, SimdFloat* v1)
-{
-    assert(std::size_t(base) % 8 == 0);
-    assert(align % 2 == 0);
-    gatherLoadUBySimdIntTranspose<align>(base, simdoffset, v0, v1);
-}
-
-template<int align>
-static inline void gmx_simdcall gatherLoadTranspose(const float*       base,
-                                                    const std::int32_t offset[],
-                                                    SimdFloat*         v0,
-                                                    SimdFloat*         v1,
-                                                    SimdFloat*         v2,
-                                                    SimdFloat*         v3)
-{
-    gatherLoadBySimdIntTranspose<align>(base, simdLoad(offset, SimdFInt32Tag()), v0, v1, v2, v3);
-}
-
-template<int align>
-static inline void gmx_simdcall
-                   gatherLoadTranspose(const float* base, const std::int32_t offset[], SimdFloat* v0, SimdFloat* v1)
-{
-    gatherLoadBySimdIntTranspose<align>(base, simdLoad(offset, SimdFInt32Tag()), v0, v1);
-}
-
-static const int c_simdBestPairAlignmentFloat = 2;
-
-template<int align>
-static inline void gmx_simdcall gatherLoadUTranspose(const float*       base,
-                                                     const std::int32_t offset[],
-                                                     SimdFloat*         v0,
-                                                     SimdFloat*         v1,
-                                                     SimdFloat*         v2)
-{
-    SimdFInt32 simdoffset;
-
-    assert(std::size_t(offset) % 64 == 0);
-
-    simdoffset = simdLoad(offset, SimdFInt32Tag());
-
-    // All instructions might be latency ~4 on MIC, so we use shifts where we
-    // only need a single instruction (since the shift parameter is an immediate),
-    // but multiplication otherwise.
-    if (align == 4)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 2);
-    }
-    else if (align == 8)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 3);
-    }
-    else
-    {
-        simdoffset = simdoffset * SimdFInt32(align);
-    }
-
-    v0->simdInternal_ = _mm512_i32gather_ps(simdoffset.simdInternal_, base, sizeof(float));
-    v1->simdInternal_ = _mm512_i32gather_ps(simdoffset.simdInternal_, base + 1, sizeof(float));
-    v2->simdInternal_ = _mm512_i32gather_ps(simdoffset.simdInternal_, base + 2, sizeof(float));
-}
-
-
-template<int align>
-static inline void gmx_simdcall
-                   transposeScatterStoreU(float* base, const std::int32_t offset[], SimdFloat v0, SimdFloat v1, SimdFloat v2)
-{
-    SimdFInt32 simdoffset;
-
-    assert(std::size_t(offset) % 64 == 0);
-
-    simdoffset = simdLoad(offset, SimdFInt32Tag());
-
-    // All instructions might be latency ~4 on MIC, so we use shifts where we
-    // only need a single instruction (since the shift parameter is an immediate),
-    // but multiplication otherwise.
-    if (align == 4)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 2);
-    }
-    else if (align == 8)
-    {
-        simdoffset.simdInternal_ = _mm512_slli_epi32(simdoffset.simdInternal_, 3);
-    }
-    else
-    {
-        simdoffset = simdoffset * SimdFInt32(align);
-    }
-
-    _mm512_i32scatter_ps(base, simdoffset.simdInternal_, v0.simdInternal_, sizeof(float));
-    _mm512_i32scatter_ps(base + 1, simdoffset.simdInternal_, v1.simdInternal_, sizeof(float));
-    _mm512_i32scatter_ps(base + 2, simdoffset.simdInternal_, v2.simdInternal_, sizeof(float));
-}
-
-
-template<int align>
-static inline void gmx_simdcall
-                   transposeScatterIncrU(float* base, const std::int32_t offset[], SimdFloat v0, SimdFloat v1, SimdFloat v2)
-{
-    alignas(GMX_SIMD_ALIGNMENT) float rdata0[GMX_SIMD_FLOAT_WIDTH];
-    alignas(GMX_SIMD_ALIGNMENT) float rdata1[GMX_SIMD_FLOAT_WIDTH];
-    alignas(GMX_SIMD_ALIGNMENT) float rdata2[GMX_SIMD_FLOAT_WIDTH];
-
-    store(rdata0, v0);
-    store(rdata1, v1);
-    store(rdata2, v2);
-
-    for (int i = 0; i < GMX_SIMD_FLOAT_WIDTH; i++)
-    {
-        base[align * offset[i] + 0] += rdata0[i];
-        base[align * offset[i] + 1] += rdata1[i];
-        base[align * offset[i] + 2] += rdata2[i];
-    }
-}
-
-template<int align>
-static inline void gmx_simdcall
-                   transposeScatterDecrU(float* base, const std::int32_t offset[], SimdFloat v0, SimdFloat v1, SimdFloat v2)
-{
-    alignas(GMX_SIMD_ALIGNMENT) float rdata0[GMX_SIMD_FLOAT_WIDTH];
-    alignas(GMX_SIMD_ALIGNMENT) float rdata1[GMX_SIMD_FLOAT_WIDTH];
-    alignas(GMX_SIMD_ALIGNMENT) float rdata2[GMX_SIMD_FLOAT_WIDTH];
-
-    store(rdata0, v0);
-    store(rdata1, v1);
-    store(rdata2, v2);
-
-    for (int i = 0; i < GMX_SIMD_FLOAT_WIDTH; i++)
-    {
-        base[align * offset[i] + 0] -= rdata0[i];
-        base[align * offset[i] + 1] -= rdata1[i];
-        base[align * offset[i] + 2] -= rdata2[i];
-    }
-}
-
-static inline void gmx_simdcall expandScalarsToTriplets(SimdFloat  scalar,
-                                                        SimdFloat* triplets0,
-                                                        SimdFloat* triplets1,
-                                                        SimdFloat* triplets2)
-{
-    triplets0->simdInternal_ = _mm512_castsi512_ps(
-            _mm512_permutevar_epi32(_mm512_set_epi32(5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0, 0, 0),
-                                    _mm512_castps_si512(scalar.simdInternal_)));
-    triplets1->simdInternal_ = _mm512_castsi512_ps(_mm512_permutevar_epi32(
-            _mm512_set_epi32(10, 10, 9, 9, 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 5, 5),
-            _mm512_castps_si512(scalar.simdInternal_)));
-    triplets2->simdInternal_ = _mm512_castsi512_ps(_mm512_permutevar_epi32(
-            _mm512_set_epi32(15, 15, 15, 14, 14, 14, 13, 13, 13, 12, 12, 12, 11, 11, 11, 10),
-            _mm512_castps_si512(scalar.simdInternal_)));
-}
-
-
-static inline float gmx_simdcall reduceIncr4ReturnSum(float* m, SimdFloat v0, SimdFloat v1, SimdFloat v2, SimdFloat v3)
-{
-    float  f;
-    __m512 t0, t1, t2, t3;
-
-    assert(std::size_t(m) % 16 == 0);
-
-    t0 = _mm512_add_ps(v0.simdInternal_, _mm512_swizzle_ps(v0.simdInternal_, _MM_SWIZ_REG_BADC));
-    t0 = _mm512_mask_add_ps(t0, _mm512_int2mask(0xCCCC), v2.simdInternal_,
-                            _mm512_swizzle_ps(v2.simdInternal_, _MM_SWIZ_REG_BADC));
-    t1 = _mm512_add_ps(v1.simdInternal_, _mm512_swizzle_ps(v1.simdInternal_, _MM_SWIZ_REG_BADC));
-    t1 = _mm512_mask_add_ps(t1, _mm512_int2mask(0xCCCC), v3.simdInternal_,
-                            _mm512_swizzle_ps(v3.simdInternal_, _MM_SWIZ_REG_BADC));
-    t2 = _mm512_add_ps(t0, _mm512_swizzle_ps(t0, _MM_SWIZ_REG_CDAB));
-    t2 = _mm512_mask_add_ps(t2, _mm512_int2mask(0xAAAA), t1, _mm512_swizzle_ps(t1, _MM_SWIZ_REG_CDAB));
-
-    t2 = _mm512_add_ps(t2, _mm512_permute4f128_ps(t2, _MM_PERM_BADC));
-    t2 = _mm512_add_ps(t2, _mm512_permute4f128_ps(t2, _MM_PERM_CDAB));
-
-    t0 = _mm512_mask_extload_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF), m, _MM_UPCONV_PS_NONE,
-                                _MM_BROADCAST_4X16, _MM_HINT_NONE);
-    t0 = _mm512_add_ps(t0, t2);
-    _mm512_mask_packstorelo_ps(m, _mm512_int2mask(0xF), t0);
-
-    t2 = _mm512_add_ps(t2, _mm512_swizzle_ps(t2, _MM_SWIZ_REG_BADC));
-    t2 = _mm512_add_ps(t2, _mm512_swizzle_ps(t2, _MM_SWIZ_REG_CDAB));
-
-    _mm512_mask_packstorelo_ps(&f, _mm512_mask2int(0x1), t2);
-    return f;
-}
-
-static inline SimdFloat gmx_simdcall loadDualHsimd(const float* m0, const float* m1)
-{
-    assert(std::size_t(m0) % 32 == 0);
-    assert(std::size_t(m1) % 32 == 0);
-
-    return _mm512_castpd_ps(_mm512_mask_extload_pd(
-            _mm512_extload_pd(reinterpret_cast<const double*>(m0), _MM_UPCONV_PD_NONE,
-                              _MM_BROADCAST_4X8, _MM_HINT_NONE),
-            _mm512_int2mask(0xF0), reinterpret_cast<const double*>(m1), _MM_UPCONV_PD_NONE,
-            _MM_BROADCAST_4X8, _MM_HINT_NONE));
-}
-
-static inline SimdFloat gmx_simdcall loadDuplicateHsimd(const float* m)
-{
-    assert(std::size_t(m) % 32 == 0);
-
-    return _mm512_castpd_ps(_mm512_extload_pd(reinterpret_cast<const double*>(m),
-                                              _MM_UPCONV_PD_NONE, _MM_BROADCAST_4X8, _MM_HINT_NONE));
-}
-
-static inline SimdFloat gmx_simdcall loadU1DualHsimd(const float* m)
-{
-    return _mm512_mask_extload_ps(
-            _mm512_extload_ps(m, _MM_UPCONV_PS_NONE, _MM_BROADCAST_1X16, _MM_HINT_NONE),
-            _mm512_int2mask(0xFF00), m + 1, _MM_UPCONV_PS_NONE, _MM_BROADCAST_1X16, _MM_HINT_NONE);
-}
-
-
-static inline void gmx_simdcall storeDualHsimd(float* m0, float* m1, SimdFloat a)
-{
-    __m512 t0;
-
-    assert(std::size_t(m0) % 32 == 0);
-    assert(std::size_t(m1) % 32 == 0);
-
-    _mm512_mask_packstorelo_ps(m0, _mm512_int2mask(0x00FF), a.simdInternal_);
-    _mm512_mask_packstorelo_ps(m1, _mm512_int2mask(0xFF00), a.simdInternal_);
-}
-
-static inline void gmx_simdcall incrDualHsimd(float* m0, float* m1, SimdFloat a)
-{
-    assert(std::size_t(m0) % 32 == 0);
-    assert(std::size_t(m1) % 32 == 0);
-
-    __m512 x;
-
-    // Update lower half
-    x = _mm512_castpd_ps(_mm512_extload_pd(reinterpret_cast<const double*>(m0), _MM_UPCONV_PD_NONE,
-                                           _MM_BROADCAST_4X8, _MM_HINT_NONE));
-    x = _mm512_add_ps(x, a.simdInternal_);
-    _mm512_mask_packstorelo_ps(m0, _mm512_int2mask(0x00FF), x);
-
-    // Update upper half
-    x = _mm512_castpd_ps(_mm512_extload_pd(reinterpret_cast<const double*>(m1), _MM_UPCONV_PD_NONE,
-                                           _MM_BROADCAST_4X8, _MM_HINT_NONE));
-    x = _mm512_add_ps(x, a.simdInternal_);
-    _mm512_mask_packstorelo_ps(m1, _mm512_int2mask(0xFF00), x);
-}
-
-static inline void gmx_simdcall decr3Hsimd(float* m, SimdFloat a0, SimdFloat a1, SimdFloat a2)
-{
-    assert(std::size_t(m) % 32 == 0);
-    decrHsimd(m, a0);
-    decrHsimd(m + GMX_SIMD_FLOAT_WIDTH / 2, a1);
-    decrHsimd(m + GMX_SIMD_FLOAT_WIDTH, a2);
-}
-
-
-template<int align>
-static inline void gmx_simdcall gatherLoadTransposeHsimd(const float*       base0,
-                                                         const float*       base1,
-                                                         const std::int32_t offset[],
-                                                         SimdFloat*         v0,
-                                                         SimdFloat*         v1)
-{
-    __m512i idx0, idx1, idx;
-    __m512  tmp1, tmp2;
-
-    assert(std::size_t(offset) % 32 == 0);
-    assert(std::size_t(base0) % 8 == 0);
-    assert(std::size_t(base1) % 8 == 0);
-    assert(std::size_t(align) % 2 == 0);
-
-    idx0 = _mm512_loadunpacklo_epi32(_mm512_undefined_epi32(), offset);
-
-    idx0 = _mm512_mullo_epi32(idx0, _mm512_set1_epi32(align));
-    idx1 = _mm512_add_epi32(idx0, _mm512_set1_epi32(1));
-
-    idx = _mm512_mask_permute4f128_epi32(idx0, _mm512_int2mask(0xFF00), idx1, _MM_PERM_BABA);
-
-    tmp1 = _mm512_i32gather_ps(idx, base0, sizeof(float));
-    tmp2 = _mm512_i32gather_ps(idx, base1, sizeof(float));
-
-    v0->simdInternal_ = _mm512_mask_permute4f128_ps(tmp1, _mm512_int2mask(0xFF00), tmp2, _MM_PERM_BABA);
-    v1->simdInternal_ = _mm512_mask_permute4f128_ps(tmp2, _mm512_int2mask(0x00FF), tmp1, _MM_PERM_DCDC);
-}
-
-static inline float gmx_simdcall reduceIncr4ReturnSumHsimd(float* m, SimdFloat v0, SimdFloat v1)
-{
-    float  f;
-    __m512 t0, t1;
-
-    assert(std::size_t(m) % 32 == 0);
-
-    t0 = _mm512_add_ps(v0.simdInternal_, _mm512_swizzle_ps(v0.simdInternal_, _MM_SWIZ_REG_BADC));
-    t0 = _mm512_mask_add_ps(t0, _mm512_int2mask(0xCCCC), v1.simdInternal_,
-                            _mm512_swizzle_ps(v1.simdInternal_, _MM_SWIZ_REG_BADC));
-    t0 = _mm512_add_ps(t0, _mm512_swizzle_ps(t0, _MM_SWIZ_REG_CDAB));
-    t0 = _mm512_add_ps(t0, _mm512_castpd_ps(_mm512_swizzle_pd(_mm512_castps_pd(t0), _MM_SWIZ_REG_BADC)));
-    t0 = _mm512_mask_permute4f128_ps(t0, _mm512_int2mask(0xAAAA), t0, _MM_PERM_BADC);
-    t1 = _mm512_mask_extload_ps(_mm512_undefined_ps(), _mm512_int2mask(0xF), m, _MM_UPCONV_PS_NONE,
-                                _MM_BROADCAST_4X16, _MM_HINT_NONE);
-    t1 = _mm512_add_ps(t1, t0);
-    _mm512_mask_packstorelo_ps(m, _mm512_int2mask(0xF), t1);
-
-    t0 = _mm512_add_ps(t0, _mm512_swizzle_ps(t0, _MM_SWIZ_REG_BADC));
-    t0 = _mm512_add_ps(t0, _mm512_swizzle_ps(t0, _MM_SWIZ_REG_CDAB));
-
-    _mm512_mask_packstorelo_ps(&f, _mm512_mask2int(0x1), t0);
-    return f;
-}
-
-} // namespace gmx
-
-#endif // GMX_SIMD_IMPL_X86_MIC_UTIL_FLOAT_H
index 25f0471a43ec6e71dc5c74f5fbf8a9dd1b7844a7..6beb22595dcbf960f37130d23c49b644a928f493 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -212,6 +212,21 @@ static inline float maskzFma(float a, float b, float c, float m)
     return m != 0.0F ? (a * b + c) : 0.0F;
 }
 
+/*! \brief Float 1.0/x, masked version.
+ *
+ * \param x Argument, x>0 for entries where mask is true.
+ * \param m Mask
+ * \return 1/x. The result for masked-out entries will be 0.0.
+ *
+ * \note This function might be superficially meaningless, but it helps us to
+ *       write templated SIMD/non-SIMD code. For clarity it should not be used
+ *       outside such code.
+ */
+static inline float gmx_simdcall maskzRcp(float x, float m)
+{
+    return m != 0.0F ? 1.0F / x : 0.0F;
+}
+
 /*! \brief Float Floating-point abs().
  *
  * \param a any floating point values
@@ -603,6 +618,21 @@ static inline double maskzFma(double a, double b, double c, double m)
     return m != 0.0 ? (a * b + c) : 0.0;
 }
 
+/*! \brief Double 1.0/x, masked version.
+ *
+ * \param x Argument, x>0 for entries where mask is true.
+ * \param m Mask
+ * \return Approximation of 1/x. The result for masked-out entries will be 0.0.
+ *
+ * \note This function might be superficially meaningless, but it helps us to
+ *       write templated SIMD/non-SIMD code. For clarity it should not be used
+ *       outside such code.
+ */
+static inline double gmx_simdcall maskzRcp(double x, double m)
+{
+    return m != 0.0 ? 1.0 / x : 0.0;
+}
+
 /*! \brief double doubleing-point abs().
  *
  * \param a any doubleing point values
index 246e45b7f2e1c1983a575d001d9ed79aa90f1ecc..a5239859843c8f0b256084865520395479e88b99 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -169,6 +169,21 @@ static inline float sqrt(float x)
     return std::sqrt(x);
 }
 
+/*! \brief Float cbrt(x). This is the cubic root.
+ *
+ * \param x Argument, should be >= 0.
+ * \result The cubic root of x. Undefined if argument is invalid.
+ *
+ * \note This function might be superficially meaningless, but it helps us to
+ *       write templated SIMD/non-SIMD code. For clarity it should not be used
+ *       outside such code.
+ */
+template<MathOptimization opt = MathOptimization::Safe>
+static inline float cbrt(float x)
+{
+    return std::cbrt(x);
+}
+
 /*! \brief Float log(x). This is the natural logarithm.
  *
  * \param x Argument, should be >0.
@@ -557,6 +572,21 @@ static inline double sqrt(double x)
     return std::sqrt(x);
 }
 
+/*! \brief Double cbrt(x). This is the cubic root.
+ *
+ * \param x Argument, should be >= 0.
+ * \result The cubic root of x. Undefined if argument is invalid.
+ *
+ * \note This function might be superficially meaningless, but it helps us to
+ *       write templated SIMD/non-SIMD code. For clarity it should not be used
+ *       outside such code.
+ */
+template<MathOptimization opt = MathOptimization::Safe>
+static inline double cbrt(double x)
+{
+    return std::cbrt(x);
+}
+
 /*! \brief Double log(x). This is the natural logarithm.
  *
  * \param x Argument, should be >0.
index 55fd89f55fd679d5d20a7c7ca4183e5d75f08e53..5f98fcdafb10d2c0c08984b2394f01868a4889ea 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstdint>
 
 #include <array>
+#include <memory>
 #include <type_traits>
 
 #include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/real.h"
 
 //! \cond libapi
@@ -142,20 +142,14 @@ struct SimdDInt32Tag
 #    include "impl_x86_avx2_256/impl_x86_avx2_256.h"
 #elif GMX_SIMD_X86_AVX2_128
 #    include "impl_x86_avx2_128/impl_x86_avx2_128.h"
-#elif GMX_SIMD_X86_MIC
-#    include "impl_x86_mic/impl_x86_mic.h"
 #elif GMX_SIMD_X86_AVX_512
 #    include "impl_x86_avx_512/impl_x86_avx_512.h"
 #elif GMX_SIMD_X86_AVX_512_KNL
 #    include "impl_x86_avx_512_knl/impl_x86_avx_512_knl.h"
-#elif GMX_SIMD_ARM_NEON
-#    include "impl_arm_neon/impl_arm_neon.h"
 #elif GMX_SIMD_ARM_NEON_ASIMD
 #    include "impl_arm_neon_asimd/impl_arm_neon_asimd.h"
 #elif GMX_SIMD_ARM_SVE
 #    include "impl_arm_sve/impl_arm_sve.h"
-#elif GMX_SIMD_IBM_VMX
-#    include "impl_ibm_vmx/impl_ibm_vmx.h"
 #elif GMX_SIMD_IBM_VSX
 #    include "impl_ibm_vsx/impl_ibm_vsx.h"
 #elif (GMX_SIMD_REFERENCE || defined DOXYGEN)
index abd001c5f55878197167250cc3d429097b9352f4..5642c45e32ac8caa588919c61151bcdadfb43c08 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -62,6 +62,7 @@
 
 #include <limits>
 
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/simd/simd.h"
 #include "gromacs/utility/basedefinitions.h"
index 9a770ce906e81538253a56ef56be570136d7c783..d6c3a697240006d6d864029ef6f7fe6f8599139d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ public:
     }
 
 private:
-    pointer const m_; //!< The pointer used to load memory
+    pointer m_; //!< The pointer used to load memory
 };
 
 template<typename T>
@@ -201,8 +201,8 @@ private:
     template<typename U>
     friend class SimdArrayRef;
 
-    pointer const begin_;
-    pointer const end_;
+    pointer begin_;
+    pointer end_;
 };
 
 } // namespace internal
index 0d1f9fd850a50b3bcd42f27b5995bdce5e153ca4..954a840529e94746b881576f638122ca0743073a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,52 +70,25 @@ namespace gmx
 
 const std::string& simdString(SimdType s)
 {
-    static const std::map<SimdType, std::string> name = {
-        { SimdType::None, "None" },
-        { SimdType::Reference, "Reference" },
-        { SimdType::Generic, "Generic" },
-        { SimdType::X86_Sse2, "SSE2" },
-        { SimdType::X86_Sse4_1, "SSE4.1" },
-        { SimdType::X86_Avx128Fma, "AVX_128_FMA" },
-        { SimdType::X86_Avx, "AVX_256" },
-        { SimdType::X86_Avx2, "AVX2_256" },
-        { SimdType::X86_Avx2_128, "AVX2_128" },
-        { SimdType::X86_Avx512, "AVX_512" },
-        { SimdType::X86_Avx512Knl, "AVX_512_KNL" },
-        { SimdType::X86_Mic, "X86_MIC" },
-        { SimdType::Arm_Neon, "ARM_NEON" },
-        { SimdType::Arm_NeonAsimd, "ARM_NEON_ASIMD" },
-        { SimdType::Arm_Sve, "ARM_SVE" },
-        { SimdType::Ibm_Vmx, "IBM_VMX" },
-        { SimdType::Ibm_Vsx, "IBM_VSX" },
-        { SimdType::Fujitsu_HpcAce, "Fujitsu HPC-ACE" }
-    };
+    static const std::map<SimdType, std::string> name = { { SimdType::None, "None" },
+                                                          { SimdType::Reference, "Reference" },
+                                                          { SimdType::Generic, "Generic" },
+                                                          { SimdType::X86_Sse2, "SSE2" },
+                                                          { SimdType::X86_Sse4_1, "SSE4.1" },
+                                                          { SimdType::X86_Avx128Fma, "AVX_128_FMA" },
+                                                          { SimdType::X86_Avx, "AVX_256" },
+                                                          { SimdType::X86_Avx2, "AVX2_256" },
+                                                          { SimdType::X86_Avx2_128, "AVX2_128" },
+                                                          { SimdType::X86_Avx512, "AVX_512" },
+                                                          { SimdType::X86_Avx512Knl, "AVX_512_KNL" },
+                                                          { SimdType::Arm_NeonAsimd,
+                                                            "ARM_NEON_ASIMD" },
+                                                          { SimdType::Arm_Sve, "ARM_SVE" },
+                                                          { SimdType::Ibm_Vsx, "IBM_VSX" } };
 
     return name.at(s);
 }
 
-namespace
-{
-
-
-//! Helper to detect correct AMD Zen architecture.
-bool cpuIsAmdZen1(const CpuInfo& cpuInfo)
-{
-    // Both Zen/Zen+/Zen2 have family==23
-    // Model numbers for Zen:
-    // 1)  Naples, Whitehaven, Summit ridge, and Snowy Owl
-    // 17) Raven ridge
-    // Model numbers for Zen+:
-    // 8)  Pinnacle Ridge
-    // 24) Picasso
-    return (cpuInfo.vendor() == gmx::CpuInfo::Vendor::Amd && cpuInfo.family() == 23
-            && (cpuInfo.model() == 1 || cpuInfo.model() == 17 || cpuInfo.model() == 8
-                || cpuInfo.model() == 24));
-}
-
-} // namespace
-
-
 SimdType simdSuggested(const CpuInfo& c)
 {
     SimdType suggested = SimdType::None;
@@ -195,7 +168,7 @@ SimdType simdSuggested(const CpuInfo& c)
                 }
                 else if (c.feature(CpuInfo::Feature::Arm_Neon))
                 {
-                    suggested = SimdType::Arm_Neon;
+                    suggested = SimdType::None;
                 }
                 break;
             case CpuInfo::Vendor::Ibm:
@@ -205,13 +178,13 @@ SimdType simdSuggested(const CpuInfo& c)
                 }
                 else if (c.feature(CpuInfo::Feature::Ibm_Vmx))
                 {
-                    suggested = SimdType::Ibm_Vmx;
+                    suggested = SimdType::None;
                 }
                 break;
             case CpuInfo::Vendor::Fujitsu:
                 if (c.feature(CpuInfo::Feature::Fujitsu_HpcAce))
                 {
-                    suggested = SimdType::Fujitsu_HpcAce;
+                    suggested = SimdType::None;
                 }
                 break;
             default: break;
@@ -226,8 +199,6 @@ SimdType simdCompiled()
     return SimdType::X86_Avx512Knl;
 #elif GMX_SIMD_X86_AVX_512
     return SimdType::X86_Avx512;
-#elif GMX_SIMD_X86_MIC
-    return SimdType::X86_Mic;
 #elif GMX_SIMD_X86_AVX2_256
     return SimdType::X86_Avx2;
 #elif GMX_SIMD_X86_AVX2_128
@@ -240,18 +211,12 @@ SimdType simdCompiled()
     return SimdType::X86_Sse4_1;
 #elif GMX_SIMD_X86_SSE2
     return SimdType::X86_Sse2;
-#elif GMX_SIMD_ARM_NEON
-    return SimdType::Arm_Neon;
 #elif GMX_SIMD_ARM_NEON_ASIMD
     return SimdType::Arm_NeonAsimd;
 #elif GMX_SIMD_ARM_SVE
     return SimdType::Arm_Sve;
-#elif GMX_SIMD_IBM_VMX
-    return SimdType::Ibm_Vmx;
 #elif GMX_SIMD_IBM_VSX
     return SimdType::Ibm_Vsx;
-#elif GMX_SIMD_SPARC64_HPC_ACE
-    return SimdType::Fujitsu_HpcAce;
 #elif GMX_SIMD_REFERENCE
     return SimdType::Reference;
 #else
@@ -278,10 +243,12 @@ bool simdCheck(gmx::SimdType wanted, FILE* log, bool warnToStdErr)
                 "which could influence performance. This build might have been configured on "
                 "a login node with only a single AVX-512 FMA unit (in which case AVX2 is faster), "
                 "while the node you are running on has dual AVX-512 FMA units.",
-                simdString(wanted).c_str(), simdString(compiled).c_str()));
+                simdString(wanted).c_str(),
+                simdString(compiled).c_str()));
         warnMsg = wrapper.wrapToString(formatString(
                 "Compiled SIMD: %s, but for this host/run %s might be better (see log).",
-                simdString(compiled).c_str(), simdString(wanted).c_str()));
+                simdString(compiled).c_str(),
+                simdString(wanted).c_str()));
     }
     else if (compiled == SimdType::X86_Avx512 && wanted == SimdType::X86_Avx2
              && identifyAvx512FmaUnits() == 1)
@@ -295,10 +262,12 @@ bool simdCheck(gmx::SimdType wanted, FILE* log, bool warnToStdErr)
                 "which could influence performance."
                 "This host supports AVX-512, but since it only has 1 AVX-512"
                 "FMA unit, it would be faster to use AVX2 instead.",
-                simdString(wanted).c_str(), simdString(compiled).c_str()));
+                simdString(wanted).c_str(),
+                simdString(compiled).c_str()));
         warnMsg = wrapper.wrapToString(formatString(
                 "Compiled SIMD: %s, but for this host/run %s might be better (see log).",
-                simdString(compiled).c_str(), simdString(wanted).c_str()));
+                simdString(compiled).c_str(),
+                simdString(wanted).c_str()));
     }
     else if (compiled == SimdType::X86_Avx2 && wanted == SimdType::X86_Avx2_128)
     {
@@ -316,7 +285,8 @@ bool simdCheck(gmx::SimdType wanted, FILE* log, bool warnToStdErr)
                 formatString("Highest SIMD level requested by all nodes in run: %s\n"
                              "SIMD instructions selected at compile time:       %s\n"
                              "Compiled SIMD newer than requested; program might crash.",
-                             simdString(wanted).c_str(), simdString(compiled).c_str()));
+                             simdString(wanted).c_str(),
+                             simdString(compiled).c_str()));
         warnMsg = logMsg;
     }
     else if (wanted != compiled)
@@ -327,10 +297,12 @@ bool simdCheck(gmx::SimdType wanted, FILE* log, bool warnToStdErr)
                 "SIMD instructions selected at compile time:       %s\n"
                 "This program was compiled for different hardware than you are running on, "
                 "which could influence performance.",
-                simdString(wanted).c_str(), simdString(compiled).c_str()));
+                simdString(wanted).c_str(),
+                simdString(compiled).c_str()));
         warnMsg = wrapper.wrapToString(formatString(
                 "Compiled SIMD: %s, but for this host/run %s might be better (see log).",
-                simdString(compiled).c_str(), simdString(wanted).c_str()));
+                simdString(compiled).c_str(),
+                simdString(wanted).c_str()));
 #if GMX_SIMD_ARM_SVE
     }
     else if ((compiled == SimdType::Arm_Sve) && (svcntb() != GMX_SIMD_ARM_SVE_LENGTH_VALUE / 8))
@@ -341,10 +313,12 @@ bool simdCheck(gmx::SimdType wanted, FILE* log, bool warnToStdErr)
                 "This program was compiled for different hardware than you are running on, "
                 "which will lead to incorrect behavior.\n"
                 "Aborting",
-                GMX_SIMD_ARM_SVE_LENGTH_VALUE, svcntb() * 8));
+                GMX_SIMD_ARM_SVE_LENGTH_VALUE,
+                svcntb() * 8));
         warnMsg = wrapper.wrapToString(formatString(
                 "Compiled SVE Length: %d, but for this process requires %ld (see log).",
-                GMX_SIMD_ARM_SVE_LENGTH_VALUE, svcntb() * 8));
+                GMX_SIMD_ARM_SVE_LENGTH_VALUE,
+                svcntb() * 8));
 #endif
     }
 
index 2e108126749e06f8c8efc3f78a7cef4f7980f748..339e17266d394ffe59f445c666408d5b0fb1d25d 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,13 +68,9 @@ enum class SimdType
     X86_Avx2_128,  //!< 128-bit AVX2, better than 256-bit for AMD Ryzen
     X86_Avx512,    //!< AVX_512
     X86_Avx512Knl, //!< AVX_512_KNL
-    X86_Mic,       //!< Knight's corner
-    Arm_Neon,      //!< 32-bit ARM NEON
     Arm_NeonAsimd, //!< 64-bit ARM AArch64 Advanced SIMD
     Arm_Sve,       //!< ARM Scalable Vector Extensions
-    Ibm_Vmx,       //!< IBM VMX SIMD (Altivec on Power6 and later)
-    Ibm_Vsx,       //!< IBM VSX SIMD (Power7 and later)
-    Fujitsu_HpcAce //!< Fujitsu K-computer
+    Ibm_Vsx        //!< IBM VSX SIMD (Power7 and later)
 };
 
 /*! \libinternal \brief Return a string with the name of a SIMD type
diff --git a/src/gromacs/simd/tests/.clang-tidy b/src/gromacs/simd/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 88015754b136a1af61e4700cb03fdf5a6ae4148f..31a39a3864ca962a154073dfb105e1c8d8b8b17e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +74,7 @@ int SimdBaseTest::s_nPoints = 10000;
 ::testing::AssertionResult SimdBaseTest::compareVectorRealUlp(const char*              refExpr,
                                                               const char*              tstExpr,
                                                               const std::vector<real>& ref,
-                                                              const std::vector<real>& tst)
+                                                              const std::vector<real>& tst) const
 {
     std::vector<real>         absDiff(tst.size());
     std::vector<std::int64_t> ulpDiff(tst.size());
index 5b17e771f1ad68a24ba7d9d19cb4750b684e40b8..a3fb6170ce70c8d78376db8a875069fe799555e8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -161,7 +161,7 @@ public:
     ::testing::AssertionResult compareVectorRealUlp(const char*              refExpr,
                                                     const char*              tstExpr,
                                                     const std::vector<real>& ref,
-                                                    const std::vector<real>& tst);
+                                                    const std::vector<real>& tst) const;
 
     /*! \brief Compare std::vectors for exact equality.
      *
index 048386b148d573350e587da53145acecbcd011d3..d83f5a6d2682e00c9ca8c61ffad83b5b4e5cbf20 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -39,6 +39,7 @@
 
 #include <gtest/gtest.h>
 
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/simd/simd.h"
 #include "gromacs/utility/basedefinitions.h"
index 2c786ab4f4c3dfa4c1a723f53f31ebe1925ee981..1395b3ae67224893f44cbe2a31828149dce05b15 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +37,7 @@
 
 #include <cmath>
 
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/simd/simd.h"
 #include "gromacs/utility/basedefinitions.h"
index c60c1e58f5ee4c201576548f0562dc725cb0dea8..e3c1bf9ebc117e9213d87de4571dd17f3ff167e9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -39,6 +39,7 @@
 
 #include <vector>
 
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/simd/simd.h"
index 4853a5a6624287789f88df7a6ba0c4c2d472fd44..0cf3958d67b440c198fc1fc384da33ffad3bb040 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -65,8 +65,8 @@ TEST_F(Simd4VectorOperationsTest, norm2)
     Simd4Real simdX  = rSimd4_c0c1c2;
     Simd4Real simdY  = rSimd4_c3c4c5;
     Simd4Real simdZ  = rSimd4_c6c7c8;
-    Simd4Real simdR2 = setSimd4RealFrom3R(c0 * c0 + c3 * c3 + c6 * c6, c1 * c1 + c4 * c4 + c7 * c7,
-                                          c2 * c2 + c5 * c5 + c8 * c8);
+    Simd4Real simdR2 = setSimd4RealFrom3R(
+            c0 * c0 + c3 * c3 + c6 * c6, c1 * c1 + c4 * c4 + c7 * c7, c2 * c2 + c5 * c5 + c8 * c8);
 
     setUlpTol(2);
     GMX_EXPECT_SIMD4_REAL_NEAR(simdR2, norm2(simdX, simdY, simdZ));
index 28d07cb7713e90a33504890ae4f0bbac0f158d30..dc5d157b1adf3be4df1fea0804ae4a478b33a5ac 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -39,6 +39,7 @@
 
 #include <array>
 
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/simd/simd.h"
 #include "gromacs/utility/basedefinitions.h"
@@ -243,14 +244,16 @@ TEST_F(SimdFloatingpointTest, frexp)
 
 
     fraction = frexp(rSimd_Exp, &exponent);
-    GMX_EXPECT_SIMD_REAL_EQ(setSimdRealFrom3R(0.609548660288905419513128, 0.5833690139241746175358116,
+    GMX_EXPECT_SIMD_REAL_EQ(setSimdRealFrom3R(0.609548660288905419513128,
+                                              0.5833690139241746175358116,
                                               -0.584452007502232362412542),
                             fraction);
     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom3I(61, -40, 55), exponent);
 
     // Test the unsafe flavor too, in case they use different branches
     fraction = frexp<MathOptimization::Unsafe>(rSimd_Exp, &exponent);
-    GMX_EXPECT_SIMD_REAL_EQ(setSimdRealFrom3R(0.609548660288905419513128, 0.5833690139241746175358116,
+    GMX_EXPECT_SIMD_REAL_EQ(setSimdRealFrom3R(0.609548660288905419513128,
+                                              0.5833690139241746175358116,
                                               -0.584452007502232362412542),
                             fraction);
     GMX_EXPECT_SIMD_INT_EQ(setSimdIntFrom3I(61, -40, 55), exponent);
index ee43c3cada45242f2fe5c960048e3b7ae7c7dac1..7a2fd80cc85ea5255c4909477053a2291e057721 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -466,9 +466,6 @@ TEST_F(SimdFloatingpointUtilTest, transposeScatterDecrU3Overlapping)
         mem0_[j] = refmem[j] = (1000.0 + j) * (1.0 + 100 * GMX_REAL_EPS);
     }
 
-#    ifdef __INTEL_COMPILER // Bug in (at least) 19u1 and 18u5 (03424712)
-#        pragma novector
-#    endif
     for (std::size_t j = 0; j < GMX_SIMD_REAL_WIDTH; j++)
     {
         // Subtract values from _reference_ memory (we will then test with mem0_, and compare)
@@ -942,9 +939,6 @@ TEST_F(SimdFloatingpointUtilTest, loadUNDuplicate4)
     real       data[GMX_SIMD_REAL_WIDTH / 4];
     std::iota(data, data + GMX_SIMD_REAL_WIDTH / 4, 1);
 
-#        if defined __ICC && __ICC == 1800 || defined __ICL && __ICL == 1800
-#            pragma novector /* Work-around for incorrect vectorization for AVX_512(_KNL) */
-#        endif
     for (i = 0; i < GMX_SIMD_REAL_WIDTH / 4; i++)
     {
         val0_[i * 4] = val0_[i * 4 + 1] = val0_[i * 4 + 2] = val0_[i * 4 + 3] = data[i];
index 07b25cde5f5849241f25d2377b33b3ff41750e03..463790cb4773971be4d6f8b70f36d767e752d73f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <utility>
 #include <vector>
 
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/simd/simd.h"
@@ -712,13 +713,17 @@ TEST_F(SimdMathTest, exp2)
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp2, exp2, settings);
 
     // Subnormal range, require matching, but DTZ is fine
-    settings = { Range(lowestRealThatProducesDenormal, lowestRealThatProducesNormal), ulpTol_,
-                 absTol_, MatchRule::Dtz };
+    settings = { Range(lowestRealThatProducesDenormal, lowestRealThatProducesNormal),
+                 ulpTol_,
+                 absTol_,
+                 MatchRule::Dtz };
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp2, exp2, settings);
 
     // Normal range, standard result expected
-    settings = { Range(lowestRealThatProducesNormal, highestRealThatProducesNormal), ulpTol_,
-                 absTol_, MatchRule::Normal };
+    settings = { Range(lowestRealThatProducesNormal, highestRealThatProducesNormal),
+                 ulpTol_,
+                 absTol_,
+                 MatchRule::Normal };
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp2, exp2, settings);
 }
 
@@ -733,7 +738,9 @@ TEST_F(SimdMathTest, exp2Unsafe)
             - 1; // adding the significant corresponds to one more unit in exponent
 
     CompareSettings settings{ Range(lowestRealThatProducesNormal, highestRealThatProducesNormal),
-                              ulpTol_, absTol_, MatchRule::Normal };
+                              ulpTol_,
+                              absTol_,
+                              MatchRule::Normal };
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp2, exp2<MathOptimization::Unsafe>, settings);
 }
 
@@ -744,7 +751,7 @@ TEST_F(SimdMathTest, exp)
     const real lowestReal = -std::numeric_limits<real>::max();
     // In theory the smallest value should be (min_exponent-1)*log(2), but rounding after the multiplication will cause this
     // value to be a single ulp too low. This might cause failed tests on CPUs that use different DTZ modes for SIMD vs.
-    // non-SIMD arithmetics (ARM v7), so multiply by (1.0-eps) to increase it by a single ulp.
+    // non-SIMD arithmetics (e.g. ARM v7), so multiply by (1.0-eps) to increase it by a single ulp.
     const real lowestRealThatProducesNormal = (std::numeric_limits<real>::min_exponent - 1)
                                               * std::log(2.0)
                                               * (1 - std::numeric_limits<real>::epsilon());
@@ -759,13 +766,17 @@ TEST_F(SimdMathTest, exp)
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp, exp, settings);
 
     // Subnormal range, require matching, but DTZ is fine
-    settings = { Range(lowestRealThatProducesDenormal, lowestRealThatProducesNormal), ulpTol_,
-                 absTol_, MatchRule::Dtz };
+    settings = { Range(lowestRealThatProducesDenormal, lowestRealThatProducesNormal),
+                 ulpTol_,
+                 absTol_,
+                 MatchRule::Dtz };
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp, exp, settings);
 
     // Normal range, standard result expected
-    settings = { Range(lowestRealThatProducesNormal, highestRealThatProducesNormal), ulpTol_,
-                 absTol_, MatchRule::Normal };
+    settings = { Range(lowestRealThatProducesNormal, highestRealThatProducesNormal),
+                 ulpTol_,
+                 absTol_,
+                 MatchRule::Normal };
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp, exp, settings);
 }
 
@@ -779,7 +790,9 @@ TEST_F(SimdMathTest, expUnsafe)
             (std::numeric_limits<real>::max_exponent - 1) * std::log(2.0);
 
     CompareSettings settings{ Range(lowestRealThatProducesNormal, highestRealThatProducesNormal),
-                              ulpTol_, absTol_, MatchRule::Normal };
+                              ulpTol_,
+                              absTol_,
+                              MatchRule::Normal };
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp, exp<MathOptimization::Unsafe>, settings);
 }
 
@@ -842,8 +855,7 @@ real refErfc(real x)
 TEST_F(SimdMathTest, erfc)
 {
     // Our erfc algorithm has 4 ulp accuracy, so relax tolerance a bit to 4*ulpTol
-    CompareSettings settings{ Range(-9, 9), 4 * ulpTol_, std::numeric_limits<real>::min(),
-                              MatchRule::Normal };
+    CompareSettings settings{ Range(-9, 9), 4 * ulpTol_, std::numeric_limits<real>::min(), MatchRule::Normal };
     GMX_EXPECT_SIMD_FUNC_NEAR(refErfc, erfc, settings);
 }
 
@@ -1183,13 +1195,17 @@ TEST_F(SimdMathTest, exp2SingleAccuracy)
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp2, exp2SingleAccuracy, settings);
 
     // Subnormal range, require matching, but DTZ is fine
-    settings = { Range(lowestRealThatProducesDenormal, lowestRealThatProducesNormal), ulpTol_,
-                 absTol_, MatchRule::Dtz };
+    settings = { Range(lowestRealThatProducesDenormal, lowestRealThatProducesNormal),
+                 ulpTol_,
+                 absTol_,
+                 MatchRule::Dtz };
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp2, exp2SingleAccuracy, settings);
 
     // Normal range, standard result expected
-    settings = { Range(lowestRealThatProducesNormal, highestRealThatProducesNormal), ulpTol_,
-                 absTol_, MatchRule::Normal };
+    settings = { Range(lowestRealThatProducesNormal, highestRealThatProducesNormal),
+                 ulpTol_,
+                 absTol_,
+                 MatchRule::Normal };
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp2, exp2SingleAccuracy, settings);
 }
 
@@ -1207,7 +1223,9 @@ TEST_F(SimdMathTest, exp2SingleAccuracyUnsafe)
     setUlpTolSingleAccuracy(ulpTol_);
 
     CompareSettings settings{ Range(lowestRealThatProducesNormal, highestRealThatProducesNormal),
-                              ulpTol_, absTol_, MatchRule::Normal };
+                              ulpTol_,
+                              absTol_,
+                              MatchRule::Normal };
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp2, exp2SingleAccuracy<MathOptimization::Unsafe>, settings);
 }
 
@@ -1217,7 +1235,7 @@ TEST_F(SimdMathTest, expSingleAccuracy)
     const real lowestReal = -std::numeric_limits<real>::max();
     // In theory the smallest value should be (min_exponent-1)*log(2), but rounding after the multiplication will cause this
     // value to be a single ulp too low. This might cause failed tests on CPUs that use different DTZ modes for SIMD vs.
-    // non-SIMD arithmetics (ARM v7), so multiply by (1.0-eps) to increase it by a single ulp.
+    // non-SIMD arithmetics (e.g. ARM v7), so multiply by (1.0-eps) to increase it by a single ulp.
     const real lowestRealThatProducesNormal = (std::numeric_limits<real>::min_exponent - 1)
                                               * std::log(2.0)
                                               * (1.0 - std::numeric_limits<real>::epsilon());
@@ -1235,13 +1253,17 @@ TEST_F(SimdMathTest, expSingleAccuracy)
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp, expSingleAccuracy, settings);
 
     // Subnormal range, require matching, but DTZ is fine
-    settings = { Range(lowestRealThatProducesDenormal, lowestRealThatProducesNormal), ulpTol_,
-                 absTol_, MatchRule::Dtz };
+    settings = { Range(lowestRealThatProducesDenormal, lowestRealThatProducesNormal),
+                 ulpTol_,
+                 absTol_,
+                 MatchRule::Dtz };
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp, expSingleAccuracy, settings);
 
     // Normal range, standard result expected
-    settings = { Range(lowestRealThatProducesNormal, highestRealThatProducesNormal), ulpTol_,
-                 absTol_, MatchRule::Normal };
+    settings = { Range(lowestRealThatProducesNormal, highestRealThatProducesNormal),
+                 ulpTol_,
+                 absTol_,
+                 MatchRule::Normal };
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp, expSingleAccuracy, settings);
 }
 
@@ -1258,7 +1280,9 @@ TEST_F(SimdMathTest, expSingleAccuracyUnsafe)
     setUlpTolSingleAccuracy(ulpTol_);
 
     CompareSettings settings{ Range(lowestRealThatProducesNormal, highestRealThatProducesNormal),
-                              ulpTol_, absTol_, MatchRule::Normal };
+                              ulpTol_,
+                              absTol_,
+                              MatchRule::Normal };
     GMX_EXPECT_SIMD_FUNC_NEAR(std::exp, expSingleAccuracy<MathOptimization::Unsafe>, settings);
 }
 
index a662f14a842180b6a7a82e14698032778bfc1f67..8e3e4ff29c12444c098f8bad8388f64d3418ee74 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -68,8 +68,8 @@ TEST_F(SimdVectorOperationsTest, iprod)
     SimdReal bX       = rSimd_c3c0c4;
     SimdReal bY       = rSimd_c4c6c8;
     SimdReal bZ       = rSimd_c7c2c3;
-    SimdReal iprodRef = setSimdRealFrom3R(c0 * c3 + c3 * c4 + c6 * c7, c1 * c0 + c4 * c6 + c7 * c2,
-                                          c2 * c4 + c5 * c8 + c8 * c3);
+    SimdReal iprodRef = setSimdRealFrom3R(
+            c0 * c3 + c3 * c4 + c6 * c7, c1 * c0 + c4 * c6 + c7 * c2, c2 * c4 + c5 * c8 + c8 * c3);
 
     setUlpTol(2);
     GMX_EXPECT_SIMD_REAL_NEAR(iprodRef, iprod(aX, aY, aZ, bX, bY, bZ));
@@ -80,8 +80,8 @@ TEST_F(SimdVectorOperationsTest, norm2)
     SimdReal simdX    = rSimd_c0c1c2;
     SimdReal simdY    = rSimd_c3c4c5;
     SimdReal simdZ    = rSimd_c6c7c8;
-    SimdReal norm2Ref = setSimdRealFrom3R(c0 * c0 + c3 * c3 + c6 * c6, c1 * c1 + c4 * c4 + c7 * c7,
-                                          c2 * c2 + c5 * c5 + c8 * c8);
+    SimdReal norm2Ref = setSimdRealFrom3R(
+            c0 * c0 + c3 * c3 + c6 * c6, c1 * c1 + c4 * c4 + c7 * c7, c2 * c2 + c5 * c5 + c8 * c8);
 
     setUlpTol(2);
     GMX_EXPECT_SIMD_REAL_NEAR(norm2Ref, norm2(simdX, simdY, simdZ));
@@ -98,12 +98,12 @@ TEST_F(SimdVectorOperationsTest, cprod)
     // The SIMD version might use FMA. If we don't force FMA for the reference value, the compiler is free to use FMA
     // for either product. If the compiler uses FMA for one product and the SIMD version uses FMA for the other, the
     // rounding error of each product adds up and the total possible ulp-error is 12.
-    SimdReal refcX = setSimdRealFrom3R(std::fma(-c6, c4, c3 * c7), std::fma(-c7, c6, c4 * c2),
-                                       std::fma(-c8, c8, c5 * c3));
-    SimdReal refcY = setSimdRealFrom3R(std::fma(-c0, c7, c6 * c3), std::fma(-c1, c2, c7 * c0),
-                                       std::fma(-c2, c3, c8 * c4));
-    SimdReal refcZ = setSimdRealFrom3R(std::fma(-c3, c3, c0 * c4), std::fma(-c4, c0, c1 * c6),
-                                       std::fma(-c5, c4, c2 * c8));
+    SimdReal refcX = setSimdRealFrom3R(
+            std::fma(-c6, c4, c3 * c7), std::fma(-c7, c6, c4 * c2), std::fma(-c8, c8, c5 * c3));
+    SimdReal refcY = setSimdRealFrom3R(
+            std::fma(-c0, c7, c6 * c3), std::fma(-c1, c2, c7 * c0), std::fma(-c2, c3, c8 * c4));
+    SimdReal refcZ = setSimdRealFrom3R(
+            std::fma(-c3, c3, c0 * c4), std::fma(-c4, c0, c1 * c6), std::fma(-c5, c4, c2 * c8));
     SimdReal cX, cY, cZ;
 
     // The test assumes that cprod uses FMA on architectures which have FMA so that the compiler
index 1fce039188965e71e37c5495edc303c45718e378..963749925f62e37b001c0bc409c8360a41eed2d5 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,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(statistics INTERFACE)
 file(GLOB STATISTICS_SOURCES *.cpp)
-
 set(LIBGROMACS_SOURCES
     ${LIBGROMACS_SOURCES} ${STATISTICS_SOURCES} PARENT_SCOPE)
 
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(statistics PUBLIC
+target_include_directories(statistics INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(statistics PUBLIC
+target_link_libraries(statistics INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when statistics is an OBJECT target
+#target_link_libraries(statistics PUBLIC legacy_api)
+#target_link_libraries(statistics PRIVATE common)
+
+# Module dependencies
+# statistics interfaces convey transitive dependence on these modules.
+#target_link_libraries(statistics PUBLIC
+target_link_libraries(statistics INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(statistics PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(statistics PRIVATE legacy_modules)
index 5e1315cfeb1e2869763e98bfc0fa88518b92b220..38ccc006e770863d3591c69aa0c8d029efd62dc2 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "gromacs/utility/enumerationhelpers.h"
 #include "statistics.h"
 
 #include <cmath>
 
 #include "gromacs/math/functions.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/real.h"
 #include "gromacs/utility/smalloc.h"
 
-static int gmx_dnint(double x)
-{
-    return gmx::roundToInt(x);
-}
 
 typedef struct gmx_stats
 {
@@ -70,15 +68,6 @@ gmx_stats_t gmx_stats_init()
     return static_cast<gmx_stats_t>(stats);
 }
 
-int gmx_stats_get_npoints(gmx_stats_t gstats, int* N)
-{
-    gmx_stats* stats = static_cast<gmx_stats*>(gstats);
-
-    *N = stats->np;
-
-    return estatsOK;
-}
-
 void gmx_stats_free(gmx_stats_t gstats)
 {
     gmx_stats* stats = static_cast<gmx_stats*>(gstats);
@@ -90,7 +79,7 @@ void gmx_stats_free(gmx_stats_t gstats)
     sfree(stats);
 }
 
-int gmx_stats_add_point(gmx_stats_t gstats, double x, double y, double dx, double dy)
+StatisticsStatus gmx_stats_add_point(gmx_stats_t gstats, double x, double y, double dx, double dy)
 {
     gmx_stats* stats = gstats;
 
@@ -123,72 +112,10 @@ int gmx_stats_add_point(gmx_stats_t gstats, double x, double y, double dx, doubl
     stats->np++;
     stats->computed = 0;
 
-    return estatsOK;
+    return StatisticsStatus::Ok;
 }
 
-int gmx_stats_get_point(gmx_stats_t gstats, real* x, real* y, real* dx, real* dy, real level)
-{
-    gmx_stats* stats = gstats;
-    int        ok, outlier;
-    real       rmsd, r;
-
-    if ((ok = gmx_stats_get_rmsd(gstats, &rmsd)) != estatsOK)
-    {
-        return ok;
-    }
-    outlier = 0;
-    while ((outlier == 0) && (stats->np_c < stats->np))
-    {
-        r       = std::abs(stats->x[stats->np_c] - stats->y[stats->np_c]);
-        outlier = static_cast<int>(r > rmsd * level);
-        if (outlier)
-        {
-            if (nullptr != x)
-            {
-                *x = stats->x[stats->np_c];
-            }
-            if (nullptr != y)
-            {
-                *y = stats->y[stats->np_c];
-            }
-            if (nullptr != dx)
-            {
-                *dx = stats->dx[stats->np_c];
-            }
-            if (nullptr != dy)
-            {
-                *dy = stats->dy[stats->np_c];
-            }
-        }
-        stats->np_c++;
-
-        if (outlier)
-        {
-            return estatsOK;
-        }
-    }
-
-    stats->np_c = 0;
-
-    return estatsNO_POINTS;
-}
-
-int gmx_stats_add_points(gmx_stats_t gstats, int n, real* x, real* y, real* dx, real* dy)
-{
-    for (int i = 0; (i < n); i++)
-    {
-        int ok;
-        if ((ok = gmx_stats_add_point(gstats, x[i], y[i], (nullptr != dx) ? dx[i] : 0,
-                                      (nullptr != dy) ? dy[i] : 0))
-            != estatsOK)
-        {
-            return ok;
-        }
-    }
-    return estatsOK;
-}
-
-static int gmx_stats_compute(gmx_stats* stats, int weight)
+static StatisticsStatus gmx_stats_compute(gmx_stats* stats, int weight)
 {
     double yy, yx, xx, sx, sy, dy, chi2, chi2aa, d2;
     double ssxx, ssyy, ssxy;
@@ -200,7 +127,7 @@ static int gmx_stats_compute(gmx_stats* stats, int weight)
     {
         if (N < 1)
         {
-            return estatsNO_POINTS;
+            return StatisticsStatus::NoPoints;
         }
 
         xx = xx_nw = 0;
@@ -314,15 +241,16 @@ static int gmx_stats_compute(gmx_stats* stats, int weight)
         stats->computed = 1;
     }
 
-    return estatsOK;
+    return StatisticsStatus::Ok;
 }
 
-int gmx_stats_get_ab(gmx_stats_t gstats, int weight, real* a, real* b, real* da, real* db, real* chi2, real* Rfit)
+StatisticsStatus
+gmx_stats_get_ab(gmx_stats_t gstats, int weight, real* a, real* b, real* da, real* db, real* chi2, real* Rfit)
 {
-    gmx_stats* stats = gstats;
-    int        ok;
+    gmx_stats*       stats = gstats;
+    StatisticsStatus ok;
 
-    if ((ok = gmx_stats_compute(stats, weight)) != estatsOK)
+    if ((ok = gmx_stats_compute(stats, weight)) != StatisticsStatus::Ok)
     {
         return ok;
     }
@@ -351,59 +279,30 @@ int gmx_stats_get_ab(gmx_stats_t gstats, int weight, real* a, real* b, real* da,
         *Rfit = stats->Rfit;
     }
 
-    return estatsOK;
-}
-
-int gmx_stats_get_a(gmx_stats_t gstats, int weight, real* a, real* da, real* chi2, real* Rfit)
-{
-    gmx_stats* stats = gstats;
-    int        ok;
-
-    if ((ok = gmx_stats_compute(stats, weight)) != estatsOK)
-    {
-        return ok;
-    }
-    if (nullptr != a)
-    {
-        *a = stats->aa;
-    }
-    if (nullptr != da)
-    {
-        *da = stats->sigma_aa;
-    }
-    if (nullptr != chi2)
-    {
-        *chi2 = stats->chi2aa;
-    }
-    if (nullptr != Rfit)
-    {
-        *Rfit = stats->Rfitaa;
-    }
-
-    return estatsOK;
+    return StatisticsStatus::Ok;
 }
 
-int gmx_stats_get_average(gmx_stats_t gstats, real* aver)
+StatisticsStatus gmx_stats_get_average(gmx_stats_t gstats, real* aver)
 {
-    gmx_stats* stats = gstats;
-    int        ok;
+    gmx_stats*       stats = gstats;
+    StatisticsStatus ok;
 
-    if ((ok = gmx_stats_compute(stats, elsqWEIGHT_NONE)) != estatsOK)
+    if ((ok = gmx_stats_compute(stats, elsqWEIGHT_NONE)) != StatisticsStatus::Ok)
     {
         return ok;
     }
 
     *aver = stats->aver;
 
-    return estatsOK;
+    return StatisticsStatus::Ok;
 }
 
-int gmx_stats_get_ase(gmx_stats_t gstats, real* aver, real* sigma, real* error)
+StatisticsStatus gmx_stats_get_ase(gmx_stats_t gstats, real* aver, real* sigma, real* error)
 {
-    gmx_stats* stats = gstats;
-    int        ok;
+    gmx_stats*       stats = gstats;
+    StatisticsStatus ok;
 
-    if ((ok = gmx_stats_compute(stats, elsqWEIGHT_NONE)) != estatsOK)
+    if ((ok = gmx_stats_compute(stats, elsqWEIGHT_NONE)) != StatisticsStatus::Ok)
     {
         return ok;
     }
@@ -421,257 +320,28 @@ int gmx_stats_get_ase(gmx_stats_t gstats, real* aver, real* sigma, real* error)
         *error = stats->error;
     }
 
-    return estatsOK;
-}
-
-int gmx_stats_get_sigma(gmx_stats_t gstats, real* sigma)
-{
-    gmx_stats* stats = gstats;
-    int        ok;
-
-    if ((ok = gmx_stats_compute(stats, elsqWEIGHT_NONE)) != estatsOK)
-    {
-        return ok;
-    }
-
-    *sigma = stats->sigma_aver;
-
-    return estatsOK;
-}
-
-int gmx_stats_get_error(gmx_stats_t gstats, real* error)
-{
-    gmx_stats* stats = gstats;
-    int        ok;
-
-    if ((ok = gmx_stats_compute(stats, elsqWEIGHT_NONE)) != estatsOK)
-    {
-        return ok;
-    }
-
-    *error = stats->error;
-
-    return estatsOK;
-}
-
-int gmx_stats_get_corr_coeff(gmx_stats_t gstats, real* R)
-{
-    gmx_stats* stats = gstats;
-    int        ok;
-
-    if ((ok = gmx_stats_compute(stats, elsqWEIGHT_NONE)) != estatsOK)
-    {
-        return ok;
-    }
-
-    *R = stats->Rdata;
-
-    return estatsOK;
-}
-
-int gmx_stats_get_rmsd(gmx_stats_t gstats, real* rmsd)
-{
-    gmx_stats* stats = gstats;
-    int        ok;
-
-    if ((ok = gmx_stats_compute(stats, elsqWEIGHT_NONE)) != estatsOK)
-    {
-        return ok;
-    }
-
-    *rmsd = stats->rmsd;
-
-    return estatsOK;
-}
-
-int gmx_stats_dump_xy(gmx_stats_t gstats, FILE* fp)
-{
-    gmx_stats* stats = gstats;
-
-    for (int i = 0; (i < stats->np); i++)
-    {
-        fprintf(fp, "%12g  %12g  %12g  %12g\n", stats->x[i], stats->y[i], stats->dx[i], stats->dy[i]);
-    }
-
-    return estatsOK;
-}
-
-int gmx_stats_remove_outliers(gmx_stats_t gstats, double level)
-{
-    gmx_stats* stats = gstats;
-    int        iter = 1, done = 0, ok;
-    real       rmsd, r;
-
-    while ((stats->np >= 10) && !done)
-    {
-        if ((ok = gmx_stats_get_rmsd(gstats, &rmsd)) != estatsOK)
-        {
-            return ok;
-        }
-        done = 1;
-        for (int i = 0; (i < stats->np);)
-        {
-            r = std::abs(stats->x[i] - stats->y[i]);
-            if (r > level * rmsd)
-            {
-                fprintf(stderr, "Removing outlier, iter = %d, rmsd = %g, x = %g, y = %g\n", iter,
-                        rmsd, stats->x[i], stats->y[i]);
-                if (i < stats->np - 1)
-                {
-                    stats->x[i]  = stats->x[stats->np - 1];
-                    stats->y[i]  = stats->y[stats->np - 1];
-                    stats->dx[i] = stats->dx[stats->np - 1];
-                    stats->dy[i] = stats->dy[stats->np - 1];
-                }
-                stats->np--;
-                done = 0;
-            }
-            else
-            {
-                i++;
-            }
-        }
-        iter++;
-    }
-
-    return estatsOK;
-}
-
-int gmx_stats_make_histogram(gmx_stats_t gstats, real binwidth, int* nb, int ehisto, int normalized, real** x, real** y)
-{
-    gmx_stats* stats = gstats;
-    int        index = 0, nbins = *nb, *nindex;
-    double     minx, maxx, maxy, miny, delta, dd, minh;
-
-    if (((binwidth <= 0) && (nbins <= 0)) || ((binwidth > 0) && (nbins > 0)))
-    {
-        return estatsINVALID_INPUT;
-    }
-    if (stats->np <= 2)
-    {
-        return estatsNO_POINTS;
-    }
-    minx = maxx = stats->x[0];
-    miny = maxy = stats->y[0];
-    for (int i = 1; (i < stats->np); i++)
-    {
-        miny = (stats->y[i] < miny) ? stats->y[i] : miny;
-        maxy = (stats->y[i] > maxy) ? stats->y[i] : maxy;
-        minx = (stats->x[i] < minx) ? stats->x[i] : minx;
-        maxx = (stats->x[i] > maxx) ? stats->x[i] : maxx;
-    }
-    if (ehisto == ehistoX)
-    {
-        delta = maxx - minx;
-        minh  = minx;
-    }
-    else if (ehisto == ehistoY)
-    {
-        delta = maxy - miny;
-        minh  = miny;
-    }
-    else
-    {
-        return estatsINVALID_INPUT;
-    }
-
-    if (binwidth == 0)
-    {
-        binwidth = (delta) / nbins;
-    }
-    else
-    {
-        nbins = gmx_dnint((delta) / binwidth + 0.5);
-    }
-    snew(*x, nbins);
-    snew(nindex, nbins);
-    for (int i = 0; (i < nbins); i++)
-    {
-        (*x)[i] = minh + binwidth * (i + 0.5);
-    }
-    if (normalized == 0)
-    {
-        dd = 1;
-    }
-    else
-    {
-        dd = 1.0 / (binwidth * stats->np);
-    }
-
-    snew(*y, nbins);
-    for (int i = 0; (i < stats->np); i++)
-    {
-        if (ehisto == ehistoY)
-        {
-            index = static_cast<int>((stats->y[i] - miny) / binwidth);
-        }
-        else if (ehisto == ehistoX)
-        {
-            index = static_cast<int>((stats->x[i] - minx) / binwidth);
-        }
-        if (index < 0)
-        {
-            index = 0;
-        }
-        if (index > nbins - 1)
-        {
-            index = nbins - 1;
-        }
-        (*y)[index] += dd;
-        nindex[index]++;
-    }
-    if (*nb == 0)
-    {
-        *nb = nbins;
-    }
-    for (int i = 0; (i < nbins); i++)
-    {
-        if (nindex[i] > 0)
-        {
-            (*y)[i] /= nindex[i];
-        }
-    }
-
-    sfree(nindex);
-
-    return estatsOK;
+    return StatisticsStatus::Ok;
 }
 
-static const char* stats_error[estatsNR] = { "All well in STATS land", "No points",
-                                             "Not enough memory",      "Invalid histogram input",
-                                             "Unknown error",          "Not implemented yet" };
-
-const char* gmx_stats_message(int estats)
+static const char* enumValueToString(StatisticsStatus enumValue)
 {
-    if ((estats >= 0) && (estats < estatsNR))
-    {
-        return stats_error[estats];
-    }
-    else
-    {
-        return stats_error[estatsERROR];
-    }
+    constexpr gmx::EnumerationArray<StatisticsStatus, const char*> statisticsStatusNames = {
+        "All well in STATS land",  "No points",     "Not enough memory",
+        "Invalid histogram input", "Unknown error", "Not implemented yet"
+    };
+    return statisticsStatusNames[enumValue];
 }
 
-/* Old convenience functions, should be merged with the core
-   statistics above. */
-int lsq_y_ax(int n, real x[], real y[], real* a)
+void gmx_stats_message([[maybe_unused]] StatisticsStatus estats)
 {
-    gmx_stats_t lsq = gmx_stats_init();
-    int         ok;
-    real        da, chi2, Rfit;
-
-    gmx_stats_add_points(lsq, n, x, y, nullptr, nullptr);
-    ok = gmx_stats_get_a(lsq, elsqWEIGHT_NONE, a, &da, &chi2, &Rfit);
-    gmx_stats_free(lsq);
-
-    return ok;
+    GMX_ASSERT(estats == StatisticsStatus::Ok, enumValueToString(estats));
 }
 
-static int low_lsq_y_ax_b(int n, const real* xr, const double* xd, real yr[], real* a, real* b, real* r, real* chi2)
+static StatisticsStatus
+low_lsq_y_ax_b(int n, const real* xr, const double* xd, real yr[], real* a, real* b, real* r, real* chi2)
 {
-    gmx_stats_t lsq = gmx_stats_init();
-    int         ok;
+    gmx_stats_t      lsq = gmx_stats_init();
+    StatisticsStatus ok;
 
     for (int i = 0; (i < n); i++)
     {
@@ -690,7 +360,7 @@ static int low_lsq_y_ax_b(int n, const real* xr, const double* xd, real yr[], re
             gmx_incons("Either xd or xr has to be non-NULL in low_lsq_y_ax_b()");
         }
 
-        if ((ok = gmx_stats_add_point(lsq, pt, yr[i], 0, 0)) != estatsOK)
+        if ((ok = gmx_stats_add_point(lsq, pt, yr[i], 0, 0)) != StatisticsStatus::Ok)
         {
             gmx_stats_free(lsq);
             return ok;
@@ -702,25 +372,26 @@ static int low_lsq_y_ax_b(int n, const real* xr, const double* xd, real yr[], re
     return ok;
 }
 
-int lsq_y_ax_b(int n, real x[], real y[], real* a, real* b, real* r, real* chi2)
+StatisticsStatus lsq_y_ax_b(int n, real x[], real y[], real* a, real* b, real* r, real* chi2)
 {
     return low_lsq_y_ax_b(n, x, nullptr, y, a, b, r, chi2);
 }
 
-int lsq_y_ax_b_xdouble(int n, double x[], real y[], real* a, real* b, real* r, real* chi2)
+StatisticsStatus lsq_y_ax_b_xdouble(int n, double x[], real y[], real* a, real* b, real* r, real* chi2)
 {
     return low_lsq_y_ax_b(n, nullptr, x, y, a, b, r, chi2);
 }
 
-int lsq_y_ax_b_error(int n, real x[], real y[], real dy[], real* a, real* b, real* da, real* db, real* r, real* chi2)
+StatisticsStatus
+lsq_y_ax_b_error(int n, real x[], real y[], real dy[], real* a, real* b, real* da, real* db, real* r, real* chi2)
 {
-    gmx_stats_t lsq = gmx_stats_init();
-    int         ok;
+    gmx_stats_t      lsq = gmx_stats_init();
+    StatisticsStatus ok;
 
     for (int i = 0; (i < n); i++)
     {
         ok = gmx_stats_add_point(lsq, x[i], y[i], 0, dy[i]);
-        if (ok != estatsOK)
+        if (ok != StatisticsStatus::Ok)
         {
             gmx_stats_free(lsq);
             return ok;
index 818bdf317ae14ca2358b479c4d0f416d8643e3ef..bfe0354af94d9b3c1319ecabf2db072997f15d59 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) 2010,2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2015,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 typedef struct gmx_stats* gmx_stats_t;
 
 //! Error codes returned by the routines
-enum
+enum class StatisticsStatus : int
 {
-    estatsOK,
-    estatsNO_POINTS,
-    estatsNO_MEMORY,
-    estatsERROR,
-    estatsINVALID_INPUT,
-    estatsNOT_IMPLEMENTED,
-    estatsNR
+    Ok,
+    NoPoints,
+    NoMemory,
+    Error,
+    InvalidInput,
+    NotImplemented,
+    Count
 };
 
 //! Enum for statistical weights
@@ -73,14 +73,6 @@ enum
     elsqWEIGHT_NR
 };
 
-//! Enum determining which coordinate to histogram
-enum
-{
-    ehistoX,
-    ehistoY,
-    ehistoNR
-};
-
 /*! \brief
  * Initiate a data structure
  * \return the data structure
@@ -93,15 +85,6 @@ gmx_stats_t gmx_stats_init();
  */
 void gmx_stats_free(gmx_stats_t stats);
 
-/*! \brief
- * Remove outliers from a straight line, where level in units of
- * sigma. Level needs to be larger than one obviously.
- * \param[in] stats The data structure
- * \param[in] level The sigma level
- * \return error code
- */
-int gmx_stats_remove_outliers(gmx_stats_t stats, double level);
-
 /*! \brief
  * Add a point to the data set
  * \param[in] stats The data structure
@@ -111,42 +94,7 @@ int gmx_stats_remove_outliers(gmx_stats_t stats, double level);
  * \param[in] dy  The error in the y value
  * \return error code
  */
-int gmx_stats_add_point(gmx_stats_t stats, double x, double y, double dx, double dy);
-
-/*! \brief
- * Add a series of datapoints at once. The arrays dx and dy may
- * be NULL in that case zero uncertainties will be assumed.
- *
- * \param[in] stats The data structure
- * \param[in] n   Number of points
- * \param[in] x   The array of x values
- * \param[in] y   The array of y values
- * \param[in] dx  The error in the x value
- * \param[in] dy  The error in the y value
- * \return error code
- */
-int gmx_stats_add_points(gmx_stats_t stats, int n, real* x, real* y, real* dx, real* dy);
-
-/*! \brief
- * Delivers data points from the statistics.
- *
- * Should be used in a while loop. Variables for either
- * pointer may be NULL, in which case the routine can be used as an
- * expensive point counter.
- * Return the data points one by one. Return estatsOK while there are
- *  more points, and returns estatsNOPOINTS when the last point has
- *  been returned.
- *  If level > 0 then the outliers outside level*sigma are reported
- * only.
- * \param[in] stats The data structure
- * \param[out] x   The array of x values
- * \param[out] y   The array of y values
- * \param[out] dx  The error in the x value
- * \param[out] dy  The error in the y value
- * \param[in]  level sigma level (see above)
- * \return error code
- */
-int gmx_stats_get_point(gmx_stats_t stats, real* x, real* y, real* dx, real* dy, real level);
+StatisticsStatus gmx_stats_add_point(gmx_stats_t stats, double x, double y, double dx, double dy);
 
 /*! \brief
  * Fit the data to y = ax + b, possibly weighted, if uncertainties
@@ -161,44 +109,8 @@ int gmx_stats_get_point(gmx_stats_t stats, real* x, real* y, real* dx, real* dy,
  * \param[out] Rfit correlation coefficient
  * \return error code
  */
-int gmx_stats_get_ab(gmx_stats_t stats, int weight, real* a, real* b, real* da, real* db, real* chi2, real* Rfit);
-
-/*! \brief
- * Fit the data to y = ax, possibly weighted, if uncertainties have
- * have been input. da and db may be NULL.
- * \param[in] stats The data structure
- * \param[in] weight type of weighting
- * \param[out] a slope
- * \param[out] da sigma in a
- * \param[out] chi2 normalized quality of fit
- * \param[out] Rfit correlation coefficient
- * \return error code
- */
-int gmx_stats_get_a(gmx_stats_t stats, int weight, real* a, real* da, real* chi2, real* Rfit);
-
-/*! \brief
- * Get the correlation coefficient.
- * \param[in]  stats The data structure
- * \param[out] R the correlation coefficient between the data (x and y) as input to the structure.
- * \return error code
- */
-int gmx_stats_get_corr_coeff(gmx_stats_t stats, real* R);
-
-/*! \brief
- * Get the root mean square deviation.
- * \param[in]  stats The data structure
- * \param[out] rmsd  the root mean square deviation between x and y values.
- * \return error code
- */
-int gmx_stats_get_rmsd(gmx_stats_t stats, real* rmsd);
-
-/*! \brief
- * Get the number of points.
- * \param[in]  stats The data structure
- * \param[out] N     number of data points
- * \return error code
- */
-int gmx_stats_get_npoints(gmx_stats_t stats, int* N);
+StatisticsStatus
+gmx_stats_get_ab(gmx_stats_t stats, int weight, real* a, real* b, real* da, real* db, real* chi2, real* Rfit);
 
 /*! \brief
  * Computes and returns the average value.
@@ -206,23 +118,7 @@ int gmx_stats_get_npoints(gmx_stats_t stats, int* N);
  * \param[out] aver  Average value
  * \return error code
  */
-int gmx_stats_get_average(gmx_stats_t stats, real* aver);
-
-/*! \brief
- * Computes and returns the standard deviation.
- * \param[in]  stats The data structure
- * \param[out] sigma  Standard deviation
- * \return error code
- */
-int gmx_stats_get_sigma(gmx_stats_t stats, real* sigma);
-
-/*! \brief
- * Computes and returns the standard error.
- * \param[in]  stats The data structure
- * \param[out] error Standard error
- * \return error code
- */
-int gmx_stats_get_error(gmx_stats_t stats, real* error);
+StatisticsStatus gmx_stats_get_average(gmx_stats_t stats, real* aver);
 
 /*! \brief
  * Pointers may be null, in which case no assignment will be done.
@@ -232,65 +128,18 @@ int gmx_stats_get_error(gmx_stats_t stats, real* error);
  * \param[out] error Standard error
  * \return error code
  */
-int gmx_stats_get_ase(gmx_stats_t stats, real* aver, real* sigma, real* error);
-
-/*! \brief
- * Dump the x, y, dx, dy data to a text file
- * \param[in]  stats The data structure
- * \param[in] fp  File pointer
- * \return error code
- */
-int gmx_stats_dump_xy(gmx_stats_t stats, FILE* fp);
+StatisticsStatus gmx_stats_get_ase(gmx_stats_t stats, real* aver, real* sigma, real* error);
 
-/*! \brief
- * Make a histogram of the data present.
+/*! \brief Assert that statistics are OK
  *
- * Uses either binwidth to
- * determine the number of bins, or nbins to determine the binwidth,
- * therefore one of these should be zero, but not the other. If *nbins = 0
- * the number of bins will be returned in this variable. ehisto should be one of
- * ehistoX or ehistoY. If
- * normalized not equal to zero, the integral of the histogram will be
- * normalized to one. The output is in two arrays, *x and *y, to which
- * you should pass a pointer. Memory for the arrays will be allocated
- * as needed. Function returns one of the estats codes.
- * \param[in]  stats The data structure
- * \param[in] binwidth For the histogram
- * \param[in] nbins    Number of bins
- * \param[in] ehisto   Type (see enum above)
- * \param[in] normalized see above
- * \param[out] x see above
- * \param[out] y see above
- * \return error code
- */
-int gmx_stats_make_histogram(gmx_stats_t stats,
-                             real        binwidth,
-                             int*        nbins,
-                             int         ehisto,
-                             int         normalized,
-                             real**      x,
-                             real**      y);
-
-/*! \brief
- * Return message belonging to error code
  * \param[in] estats error code
  */
-const char* gmx_stats_message(int estats);
+void gmx_stats_message([[maybe_unused]] StatisticsStatus estats);
 
 /****************************************************
  * Some statistics utilities for convenience: useful when a complete data
  * set is available already from another source, e.g. an xvg file.
  ****************************************************/
-/*! \brief
- * Fit a straight line y=ax thru the n data points x, y, return the
- * slope in *a.
- * \param[in] n number of points
- * \param[in] x data points x
- * \param[in] y data point y
- * \param[out] a slope
- * \return error code
- */
-int lsq_y_ax(int n, real x[], real y[], real* a);
 
 /*! \brief
  * Fit a straight line y=ax+b thru the n data points x, y.
@@ -303,11 +152,11 @@ int lsq_y_ax(int n, real x[], real y[], real* a);
  * \param[out] chi2 quality of fit
  * \return error code
  */
-int lsq_y_ax_b(int n, real x[], real y[], real* a, real* b, real* r, real* chi2);
+StatisticsStatus lsq_y_ax_b(int n, real x[], real y[], real* a, real* b, real* r, real* chi2);
 
 /*! \copydoc lsq_y_ax_b
  */
-int lsq_y_ax_b_xdouble(int n, double x[], real y[], real* a, real* b, real* r, real* chi2);
+StatisticsStatus lsq_y_ax_b_xdouble(int n, double x[], real y[], real* a, real* b, real* r, real* chi2);
 
 /*! \brief
  * Fit a straight line y=ax+b thru the n data points x, y.
@@ -323,6 +172,7 @@ int lsq_y_ax_b_xdouble(int n, double x[], real y[], real* a, real* b, real* r, r
  * \param[out] chi2 quality of fit
  * \return error code
  */
-int lsq_y_ax_b_error(int n, real x[], real y[], real dy[], real* a, real* b, real* da, real* db, real* r, real* chi2);
+StatisticsStatus
+lsq_y_ax_b_error(int n, real x[], real y[], real dy[], real* a, real* b, real* da, real* db, real* r, real* chi2);
 
 #endif
index 8ebac9a96cd7136be475c54eb55ca9b6aa1a206a..eb7dea6d04523dd885ca0f85c49486cd6deb42bb 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,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(swap INTERFACE)
 file(GLOB SWAP_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${SWAP_SOURCES} PARENT_SCOPE)
 
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(swap PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(swap PUBLIC
+target_include_directories(swap INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(swap PUBLIC
+target_link_libraries(swap INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when swap is an OBJECT target
+#target_link_libraries(swap PUBLIC legacy_api)
+#target_link_libraries(swap PRIVATE common)
+
+# Module dependencies
+# swap interfaces convey transitive dependence on these modules.
+#target_link_libraries(swap PUBLIC
+target_link_libraries(swap INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(swap PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(swap PRIVATE legacy_modules)
index e6debca14eacd2f66ac809f715bf0b334961f9d0..947218eed179aee71a2be6a6bafb5596d0682bdc 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "gmxpre.h"
 
+#include "gromacs/utility/enumerationhelpers.h"
 #include "swapcoords.h"
 
 #include <cstdio>
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/snprintf.h"
 
-static const char* SwS      = { "SWAP:" }; /**< For output that comes from the swap module */
-static const char* SwSEmpty = { "     " }; /**< Placeholder for multi-line output */
-static const char* CompStr[eCompNR]          = { "A", "B" }; /**< Compartment name */
-static const char* SwapStr[eSwapTypesNR + 1] = { "", "X-", "Y-", "Z-",
-                                                 nullptr };      /**< Name for the swap types. */
-static const char* DimStr[DIM + 1] = { "X", "Y", "Z", nullptr }; /**< Name for the swap dimension. */
+static const std::string SwS      = { "SWAP:" }; /**< For output that comes from the swap module */
+static const std::string SwSEmpty = { "     " }; /**< Placeholder for multi-line output */
+static constexpr gmx::EnumerationArray<Compartment, const char*> CompStr = { "A", "B" }; /**< Compartment name */
+static constexpr gmx::EnumerationArray<SwapType, const char*> SwapStr = { "", "X-", "Y-", "Z-" }; /**< Name for the swap types. */
+static const char* const DimStr[DIM + 1] = { "X", "Y", "Z", nullptr }; /**< Name for the swap dimension. */
 
 /** Keep track of through which channel the ions have passed */
-enum eChannelHistory
+enum class ChannelHistory : int
 {
-    eChHistPassedNone,
-    eChHistPassedCh0,
-    eChHistPassedCh1,
-    eChHistNr
+    None,
+    Ch0,
+    Ch1,
+    Count
 };
-static const char* ChannelString[eChHistNr] = { "none", "channel0", "channel1" }; /**< Name for the channels */
+static constexpr gmx::EnumerationArray<ChannelHistory, const char*> ChannelString = { "none",
+                                                                                      "channel0",
+                                                                                      "channel1" }; /**< Name for the channels */
 
 /*! \brief Domain identifier.
  *
  * Keeps track of from which compartment the ions came before passing the
  * channel.
  */
-enum eDomain
+enum class Domain : int
 {
-    eDomainNotset,
-    eDomainA,
-    eDomainB,
-    eDomainNr
+    Notset,
+    A,
+    B,
+    Count
 };
-static const char* DomainString[eDomainNr] = { "not_assigned", "Domain_A",
-                                               "Domain_B" }; /**< Name for the domains */
+static constexpr gmx::EnumerationArray<Domain, const char*> DomainString = { "not_assigned",
+                                                                             "Domain_A",
+                                                                             "Domain_B" }; /**< Name for the domains */
 
 namespace gmx
 {
@@ -126,8 +129,8 @@ class SwapCoordinates final : public IMDModule
     IMdpOptionProvider* mdpOptionProvider() override { return nullptr; }
     IMDOutputProvider*  outputProvider() override { return nullptr; }
     void                initForceProviders(ForceProviders* /* forceProviders */) override {}
-    void subscribeToSimulationSetupNotifications(MdModulesNotifier* /* notifier */) override {}
-    void subscribeToPreProcessingNotifications(MdModulesNotifier* /* notifier */) override {}
+    void subscribeToSimulationSetupNotifications(MDModulesNotifiers* /* notifiers */) override {}
+    void subscribeToPreProcessingNotifications(MDModulesNotifiers* /* notifiers */) override {}
 };
 
 std::unique_ptr<IMDModule> createSwapCoordinatesModule()
@@ -173,25 +176,25 @@ typedef struct swap_group
     int   apm     = 0;              /**< Number of atoms in each molecule                      */
     gmx::LocalAtomSet atomset;      /**< The atom indices in the swap group                    */
     rvec*             xc = nullptr; /**< Collective array of group atom positions (size nat)   */
-    ivec* xc_shifts      = nullptr; /**< Current (collective) shifts (size nat)                */
-    ivec* xc_eshifts     = nullptr; /**< Extra shifts since last DD step (size nat)            */
-    rvec* xc_old         = nullptr; /**< Old (collective) positions (size nat)                 */
-    real  q              = 0.;      /**< Total charge of one molecule of this group            */
-    real* m              = nullptr; /**< Masses (can be omitted, size apm)                     */
-    unsigned char* comp_from = nullptr; /**< (Collective) Stores from which compartment this
-                                           molecule has come. This way we keep track of
-                                           through which channel an ion permeates
-                                           (size nMol = nat/apm)                                 */
-    unsigned char* comp_now = nullptr; /**< In which compartment this ion is now (size nMol)      */
-    unsigned char* channel_label = nullptr; /**< Which channel was passed at last by this ion?
+    ivec*   xc_shifts    = nullptr; /**< Current (collective) shifts (size nat)                */
+    ivec*   xc_eshifts   = nullptr; /**< Extra shifts since last DD step (size nat)            */
+    rvec*   xc_old       = nullptr; /**< Old (collective) positions (size nat)                 */
+    real    q            = 0.;      /**< Total charge of one molecule of this group            */
+    real*   m            = nullptr; /**< Masses (can be omitted, size apm)                     */
+    Domain* comp_from    = nullptr; /**< (Collective) Stores from which compartment this
+                                              molecule has come. This way we keep track of
+                                              through which channel an ion permeates
+                                              (size nMol = nat/apm)                                 */
+    Domain* comp_now = nullptr;     /**< In which compartment this ion is now (size nMol)      */
+    ChannelHistory* channel_label = nullptr; /**< Which channel was passed at last by this ion?
                                                (size nMol) */
-    rvec          center;        /**< Center of the group; COM if masses are used           */
-    t_compartment comp[eCompNR]; /**< Distribution of particles of this group across
-                                       the two compartments                                 */
-    real vacancy[eCompNR];       /**< How many molecules need to be swapped in?             */
-    int  fluxfromAtoB[eChanNR];  /**< Net flux of ions per channel                          */
-    int  nCyl[eChanNR];          /**< Number of ions residing in a channel                  */
-    int  nCylBoth = 0;           /**< Ions assigned to cyl0 and cyl1. Not good.             */
+    rvec center; /**< Center of the group; COM if masses are used           */
+    gmx::EnumerationArray<Compartment, t_compartment> comp; /**< Distribution of particles of this
+                                       group across the two compartments */
+    gmx::EnumerationArray<Compartment, real> vacancy; /**< How many molecules need to be swapped in? */
+    gmx::EnumerationArray<Channel, int> fluxfromAtoB; /**< Net flux of ions per channel */
+    gmx::EnumerationArray<Channel, int> nCyl; /**< Number of ions residing in a channel         */
+    int nCylBoth = 0; /**< Ions assigned to cyl0 and cyl1. Not good.             */
 } t_swapgrp;
 
 t_swapgrp::swap_group(const gmx::LocalAtomSet& atomset) : atomset{ atomset }
@@ -199,12 +202,12 @@ t_swapgrp::swap_group(const gmx::LocalAtomSet& atomset) : atomset{ atomset }
     center[0] = 0;
     center[1] = 0;
     center[2] = 0;
-    for (int compartment = eCompA; compartment < eCompNR; ++compartment)
+    for (auto compartment : keysOf(comp))
     {
         comp[compartment]    = {};
         vacancy[compartment] = 0;
     }
-    for (int channel = eChan0; channel < eChanNR; ++channel)
+    for (auto channel : keysOf(fluxfromAtoB))
     {
         fluxfromAtoB[channel] = 0;
         nCyl[channel]         = 0;
@@ -294,9 +297,9 @@ static void print_ionlist(t_swap* s, double time, const char comment[])
 
     // Output number of molecules and difference to reference counts for each
     // compartment and ion type
-    for (int iComp = 0; iComp < eCompNR; iComp++)
+    for (auto iComp : gmx::EnumerationWrapper<Compartment>{})
     {
-        for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+        for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
         {
             t_compartment* comp = &s->group[ig].comp[iComp];
 
@@ -305,13 +308,15 @@ static void print_ionlist(t_swap* s, double time, const char comment[])
     }
 
     // Output center of split groups
-    fprintf(s->fpout, "%10g%10g", s->group[eGrpSplit0].center[s->swapdim],
-            s->group[eGrpSplit1].center[s->swapdim]);
+    fprintf(s->fpout,
+            "%10g%10g",
+            s->group[static_cast<int>(SwapGroupSplittingType::Split0)].center[s->swapdim],
+            s->group[static_cast<int>(SwapGroupSplittingType::Split1)].center[s->swapdim]);
 
     // Output ion flux for each channel and ion type
-    for (int iChan = 0; iChan < eChanNR; iChan++)
+    for (auto iChan : gmx::EnumerationWrapper<Channel>{})
     {
-        for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+        for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
         {
             t_swapgrp* g = &s->group[ig];
             fprintf(s->fpout, "%10d", g->fluxfromAtoB[iChan]);
@@ -485,19 +490,19 @@ static void add_to_list(int ci, t_compartment* comp, real distance)
 
 
 /*! \brief Determine the compartment boundaries from the channel centers. */
-static void get_compartment_boundaries(int c, t_swap* s, const matrix box, real* left, real* right)
+static void get_compartment_boundaries(Compartment c, t_swap* s, const matrix box, real* left, real* right)
 {
     real pos0, pos1;
     real leftpos, rightpos, leftpos_orig;
 
 
-    if (c >= eCompNR)
+    if (c >= Compartment::Count)
     {
-        gmx_fatal(FARGS, "No compartment %c.", c + 'A');
+        gmx_fatal(FARGS, "Compartment out of range");
     }
 
-    pos0 = s->group[eGrpSplit0].center[s->swapdim];
-    pos1 = s->group[eGrpSplit1].center[s->swapdim];
+    pos0 = s->group[static_cast<int>(SwapGroupSplittingType::Split0)].center[s->swapdim];
+    pos1 = s->group[static_cast<int>(SwapGroupSplittingType::Split1)].center[s->swapdim];
 
     if (pos0 < pos1)
     {
@@ -511,7 +516,7 @@ static void get_compartment_boundaries(int c, t_swap* s, const matrix box, real*
     }
 
     /* This gets us the other compartment: */
-    if (c == eCompB)
+    if (c == Compartment::B)
     {
         leftpos_orig = leftpos;
         leftpos      = rightpos;
@@ -546,20 +551,20 @@ static void get_compartment_boundaries(int c, t_swap* s, const matrix box, real*
  *
  * \endcode
  */
-static void detect_flux_per_channel(t_swapgrp*     g,
-                                    int            iAtom,
-                                    int            comp,
-                                    rvec           atomPosition,
-                                    unsigned char* comp_now,
-                                    unsigned char* comp_from,
-                                    unsigned char* channel_label,
-                                    t_swapcoords*  sc,
-                                    t_swap*        s,
-                                    real           cyl0_r2,
-                                    real           cyl1_r2,
-                                    int64_t        step,
-                                    gmx_bool       bRerun,
-                                    FILE*          fpout)
+static void detect_flux_per_channel(t_swapgrp*          g,
+                                    int                 iAtom,
+                                    Compartment         comp,
+                                    rvec                atomPosition,
+                                    Domain*             comp_now,
+                                    Domain*             comp_from,
+                                    ChannelHistory*     channel_label,
+                                    const t_swapcoords* sc,
+                                    t_swap*             s,
+                                    real                cyl0_r2,
+                                    real                cyl1_r2,
+                                    int64_t             step,
+                                    gmx_bool            bRerun,
+                                    FILE*               fpout)
 {
     int      sd, chan_nr;
     gmx_bool in_cyl0, in_cyl1;
@@ -569,66 +574,80 @@ static void detect_flux_per_channel(t_swapgrp*     g,
     sd = s->swapdim;
 
     /* Check whether ion is inside any of the channels */
-    in_cyl0 = is_in_channel(atomPosition, s->group[eGrpSplit0].center, sc->cyl0u, sc->cyl0l,
-                            cyl0_r2, s->pbc, sd);
-    in_cyl1 = is_in_channel(atomPosition, s->group[eGrpSplit1].center, sc->cyl1u, sc->cyl1l,
-                            cyl1_r2, s->pbc, sd);
+    in_cyl0 = is_in_channel(atomPosition,
+                            s->group[static_cast<int>(SwapGroupSplittingType::Split0)].center,
+                            sc->cyl0u,
+                            sc->cyl0l,
+                            cyl0_r2,
+                            s->pbc,
+                            sd);
+    in_cyl1 = is_in_channel(atomPosition,
+                            s->group[static_cast<int>(SwapGroupSplittingType::Split1)].center,
+                            sc->cyl1u,
+                            sc->cyl1l,
+                            cyl1_r2,
+                            s->pbc,
+                            sd);
 
     if (in_cyl0 && in_cyl1)
     {
         /* Ion appears to be in both channels. Something is severely wrong! */
         g->nCylBoth++;
-        *comp_now      = eDomainNotset;
-        *comp_from     = eDomainNotset;
-        *channel_label = eChHistPassedNone;
+        *comp_now      = Domain::Notset;
+        *comp_from     = Domain::Notset;
+        *channel_label = ChannelHistory::None;
     }
     else if (in_cyl0)
     {
         /* Ion is in channel 0 now */
-        *channel_label = eChHistPassedCh0;
-        *comp_now      = eDomainNotset;
-        g->nCyl[eChan0]++;
+        *channel_label = ChannelHistory::Ch0;
+        *comp_now      = Domain::Notset;
+        g->nCyl[Channel::Zero]++;
     }
     else if (in_cyl1)
     {
         /* Ion is in channel 1 now */
-        *channel_label = eChHistPassedCh1;
-        *comp_now      = eDomainNotset;
-        g->nCyl[eChan1]++;
+        *channel_label = ChannelHistory::Ch1;
+        *comp_now      = Domain::Notset;
+        g->nCyl[Channel::One]++;
     }
     else
     {
         /* Ion is not in any of the channels, so it must be in domain A or B */
-        if (eCompA == comp)
+        if (Compartment::A == comp)
         {
-            *comp_now = eDomainA;
+            *comp_now = Domain::A;
         }
         else
         {
-            *comp_now = eDomainB;
+            *comp_now = Domain::B;
         }
     }
 
     /* Only take action, if ion is now in domain A or B, and was before
      * in the other domain!
      */
-    if (eDomainNotset == *comp_from)
+    if (Domain::Notset == *comp_from)
     {
         /* Maybe we can set the domain now */
-        *comp_from = *comp_now; /* Could still be eDomainNotset, though */
+        *comp_from = *comp_now; /* Could still be Domain::Notset, though */
     }
-    else if ((*comp_now != eDomainNotset) /* if in channel */
+    else if ((*comp_now != Domain::Notset) /* if in channel */
              && (*comp_from != *comp_now))
     {
         /* Obviously the ion changed its domain.
          * Count this for the channel through which it has passed. */
         switch (*channel_label)
         {
-            case eChHistPassedNone:
+            case ChannelHistory::None:
                 ++s->fluxleak;
 
-                fprintf(stderr, " %s Warning! Step %s, ion %d moved from %s to %s\n", SwS,
-                        gmx_step_str(step, buf), iAtom, DomainString[*comp_from],
+                fprintf(stderr,
+                        " %s Warning! Step %s, ion %d moved from %s to %s\n",
+                        SwS.c_str(),
+                        gmx_step_str(step, buf),
+                        iAtom,
+                        DomainString[*comp_from],
                         DomainString[*comp_now]);
                 if (bRerun)
                 {
@@ -643,13 +662,15 @@ static void detect_flux_per_channel(t_swapgrp*     g,
                     fprintf(s->fpout,
                             " # Warning: step %s, ion %d moved from %s to %s (probably through the "
                             "membrane)\n",
-                            gmx_step_str(step, buf), iAtom, DomainString[*comp_from],
+                            gmx_step_str(step, buf),
+                            iAtom,
+                            DomainString[*comp_from],
                             DomainString[*comp_now]);
                 }
                 break;
-            case eChHistPassedCh0:
-            case eChHistPassedCh1:
-                if (*channel_label == eChHistPassedCh0)
+            case ChannelHistory::Ch0:
+            case ChannelHistory::Ch1:
+                if (*channel_label == ChannelHistory::Ch0)
                 {
                     chan_nr = 0;
                 }
@@ -658,7 +679,7 @@ static void detect_flux_per_channel(t_swapgrp*     g,
                     chan_nr = 1;
                 }
 
-                if (eDomainA == *comp_from)
+                if (Domain::A == *comp_from)
                 {
                     g->fluxfromAtoB[chan_nr]++;
                 }
@@ -666,40 +687,39 @@ static void detect_flux_per_channel(t_swapgrp*     g,
                 {
                     g->fluxfromAtoB[chan_nr]--;
                 }
-                fprintf(fpout, "# Atom nr. %d finished passing %s.\n", iAtom,
-                        ChannelString[*channel_label]);
+                fprintf(fpout, "# Atom nr. %d finished passing %s.\n", iAtom, ChannelString[*channel_label]);
                 break;
             default:
-                gmx_fatal(FARGS, "%s Unknown channel history entry for ion type '%s'\n", SwS, g->molname);
+                gmx_fatal(FARGS, "%s Unknown channel history entry for ion type '%s'\n", SwS.c_str(), g->molname);
         }
 
         /* This ion has moved to the _other_ compartment ... */
         *comp_from = *comp_now;
         /* ... and it did not pass any channel yet */
-        *channel_label = eChHistPassedNone;
+        *channel_label = ChannelHistory::None;
     }
 }
 
 
 /*! \brief Determines which ions or solvent molecules are in compartment A and B */
-static void sortMoleculesIntoCompartments(t_swapgrp*    g,
-                                          t_commrec*    cr,
-                                          t_swapcoords* sc,
-                                          t_swap*       s,
-                                          const matrix  box,
-                                          int64_t       step,
-                                          FILE*         fpout,
-                                          gmx_bool      bRerun,
-                                          gmx_bool      bIsSolvent)
+static void sortMoleculesIntoCompartments(t_swapgrp*          g,
+                                          t_commrec*          cr,
+                                          const t_swapcoords* sc,
+                                          t_swap*             s,
+                                          const matrix        box,
+                                          int64_t             step,
+                                          FILE*               fpout,
+                                          gmx_bool            bRerun,
+                                          gmx_bool            bIsSolvent)
 {
-    int  nMolNotInComp[eCompNR]; /* consistency check */
-    real cyl0_r2 = sc->cyl0r * sc->cyl0r;
-    real cyl1_r2 = sc->cyl1r * sc->cyl1r;
+    gmx::EnumerationArray<Compartment, int> nMolNotInComp; /* consistency check */
+    real                                    cyl0_r2 = sc->cyl0r * sc->cyl0r;
+    real                                    cyl1_r2 = sc->cyl1r * sc->cyl1r;
 
     /* Get us a counter that cycles in the range of [0 ... sc->nAverage[ */
     int replace = (step / sc->nstswap) % sc->nAverage;
 
-    for (int comp = eCompA; comp <= eCompB; comp++)
+    for (auto comp : gmx::EnumerationWrapper<Compartment>{})
     {
         real left, right;
 
@@ -718,8 +738,8 @@ static void sortMoleculesIntoCompartments(t_swapgrp*    g,
             int  sd = s->swapdim;
 
             /* Is this first atom of the molecule in the compartment that we look at? */
-            if (compartment_contains_atom(left, right, g->xc[iAtom][sd], box[sd][sd],
-                                          sc->bulkOffset[comp], &dist))
+            if (compartment_contains_atom(
+                        left, right, g->xc[iAtom][sd], box[sd][sd], sc->bulkOffset[comp], &dist))
             {
                 /* Add the first atom of this molecule to the list of molecules in this compartment */
                 add_to_list(iAtom, &g->comp[comp], dist);
@@ -728,9 +748,20 @@ static void sortMoleculesIntoCompartments(t_swapgrp*    g,
                 if (MASTER(cr) && (g->comp_now != nullptr) && !bIsSolvent)
                 {
                     int globalAtomNr = g->atomset.globalIndex()[iAtom] + 1; /* PDB index starts at 1 ... */
-                    detect_flux_per_channel(g, globalAtomNr, comp, g->xc[iAtom], &g->comp_now[iMol],
-                                            &g->comp_from[iMol], &g->channel_label[iMol], sc, s,
-                                            cyl0_r2, cyl1_r2, step, bRerun, fpout);
+                    detect_flux_per_channel(g,
+                                            globalAtomNr,
+                                            comp,
+                                            g->xc[iAtom],
+                                            &g->comp_now[iMol],
+                                            &g->comp_from[iMol],
+                                            &g->channel_label[iMol],
+                                            sc,
+                                            s,
+                                            cyl0_r2,
+                                            cyl1_r2,
+                                            step,
+                                            bRerun,
+                                            fpout);
                 }
             }
             else
@@ -756,7 +787,10 @@ static void sortMoleculesIntoCompartments(t_swapgrp*    g,
                     "split\n"
                     "%s          cylinder is way too large, or one compartment has collapsed (step "
                     "%" PRId64 ")\n",
-                    SwS, g->nCylBoth, SwS, step);
+                    SwS.c_str(),
+                    g->nCylBoth,
+                    SwS.c_str(),
+                    step);
 
             fprintf(s->fpout, "Warning: %d atoms were assigned to both channels!\n", g->nCylBoth);
 
@@ -766,27 +800,38 @@ static void sortMoleculesIntoCompartments(t_swapgrp*    g,
 
     if (bIsSolvent && nullptr != fpout)
     {
-        fprintf(fpout, "# Solv. molecules in comp.%s: %d   comp.%s: %d\n", CompStr[eCompA],
-                g->comp[eCompA].nMol, CompStr[eCompB], g->comp[eCompB].nMol);
+        fprintf(fpout,
+                "# Solv. molecules in comp.%s: %d   comp.%s: %d\n",
+                CompStr[Compartment::A],
+                g->comp[Compartment::A].nMol,
+                CompStr[Compartment::B],
+                g->comp[Compartment::B].nMol);
     }
 
     /* Consistency checks */
     const auto numMolecules = static_cast<int>(g->atomset.numAtomsGlobal() / g->apm);
-    if (nMolNotInComp[eCompA] + nMolNotInComp[eCompB] != numMolecules)
+    if (nMolNotInComp[Compartment::A] + nMolNotInComp[Compartment::B] != numMolecules)
     {
         fprintf(stderr,
                 "%s Warning: Inconsistency while assigning '%s' molecules to compartments. !inA: "
                 "%d, !inB: %d, total molecules %d\n",
-                SwS, g->molname, nMolNotInComp[eCompA], nMolNotInComp[eCompB], numMolecules);
+                SwS.c_str(),
+                g->molname,
+                nMolNotInComp[Compartment::A],
+                nMolNotInComp[Compartment::B],
+                numMolecules);
     }
 
-    int sum = g->comp[eCompA].nMol + g->comp[eCompB].nMol;
+    int sum = g->comp[Compartment::A].nMol + g->comp[Compartment::B].nMol;
     if (sum != numMolecules)
     {
         fprintf(stderr,
                 "%s Warning: %d molecules are in group '%s', but altogether %d have been assigned "
                 "to the compartments.\n",
-                SwS, numMolecules, g->molname, sum);
+                SwS.c_str(),
+                numMolecules,
+                g->molname,
+                sum);
     }
 }
 
@@ -805,7 +850,7 @@ static void get_initial_ioncounts(const t_inputrec* ir,
     sc = ir->swap;
 
     /* Loop over the user-defined (ion) groups */
-    for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+    for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
     {
         g = &s->group[ig];
 
@@ -821,7 +866,7 @@ static void get_initial_ioncounts(const t_inputrec* ir,
         sortMoleculesIntoCompartments(g, cr, sc, s, box, 0, s->fpout, bRerun, FALSE);
 
         /* Set initial molecule counts if requested (as signaled by "-1" value) */
-        for (int ic = 0; ic < eCompNR; ic++)
+        for (auto ic : gmx::EnumerationWrapper<Compartment>{})
         {
             int requested = sc->grp[ig].nmolReq[ic];
             if (requested < 0)
@@ -835,8 +880,8 @@ static void get_initial_ioncounts(const t_inputrec* ir,
         }
 
         /* Check whether the number of requested molecules adds up to the total number */
-        int req = g->comp[eCompA].nMolReq + g->comp[eCompB].nMolReq;
-        int tot = g->comp[eCompA].nMol + g->comp[eCompB].nMol;
+        int req = g->comp[Compartment::A].nMolReq + g->comp[Compartment::B].nMolReq;
+        int tot = g->comp[Compartment::A].nMol + g->comp[Compartment::B].nMol;
 
         if ((req != tot))
         {
@@ -844,12 +889,16 @@ static void get_initial_ioncounts(const t_inputrec* ir,
                       "Mismatch of the number of %s ions summed over both compartments.\n"
                       "You requested a total of %d ions (%d in A and %d in B),\n"
                       "but there are a total of %d ions of this type in the system.\n",
-                      g->molname, req, g->comp[eCompA].nMolReq, g->comp[eCompB].nMolReq, tot);
+                      g->molname,
+                      req,
+                      g->comp[Compartment::A].nMolReq,
+                      g->comp[Compartment::B].nMolReq,
+                      tot);
         }
 
         /* Initialize time-averaging:
          * Write initial concentrations to all time bins to start with */
-        for (int ic = 0; ic < eCompNR; ic++)
+        for (auto ic : gmx::EnumerationWrapper<Compartment>{})
         {
             g->comp[ic].nMolAv = g->comp[ic].nMol;
             for (int i = 0; i < sc->nAverage; i++)
@@ -883,23 +932,26 @@ static void get_initial_ioncounts_from_cpt(const t_inputrec* ir,
         /* Copy the past values from the checkpoint values that have been read in already */
         if (bVerbose)
         {
-            fprintf(stderr, "%s Copying values from checkpoint\n", SwS);
+            fprintf(stderr, "%s Copying values from checkpoint\n", SwS.c_str());
         }
 
-        for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+        for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
         {
             g  = &s->group[ig];
-            gs = &swapstate->ionType[ig - eSwapFixedGrpNR];
+            gs = &swapstate->ionType[ig - static_cast<int>(SwapGroupSplittingType::Count)];
 
-            for (int ic = 0; ic < eCompNR; ic++)
+            for (auto ic : gmx::EnumerationWrapper<Compartment>{})
             {
                 g->comp[ic].nMolReq    = gs->nMolReq[ic];
                 g->comp[ic].inflow_net = gs->inflow_net[ic];
 
                 if (bVerbose)
                 {
-                    fprintf(stderr, "%s ... Influx netto: %d   Requested: %d   Past values: ", SwS,
-                            g->comp[ic].inflow_net, g->comp[ic].nMolReq);
+                    fprintf(stderr,
+                            "%s ... Influx netto: %d   Requested: %d   Past values: ",
+                            SwS.c_str(),
+                            g->comp[ic].inflow_net,
+                            g->comp[ic].nMolReq);
                 }
 
                 for (int j = 0; j < sc->nAverage; j++)
@@ -923,20 +975,15 @@ static void get_initial_ioncounts_from_cpt(const t_inputrec* ir,
 /*! \brief The master lets all others know about the initial ion counts. */
 static void bc_initial_concentrations(t_commrec* cr, t_swapcoords* swap, t_swap* s)
 {
-    int        ic, ig;
-    t_swapgrp* g;
-
-
-    for (ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+    for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
     {
-        g = &s->group[ig];
+        t_swapgrp* g = &s->group[ig];
 
-        for (ic = 0; ic < eCompNR; ic++)
+        for (auto ic : gmx::EnumerationWrapper<Compartment>{})
         {
             gmx_bcast(sizeof(g->comp[ic].nMolReq), &(g->comp[ic].nMolReq), cr->mpi_comm_mygroup);
             gmx_bcast(sizeof(g->comp[ic].nMol), &(g->comp[ic].nMol), cr->mpi_comm_mygroup);
-            gmx_bcast(swap->nAverage * sizeof(g->comp[ic].nMolPast[0]), g->comp[ic].nMolPast,
-                      cr->mpi_comm_mygroup);
+            gmx_bcast(swap->nAverage * sizeof(g->comp[ic].nMolPast[0]), g->comp[ic].nMolPast, cr->mpi_comm_mygroup);
         }
     }
 }
@@ -953,7 +1000,7 @@ static void check_swap_groups(t_swap* s, int nat, gmx_bool bVerbose)
 
     if (bVerbose)
     {
-        fprintf(stderr, "%s Making sure each atom belongs to at most one of the swap groups.\n", SwS);
+        fprintf(stderr, "%s Making sure each atom belongs to at most one of the swap groups.\n", SwS.c_str());
     }
 
     /* Add one to the group count of atoms belonging to a swap group: */
@@ -987,7 +1034,11 @@ static void check_swap_groups(t_swap* s, int nat, gmx_bool bVerbose)
                   "groups, or the solvent.\n"
                   "%s Check the .mdp file settings regarding the swap index groups or the index "
                   "groups themselves.\n",
-                  SwS, nMultiple, (1 == nMultiple) ? " is" : "s are", SwSEmpty, SwSEmpty);
+                  SwS.c_str(),
+                  nMultiple,
+                  (1 == nMultiple) ? " is" : "s are",
+                  SwSEmpty.c_str(),
+                  SwSEmpty.c_str());
     }
 }
 
@@ -996,7 +1047,7 @@ static void check_swap_groups(t_swap* s, int nat, gmx_bool bVerbose)
  *
  * Also ensure that all the molecules in this group have this number of atoms.
  */
-static int get_group_apm_check(int igroup, t_swap* s, gmx_bool bVerbose, gmx_mtop_t* mtop)
+static int get_group_apm_check(int igroup, t_swap* s, gmx_bool bVerbose, const gmx_mtop_t& mtop)
 {
     t_swapgrp* g   = &s->group[igroup];
     const int* ind = s->group[igroup].atomset.globalIndex().data();
@@ -1006,19 +1057,23 @@ static int get_group_apm_check(int igroup, t_swap* s, gmx_bool bVerbose, gmx_mto
      * first solvent atom: */
     int molb = 0;
     mtopGetMolblockIndex(mtop, ind[0], &molb, nullptr, nullptr);
-    int apm = mtop->moleculeBlockIndices[molb].numAtomsPerMolecule;
+    int apm = mtop.moleculeBlockIndices[molb].numAtomsPerMolecule;
 
     if (bVerbose)
     {
-        fprintf(stderr, "%s Checking whether all %s molecules consist of %d atom%s\n", SwS,
-                g->molname, apm, apm > 1 ? "s" : "");
+        fprintf(stderr,
+                "%s Checking whether all %s molecules consist of %d atom%s\n",
+                SwS.c_str(),
+                g->molname,
+                apm,
+                apm > 1 ? "s" : "");
     }
 
     /* Check whether this is also true for all other solvent atoms */
     for (int i = 1; i < nat; i++)
     {
         mtopGetMolblockIndex(mtop, ind[i], &molb, nullptr, nullptr);
-        if (apm != mtop->moleculeBlockIndices[molb].numAtomsPerMolecule)
+        if (apm != mtop.moleculeBlockIndices[molb].numAtomsPerMolecule)
         {
             gmx_fatal(FARGS, "Not all molecules of swap group %d consist of %d atoms.", igroup, apm);
         }
@@ -1039,14 +1094,16 @@ static void print_ionlist_legend(const t_inputrec* ir, t_swap* s, const gmx_outp
     int          count = 0;
     char         buf[STRLEN];
 
-    int nIonTypes = ir->swap->ngrp - eSwapFixedGrpNR;
-    snew(legend, eCompNR * nIonTypes * 3 + 2 + eChanNR * nIonTypes + 1);
+    int nIonTypes = ir->swap->ngrp - static_cast<int>(SwapGroupSplittingType::Count);
+    snew(legend,
+         static_cast<int>(Compartment::Count) * nIonTypes * 3 + 2
+                 + static_cast<int>(Channel::Count) * nIonTypes + 1);
 
     // Number of molecules and difference to reference counts for each
     // compartment and ion type
-    for (int ic = count = 0; ic < eCompNR; ic++)
+    for (auto ic : gmx::EnumerationWrapper<Compartment>{})
     {
-        for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+        for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
         {
             t_swapGroup* g = &ir->swap->grp[ig];
             real         q = s->group[ig].q;
@@ -1054,8 +1111,12 @@ static void print_ionlist_legend(const t_inputrec* ir, t_swap* s, const gmx_outp
             snprintf(buf, STRLEN, "%s %s ions (charge %s%g)", CompStr[ic], g->molname, q > 0 ? "+" : "", q);
             legend[count++] = gmx_strdup(buf);
 
-            snprintf(buf, STRLEN, "%s av. mismatch to %d %s ions", CompStr[ic],
-                     s->group[ig].comp[ic].nMolReq, g->molname);
+            snprintf(buf,
+                     STRLEN,
+                     "%s av. mismatch to %d %s ions",
+                     CompStr[ic],
+                     s->group[ig].comp[ic].nMolReq,
+                     g->molname);
             legend[count++] = gmx_strdup(buf);
 
             snprintf(buf, STRLEN, "%s net %s ion influx", CompStr[ic], g->molname);
@@ -1064,20 +1125,26 @@ static void print_ionlist_legend(const t_inputrec* ir, t_swap* s, const gmx_outp
     }
 
     // Center of split groups
-    snprintf(buf, STRLEN, "%scenter of %s of split group 0", SwapStr[ir->eSwapCoords],
-             (nullptr != s->group[eGrpSplit0].m) ? "mass" : "geometry");
+    snprintf(buf,
+             STRLEN,
+             "%scenter of %s of split group 0",
+             SwapStr[ir->eSwapCoords],
+             (nullptr != s->group[static_cast<int>(SwapGroupSplittingType::Split0)].m) ? "mass" : "geometry");
     legend[count++] = gmx_strdup(buf);
-    snprintf(buf, STRLEN, "%scenter of %s of split group 1", SwapStr[ir->eSwapCoords],
-             (nullptr != s->group[eGrpSplit1].m) ? "mass" : "geometry");
+    snprintf(buf,
+             STRLEN,
+             "%scenter of %s of split group 1",
+             SwapStr[ir->eSwapCoords],
+             (nullptr != s->group[static_cast<int>(SwapGroupSplittingType::Split1)].m) ? "mass" : "geometry");
     legend[count++] = gmx_strdup(buf);
 
     // Ion flux for each channel and ion type
-    for (int ic = 0; ic < eChanNR; ic++)
+    for (auto ic : gmx::EnumerationWrapper<Channel>{})
     {
-        for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+        for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
         {
             t_swapGroup* g = &ir->swap->grp[ig];
-            snprintf(buf, STRLEN, "A->ch%d->B %s permeations", ic, g->molname);
+            snprintf(buf, STRLEN, "A->ch%d->B %s permeations", static_cast<int>(ic), g->molname);
             legend[count++] = gmx_strdup(buf);
         }
     }
@@ -1119,10 +1186,10 @@ static void detect_flux_per_channel_init(t_swap* s, swaphistory_t* swapstate, co
         return;
     }
 
-    for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+    for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
     {
         g  = &s->group[ig];
-        gs = &swapstate->ionType[ig - eSwapFixedGrpNR];
+        gs = &swapstate->ionType[ig - static_cast<int>(SwapGroupSplittingType::Count)];
 
         /******************************************************/
         /* Channel and domain history for the individual ions */
@@ -1144,38 +1211,42 @@ static void detect_flux_per_channel_init(t_swap* s, swaphistory_t* swapstate, co
         /* Initialize the channel and domain history counters */
         for (size_t i = 0; i < g->atomset.numAtomsGlobal() / g->apm; i++)
         {
-            g->comp_now[i] = eDomainNotset;
+            g->comp_now[i] = Domain::Notset;
             if (!isRestart)
             {
-                g->comp_from[i]     = eDomainNotset;
-                g->channel_label[i] = eChHistPassedNone;
+                g->comp_from[i]     = Domain::Notset;
+                g->channel_label[i] = ChannelHistory::None;
             }
         }
 
         /************************************/
         /* Channel fluxes for both channels */
         /************************************/
-        g->nCyl[eChan0] = 0;
-        g->nCyl[eChan1] = 0;
-        g->nCylBoth     = 0;
+        g->nCyl[Channel::Zero] = 0;
+        g->nCyl[Channel::One]  = 0;
+        g->nCylBoth            = 0;
     }
 
     if (isRestart)
     {
-        fprintf(stderr, "%s Copying channel fluxes from checkpoint file data\n", SwS);
+        fprintf(stderr, "%s Copying channel fluxes from checkpoint file data\n", SwS.c_str());
     }
 
 
     // Loop over ion types (and both channels)
-    for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+    for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
     {
         g  = &s->group[ig];
-        gs = &swapstate->ionType[ig - eSwapFixedGrpNR];
+        gs = &swapstate->ionType[ig - static_cast<int>(SwapGroupSplittingType::Count)];
 
-        for (int ic = 0; ic < eChanNR; ic++)
+        for (auto ic : gmx::EnumerationWrapper<Channel>{})
         {
-            fprintf(stderr, "%s Channel %d flux history for ion type %s (charge %g): ", SwS, ic,
-                    g->molname, g->q);
+            fprintf(stderr,
+                    "%s Channel %d flux history for ion type %s (charge %g): ",
+                    SwS.c_str(),
+                    static_cast<int>(ic),
+                    g->molname,
+                    g->q);
             if (isRestart)
             {
                 g->fluxfromAtoB[ic] = gs->fluxfromAtoB[ic];
@@ -1192,12 +1263,12 @@ static void detect_flux_per_channel_init(t_swap* s, swaphistory_t* swapstate, co
 
     /* Set pointers for checkpoint writing */
     swapstate->fluxleak_p = &s->fluxleak;
-    for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+    for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
     {
         g  = &s->group[ig];
-        gs = &swapstate->ionType[ig - eSwapFixedGrpNR];
+        gs = &swapstate->ionType[ig - static_cast<int>(SwapGroupSplittingType::Count)];
 
-        for (int ic = 0; ic < eChanNR; ic++)
+        for (auto ic : gmx::EnumerationWrapper<Channel>{})
         {
             gs->fluxfromAtoB_p[ic] = &g->fluxfromAtoB[ic];
         }
@@ -1212,7 +1283,7 @@ static void detect_flux_per_channel_init(t_swap* s, swaphistory_t* swapstate, co
  * If this is not correct, the ion counts per channel will be very likely
  * wrong.
  */
-static void outputStartStructureIfWanted(gmx_mtop_t* mtop, rvec* x, PbcType pbcType, const matrix box)
+static void outputStartStructureIfWanted(const gmx_mtop_t& mtop, rvec* x, PbcType pbcType, const matrix box)
 {
     char* env = getenv("GMX_COMPELDUMP");
 
@@ -1223,10 +1294,11 @@ static void outputStartStructureIfWanted(gmx_mtop_t* mtop, rvec* x, PbcType pbcT
                 "whole.\n"
                 "%s In case of multimeric channels, please check whether they have the correct PBC "
                 "representation.\n",
-                SwS, SwSEmpty);
+                SwS.c_str(),
+                SwSEmpty.c_str());
 
-        write_sto_conf_mtop("CompELAssumedWholeConfiguration.pdb", *mtop->name, mtop, x, nullptr,
-                            pbcType, box);
+        write_sto_conf_mtop(
+                "CompELAssumedWholeConfiguration.pdb", *mtop.name, mtop, x, nullptr, pbcType, box);
     }
 }
 
@@ -1244,7 +1316,7 @@ static void outputStartStructureIfWanted(gmx_mtop_t* mtop, rvec* x, PbcType pbcT
 static void init_swapstate(swaphistory_t*    swapstate,
                            t_swapcoords*     sc,
                            t_swap*           s,
-                           gmx_mtop_t*       mtop,
+                           const gmx_mtop_t& mtop,
                            const rvec*       x, /* the initial positions */
                            const matrix      box,
                            const t_inputrec* ir)
@@ -1258,15 +1330,15 @@ static void init_swapstate(swaphistory_t*    swapstate,
     if (swapstate->bFromCpt)
     {
         /* Copy the last whole positions of each channel from .cpt */
-        g = &(s->group[eGrpSplit0]);
+        g = &(s->group[static_cast<int>(SwapGroupSplittingType::Split0)]);
         for (size_t i = 0; i < g->atomset.numAtomsGlobal(); i++)
         {
-            copy_rvec(swapstate->xc_old_whole[eChan0][i], g->xc_old[i]);
+            copy_rvec(swapstate->xc_old_whole[Channel::Zero][i], g->xc_old[i]);
         }
-        g = &(s->group[eGrpSplit1]);
+        g = &(s->group[static_cast<int>(SwapGroupSplittingType::Split1)]);
         for (size_t i = 0; i < g->atomset.numAtomsGlobal(); i++)
         {
-            copy_rvec(swapstate->xc_old_whole[eChan1][i], g->xc_old[i]);
+            copy_rvec(swapstate->xc_old_whole[Channel::One][i], g->xc_old[i]);
         }
     }
     else
@@ -1274,7 +1346,7 @@ static void init_swapstate(swaphistory_t*    swapstate,
         swapstate->eSwapCoords = ir->eSwapCoords;
 
         /* Set the number of ion types and allocate memory for checkpointing */
-        swapstate->nIonTypes = s->ngrp - eSwapFixedGrpNR;
+        swapstate->nIonTypes = s->ngrp - static_cast<int>(SwapGroupSplittingType::Count);
         snew(swapstate->ionType, swapstate->nIonTypes);
 
         /* Store the total number of ions of each type in the swapstateIons
@@ -1282,24 +1354,26 @@ static void init_swapstate(swaphistory_t*    swapstate,
         for (int ii = 0; ii < swapstate->nIonTypes; ii++)
         {
             swapstateIons_t* gs = &swapstate->ionType[ii];
-            gs->nMol            = sc->grp[ii + eSwapFixedGrpNR].nat;
+            gs->nMol            = sc->grp[ii + static_cast<int>(SwapGroupSplittingType::Count)].nat;
         }
 
         /* Extract the initial split group positions. */
 
         /* Remove pbc, make molecule whole. */
-        snew(x_pbc, mtop->natoms);
-        copy_rvecn(x, x_pbc, 0, mtop->natoms);
+        snew(x_pbc, mtop.natoms);
+        copy_rvecn(x, x_pbc, 0, mtop.natoms);
 
         /* This can only make individual molecules whole, not multimers */
-        do_pbc_mtop(ir->pbcType, box, mtop, x_pbc);
+        do_pbc_mtop(ir->pbcType, box, &mtop, x_pbc);
 
         /* Output the starting structure? */
         outputStartStructureIfWanted(mtop, x_pbc, ir->pbcType, box);
 
         /* If this is the first run (i.e. no checkpoint present) we assume
          * that the starting positions give us the correct PBC representation */
-        for (int ig = eGrpSplit0; ig <= eGrpSplit1; ig++)
+        for (int ig = static_cast<int>(SwapGroupSplittingType::Split0);
+             ig <= static_cast<int>(SwapGroupSplittingType::Split1);
+             ig++)
         {
             g = &(s->group[ig]);
             for (size_t i = 0; i < g->atomset.numAtomsGlobal(); i++)
@@ -1310,37 +1384,38 @@ static void init_swapstate(swaphistory_t*    swapstate,
         sfree(x_pbc);
 
         /* Prepare swapstate arrays for later checkpoint writing */
-        swapstate->nat[eChan0] = s->group[eGrpSplit0].atomset.numAtomsGlobal();
-        swapstate->nat[eChan1] = s->group[eGrpSplit1].atomset.numAtomsGlobal();
+        swapstate->nat[Channel::Zero] =
+                s->group[static_cast<int>(SwapGroupSplittingType::Split0)].atomset.numAtomsGlobal();
+        swapstate->nat[Channel::One] =
+                s->group[static_cast<int>(SwapGroupSplittingType::Split1)].atomset.numAtomsGlobal();
     }
 
     /* For subsequent checkpoint writing, set the swapstate pointers to the xc_old
      * arrays that get updated at every swapping step */
-    swapstate->xc_old_whole_p[eChan0] = &s->group[eGrpSplit0].xc_old;
-    swapstate->xc_old_whole_p[eChan1] = &s->group[eGrpSplit1].xc_old;
+    swapstate->xc_old_whole_p[Channel::Zero] =
+            &s->group[static_cast<int>(SwapGroupSplittingType::Split0)].xc_old;
+    swapstate->xc_old_whole_p[Channel::One] =
+            &s->group[static_cast<int>(SwapGroupSplittingType::Split1)].xc_old;
 }
 
 /*! \brief Determine the total charge imbalance resulting from the swap groups */
 static real getRequestedChargeImbalance(t_swap* s)
 {
-    int        ig;
-    real       DeltaQ = 0.0;
-    t_swapgrp* g;
-    real       particle_charge;
-    real       particle_number[eCompNR];
+    int                                      ig;
+    real                                     DeltaQ = 0.0;
+    t_swapgrp*                               g;
+    real                                     particle_charge;
+    gmx::EnumerationArray<Compartment, real> particle_number;
 
-    //        s->deltaQ =  ( (-1) * s->comp[eCompA][eIonNEG].nat_req + s->comp[eCompA][eIonPOS].nat_req )
-    //                   - ( (-1) * s->comp[eCompB][eIonNEG].nat_req + s->comp[eCompB][eIonPOS].nat_req );
-
-    for (ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+    for (ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
     {
         g = &s->group[ig];
 
-        particle_charge         = g->q;
-        particle_number[eCompA] = g->comp[eCompA].nMolReq;
-        particle_number[eCompB] = g->comp[eCompB].nMolReq;
+        particle_charge                 = g->q;
+        particle_number[Compartment::A] = g->comp[Compartment::A].nMolReq;
+        particle_number[Compartment::B] = g->comp[Compartment::B].nMolReq;
 
-        DeltaQ += particle_charge * (particle_number[eCompA] - particle_number[eCompB]);
+        DeltaQ += particle_charge * (particle_number[Compartment::A] - particle_number[Compartment::B]);
     }
 
     return DeltaQ;
@@ -1359,18 +1434,25 @@ static void copyIndicesToGroup(const int* indIons, int nIons, t_swapGroup* g, t_
     /* If explicit ion counts were requested in the .mdp file
      * (by setting positive values for the number of ions),
      * we can make an additional consistency check here */
-    if ((g->nmolReq[eCompA] < 0) && (g->nmolReq[eCompB] < 0))
+    if ((g->nmolReq[Compartment::A] < 0) && (g->nmolReq[Compartment::B] < 0))
     {
-        if (g->nat != (g->nmolReq[eCompA] + g->nmolReq[eCompB]))
+        if (g->nat != (g->nmolReq[Compartment::A] + g->nmolReq[Compartment::B]))
         {
-            gmx_fatal_collective(FARGS, cr->mpi_comm_mysim, MASTER(cr),
+            gmx_fatal_collective(FARGS,
+                                 cr->mpi_comm_mysim,
+                                 MASTER(cr),
                                  "%s Inconsistency while importing swap-related data from an old "
                                  "input file version.\n"
                                  "%s The requested ion counts in compartments A (%d) and B (%d)\n"
                                  "%s do not add up to the number of ions (%d) of this type for the "
                                  "group '%s'.\n",
-                                 SwS, SwSEmpty, g->nmolReq[eCompA], g->nmolReq[eCompB], SwSEmpty,
-                                 g->nat, g->molname);
+                                 SwS.c_str(),
+                                 SwSEmpty.c_str(),
+                                 g->nmolReq[Compartment::A],
+                                 g->nmolReq[Compartment::B],
+                                 SwSEmpty.c_str(),
+                                 g->nat,
+                                 g->molname);
         }
     }
 
@@ -1395,7 +1477,7 @@ static void copyIndicesToGroup(const int* indIons, int nIons, t_swapGroup* g, t_
  * #4 cations        - empty before conversion
  *
  */
-static void convertOldToNewGroupFormat(t_swapcoords* sc, gmx_mtop_t* mtop, gmx_bool bVerbose, t_commrec* cr)
+static void convertOldToNewGroupFormat(t_swapcoords* sc, const gmx_mtop_t& mtop, gmx_bool bVerbose, t_commrec* cr)
 {
     t_swapGroup* g = &sc->grp[3];
 
@@ -1427,8 +1509,12 @@ static void convertOldToNewGroupFormat(t_swapcoords* sc, gmx_mtop_t* mtop, gmx_b
 
     if (bVerbose)
     {
-        fprintf(stdout, "%s Sorted %d ions into separate groups of %d anions and %d cations.\n",
-                SwS, g->nat, nAnions, nCations);
+        fprintf(stdout,
+                "%s Sorted %d ions into separate groups of %d anions and %d cations.\n",
+                SwS.c_str(),
+                g->nat,
+                nAnions,
+                nCations);
     }
 
 
@@ -1456,7 +1542,7 @@ static gmx_bool bConvertFromOldTpr(t_swapcoords* sc)
 t_swap* init_swapcoords(FILE*                       fplog,
                         const t_inputrec*           ir,
                         const char*                 fn,
-                        gmx_mtop_t*                 mtop,
+                        const gmx_mtop_t&           mtop,
                         const t_state*              globalState,
                         ObservablesHistory*         oh,
                         t_commrec*                  cr,
@@ -1474,8 +1560,8 @@ t_swap* init_swapcoords(FILE*                       fplog,
         gmx_fatal(FARGS, "Position swapping is only implemented for domain decomposition!");
     }
 
-    auto sc = ir->swap;
-    auto s  = new t_swap();
+    auto* sc = ir->swap;
+    auto* s  = new t_swap();
 
     if (mdrunOptions.rerun)
     {
@@ -1484,10 +1570,10 @@ t_swap* init_swapcoords(FILE*                       fplog,
             gmx_fatal(FARGS,
                       "%s This module does not support reruns in parallel\nPlease request a serial "
                       "run with -nt 1 / -np 1\n",
-                      SwS);
+                      SwS.c_str());
         }
 
-        fprintf(stderr, "%s Rerun - using every available frame\n", SwS);
+        fprintf(stderr, "%s Rerun - using every available frame\n", SwS.c_str());
         sc->nstswap  = 1;
         sc->nAverage = 1; /* averaging makes no sense for reruns */
     }
@@ -1500,9 +1586,9 @@ t_swap* init_swapcoords(FILE*                       fplog,
 
     switch (ir->eSwapCoords)
     {
-        case eswapX: s->swapdim = XX; break;
-        case eswapY: s->swapdim = YY; break;
-        case eswapZ: s->swapdim = ZZ; break;
+        case SwapType::X: s->swapdim = XX; break;
+        case SwapType::Y: s->swapdim = YY; break;
+        case SwapType::Z: s->swapdim = ZZ; break;
         default: s->swapdim = -1; break;
     }
 
@@ -1525,7 +1611,7 @@ t_swap* init_swapcoords(FILE*                       fplog,
     }
 
     /* Check for overlapping atoms */
-    check_swap_groups(s, mtop->natoms, bVerbose && MASTER(cr));
+    check_swap_groups(s, mtop.natoms, bVerbose && MASTER(cr));
 
     /* Allocate space for the collective arrays for all groups */
     /* For the collective position array */
@@ -1537,7 +1623,8 @@ t_swap* init_swapcoords(FILE*                       fplog,
         /* For the split groups (the channels) we need some extra memory to
          * be able to make the molecules whole even if they span more than
          * half of the box size. */
-        if ((i == eGrpSplit0) || (i == eGrpSplit1))
+        if ((i == static_cast<int>(SwapGroupSplittingType::Split0))
+            || (i == static_cast<int>(SwapGroupSplittingType::Split1)))
         {
             snew(g->xc_shifts, g->atomset.numAtomsGlobal());
             snew(g->xc_eshifts, g->atomset.numAtomsGlobal());
@@ -1560,17 +1647,18 @@ t_swap* init_swapcoords(FILE*                       fplog,
      * channels. Now transfer that to all nodes */
     if (PAR(cr))
     {
-        for (int ig = eGrpSplit0; ig <= eGrpSplit1; ig++)
+        for (int ig = static_cast<int>(SwapGroupSplittingType::Split0);
+             ig <= static_cast<int>(SwapGroupSplittingType::Split1);
+             ig++)
         {
             g = &(s->group[ig]);
-            gmx_bcast((g->atomset.numAtomsGlobal()) * sizeof((g->xc_old)[0]), g->xc_old,
-                      cr->mpi_comm_mygroup);
+            gmx_bcast((g->atomset.numAtomsGlobal()) * sizeof((g->xc_old)[0]), g->xc_old, cr->mpi_comm_mygroup);
         }
     }
 
     /* Make sure that all molecules in the solvent and ion groups contain the
      * same number of atoms each */
-    for (int ig = eGrpSolvent; ig < s->ngrp; ig++)
+    for (int ig = static_cast<int>(SwapGroupSplittingType::Solvent); ig < s->ngrp; ig++)
     {
         real charge;
 
@@ -1594,7 +1682,9 @@ t_swap* init_swapcoords(FILE*                       fplog,
 
 
     /* Need mass-weighted center of split group? */
-    for (int j = eGrpSplit0; j <= eGrpSplit1; j++)
+    for (int j = static_cast<int>(SwapGroupSplittingType::Split0);
+         j <= static_cast<int>(SwapGroupSplittingType::Split1);
+         j++)
     {
         g = &(s->group[j]);
         if (sc->massw_split[j])
@@ -1618,7 +1708,10 @@ t_swap* init_swapcoords(FILE*                       fplog,
     {
         if (bVerbose)
         {
-            fprintf(stderr, "%s Opening output file %s%s\n", SwS, fn,
+            fprintf(stderr,
+                    "%s Opening output file %s%s\n",
+                    SwS.c_str(),
+                    fn,
                     restartWithAppending ? " for appending" : "");
         }
 
@@ -1630,15 +1723,23 @@ t_swap* init_swapcoords(FILE*                       fplog,
 
             for (int ig = 0; ig < s->ngrp; ig++)
             {
-                g = &(s->group[ig]);
-                fprintf(s->fpout, "# %s group '%s' contains %d atom%s",
-                        ig < eSwapFixedGrpNR ? eSwapFixedGrp_names[ig] : "Ion", g->molname,
+                auto enumValue = static_cast<SwapGroupSplittingType>(ig);
+                g              = &(s->group[ig]);
+                fprintf(s->fpout,
+                        "# %s group '%s' contains %d atom%s",
+                        ig < static_cast<int>(SwapGroupSplittingType::Count) ? enumValueToString(enumValue)
+                                                                             : "Ion",
+                        g->molname,
                         static_cast<int>(g->atomset.numAtomsGlobal()),
                         (g->atomset.numAtomsGlobal() > 1) ? "s" : "");
-                if (!(eGrpSplit0 == ig || eGrpSplit1 == ig))
+                if (!(SwapGroupSplittingType::Split0 == enumValue
+                      || SwapGroupSplittingType::Split1 == enumValue))
                 {
-                    fprintf(s->fpout, " with %d atom%s in each molecule of charge %g", g->apm,
-                            (g->apm > 1) ? "s" : "", g->q);
+                    fprintf(s->fpout,
+                            " with %d atom%s in each molecule of charge %g",
+                            g->apm,
+                            (g->apm > 1) ? "s" : "",
+                            g->q);
                 }
                 fprintf(s->fpout, ".\n");
             }
@@ -1646,9 +1747,12 @@ t_swap* init_swapcoords(FILE*                       fplog,
             fprintf(s->fpout, "#\n# Initial positions of split groups:\n");
         }
 
-        for (int j = eGrpSplit0; j <= eGrpSplit1; j++)
+        for (int j = static_cast<int>(SwapGroupSplittingType::Split0);
+             j <= static_cast<int>(SwapGroupSplittingType::Split1);
+             j++)
         {
-            g = &(s->group[j]);
+            auto enumValue = static_cast<SwapGroupSplittingType>(j);
+            g              = &(s->group[j]);
             for (size_t i = 0; i < g->atomset.numAtomsGlobal(); i++)
             {
                 copy_rvec(globalState->x[sc->grp[j].ind[i]], g->xc[i]);
@@ -1658,14 +1762,17 @@ t_swap* init_swapcoords(FILE*                       fplog,
             get_center(g->xc, g->m, g->atomset.numAtomsGlobal(), g->center);
             if (!restartWithAppending)
             {
-                fprintf(s->fpout, "# %s group %s-center %5f nm\n", eSwapFixedGrp_names[j],
-                        DimStr[s->swapdim], g->center[s->swapdim]);
+                fprintf(s->fpout,
+                        "# %s group %s-center %5f nm\n",
+                        enumValueToString(enumValue),
+                        DimStr[s->swapdim],
+                        g->center[s->swapdim]);
             }
         }
 
         if (!restartWithAppending)
         {
-            if ((0 != sc->bulkOffset[eCompA]) || (0 != sc->bulkOffset[eCompB]))
+            if ((0 != sc->bulkOffset[Compartment::A]) || (0 != sc->bulkOffset[Compartment::B]))
             {
                 fprintf(s->fpout, "#\n");
                 fprintf(s->fpout,
@@ -1676,15 +1783,21 @@ t_swap* init_swapcoords(FILE*                       fplog,
                 fprintf(s->fpout,
                         "# are not midway (= at 0.0) between the compartment-defining layers (at "
                         "+/- 1.0).\n");
-                fprintf(s->fpout, "# bulk-offsetA = %g\n", sc->bulkOffset[eCompA]);
-                fprintf(s->fpout, "# bulk-offsetB = %g\n", sc->bulkOffset[eCompB]);
+                fprintf(s->fpout, "# bulk-offsetA = %g\n", sc->bulkOffset[Compartment::A]);
+                fprintf(s->fpout, "# bulk-offsetB = %g\n", sc->bulkOffset[Compartment::B]);
             }
 
             fprintf(s->fpout, "#\n");
-            fprintf(s->fpout, "# Split0 cylinder radius %f nm, up %f nm, down %f nm\n", sc->cyl0r,
-                    sc->cyl0u, sc->cyl0l);
-            fprintf(s->fpout, "# Split1 cylinder radius %f nm, up %f nm, down %f nm\n", sc->cyl1r,
-                    sc->cyl1u, sc->cyl1l);
+            fprintf(s->fpout,
+                    "# Split0 cylinder radius %f nm, up %f nm, down %f nm\n",
+                    sc->cyl0r,
+                    sc->cyl0u,
+                    sc->cyl0l);
+            fprintf(s->fpout,
+                    "# Split1 cylinder radius %f nm, up %f nm, down %f nm\n",
+                    sc->cyl1r,
+                    sc->cyl1u,
+                    sc->cyl1l);
 
             fprintf(s->fpout, "#\n");
             if (!mdrunOptions.rerun)
@@ -1692,7 +1805,8 @@ t_swap* init_swapcoords(FILE*                       fplog,
                 fprintf(s->fpout,
                         "# Coupling constant (number of swap attempt steps to average over): %d  "
                         "(translates to %f ps).\n",
-                        sc->nAverage, sc->nAverage * sc->nstswap * ir->delta_t);
+                        sc->nAverage,
+                        sc->nAverage * sc->nstswap * ir->delta_t);
                 fprintf(s->fpout, "# Threshold is %f\n", sc->threshold);
                 fprintf(s->fpout, "#\n");
                 fprintf(s->fpout,
@@ -1707,10 +1821,10 @@ t_swap* init_swapcoords(FILE*                       fplog,
     }
 
     /* Allocate memory to remember the past particle counts for time averaging */
-    for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+    for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
     {
         g = &(s->group[ig]);
-        for (int ic = 0; ic < eCompNR; ic++)
+        for (auto ic : keysOf(g->comp))
         {
             snew(g->comp[ic].nMolPast, sc->nAverage);
         }
@@ -1725,9 +1839,9 @@ t_swap* init_swapcoords(FILE*                       fplog,
         }
         else
         {
-            fprintf(stderr, "%s Determining initial numbers of ions per compartment.\n", SwS);
-            get_initial_ioncounts(ir, s, globalState->x.rvec_array(), globalState->box, cr,
-                                  mdrunOptions.rerun);
+            fprintf(stderr, "%s Determining initial numbers of ions per compartment.\n", SwS.c_str());
+            get_initial_ioncounts(
+                    ir, s, globalState->x.rvec_array(), globalState->box, cr, mdrunOptions.rerun);
         }
 
         /* Prepare (further) checkpoint writes ... */
@@ -1736,21 +1850,24 @@ t_swap* init_swapcoords(FILE*                       fplog,
             /* Consistency check */
             if (swapstate->nAverage != sc->nAverage)
             {
-                gmx_fatal(FARGS, "%s Ion count averaging steps mismatch! checkpoint: %d, tpr: %d",
-                          SwS, swapstate->nAverage, sc->nAverage);
+                gmx_fatal(FARGS,
+                          "%s Ion count averaging steps mismatch! checkpoint: %d, tpr: %d",
+                          SwS.c_str(),
+                          swapstate->nAverage,
+                          sc->nAverage);
             }
         }
         else
         {
             swapstate->nAverage = sc->nAverage;
         }
-        fprintf(stderr, "%s Setting pointers for checkpoint writing\n", SwS);
-        for (int ic = 0; ic < eCompNR; ic++)
+        fprintf(stderr, "%s Setting pointers for checkpoint writing\n", SwS.c_str());
+        for (auto ic : gmx::EnumerationWrapper<Compartment>{})
         {
-            for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+            for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
             {
                 g  = &s->group[ig];
-                gs = &swapstate->ionType[ig - eSwapFixedGrpNR];
+                gs = &swapstate->ionType[ig - static_cast<int>(SwapGroupSplittingType::Count)];
 
                 gs->nMolReq_p[ic]    = &(g->comp[ic].nMolReq);
                 gs->nMolPast_p[ic]   = &(g->comp[ic].nMolPast[0]);
@@ -1763,7 +1880,7 @@ t_swap* init_swapcoords(FILE*                       fplog,
 
         if (bVerbose)
         {
-            fprintf(stderr, "%s Requested charge imbalance is Q(A) - Q(B) = %g e.\n", SwS, s->deltaQ);
+            fprintf(stderr, "%s Requested charge imbalance is Q(A) - Q(B) = %g e.\n", SwS.c_str(), s->deltaQ);
         }
         if (!restartWithAppending)
         {
@@ -1777,10 +1894,10 @@ t_swap* init_swapcoords(FILE*                       fplog,
     }
 
     /* Update the time-averaged number of molecules for all groups and compartments */
-    for (int ig = eSwapFixedGrpNR; ig < sc->ngrp; ig++)
+    for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < sc->ngrp; ig++)
     {
         g = &s->group[ig];
-        for (int ic = 0; ic < eCompNR; ic++)
+        for (auto ic : keysOf(g->comp))
         {
             update_time_window(&g->comp[ic], sc->nAverage, -1);
         }
@@ -1816,16 +1933,13 @@ void finish_swapcoords(t_swap* s)
  * From the requested and average molecule counts we determine whether a swap is needed
  * at this time step.
  */
-static gmx_bool need_swap(t_swapcoords* sc, t_swap* s)
+static gmx_bool need_swap(const t_swapcoords* sc, t_swap* s)
 {
-    int        ic, ig;
-    t_swapgrp* g;
-
-    for (ig = eSwapFixedGrpNR; ig < sc->ngrp; ig++)
+    for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < sc->ngrp; ig++)
     {
-        g = &s->group[ig];
+        t_swapgrp* g = &s->group[ig];
 
-        for (ic = 0; ic < eCompNR; ic++)
+        for (auto ic : keysOf(g->comp))
         {
             if (g->comp[ic].nMolReq - g->comp[ic].nMolAv >= sc->threshold)
             {
@@ -1872,7 +1986,9 @@ static int get_index_of_distant_atom(t_compartment* comp, const char molname[])
         gmx_fatal(FARGS,
                   "Could not get index of %s atom. Compartment contains %d %s molecules before "
                   "swaps.",
-                  molname, comp->nMolBefore, molname);
+                  molname,
+                  comp->nMolBefore,
+                  molname);
     }
 
     /* Set the distance of this index to infinity such that it won't get selected again in
@@ -1924,29 +2040,25 @@ static void apply_modified_positions(swap_group* g, rvec x[])
 }
 
 
-gmx_bool do_swapcoords(t_commrec*     cr,
-                       int64_t        step,
-                       double         t,
-                       t_inputrec*    ir,
-                       t_swap*        s,
-                       gmx_wallcycle* wcycle,
-                       rvec           x[],
-                       matrix         box,
-                       gmx_bool       bVerbose,
-                       gmx_bool       bRerun)
+gmx_bool do_swapcoords(t_commrec*        cr,
+                       int64_t           step,
+                       double            t,
+                       const t_inputrec* ir,
+                       t_swap*           s,
+                       gmx_wallcycle*    wcycle,
+                       rvec              x[],
+                       matrix            box,
+                       gmx_bool          bVerbose,
+                       gmx_bool          bRerun)
 {
-    t_swapcoords* sc;
-    int           j, ic, ig, nswaps;
-    int           thisC, otherC; /* Index into this compartment and the other one */
-    gmx_bool      bSwap = FALSE;
-    t_swapgrp *   g, *gsol;
-    int           isol, iion;
-    rvec          com_solvent, com_particle; /* solvent and swap molecule's center of mass */
+    const t_swapcoords* sc    = ir->swap;
+    gmx_bool            bSwap = FALSE;
+    t_swapgrp*          gsol;
+    int                 isol, iion;
+    rvec                com_solvent, com_particle; /* solvent and swap molecule's center of mass */
 
 
-    wallcycle_start(wcycle, ewcSWAP);
-
-    sc = ir->swap;
+    wallcycle_start(wcycle, WallCycleCounter::Swap);
 
     set_pbc(s->pbc, ir->pbcType, box);
 
@@ -1954,13 +2066,23 @@ gmx_bool do_swapcoords(t_commrec*     cr,
      * Here we also pass a shifts array to communicate_group_positions(), so that it can make
      * the molecules whole even in cases where they span more than half of the box in
      * any dimension */
-    for (ig = eGrpSplit0; ig <= eGrpSplit1; ig++)
-    {
-        g = &(s->group[ig]);
-        communicate_group_positions(cr, g->xc, g->xc_shifts, g->xc_eshifts, TRUE, x,
-                                    g->atomset.numAtomsGlobal(), g->atomset.numAtomsLocal(),
+    for (int ig = static_cast<int>(SwapGroupSplittingType::Split0);
+         ig <= static_cast<int>(SwapGroupSplittingType::Split1);
+         ig++)
+    {
+        t_swapgrp* g = &(s->group[ig]);
+        communicate_group_positions(cr,
+                                    g->xc,
+                                    g->xc_shifts,
+                                    g->xc_eshifts,
+                                    TRUE,
+                                    x,
+                                    g->atomset.numAtomsGlobal(),
+                                    g->atomset.numAtomsLocal(),
                                     g->atomset.localIndex().data(),
-                                    g->atomset.collectiveIndex().data(), g->xc_old, box);
+                                    g->atomset.collectiveIndex().data(),
+                                    g->xc_old,
+                                    box);
 
         get_center(g->xc, g->m, g->atomset.numAtomsGlobal(), g->center); /* center of split groups == channels */
     }
@@ -1968,12 +2090,21 @@ gmx_bool do_swapcoords(t_commrec*     cr,
     /* Assemble the positions of the ions (ig = 3, 4, ...). These molecules should
      * be small and we can always make them whole with a simple distance check.
      * Therefore we pass NULL as third argument. */
-    for (ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
-    {
-        g = &(s->group[ig]);
-        communicate_group_positions(cr, g->xc, nullptr, nullptr, FALSE, x, g->atomset.numAtomsGlobal(),
-                                    g->atomset.numAtomsLocal(), g->atomset.localIndex().data(),
-                                    g->atomset.collectiveIndex().data(), nullptr, nullptr);
+    for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
+    {
+        t_swapgrp* g = &(s->group[ig]);
+        communicate_group_positions(cr,
+                                    g->xc,
+                                    nullptr,
+                                    nullptr,
+                                    FALSE,
+                                    x,
+                                    g->atomset.numAtomsGlobal(),
+                                    g->atomset.numAtomsLocal(),
+                                    g->atomset.localIndex().data(),
+                                    g->atomset.collectiveIndex().data(),
+                                    nullptr,
+                                    nullptr);
 
         /* Determine how many ions of this type each compartment contains */
         sortMoleculesIntoCompartments(g, cr, sc, s, box, step, s->fpout, bRerun, FALSE);
@@ -1998,23 +2129,32 @@ gmx_bool do_swapcoords(t_commrec*     cr,
     {
         /* Since we here know that we have to perform ion/water position exchanges,
          * we now assemble the solvent positions */
-        g = &(s->group[eGrpSolvent]);
-        communicate_group_positions(cr, g->xc, nullptr, nullptr, FALSE, x, g->atomset.numAtomsGlobal(),
-                                    g->atomset.numAtomsLocal(), g->atomset.localIndex().data(),
-                                    g->atomset.collectiveIndex().data(), nullptr, nullptr);
+        t_swapgrp* g = &(s->group[static_cast<int>(SwapGroupSplittingType::Solvent)]);
+        communicate_group_positions(cr,
+                                    g->xc,
+                                    nullptr,
+                                    nullptr,
+                                    FALSE,
+                                    x,
+                                    g->atomset.numAtomsGlobal(),
+                                    g->atomset.numAtomsLocal(),
+                                    g->atomset.localIndex().data(),
+                                    g->atomset.collectiveIndex().data(),
+                                    nullptr,
+                                    nullptr);
 
         /* Determine how many molecules of solvent each compartment contains */
         sortMoleculesIntoCompartments(g, cr, sc, s, box, step, s->fpout, bRerun, TRUE);
 
         /* Save number of solvent molecules per compartment prior to any swaps */
-        g->comp[eCompA].nMolBefore = g->comp[eCompA].nMol;
-        g->comp[eCompB].nMolBefore = g->comp[eCompB].nMol;
+        g->comp[Compartment::A].nMolBefore = g->comp[Compartment::A].nMol;
+        g->comp[Compartment::B].nMolBefore = g->comp[Compartment::B].nMol;
 
-        for (ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+        for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
         {
-            g = &(s->group[ig]);
+            t_swapgrp* g = &(s->group[ig]);
 
-            for (ic = 0; ic < eCompNR; ic++)
+            for (auto ic : keysOf(g->comp))
             {
                 /* Determine in which compartment ions are missing and where they are too many */
                 g->vacancy[ic] = g->comp[ic].nMolReq - g->comp[ic].nMolAv;
@@ -2025,15 +2165,15 @@ gmx_bool do_swapcoords(t_commrec*     cr,
         }
 
         /* Now actually perform the particle exchanges, one swap group after another */
-        gsol = &s->group[eGrpSolvent];
-        for (ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
+        gsol = &s->group[static_cast<int>(SwapGroupSplittingType::Solvent)];
+        for (int ig = static_cast<int>(SwapGroupSplittingType::Count); ig < s->ngrp; ig++)
         {
-            nswaps = 0;
-            g      = &s->group[ig];
-            for (thisC = 0; thisC < eCompNR; thisC++)
+            int        nswaps = 0;
+            t_swapgrp* g      = &s->group[ig];
+            for (auto thisC : gmx::EnumerationWrapper<Compartment>{})
             {
                 /* Index to the other compartment */
-                otherC = (thisC + 1) % eCompNR;
+                auto otherC = thisC == Compartment::A ? Compartment::B : Compartment::A;
 
                 while (g->vacancy[thisC] >= sc->threshold)
                 {
@@ -2063,7 +2203,7 @@ gmx_bool do_swapcoords(t_commrec*     cr,
                     /* Correct the past time window to still get the right averages from now on */
                     g->comp[thisC].nMolAv++;
                     g->comp[otherC].nMolAv--;
-                    for (j = 0; j < sc->nAverage; j++)
+                    for (int j = 0; j < sc->nAverage; j++)
                     {
                         g->comp[thisC].nMolPast[j]++;
                         g->comp[otherC].nMolPast[j]--;
@@ -2072,8 +2212,8 @@ gmx_bool do_swapcoords(t_commrec*     cr,
                     if (MASTER(cr))
                     {
                         int iMol               = iion / g->apm;
-                        g->channel_label[iMol] = eChHistPassedNone;
-                        g->comp_from[iMol]     = eDomainNotset;
+                        g->channel_label[iMol] = ChannelHistory::None;
+                        g->comp_from[iMol]     = Domain::Notset;
                     }
                     /* That was the swap */
                     nswaps++;
@@ -2082,8 +2222,13 @@ gmx_bool do_swapcoords(t_commrec*     cr,
 
             if (nswaps && bVerbose)
             {
-                fprintf(stderr, "%s Performed %d swap%s in step %" PRId64 " for iontype %s.\n", SwS,
-                        nswaps, nswaps > 1 ? "s" : "", step, g->molname);
+                fprintf(stderr,
+                        "%s Performed %d swap%s in step %" PRId64 " for iontype %s.\n",
+                        SwS.c_str(),
+                        nswaps,
+                        nswaps > 1 ? "s" : "",
+                        step,
+                        g->molname);
             }
         }
 
@@ -2094,15 +2239,15 @@ gmx_bool do_swapcoords(t_commrec*     cr,
 
         /* For the solvent and user-defined swap groups, each rank writes back its
          * (possibly modified) local positions to the official position array. */
-        for (ig = eGrpSolvent; ig < s->ngrp; ig++)
+        for (int ig = static_cast<int>(SwapGroupSplittingType::Solvent); ig < s->ngrp; ig++)
         {
-            g = &s->group[ig];
+            t_swapgrp* g = &s->group[ig];
             apply_modified_positions(g, x);
         }
 
     } /* end of if(bSwap) */
 
-    wallcycle_stop(wcycle, ewcSWAP);
+    wallcycle_stop(wcycle, WallCycleCounter::Swap);
 
     return bSwap;
 }
index 6cfdd53fd4dced594a64809f95e18e0abc450b40..ec8fdd540d56605e0faa26df1688ae8effd4380d 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2013, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +107,7 @@ std::unique_ptr<IMDModule> createSwapCoordinatesModule();
 t_swap* init_swapcoords(FILE*                     fplog,
                         const t_inputrec*         ir,
                         const char*               fn,
-                        gmx_mtop_t*               mtop,
+                        const gmx_mtop_t&         mtop,
                         const t_state*            globalState,
                         ObservablesHistory*       oh,
                         t_commrec*                cr,
@@ -139,15 +139,15 @@ void finish_swapcoords(t_swap* s);
  *
  * \returns Whether at least one pair of molecules was swapped.
  */
-gmx_bool do_swapcoords(t_commrec*     cr,
-                       int64_t        step,
-                       double         t,
-                       t_inputrec*    ir,
-                       t_swap*        s,
-                       gmx_wallcycle* wcycle,
-                       rvec           x[],
-                       matrix         box,
-                       gmx_bool       bVerbose,
-                       gmx_bool       bRerun);
+gmx_bool do_swapcoords(t_commrec*        cr,
+                       int64_t           step,
+                       double            t,
+                       const t_inputrec* ir,
+                       t_swap*           s,
+                       gmx_wallcycle*    wcycle,
+                       rvec              x[],
+                       matrix            box,
+                       gmx_bool          bVerbose,
+                       gmx_bool          bRerun);
 
 #endif
index 935f31a0fc268117063fce3563c00b889753a826..1bb2374cc987251555fb096d6e4ef4530f4cefac 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2015,2016, by the GROMACS development team, led by
+# Copyright (c) 2015,2016,200, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(tables INTERFACE)
 file(GLOB TABLE_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${TABLE_SOURCES} PARENT_SCOPE)
 
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(tables PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(tables PUBLIC
+target_include_directories(tables INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(tables PUBLIC
+target_link_libraries(tables INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when tables is an OBJECT target
+#target_link_libraries(tables PUBLIC legacy_api)
+#target_link_libraries(tables PRIVATE common)
+
+# Module dependencies
+# tables interfaces convey transitive dependence on these modules.
+#target_link_libraries(tables PUBLIC
+target_link_libraries(tables INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(tables PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(tables PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index 9f0bf2b451aba1bd28df6a029a1c024d72f8f209..dcbdbfe7a2a8d6c83b6b710679f5a0da097cbf07 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -116,8 +116,8 @@ void cubicSplineInterpolationFromFunctionAndDerivative(double  functionValue0,
 {
     double Y, F, G, H;
 
-    calculateCubicSplineCoefficients(functionValue0, functionValue1, derivativeValue0,
-                                     derivativeValue1, spacing, &Y, &F, &G, &H);
+    calculateCubicSplineCoefficients(
+            functionValue0, functionValue1, derivativeValue0, derivativeValue1, spacing, &Y, &F, &G, &H);
 
     double Fp = fma(fma(H, eps, G), eps, F);
 
@@ -179,8 +179,15 @@ void fillSingleCubicSplineTableData(const std::function<double(double)>& functio
 
         if (functionIsInRange)
         {
-            calculateCubicSplineCoefficients(tmpFunctionValue, nextHigherFunction, tmpDerivativeValue,
-                                             nextHigherDerivative, spacing, &Y, &F, &G, &H);
+            calculateCubicSplineCoefficients(tmpFunctionValue,
+                                             nextHigherFunction,
+                                             tmpDerivativeValue,
+                                             nextHigherDerivative,
+                                             spacing,
+                                             &Y,
+                                             &F,
+                                             &G,
+                                             &H);
             lastIndexInRange--;
         }
         else
@@ -250,9 +257,14 @@ void fillSingleCubicSplineTableData(ArrayRef<const double>       function,
 
         if (functionIsInRange)
         {
-            cubicSplineInterpolationFromFunctionAndDerivative(
-                    function[index], function[index + 1], derivative[index], derivative[index + 1],
-                    inputSpacing, eps, &(tmpFunction[i]), &(tmpDerivative[i]));
+            cubicSplineInterpolationFromFunctionAndDerivative(function[index],
+                                                              function[index + 1],
+                                                              derivative[index],
+                                                              derivative[index + 1],
+                                                              inputSpacing,
+                                                              eps,
+                                                              &(tmpFunction[i]),
+                                                              &(tmpDerivative[i]));
             lastIndexInRange--;
         }
         else
@@ -273,8 +285,8 @@ void fillSingleCubicSplineTableData(ArrayRef<const double>       function,
         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);
+        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;
@@ -362,11 +374,11 @@ CubicSplineTable::CubicSplineTable(std::initializer_list<AnalyticalSplineTableIn
         {
             std::vector<real> tmpYfghTableData;
 
-            fillSingleCubicSplineTableData(thisFuncInput.function, thisFuncInput.derivative, range_,
-                                           spacing, &tmpYfghTableData);
+            fillSingleCubicSplineTableData(
+                    thisFuncInput.function, thisFuncInput.derivative, range_, spacing, &tmpYfghTableData);
 
-            internal::fillMultiplexedTableData(tmpYfghTableData, &yfghMultiTableData_, 4,
-                                               numFuncInTable_, funcIndex);
+            internal::fillMultiplexedTableData(
+                    tmpYfghTableData, &yfghMultiTableData_, 4, numFuncInTable_, funcIndex);
 
             funcIndex++;
         }
@@ -467,11 +479,15 @@ CubicSplineTable::CubicSplineTable(std::initializer_list<NumericalSplineTableInp
 
             std::vector<real> tmpYfghTableData;
 
-            fillSingleCubicSplineTableData(thisFuncInput.function, thisFuncInput.derivative,
-                                           thisFuncInput.spacing, range, spacing, &tmpYfghTableData);
+            fillSingleCubicSplineTableData(thisFuncInput.function,
+                                           thisFuncInput.derivative,
+                                           thisFuncInput.spacing,
+                                           range,
+                                           spacing,
+                                           &tmpYfghTableData);
 
-            internal::fillMultiplexedTableData(tmpYfghTableData, &yfghMultiTableData_, 4,
-                                               numFuncInTable_, funcIndex);
+            internal::fillMultiplexedTableData(
+                    tmpYfghTableData, &yfghMultiTableData_, 4, numFuncInTable_, funcIndex);
 
             funcIndex++;
         }
index 268a19faf153ba125482af5c6afe7b1d85b1964b..01bca6c60c1b24675eb7d77cca5d5c81c630741c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 #define GMX_TABLES_CUBICSPLINETABLE_H
 
 #include <initializer_list>
+#include <memory>
 #include <vector>
 
 #include "gromacs/simd/simd.h"
@@ -291,8 +292,8 @@ public:
 
         // 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);
+        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);
     }
@@ -347,8 +348,8 @@ public:
 
         // 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);
+        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);
     }
 
index 2e61e90b08c0f5268cf5d934c9259d6eb4877314..0705e7db7912dc6cc5cd41f01021c4d0094b6031 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@
 #include "gromacs/math/multidimarray.h"
 #include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
-#include "gromacs/math/vec.h"
 #include "gromacs/mdspan/extensions.h"
 #include "gromacs/mdtypes/fcdata.h"
 #include "gromacs/mdtypes/interaction_const.h"
@@ -58,7 +57,6 @@
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
-#include "gromacs/utility/smalloc.h"
 
 /* All the possible (implemented) table functions */
 enum
@@ -104,12 +102,17 @@ static const t_tab_props tprops[etabNR] = {
     { "COULSwitch", TRUE },   { "EXPMIN", FALSE },    { "USER", FALSE },
 };
 
-typedef struct
+struct t_tabledata
 {
-    int     nx, nx0;
-    double  tabscale;
-    double *x, *v, *f;
-} t_tabledata;
+    t_tabledata() = default;
+    t_tabledata(int n, int nx0, double tabscale, bool bAlloc);
+    int                 nx;
+    int                 nx0;
+    double              tabscale;
+    std::vector<double> x;
+    std::vector<double> v;
+    std::vector<double> f;
+};
 
 double v_q_ewald_lr(double beta, double r)
 {
@@ -335,8 +338,7 @@ real ewald_spline3_table_scale(const interaction_const_t& ic,
 {
     GMX_RELEASE_ASSERT(!generateCoulombTables || EEL_PME_EWALD(ic.eeltype),
                        "Can only use tables with Ewald");
-    GMX_RELEASE_ASSERT(!generateVdwTables || EVDW_PME(ic.vdwtype),
-                       "Can only use tables with Ewald");
+    GMX_RELEASE_ASSERT(!generateVdwTables || EVDW_PME(ic.vdwtype), "Can only use tables with Ewald");
 
     real sc = 0;
 
@@ -386,14 +388,14 @@ real ewald_spline3_table_scale(const interaction_const_t& ic,
     return sc;
 }
 
-static void copy2table(int          n,
-                       int          offset,
-                       int          stride,
-                       const double x[],
-                       const double Vtab[],
-                       const double Ftab[],
-                       real         scalefactor,
-                       real         dest[])
+static void copy2table(int                         n,
+                       int                         offset,
+                       int                         stride,
+                       gmx::ArrayRef<const double> x,
+                       gmx::ArrayRef<const double> Vtab,
+                       gmx::ArrayRef<const double> Ftab,
+                       real                        scalefactor,
+                       gmx::ArrayRef<real>         dest)
 {
     /* Use double prec. for the intermediary variables
      * and temporary x/vtab/vtab2 data to avoid unnecessary
@@ -429,16 +431,16 @@ static void copy2table(int          n,
     }
 }
 
-static void init_table(int n, int nx0, double tabscale, t_tabledata* td, gmx_bool bAlloc)
+t_tabledata::t_tabledata(int n, int nx0, double tabscale, bool bAlloc) :
+    nx(n),
+    nx0(nx0),
+    tabscale(tabscale)
 {
-    td->nx       = n;
-    td->nx0      = nx0;
-    td->tabscale = tabscale;
     if (bAlloc)
     {
-        snew(td->x, td->nx);
-        snew(td->v, td->nx);
-        snew(td->f, td->nx);
+        x.resize(nx);
+        v.resize(nx);
+        f.resize(nx);
     }
 }
 
@@ -446,7 +448,7 @@ static void spline_forces(int nx, double h, const double v[], gmx_bool bS3, gmx_
 {
     int    start, end, i;
     double v3, b_s, b_e, b;
-    double beta, *gamma;
+    double beta;
 
     /* Formulas can be found in:
      * H.J.C. Berendsen, Simulating the Physical World, Cambridge 2007
@@ -512,7 +514,7 @@ static void spline_forces(int nx, double h, const double v[], gmx_bool bS3, gmx_
         end = nx - 1;
     }
 
-    snew(gamma, nx);
+    std::vector<double> gamma(nx);
     beta = (bS3 ? 1 : 4);
 
     /* For V'' fitting */
@@ -534,7 +536,6 @@ static void spline_forces(int nx, double h, const double v[], gmx_bool bS3, gmx_
     {
         f[i] -= gamma[i + 1] * f[i + 1];
     }
-    sfree(gamma);
 
     /* Correct for the minus sign and the spacing */
     for (i = start; i < end; i++)
@@ -574,13 +575,17 @@ static void set_forces(FILE* fp, int angle, int nx, double h, double v[], double
 
     if (fp)
     {
-        fprintf(fp, "Generating forces for table %d, boundary conditions: V''' at %g, %s at %g\n",
-                table + 1, start * h, end == nx ? "V'''" : "V'=0", (end - 1) * h);
+        fprintf(fp,
+                "Generating forces for table %d, boundary conditions: V''' at %g, %s at %g\n",
+                table + 1,
+                start * h,
+                end == nx ? "V'''" : "V'=0",
+                (end - 1) * h);
     }
     spline_forces(end - start, h, v + start, TRUE, end == nx, f + start);
 }
 
-static void read_tables(FILE* fp, const char* filename, int ntab, int angle, t_tabledata td[])
+static std::vector<t_tabledata> read_tables(FILE* fp, const char* filename, int ntab, int angle)
 {
     char     buf[STRLEN];
     double   start, end, dx0, dx1, ssd, vm, vp, f, numf;
@@ -594,8 +599,7 @@ static void read_tables(FILE* fp, const char* filename, int ntab, int angle, t_t
     int                                                            numColumns = xvgData.extent(0);
     if (numColumns != nny)
     {
-        gmx_fatal(FARGS, "Trying to read file %s, but nr columns = %d, should be %d", libfn.c_str(),
-                  numColumns, nny);
+        gmx_fatal(FARGS, "Trying to read file %s, but nr columns = %d, should be %d", libfn.c_str(), numColumns, nny);
     }
     int numRows = xvgData.extent(1);
 
@@ -604,8 +608,11 @@ static void read_tables(FILE* fp, const char* filename, int ntab, int angle, t_t
     {
         if (yy[0][0] != 0.0)
         {
-            gmx_fatal(FARGS, "The first distance in file %s is %f nm instead of %f nm",
-                      libfn.c_str(), yy[0][0], 0.0);
+            gmx_fatal(FARGS,
+                      "The first distance in file %s is %f nm instead of %f nm",
+                      libfn.c_str(),
+                      yy[0][0],
+                      0.0);
         }
     }
     else
@@ -621,8 +628,13 @@ static void read_tables(FILE* fp, const char* filename, int ntab, int angle, t_t
         end = 180.0;
         if (yy[0][0] != start || yy[0][numRows - 1] != end)
         {
-            gmx_fatal(FARGS, "The angles in file %s should go from %f to %f instead of %f to %f\n",
-                      libfn.c_str(), start, end, yy[0][0], yy[0][numRows - 1]);
+            gmx_fatal(FARGS,
+                      "The angles in file %s should go from %f to %f instead of %f to %f\n",
+                      libfn.c_str(),
+                      start,
+                      end,
+                      yy[0][0],
+                      yy[0][numRows - 1]);
         }
     }
 
@@ -653,7 +665,10 @@ static void read_tables(FILE* fp, const char* filename, int ntab, int angle, t_t
                 {
                     gmx_fatal(FARGS,
                               "In table file '%s' the x values are not equally spaced: %f %f %f",
-                              filename, yy[0][i - 2], yy[0][i - 1], yy[0][i]);
+                              filename,
+                              yy[0][i - 2],
+                              yy[0][i - 1],
+                              yy[0][i]);
                 }
             }
             if (yy[1 + k * 2][i] != 0)
@@ -666,8 +681,7 @@ static void read_tables(FILE* fp, const char* filename, int ntab, int angle, t_t
                 }
                 if (yy[1 + k * 2][i] > 0.01 * GMX_REAL_MAX || yy[1 + k * 2][i] < -0.01 * GMX_REAL_MAX)
                 {
-                    gmx_fatal(FARGS, "Out of range potential value %g in file '%s'",
-                              yy[1 + k * 2][i], filename);
+                    gmx_fatal(FARGS, "Out of range potential value %g in file '%s'", yy[1 + k * 2][i], filename);
                 }
             }
             if (yy[1 + k * 2 + 1][i] != 0)
@@ -680,16 +694,14 @@ static void read_tables(FILE* fp, const char* filename, int ntab, int angle, t_t
                 }
                 if (yy[1 + k * 2 + 1][i] > 0.01 * GMX_REAL_MAX || yy[1 + k * 2 + 1][i] < -0.01 * GMX_REAL_MAX)
                 {
-                    gmx_fatal(FARGS, "Out of range force value %g in file '%s'",
-                              yy[1 + k * 2 + 1][i], filename);
+                    gmx_fatal(FARGS, "Out of range force value %g in file '%s'", yy[1 + k * 2 + 1][i], filename);
                 }
             }
         }
 
         if (!bZeroV && bZeroF)
         {
-            set_forces(fp, angle, numRows, 1 / tabscale, yy[1 + k * 2].data(),
-                       yy[1 + k * 2 + 1].data(), k);
+            set_forces(fp, angle, numRows, 1 / tabscale, yy[1 + k * 2].data(), yy[1 + k * 2 + 1].data(), k);
         }
         else
         {
@@ -721,7 +733,10 @@ static void read_tables(FILE* fp, const char* filename, int ntab, int angle, t_t
                         "For the %d non-zero entries for table %d in %s the forces deviate on "
                         "average %" PRId64
                         "%% from minus the numerical derivative of the potential\n",
-                        ns, k, libfn.c_str(), gmx::roundToInt64(100 * ssd));
+                        ns,
+                        k,
+                        libfn.c_str(),
+                        gmx::roundToInt64(100 * ssd));
                 if (debug)
                 {
                     fprintf(debug, "%s", buf);
@@ -742,9 +757,10 @@ static void read_tables(FILE* fp, const char* filename, int ntab, int angle, t_t
         fprintf(fp, "\nNOTE: All elements in table %s are zero\n\n", libfn.c_str());
     }
 
+    std::vector<t_tabledata> td;
     for (k = 0; (k < ntab); k++)
     {
-        init_table(numRows, nx0, tabscale, &(td[k]), TRUE);
+        td.emplace_back(t_tabledata(numRows, nx0, tabscale, true));
         for (i = 0; (i < numRows); i++)
         {
             td[k].x[i] = yy[0][i];
@@ -752,18 +768,7 @@ static void read_tables(FILE* fp, const char* filename, int ntab, int angle, t_t
             td[k].f[i] = yy[2 * k + 2][i];
         }
     }
-}
-
-static void done_tabledata(t_tabledata* td)
-{
-    if (!td)
-    {
-        return;
-    }
-
-    sfree(td->x);
-    sfree(td->v);
-    sfree(td->f);
+    return td;
 }
 
 static void fill_table(t_tabledata* td, int tp, const interaction_const_t* ic, gmx_bool b14only)
@@ -801,15 +806,18 @@ static void fill_table(t_tabledata* td, int tp, const interaction_const_t* ic, g
     }
     else
     {
-        bPotentialSwitch = ((tp == etabLJ6Switch) || (tp == etabLJ12Switch) || (tp == etabCOULSwitch)
-                            || (tp == etabEwaldSwitch) || (tp == etabEwaldUserSwitch)
-                            || (tprops[tp].bCoulomb && (ic->coulomb_modifier == eintmodPOTSWITCH))
-                            || (!tprops[tp].bCoulomb && (ic->vdw_modifier == eintmodPOTSWITCH)));
-        bForceSwitch     = ((tp == etabLJ6Shift) || (tp == etabLJ12Shift) || (tp == etabShift)
-                        || (tprops[tp].bCoulomb && (ic->coulomb_modifier == eintmodFORCESWITCH))
-                        || (!tprops[tp].bCoulomb && (ic->vdw_modifier == eintmodFORCESWITCH)));
-        bPotentialShift  = ((tprops[tp].bCoulomb && (ic->coulomb_modifier == eintmodPOTSHIFT))
-                           || (!tprops[tp].bCoulomb && (ic->vdw_modifier == eintmodPOTSHIFT)));
+        bPotentialSwitch =
+                ((tp == etabLJ6Switch) || (tp == etabLJ12Switch) || (tp == etabCOULSwitch)
+                 || (tp == etabEwaldSwitch) || (tp == etabEwaldUserSwitch)
+                 || (tprops[tp].bCoulomb && (ic->coulomb_modifier == InteractionModifiers::PotSwitch))
+                 || (!tprops[tp].bCoulomb && (ic->vdw_modifier == InteractionModifiers::PotSwitch)));
+        bForceSwitch =
+                ((tp == etabLJ6Shift) || (tp == etabLJ12Shift) || (tp == etabShift)
+                 || (tprops[tp].bCoulomb && (ic->coulomb_modifier == InteractionModifiers::ForceSwitch))
+                 || (!tprops[tp].bCoulomb && (ic->vdw_modifier == InteractionModifiers::ForceSwitch)));
+        bPotentialShift =
+                ((tprops[tp].bCoulomb && (ic->coulomb_modifier == InteractionModifiers::PotShift))
+                 || (!tprops[tp].bCoulomb && (ic->vdw_modifier == InteractionModifiers::PotShift)));
     }
 
     reppow = ic->reppow;
@@ -910,7 +918,9 @@ static void fill_table(t_tabledata* td, int tp, const interaction_const_t* ic, g
                 gmx_fatal(FARGS,
                           "Cannot apply new potential-shift modifier to interaction type '%s' yet. "
                           "(%s,%d)",
-                          tprops[tp].name, __FILE__, __LINE__);
+                          tprops[tp].name,
+                          __FILE__,
+                          __LINE__);
         }
     }
 
@@ -1027,8 +1037,8 @@ static void fill_table(t_tabledata* td, int tp, const interaction_const_t* ic, g
                 break;
             case etabRF:
             case etabRF_ZERO:
-                Vtab = 1.0 / r + ic->k_rf * r2 - ic->c_rf;
-                Ftab = 1.0 / r2 - 2 * ic->k_rf * r;
+                Vtab = 1.0 / r + ic->reactionFieldCoefficient * r2 - ic->reactionFieldShift;
+                Ftab = 1.0 / r2 - 2 * ic->reactionFieldCoefficient * r;
                 if (tp == etabRF_ZERO && r >= rc)
                 {
                     Vtab = 0;
@@ -1116,21 +1126,23 @@ static void fill_table(t_tabledata* td, int tp, const interaction_const_t* ic, g
 
 static void set_table_type(int tabsel[], const interaction_const_t* ic, gmx_bool b14only)
 {
-    int eltype, vdwtype;
-
     /* Set the different table indices.
      * Coulomb first.
      */
 
+    CoulombInteractionType eltype;
+    VanDerWaalsType        vdwtype;
 
     if (b14only)
     {
         switch (ic->eeltype)
         {
-            case eelUSER:
-            case eelPMEUSER:
-            case eelPMEUSERSWITCH: eltype = eelUSER; break;
-            default: eltype = eelCUT;
+            case CoulombInteractionType::User:
+            case CoulombInteractionType::PmeUser:
+            case CoulombInteractionType::PmeUserSwitch:
+                eltype = CoulombInteractionType::User;
+                break;
+            default: eltype = CoulombInteractionType::Cut;
         }
     }
     else
@@ -1140,9 +1152,9 @@ static void set_table_type(int tabsel[], const interaction_const_t* ic, gmx_bool
 
     switch (eltype)
     {
-        case eelCUT: tabsel[etiCOUL] = etabCOUL; break;
-        case eelPOISSON: tabsel[etiCOUL] = etabShift; break;
-        case eelSHIFT:
+        case CoulombInteractionType::Cut: tabsel[etiCOUL] = etabCOUL; break;
+        case CoulombInteractionType::Poisson: tabsel[etiCOUL] = etabShift; break;
+        case CoulombInteractionType::Shift:
             if (ic->rcoulomb > ic->rcoulomb_switch)
             {
                 tabsel[etiCOUL] = etabShift;
@@ -1152,17 +1164,17 @@ static void set_table_type(int tabsel[], const interaction_const_t* ic, gmx_bool
                 tabsel[etiCOUL] = etabCOUL;
             }
             break;
-        case eelEWALD:
-        case eelPME:
-        case eelP3M_AD: tabsel[etiCOUL] = etabEwald; break;
-        case eelPMESWITCH: tabsel[etiCOUL] = etabEwaldSwitch; break;
-        case eelPMEUSER: tabsel[etiCOUL] = etabEwaldUser; break;
-        case eelPMEUSERSWITCH: tabsel[etiCOUL] = etabEwaldUserSwitch; break;
-        case eelRF:
-        case eelRF_ZERO: tabsel[etiCOUL] = etabRF_ZERO; break;
-        case eelSWITCH: tabsel[etiCOUL] = etabCOULSwitch; break;
-        case eelUSER: tabsel[etiCOUL] = etabUSER; break;
-        default: gmx_fatal(FARGS, "Invalid eeltype %d", eltype);
+        case CoulombInteractionType::Ewald:
+        case CoulombInteractionType::Pme:
+        case CoulombInteractionType::P3mAD: tabsel[etiCOUL] = etabEwald; break;
+        case CoulombInteractionType::PmeSwitch: tabsel[etiCOUL] = etabEwaldSwitch; break;
+        case CoulombInteractionType::PmeUser: tabsel[etiCOUL] = etabEwaldUser; break;
+        case CoulombInteractionType::PmeUserSwitch: tabsel[etiCOUL] = etabEwaldUserSwitch; break;
+        case CoulombInteractionType::RF:
+        case CoulombInteractionType::RFZero: tabsel[etiCOUL] = etabRF_ZERO; break;
+        case CoulombInteractionType::Switch: tabsel[etiCOUL] = etabCOULSwitch; break;
+        case CoulombInteractionType::User: tabsel[etiCOUL] = etabUSER; break;
+        default: gmx_fatal(FARGS, "Invalid eeltype %s", enumValueToString(eltype));
     }
 
     /* Van der Waals time */
@@ -1173,9 +1185,9 @@ static void set_table_type(int tabsel[], const interaction_const_t* ic, gmx_bool
     }
     else
     {
-        if (b14only && ic->vdwtype != evdwUSER)
+        if (b14only && ic->vdwtype != VanDerWaalsType::User)
         {
-            vdwtype = evdwCUT;
+            vdwtype = VanDerWaalsType::Cut;
         }
         else
         {
@@ -1184,33 +1196,33 @@ static void set_table_type(int tabsel[], const interaction_const_t* ic, gmx_bool
 
         switch (vdwtype)
         {
-            case evdwSWITCH:
+            case VanDerWaalsType::Switch:
                 tabsel[etiLJ6]  = etabLJ6Switch;
                 tabsel[etiLJ12] = etabLJ12Switch;
                 break;
-            case evdwSHIFT:
+            case VanDerWaalsType::Shift:
                 tabsel[etiLJ6]  = etabLJ6Shift;
                 tabsel[etiLJ12] = etabLJ12Shift;
                 break;
-            case evdwUSER:
+            case VanDerWaalsType::User:
                 tabsel[etiLJ6]  = etabUSER;
                 tabsel[etiLJ12] = etabUSER;
                 break;
-            case evdwCUT:
+            case VanDerWaalsType::Cut:
                 tabsel[etiLJ6]  = etabLJ6;
                 tabsel[etiLJ12] = etabLJ12;
                 break;
-            case evdwPME:
+            case VanDerWaalsType::Pme:
                 tabsel[etiLJ6]  = etabLJ6Ewald;
                 tabsel[etiLJ12] = etabLJ12;
                 break;
             default:
-                gmx_fatal(FARGS, "Invalid vdwtype %d in %s line %d", vdwtype, __FILE__, __LINE__);
+                gmx_fatal(FARGS, "Invalid vdwtype %s in %s line %d", enumValueToString(vdwtype), __FILE__, __LINE__);
         }
 
-        if (!b14only && ic->vdw_modifier != eintmodNONE)
+        if (!b14only && ic->vdw_modifier != InteractionModifiers::None)
         {
-            if (ic->vdw_modifier != eintmodPOTSHIFT && ic->vdwtype != evdwCUT)
+            if (ic->vdw_modifier != InteractionModifiers::PotShift && ic->vdwtype != VanDerWaalsType::Cut)
             {
                 gmx_incons(
                         "Potential modifiers other than potential-shift are only implemented for "
@@ -1220,20 +1232,20 @@ static void set_table_type(int tabsel[], const interaction_const_t* ic, gmx_bool
             /* LJ-PME and other (shift-only) modifiers are handled by applying the modifiers
              * to the original interaction forms when we fill the table, so we only check cutoffs here.
              */
-            if (ic->vdwtype == evdwCUT)
+            if (ic->vdwtype == VanDerWaalsType::Cut)
             {
                 switch (ic->vdw_modifier)
                 {
-                    case eintmodNONE:
-                    case eintmodPOTSHIFT:
-                    case eintmodEXACTCUTOFF:
+                    case InteractionModifiers::None:
+                    case InteractionModifiers::PotShift:
+                    case InteractionModifiers::ExactCutoff:
                         /* No modification */
                         break;
-                    case eintmodPOTSWITCH:
+                    case InteractionModifiers::PotSwitch:
                         tabsel[etiLJ6]  = etabLJ6Switch;
                         tabsel[etiLJ12] = etabLJ12Switch;
                         break;
-                    case eintmodFORCESWITCH:
+                    case InteractionModifiers::ForceSwitch:
                         tabsel[etiLJ6]  = etabLJ6Shift;
                         tabsel[etiLJ12] = etabLJ12Shift;
                         break;
@@ -1244,15 +1256,15 @@ static void set_table_type(int tabsel[], const interaction_const_t* ic, gmx_bool
     }
 }
 
-t_forcetable* make_tables(FILE* out, const interaction_const_t* ic, const char* fn, real rtab, int flags)
+std::unique_ptr<t_forcetable>
+make_tables(FILE* fp, const interaction_const_t* ic, const char* fn, real rtab, int flags)
 {
-    t_tabledata* td;
-    gmx_bool     b14only, useUserTable;
-    int          nx0, tabsel[etiNR];
-    real         scalefactor;
+    gmx_bool b14only, useUserTable;
+    int      nx0, tabsel[etiNR];
+    real     scalefactor;
 
-    t_forcetable* table = new t_forcetable(GMX_TABLE_INTERACTION_ELEC_VDWREP_VDWDISP,
-                                           GMX_TABLE_FORMAT_CUBICSPLINE_YFGH);
+    auto table = std::make_unique<t_forcetable>(GMX_TABLE_INTERACTION_ELEC_VDWREP_VDWDISP,
+                                                GMX_TABLE_FORMAT_CUBICSPLINE_YFGH);
 
     b14only = ((flags & GMX_MAKETABLES_14ONLY) != 0);
 
@@ -1266,7 +1278,7 @@ t_forcetable* make_tables(FILE* out, const interaction_const_t* ic, const char*
     {
         set_table_type(tabsel, ic, b14only);
     }
-    snew(td, etiNR);
+    std::vector<t_tabledata> td;
     table->r     = rtab;
     table->scale = 0;
     table->n     = 0;
@@ -1286,7 +1298,7 @@ t_forcetable* make_tables(FILE* out, const interaction_const_t* ic, const char*
     }
     if (useUserTable)
     {
-        read_tables(out, fn, etiNR, 0, td);
+        td = read_tables(fp, fn, etiNR, 0);
         if (rtab == 0 || (flags & GMX_MAKETABLES_14ONLY))
         {
             table->n = td[0].nx;
@@ -1298,7 +1310,8 @@ t_forcetable* make_tables(FILE* out, const interaction_const_t* ic, const char*
                 gmx_fatal(FARGS,
                           "Tables in file %s not long enough for cut-off:\n"
                           "\tshould be at least %f nm\n",
-                          fn, rtab);
+                          fn,
+                          rtab);
             }
             table->n = gmx::roundToInt(rtab * td[0].tabscale);
         }
@@ -1307,6 +1320,7 @@ t_forcetable* make_tables(FILE* out, const interaction_const_t* ic, const char*
     }
     else
     {
+        td.resize(etiNR);
         // No tables are read
 #if GMX_DOUBLE
         table->scale = 2000.0;
@@ -1335,15 +1349,18 @@ t_forcetable* make_tables(FILE* out, const interaction_const_t* ic, const char*
             {
                 scale /= ic->buckinghamBMax;
             }
-            init_table(table->n, nx0, scale, &(td[k]), !useUserTable);
+            td[k] = t_tabledata(table->n, nx0, scale, !useUserTable);
 
             fill_table(&(td[k]), tabsel[k], ic, b14only);
-            if (out)
+            if (fp)
             {
-                fprintf(out,
+                fprintf(fp,
                         "Generated table with %d data points for %s%s.\n"
                         "Tabscale = %g points/nm\n",
-                        td[k].nx, b14only ? "1-4 " : "", tprops[tabsel[k]].name, td[k].tabscale);
+                        td[k].nx,
+                        b14only ? "1-4 " : "",
+                        tprops[tabsel[k]].name,
+                        td[k].tabscale);
             }
         }
 
@@ -1366,39 +1383,33 @@ t_forcetable* make_tables(FILE* out, const interaction_const_t* ic, const char*
             scalefactor = 1.0;
         }
 
-        copy2table(table->n, k * table->formatsize, table->stride, td[k].x, td[k].v, td[k].f,
-                   scalefactor, table->data.data());
-
-        done_tabledata(&(td[k]));
+        copy2table(table->n, k * table->formatsize, table->stride, td[k].x, td[k].v, td[k].f, scalefactor, table->data);
     }
-    sfree(td);
 
     return table;
 }
 
 bondedtable_t make_bonded_table(FILE* fplog, const char* fn, int angle)
 {
-    t_tabledata   td;
     int           i;
     bondedtable_t tab;
     int           stride = 4;
 
-    read_tables(fplog, fn, 1, angle, &td);
+    t_tabledata td = read_tables(fplog, fn, 1, angle)[0];
     if (angle > 0)
     {
         /* Convert the table from degrees to radians */
         for (i = 0; i < td.nx; i++)
         {
-            td.x[i] *= DEG2RAD;
-            td.f[i] *= RAD2DEG;
+            td.x[i] *= gmx::c_deg2Rad;
+            td.f[i] *= gmx::c_rad2Deg;
         }
-        td.tabscale *= RAD2DEG;
+        td.tabscale *= gmx::c_rad2Deg;
     }
     tab.n     = td.nx;
     tab.scale = td.tabscale;
     tab.data.resize(tab.n * stride);
-    copy2table(tab.n, 0, stride, td.x, td.v, td.f, 1.0, tab.data.data());
-    done_tabledata(&td);
+    copy2table(tab.n, 0, stride, td.x, td.v, td.f, 1.0, tab.data);
 
     return tab;
 }
@@ -1406,10 +1417,10 @@ bondedtable_t make_bonded_table(FILE* fplog, const char* fn, int angle)
 std::unique_ptr<t_forcetable>
 makeDispersionCorrectionTable(FILE* fp, const interaction_const_t* ic, real rtab, const char* tabfn)
 {
-    GMX_RELEASE_ASSERT(ic->vdwtype != evdwUSER || tabfn,
+    GMX_RELEASE_ASSERT(ic->vdwtype != VanDerWaalsType::User || tabfn,
                        "With VdW user tables we need a table file name");
 
-    t_forcetable* fullTable = make_tables(fp, ic, tabfn, rtab, 0);
+    std::unique_ptr<t_forcetable> fullTable = make_tables(fp, ic, tabfn, rtab, 0);
     /* Copy the contents of the table to one that has just dispersion
      * and repulsion, to improve cache performance. We want the table
      * data to be aligned to 32-byte boundaries.
@@ -1433,7 +1444,6 @@ makeDispersionCorrectionTable(FILE* fp, const interaction_const_t* ic, real rtab
             dispersionCorrectionTable->data[8 * i + j] = fullTable->data[12 * i + 4 + j];
         }
     }
-    delete fullTable;
 
     return dispersionCorrectionTable;
 }
@@ -1449,3 +1459,5 @@ t_forcetable::t_forcetable(enum gmx_table_interaction interaction, enum gmx_tabl
     stride(0)
 {
 }
+
+t_forcetable::~t_forcetable() = default;
index a889cca9536bee87466e8e559fd0e4e0b690c434..14cbfd738412f1217fb92c65ca7ec4a9ae548c08 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@ double v_lj_ewald_lr(double beta, double r);
  *
  * \return Pointer to inner loop table structure
  */
-t_forcetable* make_tables(FILE* fp, const interaction_const_t* ic, const char* fn, real rtab, int flags);
+std::unique_ptr<t_forcetable>
+make_tables(FILE* fp, const interaction_const_t* ic, const char* fn, real rtab, int flags);
 
 /*! \brief Return a table for bonded interactions,
  *
index 695e06dc8893d87ac453507ed07d6a132ea0e179..af5129f2a3d4930f7206bd2f1f8a437c4ce80490 100644 (file)
@@ -247,8 +247,7 @@ 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");
+    GMX_ASSERT(functionTableData.size() == derivativeTableData.size(), "Mismatching vector lengths");
 
     std::size_t points = functionTableData.size();
 
@@ -342,16 +341,20 @@ QuadraticSplineTable::QuadraticSplineTable(std::initializer_list<AnalyticalSplin
             std::vector<real> tmpDerTableData;
             std::vector<real> tmpDdfzTableData;
 
-            fillSingleQuadraticSplineTableData(thisFuncInput.function, thisFuncInput.derivative,
-                                               range_, spacing, &tmpFuncTableData, &tmpDerTableData);
+            fillSingleQuadraticSplineTableData(thisFuncInput.function,
+                                               thisFuncInput.derivative,
+                                               range_,
+                                               spacing,
+                                               &tmpFuncTableData,
+                                               &tmpDerTableData);
 
             fillDdfzTableData(tmpFuncTableData, tmpDerTableData, &tmpDdfzTableData);
 
-            internal::fillMultiplexedTableData(tmpDerTableData, &derivativeMultiTableData_, 1,
-                                               numFuncInTable_, funcIndex);
+            internal::fillMultiplexedTableData(
+                    tmpDerTableData, &derivativeMultiTableData_, 1, numFuncInTable_, funcIndex);
 
-            internal::fillMultiplexedTableData(tmpDdfzTableData, &ddfzMultiTableData_, 4,
-                                               numFuncInTable_, funcIndex);
+            internal::fillMultiplexedTableData(
+                    tmpDdfzTableData, &ddfzMultiTableData_, 4, numFuncInTable_, funcIndex);
 
             funcIndex++;
         }
@@ -458,17 +461,21 @@ QuadraticSplineTable::QuadraticSplineTable(std::initializer_list<NumericalSpline
             std::vector<real> tmpDerTableData;
             std::vector<real> tmpDdfzTableData;
 
-            fillSingleQuadraticSplineTableData(thisFuncInput.function, thisFuncInput.derivative,
-                                               thisFuncInput.spacing, range, spacing,
-                                               &tmpFuncTableData, &tmpDerTableData);
+            fillSingleQuadraticSplineTableData(thisFuncInput.function,
+                                               thisFuncInput.derivative,
+                                               thisFuncInput.spacing,
+                                               range,
+                                               spacing,
+                                               &tmpFuncTableData,
+                                               &tmpDerTableData);
 
             fillDdfzTableData(tmpFuncTableData, tmpDerTableData, &tmpDdfzTableData);
 
-            internal::fillMultiplexedTableData(tmpDerTableData, &derivativeMultiTableData_, 1,
-                                               numFuncInTable_, funcIndex);
+            internal::fillMultiplexedTableData(
+                    tmpDerTableData, &derivativeMultiTableData_, 1, numFuncInTable_, funcIndex);
 
-            internal::fillMultiplexedTableData(tmpDdfzTableData, &ddfzMultiTableData_, 4,
-                                               numFuncInTable_, funcIndex);
+            internal::fillMultiplexedTableData(
+                    tmpDdfzTableData, &ddfzMultiTableData_, 4, numFuncInTable_, funcIndex);
 
             funcIndex++;
         }
index 5c742161902d028b5d13166001cd29d249971517..776ee426a0f3f57b56b9143b647014f9cf60b8de 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +59,7 @@
 
 #include <functional>
 #include <initializer_list>
+#include <memory>
 #include <vector>
 
 #include "gromacs/simd/simd.h"
@@ -330,8 +331,8 @@ public:
 
         // 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);
+        gatherLoadBySimdIntTranspose<4 * numFuncInTable>(
+                ddfzMultiTableData_.data() + 4 * funcIndex, tabIndex, &t0, &t1, &t2, &t3);
 
         t1               = t0 + eps * t1;
         *functionValue   = fma(eps * T(halfSpacing_), t0 + t1, t2);
@@ -390,17 +391,18 @@ public:
 
         if (numFuncInTable == 1)
         {
-            gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex,
-                                                          tabIndex, &t0, &t1); // works for scalar T too
+            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, &t0, &t2); // works for scalar T too
-            gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex,
-                                                          tabIndex + T(1), &t1,
+                                                          tabIndex + T(1),
+                                                          &t1,
                                                           &t2); // works for scalar T too
         }
 
@@ -517,10 +519,10 @@ public:
         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
+            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);
         }
@@ -529,17 +531,19 @@ public:
             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, &t0, &t2); // works for scalar T too
-            gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex0,
-                                                          tabIndex + T(1), &t1,
+                                                          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, &t0, &t2); // works for scalar T too
-            gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex1,
-                                                          tabIndex + T(1), &t1,
+                                                          tabIndex + T(1),
+                                                          &t1,
                                                           &t2); // works for scalar T too
             *derivativeValue2 = fma(t1 - t0, eps, t0);
         }
@@ -673,12 +677,12 @@ public:
         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);
+            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);
@@ -688,24 +692,27 @@ public:
             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, &t0, &t2); // works for scalar T too
-            gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex0,
-                                                          tabIndex + T(1), &t1,
+                                                          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, &t0, &t2); // works for scalar T too
-            gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex1,
-                                                          tabIndex + T(1), &t1,
+                                                          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, &t0, &t2); // works for scalar T too
-            gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex2,
-                                                          tabIndex + T(1), &t1,
+                                                          tabIndex + T(1),
+                                                          &t1,
                                                           &t2); // works for scalar T too
             *derivativeValue3 = fma(t1 - t0, eps, t0);
         }
index 2f1c704843a7a09f5ddbed2e93a40e25f05a2a3e..71c859b4e309d49ad5fa4d640aa4c6f36af84558 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -145,9 +145,8 @@ void throwUnlessDerivativeIsConsistentWithFunction(ArrayRef<const double>
     }
     if (!isConsistent)
     {
-        GMX_THROW(InconsistentInputError(
-                formatString("Derivative inconsistent with numerical vector for elements %zu-%zu",
-                             minFail + 1, maxFail + 1)));
+        GMX_THROW(InconsistentInputError(formatString(
+                "Derivative inconsistent with numerical vector for elements %zu-%zu", minFail + 1, maxFail + 1)));
     }
 }
 
@@ -219,9 +218,9 @@ real findSmallestQuotientOfFunctionAndSecondDerivative(ArrayRef<const double>
 
     for (std::size_t i = firstIndex + 1; (i + 1) < lastIndex; i++)
     {
-        minQuotient = std::min(
-                minQuotient, quotientOfFunctionAndSecondDerivative(function[i - 1], function[i],
-                                                                   function[i + 1], inputSpacing));
+        minQuotient = std::min(minQuotient,
+                               quotientOfFunctionAndSecondDerivative(
+                                       function[i - 1], function[i], function[i + 1], inputSpacing));
     }
     return static_cast<real>(minQuotient);
 }
@@ -281,8 +280,8 @@ real findSmallestQuotientOfFunctionAndThirdDerivative(const std::function<double
     for (double x = newRange.first; x <= newRange.second; x += dx)
     {
         minQuotient = std::min(minQuotient,
-                               quotientOfFunctionAndThirdDerivative(f(x - 2 * h), f(x - h), f(x),
-                                                                    f(x + h), f(x + 2 * h), h));
+                               quotientOfFunctionAndThirdDerivative(
+                                       f(x - 2 * h), f(x - h), f(x), f(x + h), f(x + 2 * h), h));
     }
     return static_cast<real>(minQuotient);
 }
@@ -299,9 +298,10 @@ real findSmallestQuotientOfFunctionAndThirdDerivative(ArrayRef<const double>
 
     for (std::size_t i = firstIndex + 2; (i + 2) < lastIndex; i++)
     {
-        minQuotient = std::min(minQuotient, quotientOfFunctionAndThirdDerivative(
-                                                    function[i - 2], function[i - 1], function[i],
-                                                    function[i + 1], function[i + 2], inputSpacing));
+        minQuotient = std::min(
+                minQuotient,
+                quotientOfFunctionAndThirdDerivative(
+                        function[i - 2], function[i - 1], function[i], function[i + 1], function[i + 2], inputSpacing));
     }
     return static_cast<real>(minQuotient);
 }
diff --git a/src/gromacs/tables/tests/.clang-tidy b/src/gromacs/tables/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 7af4e80c2c26c0f19266b12ea9f13c831fdea368..dd0d8ecb3af367d9c7ef17b34177e7e9c31fb1f5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <gtest/gtest.h>
 
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/options/ioptionscontainer.h"
@@ -137,8 +138,8 @@ void SplineTableTest<T>::testSplineTableAgainstFunctions(const std::string&
         real testFuncValue;
         real testDerValue;
 
-        table.template evaluateFunctionAndDerivative<numFuncInTable, funcIndex>(x, &testFuncValue,
-                                                                                &testDerValue);
+        table.template evaluateFunctionAndDerivative<numFuncInTable, funcIndex>(
+                x, &testFuncValue, &testDerValue);
 
         // Check that we get the same values from function/derivative-only methods
         real tmpFunc, tmpDer;
@@ -443,8 +444,8 @@ TYPED_TEST(SplineTableTest, PmeCorrection)
     TypeParam pmeCorrTable({ { "PMECorr", pmeCorrFunction, pmeCorrDerivative } }, range, tolerance);
 
     TestFixture::setTolerance(tolerance);
-    TestFixture::testSplineTableAgainstFunctions("PMECorr", pmeCorrFunction, pmeCorrDerivative,
-                                                 pmeCorrTable, range);
+    TestFixture::testSplineTableAgainstFunctions(
+            "PMECorr", pmeCorrFunction, pmeCorrDerivative, pmeCorrTable, range);
 }
 
 
@@ -512,12 +513,12 @@ TYPED_TEST(SplineTableTest, NumericalInputPmeCorr)
         derivativeValues.push_back(pmeCorrDerivative(x));
     }
 
-    TypeParam pmeCorrTable({ { "NumericalPMECorr", functionValues, derivativeValues, inputSpacing } },
-                           range, tolerance);
+    TypeParam pmeCorrTable(
+            { { "NumericalPMECorr", functionValues, derivativeValues, inputSpacing } }, range, tolerance);
 
     TestFixture::setTolerance(tolerance);
-    TestFixture::testSplineTableAgainstFunctions("NumericalPMECorr", pmeCorrFunction,
-                                                 pmeCorrDerivative, pmeCorrTable, range);
+    TestFixture::testSplineTableAgainstFunctions(
+            "NumericalPMECorr", pmeCorrFunction, pmeCorrDerivative, pmeCorrTable, range);
 }
 
 TYPED_TEST(SplineTableTest, TwoFunctions)
@@ -528,10 +529,10 @@ TYPED_TEST(SplineTableTest, TwoFunctions)
                     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);
+    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);
@@ -590,12 +591,12 @@ TYPED_TEST(SplineTableTest, ThreeFunctions)
                     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);
+    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);
@@ -653,8 +654,8 @@ TYPED_TEST(SplineTableTest, ThreeFunctions)
     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);
+    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);
index 22a1c70eec9ad851df1f6fe19f4d761d3e3a645c..f3db1e1e3c5c1c192082434e9e9900d59796f065 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 up the module library
+add_library(taskassignment INTERFACE)
+file(GLOB TASKASSIGNMENT_SOURCES *.cpp)
+set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${TASKASSIGNMENT_SOURCES} PARENT_SCOPE)
+
 # Note that this is a higher-level module that should not need
 # special compilation to suit e.g. GPU or MPI dependencies.
 # If you find you want to do that, consider a preliminary
 # refactoring.
-gmx_add_libgromacs_sources(
-    decidegpuusage.cpp
-    decidesimulationworkload.cpp
-    findallgputasks.cpp
-    reportgpuusage.cpp
-    resourcedivision.cpp
-    taskassignment.cpp
-    usergpuids.cpp
-    )
+
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(taskassignment PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(taskassignment PUBLIC
+target_include_directories(taskassignment INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(taskassignment PUBLIC
+target_link_libraries(taskassignment INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when taskassignment is an OBJECT target
+#target_link_libraries(taskassignment PUBLIC legacy_api)
+#target_link_libraries(taskassignment PRIVATE common)
+
+# Module dependencies
+# taskassignment interfaces convey transitive dependence on these modules.
+#target_link_libraries(taskassignment PUBLIC
+target_link_libraries(taskassignment INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(taskassignment PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(taskassignment PRIVATE legacy_modules)
 
 if (BUILD_TESTING)
     add_subdirectory(tests)
index 72d8e2a71aa58862801788cb9435c9a8e9999a85..d7fa6d2ade4845962ae4e2b4361e52a2a198849a 100644 (file)
@@ -83,7 +83,7 @@ namespace
 {
 
 //! Helper variable to localise the text of an often repeated message.
-const char* g_specifyEverythingFormatString =
+const char* const g_specifyEverythingFormatString =
         "When you use mdrun -gputasks, %s must be set to non-default "
         "values, so that the device IDs can be interpreted correctly."
 #if GMX_GPU
@@ -112,7 +112,7 @@ const char* g_specifyEverythingFormatString =
 } // namespace
 
 bool decideWhetherToUseGpusForNonbondedWithThreadMpi(const TaskTarget        nonbondedTarget,
-                                                     const int               numDevicesToUse,
+                                                     const bool              haveAvailableDevices,
                                                      const std::vector<int>& userGpuTaskAssignment,
                                                      const EmulateGpuNonbonded emulateGpuNonbonded,
                                                      const bool buildSupportsNonbondedOnGpu,
@@ -149,7 +149,7 @@ bool decideWhetherToUseGpusForNonbondedWithThreadMpi(const TaskTarget        non
     // all potential ranks can use, and can use that in a global
     // decision that will later be consistent.
     // If we get here, then the user permitted or required GPUs.
-    return (numDevicesToUse > 0);
+    return haveAvailableDevices;
 }
 
 bool decideWhetherToUseGpusForPmeWithThreadMpi(const bool              useGpuForNonbonded,
@@ -588,7 +588,8 @@ bool decideWhetherToUseGpuForUpdate(const bool                     isDomainDecom
         errorMessage += "Multiple time stepping is not supported.\n";
     }
 
-    if (inputrec.eConstrAlg == econtSHAKE && hasAnyConstraints && gmx_mtop_ftype_count(mtop, F_CONSTR) > 0)
+    if (inputrec.eConstrAlg == ConstraintAlgorithm::Shake && hasAnyConstraints
+        && gmx_mtop_ftype_count(mtop, F_CONSTR) > 0)
     {
         errorMessage += "SHAKE constraints are not supported.\n";
     }
@@ -609,16 +610,16 @@ bool decideWhetherToUseGpuForUpdate(const bool                     isDomainDecom
     {
         errorMessage += "Only a CUDA build is supported.\n";
     }
-    if (inputrec.eI != eiMD)
+    if (inputrec.eI != IntegrationAlgorithm::MD)
     {
         errorMessage += "Only the md integrator is supported.\n";
     }
-    if (inputrec.etc == etcNOSEHOOVER)
+    if (inputrec.etc == TemperatureCoupling::NoseHoover)
     {
         errorMessage += "Nose-Hoover temperature coupling is not supported.\n";
     }
-    if (!(inputrec.epc == epcNO || inputrec.epc == epcPARRINELLORAHMAN
-          || inputrec.epc == epcBERENDSEN || inputrec.epc == epcCRESCALE))
+    if (!(inputrec.epc == PressureCoupling::No || inputrec.epc == PressureCoupling::ParrinelloRahman
+          || inputrec.epc == PressureCoupling::Berendsen || inputrec.epc == PressureCoupling::CRescale))
     {
         errorMessage +=
                 "Only Parrinello-Rahman, Berendsen, and C-rescale pressure coupling are "
@@ -646,12 +647,13 @@ bool decideWhetherToUseGpuForUpdate(const bool                     isDomainDecom
         // The graph is needed, but not supported
         errorMessage += "Orientation restraints are not supported.\n";
     }
-    if (inputrec.efep != efepNO && (haveFepPerturbedMasses(mtop) || havePerturbedConstraints(mtop)))
+    if (inputrec.efep != FreeEnergyPerturbationType::No
+        && (haveFepPerturbedMasses(mtop) || havePerturbedConstraints(mtop)))
     {
         errorMessage += "Free energy perturbation for mass and constraints are not supported.\n";
     }
     const auto particleTypes = gmx_mtop_particletype_count(mtop);
-    if (particleTypes[eptShell] > 0)
+    if (particleTypes[ParticleType::Shell] > 0)
     {
         errorMessage += "Shells are not supported.\n";
     }
@@ -659,7 +661,7 @@ bool decideWhetherToUseGpuForUpdate(const bool                     isDomainDecom
     {
         errorMessage += "Replica exchange simulations are not supported.\n";
     }
-    if (inputrec.eSwapCoords != eswapNO)
+    if (inputrec.eSwapCoords != SwapType::No)
     {
         errorMessage += "Swapping the coordinates is not supported.\n";
     }
index 765636c448dec7cb1f69c683270c0bfc1b3322f6..98d0251c33c93fb3ab5e36bdb770a42ce248b59e 100644 (file)
@@ -88,6 +88,8 @@ struct DevelopmentFeatureFlags
     bool enableGpuHaloExchange = false;
     //! True if the PME PP direct communication GPU development feature is enabled
     bool enableGpuPmePPComm = false;
+    //! True if the CUDA-aware MPI is being used for GPU direct communication feature
+    bool usingCudaAwareMpi = false;
 };
 
 
@@ -103,8 +105,7 @@ class MDAtoms;
  *
  * \param[in] nonbondedTarget              The user's choice for mdrun -nb for where to assign
  *                                         short-ranged nonbonded interaction tasks.
- * \param[in] numDevicesToUse              Number of compatible GPUs that the user permitted
- *                                         us to use.
+ * \param[in] haveAvailableDevices         Whether there are available devices.
  * \param[in] userGpuTaskAssignment        The user-specified assignment of GPU tasks to device IDs.
  * \param[in] emulateGpuNonbonded          Whether we will emulate GPU calculation of nonbonded
  *                                         interactions.
@@ -118,7 +119,7 @@ class MDAtoms;
  * \throws     std::bad_alloc          If out of memory
  *             InconsistentInputError  If the user requirements are inconsistent. */
 bool decideWhetherToUseGpusForNonbondedWithThreadMpi(TaskTarget              nonbondedTarget,
-                                                     int                     numDevicesToUse,
+                                                     bool                    haveAvailableDevices,
                                                      const std::vector<int>& userGpuTaskAssignment,
                                                      EmulateGpuNonbonded     emulateGpuNonbonded,
                                                      bool buildSupportsNonbondedOnGpu,
index d1b403362d185bae3ff11b479a51b3b0793def76..24612e648cdace66f790f80de3480cc9c3cd9dd1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -138,8 +138,7 @@ std::vector<int> allgather(const int& input, int numRanks, MPI_Comm communicator
         // to compile warning-free with all versions of MPI headers.
         //
         // TODO Make an allgather template to deal with this nonsense.
-        MPI_Gather(const_cast<int*>(&input), 1, MPI_INT, const_cast<int*>(result.data()), 1,
-                   MPI_INT, root, communicator);
+        MPI_Gather(const_cast<int*>(&input), 1, MPI_INT, const_cast<int*>(result.data()), 1, MPI_INT, root, communicator);
         MPI_Bcast(const_cast<int*>(result.data()), result.size(), MPI_INT, root, communicator);
 #else
         GMX_UNUSED_VALUE(communicator);
@@ -158,8 +157,8 @@ std::vector<int> computeDisplacements(ArrayRef<const int> extentOnEachRank, int
 {
     std::vector<int> displacements(numRanks + 1);
     displacements[0] = 0;
-    std::partial_sum(std::begin(extentOnEachRank), std::end(extentOnEachRank),
-                     std::begin(displacements) + 1);
+    std::partial_sum(
+            std::begin(extentOnEachRank), std::end(extentOnEachRank), std::begin(displacements) + 1);
     return displacements;
 }
 
@@ -185,9 +184,15 @@ std::vector<GpuTask> allgatherv(ArrayRef<const GpuTask> input,
         int root = 0;
         // Calling a C API with the const T * from data() doesn't seem to compile reliably.
         // TODO Make an allgatherv template to deal with this nonsense.
-        MPI_Gatherv(const_cast<GpuTask*>(input.data()), input.size(), MPI_INT,
-                    const_cast<GpuTask*>(result.data()), const_cast<int*>(extentOnEachRank.data()),
-                    const_cast<int*>(displacementForEachRank.data()), MPI_INT, root, communicator);
+        MPI_Gatherv(const_cast<GpuTask*>(input.data()),
+                    input.size(),
+                    MPI_INT,
+                    const_cast<GpuTask*>(result.data()),
+                    const_cast<int*>(extentOnEachRank.data()),
+                    const_cast<int*>(displacementForEachRank.data()),
+                    MPI_INT,
+                    root,
+                    communicator);
         MPI_Bcast(const_cast<GpuTask*>(result.data()), result.size(), MPI_INT, root, communicator);
 #else
         GMX_UNUSED_VALUE(communicator);
@@ -227,8 +232,8 @@ GpuTasksOnRanks findAllGpuTasksOnThisNode(ArrayRef<const GpuTask>         gpuTas
      * the vector. */
     auto displacementsForEachRank =
             computeDisplacements(numGpuTasksOnEachRankOfThisNode, numRanksOnThisNode);
-    auto gpuTasksOnThisNode = allgatherv(gpuTasksOnThisRank, numGpuTasksOnEachRankOfThisNode,
-                                         displacementsForEachRank, communicator);
+    auto gpuTasksOnThisNode = allgatherv(
+            gpuTasksOnThisRank, numGpuTasksOnEachRankOfThisNode, displacementsForEachRank, communicator);
 
     /* Next, we re-use the displacements to break up the vector
      * of GPU tasks into something that can be indexed like
@@ -245,8 +250,8 @@ GpuTasksOnRanks findAllGpuTasksOnThisNode(ArrayRef<const GpuTask>         gpuTas
     do
     {
         gpuTasksOnRanksOfThisNode.emplace_back(std::vector<GpuTask>());
-        for (auto taskOnThisRankIndex = *currentDisplacementIt;
-             taskOnThisRankIndex != *nextDisplacementIt; ++taskOnThisRankIndex)
+        for (auto taskOnThisRankIndex = *currentDisplacementIt; taskOnThisRankIndex != *nextDisplacementIt;
+             ++taskOnThisRankIndex)
         {
             gpuTasksOnRanksOfThisNode.back().push_back(gpuTasksOnThisNode[taskOnThisRankIndex]);
         }
index bdcde8beb18ea8cc4512930edf7fb42a09915f6b..a320ae08bddf8bc03918e409a76c2675d931c0cb 100644 (file)
@@ -131,8 +131,12 @@ void reportGpuUsage(const MDLogger&                   mdlog,
         output += gmx::formatString(
                 "%zu GPU%s selected for this run.\n"
                 "Mapping of GPU IDs to the %zu GPU task%s in the %zu rank%s on this node:\n  %s\n",
-                numGpusInUse, bPluralGpus ? "s" : "", numGpuTasksOnThisNode,
-                (numGpuTasksOnThisNode > 1) ? "s" : "", numRanks, (numRanks > 1) ? "s" : "",
+                numGpusInUse,
+                bPluralGpus ? "s" : "",
+                numGpuTasksOnThisNode,
+                (numGpuTasksOnThisNode > 1) ? "s" : "",
+                numRanks,
+                (numRanks > 1) ? "s" : "",
                 gpuIdsString.c_str());
         // Because there is a GPU in use, there must be a PP task on a GPU.
         output += gmx::formatString(
index 143a35c244cae0aee9551ce049468ea7081e627f..42c5b64a06b8fe793d9abddda2279ecd7807903e 100644 (file)
@@ -346,7 +346,7 @@ int get_nthreads_mpi(const gmx_hw_info_t* hwinfo,
                      bool                 nonbondedOnGpu,
                      bool                 pmeOnGpu,
                      const t_inputrec*    inputrec,
-                     const gmx_mtop_t*    mtop,
+                     const gmx_mtop_t&    mtop,
                      const gmx::MDLogger& mdlog,
                      bool                 doMembed)
 {
@@ -378,8 +378,9 @@ int get_nthreads_mpi(const gmx_hw_info_t* hwinfo,
         // had to define a function that returns such requirements,
         // and a description string.
         SingleRankChecker checker;
-        checker.applyConstraint(inputrec->eI == eiLBFGS, "L-BFGS minimization");
-        checker.applyConstraint(inputrec->coulombtype == eelEWALD, "Plain Ewald electrostatics");
+        checker.applyConstraint(inputrec->eI == IntegrationAlgorithm::LBFGS, "L-BFGS minimization");
+        checker.applyConstraint(inputrec->coulombtype == CoulombInteractionType::Ewald,
+                                "Plain Ewald electrostatics");
         checker.applyConstraint(doMembed, "Membrane embedding");
         bool useOrientationRestraints = (gmx_mtop_ftype_count(mtop, F_ORIRES) > 0);
         checker.applyConstraint(useOrientationRestraints, "Orientation restraints");
@@ -437,7 +438,7 @@ int get_nthreads_mpi(const gmx_hw_info_t* hwinfo,
 
     nrank = get_tmpi_omp_thread_division(hwinfo, *hw_opt, nthreads_tot_max, ngpu);
 
-    if (inputrec->eI == eiNM || EI_TPI(inputrec->eI))
+    if (inputrec->eI == IntegrationAlgorithm::NM || EI_TPI(inputrec->eI))
     {
         /* Dims/steps are divided over the nodes iso splitting the atoms.
          * With NM we can't have more ranks than #atoms*#dim. With TPI it's
@@ -458,13 +459,13 @@ int get_nthreads_mpi(const gmx_hw_info_t* hwinfo,
         }
     }
 
-    if (mtop->natoms / nrank < min_atoms_per_mpi_rank)
+    if (mtop.natoms / nrank < min_atoms_per_mpi_rank)
     {
         int nrank_new;
 
         /* the rank number was chosen automatically, but there are too few
            atoms per rank, so we need to reduce the rank count */
-        nrank_new = std::max(1, mtop->natoms / min_atoms_per_mpi_rank);
+        nrank_new = std::max(1, mtop.natoms / min_atoms_per_mpi_rank);
 
         /* Avoid partial use of Hyper-Threading */
         if (gmxSmtIsEnabled(hwTop) && nrank_new > nthreads_hw / 2 && nrank_new < nthreads_hw)
@@ -581,10 +582,10 @@ void check_resource_division_efficiency(const gmx_hw_info_t* hwinfo,
         GMX_RELEASE_ASSERT(nthreads_omp_faster_default >= nthreads_omp_mpi_ok_max,
                            "Inconsistent OpenMP thread count default values");
     }
-    GMX_RELEASE_ASSERT(gmx_omp_nthreads_get(emntDefault) >= 1,
+    GMX_RELEASE_ASSERT(gmx_omp_nthreads_get(ModuleMultiThread::Default) >= 1,
                        "Must have at least one OpenMP thread");
 
-    nth_omp_max = gmx_omp_nthreads_get(emntDefault);
+    nth_omp_max = gmx_omp_nthreads_get(ModuleMultiThread::Default);
 
     bool anyRankIsUsingGpus = willUsePhysicalGpu;
     /* Thread-MPI seems to have a bug with reduce on 1 node, so use a cond. */
@@ -627,7 +628,9 @@ void check_resource_division_efficiency(const gmx_hw_info_t* hwinfo,
                     "threads per rank, which is most likely inefficient. The optimum is usually "
                     "between %d and"
                     " %d threads per rank.",
-                    nth_omp_max, nthreads_omp_mpi_ok_min, nthreads_omp_mpi_target_max);
+                    nth_omp_max,
+                    nthreads_omp_mpi_ok_min,
+                    nthreads_omp_mpi_target_max);
 
             if (bNtOmpOptionSet)
             {
@@ -643,7 +646,8 @@ void check_resource_division_efficiency(const gmx_hw_info_t* hwinfo,
                           "%s If you want to run with this setup, specify the -ntomp option. But "
                           "we suggest to "
                           "change the number of MPI ranks%s.",
-                          buf, mpi_option);
+                          buf,
+                          mpi_option);
             }
         }
     }
@@ -671,9 +675,14 @@ void check_resource_division_efficiency(const gmx_hw_info_t* hwinfo,
 //! Dump a \c hw_opt to \c fp.
 static void print_hw_opt(FILE* fp, const gmx_hw_opt_t* hw_opt)
 {
-    fprintf(fp, "hw_opt: nt %d ntmpi %d ntomp %d ntomp_pme %d gpu_id '%s' gputasks '%s'\n",
-            hw_opt->nthreads_tot, hw_opt->nthreads_tmpi, hw_opt->nthreads_omp, hw_opt->nthreads_omp_pme,
-            hw_opt->gpuIdsAvailable.c_str(), hw_opt->userGpuTaskAssignment.c_str());
+    fprintf(fp,
+            "hw_opt: nt %d ntmpi %d ntomp %d ntomp_pme %d gpu_id '%s' gputasks '%s'\n",
+            hw_opt->nthreads_tot,
+            hw_opt->nthreads_tmpi,
+            hw_opt->nthreads_omp,
+            hw_opt->nthreads_omp_pme,
+            hw_opt->devicesSelectedByUser.c_str(),
+            hw_opt->userGpuTaskAssignment.c_str());
 }
 
 void checkAndUpdateHardwareOptions(const gmx::MDLogger& mdlog,
@@ -790,7 +799,9 @@ void checkAndUpdateHardwareOptions(const gmx::MDLogger& mdlog,
                       "The total number of threads requested (%d) does not match the thread-MPI "
                       "ranks (%d) "
                       "times the OpenMP threads (%d) requested",
-                      hw_opt->nthreads_tot, hw_opt->nthreads_tmpi, hw_opt->nthreads_omp);
+                      hw_opt->nthreads_tot,
+                      hw_opt->nthreads_tmpi,
+                      hw_opt->nthreads_omp);
         }
 
         if (hw_opt->nthreads_tmpi > 0 && hw_opt->nthreads_tot % hw_opt->nthreads_tmpi != 0)
@@ -799,7 +810,8 @@ void checkAndUpdateHardwareOptions(const gmx::MDLogger& mdlog,
                       "The total number of threads requested (%d) is not divisible by the number "
                       "of thread-MPI "
                       "ranks requested (%d)",
-                      hw_opt->nthreads_tot, hw_opt->nthreads_tmpi);
+                      hw_opt->nthreads_tot,
+                      hw_opt->nthreads_tmpi);
         }
 
         if (hw_opt->nthreads_omp > 0 && hw_opt->nthreads_tot % hw_opt->nthreads_omp != 0)
@@ -808,7 +820,8 @@ void checkAndUpdateHardwareOptions(const gmx::MDLogger& mdlog,
                       "The total number of threads requested (%d) is not divisible by the number "
                       "of OpenMP "
                       "threads requested (%d)",
-                      hw_opt->nthreads_tot, hw_opt->nthreads_omp);
+                      hw_opt->nthreads_tot,
+                      hw_opt->nthreads_omp);
         }
     }
 
@@ -820,7 +833,8 @@ void checkAndUpdateHardwareOptions(const gmx::MDLogger& mdlog,
                       "You requested %d OpenMP threads with %d total threads. Choose a total "
                       "number of threads "
                       "that is a multiple of the number of OpenMP threads.",
-                      hw_opt->nthreads_omp, hw_opt->nthreads_tot);
+                      hw_opt->nthreads_omp,
+                      hw_opt->nthreads_tot);
         }
 
         if (hw_opt->nthreads_tmpi > hw_opt->nthreads_tot)
@@ -829,7 +843,8 @@ void checkAndUpdateHardwareOptions(const gmx::MDLogger& mdlog,
                       "You requested %d thread-MPI ranks with %d total threads. Choose a total "
                       "number of "
                       "threads that is a multiple of the number of thread-MPI ranks.",
-                      hw_opt->nthreads_tmpi, hw_opt->nthreads_tot);
+                      hw_opt->nthreads_tmpi,
+                      hw_opt->nthreads_tot);
         }
     }
 
index c45ed954939848314a45f63525b9bc8043ae7e67..f9e7151186a63c39fece0bae03ae09b871f6c311 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -79,7 +79,7 @@ int get_nthreads_mpi(const gmx_hw_info_t* hwinfo,
                      bool                 nonbondedOnGpu,
                      bool                 pmeOnGpu,
                      const t_inputrec*    inputrec,
-                     const gmx_mtop_t*    mtop,
+                     const gmx_mtop_t&    mtop,
                      const gmx::MDLogger& mdlog,
                      bool                 doMembed);
 
index 2a823e57281a1f80357c7d9470d65db8af8caf31..34acebbd268dadc9f5155820cba1a3af6d855363 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +154,9 @@ bool isAnyGpuSharedBetweenRanks(ArrayRef<const GpuTaskAssignment> gpuTaskAssignm
 
 } // namespace
 
-void GpuTaskAssignments::logPerformanceHints(const MDLogger& mdlog, size_t numCompatibleGpusOnThisNode)
+void GpuTaskAssignments::logPerformanceHints(const MDLogger& mdlog, size_t numAvailableDevicesOnThisNode)
 {
-    if (numCompatibleGpusOnThisNode > numGpuTasksOnThisNode_)
+    if (numAvailableDevicesOnThisNode > numGpuTasksOnThisNode_)
     {
         /* TODO In principle, this warning could be warranted only on
          * some nodes, but we lack the infrastructure to do a good job
@@ -234,10 +234,10 @@ void barrierOverAllRanks(MPI_Comm comm)
 
 GpuTaskAssignmentsBuilder::GpuTaskAssignmentsBuilder() = default;
 
-GpuTaskAssignments GpuTaskAssignmentsBuilder::build(const std::vector<int>& gpuIdsToUse,
-                                                    const std::vector<int>& userGpuTaskAssignment,
-                                                    const gmx_hw_info_t&    hardwareInfo,
-                                                    MPI_Comm                gromacsWorldComm,
+GpuTaskAssignments GpuTaskAssignmentsBuilder::build(const gmx::ArrayRef<const int> availableDevices,
+                                                    const gmx::ArrayRef<const int> userGpuTaskAssignment,
+                                                    const gmx_hw_info_t&           hardwareInfo,
+                                                    MPI_Comm                       gromacsWorldComm,
                                                     const PhysicalNodeCommunicator& physicalNodeComm,
                                                     const TaskTarget                nonbondedTarget,
                                                     const TaskTarget                pmeTarget,
@@ -249,9 +249,15 @@ GpuTaskAssignments GpuTaskAssignmentsBuilder::build(const std::vector<int>& gpuI
                                                     bool       rankHasPmeTask)
 {
     size_t               numRanksOnThisNode = physicalNodeComm.size_;
-    std::vector<GpuTask> gpuTasksOnThisRank = findGpuTasksOnThisRank(
-            !gpuIdsToUse.empty(), nonbondedTarget, pmeTarget, bondedTarget, updateTarget,
-            useGpuForNonbonded, useGpuForPme, rankHasPpTask, rankHasPmeTask);
+    std::vector<GpuTask> gpuTasksOnThisRank = findGpuTasksOnThisRank(!availableDevices.empty(),
+                                                                     nonbondedTarget,
+                                                                     pmeTarget,
+                                                                     bondedTarget,
+                                                                     updateTarget,
+                                                                     useGpuForNonbonded,
+                                                                     useGpuForPme,
+                                                                     rankHasPpTask,
+                                                                     rankHasPmeTask);
     /* Communicate among ranks on this node to find each task that can
      * be executed on a GPU, on each rank. */
     auto gpuTasksOnRanksOfThisNode = findAllGpuTasksOnThisNode(gpuTasksOnThisRank, physicalNodeComm);
@@ -259,6 +265,7 @@ GpuTaskAssignments GpuTaskAssignmentsBuilder::build(const std::vector<int>& gpuI
 
     std::exception_ptr             exceptionPtr;
     std::vector<GpuTaskAssignment> taskAssignmentOnRanksOfThisNode;
+    std::vector<int>               deviceIdAssignment;
     try
     {
         // Use the GPU IDs from the user if they supplied
@@ -277,11 +284,10 @@ GpuTaskAssignments GpuTaskAssignmentsBuilder::build(const std::vector<int>& gpuI
         // runtime, and subject to environment modification such as
         // with CUDA_VISIBLE_DEVICES) that will be used for the
         // GPU-suitable tasks on all of the ranks of that node.
-        ArrayRef<const int> gpuIdsForTaskAssignment;
-        std::vector<int>    generatedGpuIds;
+        std::vector<int> generatedGpuIds;
         if (userGpuTaskAssignment.empty())
         {
-            ArrayRef<const int> compatibleGpusToUse = gpuIdsToUse;
+            ArrayRef<const int> compatibleGpusToUse = availableDevices;
 
             // enforce the single device/rank restriction
             if (numRanksOnThisNode == 1 && !compatibleGpusToUse.empty())
@@ -295,8 +301,8 @@ GpuTaskAssignments GpuTaskAssignmentsBuilder::build(const std::vector<int>& gpuI
             // but we don't have any way to do a better job reliably.
             generatedGpuIds = makeGpuIds(compatibleGpusToUse, numGpuTasksOnThisNode);
 
-            if ((numGpuTasksOnThisNode > gpuIdsToUse.size())
-                && (numGpuTasksOnThisNode % gpuIdsToUse.size() != 0))
+            if ((numGpuTasksOnThisNode > availableDevices.size())
+                && (numGpuTasksOnThisNode % availableDevices.size() != 0))
             {
                 // TODO Decorating the message with hostname should be
                 // the job of an error-reporting module.
@@ -310,9 +316,11 @@ GpuTaskAssignments GpuTaskAssignmentsBuilder::build(const std::vector<int>& gpuI
                         "You should reconsider your GPU task assignment, "
                         "number of ranks, or your use of the -nb, -pme, and -npme options, "
                         "perhaps after measuring the performance you can get.",
-                        numGpuTasksOnThisNode, host, gpuIdsToUse.size())));
+                        numGpuTasksOnThisNode,
+                        host,
+                        availableDevices.size())));
             }
-            gpuIdsForTaskAssignment = generatedGpuIds;
+            deviceIdAssignment = generatedGpuIds;
         }
         else
         {
@@ -327,15 +335,17 @@ GpuTaskAssignments GpuTaskAssignmentsBuilder::build(const std::vector<int>& gpuI
                         "There were %zu GPU tasks assigned on node %s, but %zu GPU tasks were "
                         "identified, and these must match. Reconsider your GPU task assignment, "
                         "number of ranks, or your use of the -nb, -pme, and -npme options.",
-                        userGpuTaskAssignment.size(), host, numGpuTasksOnThisNode)));
+                        userGpuTaskAssignment.size(),
+                        host,
+                        numGpuTasksOnThisNode)));
             }
             // Did the user choose compatible GPUs?
-            checkUserGpuIds(hardwareInfo.deviceInfoList, gpuIdsToUse, userGpuTaskAssignment);
+            checkUserGpuIds(hardwareInfo.deviceInfoList, availableDevices, userGpuTaskAssignment);
 
-            gpuIdsForTaskAssignment = userGpuTaskAssignment;
+            deviceIdAssignment = gmx::copyOf(userGpuTaskAssignment);
         }
         taskAssignmentOnRanksOfThisNode =
-                buildTaskAssignment(gpuTasksOnRanksOfThisNode, gpuIdsForTaskAssignment);
+                buildTaskAssignment(gpuTasksOnRanksOfThisNode, deviceIdAssignment);
     }
     catch (...)
     {
@@ -382,6 +392,11 @@ GpuTaskAssignments GpuTaskAssignmentsBuilder::build(const std::vector<int>& gpuI
     gpuTaskAssignments.indexOfThisRank_                 = physicalNodeComm.rank_;
     gpuTaskAssignments.numGpuTasksOnThisNode_           = numGpuTasksOnThisNode;
     gpuTaskAssignments.numRanksOnThisNode_              = numRanksOnThisNode;
+    gpuTaskAssignments.deviceIdsAssigned_               = deviceIdAssignment;
+    std::sort(gpuTaskAssignments.deviceIdsAssigned_.begin(), gpuTaskAssignments.deviceIdsAssigned_.end());
+    gpuTaskAssignments.deviceIdsAssigned_.erase(unique(gpuTaskAssignments.deviceIdsAssigned_.begin(),
+                                                       gpuTaskAssignments.deviceIdsAssigned_.end()),
+                                                gpuTaskAssignments.deviceIdsAssigned_.end());
     return gpuTaskAssignments;
 }
 
@@ -396,8 +411,14 @@ void GpuTaskAssignments::reportGpuUsage(const MDLogger& mdlog,
                                         PmeRunMode      pmeRunMode,
                                         bool            useGpuForUpdate)
 {
-    gmx::reportGpuUsage(mdlog, assignmentForAllRanksOnThisNode_, numGpuTasksOnThisNode_,
-                        numRanksOnThisNode_, printHostName, useGpuForBonded, pmeRunMode, useGpuForUpdate);
+    gmx::reportGpuUsage(mdlog,
+                        assignmentForAllRanksOnThisNode_,
+                        numGpuTasksOnThisNode_,
+                        numRanksOnThisNode_,
+                        printHostName,
+                        useGpuForBonded,
+                        pmeRunMode,
+                        useGpuForUpdate);
 }
 
 /*! \brief Function for whether the task of \c mapping has value \c TaskType.
@@ -443,8 +464,8 @@ bool GpuTaskAssignments::thisRankHasPmeGpuTask() const
 {
     const GpuTaskAssignment& gpuTaskAssignment = assignmentForAllRanksOnThisNode_[indexOfThisRank_];
 
-    auto       pmeGpuTaskMapping = std::find_if(gpuTaskAssignment.begin(), gpuTaskAssignment.end(),
-                                          hasTaskType<GpuTask::Pme>);
+    auto pmeGpuTaskMapping = std::find_if(
+            gpuTaskAssignment.begin(), gpuTaskAssignment.end(), hasTaskType<GpuTask::Pme>);
     const bool thisRankHasPmeGpuTask = (pmeGpuTaskMapping != gpuTaskAssignment.end());
 
     return thisRankHasPmeGpuTask;
index f709f24e4067e0a6813bc36bb9266ec03a297f0d..1267de148af9ee052d5d3bb972acd3e797667d56 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +52,7 @@
 
 #include <vector>
 
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/gmxmpi.h"
 
@@ -140,7 +141,7 @@ public:
      * the ranks of that node. It throws InconsistentInputError
      * when a/the useful GPU task assignment is not possible.
      *
-     * \param[in]  gpuIdsToUse            The compatible GPUs that the user permitted us to use.
+     * \param[in]  availableDevices       The compatible devices that the user permitted us to use.
      * \param[in]  userGpuTaskAssignment  The user-specified assignment of GPU tasks to device IDs.
      * \param[in]  hardwareInfo           The detected hardware
      * \param[in]  gromacsWorldComm       MPI communicator for all ranks in the current GROMACS run
@@ -159,8 +160,8 @@ public:
      * \throws   std::bad_alloc          If out of memory.
      *           InconsistentInputError  If user and/or detected inputs are inconsistent.
      */
-    static GpuTaskAssignments build(const std::vector<int>&         gpuIdsToUse,
-                                    const std::vector<int>&         userGpuTaskAssignment,
+    static GpuTaskAssignments build(ArrayRef<const int>             availableDevices,
+                                    ArrayRef<const int>             userGpuTaskAssignment,
                                     const gmx_hw_info_t&            hardwareInfo,
                                     MPI_Comm                        gromacsWorldComm,
                                     const PhysicalNodeCommunicator& physicalNodeComm,
@@ -210,6 +211,9 @@ private:
     //! Number of ranks on this physical node.
     size_t numRanksOnThisNode_ = 0;
 
+    //! Vector of device IDs assigned to this node
+    std::vector<int> deviceIdsAssigned_;
+
 public:
     /*! \brief Log a report on how GPUs are being used on
      * the ranks of the physical node of rank 0 of the simulation.
@@ -235,10 +239,11 @@ public:
      * learn how to let mdrun make a task assignment that runs
      * faster.
      *
-     * \param[in]  mdlog                        Logging object.
-     * \param[in]  numCompatibleGpusOnThisNode  The number of compatible GPUs on this node.
+     * \param[in]  mdlog                         Logging object.
+     * \param[in]  numAvailableDevicesOnThisNode The number of compatible devices on this node
+     *                                           that the user permitted us to use.
      * */
-    void logPerformanceHints(const MDLogger& mdlog, size_t numCompatibleGpusOnThisNode);
+    void logPerformanceHints(const MDLogger& mdlog, size_t numAvailableDevicesOnThisNode);
     /*! \brief Return handle to the initialized GPU to use in the this rank.
      *
      * \param[out] deviceId Index of the assigned device.
@@ -251,6 +256,8 @@ public:
     bool thisRankHasPmeGpuTask() const;
     //! Return whether this rank has any task running on a GPU
     bool thisRankHasAnyGpuTask() const;
+    //! Get the list of unique devices that have been assigned tasks on this physical node
+    std::vector<int> deviceIdsAssigned() { return deviceIdsAssigned_; }
 };
 
 } // namespace gmx
diff --git a/src/gromacs/taskassignment/tests/.clang-tidy b/src/gromacs/taskassignment/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 8271d00913d467ad258f6694760049954a78f4e4..0162f2eb4fe10f335b61edb9f520c32e3f0b6dfb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,41 +136,41 @@ std::vector<int> parseUserGpuIdString(const std::string& gpuIdString)
     return digits;
 }
 
-std::vector<int> makeGpuIdsToUse(const std::vector<std::unique_ptr<DeviceInformation>>& deviceInfoList,
-                                 const std::string& gpuIdsAvailableString)
+std::vector<int> makeListOfAvailableDevices(gmx::ArrayRef<const std::unique_ptr<DeviceInformation>> deviceInfoList,
+                                            const std::string& devicesSelectedByUserString)
 {
-    std::vector<int> gpuIdsAvailable = parseUserGpuIdString(gpuIdsAvailableString);
+    std::vector<int> devicesSelectedByUser = parseUserGpuIdString(devicesSelectedByUserString);
 
-    if (gpuIdsAvailable.empty())
+    if (devicesSelectedByUser.empty())
     {
-        // The user didn't restrict the choice, so we use all compatible GPUs
+        // The user didn't restrict the choice, so we use all compatible devices.
         return getCompatibleDeviceIds(deviceInfoList);
     }
 
-    std::vector<int> gpuIdsToUse;
-    gpuIdsToUse.reserve(gpuIdsAvailable.size());
-    std::vector<int> availableGpuIdsThatAreIncompatible;
-    for (const int& availableGpuId : gpuIdsAvailable)
+    std::vector<int> availableDevices;
+    availableDevices.reserve(devicesSelectedByUser.size());
+    std::vector<int> incompatibleDevicesSelectedByUser;
+    for (const int& selectedDeviceId : devicesSelectedByUser)
     {
-        if (deviceIdIsCompatible(deviceInfoList, availableGpuId))
+        if (deviceIdIsCompatible(deviceInfoList, selectedDeviceId))
         {
-            gpuIdsToUse.push_back(availableGpuId);
+            availableDevices.push_back(selectedDeviceId);
         }
         else
         {
-            // Prepare data for an error message about all incompatible available GPU IDs.
-            availableGpuIdsThatAreIncompatible.push_back(availableGpuId);
+            // Prepare data for an error message about all incompatible devices that were selected by the user.
+            incompatibleDevicesSelectedByUser.push_back(selectedDeviceId);
         }
     }
-    if (!availableGpuIdsThatAreIncompatible.empty())
+    if (!incompatibleDevicesSelectedByUser.empty())
     {
-        auto message = "You requested mdrun to use GPUs with IDs " + gpuIdsAvailableString
-                       + ", but that includes the following incompatible GPUs: "
-                       + formatAndJoin(availableGpuIdsThatAreIncompatible, ",", StringFormatter("%d"))
-                       + ". Request only compatible GPUs.";
+        auto message = "You requested mdrun to use GPU devices with IDs " + devicesSelectedByUserString
+                       + ", but that includes the following incompatible devices: "
+                       + formatAndJoin(incompatibleDevicesSelectedByUser, ",", StringFormatter("%d"))
+                       + ". Request only compatible devices.";
         GMX_THROW(InvalidInputError(message));
     }
-    return gpuIdsToUse;
+    return availableDevices;
 }
 
 std::vector<int> parseUserTaskAssignmentString(const std::string& gpuIdString)
@@ -209,9 +209,9 @@ std::string makeGpuIdString(const std::vector<int>& gpuIds, int totalNumberOfTas
     return formatAndJoin(resultGpuIds, ",", StringFormatter("%d"));
 }
 
-void checkUserGpuIds(const std::vector<std::unique_ptr<DeviceInformation>>& deviceInfoList,
-                     const std::vector<int>&                                compatibleGpus,
-                     const std::vector<int>&                                gpuIds)
+void checkUserGpuIds(const ArrayRef<const std::unique_ptr<DeviceInformation>> deviceInfoList,
+                     const ArrayRef<const int>                                compatibleGpus,
+                     const ArrayRef<const int>                                gpuIds)
 {
     bool        foundIncompatibleGpuIds = false;
     std::string message =
@@ -222,7 +222,8 @@ void checkUserGpuIds(const std::vector<std::unique_ptr<DeviceInformation>>& devi
         if (std::find(compatibleGpus.begin(), compatibleGpus.end(), gpuId) == compatibleGpus.end())
         {
             foundIncompatibleGpuIds = true;
-            message += gmx::formatString("    GPU #%d: %s\n", gpuId,
+            message += gmx::formatString("    GPU #%d: %s\n",
+                                         gpuId,
                                          getDeviceCompatibilityDescription(deviceInfoList, gpuId).c_str());
         }
     }
index e85d15bf18d6d446956ffaff249af399b6e00016..c6c89aa5781fccc17ab9923adb1a69ce777e0c2e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,24 +84,24 @@ std::vector<int> parseUserGpuIdString(const std::string& gpuIdString);
  * all compatible GPUs on this physical node. Otherwise, check the
  * user specified compatible GPUs and return their IDs.
  *
- * \param[in]  deviceInfoList         Information on the GPUs on this physical node.
- * \param[in]  gpuIdsAvailableString  String like "013" or "0,1,3" typically
- *                                    supplied by the user to mdrun -gpu_id.
- *                                    Must contain only unique decimal digits, or only decimal
- *                                    digits separated by comma delimiters. A terminal
- *                                    comma is accceptable (and required to specify a
- *                                    single ID that is larger than 9).
+ * \param[in]  deviceInfoList               Information on the GPUs on this physical node.
+ * \param[in]  devicesSelectedByUserString  String like "013" or "0,1,3" typically
+ *                                          supplied by the user to mdrun -gpu_id.
+ *                                          Must contain only unique decimal digits, or only decimal
+ *                                          digits separated by comma delimiters. A terminal
+ *                                          comma is accceptable (and required to specify a
+ *                                          single ID that is larger than 9).
  *
  * \returns  A vector of unique compatible GPU IDs on this physical node.
  *
  * \throws   std::bad_alloc     If out of memory.
  *           InvalidInputError  If an invalid character is found (ie not a digit or ',') or if
  *                              identifiers are duplicated in the specifier list.
- *           InvalidInputError  If gpuIdsAvailableString specifies GPU IDs that are
+ *           InvalidInputError  If devicesSelectedByUserString specifies IDs of the devices that are
  *                              not compatible.
  */
-std::vector<int> makeGpuIdsToUse(const std::vector<std::unique_ptr<DeviceInformation>>& deviceInfoList,
-                                 const std::string& gpuIdsAvailableString);
+std::vector<int> makeListOfAvailableDevices(gmx::ArrayRef<const std::unique_ptr<DeviceInformation>> deviceInfoList,
+                                            const std::string& devicesSelectedByUserString);
 
 /*! \brief Parse a GPU ID specifier string into a container describing device ID to task mapping.
  *
@@ -172,9 +172,9 @@ std::string makeGpuIdString(const std::vector<int>& gpuIds, int totalNumberOfTas
  * \throws  std::bad_alloc          If out of memory
  *          InconsistentInputError  If the assigned GPUs are not valid
  */
-void checkUserGpuIds(const std::vector<std::unique_ptr<DeviceInformation>>& deviceInfoList,
-                     const std::vector<int>&                                compatibleGpus,
-                     const std::vector<int>&                                gpuIds);
+void checkUserGpuIds(ArrayRef<const std::unique_ptr<DeviceInformation>> deviceInfoList,
+                     ArrayRef<const int>                                compatibleGpus,
+                     ArrayRef<const int>                                gpuIds);
 
 } // namespace gmx
 
index cf359bd487d5c933a92a5fbc1b47b64b80aedc72..15f2500e56e5900b7d19dbc640dcba3524199724 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2013,2014,2015,2019, by the GROMACS development team, led by
+# Copyright (c) 2013,2014,2015,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(timing INTERFACE)
 file(GLOB TIMING_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${TIMING_SOURCES} PARENT_SCOPE)
 
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(timing PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(timing PUBLIC
+target_include_directories(timing INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(timing PUBLIC
+target_link_libraries(timing INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when timing is an OBJECT target
+#target_link_libraries(timing PUBLIC legacy_api)
+#target_link_libraries(timing PRIVATE common)
+
+# Module dependencies
+# timing interfaces convey transitive dependence on these modules.
+#target_link_libraries(timing PUBLIC
+target_link_libraries(timing INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(timing PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(timing PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
-#    add_subdirectory(tests)
+    add_subdirectory(tests)
 endif()
index bcefcac5ba39d7a4106fa1f7e96aa2848a5d43cb..24768bc59ac6ce73565f4528829eee4225278770 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
 #ifndef GMX_TIMING_GPU_TIMING_H
 #define GMX_TIMING_GPU_TIMING_H
 
+#include "gromacs/utility/enumerationhelpers.h"
+
 /*! \internal \brief GPU kernel time and call count. */
 struct gmx_kernel_timing_data_t
 {
@@ -54,16 +56,16 @@ struct gmx_kernel_timing_data_t
 /*! \internal \brief
  * PME GPU stages timing events indices, corresponding to the string in PMEStageNames in wallcycle.cpp.
  */
-enum
+enum class PmeStage : int
 {
-    gtPME_SPLINE = 0,
-    gtPME_SPREAD,
-    gtPME_SPLINEANDSPREAD,
-    gtPME_FFT_R2C,
-    gtPME_SOLVE,
-    gtPME_FFT_C2R,
-    gtPME_GATHER,
-    gtPME_EVENT_COUNT /* not a stage ID but a static array size */
+    Spline = 0,
+    Spread,
+    SplineAndSpread,
+    FftTransformR2C,
+    Solve,
+    FftTransformC2R,
+    Gather,
+    Count /* not a stage ID but a static array size */
 };
 
 /*! \internal \brief GPU timings for PME. */
@@ -73,7 +75,7 @@ struct gmx_wallclock_gpu_pme_t
      * TODO: devise a better GPU timing data structuring.
      */
     /*! \brief Array of PME GPU timing data. */
-    gmx_kernel_timing_data_t timing[gtPME_EVENT_COUNT];
+    gmx::EnumerationArray<PmeStage, gmx_kernel_timing_data_t> timing;
 };
 
 /*! \internal \brief GPU NB timings for kernels and H2d/D2H transfers. */
diff --git a/src/gromacs/timing/tests/.clang-tidy b/src/gromacs/timing/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
similarity index 67%
rename from cmake/Platform/Toolchain-Fujitsu-Sparc64-mpi.cmake
rename to src/gromacs/timing/tests/CMakeLists.txt
index d457cc5d005e004307bd87bc50cf7787d10a71e4..8a5c8c2ecca4b5641d8195d6634f57a7fa1af766 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) 2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
-# the name of the target operating system
-set(CMAKE_SYSTEM_NAME Linux CACHE STRING "Cross-compiling for Fujitsu Sparc64, with MPI")
-set(CMAKE_SYSTEM_PROCESSOR "s64fx")
-
-set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
-
-# set the compiler
-set(CMAKE_C_COMPILER mpifccpx)
-set(CMAKE_CXX_COMPILER mpiFCCpx)
-
-# Prevent CMake from adding GNU-specific linker flags (-rdynamic)
-set(CMAKE_C_COMPILER_ID "Fujitsu" CACHE STRING "Fujitsu C cross-compiler" FORCE)
-set(CMAKE_CXX_COMPILER_ID "Fujitsu" CACHE STRING "Fujitsu C++ cross-compiler" FORCE)
-
-# FindOpenMP.cmake does not try -Kopenmp,but the package will try specific
-# flags based on the compier ID.
-set(OMP_FLAG_Fujitsu "-Kopenmp")
+gmx_add_unit_test(GmxTimingTests timing-test
+    CPP_SOURCE_FILES
+        timing.cpp
+    )
diff --git a/src/gromacs/timing/tests/timing.cpp b/src/gromacs/timing/tests/timing.cpp
new file mode 100644 (file)
index 0000000..3155ad4
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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
+ * This implements tests for timing function wrappers and decorators
+ *
+ * \author Sebastian Keller <keller@cscs.ch>
+ */
+
+#include "gmxpre.h"
+
+#include "config.h"
+
+#include <chrono>
+#include <memory>
+#include <thread>
+
+#include "gromacs/timing/cyclecounter.h"
+#include "gromacs/timing/wallcycle.h"
+
+#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
+
+namespace gmx
+{
+namespace test
+{
+namespace
+{
+
+constexpr bool useCycleSubcounters = GMX_CYCLE_SUBCOUNTERS;
+
+//! Test function
+void sleepForMilliseconds(int msecs)
+{
+    std::this_thread::sleep_for(std::chrono::milliseconds(msecs));
+}
+
+//! Test Fixture for timing tests
+class TimingTest : public ::testing::Test
+{
+public:
+    TimingTest() : wcycle(wallcycle_init(nullptr, 0, nullptr)) {}
+
+protected:
+    const int                      delayInMilliseconds = 1;
+    std::unique_ptr<gmx_wallcycle> wcycle;
+};
+
+
+//! Test whether the we can run the cycle counter.
+TEST_F(TimingTest, RunWallCycle)
+{
+    WallCycleCounter probe = WallCycleCounter::Run, ref = WallCycleCounter::Step;
+    int              n1, n2;
+    double           c1, c2;
+
+    //! credit cycles from enclosing call to the ref field of wcycle
+    wallcycle_start(wcycle.get(), ref);
+    //! cycles from the probe call
+    wallcycle_start(wcycle.get(), probe);
+    sleepForMilliseconds(delayInMilliseconds);
+    wallcycle_stop(wcycle.get(), probe);
+    wallcycle_stop(wcycle.get(), ref);
+    //! extract both
+    wallcycle_get(wcycle.get(), probe, &n1, &c1);
+    wallcycle_get(wcycle.get(), ref, &n2, &c2);
+
+    EXPECT_EQ(n1, n2);
+    EXPECT_DOUBLE_EQ_TOL(c1, c2, relativeToleranceAsFloatingPoint(c1, 5e-3));
+    EXPECT_GE(c2, c1);
+}
+
+//! Test whether the subcyclecounter runs
+TEST_F(TimingTest, RunWallCycleSub)
+{
+    if (useCycleSubcounters)
+    {
+        WallCycleSubCounter probe = WallCycleSubCounter::DDRedist;
+        WallCycleSubCounter ref   = WallCycleSubCounter::DDGrid;
+        int                 n1, n2;
+        double              c1, c2;
+        wallcycle_sub_start(wcycle.get(), ref);
+        wallcycle_sub_start(wcycle.get(), probe);
+        sleepForMilliseconds(delayInMilliseconds);
+        wallcycle_sub_stop(wcycle.get(), probe);
+        wallcycle_sub_stop(wcycle.get(), ref);
+        wallcycle_sub_get(wcycle.get(), probe, &n1, &c1);
+        wallcycle_sub_get(wcycle.get(), ref, &n2, &c2);
+
+        EXPECT_EQ(n1, n2);
+        EXPECT_DOUBLE_EQ_TOL(c1, c2, relativeToleranceAsFloatingPoint(c1, 5e-3));
+        EXPECT_GE(c2, c1);
+    }
+}
+
+} // namespace
+} // namespace test
+} // namespace gmx
index a80254755c4a149b363745bb98029b60e4861860..6f499587133707491ee5fe710e9f4e5d6ab04729 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstdlib>
 
 #include <array>
+#include <memory>
 #include <vector>
 
 #include "gromacs/math/functions.h"
 #include "gromacs/timing/cyclecounter.h"
 #include "gromacs/timing/gpu_timing.h"
 #include "gromacs/timing/wallcyclereporting.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.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"
+#include "gromacs/utility/stringutil.h"
 
-static const bool useCycleSubcounters = GMX_CYCLE_SUBCOUNTERS;
-
-#ifndef DEBUG_WCYCLE
-/*! \brief Enables consistency checking for the counters.
- *
- * If the macro is set to 1, code checks if you stop a counter different from the last
- * one that was opened and if you do nest too deep.
- */
-#    define DEBUG_WCYCLE 0
-#endif
 //! Whether wallcycle debugging is enabled
 constexpr bool gmx_unused enableWallcycleDebug = (DEBUG_WCYCLE != 0);
 //! True if only the master rank should print debugging output
@@ -79,177 +73,153 @@ constexpr bool gmx_unused debugPrintDepth = false /* enableWallcycleDebug */;
 #    include "gromacs/utility/fatalerror.h"
 #endif
 
-typedef struct
+/* Each name should not exceed 19 printing characters
+   (ie. terminating null can be twentieth) */
+static const char* enumValuetoString(WallCycleCounter enumValue)
 {
-    int          n;
-    gmx_cycles_t c;
-    gmx_cycles_t start;
-} wallcc_t;
+    constexpr gmx::EnumerationArray<WallCycleCounter, const char*> wallCycleCounterNames = {
+        "Run",
+        "Step",
+        "PP during PME",
+        "Domain decomp.",
+        "DD comm. load",
+        "DD comm. bounds",
+        "Vsite constr.",
+        "Send X to PME",
+        "Neighbor search",
+        "Launch GPU ops.",
+        "Comm. coord.",
+        "Force",
+        "Wait + Comm. F",
+        "PME mesh",
+        "PME redist. X/F",
+        "PME spread",
+        "PME gather",
+        "PME 3D-FFT",
+        "PME 3D-FFT Comm.",
+        "PME solve LJ",
+        "PME solve Elec",
+        "PME wait for PP",
+        "Wait + Recv. PME F",
+        "Wait PME GPU spread",
+        "PME 3D-FFT",
+        "PME solve", /* the strings for FFT/solve are repeated here for mixed mode counters */
+        "Wait PME GPU gather",
+        "Wait Bonded GPU",
+        "Reduce GPU PME F",
+        "Wait GPU NB nonloc.",
+        "Wait GPU NB local",
+        "Wait GPU state copy",
+        "NB X/F buffer ops.",
+        "Vsite spread",
+        "COM pull force",
+        "AWH",
+        "Write traj.",
+        "Update",
+        "Constraints",
+        "Comm. energies",
+        "Enforced rotation",
+        "Add rot. forces",
+        "Position swapping",
+        "IMD",
+        "Test"
+    };
+    return wallCycleCounterNames[enumValue];
+}
 
-struct gmx_wallcycle
+static const char* enumValuetoString(WallCycleSubCounter enumValue)
 {
-    wallcc_t* wcc;
-    /* did we detect one or more invalid cycle counts */
-    gmx_bool haveInvalidCount;
-    /* variables for testing/debugging */
-    gmx_bool  wc_barrier;
-    wallcc_t* wcc_all;
-    int       wc_depth;
-#if DEBUG_WCYCLE
-#    define DEPTH_MAX 6
-    int  counterlist[DEPTH_MAX];
-    int  count_depth;
-    bool isMasterRank;
-#endif
-    int          ewc_prev;
-    gmx_cycles_t cycle_prev;
-    int64_t      reset_counters;
-#if GMX_MPI
-    MPI_Comm mpi_comm_mygroup;
-#endif
-    wallcc_t* wcsc;
-};
-
-/* Each name should not exceed 19 printing characters
-   (ie. terminating null can be twentieth) */
-static const char* wcn[ewcNR] = { "Run",
-                                  "Step",
-                                  "PP during PME",
-                                  "Domain decomp.",
-                                  "DD comm. load",
-                                  "DD comm. bounds",
-                                  "Vsite constr.",
-                                  "Send X to PME",
-                                  "Neighbor search",
-                                  "Launch GPU ops.",
-                                  "Comm. coord.",
-                                  "Force",
-                                  "Wait + Comm. F",
-                                  "PME mesh",
-                                  "PME redist. X/F",
-                                  "PME spread",
-                                  "PME gather",
-                                  "PME 3D-FFT",
-                                  "PME 3D-FFT Comm.",
-                                  "PME solve LJ",
-                                  "PME solve Elec",
-                                  "PME wait for PP",
-                                  "Wait + Recv. PME F",
-                                  "Wait PME GPU spread",
-                                  "PME 3D-FFT",
-                                  "PME solve", /* the strings for FFT/solve are repeated here for mixed mode counters */
-                                  "Wait PME GPU gather",
-                                  "Wait Bonded GPU",
-                                  "Reduce GPU PME F",
-                                  "Wait GPU NB nonloc.",
-                                  "Wait GPU NB local",
-                                  "Wait GPU state copy",
-                                  "NB X/F buffer ops.",
-                                  "Vsite spread",
-                                  "COM pull force",
-                                  "AWH",
-                                  "Write traj.",
-                                  "Update",
-                                  "Constraints",
-                                  "Comm. energies",
-                                  "Enforced rotation",
-                                  "Add rot. forces",
-                                  "Position swapping",
-                                  "IMD",
-                                  "Test" };
-
-static const char* wcsn[ewcsNR] = {
-    "DD redist.",
-    "DD NS grid + sort",
-    "DD setup comm.",
-    "DD make top.",
-    "DD make constr.",
-    "DD top. other",
-    "DD GPU ops.",
-    "NS grid local",
-    "NS grid non-loc.",
-    "NS search local",
-    "NS search non-loc.",
-    "Bonded F",
-    "Bonded-FEP F",
-    "Restraints F",
-    "Listed buffer ops.",
-    "Nonbonded pruning",
-    "Nonbonded F kernel",
-    "Nonbonded F clear",
-    "Nonbonded FEP",
-    "Launch NB GPU tasks",
-    "Launch Bonded GPU tasks",
-    "Launch PME GPU tasks",
-    "Launch state copy",
-    "Ewald F correction",
-    "NB X buffer ops.",
-    "NB F buffer ops.",
-    "Clear force buffer",
-    "Launch GPU NB X buffer ops.",
-    "Launch GPU NB F buffer ops.",
-    "Launch GPU Comm. coord.",
-    "Launch GPU Comm. force.",
-    "Launch GPU update",
-    "Test subcounter",
-};
+    constexpr gmx::EnumerationArray<WallCycleSubCounter, const char*> wallCycleSubCounterNames = {
+        "DD redist.",
+        "DD NS grid + sort",
+        "DD setup comm.",
+        "DD make top.",
+        "DD make constr.",
+        "DD top. other",
+        "DD GPU ops.",
+        "NS grid local",
+        "NS grid non-loc.",
+        "NS search local",
+        "NS search non-loc.",
+        "Bonded F",
+        "Bonded-FEP F",
+        "Restraints F",
+        "Listed buffer ops.",
+        "Nonbonded pruning",
+        "Nonbonded F kernel",
+        "Nonbonded F clear",
+        "Nonbonded FEP",
+        "Launch NB GPU tasks",
+        "Launch Bonded GPU tasks",
+        "Launch PME GPU tasks",
+        "Launch state copy",
+        "Ewald F correction",
+        "NB X buffer ops.",
+        "NB F buffer ops.",
+        "Clear force buffer",
+        "Launch GPU NB X buffer ops.",
+        "Launch GPU NB F buffer ops.",
+        "Launch GPU Comm. coord.",
+        "Launch GPU Comm. force.",
+        "Launch GPU update",
+        "Test subcounter"
+    };
+    return wallCycleSubCounterNames[enumValue];
+}
 
 /* PME GPU timing events' names - correspond to the enum in the gpu_timing.h */
-static const char* PMEStageNames[] = {
-    "PME spline", "PME spread",     "PME spline + spread", "PME 3D-FFT r2c",
-    "PME solve",  "PME 3D-FFT c2r", "PME gather",
+static const char* enumValuetoString(PmeStage enumValue)
+{
+    constexpr gmx::EnumerationArray<PmeStage, const char*> pmeStageNames = {
+        "PME spline", "PME spread",     "PME spline + spread", "PME 3D-FFT r2c",
+        "PME solve",  "PME 3D-FFT c2r", "PME gather"
+    };
+    return pmeStageNames[enumValue];
 };
 
-gmx_bool wallcycle_have_counter()
+bool wallcycle_have_counter()
 {
     return gmx_cycles_have_counter();
 }
 
-gmx_wallcycle_t wallcycle_init(FILE* fplog, int resetstep, t_commrec gmx_unused* cr)
+std::unique_ptr<gmx_wallcycle> wallcycle_init(FILE* fplog, int resetstep, const t_commrec* cr)
 {
-    gmx_wallcycle_t wc;
+    std::unique_ptr<gmx_wallcycle> wc;
 
 
     if (!wallcycle_have_counter())
     {
-        return nullptr;
+        return wc;
     }
 
-    snew(wc, 1);
+    wc = std::make_unique<gmx_wallcycle>();
 
-    wc->haveInvalidCount = FALSE;
-    wc->wc_barrier       = FALSE;
-    wc->wcc_all          = nullptr;
+    wc->haveInvalidCount = false;
+    wc->wc_barrier       = false;
     wc->wc_depth         = 0;
-    wc->ewc_prev         = -1;
+    wc->ewc_prev         = WallCycleCounter::Count;
     wc->reset_counters   = resetstep;
+    wc->cr               = cr;
 
 
 #if GMX_MPI
-    if (PAR(cr) && getenv("GMX_CYCLE_BARRIER") != nullptr)
+    if (cr != nullptr && PAR(cr) && getenv("GMX_CYCLE_BARRIER") != nullptr)
     {
         if (fplog)
         {
             fprintf(fplog, "\nWill call MPI_Barrier before each cycle start/stop call\n\n");
         }
-        wc->wc_barrier       = TRUE;
-        wc->mpi_comm_mygroup = cr->mpi_comm_mygroup;
+        wc->wc_barrier = true;
     }
 #endif
 
-    snew(wc->wcc, ewcNR);
     if (getenv("GMX_CYCLE_ALL") != nullptr)
     {
         if (fplog)
         {
             fprintf(fplog, "\nWill time all the code during the run\n\n");
         }
-        snew(wc->wcc_all, ewcNR * ewcNR);
-    }
-
-    if (useCycleSubcounters)
-    {
-        snew(wc->wcsc, ewcsNR);
+        wc->wcc_all.resize(sc_numWallCycleCountersSquared);
     }
 
 #if DEBUG_WCYCLE
@@ -260,45 +230,10 @@ gmx_wallcycle_t wallcycle_init(FILE* fplog, int resetstep, t_commrec gmx_unused*
     return wc;
 }
 
-void wallcycle_destroy(gmx_wallcycle_t wc)
-{
-    if (wc == nullptr)
-    {
-        return;
-    }
-
-    if (wc->wcc != nullptr)
-    {
-        sfree(wc->wcc);
-    }
-    if (wc->wcc_all != nullptr)
-    {
-        sfree(wc->wcc_all);
-    }
-    if (wc->wcsc != nullptr)
-    {
-        sfree(wc->wcsc);
-    }
-    sfree(wc);
-}
-
-static void wallcycle_all_start(gmx_wallcycle_t wc, int ewc, gmx_cycles_t cycle)
-{
-    wc->ewc_prev   = ewc;
-    wc->cycle_prev = cycle;
-}
-
-static void wallcycle_all_stop(gmx_wallcycle_t wc, int ewc, gmx_cycles_t cycle)
-{
-    wc->wcc_all[wc->ewc_prev * ewcNR + ewc].n += 1;
-    wc->wcc_all[wc->ewc_prev * ewcNR + ewc].c += cycle - wc->cycle_prev;
-}
-
-
 #if DEBUG_WCYCLE
-static void debug_start_check(gmx_wallcycle_t wc, int ewc)
+static void debug_start_check(gmx_wallcycle* wc, WallCycleCounter ewc)
 {
-    if (wc->count_depth < 0 || wc->count_depth >= DEPTH_MAX)
+    if (wc->count_depth < 0 || wc->count_depth >= c_MaxWallCycleDepth)
     {
         gmx_fatal(FARGS, "wallcycle counter depth out of range: %d", wc->count_depth + 1);
     }
@@ -308,197 +243,108 @@ static void debug_start_check(gmx_wallcycle_t wc, int ewc)
     if (debugPrintDepth && (!onlyMasterDebugPrints || wc->isMasterRank))
     {
         std::string indentStr(4 * wc->count_depth, ' ');
-        fprintf(stderr, "%swcycle_start depth %d, %s\n", indentStr.c_str(), wc->count_depth, wcn[ewc]);
+        fprintf(stderr, "%swcycle_start depth %d, %s\n", indentStr.c_str(), wc->count_depth, enumValuetoString(ewc));
     }
 }
 
-static void debug_stop_check(gmx_wallcycle_t wc, int ewc)
+static void debug_stop_check(gmx_wallcycle* wc, WallCycleCounter ewc)
 {
     if (debugPrintDepth && (!onlyMasterDebugPrints || wc->isMasterRank))
     {
         std::string indentStr(4 * wc->count_depth, ' ');
-        fprintf(stderr, "%swcycle_stop  depth %d, %s\n", indentStr.c_str(), wc->count_depth, wcn[ewc]);
+        fprintf(stderr, "%swcycle_stop  depth %d, %s\n", indentStr.c_str(), wc->count_depth, enumValuetoString(ewc));
     }
 
     wc->count_depth--;
 
     if (wc->count_depth < 0)
     {
-        gmx_fatal(FARGS, "wallcycle counter depth out of range when stopping %s: %d", wcn[ewc],
+        gmx_fatal(FARGS,
+                  "wallcycle counter depth out of range when stopping %s: %d",
+                  enumValuetoString(ewc),
                   wc->count_depth);
     }
     if (wc->counterlist[wc->count_depth] != ewc)
     {
-        gmx_fatal(FARGS, "wallcycle mismatch at stop, start %s, stop %s",
-                  wcn[wc->counterlist[wc->count_depth]], wcn[ewc]);
+        gmx_fatal(FARGS,
+                  "wallcycle mismatch at stop, start %s, stop %s",
+                  enumValuetoString(wc->counterlist[wc->count_depth]),
+                  enumValuetoString(ewc));
     }
 }
 #endif
 
-void wallcycle_start(gmx_wallcycle_t wc, int ewc)
+void wallcycle_get(gmx_wallcycle* wc, WallCycleCounter ewc, int* n, double* c)
 {
-    gmx_cycles_t cycle;
-
-    if (wc == nullptr)
-    {
-        return;
-    }
-
-#if GMX_MPI
-    if (wc->wc_barrier)
-    {
-        MPI_Barrier(wc->mpi_comm_mygroup);
-    }
-#endif
-
-#if DEBUG_WCYCLE
-    debug_start_check(wc, ewc);
-#endif
-
-    cycle              = gmx_cycles_read();
-    wc->wcc[ewc].start = cycle;
-    if (wc->wcc_all != nullptr)
-    {
-        wc->wc_depth++;
-        if (ewc == ewcRUN)
-        {
-            wallcycle_all_start(wc, ewc, cycle);
-        }
-        else if (wc->wc_depth == 3)
-        {
-            wallcycle_all_stop(wc, ewc, cycle);
-        }
-    }
-}
-
-void wallcycle_increment_event_count(gmx_wallcycle_t wc, int ewc)
-{
-    if (wc == nullptr)
-    {
-        return;
-    }
-    wc->wcc[ewc].n++;
-}
-
-void wallcycle_start_nocount(gmx_wallcycle_t wc, int ewc)
-{
-    if (wc == nullptr)
-    {
-        return;
-    }
-
-    wallcycle_start(wc, ewc);
-    wc->wcc[ewc].n--;
+    *n = wc->wcc[ewc].n;
+    *c = static_cast<double>(wc->wcc[ewc].c);
 }
 
-double wallcycle_stop(gmx_wallcycle_t wc, int ewc)
+void wallcycle_sub_get(gmx_wallcycle* wc, WallCycleSubCounter ewcs, int* n, double* c)
 {
-    gmx_cycles_t cycle, last;
-
-    if (wc == nullptr)
+    if (sc_useCycleSubcounters && wc != nullptr)
     {
-        return 0;
+        *n = wc->wcsc[ewcs].n;
+        *c = static_cast<double>(wc->wcsc[ewcs].c);
     }
-
-#if GMX_MPI
-    if (wc->wc_barrier)
-    {
-        MPI_Barrier(wc->mpi_comm_mygroup);
-    }
-#endif
-
-#if DEBUG_WCYCLE
-    debug_stop_check(wc, ewc);
-#endif
-
-    /* When processes or threads migrate between cores, the cycle counting
-     * can get messed up if the cycle counter on different cores are not
-     * synchronized. When this happens we expect both large negative and
-     * positive cycle differences. We can detect negative cycle differences.
-     * Detecting too large positive counts if difficult, since count can be
-     * large, especially for ewcRUN. If we detect a negative count,
-     * we will not print the cycle accounting table.
-     */
-    cycle = gmx_cycles_read();
-    if (cycle >= wc->wcc[ewc].start)
-    {
-        last = cycle - wc->wcc[ewc].start;
-    }
-    else
-    {
-        last                 = 0;
-        wc->haveInvalidCount = TRUE;
-    }
-    wc->wcc[ewc].c += last;
-    wc->wcc[ewc].n++;
-    if (wc->wcc_all)
-    {
-        wc->wc_depth--;
-        if (ewc == ewcRUN)
-        {
-            wallcycle_all_stop(wc, ewc, cycle);
-        }
-        else if (wc->wc_depth == 2)
-        {
-            wallcycle_all_start(wc, ewc, cycle);
-        }
-    }
-
-    return last;
 }
 
-void wallcycle_get(gmx_wallcycle_t wc, int ewc, int* n, double* c)
+void wallcycle_reset_all(gmx_wallcycle* wc)
 {
-    *n = wc->wcc[ewc].n;
-    *c = static_cast<double>(wc->wcc[ewc].c);
-}
-
-void wallcycle_reset_all(gmx_wallcycle_t wc)
-{
-    int i;
-
     if (wc == nullptr)
     {
         return;
     }
 
-    for (i = 0; i < ewcNR; i++)
+    for (auto& counter : wc->wcc)
     {
-        wc->wcc[i].n = 0;
-        wc->wcc[i].c = 0;
+        counter.n = 0;
+        counter.c = 0;
     }
-    wc->haveInvalidCount = FALSE;
+    wc->haveInvalidCount = false;
 
-    if (wc->wcc_all)
+    if (!wc->wcc_all.empty())
     {
-        for (i = 0; i < ewcNR * ewcNR; i++)
+        for (int i = 0; i < sc_numWallCycleCountersSquared; i++)
         {
             wc->wcc_all[i].n = 0;
             wc->wcc_all[i].c = 0;
         }
     }
-    if (wc->wcsc)
+    for (auto& counter : wc->wcsc)
     {
-        for (i = 0; i < ewcsNR; i++)
-        {
-            wc->wcsc[i].n = 0;
-            wc->wcsc[i].c = 0;
-        }
+        counter.n = 0;
+        counter.c = 0;
     }
 }
 
-static gmx_bool is_pme_counter(int ewc)
+static bool is_pme_counter(WallCycleCounter ewc)
 {
-    return (ewc >= ewcPMEMESH && ewc <= ewcPMEWAITCOMM);
+    return (ewc >= WallCycleCounter::PmeMesh && ewc <= WallCycleCounter::PmeWaitComm);
 }
 
-static gmx_bool is_pme_subcounter(int ewc)
+static bool is_pme_subcounter(WallCycleCounter ewc)
 {
-    return (ewc >= ewcPME_REDISTXF && ewc < ewcPMEWAITCOMM);
+    return (ewc >= WallCycleCounter::PmeRedistXF && ewc < WallCycleCounter::PmeWaitComm);
+}
+
+void wallcycleBarrier(gmx_wallcycle* wc)
+{
+#if GMX_MPI
+    if (wc->wc_barrier)
+    {
+        MPI_Barrier(wc->cr->mpi_comm_mygroup);
+    }
+#else
+    GMX_UNUSED_VALUE(wc);
+#endif
 }
 
 /* Subtract counter ewc_sub timed inside a timing block for ewc_main */
-static void subtract_cycles(wallcc_t* wcc, int ewc_main, int ewc_sub)
+// NOLINTNEXTLINE(google-runtime-references)
+static void subtract_cycles(gmx::EnumerationArray<WallCycleCounter, wallcc_t>& wcc,
+                            WallCycleCounter                                   ewc_main,
+                            WallCycleCounter                                   ewc_sub)
 {
     if (wcc[ewc_sub].n > 0)
     {
@@ -514,45 +360,47 @@ static void subtract_cycles(wallcc_t* wcc, int ewc_main, int ewc_sub)
     }
 }
 
-void wallcycle_scale_by_num_threads(gmx_wallcycle_t wc, bool isPmeRank, int nthreads_pp, int nthreads_pme)
+void wallcycle_scale_by_num_threads(gmx_wallcycle* wc, bool isPmeRank, int nthreads_pp, int nthreads_pme)
 {
     if (wc == nullptr)
     {
         return;
     }
 
-    for (int i = 0; i < ewcNR; i++)
+    for (auto key : keysOf(wc->wcc))
     {
-        if (is_pme_counter(i) || (i == ewcRUN && isPmeRank))
+        if (is_pme_counter(key) || (key == WallCycleCounter::Run && isPmeRank))
         {
-            wc->wcc[i].c *= nthreads_pme;
+            wc->wcc[key].c *= nthreads_pme;
 
-            if (wc->wcc_all)
+            if (!wc->wcc_all.empty())
             {
-                for (int j = 0; j < ewcNR; j++)
+                const int current = static_cast<int>(key);
+                for (int j = 0; j < sc_numWallCycleCounters; j++)
                 {
-                    wc->wcc_all[i * ewcNR + j].c *= nthreads_pme;
+                    wc->wcc_all[current * sc_numWallCycleCounters + j].c *= nthreads_pme;
                 }
             }
         }
         else
         {
-            wc->wcc[i].c *= nthreads_pp;
+            wc->wcc[key].c *= nthreads_pp;
 
-            if (wc->wcc_all)
+            if (!wc->wcc_all.empty())
             {
-                for (int j = 0; j < ewcNR; j++)
+                const int current = static_cast<int>(key);
+                for (int j = 0; j < sc_numWallCycleCounters; j++)
                 {
-                    wc->wcc_all[i * ewcNR + j].c *= nthreads_pp;
+                    wc->wcc_all[current * sc_numWallCycleCounters + j].c *= nthreads_pp;
                 }
             }
         }
     }
-    if (useCycleSubcounters && wc->wcsc && !isPmeRank)
+    if (sc_useCycleSubcounters && !isPmeRank)
     {
-        for (int i = 0; i < ewcsNR; i++)
+        for (auto counter : wc->wcsc)
         {
-            wc->wcsc[i].c *= nthreads_pp;
+            counter.c *= nthreads_pp;
         }
     }
 }
@@ -569,124 +417,146 @@ void wallcycle_scale_by_num_threads(gmx_wallcycle_t wc, bool isPmeRank, int nthr
  * wcc_all are unused by the GPU reporting, but it is not satisfactory
  * for the future. Also, there's no need for MPI_Allreduce, since
  * only MASTERRANK uses any of the results. */
-WallcycleCounts wallcycle_sum(const t_commrec* cr, gmx_wallcycle_t wc)
+WallcycleCounts wallcycle_sum(const t_commrec* cr, gmx_wallcycle* wc)
 {
-    WallcycleCounts cycles_sum;
-    wallcc_t*       wcc;
-    double          cycles[int(ewcNR) + int(ewcsNR)];
+    WallcycleCounts                                    cycles_sum;
+    gmx::EnumerationArray<WallCycleCounter, double>    cyclesMain;
+    gmx::EnumerationArray<WallCycleSubCounter, double> cyclesSub;
 #if GMX_MPI
-    double cycles_n[int(ewcNR) + int(ewcsNR) + 1];
+    gmx::EnumerationArray<WallCycleCounter, double>    cyclesMainOnNode;
+    gmx::EnumerationArray<WallCycleSubCounter, double> cyclesSubOnNode;
 #endif
-    int i;
-    int nsum;
 
     if (wc == nullptr)
     {
         /* Default construction of std::array of non-class T can leave
-           the values indeterminate, just like a C array, and icc
-           warns about it. */
+           the values indeterminate, just like a C array */
         cycles_sum.fill(0);
         return cycles_sum;
     }
 
-    wcc = wc->wcc;
+    auto& wcc = wc->wcc;
 
-    subtract_cycles(wcc, ewcDOMDEC, ewcDDCOMMLOAD);
-    subtract_cycles(wcc, ewcDOMDEC, ewcDDCOMMBOUND);
+    subtract_cycles(wcc, WallCycleCounter::Domdec, WallCycleCounter::DDCommLoad);
+    subtract_cycles(wcc, WallCycleCounter::Domdec, WallCycleCounter::DDCommBound);
 
-    subtract_cycles(wcc, ewcPME_FFT, ewcPME_FFTCOMM);
+    subtract_cycles(wcc, WallCycleCounter::PmeFft, WallCycleCounter::PmeFftComm);
 
     if (cr->npmenodes == 0)
     {
         /* All nodes do PME (or no PME at all) */
-        subtract_cycles(wcc, ewcFORCE, ewcPMEMESH);
+        subtract_cycles(wcc, WallCycleCounter::Force, WallCycleCounter::PmeMesh);
     }
     else
     {
         /* The are PME-only nodes */
-        if (wcc[ewcPMEMESH].n > 0)
+        if (wcc[WallCycleCounter::PmeMesh].n > 0)
         {
             /* This must be a PME only node, calculate the Wait + Comm. time */
-            GMX_ASSERT(wcc[ewcRUN].c >= wcc[ewcPMEMESH].c,
+            GMX_ASSERT(wcc[WallCycleCounter::Run].c >= wcc[WallCycleCounter::PmeMesh].c,
                        "Total run ticks must be greater than PME-only ticks");
-            wcc[ewcPMEWAITCOMM].c = wcc[ewcRUN].c - wcc[ewcPMEMESH].c;
+            wcc[WallCycleCounter::PmeWaitComm].c =
+                    wcc[WallCycleCounter::Run].c - wcc[WallCycleCounter::PmeMesh].c;
         }
     }
 
     /* Store the cycles in a double buffer for summing */
-    for (i = 0; i < ewcNR; i++)
+    for (auto key : keysOf(wcc))
     {
 #if GMX_MPI
-        cycles_n[i] = static_cast<double>(wcc[i].n);
+        cyclesMainOnNode[key] = static_cast<double>(wcc[key].n);
 #endif
-        cycles[i] = static_cast<double>(wcc[i].c);
+        cyclesMain[key] = static_cast<double>(wcc[key].c);
     }
-    nsum = ewcNR;
-    if (wc->wcsc)
+    if (sc_useCycleSubcounters)
     {
-        for (i = 0; i < ewcsNR; i++)
+        for (auto key : keysOf(wc->wcsc))
         {
 #if GMX_MPI
-            cycles_n[ewcNR + i] = static_cast<double>(wc->wcsc[i].n);
+            cyclesSubOnNode[key] = static_cast<double>(wc->wcsc[key].n);
 #endif
-            cycles[ewcNR + i] = static_cast<double>(wc->wcsc[i].c);
+            cyclesSub[key] = static_cast<double>(wc->wcsc[key].c);
         }
-        nsum += ewcsNR;
     }
 
 #if GMX_MPI
     if (cr->nnodes > 1)
     {
-        double buf[int(ewcNR) + int(ewcsNR) + 1];
+        gmx::EnumerationArray<WallCycleCounter, double>    bufMain;
+        gmx::EnumerationArray<WallCycleSubCounter, double> bufSub;
 
         // TODO this code is used only at the end of the run, so we
         // can just do a simple reduce of haveInvalidCount in
         // wallcycle_print, and avoid bugs
-        cycles_n[nsum] = (wc->haveInvalidCount ? 1 : 0);
+        double haveInvalidCount = (wc->haveInvalidCount ? 1 : 0);
         // TODO Use MPI_Reduce
-        MPI_Allreduce(cycles_n, buf, nsum + 1, MPI_DOUBLE, MPI_MAX, cr->mpi_comm_mysim);
-        for (i = 0; i < ewcNR; i++)
+        MPI_Allreduce(cyclesMainOnNode.data(), bufMain.data(), bufMain.size(), MPI_DOUBLE, MPI_MAX, cr->mpi_comm_mysim);
+        if (sc_useCycleSubcounters)
         {
-            wcc[i].n = gmx::roundToInt(buf[i]);
+            MPI_Allreduce(cyclesSubOnNode.data(), bufSub.data(), bufSub.size(), MPI_DOUBLE, MPI_MAX, cr->mpi_comm_mysim);
         }
-        wc->haveInvalidCount = (buf[nsum] > 0);
-        if (wc->wcsc)
+        MPI_Allreduce(MPI_IN_PLACE, &haveInvalidCount, 1, MPI_DOUBLE, MPI_MAX, cr->mpi_comm_mysim);
+        for (auto key : keysOf(wcc))
         {
-            for (i = 0; i < ewcsNR; i++)
+            wcc[key].n = gmx::roundToInt(bufMain[key]);
+        }
+        wc->haveInvalidCount = (haveInvalidCount > 0);
+        if (sc_useCycleSubcounters)
+        {
+            for (auto key : keysOf(wc->wcsc))
             {
-                wc->wcsc[i].n = gmx::roundToInt(buf[ewcNR + i]);
+                wc->wcsc[key].n = gmx::roundToInt(bufSub[key]);
             }
         }
 
         // TODO Use MPI_Reduce
-        MPI_Allreduce(cycles, cycles_sum.data(), nsum, MPI_DOUBLE, MPI_SUM, cr->mpi_comm_mysim);
+        MPI_Allreduce(cyclesMain.data(), cycles_sum.data(), cyclesMain.size(), MPI_DOUBLE, MPI_SUM, cr->mpi_comm_mysim);
+        if (sc_useCycleSubcounters)
+        {
+            MPI_Allreduce(cyclesSub.data(),
+                          cycles_sum.data() + sc_numWallCycleCounters,
+                          cyclesSub.size(),
+                          MPI_DOUBLE,
+                          MPI_SUM,
+                          cr->mpi_comm_mysim);
+        }
 
-        if (wc->wcc_all != nullptr)
+        if (!wc->wcc_all.empty())
         {
-            double *buf_all, *cyc_all;
+            std::array<double, sc_numWallCycleCountersSquared> cyc_all;
+            std::array<double, sc_numWallCycleCountersSquared> buf_all;
 
-            snew(cyc_all, ewcNR * ewcNR);
-            snew(buf_all, ewcNR * ewcNR);
-            for (i = 0; i < ewcNR * ewcNR; i++)
+            for (int i = 0; i < sc_numWallCycleCountersSquared; i++)
             {
                 cyc_all[i] = wc->wcc_all[i].c;
             }
             // TODO Use MPI_Reduce
-            MPI_Allreduce(cyc_all, buf_all, ewcNR * ewcNR, MPI_DOUBLE, MPI_SUM, cr->mpi_comm_mysim);
-            for (i = 0; i < ewcNR * ewcNR; i++)
+            MPI_Allreduce(cyc_all.data(),
+                          buf_all.data(),
+                          sc_numWallCycleCountersSquared,
+                          MPI_DOUBLE,
+                          MPI_SUM,
+                          cr->mpi_comm_mysim);
+            for (int i = 0; i < sc_numWallCycleCountersSquared; i++)
             {
                 wc->wcc_all[i].c = static_cast<gmx_cycles_t>(buf_all[i]);
             }
-            sfree(buf_all);
-            sfree(cyc_all);
         }
     }
     else
 #endif
     {
-        for (i = 0; i < nsum; i++)
+        for (auto key : keysOf(cyclesMain))
         {
-            cycles_sum[i] = cycles[i];
+            cycles_sum[static_cast<int>(key)] = cyclesMain[key];
+        }
+        if (sc_useCycleSubcounters)
+        {
+            for (auto key : keysOf(cyclesSub))
+            {
+                const int offset   = static_cast<int>(key) + sc_numWallCycleCounters;
+                cycles_sum[offset] = cyclesSub[key];
+            }
         }
     }
 
@@ -733,8 +603,15 @@ print_cycles(FILE* fplog, double c2t, const char* name, int nnodes, int nthreads
         /* Convert the cycle count to wallclock time for this task */
         wallt = c_sum * c2t;
 
-        fprintf(fplog, " %-19.19s %4s %4s %10s  %10.3f %14.3f %5.1f\n", name, nnodes_str,
-                nthreads_str, ncalls_str, wallt, c_sum * 1e-9, percentage);
+        fprintf(fplog,
+                " %-19.19s %4s %4s %10s  %10.3f %14.3f %5.1f\n",
+                name,
+                nnodes_str,
+                nthreads_str,
+                ncalls_str,
+                wallt,
+                c_sum * 1e-9,
+                percentage);
     }
 }
 
@@ -803,14 +680,14 @@ void wallcycle_print(FILE*                            fplog,
                      int                              nth_pp,
                      int                              nth_pme,
                      double                           realtime,
-                     gmx_wallcycle_t                  wc,
+                     gmx_wallcycle                  wc,
                      const WallcycleCounts&           cyc_sum,
                      const gmx_wallclock_gpu_nbnxn_t* gpu_nbnxn_t,
                      const gmx_wallclock_gpu_pme_t*   gpu_pme_t)
 {
     double      tot, tot_for_pp, tot_for_rest, tot_cpu_overlap, gpu_cpu_ratio;
     double      c2t, c2t_pp, c2t_pme = 0;
-    int         i, j, npp, nth_tot;
+    int         npp, nth_tot;
     char        buf[STRLEN];
     const char* hline =
             "-----------------------------------------------------------------------------";
@@ -833,7 +710,7 @@ void wallcycle_print(FILE*                            fplog,
     /* When using PME-only nodes, the next line is valid for both
        PP-only and PME-only nodes because they started ewcRUN at the
        same time. */
-    tot        = cyc_sum[ewcRUN];
+    tot        = cyc_sum[static_cast<int>(WallCycleCounter::Run)];
     tot_for_pp = 0;
 
     if (tot <= 0.0)
@@ -883,39 +760,64 @@ void wallcycle_print(FILE*                            fplog,
     print_header(fplog, npp, nth_pp, npme, nth_pme);
 
     fprintf(fplog, "%s\n", hline);
-    for (i = ewcPPDURINGPME + 1; i < ewcNR; i++)
+    gmx::EnumerationWrapper<WallCycleCounter> iter;
+    for (auto key = gmx::EnumerationIterator<WallCycleCounter>(WallCycleCounter::Domdec);
+         key != iter.end();
+         ++key)
     {
-        if (is_pme_subcounter(i))
+
+        if (is_pme_subcounter(*key))
         {
             /* Do not count these at all */
         }
-        else if (npme > 0 && is_pme_counter(i))
+        else if (npme > 0 && is_pme_counter(*key))
         {
             /* Print timing information for PME-only nodes, but add an
              * asterisk so the reader of the table can know that the
              * walltimes are not meant to add up. The asterisk still
              * fits in the required maximum of 19 characters. */
-            char buffer[STRLEN];
-            snprintf(buffer, STRLEN, "%s *", wcn[i]);
-            print_cycles(fplog, c2t_pme, buffer, npme, nth_pme, wc->wcc[i].n, cyc_sum[i], tot);
+            std::string message = gmx::formatString("%s *", enumValuetoString(*key));
+            print_cycles(fplog,
+                         c2t_pme,
+                         message.c_str(),
+                         npme,
+                         nth_pme,
+                         wc->wcc[*key].n,
+                         cyc_sum[static_cast<int>(*key)],
+                         tot);
         }
         else
         {
             /* Print timing information when it is for a PP or PP+PME
                node */
-            print_cycles(fplog, c2t_pp, wcn[i], npp, nth_pp, wc->wcc[i].n, cyc_sum[i], tot);
-            tot_for_pp += cyc_sum[i];
+            print_cycles(fplog,
+                         c2t_pp,
+                         enumValuetoString(*key),
+                         npp,
+                         nth_pp,
+                         wc->wcc[*key].n,
+                         cyc_sum[static_cast<int>(*key)],
+                         tot);
+            tot_for_pp += cyc_sum[static_cast<int>(*key)];
         }
     }
-    if (wc->wcc_all != nullptr)
+    if (!wc->wcc_all.empty())
     {
-        for (i = 0; i < ewcNR; i++)
+        for (auto i : keysOf(wc->wcc))
         {
-            for (j = 0; j < ewcNR; j++)
+            const int countI = static_cast<int>(i);
+            for (auto j : keysOf(wc->wcc))
             {
-                snprintf(buf, 20, "%-9.9s %-9.9s", wcn[i], wcn[j]);
-                print_cycles(fplog, c2t_pp, buf, npp, nth_pp, wc->wcc_all[i * ewcNR + j].n,
-                             wc->wcc_all[i * ewcNR + j].c, tot);
+                const int countJ = static_cast<int>(j);
+                snprintf(buf, 20, "%-9.9s %-9.9s", enumValuetoString(i), enumValuetoString(j));
+                print_cycles(fplog,
+                             c2t_pp,
+                             buf,
+                             npp,
+                             nth_pp,
+                             wc->wcc_all[countI * sc_numWallCycleCounters + countJ].n,
+                             wc->wcc_all[countI * sc_numWallCycleCounters + countJ].c,
+                             tot);
             }
         }
     }
@@ -934,16 +836,18 @@ void wallcycle_print(FILE*                            fplog,
                 hline);
     }
 
-    if (wc->wcc[ewcPMEMESH].n > 0)
+    if (wc->wcc[WallCycleCounter::PmeMesh].n > 0)
     {
         // A workaround to not print breakdown when no subcounters were recorded.
         // TODO: figure out and record PME GPU counters (what to do with the waiting ones?)
-        std::vector<int> validPmeSubcounterIndices;
-        for (i = ewcPPDURINGPME + 1; i < ewcNR; i++)
+        std::vector<WallCycleCounter> validPmeSubcounterIndices;
+        for (auto key = gmx::EnumerationIterator<WallCycleCounter>(WallCycleCounter::Domdec);
+             key != iter.end();
+             key++)
         {
-            if (is_pme_subcounter(i) && wc->wcc[i].n > 0)
+            if (is_pme_subcounter(*key) && wc->wcc[*key].n > 0)
             {
-                validPmeSubcounterIndices.push_back(i);
+                validPmeSubcounterIndices.push_back(*key);
             }
         }
 
@@ -953,20 +857,33 @@ void wallcycle_print(FILE*                            fplog,
             fprintf(fplog, "%s\n", hline);
             for (auto i : validPmeSubcounterIndices)
             {
-                print_cycles(fplog, npme > 0 ? c2t_pme : c2t_pp, wcn[i], npme > 0 ? npme : npp,
-                             nth_pme, wc->wcc[i].n, cyc_sum[i], tot);
+                print_cycles(fplog,
+                             npme > 0 ? c2t_pme : c2t_pp,
+                             enumValuetoString(i),
+                             npme > 0 ? npme : npp,
+                             nth_pme,
+                             wc->wcc[i].n,
+                             cyc_sum[static_cast<int>(i)],
+                             tot);
             }
             fprintf(fplog, "%s\n", hline);
         }
     }
 
-    if (useCycleSubcounters && wc->wcsc)
+    if (sc_useCycleSubcounters)
     {
         fprintf(fplog, " Breakdown of PP computation\n");
         fprintf(fplog, "%s\n", hline);
-        for (i = 0; i < ewcsNR; i++)
+        for (auto key : keysOf(wc->wcsc))
         {
-            print_cycles(fplog, c2t_pp, wcsn[i], npp, nth_pp, wc->wcsc[i].n, cyc_sum[ewcNR + i], tot);
+            print_cycles(fplog,
+                         c2t_pp,
+                         enumValuetoString(key),
+                         npp,
+                         nth_pp,
+                         wc->wcsc[key].n,
+                         cyc_sum[sc_numWallCycleCounters + static_cast<int>(key)],
+                         tot);
         }
         fprintf(fplog, "%s\n", hline);
     }
@@ -975,9 +892,9 @@ void wallcycle_print(FILE*                            fplog,
     double tot_gpu = 0.0;
     if (gpu_pme_t)
     {
-        for (size_t k = 0; k < gtPME_EVENT_COUNT; k++)
+        for (auto key : keysOf(gpu_pme_t->timing))
         {
-            tot_gpu += gpu_pme_t->timing[k].t;
+            tot_gpu += gpu_pme_t->timing[key].t;
         }
     }
     if (gpu_nbnxn_t)
@@ -987,55 +904,61 @@ void wallcycle_print(FILE*                            fplog,
         tot_gpu += gpu_nbnxn_t->pl_h2d_t + gpu_nbnxn_t->nb_h2d_t + gpu_nbnxn_t->nb_d2h_t;
 
         /* add up the kernel timings */
-        for (i = 0; i < 2; i++)
+        for (int i = 0; i < 2; i++)
         {
-            for (j = 0; j < 2; j++)
+            for (int j = 0; j < 2; j++)
             {
                 tot_gpu += gpu_nbnxn_t->ktime[i][j].t;
             }
         }
         tot_gpu += gpu_nbnxn_t->pruneTime.t;
 
-        tot_cpu_overlap = wc->wcc[ewcFORCE].c;
-        if (wc->wcc[ewcPMEMESH].n > 0)
+        tot_cpu_overlap = wc->wcc[WallCycleCounter::Force].c;
+        if (wc->wcc[WallCycleCounter::PmeMesh].n > 0)
         {
-            tot_cpu_overlap += wc->wcc[ewcPMEMESH].c;
+            tot_cpu_overlap += wc->wcc[WallCycleCounter::PmeMesh].c;
         }
         tot_cpu_overlap *= realtime * 1000 / tot; /* convert s to ms */
 
         fprintf(fplog, "\n GPU timings\n%s\n", hline);
         fprintf(fplog,
-                " Computing:                         Count  Wall t (s)      ms/step       %c\n", '%');
+                " Computing:                         Count  Wall t (s)      ms/step       %c\n",
+                '%');
         fprintf(fplog, "%s\n", hline);
         print_gputimes(fplog, "Pair list H2D", gpu_nbnxn_t->pl_h2d_c, gpu_nbnxn_t->pl_h2d_t, tot_gpu);
         print_gputimes(fplog, "X / q H2D", gpu_nbnxn_t->nb_c, gpu_nbnxn_t->nb_h2d_t, tot_gpu);
 
-        for (i = 0; i < 2; i++)
+        for (int i = 0; i < 2; i++)
         {
-            for (j = 0; j < 2; j++)
+            for (int j = 0; j < 2; j++)
             {
                 if (gpu_nbnxn_t->ktime[i][j].c)
                 {
-                    print_gputimes(fplog, k_log_str[i][j], gpu_nbnxn_t->ktime[i][j].c,
-                                   gpu_nbnxn_t->ktime[i][j].t, tot_gpu);
+                    print_gputimes(fplog,
+                                   k_log_str[i][j],
+                                   gpu_nbnxn_t->ktime[i][j].c,
+                                   gpu_nbnxn_t->ktime[i][j].t,
+                                   tot_gpu);
                 }
             }
         }
         if (gpu_pme_t)
         {
-            for (size_t k = 0; k < gtPME_EVENT_COUNT; k++)
+            for (auto key : keysOf(gpu_pme_t->timing))
             {
-                if (gpu_pme_t->timing[k].c)
+                if (gpu_pme_t->timing[key].c)
                 {
-                    print_gputimes(fplog, PMEStageNames[k], gpu_pme_t->timing[k].c,
-                                   gpu_pme_t->timing[k].t, tot_gpu);
+                    print_gputimes(fplog,
+                                   enumValuetoString(key),
+                                   gpu_pme_t->timing[key].c,
+                                   gpu_pme_t->timing[key].t,
+                                   tot_gpu);
                 }
             }
         }
         if (gpu_nbnxn_t->pruneTime.c)
         {
-            print_gputimes(fplog, "Pruning kernel", gpu_nbnxn_t->pruneTime.c,
-                           gpu_nbnxn_t->pruneTime.t, tot_gpu);
+            print_gputimes(fplog, "Pruning kernel", gpu_nbnxn_t->pruneTime.c, gpu_nbnxn_t->pruneTime.t, tot_gpu);
         }
         print_gputimes(fplog, "F D2H", gpu_nbnxn_t->nb_c, gpu_nbnxn_t->nb_d2h_t, tot_gpu);
         fprintf(fplog, "%s\n", hline);
@@ -1047,21 +970,26 @@ void wallcycle_print(FILE*                            fplog,
              * and avoid adding it to tot_gpu as this is not in the force
              * overlap. We print the fraction as relative to the rest.
              */
-            print_gputimes(fplog, "*Dynamic pruning", gpu_nbnxn_t->dynamicPruneTime.c,
-                           gpu_nbnxn_t->dynamicPruneTime.t, tot_gpu);
+            print_gputimes(fplog,
+                           "*Dynamic pruning",
+                           gpu_nbnxn_t->dynamicPruneTime.c,
+                           gpu_nbnxn_t->dynamicPruneTime.t,
+                           tot_gpu);
             fprintf(fplog, "%s\n", hline);
         }
         gpu_cpu_ratio = tot_gpu / tot_cpu_overlap;
-        if (gpu_nbnxn_t->nb_c > 0 && wc->wcc[ewcFORCE].n > 0)
+        if (gpu_nbnxn_t->nb_c > 0 && wc->wcc[WallCycleCounter::Force].n > 0)
         {
             fprintf(fplog,
                     "\nAverage per-step force GPU/CPU evaluation time ratio: %.3f ms/%.3f ms = "
                     "%.3f\n",
-                    tot_gpu / gpu_nbnxn_t->nb_c, tot_cpu_overlap / wc->wcc[ewcFORCE].n, gpu_cpu_ratio);
+                    tot_gpu / gpu_nbnxn_t->nb_c,
+                    tot_cpu_overlap / wc->wcc[WallCycleCounter::Force].n,
+                    gpu_cpu_ratio);
         }
 
         /* only print notes related to CPU-GPU load balance with PME */
-        if (wc->wcc[ewcPMEMESH].n > 0)
+        if (wc->wcc[WallCycleCounter::PmeMesh].n > 0)
         {
             fprintf(fplog, "For optimal resource utilization this ratio should be close to 1\n");
 
@@ -1122,10 +1050,12 @@ void wallcycle_print(FILE*                            fplog,
                         "call, so timings are not those of real runs.");
     }
 
-    if (wc->wcc[ewcNB_XF_BUF_OPS].n > 0 && (cyc_sum[ewcDOMDEC] > tot * 0.1 || cyc_sum[ewcNS] > tot * 0.1))
+    if (wc->wcc[WallCycleCounter::NbXFBufOps].n > 0
+        && (cyc_sum[static_cast<int>(WallCycleCounter::Domdec)] > tot * 0.1
+            || cyc_sum[static_cast<int>(WallCycleCounter::NS)] > tot * 0.1))
     {
         /* Only the sim master calls this function, so always print to stderr */
-        if (wc->wcc[ewcDOMDEC].n == 0)
+        if (wc->wcc[WallCycleCounter::Domdec].n == 0)
         {
             GMX_LOG(mdlog.warning)
                     .asParagraph()
@@ -1133,7 +1063,7 @@ void wallcycle_print(FILE*                            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",
-                            gmx::roundToInt(100 * cyc_sum[ewcNS] / tot));
+                            gmx::roundToInt(100 * cyc_sum[static_cast<int>(WallCycleCounter::NS)] / tot));
         }
         else
         {
@@ -1144,64 +1074,36 @@ void wallcycle_print(FILE*                            fplog,
                             "      %d %% of the run time was spent in pair search,\n"
                             "      you might want to increase nstlist (this has no effect on "
                             "accuracy)\n",
-                            gmx::roundToInt(100 * cyc_sum[ewcDOMDEC] / tot),
-                            gmx::roundToInt(100 * cyc_sum[ewcNS] / tot));
+                            gmx::roundToInt(100 * cyc_sum[static_cast<int>(WallCycleCounter::Domdec)] / tot),
+                            gmx::roundToInt(100 * cyc_sum[static_cast<int>(WallCycleCounter::NS)] / tot));
         }
     }
 
-    if (cyc_sum[ewcMoveE] > tot * 0.05)
+    if (cyc_sum[static_cast<int>(WallCycleCounter::MoveE)] > tot * 0.05)
     {
         GMX_LOG(mdlog.warning)
                 .asParagraph()
                 .appendTextFormatted(
                         "NOTE: %d %% of the run time was spent communicating energies,\n"
                         "      you might want to increase some nst* mdp options\n",
-                        gmx::roundToInt(100 * cyc_sum[ewcMoveE] / tot));
+                        gmx::roundToInt(100 * cyc_sum[static_cast<int>(WallCycleCounter::MoveE)] / tot));
     }
 }
 
-extern int64_t wcycle_get_reset_counters(gmx_wallcycle_t wc)
+int64_t wcycle_get_reset_counters(gmx_wallcycle* wc)
 {
     if (wc == nullptr)
     {
         return -1;
     }
-
     return wc->reset_counters;
 }
 
-extern void wcycle_set_reset_counters(gmx_wallcycle_t wc, int64_t reset_counters)
+void wcycle_set_reset_counters(gmx_wallcycle* wc, int64_t reset_counters)
 {
     if (wc == nullptr)
     {
         return;
     }
-
     wc->reset_counters = reset_counters;
 }
-
-void wallcycle_sub_start(gmx_wallcycle_t wc, int ewcs)
-{
-    if (useCycleSubcounters && wc != nullptr)
-    {
-        wc->wcsc[ewcs].start = gmx_cycles_read();
-    }
-}
-
-void wallcycle_sub_start_nocount(gmx_wallcycle_t wc, int ewcs)
-{
-    if (useCycleSubcounters && wc != nullptr)
-    {
-        wallcycle_sub_start(wc, ewcs);
-        wc->wcsc[ewcs].n--;
-    }
-}
-
-void wallcycle_sub_stop(gmx_wallcycle_t wc, int ewcs)
-{
-    if (useCycleSubcounters && wc != nullptr)
-    {
-        wc->wcsc[ewcs].c += gmx_cycles_read() - wc->wcsc[ewcs].start;
-        wc->wcsc[ewcs].n++;
-    }
-}
index 2cbc7fd3cb192ba6fe18ea7f4b3ba1afde2ffe7d..f68035f2a53db83c78bcbeb93318c2f65594e9b4 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <stdio.h>
 
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "gromacs/timing/cyclecounter.h"
 #include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/enumerationhelpers.h"
+
+#ifndef DEBUG_WCYCLE
+/*! \brief Enables consistency checking for the counters.
+ *
+ * If the macro is set to 1, code checks if you stop a counter different from the last
+ * one that was opened and if you do nest too deep.
+ */
+#    define DEBUG_WCYCLE 0
+#endif
 
-typedef struct gmx_wallcycle* gmx_wallcycle_t;
 struct t_commrec;
-static constexpr gmx_wallcycle* nullWallcycle = nullptr;
 
-enum
+#ifndef DEBUG_WCYCLE
+/*! \brief Enables consistency checking for the counters.
+ *
+ * If the macro is set to 1, code checks if you stop a counter different from the last
+ * one that was opened and if you do nest too deep.
+ */
+#    define DEBUG_WCYCLE 0
+#endif
+
+enum class WallCycleCounter : int
 {
-    ewcRUN,
-    ewcSTEP,
-    ewcPPDURINGPME,
-    ewcDOMDEC,
-    ewcDDCOMMLOAD,
-    ewcDDCOMMBOUND,
-    ewcVSITECONSTR,
-    ewcPP_PMESENDX,
-    ewcNS,
-    ewcLAUNCH_GPU,
-    ewcMOVEX,
-    ewcFORCE,
-    ewcMOVEF,
-    ewcPMEMESH,
-    ewcPME_REDISTXF,
-    ewcPME_SPREAD,
-    ewcPME_GATHER,
-    ewcPME_FFT,
-    ewcPME_FFTCOMM,
-    ewcLJPME,
-    ewcPME_SOLVE,
-    ewcPMEWAITCOMM,
-    ewcPP_PMEWAITRECVF,
-    ewcWAIT_GPU_PME_SPREAD,
-    ewcPME_FFT_MIXED_MODE,
-    ewcPME_SOLVE_MIXED_MODE,
-    ewcWAIT_GPU_PME_GATHER,
-    ewcWAIT_GPU_BONDED,
-    ewcPME_GPU_F_REDUCTION,
-    ewcWAIT_GPU_NB_NL,
-    ewcWAIT_GPU_NB_L,
-    ewcWAIT_GPU_STATE_PROPAGATOR_DATA,
-    ewcNB_XF_BUF_OPS,
-    ewcVSITESPREAD,
-    ewcPULLPOT,
-    ewcAWH,
-    ewcTRAJ,
-    ewcUPDATE,
-    ewcCONSTR,
-    ewcMoveE,
-    ewcROT,
-    ewcROTadd,
-    ewcSWAP,
-    ewcIMD,
-    ewcTEST,
-    ewcNR
+    Run,
+    Step,
+    PpDuringPme,
+    Domdec,
+    DDCommLoad,
+    DDCommBound,
+    VsiteConstr,
+    PpPmeSendX,
+    NS,
+    LaunchGpu,
+    MoveX,
+    Force,
+    MoveF,
+    PmeMesh,
+    PmeRedistXF,
+    PmeSpread,
+    PmeGather,
+    PmeFft,
+    PmeFftComm,
+    LJPme,
+    PmeSolve,
+    PmeWaitComm,
+    PpPmeWaitRecvF,
+    WaitGpuPmeSpread,
+    PmeFftMixedMode,
+    PmeSolveMixedMode,
+    WaitGpuPmeGather,
+    WaitGpuBonded,
+    PmeGpuFReduction,
+    WaitGpuNbNL,
+    WaitGpuNbL,
+    WaitGpuStatePropagatorData,
+    NbXFBufOps,
+    VsiteSpread,
+    PullPot,
+    Awh,
+    Traj,
+    Update,
+    Constr,
+    MoveE,
+    Rot,
+    RotAdd,
+    Swap,
+    Imd,
+    Test,
+    Count
 };
 
-enum
+enum class WallCycleSubCounter : int
 {
-    ewcsDD_REDIST,
-    ewcsDD_GRID,
-    ewcsDD_SETUPCOMM,
-    ewcsDD_MAKETOP,
-    ewcsDD_MAKECONSTR,
-    ewcsDD_TOPOTHER,
-    ewcsDD_GPU,
-    ewcsNBS_GRID_LOCAL,
-    ewcsNBS_GRID_NONLOCAL,
-    ewcsNBS_SEARCH_LOCAL,
-    ewcsNBS_SEARCH_NONLOCAL,
-    ewcsLISTED,
-    ewcsLISTED_FEP,
-    ewcsRESTRAINTS,
-    ewcsLISTED_BUF_OPS,
-    ewcsNONBONDED_PRUNING,
-    ewcsNONBONDED_KERNEL,
-    ewcsNONBONDED_CLEAR,
-    ewcsNONBONDED_FEP,
-    ewcsLAUNCH_GPU_NONBONDED,
-    ewcsLAUNCH_GPU_BONDED,
-    ewcsLAUNCH_GPU_PME,
-    ewcsLAUNCH_STATE_PROPAGATOR_DATA,
-    ewcsEWALD_CORRECTION,
-    ewcsNB_X_BUF_OPS,
-    ewcsNB_F_BUF_OPS,
-    ewcsCLEAR_FORCE_BUFFER,
-    ewcsLAUNCH_GPU_NB_X_BUF_OPS,
-    ewcsLAUNCH_GPU_NB_F_BUF_OPS,
-    ewcsLAUNCH_GPU_MOVEX,
-    ewcsLAUNCH_GPU_MOVEF,
-    ewcsLAUNCH_GPU_UPDATE_CONSTRAIN,
-    ewcsTEST,
-    ewcsNR
+    DDRedist,
+    DDGrid,
+    DDSetupComm,
+    DDMakeTop,
+    DDMakeConstr,
+    DDTopOther,
+    DDGpu,
+    NBSGridLocal,
+    NBSGridNonLocal,
+    NBSSearchLocal,
+    NBSSearchNonLocal,
+    Listed,
+    ListedFep,
+    Restraints,
+    ListedBufOps,
+    NonbondedPruning,
+    NonbondedKernel,
+    NonbondedClear,
+    NonbondedFep,
+    LaunchGpuNonBonded,
+    LaunchGpuBonded,
+    LaunchGpuPme,
+    LaunchStatePropagatorData,
+    EwaldCorrection,
+    NBXBufOps,
+    NBFBufOps,
+    ClearForceBuffer,
+    LaunchGpuNBXBufOps,
+    LaunchGpuNBFBufOps,
+    LaunchGpuMoveX,
+    LaunchGpuMoveF,
+    LaunchGpuUpdateConstrain,
+    Test,
+    Count
 };
 
-gmx_bool wallcycle_have_counter();
-/* Returns if cycle counting is supported */
+static constexpr int sc_numWallCycleCounters        = static_cast<int>(WallCycleCounter::Count);
+static constexpr int sc_numWallCycleSubCounters     = static_cast<int>(WallCycleSubCounter::Count);
+static constexpr int sc_numWallCycleCountersSquared = sc_numWallCycleCounters * sc_numWallCycleCounters;
+static constexpr bool sc_useCycleSubcounters        = GMX_CYCLE_SUBCOUNTERS;
 
-gmx_wallcycle_t wallcycle_init(FILE* fplog, int resetstep, struct t_commrec* cr);
-/* Returns the wall cycle structure.
- * Returns NULL when cycle counting is not supported.
- */
+struct wallcc_t
+{
+    int          n;
+    gmx_cycles_t c;
+    gmx_cycles_t start;
+};
+
+#if DEBUG_WCYCLE
+static constexpr int c_MaxWallCycleDepth = 6;
+#endif
+
+
+struct gmx_wallcycle
+{
+    gmx::EnumerationArray<WallCycleCounter, wallcc_t> wcc;
+    /* did we detect one or more invalid cycle counts */
+    bool haveInvalidCount;
+    /* variables for testing/debugging */
+    bool                  wc_barrier;
+    std::vector<wallcc_t> wcc_all;
+    int                   wc_depth;
+#if DEBUG_WCYCLE
+    std::array<WallCycleCounter, c_MaxWallCycleDepth> counterlist;
+    int                                               count_depth;
+    bool                                              isMasterRank;
+#endif
+    WallCycleCounter                                     ewc_prev;
+    gmx_cycles_t                                         cycle_prev;
+    int64_t                                              reset_counters;
+    const t_commrec*                                     cr;
+    gmx::EnumerationArray<WallCycleSubCounter, wallcc_t> wcsc;
+};
+
+//! Returns if cycle counting is supported
+bool wallcycle_have_counter();
+
+//! Returns the wall cycle structure.
+std::unique_ptr<gmx_wallcycle> wallcycle_init(FILE* fplog, int resetstep, const t_commrec* cr);
 
-/* cleans up wallcycle structure */
-void wallcycle_destroy(gmx_wallcycle_t wc);
+//! Adds custom barrier for wallcycle counting.
+void wallcycleBarrier(gmx_wallcycle* wc);
 
-void wallcycle_start(gmx_wallcycle_t wc, int ewc);
-/* Starts the cycle counter (and increases the call count) */
+void wallcycle_sub_get(gmx_wallcycle* wc, WallCycleSubCounter ewcs, int* n, double* c);
+/* Returns the cumulative count and sub cycle count for ewcs */
 
-void wallcycle_start_nocount(gmx_wallcycle_t wc, int ewc);
-/* Starts the cycle counter without increasing the call count */
+inline void wallcycle_all_start(gmx_wallcycle* wc, WallCycleCounter ewc, gmx_cycles_t cycle)
+{
+    wc->ewc_prev   = ewc;
+    wc->cycle_prev = cycle;
+}
 
-double wallcycle_stop(gmx_wallcycle_t wc, int ewc);
-/* Stop the cycle count for ewc, returns the last cycle count */
+inline void wallcycle_all_stop(gmx_wallcycle* wc, WallCycleCounter ewc, gmx_cycles_t cycle)
+{
+    const int prev    = static_cast<int>(wc->ewc_prev);
+    const int current = static_cast<int>(ewc);
+    wc->wcc_all[prev * sc_numWallCycleCounters + current].n += 1;
+    wc->wcc_all[prev * sc_numWallCycleCounters + current].c += cycle - wc->cycle_prev;
+}
 
-void wallcycle_increment_event_count(gmx_wallcycle_t wc, int ewc);
-/* Only increment call count for ewc by one */
+//! Starts the cycle counter (and increases the call count)
+inline void wallcycle_start(gmx_wallcycle* wc, WallCycleCounter ewc)
+{
+    if (wc == nullptr)
+    {
+        return;
+    }
 
-void wallcycle_get(gmx_wallcycle_t wc, int ewc, int* n, double* c);
-/* Returns the cumulative count and cycle count for ewc */
+    wallcycleBarrier(wc);
 
-void wallcycle_reset_all(gmx_wallcycle_t wc);
-/* Resets all cycle counters to zero */
+#if DEBUG_WCYCLE
+    debug_start_check(wc, ewc);
+#endif
+    gmx_cycles_t cycle = gmx_cycles_read();
+    wc->wcc[ewc].start = cycle;
+    if (!wc->wcc_all.empty())
+    {
+        wc->wc_depth++;
+        if (ewc == WallCycleCounter::Run)
+        {
+            wallcycle_all_start(wc, ewc, cycle);
+        }
+        else if (wc->wc_depth == 3)
+        {
+            wallcycle_all_stop(wc, ewc, cycle);
+        }
+    }
+}
 
-void wallcycle_scale_by_num_threads(gmx_wallcycle_t wc, bool isPmeRank, int nthreads_pp, int nthreads_pme);
-/* Scale the cycle counts to reflect how many threads run for that number of cycles */
+//! Starts the cycle counter without increasing the call count
+inline void wallcycle_start_nocount(gmx_wallcycle* wc, WallCycleCounter ewc)
+{
+    if (wc == nullptr)
+    {
+        return;
+    }
+    wc->wcc[ewc].n++;
+}
 
-int64_t wcycle_get_reset_counters(gmx_wallcycle_t wc);
-/* Return reset_counters from wc struct */
+//! Stop the cycle count for ewc , returns the last cycle count
+inline double wallcycle_stop(gmx_wallcycle* wc, WallCycleCounter ewc)
+{
+    gmx_cycles_t cycle, last;
 
-void wcycle_set_reset_counters(gmx_wallcycle_t wc, int64_t reset_counters);
-/* Set reset_counters */
+    if (wc == nullptr)
+    {
+        return 0;
+    }
 
-void wallcycle_sub_start(gmx_wallcycle_t wc, int ewcs);
-/* Set the start sub cycle count for ewcs */
+    wallcycleBarrier(wc);
 
-void wallcycle_sub_start_nocount(gmx_wallcycle_t wc, int ewcs);
-/* Set the start sub cycle count for ewcs without increasing the call count */
+#if DEBUG_WCYCLE
+    debug_stop_check(wc, ewc);
+#endif
+
+    /* When processes or threads migrate between cores, the cycle counting
+     * can get messed up if the cycle counter on different cores are not
+     * synchronized. When this happens we expect both large negative and
+     * positive cycle differences. We can detect negative cycle differences.
+     * Detecting too large positive counts if difficult, since count can be
+     * large, especially for ewcRUN. If we detect a negative count,
+     * we will not print the cycle accounting table.
+     */
+    cycle = gmx_cycles_read();
+    if (cycle >= wc->wcc[ewc].start)
+    {
+        last = cycle - wc->wcc[ewc].start;
+    }
+    else
+    {
+        last                 = 0;
+        wc->haveInvalidCount = true;
+    }
+    wc->wcc[ewc].c += last;
+    wc->wcc[ewc].n++;
+    if (!wc->wcc_all.empty())
+    {
+        wc->wc_depth--;
+        if (ewc == WallCycleCounter::Run)
+        {
+            wallcycle_all_stop(wc, ewc, cycle);
+        }
+        else if (wc->wc_depth == 2)
+        {
+            wallcycle_all_start(wc, ewc, cycle);
+        }
+    }
+
+    return last;
+}
+
+//! Only increment call count for ewc by one
+inline void wallcycle_increment_event_count(gmx_wallcycle* wc, WallCycleCounter ewc)
+{
+    if (wc == nullptr)
+    {
+        return;
+    }
+    wc->wcc[ewc].n++;
+}
 
-void wallcycle_sub_stop(gmx_wallcycle_t wc, int ewcs);
-/* Stop the sub cycle count for ewcs */
+//! Returns the cumulative count and cycle count for ewc
+void wallcycle_get(gmx_wallcycle* wc, WallCycleCounter ewc, int* n, double* c);
+
+//! Resets all cycle counters to zero
+void wallcycle_reset_all(gmx_wallcycle* wc);
+
+//! Scale the cycle counts to reflect how many threads run for that number of cycles
+void wallcycle_scale_by_num_threads(gmx_wallcycle* wc, bool isPmeRank, int nthreads_pp, int nthreads_pme);
+
+//! Return reset_counters from wc struct
+int64_t wcycle_get_reset_counters(gmx_wallcycle* wc);
+
+//! Set reset_counters
+void wcycle_set_reset_counters(gmx_wallcycle* wc, int64_t reset_counters);
+
+//! Set the start sub cycle count for ewcs
+inline void wallcycle_sub_start(gmx_wallcycle* wc, WallCycleSubCounter ewcs)
+{
+    if (sc_useCycleSubcounters && wc != nullptr)
+    {
+        wc->wcsc[ewcs].start = gmx_cycles_read();
+    }
+}
+
+//! Set the start sub cycle count for ewcs without increasing the call count
+inline void wallcycle_sub_start_nocount(gmx_wallcycle* wc, WallCycleSubCounter ewcs)
+{
+    if (sc_useCycleSubcounters && wc != nullptr)
+    {
+        wc->wcsc[ewcs].start = gmx_cycles_read();
+    }
+}
+
+//! Stop the sub cycle count for ewcs
+inline void wallcycle_sub_stop(gmx_wallcycle* wc, WallCycleSubCounter ewcs)
+{
+    if (sc_useCycleSubcounters && wc != nullptr)
+    {
+        wc->wcsc[ewcs].c += gmx_cycles_read() - wc->wcsc[ewcs].start;
+        wc->wcsc[ewcs].n++;
+    }
+}
 
 #endif
index 1bf3096fea4871a5e8d23d8565f3373123be4557..950b5b8af660596426f5fb7cc86763f6182d16aa 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <array>
 
+#include "gromacs/timing/wallcycle.h"
 #include "gromacs/utility/basedefinitions.h"
 
 struct t_commrec;
@@ -54,14 +55,13 @@ namespace gmx
 class MDLogger;
 }
 
-typedef struct gmx_wallcycle* gmx_wallcycle_t;
 struct gmx_wallclock_gpu_nbnxn_t;
 struct gmx_wallclock_gpu_pme_t;
 
-typedef std::array<double, int(ewcNR) + int(ewcsNR)> WallcycleCounts;
+using WallcycleCounts = std::array<double, sc_numWallCycleCounters + sc_numWallCycleSubCounters>;
 /* Convenience typedef */
 
-WallcycleCounts wallcycle_sum(const t_commrec* cr, gmx_wallcycle_t wc);
+WallcycleCounts wallcycle_sum(const t_commrec* cr, gmx_wallcycle* wc);
 /* Return a vector of the sum of cycle counts over the nodes in
    cr->mpi_comm_mysim. */
 
@@ -72,7 +72,7 @@ void wallcycle_print(FILE*                            fplog,
                      int                              nth_pp,
                      int                              nth_pme,
                      double                           realtime,
-                     gmx_wallcycle_t                  wc,
+                     gmx_wallcycle                  wc,
                      const WallcycleCounts&           cyc_sum,
                      const gmx_wallclock_gpu_nbnxn_t* gpu_nbnxn_t,
                      const gmx_wallclock_gpu_pme_t*   gpu_pme_t);
index 442b77b234837fa9b31f0f6d6cac5abb958577e6..747d39cbb13b01a399521bf91239cab1a54f67dc 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2014,2015,2018, by the GROMACS development team, led by
+# Copyright (c) 2014,2015,2018,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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.
 
+# Set up the module library
+add_library(tools INTERFACE)
 file(GLOB TOOLS_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${TOOLS_SOURCES} PARENT_SCOPE)
 
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(tools PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(tools PUBLIC
+target_include_directories(tools INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(tools PUBLIC
+target_link_libraries(tools INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when tools is an OBJECT target
+#target_link_libraries(tools PUBLIC legacy_api)
+#target_link_libraries(tools PRIVATE common)
+
+# Module dependencies
+# tools interfaces convey transitive dependence on these modules.
+#target_link_libraries(tools PUBLIC
+target_link_libraries(tools INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(tools PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(tools PRIVATE legacy_modules)
+
+
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index dc7d16b57372ea83e8f53aa3a009a8bd48fc40a7..c660dc84831f8bc1616e870ee7bd41483998e5a7 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2013, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -117,9 +117,9 @@ static void comp_tpx(const char* fn1, const char* fn2, gmx_bool bRMSD, real ftol
     }
     else
     {
-        if (ir[0]->efep == efepNO)
+        if (ir[0]->efep == FreeEnergyPerturbationType::No)
         {
-            fprintf(stdout, "inputrec->efep = %s\n", efep_names[ir[0]->efep]);
+            fprintf(stdout, "inputrec->efep = %s\n", enumValueToString(ir[0]->efep));
         }
         else
         {
@@ -271,8 +271,12 @@ static void chk_bonds(const InteractionDefinitions* idef, PbcType pbcType, rvec*
                     deviation = gmx::square(blen - b0);
                     if (std::sqrt(deviation / gmx::square(b0)) > tol)
                     {
-                        fprintf(stderr, "Distance between atoms %d and %d is %.3f, should be %.3f\n",
-                                ai + 1, aj + 1, blen, b0);
+                        fprintf(stderr,
+                                "Distance between atoms %d and %d is %.3f, should be %.3f\n",
+                                ai + 1,
+                                aj + 1,
+                                blen,
+                                b0);
                     }
                 }
             }
@@ -298,7 +302,7 @@ static void chk_trj(const gmx_output_env_t* oenv, const char* fn, const char* tp
     {
         read_tpx_state(tpr, &ir, &state, &mtop);
         top = std::make_unique<gmx_localtop_t>(mtop.ffparams);
-        gmx_mtop_generate_local_top(mtop, top.get(), ir.efep != efepNO);
+        gmx_mtop_generate_local_top(mtop, top.get(), ir.efep != FreeEnergyPerturbationType::No);
     }
     new_natoms = -1;
     natoms     = -1;
@@ -357,8 +361,12 @@ static void chk_trj(const gmx_output_env_t* oenv, const char* fn, const char* tp
                 > 0.1 * (std::fabs(fr.time - old_t1) + std::fabs(old_t1 - old_t2)))
             {
                 bShowTimestep = FALSE;
-                fprintf(stderr, "%sTimesteps at t=%g don't match (%g, %g)\n", newline ? "\n" : "",
-                        old_t1, old_t1 - old_t2, fr.time - old_t1);
+                fprintf(stderr,
+                        "%sTimesteps at t=%g don't match (%g, %g)\n",
+                        newline ? "\n" : "",
+                        old_t1,
+                        old_t1 - old_t2,
+                        fr.time - old_t1);
             }
         }
         natoms = new_natoms;
@@ -486,15 +494,18 @@ static void chk_tps(const char* fn, real vdw_fac, real bon_lo, real bon_hi)
                 ekin += 0.5 * atoms->atom[i].m * v[i][j] * v[i][j];
             }
         }
-        temp1 = (2.0 * ekin) / (natom * DIM * BOLTZ);
-        temp2 = (2.0 * ekin) / (natom * (DIM - 1) * BOLTZ);
+        temp1 = (2.0 * ekin) / (natom * DIM * gmx::c_boltz);
+        temp2 = (2.0 * ekin) / (natom * (DIM - 1) * gmx::c_boltz);
         fprintf(stderr, "Kinetic energy: %g (kJ/mol)\n", ekin);
         fprintf(stderr,
                 "Assuming the number of degrees of freedom to be "
                 "Natoms * %d or Natoms * %d,\n"
                 "the velocities correspond to a temperature of the system\n"
                 "of %g K or %g K respectively.\n\n",
-                DIM, DIM - 1, temp1, temp2);
+                DIM,
+                DIM - 1,
+                temp1,
+                temp2);
     }
 
     /* check coordinates */
@@ -507,17 +518,25 @@ static void chk_tps(const char* fn, real vdw_fac, real bon_lo, real bon_hi)
         fprintf(stderr,
                 "Checking for atoms closer than %g and not between %g and %g,\n"
                 "relative to sum of Van der Waals distance:\n",
-                vdw_fac, bon_lo, bon_hi);
+                vdw_fac,
+                bon_lo,
+                bon_hi);
         snew(atom_vdw, natom);
         AtomProperties aps;
         for (i = 0; (i < natom); i++)
         {
-            aps.setAtomProperty(epropVDW, *(atoms->resinfo[atoms->atom[i].resind].name),
-                                *(atoms->atomname[i]), &(atom_vdw[i]));
+            aps.setAtomProperty(epropVDW,
+                                *(atoms->resinfo[atoms->atom[i].resind].name),
+                                *(atoms->atomname[i]),
+                                &(atom_vdw[i]));
             if (debug)
             {
-                fprintf(debug, "%5d %4s %4s %7g\n", i + 1, *(atoms->resinfo[atoms->atom[i].resind].name),
-                        *(atoms->atomname[i]), atom_vdw[i]);
+                fprintf(debug,
+                        "%5d %4s %4s %7g\n",
+                        i + 1,
+                        *(atoms->resinfo[atoms->atom[i].resind].name),
+                        *(atoms->atomname[i]),
+                        atom_vdw[i]);
             }
         }
         if (bB)
@@ -549,15 +568,32 @@ static void chk_tps(const char* fn, real vdw_fac, real bon_lo, real bon_hi)
                 {
                     if (bFirst)
                     {
-                        fprintf(stderr, "\r%5s %4s %8s %5s  %5s %4s %8s %5s  %6s\n", "atom#", "name",
-                                "residue", "r_vdw", "atom#", "name", "residue", "r_vdw", "distance");
+                        fprintf(stderr,
+                                "\r%5s %4s %8s %5s  %5s %4s %8s %5s  %6s\n",
+                                "atom#",
+                                "name",
+                                "residue",
+                                "r_vdw",
+                                "atom#",
+                                "name",
+                                "residue",
+                                "r_vdw",
+                                "distance");
                         bFirst = FALSE;
                     }
-                    fprintf(stderr, "\r%5d %4s %4s%4d %-5.3g  %5d %4s %4s%4d %-5.3g  %-6.4g\n", i + 1,
-                            *(atoms->atomname[i]), *(atoms->resinfo[atoms->atom[i].resind].name),
-                            atoms->resinfo[atoms->atom[i].resind].nr, atom_vdw[i], j + 1,
-                            *(atoms->atomname[j]), *(atoms->resinfo[atoms->atom[j].resind].name),
-                            atoms->resinfo[atoms->atom[j].resind].nr, atom_vdw[j], std::sqrt(r2));
+                    fprintf(stderr,
+                            "\r%5d %4s %4s%4d %-5.3g  %5d %4s %4s%4d %-5.3g  %-6.4g\n",
+                            i + 1,
+                            *(atoms->atomname[i]),
+                            *(atoms->resinfo[atoms->atom[i].resind].name),
+                            atoms->resinfo[atoms->atom[i].resind].nr,
+                            atom_vdw[i],
+                            j + 1,
+                            *(atoms->atomname[j]),
+                            *(atoms->resinfo[atoms->atom[j].resind].name),
+                            atoms->resinfo[atoms->atom[j].resind].nr,
+                            atom_vdw[j],
+                            std::sqrt(r2));
                 }
             }
         }
@@ -593,12 +629,20 @@ static void chk_tps(const char* fn, real vdw_fac, real bon_lo, real bon_hi)
                                 "):\n"
                                 "(These may occur often and are normally not a problem)\n"
                                 "%5s %4s %8s %5s  %s\n",
-                                "atom#", "name", "residue", "r_vdw", "coordinate");
+                                "atom#",
+                                "name",
+                                "residue",
+                                "r_vdw",
+                                "coordinate");
                         bFirst = FALSE;
                     }
-                    fprintf(stderr, "%5d %4s %4s%4d %-5.3g", i, *(atoms->atomname[i]),
+                    fprintf(stderr,
+                            "%5d %4s %4s%4d %-5.3g",
+                            i,
+                            *(atoms->atomname[i]),
                             *(atoms->resinfo[atoms->atom[i].resind].name),
-                            atoms->resinfo[atoms->atom[i].resind].nr, atom_vdw[i]);
+                            atoms->resinfo[atoms->atom[i].resind].nr,
+                            atom_vdw[i]);
                     for (j = 0; (j < DIM); j++)
                     {
                         fprintf(stderr, " %6.3g", x[i][j]);
@@ -637,8 +681,12 @@ static void chk_ndx(const char* fn)
         printf("Nr.   Group               #Entries   First    Last\n");
         for (i = 0; (i < grps->nr); i++)
         {
-            printf("%4d  %-20s%8d%8d%8d\n", i, grpname[i], grps->index[i + 1] - grps->index[i],
-                   grps->a[grps->index[i]] + 1, grps->a[grps->index[i + 1] - 1] + 1);
+            printf("%4d  %-20s%8d%8d%8d\n",
+                   i,
+                   grpname[i],
+                   grps->index[i + 1] - grps->index[i],
+                   grps->a[grps->index[i]] + 1,
+                   grps->a[grps->index[i + 1] - 1] + 1);
         }
     }
     for (i = 0; (i < grps->nr); i++)
@@ -681,8 +729,7 @@ static void chk_enx(const char* fn)
                 > 0.1 * (fabs(fr->t - old_t1) + std::fabs(old_t1 - old_t2)))
             {
                 bShowTStep = FALSE;
-                fprintf(stderr, "\nTimesteps at t=%g don't match (%g, %g)\n", old_t1,
-                        old_t1 - old_t2, fr->t - old_t1);
+                fprintf(stderr, "\nTimesteps at t=%g don't match (%g, %g)\n", old_t1, old_t1 - old_t2, fr->t - old_t1);
             }
         }
         old_t2 = old_t1;
@@ -694,8 +741,7 @@ static void chk_enx(const char* fn)
         }
         if (fnr == 0)
         {
-            fprintf(stderr, "\rframe: %6s (index %6d), t: %10.3f\n", gmx_step_str(fr->step, buf),
-                    fnr, fr->t);
+            fprintf(stderr, "\rframe: %6s (index %6d), t: %10.3f\n", gmx_step_str(fr->step, buf), fnr, fr->t);
         }
         fnr++;
     }
@@ -753,14 +799,14 @@ int gmx_check(int argc, char* argv[])
     const char *fn1 = nullptr, *fn2 = nullptr, *tex = nullptr;
 
     gmx_output_env_t* oenv;
-    static real       vdw_fac  = 0.8;
-    static real       bon_lo   = 0.4;
-    static real       bon_hi   = 0.7;
-    static gmx_bool   bRMSD    = FALSE;
-    static real       ftol     = 0.001;
-    static real       abstol   = 0.001;
-    static gmx_bool   bCompAB  = FALSE;
-    static char*      lastener = nullptr;
+    real              vdw_fac  = 0.8;
+    real              bon_lo   = 0.4;
+    real              bon_hi   = 0.7;
+    gmx_bool          bRMSD    = FALSE;
+    real              ftol     = 0.001;
+    real              abstol   = 0.001;
+    gmx_bool          bCompAB  = FALSE;
+    char*             lastener = nullptr;
     static t_pargs    pa[]     = {
         { "-vdwfac",
           FALSE,
index fe66b9f58814f5d3ad38b6a47dd3bb60284cfe75..a1dd5ef858d9421a19f75a3e626e59274b1bf49b 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -73,7 +73,8 @@ static void rangeCheck(int numberInIndexFile, int maxAtomNumber)
         gmx_fatal(FARGS,
                   "Your index file contains atomnumbers (e.g. %d)\nthat are larger than the number "
                   "of atoms in the tpr file (%d)",
-                  (numberInIndexFile), (maxAtomNumber));
+                  (numberInIndexFile),
+                  (maxAtomNumber));
     }
 }
 
@@ -127,8 +128,13 @@ static gmx::ListOfLists<int> reduce_listoflists(gmx::ArrayRef<const int>     inv
         }
     }
 
-    fprintf(stderr, "Reduced block %8s from %6zu to %6zu index-, %6d to %6d a-entries\n", name,
-            src.size(), lists.size(), src.numElements(), lists.numElements());
+    fprintf(stderr,
+            "Reduced block %8s from %6zu to %6zu index-, %6d to %6d a-entries\n",
+            name,
+            src.size(),
+            lists.size(),
+            src.numElements(),
+            lists.numElements());
 
     return lists;
 }
@@ -215,8 +221,11 @@ static void reduce_ilist(gmx::ArrayRef<const int> invindex,
                 ilReduced.push_back(il->iatoms[i], nratoms, newAtoms.data());
             }
         }
-        fprintf(stderr, "Reduced ilist %8s from %6d to %6d entries\n", name,
-                il->size() / (nratoms + 1), ilReduced.size() / (nratoms + 1));
+        fprintf(stderr,
+                "Reduced ilist %8s from %6d to %6d entries\n",
+                name,
+                il->size() / (nratoms + 1),
+                ilReduced.size() / (nratoms + 1));
 
         *il = std::move(ilReduced);
     }
@@ -226,7 +235,7 @@ static void reduce_topology_x(int gnx, int index[], gmx_mtop_t* mtop, rvec x[],
 {
     gmx_localtop_t top(mtop->ffparams);
     gmx_mtop_generate_local_top(*mtop, &top, false);
-    t_atoms atoms = gmx_mtop_global_atoms(mtop);
+    t_atoms atoms = gmx_mtop_global_atoms(*mtop);
 
     const std::vector<bool> bKeep    = bKeepIt(gnx, atoms.nr, index);
     const std::vector<int>  invindex = invind(gnx, atoms.nr, index);
@@ -237,7 +246,10 @@ static void reduce_topology_x(int gnx, int index[], gmx_mtop_t* mtop, rvec x[],
 
     for (int i = 0; (i < F_NRE); i++)
     {
-        reduce_ilist(invindex, bKeep, &(top.idef.il[i]), interaction_function[i].nratoms,
+        reduce_ilist(invindex,
+                     bKeep,
+                     &(top.idef.il[i]),
+                     interaction_function[i].nratoms,
                      interaction_function[i].name);
     }
 
@@ -335,21 +347,21 @@ void ConvertTpr::initOptions(IOptionsContainer* options, ICommandLineOptionsModu
     settings->setHelpText(desc);
 
     options->addOption(FileNameOption("s")
-                               .filetype(eftTopology)
+                               .filetype(OptionFileType::Topology)
                                .inputFile()
                                .required()
                                .store(&inputTprFileName_)
                                .defaultBasename("topol")
                                .description("Run input file to modify"));
     options->addOption(FileNameOption("n")
-                               .filetype(eftIndex)
+                               .filetype(OptionFileType::Index)
                                .inputFile()
                                .store(&inputIndexFileName_)
                                .storeIsSet(&haveReadIndexFile_)
                                .defaultBasename("index")
                                .description("File containing additional index groups"));
     options->addOption(FileNameOption("o")
-                               .filetype(eftTopology)
+                               .filetype(OptionFileType::Topology)
                                .outputFile()
                                .store(&outputTprFileName_)
                                .defaultBasename("tprout")
@@ -400,23 +412,28 @@ int ConvertTpr::run()
         {
             ir->nsteps = ir->nsteps - (currentMaxStep - ir->init_step)
                          + gmx::roundToInt64(extendTime_ / ir->delta_t);
-            printf("Extending remaining runtime of by %g ps (now %s steps)\n", extendTime_,
+            printf("Extending remaining runtime of by %g ps (now %s steps)\n",
+                   extendTime_,
                    gmx_step_str(ir->nsteps, buf));
         }
         else if (runToMaxTimeIsSet_)
         {
             printf("nsteps = %s, run_step = %s, current_t = %g, until = %g\n",
-                   gmx_step_str(ir->nsteps, buf), gmx_step_str(currentMaxStep, buf2),
-                   currentRunTime, runToMaxTime_);
+                   gmx_step_str(ir->nsteps, buf),
+                   gmx_step_str(currentMaxStep, buf2),
+                   currentRunTime,
+                   runToMaxTime_);
             ir->nsteps = gmx::roundToInt64((currentMaxRunTime - currentRunTime) / ir->delta_t);
-            printf("Extending remaining runtime until %g ps (now %s steps)\n", currentMaxRunTime,
+            printf("Extending remaining runtime until %g ps (now %s steps)\n",
+                   currentMaxRunTime,
                    gmx_step_str(ir->nsteps, buf));
         }
         else
         {
             ir->nsteps -= currentMaxStep - ir->init_step;
             /* Print message */
-            printf("%s steps (%g ps) remaining from first run.\n", gmx_step_str(ir->nsteps, buf),
+            printf("%s steps (%g ps) remaining from first run.\n",
+                   gmx_step_str(ir->nsteps, buf),
                    ir->nsteps * ir->delta_t);
         }
     }
@@ -427,7 +444,7 @@ int ConvertTpr::run()
 
         if (haveReadIndexFile_ || !(maxStepsIsSet_ || extendTimeIsSet_ || runToMaxTimeIsSet_))
         {
-            atoms         = gmx_mtop_global_atoms(&mtop);
+            atoms         = gmx_mtop_global_atoms(mtop);
             int   gnx     = 0;
             int*  index   = nullptr;
             char* grpname = nullptr;
@@ -450,7 +467,8 @@ int ConvertTpr::run()
                 fprintf(stderr,
                         "Will write subset %s of original tpx containing %d "
                         "atoms\n",
-                        grpname, gnx);
+                        grpname,
+                        gnx);
                 reduce_topology_x(gnx, index, &mtop, state.x.rvec_array(), state.v.rvec_array());
                 state.natoms = gnx;
             }
@@ -466,12 +484,18 @@ int ConvertTpr::run()
         }
 
         double stateTime = ir->init_t + ir->init_step * ir->delta_t;
-        sprintf(buf, "Writing statusfile with starting step %s%s and length %s%s steps...\n", "%10",
-                PRId64, "%10", PRId64);
+        sprintf(buf,
+                "Writing statusfile with starting step %s%s and length %s%s steps...\n",
+                "%10",
+                PRId64,
+                "%10",
+                PRId64);
         fprintf(stderr, buf, ir->init_step, ir->nsteps);
-        fprintf(stderr, "                                 time %10.3f and length %10.3f ps\n",
-                stateTime, ir->nsteps * ir->delta_t);
-        write_tpx_state(outputTprFileName_.c_str(), ir, &state, &mtop);
+        fprintf(stderr,
+                "                                 time %10.3f and length %10.3f ps\n",
+                stateTime,
+                ir->nsteps * ir->delta_t);
+        write_tpx_state(outputTprFileName_.c_str(), ir, &state, mtop);
     }
     else
     {
index 9f004bc9fac8af98e5e9162d0c43d3c6d9f28126..541d6da1bfdc2107cbfdbefee978d3fab0d15fe5 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2013, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +168,10 @@ void list_tpr(const char* fn,
         {
             for (auto group : keysOf(gcount))
             {
+                if (group == SimulationAtomGroupType::AccelerationUnused)
+                {
+                    continue;
+                }
                 gcount[group][getGroupType(groups, group, i)]++;
             }
         }
@@ -242,16 +246,23 @@ void list_trr(const char* fn)
         snew(x, trrheader.natoms);
         snew(v, trrheader.natoms);
         snew(f, trrheader.natoms);
-        if (gmx_trr_read_frame_data(fpread, &trrheader, trrheader.box_size ? box : nullptr,
-                                    trrheader.x_size ? x : nullptr, trrheader.v_size ? v : nullptr,
+        if (gmx_trr_read_frame_data(fpread,
+                                    &trrheader,
+                                    trrheader.box_size ? box : nullptr,
+                                    trrheader.x_size ? x : nullptr,
+                                    trrheader.v_size ? v : nullptr,
                                     trrheader.f_size ? f : nullptr))
         {
             sprintf(buf, "%s frame %d", fn, nframe);
             indent = 0;
             indent = pr_title(stdout, indent, buf);
             pr_indent(stdout, indent);
-            fprintf(stdout, "natoms=%10d  step=%10" PRId64 "  time=%12.7e  lambda=%10g\n",
-                    trrheader.natoms, trrheader.step, trrheader.t, trrheader.lambda);
+            fprintf(stdout,
+                    "natoms=%10d  step=%10" PRId64 "  time=%12.7e  lambda=%10g\n",
+                    trrheader.natoms,
+                    trrheader.step,
+                    trrheader.t,
+                    trrheader.lambda);
             if (trrheader.box_size)
             {
                 pr_rvecs(stdout, indent, "box", box, DIM);
@@ -309,8 +320,7 @@ void list_xtc(const char* fn)
         indent = 0;
         indent = pr_title(stdout, indent, buf);
         pr_indent(stdout, indent);
-        fprintf(stdout, "natoms=%10d  step=%10" PRId64 "  time=%12.7e  prec=%10g\n", natoms, step,
-                time, prec);
+        fprintf(stdout, "natoms=%10d  step=%10" PRId64 "  time=%12.7e  prec=%10g\n", natoms, step, time, prec);
         pr_rvecs(stdout, indent, "box", box, DIM);
         pr_rvecs(stdout, indent, "x", x, natoms);
         nframe++;
@@ -381,25 +391,32 @@ void list_tng(const char* fn)
             int64_t n_values_per_frame, n_atoms;
             char    block_name[STRLEN];
 
-            gmx_get_tng_data_next_frame_of_block_type(tng, block_ids[i], &values, &step,
-                                                      &frame_time, &n_values_per_frame, &n_atoms,
-                                                      &prec, block_name, STRLEN, &bOK);
+            gmx_get_tng_data_next_frame_of_block_type(tng,
+                                                      block_ids[i],
+                                                      &values,
+                                                      &step,
+                                                      &frame_time,
+                                                      &n_values_per_frame,
+                                                      &n_atoms,
+                                                      &prec,
+                                                      block_name,
+                                                      STRLEN,
+                                                      &bOK);
             if (!bOK)
             {
                 /* Can't write any output because we don't know what
                    arrays are valid. */
-                fprintf(stderr, "\nWARNING: Incomplete frame at time %g, will not write output\n",
-                        frame_time);
+                fprintf(stderr, "\nWARNING: Incomplete frame at time %g, will not write output\n", frame_time);
             }
             else
             {
-                list_tng_inner(fn, (0 == i), values, step, frame_time, n_values_per_frame, n_atoms,
-                               prec, nframe, block_name);
+                list_tng_inner(
+                        fn, (0 == i), values, step, frame_time, n_values_per_frame, n_atoms, prec, nframe, block_name);
             }
         }
         nframe++;
-    } while (gmx_get_tng_data_block_types_of_next_frame(tng, step, 0, nullptr, &step, &ndatablocks,
-                                                        &block_ids));
+    } while (gmx_get_tng_data_block_types_of_next_frame(
+            tng, step, 0, nullptr, &step, &ndatablocks, &block_ids));
 
     if (block_ids)
     {
@@ -421,8 +438,7 @@ void list_trx(const char* fn)
         case efTRR: list_trr(fn); break;
         case efTNG: list_tng(fn); break;
         default:
-            fprintf(stderr, "File %s is of an unsupported type. Try using the command\n 'less %s'\n",
-                    fn, fn);
+            fprintf(stderr, "File %s is of an unsupported type. Try using the command\n 'less %s'\n", fn, fn);
     }
 }
 
@@ -456,18 +472,23 @@ void list_ene(const char* fn)
         {
             printf("\n%24s  %12.5e  %12s  %12s\n", "time:", fr->t, "step:", gmx_step_str(fr->step, buf));
             printf("%24s  %12s  %12s  %12s\n", "", "", "nsteps:", gmx_step_str(fr->nsteps, buf));
-            printf("%24s  %12.5e  %12s  %12s\n", "delta_t:", fr->dt,
-                   "sum steps:", gmx_step_str(fr->nsum, buf));
+            printf("%24s  %12.5e  %12s  %12s\n", "delta_t:", fr->dt, "sum steps:", gmx_step_str(fr->nsum, buf));
             if (fr->nre == nre)
             {
-                printf("%24s  %12s  %12s  %12s\n", "Component", "Energy", "Av. Energy",
+                printf("%24s  %12s  %12s  %12s\n",
+                       "Component",
+                       "Energy",
+                       "Av. Energy",
                        "Sum Energy");
                 if (fr->nsum > 0)
                 {
                     for (i = 0; (i < nre); i++)
                     {
-                        printf("%24s  %12.5e  %12.5e  %12.5e\n", enm[i].name, fr->ener[i].e,
-                               fr->ener[i].eav, fr->ener[i].esum);
+                        printf("%24s  %12.5e  %12.5e  %12.5e\n",
+                               enm[i].name,
+                               fr->ener[i].e,
+                               fr->ener[i].eav,
+                               fr->ener[i].esum);
                     }
                 }
                 else
@@ -493,42 +514,44 @@ void list_ene(const char* fn)
                 for (i = 0; i < eb->nsub; i++)
                 {
                     t_enxsubblock* sb = &(eb->sub[i]);
-                    printf("  Sub block %3d (%5d elems, type=%s) values:\n", i, sb->nr,
-                           xdr_datatype_names[sb->type]);
+                    printf("  Sub block %3d (%5d elems, type=%s) values:\n",
+                           i,
+                           sb->nr,
+                           enumValueToString(sb->type));
 
                     switch (sb->type)
                     {
-                        case xdr_datatype_float:
+                        case XdrDataType::Float:
                             for (j = 0; j < sb->nr; j++)
                             {
                                 printf("%14d   %8.4f\n", j, sb->fval[j]);
                             }
                             break;
-                        case xdr_datatype_double:
+                        case XdrDataType::Double:
                             for (j = 0; j < sb->nr; j++)
                             {
                                 printf("%14d   %10.6f\n", j, sb->dval[j]);
                             }
                             break;
-                        case xdr_datatype_int:
+                        case XdrDataType::Int:
                             for (j = 0; j < sb->nr; j++)
                             {
                                 printf("%14d %10d\n", j, sb->ival[j]);
                             }
                             break;
-                        case xdr_datatype_int64:
+                        case XdrDataType::Int64:
                             for (j = 0; j < sb->nr; j++)
                             {
                                 printf("%14d %s\n", j, gmx_step_str(sb->lval[j], buf));
                             }
                             break;
-                        case xdr_datatype_char:
+                        case XdrDataType::Char:
                             for (j = 0; j < sb->nr; j++)
                             {
                                 printf("%14d %1c\n", j, sb->cval[j]);
                             }
                             break;
-                        case xdr_datatype_string:
+                        case XdrDataType::String:
                             for (j = 0; j < sb->nr; j++)
                             {
                                 printf("%14d %80s\n", j, sb->sval[j]);
@@ -644,15 +667,21 @@ void Dump::initOptions(IOptionsContainer* options, ICommandLineOptionsModuleSett
     // fix it or block that run path:
     //   Position restraint output from -sys -s is broken
 
-    options->addOption(
-            FileNameOption("s").filetype(eftRunInput).inputFile().store(&inputTprFilename_).description("Run input file to dump"));
+    options->addOption(FileNameOption("s")
+                               .filetype(OptionFileType::RunInput)
+                               .inputFile()
+                               .store(&inputTprFilename_)
+                               .description("Run input file to dump"));
     options->addOption(FileNameOption("f")
-                               .filetype(eftTrajectory)
+                               .filetype(OptionFileType::Trajectory)
                                .inputFile()
                                .store(&inputTrajectoryFilename_)
                                .description("Trajectory file to dump"));
-    options->addOption(
-            FileNameOption("e").filetype(eftEnergy).inputFile().store(&inputEnergyFilename_).description("Energy file to dump"));
+    options->addOption(FileNameOption("e")
+                               .filetype(OptionFileType::Energy)
+                               .inputFile()
+                               .store(&inputEnergyFilename_)
+                               .description("Energy file to dump"));
     options->addOption(
             FileNameOption("cp").legacyType(efCPT).inputFile().store(&inputCheckpointFilename_).description("Checkpoint file to dump"));
     options->addOption(
@@ -686,8 +715,11 @@ int Dump::run()
 {
     if (!inputTprFilename_.empty())
     {
-        list_tpr(inputTprFilename_.c_str(), bShowNumbers_, bShowParams_,
-                 outputMdpFilename_.empty() ? nullptr : outputMdpFilename_.c_str(), bSysTop_,
+        list_tpr(inputTprFilename_.c_str(),
+                 bShowNumbers_,
+                 bShowParams_,
+                 outputMdpFilename_.empty() ? nullptr : outputMdpFilename_.c_str(),
+                 bSysTop_,
                  bOriginalInputrec_);
     }
     else if (!inputTrajectoryFilename_.empty())
index f918abed80abcd6c62be83a94927b4afdb9d3c21..eabfffaabee0345575d470be6d1ef694341b8558 100644 (file)
@@ -187,7 +187,10 @@ static int scan_ene_files(const std::vector<std::string>& files, real* readtime,
                 fprintf(stderr,
                         "Energy files don't match, different number of energies:\n"
                         " %s: %d\n %s: %d\n",
-                        files[f - 1].c_str(), nresav, files[f].c_str(), fr->nre);
+                        files[f - 1].c_str(),
+                        nresav,
+                        files[f].c_str(),
+                        fr->nre);
                 fprintf(stderr,
                         "\nContinue conversion using only the first %d terms (n/y)?\n"
                         "(you should be sure that the energy terms match)\n",
@@ -500,8 +503,8 @@ int gmx_eneconv(int argc, char* argv[])
         { "-error", FALSE, etBOOL, { &bError }, "Stop on errors in the file" }
     };
 
-    if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc,
-                           asize(bugs), bugs, &oenv))
+    if (!parse_common_args(
+                &argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
         return 0;
     }
@@ -598,8 +601,12 @@ int gmx_eneconv(int argc, char* argv[])
 
             if (debug)
             {
-                fprintf(debug, "fr->step %s, fr->t %.4f, fro->step %s fro->t %.4f, w %s\n",
-                        gmx_step_str(fr->step, buf), fr->t, gmx_step_str(fro->step, buf2), fro->t,
+                fprintf(debug,
+                        "fr->step %s, fr->t %.4f, fro->step %s fro->t %.4f, w %s\n",
+                        gmx_step_str(fr->step, buf),
+                        fr->t,
+                        gmx_step_str(fro->step, buf2),
+                        fro->t,
                         gmx::boolToString(bWrite));
             }
 
@@ -632,7 +639,9 @@ int gmx_eneconv(int argc, char* argv[])
                 if (bNewOutput)
                 {
                     bNewOutput = FALSE;
-                    fprintf(stderr, "\nContinue writing frames from t=%g, step=%s\n", fro->t,
+                    fprintf(stderr,
+                            "\nContinue writing frames from t=%g, step=%s\n",
+                            fro->t,
                             gmx_step_str(fro->step, buf));
                 }
 
@@ -742,7 +751,8 @@ int gmx_eneconv(int argc, char* argv[])
                                                "samples away.\n"
                                                "         Use g_energy -odh option to extract these "
                                                "samples.\n",
-                                               files[f].c_str(), size);
+                                               files[f].c_str(),
+                                               size);
                                         warned_about_dh = TRUE;
                                         break;
                                     }
@@ -764,7 +774,9 @@ int gmx_eneconv(int argc, char* argv[])
         {
             f--;
         }
-        printf("\nLast step written from %s: t %g, step %s\n", files[f].c_str(), last_t,
+        printf("\nLast step written from %s: t %g, step %s\n",
+               files[f].c_str(),
+               last_t,
                gmx_step_str(laststep, buf));
         lastfilestep = laststep;
 
@@ -797,8 +809,7 @@ int gmx_eneconv(int argc, char* argv[])
     }
     else
     {
-        fprintf(stderr, "Last frame written was at step %s, time %f\n",
-                gmx_step_str(fro->step, buf), fro->t);
+        fprintf(stderr, "Last frame written was at step %s, time %f\n", gmx_step_str(fro->step, buf), fro->t);
         fprintf(stderr, "Wrote %d frames\n", noutfr);
     }
 
index 34ecf8179847b002e30cef56fc4f7724f5753521..deded7846bea6fb7d289556e23899208cabf93e5 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "gromacs/utility/arrayref.h"
 #include "make_ndx.h"
 
+#include <array>
 #include <cctype>
 #include <cstring>
 
 #include <algorithm>
+#include <array>
+#include <vector>
 
 #include "gromacs/commandline/pargs.h"
 #include "gromacs/fileio/confio.h"
@@ -51,6 +55,7 @@
 #include "gromacs/topology/index.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/arraysize.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
@@ -64,6 +69,7 @@
 #define NAME_LEN 1024
 static const int NOTSET = -92637;
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static gmx_bool bCase = FALSE;
 
 static int or_groups(int nr1, const int* at1, int nr2, const int* at2, int* nr, int* at)
@@ -157,7 +163,7 @@ static gmx_bool is_name_char(char c)
     return (c != '\0' && std::strchr(spec, c) == nullptr);
 }
 
-static int parse_names(char** string, int* n_names, char** names)
+static int parse_names(char** string, int* n_names, gmx::ArrayRef<char*> names)
 {
     int i;
 
@@ -198,7 +204,7 @@ static int parse_names(char** string, int* n_names, char** names)
     return *n_names;
 }
 
-static gmx_bool parse_int_char(char** string, int* nr, char* c)
+static gmx_bool parse_int_char(char** string, int* nr, unsigned char* c)
 {
     char*    orig;
     gmx_bool bRet;
@@ -248,8 +254,9 @@ static gmx_bool parse_int_char(char** string, int* nr, char* c)
 
 static gmx_bool parse_int(char** string, int* nr)
 {
-    char *   orig, c;
-    gmx_bool bRet;
+    char*         orig;
+    unsigned char c;
+    gmx_bool      bRet;
 
     orig = *string;
     bRet = parse_int_char(string, nr, &c);
@@ -356,7 +363,8 @@ static int select_atomnumbers(char** string, const t_atoms* atoms, int n1, int*
     return *nr;
 }
 
-static int select_residuenumbers(char** string, const t_atoms* atoms, int n1, char c, int* nr, int* index, char* gname)
+static int
+select_residuenumbers(char** string, const t_atoms* atoms, int n1, unsigned char c, int* nr, int* index, char* gname)
 {
     char       buf[STRLEN];
     int        i, j, up;
@@ -425,7 +433,8 @@ static int select_residuenumbers(char** string, const t_atoms* atoms, int n1, ch
     return *nr;
 }
 
-static int select_residueindices(char** string, const t_atoms* atoms, int n1, char c, int* nr, int* index, char* gname)
+static int
+select_residueindices(char** string, const t_atoms* atoms, int n1, unsigned char c, int* nr, int* index, char* gname)
 {
     /*this should be similar to select_residuenumbers except select by index (sequential numbering in file)*/
     /*resind+1 for 1-indexing*/
@@ -569,7 +578,7 @@ static gmx_bool comp_name(const char* name, const char* search)
     return matches;
 }
 
-static int select_chainnames(const t_atoms* atoms, int n_names, char** names, int* nr, int* index)
+static int select_chainnames(const t_atoms* atoms, int n_names, gmx::ArrayRef<char*> names, int* nr, int* index)
 {
     char name[2];
     int  j;
@@ -601,7 +610,7 @@ static int select_chainnames(const t_atoms* atoms, int n_names, char** names, in
     return *nr;
 }
 
-static int select_atomnames(const t_atoms* atoms, int n_names, char** names, int* nr, int* index, gmx_bool bType)
+static int select_atomnames(const t_atoms* atoms, int n_names, gmx::ArrayRef<char*> names, int* nr, int* index, gmx_bool bType)
 {
     char* name;
     int   j;
@@ -639,7 +648,7 @@ static int select_atomnames(const t_atoms* atoms, int n_names, char** names, int
     return *nr;
 }
 
-static int select_residuenames(const t_atoms* atoms, int n_names, char** names, int* nr, int* index)
+static int select_residuenames(const t_atoms* atoms, int n_names, gmx::ArrayRef<char*> names, int* nr, int* index)
 {
     char* name;
     int   j;
@@ -686,7 +695,7 @@ static void copy2block(int n, const int* index, t_blocka* block)
     }
 }
 
-static void make_gname(int n, char** names, char* gname)
+static void make_gname(int n, gmx::ArrayRef<char*> names, char* gname)
 {
     int i;
 
@@ -907,31 +916,21 @@ static gmx_bool check_have_atoms(const t_atoms* atoms, char* string)
     }
 }
 
-static gmx_bool parse_entry(char**         string,
-                            int            natoms,
-                            const t_atoms* atoms,
-                            t_blocka*      block,
-                            char***        gn,
-                            int*           nr,
-                            int*           index,
-                            char*          gname)
+static gmx_bool parse_entry(char**               string,
+                            int                  natoms,
+                            const t_atoms*       atoms,
+                            t_blocka*            block,
+                            char***              gn,
+                            int*                 nr,
+                            int*                 index,
+                            char*                gname,
+                            gmx::ArrayRef<char*> entryNames)
 {
-    static char **  names, *ostring;
-    static gmx_bool bFirst = TRUE;
-    int             j, n_names, sel_nr1;
-    int             i, nr1, *index1;
-    char            c;
-    gmx_bool        bRet, bCompl;
-
-    if (bFirst)
-    {
-        bFirst = FALSE;
-        snew(names, MAXNAMES);
-        for (i = 0; i < MAXNAMES; i++)
-        {
-            snew(names[i], NAME_LEN + 1);
-        }
-    }
+    char*         ostring;
+    int           j, n_names, sel_nr1;
+    int           i, nr1, *index1;
+    unsigned char c;
+    gmx_bool      bRet, bCompl;
 
     bRet    = FALSE;
     sel_nr1 = NOTSET;
@@ -980,17 +979,17 @@ static gmx_bool parse_entry(char**         string,
             {
                 bRet = (select_atomnumbers(string, atoms, sel_nr1, nr, index, gname) != 0);
             }
-            else if (parse_names(string, &n_names, names))
+            else if (parse_names(string, &n_names, entryNames))
             {
-                bRet = (select_atomnames(atoms, n_names, names, nr, index, FALSE) != 0);
-                make_gname(n_names, names, gname);
+                bRet = (select_atomnames(atoms, n_names, entryNames, nr, index, FALSE) != 0);
+                make_gname(n_names, entryNames, gname);
             }
         }
     }
     else if ((*string)[0] == 't')
     {
         (*string)++;
-        if (check_have_atoms(atoms, ostring) && parse_names(string, &n_names, names))
+        if (check_have_atoms(atoms, ostring) && parse_names(string, &n_names, entryNames))
         {
             if (!(atoms->haveType))
             {
@@ -998,8 +997,8 @@ static gmx_bool parse_entry(char**         string,
             }
             else
             {
-                bRet = (select_atomnames(atoms, n_names, names, nr, index, TRUE) != 0);
-                make_gname(n_names, names, gname);
+                bRet = (select_atomnames(atoms, n_names, entryNames, nr, index, TRUE) != 0);
+                make_gname(n_names, entryNames, gname);
             }
         }
     }
@@ -1030,23 +1029,23 @@ static gmx_bool parse_entry(char**         string,
             {
                 bRet = (select_residuenumbers(string, atoms, sel_nr1, c, nr, index, gname) != 0);
             }
-            else if (parse_names(string, &n_names, names))
+            else if (parse_names(string, &n_names, entryNames))
             {
-                bRet = (select_residuenames(atoms, n_names, names, nr, index) != 0);
-                make_gname(n_names, names, gname);
+                bRet = (select_residuenames(atoms, n_names, entryNames, nr, index) != 0);
+                make_gname(n_names, entryNames, gname);
             }
         }
     }
     else if (std::strncmp(*string, "chain", 5) == 0)
     {
         (*string) += 5;
-        if (check_have_atoms(atoms, ostring) && parse_names(string, &n_names, names))
+        if (check_have_atoms(atoms, ostring) && parse_names(string, &n_names, entryNames))
         {
-            bRet = (select_chainnames(atoms, n_names, names, nr, index) != 0);
-            sprintf(gname, "ch%s", names[0]);
+            bRet = (select_chainnames(atoms, n_names, entryNames, nr, index) != 0);
+            sprintf(gname, "ch%s", entryNames[0]);
             for (i = 1; i < n_names; i++)
             {
-                std::strcat(gname, names[i]);
+                std::strcat(gname, entryNames[i]);
             }
         }
     }
@@ -1135,23 +1134,12 @@ static void list_residues(const t_atoms* atoms)
 
 static void edit_index(int natoms, const t_atoms* atoms, const rvec* x, t_blocka* block, char*** gn, gmx_bool bVerbose)
 {
-    static char **  atnames, *ostring;
-    static gmx_bool bFirst = TRUE;
-    char            inp_string[STRLEN], *string;
-    char            gname[STRLEN * 3], gname1[STRLEN], gname2[STRLEN];
-    int             i, i0, i1, sel_nr, sel_nr2, newgroup;
-    int             nr, nr1, nr2, *index, *index1, *index2;
-    gmx_bool        bAnd, bOr, bPrintOnce;
-
-    if (bFirst)
-    {
-        bFirst = FALSE;
-        snew(atnames, MAXNAMES);
-        for (i = 0; i < MAXNAMES; i++)
-        {
-            snew(atnames[i], NAME_LEN + 1);
-        }
-    }
+    char*    ostring;
+    char     inp_string[STRLEN], *string;
+    char     gname[STRLEN * 3], gname1[STRLEN], gname2[STRLEN];
+    int      i, i0, i1, sel_nr, sel_nr2, newgroup;
+    int      nr, nr1, nr2, *index, *index1, *index2;
+    gmx_bool bAnd, bOr, bPrintOnce;
 
     string = nullptr;
 
@@ -1161,6 +1149,12 @@ static void edit_index(int natoms, const t_atoms* atoms, const rvec* x, t_blocka
 
     newgroup   = NOTSET;
     bPrintOnce = TRUE;
+    std::array<char*, MAXNAMES> entryNames;
+    for (auto& name : entryNames)
+    {
+        snew(name, NAME_LEN + 1);
+    }
+
     do
     {
         gname1[0] = '\0';
@@ -1373,7 +1367,7 @@ static void edit_index(int natoms, const t_atoms* atoms, const rvec* x, t_blocka
         else if (string[0] != 'q')
         {
             nr2 = -1;
-            if (parse_entry(&string, natoms, atoms, block, gn, &nr, index, gname))
+            if (parse_entry(&string, natoms, atoms, block, gn, &nr, index, gname, entryNames))
             {
                 do
                 {
@@ -1402,7 +1396,7 @@ static void edit_index(int natoms, const t_atoms* atoms, const rvec* x, t_blocka
                             index1[i] = index[i];
                         }
                         std::strcpy(gname1, gname);
-                        if (parse_entry(&string, natoms, atoms, block, gn, &nr2, index2, gname2))
+                        if (parse_entry(&string, natoms, atoms, block, gn, &nr2, index2, gname2, entryNames))
                         {
                             if (bOr)
                             {
@@ -1440,6 +1434,10 @@ static void edit_index(int natoms, const t_atoms* atoms, const rvec* x, t_blocka
         }
     } while (string[0] != 'q');
 
+    for (auto& name : entryNames)
+    {
+        sfree(name);
+    }
     sfree(index);
     sfree(index1);
     sfree(index2);
@@ -1565,7 +1563,7 @@ int gmx_make_ndx(int argc, char* argv[])
         bool haveFullTopology = false;
         fprintf(stderr, "\nReading structure file\n");
         readConfAndTopology(stxfile, &haveFullTopology, &mtop, &pbcType, &x, &v, box);
-        atoms = gmx_mtop_global_atoms(&mtop);
+        atoms = gmx_mtop_global_atoms(mtop);
         if (atoms.pdbinfo == nullptr)
         {
             snew(atoms.pdbinfo, atoms.nr);
@@ -1611,7 +1609,6 @@ int gmx_make_ndx(int argc, char* argv[])
         natoms = block2natoms(block);
         printf("Counted atom numbers up to %d in index file\n", natoms);
     }
-
     edit_index(natoms, &atoms, x, block, &gnames, bVerbose);
 
     write_index(ndxoutfile, block, gnames, bDuplicate, natoms);
index ad7a15459c53303224f196eb201e3b8ab7b14063..a2198abef72bf22ae97497dce5cd672deffe6f73 100644 (file)
@@ -89,31 +89,47 @@ static void fill_ft_ind(int nft, const int* ft, const t_idef* idef, int ft_ind[]
                 switch (ftype)
                 {
                     case F_ANGLES:
-                        sprintf(buf, "Theta=%.1f_%.2f", idef->iparams[i].harmonic.rA,
+                        sprintf(buf,
+                                "Theta=%.1f_%.2f",
+                                idef->iparams[i].harmonic.rA,
                                 idef->iparams[i].harmonic.krA);
                         break;
                     case F_G96ANGLES:
-                        sprintf(buf, "Cos_th=%.1f_%.2f", idef->iparams[i].harmonic.rA,
+                        sprintf(buf,
+                                "Cos_th=%.1f_%.2f",
+                                idef->iparams[i].harmonic.rA,
                                 idef->iparams[i].harmonic.krA);
                         break;
                     case F_UREY_BRADLEY:
-                        sprintf(buf, "UB_th=%.1f_%.2f2f", idef->iparams[i].u_b.thetaA,
+                        sprintf(buf,
+                                "UB_th=%.1f_%.2f2f",
+                                idef->iparams[i].u_b.thetaA,
                                 idef->iparams[i].u_b.kthetaA);
                         break;
                     case F_QUARTIC_ANGLES:
-                        sprintf(buf, "Q_th=%.1f_%.2f_%.2f", idef->iparams[i].qangle.theta,
-                                idef->iparams[i].qangle.c[0], idef->iparams[i].qangle.c[1]);
+                        sprintf(buf,
+                                "Q_th=%.1f_%.2f_%.2f",
+                                idef->iparams[i].qangle.theta,
+                                idef->iparams[i].qangle.c[0],
+                                idef->iparams[i].qangle.c[1]);
                         break;
                     case F_TABANGLES:
-                        sprintf(buf, "Table=%d_%.2f", idef->iparams[i].tab.table,
+                        sprintf(buf,
+                                "Table=%d_%.2f",
+                                idef->iparams[i].tab.table,
                                 idef->iparams[i].tab.kA);
                         break;
                     case F_PDIHS:
-                        sprintf(buf, "Phi=%.1f_%d_%.2f", idef->iparams[i].pdihs.phiA,
-                                idef->iparams[i].pdihs.mult, idef->iparams[i].pdihs.cpA);
+                        sprintf(buf,
+                                "Phi=%.1f_%d_%.2f",
+                                idef->iparams[i].pdihs.phiA,
+                                idef->iparams[i].pdihs.mult,
+                                idef->iparams[i].pdihs.cpA);
                         break;
                     case F_IDIHS:
-                        sprintf(buf, "Xi=%.1f_%.2f", idef->iparams[i].harmonic.rA,
+                        sprintf(buf,
+                                "Xi=%.1f_%.2f",
+                                idef->iparams[i].harmonic.rA,
                                 idef->iparams[i].harmonic.krA);
                         break;
                     case F_RBDIHS:
@@ -122,7 +138,9 @@ static void fill_ft_ind(int nft, const int* ft, const t_idef* idef, int ft_ind[]
                     case F_RESTRANGLES:
                         // Fall through intended
                     case F_RESTRDIHS:
-                        sprintf(buf, "Theta=%.1f_%.2f", idef->iparams[i].harmonic.rA,
+                        sprintf(buf,
+                                "Theta=%.1f_%.2f",
+                                idef->iparams[i].harmonic.rA,
                                 idef->iparams[i].harmonic.krA);
                         break;
                     case F_CBTDIHS:
@@ -130,7 +148,8 @@ static void fill_ft_ind(int nft, const int* ft, const t_idef* idef, int ft_ind[]
                         break;
 
                     default:
-                        gmx_fatal(FARGS, "Unsupported function type '%s' selected",
+                        gmx_fatal(FARGS,
+                                  "Unsupported function type '%s' selected",
                                   interaction_function[ftype].longname);
                 }
                 grpnames[ind] = gmx_strdup(buf);
index ba1fb3b14216d366716ccc5e358f85e0053fba10..2ada54a7476d84fdea6500f5110eed3bc89b470d 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
  * Copyright (c) 2015,2016,2017,2018,2019 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -153,7 +153,13 @@ static void calc_q2all(const gmx_mtop_t* mtop, /* molecular topology */
         fprintf(stderr,
                 "Molecule %2d (%5d atoms) q2_mol=%10.3e nr.mol.charges=%5d (%6dx)  q2_all=%10.3e  "
                 "tot.charges=%d\n",
-                imol, molecule.atoms.nr, q2_mol, nrq_mol, molblock.nmol, q2_all, nrq_all);
+                imol,
+                molecule.atoms.nr,
+                q2_mol,
+                nrq_mol,
+                molblock.nmol,
+                q2_all,
+                nrq_all);
 #endif
     }
 
@@ -176,7 +182,7 @@ static real estimate_direct(t_inputinfo* info)
     e_dir = 2.0 * info->q2all * gmx::invsqrt(info->q2allnr * r_coulomb * info->volume);
     e_dir *= std::exp(-beta * beta * r_coulomb * r_coulomb);
 
-    return ONE_4PI_EPS0 * e_dir;
+    return gmx::c_one4PiEps0 * e_dir;
 }
 
 #define SUMORDER 6
@@ -599,7 +605,8 @@ static real estimate_reciprocal(t_inputinfo* info,
         }
         if (MASTER(cr))
         {
-            fprintf(stderr, "\rCalculating reciprocal error part 1 ... %3.0f%%",
+            fprintf(stderr,
+                    "\rCalculating reciprocal error part 1 ... %3.0f%%",
                     100.0 * (nx - startlocal + 1) / (x_per_core));
             fflush(stderr);
         }
@@ -652,8 +659,10 @@ static real estimate_reciprocal(t_inputinfo* info,
 
         if (bVerbose && MASTER(cr))
         {
-            fprintf(stdout, "Using %d sample%s to approximate the self interaction error term",
-                    xtot, xtot == 1 ? "" : "s");
+            fprintf(stdout,
+                    "Using %d sample%s to approximate the self interaction error term",
+                    xtot,
+                    xtot == 1 ? "" : "s");
             if (PAR(cr))
             {
                 fprintf(stdout, " (%d sample%s per rank)", x_per_core, x_per_core == 1 ? "" : "s");
@@ -767,7 +776,7 @@ static real estimate_reciprocal(t_inputinfo* info,
     e_rec = std::sqrt(e_rec1 + e_rec2 + e_rec3);
 
 
-    return ONE_4PI_EPS0 * e_rec;
+    return gmx::c_one4PiEps0 * e_rec;
 }
 
 
@@ -944,8 +953,7 @@ static void estimate_PME_error(t_inputinfo*      info,
         fprintf(fp_out, "Ewald_rtol              : %g\n", info->ewald_rtol[0]);
         fprintf(fp_out, "Ewald parameter beta    : %g\n", info->ewald_beta[0]);
         fprintf(fp_out, "Interpolation order     : %d\n", info->pme_order[0]);
-        fprintf(fp_out, "Fourier grid (nx,ny,nz) : %d x %d x %d\n", info->nkx[0], info->nky[0],
-                info->nkz[0]);
+        fprintf(fp_out, "Fourier grid (nx,ny,nz) : %d x %d x %d\n", info->nkx[0], info->nky[0], info->nkz[0]);
         fflush(fp_out);
     }
 
@@ -1033,7 +1041,9 @@ static void estimate_PME_error(t_inputinfo*      info,
             if (MASTER(cr))
             {
                 i++;
-                fprintf(stderr, "difference between real and rec. space error (step %d): %g\n", i,
+                fprintf(stderr,
+                        "difference between real and rec. space error (step %d): %g\n",
+                        i,
                         std::abs(derr));
                 fprintf(stderr, "old beta: %f\n", beta0);
                 fprintf(stderr, "new beta: %f\n", beta);
@@ -1125,8 +1135,8 @@ int gmx_pme_error(int argc, char* argv[])
     t_commrec*    cr            = commrecHandle.get();
     PCA_Flags                   = PCA_NOEXIT_ON_ARGS;
 
-    if (!parse_common_args(&argc, argv, PCA_Flags, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0,
-                           nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_Flags, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -1163,14 +1173,25 @@ int gmx_pme_error(int argc, char* argv[])
         info.nkx[0] = 0;
         info.nky[0] = 0;
         info.nkz[0] = 0;
-        calcFftGrid(stdout, state.box, info.fourier_sp[0], minimalPmeGridSize(info.pme_order[0]),
-                    &(info.nkx[0]), &(info.nky[0]), &(info.nkz[0]));
+        calcFftGrid(stdout,
+                    state.box,
+                    info.fourier_sp[0],
+                    minimalPmeGridSize(info.pme_order[0]),
+                    &(info.nkx[0]),
+                    &(info.nky[0]),
+                    &(info.nkz[0]));
         if ((ir.nkx != info.nkx[0]) || (ir.nky != info.nky[0]) || (ir.nkz != info.nkz[0]))
         {
             gmx_fatal(FARGS,
                       "Wrong fourierspacing %f nm, input file grid = %d x %d x %d, computed grid = "
                       "%d x %d x %d",
-                      fs, ir.nkx, ir.nky, ir.nkz, info.nkx[0], info.nky[0], info.nkz[0]);
+                      fs,
+                      ir.nkx,
+                      ir.nky,
+                      ir.nkz,
+                      info.nkx[0],
+                      info.nky[0],
+                      info.nkz[0]);
         }
     }
 
@@ -1190,7 +1211,7 @@ int gmx_pme_error(int argc, char* argv[])
         if (opt2bSet("-so", NFILE, fnm) || bTUNE)
         {
             ir.ewald_rtol = info.ewald_rtol[0];
-            write_tpx_state(opt2fn("-so", NFILE, fnm), &ir, &state, &mtop);
+            write_tpx_state(opt2fn("-so", NFILE, fnm), &ir, &state, mtop);
         }
         please_cite(fp, "Wang2010");
         fclose(fp);
index 4074465931e0570deea554813940062715bb18ea..1ddaceeaa10c81623fe4f7f7f035386bad86dd99 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,17 +76,18 @@ void writeSystemInformation(TextWriter* writer, const gmx_mtop_t& top, bool writ
     const t_atom*             atom;
 
     writeHeader(writer, "Simulation system", "subsection", writeFormattedText);
-    aloop = gmx_mtop_atomloop_block_init(&top);
+    aloop = gmx_mtop_atomloop_block_init(top);
     while (gmx_mtop_atomloop_block_next(aloop, &atom, &nmol))
     {
-        if (atom->ptype == eptVSite)
+        if (atom->ptype == ParticleType::VSite)
         {
             nvsite += nmol;
         }
     }
     {
         writer->writeLine(formatString("A system of %d molecules (%d atoms) was simulated.",
-                                       gmx_mtop_num_molecules(top), top.natoms - nvsite));
+                                       gmx_mtop_num_molecules(top),
+                                       top.natoms - nvsite));
     }
     if (nvsite)
     {
@@ -99,29 +100,33 @@ void writeParameterInformation(TextWriter* writer, const t_inputrec& ir, bool wr
 {
     writeHeader(writer, "Simulation settings", "subsection", writeFormattedText);
     writer->writeLine(formatString("A total of %g ns were simulated with a time step of %g fs.",
-                                   ir.nsteps * ir.delta_t * 0.001, 1000 * ir.delta_t));
+                                   ir.nsteps * ir.delta_t * 0.001,
+                                   1000 * ir.delta_t));
     writer->writeLine(formatString("Neighbor searching was performed every %d steps.", ir.nstlist));
     writer->writeLine(formatString("The %s algorithm was used for electrostatic interactions.",
-                                   EELTYPE(ir.coulombtype)));
+                                   enumValueToString(ir.coulombtype)));
     writer->writeLine(formatString("with a cut-off of %g nm.", ir.rcoulomb));
-    if (ir.coulombtype == eelPME)
+    if (ir.coulombtype == CoulombInteractionType::Pme)
     {
         writer->writeLine(
                 formatString("A reciprocal grid of %d x %d x %d cells was used with %dth order "
                              "B-spline interpolation.",
-                             ir.nkx, ir.nky, ir.nkz, ir.pme_order));
+                             ir.nkx,
+                             ir.nky,
+                             ir.nkz,
+                             ir.pme_order));
     }
     writer->writeLine(formatString(
             "A single cut-off of %g nm was used for Van der Waals interactions.", ir.rlist));
-    if (ir.etc != 0)
+    if (ir.etc != TemperatureCoupling::No)
     {
         writer->writeLine(formatString("Temperature coupling was done with the %s algorithm.",
-                                       etcoupl_names[ir.etc]));
+                                       enumValueToString(ir.etc)));
     }
-    if (ir.epc != 0)
+    if (ir.epc != PressureCoupling::No)
     {
         writer->writeLine(formatString("Pressure coupling was done with the %s algorithm.",
-                                       epcoupl_names[ir.epc]));
+                                       enumValueToString(ir.epc)));
     }
     writer->ensureEmptyLine();
 }
@@ -185,7 +190,7 @@ void ReportMethods::initOptions(IOptionsContainer* options, ICommandLineOptionsM
     settings->setHelpText(desc);
 
     options->addOption(FileNameOption("s")
-                               .filetype(eftTopology)
+                               .filetype(OptionFileType::Topology)
                                .inputFile()
                                .required()
                                .store(&inputTopology_)
diff --git a/src/gromacs/tools/tests/.clang-tidy b/src/gromacs/tools/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 8e61b543c644d9138e8d32a6a2aa5d349d683a89..f1797967649c6f9b9720de5f02e22bbdeb518e31 100644 (file)
@@ -91,11 +91,10 @@ TEST_F(DumpTest, WorksWithTpr)
 
 TEST_F(DumpTest, WorksWithTprAndMdpWriting)
 {
-    TestFileManager   fileManager;
-    std::string       mdpName   = fileManager.getTemporaryFilePath("output.mdp");
-    const char* const command[] = { "dump", "-s", s_tprFileHandle->tprName().c_str(), "-om",
-                                    mdpName.c_str() };
-    CommandLine       cmdline(command);
+    TestFileManager fileManager;
+    std::string     mdpName = fileManager.getTemporaryFilePath("output.mdp");
+    const char* const command[] = { "dump", "-s", s_tprFileHandle->tprName().c_str(), "-om", mdpName.c_str() };
+    CommandLine cmdline(command);
     runTest(&cmdline);
 }
 
index 1283cb18659ea1495ec9a6d90984bb67e842c32d..5de42bdc72d6144dd5d4c479e868b5c81468ac24 100644 (file)
@@ -176,8 +176,7 @@ TEST_F(ReportMethodsTest, ToolEndToEndTest)
 {
     const char* const command[] = { "report-methods", "-s", s_tprFileHandle->tprName().c_str() };
     CommandLine       cmdline(command);
-    EXPECT_EQ(0, gmx::test::CommandLineTestHelper::runModuleFactory(&gmx::ReportMethodsInfo::create,
-                                                                    &cmdline));
+    EXPECT_EQ(0, gmx::test::CommandLineTestHelper::runModuleFactory(&gmx::ReportMethodsInfo::create, &cmdline));
 }
 
 } // namespace test
index b2377eafd6cf650372b3eac5a858ccb1879a069d..a44057b8809edd0e479b7b54948e4ba05b4ae8b0 100644 (file)
@@ -203,12 +203,16 @@ static void edit_files(gmx::ArrayRef<std::string> files,
         fprintf(stderr,
                 "          File             Current start (%s)  New start (%s)\n"
                 "---------------------------------------------------------\n",
-                timeUnit.c_str(), timeUnit.c_str());
+                timeUnit.c_str(),
+                timeUnit.c_str());
 
         for (gmx::index i = 0; i < files.ssize(); i++)
         {
-            fprintf(stderr, "%25s   %10.3f %s          ", files[i].c_str(),
-                    output_env_conv_time(oenv, readtime[i]), timeUnit.c_str());
+            fprintf(stderr,
+                    "%25s   %10.3f %s          ",
+                    files[i].c_str(),
+                    output_env_conv_time(oenv, readtime[i]),
+                    timeUnit.c_str());
             ok = FALSE;
             do
             {
@@ -282,9 +286,13 @@ static void edit_files(gmx::ArrayRef<std::string> files,
         switch (cont_type[i])
         {
             case TIME_EXPLICIT:
-                fprintf(stderr, "%25s   %10.3f %s   %10.3f %s", files[i].c_str(),
-                        output_env_conv_time(oenv, settime[i]), timeUnit.c_str(),
-                        output_env_conv_time(oenv, timestep[i]), timeUnit.c_str());
+                fprintf(stderr,
+                        "%25s   %10.3f %s   %10.3f %s",
+                        files[i].c_str(),
+                        output_env_conv_time(oenv, settime[i]),
+                        timeUnit.c_str(),
+                        output_env_conv_time(oenv, timestep[i]),
+                        timeUnit.c_str());
                 if (i > 0 && cont_type[i - 1] == TIME_EXPLICIT && settime[i] == settime[i - 1])
                 {
                     fprintf(stderr, " WARNING: same Start time as previous");
@@ -338,8 +346,11 @@ static void do_demux(gmx::ArrayRef<const std::string> inFiles,
         }
         else if (natoms != trx[i].natoms)
         {
-            gmx_fatal(FARGS, "Trajectory file %s has %d atoms while previous trajs had %d atoms",
-                      inFiles[i].c_str(), trx[i].natoms, natoms);
+            gmx_fatal(FARGS,
+                      "Trajectory file %s has %d atoms while previous trajs had %d atoms",
+                      inFiles[i].c_str(),
+                      trx[i].natoms,
+                      natoms);
         }
         if (t == -1)
         {
@@ -347,8 +358,11 @@ static void do_demux(gmx::ArrayRef<const std::string> inFiles,
         }
         else if (t != trx[i].time)
         {
-            gmx_fatal(FARGS, "Trajectory file %s has time %f while previous trajs had time %f",
-                      inFiles[i].c_str(), trx[i].time, t);
+            gmx_fatal(FARGS,
+                      "Trajectory file %s has time %f while previous trajs had time %f",
+                      inFiles[i].c_str(),
+                      trx[i].time,
+                      t);
         }
     }
 
@@ -497,8 +511,8 @@ int gmx_trjcat(int argc, char* argv[])
 
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_TIME_UNIT, NFILE, fnm, asize(pa), pa, asize(desc), desc,
-                           0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_TIME_UNIT, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -528,8 +542,17 @@ int gmx_trjcat(int argc, char* argv[])
     {
         nset    = 0;
         dt_remd = 0;
-        val     = read_xvg_time(opt2fn("-demux", NFILE, fnm), TRUE, opt2parg_bSet("-b", npargs, pa),
-                            begin, opt2parg_bSet("-e", npargs, pa), end, 1, &nset, &n, &dt_remd, &t);
+        val     = read_xvg_time(opt2fn("-demux", NFILE, fnm),
+                            TRUE,
+                            opt2parg_bSet("-b", npargs, pa),
+                            begin,
+                            opt2parg_bSet("-e", npargs, pa),
+                            end,
+                            1,
+                            &nset,
+                            &n,
+                            &dt_remd,
+                            &t);
         printf("Read %d sets of %d points, dt = %g\n\n", nset, n, dt_remd);
         if (debug)
         {
@@ -554,8 +577,7 @@ int gmx_trjcat(int argc, char* argv[])
 
     if (bDeMux && ssize(inFiles) != nset)
     {
-        gmx_fatal(FARGS, "You have specified %td files and %d entries in the demux table",
-                  inFiles.ssize(), nset);
+        gmx_fatal(FARGS, "You have specified %td files and %d entries in the demux table", inFiles.ssize(), nset);
     }
 
     ftpin = fn2ftp(inFiles[0].c_str());
@@ -585,7 +607,9 @@ int gmx_trjcat(int argc, char* argv[])
     }
     else if (bDeMux && ssize(outFiles) != nset && outFiles.size() != 1)
     {
-        gmx_fatal(FARGS, "Number of output files should be 1 or %d (#input files), not %td", nset,
+        gmx_fatal(FARGS,
+                  "Number of output files should be 1 or %d (#input files), not %td",
+                  nset,
                   outFiles.ssize());
     }
     if (bDeMux)
@@ -632,8 +656,10 @@ int gmx_trjcat(int argc, char* argv[])
         }
         else if (n_append != -1)
         {
-            gmx_fatal(FARGS, "Can only append to the first file which is %s (not %s)",
-                      inFilesEdited[0].c_str(), out_file);
+            gmx_fatal(FARGS,
+                      "Can only append to the first file which is %s (not %s)",
+                      inFilesEdited[0].c_str(),
+                      out_file);
         }
 
         /* Not checking input format, could be dangerous :-) */
@@ -656,9 +682,14 @@ int gmx_trjcat(int argc, char* argv[])
                 }
                 if (bIndex)
                 {
-                    trxout = trjtools_gmx_prepare_tng_writing(
-                            out_file, 'w', nullptr, inFilesEdited[0].c_str(), isize, nullptr,
-                            gmx::arrayRefFromArray(index, isize), grpname);
+                    trxout = trjtools_gmx_prepare_tng_writing(out_file,
+                                                              'w',
+                                                              nullptr,
+                                                              inFilesEdited[0].c_str(),
+                                                              isize,
+                                                              nullptr,
+                                                              gmx::arrayRefFromArray(index, isize),
+                                                              grpname);
                 }
                 else
                 {
@@ -736,8 +767,7 @@ int gmx_trjcat(int argc, char* argv[])
                 read_next_frame(oenv, status, &fr);
                 if (std::abs(searchtime - fr.time) > timest[0] * 0.5)
                 {
-                    gmx_fatal(FARGS, "Error seeking: attempted to seek to %f but got %f.",
-                              searchtime, fr.time);
+                    gmx_fatal(FARGS, "Error seeking: attempted to seek to %f but got %f.", searchtime, fr.time);
                 }
                 lasttime    = fr.time;
                 lastTimeSet = TRUE;
@@ -803,7 +833,8 @@ int gmx_trjcat(int argc, char* argv[])
                                 "spacing than the rest,\n"
                                 "might be a gap or overlap that couldn't be corrected "
                                 "automatically.\n",
-                                output_env_conv_time(oenv, frout.time), timeUnit.c_str());
+                                output_env_conv_time(oenv, frout.time),
+                                timeUnit.c_str());
                     }
                 }
             }
@@ -895,7 +926,9 @@ int gmx_trjcat(int argc, char* argv[])
                                     "\nContinue writing frames from %s t=%g %s, "
                                     "frame=%d      \n",
                                     inFilesEdited[i].c_str(),
-                                    output_env_conv_time(oenv, frout.time), timeUnit.c_str(), frame);
+                                    output_env_conv_time(oenv, frout.time),
+                                    timeUnit.c_str(),
+                                    frame);
                             bNewFile = FALSE;
                         }
 
@@ -909,8 +942,11 @@ int gmx_trjcat(int argc, char* argv[])
                         }
                         if (((frame % 10) == 0) || (frame < 10))
                         {
-                            fprintf(stderr, " ->  frame %6d time %8.3f %s     \r", frame_out,
-                                    output_env_conv_time(oenv, frout.time), timeUnit.c_str());
+                            fprintf(stderr,
+                                    " ->  frame %6d time %8.3f %s     \r",
+                                    frame_out,
+                                    output_env_conv_time(oenv, frout.time),
+                                    timeUnit.c_str());
                             fflush(stderr);
                         }
                     }
@@ -923,8 +959,11 @@ int gmx_trjcat(int argc, char* argv[])
         {
             close_trx(trxout);
         }
-        fprintf(stderr, "\nLast frame written was %d, time %f %s\n", frame,
-                output_env_conv_time(oenv, last_ok_t), timeUnit.c_str());
+        fprintf(stderr,
+                "\nLast frame written was %d, time %f %s\n",
+                frame,
+                output_env_conv_time(oenv, last_ok_t),
+                timeUnit.c_str());
     }
 
     return 0;
index 43274a7522d4cfdb496383daa71bb10959466e5e..95975b6809c55c0c1320d02850bab85ec54f17af 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -152,7 +152,10 @@ static void do_trunc(const char* fn, real t0)
             fprintf(stderr,
                     "Do you REALLY want to truncate this trajectory (%s) at:\n"
                     "frame %d, time %g, bytes %ld ??? (type YES if so)\n",
-                    fn, j, t, static_cast<long int>(fpos));
+                    fn,
+                    j,
+                    t,
+                    static_cast<long int>(fpos));
             if (1 != scanf("%s", yesno))
             {
                 gmx_fatal(FARGS, "Error reading user input");
@@ -399,14 +402,14 @@ int gmx_trjconv(int argc, char* argv[])
     const char* fit[efNR + 1] = { nullptr,       "none",    "rot+trans",   "rotxy+transxy",
                                   "translation", "transxy", "progressive", nullptr };
 
-    static gmx_bool bSeparate = FALSE, bVels = TRUE, bForce = FALSE, bCONECT = FALSE;
-    static gmx_bool bCenter = FALSE;
-    static int      skip_nr = 1, ndec = 3, nzero = 0;
-    static real     tzero = 0, delta_t = 0, timestep = 0, ttrunc = -1, tdump = -1, split_t = 0;
-    static rvec     newbox = { 0, 0, 0 }, shift = { 0, 0, 0 }, trans = { 0, 0, 0 };
-    static char*    exec_command = nullptr;
-    static real     dropunder = 0, dropover = 0;
-    static gmx_bool bRound = FALSE;
+    gmx_bool bSeparate = FALSE, bVels = TRUE, bForce = FALSE, bCONECT = FALSE;
+    gmx_bool bCenter = FALSE;
+    int      skip_nr = 1, ndec = 3, nzero = 0;
+    real     tzero = 0, delta_t = 0, timestep = 0, ttrunc = -1, tdump = -1, split_t = 0;
+    rvec     newbox = { 0, 0, 0 }, shift = { 0, 0, 0 }, trans = { 0, 0, 0 };
+    char*    exec_command = nullptr;
+    real     dropunder = 0, dropover = 0;
+    gmx_bool bRound = FALSE;
 
     t_pargs pa[] = {
         { "-skip", FALSE, etINT, { &skip_nr }, "Only write every nr-th frame" },
@@ -521,8 +524,18 @@ int gmx_trjconv(int argc, char* argv[])
                        { efXVG, "-drop", "drop", ffOPTRD } };
 #define NFILE asize(fnm)
 
-    if (!parse_common_args(&argc, argv, PCA_CAN_BEGIN | PCA_CAN_END | PCA_CAN_VIEW | PCA_TIME_UNIT,
-                           NFILE, fnm, NPA, pa, asize(desc), desc, 0, nullptr, &oenv))
+    if (!parse_common_args(&argc,
+                           argv,
+                           PCA_CAN_BEGIN | PCA_CAN_END | PCA_CAN_VIEW | PCA_TIME_UNIT,
+                           NFILE,
+                           fnm,
+                           NPA,
+                           pa,
+                           asize(desc),
+                           desc,
+                           0,
+                           nullptr,
+                           &oenv))
     {
         return 0;
     }
@@ -594,7 +607,10 @@ int gmx_trjconv(int argc, char* argv[])
                         "WARNING: Option for unitcell representation (-ur %s)\n"
                         "         only has effect in combination with -pbc %s, %s or %s.\n"
                         "         Ingoring unitcell representation.\n\n",
-                        unitcell_opt[0], pbc_opt[2], pbc_opt[3], pbc_opt[4]);
+                        unitcell_opt[0],
+                        pbc_opt[2],
+                        pbc_opt[3],
+                        pbc_opt[4]);
             }
         }
         if (bFit && bPBC)
@@ -676,8 +692,7 @@ int gmx_trjconv(int argc, char* argv[])
 
             if (0 == top->mols.nr && (bCluster || bPBCcomMol))
             {
-                gmx_fatal(FARGS, "Option -pbc %s requires a .tpr file for the -s option",
-                          pbc_opt[pbc_enum]);
+                gmx_fatal(FARGS, "Option -pbc %s requires a .tpr file for the -s option", pbc_opt[pbc_enum]);
             }
 
             /* top_title is only used for gro and pdb,
@@ -922,7 +937,9 @@ int gmx_trjconv(int argc, char* argv[])
                                   "Index[%d] %d is larger than the number of atoms in the\n"
                                   "trajectory file (%d). There is a mismatch in the contents\n"
                                   "of your -f, -s and/or -n files.",
-                                  i, index[i] + 1, natoms);
+                                  i,
+                                  index[i] + 1,
+                                  natoms);
                     }
                     bCopy = bCopy || (i != index[i]);
                 }
@@ -933,9 +950,14 @@ int gmx_trjconv(int argc, char* argv[])
             switch (ftp)
             {
                 case efTNG:
-                    trxout = trjtools_gmx_prepare_tng_writing(
-                            out_file, filemode[0], trxin, nullptr, nout, mtop.get(),
-                            gmx::arrayRefFromArray(index, nout), grpnm);
+                    trxout = trjtools_gmx_prepare_tng_writing(out_file,
+                                                              filemode[0],
+                                                              trxin,
+                                                              nullptr,
+                                                              nout,
+                                                              mtop.get(),
+                                                              gmx::arrayRefFromArray(index, nout),
+                                                              grpnm);
                     break;
                 case efXTC:
                 case efTRR:
@@ -1167,7 +1189,8 @@ int gmx_trjconv(int argc, char* argv[])
 
                     if (bTDump)
                     {
-                        fprintf(stderr, "\nDumping frame at t= %g %s\n",
+                        fprintf(stderr,
+                                "\nDumping frame at t= %g %s\n",
                                 output_env_conv_time(oenv, frout_time),
                                 output_env_get_time_unit(oenv).c_str());
                     }
@@ -1183,7 +1206,8 @@ int gmx_trjconv(int argc, char* argv[])
                         else
                         {
                             /* round() is not C89 compatible, so we do this:  */
-                            bDoIt = bRmod(std::floor(frout_time + 0.5), std::floor(tzero + 0.5),
+                            bDoIt = bRmod(std::floor(frout_time + 0.5),
+                                          std::floor(tzero + 0.5),
                                           std::floor(delta_t + 0.5));
                         }
                     }
@@ -1193,7 +1217,9 @@ int gmx_trjconv(int argc, char* argv[])
                         /* print sometimes */
                         if (((outframe % SKIP) == 0) || (outframe < SKIP))
                         {
-                            fprintf(stderr, " ->  frame %6d time %8.3f      \r", outframe,
+                            fprintf(stderr,
+                                    " ->  frame %6d time %8.3f      \r",
+                                    outframe,
                                     output_env_conv_time(oenv, frout_time));
                             fflush(stderr);
                         }
@@ -1243,20 +1269,20 @@ int gmx_trjconv(int argc, char* argv[])
                                     put_atoms_in_triclinic_unitcell(ecenter, fr.box, positionsArrayRef);
                                     break;
                                 case euCompact:
-                                    put_atoms_in_compact_unitcell(pbcType, ecenter, fr.box,
-                                                                  positionsArrayRef);
+                                    put_atoms_in_compact_unitcell(
+                                            pbcType, ecenter, fr.box, positionsArrayRef);
                                     break;
                             }
                         }
                         if (bPBCcomRes)
                         {
-                            put_residue_com_in_box(unitcell_enum, ecenter, natoms, atoms->atom,
-                                                   pbcType, fr.box, fr.x);
+                            put_residue_com_in_box(
+                                    unitcell_enum, ecenter, natoms, atoms->atom, pbcType, fr.box, fr.x);
                         }
                         if (bPBCcomMol)
                         {
-                            put_molecule_com_in_box(unitcell_enum, ecenter, &top->mols, natoms,
-                                                    atoms->atom, pbcType, fr.box, fr.x);
+                            put_molecule_com_in_box(
+                                    unitcell_enum, ecenter, &top->mols, natoms, atoms->atom, pbcType, fr.box, fr.x);
                         }
                         /* Copy the input trxframe struct to the output trxframe struct */
                         frout        = fr;
@@ -1314,7 +1340,8 @@ int gmx_trjconv(int argc, char* argv[])
                             /* round() is not C89 compatible, so we do this: */
                             bSplitHere = bSplit
                                          && bRmod(std::floor(frout.time + 0.5),
-                                                  std::floor(tzero + 0.5), std::floor(split_t + 0.5));
+                                                  std::floor(tzero + 0.5),
+                                                  std::floor(split_t + 0.5));
                         }
                         if (bSeparate || bSplitHere)
                         {
@@ -1373,8 +1400,12 @@ int gmx_trjconv(int argc, char* argv[])
                                 switch (ftp)
                                 {
                                     case efGRO:
-                                        write_hconf_p(out, title.c_str(), &useatoms, frout.x,
-                                                      frout.bV ? frout.v : nullptr, frout.box);
+                                        write_hconf_p(out,
+                                                      title.c_str(),
+                                                      &useatoms,
+                                                      frout.x,
+                                                      frout.bV ? frout.v : nullptr,
+                                                      frout.box);
                                         break;
                                     case efPDB:
                                         fprintf(out, "REMARK    GENERATED BY TRJCONV\n");
@@ -1389,8 +1420,15 @@ int gmx_trjconv(int argc, char* argv[])
                                         {
                                             model_nr++;
                                         }
-                                        write_pdbfile(out, title.c_str(), &useatoms, frout.x,
-                                                      frout.pbcType, frout.box, ' ', model_nr, gc);
+                                        write_pdbfile(out,
+                                                      title.c_str(),
+                                                      &useatoms,
+                                                      frout.x,
+                                                      frout.pbcType,
+                                                      frout.box,
+                                                      ' ',
+                                                      model_nr,
+                                                      gc);
                                         break;
                                     case efG96:
                                         const char* outputTitle = "";
index da954ea332a983fad4499ebef2af002b02c91355..3c8e9857c870fa1b14ac24c9bba56cef924e33cc 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2009-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -265,7 +265,8 @@ static int parse_logfile(const char* logfile,
                     fprintf(stderr,
                             "WARNING: Time step counters were reset at step %s,\n"
                             "         though they were supposed to be reset at step %s!\n",
-                            dumstring, dumstring2);
+                            dumstring,
+                            dumstring2);
                 }
             }
         }
@@ -277,8 +278,12 @@ static int parse_logfile(const char* logfile,
                 /* Look for domain decomp grid and separate PME nodes: */
                 if (str_starts(line, matchstrdd))
                 {
-                    sscanf(line, "Domain decomposition grid %d x %d x %d, separate PME ranks %d",
-                           &(perfdata->nx), &(perfdata->ny), &(perfdata->nz), &npme);
+                    sscanf(line,
+                           "Domain decomposition grid %d x %d x %d, separate PME ranks %d",
+                           &(perfdata->nx),
+                           &(perfdata->ny),
+                           &(perfdata->nz),
+                           &npme);
                     if (perfdata->nPMEnodes == -1)
                     {
                         perfdata->guessPME = npme;
@@ -511,8 +516,16 @@ static gmx_bool analyze_data(FILE*        fp,
                     s /= (nrepeats - 1);
                     s = std::sqrt(s);
 
-                    fprintf(fp, "%4d %3d %4d%s %12.3f %12.3f %12.3f %s", line, k, pd->nPMEnodes,
-                            strbuf, pd->Gcycles_Av, s, pd->ns_per_day_Av, str_PME_f_load);
+                    fprintf(fp,
+                            "%4d %3d %4d%s %12.3f %12.3f %12.3f %s",
+                            line,
+                            k,
+                            pd->nPMEnodes,
+                            strbuf,
+                            pd->Gcycles_Av,
+                            s,
+                            pd->ns_per_day_Av,
+                            str_PME_f_load);
                     if (nnodes > 1)
                     {
                         fprintf(fp, "  %3d %3d %3d", pd->nx, pd->ny, pd->nz);
@@ -582,8 +595,7 @@ static gmx_bool analyze_data(FILE*        fp,
 
     if (bRefinedCoul)
     {
-        fprintf(fp, "   New Coulomb radius: %f nm (was %f nm)\n", info->rcoulomb[k_win],
-                info->rcoulomb[0]);
+        fprintf(fp, "   New Coulomb radius: %f nm (was %f nm)\n", info->rcoulomb[k_win], info->rcoulomb[0]);
     }
 
     if (bRefinedVdW)
@@ -593,8 +605,14 @@ static gmx_bool analyze_data(FILE*        fp,
 
     if (bRefinedGrid)
     {
-        fprintf(fp, "   New Fourier grid xyz: %d %d %d (was %d %d %d)\n", info->nkx[k_win],
-                info->nky[k_win], info->nkz[k_win], info->nkx[0], info->nky[0], info->nkz[0]);
+        fprintf(fp,
+                "   New Fourier grid xyz: %d %d %d (was %d %d %d)\n",
+                info->nkx[k_win],
+                info->nky[k_win],
+                info->nkz[k_win],
+                info->nkx[0],
+                info->nky[0],
+                info->nkz[0]);
     }
 
     if (bCanUseOrigTPR && ntprs > 1)
@@ -690,8 +708,9 @@ static void check_mdrun_works(gmx_bool    bThreads,
     }
     else
     {
-        snew(command, std::strlen(cmd_mpirun) + std::strlen(cmd_np) + std::strlen(cmd_mdrun)
-                              + std::strlen(filename) + 50);
+        snew(command,
+             std::strlen(cmd_mpirun) + std::strlen(cmd_np) + std::strlen(cmd_mdrun)
+                     + std::strlen(filename) + 50);
         sprintf(command, "%s%s%s -version -maxh 0.001 1> %s 2>&1", cmd_mpirun, cmd_np, cmd_mdrun, filename);
     }
     fprintf(stdout, "Trying '%s' ... ", command);
@@ -800,8 +819,9 @@ static void launch_simulation(gmx_bool    bLaunch,          /* Should the simula
 
     /* Make enough space for the system call command,
      * (200 extra chars for -npme ... etc. options should suffice): */
-    snew(command, std::strlen(cmd_mpirun) + std::strlen(cmd_mdrun) + std::strlen(cmd_np)
-                          + std::strlen(args_for_mdrun) + std::strlen(simulation_tpr) + 200);
+    snew(command,
+         std::strlen(cmd_mpirun) + std::strlen(cmd_mdrun) + std::strlen(cmd_np)
+                 + std::strlen(args_for_mdrun) + std::strlen(simulation_tpr) + 200);
 
     auto cmd_gpu_ids = make_gpu_id_command_line(eligible_gpu_ids);
 
@@ -809,17 +829,29 @@ static void launch_simulation(gmx_bool    bLaunch,          /* Should the simula
      * of the command line string */
     if (bThreads)
     {
-        sprintf(command, "%s%s-npme %d -s %s %s %s", cmd_mdrun, cmd_np, nPMEnodes, simulation_tpr,
-                args_for_mdrun, cmd_gpu_ids.c_str());
+        sprintf(command,
+                "%s%s-npme %d -s %s %s %s",
+                cmd_mdrun,
+                cmd_np,
+                nPMEnodes,
+                simulation_tpr,
+                args_for_mdrun,
+                cmd_gpu_ids.c_str());
     }
     else
     {
-        sprintf(command, "%s%s%s -npme %d -s %s %s %s", cmd_mpirun, cmd_np, cmd_mdrun, nPMEnodes,
-                simulation_tpr, args_for_mdrun, cmd_gpu_ids.c_str());
+        sprintf(command,
+                "%s%s%s -npme %d -s %s %s %s",
+                cmd_mpirun,
+                cmd_np,
+                cmd_mdrun,
+                nPMEnodes,
+                simulation_tpr,
+                args_for_mdrun,
+                cmd_gpu_ids.c_str());
     }
 
-    fprintf(fp, "%s this command line to launch the simulation:\n\n%s",
-            bLaunch ? "Using" : "Please use", command);
+    fprintf(fp, "%s this command line to launch the simulation:\n\n%s", bLaunch ? "Using" : "Please use", command);
     sep_line(fp);
     fflush(fp);
 
@@ -855,15 +887,16 @@ static void modify_PMEsettings(int64_t     simsteps,    /* Set this value as num
     sprintf(buf, "Writing optimized simulation file %s with nsteps=%s.\n", fn_sim_tpr, "%" PRId64);
     fprintf(stdout, buf, ir->nsteps);
     fflush(stdout);
-    write_tpx_state(fn_sim_tpr, ir, &state, &mtop);
+    write_tpx_state(fn_sim_tpr, ir, &state, mtop);
 }
 
-static gmx_bool can_scale_rvdw(int vdwtype)
+static gmx_bool can_scale_rvdw(VanDerWaalsType vdwtype)
 {
-    return (evdwCUT == vdwtype || evdwPME == vdwtype);
+    return (VanDerWaalsType::Cut == vdwtype || VanDerWaalsType::Pme == vdwtype);
 }
 
-#define EPME_SWITCHED(e) ((e) == eelPMESWITCH || (e) == eelPMEUSERSWITCH)
+#define EPME_SWITCHED(e) \
+    ((e) == CoulombInteractionType::PmeSwitch || (e) == CoulombInteractionType::PmeUserSwitch)
 
 /* Make additional TPR files with more computational load for the
  * direct space processors: */
@@ -891,8 +924,11 @@ static void make_benchmark_tprs(const char* fn_sim_tpr,  /* READ : User-provided
     real       fourierspacing; /* Basic fourierspacing from tpr          */
 
 
-    sprintf(buf, "Making benchmark tpr file%s with %s time step%s", *ntprs > 1 ? "s" : "",
-            "%" PRId64, benchsteps > 1 ? "s" : "");
+    sprintf(buf,
+            "Making benchmark tpr file%s with %s time step%s",
+            *ntprs > 1 ? "s" : "",
+            "%" PRId64,
+            benchsteps > 1 ? "s" : "");
     fprintf(stdout, buf, benchsteps);
     if (statesteps > 0)
     {
@@ -909,21 +945,29 @@ static void make_benchmark_tprs(const char* fn_sim_tpr,  /* READ : User-provided
     /* Check if some kind of PME was chosen */
     if (EEL_PME(ir->coulombtype) == FALSE)
     {
-        gmx_fatal(FARGS, "Can only do optimizations for simulations with %s electrostatics.",
-                  EELTYPE(eelPME));
+        gmx_fatal(FARGS,
+                  "Can only do optimizations for simulations with %s electrostatics.",
+                  enumValueToString(CoulombInteractionType::Pme));
     }
 
     /* Check if rcoulomb == rlist, which is necessary for plain PME. */
-    if ((ir->cutoff_scheme != ecutsVERLET) && (eelPME == ir->coulombtype) && !(ir->rcoulomb == ir->rlist))
+    if ((ir->cutoff_scheme != CutoffScheme::Verlet)
+        && (CoulombInteractionType::Pme == ir->coulombtype) && !(ir->rcoulomb == ir->rlist))
     {
-        gmx_fatal(FARGS, "%s requires rcoulomb (%f) to be equal to rlist (%f).", EELTYPE(eelPME),
-                  ir->rcoulomb, ir->rlist);
+        gmx_fatal(FARGS,
+                  "%s requires rcoulomb (%f) to be equal to rlist (%f).",
+                  enumValueToString(CoulombInteractionType::Pme),
+                  ir->rcoulomb,
+                  ir->rlist);
     }
     /* For other PME types, rcoulomb is allowed to be smaller than rlist */
     else if (ir->rcoulomb > ir->rlist)
     {
-        gmx_fatal(FARGS, "%s requires rcoulomb (%f) to be equal to or smaller than rlist (%f)",
-                  EELTYPE(ir->coulombtype), ir->rcoulomb, ir->rlist);
+        gmx_fatal(FARGS,
+                  "%s requires rcoulomb (%f) to be equal to or smaller than rlist (%f)",
+                  enumValueToString(ir->coulombtype),
+                  ir->rcoulomb,
+                  ir->rlist);
     }
 
     if (bScaleRvdw && ir->rvdw != ir->rcoulomb)
@@ -980,17 +1024,19 @@ static void make_benchmark_tprs(const char* fn_sim_tpr,  /* READ : User-provided
         fourierspacing = std::max(std::max(info->fsx[0], info->fsy[0]), info->fsz[0]);
     }
 
-    fprintf(stdout, "Calculating PME grid points on the basis of a fourierspacing of %f nm\n",
-            fourierspacing);
+    fprintf(stdout, "Calculating PME grid points on the basis of a fourierspacing of %f nm\n", fourierspacing);
 
     /* For performance comparisons the number of particles is useful to have */
     fprintf(fp, "   Number of particles  : %d\n", mtop.natoms);
 
     /* Print information about settings of which some are potentially modified: */
-    fprintf(fp, "   Coulomb type         : %s\n", EELTYPE(ir->coulombtype));
-    fprintf(fp, "   Grid spacing x y z   : %f %f %f\n", box_size[XX] / ir->nkx,
-            box_size[YY] / ir->nky, box_size[ZZ] / ir->nkz);
-    fprintf(fp, "   Van der Waals type   : %s\n", EVDWTYPE(ir->vdwtype));
+    fprintf(fp, "   Coulomb type         : %s\n", enumValueToString(ir->coulombtype));
+    fprintf(fp,
+            "   Grid spacing x y z   : %f %f %f\n",
+            box_size[XX] / ir->nkx,
+            box_size[YY] / ir->nky,
+            box_size[ZZ] / ir->nkz);
+    fprintf(fp, "   Van der Waals type   : %s\n", enumValueToString(ir->vdwtype));
     if (ir_vdw_switched(ir))
     {
         fprintf(fp, "   rvdw_switch          : %f nm\n", ir->rvdw_switch);
@@ -1044,11 +1090,16 @@ static void make_benchmark_tprs(const char* fn_sim_tpr,  /* READ : User-provided
 
             /* Scale the Fourier grid spacing */
             ir->nkx = ir->nky = ir->nkz = 0;
-            calcFftGrid(nullptr, state.box, fourierspacing * fac, minimalPmeGridSize(ir->pme_order),
-                        &ir->nkx, &ir->nky, &ir->nkz);
+            calcFftGrid(nullptr,
+                        state.box,
+                        fourierspacing * fac,
+                        minimalPmeGridSize(ir->pme_order),
+                        &ir->nkx,
+                        &ir->nky,
+                        &ir->nkz);
 
             /* Adjust other radii since various conditions need to be fulfilled */
-            if (eelPME == ir->coulombtype)
+            if (CoulombInteractionType::Pme == ir->coulombtype)
             {
                 /* plain PME, rcoulomb must be equal to rlist TODO only in the group scheme? */
                 ir->rlist = ir->rcoulomb;
@@ -1061,7 +1112,7 @@ static void make_benchmark_tprs(const char* fn_sim_tpr,  /* READ : User-provided
 
             if (bScaleRvdw && can_scale_rvdw(ir->vdwtype))
             {
-                if (ecutsVERLET == ir->cutoff_scheme || evdwPME == ir->vdwtype)
+                if (CutoffScheme::Verlet == ir->cutoff_scheme || VanDerWaalsType::Pme == ir->vdwtype)
                 {
                     /* With either the Verlet cutoff-scheme or LJ-PME,
                        the van der Waals radius must always equal the
@@ -1104,7 +1155,7 @@ static void make_benchmark_tprs(const char* fn_sim_tpr,  /* READ : User-provided
             fprintf(stdout, ", unmodified settings\n");
         }
 
-        write_tpx_state(fn_bench_tprs[j], ir, &state, &mtop);
+        write_tpx_state(fn_bench_tprs[j], ir, &state, mtop);
 
         /* Write information about modified tpr settings to log file */
         fprintf(fp, "%4d%10f%10f", j, fac, ir->rcoulomb);
@@ -1501,8 +1552,13 @@ static void do_the_tests(FILE*  fp,                    /* General tune_pme outpu
                  * the -passall (if set) options requires cmd_args_bench to be
                  * at the end of the command line string */
                 snew(pd->mdrun_cmd_line, cmdline_length);
-                sprintf(pd->mdrun_cmd_line, "%s-npme %d -s %s %s %s", cmd_stub, pd->nPMEnodes,
-                        tpr_names[k], cmd_args_bench, cmd_gpu_ids.c_str());
+                sprintf(pd->mdrun_cmd_line,
+                        "%s-npme %d -s %s %s %s",
+                        cmd_stub,
+                        pd->nPMEnodes,
+                        tpr_names[k],
+                        cmd_args_bench,
+                        cmd_gpu_ids.c_str());
 
                 /* To prevent that all benchmarks fail due to a show-stopper argument
                  * on the mdrun command line, we make a quick check first.
@@ -1527,8 +1583,7 @@ static void do_the_tests(FILE*  fp,                    /* General tune_pme outpu
                        do for this check, but it'll be easier to
                        implement that after some refactoring of how
                        the number of MPI ranks is managed. */
-                    sprintf(temporary_cmd_line, "%s-npme 0 -nb cpu -s %s %s", cmd_stub,
-                            tpr_names[k], cmd_args_bench);
+                    sprintf(temporary_cmd_line, "%s-npme 0 -nb cpu -s %s %s", cmd_stub, tpr_names[k], cmd_args_bench);
                     make_sure_it_runs(temporary_cmd_line, cmdline_length, fp, fnm, nfile);
                 }
                 bFirst = FALSE;
@@ -1542,8 +1597,14 @@ static void do_the_tests(FILE*  fp,                    /* General tune_pme outpu
                 {
                     buf[0] = '\0';
                 }
-                fprintf(stdout, "\n=== Progress %2.0f%%, tpr %d/%d, run %d/%d%s:\n",
-                        (100.0 * count) / totaltests, k + 1, nr_tprs, i + 1, *pmeentries, buf);
+                fprintf(stdout,
+                        "\n=== Progress %2.0f%%, tpr %d/%d, run %d/%d%s:\n",
+                        (100.0 * count) / totaltests,
+                        k + 1,
+                        nr_tprs,
+                        i + 1,
+                        *pmeentries,
+                        buf);
                 make_backup(opt2fn("-err", nfile, fnm));
                 sprintf(command, "%s 1> /dev/null 2>%s", pd->mdrun_cmd_line, opt2fn("-err", nfile, fnm));
                 fprintf(stdout, "%s\n", pd->mdrun_cmd_line);
@@ -1551,8 +1612,8 @@ static void do_the_tests(FILE*  fp,                    /* General tune_pme outpu
 
                 /* Collect the performance data from the log file; also check stderr
                  * for fatal errors */
-                ret = parse_logfile(opt2fn("-bg", nfile, fnm), opt2fn("-err", nfile, fnm), pd, nr,
-                                    presteps, cpt_steps, nnodes);
+                ret = parse_logfile(
+                        opt2fn("-bg", nfile, fnm), opt2fn("-err", nfile, fnm), pd, nr, presteps, cpt_steps, nnodes);
                 if ((presteps > 0) && (ret == eParselogResetProblem))
                 {
                     bResetProblem = TRUE;
@@ -1578,8 +1639,14 @@ static void do_the_tests(FILE*  fp,                    /* General tune_pme outpu
                 }
 
                 /* Write the data we got to disk */
-                fprintf(fp, "%4d%s %12.3f %12.3f %s    %s", pd->nPMEnodes, buf, pd->Gcycles[nr],
-                        pd->ns_per_day[nr], str_PME_f_load, ParseLog[ret]);
+                fprintf(fp,
+                        "%4d%s %12.3f %12.3f %s    %s",
+                        pd->nPMEnodes,
+                        buf,
+                        pd->Gcycles[nr],
+                        pd->ns_per_day[nr],
+                        str_PME_f_load,
+                        ParseLog[ret]);
                 if (!(ret == eParselogOK || ret == eParselogNoDDGrid || ret == eParselogNotFound))
                 {
                     fprintf(fp, " Check %s file for problems.", ret == eParselogFatal ? "err" : "log");
@@ -1703,7 +1770,9 @@ static void check_input(int             nnodes,
         gmx_fatal(FARGS,
                   "Please choose the Coulomb radii such that rmin <= rmax.\n"
                   "rmin = %g, rmax = %g, actual rcoul from .tpr file = %g\n",
-                  *rmin, *rmax, rcoulomb);
+                  *rmin,
+                  *rmax,
+                  rcoulomb);
     }
     /* Add test scenarios if rmin or rmax were set */
     if (*ntprs <= 2)
@@ -1774,7 +1843,8 @@ static void check_input(int             nnodes,
     {
         fprintf(stderr, "WARNING: steps=");
         fprintf(stderr, "%" PRId64, bench_nsteps);
-        fprintf(stderr, ". Are you sure you want to perform so %s steps for each benchmark?\n",
+        fprintf(stderr,
+                ". Are you sure you want to perform so %s steps for each benchmark?\n",
                 (bench_nsteps < 100) ? "few" : "many");
     }
 
@@ -1805,7 +1875,9 @@ static void check_input(int             nnodes,
             gmx_fatal(FARGS,
                       "Cannot have more than %d PME-only ranks for a total of %d ranks (you chose "
                       "%d).\n",
-                      nnodes / 2, nnodes, npme_fixed);
+                      nnodes / 2,
+                      nnodes,
+                      npme_fixed);
         }
         if ((npme_fixed > 0) && (5 * npme_fixed < nnodes))
         {
@@ -2006,9 +2078,9 @@ static float inspect_tpr(int nfile, t_filenm fnm[], real* rcoulomb)
     t_inputrec  irInstance;
     t_inputrec* ir = &irInstance;
     read_tpx_state(opt2fn("-s", nfile, fnm), ir, &state, &mtop);
-    bFree = (efepNO != ir->efep);
-    bNM   = (eiNM == ir->eI);
-    bSwap = (eswapNO != ir->eSwapCoords);
+    bFree = (FreeEnergyPerturbationType::No != ir->efep);
+    bNM   = (IntegrationAlgorithm::NM == ir->eI);
+    bSwap = (SwapType::No != ir->eSwapCoords);
     bTpi  = EI_TPI(ir->eI);
 
     /* Set these output files on the tuning command-line */
@@ -2089,7 +2161,7 @@ int gmx_tune_pme(int argc, char* argv[])
         "[THISMODULE] needs to call [gmx-mdrun] and so requires that you",
         "specify how to call mdrun with the argument to the [TT]-mdrun[tt]",
         "parameter. Depending how you have built GROMACS, values such as",
-        "'gmx mdrun', 'gmx_d mdrun', or 'mdrun_mpi' might be needed.[PAR]",
+        "'gmx mdrun', 'gmx_d mdrun', or 'gmx_mpi mdrun' might be needed.[PAR]",
         "The program that runs MPI programs can be set in the environment variable",
         "MPIRUN (defaults to 'mpirun'). Note that for certain MPI frameworks,",
         "you need to provide a machine- or hostfile. This can also be passed",
@@ -2265,7 +2337,7 @@ int gmx_tune_pme(int argc, char* argv[])
           FALSE,
           etSTR,
           { &cmd_mdrun },
-          "Command line to run a simulation, e.g. 'gmx mdrun' or 'mdrun_mpi'" },
+          "Command line to run a simulation, e.g. 'gmx mdrun' or 'gmx_mpi mdrun'" },
         { "-np",
           FALSE,
           etINT,
@@ -2376,8 +2448,8 @@ int gmx_tune_pme(int argc, char* argv[])
 
     seconds = gmx_gettime();
 
-    if (!parse_common_args(&argc, argv, PCA_NOEXIT_ON_ARGS, NFILE, fnm, asize(pa), pa, asize(desc),
-                           desc, 0, nullptr, &oenv))
+    if (!parse_common_args(
+                &argc, argv, PCA_NOEXIT_ON_ARGS, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
     {
         return 0;
     }
@@ -2438,8 +2510,16 @@ int gmx_tune_pme(int argc, char* argv[])
 
     cmd_np = bbuf;
 
-    create_command_line_snippets(bAppendFiles, bKeepAndNumCPT, bResetCountersHalfWay, presteps,
-                                 NFILE, fnm, &cmd_args_bench, &cmd_args_launch, ExtraArgs, deffnm);
+    create_command_line_snippets(bAppendFiles,
+                                 bKeepAndNumCPT,
+                                 bResetCountersHalfWay,
+                                 presteps,
+                                 NFILE,
+                                 fnm,
+                                 &cmd_args_bench,
+                                 &cmd_args_launch,
+                                 ExtraArgs,
+                                 deffnm);
 
     /* Prepare to use checkpoint file if requested */
     sim_part = 1;
@@ -2460,8 +2540,22 @@ int gmx_tune_pme(int argc, char* argv[])
     fp = gmx_ffopen(opt2fn("-p", NFILE, fnm), "w");
 
     /* Make a quick consistency check of command line parameters */
-    check_input(nnodes, repeats, &ntprs, &rmin, rcoulomb, &rmax, maxPMEfraction, minPMEfraction,
-                npme_fixed, bench_nsteps, fnm, NFILE, sim_part, presteps, asize(pa), pa);
+    check_input(nnodes,
+                repeats,
+                &ntprs,
+                &rmin,
+                rcoulomb,
+                &rmax,
+                maxPMEfraction,
+                minPMEfraction,
+                npme_fixed,
+                bench_nsteps,
+                fnm,
+                NFILE,
+                sim_part,
+                presteps,
+                asize(pa),
+                pa);
 
     /* Determine the maximum and minimum number of PME nodes to test,
      * the actual list of settings is build in do_the_tests(). */
@@ -2597,8 +2691,16 @@ int gmx_tune_pme(int argc, char* argv[])
 
     /* It can be that ntprs is reduced by make_benchmark_tprs if not enough
      * different grids could be found. */
-    make_benchmark_tprs(opt2fn("-s", NFILE, fnm), tpr_names, bench_nsteps + presteps, cpt_steps,
-                        rmin, rmax, bScaleRvdw, &ntprs, info, fp);
+    make_benchmark_tprs(opt2fn("-s", NFILE, fnm),
+                        tpr_names,
+                        bench_nsteps + presteps,
+                        cpt_steps,
+                        rmin,
+                        rmax,
+                        bScaleRvdw,
+                        &ntprs,
+                        info,
+                        fp);
 
     /********************************************************************************/
     /* Main loop over all scenarios we need to test: tpr files, PME nodes, repeats  */
@@ -2608,15 +2710,34 @@ int gmx_tune_pme(int argc, char* argv[])
     {
         GMX_RELEASE_ASSERT(npmevalues_opt[0] != nullptr,
                            "Options inconsistency; npmevalues_opt[0] is NULL");
-        do_the_tests(fp, tpr_names, maxPMEnodes, minPMEnodes, npme_fixed, npmevalues_opt[0], perfdata,
-                     &pmeentries, repeats, nnodes, ntprs, bThreads, cmd_mpirun, cmd_np, cmd_mdrun,
-                     cmd_args_bench, fnm, NFILE, presteps, cpt_steps, bCheck, eligible_gpu_ids);
+        do_the_tests(fp,
+                     tpr_names,
+                     maxPMEnodes,
+                     minPMEnodes,
+                     npme_fixed,
+                     npmevalues_opt[0],
+                     perfdata,
+                     &pmeentries,
+                     repeats,
+                     nnodes,
+                     ntprs,
+                     bThreads,
+                     cmd_mpirun,
+                     cmd_np,
+                     cmd_mdrun,
+                     cmd_args_bench,
+                     fnm,
+                     NFILE,
+                     presteps,
+                     cpt_steps,
+                     bCheck,
+                     eligible_gpu_ids);
 
         fprintf(fp, "\nTuning took%8.1f minutes.\n", (gmx_gettime() - seconds) / 60.0);
 
         /* Analyse the results and give a suggestion for optimal settings: */
-        bKeepTPR = analyze_data(fp, opt2fn("-p", NFILE, fnm), perfdata, nnodes, ntprs, pmeentries,
-                                repeats, info, &best_tpr, &best_npme);
+        bKeepTPR = analyze_data(
+                fp, opt2fn("-p", NFILE, fnm), perfdata, nnodes, ntprs, pmeentries, repeats, info, &best_tpr, &best_npme);
 
         /* Take the best-performing tpr file and enlarge nsteps to original value */
         if (bKeepTPR && !bOverwrite)
@@ -2627,7 +2748,9 @@ int gmx_tune_pme(int argc, char* argv[])
         {
             simulation_tpr = opt2fn("-so", NFILE, fnm);
             modify_PMEsettings(bOverwrite ? (new_sim_nsteps + cpt_steps) : info->orig_sim_steps,
-                               info->orig_init_step, tpr_names[best_tpr], simulation_tpr);
+                               info->orig_init_step,
+                               tpr_names[best_tpr],
+                               simulation_tpr);
         }
 
         /* Let's get rid of the temporary benchmark input files */
@@ -2638,8 +2761,8 @@ int gmx_tune_pme(int argc, char* argv[])
         }
 
         /* Now start the real simulation if the user requested it ... */
-        launch_simulation(bLaunch, fp, bThreads, cmd_mpirun, cmd_np, cmd_mdrun, cmd_args_launch,
-                          simulation_tpr, best_npme, eligible_gpu_ids);
+        launch_simulation(
+                bLaunch, fp, bThreads, cmd_mpirun, cmd_np, cmd_mdrun, cmd_args_launch, simulation_tpr, best_npme, eligible_gpu_ids);
     }
     gmx_ffclose(fp);
 
index 547af12c8dfef7b86ded7e64a3a621d03ec1c6ee..e6e2232e7cd16ad879a18a312bcb18e1370e1fbe 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 up the module library
+add_library(topology INTERFACE)
+
 file(GLOB TOPOLOGY_SOURCES *.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${TOPOLOGY_SOURCES} PARENT_SCOPE)
 
-if (BUILD_TESTING)
-    add_subdirectory(tests)
-endif()
-
 if(GMX_INSTALL_LEGACY_API)
   install(FILES
          atomprop.h
-          atoms.h
-          block.h
-          forcefieldparameters.h
-          idef.h
-          ifunc.h
+         atoms.h
+         block.h
+         forcefieldparameters.h
+         idef.h
+         ifunc.h
          index.h
-          symtab.h
-          topology.h
-          DESTINATION include/gromacs/topology)
+         symtab.h
+         topology.h
+         DESTINATION include/gromacs/topology)
 endif()
+
+# Source files have the following private module dependencies.
+target_link_libraries(options PRIVATE
+               )
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(topology PUBLIC
+target_include_directories(topology INTERFACE
+        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(topology PUBLIC
+target_link_libraries(topology INTERFACE
+        legacy_api
+        )
+
+# TODO: when topology is an OBJECT target
+#target_link_libraries(topology PUBLIC legacy_api)
+#target_link_libraries(topology PRIVATE common)
+
+# Module dependencies
+# topology interfaces convey transitive dependence on these modules.
+#target_link_libraries(topology PUBLIC
+target_link_libraries(topology INTERFACE
+                      utility
+        )
+
+if (BUILD_TESTING)
+       add_subdirectory(tests)
+endif()
\ No newline at end of file
index c415086bfb0f97a29aa71b7b83419ef9f99fe592..4516c324e0c63da6a70249585875bf20fcc8998f 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -211,7 +211,9 @@ static int findPropertyIndex(AtomProperty*      ap,
         }
         else
         {
-            fprintf(debug, " match: %4s %4s\n", ap->entry[j].residueName.c_str(),
+            fprintf(debug,
+                    " match: %4s %4s\n",
+                    ap->entry[j].residueName.c_str(),
                     ap->entry[j].atomName.c_str());
         }
     }
@@ -235,8 +237,8 @@ static void addProperty(AtomProperty*      ap,
                         real               propValue,
                         int                line)
 {
-    bool bExact;
-    int  j = findPropertyIndex(ap, restype, residueName, atomName, &bExact);
+    bool bExact = false;
+    int  j      = findPropertyIndex(ap, restype, residueName, atomName, &bExact);
 
     if (!bExact)
     {
@@ -248,16 +250,26 @@ static void addProperty(AtomProperty*      ap,
     {
         if (ap->entry[j].value == propValue)
         {
-            fprintf(stderr, "Warning double identical entries for %s %s %g on line %d in file %s\n",
-                    residueName.c_str(), atomName.c_str(), propValue, line, ap->db.c_str());
+            fprintf(stderr,
+                    "Warning double identical entries for %s %s %g on line %d in file %s\n",
+                    residueName.c_str(),
+                    atomName.c_str(),
+                    propValue,
+                    line,
+                    ap->db.c_str());
         }
         else
         {
             fprintf(stderr,
                     "Warning double different entries %s %s %g and %g on line %d in file %s\n"
                     "Using last entry (%g)\n",
-                    residueName.c_str(), atomName.c_str(), propValue, ap->entry[j].value, line,
-                    ap->db.c_str(), propValue);
+                    residueName.c_str(),
+                    atomName.c_str(),
+                    propValue,
+                    ap->entry[j].value,
+                    line,
+                    ap->db.c_str(),
+                    propValue);
             ap->entry[j].value = propValue;
         }
     }
@@ -284,7 +296,7 @@ static void readProperty(AtomProperty* ap, ResidueType* restype, double factor)
     while (get_a_line(fp.get(), line, STRLEN))
     {
         line_no++;
-        double pp;
+        double pp = 0.0;
         if (sscanf(line, "%31s %31s %20lf", resnm, atomnm, &pp) == 3)
         {
             pp *= factor;
@@ -309,10 +321,11 @@ static void readProperty(AtomProperty* ap, ResidueType* restype, double factor)
  */
 static bool setProperties(AtomProperty* ap, ResidueType* restype, int eprop, bool haveBeenWarned)
 {
-    const char* fns[epropNR] = { "atommass.dat", "vdwradii.dat", "dgsolv.dat", "electroneg.dat",
-                                 "elements.dat" };
-    double      fac[epropNR] = { 1.0, 1.0, 418.4, 1.0, 1.0 };
-    double      def[epropNR] = { 12.011, 0.14, 0.0, 2.2, -1 };
+    const char* fns[epropNR] = {
+        "atommass.dat", "vdwradii.dat", "dgsolv.dat", "electroneg.dat", "elements.dat"
+    };
+    double fac[epropNR] = { 1.0, 1.0, 418.4, 1.0, 1.0 };
+    double def[epropNR] = { 12.011, 0.14, 0.0, 2.2, -1 };
 
     bool printWarning = false;
     if (!ap->isSet)
@@ -364,7 +377,8 @@ static void printvdwWarning(FILE* fp)
 {
     if (nullptr != fp)
     {
-        fprintf(fp, "NOTE: From version 5.0 %s uses the Van der Waals radii\n",
+        fprintf(fp,
+                "NOTE: From version 5.0 %s uses the Van der Waals radii\n",
                 gmx::getProgramContext().displayName());
         fprintf(fp, "from the source below. This means the results may be different\n");
         fprintf(fp, "compared to previous GROMACS versions.\n");
@@ -377,9 +391,8 @@ bool AtomProperties::setAtomProperty(int                eprop,
                                      const std::string& atomName,
                                      real*              value)
 {
-    int         j;
     std::string tmpAtomName, tmpResidueName;
-    gmx_bool    bExact;
+    bool        bExact = false;
 
     if (setProperties(prop(eprop), restype(), eprop, impl_->bWarned))
     {
@@ -396,7 +409,8 @@ bool AtomProperties::setAtomProperty(int                eprop,
     {
         tmpAtomName = atomName;
     }
-    j = findPropertyIndex(&(impl_->prop[eprop]), &impl_->restype, residueName, tmpAtomName, &bExact);
+    const int j = findPropertyIndex(
+            &(impl_->prop[eprop]), &impl_->restype, residueName, tmpAtomName, &bExact);
 
     if (eprop == epropVDW && !impl_->bWarnVDW)
     {
index 7e112b07ae0c7477fe4350473359635f73c08f8c..5cea3899f0922b8eff389286ed96389dde755fb4 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,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_TOPOLOGY_ATOMPROP_H
 #define GMX_TOPOLOGY_ATOMPROP_H
 
+#include <memory>
 #include <string>
 
 #include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/real.h"
 
 enum
@@ -115,7 +115,7 @@ private:
     //! Implementation pointer.
     class Impl;
 
-    gmx::PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 #endif
index 20ce6be8bb049e77b4b0a8ec20e272989ebce63a..eef9b6a9dfd8cb3a6a50b4c80411fc62f9c78374 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/atomprop.h"
 #include "gromacs/topology/symtab.h"
 #include "gromacs/utility/compare.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/txtdump.h"
 
-const char* ptype_str[eptNR + 1] = { "Atom", "Nucleus", "Shell", "Bond", "VSite", nullptr };
+const char* enumValueToString(ParticleType enumValue)
+{
+    static constexpr gmx::EnumerationArray<ParticleType, const char*> particleTypeNames = {
+        "Atom", "Nucleus", "Shell", "Bond", "VSite"
+    };
+    return particleTypeNames[enumValue];
+}
 
 void init_atom(t_atoms* at)
 {
@@ -101,8 +108,6 @@ void done_atomtypes(t_atomtypes* atype)
 
 void add_t_atoms(t_atoms* atoms, int natom_extra, int nres_extra)
 {
-    int i;
-
     if (natom_extra > 0)
     {
         srenew(atoms->atomname, atoms->nr + natom_extra);
@@ -119,7 +124,7 @@ void add_t_atoms(t_atoms* atoms, int natom_extra, int nres_extra)
         {
             srenew(atoms->atomtypeB, atoms->nr + natom_extra);
         }
-        for (i = atoms->nr; (i < atoms->nr + natom_extra); i++)
+        for (int i = atoms->nr; (i < atoms->nr + natom_extra); i++)
         {
             atoms->atomname[i] = nullptr;
             memset(&atoms->atom[i], 0, sizeof(atoms->atom[i]));
@@ -141,7 +146,7 @@ void add_t_atoms(t_atoms* atoms, int natom_extra, int nres_extra)
     if (nres_extra > 0)
     {
         srenew(atoms->resinfo, atoms->nres + nres_extra);
-        for (i = atoms->nres; (i < atoms->nres + nres_extra); i++)
+        for (int i = atoms->nres; (i < atoms->nres + nres_extra); i++)
         {
             std::memset(&atoms->resinfo[i], 0, sizeof(atoms->resinfo[i]));
         }
@@ -175,7 +180,7 @@ void init_t_atoms(t_atoms* atoms, int natoms, gmx_bool bPdbinfo)
 
 void gmx_pdbinfo_init_default(t_pdbinfo* pdbinfo)
 {
-    pdbinfo->type         = epdbATOM;
+    pdbinfo->type         = PdbRecordType::Atom;
     pdbinfo->atomnr       = 0;
     pdbinfo->altloc       = ' ';
     pdbinfo->atomnm[0]    = '\0';
@@ -187,8 +192,7 @@ void gmx_pdbinfo_init_default(t_pdbinfo* pdbinfo)
 
 t_atoms* copy_t_atoms(const t_atoms* src)
 {
-    t_atoms* dst;
-    int      i;
+    t_atoms* dst = nullptr;
 
     snew(dst, 1);
     init_t_atoms(dst, src->nr, (nullptr != src->pdbinfo));
@@ -205,7 +209,7 @@ t_atoms* copy_t_atoms(const t_atoms* src)
     {
         snew(dst->atomtypeB, src->nr);
     }
-    for (i = 0; (i < src->nr); i++)
+    for (int i = 0; (i < src->nr); i++)
     {
         dst->atom[i] = src->atom[i];
         if (nullptr != src->pdbinfo)
@@ -231,7 +235,7 @@ t_atoms* copy_t_atoms(const t_atoms* src)
     dst->havePdbInfo = src->havePdbInfo;
     dst->haveType    = src->haveType;
     dst->nres        = src->nres;
-    for (i = 0; (i < src->nres); i++)
+    for (int i = 0; (i < src->nres); i++)
     {
         dst->resinfo[i] = src->resinfo[i];
     }
@@ -247,64 +251,69 @@ void t_atoms_set_resinfo(t_atoms*      atoms,
                          int           chainnum,
                          char          chainid)
 {
-    t_resinfo* ri;
-
-    ri           = &atoms->resinfo[atoms->atom[atom_ind].resind];
-    ri->name     = put_symtab(symtab, resname);
-    ri->rtp      = nullptr;
-    ri->nr       = resnr;
-    ri->ic       = ic;
-    ri->chainnum = chainnum;
-    ri->chainid  = chainid;
+    t_resinfo* ri = &atoms->resinfo[atoms->atom[atom_ind].resind];
+    ri->name      = put_symtab(symtab, resname);
+    ri->rtp       = nullptr;
+    ri->nr        = resnr;
+    ri->ic        = ic;
+    ri->chainnum  = chainnum;
+    ri->chainid   = chainid;
 }
 
 static void pr_atom(FILE* fp, int indent, const char* title, const t_atom* atom, int n)
 {
-    int i;
-
     if (available(fp, atom, 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[%6d]={type=%3hu, typeB=%3hu, ptype=%8s, m=%12.5e, "
                     "q=%12.5e, mB=%12.5e, qB=%12.5e, resind=%5d, atomnumber=%3d}\n",
-                    title, i, atom[i].type, atom[i].typeB, ptype_str[atom[i].ptype], atom[i].m,
-                    atom[i].q, atom[i].mB, atom[i].qB, atom[i].resind, atom[i].atomnumber);
+                    title,
+                    i,
+                    atom[i].type,
+                    atom[i].typeB,
+                    enumValueToString(atom[i].ptype),
+                    atom[i].m,
+                    atom[i].q,
+                    atom[i].mB,
+                    atom[i].qB,
+                    atom[i].resind,
+                    atom[i].atomnumber);
         }
     }
 }
 
 static void pr_strings2(FILE* fp, int indent, const char* title, char*** nm, char*** nmB, int n, gmx_bool bShowNumbers)
 {
-    int i;
-
     if (available(fp, nm, indent, title))
     {
         indent = pr_title_n(fp, indent, title, n);
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < n; i++)
         {
             pr_indent(fp, indent);
-            fprintf(fp, "%s[%d]={name=\"%s\",nameB=\"%s\"}\n", title, bShowNumbers ? i : -1,
-                    *(nm[i]), *(nmB[i]));
+            fprintf(fp, "%s[%d]={name=\"%s\",nameB=\"%s\"}\n", title, bShowNumbers ? i : -1, *(nm[i]), *(nmB[i]));
         }
     }
 }
 
 static void pr_resinfo(FILE* fp, int indent, const char* title, const t_resinfo* resinfo, int n, gmx_bool bShowNumbers)
 {
-    int i;
-
     if (available(fp, resinfo, indent, title))
     {
         indent = pr_title_n(fp, indent, title, n);
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < n; i++)
         {
             pr_indent(fp, indent);
-            fprintf(fp, "%s[%d]={name=\"%s\", nr=%d, ic='%c'}\n", title, bShowNumbers ? i : -1,
-                    *(resinfo[i].name), resinfo[i].nr, (resinfo[i].ic == '\0') ? ' ' : resinfo[i].ic);
+            fprintf(fp,
+                    "%s[%d]={name=\"%s\", nr=%d, ic='%c'}\n",
+                    title,
+                    bShowNumbers ? i : -1,
+                    *(resinfo[i].name),
+                    resinfo[i].nr,
+                    (resinfo[i].ic == '\0') ? ' ' : resinfo[i].ic);
         }
     }
 }
@@ -324,15 +333,13 @@ void pr_atoms(FILE* fp, int indent, const char* title, const t_atoms* atoms, gmx
 
 void pr_atomtypes(FILE* fp, int indent, const char* title, const t_atomtypes* atomtypes, gmx_bool bShowNumbers)
 {
-    int i;
     if (available(fp, atomtypes, indent, title))
     {
         indent = pr_title(fp, indent, title);
-        for (i = 0; i < atomtypes->nr; i++)
+        for (int i = 0; i < atomtypes->nr; i++)
         {
             pr_indent(fp, indent);
-            fprintf(fp, "atomtype[%3d]={atomnumber=%4d}\n", bShowNumbers ? i : -1,
-                    atomtypes->atomnumber[i]);
+            fprintf(fp, "atomtype[%3d]={atomnumber=%4d}\n", bShowNumbers ? i : -1, atomtypes->atomnumber[i]);
         }
     }
 }
@@ -342,7 +349,7 @@ static void compareAtom(FILE* fp, int index, const t_atom* a1, const t_atom* a2,
     if (a2)
     {
         cmp_us(fp, "atom.type", index, a1->type, a2->type);
-        cmp_us(fp, "atom.ptype", index, a1->ptype, a2->ptype);
+        cmpEnum<ParticleType>(fp, "atom.ptype", 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, relativeTolerance, absoluteTolerance);
@@ -386,7 +393,7 @@ static void comparePdbinfo(FILE*            fp,
                            real             absoluteTolerance)
 {
     fprintf(fp, "comparing t_pdbinfo\n");
-    cmp_int(fp, "type", pdb, pdb1.type, pdb2.type);
+    cmpEnum<PdbRecordType>(fp, "type", pdb1.type, pdb2.type);
     cmp_int(fp, "atomnr", pdb, pdb1.atomnr, pdb2.atomnr);
     cmp_uc(fp, "altloc", pdb, pdb1.altloc, pdb2.altloc);
     cmp_str(fp, "atomnm", pdb, pdb1.atomnm, pdb2.atomnm);
@@ -466,15 +473,19 @@ void atomsSetMassesBasedOnNames(t_atoms* atoms, gmx_bool printMissingMasses)
     bool haveMass = true;
     for (int i = 0; i < atoms->nr; i++)
     {
-        if (!aps.setAtomProperty(epropMass, *atoms->resinfo[atoms->atom[i].resind].name,
-                                 *atoms->atomname[i], &atoms->atom[i].m))
+        if (!aps.setAtomProperty(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,
+                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++;
             }
index 513d1cf22734425cb697a6054ae0fb17a666db2b..a8fba1dd6de7e9c10d166402ffeacd306a5de65f 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2012,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_symtab;
 
 /* The particle type */
-enum
+enum class ParticleType : int
 {
-    eptAtom,
-    eptNucleus,
-    eptShell,
-    eptBond,
-    eptVSite,
-    eptNR
+    Atom,
+    Nucleus,
+    Shell,
+    Bond,
+    VSite,
+    Count
 };
 
 /* The particle type names */
-extern const char* ptype_str[eptNR + 1];
+const char* enumValueToString(ParticleType enumValue);
 
 /* Enumerated type for pdb records. The other entries are ignored
  * when reading a pdb file
  */
-enum PDB_record
+enum class PdbRecordType : int
 {
-    epdbATOM,
-    epdbHETATM,
-    epdbANISOU,
-    epdbCRYST1,
-    epdbCOMPND,
-    epdbMODEL,
-    epdbENDMDL,
-    epdbTER,
-    epdbHEADER,
-    epdbTITLE,
-    epdbREMARK,
-    epdbCONECT,
-    epdbNR
+    Atom,
+    Hetatm,
+    Anisou,
+    Cryst1,
+    Compound,
+    Model,
+    EndModel,
+    Ter,
+    Header,
+    Title,
+    Remark,
+    Conect,
+    Count
 };
 
+const char* enumValueToString(PdbRecordType enumValue);
+
 typedef struct t_atom
 {
     real           m, q;       /* Mass and charge                      */
     real           mB, qB;     /* Mass and charge for Free Energy calc */
     unsigned short type;       /* Atom type                            */
     unsigned short typeB;      /* Atom type for Free Energy calc       */
-    int            ptype;      /* Particle type                        */
+    ParticleType   ptype;      /* Particle type                        */
     int            resind;     /* Index into resinfo (in t_atoms)      */
     int            atomnumber; /* Atomic Number or 0                   */
     char           elem[4];    /* Element name                         */
@@ -106,14 +108,14 @@ typedef struct t_resinfo
 
 typedef struct t_pdbinfo
 {
-    int      type;         /* PDB record name                      */
-    int      atomnr;       /* PDB atom number                      */
-    char     altloc;       /* Alternate location indicator         */
-    char     atomnm[6];    /* True atom name including leading spaces */
-    real     occup;        /* Occupancy                            */
-    real     bfac;         /* B-factor                             */
-    gmx_bool bAnisotropic; /* (an)isotropic switch                 */
-    int      uij[6];       /* Anisotropic B-factor                 */
+    PdbRecordType type;         /* PDB record name                      */
+    int           atomnr;       /* PDB atom number                      */
+    char          altloc;       /* Alternate location indicator         */
+    char          atomnm[6];    /* True atom name including leading spaces */
+    real          occup;        /* Occupancy                            */
+    real          bfac;         /* B-factor                             */
+    gmx_bool      bAnisotropic; /* (an)isotropic switch                 */
+    int           uij[6];       /* Anisotropic B-factor                 */
 } t_pdbinfo;
 
 //! Contains indices into group names for different groups.
index e1616ee31805d975cf61045bb85cf3a47cd21f68..2212203b458b2316d2595c95289308e79d4837d3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_TOPOLOGY_ATOMSBUILDER_H
 #define GMX_TOPOLOGY_ATOMSBUILDER_H
 
+#include <memory>
 #include <vector>
 
 #include "gromacs/math/vectypes.h"
+
 #include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/real.h"
 
index cc6ad6b191fb593251125fc68a1569d4bff94ae7..8ffa830c50a7032b751470e72e2e645bb0a0e8ce 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ void init_blocka_null(t_blocka* block)
 
 t_blocka* new_blocka()
 {
-    t_blocka* block;
+    t_blocka* block = nullptr;
 
     snew(block, 1);
     snew(block->index, 1);
@@ -235,17 +235,15 @@ static int pr_listoflists_title(FILE* fp, int indent, const char* title, const g
 
 static void low_pr_blocka(FILE* fp, int indent, const char* title, const t_blocka* block, gmx_bool bShowNumbers)
 {
-    int i;
-
     if (available(fp, block, indent, title))
     {
         indent = pr_blocka_title(fp, indent, title, block);
-        for (i = 0; i <= block->nr; i++)
+        for (int i = 0; i <= block->nr; i++)
         {
             pr_indent(fp, indent + INDENT);
             fprintf(fp, "%s->index[%d]=%d\n", title, bShowNumbers ? i : -1, block->index[i]);
         }
-        for (i = 0; i < block->nra; i++)
+        for (int i = 0; i < block->nra; i++)
         {
             pr_indent(fp, indent + INDENT);
             fprintf(fp, "%s->a[%d]=%d\n", title, bShowNumbers ? i : -1, block->a[i]);
@@ -255,19 +253,17 @@ static void low_pr_blocka(FILE* fp, int indent, const char* title, const t_block
 
 void pr_block(FILE* fp, int indent, const char* title, const t_block* block, gmx_bool bShowNumbers)
 {
-    int i, start;
-
     if (available(fp, block, indent, title))
     {
-        indent = pr_block_title(fp, indent, title, block);
-        start  = 0;
+        indent    = pr_block_title(fp, indent, title, block);
+        int start = 0;
         if (block->index[start] != 0)
         {
             fprintf(fp, "block->index[%d] should be 0\n", start);
         }
         else
         {
-            for (i = 0; i < block->nr; i++)
+            for (int i = 0; i < block->nr; i++)
             {
                 int end = block->index[i + 1];
                 pr_indent(fp, indent);
@@ -277,8 +273,12 @@ void pr_block(FILE* fp, int indent, const char* title, const t_block* block, gmx
                 }
                 else
                 {
-                    fprintf(fp, "%s[%d]={%d..%d}\n", title, bShowNumbers ? i : -1,
-                            bShowNumbers ? start : -1, bShowNumbers ? end - 1 : -1);
+                    fprintf(fp,
+                            "%s[%d]={%d..%d}\n",
+                            title,
+                            bShowNumbers ? i : -1,
+                            bShowNumbers ? start : -1,
+                            bShowNumbers ? end - 1 : -1);
                 }
                 start = end;
             }
@@ -288,33 +288,38 @@ void pr_block(FILE* fp, int indent, const char* title, const t_block* block, gmx
 
 void pr_blocka(FILE* fp, int indent, const char* title, const t_blocka* block, gmx_bool bShowNumbers)
 {
-    int i, j, ok, size, start, end;
+    bool ok = false;
 
     if (available(fp, block, indent, title))
     {
-        indent = pr_blocka_title(fp, indent, title, block);
-        start  = 0;
-        end    = start;
-        if ((ok = static_cast<int>(block->index[start] == 0)) == 0)
+        indent    = pr_blocka_title(fp, indent, title, block);
+        int start = 0;
+        int end   = start;
+        ok        = (block->index[start] == 0);
+        if (!ok)
         {
             fprintf(fp, "block->index[%d] should be 0\n", start);
         }
         else
         {
-            for (i = 0; i < block->nr; i++)
+            for (int i = 0; i < block->nr; i++)
             {
-                end  = block->index[i + 1];
-                size = pr_indent(fp, indent);
+                end      = block->index[i + 1];
+                int size = pr_indent(fp, indent);
                 if (end <= start)
                 {
                     size += fprintf(fp, "%s[%d]={", title, i);
                 }
                 else
                 {
-                    size += fprintf(fp, "%s[%d][%d..%d]={", title, bShowNumbers ? i : -1,
-                                    bShowNumbers ? start : -1, bShowNumbers ? end - 1 : -1);
+                    size += fprintf(fp,
+                                    "%s[%d][%d..%d]={",
+                                    title,
+                                    bShowNumbers ? i : -1,
+                                    bShowNumbers ? start : -1,
+                                    bShowNumbers ? end - 1 : -1);
                 }
-                for (j = start; j < end; j++)
+                for (int j = start; j < end; j++)
                 {
                     if (j > start)
                     {
index 10fee47a24b40f31275487be8f752c85de506af9..0acf7f49b3fca0e58f69adcb94f9fd60089adf6d 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,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +41,6 @@
 
 #include <vector>
 
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/range.h"
 
index 036960895d0bd45b626a03411963d8cbb0105535..d15cdfc08727fb5f4775014f6810bd3ac69b424c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 static void pr_cmap(FILE* fp, int indent, const char* title, const gmx_cmap_t* cmap_grid, gmx_bool bShowNumbers)
 {
-    int  j, nelem;
-    real dx, idx;
+    const real dx = cmap_grid->grid_spacing != 0 ? 360.0 / cmap_grid->grid_spacing : 0;
 
-    if (cmap_grid->grid_spacing != 0)
-    {
-        dx = 360.0 / cmap_grid->grid_spacing;
-    }
-    else
-    {
-        dx = 0;
-    }
-    nelem = cmap_grid->grid_spacing * cmap_grid->grid_spacing;
+    const int nelem = cmap_grid->grid_spacing * cmap_grid->grid_spacing;
 
     if (available(fp, cmap_grid, indent, title))
     {
@@ -63,12 +54,12 @@ static void pr_cmap(FILE* fp, int indent, const char* title, const gmx_cmap_t* c
 
         for (gmx::index i = 0; i < gmx::ssize(cmap_grid->cmapdata); i++)
         {
-            idx = -180.0;
+            real idx = -180.0;
             fprintf(fp, "%8s %8s %8s %8s\n", "V", "dVdx", "dVdy", "d2dV");
 
             fprintf(fp, "grid[%3zd]={\n", bShowNumbers ? i : -1);
 
-            for (j = 0; j < nelem; j++)
+            for (int j = 0; j < nelem; j++)
             {
                 if ((j % cmap_grid->grid_spacing) == 0)
                 {
@@ -88,17 +79,17 @@ static void pr_cmap(FILE* fp, int indent, const char* title, const gmx_cmap_t* c
 
 void pr_ffparams(FILE* fp, int indent, const char* title, const gmx_ffparams_t* ffparams, gmx_bool bShowNumbers)
 {
-    int i;
-
     indent = pr_title(fp, indent, title);
     pr_indent(fp, indent);
     fprintf(fp, "atnr=%d\n", ffparams->atnr);
     pr_indent(fp, indent);
     fprintf(fp, "ntypes=%d\n", ffparams->numTypes());
-    for (i = 0; i < ffparams->numTypes(); i++)
+    for (int i = 0; i < ffparams->numTypes(); i++)
     {
         pr_indent(fp, indent + INDENT);
-        fprintf(fp, "functype[%d]=%s, ", bShowNumbers ? i : -1,
+        fprintf(fp,
+                "functype[%d]=%s, ",
+                bShowNumbers ? i : -1,
                 interaction_function[ffparams->functype[i]].name);
         pr_iparams(fp, ffparams->functype[i], ffparams->iparams[i]);
     }
index 03b0989476701c49570f54ca635d677a96bccceb..9d33f271a6febd93e6e43a1fd47b576cfa222033 100644 (file)
@@ -54,9 +54,15 @@ static void printHarmonicInteraction(gmx::TextWriter* writer,
                                      const char*      r,
                                      const char*      kr)
 {
-    writer->writeLineFormatted("%sA=%12.5e, %sA=%12.5e, %sB=%12.5e, %sB=%12.5e", r,
-                               iparams.harmonic.rA, kr, iparams.harmonic.krA, r,
-                               iparams.harmonic.rB, kr, iparams.harmonic.krB);
+    writer->writeLineFormatted("%sA=%12.5e, %sA=%12.5e, %sB=%12.5e, %sB=%12.5e",
+                               r,
+                               iparams.harmonic.rA,
+                               kr,
+                               iparams.harmonic.krA,
+                               r,
+                               iparams.harmonic.rB,
+                               kr,
+                               iparams.harmonic.krB);
 }
 
 void pr_iparams(FILE* fp, t_functype ftype, const t_iparams& iparams)
@@ -76,25 +82,37 @@ void printInteractionParameters(gmx::TextWriter* writer, t_functype ftype, const
         case F_ANGLES:
         case F_G96ANGLES: printHarmonicInteraction(writer, iparams, "th", "ct"); break;
         case F_CROSS_BOND_BONDS:
-            writer->writeLineFormatted("r1e=%15.8e, r2e=%15.8e, krr=%15.8e", iparams.cross_bb.r1e,
-                                       iparams.cross_bb.r2e, iparams.cross_bb.krr);
+            writer->writeLineFormatted("r1e=%15.8e, r2e=%15.8e, krr=%15.8e",
+                                       iparams.cross_bb.r1e,
+                                       iparams.cross_bb.r2e,
+                                       iparams.cross_bb.krr);
             break;
         case F_CROSS_BOND_ANGLES:
             writer->writeLineFormatted("r1e=%15.8e, r1e=%15.8e, r3e=%15.8e, krt=%15.8e",
-                                       iparams.cross_ba.r1e, iparams.cross_ba.r2e,
-                                       iparams.cross_ba.r3e, iparams.cross_ba.krt);
+                                       iparams.cross_ba.r1e,
+                                       iparams.cross_ba.r2e,
+                                       iparams.cross_ba.r3e,
+                                       iparams.cross_ba.krt);
             break;
         case F_LINEAR_ANGLES:
             writer->writeLineFormatted("klinA=%15.8e, aA=%15.8e, klinB=%15.8e, aB=%15.8e",
-                                       iparams.linangle.klinA, iparams.linangle.aA,
-                                       iparams.linangle.klinB, iparams.linangle.aB);
+                                       iparams.linangle.klinA,
+                                       iparams.linangle.aA,
+                                       iparams.linangle.klinB,
+                                       iparams.linangle.aB);
             break;
         case F_UREY_BRADLEY:
             writer->writeLineFormatted(
                     "thetaA=%15.8e, kthetaA=%15.8e, r13A=%15.8e, kUBA=%15.8e, thetaB=%15.8e, "
                     "kthetaB=%15.8e, r13B=%15.8e, kUBB=%15.8e",
-                    iparams.u_b.thetaA, iparams.u_b.kthetaA, iparams.u_b.r13A, iparams.u_b.kUBA,
-                    iparams.u_b.thetaB, iparams.u_b.kthetaB, iparams.u_b.r13B, iparams.u_b.kUBB);
+                    iparams.u_b.thetaA,
+                    iparams.u_b.kthetaA,
+                    iparams.u_b.r13A,
+                    iparams.u_b.kUBA,
+                    iparams.u_b.thetaB,
+                    iparams.u_b.kthetaB,
+                    iparams.u_b.r13B,
+                    iparams.u_b.kUBB);
             break;
         case F_QUARTIC_ANGLES:
             writer->writeStringFormatted("theta=%15.8e", iparams.qangle.theta);
@@ -105,8 +123,8 @@ void printInteractionParameters(gmx::TextWriter* writer, t_functype ftype, const
             writer->ensureLineBreak();
             break;
         case F_BHAM:
-            writer->writeLineFormatted("a=%15.8e, b=%15.8e, c=%15.8e", iparams.bham.a,
-                                       iparams.bham.b, iparams.bham.c);
+            writer->writeLineFormatted(
+                    "a=%15.8e, b=%15.8e, c=%15.8e", iparams.bham.a, iparams.bham.b, iparams.bham.c);
             break;
         case F_BONDS:
         case F_G96BONDS:
@@ -115,12 +133,18 @@ void printInteractionParameters(gmx::TextWriter* writer, t_functype ftype, const
         case F_MORSE:
             writer->writeLineFormatted(
                     "b0A=%15.8e, cbA=%15.8e, betaA=%15.8e, b0B=%15.8e, cbB=%15.8e, betaB=%15.8e",
-                    iparams.morse.b0A, iparams.morse.cbA, iparams.morse.betaA, iparams.morse.b0B,
-                    iparams.morse.cbB, iparams.morse.betaB);
+                    iparams.morse.b0A,
+                    iparams.morse.cbA,
+                    iparams.morse.betaA,
+                    iparams.morse.b0B,
+                    iparams.morse.cbB,
+                    iparams.morse.betaB);
             break;
         case F_CUBICBONDS:
-            writer->writeLineFormatted("b0=%15.8e, kb=%15.8e, kcub=%15.8e", iparams.cubic.b0,
-                                       iparams.cubic.kb, iparams.cubic.kcub);
+            writer->writeLineFormatted("b0=%15.8e, kb=%15.8e, kcub=%15.8e",
+                                       iparams.cubic.b0,
+                                       iparams.cubic.kb,
+                                       iparams.cubic.kcub);
             break;
         case F_CONNBONDS: writer->ensureEmptyLine(); break;
         case F_FENEBONDS:
@@ -130,106 +154,153 @@ void printInteractionParameters(gmx::TextWriter* writer, t_functype ftype, const
             writer->writeLineFormatted(
                     "lowA=%15.8e, up1A=%15.8e, up2A=%15.8e, kA=%15.8e, lowB=%15.8e, up1B=%15.8e, "
                     "up2B=%15.8e, kB=%15.8e,",
-                    iparams.restraint.lowA, iparams.restraint.up1A, iparams.restraint.up2A,
-                    iparams.restraint.kA, iparams.restraint.lowB, iparams.restraint.up1B,
-                    iparams.restraint.up2B, iparams.restraint.kB);
+                    iparams.restraint.lowA,
+                    iparams.restraint.up1A,
+                    iparams.restraint.up2A,
+                    iparams.restraint.kA,
+                    iparams.restraint.lowB,
+                    iparams.restraint.up1B,
+                    iparams.restraint.up2B,
+                    iparams.restraint.kB);
             break;
         case F_TABBONDS:
         case F_TABBONDSNC:
         case F_TABANGLES:
         case F_TABDIHS:
-            writer->writeLineFormatted("tab=%d, kA=%15.8e, kB=%15.8e", iparams.tab.table,
-                                       iparams.tab.kA, iparams.tab.kB);
+            writer->writeLineFormatted(
+                    "tab=%d, kA=%15.8e, kB=%15.8e", iparams.tab.table, iparams.tab.kA, iparams.tab.kB);
             break;
         case F_POLARIZATION:
             writer->writeLineFormatted("alpha=%15.8e", iparams.polarize.alpha);
             break;
         case F_ANHARM_POL:
             writer->writeLineFormatted("alpha=%15.8e drcut=%15.8e khyp=%15.8e",
-                                       iparams.anharm_polarize.alpha, iparams.anharm_polarize.drcut,
+                                       iparams.anharm_polarize.alpha,
+                                       iparams.anharm_polarize.drcut,
                                        iparams.anharm_polarize.khyp);
             break;
         case F_THOLE_POL:
             writer->writeLineFormatted("a=%15.8e, alpha1=%15.8e, alpha2=%15.8e, rfac=%15.8e",
-                                       iparams.thole.a, iparams.thole.alpha1, iparams.thole.alpha2,
+                                       iparams.thole.a,
+                                       iparams.thole.alpha1,
+                                       iparams.thole.alpha2,
                                        iparams.thole.rfac);
             break;
         case F_WATER_POL:
             writer->writeLineFormatted(
                     "al_x=%15.8e, al_y=%15.8e, al_z=%15.8e, rOH=%9.6f, rHH=%9.6f, rOD=%9.6f",
-                    iparams.wpol.al_x, iparams.wpol.al_y, iparams.wpol.al_z, iparams.wpol.rOH,
-                    iparams.wpol.rHH, iparams.wpol.rOD);
+                    iparams.wpol.al_x,
+                    iparams.wpol.al_y,
+                    iparams.wpol.al_z,
+                    iparams.wpol.rOH,
+                    iparams.wpol.rHH,
+                    iparams.wpol.rOD);
             break;
         case F_LJ:
             writer->writeLineFormatted("c6=%15.8e, c12=%15.8e", iparams.lj.c6, iparams.lj.c12);
             break;
         case F_LJ14:
             writer->writeLineFormatted("c6A=%15.8e, c12A=%15.8e, c6B=%15.8e, c12B=%15.8e",
-                                       iparams.lj14.c6A, iparams.lj14.c12A, iparams.lj14.c6B,
+                                       iparams.lj14.c6A,
+                                       iparams.lj14.c12A,
+                                       iparams.lj14.c6B,
                                        iparams.lj14.c12B);
             break;
         case F_LJC14_Q:
             writer->writeLineFormatted("fqq=%15.8e, qi=%15.8e, qj=%15.8e, c6=%15.8e, c12=%15.8e",
-                                       iparams.ljc14.fqq, iparams.ljc14.qi, iparams.ljc14.qj,
-                                       iparams.ljc14.c6, iparams.ljc14.c12);
+                                       iparams.ljc14.fqq,
+                                       iparams.ljc14.qi,
+                                       iparams.ljc14.qj,
+                                       iparams.ljc14.c6,
+                                       iparams.ljc14.c12);
             break;
         case F_LJC_PAIRS_NB:
-            writer->writeLineFormatted("qi=%15.8e, qj=%15.8e, c6=%15.8e, c12=%15.8e", iparams.ljcnb.qi,
-                                       iparams.ljcnb.qj, iparams.ljcnb.c6, iparams.ljcnb.c12);
+            writer->writeLineFormatted("qi=%15.8e, qj=%15.8e, c6=%15.8e, c12=%15.8e",
+                                       iparams.ljcnb.qi,
+                                       iparams.ljcnb.qj,
+                                       iparams.ljcnb.c6,
+                                       iparams.ljcnb.c12);
             break;
         case F_PDIHS:
         case F_PIDIHS:
         case F_ANGRES:
         case F_ANGRESZ:
             writer->writeLineFormatted("phiA=%15.8e, cpA=%15.8e, phiB=%15.8e, cpB=%15.8e, mult=%d",
-                                       iparams.pdihs.phiA, iparams.pdihs.cpA, iparams.pdihs.phiB,
-                                       iparams.pdihs.cpB, iparams.pdihs.mult);
+                                       iparams.pdihs.phiA,
+                                       iparams.pdihs.cpA,
+                                       iparams.pdihs.phiB,
+                                       iparams.pdihs.cpB,
+                                       iparams.pdihs.mult);
             break;
         case F_DISRES:
             writer->writeLineFormatted(
                     "label=%4d, type=%1d, low=%15.8e, up1=%15.8e, up2=%15.8e, fac=%15.8e)",
-                    iparams.disres.label, iparams.disres.type, iparams.disres.low,
-                    iparams.disres.up1, iparams.disres.up2, iparams.disres.kfac);
+                    iparams.disres.label,
+                    iparams.disres.type,
+                    iparams.disres.low,
+                    iparams.disres.up1,
+                    iparams.disres.up2,
+                    iparams.disres.kfac);
             break;
         case F_ORIRES:
             writer->writeLineFormatted(
                     "ex=%4d, label=%d, power=%4d, c=%15.8e, obs=%15.8e, kfac=%15.8e)",
-                    iparams.orires.ex, iparams.orires.label, iparams.orires.power, iparams.orires.c,
-                    iparams.orires.obs, iparams.orires.kfac);
+                    iparams.orires.ex,
+                    iparams.orires.label,
+                    iparams.orires.power,
+                    iparams.orires.c,
+                    iparams.orires.obs,
+                    iparams.orires.kfac);
             break;
         case F_DIHRES:
             writer->writeLineFormatted(
                     "phiA=%15.8e, dphiA=%15.8e, kfacA=%15.8e, phiB=%15.8e, dphiB=%15.8e, "
                     "kfacB=%15.8e",
-                    iparams.dihres.phiA, iparams.dihres.dphiA, iparams.dihres.kfacA,
-                    iparams.dihres.phiB, iparams.dihres.dphiB, iparams.dihres.kfacB);
+                    iparams.dihres.phiA,
+                    iparams.dihres.dphiA,
+                    iparams.dihres.kfacA,
+                    iparams.dihres.phiB,
+                    iparams.dihres.dphiB,
+                    iparams.dihres.kfacB);
             break;
         case F_POSRES:
             writer->writeLineFormatted(
                     "pos0A=(%15.8e,%15.8e,%15.8e), fcA=(%15.8e,%15.8e,%15.8e), "
                     "pos0B=(%15.8e,%15.8e,%15.8e), fcB=(%15.8e,%15.8e,%15.8e)",
-                    iparams.posres.pos0A[XX], iparams.posres.pos0A[YY], iparams.posres.pos0A[ZZ],
-                    iparams.posres.fcA[XX], iparams.posres.fcA[YY], iparams.posres.fcA[ZZ],
-                    iparams.posres.pos0B[XX], iparams.posres.pos0B[YY], iparams.posres.pos0B[ZZ],
-                    iparams.posres.fcB[XX], iparams.posres.fcB[YY], iparams.posres.fcB[ZZ]);
+                    iparams.posres.pos0A[XX],
+                    iparams.posres.pos0A[YY],
+                    iparams.posres.pos0A[ZZ],
+                    iparams.posres.fcA[XX],
+                    iparams.posres.fcA[YY],
+                    iparams.posres.fcA[ZZ],
+                    iparams.posres.pos0B[XX],
+                    iparams.posres.pos0B[YY],
+                    iparams.posres.pos0B[ZZ],
+                    iparams.posres.fcB[XX],
+                    iparams.posres.fcB[YY],
+                    iparams.posres.fcB[ZZ]);
             break;
         case F_FBPOSRES:
             writer->writeLineFormatted(
                     "pos0=(%15.8e,%15.8e,%15.8e), geometry=%d, r=%15.8e, k=%15.8e",
-                    iparams.fbposres.pos0[XX], iparams.fbposres.pos0[YY], iparams.fbposres.pos0[ZZ],
-                    iparams.fbposres.geom, iparams.fbposres.r, iparams.fbposres.k);
+                    iparams.fbposres.pos0[XX],
+                    iparams.fbposres.pos0[YY],
+                    iparams.fbposres.pos0[ZZ],
+                    iparams.fbposres.geom,
+                    iparams.fbposres.r,
+                    iparams.fbposres.k);
             break;
         case F_RBDIHS:
             for (int i = 0; i < NR_RBDIHS; i++)
             {
-                writer->writeStringFormatted("%srbcA[%d]=%15.8e", i == 0 ? "" : ", ", i,
-                                             iparams.rbdihs.rbcA[i]);
+                writer->writeStringFormatted(
+                        "%srbcA[%d]=%15.8e", i == 0 ? "" : ", ", i, iparams.rbdihs.rbcA[i]);
             }
             writer->ensureLineBreak();
             for (int i = 0; i < NR_RBDIHS; i++)
             {
-                writer->writeStringFormatted("%srbcB[%d]=%15.8e", i == 0 ? "" : ", ", i,
-                                             iparams.rbdihs.rbcB[i]);
+                writer->writeStringFormatted(
+                        "%srbcB[%d]=%15.8e", i == 0 ? "" : ", ", i, iparams.rbdihs.rbcB[i]);
             }
             writer->ensureLineBreak();
             break;
@@ -282,8 +353,8 @@ void printInteractionParameters(gmx::TextWriter* writer, t_functype ftype, const
         case F_VSITE3OUT:
         case F_VSITE4FD:
         case F_VSITE4FDN:
-            writer->writeLineFormatted("a=%15.8e, b=%15.8e, c=%15.8e", iparams.vsite.a,
-                                       iparams.vsite.b, iparams.vsite.c);
+            writer->writeLineFormatted(
+                    "a=%15.8e, b=%15.8e, c=%15.8e", iparams.vsite.a, iparams.vsite.b, iparams.vsite.c);
             break;
         case F_VSITEN:
             writer->writeLineFormatted("n=%2d, a=%15.8e", iparams.vsiten.n, iparams.vsiten.a);
@@ -313,8 +384,12 @@ void printInteractionParameters(gmx::TextWriter* writer, t_functype ftype, const
             writer->ensureLineBreak();
             break;
         default:
-            gmx_fatal(FARGS, "unknown function type %d (%s) in %s line %d", ftype,
-                      interaction_function[ftype].name, __FILE__, __LINE__);
+            gmx_fatal(FARGS,
+                      "unknown function type %d (%s) in %s line %d",
+                      ftype,
+                      interaction_function[ftype].name,
+                      __FILE__,
+                      __LINE__);
     }
 }
 
@@ -328,8 +403,6 @@ static void printIlist(FILE*             fp,
                        gmx_bool          bShowParameters,
                        const t_iparams*  iparams)
 {
-    int i, j, k, type, ftype;
-
     indent = pr_title(fp, indent, title);
     pr_indent(fp, indent);
     fprintf(fp, "nr: %d\n", ilist.size());
@@ -337,18 +410,19 @@ static void printIlist(FILE*             fp,
     {
         pr_indent(fp, indent);
         fprintf(fp, "iatoms:\n");
-        for (i = j = 0; i < ilist.size();)
+        int j = 0;
+        for (int i = 0; i < ilist.size();)
         {
             pr_indent(fp, indent + INDENT);
-            type  = ilist.iatoms[i];
-            ftype = functype[type];
+            const int type  = ilist.iatoms[i];
+            const int ftype = functype[type];
             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++)
+            for (int k = 0; k < interaction_function[ftype].nratoms; k++)
             {
                 fprintf(fp, " %3d", ilist.iatoms[i + 1 + k]);
             }
@@ -377,8 +451,6 @@ void pr_ilist(FILE*                  fp,
 
 void pr_idef(FILE* fp, int indent, const char* title, const t_idef* idef, gmx_bool bShowNumbers, gmx_bool bShowParameters)
 {
-    int i, j;
-
     if (available(fp, idef, indent, title))
     {
         indent = pr_title(fp, indent, title);
@@ -386,19 +458,27 @@ void pr_idef(FILE* fp, int indent, const char* title, const t_idef* idef, gmx_bo
         fprintf(fp, "atnr=%d\n", idef->atnr);
         pr_indent(fp, indent);
         fprintf(fp, "ntypes=%d\n", idef->ntypes);
-        for (i = 0; i < idef->ntypes; i++)
+        for (int i = 0; i < idef->ntypes; i++)
         {
             pr_indent(fp, indent + INDENT);
-            fprintf(fp, "functype[%d]=%s, ", bShowNumbers ? i : -1,
+            fprintf(fp,
+                    "functype[%d]=%s, ",
+                    bShowNumbers ? i : -1,
                     interaction_function[idef->functype[i]].name);
             pr_iparams(fp, idef->functype[i], idef->iparams[i]);
         }
         pr_real(fp, indent, "fudgeQQ", idef->fudgeQQ);
 
-        for (j = 0; (j < F_NRE); j++)
+        for (int j = 0; (j < F_NRE); j++)
         {
-            printIlist(fp, indent, interaction_function[j].longname, idef->functype, idef->il[j],
-                       bShowNumbers, bShowParameters, idef->iparams);
+            printIlist(fp,
+                       indent,
+                       interaction_function[j].longname,
+                       idef->functype,
+                       idef->il[j],
+                       bShowNumbers,
+                       bShowParameters,
+                       idef->iparams);
         }
     }
 }
index 40a4913cfbb16b15652112801468ec393f35c78f..1fb0a2fc2d7bb97a9589add2f0359b906c7408cc 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +45,6 @@
 
 #include "gromacs/math/vectypes.h"
 #include "gromacs/topology/ifunc.h"
-#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
 struct gmx_ffparams_t;
@@ -459,10 +458,10 @@ void pr_ilist(FILE*                  fp,
               const char*            title,
               const t_functype*      functype,
               const InteractionList& ilist,
-              gmx_bool               bShowNumbers,
-              gmx_bool               bShowParameters,
+              bool                   bShowNumbers,
+              bool                   bShowParameters,
               const t_iparams*       iparams);
-void pr_idef(FILE* fp, int indent, const char* title, const t_idef* idef, gmx_bool bShowNumbers, gmx_bool bShowParameters);
+void pr_idef(FILE* fp, int indent, const char* title, const t_idef* idef, bool bShowNumbers, bool bShowParameters);
 
 /*! \brief
  * Properly initialize idef struct.
index 0be9b8bb1ec0b5b0028c83ade77edef8209508f4..f52fdce4aa1aab813282b76de79993d1cb10fab1 100644 (file)
 
 /* this MUST correspond to the enum in src/gromacs/topology/ifunc.h */
 const t_interaction_function interaction_function[F_NRE] = {
-    def_bond("BONDS", "Bond", 2, 2, 2), def_bond("G96BONDS", "G96Bond", 2, 2, 2),
-    def_bond("MORSE", "Morse", 2, 3, 3), def_bond("CUBICBONDS", "Cubic Bonds", 2, 3, 0),
+    def_bond("BONDS", "Bond", 2, 2, 2),
+    def_bond("G96BONDS", "G96Bond", 2, 2, 2),
+    def_bond("MORSE", "Morse", 2, 3, 3),
+    def_bond("CUBICBONDS", "Cubic Bonds", 2, 3, 0),
     def_bondnb("CONNBONDS", "Connect Bonds", 2, 0, 0),
-    def_bonded("HARMONIC", "Harmonic Pot.", 2, 2, 2), def_bondnb("FENEBONDS", "FENE Bonds", 2, 2, 0),
-    def_bondt("TABBONDS", "Tab. Bonds", 2, 2, 2), def_bondedtz("TABBONDSNC", "Tab. Bonds NC", 2, 2, 2),
-    def_bonded("RESTRAINTPOT", "Restraint Pot.", 2, 4, 4), def_angle("ANGLES", "Angle", 3, 2, 2),
-    def_angle("G96ANGLES", "G96Angle", 3, 2, 2), def_angle("RESTRANGLES", "Restricted Angles", 3, 2, 2),
+    def_bonded("HARMONIC", "Harmonic Pot.", 2, 2, 2),
+    def_bondnb("FENEBONDS", "FENE Bonds", 2, 2, 0),
+    def_bondt("TABBONDS", "Tab. Bonds", 2, 2, 2),
+    def_bondedtz("TABBONDSNC", "Tab. Bonds NC", 2, 2, 2),
+    def_bonded("RESTRAINTPOT", "Restraint Pot.", 2, 4, 4),
+    def_angle("ANGLES", "Angle", 3, 2, 2),
+    def_angle("G96ANGLES", "G96Angle", 3, 2, 2),
+    def_angle("RESTRANGLES", "Restricted Angles", 3, 2, 2),
     def_angle("LINEAR_ANGLES", "Lin. Angle", 3, 2, 2),
     def_bonded("CROSS_BOND_BOND", "Bond-Cross", 3, 3, 0),
-    def_bonded("CROSS_BOND_ANGLE", "BA-Cross", 3, 4, 0), def_angle("UREY_BRADLEY", "U-B", 3, 4, 4),
-    def_angle("QANGLES", "Quartic Angles", 3, 6, 0), def_bondedt("TABANGLES", "Tab. Angles", 3, 2, 2),
-    def_dihedral("PDIHS", "Proper Dih.", 4, 3, 3), def_dihedral("RBDIHS", "Ryckaert-Bell.", 4, 6, 6),
+    def_bonded("CROSS_BOND_ANGLE", "BA-Cross", 3, 4, 0),
+    def_angle("UREY_BRADLEY", "U-B", 3, 4, 4),
+    def_angle("QANGLES", "Quartic Angles", 3, 6, 0),
+    def_bondedt("TABANGLES", "Tab. Angles", 3, 2, 2),
+    def_dihedral("PDIHS", "Proper Dih.", 4, 3, 3),
+    def_dihedral("RBDIHS", "Ryckaert-Bell.", 4, 6, 6),
     def_dihedral("RESTRDIHS", "Restricted Dih.", 4, 2, 2),
-    def_dihedral("CBTDIHS", "CBT Dih.", 4, 6, 6), def_dihedral("FOURDIHS", "Fourier Dih.", 4, 4, 4),
-    def_dihedral("IDIHS", "Improper Dih.", 4, 2, 2), def_dihedral("PIDIHS", "Improper Dih.", 4, 3, 3),
+    def_dihedral("CBTDIHS", "CBT Dih.", 4, 6, 6),
+    def_dihedral("FOURDIHS", "Fourier Dih.", 4, 4, 4),
+    def_dihedral("IDIHS", "Improper Dih.", 4, 2, 2),
+    def_dihedral("PIDIHS", "Improper Dih.", 4, 3, 3),
     def_dihedral_tabulated("TABDIHS", "Tab. Dih.", 4, 2, 2),
-    def_dihedral("CMAP", "CMAP Dih.", 5, -1, -1), def_nofc("GB12", "GB 1-2 Pol. (unused)"),
-    def_nofc("GB13", "GB 1-3 Pol. (unused)"), def_nofc("GB14", "GB 1-4 Pol. (unused)"),
-    def_nofc("GBPOL", "GB Polarization (unused)"), def_nofc("NPSOLVATION", "Nonpolar Sol. (unused)"),
-    def_pair("LJ14", "LJ-14", 2, 2, 2), def_nofc("COUL14", "Coulomb-14"),
-    def_pair("LJC14_Q", "LJC-14 q", 2, 5, 0), def_pair("LJC_NB", "LJC Pairs NB", 2, 4, 0),
-    def_nb("LJ_SR", "LJ (SR)", 2, 2), def_nb("BHAM", "Buck.ham (SR)", 2, 3),
-    def_nofc("LJ_LR", "LJ (unused)"), def_nofc("BHAM_LR", "B.ham (unused)"),
-    def_nofc("DISPCORR", "Disper. corr."), def_nofc("COUL_SR", "Coulomb (SR)"),
-    def_nofc("COUL_LR", "Coul (unused)"), def_nofc("RF_EXCL", "RF excl."),
-    def_nofc("COUL_RECIP", "Coul. recip."), def_nofc("LJ_RECIP", "LJ recip."),
-    def_nofc("DPD", "DPD"), def_bondnb("POLARIZATION", "Polarization", 2, 1, 0),
-    def_bonded("WATERPOL", "Water Pol.", 5, 6, 0), def_bonded("THOLE", "Thole Pol.", 4, 3, 0),
-    def_bondnb("ANHARM_POL", "Anharm. Pol.", 2, 3, 0), def_bonded("POSRES", "Position Rest.", 1, 3, 3),
-    def_bonded("FBPOSRES", "Flat-bottom posres", 1, 3, 0), def_bonded("DISRES", "Dis. Rest.", 2, 6, 0),
-    def_nofc("DISRESVIOL", "D.R.Viol. (nm)"), def_bonded("ORIRES", "Orient. Rest.", 2, 6, 0),
-    def_nofc("ORDEV", "Ori. R. RMSD"), def_bonded("ANGRES", "Angle Rest.", 4, 3, 3),
-    def_bonded("ANGRESZ", "Angle Rest. Z", 2, 3, 3), def_bonded("DIHRES", "Dih. Rest.", 4, 3, 3),
+    def_dihedral("CMAP", "CMAP Dih.", 5, -1, -1),
+    def_nofc("GB12", "GB 1-2 Pol. (unused)"),
+    def_nofc("GB13", "GB 1-3 Pol. (unused)"),
+    def_nofc("GB14", "GB 1-4 Pol. (unused)"),
+    def_nofc("GBPOL", "GB Polarization (unused)"),
+    def_nofc("NPSOLVATION", "Nonpolar Sol. (unused)"),
+    def_pair("LJ14", "LJ-14", 2, 2, 2),
+    def_nofc("COUL14", "Coulomb-14"),
+    def_pair("LJC14_Q", "LJC-14 q", 2, 5, 0),
+    def_pair("LJC_NB", "LJC Pairs NB", 2, 4, 0),
+    def_nb("LJ_SR", "LJ (SR)", 2, 2),
+    def_nb("BHAM", "Buck.ham (SR)", 2, 3),
+    def_nofc("LJ_LR", "LJ (unused)"),
+    def_nofc("BHAM_LR", "B.ham (unused)"),
+    def_nofc("DISPCORR", "Disper. corr."),
+    def_nofc("COUL_SR", "Coulomb (SR)"),
+    def_nofc("COUL_LR", "Coul (unused)"),
+    def_nofc("RF_EXCL", "RF excl."),
+    def_nofc("COUL_RECIP", "Coul. recip."),
+    def_nofc("LJ_RECIP", "LJ recip."),
+    def_nofc("DPD", "DPD"),
+    def_bondnb("POLARIZATION", "Polarization", 2, 1, 0),
+    def_bonded("WATERPOL", "Water Pol.", 5, 6, 0),
+    def_bonded("THOLE", "Thole Pol.", 4, 3, 0),
+    def_bondnb("ANHARM_POL", "Anharm. Pol.", 2, 3, 0),
+    def_bonded("POSRES", "Position Rest.", 1, 3, 3),
+    def_bonded("FBPOSRES", "Flat-bottom posres", 1, 3, 0),
+    def_bonded("DISRES", "Dis. Rest.", 2, 6, 0),
+    def_nofc("DISRESVIOL", "D.R.Viol. (nm)"),
+    def_bonded("ORIRES", "Orient. Rest.", 2, 6, 0),
+    def_nofc("ORDEV", "Ori. R. RMSD"),
+    def_bonded("ANGRES", "Angle Rest.", 4, 3, 3),
+    def_bonded("ANGRESZ", "Angle Rest. Z", 2, 3, 3),
+    def_bonded("DIHRES", "Dih. Rest.", 4, 3, 3),
     def_nofc("DIHRESVIOL", "Dih. Rest. Viol."), /* obsolete */
-    def_shkcb("CONSTR", "Constraint", 2, 1, 1), def_shk("CONSTRNC", "Constr. No Conn.", 2, 1, 1),
-    def_shkcb("SETTLE", "Settle", 3, 2, 0), def_vsite("VSITE1", "Virtual site 1", 2, 0),
-    def_vsite("VSITE2", "Virtual site 2", 3, 1), def_vsite("VSITE2FD", "Virtual site 2fd", 3, 1),
-    def_vsite("VSITE3", "Virtual site 3", 4, 2), def_vsite("VSITE3FD", "Virtual site 3fd", 4, 2),
+    def_shkcb("CONSTR", "Constraint", 2, 1, 1),
+    def_shk("CONSTRNC", "Constr. No Conn.", 2, 1, 1),
+    def_shkcb("SETTLE", "Settle", 3, 2, 0),
+    def_vsite("VSITE1", "Virtual site 1", 2, 0),
+    def_vsite("VSITE2", "Virtual site 2", 3, 1),
+    def_vsite("VSITE2FD", "Virtual site 2fd", 3, 1),
+    def_vsite("VSITE3", "Virtual site 3", 4, 2),
+    def_vsite("VSITE3FD", "Virtual site 3fd", 4, 2),
     def_vsite("VSITE3FAD", "Virtual site 3fad", 4, 2),
-    def_vsite("VSITE3OUT", "Virtual site 3out", 4, 3), def_vsite("VSITE4FD", "Virtual site 4fd", 5, 3),
-    def_vsite("VSITE4FDN", "Virtual site 4fdn", 5, 3), def_vsite("VSITEN", "Virtual site N", 2, 2),
-    def_nofc("COM_PULL", "COM Pull En."), def_nofc("DENSITYFIT", "Density fitting"),
-    def_nofc("EQM", "Quantum En."), def_nofc("EPOT", "Potential"), def_nofc("EKIN", "Kinetic En."),
-    def_nofc("ETOT", "Total Energy"), def_nofc("ECONS", "Conserved En."),
-    def_nofc("TEMP", "Temperature"), def_nofc("VTEMP", "Vir. Temp. (not used)"),
+    def_vsite("VSITE3OUT", "Virtual site 3out", 4, 3),
+    def_vsite("VSITE4FD", "Virtual site 4fd", 5, 3),
+    def_vsite("VSITE4FDN", "Virtual site 4fdn", 5, 3),
+    def_vsite("VSITEN", "Virtual site N", 2, 2),
+    def_nofc("COM_PULL", "COM Pull En."),
+    def_nofc("DENSITYFIT", "Density fitting"),
+    def_nofc("EQM", "Quantum En."),
+    def_nofc("EPOT", "Potential"),
+    def_nofc("EKIN", "Kinetic En."),
+    def_nofc("ETOT", "Total Energy"),
+    def_nofc("ECONS", "Conserved En."),
+    def_nofc("TEMP", "Temperature"),
+    def_nofc("VTEMP", "Vir. Temp. (not used)"),
     /* Note that pressure names can not be more than 8 char's,
      * because " (bar)" is appended to them.
      */
-    def_nofc("PDISPCORR", "Pres. DC"), def_nofc("PRES", "Pressure"),
+    def_nofc("PDISPCORR", "Pres. DC"),
+    def_nofc("PRES", "Pressure"),
     def_nofc("DH/DL_CON", "dH/dl constr."), /* obsolete */
-    def_nofc("DV/DL", "dVremain/dl"), def_nofc("DK/DL", "dEkin/dl"), def_nofc("DVC/DL", "dVcoul/dl"),
-    def_nofc("DVV/DL", "dVvdw/dl"), def_nofc("DVB/DL", "dVbonded/dl"),
-    def_nofc("DVR/DL", "dVrestraint/dl"), def_nofc("DVT/DL", "dVtemperature/dl")
+    def_nofc("DV/DL", "dVremain/dl"),
+    def_nofc("DK/DL", "dEkin/dl"),
+    def_nofc("DVC/DL", "dVcoul/dl"),
+    def_nofc("DVV/DL", "dVvdw/dl"),
+    def_nofc("DVB/DL", "dVbonded/dl"),
+    def_nofc("DVR/DL", "dVrestraint/dl"),
+    def_nofc("DVT/DL", "dVtemperature/dl")
 };
index 46dd0653dc44cbdaa43c91905a518bd13ba47203..6d671af2b58aa0a50d31b8bc5931cb87eb8cb907 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstring>
 
 #include <algorithm>
+#include <numeric>
 
 #include "gromacs/topology/atoms.h"
 #include "gromacs/topology/block.h"
@@ -59,7 +60,7 @@
 
 static gmx_bool gmx_ask_yesno(gmx_bool bASK)
 {
-    char c;
+    char c = 0;
 
     if (bASK)
     {
@@ -78,15 +79,12 @@ static gmx_bool gmx_ask_yesno(gmx_bool bASK)
 
 void write_index(const char* outf, t_blocka* b, char** gnames, gmx_bool bDuplicate, int natoms)
 {
-    FILE* out;
-    int   i, j, k;
-
-    out = gmx_ffopen(outf, "w");
+    FILE* out = gmx_ffopen(outf, "w");
     /* fprintf(out,"%5d  %5d\n",b->nr,b->nra); */
-    for (i = 0; (i < b->nr); i++)
+    for (int i = 0; (i < b->nr); i++)
     {
         fprintf(out, "[ %s ]", gnames[i]);
-        for (k = 0, j = b->index[i]; j < b->index[i + 1]; j++, k++)
+        for (int k = 0, j = b->index[i]; j < b->index[i + 1]; j++, k++)
         {
             const char sep = (k % 15 == 0 ? '\n' : ' ');
             fprintf(out, "%c%4d", sep, b->a[j] + 1);
@@ -98,10 +96,10 @@ void write_index(const char* outf, t_blocka* b, char** gnames, gmx_bool bDuplica
     if (bDuplicate)
     {
         fprintf(stderr, "Duplicating the whole system with an atom offset of %d atoms.\n", natoms);
-        for (i = 0; (i < b->nr); i++)
+        for (int i = 0; (i < b->nr); i++)
         {
             fprintf(out, "[ %s_copy ]", gnames[i]);
-            for (k = 0, j = b->index[i]; j < b->index[i + 1]; j++, k++)
+            for (int k = 0, j = b->index[i]; j < b->index[i + 1]; j++, k++)
             {
                 const char sep = (k % 15 == 0 ? '\n' : ' ');
                 fprintf(out, "%c%4d", sep, b->a[j] + 1 + natoms);
@@ -228,12 +226,10 @@ static void analyse_other(gmx::ArrayRef<std::string> restype,
                           gmx_bool                   bASK,
                           gmx_bool                   bVerb)
 {
-    restp_t* restp = nullptr;
-    char**   attp  = nullptr;
-    char *   rname, *aname;
-    int      i, resind, natp, nrestp = 0;
+    std::vector<restp_t> restp;
+    int                  i = 0;
 
-    for (i = 0; (i < atoms->nres); i++)
+    for (; (i < atoms->nres); i++)
     {
         if (gmx_strcasecmp(restype[i].c_str(), "Protein")
             && gmx_strcasecmp(restype[i].c_str(), "DNA") && gmx_strcasecmp(restype[i].c_str(), "RNA")
@@ -252,38 +248,32 @@ static void analyse_other(gmx::ArrayRef<std::string> restype,
         }
         for (int k = 0; (k < atoms->nr); k++)
         {
-            resind = atoms->atom[k].resind;
-            rname  = *atoms->resinfo[resind].name;
+            int         resind = atoms->atom[k].resind;
+            const char* rname  = *atoms->resinfo[resind].name;
             if (gmx_strcasecmp(restype[resind].c_str(), "Protein")
                 && gmx_strcasecmp(restype[resind].c_str(), "DNA")
                 && gmx_strcasecmp(restype[resind].c_str(), "RNA")
                 && gmx_strcasecmp(restype[resind].c_str(), "Water"))
             {
-                int l;
-                for (l = 0; (l < nrestp); l++)
-                {
-                    assert(restp);
-                    if (strcmp(restp[l].rname, rname) == 0)
-                    {
-                        break;
-                    }
-                }
-                if (l == nrestp)
+                auto found = std::find_if(restp.begin(), restp.end(), [rname](const auto& entry) {
+                    return strcmp(entry.rname, rname) == 0;
+                });
+                if (found == restp.end())
                 {
-                    srenew(restp, nrestp + 1);
-                    restp[nrestp].rname = gmx_strdup(rname);
-                    restp[nrestp].bNeg  = FALSE;
-                    restp[nrestp].gname = gmx_strdup(rname);
-                    nrestp++;
+                    restp.emplace_back();
+                    auto& last = restp.back();
+                    last.rname = gmx_strdup(rname);
+                    last.bNeg  = false;
+                    last.gname = gmx_strdup(rname);
                 }
             }
         }
-        for (int i = 0; (i < nrestp); i++)
+        for (int i = 0; (i < gmx::ssize(restp)); i++)
         {
             std::vector<int> aid;
             for (int j = 0; (j < atoms->nr); j++)
             {
-                rname = *atoms->resinfo[atoms->atom[j].resind].name;
+                const char* rname = *atoms->resinfo[atoms->atom[j].resind].name;
                 if ((strcmp(restp[i].rname, rname) == 0 && !restp[i].bNeg)
                     || (strcmp(restp[i].rname, rname) != 0 && restp[i].bNeg))
                 {
@@ -297,32 +287,27 @@ static void analyse_other(gmx::ArrayRef<std::string> restype,
                 fflush(stdout);
                 if (gmx_ask_yesno(bASK))
                 {
-                    natp = 0;
+                    std::vector<const char*> attp;
                     for (size_t k = 0; (k < aid.size()); k++)
                     {
-                        aname = *atoms->atomname[aid[k]];
-                        int l;
-                        for (l = 0; (l < natp); l++)
-                        {
-                            if (strcmp(aname, attp[l]) == 0)
-                            {
-                                break;
-                            }
-                        }
-                        if (l == natp)
+                        const char* aname = *atoms->atomname[aid[k]];
+                        auto found = std::find_if(attp.begin(), attp.end(), [aname](const char* entry) {
+                            return strcmp(aname, entry) == 0;
+                        });
+                        if (found == attp.end())
                         {
-                            srenew(attp, ++natp);
-                            attp[natp - 1] = aname;
+                            attp.emplace_back(aname);
                         }
                     }
-                    if (natp > 1)
+                    if (attp.size() > 1)
                     {
+                        const int natp = attp.size();
                         for (int l = 0; (l < natp); l++)
                         {
                             std::vector<int> aaid;
                             for (size_t k = 0; (k < aid.size()); k++)
                             {
-                                aname = *atoms->atomname[aid[k]];
+                                const char* aname = *atoms->atomname[aid[k]];
                                 if (strcmp(aname, attp[l]) == 0)
                                 {
                                     aaid.push_back(aid[k]);
@@ -331,14 +316,11 @@ static void analyse_other(gmx::ArrayRef<std::string> restype,
                             add_grp(gb, gn, aaid, attp[l]);
                         }
                     }
-                    sfree(attp);
-                    attp = nullptr;
                 }
             }
             sfree(restp[i].rname);
             sfree(restp[i].gname);
         }
-        sfree(restp);
     }
 }
 
@@ -401,11 +383,7 @@ static void analyse_prot(gmx::ArrayRef<const std::string> restype,
     };
     const int num_index_groups = asize(constructing_data);
 
-    int      n, j;
-    int      npres;
-    gmx_bool match;
-    char     ndx_name[STRLEN], *atnm;
-    int      i;
+    char ndx_name[STRLEN];
 
     if (bVerb)
     {
@@ -414,8 +392,8 @@ static void analyse_prot(gmx::ArrayRef<const std::string> restype,
     std::vector<int> aid;
 
     /* calculate the number of protein residues */
-    npres = 0;
-    for (i = 0; (i < atoms->nres); i++)
+    int npres = 0;
+    for (int i = 0; (i < atoms->nres); i++)
     {
         if (0 == gmx_strcasecmp(restype[i].c_str(), "Protein"))
         {
@@ -423,17 +401,17 @@ static void analyse_prot(gmx::ArrayRef<const std::string> restype,
         }
     }
     /* find matching or complement atoms */
-    for (i = 0; (i < num_index_groups); i++)
+    for (int i = 0; (i < num_index_groups); i++)
     {
-        for (n = 0; (n < atoms->nr); n++)
+        for (int n = 0; (n < atoms->nr); n++)
         {
             if (0 == gmx_strcasecmp(restype[atoms->atom[n].resind].c_str(), "Protein"))
             {
-                match = FALSE;
-                for (j = 0; (j < constructing_data[i].num_defining_atomnames); j++)
+                bool match = false;
+                for (int j = 0; (j < constructing_data[i].num_defining_atomnames); j++)
                 {
                     /* skip digits at beginning of atomname, e.g. 1H */
-                    atnm = *atoms->atomname[n];
+                    char* atnm = *atoms->atomname[n];
                     while (isdigit(atnm[0]))
                     {
                         atnm++;
@@ -442,16 +420,17 @@ static void analyse_prot(gmx::ArrayRef<const std::string> restype,
                     {
                         if (0 == gmx_strcasecmp(constructing_data[i].defining_atomnames[j], atnm))
                         {
-                            match = TRUE;
+                            match = true;
                         }
                     }
                     else
                     {
                         if (0
-                            == gmx_strncasecmp(constructing_data[i].defining_atomnames[j], atnm,
+                            == gmx_strncasecmp(constructing_data[i].defining_atomnames[j],
+                                               atnm,
                                                strlen(constructing_data[i].defining_atomnames[j])))
                         {
-                            match = TRUE;
+                            match = true;
                         }
                     }
                 }
@@ -472,26 +451,25 @@ static void analyse_prot(gmx::ArrayRef<const std::string> restype,
 
     if (bASK)
     {
-        for (i = 0; (i < num_index_groups); i++)
+        for (int i = 0; (i < num_index_groups); i++)
         {
             printf("Split %12s into %5d residues (y/n) ? ", constructing_data[i].group_name, npres);
             if (gmx_ask_yesno(bASK))
             {
-                int resind;
                 aid.clear();
-                for (n = 0; ((atoms->atom[n].resind < npres) && (n < atoms->nr));)
+                for (int n = 0; ((atoms->atom[n].resind < npres) && (n < atoms->nr));)
                 {
-                    resind = atoms->atom[n].resind;
+                    int resind = atoms->atom[n].resind;
                     for (; ((atoms->atom[n].resind == resind) && (n < atoms->nr)); n++)
                     {
-                        match = FALSE;
-                        for (j = 0; (j < constructing_data[i].num_defining_atomnames); j++)
+                        bool match = false;
+                        for (int j = 0; (j < constructing_data[i].num_defining_atomnames); j++)
                         {
                             if (0
                                 == gmx_strcasecmp(constructing_data[i].defining_atomnames[j],
                                                   *atoms->atomname[n]))
                             {
-                                match = TRUE;
+                                match = true;
                             }
                         }
                         if (constructing_data[i].bTakeComplement != match)
@@ -502,10 +480,13 @@ static void analyse_prot(gmx::ArrayRef<const std::string> restype,
                     /* copy the residuename to the tail of the groupname */
                     if (!aid.empty())
                     {
-                        t_resinfo* ri;
-                        ri = &atoms->resinfo[resind];
-                        sprintf(ndx_name, "%s_%s%d%c", constructing_data[i].group_name, *ri->name,
-                                ri->nr, ri->ic == ' ' ? '\0' : ri->ic);
+                        t_resinfo* ri = &atoms->resinfo[resind];
+                        sprintf(ndx_name,
+                                "%s_%s%d%c",
+                                constructing_data[i].group_name,
+                                *ri->name,
+                                ri->nr,
+                                ri->ic == ' ' ? '\0' : ri->ic);
                         add_grp(gb, gn, aid, ndx_name);
                         aid.clear();
                     }
@@ -571,21 +552,13 @@ static void analyse_prot(gmx::ArrayRef<const std::string> restype,
 
 void analyse(const t_atoms* atoms, t_blocka* gb, char*** gn, gmx_bool bASK, gmx_bool bVerb)
 {
-    char* resnm;
-    int   i;
-    int   iwater, iion;
-    int   nwater, nion;
-
     if (bVerb)
     {
         printf("Analysing residue names:\n");
     }
     /* Create system group, every single atom */
     std::vector<int> aid(atoms->nr);
-    for (i = 0; i < atoms->nr; i++)
-    {
-        aid[i] = i;
-    }
+    std::iota(aid.begin(), aid.end(), 0);
     add_grp(gb, gn, aid, "System");
 
     /* For every residue, get a pointer to the residue type name */
@@ -595,15 +568,13 @@ void analyse(const t_atoms* atoms, t_blocka* gb, char*** gn, gmx_bool bASK, gmx_
     std::vector<std::string> previousTypename;
     if (atoms->nres > 0)
     {
-        int i = 0;
-
-        resnm = *atoms->resinfo[i].name;
+        const char* resnm = *atoms->resinfo[0].name;
         restype.emplace_back(rt.typeOfNamedDatabaseResidue(resnm));
         previousTypename.push_back(restype.back());
 
-        for (i = 1; i < atoms->nres; i++)
+        for (int i = 1; i < atoms->nres; i++)
         {
-            resnm = *atoms->resinfo[i].name;
+            const char* resnm = *atoms->resinfo[i].name;
             restype.emplace_back(rt.typeOfNamedDatabaseResidue(resnm));
 
             /* Note that this does not lead to a N*N loop, but N*K, where
@@ -628,7 +599,7 @@ void analyse(const t_atoms* atoms, t_blocka* gb, char*** gn, gmx_bool bASK, gmx_
 
     for (gmx::index k = 0; k < gmx::ssize(previousTypename); k++)
     {
-        aid = mk_aid(atoms, restype, previousTypename[k], TRUE);
+        std::vector<int> aid = mk_aid(atoms, restype, previousTypename[k], TRUE);
 
         /* Check for special types to do fancy stuff with */
 
@@ -638,7 +609,7 @@ void analyse(const t_atoms* atoms, t_blocka* gb, char*** gn, gmx_bool bASK, gmx_
             analyse_prot(restype, atoms, gb, gn, bASK, bVerb);
 
             /* Create a Non-Protein group */
-            aid = mk_aid(atoms, restype, "Protein", FALSE);
+            std::vector<int> aid = mk_aid(atoms, restype, "Protein", FALSE);
             if ((!aid.empty()) && (gmx::ssize(aid) < atoms->nr))
             {
                 add_grp(gb, gn, aid, "non-Protein");
@@ -652,7 +623,7 @@ void analyse(const t_atoms* atoms, t_blocka* gb, char*** gn, gmx_bool bASK, gmx_
 
 
             /* Solvent, create a negated group too */
-            aid = mk_aid(atoms, restype, "Water", FALSE);
+            std::vector<int> aid = mk_aid(atoms, restype, "Water", FALSE);
             if ((!aid.empty()) && (gmx::ssize(aid) < atoms->nr))
             {
                 add_grp(gb, gn, aid, "non-Water");
@@ -668,12 +639,12 @@ void analyse(const t_atoms* atoms, t_blocka* gb, char*** gn, gmx_bool bASK, gmx_
 
 
     /* Create a merged water_and_ions group */
-    iwater = -1;
-    iion   = -1;
-    nwater = 0;
-    nion   = 0;
+    int iwater = -1;
+    int iion   = -1;
+    int nwater = 0;
+    int nion   = 0;
 
-    for (i = 0; i < gb->nr; i++)
+    for (int i = 0; i < gb->nr; i++)
     {
         if (!gmx_strcasecmp((*gn)[i], "Water"))
         {
@@ -695,14 +666,14 @@ void analyse(const t_atoms* atoms, t_blocka* gb, char*** gn, gmx_bool bASK, gmx_
         srenew(gb->a, gb->nra + nwater + nion);
         if (nwater > 0)
         {
-            for (i = gb->index[iwater]; i < gb->index[iwater + 1]; i++)
+            for (int i = gb->index[iwater]; i < gb->index[iwater + 1]; i++)
             {
                 gb->a[gb->nra++] = gb->a[i];
             }
         }
         if (nion > 0)
         {
-            for (i = gb->index[iion]; i < gb->index[iion + 1]; i++)
+            for (int i = gb->index[iion]; i < gb->index[iion + 1]; i++)
             {
                 gb->a[gb->nra++] = gb->a[i];
             }
@@ -715,41 +686,42 @@ void analyse(const t_atoms* atoms, t_blocka* gb, char*** gn, gmx_bool bASK, gmx_
 
 void check_index(const char* gname, int n, int index[], const char* traj, int natoms)
 {
-    int i;
-
-    for (i = 0; i < n; i++)
+    for (int i = 0; i < n; i++)
     {
         if (index[i] >= natoms)
         {
             gmx_fatal(FARGS,
                       "%s atom number (index[%d]=%d) is larger than the number of atoms in %s (%d)",
-                      gname ? gname : "Index", i + 1, index[i] + 1, traj ? traj : "the trajectory",
+                      gname ? gname : "Index",
+                      i + 1,
+                      index[i] + 1,
+                      traj ? traj : "the trajectory",
                       natoms);
         }
         else if (index[i] < 0)
         {
-            gmx_fatal(FARGS, "%s atom number (index[%d]=%d) is less than zero",
-                      gname ? gname : "Index", i + 1, index[i] + 1);
+            gmx_fatal(FARGS,
+                      "%s atom number (index[%d]=%d) is less than zero",
+                      gname ? gname : "Index",
+                      i + 1,
+                      index[i] + 1);
         }
     }
 }
 
 t_blocka* init_index(const char* gfile, char*** grpname)
 {
-    FILE*     in;
-    t_blocka* b;
-    int       maxentries;
-    int       i, j;
-    char      line[STRLEN], *pt, str[STRLEN];
+    t_blocka* b = nullptr;
+    char      line[STRLEN], str[STRLEN];
 
-    in = gmx_ffopen(gfile, "r");
+    FILE* in = gmx_ffopen(gfile, "r");
     snew(b, 1);
-    b->nr      = 0;
-    b->index   = nullptr;
-    b->nra     = 0;
-    b->a       = nullptr;
-    *grpname   = nullptr;
-    maxentries = 0;
+    b->nr          = 0;
+    b->index       = nullptr;
+    b->nra         = 0;
+    b->a           = nullptr;
+    *grpname       = nullptr;
+    int maxentries = 0;
     while (get_a_line(in, line, STRLEN))
     {
         if (get_header(line, str))
@@ -770,10 +742,10 @@ t_blocka* init_index(const char* gfile, char*** grpname)
             {
                 gmx_fatal(FARGS, "The first header of your indexfile is invalid");
             }
-            pt = line;
+            char* pt = line;
             while (sscanf(pt, "%s", str) == 1)
             {
-                i = b->index[b->nr];
+                int i = b->index[b->nr];
                 if (i >= maxentries)
                 {
                     maxentries += 1024;
@@ -789,10 +761,10 @@ t_blocka* init_index(const char* gfile, char*** grpname)
     }
     gmx_ffclose(in);
 
-    for (i = 0; (i < b->nr); i++)
+    for (int i = 0; (i < b->nr); i++)
     {
         assert(b->a != nullptr); // for clang analyzer
-        for (j = b->index[i]; (j < b->index[i + 1]); j++)
+        for (int j = b->index[i]; (j < b->index[i + 1]); j++)
         {
             if (b->a[j] < 0)
             {
@@ -806,9 +778,7 @@ t_blocka* init_index(const char* gfile, char*** grpname)
 
 static void minstring(char* str)
 {
-    int i;
-
-    for (i = 0; (i < static_cast<int>(strlen(str))); i++)
+    for (int i = 0; (i < static_cast<int>(strlen(str))); i++)
     {
         if (str[i] == '-')
         {
@@ -819,21 +789,19 @@ static void minstring(char* str)
 
 int find_group(const char* s, int ngrps, char** grpname)
 {
-    int      aa, i, n;
-    char     string[STRLEN];
-    gmx_bool bMultiple;
-    bMultiple = FALSE;
-    n         = strlen(s);
-    aa        = -1;
+    char      string[STRLEN];
+    bool      bMultiple = false;
+    const int n         = strlen(s);
+    int       aa        = -1;
     /* first look for whole name match */
     {
-        for (i = 0; i < ngrps; i++)
+        for (int i = 0; i < ngrps; i++)
         {
             if (gmx_strcasecmp_min(s, grpname[i]) == 0)
             {
                 if (aa != -1)
                 {
-                    bMultiple = TRUE;
+                    bMultiple = true;
                 }
                 aa = i;
             }
@@ -842,7 +810,7 @@ int find_group(const char* s, int ngrps, char** grpname)
     /* second look for first string match */
     if (aa == -1)
     {
-        for (i = 0; i < ngrps; i++)
+        for (int i = 0; i < ngrps; i++)
         {
             if (gmx_strncasecmp_min(s, grpname[i], n) == 0)
             {
@@ -862,7 +830,7 @@ int find_group(const char* s, int ngrps, char** grpname)
         key[STRLEN - 1] = '\0';
         upstring(key);
         minstring(key);
-        for (i = 0; i < ngrps; i++)
+        for (int i = 0; i < ngrps; i++)
         {
             strncpy(string, grpname[i], STRLEN - 1);
             upstring(string);
@@ -887,10 +855,10 @@ int find_group(const char* s, int ngrps, char** grpname)
 
 static int qgroup(int* a, int ngrps, char** grpname)
 {
-    char     s[STRLEN];
-    int      aa;
-    gmx_bool bInRange;
-    char*    end;
+    char  s[STRLEN];
+    int   aa       = 0;
+    bool  bInRange = false;
+    char* end      = nullptr;
 
     do
     {
@@ -922,19 +890,17 @@ static int qgroup(int* a, int ngrps, char** grpname)
 static void
 rd_groups(t_blocka* grps, char** grpname, char* gnames[], int ngrps, int isize[], int* index[], int grpnr[])
 {
-    int i, j, gnr1;
-
     if (grps->nr == 0)
     {
         gmx_fatal(FARGS, "Error: no groups in indexfile");
     }
-    for (i = 0; (i < grps->nr); i++)
+    for (int i = 0; (i < grps->nr); i++)
     {
-        fprintf(stderr, "Group %5d (%15s) has %5d elements\n", i, grpname[i],
-                grps->index[i + 1] - grps->index[i]);
+        fprintf(stderr, "Group %5d (%15s) has %5d elements\n", i, grpname[i], grps->index[i + 1] - grps->index[i]);
     }
-    for (i = 0; (i < ngrps); i++)
+    for (int i = 0; (i < ngrps); i++)
     {
+        int gnr1 = 0;
         if (grps->nr > 1)
         {
             do
@@ -954,7 +920,7 @@ rd_groups(t_blocka* grps, char** grpname, char* gnames[], int ngrps, int isize[]
         gnames[i] = gmx_strdup(grpname[gnr1]);
         isize[i]  = grps->index[gnr1 + 1] - grps->index[gnr1];
         snew(index[i], isize[i]);
-        for (j = 0; (j < isize[i]); j++)
+        for (int j = 0; (j < isize[i]); j++)
         {
             index[i][j] = grps->a[grps->index[gnr1] + j];
         }
@@ -963,16 +929,15 @@ rd_groups(t_blocka* grps, char** grpname, char* gnames[], int ngrps, int isize[]
 
 void rd_index(const char* statfile, int ngrps, int isize[], int* index[], char* grpnames[])
 {
-    char**    gnames;
-    t_blocka* grps;
-    int*      grpnr;
+    char** gnames = nullptr;
+    int*   grpnr  = nullptr;
 
     snew(grpnr, ngrps);
     if (!statfile)
     {
         gmx_fatal(FARGS, "No index file specified");
     }
-    grps = init_index(statfile, &gnames);
+    t_blocka* grps = init_index(statfile, &gnames);
     rd_groups(grps, gnames, grpnames, ngrps, isize, index, grpnr);
     for (int i = 0; i < grps->nr; i++)
     {
@@ -986,9 +951,9 @@ void rd_index(const char* statfile, int ngrps, int isize[], int* index[], char*
 
 void get_index(const t_atoms* atoms, const char* fnm, int ngrps, int isize[], int* index[], char* grpnames[])
 {
-    char***   gnames;
-    t_blocka* grps = nullptr;
-    int*      grpnr;
+    char***   gnames = nullptr;
+    t_blocka* grps   = nullptr;
+    int*      grpnr  = nullptr;
 
     snew(grpnr, ngrps);
     snew(gnames, 1);
@@ -1021,30 +986,33 @@ void get_index(const t_atoms* atoms, const char* fnm, int ngrps, int isize[], in
 
 t_cluster_ndx* cluster_index(FILE* fplog, const char* ndx)
 {
-    t_cluster_ndx* c;
-    int            i;
+    t_cluster_ndx* c = nullptr;
 
     snew(c, 1);
     c->clust    = init_index(ndx, &c->grpname);
     c->maxframe = -1;
-    for (i = 0; (i < c->clust->nra); i++)
+    for (int i = 0; (i < c->clust->nra); i++)
     {
         c->maxframe = std::max(c->maxframe, c->clust->a[i]);
     }
     fprintf(fplog ? fplog : stdout,
-            "There are %d clusters containing %d structures, highest framenr is %d\n", c->clust->nr,
-            c->clust->nra, c->maxframe);
+            "There are %d clusters containing %d structures, highest framenr is %d\n",
+            c->clust->nr,
+            c->clust->nra,
+            c->maxframe);
     if (debug)
     {
         pr_blocka(debug, 0, "clust", c->clust, TRUE);
-        for (i = 0; (i < c->clust->nra); i++)
+        for (int i = 0; (i < c->clust->nra); i++)
         {
             if ((c->clust->a[i] < 0) || (c->clust->a[i] > c->maxframe))
             {
                 gmx_fatal(FARGS,
                           "Range check error for c->clust->a[%d] = %d\n"
                           "should be within 0 and %d",
-                          i, c->clust->a[i], c->maxframe + 1);
+                          i,
+                          c->clust->a[i],
+                          c->maxframe + 1);
             }
         }
     }
index 9f4d6878f3fb7c2251445266e39587c74debd544..ccd4c3f41a86d816e9446ffa45c4f0db3cdd0e11 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,2019, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2015,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 int* make_invblock(const t_block* block, int nr)
 {
-    int  i, j;
-    int* invblock;
+    int* invblock = nullptr;
 
     snew(invblock, nr + 1);
     /* Mark unused numbers */
-    for (i = 0; i <= nr; i++)
+    for (int i = 0; i <= nr; i++)
     {
         invblock[i] = -1;
     }
-    for (i = 0; (i < block->nr); i++)
+    for (int i = 0; (i < block->nr); i++)
     {
-        for (j = block->index[i]; (j < block->index[i + 1]); j++)
+        for (int j = block->index[i]; (j < block->index[i + 1]); j++)
         {
             if (invblock[j] == -1)
             {
@@ -67,7 +66,9 @@ int* make_invblock(const t_block* block, int nr)
                 gmx_fatal(FARGS,
                           "Double entries in block structure. Item %d is in blocks %d and %d\n"
                           " Cannot make an unambiguous inverse block.",
-                          j, i, invblock[j]);
+                          j,
+                          i,
+                          invblock[j]);
             }
         }
     }
@@ -76,18 +77,17 @@ int* make_invblock(const t_block* block, int nr)
 
 int* make_invblocka(const t_blocka* block, int nr)
 {
-    int  i, j;
-    int* invblock;
+    int* invblock = nullptr;
 
     snew(invblock, nr + 1);
     /* Mark unused numbers */
-    for (i = 0; i <= nr; i++)
+    for (int i = 0; i <= nr; i++)
     {
         invblock[i] = -1;
     }
-    for (i = 0; (i < block->nr); i++)
+    for (int i = 0; (i < block->nr); i++)
     {
-        for (j = block->index[i]; (j < block->index[i + 1]); j++)
+        for (int j = block->index[i]; (j < block->index[i + 1]); j++)
         {
             if (invblock[block->a[j]] == -1)
             {
@@ -98,7 +98,9 @@ int* make_invblocka(const t_blocka* block, int nr)
                 gmx_fatal(FARGS,
                           "Double entries in block structure. Item %d is in blocks %d and %d\n"
                           " Cannot make an unambiguous inverse block.",
-                          j, i, invblock[block->a[j]]);
+                          j,
+                          i,
+                          invblock[block->a[j]]);
             }
         }
     }
index 0c61cc0265f6621558a4d8ed36407f41ec9ba597..8b9c4befee492a51a3e4658a3904c110f8554357 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -69,34 +69,34 @@ struct t_atom;
  * \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,
+static inline void mtopGetMolblockIndex(const gmx_mtop_t& mtop,
                                         int               globalAtomIndex,
                                         int*              moleculeBlock,
                                         int*              moleculeIndex,
                                         int*              atomIndexInMolecule)
 {
     GMX_ASSERT(globalAtomIndex >= 0, "The atom index to look up should not be negative");
-    GMX_ASSERT(globalAtomIndex < mtop->natoms, "The atom index to look up should be within range");
+    GMX_ASSERT(globalAtomIndex < mtop.natoms, "The atom index to look up should be within range");
     GMX_ASSERT(moleculeBlock != nullptr, "molBlock can not be NULL");
-    GMX_ASSERT(!mtop->moleculeBlockIndices.empty(), "The moleculeBlockIndices should not be empty");
+    GMX_ASSERT(!mtop.moleculeBlockIndices.empty(), "The moleculeBlockIndices should not be empty");
     GMX_ASSERT(*moleculeBlock >= 0,
                "The starting molecule block index for the search should not be negative");
-    GMX_ASSERT(*moleculeBlock < gmx::ssize(mtop->moleculeBlockIndices),
+    GMX_ASSERT(*moleculeBlock < gmx::ssize(mtop.moleculeBlockIndices),
                "The starting molecule block index for the search should be within range");
 
     /* Search the molecule block index using bisection */
     int molBlock0 = -1;
-    int molBlock1 = mtop->molblock.size();
+    int molBlock1 = mtop.molblock.size();
 
-    int globalAtomStart;
+    int globalAtomStart = 0;
     while (TRUE)
     {
-        globalAtomStart = mtop->moleculeBlockIndices[*moleculeBlock].globalAtomStart;
+        globalAtomStart = mtop.moleculeBlockIndices[*moleculeBlock].globalAtomStart;
         if (globalAtomIndex < globalAtomStart)
         {
             molBlock1 = *moleculeBlock;
         }
-        else if (globalAtomIndex >= mtop->moleculeBlockIndices[*moleculeBlock].globalAtomEnd)
+        else if (globalAtomIndex >= mtop.moleculeBlockIndices[*moleculeBlock].globalAtomEnd)
         {
             molBlock0 = *moleculeBlock;
         }
@@ -108,7 +108,7 @@ static inline void mtopGetMolblockIndex(const gmx_mtop_t* mtop,
     }
 
     int molIndex = (globalAtomIndex - globalAtomStart)
-                   / mtop->moleculeBlockIndices[*moleculeBlock].numAtomsPerMolecule;
+                   / mtop.moleculeBlockIndices[*moleculeBlock].numAtomsPerMolecule;
     if (moleculeIndex != nullptr)
     {
         *moleculeIndex = molIndex;
@@ -116,7 +116,7 @@ static inline void mtopGetMolblockIndex(const gmx_mtop_t* mtop,
     if (atomIndexInMolecule != nullptr)
     {
         *atomIndexInMolecule = globalAtomIndex - globalAtomStart
-                               - molIndex * mtop->moleculeBlockIndices[*moleculeBlock].numAtomsPerMolecule;
+                               - molIndex * mtop.moleculeBlockIndices[*moleculeBlock].numAtomsPerMolecule;
     }
 }
 
@@ -132,12 +132,12 @@ static inline void mtopGetMolblockIndex(const gmx_mtop_t* mtop,
  * \param[in]     globalAtomIndex      The global atom index to look up
  * \param[in,out] moleculeBlock        The molecule block index in \p mtop
  */
-static inline int mtopGetMoleculeIndex(const gmx_mtop_t* mtop, int globalAtomIndex, int* moleculeBlock)
+static inline int mtopGetMoleculeIndex(const gmx_mtop_t& mtop, int globalAtomIndex, int* moleculeBlock)
 {
-    int localMoleculeIndex;
+    int localMoleculeIndex = 0;
     mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock, &localMoleculeIndex, nullptr);
 
-    return mtop->moleculeBlockIndices[*moleculeBlock].moleculeIndexStart + localMoleculeIndex;
+    return mtop.moleculeBlockIndices[*moleculeBlock].moleculeIndexStart + localMoleculeIndex;
 }
 
 /*! \brief Returns the atom data for an atom based on global atom index
@@ -152,11 +152,11 @@ static inline int mtopGetMoleculeIndex(const gmx_mtop_t* mtop, int globalAtomInd
  * \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)
+static inline const t_atom& mtopGetAtomParameters(const gmx_mtop_t& mtop, int globalAtomIndex, int* moleculeBlock)
 {
-    int atomIndexInMolecule;
+    int atomIndexInMolecule = 0;
     mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock, nullptr, &atomIndexInMolecule);
-    const gmx_moltype_t& moltype = mtop->moltype[mtop->molblock[*moleculeBlock].type];
+    const gmx_moltype_t& moltype = mtop.moltype[mtop.molblock[*moleculeBlock].type];
     return moltype.atoms.atom[atomIndexInMolecule];
 }
 
@@ -173,7 +173,7 @@ static inline const t_atom& mtopGetAtomParameters(const gmx_mtop_t* mtop, int gl
  * \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)
+static inline real mtopGetAtomMass(const gmx_mtop_t& mtop, int globalAtomIndex, int* moleculeBlock)
 {
     const t_atom& atom = mtopGetAtomParameters(mtop, globalAtomIndex, moleculeBlock);
     return atom.m;
@@ -198,7 +198,7 @@ static inline real mtopGetAtomMass(const gmx_mtop_t* mtop, int globalAtomIndex,
  * \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,
+static inline void mtopGetAtomAndResidueName(const gmx_mtop_t& mtop,
                                              int               globalAtomIndex,
                                              int*              moleculeBlock,
                                              const char**      atomName,
@@ -206,20 +206,20 @@ static inline void mtopGetAtomAndResidueName(const gmx_mtop_t* mtop,
                                              const char**      residueName,
                                              int*              globalResidueIndex)
 {
-    int moleculeIndex;
-    int atomIndexInMolecule;
+    int moleculeIndex       = 0;
+    int atomIndexInMolecule = 0;
     mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock, &moleculeIndex, &atomIndexInMolecule);
 
-    const gmx_molblock_t&       molb    = mtop->molblock[*moleculeBlock];
-    const t_atoms&              atoms   = mtop->moltype[molb.type].atoms;
-    const MoleculeBlockIndices& indices = mtop->moleculeBlockIndices[*moleculeBlock];
+    const gmx_molblock_t&       molb    = mtop.molblock[*moleculeBlock];
+    const t_atoms&              atoms   = mtop.moltype[molb.type].atoms;
+    const MoleculeBlockIndices& indices = mtop.moleculeBlockIndices[*moleculeBlock];
     if (atomName != nullptr)
     {
         *atomName = *(atoms.atomname[atomIndexInMolecule]);
     }
     if (residueNumber != nullptr)
     {
-        if (atoms.nres > mtop->maxResiduesPerMoleculeToTriggerRenumber())
+        if (atoms.nres > mtop.maxResiduesPerMoleculeToTriggerRenumber())
         {
             *residueNumber = atoms.resinfo[atoms.atom[atomIndexInMolecule].resind].nr;
         }
@@ -241,19 +241,6 @@ static inline void mtopGetAtomAndResidueName(const gmx_mtop_t* mtop,
     }
 }
 
-//! \copydoc mtopGetAtomAndResidueName()
-static inline void mtopGetAtomAndResidueName(const gmx_mtop_t& mtop,
-                                             int               globalAtomIndex,
-                                             int*              moleculeBlock,
-                                             const char**      atomName,
-                                             int*              residueNumber,
-                                             const char**      residueName,
-                                             int*              globalResidueIndex)
-{
-    mtopGetAtomAndResidueName(&mtop, globalAtomIndex, moleculeBlock, atomName, residueNumber,
-                              residueName, globalResidueIndex);
-}
-
 /*! \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.
@@ -266,11 +253,11 @@ static inline void mtopGetAtomAndResidueName(const gmx_mtop_t& mtop,
  * \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)
+static inline const t_resinfo& mtopGetResidueInfo(const gmx_mtop_t& mtop, int globalAtomIndex, int* moleculeBlock)
 {
-    int atomIndexInMolecule;
+    int atomIndexInMolecule = 0;
     mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock, nullptr, &atomIndexInMolecule);
-    const gmx_moltype_t& moltype = mtop->moltype[mtop->molblock[*moleculeBlock].type];
+    const gmx_moltype_t& moltype = mtop.moltype[mtop.molblock[*moleculeBlock].type];
     const int            resind  = moltype.atoms.atom[atomIndexInMolecule].resind;
     return moltype.atoms.resinfo[resind];
 }
@@ -287,11 +274,11 @@ static inline const t_resinfo& mtopGetResidueInfo(const gmx_mtop_t* mtop, int gl
  * \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)
+static inline const t_pdbinfo& mtopGetAtomPdbInfo(const gmx_mtop_t& mtop, int globalAtomIndex, int* moleculeBlock)
 {
-    int atomIndexInMolecule;
+    int atomIndexInMolecule = 0;
     mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock, nullptr, &atomIndexInMolecule);
-    const gmx_moltype_t& moltype = mtop->moltype[mtop->molblock[*moleculeBlock].type];
+    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];
 }
index 269cc533a98318e15ec30d2e1135913573d77416..1e92998ad7025764ec2edc8f2ef62184487d9498 100644 (file)
 #include "gromacs/topology/topology.h"
 #include "gromacs/topology/topsort.h"
 #include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/real.h"
 #include "gromacs/utility/smalloc.h"
 
-void gmx_mtop_count_atomtypes(const gmx_mtop_t* mtop, int state, int typecount[])
+void gmx_mtop_count_atomtypes(const gmx_mtop_t& mtop, int state, int typecount[])
 {
-    for (int i = 0; i < mtop->ffparams.atnr; ++i)
+    for (int i = 0; i < mtop.ffparams.atnr; ++i)
     {
         typecount[i] = 0;
     }
-    for (const gmx_molblock_t& molb : mtop->molblock)
+    for (const gmx_molblock_t& molb : mtop.molblock)
     {
-        const t_atoms& atoms = mtop->moltype[molb.type].atoms;
+        const t_atoms& atoms = mtop.moltype[molb.type].atoms;
         for (int i = 0; i < atoms.nr; ++i)
         {
-            int tpi;
-            if (state == 0)
-            {
-                tpi = atoms.atom[i].type;
-            }
-            else
-            {
-                tpi = atoms.atom[i].typeB;
-            }
+            const int tpi = (state == 0) ? atoms.atom[i].type : atoms.atom[i].typeB;
             typecount[tpi] += molb.nmol;
         }
     }
@@ -92,12 +85,12 @@ int gmx_mtop_num_molecules(const gmx_mtop_t& mtop)
     return numMolecules;
 }
 
-int gmx_mtop_nres(const gmx_mtop_t* mtop)
+int gmx_mtop_nres(const gmx_mtop_t& mtop)
 {
     int nres = 0;
-    for (const gmx_molblock_t& molb : mtop->molblock)
+    for (const gmx_molblock_t& molb : mtop.molblock)
     {
-        nres += molb.nmol * mtop->moltype[molb.type].atoms.nres;
+        nres += molb.nmol * mtop.moltype[molb.type].atoms.nres;
     }
     return nres;
 }
@@ -192,23 +185,23 @@ int AtomProxy::atomNumberInMol() const
     return it_->localAtomNumber_;
 }
 
-typedef struct gmx_mtop_atomloop_block
+struct gmx_mtop_atomloop_block
 {
     const gmx_mtop_t* mtop;
     size_t            mblock;
     const t_atoms*    atoms;
     int               at_local;
-} t_gmx_mtop_atomloop_block;
+};
 
-gmx_mtop_atomloop_block_t gmx_mtop_atomloop_block_init(const gmx_mtop_t* mtop)
+gmx_mtop_atomloop_block_t gmx_mtop_atomloop_block_init(const gmx_mtop_t& mtop)
 {
-    struct gmx_mtop_atomloop_block* aloop;
+    struct gmx_mtop_atomloop_block* aloop = nullptr;
 
     snew(aloop, 1);
 
-    aloop->mtop     = mtop;
+    aloop->mtop     = &mtop;
     aloop->mblock   = 0;
-    aloop->atoms    = &mtop->moltype[mtop->molblock[aloop->mblock].type].atoms;
+    aloop->atoms    = &mtop.moltype[mtop.molblock[aloop->mblock].type].atoms;
     aloop->at_local = -1;
 
     return aloop;
@@ -246,105 +239,86 @@ gmx_bool gmx_mtop_atomloop_block_next(gmx_mtop_atomloop_block_t aloop, const t_a
     return TRUE;
 }
 
-typedef struct gmx_mtop_ilistloop
+IListIterator::IListIterator(const gmx_mtop_t& mtop, size_t molblock) :
+    mtop_(&mtop), mblock_(molblock)
 {
-    const gmx_mtop_t* mtop;
-    int               mblock;
-} t_gmx_mtop_ilist;
+}
 
-gmx_mtop_ilistloop_t gmx_mtop_ilistloop_init(const gmx_mtop_t* mtop)
+IListIterator& IListIterator::operator++()
 {
-    struct gmx_mtop_ilistloop* iloop;
-
-    snew(iloop, 1);
-
-    iloop->mtop   = mtop;
-    iloop->mblock = -1;
-
-    return iloop;
+    mblock_++;
+    return *this;
 }
 
-gmx_mtop_ilistloop_t gmx_mtop_ilistloop_init(const gmx_mtop_t& mtop)
+bool IListIterator::operator==(const IListIterator& o) const
 {
-    return gmx_mtop_ilistloop_init(&mtop);
+    return mtop_ == o.mtop_ && mblock_ == o.mblock_;
 }
 
-static void gmx_mtop_ilistloop_destroy(gmx_mtop_ilistloop_t iloop)
+const InteractionLists& IListProxy::list() const
 {
-    sfree(iloop);
+    // one past the end means we want to take the
+    // intermolecular list instead.
+    if (it_->mblock_ == it_->mtop_->molblock.size())
+    {
+        return *it_->mtop_->intermolecular_ilist;
+    }
+    else
+    {
+        return it_->mtop_->moltype[it_->mtop_->molblock[it_->mblock_].type].ilist;
+    }
 }
 
-const InteractionLists* gmx_mtop_ilistloop_next(gmx_mtop_ilistloop_t iloop, int* nmol)
+int IListProxy::nmol() const
 {
-    if (iloop == nullptr)
+    // one past the end means we want to take the
+    // intermolecular list instead.
+    if (it_->mblock_ == it_->mtop_->molblock.size())
     {
-        gmx_incons("gmx_mtop_ilistloop_next called without calling gmx_mtop_ilistloop_init");
+        return 1;
     }
-
-    iloop->mblock++;
-    if (iloop->mblock >= gmx::ssize(iloop->mtop->molblock))
+    else
     {
-        if (iloop->mblock == gmx::ssize(iloop->mtop->molblock) && iloop->mtop->bIntermolecularInteractions)
-        {
-            *nmol = 1;
-            return iloop->mtop->intermolecular_ilist.get();
-        }
-
-        gmx_mtop_ilistloop_destroy(iloop);
-        return nullptr;
+        return it_->mtop_->molblock[it_->mblock_].nmol;
     }
-
-    *nmol = iloop->mtop->molblock[iloop->mblock].nmol;
-
-    return &iloop->mtop->moltype[iloop->mtop->molblock[iloop->mblock].type].ilist;
 }
-typedef struct gmx_mtop_ilistloop_all
-{
-    const gmx_mtop_t* mtop;
-    size_t            mblock;
-    int               mol;
-    int               a_offset;
-} t_gmx_mtop_ilist_all;
 
-int gmx_mtop_ftype_count(const gmx_mtop_t* mtop, int ftype)
+IListRange::IListRange(const gmx_mtop_t& mtop) : begin_(mtop), end_(mtop, mtop.molblock.size())
 {
-    gmx_mtop_ilistloop_t iloop;
-    int                  n, nmol;
+    if (mtop.bIntermolecularInteractions)
+    {
+        end_ = IListIterator(mtop, mtop.molblock.size() + 1);
+    }
+}
 
-    n = 0;
+int gmx_mtop_ftype_count(const gmx_mtop_t& mtop, int ftype)
+{
+    int n = 0;
 
-    iloop = gmx_mtop_ilistloop_init(mtop);
-    while (const InteractionLists* il = gmx_mtop_ilistloop_next(iloop, &nmol))
+    for (const IListProxy il : IListRange(mtop))
     {
-        n += nmol * (*il)[ftype].size() / (1 + NRAL(ftype));
+        n += il.nmol() * il.list()[ftype].size() / (1 + NRAL(ftype));
     }
 
-    if (mtop->bIntermolecularInteractions)
+    if (mtop.bIntermolecularInteractions)
     {
-        n += (*mtop->intermolecular_ilist)[ftype].size() / (1 + NRAL(ftype));
+        n += (*mtop.intermolecular_ilist)[ftype].size() / (1 + NRAL(ftype));
     }
 
     return n;
 }
 
-int gmx_mtop_ftype_count(const gmx_mtop_t& mtop, int ftype)
-{
-    return gmx_mtop_ftype_count(&mtop, ftype);
-}
-
 int gmx_mtop_interaction_count(const gmx_mtop_t& mtop, const int unsigned if_flags)
 {
     int n = 0;
 
-    gmx_mtop_ilistloop_t iloop = gmx_mtop_ilistloop_init(mtop);
-    int                  nmol;
-    while (const InteractionLists* il = gmx_mtop_ilistloop_next(iloop, &nmol))
+    for (const IListProxy il : IListRange(mtop))
     {
         for (int ftype = 0; ftype < F_NRE; ftype++)
         {
             if ((interaction_function[ftype].flags & if_flags) == if_flags)
             {
-                n += nmol * (*il)[ftype].size() / (1 + NRAL(ftype));
+                n += il.nmol() * il.list()[ftype].size() / (1 + NRAL(ftype));
             }
         }
     }
@@ -363,9 +337,9 @@ int gmx_mtop_interaction_count(const gmx_mtop_t& mtop, const int unsigned if_fla
     return n;
 }
 
-std::array<int, eptNR> gmx_mtop_particletype_count(const gmx_mtop_t& mtop)
+gmx::EnumerationArray<ParticleType, int> gmx_mtop_particletype_count(const gmx_mtop_t& mtop)
 {
-    std::array<int, eptNR> count = { { 0 } };
+    gmx::EnumerationArray<ParticleType, int> count = { { 0 } };
 
     for (const auto& molblock : mtop.molblock)
     {
@@ -381,7 +355,7 @@ std::array<int, eptNR> gmx_mtop_particletype_count(const gmx_mtop_t& mtop)
 
 static void atomcat(t_atoms* dest, const t_atoms* src, int copies, int maxres_renum, int* maxresnr)
 {
-    int i, j, l, size;
+    int i = 0, j = 0, l = 0, size = 0;
     int srcnr  = src->nr;
     int destnr = dest->nr;
 
@@ -429,13 +403,15 @@ static void atomcat(t_atoms* dest, const t_atoms* src, int copies, int maxres_re
     /* residue information */
     for (l = dest->nres, j = 0; (j < copies); j++, l += src->nres)
     {
-        memcpy(reinterpret_cast<char*>(&(dest->resinfo[l])), reinterpret_cast<char*>(&(src->resinfo[0])),
+        memcpy(reinterpret_cast<char*>(&(dest->resinfo[l])),
+               reinterpret_cast<char*>(&(src->resinfo[0])),
                static_cast<size_t>(src->nres * sizeof(src->resinfo[0])));
     }
 
     for (l = destnr, j = 0; (j < copies); j++, l += srcnr)
     {
-        memcpy(reinterpret_cast<char*>(&(dest->atom[l])), reinterpret_cast<char*>(&(src->atom[0])),
+        memcpy(reinterpret_cast<char*>(&(dest->atom[l])),
+               reinterpret_cast<char*>(&(src->atom[0])),
                static_cast<size_t>(srcnr * sizeof(src->atom[0])));
         memcpy(reinterpret_cast<char*>(&(dest->atomname[l])),
                reinterpret_cast<char*>(&(src->atomname[0])),
@@ -486,17 +462,20 @@ static void atomcat(t_atoms* dest, const t_atoms* src, int copies, int maxres_re
     dest->nr += copies * src->nr;
 }
 
-t_atoms gmx_mtop_global_atoms(const gmx_mtop_t* mtop)
+t_atoms gmx_mtop_global_atoms(const gmx_mtop_t& mtop)
 {
     t_atoms atoms;
 
     init_t_atoms(&atoms, 0, FALSE);
 
-    int maxresnr = mtop->maxResNumberNotRenumbered();
-    for (const gmx_molblock_t& molb : mtop->molblock)
+    int maxresnr = mtop.maxResNumberNotRenumbered();
+    for (const gmx_molblock_t& molb : mtop.molblock)
     {
-        atomcat(&atoms, &mtop->moltype[molb.type].atoms, molb.nmol,
-                mtop->maxResiduesPerMoleculeToTriggerRenumber(), &maxresnr);
+        atomcat(&atoms,
+                &mtop.moltype[molb.type].atoms,
+                molb.nmol,
+                mtop.maxResiduesPerMoleculeToTriggerRenumber(),
+                &maxresnr);
     }
 
     return atoms;
@@ -508,19 +487,17 @@ t_atoms gmx_mtop_global_atoms(const gmx_mtop_t* mtop)
 
 static void ilistcat(int ftype, InteractionList* dest, const InteractionList& src, int copies, int dnum, int snum)
 {
-    int nral, c, i, a;
-
-    nral = NRAL(ftype);
+    const int nral = NRAL(ftype);
 
     size_t destIndex = dest->iatoms.size();
     dest->iatoms.resize(dest->iatoms.size() + copies * src.size());
 
-    for (c = 0; c < copies; c++)
+    for (int c = 0; c < copies; c++)
     {
-        for (i = 0; i < src.size();)
+        for (int i = 0; i < src.size();)
         {
             dest->iatoms[destIndex++] = src.iatoms[i++];
-            for (a = 0; a < nral; a++)
+            for (int a = 0; a < nral; a++)
             {
                 dest->iatoms[destIndex++] = dnum + src.iatoms[i++];
             }
@@ -531,19 +508,17 @@ static void ilistcat(int ftype, InteractionList* dest, const InteractionList& sr
 
 static void ilistcat(int ftype, t_ilist* dest, const InteractionList& src, int copies, int dnum, int snum)
 {
-    int nral, c, i, a;
-
-    nral = NRAL(ftype);
+    const int nral = NRAL(ftype);
 
     dest->nalloc = dest->nr + copies * src.size();
     srenew(dest->iatoms, dest->nalloc);
 
-    for (c = 0; c < copies; c++)
+    for (int c = 0; c < copies; c++)
     {
-        for (i = 0; i < src.size();)
+        for (int i = 0; i < src.size();)
         {
             dest->iatoms[dest->nr++] = src.iatoms[i++];
-            for (a = 0; a < nral; a++)
+            for (int a = 0; a < nral; a++)
             {
                 dest->iatoms[dest->nr++] = dnum + src.iatoms[i++];
             }
@@ -575,18 +550,15 @@ static void resizeIParams(t_iparams** iparams, const int newSize)
 template<typename IdefType>
 static void set_posres_params(IdefType* idef, const gmx_molblock_t* molb, int i0, int a_offset)
 {
-    int        i1, i, a_molb;
-    t_iparams* ip;
-
     auto* il = &idef->il[F_POSRES];
-    i1       = il->size() / 2;
+    int   i1 = il->size() / 2;
     resizeIParams(&idef->iparams_posres, i1);
-    for (i = i0; i < i1; i++)
+    for (int i = i0; i < i1; i++)
     {
-        ip = &idef->iparams_posres[i];
+        t_iparams* ip = &idef->iparams_posres[i];
         /* Copy the force constants */
-        *ip    = getIparams(*idef, il->iatoms[i * 2]);
-        a_molb = il->iatoms[i * 2 + 1] - a_offset;
+        *ip        = getIparams(*idef, il->iatoms[i * 2]);
+        int a_molb = il->iatoms[i * 2 + 1] - a_offset;
         if (molb->posres_xA.empty())
         {
             gmx_incons("Position restraint coordinates are missing");
@@ -614,18 +586,15 @@ static void set_posres_params(IdefType* idef, const gmx_molblock_t* molb, int i0
 template<typename IdefType>
 static void set_fbposres_params(IdefType* idef, const gmx_molblock_t* molb, int i0, int a_offset)
 {
-    int        i1, i, a_molb;
-    t_iparams* ip;
-
     auto* il = &idef->il[F_FBPOSRES];
-    i1       = il->size() / 2;
+    int   i1 = il->size() / 2;
     resizeIParams(&idef->iparams_fbposres, i1);
-    for (i = i0; i < i1; i++)
+    for (int i = i0; i < i1; i++)
     {
-        ip = &idef->iparams_fbposres[i];
+        t_iparams* ip = &idef->iparams_fbposres[i];
         /* Copy the force constants */
-        *ip    = getIparams(*idef, il->iatoms[i * 2]);
-        a_molb = il->iatoms[i * 2 + 1] - a_offset;
+        *ip        = getIparams(*idef, il->iatoms[i * 2]);
+        int a_molb = il->iatoms[i * 2 + 1] - a_offset;
         if (molb->posres_xA.empty())
         {
             gmx_incons("Position restraint coordinates are missing");
@@ -715,10 +684,8 @@ static void copyIListsFromMtop(const gmx_mtop_t& mtop, IdefType* idef, bool merg
                  */
                 for (int mol = 0; mol < molb.nmol; mol++)
                 {
-                    ilistcat(ftype, &idef->il[F_CONSTR], molt.ilist[F_CONSTR], 1,
-                             destnr + mol * srcnr, srcnr);
-                    ilistcat(ftype, &idef->il[F_CONSTR], molt.ilist[F_CONSTRNC], 1,
-                             destnr + mol * srcnr, srcnr);
+                    ilistcat(ftype, &idef->il[F_CONSTR], molt.ilist[F_CONSTR], 1, destnr + mol * srcnr, srcnr);
+                    ilistcat(ftype, &idef->il[F_CONSTR], molt.ilist[F_CONSTRNC], 1, destnr + mol * srcnr, srcnr);
                 }
             }
             else if (!(mergeConstr && ftype == F_CONSTRNC))
@@ -766,7 +733,8 @@ static void copyAtomtypesFromMtop(const gmx_mtop_t& mtop, t_atomtypes* atomtypes
     if (mtop.atomtypes.atomnumber)
     {
         snew(atomtypes->atomnumber, mtop.atomtypes.nr);
-        std::copy(mtop.atomtypes.atomnumber, mtop.atomtypes.atomnumber + mtop.atomtypes.nr,
+        std::copy(mtop.atomtypes.atomnumber,
+                  mtop.atomtypes.atomnumber + mtop.atomtypes.nr,
                   atomtypes->atomnumber);
     }
     else
@@ -990,7 +958,7 @@ static void gen_t_topology(const gmx_mtop_t& mtop, bool bMergeConstr, t_topology
     copyIListsFromMtop(mtop, &top->idef, bMergeConstr);
 
     top->name                        = mtop.name;
-    top->atoms                       = gmx_mtop_global_atoms(&mtop);
+    top->atoms                       = gmx_mtop_global_atoms(mtop);
     top->mols                        = gmx_mtop_molecules_t_block(mtop);
     top->bIntermolecularInteractions = mtop.bIntermolecularInteractions;
     top->symtab                      = mtop.symtab;
@@ -1012,15 +980,15 @@ t_topology gmx_mtop_t_to_t_topology(gmx_mtop_t* mtop, bool freeMTop)
     return top;
 }
 
-std::vector<int> get_atom_index(const gmx_mtop_t* mtop)
+std::vector<int> get_atom_index(const gmx_mtop_t& mtop)
 {
 
     std::vector<int> atom_index;
-    for (const AtomProxy atomP : AtomRange(*mtop))
+    for (const AtomProxy atomP : AtomRange(mtop))
     {
         const t_atom& local = atomP.atom();
         int           index = atomP.globalAtomNumber();
-        if (local.ptype == eptAtom)
+        if (local.ptype == ParticleType::Atom)
         {
             atom_index.push_back(index);
         }
index 13c69db4781f9e7aa254b58c6cdcbf301ace7aaa..4d0e8779465b73ab3ae4c8888994b44cf0ef7d04 100644 (file)
@@ -46,7 +46,7 @@
 #include <boost/stl_interfaces/iterator_interface.hpp>
 
 #include "gromacs/topology/topology.h"
-#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/enumerationhelpers.h"
 
 struct gmx_localtop_t;
 struct t_atom;
@@ -62,7 +62,7 @@ struct t_symtab;
  * state A and 1 for state B types.  typecount should have at
  * least mtop->ffparams.atnr elements.
  */
-void gmx_mtop_count_atomtypes(const gmx_mtop_t* mtop, int state, int typecount[]);
+void gmx_mtop_count_atomtypes(const gmx_mtop_t& mtop, int state, int typecount[]);
 
 /*!\brief Returns the total number of molecules in mtop
  *
@@ -71,7 +71,7 @@ void gmx_mtop_count_atomtypes(const gmx_mtop_t* mtop, int state, int typecount[]
 int gmx_mtop_num_molecules(const gmx_mtop_t& mtop);
 
 /* Returns the total number of residues in mtop. */
-int gmx_mtop_nres(const gmx_mtop_t* mtop);
+int gmx_mtop_nres(const gmx_mtop_t& mtop);
 
 class AtomIterator;
 
@@ -157,12 +157,82 @@ private:
     AtomIterator begin_, end_;
 };
 
+class IListIterator;
+
+//! Proxy object returned from IListIterator
+class IListProxy
+{
+public:
+    //! Default constructor.
+    IListProxy(const IListIterator* it) : it_(it) {}
+    //! Access current global atom number.
+    const InteractionLists& list() const;
+    //! Access current molecule.
+    int nmol() const;
+
+private:
+    const IListIterator* it_;
+};
+
+/*! \brief
+ * Object that allows looping over all atoms in an mtop.
+ */
+class IListIterator :
+    public boost::stl_interfaces::proxy_iterator_interface<IListIterator, std::forward_iterator_tag, InteractionLists, IListProxy>
+{
+    using Base =
+            boost::stl_interfaces::proxy_iterator_interface<IListIterator, std::forward_iterator_tag, InteractionLists, IListProxy>;
+
+public:
+    //! Construct from topology.
+    explicit IListIterator(const gmx_mtop_t& mtop, size_t mblock = 0);
+
+    //! Prefix increment.
+    IListIterator& operator++();
+    using Base::   operator++;
+
+    //! Equality comparison.
+    bool operator==(const IListIterator& o) const;
+
+    //! Dereference operator. Returns proxy.
+    IListProxy operator*() const { return { this }; }
+
+private:
+    //! Global topology.
+    const gmx_mtop_t* mtop_;
+    //! Index of molecule block corresponding to the current location.
+    size_t mblock_;
+
+    friend class IListProxy;
+};
+
+
+/*! \brief
+ * Range over all interaction lists of topology.
+ *
+ * Includes the intermolecular interactions as the final element in the
+ * range if present.
+ */
+class IListRange
+{
+public:
+    //! Default constructor.
+    explicit IListRange(const gmx_mtop_t& mtop);
+    //! Iterator to begin of range.
+    IListIterator& begin() { return begin_; }
+    //! Iterator to end of range.
+    IListIterator& end() { return end_; }
+
+private:
+    IListIterator begin_, end_;
+};
+
 /* Abstract type for atom loop over atoms in all molecule blocks */
 typedef struct gmx_mtop_atomloop_block* gmx_mtop_atomloop_block_t;
 
 /* Initialize an atom loop over atoms in all molecule blocks the system.
  */
-gmx_mtop_atomloop_block_t gmx_mtop_atomloop_block_init(const gmx_mtop_t* mtop);
+gmx_mtop_atomloop_block_t gmx_mtop_atomloop_block_init(const gmx_mtop_t& mtop);
 
 /* Loop to the next atom.
  * When not at the end:
@@ -180,26 +250,6 @@ gmx_mtop_atomloop_block_t gmx_mtop_atomloop_block_init(const gmx_mtop_t* mtop);
 gmx_bool gmx_mtop_atomloop_block_next(gmx_mtop_atomloop_block_t aloop, const t_atom** atom, int* nmol);
 
 
-/* Abstract type for ilist loop over all ilists */
-typedef struct gmx_mtop_ilistloop* gmx_mtop_ilistloop_t;
-
-/* Initialize an ilist loop over all molecule types in the system. */
-gmx_mtop_ilistloop_t gmx_mtop_ilistloop_init(const gmx_mtop_t* mtop);
-
-/* Initialize an ilist loop over all molecule types in the system. */
-gmx_mtop_ilistloop_t gmx_mtop_ilistloop_init(const gmx_mtop_t& mtop);
-
-/* Loop to the next molecule,
- * When not at the end:
- *   returns a valid pointer to the next array ilist_mol[F_NRE],
- *   writes the number of molecules for this ilist in *nmol.
- * When at the end, destroys iloop and returns nullptr.
- */
-const InteractionLists* gmx_mtop_ilistloop_next(gmx_mtop_ilistloop_t iloop, int* nmol);
-
-/* Returns the total number of interactions in the system of type ftype */
-int gmx_mtop_ftype_count(const gmx_mtop_t* mtop, int ftype);
-
 /* Returns the total number of interactions in the system of type ftype */
 int gmx_mtop_ftype_count(const gmx_mtop_t& mtop, int ftype);
 
@@ -207,10 +257,10 @@ int gmx_mtop_ftype_count(const gmx_mtop_t& mtop, int ftype);
 int gmx_mtop_interaction_count(const gmx_mtop_t& mtop, int unsigned if_flags);
 
 /* Returns the count of atoms for each particle type */
-std::array<int, eptNR> gmx_mtop_particletype_count(const gmx_mtop_t& mtop);
+gmx::EnumerationArray<ParticleType, int> gmx_mtop_particletype_count(const gmx_mtop_t& mtop);
 
 /* Returns a single t_atoms struct for the whole system */
-t_atoms gmx_mtop_global_atoms(const gmx_mtop_t* mtop);
+t_atoms gmx_mtop_global_atoms(const gmx_mtop_t& mtop);
 
 
 /*! \brief
@@ -263,7 +313,7 @@ t_topology gmx_mtop_t_to_t_topology(gmx_mtop_t* mtop, bool freeMTop);
  * \param[in]  mtop Molecular topology
  * \returns Vector that will be filled with the atom indices
  */
-std::vector<int> get_atom_index(const gmx_mtop_t* mtop);
+std::vector<int> get_atom_index(const gmx_mtop_t& mtop);
 
 /*! \brief Converts a t_atoms struct to an mtop struct
  *
index 73aad6d57f7f7dd9bf4b0b4f27c2620eef0af61c..b60dd118022d512dba586ad6ef49a03d46af4534 100644 (file)
@@ -135,7 +135,9 @@ void ResidueType::addResidue(const std::string& residueName, const std::string&
             fprintf(stderr,
                     "Warning: Residue '%s' already present with type '%s' in database, ignoring "
                     "new type '%s'.\n",
-                    residueName.c_str(), (*foundIt)->residueType.c_str(), residueType.c_str());
+                    residueName.c_str(),
+                    (*foundIt)->residueType.c_str(),
+                    residueType.c_str());
         }
     }
     else
index 104101d4b777ea66dbcf7d87b27b21eff1ec7d8f..7cd5beba12ff4d834ac8f7b22643264e8d604523 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2014,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_TOPOLOGY_RESIDUETYPES_H
 #define GMX_TOPOLOGY_RESIDUETYPES_H
 
+#include <memory>
 #include <optional>
 #include <string>
 
 #include "gromacs/utility/basedefinitions.h"
-#include "gromacs/utility/classhelpers.h"
 
 struct ResidueTypeEntry;
 
@@ -111,7 +111,7 @@ private:
     //! Implementation pointer.
     class Impl;
 
-    gmx::PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 #endif
index d7432ebfaf001eb09be2c4a6fc05f1e0b9fdac3d..84ae546e074cdc9d61c38357e456e4dfda28c361 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +108,7 @@ void StringTable::printStringTableStorageToFile(FILE* fp, int indent, const char
 
 StringTable::StringTable(gmx::ISerializer* serializer)
 {
-    GMX_RELEASE_ASSERT(serializer->reading(),
-                       "Can not use writing serializer to read string table");
+    GMX_RELEASE_ASSERT(serializer->reading(), "Can not use writing serializer to read string table");
     int nr = 0;
     serializer->doInt(&nr);
     table_.resize(nr);
@@ -156,8 +155,7 @@ void StringTableEntry::serialize(gmx::ISerializer* serializer) const
 
 StringTableEntry readStringTableEntry(gmx::ISerializer* serializer, const StringTable& table)
 {
-    GMX_RELEASE_ASSERT(serializer->reading(),
-                       "Can not use writing serializer to read string index");
+    GMX_RELEASE_ASSERT(serializer->reading(), "Can not use writing serializer to read string index");
     int entry = 0;
     serializer->doInt(&entry);
     return table.at(entry);
@@ -187,7 +185,7 @@ constexpr int c_maxBufSize = 5;
  */
 static char* trim_string(const char* s, char* out, int maxlen)
 {
-    int len, i;
+    int len = 0, i = 0;
 
     if (strlen(s) > static_cast<size_t>(maxlen - 1))
     {
@@ -216,11 +214,8 @@ static char* trim_string(const char* s, char* out, int maxlen)
 
 int lookup_symtab(t_symtab* symtab, char** name)
 {
-    int       base;
-    t_symbuf* symbuf;
-
-    base   = 0;
-    symbuf = symtab->symbuf;
+    int       base   = 0;
+    t_symbuf* symbuf = symtab->symbuf;
     while (symbuf != nullptr)
     {
         const int index = name - symbuf->buf;
@@ -239,9 +234,7 @@ int lookup_symtab(t_symtab* symtab, char** name)
 
 char** get_symtab_handle(t_symtab* symtab, int name)
 {
-    t_symbuf* symbuf;
-
-    symbuf = symtab->symbuf;
+    t_symbuf* symbuf = symtab->symbuf;
     while (symbuf != nullptr)
     {
         if (name < symbuf->bufsize)
@@ -260,7 +253,7 @@ char** get_symtab_handle(t_symtab* symtab, int name)
 //! Returns a new initialized entry into the symtab linked list.
 static t_symbuf* new_symbuf()
 {
-    t_symbuf* symbuf;
+    t_symbuf* symbuf = nullptr;
 
     snew(symbuf, 1);
     symbuf->bufsize = c_maxBufSize;
@@ -279,19 +272,17 @@ static t_symbuf* new_symbuf()
  */
 static char** enter_buf(t_symtab* symtab, char* name)
 {
-    int       i;
-    t_symbuf* symbuf;
-    gmx_bool  bCont;
+    bool bCont = false;
 
     if (symtab->symbuf == nullptr)
     {
         symtab->symbuf = new_symbuf();
     }
 
-    symbuf = symtab->symbuf;
+    t_symbuf* symbuf = symtab->symbuf;
     do
     {
-        for (i = 0; (i < symbuf->bufsize); i++)
+        for (int i = 0; (i < symbuf->bufsize); i++)
         {
             if (symbuf->buf[i] == nullptr)
             {
@@ -342,7 +333,7 @@ void close_symtab(t_symtab gmx_unused* symtab) {}
 // std::list<std::vector<std::string>>> for t_symtab.
 t_symtab* duplicateSymtab(const t_symtab* symtab)
 {
-    t_symtab* copySymtab;
+    t_symtab* copySymtab = nullptr;
     snew(copySymtab, 1);
     open_symtab(copySymtab);
     t_symbuf* symbuf = symtab->symbuf;
@@ -375,21 +366,19 @@ t_symtab* duplicateSymtab(const t_symtab* symtab)
 
 void done_symtab(t_symtab* symtab)
 {
-    int       i;
-    t_symbuf *symbuf, *freeptr;
-
     close_symtab(symtab);
-    symbuf = symtab->symbuf;
+    t_symbuf* symbuf = symtab->symbuf;
     while (symbuf != nullptr)
     {
-        for (i = 0; (i < symbuf->bufsize) && (i < symtab->nr); i++)
+        int i = 0;
+        for (; (i < symbuf->bufsize) && (i < symtab->nr); i++)
         {
             sfree(symbuf->buf[i]);
         }
         symtab->nr -= i;
         sfree(symbuf->buf);
-        freeptr = symbuf;
-        symbuf  = symbuf->next;
+        t_symbuf* freeptr = symbuf;
+        symbuf            = symbuf->next;
         sfree(freeptr);
     }
     symtab->symbuf = nullptr;
@@ -401,15 +390,13 @@ void done_symtab(t_symtab* symtab)
 
 void free_symtab(t_symtab* symtab)
 {
-    t_symbuf *symbuf, *freeptr;
-
     close_symtab(symtab);
-    symbuf = symtab->symbuf;
+    t_symbuf* symbuf = symtab->symbuf;
     while (symbuf != nullptr)
     {
         symtab->nr -= std::min(symbuf->bufsize, symtab->nr);
-        freeptr = symbuf;
-        symbuf  = symbuf->next;
+        t_symbuf* freeptr = symbuf;
+        symbuf            = symbuf->next;
         sfree(freeptr);
     }
     symtab->symbuf = nullptr;
@@ -421,18 +408,16 @@ void free_symtab(t_symtab* symtab)
 
 void pr_symtab(FILE* fp, int indent, const char* title, t_symtab* symtab)
 {
-    int       i, j, nr;
-    t_symbuf* symbuf;
-
     if (available(fp, symtab, indent, title))
     {
-        indent = pr_title_n(fp, indent, title, symtab->nr);
-        i      = 0;
-        nr     = symtab->nr;
-        symbuf = symtab->symbuf;
+        indent           = pr_title_n(fp, indent, title, symtab->nr);
+        int       i      = 0;
+        int       nr     = symtab->nr;
+        t_symbuf* symbuf = symtab->symbuf;
         while (symbuf != nullptr)
         {
-            for (j = 0; (j < symbuf->bufsize) && (j < nr); j++)
+            int j = 0;
+            for (; (j < symbuf->bufsize) && (j < nr); j++)
             {
                 pr_indent(fp, indent);
                 (void)fprintf(fp, "%s[%d]=\"%s\"\n", title, i++, symbuf->buf[j]);
index 826fb86eb37284d5d9eb773279ee3048c140e427..6ffbcdff15eb6e8f41bb71d70c69769847f36db3 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,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2010,2014,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <unordered_map>
 #include <vector>
 
+#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/gmxassert.h"
 
 struct t_commrec;
diff --git a/src/gromacs/topology/tests/.clang-tidy b/src/gromacs/topology/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index f9a0d67d0ef377c1457248bc3397de159215bd05..1b8bcddb8e37c45c1ee5c454a8be8d64c2d14816 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -448,8 +448,8 @@ void LegacySymtabTest::dumpSymtab()
     int                      pos = 0;
     while (symbuf != nullptr)
     {
-        int i;
-        for (i = 0; (i < symbuf->bufsize) && (i < nr); i++)
+        int i = 0;
+        for (; (i < symbuf->bufsize) && (i < nr); i++)
         {
             symtabDump.emplace_back(formatString("Symtab[%d]=\"%s\"", pos++, symbuf->buf[i]));
         }
@@ -515,7 +515,7 @@ TEST_F(LegacySymtabTest, EmptyOnOpen)
 
 TEST_F(LegacySymtabTest, AddSingleEntry)
 {
-    auto fooSymbol = put_symtab(symtab(), "Foo");
+    auto* fooSymbol = put_symtab(symtab(), "Foo");
     ASSERT_EQ(1, symtab()->nr);
     compareSymtabLookupAndHandle(symtab(), fooSymbol);
     EXPECT_STREQ("Foo", *fooSymbol);
@@ -523,8 +523,8 @@ TEST_F(LegacySymtabTest, AddSingleEntry)
 
 TEST_F(LegacySymtabTest, AddTwoDistinctEntries)
 {
-    auto fooSymbol = put_symtab(symtab(), "Foo");
-    auto barSymbol = put_symtab(symtab(), "Bar");
+    auto* fooSymbol = put_symtab(symtab(), "Foo");
+    auto* barSymbol = put_symtab(symtab(), "Bar");
     ASSERT_EQ(2, symtab()->nr);
 
     compareSymtabLookupAndHandle(symtab(), fooSymbol);
@@ -538,8 +538,8 @@ TEST_F(LegacySymtabTest, AddTwoDistinctEntries)
 
 TEST_F(LegacySymtabTest, TryToAddDuplicates)
 {
-    auto fooSymbol = put_symtab(symtab(), "Foo");
-    auto barSymbol = put_symtab(symtab(), "Bar");
+    auto* fooSymbol = put_symtab(symtab(), "Foo");
+    auto* barSymbol = put_symtab(symtab(), "Bar");
     ASSERT_EQ(2, symtab()->nr);
 
     compareSymtabLookupAndHandle(symtab(), fooSymbol);
@@ -551,7 +551,7 @@ TEST_F(LegacySymtabTest, TryToAddDuplicates)
     EXPECT_STREQ("Bar", *barSymbol);
 
     // Insert a duplicate element
-    auto anotherFooSymbol = put_symtab(symtab(), "Foo");
+    auto* anotherFooSymbol = put_symtab(symtab(), "Foo");
     ASSERT_EQ(2, symtab()->nr);
 
     // Check for correct post-conditions
@@ -582,7 +582,7 @@ TEST_F(LegacySymtabTest, AddLargeNumberOfEntries)
         compareSymtabLookupAndHandle(symtab(), symbolsAdded[i]);
     }
     // Add something unrelated and check that indices still work afterward.
-    auto foobarSymbol = put_symtab(symtab(), "foobar");
+    auto* foobarSymbol = put_symtab(symtab(), "foobar");
     ASSERT_EQ(numStringsToAdd + 1, symtab()->nr);
     for (int i = 0; i < numStringsToAdd; ++i)
     {
@@ -608,7 +608,7 @@ TEST_F(LegacySymtabTest, NoDuplicatesInLargeTable)
     ASSERT_EQ(halfOfStringsToAdd, symtab()->nr);
 
     // We now try to mess around in the symtab.
-    auto bazSymbol = put_symtab(symtab(), "baz");
+    auto* bazSymbol = put_symtab(symtab(), "baz");
     ASSERT_EQ(halfOfStringsToAdd + 1, symtab()->nr);
     compareSymtabLookupAndHandle(symtab(), bazSymbol);
 
index 6c9bfc1d60d2e8209947590076dd281aa770963d..791bd8bc7373e7e3d98e700d90cd4ef2b4d65930 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +37,7 @@
  */
 #include "gmxpre.h"
 
+#include "gromacs/utility/enumerationhelpers.h"
 #include "topology.h"
 
 #include <cstdio>
 #include "gromacs/utility/strconvert.h"
 #include "gromacs/utility/txtdump.h"
 
-static gmx::EnumerationArray<SimulationAtomGroupType, const char*> c_simulationAtomGroupTypeShortNames = {
-    { "T-Coupling", "Energy Mon.", "Acceleration", "Freeze", "User1", "User2", "VCM",
-      "Compressed X", "Or. Res. Fit", "QMMM" }
-};
-
 const char* shortName(SimulationAtomGroupType type)
 {
-    return c_simulationAtomGroupTypeShortNames[type];
+    constexpr gmx::EnumerationArray<SimulationAtomGroupType, const char*> sc_simulationAtomGroupTypeShortNames = {
+        { "T-Coupling",
+          "Energy Mon.",
+          "Acc. not used",
+          "Freeze",
+          "User1",
+          "User2",
+          "VCM",
+          "Compressed X",
+          "Or. Res. Fit",
+          "QMMM" }
+    };
+
+    return sc_simulationAtomGroupTypeShortNames[type];
 }
 
 void init_top(t_topology* top)
@@ -279,7 +288,10 @@ static void pr_grps(FILE* fp, const char* title, gmx::ArrayRef<const AtomGroupIn
     int index = 0;
     for (const auto& group : grps)
     {
-        fprintf(fp, "%s[%-12s] nr=%zu, name=[", title, c_simulationAtomGroupTypeShortNames[index],
+        fprintf(fp,
+                "%s[%-12s] nr=%zu, name=[",
+                title,
+                shortName(static_cast<SimulationAtomGroupType>(index)),
                 group.size());
         for (const auto& entry : group)
         {
@@ -293,14 +305,18 @@ static void pr_grps(FILE* fp, const char* title, gmx::ArrayRef<const AtomGroupIn
 static void pr_groups(FILE* fp, int indent, const SimulationGroups& groups, gmx_bool bShowNumbers)
 {
     pr_grps(fp, "grp", groups.groups, const_cast<char***>(groups.groupNames.data()));
-    pr_strings(fp, indent, "grpname", const_cast<char***>(groups.groupNames.data()),
-               groups.groupNames.size(), bShowNumbers);
+    pr_strings(fp,
+               indent,
+               "grpname",
+               const_cast<char***>(groups.groupNames.data()),
+               groups.groupNames.size(),
+               bShowNumbers);
 
     pr_indent(fp, indent);
     fprintf(fp, "groups          ");
-    for (const auto& group : c_simulationAtomGroupTypeShortNames)
+    for (const auto group : gmx::EnumerationWrapper<SimulationAtomGroupType>{})
     {
-        printf(" %5.5s", group);
+        printf(" %5.5s", shortName(group));
     }
     printf("\n");
 
@@ -332,7 +348,8 @@ static void pr_groups(FILE* fp, int indent, const SimulationGroups& groups, gmx_
             fprintf(fp, "groupnr[%5d] =", i);
             for (auto group : keysOf(groups.groups))
             {
-                fprintf(fp, "  %3d ",
+                fprintf(fp,
+                        "  %3d ",
                         !groups.groupNumbers[group].empty() ? groups.groupNumbers[group][i] : 0);
             }
             fprintf(fp, "\n");
@@ -349,17 +366,21 @@ static void pr_moltype(FILE*                 fp,
                        gmx_bool              bShowNumbers,
                        gmx_bool              bShowParameters)
 {
-    int j;
-
     indent = pr_title_n(fp, indent, title, n);
     pr_indent(fp, indent);
     fprintf(fp, "name=\"%s\"\n", *(molt->name));
     pr_atoms(fp, indent, "atoms", &(molt->atoms), bShowNumbers);
     pr_listoflists(fp, indent, "excls", &molt->excls, bShowNumbers);
-    for (j = 0; (j < F_NRE); j++)
+    for (int j = 0; (j < F_NRE); j++)
     {
-        pr_ilist(fp, indent, interaction_function[j].longname, ffparams->functype.data(),
-                 molt->ilist[j], bShowNumbers, bShowParameters, ffparams->iparams.data());
+        pr_ilist(fp,
+                 indent,
+                 interaction_function[j].longname,
+                 ffparams->functype.data(),
+                 molt->ilist[j],
+                 bShowNumbers,
+                 bShowParameters,
+                 ffparams->iparams.data());
     }
 }
 
@@ -399,23 +420,26 @@ void pr_mtop(FILE* fp, int indent, const char* title, const gmx_mtop_t* mtop, gm
         {
             pr_molblock(fp, indent, "molblock", &mtop->molblock[mb], mb, mtop->moltype);
         }
-        pr_str(fp, indent, "bIntermolecularInteractions",
-               gmx::boolToString(mtop->bIntermolecularInteractions));
+        pr_str(fp, indent, "bIntermolecularInteractions", gmx::boolToString(mtop->bIntermolecularInteractions));
         if (mtop->bIntermolecularInteractions)
         {
             for (int j = 0; j < F_NRE; j++)
             {
-                pr_ilist(fp, indent, interaction_function[j].longname,
-                         mtop->ffparams.functype.data(), (*mtop->intermolecular_ilist)[j],
-                         bShowNumbers, bShowParameters, mtop->ffparams.iparams.data());
+                pr_ilist(fp,
+                         indent,
+                         interaction_function[j].longname,
+                         mtop->ffparams.functype.data(),
+                         (*mtop->intermolecular_ilist)[j],
+                         bShowNumbers,
+                         bShowParameters,
+                         mtop->ffparams.iparams.data());
             }
         }
         pr_ffparams(fp, indent, "ffparams", &(mtop->ffparams), bShowNumbers);
         pr_atomtypes(fp, indent, "atomtypes", &(mtop->atomtypes), bShowNumbers);
         for (size_t mt = 0; mt < mtop->moltype.size(); mt++)
         {
-            pr_moltype(fp, indent, "moltype", &mtop->moltype[mt], mt, &mtop->ffparams, bShowNumbers,
-                       bShowParameters);
+            pr_moltype(fp, indent, "moltype", &mtop->moltype[mt], mt, &mtop->ffparams, bShowNumbers, bShowParameters);
         }
         pr_groups(fp, indent, mtop->groups, bShowNumbers);
     }
@@ -431,8 +455,7 @@ void pr_top(FILE* fp, int indent, const char* title, const t_topology* top, gmx_
         pr_atoms(fp, indent, "atoms", &(top->atoms), bShowNumbers);
         pr_atomtypes(fp, indent, "atomtypes", &(top->atomtypes), bShowNumbers);
         pr_block(fp, indent, "mols", &top->mols, bShowNumbers);
-        pr_str(fp, indent, "bIntermolecularInteractions",
-               gmx::boolToString(top->bIntermolecularInteractions));
+        pr_str(fp, indent, "bIntermolecularInteractions", gmx::boolToString(top->bIntermolecularInteractions));
         pr_idef(fp, indent, "idef", &top->idef, bShowNumbers, bShowParameters);
     }
 }
@@ -445,11 +468,8 @@ static void cmp_iparm(FILE*            fp,
                       real             relativeTolerance,
                       real             absoluteTolerance)
 {
-    int      i;
-    gmx_bool bDiff;
-
-    bDiff = FALSE;
-    for (i = 0; i < MAXFORCEPARAM && !bDiff; i++)
+    bool bDiff = false;
+    for (int i = 0; i < MAXFORCEPARAM && !bDiff; i++)
     {
         bDiff = !equal_real(ip1.generic.buf[i], ip2.generic.buf[i], relativeTolerance, absoluteTolerance);
     }
@@ -464,13 +484,10 @@ static void cmp_iparm(FILE*            fp,
 
 static void cmp_iparm_AB(FILE* fp, const char* s, t_functype ft, const t_iparams& ip1, real relativeTolerance, real absoluteTolerance)
 {
-    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;
+    int p0    = 0;
+    int nrfpA = interaction_function[ft].nrfpA;
+    int nrfpB = interaction_function[ft].nrfpB;
     if (ft == F_PDIHS)
     {
         nrfpB = 2;
@@ -481,11 +498,11 @@ static void cmp_iparm_AB(FILE* fp, const char* s, t_functype ft, const t_iparams
         p0    = 1;
         nrfpB = 1;
     }
-    bDiff = FALSE;
-    for (i = 0; i < nrfpB && !bDiff; i++)
+    bool bDiff = false;
+    for (int i = 0; i < nrfpB && !bDiff; i++)
     {
-        bDiff = !equal_real(ip1.generic.buf[p0 + i], ip1.generic.buf[nrfpA + i], relativeTolerance,
-                            absoluteTolerance);
+        bDiff = !equal_real(
+                ip1.generic.buf[p0 + i], ip1.generic.buf[nrfpA + i], relativeTolerance, absoluteTolerance);
     }
     if (bDiff)
     {
@@ -511,14 +528,11 @@ static void cmp_cmap(FILE* fp, const gmx_cmap_t* cmap1, const gmx_cmap_t* cmap2,
     {
         for (size_t g = 0; g < cmap1->cmapdata.size(); g++)
         {
-            int i;
-
             fprintf(fp, "comparing cmap %zu\n", g);
 
-            for (i = 0; i < 4 * cmap1->grid_spacing * cmap1->grid_spacing; i++)
+            for (int 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],
-                         relativeTolerance, absoluteTolerance);
+                cmp_real(fp, "", i, cmap1->cmapdata[g].cmap[i], cmap2->cmapdata[g].cmap[i], relativeTolerance, absoluteTolerance);
             }
         }
     }
@@ -555,8 +569,7 @@ static void compareFfparams(FILE*                 fp,
         std::string buf = gmx::formatString("ffparams->functype[%d]", i);
         cmp_int(fp, buf.c_str(), i, ff1.functype[i], ff2.functype[i]);
         buf = gmx::formatString("ffparams->iparams[%d]", i);
-        cmp_iparm(fp, buf.c_str(), ff1.functype[i], ff1.iparams[i], ff2.iparams[i],
-                  relativeTolerance, absoluteTolerance);
+        cmp_iparm(fp, buf.c_str(), ff1.functype[i], ff1.iparams[i], ff2.iparams[i], relativeTolerance, absoluteTolerance);
     }
 }
 
@@ -679,11 +692,13 @@ void compareMtop(FILE* fp, const gmx_mtop_t& mtop1, const gmx_mtop_t& mtop2, rea
     fprintf(fp, "comparing mtop topology\n");
     cmp_str(fp, "Name", -1, *mtop1.name, *mtop2.name);
     cmp_int(fp, "natoms", -1, mtop1.natoms, mtop2.natoms);
-    cmp_int(fp, "maxres_renum", -1, mtop1.maxResiduesPerMoleculeToTriggerRenumber(),
+    cmp_int(fp,
+            "maxres_renum",
+            -1,
+            mtop1.maxResiduesPerMoleculeToTriggerRenumber(),
             mtop2.maxResiduesPerMoleculeToTriggerRenumber());
     cmp_int(fp, "maxresnr", -1, mtop1.maxResNumberNotRenumbered(), mtop2.maxResNumberNotRenumbered());
-    cmp_bool(fp, "bIntermolecularInteractions", -1, mtop1.bIntermolecularInteractions,
-             mtop2.bIntermolecularInteractions);
+    cmp_bool(fp, "bIntermolecularInteractions", -1, mtop1.bIntermolecularInteractions, mtop2.bIntermolecularInteractions);
     cmp_bool(fp, "haveMoleculeIndices", -1, mtop1.haveMoleculeIndices, mtop2.haveMoleculeIndices);
 
     compareFfparams(fp, mtop1.ffparams, mtop2.ffparams, relativeTolerance, absoluteTolerance);
@@ -692,8 +707,8 @@ void compareMtop(FILE* fp, const gmx_mtop_t& mtop1, const gmx_mtop_t& mtop2, rea
     compareInteractionLists(fp, mtop1.intermolecular_ilist.get(), mtop2.intermolecular_ilist.get());
     compareAtomtypes(fp, mtop1.atomtypes, mtop2.atomtypes);
     compareAtomGroups(fp, mtop1.groups, mtop2.groups, mtop1.natoms, mtop2.natoms);
-    compareIntermolecularExclusions(fp, mtop1.intermolecularExclusionGroup,
-                                    mtop2.intermolecularExclusionGroup);
+    compareIntermolecularExclusions(
+            fp, mtop1.intermolecularExclusionGroup, mtop2.intermolecularExclusionGroup);
     compareBlockIndices(fp, mtop1.moleculeBlockIndices, mtop2.moleculeBlockIndices);
 }
 
@@ -717,19 +732,24 @@ void compareAtomGroups(FILE* fp, const SimulationGroups& g0, const SimulationGro
             for (gmx::index j = 0; j < gmx::ssize(g0.groups[group]); j++)
             {
                 buf = gmx::formatString("grps[%d].name[%zd]", static_cast<int>(group), j);
-                cmp_str(fp, buf.c_str(), -1, *g0.groupNames[g0.groups[group][j]],
+                cmp_str(fp,
+                        buf.c_str(),
+                        -1,
+                        *g0.groupNames[g0.groups[group][j]],
                         *g1.groupNames[g1.groups[group][j]]);
             }
         }
-        cmp_int(fp, "ngrpnr", static_cast<int>(group), g0.numberOfGroupNumbers(group),
+        cmp_int(fp,
+                "ngrpnr",
+                static_cast<int>(group),
+                g0.numberOfGroupNumbers(group),
                 g1.numberOfGroupNumbers(group));
         if (g0.numberOfGroupNumbers(group) == g1.numberOfGroupNumbers(group) && natoms0 == natoms1
             && (!g0.groupNumbers[group].empty() || !g1.groupNumbers[group].empty()))
         {
             for (int j = 0; j < natoms0; j++)
             {
-                cmp_int(fp, c_simulationAtomGroupTypeShortNames[group], j,
-                        getGroupType(g0, group, j), getGroupType(g1, group, j));
+                cmp_int(fp, shortName(group), j, getGroupType(g0, group, j), getGroupType(g1, group, j));
             }
         }
     }
index cda4ec7e942e5bba57d907e69566725d709c82f1..ed809ab4181799f15918b6066ffc08e30ed85b2f 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2011,2014,2015,2016,2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +56,7 @@ enum class SimulationAtomGroupType : int
 {
     TemperatureCoupling,
     EnergyOutput,
-    Acceleration,
+    AccelerationUnused,
     Freeze,
     User1,
     User2,
index 5971a45094ed2eeb266ca86d9df273603156e070..8270ca0307df18a937f245025a11c05ded571df4 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 static gmx_bool ip_pert(int ftype, const t_iparams* ip)
 {
-    gmx_bool bPert;
-    int      i;
-
     if (NRFPB(ftype) == 0)
     {
         return FALSE;
     }
 
+    bool bPert = false;
     switch (ftype)
     {
         case F_BONDS:
@@ -88,7 +86,7 @@ static gmx_bool ip_pert(int ftype, const t_iparams* ip)
             break;
         case F_RBDIHS:
             bPert = FALSE;
-            for (i = 0; i < NR_RBDIHS; i++)
+            for (int i = 0; i < NR_RBDIHS; i++)
             {
                 if (ip->rbdihs.rbcA[i] != ip->rbdihs.rbcB[i])
                 {
@@ -102,7 +100,7 @@ static gmx_bool ip_pert(int ftype, const t_iparams* ip)
         case F_TABDIHS: bPert = (ip->tab.kA != ip->tab.kB); break;
         case F_POSRES:
             bPert = FALSE;
-            for (i = 0; i < DIM; i++)
+            for (int i = 0; i < DIM; i++)
             {
                 if (ip->posres.pos0A[i] != ip->posres.pos0B[i] || ip->posres.fcA[i] != ip->posres.fcB[i])
                 {
@@ -121,10 +119,12 @@ static gmx_bool ip_pert(int ftype, const t_iparams* ip)
         case F_RESTRANGLES:
         case F_RESTRDIHS:
         case F_CBTDIHS:
-            gmx_fatal(FARGS, "Function type %s does not support currentely free energy calculations",
+            gmx_fatal(FARGS,
+                      "Function type %s does not support currentely free energy calculations",
                       interaction_function[ftype].longname);
         default:
-            gmx_fatal(FARGS, "Function type %s not implemented in ip_pert",
+            gmx_fatal(FARGS,
+                      "Function type %s not implemented in ip_pert",
                       interaction_function[ftype].longname);
     }
 
@@ -178,10 +178,6 @@ gmx_bool gmx_mtop_bondeds_free_energy(const gmx_mtop_t* mtop)
 
 void gmx_sort_ilist_fe(InteractionDefinitions* idef, const real* qA, const real* qB)
 {
-    int      ftype, nral, i, ic, ib, a;
-    t_iatom* iabuf;
-    int      iabuf_nalloc;
-
     if (qB == nullptr)
     {
         qB = qA;
@@ -189,19 +185,19 @@ void gmx_sort_ilist_fe(InteractionDefinitions* idef, const real* qA, const real*
 
     bool havePerturbedInteractions = false;
 
-    iabuf_nalloc = 0;
-    iabuf        = nullptr;
+    int      iabuf_nalloc = 0;
+    t_iatom* iabuf        = nullptr;
 
-    for (ftype = 0; ftype < F_NRE; ftype++)
+    for (int ftype = 0; ftype < F_NRE; ftype++)
     {
         if (interaction_function[ftype].flags & IF_BOND)
         {
             InteractionList* ilist  = &idef->il[ftype];
             int*             iatoms = ilist->iatoms.data();
-            nral                    = NRAL(ftype);
-            ic                      = 0;
-            ib                      = 0;
-            i                       = 0;
+            const int        nral   = NRAL(ftype);
+            int              ic     = 0;
+            int              ib     = 0;
+            int              i      = 0;
             while (i < ilist->size())
             {
                 /* Check if this interaction is perturbed */
@@ -213,7 +209,7 @@ void gmx_sort_ilist_fe(InteractionDefinitions* idef, const real* qA, const real*
                         iabuf_nalloc = over_alloc_large(ib + 1 + nral);
                         srenew(iabuf, iabuf_nalloc);
                     }
-                    for (a = 0; a < 1 + nral; a++)
+                    for (int a = 0; a < 1 + nral; a++)
                     {
                         iabuf[ib++] = iatoms[i++];
                     }
@@ -223,7 +219,7 @@ void gmx_sort_ilist_fe(InteractionDefinitions* idef, const real* qA, const real*
                 else
                 {
                     /* Copy in place */
-                    for (a = 0; a < 1 + nral; a++)
+                    for (int a = 0; a < 1 + nral; a++)
                     {
                         iatoms[ic++] = iatoms[i++];
                     }
@@ -233,7 +229,7 @@ void gmx_sort_ilist_fe(InteractionDefinitions* idef, const real* qA, const real*
             idef->numNonperturbedInteractions[ftype] = ic;
 
             /* Copy the buffer with perturbed interactions to the ilist */
-            for (a = 0; a < ib; a++)
+            for (int a = 0; a < ib; a++)
             {
                 iatoms[ic++] = iabuf[a];
             }
@@ -241,8 +237,11 @@ void gmx_sort_ilist_fe(InteractionDefinitions* idef, const real* qA, const real*
             if (debug)
             {
                 const int numNonperturbed = idef->numNonperturbedInteractions[ftype];
-                fprintf(debug, "%s non-pert %d pert %d\n", interaction_function[ftype].longname,
-                        numNonperturbed, ilist->size() - numNonperturbed);
+                fprintf(debug,
+                        "%s non-pert %d pert %d\n",
+                        interaction_function[ftype].longname,
+                        numNonperturbed,
+                        ilist->size() - numNonperturbed);
             }
         }
     }
index af69089313949cde1dfeca2fc0d1fdbde8596075..2a3c613419f6a82ce2619394ef23e1f18d0ac131 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2015,2016,2018,2019, by the GROMACS development team, led by
+# Copyright (c) 2015,2016,2018,2019,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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(
-    energyframe.cpp
-    trajectoryframe.cpp
-    )
+# Set up the module library
+add_library(trajectory INTERFACE)
+file(GLOB TRAJECTORY_SOURCES *.cpp)
+set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${TRAJECTORY_SOURCES} PARENT_SCOPE)
+
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(trajectory PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(trajectory PUBLIC
+target_include_directories(trajectory INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(trajectory PUBLIC
+target_link_libraries(trajectory INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when trajectory is an OBJECT target
+#target_link_libraries(trajectory PUBLIC legacy_api)
+#target_link_libraries(trajectory PRIVATE common)
+
+# Module dependencies
+# trajectory interfaces convey transitive dependence on these modules.
+#target_link_libraries(trajectory PUBLIC
+target_link_libraries(trajectory INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(trajectory PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(trajectory PRIVATE legacy_modules)
 
 if(GMX_INSTALL_LEGACY_API)
   install(FILES trajectoryframe.h
index 41be658f4fcff4da9b675eba188a8423c406c327..ea48eb29cf5bc5b8f25e6ce81931b920adf0d5b2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,13 +57,15 @@ EnergyFrame::EnergyFrame(const t_enxframe& enxframe, const std::map<std::string,
     step_(enxframe.step),
     time_(enxframe.t)
 {
-    for (auto& index : indicesOfEnergyFields)
+    for (const auto& index : indicesOfEnergyFields)
     {
         if (index.second >= enxframe.nre)
         {
             GMX_THROW(InternalError(formatString(
                     "Index %d for energy %s not present in energy frame with %d energies",
-                    index.second, index.first.c_str(), enxframe.nre)));
+                    index.second,
+                    index.first.c_str(),
+                    enxframe.nre)));
         }
         values_[index.first] = enxframe.ener[index.second].e;
     }
index b37f14d4c8c49c03ca4031b0cf496bb66c7487c5..2f9609bd395be3945717a79a2c86bb19da1b01a0 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ struct t_enxframe
     int64_t     step;         /* MD step                                    */
     int64_t     nsteps;       /* The number of steps between frames            */
     double      dt;           /* The MD time step                              */
-    int         nsum;         /* The number of terms for the sums in ener      */
+    int         nsum;         /* The number of terms for the sums in energyGroupPairTerms      */
     int         nre;          /* Number of energies                         */
     int         e_size;       /* Size (in bytes) of energies                */
-    int         e_alloc;      /* Allocated size (in elements) of ener          */
+    int         e_alloc;      /* Allocated size (in elements) of energyGroupPairTerms          */
     t_energy*   ener;         /* The energies                                  */
     int         nblock;       /* Number of following energy blocks             */
     t_enxblock* block;        /* The blocks                                    */
index 9065899640aa867f90ee23c6fbf5f83008f016a2..09ac59bfe47f8eb941880345b5f6f9a79c4979f0 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 up the module library
+add_library(trajectoryanalysis INTERFACE)
 file(GLOB TRAJECTORYANALYSIS_SOURCES *.cpp modules/*.cpp)
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${TRAJECTORYANALYSIS_SOURCES} PARENT_SCOPE)
 
+# Source files have the following dependencies on library infrastructure.
+#target_link_libraries(trajectoryanalysis PRIVATE
+#                      common
+#                      legacy_modules
+#)
+
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(trajectoryanalysis PUBLIC
+target_include_directories(trajectoryanalysis INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(trajectoryanalysis PUBLIC
+target_link_libraries(trajectoryanalysis INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when trajectoryanalysis is an OBJECT target
+#target_link_libraries(trajectoryanalysis PUBLIC legacy_api)
+#target_link_libraries(trajectoryanalysis PRIVATE common)
+
+# Module dependencies
+# trajectoryanalysis interfaces convey transitive dependence on these modules.
+#target_link_libraries(trajectoryanalysis PUBLIC
+target_link_libraries(trajectoryanalysis INTERFACE
+                      utility
+                      )
+# Source files have the following private module dependencies.
+#target_link_libraries(trajectoryanalysis PRIVATE NOTHING)
+# TODO: Explicitly link specific modules.
+#target_link_libraries(trajectoryanalysis PRIVATE legacy_modules)
+
 if(GMX_INSTALL_LEGACY_API)
     install(FILES
            analysismodule.h
index 263fa1cbe88be0e3acb6e1cb4ca933f3b369d97b..af144432152559b621956703d82ee03f15a8ffd6 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/analysisdata/analysisdata.h"
 #include "gromacs/selection/selection.h"
+#include "gromacs/selection/selectioncollection.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/stringutil.h"
 
 namespace gmx
 {
@@ -185,8 +187,11 @@ AnalysisDataHandle TrajectoryAnalysisModuleData::dataHandle(const AnalysisData&
 
 Selection TrajectoryAnalysisModuleData::parallelSelection(const Selection& selection)
 {
-    // TODO: Implement properly.
-    return selection;
+    std::optional<Selection> sel = impl_->selections_.selection(selection.name());
+    // Selections should never be missing in an analysis module, so this is an internal consistency check.
+    GMX_RELEASE_ASSERT(sel.has_value(),
+                       gmx::formatString("invalid selection %s", selection.name()).c_str());
+    return sel.value();
 }
 
 
index 7462f19badb02604ef287afe0524015bc4c2d57e..e78232f954300ec8ff11ef1af5e0106ead948c8d 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -50,7 +50,6 @@
 #include <vector>
 
 #include "gromacs/selection/selection.h" // For gmx::SelectionList
-#include "gromacs/utility/classhelpers.h"
 
 struct t_pbc;
 struct t_trxframe;
@@ -130,7 +129,7 @@ public:
      *
      * Does not throw.
      */
-    static Selection parallelSelection(const Selection& selection);
+    Selection parallelSelection(const Selection& selection);
     /*! \brief
      * Returns a set of selection that corresponds to the given selections.
      *
@@ -140,7 +139,7 @@ public:
      *
      * \see parallelSelection()
      */
-    static SelectionList parallelSelections(const SelectionList& selections);
+    SelectionList parallelSelections(const SelectionList& selections);
 
 protected:
     /*! \brief
@@ -175,7 +174,7 @@ protected:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 //! Smart pointer to manage a TrajectoryAnalysisModuleData object.
@@ -483,7 +482,7 @@ protected:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     /*! \brief
      * Needed to access the registered analysis data sets.
index e3ac3799a8e1c74e4d9d7e26deeada5dde124ebf..7e7d47e591cb44db30ad60b9e077f5a03a7b65e2 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_TRAJECTORYANALYSIS_ANALYSISSETTINGS_H
 #define GMX_TRAJECTORYANALYSIS_ANALYSISSETTINGS_H
 
+#include <memory>
 #include <string>
 
 #include "gromacs/options/timeunitmanager.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
@@ -238,7 +238,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     friend class TrajectoryAnalysisRunnerCommon;
 };
index b8b9d85844bf1648915cc07a47c6fbf57e25a26e..6e5422b5e6374e0d59172bc0742d8ac9b05a8f61 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2016,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +52,7 @@
 #include "modules/distance.h"
 #include "modules/extract_cluster.h"
 #include "modules/freevolume.h"
+#include "modules/msd.h"
 #include "modules/pairdist.h"
 #include "modules/rdf.h"
 #include "modules/sasa.h"
@@ -96,6 +97,7 @@ void registerTrajectoryAnalysisModules(CommandLineModuleManager* manager)
     registerModule<DistanceInfo>(manager, group);
     registerModule<ExtractClusterInfo>(manager, group);
     registerModule<FreeVolumeInfo>(manager, group);
+    registerModule<MsdInfo>(manager, group);
     registerModule<PairDistanceInfo>(manager, group);
     registerModule<RdfInfo>(manager, group);
     registerModule<SasaInfo>(manager, group);
index d4a8f18c0261f0f3dda03ee1a3b381e04b89abab..e94d5afd13c6cd1ec6766d66998eb2e73cc84c18 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2011-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/analysisdata/modules/histogram.h"
 #include "gromacs/analysisdata/modules/plot.h"
 #include "gromacs/math/units.h"
+#include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/options/filenameoption.h"
@@ -64,6 +65,7 @@
 #include "gromacs/trajectory/trajectoryframe.h"
 #include "gromacs/trajectoryanalysis/analysissettings.h"
 #include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
@@ -258,8 +260,9 @@ enum class Group2Type : int
     Count
 };
 //! String values corresponding to Group1Type.
-const EnumerationArray<Group1Type, const char*> c_group1TypeEnumNames = { { "angle", "dihedral",
-                                                                            "vector", "plane" } };
+const EnumerationArray<Group1Type, const char*> c_group1TypeEnumNames = {
+    { "angle", "dihedral", "vector", "plane" }
+};
 //! String values corresponding to Group2Type.
 const EnumerationArray<Group2Type, const char*> c_group2TypeEnumNames = {
     { "none", "vector", "plane", "t0", "z", "sphnorm" }
@@ -381,19 +384,19 @@ void Angle::initOptions(IOptionsContainer* options, TrajectoryAnalysisSettings*
     settings->setHelpText(desc);
 
     options->addOption(FileNameOption("oav")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnAverage_)
                                .defaultBasename("angaver")
                                .description("Average angles as a function of time"));
     options->addOption(FileNameOption("oall")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnAll_)
                                .defaultBasename("angles")
                                .description("All angles as a function of time"));
     options->addOption(FileNameOption("oh")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnHistogram_)
                                .defaultBasename("anghist")
@@ -489,7 +492,8 @@ void Angle::initFromSelections(const SelectionList& sel1, const SelectionList& s
         {
             GMX_THROW(InconsistentInputError(formatString(
                     "Number of positions in selection %d in the first group not divisible by %d",
-                    static_cast<int>(g + 1), natoms1_)));
+                    static_cast<int>(g + 1),
+                    natoms1_)));
         }
         const int angleCount1 = posCount1 / natoms1_;
         int       angleCount  = angleCount1;
@@ -502,7 +506,8 @@ void Angle::initFromSelections(const SelectionList& sel1, const SelectionList& s
                 GMX_THROW(InconsistentInputError(
                         formatString("Number of positions in selection %d in the second group not "
                                      "divisible by %d",
-                                     static_cast<int>(g + 1), natoms2_)));
+                                     static_cast<int>(g + 1),
+                                     natoms2_)));
             }
             if (g2type_ == Group2Type::SphereNormal && posCount2 != 1)
             {
@@ -684,8 +689,8 @@ void calc_vec(int natoms, rvec x[], t_pbc* pbc, rvec xout, rvec cout)
 void Angle::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, TrajectoryAnalysisModuleData* pdata)
 {
     AnalysisDataHandle   dh   = pdata->dataHandle(angles_);
-    const SelectionList& sel1 = TrajectoryAnalysisModuleData::parallelSelections(sel1_);
-    const SelectionList& sel2 = TrajectoryAnalysisModuleData::parallelSelections(sel2_);
+    const SelectionList& sel1 = pdata->parallelSelections(sel1_);
+    const SelectionList& sel2 = pdata->parallelSelections(sel2_);
 
     checkSelections(sel1, sel2);
 
@@ -725,7 +730,7 @@ void Angle::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, TrajectoryA
             // read), but unsurprisingly the static analyzer chokes a bit on that.
             clear_rvecs(4, x);
 
-            real angle;
+            real angle = 0;
             // checkSelections() ensures that this reflects all the involved
             // positions.
             const bool bPresent = iter1.currentValuesSelected() && iter2.currentValuesSelected();
@@ -805,7 +810,7 @@ void Angle::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, TrajectoryA
                     break;
                 default: GMX_THROW(InternalError("invalid -g1 value"));
             }
-            dh.setPoint(n, angle * RAD2DEG, bPresent);
+            dh.setPoint(n, angle * gmx::c_rad2Deg, bPresent);
         }
     }
     dh.finishFrame();
index 9673a8aaec87f68964cb9a7239a3af7fad02e84a..67e908622a537db1f3930286df595c4ec0606b59 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -111,7 +111,7 @@ void ConvertTrj::initOptions(IOptionsContainer* options, TrajectoryAnalysisSetti
             "Selection of particles to write to the file"));
 
     options->addOption(FileNameOption("o")
-                               .filetype(eftTrajectory)
+                               .filetype(OptionFileType::Trajectory)
                                .outputFile()
                                .store(&name_)
                                .defaultBasename("trajout")
@@ -136,7 +136,9 @@ void ConvertTrj::optionsFinished(TrajectoryAnalysisSettings* settings)
 
 void ConvertTrj::initAnalysis(const TrajectoryAnalysisSettings& /*settings*/, const TopologyInformation& top)
 {
-    output_ = createTrajectoryFrameWriter(top.mtop(), sel_, name_,
+    output_ = createTrajectoryFrameWriter(top.mtop(),
+                                          sel_,
+                                          name_,
                                           top.hasTopology() ? top.copyAtoms() : nullptr,
                                           requirementsBuilder_.process());
 }
index 6acf73ab1d2a344614b13634fa0c0ed342b42014..604a37ea7c36d8326c6aa6cad29c921aab1ade6d 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -158,31 +158,31 @@ void Distance::initOptions(IOptionsContainer* options, TrajectoryAnalysisSetting
     settings->setHelpText(desc);
 
     options->addOption(FileNameOption("oav")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnAverage_)
                                .defaultBasename("distave")
                                .description("Average distances as function of time"));
     options->addOption(FileNameOption("oall")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnAll_)
                                .defaultBasename("dist")
                                .description("All distances as function of time"));
     options->addOption(FileNameOption("oxyz")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnXYZ_)
                                .defaultBasename("distxyz")
                                .description("Distance components as function of time"));
     options->addOption(FileNameOption("oh")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnHistogram_)
                                .defaultBasename("disthist")
                                .description("Histogram of the distances"));
     options->addOption(FileNameOption("oallstat")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnAllStats_)
                                .defaultBasename("diststat")
@@ -214,7 +214,8 @@ void checkSelections(const SelectionList& sel)
             std::string message = formatString(
                     "Selection '%s' does not evaluate into an even number of positions "
                     "(there are %d positions)",
-                    sel[g].name(), sel[g].posCount());
+                    sel[g].name(),
+                    sel[g].posCount());
             GMX_THROW(InconsistentInputError(message));
         }
         if (sel[g].isDynamic())
@@ -324,7 +325,7 @@ void Distance::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, Trajecto
 {
     AnalysisDataHandle   distHandle = pdata->dataHandle(distances_);
     AnalysisDataHandle   xyzHandle  = pdata->dataHandle(xyz_);
-    const SelectionList& sel        = TrajectoryAnalysisModuleData::parallelSelections(sel_);
+    const SelectionList& sel        = pdata->parallelSelections(sel_);
 
     checkSelections(sel);
 
@@ -369,8 +370,8 @@ void Distance::finishAnalysis(int /*nframes*/)
 void Distance::writeOutput()
 {
     SelectionList::const_iterator sel;
-    int                           index;
-    for (sel = sel_.begin(), index = 0; sel != sel_.end(); ++sel, ++index)
+    int                           index = 0;
+    for (sel = sel_.begin(); sel != sel_.end(); ++sel, ++index)
     {
         printf("%s:\n", sel->name());
         printf("  Number of samples:  %d\n", summaryStatsModule_->sampleCount(index, 0));
index 7e92eb0e81c21ded479fc7f7626f6fdf6464f20f..67d47357eda2f3611dd14bc9ffa46b96ce865c32 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +140,7 @@ void ExtractCluster::initOptions(IOptionsContainer* options, TrajectoryAnalysisS
     };
 
     options->addOption(FileNameOption("clusters")
-                               .filetype(eftIndex)
+                               .filetype(OptionFileType::Index)
                                .inputFile()
                                .required()
                                .store(&indexFileName_)
@@ -152,7 +152,7 @@ void ExtractCluster::initOptions(IOptionsContainer* options, TrajectoryAnalysisS
             "Selection of atoms to write to the file"));
 
     options->addOption(FileNameOption("o")
-                               .filetype(eftTrajectory)
+                               .filetype(OptionFileType::Trajectory)
                                .outputFile()
                                .store(&outputNamePrefix_)
                                .defaultBasename("trajout")
@@ -185,7 +185,9 @@ void ExtractCluster::initAnalysis(const TrajectoryAnalysisSettings& /*settings*/
     {
         std::string outputName = Path::concatenateBeforeExtension(
                 outputNamePrefix_, formatString("_%s", clusterIndex_->grpname[i]));
-        writers_.emplace_back(createTrajectoryFrameWriter(top.mtop(), sel_, outputName,
+        writers_.emplace_back(createTrajectoryFrameWriter(top.mtop(),
+                                                          sel_,
+                                                          outputName,
                                                           top.hasTopology() ? top.copyAtoms() : nullptr,
                                                           requirementsBuilder_.process()));
     }
index 2597e359ea3306133075e9a7ffbaa7b782a17761..d049a45483fe109f9a776af416d43db37ba08ead 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -175,7 +175,7 @@ void FreeVolume::initOptions(IOptionsContainer* options, TrajectoryAnalysisSetti
 
     // Add option for optional output file
     options->addOption(FileNameOption("o")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnFreevol_)
                                .defaultBasename("freevolume")
@@ -247,8 +247,8 @@ void FreeVolume::initAnalysis(const TrajectoryAnalysisSettings& settings, const
     for (ArrayRef<const int>::iterator ai = atomind.begin(); (ai < atomind.end()); ++ai)
     {
         // Dereference the iterator to obtain an atom number
-        int  i = *ai;
-        real value;
+        int  i     = *ai;
+        real value = 0;
 
         // Lookup the Van der Waals radius of this atom
         int resnr = atoms->atom[i].resind;
@@ -265,8 +265,10 @@ void FreeVolume::initAnalysis(const TrajectoryAnalysisSettings& settings, const
             nnovdw++;
             if (nnovdw < maxnovdw)
             {
-                fprintf(stderr, "Could not determine VDW radius for %s-%s. Set to zero.\n",
-                        *(atoms->resinfo[resnr].name), *(atoms->atomname[i]));
+                fprintf(stderr,
+                        "Could not determine VDW radius for %s-%s. Set to zero.\n",
+                        *(atoms->resinfo[resnr].name),
+                        *(atoms->atomname[i]));
             }
             vdw_radius_.push_back(0.0);
         }
@@ -303,7 +305,7 @@ void FreeVolume::initAnalysis(const TrajectoryAnalysisSettings& settings, const
 void FreeVolume::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, TrajectoryAnalysisModuleData* pdata)
 {
     AnalysisDataHandle                 dh  = pdata->dataHandle(data_);
-    const Selection&                   sel = TrajectoryAnalysisModuleData::parallelSelection(sel_);
+    const Selection&                   sel = pdata->parallelSelection(sel_);
     gmx::UniformRealDistribution<real> dist;
 
     GMX_RELEASE_ASSERT(nullptr != pbc, "You have no periodic boundary conditions");
@@ -386,7 +388,7 @@ void FreeVolume::writeOutput()
     printf("Total volume %.2f +/- %.2f nm^3\n", Vaver, Verror);
 
     printf("Number of molecules %d total mass %.2f Dalton\n", nmol_, mtot_);
-    double RhoAver  = mtot_ / (Vaver * 1e-24 * AVOGADRO);
+    double RhoAver  = mtot_ / (Vaver * 1e-24 * gmx::c_avogadro);
     double RhoError = gmx::square(RhoAver / Vaver) * Verror;
     printf("Average molar mass: %.2f Dalton\n", mtot_ / nmol_);
 
diff --git a/src/gromacs/trajectoryanalysis/modules/msd.cpp b/src/gromacs/trajectoryanalysis/modules/msd.cpp
new file mode 100644 (file)
index 0000000..52a8947
--- /dev/null
@@ -0,0 +1,838 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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
+ * Defines the trajectory analysis module for mean squared displacement calculations.
+ *
+ * \author Kevin Boyd <kevin44boyd@gmail.com>
+ * \ingroup module_trajectoryanalysis
+ */
+
+#include "gmxpre.h"
+
+#include "msd.h"
+
+#include <numeric>
+#include <optional>
+
+#include "gromacs/analysisdata/analysisdata.h"
+#include "gromacs/analysisdata/modules/average.h"
+#include "gromacs/analysisdata/modules/plot.h"
+#include "gromacs/analysisdata/paralleloptions.h"
+#include "gromacs/fileio/oenv.h"
+#include "gromacs/fileio/trxio.h"
+#include "gromacs/math/functions.h"
+#include "gromacs/math/vectypes.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/filenameoption.h"
+#include "gromacs/options/ioptionscontainer.h"
+#include "gromacs/pbcutil/pbc.h"
+#include "gromacs/selection/selectionoption.h"
+#include "gromacs/statistics/statistics.h"
+#include "gromacs/trajectoryanalysis/analysissettings.h"
+#include "gromacs/trajectoryanalysis/topologyinformation.h"
+#include "gromacs/trajectory/trajectoryframe.h"
+#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility.h"
+
+namespace gmx
+{
+namespace analysismodules
+{
+
+namespace
+{
+
+//! Convert nm^2/ps to 10e-5 cm^2/s
+constexpr double c_diffusionConversionFactor = 1000.0;
+//! Three dimensional diffusion coefficient multiplication constant.
+constexpr double c_3DdiffusionDimensionFactor = 6.0;
+//! Two dimensional diffusion coefficient multiplication constant.
+constexpr double c_2DdiffusionDimensionFactor = 4.0;
+//! One dimensional diffusion coefficient multiplication constant.
+constexpr double c_1DdiffusionDimensionFactor = 2.0;
+
+
+/*! \brief Mean Squared Displacement data accumulator
+ *
+ * This class is used to accumulate individual MSD data points
+ * and emit tau-averaged results once data is finished collecting. Displacements at each observed
+ * time difference (tau) are recorded from the trajectory. Because it is not known in advance which
+ * time differences will be observed from the trajectory, this data structure is built adaptively.
+ * New columns corresponding to observed time differences are added as needed, and additional
+ * observations at formerly observed time differences are added to those columns. Separate time lags
+ * will likely have differing total data points.
+ *
+ * Data columns per tau are accessed via operator[], which always guarantees
+ * a column is initialized and returns an MsdColumProxy to the column that can push data.
+ */
+class MsdData
+{
+public:
+    //! Proxy to a MsdData tau column vector. Supports only push_back.
+    class MsdColumnProxy
+    {
+    public:
+        MsdColumnProxy(std::vector<double>* column) : column_(column) {}
+
+        void push_back(double value) { column_->push_back(value); }
+
+    private:
+        std::vector<double>* column_;
+    };
+    //! Returns a proxy to the column for the given tau index. Guarantees that the column is initialized.
+    MsdColumnProxy operator[](size_t index)
+    {
+        if (msds_.size() <= index)
+        {
+            msds_.resize(index + 1);
+        }
+        return MsdColumnProxy(&msds_[index]);
+    }
+    /*! \brief Compute per-tau MSDs averaged over all added points.
+     *
+     * The resulting vector is size(max tau index). Any indices
+     * that have no data points have MSD set to 0.
+     *
+     * \return Average MSD per tau
+     */
+    [[nodiscard]] std::vector<real> averageMsds() const;
+
+private:
+    //! Results - first indexed by tau, then data points
+    std::vector<std::vector<double>> msds_;
+};
+
+
+std::vector<real> MsdData::averageMsds() const
+{
+    std::vector<real> msdSums;
+    msdSums.reserve(msds_.size());
+    for (gmx::ArrayRef<const double> msdValues : msds_)
+    {
+        if (msdValues.empty())
+        {
+            msdSums.push_back(0.0);
+            continue;
+        }
+        msdSums.push_back(std::accumulate(msdValues.begin(), msdValues.end(), 0.0, std::plus<>())
+                          / msdValues.size());
+    }
+    return msdSums;
+}
+
+/*! \brief Calculates 1,2, or 3D distance for two vectors.
+ *
+ * \todo Remove NOLINTs once clang-tidy is updated to v11, it should be able to handle constexpr.
+ *
+ * \tparam x If true, calculate x dimension of displacement
+ * \tparam y If true, calculate y dimension of displacement
+ * \tparam z If true, calculate z dimension of displacement
+ * \param[in] c1 First point
+ * \param[in] c2 Second point
+ * \return Euclidian distance for the given dimension.
+ */
+template<bool x, bool y, bool z>
+inline double calcSingleSquaredDistance(const RVec c1, const RVec c2)
+{
+    static_assert(x || y || z, "zero-dimensional MSD selected");
+    const DVec firstCoords  = c1.toDVec();
+    const DVec secondCoords = c2.toDVec();
+    double     result       = 0;
+    if constexpr (x) // NOLINT // NOLINTNEXTLINE
+    {
+        result += (firstCoords[XX] - secondCoords[XX]) * (firstCoords[XX] - secondCoords[XX]);
+    }
+    if constexpr (y) // NOLINT // NOLINTNEXTLINE
+    {
+        result += (firstCoords[YY] - secondCoords[YY]) * (firstCoords[YY] - secondCoords[YY]);
+    }
+    if constexpr (z) // NOLINT // NOLINTNEXTLINE
+    {
+        result += (firstCoords[ZZ] - secondCoords[ZZ]) * (firstCoords[ZZ] - secondCoords[ZZ]);
+    }
+    return result; // NOLINT
+}
+
+/*! \brief Calculate average displacement between sets of points
+ *
+ * Each displacement c1[i] - c2[i] is calculated and the distances
+ * are averaged.
+ *
+ * \tparam x If true, calculate x dimension of displacement
+ * \tparam y If true, calculate y dimension of displacement
+ * \tparam z If true, calculate z dimension of displacement
+ * \param[in] c1 First vector
+ * \param[in] c2 Second vector
+ * \return Per-particle averaged distance
+ */
+template<bool x, bool y, bool z>
+double calcAverageDisplacement(ArrayRef<const RVec> c1, ArrayRef<const RVec> c2)
+{
+    double result = 0;
+    for (size_t i = 0; i < c1.size(); i++)
+    {
+        result += calcSingleSquaredDistance<x, y, z>(c1[i], c2[i]);
+    }
+    return result / c1.size();
+}
+
+
+//! Describes 1D MSDs, in the given dimension.
+enum class SingleDimDiffType : int
+{
+    X = 0,
+    Y,
+    Z,
+    Unused,
+    Count,
+};
+
+//! Describes 2D MSDs, in the plane normal to the given dimension.
+enum class TwoDimDiffType : int
+{
+    NormalToX = 0,
+    NormalToY,
+    NormalToZ,
+    Unused,
+    Count,
+};
+
+/*! \brief Removes jumps across periodic boundaries for currentFrame, based on the positions in
+ * previousFrame. Updates currentCoords in place.
+ */
+void removePbcJumps(ArrayRef<RVec> currentCoords, ArrayRef<const RVec> previousCoords, t_pbc* pbc)
+{
+    // There are two types of "pbc removal" in gmx msd. The first happens in the trajectoryanalysis
+    // framework, which makes molecules whole across periodic boundaries and is done
+    // automatically where the inputs support it. This lambda performs the second PBC correction, where
+    // any "jump" across periodic boundaries BETWEEN FRAMES is put back. The order of these
+    // operations is important - since the first transformation may only apply to part of a
+    // molecule (e.g., one half in/out of the box is put on one side of the box), the
+    // subsequent step needs to be applied to the molecule COM rather than individual atoms, or
+    // we'd have a clash where the per-mol PBC removal moves an atom that gets put back into
+    // it's original position by the second transformation. Therefore, this second transformation
+    // is applied *after* per molecule coordinates have been consolidated into COMs.
+    auto pbcRemover = [pbc](RVec in, RVec prev) {
+        rvec dx;
+        pbc_dx(pbc, in, prev, dx);
+        return prev + dx;
+    };
+    std::transform(
+            currentCoords.begin(), currentCoords.end(), previousCoords.begin(), currentCoords.begin(), pbcRemover);
+}
+
+//! Holds data needed for MSD calculations for a single molecule, if requested.
+struct MoleculeData
+{
+    //! Number of atoms in the molecule.
+    int atomCount = 0;
+    //! Total mass.
+    double mass = 0;
+    //! MSD accumulator and calculator for the molecule
+    MsdData msdData;
+    //! Calculated diffusion coefficient
+    real diffusionCoefficient = 0;
+};
+
+/*! \brief Handles coordinate operations for MSD calculations.
+ *
+ * Can be used to hold coordinates for individual atoms as well as molecules COMs. Handles PBC
+ * jump removal between consecutive frames.
+ *
+ * Only previous_ contains valid data between calls to buildCoordinates(), although both vectors
+ * are maintained at the correct size for the number of coordinates needed.
+ */
+class MsdCoordinateManager
+{
+public:
+    MsdCoordinateManager(const int                    numAtoms,
+                         ArrayRef<const MoleculeData> molecules,
+                         ArrayRef<const int>          moleculeIndexMapping) :
+        current_(numAtoms),
+        previous_(numAtoms),
+        molecules_(molecules),
+        moleculeIndexMapping_(moleculeIndexMapping)
+    {
+    }
+    /*! \brief Prepares coordinates for the current frame.
+     *
+     * Reads in selection data, and returns an ArrayRef of the particle positions or molecule
+     * centers of mass (if the molecules input is not empty). Removes jumps across periodic
+     * boundaries based on the previous frame coordinates, except for the first frame built with
+     * builtCoordinates(), which has no previous frame as a reference.
+     *
+     * \param[in] sel                   The selection object which holds coordinates
+     * \param[in] pbc                   Information about periodicity.
+     * \returns                         The current frames coordinates in proper format.
+     */
+    ArrayRef<const RVec> buildCoordinates(const Selection& sel, t_pbc* pbc);
+
+private:
+    //! The current coordinates.
+    std::vector<RVec> current_;
+    //! The previous frame's coordinates.
+    std::vector<RVec> previous_;
+    //! Molecule data.
+    ArrayRef<const MoleculeData> molecules_;
+    //! Mapping of atom indices to molecle indices;
+    ArrayRef<const int> moleculeIndexMapping_;
+    //! Tracks if a previous frame exists to compare with for PBC handling.
+    bool containsPreviousFrame_ = false;
+};
+
+ArrayRef<const RVec> MsdCoordinateManager::buildCoordinates(const Selection& sel, t_pbc* pbc)
+{
+
+    if (molecules_.empty())
+    {
+        std::copy(sel.coordinates().begin(), sel.coordinates().end(), current_.begin());
+    }
+    else
+    {
+        // Prepare for molecule COM calculation, then sum up all positions per molecule.
+
+        std::fill(current_.begin(), current_.end(), RVec(0, 0, 0));
+        gmx::ArrayRef<const real> masses = sel.masses();
+        for (int i = 0; i < sel.posCount(); i++)
+        {
+            const int moleculeIndex = moleculeIndexMapping_[i];
+            // accumulate ri * mi, and do division at the end to minimize number of divisions.
+            current_[moleculeIndex] += RVec(sel.position(i).x()) * masses[i];
+        }
+        // Divide accumulated mass * positions to get COM.
+        std::transform(current_.begin(),
+                       current_.end(),
+                       molecules_.begin(),
+                       current_.begin(),
+                       [](const RVec& position, const MoleculeData& molecule) -> RVec {
+                           return position / molecule.mass;
+                       });
+    }
+
+    if (containsPreviousFrame_)
+    {
+        removePbcJumps(current_, previous_, pbc);
+    }
+    else
+    {
+        containsPreviousFrame_ = true;
+    }
+
+    // Previous is no longer needed, swap with current and return "current" coordinates which
+    // now reside in previous.
+    current_.swap(previous_);
+    return previous_;
+}
+
+
+//! Holds per-group coordinates, analysis, and results.
+struct MsdGroupData
+{
+    explicit MsdGroupData(const Selection&             inputSel,
+                          ArrayRef<const MoleculeData> molecules,
+                          ArrayRef<const int>          moleculeAtomMapping) :
+        sel(inputSel),
+        coordinateManager_(molecules.empty() ? sel.posCount() : molecules.size(), molecules, moleculeAtomMapping)
+    {
+    }
+
+    //! Selection associated with this group.
+    const Selection& sel;
+
+    //! Stored coordinates, indexed by frame then atom number.
+    std::vector<std::vector<RVec>> frames;
+
+    //! MSD result accumulator
+    MsdData msds;
+    //! Coordinate handler for the group.
+    MsdCoordinateManager coordinateManager_;
+    //! Collector for processed MSD averages per tau
+    std::vector<real> msdSums;
+    //! Fitted diffusion coefficient
+    real diffusionCoefficient = 0.0;
+    //! Uncertainty of diffusion coefficient
+    double sigma = 0.0;
+};
+
+} // namespace
+
+/*! \brief Implements the gmx msd module
+ *
+ * \todo Implement -(no)mw. Right now, all calculations are mass-weighted with -mol, and not otherwise
+ * \todo Implement -tensor for full MSD tensor calculation
+ * \todo Implement -rmcomm for total-frame COM removal
+ * \todo Implement -pdb for molecule B factors
+ * \todo Implement -maxtau option proposed at https://gitlab.com/gromacs/gromacs/-/issues/3870
+ * \todo Update help text as options are added and clarifications decided on at https://gitlab.com/gromacs/gromacs/-/issues/3869
+ */
+class Msd : public TrajectoryAnalysisModule
+{
+public:
+    Msd();
+
+    void initOptions(IOptionsContainer* options, TrajectoryAnalysisSettings* settings) override;
+    void optionsFinished(TrajectoryAnalysisSettings* settings) override;
+    void initAfterFirstFrame(const TrajectoryAnalysisSettings& settings, const t_trxframe& fr) override;
+    void initAnalysis(const TrajectoryAnalysisSettings& settings, const TopologyInformation& top) override;
+    void analyzeFrame(int                           frameNumber,
+                      const t_trxframe&             frame,
+                      t_pbc*                        pbc,
+                      TrajectoryAnalysisModuleData* pdata) override;
+    void finishAnalysis(int nframes) override;
+    void writeOutput() override;
+
+private:
+    //! Selections for MSD output
+    SelectionList selections_;
+
+    //! MSD type information, for -type {x,y,z}
+    SingleDimDiffType singleDimType_ = SingleDimDiffType::Unused;
+    //! MSD type information, for -lateral {x,y,z}
+    TwoDimDiffType twoDimType_ = TwoDimDiffType::Unused;
+    //! Diffusion coefficient conversion factor
+    double diffusionCoefficientDimensionFactor_ = c_3DdiffusionDimensionFactor;
+    //! Method used to calculate MSD - changes based on dimensonality.
+    std::function<double(ArrayRef<const RVec>, ArrayRef<const RVec>)> calcMsd_ =
+            calcAverageDisplacement<true, true, true>;
+
+    //! Picoseconds between restarts
+    double trestart_ = 10.0;
+    //! Initial time
+    double t0_ = 0;
+    //! Inter-frame delta-t
+    std::optional<double> dt_ = std::nullopt;
+
+    //! First tau value to fit from for diffusion coefficient, defaults to 0.1 * max tau
+    real beginFit_ = -1.0;
+    //! Final tau value to fit to for diffusion coefficient, defaults to 0.9 * max tau
+    real endFit_ = -1.0;
+
+    //! All selection group-specific data stored here.
+    std::vector<MsdGroupData> groupData_;
+
+    //! Time of all frames.
+    std::vector<double> times_;
+    //! Taus for output - won't know the size until the end.
+    std::vector<double> taus_;
+    //! Tau indices for fitting.
+    size_t beginFitIndex_ = 0;
+    size_t endFitIndex_   = 0;
+
+    // MSD per-molecule stuff
+    //! Are we doing molecule COM-based MSDs?
+    bool molSelected_ = false;
+    //! Per molecule topology information and MSD accumulators.
+    std::vector<MoleculeData> molecules_;
+    //! Atom index -> mol index map
+    std::vector<int> moleculeIndexMappings_;
+
+    // Output stuff
+    AnalysisData msdPlotData_;
+    AnalysisData msdMoleculePlotData_;
+
+    AnalysisDataPlotSettings plotSettings_;
+    //! Per-tau MSDs for each selected group
+    std::string output_;
+    //! Per molecule diffusion coefficients if -mol is selected.
+    std::string moleculeOutput_;
+};
+
+
+Msd::Msd() = default;
+
+void Msd::initOptions(IOptionsContainer* options, TrajectoryAnalysisSettings* settings)
+{
+    static const char* const desc[] = {
+        "[THISMODULE] computes the mean square displacement (MSD) of atoms from",
+        "a set of initial positions. This provides an easy way to compute",
+        "the diffusion constant using the Einstein relation.",
+        "The time between the reference points for the MSD calculation",
+        "is set with [TT]-trestart[tt].",
+        "The diffusion constant is calculated by least squares fitting a",
+        "straight line (D*t + c) through the MSD(t) from [TT]-beginfit[tt] to",
+        "[TT]-endfit[tt] (note that t is time from the reference positions,",
+        "not simulation time). An error estimate given, which is the difference",
+        "of the diffusion coefficients obtained from fits over the two halves",
+        "of the fit interval.[PAR]",
+        "There are three, mutually exclusive, options to determine different",
+        "types of mean square displacement: [TT]-type[tt], [TT]-lateral[tt]",
+        "and [TT]-ten[tt]. Option [TT]-ten[tt] writes the full MSD tensor for",
+        "each group, the order in the output is: trace xx yy zz yx zx zy.[PAR]",
+        "If [TT]-mol[tt] is set, [THISMODULE] plots the MSD for individual molecules",
+        "(including making molecules whole across periodic boundaries): ",
+        "for each individual molecule a diffusion constant is computed for ",
+        "its center of mass. The chosen index group will be split into ",
+        "molecules. With -mol, only one index group can be selected.[PAR]",
+        "The diffusion coefficient is determined by linear regression of the MSD.",
+        "When [TT]-beginfit[tt] is -1, fitting starts at 10%",
+        "and when [TT]-endfit[tt] is -1, fitting goes to 90%.",
+        "Using this option one also gets an accurate error estimate",
+        "based on the statistics between individual molecules.",
+        "Note that this diffusion coefficient and error estimate are only",
+        "accurate when the MSD is completely linear between",
+        "[TT]-beginfit[tt] and [TT]-endfit[tt].[PAR]",
+    };
+    settings->setHelpText(desc);
+
+    // Selections
+    options->addOption(SelectionOption("sel")
+                               .storeVector(&selections_)
+                               .required()
+                               .onlyStatic()
+                               .multiValue()
+                               .description("Selections to compute MSDs for from the reference"));
+
+    // Select MSD type - defaults to 3D if neither option is selected.
+    EnumerationArray<SingleDimDiffType, const char*> enumTypeNames    = { "x", "y", "z", "unused" };
+    EnumerationArray<TwoDimDiffType, const char*>    enumLateralNames = { "x", "y", "z", "unused" };
+    options->addOption(EnumOption<SingleDimDiffType>("type")
+                               .enumValue(enumTypeNames)
+                               .store(&singleDimType_)
+                               .defaultValue(SingleDimDiffType::Unused));
+    options->addOption(EnumOption<TwoDimDiffType>("lateral")
+                               .enumValue(enumLateralNames)
+                               .store(&twoDimType_)
+                               .defaultValue(TwoDimDiffType::Unused));
+
+    options->addOption(DoubleOption("trestart")
+                               .description("Time between restarting points in trajectory (ps)")
+                               .defaultValue(10.0)
+                               .store(&trestart_));
+    options->addOption(
+            RealOption("beginfit").description("Time point at which to start fitting.").store(&beginFit_));
+    options->addOption(RealOption("endfit").description("End time for fitting.").store(&endFit_));
+
+    // Output options
+    options->addOption(FileNameOption("o")
+                               .filetype(OptionFileType::Plot)
+                               .outputFile()
+                               .store(&output_)
+                               .defaultBasename("msdout")
+                               .description("MSD output"));
+    options->addOption(
+            FileNameOption("mol")
+                    .filetype(OptionFileType::Plot)
+                    .outputFile()
+                    .store(&moleculeOutput_)
+                    .storeIsSet(&molSelected_)
+                    .defaultBasename("diff_mol")
+                    .description("Report diffusion coefficients for each molecule in selection"));
+}
+
+void Msd::optionsFinished(TrajectoryAnalysisSettings gmx_unused* settings)
+{
+    if (singleDimType_ != SingleDimDiffType::Unused && twoDimType_ != TwoDimDiffType::Unused)
+    {
+        std::string errorMessage =
+                "Options -type and -lateral are mutually exclusive. Choose one or neither (for 3D "
+                "MSDs).";
+        GMX_THROW(InconsistentInputError(errorMessage.c_str()));
+    }
+    if (selections_.size() > 1 && molSelected_)
+    {
+        std::string errorMessage =
+                "Cannot have multiple groups selected with -sel when using -mol.";
+        GMX_THROW(InconsistentInputError(errorMessage.c_str()));
+    }
+}
+
+
+void Msd::initAnalysis(const TrajectoryAnalysisSettings& settings, const TopologyInformation& top)
+{
+    plotSettings_ = settings.plotSettings();
+
+    // Enumeration helpers for dispatching the right MSD calculation type.
+    const EnumerationArray<SingleDimDiffType, decltype(&calcAverageDisplacement<true, true, true>)>
+            oneDimensionalMsdFunctions = { &calcAverageDisplacement<true, false, false>,
+                                           &calcAverageDisplacement<false, true, false>,
+                                           &calcAverageDisplacement<false, false, true> };
+    const EnumerationArray<TwoDimDiffType, decltype(&calcAverageDisplacement<true, true, true>)>
+            twoDimensionalMsdFunctions = { calcAverageDisplacement<false, true, true>,
+                                           calcAverageDisplacement<true, false, true>,
+                                           calcAverageDisplacement<true, true, false> };
+
+    // Parse dimensionality and assign the MSD calculating function.
+    // Note if we don't hit either of these cases, we're computing 3D MSDs.
+    if (singleDimType_ != SingleDimDiffType::Unused)
+    {
+        calcMsd_                             = oneDimensionalMsdFunctions[singleDimType_];
+        diffusionCoefficientDimensionFactor_ = c_1DdiffusionDimensionFactor;
+    }
+    else if (twoDimType_ != TwoDimDiffType::Unused)
+    {
+        calcMsd_                             = twoDimensionalMsdFunctions[twoDimType_];
+        diffusionCoefficientDimensionFactor_ = c_2DdiffusionDimensionFactor;
+    }
+
+    // TODO validate that we have mol info and not atom only - and masses, and topology.
+    if (molSelected_)
+    {
+        Selection& sel  = selections_[0];
+        const int  nMol = sel.initOriginalIdsToGroup(top.mtop(), INDEX_MOL);
+
+        gmx::ArrayRef<const int> mappedIds = selections_[0].mappedIds();
+        moleculeIndexMappings_.resize(selections_[0].posCount());
+        std::copy(mappedIds.begin(), mappedIds.end(), moleculeIndexMappings_.begin());
+
+        // Precalculate each molecules mass for speeding up COM calculations.
+        ArrayRef<const real> masses = sel.masses();
+
+        molecules_.resize(nMol);
+        for (int i = 0; i < sel.posCount(); i++)
+        {
+            molecules_[mappedIds[i]].atomCount++;
+            molecules_[mappedIds[i]].mass += masses[i];
+        }
+    }
+
+    // Accumulated frames and results
+    for (const Selection& sel : selections_)
+    {
+        groupData_.emplace_back(sel, molecules_, moleculeIndexMappings_);
+    }
+}
+
+void Msd::initAfterFirstFrame(const TrajectoryAnalysisSettings gmx_unused& settings, const t_trxframe& fr)
+{
+    t0_ = std::round(fr.time);
+}
+
+
+void Msd::analyzeFrame(int gmx_unused                frameNumber,
+                       const t_trxframe&             frame,
+                       t_pbc*                        pbc,
+                       TrajectoryAnalysisModuleData* pdata)
+{
+    const real time = std::round(frame.time);
+    // Need to populate dt on frame 2;
+    if (!dt_.has_value() && !times_.empty())
+    {
+        dt_ = time - times_[0];
+    }
+
+    // Each frame gets an entry in times, but frameTimes only updates if we're at a restart.
+    times_.push_back(time);
+
+    // Each frame will get a tau between it and frame 0, and all other frame combos should be
+    // covered by this.
+    // \todo this will no longer hold exactly when maxtau is added
+    taus_.push_back(time - times_[0]);
+
+    for (MsdGroupData& msdData : groupData_)
+    {
+        const Selection& sel = pdata->parallelSelection(msdData.sel);
+
+        ArrayRef<const RVec> coords = msdData.coordinateManager_.buildCoordinates(sel, pbc);
+
+        // For each preceding frame, calculate tau and do comparison.
+        for (size_t i = 0; i < msdData.frames.size(); i++)
+        {
+            // If dt > trestart, the tau increment will be dt rather than trestart.
+            double  tau      = time - (t0_ + std::max<double>(trestart_, *dt_) * i);
+            int64_t tauIndex = gmx::roundToInt64(tau / *dt_);
+            msdData.msds[tauIndex].push_back(calcMsd_(coords, msdData.frames[i]));
+
+            for (size_t molInd = 0; molInd < molecules_.size(); molInd++)
+            {
+                molecules_[molInd].msdData[tauIndex].push_back(
+                        calcMsd_(arrayRefFromArray(&coords[molInd], 1),
+                                 arrayRefFromArray(&msdData.frames[i][molInd], 1)));
+            }
+        }
+
+
+        // We only store the frame for the future if it's a restart per -trestart.
+        if (bRmod(time, t0_, trestart_))
+        {
+            msdData.frames.emplace_back(coords.begin(), coords.end());
+        }
+    }
+}
+
+//! Calculate the tau index for fitting. If userFitTau < 0, uses the default fraction of max tau.
+static size_t calculateFitIndex(const int    userFitTau,
+                                const double defaultTauFraction,
+                                const int    numTaus,
+                                const double dt)
+{
+    if (userFitTau < 0)
+    {
+        return gmx::roundToInt((numTaus - 1) * defaultTauFraction);
+    }
+    return std::min<size_t>(numTaus - 1, gmx::roundToInt(static_cast<double>(userFitTau) / dt));
+}
+
+
+void Msd::finishAnalysis(int gmx_unused nframes)
+{
+    static constexpr double c_defaultStartFitIndexFraction = 0.1;
+    static constexpr double c_defaultEndFitIndexFraction   = 0.9;
+    beginFitIndex_ = calculateFitIndex(beginFit_, c_defaultStartFitIndexFraction, taus_.size(), *dt_);
+    endFitIndex_   = calculateFitIndex(endFit_, c_defaultEndFitIndexFraction, taus_.size(), *dt_);
+    const int numTausForFit = 1 + endFitIndex_ - beginFitIndex_;
+
+    // These aren't used, except for correlationCoefficient, which is used to estimate error if
+    // enough points are available.
+    real b = 0.0, correlationCoefficient = 0.0, chiSquared = 0.0;
+
+    for (MsdGroupData& msdData : groupData_)
+    {
+        msdData.msdSums = msdData.msds.averageMsds();
+
+        if (numTausForFit >= 4)
+        {
+            const int halfNumTaus         = numTausForFit / 2;
+            const int secondaryStartIndex = beginFitIndex_ + halfNumTaus;
+            // Split the fit in 2, and compare the results of each fit;
+            real a = 0.0, a2 = 0.0;
+            lsq_y_ax_b_xdouble(halfNumTaus,
+                               &taus_[beginFitIndex_],
+                               &msdData.msdSums[beginFitIndex_],
+                               &a,
+                               &b,
+                               &correlationCoefficient,
+                               &chiSquared);
+            lsq_y_ax_b_xdouble(halfNumTaus,
+                               &taus_[secondaryStartIndex],
+                               &msdData.msdSums[secondaryStartIndex],
+                               &a2,
+                               &b,
+                               &correlationCoefficient,
+                               &chiSquared);
+            msdData.sigma = std::abs(a - a2);
+        }
+        lsq_y_ax_b_xdouble(numTausForFit,
+                           &taus_[beginFitIndex_],
+                           &msdData.msdSums[beginFitIndex_],
+                           &msdData.diffusionCoefficient,
+                           &b,
+                           &correlationCoefficient,
+                           &chiSquared);
+        msdData.diffusionCoefficient *= c_diffusionConversionFactor / diffusionCoefficientDimensionFactor_;
+        msdData.sigma *= c_diffusionConversionFactor / diffusionCoefficientDimensionFactor_;
+    }
+
+    for (MoleculeData& molecule : molecules_)
+    {
+        std::vector<real> msds = molecule.msdData.averageMsds();
+        lsq_y_ax_b_xdouble(numTausForFit,
+                           &taus_[beginFitIndex_],
+                           &msds[beginFitIndex_],
+                           &molecule.diffusionCoefficient,
+                           &b,
+                           &correlationCoefficient,
+                           &chiSquared);
+        molecule.diffusionCoefficient *= c_diffusionConversionFactor / diffusionCoefficientDimensionFactor_;
+    }
+}
+
+void Msd::writeOutput()
+{
+    // AnalysisData currently doesn't support changing column counts after analysis has started.
+    // We can't determine the number of tau values until the trajectory is fully read, so analysis
+    // data construction and plotting are done here.
+    AnalysisDataPlotModulePointer msdPlotModule(new AnalysisDataPlotModule(plotSettings_));
+    msdPlotModule->setFileName(output_);
+    msdPlotModule->setTitle("Mean Squared Displacement");
+    msdPlotModule->setXLabel("tau (ps)");
+    msdPlotModule->setYLabel(R"(MSD (nm\\S2\\N))");
+    msdPlotModule->setYFormat(10, 6, 'g');
+    for (const auto& group : groupData_)
+    {
+        const real D = group.diffusionCoefficient;
+        if (D > 0.01 && D < 1e4)
+        {
+            msdPlotModule->appendLegend(formatString(
+                    "D[%10s] = %.4f (+/- %.4f) (1e-5 cm^2/s)", group.sel.name(), D, group.sigma));
+        }
+        else
+        {
+            msdPlotModule->appendLegend(formatString(
+                    "D[%10s] = %.4g (+/- %.4f) (1e-5 cm^2/s)", group.sel.name(), D, group.sigma));
+        }
+    }
+    msdPlotData_.addModule(msdPlotModule);
+    msdPlotData_.setDataSetCount(groupData_.size());
+    for (size_t i = 0; i < groupData_.size(); i++)
+    {
+        msdPlotData_.setColumnCount(i, 1);
+    }
+    AnalysisDataHandle dh = msdPlotData_.startData({});
+    for (size_t tauIndex = 0; tauIndex < taus_.size(); tauIndex++)
+    {
+        dh.startFrame(tauIndex, taus_[tauIndex]);
+        for (size_t dataSetIndex = 0; dataSetIndex < groupData_.size(); dataSetIndex++)
+        {
+            dh.selectDataSet(dataSetIndex);
+            dh.setPoint(0, groupData_[dataSetIndex].msdSums[tauIndex]);
+        }
+        dh.finishFrame();
+    }
+    dh.finishData();
+
+    if (molSelected_)
+    {
+        AnalysisDataPlotModulePointer molPlotModule(new AnalysisDataPlotModule(plotSettings_));
+        molPlotModule->setFileName(moleculeOutput_);
+        molPlotModule->setTitle("Mean Squared Displacement / Molecule");
+        molPlotModule->setXLabel("Molecule");
+        molPlotModule->setYLabel("D(1e-5 cm^2/s)");
+        molPlotModule->setYFormat(10, 0, 'g');
+        msdMoleculePlotData_.addModule(molPlotModule);
+        msdMoleculePlotData_.setDataSetCount(1);
+        msdMoleculePlotData_.setColumnCount(0, 1);
+        AnalysisDataHandle molDh = msdMoleculePlotData_.startData({});
+        for (size_t moleculeIndex = 0; moleculeIndex < molecules_.size(); moleculeIndex++)
+        {
+            molDh.startFrame(moleculeIndex, moleculeIndex);
+            molDh.setPoint(0, molecules_[moleculeIndex].diffusionCoefficient);
+            molDh.finishFrame();
+        }
+        molDh.finishData();
+    }
+}
+
+
+const char                      MsdInfo::name[]             = "msd";
+const char                      MsdInfo::shortDescription[] = "Compute mean squared displacements";
+TrajectoryAnalysisModulePointer MsdInfo::create()
+{
+    return TrajectoryAnalysisModulePointer(new Msd);
+}
+
+
+} // namespace analysismodules
+} // namespace gmx
similarity index 69%
rename from src/gromacs/simd/impl_x86_mic/impl_x86_mic_general.h
rename to src/gromacs/trajectoryanalysis/modules/msd.h
index 4c2c49f108f830ca4b39b779203798bf193799c1..53f890c1fd3d55613cf2eaf4b21cc2078f442407 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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.
  */
+/*! \internal \file
+ * \brief
+ * Declares trajectory analysis module for Mean Squared Displacement calculations.
+ *
+ * \author Kevin Boyd <kevin44boyd@gmail.com>
+ * \ingroup module_trajectoryanalysis
+ */
+#ifndef GMX_TRAJECTORYANALYSIS_MODULES_MSD_H
+#define GMX_TRAJECTORYANALYSIS_MODULES_MSD_H
 
-#ifndef GMX_SIMD_IMPL_X86_MIC_GENERAL_H
-#define GMX_SIMD_IMPL_X86_MIC_GENERAL_H
-
-#include <immintrin.h>
+#include "gromacs/trajectoryanalysis/analysismodule.h"
 
-namespace gmx
+namespace gmx::analysismodules
 {
 
-static inline void simdPrefetch(const void* m)
+class MsdInfo
 {
-    _mm_prefetch((const char*)m, _MM_HINT_T0);
-}
+public:
+    static const char                      name[];
+    static const char                      shortDescription[];
+    static TrajectoryAnalysisModulePointer create();
+};
 
-} // namespace gmx
+} // namespace gmx::analysismodules
 
-#endif // GMX_SIMD_IMPL_X86_MIC_OTHER_H
+#endif // GMX_TRAJECTORYANALYSIS_MODULES_MSD_H
index e5e27165d34119a584ffb699dbc9576e492b467a..7721100cc7f33c0402f32fe70e83da64b6b7e177 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2016,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -98,8 +98,9 @@ enum class GroupType : int
 //! Strings corresponding to DistanceType.
 const EnumerationArray<DistanceType, const char*> c_distanceTypeNames = { { "min", "max" } };
 //! Strings corresponding to GroupType.
-const EnumerationArray<GroupType, const char*> c_groupTypeNames = { { "all", "res", "mol",
-                                                                      "none" } };
+const EnumerationArray<GroupType, const char*> c_groupTypeNames = {
+    { "all", "res", "mol", "none" }
+};
 
 /*! \brief
  * Implements `gmx pairdist` trajectory analysis module.
@@ -220,7 +221,7 @@ void PairDistance::initOptions(IOptionsContainer* options, TrajectoryAnalysisSet
     settings->setHelpText(desc);
 
     options->addOption(FileNameOption("o")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .required()
                                .store(&fnDist_)
@@ -415,8 +416,8 @@ TrajectoryAnalysisModuleDataPointer PairDistance::startFrames(const AnalysisData
 void PairDistance::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, TrajectoryAnalysisModuleData* pdata)
 {
     AnalysisDataHandle      dh         = pdata->dataHandle(distances_);
-    const Selection&        refSel     = TrajectoryAnalysisModuleData::parallelSelection(refSel_);
-    const SelectionList&    sel        = TrajectoryAnalysisModuleData::parallelSelections(sel_);
+    const Selection&        refSel     = pdata->parallelSelection(refSel_);
+    const SelectionList&    sel        = pdata->parallelSelections(sel_);
     PairDistanceModuleData& frameData  = *static_cast<PairDistanceModuleData*>(pdata);
     std::vector<real>&      distArray  = frameData.distArray_;
     std::vector<int>&       countArray = frameData.countArray_;
index bc088be33f9083172c1da5ab25d694ce18a2793a..fb14250fc6eac44d14e6d114ad2c46e4d66df78f 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +58,7 @@
 #include "gromacs/analysisdata/modules/histogram.h"
 #include "gromacs/analysisdata/modules/plot.h"
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/options/basicoptions.h"
@@ -286,14 +287,14 @@ void Rdf::initOptions(IOptionsContainer* options, TrajectoryAnalysisSettings* se
     settings->setHelpText(desc);
 
     options->addOption(FileNameOption("o")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .required()
                                .store(&fnRdf_)
                                .defaultBasename("rdf")
                                .description("Computed RDFs"));
     options->addOption(FileNameOption("cn")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnCumulative_)
                                .defaultBasename("rdf_cn")
@@ -478,8 +479,8 @@ void Rdf::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, TrajectoryAna
 {
     AnalysisDataHandle   dh        = pdata->dataHandle(pairDist_);
     AnalysisDataHandle   nh        = pdata->dataHandle(normFactors_);
-    const Selection&     refSel    = TrajectoryAnalysisModuleData::parallelSelection(refSel_);
-    const SelectionList& sel       = TrajectoryAnalysisModuleData::parallelSelections(sel_);
+    const Selection&     refSel    = pdata->parallelSelection(refSel_);
+    const SelectionList& sel       = pdata->parallelSelections(sel_);
     RdfModuleData&       frameData = *static_cast<RdfModuleData*>(pdata);
     const bool           bSurface  = !frameData.surfaceDist2_.empty();
 
@@ -614,19 +615,11 @@ void Rdf::finishAnalysis(int /*nframes*/)
         real prevSphereVolume = 0.0;
         for (int i = 0; i < nbin; ++i)
         {
-            const real r = (i + 0.5) * binwidth_;
-            real       sphereVolume;
-            if (bXY_)
-            {
-                sphereVolume = M_PI * r * r;
-            }
-            else
-            {
-                sphereVolume = (4.0 / 3.0) * M_PI * r * r * r;
-            }
-            const real binVolume = sphereVolume - prevSphereVolume;
-            invBinVolume[i]      = 1.0 / binVolume;
-            prevSphereVolume     = sphereVolume;
+            const real r            = (i + 0.5) * binwidth_;
+            const real sphereVolume = (bXY_) ? M_PI * r * r : (4.0 / 3.0) * M_PI * r * r * r;
+            const real binVolume    = sphereVolume - prevSphereVolume;
+            invBinVolume[i]         = 1.0 / binVolume;
+            prevSphereVolume        = sphereVolume;
         }
         finalRdf->scaleAllByVector(invBinVolume.data());
 
index 502f51d07300fce28869d575e297d99cb69741a6..360e68c7a351ca8269afff1489b84b625489d227 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2001-2006, The GROMACS development team.
  * Copyright (c) 2008,2009,2010,2011,2012 by the GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -160,31 +160,28 @@ void add_rec(t_conect c[], int i, int j, real d2)
  */
 void do_conect(const char* fn, int n, rvec x[])
 {
-    FILE*     fp;
-    int       i, j;
-    t_conect* c;
-    rvec      dx;
-    real      d2;
+    t_conect* c = nullptr;
 
     fprintf(stderr, "Building CONECT records\n");
     snew(c, n);
-    for (i = 0; (i < n); i++)
+    for (int i = 0; (i < n); i++)
     {
         c[i].aa = c[i].ab = -1;
     }
 
-    for (i = 0; (i < n); i++)
+    for (int i = 0; (i < n); i++)
     {
-        for (j = i + 1; (j < n); j++)
+        for (int j = i + 1; (j < n); j++)
         {
+            rvec dx;
             rvec_sub(x[i], x[j], dx);
-            d2 = iprod(dx, dx);
+            const real d2 = iprod(dx, dx);
             add_rec(c, i, j, d2);
             add_rec(c, j, i, d2);
         }
     }
-    fp = gmx_ffopen(fn, "a");
-    for (i = 0; (i < n); i++)
+    FILE* fp = gmx_ffopen(fn, "a");
+    for (int i = 0; (i < n); i++)
     {
         if ((c[i].aa == -1) || (c[i].ab == -1))
         {
@@ -213,14 +210,12 @@ void connolly_plot(const char*  fn,
     const char* const resnm  = "DOT";
     const char* const title  = "Connolly Dot Surface Generated by gmx sasa";
 
-    int     i, i0, r0, ii0, k;
-    rvec*   xnew;
-    t_atoms aaa;
+    rvec* xnew = nullptr;
 
     if (bIncludeSolute)
     {
-        i0 = atoms->nr;
-        r0 = atoms->nres;
+        int i0 = atoms->nr;
+        int r0 = atoms->nres;
         srenew(atoms->atom, atoms->nr + ndots);
         memset(&atoms->atom[i0], 0, sizeof(*atoms->atom) * ndots);
         srenew(atoms->atomname, atoms->nr + ndots);
@@ -232,13 +227,14 @@ void connolly_plot(const char*  fn,
             srenew(atoms->pdbinfo, atoms->nr + ndots);
         }
         snew(xnew, atoms->nr + ndots);
-        for (i = 0; (i < atoms->nr); i++)
+        for (int i = 0; (i < atoms->nr); i++)
         {
             copy_rvec(x[i], xnew[i]);
         }
-        for (i = k = 0; (i < ndots); i++)
+        int k = 0;
+        for (int i = 0; (i < ndots); i++)
         {
-            ii0                     = i0 + i;
+            int ii0                 = i0 + i;
             atoms->atomname[ii0]    = put_symtab(symtab, atomnm);
             atoms->atom[ii0].resind = r0;
             xnew[ii0][XX]           = dots[k++];
@@ -246,7 +242,7 @@ void connolly_plot(const char*  fn,
             xnew[ii0][ZZ]           = dots[k++];
             if (atoms->pdbinfo != nullptr)
             {
-                atoms->pdbinfo[ii0].type   = epdbATOM;
+                atoms->pdbinfo[ii0].type   = PdbRecordType::Atom;
                 atoms->pdbinfo[ii0].atomnr = ii0;
                 atoms->pdbinfo[ii0].bfac   = 0.0;
                 atoms->pdbinfo[ii0].occup  = 0.0;
@@ -260,15 +256,17 @@ void connolly_plot(const char*  fn,
     }
     else
     {
+        t_atoms aaa;
         init_t_atoms(&aaa, ndots, TRUE);
         aaa.atom[0].resind = 0;
         t_atoms_set_resinfo(&aaa, 0, symtab, resnm, 1, ' ', 0, ' ');
         snew(xnew, ndots);
-        for (i = k = 0; (i < ndots); i++)
+        int k = 0;
+        for (int i = 0; (i < ndots); i++)
         {
-            ii0                     = i;
+            int ii0                 = i;
             aaa.atomname[ii0]       = put_symtab(symtab, atomnm);
-            aaa.pdbinfo[ii0].type   = epdbATOM;
+            aaa.pdbinfo[ii0].type   = PdbRecordType::Atom;
             aaa.pdbinfo[ii0].atomnr = ii0;
             aaa.atom[ii0].resind    = 0;
             xnew[ii0][XX]           = dots[k++];
@@ -439,7 +437,8 @@ void Sasa::initOptions(IOptionsContainer* options, TrajectoryAnalysisSettings* s
         "from the full surface.[PAR]",
 
         "The average and standard deviation of the area over the trajectory",
-        "can be calculated per residue and atom (options [TT]-or[tt] and", "[TT]-oa[tt]).[PAR]",
+        "can be calculated per residue and atom (options [TT]-or[tt] and",
+        "[TT]-oa[tt]).[PAR]",
         //"In combination with the latter option an [REF].itp[ref] file can be",
         //"generated (option [TT]-i[tt])",
         //"which can be used to restrain surface atoms.[PAR]",
@@ -459,7 +458,7 @@ void Sasa::initOptions(IOptionsContainer* options, TrajectoryAnalysisSettings* s
     settings->setHelpText(desc);
 
     options->addOption(FileNameOption("o")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .required()
                                .store(&fnArea_)
@@ -467,46 +466,40 @@ void Sasa::initOptions(IOptionsContainer* options, TrajectoryAnalysisSettings* s
                                .description("Total area as a function of time"));
     options->addOption(
             FileNameOption("odg")
-                    .filetype(eftPlot)
+                    .filetype(OptionFileType::Plot)
                     .outputFile()
                     .store(&fnDGSolv_)
                     .defaultBasename("dgsolv")
                     .description("Estimated solvation free energy as a function of time"));
     options->addOption(FileNameOption("or")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnResidueArea_)
                                .defaultBasename("resarea")
                                .description("Average area per residue"));
     options->addOption(FileNameOption("oa")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnAtomArea_)
                                .defaultBasename("atomarea")
                                .description("Average area per atom"));
     options->addOption(FileNameOption("tv")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnVolume_)
                                .defaultBasename("volume")
                                .description("Total volume and density as a function of time"));
     options->addOption(FileNameOption("q")
-                               .filetype(eftPDB)
+                               .filetype(OptionFileType::PDB)
                                .outputFile()
                                .store(&fnConnolly_)
                                .defaultBasename("connolly")
                                .description("PDB file for Connolly surface"));
-    // options->addOption(FileNameOption("i").filetype(eftITP).outputFile()
-    //                       .store(&fnRestraints_).defaultBasename("surfat")
-    //                       .description("Topology file for position restraings on surface atoms"));
-
 
     options->addOption(
             DoubleOption("probe").store(&solsize_).description("Radius of the solvent probe (nm)"));
     options->addOption(IntegerOption("ndots").store(&ndots_).description(
             "Number of dots per sphere, more dots means more accuracy"));
-    // options->addOption(DoubleOption("minarea").store(&minarea_)
-    //                       .description("The minimum area (nm^2) to count an atom as a surface atom when writing a position restraint file (see help)"));
     options->addOption(
             BooleanOption("prot").store(&bIncludeSolute_).description("Output the protein to the Connolly [REF].pdb[ref] file too"));
     options->addOption(
@@ -549,12 +542,6 @@ void Sasa::initAnalysis(const TrajectoryAnalysisSettings& settings, const Topolo
     }
 
     please_cite(stderr, "Eisenhaber95");
-    // if ((top.pbcType() != PbcType::Xyz) || (TRICLINIC(fr.box)))
-    //{
-    //    fprintf(stderr, "\n\nWARNING: non-rectangular boxes may give erroneous results or crashes.\n"
-    //            "Analysis based on vacuum simulations (with the possibility of evaporation)\n"
-    //            "will certainly crash the analysis.\n\n");
-    //}
 
     if (bDGsol)
     {
@@ -601,7 +588,7 @@ void Sasa::initAnalysis(const TrajectoryAnalysisSettings& settings, const Topolo
     {
         const int ii     = atomIndices[i];
         const int resind = atoms_->atom[ii].resind;
-        real      radius;
+        real      radius = 0;
         if (!aps.setAtomProperty(epropVDW, *(atoms_->resinfo[resind].name), *(atoms_->atomname[ii]), &radius))
         {
             ndefault++;
@@ -609,9 +596,9 @@ void Sasa::initAnalysis(const TrajectoryAnalysisSettings& settings, const Topolo
         radii_.push_back(radius + solsize_);
         if (bDGsol)
         {
-            real dgsFactor;
-            if (!aps.setAtomProperty(epropDGsol, *(atoms_->resinfo[resind].name),
-                                     *(atoms_->atomtype[ii]), &dgsFactor))
+            real dgsFactor = 0;
+            if (!aps.setAtomProperty(
+                        epropDGsol, *(atoms_->resinfo[resind].name), *(atoms_->atomtype[ii]), &dgsFactor))
             {
                 dgsFactor = dgsDefault_;
             }
@@ -640,7 +627,8 @@ void Sasa::initAnalysis(const TrajectoryAnalysisSettings& settings, const Topolo
                         "Output selection '%s' is not a subset of "
                         "the surface selection (atom %d is the first "
                         "atom not in the surface selection)",
-                        outputSel_[g].name(), outputIndices[i] + 1);
+                        outputSel_[g].name(),
+                        outputIndices[i] + 1);
                 GMX_THROW(InconsistentInputError(message));
             }
             outputSel_[g].setOriginalId(i, j);
@@ -906,8 +894,8 @@ void Sasa::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, TrajectoryAn
     AnalysisDataHandle   aah        = pdata->dataHandle(atomArea_);
     AnalysisDataHandle   rah        = pdata->dataHandle(residueArea_);
     AnalysisDataHandle   vh         = pdata->dataHandle(volume_);
-    const Selection&     surfaceSel = TrajectoryAnalysisModuleData::parallelSelection(surfaceSel_);
-    const SelectionList& outputSel  = TrajectoryAnalysisModuleData::parallelSelections(outputSel_);
+    const Selection&     surfaceSel = pdata->parallelSelection(surfaceSel_);
+    const SelectionList& outputSel  = pdata->parallelSelections(outputSel_);
     SasaModuleData&      frameData  = *static_cast<SasaModuleData*>(pdata);
 
     const bool bResAt    = !frameData.res_a_.empty();
@@ -947,11 +935,19 @@ void Sasa::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, TrajectoryAn
     // area array contains the per-atom areas for the selected positions.
     // surfacedots contains nsurfacedots entries, and contains the actual
     // points.
-    real  totarea, totvolume;
+    real  totarea   = 0;
+    real  totvolume = 0;
     real *area = nullptr, *surfacedots = nullptr;
-    int   nsurfacedots;
-    calculator_.calculate(surfaceSel.coordinates().data(), pbc, frameData.index_.size(),
-                          frameData.index_.data(), flag, &totarea, &totvolume, &area, &surfacedots,
+    int   nsurfacedots = 0;
+    calculator_.calculate(surfaceSel.coordinates().data(),
+                          pbc,
+                          frameData.index_.size(),
+                          frameData.index_.data(),
+                          flag,
+                          &totarea,
+                          &totvolume,
+                          &area,
+                          &surfacedots,
                           &nsurfacedots);
     // Unpack the atomwise areas into the frameData.atomAreas_ array for easier
     // indexing in the case of dynamic surfaceSel.
@@ -985,8 +981,15 @@ void Sasa::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, TrajectoryAn
         // structures.  But since it is only used in the first frame, and no
         // one else uses the topology after initialization, it may just work
         // even with future parallelization.
-        connolly_plot(fnConnolly_.c_str(), nsurfacedots, surfacedots, fr.x, atoms_.get(),
-                      &mtop_->symtab, fr.pbcType, fr.box, bIncludeSolute_);
+        connolly_plot(fnConnolly_.c_str(),
+                      nsurfacedots,
+                      surfacedots,
+                      fr.x,
+                      atoms_.get(),
+                      &mtop_->symtab,
+                      fr.pbcType,
+                      fr.box,
+                      bIncludeSolute_);
     }
 
     ah.startFrame(frnr, fr.time);
@@ -1002,11 +1005,19 @@ void Sasa::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, TrajectoryAn
 
     ah.setPoint(0, totarea);
 
-    real totalArea, dgsolv;
+    real totalArea = 0;
+    real dgsolv    = 0;
     if (bResAt || bDGsol)
     {
-        computeAreas(surfaceSel, surfaceSel, frameData.atomAreas_, dgsFactor_, &totalArea, &dgsolv,
-                     aah, rah, &frameData.res_a_);
+        computeAreas(surfaceSel,
+                     surfaceSel,
+                     frameData.atomAreas_,
+                     dgsFactor_,
+                     &totalArea,
+                     &dgsolv,
+                     aah,
+                     rah,
+                     &frameData.res_a_);
         if (bDGsol)
         {
             dgh.setPoint(0, dgsolv);
@@ -1019,8 +1030,15 @@ void Sasa::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, TrajectoryAn
             aah.selectDataSet(g + 1);
             rah.selectDataSet(g + 1);
         }
-        computeAreas(surfaceSel, outputSel[g], frameData.atomAreas_, dgsFactor_, &totalArea,
-                     &dgsolv, aah, rah, &frameData.res_a_);
+        computeAreas(surfaceSel,
+                     outputSel[g],
+                     frameData.atomAreas_,
+                     dgsFactor_,
+                     &totalArea,
+                     &dgsolv,
+                     aah,
+                     rah,
+                     &frameData.res_a_);
         ah.setPoint(g + 1, totalArea);
         if (bDGsol)
         {
@@ -1046,7 +1064,7 @@ void Sasa::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, TrajectoryAn
         {
             totmass += surfaceSel.position(i).mass();
         }
-        const real density = totmass * AMU / (totvolume * NANO * NANO * NANO);
+        const real density = totmass * gmx::c_amu / (totvolume * gmx::c_nano * gmx::c_nano * gmx::c_nano);
         vh.startFrame(frnr, fr.time);
         vh.setPoint(0, totvolume);
         vh.setPoint(1, density);
@@ -1054,26 +1072,7 @@ void Sasa::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* pbc, TrajectoryAn
     }
 }
 
-void Sasa::finishAnalysis(int /*nframes*/)
-{
-    // if (bITP)
-    //{
-    //    fp3 = ftp2FILE(efITP, nfile, fnm, "w");
-    //    fprintf(fp3, "[ position_restraints ]\n"
-    //            "#define FCX 1000\n"
-    //            "#define FCY 1000\n"
-    //            "#define FCZ 1000\n"
-    //            "; Atom  Type  fx   fy   fz\n");
-    //    for (i = 0; i < nx[0]; i++)
-    //    {
-    //        if (atom_area[i] > minarea)
-    //        {
-    //            fprintf(fp3, "%5d   1     FCX  FCX  FCZ\n", ii+1);
-    //        }
-    //    }
-    //    ffclose(fp3);
-    //}
-}
+void Sasa::finishAnalysis(int /*nframes*/) {}
 
 void Sasa::writeOutput() {}
 
index 77fec1d469a62519c7d188f265c728308ce54775..0ec05b077fb132179a70f2e75c101b2be004980e 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2009,2010,2011,2012,2013 by the GROMACS development team.
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -275,8 +275,9 @@ enum class PdbAtomsSelection : int
 const EnumerationArray<ResidueNumbering, const char*> c_residueNumberingTypeNames = { { "number",
                                                                                         "index" } };
 //! String values corresponding to PdbAtomsSelection.
-const EnumerationArray<PdbAtomsSelection, const char*> c_pdbAtomsTypeNames = { { "all", "maxsel",
-                                                                                 "selected" } };
+const EnumerationArray<PdbAtomsSelection, const char*> c_pdbAtomsTypeNames = {
+    { "all", "maxsel", "selected" }
+};
 
 class Select : public TrajectoryAnalysisModule
 {
@@ -428,50 +429,50 @@ void Select::initOptions(IOptionsContainer* options, TrajectoryAnalysisSettings*
     settings->setHelpText(desc);
 
     options->addOption(FileNameOption("os")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnSize_)
                                .defaultBasename("size")
                                .description("Number of positions in each selection"));
     options->addOption(FileNameOption("oc")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnFrac_)
                                .defaultBasename("cfrac")
                                .description("Covered fraction for each selection"));
     options->addOption(FileNameOption("oi")
-                               .filetype(eftGenericData)
+                               .filetype(OptionFileType::GenericData)
                                .outputFile()
                                .store(&fnIndex_)
                                .defaultBasename("index")
                                .description("Indices selected by each selection"));
     options->addOption(FileNameOption("on")
-                               .filetype(eftIndex)
+                               .filetype(OptionFileType::Index)
                                .outputFile()
                                .store(&fnNdx_)
                                .defaultBasename("index")
                                .description("Index file from the selection"));
     options->addOption(FileNameOption("om")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnMask_)
                                .defaultBasename("mask")
                                .description("Mask for selected positions"));
     options->addOption(FileNameOption("of")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnOccupancy_)
                                .defaultBasename("occupancy")
                                .description("Occupied fraction for selected positions"));
     options->addOption(
             FileNameOption("ofpdb")
-                    .filetype(eftPDB)
+                    .filetype(OptionFileType::PDB)
                     .outputFile()
                     .store(&fnPDB_)
                     .defaultBasename("occupancy")
                     .description("PDB file with occupied fraction for selected positions"));
     options->addOption(FileNameOption("olt")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnLifetime_)
                                .defaultBasename("lifetime")
@@ -626,7 +627,7 @@ void Select::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* /* pbc */, Traj
     AnalysisDataHandle   cdh = pdata->dataHandle(cdata_);
     AnalysisDataHandle   idh = pdata->dataHandle(idata_);
     AnalysisDataHandle   mdh = pdata->dataHandle(mdata_);
-    const SelectionList& sel = TrajectoryAnalysisModuleData::parallelSelections(sel_);
+    const SelectionList& sel = pdata->parallelSelections(sel_);
 
     sdh.startFrame(frnr, fr.time);
     for (size_t g = 0; g < sel.size(); ++g)
index 1e28faf599700073f77745f141f816fab4735bc0..c359f8bd67250354549b8d2a364acef122adbf58 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2007, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
 #include <vector>
 
 #include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/pbc.h"
@@ -125,33 +126,30 @@ static void
 divarc(real x1, real y1, real z1, real x2, real y2, real z2, int div1, int div2, real* xr, real* yr, real* zr)
 {
 
-    real xd, yd, zd, dd, d1, d2, s, x, y, z;
-    real phi, sphi, cphi;
-
-    xd = y1 * z2 - y2 * z1;
-    yd = z1 * x2 - z2 * x1;
-    zd = x1 * y2 - x2 * y1;
-    dd = std::sqrt(xd * xd + yd * yd + zd * zd);
+    const real xd = y1 * z2 - y2 * z1;
+    const real yd = z1 * x2 - z2 * x1;
+    const real zd = x1 * y2 - x2 * y1;
+    const real dd = std::sqrt(xd * xd + yd * yd + zd * zd);
     GMX_ASSERT(dd >= DP_TOL, "Rotation axis vector too short");
 
-    d1 = x1 * x1 + y1 * y1 + z1 * z1;
-    d2 = x2 * x2 + y2 * y2 + z2 * z2;
+    const real d1 = x1 * x1 + y1 * y1 + z1 * z1;
+    const real d2 = x2 * x2 + y2 * y2 + z2 * z2;
     GMX_ASSERT(d1 >= 0.5, "Vector 1 too short");
     GMX_ASSERT(d2 >= 0.5, "Vector 2 too short");
 
-    phi  = safe_asin(dd / std::sqrt(d1 * d2));
-    phi  = phi * (static_cast<real>(div1)) / (static_cast<real>(div2));
-    sphi = sin(phi);
-    cphi = cos(phi);
-    s    = (x1 * xd + y1 * yd + z1 * zd) / dd;
-
-    x   = xd * s * (1. - cphi) / dd + x1 * cphi + (yd * z1 - y1 * zd) * sphi / dd;
-    y   = yd * s * (1. - cphi) / dd + y1 * cphi + (zd * x1 - z1 * xd) * sphi / dd;
-    z   = zd * s * (1. - cphi) / dd + z1 * cphi + (xd * y1 - x1 * yd) * sphi / dd;
-    dd  = std::sqrt(x * x + y * y + z * z);
-    *xr = x / dd;
-    *yr = y / dd;
-    *zr = z / dd;
+    real phi        = safe_asin(dd / std::sqrt(d1 * d2));
+    phi             = phi * (static_cast<real>(div1)) / (static_cast<real>(div2));
+    const real sphi = sin(phi);
+    const real cphi = cos(phi);
+    const real s    = (x1 * xd + y1 * yd + z1 * zd) / dd;
+
+    const real x   = xd * s * (1. - cphi) / dd + x1 * cphi + (yd * z1 - y1 * zd) * sphi / dd;
+    const real y   = yd * s * (1. - cphi) / dd + y1 * cphi + (zd * x1 - z1 * xd) * sphi / dd;
+    const real z   = zd * s * (1. - cphi) / dd + z1 * cphi + (xd * y1 - x1 * yd) * sphi / dd;
+    const real dd2 = std::sqrt(x * x + y * y + z * z);
+    *xr            = x / dd2;
+    *yr            = y / dd2;
+    *zr            = z / dd2;
 }
 
 /* densit...required dots per unit sphere */
@@ -160,14 +158,15 @@ static std::vector<real> ico_dot_arc(int densit)
     /* dot distribution on a unit sphere based on an icosaeder *
      * great circle average refining of icosahedral face       */
 
-    int  i, j, k, tl, tl2, tn;
-    real a, d, x, y, z, x2, y2, z2, x3, y3, z3;
-    real xij, yij, zij, xji, yji, zji, xik, yik, zik, xki, yki, zki, xjk, yjk, zjk, xkj, ykj, zkj;
+    real x2 = NAN, y2 = NAN, z2 = NAN, x3 = NAN, y3 = NAN, z3 = NAN;
+    real xij = NAN, yij = NAN, zij = NAN, xji = NAN, yji = NAN, zji = NAN, xik = NAN, yik = NAN,
+         zik = NAN, xki = NAN, yki = NAN, zki = NAN, xjk = NAN, yjk = NAN, zjk = NAN, xkj = NAN,
+         ykj = NAN, zkj = NAN;
 
     /* calculate tessalation level */
-    a              = std::sqrt(((static_cast<real>(densit)) - 2.) / 10.);
-    const int tess = static_cast<int>(ceil(a));
-    const int ndot = 10 * tess * tess + 2;
+    const real a    = std::sqrt(((static_cast<real>(densit)) - 2.) / 10.);
+    const int  tess = static_cast<int>(ceil(a));
+    const int  ndot = 10 * tess * tess + 2;
     GMX_RELEASE_ASSERT(ndot >= densit, "Inconsistent surface dot formula");
 
     std::vector<real> xus(3 * ndot);
@@ -175,45 +174,54 @@ static std::vector<real> ico_dot_arc(int densit)
 
     if (tess > 1)
     {
-        tn = 12;
-        a  = rh * rh * 2. * (1. - cos(TORAD(72.)));
+        int        tn = 12;
+        const real a  = rh * rh * 2. * (1. - cos(TORAD(72.)));
         /* calculate tessalation of icosaeder edges */
-        for (i = 0; i < 11; i++)
+        for (int i = 0; i < 11; i++)
         {
-            for (j = i + 1; j < 12; j++)
+            for (int j = i + 1; j < 12; j++)
             {
-                x = xus[3 * i] - xus[3 * j];
-                y = xus[1 + 3 * i] - xus[1 + 3 * j];
-                z = xus[2 + 3 * i] - xus[2 + 3 * j];
-                d = x * x + y * y + z * z;
+                const real x = xus[3 * i] - xus[3 * j];
+                const real y = xus[1 + 3 * i] - xus[1 + 3 * j];
+                const real z = xus[2 + 3 * i] - xus[2 + 3 * j];
+                const real d = x * x + y * y + z * z;
                 if (std::fabs(a - d) > DP_TOL)
                 {
                     continue;
                 }
-                for (tl = 1; tl < tess; tl++)
+                for (int tl = 1; tl < tess; tl++)
                 {
                     GMX_ASSERT(tn < ndot, "Inconsistent precomputed surface dot count");
-                    divarc(xus[3 * i], xus[1 + 3 * i], xus[2 + 3 * i], xus[3 * j], xus[1 + 3 * j],
-                           xus[2 + 3 * j], tl, tess, &xus[3 * tn], &xus[1 + 3 * tn], &xus[2 + 3 * tn]);
+                    divarc(xus[3 * i],
+                           xus[1 + 3 * i],
+                           xus[2 + 3 * i],
+                           xus[3 * j],
+                           xus[1 + 3 * j],
+                           xus[2 + 3 * j],
+                           tl,
+                           tess,
+                           &xus[3 * tn],
+                           &xus[1 + 3 * tn],
+                           &xus[2 + 3 * tn]);
                     tn++;
                 }
             }
         }
         /* calculate tessalation of icosaeder faces */
-        for (i = 0; i < 10; i++)
+        for (int i = 0; i < 10; i++)
         {
-            for (j = i + 1; j < 11; j++)
+            for (int j = i + 1; j < 11; j++)
             {
-                x = xus[3 * i] - xus[3 * j];
-                y = xus[1 + 3 * i] - xus[1 + 3 * j];
-                z = xus[2 + 3 * i] - xus[2 + 3 * j];
-                d = x * x + y * y + z * z;
+                real x = xus[3 * i] - xus[3 * j];
+                real y = xus[1 + 3 * i] - xus[1 + 3 * j];
+                real z = xus[2 + 3 * i] - xus[2 + 3 * j];
+                real d = x * x + y * y + z * z;
                 if (std::fabs(a - d) > DP_TOL)
                 {
                     continue;
                 }
 
-                for (k = j + 1; k < 12; k++)
+                for (int k = j + 1; k < 12; k++)
                 {
                     x = xus[3 * i] - xus[3 * k];
                     y = xus[1 + 3 * i] - xus[1 + 3 * k];
@@ -231,23 +239,77 @@ static std::vector<real> ico_dot_arc(int densit)
                     {
                         continue;
                     }
-                    for (tl = 1; tl < tess - 1; tl++)
+                    for (int tl = 1; tl < tess - 1; tl++)
                     {
-                        divarc(xus[3 * j], xus[1 + 3 * j], xus[2 + 3 * j], xus[3 * i],
-                               xus[1 + 3 * i], xus[2 + 3 * i], tl, tess, &xji, &yji, &zji);
-                        divarc(xus[3 * k], xus[1 + 3 * k], xus[2 + 3 * k], xus[3 * i],
-                               xus[1 + 3 * i], xus[2 + 3 * i], tl, tess, &xki, &yki, &zki);
-
-                        for (tl2 = 1; tl2 < tess - tl; tl2++)
+                        divarc(xus[3 * j],
+                               xus[1 + 3 * j],
+                               xus[2 + 3 * j],
+                               xus[3 * i],
+                               xus[1 + 3 * i],
+                               xus[2 + 3 * i],
+                               tl,
+                               tess,
+                               &xji,
+                               &yji,
+                               &zji);
+                        divarc(xus[3 * k],
+                               xus[1 + 3 * k],
+                               xus[2 + 3 * k],
+                               xus[3 * i],
+                               xus[1 + 3 * i],
+                               xus[2 + 3 * i],
+                               tl,
+                               tess,
+                               &xki,
+                               &yki,
+                               &zki);
+
+                        for (int tl2 = 1; tl2 < tess - tl; tl2++)
                         {
-                            divarc(xus[3 * i], xus[1 + 3 * i], xus[2 + 3 * i], xus[3 * j],
-                                   xus[1 + 3 * j], xus[2 + 3 * j], tl2, tess, &xij, &yij, &zij);
-                            divarc(xus[3 * k], xus[1 + 3 * k], xus[2 + 3 * k], xus[3 * j],
-                                   xus[1 + 3 * j], xus[2 + 3 * j], tl2, tess, &xkj, &ykj, &zkj);
-                            divarc(xus[3 * i], xus[1 + 3 * i], xus[2 + 3 * i], xus[3 * k], xus[1 + 3 * k],
-                                   xus[2 + 3 * k], tess - tl - tl2, tess, &xik, &yik, &zik);
-                            divarc(xus[3 * j], xus[1 + 3 * j], xus[2 + 3 * j], xus[3 * k], xus[1 + 3 * k],
-                                   xus[2 + 3 * k], tess - tl - tl2, tess, &xjk, &yjk, &zjk);
+                            divarc(xus[3 * i],
+                                   xus[1 + 3 * i],
+                                   xus[2 + 3 * i],
+                                   xus[3 * j],
+                                   xus[1 + 3 * j],
+                                   xus[2 + 3 * j],
+                                   tl2,
+                                   tess,
+                                   &xij,
+                                   &yij,
+                                   &zij);
+                            divarc(xus[3 * k],
+                                   xus[1 + 3 * k],
+                                   xus[2 + 3 * k],
+                                   xus[3 * j],
+                                   xus[1 + 3 * j],
+                                   xus[2 + 3 * j],
+                                   tl2,
+                                   tess,
+                                   &xkj,
+                                   &ykj,
+                                   &zkj);
+                            divarc(xus[3 * i],
+                                   xus[1 + 3 * i],
+                                   xus[2 + 3 * i],
+                                   xus[3 * k],
+                                   xus[1 + 3 * k],
+                                   xus[2 + 3 * k],
+                                   tess - tl - tl2,
+                                   tess,
+                                   &xik,
+                                   &yik,
+                                   &zik);
+                            divarc(xus[3 * j],
+                                   xus[1 + 3 * j],
+                                   xus[2 + 3 * j],
+                                   xus[3 * k],
+                                   xus[1 + 3 * k],
+                                   xus[2 + 3 * k],
+                                   tess - tl - tl2,
+                                   tess,
+                                   &xjk,
+                                   &yjk,
+                                   &zjk);
                             divarc(xki, yki, zki, xji, yji, zji, tl2, tess - tl, &x, &y, &z);
                             divarc(xkj, ykj, zkj, xij, yij, zij, tl, tess - tl2, &x2, &y2, &z2);
                             divarc(xjk, yjk, zjk, xik, yik, zik, tl, tl + tl2, &x3, &y3, &z3);
@@ -277,57 +339,62 @@ static std::vector<real> ico_dot_dod(int densit)
     /* dot distribution on a unit sphere based on an icosaeder *
      * great circle average refining of icosahedral face       */
 
-    int  i, j, k, tl, tl2, tn, tess, j1, j2;
-    real a, d, x, y, z, x2, y2, z2, x3, y3, z3, ai_d, adod;
-    real xij, yij, zij, xji, yji, zji, xik, yik, zik, xki, yki, zki, xjk, yjk, zjk, xkj, ykj, zkj;
+    real x2 = NAN, y2 = NAN, z2 = NAN, x3 = NAN, y3 = NAN, z3 = NAN;
+    real xij = NAN, yij = NAN, zij = NAN, xji = NAN, yji = NAN, zji = NAN, xik = NAN, yik = NAN,
+         zik = NAN, xki = NAN, yki = NAN, zki = NAN, xjk = NAN, yjk = NAN, zjk = NAN, xkj = NAN,
+         ykj = NAN, zkj = NAN;
 
     /* calculate tesselation level */
-    a              = std::sqrt(((static_cast<real>(densit)) - 2.) / 30.);
-    tess           = std::max(static_cast<int>(ceil(a)), 1);
+    real      a    = std::sqrt(((static_cast<real>(densit)) - 2.) / 30.);
+    const int tess = std::max(static_cast<int>(ceil(a)), 1);
     const int ndot = 30 * tess * tess + 2;
     GMX_RELEASE_ASSERT(ndot >= densit, "Inconsistent surface dot formula");
 
     std::vector<real> xus(3 * ndot);
     const real        rh = icosaeder_vertices(xus.data());
 
-    tn = 12;
+    int tn = 12;
     /* square of the edge of an icosaeder */
     a = rh * rh * 2. * (1. - cos(TORAD(72.)));
     /* dodecaeder vertices */
-    for (i = 0; i < 10; i++)
+    for (int i = 0; i < 10; i++)
     {
-        for (j = i + 1; j < 11; j++)
+        for (int j = i + 1; j < 11; j++)
         {
-            x = xus[3 * i] - xus[3 * j];
-            y = xus[1 + 3 * i] - xus[1 + 3 * j];
-            z = xus[2 + 3 * i] - xus[2 + 3 * j];
-            d = x * x + y * y + z * z;
+            const real x = xus[3 * i] - xus[3 * j];
+            const real y = xus[1 + 3 * i] - xus[1 + 3 * j];
+            const real z = xus[2 + 3 * i] - xus[2 + 3 * j];
+            const real d = x * x + y * y + z * z;
             if (std::fabs(a - d) > DP_TOL)
             {
                 continue;
             }
-            for (k = j + 1; k < 12; k++)
+            for (int k = j + 1; k < 12; k++)
             {
-                x = xus[3 * i] - xus[3 * k];
-                y = xus[1 + 3 * i] - xus[1 + 3 * k];
-                z = xus[2 + 3 * i] - xus[2 + 3 * k];
-                d = x * x + y * y + z * z;
-                if (std::fabs(a - d) > DP_TOL)
                 {
-                    continue;
+                    const real x = xus[3 * i] - xus[3 * k];
+                    const real y = xus[1 + 3 * i] - xus[1 + 3 * k];
+                    const real z = xus[2 + 3 * i] - xus[2 + 3 * k];
+                    const real d = x * x + y * y + z * z;
+                    if (std::fabs(a - d) > DP_TOL)
+                    {
+                        continue;
+                    }
                 }
-                x = xus[3 * j] - xus[3 * k];
-                y = xus[1 + 3 * j] - xus[1 + 3 * k];
-                z = xus[2 + 3 * j] - xus[2 + 3 * k];
-                d = x * x + y * y + z * z;
-                if (std::fabs(a - d) > DP_TOL)
                 {
-                    continue;
+                    const real x = xus[3 * j] - xus[3 * k];
+                    const real y = xus[1 + 3 * j] - xus[1 + 3 * k];
+                    const real z = xus[2 + 3 * j] - xus[2 + 3 * k];
+                    const real d = x * x + y * y + z * z;
+                    if (std::fabs(a - d) > DP_TOL)
+                    {
+                        continue;
+                    }
                 }
-                x               = xus[3 * i] + xus[3 * j] + xus[3 * k];
-                y               = xus[1 + 3 * i] + xus[1 + 3 * j] + xus[1 + 3 * k];
-                z               = xus[2 + 3 * i] + xus[2 + 3 * j] + xus[2 + 3 * k];
-                d               = std::sqrt(x * x + y * y + z * z);
+                const real x    = xus[3 * i] + xus[3 * j] + xus[3 * k];
+                const real y    = xus[1 + 3 * i] + xus[1 + 3 * j] + xus[1 + 3 * k];
+                const real z    = xus[2 + 3 * i] + xus[2 + 3 * j] + xus[2 + 3 * k];
+                const real d    = std::sqrt(x * x + y * y + z * z);
                 xus[3 * tn]     = x / d;
                 xus[1 + 3 * tn] = y / d;
                 xus[2 + 3 * tn] = z / d;
@@ -338,62 +405,71 @@ static std::vector<real> ico_dot_dod(int densit)
 
     if (tess > 1)
     {
-        tn = 32;
+        int tn = 32;
         /* square of the edge of an dodecaeder */
-        adod = 4. * (cos(TORAD(108.)) - cos(TORAD(120.))) / (1. - cos(TORAD(120.)));
+        const real adod = 4. * (cos(TORAD(108.)) - cos(TORAD(120.))) / (1. - cos(TORAD(120.)));
         /* square of the distance of two adjacent vertices of ico- and dodecaeder */
-        ai_d = 2. * (1. - std::sqrt(1. - a / 3.));
+        const real ai_d = 2. * (1. - std::sqrt(1. - a / 3.));
 
         /* calculate tessalation of mixed edges */
-        for (i = 0; i < 31; i++)
+        for (int i = 0; i < 31; i++)
         {
-            j1 = 12;
-            j2 = 32;
-            a  = ai_d;
+            int j1 = 12;
+            int j2 = 32;
+            a      = ai_d;
             if (i >= 12)
             {
                 j1 = i + 1;
                 a  = adod;
             }
-            for (j = j1; j < j2; j++)
+            for (int j = j1; j < j2; j++)
             {
-                x = xus[3 * i] - xus[3 * j];
-                y = xus[1 + 3 * i] - xus[1 + 3 * j];
-                z = xus[2 + 3 * i] - xus[2 + 3 * j];
-                d = x * x + y * y + z * z;
+                const real x = xus[3 * i] - xus[3 * j];
+                const real y = xus[1 + 3 * i] - xus[1 + 3 * j];
+                const real z = xus[2 + 3 * i] - xus[2 + 3 * j];
+                const real d = x * x + y * y + z * z;
                 if (std::fabs(a - d) > DP_TOL)
                 {
                     continue;
                 }
-                for (tl = 1; tl < tess; tl++)
+                for (int tl = 1; tl < tess; tl++)
                 {
                     GMX_ASSERT(tn < ndot, "Inconsistent precomputed surface dot count");
-                    divarc(xus[3 * i], xus[1 + 3 * i], xus[2 + 3 * i], xus[3 * j], xus[1 + 3 * j],
-                           xus[2 + 3 * j], tl, tess, &xus[3 * tn], &xus[1 + 3 * tn], &xus[2 + 3 * tn]);
+                    divarc(xus[3 * i],
+                           xus[1 + 3 * i],
+                           xus[2 + 3 * i],
+                           xus[3 * j],
+                           xus[1 + 3 * j],
+                           xus[2 + 3 * j],
+                           tl,
+                           tess,
+                           &xus[3 * tn],
+                           &xus[1 + 3 * tn],
+                           &xus[2 + 3 * tn]);
                     tn++;
                 }
             }
         }
         /* calculate tessalation of pentakisdodecahedron faces */
-        for (i = 0; i < 12; i++)
+        for (int i = 0; i < 12; i++)
         {
-            for (j = 12; j < 31; j++)
+            for (int j = 12; j < 31; j++)
             {
-                x = xus[3 * i] - xus[3 * j];
-                y = xus[1 + 3 * i] - xus[1 + 3 * j];
-                z = xus[2 + 3 * i] - xus[2 + 3 * j];
-                d = x * x + y * y + z * z;
+                const real x = xus[3 * i] - xus[3 * j];
+                const real y = xus[1 + 3 * i] - xus[1 + 3 * j];
+                const real z = xus[2 + 3 * i] - xus[2 + 3 * j];
+                const real d = x * x + y * y + z * z;
                 if (std::fabs(ai_d - d) > DP_TOL)
                 {
                     continue;
                 }
 
-                for (k = j + 1; k < 32; k++)
+                for (int k = j + 1; k < 32; k++)
                 {
-                    x = xus[3 * i] - xus[3 * k];
-                    y = xus[1 + 3 * i] - xus[1 + 3 * k];
-                    z = xus[2 + 3 * i] - xus[2 + 3 * k];
-                    d = x * x + y * y + z * z;
+                    real x = xus[3 * i] - xus[3 * k];
+                    real y = xus[1 + 3 * i] - xus[1 + 3 * k];
+                    real z = xus[2 + 3 * i] - xus[2 + 3 * k];
+                    real d = x * x + y * y + z * z;
                     if (std::fabs(ai_d - d) > DP_TOL)
                     {
                         continue;
@@ -406,23 +482,77 @@ static std::vector<real> ico_dot_dod(int densit)
                     {
                         continue;
                     }
-                    for (tl = 1; tl < tess - 1; tl++)
+                    for (int tl = 1; tl < tess - 1; tl++)
                     {
-                        divarc(xus[3 * j], xus[1 + 3 * j], xus[2 + 3 * j], xus[3 * i],
-                               xus[1 + 3 * i], xus[2 + 3 * i], tl, tess, &xji, &yji, &zji);
-                        divarc(xus[3 * k], xus[1 + 3 * k], xus[2 + 3 * k], xus[3 * i],
-                               xus[1 + 3 * i], xus[2 + 3 * i], tl, tess, &xki, &yki, &zki);
-
-                        for (tl2 = 1; tl2 < tess - tl; tl2++)
+                        divarc(xus[3 * j],
+                               xus[1 + 3 * j],
+                               xus[2 + 3 * j],
+                               xus[3 * i],
+                               xus[1 + 3 * i],
+                               xus[2 + 3 * i],
+                               tl,
+                               tess,
+                               &xji,
+                               &yji,
+                               &zji);
+                        divarc(xus[3 * k],
+                               xus[1 + 3 * k],
+                               xus[2 + 3 * k],
+                               xus[3 * i],
+                               xus[1 + 3 * i],
+                               xus[2 + 3 * i],
+                               tl,
+                               tess,
+                               &xki,
+                               &yki,
+                               &zki);
+
+                        for (int tl2 = 1; tl2 < tess - tl; tl2++)
                         {
-                            divarc(xus[3 * i], xus[1 + 3 * i], xus[2 + 3 * i], xus[3 * j],
-                                   xus[1 + 3 * j], xus[2 + 3 * j], tl2, tess, &xij, &yij, &zij);
-                            divarc(xus[3 * k], xus[1 + 3 * k], xus[2 + 3 * k], xus[3 * j],
-                                   xus[1 + 3 * j], xus[2 + 3 * j], tl2, tess, &xkj, &ykj, &zkj);
-                            divarc(xus[3 * i], xus[1 + 3 * i], xus[2 + 3 * i], xus[3 * k], xus[1 + 3 * k],
-                                   xus[2 + 3 * k], tess - tl - tl2, tess, &xik, &yik, &zik);
-                            divarc(xus[3 * j], xus[1 + 3 * j], xus[2 + 3 * j], xus[3 * k], xus[1 + 3 * k],
-                                   xus[2 + 3 * k], tess - tl - tl2, tess, &xjk, &yjk, &zjk);
+                            divarc(xus[3 * i],
+                                   xus[1 + 3 * i],
+                                   xus[2 + 3 * i],
+                                   xus[3 * j],
+                                   xus[1 + 3 * j],
+                                   xus[2 + 3 * j],
+                                   tl2,
+                                   tess,
+                                   &xij,
+                                   &yij,
+                                   &zij);
+                            divarc(xus[3 * k],
+                                   xus[1 + 3 * k],
+                                   xus[2 + 3 * k],
+                                   xus[3 * j],
+                                   xus[1 + 3 * j],
+                                   xus[2 + 3 * j],
+                                   tl2,
+                                   tess,
+                                   &xkj,
+                                   &ykj,
+                                   &zkj);
+                            divarc(xus[3 * i],
+                                   xus[1 + 3 * i],
+                                   xus[2 + 3 * i],
+                                   xus[3 * k],
+                                   xus[1 + 3 * k],
+                                   xus[2 + 3 * k],
+                                   tess - tl - tl2,
+                                   tess,
+                                   &xik,
+                                   &yik,
+                                   &zik);
+                            divarc(xus[3 * j],
+                                   xus[1 + 3 * j],
+                                   xus[2 + 3 * j],
+                                   xus[3 * k],
+                                   xus[1 + 3 * k],
+                                   xus[2 + 3 * k],
+                                   tess - tl - tl2,
+                                   tess,
+                                   &xjk,
+                                   &yjk,
+                                   &zjk);
                             divarc(xki, yki, zki, xji, yji, zji, tl2, tess - tl, &x, &y, &z);
                             divarc(xkj, ykj, zkj, xij, yij, zij, tl, tess - tl2, &x2, &y2, &z2);
                             divarc(xjk, yjk, zjk, xik, yik, zik, tl, tl + tl2, &x3, &y3, &z3);
@@ -448,13 +578,12 @@ static std::vector<real> ico_dot_dod(int densit)
 
 static int unsp_type(int densit)
 {
-    int i1, i2;
-    i1 = 1;
+    int i1 = 1;
     while (10 * i1 * i1 + 2 < densit)
     {
         i1++;
     }
-    i2 = 1;
+    int i2 = 1;
     while (30 * i2 * i2 + 2 < densit)
     {
         i2++;
@@ -471,10 +600,7 @@ static int unsp_type(int densit)
 
 static std::vector<real> make_unsp(int densit, int cubus)
 {
-    int *ico_wk, *ico_pt;
-    int  ico_cube, ico_cube_cb, i, j, k, l, ijk, tn, tl, tl2;
-    int* work;
-    real x, y, z;
+    int ico_cube = 0;
 
     int               mode = unsp_type(densit);
     std::vector<real> xus;
@@ -500,64 +626,64 @@ static std::vector<real> make_unsp(int densit, int cubus)
     }
     else
     {
-        i = 1;
+        int i = 1;
         while (i * i * i * 2 < ndot)
         {
             i++;
         }
         ico_cube = std::max(i - 1, 0);
     }
-    ico_cube_cb         = ico_cube * ico_cube * ico_cube;
-    const real del_cube = 2. / (static_cast<real>(ico_cube));
-    snew(work, ndot);
-    for (l = 0; l < ndot; l++)
+    int              ico_cube_cb = ico_cube * ico_cube * ico_cube;
+    const real       del_cube    = 2. / (static_cast<real>(ico_cube));
+    std::vector<int> work;
+    for (int l = 0; l < ndot; l++)
     {
-        i = std::max(static_cast<int>(floor((1. + xus[3 * l]) / del_cube)), 0);
+        int i = std::max(static_cast<int>(floor((1. + xus[3 * l]) / del_cube)), 0);
         if (i >= ico_cube)
         {
             i = ico_cube - 1;
         }
-        j = std::max(static_cast<int>(floor((1. + xus[1 + 3 * l]) / del_cube)), 0);
+        int j = std::max(static_cast<int>(floor((1. + xus[1 + 3 * l]) / del_cube)), 0);
         if (j >= ico_cube)
         {
             j = ico_cube - 1;
         }
-        k = std::max(static_cast<int>(floor((1. + xus[2 + 3 * l]) / del_cube)), 0);
+        int k = std::max(static_cast<int>(floor((1. + xus[2 + 3 * l]) / del_cube)), 0);
         if (k >= ico_cube)
         {
             k = ico_cube - 1;
         }
-        ijk     = i + j * ico_cube + k * ico_cube * ico_cube;
-        work[l] = ijk;
+        int ijk = i + j * ico_cube + k * ico_cube * ico_cube;
+        work.emplace_back(ijk);
     }
 
-    snew(ico_wk, 2 * ico_cube_cb + 1);
+    std::vector<int> ico_wk(2 * ico_cube_cb + 1);
 
-    ico_pt = ico_wk + ico_cube_cb;
-    for (l = 0; l < ndot; l++)
+    int* ico_pt = ico_wk.data() + ico_cube_cb;
+    for (int l = 0; l < ndot; l++)
     {
         ico_wk[work[l]]++; /* dots per elementary cube */
     }
 
     /* reordering of the coordinate array in accordance with box number */
-    tn = 0;
-    for (i = 0; i < ico_cube; i++)
+    int tn = 0;
+    for (int i = 0; i < ico_cube; i++)
     {
-        for (j = 0; j < ico_cube; j++)
+        for (int j = 0; j < ico_cube; j++)
         {
-            for (k = 0; k < ico_cube; k++)
+            for (int k = 0; k < ico_cube; k++)
             {
-                tl              = 0;
-                tl2             = tn;
-                ijk             = i + ico_cube * j + ico_cube * ico_cube * k;
+                int tl          = 0;
+                int tl2         = tn;
+                int ijk         = i + ico_cube * j + ico_cube * ico_cube * k;
                 *(ico_pt + ijk) = tn;
-                for (l = tl2; l < ndot; l++)
+                for (int l = tl2; l < ndot; l++)
                 {
                     if (ijk == work[l])
                     {
-                        x               = xus[3 * l];
-                        y               = xus[1 + 3 * l];
-                        z               = xus[2 + 3 * l];
+                        const real x    = xus[3 * l];
+                        const real y    = xus[1 + 3 * l];
+                        const real z    = xus[2 + 3 * l];
                         xus[3 * l]      = xus[3 * tn];
                         xus[1 + 3 * l]  = xus[1 + 3 * tn];
                         xus[2 + 3 * l]  = xus[2 + 3 * tn];
@@ -571,12 +697,10 @@ static std::vector<real> make_unsp(int densit, int cubus)
                         tl++;
                     }
                 }
-                *(ico_wk + ijk) = tl;
+                *(ico_wk.data() + ijk) = tl;
             } /* cycle k */
         }     /* cycle j */
     }         /* cycle i */
-    sfree(ico_wk);
-    sfree(work);
 
     return xus;
 }
@@ -875,8 +999,20 @@ void SurfaceAreaCalculator::calculate(const rvec*  x,
     {
         *n_dots = 0;
     }
-    nsc_dclm_pbc(x, impl_->radius_, nat, &impl_->unitSphereDots_[0], impl_->unitSphereDots_.size() / 3,
-                 flags, area, at_area, volume, lidots, n_dots, index, &impl_->nb_, pbc);
+    nsc_dclm_pbc(x,
+                 impl_->radius_,
+                 nat,
+                 &impl_->unitSphereDots_[0],
+                 impl_->unitSphereDots_.size() / 3,
+                 flags,
+                 area,
+                 at_area,
+                 volume,
+                 lidots,
+                 n_dots,
+                 index,
+                 &impl_->nb_,
+                 pbc);
 }
 
 } // namespace gmx
index cdfab3e7e29214aa3eccc7eb95e806bdf152796d..8129d3c1e134f6f90c44f19b0b6a412b96dee55e 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,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_TRAJECTORYANALYSIS_SURFACEAREA_H
 #define GMX_TRAJECTORYANALYSIS_SURFACEAREA_H
 
+#include <memory>
+
 #include "gromacs/math/vectypes.h"
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/real.h"
 
 struct t_pbc;
@@ -181,7 +182,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 1247ea9b8b5aa22f400e03d93a286e9d57712993..4575a42a299138843e6981bc6e03bee558bae611 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -120,19 +120,19 @@ void Trajectory::initOptions(IOptionsContainer* options, TrajectoryAnalysisSetti
     settings->setHelpText(desc);
 
     options->addOption(FileNameOption("ox")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnX_)
                                .defaultBasename("coord")
                                .description("Coordinates for each position as a function of time"));
     options->addOption(FileNameOption("ov")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnV_)
                                .defaultBasename("veloc")
                                .description("Velocities for each position as a function of time"));
     options->addOption(FileNameOption("of")
-                               .filetype(eftPlot)
+                               .filetype(OptionFileType::Plot)
                                .outputFile()
                                .store(&fnF_)
                                .defaultBasename("force")
@@ -253,7 +253,7 @@ void analyzeFrameImpl(int frnr, const t_trxframe& fr, AnalysisDataHandle* dh, co
 void Trajectory::analyzeFrame(int frnr, const t_trxframe& fr, t_pbc* /* pbc */, TrajectoryAnalysisModuleData* pdata)
 {
     AnalysisDataHandle   dh  = pdata->dataHandle(xdata_);
-    const SelectionList& sel = TrajectoryAnalysisModuleData::parallelSelections(sel_);
+    const SelectionList& sel = pdata->parallelSelections(sel_);
     analyzeFrameImpl(frnr, fr, &dh, sel, [](const SelectionPosition& pos) { return pos.x(); });
     if (fr.bV)
     {
index 2807d5894e725cbfb732ca56cbc226fa8dc001cf..04201be572c85c48b3ce171c19050e5d11cc1cc3 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -230,7 +230,8 @@ void TrajectoryAnalysisRunnerCommon::Impl::initFirstFrame()
             {
                 const std::string message =
                         formatString("Trajectory (%d atoms) does not match topology (%d atoms)",
-                                     fr->natoms, topologyAtomCount);
+                                     fr->natoms,
+                                     topologyAtomCount);
                 GMX_THROW(InconsistentInputError(message));
             }
         }
@@ -280,7 +281,8 @@ void TrajectoryAnalysisRunnerCommon::Impl::initFrameIndexGroup()
         const std::string message = formatString(
                 "Selection specified with -fgroup has %d atoms, but "
                 "the trajectory (-f) has %d atoms.",
-                trajectoryGroup_.atomCount(), fr->natoms);
+                trajectoryGroup_.atomCount(),
+                fr->natoms);
         GMX_THROW(InconsistentInputError(message));
     }
     fr->bIndex = TRUE;
@@ -327,13 +329,13 @@ void TrajectoryAnalysisRunnerCommon::initOptions(IOptionsContainer* options, Tim
 
     // Add common file name arguments.
     options->addOption(FileNameOption("f")
-                               .filetype(eftTrajectory)
+                               .filetype(OptionFileType::Trajectory)
                                .inputFile()
                                .store(&impl_->trjfile_)
                                .defaultBasename("traj")
                                .description("Input trajectory or single configuration"));
     options->addOption(FileNameOption("s")
-                               .filetype(eftTopology)
+                               .filetype(OptionFileType::Topology)
                                .inputFile()
                                .store(&impl_->topfile_)
                                .defaultBasename("topol")
@@ -404,15 +406,15 @@ void TrajectoryAnalysisRunnerCommon::optionsFinished()
 
     if (impl_->bStartTimeSet_)
     {
-        setTimeValue(TBEGIN, impl_->startTime_);
+        setTimeValue(TimeControl::Begin, impl_->startTime_);
     }
     if (impl_->bEndTimeSet_)
     {
-        setTimeValue(TEND, impl_->endTime_);
+        setTimeValue(TimeControl::End, impl_->endTime_);
     }
     if (impl_->bDeltaTimeSet_)
     {
-        setTimeValue(TDELTA, impl_->deltaTime_);
+        setTimeValue(TimeControl::Delta, impl_->deltaTime_);
     }
 }
 
index beb63214aa0168dac094317d64a20da502089a28..91d936df93ae1291dfaa12f5054d774cb1719595 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
- * Copyright (c) 2015,2016,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +43,7 @@
 #ifndef GMX_TRAJECTORYANALYSIS_RUNNERCOMMON_H
 #define GMX_TRAJECTORYANALYSIS_RUNNERCOMMON_H
 
-#include "gromacs/utility/classhelpers.h"
+#include <memory>
 
 struct t_trxframe;
 
@@ -129,7 +129,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
diff --git a/src/gromacs/trajectoryanalysis/tests/.clang-tidy b/src/gromacs/trajectoryanalysis/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index cca089f3142ff98ed90e13d79063cfa6eb832d7c..b211f2d97d8804dc365028aff39677e2112d9406 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2010,2012,2013,2014,2015 by the GROMACS development team.
-# Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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_add_gtest_executable(trajectoryanalysis-test
         distance.cpp
         extract_cluster.cpp
         freevolume.cpp
+        msd.cpp
         pairdist.cpp
         rdf.cpp
         sasa.cpp
@@ -56,6 +57,12 @@ gmx_add_gtest_executable(trajectoryanalysis-test
         )
 gmx_register_gtest_test(TrajectoryAnalysisUnitTests trajectoryanalysis-test SLOW_TEST)
 target_link_libraries(trajectoryanalysis-test PRIVATE analysisdata-test-shared)
+target_link_libraries(trajectoryanalysis-test PRIVATE common)
 
 add_executable(test_selection ${UNITTEST_TARGET_OPTIONS} test_selection.cpp)
-target_link_libraries(test_selection PRIVATE libgromacs ${GMX_EXE_LINKER_FLAGS})
+target_link_libraries(test_selection PRIVATE
+                      common
+                      libgromacs
+                      ${GMX_EXE_LINKER_FLAGS})
+# TODO: Explicitly link to module dependencies.
+target_link_libraries(test_selection PRIVATE legacy_modules)
index 004491019cdd8d7ec29722e725f1a74065b4cdd2..f1aea17efe8aa923d00a96801360127684564b0e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -95,8 +95,9 @@ TEST_F(ConvertTrjModuleTest, WorksWithAtomAdding)
 
 TEST_F(ConvertTrjModuleTest, WorksWithAtomsAndSelection)
 {
-    const char* const cmdline[] = { "convert-trj", "-atoms", "always-from-structure", "-select",
-                                    "not resname = CO2" };
+    const char* const cmdline[] = {
+        "convert-trj", "-atoms", "always-from-structure", "-select", "not resname = CO2"
+    };
     // TODO check output structures once this is supported.
     setTopology("clustsize.tpr");
     setInputFile("-f", "clustsize.pdb");
index 2493d52c2adbab4ca2ef39c67b12133ff44f6b24..d18cf47d8242055be918bf9204772d3b489aff51 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -146,8 +146,9 @@ TEST_F(ExtractClusterModuleTest, WorksWithAllAtoms)
 TEST_F(ExtractClusterModuleTest, WorksWithAtomSubset)
 {
     std::string       realFileName = TestFileManager::getTestSpecificFileName("test.g96");
-    const char* const cmdline[]    = { "extract-cluster", "-o", realFileName.c_str(), "-select",
-                                    "atomnr 1 2" };
+    const char* const cmdline[]    = {
+        "extract-cluster", "-o", realFileName.c_str(), "-select", "atomnr 1 2"
+    };
 
     runTest(CommandLine(cmdline));
     compareFiles();
index 228fd8ee468e45d8c494e9222d33ac244d2ecfea..bb1e0594f0136aaecdd0b6c0cd06e639589d43be 100644 (file)
@@ -207,8 +207,8 @@ void AbstractTrajectoryAnalysisModuleTestFixture::runTest(const CommandLine& arg
             {
                 const char* const     name = dataset->first.c_str();
                 AbstractAnalysisData& data = module.datasetFromName(name);
-                AnalysisDataTestFixture::addReferenceCheckerModule(dataChecker, name, &data,
-                                                                   dataset->second.tolerance);
+                AnalysisDataTestFixture::addReferenceCheckerModule(
+                        dataChecker, name, &data, dataset->second.tolerance);
             }
         }
     }
index 6791b70ce0efa539fcef8fe916707e49ebd343cd..dc3a0a6449e8b4583e775ce3805a169b0e959fec 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_TRAJECTORYANALYSIS_TESTS_MODULETEST_H
 #define GMX_TRAJECTORYANALYSIS_TESTS_MODULETEST_H
 
+#include <memory>
+
 #include <gtest/gtest.h>
 
 #include "gromacs/trajectoryanalysis/analysismodule.h"
-#include "gromacs/utility/classhelpers.h"
 
 #include "testutils/cmdlinetest.h"
 
@@ -180,7 +181,7 @@ protected:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \internal \brief
diff --git a/src/gromacs/trajectoryanalysis/tests/msd.cpp b/src/gromacs/trajectoryanalysis/tests/msd.cpp
new file mode 100644 (file)
index 0000000..16220ea
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 "msd" trajectory analysis module.
+ *
+ * \author Kevin Boyd <kevin44boyd@gmail.com>
+ * \ingroup module_trajectoryanalysis
+ */
+#include "gmxpre.h"
+
+#include "gromacs/trajectoryanalysis/modules/msd.h"
+
+#include <gtest/gtest.h>
+
+#include "gromacs/gmxpreprocess/grompp.h"
+#include "gromacs/utility/path.h"
+#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/textstream.h"
+#include "gromacs/utility/textwriter.h"
+
+#include "testutils/cmdlinetest.h"
+#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
+#include "testutils/testfilemanager.h"
+#include "testutils/textblockmatchers.h"
+
+#include "moduletest.h"
+
+namespace gmx::test
+{
+
+namespace
+{
+
+using gmx::test::CommandLine;
+
+/*! \brief Returns whether or not we care about a header line in an xvg file, for matching purposes.
+ *
+ * \todo This is mostly taken from xvgtest.cpp. We could probably create some modular checker
+ * functionality where each line is compared against a set of subcheckers automatically. Then we
+ * could build matchers like this out of the modular components.
+ */
+bool isRelevantXvgHeader(const std::string& line)
+{
+    return startsWith(line, "@")
+           && (contains(line, " title ") || contains(line, " subtitle ") || contains(line, " label ")
+               || contains(line, "@TYPE ") || contains(line, " legend \""));
+}
+
+//! Helper function to check a single xvg value in a sequence.
+void checkXvgDataPoint(TestReferenceChecker* checker, const std::string& value)
+{
+    checker->checkRealFromString(value, nullptr);
+}
+
+/*! \brief MsdMatcher is effectively an extension of XvgMatcher for gmx msd results.
+ *
+ * In addition to the usual fields XvgMatcher checks, MsdMatcher checks for properly reported
+ * diffusion coefficients.
+ */
+class MsdMatcher : public ITextBlockMatcher
+{
+public:
+    MsdMatcher() = default;
+
+    void checkStream(TextInputStream* stream, TestReferenceChecker* checker) override
+    {
+        checker->setDefaultTolerance(
+                gmx::test::FloatingPointTolerance(gmx::test::absoluteTolerance(1.0e-5)));
+        TestReferenceChecker dCoefficientChecker(
+                checker->checkCompound("XvgLegend", "DiffusionCoefficient"));
+        TestReferenceChecker legendChecker(checker->checkCompound("XvgLegend", "Legend"));
+        TestReferenceChecker dataChecker(checker->checkCompound("XvgData", "Data"));
+        std::string          line;
+        int                  rowCount = 0;
+        while (stream->readLine(&line))
+        {
+            // Legend and titles.
+            if (isRelevantXvgHeader(line))
+            {
+                legendChecker.checkString(stripString(line.substr(1)), nullptr);
+                continue;
+            }
+            // All other comment lines we don't care about.
+            if (startsWith(line, "#") || startsWith(line, "@"))
+            {
+                continue;
+            }
+            // Actual data.
+            const std::vector<std::string> columns = splitString(line);
+            const std::string              id      = formatString("Row%d", rowCount);
+            dataChecker.checkSequence(columns.begin(), columns.end(), id.c_str(), &checkXvgDataPoint);
+            rowCount++;
+        }
+    }
+};
+
+class MsdMatch : public ITextBlockMatcherSettings
+{
+public:
+    [[nodiscard]] TextBlockMatcherPointer createMatcher() const override
+    {
+        return std::make_unique<MsdMatcher>();
+    }
+};
+
+class MsdModuleTest : public gmx::test::TrajectoryAnalysisModuleTestFixture<gmx::analysismodules::MsdInfo>
+{
+public:
+    MsdModuleTest() { setOutputFile("-o", "msd.xvg", MsdMatch()); }
+    // Creates a TPR for the given starting structure and topology. Builds an mdp in place prior
+    // to calling grompp. sets the -s input to the generated tpr
+    void createTpr(const std::string& structure, const std::string& topology, const std::string& index)
+    {
+        std::string tpr             = fileManager().getTemporaryFilePath(".tpr");
+        std::string mdp             = fileManager().getTemporaryFilePath(".mdp");
+        std::string mdpFileContents = gmx::formatString(
+                "cutoff-scheme = verlet\n"
+                "rcoulomb      = 0.85\n"
+                "rvdw          = 0.85\n"
+                "rlist         = 0.85\n");
+        gmx::TextWriter::writeFileFromString(mdp, mdpFileContents);
+
+        // Prepare a .tpr file
+        CommandLine caller;
+        const auto* simDB = gmx::test::TestFileManager::getTestSimulationDatabaseDirectory();
+        caller.append("grompp");
+        caller.addOption("-maxwarn", 0);
+        caller.addOption("-f", mdp.c_str());
+        std::string gro = gmx::Path::join(simDB, structure);
+        caller.addOption("-c", gro.c_str());
+        std::string top = gmx::Path::join(simDB, topology);
+        caller.addOption("-p", top.c_str());
+        std::string ndx = gmx::Path::join(simDB, index);
+        caller.addOption("-n", ndx.c_str());
+        caller.addOption("-o", tpr.c_str());
+        ASSERT_EQ(0, gmx_grompp(caller.argc(), caller.argv()));
+
+        // setInputFile() doesn't like the temporary tpr path.
+        CommandLine& cmdline = commandLine();
+        cmdline.addOption("-s", tpr.c_str());
+    }
+
+    // Convenience function to set input trajectory, tpr, and index, if all of the input files
+    // share a common prefix.
+    void setAllInputs(const std::string& prefix)
+    {
+        setInputFile("-f", prefix + ".xtc");
+        setInputFile("-n", prefix + ".ndx");
+        createTpr(prefix + ".gro", prefix + ".top", prefix + ".ndx");
+    }
+};
+
+// ----------------------------------------------
+// These tests check the basic MSD and diffusion coefficient reporting capabilities on toy systems.
+// Trestart is set to larger than the size of the trajectory so that all frames are only compared
+// against the first frame and diffusion coefficients can be predicted exactly.
+// ----------------------------------------------
+
+// for 3D, (8 + 4 + 0) / 3 should yield 4 cm^2 / s
+TEST_F(MsdModuleTest, threeDimensionalDiffusion)
+{
+    setInputFile("-f", "msd_traj.xtc");
+    setInputFile("-s", "msd_coords.gro");
+    setInputFile("-n", "msd.ndx");
+    const char* const cmdline[] = {
+        "-trestart",
+        "200",
+        "-sel",
+        "0",
+    };
+    runTest(CommandLine(cmdline));
+}
+
+// for lateral z, (8 + 4) / 2 should yield 6 cm^2 /s
+TEST_F(MsdModuleTest, twoDimensionalDiffusion)
+{
+    setInputFile("-f", "msd_traj.xtc");
+    setInputFile("-s", "msd_coords.gro");
+    setInputFile("-n", "msd.ndx");
+    const char* const cmdline[] = { "-trestart", "200", "-lateral", "z", "-sel", "0" };
+    runTest(CommandLine(cmdline));
+}
+
+// for type x, should yield 8 cm^2 / s
+TEST_F(MsdModuleTest, oneDimensionalDiffusion)
+{
+    setInputFile("-f", "msd_traj.xtc");
+    setInputFile("-s", "msd_coords.gro");
+    setInputFile("-n", "msd.ndx");
+    const char* const cmdline[] = { "-trestart", "200", "-type", "x", "-sel", "0" };
+    runTest(CommandLine(cmdline));
+}
+
+// -------------------------------------------------------------------------
+// These tests operate on a more realistic trajectory, with a solvated protein,
+// with 20 frames at a 2 ps dt. Note that this box is also non-square, so we're validating
+// non-trivial pbc removal.
+
+// Group 1 = protein, 2 = all waters, 3 = a subset of 6 water molecules
+// ------------------------------------------------------------------------
+TEST_F(MsdModuleTest, multipleGroupsWork)
+{
+    setAllInputs("alanine_vsite_solvated");
+    // Restart every frame, select protein and water separately. Note that the reported diffusion
+    // coefficient for protein is not well-sampled and doesn't correspond to anything physical.
+    const char* const cmdline[] = { "-trestart", "2", "-sel", "1;2" };
+    runTest(CommandLine(cmdline));
+}
+
+TEST_F(MsdModuleTest, trestartLessThanDt)
+{
+    setAllInputs("alanine_vsite_solvated");
+    const char* const cmdline[] = { "-trestart", "1", "-sel", "2" };
+    runTest(CommandLine(cmdline));
+}
+
+TEST_F(MsdModuleTest, trestartGreaterThanDt)
+{
+    setAllInputs("alanine_vsite_solvated");
+    const char* const cmdline[] = { "-trestart", "10", "-sel", "2" };
+    runTest(CommandLine(cmdline));
+}
+
+TEST_F(MsdModuleTest, molTest)
+{
+    setAllInputs("alanine_vsite_solvated");
+    setOutputFile("-mol", "diff_mol.xvg", MsdMatch());
+    const char* const cmdline[] = { "-trestart", "10", "-sel", "3" };
+    runTest(CommandLine(cmdline));
+}
+
+TEST_F(MsdModuleTest, beginFit)
+{
+    setAllInputs("alanine_vsite_solvated");
+    const char* const cmdline[] = { "-trestart", "2", "-sel", "3", "-beginfit", "20" };
+    runTest(CommandLine(cmdline));
+}
+
+TEST_F(MsdModuleTest, endFit)
+{
+    setAllInputs("alanine_vsite_solvated");
+    const char* const cmdline[] = { "-trestart", "2", "-sel", "3", "-endfit", "25" };
+    runTest(CommandLine(cmdline));
+}
+
+TEST_F(MsdModuleTest, notEnoughPointsForFitErrorEstimate)
+{
+    setAllInputs("alanine_vsite_solvated");
+    const char* const cmdline[] = { "-trestart", "2",        "-beginfit", "5",    "-endfit",
+                                    "9",         "-lateral", "x",         "-sel", "all" };
+    runTest(CommandLine(cmdline));
+}
+
+} // namespace
+
+} // namespace gmx::test
index 8bae34f47d367692a82661dd2a22c1f18253b31d..4fa13642e81d235b458d737f55751f4f99aba4da 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,11 +84,16 @@ TEST_F(RdfModuleTest, BasicTest)
 
 TEST_F(RdfModuleTest, SelectionsSolelyFromIndexFileWork)
 {
-    const char* const cmdline[] = { "rdf", "-bin", "0.05",
+    const char* const cmdline[] = { "rdf",
+                                    "-bin",
+                                    "0.05",
                                     // Use selection that names a group in the index file
-                                    "-ref", "name_OW",
+                                    "-ref",
+                                    "name_OW",
                                     // Use selections that name groups in the index file
-                                    "-sel", "name_OW", "not_name_OW" };
+                                    "-sel",
+                                    "name_OW",
+                                    "not_name_OW" };
     // Note not supplying a topology file to -s
     setTrajectory("spc216.gro");
     setInputFile("-n", "index.ndx");
@@ -99,11 +104,16 @@ TEST_F(RdfModuleTest, SelectionsSolelyFromIndexFileWork)
 
 TEST_F(RdfModuleTest, SelectionsFromBothTopologyFileAndIndexFileWork)
 {
-    const char* const cmdline[] = { "rdf", "-bin", "0.05",
+    const char* const cmdline[] = { "rdf",
+                                    "-bin",
+                                    "0.05",
                                     // Use selection whose parsing requires topology file
-                                    "-ref", "name OW",
+                                    "-ref",
+                                    "name OW",
                                     // Use selections that name groups in the index file
-                                    "-sel", "name_OW", "not_name_OW" };
+                                    "-sel",
+                                    "name_OW",
+                                    "not_name_OW" };
     // Note supplying a topology file to -s
     setTopology("spc216.gro");
     setInputFile("-n", "index.ndx");
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_beginFit.xml b/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_beginFit.xml
new file mode 100644 (file)
index 0000000..e4b6408
--- /dev/null
@@ -0,0 +1,124 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">-trestart 2 -sel 3 -beginfit 20</String>
+  <OutputFiles Name="Files">
+    <File Name="-o">
+      <XvgLegend Name="DiffusionCoefficient"></XvgLegend>
+      <XvgLegend Name="Legend">
+        <String>title "Mean Squared Displacement"</String>
+        <String>xaxis  label "tau (ps)"</String>
+        <String>yaxis  label "MSD (nm\\S2\\N)"</String>
+        <String>TYPE xy</String>
+        <String>s0 legend "D[some_water_subset] = 4.2232 (+/- 0.4722) (1e-5 cm^2/s)"</String>
+      </XvgLegend>
+      <XvgData Name="Data">
+        <Sequence Name="Row0">
+          <Int Name="Length">2</Int>
+          <Real>0.000</Real>
+          <Real>0</Real>
+        </Sequence>
+        <Sequence Name="Row1">
+          <Int Name="Length">2</Int>
+          <Real>2.000</Real>
+          <Real>0.0680311</Real>
+        </Sequence>
+        <Sequence Name="Row2">
+          <Int Name="Length">2</Int>
+          <Real>4.000</Real>
+          <Real>0.126496</Real>
+        </Sequence>
+        <Sequence Name="Row3">
+          <Int Name="Length">2</Int>
+          <Real>6.000</Real>
+          <Real>0.185337</Real>
+        </Sequence>
+        <Sequence Name="Row4">
+          <Int Name="Length">2</Int>
+          <Real>8.000</Real>
+          <Real>0.239227</Real>
+        </Sequence>
+        <Sequence Name="Row5">
+          <Int Name="Length">2</Int>
+          <Real>10.000</Real>
+          <Real>0.278451</Real>
+        </Sequence>
+        <Sequence Name="Row6">
+          <Int Name="Length">2</Int>
+          <Real>12.000</Real>
+          <Real>0.324372</Real>
+        </Sequence>
+        <Sequence Name="Row7">
+          <Int Name="Length">2</Int>
+          <Real>14.000</Real>
+          <Real>0.370175</Real>
+        </Sequence>
+        <Sequence Name="Row8">
+          <Int Name="Length">2</Int>
+          <Real>16.000</Real>
+          <Real>0.43655</Real>
+        </Sequence>
+        <Sequence Name="Row9">
+          <Int Name="Length">2</Int>
+          <Real>18.000</Real>
+          <Real>0.499879</Real>
+        </Sequence>
+        <Sequence Name="Row10">
+          <Int Name="Length">2</Int>
+          <Real>20.000</Real>
+          <Real>0.553128</Real>
+        </Sequence>
+        <Sequence Name="Row11">
+          <Int Name="Length">2</Int>
+          <Real>22.000</Real>
+          <Real>0.582381</Real>
+        </Sequence>
+        <Sequence Name="Row12">
+          <Int Name="Length">2</Int>
+          <Real>24.000</Real>
+          <Real>0.627822</Real>
+        </Sequence>
+        <Sequence Name="Row13">
+          <Int Name="Length">2</Int>
+          <Real>26.000</Real>
+          <Real>0.681663</Real>
+        </Sequence>
+        <Sequence Name="Row14">
+          <Int Name="Length">2</Int>
+          <Real>28.000</Real>
+          <Real>0.770022</Real>
+        </Sequence>
+        <Sequence Name="Row15">
+          <Int Name="Length">2</Int>
+          <Real>30.000</Real>
+          <Real>0.835282</Real>
+        </Sequence>
+        <Sequence Name="Row16">
+          <Int Name="Length">2</Int>
+          <Real>32.000</Real>
+          <Real>0.908245</Real>
+        </Sequence>
+        <Sequence Name="Row17">
+          <Int Name="Length">2</Int>
+          <Real>34.000</Real>
+          <Real>0.90827</Real>
+        </Sequence>
+        <Sequence Name="Row18">
+          <Int Name="Length">2</Int>
+          <Real>36.000</Real>
+          <Real>0.890272</Real>
+        </Sequence>
+        <Sequence Name="Row19">
+          <Int Name="Length">2</Int>
+          <Real>38.000</Real>
+          <Real>0.856884</Real>
+        </Sequence>
+        <Sequence Name="Row20">
+          <Int Name="Length">2</Int>
+          <Real>40.000</Real>
+          <Real>0.913993</Real>
+        </Sequence>
+      </XvgData>
+    </File>
+  </OutputFiles>
+</ReferenceData>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_endFit.xml b/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_endFit.xml
new file mode 100644 (file)
index 0000000..cbb4576
--- /dev/null
@@ -0,0 +1,124 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">-trestart 2 -sel 3 -endfit 25</String>
+  <OutputFiles Name="Files">
+    <File Name="-o">
+      <XvgLegend Name="DiffusionCoefficient"></XvgLegend>
+      <XvgLegend Name="Legend">
+        <String>title "Mean Squared Displacement"</String>
+        <String>xaxis  label "tau (ps)"</String>
+        <String>yaxis  label "MSD (nm\\S2\\N)"</String>
+        <String>TYPE xy</String>
+        <String>s0 legend "D[some_water_subset] = 4.2360 (+/- 0.4344) (1e-5 cm^2/s)"</String>
+      </XvgLegend>
+      <XvgData Name="Data">
+        <Sequence Name="Row0">
+          <Int Name="Length">2</Int>
+          <Real>0.000</Real>
+          <Real>0</Real>
+        </Sequence>
+        <Sequence Name="Row1">
+          <Int Name="Length">2</Int>
+          <Real>2.000</Real>
+          <Real>0.0680311</Real>
+        </Sequence>
+        <Sequence Name="Row2">
+          <Int Name="Length">2</Int>
+          <Real>4.000</Real>
+          <Real>0.126496</Real>
+        </Sequence>
+        <Sequence Name="Row3">
+          <Int Name="Length">2</Int>
+          <Real>6.000</Real>
+          <Real>0.185337</Real>
+        </Sequence>
+        <Sequence Name="Row4">
+          <Int Name="Length">2</Int>
+          <Real>8.000</Real>
+          <Real>0.239227</Real>
+        </Sequence>
+        <Sequence Name="Row5">
+          <Int Name="Length">2</Int>
+          <Real>10.000</Real>
+          <Real>0.278451</Real>
+        </Sequence>
+        <Sequence Name="Row6">
+          <Int Name="Length">2</Int>
+          <Real>12.000</Real>
+          <Real>0.324372</Real>
+        </Sequence>
+        <Sequence Name="Row7">
+          <Int Name="Length">2</Int>
+          <Real>14.000</Real>
+          <Real>0.370175</Real>
+        </Sequence>
+        <Sequence Name="Row8">
+          <Int Name="Length">2</Int>
+          <Real>16.000</Real>
+          <Real>0.43655</Real>
+        </Sequence>
+        <Sequence Name="Row9">
+          <Int Name="Length">2</Int>
+          <Real>18.000</Real>
+          <Real>0.499879</Real>
+        </Sequence>
+        <Sequence Name="Row10">
+          <Int Name="Length">2</Int>
+          <Real>20.000</Real>
+          <Real>0.553128</Real>
+        </Sequence>
+        <Sequence Name="Row11">
+          <Int Name="Length">2</Int>
+          <Real>22.000</Real>
+          <Real>0.582381</Real>
+        </Sequence>
+        <Sequence Name="Row12">
+          <Int Name="Length">2</Int>
+          <Real>24.000</Real>
+          <Real>0.627822</Real>
+        </Sequence>
+        <Sequence Name="Row13">
+          <Int Name="Length">2</Int>
+          <Real>26.000</Real>
+          <Real>0.681663</Real>
+        </Sequence>
+        <Sequence Name="Row14">
+          <Int Name="Length">2</Int>
+          <Real>28.000</Real>
+          <Real>0.770022</Real>
+        </Sequence>
+        <Sequence Name="Row15">
+          <Int Name="Length">2</Int>
+          <Real>30.000</Real>
+          <Real>0.835282</Real>
+        </Sequence>
+        <Sequence Name="Row16">
+          <Int Name="Length">2</Int>
+          <Real>32.000</Real>
+          <Real>0.908245</Real>
+        </Sequence>
+        <Sequence Name="Row17">
+          <Int Name="Length">2</Int>
+          <Real>34.000</Real>
+          <Real>0.90827</Real>
+        </Sequence>
+        <Sequence Name="Row18">
+          <Int Name="Length">2</Int>
+          <Real>36.000</Real>
+          <Real>0.890272</Real>
+        </Sequence>
+        <Sequence Name="Row19">
+          <Int Name="Length">2</Int>
+          <Real>38.000</Real>
+          <Real>0.856884</Real>
+        </Sequence>
+        <Sequence Name="Row20">
+          <Int Name="Length">2</Int>
+          <Real>40.000</Real>
+          <Real>0.913993</Real>
+        </Sequence>
+      </XvgData>
+    </File>
+  </OutputFiles>
+</ReferenceData>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_molTest.xml b/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_molTest.xml
new file mode 100644 (file)
index 0000000..cbdc87d
--- /dev/null
@@ -0,0 +1,165 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">-trestart 10 -sel 3</String>
+  <OutputFiles Name="Files">
+    <File Name="-o">
+      <XvgLegend Name="DiffusionCoefficient"></XvgLegend>
+      <XvgLegend Name="Legend">
+        <String>title "Mean Squared Displacement"</String>
+        <String>xaxis  label "tau (ps)"</String>
+        <String>yaxis  label "MSD (nm\\S2\\N)"</String>
+        <String>TYPE xy</String>
+        <String>s0 legend "D[some_water_subset] = 3.9792 (+/- 0.4600) (1e-5 cm^2/s)"</String>
+      </XvgLegend>
+      <XvgData Name="Data">
+        <Sequence Name="Row0">
+          <Int Name="Length">2</Int>
+          <Real>0.000</Real>
+          <Real>0</Real>
+        </Sequence>
+        <Sequence Name="Row1">
+          <Int Name="Length">2</Int>
+          <Real>2.000</Real>
+          <Real>0.0708522</Real>
+        </Sequence>
+        <Sequence Name="Row2">
+          <Int Name="Length">2</Int>
+          <Real>4.000</Real>
+          <Real>0.0947372</Real>
+        </Sequence>
+        <Sequence Name="Row3">
+          <Int Name="Length">2</Int>
+          <Real>6.000</Real>
+          <Real>0.173871</Real>
+        </Sequence>
+        <Sequence Name="Row4">
+          <Int Name="Length">2</Int>
+          <Real>8.000</Real>
+          <Real>0.224929</Real>
+        </Sequence>
+        <Sequence Name="Row5">
+          <Int Name="Length">2</Int>
+          <Real>10.000</Real>
+          <Real>0.274871</Real>
+        </Sequence>
+        <Sequence Name="Row6">
+          <Int Name="Length">2</Int>
+          <Real>12.000</Real>
+          <Real>0.311595</Real>
+        </Sequence>
+        <Sequence Name="Row7">
+          <Int Name="Length">2</Int>
+          <Real>14.000</Real>
+          <Real>0.356893</Real>
+        </Sequence>
+        <Sequence Name="Row8">
+          <Int Name="Length">2</Int>
+          <Real>16.000</Real>
+          <Real>0.459085</Real>
+        </Sequence>
+        <Sequence Name="Row9">
+          <Int Name="Length">2</Int>
+          <Real>18.000</Real>
+          <Real>0.46479</Real>
+        </Sequence>
+        <Sequence Name="Row10">
+          <Int Name="Length">2</Int>
+          <Real>20.000</Real>
+          <Real>0.545767</Real>
+        </Sequence>
+        <Sequence Name="Row11">
+          <Int Name="Length">2</Int>
+          <Real>22.000</Real>
+          <Real>0.505186</Real>
+        </Sequence>
+        <Sequence Name="Row12">
+          <Int Name="Length">2</Int>
+          <Real>24.000</Real>
+          <Real>0.574966</Real>
+        </Sequence>
+        <Sequence Name="Row13">
+          <Int Name="Length">2</Int>
+          <Real>26.000</Real>
+          <Real>0.66103</Real>
+        </Sequence>
+        <Sequence Name="Row14">
+          <Int Name="Length">2</Int>
+          <Real>28.000</Real>
+          <Real>0.64775</Real>
+        </Sequence>
+        <Sequence Name="Row15">
+          <Int Name="Length">2</Int>
+          <Real>30.000</Real>
+          <Real>0.749603</Real>
+        </Sequence>
+        <Sequence Name="Row16">
+          <Int Name="Length">2</Int>
+          <Real>32.000</Real>
+          <Real>0.804233</Real>
+        </Sequence>
+        <Sequence Name="Row17">
+          <Int Name="Length">2</Int>
+          <Real>34.000</Real>
+          <Real>0.828547</Real>
+        </Sequence>
+        <Sequence Name="Row18">
+          <Int Name="Length">2</Int>
+          <Real>36.000</Real>
+          <Real>0.909855</Real>
+        </Sequence>
+        <Sequence Name="Row19">
+          <Int Name="Length">2</Int>
+          <Real>38.000</Real>
+          <Real>0.721128</Real>
+        </Sequence>
+        <Sequence Name="Row20">
+          <Int Name="Length">2</Int>
+          <Real>40.000</Real>
+          <Real>0.899906</Real>
+        </Sequence>
+      </XvgData>
+    </File>
+    <File Name="-mol">
+      <XvgLegend Name="DiffusionCoefficient"></XvgLegend>
+      <XvgLegend Name="Legend">
+        <String>title "Mean Squared Displacement / Molecule"</String>
+        <String>xaxis  label "Molecule"</String>
+        <String>yaxis  label "D(1e-5 cm^2/s)"</String>
+        <String>TYPE xy</String>
+      </XvgLegend>
+      <XvgData Name="Data">
+        <Sequence Name="Row0">
+          <Int Name="Length">2</Int>
+          <Real>0.000</Real>
+          <Real>4</Real>
+        </Sequence>
+        <Sequence Name="Row1">
+          <Int Name="Length">2</Int>
+          <Real>1.000</Real>
+          <Real>2</Real>
+        </Sequence>
+        <Sequence Name="Row2">
+          <Int Name="Length">2</Int>
+          <Real>2.000</Real>
+          <Real>3</Real>
+        </Sequence>
+        <Sequence Name="Row3">
+          <Int Name="Length">2</Int>
+          <Real>3.000</Real>
+          <Real>3</Real>
+        </Sequence>
+        <Sequence Name="Row4">
+          <Int Name="Length">2</Int>
+          <Real>4.000</Real>
+          <Real>1e+01</Real>
+        </Sequence>
+        <Sequence Name="Row5">
+          <Int Name="Length">2</Int>
+          <Real>5.000</Real>
+          <Real>1</Real>
+        </Sequence>
+      </XvgData>
+    </File>
+  </OutputFiles>
+</ReferenceData>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_multipleGroupsWork.xml b/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_multipleGroupsWork.xml
new file mode 100644 (file)
index 0000000..109e74c
--- /dev/null
@@ -0,0 +1,146 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">-trestart 2 -sel 1;2</String>
+  <OutputFiles Name="Files">
+    <File Name="-o">
+      <XvgLegend Name="DiffusionCoefficient"></XvgLegend>
+      <XvgLegend Name="Legend">
+        <String>title "Mean Squared Displacement"</String>
+        <String>xaxis  label "tau (ps)"</String>
+        <String>yaxis  label "MSD (nm\\S2\\N)"</String>
+        <String>TYPE xy</String>
+        <String>s0 legend "D[   Protein] = 0.0005734 (+/- 1.2675) (1e-5 cm^2/s)"</String>
+        <String>s1 legend "D[     Water] = 5.4502 (+/- 0.2739) (1e-5 cm^2/s)"</String>
+      </XvgLegend>
+      <XvgData Name="Data">
+        <Sequence Name="Row0">
+          <Int Name="Length">3</Int>
+          <Real>0.000</Real>
+          <Real>0</Real>
+          <Real>0</Real>
+        </Sequence>
+        <Sequence Name="Row1">
+          <Int Name="Length">3</Int>
+          <Real>2.000</Real>
+          <Real>0.0218917</Real>
+          <Real>0.0722943</Real>
+        </Sequence>
+        <Sequence Name="Row2">
+          <Int Name="Length">3</Int>
+          <Real>4.000</Real>
+          <Real>0.0376418</Real>
+          <Real>0.13585</Real>
+        </Sequence>
+        <Sequence Name="Row3">
+          <Int Name="Length">3</Int>
+          <Real>6.000</Real>
+          <Real>0.0505145</Real>
+          <Real>0.19875</Real>
+        </Sequence>
+        <Sequence Name="Row4">
+          <Int Name="Length">3</Int>
+          <Real>8.000</Real>
+          <Real>0.0618931</Real>
+          <Real>0.262333</Real>
+        </Sequence>
+        <Sequence Name="Row5">
+          <Int Name="Length">3</Int>
+          <Real>10.000</Real>
+          <Real>0.0757011</Real>
+          <Real>0.324822</Real>
+        </Sequence>
+        <Sequence Name="Row6">
+          <Int Name="Length">3</Int>
+          <Real>12.000</Real>
+          <Real>0.0866048</Real>
+          <Real>0.388126</Real>
+        </Sequence>
+        <Sequence Name="Row7">
+          <Int Name="Length">3</Int>
+          <Real>14.000</Real>
+          <Real>0.0937544</Real>
+          <Real>0.45144</Real>
+        </Sequence>
+        <Sequence Name="Row8">
+          <Int Name="Length">3</Int>
+          <Real>16.000</Real>
+          <Real>0.0982917</Real>
+          <Real>0.515772</Real>
+        </Sequence>
+        <Sequence Name="Row9">
+          <Int Name="Length">3</Int>
+          <Real>18.000</Real>
+          <Real>0.0961307</Real>
+          <Real>0.581858</Real>
+        </Sequence>
+        <Sequence Name="Row10">
+          <Int Name="Length">3</Int>
+          <Real>20.000</Real>
+          <Real>0.0930816</Real>
+          <Real>0.645979</Real>
+        </Sequence>
+        <Sequence Name="Row11">
+          <Int Name="Length">3</Int>
+          <Real>22.000</Real>
+          <Real>0.0958314</Real>
+          <Real>0.708053</Real>
+        </Sequence>
+        <Sequence Name="Row12">
+          <Int Name="Length">3</Int>
+          <Real>24.000</Real>
+          <Real>0.102653</Real>
+          <Real>0.772597</Real>
+        </Sequence>
+        <Sequence Name="Row13">
+          <Int Name="Length">3</Int>
+          <Real>26.000</Real>
+          <Real>0.0928015</Real>
+          <Real>0.84093</Real>
+        </Sequence>
+        <Sequence Name="Row14">
+          <Int Name="Length">3</Int>
+          <Real>28.000</Real>
+          <Real>0.0763908</Real>
+          <Real>0.908325</Real>
+        </Sequence>
+        <Sequence Name="Row15">
+          <Int Name="Length">3</Int>
+          <Real>30.000</Real>
+          <Real>0.0721617</Real>
+          <Real>0.975539</Real>
+        </Sequence>
+        <Sequence Name="Row16">
+          <Int Name="Length">3</Int>
+          <Real>32.000</Real>
+          <Real>0.0722768</Real>
+          <Real>1.04299</Real>
+        </Sequence>
+        <Sequence Name="Row17">
+          <Int Name="Length">3</Int>
+          <Real>34.000</Real>
+          <Real>0.0506321</Real>
+          <Real>1.11211</Real>
+        </Sequence>
+        <Sequence Name="Row18">
+          <Int Name="Length">3</Int>
+          <Real>36.000</Real>
+          <Real>0.0367256</Real>
+          <Real>1.19384</Real>
+        </Sequence>
+        <Sequence Name="Row19">
+          <Int Name="Length">3</Int>
+          <Real>38.000</Real>
+          <Real>0.0418762</Real>
+          <Real>1.27086</Real>
+        </Sequence>
+        <Sequence Name="Row20">
+          <Int Name="Length">3</Int>
+          <Real>40.000</Real>
+          <Real>0.052471</Real>
+          <Real>1.34173</Real>
+        </Sequence>
+      </XvgData>
+    </File>
+  </OutputFiles>
+</ReferenceData>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_notEnoughPointsForFitErrorEstimate.xml b/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_notEnoughPointsForFitErrorEstimate.xml
new file mode 100644 (file)
index 0000000..f3ab37b
--- /dev/null
@@ -0,0 +1,124 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">-trestart 2 -beginfit 5 -endfit 9 -lateral x -sel all</String>
+  <OutputFiles Name="Files">
+    <File Name="-o">
+      <XvgLegend Name="DiffusionCoefficient"></XvgLegend>
+      <XvgLegend Name="Legend">
+        <String>title "Mean Squared Displacement"</String>
+        <String>xaxis  label "tau (ps)"</String>
+        <String>yaxis  label "MSD (nm\\S2\\N)"</String>
+        <String>TYPE xy</String>
+        <String>s0 legend "D[       all] = 5.0364 (+/- 0.0000) (1e-5 cm^2/s)"</String>
+      </XvgLegend>
+      <XvgData Name="Data">
+        <Sequence Name="Row0">
+          <Int Name="Length">2</Int>
+          <Real>0.000</Real>
+          <Real>0</Real>
+        </Sequence>
+        <Sequence Name="Row1">
+          <Int Name="Length">2</Int>
+          <Real>2.000</Real>
+          <Real>0.0469217</Real>
+        </Sequence>
+        <Sequence Name="Row2">
+          <Int Name="Length">2</Int>
+          <Real>4.000</Real>
+          <Real>0.0883056</Real>
+        </Sequence>
+        <Sequence Name="Row3">
+          <Int Name="Length">2</Int>
+          <Real>6.000</Real>
+          <Real>0.128427</Real>
+        </Sequence>
+        <Sequence Name="Row4">
+          <Int Name="Length">2</Int>
+          <Real>8.000</Real>
+          <Real>0.168888</Real>
+        </Sequence>
+        <Sequence Name="Row5">
+          <Int Name="Length">2</Int>
+          <Real>10.000</Real>
+          <Real>0.209869</Real>
+        </Sequence>
+        <Sequence Name="Row6">
+          <Int Name="Length">2</Int>
+          <Real>12.000</Real>
+          <Real>0.251233</Real>
+        </Sequence>
+        <Sequence Name="Row7">
+          <Int Name="Length">2</Int>
+          <Real>14.000</Real>
+          <Real>0.292567</Real>
+        </Sequence>
+        <Sequence Name="Row8">
+          <Int Name="Length">2</Int>
+          <Real>16.000</Real>
+          <Real>0.334993</Real>
+        </Sequence>
+        <Sequence Name="Row9">
+          <Int Name="Length">2</Int>
+          <Real>18.000</Real>
+          <Real>0.378822</Real>
+        </Sequence>
+        <Sequence Name="Row10">
+          <Int Name="Length">2</Int>
+          <Real>20.000</Real>
+          <Real>0.420988</Real>
+        </Sequence>
+        <Sequence Name="Row11">
+          <Int Name="Length">2</Int>
+          <Real>22.000</Real>
+          <Real>0.461147</Real>
+        </Sequence>
+        <Sequence Name="Row12">
+          <Int Name="Length">2</Int>
+          <Real>24.000</Real>
+          <Real>0.503649</Real>
+        </Sequence>
+        <Sequence Name="Row13">
+          <Int Name="Length">2</Int>
+          <Real>26.000</Real>
+          <Real>0.548967</Real>
+        </Sequence>
+        <Sequence Name="Row14">
+          <Int Name="Length">2</Int>
+          <Real>28.000</Real>
+          <Real>0.594155</Real>
+        </Sequence>
+        <Sequence Name="Row15">
+          <Int Name="Length">2</Int>
+          <Real>30.000</Real>
+          <Real>0.640334</Real>
+        </Sequence>
+        <Sequence Name="Row16">
+          <Int Name="Length">2</Int>
+          <Real>32.000</Real>
+          <Real>0.684822</Real>
+        </Sequence>
+        <Sequence Name="Row17">
+          <Int Name="Length">2</Int>
+          <Real>34.000</Real>
+          <Real>0.729676</Real>
+        </Sequence>
+        <Sequence Name="Row18">
+          <Int Name="Length">2</Int>
+          <Real>36.000</Real>
+          <Real>0.784167</Real>
+        </Sequence>
+        <Sequence Name="Row19">
+          <Int Name="Length">2</Int>
+          <Real>38.000</Real>
+          <Real>0.843655</Real>
+        </Sequence>
+        <Sequence Name="Row20">
+          <Int Name="Length">2</Int>
+          <Real>40.000</Real>
+          <Real>0.886678</Real>
+        </Sequence>
+      </XvgData>
+    </File>
+  </OutputFiles>
+</ReferenceData>
similarity index 67%
rename from src/gromacs/gmxana/tests/refdata/MsdTest_oneDimensionalDiffusion.xml
rename to src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_oneDimensionalDiffusion.xml
index 4ba6e247781cbc0e52f32f9bfe15d2edc5b56d2b..555a82052f78e8f20fd86684e8b09348d9469a03 100644 (file)
@@ -1,65 +1,66 @@
 <?xml version="1.0"?>
 <?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
 <ReferenceData>
+  <String Name="CommandLine">-trestart 200 -type x -sel 0</String>
   <OutputFiles Name="Files">
     <File Name="-o">
+      <XvgLegend Name="DiffusionCoefficient"></XvgLegend>
       <XvgLegend Name="Legend">
-        <String Name="XvgLegend"><![CDATA[
-title "Mean Square Displacement"
-xaxis  label "Time (ps)"
-yaxis  label "MSD (nm\S2\N)"
-TYPE xy
-]]></String>
+        <String>title "Mean Squared Displacement"</String>
+        <String>xaxis  label "tau (ps)"</String>
+        <String>yaxis  label "MSD (nm\\S2\\N)"</String>
+        <String>TYPE xy</String>
+        <String>s0 legend "D[ particles] = 8.0000 (+/- 0.0000) (1e-5 cm^2/s)"</String>
       </XvgLegend>
       <XvgData Name="Data">
         <Sequence Name="Row0">
           <Int Name="Length">2</Int>
-          <Real>0</Real>
+          <Real>0.000</Real>
           <Real>0</Real>
         </Sequence>
         <Sequence Name="Row1">
           <Int Name="Length">2</Int>
-          <Real>1</Real>
+          <Real>1.000</Real>
           <Real>0.016</Real>
         </Sequence>
         <Sequence Name="Row2">
           <Int Name="Length">2</Int>
-          <Real>2</Real>
+          <Real>2.000</Real>
           <Real>0.032</Real>
         </Sequence>
         <Sequence Name="Row3">
           <Int Name="Length">2</Int>
-          <Real>3</Real>
+          <Real>3.000</Real>
           <Real>0.048</Real>
         </Sequence>
         <Sequence Name="Row4">
           <Int Name="Length">2</Int>
-          <Real>4</Real>
+          <Real>4.000</Real>
           <Real>0.064</Real>
         </Sequence>
         <Sequence Name="Row5">
           <Int Name="Length">2</Int>
-          <Real>5</Real>
+          <Real>5.000</Real>
           <Real>0.08</Real>
         </Sequence>
         <Sequence Name="Row6">
           <Int Name="Length">2</Int>
-          <Real>6</Real>
+          <Real>6.000</Real>
           <Real>0.096</Real>
         </Sequence>
         <Sequence Name="Row7">
           <Int Name="Length">2</Int>
-          <Real>7</Real>
+          <Real>7.000</Real>
           <Real>0.112</Real>
         </Sequence>
         <Sequence Name="Row8">
           <Int Name="Length">2</Int>
-          <Real>8</Real>
+          <Real>8.000</Real>
           <Real>0.128</Real>
         </Sequence>
         <Sequence Name="Row9">
           <Int Name="Length">2</Int>
-          <Real>9</Real>
+          <Real>9.000</Real>
           <Real>0.144</Real>
         </Sequence>
       </XvgData>
similarity index 67%
rename from src/gromacs/gmxana/tests/refdata/MsdTest_twoDimensionalDiffusion.xml
rename to src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_threeDimensionalDiffusion.xml
index 5f04b7857bcf9cf2785133935834cecb9b60d9fd..f6195fd0fb90462b74e879b143d4ef3c8aa3d9f3 100644 (file)
@@ -1,65 +1,66 @@
 <?xml version="1.0"?>
 <?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
 <ReferenceData>
+  <String Name="CommandLine">-trestart 200 -sel 0</String>
   <OutputFiles Name="Files">
     <File Name="-o">
+      <XvgLegend Name="DiffusionCoefficient"></XvgLegend>
       <XvgLegend Name="Legend">
-        <String Name="XvgLegend"><![CDATA[
-title "Mean Square Displacement"
-xaxis  label "Time (ps)"
-yaxis  label "MSD (nm\S2\N)"
-TYPE xy
-]]></String>
+        <String>title "Mean Squared Displacement"</String>
+        <String>xaxis  label "tau (ps)"</String>
+        <String>yaxis  label "MSD (nm\\S2\\N)"</String>
+        <String>TYPE xy</String>
+        <String>s0 legend "D[ particles] = 4.0000 (+/- 0.0000) (1e-5 cm^2/s)"</String>
       </XvgLegend>
       <XvgData Name="Data">
         <Sequence Name="Row0">
           <Int Name="Length">2</Int>
-          <Real>0</Real>
+          <Real>0.000</Real>
           <Real>0</Real>
         </Sequence>
         <Sequence Name="Row1">
           <Int Name="Length">2</Int>
-          <Real>1</Real>
+          <Real>1.000</Real>
           <Real>0.024</Real>
         </Sequence>
         <Sequence Name="Row2">
           <Int Name="Length">2</Int>
-          <Real>2</Real>
+          <Real>2.000</Real>
           <Real>0.048</Real>
         </Sequence>
         <Sequence Name="Row3">
           <Int Name="Length">2</Int>
-          <Real>3</Real>
+          <Real>3.000</Real>
           <Real>0.072</Real>
         </Sequence>
         <Sequence Name="Row4">
           <Int Name="Length">2</Int>
-          <Real>4</Real>
+          <Real>4.000</Real>
           <Real>0.096</Real>
         </Sequence>
         <Sequence Name="Row5">
           <Int Name="Length">2</Int>
-          <Real>5</Real>
+          <Real>5.000</Real>
           <Real>0.12</Real>
         </Sequence>
         <Sequence Name="Row6">
           <Int Name="Length">2</Int>
-          <Real>6</Real>
+          <Real>6.000</Real>
           <Real>0.144</Real>
         </Sequence>
         <Sequence Name="Row7">
           <Int Name="Length">2</Int>
-          <Real>7</Real>
+          <Real>7.000</Real>
           <Real>0.168</Real>
         </Sequence>
         <Sequence Name="Row8">
           <Int Name="Length">2</Int>
-          <Real>8</Real>
+          <Real>8.000</Real>
           <Real>0.192</Real>
         </Sequence>
         <Sequence Name="Row9">
           <Int Name="Length">2</Int>
-          <Real>9</Real>
+          <Real>9.000</Real>
           <Real>0.216</Real>
         </Sequence>
       </XvgData>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_trestartGreaterThanDt.xml b/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_trestartGreaterThanDt.xml
new file mode 100644 (file)
index 0000000..be44932
--- /dev/null
@@ -0,0 +1,124 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">-trestart 10 -sel 2</String>
+  <OutputFiles Name="Files">
+    <File Name="-o">
+      <XvgLegend Name="DiffusionCoefficient"></XvgLegend>
+      <XvgLegend Name="Legend">
+        <String>title "Mean Squared Displacement"</String>
+        <String>xaxis  label "tau (ps)"</String>
+        <String>yaxis  label "MSD (nm\\S2\\N)"</String>
+        <String>TYPE xy</String>
+        <String>s0 legend "D[     Water] = 5.3526 (+/- 0.0465) (1e-5 cm^2/s)"</String>
+      </XvgLegend>
+      <XvgData Name="Data">
+        <Sequence Name="Row0">
+          <Int Name="Length">2</Int>
+          <Real>0.000</Real>
+          <Real>0</Real>
+        </Sequence>
+        <Sequence Name="Row1">
+          <Int Name="Length">2</Int>
+          <Real>2.000</Real>
+          <Real>0.0713805</Real>
+        </Sequence>
+        <Sequence Name="Row2">
+          <Int Name="Length">2</Int>
+          <Real>4.000</Real>
+          <Real>0.136132</Real>
+        </Sequence>
+        <Sequence Name="Row3">
+          <Int Name="Length">2</Int>
+          <Real>6.000</Real>
+          <Real>0.202192</Real>
+        </Sequence>
+        <Sequence Name="Row4">
+          <Int Name="Length">2</Int>
+          <Real>8.000</Real>
+          <Real>0.269467</Real>
+        </Sequence>
+        <Sequence Name="Row5">
+          <Int Name="Length">2</Int>
+          <Real>10.000</Real>
+          <Real>0.333361</Real>
+        </Sequence>
+        <Sequence Name="Row6">
+          <Int Name="Length">2</Int>
+          <Real>12.000</Real>
+          <Real>0.389284</Real>
+        </Sequence>
+        <Sequence Name="Row7">
+          <Int Name="Length">2</Int>
+          <Real>14.000</Real>
+          <Real>0.449046</Real>
+        </Sequence>
+        <Sequence Name="Row8">
+          <Int Name="Length">2</Int>
+          <Real>16.000</Real>
+          <Real>0.514649</Real>
+        </Sequence>
+        <Sequence Name="Row9">
+          <Int Name="Length">2</Int>
+          <Real>18.000</Real>
+          <Real>0.59199</Real>
+        </Sequence>
+        <Sequence Name="Row10">
+          <Int Name="Length">2</Int>
+          <Real>20.000</Real>
+          <Real>0.665065</Real>
+        </Sequence>
+        <Sequence Name="Row11">
+          <Int Name="Length">2</Int>
+          <Real>22.000</Real>
+          <Real>0.699726</Real>
+        </Sequence>
+        <Sequence Name="Row12">
+          <Int Name="Length">2</Int>
+          <Real>24.000</Real>
+          <Real>0.74971</Real>
+        </Sequence>
+        <Sequence Name="Row13">
+          <Int Name="Length">2</Int>
+          <Real>26.000</Real>
+          <Real>0.830236</Real>
+        </Sequence>
+        <Sequence Name="Row14">
+          <Int Name="Length">2</Int>
+          <Real>28.000</Real>
+          <Real>0.912884</Real>
+        </Sequence>
+        <Sequence Name="Row15">
+          <Int Name="Length">2</Int>
+          <Real>30.000</Real>
+          <Real>0.984772</Real>
+        </Sequence>
+        <Sequence Name="Row16">
+          <Int Name="Length">2</Int>
+          <Real>32.000</Real>
+          <Real>1.03085</Real>
+        </Sequence>
+        <Sequence Name="Row17">
+          <Int Name="Length">2</Int>
+          <Real>34.000</Real>
+          <Real>1.08669</Real>
+        </Sequence>
+        <Sequence Name="Row18">
+          <Int Name="Length">2</Int>
+          <Real>36.000</Real>
+          <Real>1.18283</Real>
+        </Sequence>
+        <Sequence Name="Row19">
+          <Int Name="Length">2</Int>
+          <Real>38.000</Real>
+          <Real>1.26495</Real>
+        </Sequence>
+        <Sequence Name="Row20">
+          <Int Name="Length">2</Int>
+          <Real>40.000</Real>
+          <Real>1.34173</Real>
+        </Sequence>
+      </XvgData>
+    </File>
+  </OutputFiles>
+</ReferenceData>
diff --git a/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_trestartLessThanDt.xml b/src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_trestartLessThanDt.xml
new file mode 100644 (file)
index 0000000..714f396
--- /dev/null
@@ -0,0 +1,124 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <String Name="CommandLine">-trestart 1 -sel 2</String>
+  <OutputFiles Name="Files">
+    <File Name="-o">
+      <XvgLegend Name="DiffusionCoefficient"></XvgLegend>
+      <XvgLegend Name="Legend">
+        <String>title "Mean Squared Displacement"</String>
+        <String>xaxis  label "tau (ps)"</String>
+        <String>yaxis  label "MSD (nm\\S2\\N)"</String>
+        <String>TYPE xy</String>
+        <String>s0 legend "D[     Water] = 5.4502 (+/- 0.2739) (1e-5 cm^2/s)"</String>
+      </XvgLegend>
+      <XvgData Name="Data">
+        <Sequence Name="Row0">
+          <Int Name="Length">2</Int>
+          <Real>0.000</Real>
+          <Real>0</Real>
+        </Sequence>
+        <Sequence Name="Row1">
+          <Int Name="Length">2</Int>
+          <Real>2.000</Real>
+          <Real>0.0722943</Real>
+        </Sequence>
+        <Sequence Name="Row2">
+          <Int Name="Length">2</Int>
+          <Real>4.000</Real>
+          <Real>0.13585</Real>
+        </Sequence>
+        <Sequence Name="Row3">
+          <Int Name="Length">2</Int>
+          <Real>6.000</Real>
+          <Real>0.19875</Real>
+        </Sequence>
+        <Sequence Name="Row4">
+          <Int Name="Length">2</Int>
+          <Real>8.000</Real>
+          <Real>0.262333</Real>
+        </Sequence>
+        <Sequence Name="Row5">
+          <Int Name="Length">2</Int>
+          <Real>10.000</Real>
+          <Real>0.324822</Real>
+        </Sequence>
+        <Sequence Name="Row6">
+          <Int Name="Length">2</Int>
+          <Real>12.000</Real>
+          <Real>0.388126</Real>
+        </Sequence>
+        <Sequence Name="Row7">
+          <Int Name="Length">2</Int>
+          <Real>14.000</Real>
+          <Real>0.45144</Real>
+        </Sequence>
+        <Sequence Name="Row8">
+          <Int Name="Length">2</Int>
+          <Real>16.000</Real>
+          <Real>0.515772</Real>
+        </Sequence>
+        <Sequence Name="Row9">
+          <Int Name="Length">2</Int>
+          <Real>18.000</Real>
+          <Real>0.581858</Real>
+        </Sequence>
+        <Sequence Name="Row10">
+          <Int Name="Length">2</Int>
+          <Real>20.000</Real>
+          <Real>0.645979</Real>
+        </Sequence>
+        <Sequence Name="Row11">
+          <Int Name="Length">2</Int>
+          <Real>22.000</Real>
+          <Real>0.708053</Real>
+        </Sequence>
+        <Sequence Name="Row12">
+          <Int Name="Length">2</Int>
+          <Real>24.000</Real>
+          <Real>0.772597</Real>
+        </Sequence>
+        <Sequence Name="Row13">
+          <Int Name="Length">2</Int>
+          <Real>26.000</Real>
+          <Real>0.84093</Real>
+        </Sequence>
+        <Sequence Name="Row14">
+          <Int Name="Length">2</Int>
+          <Real>28.000</Real>
+          <Real>0.908325</Real>
+        </Sequence>
+        <Sequence Name="Row15">
+          <Int Name="Length">2</Int>
+          <Real>30.000</Real>
+          <Real>0.975539</Real>
+        </Sequence>
+        <Sequence Name="Row16">
+          <Int Name="Length">2</Int>
+          <Real>32.000</Real>
+          <Real>1.04299</Real>
+        </Sequence>
+        <Sequence Name="Row17">
+          <Int Name="Length">2</Int>
+          <Real>34.000</Real>
+          <Real>1.11211</Real>
+        </Sequence>
+        <Sequence Name="Row18">
+          <Int Name="Length">2</Int>
+          <Real>36.000</Real>
+          <Real>1.19384</Real>
+        </Sequence>
+        <Sequence Name="Row19">
+          <Int Name="Length">2</Int>
+          <Real>38.000</Real>
+          <Real>1.27086</Real>
+        </Sequence>
+        <Sequence Name="Row20">
+          <Int Name="Length">2</Int>
+          <Real>40.000</Real>
+          <Real>1.34173</Real>
+        </Sequence>
+      </XvgData>
+    </File>
+  </OutputFiles>
+</ReferenceData>
similarity index 67%
rename from src/gromacs/gmxana/tests/refdata/MsdTest_threeDimensionalDiffusion.xml
rename to src/gromacs/trajectoryanalysis/tests/refdata/MsdModuleTest_twoDimensionalDiffusion.xml
index 5f04b7857bcf9cf2785133935834cecb9b60d9fd..b0912b6a25111d7c897e503ea673c77084b75915 100644 (file)
@@ -1,65 +1,66 @@
 <?xml version="1.0"?>
 <?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
 <ReferenceData>
+  <String Name="CommandLine">-trestart 200 -lateral z -sel 0</String>
   <OutputFiles Name="Files">
     <File Name="-o">
+      <XvgLegend Name="DiffusionCoefficient"></XvgLegend>
       <XvgLegend Name="Legend">
-        <String Name="XvgLegend"><![CDATA[
-title "Mean Square Displacement"
-xaxis  label "Time (ps)"
-yaxis  label "MSD (nm\S2\N)"
-TYPE xy
-]]></String>
+        <String>title "Mean Squared Displacement"</String>
+        <String>xaxis  label "tau (ps)"</String>
+        <String>yaxis  label "MSD (nm\\S2\\N)"</String>
+        <String>TYPE xy</String>
+        <String>s0 legend "D[ particles] = 6.0000 (+/- 0.0000) (1e-5 cm^2/s)"</String>
       </XvgLegend>
       <XvgData Name="Data">
         <Sequence Name="Row0">
           <Int Name="Length">2</Int>
-          <Real>0</Real>
+          <Real>0.000</Real>
           <Real>0</Real>
         </Sequence>
         <Sequence Name="Row1">
           <Int Name="Length">2</Int>
-          <Real>1</Real>
+          <Real>1.000</Real>
           <Real>0.024</Real>
         </Sequence>
         <Sequence Name="Row2">
           <Int Name="Length">2</Int>
-          <Real>2</Real>
+          <Real>2.000</Real>
           <Real>0.048</Real>
         </Sequence>
         <Sequence Name="Row3">
           <Int Name="Length">2</Int>
-          <Real>3</Real>
+          <Real>3.000</Real>
           <Real>0.072</Real>
         </Sequence>
         <Sequence Name="Row4">
           <Int Name="Length">2</Int>
-          <Real>4</Real>
+          <Real>4.000</Real>
           <Real>0.096</Real>
         </Sequence>
         <Sequence Name="Row5">
           <Int Name="Length">2</Int>
-          <Real>5</Real>
+          <Real>5.000</Real>
           <Real>0.12</Real>
         </Sequence>
         <Sequence Name="Row6">
           <Int Name="Length">2</Int>
-          <Real>6</Real>
+          <Real>6.000</Real>
           <Real>0.144</Real>
         </Sequence>
         <Sequence Name="Row7">
           <Int Name="Length">2</Int>
-          <Real>7</Real>
+          <Real>7.000</Real>
           <Real>0.168</Real>
         </Sequence>
         <Sequence Name="Row8">
           <Int Name="Length">2</Int>
-          <Real>8</Real>
+          <Real>8.000</Real>
           <Real>0.192</Real>
         </Sequence>
         <Sequence Name="Row9">
           <Int Name="Length">2</Int>
-          <Real>9</Real>
+          <Real>9.000</Real>
           <Real>0.216</Real>
         </Sequence>
       </XvgData>
index 5e6487ea515fa102f92260cfc03a646ec591cf87..16edcaf6f07cda73d1114b3bb0eaf968ae17bb61 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -143,8 +143,9 @@ TEST_F(SelectModuleTest, WritesResidueNumbers)
 
 TEST_F(SelectModuleTest, WritesResidueIndices)
 {
-    const char* const cmdline[] = { "select", "-select", "res_com of resname RA RD", "-resnr",
-                                    "index" };
+    const char* const cmdline[] = {
+        "select", "-select", "res_com of resname RA RD", "-resnr", "index"
+    };
     setTopology("simple.gro");
     includeDataset("index");
     runTest(CommandLine(cmdline));
index 1bb99bac10abc737ec0b75bc25db9e8fb85a9a56..d860414771b9310e6380adedb766f344b278c72a 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
 
 #include <gtest/gtest.h>
 
+#include "gromacs/math/units.h"
 #include "gromacs/math/utilities.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/pbcutil/pbc.h"
@@ -116,7 +117,7 @@ public:
         for (int i = 0; i < count; ++i)
         {
             rvec x;
-            real radius;
+            real radius = 0;
             generateRandomPosition(x, &radius);
             addSphere(x[XX], x[YY], x[ZZ], radius);
         }
@@ -147,8 +148,16 @@ public:
         gmx::SurfaceAreaCalculator calculator;
         calculator.setDotCount(ndots);
         calculator.setRadii(radius_);
-        calculator.calculate(as_rvec_array(x_.data()), bPBC ? &pbc : nullptr, index_.size(),
-                             index_.data(), flags, &area_, &volume_, &atomArea_, &dots_, &dotCount_);
+        calculator.calculate(as_rvec_array(x_.data()),
+                             bPBC ? &pbc : nullptr,
+                             index_.size(),
+                             index_.data(),
+                             flags,
+                             &area_,
+                             &volume_,
+                             &atomArea_,
+                             &dots_,
+                             &dotCount_);
     }
     real resultArea() const { return area_; }
     real resultVolume() const { return volume_; }
index 2a04f0d2259f65281839597c1b621a73244a0a07..4d2be374ef1744d4bb49304b2ef1230b37f18169 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -116,10 +116,9 @@ void SelectionTester::analyzeFrame(int /*frnr*/,
     for (size_t g = 0; g < selections_.size(); ++g)
     {
         const Selection& sel = selections_[g];
-        int              n;
 
         fprintf(stderr, "  Atoms (%d pcs):", sel.atomCount());
-        n = sel.atomCount();
+        int n = sel.atomCount();
         if (nmaxind_ >= 0 && n > nmaxind_)
         {
             n = nmaxind_;
@@ -144,8 +143,14 @@ void SelectionTester::analyzeFrame(int /*frnr*/,
         for (int i = 0; i < n; ++i)
         {
             const SelectionPosition& p = sel.position(i);
-            fprintf(stderr, "    (%.2f,%.2f,%.2f) r=%d, m=%d, n=%d\n", p.x()[XX], p.x()[YY],
-                    p.x()[ZZ], p.refId(), p.mappedId(), p.atomCount());
+            fprintf(stderr,
+                    "    (%.2f,%.2f,%.2f) r=%d, m=%d, n=%d\n",
+                    p.x()[XX],
+                    p.x()[YY],
+                    p.x()[ZZ],
+                    p.refId(),
+                    p.mappedId(),
+                    p.atomCount());
         }
         if (n < sel.posCount())
         {
index 4728ed6d9652557b3f19c706c621f1bf41a452af..1f1d387e3d3a254d8f99dbdfec9115469e983753 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -109,7 +109,7 @@ void runCommonTests(const TopologyInformation& topInfo, const int numAtoms)
     EXPECT_TRUE(atoms2);
     // Must be different pointer to a deep copy.
     EXPECT_NE(atoms1.get(), atoms2.get());
-    auto atoms = topInfo.atoms();
+    const auto* atoms = topInfo.atoms();
     // Must be a pointer to a different instance.
     EXPECT_NE(atoms1.get(), atoms);
     EXPECT_NE(atoms2.get(), atoms);
index 5369b95611648aaf2cf5828e0da7dcce4f9bd543..d387e8b9dc941b5c6e4f980f107a038acd5ff26d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +81,7 @@ void TopologyInformation::fillFromInputFile(const std::string& filename)
     // t_atoms that we'd keep, which we currently can't do.
     // TODO Once there are fewer callers of the file-reading
     // functionality, make them read directly into std::vector.
-    rvec *x, *v;
+    rvec *x = nullptr, *v = nullptr;
     readConfAndTopology(filename.c_str(), &bTop_, mtop_.get(), &pbcType_, &x, &v, boxtop_);
     xtop_.assign(x, x + mtop_->natoms);
     vtop_.assign(v, v + mtop_->natoms);
@@ -121,7 +121,7 @@ AtomsDataPtr makeAtoms(const TopologyInformation& top_)
     AtomsDataPtr atoms(new t_atoms);
     if (top_.hasTopology())
     {
-        *atoms = gmx_mtop_global_atoms(top_.mtop());
+        *atoms = gmx_mtop_global_atoms(*top_.mtop());
     }
     else
     {
index 99bfd43eea74984d1d0cbdbbf774e0505559fbb7..f04c1c515ef6839aedac95762b1499919e9cf681 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  * compiler-specific attributes, and ::GMX_UNUSED_VALUE and ::GMX_IGNORE_RETURN_VALUE
  * for handling warnings about unused values.
  *
- * The header classhelpers.h implements a gmx::PrivateImplPointer template for easily
- * writing classes that use the private implementation idiom.  This header also
- * declares ::GMX_DISALLOW_COPY_AND_ASSIGN and ::GMX_DISALLOW_ASSIGN macros for
- * class declarations.
+ * The header classhelpers.h declares ::GMX_DISALLOW_COPY_AND_ASSIGN,
+ * ::GMX_DISALLOW_COPY_MOVE_AND_ASSIGN, ::GMX_DISALLOW_ASSIGN, and
+ * ::GMX_DEFAULT_CONSTRUCTORS macros for class declarations.
  *
  * The header flags.h implements a gmx::FlagsTemplate template for better type
  * safety when using bit flag fields.
index 93e82808cde05fa4fe50da929ba1f9a2f8eb29b3..342b7eecebafa3cde366a7cbf861af135f19d61f 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.
 
+add_library(utility INTERFACE)
+
 file(GLOB UTILITY_SOURCES *.cpp)
 if (GMX_GPU_CUDA)
     gmx_add_libgromacs_sources(cuda_version_information.cu)
 endif()
 set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${UTILITY_SOURCES} PARENT_SCOPE)
 
-# TODO: (https://gitlab.com/gromacs/gromacs/-/issues/988) Find a new convention for defining public API.
-install(FILES
-        basedefinitions.h
-        current_function.h
-        gmxassert.h
-        real.h
-        DESTINATION include/gromacs/utility)
-
 if(GMX_INSTALL_LEGACY_API)
   install(FILES
-          arrayref.h
           baseversion.h
           classhelpers.h
           enumerationhelpers.h
-          exceptions.h
-          listoflists.h
          fileptr.h
          futil.h
          flags.h
@@ -67,6 +58,23 @@ if(GMX_INSTALL_LEGACY_API)
           DESTINATION include/gromacs/utility)
 endif()
 
+# Public interface for modules, including dependencies and interfaces
+#target_include_directories(utility PUBLIC
+target_include_directories(utility INTERFACE
+                           $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+#target_link_libraries(utility PUBLIC
+target_link_libraries(utility INTERFACE
+                      legacy_api
+                      )
+
+# TODO: when utility is an OBJECT target
+#target_link_libraries(utility PUBLIC legacy_api)
+#target_link_libraries(utility PRIVATE common)
+
+# Source files have the following private module dependencies.
+# TODO: Explicitly link specific modules.
+#target_link_libraries(utility PRIVATE legacy_modules)
+
 if (BUILD_TESTING)
     add_subdirectory(tests)
 endif()
index a6d073c3c9346762990829ab57995c76218cb632..8a55bb94a0f961dc9f07d79ed1a4ac0cad4184ef 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -96,6 +96,10 @@ namespace
  *  \note This is an internal routine that should only be called from
  *        gmx::alignedMalloc(). Just like system-provided routines, it provides
  *        memory that is aligned - but not padded.
+ *
+ *  \note This functionality is provided by C++17 std::aligned_alloc,
+ *  and it would be preferable to use that instead, however it is not
+ *  yet widely enough available to depend on. See #3968.
  */
 gmx_unused void* alignedMallocGeneric(std::size_t bytes, std::size_t alignment)
 {
@@ -149,7 +153,7 @@ gmx_unused void alignedFreeGeneric(void* p)
 //! Implement malloc of \c bytes of memory, aligned to \c alignment.
 void* mallocImpl(std::size_t bytes, std::size_t alignment)
 {
-    void* p;
+    void* p = nullptr;
 
 #if HAVE__MM_MALLOC
     p = _mm_malloc(bytes, alignment);
@@ -228,7 +232,7 @@ void AlignedAllocationPolicy::free(void* p)
 //! \todo Move this function into sysinfo.cpp where other OS-specific code/includes live
 static std::size_t getPageSize()
 {
-    long pageSize;
+    long pageSize = 0;
 #if GMX_NATIVE_WINDOWS
     SYSTEM_INFO si;
     GetNativeSystemInfo(&si);
index baf599b03ba3c589df810abdc03e4a0b32d21c08..f6e66cd4fff4bfc83e6934673d69865568b51bfe 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
index c7e36f603d5c2193a9d21e95001e6a7dc26e841d..970703bad86539dbd3b7c6d259f2cdc29a2df1d2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +56,12 @@ namespace gmx
 {
 
 /*! \libinternal \brief
- * Represents a dynamically typed value of an arbitrary type.
+ * Represents a dynamically typed value of an arbitrary type - deprecated.
  *
- * To create a any, either initialize it as empty, or with the create()
+ * New uses of this type should be avoided - prefer std::any or
+ * std::variant.
+ *
+ * To create an Any, 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).
  *
@@ -73,6 +76,11 @@ namespace gmx
  *
  * This provides essentially the same functionality as boost::any.
  *
+ * It would be good to replace the current uses of this type with
+ * std::any or std::variant, but see
+ * https://gitlab.com/gromacs/gromacs/-/issues/3951 for discussion
+ * about the things that have blocked such attempts.
+ *
  * \ingroup module_utility
  */
 class Any
index 6fade03e577a04d6be1bea33987e1ed80e3b2847..7aa2944bbe281229e7c664d0c4cbc2a5c806e98e 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +55,7 @@ bool gmx_mpi_initialized()
 #if !GMX_MPI
     return false;
 #else
-    int n;
+    int n = 0;
     MPI_Initialized(&n);
 
     return n != 0;
@@ -73,7 +73,7 @@ int gmx_node_num()
         return 1;
     }
 #    endif
-    int i;
+    int i = 0;
     (void)MPI_Comm_size(MPI_COMM_WORLD, &i);
     return i;
 #endif
@@ -90,7 +90,7 @@ int gmx_node_rank()
         return 0;
     }
 #    endif
-    int i;
+    int i = 0;
     (void)MPI_Comm_rank(MPI_COMM_WORLD, &i);
     return i;
 #endif
@@ -98,7 +98,7 @@ int gmx_node_rank()
 
 static int mpi_hostname_hash()
 {
-    int hash_int;
+    int hash_int = 0;
 
 #if GMX_LIB_MPI
     int  resultlen;
index 7c324773219cbbbc46a8ed90c9c1d2a2843e2a73..a78ba3c4f17f0e0118056d69ee1dd974a2ebb41b 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2012,2014,2015,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +35,9 @@
  */
 #include "gromacs/utility/baseversion_gen.h"
 
-const char _gmx_ver_string[] = "@GMX_VERSION_STRING_FULL@";
-const char _gmx_full_git_hash[] = "@GMX_VERSION_FULL_HASH@";
-const char _gmx_central_base_hash[] = "@GMX_VERSION_CENTRAL_BASE_HASH@";
+const char gmx_ver_string[] = "@GMX_VERSION_STRING_FULL@";
+const char gmx_full_git_hash[] = "@GMX_VERSION_FULL_HASH@";
+const char gmx_central_base_hash[] = "@GMX_VERSION_CENTRAL_BASE_HASH@";
 const char gmxSourceDoiString[] = "@GMX_SOURCE_DOI@";
 const char gmxReleaseSourceFileChecksum[] = "@GMX_RELEASE_SOURCE_FILE_CHECKSUM@"; 
 const char gmxCurrentSourceFileChecksum[] = "@GMX_CURRENT_SOURCE_FILE_CHECKSUM@";
index ec06ccd4ab88fe576f91f7c694096afbb34aff48..e862b805dc15d5decb11e5a7ccf4ce721d8fc820 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 const char* gmx_version()
 {
-    return _gmx_ver_string;
+    return gmx_ver_string;
 }
 
 const char* gmx_version_git_full_hash()
 {
-    return _gmx_full_git_hash;
+    return gmx_full_git_hash;
 }
 
 const char* gmx_version_git_central_base_hash()
 {
-    return _gmx_central_base_hash;
+    return gmx_central_base_hash;
 }
 
 const char* gmxDOI()
index b2f026f81a3e6336a056784343d9db63d9cda5e9..0249270ec41ac5dc0c01be2dcd94717e1e4b1dd9 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2010,2012,2013,2014,2015 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 //! \{
 
 //! Version string, containing the version, date, and abbreviated hash.
-extern const char _gmx_ver_string[];
+extern const char gmx_ver_string[];
 //! Full git hash of the latest commit.
-extern const char _gmx_full_git_hash[];
+extern const char gmx_full_git_hash[];
 //! Full git hash of the latest commit in a central \Gromacs repository.
-extern const char _gmx_central_base_hash[];
+extern const char gmx_central_base_hash[];
 /*! \brief
  *  DOI string for the \Gromacs source code populated by CMake.
  *
index 43ba3d508862dd41bcb1c4dd08a3d2606f84d135..839f4796dbe6e5673fbf45b29465cfe4e9deb3e7 100644 (file)
@@ -120,6 +120,7 @@ void printCopyright(gmx::TextWriter* writer)
                                                 "Aldert van Buuren",
                                                 "Rudi van Drunen",
                                                 "Anton Feenstra",
+                                                "Gaurav Garg",
                                                 "Gilles Gouaillardet",
                                                 "Alan Gray",
                                                 "Gerrit Groenhof",
@@ -156,7 +157,8 @@ void printCopyright(gmx::TextWriter* writer)
     static const char* const CopyrightText[] = {
         "Copyright (c) 1991-2000, University of Groningen, The Netherlands.",
         "Copyright (c) 2001-2019, The GROMACS development team at",
-        "Uppsala University, Stockholm University and", "the Royal Institute of Technology, Sweden.",
+        "Uppsala University, Stockholm University and",
+        "the Royal Institute of Technology, Sweden.",
         "check out http://www.gromacs.org for more information."
     };
 
@@ -291,7 +293,11 @@ void gmx_print_version_info(gmx::TextWriter* writer)
 #if GMX_THREAD_MPI
     writer->writeLine("MPI library:        thread_mpi");
 #elif GMX_MPI
+#    if HAVE_CUDA_AWARE_MPI
+    writer->writeLine("MPI library:        MPI (CUDA-aware)");
+#    else
     writer->writeLine("MPI library:        MPI");
+#    endif
 #else
     writer->writeLine("MPI library:        none");
 #endif
@@ -320,8 +326,8 @@ void gmx_print_version_info(gmx::TextWriter* writer)
 #if HAVE_EXTRAE
     unsigned major, minor, revision;
     Extrae_get_version(&major, &minor, &revision);
-    writer->writeLine(formatString("Tracing support:    enabled. Using Extrae-%d.%d.%d", major,
-                                   minor, revision));
+    writer->writeLine(formatString(
+            "Tracing support:    enabled. Using Extrae-%d.%d.%d", major, minor, revision));
 #else
     writer->writeLine("Tracing support:    disabled");
 #endif
@@ -331,15 +337,15 @@ void gmx_print_version_info(gmx::TextWriter* writer)
      * them. Can wait for later, as the master branch has ready code to do all
      * that. */
     writer->writeLine(formatString("C compiler:         %s", BUILD_C_COMPILER));
-    writer->writeLine(formatString("C compiler flags:   %s %s", BUILD_CFLAGS,
-                                   CMAKE_BUILD_CONFIGURATION_C_FLAGS));
+    writer->writeLine(formatString(
+            "C compiler flags:   %s %s", BUILD_CFLAGS, CMAKE_BUILD_CONFIGURATION_C_FLAGS));
     writer->writeLine(formatString("C++ compiler:       %s", BUILD_CXX_COMPILER));
-    writer->writeLine(formatString("C++ compiler flags: %s %s", BUILD_CXXFLAGS,
-                                   CMAKE_BUILD_CONFIGURATION_CXX_FLAGS));
+    writer->writeLine(formatString(
+            "C++ compiler flags: %s %s", BUILD_CXXFLAGS, CMAKE_BUILD_CONFIGURATION_CXX_FLAGS));
 #ifdef HAVE_LIBMKL
     /* MKL might be used for LAPACK/BLAS even if FFTs use FFTW, so keep it separate */
-    writer->writeLine(formatString("Linked with Intel MKL version %d.%d.%d.", __INTEL_MKL__,
-                                   __INTEL_MKL_MINOR__, __INTEL_MKL_UPDATE__));
+    writer->writeLine(formatString(
+            "Linked with Intel MKL version %d.%d.%d.", __INTEL_MKL__, __INTEL_MKL_MINOR__, __INTEL_MKL_UPDATE__));
 #endif
 #if GMX_GPU_OPENCL
     writer->writeLine(formatString("OpenCL include dir: %s", OPENCL_INCLUDE_DIR));
@@ -348,8 +354,8 @@ void gmx_print_version_info(gmx::TextWriter* writer)
 #endif
 #if GMX_GPU_CUDA
     writer->writeLine(formatString("CUDA compiler:      %s", CUDA_COMPILER_INFO));
-    writer->writeLine(formatString("CUDA compiler flags:%s %s", CUDA_COMPILER_FLAGS,
-                                   CMAKE_BUILD_CONFIGURATION_CXX_FLAGS));
+    writer->writeLine(formatString(
+            "CUDA compiler flags:%s %s", CUDA_COMPILER_FLAGS, CMAKE_BUILD_CONFIGURATION_CXX_FLAGS));
     writer->writeLine("CUDA driver:        " + gmx::getCudaDriverVersionString());
     writer->writeLine("CUDA runtime:       " + gmx::getCudaRuntimeVersionString());
 #endif
@@ -426,8 +432,8 @@ void printBinaryInformation(TextWriter*                      writer,
         // necessary to read stuff above the copyright notice.
         // The line above the copyright notice puts the copyright notice is
         // context, though.
-        writer->writeLine(formatString("%sGROMACS:      %s, version %s%s%s", prefix, name,
-                                       gmx_version(), precisionString, suffix));
+        writer->writeLine(formatString(
+                "%sGROMACS:      %s, version %s%s%s", prefix, name, gmx_version(), precisionString, suffix));
     }
     const char* const binaryPath = programContext.fullBinaryPath();
     if (!gmx::isNullOrEmpty(binaryPath))
@@ -437,8 +443,11 @@ void printBinaryInformation(TextWriter*                      writer,
     const gmx::InstallationPrefixInfo installPrefix = programContext.installationPrefix();
     if (!gmx::isNullOrEmpty(installPrefix.path))
     {
-        writer->writeLine(formatString("%sData prefix:  %s%s%s", prefix, installPrefix.path,
-                                       installPrefix.bSourceLayout ? " (source tree)" : "", suffix));
+        writer->writeLine(formatString("%sData prefix:  %s%s%s",
+                                       prefix,
+                                       installPrefix.path,
+                                       installPrefix.bSourceLayout ? " (source tree)" : "",
+                                       suffix));
     }
     const std::string workingDir = Path::getWorkingDirectory();
     if (!workingDir.empty())
@@ -452,8 +461,8 @@ void printBinaryInformation(TextWriter*                      writer,
     const char* const commandLine = programContext.commandLine();
     if (!gmx::isNullOrEmpty(commandLine))
     {
-        writer->writeLine(formatString("%sCommand line:%s\n%s  %s%s", prefix, suffix, prefix,
-                                       commandLine, suffix));
+        writer->writeLine(formatString(
+                "%sCommand line:%s\n%s  %s%s", prefix, suffix, prefix, commandLine, suffix));
     }
     if (settings.bExtendedInfo_)
     {
index eddec13736eee67b1ff75ff45ddb445e5d63e339..6d4cb52ca482299b666b02be7dda2ee85d89cb4e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +157,8 @@ inline static bool bitmask_is_set(gmx_bitmask_t m, int b)
 
 inline static bool bitmask_is_disjoint(gmx_bitmask_t a, gmx_bitmask_t b)
 {
-    int  i;
     bool r = true;
-    for (i = 0; i < BITMASK_ALEN; i++)
+    for (int i = 0; i < BITMASK_ALEN; i++)
     {
         r = r && ((a[i] & b[i]) == 0U);
     }
@@ -168,9 +167,8 @@ inline static bool bitmask_is_disjoint(gmx_bitmask_t a, gmx_bitmask_t b)
 
 inline static bool bitmask_is_equal(gmx_bitmask_t a, gmx_bitmask_t b)
 {
-    int  i;
     bool r = true;
-    for (i = 0; i < BITMASK_ALEN; i++)
+    for (int i = 0; i < BITMASK_ALEN; i++)
     {
         r = r && (a[i] == b[i]);
     }
@@ -179,9 +177,8 @@ inline static bool bitmask_is_equal(gmx_bitmask_t a, gmx_bitmask_t b)
 
 inline static bool bitmask_is_zero(gmx_bitmask_t m)
 {
-    int  i;
     bool r = true;
-    for (i = 0; i < BITMASK_ALEN; i++)
+    for (int i = 0; i < BITMASK_ALEN; i++)
     {
         r = r && (m[i] == 0U);
     }
@@ -190,8 +187,7 @@ inline static bool bitmask_is_zero(gmx_bitmask_t m)
 
 inline static void bitmask_union(gmx_bitmask_t* a, gmx_bitmask_t b)
 {
-    int i;
-    for (i = 0; i < BITMASK_ALEN; i++)
+    for (int i = 0; i < BITMASK_ALEN; i++)
     {
         (*a)[i] |= b[i];
     }
index ae4458fdda49848a5b947f1c72deb09c66cd63cd..ccee1e2dcae18ffa329752f4ed2fd868e8bc3bd5 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +48,6 @@
 #ifndef GMX_UTILITY_CLASSHELPERS_H
 #define GMX_UTILITY_CLASSHELPERS_H
 
-#include <memory>
-
 namespace gmx
 {
 
@@ -114,117 +112,6 @@ namespace gmx
 #endif
 //clang-format on
 
-/*! \brief
- * Helper class to manage a pointer to a private implementation class.
- *
- * This helper provides the following benefits (all but the last could also be
- * achieved with std::unique_ptr):
- *  - Automatic memory management: the implementation pointer is freed in
- *    the destructor automatically.  If the destructor is not declared or is
- *    defined inline in the header file, a compilation error occurs instead
- *    of a memory leak or undefined behavior.
- *  - Exception safety in constructors: the implementation pointer is freed
- *    correctly even if the constructor of the containing class throws after
- *    the implementation class is constructed.
- *  - Copy and/or assignment is automatically disallowed if explicit copy
- *    constructor and/or assignment operator is not provided.
- *  - Compiler helps to manage const-correctness: in const methods, it is not
- *    possible to change the implementation class.
- *
- * Move construction and assignment are also disallowed, but can be enabled by
- * providing explicit move constructor and/or assignment.
- *
- * Intended use:
- * \code
-   // In exampleclass.h
-   class ExampleClass
-   {
-       public:
-           ExampleClass();
-           ~ExampleClass(); // Must be defined, must not be defined inline
-
-           // <...>
-
-       private:
-           class Impl;
-
-           PrivateImplPointer<Impl> impl_;
-   };
-
-   // In exampleclass.cpp
-
-   // <definition of ExampleClass::Impl>
-
-   ExampleClass::ExampleClass()
-       : impl_(new Impl)
-   {
-   }
-
-   ExampleClass::~ExampleClass()
-   {
-   }
-   \endcode
- *
- * Note that ExampleClass::~ExampleClass cannot be declared inline (or
- * generated by the compiler) because the implementation of impl_
- * requires that ExampleClass::Impl be known in size, whereas it has
- * only been forward declared. Only the translation unit where
- * ExampleClass::Impl is declared can define the destructor for
- * ExampleClass (which may be defaulted).
- *
- * \inlibraryapi
- * \ingroup module_utility
- */
-template<class Impl>
-class PrivateImplPointer
-{
-public:
-    //! Allow implicit initialization from nullptr to support comparison.
-    PrivateImplPointer(std::nullptr_t) : ptr_(nullptr) {}
-    //! Initialize with the given implementation class.
-    explicit PrivateImplPointer(Impl* ptr) : ptr_(ptr) {}
-    //! \cond
-    // Explicitly declared to work around MSVC problems.
-    PrivateImplPointer(PrivateImplPointer&& other) noexcept : ptr_(std::move(other.ptr_)) {}
-    PrivateImplPointer& operator=(PrivateImplPointer&& other) noexcept
-    {
-        ptr_ = std::move(other.ptr_);
-        return *this;
-    }
-    //! \endcond
-
-    /*! \brief
-     * Sets a new implementation class and destructs the previous one.
-     *
-     * Needed, e.g., to implement lazily initializable or copy-assignable
-     * classes.
-     */
-    void reset(Impl* ptr) { ptr_.reset(ptr); }
-    //! Access the raw pointer.
-    Impl* get() { return ptr_.get(); }
-    //! Access the implementation class as with a raw pointer.
-    Impl* operator->() { return ptr_.get(); }
-    //! Access the implementation class as with a raw pointer.
-    Impl& operator*() { return *ptr_; }
-    //! Access the implementation class as with a raw pointer.
-    const Impl* operator->() const { return ptr_.get(); }
-    //! Access the implementation class as with a raw pointer.
-    const Impl& operator*() const { return *ptr_; }
-
-    //! Allows testing whether the implementation is initialized.
-    explicit operator bool() const { return ptr_ != nullptr; }
-
-    //! Tests for equality (mainly useful against nullptr).
-    bool operator==(const PrivateImplPointer& other) const { return ptr_ == other.ptr_; }
-    //! Tests for inequality (mainly useful against nullptr).
-    bool operator!=(const PrivateImplPointer& other) const { return ptr_ != other.ptr_; }
-
-private:
-    std::unique_ptr<Impl> ptr_;
-
-    // Copy construction and assignment disabled by the unique_ptr member.
-};
-
 } // namespace gmx
 
 #endif
index 6ab41cd3d3e113ee327325041f6ecfbe61abc765..e8e39484cea25645e9a9e81638261a84f5fb02e3 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstdio>
 
+#include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
@@ -84,4 +85,18 @@ void cmp_float(FILE* fp, const char* s, int index, float i1, float i2, float fto
 //! Compares two doubles and prints differences.
 void cmp_double(FILE* fp, const char* s, int index, double i1, double i2, double ftol, double abstol);
 
+//! Compare two enums of generic type and print differences.
+template<typename EnumType>
+void cmpEnum(FILE* fp, const char* s, EnumType value1, EnumType value2)
+{
+    if (value1 != value2)
+    {
+        fprintf(fp, "%s (", s);
+        fprintf(fp, "%s", enumValueToString(value1));
+        fprintf(fp, " - ");
+        fprintf(fp, "%s", enumValueToString(value2));
+        fprintf(fp, ")\n");
+    }
+}
+
 #endif
index 14c0f1561a6bedffc198f96719528110ba584ea2..a8ee771ca839e3596917d552d99926593e8604d1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -395,8 +395,7 @@ std::string getCoolQuote()
         { "Disturb the Peace of a John Q Citizen", "Urban Dance Squad" },
         { "Wicky-wicky Wa-wild West", "Will Smith" },
         { "This is Tense !", "Star Wars Episode I The Phantom Menace" },
-        { "Fly to the Court of England and Unfold",
-          "Macbeth, Act 3, Scene 6, William Shakespeare" },
+        { "Fly to the Court of England and Unfold", "Macbeth, Act 3, Scene 6, William Shakespeare" },
         { "Why, how now, Claudio ! Whence Comes this Restraint ?",
           "Lucio in Measure for measure, Act 1, Scene 4, William Shakespeare" },
         { "In the End Science Comes Down to Praying", "P. v.d. Berg" },
@@ -454,8 +453,7 @@ std::string getCoolQuote()
         { "Nobody Never Learnt No-Nothing from No History", "Gogol Bordello" },
         { "I'd be Safe and Warm if I was in L.A.", "The Mamas and the Papas" },
         { "It's Unacceptable That Chocolate Makes You Fat", "MI 3" },
-        { "My Brothers are Protons (Protons!), My Sisters are Neurons (Neurons)",
-          "Gogol Bordello" },
+        { "My Brothers are Protons (Protons!), My Sisters are Neurons (Neurons)", "Gogol Bordello" },
         { "Put Me Inside SSC, Let's Test Superstring Theory, Oh Yoi Yoi Accelerate the Protons",
           "Gogol Bordello" },
         { "Do You Have Sex Maniacs or Schizophrenics or Astrophysicists in Your Family?",
@@ -536,8 +534,7 @@ std::string getCoolQuote()
         { "The scientific method is an integral part of human intelligence, and when it has once "
           "been set at work it can only be dismissed by dismissing the intelligence itself",
           "George H. Mead" },
-        { "Der Ball ist rund, das Spiel dauert 90 minuten, alles andere ist Theorie",
-          "Lola rennt" },
+        { "Der Ball ist rund, das Spiel dauert 90 minuten, alles andere ist Theorie", "Lola rennt" },
         { "Life in the streets is not easy", "Marky Mark" },
         { "How will I know it's working right?", "MGMT" },
         { "There was no preconception on what to do", "Daft Punk" },
@@ -1309,8 +1306,7 @@ std::string getCoolQuote()
         { "All sorts of things can happen when you're open to new ideas and playing around with "
           "things.",
           "Stephanie Kwolek, inventor of Kevlar" },
-        { "As always in life, people want a simple answer... and it's always wrong.",
-          "Marie Daly" },
+        { "As always in life, people want a simple answer... and it's always wrong.", "Marie Daly" },
         { "For a research worker the unforgotten moments of his life are those rare ones which "
           "come after years of plodding work, when the veil over natures secret seems suddenly to "
           "lift & when what was dark & chaotic appears in a clear & beautiful light & pattern.",
@@ -1380,8 +1376,7 @@ std::string getCoolQuote()
           "3-phosphoshikimate-carboxyvinyl transferase?' Shopkeeper: 'You mean Roundup?' "
           "Scientist: 'Yeah, that's it. I can never remember that dang name!'",
           "John Pickett" },
-        { "It is not clear that intelligence has any long-term survival value.",
-          "Stephen Hawking" },
+        { "It is not clear that intelligence has any long-term survival value.", "Stephen Hawking" },
         { "The greatest shortcoming of the human race is our inability to understand the "
           "exponential function.",
           "Albert Bartlett" },
@@ -1450,8 +1445,6 @@ std::string getCoolQuote()
           "married, it never occurred to him to verify this statement by examining his wives' "
           "mouths.",
           "Bertrand Russell" },
-        { "I had trouble with physics in college. When I signed up I thought it said psychics.",
-          "Greg Tamblyn" },
         { "I don't believe in astrology; I'm a Sagittarian and we're skeptical.",
           "Arthur C. Clarke" },
         { "I see they found out the universe is 80 million years older than we thought. It's also "
@@ -1584,7 +1577,9 @@ std::string getCoolQuote()
           "attempted.",
           "Anonymous" },
         { "If my PhD doesn't allow me to be right on the internet, what is it even good for?",
-          "Martin Vögele" }
+          "Martin Vögele" },
+        { "A little less conversation, a little more action, please.", "Elvis Presley" },
+        { "Friends don't let friends use Berendsen!", "John Chodera (on Twitter)" }
     };
 
     if (beCool())
index 576f79352705090984f0c9575a072940f1f18ce5..dbefa55d97b7249761af084e4db8f2b36b691d36 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 int continuing(char* s)
 {
-    int sl;
     assert(s);
 
     rtrim(s);
-    sl = strlen(s);
+    int sl = strlen(s);
     if ((sl > 0) && (s[sl - 1] == CONTINUE))
     {
         s[sl - 1] = 0;
@@ -78,7 +77,7 @@ int continuing(char* s)
 
 char* fgets2(char* line, int n, FILE* stream)
 {
-    char* c;
+    char* c = nullptr;
     if (fgets(line, n, stream) == nullptr)
     {
         return nullptr;
@@ -98,7 +97,9 @@ char* fgets2(char* line, int n, FILE* stream)
             gmx_fatal(FARGS,
                       "An input file contains a line longer than %d characters, while the buffer "
                       "passed to fgets2 has size %d. The line starts with: '%20.20s'",
-                      n, n, line);
+                      n,
+                      n,
+                      line);
         }
     }
     if ((c = strchr(line, '\r')) != nullptr)
@@ -111,7 +112,7 @@ char* fgets2(char* line, int n, FILE* stream)
 
 void strip_comment(char* line)
 {
-    char* c;
+    char* c = nullptr;
 
     if (!line)
     {
@@ -127,9 +128,7 @@ void strip_comment(char* line)
 
 void upstring(char* str)
 {
-    int i;
-
-    for (i = 0; (i < static_cast<int>(strlen(str))); i++)
+    for (int i = 0; (i < static_cast<int>(strlen(str))); i++)
     {
         str[i] = toupper(str[i]);
     }
@@ -137,21 +136,20 @@ void upstring(char* str)
 
 void ltrim(char* str)
 {
-    int i, c;
-
     if (nullptr == str)
     {
         return;
     }
 
-    c = 0;
+    int c = 0;
     while (('\0' != str[c]) && isspace(str[c]))
     {
         c++;
     }
     if (c > 0)
     {
-        for (i = c; ('\0' != str[i]); i++)
+        int i = c;
+        for (; ('\0' != str[i]); i++)
         {
             str[i - c] = str[i];
         }
@@ -161,14 +159,12 @@ void ltrim(char* str)
 
 void rtrim(char* str)
 {
-    int nul;
-
     if (nullptr == str)
     {
         return;
     }
 
-    nul = strlen(str) - 1;
+    int nul = strlen(str) - 1;
     while ((nul > 0) && ((str[nul] == ' ') || (str[nul] == '\t')))
     {
         str[nul] = '\0';
@@ -184,7 +180,7 @@ void trim(char* str)
 
 int gmx_strcasecmp_min(const char* str1, const char* str2)
 {
-    char ch1, ch2;
+    char ch1 = 0, ch2 = 0;
 
     do
     {
@@ -207,11 +203,10 @@ int gmx_strcasecmp_min(const char* str1, const char* str2)
 
 int gmx_strncasecmp_min(const char* str1, const char* str2, int n)
 {
-    char  ch1, ch2;
-    char *stri1, *stri2;
+    char ch1 = 0, ch2 = 0;
 
-    stri1 = const_cast<char*>(str1);
-    stri2 = const_cast<char*>(str2);
+    const char* stri1 = str1;
+    const char* stri2 = str2;
     do
     {
         do
@@ -233,7 +228,7 @@ int gmx_strncasecmp_min(const char* str1, const char* str2, int n)
 
 int gmx_strcasecmp(const char* str1, const char* str2)
 {
-    char ch1, ch2;
+    char ch1 = 0, ch2 = 0;
 
     do
     {
@@ -249,7 +244,7 @@ int gmx_strcasecmp(const char* str1, const char* str2)
 
 int gmx_strncasecmp(const char* str1, const char* str2, int n)
 {
-    char ch1, ch2;
+    char ch1 = 0, ch2 = 0;
 
     if (n == 0)
     {
@@ -271,7 +266,7 @@ int gmx_strncasecmp(const char* str1, const char* str2, int n)
 
 char* gmx_strdup(const char* src)
 {
-    char* dest;
+    char* dest = nullptr;
 
     auto length = strlen(src) + 1;
     snew(dest, length);
@@ -282,10 +277,9 @@ char* gmx_strdup(const char* src)
 
 char* gmx_strndup(const char* src, int n)
 {
-    int   len;
-    char* dest;
+    char* dest = nullptr;
 
-    len = strlen(src);
+    int len = strlen(src);
     if (len > n)
     {
         len = n;
@@ -304,7 +298,7 @@ const unsigned int gmx_string_hash_init = 5381;
 
 unsigned int gmx_string_fullhash_func(const char* s, unsigned int hash_init)
 {
-    int c;
+    char c = 0;
 
     while ((c = (*s++)) != '\0')
     {
@@ -315,7 +309,7 @@ unsigned int gmx_string_fullhash_func(const char* s, unsigned int hash_init)
 
 unsigned int gmx_string_hash_func(const char* s, unsigned int hash_init)
 {
-    int c;
+    int c = 0;
 
     while ((c = toupper(*s++)) != '\0')
     {
@@ -364,9 +358,8 @@ int gmx_wcmatch(const char* pattern, const char* str)
                  * since we have processed them above. */
                 if (*pattern == *str)
                 {
-                    int rc;
                     /* Match the suffix, and return if a match or an error */
-                    rc = gmx_wcmatch(pattern, str);
+                    int rc = gmx_wcmatch(pattern, str);
                     if (rc != GMX_NO_WCMATCH)
                     {
                         return rc;
@@ -393,9 +386,7 @@ int gmx_wcmatch(const char* pattern, const char* str)
 
 char* wrap_lines(const char* buf, int line_width, int indent, gmx_bool bIndentFirst)
 {
-    char*    b2;
-    int      i, i0, i2, j, b2len, lspace = 0, l2space = 0;
-    gmx_bool bFirst, bFitsOnLine;
+    int i = 0;
 
     /* characters are copied from buf to b2 with possible spaces changed
      * into newlines and extra space added for indentation.
@@ -409,10 +400,11 @@ char* wrap_lines(const char* buf, int line_width, int indent, gmx_bool bIndentFi
      * the current line (where it also won't fit, but looks better)
      */
 
-    b2    = nullptr;
-    b2len = strlen(buf) + 1 + indent;
+    char* b2    = nullptr;
+    int   b2len = strlen(buf) + 1 + indent;
     snew(b2, b2len);
-    i0 = i2 = 0;
+    int i0 = 0;
+    int i2 = 0;
     if (bIndentFirst)
     {
         for (i2 = 0; (i2 < indent); i2++)
@@ -420,10 +412,11 @@ char* wrap_lines(const char* buf, int line_width, int indent, gmx_bool bIndentFi
             b2[i2] = ' ';
         }
     }
-    bFirst = TRUE;
+    bool bFirst = true;
     do
     {
-        l2space = -1;
+        int lspace  = 0;
+        int l2space = -1;
         /* find the last space before end of line */
         for (i = i0; ((i - i0 < line_width) || (l2space == -1)) && (buf[i]); i++)
         {
@@ -441,7 +434,7 @@ char* wrap_lines(const char* buf, int line_width, int indent, gmx_bool bIndentFi
                 b2len += indent;
                 srenew(b2, b2len);
                 /* add indentation after the newline */
-                for (j = 0; (j < indent); j++)
+                for (int j = 0; (j < indent); j++)
                 {
                     b2[i2++] = ' ';
                 }
@@ -456,7 +449,7 @@ char* wrap_lines(const char* buf, int line_width, int indent, gmx_bool bIndentFi
         if (buf[i])
         {
             /* check if one word does not fit on the line */
-            bFitsOnLine = (i - i0 <= line_width);
+            bool bFitsOnLine = (i - i0 <= line_width);
             /* reset line counters to just after the space */
             i0 = lspace + 1;
             i2 = l2space + 1;
@@ -475,7 +468,7 @@ char* wrap_lines(const char* buf, int line_width, int indent, gmx_bool bIndentFi
                     }
                     b2len += indent;
                     srenew(b2, b2len);
-                    for (j = 0; (j < indent); j++)
+                    for (int j = 0; (j < indent); j++)
                     {
                         b2[i2++] = ' ';
                     }
index 9afb8c36ef44d72c8b4016298888f9e3e9557c58..a15a4854a312be0d31be8ac152bf80755ef5c5d9 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -100,7 +100,7 @@ void DataFileFinder::setSearchPathFromEnv(const char* envVarName)
 {
     if (!impl_)
     {
-        impl_.reset(new Impl());
+        impl_ = std::make_unique<Impl>();
     }
     impl_->envName_       = envVarName;
     const char* const lib = getenv(envVarName);
index 43c95e21b11c3e0a19fa725815a0536f7f6adee5..4eda8b3afd52cd8de3cde402f05a87865c4fe8c4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <memory>
 #include <string>
 #include <vector>
 
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/fileptr.h"
 
 namespace gmx
@@ -254,7 +254,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 6631b74c97012f0f0341efcae20893e58ffe9fd3..838bdee3d407a05144c49a60cc902637013978e9 100644 (file)
@@ -139,8 +139,8 @@ public:
                 }
                 else
                 {
-                    GMX_THROW_WITH_ERRNO(FileIOError("Failed to list files in a directory"),
-                                         "_findnext", errno);
+                    GMX_THROW_WITH_ERRNO(
+                            FileIOError("Failed to list files in a directory"), "_findnext", errno);
                 }
             }
             *filename = finddata.name;
index 18bf7919822b466d7e8562645dd0308736b6718a..36dec8b24fc1d4942de3b7df3c090ddc59df65e1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_UTILITY_DIRECTORYENUMERATOR_H
 #define GMX_UTILITY_DIRECTORYENUMERATOR_H
 
+#include <memory>
 #include <string>
 #include <vector>
 
-#include "gromacs/utility/classhelpers.h"
-
 namespace gmx
 {
 
@@ -123,7 +122,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index c74866f9a8ad78f0fc35d8d7177594d8c31a7e54..b30c8fee7a90f820d79c22410269fd6c3011ac52 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,19 +190,24 @@ public:
  *
  * See file documentation for usage example.
  *
+ * Note that if clang-tidy gives strange errors referring to the line
+ * number of the struct declaration, these likely refer to the
+ * compiler-generated constructors. Simplification of the calling code
+ * might eliminate that call and thus the clang-tidy error.
+ *
  * \tparam  EnumType   The enum (class) type.
  * \tparam  DataType   Type of the data stored in the array.
  * \tparam  ArraySize  Size in entries of the array.
  */
-template<typename EnumType,                   // The enum (class) type.
-         typename DataType,                   // Type of the data stored in the array.
-         EnumType ArraySize = EnumType::Count // Size in entries of the array.
-         >
-struct EnumerationArray final
+template<typename EnumType, typename DataType, EnumType ArraySize = EnumType::Count>
+struct EnumerationArray final // NOLINT
 {
     //! Convenience alias
     using EnumerationWrapperType = EnumerationWrapper<EnumType, ArraySize>;
 
+    //! Convenience alias
+    using value_type = DataType;
+
     /*! \brief Data for names.
      *
      * Data is kept public so we can use direct aggregate
@@ -212,7 +217,7 @@ struct EnumerationArray final
     //! Returns an object that provides iterators over the keys.
     static constexpr EnumerationWrapperType keys() { return EnumerationWrapperType{}; }
     //! Returns the size of the enumeration.
-    static constexpr std::size_t size() { return std::size_t(ArraySize); }
+    constexpr std::size_t size() const { return std::size_t(ArraySize); }
 
     /*!@{*/
     //! Array access with asserts:
index 84e57940a50f43b119e119d514588507e31a274e..c6fa123cade569c6d80ea681502f8887d7265f9a 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2011-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +42,7 @@
  */
 #include "gmxpre.h"
 
-#include "exceptions.h"
+#include "gromacs/utility/exceptions.h"
 
 #include <cstring>
 
@@ -52,8 +52,6 @@
 #include <stdexcept>
 #include <typeinfo>
 
-#include "thread_mpi/system_error.h"
-
 #include "gromacs/utility/basenetwork.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
@@ -340,8 +338,7 @@ public:
         std::fprintf(fp_, "%*sReason: %s\n", indent, "", std::strerror(errorNumber));
         if (funcName != nullptr)
         {
-            std::fprintf(fp_, "%*s(call to %s() returned error code %d)\n", indent, "", funcName,
-                         errorNumber);
+            std::fprintf(fp_, "%*s(call to %s() returned error code %d)\n", indent, "", funcName, errorNumber);
         }
     }
 
@@ -467,8 +464,8 @@ void formatExceptionMessageInternal(IMessageWriter* writer, const std::exception
         if (errorNumber != nullptr && *errorNumber != 0)
         {
             const char* const* funcName = gmxEx->getInfo<ExceptionInfoApiFunction>();
-            writer->writeErrNoInfo(*errorNumber, funcName != nullptr ? *funcName : nullptr,
-                                   (indent + 1) * 2);
+            writer->writeErrNoInfo(
+                    *errorNumber, funcName != nullptr ? *funcName : nullptr, (indent + 1) * 2);
             bAnythingWritten = true;
         }
 
@@ -510,10 +507,6 @@ void printFatalErrorMessage(FILE* fp, const std::exception& ex)
     {
         title = getErrorCodeString(gmxEx->errorCode());
     }
-    else if (dynamic_cast<const tMPI::system_error*>(&ex) != nullptr)
-    {
-        title = "System error in thread synchronization";
-    }
     else if (dynamic_cast<const std::bad_alloc*>(&ex) != nullptr)
     {
         title = "Memory allocation failed";
index f29b400a807e489e70b8633a3d55e85279eff8d0..a8eb96e755e1a6effdfe8cb2f238674a27894277 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017, The GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstring>
 
 #include <exception>
+#include <mutex>
 
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/baseversion.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/futil.h"
-#include "gromacs/utility/mutex.h"
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/stringutil.h"
 
 
 #include "errorformat.h"
 
-static bool bDebug = false;
+static bool bDebug = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 
-FILE*    debug        = nullptr;
-gmx_bool gmx_debug_at = FALSE;
+FILE* debug        = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
+bool  gmx_debug_at = false;   // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 
-static FILE*      log_file = nullptr;
-static gmx::Mutex error_mutex;
+static FILE*      log_file = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
+static std::mutex error_mutex;        // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 
-using Lock = gmx::lock_guard<gmx::Mutex>;
+using Lock = std::lock_guard<std::mutex>;
 
 void gmx_init_debug(const int dbglevel, const char* dbgfile)
 {
@@ -112,6 +112,7 @@ static void default_error_handler(const char* title, const std::string& msg, con
     gmx::internal::printFatalErrorFooter(stderr);
 }
 
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 static gmx_error_handler_t gmx_error_handler = default_error_handler;
 
 void gmx_set_error_handler(gmx_error_handler_t func)
@@ -234,13 +235,13 @@ void gmx_fatal(int f_errno, const char* file, int line, gmx_fmtstr const char* f
     va_end(ap);
 }
 
-void _gmx_error(const char* key, const std::string& msg, const char* file, int line)
+void gmx_error_function(const char* key, const std::string& msg, const char* file, int line)
 {
     call_error_handler(key, file, line, msg);
     gmx_exit_on_fatal_error(ExitType_Abort, 1);
 }
 
-void _range_check(int n, int n_min, int n_max, const char* warn_str, const char* var, const char* file, int line)
+void range_check_function(int n, int n_min, int n_max, const char* warn_str, const char* var, const char* file, int line)
 {
     if ((n < n_min) || (n >= n_max))
     {
@@ -254,9 +255,12 @@ void _range_check(int n, int n_min, int n_max, const char* warn_str, const char*
         buf += gmx::formatString(
                 "Variable %s has value %d. It should have been "
                 "within [ %d .. %d ]\n",
-                var, n, n_min, n_max);
+                var,
+                n,
+                n_min,
+                n_max);
 
-        _gmx_error("range", buf, file, line);
+        gmx_error_function("range", buf, file, line);
     }
 }
 
index 55f2c946efbb65825985092e1837ac79cbace979..a43f9d091a37990e8a663a6fbc73927908f7e06e 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,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -62,9 +62,9 @@
    }
    \endcode
  */
-extern FILE* debug;
+extern FILE* debug; //NOLINT(cppcoreguidelines-avoid-non-const-global-variables,-warnings-as-errors)
 /** Whether extra debugging is enabled. */
-extern gmx_bool gmx_debug_at;
+extern gmx_bool gmx_debug_at; //NOLINT(cppcoreguidelines-avoid-non-const-global-variables,-warnings-as-errors)
 
 /*! \brief
  * Initializes debugging variables.
@@ -145,6 +145,8 @@ enum ExitType
  *
  * This is used to implement gmx_fatal_collective() (which cannot be declared
  * here, since it would bring with it mdrun-specific dependencies).
+ *
+ * This function is deprecated and no new calls should be made to it.
  */
 [[noreturn]] void gmx_fatal_mpi_va(int         fatal_errno,
                                    const char* file,
@@ -170,6 +172,8 @@ enum ExitType
  * use gmx_fatal_collective(), declared in network.h,
  * to avoid having as many error messages as processes.
  *
+ * This function is deprecated and no new calls should be made to it.
+ *
  * The first three parameters can be provided through ::FARGS:
  * \code
    gmx_fatal(FARGS, fmt, ...);
@@ -180,21 +184,27 @@ enum ExitType
 /** Helper macro to pass first three parameters to gmx_fatal(). */
 #define FARGS 0, __FILE__, __LINE__
 
-/** Implementation for gmx_error(). */
-[[noreturn]] void _gmx_error(const char* key, const std::string& msg, const char* file, int line);
+/*! \brief Implementation for gmx_error().
+ *
+ * This function is deprecated and no new calls should be made to it. */
+[[noreturn]] void gmx_error_function(const char* key, const std::string& msg, const char* file, int line);
 /*! \brief
  * Alternative fatal error routine with canned messages.
  *
  * This works as gmx_fatal(), except that a generic error message is added
  * based on a string key, and printf-style formatting is not supported.
  * Should not typically be called directly, but through gmx_call() etc.
+ *
+ * This macro is deprecated and no new calls should be made to it.
  */
-#define gmx_error(key, msg) _gmx_error(key, msg, __FILE__, __LINE__)
+#define gmx_error(key, msg) gmx_error_function(key, msg, __FILE__, __LINE__)
 
 /*! \name Fatal error routines for certain types of errors
  *
  * These wrap gmx_error() and provide the \p key parameter as one of the
  * recognized strings.
+ *
+ * These macros are deprecated and no new calls should be made to them.
  */
 /*! \{ */
 #define gmx_call(msg) gmx_error("call", msg)
@@ -212,7 +222,7 @@ enum ExitType
  *
  * \p warn_str can be NULL.
  */
-void _range_check(int n, int n_min, int n_max, const char* warn_str, const char* var, const char* file, int line);
+void range_check_function(int n, int n_min, int n_max, const char* warn_str, const char* var, const char* file, int line);
 
 /*! \brief
  * Checks that a variable is within a range.
@@ -221,14 +231,15 @@ void _range_check(int n, int n_min, int n_max, const char* warn_str, const char*
  * \p n_min is inclusive, but \p n_max is not.
  */
 #define range_check_mesg(n, n_min, n_max, str) \
-    _range_check(n, n_min, n_max, str, #n, __FILE__, __LINE__)
+    range_check_function(n, n_min, n_max, str, #n, __FILE__, __LINE__)
 
 /*! \brief
  * Checks that a variable is within a range.
  *
  * This works as range_check_mesg(), but with a default error message.
  */
-#define range_check(n, n_min, n_max) _range_check(n, n_min, n_max, NULL, #n, __FILE__, __LINE__)
+#define range_check(n, n_min, n_max) \
+    range_check_function(n, n_min, n_max, NULL, #n, __FILE__, __LINE__)
 
 /*! \brief
  * Prints a warning message to stderr.
index 4773b5c2c8ba886b5271b614b66252cd969c0489..2aa94b9bd361c6bdc7c738393beac4783042a6f0 100644 (file)
@@ -105,8 +105,8 @@ public:
         fp_ = std::fopen(filename, mode);
         if (fp_ == nullptr)
         {
-            GMX_THROW_WITH_ERRNO(FileIOError(formatString("Could not open file '%s'", filename)),
-                                 "fopen", errno);
+            GMX_THROW_WITH_ERRNO(
+                    FileIOError(formatString("Could not open file '%s'", filename)), "fopen", errno);
         }
     }
     ~FileStreamImpl()
@@ -178,8 +178,8 @@ FilePtr TextInputFile::openRawHandle(const char* filename)
     FilePtr fp(fopen(filename, "r"));
     if (fp == nullptr)
     {
-        GMX_THROW_WITH_ERRNO(FileIOError(formatString("Could not open file '%s'", filename)),
-                             "fopen", errno);
+        GMX_THROW_WITH_ERRNO(
+                FileIOError(formatString("Could not open file '%s'", filename)), "fopen", errno);
     }
     return fp;
 }
index 5309fb217822938478e17823ab2d83c415584649..9e24a1c8d2d5f193f9d5936764fa70bdea69ba34 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +45,9 @@
 
 #include <cstdio>
 
+#include <memory>
 #include <string>
 
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/fileptr.h"
 #include "gromacs/utility/textstream.h"
 
@@ -142,7 +142,7 @@ public:
     void close() override;
 
 private:
-    PrivateImplPointer<internal::FileStreamImpl> impl_;
+    std::unique_ptr<internal::FileStreamImpl> impl_;
 };
 
 /*! \libinternal \brief
@@ -181,7 +181,7 @@ public:
     static TextOutputFile& standardError();
 
 private:
-    PrivateImplPointer<internal::FileStreamImpl> impl_;
+    std::unique_ptr<internal::FileStreamImpl> impl_;
 };
 
 } // namespace gmx
index ace651cdeb97529760cf523f658f3c15bfb84192..36ea649f081a260dd8ffb44510f932651efe4de9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <array>
 #include <stdexcept>
 
+#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/gmxassert.h"
 
 namespace gmx
index 99d95bb57ac7e9cb6d7a2959a7fe3ecb7c76e507..befd2d34bb701eb16e807e374e7863781fbae28b 100644 (file)
@@ -46,6 +46,7 @@
 #include <cstdlib>
 #include <cstring>
 
+#include <mutex>
 #include <tuple>
 
 #include <fcntl.h>
@@ -66,7 +67,6 @@
 #include "gromacs/utility/dir_separator.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
-#include "gromacs/utility/mutex.h"
 #include "gromacs/utility/path.h"
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/smalloc.h"
@@ -82,22 +82,26 @@ typedef struct t_pstack
     struct t_pstack* prev;
 } t_pstack;
 
-static t_pstack* pstack           = nullptr;
-static bool      bUnbuffered      = false;
-static int       s_maxBackupCount = 0;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static t_pstack* pstack = nullptr;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static bool bUnbuffered = false;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static int s_maxBackupCount = 0;
 
 /* this linked list is an intrinsically globally shared object, so we have
    to protect it with mutexes */
-static gmx::Mutex pstack_mutex;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static std::mutex pstack_mutex;
 
-using Lock = gmx::lock_guard<gmx::Mutex>;
+using Lock = std::lock_guard<std::mutex>;
 
 namespace gmx
 {
 namespace
 {
 //! Global library file finder; stores the object set with setLibraryFileFinder().
-const DataFileFinder* g_libFileFinder;
+const DataFileFinder* g_libFileFinder; //NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 //! Default library file finder if nothing is set.
 const DataFileFinder g_defaultLibFileFinder;
 } // namespace
@@ -150,7 +154,7 @@ void gmx_set_max_backup_count(int count)
 
 static void push_ps(FILE* fp)
 {
-    t_pstack* ps;
+    t_pstack* ps = nullptr;
 
     Lock pstackLock(pstack_mutex);
 
@@ -183,12 +187,11 @@ static int pclose(FILE* /* fp */)
 
 int gmx_ffclose(FILE* fp)
 {
-    t_pstack *ps, *tmp;
-    int       ret = 0;
+    int ret = 0;
 
     Lock pstackLock(pstack_mutex);
 
-    ps = pstack;
+    t_pstack* ps = pstack;
     if (ps == nullptr)
     {
         if (fp != nullptr)
@@ -217,8 +220,8 @@ int gmx_ffclose(FILE* fp)
             {
                 ret = pclose(ps->prev->fp);
             }
-            tmp      = ps->prev;
-            ps->prev = ps->prev->prev;
+            t_pstack* tmp = ps->prev;
+            ps->prev      = ps->prev->prev;
             sfree(tmp);
         }
         else
@@ -303,7 +306,7 @@ int gmx_truncate(const std::string& filename, gmx_off_t length)
 
 static FILE* uncompress(const std::string& fn, const char* mode)
 {
-    FILE*       fp;
+    FILE*       fp  = nullptr;
     std::string buf = "uncompress -c < " + fn;
     fprintf(stderr, "Going to execute '%s'\n", buf.c_str());
     if ((fp = popen(buf.c_str(), mode)) == nullptr)
@@ -317,7 +320,7 @@ static FILE* uncompress(const std::string& fn, const char* mode)
 
 static FILE* gunzip(const std::string& fn, const char* mode)
 {
-    FILE*       fp;
+    FILE*       fp  = nullptr;
     std::string buf = "gunzip -c < ";
     buf += fn;
     fprintf(stderr, "Going to execute '%s'\n", buf.c_str());
@@ -332,13 +335,11 @@ static FILE* gunzip(const std::string& fn, const char* mode)
 
 gmx_bool gmx_fexist(const std::string& fname)
 {
-    FILE* test;
-
     if (fname.empty())
     {
         return FALSE;
     }
-    test = fopen(fname.c_str(), "r");
+    FILE* test = fopen(fname.c_str(), "r");
     if (test == nullptr)
     {
 /*Windows doesn't allow fopen of directory - so we need to check this seperately */
@@ -381,7 +382,8 @@ static std::string backup_fn(const std::string& file)
         gmx_fatal(FARGS,
                   "Won't make more than %d backups of %s for you.\n"
                   "The env.var. GMX_MAXBACKUP controls this maximum, -1 disables backups.",
-                  s_maxBackupCount, fn.c_str());
+                  s_maxBackupCount,
+                  fn.c_str());
     }
 
     return buf;
@@ -409,9 +411,7 @@ void make_backup(const std::string& name)
 
 FILE* gmx_ffopen(const std::string& file, const char* mode)
 {
-    FILE*    ff = nullptr;
-    gmx_bool bRead;
-    int      bs;
+    FILE* ff = nullptr;
 
     if (file.empty())
     {
@@ -423,7 +423,7 @@ FILE* gmx_ffopen(const std::string& file, const char* mode)
         make_backup(file);
     }
 
-    bRead = (mode[0] == 'r' && mode[1] != '+');
+    bool bRead = (mode[0] == 'r' && mode[1] != '+');
     if (!bRead || gmx_fexist(file))
     {
         if ((ff = fopen(file.c_str(), mode)) == nullptr)
@@ -437,21 +437,14 @@ FILE* gmx_ffopen(const std::string& file, const char* mode)
         if (bUnbuffered || ((bufsize = getenv("GMX_LOG_BUFFER")) != nullptr))
         {
             /* Check whether to use completely unbuffered */
-            if (bUnbuffered)
-            {
-                bs = 0;
-            }
-            else
-            {
-                bs = strtol(bufsize, nullptr, 10);
-            }
+            const int bs = bUnbuffered ? 0 : strtol(bufsize, nullptr, 10);
             if (bs <= 0)
             {
                 setbuf(ff, nullptr);
             }
             else
             {
-                char* ptr;
+                char* ptr = nullptr;
                 snew(ptr, bs + 8);
                 if (setvbuf(ff, ptr, _IOFBF, bs) != 0)
                 {
@@ -528,10 +521,12 @@ FilePtr openLibraryFile(const char* filename, bool bAddCWD, bool bFatal)
 /*! \brief Use mkstemp (or similar function to make a new temporary
  * file and (on non-Windows systems) return a file descriptor to it.
  *
+ * Note: not thread-safe on non-Windows systems
+ *
  * \todo Use std::string and std::vector<char>. */
 static int makeTemporaryFilename(char* buf)
 {
-    int len;
+    int len = 0;
 
     if ((len = strlen(buf)) < 7)
     {
@@ -545,16 +540,15 @@ static int makeTemporaryFilename(char* buf)
      * since windows doesnt support it we have to separate the cases.
      * 20090307: mktemp deprecated, use iso c++ _mktemp instead.
      */
-    int fd;
 #if GMX_NATIVE_WINDOWS
     _mktemp(buf);
     if (buf == NULL)
     {
         gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf, strerror(errno));
     }
-    fd = 0;
+    int fd = 0;
 #else
-    fd = mkstemp(buf);
+    int fd = mkstemp(buf);
 
     /* mkstemp creates 0600 files - respect umask instead */
     mode_t currUmask = umask(0);
@@ -645,12 +639,10 @@ int gmx_file_copy(const char* oldname, const char* newname, gmx_bool copy_if_emp
 
     while (!feof(in.get()))
     {
-        size_t nread;
-
-        nread = fread(buf.data(), sizeof(char), FILECOPY_BUFSIZE, in.get());
+        size_t nread = fread(buf.data(), sizeof(char), FILECOPY_BUFSIZE, in.get());
         if (nread > 0)
         {
-            size_t ret;
+            size_t ret = 0;
             if (!out)
             {
                 /* so this is where we open when copy_if_empty is false:
@@ -681,16 +673,14 @@ int gmx_fsync(FILE* fp)
     int rc = 0;
 
     {
-        int fn;
-
         /* get the file number */
 #if HAVE_FILENO
-        fn = fileno(fp);
+        int fn = fileno(fp);
 #elif HAVE__FILENO
-        fn = _fileno(fp);
+        int fn = _fileno(fp);
 #else
         GMX_UNUSED_VALUE(fp);
-        fn = -1;
+        int fn = -1;
 #endif
 
         /* do the actual fsync */
@@ -734,8 +724,8 @@ void gmx_chdir(const char* directory)
 #endif
     if (rc != 0)
     {
-        auto message = gmx::formatString("Cannot change directory to '%s'. Reason: %s", directory,
-                                         strerror(errno));
+        auto message = gmx::formatString(
+                "Cannot change directory to '%s'. Reason: %s", directory, strerror(errno));
         GMX_THROW(gmx::FileIOError(message));
     }
 }
index e0d06d56ab3a9de92772d25c22391bf7c43490df..b75f5a81a33fbf980087cf0ba3a5752b03033cd0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2012,2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2014,2015,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +41,7 @@
  */
 #include "gmxpre.h"
 
-#include "gmxassert.h"
+#include "gromacs/utility/gmxassert.h"
 
 #include <cstdio>
 #include <cstdlib>
index 1acd0f7d2a65f78a7dbdf1fab036c5b563c00989..cd79889bb7dd306af30dc9abf498a9e61f54b11d 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -95,7 +95,7 @@ void gmx_omp_set_num_threads(int num_threads)
 #endif
 }
 
-gmx_bool gmx_omp_check_thread_affinity(char** message)
+bool gmx_omp_check_thread_affinity(char** message)
 {
     bool shouldSetAffinity = true;
 
@@ -104,7 +104,7 @@ gmx_bool gmx_omp_check_thread_affinity(char** message)
     /* We assume that the affinity setting is available on all platforms
      * gcc supports. Even if this is not the case (e.g. Mac OS) the user
      * will only get a warning. */
-#    if defined(__GNUC__) || defined(__INTEL_COMPILER)
+#    if defined(__GNUC__)
     const char* programName;
     try
     {
@@ -125,36 +125,14 @@ gmx_bool gmx_omp_check_thread_affinity(char** message)
                     "      setting as the two can conflict and cause performance degradation.\n"
                     "      To keep using the %s internal affinity setting, unset the\n"
                     "      GOMP_CPU_AFFINITY environment variable.",
-                    programName, programName);
+                    programName,
+                    programName);
             *message = gmx_strdup(buf.c_str());
         }
         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
         shouldSetAffinity = false;
     }
-#    endif /* __GNUC__ || __INTEL_COMPILER */
-
-#    if defined(__INTEL_COMPILER)
-    const char* const kmp_env         = getenv("KMP_AFFINITY");
-    const bool        bKmpAffinitySet = (kmp_env != NULL);
-
-    // turn off internal pinning if KMP_AFFINITY is set but does not contain
-    // the settings 'disabled' or 'none'.
-    if (bKmpAffinitySet && (strstr(kmp_env, "disabled") == NULL) && (strstr(kmp_env, "none") == NULL))
-    {
-        try
-        {
-            std::string buf = gmx::formatString(
-                    "NOTE: KMP_AFFINITY set, will turn off %s internal affinity\n"
-                    "      setting as the two can conflict and cause performance degradation.\n"
-                    "      To keep using the %s internal affinity setting, unset the\n"
-                    "      KMP_AFFINITY environment variable or set it to 'none' or 'disabled'.",
-                    programName, programName);
-            *message = gmx_strdup(buf.c_str());
-        }
-        GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
-        shouldSetAffinity = false;
-    }
-#    endif /* __INTEL_COMPILER */
+#    endif /* __GNUC__ */
 
 #endif /* GMX_OPENMP */
     return shouldSetAffinity;
index b4a6f146190d562874f939defebdf385ace24faa..b019e3d1ee0144921cfb6141829e6b2edaf3edf1 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_UTILITY_OMP_H
 #define GMX_UTILITY_OMP_H
 
-#include "config.h"
-
-#include <stdio.h>
-
-#if GMX_NATIVE_WINDOWS
-#    include <windows.h>
-#elif HAVE_XMMINTRIN_H
-#    include <xmmintrin.h>
-#endif
-
-#include "gromacs/utility/basedefinitions.h"
-
 /*! \addtogroup module_utility
  * \{
  */
@@ -113,23 +101,7 @@ void gmx_omp_set_num_threads(int num_threads);
  * allocated for \p *message.
  * If the return value is `true`, \p *message is NULL.
  */
-gmx_bool gmx_omp_check_thread_affinity(char** message);
-
-/*! \brief
- * Pause for use in a spin-wait loop.
- */
-static inline void gmx_pause()
-{
-#if GMX_NATIVE_WINDOWS
-    YieldProcessor();
-#elif HAVE_XMMINTRIN_H
-    _mm_pause();
-#elif defined __MIC__
-    _mm_delay_32(32);
-#else
-    // No wait for unknown architecture
-#endif
-}
+bool gmx_omp_check_thread_affinity(char** message);
 
 /*! \} */
 
index 832077e9da5c354dc7f182c8d5825e16b7b96ee3..cdfc6ad9d26004f89c8388c8ca9d013c4e46ebdf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -276,7 +276,7 @@ public:
     }
     void doString(std::string* value)
     {
-        uint64_t size;
+        uint64_t size = 0;
         doValue<uint64_t>(&size);
         *value = std::string(&buffer_[pos_], size);
         pos_ += size;
index 252eeae886a9760b032e30ca82050b6efca97c17..c289c249d42bbce4a1cdbd67b154718d10d6c89d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <cstddef>
 
+#include <memory>
 #include <vector>
 
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/iserializer.h"
 
 namespace gmx
@@ -96,7 +96,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 class InMemoryDeserializer : public ISerializer
@@ -130,7 +130,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 0955138e627352132967d741571a24d15511a830..21b835dcbeda75bcc6f7be7748ad6558d86796d9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@
 
 int int64_to_int(int64_t step, const char* warn)
 {
-    int i;
-
-    i = static_cast<int>(step);
+    int i = static_cast<int>(step);
 
     if (warn != nullptr && (static_cast<int64_t>(i) != step))
     {
index aa68dea4f7d637c5a5e69806bf42f23f9048f05f..540047566e5fdc4fb65ddb2c517e489200a8581c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -179,6 +179,27 @@ public:
         }
     }
     ///@}
+
+    //! Serialize enum value with underlying type int
+    template<typename EnumType>
+    void doEnumAsInt(EnumType* enumValue)
+    {
+        static_assert(std::is_same<std::underlying_type_t<EnumType>, int>::value,
+                      "Only enums with underlying type int are supported.");
+        auto castedValue = static_cast<int>(*enumValue);
+        doInt(&castedValue);
+        *enumValue = static_cast<EnumType>(castedValue);
+    }
+
+    //! Serialize array of enum values with underlying type.
+    template<typename EnumType>
+    void doEnumArrayAsInt(EnumType* values, int elements)
+    {
+        for (int i = 0; i < elements; i++)
+        {
+            doEnumAsInt<EnumType>(&(values[i]));
+        }
+    }
 };
 
 } // namespace gmx
index adc754772e1e19dc39f2dd9948f623d9e8b49c4c..028939954fd02c174433e7aa8fe0becafc6976cf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -114,7 +114,8 @@ void dumpKeyValueTree(TextWriter* writer, const KeyValueTreeObject& tree)
             writer->wrapperSettings().setIndent(oldIndent);
         }
         else if (value.isArray()
-                 && std::all_of(value.asArray().values().begin(), value.asArray().values().end(),
+                 && std::all_of(value.asArray().values().begin(),
+                                value.asArray().values().end(),
                                 [](const auto& elem) { return elem.isObject(); }))
         {
             // Array containing only objects
@@ -173,7 +174,6 @@ public:
         abstol_(abstol)
     {
     }
-
     void compareObjects(const KeyValueTreeObject& obj1, const KeyValueTreeObject& obj2)
     {
         for (const auto& prop1 : obj1.properties())
@@ -216,7 +216,8 @@ private:
             else if (!areSimpleValuesOfSameTypeEqual(value1, value2))
             {
                 writer_->writeString(currentPath_.toString());
-                writer_->writeLine(formatString(" (%s - %s)", simpleValueToString(value1).c_str(),
+                writer_->writeLine(formatString(" (%s - %s)",
+                                                simpleValueToString(value1).c_str(),
                                                 simpleValueToString(value2).c_str()));
             }
         }
@@ -238,7 +239,7 @@ private:
         }
     }
 
-    bool areSimpleValuesOfSameTypeEqual(const KeyValueTreeValue& value1, const KeyValueTreeValue& value2)
+    bool areSimpleValuesOfSameTypeEqual(const KeyValueTreeValue& value1, const KeyValueTreeValue& value2) const
     {
         GMX_ASSERT(value1.type() == value2.type(), "Caller should ensure that types are equal");
         if (value1.isType<bool>())
@@ -281,13 +282,15 @@ private:
 
     void handleMissingKeyInFirstObject(const KeyValueTreeValue& value)
     {
-        const std::string message = formatString("%s (missing - %s)", currentPath_.toString().c_str(),
+        const std::string message = formatString("%s (missing - %s)",
+                                                 currentPath_.toString().c_str(),
                                                  formatValueForMissingMessage(value).c_str());
         writer_->writeLine(message);
     }
     void handleMissingKeyInSecondObject(const KeyValueTreeValue& value)
     {
-        const std::string message = formatString("%s (%s - missing)", currentPath_.toString().c_str(),
+        const std::string message = formatString("%s (%s - missing)",
+                                                 currentPath_.toString().c_str(),
                                                  formatValueForMissingMessage(value).c_str());
         writer_->writeLine(message);
     }
index 14510239cf3de258e36fcfbe4fb72ef77567f775..3395bb2371dda3ca1e847572787f2020eb10283c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "keyvaluetreeserializer.h"
 
+#include <mutex>
+
 #include "gromacs/utility/iserializer.h"
 #include "gromacs/utility/keyvaluetree.h"
 #include "gromacs/utility/keyvaluetreebuilder.h"
-#include "gromacs/utility/mutex.h"
 
 namespace gmx
 {
@@ -67,14 +68,19 @@ private:
         SerializerFunction   serialize;
         DeserializerFunction deserialize;
     };
-
-    static Mutex                                         s_initMutex;
-    static std::map<std::type_index, Serializer>         s_serializers;
+    // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+    static std::mutex s_initMutex;
+    // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+    static std::map<std::type_index, Serializer> s_serializers;
+    // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
     static std::map<unsigned char, DeserializerFunction> s_deserializers;
 };
 
-Mutex                                                          ValueSerializer::s_initMutex;
-std::map<std::type_index, ValueSerializer::Serializer>         ValueSerializer::s_serializers;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+std::mutex ValueSerializer::s_initMutex;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+std::map<std::type_index, ValueSerializer::Serializer> ValueSerializer::s_serializers;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 std::map<unsigned char, ValueSerializer::DeserializerFunction> ValueSerializer::s_deserializers;
 
 template<typename T>
@@ -102,7 +108,7 @@ struct SerializationTraits<KeyValueTreeObject>
     }
     static void deserializeObject(KeyValueTreeObjectBuilder* builder, ISerializer* serializer)
     {
-        int         count;
+        int         count = 0;
         std::string key;
         serializer->doInt(&count);
         for (int i = 0; i < count; ++i)
@@ -128,7 +134,7 @@ struct SerializationTraits<KeyValueTreeArray>
     static void deserialize(KeyValueTreeValueBuilder* value, ISerializer* serializer)
     {
         KeyValueTreeArrayBuilder builder(value->createArray());
-        int                      count;
+        int                      count = 0;
         serializer->doInt(&count);
         for (int i = 0; i < count; ++i)
         {
@@ -158,7 +164,7 @@ struct SerializationTraits<bool>
     static void serialize(bool value, ISerializer* serializer) { serializer->doBool(&value); }
     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
     {
-        bool value;
+        bool value = false;
         serializer->doBool(&value);
         builder->setValue<bool>(value);
     }
@@ -170,7 +176,7 @@ struct SerializationTraits<int>
     static void serialize(int value, ISerializer* serializer) { serializer->doInt(&value); }
     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
     {
-        int value;
+        int value = 0;
         serializer->doInt(&value);
         builder->setValue<int>(value);
     }
@@ -182,7 +188,7 @@ struct SerializationTraits<int64_t>
     static void serialize(int64_t value, ISerializer* serializer) { serializer->doInt64(&value); }
     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
     {
-        int64_t value;
+        int64_t value = 0;
         serializer->doInt64(&value);
         builder->setValue<int64_t>(value);
     }
@@ -194,7 +200,7 @@ struct SerializationTraits<float>
     static void serialize(float value, ISerializer* serializer) { serializer->doFloat(&value); }
     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
     {
-        float value;
+        float value = 0;
         serializer->doFloat(&value);
         builder->setValue<float>(value);
     }
@@ -206,7 +212,7 @@ struct SerializationTraits<double>
     static void serialize(double value, ISerializer* serializer) { serializer->doDouble(&value); }
     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
     {
-        double value;
+        double value = 0;
         serializer->doDouble(&value);
         builder->setValue<double>(value);
     }
@@ -230,7 +236,7 @@ void serializeValueType(const KeyValueTreeValue& value, ISerializer* serializer)
 // static
 void ValueSerializer::initSerializers()
 {
-    lock_guard<Mutex> lock(s_initMutex);
+    std::lock_guard<std::mutex> lock(s_initMutex);
     if (!s_serializers.empty())
     {
         return;
@@ -262,7 +268,7 @@ void ValueSerializer::serialize(const KeyValueTreeValue& value, ISerializer* ser
 
 KeyValueTreeValue ValueSerializer::deserialize(ISerializer* serializer)
 {
-    unsigned char typeTag;
+    unsigned char typeTag = 0;
     serializer->doUChar(&typeTag);
     auto iter = s_deserializers.find(typeTag);
     GMX_RELEASE_ASSERT(iter != s_deserializers.end(), "Unknown type tag for deserializization");
index 45ac7b87237b1abe0317d9a1b407cc74ddc006df..6c72642c69b995f91a6fbf0d5e77753fde72eca0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
index 9c2a2f5acd5bdefa5a29ad612c290f93d2c9727a..27b6f7dc4225adf2a5c1169634200945f2670806 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_UTILITY_KEYVALUETREETRANSFORM_H
 
 #include <functional>
+#include <memory>
 #include <string>
 #include <typeindex>
 #include <vector>
 
 #include "gromacs/utility/any.h"
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/keyvaluetree.h"
 
 namespace gmx
@@ -137,7 +137,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \libinternal \brief
@@ -351,7 +351,7 @@ public:
                                           IKeyValueTreeErrorHandler* errorHandler) const;
 
 private:
-    PrivateImplPointer<internal::KeyValueTreeTransformerImpl> impl_;
+    std::unique_ptr<internal::KeyValueTreeTransformerImpl> impl_;
 };
 
 class IKeyValueTreeBackMapping
index 5948a01e6c5c21ef1b6459ab302fee613ce60f9d..499f5878ed7413b4945e500593dfdd78a9964b43 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <memory>
 #include <string>
 
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/logger.h"
 
 namespace gmx
@@ -103,7 +102,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \libinternal \brief
@@ -138,8 +137,8 @@ private:
 
     LoggerOwner(std::unique_ptr<Impl> impl);
 
-    PrivateImplPointer<Impl> impl_;
-    const MDLogger*          logger_;
+    std::unique_ptr<Impl> impl_;
+    const MDLogger*       logger_;
 
     friend class LoggerBuilder;
 };
diff --git a/src/gromacs/utility/mdmodulenotification-impl.h b/src/gromacs/utility/mdmodulenotification-impl.h
deleted file mode 100644 (file)
index a402504..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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::MdModuleNotification.
- *
- * \author Christian Blau <blau@kth.se>
- * \inlibraryapi
- * \ingroup module_utility
- */
-
-#ifndef GMX_UTILITY_MDMODULENOTIFICATION_IMPL_H
-#define GMX_UTILITY_MDMODULENOTIFICATION_IMPL_H
-
-#include <functional>
-#include <vector>
-
-namespace gmx
-{
-
-/*! \libinternal \brief
- * Subscribe and trigger notification functions.
- *
- * Extends MdModuleNotificationBase with new notification function and routine
- * to subscribe new listeners.
- *
- * To create a class of this type that provides callbacks, e.g., for events
- * EventA, and EventB use registerMdModuleNotification<EventA, EventB>::type.
- *
- * \tparam CallParameter of the function to be notified
- * \tparam MdModuleNotificationBase class to be extended with a notification
- *                                  with CallParameter
- *
- * \note All added subscribers are required to out-live the MdModuleNotification
- *
- */
-template<class CallParameter, class MdModuleNotificationBase>
-class MdModuleNotification : public MdModuleNotificationBase
-{
-public:
-    //! Make base class notification trigger available to this class
-    using MdModuleNotificationBase::notify;
-    //! Make base class subscription available to this class
-    using MdModuleNotificationBase::subscribe;
-
-    /*! \brief Trigger the subscribed notifications.
-     * \param[in] callParameter of the function to be called back
-     */
-    void notify(CallParameter callParameter) const
-    {
-        for (auto& callBack : callBackFunctions_)
-        {
-            callBack(callParameter);
-        }
-    }
-
-    /*! \brief
-     * Add callback function to be called when notification is triggered.
-     *
-     * Notifications are distinguished by their call signature.
-     *
-     * \param[in] callBackFunction to be called from this class
-     */
-    void subscribe(std::function<void(CallParameter)> callBackFunction)
-    {
-        callBackFunctions_.emplace_back(callBackFunction);
-    }
-
-private:
-    std::vector<std::function<void(CallParameter)>> callBackFunctions_;
-};
-
-/*! \internal
- * \brief Aide to avoid nested MdModuleNotification definition.
- *
- * Instead of
- * MdModuleNotification<CallParameterA, MdModuleNotification<CallParameterB, etc ... >>
- * this allows to write
- * registerMdModuleNotification<CallParameterA, CallParameterB, ...>::type
- *
- * \tparam CallParameter all the event types to be registered
- */
-template<class... CallParameter>
-struct registerMdModuleNotification;
-
-/*! \internal \brief Template specialization to end parameter unpacking recursion.
- */
-template<>
-struct registerMdModuleNotification<>
-{
-    /*! \internal
-     * \brief Do nothing but be base class of MdModuleNotification.
-     *
-     * Required so that using MdModuleNotificationBase::notify and
-     * MdModuleNotificationBase::subscribe are valid in derived class.
-     */
-    class NoCallParameter
-    {
-    public:
-        //! Do nothing but provide MdModuleNotification::notify to derived class
-        void notify() {}
-        //! Do nothing but provide MdModuleNotification::subscribe to derived class
-        void subscribe() {}
-    };
-    /*! \brief Defines a type if no notifications are managed.
-     *
-     * This ensures that code works with MdModuleCallParameterManagement that
-     * does not manage any notifications.
-     */
-    using type = NoCallParameter;
-};
-
-/*! \libinternal
- * \brief Template specialization to assemble MdModuleNotification.
- *
- * Assembly of MdModuleNotification is performed by recursively taking off the
- * front of the CallParameter parameter pack and constructing the nested type
- * definition of MdModuleNotification base classes.
- *
- * \tparam CurrentCallParameter front of the template parameter pack
- * \tparam CallParameter rest of the event types
- */
-template<class CurrentCallParameter, class... CallParameter>
-struct registerMdModuleNotification<CurrentCallParameter, CallParameter...>
-{
-    // private:
-    //! The next type with rest of the arguments with the front parameter removed.
-    using next_type = typename registerMdModuleNotification<CallParameter...>::type;
-    //! The type of the MdModuleNotification
-    using type = MdModuleNotification<CurrentCallParameter, next_type>;
-};
-
-} // namespace gmx
-
-#endif
diff --git a/src/gromacs/utility/mdmodulesnotifier.h b/src/gromacs/utility/mdmodulesnotifier.h
new file mode 100644 (file)
index 0000000..4f080af
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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::MDModulesNotifier and builder.
+ *
+ * \author Christian Blau <blau@kth.se>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+
+#ifndef GMX_UTILITY_MDMODULESNOTIFIER_H
+#define GMX_UTILITY_MDMODULESNOTIFIER_H
+
+#include <functional>
+#include <vector>
+
+namespace gmx
+{
+
+/*! \libinternal
+ * \brief Organizes notifications about an event of interest to modules.
+ *
+ * An object of this type permits modules to subscribe to the
+ * corresponding event. The template types of this type encode what
+ * information is available when the event occurs. Modules \c
+ * subscribe() by providing a callback function that accepts a single
+ * parameter of such an event type. The code that handles that event
+ * has the responsibilty to call \c notify() afterwards. The
+ * subscribed modules then receive the callback with the requested
+ * event type as an argument.
+ *
+ * See gmx::MDModulesNotifiers for sequence diagrams for an example.
+ *
+ * This suits scenarios where several objects are built (or re-built)
+ * and one or more modules need to know when one or more of such
+ * objects are available (or updated), so they can adapt their
+ * internal state accordingly. Examples include responding to loading
+ * input data, or to changes related to a recurring process like
+ * checkpointing or partitioning. The coupling between these modules
+ * is now expressed indirectly. This improves the modularity and
+ * testability of those modules.
+ *
+ * The implementation provides the necessary flexibility to be
+ * parameterized with multiple event types and provide \c callback()
+ * and \b notify() methods corresponding to each related event. This
+ * is done by inheriting from a series of base classes, each of which
+ * handles a single type of event. BuildMDModulesNotifier implements
+ * the details. To create a class of this type that provides two
+ * events with callbacks that receive respectively types TypeA and
+ * TypeB, use BuildMDModulesNotifier<TypeA, TypeB>::type.
+ *
+ * \tparam CallParameter of the function to be notified
+ * \tparam MDModulesNotifierBase class to be extended with a notification
+ *                                  with CallParameter
+ *
+ * \note All added subscribers are required to out-live the MDModulesNotifier
+ *
+ */
+template<class CallParameter, class MDModulesNotifierBase>
+class MDModulesNotifier : public MDModulesNotifierBase
+{
+public:
+    //! Make base class notification trigger available to this class
+    using MDModulesNotifierBase::notify;
+    //! Make base class subscription available to this class
+    using MDModulesNotifierBase::subscribe;
+
+    /*! \brief Notifies subscribers of the event described by \c
+     * callbackParameter.
+     *
+     * \param[in] callParameter of the function to be called back
+     */
+    void notify(CallParameter callParameter) const
+    {
+        for (auto& callBack : callBackFunctions_)
+        {
+            callBack(callParameter);
+        }
+    }
+
+    /*! \brief
+     * Add callback function to be called when \c notify() is called
+     *
+     * \param[in] callBackFunction to be called
+     */
+    void subscribe(std::function<void(CallParameter)> callBackFunction)
+    {
+        callBackFunctions_.emplace_back(callBackFunction);
+    }
+
+private:
+    std::vector<std::function<void(CallParameter)>> callBackFunctions_;
+};
+
+/*! \internal
+ * \brief Aide to avoid nested MDModulesNotifier definition.
+ *
+ * Instead of
+ * MDModulesNotifier<CallParameterA, MDModulesNotifier<CallParameterB, etc ... >>
+ * this allows to write
+ * BuildMDModulesNotifier<CallParameterA, CallParameterB, ...>::type
+ *
+ * \tparam CallParameter all the callback types to be registered
+ */
+template<class... CallParameter>
+struct BuildMDModulesNotifier;
+
+/*! \internal \brief Template specialization to end parameter unpacking recursion.
+ */
+template<>
+struct BuildMDModulesNotifier<>
+{
+    /*! \internal
+     * \brief Do nothing but be base class of MDModulesNotifier.
+     *
+     * Required so that using MDModulesNotifierBase::notify and
+     * MDModulesNotifierBase::subscribe are valid in derived class.
+     */
+    class NoCallParameter
+    {
+    public:
+        //! Do nothing but provide MDModulesNotifier::notify to derived class
+        void notify() {}
+        //! Do nothing but provide MDModulesNotifier::subscribe to derived class
+        void subscribe() {}
+    };
+    /*! \brief Defines a type if no notifications are managed.
+     *
+     * This ensures that code works with MDModuleCallParameterManagement that
+     * does not manage any notifications.
+     */
+    using type = NoCallParameter;
+};
+
+/*! \libinternal
+ * \brief Template specialization to assemble MDModulesNotifier.
+ *
+ * Assembly of MDModulesNotifier is performed by recursively taking off the
+ * front of the CallParameter parameter pack and constructing the nested type
+ * definition of MDModulesNotifier base classes.
+ *
+ * \tparam CurrentCallParameter front of the template parameter pack
+ * \tparam CallParameter rest of the callback types
+ */
+template<class CurrentCallParameter, class... CallParameter>
+struct BuildMDModulesNotifier<CurrentCallParameter, CallParameter...>
+{
+    // private:
+    //! The next type with rest of the arguments with the front parameter removed.
+    using next_type = typename BuildMDModulesNotifier<CallParameter...>::type;
+    //! The type of the MDModulesNotifier
+    using type = MDModulesNotifier<CurrentCallParameter, next_type>;
+};
+
+} // namespace gmx
+
+#endif
similarity index 51%
rename from src/gromacs/utility/mdmodulenotification.h
rename to src/gromacs/utility/mdmodulesnotifiers.h
index c3eae03170688a665b294e3ba574510f4df4fd6e..012527fa9609bb6574c024239c305fbdaf9a6993 100644 (file)
  */
 /*! \libinternal \file
  * \brief
- * Declares gmx::MdModulesNotifier.
+ * Declares gmx::MDModulesNotifiers.
  *
  * \author Christian Blau <blau@kth.se>
  * \inlibraryapi
  * \ingroup module_utility
  */
 
-#ifndef GMX_UTILITY_MDMODULENOTIFICATION_H
-#define GMX_UTILITY_MDMODULENOTIFICATION_H
+#ifndef GMX_UTILITY_MDMODULESNOTIFIERS_H
+#define GMX_UTILITY_MDMODULESNOTIFIERS_H
 
 #include <string>
 #include <vector>
 
-#include "gromacs/utility/mdmodulenotification-impl.h"
+#include "gromacs/utility/mdmodulesnotifier.h"
 
 struct t_commrec;
+struct gmx_mtop_t;
 enum class PbcType : int;
 
 namespace gmx
@@ -59,15 +60,16 @@ class KeyValueTreeObject;
 class KeyValueTreeObjectBuilder;
 class LocalAtomSetManager;
 class IndexGroupsAndNames;
-struct MdModulesCheckpointReadingDataOnMaster;
-struct MdModulesCheckpointReadingBroadcast;
-struct MdModulesWriteCheckpointData;
+class SeparatePmeRanksPermitted;
+struct MDModulesCheckpointReadingDataOnMaster;
+struct MDModulesCheckpointReadingBroadcast;
+struct MDModulesWriteCheckpointData;
 
 /*! \libinternal \brief Check if module outputs energy to a specific field.
  *
  * Ensures that energy is output for this module.
  */
-struct MdModulesEnergyOutputToDensityFittingRequestChecker
+struct MDModulesEnergyOutputToDensityFittingRequestChecker
 {
     //! Trigger output to density fitting energy field
     bool energyOutputToDensityFitting_ = false;
@@ -117,53 +119,98 @@ struct SimulationTimeStep
 };
 
 /*! \libinternal
- * \brief Collection of callbacks to MDModules at differnt run-times.
+ * \brief Group of notifers to organize that MDModules
+ * can receive callbacks they subscribe to.
  *
- * MDModules use members of this struct to sign up for callback functionality.
- *
- * The members of the struct represent callbacks at these run-times:
- *
- *  When pre-processing the simulation data
- *  When reading and writing check-pointing data
- *  When setting up simulation after reading in the tpr file
+ * MDModules use members of this struct to subscribe to notifications
+ * of particular events. When the event occurs, the callback provided
+ * by a particular MDModule will be passed a parameter of the
+ * particular type they are interested in.
  *
+ * Typically, during the setup phase, modules subscribe to notifiers
+ * that interest them by passing callbacks that expect a single parameter
+ * that describes the event. These are stored for later use. See the
+ * sequence diagram that follows:
    \msc
-   wordwraparcs=true,
-   hscale="2";
-
-   runner [label="runner:\nMdrunner"],
-   CallParameter [label = "eventA:\nCallParameter"],
-   MOD [label = "mdModules_:\nMdModules"],
-   ModuleA [label="moduleA"],
-   ModuleB [label="moduleB"],
-   MdModuleNotification [label="notifier_:\nMdModuleNotification"];
-
-   MOD box MdModuleNotification [label = "mdModules_ owns notifier_ and moduleA/B"];
-   MOD =>> ModuleA [label="instantiates(notifier_)"];
-   ModuleA =>> MdModuleNotification [label="subscribe(otherfunc)"];
-   ModuleA =>> MOD;
-   MOD =>> ModuleB [label="instantiates(notifier_)"];
-   ModuleB =>> MdModuleNotification [label="subscribe(func)"];
-   ModuleB =>> MOD;
-   runner =>> CallParameter [label="instantiate"];
-   CallParameter =>> runner ;
-   runner =>> MOD [label="notify(eventA)"];
-   MOD =>> MdModuleNotification [label="notify(eventA)"];
-   MdModuleNotification =>> ModuleA [label="notify(eventA)"];
-   ModuleA -> ModuleA [label="func(eventA)"];
-   MdModuleNotification =>> ModuleB [label="notify(eventA)"];
-   ModuleB -> ModuleB [label="otherfunc(eventA)"];
+wordwraparcs=true,
+hscale="2";
+
+modules [label = "mdModules:\nMDModules"],
+notifiers [label="notifiers\nMDModulesNotifiers"],
+notifier [label="exampleNotifier:\nBuildMDModulesNotifier\n<EventX, EventY>::type"],
+moduleA [label="moduleA"],
+moduleB [label="moduleB"],
+moduleC [label="moduleC"];
+
+modules box moduleC [label = "mdModules creates and owns moduleA, moduleB, and moduleC"];
+modules =>> notifiers [label="creates"];
+notifiers =>> notifier [label="creates"];
+notifier =>> notifiers [label="returns"];
+notifiers =>> modules [label="returns"];
+
+modules =>> moduleA [label="provides notifiers"];
+moduleA =>> moduleA [label="unpacks\nnotifiers.exampleNotifier"];
+moduleA =>> notifier [label="subscribes with\ncallback(EventX&)"];
+notifier =>> notifier [label="records subscription\nto EventX"];
+moduleA =>> notifier [label="subscribes with\ncallback(EventY&)"];
+notifier =>> notifier [label="records subscription\nto EventY"];
+moduleA =>> modules [label="returns"];
+
+modules =>> moduleB [label="provides notifiers"];
+moduleB =>> moduleB [label="unpacks\nnotifiers.exampleNotifier"];
+moduleA =>> notifier [label="subscribes with\ncallback(EventY&)"];
+notifier =>> notifier [label="records subscription\nto EventY"];
+moduleB =>> modules [label="returns"];
+
+modules =>> moduleC [label="provides notifiers"];
+moduleC =>> moduleC [label="unpacks and keeps\nnotifiers.exampleNotifier"];
+moduleC =>> modules [label="returns"];
 
    \endmsc
+
+   * When the event occurs later on, the stored callbacks are used to
+   * allow the modules to react. See the following sequence diagram,
+   * which assumes that exampleNotifier was configured as in the
+   * previous sequence diagram.
+
+   \msc
+wordwraparcs=true,
+hscale="2";
+
+moduleC [label="moduleC"],
+notifier [label="exampleNotifier:\nBuildMDModulesNotifier\n<EventX, EventY>::type"],
+moduleA [label="moduleA"],
+moduleB [label="moduleB"];
+
+moduleC box moduleB [label = "Later, when ModuleC is doing work"];
+moduleC =>> moduleC [label="generates EventX"];
+moduleC =>> moduleC [label="generates EventY"];
+moduleC =>> notifier [label="calls notify(eventX)"];
+notifier =>> moduleA [label="calls callback(eventX)"];
+moduleA =>> moduleA [label="reacts to eventX"];
+moduleA =>> notifier [label="returns"];
+
+notifier =>> moduleC [label="returns"];
+moduleC =>> notifier [label="calls notify(eventY)"];
+notifier =>> moduleA [label="calls callback(eventY)"];
+moduleA =>> moduleA [label="reacts to eventY"];
+moduleA =>> notifier [label="returns"];
+notifier =>> moduleB [label="calls callback(eventY)"];
+moduleB =>> moduleB [label="reacts to eventY"];
+moduleB =>> notifier [label="returns"];
+notifier =>> moduleC [label="returns"];
+   \endmsc
  *
- * The template arguments to the members of this struct directly reflect
- * the callback function signature. Arguments passed as pointers are always
- * meant to be modified, but never meant to be stored (in line with the policy
+ * The template arguments to the members of this struct are the
+ * parameters passed to the callback functions, one type per
+ * callback. Arguments passed as pointers are always meant to be
+ * modified, but never meant to be stored (in line with the policy
  * everywhere else).
+ *
  */
-struct MdModulesNotifier
+struct MDModulesNotifiers
 {
-    /*! \brief Pre-processing callback functions.
+    /*! \brief Handles subscribing and calling pre-processing callback functions.
      *
      * EnergyCalculationFrequencyErrors* allows modules to check if they match
      *                                   their required calculation frequency
@@ -173,33 +220,35 @@ struct MdModulesNotifier
      * KeyValueTreeObjectBuilder enables writing of module internal data to
      *                           .tpr files.
      */
-    registerMdModuleNotification<EnergyCalculationFrequencyErrors*, const IndexGroupsAndNames&, KeyValueTreeObjectBuilder>::type preProcessingNotifications_;
+    BuildMDModulesNotifier<EnergyCalculationFrequencyErrors*, const IndexGroupsAndNames&, KeyValueTreeObjectBuilder>::type preProcessingNotifier_;
 
-    /*! \brief Checkpointing callback functions.
+    /*! \brief Handles subscribing and calling checkpointing callback functions.
      *
-     * MdModulesCheckpointReadingDataOnMaster provides modules with their
+     * MDModulesCheckpointReadingDataOnMaster provides modules with their
      *                                        checkpointed data on the master
      *                                        node and checkpoint file version
-     * MdModulesCheckpointReadingBroadcast provides modules with a communicator
+     * MDModulesCheckpointReadingBroadcast provides modules with a communicator
      *                                     and the checkpoint file version to
      *                                     distribute their data
-     * MdModulesWriteCheckpointData provides the modules with a key-value-tree
+     * MDModulesWriteCheckpointData provides the modules with a key-value-tree
      *                              builder to store their checkpoint data and
      *                              the checkpoint file version
      */
-    registerMdModuleNotification<MdModulesCheckpointReadingDataOnMaster,
-                                 MdModulesCheckpointReadingBroadcast,
-                                 MdModulesWriteCheckpointData>::type checkpointingNotifications_;
+    BuildMDModulesNotifier<MDModulesCheckpointReadingDataOnMaster, MDModulesCheckpointReadingBroadcast, MDModulesWriteCheckpointData>::type
+            checkpointingNotifier_;
 
-    /*! \brief Callbacks during simulation setup.
+    /*! \brief Handles subscribing and calling callbacks during simulation setup.
      *
      * const KeyValueTreeObject& provides modules with the internal data they
      *                           wrote to .tpr files
      * LocalAtomSetManager* enables modules to add atom indices to local atom sets
      *                      to be managed
-     * MdModulesEnergyOutputToDensityFittingRequestChecker* enables modules to
+     * const gmx_mtop_t& provides the topology of the system to the modules
+     * MDModulesEnergyOutputToDensityFittingRequestChecker* enables modules to
      *                      report if they want to write their energy output
      *                      to the density fitting field in the energy files
+     * SeparatePmeRanksPermitted* enables modules to report if they want
+     *                      to disable dedicated PME ranks
      * const PbcType& provides modules with the periodic boundary condition type
      *                that is used during the simulation
      * const SimulationTimeStep& provides modules with the simulation time-step
@@ -208,12 +257,14 @@ struct MdModulesNotifier
      * const t_commrec& provides a communicator to the modules during simulation
      *                  setup
      */
-    registerMdModuleNotification<const KeyValueTreeObject&,
-                                 LocalAtomSetManager*,
-                                 MdModulesEnergyOutputToDensityFittingRequestChecker*,
-                                 const PbcType&,
-                                 const SimulationTimeStep&,
-                                 const t_commrec&>::type simulationSetupNotifications_;
+    BuildMDModulesNotifier<const KeyValueTreeObject&,
+                           LocalAtomSetManager*,
+                           const gmx_mtop_t&,
+                           MDModulesEnergyOutputToDensityFittingRequestChecker*,
+                           SeparatePmeRanksPermitted*,
+                           const PbcType&,
+                           const SimulationTimeStep&,
+                           const t_commrec&>::type simulationSetupNotifier_;
 };
 
 } // namespace gmx
index ee56774f867baa21b65017596346ca766daa87f9..8b1595fd4330ea6a170789ba9c015b2a5e75309d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2012,2013,2014,2019, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2013,2014,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_UTILITY_MESSAGESTRINGCOLLECTOR_H
 #define GMX_UTILITY_MESSAGESTRINGCOLLECTOR_H
 
+#include <memory>
 #include <string>
 
 #include "gromacs/utility/classhelpers.h"
@@ -98,13 +99,13 @@ public:
     void clear();
 
     /*! \brief
-     * Returns true if any messages have been added.
+     * Returns false if any messages have been added.
      *
-     * \returns true if append() has been called at least once.
+     * \returns false if append() has been called at least once.
      *
      * The return value is identical to `toString().empty()`.
-     * Calls to startContext() or finishContext() only do not cause this
-     * function to return true.
+     * Calls to startContext() or finishContext() do not affect the
+     * return value of this function.
      */
     bool isEmpty() const;
     /*! \brief
@@ -115,7 +116,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \libinternal \brief
diff --git a/src/gromacs/utility/mpiinfo.cpp b/src/gromacs/utility/mpiinfo.cpp
new file mode 100644 (file)
index 0000000..ea26413
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 "gromacs/utility/mpiinfo.h"
+
+// need to include gmxapi.h here as mpi.h needs to be included before mpi-ext.h
+#include "gromacs/utility/gmxmpi.h"
+
+#if HAVE_CUDA_AWARE_MPI
+#    include <mpi-ext.h>
+#endif
+
+namespace gmx
+{
+
+CudaAwareMpiStatus checkMpiCudaAwareSupport()
+{
+#if defined(MPIX_CUDA_AWARE_SUPPORT)
+    // With OMPI version <=4.x, this function doesn't check if UCX PML is built with CUDA-support
+    // or if CUDA is disabled at runtime.
+    // Expect this function to work only if OMPI uses OB1 PML
+    // This is a known issue (https://github.com/open-mpi/ompi/issues/7963) and fix for this is
+    // expected soon (written March 2021)
+    CudaAwareMpiStatus status = (MPIX_Query_cuda_support() == 1) ? CudaAwareMpiStatus::Supported
+                                                                 : CudaAwareMpiStatus::NotSupported;
+#else
+    CudaAwareMpiStatus status = CudaAwareMpiStatus::NotKnown;
+#endif
+
+    return status;
+}
+
+} // namespace gmx
similarity index 65%
rename from src/gromacs/simd/impl_arm_neon/impl_arm_neon_general.h
rename to src/gromacs/utility/mpiinfo.h
index 966fb4ce370c8e865640668eba71cc2135617999..0c8b0e5c407c86399f403255b4279d6440993ead 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_SIMD_IMPL_ARM_NEON_GENERAL_H
-#define GMX_SIMD_IMPL_ARM_NEON_GENERAL_H
+#ifndef GMX_UTILITY_MPI_INFO_H
+#define GMX_UTILITY_MPI_INFO_H
 
 namespace gmx
 {
-
-static inline void simdPrefetch(void* m)
+/*! \brief Enum describing CUDA-aware support in underlying MPI library.
+ */
+enum class CudaAwareMpiStatus : int
 {
-#ifdef __GNUC__
-    __builtin_prefetch(m);
-#endif
-}
+    Supported,    //!< CUDA-aware support available.
+    NotSupported, //!< CUDA-aware support NOT available.
+    NotKnown      //!< CUDA-aware support status not known.
+};
+
+
+/*! \brief
+ * Wrapper on top of MPIX_Query_cuda_support()
+ * For MPI implementations which don't support this function, it returns NotKnown
+ * Even when an MPI implementation does support this function, MPI library might not be
+ * robust enough to detect CUDA-aware support at runtime correcly e.g. when UCX PML is used
+ * or CUDA is disabled at runtime
+ *
+ * \returns     CUDA-aware status in MPI implementation */
+CudaAwareMpiStatus checkMpiCudaAwareSupport();
 
 } // namespace gmx
 
-#endif // GMX_SIMD_IMPL_ARM_NEON_GENERAL_H
+#endif
index 333b9f5c02ba615f4aeb6387b3df659d494d1d8b..f54ff08f8d811d772704f91f514ed40b29edfa3e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 @@ namespace gmx
 
 void niceHeader(TextWriter* writer, const char* fn, char commentChar)
 {
-    int  uid;
     char userbuf[256];
     char hostbuf[256];
 
@@ -60,7 +59,7 @@ void niceHeader(TextWriter* writer, const char* fn, char commentChar)
     writer->writeLine(formatString("%c", commentChar));
     writer->writeLine(formatString("%c\tFile '%s' was generated", commentChar, fn ? fn : "unknown"));
 
-    uid = gmx_getuid();
+    int uid = gmx_getuid();
     gmx_getusername(userbuf, 256);
     gmx_gethostname(hostbuf, 256);
 
index 1b0f4645af6ec9f72660429a5aba23909fbbcf51..5185d5268d849e5a3da3d8f9d591bc5424ec416e 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2011-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -162,11 +162,21 @@ bool Path::isEquivalent(const std::string& path1, const std::string& path2)
 
     // p2 is done first, so any error reported is for p1
     // FixME: #1635
-    handle_wrapper h2(CreateFile(path2.c_str(), 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
-                                 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
-
-    handle_wrapper h1(CreateFile(path1.c_str(), 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
-                                 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
+    handle_wrapper h2(CreateFile(path2.c_str(),
+                                 0,
+                                 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                 0,
+                                 OPEN_EXISTING,
+                                 FILE_FLAG_BACKUP_SEMANTICS,
+                                 0));
+
+    handle_wrapper h1(CreateFile(path1.c_str(),
+                                 0,
+                                 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                 0,
+                                 OPEN_EXISTING,
+                                 FILE_FLAG_BACKUP_SEMANTICS,
+                                 0));
 
     if (h1.handle == INVALID_HANDLE_VALUE || h2.handle == INVALID_HANDLE_VALUE)
     {
@@ -213,8 +223,8 @@ bool Path::isEquivalent(const std::string& path1, const std::string& path2)
         // but if both are invalid then it is an error.
         if (e1 != 0 && e2 != 0)
         {
-            GMX_THROW_WITH_ERRNO(FileIOError("Path::isEquivalent called with two invalid files"),
-                                 "stat", errno);
+            GMX_THROW_WITH_ERRNO(
+                    FileIOError("Path::isEquivalent called with two invalid files"), "stat", errno);
         }
         return false;
     }
@@ -419,8 +429,8 @@ std::string Path::getWorkingDirectory()
 
 void Path::splitPathEnvironment(const std::string& pathEnv, std::vector<std::string>* result)
 {
-    size_t prevPos = 0;
-    size_t separator;
+    size_t prevPos   = 0;
+    size_t separator = 0;
     do
     {
         separator = pathEnv.find(cPathSeparator, prevPos);
@@ -452,7 +462,7 @@ std::string Path::resolveSymlinks(const std::string& path)
     std::string result(path);
 #if !GMX_NATIVE_WINDOWS
     char buf[GMX_PATH_MAX];
-    int  length;
+    int  length = 0;
     while ((length = readlink(result.c_str(), buf, sizeof(buf) - 1)) > 0)
     {
         buf[length] = '\0';
@@ -488,8 +498,8 @@ void File::throwOnError(const NotFoundInfo& info)
 void File::throwOnNotFound(const NotFoundInfo& info)
 {
     throwOnError(info);
-    const std::string message = formatString("File '%s' does not exist or is not accessible.\n%s",
-                                             info.filename, info.message);
+    const std::string message = formatString(
+            "File '%s' does not exist or is not accessible.\n%s", info.filename, info.message);
     GMX_THROW_WITH_ERRNO(InvalidInputError(message), info.call, info.err);
 }
 
index 827a9bf301fbd3810d0684b6ebc7fb52796a1186..8d9866dcd9a3c4ce497573199d88c4902cd724da 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -69,15 +69,15 @@ void MPI_Comm_free_wrapper(MPI_Comm* comm)
 PhysicalNodeCommunicator::PhysicalNodeCommunicator(MPI_Comm world, int physicalNodeId)
 {
 #if GMX_MPI
-    int isInitialized;
+    int isInitialized = 0;
     MPI_Initialized(&isInitialized);
     if (isInitialized)
     {
-        int sizeOfWorld;
+        int sizeOfWorld = 0;
         MPI_Comm_size(world, &sizeOfWorld);
         if (sizeOfWorld > 1)
         {
-            int rankWithinWorld;
+            int rankWithinWorld = 0;
             MPI_Comm_rank(world, &rankWithinWorld);
             MPI_Comm_split(world, physicalNodeId, rankWithinWorld, &comm_);
             auto ptr = MPI_Comm_ptr(&comm_);
index c5985c48fdbc7e1dd791a349233537951f17a1e4..65bfe5c7dbd9cd54f01c7db13e23bf7fc5b8bd97 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,268 +57,531 @@ typedef struct
     const char* pages;
 } t_citerec;
 
+static constexpr int sc_lineWidth = 79;
+
 void please_cite(FILE* fp, const char* key)
 {
     static const t_citerec citedb[] = {
-        { "Allen1987a", "M. P. Allen and D. J. Tildesley", "Computer simulation of liquids",
-          "Oxford Science Publications", 1, 1987, "1" },
-        { "Berendsen95a", "H. J. C. Berendsen, D. van der Spoel and R. van Drunen",
+        { "Allen1987a",
+          "M. P. Allen and D. J. Tildesley",
+          "Computer simulation of liquids",
+          "Oxford Science Publications",
+          1,
+          1987,
+          "1" },
+        { "Berendsen95a",
+          "H. J. C. Berendsen, D. van der Spoel and R. van Drunen",
           "GROMACS: A message-passing parallel molecular dynamics implementation",
-          "Comp. Phys. Comm.", 91, 1995, "43-56" },
-        { "Berendsen84a", "H. J. C. Berendsen, J. P. M. Postma, A. DiNola and J. R. Haak",
-          "Molecular dynamics with coupling to an external bath", "J. Chem. Phys.", 81, 1984,
+          "Comp. Phys. Comm.",
+          91,
+          1995,
+          "43-56" },
+        { "Berendsen84a",
+          "H. J. C. Berendsen, J. P. M. Postma, A. DiNola and J. R. Haak",
+          "Molecular dynamics with coupling to an external bath",
+          "J. Chem. Phys.",
+          81,
+          1984,
           "3684-3690" },
-        { "Ryckaert77a", "J. P. Ryckaert and G. Ciccotti and H. J. C. Berendsen",
+        { "Ryckaert77a",
+          "J. P. Ryckaert and G. Ciccotti and H. J. C. Berendsen",
           "Numerical Integration of the Cartesian Equations of Motion of a System with "
           "Constraints; Molecular Dynamics of n-Alkanes",
-          "J. Comp. Phys.", 23, 1977, "327-341" },
-        { "Miyamoto92a", "S. Miyamoto and P. A. Kollman",
+          "J. Comp. Phys.",
+          23,
+          1977,
+          "327-341" },
+        { "Miyamoto92a",
+          "S. Miyamoto and P. A. Kollman",
           "SETTLE: An Analytical Version of the SHAKE and RATTLE Algorithms for Rigid Water Models",
-          "J. Comp. Chem.", 13, 1992, "952-962" },
-        { "Cromer1968a", "D. T. Cromer & J. B. Mann",
+          "J. Comp. Chem.",
+          13,
+          1992,
+          "952-962" },
+        { "Cromer1968a",
+          "D. T. Cromer & J. B. Mann",
           "X-ray scattering factors computed from numerical Hartree-Fock wave functions",
-          "Acta Cryst. A", 24, 1968, "321" },
-        { "Barth95a", "E. Barth and K. Kuczera and B. Leimkuhler and R. D. Skeel",
-          "Algorithms for Constrained Molecular Dynamics", "J. Comp. Chem.", 16, 1995, "1192-1209" },
+          "Acta Cryst. A",
+          24,
+          1968,
+          "321" },
+        { "Barth95a",
+          "E. Barth and K. Kuczera and B. Leimkuhler and R. D. Skeel",
+          "Algorithms for Constrained Molecular Dynamics",
+          "J. Comp. Chem.",
+          16,
+          1995,
+          "1192-1209" },
         { "Essmann95a",
           "U. Essmann, L. Perera, M. L. Berkowitz, T. Darden, H. Lee and L. G. Pedersen ",
-          "A smooth particle mesh Ewald method", "J. Chem. Phys.", 103, 1995, "8577-8592" },
-        { "Torda89a", "A. E. Torda and R. M. Scheek and W. F. van Gunsteren",
+          "A smooth particle mesh Ewald method",
+          "J. Chem. Phys.",
+          103,
+          1995,
+          "8577-8592" },
+        { "Torda89a",
+          "A. E. Torda and R. M. Scheek and W. F. van Gunsteren",
           "Time-dependent distance restraints in molecular dynamics simulations",
-          "Chem. Phys. Lett.", 157, 1989, "289-294" },
-        { "Tironi95a", "I. G. Tironi and R. Sperb and P. E. Smith and W. F. van Gunsteren",
-          "Generalized reaction field method for molecular dynamics simulations", "J. Chem. Phys",
-          102, 1995, "5451-5459" },
-        { "Hess97a", "B. Hess and H. Bekker and H. J. C. Berendsen and J. G. E. M. Fraaije",
-          "LINCS: A Linear Constraint Solver for molecular simulations", "J. Comp. Chem.", 18, 1997,
+          "Chem. Phys. Lett.",
+          157,
+          1989,
+          "289-294" },
+        { "Tironi95a",
+          "I. G. Tironi and R. Sperb and P. E. Smith and W. F. van Gunsteren",
+          "Generalized reaction field method for molecular dynamics simulations",
+          "J. Chem. Phys",
+          102,
+          1995,
+          "5451-5459" },
+        { "Hess97a",
+          "B. Hess and H. Bekker and H. J. C. Berendsen and J. G. E. M. Fraaije",
+          "LINCS: A Linear Constraint Solver for molecular simulations",
+          "J. Comp. Chem.",
+          18,
+          1997,
           "1463-1472" },
-        { "Hess2008a", "B. Hess",
+        { "Hess2008a",
+          "B. Hess",
           "P-LINCS: A Parallel Linear Constraint Solver for molecular simulation",
-          "J. Chem. Theory Comput.", 4, 2008, "116-122" },
-        { "Hess2008b", "B. Hess and C. Kutzner and D. van der Spoel and E. Lindahl",
+          "J. Chem. Theory Comput.",
+          4,
+          2008,
+          "116-122" },
+        { "Hess2008b",
+          "B. Hess and C. Kutzner and D. van der Spoel and E. Lindahl",
           "GROMACS 4: Algorithms for highly efficient, load-balanced, and scalable molecular "
           "simulation",
-          "J. Chem. Theory Comput.", 4, 2008, "435-447" },
-        { "Hub2010", "J. S. Hub, B. L. de Groot and D. van der Spoel",
+          "J. Chem. Theory Comput.",
+          4,
+          2008,
+          "435-447" },
+        { "Hub2010",
+          "J. S. Hub, B. L. de Groot and D. van der Spoel",
           "g_wham - A free weighted histogram analysis implementation including robust error and "
           "autocorrelation estimates",
-          "J. Chem. Theory Comput.", 6, 2010, "3713-3720" },
-        { "In-Chul99a", "Y. In-Chul and M. L. Berkowitz",
-          "Ewald summation for systems with slab geometry", "J. Chem. Phys.", 111, 1999,
+          "J. Chem. Theory Comput.",
+          6,
+          2010,
+          "3713-3720" },
+        { "In-Chul99a",
+          "Y. In-Chul and M. L. Berkowitz",
+          "Ewald summation for systems with slab geometry",
+          "J. Chem. Phys.",
+          111,
+          1999,
           "3155-3162" },
         { "DeGroot97a",
           "B. L. de Groot and D. M. F. van Aalten and R. M. Scheek and A. Amadei and G. Vriend and "
           "H. J. C. Berendsen",
-          "Prediction of Protein Conformational Freedom From Distance Constrains", "Proteins", 29,
-          1997, "240-251" },
-        { "Spoel98a", "D. van der Spoel and P. J. van Maaren and H. J. C. Berendsen",
+          "Prediction of Protein Conformational Freedom From Distance Constrains",
+          "Proteins",
+          29,
+          1997,
+          "240-251" },
+        { "Spoel98a",
+          "D. van der Spoel and P. J. van Maaren and H. J. C. Berendsen",
           "A systematic study of water models for molecular simulation. Derivation of models "
           "optimized for use with a reaction-field.",
-          "J. Chem. Phys.", 108, 1998, "10220-10230" },
-        { "Wishart98a", "D. S. Wishart and A. M. Nip",
-          "Protein Chemical Shift Analysis: A Practical Guide", "Biochem. Cell Biol.", 76, 1998,
+          "J. Chem. Phys.",
+          108,
+          1998,
+          "10220-10230" },
+        { "Wishart98a",
+          "D. S. Wishart and A. M. Nip",
+          "Protein Chemical Shift Analysis: A Practical Guide",
+          "Biochem. Cell Biol.",
+          76,
+          1998,
           "153-163" },
-        { "Maiorov95", "V. N. Maiorov and G. M. Crippen",
+        { "Maiorov95",
+          "V. N. Maiorov and G. M. Crippen",
           "Size-Independent Comparison of Protein Three-Dimensional Structures",
-          "PROTEINS: Struct. Funct. Gen.", 22, 1995, "273-283" },
-        { "Feenstra99", "K. A. Feenstra and B. Hess and H. J. C. Berendsen",
+          "PROTEINS: Struct. Funct. Gen.",
+          22,
+          1995,
+          "273-283" },
+        { "Feenstra99",
+          "K. A. Feenstra and B. Hess and H. J. C. Berendsen",
           "Improving Efficiency of Large Time-scale Molecular Dynamics Simulations of "
           "Hydrogen-rich Systems",
-          "J. Comput. Chem.", 20, 1999, "786-798" },
+          "J. Comput. Chem.",
+          20,
+          1999,
+          "786-798" },
         { "Lourenco2013a",
           "Tuanan C. Lourenco and Mariny F. C. Coelho and Teodorico C. Ramalho and David van der "
           "Spoel and Luciano T. Costa",
           "Insights on the Solubility of CO2 in 1-Ethyl-3-methylimidazolium "
           "Bis(trifluoromethylsulfonyl)imide from the Microscopic Point of View",
-          "Environ. Sci. Technol.", 47, 2013, "7421-7429" },
-        { "Timneanu2004a", "N. Timneanu and C. Caleman and J. Hajdu and D. van der Spoel",
-          "Auger Electron Cascades in Water and Ice", "Chem. Phys.", 299, 2004, "277-283" },
-        { "Pascal2011a", "T. A. Pascal and S. T. Lin and W. A. Goddard III",
+          "Environ. Sci. Technol.",
+          47,
+          2013,
+          "7421-7429" },
+        { "Timneanu2004a",
+          "N. Timneanu and C. Caleman and J. Hajdu and D. van der Spoel",
+          "Auger Electron Cascades in Water and Ice",
+          "Chem. Phys.",
+          299,
+          2004,
+          "277-283" },
+        { "Pascal2011a",
+          "T. A. Pascal and S. T. Lin and W. A. Goddard III",
           "Thermodynamics of liquids: standard molar entropies and heat capacities of common "
           "solvents from 2PT molecular dynamics",
-          "Phys. Chem. Chem. Phys.", 13, 2011, "169-181" },
-        { "Caleman2008a", "C. Caleman and D. van der Spoel",
+          "Phys. Chem. Chem. Phys.",
+          13,
+          2011,
+          "169-181" },
+        { "Caleman2008a",
+          "C. Caleman and D. van der Spoel",
           "Picosecond Melting of Ice by an Infrared Laser Pulse: A Simulation Study",
-          "Angew. Chem. Int. Ed", 47, 2008, "1417-1420" },
+          "Angew. Chem. Int. Ed",
+          47,
+          2008,
+          "1417-1420" },
         { "Caleman2011b",
           "C. Caleman and P. J. van Maaren and M. Hong and J. S. Hub and L. T. da Costa and D. van "
           "der Spoel",
           "Force Field Benchmark of Organic Liquids: Density, Enthalpy of Vaporization, Heat "
           "Capacities, Surface Tension, Isothermal Compressibility, Volumetric Expansion "
           "Coefficient, and Dielectric Constant",
-          "J. Chem. Theo. Comp.", 8, 2012, "61" },
-        { "Lindahl2001a", "E. Lindahl and B. Hess and D. van der Spoel",
-          "GROMACS 3.0: A package for molecular simulation and trajectory analysis", "J. Mol. Mod.",
-          7, 2001, "306-317" },
-        { "Wang2001a", "J. Wang and W. Wang and S. Huo and M. Lee and P. A. Kollman",
-          "Solvation model based on weighted solvent accessible surface area", "J. Phys. Chem. B",
-          105, 2001, "5055-5067" },
-        { "Eisenberg86a", "D. Eisenberg and A. D. McLachlan",
-          "Solvation energy in protein folding and binding", "Nature", 319, 1986, "199-203" },
-        { "Bondi1964a", "A. Bondi", "van der Waals Volumes and Radii", "J. Phys. Chem.", 68, 1964,
+          "J. Chem. Theo. Comp.",
+          8,
+          2012,
+          "61" },
+        { "Lindahl2001a",
+          "E. Lindahl and B. Hess and D. van der Spoel",
+          "GROMACS 3.0: A package for molecular simulation and trajectory analysis",
+          "J. Mol. Mod.",
+          7,
+          2001,
+          "306-317" },
+        { "Wang2001a",
+          "J. Wang and W. Wang and S. Huo and M. Lee and P. A. Kollman",
+          "Solvation model based on weighted solvent accessible surface area",
+          "J. Phys. Chem. B",
+          105,
+          2001,
+          "5055-5067" },
+        { "Eisenberg86a",
+          "D. Eisenberg and A. D. McLachlan",
+          "Solvation energy in protein folding and binding",
+          "Nature",
+          319,
+          1986,
+          "199-203" },
+        { "Bondi1964a",
+          "A. Bondi",
+          "van der Waals Volumes and Radii",
+          "J. Phys. Chem.",
+          68,
+          1964,
           "441-451" },
         { "Eisenhaber95",
           "Frank Eisenhaber and Philip Lijnzaad and Patrick Argos and Chris Sander and Michael "
           "Scharf",
           "The Double Cube Lattice Method: Efficient Approaches to Numerical Integration of "
           "Surface Area and Volume and to Dot Surface Contouring of Molecular Assemblies",
-          "J. Comp. Chem.", 16, 1995, "273-284" },
-        { "Hess2002", "B. Hess, H. Saint-Martin and H.J.C. Berendsen",
+          "J. Comp. Chem.",
+          16,
+          1995,
+          "273-284" },
+        { "Hess2002",
+          "B. Hess, H. Saint-Martin and H.J.C. Berendsen",
           "Flexible constraints: an adiabatic treatment of quantum degrees of freedom, with "
           "application to the flexible and polarizable MCDHO model for water",
-          "J. Chem. Phys.", 116, 2002, "9602-9610" },
-        { "Hess2003", "B. Hess and R.M. Scheek",
+          "J. Chem. Phys.",
+          116,
+          2002,
+          "9602-9610" },
+        { "Hess2003",
+          "B. Hess and R.M. Scheek",
           "Orientation restraints in molecular dynamics simulations using time and ensemble "
           "averaging",
-          "J. Magn. Res.", 164, 2003, "19-27" },
-        { "Rappe1991a", "A. K. Rappe and W. A. Goddard III",
-          "Charge Equillibration for Molecular Dynamics Simulations", "J. Phys. Chem.", 95, 1991,
+          "J. Magn. Res.",
+          164,
+          2003,
+          "19-27" },
+        { "Rappe1991a",
+          "A. K. Rappe and W. A. Goddard III",
+          "Charge Equillibration for Molecular Dynamics Simulations",
+          "J. Phys. Chem.",
+          95,
+          1991,
           "3358-3363" },
-        { "Mu2005a", "Y. Mu, P. H. Nguyen and G. Stock",
+        { "Mu2005a",
+          "Y. Mu, P. H. Nguyen and G. Stock",
           "Energy landscape of a small peptide revelaed by dihedral angle principal component "
           "analysis",
-          "Prot. Struct. Funct. Bioinf.", 58, 2005, "45-52" },
-        { "Okabe2001a", "T. Okabe and M. Kawata and Y. Okamoto and M. Mikami",
+          "Prot. Struct. Funct. Bioinf.",
+          58,
+          2005,
+          "45-52" },
+        { "Okabe2001a",
+          "T. Okabe and M. Kawata and Y. Okamoto and M. Mikami",
           "Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble",
-          "Chem. Phys. Lett.", 335, 2001, "435-439" },
-        { "Hukushima96a", "K. Hukushima and K. Nemoto",
+          "Chem. Phys. Lett.",
+          335,
+          2001,
+          "435-439" },
+        { "Hukushima96a",
+          "K. Hukushima and K. Nemoto",
           "Exchange Monte Carlo Method and Application to Spin Glass Simulations",
-          "J. Phys. Soc. Jpn.", 65, 1996, "1604-1608" },
-        { "Tropp80a", "J. Tropp",
+          "J. Phys. Soc. Jpn.",
+          65,
+          1996,
+          "1604-1608" },
+        { "Tropp80a",
+          "J. Tropp",
           "Dipolar Relaxation and Nuclear Overhauser effects in nonrigid molecules: The effect of "
           "fluctuating internuclear distances",
-          "J. Chem. Phys.", 72, 1980, "6035-6043" },
+          "J. Chem. Phys.",
+          72,
+          1980,
+          "6035-6043" },
         { "Bultinck2002a",
           "P. Bultinck and W. Langenaeker and P. Lahorte and F. De Proft and P. Geerlings and M. "
           "Waroquier and J. P. Tollenaere",
           "The electronegativity equalization method I: Parametrization and validation for atomic "
           "charge calculations",
-          "J. Phys. Chem. A", 106, 2002, "7887-7894" },
-        { "Yang2006b", "Q. Y. Yang and K. A. Sharp",
+          "J. Phys. Chem. A",
+          106,
+          2002,
+          "7887-7894" },
+        { "Yang2006b",
+          "Q. Y. Yang and K. A. Sharp",
           "Atomic charge parameters for the finite difference Poisson-Boltzmann method using "
           "electronegativity neutralization",
-          "J. Chem. Theory Comput.", 2, 2006, "1152-1167" },
+          "J. Chem. Theory Comput.",
+          2,
+          2006,
+          "1152-1167" },
         { "Spoel2005a",
           "D. van der Spoel, E. Lindahl, B. Hess, G. Groenhof, A. E. Mark and H. J. C. Berendsen",
-          "GROMACS: Fast, Flexible and Free", "J. Comp. Chem.", 26, 2005, "1701-1719" },
-        { "Spoel2006b", "D. van der Spoel, P. J. van Maaren, P. Larsson and N. Timneanu",
+          "GROMACS: Fast, Flexible and Free",
+          "J. Comp. Chem.",
+          26,
+          2005,
+          "1701-1719" },
+        { "Spoel2006b",
+          "D. van der Spoel, P. J. van Maaren, P. Larsson and N. Timneanu",
           "Thermodynamics of hydrogen bonding in hydrophilic and hydrophobic media",
-          "J. Phys. Chem. B", 110, 2006, "4393-4398" },
-        { "Spoel2006d", "D. van der Spoel and M. M. Seibert",
+          "J. Phys. Chem. B",
+          110,
+          2006,
+          "4393-4398" },
+        { "Spoel2006d",
+          "D. van der Spoel and M. M. Seibert",
           "Protein folding kinetics and thermodynamics from atomistic simulations",
-          "Phys. Rev. Letters", 96, 2006, "238102" },
-        { "Palmer94a", "B. J. Palmer",
+          "Phys. Rev. Letters",
+          96,
+          2006,
+          "238102" },
+        { "Palmer94a",
+          "B. J. Palmer",
           "Transverse-current autocorrelation-function calculations of the shear viscosity for "
           "molecular liquids",
-          "Phys. Rev. E", 49, 1994, "359-366" },
-        { "Bussi2007a", "G. Bussi, D. Donadio and M. Parrinello",
-          "Canonical sampling through velocity rescaling", "J. Chem. Phys.", 126, 2007, "014101" },
-        { "Hub2006", "J. S. Hub and B. L. de Groot", "Does CO2 permeate through Aquaporin-1?",
-          "Biophys. J.", 91, 2006, "842-848" },
-        { "Hub2008", "J. S. Hub and B. L. de Groot",
-          "Mechanism of selectivity in aquaporins and aquaglyceroporins", "PNAS", 105, 2008,
+          "Phys. Rev. E",
+          49,
+          1994,
+          "359-366" },
+        { "Bussi2007a",
+          "G. Bussi, D. Donadio and M. Parrinello",
+          "Canonical sampling through velocity rescaling",
+          "J. Chem. Phys.",
+          126,
+          2007,
+          "014101" },
+        { "Hub2006",
+          "J. S. Hub and B. L. de Groot",
+          "Does CO2 permeate through Aquaporin-1?",
+          "Biophys. J.",
+          91,
+          2006,
+          "842-848" },
+        { "Hub2008",
+          "J. S. Hub and B. L. de Groot",
+          "Mechanism of selectivity in aquaporins and aquaglyceroporins",
+          "PNAS",
+          105,
+          2008,
           "1198-1203" },
         { "Friedrich2009",
           "M. S. Friedrichs, P. Eastman, V. Vaidyanathan, M. Houston, S. LeGrand, A. L. Beberg, D. "
           "L. Ensign, C. M. Bruns, and V. S. Pande",
           "Accelerating Molecular Dynamic Simulation on Graphics Processing Units",
-          "J. Comp. Chem.", 30, 2009, "864-872" },
-        { "Engin2010", "O. Engin, A. Villa, M. Sayar and B. Hess",
+          "J. Comp. Chem.",
+          30,
+          2009,
+          "864-872" },
+        { "Engin2010",
+          "O. Engin, A. Villa, M. Sayar and B. Hess",
           "Driving Forces for Adsorption of Amphiphilic Peptides to Air-Water Interface",
-          "J. Phys. Chem. B", 114, 2010, "11093" },
-        { "Wang2010", "H. Wang, F. Dommert, C.Holm",
+          "J. Phys. Chem. B",
+          114,
+          2010,
+          "11093" },
+        { "Wang2010",
+          "H. Wang, F. Dommert, C.Holm",
           "Optimizing working parameters of the smooth particle mesh Ewald algorithm in terms of "
           "accuracy and efficiency",
-          "J. Chem. Phys. B", 133, 2010, "034117" },
-        { "Sugita1999a", "Y. Sugita, Y. Okamoto",
-          "Replica-exchange molecular dynamics method for protein folding", "Chem. Phys. Lett.",
-          314, 1999, "141-151" },
-        { "Kutzner2011", "C. Kutzner and J. Czub and H. Grubmuller",
+          "J. Chem. Phys. B",
+          133,
+          2010,
+          "034117" },
+        { "Sugita1999a",
+          "Y. Sugita, Y. Okamoto",
+          "Replica-exchange molecular dynamics method for protein folding",
+          "Chem. Phys. Lett.",
+          314,
+          1999,
+          "141-151" },
+        { "Kutzner2011",
+          "C. Kutzner and J. Czub and H. Grubmuller",
           "Keep it Flexible: Driving Macromolecular Rotary Motions in Atomistic Simulations with "
           "GROMACS",
-          "J. Chem. Theory Comput.", 7, 2011, "1381-1393" },
+          "J. Chem. Theory Comput.",
+          7,
+          2011,
+          "1381-1393" },
         { "Hoefling2011",
           "M. Hoefling, N. Lima, D. Haenni, C.A.M. Seidel, B. Schuler, H. Grubmuller",
           "Structural Heterogeneity and Quantitative FRET Efficiency Distributions of Polyprolines "
           "through a Hybrid Atomistic Simulation and Monte Carlo Approach",
-          "PLoS ONE", 6, 2011, "e19791" },
-        { "Hockney1988", "R. W. Hockney and J. W. Eastwood", "Computer simulation using particles",
-          "IOP, Bristol", 1, 1988, "1" },
-        { "Ballenegger2012", "V. Ballenegger, J.J. Cerda, and C. Holm",
+          "PLoS ONE",
+          6,
+          2011,
+          "e19791" },
+        { "Hockney1988",
+          "R. W. Hockney and J. W. Eastwood",
+          "Computer simulation using particles",
+          "IOP, Bristol",
+          1,
+          1988,
+          "1" },
+        { "Ballenegger2012",
+          "V. Ballenegger, J.J. Cerda, and C. Holm",
           "How to Convert SPME to P3M: Influence Functions and Error Estimates",
-          "J. Chem. Theory Comput.", 8, 2012, "936-947" },
+          "J. Chem. Theory Comput.",
+          8,
+          2012,
+          "936-947" },
         { "Garmay2012",
           "Garmay Yu, Shvetsov A, Karelov D, Lebedev D, Radulescu A, Petukhov M, Isaev-Ivanov V",
           "Correlated motion of protein subdomains and large-scale conformational flexibility of "
           "RecA protein filament",
-          "Journal of Physics: Conference Series", 340, 2012, "012094" },
-        { "Kutzner2011b", "C. Kutzner, H. Grubmuller, B. L. de Groot, and U. Zachariae",
+          "Journal of Physics: Conference Series",
+          340,
+          2012,
+          "012094" },
+        { "Kutzner2011b",
+          "C. Kutzner, H. Grubmuller, B. L. de Groot, and U. Zachariae",
           "Computational Electrophysiology: The Molecular Dynamics of Ion Channel Permeation and "
           "Selectivity in Atomistic Detail",
-          "Biophys. J.", 101, 2011, "809-817" },
+          "Biophys. J.",
+          101,
+          2011,
+          "809-817" },
         { "Lundborg2014",
           "M. Lundborg, R. Apostolov, D. Spangberg, A. Gardenas, D. van der Spoel and E. Lindahl",
           "An efficient and extensible format, library, and API for binary trajectory data from "
           "molecular simulations",
-          "J. Comput. Chem.", 35, 2014, "260-269" },
+          "J. Comput. Chem.",
+          35,
+          2014,
+          "260-269" },
         { "Goga2012",
           "N. Goga and A. J. Rzepiela and A. H. de Vries and S. J. Marrink and H. J. C. Berendsen",
-          "Efficient Algorithms for Langevin and DPD Dynamics", "J. Chem. Theory Comput.", 8, 2012,
+          "Efficient Algorithms for Langevin and DPD Dynamics",
+          "J. Chem. Theory Comput.",
+          8,
+          2012,
           "3637--3649" },
         { "Pronk2013",
           "S. Pronk, S. Páll, R. Schulz, P. Larsson, P. Bjelkmar, R. Apostolov, M. R. Shirts, J. "
           "C. Smith, P. M. Kasson, D. van der Spoel, B. Hess, and E. Lindahl",
           "GROMACS 4.5: a high-throughput and highly parallel open source molecular simulation "
           "toolkit",
-          "Bioinformatics", 29, 2013, "845-54" },
-        { "Pall2015", "S. Páll, M. J. Abraham, C. Kutzner, B. Hess, E. Lindahl",
+          "Bioinformatics",
+          29,
+          2013,
+          "845-54" },
+        { "Pall2015",
+          "S. Páll, M. J. Abraham, C. Kutzner, B. Hess, E. Lindahl",
           "Tackling Exascale Software Challenges in Molecular Dynamics Simulations with GROMACS",
-          "In S. Markidis & E. Laure (Eds.), Solving Software Challenges for Exascale", 8759, 2015,
+          "In S. Markidis & E. Laure (Eds.), Solving Software Challenges for Exascale",
+          8759,
+          2015,
           "3-27" },
         { "Abraham2015",
           "M. J. Abraham, T. Murtola, R. Schulz, S. Páll, J. C. Smith, B. Hess, E. Lindahl",
           "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à",
+          "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",
+          "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" },
-        { "Spoel2018a", "D. van der Spoel, M. M. Ghahremanpour, J. Lemkul",
+          "J. Chem. Theory Comput.",
+          10,
+          2014,
+          "381-393" },
+        { "Spoel2018a",
+          "D. van der Spoel, M. M. Ghahremanpour, J. Lemkul",
           "Small Molecule Thermochemistry: A Tool For Empirical Force Field Development",
-          "J. Phys. Chem. A", 122, 2018, "8982-8988" },
-        { "Lindahl2014", "V. Lindahl, J. Lidmar, B. Hess",
+          "J. Phys. Chem. A",
+          122,
+          2018,
+          "8982-8988" },
+        { "Lindahl2014",
+          "V. Lindahl, J. Lidmar, B. Hess",
           "Accelerated weight histogram method for exploring free energy landscapes",
-          "J. Chem. Phys.", 141, 2014, "044110" },
-        { "Bernetti2020", "M. Bernetti, G. Bussi",
-          "Pressure control using stochastic cell rescaling", "J. Chem. Phys.", 153, 2020,
+          "J. Chem. Phys.",
+          141,
+          2014,
+          "044110" },
+        { "Bernetti2020",
+          "M. Bernetti, G. Bussi",
+          "Pressure control using stochastic cell rescaling",
+          "J. Chem. Phys.",
+          153,
+          2020,
           "114107" },
     };
 #define NSTR static_cast<int>(asize(citedb))
 
-    int   index;
-    char* author;
-    char* title;
-#define LINE_WIDTH 79
-
     if (fp == nullptr)
     {
         return;
     }
 
-    for (index = 0; index < NSTR && (strcmp(citedb[index].key, key) != 0); index++) {}
+    int index = 0;
+    for (; index < NSTR && (strcmp(citedb[index].key, key) != 0); index++) {}
 
     fprintf(fp, "\n++++ PLEASE READ AND CITE THE FOLLOWING REFERENCE ++++\n");
     if (index < NSTR)
     {
         /* Insert newlines */
-        author = wrap_lines(citedb[index].author, LINE_WIDTH, 0, FALSE);
-        title  = wrap_lines(citedb[index].title, LINE_WIDTH, 0, FALSE);
-        fprintf(fp, "%s\n%s\n%s %d (%d) pp. %s\n", author, title, citedb[index].journal,
-                citedb[index].volume, citedb[index].year, citedb[index].pages);
+        char* author = wrap_lines(citedb[index].author, sc_lineWidth, 0, FALSE);
+        char* title  = wrap_lines(citedb[index].title, sc_lineWidth, 0, FALSE);
+        fprintf(fp,
+                "%s\n%s\n%s %d (%d) pp. %s\n",
+                author,
+                title,
+                citedb[index].journal,
+                citedb[index].volume,
+                citedb[index].year,
+                citedb[index].pages);
         sfree(author);
         sfree(title);
     }
@@ -346,7 +609,7 @@ void writeSourceDoi(FILE* fp)
         return;
     }
     gmx::TextLineWrapper wrapper;
-    wrapper.settings().setLineLength(LINE_WIDTH);
+    wrapper.settings().setLineLength(sc_lineWidth);
     wrapper.settings().setFirstLineIndent(0);
     const std::string doiString = wrapper.wrapToString(gmxDOI());
 
index acc70d8d1586d1b0a37599de5e4a027c0668eea6..020c9c93358b4b113c81ecb12d56bf38275c8101 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -79,6 +79,7 @@ public:
 };
 
 //! Global program info; stores the object set with setProgramContext().
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 const IProgramContext* g_programContext;
 //! Default program context if nothing is set.
 const DefaultProgramContext g_defaultContext;
index 01d13705c41f11852b393244ce235eb0b116df73..d8f344a708a7ad3ac6df3dfe97092a6b8ba03ac6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <type_traits>
 
+#include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/gmxassert.h"
 
 namespace gmx
index 81895f9c3ed0eaea61bd8cfe262fb8f20afd7287..ff5128030663010cf50d9663585a2594593c0ed3 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #include <cstdio>
 #include <cstdlib>
 
-#ifdef WITH_DMALLOC
-#    include <dmalloc.h>
-#endif
+#include <mutex>
 
 #include <cstring>
 
-#include "thread_mpi/threads.h"
-
 #include "gromacs/utility/alignedallocator.h"
-#include "gromacs/utility/dir_separator.h"
 #include "gromacs/utility/fatalerror.h"
 #ifdef PRINT_ALLOC_KB
 #    include "gromacs/utility/basenetwork.h"
 #    include "gromacs/utility/gmxmpi.h"
 #endif
 
-static gmx_bool            g_bOverAllocDD     = FALSE;
-static tMPI_Thread_mutex_t g_over_alloc_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static bool g_bOverAllocDD = false;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static std::mutex g_overAllocMutex;
 
 void* save_malloc(const char* name, const char* file, int line, size_t size)
 {
-    void* p;
+    void* p = nullptr;
 
-    p = nullptr;
     if (size == 0)
     {
         p = nullptr;
@@ -77,11 +73,16 @@ void* save_malloc(const char* name, const char* file, int line, size_t size)
     {
         if ((p = malloc(size)) == nullptr)
         {
-            gmx_fatal(errno, __FILE__, __LINE__,
+            gmx_fatal(errno,
+                      __FILE__,
+                      __LINE__,
                       "Not enough memory. Failed to malloc %" PRId64
                       " bytes for %s\n"
                       "(called from file %s, line %d)",
-                      static_cast<int64_t>(size), name, file, line);
+                      static_cast<int64_t>(size),
+                      name,
+                      file,
+                      line);
         }
         (void)memset(p, 0, size);
     }
@@ -90,9 +91,8 @@ void* save_malloc(const char* name, const char* file, int line, size_t size)
 
 void* save_calloc(const char* name, const char* file, int line, size_t nelem, size_t elsize)
 {
-    void* p;
+    void* p = nullptr;
 
-    p = nullptr;
     if ((nelem == 0) || (elsize == 0))
     {
         p = nullptr;
@@ -104,7 +104,11 @@ void* save_calloc(const char* name, const char* file, int line, size_t nelem, si
         {
             int rank = gmx_node_rank();
             printf("Allocating %.1f MB for %s (called from file %s, line %d on %d)\n",
-                   nelem * elsize / 1048576.0, name, file, line, rank);
+                   nelem * elsize / 1048576.0,
+                   name,
+                   file,
+                   line,
+                   rank);
         }
 #endif
 #if GMX_BROKEN_CALLOC
@@ -112,19 +116,31 @@ void* save_calloc(const char* name, const char* file, int line, size_t nelem, si
            a broken calloc, e.g. in -lgmalloc on cray xt3. */
         if ((p = malloc((size_t)nelem * (size_t)elsize)) == NULL)
         {
-            gmx_fatal(errno, __FILE__, __LINE__,
+            gmx_fatal(errno,
+                      __FILE__,
+                      __LINE__,
                       "Not enough memory. Failed to calloc %" PRId64 " elements of size %" PRId64
                       " for %s\n(called from file %s, line %d)",
-                      (int64_t)nelem, (int64_t)elsize, name, file, line);
+                      (int64_t)nelem,
+                      (int64_t)elsize,
+                      name,
+                      file,
+                      line);
         }
         memset(p, 0, (size_t)(nelem * elsize));
 #else
         if ((p = calloc(nelem, elsize)) == nullptr)
         {
-            gmx_fatal(errno, __FILE__, __LINE__,
+            gmx_fatal(errno,
+                      __FILE__,
+                      __LINE__,
                       "Not enough memory. Failed to calloc %" PRId64 " elements of size %" PRId64
                       " for %s\n(called from file %s, line %d)",
-                      static_cast<int64_t>(nelem), static_cast<int64_t>(elsize), name, file, line);
+                      static_cast<int64_t>(nelem),
+                      static_cast<int64_t>(elsize),
+                      name,
+                      file,
+                      line);
         }
 #endif
     }
@@ -133,10 +149,9 @@ void* save_calloc(const char* name, const char* file, int line, size_t nelem, si
 
 void* save_realloc(const char* name, const char* file, int line, void* ptr, size_t nelem, size_t elsize)
 {
-    void*  p;
+    void*  p    = nullptr;
     size_t size = nelem * elsize;
 
-    p = nullptr;
     if (size == 0)
     {
         save_free(name, file, line, ptr);
@@ -148,7 +163,11 @@ void* save_realloc(const char* name, const char* file, int line, void* ptr, size
         {
             int rank = gmx_node_rank();
             printf("Reallocating %.1f MB for %s (called from file %s, line %d on %d)\n",
-                   size / 1048576.0, name, file, line, rank);
+                   size / 1048576.0,
+                   name,
+                   file,
+                   line,
+                   rank);
         }
 #endif
         if (ptr == nullptr)
@@ -161,10 +180,17 @@ void* save_realloc(const char* name, const char* file, int line, void* ptr, size
         }
         if (p == nullptr)
         {
-            gmx_fatal(errno, __FILE__, __LINE__,
+            gmx_fatal(errno,
+                      __FILE__,
+                      __LINE__,
                       "Not enough memory. Failed to realloc %zu bytes for %s, %s=%p\n"
                       "(called from file %s, line %d)",
-                      size, name, name, ptr, file, line);
+                      size,
+                      name,
+                      name,
+                      ptr,
+                      file,
+                      line);
         }
     }
     return p;
@@ -185,23 +211,30 @@ void save_free(const char gmx_unused* name, const char gmx_unused* file, int gmx
  * the necessary alignment. */
 void* save_malloc_aligned(const char* name, const char* file, int line, size_t nelem, size_t elsize, size_t alignment)
 {
-    void* p;
+    void* p = nullptr;
 
     if (alignment == 0)
     {
-        gmx_fatal(errno, __FILE__, __LINE__,
+        gmx_fatal(errno,
+                  __FILE__,
+                  __LINE__,
                   "Cannot allocate aligned memory with alignment of zero!\n(called from file %s, "
                   "line %d)",
-                  file, line);
+                  file,
+                  line);
     }
 
     size_t alignmentSize = gmx::AlignedAllocationPolicy::alignment();
     if (alignment > alignmentSize)
     {
-        gmx_fatal(errno, __FILE__, __LINE__,
+        gmx_fatal(errno,
+                  __FILE__,
+                  __LINE__,
                   "Cannot allocate aligned memory with alignment > %zu bytes\n(called from file "
                   "%s, line %d)",
-                  alignmentSize, file, line);
+                  alignmentSize,
+                  file,
+                  line);
     }
 
 
@@ -216,7 +249,11 @@ void* save_malloc_aligned(const char* name, const char* file, int line, size_t n
         {
             int rank = gmx_node_rank();
             printf("Allocating %.1f MB for %s (called from file %s, line %d on %d)\n",
-                   nelem * elsize / 1048576.0, name, file, line, rank);
+                   nelem * elsize / 1048576.0,
+                   name,
+                   file,
+                   line,
+                   rank);
         }
 #endif
 
@@ -224,10 +261,16 @@ void* save_malloc_aligned(const char* name, const char* file, int line, size_t n
 
         if (p == nullptr)
         {
-            gmx_fatal(errno, __FILE__, __LINE__,
+            gmx_fatal(errno,
+                      __FILE__,
+                      __LINE__,
                       "Not enough memory. Failed to allocate %zu aligned elements of size %zu for "
                       "%s\n(called from file %s, line %d)",
-                      nelem, elsize, name, file, line);
+                      nelem,
+                      elsize,
+                      name,
+                      file,
+                      line);
         }
     }
     return p;
@@ -249,13 +292,12 @@ void save_free_aligned(const char gmx_unused* name, const char gmx_unused* file,
     gmx::AlignedAllocationPolicy::free(ptr);
 }
 
-void set_over_alloc_dd(gmx_bool set)
+void set_over_alloc_dd(bool set)
 {
-    tMPI_Thread_mutex_lock(&g_over_alloc_mutex);
+    std::lock_guard<std::mutex> lock(g_overAllocMutex);
     /* we just make sure that we don't set this at the same time.
        We don't worry too much about reading this rarely-set variable */
     g_bOverAllocDD = set;
-    tMPI_Thread_mutex_unlock(&g_over_alloc_mutex);
 }
 
 int over_alloc_dd(int n)
index f68de025d347e350bb597075b73eb22b980dd644..2c0abc54a64939817b5432d900928b55b0a991fa 100644 (file)
@@ -3,7 +3,8 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2020, by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -65,8 +66,6 @@
 
 #include <stddef.h>
 
-#include "gromacs/utility/basedefinitions.h"
-
 /*! \brief
  * \Gromacs wrapper for malloc().
  *
@@ -357,7 +356,7 @@ constexpr float OVER_ALLOC_FAC = 1.19F;
  * This is mdrun-specific, so it might be better to put this and
  * over_alloc_dd() much higher up.
  */
-void set_over_alloc_dd(gmx_bool set);
+void set_over_alloc_dd(bool set);
 
 /*! \brief
  * Returns new allocation count for domain decomposition allocations.
index 44ee5e9f15095f20458eb667f87181f3d3cb998e..c2fe14b3df1a7fe2740b4fcbb6fce8087ebea953 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -75,9 +75,9 @@ bool boolFromString(const char* value)
 
 int intFromString(const char* str)
 {
-    errno = 0;
-    char*          endptr;
-    const long int value = std::strtol(str, &endptr, 10);
+    errno                 = 0;
+    char*          endptr = nullptr;
+    const long int value  = std::strtol(str, &endptr, 10);
     if (errno == ERANGE || value < std::numeric_limits<int>::min()
         || value > std::numeric_limits<int>::max())
     {
@@ -93,9 +93,9 @@ int intFromString(const char* str)
 
 int64_t int64FromString(const char* str)
 {
-    errno = 0;
-    char*         endptr;
-    const int64_t value = str_to_int64_t(str, &endptr);
+    errno                = 0;
+    char*         endptr = nullptr;
+    const int64_t value  = str_to_int64_t(str, &endptr);
     if (errno == ERANGE)
     {
         GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
@@ -110,9 +110,9 @@ int64_t int64FromString(const char* str)
 
 float floatFromString(const char* str)
 {
-    errno = 0;
-    char*        endptr;
-    const double value = std::strtod(str, &endptr);
+    errno               = 0;
+    char*        endptr = nullptr;
+    const double value  = std::strtod(str, &endptr);
     if (errno == ERANGE || value < -std::numeric_limits<float>::max()
         || value > std::numeric_limits<float>::max())
     {
@@ -128,9 +128,9 @@ float floatFromString(const char* str)
 
 double doubleFromString(const char* str)
 {
-    errno = 0;
-    char*        endptr;
-    const double value = std::strtod(str, &endptr);
+    errno               = 0;
+    char*        endptr = nullptr;
+    const double value  = std::strtod(str, &endptr);
     if (errno == ERANGE)
     {
         GMX_THROW(InvalidInputError("Invalid value: '" + std::string(str)
index 805717fb7e5ec7678da375d515d3306a0def8bc2..2af389fcdd56a387a111eef6be03746577c7e2b9 100644 (file)
@@ -268,7 +268,9 @@ parsedArrayFromInputString(const std::string& str)
 
     // will throw if any conversion from string to value fails
     std::array<ValueType, NumExpectedValues> valuesAsArray;
-    std::transform(std::begin(valuesAsStrings), std::end(valuesAsStrings), std::begin(valuesAsArray),
+    std::transform(std::begin(valuesAsStrings),
+                   std::end(valuesAsStrings),
+                   std::begin(valuesAsArray),
                    [](const std::string& split) { return fromString<ValueType>(split); });
 
     return { valuesAsArray };
index 4b3642d25778e4c88d9eaf88f4064615f66490a8..b4a2fd9727a5480b5cabd5089e70a442a455d28a 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +50,8 @@
 
 gmx_bool get_a_line(FILE* fp, char line[], int n)
 {
-    char* line0;
-    char* dum;
+    char* line0 = nullptr;
+    char* dum   = nullptr;
 
     snew(line0, n + 1);
 
@@ -70,7 +70,8 @@ gmx_bool get_a_line(FILE* fp, char line[], int n)
         else if (static_cast<int>(std::strlen(line0)) == n)
         {
             fprintf(stderr,
-                    "Warning: line length exceeds buffer length (%d), data might be corrupted\n", n);
+                    "Warning: line length exceeds buffer length (%d), data might be corrupted\n",
+                    n);
             line0[n - 1] = '\0';
         }
         else
@@ -112,10 +113,8 @@ gmx_bool get_header(char line[], char* header)
 
 int search_str(int nstr, char** str, char* key)
 {
-    int i;
-
     /* Linear search */
-    for (i = 0; (i < nstr); i++)
+    for (int i = 0; (i < nstr); i++)
     {
         if (gmx_strcasecmp(str[i], key) == 0)
         {
@@ -128,12 +127,11 @@ int search_str(int nstr, char** str, char* key)
 
 static int fget_lines(FILE* in, const char* db, char*** strings)
 {
-    char** ptr;
+    char** ptr = nullptr;
     char   buf[STRLEN];
-    int    i, nstr;
-    char*  pret;
+    int    nstr = 0;
 
-    pret = fgets(buf, STRLEN, in);
+    char* pret = fgets(buf, STRLEN, in);
     if (pret == nullptr || sscanf(buf, "%d", &nstr) != 1)
     {
         gmx_warning("File is empty");
@@ -142,7 +140,7 @@ static int fget_lines(FILE* in, const char* db, char*** strings)
         return 0;
     }
     snew(ptr, nstr);
-    for (i = 0; (i < nstr); i++)
+    for (int i = 0; (i < nstr); i++)
     {
         if (fgets2(buf, STRLEN, in) == nullptr)
         {
diff --git a/src/gromacs/utility/stringtoenumvalueconverter.h b/src/gromacs/utility/stringtoenumvalueconverter.h
new file mode 100644 (file)
index 0000000..bc45039
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 Defines helper function object for class enumerations
+ *
+ * This helper type facilitates efficient lookup of values from
+ * an enumeration identified by a string, given a pre-declared mapping of
+ * values to such strings.
+ *
+ * It is separated from enumerationhelpers.h because it is not as
+ * widely used and brings in several extra dependencies not needed by
+ * that header.
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_STRINGTOENUMVALUECONVERTER_H
+#define GMX_UTILITY_STRINGTOENUMVALUECONVERTER_H
+
+#include <map>
+#include <optional>
+#include <string>
+
+#include "enumerationhelpers.h"
+#include "stringcompare.h"
+#include "stringutil.h"
+
+namespace gmx
+{
+
+/*! \brief Enum class for whether StringToEnumValueConverter will strip strings
+ * of leading and trailing whitespace before comparison. */
+enum class StripStrings : int
+{
+    //! Do not strip strings
+    No,
+    //! Strip strings
+    Yes
+};
+
+/*! \brief A class to convert a string to an enum value of type \c EnumType.
+ *
+ * It can be configured:
+ *  - to match different enumerations,
+ *  - to convert enumerations to strings in a custom way,
+ *  - either strip strings of leading and trailing whitespace before
+ *    comparison or not,
+ *  - with different handling of how the string characters are compared.
+ *
+ * Usage example:
+ *
+ *    enum class Foo : int {
+ *       Fizz, Buzz, Count, Default = Fizz
+ *    };
+ *    StringToEnumValueConverter<Foo, enumValueToString> converter;
+ *    Foo type = converter.valueFrom(theString);
+ *
+ * \tparam EnumType                    A class enum for which enumValueToString
+ *                                     is defined and maps all values
+ *                                     (except EnumType::Count) to a string.
+ * \tparam enumValueToStringFunction   Function to convert EnumValue to string, which
+ *                                     is typically enumValueToString, per convention
+ * \tparam stringCompareType           Indicates how the string should be compared
+ *                                     with respect to case, hyphens, underscores, etc.
+ * \tparam stripStrings                Indicates whether strings should have leading
+ *                                     and trailing whitespace removed before comparison
+ */
+template<typename EnumType,
+         const char*(enumValueToStringFunction)(EnumType),
+         StringCompareType stringCompareType = StringCompareType::Exact,
+         StripStrings      stripStrings      = StripStrings::No>
+class StringToEnumValueConverter
+{
+public:
+    StringToEnumValueConverter() : stringToEnumValue_(stringCompareType)
+    {
+        for (const auto type : EnumerationWrapper<EnumType>{})
+        {
+            GMX_RELEASE_ASSERT(type != EnumType::Count,
+                               "EnumerationWrapper<EnumType> should never return EnumType::Count");
+            std::string stringFromType = enumValueToStringFunction(type);
+            if (stripStrings == StripStrings::Yes)
+            {
+                // Ensure leading and trailing spaces are removed
+                stringFromType = stripString(stringFromType);
+            }
+            stringToEnumValue_[stringFromType] = type;
+        }
+    }
+
+    //! Return an optional enum value identified from the \c s (which is never EnumType::Count)
+    std::optional<EnumType> valueFrom(const std::string& s) const
+    {
+        typename decltype(stringToEnumValue_)::const_iterator typeIt;
+        if (stripStrings == StripStrings::Yes)
+        {
+            // Ensure leading and trailing spaces are removed
+            typeIt = stringToEnumValue_.find(stripString(s));
+        }
+        else
+        {
+            typeIt = stringToEnumValue_.find(s);
+        }
+        return (typeIt != stringToEnumValue_.end()) ? std::make_optional(typeIt->second) : std::nullopt;
+    }
+
+private:
+    /*! \brief Map of strings to enumeration values.
+     *
+     * By construction, those values never include
+     * EnumType::Count. */
+    std::map<std::string, EnumType, StringCompare> stringToEnumValue_;
+};
+
+} // namespace gmx
+
+#endif
index a487ae0b695b8a527b33243b273789a41c2e9c61..c818320e2ec82ccd32352676a10b01a4dd34bd62 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2011-2018, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -200,11 +200,11 @@ std::vector<std::string> splitString(const std::string& str)
 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();
+    const size_t             len = str.length();
     if (len > 0)
     {
-        size_t nextDelim;
+        size_t nextDelim = 0;
+        size_t currPos   = 0;
         do
         {
             nextDelim = str.find(delim, currPos);
@@ -328,8 +328,9 @@ bool equalCaseInsensitive(const std::string& source, const std::string& target,
         }
         comparisonEnd = source.begin() + maxLengthOfComparison;
     }
-    return std::equal(source.begin(), comparisonEnd, target.begin(),
-                      [](const char& s, const char& t) { return std::tolower(s) == std::tolower(t); });
+    return std::equal(source.begin(), comparisonEnd, target.begin(), [](const char& s, const char& t) {
+        return std::tolower(s) == std::tolower(t);
+    });
 }
 
 /********************************************************************
index 14b4f5371d4896ae07259029523cf672a203f016..8eda416476c0036c64ef82424dae389045591600 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -62,7 +62,7 @@ auto dispatchTemplatedFunction(Function&& f)
 
 /** \internal \brief Helper function to select appropriate template based on runtime values.
  *
- * Can only use enums for template parameters.
+ * Can use enums or booleans for template parameters.
  * These enums must have a member \c Count indicating the total number of valid values.
  *
  * Example usage:
@@ -73,15 +73,15 @@ auto dispatchTemplatedFunction(Function&& f)
         Count = 2
     };
 
-    template<Options p1, Options p2>
+    template<bool p0, Options p1, Options p2>
     bool foo(int i);
 
-    bool bar(Options p1, Options p2, int i) {
+    bool bar(bool p0, Options p1, Options p2, int i) {
         return dispatchTemplatedFunction(
-            [=](auto p1, auto p2) {
-                return foo<p1, p2>(i);
+            [=](auto p0, auto p1, auto p2) {
+                return foo<p0, p1, p2>(i);
             },
-            p1, p2);
+            p0, p1, p2);
     }
  * \endcode
  */
@@ -98,6 +98,18 @@ auto dispatchTemplatedFunction(Function&& f, Enum e, Enums... es)
             es...);
 }
 
+template<class Function, class... Enums>
+auto dispatchTemplatedFunction(Function&& f, bool e, Enums... es)
+{
+    return dispatchTemplatedFunction(
+            [&](auto... es_) {
+                return compat::mp_with_index<2>(size_t(e), [&](auto e_) {
+                    return std::forward<Function>(f)(std::bool_constant<static_cast<bool>(e_)>(), es_...);
+                });
+            },
+            es...);
+}
+
 } // namespace gmx
 
 #endif // GMX_UTILITY_TEMPLATE_MP_H
diff --git a/src/gromacs/utility/tests/.clang-tidy b/src/gromacs/utility/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index 8bbbc308f2b4e8959d50dffc9d3335befc1274d1..7532e3c008214976783aaf3fef819efb2da2f415 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
-# Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,18 +47,20 @@ gmx_add_unit_test(UtilityUnitTests utility-test
         keyvaluetreetransform.cpp
         listoflists.cpp
         logger.cpp
-        mdmodulenotification-impl.cpp
-        mutex.cpp
+        mdmodulesnotifier.cpp
         path.cpp
         physicalnodecommunicator.cpp
         range.cpp
         strconvert.cpp
+        stringtoenumvalueconverter.cpp
         stringutil.cpp
         template_mp.cpp
         textreader.cpp
         textwriter.cpp
         typetraits.cpp
         )
+# TODO: Explicitly link specific modules.
+target_link_libraries(utility-test PRIVATE legacy_modules)
 
 gmx_add_mpi_unit_test(UtilityMpiUnitTests utility-mpi-test 4
     CPP_SOURCE_FILES
index 2cba18b9c946b9dc856b77a929bec92d465695ad..19cd95b33cc155a71a2bd8f11023675f2c1ac7c8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ class BITMASK_CLASSNAME(BITMASK_SIZE) : public ::testing::TestWithParam<int>
 
 BITMASK_TEST_P(SetAndClear) //NOLINT(misc-definitions-in-headers)
 {
-    gmx_bitmask_t m;
+    gmx_bitmask_t m; //NOLINT(cppcoreguidelines-init-variables)
     int           i = GetParam();
     bitmask_clear(&m);
     EXPECT_TRUE(bitmask_is_zero(m));
@@ -76,7 +76,7 @@ BITMASK_TEST_P(SetAndClear) //NOLINT(misc-definitions-in-headers)
 
 BITMASK_TEST_P(InitBit) //NOLINT(misc-definitions-in-headers)
 {
-    gmx_bitmask_t m1, m2;
+    gmx_bitmask_t m1, m2; //NOLINT(cppcoreguidelines-init-variables)
     int           i = GetParam();
     bitmask_init_bit(&m1, i);
     bitmask_clear(&m2);
@@ -87,7 +87,7 @@ BITMASK_TEST_P(InitBit) //NOLINT(misc-definitions-in-headers)
 
 BITMASK_TEST_P(InitLowBits) //NOLINT(misc-definitions-in-headers)
 {
-    gmx_bitmask_t m;
+    gmx_bitmask_t m; //NOLINT(cppcoreguidelines-init-variables)
     int           i = GetParam();
     bitmask_init_low_bits(&m, i);
     for (int j = 0; j < BITMASK_SIZE; j++)
@@ -98,7 +98,7 @@ BITMASK_TEST_P(InitLowBits) //NOLINT(misc-definitions-in-headers)
 
 BITMASK_TEST_P(Disjoint) //NOLINT(misc-definitions-in-headers)
 {
-    gmx_bitmask_t m1, m2;
+    gmx_bitmask_t m1, m2; //NOLINT(cppcoreguidelines-init-variables)
     int           i = GetParam();
     bitmask_init_bit(&m1, i);
     bitmask_init_bit(&m2, i);
@@ -109,7 +109,7 @@ BITMASK_TEST_P(Disjoint) //NOLINT(misc-definitions-in-headers)
 
 BITMASK_TEST_P(Union) //NOLINT(misc-definitions-in-headers)
 {
-    gmx_bitmask_t m1, m2;
+    gmx_bitmask_t m1, m2; //NOLINT(cppcoreguidelines-init-variables)
     int           i = GetParam();
     int           j = (i + BITMASK_SIZE / 2) % BITMASK_SIZE;
     bitmask_init_bit(&m1, i);
@@ -133,7 +133,7 @@ BITMASK_TEST_P(Union) //NOLINT(misc-definitions-in-headers)
 }
 BITMASK_TEST_P(ToHex) //NOLINT(misc-definitions-in-headers)
 {
-    gmx_bitmask_t m;
+    gmx_bitmask_t m; //NOLINT(cppcoreguidelines-init-variables)
     bitmask_clear(&m);
     bitmask_set_bit(&m, BITMASK_SIZE - 1);
     EXPECT_EQ(to_hex_string(m), "8" + std::string(BITMASK_SIZE / 4 - 1, '0'));
index 9f7da6257d29fe71765529e54c46c3c15522a247..cd54329df1052934a8436c8afdcf9c1774ddad9e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +124,7 @@ TEST(EnumerationHelpersTest, EnumerationArrayWorks)
     }
 
     // Incrementing iterators works
-    auto x = std::begin(fooStrings);
+    const auto* x = std::begin(fooStrings);
     EXPECT_EQ(*x, "Bar");
     ++x;
     EXPECT_EQ(*x, "Baz");
index 2db9b643f50a4923553354736f6478f1cb22c29f..ed502096d3165267865a82929efd145dbbb65262 100644 (file)
@@ -204,8 +204,8 @@ TEST_F(InMemorySerializerTest, RoundtripWithEndianessSwap)
 
     auto buffer = serializerWithSwap.finishAndGetBuffer();
 
-    InMemoryDeserializer deserializerWithSwap(buffer, std::is_same_v<real, double>,
-                                              EndianSwapBehavior::Swap);
+    InMemoryDeserializer deserializerWithSwap(
+            buffer, std::is_same_v<real, double>, EndianSwapBehavior::Swap);
 
     SerializerValues deserialisedValues = deserialize(&deserializerWithSwap);
 
@@ -234,8 +234,8 @@ TEST_F(InMemorySerializerTest, DeserializerExplicitEndianessSwap)
 
     auto buffer = serializer.finishAndGetBuffer();
 
-    InMemoryDeserializer deserializerWithSwap(buffer, std::is_same_v<real, double>,
-                                              EndianSwapBehavior::Swap);
+    InMemoryDeserializer deserializerWithSwap(
+            buffer, std::is_same_v<real, double>, EndianSwapBehavior::Swap);
 
     SerializerValues deserialisedValues = deserialize(&deserializerWithSwap);
     checkSerializerValuesforEquality(endianessSwappedValues_, deserialisedValues);
index 1d119bae6182d63f687746d4f70199077d4e7795..7c6a549ea8835c85ff8d8c8d5014b115602ca3c5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +66,8 @@ public:
         gmx::test::TestReferenceChecker checker(data.rootChecker());
         checker.checkKeyValueTreeObject(input, "Input");
         auto mappedPaths = transform.mappedPaths();
-        checker.checkSequence(mappedPaths.begin(), mappedPaths.end(), "MappedPaths",
-                              &TreeValueTransformTest::checkMappedPath);
+        checker.checkSequence(
+                mappedPaths.begin(), mappedPaths.end(), "MappedPaths", &TreeValueTransformTest::checkMappedPath);
         checker.checkKeyValueTreeObject(object, "Tree");
         checkBackMapping(&checker, object, result.backMapping());
     }
similarity index 64%
rename from src/gromacs/utility/tests/mdmodulenotification-impl.cpp
rename to src/gromacs/utility/tests/mdmodulesnotifier.cpp
index 5107ed92a9e95f71ac59e27666d1d0ff45e70dd2..1fc550b59ec7200d11c34aeb566e699882263f8a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
  */
 /*! \internal \file
  * \brief
- * Tests MdModuleNotification
+ * Tests MDModulesNotifier
  *
  * \author Christian Blau <blau@kth.se>
  * \ingroup module_utility
  */
 #include "gmxpre.h"
 
-#include "gromacs/utility/mdmodulenotification-impl.h"
+#include "gromacs/utility/mdmodulesnotifier.h"
 
 #include <gmock/gmock.h>
 
@@ -63,7 +63,7 @@ class EventACallee final
 public:
     void callback(EventA /*a*/) { notifiedEventA_ = true; }
 
-    bool notifiedEventA() { return notifiedEventA_; }
+    bool notifiedEventA() const { return notifiedEventA_; }
 
 private:
     bool notifiedEventA_ = false;
@@ -74,7 +74,7 @@ class EventBCallee final
 public:
     void callback(EventB* /* bPointer */) { notifiedEventB_ = true; }
 
-    bool notifiedEventB() { return notifiedEventB_; }
+    bool notifiedEventB() const { return notifiedEventB_; }
 
 private:
     bool notifiedEventB_ = false;
@@ -87,68 +87,68 @@ public:
 
     void callback(EventA /* a */) { notifiedEventA_ = true; }
 
-    bool notifiedEventB() { return notifiedEventB_; }
-    bool notifiedEventA() { return notifiedEventA_; }
+    bool notifiedEventB() const { return notifiedEventB_; }
+    bool notifiedEventA() const { return notifiedEventA_; }
 
 private:
     bool notifiedEventB_ = false;
     bool notifiedEventA_ = false;
 };
 
-TEST(MDModuleNotificationTest, addConsumer)
+TEST(MDModulesNotifierTest, AddConsumer)
 {
-    registerMdModuleNotification<EventA>::type notifications;
-    EventACallee                               eventACallee;
+    BuildMDModulesNotifier<EventA>::type notifier;
+    EventACallee                         eventACallee;
 
     EXPECT_FALSE(eventACallee.notifiedEventA());
 
-    notifications.subscribe([&eventACallee](EventA eventA) { eventACallee.callback(eventA); });
-    notifications.notify(EventA{});
+    notifier.subscribe([&eventACallee](EventA eventA) { eventACallee.callback(eventA); });
+    notifier.notify(EventA{});
 
     EXPECT_TRUE(eventACallee.notifiedEventA());
 }
 
-TEST(MDModuleNotificationTest, addConsumerWithPointerParameter)
+TEST(MDModulesNotifierTest, AddConsumerWithPointerParameter)
 {
-    registerMdModuleNotification<EventB*>::type notifications;
-    EventBCallee                                eventBCallee;
+    BuildMDModulesNotifier<EventB*>::type notifier;
+    EventBCallee                          eventBCallee;
 
     EXPECT_FALSE(eventBCallee.notifiedEventB());
 
-    notifications.subscribe([&eventBCallee](EventB* eventB) { eventBCallee.callback(eventB); });
+    notifier.subscribe([&eventBCallee](EventB* eventB) { eventBCallee.callback(eventB); });
     EventB* eventBPointer = nullptr;
-    notifications.notify(eventBPointer);
+    notifier.notify(eventBPointer);
 
     EXPECT_TRUE(eventBCallee.notifiedEventB());
 }
 
-TEST(MDModuleNotificationTest, addTwoDifferentConsumers)
+TEST(MDModulesNotifierTest, AddTwoDifferentConsumers)
 {
-    registerMdModuleNotification<EventA, EventB*>::type notifications;
-    EventBCallee                                        eventBCallee;
-    EventACallee                                        eventACallee;
+    BuildMDModulesNotifier<EventA, EventB*>::type notifier;
+    EventBCallee                                  eventBCallee;
+    EventACallee                                  eventACallee;
 
     EXPECT_FALSE(eventACallee.notifiedEventA());
     EXPECT_FALSE(eventBCallee.notifiedEventB());
 
-    notifications.subscribe([&eventBCallee](EventB* eventB) { eventBCallee.callback(eventB); });
-    notifications.subscribe([&eventACallee](EventA eventA) { eventACallee.callback(eventA); });
+    notifier.subscribe([&eventBCallee](EventB* eventB) { eventBCallee.callback(eventB); });
+    notifier.subscribe([&eventACallee](EventA eventA) { eventACallee.callback(eventA); });
 
     EventB* eventBPointer = nullptr;
-    notifications.notify(eventBPointer);
+    notifier.notify(eventBPointer);
 
     EXPECT_FALSE(eventACallee.notifiedEventA());
     EXPECT_TRUE(eventBCallee.notifiedEventB());
 
-    notifications.notify(EventA{});
+    notifier.notify(EventA{});
 
     EXPECT_TRUE(eventACallee.notifiedEventA());
     EXPECT_TRUE(eventBCallee.notifiedEventB());
 }
 
-TEST(MDModuleNotificationTest, consumerOfTwoResources)
+TEST(MDModulesNotifierTest, AddConsumerOfTwoResources)
 {
-    registerMdModuleNotification<EventA, EventB*>::type notifications;
+    BuildMDModulesNotifier<EventA, EventB*>::type notifier;
 
     EventAandBCallee callee;
 
@@ -156,17 +156,17 @@ TEST(MDModuleNotificationTest, consumerOfTwoResources)
     EXPECT_FALSE(callee.notifiedEventA());
 
     // requires a template parameter here, because call is ambiguous otherwise
-    notifications.subscribe([&callee](EventA msg) { callee.callback(msg); });
-    notifications.subscribe([&callee](EventB* msg) { callee.notify(msg); });
+    notifier.subscribe([&callee](EventA msg) { callee.callback(msg); });
+    notifier.subscribe([&callee](EventB* msg) { callee.notify(msg); });
 
     EventB* eventBp = nullptr;
 
-    notifications.notify(eventBp);
+    notifier.notify(eventBp);
 
     EXPECT_FALSE(callee.notifiedEventA());
     EXPECT_TRUE(callee.notifiedEventB());
 
-    notifications.notify(EventA{});
+    notifier.notify(EventA{});
 
     EXPECT_TRUE(callee.notifiedEventA());
     EXPECT_TRUE(callee.notifiedEventB());
diff --git a/src/gromacs/utility/tests/mutex.cpp b/src/gromacs/utility/tests/mutex.cpp
deleted file mode 100644 (file)
index dba7019..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * This file is part of the GROMACS molecular simulation package.
- *
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
- * Mark Abraham, David van der Spoel, Berk Hess, and 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 gmx::Mutex
- *
- * These tests ensure that basic mutual-exclusion properties hold.
- * Note that no testing can prove there isn't a bug, but if one
- * exists, then these tests might expose one.
- *
- * In particular, try_lock can be implemented differently on different
- * platforms, or with different default mutex types, so we should
- * check that the behaviour continues to conform with the thread-MPI
- * documentation.
- *
- * \author Mark Abraham <mark.j.abraham@gmail.com>
- * \ingroup module_utility
- */
-
-#include "gmxpre.h"
-
-#include "gromacs/utility/mutex.h"
-
-#include "config.h"
-
-#include <future>
-
-#include <gtest/gtest.h>
-
-
-namespace gmx
-{
-namespace test
-{
-namespace
-{
-
-//! Convenience definition.
-using Lock = gmx::lock_guard<Mutex>;
-
-TEST(MutexBasicTest, CanBeMade)
-{
-    Mutex m;
-}
-
-TEST(MutexBasicTest, CanBeLocked)
-{
-    Mutex m;
-    ASSERT_NO_THROW(m.lock());
-    m.unlock();
-}
-
-TEST(MutexBasicTest, CanBeTryLocked)
-{
-    Mutex m;
-    ASSERT_TRUE(m.try_lock());
-    m.unlock();
-}
-
-TEST(MutexBasicTest, CanBeUsedInLockGuard)
-{
-    Mutex m;
-    Lock  g(m);
-}
-
-//! A shared value for a mutex to protect
-int g_sharedValue;
-//! A mutex to protect a shared value
-Mutex g_sharedValueMutex;
-
-//! Function type for asynchronous tasks.
-using TaskType = std::function<int(void)>;
-
-//! A task that just does work.
-int updateSharedValue()
-{
-    return ++g_sharedValue;
-}
-
-//! A task that does work after it gets the mutex.
-int updateSharedValueWithLock()
-{
-    Lock guard(g_sharedValueMutex);
-    return updateSharedValue();
-}
-
-//! A task that does work only if it can get the mutex immediately.
-int updateSharedValueWithTryLock()
-{
-    // Special return value to signal when work was not done because
-    // the lock was not acquired.
-    int result = -1;
-    if (g_sharedValueMutex.try_lock())
-    {
-        result = updateSharedValue();
-        g_sharedValueMutex.unlock();
-    }
-    return result;
-}
-
-/*! \brief Parameterized test fixture.
- *
- * Checks that different launch policies work. In further tests of
- * mutual exclusion, we need to specify std::thread::async, to require
- * that a thread actually launched. The default policy permits the
- * std:: implementation to avoid launching a thread, and at least the
- * behaviour of thread-MPI try_lock also varies with the threading
- * implementation underlying it. */
-class DifferentTasksTest : public ::testing::TestWithParam<TaskType>
-{
-public:
-    DifferentTasksTest() { g_sharedValue = 0; }
-    //! Check the results
-    void checkResults()
-    {
-        int result = 0;
-        EXPECT_NO_THROW(result = futureResult_.get()) << "Future should not contain an exception";
-        EXPECT_EQ(1, result) << "Task should have run";
-        EXPECT_EQ(1, g_sharedValue) << "Shared value should be updated";
-    }
-    //! Contains the result the task returns.
-    std::future<int> futureResult_;
-};
-
-TEST_P(DifferentTasksTest, StdAsyncWorksWithDefaultPolicy)
-{
-    auto task = GetParam();
-    EXPECT_NO_THROW(futureResult_ = std::async(task)) << "Async should succeed";
-    checkResults();
-}
-
-TEST_P(DifferentTasksTest, StdAsyncWorksWithAsyncLaunchPolicy)
-{
-    auto task = GetParam();
-    EXPECT_NO_THROW(futureResult_ = std::async(std::launch::async, task)) << "Async should succeed";
-    checkResults();
-}
-
-TEST_P(DifferentTasksTest, StdAsyncWorksWithDeferredLaunchPolicy)
-{
-    auto task = GetParam();
-    EXPECT_NO_THROW(futureResult_ = std::async(std::launch::deferred, task))
-            << "Async should succeed";
-    checkResults();
-}
-
-// Test that the different launch policies work with the different tasks
-INSTANTIATE_TEST_CASE_P(WithAndWithoutMutex,
-                        DifferentTasksTest,
-                        ::testing::Values(updateSharedValue,
-                                          updateSharedValueWithLock,
-                                          updateSharedValueWithTryLock));
-
-TEST(MutexTaskTest, MutualExclusionWorksWithLock)
-{
-    g_sharedValue = 0;
-    std::future<int> result;
-    {
-        // Hold the mutex, launch a lock attempt on another
-        // thread, check that the shared value isn't changed, then
-        // release the mutex by leaving the scope, after which the
-        // other thread's lock can get the mutex.
-        Lock guard(g_sharedValueMutex);
-        result = std::async(std::launch::async, updateSharedValueWithLock);
-        EXPECT_EQ(0, g_sharedValue) << "Task should not have run yet";
-    }
-    EXPECT_EQ(1, result.get()) << "Task should have run";
-    EXPECT_EQ(1, g_sharedValue) << "Shared value should be updated";
-}
-
-TEST(MutexTaskTest, MutualExclusionWorksWithTryLockOnOtherThread)
-{
-    g_sharedValue = 0;
-    {
-        // Hold the mutex, launch a try_lock attempt on another
-        // thread, check that the shared value isn't changed, then
-        // make sure the try_lock attempt has returned, double check
-        // that the shared value isn't changed, and release the mutex
-        // by leaving the scope.
-        Lock guard(g_sharedValueMutex);
-        auto result = std::async(std::launch::async, updateSharedValueWithTryLock);
-        EXPECT_EQ(0, g_sharedValue) << "Data race detected";
-        EXPECT_EQ(-1, result.get()) << "The try_lock should fail";
-        EXPECT_EQ(0, g_sharedValue) << "Task should not have run";
-    }
-    EXPECT_EQ(0, g_sharedValue) << "Mutex release can't affect the protected value";
-}
-
-TEST(MutexTaskTest, MutualExclusionWorksWithTryLockOnSameThread)
-{
-    g_sharedValue        = 0;
-    int finalSharedValue = GMX_NATIVE_WINDOWS ? 1 : 0;
-    {
-        // Hold the mutex and launch a try_lock attempt on this
-        // thread. Behaviour then varies with the implementation
-        // underlying thread-MPI.
-        Lock guard(g_sharedValueMutex);
-        int  result = updateSharedValueWithTryLock();
-        if (GMX_NATIVE_WINDOWS)
-        {
-            EXPECT_EQ(1, result) << "The try_lock should succeed";
-            EXPECT_EQ(finalSharedValue, g_sharedValue) << "Task should have run";
-        }
-        else
-        {
-            EXPECT_EQ(-1, result) << "The try_lock should fail";
-            EXPECT_EQ(finalSharedValue, g_sharedValue) << "Task should not have run";
-        }
-    }
-    EXPECT_EQ(finalSharedValue, g_sharedValue) << "Mutex release can't affect the protected value";
-}
-
-} // namespace
-} // namespace test
-} // namespace gmx
index 89d43b0ed4c75ef0b3ad7dc49a2cb443c49e53ef..38638befd5dd6923e6c8013a9cbacf1d480cdeba 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,10 +76,17 @@ TEST(PathTest, SearchOperationsWork)
 {
     gmx::test::TestReferenceData    data;
     gmx::test::TestReferenceChecker rootChecker(data.rootChecker());
-    for (const std::string& input :
-         { "", "md.log", "md", "/tmp/absolute.txt", "simpledir/traj.tng", "simpledir/traj",
-           "windowsdir\\traj.tng", "complex.dir/traj.tng", "complex.dir/traj",
-           "nested/dir/conf.pdb", "/tmp/absolutedir/conf.pdb" })
+    for (const std::string& input : { "",
+                                      "md.log",
+                                      "md",
+                                      "/tmp/absolute.txt",
+                                      "simpledir/traj.tng",
+                                      "simpledir/traj",
+                                      "windowsdir\\traj.tng",
+                                      "complex.dir/traj.tng",
+                                      "complex.dir/traj",
+                                      "nested/dir/conf.pdb",
+                                      "/tmp/absolutedir/conf.pdb" })
     {
         SCOPED_TRACE(std::string("for input '") + input + "'");
         auto checker = rootChecker.checkCompound("PathToTest", input);
diff --git a/src/gromacs/utility/tests/stringtoenumvalueconverter.cpp b/src/gromacs/utility/tests/stringtoenumvalueconverter.cpp
new file mode 100644 (file)
index 0000000..7a984d9
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 string-to-enum-value helper functor
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \ingroup module_utility
+ */
+#include "gmxpre.h"
+
+#include "gromacs/utility/stringtoenumvalueconverter.h"
+
+#include <gtest/gtest.h>
+
+namespace gmx
+{
+
+namespace
+{
+
+//! Type to use in testing
+enum class Foo : int
+{
+    Bar,
+    Ugh,
+    Fooz,
+    Weird,
+    Empty,
+    Count,
+    Default = Ugh
+};
+
+//! Declare the conventional conversion function
+const char* enumValueToString(Foo f)
+{
+    static constexpr gmx::EnumerationArray<Foo, const char*> toString = {
+        "Bar", "Ugh ", "Foo z", "We-i_rd", ""
+    };
+    return toString[f];
+}
+
+//! Declare an atypical conversion function
+const char* enumValueToLetterAsString(Foo f)
+{
+    static constexpr gmx::EnumerationArray<Foo, const char*> toString = { "B", "U", "F", "W", "" };
+    return toString[f];
+}
+
+//! Pretty-printer for GoogleTest to use
+::std::ostream& operator<<(::std::ostream& os, const std::optional<Foo>& f)
+{
+    if (f)
+    {
+        return os << enumValueToString(f.value());
+    }
+    else
+    {
+        return os << "Out-of-range Foo value";
+    }
+}
+
+TEST(StringToEnumValueConverterTest, ExactStringComparisonWorksWithoutStripping)
+{
+    StringToEnumValueConverter<Foo, enumValueToString, StringCompareType::Exact, StripStrings::No> converter;
+    EXPECT_EQ(converter.valueFrom("Bar"), Foo::Bar);
+    EXPECT_FALSE(converter.valueFrom("bar"));
+    EXPECT_EQ(converter.valueFrom("Ugh "), Foo::Ugh);
+    EXPECT_FALSE(converter.valueFrom("ugh "));
+    EXPECT_EQ(converter.valueFrom("Foo z"), Foo::Fooz);
+    EXPECT_FALSE(converter.valueFrom("foo z"));
+    EXPECT_EQ(converter.valueFrom("We-i_rd"), Foo::Weird);
+    EXPECT_FALSE(converter.valueFrom("we-i_rd"));
+    EXPECT_EQ(converter.valueFrom(""), Foo::Empty);
+    EXPECT_FALSE(converter.valueFrom("count"));
+    EXPECT_FALSE(converter.valueFrom("Unknown"));
+    EXPECT_FALSE(converter.valueFrom("BarFoo z"));
+    EXPECT_FALSE(converter.valueFrom("Ugh"));
+    EXPECT_FALSE(converter.valueFrom("Default"));
+}
+
+TEST(StringToEnumValueConverterTest, CaseInsensitiveStringComparisonWorksWithoutStripping)
+{
+    StringToEnumValueConverter<Foo, enumValueToString, StringCompareType::CaseInsensitive, StripStrings::No> converter;
+    EXPECT_EQ(converter.valueFrom("Bar"), Foo::Bar);
+    EXPECT_EQ(converter.valueFrom("bar"), Foo::Bar);
+    EXPECT_EQ(converter.valueFrom("Ugh "), Foo::Ugh);
+    EXPECT_EQ(converter.valueFrom("ugh "), Foo::Ugh);
+    EXPECT_EQ(converter.valueFrom("Foo z"), Foo::Fooz);
+    EXPECT_EQ(converter.valueFrom("foo z"), Foo::Fooz);
+    EXPECT_EQ(converter.valueFrom("We-i_rd"), Foo::Weird);
+    EXPECT_EQ(converter.valueFrom("we-i_rd"), Foo::Weird);
+    EXPECT_EQ(converter.valueFrom(""), Foo::Empty);
+    EXPECT_FALSE(converter.valueFrom("Count"));
+    EXPECT_FALSE(converter.valueFrom("count"));
+    EXPECT_FALSE(converter.valueFrom("Unknown"));
+    EXPECT_FALSE(converter.valueFrom("barfoo z"));
+    EXPECT_FALSE(converter.valueFrom("Ugh"));
+    EXPECT_FALSE(converter.valueFrom("Default"));
+}
+
+TEST(StringToEnumValueConverterTest, CaseAndDashInsensitiveStringComparisonWorksWithoutStripping)
+{
+    StringToEnumValueConverter<Foo, enumValueToString, StringCompareType::CaseAndDashInsensitive, StripStrings::No> converter;
+    EXPECT_EQ(converter.valueFrom("Bar"), Foo::Bar);
+    EXPECT_EQ(converter.valueFrom("b-ar"), Foo::Bar);
+    EXPECT_EQ(converter.valueFrom("Ugh "), Foo::Ugh);
+    EXPECT_EQ(converter.valueFrom("_ugh "), Foo::Ugh);
+    EXPECT_EQ(converter.valueFrom("Foo z"), Foo::Fooz);
+    EXPECT_EQ(converter.valueFrom("fo_o z"), Foo::Fooz);
+    EXPECT_EQ(converter.valueFrom("We-i_rd"), Foo::Weird);
+    EXPECT_EQ(converter.valueFrom("we-i_rd"), Foo::Weird);
+    EXPECT_EQ(converter.valueFrom(""), Foo::Empty);
+    EXPECT_FALSE(converter.valueFrom("Count"));
+    EXPECT_FALSE(converter.valueFrom("count"));
+    EXPECT_FALSE(converter.valueFrom("Unknown"));
+    EXPECT_FALSE(converter.valueFrom("Bar-Foo z"));
+    EXPECT_FALSE(converter.valueFrom("Ugh"));
+    EXPECT_FALSE(converter.valueFrom("Default"));
+}
+
+TEST(StringToEnumValueConverterTest, ExactStringComparisonWorksWithStripping)
+{
+    StringToEnumValueConverter<Foo, enumValueToString, StringCompareType::Exact, StripStrings::Yes> converter;
+    EXPECT_EQ(converter.valueFrom("Bar "), Foo::Bar);
+    EXPECT_FALSE(converter.valueFrom("Ba r"));
+    EXPECT_EQ(converter.valueFrom("Ugh"), Foo::Ugh);
+    EXPECT_FALSE(converter.valueFrom("ugh"));
+    EXPECT_EQ(converter.valueFrom("  Foo z "), Foo::Fooz);
+    EXPECT_FALSE(converter.valueFrom(" foo z"));
+    EXPECT_EQ(converter.valueFrom("We-i_rd  "), Foo::Weird);
+    EXPECT_FALSE(converter.valueFrom("  we-i_rd "));
+    EXPECT_EQ(converter.valueFrom(""), Foo::Empty);
+    EXPECT_FALSE(converter.valueFrom(" Count"));
+    EXPECT_FALSE(converter.valueFrom("count  "));
+    EXPECT_FALSE(converter.valueFrom("Unknown"));
+    EXPECT_FALSE(converter.valueFrom("Bar Foo z"));
+    EXPECT_EQ(converter.valueFrom(" Ugh"), Foo::Ugh);
+    EXPECT_FALSE(converter.valueFrom("Default"));
+}
+
+TEST(StringToEnumValueConverterTest, CaseInsensitiveStringComparisonWorksWithStripping)
+{
+    StringToEnumValueConverter<Foo, enumValueToString, StringCompareType::CaseInsensitive, StripStrings::Yes> converter;
+    EXPECT_EQ(converter.valueFrom("Bar "), Foo::Bar);
+    EXPECT_FALSE(converter.valueFrom("ba r"));
+    EXPECT_EQ(converter.valueFrom("Ugh "), Foo::Ugh);
+    EXPECT_EQ(converter.valueFrom("  ugh "), Foo::Ugh);
+    EXPECT_EQ(converter.valueFrom("  Foo z "), Foo::Fooz);
+    EXPECT_EQ(converter.valueFrom("foo z   "), Foo::Fooz);
+    EXPECT_EQ(converter.valueFrom("We-i_rd  "), Foo::Weird);
+    EXPECT_EQ(converter.valueFrom("  we-i_rd "), Foo::Weird);
+    EXPECT_EQ(converter.valueFrom(""), Foo::Empty);
+    EXPECT_FALSE(converter.valueFrom("  Count"));
+    EXPECT_FALSE(converter.valueFrom("count "));
+    EXPECT_FALSE(converter.valueFrom("Unknown"));
+    EXPECT_FALSE(converter.valueFrom("  barfoo z"));
+    EXPECT_EQ(converter.valueFrom(" Ugh"), Foo::Ugh);
+    EXPECT_FALSE(converter.valueFrom("Default"));
+}
+
+TEST(StringToEnumValueConverterTest, CaseAndDashInsensitiveStringComparisonWorksWithStripping)
+{
+    StringToEnumValueConverter<Foo, enumValueToString, StringCompareType::CaseAndDashInsensitive, StripStrings::Yes> converter;
+    EXPECT_EQ(converter.valueFrom("Bar "), Foo::Bar);
+    EXPECT_FALSE(converter.valueFrom("b-a r"));
+    EXPECT_EQ(converter.valueFrom("Ugh "), Foo::Ugh);
+    EXPECT_EQ(converter.valueFrom(" _ugh "), Foo::Ugh);
+    EXPECT_EQ(converter.valueFrom(" Foo z "), Foo::Fooz);
+    EXPECT_EQ(converter.valueFrom("fo_o z  "), Foo::Fooz);
+    EXPECT_EQ(converter.valueFrom("We-i_rd  "), Foo::Weird);
+    EXPECT_EQ(converter.valueFrom("  we-i_rd "), Foo::Weird);
+    EXPECT_EQ(converter.valueFrom(""), Foo::Empty);
+    EXPECT_FALSE(converter.valueFrom("  Count"));
+    EXPECT_FALSE(converter.valueFrom("coun-t "));
+    EXPECT_FALSE(converter.valueFrom("Unknown"));
+    EXPECT_FALSE(converter.valueFrom("  Bar-Foo z   "));
+    EXPECT_EQ(converter.valueFrom("Ugh  "), Foo::Ugh);
+    EXPECT_FALSE(converter.valueFrom("Default"));
+}
+
+TEST(StringToEnumValueConverterTest, CustomConverterWorks)
+{
+    StringToEnumValueConverter<Foo, enumValueToLetterAsString> converter;
+    EXPECT_EQ(converter.valueFrom("B"), Foo::Bar);
+    EXPECT_FALSE(converter.valueFrom("b"));
+    EXPECT_EQ(converter.valueFrom("U"), Foo::Ugh);
+    EXPECT_FALSE(converter.valueFrom("u"));
+    EXPECT_EQ(converter.valueFrom("F"), Foo::Fooz);
+    EXPECT_FALSE(converter.valueFrom("f"));
+    EXPECT_EQ(converter.valueFrom(""), Foo::Empty);
+    EXPECT_FALSE(converter.valueFrom("C"));
+    EXPECT_FALSE(converter.valueFrom("c"));
+    EXPECT_FALSE(converter.valueFrom("X"));
+    EXPECT_FALSE(converter.valueFrom("Default"));
+}
+
+} // namespace
+} // namespace gmx
index 0b2acccc24fbf04f965070cda6704c4c955f8816..db0c1f1857ecf1c6fdcae4f80c5f6ef4e4b1aad2 100644 (file)
@@ -241,8 +241,8 @@ TEST(formatAndJoinTest, Works)
 {
     const char* const words[] = { "The", "quick", "brown", "fox" };
     EXPECT_EQ("The       .quick     .brown     .fox       ",
-              gmx::formatAndJoin(gmx::ArrayRef<const char* const>(words), ".",
-                                 gmx::StringFormatter("%-10s")));
+              gmx::formatAndJoin(
+                      gmx::ArrayRef<const char* const>(words), ".", gmx::StringFormatter("%-10s")));
 
     const int values[] = { 0, 1, 4 };
     EXPECT_EQ("0,1,4",
index dba10585d1a71757818820777e44b4bdd8bc0172..17db397e8427690d9076af255ddd9489d00cb879 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,11 +57,43 @@ static int testEnumTwoIPlusJPlusK(int k)
     return 2 * int(i) + int(j) + k;
 }
 
-TEST(TemplateMPTest, DispatchTemplatedFunction)
+template<bool doDoubling, Options i, Options j>
+static int testBoolEnumTwoIPlusJPlusK(int k)
+{
+    return (doDoubling ? 2 : 1) * int(i) + int(j) + k;
+}
+
+template<bool doDoubling>
+static int testBoolDoubleOrNot(int k)
+{
+    return (doDoubling ? 2 : 1) * k;
+}
+
+
+TEST(TemplateMPTest, DispatchTemplatedFunctionEnum)
+{
+    int five           = 5;
+    int two1plus2plus5 = dispatchTemplatedFunction(
+            [=](auto p1, auto p2) { return testEnumTwoIPlusJPlusK<p1, p2>(five); }, Options::Op1, Options::Op2);
+    EXPECT_EQ(two1plus2plus5, 9);
+}
+
+TEST(TemplateMPTest, DispatchTemplatedFunctionBool)
+{
+    int five = 5;
+    int double5 = dispatchTemplatedFunction([=](auto p1) { return testBoolDoubleOrNot<p1>(five); }, true);
+    EXPECT_EQ(double5, 10);
+    int just5 = dispatchTemplatedFunction([=](auto p1) { return testBoolDoubleOrNot<p1>(five); }, false);
+    EXPECT_EQ(just5, 5);
+}
+
+TEST(TemplateMPTest, DispatchTemplatedFunctionEnumBool)
 {
     int five           = 5;
     int two1plus2plus5 = dispatchTemplatedFunction(
-            [=](auto p1, auto p2) { return testEnumTwoIPlusJPlusK<p1, p2>(five); }, Options::Op1,
+            [=](auto p1, auto p2, auto p3) { return testBoolEnumTwoIPlusJPlusK<p1, p2, p3>(five); },
+            true,
+            Options::Op1,
             Options::Op2);
     EXPECT_EQ(two1plus2plus5, 9);
 }
index 55020da4048bb57d755f84989b9a30d78e6f93f3..f6c3f58c53a1226c22dd91cf102814fe40e0c721 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2017,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +43,9 @@
 #ifndef GMX_UTILITY_TEXTREADER_H
 #define GMX_UTILITY_TEXTREADER_H
 
+#include <memory>
 #include <string>
 
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/textstream.h"
 
 namespace gmx
@@ -180,7 +180,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 89b7eccf1c6b92ded3a41b4b7d6873e7161ebefd..e1ddd78f6af27da469d9d0eb12202a505d8cba73 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +45,9 @@
 
 #include <cstdio>
 
+#include <memory>
 #include <string>
 
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/textstream.h"
 
 namespace gmx
@@ -196,7 +196,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace gmx
index 1198fa9dde26af610e9b14d43f7390e569daa86f..92ae68c6fe3c20a2f2f348dd8119663bd53971ce 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +48,7 @@
 
 int pr_indent(FILE* fp, int n)
 {
-    int i;
-
-    for (i = 0; i < n; i++)
+    for (int i = 0; i < n; i++)
     {
         fprintf(fp, " ");
     }
@@ -93,13 +91,11 @@ int pr_title_nxn(FILE* fp, int indent, const char* title, int n1, int n2)
 
 void pr_reals(FILE* fp, int indent, const char* title, const real* vec, int n)
 {
-    int i;
-
     if (available(fp, vec, indent, title))
     {
         pr_indent(fp, indent);
         fprintf(fp, "%s:\t", title);
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < n; i++)
         {
             fprintf(fp, "  %10g", vec[i]);
         }
@@ -109,13 +105,11 @@ void pr_reals(FILE* fp, int indent, const char* title, const real* vec, int n)
 
 void pr_doubles(FILE* fp, int indent, const char* title, const double* vec, int n)
 {
-    int i;
-
     if (available(fp, vec, indent, title))
     {
         pr_indent(fp, indent);
         fprintf(fp, "%s:\t", title);
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < n; i++)
         {
             fprintf(fp, "  %10g", vec[i]);
         }
@@ -125,28 +119,18 @@ void pr_doubles(FILE* fp, int indent, const char* title, const double* vec, int
 
 void pr_reals_of_dim(FILE* fp, int indent, const char* title, const real* vec, int n, int dim)
 {
-    int         i, j;
     const char* fshort = "%12.5e";
     const char* flong  = "%15.8e";
-    const char* format;
-
-    if (getenv("GMX_PRINT_LONGFORMAT") != nullptr)
-    {
-        format = flong;
-    }
-    else
-    {
-        format = fshort;
-    }
+    const char* format = (getenv("GMX_PRINT_LONGFORMAT") != nullptr) ? flong : fshort;
 
     if (available(fp, vec, indent, title))
     {
         indent = pr_title_nxn(fp, indent, title, n, dim);
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < n; i++)
         {
             pr_indent(fp, indent);
             fprintf(fp, "%s[%5d]={", title, i);
-            for (j = 0; j < dim; j++)
+            for (int j = 0; j < dim; j++)
             {
                 if (j != 0)
                 {
@@ -193,12 +177,10 @@ void pr_str(FILE* fp, int indent, const char* title, const char* s)
 
 void pr_strings(FILE* fp, int indent, const char* title, char*** nm, int n, gmx_bool bShowNumbers)
 {
-    int i;
-
     if (available(fp, nm, indent, title))
     {
         indent = pr_title_n(fp, indent, title, n);
-        for (i = 0; i < n; i++)
+        for (int i = 0; i < n; i++)
         {
             pr_indent(fp, indent);
             fprintf(fp, "%s[%d]={name=\"%s\"}\n", title, bShowNumbers ? i : -1, *(nm[i]));
similarity index 80%
rename from src/gmxpre.h
rename to src/include/gmxpre.h
index 10353266f1ab3413e1dc930ef242265c41bb334e..c4b541f9e4acd7e2d7d70a075e4cebfad9638361 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 _GNU_SOURCE 1
 #endif
 
-/* Some C++(?) compilers require these to be defined to get the integer limits
- * and format specifier macros from stdint.h and inttypes.h, respectively.
- * The macros are in C99 and C++11, but not in C++98...
- * As with _GNU_SOURCE, these need to be defined before these headers get first
- * included.  Unlike _GNU_SOURCE, these headers are included indirectly in most
- * header and source files (even though the macros are not used that often), so
- * there is no easy alternative to defining them here, either.
- * If someone happens to use such a compiler to compile against the installed
- * Gromacs headers, they need for now take care to define the macros themselves
- * (as there is no way Gromacs can do that consistently).
- */
-#define __STDC_LIMIT_MACROS
-#define __STDC_FORMAT_MACROS
-
 #if GMX_FAHCORE
 #    define FULLINDIRECT 1
 #    define USE_FAH_XDR 1
index 860729a26afe1fee2ff686c61f62d490e33df611..3512ec379b40a1a933fd2d7aa47224c707627e9e 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
-# Copyright (c) 2015,2016,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2015,2016,2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,30 +41,17 @@ target_compile_definitions(mdrun_objlib PRIVATE HAVE_CONFIG_H)
 target_include_directories(mdrun_objlib SYSTEM BEFORE PRIVATE ${PROJECT_SOURCE_DIR}/src/external/thread_mpi/include)
 # Should be possible to remove this when resolving #3290
 target_include_directories(mdrun_objlib SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/src/external)
+target_link_libraries(mdrun_objlib PRIVATE common)
+target_link_libraries(mdrun_objlib PRIVATE legacy_api)
+# TODO: Explicitly link specific modules.
+target_link_libraries(mdrun_objlib PRIVATE legacy_modules)
 
 if(GMX_FAHCORE)
     # The lack of a real source file here alongside the object library
     # 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)
-    message(STATUS "The mdrun-only build is deprecated")
-    add_executable(mdrun $<TARGET_OBJECTS:mdrun_objlib> mdrun_main.cpp)
-    gmx_target_compile_options(mdrun)
-    target_include_directories(mdrun SYSTEM BEFORE PRIVATE ${PROJECT_SOURCE_DIR}/src/external/thread_mpi/include)
-    target_compile_definitions(mdrun PRIVATE HAVE_CONFIG_H)
-    target_link_libraries(mdrun libgromacs
-        ${GMX_COMMON_LIBRARIES}
-        ${GMX_EXE_LINKER_FLAGS})
-    set(BINARY_NAME "mdrun${GMX_BINARY_SUFFIX}")
-    set_target_properties(mdrun PROPERTIES
-        OUTPUT_NAME "${BINARY_NAME}")
-    install(TARGETS mdrun DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT mdrun)
-    file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/gmx-completion-${BINARY_NAME}.bash
-         "complete -o nospace -F _gmx_mdrun_compl ${BINARY_NAME}")
-    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/gmx-completion-${BINARY_NAME}.bash
-            DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime)
+    target_link_libraries(fahcore PRIVATE ${GMX_COMMON_LIBRARIES} legacy_api)
 else()
     file(GLOB GMX_MAIN_SOURCES gmx.cpp legacymodules.cpp)
     if(GMX_X11)
@@ -76,7 +63,13 @@ else()
     gmx_target_compile_options(view_objlib)
     target_compile_definitions(view_objlib PRIVATE HAVE_CONFIG_H)
     target_include_directories(view_objlib SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/src/external)
+    target_link_libraries(view_objlib PRIVATE common legacy_api)
+    # TODO: Explicitly link specific modules.
+    target_link_libraries(view_objlib PRIVATE legacy_modules)
     add_library(gmx_objlib OBJECT ${GMX_MAIN_SOURCES})
+    target_link_libraries(gmx_objlib PRIVATE common legacy_api)
+    # TODO: Explicitly link specific modules.
+    target_link_libraries(gmx_objlib PRIVATE legacy_modules)
     target_include_directories(gmx_objlib SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/src/external)
     target_include_directories(gmx_objlib SYSTEM BEFORE PRIVATE ${PROJECT_SOURCE_DIR}/src/external/thread_mpi/include)
     add_executable(gmx
@@ -86,9 +79,11 @@ else()
     add_executable(Gromacs::gmx ALIAS gmx)
     gmx_target_compile_options(gmx)
     target_compile_definitions(gmx PRIVATE HAVE_CONFIG_H)
-    target_link_libraries(gmx libgromacs
-        ${GMX_COMMON_LIBRARIES}
-        ${GMX_EXE_LINKER_FLAGS})
+    target_link_libraries(gmx PRIVATE
+                          common
+                          libgromacs
+                          ${GMX_COMMON_LIBRARIES}
+                          ${GMX_EXE_LINKER_FLAGS})
     if(GMX_X11)
         target_link_libraries(gmx ${X11_LIBRARIES})
     endif()
index f591e2c61b8a9f70760d88c430b9e78893627645..467f6a2f4947e3c0220400965d7a716b163f08a7 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -176,63 +176,82 @@ void registerLegacyModules(gmx::CommandLineModuleManager* manager)
     gmx::ICommandLineOptionsModule::registerModuleFactory(
             manager, gmx::DumpInfo::name, gmx::DumpInfo::shortDescription, &gmx::DumpInfo::create);
     registerModule(manager, &gmx_grompp, "grompp", "Make a run input file");
-    gmx::ICommandLineOptionsModule::registerModuleFactory(manager, gmx::ConvertTprInfo::name,
+    gmx::ICommandLineOptionsModule::registerModuleFactory(manager,
+                                                          gmx::ConvertTprInfo::name,
                                                           gmx::ConvertTprInfo::shortDescription,
                                                           &gmx::ConvertTprInfo::create);
     registerObsoleteTool(manager, "tpbconv");
     registerModule(manager, &gmx_x2top, "x2top", "Generate a primitive topology from coordinates");
 
     registerModuleNoNice(
-            manager, &gmx::gmx_mdrun, "mdrun",
+            manager,
+            &gmx::gmx_mdrun,
+            "mdrun",
             "Perform a simulation, do a normal mode analysis or an energy minimization");
 
-    gmx::ICommandLineOptionsModule::registerModuleFactory(
-            manager, gmx::NonbondedBenchmarkInfo::name,
-            gmx::NonbondedBenchmarkInfo::shortDescription, &gmx::NonbondedBenchmarkInfo::create);
+    gmx::ICommandLineOptionsModule::registerModuleFactory(manager,
+                                                          gmx::NonbondedBenchmarkInfo::name,
+                                                          gmx::NonbondedBenchmarkInfo::shortDescription,
+                                                          &gmx::NonbondedBenchmarkInfo::create);
 
-    gmx::ICommandLineOptionsModule::registerModuleFactory(manager, gmx::InsertMoleculesInfo::name(),
+    gmx::ICommandLineOptionsModule::registerModuleFactory(manager,
+                                                          gmx::InsertMoleculesInfo::name(),
                                                           gmx::InsertMoleculesInfo::shortDescription(),
                                                           &gmx::InsertMoleculesInfo::create);
 
-    gmx::ICommandLineOptionsModule::registerModuleFactory(manager, gmx::ReportMethodsInfo::name,
+    gmx::ICommandLineOptionsModule::registerModuleFactory(manager,
+                                                          gmx::ReportMethodsInfo::name,
                                                           gmx::ReportMethodsInfo::shortDescription,
                                                           &gmx::ReportMethodsInfo::create);
 
-    gmx::ICommandLineOptionsModule::registerModuleFactory(manager, gmx::pdb2gmxInfo::name,
-                                                          gmx::pdb2gmxInfo::shortDescription,
-                                                          &gmx::pdb2gmxInfo::create);
+    gmx::ICommandLineOptionsModule::registerModuleFactory(
+            manager, gmx::pdb2gmxInfo::name, gmx::pdb2gmxInfo::shortDescription, &gmx::pdb2gmxInfo::create);
 
     // Modules from gmx_ana.h.
-    registerModule(manager, &gmx_do_dssp, "do_dssp",
+    registerModule(manager,
+                   &gmx_do_dssp,
+                   "do_dssp",
                    "Assign secondary structure and calculate solvent accessible surface area");
     registerModule(manager, &gmx_editconf, "editconf", "Convert and manipulates structure files");
     registerModule(manager, &gmx_eneconv, "eneconv", "Convert energy files");
     registerModule(manager, &gmx_solvate, "solvate", "Solvate a system");
     registerObsoleteTool(manager, "genbox");
-    registerModule(manager, &gmx_genconf, "genconf",
-                   "Multiply a conformation in 'random' orientations");
-    registerModule(manager, &gmx_genion, "genion",
+    registerModule(
+            manager, &gmx_genconf, "genconf", "Multiply a conformation in 'random' orientations");
+    registerModule(manager,
+                   &gmx_genion,
+                   "genion",
                    "Generate monoatomic ions on energetically favorable positions");
-    registerModule(manager, &gmx_genrestr, "genrestr",
+    registerModule(manager,
+                   &gmx_genrestr,
+                   "genrestr",
                    "Generate position restraints or distance restraints for index groups");
-    registerModule(manager, &gmx_make_edi, "make_edi",
+    registerModule(manager,
+                   &gmx_make_edi,
+                   "make_edi",
                    "Generate input files for essential dynamics sampling");
     registerModule(manager, &gmx_make_ndx, "make_ndx", "Make index files");
     registerModule(manager, &gmx_mk_angndx, "mk_angndx", "Generate index files for 'gmx angle'");
     registerModule(manager, &gmx_trjcat, "trjcat", "Concatenate trajectory files");
     registerModule(manager, &gmx_trjconv, "trjconv", "Convert and manipulates trajectory files");
-    registerModule(manager, &gmx_trjorder, "trjorder",
+    registerModule(manager,
+                   &gmx_trjorder,
+                   "trjorder",
                    "Order molecules according to their distance to a group");
-    registerModule(manager, &gmx_xpm2ps, "xpm2ps",
-                   "Convert XPM (XPixelMap) matrices to postscript or XPM");
+    registerModule(
+            manager, &gmx_xpm2ps, "xpm2ps", "Convert XPM (XPixelMap) matrices to postscript or XPM");
 
     registerModule(manager, &gmx_anaeig, "anaeig", "Analyze eigenvectors/normal modes");
     registerModule(manager, &gmx_analyze, "analyze", "Analyze data sets");
-    registerModule(manager, &gmx_g_angle, "angle",
+    registerModule(manager,
+                   &gmx_g_angle,
+                   "angle",
                    "Calculate distributions and correlations for angles and dihedrals");
-    registerModule(manager, &gmx_awh, "awh",
-                   "Extract data from an accelerated weight histogram (AWH) run");
-    registerModule(manager, &gmx_bar, "bar",
+    registerModule(
+            manager, &gmx_awh, "awh", "Extract data from an accelerated weight histogram (AWH) run");
+    registerModule(manager,
+                   &gmx_bar,
+                   "bar",
                    "Calculate free energy difference estimates through Bennett's acceptance ratio");
     registerObsoleteTool(manager, "bond");
     registerObsoleteTool(manager, "dist");
@@ -240,90 +259,133 @@ void registerLegacyModules(gmx::CommandLineModuleManager* manager)
     registerObsoleteTool(manager, "sgangle");
 
     registerModule(manager, &gmx_bundle, "bundle", "Analyze bundles of axes, e.g., helices");
-    registerModule(manager, &gmx_chi, "chi",
+    registerModule(manager,
+                   &gmx_chi,
+                   "chi",
                    "Calculate everything you want to know about chi and other dihedrals");
     registerModule(manager, &gmx_cluster, "cluster", "Cluster structures");
-    registerModule(manager, &gmx_clustsize, "clustsize",
-                   "Calculate size distributions of atomic clusters");
+    registerModule(
+            manager, &gmx_clustsize, "clustsize", "Calculate size distributions of atomic clusters");
     registerModule(manager, &gmx_confrms, "confrms", "Fit two structures and calculates the RMSD");
     registerModule(manager, &gmx_covar, "covar", "Calculate and diagonalize the covariance matrix");
-    registerModule(manager, &gmx_current, "current",
+    registerModule(manager,
+                   &gmx_current,
+                   "current",
                    "Calculate dielectric constants and current autocorrelation function");
     registerModule(manager, &gmx_density, "density", "Calculate the density of the system");
-    registerModule(manager, &gmx_densmap, "densmap",
-                   "Calculate 2D planar or axial-radial density maps");
+    registerModule(
+            manager, &gmx_densmap, "densmap", "Calculate 2D planar or axial-radial density maps");
     registerModule(manager, &gmx_densorder, "densorder", "Calculate surface fluctuations");
-    registerModule(manager, &gmx_dielectric, "dielectric",
+    registerModule(manager,
+                   &gmx_dielectric,
+                   "dielectric",
                    "Calculate frequency dependent dielectric constants");
     registerModule(manager, &gmx_dipoles, "dipoles", "Compute the total dipole plus fluctuations");
     registerModule(manager, &gmx_disre, "disre", "Analyze distance restraints");
-    registerModule(manager, &gmx_dos, "dos",
-                   "Analyze density of states and properties based on that");
+    registerModule(
+            manager, &gmx_dos, "dos", "Analyze density of states and properties based on that");
     registerModule(manager, &gmx_dyecoupl, "dyecoupl", "Extract dye dynamics from trajectories");
     registerModule(manager, &gmx_enemat, "enemat", "Extract an energy matrix from an energy file");
-    registerModule(manager, &gmx_energy, "energy",
-                   "Writes energies to xvg files and display averages");
-    registerModule(manager, &gmx_filter, "filter",
+    registerModule(
+            manager, &gmx_energy, "energy", "Writes energies to xvg files and display averages");
+    registerModule(manager,
+                   &gmx_filter,
+                   "filter",
                    "Frequency filter trajectories, useful for making smooth movies");
     registerModule(manager, &gmx_gyrate, "gyrate", "Calculate the radius of gyration");
     registerModule(manager, &gmx_h2order, "h2order", "Compute the orientation of water molecules");
     registerModule(manager, &gmx_hbond, "hbond", "Compute and analyze hydrogen bonds");
     registerModule(manager, &gmx_helix, "helix", "Calculate basic properties of alpha helices");
-    registerModule(manager, &gmx_helixorient, "helixorient",
+    registerModule(manager,
+                   &gmx_helixorient,
+                   "helixorient",
                    "Calculate local pitch/bending/rotation/orientation inside helices");
-    registerModule(manager, &gmx_hydorder, "hydorder",
+    registerModule(manager,
+                   &gmx_hydorder,
+                   "hydorder",
                    "Compute tetrahedrality parameters around a given atom");
     registerModule(manager, &gmx_lie, "lie", "Estimate free energy from linear combinations");
     registerModule(manager, &gmx_mdmat, "mdmat", "Calculate residue contact maps");
-    registerModule(manager, &gmx_mindist, "mindist",
-                   "Calculate the minimum distance between two groups");
-    registerModule(manager, &gmx_msd, "msd", "Calculates mean square displacements");
+    registerModule(
+            manager, &gmx_mindist, "mindist", "Calculate the minimum distance between two groups");
     registerModule(manager, &gmx_nmeig, "nmeig", "Diagonalize the Hessian for normal mode analysis");
-    registerModule(manager, &gmx_nmens, "nmens",
+    registerModule(manager,
+                   &gmx_nmens,
+                   "nmens",
                    "Generate an ensemble of structures from the normal modes");
-    registerModule(manager, &gmx_nmr, "nmr",
+    registerModule(manager,
+                   &gmx_nmr,
+                   "nmr",
                    "Analyze nuclear magnetic resonance properties from an energy file");
-    registerModule(manager, &gmx_nmtraj, "nmtraj",
+    registerModule(manager,
+                   &gmx_nmtraj,
+                   "nmtraj",
                    "Generate a virtual oscillating trajectory from an eigenvector");
-    registerModule(manager, &gmx_order, "order",
-                   "Compute the order parameter per atom for carbon tails");
-    registerModule(manager, &gmx_pme_error, "pme_error",
+    registerModule(
+            manager, &gmx_order, "order", "Compute the order parameter per atom for carbon tails");
+    registerModule(manager,
+                   &gmx_pme_error,
+                   "pme_error",
                    "Estimate the error of using PME with a given input file");
     registerModule(manager, &gmx_polystat, "polystat", "Calculate static properties of polymers");
-    registerModule(manager, &gmx_potential, "potential",
+    registerModule(manager,
+                   &gmx_potential,
+                   "potential",
                    "Calculate the electrostatic potential across the box");
-    registerModule(manager, &gmx_principal, "principal",
+    registerModule(manager,
+                   &gmx_principal,
+                   "principal",
                    "Calculate principal axes of inertia for a group of atoms");
     registerModule(manager, &gmx_rama, "rama", "Compute Ramachandran plots");
-    registerModule(manager, &gmx_rms, "rms",
+    registerModule(manager,
+                   &gmx_rms,
+                   "rms",
                    "Calculate RMSDs with a reference structure and RMSD matrices");
-    registerModule(manager, &gmx_rmsdist, "rmsdist",
+    registerModule(manager,
+                   &gmx_rmsdist,
+                   "rmsdist",
                    "Calculate atom pair distances averaged with power -2, -3 or -6");
     registerModule(manager, &gmx_rmsf, "rmsf", "Calculate atomic fluctuations");
-    registerModule(manager, &gmx_rotacf, "rotacf",
+    registerModule(manager,
+                   &gmx_rotacf,
+                   "rotacf",
                    "Calculate the rotational correlation function for molecules");
-    registerModule(manager, &gmx_rotmat, "rotmat",
+    registerModule(manager,
+                   &gmx_rotmat,
+                   "rotmat",
                    "Plot the rotation matrix for fitting to a reference structure");
     registerModule(manager, &gmx_saltbr, "saltbr", "Compute salt bridges");
     registerModule(manager, &gmx_sans, "sans", "Compute small angle neutron scattering spectra");
     registerModule(manager, &gmx_saxs, "saxs", "Compute small angle X-ray scattering spectra");
-    registerModule(manager, &gmx_sham, "sham",
-                   "Compute free energies or other histograms from histograms");
-    registerModule(manager, &gmx_sigeps, "sigeps",
+    registerModule(
+            manager, &gmx_sham, "sham", "Compute free energies or other histograms from histograms");
+    registerModule(manager,
+                   &gmx_sigeps,
+                   "sigeps",
                    "Convert c6/12 or c6/cn combinations to and from sigma/epsilon");
     registerModule(manager, &gmx_sorient, "sorient", "Analyze solvent orientation around solutes");
     registerModule(manager, &gmx_spatial, "spatial", "Calculate the spatial distribution function");
-    registerModule(manager, &gmx_spol, "spol",
+    registerModule(manager,
+                   &gmx_spol,
+                   "spol",
                    "Analyze solvent dipole orientation and polarization around solutes");
     registerModule(manager, &gmx_tcaf, "tcaf", "Calculate viscosities of liquids");
-    registerModule(manager, &gmx_traj, "traj",
+    registerModule(manager,
+                   &gmx_traj,
+                   "traj",
                    "Plot x, v, f, box, temperature and rotational energy from trajectories");
-    registerModule(manager, &gmx_tune_pme, "tune_pme",
+    registerModule(manager,
+                   &gmx_tune_pme,
+                   "tune_pme",
                    "Time mdrun as a function of PME ranks to optimize settings");
-    registerModule(manager, &gmx_vanhove, "vanhove",
+    registerModule(manager,
+                   &gmx_vanhove,
+                   "vanhove",
                    "Compute Van Hove displacement and correlation functions");
     registerModule(manager, &gmx_velacc, "velacc", "Calculate velocity autocorrelation functions");
-    registerModule(manager, &gmx_wham, "wham",
+    registerModule(manager,
+                   &gmx_wham,
+                   "wham",
                    "Perform weighted histogram analysis after umbrella sampling");
     registerModule(manager, &gmx_wheel, "wheel", "Plot helical wheels");
     registerModuleNoNice(manager, &gmx_view, "view", "View a trajectory on an X-Windows terminal");
@@ -406,7 +468,6 @@ void registerLegacyModules(gmx::CommandLineModuleManager* manager)
         gmx::CommandLineModuleGroup group =
                 manager->addModuleGroup("Mass distribution properties over time");
         group.addModule("gyrate");
-        group.addModule("msd");
         group.addModule("polystat");
         group.addModule("rdf");
         group.addModule("rotacf");
index 77a25f1fdfab7963a8594359b643f35731d6af8d..7c59e4e6771c356b10a537a5c1f124b5acd9ce64 100644 (file)
@@ -236,9 +236,12 @@ int gmx_mdrun(MPI_Comm communicator, const gmx_hw_info_t& hwinfo, int argc, char
     StartingBehavior startingBehavior        = StartingBehavior::NewSimulation;
     LogFilePtr       logFileGuard            = nullptr;
     gmx_multisim_t*  ms                      = simulationContext.multiSimulation_.get();
-    std::tie(startingBehavior, logFileGuard) = handleRestart(
-            findIsSimulationMasterRank(ms, communicator), communicator, ms,
-            options.mdrunOptions.appendingBehavior, ssize(options.filenames), options.filenames.data());
+    std::tie(startingBehavior, logFileGuard) = handleRestart(findIsSimulationMasterRank(ms, communicator),
+                                                             communicator,
+                                                             ms,
+                                                             options.mdrunOptions.appendingBehavior,
+                                                             ssize(options.filenames),
+                                                             options.filenames.data());
 
     /* The named components for the builder exposed here are descriptive of the
      * state of mdrun at implementation and are not intended to be prescriptive
index bd693790b3499337cb7cb0aa44d89a3dd638daef..17ae7b69403a8c49167f2fbb4c7cc52e778626bf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -211,7 +211,7 @@ void NonbondedBenchmark::initOptions(IOptionsContainer* options, ICommandLineOpt
     options->addOption(
             BooleanOption("time").store(&benchmarkOptions_.reportTime).description("Report micro-seconds instead of cycles"));
     options->addOption(FileNameOption("o")
-                               .filetype(eftCsv)
+                               .filetype(OptionFileType::Csv)
                                .outputFile()
                                .store(&benchmarkOptions_.outputFile)
                                .defaultBasename("nonbonded-benchmark")
diff --git a/src/programs/mdrun/tests/.clang-tidy b/src/programs/mdrun/tests/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index e4eccebd696ee00f00d79b2dad0ac391dda809ab..b230e6f80be40a97da7b078f63918bf6b8de934c 100644 (file)
@@ -2,7 +2,7 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2013,2014,2015,2016,2017 The GROMACS development team.
-# Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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 @@ gmx_add_unit_test_library(mdrun_test_infrastructure
     $<TARGET_OBJECTS:mdrun_objlib>
     )
 target_include_directories(mdrun_test_infrastructure SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/src/external)
+target_link_libraries(mdrun_test_infrastructure PUBLIC legacy_api)
 
 # To avoid running into test timeouts, some end-to-end tests of mdrun
 # functionality are split off. This can be rearranged in future as we
@@ -109,6 +110,7 @@ gmx_add_gtest_executable(${exename}
         orires.cpp
         swapcoords.cpp
         tabulated_bonded_interactions.cpp
+        freezegroups.cpp
         # pseudo-library for code for mdrun
         $<TARGET_OBJECTS:mdrun_objlib>
     )
@@ -171,15 +173,29 @@ gmx_add_gtest_executable(${exename} MPI
         domain_decomposition.cpp
         minimize.cpp
         mimic.cpp
+        pmetest.cpp
+        # pseudo-library for code for mdrun
+        $<TARGET_OBJECTS:mdrun_objlib>
+        )
+target_link_libraries(${exename} PRIVATE mdrun_test_infrastructure)
+gmx_register_gtest_test(${testname} ${exename} MPI_RANKS 2 OPENMP_THREADS 2 INTEGRATION_TEST IGNORE_LEAKS)
+
+# Multi sim only makes sense with real MPI, and ideally at least 4 ranks,
+# to allow for multiple simulations (>= 2 sims) each using DD (>= 2 ranks per sim)
+set(testname "MdrunMultiSimTests")
+set(exename "mdrun-multisim-test")
+
+gmx_add_gtest_executable(${exename} MPI
+    CPP_SOURCE_FILES
+        # files with code for tests
         multisim.cpp
         multisimtest.cpp
         replicaexchange.cpp
-        pmetest.cpp
         # pseudo-library for code for mdrun
         $<TARGET_OBJECTS:mdrun_objlib>
         )
 target_link_libraries(${exename} PRIVATE mdrun_test_infrastructure)
-gmx_register_gtest_test(${testname} ${exename} MPI_RANKS 2 OPENMP_THREADS 2 INTEGRATION_TEST IGNORE_LEAKS)
+gmx_register_gtest_test(${testname} ${exename} MPI_RANKS 4 INTEGRATION_TEST IGNORE_LEAKS)
 
 # Tests that only make sense to run with multiple ranks and/or real
 # MPI are implemented here. Special case for slow PME tests
@@ -230,6 +246,8 @@ gmx_add_gtest_executable(${exename}
         $<TARGET_OBJECTS:mdrun_objlib>
 )
 target_link_libraries(${exename} PRIVATE mdrun_test_infrastructure)
+# TODO: Link specific modules: topology
+target_link_libraries(${exename} PRIVATE legacy_modules)
 gmx_register_gtest_test(${testname} ${exename} OPENMP_THREADS 2 INTEGRATION_TEST IGNORE_LEAKS)
 
 # End-to-end tests comparing different simulator code paths
@@ -245,3 +263,17 @@ gmx_add_gtest_executable(${exename}
         )
 target_link_libraries(${exename} PRIVATE mdrun_test_infrastructure)
 gmx_register_gtest_test(${testname} ${exename} OPENMP_THREADS 2 INTEGRATION_TEST IGNORE_LEAKS)
+
+# Tests checking virtual sites - we want to run them with multiple ranks
+set(testname "MdrunVirtualSiteTests")
+set(exename "mdrun-vsites-test")
+
+gmx_add_gtest_executable(${exename} MPI
+        CPP_SOURCE_FILES
+        # files with code for tests
+        virtualsites.cpp
+        # pseudo-library for code for mdrun
+        $<TARGET_OBJECTS:mdrun_objlib>
+        )
+target_link_libraries(${exename} PRIVATE mdrun_test_infrastructure)
+gmx_register_gtest_test(${testname} ${exename} MPI_RANKS 2 INTEGRATION_TEST IGNORE_LEAKS)
index dcee1703feef6f9d78db9d1e2905ee771616e938..2ddd809420e552b34780ca2a945ffc6a38f1dd03 100644 (file)
@@ -128,8 +128,9 @@ TEST_P(CheckpointCoordinatesSanityChecks, WithinTolerances)
         // 1/2 dt between checkpoint (top of the loop) and trajectory (full time step state)
         trajectoryMatchSettings.velocitiesComparison = ComparisonConditions::NoComparison;
     }
-    const TrajectoryTolerances trajectoryTolerances{ defaultRealTolerance(), defaultRealTolerance(),
-                                                     defaultRealTolerance(), defaultRealTolerance() };
+    const TrajectoryTolerances trajectoryTolerances{
+        defaultRealTolerance(), defaultRealTolerance(), defaultRealTolerance(), defaultRealTolerance()
+    };
 
     const auto mdpFieldValues =
             prepareMdpFieldValues(simulationName, integrator, temperatureCoupling, pressureCoupling);
@@ -141,7 +142,9 @@ TEST_P(CheckpointCoordinatesSanityChecks, WithinTolerances)
     SCOPED_TRACE(formatString(
             "Checking the sanity of the checkpointed coordinates using system '%s' "
             "with integrator '%s', '%s' temperature coupling, and '%s' pressure coupling ",
-            simulationName.c_str(), integrator.c_str(), temperatureCoupling.c_str(),
+            simulationName.c_str(),
+            integrator.c_str(),
+            temperatureCoupling.c_str(),
             pressureCoupling.c_str()));
 
     SCOPED_TRACE("End of trajectory sanity");
index cea5e9d021dd1ace8f69b2d42c6a7976c9acf045..fa9823675ab1b7b81dc4f9bc85a582ad71a2a982 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +71,9 @@ EnergyTermsToCompare EnergyComparison::defaultEnergyTermsToCompare()
         { interaction_function[F_EKIN].longname, relativeToleranceAsUlp(10.0, 50) },
         // The pressure is very strongly affected by summation errors,
         // so we need a large tolerance.
-        // The value of 15000 is calibrated for running a small water box for 16 steps.
+        // The value of 17000 is calibrated for running a small water box for 16 steps.
         // For a single frame for a water box a value of 150 could work.
-        { interaction_function[F_PRES].longname, relativeToleranceAsUlp(10.0, 15000) },
+        { interaction_function[F_PRES].longname, relativeToleranceAsUlp(10.0, 17000) },
     };
 };
 
@@ -107,15 +107,15 @@ void EnergyComparison::operator()(const EnergyFrame& reference, const EnergyFram
                  + test.frameName());
     for (auto referenceIt = reference.begin(); referenceIt != reference.end(); ++referenceIt)
     {
-        auto& energyName = referenceIt->first;
+        const auto& energyName = referenceIt->first;
         SCOPED_TRACE("Comparing " + energyName + " between frames");
         auto testIt = test.find(energyName);
         if (testIt != test.end())
         {
-            auto& energyValueInReference = referenceIt->second;
-            auto& energyValueInTest      = testIt->second;
-            EXPECT_REAL_EQ_TOL(energyValueInReference, energyValueInTest,
-                               energyTermsToCompare_.at(energyName));
+            const auto& energyValueInReference = referenceIt->second;
+            const auto& energyValueInTest      = testIt->second;
+            EXPECT_REAL_EQ_TOL(
+                    energyValueInReference, energyValueInTest, energyTermsToCompare_.at(energyName));
         }
         else
         {
@@ -185,8 +185,8 @@ void checkEnergiesAgainstReferenceData(const std::string&          energyFilenam
                                        const EnergyTermsToCompare& energyTermsToCompare,
                                        TestReferenceChecker*       checker)
 {
-    checkEnergiesAgainstReferenceData(energyFilename, energyTermsToCompare, checker,
-                                      MaxNumFrames::compareAllFrames());
+    checkEnergiesAgainstReferenceData(
+            energyFilename, energyTermsToCompare, checker, MaxNumFrames::compareAllFrames());
 }
 
 } // namespace test
index 858051ffa53149874f8853a33aef4bebfa4295ce..6f72f626b08521838795d3f9bef630a84d765f8a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -106,7 +106,7 @@ EnergyFrameReaderPtr openEnergyFileToReadTerms(const std::string&              f
     {
         std::string requiredEnergiesNotFound =
                 "Did not find the following required energies in mdrun output:\n";
-        for (auto& name : namesOfRequiredEnergyTerms)
+        for (const auto& name : namesOfRequiredEnergyTerms)
         {
             auto possibleIndex = indicesOfEnergyTerms.find(name);
             if (possibleIndex == indicesOfEnergyTerms.end())
index 367d0abb427789d551e6928b69bcf9b1fd0bb880..6c5102744dd082a21bb1cdefcabc73b898c5ec67 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 @@ TEST_P(EwaldSurfaceTermTest, WithinTolerances)
         fprintf(stdout,
                 "Test system '%s' cannot run with %d ranks.\n"
                 "The supported numbers are %s 1.\n",
-                simulationName.c_str(), numRanksAvailable, numRanksAvailable == 1 ? ">" : "=");
+                simulationName.c_str(),
+                numRanksAvailable,
+                numRanksAvailable == 1 ? ">" : "=");
         return;
     }
 
@@ -165,7 +167,7 @@ TEST_P(EwaldSurfaceTermTest, WithinTolerances)
             auto frame = reader.frame();
             auto force = frame.f();
             int  atom  = 0;
-            for (auto& f : force)
+            for (const auto& f : force)
             {
                 std::string forceName = frame.frameName() + " F[" + toString(atom) + "]";
 
index 8308c3e00d240f59dd3f1af1ef0ea3cc033ab11a..ef9af92b409784b34ef2755db76c47525bf69873 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -224,7 +224,8 @@ void runTest(TestFileManager*            fileManager,
         fprintf(stdout,
                 "Test system '%s' cannot run with %d ranks.\n"
                 "The supported numbers are: %s\n",
-                simulationName.c_str(), numRanksAvailable,
+                simulationName.c_str(),
+                numRanksAvailable,
                 reportNumbersOfPpRanksSupported(simulationName).c_str());
         return;
     }
@@ -380,14 +381,17 @@ TEST_P(MdrunNoAppendContinuationIsExact, WithinTolerances)
     SCOPED_TRACE(
             formatString("Comparing normal and two-part run of simulation '%s' "
                          "with integrator '%s'",
-                         simulationName.c_str(), integrator.c_str()));
+                         simulationName.c_str(),
+                         integrator.c_str()));
 
-    auto mdpFieldValues = prepareMdpFieldValues(simulationName.c_str(), integrator.c_str(),
-                                                temperatureCoupling.c_str(), pressureCoupling.c_str());
+    auto mdpFieldValues = prepareMdpFieldValues(simulationName.c_str(),
+                                                integrator.c_str(),
+                                                temperatureCoupling.c_str(),
+                                                pressureCoupling.c_str());
     // The exact lambda state choice is unimportant, so long as there
     // is one when using an FEP input.
-    mdpFieldValues["other"] += formatString("\ninit-lambda-state = %d", 3);
-    mdpFieldValues["nsteps"] = "16";
+    mdpFieldValues["init-lambda-state"] = "3";
+    mdpFieldValues["nsteps"]            = "16";
 
     // Forces on GPUs are generally not reproducible enough for a tight
     // tolerance. Similarly, the propagation of sd and bd are not as
@@ -420,20 +424,19 @@ TEST_P(MdrunNoAppendContinuationIsExact, WithinTolerances)
 
     if (pressureCoupling == "parrinello-rahman")
     {
-        energyTermsToCompare.insert(
-                { "Box-Vel-XX", relativeToleranceAsPrecisionDependentUlp(1e-12, ulpToleranceInMixed,
-                                                                         ulpToleranceInDouble) });
-        energyTermsToCompare.insert(
-                { "Box-Vel-YY", relativeToleranceAsPrecisionDependentUlp(1e-12, ulpToleranceInMixed,
-                                                                         ulpToleranceInDouble) });
-        energyTermsToCompare.insert(
-                { "Box-Vel-ZZ", relativeToleranceAsPrecisionDependentUlp(1e-12, ulpToleranceInMixed,
-                                                                         ulpToleranceInDouble) });
+        energyTermsToCompare.insert({ "Box-Vel-XX",
+                                      relativeToleranceAsPrecisionDependentUlp(
+                                              1e-12, ulpToleranceInMixed, ulpToleranceInDouble) });
+        energyTermsToCompare.insert({ "Box-Vel-YY",
+                                      relativeToleranceAsPrecisionDependentUlp(
+                                              1e-12, ulpToleranceInMixed, ulpToleranceInDouble) });
+        energyTermsToCompare.insert({ "Box-Vel-ZZ",
+                                      relativeToleranceAsPrecisionDependentUlp(
+                                              1e-12, ulpToleranceInMixed, ulpToleranceInDouble) });
     }
 
     int numWarningsToTolerate = 1;
-    runTest(&fileManager_, &runner_, simulationName, numWarningsToTolerate, mdpFieldValues,
-            energyTermsToCompare);
+    runTest(&fileManager_, &runner_, simulationName, numWarningsToTolerate, mdpFieldValues, energyTermsToCompare);
 }
 
 // TODO The time for OpenCL kernel compilation means these tests time
index 3159e3db4ed0f877572d2c41e6c98bff198dc7c3..9072e7b98ec93a4f53564a93a08fb383bbfa5c13 100644 (file)
@@ -104,7 +104,8 @@ TEST_P(FreeEnergyReferenceTest, WithinTolerances)
         fprintf(stdout,
                 "The FEP tests cannot run with %d ranks.\n"
                 "The maximum number of ranks supported is %d.",
-                numRanksAvailable, maxNumRanks);
+                numRanksAvailable,
+                maxNumRanks);
         return;
     }
 
@@ -173,18 +174,18 @@ TEST_P(FreeEnergyReferenceTest, WithinTolerances)
     // Check that the trajectories agree with the refdata within tolerance.
     if (testTwoTrajectoryFrames)
     {
-        checkTrajectoryAgainstReferenceData(simulationTrajectoryFileName, trajectoryComparison,
-                                            &rootChecker, MaxNumFrames(2));
+        checkTrajectoryAgainstReferenceData(
+                simulationTrajectoryFileName, trajectoryComparison, &rootChecker, MaxNumFrames(2));
     }
     else if (testOneTrajectoryFrame)
     {
-        checkTrajectoryAgainstReferenceData(simulationTrajectoryFileName, trajectoryComparison,
-                                            &rootChecker, MaxNumFrames(1));
+        checkTrajectoryAgainstReferenceData(
+                simulationTrajectoryFileName, trajectoryComparison, &rootChecker, MaxNumFrames(1));
     }
     else
     {
-        checkTrajectoryAgainstReferenceData(simulationTrajectoryFileName, trajectoryComparison,
-                                            &rootChecker, MaxNumFrames(0));
+        checkTrajectoryAgainstReferenceData(
+                simulationTrajectoryFileName, trajectoryComparison, &rootChecker, MaxNumFrames(0));
     }
     if (File::exists(simulationDhdlFileName, File::returnFalseOnError))
     {
diff --git a/src/programs/mdrun/tests/freezegroups.cpp b/src/programs/mdrun/tests/freezegroups.cpp
new file mode 100644 (file)
index 0000000..9646c1e
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 End-to-end tests checking sanity of results of simulations
+ *        containing freeze groups
+ *
+ * \author Pascal Merz <pascal.merz@me.com>
+ * \ingroup module_mdrun_integration_tests
+ */
+#include "gmxpre.h"
+
+#include "config.h"
+
+#include "gromacs/topology/ifunc.h"
+#include "gromacs/utility/stringutil.h"
+
+#include "testutils/mpitest.h"
+#include "testutils/simulationdatabase.h"
+#include "testutils/testmatchers.h"
+
+#include "moduletest.h"
+#include "simulatorcomparison.h"
+#include "trajectoryreader.h"
+
+namespace gmx::test
+{
+namespace
+{
+/*! \brief Test fixture checking sanity of freeze group results
+ *
+ * This tests the sanity of simulation results containing fully and partially
+ * frozen atoms. For fully frozen atoms, it checks that their reported position
+ * is identical for all steps, and that their velocity is zero. For partially
+ * frozen atoms (for simplicity only in z-direction), it checks that their
+ * position is identical in the frozen dimension for all steps, and that their
+ * velocity is zero in the frozen dimension.
+ */
+using FreezeGroupTestParams = std::tuple<std::string, std::string, std::string>;
+class FreezeGroupTest : public MdrunTestFixture, public ::testing::WithParamInterface<FreezeGroupTestParams>
+{
+public:
+    //! Check that the frozen positions don't change and velocities are zero
+    static void checkFreezeGroups(const std::string&           trajectoryName,
+                                  ArrayRef<const unsigned int> fullyFrozenAtoms,
+                                  ArrayRef<const unsigned int> partiallyFrozenAtomsDimZ,
+                                  const TrajectoryTolerances&  tolerances)
+    {
+        auto [fullyFrozenPositions, fullyFrozenVelocities] =
+                getFrozenPositionsAndVelocities(trajectoryName, fullyFrozenAtoms);
+        auto [partiallyFrozenPositions, partiallyFrozenVelocities] =
+                getFrozenPositionsAndVelocities(trajectoryName, partiallyFrozenAtomsDimZ);
+        GMX_RELEASE_ASSERT(fullyFrozenPositions.size() == fullyFrozenVelocities.size(),
+                           "Position and velocity trajectory don't have the same length.");
+        GMX_RELEASE_ASSERT(partiallyFrozenPositions.size() == partiallyFrozenVelocities.size(),
+                           "Position and velocity trajectory don't have the same length.");
+        GMX_RELEASE_ASSERT(fullyFrozenPositions.size() == partiallyFrozenPositions.size(),
+                           "Fully and partially frozen trajectory don't have the same length.");
+        const auto trajectorySize = fullyFrozenPositions.size();
+
+        for (auto frameIdx = decltype(trajectorySize){ 0 }; frameIdx < trajectorySize; frameIdx++)
+        {
+            SCOPED_TRACE(formatString("Checking frame %lu", frameIdx + 1));
+            if (frameIdx > 0)
+            {
+                checkFullyFrozenPositions(
+                        fullyFrozenPositions[frameIdx], fullyFrozenPositions[frameIdx - 1], tolerances);
+                checkZDimFrozenPositions(partiallyFrozenPositions[frameIdx],
+                                         partiallyFrozenPositions[frameIdx - 1],
+                                         tolerances);
+            }
+            checkFullyFrozenVelocities(fullyFrozenVelocities[frameIdx], tolerances);
+            checkZDimFrozenVelocities(partiallyFrozenVelocities[frameIdx], tolerances);
+        }
+    }
+
+    //! Check that fully frozen frame velocities are zero
+    static void checkFullyFrozenVelocities(ArrayRef<const RVec>        velocities,
+                                           const TrajectoryTolerances& tolerances)
+    {
+        SCOPED_TRACE("Checking fully frozen velocity frame");
+        std::vector<RVec> zeroVelocities(velocities.size(), RVec{ 0, 0, 0 });
+        EXPECT_THAT(zeroVelocities, Pointwise(RVecEq(tolerances.velocities), velocities));
+    }
+    //! Check that z-dimension frozen frame velocities are zero
+    static void checkZDimFrozenVelocities(ArrayRef<const RVec>        velocities,
+                                          const TrajectoryTolerances& tolerances)
+    {
+        SCOPED_TRACE("Checking z-dimension frozen velocity frame");
+        std::vector<real> zVelocities;
+        for (const auto& v : velocities)
+        {
+            zVelocities.emplace_back(v[ZZ]);
+        }
+        std::vector<real> zeroVelocities(zVelocities.size(), 0);
+        EXPECT_THAT(zeroVelocities, Pointwise(RealEq(tolerances.velocities), zVelocities));
+    }
+    //! Check that fully frozen frame positions are static
+    static void checkFullyFrozenPositions(ArrayRef<const RVec>        positions,
+                                          ArrayRef<const RVec>        previousPositions,
+                                          const TrajectoryTolerances& tolerances)
+    {
+        SCOPED_TRACE("Checking fully frozen position frame");
+        EXPECT_THAT(previousPositions, Pointwise(RVecEq(tolerances.coordinates), positions));
+    }
+    //! Check that z-dimension frozen frame positions are zero
+    static void checkZDimFrozenPositions(ArrayRef<const RVec>        positions,
+                                         ArrayRef<const RVec>        previousPositions,
+                                         const TrajectoryTolerances& tolerances)
+    {
+        SCOPED_TRACE("Checking z-dimension frozen position frame");
+        std::vector<real> zPositions;
+        for (const auto& p : positions)
+        {
+            zPositions.emplace_back(p[ZZ]);
+        }
+        std::vector<real> zPrevPositions;
+        for (const auto& p : previousPositions)
+        {
+            zPrevPositions.emplace_back(p[ZZ]);
+        }
+        EXPECT_THAT(zPrevPositions, Pointwise(RealEq(tolerances.coordinates), zPositions));
+    }
+
+    static std::tuple<std::vector<std::vector<RVec>>, std::vector<std::vector<RVec>>>
+    getFrozenPositionsAndVelocities(const std::string& trajectoryName, ArrayRef<const unsigned int> frozenAtoms)
+    {
+        std::vector<std::vector<RVec>> positions;
+        std::vector<std::vector<RVec>> velocities;
+
+        TrajectoryFrameReader trajectoryFrameReader(trajectoryName);
+        while (trajectoryFrameReader.readNextFrame())
+        {
+            const auto frame = trajectoryFrameReader.frame();
+            positions.emplace_back();
+            velocities.emplace_back();
+            for (const auto& index : frozenAtoms)
+            {
+                positions.back().emplace_back(frame.x().at(index));
+                velocities.back().emplace_back(frame.v().at(index));
+            }
+        }
+
+        return { std::move(positions), std::move(velocities) };
+    }
+};
+
+TEST_P(FreezeGroupTest, WithinTolerances)
+{
+    const auto& params         = GetParam();
+    const auto& integrator     = std::get<0>(params);
+    const auto& tcoupling      = std::get<1>(params);
+    const auto& pcoupling      = std::get<2>(params);
+    const auto& simulationName = "alanine_vacuo";
+
+    constexpr std::array<unsigned int, 5>  backbone   = { 4, 6, 8, 14, 16 };
+    constexpr std::array<unsigned int, 13> sideChainH = { 0,  1,  2,  3,  9,  10, 11,
+                                                          12, 13, 18, 19, 20, 21 };
+
+    if (integrator == "md-vv" && pcoupling == "parrinello-rahman")
+    {
+        // Parrinello-Rahman is not implemented in md-vv
+        return;
+    }
+
+    // Prepare mdp input
+    auto mdpFieldValues = prepareMdpFieldValues(simulationName, integrator, tcoupling, pcoupling);
+    mdpFieldValues["nsteps"]      = "8";
+    mdpFieldValues["nstxout"]     = "4";
+    mdpFieldValues["nstvout"]     = "4";
+    mdpFieldValues["freezegrps"]  = "Backbone SideChain";
+    mdpFieldValues["freezedim"]   = "Y Y Y N N Y";
+    mdpFieldValues["constraints"] = "all-bonds";
+
+    // Run grompp
+    runner_.useTopGroAndNdxFromDatabase(simulationName);
+    runner_.useStringAsMdpFile(prepareMdpFileContents(mdpFieldValues));
+    // Allow one warning for COMM removal + partially frozen atoms
+    runGrompp(&runner_, { SimulationOptionTuple("-maxwarn", "1") });
+    // Run mdrun
+    runMdrun(&runner_);
+
+    // Check frozen atoms
+    checkFreezeGroups(runner_.fullPrecisionTrajectoryFileName_,
+                      backbone,
+                      sideChainH,
+                      TrajectoryComparison::s_defaultTrajectoryTolerances);
+}
+
+INSTANTIATE_TEST_CASE_P(FreezeWorks,
+                        FreezeGroupTest,
+                        ::testing::Combine(::testing::Values("md", "md-vv", "sd", "bd"),
+                                           ::testing::Values("no"),
+                                           ::testing::Values("no")));
+} // namespace
+} // namespace gmx::test
index d4ae76ae5b8a2b81e3a7dae94334c8e19a9e24b5..ad18331849d0b5f44e63f01726d3dc70bd38ed3d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +76,7 @@ TEST_P(InitialConstraintsTest, Works)
 {
     const int         nsteps     = 1;
     const float       timestep   = 0.001;
-    auto              integrator = GetParam();
+    const auto*       integrator = GetParam();
     const std::string integratorName(integrator);
     SCOPED_TRACE("Integrating with " + integratorName);
     const std::string theMdpFile = formatString(
@@ -92,7 +92,9 @@ TEST_P(InitialConstraintsTest, Works)
             "integrator              = %s\n"
             "nsteps                  = %d\n"
             "dt                      = %f\n",
-            integratorName.c_str(), nsteps, timestep);
+            integratorName.c_str(),
+            nsteps,
+            timestep);
 
     runner_.useStringAsMdpFile(theMdpFile);
 
index 1a0077c9608907d22d9859a60dda900a64404c46..5a3d920eac27471117955eb841292dc9a8d5120f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@ TEST_P(EnergyMinimizationTest, WithinTolerances)
     auto simulationName = std::get<0>(params);
     auto minimizer      = std::get<1>(params);
     SCOPED_TRACE(formatString("Comparing '%s' energy minimization for simulation '%s'",
-                              minimizer.c_str(), simulationName.c_str()));
+                              minimizer.c_str(),
+                              simulationName.c_str()));
 
     // TODO At some point we should also test PME-only ranks.
     int numRanksAvailable = getNumberOfTestMpiRanks();
@@ -110,7 +111,8 @@ TEST_P(EnergyMinimizationTest, WithinTolerances)
         fprintf(stdout,
                 "Test system '%s' cannot run with %d ranks.\n"
                 "The supported numbers are: %s\n",
-                simulationName.c_str(), numRanksAvailable,
+                simulationName.c_str(),
+                numRanksAvailable,
                 reportNumbersOfPpRanksSupported(simulationName).c_str());
         return;
     }
@@ -168,7 +170,8 @@ std::vector<std::string> unconstrainedSystemsToTest_g = { "argon12",
                                                           "glycine_no_constraints_vacuo" };
 std::vector<std::string> minimizersToTest_g           = { "steep", "cg", "l-bfgs" };
 
-std::vector<std::string> constrainedSystemsToTest_g        = { "tip3p5", "glycine_vacuo",
+std::vector<std::string> constrainedSystemsToTest_g        = { "tip3p5",
+                                                        "glycine_vacuo",
                                                         "alanine_vsite_vacuo" };
 std::vector<std::string> minimizersToTestWithConstraints_g = { "steep", "cg" };
 //! \}
index 9cb67be37eb6557dd2f11eba60dfe178ae68b291..1a15c721a9db9d08296836959a08b0c7d157e9e9 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 +83,11 @@ namespace
 
 #if GMX_OPENMP || defined(DOXYGEN)
 //! Number of OpenMP threads for child mdrun call.
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 int g_numOpenMPThreads = 1;
 #endif
 //! \cond
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 GMX_TEST_OPTIONS(MdrunTestOptions, options)
 {
     GMX_UNUSED_VALUE(options);
@@ -148,7 +150,7 @@ void SimulationRunner::useStringAsMdpFile(const std::string& mdpString)
     mdpInputContents_ = mdpString;
 }
 
-void SimulationRunner::useStringAsNdxFile(const char* ndxString)
+void SimulationRunner::useStringAsNdxFile(const char* ndxString) const
 {
     gmx::TextWriter::writeFileFromString(ndxFileName_, ndxString);
 }
@@ -245,7 +247,7 @@ int SimulationRunner::callGrompp()
     return callGrompp(CommandLine());
 }
 
-int SimulationRunner::changeTprNsteps(int nsteps)
+int SimulationRunner::changeTprNsteps(int nsteps) const
 {
     CommandLine caller;
     caller.append("convert-tpr");
@@ -258,7 +260,7 @@ int SimulationRunner::changeTprNsteps(int nsteps)
     return gmx::test::CommandLineTestHelper::runModuleFactory(&gmx::ConvertTprInfo::create, &caller);
 }
 
-int SimulationRunner::callNmeig()
+int SimulationRunner::callNmeig() const
 {
     /* Conforming to style guide by not passing a non-const reference
        to this function. Passing a non-const reference might make it
@@ -316,8 +318,10 @@ int SimulationRunner::callMdrun(const CommandLine& callerRef)
     caller.addOption("-ntomp", g_numOpenMPThreads);
 #endif
 
-    return gmx_mdrun(MdrunTestFixtureBase::communicator_, *MdrunTestFixtureBase::hwinfo_,
-                     caller.argc(), caller.argv());
+    return gmx_mdrun(MdrunTestFixtureBase::communicator_,
+                     *MdrunTestFixtureBase::hwinfo_,
+                     caller.argc(),
+                     caller.argv());
 }
 
 int SimulationRunner::callMdrun()
@@ -328,8 +332,10 @@ int SimulationRunner::callMdrun()
 // ====
 
 // static
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 MPI_Comm MdrunTestFixtureBase::communicator_ = MPI_COMM_NULL;
 // static
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
 std::unique_ptr<gmx_hw_info_t> MdrunTestFixtureBase::hwinfo_;
 
 // static
index d29ebe15d30ef32b7efd9f430a36831ebafa5443..72261b69fe5d0cec23e2186aae32545735d53962 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <gtest/gtest.h>
 
+#include <memory>
+
 #include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/gmxmpi.h"
 
@@ -116,7 +118,7 @@ public:
     //! Use a given string as input to grompp
     void useStringAsMdpFile(const std::string& mdpString);
     //! Use a string as -n input to grompp
-    void useStringAsNdxFile(const char* ndxString);
+    void useStringAsNdxFile(const char* ndxString) const;
     //! Use a standard .top and .g96 file as input to grompp
     void useTopG96AndNdxFromDatabase(const std::string& name);
     //! Use a standard .top and .gro file as input to grompp
@@ -134,14 +136,14 @@ public:
     //! Convenience wrapper for a default call to \c callGromppOnThisRank
     int callGromppOnThisRank();
     //! Calls nmeig for testing
-    int callNmeig();
+    int callNmeig() const;
     //! Calls mdrun for testing with a customized command line
     int callMdrun(const CommandLine& callerRef);
     /*! \brief Convenience wrapper for calling mdrun for testing
      * with default command line */
     int callMdrun();
     //! Calls convert-tpr on this rank to set a new number of steps in the tpr.
-    int changeTprNsteps(int nsteps);
+    int changeTprNsteps(int nsteps) const;
 
     //@{
     /*! \name Names for frequently used grompp and mdrun output files
@@ -206,11 +208,13 @@ public:
     ~MdrunTestFixtureBase() override;
 
     //! Communicator over which the test fixture works
+    // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
     static MPI_Comm communicator_;
     /*! \brief Hardware information object
      *
      * Detected within \c communicator_ and available to re-use
      * over all tests in the test case of this text fixture. */
+    // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
     static std::unique_ptr<gmx_hw_info_t> hwinfo_;
 };
 
index a3022f3d43e2b92e81ca90f04f0870ad45a8fb86..6851b7bdc19f8aaabf4d13094d6c03208b6e9e02 100644 (file)
@@ -87,8 +87,8 @@ TEST_P(MtsComparisonTest, WithinTolerances)
     auto mtsScheme      = std::get<1>(params);
 
     // Note that there should be no relevant limitation on MPI ranks and OpenMP threads
-    SCOPED_TRACE(formatString("Comparing for '%s' no MTS with MTS scheme '%s'",
-                              simulationName.c_str(), mtsScheme.c_str()));
+    SCOPED_TRACE(formatString(
+            "Comparing for '%s' no MTS with MTS scheme '%s'", simulationName.c_str(), mtsScheme.c_str()));
 
     const bool isPullTest = (mtsScheme.find("pull") != std::string::npos);
 
@@ -104,7 +104,8 @@ TEST_P(MtsComparisonTest, WithinTolerances)
             "rcoulomb     = 0.9\n"
             "rvdw         = 0.9\n"
             "constraints  = h-bonds\n",
-            numSteps, isPullTest ? "reaction-field" : "PME");
+            numSteps,
+            isPullTest ? "reaction-field" : "PME");
 
     if (isPullTest)
     {
@@ -131,7 +132,9 @@ TEST_P(MtsComparisonTest, WithinTolerances)
                                    "nstxout   = 0\n"
                                    "nstvout   = 0\n"
                                    "nstfout   = %d\n",
-                                   numSteps, numSteps, nstfout);
+                                   numSteps,
+                                   numSteps,
+                                   nstfout);
 
     auto mtsMdpOptions = sharedMdpOptions
                          + gmx::formatString(
@@ -144,7 +147,10 @@ TEST_P(MtsComparisonTest, WithinTolerances)
                                    "nstxout    = 0\n"
                                    "nstvout    = 0\n"
                                    "nstfout    = %d\n",
-                                   mtsScheme.c_str(), numSteps, numSteps, nstfout);
+                                   mtsScheme.c_str(),
+                                   numSteps,
+                                   numSteps,
+                                   nstfout);
 
     // At step 0 the energy and virial should only differ due to rounding errors
     EnergyTermsToCompare energyTermsToCompareStep0 = energyTermsToCompare(0.001, 0.01);
@@ -190,12 +196,14 @@ TEST_P(MtsComparisonTest, WithinTolerances)
     runMdrun(&runner_);
 
     // Compare simulation results at step 0, which should be indentical
-    compareEnergies(simulator1EdrFileName, simulator2EdrFileName, energyTermsToCompareStep0,
-                    MaxNumFrames(1));
+    compareEnergies(
+            simulator1EdrFileName, simulator2EdrFileName, energyTermsToCompareStep0, MaxNumFrames(1));
     compareTrajectories(simulator1TrajectoryFileName, simulator2TrajectoryFileName, trajectoryComparison);
 
     // Compare energies at the last step (and step 0 again) with lower tolerance
-    compareEnergies(simulator1EdrFileName, simulator2EdrFileName, energyTermsToCompareAllSteps,
+    compareEnergies(simulator1EdrFileName,
+                    simulator2EdrFileName,
+                    energyTermsToCompareAllSteps,
                     MaxNumFrames::compareAllFrames());
 }
 
index 8d5673ff1df26e041d4f0679475274aa51e15dc1..469711e65727297a1dc85a2e2dc0cfb46b1a384c 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
 
 #include <gtest/gtest.h>
 
+#include "gromacs/mdtypes/md_enums.h"
+
 #include "multisimtest.h"
 
 namespace gmx
@@ -66,11 +68,7 @@ namespace test
  * that it is disabled. There's no elegant way to conditionally
  * disable a test at run time, so currently there is no feedback if
  * only one rank is available. However, the test harness knows to run
- * this test with more than one rank.
- *
- * Strictly, this test does not need to be parameterized, but
- * conditionally disabling it with respect to GMX_LIB_MPI is easier if
- * it is parameterized. */
+ * this test with more than one rank. */
 TEST_P(MultiSimTest, ExitsNormally)
 {
     runExitsNormallyTest();
@@ -78,21 +76,17 @@ TEST_P(MultiSimTest, ExitsNormally)
 
 TEST_P(MultiSimTest, ExitsNormallyWithDifferentNumbersOfStepsPerSimulation)
 {
-    if (size_ <= 1)
+    if (!mpiSetupValid())
     {
-        /* Can't test multi-sim without multiple ranks. */
+        // MPI setup is not suitable for multi-sim
         return;
     }
     SimulationRunner runner(&fileManager_);
     runner.useTopGroAndNdxFromDatabase("spc2");
 
-    const char* pcoupl = GetParam();
     // Do some different small numbers of steps in each simulation
-    int numSteps = rank_ % 4;
-    organizeMdpFile(&runner, pcoupl, numSteps);
-    /* Call grompp on every rank - the standard callGrompp() only runs
-       grompp on rank 0. */
-    EXPECT_EQ(0, runner.callGromppOnThisRank());
+    int numSteps = simulationNumber_ % 4;
+    runGrompp(&runner, numSteps);
 
     ASSERT_EQ(0, runner.callMdrun(*mdrunCaller_));
 }
@@ -100,19 +94,39 @@ TEST_P(MultiSimTest, ExitsNormallyWithDifferentNumbersOfStepsPerSimulation)
 /* Note, not all preprocessor implementations nest macro expansions
    the same way / at all, if we would try to duplicate less code. */
 #if GMX_LIB_MPI
-INSTANTIATE_TEST_CASE_P(InNvt, MultiSimTest, ::testing::Values("pcoupl = no"));
+INSTANTIATE_TEST_CASE_P(InNvt,
+                        MultiSimTest,
+                        ::testing::Combine(::testing::Values(NumRanksPerSimulation(1),
+                                                             NumRanksPerSimulation(2)),
+                                           ::testing::Values(IntegrationAlgorithm::MD),
+                                           ::testing::Values(TemperatureCoupling::VRescale),
+                                           ::testing::Values(PressureCoupling::No)));
 #else
 // Test needs real MPI to run
-INSTANTIATE_TEST_CASE_P(DISABLED_InNvt, MultiSimTest, ::testing::Values("pcoupl = no"));
+INSTANTIATE_TEST_CASE_P(DISABLED_InNvt,
+                        MultiSimTest,
+                        ::testing::Combine(::testing::Values(NumRanksPerSimulation(1),
+                                                             NumRanksPerSimulation(2)),
+                                           ::testing::Values(IntegrationAlgorithm::MD),
+                                           ::testing::Values(TemperatureCoupling::VRescale),
+                                           ::testing::Values(PressureCoupling::No)));
 #endif
 
 //! Convenience typedef
 typedef MultiSimTest MultiSimTerminationTest;
 
-TEST_F(MultiSimTerminationTest, WritesCheckpointAfterMaxhTerminationAndThenRestarts)
+TEST_P(MultiSimTerminationTest, WritesCheckpointAfterMaxhTerminationAndThenRestarts)
 {
     runMaxhTest();
 }
 
+INSTANTIATE_TEST_CASE_P(InNvt,
+                        MultiSimTerminationTest,
+                        ::testing::Combine(::testing::Values(NumRanksPerSimulation(1),
+                                                             NumRanksPerSimulation(2)),
+                                           ::testing::Values(IntegrationAlgorithm::MD),
+                                           ::testing::Values(TemperatureCoupling::VRescale),
+                                           ::testing::Values(PressureCoupling::No)));
+
 } // namespace test
 } // namespace gmx
index b53756599b8a77727bcdf203a7a70764b9e5cb11..26e5de90b52d421e1d730c1b906a3c69433b7d4d 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,9 @@
 
 #include <gtest/gtest.h>
 
+#include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/path.h"
 #include "gromacs/utility/real.h"
 #include "gromacs/utility/stringutil.h"
@@ -70,9 +72,14 @@ namespace test
 MultiSimTest::MultiSimTest() :
     size_(gmx_node_num()),
     rank_(gmx_node_rank()),
+    numRanksPerSimulation_(std::get<0>(GetParam())),
+    simulationNumber_(rank_ / numRanksPerSimulation_),
     mdrunCaller_(new CommandLine)
 
 {
+    // Zero or less ranks doesn't make sense
+    GMX_RELEASE_ASSERT(numRanksPerSimulation_ > 0, "Invalid number of ranks per simulation.");
+
     const char* directoryNameFormat = "sim_%d";
 
     // Modify the file manager to have a temporary directory unique to
@@ -81,74 +88,144 @@ MultiSimTest::MultiSimTest() :
     // constructed it.
     std::string originalTempDirectory = fileManager_.getOutputTempDirectory();
     std::string newTempDirectory =
-            Path::join(originalTempDirectory, formatString(directoryNameFormat, rank_));
-    Directory::create(newTempDirectory);
+            Path::join(originalTempDirectory, formatString(directoryNameFormat, simulationNumber_));
+    if (rank_ % numRanksPerSimulation_ == 0)
+    {
+        // Only one rank per simulation creates directory
+        Directory::create(newTempDirectory);
+    }
+#if GMX_LIB_MPI
+    // Make sure directories got created.
+    MPI_Barrier(MdrunTestFixtureBase::communicator_);
+#endif
     fileManager_.setOutputTempDirectory(newTempDirectory);
 
     mdrunCaller_->append("mdrun");
     mdrunCaller_->addOption("-multidir");
-    for (int i = 0; i != size_; ++i)
+    for (int i = 0; i < size_ / numRanksPerSimulation_; ++i)
     {
         mdrunCaller_->append(Path::join(originalTempDirectory, formatString(directoryNameFormat, i)));
     }
 }
 
-void MultiSimTest::organizeMdpFile(SimulationRunner* runner, const char* controlVariable, int numSteps)
+bool MultiSimTest::mpiSetupValid() const
+{
+    // Single simulation case is not implemented in multi-sim
+    const bool haveAtLeastTwoSimulations = ((size_ / numRanksPerSimulation_) >= 2);
+    // Mdrun will throw error if simulations don't have identical number of ranks
+    const bool simulationsHaveIdenticalRankNumber = ((size_ % numRanksPerSimulation_) == 0);
+
+    return (haveAtLeastTwoSimulations && simulationsHaveIdenticalRankNumber);
+}
+
+void MultiSimTest::organizeMdpFile(SimulationRunner*    runner,
+                                   IntegrationAlgorithm integrator,
+                                   TemperatureCoupling  tcoupl,
+                                   PressureCoupling     pcoupl,
+                                   int                  numSteps,
+                                   bool                 doRegression) const
 {
+    GMX_RELEASE_ASSERT(mpiSetupValid(), "Creating the mdp file without valid MPI setup is useless.");
     const real  baseTemperature = 298;
     const real  basePressure    = 1;
     std::string mdpFileContents = formatString(
+            "integrator = %s\n"
+            "tcoupl = %s\n"
+            "pcoupl = %s\n"
             "nsteps = %d\n"
             "nstlog = 1\n"
             "nstcalcenergy = 1\n"
-            "tcoupl = v-rescale\n"
             "tc-grps = System\n"
             "tau-t = 1\n"
             "ref-t = %f\n"
             // pressure coupling (if active)
-            "tau-p = 1\n"
+            "tau-p = 2\n"
             "ref-p = %f\n"
             "compressibility = 4.5e-5\n"
             // velocity generation
             "gen-vel = yes\n"
             "gen-temp = %f\n"
-            // control variable specification
-            "%s\n",
-            numSteps, baseTemperature + 0.0001 * rank_, basePressure * std::pow(1.01, rank_),
+            "gen-seed = %d\n"
+            // v-rescale and c-rescale use ld-seed
+            "ld-seed = %d\n"
+            // Two systems are used: spc2    non-interacting also at cutoff 1nm
+            //                       tip3p5  has box length of 1.86
+            "rcoulomb = 0.7\n"
+            "rvdw = 0.7\n"
+            // Trajectory output if required
+            "nstxout = %d\n"
+            "nstvout = %d\n"
+            "nstfout = %d\n"
+            "nstenergy = %d\n",
+            enumValueToString(integrator),
+            enumValueToString(tcoupl),
+            enumValueToString(pcoupl),
+            numSteps,
+            baseTemperature + 0.0001 * rank_,
+            basePressure * std::pow(1.01, rank_),
             /* Set things up so that the initial KE decreases with
                increasing replica number, so that the (identical)
                starting PE decreases on the first step more for the
                replicas with higher number, which will tend to force
                replica exchange to occur. */
-            std::max(baseTemperature - 10 * rank_, real(0)), controlVariable);
+            std::max(baseTemperature - 10 * rank_, real(0)),
+            // If we do regression, we need reproducible velocity
+            // generation, which can be different per simulation
+            (doRegression ? 671324 + simulationNumber_ : -1),
+            // If we do regression, we need reproducible temperature and
+            // pressure coupling, which can be different per simulation
+            (doRegression ? 51203 + simulationNumber_ : -1),
+            // If we do regression, write one intermediate point
+            (doRegression ? int(numSteps / 2) : 0),
+            (doRegression ? int(numSteps / 2) : 0),
+            (doRegression ? int(numSteps / 2) : 0),
+            // If we do regression, print energies every step so
+            // we're sure to catch the replica exchange steps
+            (doRegression ? 1 : 1000));
     runner->useStringAsMdpFile(mdpFileContents);
 }
 
+void MultiSimTest::runGrompp(SimulationRunner* runner, int numSteps, bool doRegression, int maxWarnings) const
+{
+    // Call grompp once per simulation
+    if (rank_ % numRanksPerSimulation_ == 0)
+    {
+        const auto& simulator = std::get<1>(GetParam());
+        const auto& tcoupl    = std::get<2>(GetParam());
+        const auto& pcoupl    = std::get<3>(GetParam());
+        organizeMdpFile(runner, simulator, tcoupl, pcoupl, numSteps, doRegression);
+        CommandLine caller;
+        caller.addOption("-maxwarn", maxWarnings);
+        EXPECT_EQ(0, runner->callGromppOnThisRank(caller));
+    }
+
+#if GMX_LIB_MPI
+    // Make sure simulation masters have written the .tpr file before other ranks try to read it.
+    MPI_Barrier(MdrunTestFixtureBase::communicator_);
+#endif
+}
+
 void MultiSimTest::runExitsNormallyTest()
 {
-    if (size_ <= 1)
+    if (!mpiSetupValid())
     {
-        /* Can't test multi-sim without multiple ranks. */
+        // Can't test multi-sim without multiple simulations
         return;
     }
 
     SimulationRunner runner(&fileManager_);
     runner.useTopGroAndNdxFromDatabase("spc2");
 
-    const char* pcoupl = GetParam();
-    organizeMdpFile(&runner, pcoupl);
-    /* Call grompp on every rank - the standard callGrompp() only runs
-       grompp on rank 0. */
-    EXPECT_EQ(0, runner.callGromppOnThisRank());
+    runGrompp(&runner);
 
     ASSERT_EQ(0, runner.callMdrun(*mdrunCaller_));
 }
 
 void MultiSimTest::runMaxhTest()
 {
-    if (size_ <= 1)
+    if (!mpiSetupValid())
     {
-        /* Can't test replica exchange without multiple ranks. */
+        // Can't test multi-sim without multiple simulations
         return;
     }
 
@@ -158,10 +235,7 @@ void MultiSimTest::runMaxhTest()
     TerminationHelper helper(&fileManager_, mdrunCaller_.get(), &runner);
     // Make sure -maxh has a chance to propagate
     int numSteps = 100;
-    organizeMdpFile(&runner, "pcoupl = no", numSteps);
-    /* Call grompp on every rank - the standard callGrompp() only runs
-       grompp on rank 0. */
-    EXPECT_EQ(0, runner.callGromppOnThisRank());
+    runGrompp(&runner, numSteps);
 
     helper.runFirstMdrun(runner.cptFileName_);
     helper.runSecondMdrun();
index 81c975c4ea1a6a6bda4d76b1df9b6fc6c815b680..a2c3b65fb75d8309d596b25b0884fe25f8fd2060 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "moduletest.h"
 
+enum class IntegrationAlgorithm : int;
+enum class PressureCoupling : int;
+enum class TemperatureCoupling : int;
+
 namespace gmx
 {
 namespace test
@@ -61,6 +65,25 @@ namespace test
 //! Convenience typedef
 typedef std::unique_ptr<CommandLine> CommandLinePointer;
 
+/*! \internal
+ * \brief Test flag setting the number of ranks per simulation
+ */
+class NumRanksPerSimulation final
+{
+public:
+    //! Explicit constructor
+    explicit NumRanksPerSimulation(int value) : value_(value) {}
+    //! Implicit conversion to int
+    operator int() const { return value_; }
+
+private:
+    //! Internal state
+    int value_;
+};
+
+//! The parameters of the MultiSimTest class
+typedef std::tuple<NumRanksPerSimulation, IntegrationAlgorithm, TemperatureCoupling, PressureCoupling> MultiSimTestParams;
+
 /*! \internal
  * \brief Test fixture for multi-sim functionality.
  *
@@ -69,11 +92,17 @@ typedef std::unique_ptr<CommandLine> CommandLinePointer;
  *
  * \ingroup module_mdrun_integration_tests
  */
-class MultiSimTest : public MdrunTestFixtureBase, public ::testing::WithParamInterface<const char*>
+class MultiSimTest : public MdrunTestFixtureBase, public ::testing::WithParamInterface<MultiSimTestParams>
 {
 public:
     MultiSimTest();
 
+    /*! \brief Check whether the MPI setup is valid
+     *
+     * Excludes MPI setups which are not supported by multi-sim
+     */
+    bool mpiSetupValid() const;
+
     /*! \brief Organize the .mdp file for this rank
      *
      * For testing multi-simulation, this .mdp file is more
@@ -81,15 +110,39 @@ public:
      * and doing it this way allows this function to be re-used
      * for testing replica-exchange.
      *
-     * \param runner          The simulation runner that uses the
-     *                        mdp file that is organized.
-     * \param controlVariable Allows parameterization to work with
+     * The mdp options, specifically the temperature and pressure
+     * coupling, allow parameterization to work with
      * T, P or (later) lambda as the control variable, by passing a
-     * string with "mdp-param = value" such that different paths
-     * in init_replica_exchange() are followed.
-     * \param numSteps        Number of MD steps to perform.
+     * string with a value for the respective mdp option such that
+     * different paths in init_replica_exchange() are followed.
+     *
+     * \param runner      The simulation runner that uses the
+     *                    mdp file that is organized.
+     * \param integrator  Value for the mdp option `integrator`
+     * \param tcoupl      Value for the mdp option `tcoupl`
+     * \param pcoupl      Value for the mdp option `pcoupl`
+     * \param numSteps    Number of MD steps to perform.
+     * \param doRegression  Whether the mdp file will be used for
+     *                      regression tests, request use of
+     *                      reproducible parameters
+     */
+    void organizeMdpFile(SimulationRunner*    runner,
+                         IntegrationAlgorithm integrator,
+                         TemperatureCoupling  tcoupl,
+                         PressureCoupling     pcoupl,
+                         int                  numSteps,
+                         bool                 doRegression) const;
+
+    /*! \brief Run grompp on the ranks that need to run it
+     *
+     * Adds an MPI barrier to ensure that all ranks have written before returning
+     *
+     * \param runner        The simulation runner to run grompp on
+     * \param numSteps      Number of MD steps to perform
+     * \param doRegression  Whether to write trajectories during the simulation
+     * \param maxWarnings   Number of grompp warning tolerated
      */
-    void organizeMdpFile(SimulationRunner* runner, const char* controlVariable, int numSteps = 2);
+    void runGrompp(SimulationRunner* runner, int numSteps = 2, bool doRegression = false, int maxWarnings = 0) const;
     //! Test that a basic simulation works
     void runExitsNormallyTest();
     //! Test that mdrun -maxh and restart works
@@ -98,6 +151,10 @@ public:
     int size_;
     //! MPI rank of this process
     int rank_;
+    //! Number of ranks per simulation
+    int numRanksPerSimulation_;
+    //! The simulation this rank belongs to (equal to `int( rank_ / numRanksPerSimulation_)`)
+    int simulationNumber_;
     //! Object for building the mdrun command line
     CommandLinePointer mdrunCaller_;
     //! Manages temporary files during the test.
index ea92e2c80b744e9f1b1063488df1cdd5dafde456..1bbb0023a4b06c8679427b975370c046dd26cc49 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +63,9 @@ TEST(NonbondedBenchTest, BasicEndToEndTest)
     const char* const command[] = { "nonbonded-benchmark" };
     CommandLine       cmdline(command);
     cmdline.addOption("-iter", 1);
-    EXPECT_EQ(0, gmx::test::CommandLineTestHelper::runModuleFactory(
-                         &gmx::NonbondedBenchmarkInfo::create, &cmdline));
+    EXPECT_EQ(0,
+              gmx::test::CommandLineTestHelper::runModuleFactory(
+                      &gmx::NonbondedBenchmarkInfo::create, &cmdline));
 }
 
 } // namespace
index 23bf340824dbda264493d6d7f1d59c4a8a212ebc..3ef84e572a6e9430256f733eae0086eb3d38343d 100644 (file)
@@ -102,7 +102,8 @@ TEST_P(NormalModesTest, WithinTolerances)
         fprintf(stdout,
                 "Test system '%s' cannot run with %d ranks.\n"
                 "The supported numbers are: %s\n",
-                simulationName.c_str(), numRanksAvailable,
+                simulationName.c_str(),
+                numRanksAvailable,
                 reportNumbersOfPpRanksSupported(simulationName).c_str());
         return;
     }
@@ -151,7 +152,10 @@ TEST_P(NormalModesTest, WithinTolerances)
 
 //! Containers of systems and integrators to test.
 //! \{
-std::vector<std::string> systemsToTest_g     = { "scaled-water", "villin", "spc-dimer", "one-tip5p",
+std::vector<std::string> systemsToTest_g     = { "scaled-water",
+                                             "villin",
+                                             "spc-dimer",
+                                             "one-tip5p",
                                              "sw-dimer" };
 std::vector<std::string> integratorsToTest_g = { "nm" };
 
index 9414b16c9f2e2659a8b53e2728627c363f1c0668..e8fddc65e6a85ec0cd391a4a2a049c495fd4fca9 100644 (file)
@@ -81,7 +81,8 @@ TEST_P(OutputFiles, FilesArePresent)
     SCOPED_TRACE(
             formatString("Checking for presence of expected output files using "
                          "simulation '%s' with integrator '%s'",
-                         simulationName.c_str(), integrator.c_str()));
+                         simulationName.c_str(),
+                         integrator.c_str()));
 
     // Prepare the .tpr file
     {
@@ -98,8 +99,10 @@ TEST_P(OutputFiles, FilesArePresent)
     }
     // Check if expected files are present
     {
-        for (const auto& file : { runner_.fullPrecisionTrajectoryFileName_, runner_.logFileName_,
-                                  runner_.edrFileName_, fileManager_.getTemporaryFilePath("state.gro"),
+        for (const auto& file : { runner_.fullPrecisionTrajectoryFileName_,
+                                  runner_.logFileName_,
+                                  runner_.edrFileName_,
+                                  fileManager_.getTemporaryFilePath("state.gro"),
                                   fileManager_.getTemporaryFilePath("state.cpt") })
         {
             EXPECT_TRUE(File::exists(file, File::returnFalseOnError))
index 6dc8f02e42893306476c85f3410e3f5058363c83..cbf98ae5776b86d136ad5e5f22a9b31eb4e5bf1c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -117,12 +117,31 @@ void PeriodicActionsTest::doMdrun(const PeriodicOutputParameters& output)
     auto propagation = std::get<0>(GetParam());
     SCOPED_TRACE(
             formatString("Doing %s simulation with %s integrator, %s tcoupling and %s pcoupling\n",
-                         propagation["simulationName"].c_str(), propagation["integrator"].c_str(),
-                         propagation["tcoupl"].c_str(), propagation["pcoupl"].c_str()));
-    auto mdpFieldValues = prepareMdpFieldValues(propagation["simulationName"], propagation["integrator"],
-                                                propagation["tcoupl"], propagation["pcoupl"]);
-    mdpFieldValues.insert(propagation.begin(), propagation.end());
-    mdpFieldValues.insert(output.begin(), output.end());
+                         propagation["simulationName"].c_str(),
+                         propagation["integrator"].c_str(),
+                         propagation["tcoupl"].c_str(),
+                         propagation["pcoupl"].c_str()));
+    auto mdpFieldValues = prepareMdpFieldValues(propagation["simulationName"],
+                                                propagation["integrator"],
+                                                propagation["tcoupl"],
+                                                propagation["pcoupl"]);
+
+    // This lambda writes all mdp options in `source` into `target`, overwriting options already
+    // present in `target`. It also filters out non-mdp option entries in the source maps
+    auto overWriteMdpMapValues = [](const MdpFieldValues& source, MdpFieldValues& target) {
+        for (auto const& [key, value] : source)
+        {
+            if (key == "simulationName" || key == "maxGromppWarningsTolerated" || key == "description")
+            {
+                // Remove non-mdp entries used in propagation and output
+                continue;
+            }
+            target[key] = value;
+        }
+    };
+    // Add options in propagation and output to the mdp options
+    overWriteMdpMapValues(propagation, mdpFieldValues);
+    overWriteMdpMapValues(output, mdpFieldValues);
 
     // prepare the tpr file
     {
@@ -205,7 +224,8 @@ TEST_P(PeriodicActionsTest, PeriodicActionsAgreeWithReference)
 {
     auto propagation = std::get<0>(GetParam());
     SCOPED_TRACE(formatString("Comparing two simulations of '%s' with integrator '%s'",
-                              propagation["simulationName"].c_str(), propagation["integrator"].c_str()));
+                              propagation["simulationName"].c_str(),
+                              propagation["integrator"].c_str()));
 
     prepareReferenceData();
 
@@ -233,7 +253,8 @@ TEST_P(PeriodicActionsTest, PeriodicActionsAgreeWithReference)
                              + "' and test '" + runner_.edrFileName_ + "'");
                 shouldContinueComparing = shouldContinueComparing
                                           && compareFrames(referenceEnergyFrameReader.get(),
-                                                           testEnergyFrameReader.get(), energyComparison_);
+                                                           testEnergyFrameReader.get(),
+                                                           energyComparison_);
             }
         }
     }
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_Crescale_4Ranks_1RanksPerSimulation_d.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_Crescale_4Ranks_1RanksPerSimulation_d.xml
new file mode 100644 (file)
index 0000000..cb11b56
--- /dev/null
@@ -0,0 +1,3398 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4533416426810541</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4533416426810541</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4533416426810541</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4533416426810541</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4529787145135691</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4529787145135691</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4529787145135691</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4529787145135691</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4529787145135691</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4529787145135691</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4538482476891659</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4538482476891659</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4485400874407262</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4485400874407262</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4485400874407262</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4485400874407262</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">19.965980763101982</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">19.968485132887469</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">19.980889243241368</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">19.980062319948967</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">19.980759213091023</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">18.429619737373255</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">18.429666577937656</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">18.429628484425088</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">18.429466554446545</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">18.42914135205238</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">18.457960883235415</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">18.432617343609081</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">18.455104038215758</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">25.687447409539949</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">25.688971889495477</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">25.692177323493887</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">25.693600736326573</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629305410083006</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">30.132005765759398</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.780900844935932</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">31.56590609570474</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">32.509043001832204</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">28.7000619992506</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.231974496546229</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.910877587883714</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">30.734095787927252</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">31.697160785211185</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">32.740618503665885</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">33.875524420251239</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">35.120031524726095</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">38.703296133174902</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">39.409137892031552</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">40.192135457052792</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">41.052095456233836</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.160837447757904</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.797328416580539</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.583160590641745</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.525600603627154</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.261702031814018</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.793567688545245</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.472508873395299</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.295889003417377</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.259279203095479</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.273541390747736</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.390143426302821</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.612163836171</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-13.075490560147948</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-13.779807839049072</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-14.559599970071902</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-15.41813655642026</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13823960248430167</Real>
+        <Real Name="Y">-0.083001582473174879</Real>
+        <Real Name="Z">-0.55156788526044775</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807346912896781</Real>
+        <Real Name="Y">0.12594239723743811</Real>
+        <Real Name="Z">0.08634003909985162</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50558175484200552</Real>
+        <Real Name="Y">-0.26347201049012287</Real>
+        <Real Name="Z">-0.37043107548326104</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.08034197360884994</Real>
+        <Real Name="Y">-0.036383374851252738</Real>
+        <Real Name="Z">0.26950251001929981</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0879938107726246</Real>
+        <Real Name="Y">-2.69925195488055</Real>
+        <Real Name="Z">-0.41161299800761308</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.005339856872981</Real>
+        <Real Name="Y">-0.44613327229712957</Real>
+        <Real Name="Z">1.1534368241800748</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046991365082634871</Real>
+        <Real Name="Y">-0.027139438957271687</Real>
+        <Real Name="Z">-0.68356956696424598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.05202773043970705</Real>
+        <Real Name="Y">-0.42394701288611158</Real>
+        <Real Name="Z">-0.38240890291446672</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25145271172169875</Real>
+        <Real Name="Y">0.072329295992862669</Real>
+        <Real Name="Z">-0.58384125172376966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20047275659675193</Real>
+        <Real Name="Y">0.39459474035999631</Real>
+        <Real Name="Z">0.71751226731035578</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21660158751017167</Real>
+        <Real Name="Y">1.2107968994948017</Real>
+        <Real Name="Z">0.86109126390401169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3771064228719012</Real>
+        <Real Name="Y">-0.66102181650660441</Real>
+        <Real Name="Z">0.8707144786748191</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2170122537672452</Real>
+        <Real Name="Y">-0.090547598182205036</Real>
+        <Real Name="Z">-0.034702681691129153</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639425064678223</Real>
+        <Real Name="Y">0.96363069485778263</Real>
+        <Real Name="Z">2.5346418773966413</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37424921124686311</Real>
+        <Real Name="Y">-0.37914050295285712</Real>
+        <Real Name="Z">0.73119277083077761</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617444914505814</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617444914505814</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617444914505814</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0031761267753968774</Real>
+        <Real Name="Y">0.59425504313414379</Real>
+        <Real Name="Z">0.24342828400930591</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8498157156612176</Real>
+        <Real Name="Y">0.68430565003069943</Real>
+        <Real Name="Z">0.27215194178596758</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059038613641020143</Real>
+        <Real Name="Y">0.60276012017084213</Real>
+        <Real Name="Z">0.16616662064520543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97835485659759824</Real>
+        <Real Name="Y">0.62989841749740993</Real>
+        <Real Name="Z">1.5700938337892012</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96144248096515206</Real>
+        <Real Name="Y">0.62383071836932336</Real>
+        <Real Name="Z">1.6641123052602775</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92768416140140708</Real>
+        <Real Name="Y">0.705887504571727</Real>
+        <Real Name="Z">1.5414502010945501</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3930815927415581</Real>
+        <Real Name="Y">0.44726907000316501</Real>
+        <Real Name="Z">1.1771271676160293</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3332013081520897</Real>
+        <Real Name="Y">0.47707081687332198</Real>
+        <Real Name="Z">1.2455999782854557</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3358212475907298</Real>
+        <Real Name="Y">0.41474199105907633</Real>
+        <Real Name="Z">1.1076609138767295</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6467736416771961</Real>
+        <Real Name="Y">0.31556285923337235</Real>
+        <Real Name="Z">0.29905936741996053</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7053334092282337</Real>
+        <Real Name="Y">0.33254000968506736</Real>
+        <Real Name="Z">0.22527015149440335</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5972080919748153</Real>
+        <Real Name="Y">0.2379342963225512</Real>
+        <Real Name="Z">0.27299443114340227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7762452711530787</Real>
+        <Real Name="Y">0.39589154098291363</Real>
+        <Real Name="Z">0.022766902561325873</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7118634083169866</Real>
+        <Real Name="Y">0.40977477038104021</Real>
+        <Real Name="Z">1.8150524127407046</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8063987112116382</Real>
+        <Real Name="Y">0.48385513526648399</Real>
+        <Real Name="Z">0.045471407254226166</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.23480924730077335</Real>
+        <Real Name="Y">-0.68793957299550323</Real>
+        <Real Name="Z">-0.13560084254658489</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.59074250403618145</Real>
+        <Real Name="Y">-0.79459532699617386</Real>
+        <Real Name="Z">0.65587090006149706</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6602615754818724</Real>
+        <Real Name="Y">-0.5931747050836802</Real>
+        <Real Name="Z">1.2100067985353338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43880588181024971</Real>
+        <Real Name="Y">-0.11980811906346578</Real>
+        <Real Name="Z">0.15843184271609073</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.419348607996338</Real>
+        <Real Name="Y">1.0234076072809875</Real>
+        <Real Name="Z">0.42102574031429096</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5176578014167659</Real>
+        <Real Name="Y">0.58948060629524002</Real>
+        <Real Name="Z">0.10246666133977728</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.47860244868197371</Real>
+        <Real Name="Y">0.038667111531531385</Real>
+        <Real Name="Z">0.39970661498333321</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.51593671710320621</Real>
+        <Real Name="Y">0.091367501593111522</Real>
+        <Real Name="Z">1.2591423775789108</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.4941192655046394</Real>
+        <Real Name="Y">-1.9514713716206011</Real>
+        <Real Name="Z">2.1116303808939767</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24773304703929611</Real>
+        <Real Name="Y">0.31824172619211505</Real>
+        <Real Name="Z">-0.37894638090153843</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2844900470088374</Real>
+        <Real Name="Y">0.83139702530798032</Real>
+        <Real Name="Z">-0.23364736482305803</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38887111904194105</Real>
+        <Real Name="Y">0.38994569691329523</Real>
+        <Real Name="Z">-0.8659211077868384</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19444002228801111</Real>
+        <Real Name="Y">0.45184907077284248</Real>
+        <Real Name="Z">-0.27717977093212742</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.40193276972877273</Real>
+        <Real Name="Y">-0.51794751796386007</Real>
+        <Real Name="Z">-1.0372897727232684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7723521907281734</Real>
+        <Real Name="Y">0.91555590404508169</Real>
+        <Real Name="Z">0.084330896303063452</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.5000354615658011</Real>
+        <Real Name="Y">59.623609799408996</Real>
+        <Real Name="Z">-374.12536663854553</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.0419970679302395</Real>
+        <Real Name="Y">1.5165120004583201</Real>
+        <Real Name="Z">111.9503722999201</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.56931075831824</Real>
+        <Real Name="Y">64.630511385336575</Real>
+        <Real Name="Z">206.36228427208516</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.61196584384426</Real>
+        <Real Name="Y">-18.892710241199779</Real>
+        <Real Name="Z">-38.911574144447016</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.692347465385886</Real>
+        <Real Name="Y">-9.5348943311679513</Real>
+        <Real Name="Z">-24.587803636490982</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4479946041186196</Real>
+        <Real Name="Y">10.529498711561203</Real>
+        <Real Name="Z">12.981604694415729</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.584494125209659</Real>
+        <Real Name="Y">-7.2607303944857122</Real>
+        <Real Name="Z">-33.323051827748614</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-56.986206976424867</Real>
+        <Real Name="Y">11.280714886887505</Real>
+        <Real Name="Z">-15.073457426765884</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.648957801056454</Real>
+        <Real Name="Y">18.888837832052914</Real>
+        <Real Name="Z">56.514099309234076</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-308.88043037612988</Real>
+        <Real Name="Y">-122.52356174124934</Real>
+        <Real Name="Z">255.49033661258812</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.67064411272267</Real>
+        <Real Name="Y">106.6949358531981</Real>
+        <Real Name="Z">-280.55159359772586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">113.93856995288232</Real>
+        <Real Name="Y">55.201361404617614</Real>
+        <Real Name="Z">-58.112809089744502</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-58.741077666978015</Real>
+        <Real Name="Y">-240.07544841444286</Real>
+        <Real Name="Z">-1.5040039329684873</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.0870084848601991</Real>
+        <Real Name="Y">45.408880554983682</Real>
+        <Real Name="Z">17.141137525846972</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-101.9076407890195</Real>
+        <Real Name="Y">24.512482694040813</Real>
+        <Real Name="Z">165.74982558034662</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8613175317847357</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8613175317847357</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8613175317847357</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0034310543403223807</Real>
+        <Real Name="Y">0.60644481338130296</Real>
+        <Real Name="Z">0.2352731825116397</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.024998109697842573</Real>
+        <Real Name="Y">0.66571037449029258</Real>
+        <Real Name="Z">0.30727855585031472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.085159372401775457</Real>
+        <Real Name="Y">0.59749807839538505</Real>
+        <Real Name="Z">0.18625526374780996</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97131884655869705</Real>
+        <Real Name="Y">0.63317463195711998</Real>
+        <Real Name="Z">1.5669177099489269</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9749957444877374</Real>
+        <Real Name="Y">0.60574903512149225</Real>
+        <Real Name="Z">1.6585508669382434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.889273989714641</Real>
+        <Real Name="Y">0.68195421706245418</Real>
+        <Real Name="Z">1.5597405278842491</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3953603682390554</Real>
+        <Real Name="Y">0.44135261626608518</Real>
+        <Real Name="Z">1.1687560804231396</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3333056751828387</Real>
+        <Real Name="Y">0.43573498598553484</Real>
+        <Real Name="Z">1.241419521710553</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3511170664790746</Real>
+        <Real Name="Y">0.39766441149753268</Real>
+        <Real Name="Z">1.0959811574518583</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6445024076003389</Real>
+        <Real Name="Y">0.3167169052981561</Real>
+        <Real Name="Z">0.30348126759366345</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6945422760118356</Real>
+        <Real Name="Y">0.33297100175588484</Real>
+        <Real Name="Z">0.22351793651183186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5988176947529513</Real>
+        <Real Name="Y">0.23426125583159815</Real>
+        <Real Name="Z">0.28685925558850806</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7758211772455985</Real>
+        <Real Name="Y">0.39347380197885751</Real>
+        <Real Name="Z">0.033304717330202731</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7157402400425481</Real>
+        <Real Name="Y">0.42426533784482579</Real>
+        <Real Name="Z">1.826765925136862</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8486322088103917</Real>
+        <Real Name="Y">0.45556176034470364</Real>
+        <Real Name="Z">0.030863916553542065</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11607197999791025</Real>
+        <Real Name="Y">0.66984453807621458</Real>
+        <Real Name="Z">-0.63051665595941297</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.64832399975187149</Real>
+        <Real Name="Y">-3.5200968541156259</Real>
+        <Real Name="Z">2.8675238572163169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.787331071926207</Real>
+        <Real Name="Y">-1.7454726474755318</Real>
+        <Real Name="Z">2.4142795561587276</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20608807290918216</Real>
+        <Real Name="Y">0.14854748459617351</Real>
+        <Real Name="Z">-0.11515356733999094</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5584834446450082</Real>
+        <Real Name="Y">-0.50098400903628071</Real>
+        <Real Name="Z">-0.3607413044117459</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.3056633892046263</Real>
+        <Real Name="Y">-1.4254475464158756</Real>
+        <Real Name="Z">1.3503934418259822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.13853442159436885</Real>
+        <Real Name="Y">-0.36182000946954557</Real>
+        <Real Name="Z">-0.28633485104638329</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92999185439660792</Real>
+        <Real Name="Y">-2.2341045335620255</Real>
+        <Real Name="Z">0.51786926881743289</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.27110020236747434</Real>
+        <Real Name="Y">-1.8356877241685123</Real>
+        <Real Name="Z">0.33072688577791448</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.01434761441317059</Real>
+        <Real Name="Y">0.22301990790558548</Real>
+        <Real Name="Z">0.087008847492427405</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.61494898474453241</Real>
+        <Real Name="Y">1.1380138582193142</Real>
+        <Real Name="Z">-0.12880784429833914</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.60793159534741958</Real>
+        <Real Name="Y">-0.064683346296277699</Real>
+        <Real Name="Z">-0.13176390705174545</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1172515502943877</Real>
+        <Real Name="Y">-0.0035901562883691</Real>
+        <Real Name="Z">0.47981319571141373</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.32479674139839942</Real>
+        <Real Name="Y">0.82427226127113751</Real>
+        <Real Name="Z">0.45758757738331579</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.0536379219727914</Real>
+        <Real Name="Y">-1.365593819593071</Real>
+        <Real Name="Z">0.066513211094502783</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">156.50347798085014</Real>
+        <Real Name="Y">104.38068905317249</Real>
+        <Real Name="Z">-274.52507637791177</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-42.962836444390035</Real>
+        <Real Name="Y">-33.846082321918736</Real>
+        <Real Name="Z">76.472681859574706</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.864423537246324</Real>
+        <Real Name="Y">42.221222044745005</Real>
+        <Real Name="Z">191.35888141664321</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">9.6738505165308624</Real>
+        <Real Name="Y">-26.852861306013324</Real>
+        <Real Name="Z">-24.470998134783017</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.34212301442161</Real>
+        <Real Name="Y">-5.3421147407948268</Real>
+        <Real Name="Z">-27.242994775722487</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">26.805294824646737</Real>
+        <Real Name="Y">-8.8010931770602774</Real>
+        <Real Name="Z">-23.484182849173486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.645499147241409</Real>
+        <Real Name="Y">-17.213619435164993</Real>
+        <Real Name="Z">-27.859685067646758</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.42193002618356</Real>
+        <Real Name="Y">17.434731594332828</Real>
+        <Real Name="Z">-21.451196219960785</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-67.062940963065572</Real>
+        <Real Name="Y">41.585260758175707</Real>
+        <Real Name="Z">83.155708902694712</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-261.60623674749525</Real>
+        <Real Name="Y">-176.49967651989601</Real>
+        <Real Name="Z">382.7975478790994</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">235.86311227200653</Real>
+        <Real Name="Y">176.93848982221482</Real>
+        <Real Name="Z">-392.43552971947048</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.71300460622281</Real>
+        <Real Name="Y">79.003717636553915</Real>
+        <Real Name="Z">-89.481890731881037</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-95.259884452948597</Real>
+        <Real Name="Y">-434.10763251732936</Real>
+        <Real Name="Z">7.8788321794280591</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.232134233899149</Real>
+        <Real Name="Y">113.99701499767872</Real>
+        <Real Name="Z">38.650746804983186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.32909149898248</Real>
+        <Real Name="Y">127.10195411130402</Real>
+        <Real Name="Z">100.63715483412659</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4529787145135691</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4529787145135691</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4529787145135691</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4529787145135691</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4533416426810541</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4533416426810541</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4533416426810541</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4533416426810541</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.435455098231774</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.435455098231774</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4485400874407262</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4485400874407262</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4538482476891659</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4538482476891659</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4538482476891659</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4538482476891659</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">18.408310287007204</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">18.410387032708318</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">18.430691850616505</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">18.429414294041674</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">18.429532542851046</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">19.981199327647399</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">19.981224319706062</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">19.980696052652046</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">19.979464411493502</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">25.745357830243204</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">25.667098974071973</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">25.699814584847527</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">25.685791622242441</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">18.454195931376905</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">18.452729159058237</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">18.451087918101617</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">18.44934125032794</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">28.072358033056044</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">27.986684114172483</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">27.996635379234156</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">28.081604271006025</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">28.316480416098926</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">33.610092975874956</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.866987325032348</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">36.272822652857769</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.814351152069584</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">36.731025684023543</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">37.160087837021912</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">37.581458750605023</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">38.084724928347129</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">36.436609587498317</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">37.827446591773025</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">39.271052675561073</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">40.742969067432419</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5675568453414339</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.557203292494922</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6434497408416213</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8782076371251524</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.626210458844042</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.883079815942773</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.289443410822209</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.832203551192567</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.09423290011992</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.519266391466994</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-11.941286016015152</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-12.458575156362345</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.929649985075887</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.321953761669263</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.76720108641393</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.240864146058954</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21190890418197439</Real>
+        <Real Name="Y">-0.7311311919098834</Real>
+        <Real Name="Z">0.011277778119910499</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.66796314487407893</Real>
+        <Real Name="Y">-0.44908961562317945</Real>
+        <Real Name="Z">-0.19934647018435334</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.080882597990871996</Real>
+        <Real Name="Y">-1.3642241529051329</Real>
+        <Real Name="Z">0.095855310056509185</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44769583968342896</Real>
+        <Real Name="Y">-0.12958260429636317</Real>
+        <Real Name="Z">0.17147102653965599</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1260077456076665</Real>
+        <Real Name="Y">1.2299432703788549</Real>
+        <Real Name="Z">0.59933785465319467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4102608467371438</Real>
+        <Real Name="Y">0.66588072547259036</Real>
+        <Real Name="Z">0.10716908923047011</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.42091576278340037</Real>
+        <Real Name="Y">0.039801072970148413</Real>
+        <Real Name="Z">0.4239928608933955</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31497744055640853</Real>
+        <Real Name="Y">0.033114800275404865</Real>
+        <Real Name="Z">1.2372826323989534</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7872566667859691</Real>
+        <Real Name="Y">-2.0657209691150182</Real>
+        <Real Name="Z">1.5960222410479219</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26078907943572527</Real>
+        <Real Name="Y">0.32044762585901831</Real>
+        <Real Name="Z">-0.34787968920455964</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.148374024658951</Real>
+        <Real Name="Y">0.34906800206533178</Real>
+        <Real Name="Z">-0.43150156880076879</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.01999757278104131</Real>
+        <Real Name="Y">0.52855025949293</Real>
+        <Real Name="Z">-0.45929211920777768</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15528384653458924</Real>
+        <Real Name="Y">0.54477489000772439</Real>
+        <Real Name="Z">-0.27405115378506656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25903608390864075</Real>
+        <Real Name="Y">-0.78199538968155358</Real>
+        <Real Name="Z">-1.2374793615012896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93642846229023646</Real>
+        <Real Name="Y">1.151169402760081</Real>
+        <Real Name="Z">-1.0669585943196809</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617793935156957</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617793935156957</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617793935156957</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059793692208015064</Real>
+        <Real Name="Y">0.59953400398140555</Real>
+        <Real Name="Z">0.23883900729963184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8576811732915823</Real>
+        <Real Name="Y">0.68761048174879225</Real>
+        <Real Name="Z">0.27494017978848989</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062417700139575386</Real>
+        <Real Name="Y">0.61123401937300537</Real>
+        <Real Name="Z">0.16241818001453365</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97409751694307656</Real>
+        <Real Name="Y">0.63061710426094908</Real>
+        <Real Name="Z">1.5710407350793358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94437944568570931</Real>
+        <Real Name="Y">0.59302499082045013</Real>
+        <Real Name="Z">1.6539019904875087</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90847655669586214</Real>
+        <Real Name="Y">0.69702253733208175</Real>
+        <Real Name="Z">1.5499095629663515</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3962842810270546</Real>
+        <Real Name="Y">0.44676430320094868</Real>
+        <Real Name="Z">1.1684215554892343</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3309315145374394</Real>
+        <Real Name="Y">0.47327215614165447</Real>
+        <Real Name="Z">1.2331414754878509</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3460111473330212</Real>
+        <Real Name="Y">0.43152559405516877</Real>
+        <Real Name="Z">1.088404606208774</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6430681186226497</Real>
+        <Real Name="Y">0.31611287349336309</Real>
+        <Real Name="Z">0.30753242348968363</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7025476557990979</Real>
+        <Real Name="Y">0.33859743091487693</Real>
+        <Real Name="Z">0.23598560151390421</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6091514087145269</Real>
+        <Real Name="Y">0.2296763859873685</Real>
+        <Real Name="Z">0.28427927710830075</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7790075295479855</Real>
+        <Real Name="Y">0.39112039244586883</Real>
+        <Real Name="Z">0.024515418876538304</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6971540434280086</Real>
+        <Real Name="Y">0.42099402566010347</Real>
+        <Real Name="Z">1.846672959222704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8182482708634853</Real>
+        <Real Name="Y">0.47035996618199594</Real>
+        <Real Name="Z">0.061170194487999402</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11743533327060737</Real>
+        <Real Name="Y">-0.020589685470007821</Real>
+        <Real Name="Z">-0.72717855943341592</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5002202212846698</Real>
+        <Real Name="Y">-0.575901866838744</Real>
+        <Real Name="Z">1.0901197226133728</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0620367716242463</Real>
+        <Real Name="Y">0.42420743542107836</Real>
+        <Real Name="Z">0.73698570707042266</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10073296579268569</Real>
+        <Real Name="Y">-0.038075003208934852</Real>
+        <Real Name="Z">0.28585139238324697</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.65074847947080405</Real>
+        <Real Name="Y">-2.7293997399418397</Real>
+        <Real Name="Z">-1.0756803296968174</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.87473761134303585</Real>
+        <Real Name="Y">-0.50788768176821319</Real>
+        <Real Name="Z">1.1749484674416248</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.060028729918335889</Real>
+        <Real Name="Y">-0.022461546820941834</Real>
+        <Real Name="Z">-0.67837120077046664</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22877087377800776</Real>
+        <Real Name="Y">-0.41849059527400162</Real>
+        <Real Name="Z">-0.2210712446827815</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46794563083205659</Real>
+        <Real Name="Y">0.10877415681079507</Real>
+        <Real Name="Z">-0.44855512896981925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22472350405396796</Real>
+        <Real Name="Y">0.38157227415158224</Real>
+        <Real Name="Z">0.66937492454695158</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019274421008187131</Real>
+        <Real Name="Y">1.4427034069202989</Real>
+        <Real Name="Z">1.1637750840558196</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9405883778869704</Real>
+        <Real Name="Y">-0.49718127047509703</Real>
+        <Real Name="Z">0.66015813643377452</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11612344769182892</Real>
+        <Real Name="Y">-0.09519215730622374</Real>
+        <Real Name="Z">-0.071082140037002708</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2098921419409854</Real>
+        <Real Name="Y">0.50508610101238693</Real>
+        <Real Name="Z">2.9769086040113697</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.097577935187605852</Real>
+        <Real Name="Y">-1.0097858875320815</Real>
+        <Real Name="Z">2.2183797214262491</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-67.302457751452806</Real>
+        <Real Name="Y">-110.64247407313545</Real>
+        <Real Name="Z">-418.24149920636108</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45237224698991696</Real>
+        <Real Name="Y">35.607029260981335</Real>
+        <Real Name="Z">108.8742619409341</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">177.20735254135772</Real>
+        <Real Name="Y">149.09307894606746</Real>
+        <Real Name="Z">168.37698900966524</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.754512308547348</Real>
+        <Real Name="Y">-14.358943973079214</Real>
+        <Real Name="Z">-37.655994186997873</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.752800565429048</Real>
+        <Real Name="Y">-8.0144376664607773</Real>
+        <Real Name="Z">-23.776820384455483</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3113639531071257</Real>
+        <Real Name="Y">7.6789319164525445</Real>
+        <Real Name="Z">12.783259690240357</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.169954645754871</Real>
+        <Real Name="Y">-14.361819299842317</Real>
+        <Real Name="Z">-32.98427328354763</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.436282999258864</Real>
+        <Real Name="Y">12.131405640756782</Real>
+        <Real Name="Z">27.161552826185108</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.929620567365284</Real>
+        <Real Name="Y">16.924863382172983</Real>
+        <Real Name="Z">54.472275338575528</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-257.21678739708159</Real>
+        <Real Name="Y">-51.562766712451975</Real>
+        <Real Name="Z">176.20611541003916</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">211.91807884522208</Real>
+        <Real Name="Y">25.169267879157303</Real>
+        <Real Name="Z">-196.62778304249184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.550125180276098</Real>
+        <Real Name="Y">32.920612216712072</Real>
+        <Real Name="Z">-53.854495468984169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.663347853619712</Real>
+        <Real Name="Y">-234.86950715529349</Real>
+        <Real Name="Z">8.1782814964972204</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.244024163174146</Real>
+        <Real Name="Y">75.898569533418467</Real>
+        <Real Name="Z">-10.557475275600893</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.701311648517589</Real>
+        <Real Name="Y">78.386190104544255</Real>
+        <Real Name="Z">217.64560513630215</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8618281105028081</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8618281105028081</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8618281105028081</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0013504472234805852</Real>
+        <Real Name="Y">0.58918136908997021</Real>
+        <Real Name="Z">0.24145480855682674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8537377573135532</Real>
+        <Real Name="Y">0.67549318534875713</Real>
+        <Real Name="Z">0.28174699218685662</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076763601345565841</Real>
+        <Real Name="Y">0.59802361481086552</Real>
+        <Real Name="Z">0.183171112071706</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98186460349953719</Real>
+        <Real Name="Y">0.62903690965423054</Real>
+        <Real Name="Z">1.5714369593570503</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97377312397419913</Real>
+        <Real Name="Y">0.63113882259127885</Real>
+        <Real Name="Z">1.6667911848590997</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94032682403180357</Real>
+        <Real Name="Y">0.71010739827577873</Real>
+        <Real Name="Z">1.5420344568861217</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3890407046578102</Real>
+        <Real Name="Y">0.44754874445833198</Real>
+        <Real Name="Z">1.1802894536443476</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3378771752081069</Real>
+        <Real Name="Y">0.47836307685252277</Real>
+        <Real Name="Z">1.2550897783318071</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3260937255845535</Real>
+        <Real Name="Y">0.39992433121527171</Real>
+        <Real Name="Z">1.126142325476688</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6487732827553483</Real>
+        <Real Name="Y">0.31809843712290253</Real>
+        <Real Name="Z">0.2959072008408265</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7081821465605946</Real>
+        <Real Name="Y">0.34137332026920736</Real>
+        <Real Name="Z">0.22455465977959199</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6023223134475968</Real>
+        <Real Name="Y">0.2406576972213004</Real>
+        <Real Name="Z">0.26416515216935099</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7747170774682171</Real>
+        <Real Name="Y">0.39919187191340932</Real>
+        <Real Name="Z">0.020617849646177369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7156442203794819</Real>
+        <Real Name="Y">0.40776056658794735</Real>
+        <Real Name="Z">1.8076175335522155</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7877416410474756</Real>
+        <Real Name="Y">0.48891769034313304</Real>
+        <Real Name="Z">0.051309161946010054</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21143746880385808</Real>
+        <Real Name="Y">-0.58649214968180374</Real>
+        <Real Name="Z">-0.34499562474694673</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.34073757453327386</Real>
+        <Real Name="Y">-1.4216345948241216</Real>
+        <Real Name="Z">1.634442995433782</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4309928903923681</Real>
+        <Real Name="Y">-0.77708849729726437</Real>
+        <Real Name="Z">2.8948637625815237</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42867584728688257</Real>
+        <Real Name="Y">-0.10317081707771336</Real>
+        <Real Name="Z">0.16360868307238696</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.59933420612862</Real>
+        <Real Name="Y">0.82679855121486157</Real>
+        <Real Name="Z">0.25421179920923476</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6172595313761533</Real>
+        <Real Name="Y">0.46426584634135498</Real>
+        <Real Name="Z">0.019180606145516699</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53767754303312287</Real>
+        <Real Name="Y">0.025831449729629554</Real>
+        <Real Name="Z">0.38091971304253086</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.59656122359921704</Real>
+        <Real Name="Y">0.21351187781476494</Real>
+        <Real Name="Z">1.0916362969552063</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.98500735251843918</Real>
+        <Real Name="Y">-1.771113520367436</Real>
+        <Real Name="Z">2.4116821572231553</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23553028773684329</Real>
+        <Real Name="Y">0.31257711705195568</Real>
+        <Real Name="Z">-0.40932828659471032</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39316278077863082</Real>
+        <Real Name="Y">1.2931402820044926</Real>
+        <Real Name="Z">0.033487636841439072</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.82009494479284295</Real>
+        <Real Name="Y">0.31263831804233905</Real>
+        <Real Name="Z">-1.2823104151096396</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20263714957687237</Real>
+        <Real Name="Y">0.38577421569624465</Real>
+        <Real Name="Z">-0.25611511218680755</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50774454342563535</Real>
+        <Real Name="Y">0.0065609602129967498</Real>
+        <Real Name="Z">-0.86717376558841763</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7568288597441679</Real>
+        <Real Name="Y">0.30500774153704124</Real>
+        <Real Name="Z">1.2051083828956557</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-78.273074851101285</Real>
+        <Real Name="Y">65.595492100656969</Real>
+        <Real Name="Z">-364.82987024864724</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.5032104130057391</Real>
+        <Real Name="Y">0.22249834983482231</Real>
+        <Real Name="Z">112.09620135667964</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">134.92691365778782</Real>
+        <Real Name="Y">1.3323051405818802</Real>
+        <Real Name="Z">132.00932811189307</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.87787379144261</Real>
+        <Real Name="Y">-23.834021361605593</Real>
+        <Real Name="Z">-37.673784608302228</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.7240625607037998</Real>
+        <Real Name="Y">7.1234240309500798</Real>
+        <Real Name="Z">14.364425737126162</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.3718465530462822</Real>
+        <Real Name="Y">12.901269685752439</Real>
+        <Real Name="Z">11.849919754922311</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.827554888754193</Real>
+        <Real Name="Y">-3.8731209374138515</Real>
+        <Real Name="Z">-32.276940798112477</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.33698105654635</Real>
+        <Real Name="Y">9.0157136055235831</Real>
+        <Real Name="Z">-18.199778086696483</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.20837133670728</Real>
+        <Real Name="Y">4.261571719300715</Real>
+        <Real Name="Z">18.151559201700955</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-315.58020310765892</Real>
+        <Real Name="Y">-131.28891724593834</Real>
+        <Real Name="Z">277.96756960986932</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">243.88135100014307</Real>
+        <Real Name="Y">100.62906875425058</Real>
+        <Real Name="Z">-285.01066857527752</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">118.78800872957518</Real>
+        <Real Name="Y">60.68842656003369</Real>
+        <Real Name="Z">-65.395023804921152</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-75.95622521455266</Real>
+        <Real Name="Y">-323.69668482383452</Real>
+        <Real Name="Z">-35.661549149226516</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.996372600466366</Real>
+        <Real Name="Y">58.168717374358039</Real>
+        <Real Name="Z">26.509802305204914</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-22.350520400858443</Real>
+        <Real Name="Y">162.75425704754946</Real>
+        <Real Name="Z">246.0988091937873</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 2">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98715
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4695777870702642</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4695777870702642</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4695777870702642</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4695777870702642</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.435455098231774</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.435455098231774</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.435455098231774</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.435455098231774</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4533416426810541</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4533416426810541</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.459691092086767</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.459691092086767</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4663501707731443</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4663501707731443</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4663501707731443</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4663501707731443</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.53844318588936</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.539758018106781</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.512238786638139</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.508127298370592</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">29.508028174517332</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">25.741244602786661</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">25.741971744614784</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">25.742921276248882</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">25.744065406223644</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">19.977411524479141</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">19.931066715852168</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">19.910789303972347</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">19.895539432758238</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">29.480046110134889</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">29.479328189228273</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">29.443143181461309</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">29.44188214216587</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">39.264244280014964</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">38.995036124534195</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">38.819961210546438</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">38.77719900208627</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">38.833314898204442</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">35.477191471366673</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">35.694457528736507</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">35.974447792172953</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">36.319048507978238</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">39.470589936902478</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">41.211617532294468</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">42.964639803908199</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">44.715264847026006</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">43.435036524173249</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">44.408316563404071</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">45.40637814873908</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">46.415231860038659</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.4290403927877016</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.2814847102685878</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.2428339900759671</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.2990490100473977</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.8445119174681768</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.061050833009885</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.340091564812232</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.683548150642759</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.490495218770338</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.234506761773837</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-23.014880809373157</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.780755723705074</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-14.037072682688015</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-15.011070642825452</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-16.045317235927424</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-17.055431986522443</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.55872268486508581</Real>
+        <Real Name="Y">-0.1954372884884242</Real>
+        <Real Name="Z">-0.12331658054675539</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5561630812121041</Real>
+        <Real Name="Y">0.1502581233870332</Real>
+        <Real Name="Z">-0.44761547196159901</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2265097662633464</Real>
+        <Real Name="Y">-1.1768262519621135</Real>
+        <Real Name="Z">-1.2616929856512602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10263626685285894</Real>
+        <Real Name="Y">0.57441118855119189</Real>
+        <Real Name="Z">0.005375904919935586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.35939325012836826</Real>
+        <Real Name="Y">0.13708618830230673</Real>
+        <Real Name="Z">-0.18874701506105859</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.676875181418428</Real>
+        <Real Name="Y">2.202437016478954</Real>
+        <Real Name="Z">0.65929093056192956</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22450558096959172</Real>
+        <Real Name="Y">0.27064569302711877</Real>
+        <Real Name="Z">0.3868191000888086</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.18295630274175456</Real>
+        <Real Name="Y">3.1066574874243527</Real>
+        <Real Name="Z">-0.46533684155430372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.43479618283021731</Real>
+        <Real Name="Y">-1.4385606453027826</Real>
+        <Real Name="Z">0.83013591007662091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11927480032898595</Real>
+        <Real Name="Y">-0.50285081385011732</Real>
+        <Real Name="Z">0.091729524538884569</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67581188225624333</Real>
+        <Real Name="Y">-0.055776720974020769</Real>
+        <Real Name="Z">0.61588372964499161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2213254303381311</Real>
+        <Real Name="Y">-1.9672700978846431</Real>
+        <Real Name="Z">0.44974949833150613</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.90469603789517505</Real>
+        <Real Name="Y">-0.20098861393275941</Real>
+        <Real Name="Z">-0.24253246946049692</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.84380910241735319</Real>
+        <Real Name="Y">0.72263550705740742</Real>
+        <Real Name="Z">-1.8704269945047447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39637402078760992</Real>
+        <Real Name="Y">-0.82004058352348863</Real>
+        <Real Name="Z">-0.19538443781690279</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8600577214745744</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8600577214745744</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8600577214745744</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0035256661593869908</Real>
+        <Real Name="Y">0.6016420724206385</Real>
+        <Real Name="Z">0.23995201116932854</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.010576802322435019</Real>
+        <Real Name="Y">0.68585090733290188</Real>
+        <Real Name="Z">0.28491279409766473</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.067670307580312367</Real>
+        <Real Name="Y">0.60682457790963262</Real>
+        <Real Name="Z">0.16909352534132704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97232523751121314</Real>
+        <Real Name="Y">0.63152584230790232</Real>
+        <Real Name="Z">1.5666962439900067</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9619102442333286</Real>
+        <Real Name="Y">0.60964991020387793</Real>
+        <Real Name="Z">1.6592991052287469</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90049279509711799</Real>
+        <Real Name="Y">0.6919942834582391</Real>
+        <Real Name="Z">1.5480955385820496</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3952509647606053</Real>
+        <Real Name="Y">0.4438476097902021</Real>
+        <Real Name="Z">1.1703268840718741</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3273499308083827</Real>
+        <Real Name="Y">0.45490565193450194</Real>
+        <Real Name="Z">1.2368812805619154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3481418352059549</Real>
+        <Real Name="Y">0.41320667931019406</Real>
+        <Real Name="Z">1.0928402291439312</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6433175472857204</Real>
+        <Real Name="Y">0.31466987518728068</Real>
+        <Real Name="Z">0.30255065341299109</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6979413319906815</Real>
+        <Real Name="Y">0.32677056871314175</Real>
+        <Real Name="Z">0.2248838409336652</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5941969730261052</Real>
+        <Real Name="Y">0.23439508911525792</Real>
+        <Real Name="Z">0.28507363119820406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7754549898473195</Real>
+        <Real Name="Y">0.3927525748260346</Real>
+        <Real Name="Z">0.029288857637699072</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7114681605068209</Real>
+        <Real Name="Y">0.41862611932099436</Real>
+        <Real Name="Z">1.8230249102082343</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8357119803555719</Real>
+        <Real Name="Y">0.46692698442460218</Real>
+        <Real Name="Z">0.034726729978247182</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.14124887104039194</Real>
+        <Real Name="Y">0.39104992242553049</Real>
+        <Real Name="Z">-0.54526866311734135</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9858348946963651</Real>
+        <Real Name="Y">-1.3161006956024894</Real>
+        <Real Name="Z">2.3992835544383468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3946226466002298</Real>
+        <Real Name="Y">-0.57483727928766004</Real>
+        <Real Name="Z">1.5953902869166852</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2060919179442037</Real>
+        <Real Name="Y">0.15417695685457822</Real>
+        <Real Name="Z">-0.092773171870536075</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5210988703534472</Real>
+        <Real Name="Y">-0.57893981686556595</Real>
+        <Real Name="Z">-0.052685908477628871</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.6949289425755718</Real>
+        <Real Name="Y">-1.1573461447241917</Real>
+        <Real Name="Z">1.2396997378186161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.05852262905097777</Real>
+        <Real Name="Y">-0.33805070556413769</Real>
+        <Real Name="Z">-0.30427672462316208</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.20069706375006446</Real>
+        <Real Name="Y">-2.6230707660770989</Real>
+        <Real Name="Z">0.38312564815063982</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.17851184551028593</Real>
+        <Real Name="Y">-2.1172348843685098</Real>
+        <Real Name="Z">0.23251836192349395</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0057348288054422684</Real>
+        <Real Name="Y">0.2381046188571059</Real>
+        <Real Name="Z">0.096027850352607191</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.5147075529238252</Real>
+        <Real Name="Y">0.24846497632816961</Real>
+        <Real Name="Z">-0.27100155755481947</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.20882610754403241</Real>
+        <Real Name="Y">0.00042324906022346565</Real>
+        <Real Name="Z">0.60667610022267071</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.088860552029537687</Real>
+        <Real Name="Y">0.12141532612709571</Real>
+        <Real Name="Z">0.52629907956886179</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.4567591952939245</Real>
+        <Real Name="Y">0.52628325128308817</Real>
+        <Real Name="Z">0.15330664829974125</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0247272077330263</Real>
+        <Real Name="Y">-1.4024810579320683</Real>
+        <Real Name="Z">-1.2072711256511359</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">117.28290869071353</Real>
+        <Real Name="Y">85.476467683806618</Real>
+        <Real Name="Z">-320.58832216615616</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-30.27986466299128</Real>
+        <Real Name="Y">-17.920572025256533</Real>
+        <Real Name="Z">88.544315493224559</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">62.459903193941727</Real>
+        <Real Name="Y">77.528667998102776</Real>
+        <Real Name="Z">218.40706226192208</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.940156104201421</Real>
+        <Real Name="Y">-21.828588519096627</Real>
+        <Real Name="Z">-33.209030778819326</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.019718120074984</Real>
+        <Real Name="Y">-6.9561126884015394</Real>
+        <Real Name="Z">-24.726214073884186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6650252404272621</Real>
+        <Real Name="Y">9.5805979447904086</Real>
+        <Real Name="Z">10.600944315795921</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.593773273866972</Real>
+        <Real Name="Y">-14.053432785400162</Real>
+        <Real Name="Z">-31.273712802001079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.563329070729132</Real>
+        <Real Name="Y">13.494330728017971</Real>
+        <Real Name="Z">25.006645041058341</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.325293186986983</Real>
+        <Real Name="Y">19.763205320089941</Real>
+        <Real Name="Z">53.601368297850328</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-294.91578957986081</Real>
+        <Real Name="Y">-160.72742123793057</Real>
+        <Real Name="Z">317.05415142874233</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.22310644487868</Real>
+        <Real Name="Y">158.9066348923194</Real>
+        <Real Name="Z">-334.89433443976225</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">105.56008196511519</Real>
+        <Real Name="Y">69.399952441379355</Real>
+        <Real Name="Z">-72.645273944784378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-69.838704955627065</Real>
+        <Real Name="Y">-328.90620587891391</Real>
+        <Real Name="Z">-21.442079827084115</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-16.954454168549624</Real>
+        <Real Name="Y">79.053125092555547</Real>
+        <Real Name="Z">-4.9370407140715429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-109.53718692762038</Real>
+        <Real Name="Y">37.189351033937271</Real>
+        <Real Name="Z">130.50152190796962</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8630295341750887</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8630295341750887</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8630295341750887</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.013557833703786812</Real>
+        <Real Name="Y">0.59759908612937818</Real>
+        <Real Name="Z">0.23984889722201536</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0059574170069372047</Real>
+        <Real Name="Y">0.68544792935347998</Real>
+        <Real Name="Z">0.27709312912738615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.057967003884200237</Real>
+        <Real Name="Y">0.61080324406523701</Real>
+        <Real Name="Z">0.15608855925056497</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97709908809249102</Real>
+        <Real Name="Y">0.64080652632143698</Real>
+        <Real Name="Z">1.5692753875277885</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9477010771103217</Real>
+        <Real Name="Y">0.6166895944872357</Real>
+        <Real Name="Z">1.6571187079864125</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94626861702447274</Real>
+        <Real Name="Y">0.73065378960245875</Real>
+        <Real Name="Z">1.5574741276529029</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3938011608278174</Real>
+        <Real Name="Y">0.45190889524197808</Real>
+        <Real Name="Z">1.1811473019185754</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3396229296659414</Real>
+        <Real Name="Y">0.51979845084925969</Real>
+        <Real Name="Z">1.2213722432810652</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3369582290294506</Real>
+        <Real Name="Y">0.41158706591464783</Real>
+        <Real Name="Z">1.1155321391567301</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6476660099968794</Real>
+        <Real Name="Y">0.30442787980644342</Real>
+        <Real Name="Z">0.30286328442275096</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.711712065571398</Real>
+        <Real Name="Y">0.33654555062653968</Real>
+        <Real Name="Z">0.23938985386761738</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6399612924828466</Real>
+        <Real Name="Y">0.21090995013874725</Real>
+        <Real Name="Z">0.28395951340486819</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7636513364065738</Real>
+        <Real Name="Y">0.38776942805022474</Real>
+        <Real Name="Z">0.020803110475604861</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7286634082923016</Real>
+        <Real Name="Y">0.42686996988147247</Real>
+        <Real Name="Z">1.8037744725832956</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8121146457130497</Real>
+        <Real Name="Y">0.45872918397920354</Real>
+        <Real Name="Z">0.062973468424812828</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.52021010250753885</Real>
+        <Real Name="Y">-0.14931630746789643</Real>
+        <Real Name="Z">-0.4085342235801368</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.2122231562583183</Real>
+        <Real Name="Y">-0.79990765443210265</Real>
+        <Real Name="Z">1.3194466207268545</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8295146419223365</Real>
+        <Real Name="Y">1.0154618714845491</Real>
+        <Real Name="Z">0.4465715300745231</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10025223243170152</Real>
+        <Real Name="Y">0.61242027747136774</Real>
+        <Real Name="Z">-0.07022966890414295</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15932484658633037</Real>
+        <Real Name="Y">0.035601807495497746</Real>
+        <Real Name="Z">-0.31285095168869703</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9787966819064748</Real>
+        <Real Name="Y">1.4628456416926434</Real>
+        <Real Name="Z">1.2434463953176969</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24971604655362142</Real>
+        <Real Name="Y">0.31119613447262512</Real>
+        <Real Name="Z">0.41430854715126542</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.78848398457668734</Real>
+        <Real Name="Y">2.1841019264420534</Real>
+        <Real Name="Z">-1.2566457541359468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1018860571817275</Real>
+        <Real Name="Y">-0.97071319529459499</Real>
+        <Real Name="Z">1.9053127225716362</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.12388037201942931</Real>
+        <Real Name="Y">-0.59662487289541222</Real>
+        <Real Name="Z">0.013099021657363111</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.093967920426236348</Real>
+        <Real Name="Y">1.0098764322240599</Real>
+        <Real Name="Z">0.58291631206698424</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9564790327613175</Real>
+        <Real Name="Y">-0.91468636586402619</Real>
+        <Real Name="Z">0.21607916785258066</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96578478891515962</Real>
+        <Real Name="Y">-0.34145102564522967</Real>
+        <Real Name="Z">-0.263875917615706</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3455163164678008</Real>
+        <Real Name="Y">0.79473426972625183</Real>
+        <Real Name="Z">-0.76204840962265108</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2774149884242609</Real>
+        <Real Name="Y">-1.2177964402636348</Real>
+        <Real Name="Z">1.6212710983022656</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-29.692198466272259</Real>
+        <Real Name="Y">-166.56827780359706</Real>
+        <Real Name="Z">-389.57084143989897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-14.275701981493938</Real>
+        <Real Name="Y">40.599558505808076</Real>
+        <Real Name="Z">98.727766116170173</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">141.7612753103046</Real>
+        <Real Name="Y">176.9705707071364</Real>
+        <Real Name="Z">161.69012489487676</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.756565080361156</Real>
+        <Real Name="Y">-3.8332628086953378</Real>
+        <Real Name="Z">-39.175670341632326</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.085954249480622</Real>
+        <Real Name="Y">-0.38746647717224469</Real>
+        <Real Name="Z">13.230433525268367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-6.2270288292096794</Real>
+        <Real Name="Y">5.2140405698967172</Real>
+        <Real Name="Z">15.059280571274421</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">35.779127066724001</Real>
+        <Real Name="Y">-8.6715025242153345</Real>
+        <Real Name="Z">-30.937358558616197</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.229240540655503</Real>
+        <Real Name="Y">1.9788965966612437</Real>
+        <Real Name="Z">24.991552397561662</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-12.993468527739353</Real>
+        <Real Name="Y">5.6992946435249578</Real>
+        <Real Name="Z">16.831762406144072</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-208.72933516867252</Real>
+        <Real Name="Y">-90.284757976100025</Real>
+        <Real Name="Z">297.5743355454195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">100.00485375529246</Real>
+        <Real Name="Y">40.869624663988603</Real>
+        <Real Name="Z">-276.38679817912134</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">72.677939001822523</Real>
+        <Real Name="Y">73.849537792435797</Real>
+        <Real Name="Z">-102.03763573434051</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">27.529843830665811</Real>
+        <Real Name="Y">-173.44263980696297</Real>
+        <Real Name="Z">54.713551498577544</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-40.293497630281905</Real>
+        <Real Name="Y">21.197517294828856</Real>
+        <Real Name="Z">-5.4503063577473085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-48.983178651364796</Real>
+        <Real Name="Y">76.808866622462318</Real>
+        <Real Name="Z">160.73980365606411</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 3">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98716
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.435455098231774</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.435455098231774</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.435455098231774</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.435455098231774</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4695777870702642</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4695777870702642</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4695777870702642</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4695777870702642</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4695777870702642</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4695777870702642</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4663501707731443</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4663501707731443</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.459691092086767</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.459691092086767</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.459691092086767</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.459691092086767</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">25.771154963006502</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">25.802683538690612</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">25.781260384047776</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">25.740523155147191</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">25.740769137152192</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">29.508013813964805</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.508042856821664</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.50810607676814</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.508174360962094</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">29.50821254424266</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">29.521593059297793</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">29.550607371407413</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">29.482865157127094</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">19.892640713414039</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">19.887306553743475</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">19.882405384038396</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">19.835496200812688</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">35.343549230704284</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">35.278559360357306</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">35.241028323556101</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">35.229028251495045</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">35.321897584958549</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">38.983794078749391</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">39.228409946421799</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">39.567272254399214</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">40.000599501696321</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">40.528482220249352</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">41.15056764503754</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">41.803785381758843</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">42.545147469299444</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">46.438464650038242</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">48.039212455529345</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">49.45868541276355</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">50.591120104677586</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5844408731034427</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5683329909450734</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.5970701477846028</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.6896934992431074</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.4495425599364236</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-9.6941293847519745</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.032928472782913</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.466187435886066</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-10.994031971158531</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.616149163194768</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-12.33526031964084</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-13.144364621461758</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.506854244165964</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-28.112936209327632</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.537310336266916</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.716654211406659</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.19787174590441542</Real>
+        <Real Name="Y">0.1615613889385647</Real>
+        <Real Name="Z">-0.38305665212567802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.7420087544145497</Real>
+        <Real Name="Y">0.75918088595013389</Real>
+        <Real Name="Z">1.2435674032029085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3711369223715755</Real>
+        <Real Name="Y">-0.19170785514288644</Real>
+        <Real Name="Z">0.42562796639667022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19638315205483492</Real>
+        <Real Name="Y">0.14565315135227885</Real>
+        <Real Name="Z">-0.067967185842621486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3802138136646303</Real>
+        <Real Name="Y">-0.58427055558605701</Real>
+        <Real Name="Z">0.23045735337154905</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.9488788834227251</Real>
+        <Real Name="Y">-0.88425910185951861</Real>
+        <Real Name="Z">0.94602094518641222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.023704545495134583</Real>
+        <Real Name="Y">-0.3413031917315365</Real>
+        <Real Name="Z">-0.30920684408559601</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.57458809086462592</Real>
+        <Real Name="Y">-2.6639579923405159</Real>
+        <Real Name="Z">0.20924282970686953</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10717835653133569</Real>
+        <Real Name="Y">-2.1491056124634227</Real>
+        <Real Name="Z">0.10532829628877118</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.012944992862387334</Real>
+        <Real Name="Y">0.24702752779615819</Real>
+        <Real Name="Z">0.1198190834623393</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53415108976374859</Real>
+        <Real Name="Y">-0.39551860957653251</Real>
+        <Real Name="Z">-0.44767485391309769</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23060498264262888</Real>
+        <Real Name="Y">0.091415864029443031</Real>
+        <Real Name="Z">1.125773624901474</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.064052506287219743</Real>
+        <Real Name="Y">0.1556142409020734</Real>
+        <Real Name="Z">0.5494680052322487</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53148313148554538</Real>
+        <Real Name="Y">0.53815672969841799</Real>
+        <Real Name="Z">0.03164652949451436</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.0632897927011018</Real>
+        <Real Name="Y">-0.36976385613194229</Real>
+        <Real Name="Z">-2.4264951267859698</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8633394536885388</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8633394536885388</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8633394536885388</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0093554429488127769</Real>
+        <Real Name="Y">0.59898854822014913</Real>
+        <Real Name="Z">0.24258440446731866</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8585779275654162</Real>
+        <Real Name="Y">0.6895964374515271</Real>
+        <Real Name="Z">0.27002962250718754</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.048280861640696782</Real>
+        <Real Name="Y">0.60610090828910623</Real>
+        <Real Name="Z">0.15542624642166808</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97645477499090028</Real>
+        <Real Name="Y">0.63609656978933626</Real>
+        <Real Name="Z">1.5699877655709202</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94948092399816719</Real>
+        <Real Name="Y">0.61634040050411953</Real>
+        <Real Name="Z">1.6596784760029122</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.93100276826193773</Real>
+        <Real Name="Y">0.71759166488771442</Real>
+        <Real Name="Z">1.5486574360090872</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3960083029208554</Real>
+        <Real Name="Y">0.44957125139420878</Real>
+        <Real Name="Z">1.1780426080104709</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3341627567745424</Real>
+        <Real Name="Y">0.5003746616695246</Real>
+        <Real Name="Z">1.2305446110795142</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3450537688107802</Real>
+        <Real Name="Y">0.42048385353050355</Real>
+        <Real Name="Z">1.1024127386522384</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6470293221322423</Real>
+        <Real Name="Y">0.30907256912851983</Real>
+        <Real Name="Z">0.30273525416992569</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7101907370214644</Real>
+        <Real Name="Y">0.33001130857037192</Real>
+        <Real Name="Z">0.23392738209283312</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6171685604338826</Real>
+        <Real Name="Y">0.22057665654986708</Real>
+        <Real Name="Z">0.28177990240325368</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7716946837673484</Real>
+        <Real Name="Y">0.3903584564774043</Real>
+        <Real Name="Z">0.022949520651257237</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.718809909951682</Real>
+        <Real Name="Y">0.42093792593426749</Real>
+        <Real Name="Z">1.8125976237876296</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8190933348325724</Real>
+        <Real Name="Y">0.46813657256239899</Real>
+        <Real Name="Z">0.052381661848695429</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.5353857941911232</Real>
+        <Real Name="Y">-0.17432736445252495</Real>
+        <Real Name="Z">-0.25552283864360414</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4728981864797368</Real>
+        <Real Name="Y">-0.20407779184415317</Real>
+        <Real Name="Z">0.34757783075618731</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.34557270917388966</Real>
+        <Real Name="Y">-0.0050645166422910101</Real>
+        <Real Name="Z">-0.32688255058197724</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10058702925633034</Real>
+        <Real Name="Y">0.5901552921510933</Real>
+        <Real Name="Z">-0.034991636694828895</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.26361692285644434</Real>
+        <Real Name="Y">0.091670937121782078</Real>
+        <Real Name="Z">-0.25193747213648426</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.857452099793079</Real>
+        <Real Name="Y">1.8696817354072182</Real>
+        <Real Name="Z">0.97530029581699773</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24115053167777994</Real>
+        <Real Name="Y">0.28853283221147824</Real>
+        <Real Name="Z">0.40725360473293726</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.56645984580395481</Real>
+        <Real Name="Y">2.7369354159357955</Real>
+        <Real Name="Z">-0.9302604929911904</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.79675344731583475</Real>
+        <Real Name="Y">-1.2480901641370339</Real>
+        <Real Name="Z">1.3490561537156309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10622598476618497</Real>
+        <Real Name="Y">-0.54517875371463087</Real>
+        <Real Name="Z">0.040256599002704008</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.55630050695440214</Real>
+        <Real Name="Y">0.52841992400318294</Real>
+        <Real Name="Z">0.76642202722762098</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.7311407736486948</Real>
+        <Real Name="Y">-1.5476395786652444</Real>
+        <Real Name="Z">0.34272982428582266</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96116582689656305</Real>
+        <Real Name="Y">-0.2752768637774205</Real>
+        <Real Name="Z">-0.2660987040629591</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1499183706090286</Real>
+        <Real Name="Y">0.70717541322133526</Real>
+        <Real Name="Z">-1.4192484552060969</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.31619282145611732</Real>
+        <Real Name="Y">-1.0863049613077695</Real>
+        <Real Name="Z">0.87897116140187759</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">16.453879468906877</Real>
+        <Real Name="Y">-61.485523962608909</Real>
+        <Real Name="Z">-385.09590861855042</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.307370587512096</Real>
+        <Real Name="Y">22.072331817053666</Real>
+        <Real Name="Z">103.57755474205054</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">142.81520473668297</Real>
+        <Real Name="Y">172.37370887103594</Real>
+        <Real Name="Z">223.29482708889407</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.375608179554405</Real>
+        <Real Name="Y">-8.2644841300624989</Real>
+        <Real Name="Z">-39.718861764076735</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.59632546884783</Real>
+        <Real Name="Y">-12.107476341647219</Real>
+        <Real Name="Z">-23.762202078345616</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3917428771111133</Real>
+        <Real Name="Y">6.6921028836861502</Real>
+        <Real Name="Z">14.479287584970265</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.630474518417941</Real>
+        <Real Name="Y">-9.2093070798193821</Real>
+        <Real Name="Z">-32.510660274763794</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.251572624337761</Real>
+        <Real Name="Y">4.9528723724999182</Real>
+        <Real Name="Z">27.220966476804335</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.959092665371294</Real>
+        <Real Name="Y">17.936292295343033</Real>
+        <Real Name="Z">54.291470055411537</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-254.89830733553595</Real>
+        <Real Name="Y">-97.875547176996363</Real>
+        <Real Name="Z">270.41712322563399</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">160.12682824607106</Real>
+        <Real Name="Y">75.451817408565063</Real>
+        <Real Name="Z">-289.53565168573857</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.214099973301359</Real>
+        <Real Name="Y">63.775895266630101</Real>
+        <Real Name="Z">-80.108373255609592</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2660939742528399</Real>
+        <Real Name="Y">-169.48692593638165</Real>
+        <Real Name="Z">52.280279860666724</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-39.210607171534321</Real>
+        <Real Name="Y">26.632144357920581</Real>
+        <Real Name="Z">-17.788843205155445</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-98.927633356126961</Real>
+        <Real Name="Y">-31.457900645218473</Real>
+        <Real Name="Z">122.95899184780865</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8623897955806521</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8623897955806521</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8623897955806521</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070910146820004783</Real>
+        <Real Name="Y">0.60002668830439776</Real>
+        <Real Name="Z">0.23202975916327448</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0048950371770967345</Real>
+        <Real Name="Y">0.67731221464766045</Real>
+        <Real Name="Z">0.28846063281097245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.082317956465080638</Real>
+        <Real Name="Y">0.61436994448993076</Real>
+        <Real Name="Z">0.17460592585374282</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9735264823504387</Real>
+        <Real Name="Y">0.63045285859138234</Real>
+        <Real Name="Z">1.5739042617210555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94141972569520971</Real>
+        <Real Name="Y">0.57218820552997407</Real>
+        <Real Name="Z">1.6427279842352827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90231279104031725</Real>
+        <Real Name="Y">0.69292654524775832</Real>
+        <Real Name="Z">1.5601941542981574</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3961915221287489</Real>
+        <Real Name="Y">0.44673997420782896</Real>
+        <Real Name="Z">1.1634070397776033</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3341090617077416</Real>
+        <Real Name="Y">0.4702321549520867</Real>
+        <Real Name="Z">1.2323722770493821</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3417984570606991</Real>
+        <Real Name="Y">0.43277113377637516</Real>
+        <Real Name="Z">1.0858919807922487</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6417049163336119</Real>
+        <Real Name="Y">0.31916116809573297</Real>
+        <Real Name="Z">0.3126881528431768</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7044376583397531</Real>
+        <Real Name="Y">0.35033140387038597</Real>
+        <Real Name="Z">0.24745520195067824</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6271494214466486</Real>
+        <Real Name="Y">0.22731104345055303</Real>
+        <Real Name="Z">0.29001635160771827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7801179577926904</Real>
+        <Real Name="Y">0.39107820251134723</Real>
+        <Real Name="Z">0.024208215970697725</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6907265332191921</Real>
+        <Real Name="Y">0.42119839276883092</Real>
+        <Real Name="Z">0.0079519632790974182</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8168737341916843</Real>
+        <Real Name="Y">0.45616635585799037</Real>
+        <Real Name="Z">0.083998379001339052</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.17194494254480486</Real>
+        <Real Name="Y">0.085132434397926809</Real>
+        <Real Name="Z">-0.961408821212834</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.70589525110225426</Real>
+        <Real Name="Y">-2.0059542689915126</Real>
+        <Real Name="Z">2.0445717954742357</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5678724753685298</Real>
+        <Real Name="Y">0.17402107118615229</Real>
+        <Real Name="Z">2.0694910922533536</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11848898179476028</Real>
+        <Real Name="Y">-0.054994409284474056</Real>
+        <Real Name="Z">0.29857291715500817</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22707104616630192</Real>
+        <Real Name="Y">-2.5166771365645166</Real>
+        <Real Name="Z">-1.7611562674529182</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.76409058623099835</Real>
+        <Real Name="Y">-0.56534324462658037</Real>
+        <Real Name="Z">1.2675113920015795</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.075611436510171035</Real>
+        <Real Name="Y">-0.020983244027670846</Real>
+        <Real Name="Z">-0.67164239724709174</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43076799214001854</Real>
+        <Real Name="Y">-0.37800839085178517</Real>
+        <Real Name="Z">-0.08893874801201021</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.67112338836622143</Real>
+        <Real Name="Y">0.16226668526383797</Real>
+        <Real Name="Z">-0.29023151951309828</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24561174634599409</Real>
+        <Real Name="Y">0.35489918822099187</Real>
+        <Real Name="Z">0.60152894623735931</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31483882839145855</Real>
+        <Real Name="Y">1.4506069872842757</Real>
+        <Real Name="Z">1.644119131981036</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3214424681969548</Real>
+        <Real Name="Y">-0.1355120892687264</Real>
+        <Real Name="Z">0.78885030198228356</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.032273749481762204</Real>
+        <Real Name="Y">0.054398003594863256</Real>
+        <Real Name="Z">0.015194854898409289</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63956916450096413</Real>
+        <Real Name="Y">-0.38898526121395005</Real>
+        <Real Name="Z">2.6539733542644499</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.30111137566276613</Real>
+        <Real Name="Y">-2.4382600816243887</Real>
+        <Real Name="Z">3.0643108063129048</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-165.60318585107009</Real>
+        <Real Name="Y">-319.09812065037283</Real>
+        <Real Name="Z">-377.0760039510505</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.503084943028604</Real>
+        <Real Name="Y">68.294441886805984</Real>
+        <Real Name="Z">99.990414282075335</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.58688972527267</Real>
+        <Real Name="Y">141.80502349784717</Real>
+        <Real Name="Z">72.057803958772595</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.213425730015729</Real>
+        <Real Name="Y">-15.085113843324841</Real>
+        <Real Name="Z">-36.539972000669181</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.352180526071713</Real>
+        <Real Name="Y">2.7178415423717102</Real>
+        <Real Name="Z">14.700530738098969</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.172231280993806</Real>
+        <Real Name="Y">7.4010595207852568</Real>
+        <Real Name="Z">12.120768977744859</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.218509581909217</Real>
+        <Real Name="Y">-17.582431069712861</Real>
+        <Real Name="Z">-31.266634455511486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.405253982904533</Real>
+        <Real Name="Y">14.930733728491873</Real>
+        <Real Name="Z">25.184035066016293</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.5022695219548936</Real>
+        <Real Name="Y">7.61791012138886</Real>
+        <Real Name="Z">15.801271674320546</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-179.64079649468871</Real>
+        <Real Name="Y">4.0047968249609482</Real>
+        <Real Name="Z">101.13298417565034</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">146.34773892419855</Real>
+        <Real Name="Y">-33.248050115065084</Real>
+        <Real Name="Z">-82.167287917547753</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">72.247125752283722</Real>
+        <Real Name="Y">9.3866166837110399</Real>
+        <Real Name="Z">-49.163035859138233</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.635642914946857</Real>
+        <Real Name="Y">-310.98238619457277</Real>
+        <Real Name="Z">-20.552292676462116</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.298339583911307</Real>
+        <Real Name="Y">116.7326992752736</Real>
+        <Real Name="Z">-0.34279563515246991</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.493125499833496</Real>
+        <Real Name="Y">323.1049787914119</Real>
+        <Real Name="Z">256.12021362285287</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_Crescale_4Ranks_1RanksPerSimulation_s.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_Crescale_4Ranks_1RanksPerSimulation_s.xml
new file mode 100644 (file)
index 0000000..5aeca61
--- /dev/null
@@ -0,0 +1,3398 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.453341</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.453341</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.453341</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.453341</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4529777</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4529777</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4529777</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4529777</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4529777</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4529777</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4538479</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4538479</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4485397</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4485397</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4485397</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4485397</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">19.965948</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">19.968513</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">19.980829</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">19.980106</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">19.980705</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">18.429564</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">18.429663</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">18.429579</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">18.429411</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">18.42914</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">18.457808</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">18.432516</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">18.455006</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">25.687378</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">25.688883</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">25.692074</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">25.693356</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629332</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">30.132038</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.78092</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">31.565931</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">32.509109</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">28.700047</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.23196</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.910864</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">30.734053</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">31.697084</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">32.740543</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">33.875446</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">35.119957</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">38.703297</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">39.409164</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">40.192192</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">41.052174</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.160834</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.797401</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.583136</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.525715</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.261741</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.793557</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.472544</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.295901</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.259204</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.273617</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.390164</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.612185</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-13.075526</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-13.77989</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-14.559728</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-15.418426</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13823938</Real>
+        <Real Name="Y">-0.083000772</Real>
+        <Real Name="Z">-0.55156732</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807449</Real>
+        <Real Name="Y">0.12591785</Real>
+        <Real Name="Z">0.086322196</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50557399</Real>
+        <Real Name="Y">-0.26345637</Real>
+        <Real Name="Z">-0.37042341</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.080341451</Real>
+        <Real Name="Y">-0.036381256</Real>
+        <Real Name="Z">0.2694976</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0880266</Real>
+        <Real Name="Y">-2.6992292</Real>
+        <Real Name="Z">-0.41159731</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0053114</Real>
+        <Real Name="Y">-0.44618699</Real>
+        <Real Name="Z">1.1535</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046993218</Real>
+        <Real Name="Y">-0.027141469</Real>
+        <Real Name="Z">-0.68357778</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051991098</Real>
+        <Real Name="Y">-0.42392981</Real>
+        <Real Name="Z">-0.38236645</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25138494</Real>
+        <Real Name="Y">0.072344378</Real>
+        <Real Name="Z">-0.58373684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20046787</Real>
+        <Real Name="Y">0.39459831</Real>
+        <Real Name="Z">0.71750742</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21663746</Real>
+        <Real Name="Y">1.2108052</Real>
+        <Real Name="Z">0.86115432</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3770657</Real>
+        <Real Name="Y">-0.66109222</Real>
+        <Real Name="Z">0.87071204</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21701036</Real>
+        <Real Name="Y">-0.090551347</Real>
+        <Real Name="Z">-0.034703776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639677</Real>
+        <Real Name="Y">0.96361506</Real>
+        <Real Name="Z">2.5346279</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37429887</Real>
+        <Real Name="Y">-0.37906641</Real>
+        <Real Name="Z">0.73122346</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617444</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617444</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617444</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.003176132</Real>
+        <Real Name="Y">0.59425509</Real>
+        <Real Name="Z">0.24342826</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8498156</Real>
+        <Real Name="Y">0.68430561</Real>
+        <Real Name="Z">0.27215207</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059038579</Real>
+        <Real Name="Y">0.60276031</Real>
+        <Real Name="Z">0.1661666</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97835487</Real>
+        <Real Name="Y">0.62989837</Real>
+        <Real Name="Z">1.5700941</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96144229</Real>
+        <Real Name="Y">0.62383074</Real>
+        <Real Name="Z">1.6641124</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92768419</Real>
+        <Real Name="Y">0.70588732</Real>
+        <Real Name="Z">1.5414503</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3930815</Real>
+        <Real Name="Y">0.44726905</Real>
+        <Real Name="Z">1.177127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3332013</Real>
+        <Real Name="Y">0.47707075</Real>
+        <Real Name="Z">1.2455997</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3358212</Real>
+        <Real Name="Y">0.41474193</Real>
+        <Real Name="Z">1.1076608</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6467737</Real>
+        <Real Name="Y">0.31556281</Real>
+        <Real Name="Z">0.29905939</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7053335</Real>
+        <Real Name="Y">0.33253998</Real>
+        <Real Name="Z">0.22527012</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.597208</Real>
+        <Real Name="Y">0.23793435</Real>
+        <Real Name="Z">0.27299443</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7762452</Real>
+        <Real Name="Y">0.39589146</Real>
+        <Real Name="Z">0.022766901</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7118634</Real>
+        <Real Name="Y">0.40977472</Real>
+        <Real Name="Z">1.8150523</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8063989</Real>
+        <Real Name="Y">0.48385501</Real>
+        <Real Name="Z">0.045471363</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.23480785</Real>
+        <Real Name="Y">-0.68794054</Real>
+        <Real Name="Z">-0.13560323</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.59073675</Real>
+        <Real Name="Y">-0.79458719</Real>
+        <Real Name="Z">0.65588379</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6602482</Real>
+        <Real Name="Y">-0.59314287</Real>
+        <Real Name="Z">1.2099996</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43880409</Real>
+        <Real Name="Y">-0.11980459</Real>
+        <Real Name="Z">0.15843503</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4193437</Real>
+        <Real Name="Y">1.0233856</Real>
+        <Real Name="Z">0.42099735</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5176858</Real>
+        <Real Name="Y">0.58945101</Real>
+        <Real Name="Z">0.10248335</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.47859523</Real>
+        <Real Name="Y">0.038668543</Real>
+        <Real Name="Z">0.39971039</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.51587087</Real>
+        <Real Name="Y">0.091344237</Real>
+        <Real Name="Z">1.2590896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.4941994</Real>
+        <Real Name="Y">-1.9514688</Real>
+        <Real Name="Z">2.1116397</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24773453</Real>
+        <Real Name="Y">0.31824481</Real>
+        <Real Name="Z">-0.37894624</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2845121</Real>
+        <Real Name="Y">0.83138615</Real>
+        <Real Name="Z">-0.23364855</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38882565</Real>
+        <Real Name="Y">0.38991076</Real>
+        <Real Name="Z">-0.86591238</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19443677</Real>
+        <Real Name="Y">0.45185071</Real>
+        <Real Name="Z">-0.27717817</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.4019095</Real>
+        <Real Name="Y">-0.51794285</Real>
+        <Real Name="Z">-1.0373455</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7723629</Real>
+        <Real Name="Y">0.9155665</Real>
+        <Real Name="Z">0.084325649</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.4993134</Real>
+        <Real Name="Y">59.62326</Real>
+        <Real Name="Z">-374.12549</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.0422325</Real>
+        <Real Name="Y">1.5163116</Real>
+        <Real Name="Z">111.95027</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.56868</Real>
+        <Real Name="Y">64.63121</Real>
+        <Real Name="Z">206.36244</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.611862</Real>
+        <Real Name="Y">-18.892681</Real>
+        <Real Name="Z">-38.911545</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.692356</Real>
+        <Real Name="Y">-9.5348892</Real>
+        <Real Name="Z">-24.587814</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.447998</Real>
+        <Real Name="Y">10.529507</Real>
+        <Real Name="Z">12.981628</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.584366</Real>
+        <Real Name="Y">-7.2607079</Real>
+        <Real Name="Z">-33.32309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-56.986061</Real>
+        <Real Name="Y">11.280678</Real>
+        <Real Name="Z">-15.073425</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.648872</Real>
+        <Real Name="Y">18.888805</Real>
+        <Real Name="Z">56.514072</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-308.88025</Real>
+        <Real Name="Y">-122.52365</Real>
+        <Real Name="Z">255.49094</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.67041</Real>
+        <Real Name="Y">106.69515</Real>
+        <Real Name="Z">-280.55228</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">113.93861</Real>
+        <Real Name="Y">55.201416</Real>
+        <Real Name="Z">-58.11293</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-58.741547</Real>
+        <Real Name="Y">-240.07562</Real>
+        <Real Name="Z">-1.5036926</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.0871239</Real>
+        <Real Name="Y">45.408875</Real>
+        <Real Name="Z">17.141006</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-101.90717</Real>
+        <Real Name="Y">24.512375</Real>
+        <Real Name="Z">165.74991</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8613175</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8613175</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8613175</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0034310666</Real>
+        <Real Name="Y">0.60644472</Real>
+        <Real Name="Z">0.23527317</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.024998033</Real>
+        <Real Name="Y">0.66571003</Real>
+        <Real Name="Z">0.30727872</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.085159466</Real>
+        <Real Name="Y">0.59749806</Real>
+        <Real Name="Z">0.1862554</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97131884</Real>
+        <Real Name="Y">0.63317448</Real>
+        <Real Name="Z">1.5669177</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97499561</Real>
+        <Real Name="Y">0.60574889</Real>
+        <Real Name="Z">1.6585509</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.889274</Real>
+        <Real Name="Y">0.68195415</Real>
+        <Real Name="Z">1.5597404</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3953604</Real>
+        <Real Name="Y">0.44135261</Real>
+        <Real Name="Z">1.1687562</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3333057</Real>
+        <Real Name="Y">0.4357352</Real>
+        <Real Name="Z">1.2414197</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3511169</Real>
+        <Real Name="Y">0.39766446</Real>
+        <Real Name="Z">1.0959814</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6445025</Real>
+        <Real Name="Y">0.31671682</Real>
+        <Real Name="Z">0.30348122</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6945425</Real>
+        <Real Name="Y">0.33297101</Real>
+        <Real Name="Z">0.22351803</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5988178</Real>
+        <Real Name="Y">0.23426116</Real>
+        <Real Name="Z">0.28685907</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7758212</Real>
+        <Real Name="Y">0.39347374</Real>
+        <Real Name="Z">0.033304706</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.71574</Real>
+        <Real Name="Y">0.42426538</Real>
+        <Real Name="Z">1.8267664</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.848632</Real>
+        <Real Name="Y">0.45556197</Real>
+        <Real Name="Z">0.030863911</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11607449</Real>
+        <Real Name="Y">0.66984594</Real>
+        <Real Name="Z">-0.63051963</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.64829922</Real>
+        <Real Name="Y">-3.5200999</Real>
+        <Real Name="Z">2.8675444</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7873324</Real>
+        <Real Name="Y">-1.7454903</Real>
+        <Real Name="Z">2.4142964</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20608908</Real>
+        <Real Name="Y">0.14854911</Real>
+        <Real Name="Z">-0.11514961</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5584512</Real>
+        <Real Name="Y">-0.50098193</Real>
+        <Real Name="Z">-0.36079141</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.3056636</Real>
+        <Real Name="Y">-1.4254407</Real>
+        <Real Name="Z">1.3504115</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.13852851</Real>
+        <Real Name="Y">-0.36181578</Real>
+        <Real Name="Z">-0.28633049</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92993701</Real>
+        <Real Name="Y">-2.2341208</Real>
+        <Real Name="Z">0.51785254</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.27099988</Real>
+        <Real Name="Y">-1.8357174</Real>
+        <Real Name="Z">0.33068129</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.014350665</Real>
+        <Real Name="Y">0.22301868</Real>
+        <Real Name="Z">0.087004438</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.61495805</Real>
+        <Real Name="Y">1.1380241</Real>
+        <Real Name="Z">-0.12880567</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.60789931</Real>
+        <Real Name="Y">-0.06472642</Real>
+        <Real Name="Z">-0.13177881</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11724748</Real>
+        <Real Name="Y">-0.0035891556</Real>
+        <Real Name="Z">0.47981313</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.3247222</Real>
+        <Real Name="Y">0.82430547</Real>
+        <Real Name="Z">0.45753601</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.0536318</Real>
+        <Real Name="Y">-1.3656118</Real>
+        <Real Name="Z">0.066534117</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">156.50185</Real>
+        <Real Name="Y">104.38004</Real>
+        <Real Name="Z">-274.52606</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-42.962585</Real>
+        <Real Name="Y">-33.846016</Real>
+        <Real Name="Z">76.472977</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.865189</Real>
+        <Real Name="Y">42.220779</Real>
+        <Real Name="Z">191.35864</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">9.6739655</Real>
+        <Real Name="Y">-26.852859</Real>
+        <Real Name="Z">-24.471123</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.342125</Real>
+        <Real Name="Y">-5.3421383</Real>
+        <Real Name="Z">-27.243</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">26.805313</Real>
+        <Real Name="Y">-8.8011265</Real>
+        <Real Name="Z">-23.484196</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.645538</Real>
+        <Real Name="Y">-17.213612</Real>
+        <Real Name="Z">-27.859722</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.421982</Real>
+        <Real Name="Y">17.434744</Real>
+        <Real Name="Z">-21.451141</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-67.063034</Real>
+        <Real Name="Y">41.585304</Real>
+        <Real Name="Z">83.155823</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-261.60611</Real>
+        <Real Name="Y">-176.4987</Real>
+        <Real Name="Z">382.79697</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">235.86288</Real>
+        <Real Name="Y">176.9375</Real>
+        <Real Name="Z">-392.43518</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.713181</Real>
+        <Real Name="Y">79.003532</Real>
+        <Real Name="Z">-89.481857</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-95.259476</Real>
+        <Real Name="Y">-434.10809</Real>
+        <Real Name="Z">7.879364</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.232073</Real>
+        <Real Name="Y">113.99759</Real>
+        <Real Name="Z">38.650879</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.32893</Real>
+        <Real Name="Y">127.10304</Real>
+        <Real Name="Z">100.63766</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4529777</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4529777</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4529777</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4529777</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.453341</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.453341</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.453341</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.453341</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4354539</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4354539</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4485397</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4485397</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4538479</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4538479</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4538479</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4538479</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">18.40823</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">18.410301</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">18.43067</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">18.429352</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">18.429575</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">19.981304</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">19.98127</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">19.980738</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">19.979595</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">25.745188</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">25.666939</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">25.699596</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">25.685669</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">18.454191</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">18.452644</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">18.450977</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">18.449226</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">28.072332</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">27.986635</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">27.996597</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">28.081598</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">28.316477</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">33.610184</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.867096</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">36.272945</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.814476</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">36.730919</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">37.160011</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">37.581402</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">38.084698</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">36.436535</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">37.827358</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">39.270943</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">40.742851</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5675926</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5571871</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6435051</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8781614</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.626191</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.883137</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.289518</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.832191</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.094261</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.519317</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-11.941415</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-12.458637</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.929577</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.321947</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.767199</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.240858</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21190877</Real>
+        <Real Name="Y">-0.73113304</Real>
+        <Real Name="Z">0.011277338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.66796941</Real>
+        <Real Name="Y">-0.44908154</Real>
+        <Real Name="Z">-0.19935304</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.080868699</Real>
+        <Real Name="Y">-1.3642008</Real>
+        <Real Name="Z">0.095872603</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44769731</Real>
+        <Real Name="Y">-0.12958133</Real>
+        <Real Name="Z">0.17146564</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1259595</Real>
+        <Real Name="Y">1.2299777</Real>
+        <Real Name="Z">0.59934753</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4102879</Real>
+        <Real Name="Y">0.66582245</Real>
+        <Real Name="Z">0.10724045</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.42090845</Real>
+        <Real Name="Y">0.039798632</Real>
+        <Real Name="Z">0.42398912</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31489116</Real>
+        <Real Name="Y">0.033143241</Real>
+        <Real Name="Z">1.2373283</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7872748</Real>
+        <Real Name="Y">-2.0657148</Real>
+        <Real Name="Z">1.5960392</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26079154</Real>
+        <Real Name="Y">0.32045048</Real>
+        <Real Name="Z">-0.34788135</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.14831775</Real>
+        <Real Name="Y">0.34903857</Real>
+        <Real Name="Z">-0.43145278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019986875</Real>
+        <Real Name="Y">0.52854216</Real>
+        <Real Name="Z">-0.45931953</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15528721</Real>
+        <Real Name="Y">0.54477292</Real>
+        <Real Name="Z">-0.27405369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25908729</Real>
+        <Real Name="Y">-0.78199595</Real>
+        <Real Name="Z">-1.2374361</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93642789</Real>
+        <Real Name="Y">1.1511997</Real>
+        <Real Name="Z">-1.0669613</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617793</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617793</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617793</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059793759</Real>
+        <Real Name="Y">0.59953403</Real>
+        <Real Name="Z">0.23883902</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8576812</Real>
+        <Real Name="Y">0.68761045</Real>
+        <Real Name="Z">0.27494028</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062417578</Real>
+        <Real Name="Y">0.61123413</Real>
+        <Real Name="Z">0.1624181</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97409749</Real>
+        <Real Name="Y">0.63061702</Real>
+        <Real Name="Z">1.5710406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94437957</Real>
+        <Real Name="Y">0.59302485</Real>
+        <Real Name="Z">1.6539019</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90847659</Real>
+        <Real Name="Y">0.69702262</Real>
+        <Real Name="Z">1.5499097</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3962845</Real>
+        <Real Name="Y">0.44676435</Real>
+        <Real Name="Z">1.1684215</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3309317</Real>
+        <Real Name="Y">0.4732722</Real>
+        <Real Name="Z">1.2331415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3460113</Real>
+        <Real Name="Y">0.43152556</Real>
+        <Real Name="Z">1.0884047</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6430682</Real>
+        <Real Name="Y">0.31611288</Real>
+        <Real Name="Z">0.30753243</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7025477</Real>
+        <Real Name="Y">0.33859748</Real>
+        <Real Name="Z">0.23598561</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6091515</Real>
+        <Real Name="Y">0.2296764</Real>
+        <Real Name="Z">0.28427923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7790074</Real>
+        <Real Name="Y">0.39112031</Real>
+        <Real Name="Z">0.024515424</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6971542</Real>
+        <Real Name="Y">0.42099407</Real>
+        <Real Name="Z">1.8466727</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8182483</Real>
+        <Real Name="Y">0.47035983</Real>
+        <Real Name="Z">0.061170232</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11743702</Real>
+        <Real Name="Y">-0.020589491</Real>
+        <Real Name="Z">-0.72718138</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5002234</Real>
+        <Real Name="Y">-0.57589453</Real>
+        <Real Name="Z">1.0901417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0620072</Real>
+        <Real Name="Y">0.42421538</Real>
+        <Real Name="Z">0.73696494</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10073391</Real>
+        <Real Name="Y">-0.038071699</Real>
+        <Real Name="Z">0.28584835</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.65074688</Real>
+        <Real Name="Y">-2.7294469</Real>
+        <Real Name="Z">-1.0756203</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.87472796</Real>
+        <Real Name="Y">-0.50789458</Real>
+        <Real Name="Z">1.1749587</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.060030226</Real>
+        <Real Name="Y">-0.022459073</Real>
+        <Real Name="Z">-0.67836475</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22880663</Real>
+        <Real Name="Y">-0.41850498</Real>
+        <Real Name="Z">-0.22110273</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46798933</Real>
+        <Real Name="Y">0.10877422</Real>
+        <Real Name="Z">-0.44860387</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22472657</Real>
+        <Real Name="Y">0.38157034</Real>
+        <Real Name="Z">0.66937542</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019275207</Real>
+        <Real Name="Y">1.4426898</Real>
+        <Real Name="Z">1.1637446</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9406409</Real>
+        <Real Name="Y">-0.49716437</Real>
+        <Real Name="Z">0.66014045</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11611833</Real>
+        <Real Name="Y">-0.095191151</Real>
+        <Real Name="Z">-0.071084805</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2098788</Real>
+        <Real Name="Y">0.50506157</Real>
+        <Real Name="Z">2.9769185</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.097535536</Real>
+        <Real Name="Y">-1.0097715</Real>
+        <Real Name="Z">2.218416</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-67.301865</Real>
+        <Real Name="Y">-110.64282</Real>
+        <Real Name="Z">-418.24164</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45218658</Real>
+        <Real Name="Y">35.606865</Real>
+        <Real Name="Z">108.87425</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">177.20695</Real>
+        <Real Name="Y">149.09366</Real>
+        <Real Name="Z">168.37708</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.754631</Real>
+        <Real Name="Y">-14.358994</Real>
+        <Real Name="Z">-37.656044</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.752789</Real>
+        <Real Name="Y">-8.0144272</Real>
+        <Real Name="Z">-23.776814</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3113632</Real>
+        <Real Name="Y">7.6789341</Real>
+        <Real Name="Z">12.783237</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.170013</Real>
+        <Real Name="Y">-14.361794</Real>
+        <Real Name="Z">-32.984215</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.436386</Real>
+        <Real Name="Y">12.131413</Real>
+        <Real Name="Z">27.161549</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.92968</Real>
+        <Real Name="Y">16.924868</Real>
+        <Real Name="Z">54.47229</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-257.21661</Real>
+        <Real Name="Y">-51.562973</Real>
+        <Real Name="Z">176.20737</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">211.9175</Real>
+        <Real Name="Y">25.169228</Real>
+        <Real Name="Z">-196.62863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.550156</Real>
+        <Real Name="Y">32.920815</Real>
+        <Real Name="Z">-53.854904</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.663452</Real>
+        <Real Name="Y">-234.86903</Real>
+        <Real Name="Z">8.1786194</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.244011</Real>
+        <Real Name="Y">75.898178</Real>
+        <Real Name="Z">-10.557526</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.700836</Real>
+        <Real Name="Y">78.386078</Real>
+        <Real Name="Z">217.64526</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8618281</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8618281</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8618281</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0013504603</Real>
+        <Real Name="Y">0.58918148</Real>
+        <Real Name="Z">0.24145478</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8537375</Real>
+        <Real Name="Y">0.67549318</Real>
+        <Real Name="Z">0.28174713</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076763451</Real>
+        <Real Name="Y">0.59802413</Real>
+        <Real Name="Z">0.18317094</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98186463</Real>
+        <Real Name="Y">0.6290369</Real>
+        <Real Name="Z">1.5714375</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97377264</Real>
+        <Real Name="Y">0.6311388</Real>
+        <Real Name="Z">1.6667917</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94032699</Real>
+        <Real Name="Y">0.71010739</Real>
+        <Real Name="Z">1.5420347</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3890407</Real>
+        <Real Name="Y">0.44754869</Real>
+        <Real Name="Z">1.180289</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3378773</Real>
+        <Real Name="Y">0.47836316</Real>
+        <Real Name="Z">1.2550894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3260936</Real>
+        <Real Name="Y">0.39992422</Real>
+        <Real Name="Z">1.1261421</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6487733</Real>
+        <Real Name="Y">0.31809843</Real>
+        <Real Name="Z">0.29590717</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7081822</Real>
+        <Real Name="Y">0.34137315</Real>
+        <Real Name="Z">0.22455469</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6023223</Real>
+        <Real Name="Y">0.2406576</Real>
+        <Real Name="Z">0.26416519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.774717</Real>
+        <Real Name="Y">0.3991918</Real>
+        <Real Name="Z">0.020617845</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7156445</Real>
+        <Real Name="Y">0.40776068</Real>
+        <Real Name="Z">1.8076173</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7877419</Real>
+        <Real Name="Y">0.48891759</Real>
+        <Real Name="Z">0.051309031</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21143733</Real>
+        <Real Name="Y">-0.58649111</Real>
+        <Real Name="Z">-0.34499806</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.34076706</Real>
+        <Real Name="Y">-1.4216595</Real>
+        <Real Name="Z">1.6344213</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.430959</Real>
+        <Real Name="Y">-0.7770254</Real>
+        <Real Name="Z">2.8948586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42867449</Real>
+        <Real Name="Y">-0.10316625</Real>
+        <Real Name="Z">0.1636036</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5993069</Real>
+        <Real Name="Y">0.82677078</Real>
+        <Real Name="Z">0.25436577</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.617262</Real>
+        <Real Name="Y">0.46428686</Real>
+        <Real Name="Z">0.019191274</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53768182</Real>
+        <Real Name="Y">0.025829099</Real>
+        <Real Name="Z">0.38091674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.5965277</Real>
+        <Real Name="Y">0.2135587</Real>
+        <Real Name="Z">1.0916916</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.98496932</Real>
+        <Real Name="Y">-1.7711056</Real>
+        <Real Name="Z">2.4116874</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.235533</Real>
+        <Real Name="Y">0.31257868</Real>
+        <Real Name="Z">-0.40933156</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39316419</Real>
+        <Real Name="Y">1.2931266</Real>
+        <Real Name="Z">0.033493649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.82004958</Real>
+        <Real Name="Y">0.31259292</Real>
+        <Real Name="Z">-1.2823068</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20264181</Real>
+        <Real Name="Y">0.38577718</Real>
+        <Real Name="Z">-0.25612324</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50784558</Real>
+        <Real Name="Y">0.0065601226</Real>
+        <Real Name="Z">-0.867091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7568383</Real>
+        <Real Name="Y">0.3050203</Real>
+        <Real Name="Z">1.2050947</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-78.270935</Real>
+        <Real Name="Y">65.595139</Real>
+        <Real Name="Z">-364.83075</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.5025673</Real>
+        <Real Name="Y">0.22229767</Real>
+        <Real Name="Z">112.09622</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">134.92656</Real>
+        <Real Name="Y">1.3336029</Real>
+        <Real Name="Z">132.01028</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.877808</Real>
+        <Real Name="Y">-23.833927</Real>
+        <Real Name="Z">-37.673752</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.7240677</Real>
+        <Real Name="Y">7.1233921</Real>
+        <Real Name="Z">14.364407</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.3718491</Real>
+        <Real Name="Y">12.901257</Real>
+        <Real Name="Z">11.84993</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.82737</Real>
+        <Real Name="Y">-3.8730927</Real>
+        <Real Name="Z">-32.277016</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.336803</Real>
+        <Real Name="Y">9.0156555</Real>
+        <Real Name="Z">-18.199703</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.208282</Real>
+        <Real Name="Y">4.2615452</Real>
+        <Real Name="Z">18.151558</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-315.58041</Real>
+        <Real Name="Y">-131.28926</Real>
+        <Real Name="Z">277.96942</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">243.8804</Real>
+        <Real Name="Y">100.62955</Real>
+        <Real Name="Z">-285.01215</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">118.78797</Real>
+        <Real Name="Y">60.688683</Real>
+        <Real Name="Z">-65.395538</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-75.955994</Real>
+        <Real Name="Y">-323.69647</Real>
+        <Real Name="Z">-35.662231</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.996414</Real>
+        <Real Name="Y">58.168488</Real>
+        <Real Name="Z">26.510437</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-22.350739</Real>
+        <Real Name="Y">162.75314</Real>
+        <Real Name="Z">246.09882</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 2">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98715
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4695773</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4695773</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4695773</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4695773</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4354539</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4354539</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4354539</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4354539</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.453341</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.453341</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4596901</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4596901</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.466351</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.466351</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.466351</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.466351</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.538376</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.539698</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.512169</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.508093</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">29.507994</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">25.741096</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">25.741814</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">25.742643</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">25.743834</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">19.977478</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">19.931118</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">19.910879</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">19.895624</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">29.479948</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">29.479143</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">29.443052</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">29.441833</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">39.264248</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">38.995052</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">38.819954</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">38.777184</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">38.833305</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">35.477077</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">35.694344</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">35.974354</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">36.318939</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">39.470695</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">41.211689</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">42.964714</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">44.715378</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">43.435005</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">44.408279</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">45.406338</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">46.415215</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.4290991</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.2815304</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.242835</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.299058</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.844511</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.06106</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.34024</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.683636</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.490528</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.234545</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-23.014883</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.780802</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-14.037125</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-15.011205</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-16.045353</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-17.055449</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.55872297</Real>
+        <Real Name="Y">-0.19543174</Real>
+        <Real Name="Z">-0.12331802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5561588</Real>
+        <Real Name="Y">0.15019241</Real>
+        <Real Name="Z">-0.44760495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2265118</Real>
+        <Real Name="Y">-1.1768512</Real>
+        <Real Name="Z">-1.2616764</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10263991</Real>
+        <Real Name="Y">0.57440907</Real>
+        <Real Name="Z">0.0053722998</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.35943791</Real>
+        <Real Name="Y">0.13711332</Real>
+        <Real Name="Z">-0.18872896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6768553</Real>
+        <Real Name="Y">2.2024438</Real>
+        <Real Name="Z">0.65932018</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22449927</Real>
+        <Real Name="Y">0.27064398</Real>
+        <Real Name="Z">0.38681656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.18288493</Real>
+        <Real Name="Y">3.1066663</Real>
+        <Real Name="Z">-0.46535692</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.43482876</Real>
+        <Real Name="Y">-1.4385394</Real>
+        <Real Name="Z">0.8301881</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11927342</Real>
+        <Real Name="Y">-0.50285125</Real>
+        <Real Name="Z">0.091731116</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.6758315</Real>
+        <Real Name="Y">-0.055776317</Real>
+        <Real Name="Z">0.61587429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2213309</Real>
+        <Real Name="Y">-1.9672643</Real>
+        <Real Name="Z">0.44974977</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.90470046</Real>
+        <Real Name="Y">-0.2009875</Real>
+        <Real Name="Z">-0.24253644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.8438639</Real>
+        <Real Name="Y">0.72260296</Real>
+        <Real Name="Z">-1.8703772</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39639631</Real>
+        <Real Name="Y">-0.8200264</Real>
+        <Real Name="Z">-0.19537324</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8600576</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8600576</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8600576</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0035256655</Real>
+        <Real Name="Y">0.60164201</Real>
+        <Real Name="Z">0.239952</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.010576865</Real>
+        <Real Name="Y">0.6858508</Real>
+        <Real Name="Z">0.28491288</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.06767036</Real>
+        <Real Name="Y">0.60682458</Real>
+        <Real Name="Z">0.16909355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97232521</Real>
+        <Real Name="Y">0.63152564</Real>
+        <Real Name="Z">1.5666963</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96191007</Real>
+        <Real Name="Y">0.60964978</Real>
+        <Real Name="Z">1.6592991</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90049285</Real>
+        <Real Name="Y">0.69199413</Real>
+        <Real Name="Z">1.5480955</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3952509</Real>
+        <Real Name="Y">0.44384763</Real>
+        <Real Name="Z">1.1703268</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3273499</Real>
+        <Real Name="Y">0.45490575</Real>
+        <Real Name="Z">1.2368813</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3481418</Real>
+        <Real Name="Y">0.41320658</Real>
+        <Real Name="Z">1.0928403</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6433175</Real>
+        <Real Name="Y">0.31466985</Real>
+        <Real Name="Z">0.30255064</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6979414</Real>
+        <Real Name="Y">0.32677051</Real>
+        <Real Name="Z">0.22488397</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5941969</Real>
+        <Real Name="Y">0.2343951</Real>
+        <Real Name="Z">0.28507352</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.775455</Real>
+        <Real Name="Y">0.39275256</Real>
+        <Real Name="Z">0.029288854</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.711468</Real>
+        <Real Name="Y">0.41862607</Real>
+        <Real Name="Z">1.823025</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8357118</Real>
+        <Real Name="Y">0.46692708</Real>
+        <Real Name="Z">0.034726702</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.14124881</Real>
+        <Real Name="Y">0.39104754</Real>
+        <Real Name="Z">-0.54527044</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9858282</Real>
+        <Real Name="Y">-1.3160686</Real>
+        <Real Name="Z">2.3993123</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.394635</Real>
+        <Real Name="Y">-0.57484555</Real>
+        <Real Name="Z">1.5953996</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20609492</Real>
+        <Real Name="Y">0.15417986</Real>
+        <Real Name="Z">-0.092770457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5210898</Real>
+        <Real Name="Y">-0.5789398</Real>
+        <Real Name="Z">-0.052691408</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.6949033</Real>
+        <Real Name="Y">-1.1573619</Real>
+        <Real Name="Z">1.2396899</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.058532055</Real>
+        <Real Name="Y">-0.33805308</Real>
+        <Real Name="Z">-0.3042796</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.20075588</Real>
+        <Real Name="Y">-2.6230409</Real>
+        <Real Name="Z">0.38319549</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.17859279</Real>
+        <Real Name="Y">-2.1172106</Real>
+        <Real Name="Z">0.23253787</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0057419487</Real>
+        <Real Name="Y">0.23810743</Real>
+        <Real Name="Z">0.09601903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.51478148</Real>
+        <Real Name="Y">0.24844848</Real>
+        <Real Name="Z">-0.27091005</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.20880592</Real>
+        <Real Name="Y">0.00037769708</Real>
+        <Real Name="Z">0.60663909</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.08886344</Real>
+        <Real Name="Y">0.12141163</Real>
+        <Real Name="Z">0.52629721</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45674059</Real>
+        <Real Name="Y">0.52628732</Real>
+        <Real Name="Z">0.15332177</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0247562</Real>
+        <Real Name="Y">-1.4024186</Real>
+        <Real Name="Z">-1.2072635</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">117.28244</Real>
+        <Real Name="Y">85.476562</Real>
+        <Real Name="Z">-320.5882</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-30.279827</Real>
+        <Real Name="Y">-17.920647</Real>
+        <Real Name="Z">88.544281</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">62.46022</Real>
+        <Real Name="Y">77.528442</Real>
+        <Real Name="Z">218.40692</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.940163</Real>
+        <Real Name="Y">-21.828564</Real>
+        <Real Name="Z">-33.209015</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.019714</Real>
+        <Real Name="Y">-6.9561157</Real>
+        <Real Name="Z">-24.726212</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6650543</Real>
+        <Real Name="Y">9.5806103</Real>
+        <Real Name="Z">10.600956</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.593781</Real>
+        <Real Name="Y">-14.053387</Real>
+        <Real Name="Z">-31.273777</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.563332</Real>
+        <Real Name="Y">13.494284</Real>
+        <Real Name="Z">25.006695</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.325272</Real>
+        <Real Name="Y">19.763176</Real>
+        <Real Name="Z">53.601353</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-294.91568</Real>
+        <Real Name="Y">-160.72694</Real>
+        <Real Name="Z">317.05295</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.22285</Real>
+        <Real Name="Y">158.90646</Real>
+        <Real Name="Z">-334.89359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">105.56026</Real>
+        <Real Name="Y">69.399918</Real>
+        <Real Name="Z">-72.645126</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-69.83812</Real>
+        <Real Name="Y">-328.90677</Real>
+        <Real Name="Z">-21.442322</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-16.954592</Real>
+        <Real Name="Y">79.053345</Real>
+        <Real Name="Z">-4.9367065</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-109.53757</Real>
+        <Real Name="Y">37.189598</Real>
+        <Real Name="Z">130.5018</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8630296</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8630296</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8630296</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.013557854</Real>
+        <Real Name="Y">0.59759915</Real>
+        <Real Name="Z">0.23984888</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0059573287</Real>
+        <Real Name="Y">0.68544781</Real>
+        <Real Name="Z">0.27709338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.057967044</Real>
+        <Real Name="Y">0.6108036</Real>
+        <Real Name="Z">0.15608861</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97709924</Real>
+        <Real Name="Y">0.6408065</Real>
+        <Real Name="Z">1.5692753</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94770122</Real>
+        <Real Name="Y">0.61668962</Real>
+        <Real Name="Z">1.6571187</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9462688</Real>
+        <Real Name="Y">0.7306537</Real>
+        <Real Name="Z">1.5574739</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.393801</Real>
+        <Real Name="Y">0.45190892</Real>
+        <Real Name="Z">1.1811472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3396227</Real>
+        <Real Name="Y">0.5197984</Real>
+        <Real Name="Z">1.2213721</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3369582</Real>
+        <Real Name="Y">0.41158709</Real>
+        <Real Name="Z">1.115532</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6476662</Real>
+        <Real Name="Y">0.30442783</Real>
+        <Real Name="Z">0.30286324</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7117124</Real>
+        <Real Name="Y">0.33654529</Real>
+        <Real Name="Z">0.23938972</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6399611</Real>
+        <Real Name="Y">0.21090992</Real>
+        <Real Name="Z">0.28395948</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7636516</Real>
+        <Real Name="Y">0.38776943</Real>
+        <Real Name="Z">0.020803127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7286634</Real>
+        <Real Name="Y">0.42686993</Real>
+        <Real Name="Z">1.8037746</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8121151</Real>
+        <Real Name="Y">0.45872918</Real>
+        <Real Name="Z">0.062973268</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.52021265</Real>
+        <Real Name="Y">-0.14931329</Real>
+        <Real Name="Z">-0.40853795</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.2122194</Real>
+        <Real Name="Y">-0.7999047</Real>
+        <Real Name="Z">1.3194624</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8295101</Real>
+        <Real Name="Y">1.0154555</Real>
+        <Real Name="Z">0.44657475</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10025549</Real>
+        <Real Name="Y">0.61242104</Real>
+        <Real Name="Z">-0.070239469</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15937924</Real>
+        <Real Name="Y">0.035643246</Real>
+        <Real Name="Z">-0.31277072</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9787831</Real>
+        <Real Name="Y">1.462808</Real>
+        <Real Name="Z">1.2435114</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24971454</Real>
+        <Real Name="Y">0.31119391</Real>
+        <Real Name="Z">0.4143075</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.78843194</Real>
+        <Real Name="Y">2.1840928</Real>
+        <Real Name="Z">-1.2566677</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1018989</Real>
+        <Real Name="Y">-0.97067046</Real>
+        <Real Name="Z">1.9053466</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.12387586</Real>
+        <Real Name="Y">-0.59662652</Real>
+        <Real Name="Z">0.013101977</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.093884386</Real>
+        <Real Name="Y">1.0098811</Real>
+        <Real Name="Z">0.58287644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9564712</Real>
+        <Real Name="Y">-0.91471243</Real>
+        <Real Name="Z">0.2160801</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96578449</Real>
+        <Real Name="Y">-0.34145471</Real>
+        <Real Name="Z">-0.26387224</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3454551</Real>
+        <Real Name="Y">0.79476094</Real>
+        <Real Name="Z">-0.76214826</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.277373</Real>
+        <Real Name="Y">-1.2177765</Real>
+        <Real Name="Z">1.6212823</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-29.690491</Real>
+        <Real Name="Y">-166.56696</Real>
+        <Real Name="Z">-389.57047</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-14.276028</Real>
+        <Real Name="Y">40.599129</Real>
+        <Real Name="Z">98.72776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">141.75983</Real>
+        <Real Name="Y">176.97015</Real>
+        <Real Name="Z">161.69025</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.756531</Real>
+        <Real Name="Y">-3.8332596</Real>
+        <Real Name="Z">-39.175667</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.0859489</Real>
+        <Real Name="Y">-0.38746357</Real>
+        <Real Name="Z">13.230446</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-6.2270508</Real>
+        <Real Name="Y">5.2140636</Real>
+        <Real Name="Z">15.059315</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">35.77916</Real>
+        <Real Name="Y">-8.6715126</Real>
+        <Real Name="Z">-30.937431</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.229225</Real>
+        <Real Name="Y">1.9788876</Real>
+        <Real Name="Z">24.99157</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-12.993464</Real>
+        <Real Name="Y">5.6992855</Real>
+        <Real Name="Z">16.831768</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-208.7298</Real>
+        <Real Name="Y">-90.285225</Real>
+        <Real Name="Z">297.57501</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">100.00529</Real>
+        <Real Name="Y">40.87075</Real>
+        <Real Name="Z">-276.388</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">72.678162</Real>
+        <Real Name="Y">73.849503</Real>
+        <Real Name="Z">-102.03748</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">27.529007</Real>
+        <Real Name="Y">-173.44409</Real>
+        <Real Name="Z">54.712982</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-40.293274</Real>
+        <Real Name="Y">21.197823</Real>
+        <Real Name="Z">-5.4502106</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-48.982681</Real>
+        <Real Name="Y">76.808922</Real>
+        <Real Name="Z">160.74023</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 3">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98716
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4354539</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4354539</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4354539</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4354539</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4695773</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4695773</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4695773</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4695773</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4695773</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4695773</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.466351</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.466351</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4596901</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4596901</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4596901</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4596901</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">25.77104</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">25.802567</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">25.78117</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">25.740416</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">25.740679</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">29.507956</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.508089</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.508112</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.508154</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">29.508142</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">29.521637</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">29.55061</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">29.482845</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">19.892748</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">19.887449</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">19.882523</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">19.835655</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">35.343521</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">35.278515</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">35.240959</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">35.228951</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">35.321815</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">38.983776</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">39.228394</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">39.567299</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">40.000622</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">40.5285</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">41.150581</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">41.803791</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">42.545132</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">46.438576</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">48.039314</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">49.458782</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">50.591217</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5844784</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5683193</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.597064</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.6896667</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.4495668</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-9.6940498</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.032931</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.466214</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-10.994102</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.616105</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-12.335249</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-13.144354</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.506876</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-28.112913</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.537308</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.71661</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.19787164</Real>
+        <Real Name="Y">0.16156073</Real>
+        <Real Name="Z">-0.3830564</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.7420168</Real>
+        <Real Name="Y">0.75917548</Real>
+        <Real Name="Z">1.2435496</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3711295</Real>
+        <Real Name="Y">-0.1916929</Real>
+        <Real Name="Z">0.42564186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19638549</Real>
+        <Real Name="Y">0.14565483</Real>
+        <Real Name="Z">-0.067964658</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3802328</Real>
+        <Real Name="Y">-0.58428359</Real>
+        <Real Name="Z">0.2304372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.9488595</Real>
+        <Real Name="Y">-0.88427049</Real>
+        <Real Name="Z">0.94601095</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.023709064</Real>
+        <Real Name="Y">-0.34130558</Real>
+        <Real Name="Z">-0.30921173</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.57465923</Real>
+        <Real Name="Y">-2.6639383</Real>
+        <Real Name="Z">0.20926186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10718073</Real>
+        <Real Name="Y">-2.149086</Real>
+        <Real Name="Z">0.10538759</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.012949247</Real>
+        <Real Name="Y">0.24703081</Real>
+        <Real Name="Z">0.11981639</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53420067</Real>
+        <Real Name="Y">-0.39553621</Real>
+        <Real Name="Z">-0.44761676</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23061849</Real>
+        <Real Name="Y">0.091385715</Real>
+        <Real Name="Z">1.1257544</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.06405513</Real>
+        <Real Name="Y">0.15561384</Real>
+        <Real Name="Z">0.54946572</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53148574</Real>
+        <Real Name="Y">0.53813189</Real>
+        <Real Name="Z">0.031651895</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.0633225</Real>
+        <Real Name="Y">-0.3697392</Real>
+        <Real Name="Z">-2.4264705</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8633394</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8633394</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8633394</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.00935545</Real>
+        <Real Name="Y">0.59898859</Real>
+        <Real Name="Z">0.24258442</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.858578</Real>
+        <Real Name="Y">0.68959641</Real>
+        <Real Name="Z">0.27002975</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.048280865</Real>
+        <Real Name="Y">0.60610104</Real>
+        <Real Name="Z">0.15542626</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97645485</Real>
+        <Real Name="Y">0.63609654</Real>
+        <Real Name="Z">1.5699877</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94948095</Real>
+        <Real Name="Y">0.6163404</Real>
+        <Real Name="Z">1.6596783</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.93100286</Real>
+        <Real Name="Y">0.71759164</Real>
+        <Real Name="Z">1.5486573</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3960083</Real>
+        <Real Name="Y">0.44957125</Real>
+        <Real Name="Z">1.1780425</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3341626</Real>
+        <Real Name="Y">0.50037467</Real>
+        <Real Name="Z">1.2305444</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3450538</Real>
+        <Real Name="Y">0.42048392</Real>
+        <Real Name="Z">1.1024126</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6470294</Real>
+        <Real Name="Y">0.30907252</Real>
+        <Real Name="Z">0.30273521</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7101908</Real>
+        <Real Name="Y">0.33001122</Real>
+        <Real Name="Z">0.23392722</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6171685</Real>
+        <Real Name="Y">0.22057666</Real>
+        <Real Name="Z">0.28177986</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7716949</Real>
+        <Real Name="Y">0.39035842</Real>
+        <Real Name="Z">0.02294952</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7188101</Real>
+        <Real Name="Y">0.42093781</Real>
+        <Real Name="Z">1.8125976</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8190935</Real>
+        <Real Name="Y">0.46813661</Real>
+        <Real Name="Z">0.052381556</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.53538781</Real>
+        <Real Name="Y">-0.17432608</Real>
+        <Real Name="Z">-0.25552613</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4728792</Real>
+        <Real Name="Y">-0.20406632</Real>
+        <Real Name="Z">0.347644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.34557694</Real>
+        <Real Name="Y">-0.0050800475</Real>
+        <Real Name="Z">-0.32689369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10058578</Real>
+        <Real Name="Y">0.59015632</Real>
+        <Real Name="Z">-0.034990519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2636176</Real>
+        <Real Name="Y">0.091685779</Real>
+        <Real Name="Z">-0.25197032</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8574657</Real>
+        <Real Name="Y">1.8696564</Real>
+        <Real Name="Z">0.97529644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24114808</Real>
+        <Real Name="Y">0.28853312</Real>
+        <Real Name="Z">0.40725526</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.56642908</Real>
+        <Real Name="Y">2.7369337</Real>
+        <Real Name="Z">-0.93027985</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.79678607</Real>
+        <Real Name="Y">-1.2480981</Real>
+        <Real Name="Z">1.3490323</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10622215</Real>
+        <Real Name="Y">-0.54518181</Real>
+        <Real Name="Z">0.04025951</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.55637914</Real>
+        <Real Name="Y">0.52840763</Real>
+        <Real Name="Z">0.76636171</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.7311418</Real>
+        <Real Name="Y">-1.5476234</Real>
+        <Real Name="Z">0.34273142</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96116477</Real>
+        <Real Name="Y">-0.27527457</Real>
+        <Real Name="Z">-0.26609623</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1499577</Real>
+        <Real Name="Y">0.70719218</Real>
+        <Real Name="Z">-1.419234</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.31622952</Real>
+        <Real Name="Y">-1.0863714</Real>
+        <Real Name="Z">0.87891459</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">16.454193</Real>
+        <Real Name="Y">-61.48465</Real>
+        <Real Name="Z">-385.09589</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.307392</Real>
+        <Real Name="Y">22.072044</Real>
+        <Real Name="Z">103.57751</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">142.81482</Real>
+        <Real Name="Y">172.37346</Real>
+        <Real Name="Z">223.29504</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.375549</Real>
+        <Real Name="Y">-8.2644501</Real>
+        <Real Name="Z">-39.718895</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.596355</Real>
+        <Real Name="Y">-12.107489</Real>
+        <Real Name="Z">-23.762215</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3917542</Real>
+        <Real Name="Y">6.6921101</Real>
+        <Real Name="Z">14.479321</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.630478</Real>
+        <Real Name="Y">-9.2093048</Real>
+        <Real Name="Z">-32.510674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.251549</Real>
+        <Real Name="Y">4.9528561</Real>
+        <Real Name="Z">27.220989</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.959084</Real>
+        <Real Name="Y">17.936275</Real>
+        <Real Name="Z">54.291473</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-254.89874</Real>
+        <Real Name="Y">-97.875786</Real>
+        <Real Name="Z">270.41711</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">160.12761</Real>
+        <Real Name="Y">75.452072</Real>
+        <Real Name="Z">-289.5361</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.214233</Real>
+        <Real Name="Y">63.775879</Real>
+        <Real Name="Z">-80.108307</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.266922</Real>
+        <Real Name="Y">-169.48738</Real>
+        <Real Name="Z">52.280884</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-39.210472</Real>
+        <Real Name="Y">26.632309</Real>
+        <Real Name="Z">-17.789124</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-98.927322</Real>
+        <Real Name="Y">-31.457962</Real>
+        <Real Name="Z">122.95883</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8623897</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8623897</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8623897</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070910389</Real>
+        <Real Name="Y">0.60002661</Real>
+        <Real Name="Z">0.23202974</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0048952559</Real>
+        <Real Name="Y">0.67731196</Real>
+        <Real Name="Z">0.28846085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.082317621</Real>
+        <Real Name="Y">0.61437017</Real>
+        <Real Name="Z">0.17460552</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97352648</Real>
+        <Real Name="Y">0.63045281</Real>
+        <Real Name="Z">1.5739042</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9414199</Real>
+        <Real Name="Y">0.57218802</Real>
+        <Real Name="Z">1.6427277</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90231276</Real>
+        <Real Name="Y">0.69292659</Real>
+        <Real Name="Z">1.5601944</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3961918</Real>
+        <Real Name="Y">0.44673991</Real>
+        <Real Name="Z">1.1634068</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3341095</Real>
+        <Real Name="Y">0.47023207</Real>
+        <Real Name="Z">1.2323723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3417985</Real>
+        <Real Name="Y">0.43277121</Real>
+        <Real Name="Z">1.085892</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.641705</Real>
+        <Real Name="Y">0.31916115</Real>
+        <Real Name="Z">0.31268811</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7044376</Real>
+        <Real Name="Y">0.35033152</Real>
+        <Real Name="Z">0.24745506</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6271497</Real>
+        <Real Name="Y">0.227311</Real>
+        <Real Name="Z">0.29001635</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7801179</Real>
+        <Real Name="Y">0.39107811</Real>
+        <Real Name="Z">0.024208212</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6907265</Real>
+        <Real Name="Y">0.4211984</Real>
+        <Real Name="Z">0.0079519749</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8168737</Real>
+        <Real Name="Y">0.45616618</Real>
+        <Real Name="Z">0.083998442</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.17194727</Real>
+        <Real Name="Y">0.085135594</Real>
+        <Real Name="Z">-0.96141195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.70590931</Real>
+        <Real Name="Y">-2.0059803</Real>
+        <Real Name="Z">2.0445914</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5678463</Real>
+        <Real Name="Y">0.17405739</Real>
+        <Real Name="Z">2.0694497</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11849158</Real>
+        <Real Name="Y">-0.054997802</Real>
+        <Real Name="Z">0.29857841</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22700778</Real>
+        <Real Name="Y">-2.5166714</Real>
+        <Real Name="Z">-1.7612052</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.76408815</Real>
+        <Real Name="Y">-0.56530792</Real>
+        <Real Name="Z">1.2675197</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.075609341</Real>
+        <Real Name="Y">-0.020982973</Real>
+        <Real Name="Z">-0.67164433</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43072644</Real>
+        <Real Name="Y">-0.37800613</Real>
+        <Real Name="Z">-0.088924333</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.67114663</Real>
+        <Real Name="Y">0.1622881</Real>
+        <Real Name="Z">-0.29022893</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24561249</Real>
+        <Real Name="Y">0.35489783</Real>
+        <Real Name="Z">0.60152698</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31483996</Real>
+        <Real Name="Y">1.4505769</Real>
+        <Real Name="Z">1.644086</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3214753</Real>
+        <Real Name="Y">-0.13550517</Real>
+        <Real Name="Z">0.78884548</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.032272458</Real>
+        <Real Name="Y">0.054400727</Real>
+        <Real Name="Z">0.01519496</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63955498</Real>
+        <Real Name="Y">-0.38899109</Real>
+        <Real Name="Z">2.6539977</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.3011499</Real>
+        <Real Name="Y">-2.4382682</Real>
+        <Real Name="Z">3.0642931</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-165.6032</Real>
+        <Real Name="Y">-319.09833</Real>
+        <Real Name="Z">-377.07571</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.503132</Real>
+        <Real Name="Y">68.294342</Real>
+        <Real Name="Z">99.990547</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.58694</Real>
+        <Real Name="Y">141.80597</Real>
+        <Real Name="Z">72.057419</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.213585</Real>
+        <Real Name="Y">-15.085148</Real>
+        <Real Name="Z">-36.540001</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.3522186</Real>
+        <Real Name="Y">2.7178402</Real>
+        <Real Name="Z">14.700527</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1722336</Real>
+        <Real Name="Y">7.401041</Real>
+        <Real Name="Z">12.120731</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.218483</Real>
+        <Real Name="Y">-17.582417</Real>
+        <Real Name="Z">-31.266502</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.405327</Real>
+        <Real Name="Y">14.930759</Real>
+        <Real Name="Z">25.183987</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.5022907</Real>
+        <Real Name="Y">7.6179218</Real>
+        <Real Name="Z">15.801258</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-179.64093</Real>
+        <Real Name="Y">4.0047455</Real>
+        <Real Name="Z">101.13348</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">146.34767</Real>
+        <Real Name="Y">-33.248535</Real>
+        <Real Name="Z">-82.167084</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">72.247147</Real>
+        <Real Name="Y">9.3867035</Real>
+        <Real Name="Z">-49.163269</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.636139</Real>
+        <Real Name="Y">-310.98163</Real>
+        <Real Name="Z">-20.551819</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.298512</Real>
+        <Real Name="Y">116.73243</Real>
+        <Real Name="Z">-0.34326935</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.493881</Real>
+        <Real Name="Y">323.10428</Real>
+        <Real Name="Z">256.11969</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_Crescale_4Ranks_2RanksPerSimulation_d.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_Crescale_4Ranks_2RanksPerSimulation_d.xml
new file mode 100644 (file)
index 0000000..61185b2
--- /dev/null
@@ -0,0 +1,1696 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4533416426810541</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4533416426810541</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4533416426810541</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4533416426810541</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4529770401682987</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4529770401682987</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4529770401682987</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4529770401682987</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4529770401682987</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4529770401682987</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4538445949049317</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4538445949049317</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4664415360463359</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4664415360463359</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4664415360463359</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4664415360463359</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">19.965980763101861</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">19.968485132887473</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">19.980889243241126</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">19.980062319948811</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">19.980759213090892</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">17.453453490251562</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">17.453506858875539</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">17.453476707662581</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">17.453323916105862</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">17.453008641468017</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">17.46693625415659</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">17.438746227671768</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">17.467979614128392</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">19.867165295769901</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">19.861846122902911</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">19.856958427131957</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">19.853101257740974</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629305410083017</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">30.132005765759363</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.780900844935836</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">31.56590609570463</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">32.509043001832083</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">27.751678970021288</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">28.287533811180953</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">28.970160432537952</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.796985505313998</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">30.763659176540731</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">31.811778351333416</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">32.959434837962149</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">34.217252950350151</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">46.423884463455494</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">48.022617148626104</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">49.44039434181181</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">50.6214421321732</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673364533766927</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.160837447757872</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.797328416580694</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.583160590641803</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.525600603627176</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.286910028861024</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.822711501396711</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.505368273966667</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.332346138299432</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.29933508416401</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.333163573765734</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.455610176573746</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.684194902505123</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.47168134247088</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-28.075733200508481</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.498398089465141</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.683303049217514</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.004987833407605083</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858972</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391528</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.02498992600415597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208519</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13823960248430261</Real>
+        <Real Name="Y">-0.083001582473173879</Real>
+        <Real Name="Z">-0.55156788526044931</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807346912896504</Real>
+        <Real Name="Y">0.12594239723743825</Real>
+        <Real Name="Z">0.086340039099900012</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50558175484201939</Real>
+        <Real Name="Y">-0.2634720104901444</Real>
+        <Real Name="Z">-0.37043107548328896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.080341973608849884</Real>
+        <Real Name="Y">-0.036383374851252599</Real>
+        <Real Name="Z">0.26950251001929965</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0879938107726246</Real>
+        <Real Name="Y">-2.69925195488055</Real>
+        <Real Name="Z">-0.41161299800761325</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.005339856872981</Real>
+        <Real Name="Y">-0.4461332722971294</Real>
+        <Real Name="Z">1.1534368241800745</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046991365082634809</Real>
+        <Real Name="Y">-0.027139438957271552</Real>
+        <Real Name="Z">-0.6835695669642462</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.052027730439707112</Real>
+        <Real Name="Y">-0.42394701288611142</Real>
+        <Real Name="Z">-0.38240890291446689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2514527117216987</Real>
+        <Real Name="Y">0.072329295992862808</Real>
+        <Real Name="Z">-0.58384125172376988</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20047275659675184</Real>
+        <Real Name="Y">0.39459474035999648</Real>
+        <Real Name="Z">0.71751226731035556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21660158751017158</Real>
+        <Real Name="Y">1.2107968994948017</Real>
+        <Real Name="Z">0.86109126390401147</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3771064228719012</Real>
+        <Real Name="Y">-0.6610218165066043</Real>
+        <Real Name="Z">0.87071447867481888</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21701225376725289</Real>
+        <Real Name="Y">-0.090547598182204897</Real>
+        <Real Name="Z">-0.034702681691122401</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639425064679751</Real>
+        <Real Name="Y">0.9636306948577793</Real>
+        <Real Name="Z">2.5346418773965156</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37424921124689092</Real>
+        <Real Name="Y">-0.37914050295285695</Real>
+        <Real Name="Z">0.73119277083081202</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959196342</Real>
+        <Real Name="Y">10.126334215507086</Real>
+        <Real Name="Z">-383.9244463652023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773668</Real>
+        <Real Name="Y">8.7835602768706877</Real>
+        <Real Name="Z">109.98162207856127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818237</Real>
+        <Real Name="Y">125.90227601095691</Real>
+        <Real Name="Z">223.10402606189822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.9064510541798</Real>
+        <Real Name="Y">-91.873016441468678</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733365</Real>
+        <Real Name="Y">82.504344401698347</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041526</Real>
+        <Real Name="Y">45.329959216167893</Real>
+        <Real Name="Z">-56.291380508471349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448434</Real>
+        <Real Name="Y">-204.77938512046111</Real>
+        <Real Name="Z">21.695070286562498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013951</Real>
+        <Real Name="Y">47.5995038096992</Real>
+        <Real Name="Z">-24.246658126595179</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564435093</Real>
+        <Real Name="Y">-23.593576368970304</Real>
+        <Real Name="Z">144.65217639452101</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617443304291632</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617443304291632</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617443304291632</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0032054186348258198</Real>
+        <Real Name="Y">0.59435548274449934</Real>
+        <Real Name="Z">0.24342655091125015</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8497222820552182</Real>
+        <Real Name="Y">0.68437606471893797</Real>
+        <Real Name="Z">0.27217959369770789</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059027646851979969</Real>
+        <Real Name="Y">0.6029635157876253</Real>
+        <Real Name="Z">0.16614719400398739</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97829499731450853</Real>
+        <Real Name="Y">0.6299144912315745</Real>
+        <Real Name="Z">1.5700671387978535</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96126298090053985</Real>
+        <Real Name="Y">0.62367497352887391</Real>
+        <Real Name="Z">1.6640527612925282</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92746764561841244</Real>
+        <Real Name="Y">0.7058101299771784</Real>
+        <Real Name="Z">1.5414533180296004</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3931452561817828</Real>
+        <Real Name="Y">0.4472645323156248</Real>
+        <Real Name="Z">1.1770717342285122</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.333136255650663</Real>
+        <Real Name="Y">0.47706729341497189</Real>
+        <Real Name="Z">1.2454313252608686</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3360109780912803</Real>
+        <Real Name="Y">0.41501147886192113</Real>
+        <Real Name="Z">1.1073742937447371</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6467372244943661</Real>
+        <Real Name="Y">0.31551836505352099</Real>
+        <Real Name="Z">0.2991077012721734</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7053126649187766</Real>
+        <Real Name="Y">0.33248745075639236</Real>
+        <Real Name="Z">0.22532907083290254</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5972097644021528</Real>
+        <Real Name="Y">0.23785961832961167</Real>
+        <Real Name="Z">0.27306028001621269</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.776267579102236</Real>
+        <Real Name="Y">0.39581468318057955</Real>
+        <Real Name="Z">0.02280638813369219</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7118054274699295</Real>
+        <Real Name="Y">0.40988930811422691</Real>
+        <Real Name="Z">1.8152048150074878</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8065410277448353</Real>
+        <Real Name="Y">0.48370630292204742</Real>
+        <Real Name="Z">0.045629619423428067</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.23119859926007669</Real>
+        <Real Name="Y">-0.67559219245559921</Real>
+        <Real Name="Z">-0.13587295235995636</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.57913599798508952</Real>
+        <Real Name="Y">-0.78527457596849382</Real>
+        <Real Name="Z">0.6592949790317354</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6588701103218342</Real>
+        <Real Name="Y">-0.56538400690895863</Real>
+        <Real Name="Z">1.2068252110721474</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43158755044649255</Real>
+        <Real Name="Y">-0.11802262631409464</Real>
+        <Real Name="Z">0.15484336474374383</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.394821169028083</Real>
+        <Real Name="Y">1.0058559446835955</Real>
+        <Real Name="Z">0.41603056326946475</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4887245757703031</Real>
+        <Real Name="Y">0.58168228116694554</Real>
+        <Real Name="Z">0.10480673530986223</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.47005089005571027</Real>
+        <Real Name="Y">0.038271759882048735</Real>
+        <Real Name="Z">0.39311924274471871</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50536848877606455</Real>
+        <Real Name="Y">0.090726354208125012</Real>
+        <Real Name="Z">1.2387251231070362</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.4770802791140767</Real>
+        <Real Name="Y">-1.920391211227267</Real>
+        <Real Name="Z">2.0700457158404002</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2432159852471002</Real>
+        <Real Name="Y">0.31272042762456059</Real>
+        <Real Name="Z">-0.37294364242564582</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.28195379060523756</Real>
+        <Real Name="Y">0.82407227485259393</Real>
+        <Real Name="Z">-0.22650497232745814</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38892598799883082</Real>
+        <Real Name="Y">0.38053895524696962</Real>
+        <Real Name="Z">-0.85719555427795169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19157495656112886</Real>
+        <Real Name="Y">0.44222756428691568</Real>
+        <Real Name="Z">-0.27210028942252701</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39267657291452479</Real>
+        <Real Name="Y">-0.5033435191894422</Real>
+        <Real Name="Z">-1.0200625686719986</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7528768206480247</Real>
+        <Real Name="Y">0.89778817236084307</Real>
+        <Real Name="Z">0.10558303644508919</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.748241736276043</Real>
+        <Real Name="Y">58.177074179842862</Real>
+        <Real Name="Z">-374.77684682668234</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.092968902309984</Real>
+        <Real Name="Y">1.7552882498541038</Real>
+        <Real Name="Z">111.96450120062376</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.58918388476854</Real>
+        <Real Name="Y">65.668901548676402</Real>
+        <Real Name="Z">206.22919092339089</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.546939267231949</Real>
+        <Real Name="Y">-18.80171179699088</Real>
+        <Real Name="Z">-38.922137288559838</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.709499341369515</Real>
+        <Real Name="Y">-9.5268254634123686</Real>
+        <Real Name="Z">-24.56571304101719</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4344038999632431</Real>
+        <Real Name="Y">10.485491186555159</Real>
+        <Real Name="Z">12.995775688021681</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.563301687790798</Real>
+        <Real Name="Y">-7.3204477305478193</Real>
+        <Real Name="Z">-33.330651850184253</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-56.92486069629993</Real>
+        <Real Name="Y">11.312978269942533</Real>
+        <Real Name="Z">-15.031581643135979</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.623567075359702</Real>
+        <Real Name="Y">18.846802212186343</Real>
+        <Real Name="Z">56.478049254797355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-308.49921370738332</Real>
+        <Real Name="Y">-121.83118841677634</Real>
+        <Real Name="Z">255.21915923555008</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.42578213376686</Real>
+        <Real Name="Y">106.04679546093109</Real>
+        <Real Name="Z">-280.40200514527538</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">113.84325431406953</Real>
+        <Real Name="Y">55.012135114256665</Real>
+        <Real Name="Z">-58.144780877052909</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-59.063773017210224</Real>
+        <Real Name="Y">-239.98501471700408</Real>
+        <Real Name="Z">-1.2356876023677046</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.088233699015337</Real>
+        <Real Name="Y">45.502431022815948</Real>
+        <Real Name="Z">17.254881516591524</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-101.37916529321012</Real>
+        <Real Name="Y">24.657290879670427</Real>
+        <Real Name="Z">166.26784645530023</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8630383085942579</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8630383085942579</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8630383085942579</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070936847096142721</Real>
+        <Real Name="Y">0.60023726825374735</Real>
+        <Real Name="Z">0.23211289360005619</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0048983540227866915</Real>
+        <Real Name="Y">0.67752444012199364</Real>
+        <Real Name="Z">0.28854153869971511</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.08231866834823115</Real>
+        <Real Name="Y">0.61457987021424132</Real>
+        <Real Name="Z">0.1746863317530129</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97386401865018113</Real>
+        <Real Name="Y">0.63067318383951987</Real>
+        <Real Name="Z">1.5744525500146171</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94175721446914784</Real>
+        <Real Name="Y">0.57240945037424618</Real>
+        <Real Name="Z">1.6432770288573084</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90265055938969618</Real>
+        <Real Name="Y">0.69314702690529262</Real>
+        <Real Name="Z">1.5607419500004616</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3966757037776318</Real>
+        <Real Name="Y">0.44689583185961501</Real>
+        <Real Name="Z">1.1638141746823856</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3345928958810747</Real>
+        <Real Name="Y">0.47038806377202852</Real>
+        <Real Name="Z">1.2327790817254034</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3422830249504136</Real>
+        <Real Name="Y">0.43292689084228769</Real>
+        <Real Name="Z">1.0862988627959391</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6422779128884819</Real>
+        <Real Name="Y">0.31926981814508554</Real>
+        <Real Name="Z">0.31279295604456459</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7050101290450168</Real>
+        <Real Name="Y">0.35043978015327604</Real>
+        <Real Name="Z">0.24755936864898001</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6277213386492753</Real>
+        <Real Name="Y">0.22741991582373322</Real>
+        <Real Name="Z">0.29012094709131697</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7807368559617918</Real>
+        <Real Name="Y">0.39121661088542481</Real>
+        <Real Name="Z">0.024216704926686369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6913457333737421</Real>
+        <Real Name="Y">0.42133739363723771</Real>
+        <Real Name="Z">0.0079598894677483933</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8174940320380188</Real>
+        <Real Name="Y">0.45630675327832582</Real>
+        <Real Name="Z">0.084003842089898542</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.17177846180545889</Real>
+        <Real Name="Y">0.085081119988439924</Real>
+        <Real Name="Z">-0.9611226270681098</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.70612143799236671</Real>
+        <Real Name="Y">-2.0055538965678474</Real>
+        <Real Name="Z">2.0443902558064844</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5673538319736746</Real>
+        <Real Name="Y">0.17378308719763808</Real>
+        <Real Name="Z">2.0690936921840195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11843329071307521</Real>
+        <Real Name="Y">-0.054915824800081683</Real>
+        <Real Name="Z">0.29849746976011066</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22706233415100735</Real>
+        <Real Name="Y">-2.5165877894228506</Real>
+        <Real Name="Z">-1.7611906089499429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.76403622983952613</Real>
+        <Real Name="Y">-0.56527018564808673</Real>
+        <Real Name="Z">1.2673704956113794</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.075580300680439805</Real>
+        <Real Name="Y">-0.020971534741961062</Real>
+        <Real Name="Z">-0.67142714223920696</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43072346797860428</Real>
+        <Real Name="Y">-0.3780286930509813</Real>
+        <Real Name="Z">-0.088775924689156072</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.67101680858853485</Real>
+        <Real Name="Y">0.16226138231698556</Real>
+        <Real Name="Z">-0.29006970471613419</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.245563982673452</Real>
+        <Real Name="Y">0.35477865548783888</Real>
+        <Real Name="Z">0.60128909466553637</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31474509215152552</Real>
+        <Real Name="Y">1.4505381661346937</Real>
+        <Real Name="Z">1.6437510227967758</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3214226885114853</Real>
+        <Real Name="Y">-0.13563135869952744</Real>
+        <Real Name="Z">0.78852831638774545</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.032290993320444571</Real>
+        <Real Name="Y">0.054425079998993826</Real>
+        <Real Name="Z">0.015113211254563495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63954507890088341</Real>
+        <Real Name="Y">-0.38872926977114231</Real>
+        <Real Name="Z">2.6541266299395292</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.30062214035618001</Real>
+        <Real Name="Y">-2.4377624905386184</Real>
+        <Real Name="Z">3.0636183931268377</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-165.527660914671</Real>
+        <Real Name="Y">-318.8932701460285</Real>
+        <Real Name="Z">-376.84149598639755</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.501040063959437</Real>
+        <Real Name="Y">68.226204380031646</Real>
+        <Real Name="Z">99.897109670973222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.37820128150048</Real>
+        <Real Name="Y">141.64461557086685</Real>
+        <Real Name="Z">72.03233206924989</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.192634679887334</Real>
+        <Real Name="Y">-15.067962490556084</Real>
+        <Real Name="Z">-36.500024025499002</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.856274261024986</Real>
+        <Real Name="Y">-7.1053032520465731</Real>
+        <Real Name="Z">-24.533096817693995</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1641346072920271</Real>
+        <Real Name="Y">7.3930723897618833</Real>
+        <Real Name="Z">12.109756456019696</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.192911326111712</Real>
+        <Real Name="Y">-17.564858758714031</Real>
+        <Real Name="Z">-31.235321234832071</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.379104513720307</Real>
+        <Real Name="Y">14.912851350870135</Real>
+        <Real Name="Z">25.15429943626949</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.698581146011712</Real>
+        <Real Name="Y">17.432200760684676</Real>
+        <Real Name="Z">55.004386185735889</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-179.38352505836116</Real>
+        <Real Name="Y">4.046664645944702</Real>
+        <Real Name="Z">100.87346257263937</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">146.18889869697335</Real>
+        <Real Name="Y">-33.189855562561775</Real>
+        <Real Name="Z">-82.014670550916989</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">72.17661417760479</Real>
+        <Real Name="Y">9.3674026416856293</Real>
+        <Real Name="Z">-49.10737666511065</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.537770141743337</Real>
+        <Real Name="Y">-310.43955315354083</Real>
+        <Real Name="Z">-20.214926840106614</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.251555305822208</Real>
+        <Real Name="Y">116.63125492642176</Real>
+        <Real Name="Z">-0.34545140711514932</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.455757200559646</Real>
+        <Real Name="Y">322.60653669718056</Real>
+        <Real Name="Z">255.7210171367845</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4529770401682987</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4529770401682987</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4529770401682987</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4529770401682987</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4533416426810541</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4533416426810541</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4533416426810541</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4533416426810541</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4533416426810541</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4533416426810541</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4664415360463359</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4664415360463359</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4538445949049317</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4538445949049317</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4538445949049317</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4538445949049317</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">17.432463115567113</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">17.434400342163482</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">17.454499472319419</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">17.4532485451737</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">17.453370226865527</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">19.981210497609418</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">19.981235490474045</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">19.980707223178523</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">19.979475581586271</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">19.977409600535399</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">19.884996659222963</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">19.872501748470711</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">19.872858859446282</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">17.467079888299793</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">17.465611983621312</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">17.463963292609865</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">17.46220195018045</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">27.096610978600332</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">27.017445687187806</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">27.034362051092462</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">27.124375073922767</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">27.363861676029565</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">33.61010415010643</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.866998685805235</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">36.272834197094298</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.814362871796284</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">39.470588718599231</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">41.21161618390515</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">42.961785648986883</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">44.705678806262569</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">35.540942268806042</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">36.939491569134006</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">38.39143839793303</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">39.872285970293277</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673364533766927</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5717298803356723</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5685471140843887</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6598110640604133</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8991759844753844</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.626210458844021</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.883080001678199</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.289443780262783</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.832204096557021</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.49049592441084</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.2345073388353</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-23.004246071510373</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.747782117810488</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-18.008783897170797</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.408801102177243</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.862396621987713</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.345005536777375</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.004987833407605083</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858972</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391528</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.02498992600415597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208519</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.20819690585540773</Real>
+        <Real Name="Y">-0.71831964871349085</Real>
+        <Real Name="Z">0.011078438999830157</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.65627408040347335</Real>
+        <Real Name="Y">-0.44130069592945115</Real>
+        <Real Name="Z">-0.19586161682440933</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.07944772612600022</Real>
+        <Real Name="Y">-1.3403514765108808</Real>
+        <Real Name="Z">0.094211853505395182</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43983396430402821</Real>
+        <Real Name="Y">-0.12730113827963044</Real>
+        <Real Name="Z">0.16848744653097211</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1064634752554481</Real>
+        <Real Name="Y">1.208306314237934</Real>
+        <Real Name="Z">0.58865730101337532</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3857124030917944</Real>
+        <Real Name="Y">0.65412452380296571</Real>
+        <Real Name="Z">0.10516368028532735</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.41357531425471322</Real>
+        <Real Name="Y">0.03909994936372093</Real>
+        <Real Name="Z">0.41653530543680806</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.30958260222840822</Real>
+        <Real Name="Y">0.032508253652296773</Real>
+        <Real Name="Z">1.2155924310115984</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7555728294294284</Real>
+        <Real Name="Y">-2.0294504264852296</Real>
+        <Real Name="Z">1.568589118909621</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25622123762474486</Real>
+        <Real Name="Y">0.31483429896995041</Real>
+        <Real Name="Z">-0.34178744751437573</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.1457763418811992</Real>
+        <Real Name="Y">0.34295833952026589</Real>
+        <Real Name="Z">-0.4239403762530316</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019644304201244064</Real>
+        <Real Name="Y">0.5193023809855738</Real>
+        <Real Name="Z">-0.45124050611198896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15257163555120895</Real>
+        <Real Name="Y">0.53524540919668817</Real>
+        <Real Name="Z">-0.26925935975066168</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25467201556722202</Real>
+        <Real Name="Y">-0.76836408689837199</Real>
+        <Real Name="Z">-1.2156468083482905</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.9200810679380822</Real>
+        <Real Name="Y">1.1308821580758028</Real>
+        <Real Name="Z">-1.0483019686667092</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959196342</Real>
+        <Real Name="Y">10.126334215507086</Real>
+        <Real Name="Z">-383.9244463652023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773668</Real>
+        <Real Name="Y">8.7835602768706877</Real>
+        <Real Name="Z">109.98162207856127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818237</Real>
+        <Real Name="Y">125.90227601095691</Real>
+        <Real Name="Z">223.10402606189822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.9064510541798</Real>
+        <Real Name="Y">-91.873016441468678</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733365</Real>
+        <Real Name="Y">82.504344401698347</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041526</Real>
+        <Real Name="Y">45.329959216167893</Real>
+        <Real Name="Z">-56.291380508471349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448434</Real>
+        <Real Name="Y">-204.77938512046111</Real>
+        <Real Name="Z">21.695070286562498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013951</Real>
+        <Real Name="Y">47.5995038096992</Real>
+        <Real Name="Z">-24.246658126595179</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564435093</Real>
+        <Real Name="Y">-23.593576368970304</Real>
+        <Real Name="Z">144.65217639452101</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617793935156957</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617793935156957</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617793935156957</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059793692859869303</Real>
+        <Real Name="Y">0.59953400396752021</Real>
+        <Real Name="Z">0.2388390069675301</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8576811740684211</Real>
+        <Real Name="Y">0.68761048152703708</Real>
+        <Real Name="Z">0.2749401801621878</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062417700871849807</Real>
+        <Real Name="Y">0.61123401941405853</Real>
+        <Real Name="Z">0.16241818018350174</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97409751688961532</Real>
+        <Real Name="Y">0.63061710424181705</Real>
+        <Real Name="Z">1.5710407352303515</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9443794453458535</Real>
+        <Real Name="Y">0.59302498947303739</Real>
+        <Real Name="Z">1.653901989933201</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90847655626505897</Real>
+        <Real Name="Y">0.697022537071464</Real>
+        <Real Name="Z">1.5499095635302913</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3962842809990219</Real>
+        <Real Name="Y">0.4467643031890059</Real>
+        <Real Name="Z">1.1684215551468071</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3309315146225575</Real>
+        <Real Name="Y">0.47327215592630478</Real>
+        <Real Name="Z">1.2331414753429919</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3460111471394101</Real>
+        <Real Name="Y">0.43152559410272279</Real>
+        <Real Name="Z">1.0884046059590458</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6430681185131562</Real>
+        <Real Name="Y">0.31611287368388413</Real>
+        <Real Name="Z">0.30753242383486284</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7025476557267782</Real>
+        <Real Name="Y">0.33859743160838085</Real>
+        <Real Name="Z">0.23598560204805641</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6091514096215693</Real>
+        <Real Name="Y">0.22967638577081845</Real>
+        <Real Name="Z">0.28427927748393794</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7790075296131889</Real>
+        <Real Name="Y">0.39112039240952656</Real>
+        <Real Name="Z">0.024515418839385145</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6971540428335388</Real>
+        <Real Name="Y">0.4209940258640596</Real>
+        <Real Name="Z">1.8466729607295254</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8182482709551107</Real>
+        <Real Name="Y">0.47035996572404681</Real>
+        <Real Name="Z">0.061170195333981575</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11743535595992063</Real>
+        <Real Name="Y">-0.020589687898528129</Real>
+        <Real Name="Z">-0.72717867118703583</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5002204721146688</Real>
+        <Real Name="Y">-0.57590196059373766</Real>
+        <Real Name="Z">1.0901198537394707</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0620370072809848</Real>
+        <Real Name="Y">0.42420743098854952</Real>
+        <Real Name="Z">0.73698577042290292</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10073298485405671</Real>
+        <Real Name="Y">-0.038075009936564604</Real>
+        <Real Name="Z">0.28585144461079898</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.65074857926027807</Real>
+        <Real Name="Y">-2.729400180972942</Real>
+        <Real Name="Z">-1.0756805411136625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.87473774873170318</Real>
+        <Real Name="Y">-0.50788777118663431</Real>
+        <Real Name="Z">1.1749486520852841</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.060028739345079782</Real>
+        <Real Name="Y">-0.022461550799644583</Real>
+        <Real Name="Z">-0.67837131488744518</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22877090311155915</Real>
+        <Real Name="Y">-0.41849066725101824</Real>
+        <Real Name="Z">-0.221071293907428</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46794569502958211</Real>
+        <Real Name="Y">0.10877417281980811</Real>
+        <Real Name="Z">-0.44855521167634116</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22472354079987431</Real>
+        <Real Name="Y">0.38157233679528391</Real>
+        <Real Name="Z">0.66937503910741891</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019274446763446307</Real>
+        <Real Name="Y">1.4427036357621008</Real>
+        <Real Name="Z">1.1637752658943299</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9405886860340211</Real>
+        <Real Name="Y">-0.49718132762288458</Real>
+        <Real Name="Z">0.66015826661969623</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11612346703212151</Real>
+        <Real Name="Y">-0.095192165405538529</Real>
+        <Real Name="Z">-0.071082153043878632</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2098923139568001</Real>
+        <Real Name="Y">0.50508613460436069</Real>
+        <Real Name="Z">2.9769091149076123</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.097577891697876423</Real>
+        <Real Name="Y">-1.0097860654825679</Real>
+        <Real Name="Z">2.2183800069656185</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-67.302462639745158</Real>
+        <Real Name="Y">-110.64248297234329</Real>
+        <Real Name="Z">-418.24150034948707</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45237318113677105</Real>
+        <Real Name="Y">35.607030973322566</Real>
+        <Real Name="Z">108.87426169011681</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">177.20735392596802</Real>
+        <Real Name="Y">149.0930802152904</Real>
+        <Real Name="Z">168.37698517722458</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.754512298263762</Real>
+        <Real Name="Y">-14.358944015283548</Real>
+        <Real Name="Z">-37.655994114795718</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.752800573871781</Real>
+        <Real Name="Y">-8.0144376026663249</Real>
+        <Real Name="Z">-23.776820413504396</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3113639322056088</Real>
+        <Real Name="Y">7.678931896975044</Real>
+        <Real Name="Z">12.78325964823749</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.169954431017089</Real>
+        <Real Name="Y">-14.361819522066106</Real>
+        <Real Name="Z">-32.984273217971278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.436282829475125</Real>
+        <Real Name="Y">12.131405835280525</Real>
+        <Real Name="Z">27.161552743220817</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.929620541471905</Real>
+        <Real Name="Y">16.924863407760405</Real>
+        <Real Name="Z">54.472275354813085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-257.21678461319459</Real>
+        <Real Name="Y">-51.56276408498104</Real>
+        <Real Name="Z">176.20611126535306</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">211.91807729075879</Real>
+        <Real Name="Y">25.16926446972866</Real>
+        <Real Name="Z">-196.6277774154552</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.550124253595854</Real>
+        <Real Name="Y">32.920611258491732</Real>
+        <Real Name="Z">-53.854495222552508</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.663347320365233</Real>
+        <Real Name="Y">-234.86950914037746</Real>
+        <Real Name="Z">8.1782804921192565</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.244024191983868</Real>
+        <Real Name="Y">75.898571544251965</Real>
+        <Real Name="Z">-10.557474699414968</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.701309886170634</Real>
+        <Real Name="Y">78.386197736616396</Real>
+        <Real Name="Z">217.64560906209596</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8618277592468653</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8618277592468653</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8618277592468653</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0014069278004128249</Real>
+        <Real Name="Y">0.58937685811507856</Real>
+        <Real Name="Z">0.24144878276685186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.853553557788741</Real>
+        <Real Name="Y">0.67563325067115731</Real>
+        <Real Name="Z">0.2818025791123121</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076755501038651142</Real>
+        <Real Name="Y">0.59848891318961295</Real>
+        <Real Name="Z">0.18312313349245249</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98174905775924759</Real>
+        <Real Name="Y">0.62906397935409408</Real>
+        <Real Name="Z">1.5713787816432805</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97338454237078997</Real>
+        <Real Name="Y">0.63086891030034298</Real>
+        <Real Name="Z">1.6667155295770921</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.93986610948206983</Real>
+        <Real Name="Y">0.70999317365413239</Real>
+        <Real Name="Z">1.5420768609970585</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3891787364915129</Real>
+        <Real Name="Y">0.44754393159115136</Real>
+        <Real Name="Z">1.1801831599895558</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3377006801790097</Real>
+        <Real Name="Y">0.47834682343480689</Real>
+        <Real Name="Z">1.25477210000317</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3263434064688995</Real>
+        <Real Name="Y">0.40040039900621183</Real>
+        <Real Name="Z">1.1254883061515417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6487010599723173</Real>
+        <Real Name="Y">0.31801068176663755</Real>
+        <Real Name="Z">0.29600229864558064</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7081426464735476</Real>
+        <Real Name="Y">0.34124813635823492</Real>
+        <Real Name="Z">0.22466481271903704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6023210148850311</Real>
+        <Real Name="Y">0.2405065419340956</Real>
+        <Real Name="Z">0.26431132001571411</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7747621258158073</Real>
+        <Real Name="Y">0.39903967645621313</Real>
+        <Real Name="Z">0.020699563610929839</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7154972476928771</Real>
+        <Real Name="Y">0.40798479712127961</Real>
+        <Real Name="Z">1.8078950413881696</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7880558854553925</Real>
+        <Real Name="Y">0.48863313014779819</Real>
+        <Real Name="Z">0.051660949404503352</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.20826609055509204</Real>
+        <Real Name="Y">-0.5749601951769916</Real>
+        <Real Name="Z">-0.34580549203053057</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.32976324581811828</Real>
+        <Real Name="Y">-1.4140328125099884</Real>
+        <Real Name="Z">1.6378573660568236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4336515778289574</Real>
+        <Real Name="Y">-0.74041669793815268</Real>
+        <Real Name="Z">2.8914270275494705</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42187202603592078</Real>
+        <Real Name="Y">-0.10213428021780573</Real>
+        <Real Name="Z">0.15944198616237618</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.572448756471774</Real>
+        <Real Name="Y">0.81530116008555953</Real>
+        <Real Name="Z">0.25442505972236801</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.585834201068703</Real>
+        <Real Name="Y">0.46241396419408015</Real>
+        <Real Name="Z">0.026092866034380158</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.52776668539075178</Real>
+        <Real Name="Y">0.026134733529718093</Real>
+        <Real Name="Z">0.37466539013867683</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.58015765331100333</Real>
+        <Real Name="Y">0.21098223759061741</Real>
+        <Real Name="Z">1.0747131413197228</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.98482891598480116</Real>
+        <Real Name="Y">-1.7498360934159871</Real>
+        <Real Name="Z">2.3636227101741798</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23112357838818126</Real>
+        <Real Name="Y">0.30726873012991829</Real>
+        <Real Name="Z">-0.40360397748720916</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39105044254149657</Real>
+        <Real Name="Y">1.2823810838784846</Real>
+        <Real Name="Z">0.039069950613251858</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.81924545242369384</Real>
+        <Real Name="Y">0.30287171201255064</Real>
+        <Real Name="Z">-1.2708976233836315</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19976353622120896</Real>
+        <Real Name="Y">0.37662456920501713</Real>
+        <Real Name="Z">-0.25063443379907813</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.49562284993124217</Real>
+        <Real Name="Y">0.018943423227078676</Real>
+        <Real Name="Z">-0.85222660185849997</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7342134742608928</Real>
+        <Real Name="Y">0.28865674571011679</Real>
+        <Real Name="Z">1.2314566497401547</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-78.951546950868362</Real>
+        <Real Name="Y">62.340240570983326</Real>
+        <Real Name="Z">-366.78863927627623</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.3955316253394088</Real>
+        <Real Name="Y">0.77530243716340408</Real>
+        <Real Name="Z">112.24786868621561</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">135.46726443830312</Real>
+        <Real Name="Y">3.0722661162647995</Real>
+        <Real Name="Z">132.26826214510038</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.735702723357264</Real>
+        <Real Name="Y">-23.668381707604091</Real>
+        <Real Name="Z">-37.753579654402202</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6765503437333962</Real>
+        <Real Name="Y">7.050029653287659</Real>
+        <Real Name="Z">14.371370566975486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.3388088747683184</Real>
+        <Real Name="Y">12.819192628477367</Real>
+        <Real Name="Z">11.901921532928256</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.812824572099032</Real>
+        <Real Name="Y">-4.0081322090709932</Real>
+        <Real Name="Z">-32.320334515795025</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.249292484415705</Real>
+        <Real Name="Y">9.0968805886089967</Real>
+        <Real Name="Z">-18.083367368005113</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.158072196027469</Real>
+        <Real Name="Y">4.2742758038414905</Real>
+        <Real Name="Z">18.145890901368801</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-314.72255147079636</Real>
+        <Real Name="Y">-129.76591204214981</Real>
+        <Real Name="Z">277.36881083698927</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">243.22351487952506</Real>
+        <Real Name="Y">99.170299614333544</Real>
+        <Real Name="Z">-284.62936731532733</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">118.5740147339023</Real>
+        <Real Name="Y">60.27459386671687</Real>
+        <Real Name="Z">-65.461916351323282</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-76.431199942299656</Real>
+        <Real Name="Y">-323.40092280550402</Real>
+        <Real Name="Z">-34.972717381993903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">20.01566899710113</Real>
+        <Real Name="Y">58.382734621001141</Real>
+        <Real Name="Z">26.734178435328459</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.696499706718043</Real>
+        <Real Name="Y">163.58753286365032</Real>
+        <Real Name="Z">246.97161875821678</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_Crescale_4Ranks_2RanksPerSimulation_s.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_Crescale_4Ranks_2RanksPerSimulation_s.xml
new file mode 100644 (file)
index 0000000..5952089
--- /dev/null
@@ -0,0 +1,1696 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.453341</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.453341</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.453341</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.453341</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4529767</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4529767</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4529767</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4529767</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4529767</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4529767</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4538445</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4538445</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4664402</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4664402</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4664402</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4664402</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">19.965998</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">19.96855</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">19.980904</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">19.980106</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">19.980774</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">17.453478</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">17.453413</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">17.453575</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">17.453312</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">17.452906</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">17.46685</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">17.438677</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">17.467831</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">19.86713</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">19.86174</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">19.856911</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">19.853054</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629341</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">30.132036</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.78092</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">31.565922</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">32.50909</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">27.75164</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">28.287493</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">28.970108</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.796928</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">30.763613</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">31.811718</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">32.959351</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">34.217148</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">46.423836</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">48.022594</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">49.440414</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">50.62146</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733761</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.160797</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.797328</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.583126</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.525627</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.286845</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.822763</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.505217</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.3323</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.299391</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.333189</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.455595</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.684238</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.471684</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-28.075832</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.498482</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.683384</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951088</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154483</Real>
+        <Real Name="Y">0.6098752</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829585</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13824016</Real>
+        <Real Name="Y">-0.083002254</Real>
+        <Real Name="Z">-0.55156869</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807338</Real>
+        <Real Name="Y">0.12595503</Real>
+        <Real Name="Z">0.08634457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50557774</Real>
+        <Real Name="Y">-0.26347136</Real>
+        <Real Name="Z">-0.37042338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.080341488</Real>
+        <Real Name="Y">-0.036381338</Real>
+        <Real Name="Z">0.26949763</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0880266</Real>
+        <Real Name="Y">-2.6992292</Real>
+        <Real Name="Z">-0.41159728</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0053114</Real>
+        <Real Name="Y">-0.44618708</Real>
+        <Real Name="Z">1.1535001</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046993256</Real>
+        <Real Name="Y">-0.027141552</Real>
+        <Real Name="Z">-0.68357778</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.05199106</Real>
+        <Real Name="Y">-0.4239299</Real>
+        <Real Name="Z">-0.38236642</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25138497</Real>
+        <Real Name="Y">0.072344288</Real>
+        <Real Name="Z">-0.58373684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20046791</Real>
+        <Real Name="Y">0.39459822</Real>
+        <Real Name="Z">0.71750742</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21663751</Real>
+        <Real Name="Y">1.2108051</Real>
+        <Real Name="Z">0.86115432</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3770657</Real>
+        <Real Name="Y">-0.66109234</Real>
+        <Real Name="Z">0.87071204</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2170116</Real>
+        <Real Name="Y">-0.090551436</Real>
+        <Real Name="Z">-0.034702588</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639975</Real>
+        <Real Name="Y">0.96362239</Real>
+        <Real Name="Z">2.5346055</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37430629</Real>
+        <Real Name="Y">-0.3790665</Real>
+        <Real Name="Z">0.73122531</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9518738</Real>
+        <Real Name="Y">10.126022</Real>
+        <Real Name="Z">-383.92468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054081</Real>
+        <Real Name="Y">8.7835617</Real>
+        <Real Name="Z">109.98161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.0733</Real>
+        <Real Name="Y">125.90257</Real>
+        <Real Name="Z">223.10434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850433</Real>
+        <Real Name="Y">8.0224648</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90619</Real>
+        <Real Name="Y">-91.872864</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62735</Real>
+        <Real Name="Y">82.504333</Real>
+        <Real Name="Z">-270.19894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937</Real>
+        <Real Name="Y">45.329948</Real>
+        <Real Name="Z">-56.291359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365723</Real>
+        <Real Name="Y">-204.77948</Real>
+        <Real Name="Z">21.695251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097099</Real>
+        <Real Name="Y">47.599464</Real>
+        <Real Name="Z">-24.246674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.29879</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65219</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617443</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617443</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617443</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0032054209</Real>
+        <Real Name="Y">0.59435564</Real>
+        <Real Name="Z">0.24342653</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8497221</Real>
+        <Real Name="Y">0.68437618</Real>
+        <Real Name="Z">0.27217951</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059027661</Real>
+        <Real Name="Y">0.60296375</Real>
+        <Real Name="Z">0.1661472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97829503</Real>
+        <Real Name="Y">0.62991452</Real>
+        <Real Name="Z">1.5700674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96126294</Real>
+        <Real Name="Y">0.62367493</Real>
+        <Real Name="Z">1.664053</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92746776</Real>
+        <Real Name="Y">0.70581025</Real>
+        <Real Name="Z">1.5414536</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3931451</Real>
+        <Real Name="Y">0.44726452</Real>
+        <Real Name="Z">1.1770718</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.333136</Real>
+        <Real Name="Y">0.47706738</Real>
+        <Real Name="Z">1.2454312</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3360111</Real>
+        <Real Name="Y">0.41501147</Real>
+        <Real Name="Z">1.1073742</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6467373</Real>
+        <Real Name="Y">0.31551835</Real>
+        <Real Name="Z">0.29910767</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7053126</Real>
+        <Real Name="Y">0.33248743</Real>
+        <Real Name="Z">0.22532892</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5972096</Real>
+        <Real Name="Y">0.23785976</Real>
+        <Real Name="Z">0.27306023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7762678</Real>
+        <Real Name="Y">0.39581466</Real>
+        <Real Name="Z">0.022806389</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7118056</Real>
+        <Real Name="Y">0.40988934</Real>
+        <Real Name="Z">1.8152047</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8065412</Real>
+        <Real Name="Y">0.48370624</Real>
+        <Real Name="Z">0.045629635</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.23119716</Real>
+        <Real Name="Y">-0.67559189</Real>
+        <Real Name="Z">-0.13587275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.57912636</Real>
+        <Real Name="Y">-0.78530377</Real>
+        <Real Name="Z">0.65928555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6588578</Real>
+        <Real Name="Y">-0.56534785</Real>
+        <Real Name="Z">1.206836</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43158776</Real>
+        <Real Name="Y">-0.1180234</Real>
+        <Real Name="Z">0.15484269</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3948156</Real>
+        <Real Name="Y">1.0058326</Real>
+        <Real Name="Z">0.41608512</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4887097</Real>
+        <Real Name="Y">0.58174098</Real>
+        <Real Name="Z">0.10477537</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.47005975</Real>
+        <Real Name="Y">0.038271975</Real>
+        <Real Name="Z">0.39312169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50544786</Real>
+        <Real Name="Y">0.090705983</Real>
+        <Real Name="Z">1.2386584</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.4770308</Real>
+        <Real Name="Y">-1.9203808</Real>
+        <Real Name="Z">2.070045</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24321488</Real>
+        <Real Name="Y">0.31271866</Real>
+        <Real Name="Z">-0.37294558</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2819958</Real>
+        <Real Name="Y">0.82409883</Real>
+        <Real Name="Z">-0.22653885</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38890299</Real>
+        <Real Name="Y">0.38052893</Real>
+        <Real Name="Z">-0.85718012</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19157502</Real>
+        <Real Name="Y">0.44223043</Real>
+        <Real Name="Z">-0.27210075</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39267418</Real>
+        <Real Name="Y">-0.50335544</Real>
+        <Real Name="Z">-1.0200632</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7528665</Real>
+        <Real Name="Y">0.89777505</Real>
+        <Real Name="Z">0.10560168</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.7481689</Real>
+        <Real Name="Y">58.177277</Real>
+        <Real Name="Z">-374.77686</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.0929718</Real>
+        <Real Name="Y">1.7552185</Real>
+        <Real Name="Z">111.96458</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.5889</Real>
+        <Real Name="Y">65.669197</Real>
+        <Real Name="Z">206.22922</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.546822</Real>
+        <Real Name="Y">-18.80162</Real>
+        <Real Name="Z">-38.92215</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.709515</Real>
+        <Real Name="Y">-9.5268383</Real>
+        <Real Name="Z">-24.565697</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4343719</Real>
+        <Real Name="Y">10.485462</Real>
+        <Real Name="Z">12.995796</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.563263</Real>
+        <Real Name="Y">-7.3204346</Real>
+        <Real Name="Z">-33.330658</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-56.924789</Real>
+        <Real Name="Y">11.312946</Real>
+        <Real Name="Z">-15.031494</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.62352</Real>
+        <Real Name="Y">18.846767</Real>
+        <Real Name="Z">56.478004</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-308.49896</Real>
+        <Real Name="Y">-121.83099</Real>
+        <Real Name="Z">255.21877</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.42627</Real>
+        <Real Name="Y">106.04654</Real>
+        <Real Name="Z">-280.40195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">113.84319</Real>
+        <Real Name="Y">55.011841</Real>
+        <Real Name="Z">-58.144478</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-59.065125</Real>
+        <Real Name="Y">-239.98497</Real>
+        <Real Name="Z">-1.2354736</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.0885887</Real>
+        <Real Name="Y">45.502495</Real>
+        <Real Name="Z">17.254639</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-101.37862</Real>
+        <Real Name="Y">24.657112</Real>
+        <Real Name="Z">166.26773</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8630382</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8630382</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8630382</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070936927</Real>
+        <Real Name="Y">0.60023731</Real>
+        <Real Name="Z">0.23211288</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.004898244</Real>
+        <Real Name="Y">0.67752439</Real>
+        <Real Name="Z">0.28854164</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.082318686</Real>
+        <Real Name="Y">0.61458009</Real>
+        <Real Name="Z">0.17468637</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97386396</Real>
+        <Real Name="Y">0.63067299</Real>
+        <Real Name="Z">1.5744523</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94175726</Real>
+        <Real Name="Y">0.57240927</Real>
+        <Real Name="Z">1.6432768</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90265059</Real>
+        <Real Name="Y">0.69314706</Real>
+        <Real Name="Z">1.5607421</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3966759</Real>
+        <Real Name="Y">0.4468959</Real>
+        <Real Name="Z">1.1638138</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3345932</Real>
+        <Real Name="Y">0.47038803</Real>
+        <Real Name="Z">1.2327789</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.342283</Real>
+        <Real Name="Y">0.43292686</Real>
+        <Real Name="Z">1.0862987</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6422782</Real>
+        <Real Name="Y">0.31926984</Real>
+        <Real Name="Z">0.31279296</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7050102</Real>
+        <Real Name="Y">0.35043994</Real>
+        <Real Name="Z">0.24755931</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6277217</Real>
+        <Real Name="Y">0.22741994</Real>
+        <Real Name="Z">0.2901209</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7807364</Real>
+        <Real Name="Y">0.39121646</Real>
+        <Real Name="Z">0.024216719</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6913455</Real>
+        <Real Name="Y">0.42133743</Real>
+        <Real Name="Z">0.0079593658</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8174937</Real>
+        <Real Name="Y">0.45630684</Real>
+        <Real Name="Z">0.084003597</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.17178163</Real>
+        <Real Name="Y">0.085084774</Real>
+        <Real Name="Z">-0.96112388</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.70608383</Real>
+        <Real Name="Y">-2.0055332</Real>
+        <Real Name="Z">2.0444255</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5673654</Real>
+        <Real Name="Y">0.1737687</Real>
+        <Real Name="Z">2.069087</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11843216</Real>
+        <Real Name="Y">-0.054910161</Real>
+        <Real Name="Z">0.2984924</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22709711</Real>
+        <Real Name="Y">-2.5166426</Real>
+        <Real Name="Z">-1.7611006</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.76404464</Real>
+        <Real Name="Y">-0.56527424</Real>
+        <Real Name="Z">1.2674021</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.075581066</Real>
+        <Real Name="Y">-0.020968232</Real>
+        <Real Name="Z">-0.67141628</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43079448</Real>
+        <Real Name="Y">-0.3780458</Real>
+        <Real Name="Z">-0.088775367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.67109656</Real>
+        <Real Name="Y">0.16224378</Real>
+        <Real Name="Z">-0.29023308</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24556297</Real>
+        <Real Name="Y">0.35477701</Real>
+        <Real Name="Z">0.60128409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31471321</Real>
+        <Real Name="Y">1.4505299</Real>
+        <Real Name="Z">1.6437711</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3214371</Real>
+        <Real Name="Y">-0.13563515</Real>
+        <Real Name="Z">0.78853083</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.032291599</Real>
+        <Real Name="Y">0.054423083</Real>
+        <Real Name="Z">0.015112313</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63952196</Real>
+        <Real Name="Y">-0.38871324</Real>
+        <Real Name="Z">2.6541297</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.30065101</Real>
+        <Real Name="Y">-2.4377267</Real>
+        <Real Name="Z">3.063637</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-165.52742</Real>
+        <Real Name="Y">-318.89148</Real>
+        <Real Name="Z">-376.84265</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.500896</Real>
+        <Real Name="Y">68.225723</Real>
+        <Real Name="Z">99.897476</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.3775</Real>
+        <Real Name="Y">141.64369</Real>
+        <Real Name="Z">72.032928</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.192741</Real>
+        <Real Name="Y">-15.068031</Real>
+        <Real Name="Z">-36.500061</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.856251</Real>
+        <Real Name="Y">-7.1052742</Real>
+        <Real Name="Z">-24.533096</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1641312</Real>
+        <Real Name="Y">7.3930855</Real>
+        <Real Name="Z">12.109745</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.193039</Real>
+        <Real Name="Y">-17.564827</Real>
+        <Real Name="Z">-31.235287</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.379238</Real>
+        <Real Name="Y">14.912846</Real>
+        <Real Name="Z">25.154278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.698662</Real>
+        <Real Name="Y">17.432201</Real>
+        <Real Name="Z">55.004425</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-179.38477</Real>
+        <Real Name="Y">4.0460052</Real>
+        <Real Name="Z">100.87669</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">146.18936</Real>
+        <Real Name="Y">-33.189606</Real>
+        <Real Name="Z">-82.017616</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">72.177094</Real>
+        <Real Name="Y">9.3680573</Real>
+        <Real Name="Z">-49.108437</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.538246</Real>
+        <Real Name="Y">-310.43915</Real>
+        <Real Name="Z">-20.21344</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.251347</Real>
+        <Real Name="Y">116.63049</Real>
+        <Real Name="Z">-0.34515381</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.456909</Real>
+        <Real Name="Y">322.60626</Real>
+        <Real Name="Z">255.72025</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4529767</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4529767</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4529767</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4529767</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.453341</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.453341</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.453341</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.453341</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.453341</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.453341</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4664402</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4664402</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4538445</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4538445</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4538445</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4538445</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">17.432463</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">17.434389</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">17.454576</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">17.453314</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">17.453318</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">19.98122</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">19.981276</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">19.980732</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">19.979424</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">19.977308</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">19.884954</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">19.872499</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">19.872766</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">17.466978</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">17.465488</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">17.463848</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">17.462166</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">27.096624</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">27.017441</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">27.034367</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">27.124359</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">27.363819</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">33.610168</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.867058</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">36.272888</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.814381</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">39.470562</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">41.211563</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">42.961723</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">44.705627</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">35.540833</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">36.939381</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">38.391346</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">39.872204</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733761</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5717344</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5684748</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6597281</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8991842</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.626259</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.883093</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.289467</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.832268</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.490564</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.234512</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-23.004202</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.747839</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-18.008776</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.408813</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.862419</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.344959</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951088</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154483</Real>
+        <Real Name="Y">0.6098752</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829585</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.2081964</Real>
+        <Real Name="Y">-0.7183184</Real>
+        <Real Name="Z">0.011077392</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.65627712</Real>
+        <Real Name="Y">-0.44132945</Real>
+        <Real Name="Z">-0.19586644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.079432383</Real>
+        <Real Name="Y">-1.3403528</Real>
+        <Real Name="Z">0.0942358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43983412</Real>
+        <Real Name="Y">-0.12730011</Real>
+        <Real Name="Z">0.16848481</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1064552</Real>
+        <Real Name="Y">1.2083107</Real>
+        <Real Name="Z">0.58867824</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3857259</Real>
+        <Real Name="Y">0.65410167</Real>
+        <Real Name="Z">0.10518272</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.41357264</Real>
+        <Real Name="Y">0.039098304</Real>
+        <Real Name="Z">0.41653091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.30952451</Real>
+        <Real Name="Y">0.032534141</Real>
+        <Real Name="Z">1.21565</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7555673</Real>
+        <Real Name="Y">-2.029453</Real>
+        <Real Name="Z">1.5685941</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25622329</Real>
+        <Real Name="Y">0.31483555</Real>
+        <Real Name="Z">-0.34178945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.14576393</Real>
+        <Real Name="Y">0.34296301</Real>
+        <Real Name="Z">-0.42390847</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.0196642</Real>
+        <Real Name="Y">0.51929116</Real>
+        <Real Name="Z">-0.45123479</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1525732</Real>
+        <Real Name="Y">0.53524446</Real>
+        <Real Name="Z">-0.26926085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25469711</Real>
+        <Real Name="Y">-0.76836795</Real>
+        <Real Name="Z">-1.2156236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.92007476</Real>
+        <Real Name="Y">1.1309038</Real>
+        <Real Name="Z">-1.048301</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9518738</Real>
+        <Real Name="Y">10.126022</Real>
+        <Real Name="Z">-383.92468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054081</Real>
+        <Real Name="Y">8.7835617</Real>
+        <Real Name="Z">109.98161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.0733</Real>
+        <Real Name="Y">125.90257</Real>
+        <Real Name="Z">223.10434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850433</Real>
+        <Real Name="Y">8.0224648</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90619</Real>
+        <Real Name="Y">-91.872864</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62735</Real>
+        <Real Name="Y">82.504333</Real>
+        <Real Name="Z">-270.19894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937</Real>
+        <Real Name="Y">45.329948</Real>
+        <Real Name="Z">-56.291359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365723</Real>
+        <Real Name="Y">-204.77948</Real>
+        <Real Name="Z">21.695251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097099</Real>
+        <Real Name="Y">47.599464</Real>
+        <Real Name="Z">-24.246674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.29879</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65219</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617793</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617793</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617793</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059793685</Real>
+        <Real Name="Y">0.59953403</Real>
+        <Real Name="Z">0.23883899</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8576812</Real>
+        <Real Name="Y">0.68761045</Real>
+        <Real Name="Z">0.27494025</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.06241769</Real>
+        <Real Name="Y">0.61123407</Real>
+        <Real Name="Z">0.16241816</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97409749</Real>
+        <Real Name="Y">0.63061702</Real>
+        <Real Name="Z">1.5710406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94437957</Real>
+        <Real Name="Y">0.59302485</Real>
+        <Real Name="Z">1.6539019</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90847659</Real>
+        <Real Name="Y">0.69702262</Real>
+        <Real Name="Z">1.5499097</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3962845</Real>
+        <Real Name="Y">0.44676435</Real>
+        <Real Name="Z">1.1684215</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3309317</Real>
+        <Real Name="Y">0.4732722</Real>
+        <Real Name="Z">1.2331415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3460113</Real>
+        <Real Name="Y">0.43152556</Real>
+        <Real Name="Z">1.0884047</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6430682</Real>
+        <Real Name="Y">0.31611288</Real>
+        <Real Name="Z">0.30753243</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7025477</Real>
+        <Real Name="Y">0.33859748</Real>
+        <Real Name="Z">0.23598561</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6091515</Real>
+        <Real Name="Y">0.2296764</Real>
+        <Real Name="Z">0.28427923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7790073</Real>
+        <Real Name="Y">0.39112031</Real>
+        <Real Name="Z">0.024515426</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6971539</Real>
+        <Real Name="Y">0.42099401</Real>
+        <Real Name="Z">1.8466728</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8182483</Real>
+        <Real Name="Y">0.47035989</Real>
+        <Real Name="Z">0.061170001</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11743671</Real>
+        <Real Name="Y">-0.020587219</Real>
+        <Real Name="Z">-0.72718066</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5002056</Real>
+        <Real Name="Y">-0.57590193</Real>
+        <Real Name="Z">1.0901439</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0620306</Real>
+        <Real Name="Y">0.42419147</Real>
+        <Real Name="Z">0.73699516</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10073407</Real>
+        <Real Name="Y">-0.038071826</Real>
+        <Real Name="Z">0.28584835</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.65074718</Real>
+        <Real Name="Y">-2.7294476</Real>
+        <Real Name="Z">-1.0756205</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.87472832</Real>
+        <Real Name="Y">-0.50789481</Real>
+        <Real Name="Z">1.1749591</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.060030378</Real>
+        <Real Name="Y">-0.022459202</Real>
+        <Real Name="Z">-0.67836499</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22880653</Real>
+        <Real Name="Y">-0.41850519</Real>
+        <Real Name="Z">-0.22110285</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46798953</Real>
+        <Real Name="Y">0.10877412</Real>
+        <Real Name="Z">-0.44860405</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22472684</Real>
+        <Real Name="Y">0.38157025</Real>
+        <Real Name="Z">0.66937548</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019273821</Real>
+        <Real Name="Y">1.4426904</Real>
+        <Real Name="Z">1.1637461</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9406415</Real>
+        <Real Name="Y">-0.49716482</Real>
+        <Real Name="Z">0.66014129</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11612286</Real>
+        <Real Name="Y">-0.095192678</Real>
+        <Real Name="Z">-0.071082078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2098497</Real>
+        <Real Name="Y">0.50510567</Real>
+        <Real Name="Z">2.976933</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.097627416</Real>
+        <Real Name="Y">-1.0097802</Real>
+        <Real Name="Z">2.2183394</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-67.301743</Real>
+        <Real Name="Y">-110.64212</Real>
+        <Real Name="Z">-418.24124</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45213699</Real>
+        <Real Name="Y">35.606613</Real>
+        <Real Name="Z">108.87421</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">177.20667</Real>
+        <Real Name="Y">149.0929</Real>
+        <Real Name="Z">168.37729</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.754631</Real>
+        <Real Name="Y">-14.358994</Real>
+        <Real Name="Z">-37.656044</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.752789</Real>
+        <Real Name="Y">-8.0144272</Real>
+        <Real Name="Z">-23.776814</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3113632</Real>
+        <Real Name="Y">7.678936</Real>
+        <Real Name="Z">12.783241</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.170013</Real>
+        <Real Name="Y">-14.361794</Real>
+        <Real Name="Z">-32.984215</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.436386</Real>
+        <Real Name="Y">12.131413</Real>
+        <Real Name="Z">27.161549</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.92968</Real>
+        <Real Name="Y">16.924868</Real>
+        <Real Name="Z">54.47229</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-257.21674</Real>
+        <Real Name="Y">-51.562897</Real>
+        <Real Name="Z">176.20728</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">211.91789</Real>
+        <Real Name="Y">25.169617</Real>
+        <Real Name="Z">-196.62906</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.550247</Real>
+        <Real Name="Y">32.920883</Real>
+        <Real Name="Z">-53.854874</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.663467</Real>
+        <Real Name="Y">-234.86948</Real>
+        <Real Name="Z">8.1793518</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.243988</Real>
+        <Real Name="Y">75.898483</Real>
+        <Real Name="Z">-10.557526</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.701004</Real>
+        <Real Name="Y">78.386002</Real>
+        <Real Name="Z">217.64459</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8618277</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8618277</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8618277</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.001406942</Real>
+        <Real Name="Y">0.58937705</Real>
+        <Real Name="Z">0.24144877</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8535533</Real>
+        <Real Name="Y">0.67563343</Real>
+        <Real Name="Z">0.28180254</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076755442</Real>
+        <Real Name="Y">0.59848934</Real>
+        <Real Name="Z">0.18312305</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98174906</Real>
+        <Real Name="Y">0.62906402</Real>
+        <Real Name="Z">1.5713792</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97338438</Real>
+        <Real Name="Y">0.63086885</Real>
+        <Real Name="Z">1.666716</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.93986636</Real>
+        <Real Name="Y">0.70999336</Real>
+        <Real Name="Z">1.5420773</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3891788</Real>
+        <Real Name="Y">0.44754389</Real>
+        <Real Name="Z">1.1801833</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3377004</Real>
+        <Real Name="Y">0.478347</Real>
+        <Real Name="Z">1.2547719</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3263435</Real>
+        <Real Name="Y">0.40040052</Real>
+        <Real Name="Z">1.1254882</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.648701</Real>
+        <Real Name="Y">0.31801069</Real>
+        <Real Name="Z">0.29600221</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7081425</Real>
+        <Real Name="Y">0.34124804</Real>
+        <Real Name="Z">0.22466464</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6023208</Real>
+        <Real Name="Y">0.2405066</Real>
+        <Real Name="Z">0.26431131</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7747625</Real>
+        <Real Name="Y">0.39903966</Real>
+        <Real Name="Z">0.020699549</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7154974</Real>
+        <Real Name="Y">0.40798476</Real>
+        <Real Name="Z">1.8078952</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7880561</Real>
+        <Real Name="Y">0.4886331</Real>
+        <Real Name="Z">0.051661074</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.2082646</Real>
+        <Real Name="Y">-0.57496053</Real>
+        <Real Name="Z">-0.3458057</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.32974288</Real>
+        <Real Name="Y">-1.4140277</Real>
+        <Real Name="Z">1.6378648</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4336426</Real>
+        <Real Name="Y">-0.74040651</Real>
+        <Real Name="Z">2.8913951</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.421868</Real>
+        <Real Name="Y">-0.10212649</Real>
+        <Real Name="Z">0.15944974</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5724618</Real>
+        <Real Name="Y">0.81524354</Real>
+        <Real Name="Z">0.25438321</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5858712</Real>
+        <Real Name="Y">0.46241307</Real>
+        <Real Name="Z">0.02601579</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.5277794</Real>
+        <Real Name="Y">0.026126321</Real>
+        <Real Name="Z">0.37465522</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.58014858</Real>
+        <Real Name="Y">0.21101066</Real>
+        <Real Name="Z">1.0747467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.98468053</Real>
+        <Real Name="Y">-1.749753</Real>
+        <Real Name="Z">2.3637147</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23112383</Real>
+        <Real Name="Y">0.30726844</Real>
+        <Real Name="Z">-0.40360826</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39107737</Real>
+        <Real Name="Y">1.2823795</Real>
+        <Real Name="Z">0.039054405</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.8192212</Real>
+        <Real Name="Y">0.30283123</Real>
+        <Real Name="Z">-1.2708944</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19976591</Real>
+        <Real Name="Y">0.37662888</Real>
+        <Real Name="Z">-0.25063533</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.49566844</Real>
+        <Real Name="Y">0.018964129</Real>
+        <Real Name="Z">-0.85218924</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7342312</Real>
+        <Real Name="Y">0.28864154</Real>
+        <Real Name="Z">1.2314376</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-78.95195</Real>
+        <Real Name="Y">62.339798</Real>
+        <Real Name="Z">-366.78931</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.3955956</Real>
+        <Real Name="Y">0.77549744</Real>
+        <Real Name="Z">112.24796</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">135.46754</Real>
+        <Real Name="Y">3.0727692</Real>
+        <Real Name="Z">132.26825</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.735558</Real>
+        <Real Name="Y">-23.668217</Real>
+        <Real Name="Z">-37.753693</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6764755</Real>
+        <Real Name="Y">7.0499535</Real>
+        <Real Name="Z">14.371361</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.338768</Real>
+        <Real Name="Y">12.819151</Real>
+        <Real Name="Z">11.901997</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.812805</Real>
+        <Real Name="Y">-4.0081177</Real>
+        <Real Name="Z">-32.320312</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.249229</Real>
+        <Real Name="Y">9.0968552</Real>
+        <Real Name="Z">-18.083221</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.158043</Real>
+        <Real Name="Y">4.2742462</Real>
+        <Real Name="Z">18.145859</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-314.7229</Real>
+        <Real Name="Y">-129.7652</Real>
+        <Real Name="Z">277.36713</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">243.22449</Real>
+        <Real Name="Y">99.169434</Real>
+        <Real Name="Z">-284.62784</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">118.57388</Real>
+        <Real Name="Y">60.273941</Real>
+        <Real Name="Z">-65.461304</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-76.432068</Real>
+        <Real Name="Y">-323.40048</Real>
+        <Real Name="Z">-34.9729</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">20.015818</Real>
+        <Real Name="Y">58.382851</Real>
+        <Real Name="Z">26.73349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.696259</Real>
+        <Real Name="Y">163.58749</Real>
+        <Real Name="Z">246.97238</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_ParrinelloRahman_4Ranks_1RanksPerSimulation_d.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_ParrinelloRahman_4Ranks_1RanksPerSimulation_d.xml
new file mode 100644 (file)
index 0000000..c4ef60d
--- /dev/null
@@ -0,0 +1,3398 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562600160298169</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562579188546056</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562579188546056</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562579188546056</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.45626001137515</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.45626001137515</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.45626001137515</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.45626001137515</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.45626001137515</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.45626001137515</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.45626001137515</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562737386317188</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562360002045098</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562360002045098</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562360002045098</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562360002045098</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">20.344745942447496</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">20.345820773717627</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">20.359509666106668</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">20.360353120195832</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">20.361048505402536</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">18.802030172189028</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">18.802077298175188</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">18.802039820227922</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">18.801878936601057</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">18.801555302804434</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">18.825696915093005</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">18.804066607757488</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">18.82542605142584</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">26.078886771678835</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">26.080392514118863</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">26.081852665954468</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">26.09252486318308</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629305410083006</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">30.128031944401215</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.774393444413043</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">31.560514821649029</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">32.502914188437202</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">28.693156254217641</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.224473760524699</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.902597026099599</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">30.724860086504144</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">31.686809308732265</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">32.729030864892358</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">33.863760885046325</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">35.107786818719163</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">38.665947397246882</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">39.366088174476999</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">40.15447370957483</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">41.019081615595205</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.158293500466156</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.790966108088947</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.576244031235769</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.517948012817234</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.261874130100583</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.793144510421481</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.471305253943649</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.293729197975058</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.256002053999802</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.274081997871324</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.386783566526061</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.609450056530548</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-13.016678375231901</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-13.71531341002199</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-14.502238793284217</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-15.35617450207598</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13823960248430167</Real>
+        <Real Name="Y">-0.083001582473174879</Real>
+        <Real Name="Z">-0.55156788526044775</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807346912896781</Real>
+        <Real Name="Y">0.12594239723743811</Real>
+        <Real Name="Z">0.08634003909985162</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50558175484200552</Real>
+        <Real Name="Y">-0.26347201049012287</Real>
+        <Real Name="Z">-0.37043107548326104</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.08034197360884994</Real>
+        <Real Name="Y">-0.036383374851252738</Real>
+        <Real Name="Z">0.26950251001929981</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0879938107726246</Real>
+        <Real Name="Y">-2.69925195488055</Real>
+        <Real Name="Z">-0.41161299800761308</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.005339856872981</Real>
+        <Real Name="Y">-0.44613327229712957</Real>
+        <Real Name="Z">1.1534368241800748</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046991365082634871</Real>
+        <Real Name="Y">-0.027139438957271687</Real>
+        <Real Name="Z">-0.68356956696424598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.05202773043970705</Real>
+        <Real Name="Y">-0.42394701288611158</Real>
+        <Real Name="Z">-0.38240890291446672</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25145271172169875</Real>
+        <Real Name="Y">0.072329295992862669</Real>
+        <Real Name="Z">-0.58384125172376966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20047275659675193</Real>
+        <Real Name="Y">0.39459474035999631</Real>
+        <Real Name="Z">0.71751226731035578</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21660158751017167</Real>
+        <Real Name="Y">1.2107968994948017</Real>
+        <Real Name="Z">0.86109126390401169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3771064228719012</Real>
+        <Real Name="Y">-0.66102181650660441</Real>
+        <Real Name="Z">0.8707144786748191</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2170122537672452</Real>
+        <Real Name="Y">-0.090547598182205036</Real>
+        <Real Name="Z">-0.034702681691129153</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639425064678223</Real>
+        <Real Name="Y">0.96363069485778263</Real>
+        <Real Name="Z">2.5346418773966413</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37424921124686311</Real>
+        <Real Name="Y">-0.37914050295285712</Real>
+        <Real Name="Z">0.73119277083077761</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620599995525136</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620599995525136</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620599995525136</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0031772668880734956</Real>
+        <Real Name="Y">0.5943581491249863</Real>
+        <Real Name="Z">0.24346921413278894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8501326265675104</Real>
+        <Real Name="Y">0.68440928053826688</Real>
+        <Real Name="Z">0.27219136561021889</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059036546161559705</Real>
+        <Real Name="Y">0.60286196715442875</Real>
+        <Real Name="Z">0.16620509310647749</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97851873027442338</Real>
+        <Real Name="Y">0.63000587906410499</Real>
+        <Real Name="Z">1.5703601399344986</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96160608018769922</Real>
+        <Real Name="Y">0.62393808077212709</Real>
+        <Real Name="Z">1.6643785556355273</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92784787832908167</Real>
+        <Real Name="Y">0.70599481536947351</Real>
+        <Real Name="Z">1.5417163845537625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3933176977838739</Real>
+        <Real Name="Y">0.44734499300370989</Real>
+        <Real Name="Z">1.1773253791163016</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3334372113688961</Real>
+        <Real Name="Y">0.47714666928063715</Real>
+        <Real Name="Z">1.2457980440110654</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3360575514245783</Real>
+        <Real Name="Y">0.41481829260020914</Real>
+        <Real Name="Z">1.107858784268327</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6470522830662826</Real>
+        <Real Name="Y">0.31561502687856213</Real>
+        <Real Name="Z">0.29910990536493953</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7056123442752553</Real>
+        <Real Name="Y">0.33259114820061214</Real>
+        <Real Name="Z">0.22532068571830033</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5974862793519886</Real>
+        <Real Name="Y">0.23798656898821854</Real>
+        <Real Name="Z">0.2730455196756259</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7765464922432563</Real>
+        <Real Name="Y">0.39595878881560248</Real>
+        <Real Name="Z">0.022771429651659739</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7121647466065582</Real>
+        <Real Name="Y">0.40984154766508391</Real>
+        <Real Name="Z">1.815372245250586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8067021661563025</Real>
+        <Real Name="Y">0.48392231310386824</Real>
+        <Real Name="Z">0.045473238514332846</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.23480998320370855</Real>
+        <Real Name="Y">-0.68788294952360796</Real>
+        <Real Name="Z">-0.13555934462663172</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.59085729139061538</Real>
+        <Real Name="Y">-0.79437630170293649</Real>
+        <Real Name="Z">0.65549099391050913</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6594469782353278</Real>
+        <Real Name="Y">-0.59342695737438023</Real>
+        <Real Name="Z">1.2093356322257187</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43871144442659893</Real>
+        <Real Name="Y">-0.11980556865314423</Real>
+        <Real Name="Z">0.158409498324737</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4192184373621348</Real>
+        <Real Name="Y">1.0234415614437058</Real>
+        <Real Name="Z">0.42100322736649626</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5175688823600044</Real>
+        <Real Name="Y">0.58947657117911723</Real>
+        <Real Name="Z">0.10240757013196999</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.47851575114255457</Real>
+        <Real Name="Y">0.038678054679743223</Real>
+        <Real Name="Z">0.39961402087290671</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.51601280951233586</Real>
+        <Real Name="Y">0.091354769111024234</Real>
+        <Real Name="Z">1.2590555288845722</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.4940371529286469</Real>
+        <Real Name="Y">-1.9514508360704248</Real>
+        <Real Name="Z">2.1115156703340476</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24770785032555381</Real>
+        <Real Name="Y">0.31820261684292406</Real>
+        <Real Name="Z">-0.37890334186678015</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.28454784230627489</Real>
+        <Real Name="Y">0.83108667536478953</Real>
+        <Real Name="Z">-0.23360603470901165</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38871623212406137</Real>
+        <Real Name="Y">0.38994062518712713</Real>
+        <Real Name="Z">-0.86574212409834805</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19439892227565478</Real>
+        <Real Name="Y">0.45184799786058594</Real>
+        <Real Name="Z">-0.27704297418250251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.40203203571314605</Real>
+        <Real Name="Y">-0.51813957982750325</Real>
+        <Real Name="Z">-1.0372393806486611</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7717115637149567</Real>
+        <Real Name="Y">0.91558375521600399</Real>
+        <Real Name="Z">0.08370567688794886</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.5468199029993173</Real>
+        <Real Name="Y">59.478612890794409</Real>
+        <Real Name="Z">-374.00725675663057</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.0361464304237842</Real>
+        <Real Name="Y">1.5119114175170267</Real>
+        <Real Name="Z">111.89642872840045</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.44500997396062</Real>
+        <Real Name="Y">64.585598718152752</Real>
+        <Real Name="Z">206.25990400700783</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.59938435298703</Real>
+        <Real Name="Y">-18.882165698728173</Real>
+        <Real Name="Z">-38.890208116693614</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.68827069287002</Real>
+        <Real Name="Y">-9.5329106049003691</Real>
+        <Real Name="Z">-24.582642696234572</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4432153258108826</Real>
+        <Real Name="Y">10.523649832252126</Real>
+        <Real Name="Z">12.975770469826671</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.56765599382021</Real>
+        <Real Name="Y">-7.2570100462609659</Real>
+        <Real Name="Z">-33.306216123636261</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-56.956672390791795</Real>
+        <Real Name="Y">11.274439711346261</Real>
+        <Real Name="Z">-15.073384268397035</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.637682555667027</Real>
+        <Real Name="Y">18.882374092247844</Real>
+        <Real Name="Z">56.492944940862699</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-308.66471508440162</Real>
+        <Real Name="Y">-122.41227321914589</Real>
+        <Real Name="Z">255.23987080455487</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.5405760008658</Real>
+        <Real Name="Y">106.627864060856</Real>
+        <Real Name="Z">-280.35184510004331</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">113.88761847349201</Real>
+        <Real Name="Y">55.172897018121986</Real>
+        <Real Name="Z">-58.089110871993881</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-58.715700618876895</Real>
+        <Real Name="Y">-239.85173114515271</Real>
+        <Real Name="Z">-1.3123528940032543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.0927990618773435</Real>
+        <Real Name="Y">45.387871456853944</Real>
+        <Real Name="Z">17.13628510525092</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-101.82036224090172</Real>
+        <Real Name="Y">24.490871516045672</Real>
+        <Real Name="Z">165.61181277172898</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620576911832853</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620576911832853</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620576911832853</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0034244566235419986</Real>
+        <Real Name="Y">0.60667226370611671</Real>
+        <Real Name="Z">0.23537675433620395</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.02503738975762904</Real>
+        <Real Name="Y">0.66597380720699895</Real>
+        <Real Name="Z">0.30733873360132802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.085115330149667282</Real>
+        <Real Name="Y">0.5977199731003392</Real>
+        <Real Name="Z">0.18629747076922429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97170822571521576</Real>
+        <Real Name="Y">0.63342600958582052</Real>
+        <Real Name="Z">1.5675436967477914</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97538162988173915</Real>
+        <Real Name="Y">0.60600180466399445</Real>
+        <Real Name="Z">1.6591774104465975</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.88966347225990405</Real>
+        <Real Name="Y">0.68220518699367128</Real>
+        <Real Name="Z">1.5603625630023259</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959149359393521</Real>
+        <Real Name="Y">0.44154213817920468</Real>
+        <Real Name="Z">1.1692274352165526</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3338782252854895</Real>
+        <Real Name="Y">0.43591135769209938</Real>
+        <Real Name="Z">1.2419052120286882</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3516615783804109</Real>
+        <Real Name="Y">0.39784995198718492</Real>
+        <Real Name="Z">1.0964610170655813</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6451581848648249</Real>
+        <Real Name="Y">0.31683769363452735</Real>
+        <Real Name="Z">0.30359422309964862</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6952107658498772</Real>
+        <Real Name="Y">0.33305695341009828</Real>
+        <Real Name="Z">0.22363177473126133</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5994600132598595</Real>
+        <Real Name="Y">0.23438532830658038</Real>
+        <Real Name="Z">0.2869929290600397</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.776526593186867</Real>
+        <Real Name="Y">0.39364175828897385</Real>
+        <Real Name="Z">0.033313590546139929</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7164502141229405</Real>
+        <Real Name="Y">0.42439651715729787</Real>
+        <Real Name="Z">1.8274942466916573</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8493675532750733</Real>
+        <Real Name="Y">0.45569174026063858</Real>
+        <Real Name="Z">0.030801087661737205</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11501089542901557</Real>
+        <Real Name="Y">0.66863442181635668</Real>
+        <Real Name="Z">-0.63013002388210848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.6551442047690248</Real>
+        <Real Name="Y">-3.5157754545032764</Real>
+        <Real Name="Z">2.8644173386680896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7850199366725636</Real>
+        <Real Name="Y">-1.7458656112444975</Real>
+        <Real Name="Z">2.4081164879819896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20602512313577295</Real>
+        <Real Name="Y">0.14856183181885224</Real>
+        <Real Name="Z">-0.11507705067740623</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5582832620521863</Real>
+        <Real Name="Y">-0.50091206013569289</Real>
+        <Real Name="Z">-0.36056410794797028</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.3056899814129941</Real>
+        <Real Name="Y">-1.4255278934307727</Real>
+        <Real Name="Z">1.3501480352159934</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.13735686855539922</Real>
+        <Real Name="Y">-0.36089327953541095</Real>
+        <Real Name="Z">-0.28563669823258719</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95296074563062927</Real>
+        <Real Name="Y">-2.2439467879603909</Real>
+        <Real Name="Z">0.53637315997019019</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25703378549730072</Real>
+        <Real Name="Y">-1.8380985009190867</Real>
+        <Real Name="Z">0.34271581708766891</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.014476314928185617</Real>
+        <Real Name="Y">0.22312887783595609</Real>
+        <Real Name="Z">0.086716829609878476</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.61347934997585218</Real>
+        <Real Name="Y">1.1346603117787071</Real>
+        <Real Name="Z">-0.12941464645298817</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.6065627601055219</Real>
+        <Real Name="Y">-0.064343632200372494</Real>
+        <Real Name="Z">-0.12980385568804531</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1186699272776678</Real>
+        <Real Name="Y">-0.0018204880977220356</Real>
+        <Real Name="Z">0.47893397133766391</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.32826627454415291</Real>
+        <Real Name="Y">0.81305324310485139</Real>
+        <Real Name="Z">0.44620589604457761</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.0545053055313907</Real>
+        <Real Name="Y">-1.3685762083287865</Real>
+        <Real Name="Z">0.055544400646055342</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">156.42843850079186</Real>
+        <Real Name="Y">104.37056448413537</Real>
+        <Real Name="Z">-274.03256602173371</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-42.954312098085012</Real>
+        <Real Name="Y">-33.855623941482051</Real>
+        <Real Name="Z">76.320312389976394</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.572457064839341</Real>
+        <Real Name="Y">42.054920411230043</Real>
+        <Real Name="Z">191.12915567414331</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">9.6620168526180947</Real>
+        <Real Name="Y">-26.822604506297168</Real>
+        <Real Name="Z">-24.435658906425729</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.329923103278617</Real>
+        <Real Name="Y">-5.3412187677393597</Real>
+        <Real Name="Z">-27.231665845733929</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">26.791873039998151</Real>
+        <Real Name="Y">-8.7982367542779407</Real>
+        <Real Name="Z">-23.474571404528376</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.609149109668223</Real>
+        <Real Name="Y">-17.193219100228582</Real>
+        <Real Name="Z">-27.830182205091866</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.366471689659122</Real>
+        <Real Name="Y">17.413297194289253</Real>
+        <Real Name="Z">-21.445698045575824</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-67.021979390566031</Real>
+        <Real Name="Y">41.554505484780393</Real>
+        <Real Name="Z">83.09676287219105</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-261.23396161150663</Real>
+        <Real Name="Y">-176.41826213823748</Real>
+        <Real Name="Z">381.99651941116906</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">235.51652509664217</Real>
+        <Real Name="Y">176.96826578937493</Real>
+        <Real Name="Z">-391.77462353779424</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.623097627210441</Real>
+        <Real Name="Y">78.969297519250489</Real>
+        <Real Name="Z">-89.36280700025722</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-94.88547104561269</Real>
+        <Real Name="Y">-433.3016306349752</Real>
+        <Real Name="Z">8.1686655766393415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.151387040089372</Real>
+        <Real Name="Y">113.81440144065861</Real>
+        <Real Name="Z">38.638976656565887</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.22267159970681</Real>
+        <Real Name="Y">126.58554351951881</Real>
+        <Real Name="Z">100.2373803864557</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562600160298169</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.45626001137515</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.45626001137515</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.45626001137515</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562579188546056</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562579188546056</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562579188546056</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562579188546056</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562540142582749</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562540142582749</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562540142582749</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562360002045098</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562737386317188</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562737386317188</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562737386317188</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562737386317188</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">18.791686616081851</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">18.791805005019956</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">18.805593268639686</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">18.805712821126871</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">18.805830973252302</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">20.365376534936427</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">20.365402158867692</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">20.364875590336613</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">20.363647015124858</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">26.059788494568235</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">26.095637498809893</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">26.104994114369358</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">26.081291846150638</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">18.82812700901097</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">18.826670078627536</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">18.825032396043145</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">18.823289071454234</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">28.072358033056044</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">27.982132066767296</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">27.988967538222521</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">28.075315097736997</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">28.309979355267512</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">33.603047962744981</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.858851901995145</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">36.263436685192161</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.803580276562272</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">36.704488806788262</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">37.128805934470563</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">37.5501081204103</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">38.052997749546151</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">36.42280788472182</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">37.81244518505153</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">39.254927426287836</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">40.725848906556159</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5649631544184182</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5580103622539134</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6442383692812044</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8787844746862863</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.617641802720003</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.873420118038903</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.278531469766996</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.819903636348862</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.044991626801238</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.433459750241882</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-11.878619805588022</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-12.405211702942594</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.92565820315642</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.316752433869564</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.760872357690261</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.233537162547496</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21190890418197439</Real>
+        <Real Name="Y">-0.7311311919098834</Real>
+        <Real Name="Z">0.011277778119910499</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.66796314487407893</Real>
+        <Real Name="Y">-0.44908961562317945</Real>
+        <Real Name="Z">-0.19934647018435334</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.080882597990871996</Real>
+        <Real Name="Y">-1.3642241529051329</Real>
+        <Real Name="Z">0.095855310056509185</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44769583968342896</Real>
+        <Real Name="Y">-0.12958260429636317</Real>
+        <Real Name="Z">0.17147102653965599</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1260077456076665</Real>
+        <Real Name="Y">1.2299432703788549</Real>
+        <Real Name="Z">0.59933785465319467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4102608467371438</Real>
+        <Real Name="Y">0.66588072547259036</Real>
+        <Real Name="Z">0.10716908923047011</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.42091576278340037</Real>
+        <Real Name="Y">0.039801072970148413</Real>
+        <Real Name="Z">0.4239928608933955</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31497744055640853</Real>
+        <Real Name="Y">0.033114800275404865</Real>
+        <Real Name="Z">1.2372826323989534</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7872566667859691</Real>
+        <Real Name="Y">-2.0657209691150182</Real>
+        <Real Name="Z">1.5960222410479219</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26078907943572527</Real>
+        <Real Name="Y">0.32044762585901831</Real>
+        <Real Name="Z">-0.34787968920455964</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.148374024658951</Real>
+        <Real Name="Y">0.34906800206533178</Real>
+        <Real Name="Z">-0.43150156880076879</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.01999757278104131</Real>
+        <Real Name="Y">0.52855025949293</Real>
+        <Real Name="Z">-0.45929211920777768</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15528384653458924</Real>
+        <Real Name="Y">0.54477489000772439</Real>
+        <Real Name="Z">-0.27405115378506656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25903608390864075</Real>
+        <Real Name="Y">-0.78199538968155358</Real>
+        <Real Name="Z">-1.2374793615012896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93642846229023646</Real>
+        <Real Name="Y">1.151169402760081</Real>
+        <Real Name="Z">-1.0669585943196809</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620597983834559</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620597983834559</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620597983834559</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059800328505390556</Real>
+        <Real Name="Y">0.59962504497847613</Real>
+        <Real Name="Z">0.23887591461460062</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8579625484966711</Real>
+        <Real Name="Y">0.68770227679597895</Real>
+        <Real Name="Z">0.27497533300323135</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.06241565913332163</Real>
+        <Real Name="Y">0.6113238282135034</Real>
+        <Real Name="Z">0.16245290134706805</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97424378889759466</Real>
+        <Real Name="Y">0.6307127477751906</Real>
+        <Real Name="Z">1.5712773250888159</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94452570911175848</Real>
+        <Real Name="Y">0.59312110810454799</Real>
+        <Real Name="Z">1.6541387923743702</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90862295983615327</Real>
+        <Real Name="Y">0.69711822623013464</Real>
+        <Real Name="Z">1.5501458882124746</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3964937370556405</Real>
+        <Real Name="Y">0.44683176435831257</Real>
+        <Real Name="Z">1.1685987747755346</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3311407932633517</Real>
+        <Real Name="Y">0.47333967838980612</Real>
+        <Real Name="Z">1.2333184907157371</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3462208283358859</Real>
+        <Real Name="Y">0.43159302277090855</Real>
+        <Real Name="Z">1.08858169032673</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6433160909227307</Real>
+        <Real Name="Y">0.31615917470937016</Real>
+        <Real Name="Z">0.30757638814545513</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7027956551412871</Real>
+        <Real Name="Y">0.33864314948501711</Real>
+        <Real Name="Z">0.23602940554899296</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6093986801458802</Real>
+        <Real Name="Y">0.22972290093902697</Real>
+        <Real Name="Z">0.28432346955676191</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7792750086957605</Real>
+        <Real Name="Y">0.39118056857586669</Real>
+        <Real Name="Z">0.024518995768028948</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6974218174761648</Real>
+        <Real Name="Y">0.42105405128654816</Real>
+        <Real Name="Z">1.8469562182899566</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8185172088707484</Real>
+        <Real Name="Y">0.47042087258533349</Real>
+        <Real Name="Z">0.061170630737196648</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11737434299139263</Real>
+        <Real Name="Y">-0.020636631308915868</Real>
+        <Real Name="Z">-0.72704473568947947</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.500327802046507</Real>
+        <Real Name="Y">-0.57571139856021403</Real>
+        <Real Name="Z">1.0897889226588611</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0613131287717863</Real>
+        <Real Name="Y">0.42387074009428305</Real>
+        <Real Name="Z">0.73649840103903563</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10070670331690768</Real>
+        <Real Name="Y">-0.038042320145766209</Real>
+        <Real Name="Z">0.28581739392488709</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.65075457861337205</Real>
+        <Real Name="Y">-2.7293500850419026</Real>
+        <Real Name="Z">-1.0756999941488385</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.87471004004556518</Real>
+        <Real Name="Y">-0.50786099032704346</Real>
+        <Real Name="Z">1.1748761490334556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.060017278939684067</Real>
+        <Real Name="Y">-0.022456514491390807</Real>
+        <Real Name="Z">-0.6782746113478082</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22874045379790209</Real>
+        <Real Name="Y">-0.41848706272370995</Real>
+        <Real Name="Z">-0.22101417161623294</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46788529566315562</Real>
+        <Real Name="Y">0.10877447632510473</Real>
+        <Real Name="Z">-0.44848959704243452</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22469387559909282</Real>
+        <Real Name="Y">0.38152504271057985</Real>
+        <Real Name="Z">0.6692591842664336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019246708661909195</Real>
+        <Real Name="Y">1.4425619201128246</Real>
+        <Real Name="Z">1.1636201313462169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9405051279226606</Real>
+        <Real Name="Y">-0.49721381286418365</Real>
+        <Real Name="Z">0.66009009399284857</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11612929262376907</Real>
+        <Real Name="Y">-0.095145558341302033</Real>
+        <Real Name="Z">-0.071047791641900643</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2098738456442253</Real>
+        <Real Name="Y">0.50517729153240387</Real>
+        <Real Name="Z">2.9768871414951508</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.097169608082302433</Real>
+        <Real Name="Y">-1.0094804717620147</Real>
+        <Real Name="Z">2.2175859723188456</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-67.305272277436075</Real>
+        <Real Name="Y">-110.64970794905523</Real>
+        <Real Name="Z">-418.09618882821349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45499314037364513</Real>
+        <Real Name="Y">35.58746317066506</Real>
+        <Real Name="Z">108.83013613136191</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">177.09154443724111</Real>
+        <Real Name="Y">149.00175034825025</Real>
+        <Real Name="Z">168.31879929809574</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.745661000627152</Real>
+        <Real Name="Y">-14.351915393354027</Real>
+        <Real Name="Z">-37.638091660025069</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.748815649541349</Real>
+        <Real Name="Y">-8.0131143158013778</Real>
+        <Real Name="Z">-23.772529732591643</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3077237126842149</Real>
+        <Real Name="Y">7.6752787773066586</Real>
+        <Real Name="Z">12.778185603981704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.157339628508097</Real>
+        <Real Name="Y">-14.355671470284776</Real>
+        <Real Name="Z">-32.970003394938665</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.423603522315531</Real>
+        <Real Name="Y">12.125171875830365</Real>
+        <Real Name="Z">27.147601666576108</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.920489043676859</Real>
+        <Real Name="Y">16.92025052630316</Real>
+        <Real Name="Z">54.454837516997571</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-257.06930589985734</Real>
+        <Real Name="Y">-51.515889985441973</Real>
+        <Real Name="Z">176.05114825669767</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">211.81603169700858</Real>
+        <Real Name="Y">25.161159534763669</Real>
+        <Real Name="Z">-196.50027384754549</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.512449015604432</Real>
+        <Real Name="Y">32.904791264708535</Real>
+        <Real Name="Z">-53.832575262237867</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.628100769133425</Real>
+        <Real Name="Y">-234.67760321077708</Real>
+        <Real Name="Z">8.306302316942265</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.22492899522301</Real>
+        <Real Name="Y">75.865998360930448</Real>
+        <Real Name="Z">-10.555313679595315</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.647410348577864</Real>
+        <Real Name="Y">78.322038465956268</Real>
+        <Real Name="Z">217.47796561449451</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620613192513897</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620613192513897</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620613192513897</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0013510492400190216</Real>
+        <Real Name="Y">0.58925784596696729</Real>
+        <Real Name="Z">0.24148585180800763</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8539739573051051</Real>
+        <Real Name="Y">0.67557338926145094</Real>
+        <Real Name="Z">0.2817706104650497</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076753956647818811</Real>
+        <Real Name="Y">0.59809783477007161</Real>
+        <Real Name="Z">0.18318855725318703</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98198467409609558</Real>
+        <Real Name="Y">0.62911637101488815</Real>
+        <Real Name="Z">1.5716335666149699</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97389259697656927</Real>
+        <Real Name="Y">0.63121859907678413</Real>
+        <Real Name="Z">1.6669877344581587</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94044688321236158</Real>
+        <Real Name="Y">0.71018665702395034</Real>
+        <Real Name="Z">1.5422305216211665</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3892161983398914</Real>
+        <Real Name="Y">0.44760498279632344</Real>
+        <Real Name="Z">1.1804349293147014</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3380525805517114</Real>
+        <Real Name="Y">0.47841888115182307</Real>
+        <Real Name="Z">1.255235372381315</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3262692564998879</Real>
+        <Real Name="Y">0.39998098924696901</Real>
+        <Real Name="Z">1.1262873887297218</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6489790102895019</Real>
+        <Real Name="Y">0.31813661249609676</Real>
+        <Real Name="Z">0.29594500798716916</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7083891039365808</Real>
+        <Real Name="Y">0.34140748243455665</Real>
+        <Real Name="Z">0.22459218193835601</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6025259083292305</Real>
+        <Real Name="Y">0.24069631187421586</Real>
+        <Real Name="Z">0.26420500865098562</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7749401328664474</Real>
+        <Real Name="Y">0.39924161887613846</Real>
+        <Real Name="Z">0.020622818905004121</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7158682415517408</Real>
+        <Real Name="Y">0.40780668785283553</Real>
+        <Real Name="Z">1.8078545340552918</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7879748823032138</Real>
+        <Real Name="Y">0.48897019452511248</Real>
+        <Real Name="Z">0.051301743578577995</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21151308704301588</Real>
+        <Real Name="Y">-0.5865846337625068</Real>
+        <Real Name="Z">-0.34485949692056478</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.34109701789253205</Real>
+        <Real Name="Y">-1.4210617297809005</Real>
+        <Real Name="Z">1.6336093437893937</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4302803548639869</Real>
+        <Real Name="Y">-0.77698374371605194</Real>
+        <Real Name="Z">2.8931267925176947</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42860389149495703</Real>
+        <Real Name="Y">-0.10316856864489463</Real>
+        <Real Name="Z">0.16359961327180925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5992136803027486</Real>
+        <Real Name="Y">0.82685415394468631</Real>
+        <Real Name="Z">0.25420167247218284</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6172040594393786</Real>
+        <Real Name="Y">0.46425663173604281</Real>
+        <Real Name="Z">0.019114210069263747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53760639985504544</Real>
+        <Real Name="Y">0.025838532379857365</Real>
+        <Real Name="Z">0.3808505813802609</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.59666457742932533</Real>
+        <Real Name="Y">0.21345757259212234</Real>
+        <Real Name="Z">1.0916165939206661</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.9849642713427379</Real>
+        <Real Name="Y">-1.7710873009312698</Real>
+        <Real Name="Z">2.4116000051874913</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23553546360942562</Real>
+        <Real Name="Y">0.31257188968892857</Real>
+        <Real Name="Z">-0.4093158817338064</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39327859924905023</Real>
+        <Real Name="Y">1.2927479715402526</Real>
+        <Real Name="Z">0.033417307194806345</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.81983495960299635</Real>
+        <Real Name="Y">0.31267442354425945</Real>
+        <Real Name="Z">-1.2820959826382856</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20261672786271603</Real>
+        <Real Name="Y">0.38582308424327838</Real>
+        <Real Name="Z">-0.25594466684623485</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50789622535090828</Real>
+        <Real Name="Y">0.0060449943276779522</Real>
+        <Real Name="Z">-0.86713965739387078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7556468730395647</Real>
+        <Real Name="Y">0.30581113954865813</Real>
+        <Real Name="Z">1.2038574645495292</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-78.219013266442687</Real>
+        <Real Name="Y">65.501033697191133</Real>
+        <Real Name="Z">-364.76182973013124</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.4931748371268441</Real>
+        <Real Name="Y">0.21379044418503668</Real>
+        <Real Name="Z">112.0544822638681</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">134.87015500802499</Real>
+        <Real Name="Y">1.3438506396439749</Real>
+        <Real Name="Z">132.01153759372846</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.866681276084691</Real>
+        <Real Name="Y">-23.824128284680889</Real>
+        <Real Name="Z">-37.658038665215329</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.7219551832781832</Real>
+        <Real Name="Y">7.1210009276820401</Real>
+        <Real Name="Z">14.358944598354249</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.3680250579229991</Real>
+        <Real Name="Y">12.895959043440602</Real>
+        <Real Name="Z">11.845999047140538</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.814173631756461</Real>
+        <Real Name="Y">-3.8713185229010847</Real>
+        <Real Name="Z">-32.264316054411552</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.312872938792168</Real>
+        <Real Name="Y">9.0119944507972107</Real>
+        <Real Name="Z">-18.198628843461819</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.203899839338497</Real>
+        <Real Name="Y">4.2595196744229789</Real>
+        <Real Name="Z">18.144363849587982</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-315.42326448881357</Real>
+        <Real Name="Y">-131.22415269071621</Real>
+        <Real Name="Z">277.77480345929871</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">243.78269368452877</Real>
+        <Real Name="Y">100.62663242344702</Real>
+        <Real Name="Z">-284.8818134183856</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">118.7508798562117</Real>
+        <Real Name="Y">60.673644989008807</Real>
+        <Real Name="Z">-65.372749970439116</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-75.897034072772783</Real>
+        <Real Name="Y">-323.46178693255422</Real>
+        <Real Name="Z">-35.473255339602701</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.987209331805239</Real>
+        <Real Name="Y">58.143035572513156</Real>
+        <Real Name="Z">26.498314851550958</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-22.418902778177824</Real>
+        <Real Name="Y">162.59092456852051</Real>
+        <Real Name="Z">245.92218635811827</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 2">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98715
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562600160298169</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562602679570631</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562602679570631</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562602679570631</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562540142582749</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562540142582749</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562540142582749</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562540142582749</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562579188546056</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562579188546056</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562579188546056</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562432723667973</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562606924239949</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562606924239949</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562606924239949</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562606924239949</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.987499794208691</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.987278087101004</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.960874985007223</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.960696714285241</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">29.960598403401598</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">26.059621615165469</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">26.06034681126339</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">26.061292176201256</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">26.062430321751688</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">20.365525729024693</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">20.362548164916173</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">20.339977903743968</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">20.310089305558829</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">29.919152389359258</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">29.918422102651856</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">29.898083509580687</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">29.896805360581762</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">39.264244280014964</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">39.004874449699635</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">38.84351490479326</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">38.804895194732275</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">38.861865245751133</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">35.462693606008273</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">35.678064394247357</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">35.955409531124246</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">36.296627302896937</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">39.458340032944761</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">41.19785122704846</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">42.957107193270332</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">44.712827978816591</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">43.490734391819629</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">44.469759405170926</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">45.473555496178776</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">46.487975715521316</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.4404152794192715</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.3054588366066735</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.2670173972676704</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.3240857591701758</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.8072902354900293</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.021935827631193</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.298335599570215</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.638415225792475</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.476711604454376</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.219200362666594</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-23.008047528652078</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.793656912383476</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-14.089667398330532</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-15.06942269838923</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-16.093557382468251</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-17.109255750809716</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.55872268486508581</Real>
+        <Real Name="Y">-0.1954372884884242</Real>
+        <Real Name="Z">-0.12331658054675539</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5561630812121041</Real>
+        <Real Name="Y">0.1502581233870332</Real>
+        <Real Name="Z">-0.44761547196159901</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2265097662633464</Real>
+        <Real Name="Y">-1.1768262519621135</Real>
+        <Real Name="Z">-1.2616929856512602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10263626685285894</Real>
+        <Real Name="Y">0.57441118855119189</Real>
+        <Real Name="Z">0.005375904919935586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.35939325012836826</Real>
+        <Real Name="Y">0.13708618830230673</Real>
+        <Real Name="Z">-0.18874701506105859</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.676875181418428</Real>
+        <Real Name="Y">2.202437016478954</Real>
+        <Real Name="Z">0.65929093056192956</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22450558096959172</Real>
+        <Real Name="Y">0.27064569302711877</Real>
+        <Real Name="Z">0.3868191000888086</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.18295630274175456</Real>
+        <Real Name="Y">3.1066574874243527</Real>
+        <Real Name="Z">-0.46533684155430372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.43479618283021731</Real>
+        <Real Name="Y">-1.4385606453027826</Real>
+        <Real Name="Z">0.83013591007662091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11927480032898595</Real>
+        <Real Name="Y">-0.50285081385011732</Real>
+        <Real Name="Z">0.091729524538884569</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67581188225624333</Real>
+        <Real Name="Y">-0.055776720974020769</Real>
+        <Real Name="Z">0.61588372964499161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2213254303381311</Real>
+        <Real Name="Y">-1.9672700978846431</Real>
+        <Real Name="Z">0.44974949833150613</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.90469603789517505</Real>
+        <Real Name="Y">-0.20098861393275941</Real>
+        <Real Name="Z">-0.24253246946049692</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.84380910241735319</Real>
+        <Real Name="Y">0.72263550705740742</Real>
+        <Real Name="Z">-1.8704269945047447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39637402078760992</Real>
+        <Real Name="Y">-0.82004058352348863</Real>
+        <Real Name="Z">-0.19538443781690279</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620594230063974</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620594230063974</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620594230063974</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0035309757036148634</Real>
+        <Real Name="Y">0.60228975490219361</Real>
+        <Real Name="Z">0.24021335686682652</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.010584807310778755</Real>
+        <Real Name="Y">0.6865054330347512</Real>
+        <Real Name="Z">0.28516089758187424</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.067659238400367444</Real>
+        <Real Name="Y">0.60746809040164473</Real>
+        <Real Name="Z">0.16933974284192255</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97336963443137414</Real>
+        <Real Name="Y">0.63220704011959683</Real>
+        <Real Name="Z">1.5683870514865952</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96295208106073238</Real>
+        <Real Name="Y">0.61033229248204213</Real>
+        <Real Name="Z">1.660989904561232</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90153879439482709</Real>
+        <Real Name="Y">0.6926766778078064</Real>
+        <Real Name="Z">1.549784048032844</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3967459980998351</Real>
+        <Real Name="Y">0.44433239251929835</Real>
+        <Real Name="Z">1.1715894001268288</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3288437203566223</Real>
+        <Real Name="Y">0.45539245562767056</Real>
+        <Real Name="Z">1.238142191813745</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349637741353845</Real>
+        <Real Name="Y">0.41369319510058855</Real>
+        <Real Name="Z">1.0941015292831229</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450870239208999</Real>
+        <Real Name="Y">0.3150016444039187</Real>
+        <Real Name="Z">0.30286795504616448</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6997139749780918</Real>
+        <Real Name="Y">0.32709460379876787</Real>
+        <Real Name="Z">0.22520216494995005</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5959633363102672</Real>
+        <Real Name="Y">0.23472794902535499</Real>
+        <Real Name="Z">0.28539467413495395</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7773645738681352</Real>
+        <Real Name="Y">0.39318200728285679</Real>
+        <Real Name="Z">0.029313003716451194</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7133777319095951</Real>
+        <Real Name="Y">0.41904991754868254</Real>
+        <Real Name="Z">1.8250485722310312</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8376274282860428</Real>
+        <Real Name="Y">0.46735265002602089</Real>
+        <Real Name="Z">0.034737257810036067</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.14170673777288273</Real>
+        <Real Name="Y">0.39028062112131762</Real>
+        <Real Name="Z">-0.54479301149013781</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.987573044679535</Real>
+        <Real Name="Y">-1.3149701673304466</Real>
+        <Real Name="Z">2.3966735436741167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3907503977194926</Real>
+        <Real Name="Y">-0.57651045426407255</Real>
+        <Real Name="Z">1.5919522055538735</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20588268573978807</Real>
+        <Real Name="Y">0.1541397012001815</Real>
+        <Real Name="Z">-0.092717695372326492</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5210938513937051</Real>
+        <Real Name="Y">-0.57887863110277216</Real>
+        <Real Name="Z">-0.052578903011445265</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.6947685354955078</Real>
+        <Real Name="Y">-1.1574139944949249</Real>
+        <Real Name="Z">1.2394806900429409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.058472257123416076</Real>
+        <Real Name="Y">-0.3374372489164712</Real>
+        <Real Name="Z">-0.30402495452873773</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.20038525183514555</Real>
+        <Real Name="Y">-2.6226472016443343</Real>
+        <Real Name="Z">0.38313283989745045</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.17884199335172166</Real>
+        <Real Name="Y">-2.1166978053654799</Real>
+        <Real Name="Z">0.23258338185775607</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0058480243876327647</Real>
+        <Real Name="Y">0.23799926379649561</Real>
+        <Real Name="Z">0.095720788088370423</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.51381290538722602</Real>
+        <Real Name="Y">0.24601548216997474</Real>
+        <Real Name="Z">-0.27114476981300484</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2080654192134106</Real>
+        <Real Name="Y">0.00056630963495717113</Real>
+        <Real Name="Z">0.60771698133892549</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.08881412222051803</Real>
+        <Real Name="Y">0.12197842730115832</Real>
+        <Real Name="Z">0.52645503746525879</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45691126841028573</Real>
+        <Real Name="Y">0.52527011503284071</Real>
+        <Real Name="Z">0.15272830895553974</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0270148162997819</Real>
+        <Real Name="Y">-1.4037733903183276</Real>
+        <Real Name="Z">-1.2115306301830351</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">116.49667316481268</Real>
+        <Real Name="Y">84.50884900826523</Real>
+        <Real Name="Z">-320.08140620893175</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-30.184279248887741</Real>
+        <Real Name="Y">-17.882556646671418</Real>
+        <Real Name="Z">88.293803253671044</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">62.053261292760595</Real>
+        <Real Name="Y">77.085937726597422</Real>
+        <Real Name="Z">217.62614364481632</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.886551548885961</Real>
+        <Real Name="Y">-21.749951758882808</Real>
+        <Real Name="Z">-33.097794067792734</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.98986812475561</Real>
+        <Real Name="Y">-6.9519169823324631</Real>
+        <Real Name="Z">-24.693559761862751</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6449623433216658</Real>
+        <Real Name="Y">9.5489903287699107</Real>
+        <Real Name="Z">10.572434217016557</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.492404816515986</Real>
+        <Real Name="Y">-14.008898225376733</Real>
+        <Real Name="Z">-31.177879266335069</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.465552818511512</Real>
+        <Real Name="Y">13.441348500050335</Real>
+        <Real Name="Z">24.916918735350357</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.258309328324387</Real>
+        <Real Name="Y">19.720428137771759</Real>
+        <Real Name="Z">53.479880143623639</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-293.59223317567375</Real>
+        <Real Name="Y">-159.95457996746177</Real>
+        <Real Name="Z">315.22733819129303</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">235.35770116221781</Real>
+        <Real Name="Y">158.27949060638392</Real>
+        <Real Name="Z">-333.41698346327945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">105.26783364942125</Real>
+        <Real Name="Y">69.192529175340411</Real>
+        <Real Name="Z">-72.462079334667749</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-69.587299673789516</Real>
+        <Real Name="Y">-327.14677271196643</Real>
+        <Real Name="Z">-20.213005181779579</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-16.863059419897247</Real>
+        <Real Name="Y">78.813557542144352</Real>
+        <Real Name="Z">-4.9069859319740772</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-108.94859775096401</Real>
+        <Real Name="Y">37.103545267368247</Real>
+        <Real Name="Z">129.93317503085228</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620600650266304</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620600650266304</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620600650266304</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.013561157891939232</Real>
+        <Real Name="Y">0.5972849492458161</Real>
+        <Real Name="Z">0.23971759155704883</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0059501463973008033</Real>
+        <Real Name="Y">0.6851179604005595</Real>
+        <Real Name="Z">0.27699698339112833</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.058029401355450795</Real>
+        <Real Name="Y">0.61052011020230601</Real>
+        <Real Name="Z">0.15599349563642817</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97659580143923264</Real>
+        <Real Name="Y">0.64048319968601519</Real>
+        <Real Name="Z">1.5684562282863155</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9471997040865987</Real>
+        <Real Name="Y">0.61636363261340277</Real>
+        <Real Name="Z">1.6562994656165959</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94576555625684522</Real>
+        <Real Name="Y">0.7303310108739427</Real>
+        <Real Name="Z">1.5566585502634094</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3930747775745824</Real>
+        <Real Name="Y">0.4516795219120483</Real>
+        <Real Name="Z">1.1805405516365082</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3388982461296359</Real>
+        <Real Name="Y">0.51956813010147052</Real>
+        <Real Name="Z">1.220769381083777</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3362277788895107</Real>
+        <Real Name="Y">0.41135656808768983</Real>
+        <Real Name="Z">1.1149296033475398</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6468114485948104</Real>
+        <Real Name="Y">0.30425972746649155</Real>
+        <Real Name="Z">0.30271194497593457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7108393984972055</Real>
+        <Real Name="Y">0.3363908179943158</Real>
+        <Real Name="Z">0.23922704084283442</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.639113177540714</Real>
+        <Real Name="Y">0.2107427198046995</Real>
+        <Real Name="Z">0.28380098781449653</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7627184073051994</Real>
+        <Real Name="Y">0.38755487777993181</Real>
+        <Real Name="Z">0.020784138774629122</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7277307602408609</Real>
+        <Real Name="Y">0.4266742720951171</Real>
+        <Real Name="Z">1.8027951192261438</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8111404875479364</Real>
+        <Real Name="Y">0.45851815739398583</Real>
+        <Real Name="Z">0.062995908358280145</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.52059443689098461</Real>
+        <Real Name="Y">-0.14902345590769622</Real>
+        <Real Name="Z">-0.40926397826720323</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.2110970507363001</Real>
+        <Real Name="Y">-0.80229622694987479</Real>
+        <Real Name="Z">1.3232458475198023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8365723701988306</Real>
+        <Real Name="Y">1.0186746505159199</Real>
+        <Real Name="Z">0.45137111074889913</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10035739010726291</Real>
+        <Real Name="Y">0.61275840737284348</Real>
+        <Real Name="Z">-0.07029016037841225</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15895473496335305</Real>
+        <Real Name="Y">0.035625203884120632</Real>
+        <Real Name="Z">-0.31291976753887446</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9788109819590387</Real>
+        <Real Name="Y">1.4631426148179665</Real>
+        <Real Name="Z">1.2437599770129308</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2498348268922371</Real>
+        <Real Name="Y">0.31139542245653451</Real>
+        <Real Name="Z">0.41448369825979786</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.78842115585311678</Real>
+        <Real Name="Y">2.1840255658661549</Real>
+        <Real Name="Z">-1.2558072741512063</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1024373357572474</Real>
+        <Real Name="Y">-0.97054513554178601</Real>
+        <Real Name="Z">1.9060337234193523</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.12396199858128185</Real>
+        <Real Name="Y">-0.59704368763111404</Real>
+        <Real Name="Z">0.013396852886839374</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.096442957127430534</Real>
+        <Real Name="Y">1.0104748458784654</Real>
+        <Real Name="Z">0.58143059725495161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9570260859140962</Real>
+        <Real Name="Y">-0.91479984323261176</Real>
+        <Real Name="Z">0.21549540801274411</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96606922665389738</Real>
+        <Real Name="Y">-0.3420673910587797</Real>
+        <Real Name="Z">-0.26438903401365982</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3452441772077144</Real>
+        <Real Name="Y">0.79661930959981553</Real>
+        <Real Name="Z">-0.76115247962872801</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2835817807979808</Real>
+        <Real Name="Y">-1.2181502627463736</Real>
+        <Real Name="Z">1.6252217329745422</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-29.967521635374254</Real>
+        <Real Name="Y">-166.86619976435725</Real>
+        <Real Name="Z">-390.15855499769594</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-14.255171923628666</Real>
+        <Real Name="Y">40.67985554903386</Real>
+        <Real Name="Z">98.874841894403502</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">142.12917827335329</Real>
+        <Real Name="Y">177.11181691096539</Real>
+        <Real Name="Z">161.6642362503909</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.784356413089114</Real>
+        <Real Name="Y">-3.8394171494858043</Real>
+        <Real Name="Z">-39.242746772444121</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.0896022849804083</Real>
+        <Real Name="Y">-0.38916318327134825</Real>
+        <Real Name="Z">13.250258593546945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-6.2391177203536756</Real>
+        <Real Name="Y">5.2242135587778513</Real>
+        <Real Name="Z">15.081933841843139</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">35.835296892007918</Real>
+        <Real Name="Y">-8.6867443671307214</Real>
+        <Real Name="Z">-30.984934291268758</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.279237246947758</Real>
+        <Real Name="Y">1.9813535301474303</Real>
+        <Real Name="Z">25.037085318580509</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.011696052815193</Real>
+        <Real Name="Y">5.7097576109625905</Real>
+        <Real Name="Z">16.858403309742286</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-209.10443670590334</Real>
+        <Real Name="Y">-90.430723788728784</Real>
+        <Real Name="Z">298.35266947334941</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">100.09290721169602</Real>
+        <Real Name="Y">40.752692329607797</Real>
+        <Real Name="Z">-276.87865977860866</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">72.756221638348819</Real>
+        <Real Name="Y">73.939333718555375</Real>
+        <Real Name="Z">-102.1905688183064</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">27.491461256855132</Real>
+        <Real Name="Y">-173.98477234447864</Real>
+        <Real Name="Z">54.400680493161076</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-40.313669424028006</Real>
+        <Real Name="Y">21.280846953341324</Real>
+        <Real Name="Z">-5.4091402039528305</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-48.828968691319005</Real>
+        <Real Name="Y">77.517150436060888</Real>
+        <Real Name="Z">161.34449568725887</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 3">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98716
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562600160298169</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562540142582749</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562540142582749</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562540142582749</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562602679570631</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562602679570631</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562602679570631</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562602679570631</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562602679570631</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562602679570631</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562602679570631</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562606924239949</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562432723667973</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562432723667973</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562432723667973</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562432723667973</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">26.070770945377618</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">26.070576005011425</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">26.062850994325579</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">26.06286705512915</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">26.063111788623662</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">29.964551085666731</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.964580869410803</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.964644423127897</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.964712241844996</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">29.964748707492181</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">29.964713483025076</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">29.991574046567923</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">29.923634745652912</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">20.308774972857805</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">20.303423244171864</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">20.2985148122639</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">20.256943186943023</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">35.343549230704284</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">35.230764661135105</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">35.186684843073699</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">35.215974649908773</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">35.308522886387806</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">39.013848109367771</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">39.260622671887283</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">39.602302043008351</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">40.039103238344374</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">40.571106867715713</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">41.19793756062208</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">41.850137198459109</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">42.592981361452019</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">46.434631238209079</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">48.036458759952687</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">49.457124366572572</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">50.590773492895138</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5683731001120886</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5320182927365291</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.561292038768034</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.653595541752555</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.4760821499476027</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-9.7228269287230411</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.064442746127012</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.501176122745939</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.033143286470095</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.660009203843565</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-12.38061478941661</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-13.191398253324532</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.520740692750078</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-28.127919943179627</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.553493981707476</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.72871473335092</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.19787174590441542</Real>
+        <Real Name="Y">0.1615613889385647</Real>
+        <Real Name="Z">-0.38305665212567802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.7420087544145497</Real>
+        <Real Name="Y">0.75918088595013389</Real>
+        <Real Name="Z">1.2435674032029085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3711369223715755</Real>
+        <Real Name="Y">-0.19170785514288644</Real>
+        <Real Name="Z">0.42562796639667022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19638315205483492</Real>
+        <Real Name="Y">0.14565315135227885</Real>
+        <Real Name="Z">-0.067967185842621486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3802138136646303</Real>
+        <Real Name="Y">-0.58427055558605701</Real>
+        <Real Name="Z">0.23045735337154905</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.9488788834227251</Real>
+        <Real Name="Y">-0.88425910185951861</Real>
+        <Real Name="Z">0.94602094518641222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.023704545495134583</Real>
+        <Real Name="Y">-0.3413031917315365</Real>
+        <Real Name="Z">-0.30920684408559601</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.57458809086462592</Real>
+        <Real Name="Y">-2.6639579923405159</Real>
+        <Real Name="Z">0.20924282970686953</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10717835653133569</Real>
+        <Real Name="Y">-2.1491056124634227</Real>
+        <Real Name="Z">0.10532829628877118</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.012944992862387334</Real>
+        <Real Name="Y">0.24702752779615819</Real>
+        <Real Name="Z">0.1198190834623393</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53415108976374859</Real>
+        <Real Name="Y">-0.39551860957653251</Real>
+        <Real Name="Z">-0.44767485391309769</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23060498264262888</Real>
+        <Real Name="Y">0.091415864029443031</Real>
+        <Real Name="Z">1.125773624901474</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.064052506287219743</Real>
+        <Real Name="Y">0.1556142409020734</Real>
+        <Real Name="Z">0.5494680052322487</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53148313148554538</Real>
+        <Real Name="Y">0.53815672969841799</Real>
+        <Real Name="Z">0.03164652949451436</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.0632897927011018</Real>
+        <Real Name="Y">-0.36976385613194229</Real>
+        <Real Name="Z">-2.4264951267859698</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620600242195762</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620600242195762</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620600242195762</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0093535294425933745</Real>
+        <Real Name="Y">0.598572391863195</Real>
+        <Real Name="Z">0.24241760724803949</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8572951428084827</Real>
+        <Real Name="Y">0.68917796046115665</Real>
+        <Real Name="Z">0.26986974403201569</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.04829168634171023</Real>
+        <Real Name="Y">0.60569228356743499</Real>
+        <Real Name="Z">0.1552657542590225</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97578872244368142</Real>
+        <Real Name="Y">0.63566352831626483</Real>
+        <Real Name="Z">1.5689071694625707</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94881504710619391</Real>
+        <Real Name="Y">0.61590657961146089</Real>
+        <Real Name="Z">1.6585977610352844</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.93033779172912923</Real>
+        <Real Name="Y">0.71715956368717437</Real>
+        <Real Name="Z">1.5475781395736099</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3950519350967645</Real>
+        <Real Name="Y">0.44926497262917725</Real>
+        <Real Name="Z">1.1772382451039782</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3332073703278076</Real>
+        <Real Name="Y">0.50006969880526941</Real>
+        <Real Name="Z">1.2297401308483036</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.344096229560066</Real>
+        <Real Name="Y">0.42017644857268865</Real>
+        <Real Name="Z">1.10160959814086</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6458994598342638</Real>
+        <Real Name="Y">0.30885736584054324</Real>
+        <Real Name="Z">0.30253235359075492</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7090582426396048</Real>
+        <Real Name="Y">0.32980039618075246</Real>
+        <Real Name="Z">0.23372337136665433</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6160418417781839</Real>
+        <Real Name="Y">0.22036071850467448</Real>
+        <Real Name="Z">0.28157562545089831</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7704707465869085</Real>
+        <Real Name="Y">0.39008286940906933</Real>
+        <Real Name="Z">0.022931453557234197</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7175869394610954</Real>
+        <Real Name="Y">0.42066620945599675</Real>
+        <Real Name="Z">1.811301039757665</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8178624712612983</Real>
+        <Real Name="Y">0.46786134841375793</Real>
+        <Real Name="Z">0.052373787637665675</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.53580772842891533</Real>
+        <Real Name="Y">-0.1742698902934951</Real>
+        <Real Name="Z">-0.25583356206943786</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4727045459496788</Real>
+        <Real Name="Y">-0.2047507794738698</Real>
+        <Real Name="Z">0.34928021582177049</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.34978853030439683</Real>
+        <Real Name="Y">-0.0028362452933878707</Real>
+        <Real Name="Z">-0.32533371590693855</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10071265409932498</Real>
+        <Real Name="Y">0.59059603810646311</Real>
+        <Real Name="Z">-0.035014034693205902</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.26336406444416932</Real>
+        <Real Name="Y">0.091977360159904431</Real>
+        <Real Name="Z">-0.25195488232280422</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8575507171509531</Real>
+        <Real Name="Y">1.8701068660494513</Real>
+        <Real Name="Z">0.97547615372635332</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24130853592135698</Real>
+        <Real Name="Y">0.28877833504684813</Real>
+        <Real Name="Z">0.4075120020970035</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.56643266472003262</Real>
+        <Real Name="Y">2.7370303366796742</Real>
+        <Real Name="Z">-0.92979208873672758</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.79715989400967024</Real>
+        <Real Name="Y">-1.2478554419659846</Real>
+        <Real Name="Z">1.3495280947615602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10637153750484818</Real>
+        <Real Name="Y">-0.54563506568525677</Real>
+        <Real Name="Z">0.040439179875400237</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.55547103189880787</Real>
+        <Real Name="Y">0.52896120477842279</Real>
+        <Real Name="Z">0.76604796382393014</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.731669870832417</Real>
+        <Real Name="Y">-1.5480340246429596</Real>
+        <Real Name="Z">0.34247496922951426</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.9617159897688301</Real>
+        <Real Name="Y">-0.2757571766859882</Real>
+        <Real Name="Z">-0.26657900158490333</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1492888699605568</Real>
+        <Real Name="Y">0.70766726044905948</Real>
+        <Real Name="Z">-1.4192058422300629</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.31896400753147719</Real>
+        <Real Name="Y">-1.0864983030824429</Real>
+        <Real Name="Z">0.88111898972280533</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">16.596878133558022</Real>
+        <Real Name="Y">-61.415792623175122</Real>
+        <Real Name="Z">-385.76367559147809</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.347409985674844</Real>
+        <Real Name="Y">22.130720722084078</Real>
+        <Real Name="Z">103.76752485218381</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">143.32369385366999</Real>
+        <Real Name="Y">172.89422898718141</Real>
+        <Real Name="Z">223.72229949837856</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.416556998064209</Real>
+        <Real Name="Y">-8.2813728014812185</Real>
+        <Real Name="Z">-39.807353148849487</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.61712117260052</Real>
+        <Real Name="Y">-12.121763080298784</Real>
+        <Real Name="Z">-23.782495379664731</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.4095374073185951</Real>
+        <Real Name="Y">6.7076842290854835</Real>
+        <Real Name="Z">14.507157350720163</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.69867399146932</Real>
+        <Real Name="Y">-9.2284728904798285</Real>
+        <Real Name="Z">-32.576066873876329</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.316944006824322</Real>
+        <Real Name="Y">4.9631926696804243</Real>
+        <Real Name="Z">27.286434643424322</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-38.005870747991132</Real>
+        <Real Name="Y">17.960731873493923</Real>
+        <Real Name="Z">54.372323408246054</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-255.5905359976615</Real>
+        <Real Name="Y">-98.227494801364841</Real>
+        <Real Name="Z">271.42658249867338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">160.41651062727789</Real>
+        <Real Name="Y">75.617627994369357</Real>
+        <Real Name="Z">-290.33600747490135</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.375360541399502</Real>
+        <Real Name="Y">63.913495021486355</Real>
+        <Real Name="Z">-80.250825389890764</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1825865210201414</Real>
+        <Real Name="Y">-170.0717795506697</Real>
+        <Real Name="Z">51.815023166977369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-39.311344253493928</Real>
+        <Real Name="Y">26.682956091412692</Real>
+        <Real Name="Z">-17.807232531768904</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-99.280566398054958</Real>
+        <Real Name="Y">-31.523961841324251</Real>
+        <Real Name="Z">123.42631097182579</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620583903099712</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620583903099712</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620583903099712</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.007088374047241483</Real>
+        <Real Name="Y">0.59991834041767034</Real>
+        <Real Name="Z">0.2319897597889865</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0048956497928645407</Real>
+        <Real Name="Y">0.67720793283292424</Real>
+        <Real Name="Z">0.28841519079866357</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.082309269460396711</Real>
+        <Real Name="Y">0.61425960542214941</Real>
+        <Real Name="Z">0.17455750916867654</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97335451661626871</Real>
+        <Real Name="Y">0.63034091463330044</Real>
+        <Real Name="Z">1.573623370427031</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94124743622166784</Real>
+        <Real Name="Y">0.57207602683457603</Real>
+        <Real Name="Z">1.6424467431890253</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90214075411576511</Real>
+        <Real Name="Y">0.69281444103480161</Real>
+        <Real Name="Z">1.5599129025472496</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959443095783743</Real>
+        <Real Name="Y">0.44666043570539121</Real>
+        <Real Name="Z">1.1632009197355841</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3338614025127125</Real>
+        <Real Name="Y">0.4701525423020968</Real>
+        <Real Name="Z">1.2321657801931023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3415517361609273</Real>
+        <Real Name="Y">0.4326915750853248</Real>
+        <Real Name="Z">1.0856855193947208</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6414126114223142</Real>
+        <Real Name="Y">0.3191046457705139</Real>
+        <Real Name="Z">0.31263234583929217</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7041454599290913</Real>
+        <Real Name="Y">0.35027404996239547</Real>
+        <Real Name="Z">0.24739910001671689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6268562708483205</Real>
+        <Real Name="Y">0.22725454466211636</Real>
+        <Real Name="Z">0.28996099220809723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7798016634559055</Real>
+        <Real Name="Y">0.39100791347382791</Real>
+        <Real Name="Z">0.024203978510430608</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6904105428135303</Real>
+        <Real Name="Y">0.42112944834335359</Real>
+        <Real Name="Z">0.0079485459599288877</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8165624309311277</Real>
+        <Real Name="Y">0.45610126449214633</Real>
+        <Real Name="Z">0.083985413988664728</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.17196590341604925</Real>
+        <Real Name="Y">0.08505851849373694</Real>
+        <Real Name="Z">-0.96145758354413424</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.70626595324435126</Real>
+        <Real Name="Y">-2.0054927795912292</Real>
+        <Real Name="Z">2.0441781953990943</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5678221176544302</Real>
+        <Real Name="Y">0.17414989641433404</Real>
+        <Real Name="Z">2.0687397501797262</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11851858104845919</Real>
+        <Real Name="Y">-0.055034367833595513</Real>
+        <Real Name="Z">0.29862068201872899</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2271083401023026</Real>
+        <Real Name="Y">-2.5167057012190392</Real>
+        <Real Name="Z">-1.7611218174444665</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.76411619693083821</Real>
+        <Real Name="Y">-0.56538334123347811</Real>
+        <Real Name="Z">1.2675243002125243</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.075624942681916288</Real>
+        <Real Name="Y">-0.020989760898961551</Real>
+        <Real Name="Z">-0.67175289933853888</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43072385923552786</Real>
+        <Real Name="Y">-0.3780050814259851</Real>
+        <Real Name="Z">-0.089074578099002502</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.67110706360759886</Real>
+        <Real Name="Y">0.16226042992220341</Real>
+        <Real Name="Z">-0.2903681484562402</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24561585225584484</Real>
+        <Real Name="Y">0.35497882966820099</Real>
+        <Real Name="Z">0.60164449849684176</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.3148727039267335</Real>
+        <Real Name="Y">1.4506146767731696</Real>
+        <Real Name="Z">1.6442201775680916</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3213582664169654</Real>
+        <Real Name="Y">-0.13544610262315659</Real>
+        <Real Name="Z">0.78898861963670719</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.032271631040131976</Real>
+        <Real Name="Y">0.054351108112427458</Real>
+        <Real Name="Z">0.015260269946552786</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63952415588366451</Real>
+        <Real Name="Y">-0.38884276312314925</Real>
+        <Real Name="Z">2.6541960390314725</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.30088540647786616</Real>
+        <Real Name="Y">-2.4376038192828924</Real>
+        <Real Name="Z">3.0641161799376446</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-165.59990608123613</Real>
+        <Real Name="Y">-319.14650040741572</Real>
+        <Real Name="Z">-377.24351672646935</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.500401618303464</Real>
+        <Real Name="Y">68.321699879218627</Real>
+        <Real Name="Z">100.04194000729319</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.71205874573471</Real>
+        <Real Name="Y">141.91159639429247</Real>
+        <Real Name="Z">72.10778459196024</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.224105545381121</Real>
+        <Real Name="Y">-15.094101300366603</Real>
+        <Real Name="Z">-36.560649870541653</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.3552392256092602</Real>
+        <Real Name="Y">2.7187462087188976</Real>
+        <Real Name="Z">14.708162508816706</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1764088308408631</Real>
+        <Real Name="Y">7.4052387980883374</Real>
+        <Real Name="Z">12.126470032264898</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.231834692698058</Real>
+        <Real Name="Y">-17.59162520425987</Real>
+        <Real Name="Z">-31.282849718191294</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.418818156672636</Real>
+        <Real Name="Y">14.940099156764948</Real>
+        <Real Name="Z">25.19947331150771</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.5054740249564169</Real>
+        <Real Name="Y">7.6216423410542902</Real>
+        <Real Name="Z">15.809393736143633</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-179.80571018053251</Real>
+        <Real Name="Y">3.9611470358213126</Real>
+        <Real Name="Z">101.28678633351251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">146.46280254932086</Real>
+        <Real Name="Y">-33.253862982533931</Real>
+        <Real Name="Z">-82.280237851221102</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">72.292208521703927</Real>
+        <Real Name="Y">9.4069390386156897</Real>
+        <Real Name="Z">-49.194712459026391</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.667914051295327</Real>
+        <Real Name="Y">-311.22847356968657</Real>
+        <Real Name="Z">-20.719467235725631</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.333103377663406</Real>
+        <Real Name="Y">116.77852719859757</Real>
+        <Real Name="Z">-0.34064597109647821</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.439162255664357</Real>
+        <Real Name="Y">323.24892741309054</Real>
+        <Real Name="Z">256.3420693107729</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_ParrinelloRahman_4Ranks_1RanksPerSimulation_s.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_ParrinelloRahman_4Ranks_1RanksPerSimulation_s.xml
new file mode 100644 (file)
index 0000000..93354ff
--- /dev/null
@@ -0,0 +1,3398 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562597</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562569</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562569</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562569</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562597</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562597</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562597</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562597</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562597</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562597</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562597</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562731</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562349</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562349</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562349</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562349</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">20.344719</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">20.345821</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">20.35939</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">20.360376</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">20.36096</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">18.80208</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">18.802179</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">18.802076</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">18.801966</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">18.80158</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">18.825708</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">18.804052</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">18.825514</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">26.078661</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">26.080217</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">26.081722</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">26.09244</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629332</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">30.128056</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.774372</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">31.560455</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">32.502838</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">28.693203</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.224548</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.902695</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">30.724957</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">31.686895</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">32.729115</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">33.863823</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">35.107834</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">38.665844</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">39.36599</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">40.1544</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">41.019016</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.158316</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.791063</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.576159</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.517959</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.261872</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.793117</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.471367</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.293738</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.256063</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.274155</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.38686</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.609409</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-13.0168</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-13.715389</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-14.502295</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-15.356194</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13823938</Real>
+        <Real Name="Y">-0.083000772</Real>
+        <Real Name="Z">-0.55156732</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807449</Real>
+        <Real Name="Y">0.12591785</Real>
+        <Real Name="Z">0.086322196</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50557399</Real>
+        <Real Name="Y">-0.26345637</Real>
+        <Real Name="Z">-0.37042341</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.080341451</Real>
+        <Real Name="Y">-0.036381256</Real>
+        <Real Name="Z">0.2694976</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0880266</Real>
+        <Real Name="Y">-2.6992292</Real>
+        <Real Name="Z">-0.41159731</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0053114</Real>
+        <Real Name="Y">-0.44618699</Real>
+        <Real Name="Z">1.1535</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046993218</Real>
+        <Real Name="Y">-0.027141469</Real>
+        <Real Name="Z">-0.68357778</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051991098</Real>
+        <Real Name="Y">-0.42392981</Real>
+        <Real Name="Z">-0.38236645</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25138494</Real>
+        <Real Name="Y">0.072344378</Real>
+        <Real Name="Z">-0.58373684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20046787</Real>
+        <Real Name="Y">0.39459831</Real>
+        <Real Name="Z">0.71750742</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21663746</Real>
+        <Real Name="Y">1.2108052</Real>
+        <Real Name="Z">0.86115432</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3770657</Real>
+        <Real Name="Y">-0.66109222</Real>
+        <Real Name="Z">0.87071204</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21701036</Real>
+        <Real Name="Y">-0.090551347</Real>
+        <Real Name="Z">-0.034703776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639677</Real>
+        <Real Name="Y">0.96361506</Real>
+        <Real Name="Z">2.5346279</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37429887</Real>
+        <Real Name="Y">-0.37906641</Real>
+        <Real Name="Z">0.73122346</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0031772675</Real>
+        <Real Name="Y">0.59435815</Real>
+        <Real Name="Z">0.24346919</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8501325</Real>
+        <Real Name="Y">0.6844092</Real>
+        <Real Name="Z">0.27219144</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.05903659</Real>
+        <Real Name="Y">0.60286212</Real>
+        <Real Name="Z">0.16620512</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97851872</Real>
+        <Real Name="Y">0.63000584</Real>
+        <Real Name="Z">1.5703605</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96160591</Real>
+        <Real Name="Y">0.62393808</Real>
+        <Real Name="Z">1.6643789</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92784786</Real>
+        <Real Name="Y">0.70599467</Real>
+        <Real Name="Z">1.5417166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3933177</Real>
+        <Real Name="Y">0.44734499</Real>
+        <Real Name="Z">1.1773255</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3334372</Real>
+        <Real Name="Y">0.47714666</Real>
+        <Real Name="Z">1.2457981</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3360575</Real>
+        <Real Name="Y">0.41481835</Real>
+        <Real Name="Z">1.1078589</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6470523</Real>
+        <Real Name="Y">0.315615</Real>
+        <Real Name="Z">0.29910994</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7056124</Real>
+        <Real Name="Y">0.33259118</Real>
+        <Real Name="Z">0.22532079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5974864</Real>
+        <Real Name="Y">0.23798651</Real>
+        <Real Name="Z">0.27304548</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7765465</Real>
+        <Real Name="Y">0.39595881</Real>
+        <Real Name="Z">0.022771422</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7121646</Real>
+        <Real Name="Y">0.4098416</Real>
+        <Real Name="Z">1.8153723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8067023</Real>
+        <Real Name="Y">0.4839223</Real>
+        <Real Name="Z">0.045473218</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.23481014</Real>
+        <Real Name="Y">-0.68788511</Real>
+        <Real Name="Z">-0.13555899</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.59085131</Real>
+        <Real Name="Y">-0.79436761</Real>
+        <Real Name="Z">0.65548515</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6594534</Real>
+        <Real Name="Y">-0.59338421</Real>
+        <Real Name="Z">1.2093362</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43871173</Real>
+        <Real Name="Y">-0.11980366</Real>
+        <Real Name="Z">0.15840614</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4191811</Real>
+        <Real Name="Y">1.0234627</Real>
+        <Real Name="Z">0.42105603</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5175936</Real>
+        <Real Name="Y">0.58942425</Real>
+        <Real Name="Z">0.10242487</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.47850975</Real>
+        <Real Name="Y">0.038679577</Real>
+        <Real Name="Z">0.39961845</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.51601094</Real>
+        <Real Name="Y">0.091345549</Real>
+        <Real Name="Z">1.259051</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.4941276</Real>
+        <Real Name="Y">-1.9514664</Real>
+        <Real Name="Z">2.1114922</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24770613</Real>
+        <Real Name="Y">0.31820211</Real>
+        <Real Name="Z">-0.37890229</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.28458431</Real>
+        <Real Name="Y">0.83112139</Real>
+        <Real Name="Z">-0.23365732</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38870722</Real>
+        <Real Name="Y">0.38992894</Real>
+        <Real Name="Z">-0.86572438</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19439927</Real>
+        <Real Name="Y">0.45184973</Real>
+        <Real Name="Z">-0.27704307</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.402006</Real>
+        <Real Name="Y">-0.5181514</Real>
+        <Real Name="Z">-1.0372642</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7716932</Real>
+        <Real Name="Y">0.91559154</Real>
+        <Real Name="Z">0.083725035</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.5468292</Real>
+        <Real Name="Y">59.477936</Real>
+        <Real Name="Z">-374.00726</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.0362663</Real>
+        <Real Name="Y">1.5119858</Real>
+        <Real Name="Z">111.89647</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.44461</Real>
+        <Real Name="Y">64.585808</Real>
+        <Real Name="Z">206.25967</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.599312</Real>
+        <Real Name="Y">-18.882107</Real>
+        <Real Name="Z">-38.890167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.688286</Real>
+        <Real Name="Y">-9.5329113</Real>
+        <Real Name="Z">-24.582653</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4431915</Real>
+        <Real Name="Y">10.52363</Real>
+        <Real Name="Z">12.975765</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.567505</Real>
+        <Real Name="Y">-7.2569618</Real>
+        <Real Name="Z">-33.30619</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-56.956566</Real>
+        <Real Name="Y">11.27441</Real>
+        <Real Name="Z">-15.073364</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.637596</Real>
+        <Real Name="Y">18.882315</Real>
+        <Real Name="Z">56.492878</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-308.66461</Real>
+        <Real Name="Y">-122.41221</Real>
+        <Real Name="Z">255.24008</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.54044</Real>
+        <Real Name="Y">106.62807</Real>
+        <Real Name="Z">-280.35159</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">113.88762</Real>
+        <Real Name="Y">55.172935</Real>
+        <Real Name="Z">-58.089142</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-58.715485</Real>
+        <Real Name="Y">-239.85184</Real>
+        <Real Name="Z">-1.3132324</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.0928154</Real>
+        <Real Name="Y">45.388027</Real>
+        <Real Name="Z">17.136444</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-101.82002</Real>
+        <Real Name="Y">24.490936</Real>
+        <Real Name="Z">165.61224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620576</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620576</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620576</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0034244696</Real>
+        <Real Name="Y">0.60667223</Real>
+        <Real Name="Z">0.23537673</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.025037404</Real>
+        <Real Name="Y">0.66597372</Real>
+        <Real Name="Z">0.30733871</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.08511541</Real>
+        <Real Name="Y">0.59771973</Real>
+        <Real Name="Z">0.18629761</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97170818</Real>
+        <Real Name="Y">0.63342589</Real>
+        <Real Name="Z">1.5675435</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97538167</Real>
+        <Real Name="Y">0.60600179</Real>
+        <Real Name="Z">1.6591773</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.88966358</Real>
+        <Real Name="Y">0.68220532</Real>
+        <Real Name="Z">1.5603626</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959149</Real>
+        <Real Name="Y">0.44154215</Real>
+        <Real Name="Z">1.1692275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3338782</Real>
+        <Real Name="Y">0.4359113</Real>
+        <Real Name="Z">1.2419052</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3516617</Real>
+        <Real Name="Y">0.39784992</Real>
+        <Real Name="Z">1.0964611</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6451583</Real>
+        <Real Name="Y">0.31683764</Real>
+        <Real Name="Z">0.30359417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6952109</Real>
+        <Real Name="Y">0.33305693</Real>
+        <Real Name="Z">0.22363183</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5994601</Real>
+        <Real Name="Y">0.23438528</Real>
+        <Real Name="Z">0.28699273</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7765268</Real>
+        <Real Name="Y">0.39364183</Real>
+        <Real Name="Z">0.033313546</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7164505</Real>
+        <Real Name="Y">0.42439654</Real>
+        <Real Name="Z">1.827494</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8493676</Real>
+        <Real Name="Y">0.45569193</Real>
+        <Real Name="Z">0.030801222</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11501376</Real>
+        <Real Name="Y">0.66863501</Real>
+        <Real Name="Z">-0.63013035</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.65512604</Real>
+        <Real Name="Y">-3.5157816</Real>
+        <Real Name="Z">2.8643954</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7850171</Real>
+        <Real Name="Y">-1.7458638</Real>
+        <Real Name="Z">2.4081395</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20602582</Real>
+        <Real Name="Y">0.14856124</Real>
+        <Real Name="Z">-0.11506297</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5583168</Real>
+        <Real Name="Y">-0.5009051</Real>
+        <Real Name="Z">-0.36067939</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.3057373</Real>
+        <Real Name="Y">-1.4254844</Real>
+        <Real Name="Z">1.3500983</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.13735746</Real>
+        <Real Name="Y">-0.36089236</Real>
+        <Real Name="Z">-0.2856335</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95294398</Real>
+        <Real Name="Y">-2.243969</Real>
+        <Real Name="Z">0.53625298</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25700936</Real>
+        <Real Name="Y">-1.8381097</Real>
+        <Real Name="Z">0.34274292</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.014475021</Real>
+        <Real Name="Y">0.22312607</Real>
+        <Real Name="Z">0.086713627</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.61348397</Real>
+        <Real Name="Y">1.1346548</Real>
+        <Real Name="Z">-0.12940511</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.60657972</Real>
+        <Real Name="Y">-0.064330287</Real>
+        <Real Name="Z">-0.12982269</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11867321</Real>
+        <Real Name="Y">-0.0018169922</Real>
+        <Real Name="Z">0.47892767</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.32829669</Real>
+        <Real Name="Y">0.813021</Real>
+        <Real Name="Z">0.44622862</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.0545353</Real>
+        <Real Name="Y">-1.368561</Real>
+        <Real Name="Z">0.055566382</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">156.42841</Real>
+        <Real Name="Y">104.37057</Real>
+        <Real Name="Z">-274.03284</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-42.954235</Real>
+        <Real Name="Y">-33.855457</Real>
+        <Real Name="Z">76.320534</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.572784</Real>
+        <Real Name="Y">42.054924</Real>
+        <Real Name="Z">191.12967</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">9.6619949</Real>
+        <Real Name="Y">-26.822617</Real>
+        <Real Name="Z">-24.435623</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.329971</Real>
+        <Real Name="Y">-5.3412228</Real>
+        <Real Name="Z">-27.231701</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">26.791904</Real>
+        <Real Name="Y">-8.7982483</Real>
+        <Real Name="Z">-23.47459</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.609238</Real>
+        <Real Name="Y">-17.19318</Real>
+        <Real Name="Z">-27.830158</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.366589</Real>
+        <Real Name="Y">17.41328</Real>
+        <Real Name="Z">-21.445671</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-67.022026</Real>
+        <Real Name="Y">41.554504</Real>
+        <Real Name="Z">83.096748</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-261.23346</Real>
+        <Real Name="Y">-176.4183</Real>
+        <Real Name="Z">381.99588</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">235.5159</Real>
+        <Real Name="Y">176.96829</Real>
+        <Real Name="Z">-391.77396</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.623047</Real>
+        <Real Name="Y">78.969292</Real>
+        <Real Name="Z">-89.362717</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-94.884567</Real>
+        <Real Name="Y">-433.30225</Real>
+        <Real Name="Z">8.1679382</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.151274</Real>
+        <Real Name="Y">113.81444</Real>
+        <Real Name="Z">38.639099</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.22362</Real>
+        <Real Name="Y">126.58598</Real>
+        <Real Name="Z">100.23735</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562597</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562597</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562597</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562597</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562569</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562569</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562569</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562569</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562535</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562535</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562535</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562349</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562731</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562731</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562731</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562731</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">18.791607</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">18.791725</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">18.805605</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">18.805708</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">18.805866</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">20.365242</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">20.365387</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">20.364643</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">20.363539</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">26.059879</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">26.095703</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">26.104897</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">26.08128</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">18.828205</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">18.826818</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">18.824976</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">18.823307</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">28.072332</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">27.982103</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">27.988964</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">28.075342</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">28.31002</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">33.602951</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.858715</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">36.263237</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.80336</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">36.704548</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">37.128838</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">37.550087</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">38.052925</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">36.422859</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">37.812477</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">39.254921</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">40.725815</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5650139</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5579958</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6442699</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8787899</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.61768</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.873298</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.278564</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.819792</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.044959</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.433427</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-11.878696</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-12.405151</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.925631</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.316635</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.760921</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.233484</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21190877</Real>
+        <Real Name="Y">-0.73113304</Real>
+        <Real Name="Z">0.011277338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.66796941</Real>
+        <Real Name="Y">-0.44908154</Real>
+        <Real Name="Z">-0.19935304</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.080868699</Real>
+        <Real Name="Y">-1.3642008</Real>
+        <Real Name="Z">0.095872603</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44769731</Real>
+        <Real Name="Y">-0.12958133</Real>
+        <Real Name="Z">0.17146564</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1259595</Real>
+        <Real Name="Y">1.2299777</Real>
+        <Real Name="Z">0.59934753</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4102879</Real>
+        <Real Name="Y">0.66582245</Real>
+        <Real Name="Z">0.10724045</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.42090845</Real>
+        <Real Name="Y">0.039798632</Real>
+        <Real Name="Z">0.42398912</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31489116</Real>
+        <Real Name="Y">0.033143241</Real>
+        <Real Name="Z">1.2373283</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7872748</Real>
+        <Real Name="Y">-2.0657148</Real>
+        <Real Name="Z">1.5960392</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26079154</Real>
+        <Real Name="Y">0.32045048</Real>
+        <Real Name="Z">-0.34788135</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.14831775</Real>
+        <Real Name="Y">0.34903857</Real>
+        <Real Name="Z">-0.43145278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019986875</Real>
+        <Real Name="Y">0.52854216</Real>
+        <Real Name="Z">-0.45931953</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15528721</Real>
+        <Real Name="Y">0.54477292</Real>
+        <Real Name="Z">-0.27405369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25908729</Real>
+        <Real Name="Y">-0.78199595</Real>
+        <Real Name="Z">-1.2374361</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93642789</Real>
+        <Real Name="Y">1.1511997</Real>
+        <Real Name="Z">-1.0669613</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620597</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620597</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620597</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059800362</Real>
+        <Real Name="Y">0.59962511</Real>
+        <Real Name="Z">0.2388759</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8579626</Real>
+        <Real Name="Y">0.6877023</Real>
+        <Real Name="Z">0.27497539</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062415533</Real>
+        <Real Name="Y">0.61132389</Real>
+        <Real Name="Z">0.16245279</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97424376</Real>
+        <Real Name="Y">0.63071269</Real>
+        <Real Name="Z">1.5712773</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94452566</Real>
+        <Real Name="Y">0.59312117</Real>
+        <Real Name="Z">1.6541388</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9086231</Real>
+        <Real Name="Y">0.69711834</Real>
+        <Real Name="Z">1.5501459</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3964937</Real>
+        <Real Name="Y">0.44683182</Real>
+        <Real Name="Z">1.1685987</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3311406</Real>
+        <Real Name="Y">0.47333977</Real>
+        <Real Name="Z">1.2333184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3462207</Real>
+        <Real Name="Y">0.43159303</Real>
+        <Real Name="Z">1.0885816</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.643316</Real>
+        <Real Name="Y">0.31615916</Real>
+        <Real Name="Z">0.30757636</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7027955</Real>
+        <Real Name="Y">0.33864319</Real>
+        <Real Name="Z">0.23602939</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6093986</Real>
+        <Real Name="Y">0.22972292</Real>
+        <Real Name="Z">0.28432336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7792749</Real>
+        <Real Name="Y">0.39118055</Real>
+        <Real Name="Z">0.024518993</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6974218</Real>
+        <Real Name="Y">0.42105407</Real>
+        <Real Name="Z">1.846956</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8185171</Real>
+        <Real Name="Y">0.47042087</Real>
+        <Real Name="Z">0.061170582</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11737773</Real>
+        <Real Name="Y">-0.020628737</Real>
+        <Real Name="Z">-0.72704792</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.500302</Real>
+        <Real Name="Y">-0.57572794</Real>
+        <Real Name="Z">1.0898212</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0612791</Real>
+        <Real Name="Y">0.4238165</Real>
+        <Real Name="Z">0.7364856</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10070693</Real>
+        <Real Name="Y">-0.038040854</Real>
+        <Real Name="Z">0.28581458</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.65078604</Real>
+        <Real Name="Y">-2.7293489</Real>
+        <Real Name="Z">-1.0756631</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.87467366</Real>
+        <Real Name="Y">-0.50787324</Real>
+        <Real Name="Z">1.1748987</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.06002387</Real>
+        <Real Name="Y">-0.022458689</Real>
+        <Real Name="Z">-0.6782853</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2286894</Real>
+        <Real Name="Y">-0.41845098</Real>
+        <Real Name="Z">-0.22088853</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46781006</Real>
+        <Real Name="Y">0.10878451</Real>
+        <Real Name="Z">-0.44839978</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.224693</Real>
+        <Real Name="Y">0.38152522</Real>
+        <Real Name="Z">0.66925645</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019214023</Real>
+        <Real Name="Y">1.4425762</Real>
+        <Real Name="Z">1.1636043</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9404812</Real>
+        <Real Name="Y">-0.49722528</Real>
+        <Real Name="Z">0.66008115</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11612592</Real>
+        <Real Name="Y">-0.095147252</Real>
+        <Real Name="Z">-0.071049713</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2097895</Real>
+        <Real Name="Y">0.50520486</Real>
+        <Real Name="Z">2.9769249</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.097227305</Real>
+        <Real Name="Y">-1.0094522</Real>
+        <Real Name="Z">2.2175608</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-67.305252</Real>
+        <Real Name="Y">-110.64915</Real>
+        <Real Name="Z">-418.09567</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45508194</Real>
+        <Real Name="Y">35.587311</Real>
+        <Real Name="Z">108.83005</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">177.09151</Real>
+        <Real Name="Y">149.00174</Real>
+        <Real Name="Z">168.3188</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.745712</Real>
+        <Real Name="Y">-14.351944</Real>
+        <Real Name="Z">-37.638168</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.748779</Real>
+        <Real Name="Y">-8.0131025</Real>
+        <Real Name="Z">-23.772495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3077431</Real>
+        <Real Name="Y">7.6753006</Real>
+        <Real Name="Z">12.778206</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.157379</Real>
+        <Real Name="Y">-14.35561</Real>
+        <Real Name="Z">-32.970016</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.423615</Real>
+        <Real Name="Y">12.125118</Real>
+        <Real Name="Z">27.147602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.920513</Real>
+        <Real Name="Y">16.920238</Real>
+        <Real Name="Z">54.454868</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-257.06952</Real>
+        <Real Name="Y">-51.516083</Real>
+        <Real Name="Z">176.05173</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">211.81612</Real>
+        <Real Name="Y">25.161041</Real>
+        <Real Name="Z">-196.50034</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.512535</Real>
+        <Real Name="Y">32.904861</Real>
+        <Real Name="Z">-53.832611</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.628113</Real>
+        <Real Name="Y">-234.67686</Real>
+        <Real Name="Z">8.3063354</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.22496</Real>
+        <Real Name="Y">75.865753</Real>
+        <Real Name="Z">-10.555634</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.647369</Real>
+        <Real Name="Y">78.321396</Real>
+        <Real Name="Z">217.47739</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620613</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620613</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620613</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0013510671</Real>
+        <Real Name="Y">0.58925784</Real>
+        <Real Name="Z">0.24148585</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8539735</Real>
+        <Real Name="Y">0.67557329</Real>
+        <Real Name="Z">0.28177068</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076753967</Real>
+        <Real Name="Y">0.59809816</Real>
+        <Real Name="Z">0.1831886</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98198467</Real>
+        <Real Name="Y">0.62911624</Real>
+        <Real Name="Z">1.5716342</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97389215</Real>
+        <Real Name="Y">0.63121885</Real>
+        <Real Name="Z">1.6669883</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94044673</Real>
+        <Real Name="Y">0.71018624</Real>
+        <Real Name="Z">1.5422306</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3892162</Real>
+        <Real Name="Y">0.44760504</Real>
+        <Real Name="Z">1.1804351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3380529</Real>
+        <Real Name="Y">0.47841886</Real>
+        <Real Name="Z">1.2552358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.326269</Real>
+        <Real Name="Y">0.39998102</Real>
+        <Real Name="Z">1.1262878</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6489791</Real>
+        <Real Name="Y">0.31813651</Real>
+        <Real Name="Z">0.29594502</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7083889</Real>
+        <Real Name="Y">0.34140766</Real>
+        <Real Name="Z">0.22459212</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6025262</Real>
+        <Real Name="Y">0.24069609</Real>
+        <Real Name="Z">0.26420504</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.77494</Real>
+        <Real Name="Y">0.39924172</Real>
+        <Real Name="Z">0.020622814</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7158679</Real>
+        <Real Name="Y">0.40780699</Real>
+        <Real Name="Z">1.8078545</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7879752</Real>
+        <Real Name="Y">0.48897022</Real>
+        <Real Name="Z">0.051301654</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.2115076</Real>
+        <Real Name="Y">-0.58657956</Real>
+        <Real Name="Z">-0.3448616</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.34103817</Real>
+        <Real Name="Y">-1.4211071</Real>
+        <Real Name="Z">1.633618</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4302576</Real>
+        <Real Name="Y">-0.77699631</Real>
+        <Real Name="Z">2.8931055</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42860568</Real>
+        <Real Name="Y">-0.10316841</Real>
+        <Real Name="Z">0.16359788</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.599167</Real>
+        <Real Name="Y">0.82689649</Real>
+        <Real Name="Z">0.25425303</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6171958</Real>
+        <Real Name="Y">0.46423465</Real>
+        <Real Name="Z">0.019135954</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53760922</Real>
+        <Real Name="Y">0.025839394</Real>
+        <Real Name="Z">0.38085407</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.59669191</Real>
+        <Real Name="Y">0.2134524</Real>
+        <Real Name="Z">1.0915993</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.98501021</Real>
+        <Real Name="Y">-1.7711105</Real>
+        <Real Name="Z">2.4115789</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23553587</Real>
+        <Real Name="Y">0.31257027</Real>
+        <Real Name="Z">-0.40931988</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39327651</Real>
+        <Real Name="Y">1.292789</Real>
+        <Real Name="Z">0.033397716</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.81982857</Real>
+        <Real Name="Y">0.31264123</Real>
+        <Real Name="Z">-1.2820736</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20261706</Real>
+        <Real Name="Y">0.38582489</Real>
+        <Real Name="Z">-0.25594568</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50791037</Real>
+        <Real Name="Y">0.0060716346</Real>
+        <Real Name="Z">-0.86712694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7556548</Real>
+        <Real Name="Y">0.30580643</Real>
+        <Real Name="Z">1.2038472</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-78.21843</Real>
+        <Real Name="Y">65.500732</Real>
+        <Real Name="Z">-364.76282</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.492878</Real>
+        <Real Name="Y">0.2137146</Real>
+        <Real Name="Z">112.05481</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">134.87009</Real>
+        <Real Name="Y">1.3446732</Real>
+        <Real Name="Z">132.01221</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.866722</Real>
+        <Real Name="Y">-23.824131</Real>
+        <Real Name="Z">-37.657913</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.721981</Real>
+        <Real Name="Y">7.1210117</Real>
+        <Real Name="Z">14.358871</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.3680763</Real>
+        <Real Name="Y">12.895979</Real>
+        <Real Name="Z">11.845959</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.813995</Real>
+        <Real Name="Y">-3.8712502</Real>
+        <Real Name="Z">-32.264458</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.312809</Real>
+        <Real Name="Y">9.01194</Real>
+        <Real Name="Z">-18.198658</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.2038</Real>
+        <Real Name="Y">4.2594681</Real>
+        <Real Name="Z">18.144405</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-315.42337</Real>
+        <Real Name="Y">-131.22447</Real>
+        <Real Name="Z">277.77576</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">243.7832</Real>
+        <Real Name="Y">100.62667</Real>
+        <Real Name="Z">-284.88235</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">118.75096</Real>
+        <Real Name="Y">60.674019</Real>
+        <Real Name="Z">-65.373169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-75.898712</Real>
+        <Real Name="Y">-323.46143</Real>
+        <Real Name="Z">-35.473328</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.987488</Real>
+        <Real Name="Y">58.142944</Real>
+        <Real Name="Z">26.498276</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-22.418167</Real>
+        <Real Name="Y">162.59016</Real>
+        <Real Name="Z">245.92236</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 2">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98715
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562597</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562597</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562597</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562597</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562535</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562535</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562535</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562535</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562569</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562569</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562569</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562421</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562597</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562597</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562597</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562597</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.98745</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.987299</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.960842</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.96067</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">29.960554</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">26.059542</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">26.060318</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">26.061373</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">26.062513</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">20.365326</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">20.362499</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">20.339785</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">20.309885</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">29.919106</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">29.918312</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">29.897968</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">29.896759</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">39.264248</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">39.004894</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">38.843525</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">38.804882</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">38.861839</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">35.462696</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">35.678097</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">35.955452</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">36.296677</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">39.458138</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">41.197662</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">42.956924</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">44.712624</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">43.490711</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">44.469757</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">45.473545</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">46.487946</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.4404144</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.3055019</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.2670307</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.3241034</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.807373</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.021997</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.298299</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.638383</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.476709</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.219061</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-23.008057</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.793655</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-14.089692</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-15.06953</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-16.093662</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-17.109272</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.55872297</Real>
+        <Real Name="Y">-0.19543174</Real>
+        <Real Name="Z">-0.12331802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5561588</Real>
+        <Real Name="Y">0.15019241</Real>
+        <Real Name="Z">-0.44760495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2265118</Real>
+        <Real Name="Y">-1.1768512</Real>
+        <Real Name="Z">-1.2616764</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10263991</Real>
+        <Real Name="Y">0.57440907</Real>
+        <Real Name="Z">0.0053722998</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.35943791</Real>
+        <Real Name="Y">0.13711332</Real>
+        <Real Name="Z">-0.18872896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6768553</Real>
+        <Real Name="Y">2.2024438</Real>
+        <Real Name="Z">0.65932018</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22449927</Real>
+        <Real Name="Y">0.27064398</Real>
+        <Real Name="Z">0.38681656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.18288493</Real>
+        <Real Name="Y">3.1066663</Real>
+        <Real Name="Z">-0.46535692</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.43482876</Real>
+        <Real Name="Y">-1.4385394</Real>
+        <Real Name="Z">0.8301881</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11927342</Real>
+        <Real Name="Y">-0.50285125</Real>
+        <Real Name="Z">0.091731116</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.6758315</Real>
+        <Real Name="Y">-0.055776317</Real>
+        <Real Name="Z">0.61587429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2213309</Real>
+        <Real Name="Y">-1.9672643</Real>
+        <Real Name="Z">0.44974977</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.90470046</Real>
+        <Real Name="Y">-0.2009875</Real>
+        <Real Name="Z">-0.24253644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.8438639</Real>
+        <Real Name="Y">0.72260296</Real>
+        <Real Name="Z">-1.8703772</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39639631</Real>
+        <Real Name="Y">-0.8200264</Real>
+        <Real Name="Z">-0.19537324</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620594</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620594</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620594</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0035309815</Real>
+        <Real Name="Y">0.60228974</Real>
+        <Real Name="Z">0.24021335</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.010584869</Real>
+        <Real Name="Y">0.68650538</Real>
+        <Real Name="Z">0.28516093</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.067659266</Real>
+        <Real Name="Y">0.60746807</Real>
+        <Real Name="Z">0.16933975</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9733696</Real>
+        <Real Name="Y">0.63220698</Real>
+        <Real Name="Z">1.5683872</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96295214</Real>
+        <Real Name="Y">0.61033231</Real>
+        <Real Name="Z">1.66099</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90153885</Real>
+        <Real Name="Y">0.69267672</Real>
+        <Real Name="Z">1.5497842</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3967459</Real>
+        <Real Name="Y">0.44433245</Real>
+        <Real Name="Z">1.1715895</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3288437</Real>
+        <Real Name="Y">0.45539242</Real>
+        <Real Name="Z">1.2381423</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3496376</Real>
+        <Real Name="Y">0.41369313</Real>
+        <Real Name="Z">1.0941017</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450871</Real>
+        <Real Name="Y">0.31500164</Real>
+        <Real Name="Z">0.30286792</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6997141</Real>
+        <Real Name="Y">0.32709458</Real>
+        <Real Name="Z">0.22520211</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5959635</Real>
+        <Real Name="Y">0.23472798</Real>
+        <Real Name="Z">0.28539467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7773647</Real>
+        <Real Name="Y">0.39318204</Real>
+        <Real Name="Z">0.029312987</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7133778</Real>
+        <Real Name="Y">0.41904986</Real>
+        <Real Name="Z">1.8250486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8376274</Real>
+        <Real Name="Y">0.46735284</Real>
+        <Real Name="Z">0.03473733</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.14170483</Real>
+        <Real Name="Y">0.39028263</Real>
+        <Real Name="Z">-0.54479516</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.98756</Real>
+        <Real Name="Y">-1.3149718</Real>
+        <Real Name="Z">2.396687</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3907585</Real>
+        <Real Name="Y">-0.57653356</Real>
+        <Real Name="Z">1.5919579</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20588334</Real>
+        <Real Name="Y">0.15413834</Real>
+        <Real Name="Z">-0.09270595</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.521161</Real>
+        <Real Name="Y">-0.57890171</Real>
+        <Real Name="Z">-0.052677125</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.6948118</Real>
+        <Real Name="Y">-1.1573412</Real>
+        <Real Name="Z">1.2394009</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.058469445</Real>
+        <Real Name="Y">-0.33743429</Real>
+        <Real Name="Z">-0.30401522</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.20039357</Real>
+        <Real Name="Y">-2.6226571</Real>
+        <Real Name="Z">0.38305604</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.1787789</Real>
+        <Real Name="Y">-2.1167388</Real>
+        <Real Name="Z">0.2324881</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0058476813</Real>
+        <Real Name="Y">0.23799747</Real>
+        <Real Name="Z">0.095719263</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.51380646</Real>
+        <Real Name="Y">0.2460199</Real>
+        <Real Name="Z">-0.27114168</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.20806241</Real>
+        <Real Name="Y">0.00055955083</Real>
+        <Real Name="Z">0.60771406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.088818423</Real>
+        <Real Name="Y">0.12197801</Real>
+        <Real Name="Z">0.52645081</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45693463</Real>
+        <Real Name="Y">0.5252685</Real>
+        <Real Name="Z">0.15275593</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0270569</Real>
+        <Real Name="Y">-1.4037397</Real>
+        <Real Name="Z">-1.2115136</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">116.49631</Real>
+        <Real Name="Y">84.508987</Real>
+        <Real Name="Z">-320.08206</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-30.184189</Real>
+        <Real Name="Y">-17.882553</Real>
+        <Real Name="Z">88.293961</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">62.053902</Real>
+        <Real Name="Y">77.086159</Real>
+        <Real Name="Z">217.62656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.886497</Real>
+        <Real Name="Y">-21.749969</Real>
+        <Real Name="Z">-33.09774</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.989891</Real>
+        <Real Name="Y">-6.9519196</Real>
+        <Real Name="Z">-24.6936</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6449318</Real>
+        <Real Name="Y">9.548996</Real>
+        <Real Name="Z">10.572418</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.492424</Real>
+        <Real Name="Y">-14.008846</Real>
+        <Real Name="Z">-31.177872</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.465565</Real>
+        <Real Name="Y">13.441313</Real>
+        <Real Name="Z">24.916901</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.258316</Real>
+        <Real Name="Y">19.720427</Real>
+        <Real Name="Z">53.479893</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-293.59235</Real>
+        <Real Name="Y">-159.95461</Real>
+        <Real Name="Z">315.22696</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">235.3578</Real>
+        <Real Name="Y">158.27934</Real>
+        <Real Name="Z">-333.41626</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">105.26781</Real>
+        <Real Name="Y">69.192444</Real>
+        <Real Name="Z">-72.462006</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-69.587036</Real>
+        <Real Name="Y">-327.14697</Real>
+        <Real Name="Z">-20.213562</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-16.86311</Real>
+        <Real Name="Y">78.813698</Real>
+        <Real Name="Z">-4.907074</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-108.94918</Real>
+        <Real Name="Y">37.10347</Real>
+        <Real Name="Z">129.93344</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.013561176</Real>
+        <Real Name="Y">0.59728497</Real>
+        <Real Name="Z">0.23971751</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.005949921</Real>
+        <Real Name="Y">0.68511796</Real>
+        <Real Name="Z">0.27699691</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.058029581</Real>
+        <Real Name="Y">0.61052024</Real>
+        <Real Name="Z">0.15599352</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97659588</Real>
+        <Real Name="Y">0.64048296</Real>
+        <Real Name="Z">1.5684563</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94719976</Real>
+        <Real Name="Y">0.61636353</Real>
+        <Real Name="Z">1.6562996</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94576579</Real>
+        <Real Name="Y">0.73033082</Real>
+        <Real Name="Z">1.5566586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3930745</Real>
+        <Real Name="Y">0.45167953</Real>
+        <Real Name="Z">1.1805406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3388977</Real>
+        <Real Name="Y">0.51956797</Real>
+        <Real Name="Z">1.2207693</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3362279</Real>
+        <Real Name="Y">0.41135663</Real>
+        <Real Name="Z">1.1149292</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6468115</Real>
+        <Real Name="Y">0.30425969</Real>
+        <Real Name="Z">0.3027119</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7108396</Real>
+        <Real Name="Y">0.33639061</Real>
+        <Real Name="Z">0.23922715</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6391129</Real>
+        <Real Name="Y">0.21074271</Real>
+        <Real Name="Z">0.28380093</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7627184</Real>
+        <Real Name="Y">0.38755485</Real>
+        <Real Name="Z">0.020784121</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7277308</Real>
+        <Real Name="Y">0.42667416</Real>
+        <Real Name="Z">1.8027949</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8111405</Real>
+        <Real Name="Y">0.45851821</Real>
+        <Real Name="Z">0.062995762</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.52059537</Real>
+        <Real Name="Y">-0.14902569</Real>
+        <Real Name="Z">-0.40926698</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.211103</Real>
+        <Real Name="Y">-0.80230927</Real>
+        <Real Name="Z">1.3232099</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8365848</Real>
+        <Real Name="Y">1.0187286</Real>
+        <Real Name="Z">0.4513796</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10035311</Real>
+        <Real Name="Y">0.612764</Real>
+        <Real Name="Z">-0.070292249</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1589468</Real>
+        <Real Name="Y">0.0356084</Real>
+        <Real Name="Z">-0.31288093</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9788312</Real>
+        <Real Name="Y">1.4631267</Real>
+        <Real Name="Z">1.2437687</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24983801</Real>
+        <Real Name="Y">0.31139797</Real>
+        <Real Name="Z">0.41448563</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.78839332</Real>
+        <Real Name="Y">2.1839774</Real>
+        <Real Name="Z">-1.2558388</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1024554</Real>
+        <Real Name="Y">-0.9705103</Real>
+        <Real Name="Z">1.9060079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.12396441</Real>
+        <Real Name="Y">-0.59704506</Real>
+        <Real Name="Z">0.013396551</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.096453905</Real>
+        <Real Name="Y">1.0104758</Real>
+        <Real Name="Z">0.58145791</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9570143</Real>
+        <Real Name="Y">-0.91481006</Real>
+        <Real Name="Z">0.21550491</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96607399</Real>
+        <Real Name="Y">-0.34206593</Real>
+        <Real Name="Z">-0.26439679</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3452796</Real>
+        <Real Name="Y">0.79659712</Real>
+        <Real Name="Z">-0.76104468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2835478</Real>
+        <Real Name="Y">-1.2181044</Real>
+        <Real Name="Z">1.6252133</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-29.96666</Real>
+        <Real Name="Y">-166.86574</Real>
+        <Real Name="Z">-390.15814</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-14.255459</Real>
+        <Real Name="Y">40.679695</Real>
+        <Real Name="Z">98.874863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">142.12856</Real>
+        <Real Name="Y">177.11133</Real>
+        <Real Name="Z">161.66415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.784195</Real>
+        <Real Name="Y">-3.8393478</Real>
+        <Real Name="Z">-39.242752</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.0895653</Real>
+        <Real Name="Y">-0.38917542</Real>
+        <Real Name="Z">13.250259</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-6.2390747</Real>
+        <Real Name="Y">5.2241993</Real>
+        <Real Name="Z">15.081966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">35.835403</Real>
+        <Real Name="Y">-8.686718</Real>
+        <Real Name="Z">-30.985039</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.279266</Real>
+        <Real Name="Y">1.981329</Real>
+        <Real Name="Z">25.037163</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.011692</Real>
+        <Real Name="Y">5.709713</Real>
+        <Real Name="Z">16.858398</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-209.10471</Real>
+        <Real Name="Y">-90.430946</Real>
+        <Real Name="Z">298.35315</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">100.09286</Real>
+        <Real Name="Y">40.753616</Real>
+        <Real Name="Z">-276.87903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">72.756393</Real>
+        <Real Name="Y">73.939323</Real>
+        <Real Name="Z">-102.19046</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">27.492035</Real>
+        <Real Name="Y">-173.98549</Real>
+        <Real Name="Z">54.399246</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-40.313599</Real>
+        <Real Name="Y">21.280952</Real>
+        <Real Name="Z">-5.4087677</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-48.829391</Real>
+        <Real Name="Y">77.517258</Real>
+        <Real Name="Z">161.34494</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 3">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98716
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562597</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562535</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562535</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562535</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562597</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562597</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562597</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562597</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562597</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562597</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562597</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562597</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562421</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562421</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562421</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562421</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">26.07069</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">26.070591</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">26.06287</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">26.062885</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">26.063065</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">29.964493</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.964531</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.964584</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.964592</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">29.964653</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">29.964594</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">29.991476</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">29.923521</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">20.308588</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">20.303234</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">20.298325</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">20.256826</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">35.343521</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">35.230721</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">35.186649</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">35.215961</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">35.308521</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">39.013817</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">39.260586</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">39.602264</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">40.039062</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">40.57106</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">41.197884</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">41.850082</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">42.592945</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">46.434387</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">48.03624</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">49.45694</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">50.590599</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5683126</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5319633</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.5612612</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.6536407</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.4761095</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-9.7228403</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.064466</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.501254</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.033191</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.660074</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-12.380656</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-13.191475</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.520683</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-28.12789</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.553499</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.728657</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.19787164</Real>
+        <Real Name="Y">0.16156073</Real>
+        <Real Name="Z">-0.3830564</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.7420168</Real>
+        <Real Name="Y">0.75917548</Real>
+        <Real Name="Z">1.2435496</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3711295</Real>
+        <Real Name="Y">-0.1916929</Real>
+        <Real Name="Z">0.42564186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19638549</Real>
+        <Real Name="Y">0.14565483</Real>
+        <Real Name="Z">-0.067964658</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3802328</Real>
+        <Real Name="Y">-0.58428359</Real>
+        <Real Name="Z">0.2304372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.9488595</Real>
+        <Real Name="Y">-0.88427049</Real>
+        <Real Name="Z">0.94601095</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.023709064</Real>
+        <Real Name="Y">-0.34130558</Real>
+        <Real Name="Z">-0.30921173</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.57465923</Real>
+        <Real Name="Y">-2.6639383</Real>
+        <Real Name="Z">0.20926186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10718073</Real>
+        <Real Name="Y">-2.149086</Real>
+        <Real Name="Z">0.10538759</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.012949247</Real>
+        <Real Name="Y">0.24703081</Real>
+        <Real Name="Z">0.11981639</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53420067</Real>
+        <Real Name="Y">-0.39553621</Real>
+        <Real Name="Z">-0.44761676</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23061849</Real>
+        <Real Name="Y">0.091385715</Real>
+        <Real Name="Z">1.1257544</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.06405513</Real>
+        <Real Name="Y">0.15561384</Real>
+        <Real Name="Z">0.54946572</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53148574</Real>
+        <Real Name="Y">0.53813189</Real>
+        <Real Name="Z">0.031651895</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.0633225</Real>
+        <Real Name="Y">-0.3697392</Real>
+        <Real Name="Z">-2.4264705</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0093535352</Real>
+        <Real Name="Y">0.59857243</Real>
+        <Real Name="Z">0.24241757</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8572949</Real>
+        <Real Name="Y">0.68917799</Real>
+        <Real Name="Z">0.26986974</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.048291765</Real>
+        <Real Name="Y">0.60569239</Real>
+        <Real Name="Z">0.15526576</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97578877</Real>
+        <Real Name="Y">0.63566333</Real>
+        <Real Name="Z">1.5689071</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94881505</Real>
+        <Real Name="Y">0.61590654</Real>
+        <Real Name="Z">1.6585978</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.93033791</Real>
+        <Real Name="Y">0.71715939</Real>
+        <Real Name="Z">1.547578</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3950518</Real>
+        <Real Name="Y">0.44926497</Real>
+        <Real Name="Z">1.1772383</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3332071</Real>
+        <Real Name="Y">0.50006974</Real>
+        <Real Name="Z">1.22974</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3440963</Real>
+        <Real Name="Y">0.42017651</Real>
+        <Real Name="Z">1.1016096</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6458995</Real>
+        <Real Name="Y">0.30885732</Real>
+        <Real Name="Z">0.30253235</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7090583</Real>
+        <Real Name="Y">0.32980028</Real>
+        <Real Name="Z">0.23372337</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6160418</Real>
+        <Real Name="Y">0.22036074</Real>
+        <Real Name="Z">0.28157559</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7704709</Real>
+        <Real Name="Y">0.39008287</Real>
+        <Real Name="Z">0.022931457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.717587</Real>
+        <Real Name="Y">0.42066619</Real>
+        <Real Name="Z">1.811301</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8178625</Real>
+        <Real Name="Y">0.46786135</Real>
+        <Real Name="Z">0.0523738</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.53580904</Real>
+        <Real Name="Y">-0.17427045</Real>
+        <Real Name="Z">-0.25583652</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4726843</Real>
+        <Real Name="Y">-0.20472801</Real>
+        <Real Name="Z">0.34929574</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.34980398</Real>
+        <Real Name="Y">-0.002836745</Real>
+        <Real Name="Z">-0.32533351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10070754</Real>
+        <Real Name="Y">0.5906027</Real>
+        <Real Name="Z">-0.035014968</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.26335594</Real>
+        <Real Name="Y">0.091935724</Real>
+        <Real Name="Z">-0.25191721</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8575956</Real>
+        <Real Name="Y">1.8700833</Real>
+        <Real Name="Z">0.97545344</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24131127</Real>
+        <Real Name="Y">0.28877956</Real>
+        <Real Name="Z">0.40751317</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.5664078</Real>
+        <Real Name="Y">2.737009</Real>
+        <Real Name="Z">-0.92979974</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.79717189</Real>
+        <Real Name="Y">-1.2478402</Real>
+        <Real Name="Z">1.3495164</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10637061</Real>
+        <Real Name="Y">-0.54563576</Real>
+        <Real Name="Z">0.040444028</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.55549061</Real>
+        <Real Name="Y">0.52895892</Real>
+        <Real Name="Z">0.766029</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.731668</Real>
+        <Real Name="Y">-1.5480431</Real>
+        <Real Name="Z">0.34247068</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96171474</Real>
+        <Real Name="Y">-0.27575648</Real>
+        <Real Name="Z">-0.26657832</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1492314</Real>
+        <Real Name="Y">0.70764601</Real>
+        <Real Name="Z">-1.4192637</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.31891999</Real>
+        <Real Name="Y">-1.0864772</Real>
+        <Real Name="Z">0.88115197</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">16.596939</Real>
+        <Real Name="Y">-61.415466</Real>
+        <Real Name="Z">-385.76343</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.347466</Real>
+        <Real Name="Y">22.130547</Real>
+        <Real Name="Z">103.76746</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">143.32344</Real>
+        <Real Name="Y">172.89394</Real>
+        <Real Name="Z">223.72205</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.416481</Real>
+        <Real Name="Y">-8.2812996</Real>
+        <Real Name="Z">-39.807404</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.617153</Real>
+        <Real Name="Y">-12.121773</Real>
+        <Real Name="Z">-23.78249</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.4095306</Real>
+        <Real Name="Y">6.7076721</Real>
+        <Real Name="Z">14.507195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.698715</Real>
+        <Real Name="Y">-9.2284317</Real>
+        <Real Name="Z">-32.576126</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.316967</Real>
+        <Real Name="Y">4.9631481</Real>
+        <Real Name="Z">27.286518</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-38.005856</Real>
+        <Real Name="Y">17.960684</Real>
+        <Real Name="Z">54.372311</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-255.59038</Real>
+        <Real Name="Y">-98.227272</Real>
+        <Real Name="Z">271.42618</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">160.4167</Real>
+        <Real Name="Y">75.617836</Real>
+        <Real Name="Z">-290.33572</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.375473</Real>
+        <Real Name="Y">63.913437</Real>
+        <Real Name="Z">-80.25074</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1831207</Real>
+        <Real Name="Y">-170.07243</Real>
+        <Real Name="Z">51.81424</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-39.311192</Real>
+        <Real Name="Y">26.683067</Real>
+        <Real Name="Z">-17.807114</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-99.280396</Real>
+        <Real Name="Y">-31.523666</Real>
+        <Real Name="Z">123.42719</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620583</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620583</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620583</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070883762</Real>
+        <Real Name="Y">0.59991848</Real>
+        <Real Name="Z">0.23198976</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.004895837</Real>
+        <Real Name="Y">0.67720813</Real>
+        <Real Name="Z">0.28841513</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.082309097</Real>
+        <Real Name="Y">0.61425972</Real>
+        <Real Name="Z">0.17455727</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97335446</Real>
+        <Real Name="Y">0.63034075</Real>
+        <Real Name="Z">1.5736233</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94124717</Real>
+        <Real Name="Y">0.57207596</Real>
+        <Real Name="Z">1.6424468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90214092</Real>
+        <Real Name="Y">0.69281459</Real>
+        <Real Name="Z">1.5599129</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959444</Real>
+        <Real Name="Y">0.44666046</Real>
+        <Real Name="Z">1.1632005</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3338616</Real>
+        <Real Name="Y">0.47015244</Real>
+        <Real Name="Z">1.2321656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3415514</Real>
+        <Real Name="Y">0.43269157</Real>
+        <Real Name="Z">1.0856854</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6414124</Real>
+        <Real Name="Y">0.31910464</Real>
+        <Real Name="Z">0.31263226</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7041454</Real>
+        <Real Name="Y">0.35027409</Real>
+        <Real Name="Z">0.24739927</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.626856</Real>
+        <Real Name="Y">0.2272546</Real>
+        <Real Name="Z">0.28996074</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7798015</Real>
+        <Real Name="Y">0.39100784</Real>
+        <Real Name="Z">0.024203973</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6904104</Real>
+        <Real Name="Y">0.42112944</Real>
+        <Real Name="Z">0.0079483986</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8165623</Real>
+        <Real Name="Y">0.45610124</Real>
+        <Real Name="Z">0.083985344</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.17196538</Real>
+        <Real Name="Y">0.08506266</Real>
+        <Real Name="Z">-0.96145606</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.70627159</Real>
+        <Real Name="Y">-2.0054946</Real>
+        <Real Name="Z">2.0441639</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5678227</Real>
+        <Real Name="Y">0.1741485</Real>
+        <Real Name="Z">2.0687132</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11852004</Real>
+        <Real Name="Y">-0.055028398</Real>
+        <Real Name="Z">0.2986151</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22716357</Real>
+        <Real Name="Y">-2.5167446</Real>
+        <Real Name="Z">-1.7610517</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.76406574</Real>
+        <Real Name="Y">-0.56544882</Real>
+        <Real Name="Z">1.2675773</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.075636119</Real>
+        <Real Name="Y">-0.020988159</Real>
+        <Real Name="Z">-0.67175126</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43077222</Real>
+        <Real Name="Y">-0.37801468</Real>
+        <Real Name="Z">-0.089059383</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.67108583</Real>
+        <Real Name="Y">0.16225487</Real>
+        <Real Name="Z">-0.2903578</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24561092</Real>
+        <Real Name="Y">0.35497904</Real>
+        <Real Name="Z">0.60163683</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31486496</Real>
+        <Real Name="Y">1.450613</Real>
+        <Real Name="Z">1.6442546</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3213334</Real>
+        <Real Name="Y">-0.13544737</Real>
+        <Real Name="Z">0.78896701</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.032267984</Real>
+        <Real Name="Y">0.054355282</Real>
+        <Real Name="Z">0.015259419</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63948768</Real>
+        <Real Name="Y">-0.38885209</Real>
+        <Real Name="Z">2.6542094</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.30090672</Real>
+        <Real Name="Y">-2.437623</Real>
+        <Real Name="Z">3.0640991</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-165.59985</Real>
+        <Real Name="Y">-319.14703</Real>
+        <Real Name="Z">-377.2431</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.500435</Real>
+        <Real Name="Y">68.321739</Real>
+        <Real Name="Z">100.04167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.71204</Real>
+        <Real Name="Y">141.91193</Real>
+        <Real Name="Z">72.107697</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.224129</Real>
+        <Real Name="Y">-15.094147</Real>
+        <Real Name="Z">-36.560623</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.3552551</Real>
+        <Real Name="Y">2.7187653</Real>
+        <Real Name="Z">14.708138</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1764145</Real>
+        <Real Name="Y">7.4052696</Real>
+        <Real Name="Z">12.126461</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.231888</Real>
+        <Real Name="Y">-17.591545</Real>
+        <Real Name="Z">-31.282894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.418846</Real>
+        <Real Name="Y">14.940029</Real>
+        <Real Name="Z">25.199474</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.5054989</Real>
+        <Real Name="Y">7.621624</Real>
+        <Real Name="Z">15.809441</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-179.80597</Real>
+        <Real Name="Y">3.9610443</Real>
+        <Real Name="Z">101.28729</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">146.46248</Real>
+        <Real Name="Y">-33.253502</Real>
+        <Real Name="Z">-82.280273</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">72.292419</Real>
+        <Real Name="Y">9.4070206</Real>
+        <Real Name="Z">-49.194809</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.666374</Real>
+        <Real Name="Y">-311.22681</Real>
+        <Real Name="Z">-20.719269</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.333469</Real>
+        <Real Name="Y">116.77807</Real>
+        <Real Name="Z">-0.34040833</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.43829</Real>
+        <Real Name="Y">323.2475</Real>
+        <Real Name="Z">256.34116</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_ParrinelloRahman_4Ranks_2RanksPerSimulation_d.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_ParrinelloRahman_4Ranks_2RanksPerSimulation_d.xml
new file mode 100644 (file)
index 0000000..0f3ef5d
--- /dev/null
@@ -0,0 +1,1696 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562600160298169</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562579188546056</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562579188546056</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562579188546056</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562596808132486</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562596808132486</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562596808132486</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562596808132486</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562596808132486</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562596808132486</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562596808132486</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562726872769858</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562432723662848</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562432723662848</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562432723662848</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562432723662848</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">20.344745942447368</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">20.345820773717548</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">20.359509666106518</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">20.360353120195587</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">20.361048505402199</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">17.826191226878834</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">17.82624487000281</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">17.826215320663021</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">17.826063560039522</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">17.825749838426997</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">17.834989630602205</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">17.810460418462242</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">17.838535162180584</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">20.29694559197246</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">20.291593860028456</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">20.286685431632712</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">20.245113734077513</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629305410083017</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">30.128031944401187</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.774393444412976</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">31.560514821648979</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">32.502914188437224</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">27.744970249540629</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">28.280224337518895</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">28.962065281152885</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.787929108244182</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">30.753480458693708</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">31.8003559858156</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">32.947788890558613</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">34.205084540905276</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">46.434583186513677</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">48.036409876346582</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">49.457074943406433</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">50.590723891508766</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673364533766927</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.158293500466206</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.790966108089027</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.576244031235962</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.517948012817595</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.28705195876335</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.82225240361764</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.504122896591419</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.330138484306215</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.296003556368266</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.333639291314949</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.452193912696941</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.681414819325262</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.520740868695185</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-28.127919290472093</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.553492785927688</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.72871343158522</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.004987833407605083</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858972</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391528</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.02498992600415597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208519</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13823960248430261</Real>
+        <Real Name="Y">-0.083001582473173879</Real>
+        <Real Name="Z">-0.55156788526044931</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807346912896504</Real>
+        <Real Name="Y">0.12594239723743825</Real>
+        <Real Name="Z">0.086340039099900012</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50558175484201939</Real>
+        <Real Name="Y">-0.2634720104901444</Real>
+        <Real Name="Z">-0.37043107548328896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.080341973608849884</Real>
+        <Real Name="Y">-0.036383374851252599</Real>
+        <Real Name="Z">0.26950251001929965</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0879938107726246</Real>
+        <Real Name="Y">-2.69925195488055</Real>
+        <Real Name="Z">-0.41161299800761325</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.005339856872981</Real>
+        <Real Name="Y">-0.4461332722971294</Real>
+        <Real Name="Z">1.1534368241800745</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046991365082634809</Real>
+        <Real Name="Y">-0.027139438957271552</Real>
+        <Real Name="Z">-0.6835695669642462</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.052027730439707112</Real>
+        <Real Name="Y">-0.42394701288611142</Real>
+        <Real Name="Z">-0.38240890291446689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2514527117216987</Real>
+        <Real Name="Y">0.072329295992862808</Real>
+        <Real Name="Z">-0.58384125172376988</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20047275659675184</Real>
+        <Real Name="Y">0.39459474035999648</Real>
+        <Real Name="Z">0.71751226731035556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21660158751017158</Real>
+        <Real Name="Y">1.2107968994948017</Real>
+        <Real Name="Z">0.86109126390401147</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3771064228719012</Real>
+        <Real Name="Y">-0.6610218165066043</Real>
+        <Real Name="Z">0.87071447867481888</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21701225376725289</Real>
+        <Real Name="Y">-0.090547598182204897</Real>
+        <Real Name="Z">-0.034702681691122401</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639425064679751</Real>
+        <Real Name="Y">0.9636306948577793</Real>
+        <Real Name="Z">2.5346418773965156</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37424921124689092</Real>
+        <Real Name="Y">-0.37914050295285695</Real>
+        <Real Name="Z">0.73119277083081202</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959196342</Real>
+        <Real Name="Y">10.126334215507086</Real>
+        <Real Name="Z">-383.9244463652023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773668</Real>
+        <Real Name="Y">8.7835602768706877</Real>
+        <Real Name="Z">109.98162207856127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818237</Real>
+        <Real Name="Y">125.90227601095691</Real>
+        <Real Name="Z">223.10402606189822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.9064510541798</Real>
+        <Real Name="Y">-91.873016441468678</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733365</Real>
+        <Real Name="Y">82.504344401698347</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041526</Real>
+        <Real Name="Y">45.329959216167893</Real>
+        <Real Name="Z">-56.291380508471349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448434</Real>
+        <Real Name="Y">-204.77938512046111</Real>
+        <Real Name="Z">21.695070286562498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013951</Real>
+        <Real Name="Y">47.5995038096992</Real>
+        <Real Name="Z">-24.246658126595179</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564435093</Real>
+        <Real Name="Y">-23.593576368970304</Real>
+        <Real Name="Z">144.65217639452101</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620599677732221</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620599677732221</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620599677732221</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0032065566355191375</Real>
+        <Real Name="Y">0.59445861835446112</Real>
+        <Real Name="Z">0.24346749855824193</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8500393232393089</Real>
+        <Real Name="Y">0.68447972721175943</Real>
+        <Real Name="Z">0.27221903251119439</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059025578783731728</Real>
+        <Real Name="Y">0.6030653833244608</Real>
+        <Real Name="Z">0.16618568463563638</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97845894729669225</Real>
+        <Real Name="Y">0.63002199637779155</Real>
+        <Real Name="Z">1.5703335574700192</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96142665925898074</Real>
+        <Real Name="Y">0.62378238264599317</Real>
+        <Real Name="Z">1.6643191243655693</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92763144249100238</Real>
+        <Real Name="Y">0.70591748586132963</Real>
+        <Real Name="Z">1.541719612770253</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.393381449731927</Real>
+        <Real Name="Y">0.44734048531098125</Real>
+        <Real Name="Z">1.1772700359247106</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3333722504861811</Real>
+        <Real Name="Y">0.47714317640795512</Real>
+        <Real Name="Z">1.2456294830352781</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3362473694799597</Real>
+        <Real Name="Y">0.41508780529016748</Real>
+        <Real Name="Z">1.1075722604563609</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6470159841962571</Real>
+        <Real Name="Y">0.3155705597745071</Real>
+        <Real Name="Z">0.29915825381312827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7055917178672895</Real>
+        <Real Name="Y">0.33253861852385369</Real>
+        <Real Name="Z">0.22537962000103776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5974880696371019</Real>
+        <Real Name="Y">0.23791191882016416</Real>
+        <Real Name="Z">0.27311138136085411</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7765689205367201</Real>
+        <Real Name="Y">0.39588196717868396</Real>
+        <Real Name="Z">0.022810910238719347</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7121068870100586</Real>
+        <Real Name="Y">0.40995611716633057</Real>
+        <Real Name="Z">1.8155247682743907</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8068445978361278</Real>
+        <Real Name="Y">0.48377352118739142</Real>
+        <Real Name="Z">0.045631438234281757</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.23119969306929994</Real>
+        <Real Name="Y">-0.67553756385331221</Real>
+        <Real Name="Z">-0.13583119737163479</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.57925061676728107</Real>
+        <Real Name="Y">-0.78505690333532341</Real>
+        <Real Name="Z">0.65891474474278167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6580553571117502</Real>
+        <Real Name="Y">-0.56564064781332557</Real>
+        <Real Name="Z">1.2061544195092746</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.4314946624965979</Real>
+        <Real Name="Y">-0.11802009234773667</Real>
+        <Real Name="Z">0.15482159029374903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3946926154657764</Real>
+        <Real Name="Y">1.0058897541063798</Real>
+        <Real Name="Z">0.41600849604994039</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4886372818599418</Real>
+        <Real Name="Y">0.58167810991364144</Real>
+        <Real Name="Z">0.1047480420388677</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46996554208729041</Real>
+        <Real Name="Y">0.038282458559898619</Real>
+        <Real Name="Z">0.39302818368091819</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50544331857195257</Real>
+        <Real Name="Y">0.090713613582672131</Real>
+        <Real Name="Z">1.2386396196680318</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.4769990677633138</Real>
+        <Real Name="Y">-1.9203707230001295</Real>
+        <Real Name="Z">2.0699328452413797</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24319144300606185</Real>
+        <Real Name="Y">0.31268223408558693</Real>
+        <Real Name="Z">-0.37290157484111847</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2820121995682795</Real>
+        <Real Name="Y">0.82376360181697184</Real>
+        <Real Name="Z">-0.22646438998067586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38877190214745383</Real>
+        <Real Name="Y">0.38053483826313622</Real>
+        <Real Name="Z">-0.85701807702163646</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19153434638339689</Real>
+        <Real Name="Y">0.44222782071167976</Real>
+        <Real Name="Z">-0.27196471174017217</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39277502580858814</Real>
+        <Real Name="Y">-0.50353426163589343</Real>
+        <Real Name="Z">-1.0200138579442646</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7522376537920359</Real>
+        <Real Name="Y">0.89781831891176833</Real>
+        <Real Name="Z">0.10495495434916896</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.7945956039147575</Real>
+        <Real Name="Y">58.033597380595666</Real>
+        <Real Name="Z">-374.65768392109783</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.0870693351609333</Real>
+        <Real Name="Y">1.7505547953654741</Real>
+        <Real Name="Z">111.91056255139812</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.46485172560583</Real>
+        <Real Name="Y">65.623132633838281</Real>
+        <Real Name="Z">206.1269197456661</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.534391152546306</Real>
+        <Real Name="Y">-18.791213810528205</Real>
+        <Real Name="Z">-38.90075933047784</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.705411195275317</Real>
+        <Real Name="Y">-9.5248428347184451</Real>
+        <Real Name="Z">-24.560559382324115</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4296282804309186</Real>
+        <Real Name="Y">10.479664363486137</Real>
+        <Real Name="Z">12.989930445679434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.546470882610365</Real>
+        <Real Name="Y">-7.3166979454419661</Real>
+        <Real Name="Z">-33.31381347275402</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-56.895360106612102</Real>
+        <Real Name="Y">11.306684855807617</Real>
+        <Real Name="Z">-15.031528401953956</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.612299967509841</Real>
+        <Real Name="Y">18.840360870727537</Real>
+        <Real Name="Z">56.456910767560011</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-308.28380154726369</Real>
+        <Real Name="Y">-121.72044280670343</Real>
+        <Real Name="Z">254.96890783249256</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.29581918074825</Real>
+        <Real Name="Y">105.98016420565295</Real>
+        <Real Name="Z">-280.20225221908447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">113.79233303275203</Real>
+        <Real Name="Y">54.983753588430133</Real>
+        <Real Name="Z">-58.121046634147881</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-59.038322968008913</Real>
+        <Real Name="Y">-239.7616075934607</Real>
+        <Real Name="Z">-1.0448613628317389</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.0940306700134563</Real>
+        <Real Name="Y">45.481347514010096</Real>
+        <Real Name="Z">17.249964543319749</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-101.29223003065047</Real>
+        <Real Name="Y">24.635544782938865</Real>
+        <Real Name="Z">166.12930883855603</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620583903099219</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620583903099219</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620583903099219</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070883738852910941</Real>
+        <Real Name="Y">0.5999183402374102</Real>
+        <Real Name="Z">0.23198976079285899</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0048956495571432735</Real>
+        <Real Name="Y">0.6772079354066427</Real>
+        <Real Name="Z">0.28841518802736493</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.082309266152553795</Real>
+        <Real Name="Y">0.61425960496641563</Real>
+        <Real Name="Z">0.17455750598348307</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97335451670836637</Real>
+        <Real Name="Y">0.63034091468303455</Real>
+        <Real Name="Z">1.5736233702037932</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94124743628253649</Real>
+        <Real Name="Y">0.5720760289958372</Real>
+        <Real Name="Z">1.6424467447388071</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90214075476710343</Real>
+        <Real Name="Y">0.69281444150766758</Real>
+        <Real Name="Z">1.5599129013473052</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.395944309653812</Real>
+        <Real Name="Y">0.44666043571826114</Real>
+        <Real Name="Z">1.1632009202936391</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3338614019912638</Real>
+        <Real Name="Y">0.47015254261665279</Real>
+        <Real Name="Z">1.2321657801110677</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3415517369229555</Real>
+        <Real Name="Y">0.43269157491586868</Real>
+        <Real Name="Z">1.0856855195038515</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6414126116424359</Real>
+        <Real Name="Y">0.31910464547754519</Real>
+        <Real Name="Z">0.31263234538813039</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7041454594713992</Real>
+        <Real Name="Y">0.35027404847783294</Real>
+        <Real Name="Z">0.24739909834436111</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6268562684948311</Real>
+        <Real Name="Y">0.22725454478288898</Real>
+        <Real Name="Z">0.28996099173312467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7798016634753724</Real>
+        <Real Name="Y">0.39100791343887781</Real>
+        <Real Name="Z">0.024203978496672735</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6904105433964201</Real>
+        <Real Name="Y">0.42112944880716918</Real>
+        <Real Name="Z">0.0079485437720425711</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8165624318559268</Real>
+        <Real Name="Y">0.45610126756613112</Real>
+        <Real Name="Z">0.083985410033019042</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.17196580096105951</Real>
+        <Real Name="Y">0.085058447237644136</Real>
+        <Real Name="Z">-0.96145712019557261</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.70626563898833705</Real>
+        <Real Name="Y">-2.0054916754963097</Real>
+        <Real Name="Z">2.0441772223215837</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5678210236720176</Real>
+        <Real Name="Y">0.17414999781082874</Real>
+        <Real Name="Z">2.0687387249566096</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11851851812265768</Real>
+        <Real Name="Y">-0.055034338044971098</Real>
+        <Real Name="Z">0.29862052628977898</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22710823843795261</Real>
+        <Real Name="Y">-2.5167044863474128</Real>
+        <Real Name="Z">-1.761120897917847</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.76411582527329236</Real>
+        <Real Name="Y">-0.56538305072842743</Real>
+        <Real Name="Z">1.2675236751839096</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.07562490569199895</Real>
+        <Real Name="Y">-0.020989750858199437</Real>
+        <Real Name="Z">-0.67175256065840017</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43072365834027626</Real>
+        <Real Name="Y">-0.37800487738228572</Real>
+        <Real Name="Z">-0.089074513363807964</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.67110675161815447</Real>
+        <Real Name="Y">0.16226035493625243</Real>
+        <Real Name="Z">-0.29036799212400355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24561573265802705</Real>
+        <Real Name="Y">0.35497865501283127</Real>
+        <Real Name="Z">0.60164419416117021</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31487263412307476</Real>
+        <Real Name="Y">1.4506138994528204</Real>
+        <Real Name="Z">1.6442193774471001</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3213571124565999</Real>
+        <Real Name="Y">-0.13544608940344841</Real>
+        <Real Name="Z">0.78898822035128768</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.032271617692655477</Real>
+        <Real Name="Y">0.054351076094991575</Real>
+        <Real Name="Z">0.015260270874699394</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63952383852984962</Real>
+        <Real Name="Y">-0.38884245996860367</Real>
+        <Real Name="Z">2.6541946939440719</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.30088532239091537</Real>
+        <Real Name="Y">-2.4376024190471695</Real>
+        <Real Name="Z">3.0641147646370346</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-165.5998930259039</Real>
+        <Real Name="Y">-319.1464703052452</Real>
+        <Real Name="Z">-377.24353735317197</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.500400211136714</Real>
+        <Real Name="Y">68.321695509162282</Real>
+        <Real Name="Z">100.04194181457775</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.7120649855344</Real>
+        <Real Name="Y">141.91160168707222</Real>
+        <Real Name="Z">72.107798680355458</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.224105387118215</Real>
+        <Real Name="Y">-15.094101198693551</Real>
+        <Real Name="Z">-36.560649974338375</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.3552390362413362</Real>
+        <Real Name="Y">2.7187462058487721</Real>
+        <Real Name="Z">14.708162406544453</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1764088153795456</Real>
+        <Real Name="Y">7.4052388203635005</Real>
+        <Real Name="Z">12.126470103263294</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.231835141056081</Real>
+        <Real Name="Y">-17.591624882870804</Real>
+        <Real Name="Z">-31.282849970482538</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.418818484260512</Real>
+        <Real Name="Y">14.940098879716658</Real>
+        <Real Name="Z">25.199473596329284</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.5054741922928976</Real>
+        <Real Name="Y">7.6216421756354329</Real>
+        <Real Name="Z">15.809393838683874</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-179.80572529473079</Real>
+        <Real Name="Y">3.9611381800073673</Real>
+        <Real Name="Z">101.28679678744507</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">146.46281768053049</Real>
+        <Real Name="Y">-33.253855072782471</Real>
+        <Real Name="Z">-82.280255710694689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">72.292213089290684</Real>
+        <Real Name="Y">9.4069434365705717</Real>
+        <Real Name="Z">-49.194713451929871</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.667914130103114</Real>
+        <Real Name="Y">-311.22845929118085</Real>
+        <Real Name="Z">-20.719463783278911</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.333105014801966</Real>
+        <Real Name="Y">116.77852203480059</Real>
+        <Real Name="Z">-0.34064660692689586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.439141499047516</Real>
+        <Real Name="Y">323.24888382159554</Real>
+        <Real Name="Z">256.34207962362404</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562600160298169</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562596808132486</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562596808132486</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562596808132486</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562579188546056</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562579188546056</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562579188546056</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562579188546056</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562579188546056</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562579188546056</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562579188546056</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562432723662848</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562726872769858</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562726872769858</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562726872769858</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562726872769858</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">17.819866492793917</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">17.819983695352036</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">17.833680477900767</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">17.833801390337673</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">17.833922895439404</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">20.369314632518225</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">20.369340257255349</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">20.368813688479765</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">20.367585112838782</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">20.365523806788836</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">20.36254624117468</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">20.339975980986132</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">20.31008739096011</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">17.845175958839903</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">17.843717504312114</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">17.842072420526684</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">17.840314483961162</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">27.096610978600332</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">27.013027660158095</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">27.026934199983188</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">27.118294747833708</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">27.357563442798696</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">33.603059134704061</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.858863260342879</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">36.263448226857506</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.803591993586991</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">39.458338815814741</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">41.197849879991438</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">42.957105720984337</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">44.712826379769169</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">35.527214210201009</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">36.924554085670444</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">38.375367529951333</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">39.855210859931773</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673364533766927</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5691318685511426</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5693416258275033</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6605812612411217</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8997284511043766</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.617641802720144</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.873420303621838</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.278531838912048</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.819904181282517</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.476712309560213</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.219200939351065</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-23.008047971872891</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.793657220683745</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-18.004718639492488</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.403516969489711</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.855975497556031</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.337576764101993</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.004987833407605083</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858972</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391528</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.02498992600415597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208519</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.20819690585540773</Real>
+        <Real Name="Y">-0.71831964871349085</Real>
+        <Real Name="Z">0.011078438999830157</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.65627408040347335</Real>
+        <Real Name="Y">-0.44130069592945115</Real>
+        <Real Name="Z">-0.19586161682440933</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.07944772612600022</Real>
+        <Real Name="Y">-1.3403514765108808</Real>
+        <Real Name="Z">0.094211853505395182</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43983396430402821</Real>
+        <Real Name="Y">-0.12730113827963044</Real>
+        <Real Name="Z">0.16848744653097211</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1064634752554481</Real>
+        <Real Name="Y">1.208306314237934</Real>
+        <Real Name="Z">0.58865730101337532</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3857124030917944</Real>
+        <Real Name="Y">0.65412452380296571</Real>
+        <Real Name="Z">0.10516368028532735</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.41357531425471322</Real>
+        <Real Name="Y">0.03909994936372093</Real>
+        <Real Name="Z">0.41653530543680806</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.30958260222840822</Real>
+        <Real Name="Y">0.032508253652296773</Real>
+        <Real Name="Z">1.2155924310115984</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7555728294294284</Real>
+        <Real Name="Y">-2.0294504264852296</Real>
+        <Real Name="Z">1.568589118909621</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25622123762474486</Real>
+        <Real Name="Y">0.31483429896995041</Real>
+        <Real Name="Z">-0.34178744751437573</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.1457763418811992</Real>
+        <Real Name="Y">0.34295833952026589</Real>
+        <Real Name="Z">-0.4239403762530316</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019644304201244064</Real>
+        <Real Name="Y">0.5193023809855738</Real>
+        <Real Name="Z">-0.45124050611198896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15257163555120895</Real>
+        <Real Name="Y">0.53524540919668817</Real>
+        <Real Name="Z">-0.26925935975066168</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25467201556722202</Real>
+        <Real Name="Y">-0.76836408689837199</Real>
+        <Real Name="Z">-1.2156468083482905</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.9200810679380822</Real>
+        <Real Name="Y">1.1308821580758028</Real>
+        <Real Name="Z">-1.0483019686667092</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959196342</Real>
+        <Real Name="Y">10.126334215507086</Real>
+        <Real Name="Z">-383.9244463652023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773668</Real>
+        <Real Name="Y">8.7835602768706877</Real>
+        <Real Name="Z">109.98162207856127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818237</Real>
+        <Real Name="Y">125.90227601095691</Real>
+        <Real Name="Z">223.10402606189822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.9064510541798</Real>
+        <Real Name="Y">-91.873016441468678</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733365</Real>
+        <Real Name="Y">82.504344401698347</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041526</Real>
+        <Real Name="Y">45.329959216167893</Real>
+        <Real Name="Z">-56.291380508471349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448434</Real>
+        <Real Name="Y">-204.77938512046111</Real>
+        <Real Name="Z">21.695070286562498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013951</Real>
+        <Real Name="Y">47.5995038096992</Real>
+        <Real Name="Z">-24.246658126595179</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564435093</Real>
+        <Real Name="Y">-23.593576368970304</Real>
+        <Real Name="Z">144.65217639452101</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620597983834559</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620597983834559</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620597983834559</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059800329156975435</Real>
+        <Real Name="Y">0.59962504496457802</Real>
+        <Real Name="Z">0.2388759142825515</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8579625492735354</Real>
+        <Real Name="Y">0.68770227657428362</Real>
+        <Real Name="Z">0.27497533337685187</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062415659865401651</Real>
+        <Real Name="Y">0.6113238282544825</Real>
+        <Real Name="Z">0.1624529015159169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97424378884414731</Real>
+        <Real Name="Y">0.63071274775607489</Real>
+        <Real Name="Z">1.5712773252398125</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94452570877190623</Real>
+        <Real Name="Y">0.59312110675715457</Real>
+        <Real Name="Z">1.6541387918200505</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90862295940536364</Real>
+        <Real Name="Y">0.6971182259695321</Real>
+        <Real Name="Z">1.550145888776385</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3964937370276129</Real>
+        <Real Name="Y">0.44683176434637256</Real>
+        <Real Name="Z">1.1685987744331567</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3311407933484634</Real>
+        <Real Name="Y">0.47333967817445949</Real>
+        <Real Name="Z">1.2333184905709165</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3462208281422934</Real>
+        <Real Name="Y">0.43159302281846423</Real>
+        <Real Name="Z">1.0885816900770422</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6433160908132491</Real>
+        <Real Name="Y">0.31615917489986561</Real>
+        <Real Name="Z">0.30757638849057611</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7027956550689842</Real>
+        <Real Name="Y">0.33864315017846269</Real>
+        <Real Name="Z">0.23602940608307649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6093986810529006</Real>
+        <Real Name="Y">0.22972290072245072</Real>
+        <Real Name="Z">0.28432346993235841</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.779275008760963</Real>
+        <Real Name="Y">0.39118056853953792</Real>
+        <Real Name="Z">0.024518995730881402</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.697421816881697</Real>
+        <Real Name="Y">0.42105405149055386</Real>
+        <Real Name="Z">1.8469562197967708</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8185172089624626</Real>
+        <Real Name="Y">0.47042087212748901</Real>
+        <Real Name="Z">0.061170631582974457</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11737436567115672</Real>
+        <Real Name="Y">-0.020636633742389193</Real>
+        <Real Name="Z">-0.72704484742497044</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5003280528886331</Real>
+        <Real Name="Y">-0.57571149229050678</Real>
+        <Real Name="Z">1.0897890537567456</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0613133643705073</Real>
+        <Real Name="Y">0.42387073564478361</Real>
+        <Real Name="Z">0.73649846434730926</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10070672237372216</Real>
+        <Real Name="Y">-0.038042326867970572</Real>
+        <Real Name="Z">0.28581744614611193</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.65075467840149637</Real>
+        <Real Name="Y">-2.7293505260667641</Real>
+        <Real Name="Z">-1.0757002055698397</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.87471017742975299</Real>
+        <Real Name="Y">-0.50786107974028905</Real>
+        <Real Name="Z">1.174876333667074</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.060017288364742419</Real>
+        <Real Name="Y">-0.022456518469153416</Real>
+        <Real Name="Z">-0.67827472544840561</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22874048312940026</Real>
+        <Real Name="Y">-0.4184871346997816</Real>
+        <Real Name="Z">-0.22101422082789193</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46788535985452018</Real>
+        <Real Name="Y">0.10877449233460799</Real>
+        <Real Name="Z">-0.44848967973555898</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22469391234086961</Real>
+        <Real Name="Y">0.38152510534580686</Real>
+        <Real Name="Z">0.66925929880763424</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019246734411716121</Real>
+        <Real Name="Y">1.4425621489365257</Real>
+        <Real Name="Z">1.1636203131610374</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9405054360623324</Real>
+        <Real Name="Y">-0.49721387002190659</Real>
+        <Real Name="Z">0.66009022416450291</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11612931196387787</Real>
+        <Real Name="Y">-0.095145566437560225</Real>
+        <Real Name="Z">-0.071047804647333568</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2098740176583866</Real>
+        <Real Name="Y">0.50517732514892455</Real>
+        <Real Name="Z">2.97688765239256</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.097169564566495531</Real>
+        <Real Name="Y">-1.0094806496660276</Real>
+        <Real Name="Z">2.2175862577908121</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-67.305277162531695</Real>
+        <Real Name="Y">-110.64971684238196</Real>
+        <Real Name="Z">-418.09618997120106</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45499407406034464</Real>
+        <Real Name="Y">35.58746488213113</Real>
+        <Real Name="Z">108.83013588069055</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">177.09154582195762</Real>
+        <Real Name="Y">149.00175161800718</Real>
+        <Real Name="Z">168.31879546932018</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.74566099036771</Real>
+        <Real Name="Y">-14.351915435549394</Real>
+        <Real Name="Z">-37.638091587878051</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.748815657993198</Real>
+        <Real Name="Y">-8.0131142520266856</Real>
+        <Real Name="Z">-23.772529761630537</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3077236918012431</Real>
+        <Real Name="Y">7.67527875784846</Real>
+        <Real Name="Z">12.778185562001624</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.157339413874766</Real>
+        <Real Name="Y">-14.355671692426505</Real>
+        <Real Name="Z">-32.970003329401166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.423603352629065</Real>
+        <Real Name="Y">12.125172070267205</Real>
+        <Real Name="Z">27.147601583670223</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.920489017805373</Real>
+        <Real Name="Y">16.920250551886923</Real>
+        <Real Name="Z">54.454837533237907</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-257.06930311822731</Real>
+        <Real Name="Y">-51.515887360074828</Real>
+        <Real Name="Z">176.05114411521862</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">211.8160301436472</Real>
+        <Real Name="Y">25.161156127956701</Real>
+        <Real Name="Z">-196.500268224243</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.512448089358429</Real>
+        <Real Name="Y">32.904790306995437</Real>
+        <Real Name="Z">-53.832575015727258</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.628100234699332</Real>
+        <Real Name="Y">-234.67760519362793</Real>
+        <Real Name="Z">8.3063013132113497</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.224929024226796</Real>
+        <Real Name="Y">75.86600037082232</Real>
+        <Real Name="Z">-10.555313103684483</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.647408589338426</Real>
+        <Real Name="Y">78.322046090172023</Real>
+        <Real Name="Z">217.47796953641495</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620612181772425</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620612181772425</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620612181772425</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0014075259809515374</Real>
+        <Real Name="Y">0.58945338625020505</Real>
+        <Real Name="Z">0.24147986451297943</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8537900083739003</Real>
+        <Real Name="Y">0.67571352569725096</Real>
+        <Real Name="Z">0.28182622514431499</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076745845178334313</Real>
+        <Real Name="Y">0.59856313945893158</Real>
+        <Real Name="Z">0.18314061137249849</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98186928288567976</Real>
+        <Real Name="Y">0.6291435253627865</Real>
+        <Real Name="Z">1.5715756090334498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97350417072847595</Real>
+        <Real Name="Y">0.63094877239107583</Real>
+        <Real Name="Z">1.6669122986223162</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.93998632496196088</Real>
+        <Real Name="Y">0.71007251718531772</Real>
+        <Real Name="Z">1.5422731429572254</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3893543962775179</Real>
+        <Real Name="Y">0.44760022644982778</Real>
+        <Real Name="Z">1.1803288170712138</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3378762512251814</Real>
+        <Real Name="Y">0.4784026890355057</Real>
+        <Real Name="Z">1.2549178731091355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3265191059046491</Real>
+        <Real Name="Y">0.40045711276338802</Real>
+        <Real Name="Z">1.1256335566211131</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6489070185486634</Real>
+        <Real Name="Y">0.31804891264251317</Real>
+        <Real Name="Z">0.29604013086497905</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.708349833866476</Real>
+        <Real Name="Y">0.34128237090513136</Real>
+        <Real Name="Z">0.22470236720328857</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6025248448961125</Real>
+        <Real Name="Y">0.24054521401871831</Real>
+        <Real Name="Z">0.26435118852074535</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7749854120641677</Real>
+        <Real Name="Y">0.39908949573184971</Real>
+        <Real Name="Z">0.020704515649943907</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7157214900721687</Real>
+        <Real Name="Y">0.40803099678600296</Real>
+        <Real Name="Z">1.8081322593735301</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7882893469759666</Real>
+        <Real Name="Y">0.48868572902375873</Real>
+        <Real Name="Z">0.051653484869680362</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.20834158847945064</Real>
+        <Real Name="Y">-0.57505362344785926</Real>
+        <Real Name="Z">-0.34566835366978826</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.33012275742115915</Real>
+        <Real Name="Y">-1.4134569509778854</Real>
+        <Real Name="Z">1.6370236829566507</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4329365227508783</Real>
+        <Real Name="Y">-0.74031805695947284</Real>
+        <Real Name="Z">2.8896890612899289</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42180118368162461</Real>
+        <Real Name="Y">-0.10213203826753006</Real>
+        <Real Name="Z">0.15943332717882686</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.572328978511478</Real>
+        <Real Name="Y">0.8153565528025507</Real>
+        <Real Name="Z">0.25441523889351492</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5857795595711157</Real>
+        <Real Name="Y">0.46240461778796915</Real>
+        <Real Name="Z">0.026026560650971885</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.52769643695847268</Real>
+        <Real Name="Y">0.026141601613783448</Real>
+        <Real Name="Z">0.37459733951025559</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.58025934264954881</Real>
+        <Real Name="Y">0.21092845372474384</Real>
+        <Real Name="Z">1.0746939046771584</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.98478641187101679</Real>
+        <Real Name="Y">-1.7498095510598097</Real>
+        <Real Name="Z">2.3635417329716644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23112907897325433</Real>
+        <Real Name="Y">0.30726399035269131</Real>
+        <Real Name="Z">-0.40359207502217676</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.3911664949135697</Real>
+        <Real Name="Y">1.2819919686266716</Real>
+        <Real Name="Z">0.039000701283138928</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.81898682684503732</Real>
+        <Real Name="Y">0.30290863886777453</Real>
+        <Real Name="Z">-1.2706859574338638</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1997435061181749</Real>
+        <Real Name="Y">0.3766736099650837</Real>
+        <Real Name="Z">-0.25046545400502612</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.49577183201723146</Real>
+        <Real Name="Y">0.018430357794563736</Real>
+        <Real Name="Z">-0.85219650734437147</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.733031585687753</Real>
+        <Real Name="Y">0.28946386291024295</Real>
+        <Real Name="Z">1.2302019382027989</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-78.896501019434908</Real>
+        <Real Name="Y">62.248572763609843</Real>
+        <Real Name="Z">-366.71858283000535</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.3855762143081947</Real>
+        <Real Name="Y">0.76632181533577182</Real>
+        <Real Name="Z">112.20607325172955</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">135.41012781194922</Real>
+        <Real Name="Y">3.0832225261534347</Real>
+        <Real Name="Z">132.27037168881404</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.724561035781548</Real>
+        <Real Name="Y">-23.6585505698649</Real>
+        <Real Name="Z">-37.737792741360821</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6744579697081008</Real>
+        <Real Name="Y">7.0476336072464782</Real>
+        <Real Name="Z">14.365887115045986</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.3349943642488284</Real>
+        <Real Name="Y">12.813911893452559</Real>
+        <Real Name="Z">11.89797588085964</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.799444813997525</Real>
+        <Real Name="Y">-4.0062815392755624</Real>
+        <Real Name="Z">-32.307698339227272</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.2252203579053</Real>
+        <Real Name="Y">9.0931253141346957</Real>
+        <Real Name="Z">-18.082260132521498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.153620522689522</Real>
+        <Real Name="Y">4.2722280444333975</Real>
+        <Real Name="Z">18.138702063894456</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-314.56629100788433</Real>
+        <Real Name="Y">-129.70216450613611</Real>
+        <Real Name="Z">277.17642997533221</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">243.12533109287543</Real>
+        <Real Name="Y">99.168773419568197</Real>
+        <Real Name="Z">-284.50062103058991</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">118.53698323907844</Real>
+        <Real Name="Y">60.259977184667449</Real>
+        <Real Name="Z">-65.439593887712135</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-76.372130955622652</Real>
+        <Real Name="Y">-323.16644475301854</Real>
+        <Real Name="Z">-34.785880686591895</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">20.006487375822701</Real>
+        <Real Name="Y">58.356899726408443</Real>
+        <Real Name="Z">26.722629144754336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.765295386319366</Real>
+        <Real Name="Y">163.42277507328481</Real>
+        <Real Name="Z">246.79436052757882</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_ParrinelloRahman_4Ranks_2RanksPerSimulation_s.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_NoseHoover_ParrinelloRahman_4Ranks_2RanksPerSimulation_s.xml
new file mode 100644 (file)
index 0000000..0826014
--- /dev/null
@@ -0,0 +1,1696 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562597</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562569</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562569</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562569</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562597</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562597</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562597</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562597</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562597</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562597</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562597</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562721</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562421</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562421</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562421</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562421</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">20.34477</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">20.345877</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">20.359442</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">20.360447</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">20.361023</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">17.826244</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">17.826307</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">17.826166</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">17.826071</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">17.825752</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">17.835016</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">17.810446</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">17.838474</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">20.296726</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">20.291443</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">20.286453</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">20.244999</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629341</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">30.128061</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.774403</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">31.560501</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">32.502899</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">27.745005</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">28.280277</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">28.962126</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.787983</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">30.753538</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">31.800413</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">32.947834</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">34.205135</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">46.434456</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">48.036259</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">49.456924</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">50.590591</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733761</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.158266</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.791043</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.576136</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.517958</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.287033</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.822243</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.504232</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.330185</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.296059</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.33367</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.452253</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.681526</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.520832</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-28.127918</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.553574</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.728695</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951088</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154483</Real>
+        <Real Name="Y">0.6098752</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829585</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13824016</Real>
+        <Real Name="Y">-0.083002254</Real>
+        <Real Name="Z">-0.55156869</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807338</Real>
+        <Real Name="Y">0.12595503</Real>
+        <Real Name="Z">0.08634457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50557774</Real>
+        <Real Name="Y">-0.26347136</Real>
+        <Real Name="Z">-0.37042338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.080341488</Real>
+        <Real Name="Y">-0.036381338</Real>
+        <Real Name="Z">0.26949763</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0880266</Real>
+        <Real Name="Y">-2.6992292</Real>
+        <Real Name="Z">-0.41159728</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0053114</Real>
+        <Real Name="Y">-0.44618708</Real>
+        <Real Name="Z">1.1535001</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046993256</Real>
+        <Real Name="Y">-0.027141552</Real>
+        <Real Name="Z">-0.68357778</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.05199106</Real>
+        <Real Name="Y">-0.4239299</Real>
+        <Real Name="Z">-0.38236642</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25138497</Real>
+        <Real Name="Y">0.072344288</Real>
+        <Real Name="Z">-0.58373684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20046791</Real>
+        <Real Name="Y">0.39459822</Real>
+        <Real Name="Z">0.71750742</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21663751</Real>
+        <Real Name="Y">1.2108051</Real>
+        <Real Name="Z">0.86115432</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3770657</Real>
+        <Real Name="Y">-0.66109234</Real>
+        <Real Name="Z">0.87071204</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2170116</Real>
+        <Real Name="Y">-0.090551436</Real>
+        <Real Name="Z">-0.034702588</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639975</Real>
+        <Real Name="Y">0.96362239</Real>
+        <Real Name="Z">2.5346055</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37430629</Real>
+        <Real Name="Y">-0.3790665</Real>
+        <Real Name="Z">0.73122531</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9518738</Real>
+        <Real Name="Y">10.126022</Real>
+        <Real Name="Z">-383.92468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054081</Real>
+        <Real Name="Y">8.7835617</Real>
+        <Real Name="Z">109.98161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.0733</Real>
+        <Real Name="Y">125.90257</Real>
+        <Real Name="Z">223.10434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850433</Real>
+        <Real Name="Y">8.0224648</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90619</Real>
+        <Real Name="Y">-91.872864</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62735</Real>
+        <Real Name="Y">82.504333</Real>
+        <Real Name="Z">-270.19894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937</Real>
+        <Real Name="Y">45.329948</Real>
+        <Real Name="Z">-56.291359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365723</Real>
+        <Real Name="Y">-204.77948</Real>
+        <Real Name="Z">21.695251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097099</Real>
+        <Real Name="Y">47.599464</Real>
+        <Real Name="Z">-24.246674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.29879</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65219</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.003206562</Real>
+        <Real Name="Y">0.59445864</Real>
+        <Real Name="Z">0.24346748</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8500394</Real>
+        <Real Name="Y">0.68447971</Real>
+        <Real Name="Z">0.27221915</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059025619</Real>
+        <Real Name="Y">0.60306549</Real>
+        <Real Name="Z">0.16618571</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.978459</Real>
+        <Real Name="Y">0.63002211</Real>
+        <Real Name="Z">1.5703336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96142673</Real>
+        <Real Name="Y">0.62378252</Real>
+        <Real Name="Z">1.6643192</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92763126</Real>
+        <Real Name="Y">0.70591748</Real>
+        <Real Name="Z">1.5417197</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3933816</Real>
+        <Real Name="Y">0.44734058</Real>
+        <Real Name="Z">1.1772702</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3333721</Real>
+        <Real Name="Y">0.47714314</Real>
+        <Real Name="Z">1.2456294</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3362477</Real>
+        <Real Name="Y">0.41508785</Real>
+        <Real Name="Z">1.1075722</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.647016</Real>
+        <Real Name="Y">0.31557053</Real>
+        <Real Name="Z">0.29915825</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7055918</Real>
+        <Real Name="Y">0.33253855</Real>
+        <Real Name="Z">0.22537962</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.597488</Real>
+        <Real Name="Y">0.237912</Real>
+        <Real Name="Z">0.27311131</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7765689</Real>
+        <Real Name="Y">0.39588198</Real>
+        <Real Name="Z">0.022810915</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7121068</Real>
+        <Real Name="Y">0.4099561</Real>
+        <Real Name="Z">1.8155247</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8068445</Real>
+        <Real Name="Y">0.48377353</Real>
+        <Real Name="Z">0.045631435</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.23119915</Real>
+        <Real Name="Y">-0.67554122</Real>
+        <Real Name="Z">-0.13583225</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.57924581</Real>
+        <Real Name="Y">-0.78501922</Real>
+        <Real Name="Z">0.65893275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6580614</Real>
+        <Real Name="Y">-0.56561226</Real>
+        <Real Name="Z">1.2061505</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43149701</Real>
+        <Real Name="Y">-0.11802036</Real>
+        <Real Name="Z">0.15481809</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3946803</Real>
+        <Real Name="Y">1.0059086</Real>
+        <Real Name="Z">0.4161008</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4885997</Real>
+        <Real Name="Y">0.58169425</Real>
+        <Real Name="Z">0.10475422</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46996155</Real>
+        <Real Name="Y">0.038284291</Real>
+        <Real Name="Z">0.39303151</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50542456</Real>
+        <Real Name="Y">0.090694554</Real>
+        <Real Name="Z">1.2386229</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.477072</Real>
+        <Real Name="Y">-1.9203901</Real>
+        <Real Name="Z">2.0698869</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24319121</Real>
+        <Real Name="Y">0.31267953</Real>
+        <Real Name="Z">-0.37290612</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.28201953</Real>
+        <Real Name="Y">0.82378089</Real>
+        <Real Name="Z">-0.22643967</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38876641</Real>
+        <Real Name="Y">0.38053483</Real>
+        <Real Name="Z">-0.85700959</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19153851</Real>
+        <Real Name="Y">0.44222993</Real>
+        <Real Name="Z">-0.27196914</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39286178</Real>
+        <Real Name="Y">-0.50354707</Real>
+        <Real Name="Z">-1.0199476</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7522477</Real>
+        <Real Name="Y">0.89780098</Real>
+        <Real Name="Z">0.10495238</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.7950134</Real>
+        <Real Name="Y">58.033646</Real>
+        <Real Name="Z">-374.65729</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.0870094</Real>
+        <Real Name="Y">1.7504272</Real>
+        <Real Name="Z">111.91047</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.46463</Real>
+        <Real Name="Y">65.622849</Real>
+        <Real Name="Z">206.12633</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.534264</Real>
+        <Real Name="Y">-18.791229</Real>
+        <Real Name="Z">-38.900749</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.705444</Real>
+        <Real Name="Y">-9.524826</Real>
+        <Real Name="Z">-24.560528</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4295654</Real>
+        <Real Name="Y">10.479645</Real>
+        <Real Name="Z">12.989922</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.546494</Real>
+        <Real Name="Y">-7.3167458</Real>
+        <Real Name="Z">-33.31385</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-56.89537</Real>
+        <Real Name="Y">11.306744</Real>
+        <Real Name="Z">-15.031479</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.612278</Real>
+        <Real Name="Y">18.840364</Real>
+        <Real Name="Z">56.456867</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-308.28369</Real>
+        <Real Name="Y">-121.72034</Real>
+        <Real Name="Z">254.96918</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.29568</Real>
+        <Real Name="Y">105.98029</Real>
+        <Real Name="Z">-280.20239</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">113.79247</Real>
+        <Real Name="Y">54.98378</Real>
+        <Real Name="Z">-58.121162</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-59.038528</Real>
+        <Real Name="Y">-239.76218</Real>
+        <Real Name="Z">-1.0450134</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.09412</Real>
+        <Real Name="Y">45.481411</Real>
+        <Real Name="Z">17.249908</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-101.29166</Real>
+        <Real Name="Y">24.636169</Real>
+        <Real Name="Z">166.12979</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620583</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620583</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620583</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070883734</Real>
+        <Real Name="Y">0.59991843</Real>
+        <Real Name="Z">0.23198971</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.004895567</Real>
+        <Real Name="Y">0.67720783</Real>
+        <Real Name="Z">0.2884154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.082309276</Real>
+        <Real Name="Y">0.61425996</Real>
+        <Real Name="Z">0.17455754</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9733544</Real>
+        <Real Name="Y">0.63034081</Real>
+        <Real Name="Z">1.5736233</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94124728</Real>
+        <Real Name="Y">0.57207602</Real>
+        <Real Name="Z">1.6424468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90214086</Real>
+        <Real Name="Y">0.69281465</Real>
+        <Real Name="Z">1.5599132</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959444</Real>
+        <Real Name="Y">0.44666046</Real>
+        <Real Name="Z">1.1632005</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3338616</Real>
+        <Real Name="Y">0.47015244</Real>
+        <Real Name="Z">1.2321656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3415514</Real>
+        <Real Name="Y">0.43269157</Real>
+        <Real Name="Z">1.0856854</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6414124</Real>
+        <Real Name="Y">0.31910458</Real>
+        <Real Name="Z">0.31263226</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7041454</Real>
+        <Real Name="Y">0.35027403</Real>
+        <Real Name="Z">0.2473993</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.626856</Real>
+        <Real Name="Y">0.22725457</Real>
+        <Real Name="Z">0.28996071</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7798015</Real>
+        <Real Name="Y">0.3910079</Real>
+        <Real Name="Z">0.024203956</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6904104</Real>
+        <Real Name="Y">0.42112949</Real>
+        <Real Name="Z">0.0079487562</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8165625</Real>
+        <Real Name="Y">0.45610136</Real>
+        <Real Name="Z">0.083985105</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.17196612</Real>
+        <Real Name="Y">0.085058868</Real>
+        <Real Name="Z">-0.96145558</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.70626277</Real>
+        <Real Name="Y">-2.005532</Real>
+        <Real Name="Z">2.0441647</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5678263</Real>
+        <Real Name="Y">0.17417142</Real>
+        <Real Name="Z">2.0687399</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11851782</Real>
+        <Real Name="Y">-0.055032719</Real>
+        <Real Name="Z">0.2986187</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22711693</Real>
+        <Real Name="Y">-2.5167255</Real>
+        <Real Name="Z">-1.7610809</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.76412129</Real>
+        <Real Name="Y">-0.56535572</Real>
+        <Real Name="Z">1.2675359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.075636238</Real>
+        <Real Name="Y">-0.02098828</Real>
+        <Real Name="Z">-0.67175108</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43077201</Real>
+        <Real Name="Y">-0.37801453</Real>
+        <Real Name="Z">-0.089059517</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.6710856</Real>
+        <Real Name="Y">0.16225477</Real>
+        <Real Name="Z">-0.29035774</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24561226</Real>
+        <Real Name="Y">0.3549757</Real>
+        <Real Name="Z">0.60163552</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31486189</Real>
+        <Real Name="Y">1.4506271</Real>
+        <Real Name="Z">1.6442505</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3213427</Real>
+        <Real Name="Y">-0.13544855</Real>
+        <Real Name="Z">0.7889781</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.032266356</Real>
+        <Real Name="Y">0.054356504</Real>
+        <Real Name="Z">0.01525806</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63948548</Real>
+        <Real Name="Y">-0.38885447</Real>
+        <Real Name="Z">2.6542115</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.30089188</Real>
+        <Real Name="Y">-2.4375682</Real>
+        <Real Name="Z">3.0641038</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-165.59886</Real>
+        <Real Name="Y">-319.1459</Real>
+        <Real Name="Z">-377.24359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.500202</Real>
+        <Real Name="Y">68.321678</Real>
+        <Real Name="Z">100.04211</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.71136</Real>
+        <Real Name="Y">141.9118</Real>
+        <Real Name="Z">72.10833</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.224174</Real>
+        <Real Name="Y">-15.094166</Real>
+        <Real Name="Z">-36.560646</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.3552971</Real>
+        <Real Name="Y">2.7187796</Real>
+        <Real Name="Z">14.708187</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1764297</Real>
+        <Real Name="Y">7.4052773</Real>
+        <Real Name="Z">12.12648</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.231934</Real>
+        <Real Name="Y">-17.591557</Real>
+        <Real Name="Z">-31.282852</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.41885</Real>
+        <Real Name="Y">14.940037</Real>
+        <Real Name="Z">25.199409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.5055256</Real>
+        <Real Name="Y">7.6216316</Real>
+        <Real Name="Z">15.809425</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-179.80611</Real>
+        <Real Name="Y">3.9613647</Real>
+        <Real Name="Z">101.28729</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">146.4632</Real>
+        <Real Name="Y">-33.253265</Real>
+        <Real Name="Z">-82.281128</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">72.29248</Real>
+        <Real Name="Y">9.4069519</Real>
+        <Real Name="Z">-49.194923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.66787</Real>
+        <Real Name="Y">-311.22858</Real>
+        <Real Name="Z">-20.719849</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.332924</Real>
+        <Real Name="Y">116.77867</Real>
+        <Real Name="Z">-0.34015656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.43856</Real>
+        <Real Name="Y">323.24731</Real>
+        <Real Name="Z">256.34195</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562597</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562597</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562597</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562597</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562569</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562569</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562569</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562569</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562569</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562569</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562569</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562421</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562721</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562721</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562721</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562721</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">17.819868</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">17.819992</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">17.833693</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">17.83379</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">17.83391</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">20.369211</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">20.369324</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">20.368769</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">20.367521</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">20.365421</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">20.362448</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">20.339834</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">20.309952</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">17.845234</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">17.843647</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">17.841927</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">17.840126</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">27.096624</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">27.013031</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">27.026947</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">27.118313</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">27.357586</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">33.603043</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.858845</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">36.263416</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.803551</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">39.45829</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">41.197769</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">42.956997</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">44.712715</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">35.527287</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">36.924614</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">38.375389</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">39.855198</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733761</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5691261</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5693417</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6606112</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8997631</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.617729</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.873419</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.278545</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.819927</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.476767</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.219219</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-23.008081</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.793682</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-18.004732</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.403646</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.856142</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.337751</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951088</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154483</Real>
+        <Real Name="Y">0.6098752</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829585</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.2081964</Real>
+        <Real Name="Y">-0.7183184</Real>
+        <Real Name="Z">0.011077392</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.65627712</Real>
+        <Real Name="Y">-0.44132945</Real>
+        <Real Name="Z">-0.19586644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.079432383</Real>
+        <Real Name="Y">-1.3403528</Real>
+        <Real Name="Z">0.0942358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43983412</Real>
+        <Real Name="Y">-0.12730011</Real>
+        <Real Name="Z">0.16848481</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1064552</Real>
+        <Real Name="Y">1.2083107</Real>
+        <Real Name="Z">0.58867824</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3857259</Real>
+        <Real Name="Y">0.65410167</Real>
+        <Real Name="Z">0.10518272</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.41357264</Real>
+        <Real Name="Y">0.039098304</Real>
+        <Real Name="Z">0.41653091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.30952451</Real>
+        <Real Name="Y">0.032534141</Real>
+        <Real Name="Z">1.21565</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7555673</Real>
+        <Real Name="Y">-2.029453</Real>
+        <Real Name="Z">1.5685941</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25622329</Real>
+        <Real Name="Y">0.31483555</Real>
+        <Real Name="Z">-0.34178945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.14576393</Real>
+        <Real Name="Y">0.34296301</Real>
+        <Real Name="Z">-0.42390847</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.0196642</Real>
+        <Real Name="Y">0.51929116</Real>
+        <Real Name="Z">-0.45123479</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1525732</Real>
+        <Real Name="Y">0.53524446</Real>
+        <Real Name="Z">-0.26926085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25469711</Real>
+        <Real Name="Y">-0.76836795</Real>
+        <Real Name="Z">-1.2156236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.92007476</Real>
+        <Real Name="Y">1.1309038</Real>
+        <Real Name="Z">-1.048301</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9518738</Real>
+        <Real Name="Y">10.126022</Real>
+        <Real Name="Z">-383.92468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054081</Real>
+        <Real Name="Y">8.7835617</Real>
+        <Real Name="Z">109.98161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.0733</Real>
+        <Real Name="Y">125.90257</Real>
+        <Real Name="Z">223.10434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850433</Real>
+        <Real Name="Y">8.0224648</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90619</Real>
+        <Real Name="Y">-91.872864</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62735</Real>
+        <Real Name="Y">82.504333</Real>
+        <Real Name="Z">-270.19894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937</Real>
+        <Real Name="Y">45.329948</Real>
+        <Real Name="Z">-56.291359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365723</Real>
+        <Real Name="Y">-204.77948</Real>
+        <Real Name="Z">21.695251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097099</Real>
+        <Real Name="Y">47.599464</Real>
+        <Real Name="Z">-24.246674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.29879</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65219</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620597</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620597</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620597</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059800348</Real>
+        <Real Name="Y">0.59962511</Real>
+        <Real Name="Z">0.23887588</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8579625</Real>
+        <Real Name="Y">0.68770224</Real>
+        <Real Name="Z">0.27497548</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062415659</Real>
+        <Real Name="Y">0.61132395</Real>
+        <Real Name="Z">0.16245289</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97424376</Real>
+        <Real Name="Y">0.63071269</Real>
+        <Real Name="Z">1.5712773</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94452566</Real>
+        <Real Name="Y">0.59312117</Real>
+        <Real Name="Z">1.6541388</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9086231</Real>
+        <Real Name="Y">0.69711834</Real>
+        <Real Name="Z">1.5501459</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3964937</Real>
+        <Real Name="Y">0.44683182</Real>
+        <Real Name="Z">1.1685987</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3311406</Real>
+        <Real Name="Y">0.47333977</Real>
+        <Real Name="Z">1.2333184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3462207</Real>
+        <Real Name="Y">0.43159303</Real>
+        <Real Name="Z">1.0885816</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.643316</Real>
+        <Real Name="Y">0.31615916</Real>
+        <Real Name="Z">0.30757636</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7027956</Real>
+        <Real Name="Y">0.33864319</Real>
+        <Real Name="Z">0.23602945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6093986</Real>
+        <Real Name="Y">0.22972292</Real>
+        <Real Name="Z">0.28432333</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7792749</Real>
+        <Real Name="Y">0.39118055</Real>
+        <Real Name="Z">0.024518978</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6974217</Real>
+        <Real Name="Y">0.42105404</Real>
+        <Real Name="Z">1.8469563</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8185172</Real>
+        <Real Name="Y">0.47042087</Real>
+        <Real Name="Z">0.0611705</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11737403</Real>
+        <Real Name="Y">-0.020639135</Real>
+        <Real Name="Z">-0.72704613</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5003158</Real>
+        <Real Name="Y">-0.57569098</Real>
+        <Real Name="Z">1.0898176</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.061316</Real>
+        <Real Name="Y">0.42389175</Real>
+        <Real Name="Z">0.73648548</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10070757</Real>
+        <Real Name="Y">-0.038040169</Real>
+        <Real Name="Z">0.2858139</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.65078074</Real>
+        <Real Name="Y">-2.7293496</Real>
+        <Real Name="Z">-1.0756634</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.87468147</Real>
+        <Real Name="Y">-0.50788838</Real>
+        <Real Name="Z">1.1749139</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.060024023</Real>
+        <Real Name="Y">-0.022458818</Real>
+        <Real Name="Z">-0.67828554</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22868931</Real>
+        <Real Name="Y">-0.41845119</Real>
+        <Real Name="Z">-0.22088864</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46781027</Real>
+        <Real Name="Y">0.10878441</Real>
+        <Real Name="Z">-0.44839996</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2246919</Real>
+        <Real Name="Y">0.38152525</Real>
+        <Real Name="Z">0.6692546</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019250426</Real>
+        <Real Name="Y">1.4425607</Real>
+        <Real Name="Z">1.1636504</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9405003</Real>
+        <Real Name="Y">-0.49722627</Real>
+        <Real Name="Z">0.66007453</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11612008</Real>
+        <Real Name="Y">-0.095142275</Real>
+        <Real Name="Z">-0.071052521</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2097604</Real>
+        <Real Name="Y">0.50515223</Real>
+        <Real Name="Z">2.9769554</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.097167075</Real>
+        <Real Name="Y">-1.009452</Real>
+        <Real Name="Z">2.2175789</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-67.305069</Real>
+        <Real Name="Y">-110.64977</Real>
+        <Real Name="Z">-418.09601</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45492172</Real>
+        <Real Name="Y">35.587212</Real>
+        <Real Name="Z">108.83005</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">177.0912</Real>
+        <Real Name="Y">149.00166</Real>
+        <Real Name="Z">168.31873</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.745712</Real>
+        <Real Name="Y">-14.351944</Real>
+        <Real Name="Z">-37.638168</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.748779</Real>
+        <Real Name="Y">-8.0131025</Real>
+        <Real Name="Z">-23.772495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3077393</Real>
+        <Real Name="Y">7.6753006</Real>
+        <Real Name="Z">12.778206</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.157379</Real>
+        <Real Name="Y">-14.35561</Real>
+        <Real Name="Z">-32.970016</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.423615</Real>
+        <Real Name="Y">12.125118</Real>
+        <Real Name="Z">27.147602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.920513</Real>
+        <Real Name="Y">16.920238</Real>
+        <Real Name="Z">54.454868</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-257.06943</Real>
+        <Real Name="Y">-51.51593</Real>
+        <Real Name="Z">176.05133</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">211.81606</Real>
+        <Real Name="Y">25.161224</Real>
+        <Real Name="Z">-196.50021</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.512527</Real>
+        <Real Name="Y">32.904785</Real>
+        <Real Name="Z">-53.832558</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.627975</Real>
+        <Real Name="Y">-234.67767</Real>
+        <Real Name="Z">8.3063354</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.22493</Real>
+        <Real Name="Y">75.866165</Real>
+        <Real Name="Z">-10.555252</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.647339</Real>
+        <Real Name="Y">78.322296</Real>
+        <Real Name="Z">217.47757</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620611</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620611</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620611</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0014075278</Real>
+        <Real Name="Y">0.58945352</Real>
+        <Real Name="Z">0.24147981</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8537898</Real>
+        <Real Name="Y">0.67571354</Real>
+        <Real Name="Z">0.28182638</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.07674589</Real>
+        <Real Name="Y">0.59856343</Real>
+        <Real Name="Z">0.18314065</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98186928</Real>
+        <Real Name="Y">0.6291436</Real>
+        <Real Name="Z">1.5715755</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9735043</Real>
+        <Real Name="Y">0.63094902</Real>
+        <Real Name="Z">1.6669122</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.93998593</Real>
+        <Real Name="Y">0.71007234</Real>
+        <Real Name="Z">1.5422729</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3893542</Real>
+        <Real Name="Y">0.44760033</Real>
+        <Real Name="Z">1.1803287</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3378758</Real>
+        <Real Name="Y">0.4784025</Real>
+        <Real Name="Z">1.2549177</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3265193</Real>
+        <Real Name="Y">0.40045702</Real>
+        <Real Name="Z">1.1256334</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6489069</Real>
+        <Real Name="Y">0.31804886</Real>
+        <Real Name="Z">0.29604006</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7083499</Real>
+        <Real Name="Y">0.3412824</Real>
+        <Real Name="Z">0.2247024</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6025246</Real>
+        <Real Name="Y">0.24054536</Real>
+        <Real Name="Z">0.26435083</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7749853</Real>
+        <Real Name="Y">0.39908949</Real>
+        <Real Name="Z">0.02070451</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7157216</Real>
+        <Real Name="Y">0.40803099</Real>
+        <Real Name="Z">1.8081321</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7882892</Real>
+        <Real Name="Y">0.48868573</Real>
+        <Real Name="Z">0.051653553</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.20834284</Real>
+        <Real Name="Y">-0.57505912</Real>
+        <Real Name="Z">-0.34566823</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.33012763</Real>
+        <Real Name="Y">-1.4134141</Real>
+        <Real Name="Z">1.6370255</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4329278</Real>
+        <Real Name="Y">-0.74026102</Real>
+        <Real Name="Z">2.8896997</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42179811</Real>
+        <Real Name="Y">-0.10212653</Real>
+        <Real Name="Z">0.15944542</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5723622</Real>
+        <Real Name="Y">0.81535208</Real>
+        <Real Name="Z">0.25427929</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5857781</Real>
+        <Real Name="Y">0.4623782</Real>
+        <Real Name="Z">0.026008813</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.52768898</Real>
+        <Real Name="Y">0.026142946</Real>
+        <Real Name="Z">0.3745966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.58014852</Real>
+        <Real Name="Y">0.21091054</Real>
+        <Real Name="Z">1.0747161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.98487526</Real>
+        <Real Name="Y">-1.7498201</Real>
+        <Real Name="Z">2.3635409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23112316</Real>
+        <Real Name="Y">0.30725667</Real>
+        <Real Name="Z">-0.40359142</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39121118</Real>
+        <Real Name="Y">1.2820225</Real>
+        <Real Name="Z">0.038961452</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.81902796</Real>
+        <Real Name="Y">0.30296874</Real>
+        <Real Name="Z">-1.27071</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19974084</Real>
+        <Real Name="Y">0.37667432</Real>
+        <Real Name="Z">-0.25046107</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.49571744</Real>
+        <Real Name="Y">0.018430706</Real>
+        <Real Name="Z">-0.85229957</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7329931</Real>
+        <Real Name="Y">0.2894499</Real>
+        <Real Name="Z">1.2302283</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-78.897171</Real>
+        <Real Name="Y">62.24733</Real>
+        <Real Name="Z">-366.71887</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.3855476</Real>
+        <Real Name="Y">0.76643372</Real>
+        <Real Name="Z">112.20612</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">135.41</Real>
+        <Real Name="Y">3.0836945</Real>
+        <Real Name="Z">132.27005</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.724411</Real>
+        <Real Name="Y">-23.658642</Real>
+        <Real Name="Z">-37.737694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.674408</Real>
+        <Real Name="Y">7.0476761</Real>
+        <Real Name="Z">14.365864</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.3349686</Real>
+        <Real Name="Y">12.813938</Real>
+        <Real Name="Z">11.897949</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.799438</Real>
+        <Real Name="Y">-4.0063248</Real>
+        <Real Name="Z">-32.307785</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.225182</Real>
+        <Real Name="Y">9.0931587</Real>
+        <Real Name="Z">-18.082169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.153587</Real>
+        <Real Name="Y">4.2722359</Real>
+        <Real Name="Z">18.138695</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-314.56589</Real>
+        <Real Name="Y">-129.70181</Real>
+        <Real Name="Z">277.17676</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">243.12465</Real>
+        <Real Name="Y">99.168594</Real>
+        <Real Name="Z">-284.50128</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">118.53728</Real>
+        <Real Name="Y">60.260033</Real>
+        <Real Name="Z">-65.439774</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-76.372406</Real>
+        <Real Name="Y">-323.16693</Real>
+        <Real Name="Z">-34.785217</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">20.006628</Real>
+        <Real Name="Y">58.356884</Real>
+        <Real Name="Z">26.722534</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.764313</Real>
+        <Real Name="Y">163.42374</Real>
+        <Real Name="Z">246.79477</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_Crescale_4Ranks_1RanksPerSimulation_d.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_Crescale_4Ranks_1RanksPerSimulation_d.xml
new file mode 100644 (file)
index 0000000..f4d0ddb
--- /dev/null
@@ -0,0 +1,3398 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4533416426810541</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4533416426810541</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4533416426810541</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4533416426810541</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4529787145135691</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4529787145135691</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4529787145135691</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4529787145135691</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4529787145135691</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4529787145135691</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.453853501650137</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.453853501650137</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4485388113178264</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4485388113178264</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4485388113178264</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4485388113178264</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">19.965980763101982</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">20.842760388505631</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">19.960013877466871</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">19.959232604591755</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">19.959915811882034</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">18.41224606539663</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">18.412274144635465</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">18.412211496403025</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">18.412019666767495</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">18.372195539529724</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">18.371195270594395</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">18.731819710149967</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">18.360830976924237</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">25.691020568821983</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">25.692435663552004</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">25.691888424681053</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">25.693207802703562</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629305410083006</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.229344742176963</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">28.967916050097003</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.737254472731372</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">30.664158285412096</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">31.494104361336923</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">32.021175116445328</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">32.695884068204165</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">33.515214605630732</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">34.420423841336969</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">35.403064325879946</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">36.127958977809008</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">36.955063388488242</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">36.26888217566858</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">36.991491492548597</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">37.792814546880592</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">38.672439739062114</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.160837447757904</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.782155266716705</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.552274962226191</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.478495567616639</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.231653597802186</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.758696273671756</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.433467873663034</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.252990240725129</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.198023603669139</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.181236074953089</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.287459570883399</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.485552714788362</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-13.245643210179139</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-13.966837432329138</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-14.768707725532083</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-15.647013539691097</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13823960248430167</Real>
+        <Real Name="Y">-0.083001582473174879</Real>
+        <Real Name="Z">-0.55156788526044775</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807346912896781</Real>
+        <Real Name="Y">0.12594239723743811</Real>
+        <Real Name="Z">0.08634003909985162</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50558175484200552</Real>
+        <Real Name="Y">-0.26347201049012287</Real>
+        <Real Name="Z">-0.37043107548326104</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.08034197360884994</Real>
+        <Real Name="Y">-0.036383374851252738</Real>
+        <Real Name="Z">0.26950251001929981</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0879938107726246</Real>
+        <Real Name="Y">-2.69925195488055</Real>
+        <Real Name="Z">-0.41161299800761308</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.005339856872981</Real>
+        <Real Name="Y">-0.44613327229712957</Real>
+        <Real Name="Z">1.1534368241800748</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046991365082634871</Real>
+        <Real Name="Y">-0.027139438957271687</Real>
+        <Real Name="Z">-0.68356956696424598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.05202773043970705</Real>
+        <Real Name="Y">-0.42394701288611158</Real>
+        <Real Name="Z">-0.38240890291446672</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25145271172169875</Real>
+        <Real Name="Y">0.072329295992862669</Real>
+        <Real Name="Z">-0.58384125172376966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20047275659675193</Real>
+        <Real Name="Y">0.39459474035999631</Real>
+        <Real Name="Z">0.71751226731035578</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21660158751017167</Real>
+        <Real Name="Y">1.2107968994948017</Real>
+        <Real Name="Z">0.86109126390401169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3771064228719012</Real>
+        <Real Name="Y">-0.66102181650660441</Real>
+        <Real Name="Z">0.8707144786748191</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2170122537672452</Real>
+        <Real Name="Y">-0.090547598182205036</Real>
+        <Real Name="Z">-0.034702681691129153</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639425064678223</Real>
+        <Real Name="Y">0.96363069485778263</Real>
+        <Real Name="Z">2.5346418773966413</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37424921124686311</Real>
+        <Real Name="Y">-0.37914050295285712</Real>
+        <Real Name="Z">0.73119277083077761</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617444914505814</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617444914505814</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617444914505814</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0031028528386705871</Real>
+        <Real Name="Y">0.59400799129143278</Real>
+        <Real Name="Z">0.24342543439404379</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8500400458566697</Real>
+        <Real Name="Y">0.68411570892063489</Real>
+        <Real Name="Z">0.27212493851491881</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059129369823651988</Real>
+        <Real Name="Y">0.60229898537169224</Real>
+        <Real Name="Z">0.16625933295246265</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97850277762156124</Real>
+        <Real Name="Y">0.62985864901807953</Real>
+        <Real Name="Z">1.5701583220364854</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96189298516567268</Real>
+        <Real Name="Y">0.62420949123610092</Real>
+        <Real Name="Z">1.664256782230721</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92821886331112391</Real>
+        <Real Name="Y">0.70607842940365995</Real>
+        <Real Name="Z">1.5414461044350183</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3929230092423734</Real>
+        <Real Name="Y">0.4472803467118171</Real>
+        <Real Name="Z">1.1772638414128016</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3333708947762455</Real>
+        <Real Name="Y">0.47707807811856384</Real>
+        <Real Name="Z">1.2460239989578823</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.335348079935518</Real>
+        <Real Name="Y">0.41407945126181006</Real>
+        <Real Name="Z">1.1083788179561167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6468628021738794</Real>
+        <Real Name="Y">0.31567282121200158</Real>
+        <Real Name="Z">0.2989382660451253</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7053904036784551</Real>
+        <Real Name="Y">0.33268596023410624</Real>
+        <Real Name="Z">0.2251318207795818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5972199852746483</Real>
+        <Real Name="Y">0.23811239435272635</Real>
+        <Real Name="Z">0.27281759768239056</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7761877771988581</Real>
+        <Real Name="Y">0.39607734648512571</Real>
+        <Real Name="Z">0.022669498455783452</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7120097310336984</Real>
+        <Real Name="Y">0.4095082534453941</Real>
+        <Real Name="Z">1.8146780054460672</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8060164386426185</Real>
+        <Real Name="Y">0.48421325865438625</Real>
+        <Real Name="Z">0.045133477234387549</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.24509320223178696</Real>
+        <Real Name="Y">-0.72268188181684412</Real>
+        <Real Name="Z">-0.13607304126360209</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.62219151707313913</Real>
+        <Real Name="Y">-0.82375119376745332</Real>
+        <Real Name="Z">0.65284882807172728</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6720370142872181</Real>
+        <Real Name="Y">-0.66553595720917413</Real>
+        <Real Name="Z">1.2261414808272679</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45931933362987609</Real>
+        <Real Name="Y">-0.12490695411780134</Real>
+        <Real Name="Z">0.1683235565735918</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4889537825757255</Real>
+        <Real Name="Y">1.0727112850122202</Real>
+        <Real Name="Z">0.43560195826582415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.598760022121849</Real>
+        <Real Name="Y">0.61206677556074696</Real>
+        <Real Name="Z">0.097035758472257441</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.50273694726302331</Real>
+        <Real Name="Y">0.039858804075739572</Real>
+        <Real Name="Z">0.41842661651062257</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.54647420735842722</Real>
+        <Real Name="Y">0.092774807263900833</Real>
+        <Real Name="Z">1.3181119438426145</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.5448353732913092</Real>
+        <Real Name="Y">-2.0395209092771003</Real>
+        <Real Name="Z">2.2285846848256865</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26044567657477458</Real>
+        <Real Name="Y">0.33387884835778459</Real>
+        <Real Name="Z">-0.39617872342005239</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.29250413942055542</Real>
+        <Real Name="Y">0.85370808625167371</Real>
+        <Real Name="Z">-0.25290744714910263</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39090664317585488</Real>
+        <Real Name="Y">0.41564837176935887</Real>
+        <Real Name="Z">-0.89208267040958156</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20275669441386795</Real>
+        <Real Name="Y">0.47850379315548747</Real>
+        <Real Name="Z">-0.29139011402370463</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42793204241023608</Real>
+        <Real Name="Y">-0.55593737295483581</Real>
+        <Real Name="Z">-1.0860953289613544</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8312227588576393</Real>
+        <Real Name="Y">0.96398792986650883</Real>
+        <Real Name="Z">0.0328055887890496</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.1370039094056494</Real>
+        <Real Name="Y">62.916730147705039</Real>
+        <Real Name="Z">-372.66519203563985</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.889571290285069</Real>
+        <Real Name="Y">0.97026860343865451</Real>
+        <Real Name="Z">111.92505380980094</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.48977416025576</Real>
+        <Real Name="Y">62.028594745568839</Real>
+        <Real Name="Z">206.36463819039125</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.777324974603587</Real>
+        <Real Name="Y">-19.119550167219067</Real>
+        <Real Name="Z">-38.883075913022154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.649149980148046</Real>
+        <Real Name="Y">-9.5548070808283683</Real>
+        <Real Name="Z">-24.64425427305224</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4826472105680537</Real>
+        <Real Name="Y">10.638687729663612</Real>
+        <Real Name="Z">12.94494372230821</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.637587322753845</Real>
+        <Real Name="Y">-7.113777524477932</Real>
+        <Real Name="Z">-33.302469751027218</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-57.139732774775297</Real>
+        <Real Name="Y">11.20052914069672</Real>
+        <Real Name="Z">-15.181298875839801</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.714143084053887</Real>
+        <Real Name="Y">18.994267284889876</Real>
+        <Real Name="Z">56.60551301413539</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-309.77953775539635</Real>
+        <Real Name="Y">-124.14990437912569</Real>
+        <Real Name="Z">256.210291408817</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">237.24007197184639</Real>
+        <Real Name="Y">108.17867985462698</Real>
+        <Real Name="Z">-280.93663765543738</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">114.17263388168055</Real>
+        <Real Name="Y">55.657940180179864</Real>
+        <Real Name="Z">-58.071148288795541</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-58.066015601778872</Real>
+        <Real Name="Y">-240.6101509957135</Real>
+        <Real Name="Z">-2.2670129205145599</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.1327670844105668</Real>
+        <Real Name="Y">45.245204790198535</Real>
+        <Real Name="Z">16.931412969153229</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.89065774943552</Real>
+        <Real Name="Y">24.717287670396502</Real>
+        <Real Name="Z">164.96923659872283</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8613174090039692</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8613174090039692</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8613174090039692</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0034234718454542452</Real>
+        <Real Name="Y">0.60625590066704504</Real>
+        <Real Name="Z">0.23542252401855071</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.02438435364296633</Real>
+        <Real Name="Y">0.66660323268056432</Real>
+        <Real Name="Z">0.30670477533765889</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.084996388043535764</Real>
+        <Real Name="Y">0.59825359210291518</Real>
+        <Real Name="Z">0.18598427161633779</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97140251138137035</Real>
+        <Real Name="Y">0.63311446527135562</Real>
+        <Real Name="Z">1.566941105489613</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97448319158524721</Real>
+        <Real Name="Y">0.60590486686803091</Real>
+        <Real Name="Z">1.6586605994056336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.88974971908378764</Real>
+        <Real Name="Y">0.68247510932792566</Real>
+        <Real Name="Z">1.5592816846023585</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3954028041275528</Real>
+        <Real Name="Y">0.44148288878478825</Real>
+        <Real Name="Z">1.1688650848303117</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3330591058715195</Real>
+        <Real Name="Y">0.43661460466570423</Real>
+        <Real Name="Z">1.241334950964424</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3508380814749559</Real>
+        <Real Name="Y">0.39838536694386323</Real>
+        <Real Name="Z">1.0959342442615392</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6444969271345988</Real>
+        <Real Name="Y">0.31663147416594306</Real>
+        <Real Name="Z">0.3034388791374818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6947676413633745</Real>
+        <Real Name="Y">0.33295481734220972</Real>
+        <Real Name="Z">0.22363460507601152</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5988130356786514</Real>
+        <Real Name="Y">0.2342214502335925</Real>
+        <Real Name="Z">0.28658989053548323</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7758290178168044</Real>
+        <Real Name="Y">0.39339098531432382</Real>
+        <Real Name="Z">0.033119229474464627</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7156323687701458</Real>
+        <Real Name="Y">0.42418407160794108</Real>
+        <Real Name="Z">1.8266836482856241</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8479330381408401</Real>
+        <Real Name="Y">0.45632677686974416</Real>
+        <Real Name="Z">0.03156526859869517</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.10691349622197982</Real>
+        <Real Name="Y">0.64458239633897607</Real>
+        <Real Name="Z">-0.6176919820665695</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.66396759540976313</Real>
+        <Real Name="Y">-3.3806398252138643</Real>
+        <Real Name="Z">2.8252162055704906</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8156365801813028</Real>
+        <Real Name="Y">-1.6359877070189797</Real>
+        <Real Name="Z">2.3968035629577091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19690784509018525</Real>
+        <Real Name="Y">0.14221064186001789</Real>
+        <Real Name="Z">-0.11297147375052549</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5068004435354996</Real>
+        <Real Name="Y">-0.48790353956115512</Real>
+        <Real Name="Z">-0.33886007823427766</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2730619568280628</Real>
+        <Real Name="Y">-1.3637440682072752</Real>
+        <Real Name="Z">1.3002538120305129</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.13193432106367897</Real>
+        <Real Name="Y">-0.3476995449750408</Real>
+        <Real Name="Z">-0.2758265236409102</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.88425092682002326</Real>
+        <Real Name="Y">-2.1573382632816913</Real>
+        <Real Name="Z">0.51079016764823737</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22974547311683241</Real>
+        <Real Name="Y">-1.7713609646212487</Real>
+        <Real Name="Z">0.32717627768097385</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.013667382504599028</Real>
+        <Real Name="Y">0.21463992531369278</Real>
+        <Real Name="Z">0.082702749210800897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.59108407561997778</Real>
+        <Real Name="Y">1.1242667709395222</Real>
+        <Real Name="Z">-0.11992095236285893</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.60249899467255719</Real>
+        <Real Name="Y">-0.067645328840258825</Real>
+        <Real Name="Z">-0.14737976763727725</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11678404497713082</Real>
+        <Real Name="Y">-0.010808026214218194</Real>
+        <Real Name="Z">0.46217801592059959</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31806368080012282</Real>
+        <Real Name="Y">0.8132898772195214</Real>
+        <Real Name="Z">0.44396274709577505</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.0024385792524981</Real>
+        <Real Name="Y">-1.2777192152433043</Real>
+        <Real Name="Z">0.12881364399777462</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">153.33758463975619</Real>
+        <Real Name="Y">100.15282112898652</Real>
+        <Real Name="Z">-279.81001717075407</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-42.076620083082794</Real>
+        <Real Name="Y">-32.723451198679676</Real>
+        <Real Name="Z">77.473880086615893</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.178176046374674</Real>
+        <Real Name="Y">44.0594357986229</Real>
+        <Real Name="Z">191.80198283238292</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">9.8835550237951111</Real>
+        <Real Name="Y">-26.702591602868416</Real>
+        <Real Name="Z">-24.927431437865764</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.31059112292624</Real>
+        <Real Name="Y">-5.4051904449843704</Real>
+        <Real Name="Z">-27.115418913319623</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">26.771596840069385</Real>
+        <Real Name="Y">-8.8599210031659368</Real>
+        <Real Name="Z">-23.414326644171382</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.66773700974997</Real>
+        <Real Name="Y">-17.088547666959521</Real>
+        <Real Name="Z">-28.023746063963621</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.5138822622582</Real>
+        <Real Name="Y">17.401580788340162</Real>
+        <Real Name="Z">-21.194903825450545</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-67.136580422454543</Real>
+        <Real Name="Y">41.532503089963576</Real>
+        <Real Name="Z">83.339023831021251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-262.71134302178473</Real>
+        <Real Name="Y">-175.09068917276392</Real>
+        <Real Name="Z">380.66926403601451</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">235.54512710024292</Real>
+        <Real Name="Y">174.94647517094683</Real>
+        <Real Name="Z">-390.71736659411619</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">95.282735957212168</Real>
+        <Real Name="Y">78.592659503876149</Real>
+        <Real Name="Z">-89.224602628047649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-95.556312845852915</Real>
+        <Real Name="Y">-431.39222120350939</Real>
+        <Real Name="Z">6.7281327266410926</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.233877413023308</Real>
+        <Real Name="Y">112.92192077182962</Real>
+        <Real Name="Z">39.010517450944747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.21624251771669</Real>
+        <Real Name="Y">127.65521604036553</Real>
+        <Real Name="Z">105.40501231406841</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4529787145135691</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4529787145135691</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4529787145135691</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4529787145135691</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4533416426810541</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4533416426810541</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4533416426810541</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4533416426810541</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.435455098231774</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.435455098231774</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4485388113178264</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4485388113178264</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.453853501650137</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.453853501650137</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.453853501650137</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.453853501650137</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">18.408310287007204</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">16.978553735510552</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">18.413417110959287</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">18.412061726680996</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">18.412172742795455</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">19.960355908069381</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">19.960400747336912</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">19.959916123129517</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">19.958755000661352</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">25.752902610444337</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">25.657509122857654</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">26.365557338239149</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">25.690136754749417</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">18.359928875026682</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">18.358468816960535</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">18.356850446045897</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">18.355143909370923</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">28.072358033056044</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.396315278990091</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.811461207239759</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">30.888266364150173</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">31.116279917903107</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">31.748650387492823</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">32.989016405114469</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">34.378930457539553</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.905985061506456</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">35.555876014309533</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">36.003547193708428</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">35.780413976023738</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">35.635684041840804</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">38.246438101004301</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">39.610773153391499</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">41.026725437898634</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">42.470133463545878</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5675568453414339</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.547839398142365</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6259999393310718</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8539024769695462</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.562547573510018</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.80286875186413</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.193267428496611</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.721483154931679</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.178610013746104</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.640269144870544</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-12.082638241117129</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-12.613328890423929</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.777829529201977</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.143624639655322</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.561195295077095</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.006309857399312</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21190890418197439</Real>
+        <Real Name="Y">-0.7311311919098834</Real>
+        <Real Name="Z">0.011277778119910499</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.66796314487407893</Real>
+        <Real Name="Y">-0.44908961562317945</Real>
+        <Real Name="Z">-0.19934647018435334</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.080882597990871996</Real>
+        <Real Name="Y">-1.3642241529051329</Real>
+        <Real Name="Z">0.095855310056509185</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44769583968342896</Real>
+        <Real Name="Y">-0.12958260429636317</Real>
+        <Real Name="Z">0.17147102653965599</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1260077456076665</Real>
+        <Real Name="Y">1.2299432703788549</Real>
+        <Real Name="Z">0.59933785465319467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4102608467371438</Real>
+        <Real Name="Y">0.66588072547259036</Real>
+        <Real Name="Z">0.10716908923047011</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.42091576278340037</Real>
+        <Real Name="Y">0.039801072970148413</Real>
+        <Real Name="Z">0.4239928608933955</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31497744055640853</Real>
+        <Real Name="Y">0.033114800275404865</Real>
+        <Real Name="Z">1.2372826323989534</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7872566667859691</Real>
+        <Real Name="Y">-2.0657209691150182</Real>
+        <Real Name="Z">1.5960222410479219</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26078907943572527</Real>
+        <Real Name="Y">0.32044762585901831</Real>
+        <Real Name="Z">-0.34787968920455964</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.148374024658951</Real>
+        <Real Name="Y">0.34906800206533178</Real>
+        <Real Name="Z">-0.43150156880076879</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.01999757278104131</Real>
+        <Real Name="Y">0.52855025949293</Real>
+        <Real Name="Z">-0.45929211920777768</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15528384653458924</Real>
+        <Real Name="Y">0.54477489000772439</Real>
+        <Real Name="Z">-0.27405115378506656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25903608390864075</Real>
+        <Real Name="Y">-0.78199538968155358</Real>
+        <Real Name="Z">-1.2374793615012896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93642846229023646</Real>
+        <Real Name="Y">1.151169402760081</Real>
+        <Real Name="Z">-1.0669585943196809</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617793935156957</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617793935156957</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617793935156957</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059497489050776581</Real>
+        <Real Name="Y">0.59954474592815077</Real>
+        <Real Name="Z">0.23896244186524002</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8573371245625392</Real>
+        <Real Name="Y">0.68765816996992235</Real>
+        <Real Name="Z">0.27488386817974808</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062270910153864732</Real>
+        <Real Name="Y">0.61130311310468655</Real>
+        <Real Name="Z">0.16246416739496561</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97412100480290587</Real>
+        <Real Name="Y">0.63062490899829415</Real>
+        <Real Name="Z">1.5709736645959547</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94453793300447542</Real>
+        <Real Name="Y">0.5935857506672233</Real>
+        <Real Name="Z">1.6541317129923336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90865659068372773</Real>
+        <Real Name="Y">0.69713445082783165</Real>
+        <Real Name="Z">1.5496849415328522</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3962949036566197</Real>
+        <Real Name="Y">0.44676994229295364</Real>
+        <Real Name="Z">1.1685669747851448</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3309123545411441</Real>
+        <Real Name="Y">0.47336310536618653</Real>
+        <Real Name="Z">1.2332217839560211</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3460697680359861</Real>
+        <Real Name="Y">0.43150877954672962</Real>
+        <Real Name="Z">1.0885241670912502</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6431129393900665</Real>
+        <Real Name="Y">0.31603203732342</Real>
+        <Real Name="Z">0.3073822074989454</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7025944180619708</Real>
+        <Real Name="Y">0.33834405868912987</Real>
+        <Real Name="Z">0.23578300500632227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6088127735528364</Real>
+        <Real Name="Y">0.22975868796140375</Real>
+        <Real Name="Z">0.2840857224980331</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7789743570570937</Real>
+        <Real Name="Y">0.39112882323373893</Real>
+        <Real Name="Z">0.024530529164732411</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.697407719385073</Real>
+        <Real Name="Y">0.42091470962013849</Real>
+        <Real Name="Z">1.8460358244154473</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8181431682367963</Real>
+        <Real Name="Y">0.47051212433116391</Real>
+        <Real Name="Z">0.060950498105464893</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.1129592668898026</Real>
+        <Real Name="Y">-0.01981015051767257</Real>
+        <Real Name="Z">-0.70917393675102647</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4541384125350827</Real>
+        <Real Name="Y">-0.56090328037620041</Real>
+        <Real Name="Z">1.0797594548406897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0424951693079696</Real>
+        <Real Name="Y">0.43998062957749673</Real>
+        <Real Name="Z">0.74261037161605914</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.096717856022201634</Real>
+        <Real Name="Y">-0.036783779902019476</Real>
+        <Real Name="Z">0.27525323798349893</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63530919155937493</Real>
+        <Real Name="Y">-2.6533573850023995</Real>
+        <Real Name="Z">-1.0286555737423457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.8522916714595743</Real>
+        <Real Name="Y">-0.49063759994168915</Real>
+        <Real Name="Z">1.1447798716167479</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.058474050679650544</Real>
+        <Real Name="Y">-0.021643148355950423</Real>
+        <Real Name="Z">-0.6576129800676751</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22556619547512924</Real>
+        <Real Name="Y">-0.40557886298810963</Real>
+        <Real Name="Z">-0.20913980962314288</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.45968962329950469</Real>
+        <Real Name="Y">0.10625579291077349</Real>
+        <Real Name="Z">-0.43167101740346447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21813753569207547</Real>
+        <Real Name="Y">0.37040368424829462</Real>
+        <Real Name="Z">0.64817623989753326</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.013139387655007773</Real>
+        <Real Name="Y">1.4088542005890337</Real>
+        <Real Name="Z">1.1326226561647184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8894030818268588</Real>
+        <Real Name="Y">-0.49254877070096148</Real>
+        <Real Name="Z">0.62960804616124932</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.1126795797081841</Real>
+        <Real Name="Y">-0.095850153269862931</Real>
+        <Real Name="Z">-0.068546924774971416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1882018619543424</Real>
+        <Real Name="Y">0.51005528381889209</Real>
+        <Real Name="Z">2.8806759293597564</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11876386292197338</Real>
+        <Real Name="Y">-0.97813731480475419</Real>
+        <Real Name="Z">2.1845714567081576</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-65.823698354404854</Real>
+        <Real Name="Y">-107.78819810837217</Real>
+        <Real Name="Z">-417.92487849928261</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10817279250452572</Real>
+        <Real Name="Y">34.996497133333705</Real>
+        <Real Name="Z">108.98042138455325</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">176.49144545297074</Real>
+        <Real Name="Y">148.22109907619767</Real>
+        <Real Name="Z">169.25079867877113</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.768837304682663</Real>
+        <Real Name="Y">-14.345078322164831</Real>
+        <Real Name="Z">-37.687769006710994</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.747333722170659</Real>
+        <Real Name="Y">-8.0413327786361357</Real>
+        <Real Name="Z">-23.767429684577948</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3226519204632794</Real>
+        <Real Name="Y">7.688120983585474</Real>
+        <Real Name="Z">12.800200163201872</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.263941864372697</Real>
+        <Real Name="Y">-14.270333222732404</Real>
+        <Real Name="Z">-33.009606628813337</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.512785093180227</Real>
+        <Real Name="Y">12.051544557678657</Real>
+        <Real Name="Z">27.19280843069032</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.944675877582505</Real>
+        <Real Name="Y">16.917078782269243</Real>
+        <Real Name="Z">54.471796726210087</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-258.17278525101426</Real>
+        <Real Name="Y">-52.474226539225327</Real>
+        <Real Name="Z">177.98863222195598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">212.33232141998332</Real>
+        <Real Name="Y">26.343449337154581</Real>
+        <Real Name="Z">-198.8950448965407</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.904021731962786</Real>
+        <Real Name="Y">33.282805108697829</Real>
+        <Real Name="Z">-54.025979461637831</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-61.081198404041231</Real>
+        <Real Name="Y">-234.73650677244035</Real>
+        <Real Name="Z">8.4394244210208171</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.080375396927934</Real>
+        <Real Name="Y">75.226858199565513</Real>
+        <Real Name="Z">-10.682195846987611</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.677903991032991</Real>
+        <Real Name="Y">76.928222565088561</Real>
+        <Real Name="Z">216.8688219981475</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8618286157295192</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8618286157295192</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8618286157295192</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0012119308997011764</Real>
+        <Real Name="Y">0.58870229688625131</Real>
+        <Real Name="Z">0.24146344238868367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8541786097398401</Real>
+        <Real Name="Y">0.67512888710405727</Real>
+        <Real Name="Z">0.2816409109238196</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076792124892622424</Real>
+        <Real Name="Y">0.59690997038346949</Real>
+        <Real Name="Z">0.1833034323151356</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98214059710212387</Real>
+        <Real Name="Y">0.62897500899807934</Real>
+        <Real Name="Z">1.571599492617282</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97463510743855686</Real>
+        <Real Name="Y">0.63184920048872883</Real>
+        <Real Name="Z">1.6669814880261893</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94148050383468118</Real>
+        <Real Name="Y">0.71036823099245161</Real>
+        <Real Name="Z">1.5418636787078341</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3887120623087101</Real>
+        <Real Name="Y">0.44755825619994144</Real>
+        <Real Name="Z">1.180544427080725</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3382108854253327</Real>
+        <Real Name="Y">0.47834972625726607</Real>
+        <Real Name="Z">1.2558028811247888</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3256123438753271</Real>
+        <Real Name="Y">0.3987408133844354</Real>
+        <Real Name="Z">1.1276520721456089</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6489499902601774</Real>
+        <Real Name="Y">0.318313831662979</Real>
+        <Real Name="Z">0.2956726953105725</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7082821331660101</Real>
+        <Real Name="Y">0.34167515467224896</Real>
+        <Real Name="Z">0.22428457441179839</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.602328608732672</Real>
+        <Real Name="Y">0.24102491590704866</Real>
+        <Real Name="Z">0.26381066954730575</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7746047753442538</Real>
+        <Real Name="Y">0.39956404431806164</Real>
+        <Real Name="Z">0.020418491770239969</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7160150515866277</Real>
+        <Real Name="Y">0.40723725790528603</Real>
+        <Real Name="Z">1.8069431603040798</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7869677216436848</Real>
+        <Real Name="Y">0.48959662446551611</Real>
+        <Real Name="Z">0.050478606054608896</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.2183256172080062</Real>
+        <Real Name="Y">-0.61212259486647358</Real>
+        <Real Name="Z">-0.3418878576406863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.36598463154664085</Real>
+        <Real Name="Y">-1.4358446684119333</Real>
+        <Real Name="Z">1.6194869463635053</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4109486364720034</Real>
+        <Real Name="Y">-0.86410888688476062</Real>
+        <Real Name="Z">2.8895987556398222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44242482756867396</Real>
+        <Real Name="Y">-0.10459959976108849</Real>
+        <Real Name="Z">0.17602547072308894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6441804295498847</Real>
+        <Real Name="Y">0.85901501736735841</Real>
+        <Real Name="Z">0.2540231885805892</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6905678071341015</Real>
+        <Real Name="Y">0.46371562525754978</Real>
+        <Real Name="Z">-0.0072491165301504998</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.557950209570792</Real>
+        <Real Name="Y">0.02462943683548198</Real>
+        <Real Name="Z">0.39378838046470038</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.61743763436921584</Real>
+        <Real Name="Y">0.21256966297124308</Real>
+        <Real Name="Z">1.1185250889850873</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.9627906247772573</Real>
+        <Real Name="Y">-1.8188638680846387</Real>
+        <Real Name="Z">2.5025128680525146</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24529557728621521</Real>
+        <Real Name="Y">0.32420946120512389</Real>
+        <Real Name="Z">-0.42158615880360101</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39679871128971855</Real>
+        <Real Name="Y">1.3125593753943385</Real>
+        <Real Name="Z">0.019398123284602886</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.81813789558287808</Real>
+        <Real Name="Y">0.33513060837416642</Real>
+        <Real Name="Z">-1.3036369326334094</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20875585165738766</Real>
+        <Real Name="Y">0.40662802706382056</Real>
+        <Real Name="Z">-0.26819584154094295</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53632226178674358</Real>
+        <Real Name="Y">-0.020440971218640667</Real>
+        <Real Name="Z">-0.89895434840427391</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7985377891675718</Real>
+        <Real Name="Y">0.34129544571997783</Real>
+        <Real Name="Z">1.1370682393154505</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-76.644468462490693</Real>
+        <Real Name="Y">73.39649774815544</Real>
+        <Real Name="Z">-360.02662649112074</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.7509669043584069</Real>
+        <Real Name="Y">-1.1252431270135759</Real>
+        <Real Name="Z">111.71889452272526</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">133.53103793789975</Real>
+        <Real Name="Y">-2.8572855864690752</Real>
+        <Real Name="Z">131.26402263428002</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">24.1743950623339</Real>
+        <Real Name="Y">-24.235255615191143</Real>
+        <Real Name="Z">-37.464702329239501</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.8224744659025873</Real>
+        <Real Name="Y">7.3016943236409801</Real>
+        <Real Name="Z">14.333258320986481</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.4376149809258578</Real>
+        <Real Name="Y">13.103748132684238</Real>
+        <Real Name="Z">11.721836555169418</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.83456084376931</Real>
+        <Real Name="Y">-3.5245968557444272</Real>
+        <Real Name="Z">-32.177553712421883</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.518026169375901</Real>
+        <Real Name="Y">8.8011497256973357</Real>
+        <Real Name="Z">-18.447460449657314</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.312045302185602</Real>
+        <Real Name="Y">4.215317330688471</Real>
+        <Real Name="Z">18.152194650492461</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-317.63408680048906</Real>
+        <Real Name="Y">-134.95461548416796</Real>
+        <Real Name="Z">279.47268304625266</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">245.42803977792724</Real>
+        <Real Name="Y">104.13445945651257</Real>
+        <Real Name="Z">-285.95538387334699</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">119.2942198874147</Real>
+        <Real Name="Y">61.682591042041182</Real>
+        <Real Name="Z">-65.258005831813108</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.858934316837747</Real>
+        <Real Name="Y">-324.58040578217475</Real>
+        <Real Name="Z">-37.439979441925516</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.965352825962142</Real>
+        <Real Name="Y">57.68197894135173</Real>
+        <Real Name="Z">25.992959687074091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.750922741458112</Real>
+        <Real Name="Y">160.95996574998907</Real>
+        <Real Name="Z">244.1138627125448</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 2">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98715
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4695777870702642</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4695777870702642</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4695777870702642</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4695777870702642</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.435455098231774</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.435455098231774</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.435455098231774</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.435455098231774</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4533416426810541</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4533416426810541</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4596894045835151</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4596894045835151</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4663464793233256</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4663464793233256</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4663464793233256</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4663464793233256</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.53844318588936</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">30.683519558832479</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.543720439030917</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.539240777671175</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">29.539146146270891</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">25.74892237193059</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">25.749619568373191</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">25.750536259365717</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">25.751645599784069</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">19.956799010370784</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">19.911406069531967</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">20.056781102143354</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">19.917538779575747</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">29.552732453441216</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">29.551974776629272</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">29.550963314003305</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">29.587073039260723</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">39.264244280014964</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">37.886750054748433</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">36.607657197635007</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">36.57480622309896</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">36.643203619473383</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">34.24509315057287</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.474178806496198</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">34.767726988596053</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.127438690183524</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">37.550316925031886</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">39.283389409558097</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">40.907435076290128</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">42.533781362268577</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">42.002405023756197</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">43.007905327762657</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">44.086026771059622</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">45.175706706298449</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.4290403927877016</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.2897466554758381</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.2613753422995337</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.3298673700742398</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.8718073885231874</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.100195848003912</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.392827339111241</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.75142970028036</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.367771008747678</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.103707443351269</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-22.881573450540717</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.647162059086774</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-14.27102455637193</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-15.277282537190331</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-16.356415443113264</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-17.409985653094672</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.55872268486508581</Real>
+        <Real Name="Y">-0.1954372884884242</Real>
+        <Real Name="Z">-0.12331658054675539</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5561630812121041</Real>
+        <Real Name="Y">0.1502581233870332</Real>
+        <Real Name="Z">-0.44761547196159901</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2265097662633464</Real>
+        <Real Name="Y">-1.1768262519621135</Real>
+        <Real Name="Z">-1.2616929856512602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10263626685285894</Real>
+        <Real Name="Y">0.57441118855119189</Real>
+        <Real Name="Z">0.005375904919935586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.35939325012836826</Real>
+        <Real Name="Y">0.13708618830230673</Real>
+        <Real Name="Z">-0.18874701506105859</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.676875181418428</Real>
+        <Real Name="Y">2.202437016478954</Real>
+        <Real Name="Z">0.65929093056192956</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22450558096959172</Real>
+        <Real Name="Y">0.27064569302711877</Real>
+        <Real Name="Z">0.3868191000888086</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.18295630274175456</Real>
+        <Real Name="Y">3.1066574874243527</Real>
+        <Real Name="Z">-0.46533684155430372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.43479618283021731</Real>
+        <Real Name="Y">-1.4385606453027826</Real>
+        <Real Name="Z">0.83013591007662091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11927480032898595</Real>
+        <Real Name="Y">-0.50285081385011732</Real>
+        <Real Name="Z">0.091729524538884569</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67581188225624333</Real>
+        <Real Name="Y">-0.055776720974020769</Real>
+        <Real Name="Z">0.61588372964499161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2213254303381311</Real>
+        <Real Name="Y">-1.9672700978846431</Real>
+        <Real Name="Z">0.44974949833150613</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.90469603789517505</Real>
+        <Real Name="Y">-0.20098861393275941</Real>
+        <Real Name="Z">-0.24253246946049692</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.84380910241735319</Real>
+        <Real Name="Y">0.72263550705740742</Real>
+        <Real Name="Z">-1.8704269945047447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39637402078760992</Real>
+        <Real Name="Y">-0.82004058352348863</Real>
+        <Real Name="Z">-0.19538443781690279</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8600577214745744</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8600577214745744</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8600577214745744</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0035440650850274138</Real>
+        <Real Name="Y">0.60159875632032089</Real>
+        <Real Name="Z">0.24000494429034802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.010168465943343688</Real>
+        <Real Name="Y">0.68597644521019763</Real>
+        <Real Name="Z">0.28471334764890233</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.06751863617706555</Real>
+        <Real Name="Y">0.60697062957978409</Real>
+        <Real Name="Z">0.16900694691525514</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9723522037222464</Real>
+        <Real Name="Y">0.6315058582476365</Real>
+        <Real Name="Z">1.5667045589559458</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96173371105130623</Real>
+        <Real Name="Y">0.60971263048449742</Real>
+        <Real Name="Z">1.6593038096929833</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90070297936228139</Real>
+        <Real Name="Y">0.69214464183838964</Real>
+        <Real Name="Z">1.5479523597982785</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3952575702290542</Real>
+        <Real Name="Y">0.4438905778520712</Real>
+        <Real Name="Z">1.1703659406908198</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3273377576351837</Real>
+        <Real Name="Y">0.45524157160856737</Real>
+        <Real Name="Z">1.2368518218833944</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3480914743350965</Real>
+        <Real Name="Y">0.41347818067194259</Real>
+        <Real Name="Z">1.0928239269442079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.643315941282891</Real>
+        <Real Name="Y">0.31463923778186692</Real>
+        <Real Name="Z">0.30253600907398875</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6980146139577059</Real>
+        <Real Name="Y">0.32680795675174573</Real>
+        <Real Name="Z">0.22493255627551403</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5942141398991361</Real>
+        <Real Name="Y">0.23437844086454407</Real>
+        <Real Name="Z">0.28494237445614834</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7754595115710718</Real>
+        <Real Name="Y">0.39272241170113165</Real>
+        <Real Name="Z">0.029220602505195346</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7114140721274667</Real>
+        <Real Name="Y">0.41859673080834486</Real>
+        <Real Name="Z">1.8230135543264059</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8353933317840254</Real>
+        <Real Name="Y">0.46713131512053202</Real>
+        <Real Name="Z">0.035014624131273264</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.1399985837713045</Real>
+        <Real Name="Y">0.38253845797611014</Real>
+        <Real Name="Z">-0.53779305046354797</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.93967238233494</Real>
+        <Real Name="Y">-1.2773261465721077</Real>
+        <Real Name="Z">2.3699801850296698</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3824096816723155</Real>
+        <Real Name="Y">-0.53853884701245269</Real>
+        <Real Name="Z">1.582940807464694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20197833632454329</Real>
+        <Real Name="Y">0.15117332743678702</Real>
+        <Real Name="Z">-0.09168807252641123</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4960066885797823</Real>
+        <Real Name="Y">-0.57126304805532513</Real>
+        <Real Name="Z">-0.048606916266380161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.6691441290311348</Real>
+        <Real Name="Y">-1.1321030199206739</Real>
+        <Real Name="Z">1.2174075506166606</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.056648109560851694</Real>
+        <Real Name="Y">-0.33177004337627702</Real>
+        <Real Name="Z">-0.29871924348750456</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.19087894070881078</Real>
+        <Real Name="Y">-2.5765358043367166</Real>
+        <Real Name="Z">0.37920248380985189</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.16458893557995807</Real>
+        <Real Name="Y">-2.0793739931041522</Real>
+        <Real Name="Z">0.23031609966901523</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0054690543037552893</Real>
+        <Real Name="Y">0.23379969388994082</Real>
+        <Real Name="Z">0.093861862316740527</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.5032754831095293</Real>
+        <Real Name="Y">0.25227079741765301</Real>
+        <Real Name="Z">-0.26432595803324055</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21077742295725976</Real>
+        <Real Name="Y">-0.0025241549058458712</Real>
+        <Real Name="Z">0.58920283647882365</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.088729453297768712</Real>
+        <Real Name="Y">0.11622917995067455</Real>
+        <Real Name="Z">0.51681448058715174</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45101456302687082</Real>
+        <Real Name="Y">0.52527424242705989</Real>
+        <Real Name="Z">0.15039302559180809</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.985759218663889</Real>
+        <Real Name="Y">-1.36098981925708</Real>
+        <Real Name="Z">-1.166635250508768</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">115.53960240451966</Real>
+        <Real Name="Y">83.828228704908128</Real>
+        <Real Name="Z">-322.37330617460157</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-29.995090342748711</Real>
+        <Real Name="Y">-17.473359456624706</Real>
+        <Real Name="Z">88.933550203716663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">63.888802078333711</Real>
+        <Real Name="Y">78.349367568003061</Real>
+        <Real Name="Z">218.46423781058883</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">13.004353382780437</Real>
+        <Real Name="Y">-21.724378417142731</Real>
+        <Real Name="Z">-33.33032288032399</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.011558304990025</Real>
+        <Real Name="Y">-6.9872798041538182</Real>
+        <Real Name="Z">-24.698130127410572</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6996274661389847</Real>
+        <Real Name="Y">9.5651985977686884</Real>
+        <Real Name="Z">10.651393667926968</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.590176715978245</Real>
+        <Real Name="Y">-14.000553065018018</Real>
+        <Real Name="Z">-31.315334090184358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.577615785844038</Real>
+        <Real Name="Y">13.430471002726627</Real>
+        <Real Name="Z">25.068718312210571</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.328845151765677</Real>
+        <Real Name="Y">19.716541685819255</Real>
+        <Real Name="Z">53.623675117781382</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-294.95747816208177</Real>
+        <Real Name="Y">-159.7181090957526</Real>
+        <Real Name="Z">316.04696322732661</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.06131107183108</Real>
+        <Real Name="Y">157.72078750771828</Real>
+        <Real Name="Z">-334.16329694888964</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">105.66471463471596</Real>
+        <Real Name="Y">69.093162497496536</Real>
+        <Real Name="Z">-72.495180201990166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-69.989771619957139</Real>
+        <Real Name="Y">-327.41756170994336</Real>
+        <Real Name="Z">-21.004397324498939</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-16.965294706144832</Real>
+        <Real Name="Y">78.653042708466316</Real>
+        <Real Name="Z">-5.0756745893235689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-109.24679535846798</Real>
+        <Real Name="Y">36.964441275728461</Real>
+        <Real Name="Z">131.6671039976718</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8630291796586993</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8630291796586993</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8630291796586993</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.013331170755786107</Real>
+        <Real Name="Y">0.59768004518412965</Real>
+        <Real Name="Z">0.23989246134237674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0053255283760643346</Real>
+        <Real Name="Y">0.68541884784449125</Real>
+        <Real Name="Z">0.27731078035611323</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.058500782745805877</Real>
+        <Real Name="Y">0.61114949909246186</Real>
+        <Real Name="Z">0.15658220768724734</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97706694640451763</Real>
+        <Real Name="Y">0.64056082204840226</Real>
+        <Real Name="Z">1.5692768134987369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94787896335617594</Real>
+        <Real Name="Y">0.61657138584615978</Real>
+        <Real Name="Z">1.6572250198264844</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94544720786694969</Real>
+        <Real Name="Y">0.73008060009954789</Real>
+        <Real Name="Z">1.5570817377511574</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.393893612973599</Real>
+        <Real Name="Y">0.45179156508163282</Real>
+        <Real Name="Z">1.1809808226816072</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3393958690950361</Real>
+        <Real Name="Y">0.51891026620785508</Real>
+        <Real Name="Z">1.2220587275852777</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3372103311733876</Real>
+        <Real Name="Y">0.41197020304224025</Real>
+        <Real Name="Z">1.1149234000125003</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.647617534459459</Real>
+        <Real Name="Y">0.30465949665815334</Real>
+        <Real Name="Z">0.30283687025242223</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7115802150916537</Real>
+        <Real Name="Y">0.33648141267227305</Real>
+        <Real Name="Z">0.23913083013428338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6390230425871561</Real>
+        <Real Name="Y">0.2112823436058715</Real>
+        <Real Name="Z">0.2836233230185714</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7640210170290154</Real>
+        <Real Name="Y">0.38783008267317132</Real>
+        <Real Name="Z">0.020920342278675414</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7281662145138406</Real>
+        <Real Name="Y">0.42682827380900606</Real>
+        <Real Name="Z">1.804225669642529</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8119209466214929</Real>
+        <Real Name="Y">0.45917191091262488</Real>
+        <Real Name="Z">0.06308974692810948</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.50736704590548876</Real>
+        <Real Name="Y">-0.14407333674159079</Real>
+        <Real Name="Z">-0.4084122884356633</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1777640092453587</Real>
+        <Real Name="Y">-0.80471549752946958</Real>
+        <Real Name="Z">1.3366268560519223</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8677376525592222</Real>
+        <Real Name="Y">1.0278046791527093</Real>
+        <Real Name="Z">0.49438765611902169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10010707897629689</Real>
+        <Real Name="Y">0.59762618424816949</Real>
+        <Real Name="Z">-0.072790390899174481</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.13768233722108281</Real>
+        <Real Name="Y">0.013901941844024813</Real>
+        <Real Name="Z">-0.30835431774099231</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9231066078116887</Real>
+        <Real Name="Y">1.450640407545408</Real>
+        <Real Name="Z">1.2268240364843086</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24565723963284175</Real>
+        <Real Name="Y">0.30480595251650489</Real>
+        <Real Name="Z">0.40501032499995143</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.78425273261657713</Real>
+        <Real Name="Y">2.1660216901130624</Real>
+        <Real Name="Z">-1.1839180095399209</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1065027337085374</Real>
+        <Real Name="Y">-0.96798077343993327</Real>
+        <Real Name="Z">1.8767024594453365</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.12051410913059526</Real>
+        <Real Name="Y">-0.58212120222983466</Real>
+        <Real Name="Z">0.011117871538848075</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.085129676106596414</Real>
+        <Real Name="Y">1.0060300550625918</Real>
+        <Real Name="Z">0.57531977945588775</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.911596862317344</Real>
+        <Real Name="Y">-0.91851236524577051</Real>
+        <Real Name="Z">0.1909642940877484</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.9455588597789929</Real>
+        <Real Name="Y">-0.33935351290643723</Real>
+        <Real Name="Z">-0.25611785804213416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3155841549360072</Real>
+        <Real Name="Y">0.80946424484949875</Real>
+        <Real Name="Z">-0.75296698320492084</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2981797430134825</Real>
+        <Real Name="Y">-1.1936099654255641</Real>
+        <Real Name="Z">1.6425141673397996</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-31.203992749955034</Real>
+        <Real Name="Y">-164.60262180469812</Real>
+        <Real Name="Z">-390.93823242341273</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-14.042104759911901</Real>
+        <Real Name="Y">40.13236898501593</Real>
+        <Real Name="Z">99.201885022547046</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">142.33273858178268</Real>
+        <Real Name="Y">174.20102071234228</Real>
+        <Real Name="Z">160.89182157582721</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">13.031618962860378</Real>
+        <Real Name="Y">-4.0822402491075849</Real>
+        <Real Name="Z">-39.267183731299269</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.176977538985426</Real>
+        <Real Name="Y">-0.31417713279510551</Real>
+        <Real Name="Z">13.286344163663209</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-6.3335163321453152</Real>
+        <Real Name="Y">5.3133812532128601</Real>
+        <Real Name="Z">15.039297251535793</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">35.697655780073646</Real>
+        <Real Name="Y">-8.7159511667717311</Real>
+        <Real Name="Z">-31.015621753503581</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.293136833613026</Real>
+        <Real Name="Y">2.1324206478671073</Real>
+        <Real Name="Z">25.112545149872474</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-12.925644038190264</Real>
+        <Real Name="Y">5.6665666475944541</Real>
+        <Real Name="Z">16.844618919731374</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-210.54789267356514</Real>
+        <Real Name="Y">-89.487000603792922</Real>
+        <Real Name="Z">296.91127366630707</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">102.73234119330137</Real>
+        <Real Name="Y">40.615577749310063</Real>
+        <Real Name="Z">-277.1447991117376</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.847652763168213</Real>
+        <Real Name="Y">73.312559654165923</Real>
+        <Real Name="Z">-101.62872102549142</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">24.088456394890613</Real>
+        <Real Name="Y">-177.29492989776503</Real>
+        <Real Name="Z">53.93454635191415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-39.511637762305867</Real>
+        <Real Name="Y">22.477863035748157</Real>
+        <Real Name="Z">-5.0160270353654823</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-47.695560987404974</Real>
+        <Real Name="Y">80.645162169673711</Real>
+        <Real Name="Z">163.78825297941182</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 3">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98716
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.435455098231774</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.435455098231774</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.435455098231774</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.435455098231774</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4695777870702642</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4695777870702642</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4695777870702642</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4695777870702642</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4695777870702642</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4695777870702642</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4663464793233256</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4663464793233256</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4596894045835151</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4596894045835151</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4596894045835151</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4596894045835151</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">25.771154963006502</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">26.44018057419839</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">25.788461160928172</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">25.748248990566118</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">25.748472756882975</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">29.53913399319762</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.539164233518971</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.539226620137516</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.539291670256262</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">29.539323735627949</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">29.552512449526425</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">29.347405272575799</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">29.555535194715802</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">19.914558756726002</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">19.909279657315373</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">19.904344438924458</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">19.900338327883503</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">35.343549230704284</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">34.648984837420926</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">33.984776666927829</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">33.979105327938441</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">34.07987565859996</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">36.807946964667927</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">37.068793009403109</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">37.425822601259952</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.879210658747894</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">38.428982678276419</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">39.074692500368556</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">40.031642487905543</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">41.080454649556629</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">44.266248816541122</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">45.887590972515092</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">47.339488021522421</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">48.565730773027298</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5844408731034427</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5719521158805616</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6064929472532299</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.7070395115978929</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.4946228683420575</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-9.7554386727558882</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.112405877994183</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.565728885363381</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.115468839520217</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.761220050078023</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-12.505589201386691</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-13.346271440897771</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.382609536209063</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-28.009230791593662</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.466063058991907</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.696311921537738</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.19787174590441542</Real>
+        <Real Name="Y">0.1615613889385647</Real>
+        <Real Name="Z">-0.38305665212567802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.7420087544145497</Real>
+        <Real Name="Y">0.75918088595013389</Real>
+        <Real Name="Z">1.2435674032029085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3711369223715755</Real>
+        <Real Name="Y">-0.19170785514288644</Real>
+        <Real Name="Z">0.42562796639667022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19638315205483492</Real>
+        <Real Name="Y">0.14565315135227885</Real>
+        <Real Name="Z">-0.067967185842621486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3802138136646303</Real>
+        <Real Name="Y">-0.58427055558605701</Real>
+        <Real Name="Z">0.23045735337154905</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.9488788834227251</Real>
+        <Real Name="Y">-0.88425910185951861</Real>
+        <Real Name="Z">0.94602094518641222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.023704545495134583</Real>
+        <Real Name="Y">-0.3413031917315365</Real>
+        <Real Name="Z">-0.30920684408559601</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.57458809086462592</Real>
+        <Real Name="Y">-2.6639579923405159</Real>
+        <Real Name="Z">0.20924282970686953</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10717835653133569</Real>
+        <Real Name="Y">-2.1491056124634227</Real>
+        <Real Name="Z">0.10532829628877118</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.012944992862387334</Real>
+        <Real Name="Y">0.24702752779615819</Real>
+        <Real Name="Z">0.1198190834623393</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53415108976374859</Real>
+        <Real Name="Y">-0.39551860957653251</Real>
+        <Real Name="Z">-0.44767485391309769</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23060498264262888</Real>
+        <Real Name="Y">0.091415864029443031</Real>
+        <Real Name="Z">1.125773624901474</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.064052506287219743</Real>
+        <Real Name="Y">0.1556142409020734</Real>
+        <Real Name="Z">0.5494680052322487</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53148313148554538</Real>
+        <Real Name="Y">0.53815672969841799</Real>
+        <Real Name="Z">0.03164652949451436</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.0632897927011018</Real>
+        <Real Name="Y">-0.36976385613194229</Real>
+        <Real Name="Z">-2.4264951267859698</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8633394536885388</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8633394536885388</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8633394536885388</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0092421217970196888</Real>
+        <Real Name="Y">0.59902768197113154</Real>
+        <Real Name="Z">0.24261344488908493</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8582574023553262</Real>
+        <Real Name="Y">0.6895853061974887</Real>
+        <Real Name="Z">0.27011713843399987</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.048511618384160765</Real>
+        <Real Name="Y">0.60629300268246844</Real>
+        <Real Name="Z">0.15562240999034666</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97643614979287485</Real>
+        <Real Name="Y">0.63597673745978855</Real>
+        <Real Name="Z">1.5699893858296883</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94955827760614131</Real>
+        <Real Name="Y">0.61630154249305813</Real>
+        <Real Name="Z">1.6597266974104044</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.93061948170641062</Real>
+        <Real Name="Y">0.71722041262396996</Real>
+        <Real Name="Z">1.5484808626058242</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3960554424926559</Real>
+        <Real Name="Y">0.4495142225923297</Real>
+        <Real Name="Z">1.1779605077197686</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3340693114029034</Real>
+        <Real Name="Y">0.49982056570267391</Real>
+        <Real Name="Z">1.2307744244026666</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3451760776129116</Real>
+        <Real Name="Y">0.42073545899918796</Real>
+        <Real Name="Z">1.1021621476089876</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6470069257696351</Real>
+        <Real Name="Y">0.30918211391515005</Real>
+        <Real Name="Z">0.30272178605288846</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7100685398397772</Real>
+        <Real Name="Y">0.32998848349025622</Real>
+        <Real Name="Z">0.23378234729703359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6166790290489528</Real>
+        <Real Name="Y">0.22087321021381645</Real>
+        <Real Name="Z">0.28164870826230615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7718822059681083</Real>
+        <Real Name="Y">0.39039535236321471</Real>
+        <Real Name="Z">0.023003848260178143</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7185817566657042</Real>
+        <Real Name="Y">0.42084790907076353</Real>
+        <Real Name="Z">1.8128992940642403</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8190251967613977</Real>
+        <Real Name="Y">0.46834619744003492</Real>
+        <Real Name="Z">0.052389602816988415</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.51909606583072954</Real>
+        <Real Name="Y">-0.16868557594645678</Real>
+        <Real Name="Z">-0.25152349782220706</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.427018828152782</Real>
+        <Real Name="Y">-0.20452463084253492</Real>
+        <Real Name="Z">0.36116661791768301</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37975248104801912</Real>
+        <Real Name="Y">0.019630126127879063</Real>
+        <Real Name="Z">-0.29902662793325907</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.098129441548187049</Real>
+        <Real Name="Y">0.57260914102066551</Real>
+        <Real Name="Z">-0.034582509352709311</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25189799152272641</Real>
+        <Real Name="Y">0.084750951318456391</Real>
+        <Real Name="Z">-0.24413279791056303</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7987911700093517</Real>
+        <Real Name="Y">1.8247445036904346</Real>
+        <Real Name="Z">0.94634351398648009</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23430016614323884</Real>
+        <Real Name="Y">0.28010351474549577</Real>
+        <Real Name="Z">0.39519763789115298</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.54857699567891827</Real>
+        <Real Name="Y">2.6670989542696173</Real>
+        <Real Name="Z">-0.88437994531100805</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.7765779540910559</Real>
+        <Real Name="Y">-1.2169336901159915</Real>
+        <Real Name="Z">1.3053994246432843</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10299143551909934</Real>
+        <Real Name="Y">-0.52866022307489036</Real>
+        <Real Name="Z">0.038667261683557441</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.5428704776522324</Real>
+        <Real Name="Y">0.52248163703262462</Real>
+        <Real Name="Z">0.74524547744073655</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.6598886710899037</Real>
+        <Real Name="Y">-1.5167224706397677</Real>
+        <Real Name="Z">0.31926302532388906</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93418964242218583</Real>
+        <Real Name="Y">-0.27054373573615403</Real>
+        <Real Name="Z">-0.25782565980294919</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1130310907586674</Real>
+        <Real Name="Y">0.7007105380090628</Real>
+        <Real Name="Z">-1.3844315691095792</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.32627828568172751</Real>
+        <Real Name="Y">-1.05310004808182</Real>
+        <Real Name="Z">0.88157891110117015</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">15.821547349479715</Real>
+        <Real Name="Y">-60.161201174672243</Real>
+        <Real Name="Z">-385.48962364239185</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.160360111588055</Real>
+        <Real Name="Y">21.800271789631523</Real>
+        <Real Name="Z">103.78343500257321</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">143.10851445289711</Real>
+        <Real Name="Y">170.89111169422316</Real>
+        <Real Name="Z">222.70973992516744</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.439832699059565</Real>
+        <Real Name="Y">-8.4087706466486694</Real>
+        <Real Name="Z">-39.720046522872579</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.555000422469213</Real>
+        <Real Name="Y">-12.030102681399889</Real>
+        <Real Name="Z">-23.741375973022272</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.4157720621976537</Real>
+        <Real Name="Y">6.7338226726064612</Real>
+        <Real Name="Z">14.456940195941606</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.585539515058372</Real>
+        <Real Name="Y">-9.2364887431082181</Real>
+        <Real Name="Z">-32.537332276521056</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.253018145111575</Real>
+        <Real Name="Y">5.0463676615103985</Real>
+        <Real Name="Z">27.2548780988988</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.911582429277928</Real>
+        <Real Name="Y">17.895171737039917</Real>
+        <Real Name="Z">54.286936477575502</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-255.79800233755509</Real>
+        <Real Name="Y">-97.596892037142752</Real>
+        <Real Name="Z">269.77609343575551</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">161.74377161822778</Real>
+        <Real Name="Y">75.478109391660638</Real>
+        <Real Name="Z">-289.42480190955263</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.671306708564373</Real>
+        <Real Name="Y">63.365894194720624</Real>
+        <Real Name="Z">-79.672724818795047</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-3.1925702206851838</Real>
+        <Real Name="Y">-171.12346871486892</Real>
+        <Real Name="Z">51.520362736515438</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-38.75012429427786</Real>
+        <Real Name="Y">27.281903704539161</Real>
+        <Real Name="Z">-17.705159465172159</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-98.44408316506275</Real>
+        <Real Name="Y">-29.935728848091202</Real>
+        <Real Name="Z">124.50267873590019</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8623896334062764</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8623896334062764</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8623896334062764</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070135377049909235</Real>
+        <Real Name="Y">0.60003451393963447</Real>
+        <Real Name="Z">0.23230985612584176</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0042681776666629598</Real>
+        <Real Name="Y">0.67762151100590529</Real>
+        <Real Name="Z">0.28830127765180469</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.082054501703369975</Real>
+        <Real Name="Y">0.61464895047680945</Real>
+        <Real Name="Z">0.17471132865426053</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97359114469318286</Real>
+        <Real Name="Y">0.63047772881570641</Real>
+        <Real Name="Z">1.5737368094544528</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94162153781951685</Real>
+        <Real Name="Y">0.57328829750394517</Real>
+        <Real Name="Z">1.6435195550480473</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90265307188194566</Real>
+        <Real Name="Y">0.69319632348228721</Real>
+        <Real Name="Z">1.5597194591743015</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3962160261509335</Real>
+        <Real Name="Y">0.44675286865528979</Real>
+        <Real Name="Z">1.163728450216559</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3340526977943394</Real>
+        <Real Name="Y">0.47042869393617848</Real>
+        <Real Name="Z">1.2325579083351481</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3419293529418648</Real>
+        <Real Name="Y">0.43272953410566778</Real>
+        <Real Name="Z">1.0861486745014881</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6418067601025155</Real>
+        <Real Name="Y">0.31899218641528898</Real>
+        <Real Name="Z">0.31236285321395135</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7045133167819357</Real>
+        <Real Name="Y">0.3498042640143782</Real>
+        <Real Name="Z">0.24693486208295296</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6263677435909218</Real>
+        <Real Name="Y">0.22733146587707909</Real>
+        <Real Name="Z">0.28950968101465785</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7800719807193612</Real>
+        <Real Name="Y">0.39105229386845147</Real>
+        <Real Name="Z">0.024231872573953331</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6910142606513414</Real>
+        <Real Name="Y">0.42138224941025215</Real>
+        <Real Name="Z">0.0065928620257875714</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8164844256598189</Real>
+        <Real Name="Y">0.4567421296405289</Real>
+        <Real Name="Z">0.083572396077671279</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.16438075401180441</Real>
+        <Real Name="Y">0.084155577979260876</Real>
+        <Real Name="Z">-0.9415965086843604</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.6833522275480336</Real>
+        <Real Name="Y">-1.9596891580931062</Real>
+        <Real Name="Z">2.0348122979517052</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5617331578138627</Real>
+        <Real Name="Y">0.20735639041955894</Real>
+        <Real Name="Z">2.0835362660933208</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11250582102647881</Real>
+        <Real Name="Y">-0.052008331428465358</Real>
+        <Real Name="Z">0.28469964105622314</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2296104343588832</Real>
+        <Real Name="Y">-2.4603836143016857</Real>
+        <Real Name="Z">-1.6735639589409042</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.74584229102939192</Real>
+        <Real Name="Y">-0.54358317942013579</Real>
+        <Real Name="Z">1.23521219860686</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.073724889191719267</Real>
+        <Real Name="Y">-0.019993936554967992</Real>
+        <Real Name="Z">-0.64889764801779914</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42505542654653505</Real>
+        <Real Name="Y">-0.36484233812594502</Real>
+        <Real Name="Z">-0.07473802395704493</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.6616859654996492</Real>
+        <Real Name="Y">0.15869811142052989</Real>
+        <Real Name="Z">-0.27311451188474406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23825729299684198</Real>
+        <Real Name="Y">0.34428081835616003</Real>
+        <Real Name="Z">0.57936711621700532</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31695033977569093</Real>
+        <Real Name="Y">1.4150905239634533</Real>
+        <Real Name="Z">1.5967309452876832</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2657996596757486</Real>
+        <Real Name="Y">-0.15387777880665038</Real>
+        <Real Name="Z">0.74253291844636915</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.032040242999693762</Real>
+        <Real Name="Y">0.047539172663978391</Real>
+        <Real Name="Z">0.014054101966723071</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.64694958073796804</Real>
+        <Real Name="Y">-0.33649111244206592</Real>
+        <Real Name="Z">2.5782491170934492</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.34882708432435666</Real>
+        <Real Name="Y">-2.3743120036166392</Real>
+        <Real Name="Z">3.0574313777089182</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-164.18515372439015</Real>
+        <Real Name="Y">-312.61526488530467</Real>
+        <Real Name="Z">-380.59396457022808</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.023439100042218</Real>
+        <Real Name="Y">67.037873751444423</Real>
+        <Real Name="Z">100.55710221730644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.25049877168354</Real>
+        <Real Name="Y">140.24801833187951</Real>
+        <Real Name="Z">74.049000298979152</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.248881450238073</Real>
+        <Real Name="Y">-15.065682688126834</Real>
+        <Real Name="Z">-36.613019444321296</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.841392215167723</Real>
+        <Real Name="Y">-7.1573684038301106</Real>
+        <Real Name="Z">-24.511464431177167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1940888404407417</Real>
+        <Real Name="Y">7.4197747312145275</Real>
+        <Real Name="Z">12.15230636867507</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.505549216701013</Real>
+        <Real Name="Y">-17.43959012006961</Real>
+        <Real Name="Z">-31.379190480671689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.641602793909229</Real>
+        <Real Name="Y">14.806093706656668</Real>
+        <Real Name="Z">25.29630178109371</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.760131247756846</Real>
+        <Real Name="Y">17.436772774155362</Real>
+        <Real Name="Z">55.055066206401364</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-182.71947354519756</Real>
+        <Real Name="Y">2.6001665575673201</Real>
+        <Real Name="Z">105.51746897225149</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">148.40180785492296</Real>
+        <Real Name="Y">-32.519882105148568</Real>
+        <Real Name="Z">-88.072283963127063</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.388900438151666</Real>
+        <Real Name="Y">10.393938599453975</Real>
+        <Real Name="Z">-49.919831898860394</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-53.991544521779417</Real>
+        <Real Name="Y">-310.60588148910574</Real>
+        <Real Name="Z">-19.608424658311719</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-18.861216973353727</Real>
+        <Real Name="Y">115.33576768113197</Real>
+        <Real Name="Z">0.1736162995748316</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.692742599920408</Real>
+        <Real Name="Y">320.12526355808177</Real>
+        <Real Name="Z">257.89731730241539</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_Crescale_4Ranks_1RanksPerSimulation_s.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_Crescale_4Ranks_1RanksPerSimulation_s.xml
new file mode 100644 (file)
index 0000000..e3a2b87
--- /dev/null
@@ -0,0 +1,3398 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.453341</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.453341</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.453341</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.453341</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4529777</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4529777</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4529777</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4529777</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4529777</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4529777</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4538531</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4538531</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4485378</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4485378</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4485378</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4485378</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">19.965948</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">20.842787</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">19.959951</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">19.959257</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">19.959888</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">18.412148</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">18.41218</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">18.412098</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">18.411869</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">18.372055</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">18.37104</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">18.731646</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">18.360758</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">25.690891</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">25.69235</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">25.69178</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">25.6931</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629332</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.229374</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">28.96793</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.73727</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">30.664171</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">31.494011</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">32.021095</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">32.695801</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">33.515129</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">34.420345</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">35.402973</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">36.127865</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">36.95499</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">36.268795</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">36.991394</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">37.792694</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">38.67234</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.160834</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.782228</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.552262</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.478531</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.231659</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.758711</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.433498</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.253057</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.198086</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.181296</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.287535</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.485548</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-13.245657</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-13.966798</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-14.768667</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-15.646994</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13823938</Real>
+        <Real Name="Y">-0.083000772</Real>
+        <Real Name="Z">-0.55156732</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807449</Real>
+        <Real Name="Y">0.12591785</Real>
+        <Real Name="Z">0.086322196</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50557399</Real>
+        <Real Name="Y">-0.26345637</Real>
+        <Real Name="Z">-0.37042341</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.080341451</Real>
+        <Real Name="Y">-0.036381256</Real>
+        <Real Name="Z">0.2694976</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0880266</Real>
+        <Real Name="Y">-2.6992292</Real>
+        <Real Name="Z">-0.41159731</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0053114</Real>
+        <Real Name="Y">-0.44618699</Real>
+        <Real Name="Z">1.1535</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046993218</Real>
+        <Real Name="Y">-0.027141469</Real>
+        <Real Name="Z">-0.68357778</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051991098</Real>
+        <Real Name="Y">-0.42392981</Real>
+        <Real Name="Z">-0.38236645</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25138494</Real>
+        <Real Name="Y">0.072344378</Real>
+        <Real Name="Z">-0.58373684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20046787</Real>
+        <Real Name="Y">0.39459831</Real>
+        <Real Name="Z">0.71750742</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21663746</Real>
+        <Real Name="Y">1.2108052</Real>
+        <Real Name="Z">0.86115432</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3770657</Real>
+        <Real Name="Y">-0.66109222</Real>
+        <Real Name="Z">0.87071204</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21701036</Real>
+        <Real Name="Y">-0.090551347</Real>
+        <Real Name="Z">-0.034703776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639677</Real>
+        <Real Name="Y">0.96361506</Real>
+        <Real Name="Z">2.5346279</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37429887</Real>
+        <Real Name="Y">-0.37906641</Real>
+        <Real Name="Z">0.73122346</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617444</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617444</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617444</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0031028555</Real>
+        <Real Name="Y">0.59400803</Real>
+        <Real Name="Z">0.2434254</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8500398</Real>
+        <Real Name="Y">0.68411571</Real>
+        <Real Name="Z">0.27212498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059129406</Real>
+        <Real Name="Y">0.60229921</Real>
+        <Real Name="Z">0.16625932</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97850257</Real>
+        <Real Name="Y">0.62985861</Real>
+        <Real Name="Z">1.5701584</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96189284</Real>
+        <Real Name="Y">0.62420964</Real>
+        <Real Name="Z">1.6642569</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9282189</Real>
+        <Real Name="Y">0.70607853</Real>
+        <Real Name="Z">1.5414462</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.392923</Real>
+        <Real Name="Y">0.44728038</Real>
+        <Real Name="Z">1.1772636</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3333709</Real>
+        <Real Name="Y">0.47707799</Real>
+        <Real Name="Z">1.2460239</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3353479</Real>
+        <Real Name="Y">0.41407943</Real>
+        <Real Name="Z">1.1083788</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6468627</Real>
+        <Real Name="Y">0.31567279</Real>
+        <Real Name="Z">0.29893827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7053905</Real>
+        <Real Name="Y">0.33268589</Real>
+        <Real Name="Z">0.22513184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5972198</Real>
+        <Real Name="Y">0.23811248</Real>
+        <Real Name="Z">0.27281755</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7761879</Real>
+        <Real Name="Y">0.39607728</Real>
+        <Real Name="Z">0.022669487</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7120098</Real>
+        <Real Name="Y">0.40950817</Real>
+        <Real Name="Z">1.8146781</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8060164</Real>
+        <Real Name="Y">0.4842132</Real>
+        <Real Name="Z">0.045133501</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.24509357</Real>
+        <Real Name="Y">-0.72268373</Real>
+        <Real Name="Z">-0.13607271</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.62220061</Real>
+        <Real Name="Y">-0.82376188</Real>
+        <Real Name="Z">0.65281832</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6720454</Real>
+        <Real Name="Y">-0.66547751</Real>
+        <Real Name="Z">1.2261419</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45931995</Real>
+        <Real Name="Y">-0.12490919</Real>
+        <Real Name="Z">0.16833009</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4889319</Real>
+        <Real Name="Y">1.0727507</Real>
+        <Real Name="Z">0.43549877</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5987371</Real>
+        <Real Name="Y">0.61209542</Real>
+        <Real Name="Z">0.097052917</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.50274026</Real>
+        <Real Name="Y">0.03985915</Real>
+        <Real Name="Z">0.41842917</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.54651636</Real>
+        <Real Name="Y">0.092769124</Real>
+        <Real Name="Z">1.3181231</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.5448405</Real>
+        <Real Name="Y">-2.0395298</Real>
+        <Real Name="Z">2.2285211</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26044866</Real>
+        <Real Name="Y">0.33388034</Real>
+        <Real Name="Z">-0.39618164</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.29245031</Real>
+        <Real Name="Y">0.85369658</Real>
+        <Real Name="Z">-0.25286898</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39089277</Real>
+        <Real Name="Y">0.41563565</Real>
+        <Real Name="Z">-0.8920905</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20275627</Real>
+        <Real Name="Y">0.47850367</Real>
+        <Real Name="Z">-0.29139045</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42791542</Real>
+        <Real Name="Y">-0.55594105</Real>
+        <Real Name="Z">-1.0860839</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8312243</Real>
+        <Real Name="Y">0.96398181</Real>
+        <Real Name="Z">0.032813128</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.1375885</Real>
+        <Real Name="Y">62.916016</Real>
+        <Real Name="Z">-372.66547</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.8895111</Real>
+        <Real Name="Y">0.97045135</Real>
+        <Real Name="Z">111.92515</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.4897</Real>
+        <Real Name="Y">62.029015</Real>
+        <Real Name="Z">206.36418</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.777412</Real>
+        <Real Name="Y">-19.119633</Real>
+        <Real Name="Z">-38.883125</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.649117</Real>
+        <Real Name="Y">-9.5547829</Real>
+        <Real Name="Z">-24.644249</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4826622</Real>
+        <Real Name="Y">10.638727</Real>
+        <Real Name="Z">12.94495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.637543</Real>
+        <Real Name="Y">-7.1136703</Real>
+        <Real Name="Z">-33.302345</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-57.139702</Real>
+        <Real Name="Y">11.200466</Real>
+        <Real Name="Z">-15.181343</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.714146</Real>
+        <Real Name="Y">18.994242</Real>
+        <Real Name="Z">56.605495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-309.77954</Real>
+        <Real Name="Y">-124.14948</Real>
+        <Real Name="Z">256.2095</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">237.24033</Real>
+        <Real Name="Y">108.17855</Real>
+        <Real Name="Z">-280.93631</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">114.1727</Real>
+        <Real Name="Y">55.657654</Real>
+        <Real Name="Z">-58.070877</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-58.066498</Real>
+        <Real Name="Y">-240.61044</Real>
+        <Real Name="Z">-2.2670898</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.1328812</Real>
+        <Real Name="Y">45.245335</Real>
+        <Real Name="Z">16.931473</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.89006</Real>
+        <Real Name="Y">24.717514</Real>
+        <Real Name="Z">164.97003</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8613173</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8613173</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8613173</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0034234915</Real>
+        <Real Name="Y">0.60625589</Real>
+        <Real Name="Z">0.23542252</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.024384495</Real>
+        <Real Name="Y">0.66660339</Real>
+        <Real Name="Z">0.30670458</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.084996372</Real>
+        <Real Name="Y">0.59825337</Real>
+        <Real Name="Z">0.18598427</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97140241</Real>
+        <Real Name="Y">0.63311422</Real>
+        <Real Name="Z">1.5669411</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97448301</Real>
+        <Real Name="Y">0.60590488</Real>
+        <Real Name="Z">1.6586608</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.88974994</Real>
+        <Real Name="Y">0.68247533</Real>
+        <Real Name="Z">1.5592817</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3954031</Real>
+        <Real Name="Y">0.44148287</Real>
+        <Real Name="Z">1.1688653</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3330592</Real>
+        <Real Name="Y">0.43661475</Real>
+        <Real Name="Z">1.241335</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3508385</Real>
+        <Real Name="Y">0.39838538</Real>
+        <Real Name="Z">1.0959344</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.644497</Real>
+        <Real Name="Y">0.31663144</Real>
+        <Real Name="Z">0.30343884</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6947677</Real>
+        <Real Name="Y">0.3329547</Real>
+        <Real Name="Z">0.22363454</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5988131</Real>
+        <Real Name="Y">0.23422146</Real>
+        <Real Name="Z">0.28658992</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7758292</Real>
+        <Real Name="Y">0.39339092</Real>
+        <Real Name="Z">0.03311919</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7156326</Real>
+        <Real Name="Y">0.42418382</Real>
+        <Real Name="Z">1.8266834</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8479329</Real>
+        <Real Name="Y">0.45632705</Real>
+        <Real Name="Z">0.031565394</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.10691666</Real>
+        <Real Name="Y">0.64458561</Real>
+        <Real Name="Z">-0.61769253</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.66399252</Real>
+        <Real Name="Y">-3.3806417</Real>
+        <Real Name="Z">2.825206</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8156087</Real>
+        <Real Name="Y">-1.6359835</Real>
+        <Real Name="Z">2.3968179</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19691311</Real>
+        <Real Name="Y">0.1422133</Real>
+        <Real Name="Z">-0.11296655</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5068347</Real>
+        <Real Name="Y">-0.48792741</Real>
+        <Real Name="Z">-0.33881676</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2730396</Real>
+        <Real Name="Y">-1.3637185</Real>
+        <Real Name="Z">1.3002032</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.13194188</Real>
+        <Real Name="Y">-0.34770077</Real>
+        <Real Name="Z">-0.27582645</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.88431811</Real>
+        <Real Name="Y">-2.15731</Real>
+        <Real Name="Z">0.51077694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22978118</Real>
+        <Real Name="Y">-1.7713649</Real>
+        <Real Name="Z">0.3271586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.013667684</Real>
+        <Real Name="Y">0.21464083</Real>
+        <Real Name="Z">0.082698204</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.5911029</Real>
+        <Real Name="Y">1.1242236</Real>
+        <Real Name="Z">-0.11993202</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.60254288</Real>
+        <Real Name="Y">-0.06759984</Real>
+        <Real Name="Z">-0.14737314</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11678199</Real>
+        <Real Name="Y">-0.010804798</Real>
+        <Real Name="Z">0.4621762</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31804037</Real>
+        <Real Name="Y">0.81327957</Real>
+        <Real Name="Z">0.44395703</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.0023874</Real>
+        <Real Name="Y">-1.2777282</Real>
+        <Real Name="Z">0.12881415</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">153.33714</Real>
+        <Real Name="Y">100.15289</Real>
+        <Real Name="Z">-279.8111</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-42.076443</Real>
+        <Real Name="Y">-32.723339</Real>
+        <Real Name="Z">77.474106</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.178719</Real>
+        <Real Name="Y">44.059288</Real>
+        <Real Name="Z">191.80267</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">9.883606</Real>
+        <Real Name="Y">-26.702541</Real>
+        <Real Name="Z">-24.927536</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.310581</Real>
+        <Real Name="Y">-5.4051933</Real>
+        <Real Name="Z">-27.115322</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">26.771576</Real>
+        <Real Name="Y">-8.8599224</Real>
+        <Real Name="Z">-23.414261</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.667847</Real>
+        <Real Name="Y">-17.088413</Real>
+        <Real Name="Z">-28.02375</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.513977</Real>
+        <Real Name="Y">17.401503</Real>
+        <Real Name="Z">-21.194881</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-67.136635</Real>
+        <Real Name="Y">41.532429</Real>
+        <Real Name="Z">83.338943</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-262.71118</Real>
+        <Real Name="Y">-175.09064</Real>
+        <Real Name="Z">380.66849</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">235.54523</Real>
+        <Real Name="Y">174.9463</Real>
+        <Real Name="Z">-390.71677</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">95.2827</Real>
+        <Real Name="Y">78.592537</Real>
+        <Real Name="Z">-89.22438</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-95.555557</Real>
+        <Real Name="Y">-431.39191</Real>
+        <Real Name="Z">6.7282104</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.233707</Real>
+        <Real Name="Y">112.92177</Real>
+        <Real Name="Z">39.010231</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.21729</Real>
+        <Real Name="Y">127.65524</Real>
+        <Real Name="Z">105.40535</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4529777</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4529777</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4529777</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4529777</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.453341</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.453341</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.453341</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.453341</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4354539</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4354539</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4485378</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4485378</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4538531</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4538531</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4538531</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4538531</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">18.40823</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">16.978479</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">18.413391</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">18.412031</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">18.412106</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">19.960245</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">19.96032</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">19.959902</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">19.958689</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">25.752682</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">25.657337</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">26.36541</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">25.690014</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">18.359735</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">18.358271</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">18.356688</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">18.355051</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">28.072332</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.396276</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.811417</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">30.888191</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">31.11618</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">31.74864</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">32.988998</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">34.378891</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.90593</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">35.555702</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">36.003342</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">35.780251</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">35.635574</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">38.246368</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">39.610687</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">41.026634</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">42.47007</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5675926</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.547822</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6259556</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8538694</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.562643</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.802927</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.193237</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.721489</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.178624</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.640215</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-12.082594</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-12.613314</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.777948</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.143732</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.561262</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.006334</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21190877</Real>
+        <Real Name="Y">-0.73113304</Real>
+        <Real Name="Z">0.011277338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.66796941</Real>
+        <Real Name="Y">-0.44908154</Real>
+        <Real Name="Z">-0.19935304</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.080868699</Real>
+        <Real Name="Y">-1.3642008</Real>
+        <Real Name="Z">0.095872603</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44769731</Real>
+        <Real Name="Y">-0.12958133</Real>
+        <Real Name="Z">0.17146564</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1259595</Real>
+        <Real Name="Y">1.2299777</Real>
+        <Real Name="Z">0.59934753</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4102879</Real>
+        <Real Name="Y">0.66582245</Real>
+        <Real Name="Z">0.10724045</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.42090845</Real>
+        <Real Name="Y">0.039798632</Real>
+        <Real Name="Z">0.42398912</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31489116</Real>
+        <Real Name="Y">0.033143241</Real>
+        <Real Name="Z">1.2373283</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7872748</Real>
+        <Real Name="Y">-2.0657148</Real>
+        <Real Name="Z">1.5960392</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26079154</Real>
+        <Real Name="Y">0.32045048</Real>
+        <Real Name="Z">-0.34788135</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.14831775</Real>
+        <Real Name="Y">0.34903857</Real>
+        <Real Name="Z">-0.43145278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019986875</Real>
+        <Real Name="Y">0.52854216</Real>
+        <Real Name="Z">-0.45931953</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15528721</Real>
+        <Real Name="Y">0.54477292</Real>
+        <Real Name="Z">-0.27405369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25908729</Real>
+        <Real Name="Y">-0.78199595</Real>
+        <Real Name="Z">-1.2374361</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93642789</Real>
+        <Real Name="Y">1.1511997</Real>
+        <Real Name="Z">-1.0669613</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617793</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617793</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617793</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059497543</Real>
+        <Real Name="Y">0.59954488</Real>
+        <Real Name="Z">0.23896244</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8573372</Real>
+        <Real Name="Y">0.68765825</Real>
+        <Real Name="Z">0.27488399</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062270876</Real>
+        <Real Name="Y">0.61130321</Real>
+        <Real Name="Z">0.16246414</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97412103</Real>
+        <Real Name="Y">0.63062483</Real>
+        <Real Name="Z">1.5709736</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94453794</Real>
+        <Real Name="Y">0.59358561</Real>
+        <Real Name="Z">1.6541317</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90865666</Real>
+        <Real Name="Y">0.69713449</Real>
+        <Real Name="Z">1.549685</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3962948</Real>
+        <Real Name="Y">0.44677001</Real>
+        <Real Name="Z">1.1685667</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3309122</Real>
+        <Real Name="Y">0.47336301</Real>
+        <Real Name="Z">1.2332217</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3460696</Real>
+        <Real Name="Y">0.43150869</Real>
+        <Real Name="Z">1.088524</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6431131</Real>
+        <Real Name="Y">0.31603196</Real>
+        <Real Name="Z">0.3073822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7025946</Real>
+        <Real Name="Y">0.33834401</Real>
+        <Real Name="Z">0.23578298</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6088128</Real>
+        <Real Name="Y">0.22975874</Real>
+        <Real Name="Z">0.2840856</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7789745</Real>
+        <Real Name="Y">0.39112881</Real>
+        <Real Name="Z">0.024530524</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6974078</Real>
+        <Real Name="Y">0.42091465</Real>
+        <Real Name="Z">1.8460358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8181432</Real>
+        <Real Name="Y">0.47051209</Real>
+        <Real Name="Z">0.060950611</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11296094</Real>
+        <Real Name="Y">-0.019806599</Real>
+        <Real Name="Z">-0.70917553</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4541276</Real>
+        <Real Name="Y">-0.56093162</Real>
+        <Real Name="Z">1.0797703</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0424843</Real>
+        <Real Name="Y">0.43996507</Real>
+        <Real Name="Z">0.74261123</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.096717834</Real>
+        <Real Name="Y">-0.036779247</Real>
+        <Real Name="Z">0.27524921</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63534278</Real>
+        <Real Name="Y">-2.6533635</Real>
+        <Real Name="Z">-1.0285971</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.85224974</Real>
+        <Real Name="Y">-0.4907068</Real>
+        <Real Name="Z">1.1448126</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.058483776</Real>
+        <Real Name="Y">-0.021639682</Real>
+        <Real Name="Z">-0.65760708</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22564432</Real>
+        <Real Name="Y">-0.40560782</Real>
+        <Real Name="Z">-0.20917745</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.45968539</Real>
+        <Real Name="Y">0.10623349</Real>
+        <Real Name="Z">-0.43173441</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21813509</Real>
+        <Real Name="Y">0.3704035</Real>
+        <Real Name="Z">0.64817208</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.013166312</Real>
+        <Real Name="Y">1.4088322</Real>
+        <Real Name="Z">1.132651</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8894093</Real>
+        <Real Name="Y">-0.49254641</Real>
+        <Real Name="Z">0.62959498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11267813</Real>
+        <Real Name="Y">-0.095850997</Real>
+        <Real Name="Z">-0.068547457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1881802</Real>
+        <Real Name="Y">0.5100888</Real>
+        <Real Name="Z">2.8806784</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11878823</Real>
+        <Real Name="Y">-0.97813362</Real>
+        <Real Name="Z">2.1845691</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-65.824158</Real>
+        <Real Name="Y">-107.78934</Real>
+        <Real Name="Z">-417.92514</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10830688</Real>
+        <Real Name="Y">34.996651</Real>
+        <Real Name="Z">108.98042</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">176.49156</Real>
+        <Real Name="Y">148.22162</Real>
+        <Real Name="Z">169.25069</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.768799</Real>
+        <Real Name="Y">-14.345158</Real>
+        <Real Name="Z">-37.687744</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.747303</Real>
+        <Real Name="Y">-8.0412951</Real>
+        <Real Name="Z">-23.767414</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3226509</Real>
+        <Real Name="Y">7.6881638</Real>
+        <Real Name="Z">12.800205</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.263962</Real>
+        <Real Name="Y">-14.270321</Real>
+        <Real Name="Z">-33.009651</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.512745</Real>
+        <Real Name="Y">12.051531</Real>
+        <Real Name="Z">27.192776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.944672</Real>
+        <Real Name="Y">16.917082</Real>
+        <Real Name="Z">54.471825</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-258.1723</Real>
+        <Real Name="Y">-52.474152</Real>
+        <Real Name="Z">177.98831</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">212.33189</Real>
+        <Real Name="Y">26.343239</Real>
+        <Real Name="Z">-198.89453</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.904053</Real>
+        <Real Name="Y">33.282768</Real>
+        <Real Name="Z">-54.025848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-61.080841</Real>
+        <Real Name="Y">-234.73648</Real>
+        <Real Name="Z">8.4395447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.080437</Real>
+        <Real Name="Y">75.227051</Real>
+        <Real Name="Z">-10.682327</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.678085</Real>
+        <Real Name="Y">76.928635</Real>
+        <Real Name="Z">216.86887</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8618286</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8618286</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8618286</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0012119483</Real>
+        <Real Name="Y">0.5887025</Real>
+        <Real Name="Z">0.24146336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8541783</Real>
+        <Real Name="Y">0.67512894</Real>
+        <Real Name="Z">0.28164101</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076792136</Real>
+        <Real Name="Y">0.59691048</Real>
+        <Real Name="Z">0.18330339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98214036</Real>
+        <Real Name="Y">0.62897497</Real>
+        <Real Name="Z">1.5715997</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97463477</Real>
+        <Real Name="Y">0.63184929</Real>
+        <Real Name="Z">1.6669817</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94148064</Real>
+        <Real Name="Y">0.71036839</Real>
+        <Real Name="Z">1.5418638</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3887119</Real>
+        <Real Name="Y">0.44755831</Real>
+        <Real Name="Z">1.1805441</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3382109</Real>
+        <Real Name="Y">0.47834957</Real>
+        <Real Name="Z">1.2558029</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3256121</Real>
+        <Real Name="Y">0.39874086</Real>
+        <Real Name="Z">1.127652</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.64895</Real>
+        <Real Name="Y">0.31831384</Real>
+        <Real Name="Z">0.29567274</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7082821</Real>
+        <Real Name="Y">0.34167513</Real>
+        <Real Name="Z">0.22428459</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6023285</Real>
+        <Real Name="Y">0.24102496</Real>
+        <Real Name="Z">0.26381072</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7746052</Real>
+        <Real Name="Y">0.39956397</Real>
+        <Real Name="Z">0.020418452</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.716015</Real>
+        <Real Name="Y">0.40723705</Real>
+        <Real Name="Z">1.8069434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7869678</Real>
+        <Real Name="Y">0.48959652</Real>
+        <Real Name="Z">0.050478783</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21832228</Real>
+        <Real Name="Y">-0.61211735</Real>
+        <Real Name="Z">-0.34189141</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.36596027</Real>
+        <Real Name="Y">-1.435892</Real>
+        <Real Name="Z">1.6194848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4109368</Real>
+        <Real Name="Y">-0.86408943</Real>
+        <Real Name="Z">2.8895948</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44242257</Real>
+        <Real Name="Y">-0.10459414</Real>
+        <Real Name="Z">0.17602694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6441607</Real>
+        <Real Name="Y">0.85899937</Real>
+        <Real Name="Z">0.25405198</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6905975</Real>
+        <Real Name="Y">0.46370864</Real>
+        <Real Name="Z">-0.0072683324</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.55795717</Real>
+        <Real Name="Y">0.024626339</Real>
+        <Real Name="Z">0.39378598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.61744565</Real>
+        <Real Name="Y">0.21256842</Real>
+        <Real Name="Z">1.1185452</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96275395</Real>
+        <Real Name="Y">-1.8188386</Real>
+        <Real Name="Z">2.5025265</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24529488</Real>
+        <Real Name="Y">0.3242096</Real>
+        <Real Name="Z">-0.42158732</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39681417</Real>
+        <Real Name="Y">1.3125696</Real>
+        <Real Name="Z">0.019382903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.81812513</Real>
+        <Real Name="Y">0.33510405</Real>
+        <Real Name="Z">-1.3036219</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20876089</Real>
+        <Real Name="Y">0.40662917</Real>
+        <Real Name="Z">-0.26820141</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53637588</Real>
+        <Real Name="Y">-0.020447832</Real>
+        <Real Name="Z">-0.89886612</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7985342</Real>
+        <Real Name="Y">0.34124973</Real>
+        <Real Name="Z">1.1370618</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-76.646454</Real>
+        <Real Name="Y">73.395126</Real>
+        <Real Name="Z">-360.02655</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.7511787</Real>
+        <Real Name="Y">-1.1251068</Real>
+        <Real Name="Z">111.71889</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">133.53137</Real>
+        <Real Name="Y">-2.8567429</Real>
+        <Real Name="Z">131.26326</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">24.174393</Real>
+        <Real Name="Y">-24.235294</Real>
+        <Real Name="Z">-37.464561</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.8224869</Real>
+        <Real Name="Y">7.3017159</Real>
+        <Real Name="Z">14.333199</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.4376144</Real>
+        <Real Name="Y">13.103792</Real>
+        <Real Name="Z">11.721798</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.83445</Real>
+        <Real Name="Y">-3.5244637</Real>
+        <Real Name="Z">-32.17749</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.517872</Real>
+        <Real Name="Y">8.8010445</Real>
+        <Real Name="Z">-18.447533</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.312038</Real>
+        <Real Name="Y">4.2152615</Real>
+        <Real Name="Z">18.152184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-317.63376</Real>
+        <Real Name="Y">-134.95288</Real>
+        <Real Name="Z">279.47031</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">245.4288</Real>
+        <Real Name="Y">104.13286</Real>
+        <Real Name="Z">-285.95306</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">119.29408</Real>
+        <Real Name="Y">61.68187</Real>
+        <Real Name="Z">-65.257263</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.859985</Real>
+        <Real Name="Y">-324.58041</Real>
+        <Real Name="Z">-37.440613</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.965565</Real>
+        <Real Name="Y">57.682228</Real>
+        <Real Name="Z">25.992691</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.749634</Real>
+        <Real Name="Y">160.96101</Real>
+        <Real Name="Z">244.11469</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 2">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98715
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4695773</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4695773</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4695773</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4695773</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4354539</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4354539</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4354539</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4354539</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.453341</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.453341</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4596901</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4596901</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4663458</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4663458</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4663458</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4663458</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.538376</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">30.683466</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.543703</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.539244</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">29.539164</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">25.748821</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">25.749447</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">25.750429</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">25.751516</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">19.956553</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">19.911335</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">20.056658</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">19.917387</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">29.552752</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">29.551897</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">29.550919</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">29.586946</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">39.264248</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">37.886772</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">36.607677</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">36.574806</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">36.6432</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">34.244972</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.474041</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">34.767593</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.127304</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">37.550224</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">39.283279</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">40.907303</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">42.533607</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">42.00238</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">43.007889</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">44.085976</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">45.175636</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.4290991</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.2897673</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.2613564</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.3298292</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.8717546</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.100196</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.392767</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.75139</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.36792</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.103653</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-22.881548</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.647123</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-14.270962</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-15.277324</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-16.35639</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-17.410023</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.55872297</Real>
+        <Real Name="Y">-0.19543174</Real>
+        <Real Name="Z">-0.12331802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5561588</Real>
+        <Real Name="Y">0.15019241</Real>
+        <Real Name="Z">-0.44760495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2265118</Real>
+        <Real Name="Y">-1.1768512</Real>
+        <Real Name="Z">-1.2616764</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10263991</Real>
+        <Real Name="Y">0.57440907</Real>
+        <Real Name="Z">0.0053722998</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.35943791</Real>
+        <Real Name="Y">0.13711332</Real>
+        <Real Name="Z">-0.18872896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6768553</Real>
+        <Real Name="Y">2.2024438</Real>
+        <Real Name="Z">0.65932018</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22449927</Real>
+        <Real Name="Y">0.27064398</Real>
+        <Real Name="Z">0.38681656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.18288493</Real>
+        <Real Name="Y">3.1066663</Real>
+        <Real Name="Z">-0.46535692</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.43482876</Real>
+        <Real Name="Y">-1.4385394</Real>
+        <Real Name="Z">0.8301881</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11927342</Real>
+        <Real Name="Y">-0.50285125</Real>
+        <Real Name="Z">0.091731116</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.6758315</Real>
+        <Real Name="Y">-0.055776317</Real>
+        <Real Name="Z">0.61587429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2213309</Real>
+        <Real Name="Y">-1.9672643</Real>
+        <Real Name="Z">0.44974977</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.90470046</Real>
+        <Real Name="Y">-0.2009875</Real>
+        <Real Name="Z">-0.24253644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.8438639</Real>
+        <Real Name="Y">0.72260296</Real>
+        <Real Name="Z">-1.8703772</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39639631</Real>
+        <Real Name="Y">-0.8200264</Real>
+        <Real Name="Z">-0.19537324</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8600576</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8600576</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8600576</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0035440694</Real>
+        <Real Name="Y">0.60159874</Real>
+        <Real Name="Z">0.24000494</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.010168534</Real>
+        <Real Name="Y">0.68597651</Real>
+        <Real Name="Z">0.28471321</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.067518614</Real>
+        <Real Name="Y">0.60697043</Real>
+        <Real Name="Z">0.16900693</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97235215</Real>
+        <Real Name="Y">0.63150573</Real>
+        <Real Name="Z">1.5667046</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96173358</Real>
+        <Real Name="Y">0.6097126</Real>
+        <Real Name="Z">1.6593039</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90070307</Real>
+        <Real Name="Y">0.69214475</Real>
+        <Real Name="Z">1.5479524</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3952576</Real>
+        <Real Name="Y">0.44389057</Real>
+        <Real Name="Z">1.1703659</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3273376</Real>
+        <Real Name="Y">0.45524156</Real>
+        <Real Name="Z">1.2368517</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3480916</Real>
+        <Real Name="Y">0.4134782</Real>
+        <Real Name="Z">1.0928239</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6433158</Real>
+        <Real Name="Y">0.31463918</Real>
+        <Real Name="Z">0.30253601</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6980145</Real>
+        <Real Name="Y">0.32680798</Real>
+        <Real Name="Z">0.2249326</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5942141</Real>
+        <Real Name="Y">0.23437834</Real>
+        <Real Name="Z">0.28494233</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7754595</Real>
+        <Real Name="Y">0.39272234</Real>
+        <Real Name="Z">0.029220587</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.711414</Real>
+        <Real Name="Y">0.4185966</Real>
+        <Real Name="Z">1.8230134</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8353932</Real>
+        <Real Name="Y">0.46713132</Real>
+        <Real Name="Z">0.035014682</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.13999636</Real>
+        <Real Name="Y">0.38254365</Real>
+        <Real Name="Z">-0.53779292</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9396605</Real>
+        <Real Name="Y">-1.277357</Real>
+        <Real Name="Z">2.3699629</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3824043</Real>
+        <Real Name="Y">-0.53857791</Real>
+        <Real Name="Z">1.5829322</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20198093</Real>
+        <Real Name="Y">0.15117285</Real>
+        <Real Name="Z">-0.091680847</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.495996</Real>
+        <Real Name="Y">-0.57121807</Real>
+        <Real Name="Z">-0.048701935</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.6691253</Real>
+        <Real Name="Y">-1.1321015</Real>
+        <Real Name="Z">1.217416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.056646761</Real>
+        <Real Name="Y">-0.33177066</Real>
+        <Real Name="Z">-0.29872352</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.19083714</Real>
+        <Real Name="Y">-2.5765393</Real>
+        <Real Name="Z">0.37919727</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.1645962</Real>
+        <Real Name="Y">-2.0793557</Real>
+        <Real Name="Z">0.23037335</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0054697306</Real>
+        <Real Name="Y">0.23380075</Real>
+        <Real Name="Z">0.093860336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.50328386</Real>
+        <Real Name="Y">0.25225928</Real>
+        <Real Name="Z">-0.26432547</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21080205</Real>
+        <Real Name="Y">-0.0025314789</Real>
+        <Real Name="Z">0.58919519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.088726938</Real>
+        <Real Name="Y">0.11622863</Real>
+        <Real Name="Z">0.51681727</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45098117</Real>
+        <Real Name="Y">0.52531523</Real>
+        <Real Name="Z">0.15033868</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9857125</Real>
+        <Real Name="Y">-1.3609871</Real>
+        <Real Name="Z">-1.1666512</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">115.53893</Real>
+        <Real Name="Y">83.827911</Real>
+        <Real Name="Z">-322.37323</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-29.994846</Real>
+        <Real Name="Y">-17.473022</Real>
+        <Real Name="Z">88.93364</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">63.889244</Real>
+        <Real Name="Y">78.349403</Real>
+        <Real Name="Z">218.46448</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">13.004318</Real>
+        <Real Name="Y">-21.724346</Real>
+        <Real Name="Z">-33.33036</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.011578</Real>
+        <Real Name="Y">-6.9872799</Real>
+        <Real Name="Z">-24.69812</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6996078</Real>
+        <Real Name="Y">9.565197</Real>
+        <Real Name="Z">10.651409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.590187</Real>
+        <Real Name="Y">-14.000481</Real>
+        <Real Name="Z">-31.315334</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.577641</Real>
+        <Real Name="Y">13.430428</Real>
+        <Real Name="Z">25.068775</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.328831</Real>
+        <Real Name="Y">19.716484</Real>
+        <Real Name="Z">53.623631</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-294.95724</Real>
+        <Real Name="Y">-159.71771</Real>
+        <Real Name="Z">316.04581</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.06143</Real>
+        <Real Name="Y">157.72026</Real>
+        <Real Name="Z">-334.16251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">105.6647</Real>
+        <Real Name="Y">69.093102</Real>
+        <Real Name="Z">-72.494995</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-69.989456</Real>
+        <Real Name="Y">-327.41699</Real>
+        <Real Name="Z">-21.003876</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-16.965445</Real>
+        <Real Name="Y">78.652946</Real>
+        <Real Name="Z">-5.0758362</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-109.2473</Real>
+        <Real Name="Y">36.964081</Real>
+        <Real Name="Z">131.66653</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8630291</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8630291</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8630291</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0133312</Real>
+        <Real Name="Y">0.59768015</Real>
+        <Real Name="Z">0.2398925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0053255465</Real>
+        <Real Name="Y">0.6854189</Real>
+        <Real Name="Z">0.27731091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.058500759</Real>
+        <Real Name="Y">0.61114973</Real>
+        <Real Name="Z">0.15658224</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97706705</Real>
+        <Real Name="Y">0.64056098</Real>
+        <Real Name="Z">1.5692767</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9478789</Real>
+        <Real Name="Y">0.61657125</Real>
+        <Real Name="Z">1.6572248</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94544721</Real>
+        <Real Name="Y">0.73008078</Real>
+        <Real Name="Z">1.5570818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3938936</Real>
+        <Real Name="Y">0.45179155</Real>
+        <Real Name="Z">1.1809812</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3393959</Real>
+        <Real Name="Y">0.51891041</Real>
+        <Real Name="Z">1.2220588</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3372105</Real>
+        <Real Name="Y">0.41197044</Real>
+        <Real Name="Z">1.1149234</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6476173</Real>
+        <Real Name="Y">0.30465943</Real>
+        <Real Name="Z">0.30283684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7115803</Real>
+        <Real Name="Y">0.33648124</Real>
+        <Real Name="Z">0.239131</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6390228</Real>
+        <Real Name="Y">0.21128228</Real>
+        <Real Name="Z">0.28362337</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7640212</Real>
+        <Real Name="Y">0.38783005</Real>
+        <Real Name="Z">0.020920331</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.728166</Real>
+        <Real Name="Y">0.42682832</Real>
+        <Real Name="Z">1.8042259</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.811921</Real>
+        <Real Name="Y">0.45917195</Real>
+        <Real Name="Z">0.063089721</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.50736982</Real>
+        <Real Name="Y">-0.14407218</Real>
+        <Real Name="Z">-0.40841478</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1777533</Real>
+        <Real Name="Y">-0.80467659</Real>
+        <Real Name="Z">1.3366399</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8677279</Real>
+        <Real Name="Y">1.0278221</Real>
+        <Real Name="Z">0.49438733</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10010453</Real>
+        <Real Name="Y">0.59763086</Real>
+        <Real Name="Z">-0.072785005</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.13765462</Real>
+        <Real Name="Y">0.013841485</Real>
+        <Real Name="Z">-0.30839935</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9231188</Real>
+        <Real Name="Y">1.4506483</Real>
+        <Real Name="Z">1.2267997</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2456588</Real>
+        <Real Name="Y">0.30480564</Real>
+        <Real Name="Z">0.40500662</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.78423852</Real>
+        <Real Name="Y">2.1660016</Real>
+        <Real Name="Z">-1.1839032</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1065043</Real>
+        <Real Name="Y">-0.96795237</Real>
+        <Real Name="Z">1.8767413</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.12050907</Real>
+        <Real Name="Y">-0.58212268</Real>
+        <Real Name="Z">0.011123641</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.085032895</Real>
+        <Real Name="Y">1.0060257</Real>
+        <Real Name="Z">0.5752241</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9116142</Real>
+        <Real Name="Y">-0.91851223</Real>
+        <Real Name="Z">0.19094355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.9455592</Real>
+        <Real Name="Y">-0.33935115</Real>
+        <Real Name="Z">-0.25612161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3156105</Real>
+        <Real Name="Y">0.80946773</Real>
+        <Real Name="Z">-0.75290483</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2981914</Real>
+        <Real Name="Y">-1.1935745</Real>
+        <Real Name="Z">1.6424874</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-31.2043</Real>
+        <Real Name="Y">-164.60281</Real>
+        <Real Name="Z">-390.93777</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-14.042034</Real>
+        <Real Name="Y">40.132416</Real>
+        <Real Name="Z">99.201828</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">142.33237</Real>
+        <Real Name="Y">174.20074</Real>
+        <Real Name="Z">160.8914</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">13.031548</Real>
+        <Real Name="Y">-4.0820923</Real>
+        <Real Name="Z">-39.267212</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.1769409</Real>
+        <Real Name="Y">-0.31424046</Real>
+        <Real Name="Z">13.286335</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-6.3334579</Real>
+        <Real Name="Y">5.3132973</Real>
+        <Real Name="Z">15.039284</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">35.697723</Real>
+        <Real Name="Y">-8.7160797</Real>
+        <Real Name="Z">-31.015663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.293213</Real>
+        <Real Name="Y">2.1325073</Real>
+        <Real Name="Z">25.112614</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-12.925661</Real>
+        <Real Name="Y">5.6666107</Real>
+        <Real Name="Z">16.844643</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-210.54822</Real>
+        <Real Name="Y">-89.486305</Real>
+        <Real Name="Z">296.91025</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">102.73276</Real>
+        <Real Name="Y">40.615562</Real>
+        <Real Name="Z">-277.1438</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.847778</Real>
+        <Real Name="Y">73.312141</Real>
+        <Real Name="Z">-101.62836</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">24.089157</Real>
+        <Real Name="Y">-177.29469</Real>
+        <Real Name="Z">53.933716</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-39.511784</Real>
+        <Real Name="Y">22.477959</Real>
+        <Real Name="Z">-5.0157471</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-47.69574</Real>
+        <Real Name="Y">80.644928</Real>
+        <Real Name="Z">163.78848</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 3">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98716
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4354539</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4354539</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4354539</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4354539</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4695773</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4695773</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4695773</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4695773</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4695773</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4695773</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4663458</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4663458</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4596901</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4596901</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4596901</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4596901</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">25.77104</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">26.440069</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">25.788334</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">25.74818</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">25.748268</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">29.539114</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.539104</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.539175</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.539259</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">29.539404</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">29.552454</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">29.347403</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">29.555498</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">19.914249</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">19.90896</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">19.903955</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">19.900032</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">35.343521</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">34.648945</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">33.984718</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">33.979034</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">34.079788</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">36.807934</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">37.068752</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">37.425777</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.879196</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">38.428978</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">39.074673</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">40.031612</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">41.080421</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">44.266014</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">45.887295</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">47.339172</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">48.565414</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5844784</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5719872</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6064577</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.7071228</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.4946146</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-9.7554417</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.112396</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.565731</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.115369</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.761237</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-12.505542</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-13.346255</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.382668</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-28.009237</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.46612</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.696285</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.19787164</Real>
+        <Real Name="Y">0.16156073</Real>
+        <Real Name="Z">-0.3830564</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.7420168</Real>
+        <Real Name="Y">0.75917548</Real>
+        <Real Name="Z">1.2435496</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3711295</Real>
+        <Real Name="Y">-0.1916929</Real>
+        <Real Name="Z">0.42564186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19638549</Real>
+        <Real Name="Y">0.14565483</Real>
+        <Real Name="Z">-0.067964658</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3802328</Real>
+        <Real Name="Y">-0.58428359</Real>
+        <Real Name="Z">0.2304372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.9488595</Real>
+        <Real Name="Y">-0.88427049</Real>
+        <Real Name="Z">0.94601095</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.023709064</Real>
+        <Real Name="Y">-0.34130558</Real>
+        <Real Name="Z">-0.30921173</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.57465923</Real>
+        <Real Name="Y">-2.6639383</Real>
+        <Real Name="Z">0.20926186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10718073</Real>
+        <Real Name="Y">-2.149086</Real>
+        <Real Name="Z">0.10538759</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.012949247</Real>
+        <Real Name="Y">0.24703081</Real>
+        <Real Name="Z">0.11981639</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53420067</Real>
+        <Real Name="Y">-0.39553621</Real>
+        <Real Name="Z">-0.44761676</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23061849</Real>
+        <Real Name="Y">0.091385715</Real>
+        <Real Name="Z">1.1257544</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.06405513</Real>
+        <Real Name="Y">0.15561384</Real>
+        <Real Name="Z">0.54946572</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53148574</Real>
+        <Real Name="Y">0.53813189</Real>
+        <Real Name="Z">0.031651895</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.0633225</Real>
+        <Real Name="Y">-0.3697392</Real>
+        <Real Name="Z">-2.4264705</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8633394</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8633394</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8633394</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0092421323</Real>
+        <Real Name="Y">0.59902775</Real>
+        <Real Name="Z">0.24261346</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8582575</Real>
+        <Real Name="Y">0.68958539</Real>
+        <Real Name="Z">0.27011719</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.048511647</Real>
+        <Real Name="Y">0.60629308</Real>
+        <Real Name="Z">0.15562242</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9764362</Real>
+        <Real Name="Y">0.63597685</Real>
+        <Real Name="Z">1.5699894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9495582</Real>
+        <Real Name="Y">0.61630154</Real>
+        <Real Name="Z">1.6597266</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.93061954</Real>
+        <Real Name="Y">0.71722054</Real>
+        <Real Name="Z">1.5484809</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3960555</Real>
+        <Real Name="Y">0.44951424</Real>
+        <Real Name="Z">1.1779605</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3340693</Real>
+        <Real Name="Y">0.49982059</Real>
+        <Real Name="Z">1.2307744</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3451762</Real>
+        <Real Name="Y">0.42073551</Real>
+        <Real Name="Z">1.1021621</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6470068</Real>
+        <Real Name="Y">0.30918208</Real>
+        <Real Name="Z">0.30272177</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7100686</Real>
+        <Real Name="Y">0.32998836</Real>
+        <Real Name="Z">0.23378247</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.616679</Real>
+        <Real Name="Y">0.22087313</Real>
+        <Real Name="Z">0.28164873</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7718822</Real>
+        <Real Name="Y">0.39039528</Real>
+        <Real Name="Z">0.023003843</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7185817</Real>
+        <Real Name="Y">0.42084789</Real>
+        <Real Name="Z">1.8128995</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8190252</Real>
+        <Real Name="Y">0.46834609</Real>
+        <Real Name="Z">0.052389581</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.51909775</Real>
+        <Real Name="Y">-0.16868283</Real>
+        <Real Name="Z">-0.25152397</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4270048</Real>
+        <Real Name="Y">-0.20453218</Real>
+        <Real Name="Z">0.36117899</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37975219</Real>
+        <Real Name="Y">0.019636139</Real>
+        <Real Name="Z">-0.29903603</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.098124154</Real>
+        <Real Name="Y">0.57261181</Real>
+        <Real Name="Z">-0.034573164</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25185391</Real>
+        <Real Name="Y">0.084726281</Real>
+        <Real Name="Z">-0.24421519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7988112</Real>
+        <Real Name="Y">1.8247384</Real>
+        <Real Name="Z">0.94630015</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23429824</Real>
+        <Real Name="Y">0.2801033</Real>
+        <Real Name="Z">0.39519852</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.54855156</Real>
+        <Real Name="Y">2.6671031</Real>
+        <Real Name="Z">-0.88438952</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.7765913</Real>
+        <Real Name="Y">-1.2169187</Real>
+        <Real Name="Z">1.3054005</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10299214</Real>
+        <Real Name="Y">-0.52866131</Real>
+        <Real Name="Z">0.038666837</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.54287606</Real>
+        <Real Name="Y">0.52248424</Real>
+        <Real Name="Z">0.74525595</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.659873</Real>
+        <Real Name="Y">-1.5167377</Real>
+        <Real Name="Z">0.31927741</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93418998</Real>
+        <Real Name="Y">-0.27053937</Real>
+        <Real Name="Z">-0.25782821</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1130617</Real>
+        <Real Name="Y">0.70070261</Real>
+        <Real Name="Z">-1.3843707</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.32631254</Real>
+        <Real Name="Y">-1.0531381</Real>
+        <Real Name="Z">0.88155556</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">15.821472</Real>
+        <Real Name="Y">-60.161896</Real>
+        <Real Name="Z">-385.48904</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.160297</Real>
+        <Real Name="Y">21.8004</Real>
+        <Real Name="Z">103.78319</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">143.10815</Real>
+        <Real Name="Y">170.89096</Real>
+        <Real Name="Z">222.70911</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.439751</Real>
+        <Real Name="Y">-8.4087334</Real>
+        <Real Name="Z">-39.719971</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.555016</Real>
+        <Real Name="Y">-12.030103</Real>
+        <Real Name="Z">-23.741364</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.4157448</Real>
+        <Real Name="Y">6.7338104</Real>
+        <Real Name="Z">14.456924</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.585464</Real>
+        <Real Name="Y">-9.236496</Real>
+        <Real Name="Z">-32.537338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.252937</Real>
+        <Real Name="Y">5.0463657</Real>
+        <Real Name="Z">27.254852</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.911549</Real>
+        <Real Name="Y">17.895155</Real>
+        <Real Name="Z">54.286896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-255.79788</Real>
+        <Real Name="Y">-97.596657</Real>
+        <Real Name="Z">269.77563</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">161.74324</Real>
+        <Real Name="Y">75.477951</Real>
+        <Real Name="Z">-289.42404</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.671265</Real>
+        <Real Name="Y">63.365852</Real>
+        <Real Name="Z">-79.672691</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-3.1915283</Real>
+        <Real Name="Y">-171.12366</Real>
+        <Real Name="Z">51.520142</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-38.75034</Real>
+        <Real Name="Y">27.282066</Real>
+        <Real Name="Z">-17.70491</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-98.444031</Real>
+        <Real Name="Y">-29.935059</Real>
+        <Real Name="Z">124.50256</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8623897</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8623897</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8623897</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070135458</Real>
+        <Real Name="Y">0.60003477</Real>
+        <Real Name="Z">0.23230985</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0042683878</Real>
+        <Real Name="Y">0.67762172</Real>
+        <Real Name="Z">0.28830129</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.082054406</Real>
+        <Real Name="Y">0.61464912</Real>
+        <Real Name="Z">0.1747112</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97359121</Real>
+        <Real Name="Y">0.63047773</Real>
+        <Real Name="Z">1.5737368</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94162154</Real>
+        <Real Name="Y">0.57328832</Real>
+        <Real Name="Z">1.6435196</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90265316</Real>
+        <Real Name="Y">0.6931963</Real>
+        <Real Name="Z">1.5597193</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396216</Real>
+        <Real Name="Y">0.446753</Real>
+        <Real Name="Z">1.1637279</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3340528</Real>
+        <Real Name="Y">0.4704285</Real>
+        <Real Name="Z">1.2325575</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3419291</Real>
+        <Real Name="Y">0.43272939</Real>
+        <Real Name="Z">1.0861484</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6418072</Real>
+        <Real Name="Y">0.31899214</Real>
+        <Real Name="Z">0.31236282</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7045138</Real>
+        <Real Name="Y">0.34980416</Real>
+        <Real Name="Z">0.24693488</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.626368</Real>
+        <Real Name="Y">0.22733144</Real>
+        <Real Name="Z">0.28950959</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7800722</Real>
+        <Real Name="Y">0.39105237</Real>
+        <Real Name="Z">0.024231877</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6910145</Real>
+        <Real Name="Y">0.42138243</Real>
+        <Real Name="Z">0.0065927505</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8164846</Real>
+        <Real Name="Y">0.45674214</Real>
+        <Real Name="Z">0.083572499</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.16438076</Real>
+        <Real Name="Y">0.084157526</Real>
+        <Real Name="Z">-0.94159567</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.68336308</Real>
+        <Real Name="Y">-1.9596776</Real>
+        <Real Name="Z">2.0348001</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5617356</Real>
+        <Real Name="Y">0.20735136</Real>
+        <Real Name="Z">2.0835056</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11250072</Real>
+        <Real Name="Y">-0.052009981</Real>
+        <Real Name="Z">0.28470123</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22965556</Real>
+        <Real Name="Y">-2.4603388</Real>
+        <Real Name="Z">-1.6735603</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.74590248</Real>
+        <Real Name="Y">-0.5436216</Real>
+        <Real Name="Z">1.2352371</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.073732346</Real>
+        <Real Name="Y">-0.019990299</Real>
+        <Real Name="Z">-0.6488896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42511129</Real>
+        <Real Name="Y">-0.36487713</Real>
+        <Real Name="Z">-0.07483051</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.66172981</Real>
+        <Real Name="Y">0.15868105</Real>
+        <Real Name="Z">-0.27318129</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23825349</Real>
+        <Real Name="Y">0.34428003</Real>
+        <Real Name="Z">0.57936168</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31692269</Real>
+        <Real Name="Y">1.4150901</Real>
+        <Real Name="Z">1.596742</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2657793</Real>
+        <Real Name="Y">-0.15391546</Real>
+        <Real Name="Z">0.74252754</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.032043934</Real>
+        <Real Name="Y">0.04753904</Real>
+        <Real Name="Z">0.014056274</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.64698917</Real>
+        <Real Name="Y">-0.33644041</Real>
+        <Real Name="Z">2.5782263</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.34888014</Real>
+        <Real Name="Y">-2.3743117</Real>
+        <Real Name="Z">3.057409</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-164.18471</Real>
+        <Real Name="Y">-312.61584</Real>
+        <Real Name="Z">-380.59369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.023422</Real>
+        <Real Name="Y">67.037704</Real>
+        <Real Name="Z">100.55685</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.25047</Real>
+        <Real Name="Y">140.24834</Real>
+        <Real Name="Z">74.048721</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.248886</Real>
+        <Real Name="Y">-15.065842</Real>
+        <Real Name="Z">-36.612999</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.841362</Real>
+        <Real Name="Y">-7.1573162</Real>
+        <Real Name="Z">-24.51149</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1940727</Real>
+        <Real Name="Y">7.4198246</Real>
+        <Real Name="Z">12.152283</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.505424</Real>
+        <Real Name="Y">-17.439507</Real>
+        <Real Name="Z">-31.379139</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.641529</Real>
+        <Real Name="Y">14.806063</Real>
+        <Real Name="Z">25.296268</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.760071</Real>
+        <Real Name="Y">17.436779</Real>
+        <Real Name="Z">55.055077</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-182.71924</Real>
+        <Real Name="Y">2.5998535</Real>
+        <Real Name="Z">105.51813</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">148.40079</Real>
+        <Real Name="Y">-32.520088</Real>
+        <Real Name="Z">-88.072662</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.38884</Real>
+        <Real Name="Y">10.394051</Real>
+        <Real Name="Z">-49.919983</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-53.990097</Real>
+        <Real Name="Y">-310.60556</Real>
+        <Real Name="Z">-19.608124</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-18.861469</Real>
+        <Real Name="Y">115.33578</Real>
+        <Real Name="Z">0.17415619</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.691986</Real>
+        <Real Name="Y">320.12573</Real>
+        <Real Name="Z">257.89658</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_Crescale_4Ranks_2RanksPerSimulation_d.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_Crescale_4Ranks_2RanksPerSimulation_d.xml
new file mode 100644 (file)
index 0000000..50c3a27
--- /dev/null
@@ -0,0 +1,1696 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4533416426810541</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4533416426810541</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4533416426810541</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4533416426810541</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4529770401682987</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4529770401682987</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4529770401682987</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4529770401682987</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4529770401682987</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4529770401682987</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.453849777960853</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.453849777960853</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.466439846779636</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.466439846779636</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.466439846779636</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.466439846779636</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">19.965980763101861</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">20.842760388505674</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">19.960013877466789</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">19.959232604591765</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">19.959915811881984</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">17.433636406183297</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">17.433671522954445</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">17.433617463135164</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">17.433435543305738</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">17.380514126918843</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">17.379539501938311</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">17.729733229954196</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">17.369260607482062</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">19.877984439341457</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">19.872813616001782</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">19.867951062312326</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">19.863960197493345</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629305410083017</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.229344742176963</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">28.967916050097003</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.737254472731379</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">30.664158285412039</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">30.504226924752725</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">31.035241150209885</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">31.713668302200631</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">32.536600955137288</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">33.446321468564719</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">34.434544621873059</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">35.175851634941431</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">36.019809174149287</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">43.014917580215382</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">44.621978836390092</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">46.067774517140059</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">47.297154169595174</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673364533766927</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.160837447757872</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.782155266716796</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.552274962226196</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.478495567616637</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.257018274455515</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.787997383141526</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.466478594951553</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.289593167717637</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.252235097531962</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.241018752015297</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.353135972005639</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.557566133685629</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.304871112959624</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-27.917103192474009</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.367761426913432</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.601131944187529</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.004987833407605083</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858972</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391528</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.02498992600415597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208519</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13823960248430261</Real>
+        <Real Name="Y">-0.083001582473173879</Real>
+        <Real Name="Z">-0.55156788526044931</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807346912896504</Real>
+        <Real Name="Y">0.12594239723743825</Real>
+        <Real Name="Z">0.086340039099900012</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50558175484201939</Real>
+        <Real Name="Y">-0.2634720104901444</Real>
+        <Real Name="Z">-0.37043107548328896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.080341973608849884</Real>
+        <Real Name="Y">-0.036383374851252599</Real>
+        <Real Name="Z">0.26950251001929965</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0879938107726246</Real>
+        <Real Name="Y">-2.69925195488055</Real>
+        <Real Name="Z">-0.41161299800761325</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.005339856872981</Real>
+        <Real Name="Y">-0.4461332722971294</Real>
+        <Real Name="Z">1.1534368241800745</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046991365082634809</Real>
+        <Real Name="Y">-0.027139438957271552</Real>
+        <Real Name="Z">-0.6835695669642462</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.052027730439707112</Real>
+        <Real Name="Y">-0.42394701288611142</Real>
+        <Real Name="Z">-0.38240890291446689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2514527117216987</Real>
+        <Real Name="Y">0.072329295992862808</Real>
+        <Real Name="Z">-0.58384125172376988</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20047275659675184</Real>
+        <Real Name="Y">0.39459474035999648</Real>
+        <Real Name="Z">0.71751226731035556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21660158751017158</Real>
+        <Real Name="Y">1.2107968994948017</Real>
+        <Real Name="Z">0.86109126390401147</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3771064228719012</Real>
+        <Real Name="Y">-0.6610218165066043</Real>
+        <Real Name="Z">0.87071447867481888</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21701225376725289</Real>
+        <Real Name="Y">-0.090547598182204897</Real>
+        <Real Name="Z">-0.034702681691122401</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639425064679751</Real>
+        <Real Name="Y">0.9636306948577793</Real>
+        <Real Name="Z">2.5346418773965156</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37424921124689092</Real>
+        <Real Name="Y">-0.37914050295285695</Real>
+        <Real Name="Z">0.73119277083081202</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959196342</Real>
+        <Real Name="Y">10.126334215507086</Real>
+        <Real Name="Z">-383.9244463652023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773668</Real>
+        <Real Name="Y">8.7835602768706877</Real>
+        <Real Name="Z">109.98162207856127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818237</Real>
+        <Real Name="Y">125.90227601095691</Real>
+        <Real Name="Z">223.10402606189822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.9064510541798</Real>
+        <Real Name="Y">-91.873016441468678</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733365</Real>
+        <Real Name="Y">82.504344401698347</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041526</Real>
+        <Real Name="Y">45.329959216167893</Real>
+        <Real Name="Z">-56.291380508471349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448434</Real>
+        <Real Name="Y">-204.77938512046111</Real>
+        <Real Name="Z">21.695070286562498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013951</Real>
+        <Real Name="Y">47.5995038096992</Real>
+        <Real Name="Z">-24.246658126595179</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564435093</Real>
+        <Real Name="Y">-23.593576368970304</Real>
+        <Real Name="Z">144.65217639452101</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617443304291632</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617443304291632</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617443304291632</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0031319514973263056</Real>
+        <Real Name="Y">0.59410785737283001</Real>
+        <Real Name="Z">0.24342359478984851</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8499470358519892</Real>
+        <Real Name="Y">0.68418585926343423</Real>
+        <Real Name="Z">0.27215318906200964</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059119918712009042</Real>
+        <Real Name="Y">0.60250218332105165</Real>
+        <Real Name="Z">0.16624068723226609</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97844335808524308</Real>
+        <Real Name="Y">0.62987453388483328</Real>
+        <Real Name="Z">1.5701316447392728</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96171380880012147</Real>
+        <Real Name="Y">0.62405529923602043</Real>
+        <Real Name="Z">1.664198520358793</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92800279912853745</Real>
+        <Real Name="Y">0.70600227622230394</Real>
+        <Real Name="Z">1.5414500259088386</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3929865319441028</Real>
+        <Real Name="Y">0.4472759015521206</Real>
+        <Real Name="Z">1.1772088481218357</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3333053453617376</Real>
+        <Real Name="Y">0.47707460548633418</Real>
+        <Real Name="Z">1.2458565837870543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3355339511471416</Real>
+        <Real Name="Y">0.4143464197451685</Real>
+        <Real Name="Z">1.108091783747732</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6468265804245077</Real>
+        <Real Name="Y">0.31562858261302945</Real>
+        <Real Name="Z">0.29898630325357595</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7053698863476372</Real>
+        <Real Name="Y">0.3326340054687526</Real>
+        <Real Name="Z">0.2251905355897833</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5972219574315853</Real>
+        <Real Name="Y">0.23803796497588953</Real>
+        <Real Name="Z">0.27288274348834946</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7762099578383366</Real>
+        <Real Name="Y">0.39600078592797999</Real>
+        <Real Name="Z">0.022708809110338842</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7119511904885945</Real>
+        <Real Name="Y">0.40962255237208145</Real>
+        <Real Name="Z">1.8148285986244359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8061576690789511</Real>
+        <Real Name="Y">0.4840658263368085</Real>
+        <Real Name="Z">0.045292025206365112</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.24151076377176608</Real>
+        <Real Name="Y">-0.71041738569560731</Real>
+        <Real Name="Z">-0.13636236434405472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.61063830178654011</Real>
+        <Real Name="Y">-0.81444214376777424</Real>
+        <Real Name="Z">0.65637387097936561</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6708858070288208</Real>
+        <Real Name="Y">-0.63778007581879614</Real>
+        <Real Name="Z">1.2230788954130571</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45217068966505947</Real>
+        <Real Name="Y">-0.12316015295171615</Real>
+        <Real Name="Z">0.16472807103629294</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4644188662956261</Real>
+        <Real Name="Y">1.055472809535283</Real>
+        <Real Name="Z">0.43087410000146492</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5698359924360725</Real>
+        <Real Name="Y">0.6045369395439032</Real>
+        <Real Name="Z">0.099557103060112104</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.49418075810934409</Real>
+        <Real Name="Y">0.03948648828584872</Real>
+        <Real Name="Z">0.41190790332423355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53571862460036135</Real>
+        <Real Name="Y">0.092132184496962546</Real>
+        <Real Name="Z">1.2978958029902949</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.5286242915169357</Real>
+        <Real Name="Y">-2.0089471705055297</Real>
+        <Real Name="Z">2.1868251137519783</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2559566808808359</Real>
+        <Real Name="Y">0.32839465439402304</Real>
+        <Real Name="Z">-0.39021806249716129</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.28999985732457512</Real>
+        <Real Name="Y">0.84646582037141271</Real>
+        <Real Name="Z">-0.24579498338285322</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39100484269189673</Real>
+        <Real Name="Y">0.40627277013457347</Real>
+        <Real Name="Z">-0.88346191980705768</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1999061365891262</Real>
+        <Real Name="Y">0.46891940265177012</Real>
+        <Real Name="Z">-0.28633063517271912</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.41851383759645217</Real>
+        <Real Name="Y">-0.54136147962012515</Real>
+        <Real Name="Z">-1.0692260442341768</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.811887746361766</Real>
+        <Real Name="Y">0.94649342782738122</Real>
+        <Real Name="Z">0.054135638015422621</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.3941227301346828</Real>
+        <Real Name="Y">61.471830024453766</Real>
+        <Real Name="Z">-373.33287614159565</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.9392597337124826</Real>
+        <Real Name="Y">1.2098667482349441</Real>
+        <Real Name="Z">111.94159270722828</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.522514413002</Real>
+        <Real Name="Y">63.068208626590689</Real>
+        <Real Name="Z">206.24058096058414</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.71236393208271</Real>
+        <Real Name="Y">-19.029171451089304</Real>
+        <Real Name="Z">-38.894779714127836</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.666185998404437</Real>
+        <Real Name="Y">-9.5466951513821776</Real>
+        <Real Name="Z">-24.622022353167388</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4690415863669131</Real>
+        <Real Name="Y">10.594948077038083</Real>
+        <Real Name="Z">12.959540483407892</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.617134429303363</Real>
+        <Real Name="Y">-7.1735503778465315</Real>
+        <Real Name="Z">-33.310611119395872</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-57.079432230843494</Real>
+        <Real Name="Y">11.232953039262725</Real>
+        <Real Name="Z">-15.139060246843357</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.688623471022858</Real>
+        <Real Name="Y">18.952447298726746</Real>
+        <Real Name="Z">56.569986070735524</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-309.40083551989301</Real>
+        <Real Name="Y">-123.45769934839541</Real>
+        <Real Name="Z">255.94261768929547</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.99835862900824</Real>
+        <Real Name="Y">107.5308383297031</Real>
+        <Real Name="Z">-280.79028987259801</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">114.07862803947106</Real>
+        <Real Name="Y">55.469518801119861</Real>
+        <Real Name="Z">-58.103888009262931</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-58.389889078123531</Real>
+        <Real Name="Y">-240.52397367006111</Real>
+        <Real Name="Z">-2.0011259053333106</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.1344510553070783</Real>
+        <Real Name="Y">45.339321708908514</Real>
+        <Real Name="Z">17.045843326876792</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.36843214648195</Real>
+        <Real Name="Y">24.861157344736085</Real>
+        <Real Name="Z">165.49449212419626</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8630381463634116</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8630381463634116</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8630381463634116</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070034293140865999</Real>
+        <Real Name="Y">0.60023884245296899</Real>
+        <Real Name="Z">0.23245336275209816</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0042050949927956273</Real>
+        <Real Name="Y">0.67795149068612759</Real>
+        <Real Name="Z">0.28826762642739218</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.081911490920722058</Real>
+        <Real Name="Y">0.61486639054635928</Real>
+        <Real Name="Z">0.174685417115165</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97393769498390548</Real>
+        <Real Name="Y">0.63070202575719958</Real>
+        <Real Name="Z">1.574262345254924</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94197984763382969</Real>
+        <Real Name="Y">0.57368631203055054</Real>
+        <Real Name="Z">1.6441924731040116</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90304493650959738</Real>
+        <Real Name="Y">0.69345763435339147</Real>
+        <Real Name="Z">1.5601815503333052</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3967051118004143</Real>
+        <Real Name="Y">0.44691025937279988</Real>
+        <Real Name="Z">1.1641843278661255</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3345128675543836</Real>
+        <Real Name="Y">0.47061437138194168</Real>
+        <Real Name="Z">1.2329779193518131</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3424531589383262</Real>
+        <Real Name="Y">0.4328757715622859</Real>
+        <Real Name="Z">1.0865822843199284</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6423965888528338</Real>
+        <Real Name="Y">0.31907531116763421</Real>
+        <Real Name="Z">0.31242215029253356</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7050820103563928</Real>
+        <Real Name="Y">0.34980566163483662</Real>
+        <Real Name="Z">0.24693549599500755</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6267835212181649</Real>
+        <Real Name="Y">0.22744696303254952</Real>
+        <Real Name="Z">0.28955741025310588</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7806875759419867</Real>
+        <Real Name="Y">0.39118843407789672</Real>
+        <Real Name="Z">0.024242507319622877</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6916820979143103</Real>
+        <Real Name="Y">0.42155231892829509</Real>
+        <Real Name="Z">0.0063993635984005426</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8171028014258583</Real>
+        <Real Name="Y">0.45704169561420105</Real>
+        <Real Name="Z">0.083399904980350797</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.16099897782621023</Real>
+        <Real Name="Y">0.082132730699561479</Real>
+        <Real Name="Z">-0.92927884455511434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67514960405355651</Real>
+        <Real Name="Y">-1.9289190286606255</Real>
+        <Real Name="Z">2.0127094590958796</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5391166519071575</Real>
+        <Real Name="Y">0.21508357436962466</Real>
+        <Real Name="Z">2.0615796847262429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11046681605259275</Real>
+        <Real Name="Y">-0.05098050769496619</Real>
+        <Real Name="Z">0.27981299770332141</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22754372024930156</Real>
+        <Real Name="Y">-2.4279309437385805</Real>
+        <Real Name="Z">-1.6446991111528781</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.73580571266190886</Real>
+        <Real Name="Y">-0.53489076561220594</Real>
+        <Real Name="Z">1.2180526985939195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.072691092092485227</Real>
+        <Real Name="Y">-0.019675511989091846</Real>
+        <Real Name="Z">-0.63895192181234006</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42004371255767609</Real>
+        <Real Name="Y">-0.35887117786173806</Real>
+        <Real Name="Z">-0.071683490059401334</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.65385772842294831</Real>
+        <Real Name="Y">0.1567324802785473</Real>
+        <Real Name="Z">-0.26782350231956686</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23488682779265865</Real>
+        <Real Name="Y">0.33929631342488664</Real>
+        <Real Name="Z">0.57018479888388507</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31679978966615058</Real>
+        <Real Name="Y">1.3934778502638365</Real>
+        <Real Name="Z">1.5744500823052376</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2346619201192781</Real>
+        <Real Name="Y">-0.15595295036109516</Real>
+        <Real Name="Z">0.72925145761455157</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.031741794282141744</Real>
+        <Real Name="Y">0.046178102770435284</Real>
+        <Real Name="Z">0.013838194313965688</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.64038710802313481</Real>
+        <Real Name="Y">-0.32384536645439521</Real>
+        <Real Name="Z">2.5413771247845136</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.35205812433158573</Real>
+        <Real Name="Y">-2.3354589348193056</Real>
+        <Real Name="Z">3.0272357656528368</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-163.48546373939337</Real>
+        <Real Name="Y">-310.75411730458194</Real>
+        <Real Name="Z">-381.34931604107805</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">13.923110913004955</Real>
+        <Real Name="Y">66.703128403433965</Real>
+        <Real Name="Z">100.57343740934895</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.22490969970499</Real>
+        <Real Name="Y">140.13888559260454</Real>
+        <Real Name="Z">74.695700255803587</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.225487113344172</Real>
+        <Real Name="Y">-15.042691265259229</Real>
+        <Real Name="Z">-36.583313588682771</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.830116372652995</Real>
+        <Real Name="Y">-7.1623282197692344</Real>
+        <Real Name="Z">-24.493258854407252</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1874149270702361</Real>
+        <Real Name="Y">7.4141045708519542</Real>
+        <Real Name="Z">12.146730603651378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.520592859436249</Real>
+        <Real Name="Y">-17.397509644589981</Real>
+        <Real Name="Z">-31.366479913676656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.647382947811863</Real>
+        <Real Name="Y">14.766881970065565</Real>
+        <Real Name="Z">25.286448600110525</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.741398470551317</Real>
+        <Real Name="Y">17.42154258870093</Real>
+        <Real Name="Z">55.009873153004776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-183.26423481765099</Real>
+        <Real Name="Y">2.1973877845149445</Real>
+        <Real Name="Z">106.00992936597322</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">148.94547691998719</Real>
+        <Real Name="Y">-32.090309670933152</Real>
+        <Real Name="Z">-89.083168640373984</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.576241076474901</Real>
+        <Real Name="Y">10.618023629111903</Real>
+        <Real Name="Z">-49.960030440597095</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-53.988044470820512</Real>
+        <Real Name="Y">-309.54135212844915</Real>
+        <Real Name="Z">-19.093567910715365</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-18.845299459592596</Real>
+        <Real Name="Y">114.92103983386656</Real>
+        <Real Name="Z">0.20860302884248938</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.913303878285397</Real>
+        <Real Name="Y">317.80731386043237</Real>
+        <Real Name="Z">257.99841297279625</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4529770401682987</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4529770401682987</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4529770401682987</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4529770401682987</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4533416426810541</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4533416426810541</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4533416426810541</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4533416426810541</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4533416426810541</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4533416426810541</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.466439846779636</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.466439846779636</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.453849777960853</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.453849777960853</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.453849777960853</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.453849777960853</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">17.432463115567113</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">16.020967458645281</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">17.434780469138921</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">17.433452881673624</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">17.433567562733728</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">19.960366458965474</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">19.960411298954877</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">19.959926674522031</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">19.958765551645634</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">19.956797106748475</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">19.866207838055072</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">20.598432684275735</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">19.884123522804757</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">17.368368275119323</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">17.366908229450505</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">17.365283548378756</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">17.363563440758636</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">27.096610978600332</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">28.406269583094865</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.807603134684776</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.889501262149846</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">30.12215451500505</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">31.748660938388916</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">32.989027139778521</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">34.378941373350045</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.905996151209841</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">37.550315719937231</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">39.283388076747485</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">40.301481878146689</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">41.306693688391952</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">37.31811995227693</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">38.690055145764532</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">40.114311497387597</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">41.566701074051167</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673364533766927</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5717298803356723</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5592504214319423</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6424761363623084</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8750147081574067</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.562547573510024</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.802868934910226</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.193267792914597</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.721483693650789</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.367771707275338</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.103708015544157</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-22.870987165956652</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.590508137672895</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.856769244176011</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.23016448333243</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.656045516027245</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.110155200310935</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.004987833407605083</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858972</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391528</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.02498992600415597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208519</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.20819690585540773</Real>
+        <Real Name="Y">-0.71831964871349085</Real>
+        <Real Name="Z">0.011078438999830157</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.65627408040347335</Real>
+        <Real Name="Y">-0.44130069592945115</Real>
+        <Real Name="Z">-0.19586161682440933</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.07944772612600022</Real>
+        <Real Name="Y">-1.3403514765108808</Real>
+        <Real Name="Z">0.094211853505395182</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43983396430402821</Real>
+        <Real Name="Y">-0.12730113827963044</Real>
+        <Real Name="Z">0.16848744653097211</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1064634752554481</Real>
+        <Real Name="Y">1.208306314237934</Real>
+        <Real Name="Z">0.58865730101337532</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3857124030917944</Real>
+        <Real Name="Y">0.65412452380296571</Real>
+        <Real Name="Z">0.10516368028532735</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.41357531425471322</Real>
+        <Real Name="Y">0.03909994936372093</Real>
+        <Real Name="Z">0.41653530543680806</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.30958260222840822</Real>
+        <Real Name="Y">0.032508253652296773</Real>
+        <Real Name="Z">1.2155924310115984</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7555728294294284</Real>
+        <Real Name="Y">-2.0294504264852296</Real>
+        <Real Name="Z">1.568589118909621</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25622123762474486</Real>
+        <Real Name="Y">0.31483429896995041</Real>
+        <Real Name="Z">-0.34178744751437573</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.1457763418811992</Real>
+        <Real Name="Y">0.34295833952026589</Real>
+        <Real Name="Z">-0.4239403762530316</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019644304201244064</Real>
+        <Real Name="Y">0.5193023809855738</Real>
+        <Real Name="Z">-0.45124050611198896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15257163555120895</Real>
+        <Real Name="Y">0.53524540919668817</Real>
+        <Real Name="Z">-0.26925935975066168</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25467201556722202</Real>
+        <Real Name="Y">-0.76836408689837199</Real>
+        <Real Name="Z">-1.2156468083482905</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.9200810679380822</Real>
+        <Real Name="Y">1.1308821580758028</Real>
+        <Real Name="Z">-1.0483019686667092</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959196342</Real>
+        <Real Name="Y">10.126334215507086</Real>
+        <Real Name="Z">-383.9244463652023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773668</Real>
+        <Real Name="Y">8.7835602768706877</Real>
+        <Real Name="Z">109.98162207856127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818237</Real>
+        <Real Name="Y">125.90227601095691</Real>
+        <Real Name="Z">223.10402606189822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.9064510541798</Real>
+        <Real Name="Y">-91.873016441468678</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733365</Real>
+        <Real Name="Y">82.504344401698347</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041526</Real>
+        <Real Name="Y">45.329959216167893</Real>
+        <Real Name="Z">-56.291380508471349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448434</Real>
+        <Real Name="Y">-204.77938512046111</Real>
+        <Real Name="Z">21.695070286562498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013951</Real>
+        <Real Name="Y">47.5995038096992</Real>
+        <Real Name="Z">-24.246658126595179</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564435093</Real>
+        <Real Name="Y">-23.593576368970304</Real>
+        <Real Name="Z">144.65217639452101</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617793935156957</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617793935156957</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617793935156957</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059497489680088696</Real>
+        <Real Name="Y">0.59954474591460905</Real>
+        <Real Name="Z">0.23896244154207297</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.85733712531583</Real>
+        <Real Name="Y">0.68765816975566385</Real>
+        <Real Name="Z">0.27488386854864905</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062270910876357242</Real>
+        <Real Name="Y">0.61130311315342034</Real>
+        <Real Name="Z">0.1624641675669668</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97412100475152308</Real>
+        <Real Name="Y">0.63062490897984402</Real>
+        <Real Name="Z">1.5709736647415606</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94453793267171193</Real>
+        <Real Name="Y">0.5935857493575678</Real>
+        <Real Name="Z">1.6541317124627282</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90865659026399603</Real>
+        <Real Name="Y">0.69713445057591383</Real>
+        <Real Name="Z">1.5496849420817664</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396294903629369</Real>
+        <Real Name="Y">0.44676994228141126</Real>
+        <Real Name="Z">1.1685669744531675</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3309123546246615</Real>
+        <Real Name="Y">0.47336310515747404</Real>
+        <Real Name="Z">1.2332217838171569</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3460697678465297</Real>
+        <Real Name="Y">0.43150877959305761</Real>
+        <Real Name="Z">1.0885241668500196</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6431129392838568</Real>
+        <Real Name="Y">0.31603203750836351</Real>
+        <Real Name="Z">0.30738220783342612</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7025944179937127</Real>
+        <Real Name="Y">0.33834405936467216</Real>
+        <Real Name="Z">0.23578300552521403</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6088127744338652</Real>
+        <Real Name="Y">0.22975868774674407</Real>
+        <Real Name="Z">0.2840857228588124</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7789743571206655</Real>
+        <Real Name="Y">0.39112882319714565</Real>
+        <Real Name="Z">0.024530529128927555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6974077188001733</Real>
+        <Real Name="Y">0.42091470982710288</Real>
+        <Real Name="Z">1.8460358258731142</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8181431683175646</Real>
+        <Real Name="Y">0.47051212388911878</Real>
+        <Real Name="Z">0.060950498934914638</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11295928879195838</Real>
+        <Real Name="Y">-0.019810152916361776</Real>
+        <Real Name="Z">-0.7091740455152965</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4541386558688667</Real>
+        <Real Name="Y">-0.56090337079871344</Real>
+        <Real Name="Z">1.0797595842436403</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0424954019405153</Real>
+        <Real Name="Y">0.43998062828451961</Real>
+        <Real Name="Z">0.74261043597057241</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.096717874317655828</Real>
+        <Real Name="Y">-0.036783786364896154</Real>
+        <Real Name="Z">0.27525328830092083</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63530928981423973</Real>
+        <Real Name="Y">-2.653357814132856</Real>
+        <Real Name="Z">-1.0286557753984651</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.85229180548980521</Real>
+        <Real Name="Y">-0.49063768637034177</Real>
+        <Real Name="Z">1.1447800514230897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.058474059842274023</Real>
+        <Real Name="Y">-0.021643152201569638</Real>
+        <Real Name="Z">-0.65761309070313434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22556622423131917</Real>
+        <Real Name="Y">-0.40557893274064205</Real>
+        <Real Name="Z">-0.20913985680379593</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.4596896861246364</Real>
+        <Real Name="Y">0.10625580850547581</Real>
+        <Real Name="Z">-0.43167109729833381</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2181375713334727</Real>
+        <Real Name="Y">0.37040374508161944</Real>
+        <Real Name="Z">0.64817635091512926</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.013139411969303405</Real>
+        <Real Name="Y">1.4088544235030227</Real>
+        <Real Name="Z">1.1326228327458763</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8894033810587525</Real>
+        <Real Name="Y">-0.49254882803135419</Real>
+        <Real Name="Z">0.62960817115902157</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11267959865455497</Real>
+        <Real Name="Y">-0.095850161641488185</Real>
+        <Real Name="Z">-0.068546937320408785</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1882020324368332</Real>
+        <Real Name="Y">0.51005532020072941</Real>
+        <Real Name="Z">2.8806764236310203</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11876382379300601</Real>
+        <Real Name="Y">-0.97813748633801134</Real>
+        <Real Name="Z">2.184571736779815</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-65.82370315010192</Real>
+        <Real Name="Y">-107.78820676062281</Real>
+        <Real Name="Z">-417.92487967579598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10817370513766633</Real>
+        <Real Name="Y">34.996498801787666</Real>
+        <Real Name="Z">108.980421149503</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">176.49144680944841</Real>
+        <Real Name="Y">148.22110028196056</Real>
+        <Real Name="Z">169.25079492177724</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.768837295590899</Real>
+        <Real Name="Y">-14.345078363599548</Real>
+        <Real Name="Z">-37.687768936943542</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.747333729876509</Real>
+        <Real Name="Y">-8.0413327165387294</Real>
+        <Real Name="Z">-23.767429712688802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3226519002757868</Real>
+        <Real Name="Y">7.6881209646619553</Real>
+        <Real Name="Z">12.80020012224189</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.263941658804043</Real>
+        <Real Name="Y">-14.270333440101552</Real>
+        <Real Name="Z">-33.009606566812266</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.512784930936022</Real>
+        <Real Name="Y">12.051544747936084</Real>
+        <Real Name="Z">27.19280835139152</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.944675853059657</Real>
+        <Real Name="Y">16.91707880764179</Real>
+        <Real Name="Z">54.4717967428112</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-258.17278256155527</Real>
+        <Real Name="Y">-52.474223973510448</Real>
+        <Real Name="Z">177.98862822391294</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">212.33231992151286</Real>
+        <Real Name="Y">26.3434459903375</Real>
+        <Real Name="Z">-198.89503947445411</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.904020839178472</Real>
+        <Real Name="Y">33.282804183521449</Real>
+        <Real Name="Z">-54.025979233981396</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-61.081197910814922</Real>
+        <Real Name="Y">-234.73650874889756</Real>
+        <Real Name="Z">8.4394234438922808</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.080375418036198</Real>
+        <Real Name="Y">75.226860153150668</Real>
+        <Real Name="Z">-10.68219526122823</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.677902234769078</Real>
+        <Real Name="Y">76.928230072273038</Real>
+        <Real Name="Z">216.86882590637413</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8618282576554581</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8618282576554581</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8618282576554581</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0012680070157763143</Real>
+        <Real Name="Y">0.58889656101820098</Real>
+        <Real Name="Z">0.24145737706290119</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8539951113931183</Real>
+        <Real Name="Y">0.67526939218540616</Real>
+        <Real Name="Z">0.28169692782045141</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076786292004714249</Real>
+        <Real Name="Y">0.597373419358326</Real>
+        <Real Name="Z">0.18325557378318519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98202595343942767</Real>
+        <Real Name="Y">0.62900139552856427</Real>
+        <Real Name="Z">1.5715412392109571</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97424721165723205</Real>
+        <Real Name="Y">0.63158466983877359</Real>
+        <Real Name="Z">1.6669096630740143</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94102033949788966</Real>
+        <Real Name="Y">0.71025874883839346</Real>
+        <Real Name="Z">1.5419084776393666</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3888502471000888</Real>
+        <Real Name="Y">0.44755384076002563</Real>
+        <Real Name="Z">1.1804389861635949</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3380313625638636</Real>
+        <Real Name="Y">0.47833346849088071</Real>
+        <Real Name="Z">1.2554881293382074</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3258495553063456</Real>
+        <Real Name="Y">0.39920867498558649</Real>
+        <Real Name="Z">1.1269976521631087</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6488781805007131</Real>
+        <Real Name="Y">0.31822662088051401</Real>
+        <Real Name="Z">0.29576723860698884</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7082429686150358</Real>
+        <Real Name="Y">0.34155050106894796</Real>
+        <Real Name="Z">0.22439401572125434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6023274117330111</Real>
+        <Real Name="Y">0.24087432882977139</Real>
+        <Real Name="Z">0.26395580604521718</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7746496482683871</Real>
+        <Real Name="Y">0.3994124445860715</Real>
+        <Real Name="Z">0.02049990240976279</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7158656225457205</Real>
+        <Real Name="Y">0.40746057115098261</Real>
+        <Real Name="Z">1.8072150162178771</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7872807948115466</Real>
+        <Real Name="Y">0.48931710052433031</Real>
+        <Real Name="Z">0.050830174047654303</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21518382289000587</Real>
+        <Real Name="Y">-0.6006719188763523</Real>
+        <Real Name="Z">-0.34267470683069251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.35502447322248032</Real>
+        <Real Name="Y">-1.4280686059168914</Real>
+        <Real Name="Z">1.6228192044971546</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.413712154207639</Real>
+        <Real Name="Y">-0.82773106157686205</Real>
+        <Real Name="Z">2.8859476178107255</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43567141915559776</Real>
+        <Real Name="Y">-0.10363833445871723</Real>
+        <Real Name="Z">0.17184867270973336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6173729297075146</Real>
+        <Real Name="Y">0.84809242144925767</Real>
+        <Real Name="Z">0.25456048182113294</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6591722746275628</Real>
+        <Real Name="Y">0.46243160946515277</Real>
+        <Real Name="Z">-0.0001414863100911469</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.54798151806715023</Real>
+        <Real Name="Y">0.024985942812960994</Real>
+        <Real Name="Z">0.38756627286684325</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.60060952511992305</Real>
+        <Real Name="Y">0.20997260517083199</Real>
+        <Real Name="Z">1.1018736045673339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96381900827747946</Real>
+        <Real Name="Y">-1.7984724396187226</Real>
+        <Real Name="Z">2.4546564360853882</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24091656955059756</Real>
+        <Real Name="Y">0.31893810140481799</Real>
+        <Real Name="Z">-0.41588783488640252</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39470045154243971</Real>
+        <Real Name="Y">1.3017327387206186</Real>
+        <Real Name="Z">0.024894001272350252</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.8172285215091033</Real>
+        <Real Name="Y">0.3254004920845277</Real>
+        <Real Name="Z">-1.2922307068915286</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20588270592463648</Real>
+        <Real Name="Y">0.39750990423514826</Real>
+        <Real Name="Z">-0.26273107384422778</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.52392191061873283</Real>
+        <Real Name="Y">-0.0081608448836794842</Real>
+        <Real Name="Z">-0.88456194223226592</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7758741700014493</Real>
+        <Real Name="Y">0.32556018067255987</Real>
+        <Real Name="Z">1.1633153216753001</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-77.356100506311577</Real>
+        <Real Name="Y">70.170638032984073</Real>
+        <Real Name="Z">-362.04920053458926</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.6489688617908413</Real>
+        <Real Name="Y">-0.57213455818137504</Real>
+        <Real Name="Z">111.88115295907286</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">134.11358401103371</Real>
+        <Real Name="Y">-1.1275619799829002</Real>
+        <Real Name="Z">131.56117607658391</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">24.032623617448124</Real>
+        <Real Name="Y">-24.072529091479964</Real>
+        <Real Name="Z">-37.549696519389286</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.7745842237669862</Real>
+        <Real Name="Y">7.2290138535279596</Real>
+        <Real Name="Z">14.341700053168161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.4044192231882562</Real>
+        <Real Name="Y">13.022907136416237</Real>
+        <Real Name="Z">11.775884264320787</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.82239808605965</Real>
+        <Real Name="Y">-3.6600465237815598</Real>
+        <Real Name="Z">-32.223099363799065</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.434141411109024</Real>
+        <Real Name="Y">8.8829687542290898</Real>
+        <Real Name="Z">-18.329386901253599</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.262063549721148</Real>
+        <Real Name="Y">4.228772926346295</Real>
+        <Real Name="Z">18.148065076114193</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-316.78622386144355</Real>
+        <Real Name="Y">-133.42735264632881</Real>
+        <Real Name="Z">278.88299873935443</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">244.78555591896446</Real>
+        <Real Name="Y">102.67623878036966</Real>
+        <Real Name="Z">-285.58602551485603</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">119.08485863952549</Real>
+        <Real Name="Y">61.270489979892133</Real>
+        <Real Name="Z">-65.326520892603796</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-75.333094797193723</Real>
+        <Real Name="Y">-324.28442419905025</Real>
+        <Real Name="Z">-36.753411522803958</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.983232952119906</Real>
+        <Real Name="Y">57.894350467987287</Real>
+        <Real Name="Z">26.217292235544647</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.120594514207966</Real>
+        <Real Name="Y">161.76866906705209</Real>
+        <Real Name="Z">245.00907184513613</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_Crescale_4Ranks_2RanksPerSimulation_s.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_Crescale_4Ranks_2RanksPerSimulation_s.xml
new file mode 100644 (file)
index 0000000..b953e8a
--- /dev/null
@@ -0,0 +1,1696 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.453341</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.453341</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.453341</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.453341</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4529767</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4529767</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4529767</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4529767</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4529767</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4529767</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4538493</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4538493</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4664402</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4664402</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4664402</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4664402</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">19.965998</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">20.842831</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">19.960037</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">19.959253</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">19.959911</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">17.433645</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">17.4338</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">17.433693</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">17.433418</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">17.380611</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">17.379568</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">17.729788</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">17.369326</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">19.877855</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">19.87261</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">19.867712</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">19.86376</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629341</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.229382</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">28.967957</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.73731</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">30.664227</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">30.504295</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">31.035324</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">31.713757</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">32.536671</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">33.446373</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">34.434612</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">35.175953</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">36.01992</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">43.014736</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">44.621765</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">46.067532</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">47.296928</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733761</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.160797</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.782166</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.552303</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.478561</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.257077</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.787951</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.46649</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.289679</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.252188</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.241055</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.35318</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.55761</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.304798</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-27.917072</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.367737</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.601086</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951088</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154483</Real>
+        <Real Name="Y">0.6098752</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829585</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13824016</Real>
+        <Real Name="Y">-0.083002254</Real>
+        <Real Name="Z">-0.55156869</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807338</Real>
+        <Real Name="Y">0.12595503</Real>
+        <Real Name="Z">0.08634457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50557774</Real>
+        <Real Name="Y">-0.26347136</Real>
+        <Real Name="Z">-0.37042338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.080341488</Real>
+        <Real Name="Y">-0.036381338</Real>
+        <Real Name="Z">0.26949763</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0880266</Real>
+        <Real Name="Y">-2.6992292</Real>
+        <Real Name="Z">-0.41159728</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0053114</Real>
+        <Real Name="Y">-0.44618708</Real>
+        <Real Name="Z">1.1535001</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046993256</Real>
+        <Real Name="Y">-0.027141552</Real>
+        <Real Name="Z">-0.68357778</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.05199106</Real>
+        <Real Name="Y">-0.4239299</Real>
+        <Real Name="Z">-0.38236642</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25138497</Real>
+        <Real Name="Y">0.072344288</Real>
+        <Real Name="Z">-0.58373684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20046791</Real>
+        <Real Name="Y">0.39459822</Real>
+        <Real Name="Z">0.71750742</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21663751</Real>
+        <Real Name="Y">1.2108051</Real>
+        <Real Name="Z">0.86115432</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3770657</Real>
+        <Real Name="Y">-0.66109234</Real>
+        <Real Name="Z">0.87071204</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2170116</Real>
+        <Real Name="Y">-0.090551436</Real>
+        <Real Name="Z">-0.034702588</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639975</Real>
+        <Real Name="Y">0.96362239</Real>
+        <Real Name="Z">2.5346055</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37430629</Real>
+        <Real Name="Y">-0.3790665</Real>
+        <Real Name="Z">0.73122531</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9518738</Real>
+        <Real Name="Y">10.126022</Real>
+        <Real Name="Z">-383.92468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054081</Real>
+        <Real Name="Y">8.7835617</Real>
+        <Real Name="Z">109.98161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.0733</Real>
+        <Real Name="Y">125.90257</Real>
+        <Real Name="Z">223.10434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850433</Real>
+        <Real Name="Y">8.0224648</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90619</Real>
+        <Real Name="Y">-91.872864</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62735</Real>
+        <Real Name="Y">82.504333</Real>
+        <Real Name="Z">-270.19894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937</Real>
+        <Real Name="Y">45.329948</Real>
+        <Real Name="Z">-56.291359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365723</Real>
+        <Real Name="Y">-204.77948</Real>
+        <Real Name="Z">21.695251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097099</Real>
+        <Real Name="Y">47.599464</Real>
+        <Real Name="Z">-24.246674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.29879</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65219</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617443</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617443</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617443</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0031319575</Real>
+        <Real Name="Y">0.59410781</Real>
+        <Real Name="Z">0.24342358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.849947</Real>
+        <Real Name="Y">0.6841858</Real>
+        <Real Name="Z">0.27215329</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059119962</Real>
+        <Real Name="Y">0.60250223</Real>
+        <Real Name="Z">0.16624072</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97844338</Real>
+        <Real Name="Y">0.62987453</Real>
+        <Real Name="Z">1.5701318</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96171379</Real>
+        <Real Name="Y">0.62405521</Real>
+        <Real Name="Z">1.6641986</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92800289</Real>
+        <Real Name="Y">0.70600235</Real>
+        <Real Name="Z">1.5414503</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3929865</Real>
+        <Real Name="Y">0.44727588</Real>
+        <Real Name="Z">1.1772089</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3333052</Real>
+        <Real Name="Y">0.4770745</Real>
+        <Real Name="Z">1.2458565</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3355341</Real>
+        <Real Name="Y">0.41434646</Real>
+        <Real Name="Z">1.1080917</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6468266</Real>
+        <Real Name="Y">0.31562862</Real>
+        <Real Name="Z">0.29898632</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7053698</Real>
+        <Real Name="Y">0.33263397</Real>
+        <Real Name="Z">0.22519043</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5972217</Real>
+        <Real Name="Y">0.2380382</Real>
+        <Real Name="Z">0.27288279</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7762097</Real>
+        <Real Name="Y">0.39600074</Real>
+        <Real Name="Z">0.022708815</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7119511</Real>
+        <Real Name="Y">0.40962258</Real>
+        <Real Name="Z">1.8148284</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8061577</Real>
+        <Real Name="Y">0.48406574</Real>
+        <Real Name="Z">0.045291938</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.24150857</Real>
+        <Real Name="Y">-0.71041775</Real>
+        <Real Name="Z">-0.13636526</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.61062574</Real>
+        <Real Name="Y">-0.81442577</Real>
+        <Real Name="Z">0.65641171</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6708878</Real>
+        <Real Name="Y">-0.637775</Real>
+        <Real Name="Z">1.2230791</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45217079</Real>
+        <Real Name="Y">-0.12316018</Real>
+        <Real Name="Z">0.16472577</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4644017</Real>
+        <Real Name="Y">1.0554943</Real>
+        <Real Name="Z">0.43087134</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5698447</Real>
+        <Real Name="Y">0.60451102</Real>
+        <Real Name="Z">0.099591739</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.49418238</Real>
+        <Real Name="Y">0.039484952</Real>
+        <Real Name="Z">0.41190496</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53571653</Real>
+        <Real Name="Y">0.092119634</Real>
+        <Real Name="Z">1.2978714</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.5286325</Real>
+        <Real Name="Y">-2.0089114</Real>
+        <Real Name="Z">2.1868899</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25595498</Real>
+        <Real Name="Y">0.32839361</Real>
+        <Real Name="Z">-0.39021632</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.29002714</Real>
+        <Real Name="Y">0.84646446</Real>
+        <Real Name="Z">-0.24582888</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.3910118</Real>
+        <Real Name="Y">0.40627581</Real>
+        <Real Name="Z">-0.88346249</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19990483</Real>
+        <Real Name="Y">0.46892008</Real>
+        <Real Name="Z">-0.28632975</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.41847819</Real>
+        <Real Name="Y">-0.54137141</Real>
+        <Real Name="Z">-1.0692643</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8118767</Real>
+        <Real Name="Y">0.94653052</Real>
+        <Real Name="Z">0.054143198</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.3932343</Real>
+        <Real Name="Y">61.471985</Real>
+        <Real Name="Z">-373.33313</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.9395561</Real>
+        <Real Name="Y">1.2095032</Real>
+        <Real Name="Z">111.94157</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.52182</Real>
+        <Real Name="Y">63.068405</Real>
+        <Real Name="Z">206.24097</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.712227</Real>
+        <Real Name="Y">-19.029125</Real>
+        <Real Name="Z">-38.894722</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.666203</Real>
+        <Real Name="Y">-9.5466843</Real>
+        <Real Name="Z">-24.622017</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4689865</Real>
+        <Real Name="Y">10.594925</Real>
+        <Real Name="Z">12.959534</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.617126</Real>
+        <Real Name="Y">-7.1735497</Real>
+        <Real Name="Z">-33.310593</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-57.079411</Real>
+        <Real Name="Y">11.232948</Real>
+        <Real Name="Z">-15.139088</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.688591</Real>
+        <Real Name="Y">18.952412</Real>
+        <Real Name="Z">56.569931</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-309.40076</Real>
+        <Real Name="Y">-123.45801</Real>
+        <Real Name="Z">255.94427</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.99826</Real>
+        <Real Name="Y">107.53157</Real>
+        <Real Name="Z">-280.79208</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">114.0788</Real>
+        <Real Name="Y">55.469704</Real>
+        <Real Name="Z">-58.104252</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-58.390854</Real>
+        <Real Name="Y">-240.52457</Real>
+        <Real Name="Z">-2.0006104</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.1347561</Real>
+        <Real Name="Y">45.339294</Real>
+        <Real Name="Z">17.045868</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.36783</Real>
+        <Real Name="Y">24.861153</Real>
+        <Real Name="Z">165.49438</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8630382</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8630382</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8630382</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070034377</Real>
+        <Real Name="Y">0.60023904</Real>
+        <Real Name="Z">0.23245336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0042053335</Real>
+        <Real Name="Y">0.67795169</Real>
+        <Real Name="Z">0.28826767</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.081911437</Real>
+        <Real Name="Y">0.6148665</Real>
+        <Real Name="Z">0.17468534</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97393769</Real>
+        <Real Name="Y">0.6307019</Real>
+        <Real Name="Z">1.5742624</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94197994</Real>
+        <Real Name="Y">0.57368624</Real>
+        <Real Name="Z">1.6441926</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.903045</Real>
+        <Real Name="Y">0.6934576</Real>
+        <Real Name="Z">1.5601817</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3967053</Real>
+        <Real Name="Y">0.44691035</Real>
+        <Real Name="Z">1.1641839</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3345132</Real>
+        <Real Name="Y">0.47061419</Real>
+        <Real Name="Z">1.2329776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3424531</Real>
+        <Real Name="Y">0.43287563</Real>
+        <Real Name="Z">1.0865821</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6423969</Real>
+        <Real Name="Y">0.31907523</Real>
+        <Real Name="Z">0.3124221</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7050822</Real>
+        <Real Name="Y">0.3498055</Real>
+        <Real Name="Z">0.24693525</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6267836</Real>
+        <Real Name="Y">0.22744691</Real>
+        <Real Name="Z">0.2895574</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7806878</Real>
+        <Real Name="Y">0.39118853</Real>
+        <Real Name="Z">0.024242504</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6916822</Real>
+        <Real Name="Y">0.42155224</Real>
+        <Real Name="Z">0.0063993931</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8171029</Real>
+        <Real Name="Y">0.45704186</Real>
+        <Real Name="Z">0.083399877</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.16099982</Real>
+        <Real Name="Y">0.082132831</Real>
+        <Real Name="Z">-0.92927921</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.6751458</Real>
+        <Real Name="Y">-1.9289031</Real>
+        <Real Name="Z">2.0127039</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5391154</Real>
+        <Real Name="Y">0.21510646</Real>
+        <Real Name="Z">2.0615685</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11046407</Real>
+        <Real Name="Y">-0.050984424</Real>
+        <Real Name="Z">0.27981615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22755328</Real>
+        <Real Name="Y">-2.4278982</Real>
+        <Real Name="Z">-1.6447234</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.73585057</Real>
+        <Real Name="Y">-0.53489017</Real>
+        <Real Name="Z">1.2180563</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.072699405</Real>
+        <Real Name="Y">-0.019674057</Real>
+        <Real Name="Z">-0.63895136</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42003757</Real>
+        <Real Name="Y">-0.35887378</Real>
+        <Real Name="Z">-0.071694024</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.65386122</Real>
+        <Real Name="Y">0.15672383</Real>
+        <Real Name="Z">-0.26782373</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23488146</Real>
+        <Real Name="Y">0.33929873</Real>
+        <Real Name="Z">0.57017773</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.3167716</Real>
+        <Real Name="Y">1.3934485</Real>
+        <Real Name="Z">1.574455</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2346468</Real>
+        <Real Name="Y">-0.15598421</Real>
+        <Real Name="Z">0.72924936</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.031746496</Real>
+        <Real Name="Y">0.046178374</Real>
+        <Real Name="Z">0.013839331</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.64048427</Real>
+        <Real Name="Y">-0.32380146</Real>
+        <Real Name="Z">2.5413594</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.3520712</Real>
+        <Real Name="Y">-2.3354311</Real>
+        <Real Name="Z">3.0272338</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-163.48514</Real>
+        <Real Name="Y">-310.75327</Real>
+        <Real Name="Z">-381.34961</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">13.923252</Real>
+        <Real Name="Y">66.702866</Real>
+        <Real Name="Z">100.57333</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.22491</Real>
+        <Real Name="Y">140.1387</Real>
+        <Real Name="Z">74.695824</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.225449</Real>
+        <Real Name="Y">-15.042759</Real>
+        <Real Name="Z">-36.583168</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.830078</Real>
+        <Real Name="Y">-7.162281</Real>
+        <Real Name="Z">-24.493279</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1873703</Real>
+        <Real Name="Y">7.4141235</Real>
+        <Real Name="Z">12.146671</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.520584</Real>
+        <Real Name="Y">-17.397434</Real>
+        <Real Name="Z">-31.366451</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.647354</Real>
+        <Real Name="Y">14.766821</Real>
+        <Real Name="Z">25.286358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.741383</Real>
+        <Real Name="Y">17.421532</Real>
+        <Real Name="Z">55.009865</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-183.26425</Real>
+        <Real Name="Y">2.1970367</Real>
+        <Real Name="Z">106.0096</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">148.94583</Real>
+        <Real Name="Y">-32.090393</Real>
+        <Real Name="Z">-89.083359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.576149</Real>
+        <Real Name="Y">10.617966</Real>
+        <Real Name="Z">-49.959679</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-53.988037</Real>
+        <Real Name="Y">-309.5415</Real>
+        <Real Name="Z">-19.09314</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-18.845303</Real>
+        <Real Name="Y">114.92148</Real>
+        <Real Name="Z">0.20840454</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.91259</Real>
+        <Real Name="Y">317.80716</Real>
+        <Real Name="Z">257.99866</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4529767</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4529767</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4529767</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4529767</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.453341</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.453341</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.453341</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.453341</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.453341</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.453341</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4664402</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4664402</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4538493</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4538493</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4538493</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4538493</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">17.432463</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">16.020971</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">17.434881</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">17.433516</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">17.433643</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">19.960379</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">19.960409</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">19.960003</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">19.958788</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">19.956701</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">19.866152</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">20.598333</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">19.883961</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">17.368425</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">17.367149</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">17.365492</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">17.363823</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">27.096624</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">28.406281</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.807617</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.889538</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">30.122219</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">31.748699</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">32.989037</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">34.378929</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.905952</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">37.550236</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">39.283287</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">40.301361</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">41.306534</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">37.318253</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">38.690216</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">40.114479</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">41.566837</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733761</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5717344</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5591621</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6424494</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8750019</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.562567</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.802874</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.193172</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.721411</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.367781</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.103645</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-22.870945</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.59049</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.856842</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.230082</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.656002</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.110029</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951088</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154483</Real>
+        <Real Name="Y">0.6098752</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829585</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.2081964</Real>
+        <Real Name="Y">-0.7183184</Real>
+        <Real Name="Z">0.011077392</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.65627712</Real>
+        <Real Name="Y">-0.44132945</Real>
+        <Real Name="Z">-0.19586644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.079432383</Real>
+        <Real Name="Y">-1.3403528</Real>
+        <Real Name="Z">0.0942358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43983412</Real>
+        <Real Name="Y">-0.12730011</Real>
+        <Real Name="Z">0.16848481</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1064552</Real>
+        <Real Name="Y">1.2083107</Real>
+        <Real Name="Z">0.58867824</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3857259</Real>
+        <Real Name="Y">0.65410167</Real>
+        <Real Name="Z">0.10518272</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.41357264</Real>
+        <Real Name="Y">0.039098304</Real>
+        <Real Name="Z">0.41653091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.30952451</Real>
+        <Real Name="Y">0.032534141</Real>
+        <Real Name="Z">1.21565</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7555673</Real>
+        <Real Name="Y">-2.029453</Real>
+        <Real Name="Z">1.5685941</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25622329</Real>
+        <Real Name="Y">0.31483555</Real>
+        <Real Name="Z">-0.34178945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.14576393</Real>
+        <Real Name="Y">0.34296301</Real>
+        <Real Name="Z">-0.42390847</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.0196642</Real>
+        <Real Name="Y">0.51929116</Real>
+        <Real Name="Z">-0.45123479</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1525732</Real>
+        <Real Name="Y">0.53524446</Real>
+        <Real Name="Z">-0.26926085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25469711</Real>
+        <Real Name="Y">-0.76836795</Real>
+        <Real Name="Z">-1.2156236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.92007476</Real>
+        <Real Name="Y">1.1309038</Real>
+        <Real Name="Z">-1.048301</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9518738</Real>
+        <Real Name="Y">10.126022</Real>
+        <Real Name="Z">-383.92468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054081</Real>
+        <Real Name="Y">8.7835617</Real>
+        <Real Name="Z">109.98161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.0733</Real>
+        <Real Name="Y">125.90257</Real>
+        <Real Name="Z">223.10434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850433</Real>
+        <Real Name="Y">8.0224648</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90619</Real>
+        <Real Name="Y">-91.872864</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62735</Real>
+        <Real Name="Y">82.504333</Real>
+        <Real Name="Z">-270.19894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937</Real>
+        <Real Name="Y">45.329948</Real>
+        <Real Name="Z">-56.291359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365723</Real>
+        <Real Name="Y">-204.77948</Real>
+        <Real Name="Z">21.695251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097099</Real>
+        <Real Name="Y">47.599464</Real>
+        <Real Name="Z">-24.246674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.29879</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65219</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8617793</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8617793</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8617793</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059497468</Real>
+        <Real Name="Y">0.59954488</Real>
+        <Real Name="Z">0.23896244</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8573372</Real>
+        <Real Name="Y">0.68765825</Real>
+        <Real Name="Z">0.27488393</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062270906</Real>
+        <Real Name="Y">0.61130315</Real>
+        <Real Name="Z">0.16246417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97412103</Real>
+        <Real Name="Y">0.63062483</Real>
+        <Real Name="Z">1.5709736</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94453794</Real>
+        <Real Name="Y">0.59358561</Real>
+        <Real Name="Z">1.6541317</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90865666</Real>
+        <Real Name="Y">0.69713449</Real>
+        <Real Name="Z">1.549685</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3962948</Real>
+        <Real Name="Y">0.44677001</Real>
+        <Real Name="Z">1.1685667</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3309122</Real>
+        <Real Name="Y">0.47336301</Real>
+        <Real Name="Z">1.2332217</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3460696</Real>
+        <Real Name="Y">0.43150869</Real>
+        <Real Name="Z">1.088524</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6431131</Real>
+        <Real Name="Y">0.31603196</Real>
+        <Real Name="Z">0.3073822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7025946</Real>
+        <Real Name="Y">0.33834395</Real>
+        <Real Name="Z">0.23578298</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6088127</Real>
+        <Real Name="Y">0.22975874</Real>
+        <Real Name="Z">0.28408563</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7789745</Real>
+        <Real Name="Y">0.39112881</Real>
+        <Real Name="Z">0.024530521</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6974078</Real>
+        <Real Name="Y">0.42091459</Real>
+        <Real Name="Z">1.8460358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8181432</Real>
+        <Real Name="Y">0.47051212</Real>
+        <Real Name="Z">0.060950533</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11295948</Real>
+        <Real Name="Y">-0.019809877</Real>
+        <Real Name="Z">-0.70917445</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4541506</Real>
+        <Real Name="Y">-0.56090975</Real>
+        <Real Name="Z">1.0797558</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.04248</Real>
+        <Real Name="Y">0.43999442</Real>
+        <Real Name="Z">0.74262029</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.096717991</Real>
+        <Real Name="Y">-0.03677937</Real>
+        <Real Name="Z">0.27524921</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63534307</Real>
+        <Real Name="Y">-2.6533642</Real>
+        <Real Name="Z">-1.0285974</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.8522501</Real>
+        <Real Name="Y">-0.49070704</Real>
+        <Real Name="Z">1.1448128</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.058483925</Real>
+        <Real Name="Y">-0.021639807</Real>
+        <Real Name="Z">-0.65760732</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22564423</Real>
+        <Real Name="Y">-0.40560803</Real>
+        <Real Name="Z">-0.20917757</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.45968559</Real>
+        <Real Name="Y">0.10623339</Real>
+        <Real Name="Z">-0.43173459</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21813262</Real>
+        <Real Name="Y">0.37040648</Real>
+        <Real Name="Z">0.64816988</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.013184894</Real>
+        <Real Name="Y">1.4088252</Real>
+        <Real Name="Z">1.1326584</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8893982</Real>
+        <Real Name="Y">-0.49256915</Real>
+        <Real Name="Z">0.62960845</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11267684</Real>
+        <Real Name="Y">-0.09584593</Real>
+        <Real Name="Z">-0.06854862</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.188189</Real>
+        <Real Name="Y">0.51003677</Real>
+        <Real Name="Z">2.8806968</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11874488</Real>
+        <Real Name="Y">-0.97814411</Real>
+        <Real Name="Z">2.1845779</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-65.823822</Real>
+        <Real Name="Y">-107.78876</Real>
+        <Real Name="Z">-417.92471</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10825729</Real>
+        <Real Name="Y">34.996468</Real>
+        <Real Name="Z">108.98035</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">176.49142</Real>
+        <Real Name="Y">148.22128</Real>
+        <Real Name="Z">169.25082</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.768799</Real>
+        <Real Name="Y">-14.345158</Real>
+        <Real Name="Z">-37.687744</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.747303</Real>
+        <Real Name="Y">-8.0412951</Real>
+        <Real Name="Z">-23.767414</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3226547</Real>
+        <Real Name="Y">7.6881638</Real>
+        <Real Name="Z">12.800201</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.263962</Real>
+        <Real Name="Y">-14.270321</Real>
+        <Real Name="Z">-33.009651</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.512745</Real>
+        <Real Name="Y">12.051531</Real>
+        <Real Name="Z">27.192776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.944672</Real>
+        <Real Name="Y">16.917082</Real>
+        <Real Name="Z">54.471825</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-258.17236</Real>
+        <Real Name="Y">-52.474335</Real>
+        <Real Name="Z">177.98836</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">212.332</Real>
+        <Real Name="Y">26.343597</Real>
+        <Real Name="Z">-198.89453</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.903984</Real>
+        <Real Name="Y">33.2827</Real>
+        <Real Name="Z">-54.025757</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-61.080505</Real>
+        <Real Name="Y">-234.73615</Real>
+        <Real Name="Z">8.4395752</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.080475</Real>
+        <Real Name="Y">75.227051</Real>
+        <Real Name="Z">-10.682419</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.678497</Real>
+        <Real Name="Y">76.928131</Real>
+        <Real Name="Z">216.86829</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8618282</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8618282</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8618282</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0012680263</Real>
+        <Real Name="Y">0.58889657</Real>
+        <Real Name="Z">0.24145733</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8539951</Real>
+        <Real Name="Y">0.67526931</Real>
+        <Real Name="Z">0.28169712</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076786317</Real>
+        <Real Name="Y">0.5973736</Real>
+        <Real Name="Z">0.18325557</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98202604</Real>
+        <Real Name="Y">0.62900144</Real>
+        <Real Name="Z">1.5715412</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97424716</Real>
+        <Real Name="Y">0.6315847</Real>
+        <Real Name="Z">1.6669096</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94102043</Real>
+        <Real Name="Y">0.71025884</Real>
+        <Real Name="Z">1.5419085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3888503</Real>
+        <Real Name="Y">0.44755378</Real>
+        <Real Name="Z">1.180439</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3380314</Real>
+        <Real Name="Y">0.47833353</Real>
+        <Real Name="Z">1.255488</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3258497</Real>
+        <Real Name="Y">0.39920875</Real>
+        <Real Name="Z">1.1269976</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6488782</Real>
+        <Real Name="Y">0.31822667</Real>
+        <Real Name="Z">0.29576725</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7082429</Real>
+        <Real Name="Y">0.34155035</Real>
+        <Real Name="Z">0.22439386</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6023269</Real>
+        <Real Name="Y">0.24087469</Real>
+        <Real Name="Z">0.26395583</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7746493</Real>
+        <Real Name="Y">0.39941245</Real>
+        <Real Name="Z">0.020499922</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7158655</Real>
+        <Real Name="Y">0.40746057</Real>
+        <Real Name="Z">1.8072149</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7872807</Real>
+        <Real Name="Y">0.48931718</Real>
+        <Real Name="Z">0.05082991</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21518007</Real>
+        <Real Name="Y">-0.60066378</Real>
+        <Real Name="Z">-0.34267539</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.35501426</Real>
+        <Real Name="Y">-1.4281516</Real>
+        <Real Name="Z">1.6228273</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4136987</Real>
+        <Real Name="Y">-0.82774597</Real>
+        <Real Name="Z">2.8859477</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43567014</Real>
+        <Real Name="Y">-0.10363892</Real>
+        <Real Name="Z">0.17185804</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6173677</Real>
+        <Real Name="Y">0.84813344</Real>
+        <Real Name="Z">0.25441116</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6591586</Real>
+        <Real Name="Y">0.46245411</Real>
+        <Real Name="Z">-0.00012940569</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.54797888</Real>
+        <Real Name="Y">0.024985965</Real>
+        <Real Name="Z">0.38756338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.60056323</Real>
+        <Real Name="Y">0.20997523</Real>
+        <Real Name="Z">1.1018997</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96387082</Real>
+        <Real Name="Y">-1.7984709</Real>
+        <Real Name="Z">2.4546807</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24091475</Real>
+        <Real Name="Y">0.3189342</Real>
+        <Real Name="Z">-0.41588789</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39471141</Real>
+        <Real Name="Y">1.3017385</Real>
+        <Real Name="Z">0.024843642</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.81724858</Real>
+        <Real Name="Y">0.32542676</Real>
+        <Real Name="Z">-1.2922425</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20588127</Real>
+        <Real Name="Y">0.39751759</Real>
+        <Real Name="Z">-0.26272884</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.52389097</Real>
+        <Real Name="Y">-0.0081827305</Real>
+        <Real Name="Z">-0.88461632</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7758739</Real>
+        <Real Name="Y">0.32554051</Real>
+        <Real Name="Z">1.1633112</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-77.354065</Real>
+        <Real Name="Y">70.172836</Real>
+        <Real Name="Z">-362.04892</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.6486549</Real>
+        <Real Name="Y">-0.57272339</Real>
+        <Real Name="Z">111.88117</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">134.11258</Real>
+        <Real Name="Y">-1.1278152</Real>
+        <Real Name="Z">131.56161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">24.032654</Real>
+        <Real Name="Y">-24.072487</Real>
+        <Real Name="Z">-37.549789</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.7745781</Real>
+        <Real Name="Y">7.2289886</Real>
+        <Real Name="Z">14.341713</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.4043922</Real>
+        <Real Name="Y">13.022867</Real>
+        <Real Name="Z">11.77589</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.822372</Real>
+        <Real Name="Y">-3.6600494</Real>
+        <Real Name="Z">-32.223083</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.434158</Real>
+        <Real Name="Y">8.8829842</Real>
+        <Real Name="Z">-18.329391</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.262085</Real>
+        <Real Name="Y">4.2287865</Real>
+        <Real Name="Z">18.148094</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-316.7865</Real>
+        <Real Name="Y">-133.42819</Real>
+        <Real Name="Z">278.88531</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">244.78528</Real>
+        <Real Name="Y">102.67735</Real>
+        <Real Name="Z">-285.58844</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">119.08507</Real>
+        <Real Name="Y">61.270538</Real>
+        <Real Name="Z">-65.326843</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-75.334595</Real>
+        <Real Name="Y">-324.28561</Real>
+        <Real Name="Z">-36.753235</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.983662</Real>
+        <Real Name="Y">57.894409</Real>
+        <Real Name="Z">26.217224</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.119949</Real>
+        <Real Name="Y">161.76813</Real>
+        <Real Name="Z">245.0087</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_ParrinelloRahman_4Ranks_1RanksPerSimulation_d.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_ParrinelloRahman_4Ranks_1RanksPerSimulation_d.xml
new file mode 100644 (file)
index 0000000..fadef16
--- /dev/null
@@ -0,0 +1,3398 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562600160298169</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562579188546056</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562579188546056</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562579188546056</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.45626001137515</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.45626001137515</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.45626001137515</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.45626001137515</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.45626001137515</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.45626001137515</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.45626001137515</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562747749874143</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562357501768357</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562357501768357</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562357501768357</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562357501768357</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">20.344745942447496</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">21.220300790042977</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">20.338968338604239</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">20.339788659740066</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">20.340470425463366</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">18.784005512646754</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">18.784033913689704</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">18.783971928972932</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">18.783781202827093</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">18.738928227198201</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">18.738358459938311</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">19.102676538677464</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">18.730712651506376</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">26.080945551340285</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">26.082342833425816</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">26.083697087379242</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">26.089918638527635</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629305410083006</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.225575681525967</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">28.961753624312852</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.732148146625004</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">30.658323547277583</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">31.486598844697532</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">32.013085983619447</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">32.687026657992931</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">33.505414373926897</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">34.409541292573842</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">35.390982054136799</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">36.115899171816835</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">36.94271491009642</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">36.231285150370191</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">36.948179604564189</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">37.754527433363798</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">38.638445054619268</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.158293500466156</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.775803894691784</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.545378095868104</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.470871730797388</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.231876912047969</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.758335649926936</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.43233830901719</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.250916751096993</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.19989664537283</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.181907174195681</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.284208467852794</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.482988093303465</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-13.186451915282612</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-13.901949087391078</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-14.706942662237262</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-15.584638732344336</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13823960248430167</Real>
+        <Real Name="Y">-0.083001582473174879</Real>
+        <Real Name="Z">-0.55156788526044775</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807346912896781</Real>
+        <Real Name="Y">0.12594239723743811</Real>
+        <Real Name="Z">0.08634003909985162</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50558175484200552</Real>
+        <Real Name="Y">-0.26347201049012287</Real>
+        <Real Name="Z">-0.37043107548326104</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.08034197360884994</Real>
+        <Real Name="Y">-0.036383374851252738</Real>
+        <Real Name="Z">0.26950251001929981</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0879938107726246</Real>
+        <Real Name="Y">-2.69925195488055</Real>
+        <Real Name="Z">-0.41161299800761308</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.005339856872981</Real>
+        <Real Name="Y">-0.44613327229712957</Real>
+        <Real Name="Z">1.1534368241800748</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046991365082634871</Real>
+        <Real Name="Y">-0.027139438957271687</Real>
+        <Real Name="Z">-0.68356956696424598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.05202773043970705</Real>
+        <Real Name="Y">-0.42394701288611158</Real>
+        <Real Name="Z">-0.38240890291446672</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25145271172169875</Real>
+        <Real Name="Y">0.072329295992862669</Real>
+        <Real Name="Z">-0.58384125172376966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20047275659675193</Real>
+        <Real Name="Y">0.39459474035999631</Real>
+        <Real Name="Z">0.71751226731035578</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21660158751017167</Real>
+        <Real Name="Y">1.2107968994948017</Real>
+        <Real Name="Z">0.86109126390401169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3771064228719012</Real>
+        <Real Name="Y">-0.66102181650660441</Real>
+        <Real Name="Z">0.8707144786748191</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2170122537672452</Real>
+        <Real Name="Y">-0.090547598182205036</Real>
+        <Real Name="Z">-0.034702681691129153</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639425064678223</Real>
+        <Real Name="Y">0.96363069485778263</Real>
+        <Real Name="Z">2.5346418773966413</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37424921124686311</Real>
+        <Real Name="Y">-0.37914050295285712</Real>
+        <Real Name="Z">0.73119277083077761</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620599995525136</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620599995525136</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620599995525136</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0031040011313863127</Real>
+        <Real Name="Y">0.59411113917648661</Real>
+        <Real Name="Z">0.24346636361975599</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8503569576232775</Real>
+        <Real Name="Y">0.68421937792947574</Real>
+        <Real Name="Z">0.27216436328236082</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059127305768975583</Real>
+        <Real Name="Y">0.6024008954100748</Real>
+        <Real Name="Z">0.1662977969680989</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97866662072466937</Real>
+        <Real Name="Y">0.6299661119403589</Real>
+        <Real Name="Z">1.5704246170261908</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96205654544697317</Real>
+        <Real Name="Y">0.62431684611278926</Real>
+        <Real Name="Z">1.6645230208111552</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92838253935370152</Real>
+        <Real Name="Y">0.70618573704314636</Real>
+        <Real Name="Z">1.5417122797847203</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3931591413870179</Real>
+        <Real Name="Y">0.44735627344308421</Real>
+        <Real Name="Z">1.1774620228233992</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3336068159053112</Real>
+        <Real Name="Y">0.47715393298895875</Real>
+        <Real Name="Z">1.2462220287520547</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3355844143016877</Real>
+        <Real Name="Y">0.41415577129281866</Real>
+        <Real Name="Z">1.1085766407890392</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6471414295532947</Real>
+        <Real Name="Y">0.31572496970507741</Real>
+        <Real Name="Z">0.29898882474718685</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7056693261098688</Real>
+        <Real Name="Y">0.33273707398781122</Real>
+        <Real Name="Z">0.22518237494409776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5974981595356113</Real>
+        <Real Name="Y">0.23816464596727133</Real>
+        <Real Name="Z">0.272868711354676</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7764890087360155</Real>
+        <Real Name="Y">0.39614456583291369</Real>
+        <Real Name="Z">0.022674046996585952</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.71231107661316</Real>
+        <Real Name="Y">0.40957501163931248</Real>
+        <Real Name="Z">1.8149978683208998</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.80631992093672</Real>
+        <Real Name="Y">0.48428039999039657</Real>
+        <Real Name="Z">0.045135342921759108</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.2450930020682206</Real>
+        <Real Name="Y">-0.72261954420787011</Real>
+        <Real Name="Z">-0.13603190963187844</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.62230721491797047</Real>
+        <Real Name="Y">-0.82352727352426924</Real>
+        <Real Name="Z">0.65246903173735371</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6712235444101649</Real>
+        <Real Name="Y">-0.66577640091029755</Real>
+        <Real Name="Z">1.2254681759537105</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.4592204003773061</Real>
+        <Real Name="Y">-0.12490435087041919</Real>
+        <Real Name="Z">0.16829959772585851</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4888188576988404</Real>
+        <Real Name="Y">1.0727456950577099</Real>
+        <Real Name="Z">0.43557819737171505</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5986663799298741</Real>
+        <Real Name="Y">0.61206312835724153</Real>
+        <Real Name="Z">0.096975482788899683</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.5026463233609586</Real>
+        <Real Name="Y">0.039870441559044068</Real>
+        <Real Name="Z">0.41832956169583596</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.54655391350728522</Real>
+        <Real Name="Y">0.09276220600984024</Real>
+        <Real Name="Z">1.3180210922453812</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.5447506105516093</Real>
+        <Real Name="Y">-2.0395002468915848</Real>
+        <Real Name="Z">2.2284646136369952</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26041855395731028</Real>
+        <Real Name="Y">0.33383705890088583</Real>
+        <Real Name="Z">-0.39613279709128529</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.29256024023731703</Real>
+        <Real Name="Y">0.85339324309170805</Real>
+        <Real Name="Z">-0.25286374086875885</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39074944256391148</Real>
+        <Real Name="Y">0.41564051775409583</Real>
+        <Real Name="Z">-0.89189961844744059</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20271414101794608</Real>
+        <Real Name="Y">0.47849888939886387</Real>
+        <Real Name="Z">-0.2912499533094266</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42803352862651134</Real>
+        <Real Name="Y">-0.55613404469745564</Real>
+        <Real Name="Z">-1.0860406078308174</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8305774864465572</Real>
+        <Real Name="Y">0.96401064897612498</Real>
+        <Real Name="Z">0.032186439359276155</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.1847542084419729</Real>
+        <Real Name="Y">62.767946958966121</Real>
+        <Real Name="Z">-372.54946272686391</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.8838438578422156</Real>
+        <Real Name="Y">0.96598214011763162</Real>
+        <Real Name="Z">111.87103120110969</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.36553087649028</Real>
+        <Real Name="Y">61.985847480875009</Real>
+        <Real Name="Z">206.26213777034565</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.764644681408029</Real>
+        <Real Name="Y">-19.108876327616493</Real>
+        <Real Name="Z">-38.861717127331531</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.645097654868444</Real>
+        <Real Name="Y">-9.5528182816014073</Real>
+        <Real Name="Z">-24.639068432551646</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4778534242432784</Real>
+        <Real Name="Y">10.632777139576458</Real>
+        <Real Name="Z">12.939131357994633</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.620711840498686</Real>
+        <Real Name="Y">-7.1101252736541767</Real>
+        <Real Name="Z">-33.285622048135579</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-57.110079350448132</Real>
+        <Real Name="Y">11.194292669225657</Real>
+        <Real Name="Z">-15.181174891909791</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.702834388413613</Real>
+        <Real Name="Y">18.987739199805961</Real>
+        <Real Name="Z">56.584293753173441</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-309.56284332134885</Real>
+        <Real Name="Y">-124.03718622984279</Real>
+        <Real Name="Z">255.95897395107801</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">237.10963215728646</Real>
+        <Real Name="Y">108.11052832205668</Real>
+        <Real Name="Z">-280.73667803657946</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">114.12155027631039</Real>
+        <Real Name="Y">55.629240146506405</Real>
+        <Real Name="Z">-58.047491201564782</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-58.040730835582167</Real>
+        <Real Name="Y">-240.38527824814824</Real>
+        <Real Name="Z">-2.0730314591509114</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.1385232957474258</Real>
+        <Real Name="Y">45.224337625700954</Real>
+        <Real Name="Z">16.926680064652828</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.80275139628944</Real>
+        <Real Name="Y">24.695592678032142</Real>
+        <Real Name="Z">164.83199782573359</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620576671462685</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620576671462685</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620576671462685</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0034170472601017529</Real>
+        <Real Name="Y">0.60648354545599403</Real>
+        <Real Name="Z">0.2355261022686132</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0244227549072044</Real>
+        <Real Name="Y">0.66686668798192161</Real>
+        <Real Name="Z">0.30676481888351059</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.084952107337433552</Real>
+        <Real Name="Y">0.5984754822053564</Real>
+        <Real Name="Z">0.18602637195460672</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97179187201353678</Real>
+        <Real Name="Y">0.63336588331178778</Real>
+        <Real Name="Z">1.5675671775925759</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97486899200733279</Real>
+        <Real Name="Y">0.60615771878143931</Real>
+        <Real Name="Z">1.6592872163814523</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.8901392591367967</Real>
+        <Real Name="Y">0.68272620368035419</Real>
+        <Real Name="Z">1.5599037590660041</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959574667662846</Real>
+        <Real Name="Y">0.44167221338992518</Real>
+        <Real Name="Z">1.1693364147078253</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3336314823457491</Real>
+        <Real Name="Y">0.43679092413345938</Real>
+        <Real Name="Z">1.24182064113817</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3513824402667027</Real>
+        <Real Name="Y">0.3985709702280672</Real>
+        <Real Name="Z">1.0964140707351884</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6451527706273472</Real>
+        <Real Name="Y">0.31675233044674889</Real>
+        <Real Name="Z">0.30355193920278217</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6954360864371034</Real>
+        <Real Name="Y">0.33304132125618374</Real>
+        <Real Name="Z">0.22374858507787004</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5994555406342323</Real>
+        <Real Name="Y">0.23434554911156302</Real>
+        <Real Name="Z">0.28672327434394995</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7765345012949176</Real>
+        <Real Name="Y">0.39355882224684918</Real>
+        <Real Name="Z">0.033128140619744603</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7163425492989046</Real>
+        <Real Name="Y">0.42431571408598334</Real>
+        <Real Name="Z">1.8274122073060615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8486689085894381</Real>
+        <Real Name="Y">0.4564579694620064</Real>
+        <Real Name="Z">0.031502421125508238</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.10587894854229798</Real>
+        <Real Name="Y">0.64338994872557276</Real>
+        <Real Name="Z">-0.61728866572822927</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67059288127253447</Real>
+        <Real Name="Y">-3.3763297660003135</Real>
+        <Real Name="Z">2.8220510259253873</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8132893366688987</Real>
+        <Real Name="Y">-1.6363637037521015</Real>
+        <Real Name="Z">2.3906110776658149</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19684577513922535</Real>
+        <Real Name="Y">0.14222362629823443</Real>
+        <Real Name="Z">-0.11289494014075641</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5065878884033213</Real>
+        <Real Name="Y">-0.48782667454452</Real>
+        <Real Name="Z">-0.3386838427323336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2730786410632653</Real>
+        <Real Name="Y">-1.3638093592263671</Real>
+        <Real Name="Z">1.3000008077606973</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.13073506007727223</Real>
+        <Real Name="Y">-0.34678835942271546</Real>
+        <Real Name="Z">-0.27513322980821886</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90701138876367193</Real>
+        <Real Name="Y">-2.1672090563387605</Real>
+        <Real Name="Z">0.52933947625284161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21553473104229517</Real>
+        <Real Name="Y">-1.773608056367181</Real>
+        <Real Name="Z">0.339166509582497</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.013793800703266077</Real>
+        <Real Name="Y">0.21474649736234477</Real>
+        <Real Name="Z">0.082418100425596649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.58963638497221615</Real>
+        <Real Name="Y">1.1209904621896312</Real>
+        <Real Name="Z">-0.12050523726780193</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.60115171847378002</Real>
+        <Real Name="Y">-0.067313516808364782</Real>
+        <Real Name="Z">-0.14547961153083788</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1182188617389517</Real>
+        <Real Name="Y">-0.0090799088493098076</Real>
+        <Real Name="Z">0.46128805397061762</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.32160100326167057</Real>
+        <Real Name="Y">0.8022640949724531</Real>
+        <Real Name="Z">0.43258264771793947</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.0033701725833803</Real>
+        <Real Name="Y">-1.2804394347827017</Real>
+        <Real Name="Z">0.11779604949010815</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">153.26883975898485</Real>
+        <Real Name="Y">100.15019744081945</Real>
+        <Real Name="Z">-279.31211851254074</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-42.068982581038739</Real>
+        <Real Name="Y">-32.734853697727992</Real>
+        <Real Name="Z">77.321596383144069</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.884684124344872</Real>
+        <Real Name="Y">43.893661453932211</Real>
+        <Real Name="Z">191.57860693500342</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">9.8715354998063845</Real>
+        <Real Name="Y">-26.672529343328634</Real>
+        <Real Name="Z">-24.891686037577685</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.298389374569012</Real>
+        <Real Name="Y">-5.4042068148301929</Real>
+        <Real Name="Z">-27.104147320433249</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">26.758190370688069</Real>
+        <Real Name="Y">-8.8570187179350839</Real>
+        <Real Name="Z">-23.404760231531341</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.63130804683874</Real>
+        <Real Name="Y">-17.068253030316662</Real>
+        <Real Name="Z">-27.994022187481278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.458238508084115</Real>
+        <Real Name="Y">17.380148451102094</Real>
+        <Real Name="Z">-21.189716054794125</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-67.09552944307687</Real>
+        <Real Name="Y">41.501792513945205</Real>
+        <Real Name="Z">83.279906818610286</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-262.33916303896007</Real>
+        <Real Name="Y">-175.00911596455938</Real>
+        <Real Name="Z">379.87434725764632</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">235.20188002227042</Real>
+        <Real Name="Y">174.9771234478977</Real>
+        <Real Name="Z">-390.06208564088644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">95.192716350195099</Real>
+        <Real Name="Y">78.558456417100174</Real>
+        <Real Name="Z">-89.10645393586347</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-95.185397701185138</Real>
+        <Real Name="Y">-430.58689553821978</Real>
+        <Real Name="Z">7.0199512434330131</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.153843944484173</Real>
+        <Real Name="Y">112.74021704545072</Real>
+        <Real Name="Z">38.997693863547951</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.11407621983665</Real>
+        <Real Name="Y">127.13127633667017</Real>
+        <Real Name="Z">104.99288741972327</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562600160298169</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.45626001137515</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.45626001137515</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.45626001137515</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562579188546056</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562579188546056</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562579188546056</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562579188546056</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562540142582749</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562540142582749</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562540142582749</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562357501768357</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562747749874143</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562747749874143</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562747749874143</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562747749874143</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">18.791686616081851</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">17.359573776474999</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">18.787591337068744</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">18.787709230037621</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">18.787820161360287</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">20.344798432223445</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">20.34484386979701</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">20.344360873750347</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">20.343202705696008</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">26.067873337058046</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">26.085744758463377</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">26.768814561492803</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">26.0834610065425</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">18.733410663305875</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">18.731961000893666</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">18.730346054539876</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">18.728642699117643</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">28.072358033056044</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.391365300237716</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.803080417491906</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">30.881353478196424</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">31.109167420493087</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">31.741908687750502</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">32.981193320131055</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">34.369864937035842</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.895540734510419</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">35.529337832741675</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">35.972157616933181</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">35.74819441668506</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">35.603047169549612</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">38.23255258561236</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">39.595719989766501</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">41.010578941775023</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">42.453020157628764</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5649631544184182</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5486607110788633</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6268158788145044</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.854518889788503</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.554016913908592</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.793256108715578</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.182410721667029</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.709244687195945</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.128827373806159</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.553775736592334</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-12.019380207493034</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-12.559586515307894</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.774015816569271</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.138632883135621</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.555106781497933</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-21.999251352773907</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21190890418197439</Real>
+        <Real Name="Y">-0.7311311919098834</Real>
+        <Real Name="Z">0.011277778119910499</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.66796314487407893</Real>
+        <Real Name="Y">-0.44908961562317945</Real>
+        <Real Name="Z">-0.19934647018435334</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.080882597990871996</Real>
+        <Real Name="Y">-1.3642241529051329</Real>
+        <Real Name="Z">0.095855310056509185</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44769583968342896</Real>
+        <Real Name="Y">-0.12958260429636317</Real>
+        <Real Name="Z">0.17147102653965599</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1260077456076665</Real>
+        <Real Name="Y">1.2299432703788549</Real>
+        <Real Name="Z">0.59933785465319467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4102608467371438</Real>
+        <Real Name="Y">0.66588072547259036</Real>
+        <Real Name="Z">0.10716908923047011</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.42091576278340037</Real>
+        <Real Name="Y">0.039801072970148413</Real>
+        <Real Name="Z">0.4239928608933955</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31497744055640853</Real>
+        <Real Name="Y">0.033114800275404865</Real>
+        <Real Name="Z">1.2372826323989534</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7872566667859691</Real>
+        <Real Name="Y">-2.0657209691150182</Real>
+        <Real Name="Z">1.5960222410479219</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26078907943572527</Real>
+        <Real Name="Y">0.32044762585901831</Real>
+        <Real Name="Z">-0.34787968920455964</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.148374024658951</Real>
+        <Real Name="Y">0.34906800206533178</Real>
+        <Real Name="Z">-0.43150156880076879</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.01999757278104131</Real>
+        <Real Name="Y">0.52855025949293</Real>
+        <Real Name="Z">-0.45929211920777768</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15528384653458924</Real>
+        <Real Name="Y">0.54477489000772439</Real>
+        <Real Name="Z">-0.27405115378506656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25903608390864075</Real>
+        <Real Name="Y">-0.78199538968155358</Real>
+        <Real Name="Z">-1.2374793615012896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93642846229023646</Real>
+        <Real Name="Y">1.151169402760081</Real>
+        <Real Name="Z">-1.0669585943196809</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620597983834559</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620597983834559</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620597983834559</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059504205738956026</Real>
+        <Real Name="Y">0.59963578520166738</Real>
+        <Real Name="Z">0.23899933171809468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8576185094484228</Real>
+        <Real Name="Y">0.68774995685397866</Real>
+        <Real Name="Z">0.27491901333567897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062268876555089385</Real>
+        <Real Name="Y">0.61139291142671881</Real>
+        <Real Name="Z">0.16249887486441247</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97426727099937505</Real>
+        <Real Name="Y">0.63072054654560328</Real>
+        <Real Name="Z">1.5712102638934657</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94468418889861883</Real>
+        <Real Name="Y">0.59368185109181337</Real>
+        <Real Name="Z">1.6543685147919849</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90880298548550742</Real>
+        <Real Name="Y">0.69723013120955479</Real>
+        <Real Name="Z">1.5499212791833576</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3965043579343859</Real>
+        <Real Name="Y">0.44683740210870809</Real>
+        <Real Name="Z">1.1687441728199883</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3311216324463928</Real>
+        <Real Name="Y">0.4734306249702967</Real>
+        <Real Name="Z">1.2333987790410086</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3462794463499737</Real>
+        <Real Name="Y">0.43157620757429599</Real>
+        <Real Name="Z">1.088701230609445</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6433609075857434</Real>
+        <Real Name="Y">0.31607835091314557</Real>
+        <Real Name="Z">0.30742619501386337</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7028424180127983</Real>
+        <Real Name="Y">0.33838978713094348</Real>
+        <Real Name="Z">0.23582683655853209</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6090600498316729</Real>
+        <Real Name="Y">0.22980521399817297</Real>
+        <Real Name="Z">0.28412994200645586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7792418389681328</Real>
+        <Real Name="Y">0.3911889997055118</Real>
+        <Real Name="Z">0.02453411038048629</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6976754922451263</Real>
+        <Real Name="Y">0.42097472129030955</Real>
+        <Real Name="Z">1.846319099367314</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8184121171391181</Real>
+        <Real Name="Y">0.47057301265921225</Real>
+        <Real Name="Z">0.06095094982838329</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11289962850011587</Real>
+        <Real Name="Y">-0.019857253874299326</Real>
+        <Real Name="Z">-0.70904271070420422</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4542451811682351</Real>
+        <Real Name="Y">-0.56071508220296973</Real>
+        <Real Name="Z">1.0794278719921591</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0417713185797308</Real>
+        <Real Name="Y">0.4396409703373827</Real>
+        <Real Name="Z">0.74212083053578182</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.096692480738276188</Real>
+        <Real Name="Y">-0.03675207578917096</Real>
+        <Real Name="Z">0.27522056811850976</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63531588002411876</Real>
+        <Real Name="Y">-2.6533082869300575</Real>
+        <Real Name="Z">-1.0286747806486538</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.8522647674637045</Real>
+        <Real Name="Y">-0.4906119716796325</Real>
+        <Real Name="Z">1.1447088461966053</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.058462856481769264</Real>
+        <Real Name="Y">-0.021638327601527445</Real>
+        <Real Name="Z">-0.65751940927468677</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22553561722289467</Real>
+        <Real Name="Y">-0.40557533700291998</Real>
+        <Real Name="Z">-0.20908586217096919</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.45962950842864964</Real>
+        <Real Name="Y">0.10625596444966329</Real>
+        <Real Name="Z">-0.43160846994798235</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2181084448427936</Real>
+        <Real Name="Y">0.37035823503375381</Real>
+        <Real Name="Z">0.6480636863796565</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.013110399386607796</Real>
+        <Real Name="Y">1.4087123829431427</Real>
+        <Real Name="Z">1.1324721908961335</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8893193956727565</Real>
+        <Real Name="Y">-0.49257875143947061</Real>
+        <Real Name="Z">0.62954442254135123</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11268564283172391</Real>
+        <Real Name="Y">-0.095803003343580329</Real>
+        <Real Name="Z">-0.068511660605069288</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1881828625573017</Real>
+        <Real Name="Y">0.5101409722182717</Real>
+        <Real Name="Z">2.880653600036728</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11835265372217771</Real>
+        <Real Name="Y">-0.97783725579077796</Real>
+        <Real Name="Z">2.1837799851492301</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-65.827146055809777</Real>
+        <Real Name="Y">-107.7969262020936</Real>
+        <Real Name="Z">-417.77945654226812</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11093464554923571</Real>
+        <Real Name="Y">34.977206424453854</Real>
+        <Real Name="Z">108.9362353840791</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">176.37591850783059</Real>
+        <Real Name="Y">148.13014510036885</Real>
+        <Real Name="Z">169.19192952891515</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.759968759850892</Real>
+        <Real Name="Y">-14.33805127904305</Real>
+        <Real Name="Z">-37.669842608810612</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.743346850528717</Real>
+        <Real Name="Y">-8.0400007387779802</Real>
+        <Real Name="Z">-23.763141810575632</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3190023346356909</Real>
+        <Real Name="Y">7.6844590722618733</Real>
+        <Real Name="Z">12.79511698688902</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.251278711462518</Real>
+        <Real Name="Y">-14.264220598217193</Real>
+        <Real Name="Z">-32.995321402792975</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.500059263330648</Real>
+        <Real Name="Y">12.045347614248033</Real>
+        <Real Name="Z">27.178835256949043</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.935532723875781</Real>
+        <Real Name="Y">16.912465929528313</Real>
+        <Real Name="Z">54.454353578341156</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-258.02459216325337</Real>
+        <Real Name="Y">-52.426706749237354</Real>
+        <Real Name="Z">177.83232173768101</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">212.23008284685818</Real>
+        <Real Name="Y">26.33462972002711</Real>
+        <Real Name="Z">-198.76614673960131</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.86620098927736</Real>
+        <Real Name="Y">33.266828352574848</Real>
+        <Real Name="Z">-54.004045606329385</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-61.04618080378026</Real>
+        <Real Name="Y">-234.54500525094494</Real>
+        <Real Name="Z">8.5672388700421038</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.061370028048913</Real>
+        <Real Name="Y">75.194567920667097</Real>
+        <Real Name="Z">-10.679967675004804</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.623847938623072</Real>
+        <Real Name="Y">76.865260684184165</Real>
+        <Real Name="Z">216.70189104248618</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620614188835629</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620614188835629</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620614188835629</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0012125487122049312</Real>
+        <Real Name="Y">0.58877873858536678</Real>
+        <Real Name="Z">0.24149441842661679</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8544143940449385</Real>
+        <Real Name="Y">0.67520900253475813</Real>
+        <Real Name="Z">0.28166450468661541</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076782551620039122</Real>
+        <Real Name="Y">0.59698427826257594</Real>
+        <Real Name="Z">0.1833208661961106</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98226038547506145</Real>
+        <Real Name="Y">0.62905433374475273</Real>
+        <Real Name="Z">1.5717957248043826</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97475430670867347</Real>
+        <Real Name="Y">0.63192881130287171</Real>
+        <Real Name="Z">1.6671776652350545</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94160025886486964</Real>
+        <Real Name="Y">0.71044735316231111</Real>
+        <Real Name="Z">1.5420594019964804</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.388887313631022</Real>
+        <Real Name="Y">0.4476144077747739</Real>
+        <Real Name="Z">1.1806895775305668</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3383860756746886</Real>
+        <Real Name="Y">0.47840544562747406</Real>
+        <Real Name="Z">1.2559481674245523</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3257876005673155</Real>
+        <Real Name="Y">0.3987974049537405</Real>
+        <Real Name="Z">1.1277968100963622</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6491553272641382</Real>
+        <Real Name="Y">0.31835189541880987</Real>
+        <Real Name="Z">0.29571048568555625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7084886972223094</Real>
+        <Real Name="Y">0.34170917820572239</Real>
+        <Real Name="Z">0.22432206260296833</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6025318108799758</Real>
+        <Real Name="Y">0.24106341214524463</Real>
+        <Real Name="Z">0.26385053475578946</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7748274681031644</Real>
+        <Real Name="Y">0.39961364171397967</Real>
+        <Real Name="Z">0.020423507772989829</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7162387228953957</Real>
+        <Real Name="Y">0.40728322271107975</Real>
+        <Real Name="Z">1.8071798480608308</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.787200597987523</Real>
+        <Real Name="Y">0.4896489227342366</Real>
+        <Real Name="Z">0.050471340115238982</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21840057145218336</Real>
+        <Real Name="Y">-0.61221102635234304</Real>
+        <Real Name="Z">-0.34175474769096398</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.36633996847717298</Real>
+        <Real Name="Y">-1.4352805833270397</Real>
+        <Real Name="Z">1.6186583472351066</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4102470719858466</Real>
+        <Real Name="Y">-0.86398696464355629</Real>
+        <Real Name="Z">2.8878762029107734</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44235003709502541</Real>
+        <Real Name="Y">-0.10459732370443441</Real>
+        <Real Name="Z">0.17601436672169096</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6440593699311146</Real>
+        <Real Name="Y">0.8590670824167479</Real>
+        <Real Name="Z">0.2540114397511728</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6905072734193212</Real>
+        <Real Name="Y">0.4637068977169499</Real>
+        <Real Name="Z">-0.0073126792812255349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.55787679514559274</Real>
+        <Real Name="Y">0.024637065557418847</Real>
+        <Real Name="Z">0.39371651911889916</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.6175489138480913</Real>
+        <Real Name="Y">0.21251597725385854</Real>
+        <Real Name="Z">1.1185053879853375</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96274966418180408</Real>
+        <Real Name="Y">-1.8188353989761521</Real>
+        <Real Name="Z">2.5024295996373649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24529950438949574</Real>
+        <Real Name="Y">0.32420250752980345</Real>
+        <Real Name="Z">-0.42157189848903276</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39691228646822885</Real>
+        <Real Name="Y">1.3121613437885917</Real>
+        <Real Name="Z">0.019326076136792381</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.81787583169442879</Real>
+        <Real Name="Y">0.33516387822199406</Real>
+        <Real Name="Z">-1.3034161969661611</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20873430191546632</Real>
+        <Real Name="Y">0.40667527847284551</Real>
+        <Real Name="Z">-0.26802270612192425</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.5364785621029271</Real>
+        <Real Name="Y">-0.02096284365796235</Real>
+        <Real Name="Z">-0.89890989631004103</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7973628526507031</Real>
+        <Real Name="Y">0.34208473804021933</Real>
+        <Real Name="Z">1.1358341914221102</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-76.593141272987168</Real>
+        <Real Name="Y">73.294863898190556</Real>
+        <Real Name="Z">-359.96363196631853</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.740785469579528</Real>
+        <Real Name="Y">-1.1332375831744201</Real>
+        <Real Name="Z">111.67732219885457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">133.4751481806573</Real>
+        <Real Name="Y">-2.8443115980706608</Real>
+        <Real Name="Z">131.26631215686595</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">24.163099297760908</Real>
+        <Real Name="Y">-24.225196563120576</Real>
+        <Real Name="Z">-37.449044905043138</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.8203394930567143</Real>
+        <Real Name="Y">7.29920063714642</Real>
+        <Real Name="Z">14.327785850331701</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.4337808430307035</Real>
+        <Real Name="Y">13.098353748571387</Real>
+        <Real Name="Z">11.717972015764097</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.82118028501371</Real>
+        <Real Name="Y">-3.522926941542984</Real>
+        <Real Name="Z">-32.16493930813165</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.493827526908959</Real>
+        <Real Name="Y">8.7975288349119083</Real>
+        <Real Name="Z">-18.446238086448076</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.307532466584661</Real>
+        <Real Name="Y">4.2132643385943389</Real>
+        <Real Name="Z">18.144986084389799</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-317.47523121013796</Real>
+        <Real Name="Y">-134.88711384636429</Real>
+        <Real Name="Z">279.27865289536169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">245.32816653129433</Real>
+        <Real Name="Y">104.12959384326963</Real>
+        <Real Name="Z">-285.82603074522274</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">119.25680589247619</Real>
+        <Real Name="Y">61.667344634653489</Real>
+        <Real Name="Z">-65.235819177849237</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.799517868545024</Real>
+        <Real Name="Y">-324.34426591475528</Real>
+        <Real Name="Z">-37.247740487607189</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.956271990157624</Real>
+        <Real Name="Y">57.656677243338308</Real>
+        <Real Name="Z">25.981622438351877</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.818086965688423</Real>
+        <Real Name="Y">160.80022526835222</Real>
+        <Real Name="Z">243.93879103670093</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 2">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98715
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562600160298169</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562602679570631</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562602679570631</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562602679570631</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562540142582749</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562540142582749</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562540142582749</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562540142582749</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562579188546056</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562579188546056</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562579188546056</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562429396659962</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562599622364996</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562599622364996</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562599622364996</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562599622364996</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.987499794208691</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">31.129888480869511</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.990407417889308</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.99023503544791</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">29.990141197005528</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">26.067839112431162</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">26.068534418585074</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">26.069447025600134</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">26.070550478663016</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">20.345178166441762</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">20.342320425797389</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">20.484840570362163</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">20.330737852206894</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">29.991183778805489</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">29.990412898577326</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">29.949034232594492</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">29.947701605215126</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">39.264244280014964</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">37.895437232956681</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">36.629298167656529</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">36.600997533790363</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">36.670288298035338</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">34.23092640868704</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.458046361685547</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">34.748870587606469</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.105112021708948</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">37.538396161928446</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">39.269949479103545</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">40.89970109315707</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">42.530810735328764</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">42.057858448684669</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">43.069166234122754</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">44.106072987723628</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">45.153950756128481</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.4404152794192715</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.3137572770993184</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.2856290256745506</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.3550136283619079</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.8343771018958428</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.060801748740436</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.3507133676463</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.705851348685895</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.354051583760565</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.088462641580037</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-22.874743511413616</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.659955871740578</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-14.324145812793656</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-15.336224478459904</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-16.414509898043612</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-17.46372029382783</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.55872268486508581</Real>
+        <Real Name="Y">-0.1954372884884242</Real>
+        <Real Name="Z">-0.12331658054675539</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5561630812121041</Real>
+        <Real Name="Y">0.1502581233870332</Real>
+        <Real Name="Z">-0.44761547196159901</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2265097662633464</Real>
+        <Real Name="Y">-1.1768262519621135</Real>
+        <Real Name="Z">-1.2616929856512602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10263626685285894</Real>
+        <Real Name="Y">0.57441118855119189</Real>
+        <Real Name="Z">0.005375904919935586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.35939325012836826</Real>
+        <Real Name="Y">0.13708618830230673</Real>
+        <Real Name="Z">-0.18874701506105859</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.676875181418428</Real>
+        <Real Name="Y">2.202437016478954</Real>
+        <Real Name="Z">0.65929093056192956</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22450558096959172</Real>
+        <Real Name="Y">0.27064569302711877</Real>
+        <Real Name="Z">0.3868191000888086</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.18295630274175456</Real>
+        <Real Name="Y">3.1066574874243527</Real>
+        <Real Name="Z">-0.46533684155430372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.43479618283021731</Real>
+        <Real Name="Y">-1.4385606453027826</Real>
+        <Real Name="Z">0.83013591007662091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11927480032898595</Real>
+        <Real Name="Y">-0.50285081385011732</Real>
+        <Real Name="Z">0.091729524538884569</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67581188225624333</Real>
+        <Real Name="Y">-0.055776720974020769</Real>
+        <Real Name="Z">0.61588372964499161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2213254303381311</Real>
+        <Real Name="Y">-1.9672700978846431</Real>
+        <Real Name="Z">0.44974949833150613</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.90469603789517505</Real>
+        <Real Name="Y">-0.20098861393275941</Real>
+        <Real Name="Z">-0.24253246946049692</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.84380910241735319</Real>
+        <Real Name="Y">0.72263550705740742</Real>
+        <Real Name="Z">-1.8704269945047447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39637402078760992</Real>
+        <Real Name="Y">-0.82004058352348863</Real>
+        <Real Name="Z">-0.19538443781690279</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620594230063974</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620594230063974</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620594230063974</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0035493939170043588</Real>
+        <Real Name="Y">0.60224647539438725</Real>
+        <Real Name="Z">0.24026625779042077</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.010176494832387634</Real>
+        <Real Name="Y">0.68663094408671432</Real>
+        <Real Name="Z">0.2849614630922277</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.067507535609723862</Real>
+        <Real Name="Y">0.60761406681780616</Real>
+        <Real Name="Z">0.16925313594998251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9733965722365</Real>
+        <Real Name="Y">0.63218706444988126</Real>
+        <Real Name="Z">1.5683953658120704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96277555085784383</Real>
+        <Real Name="Y">0.61039501200815161</Real>
+        <Real Name="Z">1.6609946031482961</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90174892955815722</Real>
+        <Real Name="Y">0.69282701386659729</Real>
+        <Real Name="Z">1.5496408934554764</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3967525993749075</Real>
+        <Real Name="Y">0.44437528686915734</Real>
+        <Real Name="Z">1.1716284212870838</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3288315554692205</Real>
+        <Real Name="Y">0.4557282663816663</Real>
+        <Real Name="Z">1.238112705527421</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349587393794133</Real>
+        <Real Name="Y">0.41396459064452035</Real>
+        <Real Name="Z">1.0940851989033336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.64508541490233</Real>
+        <Real Name="Y">0.3149710349787736</Real>
+        <Real Name="Z">0.30285333155711475</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6997872353297314</Real>
+        <Real Name="Y">0.32713204018026931</Real>
+        <Real Name="Z">0.2252508883325805</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5959805011319392</Real>
+        <Real Name="Y">0.23471132386354554</Real>
+        <Real Name="Z">0.28526343061077147</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7773691070770776</Real>
+        <Real Name="Y">0.39315185713392803</Real>
+        <Real Name="Z">0.029244798625577908</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7133236648973531</Real>
+        <Real Name="Y">0.41902056012958311</Real>
+        <Real Name="Z">1.8250372619814381</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.837308890882184</Real>
+        <Real Name="Y">0.46755702401291105</Real>
+        <Real Name="Z">0.035025097848590092</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.14045102368017015</Real>
+        <Real Name="Y">0.38177550752942979</Real>
+        <Real Name="Z">-0.5373199097365714</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9413930406954605</Real>
+        <Real Name="Y">-1.2761991460850763</Real>
+        <Real Name="Z">2.367366169159054</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3785139043018639</Real>
+        <Real Name="Y">-0.54023247456040857</Real>
+        <Real Name="Z">1.5794898632847516</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20177321875264462</Real>
+        <Real Name="Y">0.1511369192151934</Real>
+        <Real Name="Z">-0.09163242437204637</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4959974943229779</Real>
+        <Real Name="Y">-0.5711997842009453</Real>
+        <Real Name="Z">-0.048501532329643236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.668985406576291</Real>
+        <Real Name="Y">-1.1321711808915205</Real>
+        <Real Name="Z">1.2171889334341415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.056598330578124828</Real>
+        <Real Name="Y">-0.33116791339929941</Real>
+        <Real Name="Z">-0.29847234740533718</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.1905687213592373</Real>
+        <Real Name="Y">-2.5761197138624512</Real>
+        <Real Name="Z">0.37920372289941623</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.16492065243197221</Real>
+        <Real Name="Y">-2.0788469577197866</Real>
+        <Real Name="Z">0.23037569890624521</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0055817243700491681</Real>
+        <Real Name="Y">0.23369813495990388</Real>
+        <Real Name="Z">0.093558402843818347</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.5023835505252876</Real>
+        <Real Name="Y">0.24983634655652126</Real>
+        <Real Name="Z">-0.26446645697194249</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21001749660732982</Real>
+        <Real Name="Y">-0.0023785680510789442</Real>
+        <Real Name="Z">0.5902376512832106</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.088681859956483491</Real>
+        <Real Name="Y">0.11679190788677732</Real>
+        <Real Name="Z">0.51697655928524711</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45116850610174741</Real>
+        <Real Name="Y">0.52426822984452204</Real>
+        <Real Name="Z">0.14982209090332133</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9880690856587753</Real>
+        <Real Name="Y">-1.3622559160479888</Real>
+        <Real Name="Z">-1.1709092196096609</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">114.76116092192248</Real>
+        <Real Name="Y">82.870070232713402</Real>
+        <Real Name="Z">-321.85574969744346</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-29.900197478239747</Real>
+        <Real Name="Y">-17.43681141226044</Real>
+        <Real Name="Z">88.681790769954674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">63.476152368329252</Real>
+        <Real Name="Y">77.903741267309243</Real>
+        <Real Name="Z">217.6845461488121</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.950477831408534</Real>
+        <Real Name="Y">-21.646106157076886</Real>
+        <Real Name="Z">-33.218599940412446</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.981729176744224</Real>
+        <Real Name="Y">-6.982970953444724</Real>
+        <Real Name="Z">-24.665551637008498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6794282265842071</Real>
+        <Real Name="Y">9.5336087451639422</Real>
+        <Real Name="Z">10.622709794176551</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.488799634190229</Real>
+        <Real Name="Y">-13.956189093510133</Real>
+        <Real Name="Z">-31.219341133972478</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.479737498889897</Real>
+        <Real Name="Y">13.377745000073784</Real>
+        <Real Name="Z">24.978693842453843</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.261840916868884</Real>
+        <Real Name="Y">19.673912458794014</Real>
+        <Real Name="Z">53.502089074763028</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-293.63489963550069</Real>
+        <Real Name="Y">-158.94874011536504</Real>
+        <Real Name="Z">314.22514169901666</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">235.19746418264469</Real>
+        <Real Name="Y">157.09851881953182</Real>
+        <Real Name="Z">-332.68871826629089</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">105.37212896575208</Real>
+        <Real Name="Y">68.886440112643911</Real>
+        <Real Name="Z">-72.31226053895287</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-69.739326428596087</Real>
+        <Real Name="Y">-325.66617350196458</Real>
+        <Real Name="Z">-19.780565993474909</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-16.873667029594884</Real>
+        <Real Name="Y">78.414678353235303</Real>
+        <Real Name="Z">-5.045467702495614</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-108.65881586671708</Real>
+        <Real Name="Y">36.878276244156297</Real>
+        <Real Name="Z">131.09128358087423</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.862059994828462</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.862059994828462</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.862059994828462</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.013334344501735658</Real>
+        <Real Name="Y">0.59736609784975458</Real>
+        <Real Name="Z">0.23976122287419785</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0053180861355399765</Real>
+        <Real Name="Y">0.68508895381642487</Real>
+        <Real Name="Z">0.27721464118090033</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.058562829084237288</Real>
+        <Real Name="Y">0.61086640724874586</Real>
+        <Real Name="Z">0.15648791245302179</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97656242604101318</Real>
+        <Real Name="Y">0.64023747268197262</Real>
+        <Real Name="Z">1.5684607796259709</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94736682686795037</Real>
+        <Real Name="Y">0.61625779832880745</Real>
+        <Real Name="Z">1.656409120183606</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94494893644427946</Real>
+        <Real Name="Y">0.72975804515401621</Real>
+        <Real Name="Z">1.5562553390442238</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3931686252961308</Real>
+        <Real Name="Y">0.45156137499446375</Real>
+        <Real Name="Z">1.1803738432707205</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3386582448866278</Real>
+        <Real Name="Y">0.51867453889137094</Real>
+        <Real Name="Z">1.2214440278254288</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3365029500900214</Real>
+        <Real Name="Y">0.41174315963805058</Real>
+        <Real Name="Z">1.1142994202367984</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6467631384968158</Real>
+        <Real Name="Y">0.30449156960766605</Real>
+        <Real Name="Z">0.30268551177339109</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7107079270509171</Real>
+        <Real Name="Y">0.3363269684360588</Real>
+        <Real Name="Z">0.23896824725106411</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.638175036790338</Real>
+        <Real Name="Y">0.21111529198308834</Real>
+        <Real Name="Z">0.28346485397880083</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7630886050211954</Real>
+        <Real Name="Y">0.38761567857939005</Real>
+        <Real Name="Z">0.020901459777158047</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7272339379617043</Real>
+        <Real Name="Y">0.42663257648491415</Real>
+        <Real Name="Z">1.8032466948187234</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8109470807559582</Real>
+        <Real Name="Y">0.45896060930270782</Real>
+        <Real Name="Z">0.063112661613042659</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.50774747066491099</Real>
+        <Real Name="Y">-0.14377124980537978</Real>
+        <Real Name="Z">-0.40914513300850197</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1766273379351722</Real>
+        <Real Name="Y">-0.80712193223308548</Real>
+        <Real Name="Z">1.3404183671316319</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8747345607091199</Real>
+        <Real Name="Y">1.0309865686631881</Real>
+        <Real Name="Z">0.49930147163780525</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.098878658076608297</Real>
+        <Real Name="Y">0.59804268151554285</Real>
+        <Real Name="Z">-0.069957547840315271</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.14819383591925847</Real>
+        <Real Name="Y">0.026381255730745033</Real>
+        <Real Name="Z">-0.30532372734976443</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9278738545532936</Real>
+        <Real Name="Y">1.4512729878721311</Real>
+        <Real Name="Z">1.2161193583990801</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24465681212169549</Real>
+        <Real Name="Y">0.30422157068865613</Real>
+        <Real Name="Z">0.40488776441481722</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.77095630378268298</Real>
+        <Real Name="Y">2.1606255278963262</Real>
+        <Real Name="Z">-1.1950310928494261</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0842755306473175</Real>
+        <Real Name="Y">-0.96436301834765692</Real>
+        <Real Name="Z">1.8559842378878613</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.12059153925962759</Real>
+        <Real Name="Y">-0.58253200105749514</Real>
+        <Real Name="Z">0.011409744277778161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.087577819387876107</Real>
+        <Real Name="Y">1.0066516925894275</Real>
+        <Real Name="Z">0.57386878286477772</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9121339036242526</Real>
+        <Real Name="Y">-0.91862480223817311</Real>
+        <Real Name="Z">0.19039392702353769</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.94583064824025742</Real>
+        <Real Name="Y">-0.33996198606441907</Real>
+        <Real Name="Z">-0.25662812094484144</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3153037799108001</Real>
+        <Real Name="Y">0.81133585470117375</Real>
+        <Real Name="Z">-0.75206950197421596</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.3043695427578768</Real>
+        <Real Name="Y">-1.1940515205678519</Real>
+        <Real Name="Z">1.6465177701266274</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-31.481665100704106</Real>
+        <Real Name="Y">-164.89757885987316</Real>
+        <Real Name="Z">-391.52533232770412</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-14.021420837834235</Real>
+        <Real Name="Y">40.212493764628078</Real>
+        <Real Name="Z">99.349420666358455</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">142.69649222508906</Real>
+        <Real Name="Y">174.33774156240901</Real>
+        <Real Name="Z">160.86460265623523</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">13.050541676679416</Real>
+        <Real Name="Y">-4.0839876076317623</Real>
+        <Real Name="Z">-39.331168889019963</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.1776406370451014</Real>
+        <Real Name="Y">-0.31681185826262848</Real>
+        <Real Name="Z">13.303933036949303</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-6.3430252715941293</Real>
+        <Real Name="Y">5.321921493260124</Real>
+        <Real Name="Z">15.062153062414275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">35.750981805044049</Real>
+        <Real Name="Y">-8.7273003297951846</Real>
+        <Real Name="Z">-31.064605677491585</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.339635849635975</Real>
+        <Real Name="Y">2.1326750940094321</Real>
+        <Real Name="Z">25.160243088692638</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-12.941221723448258</Real>
+        <Real Name="Y">5.6735032084200157</Real>
+        <Real Name="Z">16.869445378455332</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-210.92635672076696</Real>
+        <Real Name="Y">-89.630750362843457</Real>
+        <Real Name="Z">297.68797769251051</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">102.82580936493778</Real>
+        <Real Name="Y">40.496820924240012</Real>
+        <Real Name="Z">-277.63814283998431</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.927787478481633</Real>
+        <Real Name="Y">73.401189444930523</Real>
+        <Real Name="Z">-101.78087928850336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">24.043942273983532</Real>
+        <Real Name="Y">-177.84453887487831</Real>
+        <Real Name="Z">53.620373217152974</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-39.53047027718565</Real>
+        <Real Name="Y">22.562808687457562</Real>
+        <Real Name="Z">-4.9749861508549884</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-47.534118406001028</Real>
+        <Real Name="Y">81.361813713929706</Real>
+        <Real Name="Z">164.3969663747896</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 3">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98716
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562600160298169</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562540142582749</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562540142582749</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562540142582749</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562602679570631</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562602679570631</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562602679570631</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562602679570631</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562602679570631</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562602679570631</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562602679570631</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562599622364996</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562429396659962</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562429396659962</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562429396659962</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562429396659962</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">26.070770945377618</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">26.708875131897635</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">26.071134664508627</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">26.071132472855979</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">26.071355119442508</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">29.994096065938798</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.994127016510433</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.994189691474816</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.994254209718953</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">29.994284462146183</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">29.994239482449686</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">29.787313070633882</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">29.995699050935787</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">20.329538585572401</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">20.324242279860442</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">20.31929988991422</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">20.315286107052259</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">35.343549230704284</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">34.601992229577156</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">33.93147185934744</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">33.966499592113792</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">34.066894374886829</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">36.836579753161558</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">37.099633885989618</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">37.45953460358713</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.916454924332413</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">38.470409806019035</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">39.120929572638758</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">40.077314105778335</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">41.128019040261549</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">44.262071950072631</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">45.884492627713186</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">47.337588114953249</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">48.565070565584172</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5683731001120886</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5355931972713801</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.5706231216903817</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.6707952578768897</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.521316415189224</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-9.7843395974456495</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.144177640078784</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.601033442579924</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.154958071839316</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.805522818155541</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-12.551438378505487</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-13.393757332686796</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.396382543108217</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-28.024099526460731</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.482137403647016</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.7136336371399</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.19787174590441542</Real>
+        <Real Name="Y">0.1615613889385647</Real>
+        <Real Name="Z">-0.38305665212567802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.7420087544145497</Real>
+        <Real Name="Y">0.75918088595013389</Real>
+        <Real Name="Z">1.2435674032029085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3711369223715755</Real>
+        <Real Name="Y">-0.19170785514288644</Real>
+        <Real Name="Z">0.42562796639667022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19638315205483492</Real>
+        <Real Name="Y">0.14565315135227885</Real>
+        <Real Name="Z">-0.067967185842621486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3802138136646303</Real>
+        <Real Name="Y">-0.58427055558605701</Real>
+        <Real Name="Z">0.23045735337154905</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.9488788834227251</Real>
+        <Real Name="Y">-0.88425910185951861</Real>
+        <Real Name="Z">0.94602094518641222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.023704545495134583</Real>
+        <Real Name="Y">-0.3413031917315365</Real>
+        <Real Name="Z">-0.30920684408559601</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.57458809086462592</Real>
+        <Real Name="Y">-2.6639579923405159</Real>
+        <Real Name="Z">0.20924282970686953</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10717835653133569</Real>
+        <Real Name="Y">-2.1491056124634227</Real>
+        <Real Name="Z">0.10532829628877118</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.012944992862387334</Real>
+        <Real Name="Y">0.24702752779615819</Real>
+        <Real Name="Z">0.1198190834623393</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53415108976374859</Real>
+        <Real Name="Y">-0.39551860957653251</Real>
+        <Real Name="Z">-0.44767485391309769</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23060498264262888</Real>
+        <Real Name="Y">0.091415864029443031</Real>
+        <Real Name="Z">1.125773624901474</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.064052506287219743</Real>
+        <Real Name="Y">0.1556142409020734</Real>
+        <Real Name="Z">0.5494680052322487</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53148313148554538</Real>
+        <Real Name="Y">0.53815672969841799</Real>
+        <Real Name="Z">0.03164652949451436</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.0632897927011018</Real>
+        <Real Name="Y">-0.36976385613194229</Real>
+        <Real Name="Z">-2.4264951267859698</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620600242195762</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620600242195762</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620600242195762</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0092401358586947212</Real>
+        <Real Name="Y">0.59861155711457581</Real>
+        <Real Name="Z">0.24244667257745878</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8569745331930929</Real>
+        <Real Name="Y">0.68916685357066676</Real>
+        <Real Name="Z">0.26995727231820821</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.048522374867189404</Real>
+        <Real Name="Y">0.60588440621964357</Real>
+        <Real Name="Z">0.15546202011293497</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97577007571589425</Real>
+        <Real Name="Y">0.63554360748265382</Real>
+        <Real Name="Z">1.5689087866545892</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94889238914557628</Real>
+        <Real Name="Y">0.61586764187881493</Real>
+        <Real Name="Z">1.6586459848623785</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92995444516063985</Real>
+        <Real Name="Y">0.71678820621704509</Real>
+        <Real Name="Z">1.5474015419842013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3950991047035326</Real>
+        <Real Name="Y">0.44920789799542465</Real>
+        <Real Name="Z">1.1771560932979219</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3331139422028242</Real>
+        <Real Name="Y">0.49951551914117948</Real>
+        <Real Name="Z">1.2299699294056667</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3442185783038627</Real>
+        <Real Name="Y">0.42042803637010323</Real>
+        <Real Name="Z">1.1013589297750066</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6458770284247977</Real>
+        <Real Name="Y">0.3089669887111372</Real>
+        <Real Name="Z">0.30251886577750364</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7089360395121638</Real>
+        <Real Name="Y">0.32977763545980154</Real>
+        <Real Name="Z">0.23357833704015291</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6155522327599521</Real>
+        <Real Name="Y">0.22065735075275106</Real>
+        <Real Name="Z">0.28144440228388551</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7706583749451787</Real>
+        <Real Name="Y">0.3901197947514275</Real>
+        <Real Name="Z">0.022985823711420349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7173588454540307</Real>
+        <Real Name="Y">0.42057619348941239</Real>
+        <Real Name="Z">1.8116027656704132</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.817794410483254</Real>
+        <Real Name="Y">0.46807098844596778</Real>
+        <Real Name="Z">0.052381809072507717</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.51950798406302368</Real>
+        <Real Name="Y">-0.16862325324379446</Real>
+        <Real Name="Z">-0.25183117458558557</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4268182304532906</Real>
+        <Real Name="Y">-0.205193947274247</Real>
+        <Real Name="Z">0.36286492638831191</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38394685016132624</Real>
+        <Real Name="Y">0.021856340615029106</Real>
+        <Real Name="Z">-0.29745055246615171</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.098251790361309432</Real>
+        <Real Name="Y">0.5730370064105943</Real>
+        <Real Name="Z">-0.034605428054109544</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25164827921984845</Real>
+        <Real Name="Y">0.085044888109765557</Real>
+        <Real Name="Z">-0.24415044585004197</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7988859005186268</Real>
+        <Real Name="Y">1.8251592191696377</Real>
+        <Real Name="Z">0.94651783216627661</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23445400230885843</Real>
+        <Real Name="Y">0.28034225200685314</Real>
+        <Real Name="Z">0.39544887678217278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.54855502166100623</Real>
+        <Real Name="Y">2.6671905695427558</Real>
+        <Real Name="Z">-0.88391768451949937</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.77697950461671406</Real>
+        <Real Name="Y">-1.2167064330843589</Real>
+        <Real Name="Z">1.3058611448231656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.1031313913059544</Real>
+        <Real Name="Y">-0.52910520348470169</Real>
+        <Real Name="Z">0.038846175126815492</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.54204962127178313</Real>
+        <Real Name="Y">0.52303487482542943</Real>
+        <Real Name="Z">0.74488077501378602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.6604136097674114</Real>
+        <Real Name="Y">-1.5171112939060083</Real>
+        <Real Name="Z">0.31900658340580795</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93472531476314713</Real>
+        <Real Name="Y">-0.27101907198880099</Real>
+        <Real Name="Z">-0.25829999780322155</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1124138497337599</Real>
+        <Real Name="Y">0.70120080508230243</Real>
+        <Real Name="Z">-1.3843865684408865</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.32903719598389514</Real>
+        <Real Name="Y">-1.0533013089578174</Real>
+        <Real Name="Z">0.88374870338175082</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">15.964267171700129</Real>
+        <Real Name="Y">-60.086537363417847</Real>
+        <Real Name="Z">-386.15719268939853</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.20032887777117</Real>
+        <Real Name="Y">21.858174725912676</Real>
+        <Real Name="Z">103.97388838461664</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">143.61650782860937</Real>
+        <Real Name="Y">171.40700098545841</Real>
+        <Real Name="Z">223.13592479768147</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.480958325500666</Real>
+        <Real Name="Y">-8.426043595942474</Real>
+        <Real Name="Z">-39.808534885485159</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.575699303276643</Real>
+        <Real Name="Y">-12.044217982629402</Real>
+        <Real Name="Z">-23.761605534528002</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.4336162594450315</Real>
+        <Real Name="Y">6.7494932417979534</Real>
+        <Real Name="Z">14.484736601497218</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.653630330598503</Real>
+        <Real Name="Y">-9.255690297415093</Real>
+        <Real Name="Z">-32.60277824221113</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.318415326506724</Real>
+        <Real Name="Y">5.0569574483331365</Real>
+        <Real Name="Z">27.320424556945156</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.958256373424049</Real>
+        <Real Name="Y">17.919501185855882</Real>
+        <Real Name="Z">54.367757503781917</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-256.49296456454607</Real>
+        <Real Name="Y">-97.948342789871475</Real>
+        <Real Name="Z">270.7842176966148</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">162.03865626745309</Real>
+        <Real Name="Y">75.644470812827706</Real>
+        <Real Name="Z">-290.2260734702798</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.833682313043113</Real>
+        <Real Name="Y">63.502605348423572</Real>
+        <Real Name="Z">-79.814321600205147</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-3.1144132190489131</Real>
+        <Real Name="Y">-171.71420368760485</Real>
+        <Real Name="Z">51.053022720191791</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-38.850104579440163</Real>
+        <Real Name="Y">27.334021469851535</Real>
+        <Real Name="Z">-17.723594518768351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-98.795302339999381</Real>
+        <Real Name="Y">-29.997189501579754</Real>
+        <Real Name="Z">124.97412867954699</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620583583249968</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620583583249968</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620583583249968</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070109310152138473</Real>
+        <Real Name="Y">0.59992620259325624</Real>
+        <Real Name="Z">0.23226981671892369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.004268766009789122</Real>
+        <Real Name="Y">0.67751724180490869</Real>
+        <Real Name="Z">0.28825579322320971</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.082045813706257922</Real>
+        <Real Name="Y">0.61453861708156399</Real>
+        <Real Name="Z">0.17466285427198694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97341922564630479</Real>
+        <Real Name="Y">0.6303658042483764</Real>
+        <Real Name="Z">1.5734560581215615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94144929194242932</Real>
+        <Real Name="Y">0.57317616232027158</Real>
+        <Real Name="Z">1.6432384813748757</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9024810872814063</Real>
+        <Real Name="Y">0.69308424309750438</Real>
+        <Real Name="Z">1.5594383424142713</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959689047281951</Real>
+        <Real Name="Y">0.44667335628220445</Real>
+        <Real Name="Z">1.1635223387348295</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3338051282346637</Real>
+        <Real Name="Y">0.47034911419265835</Real>
+        <Real Name="Z">1.2323514152899264</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3416827267545248</Real>
+        <Real Name="Y">0.43265000068111975</Real>
+        <Real Name="Z">1.0859422202849582</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6415145586428037</Real>
+        <Real Name="Y">0.31893572896987682</Real>
+        <Real Name="Z">0.31230714791602432</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7042212389300453</Real>
+        <Real Name="Y">0.34974694545616714</Real>
+        <Real Name="Z">0.24687886973305301</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.626074671018096</Real>
+        <Real Name="Y">0.2272750409952537</Real>
+        <Real Name="Z">0.28945443363183432</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7797558205334429</Real>
+        <Real Name="Y">0.39098203591183861</Real>
+        <Real Name="Z">0.024227661601527797</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6906983885055282</Real>
+        <Real Name="Y">0.42131326285463266</Real>
+        <Real Name="Z">0.0065893829797984971</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8161732870016867</Real>
+        <Real Name="Y">0.45667699430268821</Real>
+        <Real Name="Z">0.083559431995293643</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.16440048224296605</Real>
+        <Real Name="Y">0.084082915799049529</Real>
+        <Real Name="Z">-0.94164129373145367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.68371540961991228</Real>
+        <Real Name="Y">-1.9592301193604127</Real>
+        <Real Name="Z">2.0344201863049012</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5616798760775543</Real>
+        <Real Name="Y">0.20748312468848373</Real>
+        <Real Name="Z">2.0827862520375984</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11253411941990832</Real>
+        <Real Name="Y">-0.052046916836204098</Real>
+        <Real Name="Z">0.28474534818266428</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22964720746628722</Real>
+        <Real Name="Y">-2.4604093184262528</Real>
+        <Real Name="Z">-1.6735285811580447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.74586625727243161</Real>
+        <Real Name="Y">-0.54362164760303278</Real>
+        <Real Name="Z">1.2352227384821723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.073737997223809498</Real>
+        <Real Name="Y">-0.020000168681445257</Real>
+        <Real Name="Z">-0.64900356122459446</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42501148284531554</Real>
+        <Real Name="Y">-0.36483849698241166</Real>
+        <Real Name="Z">-0.074869647244044837</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.66166887323893864</Real>
+        <Real Name="Y">0.15869194511097662</Real>
+        <Real Name="Z">-0.27324667547409509</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23826056097181239</Real>
+        <Real Name="Y">0.34435780619861633</Real>
+        <Real Name="Z">0.57947763940087171</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.3169833089888342</Real>
+        <Real Name="Y">1.4150949144073788</Real>
+        <Real Name="Z">1.5968256302437762</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2657140628680681</Real>
+        <Real Name="Y">-0.1538137225024632</Real>
+        <Real Name="Z">0.74266661473551765</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.032037588247121551</Real>
+        <Real Name="Y">0.047493151154236128</Real>
+        <Real Name="Z">0.014118797655795153</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.64690890614540986</Real>
+        <Real Name="Y">-0.33635295444513913</Real>
+        <Real Name="Z">2.5784633331444762</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.3485993474246093</Real>
+        <Real Name="Y">-2.3736647071047696</Real>
+        <Real Name="Z">3.0572340910166069</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-164.18118568266902</Real>
+        <Real Name="Y">-312.65980337560785</Real>
+        <Real Name="Z">-380.76355676757476</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.020446469443328</Real>
+        <Real Name="Y">67.064529792454735</Real>
+        <Real Name="Z">100.60876744881331</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.37544098237592</Real>
+        <Real Name="Y">140.35365419139407</Real>
+        <Real Name="Z">74.10033363462739</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.259582174473977</Real>
+        <Real Name="Y">-15.074648713462544</Real>
+        <Real Name="Z">-36.633735428400655</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.846215338213241</Real>
+        <Real Name="Y">-7.1587541994354851</Real>
+        <Real Name="Z">-24.516813215898111</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1982793973550585</Real>
+        <Real Name="Y">7.423965253233817</Real>
+        <Real Name="Z">12.158022195032032</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.519014063489379</Real>
+        <Real Name="Y">-17.448697421023383</Real>
+        <Real Name="Z">-31.395458866817613</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.655302684815005</Real>
+        <Real Name="Y">14.815369549061444</Real>
+        <Real Name="Z">25.311808881284257</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.771229494006533</Real>
+        <Real Name="Y">17.442765531626151</Real>
+        <Real Name="Z">55.07617643480009</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-182.88608667602705</Real>
+        <Real Name="Y">2.5549971807892291</Real>
+        <Real Name="Z">105.67456637759051</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">148.51742959975303</Real>
+        <Real Name="Y">-32.524513385531378</Real>
+        <Real Name="Z">-88.189360081240295</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.434358114233277</Real>
+        <Real Name="Y">10.414779075892099</Real>
+        <Real Name="Z">-49.951519763168022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-54.023500733450874</Real>
+        <Real Name="Y">-310.85063849465325</Real>
+        <Real Name="Z">-19.774621287252842</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-18.895497261548556</Real>
+        <Real Name="Y">115.38074203203961</Real>
+        <Real Name="Z">0.17595907508265896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.638595187889933</Real>
+        <Real Name="Y">320.26625298322267</Real>
+        <Real Name="Z">258.11943136312215</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_ParrinelloRahman_4Ranks_1RanksPerSimulation_s.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_ParrinelloRahman_4Ranks_1RanksPerSimulation_s.xml
new file mode 100644 (file)
index 0000000..0b68a2d
--- /dev/null
@@ -0,0 +1,3398 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562597</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562569</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562569</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562569</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562597</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562597</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562597</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562597</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562597</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562597</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562597</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.456274</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562349</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562349</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562349</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562349</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">20.344719</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">21.220322</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">20.33905</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">20.339771</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">20.340446</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">18.783875</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">18.783936</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">18.783871</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">18.783638</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">18.738853</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">18.738388</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">19.10268</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">18.730734</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">26.080875</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">26.082317</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">26.083651</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">26.089849</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629332</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.225618</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">28.961798</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.732178</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">30.658318</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">31.486567</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">32.013054</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">32.686993</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">33.505371</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">34.409489</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">35.390949</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">36.115913</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">36.942734</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">36.231239</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">36.948151</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">37.754505</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">38.638401</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.158316</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.775765</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.545425</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.470889</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.231978</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.758405</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.432406</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.251019</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.199922</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.181848</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.284223</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.482988</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-13.186468</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-13.901937</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-14.70696</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-15.584657</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13823938</Real>
+        <Real Name="Y">-0.083000772</Real>
+        <Real Name="Z">-0.55156732</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807449</Real>
+        <Real Name="Y">0.12591785</Real>
+        <Real Name="Z">0.086322196</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50557399</Real>
+        <Real Name="Y">-0.26345637</Real>
+        <Real Name="Z">-0.37042341</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.080341451</Real>
+        <Real Name="Y">-0.036381256</Real>
+        <Real Name="Z">0.2694976</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0880266</Real>
+        <Real Name="Y">-2.6992292</Real>
+        <Real Name="Z">-0.41159731</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0053114</Real>
+        <Real Name="Y">-0.44618699</Real>
+        <Real Name="Z">1.1535</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046993218</Real>
+        <Real Name="Y">-0.027141469</Real>
+        <Real Name="Z">-0.68357778</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051991098</Real>
+        <Real Name="Y">-0.42392981</Real>
+        <Real Name="Z">-0.38236645</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25138494</Real>
+        <Real Name="Y">0.072344378</Real>
+        <Real Name="Z">-0.58373684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20046787</Real>
+        <Real Name="Y">0.39459831</Real>
+        <Real Name="Z">0.71750742</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21663746</Real>
+        <Real Name="Y">1.2108052</Real>
+        <Real Name="Z">0.86115432</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3770657</Real>
+        <Real Name="Y">-0.66109222</Real>
+        <Real Name="Z">0.87071204</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21701036</Real>
+        <Real Name="Y">-0.090551347</Real>
+        <Real Name="Z">-0.034703776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639677</Real>
+        <Real Name="Y">0.96361506</Real>
+        <Real Name="Z">2.5346279</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37429887</Real>
+        <Real Name="Y">-0.37906641</Real>
+        <Real Name="Z">0.73122346</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0031040055</Real>
+        <Real Name="Y">0.59411114</Real>
+        <Real Name="Z">0.24346638</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8503568</Real>
+        <Real Name="Y">0.68421936</Real>
+        <Real Name="Z">0.27216437</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059127338</Real>
+        <Real Name="Y">0.60240096</Real>
+        <Real Name="Z">0.16629784</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97866666</Real>
+        <Real Name="Y">0.62996608</Real>
+        <Real Name="Z">1.5704244</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96205664</Real>
+        <Real Name="Y">0.62431675</Real>
+        <Real Name="Z">1.6645229</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92838252</Real>
+        <Real Name="Y">0.7061857</Real>
+        <Real Name="Z">1.5417123</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3931589</Real>
+        <Real Name="Y">0.44735631</Real>
+        <Real Name="Z">1.177462</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3336065</Real>
+        <Real Name="Y">0.4771539</Real>
+        <Real Name="Z">1.2462219</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3355844</Real>
+        <Real Name="Y">0.41415587</Real>
+        <Real Name="Z">1.1085765</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6471413</Real>
+        <Real Name="Y">0.31572494</Real>
+        <Real Name="Z">0.29898876</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7056693</Real>
+        <Real Name="Y">0.33273715</Real>
+        <Real Name="Z">0.22518238</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5974983</Real>
+        <Real Name="Y">0.23816451</Real>
+        <Real Name="Z">0.2728686</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7764891</Real>
+        <Real Name="Y">0.39614454</Real>
+        <Real Name="Z">0.022674039</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.712311</Real>
+        <Real Name="Y">0.40957499</Real>
+        <Real Name="Z">1.814998</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8063201</Real>
+        <Real Name="Y">0.48428038</Real>
+        <Real Name="Z">0.045135282</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.24509245</Real>
+        <Real Name="Y">-0.72261846</Real>
+        <Real Name="Z">-0.13603236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.62228543</Real>
+        <Real Name="Y">-0.82350731</Real>
+        <Real Name="Z">0.65246499</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6712279</Real>
+        <Real Name="Y">-0.66578299</Real>
+        <Real Name="Z">1.2254615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45921987</Real>
+        <Real Name="Y">-0.1249053</Real>
+        <Real Name="Z">0.16829936</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4888017</Real>
+        <Real Name="Y">1.0727788</Real>
+        <Real Name="Z">0.43556768</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5986701</Real>
+        <Real Name="Y">0.61206311</Real>
+        <Real Name="Z">0.097001143</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.50264651</Real>
+        <Real Name="Y">0.039873727</Real>
+        <Real Name="Z">0.41833919</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.54661274</Real>
+        <Real Name="Y">0.092727907</Real>
+        <Real Name="Z">1.3179328</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.5448171</Real>
+        <Real Name="Y">-2.0395236</Real>
+        <Real Name="Z">2.2283819</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26042402</Real>
+        <Real Name="Y">0.3338407</Real>
+        <Real Name="Z">-0.39613727</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.29252464</Real>
+        <Real Name="Y">0.85340893</Real>
+        <Real Name="Z">-0.25280377</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39071029</Real>
+        <Real Name="Y">0.41557524</Real>
+        <Real Name="Z">-0.89190936</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20271613</Real>
+        <Real Name="Y">0.47850075</Real>
+        <Real Name="Z">-0.2912524</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42807728</Real>
+        <Real Name="Y">-0.55615687</Real>
+        <Real Name="Z">-1.0859834</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8305813</Real>
+        <Real Name="Y">0.9640227</Real>
+        <Real Name="Z">0.032177288</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.1849518</Real>
+        <Real Name="Y">62.767319</Real>
+        <Real Name="Z">-372.54938</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.8838844</Real>
+        <Real Name="Y">0.96609497</Real>
+        <Real Name="Z">111.87108</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.36542</Real>
+        <Real Name="Y">61.986015</Real>
+        <Real Name="Z">206.26207</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.764641</Real>
+        <Real Name="Y">-19.108894</Real>
+        <Real Name="Z">-38.861778</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.645111</Real>
+        <Real Name="Y">-9.5528107</Real>
+        <Real Name="Z">-24.639069</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4778404</Real>
+        <Real Name="Y">10.632778</Real>
+        <Real Name="Z">12.93914</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.620796</Real>
+        <Real Name="Y">-7.1101837</Real>
+        <Real Name="Z">-33.285667</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-57.110104</Real>
+        <Real Name="Y">11.194328</Real>
+        <Real Name="Z">-15.181065</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.702881</Real>
+        <Real Name="Y">18.987759</Real>
+        <Real Name="Z">56.584343</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-309.56281</Real>
+        <Real Name="Y">-124.03668</Real>
+        <Real Name="Z">255.95786</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">237.11014</Real>
+        <Real Name="Y">108.11028</Real>
+        <Real Name="Z">-280.73593</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">114.12157</Real>
+        <Real Name="Y">55.629196</Real>
+        <Real Name="Z">-58.047287</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-58.040863</Real>
+        <Real Name="Y">-240.38489</Real>
+        <Real Name="Z">-2.0724182</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.1384239</Real>
+        <Real Name="Y">45.224449</Real>
+        <Real Name="Z">16.926575</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.8027</Real>
+        <Real Name="Y">24.695267</Real>
+        <Real Name="Z">164.83154</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620576</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620576</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620576</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0034170724</Real>
+        <Real Name="Y">0.60648358</Real>
+        <Real Name="Z">0.23552604</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.024422608</Real>
+        <Real Name="Y">0.66686666</Real>
+        <Real Name="Z">0.30676484</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.084952176</Real>
+        <Real Name="Y">0.59847569</Real>
+        <Real Name="Z">0.18602638</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9717918</Real>
+        <Real Name="Y">0.63336569</Real>
+        <Real Name="Z">1.5675673</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97486883</Real>
+        <Real Name="Y">0.60615802</Real>
+        <Real Name="Z">1.6592876</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.89013922</Real>
+        <Real Name="Y">0.68272603</Real>
+        <Real Name="Z">1.5599036</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959576</Real>
+        <Real Name="Y">0.44167224</Real>
+        <Real Name="Z">1.1693362</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3336316</Real>
+        <Real Name="Y">0.43679103</Real>
+        <Real Name="Z">1.2418203</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3513826</Real>
+        <Real Name="Y">0.39857104</Real>
+        <Real Name="Z">1.0964139</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6451527</Real>
+        <Real Name="Y">0.31675223</Real>
+        <Real Name="Z">0.30355188</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6954362</Real>
+        <Real Name="Y">0.33304125</Real>
+        <Real Name="Z">0.22374871</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5994555</Real>
+        <Real Name="Y">0.23434544</Real>
+        <Real Name="Z">0.28672311</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7765347</Real>
+        <Real Name="Y">0.39355877</Real>
+        <Real Name="Z">0.033128105</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7163427</Real>
+        <Real Name="Y">0.42431563</Real>
+        <Real Name="Z">1.8274121</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8486691</Real>
+        <Real Name="Y">0.45645806</Real>
+        <Real Name="Z">0.031502429</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.10588159</Real>
+        <Real Name="Y">0.64339352</Real>
+        <Real Name="Z">-0.61728913</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67058426</Real>
+        <Real Name="Y">-3.3763533</Real>
+        <Real Name="Z">2.8220227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8132885</Real>
+        <Real Name="Y">-1.63633</Real>
+        <Real Name="Z">2.3906372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19684787</Real>
+        <Real Name="Y">0.14222711</Real>
+        <Real Name="Z">-0.11289637</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5065674</Real>
+        <Real Name="Y">-0.48782685</Real>
+        <Real Name="Z">-0.33861867</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2730631</Real>
+        <Real Name="Y">-1.3638253</Real>
+        <Real Name="Z">1.2999779</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1307414</Real>
+        <Real Name="Y">-0.34678811</Real>
+        <Real Name="Z">-0.27513614</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90702146</Real>
+        <Real Name="Y">-2.1672072</Real>
+        <Real Name="Z">0.52931434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21554555</Real>
+        <Real Name="Y">-1.7736021</Real>
+        <Real Name="Z">0.33919841</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.013792425</Real>
+        <Real Name="Y">0.21474239</Real>
+        <Real Name="Z">0.082416549</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.58958763</Real>
+        <Real Name="Y">1.1210244</Real>
+        <Real Name="Z">-0.12053254</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.60114127</Real>
+        <Real Name="Y">-0.06730026</Real>
+        <Real Name="Z">-0.14546779</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11822164</Real>
+        <Real Name="Y">-0.0090760374</Real>
+        <Real Name="Z">0.46128684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.32161766</Real>
+        <Real Name="Y">0.80226749</Real>
+        <Real Name="Z">0.43258265</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.0033696</Real>
+        <Real Name="Y">-1.280437</Real>
+        <Real Name="Z">0.11776792</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">153.26878</Real>
+        <Real Name="Y">100.14955</Real>
+        <Real Name="Z">-279.31244</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-42.068977</Real>
+        <Real Name="Y">-32.734707</Real>
+        <Real Name="Z">77.321655</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.884781</Real>
+        <Real Name="Y">43.893906</Real>
+        <Real Name="Z">191.57845</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">9.8715591</Real>
+        <Real Name="Y">-26.672424</Real>
+        <Real Name="Z">-24.891724</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.298355</Real>
+        <Real Name="Y">-5.4042263</Real>
+        <Real Name="Z">-27.104107</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">26.758175</Real>
+        <Real Name="Y">-8.8570137</Real>
+        <Real Name="Z">-23.404736</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.631248</Real>
+        <Real Name="Y">-17.068108</Real>
+        <Real Name="Z">-27.994053</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.458179</Real>
+        <Real Name="Y">17.380032</Real>
+        <Real Name="Z">-21.189655</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-67.095482</Real>
+        <Real Name="Y">41.501686</Real>
+        <Real Name="Z">83.279861</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-262.33932</Real>
+        <Real Name="Y">-175.00864</Real>
+        <Real Name="Z">379.87369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">235.20134</Real>
+        <Real Name="Y">174.97668</Real>
+        <Real Name="Z">-390.06131</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">95.19281</Real>
+        <Real Name="Y">78.558342</Real>
+        <Real Name="Z">-89.106323</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-95.184509</Real>
+        <Real Name="Y">-430.58673</Real>
+        <Real Name="Z">7.019104</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.15373</Real>
+        <Real Name="Y">112.74017</Real>
+        <Real Name="Z">38.997917</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.11433</Real>
+        <Real Name="Y">127.13152</Real>
+        <Real Name="Z">104.99358</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562597</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562597</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562597</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562597</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562569</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562569</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562569</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562569</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562535</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562535</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562535</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562349</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.456274</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.456274</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.456274</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.456274</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">18.791607</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">17.359474</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">18.787497</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">18.78771</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">18.787731</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">20.344707</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">20.34478</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">20.344202</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">20.343077</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">26.067837</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">26.085533</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">26.768679</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">26.083387</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">18.733389</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">18.731955</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">18.730427</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">18.728645</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">28.072332</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.391315</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.803036</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">30.881325</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">31.10914</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">31.741867</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">32.981155</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">34.369827</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.895466</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">35.529175</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">35.971992</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">35.748043</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">35.602959</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">38.232567</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">39.595753</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">41.01062</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">42.453064</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5650139</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5487118</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6267872</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8545809</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.554067</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.793282</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.182531</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.709295</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.1287</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.553822</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-12.019358</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-12.559565</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.774055</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.138676</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.555071</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-21.999296</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21190877</Real>
+        <Real Name="Y">-0.73113304</Real>
+        <Real Name="Z">0.011277338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.66796941</Real>
+        <Real Name="Y">-0.44908154</Real>
+        <Real Name="Z">-0.19935304</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.080868699</Real>
+        <Real Name="Y">-1.3642008</Real>
+        <Real Name="Z">0.095872603</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44769731</Real>
+        <Real Name="Y">-0.12958133</Real>
+        <Real Name="Z">0.17146564</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1259595</Real>
+        <Real Name="Y">1.2299777</Real>
+        <Real Name="Z">0.59934753</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4102879</Real>
+        <Real Name="Y">0.66582245</Real>
+        <Real Name="Z">0.10724045</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.42090845</Real>
+        <Real Name="Y">0.039798632</Real>
+        <Real Name="Z">0.42398912</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31489116</Real>
+        <Real Name="Y">0.033143241</Real>
+        <Real Name="Z">1.2373283</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7872748</Real>
+        <Real Name="Y">-2.0657148</Real>
+        <Real Name="Z">1.5960392</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26079154</Real>
+        <Real Name="Y">0.32045048</Real>
+        <Real Name="Z">-0.34788135</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.14831775</Real>
+        <Real Name="Y">0.34903857</Real>
+        <Real Name="Z">-0.43145278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019986875</Real>
+        <Real Name="Y">0.52854216</Real>
+        <Real Name="Z">-0.45931953</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15528721</Real>
+        <Real Name="Y">0.54477292</Real>
+        <Real Name="Z">-0.27405369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25908729</Real>
+        <Real Name="Y">-0.78199595</Real>
+        <Real Name="Z">-1.2374361</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93642789</Real>
+        <Real Name="Y">1.1511997</Real>
+        <Real Name="Z">-1.0669613</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620597</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620597</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620597</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059504276</Real>
+        <Real Name="Y">0.59963584</Real>
+        <Real Name="Z">0.23899931</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8576183</Real>
+        <Real Name="Y">0.68774992</Real>
+        <Real Name="Z">0.27491909</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062268782</Real>
+        <Real Name="Y">0.61139309</Real>
+        <Real Name="Z">0.1624988</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97426736</Real>
+        <Real Name="Y">0.6307205</Real>
+        <Real Name="Z">1.5712103</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94468415</Real>
+        <Real Name="Y">0.59368181</Real>
+        <Real Name="Z">1.6543684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90880311</Real>
+        <Real Name="Y">0.69723016</Real>
+        <Real Name="Z">1.5499213</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3965044</Real>
+        <Real Name="Y">0.44683748</Real>
+        <Real Name="Z">1.1687438</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3311217</Real>
+        <Real Name="Y">0.47343054</Real>
+        <Real Name="Z">1.2333987</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3462793</Real>
+        <Real Name="Y">0.4315761</Real>
+        <Real Name="Z">1.0887011</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.643361</Real>
+        <Real Name="Y">0.31607834</Real>
+        <Real Name="Z">0.30742615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7028425</Real>
+        <Real Name="Y">0.33838981</Real>
+        <Real Name="Z">0.23582679</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.60906</Real>
+        <Real Name="Y">0.2298052</Real>
+        <Real Name="Z">0.28412992</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7792419</Real>
+        <Real Name="Y">0.39118895</Real>
+        <Real Name="Z">0.02453411</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6976756</Real>
+        <Real Name="Y">0.42097467</Real>
+        <Real Name="Z">1.846319</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8184122</Real>
+        <Real Name="Y">0.47057295</Real>
+        <Real Name="Z">0.060950961</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.1129016</Real>
+        <Real Name="Y">-0.019850576</Real>
+        <Real Name="Z">-0.70904356</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4542389</Real>
+        <Real Name="Y">-0.5607568</Real>
+        <Real Name="Z">1.0794379</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0417492</Real>
+        <Real Name="Y">0.43964252</Real>
+        <Real Name="Z">0.74210674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.096688889</Real>
+        <Real Name="Y">-0.0367507</Real>
+        <Real Name="Z">0.27521297</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63536286</Real>
+        <Real Name="Y">-2.6533091</Real>
+        <Real Name="Z">-1.02859</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.85227448</Real>
+        <Real Name="Y">-0.49061295</Real>
+        <Real Name="Z">1.1447501</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.058465049</Real>
+        <Real Name="Y">-0.021635365</Real>
+        <Real Name="Z">-0.65751112</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22554556</Real>
+        <Real Name="Y">-0.40557593</Real>
+        <Real Name="Z">-0.20906946</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.45968288</Real>
+        <Real Name="Y">0.10622752</Real>
+        <Real Name="Z">-0.43174902</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21811114</Real>
+        <Real Name="Y">0.37035498</Real>
+        <Real Name="Z">0.64805996</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.013067935</Real>
+        <Real Name="Y">1.4087552</Real>
+        <Real Name="Z">1.1324444</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8893229</Real>
+        <Real Name="Y">-0.49259403</Real>
+        <Real Name="Z">0.62956828</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11268703</Real>
+        <Real Name="Y">-0.09580069</Real>
+        <Real Name="Z">-0.06851019</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1881887</Real>
+        <Real Name="Y">0.51014715</Real>
+        <Real Name="Z">2.88065</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11835963</Real>
+        <Real Name="Y">-0.97785115</Real>
+        <Real Name="Z">2.1837807</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-65.826874</Real>
+        <Real Name="Y">-107.79721</Real>
+        <Real Name="Z">-417.77945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11085892</Real>
+        <Real Name="Y">34.977211</Real>
+        <Real Name="Z">108.93626</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">176.37561</Real>
+        <Real Name="Y">148.13066</Real>
+        <Real Name="Z">169.19189</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.760002</Real>
+        <Real Name="Y">-14.338161</Real>
+        <Real Name="Z">-37.669838</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.743313</Real>
+        <Real Name="Y">-8.0399647</Real>
+        <Real Name="Z">-23.763134</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3190346</Real>
+        <Real Name="Y">7.6845188</Real>
+        <Real Name="Z">12.795132</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.251244</Real>
+        <Real Name="Y">-14.264183</Real>
+        <Real Name="Z">-32.995361</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.500019</Real>
+        <Real Name="Y">12.045322</Real>
+        <Real Name="Z">27.178833</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.935509</Real>
+        <Real Name="Y">16.91247</Real>
+        <Real Name="Z">54.454372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-258.0246</Real>
+        <Real Name="Y">-52.426613</Real>
+        <Real Name="Z">177.83249</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">212.23019</Real>
+        <Real Name="Y">26.334526</Real>
+        <Real Name="Z">-198.76645</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.866211</Real>
+        <Real Name="Y">33.2668</Real>
+        <Real Name="Z">-54.004059</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-61.046539</Real>
+        <Real Name="Y">-234.54472</Real>
+        <Real Name="Z">8.5672607</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.06134</Real>
+        <Real Name="Y">75.194359</Real>
+        <Real Name="Z">-10.679977</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.623505</Real>
+        <Real Name="Y">76.864975</Real>
+        <Real Name="Z">216.702</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620614</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620614</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620614</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0012125584</Real>
+        <Real Name="Y">0.58877873</Real>
+        <Real Name="Z">0.24149442</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8544141</Real>
+        <Real Name="Y">0.67520911</Real>
+        <Real Name="Z">0.28166428</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076782599</Real>
+        <Real Name="Y">0.59698445</Real>
+        <Real Name="Z">0.18332094</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98226029</Real>
+        <Real Name="Y">0.62905431</Real>
+        <Real Name="Z">1.5717956</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97475445</Real>
+        <Real Name="Y">0.6319288</Real>
+        <Real Name="Z">1.6671776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94160014</Real>
+        <Real Name="Y">0.71044737</Real>
+        <Real Name="Z">1.5420594</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.388887</Real>
+        <Real Name="Y">0.44761443</Real>
+        <Real Name="Z">1.1806893</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3383858</Real>
+        <Real Name="Y">0.47840545</Real>
+        <Real Name="Z">1.2559481</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3257873</Real>
+        <Real Name="Y">0.39879748</Real>
+        <Real Name="Z">1.1277966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6491549</Real>
+        <Real Name="Y">0.31835186</Real>
+        <Real Name="Z">0.29571038</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7084886</Real>
+        <Real Name="Y">0.34170932</Real>
+        <Real Name="Z">0.22432223</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.602532</Real>
+        <Real Name="Y">0.24106303</Real>
+        <Real Name="Z">0.26385036</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7748276</Real>
+        <Real Name="Y">0.39961365</Real>
+        <Real Name="Z">0.020423496</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7162387</Real>
+        <Real Name="Y">0.40728298</Real>
+        <Real Name="Z">1.8071798</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7872006</Real>
+        <Real Name="Y">0.48964903</Real>
+        <Real Name="Z">0.050471202</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21839961</Real>
+        <Real Name="Y">-0.61221218</Real>
+        <Real Name="Z">-0.3417547</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.3663227</Real>
+        <Real Name="Y">-1.4352521</Real>
+        <Real Name="Z">1.6186291</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4102504</Real>
+        <Real Name="Y">-0.86396545</Real>
+        <Real Name="Z">2.8878915</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44234815</Real>
+        <Real Name="Y">-0.10459462</Real>
+        <Real Name="Z">0.17600323</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6440507</Real>
+        <Real Name="Y">0.85908777</Real>
+        <Real Name="Z">0.25415993</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6905296</Real>
+        <Real Name="Y">0.46368715</Real>
+        <Real Name="Z">-0.007264324</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.55788469</Real>
+        <Real Name="Y">0.024632791</Real>
+        <Real Name="Z">0.39371467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.61759883</Real>
+        <Real Name="Y">0.21255817</Real>
+        <Real Name="Z">1.118535</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96270055</Real>
+        <Real Name="Y">-1.8188128</Real>
+        <Real Name="Z">2.5024037</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24530165</Real>
+        <Real Name="Y">0.32420504</Real>
+        <Real Name="Z">-0.42157286</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39689723</Real>
+        <Real Name="Y">1.3121566</Real>
+        <Real Name="Z">0.019339452</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.81787318</Real>
+        <Real Name="Y">0.33513635</Real>
+        <Real Name="Z">-1.3034421</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20873824</Real>
+        <Real Name="Y">0.40667999</Real>
+        <Real Name="Z">-0.26802832</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53653961</Real>
+        <Real Name="Y">-0.02101266</Real>
+        <Real Name="Z">-0.89883941</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.797363</Real>
+        <Real Name="Y">0.3421177</Real>
+        <Real Name="Z">1.1358343</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-76.593307</Real>
+        <Real Name="Y">73.294724</Real>
+        <Real Name="Z">-359.96191</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.740818</Real>
+        <Real Name="Y">-1.1328201</Real>
+        <Real Name="Z">111.67725</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">133.47488</Real>
+        <Real Name="Y">-2.8443298</Real>
+        <Real Name="Z">131.2657</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">24.163239</Real>
+        <Real Name="Y">-24.225266</Real>
+        <Real Name="Z">-37.449142</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.8203888</Real>
+        <Real Name="Y">7.2992325</Real>
+        <Real Name="Z">14.32785</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.433815</Real>
+        <Real Name="Y">13.098379</Real>
+        <Real Name="Z">11.717995</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.821228</Real>
+        <Real Name="Y">-3.5229301</Real>
+        <Real Name="Z">-32.16494</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.493889</Real>
+        <Real Name="Y">8.797554</Real>
+        <Real Name="Z">-18.446175</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.307556</Real>
+        <Real Name="Y">4.2132664</Real>
+        <Real Name="Z">18.144985</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-317.47601</Real>
+        <Real Name="Y">-134.88672</Real>
+        <Real Name="Z">279.27707</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">245.32898</Real>
+        <Real Name="Y">104.12957</Real>
+        <Real Name="Z">-285.82486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">119.25689</Real>
+        <Real Name="Y">61.66758</Real>
+        <Real Name="Z">-65.235611</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.799133</Real>
+        <Real Name="Y">-324.34424</Real>
+        <Real Name="Z">-37.248474</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.956017</Real>
+        <Real Name="Y">57.656509</Real>
+        <Real Name="Z">25.981705</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.817993</Real>
+        <Real Name="Y">160.79955</Real>
+        <Real Name="Z">243.9386</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 2">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98715
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562597</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562597</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562597</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562597</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562535</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562535</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562535</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562535</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562569</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562569</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562569</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562421</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562597</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562597</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562597</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562597</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.98745</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">31.129892</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.990484</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.990284</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">29.990221</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">26.067739</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">26.068399</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">26.069365</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">26.070429</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">20.345005</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">20.342028</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">20.484623</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">20.330456</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">29.991104</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">29.990414</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">29.948942</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">29.947643</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">39.264248</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">37.895439</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">36.629311</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">36.601009</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">36.670311</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">34.230846</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.457932</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">34.748703</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.104935</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">37.538258</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">39.269753</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">40.899467</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">42.530575</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">42.057907</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">43.069214</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">44.10611</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">45.153988</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.4404144</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.313695</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.285593</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.3549585</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.8343964</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.060822</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.350629</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.705794</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.354086</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.088558</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-22.874723</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.659998</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-14.324274</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-15.336271</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-16.414639</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-17.463816</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.55872297</Real>
+        <Real Name="Y">-0.19543174</Real>
+        <Real Name="Z">-0.12331802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5561588</Real>
+        <Real Name="Y">0.15019241</Real>
+        <Real Name="Z">-0.44760495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2265118</Real>
+        <Real Name="Y">-1.1768512</Real>
+        <Real Name="Z">-1.2616764</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10263991</Real>
+        <Real Name="Y">0.57440907</Real>
+        <Real Name="Z">0.0053722998</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.35943791</Real>
+        <Real Name="Y">0.13711332</Real>
+        <Real Name="Z">-0.18872896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6768553</Real>
+        <Real Name="Y">2.2024438</Real>
+        <Real Name="Z">0.65932018</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22449927</Real>
+        <Real Name="Y">0.27064398</Real>
+        <Real Name="Z">0.38681656</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.18288493</Real>
+        <Real Name="Y">3.1066663</Real>
+        <Real Name="Z">-0.46535692</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.43482876</Real>
+        <Real Name="Y">-1.4385394</Real>
+        <Real Name="Z">0.8301881</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11927342</Real>
+        <Real Name="Y">-0.50285125</Real>
+        <Real Name="Z">0.091731116</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.6758315</Real>
+        <Real Name="Y">-0.055776317</Real>
+        <Real Name="Z">0.61587429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2213309</Real>
+        <Real Name="Y">-1.9672643</Real>
+        <Real Name="Z">0.44974977</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.90470046</Real>
+        <Real Name="Y">-0.2009875</Real>
+        <Real Name="Z">-0.24253644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.8438639</Real>
+        <Real Name="Y">0.72260296</Real>
+        <Real Name="Z">-1.8703772</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39639631</Real>
+        <Real Name="Y">-0.8200264</Real>
+        <Real Name="Z">-0.19537324</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620594</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620594</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620594</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.003549397</Real>
+        <Real Name="Y">0.60224652</Real>
+        <Real Name="Z">0.2402662</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.010176502</Real>
+        <Real Name="Y">0.68663096</Real>
+        <Real Name="Z">0.28496146</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.067507543</Real>
+        <Real Name="Y">0.60761416</Real>
+        <Real Name="Z">0.16925311</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9733966</Real>
+        <Real Name="Y">0.63218689</Real>
+        <Real Name="Z">1.5683956</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96277553</Real>
+        <Real Name="Y">0.61039513</Real>
+        <Real Name="Z">1.6609949</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90174901</Real>
+        <Real Name="Y">0.69282687</Real>
+        <Real Name="Z">1.5496409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3967527</Real>
+        <Real Name="Y">0.44437531</Real>
+        <Real Name="Z">1.1716282</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3288317</Real>
+        <Real Name="Y">0.45572823</Real>
+        <Real Name="Z">1.2381126</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3495874</Real>
+        <Real Name="Y">0.4139646</Real>
+        <Real Name="Z">1.0940851</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450856</Real>
+        <Real Name="Y">0.31497097</Real>
+        <Real Name="Z">0.30285335</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6997873</Real>
+        <Real Name="Y">0.32713202</Real>
+        <Real Name="Z">0.22525081</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5959805</Real>
+        <Real Name="Y">0.23471138</Real>
+        <Real Name="Z">0.28526342</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7773693</Real>
+        <Real Name="Y">0.39315185</Real>
+        <Real Name="Z">0.029244781</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7133238</Real>
+        <Real Name="Y">0.41902053</Real>
+        <Real Name="Z">1.8250372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.837309</Real>
+        <Real Name="Y">0.46755701</Real>
+        <Real Name="Z">0.035025105</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.1404493</Real>
+        <Real Name="Y">0.38177678</Real>
+        <Real Name="Z">-0.53732103</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9413846</Real>
+        <Real Name="Y">-1.2762038</Real>
+        <Real Name="Z">2.3673573</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3785017</Real>
+        <Real Name="Y">-0.54021811</Real>
+        <Real Name="Z">1.579507</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20176861</Real>
+        <Real Name="Y">0.15113764</Real>
+        <Real Name="Z">-0.091641173</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4959286</Real>
+        <Real Name="Y">-0.57117224</Real>
+        <Real Name="Z">-0.048386041</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.6690072</Real>
+        <Real Name="Y">-1.1321731</Real>
+        <Real Name="Z">1.2172091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.056601621</Real>
+        <Real Name="Y">-0.33116889</Real>
+        <Real Name="Z">-0.29847628</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.19054805</Real>
+        <Real Name="Y">-2.5761054</Real>
+        <Real Name="Z">0.37923306</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.16495264</Real>
+        <Real Name="Y">-2.0788357</Real>
+        <Real Name="Z">0.23038527</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0055810227</Real>
+        <Real Name="Y">0.23369618</Real>
+        <Real Name="Z">0.093556888</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.5023402</Real>
+        <Real Name="Y">0.24985836</Real>
+        <Real Name="Z">-0.26447228</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21000603</Real>
+        <Real Name="Y">-0.0023754267</Real>
+        <Real Name="Z">0.59023899</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.088682204</Real>
+        <Real Name="Y">0.11679573</Real>
+        <Real Name="Z">0.51697469</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45121691</Real>
+        <Real Name="Y">0.52429414</Real>
+        <Real Name="Z">0.14985284</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9879831</Real>
+        <Real Name="Y">-1.3623033</Real>
+        <Real Name="Z">-1.1709347</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">114.76115</Real>
+        <Real Name="Y">82.870529</Real>
+        <Real Name="Z">-321.85577</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-29.900101</Real>
+        <Real Name="Y">-17.43676</Real>
+        <Real Name="Z">88.68187</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">63.476105</Real>
+        <Real Name="Y">77.903847</Real>
+        <Real Name="Z">217.68457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.950493</Real>
+        <Real Name="Y">-21.646088</Real>
+        <Real Name="Z">-33.218597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.981686</Real>
+        <Real Name="Y">-6.982954</Real>
+        <Real Name="Z">-24.665527</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6794586</Real>
+        <Real Name="Y">9.5336246</Real>
+        <Real Name="Z">10.62273</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.488716</Real>
+        <Real Name="Y">-13.956066</Real>
+        <Real Name="Z">-31.219357</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.479649</Real>
+        <Real Name="Y">13.377634</Real>
+        <Real Name="Z">24.978691</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.261784</Real>
+        <Real Name="Y">19.673851</Real>
+        <Real Name="Z">53.50206</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-293.6347</Real>
+        <Real Name="Y">-158.94904</Real>
+        <Real Name="Z">314.22507</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">235.19765</Real>
+        <Real Name="Y">157.0984</Real>
+        <Real Name="Z">-332.6882</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">105.37209</Real>
+        <Real Name="Y">68.886345</Real>
+        <Real Name="Z">-72.31221</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-69.739944</Real>
+        <Real Name="Y">-325.66626</Real>
+        <Real Name="Z">-19.780945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-16.873493</Real>
+        <Real Name="Y">78.414734</Real>
+        <Real Name="Z">-5.0457306</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-108.65871</Real>
+        <Real Name="Y">36.878181</Real>
+        <Real Name="Z">131.0914</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.013334357</Real>
+        <Real Name="Y">0.59736609</Real>
+        <Real Name="Z">0.23976123</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.005318061</Real>
+        <Real Name="Y">0.68508893</Real>
+        <Real Name="Z">0.27721474</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.058563087</Real>
+        <Real Name="Y">0.61086649</Real>
+        <Real Name="Z">0.15648805</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97656238</Real>
+        <Real Name="Y">0.64023745</Real>
+        <Real Name="Z">1.5684611</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94736677</Real>
+        <Real Name="Y">0.61625803</Real>
+        <Real Name="Z">1.6564094</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94494897</Real>
+        <Real Name="Y">0.72975796</Real>
+        <Real Name="Z">1.5562552</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3931686</Real>
+        <Real Name="Y">0.45156142</Real>
+        <Real Name="Z">1.1803741</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3386581</Real>
+        <Real Name="Y">0.51867449</Real>
+        <Real Name="Z">1.2214442</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3365031</Real>
+        <Real Name="Y">0.41174328</Real>
+        <Real Name="Z">1.1142995</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6467632</Real>
+        <Real Name="Y">0.30449155</Real>
+        <Real Name="Z">0.30268547</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7107079</Real>
+        <Real Name="Y">0.33632717</Real>
+        <Real Name="Z">0.23896812</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6381752</Real>
+        <Real Name="Y">0.21111529</Real>
+        <Real Name="Z">0.28346473</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7630883</Real>
+        <Real Name="Y">0.38761577</Real>
+        <Real Name="Z">0.020901443</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.727234</Real>
+        <Real Name="Y">0.42663264</Real>
+        <Real Name="Z">1.8032465</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8109468</Real>
+        <Real Name="Y">0.45896062</Real>
+        <Real Name="Z">0.063112676</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.50774837</Real>
+        <Real Name="Y">-0.14377126</Real>
+        <Real Name="Z">-0.40914693</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1766282</Real>
+        <Real Name="Y">-0.80711323</Real>
+        <Real Name="Z">1.3404171</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8747494</Real>
+        <Real Name="Y">1.0309957</Real>
+        <Real Name="Z">0.49931186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.098879606</Real>
+        <Real Name="Y">0.59804106</Real>
+        <Real Name="Z">-0.069958292</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.14821906</Real>
+        <Real Name="Y">0.026412878</Real>
+        <Real Name="Z">-0.30527526</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9278561</Real>
+        <Real Name="Y">1.4512831</Real>
+        <Real Name="Z">1.2161278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24466389</Real>
+        <Real Name="Y">0.30422741</Real>
+        <Real Name="Z">0.40489131</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.77103192</Real>
+        <Real Name="Y">2.1605523</Real>
+        <Real Name="Z">-1.1950574</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0842721</Real>
+        <Real Name="Y">-0.96436262</Real>
+        <Real Name="Z">1.8559505</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.12059107</Real>
+        <Real Name="Y">-0.58253783</Real>
+        <Real Name="Z">0.011410528</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.087577507</Real>
+        <Real Name="Y">1.0067015</Real>
+        <Real Name="Z">0.57385516</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9121311</Real>
+        <Real Name="Y">-0.91863519</Real>
+        <Real Name="Z">0.190413</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.94583249</Real>
+        <Real Name="Y">-0.33996001</Real>
+        <Real Name="Z">-0.25663248</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3152964</Real>
+        <Real Name="Y">0.81132495</Real>
+        <Real Name="Z">-0.75204355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.3043404</Real>
+        <Real Name="Y">-1.1940494</Real>
+        <Real Name="Z">1.6465267</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-31.482208</Real>
+        <Real Name="Y">-164.8981</Real>
+        <Real Name="Z">-391.52533</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-14.02142</Real>
+        <Real Name="Y">40.212479</Real>
+        <Real Name="Z">99.349426</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">142.69626</Real>
+        <Real Name="Y">174.33684</Real>
+        <Real Name="Z">160.86397</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">13.050438</Real>
+        <Real Name="Y">-4.0839233</Real>
+        <Real Name="Z">-39.331093</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.1776047</Real>
+        <Real Name="Y">-0.31682301</Real>
+        <Real Name="Z">13.303894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-6.3430099</Real>
+        <Real Name="Y">5.321907</Real>
+        <Real Name="Z">15.062153</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">35.750908</Real>
+        <Real Name="Y">-8.7272034</Real>
+        <Real Name="Z">-31.064606</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.33955</Real>
+        <Real Name="Y">2.1326084</Real>
+        <Real Name="Z">25.160236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-12.941181</Real>
+        <Real Name="Y">5.6734352</Real>
+        <Real Name="Z">16.869415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-210.92593</Real>
+        <Real Name="Y">-89.631187</Real>
+        <Real Name="Z">297.68915</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">102.82518</Real>
+        <Real Name="Y">40.496742</Real>
+        <Real Name="Z">-277.63858</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.927612</Real>
+        <Real Name="Y">73.401558</Real>
+        <Real Name="Z">-101.78136</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">24.043686</Real>
+        <Real Name="Y">-177.84523</Real>
+        <Real Name="Z">53.620956</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-39.5303</Real>
+        <Real Name="Y">22.562912</Real>
+        <Real Name="Z">-4.9750671</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-47.532883</Real>
+        <Real Name="Y">81.363983</Real>
+        <Real Name="Z">164.39691</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 3">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.01  1.02  1.03
+Replica exchange interval: 4
+Replica random seed: 98716
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562597</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562535</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562535</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562535</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562597</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562597</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562597</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562597</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562597</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562597</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562597</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562597</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562421</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562421</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562421</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562421</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">26.07069</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">26.708885</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">26.071068</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">26.071045</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">26.071302</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">29.993977</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.994164</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.994076</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.994125</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">29.994186</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">29.99416</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">29.787296</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">29.995674</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">20.329262</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">20.323956</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">20.318975</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">20.315039</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">35.343521</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">34.601944</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">33.931412</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">33.966423</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">34.066818</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">36.836617</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">37.099655</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">37.459538</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.916435</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">38.470379</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">39.120926</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">40.077339</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">41.128056</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">44.261833</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">45.884254</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">47.337353</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">48.564808</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5683126</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5355978</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.5706329</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.6707706</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.5214748</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-9.7843246</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.144294</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.601143</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-11.155027</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.8056</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-12.551479</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-13.393817</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.396416</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-28.024143</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.482222</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.713614</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.19787164</Real>
+        <Real Name="Y">0.16156073</Real>
+        <Real Name="Z">-0.3830564</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.7420168</Real>
+        <Real Name="Y">0.75917548</Real>
+        <Real Name="Z">1.2435496</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3711295</Real>
+        <Real Name="Y">-0.1916929</Real>
+        <Real Name="Z">0.42564186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19638549</Real>
+        <Real Name="Y">0.14565483</Real>
+        <Real Name="Z">-0.067964658</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3802328</Real>
+        <Real Name="Y">-0.58428359</Real>
+        <Real Name="Z">0.2304372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.9488595</Real>
+        <Real Name="Y">-0.88427049</Real>
+        <Real Name="Z">0.94601095</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.023709064</Real>
+        <Real Name="Y">-0.34130558</Real>
+        <Real Name="Z">-0.30921173</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.57465923</Real>
+        <Real Name="Y">-2.6639383</Real>
+        <Real Name="Z">0.20926186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10718073</Real>
+        <Real Name="Y">-2.149086</Real>
+        <Real Name="Z">0.10538759</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.012949247</Real>
+        <Real Name="Y">0.24703081</Real>
+        <Real Name="Z">0.11981639</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53420067</Real>
+        <Real Name="Y">-0.39553621</Real>
+        <Real Name="Z">-0.44761676</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23061849</Real>
+        <Real Name="Y">0.091385715</Real>
+        <Real Name="Z">1.1257544</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.06405513</Real>
+        <Real Name="Y">0.15561384</Real>
+        <Real Name="Z">0.54946572</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53148574</Real>
+        <Real Name="Y">0.53813189</Real>
+        <Real Name="Z">0.031651895</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.0633225</Real>
+        <Real Name="Y">-0.3697392</Real>
+        <Real Name="Z">-2.4264705</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0092401421</Real>
+        <Real Name="Y">0.59861147</Real>
+        <Real Name="Z">0.24244666</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8569745</Real>
+        <Real Name="Y">0.68916672</Real>
+        <Real Name="Z">0.26995736</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.048522495</Real>
+        <Real Name="Y">0.60588443</Real>
+        <Real Name="Z">0.15546209</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97577012</Real>
+        <Real Name="Y">0.63554358</Real>
+        <Real Name="Z">1.5689088</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94889241</Real>
+        <Real Name="Y">0.61586756</Real>
+        <Real Name="Z">1.658646</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92995447</Real>
+        <Real Name="Y">0.71678817</Real>
+        <Real Name="Z">1.5474015</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.395099</Real>
+        <Real Name="Y">0.44920796</Real>
+        <Real Name="Z">1.1771562</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3331138</Real>
+        <Real Name="Y">0.49951556</Real>
+        <Real Name="Z">1.22997</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3442186</Real>
+        <Real Name="Y">0.42042804</Real>
+        <Real Name="Z">1.101359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6458769</Real>
+        <Real Name="Y">0.30896699</Real>
+        <Real Name="Z">0.30251884</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.708936</Real>
+        <Real Name="Y">0.32977763</Real>
+        <Real Name="Z">0.23357838</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6155521</Real>
+        <Real Name="Y">0.22065735</Real>
+        <Real Name="Z">0.28144437</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7706583</Real>
+        <Real Name="Y">0.39011979</Real>
+        <Real Name="Z">0.022985814</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7173589</Real>
+        <Real Name="Y">0.42057618</Real>
+        <Real Name="Z">1.8116025</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177943</Real>
+        <Real Name="Y">0.46807098</Real>
+        <Real Name="Z">0.052381843</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.5195089</Real>
+        <Real Name="Y">-0.1686229</Real>
+        <Real Name="Z">-0.25183299</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4268035</Real>
+        <Real Name="Y">-0.2051765</Real>
+        <Real Name="Z">0.36288297</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38396049</Real>
+        <Real Name="Y">0.021860808</Real>
+        <Real Name="Z">-0.29743016</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.098248608</Real>
+        <Real Name="Y">0.5730359</Real>
+        <Real Name="Z">-0.034597859</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2516267</Real>
+        <Real Name="Y">0.085044965</Real>
+        <Real Name="Z">-0.2442027</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7988997</Real>
+        <Real Name="Y">1.8251824</Real>
+        <Real Name="Z">0.94647646</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23444991</Real>
+        <Real Name="Y">0.28033921</Real>
+        <Real Name="Z">0.39544567</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.54848427</Real>
+        <Real Name="Y">2.6672046</Real>
+        <Real Name="Z">-0.88390613</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.77698988</Real>
+        <Real Name="Y">-1.2166719</Real>
+        <Real Name="Z">1.3058895</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10313097</Real>
+        <Real Name="Y">-0.52910477</Real>
+        <Real Name="Z">0.03884792</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.54200804</Real>
+        <Real Name="Y">0.52300477</Real>
+        <Real Name="Z">0.74490809</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.6604416</Real>
+        <Real Name="Y">-1.5171077</Real>
+        <Real Name="Z">0.31898019</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93472397</Real>
+        <Real Name="Y">-0.27102017</Real>
+        <Real Name="Z">-0.25829822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1123816</Real>
+        <Real Name="Y">0.70122254</Real>
+        <Real Name="Z">-1.3844332</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.3290202</Real>
+        <Real Name="Y">-1.0532794</Real>
+        <Real Name="Z">0.88375854</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">15.964417</Real>
+        <Real Name="Y">-60.086899</Real>
+        <Real Name="Z">-386.15738</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.200443</Real>
+        <Real Name="Y">21.858147</Real>
+        <Real Name="Z">103.97392</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">143.61618</Real>
+        <Real Name="Y">171.40668</Real>
+        <Real Name="Z">223.1356</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.480995</Real>
+        <Real Name="Y">-8.4260712</Real>
+        <Real Name="Z">-39.808624</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.57571</Real>
+        <Real Name="Y">-12.044214</Real>
+        <Real Name="Z">-23.761593</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.4336281</Real>
+        <Real Name="Y">6.7495117</Real>
+        <Real Name="Z">14.484768</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.65361</Real>
+        <Real Name="Y">-9.2556953</Real>
+        <Real Name="Z">-32.602776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.318447</Real>
+        <Real Name="Y">5.0569744</Real>
+        <Real Name="Z">27.32048</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.958244</Real>
+        <Real Name="Y">17.919493</Real>
+        <Real Name="Z">54.367748</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-256.49289</Real>
+        <Real Name="Y">-97.948463</Real>
+        <Real Name="Z">270.7847</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">162.03836</Real>
+        <Real Name="Y">75.644821</Real>
+        <Real Name="Z">-290.2265</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.833725</Real>
+        <Real Name="Y">63.502808</Real>
+        <Real Name="Z">-79.814507</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-3.114212</Real>
+        <Real Name="Y">-171.71452</Real>
+        <Real Name="Z">51.052612</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-38.850002</Real>
+        <Real Name="Y">27.333931</Real>
+        <Real Name="Z">-17.723389</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-98.795181</Real>
+        <Real Name="Y">-29.996506</Real>
+        <Real Name="Z">124.97488</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620583</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620583</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620583</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070109405</Real>
+        <Real Name="Y">0.59992617</Real>
+        <Real Name="Z">0.23226979</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0042686425</Real>
+        <Real Name="Y">0.67751718</Real>
+        <Real Name="Z">0.28825584</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.082045607</Real>
+        <Real Name="Y">0.61453891</Real>
+        <Real Name="Z">0.17466263</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97341937</Real>
+        <Real Name="Y">0.63036573</Real>
+        <Real Name="Z">1.5734562</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94144922</Real>
+        <Real Name="Y">0.57317621</Real>
+        <Real Name="Z">1.6432387</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90248138</Real>
+        <Real Name="Y">0.69308424</Real>
+        <Real Name="Z">1.5594383</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959689</Real>
+        <Real Name="Y">0.44667342</Real>
+        <Real Name="Z">1.1635216</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3338052</Real>
+        <Real Name="Y">0.47034895</Real>
+        <Real Name="Z">1.2323509</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3416826</Real>
+        <Real Name="Y">0.43264991</Real>
+        <Real Name="Z">1.0859417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6415145</Real>
+        <Real Name="Y">0.31893572</Real>
+        <Real Name="Z">0.31230706</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7042214</Real>
+        <Real Name="Y">0.34974691</Real>
+        <Real Name="Z">0.24687897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6260748</Real>
+        <Real Name="Y">0.22727498</Real>
+        <Real Name="Z">0.28945443</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7797557</Real>
+        <Real Name="Y">0.39098203</Real>
+        <Real Name="Z">0.024227683</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6906984</Real>
+        <Real Name="Y">0.42131338</Real>
+        <Real Name="Z">0.0065891743</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8161732</Real>
+        <Real Name="Y">0.45667693</Real>
+        <Real Name="Z">0.083559491</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.16439931</Real>
+        <Real Name="Y">0.084085174</Real>
+        <Real Name="Z">-0.94164217</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.68373454</Real>
+        <Real Name="Y">-1.9591984</Real>
+        <Real Name="Z">2.0344369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5616856</Real>
+        <Real Name="Y">0.20752828</Real>
+        <Real Name="Z">2.0827453</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11253488</Real>
+        <Real Name="Y">-0.052045751</Real>
+        <Real Name="Z">0.28474358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22966386</Real>
+        <Real Name="Y">-2.4604015</Real>
+        <Real Name="Z">-1.6734979</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.74588007</Real>
+        <Real Name="Y">-0.54360163</Real>
+        <Real Name="Z">1.2352301</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.073741488</Real>
+        <Real Name="Y">-0.019999217</Real>
+        <Real Name="Z">-0.64900315</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.4249616</Real>
+        <Real Name="Y">-0.36482844</Real>
+        <Real Name="Z">-0.074859336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.6616562</Real>
+        <Real Name="Y">0.15868822</Real>
+        <Real Name="Z">-0.27326229</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23825721</Real>
+        <Real Name="Y">0.34435701</Real>
+        <Real Name="Z">0.57946885</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31694305</Real>
+        <Real Name="Y">1.4151036</Real>
+        <Real Name="Z">1.5968635</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2657197</Real>
+        <Real Name="Y">-0.15384266</Real>
+        <Real Name="Z">0.74269497</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.032040142</Real>
+        <Real Name="Y">0.047499076</Real>
+        <Real Name="Z">0.0141235</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.64692962</Real>
+        <Real Name="Y">-0.33636522</Real>
+        <Real Name="Z">2.5784249</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.34859005</Real>
+        <Real Name="Y">-2.3736904</Real>
+        <Real Name="Z">3.0572178</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-164.18048</Real>
+        <Real Name="Y">-312.65945</Real>
+        <Real Name="Z">-380.76276</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.020203</Real>
+        <Real Name="Y">67.064491</Real>
+        <Real Name="Z">100.6087</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.37497</Real>
+        <Real Name="Y">140.354</Real>
+        <Real Name="Z">74.099861</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.259605</Real>
+        <Real Name="Y">-15.074749</Real>
+        <Real Name="Z">-36.633736</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.846157</Real>
+        <Real Name="Y">-7.1587076</Real>
+        <Real Name="Z">-24.516815</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1982384</Real>
+        <Real Name="Y">7.4239883</Real>
+        <Real Name="Z">12.157993</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.518883</Real>
+        <Real Name="Y">-17.448582</Real>
+        <Real Name="Z">-31.395458</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.655254</Real>
+        <Real Name="Y">14.815317</Real>
+        <Real Name="Z">25.31184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.771149</Real>
+        <Real Name="Y">17.442732</Real>
+        <Real Name="Z">55.076176</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-182.88638</Real>
+        <Real Name="Y">2.5549622</Real>
+        <Real Name="Z">105.67532</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">148.51685</Real>
+        <Real Name="Y">-32.524521</Real>
+        <Real Name="Z">-88.189911</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.434494</Real>
+        <Real Name="Y">10.415039</Real>
+        <Real Name="Z">-49.951965</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-54.022964</Real>
+        <Real Name="Y">-310.85068</Real>
+        <Real Name="Z">-19.775574</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-18.895714</Real>
+        <Real Name="Y">115.38008</Real>
+        <Real Name="Z">0.17680359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.639038</Real>
+        <Real Name="Y">320.26605</Real>
+        <Real Name="Z">258.11951</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_ParrinelloRahman_4Ranks_2RanksPerSimulation_d.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_ParrinelloRahman_4Ranks_2RanksPerSimulation_d.xml
new file mode 100644 (file)
index 0000000..8fb6083
--- /dev/null
@@ -0,0 +1,1696 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562600160298169</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562579188546056</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562579188546056</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562579188546056</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562596808132486</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562596808132486</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562596808132486</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562596808132486</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562596808132486</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562596808132486</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562596808132486</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562737307718585</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562429396654863</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562429396654863</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562429396654863</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562429396654863</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">20.344745942447368</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">21.220300790042927</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">20.338968338604204</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">20.339788659740044</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">20.340470425463167</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">17.80573254099717</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">17.805767967712743</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">17.805714556614699</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">17.805533723508905</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">17.805186787471062</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">17.853143044691709</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">18.208124226007417</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">17.845500018769791</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">20.304673101250394</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">20.299470718522215</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">20.294587433354202</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">20.290578548653031</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629305410083017</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.225575681525967</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">28.961753624312841</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.732148146625001</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">30.658323547277579</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">30.496927784717926</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">31.027352637459437</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">31.705005654759113</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">32.526989352122492</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">33.488567120804461</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">34.528284386557601</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">35.267910432927088</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">36.109838404837809</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">43.024210934218573</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">44.634387309836605</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">46.083133346875044</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">47.315086493564536</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673364533766927</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.158293500466206</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.775803894691808</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.545378095868124</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.47087173079758</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.257211386617103</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.787600812643038</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.465307241040758</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.287471771509932</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.249396476229744</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.241157484762237</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.348849131511091</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.553401310659439</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.353607077390542</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-27.968985835736753</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.422615157943206</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.658577189333869</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.004987833407605083</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858972</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391528</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.02498992600415597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208519</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13823960248430261</Real>
+        <Real Name="Y">-0.083001582473173879</Real>
+        <Real Name="Z">-0.55156788526044931</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807346912896504</Real>
+        <Real Name="Y">0.12594239723743825</Real>
+        <Real Name="Z">0.086340039099900012</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50558175484201939</Real>
+        <Real Name="Y">-0.2634720104901444</Real>
+        <Real Name="Z">-0.37043107548328896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.080341973608849884</Real>
+        <Real Name="Y">-0.036383374851252599</Real>
+        <Real Name="Z">0.26950251001929965</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0879938107726246</Real>
+        <Real Name="Y">-2.69925195488055</Real>
+        <Real Name="Z">-0.41161299800761325</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.005339856872981</Real>
+        <Real Name="Y">-0.4461332722971294</Real>
+        <Real Name="Z">1.1534368241800745</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046991365082634809</Real>
+        <Real Name="Y">-0.027139438957271552</Real>
+        <Real Name="Z">-0.6835695669642462</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.052027730439707112</Real>
+        <Real Name="Y">-0.42394701288611142</Real>
+        <Real Name="Z">-0.38240890291446689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2514527117216987</Real>
+        <Real Name="Y">0.072329295992862808</Real>
+        <Real Name="Z">-0.58384125172376988</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20047275659675184</Real>
+        <Real Name="Y">0.39459474035999648</Real>
+        <Real Name="Z">0.71751226731035556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21660158751017158</Real>
+        <Real Name="Y">1.2107968994948017</Real>
+        <Real Name="Z">0.86109126390401147</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3771064228719012</Real>
+        <Real Name="Y">-0.6610218165066043</Real>
+        <Real Name="Z">0.87071447867481888</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21701225376725289</Real>
+        <Real Name="Y">-0.090547598182204897</Real>
+        <Real Name="Z">-0.034702681691122401</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639425064679751</Real>
+        <Real Name="Y">0.9636306948577793</Real>
+        <Real Name="Z">2.5346418773965156</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37424921124689092</Real>
+        <Real Name="Y">-0.37914050295285695</Real>
+        <Real Name="Z">0.73119277083081202</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959196342</Real>
+        <Real Name="Y">10.126334215507086</Real>
+        <Real Name="Z">-383.9244463652023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773668</Real>
+        <Real Name="Y">8.7835602768706877</Real>
+        <Real Name="Z">109.98162207856127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818237</Real>
+        <Real Name="Y">125.90227601095691</Real>
+        <Real Name="Z">223.10402606189822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.9064510541798</Real>
+        <Real Name="Y">-91.873016441468678</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733365</Real>
+        <Real Name="Y">82.504344401698347</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041526</Real>
+        <Real Name="Y">45.329959216167893</Real>
+        <Real Name="Z">-56.291380508471349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448434</Real>
+        <Real Name="Y">-204.77938512046111</Real>
+        <Real Name="Z">21.695070286562498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013951</Real>
+        <Real Name="Y">47.5995038096992</Real>
+        <Real Name="Z">-24.246658126595179</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564435093</Real>
+        <Real Name="Y">-23.593576368970304</Real>
+        <Real Name="Z">144.65217639452101</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620599677732221</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620599677732221</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620599677732221</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0031330976971096621</Real>
+        <Real Name="Y">0.59421103498992767</Real>
+        <Real Name="Z">0.2434645415528158</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8502640779157913</Real>
+        <Real Name="Y">0.6842895603690855</Real>
+        <Real Name="Z">0.27219262878660994</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059117854013968546</Real>
+        <Real Name="Y">0.6026041140645273</Real>
+        <Real Name="Z">0.16627916933897507</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97860727740332898</Real>
+        <Real Name="Y">0.62998204039647709</Real>
+        <Real Name="Z">1.5703980522320666</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96187744813333986</Real>
+        <Real Name="Y">0.62416270076426228</Real>
+        <Real Name="Z">1.664464871561953</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9281665550246796</Real>
+        <Real Name="Y">0.70610962889793638</Real>
+        <Real Name="Z">1.5417163124858095</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3932227526632537</Real>
+        <Real Name="Y">0.44735185828322294</Real>
+        <Real Name="Z">1.1774071196381815</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3335413582002349</Real>
+        <Real Name="Y">0.47715049095248552</Real>
+        <Real Name="Z">1.2460547055097302</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3357703732867119</Real>
+        <Real Name="Y">0.41442276478543005</Real>
+        <Real Name="Z">1.1082897028361391</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6471053260734081</Real>
+        <Real Name="Y">0.31568075812414625</Real>
+        <Real Name="Z">0.29903687661750744</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7056489266395503</Real>
+        <Real Name="Y">0.33268514841693253</Real>
+        <Real Name="Z">0.22524110476354459</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5975002495075667</Real>
+        <Real Name="Y">0.23809024435588977</Real>
+        <Real Name="Z">0.27293387004595349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7765113097565919</Real>
+        <Real Name="Y">0.39606804137362506</Real>
+        <Real Name="Z">0.022713352710603991</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7122526573835268</Real>
+        <Real Name="Y">0.40968934226160303</Real>
+        <Real Name="Z">1.8151485823707358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8064612666171929</Real>
+        <Real Name="Y">0.48413300796819547</Real>
+        <Real Name="Z">0.045293878451715126</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.24151091942767461</Real>
+        <Real Name="Y">-0.71035702821513758</Real>
+        <Real Name="Z">-0.13632097188490203</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.61075384323547399</Real>
+        <Real Name="Y">-0.81421955640490173</Real>
+        <Real Name="Z">0.6559937358248551</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.670072165092326</Real>
+        <Real Name="Y">-0.63802487749524706</Real>
+        <Real Name="Z">1.2224059383581332</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.45207329296383492</Real>
+        <Real Name="Y">-0.12315756497960181</Real>
+        <Real Name="Z">0.16470467863299537</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4642855465523363</Real>
+        <Real Name="Y">1.0555070687535424</Real>
+        <Real Name="Z">0.43085077602633304</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5697439628562642</Real>
+        <Real Name="Y">0.60453315019304932</Real>
+        <Real Name="Z">0.099497218261723017</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.49409147410011939</Real>
+        <Real Name="Y">0.03949788200351969</Real>
+        <Real Name="Z">0.41181237090929518</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53579708315069041</Real>
+        <Real Name="Y">0.092119577775265207</Real>
+        <Real Name="Z">1.2978062806585404</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.5285404038491415</Real>
+        <Real Name="Y">-2.008926539520143</Real>
+        <Real Name="Z">2.1867068691942664</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25593020649572751</Real>
+        <Real Name="Y">0.3283537722566478</Real>
+        <Real Name="Z">-0.39017309822179291</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.29005656579659828</Real>
+        <Real Name="Y">0.84615264848299465</Real>
+        <Real Name="Z">-0.2457520155828854</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39084843642843681</Real>
+        <Real Name="Y">0.40626586250724928</Real>
+        <Real Name="Z">-0.88328036545392807</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19986406769499088</Real>
+        <Real Name="Y">0.46891582008128641</Real>
+        <Real Name="Z">-0.28619168668928863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.41861452266578403</Real>
+        <Real Name="Y">-0.54155685213631788</Real>
+        <Real Name="Z">-1.0691729915945043</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8112439139580543</Real>
+        <Real Name="Y">0.94651842000862774</Real>
+        <Real Name="Z">0.053513616643597661</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.441432370919415</Real>
+        <Real Name="Y">61.324563987242698</Real>
+        <Real Name="Z">-373.21607629853537</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.9334841631889361</Real>
+        <Real Name="Y">1.205446568517786</Real>
+        <Real Name="Z">111.88757283239869</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.3982253868507</Real>
+        <Real Name="Y">63.024604501284813</Real>
+        <Real Name="Z">206.13817955628605</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.69971690775067</Real>
+        <Real Name="Y">-19.018543824903624</Real>
+        <Real Name="Z">-38.873408263223425</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.662122333220076</Real>
+        <Real Name="Y">-9.5447074705700068</Real>
+        <Real Name="Z">-24.616843861289411</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4642514518266978</Real>
+        <Real Name="Y">10.589059388704648</Real>
+        <Real Name="Z">12.953716845305379</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.600265892568174</Real>
+        <Real Name="Y">-7.1698686253864423</Real>
+        <Real Name="Z">-33.293760441606835</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-57.049812114039945</Real>
+        <Real Name="Y">11.226698182834738</Real>
+        <Real Name="Z">-15.138956440313905</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.677323010157515</Real>
+        <Real Name="Y">18.945941525424356</Real>
+        <Real Name="Z">56.54878239497782</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-309.18444358911802</Real>
+        <Real Name="Y">-123.34552573594652</Real>
+        <Real Name="Z">255.69151137088232</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.86802173461788</Real>
+        <Real Name="Y">107.46312760405743</Real>
+        <Real Name="Z">-280.59032309773573</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">114.02757393146977</Real>
+        <Real Name="Y">55.440901196261024</Real>
+        <Real Name="Z">-58.080194501544071</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-58.364531502892476</Real>
+        <Real Name="Y">-240.29940869251016</Real>
+        <Real Name="Z">-1.8079685334115538</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.1402133760797568</Real>
+        <Real Name="Y">45.318380322561623</Real>
+        <Real Name="Z">17.041045632348442</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.28086136041395</Real>
+        <Real Name="Y">24.839331072427683</Real>
+        <Real Name="Z">165.35672280546152</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620583583249477</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620583583249477</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620583583249477</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.006998153655334345</Real>
+        <Real Name="Y">0.59991995516932561</Real>
+        <Real Name="Z">0.23233019200213634</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0042023279881730413</Real>
+        <Real Name="Y">0.67763500746216221</Real>
+        <Real Name="Z">0.28814123397377611</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.08190211612263476</Real>
+        <Real Name="Y">0.6145461529405708</Real>
+        <Real Name="Z">0.17455658950537939</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97342823838776571</Real>
+        <Real Name="Y">0.6303697721496383</Real>
+        <Real Name="Z">1.5734333023035818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94147011383914969</Real>
+        <Real Name="Y">0.57335299681522522</Real>
+        <Real Name="Z">1.6433624379038443</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90253519978426178</Real>
+        <Real Name="Y">0.69312508786759108</Real>
+        <Real Name="Z">1.559352612451808</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959738097424796</Real>
+        <Real Name="Y">0.44667488882357625</Real>
+        <Real Name="Z">1.1635710834649413</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3337814568533133</Real>
+        <Real Name="Y">0.4703788929904027</Real>
+        <Real Name="Z">1.232364613891632</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3417219745764175</Real>
+        <Real Name="Y">0.43264047509233722</Real>
+        <Real Name="Z">1.0859689442396958</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6415313928666333</Real>
+        <Real Name="Y">0.31891020220493405</Real>
+        <Real Name="Z">0.31226164560440745</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7042174375456132</Real>
+        <Real Name="Y">0.34963994552309352</Real>
+        <Real Name="Z">0.24677530292057306</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6259184713203312</Real>
+        <Real Name="Y">0.22728166827700125</Real>
+        <Real Name="Z">0.28939755036741394</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7797525235441467</Real>
+        <Real Name="Y">0.39097976299613668</Real>
+        <Real Name="Z">0.024229798908556255</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6907470400839988</Real>
+        <Real Name="Y">0.42134435919411922</Real>
+        <Real Name="Z">0.0063878928512306477</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8161712917441628</Real>
+        <Real Name="Y">0.4568361412491847</Real>
+        <Real Name="Z">0.083381545849661565</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.16117913170139414</Real>
+        <Real Name="Y">0.082115131798281879</Real>
+        <Real Name="Z">-0.92959961559459248</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67527991432760637</Real>
+        <Real Name="Y">-1.9288617432509276</Real>
+        <Real Name="Z">2.0125189698258188</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5395910382263596</Real>
+        <Real Name="Y">0.21545148352380805</Real>
+        <Real Name="Z">2.0612602297978797</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11054684363041412</Real>
+        <Real Name="Y">-0.051093233297400835</Real>
+        <Real Name="Z">0.27992773344847577</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22758584712019994</Real>
+        <Real Name="Y">-2.4280384326645641</Real>
+        <Real Name="Z">-1.6446257443105567</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.73587905053415681</Real>
+        <Real Name="Y">-0.5349958189207964</Real>
+        <Real Name="Z">1.2181961049838779</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.072733935647416176</Real>
+        <Real Name="Y">-0.019692535494598307</Real>
+        <Real Name="Z">-0.63925865215173416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42004501139840555</Real>
+        <Real Name="Y">-0.35884615487782695</Real>
+        <Real Name="Z">-0.071963724304560189</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.6539454685851942</Real>
+        <Real Name="Y">0.15673176617514906</Real>
+        <Real Name="Z">-0.26810346685223035</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23493561104470276</Real>
+        <Real Name="Y">0.33948528011516771</Real>
+        <Real Name="Z">0.57052007165324248</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31692065915543804</Real>
+        <Real Name="Y">1.3935428340381368</Real>
+        <Real Name="Z">1.5748888083186121</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2345958604724343</Real>
+        <Real Name="Y">-0.15578000254811467</Real>
+        <Real Name="Z">0.72968782857801717</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.031721193260768402</Real>
+        <Real Name="Y">0.04610556697826608</Real>
+        <Real Name="Z">0.013977032510920811</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.64037126435151759</Real>
+        <Real Name="Y">-0.32395599294636235</Real>
+        <Real Name="Z">2.5414412771166535</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.35233948778416241</Real>
+        <Real Name="Y">-2.3353324717322113</Real>
+        <Real Name="Z">3.0277634292283562</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-163.55618367861791</Real>
+        <Real Name="Y">-310.99412616187385</Real>
+        <Real Name="Z">-381.76319719033955</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">13.921601986198148</Real>
+        <Real Name="Y">66.79649156403795</Real>
+        <Real Name="Z">100.71902422604902</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.55929115019748</Real>
+        <Real Name="Y">140.40392750690785</Real>
+        <Real Name="Z">74.776187893704375</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.257055812274871</Real>
+        <Real Name="Y">-15.06879123312271</Real>
+        <Real Name="Z">-36.64411198762879</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.844034204212207</Real>
+        <Real Name="Y">-7.1663301324253865</Real>
+        <Real Name="Z">-24.509154001546342</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1997443844882696</Real>
+        <Real Name="Y">7.426323855807901</Real>
+        <Real Name="Z">12.163505239794532</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.560029104036957</Real>
+        <Real Name="Y">-17.424008104272318</Real>
+        <Real Name="Z">-31.41421922767573</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.687590972827714</Real>
+        <Real Name="Y">14.793853215977869</Real>
+        <Real Name="Z">25.331886157442284</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.773783763208058</Real>
+        <Real Name="Y">17.438952398034647</Real>
+        <Real Name="Z">55.072093819614039</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-183.69321431973452</Real>
+        <Real Name="Y">2.1072079956204561</Real>
+        <Real Name="Z">106.43450779152627</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">149.22308172367514</Real>
+        <Real Name="Y">-32.151796768271339</Real>
+        <Real Name="Z">-89.363178220184579</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.693393022093261</Real>
+        <Real Name="Y">10.659391308816566</Real>
+        <Real Name="Z">-50.047656869369945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-54.117004383455949</Real>
+        <Real Name="Y">-310.32486862237306</Real>
+        <Real Name="Z">-19.593825078206919</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-18.925421298480721</Real>
+        <Real Name="Y">115.06595163801093</Real>
+        <Real Name="Z">0.21417093832873491</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.894455798125108</Real>
+        <Real Name="Y">318.43782153912451</Real>
+        <Real Name="Z">258.62396650849263</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562600160298169</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562600160298169</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562596808132486</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562596808132486</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562596808132486</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562579188546056</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562579188546056</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562579188546056</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562579188546056</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562579188546056</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562579188546056</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562579188546056</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562429396654863</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562737307718585</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562737307718585</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562737307718585</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562737307718585</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">17.819866492793917</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">16.406158645393088</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">17.813244762378819</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">17.813364097349581</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">17.813478605711499</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">20.34873591084007</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">20.348781349135688</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">20.348298352864106</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">20.347140184402061</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">20.345176264518781</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">20.342318522494626</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">21.062746064157604</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">20.317589280021966</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">17.852139406356816</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">17.850689074624</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">17.849067583473648</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">17.847350450184813</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">27.096610978600332</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">28.40145938962441</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.799472779610717</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.88280657417728</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">30.115254189939478</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">31.741919236475109</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">32.981204052472208</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">34.369875850378364</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.895551821615243</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">37.538394957998868</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">39.269948147614748</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">40.295605810959934</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">41.311780325033808</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">37.406007799413075</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">38.776114730648381</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">40.19856736302259</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">41.64922910937004</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673364533766927</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5691318685511426</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5600591415517187</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6432736011475217</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8756067085477994</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.554016913908921</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.793256291610401</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.182411085788139</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.709245225487063</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.354052281753969</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.088463213394004</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-22.874743952383842</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.636075250593354</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.850746316077931</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.222303579046052</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.646377702570614</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.098756582206899</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.004987833407605083</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858972</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391528</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.02498992600415597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208519</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.20819690585540773</Real>
+        <Real Name="Y">-0.71831964871349085</Real>
+        <Real Name="Z">0.011078438999830157</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.65627408040347335</Real>
+        <Real Name="Y">-0.44130069592945115</Real>
+        <Real Name="Z">-0.19586161682440933</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.07944772612600022</Real>
+        <Real Name="Y">-1.3403514765108808</Real>
+        <Real Name="Z">0.094211853505395182</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43983396430402821</Real>
+        <Real Name="Y">-0.12730113827963044</Real>
+        <Real Name="Z">0.16848744653097211</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1064634752554481</Real>
+        <Real Name="Y">1.208306314237934</Real>
+        <Real Name="Z">0.58865730101337532</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3857124030917944</Real>
+        <Real Name="Y">0.65412452380296571</Real>
+        <Real Name="Z">0.10516368028532735</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.41357531425471322</Real>
+        <Real Name="Y">0.03909994936372093</Real>
+        <Real Name="Z">0.41653530543680806</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.30958260222840822</Real>
+        <Real Name="Y">0.032508253652296773</Real>
+        <Real Name="Z">1.2155924310115984</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7555728294294284</Real>
+        <Real Name="Y">-2.0294504264852296</Real>
+        <Real Name="Z">1.568589118909621</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25622123762474486</Real>
+        <Real Name="Y">0.31483429896995041</Real>
+        <Real Name="Z">-0.34178744751437573</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.1457763418811992</Real>
+        <Real Name="Y">0.34295833952026589</Real>
+        <Real Name="Z">-0.4239403762530316</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019644304201244064</Real>
+        <Real Name="Y">0.5193023809855738</Real>
+        <Real Name="Z">-0.45124050611198896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15257163555120895</Real>
+        <Real Name="Y">0.53524540919668817</Real>
+        <Real Name="Z">-0.26925935975066168</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25467201556722202</Real>
+        <Real Name="Y">-0.76836408689837199</Real>
+        <Real Name="Z">-1.2156468083482905</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.9200810679380822</Real>
+        <Real Name="Y">1.1308821580758028</Real>
+        <Real Name="Z">-1.0483019686667092</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959196342</Real>
+        <Real Name="Y">10.126334215507086</Real>
+        <Real Name="Z">-383.9244463652023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773668</Real>
+        <Real Name="Y">8.7835602768706877</Real>
+        <Real Name="Z">109.98162207856127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818237</Real>
+        <Real Name="Y">125.90227601095691</Real>
+        <Real Name="Z">223.10402606189822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.9064510541798</Real>
+        <Real Name="Y">-91.873016441468678</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733365</Real>
+        <Real Name="Y">82.504344401698347</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041526</Real>
+        <Real Name="Y">45.329959216167893</Real>
+        <Real Name="Z">-56.291380508471349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448434</Real>
+        <Real Name="Y">-204.77938512046111</Real>
+        <Real Name="Z">21.695070286562498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013951</Real>
+        <Real Name="Y">47.5995038096992</Real>
+        <Real Name="Z">-24.246658126595179</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564435093</Real>
+        <Real Name="Y">-23.593576368970304</Real>
+        <Real Name="Z">144.65217639452101</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620597983834559</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620597983834559</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620597983834559</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059504206368005391</Real>
+        <Real Name="Y">0.59963578518811256</Real>
+        <Real Name="Z">0.238999331394979</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8576185102017386</Real>
+        <Real Name="Y">0.68774995663977878</Real>
+        <Real Name="Z">0.27491901370450189</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062268877277387766</Real>
+        <Real Name="Y">0.61139291147537722</Real>
+        <Real Name="Z">0.16249887503629346</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97426727094800569</Real>
+        <Real Name="Y">0.6307205465271688</Real>
+        <Real Name="Z">1.5712102640390531</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94468418856585878</Real>
+        <Real Name="Y">0.59368184978217708</Real>
+        <Real Name="Z">1.6543685142623674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90880298506578905</Real>
+        <Real Name="Y">0.69723013095765163</Real>
+        <Real Name="Z">1.549921279732243</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3965043579071401</Real>
+        <Real Name="Y">0.44683740209716838</Real>
+        <Real Name="Z">1.1687441724880585</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.331121632529904</Real>
+        <Real Name="Y">0.47343062476158709</Real>
+        <Real Name="Z">1.2333987789021814</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.346279446160535</Real>
+        <Real Name="Y">0.43157620762062554</Real>
+        <Real Name="Z">1.0887012303682537</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6433609074795459</Real>
+        <Real Name="Y">0.31607835109806431</Real>
+        <Real Name="Z">0.30742619534828769</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.702842417944558</Real>
+        <Real Name="Y">0.33838978780642803</Real>
+        <Real Name="Z">0.23582683707735724</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.60906005071268</Real>
+        <Real Name="Y">0.22980521378348834</Real>
+        <Real Name="Z">0.28412994236719646</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7792418390317042</Real>
+        <Real Name="Y">0.39118899966893206</Real>
+        <Real Name="Z">0.024534110344687429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6976754916602286</Real>
+        <Real Name="Y">0.42097472149732068</Real>
+        <Real Name="Z">1.846319100824974</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8184121172199763</Real>
+        <Real Name="Y">0.47057301221726977</Real>
+        <Real Name="Z">0.060950950657628927</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11289965039295728</Real>
+        <Real Name="Y">-0.01985725627796045</Real>
+        <Real Name="Z">-0.7090428194507632</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4542454245139569</Real>
+        <Real Name="Y">-0.56071517260098558</Real>
+        <Real Name="Z">1.0794280013667348</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0417715511541754</Real>
+        <Real Name="Y">0.43964096902677618</Real>
+        <Real Name="Z">0.74212089484570454</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.096692499029323226</Real>
+        <Real Name="Y">-0.036752082246785202</Real>
+        <Real Name="Z">0.27522061842982909</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.6353159782776383</Real>
+        <Real Name="Y">-2.6533087160544935</Real>
+        <Real Name="Z">-1.028674982308744</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.85226490148963086</Real>
+        <Real Name="Y">-0.49061205810321523</Real>
+        <Real Name="Z">1.1447090259930364</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.058462865642695337</Real>
+        <Real Name="Y">-0.021638331446244313</Real>
+        <Real Name="Z">-0.65751951989425572</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22553564597663237</Real>
+        <Real Name="Y">-0.40557540675453319</Real>
+        <Real Name="Z">-0.2090859093393867</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.45962957124809051</Real>
+        <Real Name="Y">0.10625598004487767</Real>
+        <Real Name="Z">-0.43160854982993097</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21810848048015477</Real>
+        <Real Name="Y">0.37035829585887364</Real>
+        <Real Name="Z">0.64806379737852116</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.013110423695416318</Real>
+        <Real Name="Y">1.4087126058391801</Real>
+        <Real Name="Z">1.1324723674543504</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8893196948972926</Real>
+        <Real Name="Y">-0.49257880877916577</Real>
+        <Real Name="Z">0.62954454752557643</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11268566177796434</Real>
+        <Real Name="Y">-0.095803011712060709</Real>
+        <Real Name="Z">-0.068511673148894059</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1881830330383436</Real>
+        <Real Name="Y">0.51014100862367684</Real>
+        <Real Name="Z">2.8806540943088286</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11835261456650176</Real>
+        <Real Name="Y">-0.97783742727853662</Real>
+        <Real Name="Z">2.1837802651534526</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-65.827150848341404</Real>
+        <Real Name="Y">-107.7969348485928</Real>
+        <Real Name="Z">-417.7794577185764</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11093555773043562</Real>
+        <Real Name="Y">34.977208092050233</Real>
+        <Real Name="Z">108.9362351491655</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">176.37591986441123</Real>
+        <Real Name="Y">148.13014630668286</Real>
+        <Real Name="Z">169.19192577553409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.759968750782036</Real>
+        <Real Name="Y">-14.338051320468807</Real>
+        <Real Name="Z">-37.669842539096479</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.743346858243555</Real>
+        <Real Name="Y">-8.0400006766998171</Real>
+        <Real Name="Z">-23.763141838676809</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3190023144664451</Real>
+        <Real Name="Y">7.6844590533572941</Real>
+        <Real Name="Z">12.795116945951435</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.251278505994122</Real>
+        <Real Name="Y">-14.264220815505816</Real>
+        <Real Name="Z">-32.995321340828966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.500059101179275</Real>
+        <Real Name="Y">12.045347804420089</Real>
+        <Real Name="Z">27.178835177706127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.935532699374001</Real>
+        <Real Name="Y">16.912465954897062</Real>
+        <Real Name="Z">54.454353594944685</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-258.02458947599337</Real>
+        <Real Name="Y">-52.42670418558896</Real>
+        <Real Name="Z">177.83231774274446</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">212.23008134946372</Real>
+        <Real Name="Y">26.334626375807147</Real>
+        <Real Name="Z">-198.76614132112348</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.866200096914156</Real>
+        <Real Name="Y">33.266827427890661</Real>
+        <Real Name="Z">-54.0040453785886</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-61.046180309383317</Real>
+        <Real Name="Y">-234.54500722520308</Real>
+        <Real Name="Z">8.5672378935284428</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.061370049357379</Real>
+        <Real Name="Y">75.19456987333291</Real>
+        <Real Name="Z">-10.679967089530891</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.62384618544408</Real>
+        <Real Name="Y">76.865268183621083</Real>
+        <Real Name="Z">216.70189494684701</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620613184957659</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620613184957659</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620613184957659</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0012686227622512962</Real>
+        <Real Name="Y">0.58897306200455535</Real>
+        <Real Name="Z">0.24148839456723697</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8542311513356289</Real>
+        <Real Name="Y">0.67534959144163131</Real>
+        <Real Name="Z">0.28172054072368685</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.07677669377877494</Real>
+        <Real Name="Y">0.59744774515051591</Real>
+        <Real Name="Z">0.18327302411458976</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98215264276959613</Real>
+        <Real Name="Y">0.62907721501595437</Real>
+        <Real Name="Z">1.5717173877652071</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97446221755864482</Real>
+        <Real Name="Y">0.63160544526044982</Real>
+        <Real Name="Z">1.6670944490111124</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94111767932770596</Real>
+        <Real Name="Y">0.71035061536665101</Real>
+        <Real Name="Z">1.5421693832512346</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3890143315603349</Real>
+        <Real Name="Y">0.44761180754883201</Real>
+        <Real Name="Z">1.1805895090748932</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3383283611035703</Real>
+        <Real Name="Y">0.47843309667561146</Real>
+        <Real Name="Z">1.2557114029236187</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3259031554487271</Real>
+        <Real Name="Y">0.39929694627451157</Real>
+        <Real Name="Z">1.1272512298576884</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6490837529772204</Real>
+        <Real Name="Y">0.31826473854495191</Real>
+        <Real Name="Z">0.29580505874876223</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7084497665552403</Real>
+        <Real Name="Y">0.34158458987166057</Real>
+        <Real Name="Z">0.22443153868736854</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6025308509971494</Real>
+        <Real Name="Y">0.24091288028751812</Real>
+        <Real Name="Z">0.26399569312548449</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7748725870483779</Real>
+        <Real Name="Y">0.39946211010242921</Real>
+        <Real Name="Z">0.020504911032624945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.716089485790111</Real>
+        <Real Name="Y">0.40750659099214703</Real>
+        <Real Name="Z">1.8074519716696122</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7875139110397864</Real>
+        <Real Name="Y">0.48936949448070027</Real>
+        <Real Name="Z">0.050822852288617514</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21525836962550648</Real>
+        <Real Name="Y">-0.60076025108781428</Real>
+        <Real Name="Z">-0.3425401520428043</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.35537973595144101</Real>
+        <Real Name="Y">-1.4274991637513965</Real>
+        <Real Name="Z">1.621988483387846</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.413005972858782</Real>
+        <Real Name="Y">-0.82761290744239924</Real>
+        <Real Name="Z">2.8842203303238199</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43656208051628204</Real>
+        <Real Name="Y">-0.10414598211461593</Real>
+        <Real Name="Z">0.16900018777638304</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6309728038557316</Real>
+        <Real Name="Y">0.83953265792035348</Real>
+        <Real Name="Z">0.25247672498717155</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6557698811356507</Real>
+        <Real Name="Y">0.46440810353922057</Real>
+        <Real Name="Z">0.0085985352846254942</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.5496816490491091</Real>
+        <Real Name="Y">0.02522733442107683</Real>
+        <Real Name="Z">0.3882698658567959</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.61907386070299053</Real>
+        <Real Name="Y">0.21569099668335084</Real>
+        <Real Name="Z">1.1115190609361481</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.97970585110670672</Real>
+        <Real Name="Y">-1.7931866112840389</Real>
+        <Real Name="Z">2.4708529760186093</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24092038677884633</Real>
+        <Real Name="Y">0.3189310817822229</Real>
+        <Real Name="Z">-0.41587338916772965</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39481378218553786</Real>
+        <Real Name="Y">1.301336244593033</Real>
+        <Real Name="Z">0.024823264197237793</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.81696690257161397</Real>
+        <Real Name="Y">0.32543385246266771</Real>
+        <Real Name="Z">-1.2920110412531973</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20585887656427712</Real>
+        <Real Name="Y">0.39755586920157127</Real>
+        <Real Name="Z">-0.26255614710374475</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.524062393621886</Real>
+        <Real Name="Y">-0.0086902306747093615</Real>
+        <Real Name="Z">-0.88450726971714178</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7746977583210972</Real>
+        <Real Name="Y">0.32635417064473415</Real>
+        <Real Name="Z">1.1620745857524399</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-77.303718326309053</Real>
+        <Real Name="Y">70.071819507286847</Real>
+        <Real Name="Z">-361.98407019995517</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.6388665259318316</Real>
+        <Real Name="Y">-0.58040768998615988</Real>
+        <Real Name="Z">111.83948576741143</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">134.05730982982487</Real>
+        <Real Name="Y">-1.1151585897971188</Real>
+        <Real Name="Z">131.56337126922074</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">24.078872890063423</Real>
+        <Real Name="Y">-24.068245223030907</Real>
+        <Real Name="Z">-37.533258381345547</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.793972287757498</Real>
+        <Real Name="Y">7.2293475469488975</Real>
+        <Real Name="Z">14.347277830730519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.417215954148304</Real>
+        <Real Name="Y">13.015907920295312</Real>
+        <Real Name="Z">11.766021048494956</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.834884793115862</Real>
+        <Real Name="Y">-3.6748459475872153</Real>
+        <Real Name="Z">-32.198969740267586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.441809989204415</Real>
+        <Real Name="Y">8.8925395438859454</Real>
+        <Real Name="Z">-18.376193785982494</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.278377586823652</Real>
+        <Real Name="Y">4.241251328261292</Real>
+        <Real Name="Z">18.152767053248752</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-316.62809796798956</Real>
+        <Real Name="Y">-133.36087232585311</Real>
+        <Real Name="Z">278.68925598182398</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">244.68622653480406</Real>
+        <Real Name="Y">102.67230258524404</Real>
+        <Real Name="Z">-285.45671911682803</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">119.0475463570987</Real>
+        <Real Name="Y">61.255387971332382</Real>
+        <Real Name="Z">-65.30423393797345</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-75.273804452980642</Real>
+        <Real Name="Y">-324.04865620656813</Real>
+        <Real Name="Z">-36.562618761542353</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.981537264078103</Real>
+        <Real Name="Y">57.862226062225325</Real>
+        <Real Name="Z">26.224619594944329</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.18824762970371</Real>
+        <Real Name="Y">161.60740351734262</Real>
+        <Real Name="Z">244.83326537802009</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_ParrinelloRahman_4Ranks_2RanksPerSimulation_s.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceLeapFrog_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_md_Vrescale_ParrinelloRahman_4Ranks_2RanksPerSimulation_s.xml
new file mode 100644 (file)
index 0000000..1357c34
--- /dev/null
@@ -0,0 +1,1696 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562597</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562569</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562569</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562569</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562597</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562597</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562597</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562597</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562597</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562597</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562597</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562731</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562421</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562421</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562421</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562421</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">20.34477</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">21.220358</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">20.339005</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">20.339796</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">20.340513</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">17.80582</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">17.805809</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">17.805733</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">17.805563</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">17.805214</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">17.853046</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">18.208187</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">17.845507</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">20.304443</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">20.2994</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">20.294434</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">20.290405</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.629341</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.225605</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">28.961779</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.732141</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">30.658285</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">30.497021</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">31.027422</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">31.705044</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">32.527012</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">33.488583</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">34.528297</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">35.267944</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">36.109886</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">43.024017</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">44.634186</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">46.082924</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">47.314865</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733761</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.158266</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.775792</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.545364</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.470791</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-10.257218</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.78763</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.465328</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-12.287466</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-13.249386</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-14.241268</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-15.348822</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-16.553444</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-26.353642</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-27.968853</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-29.422558</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.658527</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951088</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154483</Real>
+        <Real Name="Y">0.6098752</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829585</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13824016</Real>
+        <Real Name="Y">-0.083002254</Real>
+        <Real Name="Z">-0.55156869</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6807338</Real>
+        <Real Name="Y">0.12595503</Real>
+        <Real Name="Z">0.08634457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50557774</Real>
+        <Real Name="Y">-0.26347136</Real>
+        <Real Name="Z">-0.37042338</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.080341488</Real>
+        <Real Name="Y">-0.036381338</Real>
+        <Real Name="Z">0.26949763</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0880266</Real>
+        <Real Name="Y">-2.6992292</Real>
+        <Real Name="Z">-0.41159728</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0053114</Real>
+        <Real Name="Y">-0.44618708</Real>
+        <Real Name="Z">1.1535001</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.046993256</Real>
+        <Real Name="Y">-0.027141552</Real>
+        <Real Name="Z">-0.68357778</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.05199106</Real>
+        <Real Name="Y">-0.4239299</Real>
+        <Real Name="Z">-0.38236642</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25138497</Real>
+        <Real Name="Y">0.072344288</Real>
+        <Real Name="Z">-0.58373684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20046791</Real>
+        <Real Name="Y">0.39459822</Real>
+        <Real Name="Z">0.71750742</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21663751</Real>
+        <Real Name="Y">1.2108051</Real>
+        <Real Name="Z">0.86115432</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3770657</Real>
+        <Real Name="Y">-0.66109234</Real>
+        <Real Name="Z">0.87071204</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2170116</Real>
+        <Real Name="Y">-0.090551436</Real>
+        <Real Name="Z">-0.034702588</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8639975</Real>
+        <Real Name="Y">0.96362239</Real>
+        <Real Name="Z">2.5346055</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.37430629</Real>
+        <Real Name="Y">-0.3790665</Real>
+        <Real Name="Z">0.73122531</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9518738</Real>
+        <Real Name="Y">10.126022</Real>
+        <Real Name="Z">-383.92468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054081</Real>
+        <Real Name="Y">8.7835617</Real>
+        <Real Name="Z">109.98161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.0733</Real>
+        <Real Name="Y">125.90257</Real>
+        <Real Name="Z">223.10434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850433</Real>
+        <Real Name="Y">8.0224648</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90619</Real>
+        <Real Name="Y">-91.872864</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62735</Real>
+        <Real Name="Y">82.504333</Real>
+        <Real Name="Z">-270.19894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937</Real>
+        <Real Name="Y">45.329948</Real>
+        <Real Name="Z">-56.291359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365723</Real>
+        <Real Name="Y">-204.77948</Real>
+        <Real Name="Z">21.695251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097099</Real>
+        <Real Name="Y">47.599464</Real>
+        <Real Name="Z">-24.246674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.29879</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65219</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0031331014</Real>
+        <Real Name="Y">0.5942111</Real>
+        <Real Name="Z">0.24346453</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8502643</Real>
+        <Real Name="Y">0.68428963</Real>
+        <Real Name="Z">0.27219266</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.059117816</Real>
+        <Real Name="Y">0.60260421</Real>
+        <Real Name="Z">0.16627912</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97860736</Real>
+        <Real Name="Y">0.62998199</Real>
+        <Real Name="Z">1.5703981</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96187741</Real>
+        <Real Name="Y">0.62416267</Real>
+        <Real Name="Z">1.6644648</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92816675</Real>
+        <Real Name="Y">0.70610958</Real>
+        <Real Name="Z">1.5417162</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3932226</Real>
+        <Real Name="Y">0.44735184</Real>
+        <Real Name="Z">1.1774073</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.333541</Real>
+        <Real Name="Y">0.47715062</Real>
+        <Real Name="Z">1.2460545</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3357704</Real>
+        <Real Name="Y">0.41442284</Real>
+        <Real Name="Z">1.1082896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6471055</Real>
+        <Real Name="Y">0.31568071</Real>
+        <Real Name="Z">0.29903683</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7056489</Real>
+        <Real Name="Y">0.33268511</Real>
+        <Real Name="Z">0.22524095</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5975001</Real>
+        <Real Name="Y">0.23809037</Real>
+        <Real Name="Z">0.27293378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7765112</Real>
+        <Real Name="Y">0.39606798</Real>
+        <Real Name="Z">0.022713354</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7122529</Real>
+        <Real Name="Y">0.40968916</Real>
+        <Real Name="Z">1.8151482</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.806461</Real>
+        <Real Name="Y">0.48413301</Real>
+        <Real Name="Z">0.045293901</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.24151085</Real>
+        <Real Name="Y">-0.71036071</Real>
+        <Real Name="Z">-0.13632002</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.61076218</Real>
+        <Real Name="Y">-0.81423211</Real>
+        <Real Name="Z">0.65597749</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6700563</Real>
+        <Real Name="Y">-0.63797885</Real>
+        <Real Name="Z">1.2223989</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.4520714</Real>
+        <Real Name="Y">-0.12315645</Real>
+        <Real Name="Z">0.16470326</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4642667</Real>
+        <Real Name="Y">1.0555332</Real>
+        <Real Name="Z">0.43085968</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5697633</Real>
+        <Real Name="Y">0.60449553</Real>
+        <Real Name="Z">0.099532813</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.49408388</Real>
+        <Real Name="Y">0.039497416</Real>
+        <Real Name="Z">0.41181213</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.53571719</Real>
+        <Real Name="Y">0.09213382</Real>
+        <Real Name="Z">1.2978187</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.5286328</Real>
+        <Real Name="Y">-2.0089331</Real>
+        <Real Name="Z">2.1866734</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25592753</Real>
+        <Real Name="Y">0.32835141</Real>
+        <Real Name="Z">-0.39017183</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.29008794</Real>
+        <Real Name="Y">0.8461569</Real>
+        <Real Name="Z">-0.24579097</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39087009</Real>
+        <Real Name="Y">0.4063057</Real>
+        <Real Name="Z">-0.88327569</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19986291</Real>
+        <Real Name="Y">0.46891496</Real>
+        <Real Name="Z">-0.28618962</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.41860765</Real>
+        <Real Name="Y">-0.54155475</Real>
+        <Real Name="Z">-1.0692044</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.811255</Real>
+        <Real Name="Y">0.94653732</Real>
+        <Real Name="Z">0.053504623</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-5.4417267</Real>
+        <Real Name="Y">61.325073</Real>
+        <Real Name="Z">-373.21631</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.9332123</Real>
+        <Real Name="Y">1.2054291</Real>
+        <Real Name="Z">111.88754</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.39807</Real>
+        <Real Name="Y">63.024155</Real>
+        <Real Name="Z">206.13776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.699593</Real>
+        <Real Name="Y">-19.018429</Real>
+        <Real Name="Z">-38.873482</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.662163</Real>
+        <Real Name="Y">-9.5447369</Real>
+        <Real Name="Z">-24.616829</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4642258</Real>
+        <Real Name="Y">10.589035</Real>
+        <Real Name="Z">12.953773</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.600258</Real>
+        <Real Name="Y">-7.1698532</Real>
+        <Real Name="Z">-33.293823</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-57.049809</Real>
+        <Real Name="Y">11.226688</Real>
+        <Real Name="Z">-15.138824</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.67728</Real>
+        <Real Name="Y">18.945898</Real>
+        <Real Name="Z">56.548763</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-309.1846</Real>
+        <Real Name="Y">-123.34634</Real>
+        <Real Name="Z">255.69296</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.86797</Real>
+        <Real Name="Y">107.46335</Real>
+        <Real Name="Z">-280.59161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">114.02769</Real>
+        <Real Name="Y">55.441063</Real>
+        <Real Name="Z">-58.08041</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-58.364944</Real>
+        <Real Name="Y">-240.29939</Real>
+        <Real Name="Z">-1.8074951</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">8.1404495</Real>
+        <Real Name="Y">45.318127</Real>
+        <Real Name="Z">17.040848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.28039</Real>
+        <Real Name="Y">24.839935</Real>
+        <Real Name="Z">165.35713</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620583</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620583</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620583</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.006998152</Real>
+        <Real Name="Y">0.59991992</Real>
+        <Real Name="Z">0.23233022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0042025964</Real>
+        <Real Name="Y">0.67763501</Real>
+        <Real Name="Z">0.28814122</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.081902072</Real>
+        <Real Name="Y">0.61454594</Real>
+        <Real Name="Z">0.17455652</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97342837</Real>
+        <Real Name="Y">0.63036966</Real>
+        <Real Name="Z">1.5734334</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94147015</Real>
+        <Real Name="Y">0.57335305</Real>
+        <Real Name="Z">1.6433626</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9025355</Real>
+        <Real Name="Y">0.69312513</Real>
+        <Real Name="Z">1.5593526</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959739</Real>
+        <Real Name="Y">0.44667494</Real>
+        <Real Name="Z">1.1635704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3337818</Real>
+        <Real Name="Y">0.47037858</Real>
+        <Real Name="Z">1.2323643</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3417217</Real>
+        <Real Name="Y">0.43264022</Real>
+        <Real Name="Z">1.0859686</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6415313</Real>
+        <Real Name="Y">0.31891018</Real>
+        <Real Name="Z">0.31226146</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7042176</Real>
+        <Real Name="Y">0.34963992</Real>
+        <Real Name="Z">0.2467753</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6259186</Real>
+        <Real Name="Y">0.22728157</Real>
+        <Real Name="Z">0.28939751</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7797525</Real>
+        <Real Name="Y">0.39097974</Real>
+        <Real Name="Z">0.024229787</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6907469</Real>
+        <Real Name="Y">0.4213441</Real>
+        <Real Name="Z">0.006387949</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8161711</Real>
+        <Real Name="Y">0.45683616</Real>
+        <Real Name="Z">0.083381586</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.16117992</Real>
+        <Real Name="Y">0.082122326</Real>
+        <Real Name="Z">-0.9295969</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67529637</Real>
+        <Real Name="Y">-1.928859</Real>
+        <Real Name="Z">2.0125172</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5395961</Real>
+        <Real Name="Y">0.21540359</Real>
+        <Real Name="Z">2.0612452</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11055423</Real>
+        <Real Name="Y">-0.05109122</Real>
+        <Real Name="Z">0.27992859</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22754982</Real>
+        <Real Name="Y">-2.4280317</Real>
+        <Real Name="Z">-1.6445856</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.73583806</Real>
+        <Real Name="Y">-0.53498524</Real>
+        <Real Name="Z">1.2181886</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.072737053</Real>
+        <Real Name="Y">-0.019690612</Real>
+        <Real Name="Z">-0.63925445</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42003042</Real>
+        <Real Name="Y">-0.35885853</Real>
+        <Real Name="Z">-0.071992673</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.65397048</Real>
+        <Real Name="Y">0.15671381</Real>
+        <Real Name="Z">-0.26816601</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.23493798</Real>
+        <Real Name="Y">0.3394798</Real>
+        <Real Name="Z">0.57051438</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.3169384</Real>
+        <Real Name="Y">1.3935637</Real>
+        <Real Name="Z">1.5748779</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2346153</Real>
+        <Real Name="Y">-0.15579382</Real>
+        <Real Name="Z">0.72971302</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.031715669</Real>
+        <Real Name="Y">0.046109561</Real>
+        <Real Name="Z">0.013976831</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.64034623</Real>
+        <Real Name="Y">-0.32400858</Real>
+        <Real Name="Z">2.5414124</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.35229075</Real>
+        <Real Name="Y">-2.3353012</Real>
+        <Real Name="Z">3.0278037</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-163.55673</Real>
+        <Real Name="Y">-310.99408</Real>
+        <Real Name="Z">-381.76221</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">13.921825</Real>
+        <Real Name="Y">66.796631</Real>
+        <Real Name="Z">100.71881</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">168.55972</Real>
+        <Real Name="Y">140.40384</Real>
+        <Real Name="Z">74.775772</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.25708</Real>
+        <Real Name="Y">-15.068954</Real>
+        <Real Name="Z">-36.64402</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.843956</Real>
+        <Real Name="Y">-7.1662674</Real>
+        <Real Name="Z">-24.509178</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.199707</Real>
+        <Real Name="Y">7.4263687</Real>
+        <Real Name="Z">12.163445</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.559921</Real>
+        <Real Name="Y">-17.423859</Real>
+        <Real Name="Z">-31.414185</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.687542</Real>
+        <Real Name="Y">14.793777</Real>
+        <Real Name="Z">25.331844</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.773712</Real>
+        <Real Name="Y">17.438938</Real>
+        <Real Name="Z">55.072098</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-183.69344</Real>
+        <Real Name="Y">2.1072388</Real>
+        <Real Name="Z">106.43352</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">149.22313</Real>
+        <Real Name="Y">-32.151871</Real>
+        <Real Name="Z">-89.36235</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.693382</Real>
+        <Real Name="Y">10.659317</Real>
+        <Real Name="Z">-50.047405</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-54.115364</Real>
+        <Real Name="Y">-310.32449</Real>
+        <Real Name="Z">-19.593872</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-18.926228</Real>
+        <Real Name="Y">115.06573</Real>
+        <Real Name="Z">0.21431732</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.893696</Real>
+        <Real Name="Y">318.43768</Real>
+        <Real Name="Z">258.62341</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Repl  Using Constant Pressure REMD.
+Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble
+Replica exchange in temperature
+Repl  p  1.00  1.02
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Volume">
+      <Real Name="Time 0.000000 Step 0 in frame 0">6.4562597</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">6.4562597</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">6.4562597</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">6.4562597</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">6.4562597</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">6.4562569</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">6.4562569</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">6.4562569</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">6.4562569</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">6.4562569</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">6.4562569</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">6.4562569</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">6.4562421</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">6.4562731</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">6.4562731</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">6.4562731</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">6.4562731</Real>
+    </Energy>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">17.819868</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">16.406164</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">17.813211</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">17.813364</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">17.813555</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">20.348709</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">20.348778</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">20.348274</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">20.347202</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">20.345173</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">20.342215</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">21.06263</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">20.317444</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">17.852165</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">17.850599</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">17.848927</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">17.847347</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">27.096624</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">28.401459</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.799488</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.882864</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">30.115343</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">31.741884</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">32.98119</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">34.369881</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.895554</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">37.538349</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">39.269855</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">40.295471</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">41.311607</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">37.406029</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">38.7761</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">40.198547</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">41.649208</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733761</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5691261</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.5601072</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.6433325</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.8756189</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.554008</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.793245</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-16.18244</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.709185</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-19.35401</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-21.088474</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-22.874723</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.636045</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.850742</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-19.22238</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-20.6465</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-22.09874</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951088</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154483</Real>
+        <Real Name="Y">0.6098752</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829585</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.2081964</Real>
+        <Real Name="Y">-0.7183184</Real>
+        <Real Name="Z">0.011077392</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.65627712</Real>
+        <Real Name="Y">-0.44132945</Real>
+        <Real Name="Z">-0.19586644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.079432383</Real>
+        <Real Name="Y">-1.3403528</Real>
+        <Real Name="Z">0.0942358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43983412</Real>
+        <Real Name="Y">-0.12730011</Real>
+        <Real Name="Z">0.16848481</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1064552</Real>
+        <Real Name="Y">1.2083107</Real>
+        <Real Name="Z">0.58867824</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3857259</Real>
+        <Real Name="Y">0.65410167</Real>
+        <Real Name="Z">0.10518272</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.41357264</Real>
+        <Real Name="Y">0.039098304</Real>
+        <Real Name="Z">0.41653091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.30952451</Real>
+        <Real Name="Y">0.032534141</Real>
+        <Real Name="Z">1.21565</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7555673</Real>
+        <Real Name="Y">-2.029453</Real>
+        <Real Name="Z">1.5685941</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25622329</Real>
+        <Real Name="Y">0.31483555</Real>
+        <Real Name="Z">-0.34178945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.14576393</Real>
+        <Real Name="Y">0.34296301</Real>
+        <Real Name="Z">-0.42390847</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.0196642</Real>
+        <Real Name="Y">0.51929116</Real>
+        <Real Name="Z">-0.45123479</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1525732</Real>
+        <Real Name="Y">0.53524446</Real>
+        <Real Name="Z">-0.26926085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25469711</Real>
+        <Real Name="Y">-0.76836795</Real>
+        <Real Name="Z">-1.2156236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.92007476</Real>
+        <Real Name="Y">1.1309038</Real>
+        <Real Name="Z">-1.048301</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9518738</Real>
+        <Real Name="Y">10.126022</Real>
+        <Real Name="Z">-383.92468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054081</Real>
+        <Real Name="Y">8.7835617</Real>
+        <Real Name="Z">109.98161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.0733</Real>
+        <Real Name="Y">125.90257</Real>
+        <Real Name="Z">223.10434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850433</Real>
+        <Real Name="Y">8.0224648</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90619</Real>
+        <Real Name="Y">-91.872864</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62735</Real>
+        <Real Name="Y">82.504333</Real>
+        <Real Name="Z">-270.19894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937</Real>
+        <Real Name="Y">45.329948</Real>
+        <Real Name="Z">-56.291359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365723</Real>
+        <Real Name="Y">-204.77948</Real>
+        <Real Name="Z">21.695251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097099</Real>
+        <Real Name="Y">47.599464</Real>
+        <Real Name="Z">-24.246674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.29879</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65219</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.8620597</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.8620597</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.8620597</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059504164</Real>
+        <Real Name="Y">0.5996359</Real>
+        <Real Name="Z">0.23899932</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8576185</Real>
+        <Real Name="Y">0.68775004</Real>
+        <Real Name="Z">0.274919</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.062268876</Real>
+        <Real Name="Y">0.61139292</Real>
+        <Real Name="Z">0.16249886</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97426736</Real>
+        <Real Name="Y">0.6307205</Real>
+        <Real Name="Z">1.5712103</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94468415</Real>
+        <Real Name="Y">0.59368181</Real>
+        <Real Name="Z">1.6543684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90880311</Real>
+        <Real Name="Y">0.69723016</Real>
+        <Real Name="Z">1.5499213</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3965044</Real>
+        <Real Name="Y">0.44683748</Real>
+        <Real Name="Z">1.1687438</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3311217</Real>
+        <Real Name="Y">0.47343051</Real>
+        <Real Name="Z">1.2333987</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3462793</Real>
+        <Real Name="Y">0.4315761</Real>
+        <Real Name="Z">1.0887011</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.643361</Real>
+        <Real Name="Y">0.31607834</Real>
+        <Real Name="Z">0.30742615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7028425</Real>
+        <Real Name="Y">0.33838981</Real>
+        <Real Name="Z">0.23582679</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.60906</Real>
+        <Real Name="Y">0.2298052</Real>
+        <Real Name="Z">0.28412992</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7792419</Real>
+        <Real Name="Y">0.39118895</Real>
+        <Real Name="Z">0.024534093</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6976755</Real>
+        <Real Name="Y">0.42097449</Real>
+        <Real Name="Z">1.8463192</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8184121</Real>
+        <Real Name="Y">0.47057301</Real>
+        <Real Name="Z">0.060950965</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11290002</Real>
+        <Real Name="Y">-0.019850655</Real>
+        <Real Name="Z">-0.70904332</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4542381</Real>
+        <Real Name="Y">-0.56074893</Real>
+        <Real Name="Z">1.079447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0417728</Real>
+        <Real Name="Y">0.43959785</Real>
+        <Real Name="Z">0.74211377</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.096689053</Real>
+        <Real Name="Y">-0.036750823</Real>
+        <Real Name="Z">0.275213</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63536316</Real>
+        <Real Name="Y">-2.6533098</Real>
+        <Real Name="Z">-1.0285902</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.85227478</Real>
+        <Real Name="Y">-0.49061319</Real>
+        <Real Name="Z">1.1447505</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.058464732</Real>
+        <Real Name="Y">-0.021635663</Real>
+        <Real Name="Z">-0.65751183</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.22554545</Real>
+        <Real Name="Y">-0.40557614</Real>
+        <Real Name="Z">-0.20906213</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.45968682</Real>
+        <Real Name="Y">0.10622556</Real>
+        <Real Name="Z">-0.43174919</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2181114</Real>
+        <Real Name="Y">0.37035489</Real>
+        <Real Name="Z">0.64805996</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.013067413</Real>
+        <Real Name="Y">1.4087541</Real>
+        <Real Name="Z">1.1324474</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.889323</Real>
+        <Real Name="Y">-0.49259514</Real>
+        <Real Name="Z">0.62956953</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11268624</Real>
+        <Real Name="Y">-0.095800281</Real>
+        <Real Name="Z">-0.068511471</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1882132</Real>
+        <Real Name="Y">0.51012594</Real>
+        <Real Name="Z">2.8806419</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11835399</Real>
+        <Real Name="Y">-0.97785932</Real>
+        <Real Name="Z">2.1837888</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-65.827637</Real>
+        <Real Name="Y">-107.79741</Real>
+        <Real Name="Z">-417.7793</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11100769</Real>
+        <Real Name="Y">34.977165</Real>
+        <Real Name="Z">108.9361</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">176.37607</Real>
+        <Real Name="Y">148.13014</Real>
+        <Real Name="Z">169.1918</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.760002</Real>
+        <Real Name="Y">-14.338173</Real>
+        <Real Name="Z">-37.669838</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.743313</Real>
+        <Real Name="Y">-8.0399609</Real>
+        <Real Name="Z">-23.763134</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3190308</Real>
+        <Real Name="Y">7.6845245</Real>
+        <Real Name="Z">12.795128</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.251244</Real>
+        <Real Name="Y">-14.264183</Real>
+        <Real Name="Z">-32.995361</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.500019</Real>
+        <Real Name="Y">12.045326</Real>
+        <Real Name="Z">27.178833</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.935509</Real>
+        <Real Name="Y">16.91247</Real>
+        <Real Name="Z">54.454372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-258.02451</Real>
+        <Real Name="Y">-52.426453</Real>
+        <Real Name="Z">177.83163</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">212.2301</Real>
+        <Real Name="Y">26.334076</Real>
+        <Real Name="Z">-198.76508</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.866127</Real>
+        <Real Name="Y">33.266602</Real>
+        <Real Name="Z">-54.003738</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-61.045685</Real>
+        <Real Name="Y">-234.54402</Real>
+        <Real Name="Z">8.567688</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.061478</Real>
+        <Real Name="Y">75.194733</Real>
+        <Real Name="Z">-10.680298</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-74.623993</Real>
+        <Real Name="Y">76.865204</Real>
+        <Real Name="Z">216.70117</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.8620613</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.8620613</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.8620613</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0012686428</Real>
+        <Real Name="Y">0.58897305</Real>
+        <Real Name="Z">0.24148838</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8542311</Real>
+        <Real Name="Y">0.67534947</Real>
+        <Real Name="Z">0.2817207</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.076776601</Real>
+        <Real Name="Y">0.59744781</Real>
+        <Real Name="Z">0.18327287</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98215264</Real>
+        <Real Name="Y">0.62907732</Real>
+        <Real Name="Z">1.5717174</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97446215</Real>
+        <Real Name="Y">0.63160557</Real>
+        <Real Name="Z">1.6670945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94111758</Real>
+        <Real Name="Y">0.71035063</Real>
+        <Real Name="Z">1.5421693</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3890139</Real>
+        <Real Name="Y">0.44761172</Real>
+        <Real Name="Z">1.1805898</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3383276</Real>
+        <Real Name="Y">0.4784334</Real>
+        <Real Name="Z">1.2557113</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3259027</Real>
+        <Real Name="Y">0.39929703</Real>
+        <Real Name="Z">1.1272513</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6490839</Real>
+        <Real Name="Y">0.31826469</Real>
+        <Real Name="Z">0.29580495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7084497</Real>
+        <Real Name="Y">0.34158462</Real>
+        <Real Name="Z">0.22443137</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6025307</Real>
+        <Real Name="Y">0.240913</Real>
+        <Real Name="Z">0.26399553</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7748725</Real>
+        <Real Name="Y">0.39946201</Real>
+        <Real Name="Z">0.020504914</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7160898</Real>
+        <Real Name="Y">0.40750635</Real>
+        <Real Name="Z">1.8074516</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7875137</Real>
+        <Real Name="Y">0.48936945</Real>
+        <Real Name="Z">0.050822757</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21525739</Real>
+        <Real Name="Y">-0.60075849</Real>
+        <Real Name="Z">-0.34253943</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.35536668</Real>
+        <Real Name="Y">-1.4275188</Real>
+        <Real Name="Z">1.6219848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4130096</Real>
+        <Real Name="Y">-0.82760006</Real>
+        <Real Name="Z">2.8842061</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43656242</Real>
+        <Real Name="Y">-0.10414445</Real>
+        <Real Name="Z">0.16899864</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6309698</Real>
+        <Real Name="Y">0.83952558</Real>
+        <Real Name="Z">0.25253725</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.655745</Real>
+        <Real Name="Y">0.46441641</Real>
+        <Real Name="Z">0.0085918102</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.54968494</Real>
+        <Real Name="Y">0.025226889</Real>
+        <Real Name="Z">0.38827091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.61907136</Real>
+        <Real Name="Y">0.21569782</Real>
+        <Real Name="Z">1.1115128</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.97972673</Real>
+        <Real Name="Y">-1.7931856</Real>
+        <Real Name="Z">2.4708238</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24091893</Real>
+        <Real Name="Y">0.31892711</Real>
+        <Real Name="Z">-0.41587359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39488757</Real>
+        <Real Name="Y">1.3013992</Real>
+        <Real Name="Z">0.024758944</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.81693673</Real>
+        <Real Name="Y">0.32542533</Real>
+        <Real Name="Z">-1.2920015</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20586061</Real>
+        <Real Name="Y">0.39755613</Real>
+        <Real Name="Z">-0.26255599</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.52408892</Real>
+        <Real Name="Y">-0.0086942092</Real>
+        <Real Name="Z">-0.88451606</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7747066</Real>
+        <Real Name="Y">0.32636377</Real>
+        <Real Name="Z">1.1620696</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-77.303604</Real>
+        <Real Name="Y">70.072647</Real>
+        <Real Name="Z">-361.98389</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">4.6388168</Real>
+        <Real Name="Y">-0.58081818</Real>
+        <Real Name="Z">111.83943</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">134.05725</Real>
+        <Real Name="Y">-1.1152573</Real>
+        <Real Name="Z">131.56345</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">24.078865</Real>
+        <Real Name="Y">-24.068169</Real>
+        <Real Name="Z">-37.533562</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.7939529</Real>
+        <Real Name="Y">7.2293091</Real>
+        <Real Name="Z">14.347374</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.4172287</Real>
+        <Real Name="Y">13.015892</Real>
+        <Real Name="Z">11.76614</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.834946</Real>
+        <Real Name="Y">-3.6749191</Real>
+        <Real Name="Z">-32.199081</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.441895</Real>
+        <Real Name="Y">8.8925934</Real>
+        <Real Name="Z">-18.375938</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.278374</Real>
+        <Real Name="Y">4.2412758</Real>
+        <Real Name="Z">18.152817</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-316.6286</Real>
+        <Real Name="Y">-133.36163</Real>
+        <Real Name="Z">278.6907</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">244.68665</Real>
+        <Real Name="Y">102.67249</Real>
+        <Real Name="Z">-285.45776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">119.04779</Real>
+        <Real Name="Y">61.255577</Real>
+        <Real Name="Z">-65.304413</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-75.274597</Real>
+        <Real Name="Y">-324.04807</Real>
+        <Real Name="Z">-36.56189</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.981796</Real>
+        <Real Name="Y">57.861839</Real>
+        <Real Name="Z">26.224182</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.187851</Real>
+        <Real Name="Y">161.60725</Real>
+        <Real Name="Z">244.83252</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceVelocityVerlet_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_mdvv_NoseHoover_No_4Ranks_1RanksPerSimulation_d.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceVelocityVerlet_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_mdvv_NoseHoover_No_4Ranks_1RanksPerSimulation_d.xml
new file mode 100644 (file)
index 0000000..eee665f
--- /dev/null
@@ -0,0 +1,3310 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Replica exchange in temperature
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">19.745687852366352</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">19.745959185871566</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">19.746180949180349</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">19.746298539227634</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">19.746240975198585</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">18.483472747791065</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">18.483329976801897</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">18.483079241288976</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">18.482684767362585</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">18.482109159000078</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">18.495634628958175</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">18.494602125478721</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">18.493298014177526</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">25.760463806489305</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">25.75993170542425</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">25.759249595332413</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">25.761706543940036</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.419052386133135</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.849629854576342</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.412390353433604</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">31.12627729234212</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">31.99553353442063</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">28.426075309828075</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">28.8893792707911</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.499787165628298</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">30.255175605647381</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">31.151847254024247</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">32.132055839058772</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">33.232201420203147</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">34.401128707141105</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">37.954317707251064</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">38.593396024053618</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">39.320885539016423</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">40.125175050641502</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.089891600229349</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.652430335777829</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.366199684639058</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.235513490746619</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.9249588343292494</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.388405566281442</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.999064196631561</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-11.754847110577035</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-12.652094367316408</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-13.618777482392835</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-14.674329280054893</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-15.844560678294043</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-12.232035129455397</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-12.871645547323004</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-13.599817172377648</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-14.401649735395104</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13816730666039259</Real>
+        <Real Name="Y">-0.081793941152958807</Real>
+        <Real Name="Z">-0.55161420803864147</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6817968912385861</Real>
+        <Real Name="Y">0.11154328864465544</Real>
+        <Real Name="Z">0.086537431945853185</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50566706462034017</Real>
+        <Real Name="Y">-0.26824109290791975</Real>
+        <Real Name="Z">-0.36989321370880779</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.082187565565796414</Real>
+        <Real Name="Y">-0.035856486511024722</Real>
+        <Real Name="Z">0.27249213202030709</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0691700139813751</Real>
+        <Real Name="Y">-2.700986918594118</Real>
+        <Real Name="Z">-0.45056456497429864</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.99486964180314541</Real>
+        <Real Name="Y">-0.45276130194728997</Real>
+        <Real Name="Z">1.1449358532073448</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.0470582094128967</Real>
+        <Real Name="Y">-0.027117909659181094</Real>
+        <Real Name="Z">-0.68353533736848382</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.052922616420256773</Real>
+        <Real Name="Y">-0.42434110700619487</Real>
+        <Real Name="Z">-0.38322245057059767</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25128661637527649</Real>
+        <Real Name="Y">0.072381668037675526</Real>
+        <Real Name="Z">-0.58357101060971228</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20092812452327882</Real>
+        <Real Name="Y">0.39382068387208857</Real>
+        <Real Name="Z">0.71723514347464723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21974992231123289</Real>
+        <Real Name="Y">1.2084096572009659</Real>
+        <Real Name="Z">0.86299525553264622</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3874825489464533</Real>
+        <Real Name="Y">-0.64634842404151116</Real>
+        <Real Name="Z">0.87320911313451055</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2141468744966111</Real>
+        <Real Name="Y">-0.088294604527846279</Real>
+        <Real Name="Z">-0.037485865576621168</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8251647053114093</Real>
+        <Real Name="Y">0.93710079485932885</Real>
+        <Real Name="Z">2.5717978189626107</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38095191515252169</Real>
+        <Real Name="Y">-0.38837106592419213</Real>
+        <Real Name="Z">0.7382126945996792</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0031892964474940118</Real>
+        <Real Name="Y">0.59434435165674249</Real>
+        <Real Name="Z">0.24354731545017297</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8501856471995966</Real>
+        <Real Name="Y">0.68456996230865896</Real>
+        <Real Name="Z">0.27173852070686261</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.058269682764835129</Real>
+        <Real Name="Y">0.60241028732796376</Real>
+        <Real Name="Z">0.1656794136877659</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97851335458536903</Real>
+        <Real Name="Y">0.63000743966951411</Real>
+        <Real Name="Z">1.5703752146593384</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96153483249811356</Real>
+        <Real Name="Y">0.62398745344669726</Real>
+        <Real Name="Z">1.6643848309419782</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92785971505682796</Real>
+        <Real Name="Y">0.70597961835307188</Real>
+        <Real Name="Z">1.5416566619697321</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3933255305239798</Real>
+        <Real Name="Y">0.44734200905087834</Real>
+        <Real Name="Z">1.1773223303088398</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.333350743742469</Real>
+        <Real Name="Y">0.47715143833872575</Real>
+        <Real Name="Z">1.2457090342507966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3361612012542816</Real>
+        <Real Name="Y">0.4148055197716955</Real>
+        <Real Name="Z">1.1077814450359957</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6470575959101439</Real>
+        <Real Name="Y">0.31561407199718799</Real>
+        <Real Name="Z">0.29912783931133824</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7055428177902936</Real>
+        <Real Name="Y">0.33238282714799866</Real>
+        <Real Name="Z">0.22523192553850915</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5972911701617056</Real>
+        <Real Name="Y">0.23805908047548213</Real>
+        <Real Name="Z">0.27322717217141923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7765689727103515</Real>
+        <Real Name="Y">0.39600575099713692</Real>
+        <Real Name="Z">0.02277166399835371</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7121443546553381</Real>
+        <Real Name="Y">0.4096709664056008</Real>
+        <Real Name="Z">1.8153690922326495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8070722059208846</Real>
+        <Real Name="Y">0.48400488435134625</Real>
+        <Real Name="Z">0.044862922283285964</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.2346888771242896</Real>
+        <Real Name="Y">-0.68630032052929013</Real>
+        <Real Name="Z">-0.13430121798608188</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.59494298070650542</Real>
+        <Real Name="Y">-0.79239508446188722</Real>
+        <Real Name="Z">0.6485581160892917</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6637339792499741</Real>
+        <Real Name="Y">-0.6126609744581758</Real>
+        <Real Name="Z">1.2161889348359631</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43756011359762575</Real>
+        <Real Name="Y">-0.11889320063179534</Real>
+        <Real Name="Z">0.15943602083848921</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4277478848461573</Real>
+        <Real Name="Y">1.0155058954389415</Real>
+        <Real Name="Z">0.41091020836329067</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.524944801510552</Real>
+        <Real Name="Y">0.58147709607197595</Real>
+        <Real Name="Z">0.094274844201667971</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.48144377954812217</Real>
+        <Real Name="Y">0.0378867242761236</Real>
+        <Real Name="Z">0.39795702518097109</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.51542988135870482</Real>
+        <Real Name="Y">0.1002695426906664</Real>
+        <Real Name="Z">1.245017721304772</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.4590438945783044</Real>
+        <Real Name="Y">-1.9433160634115312</Real>
+        <Real Name="Z">2.1285251313963487</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24744454980739714</Real>
+        <Real Name="Y">0.3177388812146692</Real>
+        <Real Name="Z">-0.37827025864319608</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.28410044677339158</Real>
+        <Real Name="Y">0.83956824484902237</Real>
+        <Real Name="Z">-0.2308432015795247</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39101565795543036</Real>
+        <Real Name="Y">0.39054800197094491</Real>
+        <Real Name="Z">-0.87214678958824798</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19358420650112745</Real>
+        <Real Name="Y">0.45158058964086401</Real>
+        <Real Name="Z">-0.27734161828771953</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.40639410059259867</Real>
+        <Real Name="Y">-0.52459740030181035</Real>
+        <Real Name="Z">-1.0258462368720453</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7825392818908763</Real>
+        <Real Name="Y">0.91365473374994621</Real>
+        <Real Name="Z">0.076017294002523286</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-2.4436026146114784</Real>
+        <Real Name="Y">62.730391420611284</Real>
+        <Real Name="Z">-371.99265130131528</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.3935523284822935</Real>
+        <Real Name="Y">0.95419199124893339</Real>
+        <Real Name="Z">111.7412976209331</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.47534344589351</Real>
+        <Real Name="Y">65.010477334634061</Real>
+        <Real Name="Z">209.84688037696412</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.551520521429495</Real>
+        <Real Name="Y">-18.859652220286868</Real>
+        <Real Name="Z">-38.892217537407603</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.698033213022669</Real>
+        <Real Name="Y">-9.5334833226467772</Real>
+        <Real Name="Z">-24.567026009968778</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.432224279661547</Real>
+        <Real Name="Y">10.518458206481668</Real>
+        <Real Name="Z">12.983622714960951</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.547148075585696</Real>
+        <Real Name="Y">-7.2440703140311555</Real>
+        <Real Name="Z">-33.315570088294464</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-56.921041785311786</Real>
+        <Real Name="Y">11.272878860124717</Real>
+        <Real Name="Z">-15.036113213682128</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.615268615857012</Real>
+        <Real Name="Y">18.864561087624971</Real>
+        <Real Name="Z">56.460253887807475</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-309.14205075014803</Real>
+        <Real Name="Y">-123.38227480886626</Real>
+        <Real Name="Z">254.69626351478212</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.88883755285249</Real>
+        <Real Name="Y">108.01807731373977</Real>
+        <Real Name="Z">-280.1805244724996</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">113.87965794252231</Real>
+        <Real Name="Y">55.284596132613785</Real>
+        <Real Name="Z">-57.669172386623927</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-57.349111817624987</Real>
+        <Real Name="Y">-236.34307426055943</Real>
+        <Real Name="Z">-0.27415506548726398</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">7.5447461614665272</Real>
+        <Real Name="Y">44.614203614245724</Real>
+        <Real Name="Z">16.347026538873536</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-105.28843472107565</Real>
+        <Real Name="Y">18.094718965065567</Real>
+        <Real Name="Z">159.85208542095785</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0033644531920266792</Real>
+        <Real Name="Y">0.60656188412965628</Real>
+        <Real Name="Z">0.23556633654963643</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.025851574123490716</Real>
+        <Real Name="Y">0.66696044043732883</Real>
+        <Real Name="Z">0.30633823908279084</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.084187029465572896</Real>
+        <Real Name="Y">0.59760576442137792</Real>
+        <Real Name="Z">0.18507061906510627</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9717015417747541</Real>
+        <Real Name="Y">0.63342920847582285</Real>
+        <Real Name="Z">1.5675744160013783</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9752497058784324</Real>
+        <Real Name="Y">0.6060891102938456</Real>
+        <Real Name="Z">1.6592381927231177</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.88966632581018668</Real>
+        <Real Name="Y">0.68220105180475399</Real>
+        <Real Name="Z">1.560236225492494</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959297221909546</Real>
+        <Real Name="Y">0.44153602834864886</Real>
+        <Real Name="Z">1.1692214160390264</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3337050741076391</Real>
+        <Real Name="Y">0.43590712176713714</Real>
+        <Real Name="Z">1.2417384966587239</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3518768536224663</Real>
+        <Real Name="Y">0.39781612084733797</Real>
+        <Real Name="Z">1.0963500714722907</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6451682815453181</Real>
+        <Real Name="Y">0.31683608005805697</Real>
+        <Real Name="Z">0.30363101313856011</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6950923161725286</Real>
+        <Real Name="Y">0.33270230792769645</Real>
+        <Real Name="Z">0.2235175187713227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5991108635435984</Real>
+        <Real Name="Y">0.23452923567018077</Real>
+        <Real Name="Z">0.28730263251081761</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.77659257584179</Real>
+        <Real Name="Y">0.39377501853016234</Real>
+        <Real Name="Z">0.033312599669388536</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7162951525443457</Real>
+        <Real Name="Y">0.42399059166093594</Real>
+        <Real Name="Z">1.8274494203852336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8499358003936774</Real>
+        <Real Name="Y">0.45515259073902165</Real>
+        <Real Name="Z">0.029327196041473415</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.12386801085079827</Real>
+        <Real Name="Y">0.67299745782716036</Real>
+        <Real Name="Z">-0.61833047229450422</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.58813662163845537</Real>
+        <Real Name="Y">-3.5232413586181281</Real>
+        <Real Name="Z">2.8153302509876852</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7111221100415379</Real>
+        <Real Name="Y">-1.7767548147279766</Real>
+        <Real Name="Z">2.356698848795872</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20627150899439595</Real>
+        <Real Name="Y">0.14808136436957364</Real>
+        <Real Name="Z">-0.11473521931080279</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5504097157843519</Real>
+        <Real Name="Y">-0.49098955993461157</Real>
+        <Real Name="Z">-0.37334615513390523</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.281172169400604</Real>
+        <Real Name="Y">-1.4403547208508169</Real>
+        <Real Name="Z">1.344582567209563</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.14122421577823888</Real>
+        <Real Name="Y">-0.36388728402662596</Real>
+        <Real Name="Z">-0.28508620873721424</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97008486868841293</Real>
+        <Real Name="Y">-2.2081107725468438</Real>
+        <Real Name="Z">0.5253415478437049</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.27372306245447159</Real>
+        <Real Name="Y">-1.8168818482008298</Real>
+        <Real Name="Z">0.33580490153083803</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.015515691796199389</Real>
+        <Real Name="Y">0.22205486646096334</Real>
+        <Real Name="Z">0.088890659144712544</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.62206808246108836</Real>
+        <Real Name="Y">1.1765605163968009</Real>
+        <Real Name="Z">-0.11939323123884069</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.61082271996207793</Real>
+        <Real Name="Y">-0.060171277440738045</Real>
+        <Real Name="Z">-0.16766640078638589</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11575130860451384</Real>
+        <Real Name="Y">-0.0025728949642267146</Real>
+        <Real Name="Z">0.47590657936601938</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.30010988975485886</Real>
+        <Real Name="Y">0.81264276456272977</Real>
+        <Real Name="Z">0.4693822921147553</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.0393262771127247</Real>
+        <Real Name="Y">-1.4131455065796981</Real>
+        <Real Name="Z">0.0091012680731963648</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">160.07262804605011</Real>
+        <Real Name="Y">112.48097382539865</Real>
+        <Real Name="Z">-266.13326298979115</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-43.177245090086295</Real>
+        <Real Name="Y">-34.574030264196558</Real>
+        <Real Name="Z">74.962739790185054</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.696152632686861</Real>
+        <Real Name="Y">40.518945822980058</Real>
+        <Real Name="Z">191.57936534660962</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">9.5895789146594836</Real>
+        <Real Name="Y">-26.792943165644424</Real>
+        <Real Name="Z">-24.444046514631822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.347414140330784</Real>
+        <Real Name="Y">-5.343604458400808</Real>
+        <Real Name="Z">-27.20016831811612</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">26.806213312796686</Real>
+        <Real Name="Y">-8.7929490539806459</Real>
+        <Real Name="Z">-23.447772523075287</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.587209884238362</Real>
+        <Real Name="Y">-17.175648034358709</Real>
+        <Real Name="Z">-27.862856659913298</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.328482463417359</Real>
+        <Real Name="Y">17.431750231400571</Real>
+        <Real Name="Z">-21.38109600129436</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.98496785608846</Real>
+        <Real Name="Y">41.513834826786074</Real>
+        <Real Name="Z">83.027347088575098</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-263.79270882973674</Real>
+        <Real Name="Y">-180.21275265722196</Real>
+        <Real Name="Z">380.17567780184288</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">237.55235454553707</Real>
+        <Real Name="Y">180.88375229732929</Real>
+        <Real Name="Z">-389.44741758594745</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">95.071442753244028</Real>
+        <Real Name="Y">79.673620529639777</Real>
+        <Real Name="Z">-88.260592585477269</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.585476455892092</Real>
+        <Real Name="Y">-429.78032785358403</Real>
+        <Real Name="Z">5.3728662187716054</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.134667270941549</Real>
+        <Real Name="Y">112.49619939567556</Real>
+        <Real Name="Z">38.13834472575499</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.9887808052641</Real>
+        <Real Name="Y">117.67317855817714</Real>
+        <Real Name="Z">94.920872206507511</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Replica exchange in temperature
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">18.488713586547306</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">18.488785328167737</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">18.483546214400391</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">18.483564054713952</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">18.483548642211634</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">19.745932186164943</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">19.745249450357537</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">19.74409462093946</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">19.742359566157198</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">25.723885273140002</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">25.761420813340433</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">25.761188659826665</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">25.760882773850476</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">18.491724140066523</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">18.489861053709458</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">18.487741917329419</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">18.485406344657449</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">28.162078120314089</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">28.003688745028921</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">27.925039990657197</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">27.943934270584425</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">28.110863158164904</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">33.022499183449348</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.20644441177879</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">35.542324746516883</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.019306257091216</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">36.213996501613224</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">36.578347486750609</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">36.934585715112021</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">37.402220074748179</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">35.670025738372985</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">37.021650012766699</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">38.435710677725638</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">39.889134045032073</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.4972596832327092</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.4238500426283309</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.4427264822419978</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.6096707823247947</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.262787924185135</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.447415888321981</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-15.784451052478151</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.263167617834746</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-10.498049678131444</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-10.824865123068399</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-11.211578296791485</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-11.679518542403834</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.115031562405377</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-18.468518923156157</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-19.884698724495134</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-21.34045766447354</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.211878078767191</Real>
+        <Real Name="Y">-0.73077347026156991</Real>
+        <Real Name="Z">0.011171437501855584</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.66853774156615786</Real>
+        <Real Name="Y">-0.45353902926449868</Real>
+        <Real Name="Z">-0.19972227335766229</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.079818727349109581</Real>
+        <Real Name="Y">-1.3654526477360689</Real>
+        <Real Name="Z">0.097918996250142207</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44649060975497223</Real>
+        <Real Name="Y">-0.1288882323582177</Real>
+        <Real Name="Z">0.17260901011763136</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1362962189418437</Real>
+        <Real Name="Y">1.2244003919727864</Real>
+        <Real Name="Z">0.58872925177925128</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4191022897892034</Real>
+        <Real Name="Y">0.66040224039932383</Real>
+        <Real Name="Z">0.09971513807916231</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.42277370397287506</Real>
+        <Real Name="Y">0.039570897331179494</Real>
+        <Real Name="Z">0.42216353749486379</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.32221850243232519</Real>
+        <Real Name="Y">0.031569804773277761</Real>
+        <Real Name="Z">1.2362165347476495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7650077045875798</Real>
+        <Real Name="Y">-2.0605225290512674</Real>
+        <Real Name="Z">1.6261241291580466</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2607742955347423</Real>
+        <Real Name="Y">0.32039821416325343</Real>
+        <Real Name="Z">-0.34791997504828298</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.14843292582223969</Real>
+        <Real Name="Y">0.34930531668637371</Real>
+        <Real Name="Z">-0.4312889387669494</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019821817649299106</Real>
+        <Real Name="Y">0.52909722809135307</Real>
+        <Real Name="Z">-0.45886531538439351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15571996415174752</Real>
+        <Real Name="Y">0.54546652165796994</Real>
+        <Real Name="Z">-0.27451962327590645</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26909661321241973</Real>
+        <Real Name="Y">-0.7857342221338679</Real>
+        <Real Name="Z">-1.2282440898380882</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93956674932818385</Real>
+        <Real Name="Y">1.1439303667352787</Real>
+        <Real Name="Z">-1.0687581211696437</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0059893323231195051</Real>
+        <Real Name="Y">0.59960420077688648</Real>
+        <Real Name="Z">0.23895579497248348</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8580335089497806</Real>
+        <Real Name="Y">0.68791033764979626</Real>
+        <Real Name="Z">0.27450896463056917</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.061665134983477601</Real>
+        <Real Name="Y">0.61092101410108057</Real>
+        <Real Name="Z">0.16192039314767412</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97423961290560879</Real>
+        <Real Name="Y">0.6307141718496917</Real>
+        <Real Name="Z">1.5712926241567604</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9444612209902431</Real>
+        <Real Name="Y">0.5931704592423096</Real>
+        <Real Name="Z">1.6541541678220153</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90863690528461272</Real>
+        <Real Name="Y">0.69711089689337935</Real>
+        <Real Name="Z">1.550077580997087</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3964997513060144</Real>
+        <Real Name="Y">0.44682891475738734</Real>
+        <Real Name="Z">1.1685973973665778</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3310622503035729</Real>
+        <Real Name="Y">0.47334316573490609</Real>
+        <Real Name="Z">1.2332290177830278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3463309334205393</Real>
+        <Real Name="Y">0.43157811180839217</Real>
+        <Real Name="Z">1.0885173054498944</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.643322704370038</Real>
+        <Real Name="Y">0.3161602180424905</Real>
+        <Real Name="Z">0.30759367876334903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7027379844322608</Real>
+        <Real Name="Y">0.33843584793596143</Real>
+        <Real Name="Z">0.23592821143091303</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6091881965628587</Real>
+        <Real Name="Y">0.22976814977117793</Real>
+        <Real Name="Z">0.28449466760342729</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.779299600370108</Real>
+        <Real Name="Y">0.39121343740472742</Real>
+        <Real Name="Z">0.024520642120395241</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6974192099821359</Real>
+        <Real Name="Y">0.42101078236544304</Real>
+        <Real Name="Z">1.8469569332681814</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8188258358470284</Real>
+        <Real Name="Y">0.47061019011934618</Real>
+        <Real Name="Z">0.060522736051114731</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11757754520467041</Real>
+        <Real Name="Y">-0.019415861653820088</Real>
+        <Real Name="Z">-0.72920643874077751</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.490750066076296</Real>
+        <Real Name="Y">-0.599072613863323</Real>
+        <Real Name="Z">1.0973733726972887</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0630338524078491</Real>
+        <Real Name="Y">0.41162533032846299</Real>
+        <Real Name="Z">0.74015506866478087</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10247986859543927</Real>
+        <Real Name="Y">-0.0385157149686981</Real>
+        <Real Name="Z">0.28861633891611627</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63113547368025247</Real>
+        <Real Name="Y">-2.7178473591125059</Real>
+        <Real Name="Z">-1.1153470182479719</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.86551845382465065</Real>
+        <Real Name="Y">-0.51105407318726792</Real>
+        <Real Name="Z">1.1692366434087742</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.060120711973995537</Real>
+        <Real Name="Y">-0.02264438498810931</Real>
+        <Real Name="Z">-0.67807410815691715</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23030822314177529</Real>
+        <Real Name="Y">-0.41629215553299992</Real>
+        <Real Name="Z">-0.22253517337491593</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46763676251797881</Real>
+        <Real Name="Y">0.10964395334057218</Real>
+        <Real Name="Z">-0.44796579154783545</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22564630070519798</Real>
+        <Real Name="Y">0.38080494708756446</Real>
+        <Real Name="Z">0.6678429944391101</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.0044103898003086534</Real>
+        <Real Name="Y">1.4224571130176153</Real>
+        <Real Name="Z">1.1750363901594689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9458785407373904</Real>
+        <Real Name="Y">-0.47943369490283971</Real>
+        <Real Name="Z">0.67623572750496219</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11255430841403102</Real>
+        <Real Name="Y">-0.088988578726761164</Real>
+        <Real Name="Z">-0.071537519050047876</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1680087851073384</Real>
+        <Real Name="Y">0.46198818596996655</Real>
+        <Real Name="Z">2.9890202694516379</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.083592589775764642</Real>
+        <Real Name="Y">-1.0349112770881352</Real>
+        <Real Name="Z">2.2298880373163295</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-64.500762272583643</Real>
+        <Real Name="Y">-106.42569518958294</Real>
+        <Real Name="Z">-417.21142154430942</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.19957151831450659</Real>
+        <Real Name="Y">35.041512960807907</Real>
+        <Real Name="Z">108.81180041863723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">177.61023247980683</Real>
+        <Real Name="Y">150.50688377952639</Real>
+        <Real Name="Z">171.79033840292306</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.698962476050468</Real>
+        <Real Name="Y">-14.33192809069525</Real>
+        <Real Name="Z">-37.63266659634121</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.7580527662764</Real>
+        <Real Name="Y">-8.0142628723856006</Real>
+        <Real Name="Z">-23.759068632183556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.2965714288459012</Real>
+        <Real Name="Y">7.67071271731254</Real>
+        <Real Name="Z">12.782543156913505</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.140610756659356</Real>
+        <Real Name="Y">-14.341499754198722</Real>
+        <Real Name="Z">-32.979773675920676</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.400011996062517</Real>
+        <Real Name="Y">12.111500359467549</Real>
+        <Real Name="Z">27.164536420448947</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.901042574077799</Real>
+        <Real Name="Y">16.905477640499484</Real>
+        <Real Name="Z">54.42442932708299</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-258.07750313837937</Real>
+        <Real Name="Y">-52.449871366652545</Real>
+        <Real Name="Z">175.90745565340103</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">212.878680166669</Real>
+        <Real Name="Y">26.473822004919683</Real>
+        <Real Name="Z">-197.02158368441644</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.675190760443826</Real>
+        <Real Name="Y">33.097812745823745</Real>
+        <Real Name="Z">-53.51358059344048</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-59.619044958686061</Real>
+        <Real Name="Y">-231.467604972153</Real>
+        <Real Name="Z">9.0245777631747615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.945713160147761</Real>
+        <Real Name="Y">75.055910647825613</Real>
+        <Real Name="Z">-11.075745178175168</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-78.220651395437358</Real>
+        <Real Name="Y">70.167229389485158</Real>
+        <Real Name="Z">213.28815876220528</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0013531261322683277</Real>
+        <Real Name="Y">0.58920755970593197</Real>
+        <Real Name="Z">0.24168472408337494</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8542042015417388</Real>
+        <Real Name="Y">0.67610329959106286</Real>
+        <Real Name="Z">0.28075702242505612</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.075632727477763215</Real>
+        <Real Name="Y">0.5975308820665004</Real>
+        <Real Name="Z">0.1818885575771837</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9819732381426276</Real>
+        <Real Name="Y">0.62911893408986219</Real>
+        <Real Name="Z">1.5716620094028959</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97374818268183294</Real>
+        <Real Name="Y">0.63131987825525659</Real>
+        <Real Name="Z">1.6670025711143062</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94047033001922886</Real>
+        <Real Name="Y">0.71015535007476482</Real>
+        <Real Name="Z">1.5421166831799189</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3892341881959629</Real>
+        <Real Name="Y">0.44759903699145015</Real>
+        <Real Name="Z">1.1804276514209311</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3378569610515643</Real>
+        <Real Name="Y">0.4784314291759178</Real>
+        <Real Name="Z">1.2550739006444236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3264461468662527</Real>
+        <Real Name="Y">0.39994624312151233</Real>
+        <Real Name="Z">1.1261211922989491</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6489865975301321</Real>
+        <Real Name="Y">0.3181335143301855</Real>
+        <Real Name="Z">0.29598441669927877</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7082590731228386</Real>
+        <Real Name="Y">0.34106684029309681</Real>
+        <Real Name="Z">0.22440820139425982</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6021445784390125</Real>
+        <Real Name="Y">0.24081692492367757</Real>
+        <Real Name="Z">0.26451556463867421</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.774971894665565</Real>
+        <Real Name="Y">0.39931717153493479</Real>
+        <Real Name="Z">0.020606156793391138</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.715821754845007</Real>
+        <Real Name="Y">0.40730263199185951</Real>
+        <Real Name="Z">1.8078342666629188</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7887272312185531</Real>
+        <Real Name="Y">0.48935505155015224</Real>
+        <Real Name="Z">0.050038949366965485</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21092086228099188</Real>
+        <Real Name="Y">-0.58443078366116918</Real>
+        <Real Name="Z">-0.34199623147522196</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.34983916022098566</Real>
+        <Real Name="Y">-1.408065208170155</Real>
+        <Real Name="Z">1.6219097256851969</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4243096135798665</Real>
+        <Real Name="Y">-0.81186354784481563</Real>
+        <Real Name="Z">2.8998649833020878</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.4274186958118425</Real>
+        <Real Name="Y">-0.10170799354016853</Real>
+        <Real Name="Z">0.16605345584107217</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5972974367711184</Real>
+        <Real Name="Y">0.82089952832258306</Real>
+        <Real Name="Z">0.24568073879731864</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6236853105032572</Real>
+        <Real Name="Y">0.4526833869500923</Real>
+        <Real Name="Z">0.0062091259077262581</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53943476356382081</Real>
+        <Real Name="Y">0.024373722595010538</Real>
+        <Real Name="Z">0.37948555445528115</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.58301557069509247</Real>
+        <Real Name="Y">0.22375735019531609</Real>
+        <Real Name="Z">1.0696864971166764</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.94317040109162686</Real>
+        <Real Name="Y">-1.7603480074397084</Real>
+        <Real Name="Z">2.4123329983283055</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23510342489095926</Real>
+        <Real Name="Y">0.31181573253140615</Real>
+        <Real Name="Z">-0.4083089542619176</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39282067104844898</Real>
+        <Real Name="Y">1.3072593167242992</Real>
+        <Real Name="Z">0.041241551870331433</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.82523428988037972</Real>
+        <Real Name="Y">0.31506699369052438</Real>
+        <Real Name="Z">-1.2947187163487444</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20182294593812372</Real>
+        <Real Name="Y">0.38512288581526988</Real>
+        <Real Name="Z">-0.25701130710744347</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.51043440341601209</Real>
+        <Real Name="Y">-0.001954245621809219</Real>
+        <Real Name="Z">-0.86131397607040916</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7659170238614865</Real>
+        <Real Name="Y">0.30427483427748792</Real>
+        <Real Name="Z">1.1886335141517215</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-71.125572016362611</Real>
+        <Real Name="Y">72.032026969690776</Real>
+        <Real Name="Z">-362.29053246249021</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.8458441669965211</Real>
+        <Real Name="Y">-0.67692397313088293</Real>
+        <Real Name="Z">111.86362201508132</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">135.89762223614272</Real>
+        <Real Name="Y">0.94905780128802064</Real>
+        <Real Name="Z">136.34503626557981</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.781472201795211</Real>
+        <Real Name="Y">-23.784776840398443</Real>
+        <Real Name="Z">-37.684969414157067</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6875346853239392</Real>
+        <Real Name="Y">7.1059220008763475</Real>
+        <Real Name="Z">14.348627908018393</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.3502142974762279</Real>
+        <Real Name="Y">12.89026610854145</Real>
+        <Real Name="Z">11.868830803971498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.772929899609423</Real>
+        <Real Name="Y">-3.8450587690236731</Real>
+        <Real Name="Z">-32.283551382228438</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.248975725433965</Real>
+        <Real Name="Y">9.0251033838137218</Real>
+        <Real Name="Z">-18.110316762210587</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.171523848667086</Real>
+        <Real Name="Y">4.2361175422982491</Real>
+        <Real Name="Z">18.128043404960245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-317.03994585265588</Real>
+        <Real Name="Y">-134.54136550251559</Real>
+        <Real Name="Z">277.22436322191106</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">244.71969926910984</Real>
+        <Real Name="Y">104.75744719525008</Real>
+        <Real Name="Z">-285.41545552779371</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">118.95340350592031</Real>
+        <Real Name="Y">61.360283386446937</Real>
+        <Real Name="Z">-64.544447586624955</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-73.075822031276743</Real>
+        <Real Name="Y">-317.70988901704038</Real>
+        <Real Name="Z">-34.09131860737557</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.021997197783421</Real>
+        <Real Name="Y">56.775346609541273</Real>
+        <Real Name="Z">25.171364673224531</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-31.29338002016101</Real>
+        <Real Name="Y">151.42644310436205</Real>
+        <Real Name="Z">239.47070345013316</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 2">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Replica exchange in temperature
+Replica exchange interval: 4
+Replica random seed: 98715
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.728260327373206</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.728243473655716</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.72821128933289</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.728178703739811</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">29.728155893618855</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">25.724700459236608</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">25.724463167137685</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">25.724260162558565</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">25.724078086190787</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">19.739964411684667</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">19.736826220222138</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">19.732959039999297</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">19.728454061719347</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">29.727249654779431</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">29.726696149958759</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">29.691086343775265</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">29.690170102144709</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">39.401624861139993</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">39.074321110569585</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">38.872947836756602</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">38.768875631058528</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">38.761001030586065</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">35.208544690832738</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">35.364369625900991</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">35.582699786202859</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.865083831074998</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">38.619355046981966</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">40.315934620455565</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">42.074714201396276</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">43.847699130124752</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">42.880449833154955</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">43.80966035918923</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">44.77086723749963</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">45.75075181722535</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.3732419418552322</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.1719008523650771</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.067861232260082</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.0600094419085782</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.4917826839182595</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-9.6478449110854338</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-9.8663780759664235</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.148944197206342</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-18.865611557574177</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-20.565329322510305</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-22.326736716162035</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.104226623170462</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-13.272724352390009</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-14.202488383244955</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-15.199305067738846</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-16.180105889095124</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.55933757253984606</Real>
+        <Real Name="Y">-0.1953333817225075</Real>
+        <Real Name="Z">-0.12442175095694226</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5601319004003147</Real>
+        <Real Name="Y">0.14590968271733512</Real>
+        <Real Name="Z">-0.45402360377419232</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.240238341268574</Real>
+        <Real Name="Y">-1.1741270631878449</Real>
+        <Real Name="Z">-1.2377431242149066</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10186697006374196</Real>
+        <Real Name="Y">0.57542717134575494</Real>
+        <Real Name="Z">0.0047707720363739034</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.36213664999805006</Real>
+        <Real Name="Y">0.14107914283668432</Real>
+        <Real Name="Z">-0.19176476301858633</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6918291835180566</Real>
+        <Real Name="Y">2.1823179556714214</Real>
+        <Real Name="Z">0.67191360218736684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22502769487513585</Real>
+        <Real Name="Y">0.27110838053704805</Real>
+        <Real Name="Z">0.38807489163868208</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.20024829808261638</Real>
+        <Real Name="Y">3.0906294848161289</Real>
+        <Real Name="Z">-0.50929083080598947</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.44380096664296076</Real>
+        <Real Name="Y">-1.4298766134746896</Real>
+        <Real Name="Z">0.85415744761894952</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11843167602141179</Real>
+        <Real Name="Y">-0.50488773980756441</Real>
+        <Real Name="Z">0.090438443427804896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67606901848995327</Real>
+        <Real Name="Y">-0.050571628651510762</Real>
+        <Real Name="Z">0.62218423978243576</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2344507177617747</Real>
+        <Real Name="Y">-1.9401442446083794</Real>
+        <Real Name="Z">0.46394157066291142</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.90616875321389834</Real>
+        <Real Name="Y">-0.19883636434320212</Real>
+        <Real Name="Z">-0.24409085123059568</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.86349870962648956</Real>
+        <Real Name="Y">0.70307319456972894</Real>
+        <Real Name="Z">-1.8507772174768506</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.40005997059275533</Real>
+        <Real Name="Y">-0.83463968183258119</Real>
+        <Real Name="Z">-0.190298923880004</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0035317080356165342</Real>
+        <Real Name="Y">0.60225632930771267</Real>
+        <Real Name="Z">0.24029868662290682</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.010740582722320594</Real>
+        <Real Name="Y">0.68678613600152549</Real>
+        <Real Name="Z">0.28462770991530206</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.066951189512772735</Real>
+        <Real Name="Y">0.60718198406166191</Real>
+        <Real Name="Z">0.16877228803879507</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9733657442066127</Real>
+        <Real Name="Y">0.63220849130472012</Real>
+        <Real Name="Z">1.5684025671750976</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96288476958305647</Real>
+        <Real Name="Y">0.61037947027757733</Real>
+        <Real Name="Z">1.6610090540533755</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90154775178218871</Real>
+        <Real Name="Y">0.69266902925674845</Real>
+        <Real Name="Z">1.5497205513664003</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3967524276177743</Real>
+        <Real Name="Y">0.44432936438882814</Real>
+        <Real Name="Z">1.1715869610030765</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3287635474723645</Real>
+        <Real Name="Y">0.45539255512177901</Real>
+        <Real Name="Z">1.2380507585727236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3497462886905984</Real>
+        <Real Name="Y">0.41367812063004145</Real>
+        <Real Name="Z">1.0940418608406675</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450935092707222</Real>
+        <Real Name="Y">0.31500125286474939</Real>
+        <Real Name="Z">0.30288435157329852</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6996373243647238</Real>
+        <Real Name="Y">0.32688411659538974</Real>
+        <Real Name="Z">0.22512775581094527</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5957757948759512</Real>
+        <Real Name="Y">0.23481052205810632</Real>
+        <Real Name="Z">0.28557747029526576</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7773945897540362</Real>
+        <Real Name="Y">0.39324260688377438</Real>
+        <Real Name="Z">0.029315571703551178</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7133341910718911</Real>
+        <Real Name="Y">0.41887950642193156</Real>
+        <Real Name="Z">1.8250330280173557</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8379181835661336</Real>
+        <Real Name="Y">0.46724501476402247</Real>
+        <Real Name="Z">0.034096431458169645</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.13406961096748515</Real>
+        <Real Name="Y">0.4001027512189857</Real>
+        <Real Name="Z">-0.54057622402621242</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9294551322261468</Real>
+        <Real Name="Y">-1.3939085692923943</Real>
+        <Real Name="Z">2.3821785432385538</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3350203354170938</Real>
+        <Real Name="Y">-0.64168675717925538</Real>
+        <Real Name="Z">1.5769204160067247</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20719376666973552</Real>
+        <Real Name="Y">0.15462536345077607</Real>
+        <Real Name="Z">-0.092224889386937792</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5206072302277323</Real>
+        <Real Name="Y">-0.57208293191390902</Real>
+        <Real Name="Z">-0.067974884677499806</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.6742858861270111</Real>
+        <Real Name="Y">-1.1739853884228346</Real>
+        <Real Name="Z">1.2478387413446212</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.062636467590587719</Real>
+        <Real Name="Y">-0.33863534772653914</Real>
+        <Real Name="Z">-0.30384581457532461</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23647100955243278</Real>
+        <Real Name="Y">-2.6090094521301821</Real>
+        <Real Name="Z">0.38003873352941264</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.20925748176087344</Real>
+        <Real Name="Y">-2.1102133497784927</Real>
+        <Real Name="Z">0.23158949126561168</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0064911891838976875</Real>
+        <Real Name="Y">0.23696319189784243</Real>
+        <Real Name="Z">0.097191761674596255</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.52637806722745406</Real>
+        <Real Name="Y">0.27573499285604375</Real>
+        <Real Name="Z">-0.27067416510831127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21235041746641939</Real>
+        <Real Name="Y">0.0048643583410875393</Real>
+        <Real Name="Z">0.58599551091265878</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.08621413268750111</Real>
+        <Real Name="Y">0.12506157725780115</Real>
+        <Real Name="Z">0.52370543908141387</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43917302377320527</Real>
+        <Real Name="Y">0.50834305013000014</Real>
+        <Real Name="Z">0.16450362428201321</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9945936543087803</Real>
+        <Real Name="Y">-1.4641806619950979</Real>
+        <Real Name="Z">-1.2187035247985549</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">118.59007001614734</Real>
+        <Real Name="Y">88.077669973266893</Real>
+        <Real Name="Z">-316.8999417787935</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-30.395159154352179</Real>
+        <Real Name="Y">-18.367578791642273</Real>
+        <Real Name="Z">87.898452134901831</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">60.379268249190304</Real>
+        <Real Name="Y">76.797365416615122</Real>
+        <Real Name="Z">219.39143392431862</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.841503838650794</Real>
+        <Real Name="Y">-21.730158660300354</Real>
+        <Real Name="Z">-33.096264616359321</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.000067190520561</Real>
+        <Real Name="Y">-6.953660987988286</Real>
+        <Real Name="Z">-24.680462167451765</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6338470573587145</Real>
+        <Real Name="Y">9.5452318174986068</Real>
+        <Real Name="Z">10.576884851497582</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.477147697698541</Real>
+        <Real Name="Y">-13.997720562198829</Real>
+        <Real Name="Z">-31.190679406117454</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.444704004301393</Real>
+        <Real Name="Y">13.43128743704095</Real>
+        <Real Name="Z">24.938502350520253</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.240167665209796</Real>
+        <Real Name="Y">19.705020955947912</Real>
+        <Real Name="Z">53.452018987910705</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-294.36757497412867</Real>
+        <Real Name="Y">-161.07557230039257</Real>
+        <Real Name="Z">314.37903616810547</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.00647650314949</Real>
+        <Real Name="Y">159.62872977741725</Real>
+        <Real Name="Z">-332.527088215758</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">105.3466408157413</Real>
+        <Real Name="Y">69.314932358998718</Real>
+        <Real Name="Z">-71.966922313429137</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-68.409385974989164</Real>
+        <Real Name="Y">-324.1932790931246</Real>
+        <Real Name="Z">-20.511703850249432</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-17.411117481186551</Real>
+        <Real Name="Y">78.021320319328794</Real>
+        <Real Name="Z">-5.4526489172181982</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-109.73921799957168</Real>
+        <Real Name="Y">31.796412339532679</Real>
+        <Real Name="Z">125.68938284812214</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.013605581144290672</Real>
+        <Real Name="Y">0.59725969557387604</Real>
+        <Real Name="Z">0.23987830472120988</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.006053409106475967</Real>
+        <Real Name="Y">0.68552336822467341</Real>
+        <Real Name="Z">0.27613857482091653</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.056328269118503034</Real>
+        <Real Name="Y">0.60970515512236334</Real>
+        <Real Name="Z">0.15513043826497044</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97658837850405911</Real>
+        <Real Name="Y">0.64048870035830496</Real>
+        <Real Name="Z">1.5684868748690532</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94705903576027639</Real>
+        <Real Name="Y">0.6164711826791438</Real>
+        <Real Name="Z">1.6563133809002688</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94579680766764562</Real>
+        <Real Name="Y">0.73033102701462427</Real>
+        <Real Name="Z">1.5565472808053882</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.393083204461137</Real>
+        <Real Name="Y">0.45167701643332059</Real>
+        <Real Name="Z">1.180540158131606</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.338779064819108</Real>
+        <Real Name="Y">0.51957784081980474</Real>
+        <Real Name="Z">1.2205758530222215</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3364330669667379</Real>
+        <Real Name="Y">0.41130941985529856</Real>
+        <Real Name="Z">1.1147865463039706</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6468202607618658</Real>
+        <Real Name="Y">0.30426438025772157</Real>
+        <Real Name="Z">0.30275339299805204</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7107650065488063</Real>
+        <Real Name="Y">0.33603032437333985</Real>
+        <Real Name="Z">0.2390014308267846</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6387463701097242</Real>
+        <Real Name="Y">0.21073084384590524</Real>
+        <Real Name="Z">0.28408233903646646</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7627405455769776</Real>
+        <Real Name="Y">0.38764308153868482</Real>
+        <Real Name="Z">0.02077251780292733</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7275376359887642</Real>
+        <Real Name="Y">0.4261769902469788</Real>
+        <Real Name="Z">1.8025940517396695</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.812180079557808</Real>
+        <Real Name="Y">0.45860517037141491</Real>
+        <Real Name="Z">0.061789987596342077</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.52323029120395226</Real>
+        <Real Name="Y">-0.14959606293338318</Real>
+        <Real Name="Z">-0.40599816644943254</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.2008152394513927</Real>
+        <Real Name="Y">-0.80605735224872188</Real>
+        <Real Name="Z">1.3330656153164493</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8229092133395675</Real>
+        <Real Name="Y">1.0542019729580105</Real>
+        <Real Name="Z">0.4259708230436885</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.099483417434962737</Real>
+        <Real Name="Y">0.61493630655196063</Real>
+        <Real Name="Z">-0.069274846950111657</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.16564326529542556</Real>
+        <Real Name="Y">0.044071141062064279</Real>
+        <Real Name="Z">-0.31452860760618129</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9884390325426697</Real>
+        <Real Name="Y">1.4374540422152684</Real>
+        <Real Name="Z">1.2484413479855321</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24926844330650322</Real>
+        <Real Name="Y">0.31255318031872081</Real>
+        <Real Name="Z">0.41460982745843195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.78582602562539072</Real>
+        <Real Name="Y">2.1442584052756475</Real>
+        <Real Name="Z">-1.287980333903149</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0986125998954965</Real>
+        <Real Name="Y">-0.95218110583063176</Real>
+        <Real Name="Z">1.9228120985741421</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.1259043041104769</Real>
+        <Real Name="Y">-0.59953836939777683</Real>
+        <Real Name="Z">0.015833203102406664</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.14985189466079804</Real>
+        <Real Name="Y">1.0153490187690388</Real>
+        <Real Name="Z">0.54389949862254494</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9456730963636892</Real>
+        <Real Name="Y">-0.88252383445468352</Real>
+        <Real Name="Z">0.21411480062539612</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96629435213465786</Real>
+        <Real Name="Y">-0.34217287184553113</Real>
+        <Real Name="Z">-0.26563206117851146</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3332721774731677</Real>
+        <Real Name="Y">0.76015990232835706</Real>
+        <Real Name="Z">-0.7451307858594749</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2512830207787888</Real>
+        <Real Name="Y">-1.2145468862988344</Real>
+        <Real Name="Z">1.5871196970195256</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-22.943267635118019</Real>
+        <Real Name="Y">-160.92108809071303</Real>
+        <Real Name="Z">-388.62082215660848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.269501294329437</Real>
+        <Real Name="Y">39.693394124075041</Real>
+        <Real Name="Z">98.581307451420201</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">141.00081736152578</Real>
+        <Real Name="Y">181.80902904162826</Real>
+        <Real Name="Z">167.97316008436152</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.665821885685631</Real>
+        <Real Name="Y">-3.7820207736490659</Real>
+        <Real Name="Z">-39.203017217625415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.0514187152822174</Real>
+        <Real Name="Y">-0.40138401422217562</Real>
+        <Real Name="Z">13.222910151971639</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-6.2043866739720244</Real>
+        <Real Name="Y">5.2008854227279997</Real>
+        <Real Name="Z">15.083199645218457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">35.805297333054313</Real>
+        <Real Name="Y">-8.6559210503668922</Real>
+        <Real Name="Z">-31.008474034787881</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.22968029081548</Real>
+        <Real Name="Y">1.9531619695758913</Real>
+        <Real Name="Z">25.060889752308086</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-12.985633538670218</Real>
+        <Real Name="Y">5.6852784459342445</Real>
+        <Real Name="Z">16.844491702915114</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-210.54766033666638</Real>
+        <Real Name="Y">-92.830909558613669</Real>
+        <Real Name="Z">298.22961563929988</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">101.40912544568994</Real>
+        <Real Name="Y">44.375705942328622</Real>
+        <Real Name="Z">-279.03489826351665</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.019943940369529</Real>
+        <Real Name="Y">74.505781244012354</Real>
+        <Real Name="Z">-101.43770511717975</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.200207029403145</Real>
+        <Real Name="Y">-168.15266111198002</Real>
+        <Real Name="Z">56.854433577710552</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-41.231751243475834</Real>
+        <Real Name="Y">19.672919917643114</Real>
+        <Real Name="Z">-7.3846500623037059</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-54.637913267398716</Real>
+        <Real Name="Y">61.84782849161931</Real>
+        <Real Name="Z">154.83955884681643</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 3">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Replica exchange in temperature
+Replica exchange interval: 4
+Replica random seed: 98716
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">25.726002662765701</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">25.725860630086956</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">25.725599668389684</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">25.725292591220537</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">25.724987870239637</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">29.728160552318045</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.728165253547203</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.728175451357753</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.728177479911281</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">29.728152107086508</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">29.728075474811362</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">29.727920339314988</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">29.727659280073677</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">19.723520660706676</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">19.718437942107229</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">19.713627280116647</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">19.709544291701</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">35.399367196532488</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">35.219500893686281</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">35.11798107003446</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">35.083992622950689</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">35.114825484632028</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">38.848623333107838</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">39.031408548734639</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">39.309409543510363</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">39.682879338789732</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">40.152074409508721</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">40.716976371724009</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">41.284338082047533</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">42.037112182682158</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">45.582952922353215</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">47.221217616563337</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">48.701343574203051</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">49.965399351248422</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733645337667848</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.501578718585364</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.4003198566308175</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.3666384867161909</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.3977760693784305</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.1476270948466905</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-9.3304076092443307</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-9.6083984062095062</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-9.9818661729353497</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-10.451086616479111</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.016065210969545</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-11.675941956855789</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-12.428977116731721</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-25.844413811371854</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-27.487761224181423</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-28.972697843811719</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.240836609272737</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878334076050813</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391507</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.024989926004155966</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208521</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.19773776002079221</Real>
+        <Real Name="Y">0.17085393481678812</Real>
+        <Real Name="Z">-0.38463693074579619</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.7416095442536688</Real>
+        <Real Name="Y">0.65998740974828218</Real>
+        <Real Name="Z">1.2586081794761004</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3694094522284488</Real>
+        <Real Name="Y">-0.24000957588948305</Real>
+        <Real Name="Z">0.43567003710236557</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19731478831949562</Real>
+        <Real Name="Y">0.14646793675608691</Real>
+        <Real Name="Z">-0.06773388800168062</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3809769463606123</Real>
+        <Real Name="Y">-0.57837565229454591</Real>
+        <Real Name="Z">0.2150108590146487</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.9348546934472659</Real>
+        <Real Name="Y">-0.90308662180745947</Real>
+        <Real Name="Z">0.95776443807868572</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.01931113382977933</Real>
+        <Real Name="Y">-0.34060637496946677</Real>
+        <Real Name="Z">-0.3093674186763401</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53589763839885385</Real>
+        <Real Name="Y">-2.6701745377290518</Real>
+        <Real Name="Z">0.21038828048600336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.076134731022213561</Real>
+        <Real Name="Y">-2.1539492358279233</Real>
+        <Real Name="Z">0.10673155295719959</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.012962816014384404</Real>
+        <Real Name="Y">0.24682864399281981</Real>
+        <Real Name="Z">0.11953460913784721</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53758870683866</Real>
+        <Real Name="Y">-0.39684400839013351</Real>
+        <Real Name="Z">-0.44394497510288983</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22745026213327166</Real>
+        <Real Name="Y">0.095898030227100278</Real>
+        <Real Name="Z">1.1265590422294318</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.062451414618209272</Real>
+        <Real Name="Y">0.16304349124075279</Real>
+        <Real Name="Z">0.54990545422288384</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.52785782492259303</Real>
+        <Real Name="Y">0.51248302446975491</Real>
+        <Real Name="Z">0.031794800751745109</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.0415018988184594</Real>
+        <Real Name="Y">-0.46201033728093577</Real>
+        <Real Name="Z">-2.433586772428868</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959197195</Real>
+        <Real Name="Y">10.126334215507057</Real>
+        <Real Name="Z">-383.92444636520236</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773661</Real>
+        <Real Name="Y">8.7835602768708725</Real>
+        <Real Name="Z">109.9816220785615</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818248</Real>
+        <Real Name="Y">125.90227601095721</Real>
+        <Real Name="Z">223.10402606189848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90645105417968</Real>
+        <Real Name="Y">-91.873016441468636</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733345</Real>
+        <Real Name="Y">82.504344401698219</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041522</Real>
+        <Real Name="Y">45.329959216167921</Real>
+        <Real Name="Z">-56.291380508471406</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448889</Real>
+        <Real Name="Y">-204.77938512046128</Real>
+        <Real Name="Z">21.69507028656227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013894</Real>
+        <Real Name="Y">47.599503809699016</Real>
+        <Real Name="Z">-24.246658126595378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564434752</Real>
+        <Real Name="Y">-23.593576368970389</Real>
+        <Real Name="Z">144.65217639452089</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0093734982386991864</Real>
+        <Real Name="Y">0.59856163528510387</Real>
+        <Real Name="Z">0.24248324186672551</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8573337799754703</Real>
+        <Real Name="Y">0.68931678292250642</Real>
+        <Real Name="Z">0.2694465414090747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.047422085808271001</Real>
+        <Real Name="Y">0.6051822488309595</Real>
+        <Real Name="Z">0.1549001906511126</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97578466355320015</Real>
+        <Real Name="Y">0.6356658870010774</Real>
+        <Real Name="Z">1.5689227086209687</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94874631575329449</Real>
+        <Real Name="Y">0.6159582116026181</Real>
+        <Real Name="Z">1.65860466711118</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.93035426616110495</Real>
+        <Real Name="Y">0.71715364631645973</Real>
+        <Real Name="Z">1.5475184456214093</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.395056599037884</Real>
+        <Real Name="Y">0.44926290271674929</Real>
+        <Real Name="Z">1.17723707031792</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3331386567962746</Real>
+        <Real Name="Y">0.50007577531725911</Real>
+        <Real Name="Z">1.2296445011521884</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3442051615400605</Real>
+        <Real Name="Y">0.42015764379327891</Real>
+        <Real Name="Z">1.1015447086993111</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6459057244761477</Real>
+        <Real Name="Y">0.30885820934055963</Real>
+        <Real Name="Z">0.30255112004985607</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7090019986380793</Real>
+        <Real Name="Y">0.32959262815430224</Real>
+        <Real Name="Z">0.23362171802620285</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6158395318597301</Real>
+        <Real Name="Y">0.2203965292595447</Real>
+        <Real Name="Z">0.28174550497131651</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7704918340624247</Real>
+        <Real Name="Y">0.39013372267850022</Real>
+        <Real Name="Z">0.022931438475633566</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7175300345064066</Real>
+        <Real Name="Y">0.42047844009889535</Real>
+        <Real Name="Z">1.8112583772855251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8182588609235415</Real>
+        <Real Name="Y">0.46790434078986148</Real>
+        <Real Name="Z">0.051782097106346098</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.53741338910671044</Real>
+        <Real Name="Y">-0.17440937166116255</Real>
+        <Real Name="Z">-0.2547911229013185</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4669797090410666</Real>
+        <Real Name="Y">-0.21006115177454826</Real>
+        <Real Name="Z">0.35129960275783995</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.34010858380637876</Real>
+        <Real Name="Y">0.013964429755924605</Real>
+        <Real Name="Z">-0.32626635622710665</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10024356493533586</Real>
+        <Real Name="Y">0.592149087314364</Real>
+        <Real Name="Z">-0.035548424327033486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.26560030810769247</Real>
+        <Real Name="Y">0.095124965791290053</Real>
+        <Real Name="Z">-0.25506865184449912</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8684393689551499</Real>
+        <Real Name="Y">1.846555932134436</Real>
+        <Real Name="Z">0.98709669132404765</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24160498647497813</Real>
+        <Real Name="Y">0.29004541339066625</Real>
+        <Real Name="Z">0.408367827251985</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.57847140415210874</Real>
+        <Real Name="Y">2.7069673734208943</Real>
+        <Real Name="Z">-0.96611865119475604</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.80598040805065774</Real>
+        <Real Name="Y">-1.2365297500252259</Real>
+        <Real Name="Z">1.374524323219247</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10733319907819175</Real>
+        <Real Name="Y">-0.54855341559918069</Real>
+        <Real Name="Z">0.040495799879870668</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.52276489599853915</Real>
+        <Real Name="Y">0.54259499716811865</Real>
+        <Real Name="Z">0.74899636696663507</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.7292912649519114</Real>
+        <Real Name="Y">-1.5136372548734536</Real>
+        <Real Name="Z">0.35486485726264155</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96180250383623644</Real>
+        <Real Name="Y">-0.27451148958554011</Real>
+        <Real Name="Z">-0.26788541393311655</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1517047025306331</Real>
+        <Real Name="Y">0.67821324801382032</Real>
+        <Real Name="Z">-1.3939065059892712</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.30998641104202179</Real>
+        <Real Name="Y">-1.0934236920041984</Real>
+        <Real Name="Z">0.86040741863927583</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">19.527345073699593</Real>
+        <Real Name="Y">-58.16505865561922</Real>
+        <Real Name="Z">-384.15079921744945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.739093058336771</Real>
+        <Real Name="Y">21.560861427644369</Real>
+        <Real Name="Z">103.61374336806139</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">142.32809279191051</Real>
+        <Real Name="Y">174.48941972643166</Real>
+        <Real Name="Z">227.80771401642835</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.362546732736362</Real>
+        <Real Name="Y">-8.2558162802596016</Real>
+        <Real Name="Z">-39.795401368534627</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.627443811303472</Real>
+        <Real Name="Y">-12.122867903312033</Real>
+        <Real Name="Z">-23.771086304570368</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3952578375634701</Real>
+        <Real Name="Y">6.6991300565362621</Real>
+        <Real Name="Z">14.510778532263224</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.681016239373278</Real>
+        <Real Name="Y">-9.2137405008536177</Real>
+        <Real Name="Z">-32.586235410352486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.290230264638467</Real>
+        <Real Name="Y">4.9485840990756991</Real>
+        <Real Name="Z">27.300494707667866</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.985518681211182</Real>
+        <Real Name="Y">17.944710528813292</Real>
+        <Real Name="Z">54.341449843526398</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-256.06820252061925</Real>
+        <Real Name="Y">-98.979082153579895</Real>
+        <Real Name="Z">270.96602349566331</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">160.93966732948999</Real>
+        <Real Name="Y">76.923989760848045</Real>
+        <Real Name="Z">-290.5715679651974</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.409296746549074</Real>
+        <Real Name="Y">63.97343745854694</Real>
+        <Real Name="Z">-79.816412654382034</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22495896457724029</Real>
+        <Real Name="Y">-166.63504452801078</Real>
+        <Real Name="Z">53.203397672939445</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-39.816577995971862</Real>
+        <Real Name="Y">25.882665428297543</Real>
+        <Real Name="Z">-18.801447127352446</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-101.35556940214406</Real>
+        <Real Name="Y">-39.051188464558692</Real>
+        <Real Name="Z">117.74934841128874</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070787995366681259</Real>
+        <Real Name="Y">0.59985143649681216</Real>
+        <Real Name="Z">0.23216740456238558</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0052211586376703836</Real>
+        <Real Name="Y">0.67791753130616239</Real>
+        <Real Name="Z">0.28752580420966162</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.081287366187574914</Real>
+        <Real Name="Y">0.61389285075322253</Real>
+        <Real Name="Z">0.17336055358992289</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.973346257165707</Real>
+        <Real Name="Y">0.63034414069527134</Real>
+        <Real Name="Z">1.5736557085925051</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94112496294910519</Real>
+        <Real Name="Y">0.57215320986956753</Real>
+        <Real Name="Z">1.6424882747850065</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90216144215769656</Real>
+        <Real Name="Y">0.6928120908636386</Real>
+        <Real Name="Z">1.5597706189623497</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959581053509376</Real>
+        <Real Name="Y">0.44665492887276648</Real>
+        <Real Name="Z">1.1631968523302278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3336974785194617</Real>
+        <Real Name="Y">0.47016044849785593</Real>
+        <Real Name="Z">1.2319967309180986</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3417646250865736</Real>
+        <Real Name="Y">0.43266026720368367</Real>
+        <Real Name="Z">1.0855467747925758</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6414230941153518</Real>
+        <Real Name="Y">0.31911231123270861</Real>
+        <Real Name="Z">0.3126719852884377</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.704079399269697</Real>
+        <Real Name="Y">0.34990901952528514</Real>
+        <Real Name="Z">0.24718863944579433</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6264625623714628</Real>
+        <Real Name="Y">0.22726769232372507</Real>
+        <Real Name="Z">0.29024283311089522</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.779841667898665</Real>
+        <Real Name="Y">0.39102509070509989</Real>
+        <Real Name="Z">0.024174026133215763</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6904250018612108</Real>
+        <Real Name="Y">0.42115363326866662</Real>
+        <Real Name="Z">0.0080728101002145447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8171091415281677</Real>
+        <Real Name="Y">0.4567755031166324</Real>
+        <Real Name="Z">0.082913596075354021</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.17446856887434514</Real>
+        <Real Name="Y">0.084341771366442539</Real>
+        <Real Name="Z">-0.96273554398462191</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67589102600566464</Real>
+        <Real Name="Y">-2.0324990359223176</Real>
+        <Real Name="Z">2.0392471556783121</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5507812568052803</Real>
+        <Real Name="Y">0.16609876961931874</Real>
+        <Real Name="Z">2.0554628365010164</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.12015782983138884</Real>
+        <Real Name="Y">-0.056412558962477204</Real>
+        <Real Name="Z">0.30130077199896282</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20846861816102458</Real>
+        <Real Name="Y">-2.4929476065115517</Real>
+        <Real Name="Z">-1.7998809549051307</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.75786215718447514</Real>
+        <Real Name="Y">-0.56873572052142107</Real>
+        <Real Name="Z">1.2657228393214597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.075791971326249014</Real>
+        <Real Name="Y">-0.021385234136078443</Real>
+        <Real Name="Z">-0.67195480897883408</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43282607657753164</Real>
+        <Real Name="Y">-0.37385176800754838</Real>
+        <Real Name="Z">-0.091259198326439833</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.6712323071463322</Real>
+        <Real Name="Y">0.16397465043878043</Real>
+        <Real Name="Z">-0.28979247048229584</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.2463126402568126</Real>
+        <Real Name="Y">0.35383617114975885</Real>
+        <Real Name="Z">0.60026122326327147</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.33669209698506686</Real>
+        <Real Name="Y">1.4335547604853107</Real>
+        <Real Name="Z">1.6658863873252632</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3137691773310407</Real>
+        <Real Name="Y">-0.11593786715502134</Real>
+        <Real Name="Z">0.81632075971390483</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.02924319798006926</Real>
+        <Real Name="Y">0.062146573516938336</Real>
+        <Real Name="Z">0.020170123885872002</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.60699039260708709</Real>
+        <Real Name="Y">-0.43418682173729439</Real>
+        <Real Name="Z">2.6246991595035931</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.279029509244762</Real>
+        <Real Name="Y">-2.4519912366005006</Real>
+        <Real Name="Z">3.029966467917649</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-161.52835605563649</Real>
+        <Real Name="Y">-312.79324839644721</Real>
+        <Real Name="Z">-381.68331946386036</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.219261166460022</Real>
+        <Real Name="Y">67.593038651422944</Real>
+        <Real Name="Z">100.1855461803313</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">171.02543393737827</Real>
+        <Real Name="Y">144.8605124822634</Real>
+        <Real Name="Z">75.640956113225371</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.137801776476678</Real>
+        <Real Name="Y">-15.058447702140271</Real>
+        <Real Name="Z">-36.553416324259928</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.886261556429105</Real>
+        <Real Name="Y">-7.1101356172793881</Real>
+        <Real Name="Z">-24.518132946504572</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.156291749857246</Real>
+        <Real Name="Y">7.3981869106141538</Real>
+        <Real Name="Z">12.134216567249126</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.2018021610251</Real>
+        <Real Name="Y">-17.564566211145149</Real>
+        <Real Name="Z">-31.302368177957071</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.378319942927973</Real>
+        <Real Name="Y">14.915678367104487</Real>
+        <Real Name="Z">25.233734743486117</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.691253801145663</Real>
+        <Real Name="Y">17.419284252846161</Real>
+        <Real Name="Z">55.005966137986334</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-182.95815907903989</Real>
+        <Real Name="Y">1.8337491536482844</Real>
+        <Real Name="Z">101.7940269753081</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">150.07368963791046</Real>
+        <Real Name="Y">-30.871780810832917</Real>
+        <Real Name="Z">-84.719581227693766</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.021190951224483</Real>
+        <Real Name="Y">10.203919197770702</Real>
+        <Real Name="Z">-48.898706363062814</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-50.969778603902711</Real>
+        <Real Name="Y">-306.68444279784342</Real>
+        <Real Name="Z">-20.453830651952273</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-20.454026566894271</Real>
+        <Real Name="Y">115.88292394226572</Real>
+        <Real Name="Z">-0.45533784146013545</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">7.5707446125000928</Real>
+        <Real Name="Y">309.97532857775258</Real>
+        <Real Name="Z">258.5902462791646</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceVelocityVerlet_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_mdvv_NoseHoover_No_4Ranks_1RanksPerSimulation_s.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceVelocityVerlet_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_mdvv_NoseHoover_No_4Ranks_1RanksPerSimulation_s.xml
new file mode 100644 (file)
index 0000000..cb813bc
--- /dev/null
@@ -0,0 +1,3310 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Replica exchange in temperature
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">19.745632</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">19.74589</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">19.746155</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">19.746382</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">19.746197</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">18.483475</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">18.483318</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">18.483021</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">18.482742</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">18.482128</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">18.495646</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">18.494614</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">18.493309</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">25.760088</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">25.759424</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">25.758902</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">25.761225</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.41905</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.849567</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.412399</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">31.126263</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">31.995508</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">28.426037</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">28.889349</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.499783</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">30.255215</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">31.151909</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">32.132118</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">33.232262</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">34.401196</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">37.953979</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">38.59304</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">39.320549</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">40.124847</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.089899</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.652467</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.366102</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.235532</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.9249191</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.388389</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-10.99912</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-11.75483</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-12.652139</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-13.61883</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-14.674376</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-15.844617</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-12.232071</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-12.871797</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-13.599827</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-14.401801</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13816734</Real>
+        <Real Name="Y">-0.081793927</Real>
+        <Real Name="Z">-0.55161422</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6817961</Real>
+        <Real Name="Y">0.11154398</Real>
+        <Real Name="Z">0.086538419</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50566709</Real>
+        <Real Name="Y">-0.26824209</Real>
+        <Real Name="Z">-0.36989284</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.082187586</Real>
+        <Real Name="Y">-0.035856467</Real>
+        <Real Name="Z">0.27249211</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0691695</Real>
+        <Real Name="Y">-2.7009876</Real>
+        <Real Name="Z">-0.45056438</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.99486995</Real>
+        <Real Name="Y">-0.45276091</Real>
+        <Real Name="Z">1.1449357</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.047058146</Real>
+        <Real Name="Y">-0.02711791</Real>
+        <Real Name="Z">-0.68353546</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.052919496</Real>
+        <Real Name="Y">-0.42434022</Real>
+        <Real Name="Z">-0.38322306</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25128448</Real>
+        <Real Name="Y">0.072380684</Real>
+        <Real Name="Z">-0.58356738</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20092826</Real>
+        <Real Name="Y">0.39382076</Real>
+        <Real Name="Z">0.71723521</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21974827</Real>
+        <Real Name="Y">1.2084097</Real>
+        <Real Name="Z">0.8629939</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3874834</Real>
+        <Real Name="Y">-0.64634955</Real>
+        <Real Name="Z">0.87320864</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21414684</Real>
+        <Real Name="Y">-0.08829473</Real>
+        <Real Name="Z">-0.037485842</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8251648</Real>
+        <Real Name="Y">0.9371016</Real>
+        <Real Name="Z">2.5717969</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38095254</Real>
+        <Real Name="Y">-0.38837013</Real>
+        <Real Name="Z">0.73821282</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0031893018</Real>
+        <Real Name="Y">0.59434432</Real>
+        <Real Name="Z">0.24354731</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8501855</Real>
+        <Real Name="Y">0.6845699</Real>
+        <Real Name="Z">0.27173859</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.058269698</Real>
+        <Real Name="Y">0.60241038</Real>
+        <Real Name="Z">0.16567943</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97851342</Real>
+        <Real Name="Y">0.63000739</Real>
+        <Real Name="Z">1.5703751</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96153498</Real>
+        <Real Name="Y">0.62398744</Real>
+        <Real Name="Z">1.6643847</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92785978</Real>
+        <Real Name="Y">0.70597959</Real>
+        <Real Name="Z">1.5416566</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3933256</Real>
+        <Real Name="Y">0.44734201</Real>
+        <Real Name="Z">1.1773221</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3333508</Real>
+        <Real Name="Y">0.47715145</Real>
+        <Real Name="Z">1.2457089</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3361613</Real>
+        <Real Name="Y">0.41480547</Real>
+        <Real Name="Z">1.1077814</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6470577</Real>
+        <Real Name="Y">0.31561404</Real>
+        <Real Name="Z">0.29912776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7055428</Real>
+        <Real Name="Y">0.3323828</Real>
+        <Real Name="Z">0.22523187</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5972911</Real>
+        <Real Name="Y">0.2380591</Real>
+        <Real Name="Z">0.27322704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.776569</Real>
+        <Real Name="Y">0.39600569</Real>
+        <Real Name="Z">0.022771658</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7121446</Real>
+        <Real Name="Y">0.40967101</Real>
+        <Real Name="Z">1.8153689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8070723</Real>
+        <Real Name="Y">0.4840048</Real>
+        <Real Name="Z">0.044863001</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.23468855</Real>
+        <Real Name="Y">-0.68629974</Real>
+        <Real Name="Z">-0.13430253</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.59493577</Real>
+        <Real Name="Y">-0.79239666</Real>
+        <Real Name="Z">0.64856076</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6637363</Real>
+        <Real Name="Y">-0.61265165</Real>
+        <Real Name="Z">1.2161908</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43755782</Real>
+        <Real Name="Y">-0.11889217</Real>
+        <Real Name="Z">0.15943496</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.427763</Real>
+        <Real Name="Y">1.0155027</Real>
+        <Real Name="Z">0.41091067</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5249478</Real>
+        <Real Name="Y">0.5814864</Real>
+        <Real Name="Z">0.094286859</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.48144418</Real>
+        <Real Name="Y">0.037885863</Real>
+        <Real Name="Z">0.3979575</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.51542902</Real>
+        <Real Name="Y">0.10027331</Real>
+        <Real Name="Z">1.2450147</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.4590386</Real>
+        <Real Name="Y">-1.9433109</Real>
+        <Real Name="Z">2.1285224</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24744625</Real>
+        <Real Name="Y">0.31773919</Real>
+        <Real Name="Z">-0.37827015</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.28410193</Real>
+        <Real Name="Y">0.83957613</Real>
+        <Real Name="Z">-0.23084193</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39101702</Real>
+        <Real Name="Y">0.3905513</Real>
+        <Real Name="Z">-0.87215453</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19358611</Real>
+        <Real Name="Y">0.45157853</Real>
+        <Real Name="Z">-0.27734312</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.40642199</Real>
+        <Real Name="Y">-0.52459109</Real>
+        <Real Name="Z">-1.025871</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7825418</Real>
+        <Real Name="Y">0.91365057</Real>
+        <Real Name="Z">0.076027393</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-2.4434814</Real>
+        <Real Name="Y">62.72998</Real>
+        <Real Name="Z">-371.99356</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.3937569</Real>
+        <Real Name="Y">0.95398712</Real>
+        <Real Name="Z">111.74129</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.47522</Real>
+        <Real Name="Y">65.010971</Real>
+        <Real Name="Z">209.84692</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.551514</Real>
+        <Real Name="Y">-18.859653</Real>
+        <Real Name="Z">-38.892166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.698017</Real>
+        <Real Name="Y">-9.5334778</Real>
+        <Real Name="Z">-24.56702</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4322662</Real>
+        <Real Name="Y">10.518484</Real>
+        <Real Name="Z">12.983639</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.547226</Real>
+        <Real Name="Y">-7.2440834</Real>
+        <Real Name="Z">-33.315613</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-56.921051</Real>
+        <Real Name="Y">11.272854</Real>
+        <Real Name="Z">-15.036118</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.61528</Real>
+        <Real Name="Y">18.864565</Real>
+        <Real Name="Z">56.460255</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-309.14212</Real>
+        <Real Name="Y">-123.38241</Real>
+        <Real Name="Z">254.6972</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.8886</Real>
+        <Real Name="Y">108.01786</Real>
+        <Real Name="Z">-280.18073</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">113.8797</Real>
+        <Real Name="Y">55.284653</Real>
+        <Real Name="Z">-57.669312</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-57.349487</Real>
+        <Real Name="Y">-236.3429</Real>
+        <Real Name="Z">-0.27481079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">7.5450287</Real>
+        <Real Name="Y">44.614109</Real>
+        <Real Name="Z">16.347076</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-105.28783</Real>
+        <Real Name="Y">18.095032</Real>
+        <Real Name="Z">159.85294</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0033644733</Real>
+        <Real Name="Y">0.60656196</Real>
+        <Real Name="Z">0.23556635</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.025851609</Real>
+        <Real Name="Y">0.66696054</Real>
+        <Real Name="Z">0.30633825</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.084186964</Real>
+        <Real Name="Y">0.597606</Real>
+        <Real Name="Z">0.18507048</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9717015</Real>
+        <Real Name="Y">0.63342917</Real>
+        <Real Name="Z">1.5675744</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97524953</Real>
+        <Real Name="Y">0.60608947</Real>
+        <Real Name="Z">1.6592382</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.88966626</Real>
+        <Real Name="Y">0.68220091</Real>
+        <Real Name="Z">1.5602357</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959295</Real>
+        <Real Name="Y">0.44153607</Real>
+        <Real Name="Z">1.1692213</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3337047</Real>
+        <Real Name="Y">0.43590724</Real>
+        <Real Name="Z">1.2417383</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3518766</Real>
+        <Real Name="Y">0.39781615</Real>
+        <Real Name="Z">1.09635</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6451682</Real>
+        <Real Name="Y">0.316836</Real>
+        <Real Name="Z">0.30363098</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.695092</Real>
+        <Real Name="Y">0.33270246</Real>
+        <Real Name="Z">0.22351736</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.599111</Real>
+        <Real Name="Y">0.23452906</Real>
+        <Real Name="Z">0.28730261</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7765924</Real>
+        <Real Name="Y">0.39377502</Real>
+        <Real Name="Z">0.033312578</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7162952</Real>
+        <Real Name="Y">0.42399055</Real>
+        <Real Name="Z">1.8274491</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8499357</Real>
+        <Real Name="Y">0.4551526</Real>
+        <Real Name="Z">0.029327367</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.12387047</Real>
+        <Real Name="Y">0.6729961</Real>
+        <Real Name="Z">-0.61832911</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.58814228</Real>
+        <Real Name="Y">-3.5232332</Real>
+        <Real Name="Z">2.8153234</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7111278</Real>
+        <Real Name="Y">-1.776723</Real>
+        <Real Name="Z">2.3566802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20627145</Real>
+        <Real Name="Y">0.14808135</Real>
+        <Real Name="Z">-0.11472952</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5503843</Real>
+        <Real Name="Y">-0.49098408</Real>
+        <Real Name="Z">-0.3733322</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2811742</Real>
+        <Real Name="Y">-1.440352</Real>
+        <Real Name="Z">1.3445667</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.14122541</Real>
+        <Real Name="Y">-0.36388803</Real>
+        <Real Name="Z">-0.28508511</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97007847</Real>
+        <Real Name="Y">-2.2081139</Real>
+        <Real Name="Z">0.52534193</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.27371642</Real>
+        <Real Name="Y">-1.8168646</Real>
+        <Real Name="Z">0.33579904</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.015515367</Real>
+        <Real Name="Y">0.22205195</Real>
+        <Real Name="Z">0.088888504</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.62208056</Real>
+        <Real Name="Y">1.1765653</Real>
+        <Real Name="Z">-0.11939625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.61082685</Real>
+        <Real Name="Y">-0.060174424</Real>
+        <Real Name="Z">-0.16767141</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.11575386</Real>
+        <Real Name="Y">-0.0025695397</Real>
+        <Real Name="Z">0.4759036</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.30012918</Real>
+        <Real Name="Y">0.81263608</Real>
+        <Real Name="Z">0.46935675</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.0393171</Real>
+        <Real Name="Y">-1.4131314</Real>
+        <Real Name="Z">0.0091331955</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">160.07199</Real>
+        <Real Name="Y">112.47925</Real>
+        <Real Name="Z">-266.13443</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-43.177151</Real>
+        <Real Name="Y">-34.57383</Real>
+        <Real Name="Z">74.962852</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.696449</Real>
+        <Real Name="Y">40.519547</Real>
+        <Real Name="Z">191.5795</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">9.5896072</Real>
+        <Real Name="Y">-26.792961</Real>
+        <Real Name="Z">-24.444122</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.347424</Real>
+        <Real Name="Y">-5.3436279</Real>
+        <Real Name="Z">-27.200169</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">26.806244</Real>
+        <Real Name="Y">-8.7929573</Real>
+        <Real Name="Z">-23.447784</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.587135</Real>
+        <Real Name="Y">-17.175571</Real>
+        <Real Name="Z">-27.862946</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-52.328506</Real>
+        <Real Name="Y">17.431728</Real>
+        <Real Name="Z">-21.380939</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.984962</Real>
+        <Real Name="Y">41.51384</Real>
+        <Real Name="Z">83.027397</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-263.7923</Real>
+        <Real Name="Y">-180.21286</Real>
+        <Real Name="Z">380.17618</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">237.55289</Real>
+        <Real Name="Y">180.88362</Real>
+        <Real Name="Z">-389.448</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">95.071304</Real>
+        <Real Name="Y">79.673882</Real>
+        <Real Name="Z">-88.260849</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.586899</Real>
+        <Real Name="Y">-429.77893</Real>
+        <Real Name="Z">5.3737793</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.134954</Real>
+        <Real Name="Y">112.49574</Real>
+        <Real Name="Z">38.137917</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-102.98824</Real>
+        <Real Name="Y">117.67311</Real>
+        <Real Name="Z">94.921539</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Replica exchange in temperature
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">18.488668</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">18.488764</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">18.483406</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">18.483517</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">18.483372</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">19.745907</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">19.745258</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">19.744041</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">19.742239</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">25.723606</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">25.761114</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">25.760836</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">25.760515</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">18.491682</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">18.489893</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">18.487719</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">18.485489</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">28.162086</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">28.003685</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">27.924997</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">27.943874</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">28.110786</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">33.022438</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.20639</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">35.542313</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.019321</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">36.213757</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">36.578102</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">36.934303</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">37.401909</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">35.670082</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">37.021706</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">38.43576</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">39.889198</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.4972782</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.4239483</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.4427147</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.6097717</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.262753</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.447354</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-15.784492</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.263304</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-10.498089</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-10.824926</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-11.211646</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-11.679573</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.115129</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-18.468542</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-19.884771</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-21.340439</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.21187809</Real>
+        <Real Name="Y">-0.73077357</Real>
+        <Real Name="Z">0.011171445</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.66853744</Real>
+        <Real Name="Y">-0.45353815</Real>
+        <Real Name="Z">-0.19972205</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.079818927</Real>
+        <Real Name="Y">-1.3654529</Real>
+        <Real Name="Z">0.097918585</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.44649071</Real>
+        <Real Name="Y">-0.12888828</Real>
+        <Real Name="Z">0.17260903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1362944</Real>
+        <Real Name="Y">1.224402</Real>
+        <Real Name="Z">0.58872867</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4191031</Real>
+        <Real Name="Y">0.66040111</Real>
+        <Real Name="Z">0.099715605</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.42277378</Real>
+        <Real Name="Y">0.039570879</Real>
+        <Real Name="Z">0.42216343</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.32221863</Real>
+        <Real Name="Y">0.031569872</Real>
+        <Real Name="Z">1.236218</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7650071</Real>
+        <Real Name="Y">-2.0605228</Real>
+        <Real Name="Z">1.6261249</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2607744</Real>
+        <Real Name="Y">0.32039824</Real>
+        <Real Name="Z">-0.34791988</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.14843366</Real>
+        <Real Name="Y">0.34930536</Real>
+        <Real Name="Z">-0.43129006</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019823467</Real>
+        <Real Name="Y">0.52909756</Real>
+        <Real Name="Z">-0.45886597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15571988</Real>
+        <Real Name="Y">0.54546666</Real>
+        <Real Name="Z">-0.27451965</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26909682</Real>
+        <Real Name="Y">-0.7857343</Real>
+        <Real Name="Z">-1.2282431</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.93956846</Real>
+        <Real Name="Y">1.1439295</Real>
+        <Real Name="Z">-1.0687592</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.005989335</Real>
+        <Real Name="Y">0.59960419</Real>
+        <Real Name="Z">0.23895578</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8580334</Real>
+        <Real Name="Y">0.68791026</Real>
+        <Real Name="Z">0.27450904</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.061665207</Real>
+        <Real Name="Y">0.61092108</Real>
+        <Real Name="Z">0.16192043</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97423959</Real>
+        <Real Name="Y">0.630714</Real>
+        <Real Name="Z">1.5712928</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94446111</Real>
+        <Real Name="Y">0.59317052</Real>
+        <Real Name="Z">1.6541543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90863705</Real>
+        <Real Name="Y">0.69711077</Real>
+        <Real Name="Z">1.5500776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3964998</Real>
+        <Real Name="Y">0.4468289</Real>
+        <Real Name="Z">1.1685977</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3310622</Real>
+        <Real Name="Y">0.47334334</Real>
+        <Real Name="Z">1.2332292</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.346331</Real>
+        <Real Name="Y">0.43157807</Real>
+        <Real Name="Z">1.0885175</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6433228</Real>
+        <Real Name="Y">0.31616026</Real>
+        <Real Name="Z">0.30759373</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.702738</Real>
+        <Real Name="Y">0.33843592</Real>
+        <Real Name="Z">0.23592821</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6091882</Real>
+        <Real Name="Y">0.22976822</Real>
+        <Real Name="Z">0.2844947</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7792996</Real>
+        <Real Name="Y">0.39121339</Real>
+        <Real Name="Z">0.024520639</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6974192</Real>
+        <Real Name="Y">0.42101082</Real>
+        <Real Name="Z">1.8469568</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.818826</Real>
+        <Real Name="Y">0.47061008</Real>
+        <Real Name="Z">0.060522743</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11757857</Real>
+        <Real Name="Y">-0.019413065</Real>
+        <Real Name="Z">-0.72920591</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4907411</Real>
+        <Real Name="Y">-0.59907359</Real>
+        <Real Name="Z">1.0973756</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0630476</Real>
+        <Real Name="Y">0.41163054</Real>
+        <Real Name="Z">0.74016827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1024816</Real>
+        <Real Name="Y">-0.038517557</Real>
+        <Real Name="Z">0.28861734</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63113236</Real>
+        <Real Name="Y">-2.7178352</Real>
+        <Real Name="Z">-1.1153307</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.8655231</Real>
+        <Real Name="Y">-0.51105565</Real>
+        <Real Name="Z">1.1692337</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.060124025</Real>
+        <Real Name="Y">-0.022644211</Real>
+        <Real Name="Z">-0.67807311</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23030806</Real>
+        <Real Name="Y">-0.41628471</Real>
+        <Real Name="Z">-0.22253145</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46764436</Real>
+        <Real Name="Y">0.10964777</Real>
+        <Real Name="Z">-0.44796333</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22564596</Real>
+        <Real Name="Y">0.38080463</Real>
+        <Real Name="Z">0.66784263</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.0044132918</Real>
+        <Real Name="Y">1.4224596</Real>
+        <Real Name="Z">1.175034</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9458933</Real>
+        <Real Name="Y">-0.4794443</Real>
+        <Real Name="Z">0.6762405</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11255383</Real>
+        <Real Name="Y">-0.088987641</Real>
+        <Real Name="Z">-0.071537621</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1680025</Real>
+        <Real Name="Y">0.46199808</Real>
+        <Real Name="Z">2.9890139</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.083595261</Real>
+        <Real Name="Y">-1.034916</Real>
+        <Real Name="Z">2.2299013</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-64.500626</Real>
+        <Real Name="Y">-106.42625</Real>
+        <Real Name="Z">-417.21167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.19946671</Real>
+        <Real Name="Y">35.041435</Real>
+        <Real Name="Z">108.81183</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">177.60979</Real>
+        <Real Name="Y">150.50706</Real>
+        <Real Name="Z">171.79034</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.698997</Real>
+        <Real Name="Y">-14.331871</Real>
+        <Real Name="Z">-37.632751</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.75808</Real>
+        <Real Name="Y">-8.0142937</Real>
+        <Real Name="Z">-23.75906</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.2965736</Real>
+        <Real Name="Y">7.6706944</Real>
+        <Real Name="Z">12.782566</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.140564</Real>
+        <Real Name="Y">-14.3414</Real>
+        <Real Name="Z">-32.97974</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.400028</Real>
+        <Real Name="Y">12.111423</Real>
+        <Real Name="Z">27.164577</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.901039</Real>
+        <Real Name="Y">16.905447</Real>
+        <Real Name="Z">54.424404</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-258.07727</Real>
+        <Real Name="Y">-52.449753</Real>
+        <Real Name="Z">175.90768</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">212.87875</Real>
+        <Real Name="Y">26.473976</Real>
+        <Real Name="Z">-197.02203</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.675278</Real>
+        <Real Name="Y">33.0979</Real>
+        <Real Name="Z">-53.513733</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-59.61969</Real>
+        <Real Name="Y">-231.46796</Real>
+        <Real Name="Z">9.0249023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.945496</Real>
+        <Real Name="Y">75.056007</Real>
+        <Real Name="Z">-11.075592</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-78.220276</Real>
+        <Real Name="Y">70.167587</Real>
+        <Real Name="Z">213.28827</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0013531335</Real>
+        <Real Name="Y">0.58920771</Real>
+        <Real Name="Z">0.24168469</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8542038</Real>
+        <Real Name="Y">0.67610335</Real>
+        <Real Name="Z">0.28075707</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.075632811</Real>
+        <Real Name="Y">0.59753126</Real>
+        <Real Name="Z">0.18188864</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98197329</Real>
+        <Real Name="Y">0.62911886</Real>
+        <Real Name="Z">1.5716619</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97374845</Real>
+        <Real Name="Y">0.63131988</Real>
+        <Real Name="Z">1.6670024</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94047058</Real>
+        <Real Name="Y">0.71015537</Real>
+        <Real Name="Z">1.5421166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3892345</Real>
+        <Real Name="Y">0.44759905</Real>
+        <Real Name="Z">1.1804276</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3378572</Real>
+        <Real Name="Y">0.47843152</Real>
+        <Real Name="Z">1.2550737</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3264465</Real>
+        <Real Name="Y">0.3999463</Real>
+        <Real Name="Z">1.126121</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6489869</Real>
+        <Real Name="Y">0.3181335</Real>
+        <Real Name="Z">0.2959843</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7082592</Real>
+        <Real Name="Y">0.34106687</Real>
+        <Real Name="Z">0.22440794</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6021447</Real>
+        <Real Name="Y">0.24081704</Real>
+        <Real Name="Z">0.26451546</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7749718</Real>
+        <Real Name="Y">0.39931715</Real>
+        <Real Name="Z">0.020606142</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7158221</Real>
+        <Real Name="Y">0.40730283</Real>
+        <Real Name="Z">1.8078339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7887273</Real>
+        <Real Name="Y">0.48935497</Real>
+        <Real Name="Z">0.050039079</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.2109195</Real>
+        <Real Name="Y">-0.58442998</Real>
+        <Real Name="Z">-0.34199911</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.34982225</Real>
+        <Real Name="Y">-1.4080673</Real>
+        <Real Name="Z">1.6219079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4243124</Real>
+        <Real Name="Y">-0.81184566</Real>
+        <Real Name="Z">2.8998749</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42741495</Real>
+        <Real Name="Y">-0.10170297</Real>
+        <Real Name="Z">0.16605321</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5973116</Real>
+        <Real Name="Y">0.8208918</Real>
+        <Real Name="Z">0.24567911</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.623692</Real>
+        <Real Name="Y">0.45269495</Real>
+        <Real Name="Z">0.0062214565</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53943491</Real>
+        <Real Name="Y">0.024373578</Real>
+        <Real Name="Z">0.37948519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.58300233</Real>
+        <Real Name="Y">0.22376163</Real>
+        <Real Name="Z">1.0696774</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.94316745</Real>
+        <Real Name="Y">-1.7603476</Real>
+        <Real Name="Z">2.4123251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23510537</Real>
+        <Real Name="Y">0.31181404</Real>
+        <Real Name="Z">-0.40831196</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39282322</Real>
+        <Real Name="Y">1.3072559</Real>
+        <Real Name="Z">0.04123769</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.82522643</Real>
+        <Real Name="Y">0.31507075</Real>
+        <Real Name="Z">-1.2947247</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20182566</Real>
+        <Real Name="Y">0.38512203</Real>
+        <Real Name="Z">-0.25701323</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.5104714</Real>
+        <Real Name="Y">-0.0019376911</Real>
+        <Real Name="Z">-0.86134022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7659225</Real>
+        <Real Name="Y">0.30427396</Real>
+        <Real Name="Z">1.1886344</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-71.125137</Real>
+        <Real Name="Y">72.031601</Real>
+        <Real Name="Z">-362.29193</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.8456268</Real>
+        <Real Name="Y">-0.67694855</Real>
+        <Real Name="Z">111.86395</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">135.89732</Real>
+        <Real Name="Y">0.94975281</Real>
+        <Real Name="Z">136.34532</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.781425</Real>
+        <Real Name="Y">-23.784687</Real>
+        <Real Name="Z">-37.684967</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6875381</Real>
+        <Real Name="Y">7.1059074</Real>
+        <Real Name="Z">14.348648</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.3501778</Real>
+        <Real Name="Y">12.890226</Real>
+        <Real Name="Z">11.868824</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.772888</Real>
+        <Real Name="Y">-3.8449554</Real>
+        <Real Name="Z">-32.283424</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.248936</Real>
+        <Real Name="Y">9.0250053</Real>
+        <Real Name="Z">-18.11042</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.171524</Real>
+        <Real Name="Y">4.2360706</Real>
+        <Real Name="Z">18.127998</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-317.04019</Real>
+        <Real Name="Y">-134.54195</Real>
+        <Real Name="Z">277.22723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">244.71931</Real>
+        <Real Name="Y">104.75713</Real>
+        <Real Name="Z">-285.41748</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">118.9535</Real>
+        <Real Name="Y">61.360413</Real>
+        <Real Name="Z">-64.545029</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-73.076965</Real>
+        <Real Name="Y">-317.71033</Real>
+        <Real Name="Z">-34.091003</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.022362</Real>
+        <Real Name="Y">56.775246</Real>
+        <Real Name="Z">25.171326</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-31.291992</Real>
+        <Real Name="Y">151.42758</Real>
+        <Real Name="Z">239.47101</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 2">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Replica exchange in temperature
+Replica exchange interval: 4
+Replica random seed: 98715
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl 1 <-> 2  [ not checked ]
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.728209</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.728306</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">29.728102</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">29.728085</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">29.728073</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">25.724579</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">25.724363</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">25.724159</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">25.723894</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">19.739889</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">19.736694</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">19.732742</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">19.728338</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">29.72732</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">29.726776</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">29.691196</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">29.690331</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">39.401627</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">39.074314</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">38.872932</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">38.768845</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">38.76099</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">35.208439</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">35.36425</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">35.582607</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">35.864933</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">38.61932</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">40.315842</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">42.0746</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">43.847633</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">42.880569</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">43.809803</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">44.771057</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">45.750961</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.3731728</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.1719952</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.0679255</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.0600815</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.4917994</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-9.6478252</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-9.8663874</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-10.148977</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-18.865652</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-20.565369</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-22.326839</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.104277</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-13.272773</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-14.202551</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-15.199385</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-16.180155</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.55933756</Real>
+        <Real Name="Y">-0.19533345</Real>
+        <Real Name="Z">-0.12442181</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5601319</Real>
+        <Real Name="Y">0.14590967</Real>
+        <Real Name="Z">-0.45402375</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2402388</Real>
+        <Real Name="Y">-1.174126</Real>
+        <Real Name="Z">-1.2377422</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.101867</Real>
+        <Real Name="Y">0.57542717</Real>
+        <Real Name="Z">0.0047707758</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.36213741</Real>
+        <Real Name="Y">0.14107965</Real>
+        <Real Name="Z">-0.19176498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6918294</Real>
+        <Real Name="Y">2.1823173</Real>
+        <Real Name="Z">0.67191356</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22502765</Real>
+        <Real Name="Y">0.27110839</Real>
+        <Real Name="Z">0.38807479</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.20024879</Real>
+        <Real Name="Y">3.0906291</Real>
+        <Real Name="Z">-0.5092907</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.44380179</Real>
+        <Real Name="Y">-1.4298763</Real>
+        <Real Name="Z">0.85415882</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11843175</Real>
+        <Real Name="Y">-0.50488758</Real>
+        <Real Name="Z">0.09043847</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67606801</Real>
+        <Real Name="Y">-0.050571993</Real>
+        <Real Name="Z">0.62218434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.2344503</Real>
+        <Real Name="Y">-1.9401455</Real>
+        <Real Name="Z">0.46394107</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.90616888</Real>
+        <Real Name="Y">-0.1988364</Real>
+        <Real Name="Z">-0.24409088</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.86349922</Real>
+        <Real Name="Y">0.70307297</Real>
+        <Real Name="Z">-1.8507771</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.4000614</Real>
+        <Real Name="Y">-0.83463943</Real>
+        <Real Name="Z">-0.19029823</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.003531713</Real>
+        <Real Name="Y">0.60225636</Real>
+        <Real Name="Z">0.24029867</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.010740573</Real>
+        <Real Name="Y">0.68678612</Real>
+        <Real Name="Z">0.28462774</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.066951171</Real>
+        <Real Name="Y">0.60718203</Real>
+        <Real Name="Z">0.16877225</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97336572</Real>
+        <Real Name="Y">0.63220835</Real>
+        <Real Name="Z">1.5684025</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96288466</Real>
+        <Real Name="Y">0.61037964</Real>
+        <Real Name="Z">1.6610092</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90154773</Real>
+        <Real Name="Y">0.69266886</Real>
+        <Real Name="Z">1.5497203</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3967522</Real>
+        <Real Name="Y">0.44432938</Real>
+        <Real Name="Z">1.171587</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3287634</Real>
+        <Real Name="Y">0.45539266</Real>
+        <Real Name="Z">1.2380507</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3497461</Real>
+        <Real Name="Y">0.41367811</Real>
+        <Real Name="Z">1.0940418</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450934</Real>
+        <Real Name="Y">0.31500122</Real>
+        <Real Name="Z">0.30288434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6996372</Real>
+        <Real Name="Y">0.32688415</Real>
+        <Real Name="Z">0.22512776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5957758</Real>
+        <Real Name="Y">0.23481038</Real>
+        <Real Name="Z">0.28557745</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7773944</Real>
+        <Real Name="Y">0.3932426</Real>
+        <Real Name="Z">0.029315567</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7133342</Real>
+        <Real Name="Y">0.41887948</Real>
+        <Real Name="Z">1.8250328</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.837918</Real>
+        <Real Name="Y">0.46724498</Real>
+        <Real Name="Z">0.034096453</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.13406804</Real>
+        <Real Name="Y">0.40010208</Real>
+        <Real Name="Z">-0.54057634</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9294529</Real>
+        <Real Name="Y">-1.3939143</Real>
+        <Real Name="Z">2.3821855</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3350146</Real>
+        <Real Name="Y">-0.64167333</Real>
+        <Real Name="Z">1.5769132</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20719378</Real>
+        <Real Name="Y">0.15462494</Real>
+        <Real Name="Z">-0.092222393</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5206006</Real>
+        <Real Name="Y">-0.57207513</Real>
+        <Real Name="Z">-0.067967258</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.6742868</Real>
+        <Real Name="Y">-1.1739855</Real>
+        <Real Name="Z">1.2478319</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.06263756</Real>
+        <Real Name="Y">-0.33863607</Real>
+        <Real Name="Z">-0.30384478</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.236463</Real>
+        <Real Name="Y">-2.6090043</Real>
+        <Real Name="Z">0.38003564</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.20925702</Real>
+        <Real Name="Y">-2.1101985</Real>
+        <Real Name="Z">0.23158427</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0064902971</Real>
+        <Real Name="Y">0.23696053</Real>
+        <Real Name="Z">0.097191036</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.52638423</Real>
+        <Real Name="Y">0.27573752</Real>
+        <Real Name="Z">-0.27067754</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21234918</Real>
+        <Real Name="Y">0.0048629344</Real>
+        <Real Name="Z">0.58599234</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.086214408</Real>
+        <Real Name="Y">0.12506315</Real>
+        <Real Name="Z">0.52370387</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43918082</Real>
+        <Real Name="Y">0.50833684</Real>
+        <Real Name="Z">0.16449352</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9945886</Real>
+        <Real Name="Y">-1.4641769</Real>
+        <Real Name="Z">-1.2186911</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">118.58987</Real>
+        <Real Name="Y">88.077011</Real>
+        <Real Name="Z">-316.90012</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-30.395176</Real>
+        <Real Name="Y">-18.367523</Real>
+        <Real Name="Z">87.898445</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">60.379311</Real>
+        <Real Name="Y">76.797607</Real>
+        <Real Name="Z">219.39142</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.841476</Real>
+        <Real Name="Y">-21.730122</Real>
+        <Real Name="Z">-33.096306</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.000034</Real>
+        <Real Name="Y">-6.9536667</Real>
+        <Real Name="Z">-24.68042</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6338348</Real>
+        <Real Name="Y">9.5452271</Real>
+        <Real Name="Z">10.576893</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">32.477196</Real>
+        <Real Name="Y">-13.997688</Real>
+        <Real Name="Z">-31.190788</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.444714</Real>
+        <Real Name="Y">13.431238</Real>
+        <Real Name="Z">24.938564</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.240162</Real>
+        <Real Name="Y">19.705011</Real>
+        <Real Name="Z">53.452057</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-294.36719</Real>
+        <Real Name="Y">-161.07556</Real>
+        <Real Name="Z">314.37973</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.00629</Real>
+        <Real Name="Y">159.62878</Real>
+        <Real Name="Z">-332.52762</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">105.34657</Real>
+        <Real Name="Y">69.315125</Real>
+        <Real Name="Z">-71.967148</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-68.409668</Real>
+        <Real Name="Y">-324.19321</Real>
+        <Real Name="Z">-20.511414</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-17.41099</Real>
+        <Real Name="Y">78.021255</Real>
+        <Real Name="Z">-5.4529419</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-109.73906</Real>
+        <Real Name="Y">31.796524</Real>
+        <Real Name="Z">125.68959</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.013605584</Real>
+        <Real Name="Y">0.59725976</Real>
+        <Real Name="Z">0.2398783</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0060534449</Real>
+        <Real Name="Y">0.68552339</Real>
+        <Real Name="Z">0.2761386</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.05632833</Real>
+        <Real Name="Y">0.60970521</Real>
+        <Real Name="Z">0.15513045</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97658825</Real>
+        <Real Name="Y">0.6404888</Real>
+        <Real Name="Z">1.5684869</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94705874</Real>
+        <Real Name="Y">0.61647117</Real>
+        <Real Name="Z">1.6563133</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94579661</Real>
+        <Real Name="Y">0.73033106</Real>
+        <Real Name="Z">1.5565473</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3930831</Real>
+        <Real Name="Y">0.45167708</Real>
+        <Real Name="Z">1.1805403</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3387789</Real>
+        <Real Name="Y">0.51957792</Real>
+        <Real Name="Z">1.2205759</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3364329</Real>
+        <Real Name="Y">0.41130936</Real>
+        <Real Name="Z">1.1147869</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6468202</Real>
+        <Real Name="Y">0.30426431</Real>
+        <Real Name="Z">0.30275336</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.710765</Real>
+        <Real Name="Y">0.33603039</Real>
+        <Real Name="Z">0.23900157</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6387461</Real>
+        <Real Name="Y">0.21073082</Real>
+        <Real Name="Z">0.284082</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7627407</Real>
+        <Real Name="Y">0.3876431</Real>
+        <Real Name="Z">0.020772513</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7275373</Real>
+        <Real Name="Y">0.42617679</Real>
+        <Real Name="Z">1.8025941</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8121799</Real>
+        <Real Name="Y">0.45860547</Real>
+        <Real Name="Z">0.061789811</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.52323073</Real>
+        <Real Name="Y">-0.1495952</Real>
+        <Real Name="Z">-0.40600052</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.2008246</Real>
+        <Real Name="Y">-0.80605865</Real>
+        <Real Name="Z">1.3330675</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8229196</Real>
+        <Real Name="Y">1.0542003</Real>
+        <Real Name="Z">0.42597404</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.099483654</Real>
+        <Real Name="Y">0.61493605</Real>
+        <Real Name="Z">-0.069274485</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1656597</Real>
+        <Real Name="Y">0.044083569</Real>
+        <Real Name="Z">-0.31453198</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9884303</Real>
+        <Real Name="Y">1.4374514</Real>
+        <Real Name="Z">1.2484246</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24927063</Real>
+        <Real Name="Y">0.31255421</Real>
+        <Real Name="Z">0.41460899</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.78582793</Real>
+        <Real Name="Y">2.1442647</Real>
+        <Real Name="Z">-1.2879866</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0986372</Real>
+        <Real Name="Y">-0.95221663</Real>
+        <Real Name="Z">1.9228592</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.1259062</Real>
+        <Real Name="Y">-0.59954149</Real>
+        <Real Name="Z">0.015831629</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.14985497</Real>
+        <Real Name="Y">1.0153686</Real>
+        <Real Name="Z">0.54390877</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.9456916</Real>
+        <Real Name="Y">-0.88253015</Real>
+        <Real Name="Z">0.21409456</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96629333</Real>
+        <Real Name="Y">-0.34217152</Real>
+        <Real Name="Z">-0.26563311</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3332443</Real>
+        <Real Name="Y">0.76015425</Real>
+        <Real Name="Z">-0.74514198</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.2512903</Real>
+        <Real Name="Y">-1.2145237</Real>
+        <Real Name="Z">1.5871022</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-22.944626</Real>
+        <Real Name="Y">-160.91989</Real>
+        <Real Name="Z">-388.6203</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.269073</Real>
+        <Real Name="Y">39.693375</Real>
+        <Real Name="Z">98.581383</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">141.00146</Real>
+        <Real Name="Y">181.80798</Real>
+        <Real Name="Z">167.97304</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">12.665855</Real>
+        <Real Name="Y">-3.7820816</Real>
+        <Real Name="Z">-39.203094</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.0514336</Real>
+        <Real Name="Y">-0.40136814</Real>
+        <Real Name="Z">13.222935</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-6.2043839</Real>
+        <Real Name="Y">5.2009029</Real>
+        <Real Name="Z">15.083206</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">35.805252</Real>
+        <Real Name="Y">-8.6559448</Real>
+        <Real Name="Z">-31.008476</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.22966</Real>
+        <Real Name="Y">1.9531918</Real>
+        <Real Name="Z">25.060932</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-12.985624</Real>
+        <Real Name="Y">5.6852989</Real>
+        <Real Name="Z">16.844494</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-210.54865</Real>
+        <Real Name="Y">-92.830818</Real>
+        <Real Name="Z">298.22876</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">101.41061</Real>
+        <Real Name="Y">44.375778</Real>
+        <Real Name="Z">-279.03412</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.020584</Real>
+        <Real Name="Y">74.505836</Real>
+        <Real Name="Z">-101.43745</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.199921</Real>
+        <Real Name="Y">-168.15239</Real>
+        <Real Name="Z">56.853714</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-41.231632</Real>
+        <Real Name="Y">19.673111</Real>
+        <Real Name="Z">-7.3845215</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-54.638596</Real>
+        <Real Name="Y">61.847054</Real>
+        <Real Name="Z">154.83948</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 3">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 4 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Replica exchange in temperature
+Replica exchange interval: 4
+Replica random seed: 98716
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1 x  2    3
+Repl pr        1.0     
+Replica exchange at step 12 time 0.01200
+Repl 2 <-> 3  [ not checked ]
+Repl ex  0 x  1    2 x  3
+Repl pr   1.0       1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl  number of exchanges:
+Repl     0    1    2    3
+Repl        2    1    2
+Repl  average number of exchanges:
+Repl     0    1    2    3
+Repl      1.0  1.0  1.0
+Repl                Empirical Transition Matrix
+Repl       1       2       3       4
+Repl  0.3333  0.6667  0.0000  0.0000  0
+Repl  0.6667  0.0000  0.3333  0.0000  1
+Repl  0.0000  0.3333  0.0000  0.6667  2
+Repl  0.0000  0.0000  0.6667  0.3333  3
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">25.725943</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">25.725723</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">25.725651</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">25.725159</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">25.724848</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">29.728069</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">29.728149</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">29.728266</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.728144</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">29.728222</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">29.728069</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">29.727938</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">29.727697</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">19.723433</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">19.718191</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">19.713408</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">19.709362</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">35.399361</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">35.219456</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">35.117966</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">35.083908</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">35.114708</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">38.848621</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">39.031418</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">39.309452</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">39.682892</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">40.152107</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">40.717049</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">41.284401</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">42.037231</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">45.582909</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">47.221081</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">48.70118</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">49.965275</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673418</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5016699</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.4002542</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.3666878</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.3977985</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.1477165</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-9.3304329</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-9.6083508</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-9.9819126</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-10.451051</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-11.016143</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-11.675986</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-12.429058</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-25.844458</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-27.487871</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-28.972754</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.240894</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951082</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154479</Real>
+        <Real Name="Y">0.60987526</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829578</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.19773772</Real>
+        <Real Name="Y">0.17085385</Real>
+        <Real Name="Z">-0.38463682</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.7416091</Real>
+        <Real Name="Y">0.65998852</Real>
+        <Real Name="Z">1.2586081</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3694094</Real>
+        <Real Name="Y">-0.24000962</Real>
+        <Real Name="Z">0.43566996</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19731475</Real>
+        <Real Name="Y">0.14646794</Real>
+        <Real Name="Z">-0.067733802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.380977</Real>
+        <Real Name="Y">-0.57837629</Real>
+        <Real Name="Z">0.21501081</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.9348555</Real>
+        <Real Name="Y">-0.90308607</Real>
+        <Real Name="Z">0.95776355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.019311024</Real>
+        <Real Name="Y">-0.34060633</Real>
+        <Real Name="Z">-0.30936736</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53589791</Real>
+        <Real Name="Y">-2.6701736</Real>
+        <Real Name="Z">0.21038769</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.076132908</Real>
+        <Real Name="Y">-2.1539493</Real>
+        <Real Name="Z">0.10673165</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.012962769</Real>
+        <Real Name="Y">0.24682857</Real>
+        <Real Name="Z">0.11953462</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.53758782</Real>
+        <Real Name="Y">-0.39684346</Real>
+        <Real Name="Z">-0.44394565</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22745027</Real>
+        <Real Name="Y">0.095898077</Real>
+        <Real Name="Z">1.1265593</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.062451392</Real>
+        <Real Name="Y">0.16304354</Real>
+        <Real Name="Z">0.54990536</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.52785772</Real>
+        <Real Name="Y">0.51248276</Real>
+        <Real Name="Z">0.03179457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.0415015</Real>
+        <Real Name="Y">-0.46201131</Real>
+        <Real Name="Z">-2.4335866</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519501</Real>
+        <Real Name="Y">10.126175</Real>
+        <Real Name="Z">-383.9245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.05405</Real>
+        <Real Name="Y">8.7836609</Real>
+        <Real Name="Z">109.98167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07303</Real>
+        <Real Name="Y">125.9024</Real>
+        <Real Name="Z">223.10417</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850471</Real>
+        <Real Name="Y">8.0224667</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90616</Real>
+        <Real Name="Y">-91.872803</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62738</Real>
+        <Real Name="Y">82.504341</Real>
+        <Real Name="Z">-270.19897</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06936</Real>
+        <Real Name="Y">45.329926</Real>
+        <Real Name="Z">-56.291367</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365845</Real>
+        <Real Name="Y">-204.77954</Real>
+        <Real Name="Z">21.69519</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097103</Real>
+        <Real Name="Y">47.599419</Real>
+        <Real Name="Z">-24.246689</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298553</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65224</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0093734991</Real>
+        <Real Name="Y">0.5985617</Real>
+        <Real Name="Z">0.24248323</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8573338</Real>
+        <Real Name="Y">0.68931687</Real>
+        <Real Name="Z">0.26944661</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.047422096</Real>
+        <Real Name="Y">0.60518241</Real>
+        <Real Name="Z">0.15490019</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9757846</Real>
+        <Real Name="Y">0.63566589</Real>
+        <Real Name="Z">1.5689228</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.9487462</Real>
+        <Real Name="Y">0.61595821</Real>
+        <Real Name="Z">1.6586046</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.93035418</Real>
+        <Real Name="Y">0.71715361</Real>
+        <Real Name="Z">1.5475184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3950565</Real>
+        <Real Name="Y">0.44926295</Real>
+        <Real Name="Z">1.177237</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3331386</Real>
+        <Real Name="Y">0.50007576</Real>
+        <Real Name="Z">1.2296445</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3442049</Real>
+        <Real Name="Y">0.42015764</Real>
+        <Real Name="Z">1.1015447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6459056</Real>
+        <Real Name="Y">0.30885819</Real>
+        <Real Name="Z">0.30255109</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.709002</Real>
+        <Real Name="Y">0.32959262</Real>
+        <Real Name="Z">0.23362181</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6158395</Real>
+        <Real Name="Y">0.22039652</Real>
+        <Real Name="Z">0.28174537</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.770492</Real>
+        <Real Name="Y">0.39013377</Real>
+        <Real Name="Z">0.022931434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7175299</Real>
+        <Real Name="Y">0.42047828</Real>
+        <Real Name="Z">1.8112584</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8182588</Real>
+        <Real Name="Y">0.46790454</Real>
+        <Real Name="Z">0.051781986</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.53741348</Real>
+        <Real Name="Y">-0.17440791</Real>
+        <Real Name="Z">-0.25479135</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4669849</Real>
+        <Real Name="Y">-0.21005818</Real>
+        <Real Name="Z">0.35129488</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.34010595</Real>
+        <Real Name="Y">0.013960329</Real>
+        <Real Name="Z">-0.32626799</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10024429</Real>
+        <Real Name="Y">0.59214914</Real>
+        <Real Name="Z">-0.035546921</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.26560268</Real>
+        <Real Name="Y">0.095128722</Real>
+        <Real Name="Z">-0.25506774</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8684317</Real>
+        <Real Name="Y">1.8465521</Real>
+        <Real Name="Z">0.98709106</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24160631</Real>
+        <Real Name="Y">0.29004613</Real>
+        <Real Name="Z">0.40836841</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.57847255</Real>
+        <Real Name="Y">2.7069743</Real>
+        <Real Name="Z">-0.96611685</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.80599058</Real>
+        <Real Name="Y">-1.2365429</Real>
+        <Real Name="Z">1.3745391</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.10733435</Real>
+        <Real Name="Y">-0.54855478</Real>
+        <Real Name="Z">0.040494107</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.52276337</Real>
+        <Real Name="Y">0.54260927</Real>
+        <Real Name="Z">0.74899906</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.7292979</Real>
+        <Real Name="Y">-1.5136369</Real>
+        <Real Name="Z">0.35485333</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.96180129</Real>
+        <Real Name="Y">-0.27451086</Real>
+        <Real Name="Z">-0.26788449</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1516912</Real>
+        <Real Name="Y">0.67819536</Real>
+        <Real Name="Z">-1.3939142</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.30999547</Real>
+        <Real Name="Y">-1.0934045</Real>
+        <Real Name="Z">0.86038899</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">19.526718</Real>
+        <Real Name="Y">-58.164612</Real>
+        <Real Name="Z">-384.1503</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-19.738918</Real>
+        <Real Name="Y">21.560783</Real>
+        <Real Name="Z">103.61362</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">142.32828</Real>
+        <Real Name="Y">174.48886</Real>
+        <Real Name="Z">227.80746</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.362541</Real>
+        <Real Name="Y">-8.2558594</Real>
+        <Real Name="Z">-39.79541</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.627434</Real>
+        <Real Name="Y">-12.122859</Real>
+        <Real Name="Z">-23.771091</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.3952522</Real>
+        <Real Name="Y">6.6991405</Real>
+        <Real Name="Z">14.510761</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.680939</Real>
+        <Real Name="Y">-9.2137032</Real>
+        <Real Name="Z">-32.58622</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-27.290161</Real>
+        <Real Name="Y">4.9485683</Real>
+        <Real Name="Z">27.300488</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.9855</Real>
+        <Real Name="Y">17.944714</Real>
+        <Real Name="Z">54.341476</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-256.06866</Real>
+        <Real Name="Y">-98.978958</Real>
+        <Real Name="Z">270.96521</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">160.94031</Real>
+        <Real Name="Y">76.924072</Real>
+        <Real Name="Z">-290.57068</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">94.40947</Real>
+        <Real Name="Y">63.97332</Real>
+        <Real Name="Z">-79.816063</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22479248</Real>
+        <Real Name="Y">-166.63504</Real>
+        <Real Name="Z">53.202667</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-39.816574</Real>
+        <Real Name="Y">25.882828</Real>
+        <Real Name="Z">-18.801407</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-101.35582</Real>
+        <Real Name="Y">-39.0513</Real>
+        <Real Name="Z">117.74954</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070788218</Real>
+        <Real Name="Y">0.59985143</Real>
+        <Real Name="Z">0.23216741</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0052211494</Real>
+        <Real Name="Y">0.67791736</Real>
+        <Real Name="Z">0.28752598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.081287436</Real>
+        <Real Name="Y">0.61389297</Real>
+        <Real Name="Z">0.17336068</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97334617</Real>
+        <Real Name="Y">0.63034391</Real>
+        <Real Name="Z">1.5736558</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94112474</Real>
+        <Real Name="Y">0.57215339</Real>
+        <Real Name="Z">1.6424887</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90216142</Real>
+        <Real Name="Y">0.69281185</Real>
+        <Real Name="Z">1.5597703</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959581</Real>
+        <Real Name="Y">0.44665492</Real>
+        <Real Name="Z">1.1631975</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3336974</Real>
+        <Real Name="Y">0.47016072</Real>
+        <Real Name="Z">1.2319971</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3417647</Real>
+        <Real Name="Y">0.43266025</Real>
+        <Real Name="Z">1.0855473</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6414233</Real>
+        <Real Name="Y">0.31911239</Real>
+        <Real Name="Z">0.31267208</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7040794</Real>
+        <Real Name="Y">0.34990901</Real>
+        <Real Name="Z">0.24718852</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6264625</Real>
+        <Real Name="Y">0.22726779</Real>
+        <Real Name="Z">0.29024291</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7798417</Real>
+        <Real Name="Y">0.39102501</Real>
+        <Real Name="Z">0.024174023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.690425</Real>
+        <Real Name="Y">0.42115369</Real>
+        <Real Name="Z">0.0080727339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8171091</Real>
+        <Real Name="Y">0.45677534</Real>
+        <Real Name="Z">0.082913674</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.17447139</Real>
+        <Real Name="Y">0.084346771</Real>
+        <Real Name="Z">-0.96273595</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67588788</Real>
+        <Real Name="Y">-2.0325165</Real>
+        <Real Name="Z">2.0392632</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5507786</Real>
+        <Real Name="Y">0.16611598</Real>
+        <Real Name="Z">2.0554669</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.12016032</Real>
+        <Real Name="Y">-0.05641425</Real>
+        <Real Name="Z">0.30130097</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20845804</Real>
+        <Real Name="Y">-2.4929349</Real>
+        <Real Name="Z">-1.7998385</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.75786817</Real>
+        <Real Name="Y">-0.56873626</Real>
+        <Real Name="Z">1.2657158</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.075797163</Real>
+        <Real Name="Y">-0.021384535</Real>
+        <Real Name="Z">-0.67195547</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43283227</Real>
+        <Real Name="Y">-0.37384507</Real>
+        <Real Name="Z">-0.091247775</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.6712535</Real>
+        <Real Name="Y">0.16397838</Real>
+        <Real Name="Z">-0.28978387</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24631183</Real>
+        <Real Name="Y">0.35383612</Real>
+        <Real Name="Z">0.60025954</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.33667877</Real>
+        <Real Name="Y">1.4335442</Real>
+        <Real Name="Z">1.6658587</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3137784</Real>
+        <Real Name="Y">-0.11595275</Real>
+        <Real Name="Z">0.81633365</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.029242735</Real>
+        <Real Name="Y">0.062146634</Real>
+        <Real Name="Z">0.020171298</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.60698593</Real>
+        <Real Name="Y">-0.43418175</Real>
+        <Real Name="Z">2.6246724</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.27904311</Real>
+        <Real Name="Y">-2.4519882</Real>
+        <Real Name="Z">3.0299652</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-161.52841</Real>
+        <Real Name="Y">-312.79315</Real>
+        <Real Name="Z">-381.68372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.219154</Real>
+        <Real Name="Y">67.592659</Real>
+        <Real Name="Z">100.18578</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">171.02486</Real>
+        <Real Name="Y">144.86008</Real>
+        <Real Name="Z">75.640854</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.137802</Real>
+        <Real Name="Y">-15.058331</Real>
+        <Real Name="Z">-36.553482</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.886292</Real>
+        <Real Name="Y">-7.1101837</Real>
+        <Real Name="Z">-24.518116</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1563263</Real>
+        <Real Name="Y">7.3981667</Real>
+        <Real Name="Z">12.134254</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.201904</Real>
+        <Real Name="Y">-17.564514</Real>
+        <Real Name="Z">-31.302471</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.378387</Real>
+        <Real Name="Y">14.915598</Real>
+        <Real Name="Z">25.233826</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.691284</Real>
+        <Real Name="Y">17.419264</Real>
+        <Real Name="Z">55.005985</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-182.95808</Real>
+        <Real Name="Y">1.833786</Real>
+        <Real Name="Z">101.79486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">150.07346</Real>
+        <Real Name="Y">-30.872208</Real>
+        <Real Name="Z">-84.71991</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.021156</Real>
+        <Real Name="Y">10.203827</Real>
+        <Real Name="Z">-48.898819</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-50.970779</Real>
+        <Real Name="Y">-306.68451</Real>
+        <Real Name="Z">-20.453552</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-20.453407</Real>
+        <Real Name="Y">115.88318</Real>
+        <Real Name="Z">-0.4553833</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">7.5720444</Real>
+        <Real Name="Y">309.97635</Real>
+        <Real Name="Z">258.58994</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceVelocityVerlet_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_mdvv_NoseHoover_No_4Ranks_2RanksPerSimulation_d.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceVelocityVerlet_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_mdvv_NoseHoover_No_4Ranks_2RanksPerSimulation_d.xml
new file mode 100644 (file)
index 0000000..f396d17
--- /dev/null
@@ -0,0 +1,1652 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Replica exchange in temperature
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">19.745687852366203</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">19.745959185871598</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">19.746180949180243</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">19.746298539227812</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">19.746240975198788</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">17.503050979451981</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">17.502915115248118</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">17.502673039035248</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">17.502288843605747</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">17.501724859288121</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">17.500318672736427</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">17.499298168230808</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">17.498004993441533</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">19.723473381850415</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">19.718390669216756</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">19.71358001224721</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">19.709497027168194</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.419052386133128</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.84962985457631</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.412390353433597</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">31.126277292342095</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">31.995533534420641</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">27.473224924577302</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">27.940390816718903</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">28.554418123616422</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.31328503305518</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">30.213413977588012</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">31.198114732953112</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">32.313590710087908</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">33.488831227994908</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">45.582905788246592</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">47.221169643416559</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">48.701295028174172</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">49.965350551871275</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673364533766927</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.089891600229286</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.652430335777929</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.366199684638858</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.235513490746428</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.9500217159809683</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.417323472326428</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.03159285543682</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-11.790843960305079</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-12.691536889155536</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-13.677643831072331</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-14.738947919283415</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-15.91548161197969</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-25.844413964745151</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-27.487760532548776</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-28.972696574275936</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.240835083052055</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.004987833407605083</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858972</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391528</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.02498992600415597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208519</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13816730666039254</Real>
+        <Real Name="Y">-0.081793941152958655</Real>
+        <Real Name="Z">-0.55161420803864136</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6817968912385868</Real>
+        <Real Name="Y">0.11154328864465367</Real>
+        <Real Name="Z">0.086537431945852714</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.5056670646203405</Real>
+        <Real Name="Y">-0.2682410929079202</Real>
+        <Real Name="Z">-0.36989321370880823</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.082187565565796414</Real>
+        <Real Name="Y">-0.035856486511024722</Real>
+        <Real Name="Z">0.27249213202030709</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0691700139813751</Real>
+        <Real Name="Y">-2.700986918594118</Real>
+        <Real Name="Z">-0.45056456497429864</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.99486964180314541</Real>
+        <Real Name="Y">-0.45276130194728997</Real>
+        <Real Name="Z">1.1449358532073448</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.047058209412896693</Real>
+        <Real Name="Y">-0.027117909659181094</Real>
+        <Real Name="Z">-0.68353533736848382</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.052922616420256779</Real>
+        <Real Name="Y">-0.42434110700619487</Real>
+        <Real Name="Z">-0.38322245057059767</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25128661637527649</Real>
+        <Real Name="Y">0.072381668037675526</Real>
+        <Real Name="Z">-0.58357101060971228</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20092812452327882</Real>
+        <Real Name="Y">0.39382068387208857</Real>
+        <Real Name="Z">0.71723514347464723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21974992231123289</Real>
+        <Real Name="Y">1.2084096572009659</Real>
+        <Real Name="Z">0.86299525553264622</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3874825489464533</Real>
+        <Real Name="Y">-0.64634842404151116</Real>
+        <Real Name="Z">0.87320911313451055</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2141468744966106</Real>
+        <Real Name="Y">-0.088294604527846196</Real>
+        <Real Name="Z">-0.037485865576621598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8251647053113969</Real>
+        <Real Name="Y">0.93710079485932685</Real>
+        <Real Name="Z">2.5717978189626187</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38095191515251692</Real>
+        <Real Name="Y">-0.38837106592419146</Real>
+        <Real Name="Z">0.73821269459967742</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959196342</Real>
+        <Real Name="Y">10.126334215507086</Real>
+        <Real Name="Z">-383.9244463652023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773668</Real>
+        <Real Name="Y">8.7835602768706877</Real>
+        <Real Name="Z">109.98162207856127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818237</Real>
+        <Real Name="Y">125.90227601095691</Real>
+        <Real Name="Z">223.10402606189822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.9064510541798</Real>
+        <Real Name="Y">-91.873016441468678</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733365</Real>
+        <Real Name="Y">82.504344401698347</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041526</Real>
+        <Real Name="Y">45.329959216167893</Real>
+        <Real Name="Z">-56.291380508471349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448434</Real>
+        <Real Name="Y">-204.77938512046111</Real>
+        <Real Name="Z">21.695070286562498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013951</Real>
+        <Real Name="Y">47.5995038096992</Real>
+        <Real Name="Z">-24.246658126595179</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564435093</Real>
+        <Real Name="Y">-23.593576368970304</Real>
+        <Real Name="Z">144.65217639452101</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0032186817093378325</Real>
+        <Real Name="Y">0.59444510592794642</Real>
+        <Real Name="Z">0.24354558683394534</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8500917914722155</Real>
+        <Real Name="Y">0.68464069424978757</Real>
+        <Real Name="Z">0.2717667245183521</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.058258538829523435</Real>
+        <Real Name="Y">0.60261362424167142</Real>
+        <Real Name="Z">0.16565972266882495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97845344013592483</Real>
+        <Real Name="Y">0.63002360818642467</Real>
+        <Real Name="Z">1.5703486007994663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96135499327556284</Real>
+        <Real Name="Y">0.62383136658842164</Real>
+        <Real Name="Z">1.6643252875837684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92764276521597555</Real>
+        <Real Name="Y">0.70590212724906187</Real>
+        <Real Name="Z">1.5416598563333912</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3933894374164111</Real>
+        <Real Name="Y">0.44733749674722634</Real>
+        <Real Name="Z">1.1772668694707331</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3332858146118982</Real>
+        <Real Name="Y">0.47714789696999571</Real>
+        <Real Name="Z">1.2455399458942462</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3363517602976993</Real>
+        <Real Name="Y">0.41507575362176385</Real>
+        <Real Name="Z">1.1074943697347486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6470212395694162</Real>
+        <Real Name="Y">0.3155695064342634</Real>
+        <Real Name="Z">0.2991763164457138</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7055221626298422</Real>
+        <Real Name="Y">0.33233011954142255</Real>
+        <Real Name="Z">0.22529098468527695</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5972929262037461</Real>
+        <Real Name="Y">0.23798421025022443</Real>
+        <Real Name="Z">0.27329321257774175</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7765915085399326</Real>
+        <Real Name="Y">0.39592868771019668</Real>
+        <Real Name="Z">0.022811271004567039</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7120862286089165</Real>
+        <Real Name="Y">0.40978639474605</Real>
+        <Real Name="Z">1.8155217849449763</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8072149698943598</Real>
+        <Real Name="Y">0.48385616824207378</Real>
+        <Real Name="Z">0.045021182800653751</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.23107308744841995</Real>
+        <Real Name="Y">-0.67394989459516885</Real>
+        <Real Name="Z">-0.13459624611069593</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.58320734692483889</Real>
+        <Real Name="Y">-0.78300026848907822</Real>
+        <Real Name="Z">0.65212789157027984</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.662354942315146</Real>
+        <Real Name="Y">-0.58440051048868968</Real>
+        <Real Name="Z">1.2128304677678359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43035293840862932</Real>
+        <Real Name="Y">-0.11713979282068097</Real>
+        <Real Name="Z">0.15580072455137015</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4028864727648733</Real>
+        <Real Name="Y">0.99821031527334769</Real>
+        <Real Name="Z">0.40623869058443762</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4956878103252649</Real>
+        <Real Name="Y">0.57396913294297425</Real>
+        <Real Name="Z">0.096890441394003685</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.47278513228931057</Real>
+        <Real Name="Y">0.037523742887050585</Real>
+        <Real Name="Z">0.39138603408084977</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50449589778662507</Real>
+        <Real Name="Y">0.099527561234820455</Real>
+        <Real Name="Z">1.2246540622051882</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.442913559193379</Real>
+        <Real Name="Y">-1.9126189841592163</Real>
+        <Real Name="Z">2.086163720745954</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24291854493897852</Real>
+        <Real Name="Y">0.31221096846669005</Real>
+        <Real Name="Z">-0.372259628230874</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.28156994205702041</Real>
+        <Real Name="Y">0.8320452329987118</Real>
+        <Real Name="Z">-0.22373375529811312</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.3910258972438711</Real>
+        <Real Name="Y">0.38108918948999598</Real>
+        <Real Name="Z">-0.86327747797285814</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19070267356234233</Real>
+        <Real Name="Y">0.44191941732185541</Real>
+        <Real Name="Z">-0.27221774484151712</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39680352685675624</Real>
+        <Real Name="Y">-0.50979684378008006</Real>
+        <Real Name="Z">-1.0088613733603027</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7627196802622014</Real>
+        <Real Name="Y">0.89601612587883506</Real>
+        <Real Name="Z">0.097573122738124476</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-2.6940160384030207</Real>
+        <Real Name="Y">61.290103766663663</Real>
+        <Real Name="Z">-372.6497748433278</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.4441412960204829</Real>
+        <Real Name="Y">1.1925088868346023</Real>
+        <Real Name="Z">111.75566620639765</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.49655089870242</Real>
+        <Real Name="Y">66.064651376917851</Real>
+        <Real Name="Z">209.71456979099011</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.486294603178166</Real>
+        <Real Name="Y">-18.768454085245637</Real>
+        <Real Name="Z">-38.90261132394113</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.71522963586704</Real>
+        <Real Name="Y">-9.5254103906903289</Real>
+        <Real Name="Z">-24.544943744296802</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4185722854276435</Real>
+        <Real Name="Y">10.474337082760655</Real>
+        <Real Name="Z">12.997757171902279</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.525917311464198</Real>
+        <Real Name="Y">-7.3039046210512097</Real>
+        <Real Name="Z">-33.323187622955047</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-56.859559770232444</Real>
+        <Real Name="Y">11.305139838321729</Real>
+        <Real Name="Z">-14.994295063058217</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.589857926174268</Real>
+        <Real Name="Y">18.82248315800512</Real>
+        <Real Name="Z">56.424133758573291</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-308.76355784011872</Real>
+        <Real Name="Y">-122.68860864153959</Real>
+        <Real Name="Z">254.42773357455576</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.64884671126401</Real>
+        <Real Name="Y">107.37090153158394</Real>
+        <Real Name="Z">-280.03494716656576</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">113.78516721797325</Real>
+        <Real Name="Y">55.095298351001134</Real>
+        <Real Name="Z">-57.701672450342457</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-57.677464145174497</Real>
+        <Real Name="Y">-236.25574180057791</Real>
+        <Real Name="Z">-0.011609031788395896</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">7.5450683610524258</Real>
+        <Real Name="Y">44.70723690521298</Real>
+        <Real Name="Z">16.461810667181652</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-104.75590543795039</Real>
+        <Real Name="Y">18.219458641802987</Real>
+        <Real Name="Z">160.38137007667467</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070787993807611771</Real>
+        <Real Name="Y">0.59985143632530491</Real>
+        <Real Name="Z">0.23216740555529605</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0052211583495530524</Real>
+        <Real Name="Y">0.67791753378416286</Real>
+        <Real Name="Z">0.287525801461815</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.081287362845243835</Real>
+        <Real Name="Y">0.61389285024541129</Real>
+        <Real Name="Z">0.1733605504815742</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97334625725848101</Real>
+        <Real Name="Y">0.6303441407449426</Real>
+        <Real Name="Z">1.5736557083673339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94112496301574966</Real>
+        <Real Name="Y">0.57215321203145852</Real>
+        <Real Name="Z">1.6424882763332704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90216144280968391</Real>
+        <Real Name="Y">0.69281209133550636</Real>
+        <Real Name="Z">1.5597706177696835</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.395958105425664</Real>
+        <Real Name="Y">0.44665492888598624</Real>
+        <Real Name="Z">1.1631968528893808</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3336974780076019</Real>
+        <Real Name="Y">0.4701604488122107</Real>
+        <Real Name="Z">1.2319967308435358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3417646258393612</Real>
+        <Real Name="Y">0.43266026703608346</Real>
+        <Real Name="Z">1.0855467749110856</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6414230943359058</Real>
+        <Real Name="Y">0.31911231093852566</Real>
+        <Real Name="Z">0.31267198483387215</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7040793988098979</Real>
+        <Real Name="Y">0.34990901804936458</Real>
+        <Real Name="Z">0.24718863778447875</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6264625600309222</Real>
+        <Real Name="Y">0.22726769245287287</Real>
+        <Real Name="Z">0.29024283263112532</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7798416679185258</Real>
+        <Real Name="Y">0.39102509067626678</Real>
+        <Real Name="Z">0.024174026126615355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6904250024435643</Real>
+        <Real Name="Y">0.42115363373070797</Real>
+        <Real Name="Z">0.0080728078883847143</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.81710914241706</Real>
+        <Real Name="Y">0.45677550610171647</Real>
+        <Real Name="Z">0.082913592143751963</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.17446846201908134</Real>
+        <Real Name="Y">0.084341697470427968</Real>
+        <Real Name="Z">-0.96273508757496484</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67589073590978566</Real>
+        <Real Name="Y">-2.0324979104258274</Real>
+        <Real Name="Z">2.0392462199284092</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5507802358552771</Real>
+        <Real Name="Y">0.16609891961909087</Real>
+        <Real Name="Z">2.0554618531517703</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.12015776490054558</Real>
+        <Real Name="Y">-0.05641252759442425</Real>
+        <Real Name="Z">0.30130061292215848</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20846853219757044</Real>
+        <Real Name="Y">-2.4929464228494296</Real>
+        <Real Name="Z">-1.799880001118334</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.75786179301290768</Real>
+        <Real Name="Y">-0.5687354264172193</Real>
+        <Real Name="Z">1.265722219693538</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.07579193455959396</Real>
+        <Real Name="Y">-0.02138522390730269</Real>
+        <Real Name="Z">-0.67195446997771524</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43282587918410864</Real>
+        <Real Name="Y">-0.37385156368936806</Real>
+        <Real Name="Z">-0.091259126311861047</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.67123200246577408</Real>
+        <Real Name="Y">0.16397457607943797</Real>
+        <Real Name="Z">-0.28979231101819503</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24631252136841331</Real>
+        <Real Name="Y">0.35383599818338801</Real>
+        <Real Name="Z">0.60026091863722186</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.33669203614986226</Real>
+        <Real Name="Y">1.4335539884992163</Real>
+        <Real Name="Z">1.6658855838366835</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3137680378133947</Real>
+        <Real Name="Y">-0.11593788059678069</Real>
+        <Real Name="Z">0.81632033979247631</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.029243187000817905</Real>
+        <Real Name="Y">0.062146535109581319</Real>
+        <Real Name="Z">0.020170121430812663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.60699010528297404</Real>
+        <Real Name="Y">-0.43418646941559169</Real>
+        <Real Name="Z">2.6246978375028243</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.27902947350535412</Real>
+        <Real Name="Y">-2.4519898190367431</Real>
+        <Real Name="Z">3.0299651407501362</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-161.52834287810253</Real>
+        <Real Name="Y">-312.79321787174433</Real>
+        <Real Name="Z">-381.68333870085536</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.219259755888324</Real>
+        <Real Name="Y">67.593034294350204</Real>
+        <Real Name="Z">100.18554796834346</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">171.02544006603736</Real>
+        <Real Name="Y">144.86051780735755</Real>
+        <Real Name="Z">75.64097048971712</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.137801621674612</Real>
+        <Real Name="Y">-15.058447601643337</Real>
+        <Real Name="Z">-36.553416427882141</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.886261551335132</Real>
+        <Real Name="Y">-7.1101356999553289</Real>
+        <Real Name="Z">-24.518132813962069</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1562917351416928</Real>
+        <Real Name="Y">7.3981869330054835</Real>
+        <Real Name="Z">12.134216637974482</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.201802611021876</Real>
+        <Real Name="Y">-17.564565890747311</Real>
+        <Real Name="Z">-31.302368429416056</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.378320272075072</Real>
+        <Real Name="Y">14.915678090623601</Real>
+        <Real Name="Z">25.233735026569398</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.691253776814847</Real>
+        <Real Name="Y">17.419284168716889</Real>
+        <Real Name="Z">55.005966006716378</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-182.95817379463983</Real>
+        <Real Name="Y">1.8337404961539221</Real>
+        <Real Name="Z">101.79403721601813</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">150.07370426635779</Real>
+        <Real Name="Y">-30.87177305267204</Real>
+        <Real Name="Z">-84.719598637334315</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.02119539722068</Real>
+        <Real Name="Y">10.203923457115792</Real>
+        <Real Name="Z">-48.898707297421836</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-50.969778697190037</Real>
+        <Real Name="Y">-306.68442844103578</Real>
+        <Real Name="Z">-20.453827009224142</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-20.454028236055002</Real>
+        <Real Name="Y">115.88291869351499</Real>
+        <Real Name="Z">-0.45533857338506323</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">7.5707241204832485</Real>
+        <Real Name="Y">309.9752846169597</Real>
+        <Real Name="Z">258.59025454414194</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Replica exchange in temperature
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">17.510863651814013</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">17.51093282048511</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">17.503123515386253</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">17.503142765020236</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">17.50313062913424</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">19.74594317009991</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">19.745260433917014</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">19.744105603976415</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">19.742370548509712</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">19.739962577180481</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">19.73682438595274</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">19.73295720605201</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">19.728452228182977</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">17.496451342470227</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">17.494594104745453</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">17.492476479926506</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">17.490137108795761</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">27.184228185580942</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">27.032510225321467</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">26.958446446583721</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">26.982335839501914</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">27.153835583583714</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">33.022510172008296</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.206455573670837</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">35.542336080498821</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.019317756938591</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">38.619353878880347</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">40.315933327944244</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">42.074712786490892</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">43.847697584860711</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">34.764610309040819</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">36.123758372626682</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">37.546047584270269</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">39.00839800951475</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.673364533766927</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5014251621670169</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.4351706885281281</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.459040831812338</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.6305527117801333</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.262787924185265</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.447416062030701</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-15.784451398799284</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.263168130705758</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-18.865612223976743</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-20.565329864268381</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-22.326737128708363</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.104226904947215</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.192814293430047</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-18.553819594740684</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-19.978226431203218</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-21.442916227578444</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.004987833407605083</Real>
+        <Real Name="Y">0.60003868084888567</Real>
+        <Real Name="Z">0.24401598138174649</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986231367943</Real>
+        <Real Name="Y">0.68951083699925309</Real>
+        <Real Name="Z">0.27000220546858972</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154490135391528</Real>
+        <Real Name="Y">0.6098752042967166</Real>
+        <Real Name="Z">0.16074413131800275</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497873335228347</Real>
+        <Real Name="Y">0.63100079416085897</Real>
+        <Real Name="Z">1.5690467169862339</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126607650355988</Real>
+        <Real Name="Y">0.61500006951715269</Real>
+        <Real Name="Z">1.660392242963429</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607147667449185</Real>
+        <Real Name="Y">0.70098732522764173</Real>
+        <Real Name="Z">1.5408662453802704</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3969269888287765</Real>
+        <Real Name="Y">0.44702570682110637</Real>
+        <Real Name="Z">1.1740447415372022</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457691645356</Real>
+        <Real Name="Y">0.47673109288482313</Real>
+        <Real Name="Z">1.2356355253534184</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.349213094856172</Real>
+        <Real Name="Y">0.43086087763738978</Real>
+        <Real Name="Z">1.0926543181482555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450240462707935</Real>
+        <Real Name="Y">0.31305820390562578</Real>
+        <Real Name="Z">0.3020369638022472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948669780205</Real>
+        <Real Name="Y">0.32767986184373582</Real>
+        <Real Name="Z">0.22791196024380245</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234604972457</Real>
+        <Real Name="Y">0.23439630128357664</Real>
+        <Real Name="Z">0.27850133473866351</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906273585884</Real>
+        <Real Name="Y">0.39201491115703496</Real>
+        <Real Name="Z">0.02498992600415597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813745208519</Real>
+        <Real Name="Y">0.41501193039379697</Real>
+        <Real Name="Z">1.8243903223406222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177673919860959</Real>
+        <Real Name="Y">0.47575139344959078</Real>
+        <Real Name="Z">0.048829576358888821</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.20816714232045599</Real>
+        <Real Name="Y">-0.71797434577979458</Real>
+        <Real Name="Z">0.010975775473819111</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.65682864411902719</Real>
+        <Real Name="Y">-0.44559552456827389</Real>
+        <Real Name="Z">-0.19622423964063035</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.078420743064112786</Real>
+        <Real Name="Y">-1.3415374412821621</Real>
+        <Real Name="Z">0.09620399499033</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43867055453026338</Real>
+        <Real Name="Y">-0.12663082072886794</Real>
+        <Real Name="Z">0.16958585137271856</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1163945704197633</Real>
+        <Real Name="Y">1.2029556438119304</Real>
+        <Real Name="Z">0.5784179593114398</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3942474372274611</Real>
+        <Real Name="Y">0.64883563210429596</Real>
+        <Real Name="Z">0.097968678311628032</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.41536903825227472</Real>
+        <Real Name="Y">0.038877833253995513</Real>
+        <Real Name="Z">0.41476955852881103</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.31657500976217356</Real>
+        <Real Name="Y">0.03101687574998693</Real>
+        <Real Name="Z">1.2145648328748377</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7340944951709563</Real>
+        <Real Name="Y">-2.0244335282595589</Real>
+        <Real Name="Z">1.5976433947049167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25620696679879112</Real>
+        <Real Name="Y">0.31478660291340033</Real>
+        <Real Name="Z">-0.34182633419847874</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.14583319885881685</Real>
+        <Real Name="Y">0.3431874122845972</Real>
+        <Real Name="Z">-0.42373513305351085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019474648626513155</Real>
+        <Real Name="Y">0.51983036009342254</Real>
+        <Real Name="Z">-0.45082852350431635</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15299260842992252</Real>
+        <Real Name="Y">0.53591295383504078</Real>
+        <Real Name="Z">-0.2697115521376085</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26438352332848547</Real>
+        <Real Name="Y">-0.77197248812472063</Real>
+        <Real Name="Z">-1.2067320212702319</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.92311071709251591</Real>
+        <Real Name="Y">1.1238950100096334</Real>
+        <Real Name="Z">-1.0500393679712476</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9519396959196342</Real>
+        <Real Name="Y">10.126334215507086</Real>
+        <Real Name="Z">-383.9244463652023</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054086505773668</Real>
+        <Real Name="Y">8.7835602768706877</Real>
+        <Real Name="Z">109.98162207856127</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.07315715818237</Real>
+        <Real Name="Y">125.90227601095691</Real>
+        <Real Name="Z">223.10402606189822</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894355646832736</Real>
+        <Real Name="Y">-13.626754903483636</Real>
+        <Real Name="Z">-38.735776155935625</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715860216981412</Real>
+        <Real Name="Y">-9.0983247682018664</Real>
+        <Real Name="Z">-23.405587282427078</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850359748392378</Real>
+        <Real Name="Y">8.0224518367786501</Real>
+        <Real Name="Z">13.504349102913409</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797414589831448</Real>
+        <Real Name="Y">-10.314755630892151</Real>
+        <Real Name="Z">-33.439102282315602</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476498137025935</Real>
+        <Real Name="Y">8.5987757245371377</Real>
+        <Real Name="Z">27.984817114808166</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246096341780422</Real>
+        <Real Name="Y">16.418607741261862</Real>
+        <Real Name="Z">54.091299502956723</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.9064510541798</Real>
+        <Real Name="Y">-91.873016441468678</Real>
+        <Real Name="Z">235.22831958682747</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62742268733365</Real>
+        <Real Name="Y">82.504344401698347</Real>
+        <Real Name="Z">-270.19872940810154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937853041526</Real>
+        <Real Name="Y">45.329959216167893</Real>
+        <Real Name="Z">-56.291380508471349</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365651136448434</Real>
+        <Real Name="Y">-204.77938512046111</Real>
+        <Real Name="Z">21.695070286562498</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097047811013951</Real>
+        <Real Name="Y">47.5995038096992</Real>
+        <Real Name="Z">-24.246658126595179</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.298661564435093</Real>
+        <Real Name="Y">-23.593576368970304</Real>
+        <Real Name="Z">144.65217639452101</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.005989332388362717</Real>
+        <Real Name="Y">0.59960420076085807</Real>
+        <Real Name="Z">0.238955794646007</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8580335097345353</Real>
+        <Real Name="Y">0.68791033744669439</Real>
+        <Real Name="Z">0.27450896497143806</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.061665135672900363</Real>
+        <Real Name="Y">0.61092101412439925</Real>
+        <Real Name="Z">0.16192039327809121</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97423961285189453</Real>
+        <Real Name="Y">0.63071417183066392</Real>
+        <Real Name="Z">1.571292624308696</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94446122064648064</Real>
+        <Real Name="Y">0.59317045789768719</Real>
+        <Real Name="Z">1.6541541672691014</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90863690485455206</Real>
+        <Real Name="Y">0.69711089663265846</Real>
+        <Real Name="Z">1.5500775815563614</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396499751278377</Real>
+        <Real Name="Y">0.44682891474526276</Real>
+        <Real Name="Z">1.1685973970241168</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3310622503835363</Real>
+        <Real Name="Y">0.47334316551985939</Real>
+        <Real Name="Z">1.2332290176327554</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3463309332337372</Real>
+        <Real Name="Y">0.43157811185497058</Real>
+        <Real Name="Z">1.0885173051959678</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6433227042609633</Real>
+        <Real Name="Y">0.31616021823315443</Real>
+        <Real Name="Z">0.30759367910964724</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7027379843571337</Real>
+        <Real Name="Y">0.33843584861665787</Real>
+        <Real Name="Z">0.2359282119576718</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.609188197455822</Real>
+        <Real Name="Y">0.22976814955540215</Real>
+        <Real Name="Z">0.28449466798908196</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7792996004368868</Real>
+        <Real Name="Y">0.39121343736957404</Real>
+        <Real Name="Z">0.024520642083232035</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6974192093889267</Real>
+        <Real Name="Y">0.42101078257249641</Real>
+        <Real Name="Z">1.8469569347769914</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8188258359558944</Real>
+        <Real Name="Y">0.47061018968151114</Real>
+        <Real Name="Z">0.060522736855793451</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11757756835905483</Real>
+        <Real Name="Y">-0.019415863899251203</Real>
+        <Real Name="Z">-0.729206549041575</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4907503153770176</Real>
+        <Real Name="Y">-0.59907271040563725</Real>
+        <Real Name="Z">1.0973734951921452</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0630340698538849</Real>
+        <Real Name="Y">0.41162531222392096</Real>
+        <Real Name="Z">0.74015512115258486</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.10247988836235654</Real>
+        <Real Name="Y">-0.038515721913593988</Real>
+        <Real Name="Z">0.28861639236685777</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.63113556790187664</Real>
+        <Real Name="Y">-2.7178477941879584</Real>
+        <Real Name="Z">-1.115347242192243</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.86551858796883852</Real>
+        <Real Name="Y">-0.51105416366336276</Real>
+        <Real Name="Z">1.1692368249454035</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.060120721307194307</Real>
+        <Real Name="Y">-0.022644389032821156</Real>
+        <Real Name="Z">-0.67807422227145264</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23030825121247572</Real>
+        <Real Name="Y">-0.41629222741995686</Real>
+        <Real Name="Z">-0.22253522486183364</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46763682430090597</Real>
+        <Real Name="Y">0.10964396911903196</Real>
+        <Real Name="Z">-0.44796587541737609</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22564633742720119</Real>
+        <Real Name="Y">0.38080500935265044</Real>
+        <Real Name="Z">0.66784310912536304</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.0044104167134187411</Real>
+        <Real Name="Y">1.4224573362052009</Real>
+        <Real Name="Z">1.1750365715016824</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9458788464292276</Real>
+        <Real Name="Y">-0.47943374446897924</Real>
+        <Real Name="Z">0.67623586379903255</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11255432705487321</Real>
+        <Real Name="Y">-0.088988584447188573</Real>
+        <Real Name="Z">-0.07153753214218013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.1680089431123104</Real>
+        <Real Name="Y">0.46198820401445084</Real>
+        <Real Name="Z">2.9890207833699192</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.08359253385328648</Real>
+        <Real Name="Y">-1.0349114598756601</Real>
+        <Real Name="Z">2.2298883096204447</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-64.500766989015915</Real>
+        <Real Name="Y">-106.42570378406324</Real>
+        <Real Name="Z">-417.21142273071393</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.19957244111220263</Real>
+        <Real Name="Y">35.041514644477203</Real>
+        <Real Name="Z">108.81180017550824</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">177.61023395463013</Real>
+        <Real Name="Y">150.50688517703378</Real>
+        <Real Name="Z">171.79033475451504</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.69896246303135</Real>
+        <Real Name="Y">-14.331928131716509</Real>
+        <Real Name="Z">-37.632666523941154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.758052775255294</Real>
+        <Real Name="Y">-8.0142628086642489</Real>
+        <Real Name="Z">-23.759068660286601</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.2965714073206414</Real>
+        <Real Name="Y">7.6707126976215747</Real>
+        <Real Name="Z">12.782543115182172</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.140610541124872</Real>
+        <Real Name="Y">-14.341499975449608</Real>
+        <Real Name="Z">-32.979773611024065</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.40001182510003</Real>
+        <Real Name="Y">12.111500553070027</Real>
+        <Real Name="Z">27.164536338636495</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.901042546990844</Real>
+        <Real Name="Y">16.905477665138768</Real>
+        <Real Name="Z">54.424429341433154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-258.07750045203039</Real>
+        <Real Name="Y">-52.449868807497182</Real>
+        <Real Name="Z">175.90745152419657</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">212.87867871860257</Real>
+        <Real Name="Y">26.473818676446797</Real>
+        <Real Name="Z">-197.02157813272748</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.675189854717587</Real>
+        <Real Name="Y">33.097811809153512</Real>
+        <Real Name="Z">-53.513580333297369</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-59.619044365743832</Real>
+        <Real Name="Y">-231.46760677603157</Real>
+        <Real Name="Z">9.0245767855573149</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.945713239108017</Real>
+        <Real Name="Y">75.055912612044807</Real>
+        <Real Name="Z">-11.075744613060039</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-78.220649923164245</Real>
+        <Real Name="Y">70.167236448435915</Real>
+        <Real Name="Z">213.28816257002165</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0014099406815372166</Real>
+        <Real Name="Y">0.58940387494919211</Real>
+        <Real Name="Z">0.24167871260823096</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8540178029085259</Real>
+        <Real Name="Y">0.67624477597023303</Real>
+        <Real Name="Z">0.28081480083091254</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.075623617913748289</Real>
+        <Real Name="Y">0.59799692291974005</Real>
+        <Real Name="Z">0.1818388593476423</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98185750322509957</Real>
+        <Real Name="Y">0.62914621642067525</Real>
+        <Real Name="Z">1.571603977433494</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97335844352705203</Real>
+        <Real Name="Y">0.63104911587305756</Real>
+        <Real Name="Z">1.6669269198866239</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94000819421087789</Real>
+        <Real Name="Y">0.71004095873959772</Real>
+        <Real Name="Z">1.5421592087947886</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3893728310254068</Real>
+        <Real Name="Y">0.44759427711477406</Real>
+        <Real Name="Z">1.1803212663379019</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.337680861452065</Real>
+        <Real Name="Y">0.47841503593279605</Real>
+        <Real Name="Z">1.2547547232474781</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3266979970501318</Real>
+        <Real Name="Y">0.400424290966717</Real>
+        <Real Name="Z">1.1254653095696205</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6489144629224148</Real>
+        <Real Name="Y">0.31804556738880557</Real>
+        <Real Name="Z">0.29607989789597827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.708219767461796</Real>
+        <Real Name="Y">0.34094096646602762</Real>
+        <Real Name="Z">0.22451873556203095</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6021434292792933</Real>
+        <Real Name="Y">0.24066517451316438</Real>
+        <Real Name="Z">0.264662329397366</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7750174666746248</Real>
+        <Real Name="Y">0.39916419452560009</Real>
+        <Real Name="Z">0.020688203024768714</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7156734697021003</Real>
+        <Real Name="Y">0.40753057609834098</Real>
+        <Real Name="Z">1.8081116698610156</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7890438280592864</Real>
+        <Real Name="Y">0.4890712758670363</Real>
+        <Real Name="Z">0.05039167607037346</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.20774742277146843</Real>
+        <Real Name="Y">-0.57287048764670545</Real>
+        <Real Name="Z">-0.34285661784200672</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.33855542209868705</Real>
+        <Real Name="Y">-1.4004973910624965</Real>
+        <Real Name="Z">1.6255464407124192</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4273100255927411</Real>
+        <Real Name="Y">-0.77438922892469819</Real>
+        <Real Name="Z">2.8962162105354787</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42058140671746536</Real>
+        <Real Name="Y">-0.1007156737607766</Real>
+        <Real Name="Z">0.16183384153559505</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.570187420305712</Real>
+        <Real Name="Y">0.80972525550179009</Real>
+        <Real Name="Z">0.24615868911311473</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5919744794404136</Real>
+        <Real Name="Y">0.45124502019236923</Real>
+        <Real Name="Z">0.013377162401022505</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.52939267990205574</Real>
+        <Real Name="Y">0.024729877618035617</Real>
+        <Real Name="Z">0.37319463394667513</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.56629472024782057</Real>
+        <Real Name="Y">0.22101908228011855</Real>
+        <Real Name="Z">1.0528413897923201</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.94382131388640134</Real>
+        <Real Name="Y">-1.7395963911549697</Real>
+        <Real Name="Z">2.3638169459320242</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23067685585573569</Real>
+        <Real Name="Y">0.30649356772535408</Real>
+        <Real Name="Z">-0.40256304709475005</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39073538233227634</Real>
+        <Real Name="Y">1.2960864277857758</Real>
+        <Real Name="Z">0.046695210643423857</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.82426199611429729</Real>
+        <Real Name="Y">0.30517284944798811</Real>
+        <Real Name="Z">-1.2829746826142574</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19892715442453848</Real>
+        <Real Name="Y">0.37591003717156662</Real>
+        <Real Name="Z">-0.25146042729264317</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.49795643525106714</Real>
+        <Real Name="Y">0.010634816674450723</Real>
+        <Real Name="Z">-0.84650266233612914</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7428464057893645</Real>
+        <Real Name="Y">0.28812236746708181</Real>
+        <Real Name="Z">1.2155284277491885</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-71.80759364683567</Real>
+        <Real Name="Y">68.801179729686282</Real>
+        <Real Name="Z">-364.28355949014411</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.7376834155870071</Real>
+        <Real Name="Y">-0.12455604105588236</Real>
+        <Real Name="Z">112.01711379574468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">136.45971799332753</Real>
+        <Real Name="Y">2.7421778316274441</Real>
+        <Real Name="Z">136.62446540856797</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.638357027501627</Real>
+        <Real Name="Y">-23.618362873792478</Real>
+        <Real Name="Z">-37.764109854402122</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6398236077535557</Real>
+        <Real Name="Y">7.0322978222417802</Real>
+        <Real Name="Z">14.35533589904675</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.3168805638649559</Real>
+        <Real Name="Y">12.807734775411713</Real>
+        <Real Name="Z">11.920700343484796</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.758170241256153</Real>
+        <Real Name="Y">-3.9804782325609267</Real>
+        <Real Name="Z">-32.327110005702991</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.160911158611853</Real>
+        <Real Name="Y">9.1062083323658243</Real>
+        <Real Name="Z">-17.994215449502505</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.121145168087217</Real>
+        <Real Name="Y">4.2488751736798349</Real>
+        <Real Name="Z">18.122282706549385</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-316.19496458093352</Real>
+        <Real Name="Y">-133.01248701239285</Real>
+        <Real Name="Z">276.63889772920231</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">244.0843668914313</Real>
+        <Real Name="Y">103.30500626982189</Real>
+        <Real Name="Z">-285.05431973771226</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">118.74368874444922</Real>
+        <Real Name="Y">60.946372139053778</Real>
+        <Real Name="Z">-64.614475721029777</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-73.572582879713764</Real>
+        <Real Name="Y">-317.42216089764747</Real>
+        <Real Name="Z">-33.423314664841769</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.039215248079607</Real>
+        <Real Name="Y">56.988865370784197</Real>
+        <Real Name="Z">25.400850294796982</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-30.647297955831931</Real>
+        <Real Name="Y">152.17932761277686</Real>
+        <Real Name="Z">240.38145874594284</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceVelocityVerlet_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_mdvv_NoseHoover_No_4Ranks_2RanksPerSimulation_s.xml b/src/programs/mdrun/tests/refdata/ReplicaExchangeIsEquivalentToReferenceVelocityVerlet_ReplicaExchangeRegressionTest_WithinTolerances_ReplExRegression_mdvv_NoseHoover_No_4Ranks_2RanksPerSimulation_s.xml
new file mode 100644 (file)
index 0000000..6a22098
--- /dev/null
@@ -0,0 +1,1652 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <Simulation Name="Replica 0">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Replica exchange in temperature
+Replica exchange interval: 4
+Replica random seed: 98713
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">19.745672</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">19.746006</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">19.746151</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">19.746414</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">19.746365</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">17.503122</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">17.502979</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">17.502617</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">17.502325</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">17.501701</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">17.500376</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">17.499199</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">17.497988</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">19.723415</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">19.718357</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">19.713585</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">19.709377</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">29.419048</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">29.849585</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">30.412392</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">31.126295</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">31.995533</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">27.473236</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">27.940393</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">28.554379</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">29.313255</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">30.213358</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">31.198086</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">32.313545</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">33.488785</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">45.58284</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">47.221062</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">48.701195</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">49.96524</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733761</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-10.089799</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-10.652463</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-11.366102</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-12.23539</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-9.9499607</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-10.417261</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-11.031609</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-11.790777</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-12.691504</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-13.677557</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-14.739002</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-15.915453</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-25.844406</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-27.487686</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-28.972591</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-30.240845</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951088</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154483</Real>
+        <Real Name="Y">0.6098752</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829585</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.13816731</Real>
+        <Real Name="Y">-0.08179383</Real>
+        <Real Name="Z">-0.55161422</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6817964</Real>
+        <Real Name="Y">0.11154218</Real>
+        <Real Name="Z">0.086537696</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50566709</Real>
+        <Real Name="Y">-0.26824197</Real>
+        <Real Name="Z">-0.36989227</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.082187578</Real>
+        <Real Name="Y">-0.035856474</Real>
+        <Real Name="Z">0.27249208</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.0691695</Real>
+        <Real Name="Y">-2.7009876</Real>
+        <Real Name="Z">-0.45056441</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.99486995</Real>
+        <Real Name="Y">-0.45276091</Real>
+        <Real Name="Z">1.1449357</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.047058143</Real>
+        <Real Name="Y">-0.027117917</Real>
+        <Real Name="Z">-0.68353546</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0529195</Real>
+        <Real Name="Y">-0.42434022</Real>
+        <Real Name="Z">-0.38322309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.25128448</Real>
+        <Real Name="Y">0.072380677</Real>
+        <Real Name="Z">-0.58356738</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20092826</Real>
+        <Real Name="Y">0.39382076</Real>
+        <Real Name="Z">0.71723521</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.21974827</Real>
+        <Real Name="Y">1.2084097</Real>
+        <Real Name="Z">0.8629939</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3874834</Real>
+        <Real Name="Y">-0.64634955</Real>
+        <Real Name="Z">0.87320864</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.21414684</Real>
+        <Real Name="Y">-0.088294722</Real>
+        <Real Name="Z">-0.03748586</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.8251648</Real>
+        <Real Name="Y">0.93710148</Real>
+        <Real Name="Z">2.5717959</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.38095242</Real>
+        <Real Name="Y">-0.38837025</Real>
+        <Real Name="Z">0.7382139</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9518738</Real>
+        <Real Name="Y">10.126022</Real>
+        <Real Name="Z">-383.92468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054081</Real>
+        <Real Name="Y">8.7835617</Real>
+        <Real Name="Z">109.98161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.0733</Real>
+        <Real Name="Y">125.90257</Real>
+        <Real Name="Z">223.10434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850433</Real>
+        <Real Name="Y">8.0224648</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90619</Real>
+        <Real Name="Y">-91.872864</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62735</Real>
+        <Real Name="Y">82.504333</Real>
+        <Real Name="Z">-270.19894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937</Real>
+        <Real Name="Y">45.329948</Real>
+        <Real Name="Z">-56.291359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365723</Real>
+        <Real Name="Y">-204.77948</Real>
+        <Real Name="Z">21.695251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097099</Real>
+        <Real Name="Y">47.599464</Real>
+        <Real Name="Z">-24.246674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.29879</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65219</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0032186818</Real>
+        <Real Name="Y">0.59444505</Real>
+        <Real Name="Z">0.24354556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8500917</Real>
+        <Real Name="Y">0.68464065</Real>
+        <Real Name="Z">0.27176666</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.058258556</Real>
+        <Real Name="Y">0.60261357</Real>
+        <Real Name="Z">0.16565971</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97845346</Real>
+        <Real Name="Y">0.6300236</Real>
+        <Real Name="Z">1.5703487</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.96135491</Real>
+        <Real Name="Y">0.62383121</Real>
+        <Real Name="Z">1.6643254</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.92764282</Real>
+        <Real Name="Y">0.70590216</Real>
+        <Real Name="Z">1.5416601</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3933895</Real>
+        <Real Name="Y">0.44733754</Real>
+        <Real Name="Z">1.1772668</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3332859</Real>
+        <Real Name="Y">0.47714785</Real>
+        <Real Name="Z">1.24554</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3363516</Real>
+        <Real Name="Y">0.41507566</Real>
+        <Real Name="Z">1.1074945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6470212</Real>
+        <Real Name="Y">0.31556946</Real>
+        <Real Name="Z">0.29917628</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7055221</Real>
+        <Real Name="Y">0.33233008</Real>
+        <Real Name="Z">0.22529092</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5972928</Real>
+        <Real Name="Y">0.23798424</Real>
+        <Real Name="Z">0.27329314</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7765915</Real>
+        <Real Name="Y">0.39592871</Real>
+        <Real Name="Z">0.022811269</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7120862</Real>
+        <Real Name="Y">0.4097864</Real>
+        <Real Name="Z">1.8155217</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.807215</Real>
+        <Real Name="Y">0.4838562</Real>
+        <Real Name="Z">0.04502115</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.2310724</Real>
+        <Real Name="Y">-0.67394811</Real>
+        <Real Name="Z">-0.13459779</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.58321589</Real>
+        <Real Name="Y">-0.78299886</Real>
+        <Real Name="Z">0.65213329</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6623574</Real>
+        <Real Name="Y">-0.58439726</Real>
+        <Real Name="Z">1.212831</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43035176</Real>
+        <Real Name="Y">-0.11713909</Real>
+        <Real Name="Z">0.15580043</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4029002</Real>
+        <Real Name="Y">0.99820352</Real>
+        <Real Name="Z">0.40624356</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4956855</Real>
+        <Real Name="Y">0.57397455</Real>
+        <Real Name="Z">0.096906975</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.47278714</Real>
+        <Real Name="Y">0.037523676</Real>
+        <Real Name="Z">0.39138681</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.50449032</Real>
+        <Real Name="Y">0.099519581</Real>
+        <Real Name="Z">1.2246525</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.4429029</Real>
+        <Real Name="Y">-1.9126067</Real>
+        <Real Name="Z">2.0861578</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.24291719</Real>
+        <Real Name="Y">0.31220955</Real>
+        <Real Name="Z">-0.3722603</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.28157347</Real>
+        <Real Name="Y">0.8320474</Real>
+        <Real Name="Z">-0.22372982</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39103428</Real>
+        <Real Name="Y">0.38108227</Real>
+        <Real Name="Z">-0.86327982</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19070277</Real>
+        <Real Name="Y">0.44192058</Real>
+        <Real Name="Z">-0.27221885</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.39680779</Real>
+        <Real Name="Y">-0.50979918</Real>
+        <Real Name="Z">-1.008867</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.7627141</Real>
+        <Real Name="Y">0.89601707</Real>
+        <Real Name="Z">0.097563855</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-2.6940002</Real>
+        <Real Name="Y">61.290665</Real>
+        <Real Name="Z">-372.64963</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.4440842</Real>
+        <Real Name="Y">1.1924896</Real>
+        <Real Name="Z">111.75572</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">153.49663</Real>
+        <Real Name="Y">66.064491</Real>
+        <Real Name="Z">209.71472</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.486343</Real>
+        <Real Name="Y">-18.768524</Real>
+        <Real Name="Z">-38.902603</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">21.715202</Real>
+        <Real Name="Y">-9.525383</Real>
+        <Real Name="Z">-24.544937</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-8.4185715</Real>
+        <Real Name="Y">10.474358</Real>
+        <Real Name="Z">12.997749</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">33.525871</Real>
+        <Real Name="Y">-7.3039093</Real>
+        <Real Name="Z">-33.323181</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-56.859547</Real>
+        <Real Name="Y">11.305141</Real>
+        <Real Name="Z">-14.994366</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-37.589867</Real>
+        <Real Name="Y">18.822504</Real>
+        <Real Name="Z">56.424164</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-308.76379</Real>
+        <Real Name="Y">-122.68884</Real>
+        <Real Name="Z">254.42755</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">236.64932</Real>
+        <Real Name="Y">107.37119</Real>
+        <Real Name="Z">-280.03479</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">113.78526</Real>
+        <Real Name="Y">55.095253</Real>
+        <Real Name="Z">-57.701538</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-57.677826</Real>
+        <Real Name="Y">-236.2558</Real>
+        <Real Name="Z">-0.012115479</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">7.5451889</Real>
+        <Real Name="Y">44.707294</Real>
+        <Real Name="Z">16.4617</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-104.75612</Real>
+        <Real Name="Y">18.219063</Real>
+        <Real Name="Z">160.38147</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0070788073</Real>
+        <Real Name="Y">0.59985131</Real>
+        <Real Name="Z">0.23216741</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.0052211452</Real>
+        <Real Name="Y">0.67791748</Real>
+        <Real Name="Z">0.28752565</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.081287377</Real>
+        <Real Name="Y">0.61389267</Real>
+        <Real Name="Z">0.17336057</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97334617</Real>
+        <Real Name="Y">0.63034391</Real>
+        <Real Name="Z">1.5736558</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94112474</Real>
+        <Real Name="Y">0.57215339</Real>
+        <Real Name="Z">1.6424887</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90216142</Real>
+        <Real Name="Y">0.69281185</Real>
+        <Real Name="Z">1.5597703</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3959581</Real>
+        <Real Name="Y">0.44665492</Real>
+        <Real Name="Z">1.1631975</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3336974</Real>
+        <Real Name="Y">0.47016072</Real>
+        <Real Name="Z">1.2319971</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3417647</Real>
+        <Real Name="Y">0.43266025</Real>
+        <Real Name="Z">1.0855473</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6414233</Real>
+        <Real Name="Y">0.31911236</Real>
+        <Real Name="Z">0.31267208</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7040795</Real>
+        <Real Name="Y">0.3499091</Real>
+        <Real Name="Z">0.24718866</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6264626</Real>
+        <Real Name="Y">0.22726777</Real>
+        <Real Name="Z">0.29024282</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7798417</Real>
+        <Real Name="Y">0.39102501</Real>
+        <Real Name="Z">0.024174005</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.690425</Real>
+        <Real Name="Y">0.4211536</Real>
+        <Real Name="Z">0.0080728531</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8171092</Real>
+        <Real Name="Y">0.45677543</Real>
+        <Real Name="Z">0.082913548</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.17446959</Real>
+        <Real Name="Y">0.08434546</Real>
+        <Real Name="Z">-0.96273494</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.67589372</Real>
+        <Real Name="Y">-2.0324817</Real>
+        <Real Name="Z">2.0392401</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.5507815</Real>
+        <Real Name="Y">0.16609778</Real>
+        <Real Name="Z">2.0554624</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.12016027</Real>
+        <Real Name="Y">-0.056414243</Real>
+        <Real Name="Z">0.30130079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.20845793</Real>
+        <Real Name="Y">-2.492934</Real>
+        <Real Name="Z">-1.7998379</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.75786799</Real>
+        <Real Name="Y">-0.5687362</Real>
+        <Real Name="Z">1.2657154</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.075797126</Real>
+        <Real Name="Y">-0.021384533</Real>
+        <Real Name="Z">-0.67195529</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43283218</Real>
+        <Real Name="Y">-0.37384492</Real>
+        <Real Name="Z">-0.091247827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.6712532</Real>
+        <Real Name="Y">0.16397837</Real>
+        <Real Name="Z">-0.28978387</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.24631226</Real>
+        <Real Name="Y">0.35383347</Real>
+        <Real Name="Z">0.60026193</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.33669186</Real>
+        <Real Name="Y">1.4335552</Real>
+        <Real Name="Z">1.6658859</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.3137791</Real>
+        <Real Name="Y">-0.11594727</Real>
+        <Real Name="Z">0.81631416</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.029242089</Real>
+        <Real Name="Y">0.062147845</Real>
+        <Real Name="Z">0.020170119</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.60699046</Real>
+        <Real Name="Y">-0.43418908</Real>
+        <Real Name="Z">2.6246979</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.27903134</Real>
+        <Real Name="Y">-2.4519846</Real>
+        <Real Name="Z">3.029963</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-161.52812</Real>
+        <Real Name="Y">-312.79349</Real>
+        <Real Name="Z">-381.68448</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">14.21925</Real>
+        <Real Name="Y">67.593109</Real>
+        <Real Name="Z">100.18576</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">171.02562</Real>
+        <Real Name="Y">144.86072</Real>
+        <Real Name="Z">75.641365</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">16.137802</Real>
+        <Real Name="Y">-15.058331</Real>
+        <Real Name="Z">-36.553482</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.886292</Real>
+        <Real Name="Y">-7.1101837</Real>
+        <Real Name="Z">-24.518116</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.1563263</Real>
+        <Real Name="Y">7.3981667</Real>
+        <Real Name="Z">12.134251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">25.201904</Real>
+        <Real Name="Y">-17.564514</Real>
+        <Real Name="Z">-31.302471</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-21.378387</Real>
+        <Real Name="Y">14.915598</Real>
+        <Real Name="Z">25.233826</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.691284</Real>
+        <Real Name="Y">17.419264</Real>
+        <Real Name="Z">55.005985</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-182.95822</Real>
+        <Real Name="Y">1.8334503</Real>
+        <Real Name="Z">101.79441</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">150.07364</Real>
+        <Real Name="Y">-30.871582</Real>
+        <Real Name="Z">-84.71962</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">73.021225</Real>
+        <Real Name="Y">10.203926</Real>
+        <Real Name="Z">-48.89875</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-50.969887</Real>
+        <Real Name="Y">-306.68405</Real>
+        <Real Name="Z">-20.453796</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-20.45377</Real>
+        <Real Name="Y">115.88306</Real>
+        <Real Name="Z">-0.45542908</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">7.5702362</Real>
+        <Real Name="Y">309.97488</Real>
+        <Real Name="Z">258.59055</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+  <Simulation Name="Replica 1">
+    <ReplExOutput Name="Output">
+      <String Name="Replica Exchange Output"><![CDATA[
+Repl  There are 2 replicas:
+Replica-exchange molecular dynamics method for protein folding
+Replica exchange in temperature
+Replica exchange interval: 4
+Replica random seed: 98714
+Replica exchange information below: ex and x = exchange, pr = probability
+Replica exchange at step 4 time 0.00400
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange at step 8 time 0.00800
+Repl ex  0    1
+Repl pr      
+Replica exchange at step 12 time 0.01200
+Repl 0 <-> 1  [ not checked ]
+Repl ex  0 x  1
+Repl pr   1.0
+Replica exchange statistics
+Repl  3 attempts, 2 odd, 1 even
+Repl  average probabilities:
+Repl     0    1
+Repl      1.0
+Repl  number of exchanges:
+Repl     0    1
+Repl        2
+Repl  average number of exchanges:
+Repl     0    1
+Repl      1.0
+Repl        Empirical Transition Matrix
+Repl       1       2
+Repl  0.3333  0.6667  0
+Repl  0.6667  0.3333  1
+]]></String>
+    </ReplExOutput>
+    <Energy Name="Conserved En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">17.510857</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">17.510912</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">17.503202</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">17.50312</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">17.503132</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">19.745972</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">19.745237</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">19.744135</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">19.742321</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">19.73995</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">19.736788</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">19.732904</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">19.728432</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">17.496523</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">17.494547</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">17.492502</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">17.490181</Real>
+    </Energy>
+    <Energy Name="Kinetic En.">
+      <Real Name="Time 0.000000 Step 0 in frame 0">27.184233</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">27.032543</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">26.958456</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">26.982346</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">27.15382</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">33.022476</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">34.206444</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">35.542336</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">37.01931</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">38.619328</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">40.315876</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">42.074631</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">43.847614</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">34.764591</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">36.123768</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">37.546051</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">39.0084</Real>
+    </Energy>
+    <Energy Name="Potential">
+      <Real Name="Time 0.000000 Step 0 in frame 0">-9.6733761</Real>
+      <Real Name="Time 0.001000 Step 1 in frame 1">-9.5014782</Real>
+      <Real Name="Time 0.002000 Step 2 in frame 2">-9.4351006</Real>
+      <Real Name="Time 0.003000 Step 3 in frame 3">-9.4590721</Real>
+      <Real Name="Time 0.004000 Step 4 in frame 4">-9.6305351</Real>
+      <Real Name="Time 0.005000 Step 5 in frame 5">-13.262726</Real>
+      <Real Name="Time 0.006000 Step 6 in frame 6">-14.447428</Real>
+      <Real Name="Time 0.007000 Step 7 in frame 7">-15.784422</Real>
+      <Real Name="Time 0.008000 Step 8 in frame 8">-17.26321</Real>
+      <Real Name="Time 0.009000 Step 9 in frame 9">-18.865599</Real>
+      <Real Name="Time 0.010000 Step 10 in frame 10">-20.56531</Real>
+      <Real Name="Time 0.011000 Step 11 in frame 11">-22.326708</Real>
+      <Real Name="Time 0.012000 Step 12 in frame 12">-24.104164</Real>
+      <Real Name="Time 0.013000 Step 13 in frame 13">-17.192724</Real>
+      <Real Name="Time 0.014000 Step 14 in frame 14">-18.553877</Real>
+      <Real Name="Time 0.015000 Step 15 in frame 15">-19.978205</Real>
+      <Real Name="Time 0.016000 Step 16 in frame 16">-21.442875</Real>
+    </Energy>
+    <Real Name="Time 0.000000 Step 0 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[0][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.000000 Step 0 Box[1][2]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][0]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][1]">0</Real>
+    <Real Name="Time 0.000000 Step 0 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.000000 Step 0 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0049878336</Real>
+        <Real Name="Y">0.60003871</Real>
+        <Real Name="Z">0.24401598</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8450986</Real>
+        <Real Name="Y">0.68951088</Real>
+        <Real Name="Z">0.27000222</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.051154483</Real>
+        <Real Name="Y">0.6098752</Real>
+        <Real Name="Z">0.16074415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97497874</Real>
+        <Real Name="Y">0.63100076</Real>
+        <Real Name="Z">1.5690467</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.95126605</Real>
+        <Real Name="Y">0.61500007</Real>
+        <Real Name="Z">1.6603923</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.91607153</Real>
+        <Real Name="Y">0.70098728</Real>
+        <Real Name="Z">1.5408663</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.396927</Real>
+        <Real Name="Y">0.44702572</Real>
+        <Real Name="Z">1.1740447</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3299457</Real>
+        <Real Name="Y">0.47673112</Real>
+        <Real Name="Z">1.2356355</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3492131</Real>
+        <Real Name="Y">0.43086085</Real>
+        <Real Name="Z">1.0926543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6450241</Real>
+        <Real Name="Y">0.3130582</Real>
+        <Real Name="Z">0.30203694</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7037948</Real>
+        <Real Name="Y">0.32767984</Real>
+        <Real Name="Z">0.22791195</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5958234</Real>
+        <Real Name="Y">0.23439631</Real>
+        <Real Name="Z">0.2785013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7779906</Real>
+        <Real Name="Y">0.39201489</Real>
+        <Real Name="Z">0.024989925</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7093813</Real>
+        <Real Name="Y">0.41501191</Real>
+        <Real Name="Z">1.8243903</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8177674</Real>
+        <Real Name="Y">0.4757514</Real>
+        <Real Name="Z">0.048829585</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.20816714</Real>
+        <Real Name="Y">-0.71797431</Real>
+        <Real Name="Z">0.010975818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.65682852</Real>
+        <Real Name="Y">-0.44559601</Real>
+        <Real Name="Z">-0.19622456</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.078420706</Real>
+        <Real Name="Y">-1.3415372</Real>
+        <Real Name="Z">0.096203938</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.43867061</Real>
+        <Real Name="Y">-0.12663089</Real>
+        <Real Name="Z">0.16958587</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.1163926</Real>
+        <Real Name="Y">1.2029573</Real>
+        <Real Name="Z">0.57841772</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3942481</Real>
+        <Real Name="Y">0.64883482</Real>
+        <Real Name="Z">0.0979691</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.41536909</Real>
+        <Real Name="Y">0.038877822</Real>
+        <Real Name="Z">0.41476944</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.3165752</Real>
+        <Real Name="Y">0.03101692</Real>
+        <Real Name="Z">1.2145665</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.734094</Real>
+        <Real Name="Y">-2.0244336</Real>
+        <Real Name="Z">1.5976441</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.25620705</Real>
+        <Real Name="Y">0.31478664</Real>
+        <Real Name="Z">-0.3418262</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.14583358</Real>
+        <Real Name="Y">0.34318721</Real>
+        <Real Name="Z">-0.42373627</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.019476259</Real>
+        <Real Name="Y">0.51983035</Real>
+        <Real Name="Z">-0.45082945</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.15299252</Real>
+        <Real Name="Y">0.53591299</Real>
+        <Real Name="Z">-0.26971152</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.26438329</Real>
+        <Real Name="Y">-0.77197242</Real>
+        <Real Name="Z">-1.2067301</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.92311227</Real>
+        <Real Name="Y">1.1238943</Real>
+        <Real Name="Z">-1.0500419</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.000000 Step 0 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">8.9518738</Real>
+        <Real Name="Y">10.126022</Real>
+        <Real Name="Z">-383.92468</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-15.054081</Real>
+        <Real Name="Y">8.7835617</Real>
+        <Real Name="Z">109.98161</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">145.0733</Real>
+        <Real Name="Y">125.90257</Real>
+        <Real Name="Z">223.10434</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.894417</Real>
+        <Real Name="Y">-13.626793</Real>
+        <Real Name="Z">-38.735863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.715843</Real>
+        <Real Name="Y">-9.0983162</Real>
+        <Real Name="Z">-23.405556</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.6850433</Real>
+        <Real Name="Y">8.0224648</Real>
+        <Real Name="Z">13.504372</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">31.797379</Real>
+        <Real Name="Y">-10.314728</Real>
+        <Real Name="Z">-33.439079</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.476482</Real>
+        <Real Name="Y">8.5987606</Real>
+        <Real Name="Z">27.984818</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-36.246109</Real>
+        <Real Name="Y">16.41861</Real>
+        <Real Name="Z">54.091309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-290.90619</Real>
+        <Real Name="Y">-91.872864</Real>
+        <Real Name="Z">235.22827</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">225.62735</Real>
+        <Real Name="Y">82.504333</Real>
+        <Real Name="Z">-270.19894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">108.06937</Real>
+        <Real Name="Y">45.329948</Real>
+        <Real Name="Z">-56.291359</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-66.365723</Real>
+        <Real Name="Y">-204.77948</Real>
+        <Real Name="Z">21.695251</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-23.097099</Real>
+        <Real Name="Y">47.599464</Real>
+        <Real Name="Z">-24.246674</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-92.29879</Real>
+        <Real Name="Y">-23.593597</Real>
+        <Real Name="Z">144.65219</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.008000 Step 8 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[0][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.008000 Step 8 Box[1][2]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][0]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][1]">0</Real>
+    <Real Name="Time 0.008000 Step 8 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.008000 Step 8 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.005989329</Real>
+        <Real Name="Y">0.59960425</Real>
+        <Real Name="Z">0.23895578</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8580335</Real>
+        <Real Name="Y">0.68791038</Real>
+        <Real Name="Z">0.27450889</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.061665192</Real>
+        <Real Name="Y">0.61092097</Real>
+        <Real Name="Z">0.16192041</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97423959</Real>
+        <Real Name="Y">0.630714</Real>
+        <Real Name="Z">1.5712928</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94446111</Real>
+        <Real Name="Y">0.59317052</Real>
+        <Real Name="Z">1.6541543</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.90863705</Real>
+        <Real Name="Y">0.69711077</Real>
+        <Real Name="Z">1.5500776</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3964998</Real>
+        <Real Name="Y">0.4468289</Real>
+        <Real Name="Z">1.1685977</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3310622</Real>
+        <Real Name="Y">0.47334334</Real>
+        <Real Name="Z">1.2332292</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.346331</Real>
+        <Real Name="Y">0.43157807</Real>
+        <Real Name="Z">1.0885175</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6433228</Real>
+        <Real Name="Y">0.31616023</Real>
+        <Real Name="Z">0.30759373</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.702738</Real>
+        <Real Name="Y">0.33843589</Real>
+        <Real Name="Z">0.23592821</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6091882</Real>
+        <Real Name="Y">0.22976819</Real>
+        <Real Name="Z">0.2844947</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7792996</Real>
+        <Real Name="Y">0.39121339</Real>
+        <Real Name="Z">0.02452063</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6974192</Real>
+        <Real Name="Y">0.42101079</Real>
+        <Real Name="Z">1.8469568</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.818826</Real>
+        <Real Name="Y">0.47061008</Real>
+        <Real Name="Z">0.06052269</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.11757773</Real>
+        <Real Name="Y">-0.019413352</Real>
+        <Real Name="Z">-0.72920555</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.4907486</Real>
+        <Real Name="Y">-0.59906572</Real>
+        <Real Name="Z">1.097362</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.0630376</Real>
+        <Real Name="Y">0.41161385</Real>
+        <Real Name="Z">0.74015796</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.1024816</Real>
+        <Real Name="Y">-0.038517565</Real>
+        <Real Name="Z">0.2886174</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.6311326</Real>
+        <Real Name="Y">-2.7178357</Real>
+        <Real Name="Z">-1.1153309</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.8655234</Real>
+        <Real Name="Y">-0.51105589</Real>
+        <Real Name="Z">1.1692342</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.060124028</Real>
+        <Real Name="Y">-0.022644222</Real>
+        <Real Name="Z">-0.67807329</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.2303081</Real>
+        <Real Name="Y">-0.41628483</Real>
+        <Real Name="Z">-0.22253153</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.46764445</Real>
+        <Real Name="Y">0.10964781</Real>
+        <Real Name="Z">-0.44796345</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.22564617</Real>
+        <Real Name="Y">0.38080373</Real>
+        <Real Name="Z">0.6678437</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.0044155717</Real>
+        <Real Name="Y">1.4224664</Real>
+        <Real Name="Z">1.1750358</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.9458933</Real>
+        <Real Name="Y">-0.47944322</Real>
+        <Real Name="Z">0.67623401</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.11255254</Real>
+        <Real Name="Y">-0.088989057</Real>
+        <Real Name="Z">-0.071539149</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-1.16801</Real>
+        <Real Name="Y">0.46199492</Real>
+        <Real Name="Z">2.9890239</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.083593786</Real>
+        <Real Name="Y">-1.0349144</Real>
+        <Real Name="Z">2.229893</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.008000 Step 8 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-64.500107</Real>
+        <Real Name="Y">-106.42567</Real>
+        <Real Name="Z">-417.21143</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.19950867</Real>
+        <Real Name="Y">35.041397</Real>
+        <Real Name="Z">108.81167</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">177.61</Real>
+        <Real Name="Y">150.50708</Real>
+        <Real Name="Z">171.79062</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">15.698997</Real>
+        <Real Name="Y">-14.331871</Real>
+        <Real Name="Z">-37.632751</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">22.75808</Real>
+        <Real Name="Y">-8.0142937</Real>
+        <Real Name="Z">-23.75906</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-7.2965698</Real>
+        <Real Name="Y">7.6706924</Real>
+        <Real Name="Z">12.782566</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">29.140564</Real>
+        <Real Name="Y">-14.3414</Real>
+        <Real Name="Z">-32.97974</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-24.400028</Real>
+        <Real Name="Y">12.111423</Real>
+        <Real Name="Z">27.164577</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-35.901039</Real>
+        <Real Name="Y">16.905447</Real>
+        <Real Name="Z">54.424404</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-258.07733</Real>
+        <Real Name="Y">-52.450287</Real>
+        <Real Name="Z">175.90759</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">212.8786</Real>
+        <Real Name="Y">26.47406</Real>
+        <Real Name="Z">-197.02202</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">96.675217</Real>
+        <Real Name="Y">33.097923</Real>
+        <Real Name="Z">-53.513664</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-59.61908</Real>
+        <Real Name="Y">-231.46751</Real>
+        <Real Name="Z">9.0253601</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-26.94574</Real>
+        <Real Name="Y">75.055931</Real>
+        <Real Name="Z">-11.075729</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-78.221039</Real>
+        <Real Name="Y">70.167076</Real>
+        <Real Name="Z">213.2876</Real>
+      </Vector>
+    </Sequence>
+    <Real Name="Time 0.016000 Step 16 Box[0][0]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[0][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][1]">1.86206</Real>
+    <Real Name="Time 0.016000 Step 16 Box[1][2]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][0]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][1]">0</Real>
+    <Real Name="Time 0.016000 Step 16 Box[2][2]">1.86206</Real>
+    <Sequence Name="Time 0.016000 Step 16 X">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">0.0014099475</Real>
+        <Real Name="Y">0.58940381</Real>
+        <Real Name="Z">0.24167866</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.8540177</Real>
+        <Real Name="Y">0.67624474</Real>
+        <Real Name="Z">0.28081471</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.075623721</Real>
+        <Real Name="Y">0.59799689</Real>
+        <Real Name="Z">0.18183894</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.98185748</Real>
+        <Real Name="Y">0.62914616</Real>
+        <Real Name="Z">1.571604</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.97335869</Real>
+        <Real Name="Y">0.63104868</Real>
+        <Real Name="Z">1.666927</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.94000816</Real>
+        <Real Name="Y">0.71004111</Real>
+        <Real Name="Z">1.5421597</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3893729</Real>
+        <Real Name="Y">0.44759429</Real>
+        <Real Name="Z">1.1803213</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3376812</Real>
+        <Real Name="Y">0.47841489</Real>
+        <Real Name="Z">1.254755</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.3266979</Real>
+        <Real Name="Y">0.40042442</Real>
+        <Real Name="Z">1.1254655</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6489143</Real>
+        <Real Name="Y">0.3180455</Real>
+        <Real Name="Z">0.29607984</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7082195</Real>
+        <Real Name="Y">0.34094101</Real>
+        <Real Name="Z">0.22451863</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.6021434</Real>
+        <Real Name="Y">0.24066503</Real>
+        <Real Name="Z">0.2646623</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7750171</Real>
+        <Real Name="Y">0.39916423</Real>
+        <Real Name="Z">0.020688197</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7156733</Real>
+        <Real Name="Y">0.4075307</Real>
+        <Real Name="Z">1.8081114</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.7890438</Real>
+        <Real Name="Y">0.48907131</Real>
+        <Real Name="Z">0.050391514</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 V">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-0.20774576</Real>
+        <Real Name="Y">-0.57286853</Real>
+        <Real Name="Z">-0.34285799</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.33856916</Real>
+        <Real Name="Y">-1.4004967</Real>
+        <Real Name="Z">1.6255525</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">2.4273114</Real>
+        <Real Name="Y">-0.77439821</Real>
+        <Real Name="Z">2.896225</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.42057839</Real>
+        <Real Name="Y">-0.10071245</Real>
+        <Real Name="Z">0.16183321</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.570209</Real>
+        <Real Name="Y">0.80972606</Real>
+        <Real Name="Z">0.24616064</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">1.5919843</Real>
+        <Real Name="Y">0.45125833</Real>
+        <Real Name="Z">0.013387703</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.52939558</Real>
+        <Real Name="Y">0.024729343</Real>
+        <Real Name="Z">0.37319544</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.56629837</Real>
+        <Real Name="Y">0.22102354</Real>
+        <Real Name="Z">1.0528401</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.94382876</Real>
+        <Real Name="Y">-1.7395716</Real>
+        <Real Name="Z">2.3638034</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.23067445</Real>
+        <Real Name="Y">0.30649024</Real>
+        <Real Name="Z">-0.40256715</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.3907373</Real>
+        <Real Name="Y">1.2960894</Real>
+        <Real Name="Z">0.046697684</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.8242712</Real>
+        <Real Name="Y">0.30516517</Real>
+        <Real Name="Z">-1.282984</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-0.19892913</Real>
+        <Real Name="Y">0.37591052</Real>
+        <Real Name="Z">-0.25146261</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">0.49795806</Real>
+        <Real Name="Y">0.010643594</Real>
+        <Real Name="Z">-0.84650415</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-2.7428274</Real>
+        <Real Name="Y">0.28813386</Real>
+        <Real Name="Z">1.2155147</Real>
+      </Vector>
+    </Sequence>
+    <Sequence Name="Time 0.016000 Step 16 F">
+      <Int Name="Length">15</Int>
+      <Vector>
+        <Real Name="X">-71.80658</Real>
+        <Real Name="Y">68.801941</Real>
+        <Real Name="Z">-364.28366</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">3.7374649</Real>
+        <Real Name="Y">-0.12477875</Real>
+        <Real Name="Z">112.0171</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">136.45911</Real>
+        <Real Name="Y">2.7420578</Real>
+        <Real Name="Z">136.62473</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">23.638466</Real>
+        <Real Name="Y">-23.618427</Real>
+        <Real Name="Z">-37.764069</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-5.6398582</Real>
+        <Real Name="Y">7.0323143</Real>
+        <Real Name="Z">14.355347</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-9.3168449</Real>
+        <Real Name="Y">12.807716</Real>
+        <Real Name="Z">11.920631</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">34.758224</Real>
+        <Real Name="Y">-3.9805069</Real>
+        <Real Name="Z">-32.326981</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-60.161064</Real>
+        <Real Name="Y">9.1062698</Real>
+        <Real Name="Z">-17.994423</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-13.121216</Real>
+        <Real Name="Y">4.248909</Real>
+        <Real Name="Z">18.122276</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-316.19507</Real>
+        <Real Name="Y">-133.0134</Real>
+        <Real Name="Z">276.64075</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">244.08429</Real>
+        <Real Name="Y">103.30573</Real>
+        <Real Name="Z">-285.05554</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">118.7437</Real>
+        <Real Name="Y">60.946838</Real>
+        <Real Name="Z">-64.615013</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-73.573181</Real>
+        <Real Name="Y">-317.42291</Real>
+        <Real Name="Z">-33.423706</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">19.039402</Real>
+        <Real Name="Y">56.988865</Real>
+        <Real Name="Z">25.400909</Real>
+      </Vector>
+      <Vector>
+        <Real Name="X">-30.646835</Real>
+        <Real Name="Y">152.17938</Real>
+        <Real Name="Z">240.38171</Real>
+      </Vector>
+    </Sequence>
+  </Simulation>
+</ReferenceData>
index fba9b916bb66265a0b9af451a319273261774c0b..97f391224de1879da6a1c65d8d5fcf001afa357f 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "config.h"
 
+#include <regex>
+
 #include <gtest/gtest.h>
 
+#include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/topology/ifunc.h"
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/filestream.h"
 #include "gromacs/utility/path.h"
 #include "gromacs/utility/stringutil.h"
 
+#include "testutils/refdata.h"
 #include "testutils/testfilemanager.h"
 
+#include "energycomparison.h"
 #include "multisimtest.h"
+#include "trajectorycomparison.h"
 
 namespace gmx
 {
@@ -70,24 +79,278 @@ TEST_P(ReplicaExchangeEnsembleTest, ExitsNormally)
 
 /* Note, not all preprocessor implementations nest macro expansions
    the same way / at all, if we would try to duplicate less code. */
+
 #if GMX_LIB_MPI
-INSTANTIATE_TEST_CASE_P(WithDifferentControlVariables,
-                        ReplicaExchangeEnsembleTest,
-                        ::testing::Values("pcoupl = no", "pcoupl = Berendsen"));
+INSTANTIATE_TEST_CASE_P(
+        WithDifferentControlVariables,
+        ReplicaExchangeEnsembleTest,
+        ::testing::Combine(::testing::Values(NumRanksPerSimulation(1), NumRanksPerSimulation(2)),
+                           ::testing::Values(IntegrationAlgorithm::MD),
+                           ::testing::Values(TemperatureCoupling::VRescale),
+                           ::testing::Values(PressureCoupling::No, PressureCoupling::Berendsen)));
 #else
-INSTANTIATE_TEST_CASE_P(DISABLED_WithDifferentControlVariables,
-                        ReplicaExchangeEnsembleTest,
-                        ::testing::Values("pcoupl = no", "pcoupl = Berendsen"));
+INSTANTIATE_TEST_CASE_P(
+        DISABLED_WithDifferentControlVariables,
+        ReplicaExchangeEnsembleTest,
+        ::testing::Combine(::testing::Values(NumRanksPerSimulation(1), NumRanksPerSimulation(2)),
+                           ::testing::Values(IntegrationAlgorithm::MD),
+                           ::testing::Values(TemperatureCoupling::VRescale),
+                           ::testing::Values(PressureCoupling::No, PressureCoupling::Berendsen)));
 #endif
 
 //! Convenience typedef
 typedef MultiSimTest ReplicaExchangeTerminationTest;
 
-TEST_F(ReplicaExchangeTerminationTest, WritesCheckpointAfterMaxhTerminationAndThenRestarts)
+TEST_P(ReplicaExchangeTerminationTest, WritesCheckpointAfterMaxhTerminationAndThenRestarts)
 {
     mdrunCaller_->addOption("-replex", 1);
     runMaxhTest();
 }
 
+INSTANTIATE_TEST_CASE_P(InNvt,
+                        ReplicaExchangeTerminationTest,
+                        ::testing::Combine(::testing::Values(NumRanksPerSimulation(1)),
+                                           ::testing::Values(IntegrationAlgorithm::MD),
+                                           ::testing::Values(TemperatureCoupling::VRescale),
+                                           ::testing::Values(PressureCoupling::No)));
+
+/*! \brief Return replica exchange related output from logfile
+ *
+ * All replica exchange related output in log files start with 'Repl',
+ * making extraction easy. This function also removes the printing of
+ * energy differences, as the log files are compared exactly, and
+ * energy differences will slightly vary between runs.
+ *
+ * \param logFileName  Name of log file
+ * \return  Replica exchange related output in log file
+ */
+static std::string getReplicaExchangeOutputFromLogFile(const std::string& logFileName)
+{
+    TextInputFile logFile(logFileName);
+    std::string   replExOutput;
+    std::string   line;
+    while (logFile.readLine(&line))
+    {
+        // All replica exchange output lines starts with "Repl"
+        if (startsWith(line, "Repl"))
+        {
+            // This is an exact comparison, so we can't compare the energies which
+            // are slightly different per run. Energies are tested later.
+            const auto pos = line.find("dE_term");
+            if (pos != std::string::npos)
+            {
+                line.replace(line.begin() + pos, line.end(), "[ not checked ]\n");
+            }
+            replExOutput.append(line);
+        }
+    }
+    return replExOutput;
+}
+
+//! Convenience typedef
+typedef MultiSimTest ReplicaExchangeRegressionTest;
+
+/* Run replica exchange simulations, compare to reference data
+ *
+ * Reference data generated by
+ *
+ * GROMACS version:    2022-dev
+ * Precision:          single and double (separate reference data)
+ * Memory model:       64 bit
+ * MPI library:        MPI
+ * OpenMP support:     enabled (GMX_OPENMP_MAX_THREADS = 64)
+ * GPU support:        disabled
+ * SIMD instructions:  AVX2_256
+ * FFT library:        fftw-3.3.9-sse2-avx
+ * RDTSCP usage:       enabled
+ * TNG support:        enabled
+ * Hwloc support:      disabled
+ * Tracing support:    disabled
+ * C compiler:         /usr/local/bin/mpicc Clang 8.0.1
+ * C++ compiler:       /usr/local/bin/mpic++ Clang 8.0.1
+ *
+ */
+TEST_P(ReplicaExchangeRegressionTest, WithinTolerances)
+{
+    if (!mpiSetupValid())
+    {
+        // Can't test multi-sim without multiple simulations
+        return;
+    }
+
+    if (size_ != 4)
+    {
+        // Results are depending on number of ranks, and we can't have reference
+        // data for all cases. Restricting the regression tests to runs with 4 ranks.
+        // This allows testing 4 replicas with single rank, or 2 replicas with 2 ranks each.
+        return;
+    }
+    const auto& tcoupl = std::get<2>(GetParam());
+    const auto& pcoupl = std::get<3>(GetParam());
+
+    const int numSteps       = 16;
+    const int exchangePeriod = 4;
+    // grompp warns about generating velocities and using parrinello-rahman
+    const int maxWarnings = (pcoupl == PressureCoupling::ParrinelloRahman ? 1 : 0);
+
+    mdrunCaller_->addOption("-replex", exchangePeriod);
+    // Seeds need to be reproducible for regression, but can be different per simulation
+    mdrunCaller_->addOption("-reseed", 98713 + simulationNumber_);
+
+    SimulationRunner runner(&fileManager_);
+    runner.useTopGroAndNdxFromDatabase("tip3p5");
+
+    runGrompp(&runner, numSteps, true, maxWarnings);
+    ASSERT_EQ(0, runner.callMdrun(*mdrunCaller_));
+
+#if GMX_LIB_MPI
+    // Make sure all simulations are finished before checking the results.
+    MPI_Barrier(MdrunTestFixtureBase::communicator_);
+#endif
+
+    // We only test simulation results on one rank to avoid problems with reference file access.
+    if (rank_ == 0)
+    {
+        // Create reference data helper object
+        TestReferenceData refData;
+
+        // Specify how energy trajectory comparison must work
+        const auto hasConservedField =
+                !(tcoupl == TemperatureCoupling::No && pcoupl == PressureCoupling::No);
+        // Tolerances copied from simulator tests
+        EnergyTermsToCompare energyTermsToCompare{ {
+                { interaction_function[F_EPOT].longname,
+                  relativeToleranceAsPrecisionDependentUlp(60.0, 200, 160) },
+                { interaction_function[F_EKIN].longname,
+                  relativeToleranceAsPrecisionDependentUlp(60.0, 200, 160) },
+        } };
+        if (hasConservedField)
+        {
+            energyTermsToCompare.emplace(interaction_function[F_ECONSERVED].longname,
+                                         relativeToleranceAsPrecisionDependentUlp(50.0, 100, 80));
+        }
+        if (pcoupl != PressureCoupling::No)
+        {
+            energyTermsToCompare.emplace("Volume",
+                                         relativeToleranceAsPrecisionDependentUlp(10.0, 200, 160));
+        }
+
+        // Specify how trajectory frame matching must work.
+        const TrajectoryFrameMatchSettings trajectoryMatchSettings{ true,
+                                                                    true,
+                                                                    true,
+                                                                    ComparisonConditions::MustCompare,
+                                                                    ComparisonConditions::MustCompare,
+                                                                    ComparisonConditions::MustCompare,
+                                                                    MaxNumFrames::compareAllFrames() };
+        TrajectoryTolerances trajectoryTolerances = TrajectoryComparison::s_defaultTrajectoryTolerances;
+        // By default, velocity tolerance is MUCH tighter than force tolerance
+        trajectoryTolerances.velocities = trajectoryTolerances.forces;
+        // Build the functor that will compare reference and test
+        // trajectory frames in the chosen way.
+        TrajectoryComparison trajectoryComparison{ trajectoryMatchSettings, trajectoryTolerances };
+
+        // Loop over simulations
+        for (int simulationNumber = 0; simulationNumber < (size_ / numRanksPerSimulation_);
+             simulationNumber++)
+        {
+            TestReferenceChecker simulationChecker(refData.rootChecker().checkCompound(
+                    "Simulation", formatString("Replica %d", simulationNumber)));
+
+            const auto logFileName =
+                    std::regex_replace(runner.logFileName_,
+                                       std::regex(formatString("sim_%d", simulationNumber_)),
+                                       formatString("sim_%d", simulationNumber));
+            const auto energyFileName =
+                    std::regex_replace(runner.edrFileName_,
+                                       std::regex(formatString("sim_%d", simulationNumber_)),
+                                       formatString("sim_%d", simulationNumber));
+            const auto trajectoryFileName =
+                    std::regex_replace(runner.fullPrecisionTrajectoryFileName_,
+                                       std::regex(formatString("sim_%d", simulationNumber_)),
+                                       formatString("sim_%d", simulationNumber));
+
+            // Check log replica exchange related output (contains exchange statistics)
+            auto replicaExchangeOutputChecker =
+                    simulationChecker.checkCompound("ReplExOutput", "Output");
+            const auto replExOutput = getReplicaExchangeOutputFromLogFile(logFileName);
+            replicaExchangeOutputChecker.checkTextBlock(replExOutput, "Replica Exchange Output");
+
+            // Check that the energies agree with the refdata within tolerance.
+            checkEnergiesAgainstReferenceData(energyFileName, energyTermsToCompare, &simulationChecker);
+
+            // Check that the trajectories agree with the refdata within tolerance.
+            checkTrajectoryAgainstReferenceData(trajectoryFileName, trajectoryComparison, &simulationChecker);
+
+        } // end loop over simulations
+    }     // end testing simulations on one rank
+
+#if GMX_LIB_MPI
+    // Make sure testing is complete before returning - ranks delete temporary files on exit
+    MPI_Barrier(MdrunTestFixtureBase::communicator_);
+#endif
+}
+
+/*! \brief Helper struct printing custom test name
+ *
+ * Regression test results not only depend on the test parameters, but
+ * also on the total number of ranks and the precision. Names must
+ * reflect that to identify correct reference data.
+ */
+struct PrintReplicaExchangeParametersToString
+{
+    template<class ParamType>
+    std::string operator()(const testing::TestParamInfo<ParamType>& parameter) const
+    {
+        auto testIdentifier =
+                formatString("ReplExRegression_%s_%s_%s_%dRanks_%dRanksPerSimulation_%s",
+                             enumValueToString(std::get<1>(parameter.param)),
+                             enumValueToString(std::get<2>(parameter.param)),
+                             enumValueToString(std::get<3>(parameter.param)),
+                             gmx_node_num(),
+                             static_cast<int>(std::get<0>(parameter.param)),
+                             GMX_DOUBLE ? "d" : "s");
+        // Valid GTest names cannot include hyphens
+        testIdentifier.erase(std::remove(testIdentifier.begin(), testIdentifier.end(), '-'),
+                             testIdentifier.end());
+        return testIdentifier;
+    }
+};
+
+#if GMX_LIB_MPI
+INSTANTIATE_TEST_CASE_P(
+        ReplicaExchangeIsEquivalentToReferenceLeapFrog,
+        ReplicaExchangeRegressionTest,
+        ::testing::Combine(::testing::Values(NumRanksPerSimulation(1), NumRanksPerSimulation(2)),
+                           ::testing::Values(IntegrationAlgorithm::MD),
+                           ::testing::Values(TemperatureCoupling::VRescale, TemperatureCoupling::NoseHoover),
+                           ::testing::Values(PressureCoupling::CRescale, PressureCoupling::ParrinelloRahman)),
+        PrintReplicaExchangeParametersToString());
+INSTANTIATE_TEST_CASE_P(ReplicaExchangeIsEquivalentToReferenceVelocityVerlet,
+                        ReplicaExchangeRegressionTest,
+                        ::testing::Combine(::testing::Values(NumRanksPerSimulation(1),
+                                                             NumRanksPerSimulation(2)),
+                                           ::testing::Values(IntegrationAlgorithm::VV),
+                                           ::testing::Values(TemperatureCoupling::NoseHoover),
+                                           ::testing::Values(PressureCoupling::No)),
+                        PrintReplicaExchangeParametersToString());
+#else
+INSTANTIATE_TEST_CASE_P(
+        DISABLED_ReplicaExchangeIsEquivalentToReferenceLeapFrog,
+        ReplicaExchangeRegressionTest,
+        ::testing::Combine(::testing::Values(NumRanksPerSimulation(1), NumRanksPerSimulation(2)),
+                           ::testing::Values(IntegrationAlgorithm::MD),
+                           ::testing::Values(TemperatureCoupling::VRescale, TemperatureCoupling::NoseHoover),
+                           ::testing::Values(PressureCoupling::CRescale, PressureCoupling::ParrinelloRahman)),
+        PrintReplicaExchangeParametersToString());
+INSTANTIATE_TEST_CASE_P(DISABLED_ReplicaExchangeIsEquivalentToReferenceVelocityVerlet,
+                        ReplicaExchangeRegressionTest,
+                        ::testing::Combine(::testing::Values(NumRanksPerSimulation(1),
+                                                             NumRanksPerSimulation(2)),
+                                           ::testing::Values(IntegrationAlgorithm::VV),
+                                           ::testing::Values(TemperatureCoupling::NoseHoover),
+                                           ::testing::Values(PressureCoupling::No)),
+                        PrintReplicaExchangeParametersToString());
+#endif
 } // namespace test
 } // namespace gmx
index e358b9cd1ec12878815e88384df75eeec542f13a..c7a7ed17eb5bf75a4e8dea7be6c498c33cc18af8 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "config.h"
 
 #include "gromacs/topology/ifunc.h"
+#include "gromacs/utility/strconvert.h"
 #include "gromacs/utility/stringutil.h"
 
 #include "testutils/mpitest.h"
@@ -124,7 +125,8 @@ void executeRerunTest(TestFileManager*            fileManager,
         fprintf(stdout,
                 "Test system '%s' cannot run with %d ranks.\n"
                 "The supported numbers are: %s\n",
-                simulationName.c_str(), numRanksAvailable,
+                simulationName.c_str(),
+                numRanksAvailable,
                 reportNumbersOfPpRanksSupported(simulationName).c_str());
         return;
     }
@@ -169,7 +171,8 @@ TEST_P(MdrunRerunTest, WithinTolerances)
     SCOPED_TRACE(
             formatString("Comparing normal and rerun of simulation '%s' "
                          "with integrator '%s'",
-                         simulationName.c_str(), integrator.c_str()));
+                         simulationName.c_str(),
+                         integrator.c_str()));
 
     auto mdpFieldValues =
             prepareMdpFieldValues(simulationName.c_str(), integrator.c_str(), "no", "no");
@@ -178,8 +181,8 @@ TEST_P(MdrunRerunTest, WithinTolerances)
     const int            toleranceScaleFactor = (integrator == "bd") ? 2 : 1;
     EnergyTermsToCompare energyTermsToCompare{ {
             { interaction_function[F_EPOT].longname,
-              relativeToleranceAsPrecisionDependentUlp(10.0, 24 * toleranceScaleFactor,
-                                                       40 * toleranceScaleFactor) },
+              relativeToleranceAsPrecisionDependentUlp(
+                      10.0, 24 * toleranceScaleFactor, 40 * toleranceScaleFactor) },
     } };
 
     // Specify how trajectory frame matching must work
@@ -187,8 +190,13 @@ TEST_P(MdrunRerunTest, WithinTolerances)
                                                TrajectoryComparison::s_defaultTrajectoryTolerances };
 
     int numWarningsToTolerate = 0;
-    executeRerunTest(&fileManager_, &runner_, simulationName, numWarningsToTolerate, mdpFieldValues,
-                     energyTermsToCompare, trajectoryComparison);
+    executeRerunTest(&fileManager_,
+                     &runner_,
+                     simulationName,
+                     numWarningsToTolerate,
+                     mdpFieldValues,
+                     energyTermsToCompare,
+                     trajectoryComparison);
 }
 
 // TODO The time for OpenCL kernel compilation means these tests time
@@ -223,11 +231,13 @@ TEST_P(MdrunRerunFreeEnergyTest, WithinTolerances)
     SCOPED_TRACE(
             formatString("Comparing normal and rerun of simulation '%s' "
                          "with integrator '%s' for initial lambda state %d",
-                         simulationName.c_str(), integrator.c_str(), initLambdaState));
+                         simulationName.c_str(),
+                         integrator.c_str(),
+                         initLambdaState));
 
     auto mdpFieldValues =
             prepareMdpFieldValues(simulationName.c_str(), integrator.c_str(), "no", "no");
-    mdpFieldValues["other"] += formatString("\ninit-lambda-state = %d", initLambdaState);
+    mdpFieldValues["init-lambda-state"] = toString(initLambdaState);
 
     EnergyTermsToCompare energyTermsToCompare{
         { { interaction_function[F_EPOT].longname, relativeToleranceAsPrecisionDependentUlp(10.0, 24, 32) },
@@ -246,8 +256,13 @@ TEST_P(MdrunRerunFreeEnergyTest, WithinTolerances)
     // The md integrator triggers a warning for nearly decoupled
     // states, which we need to suppress. TODO sometimes?
     int numWarningsToTolerate = (integrator == "md") ? 1 : 0;
-    executeRerunTest(&fileManager_, &runner_, simulationName, numWarningsToTolerate, mdpFieldValues,
-                     energyTermsToCompare, trajectoryComparison);
+    executeRerunTest(&fileManager_,
+                     &runner_,
+                     simulationName,
+                     numWarningsToTolerate,
+                     mdpFieldValues,
+                     energyTermsToCompare,
+                     trajectoryComparison);
 }
 
 // TODO The time for OpenCL kernel compilation means these tests time
index 7d0bf8c017ccfc0781986fcf824787030009e2b4..271b6232e0eedffb1ace111f1d31e1b03b2b950b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -117,7 +117,8 @@ TEST_P(SimpleMdrunTest, WithinTolerances)
         fprintf(stdout,
                 "Test system '%s' cannot run with %d ranks.\n"
                 "The supported numbers are: %s\n",
-                simulationName.c_str(), numRanksAvailable,
+                simulationName.c_str(),
+                numRanksAvailable,
                 reportNumbersOfPpRanksSupported(simulationName).c_str());
         return;
     }
@@ -159,7 +160,7 @@ TEST_P(SimpleMdrunTest, WithinTolerances)
             auto frame = reader.frame();
             auto force = frame.f();
             int  atom  = 0;
-            for (auto& f : force)
+            for (const auto& f : force)
             {
                 std::string forceName = frame.frameName() + " F[" + toString(atom) + "]";
 
index 693f22c7731e59f85ee238261a1e39729e51e3c3..a1889c6c35274645fd96e4c3c22212f3f4ea3611 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -97,7 +97,8 @@ TEST_P(SimulatorComparisonTest, WithinTolerances)
         fprintf(stdout,
                 "Test system '%s' cannot run with %d ranks.\n"
                 "The supported numbers are: %s\n",
-                simulationName.c_str(), numRanksAvailable,
+                simulationName.c_str(),
+                numRanksAvailable,
                 reportNumbersOfPpRanksSupported(simulationName).c_str());
         return;
     }
@@ -123,11 +124,14 @@ TEST_P(SimulatorComparisonTest, WithinTolerances)
             "Comparing two simulations of '%s' "
             "with integrator '%s', '%s' temperature coupling, and '%s' pressure coupling "
             "switching environment variable '%s'",
-            simulationName.c_str(), integrator.c_str(), tcoupling.c_str(), pcoupling.c_str(),
+            simulationName.c_str(),
+            integrator.c_str(),
+            tcoupling.c_str(),
+            pcoupling.c_str(),
             environmentVariable.c_str()));
 
-    const auto mdpFieldValues = prepareMdpFieldValues(simulationName.c_str(), integrator.c_str(),
-                                                      tcoupling.c_str(), pcoupling.c_str());
+    const auto mdpFieldValues = prepareMdpFieldValues(
+            simulationName.c_str(), integrator.c_str(), tcoupling.c_str(), pcoupling.c_str());
 
     EnergyTermsToCompare energyTermsToCompare{ {
             { interaction_function[F_EPOT].longname, relativeToleranceAsPrecisionDependentUlp(60.0, 200, 160) },
@@ -243,11 +247,12 @@ INSTANTIATE_TEST_CASE_P(
 INSTANTIATE_TEST_CASE_P(
         SimulatorsAreEquivalentDefaultLegacy,
         SimulatorComparisonTest,
-        ::testing::Combine(::testing::Combine(::testing::Values("argon12", "tip3p5"),
-                                              ::testing::Values("md"),
-                                              ::testing::Values("no", "v-rescale", "berendsen"),
-                                              ::testing::Values("no", "Parrinello-Rahman")),
-                           ::testing::Values("GMX_USE_MODULAR_SIMULATOR")));
+        ::testing::Combine(
+                ::testing::Combine(::testing::Values("argon12", "tip3p5"),
+                                   ::testing::Values("md"),
+                                   ::testing::Values("no", "v-rescale", "berendsen", "nose-hoover"),
+                                   ::testing::Values("no", "Parrinello-Rahman")),
+                ::testing::Values("GMX_USE_MODULAR_SIMULATOR")));
 #else
 INSTANTIATE_TEST_CASE_P(
         DISABLED_SimulatorsAreEquivalentDefaultModular,
@@ -260,11 +265,12 @@ INSTANTIATE_TEST_CASE_P(
 INSTANTIATE_TEST_CASE_P(
         DISABLED_SimulatorsAreEquivalentDefaultLegacy,
         SimulatorComparisonTest,
-        ::testing::Combine(::testing::Combine(::testing::Values("argon12", "tip3p5"),
-                                              ::testing::Values("md"),
-                                              ::testing::Values("no", "v-rescale", "berendsen"),
-                                              ::testing::Values("no", "Parrinello-Rahman")),
-                           ::testing::Values("GMX_USE_MODULAR_SIMULATOR")));
+        ::testing::Combine(
+                ::testing::Combine(::testing::Values("argon12", "tip3p5"),
+                                   ::testing::Values("md"),
+                                   ::testing::Values("no", "v-rescale", "berendsen", "nose-hoover"),
+                                   ::testing::Values("no", "Parrinello-Rahman")),
+                ::testing::Values("GMX_USE_MODULAR_SIMULATOR")));
 #endif
 
 } // namespace
index 105baba9107d215a03b8eb6ff0c356c91254f1a8..cbc587effaf27c8666856b56d7aaa640431d13b8 100644 (file)
@@ -108,9 +108,7 @@ TEST_F(MdrunTerminationTest, CheckpointRestartAppendsByDefault)
         ASSERT_EQ(0, runner_.callMdrun(secondPart));
 
         auto logFileContents = TextReader::readFileToString(runner_.logFileName_);
-        EXPECT_NE(
-                std::string::npos,
-                logFileContents.find("Restarting from checkpoint, appending to previous log file"))
+        EXPECT_NE(std::string::npos, logFileContents.find("Restarting from checkpoint, appending to previous log file"))
                 << "appending was not detected";
     }
 }
@@ -297,9 +295,7 @@ TEST_F(MdrunTerminationTest, CheckpointRestartWorksEvenWithMissingCheckpointFile
 
         ASSERT_EQ(0, runner_.callMdrun(secondPart));
         auto logFileContents = TextReader::readFileToString(runner_.logFileName_);
-        EXPECT_EQ(
-                std::string::npos,
-                logFileContents.find("Restarting from checkpoint, appending to previous log file"))
+        EXPECT_EQ(std::string::npos, logFileContents.find("Restarting from checkpoint, appending to previous log file"))
                 << "appending was not detected";
     }
 }
index 242e476b79f519c857d1be5094102e8a1f719769..9802164ceb234a6c2d120c9eab0cf7116254a73a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -134,7 +134,8 @@ TEST_P(TpiTest, ReproducesOutput)
         ref_t                    = 298
         nsteps                   = %d
     )",
-                                                     randomSeed, nsteps);
+                                                     randomSeed,
+                                                     nsteps);
 
     runner_.useStringAsMdpFile(mdpFileContents);
     runTest();
index 72aea1dcef002cf2ed413ea73111962854be1ad4..c4df99d9103c90ccf925548ce8dece6962ffd852 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -309,11 +309,18 @@ static void checkPositionsAgainstReference(const TrajectoryFrame&              f
     SCOPED_TRACE("Comparing positions");
     if (shouldDoComparison(frame.x(), matchSettings.coordinatesComparison))
     {
-        auto positions = frame.x();
+        ArrayRef<const RVec> positions{};
+        std::vector<RVec>    shiftedPositions{};
         if (frame.hasBox() && (matchSettings.handlePbcIfPossible || matchSettings.requirePbcHandling))
         {
-            positions = putAtomsInBox(frame);
+            shiftedPositions = putAtomsInBox(frame);
+            positions        = shiftedPositions;
         }
+        else
+        {
+            positions = frame.x();
+        }
+
         if (!frame.hasBox() && matchSettings.requirePbcHandling)
         {
             ADD_FAILURE() << "Comparing positions required PBC handling, "
@@ -405,8 +412,8 @@ void checkTrajectoryAgainstReferenceData(const std::string&          trajectoryF
                                          const TrajectoryComparison& trajectoryComparison,
                                          TestReferenceChecker*       checker)
 {
-    checkTrajectoryAgainstReferenceData(trajectoryFilename, trajectoryComparison, checker,
-                                        MaxNumFrames::compareAllFrames());
+    checkTrajectoryAgainstReferenceData(
+            trajectoryFilename, trajectoryComparison, checker, MaxNumFrames::compareAllFrames());
 }
 
 void checkTrajectoryAgainstReferenceData(const std::string&          trajectoryFilename,
index ff08891e903d973702783eb6c507a2a0b369f81e..5543cb97862d0ca6421fc82c2d567ccf3ae84123 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -118,8 +118,8 @@ bool TrajectoryFrameReader::readNextFrame()
     {
         t_trxstatus* trajectoryFile;
         int          flags = TRX_READ_X | TRX_READ_V | TRX_READ_F;
-        nextFrameExists_   = read_first_frame(oenvGuard_.get(), &trajectoryFile, filename_.c_str(),
-                                            trxframeGuard_.get(), flags);
+        nextFrameExists_   = read_first_frame(
+                oenvGuard_.get(), &trajectoryFile, filename_.c_str(), trxframeGuard_.get(), flags);
         if (!trajectoryFile)
         {
             GMX_THROW(FileIOError("Could not open trajectory file " + filename_ + " for reading"));
diff --git a/src/programs/mdrun/tests/virtualsites.cpp b/src/programs/mdrun/tests/virtualsites.cpp
new file mode 100644 (file)
index 0000000..00f996b
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2021, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 Sanity checks for virtual sites
+ *
+ * The tests in this file test the virtual site implementation in two ways.
+ * 1) An artificial test system containing all virtual site types is run
+ *    end-to-end. The virtual sites are recalculated using a reference
+ *    implementation, and compared to the trajectory values. This ensures
+ *    that no relevant (real or virtual) coordinates were changed between
+ *    virtual site computation, and that the mdrun implementation agrees
+ *    with the reference implementation. The latter has the advantage to
+ *    be written closer to the analytical expressions, hence easier to
+ *    check by eye. Unlike the mdrun implementation, it can also be unit-
+ *    tested (see 2)). Since this is an end-to-end test, it also ensures
+ *    that virtual sites can be processed by grompp and run by mdrun.
+ * 2) The reference implementation is tested to have corresponding positions
+ *    and velocities. This is achieved by comparing virtual site positions
+ *    calculated from propagated real positions to virtual site positions
+ *    calculated by propagating virtual sites using the virtual velocities.
+ *
+ * Note, this only ensures that the position and velocity implementation
+ * match, not that they are actually correct. Some regression test systems
+ * include virtual sites, so there is some testing that no bugs are introduced.
+ * It would be good to have unit tests, though. This can either be achieved by
+ * refactoring the mdrun implementation, or adding them to the reference
+ * implementation here. See also #3911.
+ *
+ * \author Pascal Merz <pascal.merz@me.com>
+ * \ingroup module_mdrun_integration_tests
+ */
+#include "gmxpre.h"
+
+#include "config.h"
+
+#include "gromacs/topology/idef.h"
+#include "gromacs/topology/ifunc.h"
+#include "gromacs/trajectoryanalysis/topologyinformation.h"
+#include "gromacs/utility/stringutil.h"
+
+#include "testutils/mpitest.h"
+#include "testutils/simulationdatabase.h"
+#include "testutils/testmatchers.h"
+
+#include "gromacs/utility/strconvert.h"
+
+#include "moduletest.h"
+#include "simulatorcomparison.h"
+#include "trajectoryreader.h"
+
+namespace gmx::test
+{
+namespace
+{
+using VirtualSiteTestParams = std::tuple<std::string, std::string, std::string>;
+class VirtualSiteTest : public MdrunTestFixture, public ::testing::WithParamInterface<VirtualSiteTestParams>
+{
+public:
+    struct VirtualSite;
+
+    /*! \brief Check against reference implementation
+     *
+     * Check that the positions and velocities of virtual sites are equal to the reference
+     * implementation, within a given tolerance. This loops over the trajectory, calculates
+     * the virtual site positions and velocities using a reference implementation, and
+     * compares it with the reported virtual site positions and velocities.
+     *
+     * The expectation is that the trajectory and the reference calculations are identical.
+     * This ensures that neither the real atoms nor the virtual sites are changed between
+     * virtual site calculation and trajectory printing. The reference implementation is
+     * also closer to the analytically derived equations than the mdrun implementation,
+     * making it easier to verify. Finally, the reference implementation is tested (within
+     * this file), which is a reasonable work-around for the fact that the actual implementation
+     * doesn't have unit tests.
+     *
+     * Note that the reference implementation does not take into account PBC. It's intended
+     * to be used with simple test cases in which molecules are ensured not to be broken
+     * across periodic boundaries.
+     */
+    static void checkVirtualSitesAgainstReferenceImplementation(const std::string& trajectoryName,
+                                                                ArrayRef<const VirtualSite> virtualSites,
+                                                                FloatingPointTolerance tolerance)
+    {
+        SCOPED_TRACE(
+                "Checking virtual site positions and velocities against reference implementation.");
+        TrajectoryFrameReader trajectoryFrameReader(trajectoryName);
+        while (trajectoryFrameReader.readNextFrame())
+        {
+            const auto frame = trajectoryFrameReader.frame();
+            SCOPED_TRACE(formatString("Checking frame %s", frame.frameName().c_str()));
+            std::vector<RVec> positions;
+            std::vector<RVec> velocities;
+            std::vector<RVec> refPositions;
+            std::vector<RVec> refVelocities;
+            for (const auto& vSite : virtualSites)
+            {
+                auto [refPosition, refVelocity] = vSite.calculate(frame.x(), frame.v());
+                refPositions.emplace_back(refPosition);
+                refVelocities.emplace_back(refVelocity);
+                positions.emplace_back(frame.x().at(vSite.atomIdx));
+                velocities.emplace_back(frame.v().at(vSite.atomIdx));
+            }
+            EXPECT_THAT(refPositions, Pointwise(RVecEq(tolerance), positions));
+            EXPECT_THAT(refVelocities, Pointwise(RVecEq(tolerance), velocities));
+        }
+    }
+
+    /*! \brief Check the reference implementation
+     *
+     * This tests that the reference implementation position and velocities correspond.
+     * This is done by
+     *   a) generating real atom starting positions (x(t)) and half-step velocities (v(t+dt/2))
+     *   b) propagating the real atoms positions by one time step x(t+dt) = x(t) + dt*v(t+dt/2)
+     *   c) calculating the half-step positions x(t+dt/2) = 0.5 * (x(t) + x(t+dt))
+     *   d) calculating the virtual position xv(t) := xv(x(t)) and xv1(t+dt) := xv(x(t+dt))
+     *      using the reference implementation
+     *   e) calculating the virtual velocity vv(t+dt/2) := vv(x(t+dt/2), v(t+dt/2))
+     *      using the reference implementation
+     *   f) calculating the virtual position xv2(t+dt) = xv(t) + dt*xv(t+dt/2)
+     *   g) comparing xv1(t+dt) and xv2(t+dt)
+     * If the calculation of the virtual positions and velocities correspond, xv1 and xv2 will
+     * be identical up to some integration error.
+     *
+     * Maybe unused because this test runs only in double precision.
+     */
+    [[maybe_unused]] static void checkReferenceImplementation()
+    {
+        SCOPED_TRACE("Checking virtual site reference implementation.");
+        // Randomly generated real atom positions and velocities
+        std::vector<RVec> startPositions     = { { 2.641321, 2.076298, 2.138602 },
+                                             { 3.776765, 3.154901, 1.556379 },
+                                             { 2.376669, 1.166706, 2.457044 },
+                                             { 3.242320, 2.142465, 2.023578 } };
+        std::vector<RVec> halfStepVelocities = { { 0.154667, 0.319010, 0.458749 },
+                                                 { -0.010590, -0.191858, -0.096820 },
+                                                 { -0.008609, 0.004656, 0.448852 },
+                                                 { 0.411874, -0.038205, -0.151459 } };
+        // Virtual site definitions with randomly generated parameters
+        std::vector<VirtualSite> virtualSites = {
+            { F_VSITE1, 6, { 0 }, {} },
+            { F_VSITE2, 6, { 0, 1 }, { 0.710573 } },
+            { F_VSITE2FD, 6, { 0, 1 }, { 0.292430 } },
+            { F_VSITE3, 6, { 0, 1, 2 }, { 0.060990, 0.543636 } },
+            { F_VSITE3FD, 6, { 0, 1, 2 }, { 0.125024, 0.444587 } },
+            { F_VSITE3FAD, 6, { 0, 1, 2 }, { 0.414850, 0.349767 } },
+            { F_VSITE3OUT, 6, { 0, 1, 2 }, { 0.779323, 0.093773, 0.743164 } },
+            { F_VSITE4FDN, 6, { 0, 1, 2, 3 }, { 0.975111, 0.952180, 0.757594 } }
+        };
+
+        // Make integration step
+        const real        timeStep = 1e-5;
+        std::vector<RVec> endPositions;
+        std::vector<RVec> halfStepPositions;
+        GMX_RELEASE_ASSERT(startPositions.size() == halfStepVelocities.size(),
+                           "Need positions and velocities for every real atom.");
+        const auto numRealAtoms = startPositions.size();
+        for (auto idx = decltype(numRealAtoms){ 0 }; idx < numRealAtoms; idx++)
+        {
+            endPositions.emplace_back(startPositions[idx] + timeStep * halfStepVelocities[idx]);
+            halfStepPositions.emplace_back(startPositions[idx]
+                                           + real(0.5) * timeStep * halfStepVelocities[idx]);
+        }
+
+        // Check that displacement equals the calculated velocities
+        for (const auto& vSite : virtualSites)
+        {
+            SCOPED_TRACE(formatString("Checking %s", interaction_function[vSite.type].longname));
+
+            // GCC 7 falsely flags unused "variables" in structured bindings, GCC 8+ fixed this
+            // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81767
+            // clang-format off
+            GCC_DIAGNOSTIC_IGNORE(-Wunused-variable)
+            // clang-format on
+            /* Calculate start and end virtual position
+             *
+             * The reference implementation always calculates the virtual velocity, but
+             * since we don't have real velocities at full steps, these virtual velocities
+             * are unprecise. We don't need them anyway, so we'll just ignore them.
+             */
+            const auto [startVPosition, vVelocityUnused1] =
+                    vSite.calculate(startPositions, halfStepVelocities);
+            const auto [endVPosition1, vVelocityUnused2] =
+                    vSite.calculate(endPositions, halfStepVelocities);
+
+            /* Calculate virtual velocity at half step using reference implementation
+             *
+             * The virtual positions are exact, but we don't need them.
+             */
+            const auto [halfStepVPositionUnused, halfStepVVelocity] =
+                    vSite.calculate(halfStepPositions, halfStepVelocities);
+            GCC_DIAGNOSTIC_RESET
+
+            // We can now integrate the virtual positions using the half step velocity
+            const auto endVPosition2 = startVPosition + timeStep * halfStepVVelocity;
+
+            /* We can now calculate the displacement of the virtual site in two ways:
+             *   (1) Using endVPosition1, calculated by advancing the real positions
+             *       and calculating the virtual position from them.
+             *   (2) Using endVPosition2, calculated by advancing the virtual position
+             *       by the virtual velocity.
+             * Comparing the difference of the displacement with relative tolerance makes
+             * this at least somewhat independent of the choice of time step and coordinates -
+             * assuming that the displacement doesn't go to zero, of course!
+             */
+            const auto displacement1 = endVPosition1 - startVPosition;
+            const auto displacement2 = endVPosition2 - startVPosition;
+            ASSERT_GT(std::abs(displacement1[XX]), 0)
+                    << "adjust choice of coordinates or time step.";
+            ASSERT_GT(std::abs(displacement1[YY]), 0)
+                    << "adjust choice of coordinates or time step.";
+            ASSERT_GT(std::abs(displacement1[ZZ]), 0)
+                    << "adjust choice of coordinates or time step.";
+
+            EXPECT_REAL_EQ_TOL(displacement1[XX],
+                               displacement2[XX],
+                               relativeToleranceAsFloatingPoint(displacement1[XX], 1e-9));
+            EXPECT_REAL_EQ_TOL(displacement1[YY],
+                               displacement2[YY],
+                               relativeToleranceAsFloatingPoint(displacement1[YY], 1e-9));
+            EXPECT_REAL_EQ_TOL(displacement1[ZZ],
+                               displacement2[ZZ],
+                               relativeToleranceAsFloatingPoint(displacement1[ZZ], 1e-9));
+        }
+    }
+
+    //! Holds parameters of virtual site and allows calculation
+    struct VirtualSite
+    {
+        //! Type of virtual site
+        int type;
+        //! Index of virtual site
+        int atomIdx;
+        //! Indices of constructing atoms
+        std::vector<int> constructingAtomIdx;
+        //! Construction parameters
+        std::vector<real> parameters;
+
+        //! Dispatch function to compute position and velocity of virtual site from reference implementation based on \p type
+        [[nodiscard]] std::tuple<RVec, RVec> calculate(ArrayRef<const RVec> constructingPositions,
+                                                       ArrayRef<const RVec> constructingVelocities) const;
+
+    private:
+        //! Templated reference implementation of virtual site position and velocity calculation
+        template<int vsiteType>
+        [[nodiscard]] std::tuple<RVec, RVec> calculateVSite(ArrayRef<const RVec> positions,
+                                                            ArrayRef<const RVec> velocities) const;
+    };
+
+    /*! \brief Helper function returning a list of virtual sites from the topology
+     *
+     * This also prints the indices of the virtual sites. If any tests fail, this
+     * can be used to understand which type is failing.
+     */
+    static std::vector<VirtualSite> vSiteList(const TopologyInformation& topologyInformation)
+    {
+        std::vector<VirtualSite> virtualSites;
+        const auto&              localTopology = *topologyInformation.expandedTopology();
+        printf("Reading virtual site types...\n");
+        for (int vsiteType = F_VSITE1; vsiteType <= F_VSITEN; vsiteType++)
+        {
+            const auto& interactionList = localTopology.idef.il.at(vsiteType);
+            if (vsiteType == F_VSITE4FD || interactionList.empty())
+            {
+                // 4FD is deprecated. Interaction list empty means system doesn't contain this type.
+                continue;
+            }
+            const int   numConstructingAtoms = interaction_function[vsiteType].nratoms - 1;
+            const int   defaultIncrement     = numConstructingAtoms + 2;
+            std::string indexString;
+
+            for (int i = 0; i < interactionList.size();)
+            {
+                const int parameterIdx   = interactionList.iatoms[i];
+                const int virtualSiteIdx = interactionList.iatoms[i + 1];
+                if (!indexString.empty())
+                {
+                    indexString += ", ";
+                }
+                indexString += toString(virtualSiteIdx);
+
+                if (vsiteType == F_VSITEN)
+                {
+                    const int vSiteNConstructingAtoms =
+                            localTopology.idef.iparams[parameterIdx].vsiten.n;
+                    VirtualSite vSite{ vsiteType, virtualSiteIdx, { interactionList.iatoms[i + 2] }, {} };
+                    for (int j = 3; j < 3 * vSiteNConstructingAtoms; j += 3)
+                    {
+                        vSite.constructingAtomIdx.push_back(interactionList.iatoms[j + 2]);
+                        vSite.parameters.push_back(
+                                localTopology.idef.iparams[interactionList.iatoms[j]].vsiten.a);
+                    }
+                    virtualSites.push_back(std::move(vSite));
+                    i += 3 * vSiteNConstructingAtoms;
+                }
+                else
+                {
+                    virtualSites.emplace_back(VirtualSite{
+                            vsiteType,
+                            virtualSiteIdx,
+                            { &interactionList.iatoms[i + 2],
+                              &interactionList.iatoms[i + 2 + numConstructingAtoms] },
+                            { localTopology.idef.iparams[parameterIdx].generic.buf,
+                              localTopology.idef.iparams[parameterIdx].generic.buf + MAXFORCEPARAM } });
+                    i += defaultIncrement;
+                }
+            }
+        }
+        return virtualSites;
+    }
+};
+
+// check-source gets confused by these
+//! \cond
+template<>
+[[nodiscard]] std::tuple<RVec, RVec>
+VirtualSiteTest::VirtualSite::calculateVSite<F_VSITE1>(ArrayRef<const RVec> positions,
+                                                       ArrayRef<const RVec> velocities) const
+{
+    return { positions[constructingAtomIdx.at(0)], velocities[constructingAtomIdx.at(0)] };
+}
+template<>
+[[nodiscard]] std::tuple<RVec, RVec>
+VirtualSiteTest::VirtualSite::calculateVSite<F_VSITE2>(ArrayRef<const RVec> positions,
+                                                       ArrayRef<const RVec> velocities) const
+{
+    const auto& a = parameters[0];
+    return { (1 - a) * positions[constructingAtomIdx.at(0)] + a * positions[constructingAtomIdx.at(1)],
+             (1 - a) * velocities[constructingAtomIdx.at(0)] + a * velocities[constructingAtomIdx.at(1)] };
+}
+template<>
+[[nodiscard]] std::tuple<RVec, RVec>
+VirtualSiteTest::VirtualSite::calculateVSite<F_VSITE2FD>(ArrayRef<const RVec> positions,
+                                                         ArrayRef<const RVec> velocities) const
+{
+    const auto& a   = parameters[0];
+    const auto& ri  = positions[constructingAtomIdx.at(0)];
+    const auto& rj  = positions[constructingAtomIdx.at(1)];
+    const auto& vi  = velocities[constructingAtomIdx.at(0)];
+    const auto& vj  = velocities[constructingAtomIdx.at(1)];
+    const auto  rij = rj - ri;
+    const auto  vij = vj - vi;
+
+    return { ri + (a / rij.norm()) * rij,
+             vi + (a / rij.norm()) * (vij - rij * (vij.dot(rij) / rij.norm2())) };
+}
+template<>
+[[nodiscard]] std::tuple<RVec, RVec>
+VirtualSiteTest::VirtualSite::calculateVSite<F_VSITE3>(ArrayRef<const RVec> positions,
+                                                       ArrayRef<const RVec> velocities) const
+{
+    const auto& a  = parameters[0];
+    const auto& b  = parameters[1];
+    const auto& ri = positions[constructingAtomIdx.at(0)];
+    const auto& rj = positions[constructingAtomIdx.at(1)];
+    const auto& rk = positions[constructingAtomIdx.at(2)];
+    const auto& vi = velocities[constructingAtomIdx.at(0)];
+    const auto& vj = velocities[constructingAtomIdx.at(1)];
+    const auto& vk = velocities[constructingAtomIdx.at(2)];
+
+    return { (1 - a - b) * ri + a * rj + b * rk, (1 - a - b) * vi + a * vj + b * vk };
+}
+template<>
+[[nodiscard]] std::tuple<RVec, RVec>
+VirtualSiteTest::VirtualSite::calculateVSite<F_VSITE3FD>(ArrayRef<const RVec> positions,
+                                                         ArrayRef<const RVec> velocities) const
+{
+    const auto& a   = parameters[0];
+    const auto& b   = parameters[1];
+    const auto& ri  = positions[constructingAtomIdx.at(0)];
+    const auto& rj  = positions[constructingAtomIdx.at(1)];
+    const auto& rk  = positions[constructingAtomIdx.at(2)];
+    const auto& vi  = velocities[constructingAtomIdx.at(0)];
+    const auto& vj  = velocities[constructingAtomIdx.at(1)];
+    const auto& vk  = velocities[constructingAtomIdx.at(2)];
+    const auto  rij = rj - ri;
+    const auto  rjk = rk - rj;
+    const auto  vij = vj - vi;
+    const auto  vjk = vk - vj;
+
+    // TODO: Should be uncommented after resolution of #3909
+    const auto rijk = /*(1 - a) **/ rij + a * rjk;
+    const auto vijk = /*(1 - a) **/ vij + a * vjk;
+
+    return { ri + (b / rijk.norm()) * rijk,
+             vi + (b / rijk.norm()) * (vijk - rijk * (vijk.dot(rijk) / rijk.norm2())) };
+}
+template<>
+[[nodiscard]] std::tuple<RVec, RVec>
+VirtualSiteTest::VirtualSite::calculateVSite<F_VSITE3FAD>(ArrayRef<const RVec> positions,
+                                                          ArrayRef<const RVec> velocities) const
+{
+    // Note: a = d * cos(theta)
+    //       b = d * sin(theta)
+    const auto& a   = parameters[0];
+    const auto& b   = parameters[1];
+    const auto& ri  = positions[constructingAtomIdx.at(0)];
+    const auto& rj  = positions[constructingAtomIdx.at(1)];
+    const auto& rk  = positions[constructingAtomIdx.at(2)];
+    const auto& vi  = velocities[constructingAtomIdx.at(0)];
+    const auto& vj  = velocities[constructingAtomIdx.at(1)];
+    const auto& vk  = velocities[constructingAtomIdx.at(2)];
+    const auto  rij = rj - ri;
+    const auto  rjk = rk - rj;
+    const auto  vij = vj - vi;
+    const auto  vjk = vk - vj;
+
+    const auto rPerp        = rjk - rij * (rij.dot(rjk) / rij.norm2());
+    const auto dtRijNormRij = (1 / rij.norm()) * (vij - rij * (vij.dot(rij) / rij.norm2()));
+    const auto vPerp        = vjk
+                       - rij
+                                 * ((vij.dot(rjk) + rij.dot(vjk)) / rij.norm2()
+                                    - 2 * rij.dot(rjk) * rij.dot(vij) / rij.norm2() / rij.norm2())
+                       - vij * (rij.dot(rjk) / rij.norm2());
+    const auto dtRPerpNormRPerp =
+            (1 / rPerp.norm()) * (vPerp - rPerp * (vPerp.dot(rPerp) / rPerp.norm2()));
+
+    return { ri + (a / rij.norm()) * rij + (b / rPerp.norm()) * rPerp,
+             vi + a * dtRijNormRij + b * dtRPerpNormRPerp };
+}
+template<>
+[[nodiscard]] std::tuple<RVec, RVec>
+VirtualSiteTest::VirtualSite::calculateVSite<F_VSITE3OUT>(ArrayRef<const RVec> positions,
+                                                          ArrayRef<const RVec> velocities) const
+{
+    const auto& a   = parameters[0];
+    const auto& b   = parameters[1];
+    const auto& c   = parameters[2];
+    const auto& ri  = positions[constructingAtomIdx.at(0)];
+    const auto& rj  = positions[constructingAtomIdx.at(1)];
+    const auto& rk  = positions[constructingAtomIdx.at(2)];
+    const auto& vi  = velocities[constructingAtomIdx.at(0)];
+    const auto& vj  = velocities[constructingAtomIdx.at(1)];
+    const auto& vk  = velocities[constructingAtomIdx.at(2)];
+    const auto  rij = rj - ri;
+    const auto  rik = rk - ri;
+    const auto  vij = vj - vi;
+    const auto  vik = vk - vi;
+
+    return { ri + a * rij + b * rik + c * rij.cross(rik),
+             vi + a * vij + b * vik + c * (vij.cross(rik) + rij.cross(vik)) };
+}
+template<>
+[[nodiscard]] std::tuple<RVec, RVec>
+VirtualSiteTest::VirtualSite::calculateVSite<F_VSITE4FDN>(ArrayRef<const RVec> positions,
+                                                          ArrayRef<const RVec> velocities) const
+{
+    const auto& a   = parameters[0];
+    const auto& b   = parameters[1];
+    const auto& c   = parameters[2];
+    const auto& ri  = positions[constructingAtomIdx.at(0)];
+    const auto& rj  = positions[constructingAtomIdx.at(1)];
+    const auto& rk  = positions[constructingAtomIdx.at(2)];
+    const auto& rl  = positions[constructingAtomIdx.at(3)];
+    const auto& vi  = velocities[constructingAtomIdx.at(0)];
+    const auto& vj  = velocities[constructingAtomIdx.at(1)];
+    const auto& vk  = velocities[constructingAtomIdx.at(2)];
+    const auto& vl  = velocities[constructingAtomIdx.at(3)];
+    const auto  rij = rj - ri;
+    const auto  rik = rk - ri;
+    const auto  ril = rl - ri;
+    const auto  vij = vj - vi;
+    const auto  vik = vk - vi;
+    const auto  vil = vl - vi;
+
+    const auto rja = a * rik - rij;
+    const auto rjb = b * ril - rij;
+    const auto rm  = rja.cross(rjb);
+
+    const auto vja = a * vik - vij;
+    const auto vjb = b * vil - vij;
+    const auto vm  = vja.cross(rjb) + rja.cross(vjb);
+
+    return { ri + (c / rm.norm()) * rm, vi + (c / rm.norm()) * (vm - rm * (vm.dot(rm) / rm.norm2())) };
+}
+
+template<>
+[[nodiscard]] std::tuple<RVec, RVec>
+VirtualSiteTest::VirtualSite::calculateVSite<F_VSITEN>(ArrayRef<const RVec> positions,
+                                                       ArrayRef<const RVec> velocities) const
+{
+    const auto& ri = positions[constructingAtomIdx.at(0)];
+    const auto& vi = velocities[constructingAtomIdx.at(0)];
+    GMX_RELEASE_ASSERT(constructingAtomIdx.size() == parameters.size() - 1,
+                       "VSITEN atom / parameters mismatch.");
+
+    RVec rSum(0, 0, 0);
+    RVec vSum(0, 0, 0);
+
+    const auto parameterSize = parameters.size();
+    for (auto idx = decltype(parameterSize){ 0 }; idx < parameterSize; idx++)
+    {
+        rSum += parameters[idx] * (positions[constructingAtomIdx[idx + 1]] - ri);
+        vSum += parameters[idx] * (velocities[constructingAtomIdx[idx + 1]] - vi);
+    }
+
+    return { ri + rSum, vi + vSum };
+}
+
+[[nodiscard]] std::tuple<RVec, RVec>
+VirtualSiteTest::VirtualSite::calculate(ArrayRef<const RVec> constructingPositions,
+                                        ArrayRef<const RVec> constructingVelocities) const
+{
+    switch (type)
+    {
+        case F_VSITE1:
+            return calculateVSite<F_VSITE1>(constructingPositions, constructingVelocities);
+        case F_VSITE2:
+            return calculateVSite<F_VSITE2>(constructingPositions, constructingVelocities);
+        case F_VSITE2FD:
+            return calculateVSite<F_VSITE2FD>(constructingPositions, constructingVelocities);
+        case F_VSITE3:
+            return calculateVSite<F_VSITE3>(constructingPositions, constructingVelocities);
+        case F_VSITE3FD:
+            return calculateVSite<F_VSITE3FD>(constructingPositions, constructingVelocities);
+        case F_VSITE3FAD:
+            return calculateVSite<F_VSITE3FAD>(constructingPositions, constructingVelocities);
+        case F_VSITE3OUT:
+            return calculateVSite<F_VSITE3OUT>(constructingPositions, constructingVelocities);
+        case F_VSITE4FDN:
+            return calculateVSite<F_VSITE4FDN>(constructingPositions, constructingVelocities);
+        case F_VSITEN:
+            return calculateVSite<F_VSITEN>(constructingPositions, constructingVelocities);
+        default: throw NotImplementedError("Unknown virtual site type");
+    }
+}
+//! \endcond
+
+TEST(VirtualSiteVelocityTest, ReferenceIsCorrect)
+{
+    // Test is too sensitive to run in single precision
+    if constexpr (GMX_DOUBLE)
+    {
+        VirtualSiteTest::checkReferenceImplementation();
+    }
+}
+
+TEST_P(VirtualSiteTest, WithinToleranceOfReference)
+{
+    const auto& params         = GetParam();
+    const auto& integrator     = std::get<0>(params);
+    const auto& tcoupling      = std::get<1>(params);
+    const auto& pcoupling      = std::get<2>(params);
+    const real  timeStep       = 0.001;
+    const auto& simulationName = "vsite_test";
+
+    if (integrator == "md-vv" && pcoupling == "parrinello-rahman")
+    {
+        // Parrinello-Rahman is not implemented in md-vv
+        return;
+    }
+
+    if ((integrator == "sd" || integrator == "bd") && tcoupling != "no")
+    {
+        // bd and sd handle temperature coupling implicitly and would set tcoupling to "no" anyway
+        return;
+    }
+
+    // Prepare mdp input
+    auto mdpFieldValues = prepareMdpFieldValues(simulationName, integrator, tcoupling, pcoupling);
+    mdpFieldValues["nsteps"]      = "8";
+    mdpFieldValues["nstxout"]     = "4";
+    mdpFieldValues["nstvout"]     = "4";
+    mdpFieldValues["dt"]          = toString(timeStep);
+    mdpFieldValues["constraints"] = "none";
+    if (pcoupling == "parrinello-rahman")
+    {
+        mdpFieldValues["tau-p"] = "2";
+    }
+
+    // Run grompp
+    runner_.useTopGroAndNdxFromDatabase(simulationName);
+    runner_.useStringAsMdpFile(prepareMdpFileContents(mdpFieldValues));
+    runGrompp(&runner_);
+    // Run mdrun
+    runMdrun(&runner_);
+
+    TopologyInformation topologyInformation;
+    topologyInformation.fillFromInputFile(runner_.tprFileName_);
+    const auto virtualSites = vSiteList(topologyInformation);
+
+    // This is in line with other tests (e.g. exact continuation, rerun), which
+    // never reach the same reproducibility for BD as for the other integrators.
+    const auto tolerance =
+            (integrator == "bd") ? relativeToleranceAsUlp(1.0, 100) : defaultRealTolerance();
+
+    checkVirtualSitesAgainstReferenceImplementation(
+            runner_.fullPrecisionTrajectoryFileName_, virtualSites, tolerance);
+}
+
+INSTANTIATE_TEST_CASE_P(
+        VelocitiesConformToExpectations,
+        VirtualSiteTest,
+        ::testing::Combine(::testing::Values("md", "md-vv", "sd", "bd"),
+                           ::testing::Values("no", "v-rescale", "nose-hoover"),
+                           ::testing::Values("no", "c-rescale", "parrinello-rahman")));
+
+} // namespace
+} // namespace gmx::test
index 1e77a6a4da75186165beef1d6ce1ce8161655f54..416c3c34682b6ad0f653e0269cf7554d32faef61 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2016,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,6 +52,6 @@ void initSettingsNoNice(gmx::CommandLineModuleSettings* settings)
 
 int main(int argc, char* argv[])
 {
-    return gmx::CommandLineModuleManager::runAsMainCMainWithSettings(argc, argv, &gmx::gmx_mdrun,
-                                                                     &initSettingsNoNice);
+    return gmx::CommandLineModuleManager::runAsMainCMainWithSettings(
+            argc, argv, &gmx::gmx_mdrun, &initSettingsNoNice);
 }
index ea66889c2b82c6010fe9e401ac20f601bd6c5ea9..82c5114578f0154eabef56cbb9b45c3b91e35e8a 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,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -178,10 +178,15 @@ t_butbox* init_vbox(t_x11* x11, Window Parent, Window SendTo, unsigned long fg,
 
     /* VBox holder */
     y0 = XTextHeight(x11->font) + 2 * AIR + 2;
-    InitWin(&vb->wd, 0, 0, vb->nbut * (play_width + AIR) + AIR, y0 + play_height + 2 * AIR, 1,
+    InitWin(&vb->wd,
+            0,
+            0,
+            vb->nbut * (play_width + AIR) + AIR,
+            y0 + play_height + 2 * AIR,
+            1,
             "VCR - Control");
-    vb->wd.self = XCreateSimpleWindow(x11->disp, Parent, vb->wd.x, vb->wd.y, vb->wd.width,
-                                      vb->wd.height, vb->wd.bwidth, fg, bg);
+    vb->wd.self = XCreateSimpleWindow(
+            x11->disp, Parent, vb->wd.x, vb->wd.y, vb->wd.width, vb->wd.height, vb->wd.bwidth, fg, bg);
     x11->RegisterCallback(x11, vb->wd.self, Parent, VBCallBack, vb);
     x11->SetInputMask(x11, vb->wd.self, ExposureMask);
 
@@ -199,12 +204,12 @@ t_butbox* init_vbox(t_x11* x11, Window Parent, Window SendTo, unsigned long fg,
             default: fprintf(stderr, "Invalid bitmap in init_vbox %d\n", ID); std::exit(1);
         }
         /* Rely on the fact that all bitmaps are equal size */
-        pm = XCreatePixmapFromBitmapData(x11->disp, x11->root, (char*)data, play_width, play_height,
-                                         BLACK, LIGHTGREY, x11->depth);
+        pm = XCreatePixmapFromBitmapData(
+                x11->disp, x11->root, (char*)data, play_width, play_height, BLACK, LIGHTGREY, x11->depth);
         vb->b[i].ID        = ID;
         vb->b[i].wd.Parent = SendTo;
-        vb->b[i].wd.self   = XCreateSimpleWindow(x11->disp, vb->wd.self, x, y0 + AIR, play_width,
-                                               play_height, 0, WHITE, BLACK);
+        vb->b[i].wd.self   = XCreateSimpleWindow(
+                x11->disp, vb->wd.self, x, y0 + AIR, play_width, play_height, 0, WHITE, BLACK);
         XSetWindowBackgroundPixmap(x11->disp, vb->b[i].wd.self, pm);
 
         x11->RegisterCallback(x11, vb->b[i].wd.self, vb->wd.self, ButtonCallBack, &(vb->b[i]));
@@ -245,8 +250,8 @@ t_butbox* init_bbox(t_x11* x11, Window Parent, Window SendTo, int width, unsigne
 
     InitWin(&(bbox->wd), 0, 0, /*width,(y0+AIR)*IDBUTNR+AIR+2*BORDER,*/ 1, 1, 1, "Button Box");
     width -= 2 * AIR + 2 * BORDER;
-    bbox->wd.self = XCreateSimpleWindow(x11->disp, Parent, bbox->wd.x, bbox->wd.y, bbox->wd.width,
-                                        bbox->wd.height, bbox->wd.bwidth, fg, bg);
+    bbox->wd.self = XCreateSimpleWindow(
+            x11->disp, Parent, bbox->wd.x, bbox->wd.y, bbox->wd.width, bbox->wd.height, bbox->wd.bwidth, fg, bg);
     x11->RegisterCallback(x11, bbox->wd.self, Parent, BBCallBack, bbox);
     x11->SetInputMask(x11, bbox->wd.self, StructureNotifyMask);
 
@@ -259,8 +264,8 @@ t_butbox* init_bbox(t_x11* x11, Window Parent, Window SendTo, int width, unsigne
         h0 += y0 + AIR;
         but->wd.Parent = SendTo;
         but->ID        = i;
-        but->wd.self   = XCreateSimpleWindow(x11->disp, DrawOn, but->wd.x, but->wd.y, but->wd.width,
-                                           but->wd.height, but->wd.bwidth, bg, bg);
+        but->wd.self   = XCreateSimpleWindow(
+                x11->disp, DrawOn, but->wd.x, but->wd.y, but->wd.width, but->wd.height, but->wd.bwidth, bg, bg);
         x11->RegisterCallback(x11, but->wd.self, DrawOn, ButtonCallBack, but);
         x11->SetInputMask(x11, but->wd.self, ExposureMask | ButtonPressMask | EnterLeave);
     }
index bf1cbc0335706189b258eed54aa5983a175a1f11..af943597ae17e906d89b8d522fa6ae20b7013bbb 100644 (file)
@@ -138,13 +138,14 @@ static void MBCallback(t_x11* /*x11*/, int dlg_mess, int /*item_id*/, char* /*se
 
 static t_dlg* about_mb(t_x11* x11, t_gmx* gmx)
 {
-    const char* lines[] = { "         G R O M A C S", " Machine for Simulating Chemistry",
+    const char* lines[] = { "         G R O M A C S",
+                            " Machine for Simulating Chemistry",
                             "       Copyright (c) 1992-2013",
                             "  Berk Hess, David van der Spoel, Erik Lindahl",
                             "        and many collaborators!" };
 
-    return MessageBox(x11, gmx->wd->self, gmx->wd->text, asize(lines), lines,
-                      MB_OK | MB_ICONGMX | MBFLAGS, MBCallback, gmx);
+    return MessageBox(
+            x11, gmx->wd->self, gmx->wd->text, asize(lines), lines, MB_OK | MB_ICONGMX | MBFLAGS, MBCallback, gmx);
 }
 
 static void QuitCB(t_x11* x11, int dlg_mess, int /*item_id*/, char* set, void* data)
@@ -166,24 +167,24 @@ static t_dlg* quit_mb(t_x11* x11, t_gmx* gmx)
 {
     const char* lines[] = { " Do you really want to Quit ?" };
 
-    return MessageBox(x11, gmx->wd->self, gmx->wd->text, asize(lines), lines,
-                      MB_YESNO | MB_ICONSTOP | MBFLAGS, QuitCB, gmx);
+    return MessageBox(
+            x11, gmx->wd->self, gmx->wd->text, asize(lines), lines, MB_YESNO | MB_ICONSTOP | MBFLAGS, QuitCB, gmx);
 }
 
 static t_dlg* help_mb(t_x11* x11, t_gmx* gmx)
 {
     const char* lines[] = { " Help will soon be added" };
 
-    return MessageBox(x11, gmx->wd->self, gmx->wd->text, asize(lines), lines,
-                      MB_OK | MB_ICONINFORMATION | MBFLAGS, MBCallback, gmx);
+    return MessageBox(
+            x11, gmx->wd->self, gmx->wd->text, asize(lines), lines, MB_OK | MB_ICONINFORMATION | MBFLAGS, MBCallback, gmx);
 }
 
 static t_dlg* ni_mb(t_x11* x11, t_gmx* gmx)
 {
     const char* lines[] = { " This feature has not been", " implemented yet." };
 
-    return MessageBox(x11, gmx->wd->self, gmx->wd->text, asize(lines), lines,
-                      MB_OK | MB_ICONEXCLAMATION | MBFLAGS, MBCallback, gmx);
+    return MessageBox(
+            x11, gmx->wd->self, gmx->wd->text, asize(lines), lines, MB_OK | MB_ICONEXCLAMATION | MBFLAGS, MBCallback, gmx);
 }
 
 enum
@@ -392,8 +393,8 @@ void init_dlgs(t_x11* x11, t_gmx* gmx)
     snew(gmx->dlgs, edNR);
     for (int i = 0; (i < asize(di)); i++)
     {
-        gmx->dlgs[i] = ReadDlg(x11, gmx->wd->self, di[i].dlgfile, di[i].dlgfile, 0, 0, true, false,
-                               di[i].cb, gmx);
+        gmx->dlgs[i] = ReadDlg(
+                x11, gmx->wd->self, di[i].dlgfile, di[i].dlgfile, 0, 0, true, false, di[i].cb, gmx);
     }
 
     gmx->dlgs[edFilter] = select_filter(x11, gmx);
index 940e84e5739f3d9af9421fc490c05fb2c42961a1..924eac38344f0961dc4766517ffb343798464d36 100644 (file)
@@ -434,8 +434,12 @@ static void DumpFItem(t_fitem* fitem)
 {
     int i;
 
-    std::printf("  type: %s, set: '%s', get: '%s', def: '%s', help: '%s'\n  {", type[fitem->edlg],
-                fitem->set, fitem->get, fitem->def, fitem->help);
+    std::printf("  type: %s, set: '%s', get: '%s', def: '%s', help: '%s'\n  {",
+                type[fitem->edlg],
+                fitem->set,
+                fitem->get,
+                fitem->def,
+                fitem->help);
     for (i = 0; (i < fitem->nname); i++)
     {
         std::printf("  '%s'", fitem->name[i]);
index 3064c79de79dd5d069de694146be795a8223869b..80a7ade897f73ed90316f3f37a7bc02fef81c9cf 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,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -159,13 +159,18 @@ t_dlg* select_filter(t_x11* x11, t_gmx* gmx)
         {
             if (!gmx->filter->bDisable[k])
             {
-                std::fprintf(tmp, "checkbox \"%s\" \"%d\" %s %s %s\n", gmx->filter->grpnames[k], k,
-                             dummy, dummy, dummy);
+                std::fprintf(
+                        tmp, "checkbox \"%s\" \"%d\" %s %s %s\n", gmx->filter->grpnames[k], k, dummy, dummy, dummy);
             }
             else
             {
-                std::fprintf(tmp, "statictext { \"  %s\" } \"%d\" %s %s %s\n",
-                             gmx->filter->grpnames[k], k, dummy, dummy, dummy);
+                std::fprintf(tmp,
+                             "statictext { \"  %s\" } \"%d\" %s %s %s\n",
+                             gmx->filter->grpnames[k],
+                             k,
+                             dummy,
+                             dummy,
+                             dummy);
             }
         }
         std::fprintf(tmp, "}\n\n");
index e8fb69d6f6d20ec33152c73c1adca5766216ddbc..d1e47e9fc4cb6497ab5204ed9c7fb8639a8358d6 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,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -134,8 +134,13 @@ static bool LogoCallBack(t_x11* x11, XEvent* event, Window /*w*/, void* data)
             XSetLineAttributes(x11->disp, x11->gc, 3, LineSolid, CapNotLast, JoinRound);
             for (i = 0; (i < asize(lines)); i += 2)
             {
-                XDrawLine(x11->disp, wd->self, x11->gc, c[lines[i]].x, c[lines[i]].y,
-                          c[lines[i + 1]].x, c[lines[i + 1]].y);
+                XDrawLine(x11->disp,
+                          wd->self,
+                          x11->gc,
+                          c[lines[i]].x,
+                          c[lines[i]].y,
+                          c[lines[i + 1]].x,
+                          c[lines[i + 1]].y);
             }
             XSetLineAttributes(x11->disp, x11->gc, 1, LineSolid, CapNotLast, JoinRound);
             for (i = 0; (i < asize(c)); i++)
@@ -147,8 +152,8 @@ static bool LogoCallBack(t_x11* x11, XEvent* event, Window /*w*/, void* data)
             XDrawRectangle(x11->disp, wd->self, x11->gc, 2, 2, wd->width - 5, wd->height - 5);
             for (i = 0; (i < NMESS); i++)
             {
-                SpecialTextInRect(x11, Mess[i].fnt, wd->self, Mess[i].text, 0, Mess[i].y, wd->width,
-                                  Mess[i].h, eXCenter, eYCenter);
+                SpecialTextInRect(
+                        x11, Mess[i].fnt, wd->self, Mess[i].text, 0, Mess[i].y, wd->width, Mess[i].h, eXCenter, eYCenter);
             }
             XSetForeground(x11->disp, x11->gc, x11->fg);
             break;
@@ -186,8 +191,8 @@ t_logo* init_logo(t_x11* x11, Window parent, bool bQuitOnClick)
     {
         GetNamedColor(x11, newcol, &bg);
     }
-    logo->wd.self = XCreateSimpleWindow(x11->disp, parent, logo->wd.x, logo->wd.y, logo->wd.width,
-                                        logo->wd.height, logo->wd.bwidth, WHITE, bg);
+    logo->wd.self = XCreateSimpleWindow(
+            x11->disp, parent, logo->wd.x, logo->wd.y, logo->wd.width, logo->wd.height, logo->wd.bwidth, WHITE, bg);
     for (i = 0, logo->bigfont = nullptr; (i < NBF); i++)
     {
         if ((logo->bigfont = XLoadQueryFont(x11->disp, bfname[i])) != nullptr)
index d5fbd842f365399b8f8365728134d6093229a1e5..ad67d7837f1124b041f40551fbce913ae5ea1325 100644 (file)
@@ -186,8 +186,8 @@ static void do_label(t_x11* x11, t_manager* man, int x, int y, bool bSet)
             return;
         }
         XSetForeground(x11->disp, x11->gc, col);
-        XDrawString(x11->disp, man->molw->wd.self, x11->gc, x + 2, y - 2, man->szLab[ai],
-                    std::strlen(man->szLab[ai]));
+        XDrawString(
+                x11->disp, man->molw->wd.self, x11->gc, x + 2, y - 2, man->szLab[ai], std::strlen(man->szLab[ai]));
         XSetForeground(x11->disp, x11->gc, x11->fg);
     }
 }
@@ -236,7 +236,10 @@ void set_file(t_x11* x11, t_manager* man, const char* trajectory, const char* st
         gmx_fatal(FARGS,
                   "Topology %s (%d atoms) and trajectory %s (%d atoms) "
                   "do not match",
-                  status, man->top.atoms.nr, trajectory, man->natom);
+                  status,
+                  man->top.atoms.nr,
+                  trajectory,
+                  man->natom);
     }
 
     man->title.text =
@@ -634,8 +637,8 @@ t_manager* init_man(t_x11*            x11,
     man->bSort  = true;
     man->oenv   = oenv;
     InitWin(&(man->wd), x, y, width, height, 0, "Manager");
-    man->wd.self = XCreateSimpleWindow(x11->disp, Parent, man->wd.x, man->wd.y, man->wd.width,
-                                       man->wd.height, man->wd.bwidth, fg, bg);
+    man->wd.self = XCreateSimpleWindow(
+            x11->disp, Parent, man->wd.x, man->wd.y, man->wd.width, man->wd.height, man->wd.bwidth, fg, bg);
     x11->RegisterCallback(x11, man->wd.self, Parent, ManCallBack, man);
     x11->SetInputMask(x11, man->wd.self, StructureNotifyMask | ExposureMask | ButtonPressMask);
 
@@ -645,9 +648,15 @@ t_manager* init_man(t_x11*            x11,
 
     /* Title Window */
     InitWin(&(man->title), 0, 0, 1, 1, 0, nullptr);
-    man->title.self =
-            XCreateSimpleWindow(x11->disp, man->molw->wd.self, man->title.x, man->title.y,
-                                man->title.width, man->title.height, man->title.bwidth, WHITE, BLUE);
+    man->title.self = XCreateSimpleWindow(x11->disp,
+                                          man->molw->wd.self,
+                                          man->title.x,
+                                          man->title.y,
+                                          man->title.width,
+                                          man->title.height,
+                                          man->title.bwidth,
+                                          WHITE,
+                                          BLUE);
     x11->RegisterCallback(x11, man->title.self, man->molw->wd.self, TitleCallBack, &(man->title));
     x11->SetInputMask(x11, man->title.self, ExposureMask | StructureNotifyMask);
 
index 3f2dcf51587f251ca9326ab52e81d71d52edbf73..daa0645764dabf9bccf349132ee9433d839ad0da 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,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -186,8 +186,7 @@ static void draw_box(t_psdata* ps, t_3dview* view, matrix box, int x0, int y0, r
     ps_color(ps, 0, 0, 0.5);
     for (i = 0; (i < 12); i++)
     {
-        ps_line(ps, vec2[bonds[i][0]][XX], vec2[bonds[i][0]][YY], vec2[bonds[i][1]][XX],
-                vec2[bonds[i][1]][YY]);
+        ps_line(ps, vec2[bonds[i][0]][XX], vec2[bonds[i][0]][YY], vec2[bonds[i][1]][XX], vec2[bonds[i][1]][YY]);
     }
 }
 
index 1c1123ea6cc1e17de1e47703ee0483626be380b4..4a272709ee028c16cebfd45258312d4d1dd3e193 100644 (file)
@@ -590,8 +590,18 @@ void draw_mol(t_x11* x11, t_manager* man)
     }
 
     /* Draw the objects */
-    draw_objects(x11->disp, win->self, x11->gc, nvis, man->obj, man->ix, man->x, man->col,
-                 man->size, mw->bShowHydrogen, mw->bond_type, man->bPlus);
+    draw_objects(x11->disp,
+                 win->self,
+                 x11->gc,
+                 nvis,
+                 man->obj,
+                 man->ix,
+                 man->x,
+                 man->col,
+                 man->size,
+                 mw->bShowHydrogen,
+                 mw->bond_type,
+                 man->bPlus);
 
     /* Draw the labels */
     XSetForeground(x11->disp, x11->gc, WHITE);
@@ -599,8 +609,13 @@ void draw_mol(t_x11* x11, t_manager* man)
     {
         if (man->bLabel[i] && man->bVis[i])
         {
-            XDrawString(x11->disp, win->self, x11->gc, vec2[i][XX] + 2, vec2[i][YY] - 2,
-                        man->szLab[i], std::strlen(man->szLab[i]));
+            XDrawString(x11->disp,
+                        win->self,
+                        x11->gc,
+                        vec2[i][XX] + 2,
+                        vec2[i][YY] - 2,
+                        man->szLab[i],
+                        std::strlen(man->szLab[i]));
         }
     }
 
index 63d2d465ffb6929715a1d439f81244f2bb97b408..b0f298e6a7c054c974bc267d96b68dfbca2c8111 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,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -98,9 +98,16 @@ static bool MenuCallBack(t_x11* x11, XEvent* event, Window /*w*/, void* data)
             /* Nothing to be done */
             if (m->bGrabbed)
             {
-                m->bGrabbed = GrabOK(stderr, XGrabPointer(x11->disp, m->wd.self, True, ButtonReleaseMask,
-                                                          GrabModeAsync, GrabModeAsync, m->wd.self,
-                                                          None, CurrentTime));
+                m->bGrabbed = GrabOK(stderr,
+                                     XGrabPointer(x11->disp,
+                                                  m->wd.self,
+                                                  True,
+                                                  ButtonReleaseMask,
+                                                  GrabModeAsync,
+                                                  GrabModeAsync,
+                                                  m->wd.self,
+                                                  None,
+                                                  CurrentTime));
             }
             break;
         case ButtonRelease: hide_menu(x11, m); break;
@@ -163,8 +170,8 @@ t_menu* init_menu(t_x11* x11, Window Parent, unsigned long fg, unsigned long bg,
     }
     InitWin(&(m->wd), 10, 10, fcol * mlen, frows * mht, 1, "Menu");
     snew(m->item, nent);
-    m->wd.self = XCreateSimpleWindow(x11->disp, Parent, m->wd.x, m->wd.y, m->wd.width, m->wd.height,
-                                     m->wd.bwidth, fg, bg);
+    m->wd.self = XCreateSimpleWindow(
+            x11->disp, Parent, m->wd.x, m->wd.y, m->wd.width, m->wd.height, m->wd.bwidth, fg, bg);
     x11->RegisterCallback(x11, m->wd.self, Parent, MenuCallBack, m);
     x11->SetInputMask(x11, m->wd.self, ExposureMask | OwnerGrabButtonMask | ButtonReleaseMask);
 
@@ -177,10 +184,11 @@ t_menu* init_menu(t_x11* x11, Window Parent, unsigned long fg, unsigned long bg,
             kid->Parent = Parent;
             w           = &(kid->wd);
             InitWin(w, j * mlen, k * mht, mlen - 2, mht - 2, 1, nullptr);
-            w->self = XCreateSimpleWindow(x11->disp, m->wd.self, w->x, w->y, w->width, w->height,
-                                          w->bwidth, bg, bg);
+            w->self = XCreateSimpleWindow(
+                    x11->disp, m->wd.self, w->x, w->y, w->width, w->height, w->bwidth, bg, bg);
             x11->RegisterCallback(x11, w->self, m->wd.self, ChildCallBack, kid);
-            x11->SetInputMask(x11, w->self,
+            x11->SetInputMask(x11,
+                              w->self,
                               ButtonPressMask | ButtonReleaseMask | OwnerGrabButtonMask
                                       | ExposureMask | EnterWindowMask | LeaveWindowMask);
         }
index 6c4bbb703c9d531336a38642012578ba5e2eec6d..36df602e905627378ffbff6b8f2844113d36a109 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,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -62,8 +62,13 @@ static bool PDCallBack(t_x11* x11, XEvent* event, Window w, void* data)
             XDrawLine(x11->disp, w, x11->gc, 0, y - 1, pd->wd.width, y - 1);
             for (i = 0; (i < pd->nmenu); i++)
             {
-                XDrawString(x11->disp, pd->wd.self, x11->gc, pd->xpos[i], x11->font->ascent,
-                            pd->title[i], std::strlen(pd->title[i]));
+                XDrawString(x11->disp,
+                            pd->wd.self,
+                            x11->gc,
+                            pd->xpos[i],
+                            x11->font->ascent,
+                            pd->title[i],
+                            std::strlen(pd->title[i]));
             }
             break;
         case ButtonPress:
@@ -116,11 +121,11 @@ t_pulldown* init_pd(t_x11*        x11,
     }
 
     InitWin(&(pd->wd), 0, 0, width, XTextHeight(x11->font) + 2, 0, "PullDown");
-    pd->wd.self = XCreateSimpleWindow(x11->disp, Parent, pd->wd.x, pd->wd.y, pd->wd.width,
-                                      pd->wd.height, pd->wd.bwidth, fg, bg);
+    pd->wd.self = XCreateSimpleWindow(
+            x11->disp, Parent, pd->wd.x, pd->wd.y, pd->wd.width, pd->wd.height, pd->wd.bwidth, fg, bg);
     x11->RegisterCallback(x11, pd->wd.self, Parent, PDCallBack, pd);
-    x11->SetInputMask(x11, pd->wd.self,
-                      ExposureMask | ButtonPressMask | OwnerGrabButtonMask | ButtonReleaseMask);
+    x11->SetInputMask(
+            x11, pd->wd.self, ExposureMask | ButtonPressMask | OwnerGrabButtonMask | ButtonReleaseMask);
     XMapWindow(x11->disp, pd->wd.self);
 
     for (i = 0; (i < nmenu); i++)
index 15395ab0903629eb4ce50398b60866db74ad6180..c307a4e2396b6333f9865a3253591f12c063ecdb 100644 (file)
@@ -129,8 +129,13 @@ static bool HandleClient(t_x11* x11, int ID, t_gmx* gmx)
         case IDIMPORT:
         case IDEXPORT: ShowDlg(gmx->dlgs[edExport]); break;
         case IDDOEXPORT:
-            write_sto_conf(gmx->confout, *gmx->man->top.name, &(gmx->man->top.atoms), gmx->man->x,
-                           nullptr, gmx->man->molw->pbcType, gmx->man->box);
+            write_sto_conf(gmx->confout,
+                           *gmx->man->top.name,
+                           &(gmx->man->top.atoms),
+                           gmx->man->x,
+                           nullptr,
+                           gmx->man->molw->pbcType,
+                           gmx->man->box);
             break;
         case IDQUIT: show_mb(gmx, emQuit); break;
         case IDTERM: done_gmx(x11, gmx); return true;
@@ -259,17 +264,18 @@ static void init_gmx(t_x11* x11, char* program, int nfile, t_filenm fnm[], gmx_o
     w0 = DisplayWidth(x11->disp, x11->screen) - 132;
     h0 = DisplayHeight(x11->disp, x11->screen) - 140;
     InitWin(gmx->wd, 0, 0, w0, h0, 3, gmx::bromacs().c_str());
-    gmx->wd->self = XCreateSimpleWindow(x11->disp, x11->root, gmx->wd->x, gmx->wd->y, gmx->wd->width,
-                                        gmx->wd->height, gmx->wd->bwidth, WHITE, BLACK);
-    pm = XCreatePixmapFromBitmapData(x11->disp, x11->root, (char*)gromacs_bits, gromacs_width,
-                                     gromacs_height, WHITE, BLACK, 1);
+    gmx->wd->self = XCreateSimpleWindow(
+            x11->disp, x11->root, gmx->wd->x, gmx->wd->y, gmx->wd->width, gmx->wd->height, gmx->wd->bwidth, WHITE, BLACK);
+    pm = XCreatePixmapFromBitmapData(
+            x11->disp, x11->root, (char*)gromacs_bits, gromacs_width, gromacs_height, WHITE, BLACK, 1);
     hints.flags      = PMinSize;
     hints.min_width  = 2 * EWIDTH + 40;
     hints.min_height = EHEIGHT + LDHEIGHT + LEGHEIGHT + 40;
     XSetStandardProperties(x11->disp, gmx->wd->self, gmx->wd->text, program, pm, nullptr, 0, &hints);
 
     x11->RegisterCallback(x11, gmx->wd->self, x11->root, MainCallBack, gmx);
-    x11->SetInputMask(x11, gmx->wd->self,
+    x11->SetInputMask(x11,
+                      gmx->wd->self,
                       ButtonPressMask | ButtonReleaseMask | OwnerGrabButtonMask | ExposureMask
                               | StructureNotifyMask);
 
@@ -285,8 +291,8 @@ static void init_gmx(t_x11* x11, char* program, int nfile, t_filenm fnm[], gmx_o
     map_man(x11, gmx->man);
 
     /* Pull Down menu */
-    gmx->pd = init_pd(x11, gmx->wd->self, gmx->wd->width, x11->fg, x11->bg, MSIZE, gmx_pd_size,
-                      gmx_pd, MenuTitle);
+    gmx->pd = init_pd(
+            x11, gmx->wd->self, gmx->wd->width, x11->fg, x11->bg, MSIZE, gmx_pd_size, gmx_pd, MenuTitle);
 
     /* Dialogs & Filters */
 
@@ -328,8 +334,8 @@ int gmx_view(int argc, char* argv[])
                        { efNDX, nullptr, nullptr, ffOPTRD } };
 #define NFILE asize(fnm)
 
-    if (parse_common_args(&argc, argv, PCA_CAN_TIME, NFILE, fnm, 0, nullptr, asize(desc), desc,
-                          asize(bugs), bugs, &oenv))
+    if (parse_common_args(
+                &argc, argv, PCA_CAN_TIME, NFILE, fnm, 0, nullptr, asize(desc), desc, asize(bugs), bugs, &oenv))
     {
 #if !GMX_X11
         std::fprintf(stderr, "Compiled without X-Windows - can not run viewer.\n");
index b429024522bb2f9b7f36a8f26480212256aa1799..96707325a42fa511f5c40c944a3f1ae40cf3f6bc 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,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -419,8 +419,10 @@ t_x11* GetX11(int* argc, char* argv[])
         else
         {
             /* We have real color! */
-            std::fprintf(x11->console, "%s screen with depth %d.\n",
-                         (i == NCLASS) ? "Unknown" : v_name[i], x11->depth);
+            std::fprintf(x11->console,
+                         "%s screen with depth %d.\n",
+                         (i == NCLASS) ? "Unknown" : v_name[i],
+                         x11->depth);
             GetNamedColor(x11, "midnight blue", &BLUE);
             GetNamedColor(x11, "DarkGreen", &GREEN);
             GetNamedColor(x11, "SeaGreen", &CYAN);
index b403a9e71b5ac96c7850108df398b05d3f3ee87d..92126604d2b15f9d01ffe3ff38337be73a3fb81b 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,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -179,8 +179,12 @@ bool SetDlgItemSize(t_dlg* dlg, t_id id, int w, int h)
             dlgitem->win.height = h;
         }
 #ifdef DEBUG
-        std::fprintf(dlg->x11->console, "Size window from: %dx%d to %dx%d\n", old_w, old_h,
-                     dlgitem->win.width, dlgitem->win.height);
+        std::fprintf(dlg->x11->console,
+                     "Size window from: %dx%d to %dx%d\n",
+                     old_w,
+                     old_h,
+                     dlgitem->win.width,
+                     dlgitem->win.height);
         dlg->x11->Flush(dlg->x11);
 #endif
         if (dlgitem->win.self)
@@ -359,16 +363,15 @@ void HideDlg(t_dlg* dlg)
 void NoHelp(t_dlg* dlg)
 {
     const char* lines[2] = { "Error", "No help for this item" };
-    MessageBox(dlg->x11, dlg->wDad, "No Help", 2, lines, MB_OK | MB_ICONSTOP | MB_APPLMODAL,
-               nullptr, nullptr);
+    MessageBox(dlg->x11, dlg->wDad, "No Help", 2, lines, MB_OK | MB_ICONSTOP | MB_APPLMODAL, nullptr, nullptr);
 }
 
 void HelpDlg(t_dlg* dlg)
 {
     const char* lines[] = { "Place the cursor over one of the items",
-                            "and press the F1 key to get more help.", "First press the OK button." };
-    MessageBox(dlg->x11, dlg->win.self, "Help Dialogbox", 3, lines,
-               MB_OK | MB_ICONINFORMATION | MB_APPLMODAL, nullptr, nullptr);
+                            "and press the F1 key to get more help.",
+                            "First press the OK button." };
+    MessageBox(dlg->x11, dlg->win.self, "Help Dialogbox", 3, lines, MB_OK | MB_ICONINFORMATION | MB_APPLMODAL, nullptr, nullptr);
 }
 
 void HelpNow(t_dlg* dlg, t_dlgitem* dlgitem)
@@ -416,8 +419,7 @@ void HelpNow(t_dlg* dlg, t_dlgitem* dlgitem)
             }
         }
     } while (bCont);
-    MessageBox(dlg->x11, dlg->wDad, "Help", nlines, lines,
-               MB_OK | MB_ICONINFORMATION | MB_APPLMODAL, nullptr, nullptr);
+    MessageBox(dlg->x11, dlg->wDad, "Help", nlines, lines, MB_OK | MB_ICONINFORMATION | MB_APPLMODAL, nullptr, nullptr);
     for (i = 0; (i < nlines); i++)
     {
         sfree(lines[i]);
@@ -429,9 +431,10 @@ static void EnterDlg(t_dlg* dlg)
 {
     if (dlg->flags & DLG_APPLMODAL)
     {
-        dlg->bGrab = GrabOK(dlg->x11->console,
-                            XGrabPointer(dlg->x11->disp, dlg->win.self, True, 0, GrabModeAsync,
-                                         GrabModeAsync, dlg->win.self, None, CurrentTime));
+        dlg->bGrab = GrabOK(
+                dlg->x11->console,
+                XGrabPointer(
+                        dlg->x11->disp, dlg->win.self, True, 0, GrabModeAsync, GrabModeAsync, dlg->win.self, None, CurrentTime));
     }
     dlg->x11->Flush(dlg->x11);
 }
@@ -483,8 +486,10 @@ static bool DlgCB(t_x11* x11, XEvent* event, Window w, void* data)
                     {
                         if ((dlg->dlgitem[i]->type == edlgBN) && (dlg->dlgitem[i]->u.button.bDefault))
                         {
-                            PushMouse(x11->disp, dlg->dlgitem[i]->win.self,
-                                      dlg->dlgitem[i]->win.width / 2, dlg->dlgitem[i]->win.height / 2);
+                            PushMouse(x11->disp,
+                                      dlg->dlgitem[i]->win.self,
+                                      dlg->dlgitem[i]->win.width / 2,
+                                      dlg->dlgitem[i]->win.height / 2);
                             break;
                         }
                     }
@@ -585,9 +590,18 @@ static void DoCreateDlg(t_dlg* dlg)
     attr.save_under        = True;
     attr.cursor            = XCreateFontCursor(dlg->x11->disp, XC_hand2);
     Val           = CWBackPixel | CWBorderPixel | CWOverrideRedirect | CWSaveUnder | CWCursor;
-    dlg->win.self = XCreateWindow(dlg->x11->disp, dlg->wDad, dlg->win.x, dlg->win.y, dlg->win.width,
-                                  dlg->win.height, dlg->win.bwidth, CopyFromParent, InputOutput,
-                                  CopyFromParent, Val, &attr);
+    dlg->win.self = XCreateWindow(dlg->x11->disp,
+                                  dlg->wDad,
+                                  dlg->win.x,
+                                  dlg->win.y,
+                                  dlg->win.width,
+                                  dlg->win.height,
+                                  dlg->win.bwidth,
+                                  CopyFromParent,
+                                  InputOutput,
+                                  CopyFromParent,
+                                  Val,
+                                  &attr);
     dlg->x11->RegisterCallback(dlg->x11, dlg->win.self, dlg->wDad, DlgCB, dlg);
     dlg->x11->SetInputMask(dlg->x11, dlg->win.self, ExposureMask | ButtonPressMask | KeyPressMask);
 
@@ -624,9 +638,15 @@ void AddDlgItem(t_dlg* dlg, t_dlgitem* item)
     {
         gmx_fatal(FARGS, "dlgitem not allocated");
     }
-    item->win.self = XCreateSimpleWindow(dlg->x11->disp, dlg->win.self, item->win.x, item->win.y,
-                                         item->win.width, item->win.height, item->win.bwidth,
-                                         dlg->x11->fg, dlg->x11->bg);
+    item->win.self = XCreateSimpleWindow(dlg->x11->disp,
+                                         dlg->win.self,
+                                         item->win.x,
+                                         item->win.y,
+                                         item->win.width,
+                                         item->win.height,
+                                         item->win.bwidth,
+                                         dlg->x11->fg,
+                                         dlg->x11->bg);
     CheckWindow(item->win.self);
 
     dlg->x11->RegisterCallback(dlg->x11, item->win.self, dlg->win.self, DlgCB, dlg);
@@ -799,8 +819,12 @@ void SetDlgSize(t_dlg* dlg, int w, int h, bool bAutoPosition)
     dlg->win.height = h;
 
 #ifdef DEBUG
-    std::fprintf(dlg->x11->console, "SetDlgSize: Dialog is %dx%d, at %d,%d\n", dlg->win.width,
-                 dlg->win.height, dlg->win.x, dlg->win.y);
+    std::fprintf(dlg->x11->console,
+                 "SetDlgSize: Dialog is %dx%d, at %d,%d\n",
+                 dlg->win.width,
+                 dlg->win.height,
+                 dlg->win.x,
+                 dlg->win.y);
     dlg->x11->Flush(dlg->x11);
 #endif
     if (dlg->win.self)
index a57a6c1e819771f4ecb1292d8838018f3e15fde0..8a966861f950191cd46cd5b5525319b145e3483d 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,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -269,8 +269,8 @@ AddListFItem(t_x11* x11, t_dlgitemlist* list, t_fitem* fitem, t_id GroupID, t_id
     switch (fitem->edlg)
     {
         case edlgBN:
-            AddListItem(list, CreateButton(x11, fitem->name[0], fitem->bDef, (*ID)++, GroupID, x,
-                                           (*y), 0, 0, 0));
+            AddListItem(list,
+                        CreateButton(x11, fitem->name[0], fitem->bDef, (*ID)++, GroupID, x, (*y), 0, 0, 0));
             break;
         case edlgRB:
             std::strcpy(buf, fitem->def);
@@ -289,8 +289,9 @@ AddListFItem(t_x11* x11, t_dlgitemlist* list, t_fitem* fitem, t_id GroupID, t_id
 
             for (i = 0; (i < fitem->nname); i++)
             {
-                AddListItem(list, CreateRadioButton(x11, fitem->name[i], (iSel == i), (*ID)++,
-                                                    GroupID, x, (*y), 0, 0, 0));
+                AddListItem(list,
+                            CreateRadioButton(
+                                    x11, fitem->name[i], (iSel == i), (*ID)++, GroupID, x, (*y), 0, 0, 0));
                 (*y) += list->list[list->nitem - 1]->win.height + OFFS_Y;
                 (*w) = std::max((*w), list->list[list->nitem - 1]->win.width);
                 SetDlgitemOpts(list->list[list->nitem - 1], bUseMon, fitem->set, fitem->get, fitem->help);
@@ -301,18 +302,20 @@ AddListFItem(t_x11* x11, t_dlgitemlist* list, t_fitem* fitem, t_id GroupID, t_id
             bool bCheck;
 
             bCheck = gmx_strcasecmp(fitem->def, "TRUE") == 0;
-            AddListItem(list, CreateCheckBox(x11, fitem->name[0], bCheck, (*ID)++, GroupID, x, (*y),
-                                             0, 0, 0));
+            AddListItem(list,
+                        CreateCheckBox(x11, fitem->name[0], bCheck, (*ID)++, GroupID, x, (*y), 0, 0, 0));
             break;
         }
         case edlgST:
-            AddListItem(list, CreateStaticText(x11, fitem->nname, fitem->name, (*ID)++, GroupID, x,
-                                               (*y), 0, 0, 0));
+            AddListItem(list,
+                        CreateStaticText(
+                                x11, fitem->nname, fitem->name, (*ID)++, GroupID, x, (*y), 0, 0, 0));
             break;
         case edlgET:
             slen = std::strlen(fitem->name[0]) + strlen(fitem->def);
-            AddListItem(list, CreateEditText(x11, fitem->name[0], slen, fitem->def, (*ID)++,
-                                             GroupID, x, (*y), 0, 0, 0));
+            AddListItem(list,
+                        CreateEditText(
+                                x11, fitem->name[0], slen, fitem->def, (*ID)++, GroupID, x, (*y), 0, 0, 0));
             break;
         case edlgPM:
         case edlgGB:
@@ -353,8 +356,8 @@ static void AddListFGroup(t_x11* x11, t_dlgitemlist** grid, t_fgroup* fgroup, t_
     {
         ids[i] = GroupID + i + 1;
     }
-    item->list[0] = CreateGroupBox(x11, fgroup->name, GroupID, item->nitem - 1, ids, 2 * OFFS_X,
-                                   2 * OFFS_Y, w + 2 * OFFS_X, y, 0);
+    item->list[0] = CreateGroupBox(
+            x11, fgroup->name, GroupID, item->nitem - 1, ids, 2 * OFFS_X, 2 * OFFS_Y, w + 2 * OFFS_X, y, 0);
     sfree(ids);
     item->w = fgroup->w;
     item->h = fgroup->h;
index 3bd79a29c8a5e11d130e239fe8d0a941d91c356f..dd5c415a55aec024222c6c521638579cd0874a86 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,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +226,8 @@ static int WndProcGB(t_x11* x11, t_dlgitem* dlgitem, XEvent* event)
     {
         case Expose:
             XSetForeground(x11->disp, x11->gc, x11->fg);
-            XDrawRoundRect(x11->disp, win->self, x11->gc, 0, y / 2, win->width - 1,
-                           win->height - y / 2 - 1);
+            XDrawRoundRect(
+                    x11->disp, win->self, x11->gc, 0, y / 2, win->width - 1, win->height - y / 2 - 1);
             XClearArea(x11->disp, win->self, OFFS_X, 0, x + OFFS_X, y, False);
             TextInRect(x11, win->self, win->text, 2 * OFFS_X, 0, x, y, eXCenter, eYCenter);
             break;
@@ -296,8 +296,7 @@ static int WndProcST(t_x11* x11, t_dlgitem* dlgitem, XEvent* event)
             dy = XTextHeight(x11->font) + OFFS_Y;
             for (i = 0; (i < st->nlines); i++)
             {
-                TextInRect(x11, win->self, st->lines[i], 0, OFFS_Y + i * dy, win->width, dy, eXLeft,
-                           eYCenter);
+                TextInRect(x11, win->self, st->lines[i], 0, OFFS_Y + i * dy, win->width, dy, eXLeft, eYCenter);
             }
             break;
         default: return DefWndProc(x11, dlgitem, event);
index 1d564cf9b7b4d7d6f8c6c396c9ac9a6977ff8862..7e6eeab86a4ba2eff15eedcbdb1615ef82b0478b 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,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -141,9 +141,16 @@ t_dlg* MessageBox(t_x11*             x11,
     if (nicon > 0)
     {
         AddDlgItem(dlg,
-                   CreatePixmap(XCreatePixmapFromBitmapData(x11->disp, dlg->win.self, icon_bits, icon_width,
-                                                            icon_height, icon_fg, icon_bg, x11->depth),
-                                ID_ICON, ID_BOX, 2 * OFFS_X, 2 * OFFS_Y, icon_width, icon_height, 0));
+                   CreatePixmap(
+                           XCreatePixmapFromBitmapData(
+                                   x11->disp, dlg->win.self, icon_bits, icon_width, icon_height, icon_fg, icon_bg, x11->depth),
+                           ID_ICON,
+                           ID_BOX,
+                           2 * OFFS_X,
+                           2 * OFFS_Y,
+                           icon_width,
+                           icon_height,
+                           0));
         x += QueryDlgItemW(dlg, ID_ICON) + 2 * OFFS_X;
     }
 
index 17d2081c04b2ffbc723f4643691a6fcce69c24a4..b10e3ad4e44e49884f4b5cb5ab95a6abc9d53aa2 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,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -225,8 +225,8 @@ void RoundRectWin(Display* disp, GC gc, t_windata* win, int offsx, int offsy, un
 {
     XSetLineAttributes(disp, gc, 1, LineOnOffDash, CapButt, JoinRound);
     XSetForeground(disp, gc, color);
-    XDrawRoundRect(disp, win->self, gc, offsx, offsy, win->width - 2 * offsx - 1,
-                   win->height - 2 * offsy - 1);
+    XDrawRoundRect(
+            disp, win->self, gc, offsx, offsy, win->width - 2 * offsx - 1, win->height - 2 * offsy - 1);
     XSetLineAttributes(disp, gc, 1, LineSolid, CapButt, JoinRound);
 }
 
diff --git a/src/testutils/.clang-tidy b/src/testutils/.clang-tidy
new file mode 100644 (file)
index 0000000..0adf51e
--- /dev/null
@@ -0,0 +1,91 @@
+# List of rationales for check suppressions (where known).
+# This have to precede the list because inline comments are not
+# supported by clang-tidy.
+#
+#         -cppcoreguidelines-non-private-member-variables-in-classes,
+#         -misc-non-private-member-variables-in-classes,
+# We intend a gradual transition to conform to this guideline, but it
+# is not practical to implement yet.
+#
+#         -readability-isolate-declaration,
+# Declarations like "int a, b;" are readable. Some forms are not, and
+# those might reasonably be suggested against during code review.
+#
+#         -cppcoreguidelines-avoid-c-arrays,
+# C arrays are still necessary in many places with legacy code
+#
+#         -cppcoreguidelines-avoid-magic-numbers,
+#         -readability-magic-numbers,
+# We have many legitimate use cases for magic numbers
+#
+#         -cppcoreguidelines-macro-usage,
+# We do use too many macros, and we should fix many of them, but there
+# is no reasonable way to suppress the check e.g. in src/config.h and
+# configuring the build is a major legitimate use of macros.
+#
+#         -cppcoreguidelines-narrowing-conversions,
+#         -bugprone-narrowing-conversions
+# We have many cases where int is converted to float and we don't care
+# enough about such potential loss of precision to use explicit casts
+# in large numbers of places.
+#
+#         -google-readability-avoid-underscore-in-googletest-name
+# We need to use underscores for readability for our legacy types
+# and command-line parameter names
+#
+#         -misc-no-recursion
+# We have way too many functions and methods relying on recursion
+#
+#         -cppcoreguidelines-avoid-non-const-global-variables
+# There are quite a lot of static variables in the test code that
+# can not be replaced.
+#
+#         -modernize-avoid-bind
+# Some code needs to use std::bind and can't be modernized quickly.
+Checks:  clang-diagnostic-*,-clang-analyzer-*,-clang-analyzer-security.insecureAPI.strcpy,
+         bugprone-*,misc-*,readability-*,performance-*,mpi-*,
+         -readability-inconsistent-declaration-parameter-name,
+         -readability-function-size,-readability-else-after-return,
+         modernize-use-nullptr,modernize-use-emplace,
+         modernize-make-unique,modernize-make-shared,
+         modernize-avoid-bind,
+         modernize-use-override,
+         modernize-redundant-void-arg,modernize-use-bool-literals,
+         cppcoreguidelines-*,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,
+         -cppcoreguidelines-no-malloc,-cppcoreguidelines-special-member-functions,
+         -cppcoreguidelines-avoid-goto,
+         google-*,-google-build-using-namespace,-google-explicit-constructor,
+         -google-readability-function-size,-google-readability-todo,-google-runtime-int,
+         -cppcoreguidelines-non-private-member-variables-in-classes,
+         -misc-non-private-member-variables-in-classes,
+         -readability-isolate-declaration,
+         -cppcoreguidelines-avoid-c-arrays,
+         -cppcoreguidelines-avoid-magic-numbers,
+         -readability-magic-numbers,
+         -cppcoreguidelines-macro-usage,
+         -cppcoreguidelines-narrowing-conversions,
+         -bugprone-narrowing-conversions,
+         -google-readability-avoid-underscore-in-googletest-name,
+         -cppcoreguidelines-init-variables,
+         -misc-no-recursion,
+         -cppcoreguidelines-avoid-non-const-global-variables,
+         -modernize-avoid-bind
+HeaderFilterRegex: .*
+CheckOptions:
+  - key:           cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
+    value:         1
+  - key:           modernize-make-unique.IncludeStyle
+    value:         google
+  - key:           modernize-make-shared.IncludeStyle
+    value:         google
+  - key:           readability-implicit-bool-conversion.AllowIntegerConditions
+    value:         1
+  - key:           readability-implicit-bool-conversion.AllowPointerConditions
+    value:         1
+  - key:           bugprone-dangling-handle.HandleClasses
+    value:         std::basic_string_view; nonstd::sv_lite::basic_string_view
+# Permit passing shard pointers by value for sink parameters
+  - key:           performance-unnecessary-copy-initialization.AllowedTypes
+    value:         shared_ptr
+  - key:           performance-unnecessary-value-param.AllowedTypes
+    value:         shared_ptr
index e932e692b077e4bb5f06138433150b8648aaae1f..b5de0e007f8f8cea1771ba4ca84d17c6e2a0135a 100644 (file)
@@ -2,7 +2,8 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2011,2012,2013,2014,2015 by the GROMACS development team.
-# Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2016,2017,2018,2019,2020 by the GROMACS development team.
+# Copyright (c) 2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,42 +39,12 @@ if (NOT GMX_BUILD_UNITTESTS)
     return()
 endif()
 
-set(TESTUTILS_SOURCES
-    cmdlinetest.cpp
-    conftest.cpp
-    filematchers.cpp
-    interactivetest.cpp
-    loggertest.cpp
-    mpi_printer.cpp
-    mpitest.cpp
-    refdata.cpp
-    refdata_xml.cpp
-    simulationdatabase.cpp
-    stdiohelper.cpp
-    stringtest.cpp
-    testasserts.cpp
-    testfilemanager.cpp
-    testfileredirector.cpp
-    test_device.cpp
-    test_hardware_environment.cpp
-    testinit.cpp
-    testmatchers.cpp
-    testoptions.cpp
-    textblockmatchers.cpp
-    tprfilegenerator.cpp
-    xvgtest.cpp
-    )
-
-if(NOT HAVE_TINYXML2)
-    list(APPEND TESTUTILS_SOURCES ../external/tinyxml2/tinyxml2.cpp)
-endif()
-
 if (GMX_GPU_CUDA)
     # Work around FindCUDA that prevents using target_link_libraries()
     # with keywords otherwise...
     set(CUDA_LIBRARIES PRIVATE ${CUDA_LIBRARIES})
     if (NOT GMX_CLANG_CUDA)
-        gmx_cuda_add_library(testutils ${TESTUTILS_SOURCES})
+        gmx_cuda_add_library(testutils)
     else()
         set_source_files_properties(test_device.cpp PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ)
         gmx_compile_cuda_file_with_clang(test_device.cpp)
@@ -82,25 +53,71 @@ if (GMX_GPU_CUDA)
     endif()
     target_link_libraries(testutils PRIVATE ${CUDA_CUFFT_LIBRARIES})
 else()
-    add_library(testutils STATIC ${UNITTEST_TARGET_OPTIONS} ${TESTUTILS_SOURCES})
+    add_library(testutils STATIC ${UNITTEST_TARGET_OPTIONS})
+endif()
+
+# Module interface / provided facilities
+target_include_directories(testutils PUBLIC include)
+
+# Executable targets for tests based on `testutils` acquire the source for
+# their entry point from unittest_main.cpp when linking to the `testutils` target.
+target_sources(testutils INTERFACE unittest_main.cpp)
+
+
+target_sources(testutils PRIVATE
+               cmdlinetest.cpp
+               conftest.cpp
+               filematchers.cpp
+               interactivetest.cpp
+               loggertest.cpp
+               mpi_printer.cpp
+               mpitest.cpp
+               refdata.cpp
+               refdata_xml.cpp
+               simulationdatabase.cpp
+               stdiohelper.cpp
+               stringtest.cpp
+               testasserts.cpp
+               testfilemanager.cpp
+               testfileredirector.cpp
+               test_device.cpp
+               test_hardware_environment.cpp
+               testinit.cpp
+               testmatchers.cpp
+               testoptions.cpp
+               textblockmatchers.cpp
+               tprfilegenerator.cpp
+               xvgtest.cpp
+               )
+
+
+if(HAVE_TINYXML2)
+    target_include_directories(testutils SYSTEM PRIVATE ${TinyXML2_INCLUDE_DIR})
+    target_link_libraries(testutils PRIVATE ${TinyXML2_LIBRARIES})
+else()
+    target_include_directories(testutils SYSTEM BEFORE PRIVATE ${CMAKE_SOURCE_DIR}/src/external/tinyxml2)
+    target_sources(testutils PRIVATE ${CMAKE_SOURCE_DIR}/src/external/tinyxml2/tinyxml2.cpp)
 endif()
 
+target_include_directories(testutils PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+
 if (GMX_GPU_SYCL)
-    set_source_files_properties(test_device.cpp
-      PROPERTIES COMPILE_FLAGS "${SYCL_CXX_FLAGS}")
+    add_sycl_to_target(
+        TARGET testutils
+        SOURCES test_device.cpp
+        )
 endif()
 
 gmx_target_compile_options(testutils)
 target_compile_definitions(testutils PRIVATE HAVE_CONFIG_H)
 target_include_directories(testutils SYSTEM BEFORE PRIVATE ${PROJECT_SOURCE_DIR}/src/external/thread_mpi/include)
 target_link_libraries(testutils PRIVATE libgromacs ${GMX_COMMON_LIBRARIES} gmock)
+target_link_libraries(testutils PUBLIC common)
 
-if(HAVE_TINYXML2)
-    include_directories(SYSTEM ${TinyXML2_INCLUDE_DIR})
-    target_link_libraries(testutils PRIVATE ${TinyXML2_LIBRARIES})
-else()
-    include_directories(BEFORE SYSTEM "../external/tinyxml2")
-endif()
+# GROMACS module dependencies.
+# Note that testutils conveys transitive dependencies on some modules.
+# TODO: Explicitly link specific modules with minimal exposure.
+target_link_libraries(testutils PUBLIC legacy_modules)
 
 # TODO Use gmx_add_missing_tests_notice() instead of the messages below.
 set(GMX_CAN_RUN_MPI_TESTS 1)
@@ -128,8 +145,6 @@ 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(GMX_CAN_RUN_MPI_TESTS ${GMX_CAN_RUN_MPI_TESTS} PARENT_SCOPE)
 
 add_subdirectory(tests)
index 70dd60e0364012ebc6ee69948859c61fdf783273..bdd991af4b30e18e5b889000ac093cab689df3ce 100644 (file)
@@ -2,7 +2,8 @@
 # This file is part of the GROMACS molecular simulation package.
 #
 # Copyright (c) 2011,2012,2013,2014,2015 by the GROMACS development team.
-# Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+# Copyright (c) 2016,2017,2018,2019,2020 by the GROMACS development team.
+# Copyright (c) 2021, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and 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,12 +120,10 @@ function (gmx_add_gtest_executable EXENAME)
             cuda_add_executable(${EXENAME} ${UNITTEST_TARGET_OPTIONS}
                 ${ARG_CPP_SOURCE_FILES}
                 ${ARG_CUDA_CU_SOURCE_FILES}
-                ${ARG_GPU_CPP_SOURCE_FILES}
-                ${TESTUTILS_DIR}/unittest_main.cpp)
+                ${ARG_GPU_CPP_SOURCE_FILES})
         else()
             add_executable(${EXENAME} ${UNITTEST_TARGET_OPTIONS}
-                ${ARG_CPP_SOURCE_FILES}
-                ${TESTUTILS_DIR}/unittest_main.cpp)
+                ${ARG_CPP_SOURCE_FILES})
         endif()
 
         if (GMX_GPU_CUDA)
@@ -146,10 +145,11 @@ function (gmx_add_gtest_executable EXENAME)
             endif()
         elseif (GMX_GPU_SYCL)
             target_sources(${EXENAME} PRIVATE ${ARG_SYCL_CPP_SOURCE_FILES} ${ARG_GPU_CPP_SOURCE_FILES})
-            set_source_files_properties(${ARG_GPU_CPP_SOURCE_FILES} PROPERTIES COMPILE_FLAGS "${SYCL_CXX_FLAGS}")
-            set_source_files_properties(${ARG_SYCL_CPP_SOURCE_FILES} PROPERTIES COMPILE_FLAGS "${SYCL_CXX_FLAGS}")
             if(ARG_SYCL_CPP_SOURCE_FILES OR ARG_GPU_CPP_SOURCE_FILES)
-                target_link_libraries(${EXENAME} PRIVATE ${SYCL_CXX_FLAGS})
+                add_sycl_to_target(
+                    TARGET ${EXENAME}
+                    SOURCES ${ARG_SYCL_CPP_SOURCE_FILES} ${ARG_GPU_CPP_SOURCE_FILES}
+                    )
             endif()
         else()
             target_sources(${EXENAME} PRIVATE ${ARG_NON_GPU_CPP_SOURCE_FILES} ${ARG_GPU_CPP_SOURCE_FILES})
@@ -169,7 +169,7 @@ function (gmx_add_gtest_executable EXENAME)
         endif()
 
         target_link_libraries(${EXENAME} PRIVATE
-            testutils libgromacs gmock
+            testutils common libgromacs gmock
             ${GMX_COMMON_LIBRARIES} ${GMX_EXE_LINKER_FLAGS})
 
         if(GMX_CLANG_TIDY)
@@ -214,7 +214,7 @@ function (gmx_register_gtest_test NAME EXENAME)
             # Both OpenCL (from JIT) and ThreadSanitizer (from how it
             # checks) can take signficantly more time than other
             # configurations.
-            if (GMX_GPU_OPENCL)
+            if (GMX_GPU_OPENCL OR GMX_GPU_SYCL)
                 set(_timeout 240)
             elseif (${CMAKE_BUILD_TYPE} STREQUAL TSAN)
                 set(_timeout 300)
index 1c6bdc0f9f8b1b20f53199be6e238e7cc35305f8..ab2b4c0b2eb9a8dc75d0fd4d784e657d4c2d2b49 100644 (file)
@@ -42,7 +42,7 @@
  */
 #include "gmxpre.h"
 
-#include "cmdlinetest.h"
+#include "testutils/cmdlinetest.h"
 
 #include <cstdlib>
 #include <cstring>
@@ -114,8 +114,8 @@ namespace
 std::vector<const char*> convertFromStringArrayRef(const ArrayRef<const std::string>& cmdline)
 {
     std::vector<const char*> v(cmdline.size());
-    std::transform(cmdline.begin(), cmdline.end(), v.begin(),
-                   [](const std::string& s) { return s.c_str(); });
+    std::transform(
+            cmdline.begin(), cmdline.end(), v.begin(), [](const std::string& s) { return s.c_str(); });
     return v;
 }
 
index 6934af51601cbe1ad512ec742049a6439780e8e8..c9fe48523467e426b889df9df362528f6ec073e7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2021, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +41,7 @@
  */
 #include "gmxpre.h"
 
-#include "conftest.h"
+#include "testutils/conftest.h"
 
 #include <cstdio>
 #include <cstdlib>
index d836f4e6fcb3fc04a4b68e0e2ffcab2aaec3c890..a312dddd0ff6fd2eb701680a8523d431a9462f16 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +41,7 @@
  */
 #include "gmxpre.h"
 
-#include "filematchers.h"
+#include "testutils/filematchers.h"
 
 #include "gromacs/utility/filestream.h"
 
similarity index 98%
rename from src/testutils/cmdlinetest.h
rename to src/testutils/include/testutils/cmdlinetest.h
index a06ddc913eb4f50c371fc51b6124ec81205170ef..3dfcd4eac38aa09272be0b050d5cac06482193aa 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +53,6 @@
 // arrayref.h is not strictly necessary for this header, but nearly all
 // callers will need it to use the constructor that takes ArrayRef.
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
@@ -194,7 +193,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \libinternal \brief
@@ -354,7 +353,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 /*! \libinternal \brief
@@ -489,7 +488,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace test
similarity index 97%
rename from src/testutils/conftest.h
rename to src/testutils/include/testutils/conftest.h
index 44ac7d91b9eec7ac4bc1839fe03a83c0307b075d..144a60f436ef66d9c74cf9d9f85529d13329efc4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019,2021, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
similarity index 98%
rename from src/testutils/filematchers.h
rename to src/testutils/include/testutils/filematchers.h
index 84201794a5b460982f407f8c60fdbe1077dbc502..921d44709fe0399faa21030da065e6e647a6e76d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
similarity index 96%
rename from src/testutils/interactivetest.h
rename to src/testutils/include/testutils/interactivetest.h
index 6e0e279deb1ab12dd74746735c56d3699f3cea0b..074455ae068b0f7d87b0eb3a3a17efda3c43ceec 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 +43,9 @@
 #ifndef GMX_TESTUTILS_INTERACTIVETEST_H
 #define GMX_TESTUTILS_INTERACTIVETEST_H
 
+#include <memory>
+
 #include "gromacs/utility/arrayref.h"
-#include "gromacs/utility/classhelpers.h"
 
 namespace gmx
 {
@@ -118,7 +119,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 } // namespace test
 } // namespace gmx
similarity index 88%
rename from src/testutils/loggertest.h
rename to src/testutils/include/testutils/loggertest.h
index 5fe63949ce5fc3bfabbf6b342ca84d1333d7af6d..a597b574e9d6d9fd91c3437479a6cd6af00b8efd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +43,8 @@
 #ifndef GMX_TESTUTILS_LOGGERTEST_H
 #define GMX_TESTUTILS_LOGGERTEST_H
 
-#include "gromacs/utility/classhelpers.h"
+#include <memory>
+
 #include "gromacs/utility/logger.h"
 
 namespace gmx
@@ -79,10 +80,18 @@ public:
      */
     void expectEntryMatchingRegex(gmx::MDLogger::LogLevel level, const char* re);
 
+    /*! \brief
+     * Expects that no log entries were made at a given level.
+     *
+     * If not called for a log level, all entries for that level are
+     * accepted.
+     */
+    void expectNoEntries(gmx::MDLogger::LogLevel level);
+
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace test
similarity index 91%
rename from src/testutils/mpitest.h
rename to src/testutils/include/testutils/mpitest.h
index dbb640a9336ea975cc080a8072ea57af5d410679..37d543937cbfb64c74fcf46f14728e3dc59edda8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,15 +111,15 @@ bool threadMpiTestRunner(std::function<void()> testBody);
  * \ingroup module_testutils
  */
 #if GMX_THREAD_MPI
-#    define GMX_MPI_TEST(expectedRankCount)                                                 \
-        do                                                                                  \
-        {                                                                                   \
-            ASSERT_EQ(expectedRankCount, ::gmx::test::getNumberOfTestMpiRanks());           \
-            using MyTestClass = std::remove_reference_t<decltype(*this)>;                   \
-            if (!::gmx::test::threadMpiTestRunner(std::bind(&MyTestClass::TestBody, this))) \
-            {                                                                               \
-                return;                                                                     \
-            }                                                                               \
+#    define GMX_MPI_TEST(expectedRankCount)                                                     \
+        do                                                                                      \
+        {                                                                                       \
+            ASSERT_EQ(expectedRankCount, ::gmx::test::getNumberOfTestMpiRanks());               \
+            using MyTestClass = std::remove_reference_t<decltype(*this)>;                       \
+            if (!::gmx::test::threadMpiTestRunner([this]() { this->MyTestClass::TestBody(); })) \
+            {                                                                                   \
+                return;                                                                         \
+            }                                                                                   \
         } while (0)
 #else
 #    define GMX_MPI_TEST(expectedRankCount) \
similarity index 99%
rename from src/testutils/refdata.h
rename to src/testutils/include/testutils/refdata.h
index 78b0449b84035230e7e58aa75e0c9b79400b5f91..e57b96769004ef258f462cf4360ea3d2785015c2 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2011-2018, The GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -594,7 +594,7 @@ private:
      */
     explicit TestReferenceChecker(Impl* impl);
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 
     /*! \brief
      * Needed to expose the constructor only to TestReferenceData.
similarity index 97%
rename from src/testutils/setenv.h
rename to src/testutils/include/testutils/setenv.h
index 588d93f921793cad7b9419ce8e1294c3b98bc170..fc577ee3d45ad81ea6625945dc51ab38d8edb9ea 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
similarity index 96%
rename from src/testutils/simulationdatabase.h
rename to src/testutils/include/testutils/simulationdatabase.h
index 11b1e428d9701a96b8f3cb3da35f4753aca0c9dc..02bdc7886bfa0077be7ae3de10c06bc58de53b2d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -40,8 +40,8 @@
  * \inlibraryapi
  * \ingroup module_testutils
  */
-#ifndef GMX_TESTUTILS__SIMULATIONDATABASE_H
-#define GMX_TESTUTILS__SIMULATIONDATABASE_H
+#ifndef GMX_TESTUTILS_SIMULATIONDATABASE_H
+#define GMX_TESTUTILS_SIMULATIONDATABASE_H
 
 #include <map>
 #include <string>
similarity index 96%
rename from src/testutils/stdiohelper.h
rename to src/testutils/include/testutils/stdiohelper.h
index 6cb8b68947ebe466906c5be3e95d490809013209..0c632b834d0afd33e812aac5f44c840088a87240 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,8 @@
 #ifndef GMX_TESTUTILS_STDIOHELPER_H
 #define GMX_TESTUTILS_STDIOHELPER_H
 
+#include <memory>
+
 #include "gromacs/utility/classhelpers.h"
 
 namespace gmx
similarity index 94%
rename from src/testutils/stringtest.h
rename to src/testutils/include/testutils/stringtest.h
index edf09974a114e239f027c10f8eeb26256844cce3..08441dd3f498150b4fb7475e88f4577e99bfc799 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_TESTUTILS_STRINGTEST_H
 #define GMX_TESTUTILS_STRINGTEST_H
 
+#include <memory>
 #include <string>
 
 #include <gtest/gtest.h>
 
-#include "gromacs/utility/classhelpers.h"
-
 namespace gmx
 {
 
@@ -120,12 +119,12 @@ public:
      * \param[in] refFilename   File with the expected contents.
      * \param[in] testFilename  File with the contents to be tested.
      */
-    void testFilesEqual(const std::string& refFilename, const std::string& testFilename);
+    static void testFilesEqual(const std::string& refFilename, const std::string& testFilename);
 
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace test
similarity index 95%
rename from src/testutils/test_device.h
rename to src/testutils/include/testutils/test_device.h
index 3fa7915fcf5a5107185fcfdd15440e3c212cefe0..0b1f011c76a07f37b33e1a920c3c8e50da35ef95 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2020, by the GROMACS development team, led by
+ * Copyright (c) 2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 <map>
+#include <memory>
 #include <string>
 #include <vector>
 
-#include "gromacs/utility/classhelpers.h"
 #include "gromacs/utility/gmxassert.h"
 
 class DeviceContext;
@@ -85,7 +85,7 @@ private:
     //! Implementation type.
     class Impl;
     //! Implementation object.
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace test
similarity index 99%
rename from src/testutils/testasserts.h
rename to src/testutils/include/testutils/testasserts.h
index a737f03e4c6be1920d869b0bd54387280e17bce8..9b1c3d4cea07ab142738a70e327e954c7a902b90 100644 (file)
@@ -509,8 +509,12 @@ static inline FloatingPointTolerance relativeToleranceAsPrecisionDependentUlp(do
                                                                               uint64_t doubleUlpDiff)
 {
     return FloatingPointTolerance(float(magnitude) * singleUlpDiff * GMX_FLOAT_EPS,
-                                  magnitude * doubleUlpDiff * GMX_DOUBLE_EPS, 0.0, 0.0,
-                                  singleUlpDiff, doubleUlpDiff, false);
+                                  magnitude * doubleUlpDiff * GMX_DOUBLE_EPS,
+                                  0.0,
+                                  0.0,
+                                  singleUlpDiff,
+                                  doubleUlpDiff,
+                                  false);
 }
 
 /*! \brief
@@ -573,7 +577,8 @@ static inline FloatingPointTolerance defaultRealTolerance()
 static inline FloatingPointTolerance defaultFloatTolerance()
 {
     return relativeToleranceAsPrecisionDependentUlp(
-            1.0, detail::g_defaultUlpTolerance,
+            1.0,
+            detail::g_defaultUlpTolerance,
             static_cast<uint64_t>(detail::g_defaultUlpTolerance * (GMX_FLOAT_EPS / GMX_DOUBLE_EPS)));
 }
 
similarity index 97%
rename from src/testutils/testexceptions.h
rename to src/testutils/include/testutils/testexceptions.h
index edbdd6b6fa4cda9c4e87ba6558e9d6c391d807b1..86ea316a942165ab724d3a2df3c9c98b1e92cdc3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2012,2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2015,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
similarity index 98%
rename from src/testutils/testfilemanager.h
rename to src/testutils/include/testutils/testfilemanager.h
index 53dbba16c63f556b6947a99b0ea5e4a7923cfbca..d9b8e7c2b1b3aef2467de7d9536ce48011bf7db1 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_TESTUTILS_TESTFILEMANAGER_H
 #define GMX_TESTUTILS_TESTFILEMANAGER_H
 
+#include <memory>
 #include <string>
 
-#include "gromacs/utility/classhelpers.h"
-
 namespace gmx
 {
 /*! \libinternal \brief
@@ -235,7 +234,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace test
similarity index 96%
rename from src/testutils/testfileredirector.h
rename to src/testutils/include/testutils/testfileredirector.h
index 5e34af133bcf9d67c134d17bfc55fe152ebb551c..1574d7a000fabb277964c2d94f7a2ed9b1ff06fb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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_TESTUTILS_TESTFILEREDIRECTOR_H
 #define GMX_TESTUTILS_TESTFILEREDIRECTOR_H
 
+#include <memory>
 #include <set>
 #include <string>
 
@@ -120,7 +121,7 @@ public:
 private:
     class Impl;
 
-    PrivateImplPointer<Impl> impl_;
+    std::unique_ptr<Impl> impl_;
 };
 
 } // namespace test
similarity index 98%
rename from src/testutils/testoptions.h
rename to src/testutils/include/testutils/testoptions.h
index 6b712157312adbdf2f743f58f1fe6f15228297ac..c3421ffff88d1ed472addbbfa0fd027cc0dea27f 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +85,6 @@ protected:
  * \param[in] name     Name of the options provider (for ordering).
  * \param[in] provider The provider to register.
  * \throws  std::bad_alloc     if out of memory.
- * \throws  tMPI::system_error on mutex failures.
  *
  * Typically not used directly in test code, but through the
  * #GMX_TEST_OPTIONS macro.
similarity index 98%
rename from src/testutils/textblockmatchers.h
rename to src/testutils/include/testutils/textblockmatchers.h
index 6eb6be88e9f4b4b4ed641e233caf63ec5ce775b7..67cb5b95bbe5057c8818ebca3206a09b81ce45c7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
similarity index 97%
rename from src/testutils/tprfilegenerator.h
rename to src/testutils/include/testutils/tprfilegenerator.h
index 2073eccfd6945a61bd89be84bd8aa740f9f9ad84..ece2bfe3fac071bd7e250f3f95bf427ac180fa7d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
similarity index 98%
rename from src/testutils/xvgtest.h
rename to src/testutils/include/testutils/xvgtest.h
index 1812cc328d61bb2a571e94b7a32d30f6efc6d56b..5783fff1ed56e1db527f23180b8085388fafc7f1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
index 897a01660ec9c16a99e8d0e7dde20b32ab1559c5..e28dbd751df4fefd94e9fecadfdd6475f02db40d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +41,7 @@
  */
 #include "gmxpre.h"
 
-#include "interactivetest.h"
+#include "testutils/interactivetest.h"
 
 #include <string>
 #include <utility>
index c090c3b2f75dded5864d2e2beec0bf7e8e25c4e1..52a48f94bca8b91c98a93f81607e7d6499b8abab 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +41,7 @@
  */
 #include "gmxpre.h"
 
-#include "loggertest.h"
+#include "testutils/loggertest.h"
 
 #include <gmock/gmock.h>
 
@@ -108,5 +108,11 @@ void LoggerTestHelper::expectEntryMatchingRegex(gmx::MDLogger::LogLevel level, c
     EXPECT_CALL(target, writeEntry(Field(&LogEntry::text, ContainsRegex(re))));
 }
 
+void LoggerTestHelper::expectNoEntries(gmx::MDLogger::LogLevel level)
+{
+    auto& target = impl_->getTarget(level);
+    EXPECT_CALL(target, writeEntry(testing::_)).Times(0);
+}
+
 } // namespace test
 } // namespace gmx
index 63b04b9ce69fcd4dbbfb78dd8bb609d9f3a6d3c4..7c11477f541dcaf2ef0fff9572371db5be562e0d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +41,7 @@
  */
 #include "gmxpre.h"
 
-#include "mpitest.h"
+#include "testutils/mpitest.h"
 
 #include "config.h"
 
index 8c92d6754f5e4256d2bdd0ab53dee71690222523..cfc320c04bec680ac92fdf0645b0a1f1ec2e8815 100644 (file)
@@ -42,7 +42,7 @@
  */
 #include "gmxpre.h"
 
-#include "refdata.h"
+#include "testutils/refdata.h"
 
 #include <cctype>
 #include <cstdlib>
 #include "gromacs/utility/real.h"
 #include "gromacs/utility/stringutil.h"
 
-#include "testutils/refdata_checkers.h"
-#include "testutils/refdata_impl.h"
-#include "testutils/refdata_xml.h"
 #include "testutils/testasserts.h"
 #include "testutils/testexceptions.h"
 #include "testutils/testfilemanager.h"
 
+#include "refdata_checkers.h"
+#include "refdata_impl.h"
+#include "refdata_xml.h"
+
 namespace gmx
 {
 namespace test
@@ -703,9 +704,12 @@ TestReferenceChecker TestReferenceData::rootChecker()
         return TestReferenceChecker(new TestReferenceChecker::Impl(true));
     }
     impl_->compareRootEntry_->setChecked();
-    return TestReferenceChecker(new TestReferenceChecker::Impl(
-            "", impl_->compareRootEntry_.get(), impl_->outputRootEntry_.get(),
-            impl_->updateMismatchingEntries_, impl_->bSelfTestMode_, defaultRealTolerance()));
+    return TestReferenceChecker(new TestReferenceChecker::Impl("",
+                                                               impl_->compareRootEntry_.get(),
+                                                               impl_->outputRootEntry_.get(),
+                                                               impl_->updateMismatchingEntries_,
+                                                               impl_->bSelfTestMode_,
+                                                               defaultRealTolerance()));
 }
 
 
@@ -822,8 +826,11 @@ TestReferenceChecker TestReferenceChecker::checkCompound(const char* type, const
     {
         impl_->outputRootEntry_->addChild(entry->cloneToOutputEntry());
     }
-    return TestReferenceChecker(new Impl(fullId, entry, entry->correspondingOutputEntry(),
-                                         impl_->updateMismatchingEntries_, impl_->bSelfTestMode_,
+    return TestReferenceChecker(new Impl(fullId,
+                                         entry,
+                                         entry->correspondingOutputEntry(),
+                                         impl_->updateMismatchingEntries_,
+                                         impl_->bSelfTestMode_,
                                          impl_->defaultTolerance_));
 }
 
@@ -860,8 +867,8 @@ static void throwIfNonEmptyAndOnlyWhitespace(const std::string& s, const char* i
 
 void TestReferenceChecker::checkBoolean(bool value, const char* id)
 {
-    EXPECT_PLAIN(impl_->processItem(Impl::cBooleanNodeName, id,
-                                    ExactStringChecker(value ? "true" : "false")));
+    EXPECT_PLAIN(impl_->processItem(
+            Impl::cBooleanNodeName, id, ExactStringChecker(value ? "true" : "false")));
 }
 
 
@@ -887,38 +894,38 @@ void TestReferenceChecker::checkTextBlock(const std::string& value, const char*
 
 void TestReferenceChecker::checkUChar(unsigned char value, const char* id)
 {
-    EXPECT_PLAIN(impl_->processItem(Impl::cUCharNodeName, id,
-                                    ExactStringChecker(formatString("%d", value))));
+    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,
-                                    ExactStringChecker(formatString("%d", value))));
+    EXPECT_PLAIN(impl_->processItem(
+            Impl::cIntegerNodeName, id, ExactStringChecker(formatString("%d", value))));
 }
 
 void TestReferenceChecker::checkInt32(int32_t value, const char* id)
 {
-    EXPECT_PLAIN(impl_->processItem(Impl::cInt32NodeName, id,
-                                    ExactStringChecker(formatString("%" PRId32, value))));
+    EXPECT_PLAIN(impl_->processItem(
+            Impl::cInt32NodeName, id, ExactStringChecker(formatString("%" PRId32, value))));
 }
 
 void TestReferenceChecker::checkUInt32(uint32_t value, const char* id)
 {
-    EXPECT_PLAIN(impl_->processItem(Impl::cUInt32NodeName, id,
-                                    ExactStringChecker(formatString("%" PRIu32, value))));
+    EXPECT_PLAIN(impl_->processItem(
+            Impl::cUInt32NodeName, id, ExactStringChecker(formatString("%" PRIu32, value))));
 }
 
 void TestReferenceChecker::checkInt64(int64_t value, const char* id)
 {
-    EXPECT_PLAIN(impl_->processItem(Impl::cInt64NodeName, id,
-                                    ExactStringChecker(formatString("%" PRId64, value))));
+    EXPECT_PLAIN(impl_->processItem(
+            Impl::cInt64NodeName, id, ExactStringChecker(formatString("%" PRId64, value))));
 }
 
 void TestReferenceChecker::checkUInt64(uint64_t value, const char* id)
 {
-    EXPECT_PLAIN(impl_->processItem(Impl::cUInt64NodeName, id,
-                                    ExactStringChecker(formatString("%" PRIu64, value))));
+    EXPECT_PLAIN(impl_->processItem(
+            Impl::cUInt64NodeName, id, ExactStringChecker(formatString("%" PRIu64, value))));
 }
 
 void TestReferenceChecker::checkDouble(double value, const char* id)
index f8c69f791a6cfd1a522fbb31d58db16b4fabda63..9b5c7c2faa7dfe6b1eab4bae2981a53f44a34607 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/strconvert.h"
 #include "gromacs/utility/stringutil.h"
 
-#include "testutils/refdata_impl.h"
 #include "testutils/testasserts.h"
 #include "testutils/testexceptions.h"
 
+#include "refdata_impl.h"
+
 namespace gmx
 {
 namespace test
index 4d2a71775ddbd7bea4f2d174f7e285dab4fae515..aa8dac17b89669599fdfd4373891d0488873fc67 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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/exceptions.h"
 
-#include "testutils/refdata_impl.h"
 #include "testutils/testexceptions.h"
 
+#include "refdata_impl.h"
+
 namespace gmx
 {
 namespace test
index d2a9707ccf9c9b84c361a996259b7e32c821698b..546d87903fe39f5bf6619dbd72af6ff08cae767f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 @@
 
 #include <string>
 
-#include "testutils/refdata_impl.h"
+#include "refdata_impl.h"
 
 namespace gmx
 {
index b8edf036824a120219559e9e2d0e56fb2cd85f1b..1a948a62590b9925aef07d22c9502982c96dfc40 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2016,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +41,7 @@
  */
 #include "gmxpre.h"
 
-#include "simulationdatabase.h"
+#include "testutils/simulationdatabase.h"
 
 #include <algorithm>
 #include <map>
@@ -80,20 +80,44 @@ const MdpFileValues mdpFileValueDatabase_g{
       { { { "ref-t", "80" } },
         { // TODO This test case is not currently used, so we
           // have not tested which rank counts work.
-          1, 2, 3, 4, 5, 6, 7, 8, 9 } } },
+          1,
+          2,
+          3,
+          4,
+          5,
+          6,
+          7,
+          8,
+          9 } } },
     // Simple system with 2 nearby water molecules
     { "spc2",
       { {},
         { // TODO This test case is not currently used, so we
           // have not tested which rank counts work.
-          1, 2, 3, 4, 5, 6, 7, 8, 9 } } },
+          1,
+          2,
+          3,
+          4,
+          5,
+          6,
+          7,
+          8,
+          9 } } },
     // Simple system with 216 water molecules, condensed phase
     { "spc216",
       { {},
         {
                 // TODO This test case is not currently used, so we
                 // have not tested which rank counts work.
-                1, 2, 3, 4, 5, 6, 7, 8, 9 // TODO tpi test
+                1,
+                2,
+                3,
+                4,
+                5,
+                6,
+                7,
+                8,
+                9 // TODO tpi test
         } } },
     // Capped alanine peptide in vacuo with virtual sites
     { "alanine_vsite_vacuo",
@@ -104,7 +128,17 @@ const MdpFileValues mdpFileValueDatabase_g{
       { { { "constraints", "all-bonds" }, { "compressibility", "5e-10" }, { "tau-p", "1000" } },
         { // TODO This test case is not currently used, so we
           // have not tested which rank counts work.
-          1, 2, 3, 4, 5, 6, 7, 8, 9 } } },
+          1,
+          2,
+          3,
+          4,
+          5,
+          6,
+          7,
+          8,
+          9 } } },
+    // Capped alanine peptide in vacuo (no virtual sites)
+    { "alanine_vacuo", { { { "constraints", "h-bonds" } }, { 1, 2, 3, 4, 5, 6, 7, 8, 9 } } },
     // Zwitterionic glycine in vacuo
     { "glycine_vacuo", { { { "constraints", "h-bonds" } }, { 1, 2, 3, 4, 5, 6, 7, 8, 9 } } },
     // Zwitterionic glycine in vacuo, without constraints
@@ -130,20 +164,21 @@ const MdpFileValues mdpFileValueDatabase_g{
           { "compressibility", "5e-10" },
           { "tau-p", "1000" },
           { "constraints", "h-bonds" },
-          { "other",
-            R"(free-energy         = yes
-                                  sc-alpha            = 0.5
-                                  sc-r-power          = 6
-                                  mass-lambdas        = 0.0 0.5 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
-                                  bonded-lambdas      = 0.0 0.0 0.0 0.5 1.0 1.0 1.0 1.0 1.0 1.0 1.0
-                                  restraint-lambdas   = 0.0 0.0 0.0 0.0 0.0 0.5 1.0 1.0 1.0 1.0 1.0
-                                  vdw-lambdas         = 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5 1.0 1.0 1.0
-                                  coul-lambdas        = 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5 1.0
-                                  ;couple-moltype      = nonanol
-                                  ;couple-lambda0      = none
-                                  ;couple-lambda1      = vdw-q
-                                  ;couple-intramol     = yes)" } },
-        { 1, 2, 3, 4, 5, 6, 8, 9 } } }
+          { "free-energy", "yes" },
+          { "sc-alpha", "0.5" },
+          { "sc-r-power", "6" },
+          { "mass-lambdas", "0.0 0.5 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0" },
+          { "bonded-lambdas", "0.0 0.0 0.0 0.5 1.0 1.0 1.0 1.0 1.0 1.0 1.0" },
+          { "restraint-lambdas", "0.0 0.0 0.0 0.0 0.0 0.5 1.0 1.0 1.0 1.0 1.0" },
+          { "vdw-lambdas", "0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5 1.0 1.0 1.0" },
+          { "coul-lambdas", "0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5 1.0" },
+          { ";couple-moltype", "nonanol" },
+          { ";couple-lambda0", "none" },
+          { ";couple-lambda1", "vdw-q" },
+          { ";couple-intramol", "yes" } },
+        { 1, 2, 3, 4, 5, 6, 8, 9 } } },
+    // Artificial test system including all virtual site types
+    { "vsite_test", { {}, { 1, 2, 3, 4, 5, 6, 7, 8, 9 } } },
 };
 
 /*! \brief Prepare default .mdp values
@@ -158,8 +193,6 @@ const MdpFileValues mdpFileValueDatabase_g{
  *
  * \throws  std::bad_alloc     if out of memory
  *          std::out_of_range  if \c simulationName is not in the database
- *
- * Note: Any mdp options that are not added here cannot be used
  */
 MdpFieldValues prepareDefaultMdpFieldValues(const std::string& simulationName)
 {
@@ -181,12 +214,23 @@ MdpFieldValues prepareDefaultMdpFieldValues(const std::string& simulationName)
     mdpFieldValues.insert(MdpField("nstpcouple", "4"));
     mdpFieldValues.insert(MdpField("compressibility", "5e-5"));
     mdpFieldValues.insert(MdpField("constraints", "none"));
-    mdpFieldValues.insert(MdpField("other", ""));
     mdpFieldValues.insert(MdpField("coulombtype", "Cut-off"));
     mdpFieldValues.insert(MdpField("rcoulomb", "0.7"));
     mdpFieldValues.insert(MdpField("vdwtype", "Cut-off"));
     mdpFieldValues.insert(MdpField("rvdw", "0.7"));
     mdpFieldValues.insert(MdpField("nstcalcenergy", "100"));
+    mdpFieldValues.insert(MdpField("rlist", "-1"));
+    mdpFieldValues.insert(MdpField("bd-fric", "1000"));
+    mdpFieldValues.insert(MdpField("verlet-buffer-tolerance", "0.000001"));
+    mdpFieldValues.insert(MdpField("nstlist", "8"));
+    mdpFieldValues.insert(MdpField("ld-seed", "234262"));
+    mdpFieldValues.insert(MdpField("tau-t", "1"));
+    mdpFieldValues.insert(MdpField("tc-grps", "System"));
+    mdpFieldValues.insert(MdpField("pcoupltype", "isotropic"));
+    mdpFieldValues.insert(MdpField("ref-p", "1"));
+    mdpFieldValues.insert(MdpField("constraint-algorithm", "lincs"));
+    mdpFieldValues.insert(MdpField("lincs-order", "2"));
+    mdpFieldValues.insert(MdpField("lincs-iter", "5"));
 
     return mdpFieldValues;
 }
@@ -203,8 +247,8 @@ bool isNumberOfPpRanksSupported(const std::string& simulationName, int possibleN
 std::string reportNumbersOfPpRanksSupported(const std::string& simulationName)
 {
     const auto& possibleNumbers = mdpFileValueDatabase_g.at(simulationName).validPpRankCounts;
-    return formatAndJoin(std::begin(possibleNumbers), std::end(possibleNumbers), ",",
-                         StringFormatter("%d"));
+    return formatAndJoin(
+            std::begin(possibleNumbers), std::end(possibleNumbers), ",", StringFormatter("%d"));
 }
 
 MdpFieldValues prepareMdpFieldValues(const std::string& simulationName,
@@ -248,58 +292,13 @@ std::string prepareMdpFileContents(const MdpFieldValues& mdpFieldValues)
      * currently have a good way to compare forces at steps where
      * energies were not computed with those from rerun on the same
      * coordinates.
-     *
-     * Note: Any mdp options that are not printed here cannot be used
      */
-    return formatString(
-            R"(coulombtype             = %s
-                           rcoulomb                = %s
-                           vdwtype                 = %s
-                           rvdw                    = %s
-                           rlist                   = -1
-                           bd-fric                 = 1000
-                           verlet-buffer-tolerance = 0.000001
-                           nsteps                  = %s
-                           nstenergy               = %s
-                           nstxout                 = %s
-                           nstvout                 = %s
-                           nstfout                 = %s
-                           nstxout-compressed      = %s
-                           nstdhdl                 = %s
-                           nstlist                 = 8
-                           integrator              = %s
-                           ld-seed                 = 234262
-                           tcoupl                  = %s
-                           nsttcouple              = %s
-                           ref-t                   = %s
-                           tau-t                   = 1
-                           tc-grps                 = System
-                           pcoupl                  = %s
-                           nstpcouple              = %s
-                           pcoupltype              = isotropic
-                           ref-p                   = 1
-                           tau-p                   = %s
-                           compressibility         = %s
-                           constraints             = %s
-                           constraint-algorithm    = lincs
-                           lincs-order             = 2
-                           lincs-iter              = 5
-                           nstcalcenergy           = %s
-                           comm-mode               = %s
-                           nstcomm                 = %s
-                           %s)",
-            mdpFieldValues.at("coulombtype").c_str(), mdpFieldValues.at("rcoulomb").c_str(),
-            mdpFieldValues.at("vdwtype").c_str(), mdpFieldValues.at("rvdw").c_str(),
-            mdpFieldValues.at("nsteps").c_str(), mdpFieldValues.at("nstenergy").c_str(),
-            mdpFieldValues.at("nstxout").c_str(), mdpFieldValues.at("nstvout").c_str(),
-            mdpFieldValues.at("nstfout").c_str(), mdpFieldValues.at("nstxout-compressed").c_str(),
-            mdpFieldValues.at("nstdhdl").c_str(), mdpFieldValues.at("integrator").c_str(),
-            mdpFieldValues.at("tcoupl").c_str(), mdpFieldValues.at("nsttcouple").c_str(),
-            mdpFieldValues.at("ref-t").c_str(), mdpFieldValues.at("pcoupl").c_str(),
-            mdpFieldValues.at("nstpcouple").c_str(), mdpFieldValues.at("tau-p").c_str(),
-            mdpFieldValues.at("compressibility").c_str(), mdpFieldValues.at("constraints").c_str(),
-            mdpFieldValues.at("nstcalcenergy").c_str(), mdpFieldValues.at("comm-mode").c_str(),
-            mdpFieldValues.at("nstcomm").c_str(), mdpFieldValues.at("other").c_str());
+    std::string optionString;
+    for (auto const& [key, value] : mdpFieldValues)
+    {
+        optionString += formatString("%-24s = %s\n", key.c_str(), value.c_str());
+    }
+    return optionString;
 }
 
 } // namespace test
diff --git a/src/testutils/simulationdatabase/alanine_vacuo.gro b/src/testutils/simulationdatabase/alanine_vacuo.gro
new file mode 100644 (file)
index 0000000..3b19ad6
--- /dev/null
@@ -0,0 +1,25 @@
+Generated by trjconv : Alanine-dipeptide t=   1.25800
+   22
+    1ACE    CH3    1   2.389   2.391   1.033 -0.7039  0.4613  0.0257
+    1ACE   HH31    2   2.354   2.463   0.960  0.5981 -0.1788 -1.3029
+    1ACE   HH32    3   2.440   2.450   1.109 -0.1149  0.3508 -0.2771
+    1ACE   HH33    4   2.460   2.325   0.982 -0.9598  0.6736 -0.6069
+    1ACE      C    5   2.272   2.319   1.095  0.2222 -0.0856 -0.2558
+    1ACE      O    6   2.221   2.357   1.199  0.2726  0.1210 -0.4387
+    2ALA      N    7   2.219   2.218   1.026  0.4241 -0.9217  0.8026
+    2ALA      H    8   2.266   2.192   0.941  1.5735 -0.8934  1.4029
+    2ALA     CA    9   2.096   2.154   1.056  0.0365 -0.2046  0.2115
+    2ALA     HA   10   2.105   2.106   1.153 -0.0104  0.7343  0.6916
+    2ALA     CB   11   1.968   2.244   1.045 -0.3611  0.0604 -0.0105
+    2ALA    HB1   12   1.950   2.276   0.942 -0.3033  1.7389  0.4634
+    2ALA    HB2   13   1.882   2.189   1.084  0.2534 -0.2994  0.8622
+    2ALA    HB3   14   1.984   2.333   1.106 -1.1497  0.4723 -0.3796
+    2ALA      C   15   2.076   2.046   0.948 -0.3002 -0.0866 -0.1169
+    2ALA      O   16   2.130   2.052   0.836  0.3392  0.2597 -0.0125
+    3NME      N   17   1.992   1.950   0.986  0.0586  0.0225 -0.1088
+    3NME      H   18   1.962   1.955   1.082 -0.6948  0.1462 -0.3441
+    3NME    CH3   19   1.964   1.834   0.902 -0.3035  0.0695 -0.1543
+    3NME   HH31   20   1.957   1.867   0.799  1.3131  1.1659  0.0471
+    3NME   HH32   21   2.050   1.768   0.911 -0.0987  0.4321  0.7448
+    3NME   HH33   22   1.876   1.782   0.939 -0.0292 -0.4463 -0.2141
+   3.00000   3.00000   3.00000
diff --git a/src/testutils/simulationdatabase/alanine_vacuo.ndx b/src/testutils/simulationdatabase/alanine_vacuo.ndx
new file mode 100644 (file)
index 0000000..45f63e7
--- /dev/null
@@ -0,0 +1,32 @@
+[ System ]
+   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15 
+  16   17   18   19   20   21   22 
+[ Protein ]
+   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15 
+  16   17   18   19   20   21   22 
+[ Protein-H ]
+   1    5    6    7    9   11   15   16   17   19 
+[ C-alpha ]
+   9 
+[ Backbone ]
+   5    7    9   15   17 
+[ MainChain ]
+   5    6    7    9   15   16   17 
+[ MainChain+Cb ]
+   5    6    7    9   11   15   16   17 
+[ MainChain+H ]
+   5    6    7    8    9   15   16   17   18 
+[ SideChain ]
+   1    2    3    4   10   11   12   13   14   19   20   21   22 
+[ SideChain-H ]
+   1   11   19 
+[ CA ]
+   9 
+[ C_&_r_1 ]
+   5 
+[ C_&_r_2 ]
+  15 
+[ N_&_r_2 ]
+   7 
+[ N_&_r_3 ]
+  17 
diff --git a/src/testutils/simulationdatabase/alanine_vacuo.top b/src/testutils/simulationdatabase/alanine_vacuo.top
new file mode 100644 (file)
index 0000000..aeb1cbf
--- /dev/null
@@ -0,0 +1,199 @@
+#include "amber99sb-ildn.ff/forcefield.itp"
+
+[ moleculetype ]
+; Name            nrexcl
+ALANINEDIPEPTIDE     3
+
+[ atoms ]
+;   nr       type  resnr residue  atom   cgnr     charge       mass  typeB    chargeB      massB
+; residue   1 ACE rtp ACE  q  0.0
+     1         CT      1    ACE    CH3      1    -0.3662      12.01   ; qtot -0.3662
+     2         HC      1    ACE   HH31      2     0.1123      1.008   ; qtot -0.2539
+     3         HC      1    ACE   HH32      3     0.1123      1.008   ; qtot -0.1416
+     4         HC      1    ACE   HH33      4     0.1123      1.008   ; qtot -0.0293
+     5          C      1    ACE      C      5     0.5972      12.01   ; qtot 0.5679
+     6          O      1    ACE      O      6    -0.5679         16   ; qtot 0
+; residue   2 ALA rtp ALA  q  0.0
+     7          N      2    ALA      N      7    -0.4157      14.01   ; qtot -0.4157
+     8          H      2    ALA      H      8     0.2719      1.008   ; qtot -0.1438
+     9         CT      2    ALA     CA      9     0.0337      12.01   ; qtot -0.1101
+    10         H1      2    ALA     HA     10     0.0823      1.008   ; qtot -0.0278
+    11         CT      2    ALA     CB     11    -0.1825      12.01   ; qtot -0.2103
+    12         HC      2    ALA    HB1     12     0.0603      1.008   ; qtot -0.15
+    13         HC      2    ALA    HB2     13     0.0603      1.008   ; qtot -0.0897
+    14         HC      2    ALA    HB3     14     0.0603      1.008   ; qtot -0.0294
+    15          C      2    ALA      C     15     0.5973      12.01   ; qtot 0.5679
+    16          O      2    ALA      O     16    -0.5679         16   ; qtot 0
+; residue   3 NME rtp NME  q  0.0
+    17          N      3    NME      N     17    -0.4157      14.01   ; qtot -0.4157
+    18          H      3    NME      H     18     0.2719      1.008   ; qtot -0.1438
+    19         CT      3    NME    CH3     19     -0.149      12.01   ; qtot -0.2928
+    20         H1      3    NME   HH31     20     0.0976      1.008   ; qtot -0.1952
+    21         H1      3    NME   HH32     21     0.0976      1.008   ; qtot -0.0976
+    22         H1      3    NME   HH33     22     0.0976      1.008   ; qtot 0
+
+[ bonds ]
+;  ai    aj funct            c0            c1            c2            c3
+    1     2     1 
+    1     3     1 
+    1     4     1 
+    1     5     1 
+    5     6     1 
+    5     7     1 
+    7     8     1 
+    7     9     1 
+    9    10     1 
+    9    11     1 
+    9    15     1 
+   11    12     1 
+   11    13     1 
+   11    14     1 
+   15    16     1 
+   15    17     1 
+   17    18     1 
+   17    19     1 
+   19    20     1 
+   19    21     1 
+   19    22     1 
+
+[ pairs ]
+;  ai    aj funct            c0            c1            c2            c3
+    1     8     1 
+    1     9     1 
+    2     6     1 
+    2     7     1 
+    3     6     1 
+    3     7     1 
+    4     6     1 
+    4     7     1 
+    5    10     1 
+    5    11     1 
+    5    15     1 
+    6     8     1 
+    6     9     1 
+    7    12     1 
+    7    13     1 
+    7    14     1 
+    7    16     1 
+    7    17     1 
+    8    10     1 
+    8    11     1 
+    8    15     1 
+    9    18     1 
+    9    19     1 
+   10    12     1 
+   10    13     1 
+   10    14     1 
+   10    16     1 
+   10    17     1 
+   11    16     1 
+   11    17     1 
+   12    15     1 
+   13    15     1 
+   14    15     1 
+   15    20     1 
+   15    21     1 
+   15    22     1 
+   16    18     1 
+   16    19     1 
+   18    20     1 
+   18    21     1 
+   18    22     1 
+
+[ angles ]
+;  ai    aj    ak funct            c0            c1            c2            c3
+    2     1     3     1 
+    2     1     4     1 
+    2     1     5     1 
+    3     1     4     1 
+    3     1     5     1 
+    4     1     5     1 
+    1     5     6     1 
+    1     5     7     1 
+    6     5     7     1 
+    5     7     8     1 
+    5     7     9     1 
+    8     7     9     1 
+    7     9    10     1 
+    7     9    11     1 
+    7     9    15     1 
+   10     9    11     1 
+   10     9    15     1 
+   11     9    15     1 
+    9    11    12     1 
+    9    11    13     1 
+    9    11    14     1 
+   12    11    13     1 
+   12    11    14     1 
+   13    11    14     1 
+    9    15    16     1 
+    9    15    17     1 
+   16    15    17     1 
+   15    17    18     1 
+   15    17    19     1 
+   18    17    19     1 
+   17    19    20     1 
+   17    19    21     1 
+   17    19    22     1 
+   20    19    21     1 
+   20    19    22     1 
+   21    19    22     1 
+
+[ dihedrals ]
+;  ai    aj    ak    al funct            c0            c1            c2            c3            c4            c5
+    2     1     5     6     9 
+    2     1     5     7     9 
+    3     1     5     6     9 
+    3     1     5     7     9 
+    4     1     5     6     9 
+    4     1     5     7     9 
+    1     5     7     8     9 
+    1     5     7     9     9 
+    6     5     7     8     9 
+    6     5     7     9     9 
+    5     7     9    10     9 
+    5     7     9    11     9 
+    5     7     9    15     9 
+    8     7     9    10     9 
+    8     7     9    11     9 
+    8     7     9    15     9 
+    7     9    11    12     9 
+    7     9    11    13     9 
+    7     9    11    14     9 
+   10     9    11    12     9 
+   10     9    11    13     9 
+   10     9    11    14     9 
+   15     9    11    12     9 
+   15     9    11    13     9 
+   15     9    11    14     9 
+    7     9    15    16     9 
+    7     9    15    17     9 
+   10     9    15    16     9 
+   10     9    15    17     9 
+   11     9    15    16     9 
+   11     9    15    17     9 
+    9    15    17    18     9 
+    9    15    17    19     9 
+   16    15    17    18     9 
+   16    15    17    19     9 
+   15    17    19    20     9 
+   15    17    19    21     9 
+   15    17    19    22     9 
+   18    17    19    20     9 
+   18    17    19    21     9 
+   18    17    19    22     9 
+
+[ dihedrals ]
+;  ai    aj    ak    al funct            c0            c1            c2            c3
+    1     7     5     6     4 
+    5     9     7     8     4 
+    9    17    15    16     4 
+   15    19    17    18     4 
+
+[ system ]
+; Name
+Alanine-dipeptide
+
+[ molecules ]
+; Compound        #mols
+ALANINEDIPEPTIDE     1
index d178fb5b0e2ad06fba8cec3a39f5e777d959182f..5119ad8a3a29fc06ed1fb8079fd17c3c7253c3a1 100644 (file)
 [ System ]
-   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15 
-  16   17   18   19   20   21   22   23   24   25   26   27   28   29   30 
-  31   32   33   34   35   36   37   38   39   40   41   42   43   44   45 
-  46   47   48   49   50   51   52   53   54   55   56   57   58   59   60 
-  61   62   63   64   65   66   67   68   69   70   71   72   73   74   75 
-  76   77   78   79   80   81   82   83   84   85   86   87   88   89   90 
-  91   92   93   94   95   96   97   98   99  100  101  102  103  104  105 
- 106  107  108  109  110  111  112  113  114  115  116  117  118  119  120 
- 121  122  123  124  125  126  127  128  129  130  131  132  133  134  135 
- 136  137  138  139  140  141  142  143  144  145  146  147  148  149  150 
- 151  152  153  154  155  156  157  158  159  160  161  162  163  164  165 
- 166  167  168  169  170  171  172  173  174  175  176  177  178  179  180 
- 181  182  183  184  185  186  187  188  189  190  191  192  193  194  195 
- 196  197  198  199  200  201  202  203  204  205  206  207  208  209  210 
- 211  212  213  214  215  216  217  218  219  220  221  222  223  224  225 
- 226  227  228  229  230  231  232  233  234  235  236  237  238  239  240 
- 241  242  243  244  245  246  247  248  249  250  251  252  253  254  255 
- 256  257  258  259  260  261  262  263  264  265  266  267  268  269  270 
- 271  272  273  274  275  276  277  278  279  280  281  282  283  284  285 
- 286  287  288  289  290  291  292  293  294  295  296  297  298  299  300 
- 301  302  303  304  305  306  307  308  309  310  311  312  313  314  315 
- 316  317  318  319  320  321  322  323  324  325  326  327  328  329  330 
- 331  332  333  334  335  336  337  338  339  340  341  342  343  344  345 
- 346  347  348  349  350  351  352  353  354  355  356  357  358  359  360 
- 361  362  363  364  365  366  367  368  369  370  371  372  373  374  375 
- 376  377  378  379  380  381  382  383  384  385  386  387  388  389  390 
- 391  392  393  394  395  396  397  398  399  400  401  402  403  404  405 
- 406  407  408  409  410  411  412  413  414  415  416  417  418  419  420 
- 421  422  423  424  425  426  427  428  429  430  431  432  433  434  435 
- 436  437  438  439  440  441  442  443  444  445  446  447  448  449  450 
- 451  452  453  454  455  456  457  458  459  460  461  462  463  464  465 
- 466  467  468  469  470  471  472  473  474  475  476  477  478  479  480 
- 481  482  483  484  485  486  487  488  489  490  491  492  493  494  495 
- 496  497  498  499  500  501  502  503  504  505  506  507  508  509  510 
- 511  512  513  514  515  516  517  518  519  520  521  522  523  524  525 
- 526  527  528  529  530  531  532  533  534  535  536  537  538  539  540 
- 541  542  543  544  545  546  547  548  549  550  551  552  553  554  555 
- 556  557  558  559  560  561  562  563  564  565  566  567  568  569  570 
- 571  572  573  574  575  576  577  578  579  580  581  582  583  584  585 
- 586  587  588  589  590  591  592  593  594  595  596  597  598  599  600 
- 601  602  603  604  605  606  607  608  609  610  611  612  613  614  615 
- 616  617  618  619  620  621  622  623  624  625  626  627  628  629  630 
- 631  632  633  634  635  636  637  638  639  640  641  642  643  644  645 
- 646  647  648  649  650  651  652  653  654  655  656  657  658  659  660 
- 661  662  663  664  665  666  667  668  669  670  671  672  673  674  675 
- 676  677  678  679  680  681  682  683  684  685  686  687  688  689  690 
- 691  692  693  694  695  696  697  698  699  700  701  702  703  704  705 
- 706  707  708  709  710  711  712  713  714  715  716  717  718  719  720 
- 721  722  723  724  725  726  727  728  729  730  731  732  733  734  735 
- 736  737  738  739  740  741  742  743  744  745  746  747  748  749  750 
- 751  752  753  754  755  756  757  758  759  760  761  762  763  764  765 
- 766  767  768  769  770  771  772  773  774  775  776  777  778  779  780 
- 781  782  783  784  785  786  787  788  789  790  791  792  793  794  795 
- 796  797  798  799  800  801  802  803  804  805  806  807  808  809  810 
- 811  812  813  814  815  816  817  818  819  820  821  822  823  824  825 
- 826  827  828  829  830  831  832  833  834  835  836  837  838  839  840 
- 841  842  843  844  845  846  847  848  849  850  851  852  853  854  855 
- 856  857  858  859  860  861  862  863  864  865  866  867  868  869  870 
- 871  872  873  874  875  876  877  878  879  880  881  882  883  884  885 
- 886  887  888  889  890  891  892  893  894  895  896  897  898  899  900 
- 901  902  903  904  905  906  907  908  909  910  911  912  913  914  915 
- 916  917  918  919  920  921  922  923 
+   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15
+  16   17   18   19   20   21   22   23   24   25   26   27   28   29   30
+  31   32   33   34   35   36   37   38   39   40   41   42   43   44   45
+  46   47   48   49   50   51   52   53   54   55   56   57   58   59   60
+  61   62   63   64   65   66   67   68   69   70   71   72   73   74   75
+  76   77   78   79   80   81   82   83   84   85   86   87   88   89   90
+  91   92   93   94   95   96   97   98   99  100  101  102  103  104  105
+ 106  107  108  109  110  111  112  113  114  115  116  117  118  119  120
+ 121  122  123  124  125  126  127  128  129  130  131  132  133  134  135
+ 136  137  138  139  140  141  142  143  144  145  146  147  148  149  150
+ 151  152  153  154  155  156  157  158  159  160  161  162  163  164  165
+ 166  167  168  169  170  171  172  173  174  175  176  177  178  179  180
+ 181  182  183  184  185  186  187  188  189  190  191  192  193  194  195
+ 196  197  198  199  200  201  202  203  204  205  206  207  208  209  210
+ 211  212  213  214  215  216  217  218  219  220  221  222  223  224  225
+ 226  227  228  229  230  231  232  233  234  235  236  237  238  239  240
+ 241  242  243  244  245  246  247  248  249  250  251  252  253  254  255
+ 256  257  258  259  260  261  262  263  264  265  266  267  268  269  270
+ 271  272  273  274  275  276  277  278  279  280  281  282  283  284  285
+ 286  287  288  289  290  291  292  293  294  295  296  297  298  299  300
+ 301  302  303  304  305  306  307  308  309  310  311  312  313  314  315
+ 316  317  318  319  320  321  322  323  324  325  326  327  328  329  330
+ 331  332  333  334  335  336  337  338  339  340  341  342  343  344  345
+ 346  347  348  349  350  351  352  353  354  355  356  357  358  359  360
+ 361  362  363  364  365  366  367  368  369  370  371  372  373  374  375
+ 376  377  378  379  380  381  382  383  384  385  386  387  388  389  390
+ 391  392  393  394  395  396  397  398  399  400  401  402  403  404  405
+ 406  407  408  409  410  411  412  413  414  415  416  417  418  419  420
+ 421  422  423  424  425  426  427  428  429  430  431  432  433  434  435
+ 436  437  438  439  440  441  442  443  444  445  446  447  448  449  450
+ 451  452  453  454  455  456  457  458  459  460  461  462  463  464  465
+ 466  467  468  469  470  471  472  473  474  475  476  477  478  479  480
+ 481  482  483  484  485  486  487  488  489  490  491  492  493  494  495
+ 496  497  498  499  500  501  502  503  504  505  506  507  508  509  510
+ 511  512  513  514  515  516  517  518  519  520  521  522  523  524  525
+ 526  527  528  529  530  531  532  533  534  535  536  537  538  539  540
+ 541  542  543  544  545  546  547  548  549  550  551  552  553  554  555
+ 556  557  558  559  560  561  562  563  564  565  566  567  568  569  570
+ 571  572  573  574  575  576  577  578  579  580  581  582  583  584  585
+ 586  587  588  589  590  591  592  593  594  595  596  597  598  599  600
+ 601  602  603  604  605  606  607  608  609  610  611  612  613  614  615
+ 616  617  618  619  620  621  622  623  624  625  626  627  628  629  630
+ 631  632  633  634  635  636  637  638  639  640  641  642  643  644  645
+ 646  647  648  649  650  651  652  653  654  655  656  657  658  659  660
+ 661  662  663  664  665  666  667  668  669  670  671  672  673  674  675
+ 676  677  678  679  680  681  682  683  684  685  686  687  688  689  690
+ 691  692  693  694  695  696  697  698  699  700  701  702  703  704  705
+ 706  707  708  709  710  711  712  713  714  715  716  717  718  719  720
+ 721  722  723  724  725  726  727  728  729  730  731  732  733  734  735
+ 736  737  738  739  740  741  742  743  744  745  746  747  748  749  750
+ 751  752  753  754  755  756  757  758  759  760  761  762  763  764  765
+ 766  767  768  769  770  771  772  773  774  775  776  777  778  779  780
+ 781  782  783  784  785  786  787  788  789  790  791  792  793  794  795
+ 796  797  798  799  800  801  802  803  804  805  806  807  808  809  810
+ 811  812  813  814  815  816  817  818  819  820  821  822  823  824  825
+ 826  827  828  829  830  831  832  833  834  835  836  837  838  839  840
+ 841  842  843  844  845  846  847  848  849  850  851  852  853  854  855
+ 856  857  858  859  860  861  862  863  864  865  866  867  868  869  870
+ 871  872  873  874  875  876  877  878  879  880  881  882  883  884  885
+ 886  887  888  889  890  891  892  893  894  895  896  897  898  899  900
+ 901  902  903  904  905  906  907  908  909  910  911  912  913  914  915
+ 916  917  918  919  920  921  922  923
+[ Protein ]
+   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15
+  16   17   18   19   20   21   22   23   24   25   26   27   28   29
+[ Water ]
+  30   31   32   33   34   35   36   37   38   39   40   41   42   43   44
+  45   46   47   48   49   50   51   52   53   54   55   56   57   58   59
+  60   61   62   63   64   65   66   67   68   69   70   71   72   73   74
+  75   76   77   78   79   80   81   82   83   84   85   86   87   88   89
+  90   91   92   93   94   95   96   97   98   99  100  101  102  103  104
+ 105  106  107  108  109  110  111  112  113  114  115  116  117  118  119
+ 120  121  122  123  124  125  126  127  128  129  130  131  132  133  134
+ 135  136  137  138  139  140  141  142  143  144  145  146  147  148  149
+ 150  151  152  153  154  155  156  157  158  159  160  161  162  163  164
+ 165  166  167  168  169  170  171  172  173  174  175  176  177  178  179
+ 180  181  182  183  184  185  186  187  188  189  190  191  192  193  194
+ 195  196  197  198  199  200  201  202  203  204  205  206  207  208  209
+ 210  211  212  213  214  215  216  217  218  219  220  221  222  223  224
+ 225  226  227  228  229  230  231  232  233  234  235  236  237  238  239
+ 240  241  242  243  244  245  246  247  248  249  250  251  252  253  254
+ 255  256  257  258  259  260  261  262  263  264  265  266  267  268  269
+ 270  271  272  273  274  275  276  277  278  279  280  281  282  283  284
+ 285  286  287  288  289  290  291  292  293  294  295  296  297  298  299
+ 300  301  302  303  304  305  306  307  308  309  310  311  312  313  314
+ 315  316  317  318  319  320  321  322  323  324  325  326  327  328  329
+ 330  331  332  333  334  335  336  337  338  339  340  341  342  343  344
+ 345  346  347  348  349  350  351  352  353  354  355  356  357  358  359
+ 360  361  362  363  364  365  366  367  368  369  370  371  372  373  374
+ 375  376  377  378  379  380  381  382  383  384  385  386  387  388  389
+ 390  391  392  393  394  395  396  397  398  399  400  401  402  403  404
+ 405  406  407  408  409  410  411  412  413  414  415  416  417  418  419
+ 420  421  422  423  424  425  426  427  428  429  430  431  432  433  434
+ 435  436  437  438  439  440  441  442  443  444  445  446  447  448  449
+ 450  451  452  453  454  455  456  457  458  459  460  461  462  463  464
+ 465  466  467  468  469  470  471  472  473  474  475  476  477  478  479
+ 480  481  482  483  484  485  486  487  488  489  490  491  492  493  494
+ 495  496  497  498  499  500  501  502  503  504  505  506  507  508  509
+ 510  511  512  513  514  515  516  517  518  519  520  521  522  523  524
+ 525  526  527  528  529  530  531  532  533  534  535  536  537  538  539
+ 540  541  542  543  544  545  546  547  548  549  550  551  552  553  554
+ 555  556  557  558  559  560  561  562  563  564  565  566  567  568  569
+ 570  571  572  573  574  575  576  577  578  579  580  581  582  583  584
+ 585  586  587  588  589  590  591  592  593  594  595  596  597  598  599
+ 600  601  602  603  604  605  606  607  608  609  610  611  612  613  614
+ 615  616  617  618  619  620  621  622  623  624  625  626  627  628  629
+ 630  631  632  633  634  635  636  637  638  639  640  641  642  643  644
+ 645  646  647  648  649  650  651  652  653  654  655  656  657  658  659
+ 660  661  662  663  664  665  666  667  668  669  670  671  672  673  674
+ 675  676  677  678  679  680  681  682  683  684  685  686  687  688  689
+ 690  691  692  693  694  695  696  697  698  699  700  701  702  703  704
+ 705  706  707  708  709  710  711  712  713  714  715  716  717  718  719
+ 720  721  722  723  724  725  726  727  728  729  730  731  732  733  734
+ 735  736  737  738  739  740  741  742  743  744  745  746  747  748  749
+ 750  751  752  753  754  755  756  757  758  759  760  761  762  763  764
+ 765  766  767  768  769  770  771  772  773  774  775  776  777  778  779
+ 780  781  782  783  784  785  786  787  788  789  790  791  792  793  794
+ 795  796  797  798  799  800  801  802  803  804  805  806  807  808  809
+ 810  811  812  813  814  815  816  817  818  819  820  821  822  823  824
+ 825  826  827  828  829  830  831  832  833  834  835  836  837  838  839
+ 840  841  842  843  844  845  846  847  848  849  850  851  852  853  854
+ 855  856  857  858  859  860  861  862  863  864  865  866  867  868  869
+ 870  871  872  873  874  875  876  877  878  879  880  881  882  883  884
+ 885  886  887  888  889  890  891  892  893  894  895  896  897  898  899
+ 900  901  902  903  904  905  906  907  908  909  910  911  912  913  914
+ 915  916  917  918  919  920  921  922  923
+[ some_water_subset ]
+  30   31   32   33   34   35   36   37   38   39   40   41   42   43   44
+  45   46   47
diff --git a/src/testutils/simulationdatabase/alanine_vsite_solvated.xtc b/src/testutils/simulationdatabase/alanine_vsite_solvated.xtc
new file mode 100644 (file)
index 0000000..94634ee
Binary files /dev/null and b/src/testutils/simulationdatabase/alanine_vsite_solvated.xtc differ
diff --git a/src/testutils/simulationdatabase/msd.ndx b/src/testutils/simulationdatabase/msd.ndx
new file mode 100644 (file)
index 0000000..ec955c4
--- /dev/null
@@ -0,0 +1,2 @@
+[ particles ]
+1 2 3
diff --git a/src/testutils/simulationdatabase/msd_coords.gro b/src/testutils/simulationdatabase/msd_coords.gro
new file mode 100644 (file)
index 0000000..294f9bc
--- /dev/null
@@ -0,0 +1,6 @@
+msd_beads
+    3
+    1A        A    1   2.167   1.833   1.500
+    2A        A    2   0.000   0.000   0.000
+    3A        A    3   3.167   3.833   4.500
+   5.00000   5.00000   5.00000
diff --git a/src/testutils/simulationdatabase/msd_traj.xtc b/src/testutils/simulationdatabase/msd_traj.xtc
new file mode 100644 (file)
index 0000000..28bb267
Binary files /dev/null and b/src/testutils/simulationdatabase/msd_traj.xtc differ
diff --git a/src/testutils/simulationdatabase/vsite_test.gro b/src/testutils/simulationdatabase/vsite_test.gro
new file mode 100644 (file)
index 0000000..b44951e
--- /dev/null
@@ -0,0 +1,27 @@
+UNITED ATOM STRUCTURE FOR MOLECULE VSTEST
+   24
+    1VSTST   C1    1   1.537   2.466   2.499
+    1VSTST   C2    2   1.666   2.549   2.500
+    1VSTST   C3    3   1.793   2.464   2.500
+    1VSTST   C4    4   1.922   2.547   2.500
+    1VSTST   C5    5   2.050   2.462   2.501
+    1VSTST   C6    6   2.179   2.545   2.500
+    1VSTST   C7    7   2.307   2.460   2.500
+    1VSTST   C8    8   2.436   2.543   2.500
+    1VSTST   C9    9   2.564   2.457   2.500
+    1VSTST  C10   10   2.693   2.540   2.500
+    1VSTST  C11   11   2.821   2.455   2.500
+    1VSTST  C12   12   2.950   2.538   2.499
+    1VSTST  C13   13   3.078   2.453   2.500
+    1VSTST  C14   14   3.207   2.536   2.500
+    1VSTST  C15   15   3.334   2.451   2.500
+    1VSTST  C16   16   3.463   2.534   2.501
+    1VSTST  VS1   17   2.500   2.500   2.500
+    1VSTST  VS2   18   2.500   2.500   2.500
+    1VSTST  VS3   19   2.500   2.500   2.500
+    1VSTST  VS4   20   2.500   2.500   2.500
+    1VSTST  VS5   21   2.500   2.500   2.500
+    1VSTST  VS6   22   2.500   2.500   2.500
+    1VSTST  VS7   23   2.500   2.500   2.500
+    1VSTST  VS8   24   2.500   2.500   2.500
+   5.00000   5.00000   5.00000
diff --git a/src/testutils/simulationdatabase/vsite_test.ndx b/src/testutils/simulationdatabase/vsite_test.ndx
new file mode 100644 (file)
index 0000000..eaaa03a
--- /dev/null
@@ -0,0 +1,3 @@
+[ System ]
+   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15 
+  16   17   18   19   20   21   22   23   24
diff --git a/src/testutils/simulationdatabase/vsite_test.top b/src/testutils/simulationdatabase/vsite_test.top
new file mode 100644 (file)
index 0000000..f6c9ce0
--- /dev/null
@@ -0,0 +1,154 @@
+; Combination of a GROMOS54A7 hexadecane (from ATB) with some
+; added virtual sites for testing purposes. Not a physical system.
+
+[ defaults ]
+; nbfunc       comb-rule       gen-pairs       fudgeLJ fudgeQQ
+  1            1               no              1.0     1.0
+[ atomtypes ]
+;name  at.num   mass      charge  ptype       c6           c12
+  CH2    6      0.000      0.000     A  0.0074684164  3.3965584e-05
+  CH3    6      0.000      0.000     A  0.0096138025  2.6646244e-05
+  DUM    0      0.000      0.000     A           0           0
+[ nonbond_params ]                     
+;      i       j       func    c6      c12
+       CH3     CH2     1       8.473481E-03    3.008414E-05
+       DUM     CH2     1       0.000000E+00    0.000000E+00
+       DUM     CH3     1       0.000000E+00    0.000000E+00
+[ pairtypes ]                  
+;      i       j       func    c6      c12
+       CH2     CH2     1       4.723813E-03    4.741926E-06
+       CH3     CH2     1       5.689469E-03    5.347702E-06
+       CH3     CH3     1       6.852528E-03    6.030865E-06
+               DUM     CH2     1       0.000000E+00    0.000000E+00
+       DUM     CH3     1       0.000000E+00    0.000000E+00
+        DUM    DUM     1       0.000000E+00    0.000000E+00
+
+
+[ moleculetype ]
+; Name   nrexcl
+VSTEST     3
+
+[ atoms ]
+;  nr  type  resnr  resid  atom  cgnr  charge    mass
+    1   CH3    1   VSTEST    C1    1   -0.016  15.0350
+    2   CH2    1   VSTEST    C2    2    0.013  14.0270
+    3   CH2    1   VSTEST    C3    3    0.012  14.0270
+    4   CH2    1   VSTEST    C4    4   -0.010  14.0270
+    5   CH2    1   VSTEST    C5    5   -0.004  14.0270
+    6   CH2    1   VSTEST    C6    6    0.006  14.0270
+    7   CH2    1   VSTEST    C7    7    0.001  14.0270
+    8   CH2    1   VSTEST    C8    8   -0.002  14.0270
+    9   CH2    1   VSTEST    C9    9   -0.002  14.0270
+   10   CH2    1   VSTEST   C10   10    0.001  14.0270
+   11   CH2    1   VSTEST   C11   11    0.006  14.0270
+   12   CH2    1   VSTEST   C12   12   -0.004  14.0270
+   13   CH2    1   VSTEST   C13   13   -0.010  14.0270
+   14   CH2    1   VSTEST   C14   14    0.012  14.0270
+   15   CH2    1   VSTEST   C15   15    0.013  14.0270
+   16   CH3    1   VSTEST   C16   16   -0.016  15.0350
+   17   DUM    1   VSTEST   VS1   17    0.010   0.0
+   18   DUM    1   VSTEST   VS2   18   -0.010   0.0
+   19   DUM    1   VSTEST   VS3   19    0.010   0.0
+   20   DUM    1   VSTEST   VS4   20   -0.010   0.0
+   21   DUM    1   VSTEST   VS5   21    0.010   0.0
+   22   DUM    1   VSTEST   VS6   22   -0.010   0.0
+   23   DUM    1   VSTEST   VS7   23    0.010   0.0
+   24   DUM    1   VSTEST   VS8   24   -0.010   0.0
+; total charge of the molecule:   0.000
+[ bonds ]
+;  ai   aj  funct   c0         c1
+    1    2    2   0.1530   7.1500e+06
+    2    3    2   0.1530   7.1500e+06
+    3    4    2   0.1530   7.1500e+06
+    4    5    2   0.1530   7.1500e+06
+    5    6    2   0.1530   7.1500e+06
+    6    7    2   0.1530   7.1500e+06
+    7    8    2   0.1530   7.1500e+06
+    8    9    2   0.1530   7.1500e+06
+    9   10    2   0.1530   7.1500e+06
+   10   11    2   0.1530   7.1500e+06
+   11   12    2   0.1530   7.1500e+06
+   12   13    2   0.1530   7.1500e+06
+   13   14    2   0.1530   7.1500e+06
+   14   15    2   0.1530   7.1500e+06
+   15   16    2   0.1530   7.1500e+06
+[ pairs ]
+;  ai   aj  funct  ;  all 1-4 pairs but the ones excluded in GROMOS itp
+    1    4    1
+    2    5    1
+    3    6    1
+    4    7    1
+    5    8    1
+    6    9    1
+    7   10    1
+    8   11    1
+    9   12    1
+   10   13    1
+   11   14    1
+   12   15    1
+   13   16    1
+[ angles ]
+;  ai   aj   ak  funct   angle     fc
+    1    2    3    2    111.00   530.00
+    2    3    4    2    111.00   530.00
+    3    4    5    2    111.00   530.00
+    4    5    6    2    111.00   530.00
+    5    6    7    2    111.00   530.00
+    6    7    8    2    111.00   530.00
+    7    8    9    2    111.00   530.00
+    8    9   10    2    111.00   530.00
+    9   10   11    2    111.00   530.00
+   10   11   12    2    111.00   530.00
+   11   12   13    2    111.00   530.00
+   12   13   14    2    111.00   530.00
+   13   14   15    2    111.00   530.00
+   14   15   16    2    111.00   530.00
+[ dihedrals ]
+;  ai   aj   ak   al  funct    ph0      cp     mult
+    1    2    3    4    1      0.00     5.92    3
+    2    3    4    5    1      0.00     5.92    3
+    3    4    5    6    1      0.00     5.92    3
+    4    5    6    7    1      0.00     5.92    3
+    5    6    7    8    1      0.00     5.92    3
+    6    7    8    9    1      0.00     5.92    3
+    7    8    9   10    1      0.00     5.92    3
+    8    9   10   11    1      0.00     5.92    3
+    9   10   11   12    1      0.00     5.92    3
+   10   11   12   13    1      0.00     5.92    3
+   11   12   13   14    1      0.00     5.92    3
+   12   13   14   15    1      0.00     5.92    3
+   13   14   15   16    1      0.00     5.92    3
+[ exclusions ]
+;  ai   aj  funct  ;  GROMOS 1-4 exclusions
+[ virtual_sites1 ]
+; Site  from        funct
+  17    1           1
+[ virtual_sites2 ]
+; Site  from        funct  a
+  18    2     3     1      0.7439756
+[ virtual_sites2 ]
+; Site  from        funct  a
+  19    3     4     2      0.7439756
+[ virtual_sites3 ]
+; Site  from               funct   a          b
+  20    4     5     6      1       0.7439756  0.128012
+[ virtual_sites3 ]
+; Site  from               funct   a          d
+  21    6     7     8      2       0.5        -0.105
+[ virtual_sites3 ]
+; Site  from               funct   theta      d
+  22    8     9    10      3       120        0.5
+[ virtual_sites3 ]
+; Site  from               funct   a          b          c
+  23    10   11    12      4       -0.4       -0.4       6.9281
+[ virtual_sites4 ]
+; Site  from                      funct   a          b          c
+  24    12   13    14    15       2       1.0        0.9       0.105
+
+[ system ]
+; Name
+Virtual sites test system in vacuo
+
+[ molecules ]
+; Compound        #mols
+VSTEST 1
index 4afb9ba460474ca45a246152c50a7e6713697177..8bceb0c9238b0741a5a030e66ed8b1075354f7bb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +41,7 @@
  */
 #include "gmxpre.h"
 
-#include "stdiohelper.h"
+#include "testutils/stdiohelper.h"
 
 #include <cerrno>
 #include <cstdio>
index 452c300435d9ae72e4d1a0c3e385a282dccf1e1d..4e5e8b0ae2927fb709b110fa4fa735d4f2720975 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +41,7 @@
  */
 #include "gmxpre.h"
 
-#include "stringtest.h"
+#include "testutils/stringtest.h"
 
 #include <string>
 
index 8d3865eee0a8920e4588a631230cfa175cf5a544..6865e949845440dfb00e00f478dea368f5290e13 100644 (file)
@@ -43,7 +43,7 @@
  */
 #include "gmxpre.h"
 
-#include "test_device.h"
+#include "testutils/test_device.h"
 
 #include <memory>
 
index 5a06c351318f4ad0d88848e12b741ee4087db4d1..c42f02d9e91ca741d13b005bb2c89d0fcfb4047d 100644 (file)
@@ -44,7 +44,7 @@
 
 #include "gmxpre.h"
 
-#include "test_hardware_environment.h"
+#include "testutils/test_hardware_environment.h"
 
 #include <memory>
 
index acf173cd957aa2a762d83e1fdbf3bb21cd062b1b..45c483a32bd98d050780aaa4d4ab98473b082c54 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2016,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +41,7 @@
  */
 #include "gmxpre.h"
 
-#include "testasserts.h"
+#include "testutils/testasserts.h"
 
 #include <cmath>
 #include <cstdio>
@@ -228,8 +228,11 @@ std::string FloatingPointDifference::toString() const
         relDiffStr = formatString("Inf");
     }
 
-    return formatString("%g (%" PRIu64 " %s-prec. ULPs, rel. %s)%s", absoluteDifference_,
-                        ulpDifference_, isDouble() ? "double" : "single", relDiffStr.c_str(),
+    return formatString("%g (%" PRIu64 " %s-prec. ULPs, rel. %s)%s",
+                        absoluteDifference_,
+                        ulpDifference_,
+                        isDouble() ? "double" : "single",
+                        relDiffStr.c_str(),
                         bSignDifference_ ? ", signs differ" : "");
 }
 
index cb0a1ceeb5b1203298b6762c562ff8c7f3187397..99748ff77fbc39c64e18e54ffb71a357e6b16c02 100644 (file)
@@ -42,7 +42,7 @@
  */
 #include "gmxpre.h"
 
-#include "testfilemanager.h"
+#include "testutils/testfilemanager.h"
 
 #include <cstdio>
 
@@ -214,11 +214,8 @@ std::string TestFileManager::getInputFilePath(const char* filename)
         // Assume file is in global directory for simulation input files.
         return Path::join(getTestSimulationDatabaseDirectory(), filename);
     }
-    else
-    {
-        // Assume file is present locally without full name (e.g. extension).
-        return Path::join(getInputDataDirectory(), filename);
-    }
+    // Assume file is present locally without full name (e.g. extension).
+    return Path::join(getInputDataDirectory(), filename);
 }
 
 std::string TestFileManager::getInputFilePath(const std::string& filename)
index da0e74ae216395ea4e4cbc3b029f36d14553127f..d233ae017851335f68a9dd8ec3e80fc8e9d8a7c1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +41,7 @@
  */
 #include "gmxpre.h"
 
-#include "testfileredirector.h"
+#include "testutils/testfileredirector.h"
 
 #include <memory>
 #include <set>
index 753b814a0f3669d90f5a31ef8b80b335b47d1ccc..e88d74c92a062fabfbb415c4b6e04fb1b971064e 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
- * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2017,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +42,7 @@
  */
 #include "gmxpre.h"
 
-#include "testinit.h"
+#include "testutils/testinit.h"
 
 #include <cstdio>
 #include <cstdlib>
 #include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/textwriter.h"
 
-#include "testutils/mpi_printer.h"
 #include "testutils/refdata.h"
 #include "testutils/test_hardware_environment.h"
 #include "testutils/testfilemanager.h"
 #include "testutils/testoptions.h"
 
+#include "mpi_printer.h"
+
 namespace gmx
 {
 namespace test
@@ -152,11 +153,10 @@ void initTestUtils(const char* dataPath,
                    int*        argc,
                    char***     argv)
 {
-#if !defined NDEBUG                                                                         \
-        && !((defined __clang__ || (defined(__GNUC__) && !defined(__ICC) && __GNUC__ == 7)) \
-             && defined __OPTIMIZE__)
-    gmx_feenableexcept();
-#endif
+    if (gmxShouldEnableFPExceptions())
+    {
+        gmx_feenableexcept();
+    }
     const CommandLineProgramContext& context = initForCommandLine(argc, argv);
     try
     {
@@ -171,7 +171,8 @@ void initTestUtils(const char* dataPath,
                         "NOTE: You are running %s on %d MPI ranks, "
                         "but it is does not contain MPI-enabled tests. "
                         "The test will now exit.\n",
-                        context.programName(), gmx_node_num());
+                        context.programName(),
+                        gmx_node_num());
             }
             finalizeForCommandLine();
             std::exit(1);
index 9a4446847ebd8e8e87b2fe40f444235bd42ca7f5..782d0bd162468fb04f748f717b946a77d2fda5ce 100644 (file)
@@ -42,7 +42,7 @@
  */
 #include "gmxpre.h"
 
-#include "testmatchers.h"
+#include "testutils/testmatchers.h"
 
 #include <memory>
 
index 02749d82596e62df18b5585d397ff80fce3ad4be..d3ecf41ebc447d132301b2799c3c7647d2a6b346 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2012,2013,2014,2015,2019, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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 "testoptions.h"
+#include "testutils/testoptions.h"
 
 #include <list>
+#include <mutex>
 
+#include <memory>
 #include "gromacs/utility/classhelpers.h"
-#include "gromacs/utility/mutex.h"
 
 namespace gmx
 {
@@ -74,7 +75,7 @@ public:
     //! Adds a provider into the registry.
     void add(const char* /*name*/, TestOptionsProvider* provider)
     {
-        lock_guard<Mutex> lock(listMutex_);
+        std::lock_guard<std::mutex> lock(listMutex_);
         providerList_.push_back(provider);
     }
 
@@ -86,7 +87,7 @@ private:
 
     typedef std::list<TestOptionsProvider*> ProviderList;
 
-    Mutex        listMutex_;
+    std::mutex   listMutex_;
     ProviderList providerList_;
 
     GMX_DISALLOW_COPY_AND_ASSIGN(TestOptionsRegistry);
@@ -96,7 +97,7 @@ void TestOptionsRegistry::initOptions(IOptionsContainer* options)
 {
     // TODO: Have some deterministic order for the options; now it depends on
     // the order in which the global initializers are run.
-    lock_guard<Mutex>            lock(listMutex_);
+    std::lock_guard<std::mutex>  lock(listMutex_);
     ProviderList::const_iterator i;
     for (i = providerList_.begin(); i != providerList_.end(); ++i)
     {
index 7a6d651ab43e09df488764b9644772482ae9d6b7..8a1030852713f5d6811975cd0aad3e10f96aa01b 100644 (file)
@@ -39,8 +39,10 @@ gmx_add_unit_test(TestUtilsUnitTests testutils-test
         testasserts_tests.cpp
         xvgtest_tests.cpp
         )
+target_link_libraries(testutils-test PRIVATE testutils)
 
 gmx_add_mpi_unit_test(TestUtilsMpiUnitTests testutils-mpi-test 2
     CPP_SOURCE_FILES
         mpitest.cpp
         )
+target_link_libraries(testutils-test PRIVATE testutils)
index c8dc14164f13d5c16c3d8776db1c19a78db26ee6..7188644487f619fb455c00d84e4fd7c5a531400f 100644 (file)
@@ -97,7 +97,8 @@ TEST(XvgTests, CheckMissing)
         checkXvgFile(&sis, &checker, XvgMatchSettings());
     }
     {
-        const char* const input[] = { "0     2905.86    -410.199", "0.2     6656.67    -430.437",
+        const char* const input[] = { "0     2905.86    -410.199",
+                                      "0.2     6656.67    -430.437",
                                       "0.4     5262.44    -409.399" };
         // Now check with missing data
         TestReferenceData      data(ReferenceDataMode::Compare);
index 7dd2f7ca6c9a2b4a62f1896b457c50431b12fb67..0a9ec10a68cf3e8439e1b3aa27d7e29f2981ea1a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +41,7 @@
  */
 #include "gmxpre.h"
 
-#include "textblockmatchers.h"
+#include "testutils/textblockmatchers.h"
 
 #include <memory>
 #include <regex>
index 872703eef14aa64a24ff11630ebb913ff173a837..9321f9ef7a945dacae246acbe8ac4ddeccf12c3a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +42,7 @@
 
 #include "gmxpre.h"
 
-#include "tprfilegenerator.h"
+#include "testutils/tprfilegenerator.h"
 
 #include "gromacs/gmxpreprocess/grompp.h"
 #include "gromacs/utility/textwriter.h"
index e5bb19f76a82d1412fe04f1e2acaec63c22d952b..f63b8bd58914c734fe2db4d5c2923429be8cdb30 100644 (file)
@@ -72,8 +72,8 @@
 int main(int argc, char* argv[])
 {
     // Calls ::testing::InitGoogleMock()
-    ::gmx::test::initTestUtils(TEST_DATA_PATH, TEST_TEMP_PATH, TEST_USES_MPI,
-                               TEST_USES_HARDWARE_DETECTION, &argc, &argv);
+    ::gmx::test::initTestUtils(
+            TEST_DATA_PATH, TEST_TEMP_PATH, TEST_USES_MPI, TEST_USES_HARDWARE_DETECTION, &argc, &argv);
     int errcode = RUN_ALL_TESTS();
     ::gmx::test::finalizeTestUtils();
     return errcode;
index eb73e8fb2721f0564693086f48a75d929419320f..437f046a0f6a3c53b77be597bd5a4941e9ee86dc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and 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,7 +42,7 @@
  */
 #include "gmxpre.h"
 
-#include "xvgtest.h"
+#include "testutils/xvgtest.h"
 
 #include <cerrno>
 #include <cstdlib>
index 67a4990890e7a35cc5fd30be4cf500683a259951..325664ac02607f6b530d35b2af4a0d5908e0a640 100644 (file)
@@ -88,13 +88,12 @@ log: ${log}")
     set(REGRESSIONTEST_DOWNLOAD OFF CACHE BOOL "Tests already downloaded. Set to yes to download again" FORCE)
 endif()
 
-if(REGRESSIONTEST_PATH AND (CMAKE_CROSSCOMPILING OR CMAKE_CONFIGURATION_TYPES OR GMX_BUILD_MDRUN_ONLY))
+if(REGRESSIONTEST_PATH AND (CMAKE_CROSSCOMPILING OR CMAKE_CONFIGURATION_TYPES))
     # 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.")
+        "With cross-compiling or multi-configuration generators (e.g. Visual Studio), running regressiontests from build system is not supported. Please run gmxtest.pl directly.")
     set(REGRESSIONTEST_PATH OFF CACHE BOOL
         "With cross-compiling or multi-configuration generators, running regressiontests from build system is not supported." FORCE)
 endif()
@@ -136,7 +135,7 @@ if(REGRESSIONTEST_PATH)
         list(APPEND ARGS -suffix ${GMX_BINARY_SUFFIX})
     endif()
     #crosscompile is only used to disable checking whether binaries work
-    #given that we know they are there and that mdrun might not be exectuable
+    #given that we know they are there and that mdrun might not be executable
     #(e.g. Cray) we enable it.
     list(APPEND ARGS -crosscompile)
 
@@ -206,15 +205,14 @@ if(GMX_PHYSICAL_VALIDATION)
             "GMX_PHYSICAL_VALIDATION set, but physical validation script not found in ${PHYSVALTEST_SOURCE_PATH}.")
     endif()
 
-    if(CMAKE_CROSSCOMPILING OR CMAKE_CONFIGURATION_TYPES OR GMX_BUILD_MDRUN_ONLY)
+    if(CMAKE_CROSSCOMPILING OR CMAKE_CONFIGURATION_TYPES)
         # The following comment is copied from regression 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
         # TODO: Look into the details of this.
         # For now, turn it off - our python-gmx interface is probably not that stable for special cases anyway
         message(WARNING
-                "With cross-compiling, multi-configuration generators (e.g. Visual Studio), or with mdrun-only builds,\
+                "With cross-compiling or multi-configuration generators (e.g. Visual Studio),\
                 running physical validation tests from build system is not supported.\
                 Please run physicalvalidation.py directly.")
         set(GMX_PHYSICAL_VALIDATION OFF CACHE BOOL